1238384Sjkim/***********************license start***************
2238384Sjkim * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3238384Sjkim * reserved.
4238384Sjkim *
5238384Sjkim *
6238384Sjkim * Redistribution and use in source and binary forms, with or without
7238384Sjkim * modification, are permitted provided that the following conditions are
8238384Sjkim * met:
9238384Sjkim *
10238384Sjkim *   * Redistributions of source code must retain the above copyright
11238384Sjkim *     notice, this list of conditions and the following disclaimer.
12238384Sjkim *
13238384Sjkim *   * Redistributions in binary form must reproduce the above
14238384Sjkim *     copyright notice, this list of conditions and the following
15238384Sjkim *     disclaimer in the documentation and/or other materials provided
16238384Sjkim *     with the distribution.
17238384Sjkim
18238384Sjkim *   * Neither the name of Cavium Inc. nor the names of
19238384Sjkim *     its contributors may be used to endorse or promote products
20238384Sjkim *     derived from this software without specific prior written
21238384Sjkim *     permission.
22238384Sjkim
23238384Sjkim * This Software, including technical data, may be subject to U.S. export  control
24238384Sjkim * laws, including the U.S. Export Administration Act and its  associated
25238384Sjkim * regulations, and may be subject to export or import  regulations in other
26238384Sjkim * countries.
27238384Sjkim
28238384Sjkim * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29238384Sjkim * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30238384Sjkim * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31238384Sjkim * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32238384Sjkim * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33238384Sjkim * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34238384Sjkim * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35238384Sjkim * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36238384Sjkim * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37238384Sjkim * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38238384Sjkim ***********************license end**************************************/
39238384Sjkim
40238384Sjkim
41238384Sjkim/**
42238384Sjkim * @file
43238384Sjkim * Functions for accessing memory and CSRs on Octeon when we are compiling
44238384Sjkim * natively.
45238384Sjkim *
46238384Sjkim * <hr>$Revision: 38306 $<hr>
47238384Sjkim*/
48238384Sjkim#ifndef __CVMX_ACCESS_NATIVE_H__
49238384Sjkim#define __CVMX_ACCESS_NATIVE_H__
50238384Sjkim
51238384Sjkim#ifdef	__cplusplus
52238384Sjkimextern "C" {
53238384Sjkim#endif
54238384Sjkim
55238384Sjkim/**
56238384Sjkim * Returns the Octeon processor ID.
57238384Sjkim *
58238384Sjkim * @return Octeon processor ID from COP0
59238384Sjkim */
60238384Sjkimstatic inline uint32_t cvmx_get_proc_id(void)
61238384Sjkim{
62238384Sjkim#ifdef CVMX_BUILD_FOR_LINUX_USER
63238384Sjkim    extern uint32_t cvmx_app_init_processor_id;
64238384Sjkim    return cvmx_app_init_processor_id;
65238384Sjkim#else
66238384Sjkim    uint32_t id;
67238384Sjkim    asm ("mfc0 %0, $15,0" : "=r" (id));
68238384Sjkim    return id;
69238384Sjkim#endif
70238384Sjkim}
71238384Sjkim
72238384Sjkim/**
73238384Sjkim * Convert a memory pointer (void*) into a hardware compatable
74238384Sjkim * memory address (uint64_t). Octeon hardware widgets don't
75238384Sjkim * understand logical addresses.
76238384Sjkim *
77238384Sjkim * @param ptr    C style memory pointer
78238384Sjkim * @return Hardware physical address
79238384Sjkim */
80238384Sjkimstatic inline uint64_t cvmx_ptr_to_phys(void *ptr)
81238384Sjkim{
82238384Sjkim    if (CVMX_ENABLE_PARAMETER_CHECKING)
83238384Sjkim        cvmx_warn_if(ptr==NULL, "cvmx_ptr_to_phys() passed a NULL pointer\n");
84238384Sjkim
85238384Sjkim#ifdef CVMX_BUILD_FOR_UBOOT
86238384Sjkim    uint64_t uboot_tlb_ptr_to_phys(void *ptr);
87238384Sjkim
88238384Sjkim    if (((uint32_t)ptr) < 0x80000000)
89238384Sjkim    {
90238384Sjkim        /* Handle useg (unmapped due to ERL) here*/
91238384Sjkim        return(CAST64(ptr) & 0x7FFFFFFF);
92238384Sjkim    }
93    else if (((uint32_t)ptr) < 0xC0000000)
94    {
95        /* Here we handle KSEG0/KSEG1 _pointers_.  We know we are dealing
96        ** with 32 bit only values, so we treat them that way.  Note that
97        ** a cvmx_phys_to_ptr(cvmx_ptr_to_phys(X)) will not return X in this case,
98        ** but the physical address of the KSEG0/KSEG1 address. */
99        return(CAST64(ptr) & 0x1FFFFFFF);
100    }
101    else
102        return(uboot_tlb_ptr_to_phys(ptr));   /* Should not get get here in !TLB case */
103
104#endif
105
106#ifdef __linux__
107    if (sizeof(void*) == 8)
108    {
109        /* We're running in 64 bit mode. Normally this means that we can use
110            40 bits of address space (the hardware limit). Unfortunately there
111            is one case were we need to limit this to 30 bits, sign extended
112            32 bit. Although these are 64 bits wide, only 30 bits can be used */
113        if ((CAST64(ptr) >> 62) == 3)
114            return CAST64(ptr) & cvmx_build_mask(30);
115        else
116            return CAST64(ptr) & cvmx_build_mask(40);
117    }
118    else
119    {
120#ifdef __KERNEL__
121	return (long)(ptr) & 0x1fffffff;
122#else
123        extern uint64_t linux_mem32_offset;
124        if (cvmx_likely(ptr))
125            return CAST64(ptr) - linux_mem32_offset;
126        else
127            return 0;
128#endif
129    }
130#elif defined(_WRS_KERNEL)
131	return (long)(ptr) & 0x7fffffff;
132#elif defined(VXWORKS_USER_MAPPINGS)
133    /* This mapping mode is used in vxWorks 5.5 to support 2GB of ram. The
134        2nd 256MB is mapped at 0x10000000 and the rest of memory is 1:1 */
135    uint64_t address = (long)ptr;
136    if (address & 0x80000000)
137        return address & 0x1fffffff;    /* KSEG pointers directly map the lower 256MB and bootbus */
138    else if ((address >= 0x10000000) && (address < 0x20000000))
139        return address + 0x400000000ull;   /* 256MB-512MB is a virtual mapping for the 2nd 256MB */
140    else
141        return address; /* Looks to be a 1:1 mapped userspace pointer */
142#elif defined(__FreeBSD__) && defined(_KERNEL)
143    return (pmap_kextract((vm_offset_t)ptr));
144#else
145#if CVMX_USE_1_TO_1_TLB_MAPPINGS
146    /* We are assumung we're running the Simple Executive standalone. In this
147        mode the TLB is setup to perform 1:1 mapping and 32 bit sign extended
148        addresses are never used. Since we know all this, save the masking
149        cycles and do nothing */
150    return CAST64(ptr);
151#else
152
153    if (sizeof(void*) == 8)
154    {
155        /* We're running in 64 bit mode. Normally this means that we can use
156            40 bits of address space (the hardware limit). Unfortunately there
157            is one case were we need to limit this to 30 bits, sign extended
158            32 bit. Although these are 64 bits wide, only 30 bits can be used */
159        if ((CAST64(ptr) >> 62) == 3)
160            return CAST64(ptr) & cvmx_build_mask(30);
161        else
162            return CAST64(ptr) & cvmx_build_mask(40);
163    }
164    else
165	return (long)(ptr) & 0x7fffffff;
166
167#endif
168#endif
169}
170
171
172/**
173 * Convert a hardware physical address (uint64_t) into a
174 * memory pointer (void *).
175 *
176 * @param physical_address
177 *               Hardware physical address to memory
178 * @return Pointer to memory
179 */
180static inline void *cvmx_phys_to_ptr(uint64_t physical_address)
181{
182    if (CVMX_ENABLE_PARAMETER_CHECKING)
183        cvmx_warn_if(physical_address==0, "cvmx_phys_to_ptr() passed a zero address\n");
184
185#ifdef CVMX_BUILD_FOR_UBOOT
186
187    /* U-boot is a special case, as it is running in 32 bit mode, using the TLB to map code/data
188    ** which can have a physical address above the 32 bit address space.  1-1 mappings are used
189    ** to allow the low 2 GBytes to be accessed as in error level.
190    **
191    ** NOTE:  This conversion can cause problems in u-boot, as users may want to enter addresses
192    ** like 0xBFC00000 (kseg1 boot bus address), which is a valid 64 bit physical address,
193    ** but is likely intended to be a boot bus address. */
194
195    if (physical_address < 0x80000000)
196    {
197        /* Handle useg here.  ERL is set, so useg is unmapped.  This is the only physical
198        ** address range that is directly addressable by u-boot. */
199        return CASTPTR(void, physical_address);
200    }
201    else
202    {
203	DECLARE_GLOBAL_DATA_PTR;
204        extern char uboot_start;
205        /* Above 0x80000000 we can only support one case - a physical address
206        ** that is mapped for u-boot code/data.  We check against the u-boot mem range,
207        ** and return NULL if it is out of this range.
208        */
209        if (physical_address >= gd->bd->bi_uboot_ram_addr
210            && physical_address < gd->bd->bi_uboot_ram_addr + gd->bd->bi_uboot_ram_used_size)
211        {
212            return ((char *)&uboot_start + (physical_address - gd->bd->bi_uboot_ram_addr));
213        }
214        else
215            return(NULL);
216    }
217
218    if (physical_address >= 0x80000000)
219        return NULL;
220    else
221#endif
222
223#ifdef __linux__
224    if (sizeof(void*) == 8)
225    {
226        /* Just set the top bit, avoiding any TLB uglyness */
227        return CASTPTR(void, CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, physical_address));
228    }
229    else
230    {
231#ifdef __KERNEL__
232	return CASTPTR(void, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, physical_address));
233#else
234        extern uint64_t linux_mem32_offset;
235        if (cvmx_likely(physical_address))
236            return CASTPTR(void, physical_address + linux_mem32_offset);
237        else
238            return NULL;
239#endif
240    }
241#elif defined(_WRS_KERNEL)
242	return CASTPTR(void, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, physical_address));
243#elif defined(VXWORKS_USER_MAPPINGS)
244    /* This mapping mode is used in vxWorks 5.5 to support 2GB of ram. The
245        2nd 256MB is mapped at 0x10000000 and the rest of memory is 1:1 */
246    if ((physical_address >= 0x10000000) && (physical_address < 0x20000000))
247        return CASTPTR(void, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, physical_address));
248    else if ((OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN5XXX))
249              && (physical_address >= 0x410000000ull)
250              && (physical_address < 0x420000000ull))
251        return CASTPTR(void, physical_address - 0x400000000ull);
252    else
253        return CASTPTR(void, physical_address);
254#elif defined(__FreeBSD__) && defined(_KERNEL)
255#if defined(__mips_n64)
256    return CASTPTR(void, CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, physical_address));
257#else
258    if (physical_address < 0x20000000)
259	return CASTPTR(void, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, physical_address));
260    else
261	panic("%s: mapping high address (%#jx) not yet supported.\n", __func__, (uintmax_t)physical_address);
262#endif
263#else
264
265#if CVMX_USE_1_TO_1_TLB_MAPPINGS
266        /* We are assumung we're running the Simple Executive standalone. In this
267            mode the TLB is setup to perform 1:1 mapping and 32 bit sign extended
268            addresses are never used. Since we know all this, save bit insert
269            cycles and do nothing */
270    return CASTPTR(void, physical_address);
271#else
272    /* Set the XKPHYS/KSEG0 bit as appropriate based on ABI */
273    if (sizeof(void*) == 8)
274        return CASTPTR(void, CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, physical_address));
275    else
276	return CASTPTR(void, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, physical_address));
277
278#endif
279
280#endif
281}
282
283
284/* The following #if controls the definition of the macro
285    CVMX_BUILD_WRITE64. This macro is used to build a store operation to
286    a full 64bit address. With a 64bit ABI, this can be done with a simple
287    pointer access. 32bit ABIs require more complicated assembly */
288#if defined(CVMX_ABI_N64) || defined(CVMX_ABI_EABI)
289
290/* We have a full 64bit ABI. Writing to a 64bit address can be done with
291    a simple volatile pointer */
292#define CVMX_BUILD_WRITE64(TYPE, ST)                                    \
293static inline void cvmx_write64_##TYPE(uint64_t addr, TYPE##_t val)     \
294{                                                                       \
295    *CASTPTR(volatile TYPE##_t, addr) = val;                            \
296}
297
298#elif defined(CVMX_ABI_N32)
299
300/* The N32 ABI passes all 64bit quantities in a single register, so it is
301    possible to use the arguments directly. We have to use inline assembly
302    for the actual store since a pointer would truncate the address */
303#define CVMX_BUILD_WRITE64(TYPE, ST)                                    \
304static inline void cvmx_write64_##TYPE(uint64_t addr, TYPE##_t val)     \
305{                                                                       \
306    asm volatile (ST " %[v], 0(%[c])" ::[v] "r" (val), [c] "r" (addr)); \
307}
308
309#elif defined(CVMX_ABI_O32)
310
311#ifdef __KERNEL__
312#define CVMX_BUILD_WRITE64(TYPE, LT) extern void cvmx_write64_##TYPE(uint64_t csr_addr, TYPE##_t val);
313#else
314
315/* Ok, now the ugly stuff starts. O32 splits 64bit quantities into two
316    separate registers. Assembly must be used to put them back together
317    before they're used. What should be a simple store becomes a
318    convoluted mess of shifts and ors */
319#define CVMX_BUILD_WRITE64(TYPE, ST)                                    \
320static inline void cvmx_write64_##TYPE(uint64_t csr_addr, TYPE##_t val) \
321{                                                                       \
322    if (sizeof(TYPE##_t) == 8)                                          \
323    {                                                                   \
324        uint32_t csr_addrh = csr_addr>>32;                              \
325        uint32_t csr_addrl = csr_addr;                                  \
326        uint32_t valh = (uint64_t)val>>32;                              \
327        uint32_t vall = val;                                            \
328        uint32_t tmp1;                                                  \
329        uint32_t tmp2;                                                  \
330        uint32_t tmp3;                                                  \
331                                                                        \
332        asm volatile (                                                  \
333            ".set push\n"                                             \
334            ".set mips64\n"                                             \
335            "dsll   %[tmp1], %[valh], 32\n"                             \
336            "dsll   %[tmp2], %[csrh], 32\n"                             \
337            "dsll   %[tmp3], %[vall], 32\n"                             \
338            "dsrl   %[tmp3], %[tmp3], 32\n"                             \
339            "or     %[tmp1], %[tmp1], %[tmp3]\n"                        \
340            "dsll   %[tmp3], %[csrl], 32\n"                             \
341            "dsrl   %[tmp3], %[tmp3], 32\n"                             \
342            "or     %[tmp2], %[tmp2], %[tmp3]\n"                        \
343            ST "    %[tmp1], 0(%[tmp2])\n"                              \
344            ".set pop\n"                                             \
345            : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3)\
346            : [valh] "r" (valh), [vall] "r" (vall),                     \
347              [csrh] "r" (csr_addrh), [csrl] "r" (csr_addrl)            \
348        );                                                              \
349    }                                                                   \
350    else                                                                \
351    {                                                                   \
352        uint32_t csr_addrh = csr_addr>>32;                              \
353        uint32_t csr_addrl = csr_addr;                                  \
354        uint32_t tmp1;                                                  \
355        uint32_t tmp2;                                                  \
356                                                                        \
357        asm volatile (                                                  \
358            ".set push\n"                                             \
359            ".set mips64\n"                                             \
360            "dsll   %[tmp1], %[csrh], 32\n"                             \
361            "dsll   %[tmp2], %[csrl], 32\n"                             \
362            "dsrl   %[tmp2], %[tmp2], 32\n"                             \
363            "or     %[tmp1], %[tmp1], %[tmp2]\n"                        \
364            ST "    %[val], 0(%[tmp1])\n"                               \
365            ".set pop\n"                                             \
366            : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2)                  \
367            : [val] "r" (val), [csrh] "r" (csr_addrh),                  \
368              [csrl] "r" (csr_addrl)                                    \
369        );                                                              \
370    }                                                                   \
371}
372
373#endif
374
375#else
376
377/* cvmx-abi.h didn't recognize the ABI. Force the compile to fail. */
378#error: Unsupported ABI
379
380#endif
381
382/* The following #if controls the definition of the macro
383    CVMX_BUILD_READ64. This macro is used to build a load operation from
384    a full 64bit address. With a 64bit ABI, this can be done with a simple
385    pointer access. 32bit ABIs require more complicated assembly */
386#if defined(CVMX_ABI_N64) || defined(CVMX_ABI_EABI)
387
388/* We have a full 64bit ABI. Writing to a 64bit address can be done with
389    a simple volatile pointer */
390#define CVMX_BUILD_READ64(TYPE, LT)                                     \
391static inline TYPE##_t cvmx_read64_##TYPE(uint64_t addr)                \
392{                                                                       \
393    return *CASTPTR(volatile TYPE##_t, addr);                           \
394}
395
396#elif defined(CVMX_ABI_N32)
397
398/* The N32 ABI passes all 64bit quantities in a single register, so it is
399    possible to use the arguments directly. We have to use inline assembly
400    for the actual store since a pointer would truncate the address */
401#define CVMX_BUILD_READ64(TYPE, LT)                                     \
402static inline TYPE##_t cvmx_read64_##TYPE(uint64_t addr)                \
403{                                                                       \
404    TYPE##_t val;                                                       \
405    asm volatile (LT " %[v], 0(%[c])": [v] "=r" (val) : [c] "r" (addr));\
406    return val;                                                         \
407}
408
409#elif defined(CVMX_ABI_O32)
410
411#ifdef __KERNEL__
412#define CVMX_BUILD_READ64(TYPE, LT) extern TYPE##_t cvmx_read64_##TYPE(uint64_t csr_addr);
413#else
414
415/* Ok, now the ugly stuff starts. O32 splits 64bit quantities into two
416    separate registers. Assembly must be used to put them back together
417    before they're used. What should be a simple load becomes a
418    convoluted mess of shifts and ors */
419#define CVMX_BUILD_READ64(TYPE, LT)                                     \
420static inline TYPE##_t cvmx_read64_##TYPE(uint64_t csr_addr)            \
421{                                                                       \
422    if (sizeof(TYPE##_t) == 8)                                          \
423    {                                                                   \
424        uint32_t csr_addrh = csr_addr>>32;                              \
425        uint32_t csr_addrl = csr_addr;                                  \
426        uint32_t valh;                                                  \
427        uint32_t vall;                                                  \
428                                                                        \
429        asm volatile (                                                  \
430            ".set push\n"                                               \
431            ".set mips64\n"                                             \
432            "dsll   %[valh], %[csrh], 32\n"                             \
433            "dsll   %[vall], %[csrl], 32\n"                             \
434            "dsrl   %[vall], %[vall], 32\n"                             \
435            "or     %[valh], %[valh], %[vall]\n"                        \
436            LT "    %[vall], 0(%[valh])\n"                              \
437            "dsrl   %[valh], %[vall], 32\n"                             \
438            "sll    %[vall], 0\n"                                       \
439            "sll    %[valh], 0\n"                                       \
440            ".set pop\n"                                                \
441            : [valh] "=&r" (valh), [vall] "=&r" (vall)                  \
442            : [csrh] "r" (csr_addrh), [csrl] "r" (csr_addrl)            \
443        );                                                              \
444        return ((uint64_t)valh<<32) | vall;                             \
445    }                                                                   \
446    else                                                                \
447    {                                                                   \
448        uint32_t csr_addrh = csr_addr>>32;                              \
449        uint32_t csr_addrl = csr_addr;                                  \
450        TYPE##_t val;                                                   \
451        uint32_t tmp;                                                   \
452                                                                        \
453        asm volatile (                                                  \
454            ".set push\n"                                             \
455            ".set mips64\n"                                             \
456            "dsll   %[val], %[csrh], 32\n"                              \
457            "dsll   %[tmp], %[csrl], 32\n"                              \
458            "dsrl   %[tmp], %[tmp], 32\n"                               \
459            "or     %[val], %[val], %[tmp]\n"                           \
460            LT "    %[val], 0(%[val])\n"                                \
461            ".set pop\n"                                             \
462            : [val] "=&r" (val), [tmp] "=&r" (tmp)                      \
463            : [csrh] "r" (csr_addrh), [csrl] "r" (csr_addrl)            \
464        );                                                              \
465        return val;                                                     \
466    }                                                                   \
467}
468
469#endif /* __KERNEL__ */
470
471#else
472
473/* cvmx-abi.h didn't recognize the ABI. Force the compile to fail. */
474#error: Unsupported ABI
475
476#endif
477
478/* The following defines 8 functions for writing to a 64bit address. Each
479    takes two arguments, the address and the value to write.
480    cvmx_write64_int64      cvmx_write64_uint64
481    cvmx_write64_int32      cvmx_write64_uint32
482    cvmx_write64_int16      cvmx_write64_uint16
483    cvmx_write64_int8       cvmx_write64_uint8 */
484CVMX_BUILD_WRITE64(int64, "sd");
485CVMX_BUILD_WRITE64(int32, "sw");
486CVMX_BUILD_WRITE64(int16, "sh");
487CVMX_BUILD_WRITE64(int8, "sb");
488CVMX_BUILD_WRITE64(uint64, "sd");
489CVMX_BUILD_WRITE64(uint32, "sw");
490CVMX_BUILD_WRITE64(uint16, "sh");
491CVMX_BUILD_WRITE64(uint8, "sb");
492
493/* The following defines 8 functions for reading from a 64bit address. Each
494    takes the address as the only argument
495    cvmx_read64_int64       cvmx_read64_uint64
496    cvmx_read64_int32       cvmx_read64_uint32
497    cvmx_read64_int16       cvmx_read64_uint16
498    cvmx_read64_int8        cvmx_read64_uint8 */
499CVMX_BUILD_READ64(int64, "ld");
500CVMX_BUILD_READ64(int32, "lw");
501CVMX_BUILD_READ64(int16, "lh");
502CVMX_BUILD_READ64(int8, "lb");
503CVMX_BUILD_READ64(uint64, "ld");
504CVMX_BUILD_READ64(uint32, "lw");
505CVMX_BUILD_READ64(uint16, "lhu");
506CVMX_BUILD_READ64(uint8, "lbu");
507
508static inline void cvmx_write_csr(uint64_t csr_addr, uint64_t val)
509{
510    cvmx_write64_uint64(csr_addr, val);
511
512    /* Perform an immediate read after every write to an RSL register to force
513        the write to complete. It doesn't matter what RSL read we do, so we
514        choose CVMX_MIO_BOOT_BIST_STAT because it is fast and harmless */
515    if (((csr_addr >> 40) & 0x7ffff) == (0x118))
516        cvmx_read64_uint64(CVMX_MIO_BOOT_BIST_STAT);
517}
518
519static inline void cvmx_write_io(uint64_t io_addr, uint64_t val)
520{
521    cvmx_write64_uint64(io_addr, val);
522}
523
524static inline uint64_t cvmx_read_csr(uint64_t csr_addr)
525{
526    return cvmx_read64_uint64(csr_addr);
527}
528
529static inline void cvmx_send_single(uint64_t data)
530{
531    const uint64_t CVMX_IOBDMA_SENDSINGLE = 0xffffffffffffa200ull;
532    cvmx_write64_uint64(CVMX_IOBDMA_SENDSINGLE, data);
533}
534
535static inline void cvmx_read_csr_async(uint64_t scraddr, uint64_t csr_addr)
536{
537    union
538    {
539        uint64_t    u64;
540        struct {
541            uint64_t    scraddr : 8;
542            uint64_t    len     : 8;
543            uint64_t    addr    :48;
544        } s;
545    } addr;
546    addr.u64 = csr_addr;
547    addr.s.scraddr = scraddr >> 3;
548    addr.s.len = 1;
549    cvmx_send_single(addr.u64);
550}
551
552
553/**
554 * Number of the Core on which the program is currently running.
555 *
556 * @return Number of cores
557 */
558static inline unsigned int cvmx_get_core_num(void)
559{
560    unsigned int core_num;
561    CVMX_RDHWRNV(core_num, 0);
562    return core_num;
563}
564
565
566/**
567 * Returns the number of bits set in the provided value.
568 * Simple wrapper for POP instruction.
569 *
570 * @param val    32 bit value to count set bits in
571 *
572 * @return Number of bits set
573 */
574static inline uint32_t cvmx_pop(uint32_t val)
575{
576    uint32_t pop;
577    CVMX_POP(pop, val);
578    return pop;
579}
580
581
582/**
583 * Returns the number of bits set in the provided value.
584 * Simple wrapper for DPOP instruction.
585 *
586 * @param val    64 bit value to count set bits in
587 *
588 * @return Number of bits set
589 */
590static inline int cvmx_dpop(uint64_t val)
591{
592    int pop;
593    CVMX_DPOP(pop, val);
594    return pop;
595}
596
597
598/**
599 * @deprecated
600 * Provide current cycle counter as a return value. Deprecated, use
601 * cvmx_clock_get_count(CVMX_CLOCK_CORE) to get cycle counter.
602 *
603 * @return current cycle counter
604 */
605static inline uint64_t cvmx_get_cycle(void)
606{
607    return cvmx_clock_get_count(CVMX_CLOCK_CORE);
608}
609
610
611/**
612 * @deprecated
613 * Reads a chip global cycle counter.  This counts SCLK cycles since
614 * chip reset.  The counter is 64 bit. This function is deprecated as the rate
615 * of the global cycle counter is different between Octeon+ and Octeon2, use
616 * cvmx_clock_get_count(CVMX_CLOCK_SCLK) instead. For Octeon2, the clock rate
617 * of SCLK may be differnet than the core clock.
618 *
619 * @return Global chip cycle count since chip reset.
620 */
621static inline uint64_t cvmx_get_cycle_global(void)
622{
623    return cvmx_clock_get_count(CVMX_CLOCK_IPD);
624}
625
626
627/**
628 * Wait for the specified number of core clock cycles
629 *
630 * @param cycles
631 */
632static inline void cvmx_wait(uint64_t cycles)
633{
634    uint64_t done = cvmx_get_cycle() + cycles;
635
636    while (cvmx_get_cycle() < done)
637    {
638        /* Spin */
639    }
640}
641
642
643/**
644 * Wait for the specified number of micro seconds
645 *
646 * @param usec   micro seconds to wait
647 */
648static inline void cvmx_wait_usec(uint64_t usec)
649{
650    uint64_t done = cvmx_get_cycle() + usec * cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000000;
651    while (cvmx_get_cycle() < done)
652    {
653        /* Spin */
654    }
655}
656
657
658/**
659 * Wait for the specified number of io clock cycles
660 *
661 * @param cycles
662 */
663static inline void cvmx_wait_io(uint64_t cycles)
664{
665    uint64_t done = cvmx_clock_get_count(CVMX_CLOCK_SCLK) + cycles;
666
667    while (cvmx_clock_get_count(CVMX_CLOCK_SCLK) < done)
668    {
669        /* Spin */
670    }
671}
672
673
674/**
675 * Perform a soft reset of Octeon
676 *
677 * @return
678 */
679static inline void cvmx_reset_octeon(void)
680{
681    cvmx_ciu_soft_rst_t ciu_soft_rst;
682    ciu_soft_rst.u64 = 0;
683    ciu_soft_rst.s.soft_rst = 1;
684    cvmx_write_csr(CVMX_CIU_SOFT_RST, ciu_soft_rst.u64);
685}
686
687
688/**
689 * Read a byte of fuse data
690 * @param byte_addr   address to read
691 *
692 * @return fuse value: 0 or 1
693 */
694static inline uint8_t cvmx_fuse_read_byte(int byte_addr)
695{
696    cvmx_mio_fus_rcmd_t read_cmd;
697
698    read_cmd.u64 = 0;
699    read_cmd.s.addr = byte_addr;
700    read_cmd.s.pend = 1;
701    cvmx_write_csr(CVMX_MIO_FUS_RCMD, read_cmd.u64);
702    while ((read_cmd.u64 = cvmx_read_csr(CVMX_MIO_FUS_RCMD)) && read_cmd.s.pend)
703        ;
704    return(read_cmd.s.dat);
705}
706
707
708/**
709 * Read a single fuse bit
710 *
711 * @param fuse   Fuse number (0-1024)
712 *
713 * @return fuse value: 0 or 1
714 */
715static inline int cvmx_fuse_read(int fuse)
716{
717    return((cvmx_fuse_read_byte(fuse >> 3) >> (fuse & 0x7)) & 1);
718}
719
720#ifdef	__cplusplus
721}
722#endif
723
724#endif /* __CVMX_ACCESS_NATIVE_H__ */
725
726