shbde_iproc.c (14565B)
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 8 #include <shbde_iproc.h> 9 #include <shbde_mdio.h> 10 #include <shbde_pci.h> 11 12 /* PAXB register offsets within PCI BAR0 window */ 13 #define BAR0_PAXB_ENDIANESS 0x2030 14 #define BAR0_PAXB_PCIE_EP_AXI_CONFIG 0x2104 15 #define BAR0_PAXB_CONFIG_IND_ADDR 0x2120 16 #define BAR0_PAXB_CONFIG_IND_DATA 0x2124 17 18 #define PAXB_0_CMICD_TO_PCIE_INTR_EN 0x2380 19 20 #define BAR0_PAXB_IMAP0_0 (0x2c00) 21 #define BAR0_PAXB_IMAP0_1 (0x2c04) 22 #define BAR0_PAXB_IMAP0_2 (0x2c08) 23 #define BAR0_PAXB_IMAP0_7 (0x2c1c) 24 25 #define BAR0_PAXB_OARR_FUNC0_MSI_PAGE 0x2d34 26 #define BAR0_PAXB_OARR_2 0x2d60 27 #define BAR0_PAXB_OARR_2_UPPER 0x2d64 28 #define BAR0_DMU_PCU_PCIE_SLAVE_RESET_MODE 0x7024 29 30 #define PAXB_0_FUNC0_IMAP1_3 0x2d88 31 32 /* Force byte pointer for offset adjustments */ 33 #define ROFFS(_ptr, _offset) ((unsigned char*)(_ptr) + (_offset)) 34 35 #define PAXB_CONFIG_IND_ADDRr_PROTOCOL_LAYERf_SHFT 11 36 #define PAXB_CONFIG_IND_ADDRr_PROTOCOL_LAYERf_MASK 0x3 37 #define PAXB_CONFIG_IND_ADDRr_ADDRESSf_SHFT 0 38 #define PAXB_CONFIG_IND_ADDRr_ADDRESSf_MASK 0x7ff 39 #define PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT 20 40 41 /* Register value set/get by field */ 42 #define REG_FIELD_SET(_r, _f, _r_val, _f_val) \ 43 _r_val = ((_r_val) & ~(_r##_##_f##_MASK << _r##_##_f##_SHFT)) | \ 44 (((_f_val) & _r##_##_f##_MASK) << _r##_##_f##_SHFT) 45 #define REG_FIELD_GET(_r, _f, _r_val) \ 46 (((_r_val) >> _r##_##_f##_SHFT) & _r##_##_f##_MASK) 47 48 /* PCIe capabilities definition */ 49 #ifndef PCI_EXP_LNKSTA 50 #define PCI_EXP_LNKSTA 0x12 51 #endif 52 /* Current Link Speed 5.0GT/s */ 53 #ifndef PCI_EXP_LNKSTA_CLS_5_0GB 54 #define PCI_EXP_LNKSTA_CLS_5_0GB 2 55 #endif 56 #ifndef PCI_EXP_LNKSTA2 57 #define PCI_EXP_LNKSTA2 0x32 58 #endif 59 /* Current Deemphasis Level -3.5 dB */ 60 #ifndef PCI_EXP_LNKSTA2_CDL_3_5DB 61 #define PCI_EXP_LNKSTA2_CDL_3_5DB 0x1 62 #endif 63 64 static unsigned int 65 iproc32_read(shbde_hal_t *shbde, void *addr) 66 { 67 if (!shbde || !shbde->io32_read) { 68 return 0; 69 } 70 return shbde->io32_read(addr); 71 } 72 73 static void 74 iproc32_write(shbde_hal_t *shbde, void *addr, unsigned int data) 75 { 76 if (!shbde || !shbde->io32_write) { 77 return; 78 } 79 shbde->io32_write(addr, data); 80 } 81 82 static void 83 wait_usec(shbde_hal_t *shbde, int usec) 84 { 85 if (shbde && shbde->usleep) { 86 shbde->usleep(usec); 87 } else { 88 int idx; 89 volatile int count; 90 for (idx = 0; idx < usec; idx++) { 91 for (count = 0; count < 100; count++); 92 } 93 } 94 } 95 96 /* 97 * Function: 98 * shbde_iproc_config_init 99 * Purpose: 100 * Initialize iProc configuration parameters 101 * Parameters: 102 * icfg - pointer to empty iProc configuration structure 103 * Returns: 104 * -1 if error, otherwise 0 105 */ 106 int 107 shbde_iproc_config_init(shbde_iproc_config_t *icfg, 108 unsigned int dev_id, unsigned int dev_rev) 109 { 110 if (!icfg) { 111 return -1; 112 } 113 114 /* Save device ID and revision */ 115 icfg->dev_id = dev_id; 116 icfg->dev_rev = dev_rev; 117 118 /* Check device families first */ 119 switch (icfg->dev_id & 0xfff0) { 120 case 0x8400: /* Greyhound Lite */ 121 case 0x8410: /* Greyhound */ 122 case 0x8420: /* Bloodhound */ 123 case 0x8450: /* Elkhound */ 124 case 0xb060: /* Ranger2(Greyhound) */ 125 case 0x8360: /* Greyhound 53365 & 53369 */ 126 case 0xb260: /* saber2 */ 127 case 0xb460: /* saber2+ */ 128 case 0xb170: /* Hurricane3-MG */ 129 case 0x8570: /* Greyhound2 */ 130 case 0xb070: /* Greyhound2(emulation) */ 131 case 0x8580: /* Greyhound2(emulation) */ 132 case 0xb230: /* Dagger2 */ 133 icfg->iproc_ver = 7; 134 icfg->dma_hi_bits = 0x2; 135 break; 136 case 0xb560: /* Apache */ 137 case 0xb670: /* MO */ 138 case 0xb760: /* Maverick */ 139 icfg->iproc_ver = 0xB; 140 break; 141 case 0xb160: /* Hurricane3 */ 142 case 0x8440: /* Buckhound2 */ 143 case 0x8430: /* Foxhound2 */ 144 case 0x8540: /* Wolfhound2 */ 145 icfg->iproc_ver = 10; 146 icfg->dma_hi_bits = 0x2; 147 break; 148 default: 149 break; 150 } 151 152 /* Check for exceptions */ 153 switch (icfg->dev_id) { 154 case 0xb069: 155 case 0xb068: 156 icfg->iproc_ver = 0xB; /*Ranger2+ Apache Family */ 157 icfg->dma_hi_bits = 0; 158 break; 159 case 0xb168: /* Ranger3+ */ 160 case 0xb169: 161 icfg->iproc_ver = 0; 162 icfg->dma_hi_bits = 0; 163 break; 164 default: 165 break; 166 } 167 /* Check for PCIe PHY address that needs PCIe preemphasis and 168 * assign the MDIO base address 169 */ 170 switch (icfg->dev_id & 0xfff0) { 171 case 0xb150: /* Hurricane2 */ 172 case 0x8340: /* Wolfhound */ 173 case 0x8330: /* Foxhound */ 174 case 0x8390: /* Dearhound */ 175 icfg->mdio_base_addr = 0x18032000; 176 icfg->pcie_phy_addr = 0x2; 177 break; 178 case 0xb340: /* Helilx4 */ 179 case 0xb540: /* FireScout */ 180 case 0xb040: /* Spiral, Ranger */ 181 icfg->mdio_base_addr = 0x18032000; 182 icfg->pcie_phy_addr = 0x5; 183 icfg->adjust_pcie_preemphasis = 1; 184 break; 185 case 0xa450: /* Katana2 */ 186 case 0xb240: 187 case 0xb450: 188 icfg->mdio_base_addr = 0x18032000; 189 icfg->pcie_phy_addr = 0x5; 190 icfg->adjust_pcie_preemphasis = 1; 191 break; 192 default: 193 break; 194 } 195 196 /* Check for exceptions */ 197 switch (icfg->dev_id) { 198 default: 199 break; 200 } 201 202 return 0; 203 } 204 205 /* 206 * Function: 207 * shbde_iproc_paxb_init 208 * Purpose: 209 * Initialize iProc PCI-AXI bridge for CMIC access 210 * Parameters: 211 * shbde - pointer to initialized hardware abstraction module 212 * iproc_regs - memory mapped iProc registers in PCI BAR 213 * icfg - iProc configuration parameters 214 * Returns: 215 * -1 if error, otherwise 0 216 */ 217 int 218 shbde_iproc_paxb_init(shbde_hal_t *shbde, void *iproc_regs, 219 shbde_iproc_config_t *icfg) 220 { 221 void *reg; 222 unsigned int data; 223 int pci_num; 224 225 if (!iproc_regs || !icfg) { 226 return -1; 227 } 228 229 /* 230 * The following code attempts to auto-detect the correct 231 * iProc PCI endianess configuration by reading a well-known 232 * register (the endianess configuration register itself). 233 * Note that the PCI endianess may be different for different 234 * big endian host processors. 235 */ 236 reg = ROFFS(iproc_regs, BAR0_PAXB_ENDIANESS); 237 /* Select big endian */ 238 iproc32_write(shbde, reg, 0x01010101); 239 /* Check if endianess register itself is correct endian */ 240 if (iproc32_read(shbde, reg) != 1) { 241 /* If not, then assume little endian */ 242 iproc32_write(shbde, reg, 0x0); 243 } 244 245 /* Select which PCI core to use */ 246 pci_num = 0; 247 reg = ROFFS(iproc_regs, BAR0_PAXB_IMAP0_2); 248 data = iproc32_read(shbde, reg); 249 if (data & 0x1000) { 250 /* PAXB_1 is mapped to sub-window 2 */ 251 pci_num = 1; 252 } 253 254 /* Default DMA mapping if uninitialized */ 255 if (icfg->dma_hi_bits == 0) { 256 icfg->dma_hi_bits = 0x1; 257 if (pci_num == 1) { 258 icfg->dma_hi_bits = 0x2; 259 } 260 } 261 262 /* Enable iProc DMA to external host memory */ 263 reg = ROFFS(iproc_regs, BAR0_PAXB_PCIE_EP_AXI_CONFIG); 264 iproc32_write(shbde, reg, 0x0); 265 if(icfg->cmic_ver < 4) { /* Non-CMICX */ 266 reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_2); 267 iproc32_write(shbde, reg, 0x1); 268 reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_2_UPPER); 269 iproc32_write(shbde, reg, icfg->dma_hi_bits); 270 /* Configure MSI interrupt page */ 271 if (icfg->use_msi) { 272 reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_FUNC0_MSI_PAGE); 273 data = iproc32_read(shbde, reg); 274 iproc32_write(shbde, reg, data | 0x1); 275 } 276 } 277 278 /* Configure MSIX interrupt page, only need for iproc ver == 0x10 */ 279 if ((icfg->use_msi == 2) && (icfg->iproc_ver == 0x10)) { 280 unsigned int mask = (0x1 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT) - 1; 281 reg = ROFFS(iproc_regs, PAXB_0_FUNC0_IMAP1_3); 282 data = iproc32_read(shbde, reg); 283 data &= mask; 284 data |= 0x410 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT; 285 iproc32_write(shbde, reg, data); 286 } 287 288 /* Disable INTx interrupt if MSI/MSIX is selected */ 289 reg = ROFFS(iproc_regs, PAXB_0_CMICD_TO_PCIE_INTR_EN); 290 data = iproc32_read(shbde, reg); 291 if (icfg->use_msi) { 292 data &= ~0x1; 293 } else { 294 data |= 0x1; 295 } 296 iproc32_write(shbde, reg, data); 297 298 return pci_num; 299 } 300 301 /* 302 * Function: 303 * shbde_iproc_pci_read 304 * Purpose: 305 * Read iProc register through PCI BAR 0 306 * Parameters: 307 * shbde - pointer to initialized hardware abstraction module 308 * iproc_regs - memory mapped iProc registers in PCI BAR 309 * addr - iProc register address in AXI memory space 310 * Returns: 311 * Register value 312 */ 313 unsigned int 314 shbde_iproc_pci_read(shbde_hal_t *shbde, void *iproc_regs, 315 unsigned int addr) 316 { 317 unsigned int subwin_base; 318 void *reg; 319 shbde_iproc_config_t *icfg = &shbde->icfg; 320 321 if (!iproc_regs) { 322 return -1; 323 } 324 325 /* Sub-window size is 0x1000 (4K) */ 326 subwin_base = (addr & ~0xfff); 327 328 if((icfg->cmic_ver >= 4) && 329 ((subwin_base == 0x10231000) || (subwin_base == 0x18013000))) { 330 /* Route the INTC block access through IMAP0_6 */ 331 reg = ROFFS(iproc_regs, 0x6000 + (addr & 0xfff)); 332 } else { 333 /* Update base address for sub-window 7 */ 334 subwin_base |= 1; /* Valid bit */ 335 reg = ROFFS(iproc_regs, BAR0_PAXB_IMAP0_7); 336 iproc32_write(shbde, reg, subwin_base); 337 /* Read it to make sure the write actually goes through */ 338 subwin_base = iproc32_read(shbde, reg); 339 340 /* Read register through sub-window 7 */ 341 reg = ROFFS(iproc_regs, 0x7000 + (addr & 0xfff)); 342 } 343 344 return iproc32_read(shbde, reg); 345 } 346 347 /* 348 * Function: 349 * shbde_iproc_pci_write 350 * Purpose: 351 * Write iProc register through PCI BAR 0 352 * Parameters: 353 * shbde - pointer to initialized hardware abstraction module 354 * iproc_regs - memory mapped iProc registers in PCI BAR 355 * addr - iProc register address in AXI memory space 356 * data - data to write to iProc register 357 * Returns: 358 * Register value 359 */ 360 void 361 shbde_iproc_pci_write(shbde_hal_t *shbde, void *iproc_regs, 362 unsigned int addr, unsigned int data) 363 { 364 unsigned int subwin_base; 365 void *reg; 366 shbde_iproc_config_t *icfg = &shbde->icfg; 367 368 if (!iproc_regs) { 369 return; 370 } 371 372 /* Sub-window size is 0x1000 (4K) */ 373 subwin_base = (addr & ~0xfff); 374 375 if((icfg->cmic_ver >= 4) && 376 ((subwin_base == 0x10231000) || (subwin_base == 0x18013000))) { 377 /* Route the INTC block access through IMAP0_6 */ 378 reg = ROFFS(iproc_regs, 0x6000 + (addr & 0xfff)); 379 } else { 380 /* Update base address for sub-window 7 */ 381 subwin_base |= 1; /* Valid bit */ 382 reg = ROFFS(iproc_regs, BAR0_PAXB_IMAP0_7); 383 iproc32_write(shbde, reg, subwin_base); 384 /* Read it to make sure the write actually goes through */ 385 subwin_base = iproc32_read(shbde, reg); 386 387 /* Read register through sub-window 7 */ 388 reg = ROFFS(iproc_regs, 0x7000 + (addr & 0xfff)); 389 } 390 391 iproc32_write(shbde, reg, data); 392 } 393 394 int 395 shbde_iproc_pcie_preemphasis_set(shbde_hal_t *shbde, void *iproc_regs, 396 shbde_iproc_config_t *icfg, void *pci_dev) 397 { 398 shbde_mdio_ctrl_t mdio_ctrl, *smc = &mdio_ctrl; 399 unsigned int phy_addr, data; 400 void *reg; 401 unsigned int pcie_cap_base; 402 unsigned short link_stat, link_stat2; 403 404 if (!icfg) { 405 return -1; 406 } 407 408 /* PHY address for PCIe link */ 409 phy_addr = icfg->pcie_phy_addr; 410 if (phy_addr == 0 || icfg->mdio_base_addr == 0) { 411 return 0; 412 } 413 414 /* Initialize MDIO control */ 415 smc->shbde = shbde; 416 smc->regs = iproc_regs; 417 smc->base_addr = icfg->mdio_base_addr; 418 smc->io32_read = shbde_iproc_pci_read; 419 smc->io32_write = shbde_iproc_pci_write; 420 shbde_iproc_mdio_init(smc); 421 422 /* PCIe SerDes Gen1/Gen2 CDR Track Bandwidth Adjustment 423 * for Better Jitter Tolerance 424 */ 425 shbde_iproc_mdio_write(smc, phy_addr, 0x1f, 0x8630); 426 shbde_iproc_mdio_write(smc, phy_addr, 0x13, 0x190); 427 shbde_iproc_mdio_write(smc, phy_addr, 0x19, 0x191); 428 429 if (!icfg->adjust_pcie_preemphasis) { 430 return 0; 431 } 432 433 /* Check to see if the PCIe SerDes deemphasis needs to be changed 434 * based on the advertisement from the root complex 435 */ 436 /* Find PCIe capability base */ 437 if (!shbde || !shbde->pcic16_read || !pci_dev) { 438 return -1; 439 } 440 pcie_cap_base = shbde_pci_pcie_cap(shbde, pci_dev); 441 if (pcie_cap_base) { 442 link_stat = shbde->pcic16_read(pci_dev, 443 pcie_cap_base + PCI_EXP_LNKSTA); 444 link_stat2 = shbde->pcic16_read(pci_dev, 445 pcie_cap_base + PCI_EXP_LNKSTA2); 446 if (((link_stat & 0xf) == PCI_EXP_LNKSTA_CLS_5_0GB) && 447 (link_stat2 & PCI_EXP_LNKSTA2_CDL_3_5DB)) { 448 /* Device is operating at Gen2 speeds and RC requested -3.5dB */ 449 /* Change the transmitter setting */ 450 shbde_iproc_mdio_write(smc, phy_addr, 0x1f, 0x8610); 451 shbde_iproc_mdio_read(smc, phy_addr, 0x17, &data); 452 data &= ~0xf00; 453 data |= 0x700; 454 shbde_iproc_mdio_write(smc, phy_addr, 0x17, data); 455 456 /* Force the PCIe link to retrain */ 457 data = 0; 458 REG_FIELD_SET(PAXB_CONFIG_IND_ADDRr, PROTOCOL_LAYERf, data, 0x2); 459 REG_FIELD_SET(PAXB_CONFIG_IND_ADDRr, ADDRESSf, data, 0x4); 460 reg = ROFFS(iproc_regs, BAR0_PAXB_CONFIG_IND_ADDR); 461 iproc32_write(shbde, reg, data); 462 463 reg = ROFFS(iproc_regs, BAR0_PAXB_CONFIG_IND_DATA); 464 data = iproc32_read(shbde, reg); 465 data &= ~0x4000; 466 iproc32_write(shbde, reg, data); 467 data |= 0x4000; 468 iproc32_write(shbde, reg, data); 469 data &= ~0x4000; 470 iproc32_write(shbde, reg, data); 471 472 /* Wait a short while for the retraining to complete */ 473 wait_usec(shbde, 1000); 474 } 475 } 476 477 return 0; 478 } 479