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

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