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