]>
Commit | Line | Data |
---|---|---|
58f07778 DD |
1 | /***********************license start*************** |
2 | * Author: Cavium Networks | |
3 | * | |
4 | * Contact: support@caviumnetworks.com | |
5 | * This file is part of the OCTEON SDK | |
6 | * | |
15f68479 | 7 | * Copyright (c) 2003-2017 Cavium, Inc. |
58f07778 DD |
8 | * |
9 | * This file is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License, Version 2, as | |
11 | * published by the Free Software Foundation. | |
12 | * | |
13 | * This file is distributed in the hope that it will be useful, but | |
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | |
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | |
16 | * NONINFRINGEMENT. See the GNU General Public License for more | |
17 | * details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this file; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * or visit http://www.gnu.org/licenses/. | |
23 | * | |
24 | * This file may also be available under a different license from Cavium. | |
25 | * Contact Cavium Networks for more information | |
26 | ***********************license end**************************************/ | |
27 | ||
28 | #ifndef __CVMX_H__ | |
29 | #define __CVMX_H__ | |
30 | ||
31 | #include <linux/kernel.h> | |
32 | #include <linux/string.h> | |
33 | ||
26afc5e3 DD |
34 | enum cvmx_mips_space { |
35 | CVMX_MIPS_SPACE_XKSEG = 3LL, | |
36 | CVMX_MIPS_SPACE_XKPHYS = 2LL, | |
37 | CVMX_MIPS_SPACE_XSSEG = 1LL, | |
38 | CVMX_MIPS_SPACE_XUSEG = 0LL | |
39 | }; | |
40 | ||
41 | /* These macros for use when using 32 bit pointers. */ | |
42 | #define CVMX_MIPS32_SPACE_KSEG0 1l | |
43 | #define CVMX_ADD_SEG32(segment, add) \ | |
44 | (((int32_t)segment << 31) | (int32_t)(add)) | |
45 | ||
46 | #define CVMX_IO_SEG CVMX_MIPS_SPACE_XKPHYS | |
47 | ||
48 | /* These macros simplify the process of creating common IO addresses */ | |
49 | #define CVMX_ADD_SEG(segment, add) \ | |
50 | ((((uint64_t)segment) << 62) | (add)) | |
51 | #ifndef CVMX_ADD_IO_SEG | |
52 | #define CVMX_ADD_IO_SEG(add) CVMX_ADD_SEG(CVMX_IO_SEG, (add)) | |
53 | #endif | |
54 | ||
a1ce3928 DH |
55 | #include <asm/octeon/cvmx-asm.h> |
56 | #include <asm/octeon/cvmx-packet.h> | |
57 | #include <asm/octeon/cvmx-sysinfo.h> | |
58f07778 | 58 | |
a1ce3928 | 59 | #include <asm/octeon/cvmx-ciu-defs.h> |
182a6d1c | 60 | #include <asm/octeon/cvmx-ciu3-defs.h> |
a1ce3928 DH |
61 | #include <asm/octeon/cvmx-gpio-defs.h> |
62 | #include <asm/octeon/cvmx-iob-defs.h> | |
63 | #include <asm/octeon/cvmx-ipd-defs.h> | |
64 | #include <asm/octeon/cvmx-l2c-defs.h> | |
81a67e52 | 65 | #include <asm/octeon/cvmx-l2d-defs.h> |
a1ce3928 DH |
66 | #include <asm/octeon/cvmx-l2t-defs.h> |
67 | #include <asm/octeon/cvmx-led-defs.h> | |
68 | #include <asm/octeon/cvmx-mio-defs.h> | |
69 | #include <asm/octeon/cvmx-pow-defs.h> | |
58f07778 | 70 | |
a1ce3928 DH |
71 | #include <asm/octeon/cvmx-bootinfo.h> |
72 | #include <asm/octeon/cvmx-bootmem.h> | |
73 | #include <asm/octeon/cvmx-l2c.h> | |
58f07778 DD |
74 | |
75 | #ifndef CVMX_ENABLE_DEBUG_PRINTS | |
76 | #define CVMX_ENABLE_DEBUG_PRINTS 1 | |
77 | #endif | |
78 | ||
79 | #if CVMX_ENABLE_DEBUG_PRINTS | |
70342287 | 80 | #define cvmx_dprintf printk |
58f07778 DD |
81 | #else |
82 | #define cvmx_dprintf(...) {} | |
83 | #endif | |
84 | ||
70342287 RB |
85 | #define CVMX_MAX_CORES (16) |
86 | #define CVMX_CACHE_LINE_SIZE (128) /* In bytes */ | |
87 | #define CVMX_CACHE_LINE_MASK (CVMX_CACHE_LINE_SIZE - 1) /* In bytes */ | |
58f07778 DD |
88 | #define CVMX_CACHE_LINE_ALIGNED __attribute__ ((aligned(CVMX_CACHE_LINE_SIZE))) |
89 | #define CAST64(v) ((long long)(long)(v)) | |
90 | #define CASTPTR(type, v) ((type *)(long)(v)) | |
91 | ||
92 | /* | |
93 | * Returns processor ID, different Linux and simple exec versions | |
94 | * provided in the cvmx-app-init*.c files. | |
95 | */ | |
96 | static inline uint32_t cvmx_get_proc_id(void) __attribute__ ((pure)); | |
97 | static inline uint32_t cvmx_get_proc_id(void) | |
98 | { | |
99 | uint32_t id; | |
100 | asm("mfc0 %0, $15,0" : "=r"(id)); | |
101 | return id; | |
102 | } | |
103 | ||
104 | /* turn the variable name into a string */ | |
105 | #define CVMX_TMP_STR(x) CVMX_TMP_STR2(x) | |
106 | #define CVMX_TMP_STR2(x) #x | |
107 | ||
108 | /** | |
109 | * Builds a bit mask given the required size in bits. | |
110 | * | |
111 | * @bits: Number of bits in the mask | |
112 | * Returns The mask | |
113 | */ static inline uint64_t cvmx_build_mask(uint64_t bits) | |
114 | { | |
115 | return ~((~0x0ull) << bits); | |
116 | } | |
117 | ||
118 | /** | |
119 | * Builds a memory address for I/O based on the Major and Sub DID. | |
120 | * | |
121 | * @major_did: 5 bit major did | |
122 | * @sub_did: 3 bit sub did | |
123 | * Returns I/O base address | |
124 | */ | |
125 | static inline uint64_t cvmx_build_io_address(uint64_t major_did, | |
126 | uint64_t sub_did) | |
127 | { | |
128 | return (0x1ull << 48) | (major_did << 43) | (sub_did << 40); | |
129 | } | |
130 | ||
131 | /** | |
132 | * Perform mask and shift to place the supplied value into | |
133 | * the supplied bit rage. | |
134 | * | |
135 | * Example: cvmx_build_bits(39,24,value) | |
136 | * <pre> | |
70342287 RB |
137 | * 6 5 4 3 3 2 1 |
138 | * 3 5 7 9 1 3 5 7 0 | |
58f07778 DD |
139 | * +-------+-------+-------+-------+-------+-------+-------+------+ |
140 | * 000000000000000000000000___________value000000000000000000000000 | |
141 | * </pre> | |
142 | * | |
143 | * @high_bit: Highest bit value can occupy (inclusive) 0-63 | |
144 | * @low_bit: Lowest bit value can occupy inclusive 0-high_bit | |
145 | * @value: Value to use | |
146 | * Returns Value masked and shifted | |
147 | */ | |
148 | static inline uint64_t cvmx_build_bits(uint64_t high_bit, | |
149 | uint64_t low_bit, uint64_t value) | |
150 | { | |
151 | return (value & cvmx_build_mask(high_bit - low_bit + 1)) << low_bit; | |
152 | } | |
153 | ||
58f07778 | 154 | /** |
25985edc | 155 | * Convert a memory pointer (void*) into a hardware compatible |
58f07778 DD |
156 | * memory address (uint64_t). Octeon hardware widgets don't |
157 | * understand logical addresses. | |
158 | * | |
159 | * @ptr: C style memory pointer | |
160 | * Returns Hardware physical address | |
161 | */ | |
162 | static inline uint64_t cvmx_ptr_to_phys(void *ptr) | |
163 | { | |
164 | if (sizeof(void *) == 8) { | |
165 | /* | |
166 | * We're running in 64 bit mode. Normally this means | |
167 | * that we can use 40 bits of address space (the | |
168 | * hardware limit). Unfortunately there is one case | |
169 | * were we need to limit this to 30 bits, sign | |
170 | * extended 32 bit. Although these are 64 bits wide, | |
171 | * only 30 bits can be used. | |
172 | */ | |
173 | if ((CAST64(ptr) >> 62) == 3) | |
174 | return CAST64(ptr) & cvmx_build_mask(30); | |
175 | else | |
176 | return CAST64(ptr) & cvmx_build_mask(40); | |
177 | } else { | |
178 | return (long)(ptr) & 0x1fffffff; | |
179 | } | |
180 | } | |
181 | ||
182 | /** | |
183 | * Convert a hardware physical address (uint64_t) into a | |
184 | * memory pointer (void *). | |
185 | * | |
186 | * @physical_address: | |
70342287 | 187 | * Hardware physical address to memory |
58f07778 DD |
188 | * Returns Pointer to memory |
189 | */ | |
190 | static inline void *cvmx_phys_to_ptr(uint64_t physical_address) | |
191 | { | |
192 | if (sizeof(void *) == 8) { | |
92a76f6d | 193 | /* Just set the top bit, avoiding any TLB ugliness */ |
58f07778 DD |
194 | return CASTPTR(void, |
195 | CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, | |
196 | physical_address)); | |
197 | } else { | |
198 | return CASTPTR(void, | |
199 | CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, | |
200 | physical_address)); | |
201 | } | |
202 | } | |
203 | ||
204 | /* The following #if controls the definition of the macro | |
205 | CVMX_BUILD_WRITE64. This macro is used to build a store operation to | |
206 | a full 64bit address. With a 64bit ABI, this can be done with a simple | |
207 | pointer access. 32bit ABIs require more complicated assembly */ | |
208 | ||
209 | /* We have a full 64bit ABI. Writing to a 64bit address can be done with | |
210 | a simple volatile pointer */ | |
70342287 RB |
211 | #define CVMX_BUILD_WRITE64(TYPE, ST) \ |
212 | static inline void cvmx_write64_##TYPE(uint64_t addr, TYPE##_t val) \ | |
213 | { \ | |
214 | *CASTPTR(volatile TYPE##_t, addr) = val; \ | |
58f07778 DD |
215 | } |
216 | ||
217 | ||
218 | /* The following #if controls the definition of the macro | |
219 | CVMX_BUILD_READ64. This macro is used to build a load operation from | |
220 | a full 64bit address. With a 64bit ABI, this can be done with a simple | |
221 | pointer access. 32bit ABIs require more complicated assembly */ | |
222 | ||
223 | /* We have a full 64bit ABI. Writing to a 64bit address can be done with | |
224 | a simple volatile pointer */ | |
70342287 RB |
225 | #define CVMX_BUILD_READ64(TYPE, LT) \ |
226 | static inline TYPE##_t cvmx_read64_##TYPE(uint64_t addr) \ | |
227 | { \ | |
58f07778 DD |
228 | return *CASTPTR(volatile TYPE##_t, addr); \ |
229 | } | |
230 | ||
231 | ||
232 | /* The following defines 8 functions for writing to a 64bit address. Each | |
233 | takes two arguments, the address and the value to write. | |
70342287 RB |
234 | cvmx_write64_int64 cvmx_write64_uint64 |
235 | cvmx_write64_int32 cvmx_write64_uint32 | |
236 | cvmx_write64_int16 cvmx_write64_uint16 | |
237 | cvmx_write64_int8 cvmx_write64_uint8 */ | |
58f07778 DD |
238 | CVMX_BUILD_WRITE64(int64, "sd"); |
239 | CVMX_BUILD_WRITE64(int32, "sw"); | |
240 | CVMX_BUILD_WRITE64(int16, "sh"); | |
241 | CVMX_BUILD_WRITE64(int8, "sb"); | |
242 | CVMX_BUILD_WRITE64(uint64, "sd"); | |
243 | CVMX_BUILD_WRITE64(uint32, "sw"); | |
244 | CVMX_BUILD_WRITE64(uint16, "sh"); | |
245 | CVMX_BUILD_WRITE64(uint8, "sb"); | |
246 | #define cvmx_write64 cvmx_write64_uint64 | |
247 | ||
248 | /* The following defines 8 functions for reading from a 64bit address. Each | |
249 | takes the address as the only argument | |
70342287 RB |
250 | cvmx_read64_int64 cvmx_read64_uint64 |
251 | cvmx_read64_int32 cvmx_read64_uint32 | |
252 | cvmx_read64_int16 cvmx_read64_uint16 | |
253 | cvmx_read64_int8 cvmx_read64_uint8 */ | |
58f07778 DD |
254 | CVMX_BUILD_READ64(int64, "ld"); |
255 | CVMX_BUILD_READ64(int32, "lw"); | |
256 | CVMX_BUILD_READ64(int16, "lh"); | |
257 | CVMX_BUILD_READ64(int8, "lb"); | |
258 | CVMX_BUILD_READ64(uint64, "ld"); | |
259 | CVMX_BUILD_READ64(uint32, "lw"); | |
260 | CVMX_BUILD_READ64(uint16, "lhu"); | |
261 | CVMX_BUILD_READ64(uint8, "lbu"); | |
262 | #define cvmx_read64 cvmx_read64_uint64 | |
263 | ||
264 | ||
265 | static inline void cvmx_write_csr(uint64_t csr_addr, uint64_t val) | |
266 | { | |
267 | cvmx_write64(csr_addr, val); | |
268 | ||
269 | /* | |
270 | * Perform an immediate read after every write to an RSL | |
271 | * register to force the write to complete. It doesn't matter | |
272 | * what RSL read we do, so we choose CVMX_MIO_BOOT_BIST_STAT | |
273 | * because it is fast and harmless. | |
274 | */ | |
26084411 | 275 | if (((csr_addr >> 40) & 0x7ffff) == (0x118)) |
58f07778 DD |
276 | cvmx_read64(CVMX_MIO_BOOT_BIST_STAT); |
277 | } | |
278 | ||
a2127e40 AM |
279 | static inline void cvmx_writeq_csr(void __iomem *csr_addr, uint64_t val) |
280 | { | |
281 | cvmx_write_csr((__force uint64_t)csr_addr, val); | |
282 | } | |
283 | ||
58f07778 DD |
284 | static inline void cvmx_write_io(uint64_t io_addr, uint64_t val) |
285 | { | |
286 | cvmx_write64(io_addr, val); | |
287 | ||
288 | } | |
289 | ||
290 | static inline uint64_t cvmx_read_csr(uint64_t csr_addr) | |
291 | { | |
292 | uint64_t val = cvmx_read64(csr_addr); | |
293 | return val; | |
294 | } | |
295 | ||
a2127e40 AM |
296 | static inline uint64_t cvmx_readq_csr(void __iomem *csr_addr) |
297 | { | |
298 | return cvmx_read_csr((__force uint64_t) csr_addr); | |
299 | } | |
58f07778 DD |
300 | |
301 | static inline void cvmx_send_single(uint64_t data) | |
302 | { | |
303 | const uint64_t CVMX_IOBDMA_SENDSINGLE = 0xffffffffffffa200ull; | |
304 | cvmx_write64(CVMX_IOBDMA_SENDSINGLE, data); | |
305 | } | |
306 | ||
307 | static inline void cvmx_read_csr_async(uint64_t scraddr, uint64_t csr_addr) | |
308 | { | |
309 | union { | |
310 | uint64_t u64; | |
311 | struct { | |
312 | uint64_t scraddr:8; | |
313 | uint64_t len:8; | |
314 | uint64_t addr:48; | |
315 | } s; | |
316 | } addr; | |
317 | addr.u64 = csr_addr; | |
318 | addr.s.scraddr = scraddr >> 3; | |
319 | addr.s.len = 1; | |
320 | cvmx_send_single(addr.u64); | |
321 | } | |
322 | ||
323 | /* Return true if Octeon is CN38XX pass 1 */ | |
324 | static inline int cvmx_octeon_is_pass1(void) | |
325 | { | |
326 | #if OCTEON_IS_COMMON_BINARY() | |
327 | return 0; /* Pass 1 isn't supported for common binaries */ | |
328 | #else | |
329 | /* Now that we know we're built for a specific model, only check CN38XX */ | |
330 | #if OCTEON_IS_MODEL(OCTEON_CN38XX) | |
331 | return cvmx_get_proc_id() == OCTEON_CN38XX_PASS1; | |
332 | #else | |
333 | return 0; /* Built for non CN38XX chip, we're not CN38XX pass1 */ | |
334 | #endif | |
335 | #endif | |
336 | } | |
337 | ||
338 | static inline unsigned int cvmx_get_core_num(void) | |
339 | { | |
340 | unsigned int core_num; | |
341 | CVMX_RDHWRNV(core_num, 0); | |
342 | return core_num; | |
343 | } | |
344 | ||
182a6d1c DD |
345 | /* Maximum # of bits to define core in node */ |
346 | #define CVMX_NODE_NO_SHIFT 7 | |
347 | #define CVMX_NODE_MASK 0x3 | |
348 | static inline unsigned int cvmx_get_node_num(void) | |
349 | { | |
350 | unsigned int core_num = cvmx_get_core_num(); | |
351 | ||
352 | return (core_num >> CVMX_NODE_NO_SHIFT) & CVMX_NODE_MASK; | |
353 | } | |
354 | ||
355 | static inline unsigned int cvmx_get_local_core_num(void) | |
356 | { | |
357 | return cvmx_get_core_num() & ((1 << CVMX_NODE_NO_SHIFT) - 1); | |
358 | } | |
359 | ||
58f07778 DD |
360 | /** |
361 | * Returns the number of bits set in the provided value. | |
362 | * Simple wrapper for POP instruction. | |
363 | * | |
364 | * @val: 32 bit value to count set bits in | |
365 | * | |
366 | * Returns Number of bits set | |
367 | */ | |
368 | static inline uint32_t cvmx_pop(uint32_t val) | |
369 | { | |
370 | uint32_t pop; | |
371 | CVMX_POP(pop, val); | |
372 | return pop; | |
373 | } | |
374 | ||
375 | /** | |
376 | * Returns the number of bits set in the provided value. | |
377 | * Simple wrapper for DPOP instruction. | |
378 | * | |
379 | * @val: 64 bit value to count set bits in | |
380 | * | |
381 | * Returns Number of bits set | |
382 | */ | |
383 | static inline int cvmx_dpop(uint64_t val) | |
384 | { | |
385 | int pop; | |
386 | CVMX_DPOP(pop, val); | |
387 | return pop; | |
388 | } | |
389 | ||
390 | /** | |
391 | * Provide current cycle counter as a return value | |
392 | * | |
393 | * Returns current cycle counter | |
394 | */ | |
395 | ||
396 | static inline uint64_t cvmx_get_cycle(void) | |
397 | { | |
398 | uint64_t cycle; | |
399 | CVMX_RDHWR(cycle, 31); | |
400 | return cycle; | |
401 | } | |
402 | ||
e8635b48 DD |
403 | /** |
404 | * Wait for the specified number of cycle | |
405 | * | |
406 | */ | |
407 | static inline void cvmx_wait(uint64_t cycles) | |
408 | { | |
409 | uint64_t done = cvmx_get_cycle() + cycles; | |
410 | ||
411 | while (cvmx_get_cycle() < done) | |
412 | ; /* Spin */ | |
413 | } | |
414 | ||
58f07778 DD |
415 | /** |
416 | * Reads a chip global cycle counter. This counts CPU cycles since | |
70342287 | 417 | * chip reset. The counter is 64 bit. |
58f07778 DD |
418 | * This register does not exist on CN38XX pass 1 silicion |
419 | * | |
420 | * Returns Global chip cycle count since chip reset. | |
421 | */ | |
422 | static inline uint64_t cvmx_get_cycle_global(void) | |
423 | { | |
424 | if (cvmx_octeon_is_pass1()) | |
425 | return 0; | |
426 | else | |
427 | return cvmx_read64(CVMX_IPD_CLK_COUNT); | |
428 | } | |
429 | ||
430 | /** | |
431 | * This macro spins on a field waiting for it to reach a value. It | |
432 | * is common in code to need to wait for a specific field in a CSR | |
433 | * to match a specific value. Conceptually this macro expands to: | |
434 | * | |
435 | * 1) read csr at "address" with a csr typedef of "type" | |
436 | * 2) Check if ("type".s."field" "op" "value") | |
437 | * 3) If #2 isn't true loop to #1 unless too much time has passed. | |
438 | */ | |
439 | #define CVMX_WAIT_FOR_FIELD64(address, type, field, op, value, timeout_usec)\ | |
440 | ( \ | |
441 | { \ | |
442 | int result; \ | |
443 | do { \ | |
444 | uint64_t done = cvmx_get_cycle() + (uint64_t)timeout_usec * \ | |
445 | cvmx_sysinfo_get()->cpu_clock_hz / 1000000; \ | |
446 | type c; \ | |
447 | while (1) { \ | |
448 | c.u64 = cvmx_read_csr(address); \ | |
449 | if ((c.s.field) op(value)) { \ | |
450 | result = 0; \ | |
451 | break; \ | |
452 | } else if (cvmx_get_cycle() > done) { \ | |
453 | result = -1; \ | |
454 | break; \ | |
455 | } else \ | |
456 | cvmx_wait(100); \ | |
457 | } \ | |
458 | } while (0); \ | |
459 | result; \ | |
460 | }) | |
461 | ||
462 | /***************************************************************************/ | |
463 | ||
58f07778 DD |
464 | /* Return the number of cores available in the chip */ |
465 | static inline uint32_t cvmx_octeon_num_cores(void) | |
466 | { | |
182a6d1c DD |
467 | u64 ciu_fuse_reg; |
468 | u64 ciu_fuse; | |
469 | ||
470 | if (OCTEON_IS_OCTEON3() && !OCTEON_IS_MODEL(OCTEON_CN70XX)) | |
471 | ciu_fuse_reg = CVMX_CIU3_FUSE; | |
472 | else | |
473 | ciu_fuse_reg = CVMX_CIU_FUSE; | |
474 | ciu_fuse = cvmx_read_csr(ciu_fuse_reg); | |
475 | return cvmx_dpop(ciu_fuse); | |
58f07778 DD |
476 | } |
477 | ||
58f07778 | 478 | #endif /* __CVMX_H__ */ |