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 (15582B)


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