openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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