pci.c (19226B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * Routines for accessing BCM56xx PCI memory mapped registers 8 */ 9 10 #include <shared/bsl.h> 11 12 #include <sal/core/libc.h> 13 #include <sal/core/boot.h> 14 15 #include <soc/mem.h> 16 #include <soc/debug.h> 17 #include <soc/cm.h> 18 #include <soc/drv.h> 19 #include <soc/error.h> 20 #include <soc/cmic.h> 21 #ifdef BCM_CMICM_SUPPORT 22 #include <soc/cmicm.h> 23 #endif 24 25 /* The buffer used by soc_pci_off2name */ 26 static char _soc_pci_off2name_buf[SOC_MAX_NUM_DEVICES][40]; 27 28 /* 29 * CMIC PCI Memory-Accessible registers. 30 * 31 * NOTE: Names must be kept in correct order to correspond with offsets. 32 */ 33 34 STATIC char *_soc_pci_reg_names[] = { 35 "CMIC_SCHAN_CTRL", /* Start at offset 0x50 */ 36 "CMIC_ARL_DMA_ADDR", "CMIC_ARL_DMA_CNT", 37 "CMIC_SCHAN_ERR", 38 "CMIC_COS_ENABLE_COS0", "CMIC_COS_ENABLE_COS1", 39 "CMIC_COS_ENABLE_COS2", "CMIC_COS_ENABLE_COS3", 40 "CMIC_COS_ENABLE_COS4", "CMIC_COS_ENABLE_COS5", 41 "CMIC_COS_ENABLE_COS6", "CMIC_COS_ENABLE_COS7", 42 "CMIC_ARL_MBUF00", "CMIC_ARL_MBUF01", "CMIC_ARL_MBUF02", "CMIC_ARL_MBUF03", 43 0, 0, 0, 0, 44 "CMIC_ARL_MBUF10", "CMIC_ARL_MBUF11", "CMIC_ARL_MBUF12", "CMIC_ARL_MBUF13", 45 0, 0, 0, 0, 46 "CMIC_ARL_MBUF20", "CMIC_ARL_MBUF21", "CMIC_ARL_MBUF22", "CMIC_ARL_MBUF23", 47 0, 0, 0, 0, 48 "CMIC_ARL_MBUF30", "CMIC_ARL_MBUF31", "CMIC_ARL_MBUF32", "CMIC_ARL_MBUF33", 49 0, 0, 0, 0, 50 "CMIC_DMA_CTRL", "CMIC_DMA_STAT", "CMIC_HOL_STAT", "CMIC_CONFIG", 51 "CMIC_DMA_DESC0", "CMIC_DMA_DESC1", "CMIC_DMA_DESC2", "CMIC_DMA_DESC3", 52 "CMIC_I2C_SLAVE_ADDR", "CMIC_I2C_DATA", "CMIC_I2C_CTRL", "CMIC_I2C_STAT", 53 "CMIC_I2C_SLAVE_XADDR", "CMIC_I2C_GP0", "CMIC_I2C_GP1", 54 "CMIC_I2C_RESET", "CMIC_LINK_STAT", 55 "CMIC_IRQ_STAT", "CMIC_IRQ_MASK", 56 "CMIC_MEM_FAIL", 57 "CMIC_IGBP_WARN", "CMIC_IGBP_DISCARD", 58 "CMIC_MIIM_PARAM", "CMIC_MIIM_READ_DATA", 59 "CMIC_SCAN_PORTS", 60 "CMIC_STAT_DMA_ADDR", "CMIC_STAT_DMA_SETUP", 61 "CMIC_STAT_DMA_PORTS", "CMIC_STAT_DMA_CURRENT", 62 "CMIC_ENDIAN_SELECT", 63 }; 64 65 char * 66 soc_pci_off2name(int unit, uint32 offset) 67 { 68 int led = soc_feature(unit, soc_feature_led_proc); 69 70 assert((offset & 3) == 0); 71 72 #ifdef BCM_CMICM_SUPPORT 73 if(soc_feature(unit, soc_feature_cmicm)) { 74 sal_strncpy(_soc_pci_off2name_buf[unit], 75 soc_cmicm_addr_name (offset), 39); 76 _soc_pci_off2name_buf[unit][39] = 0; 77 return _soc_pci_off2name_buf[unit]; 78 } 79 #endif /* CMICM Support */ 80 81 #ifdef BCM_CMICX_SUPPORT 82 if(soc_feature(unit, soc_feature_cmicx)) { 83 sal_strncpy(_soc_pci_off2name_buf[unit], 84 soc_cmicx_addr_name (offset), 39); 85 _soc_pci_off2name_buf[unit][39] = 0; 86 return _soc_pci_off2name_buf[unit]; 87 } 88 #endif /* BCM_CMICX_SUPPORT */ 89 90 /* CMIC_SCHAN_MESSAGE begins at 0x800 on some chips */ 91 92 if (offset < 0x50) { 93 sal_sprintf(_soc_pci_off2name_buf[unit], "CMIC_SCHAN_D%02d", 94 offset / 4); 95 } else if ((int) offset >= CMIC_SCHAN_MESSAGE(unit, 0) && 96 (int)offset < CMIC_SCHAN_MESSAGE(unit, CMIC_SCHAN_WORDS(unit))) { 97 sal_sprintf(_soc_pci_off2name_buf[unit], "CMIC_SCHAN_D%02d", 98 (offset - CMIC_SCHAN_MESSAGE(unit, 0)) / 4); 99 } else if (led && offset == 0x1000) { 100 sal_strncpy(_soc_pci_off2name_buf[unit], "CMIC_LED_CTRL", 101 sizeof(_soc_pci_off2name_buf[unit])); 102 } else if (led && offset == 0x1004) { 103 sal_strncpy(_soc_pci_off2name_buf[unit], "CMIC_LED_STATUS", 104 sizeof(_soc_pci_off2name_buf[unit])); 105 } else if (led && offset >= 0x1800 && offset < 0x1c00) { 106 sal_sprintf(_soc_pci_off2name_buf[unit], "CMIC_LED_PROG%02x", 107 (offset - 0x1800) / 4); 108 } else if (led && offset >= 0x1c00 && offset < 0x2000) { 109 sal_sprintf(_soc_pci_off2name_buf[unit], "CMIC_LED_DATA%02x", 110 (offset - 0x1c00) / 4); 111 } else if ((offset - 0x50) < 4 * (uint32)COUNTOF(_soc_pci_reg_names) && 112 _soc_pci_reg_names[(offset - 0x50) / 4] != NULL) { 113 sal_strncpy(_soc_pci_off2name_buf[unit], 114 _soc_pci_reg_names[(offset - 0x50) / 4], 39); 115 _soc_pci_off2name_buf[unit][39] = 0; 116 } else { 117 sal_sprintf(_soc_pci_off2name_buf[unit], "CMIC_UNUSED_0x%04x", offset); 118 } 119 120 return _soc_pci_off2name_buf[unit]; 121 } 122 123 /* If SOC_PCI_DEBUG not defined, then these functions are inlined in cmic.h */ 124 #ifdef SOC_PCI_DEBUG 125 /* 126 * Get a CMIC register in PCI space using more "soc-like" semantics. 127 * Input address is relative to the base of CMIC registers. 128 */ 129 int 130 soc_pci_getreg(int unit, uint32 addr, uint32 *datap) 131 { 132 uint32 addr32 = addr; 133 #if defined(BCM_IPROC_SUPPORT) && defined(IPROC_NO_ATL) 134 addr32 += SOC_DRIVER(unit)->cmicd_base; 135 #endif 136 *datap = CMREAD(unit, addr32); 137 #if defined(CMIC_SOFT_BYTE_SWAP) 138 *datap = CMIC_SWAP32(*datap); 139 #endif 140 LOG_VERBOSE(BSL_LS_SOC_PCI, 141 (BSL_META_U(unit, 142 "PCI%d memR(0x%x)=0x%x\n"), unit, addr32, *datap)); 143 return SOC_E_NONE; 144 } 145 146 /* 147 * Get a CMIC register in PCI space. 148 * Input address is relative to the base of CMIC registers. 149 */ 150 uint32 151 soc_pci_read(int unit, uint32 addr) 152 { 153 uint32 data, addr32 = addr; 154 155 #if defined(IPROC_ACCESS_DEBUG) && (defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT)) 156 if (SOC_IS_DNX(unit) || SOC_IS_DNXF(unit)) { 157 assert(addr < 0x50000); /* check that the address is in the currently supported address range of the iproc BAR in Jericho 2 and Ramon */ 158 } 159 #endif /* IPROC_ACCESS_DEBUG) && (defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT) */ 160 161 #if defined(BCM_IPROC_SUPPORT) && defined(IPROC_NO_ATL) 162 addr32 += SOC_DRIVER(unit)->cmicd_base; 163 #endif 164 data = CMREAD(unit, addr32); 165 #if defined(CMIC_SOFT_BYTE_SWAP) 166 data = CMIC_SWAP32(data); 167 #endif 168 LOG_VERBOSE(BSL_LS_SOC_PCI, 169 (BSL_META_U(unit, 170 "PCI%d barR(0x%x)=0x%x\n"), unit, addr32, data)); 171 return data; 172 } 173 174 /* 175 * Set a CMIC register in PCI space. 176 * Input address is relative to the base of CMIC registers. 177 */ 178 int 179 soc_pci_write(int unit, uint32 addr, uint32 data) 180 { 181 uint32 addr32 = addr; 182 183 #if defined(IPROC_ACCESS_DEBUG) && (defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT)) 184 if (SOC_IS_DNX(unit) || SOC_IS_DNXF(unit)) { 185 assert(addr < 0x50000); /* check that the address is in the currently supported address range of the iproc BAR in Jericho 2 and Ramon */ 186 } 187 #endif /* IPROC_ACCESS_DEBUG) && (defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT) */ 188 189 #if defined(BCM_IPROC_SUPPORT) && defined(IPROC_NO_ATL) 190 addr32 += SOC_DRIVER(unit)->cmicd_base; 191 #endif 192 #if defined(CMIC_SOFT_BYTE_SWAP) 193 data = CMIC_SWAP32(data); 194 #endif 195 LOG_VERBOSE(BSL_LS_SOC_PCI, 196 (BSL_META_U(unit, 197 "PCI%d barW(0x%x)=0x%x\n"), unit, addr32, data)); 198 CMWRITE(unit, addr32, data); 199 return 0; 200 } 201 202 /* 203 * Read a register from the PCI Config Space 204 */ 205 uint32 206 soc_pci_conf_read(int unit, uint32 addr) 207 { 208 uint32 data; 209 data = CMCONFREAD(unit, addr); 210 LOG_VERBOSE(BSL_LS_SOC_PCI, 211 (BSL_META_U(unit, 212 "PCI%d ConfigR(0x%x)=0x%x\n"), unit, addr, data)); 213 return data; 214 } 215 216 /* 217 * Write a value to the PCI Config Space 218 */ 219 int 220 soc_pci_conf_write(int unit, uint32 addr, uint32 data) 221 { 222 LOG_VERBOSE(BSL_LS_SOC_PCI, 223 (BSL_META_U(unit, 224 "PCI%d ConfigW(0x%x)=0x%x\n"), unit, addr, data)); 225 CMCONFWRITE(unit, addr, data); 226 return 0; 227 } 228 #else 229 /* Get CMIC PCI Register */ 230 int 231 soc_pci_getreg(int unit, uint32 addr, uint32 *datap) 232 { 233 *datap = CMREAD(unit, addr); 234 #if defined(CMIC_SOFT_BYTE_SWAP) 235 *datap = CMIC_SWAP32(*datap); 236 #endif 237 return SOC_E_NONE; 238 } 239 #endif /* SOC_PCI_DEBUG */ 240 241 /* 242 * The functions below access iproc or cmic registers, used in register access 243 * macros for registers who have different types in different devices. 244 * The previous macros used soc_reg_addr() so it is safe not to compile the 245 * functions in builds where soc_reg_addr() is not compiled. 246 */ 247 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) || defined(PORTMOD_SUPPORT) 248 /* 249 * Function: 250 * soc_cmic_or_iproc_getreg 251 * Purpose: 252 * Read iProc or CMIC register 253 * Parameters: 254 * unit - unit number 255 * Returns: 256 * SOC_E_XXX 257 */ 258 int soc_cmic_or_iproc_getreg(int unit, soc_reg_t reg, uint32 *data) 259 { 260 soc_regtype_t regtype = SOC_REG_TYPE(unit, reg); 261 uint32 addr = soc_reg_addr(unit, reg, REG_PORT_ANY, 0); 262 if (regtype == soc_cpureg) { 263 /* Read PCI register value. */ 264 SOC_IF_ERROR_RETURN(soc_pci_getreg(unit, addr, data)); 265 #ifdef BCM_IPROC_SUPPORT 266 } else if (regtype == soc_iprocreg) { 267 *data = soc_cm_iproc_read(unit, addr); 268 #endif 269 } else { 270 LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "Illegal register type\n"))); 271 return SOC_E_PARAM; 272 } 273 274 return SOC_E_NONE; 275 } 276 277 278 /* 279 * Function: 280 * soc_cmic_or_iproc_setreg 281 * Purpose: 282 * Write iProc or CMIC register 283 * Parameters: 284 * unit - unit number 285 * Returns: 286 * SOC_E_XXX 287 */ 288 int soc_cmic_or_iproc_setreg(int unit, soc_reg_t reg, uint32 data) 289 { 290 soc_regtype_t regtype = SOC_REG_TYPE(unit, reg); 291 uint32 addr = soc_reg_addr(unit, reg, REG_PORT_ANY, 0); 292 if (regtype == soc_cpureg) { 293 soc_pci_write(unit, addr, data); 294 #ifdef BCM_IPROC_SUPPORT 295 } else if (regtype == soc_iprocreg) { 296 soc_cm_iproc_write(unit, addr, data); 297 #endif 298 } else { 299 LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "Illegal register type\n"))); 300 return SOC_E_PARAM; 301 } 302 303 return SOC_E_NONE; 304 } 305 #endif /* defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) || defined(PORTMOD_SUPPORT) */ 306 307 /* 308 * soc_pci_test checks PCI memory range 0x00-0x4f 309 */ 310 311 int 312 soc_pci_test(int unit) 313 { 314 int i; 315 uint32 tmp, reread; 316 uint32 pat; 317 #ifdef BCM_CMICM_SUPPORT 318 int cmc = SOC_PCI_CMC(unit); 319 #endif 320 #ifdef BCM_CMICX_SUPPORT 321 if(soc_feature(unit, soc_feature_cmicx)) { 322 return(soc_cmicx_pci_test(unit)); 323 } 324 #endif 325 SCHAN_LOCK(unit); 326 327 /* Check for address uniqueness */ 328 329 #ifdef BCM_CMICM_SUPPORT 330 if(soc_feature(unit, soc_feature_cmicm)) { 331 for (i = 0; i < CMIC_SCHAN_WORDS(unit); i++) { 332 pat = 0x55555555 ^ (i << 24 | i << 16 | i << 8 | i); 333 soc_pci_write(unit, CMIC_CMCx_SCHAN_MESSAGEn(cmc, i), pat); 334 } 335 336 for (i = 0; i < CMIC_SCHAN_WORDS(unit); i++) { 337 pat = 0x55555555 ^ (i << 24 | i << 16 | i << 8 | i); 338 tmp = soc_pci_read(unit, CMIC_CMCx_SCHAN_MESSAGEn(cmc, i)); 339 if (tmp != pat) { 340 goto error; 341 } 342 } 343 } else 344 #endif 345 { 346 for (i = 0; i < CMIC_SCHAN_WORDS(unit); i++) { 347 pat = 0x55555555 ^ (i << 24 | i << 16 | i << 8 | i); 348 soc_pci_write(unit, CMIC_SCHAN_MESSAGE(unit, i), pat); 349 } 350 351 for (i = 0; i < CMIC_SCHAN_WORDS(unit); i++) { 352 pat = 0x55555555 ^ (i << 24 | i << 16 | i << 8 | i); 353 tmp = soc_pci_read(unit, CMIC_SCHAN_MESSAGE(unit, i)); 354 if (tmp != pat) { 355 goto error; 356 } 357 } 358 } 359 if (!SAL_BOOT_QUICKTURN) { /* Takes too long */ 360 /* Rotate walking zero/one pattern through each register */ 361 362 pat = 0xff7f0080; /* Simultaneous walking 0 and 1 */ 363 364 for (i = 0; i < CMIC_SCHAN_WORDS(unit); i++) { 365 int j; 366 367 for (j = 0; j < 32; j++) { 368 #ifdef BCM_CMICM_SUPPORT 369 if(soc_feature(unit, soc_feature_cmicm)) { 370 soc_pci_write(unit, CMIC_CMCx_SCHAN_MESSAGEn(cmc, i), pat); 371 tmp = soc_pci_read(unit, CMIC_CMCx_SCHAN_MESSAGEn(cmc, i)); 372 } else 373 #endif 374 { 375 soc_pci_write(unit, CMIC_SCHAN_MESSAGE(unit, i), pat); 376 tmp = soc_pci_read(unit, CMIC_SCHAN_MESSAGE(unit, i)); 377 } 378 if (tmp != pat) { 379 goto error; 380 } 381 pat = (pat << 1) | ((pat >> 31) & 1); /* Rotate left */ 382 } 383 } 384 } 385 386 /* Clear to zeroes when done */ 387 388 for (i = 0; i < CMIC_SCHAN_WORDS(unit); i++) { 389 #ifdef BCM_CMICM_SUPPORT 390 if(soc_feature(unit, soc_feature_cmicm)) { 391 soc_pci_write(unit, CMIC_CMCx_SCHAN_MESSAGEn(cmc, i), 0); 392 } else 393 #endif 394 { 395 soc_pci_write(unit, CMIC_SCHAN_MESSAGE(unit, i), 0); 396 } 397 } 398 399 SCHAN_UNLOCK(unit); 400 return 0; 401 402 error: 403 #ifdef BCM_CMICM_SUPPORT 404 if(soc_feature(unit, soc_feature_cmicm)) { 405 reread = soc_pci_read(unit, CMIC_CMCx_SCHAN_MESSAGEn(cmc, i)); 406 } else 407 #endif 408 { 409 reread = soc_pci_read(unit, CMIC_SCHAN_MESSAGE(unit, i)); 410 } 411 LOG_ERROR(BSL_LS_SOC_COMMON, 412 (BSL_META_U(unit, 413 "FATAL PCI error testing PCIM[0x%x]:\n" 414 "Wrote 0x%x, read 0x%x, re-read 0x%x\n"), 415 i, pat, tmp, reread)); 416 417 SCHAN_UNLOCK(unit); 418 return SOC_E_INTERNAL; 419 } 420 421 /* 422 * Do a harmless memory read from the address CMIC_OFFSET_TRIGGER. This 423 * can be called from error interrupts, memory test miscompare, etc. to 424 * trigger a logic analyzer that is waiting for a PCI memory read of the 425 * trigger address. 426 */ 427 428 void 429 soc_pci_analyzer_trigger(int unit) 430 { 431 if (soc_cm_get_bus_type(unit) & SOC_PCI_DEV_TYPE) { 432 (void) soc_pci_read(unit, CMIC_OFFSET_TRIGGER); 433 } 434 } 435 436 #define SERDES_PMI_ADDR (0x1130) 437 #define SERDES_PMI_WDATA (0x1134) 438 #define PMI_WDATA_DATA_MASK (0xFFFF) 439 #define PMI_WDATA_RCMD (1 << 30) 440 #define PMI_WDATA_WCMD (1 << 31) 441 #define SERDES_PMI_RDATA (0x1138) 442 #define PMI_RDATA_DATA_MASK (0xFFFF) 443 #define PMI_RDATA_VALID (1 << 31) 444 #define SERDES_PMI_RD_DONE_COUNT (1000) 445 446 int 447 soc_pcie_phy_read(int unit, uint32 addr, uint16 *val) 448 { 449 #ifdef BCM_CMICX_SUPPORT 450 uint32 data, cmd, ioerr = 0; 451 452 if (!soc_feature(unit, soc_feature_cmicx)) { 453 return SOC_E_UNAVAIL; 454 } 455 456 /* 457 * Accessed indirectly via the PAXB CFG IND ADDR/DATA and 458 * SERDES_PMI_ADDR/DATA registers. 459 */ 460 ioerr += WRITE_PAXB_0_CONFIG_IND_ADDRr(unit, SERDES_PMI_ADDR); 461 sal_udelay(1000); 462 ioerr += WRITE_PAXB_0_CONFIG_IND_DATAr(unit, addr); 463 sal_udelay(1000); 464 /* Initiate read cycle */ 465 ioerr += WRITE_PAXB_0_CONFIG_IND_ADDRr(unit, SERDES_PMI_WDATA); 466 sal_udelay(1000); 467 ioerr += WRITE_PAXB_0_CONFIG_IND_DATAr(unit, PMI_WDATA_RCMD); 468 sal_udelay(1000); 469 /* Check if read is complete */ 470 do { 471 ioerr += WRITE_PAXB_0_CONFIG_IND_ADDRr(unit, SERDES_PMI_WDATA); 472 sal_udelay(1000); 473 ioerr += READ_PAXB_0_CONFIG_IND_DATAr(unit, &cmd); 474 sal_udelay(1000); 475 ioerr += WRITE_PAXB_0_CONFIG_IND_ADDRr(unit, SERDES_PMI_RDATA); 476 sal_udelay(1000); 477 ioerr += READ_PAXB_0_CONFIG_IND_DATAr(unit, &data); 478 sal_udelay(1000); 479 } while (((cmd & PMI_WDATA_RCMD) != 0) || ((data & PMI_RDATA_VALID) == 0)); 480 481 *val = data; 482 483 return (ioerr == 0) ? SOC_E_NONE : SOC_E_FAIL; 484 #else 485 return SOC_E_UNAVAIL; 486 #endif 487 } 488 489 int 490 soc_pcie_phy_write(int unit, uint32 addr, uint16 val) 491 { 492 #ifdef BCM_CMICX_SUPPORT 493 uint32 data, ioerr = 0; 494 495 if (!soc_feature(unit, soc_feature_cmicx)) { 496 return SOC_E_UNAVAIL; 497 } 498 499 /* 500 * Accessed indirectly via the PAXB CFG IND ADDR/DATA and 501 * SERDES_PMI_ADDR/DATA registers. 502 */ 503 ioerr += WRITE_PAXB_0_CONFIG_IND_ADDRr(unit, SERDES_PMI_ADDR); 504 sal_udelay(1000); 505 ioerr += WRITE_PAXB_0_CONFIG_IND_DATAr(unit, addr); 506 sal_udelay(1000); 507 /* Initiate write cycle */ 508 ioerr += WRITE_PAXB_0_CONFIG_IND_ADDRr(unit, SERDES_PMI_WDATA); 509 sal_udelay(1000); 510 ioerr += WRITE_PAXB_0_CONFIG_IND_DATAr(unit, PMI_WDATA_WCMD | val); 511 sal_udelay(1000); 512 /* Check if write is complete */ 513 do { 514 ioerr += WRITE_PAXB_0_CONFIG_IND_ADDRr(unit, SERDES_PMI_WDATA); 515 sal_udelay(1000); 516 ioerr += READ_PAXB_0_CONFIG_IND_DATAr(unit, &data); 517 } while ((data & PMI_WDATA_WCMD) != 0); 518 519 return (ioerr == 0) ? SOC_E_NONE : SOC_E_FAIL; 520 #else 521 return SOC_E_UNAVAIL; 522 #endif 523 } 524 525 #ifdef BCM_CMICX_SUPPORT 526 #include <pcig3_phy_acc.h> 527 528 static int 529 pcie_srds_bus_read(void *user_acc, uint32_t addr, uint16_t *val) 530 { 531 srds_access_t *sa = user_acc; 532 int unit = sa->unit; 533 534 if (soc_pcie_phy_read(unit, addr, val) != SOC_E_NONE) { 535 return -1; 536 } 537 538 return 0; 539 } 540 541 static int 542 pcie_srds_bus_write(void *user_acc, uint32_t addr, uint16_t val) 543 { 544 srds_access_t *sa = user_acc; 545 int unit = sa->unit; 546 547 if (soc_pcie_phy_write(unit, addr, val) != SOC_E_NONE) { 548 return -1; 549 } 550 551 return 0; 552 } 553 554 /* 555 * Returns 0 - if PCIe FW is required but not loaded 556 * 1 - if PCIe FW is loaded or FW is not required 557 */ 558 int 559 soc_pcie_fw_status_get(int unit, uint32 *valid) 560 { 561 uint32 mode, bootdev, mhost_en = 0, rval; 562 uint16 loaded; 563 int rv; 564 srds_access_t sa; 565 srds_bus_t pcie_srds_bus; 566 567 sal_memset(&pcie_srds_bus, 0, sizeof(pcie_srds_bus)); 568 pcie_srds_bus.name = "pcie_srds_bus"; 569 pcie_srds_bus.read = pcie_srds_bus_read; 570 pcie_srds_bus.write = pcie_srds_bus_write; 571 572 sal_memset(&sa, 0, sizeof(sa)); 573 sa.unit = unit; 574 sa.bus = &pcie_srds_bus; 575 576 if(soc_feature(unit, soc_feature_cmicx) && 577 (soc_cm_get_bus_type(unit) & SOC_PCI_DEV_TYPE)) { 578 /* Read PCIe link capability register and extract max link speed */ 579 SOC_IF_ERROR_RETURN(WRITE_PAXB_0_CONFIG_IND_ADDRr(unit, 0xb8)); 580 sal_udelay(1000); 581 SOC_IF_ERROR_RETURN(READ_PAXB_0_CONFIG_IND_DATAr(unit, &mode)); 582 mode &= 0xF; /* 1 - Gen1, 2 - Gen2, 3 - Gen3 */ 583 SOC_IF_ERROR_RETURN(READ_PAXB_0_GEN3_UC_LOADER_STATUSr(unit, &rval)); 584 /* Read SerDes register 0xd230 which has FW version loaded */ 585 rv = pcie_phy_diag_reg_read(&sa, 0xd230, &loaded); 586 if(rv != 0) { 587 LOG_ERROR(BSL_LS_SOC_COMMON, 588 (BSL_META_U(unit, "pcie_phy_diag_reg_read failed, %d\n"), rv)); 589 } 590 591 if (SOC_IS_HELIX5(unit)) { 592 SOC_IF_ERROR_RETURN(READ_ICFG_ROM_S0_IDM_IO_STATUSr(unit, &rval)); 593 bootdev = soc_reg_field_get(unit, ICFG_ROM_S0_IDM_IO_STATUSr, 594 rval, STRAP_BOOT_DEVf); 595 } 596 else { 597 SOC_IF_ERROR_RETURN(READ_ROM_S0_IDM_IO_STATUSr(unit, &rval)); 598 bootdev = soc_reg_field_get(unit, ROM_S0_IDM_IO_STATUSr, 599 rval, STRAP_BOOT_DEVf); 600 SOC_IF_ERROR_RETURN(READ_ICFG_MHOST0_STRAPSr(unit, &rval)); 601 mhost_en = soc_reg_field_get(unit, ICFG_MHOST0_STRAPSr, rval, 602 MHOST0_BOOT_DEVf); 603 } 604 if (mode == 3) { 605 *valid = loaded; 606 } 607 else if (!SOC_IS_HELIX5(unit) && (mhost_en == 1) && 608 (bootdev == 0 || bootdev == 6) && 609 (loaded == 0)) { 610 *valid = 0; 611 } 612 else { 613 *valid = 1; 614 } 615 } 616 else { 617 *valid = 1; 618 } 619 return SOC_E_NONE; 620 } 621 #endif