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

wc40.c (475018B)


      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  * File:        wc40.c
      8  * Purpose:     Broadcom 10M/100M/1G/2.5G/10G/12G/13G/16G/20G/25G/30G/40G SerDes 
      9  *              (Warpcore 40nm with x1 and x4 lane support)
     10  */
     11 #include <sal/types.h>
     12 #include <sal/core/spl.h>
     13 #include <shared/bsl.h>
     14 #include <soc/drv.h>
     15 #include <soc/debug.h>
     16 #include <soc/error.h>
     17 #include <soc/phyreg.h>
     18 #include <soc/port_ability.h>
     19 #include <soc/phyctrl.h>
     20 
     21 #include <soc/phy.h>
     22 #include <soc/phy/phyctrl.h>
     23 #include <soc/phy/drv.h>
     24 
     25 #include "phydefs.h"      /* Must include before other phy related includes */
     26 
     27 #ifdef BCM_WARM_BOOT_SUPPORT
     28 #include <soc/scache.h>
     29 #endif
     30 
     31 #if defined(INCLUDE_XGXS_WC40)
     32 #include "phyconfig.h"     /* Must include before other phy related includes */
     33 #include "phyreg.h"
     34 #include "phyfege.h"
     35 #include "phynull.h"
     36 #include "serdesid.h"
     37 #include "wc40.h"
     38 #include "wc40_extra.h"
     39 
     40 /* Do not change the value, used as index */
     41 #define WC_UTIL_VEYE           0  /* vertical eye */
     42 #define WC_UTIL_HEYE_R         1  /* horizontal right eye */
     43 #define WC_UTIL_HEYE_L         2  /* horizontal left eye */
     44 
     45 #define WC40_SDK32387_REVS(_pc) (WC40_REVID_A0(_pc) || WC40_REVID_A1(_pc) || WC40_REVID_B(_pc))
     46 #define WC40_PHY400_REVS(_pc) (WC40_REVID_B(_pc))
     47 
     48 #define WC40_CL73_SOFT_KR2(_pc)  ((DEV_CFG_PTR(_pc)->cl73an == WC40_CL73_KR2) || \
     49                                   (DEV_CFG_PTR(_pc)->cl73an == WC40_CL73_KR2_WAR) || \
     50                                   (DEV_CFG_PTR(_pc)->cl73an == WC40_CL73_KR2_CUSTOM) || \
     51                                   (DEV_CFG_PTR(_pc)->cl73an == WC40_CL73_KR2_CUSTOM_WAR))
     52  
     53 #define DSC1B0_UC_CTRLr 0x820e
     54 #define WC40_UC_INFO_B1_REGB_SERDES_PLL_RATE_MASK (0x1f << WC40_UC_INFO_B1_REGB_SERDES_PLL_RATE_SHIFT)
     55 #define WC40_UC_INFO_B1_REGB_SERDES_PLL_RATE_SHIFT (7)
     56 
     57 /*
     58    SOFTWARE RX LOS feature introduces link flaps untill the link is stablized.
     59    Some customer applications do not like it. In order to minimize the link flaps
     60    a WAR is proposed to disable link fault reporitng briefly during SOFTWARE 
     61    RX LOS state machine transitions. 
     62  */
     63 #define SW_RX_LOS_LINK_FLAP_WAR
     64 
     65 
     66 /* CL73 AN TX FIFO RESET feature in wc firmware has a requirement that 
     67    this feature be disabled when reg 0x8345[15:14] is to be used with cl73 
     68    an and this feature enabled. Restore the state of the feature/routine
     69    afterwards.
     70    -DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status-
     71 */
     72 #define WC40_CL73_AN_TX_FIFO_RESET_STOP(pc) {\
     73           if(DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status == ACTIVE) {\
     74               SOC_IF_ERROR_RETURN \
     75                   (MODIFY_WC40_MICROBLK_MDIO_UC_MAILBOXr(unit, pc, 0x0, \
     76                                                           0, 1<<pc->lane_num)); \
     77               DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status = REACTIVATE; \
     78           } \
     79         }   
     80 
     81 #define WC40_CL73_AN_TX_FIFO_RESET_START(pc) {\
     82           if(DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status == REACTIVATE) {\
     83               SOC_IF_ERROR_RETURN \
     84                   (MODIFY_WC40_MICROBLK_MDIO_UC_MAILBOXr(unit, pc, 0x0, \
     85                                          1<<pc->lane_num, 1<<pc->lane_num)); \
     86               DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status = ACTIVE; \
     87           } \
     88         }   
     89 
     90 /* static variables */
     91 STATIC char wc_device_name[] = "WarpCore";
     92 int (*_phy_wc40_firmware_set_helper[SOC_MAX_NUM_DEVICES])(int, int, uint8 *,int) = {NULL};
     93  
     94 static int ln_access[4] = {LANE0_ACCESS, LANE1_ACCESS,LANE2_ACCESS,LANE3_ACCESS};
     95 
     96 /* uController's firmware */
     97 extern uint8 wc40_ucode_revA0[];
     98 extern int   wc40_ucode_revA0_len;
     99 extern uint8 wc40_ucode_revB0[];
    100 extern int   wc40_ucode_revB0_len;
    101 
    102 STATIC WC40_UCODE_DESC wc40_ucodes[] = {
    103     {&wc40_ucode_revA0[0], &wc40_ucode_revA0_len, WC40_SERDES_ID0_REVID_A0},
    104     {&wc40_ucode_revA0[0], &wc40_ucode_revA0_len, WC40_SERDES_ID0_REVID_A1},
    105     {&wc40_ucode_revA0[0], &wc40_ucode_revA0_len, WC40_SERDES_ID0_REVID_A2},
    106     {&wc40_ucode_revB0[0], &wc40_ucode_revB0_len, WC40_SERDES_ID0_REVID_B0},
    107     {&wc40_ucode_revB0[0], &wc40_ucode_revB0_len, WC40_SERDES_ID0_REVID_B1}
    108 };
    109 #define WC40_UCODE_NUM_ENTRIES  (sizeof(wc40_ucodes)/sizeof(wc40_ucodes[0]))
    110 /* function forward declaration */
    111 STATIC int _phy_wc40_notify_duplex(int unit, soc_port_t port, uint32 duplex);
    112 STATIC int _phy_wc40_notify_speed(int unit, soc_port_t port, uint32 speed);
    113 STATIC int _phy_wc40_notify_stop(int unit, soc_port_t port, uint32 flags);
    114 STATIC int _phy_wc40_notify_resume(int unit, soc_port_t port, uint32 flags);
    115 STATIC int _phy_wc40_notify_interface(int unit, soc_port_t port, uint32 intf);
    116 STATIC int _phy_wc40_notify_mac_loopback(int unit, soc_port_t port, uint32 enable);
    117 STATIC int _phy_wc40_combo_speed_get(int unit, soc_port_t port, int *speed,
    118                                      int *intf, int *scr);
    119 STATIC int _phy_wc40_ind_speed_get(int unit, soc_port_t port, int *speed,
    120                                    int *intf, int *scr);
    121 STATIC int phy_wc40_an_set(int unit, soc_port_t port, int an);
    122 STATIC int phy_wc40_lb_set(int unit, soc_port_t port, int enable);
    123 STATIC int phy_wc40_ability_advert_set(int unit, soc_port_t port,
    124                                       soc_port_ability_t *ability);
    125 STATIC int phy_wc40_ability_local_get(int unit, soc_port_t port,
    126                                 soc_port_ability_t *ability);
    127 STATIC int phy_wc40_speed_set(int unit, soc_port_t port, int speed);
    128 STATIC int phy_wc40_speed_get(int unit, soc_port_t port, int *speed);
    129 STATIC int phy_wc40_an_get(int unit, soc_port_t port, int *an, int *an_done);
    130 STATIC int _wc40_xgmii_scw_config (int unit, phy_ctrl_t *pc);
    131 STATIC int _wc40_rxaui_config(int unit, phy_ctrl_t  *pc,int rxaui);
    132 STATIC int _wc40_soft_reset(int unit, phy_ctrl_t  *pc);
    133 STATIC int phy_wc40_reg_aer_read(int unit, phy_ctrl_t *pc, uint32 flags,
    134                   uint32 phy_reg_addr, uint16 *phy_data);
    135 STATIC int phy_wc40_reg_aer_write(int unit, phy_ctrl_t *pc,  uint32 flags,
    136                    uint32 phy_reg_addr, uint16 phy_data);
    137 STATIC int phy_wc40_reg_aer_modify(int unit, phy_ctrl_t *pc,  uint32 flags,
    138                     uint32 phy_reg_addr, uint16 phy_data,uint16 phy_data_mask);
    139 STATIC int _wc40_chip_init_done(int unit,int chip_num,int phy_mode);
    140 STATIC int phy_wc40_firmware_load(int unit, int port, int offset, 
    141                                  uint8 *array,int datalen);
    142 STATIC int _phy_wc40_ind_speed_ctrl_get(int unit, soc_port_t port, int speed,
    143                                         uint16 *speed_val, int *tx_inx);
    144 STATIC int _phy_wc40_vco_set(int unit, soc_port_t port, int speed,int speed_val);
    145 STATIC int _phy_wc40_control_vco_disturbed_set(int unit, soc_port_t port);
    146 STATIC int _wc40_soft_an_cl73kr2(int unit, soc_port_t port, int an);
    147 STATIC int _wc40_soft_an_cl73kr2_custom(int unit, soc_port_t port, int an);
    148 STATIC int _wc40_soft_an_cl73kr2_check(int unit, soc_port_t port);
    149 STATIC int _wc40_soft_an_cl73kr2_custom_check(int unit, soc_port_t port);
    150 STATIC int phy_wc40_diag_ctrl(int, soc_port_t, uint32, int, int, void *); 
    151 STATIC int wc40_eye_margin(int unit, soc_port_t port, int type);
    152 STATIC int wc40_uc_status_dump(int unit, soc_port_t port);
    153 STATIC int _wc40_soft_an_cl73kr2_init(int unit, soc_port_t port);
    154 STATIC int _phy_wc40_tx_disable(int, soc_port_t, int, int, int);
    155 STATIC int _phy_wc40_tx_control_set(int, soc_port_t, WC40_TX_DRIVE_t *);
    156 STATIC int _phy_wc40_tx_control_get(int, soc_port_t, WC40_TX_DRIVE_t *, int);
    157 STATIC int _phy_wc40_firmware_mode_set(int, soc_port_t, uint32);
    158 STATIC int _phy_wc40_firmware_mode_get(int, soc_port_t, uint32 *);
    159 STATIC int _phy_wc40_firmware_dfe_mode_set(int, soc_port_t, uint32);
    160 STATIC int _phy_wc40_firmware_dfe_mode_get(int, soc_port_t, uint32 *);
    161 STATIC int _phy_wc40_speed_set(int unit, soc_port_t port, int speed);
    162 STATIC int _phy_wc40_ind_speed_set(int unit, soc_port_t port, int speed);
    163 STATIC int phy_wc40_enable_set(int unit, soc_port_t port, int enable);
    164 STATIC int phy_wc40_medium_get(int unit, soc_port_t port, soc_port_medium_t *medium);
    165 
    166 #ifdef BCM_WARM_BOOT_SUPPORT
    167 #define BCM_WB_VERSION_1_0                SOC_SCACHE_VERSION(1,0)
    168 #define BCM_WB_DEFAULT_VERSION            BCM_WB_VERSION_1_0
    169 
    170 /*
    171  * Warm Boot Version Map:
    172  *  BCM_WB_VERSION_1_0
    173  *      scache_ver
    174  *      sw_rx_los.sys_link
    175  *      sw_rx_los.state
    176  *      sw_rx_los.link_status
    177  */
    178 STATIC int wc40_wb_sc_handler(int unit, soc_port_t port, 
    179                                 WC40_WB_HANDLER_TYPE_t type, WC40_WB_DATA_ID_t id) ;
    180 STATIC int wc40_wb_id_command(int unit, soc_port_t port, int offset, 
    181                                 WC40_WB_HANDLER_TYPE_t type, WC40_WB_DATA_ID_t id, int *size) ;
    182 STATIC int wc40_wb_sc_size_count(int unit, soc_port_t port, int *size) ;
    183 STATIC int wc40_wb_sc_init(int unit, soc_port_t port) ;
    184 STATIC int wc40_wb_sc_realloc_init(int unit, soc_port_t port) ;
    185 STATIC int wc40_wb_sc_sync(int unit, soc_port_t port) ;
    186 STATIC int wc40_wb_sc_reinit(int unit, soc_port_t port) ;
    187 #endif
    188 
    189 STATIC int
    190 _phy_wc40_ucode_get(int unit, soc_port_t port, uint8 **ppdata, int *len, 
    191                     int *mem_alloced)
    192 {
    193     int ix;
    194     phy_ctrl_t     *pc;
    195 
    196     pc = INT_PHY_SW_STATE(unit, port);
    197 
    198     *mem_alloced = FALSE;
    199     *ppdata = NULL;
    200 
    201     /* check which firmware to load */
    202     for (ix = 0; ix < WC40_UCODE_NUM_ENTRIES; ix++) {
    203         if (wc40_ucodes[ix].chip_rev == WC40_REVID(pc)) {
    204             break;
    205         }
    206     }
    207     if (ix >= WC40_UCODE_NUM_ENTRIES) {
    208         LOG_WARN(BSL_LS_SOC_PHY,
    209                  (BSL_META_U(unit,
    210                              "no firmware matches the chip rev number!!! use default\n")));
    211         ix = WC40_UCODE_NUM_ENTRIES - 1;
    212     }  
    213     for (; ix >= 0; ix--) {
    214         if ((wc40_ucodes[ix].pdata != NULL) && 
    215             (*(wc40_ucodes[ix].plen) != 0)) {
    216             break;
    217         }
    218     }
    219     if (ix < 0) {
    220         LOG_WARN(BSL_LS_SOC_PHY,
    221                  (BSL_META_U(unit,
    222                              "no valid firmware found!!!\n")));
    223         return SOC_E_NOT_FOUND;
    224     }
    225     
    226     *ppdata = wc40_ucodes[ix].pdata;
    227     *len = *(wc40_ucodes[ix].plen);
    228     return SOC_E_NONE;
    229 }
    230 
    231 
    232 STATIC int
    233 _phy_wc40_config_init(int unit, soc_port_t port)
    234 {
    235     WC40_DEV_CFG_t *pCfg;
    236     WC40_DEV_INFO_t  *pInfo;
    237     phy_ctrl_t      *pc;
    238     WC40_DEV_DESC_t *pDesc;
    239     uint16 serdes_id0;
    240     WC40_TX_DRIVE_t *p_tx;
    241     int i;
    242     int line_intf = 0;
    243 
    244     pc = INT_PHY_SW_STATE(unit, port);
    245 
    246     pDesc = (WC40_DEV_DESC_t *)(pc + 1);
    247 
    248     /* clear the memory */
    249     WC40_MEM_SET(pDesc, 0, sizeof(*pDesc));
    250 
    251     pCfg = &pDesc->cfg; 
    252     pInfo = &pDesc->info;
    253 
    254     SOC_IF_ERROR_RETURN
    255         (READ_WC40_SERDESID_SERDESID0r(unit, pc, 0x00, &serdes_id0));
    256     pInfo->serdes_id0 = serdes_id0;
    257 
    258     /* init the default configuration values */
    259 
    260     for (i = 0; i < NUM_LANES; i++) {
    261         pCfg->preemph[i] = WC40_NO_CFG_VALUE;
    262         pCfg->idriver[i] = WC40_NO_CFG_VALUE;
    263         pCfg->pdriver[i] = WC40_NO_CFG_VALUE;
    264         pCfg->post2driver[i] = WC40_NO_CFG_VALUE;
    265     }
    266 
    267    /* default */
    268     p_tx = &pCfg->tx_drive[TXDRV_DFT_INX];
    269     p_tx->u.tap.post  = 0x00;
    270     p_tx->u.tap.main  = 0x00;
    271     p_tx->u.tap.pre   = 0x00;
    272     p_tx->u.tap.force = 0x00;
    273     p_tx->post2     = 0x00;
    274     p_tx->idrive    = 0x09;
    275     p_tx->ipredrive = 0x09;
    276 
    277     pCfg->hg_mode    = FALSE;
    278     pCfg->sgmii_mstr = FALSE;
    279     pCfg->pdetect10g = TRUE;
    280     pCfg->cx42hg     = FALSE;
    281     pCfg->rxlane_map = WC40_RX_LANE_MAP_DEFAULT;
    282     pCfg->txlane_map = WC40_RX_LANE_MAP_DEFAULT;
    283     pCfg->medium = SOC_PORT_MEDIUM_COPPER;
    284     pCfg->cx4_10g    = TRUE;
    285     pCfg->lane0_rst  = TRUE;  
    286     pCfg->rxaui      = FALSE;
    287     pCfg->load_mthd = 2;             
    288     pCfg->uc_cksum  = 0;
    289     pCfg->refclk    = 156;
    290 
    291     /* this property is for debug and diagnostic purpose. byte0: 
    292      * 0: not loading WC firmware
    293      * 1: load from MDIO. default method.
    294      * 2: load from parallel bus if applicable. Provide fast downloading time
    295      * 
    296      * byte1:
    297      * 0: inform uC not to perform checksum calculation(default). Save ~70ms for WC init time
    298      * 1: inform uC to perform checksum calculation. 
    299      */
    300     pCfg->load_mthd = soc_property_port_get(unit, port, spn_LOAD_FIRMWARE, pCfg->load_mthd);
    301     pCfg->load_mthd &= 0xff;
    302     pCfg->uc_cksum = soc_property_port_get(unit, port, spn_LOAD_FIRMWARE, pCfg->uc_cksum);
    303     pCfg->uc_cksum = (pCfg->uc_cksum >> 8) & 0xff;
    304 
    305     /* before performing device configuration, must not call any driver function. 
    306      * Only allowed operation is to read common register shared by all four lanes
    307      */
    308     SOC_IF_ERROR_RETURN(phy_wc40_config_init(pc));
    309 
    310     /* CL73 auto recover feature:
    311        Monitor the CL73 fsm for particular FSM states
    312        and take action if it sees the same state for a 
    313        a fixed number of times (implying stuck fsm) to 
    314        recover fsm.
    315        TO disable this feature use PHY ctrl:
    316        PORT_PHY_CONTROL_CL73_FSM_AUTO_RECOVER.
    317 
    318        Recommended by DE to enable it by default.
    319 
    320     */
    321     pCfg->cl73_fsm_auto_recover.enable = 1;
    322 
    323     /* Select firmware based implementation */
    324     pCfg->force_cl72_fw = 1; /* Select by default */
    325 
    326     /* Forced cl72 config - enabled(default)/disabled */
    327     if (SOC_IS_HELIX4(unit) || SOC_IS_KATANA2(unit)) {
    328         pCfg->force_cl72 = 0;
    329     } else {
    330         pCfg->force_cl72 = 1;
    331     }
    332     pCfg->force_cl72 = soc_property_port_get(unit, port,
    333                                         spn_PORT_INIT_CL72, pCfg->force_cl72);
    334 
    335     line_intf = soc_property_port_get(unit, port, spn_SERDES_IF_TYPE, line_intf) ;
    336     if (line_intf > 0) {
    337          pCfg->line_intf = 1 << line_intf;
    338     }
    339 
    340     {
    341         uint16 data16;
    342 
    343         SOC_IF_ERROR_RETURN
    344             (READ_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit,pc,LANE0_ACCESS,&data16));
    345         if (((data16 >> (pc->lane_num * 4)) & 0xf) == WC40_UC_CTRL_SFP_DAC) {
    346             pCfg->medium = SOC_PORT_MEDIUM_COPPER;
    347         } else {
    348             pCfg->medium = SOC_PORT_MEDIUM_FIBER;
    349         }
    350     }
    351 
    352     
    353 #ifdef BCM_WARM_BOOT_SUPPORT
    354     if (SOC_WARM_BOOT(unit)) {
    355         int current_ver = BCM_WB_DEFAULT_VERSION;
    356         int rv = SOC_E_NONE;
    357         int intf;
    358         int scr;
    359         int speed;
    360 
    361         intf = 0;
    362         /* recovery software states from device */
    363         /* recover interface value from hardware */
    364         if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
    365             SOC_IF_ERROR_RETURN
    366                 (_phy_wc40_combo_speed_get(unit, port, &speed,&intf,&scr));
    367         } else {
    368             SOC_IF_ERROR_RETURN
    369                 (_phy_wc40_ind_speed_get(unit, port, &speed,&intf,&scr));
    370         }
    371         pCfg->line_intf =  1 << intf;
    372         pCfg->scrambler_en = scr;
    373         
    374         rv = wc40_wb_sc_reinit(unit, port);
    375         if(rv == SOC_E_NONE){
    376             if(current_ver > pCfg->scache_ver) { /* upgrade expandsion and update */ 
    377                 SOC_IF_ERROR_RETURN(wc40_wb_sc_realloc_init(unit, port)) ;
    378                 SOC_IF_ERROR_RETURN(wc40_wb_sc_sync(unit, port)) ;
    379             }
    380         }else if(rv == SOC_E_NOT_FOUND){
    381             SOC_IF_ERROR_RETURN(wc40_wb_sc_init(unit, port)) ;
    382             SOC_IF_ERROR_RETURN(wc40_wb_sc_sync(unit, port)) ;
    383         }else{
    384             return rv;
    385         }
    386     } else {
    387             SOC_IF_ERROR_RETURN(wc40_wb_sc_init(unit, port)) ;
    388             SOC_IF_ERROR_RETURN(wc40_wb_sc_sync(unit, port)) ;
    389     }
    390 #endif
    391     
    392     return SOC_E_NONE;
    393 }
    394 
    395 STATIC int
    396 _phy_wc40_regbit_set_wait_check(phy_ctrl_t *pc,
    397                   int reg,   /* register to check */
    398                   int bit_num,   /* bit number to check */
    399                   int bitset, /* check bit set or bit clear */
    400                   int timeout,  /* max wait time to check */
    401                   int lane_ctrl) /*  point to the specified lane  */
    402 {
    403     uint16           data16 = 0;
    404     soc_timeout_t    to;
    405     int              rv;
    406     int  cond;
    407 
    408     soc_timeout_init(&to, timeout, 0);
    409     do {
    410         rv = WC40_REG_READ(pc->unit, pc, lane_ctrl, reg,&data16);
    411         cond = (bitset && (data16 & bit_num)) || 
    412                (!bitset && !(data16 & bit_num));
    413         if (cond || SOC_FAILURE(rv)) {
    414             break;
    415         }
    416     } while (!soc_timeout_check(&to));
    417     return (cond? SOC_E_NONE: SOC_E_TIMEOUT);
    418 }
    419 
    420 STATIC int
    421 _phy_wc40_pll_lock_wait(int unit, soc_port_t port)
    422 {
    423     phy_ctrl_t      *pc;
    424     int              rv;
    425 
    426     pc = INT_PHY_SW_STATE(unit, port);
    427     rv = _phy_wc40_regbit_set_wait_check(pc,WC40_XGXSBLK0_XGXSSTATUSr,
    428                      XGXSBLK0_XGXSSTATUS_TXPLL_LOCK_MASK,1,WC40_PLL_WAIT,0);
    429  
    430     if (rv == SOC_E_TIMEOUT) {
    431         LOG_WARN(BSL_LS_SOC_PHY,
    432                  (BSL_META_U(unit,
    433                              "WC40 : TXPLL did not lock: u=%d p=%d\n"),
    434                   unit, port));
    435         return (SOC_E_TIMEOUT);
    436     }
    437     return (SOC_E_NONE);
    438 }
    439 
    440 /*
    441  * Select the analog Rx div/16 and div/33 clocks for digital lanes 
    442  * this function must called after RX lane swap is done 
    443  */
    444 STATIC int
    445 _phy_wc40_rx_div16_clk_select(int unit, phy_ctrl_t *pc)
    446 {
    447     uint16 rxlane_map;
    448     uint16 data16;
    449     uint16 mask16;
    450     uint16 div16_mode;
    451     uint16 div33_mode;
    452 
    453     if (WC40_REVID_A0(pc) || WC40_REVID_A1(pc)) {
    454     
    455         /* check the pcs lane remapping register */
    456         SOC_IF_ERROR_RETURN     
    457             (READ_WC40_XGXSBLK8_RXLNSWAP1r(unit, pc, LANE0_ACCESS, &rxlane_map));
    458 
    459         SOC_IF_ERROR_RETURN     
    460             (MODIFY_WC40_XGXSBLK2_TESTMODEMUXr(unit, pc, LANE0_ACCESS,
    461                    (rxlane_map<<8),0xFF00));
    462 
    463         mask16 = 0x80;
    464         data16 = 0;
    465         /* enable override in single lane port */
    466         if (IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
    467             if (!IS_DUAL_LANE_PORT(pc)) {
    468                 data16 = mask16;
    469             }
    470         }
    471         SOC_IF_ERROR_RETURN     
    472             (MODIFY_WC40_XGXSBLK2_TESTMODEMUXr(unit, pc, LANE0_ACCESS, data16,mask16));
    473 
    474     } else { /* B0 and above */
    475         /* 
    476          * Table 20 Rev B0 Lane Swap Programming Settings
    477          * Mode       0x8108.7  0x82EC[8:5] 0x82EC[4:3]
    478          * Single     0x0   0x1         0x1
    479          * Dual       0x0   0x2         0x2
    480          * Quad       0x0   0x3         0x3
    481          */
    482         /* not to force the override */
    483         SOC_IF_ERROR_RETURN     
    484             (MODIFY_WC40_XGXSBLK2_TESTMODEMUXr(unit, pc, LANE0_ACCESS, 0,0x80));
    485 
    486         /* configure for single port mode */
    487         if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
    488             div16_mode = 1;
    489             div33_mode = 1;
    490 
    491         } else { /* quad-port or dual-port modes */
    492 
    493             /* dual-port mode */
    494             if (IS_DUAL_LANE_PORT(pc)) {
    495                 div16_mode = 2;
    496                 div33_mode = 2;
    497             } else {
    498             /* quad-port mode */
    499                 div16_mode = 3;
    500                 div33_mode = 3;
    501             }
    502         }
    503         SOC_IF_ERROR_RETURN     
    504             (MODIFY_WC40_CL72_USERB0_CL72_MISC4_CONTROLr(unit, pc, LANE0_ACCESS, 
    505               CL72_MISC4_CTRL_DIV16_FIELD(div16_mode) |
    506               CL72_MISC4_CTRL_DIV33_FIELD(div33_mode),
    507               CL72_MISC4_CTRL_DIV16_MASK |
    508               CL72_MISC4_CTRL_DIV33_MASK));
    509     } 
    510     return SOC_E_NONE;
    511 }
    512 
    513 STATIC int
    514 _phy_wc40_rxlane_map_set(int unit, phy_ctrl_t *pc, uint16 req_map)
    515 {
    516     uint16 i;
    517     uint16 lane, hw_map, chk_map;
    518 
    519     /* Update RX lane map */
    520 
    521     if (req_map != WC40_RX_LANE_MAP_DEFAULT) {
    522         hw_map  = 0;
    523         chk_map = 0;
    524         for (i = 0; i < 4; i++) {
    525             lane     = (req_map >> (i * 4)) & 0xf;
    526             hw_map  |= lane << (i * 2);
    527             chk_map |= 1 << lane;
    528         }
    529         if (chk_map == 0xf) {
    530 #ifdef WC40_PCS_LANE_SWAP
    531             SOC_IF_ERROR_RETURN     /* Enable RX Lane swap */
    532                (MODIFY_WC40_XGXSBLK8_RXLNSWAP1r(unit, pc, LANE0_ACCESS,
    533                    hw_map,
    534                    XGXSBLK2_RXLNSWAP_RX_LNSWAP_EN_MASK |
    535                    XGXSBLK8_RXLNSWAP1_RX0_LNSWAP_SEL_MASK |
    536                    XGXSBLK8_RXLNSWAP1_RX1_LNSWAP_SEL_MASK |
    537                    XGXSBLK8_RXLNSWAP1_RX2_LNSWAP_SEL_MASK |
    538                    XGXSBLK8_RXLNSWAP1_RX3_LNSWAP_SEL_MASK));
    539 #else
    540             SOC_IF_ERROR_RETURN     /* Enable RX Lane swap */
    541                (MODIFY_WC40_XGXSBLK2_RXLNSWAPr(unit, pc,
    542                    XGXSBLK2_RXLNSWAP_RX_LNSWAP_EN_MASK |
    543                    XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE_EN_MASK | hw_map,
    544                    XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE_EN_MASK | 
    545                    XGXSBLK2_RXLNSWAP_RX_LNSWAP_EN_MASK |
    546                    XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE0_MASK |
    547                    XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE1_MASK |
    548                    XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE2_MASK |
    549                    XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE3_MASK));
    550 #endif
    551         } else {
    552             LOG_ERROR(BSL_LS_SOC_PHY,
    553                       (BSL_META_U(unit,
    554                                   "unit %d port %s: Invalid RX lane map 0x%04x.\n"),
    555                        unit, SOC_PORT_NAME(unit, pc->port), req_map));
    556         }
    557     }
    558     return SOC_E_NONE;
    559 }
    560 STATIC int
    561 _phy_wc40_txlane_map_set(int unit, phy_ctrl_t *pc, uint16 req_map)
    562 {
    563     uint16 i;
    564     uint16 lane, hw_map, chk_map;
    565 
    566     /* Update TX lane map */
    567 
    568     if (req_map != WC40_TX_LANE_MAP_DEFAULT) {
    569         hw_map  = 0;
    570         chk_map = 0;
    571         for (i = 0; i < 4; i++) {
    572             lane     = (req_map >> (i * 4)) & 0xf;
    573             hw_map  |= lane << (i * 2);
    574             chk_map |= 1 << lane;
    575         }
    576         if (chk_map == 0xf) {
    577 #ifdef WC40_PCS_LANE_SWAP
    578             SOC_IF_ERROR_RETURN     /* Enable TX Lane swap */
    579                (MODIFY_WC40_XGXSBLK8_TXLNSWAP1r(unit, pc, LANE0_ACCESS,
    580                     hw_map,
    581                     XGXSBLK8_TXLNSWAP1_TX3_LNSWAP_SEL_MASK |
    582                     XGXSBLK8_TXLNSWAP1_TX2_LNSWAP_SEL_MASK |
    583                     XGXSBLK8_TXLNSWAP1_TX1_LNSWAP_SEL_MASK |
    584                     XGXSBLK8_TXLNSWAP1_TX0_LNSWAP_SEL_MASK));
    585 #else
    586             SOC_IF_ERROR_RETURN     /* Enable TX Lane swap */
    587                (MODIFY_WC40_XGXSBLK2_TXLNSWAPr(unit, pc, 0x00, 
    588                     XGXSBLK2_TXLNSWAP_TX_LNSWAP_EN_MASK | hw_map,
    589                     XGXSBLK2_TXLNSWAP_TX_LNSWAP_EN_MASK |
    590                     XGXSBLK2_TXLNSWAP_TX_LNSWAP_FORCE0_MASK |
    591                     XGXSBLK2_TXLNSWAP_TX_LNSWAP_FORCE1_MASK |
    592                     XGXSBLK2_TXLNSWAP_TX_LNSWAP_FORCE2_MASK |
    593                     XGXSBLK2_TXLNSWAP_TX_LNSWAP_FORCE3_MASK));
    594 #endif
    595         } else {
    596             LOG_ERROR(BSL_LS_SOC_PHY,
    597                       (BSL_META_U(unit,
    598                                   "unit %d port %s: Invalid TX lane map 0x%04x.\n"),
    599                        unit, SOC_PORT_NAME(unit, pc->port), req_map));
    600         }
    601     }
    602     return SOC_E_NONE;
    603 }
    604 
    605 STATIC int
    606 _phy_wc40_ind_lane_polarity_set (int unit, phy_ctrl_t *pc, int enable)
    607 {
    608     uint16 data16;
    609     uint16 mask16;
    610     int cur_lane = FALSE;
    611     int nxt_lane = FALSE;
    612 
    613     if (DEV_CFG_PTR(pc)->txpol) {
    614         /* Flip TX polarity */
    615         data16 = enable? TX0_ANATXACONTROL0_TXPOL_FLIP_MASK: 0;
    616         mask16 = TX0_ANATXACONTROL0_TXPOL_FLIP_MASK;
    617 
    618         if (IS_DUAL_LANE_PORT(pc)) {
    619             if (DEV_CFG_PTR(pc)->txpol == 1) {
    620                 cur_lane = TRUE;
    621                 nxt_lane = TRUE;
    622             } else {
    623                 if ((DEV_CFG_PTR(pc)->txpol & 0x000F) == 0x000F) {
    624                     cur_lane = TRUE;
    625                 } 
    626                 if ((DEV_CFG_PTR(pc)->txpol & 0x00F0) == 0x00F0) {
    627                     nxt_lane = TRUE;
    628                 }
    629             }
    630         } else {
    631             if((DEV_CFG_PTR(pc)->txpol == 1) 
    632                     || ((DEV_CFG_PTR(pc)->txpol & 0x000F) == 0x000F)) {
    633                 cur_lane = TRUE;
    634             }
    635         }
    636         
    637         if (cur_lane) {    
    638             SOC_IF_ERROR_RETURN
    639                 (WC40_REG_MODIFY(unit,pc,0x0,
    640                     WC40_TX0_ANATXACONTROL0r + (0x10 * pc->lane_num), 
    641                      data16, mask16));
    642         }
    643         if (nxt_lane) {    
    644             SOC_IF_ERROR_RETURN
    645                 (WC40_REG_MODIFY(unit,pc,0x0,
    646                     WC40_TX0_ANATXACONTROL0r + (0x10 * (pc->lane_num + 1)), 
    647                      data16, mask16));
    648         }
    649     }
    650 
    651     cur_lane = FALSE;
    652     nxt_lane = FALSE;
    653     if (DEV_CFG_PTR(pc)->rxpol) {
    654         /* Flip Rx polarity */
    655         mask16 = RX0_ANARXCONTROLPCI_RX_POLARITY_FORCE_SM_MASK |
    656                  RX0_ANARXCONTROLPCI_RX_POLARITY_R_MASK;
    657         data16 = enable? mask16: 0;
    658 
    659         if (IS_DUAL_LANE_PORT(pc)) {
    660             if (DEV_CFG_PTR(pc)->rxpol == 1) {
    661                 cur_lane = TRUE;
    662                 nxt_lane = TRUE;
    663             } else {
    664                 if ((DEV_CFG_PTR(pc)->rxpol & 0x000F) == 0x000F) {
    665                     cur_lane = TRUE;
    666                 }
    667                 if ((DEV_CFG_PTR(pc)->rxpol & 0x00F0) == 0x00F0) {
    668                     nxt_lane = TRUE;
    669                 }
    670             }
    671         } else {
    672             if((DEV_CFG_PTR(pc)->rxpol == 1) 
    673                     || ((DEV_CFG_PTR(pc)->rxpol & 0x000F) == 0x000F)) {
    674                 cur_lane = TRUE;
    675             }
    676         }
    677 
    678         if (cur_lane) {
    679             SOC_IF_ERROR_RETURN
    680                 (WC40_REG_MODIFY(unit,pc,0x0,
    681                     WC40_RX0_ANARXCONTROLPCIr + (0x10 * pc->lane_num),
    682                      data16, mask16));
    683         }
    684         if (nxt_lane) {
    685             SOC_IF_ERROR_RETURN
    686                 (WC40_REG_MODIFY(unit,pc,0x0,
    687                     WC40_RX0_ANARXCONTROLPCIr + (0x10 * (pc->lane_num + 1)),
    688                      data16, mask16));
    689         }
    690          
    691     }
    692     return SOC_E_NONE;
    693 }
    694 
    695 STATIC int 
    696 _phy_wc40_firmware_mode_set(int unit, soc_port_t port, uint32 value) {
    697     uint16 data16 = 0;
    698     uint16 mask16 = 0;
    699     int lane_start;
    700     int lane_end;
    701     int i, rv;
    702     phy_ctrl_t     *pc;
    703 
    704     /* Param 'value' check */
    705     switch(value) {
    706         case SOC_PHY_FIRMWARE_DEFAULT:
    707             value = UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_DEFAULT;
    708             break;
    709         case SOC_PHY_FIRMWARE_SFP_OPT_SR4:
    710             value = UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_SFP_OPT_LR;
    711             break;
    712         case SOC_PHY_FIRMWARE_SFP_DAC:
    713             value = UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_SFP_DAC;
    714             break;
    715         case SOC_PHY_FIRMWARE_XLAUI:
    716             value = UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_XLAUI;
    717             break;
    718         case SOC_PHY_FIRMWARE_FORCE_OSDFE:
    719             value = UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_LONG_CH_6G;
    720             break;
    721         case SOC_PHY_FIRMWARE_FORCE_BRDFE:
    722             value = UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_BR_DFE;
    723             break;
    724         case SOC_PHY_FIRMWARE_SW_CL72:
    725             value = UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_SW_CL72;
    726             break;
    727         case SOC_PHY_FIRMWARE_CL72_WITHOUT_AN:
    728             value = UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_CL72_WO_AN;
    729             break;
    730         default:
    731             return SOC_E_PARAM;
    732     }    
    733 
    734     pc = INT_PHY_SW_STATE(unit, port);
    735 
    736     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
    737         lane_start = 0;
    738         lane_end   = 3;
    739     } else if (IS_DUAL_LANE_PORT(pc)) {
    740         lane_start = pc->lane_num;
    741         lane_end = lane_start + 1;
    742     } else {  /* quad-port mode */
    743         lane_start = pc->lane_num;
    744         lane_end   = lane_start;
    745     }
    746 
    747     for(i = lane_start; i <= lane_end; ++i) {
    748         /* Restart the firmware */
    749         data16 = 3 << DSC1B0_UC_CTRL_SUPPLEMENT_INFO_SHIFT;
    750         data16 |= 1 << DSC1B0_UC_CTRL_GP_UC_REQ_SHIFT;
    751         mask16 = DSC1B0_UC_CTRL_SUPPLEMENT_INFO_MASK |
    752             DSC1B0_UC_CTRL_GP_UC_REQ_MASK;
    753         SOC_IF_ERROR_RETURN
    754             (MODIFY_WC40_DSC1B0_UC_CTRLr(unit, pc,
    755                                          ln_access[i],
    756                                          data16,mask16));
    757 
    758         /* wait for uC ready for command:  bit7=1 */
    759         rv = _phy_wc40_regbit_set_wait_check(pc,DSC1B0_UC_CTRLr,
    760                 DSC1B0_UC_CTRL_READY_FOR_CMD_MASK,
    761                 1, WC40_PLL_WAIT,ln_access[i]);
    762         if (rv == SOC_E_TIMEOUT) {
    763             LOG_WARN(BSL_LS_SOC_PHY,
    764                      (BSL_META_U(unit,
    765                                  "_phy_wc40_firmware_mode_set: uController not ready: u=%d p=%d\n lane=%d"), unit, port, i));
    766             return (SOC_E_TIMEOUT);
    767         }
    768 
    769         /* Stop the firmware */
    770         data16 = 0 << DSC1B0_UC_CTRL_SUPPLEMENT_INFO_SHIFT;
    771         data16 |= 1 << DSC1B0_UC_CTRL_GP_UC_REQ_SHIFT;    
    772         mask16 = DSC1B0_UC_CTRL_SUPPLEMENT_INFO_MASK |
    773             DSC1B0_UC_CTRL_GP_UC_REQ_MASK;
    774         SOC_IF_ERROR_RETURN
    775             (MODIFY_WC40_DSC1B0_UC_CTRLr(unit, pc, 
    776                                          ln_access[i], 
    777                                          data16,mask16));
    778 
    779         sal_usleep(1000);
    780         
    781         /* wait for uC ready for command:  bit7=1 */
    782         rv = _phy_wc40_regbit_set_wait_check(pc,DSC1B0_UC_CTRLr,
    783                 DSC1B0_UC_CTRL_READY_FOR_CMD_MASK,
    784                 1, WC40_PLL_WAIT,ln_access[i]);
    785         if (rv == SOC_E_TIMEOUT) {
    786             LOG_WARN(BSL_LS_SOC_PHY,
    787                      (BSL_META_U(unit,
    788                                  "_phy_wc40_firmware_mode_set: uController not ready (post stop): u=%d p=%d\n lane=%d"), unit, port, i));
    789             return (SOC_E_TIMEOUT);
    790         }
    791        
    792         /* Program firmware mode */
    793         mask16 = UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_MASK << 
    794             (UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_BITS * i);
    795         data16 = value << (UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_BITS * i);
    796         SOC_IF_ERROR_RETURN
    797             (MODIFY_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit, pc, 
    798                                             LANE0_ACCESS, data16, mask16));
    799 
    800         /* Resume the firmware */
    801         data16 = 2 << DSC1B0_UC_CTRL_SUPPLEMENT_INFO_SHIFT;
    802         data16 |= 1 << DSC1B0_UC_CTRL_GP_UC_REQ_SHIFT;    
    803         mask16 = DSC1B0_UC_CTRL_SUPPLEMENT_INFO_MASK |
    804             DSC1B0_UC_CTRL_GP_UC_REQ_MASK;
    805         SOC_IF_ERROR_RETURN
    806             (MODIFY_WC40_DSC1B0_UC_CTRLr(unit, pc, 
    807                                          ln_access[i], 
    808                                          data16,mask16));
    809         
    810         sal_usleep(1000);
    811         
    812         /* wait for uC ready for command:  bit7=1 */
    813         rv = _phy_wc40_regbit_set_wait_check(pc,DSC1B0_UC_CTRLr,
    814                 DSC1B0_UC_CTRL_READY_FOR_CMD_MASK,
    815                 1, WC40_PLL_WAIT,ln_access[i]);
    816         if (rv == SOC_E_TIMEOUT) {
    817             LOG_WARN(BSL_LS_SOC_PHY,
    818                      (BSL_META_U(unit,
    819                                  "_phy_wc40_firmware_mode_set: uController not ready (post resume): u=%d p=%d\n lane=%d"), unit, port, i));
    820             return (SOC_E_TIMEOUT);
    821         }
    822         
    823         /* Restart the firmware */
    824         data16 = 3 << DSC1B0_UC_CTRL_SUPPLEMENT_INFO_SHIFT;
    825         data16 |= 1 << DSC1B0_UC_CTRL_GP_UC_REQ_SHIFT;    
    826         mask16 = DSC1B0_UC_CTRL_SUPPLEMENT_INFO_MASK |
    827             DSC1B0_UC_CTRL_GP_UC_REQ_MASK;
    828         SOC_IF_ERROR_RETURN
    829             (MODIFY_WC40_DSC1B0_UC_CTRLr(unit, pc, 
    830                                          ln_access[i], 
    831                                          data16,mask16));
    832         
    833         
    834         sal_usleep(1000);
    835 
    836         /* wait for uC ready for command:  bit7=1 */
    837         rv = _phy_wc40_regbit_set_wait_check(pc,DSC1B0_UC_CTRLr,
    838                 DSC1B0_UC_CTRL_READY_FOR_CMD_MASK,
    839                 1, WC40_PLL_WAIT,ln_access[i]);
    840         if (rv == SOC_E_TIMEOUT) {
    841             LOG_WARN(BSL_LS_SOC_PHY,
    842                      (BSL_META_U(unit,
    843                                  "_phy_wc40_firmware_mode_set: uController not ready (post restart): u=%d p=%d lane=%d\n"), unit, port, i));
    844         }
    845     }
    846     if (DEV_CFG_PTR(pc)->fw_dfe == SOC_PHY_DFE_FREEZE) {
    847        rv = _phy_wc40_firmware_dfe_mode_set(unit, port, DEV_CFG_PTR(pc)->fw_dfe); 
    848        if (rv != SOC_E_NONE) {
    849            LOG_WARN(BSL_LS_SOC_PHY,
    850                 (BSL_META_U(unit,
    851                         "%s: DFE Set fail: u=%d p=%d\n"),__FUNCTION__, unit, port));
    852        }
    853     }
    854 
    855     return SOC_E_NONE;
    856 }
    857 
    858 STATIC int 
    859 _phy_wc40_firmware_mode_get(int unit, soc_port_t port, uint32 *value) {
    860     uint16 data16 = 0, temp16 = 0;
    861     int lane_start;
    862     int lane_end;
    863     int i;
    864     phy_ctrl_t     *pc;
    865 
    866     pc = INT_PHY_SW_STATE(unit, port);
    867     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
    868         lane_start = 0;
    869         lane_end   = 3;
    870     } else if (IS_DUAL_LANE_PORT(pc)) {
    871         lane_start = pc->lane_num;
    872         lane_end = lane_start + 1;
    873     } else {  /* quad-port mode */
    874         lane_start = pc->lane_num;
    875         lane_end   = lane_start;
    876     }
    877     
    878     /* Read firmware mode */
    879     SOC_IF_ERROR_RETURN
    880         (READ_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit, pc, 
    881                                              LANE0_ACCESS, &data16));
    882 
    883     /* Check all the lanes have matching firmware mode */
    884     *value = UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_MASK 
    885         & (data16 >> (UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_BITS * lane_start));
    886     for(i = lane_start + 1; i <= lane_end; ++i) {
    887         temp16 = UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_MASK
    888             & (data16 >> (UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_BITS * i));
    889     
    890         if(*value != temp16) {
    891             LOG_WARN(BSL_LS_SOC_PHY,
    892                      (BSL_META_U(unit,
    893                                  "WC: _phy_wc40_firmware_mode_get: "
    894                                  "value mismatch u=%d p=%d\n"), unit, port));
    895             return SOC_E_FAIL;
    896         }
    897 
    898     }
    899 
    900     switch(*value) {
    901         case UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_DEFAULT:
    902             *value = SOC_PHY_FIRMWARE_DEFAULT;
    903             break;
    904         case UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_SFP_OPT_LR:
    905             *value = SOC_PHY_FIRMWARE_SFP_OPT_SR4;
    906             break;
    907         case UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_SFP_DAC: 
    908             *value = SOC_PHY_FIRMWARE_SFP_DAC;
    909             break;
    910         case UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_XLAUI:
    911             *value = SOC_PHY_FIRMWARE_XLAUI;
    912             break;
    913         case UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_LONG_CH_6G:
    914             *value = SOC_PHY_FIRMWARE_FORCE_OSDFE;
    915             break;
    916         case UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_BR_DFE:
    917             *value = SOC_PHY_FIRMWARE_FORCE_BRDFE;
    918             break;
    919         case UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_SW_CL72:
    920             *value = SOC_PHY_FIRMWARE_SW_CL72;
    921             break;
    922         case UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_CL72_WO_AN:
    923             *value = SOC_PHY_FIRMWARE_CL72_WITHOUT_AN;
    924             break;
    925         default:
    926             break;
    927     }
    928     return SOC_E_NONE;
    929 }
    930 
    931 STATIC int 
    932 _phy_wc40_firmware_dfe_mode_set(int unit, soc_port_t port, uint32 value) {
    933     uint16 data16 = 0;
    934     uint16 mask16 = 0;
    935     int lane_start;
    936     int lane_end;
    937     int i, rv;
    938     phy_ctrl_t     *pc;
    939 
    940     /* Param 'value' check */
    941     switch(value) {
    942         case SOC_PHY_DFE_AUTO:
    943             data16 = 0 << DSC1B0_UC_CTRL_SUPPLEMENT_INFO_SHIFT;
    944             break;
    945         case SOC_PHY_DFE_FREEZE:
    946             data16 = 0x7f << DSC1B0_UC_CTRL_SUPPLEMENT_INFO_SHIFT;
    947             break;
    948         default:
    949             return SOC_E_PARAM;
    950     }    
    951     pc = INT_PHY_SW_STATE(unit, port);
    952 
    953     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
    954         lane_start = 0;
    955         lane_end   = 3;
    956     } else if (IS_DUAL_LANE_PORT(pc)) {
    957         lane_start = pc->lane_num;
    958         lane_end = lane_start + 1;
    959     } else {  /* quad-port mode */
    960         lane_start = pc->lane_num;
    961         lane_end   = lane_start;
    962     }
    963 
    964     for(i = lane_start; i <= lane_end; ++i) {
    965         /* wait for uC ready for command:  bit7=1 */
    966         rv = _phy_wc40_regbit_set_wait_check(pc,DSC1B0_UC_CTRLr,
    967                 DSC1B0_UC_CTRL_READY_FOR_CMD_MASK,
    968                 1, WC40_PLL_WAIT,ln_access[i]);
    969         if (rv == SOC_E_TIMEOUT) {
    970             LOG_WARN(BSL_LS_SOC_PHY,
    971                     (BSL_META_U(unit,
    972                                 "%s: uController not ready: u=%d p=%d\n lane=%d"),
    973                      __FUNCTION__, unit, port, i));
    974             return (SOC_E_TIMEOUT);
    975         }
    976         /*Command*/
    977         data16 |= 4 << DSC1B0_UC_CTRL_GP_UC_REQ_SHIFT;
    978         mask16 = DSC1B0_UC_CTRL_SUPPLEMENT_INFO_MASK |
    979                  DSC1B0_UC_CTRL_GP_UC_REQ_MASK;
    980         SOC_IF_ERROR_RETURN
    981             (MODIFY_WC40_DSC1B0_UC_CTRLr(unit, pc,
    982                                          ln_access[i],
    983                                          data16,mask16));
    984         
    985         sal_usleep(1000);
    986         /* wait for uC ready for command:  bit7=1 */
    987         rv = _phy_wc40_regbit_set_wait_check(pc,DSC1B0_UC_CTRLr,
    988                 DSC1B0_UC_CTRL_READY_FOR_CMD_MASK,
    989                 1, WC40_PLL_WAIT,ln_access[i]);
    990         if (rv == SOC_E_TIMEOUT) {
    991             LOG_WARN(BSL_LS_SOC_PHY,
    992                     (BSL_META_U(unit,
    993                                 "%s: uController not ready2: u=%d p=%d\n lane=%d"),
    994                      __FUNCTION__, unit, port, i));
    995         }
    996     }
    997     DEV_CFG_PTR(pc)->fw_dfe = value;
    998     return SOC_E_NONE;
    999 }
   1000 
   1001 STATIC int 
   1002 _phy_wc40_firmware_dfe_mode_get(int unit, soc_port_t port, uint32 *value) {
   1003     uint16 data16 = 0;
   1004     int rv, lane;
   1005     phy_ctrl_t     *pc;
   1006 
   1007     pc = INT_PHY_SW_STATE(unit, port);
   1008     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   1009         lane = 0;
   1010     } else if (IS_DUAL_LANE_PORT(pc)) {
   1011         lane = pc->lane_num;
   1012     } else {  /* quad-port mode */
   1013         lane = pc->lane_num;
   1014     }
   1015 
   1016     rv = _phy_wc40_regbit_set_wait_check(pc,DSC1B0_UC_CTRLr,
   1017             DSC1B0_UC_CTRL_READY_FOR_CMD_MASK,
   1018             1, WC40_PLL_WAIT,ln_access[lane]);
   1019     if (rv == SOC_E_TIMEOUT) {
   1020         LOG_WARN(BSL_LS_SOC_PHY,
   1021                  (BSL_META_U(unit,
   1022                             "%s: uController not ready: u=%d p=%d\n lane=%d"),
   1023                              __FUNCTION__, unit, port, lane));
   1024         return (SOC_E_TIMEOUT);
   1025     }
   1026     SOC_IF_ERROR_RETURN
   1027         (WRITE_WC40_DSC1B0_UC_CTRLr(unit, pc, ln_access[lane], 0x8004));
   1028     rv = _phy_wc40_regbit_set_wait_check(pc,DSC1B0_UC_CTRLr,
   1029             DSC1B0_UC_CTRL_READY_FOR_CMD_MASK,
   1030             1, WC40_PLL_WAIT,ln_access[lane]);
   1031     if (rv == SOC_E_TIMEOUT) {
   1032         LOG_WARN(BSL_LS_SOC_PHY,
   1033                 (BSL_META_U(unit,
   1034                             "%s: uController not ready2: u=%d p=%d\n lane=%d"),
   1035                  __FUNCTION__, unit, port, lane));
   1036         return (SOC_E_TIMEOUT);
   1037     }
   1038 
   1039     SOC_IF_ERROR_RETURN
   1040         (READ_WC40_DSC1B0_UC_CTRLr(unit, pc, ln_access[lane], &data16));
   1041     
   1042     switch(data16 >> DSC1B0_UC_CTRL_SUPPLEMENT_INFO_SHIFT) {
   1043         case 0x7f:
   1044             *value = SOC_PHY_DFE_FREEZE;
   1045             break;
   1046         default:
   1047             *value = SOC_PHY_DFE_AUTO;
   1048             break;
   1049     }
   1050     return SOC_E_NONE;
   1051 }
   1052 
   1053 
   1054 STATIC int
   1055 _phy_wc40_combo_polarity_set (int unit, phy_ctrl_t *pc, int enable)
   1056 {
   1057     uint16 data16;
   1058     uint16 mask16;
   1059     if (DEV_CFG_PTR(pc)->txpol) {
   1060         /* Flip TX polarity */
   1061         data16 = enable? TX0_ANATXACONTROL0_TXPOL_FLIP_MASK:0;
   1062         mask16 = TX0_ANATXACONTROL0_TXPOL_FLIP_MASK;
   1063         if (DEV_CFG_PTR(pc)->txpol == 1) {
   1064             SOC_IF_ERROR_RETURN
   1065                 (MODIFY_WC40_TXB_ANATXACONTROL0r(unit, pc, 0x00, data16, mask16));
   1066         }
   1067         if ((DEV_CFG_PTR(pc)->txpol & 0x000F) == 0x000F) {
   1068             SOC_IF_ERROR_RETURN
   1069               (MODIFY_WC40_TX0_ANATXACONTROL0r(unit, pc, 0x00, data16, mask16));
   1070         }
   1071         if ((DEV_CFG_PTR(pc)->txpol & 0x00F0) == 0x00F0) {
   1072             SOC_IF_ERROR_RETURN
   1073               (MODIFY_WC40_TX1_ANATXACONTROL0r(unit, pc, 0x00, data16, mask16));
   1074         }
   1075         if ((DEV_CFG_PTR(pc)->txpol & 0x0F00) == 0x0F00) {
   1076             SOC_IF_ERROR_RETURN
   1077               (MODIFY_WC40_TX2_ANATXACONTROL0r(unit, pc, 0x00, data16, mask16));
   1078         }
   1079         if ((DEV_CFG_PTR(pc)->txpol & 0xF000) == 0xF000) {
   1080             SOC_IF_ERROR_RETURN
   1081               (MODIFY_WC40_TX3_ANATXACONTROL0r(unit, pc, 0x00, data16, mask16));
   1082         }
   1083     }
   1084 
   1085     if (DEV_CFG_PTR(pc)->rxpol) {
   1086         /* Flip Rx polarity */
   1087         mask16 = RX0_ANARXCONTROLPCI_RX_POLARITY_FORCE_SM_MASK |
   1088                  RX0_ANARXCONTROLPCI_RX_POLARITY_R_MASK;
   1089         data16 = enable? mask16:0;
   1090         if (DEV_CFG_PTR(pc)->rxpol == 1) {
   1091             SOC_IF_ERROR_RETURN
   1092                 (MODIFY_WC40_RXB_ANARXCONTROLPCIr(unit,pc,0x00,data16,mask16));
   1093         } 
   1094         if ((DEV_CFG_PTR(pc)->rxpol & 0x000F) == 0x000F) {
   1095             SOC_IF_ERROR_RETURN
   1096                 (MODIFY_WC40_RX0_ANARXCONTROLPCIr(unit,pc,0x00,data16,mask16));
   1097         } 
   1098         if ((DEV_CFG_PTR(pc)->rxpol & 0x00F0) == 0x00F0) {
   1099             SOC_IF_ERROR_RETURN
   1100                 (MODIFY_WC40_RX1_ANARXCONTROLPCIr(unit,pc,0x00,data16,mask16));
   1101         } 
   1102         if ((DEV_CFG_PTR(pc)->rxpol & 0x0F00) == 0x0F00) {
   1103             SOC_IF_ERROR_RETURN
   1104                 (MODIFY_WC40_RX2_ANARXCONTROLPCIr(unit,pc,0x00,data16,mask16));
   1105         } 
   1106         if ((DEV_CFG_PTR(pc)->rxpol & 0xF000) == 0xF000) {
   1107             SOC_IF_ERROR_RETURN
   1108                 (MODIFY_WC40_RX3_ANARXCONTROLPCIr(unit,pc,0x00,data16,mask16));
   1109         }
   1110     }
   1111     return SOC_E_NONE;
   1112 }
   1113 
   1114 STATIC int
   1115 _phy_wc40_cl72_enable(int unit, soc_port_t port, int en)
   1116 {
   1117     phy_ctrl_t     *pc;
   1118 
   1119     pc = INT_PHY_SW_STATE(unit, port);
   1120 
   1121     if (IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   1122         DUAL_LANE_BCST_ENABLE(pc);
   1123         /* disable KR PMD start-up protocol */
   1124         SOC_IF_ERROR_RETURN
   1125           (MODIFY_WC40_PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150r(unit,pc,0x00,
   1126              en? PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150_TRAINING_ENABLE_MASK: 0,
   1127              PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150_TRAINING_ENABLE_MASK));
   1128 
   1129         SOC_IF_ERROR_RETURN
   1130             (MODIFY_WC40_CL72_USERB0_CL72_MISC1_CONTROLr(unit, pc, 0x00,
   1131                en? 0:CL72_USERB0_CL72_MISC1_CONTROL_LINK_CONTROL_FORCE_MASK,
   1132                CL72_USERB0_CL72_MISC1_CONTROL_LINK_CONTROL_FORCE_MASK));
   1133         DUAL_LANE_BCST_DISABLE(pc);
   1134 
   1135     } else {  /* combo mode */
   1136         /* bcst to PMD */
   1137         SOC_IF_ERROR_RETURN
   1138             (WRITE_WC40_AERBLK_AERr(unit,pc,0x00,
   1139                      (AERBLK_AER_MMD_DEVICETYPE_PMA_PMD <<
   1140                      AERBLK_AER_MMD_DEVICETYPE_SHIFT) |
   1141                      WC_AER_BCST_OFS_STRAP));
   1142 
   1143         SOC_IF_ERROR_RETURN
   1144           (WC40_REG_MODIFY(unit, pc, 0x00,  0x0096,
   1145              en? PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150_TRAINING_ENABLE_MASK: 0,
   1146              PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150_TRAINING_ENABLE_MASK));
   1147 
   1148         SOC_IF_ERROR_RETURN
   1149             (MODIFY_WC40_CL72_USERB0_CL72_MISC1_CONTROLr(unit, pc, 0x00,
   1150                en? 0:CL72_USERB0_CL72_MISC1_CONTROL_LINK_CONTROL_FORCE_MASK,
   1151                CL72_USERB0_CL72_MISC1_CONTROL_LINK_CONTROL_FORCE_MASK));
   1152 
   1153         /* restore AER */
   1154         SOC_IF_ERROR_RETURN
   1155             (WRITE_WC40_AERBLK_AERr(unit,pc,0x00,0));
   1156     }
   1157     return SOC_E_NONE;
   1158 }
   1159 
   1160 /*
   1161  * Function:
   1162  *      _phy_wc40_firmware_force_cl72_config
   1163  * Purpose:     
   1164  *      Configure the device to perform CL72 tunning in forced mode 
   1165  *      (w/o autoneg) through firmware 
   1166  * Parameters:
   1167  *      unit - StrataSwitch unit #.
   1168  *      port - StrataSwitch port #.
   1169  *      enable - Forced_CL72_WO_AN enable  
   1170  * Returns:     
   1171  *      SOC_E_NONE
   1172  */
   1173 STATIC int
   1174 _phy_wc40_firmware_force_cl72_config(int unit, soc_port_t port, int enable)
   1175 {
   1176     uint16 data16;
   1177     uint16 mask16;
   1178     int lane_start;
   1179     int lane_end;
   1180     int pll_reset = 0x00;
   1181     int i, rv;
   1182     phy_ctrl_t     *pc;
   1183     
   1184     pc = INT_PHY_SW_STATE(unit, port);
   1185 
   1186     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   1187         lane_start = 0;
   1188         lane_end   = 3;
   1189     } else if (IS_DUAL_LANE_PORT(pc)) {
   1190         lane_start = pc->lane_num;
   1191         lane_end = lane_start + 1;
   1192     } else {  /* quad-port mode */
   1193         lane_start = pc->lane_num;
   1194         lane_end   = lane_start;
   1195     }
   1196     
   1197 
   1198     if(enable) {
   1199         /* 1. Program PLL into reset by programming 0x8000.13 == 1'b0. */
   1200         SOC_IF_ERROR_RETURN
   1201             (READ_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00, &data16));
   1202         mask16 = XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK;
   1203         if(data16 & mask16) {
   1204             /* Reset only if it is not already in reset */
   1205             pll_reset = 1;
   1206             data16 = 0x00;
   1207             SOC_IF_ERROR_RETURN
   1208                 (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00,
   1209                                               data16, mask16));
   1210         }
   1211     }
   1212     for (i = lane_start; i <= lane_end; i++) {
   1213         /* Restart_cl72_training */
   1214         mask16 =
   1215         PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150_TRAINING_ENABLE_MASK;
   1216         data16 = enable? mask16 : 0;
   1217         if (!(SOC_IS_KATANA2(unit)) && !(lane_start == lane_end)) {/* Skiped for HG[11] */
   1218             SOC_IF_ERROR_RETURN
   1219               (MODIFY_WC40_PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150r(unit, 
   1220                   pc, ln_access[i], data16, mask16));
   1221         }
   1222         /* 3. Enable cl72 (0x82E3[15:14] == 0x3)
   1223          *    0x82e3[15:14]=0x3 force enable cl72
   1224          *                 =0x2 force disable cl72
   1225          *                 =0x0 controlled by autoneg
   1226          */
   1227         mask16 = CL72_USERB0_CL72_MISC1_CONTROL_LINK_CONTROL_FORCE_MASK |
   1228                  CL72_USERB0_CL72_MISC1_CONTROL_LINK_CONTROL_FORCEVAL_MASK;
   1229         data16 = enable? mask16: 
   1230                        CL72_USERB0_CL72_MISC1_CONTROL_LINK_CONTROL_FORCE_MASK;
   1231         SOC_IF_ERROR_RETURN
   1232             (MODIFY_WC40_CL72_USERB0_CL72_MISC1_CONTROLr(unit, pc, 
   1233                 ln_access[i], data16, mask16));
   1234         
   1235         /* 4. Disable CL72 timers */
   1236         mask16 = CL72_USERB0_CL72_MISC2_CONTROL_DIS_MAX_WAIT_TIMER_FORCE_MASK |
   1237              CL72_USERB0_CL72_MISC2_CONTROL_DIS_MAX_WAIT_TIMER_FORCEVAL_MASK;
   1238         data16 = enable? mask16: 0;
   1239         SOC_IF_ERROR_RETURN
   1240             (MODIFY_WC40_CL72_USERB0_CL72_MISC2_CONTROLr(unit, pc, 
   1241                 ln_access[i], data16, mask16));
   1242 
   1243        /* 5. 0x82e2[15] = 0 */ 
   1244         mask16 = CL72_USERB0_CL72_TX_FIR_TAP_REGISTER_TX_FIR_TAP_FORCE_MASK;
   1245         data16 = 0;
   1246         SOC_IF_ERROR_RETURN
   1247             (MODIFY_WC40_CL72_USERB0_CL72_TX_FIR_TAP_REGISTERr(unit, pc, 
   1248                 ln_access[i], data16, mask16));
   1249 
   1250        /* 6. Program firmware mode (per lane) to 0x7. */
   1251        mask16 = UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_MASK << 
   1252                            (UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_BITS * i);
   1253        data16 = enable? WC40_UC_CTRL_CL72_WO_AN : WC40_UC_CTRL_DEFAULT;
   1254        SOC_IF_ERROR_RETURN
   1255            (MODIFY_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit, pc, 
   1256                                              LANE0_ACCESS, data16, mask16));
   1257 
   1258     }
   1259 
   1260     /* 7. Program Core PLL speed by setting 0x81FB[11:7] == 0x16 (22). 
   1261      *    val = 0x16, PLL rate forced to 11.00GHz 
   1262      *    val = 00, default (PLL rate computed from forced speed reg)
   1263      */
   1264     mask16 =  WC40_UC_INFO_B1_REGB_SERDES_PLL_RATE_MASK; 
   1265     data16 = enable? 0x16 << WC40_UC_INFO_B1_REGB_SERDES_PLL_RATE_SHIFT: 0;
   1266     SOC_IF_ERROR_RETURN    
   1267         (MODIFY_WC40_UC_INFO_B1_REGBr(unit, pc, 0x00, data16, mask16)); 
   1268             
   1269     
   1270     if(enable) {   
   1271         for(i = lane_start; i <= lane_end; ++i) {
   1272 
   1273             /* wait for uC ready for command:  bit7=1 */
   1274             rv = _phy_wc40_regbit_set_wait_check(pc,DSC1B0_UC_CTRLr,
   1275                                  DSC1B0_UC_CTRL_READY_FOR_CMD_MASK,
   1276                                  1, WC40_PLL_WAIT,ln_access[i]);
   1277             if (rv == SOC_E_TIMEOUT) {
   1278                 LOG_WARN(BSL_LS_SOC_PHY,
   1279                          (BSL_META_U(unit,
   1280                                      "WC: Force CL72 uController not ready: u=%d p=%d\n"), 
   1281                           unit, port));
   1282                 return (SOC_E_TIMEOUT);
   1283             }
   1284 
   1285             /* 8. Write below values in one mdio write command. 
   1286              *    This write should be done before configuring any 
   1287              *    speed. 
   1288              *  a. 0x820E[15:8] = 0x3 restart link 
   1289              *  b. 0x820E[7:6] = 0x0  ready_cmd =0 , error =0 
   1290              *  c. 0x820E[3:0] = 0x1  command restart 
   1291             */
   1292             data16 = 3 << DSC1B0_UC_CTRL_SUPPLEMENT_INFO_SHIFT;
   1293             data16 |= 1;    
   1294             mask16 = DSC1B0_UC_CTRL_SUPPLEMENT_INFO_MASK |
   1295                      DSC1B0_UC_CTRL_GP_UC_REQ_MASK;
   1296             SOC_IF_ERROR_RETURN
   1297                 (MODIFY_WC40_DSC1B0_UC_CTRLr(unit, pc, 
   1298                                              ln_access[i], 
   1299                                              data16,mask16));
   1300         }
   1301     }
   1302     
   1303     sal_udelay(4000);
   1304     
   1305     /* 9. Release PLL reset (0x8000.13 == 1'b1). */
   1306     if(pll_reset && enable) {
   1307         /* if this routine did pll reset, release pll reset */
   1308         mask16 = XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK;
   1309         data16 = mask16;
   1310         SOC_IF_ERROR_RETURN
   1311             (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00,
   1312                                           data16, mask16));
   1313         (void) _phy_wc40_pll_lock_wait(unit, port);
   1314         _phy_wc40_control_vco_disturbed_set(unit, port);
   1315     }
   1316  
   1317     FORCE_CL72_STATE(pc) = WC40_FORCED_CL72_STATE_WAIT_4_LINK;
   1318     FORCE_CL72_TICK_CNT(pc) = 0;
   1319 
   1320     return SOC_E_NONE;
   1321 }
   1322 
   1323 /* 
   1324  * configure the device to perform CL72 tunning in forced mode thru software 
   1325  */
   1326 
   1327 STATIC int
   1328 _phy_wc40_force_cl72_config(int unit, soc_port_t port, int enable)
   1329 {
   1330     uint16 data16;
   1331     uint16 mask16;
   1332     uint16 ver = 0;
   1333     int lane_start;
   1334     int lane_end;
   1335     int i;
   1336     phy_ctrl_t     *pc;
   1337     WC40_TX_DRIVE_t tx_drv[NUM_LANES];
   1338 
   1339     pc = INT_PHY_SW_STATE(unit, port);
   1340 
   1341     SOC_IF_ERROR_RETURN
   1342         (READ_WC40_UC_INFO_B1_VERSIONr(unit, pc, 0x00, &ver));
   1343     
   1344     /* Decide whether to use forced cl72 
   1345        software implementation or firmware implementation (hw)
   1346        For firmware version >= 0xd10a, use firmware implementation.
   1347      */
   1348     if( ((ver >= 0xd10a) || ((ver & 0xD000) == 0)) 
   1349             && (DEV_CFG_PTR(pc)->force_cl72_fw))
   1350     {
   1351         _phy_wc40_firmware_force_cl72_config(unit, port, enable);
   1352         return SOC_E_NONE;
   1353     }
   1354 
   1355     DEV_CFG_PTR(pc)->force_cl72_fw  = FALSE;
   1356 
   1357     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   1358         lane_start = 0;
   1359         lane_end   = 3;
   1360     } else if (IS_DUAL_LANE_PORT(pc)) {
   1361         lane_start = pc->lane_num;
   1362         lane_end = lane_start + 1;
   1363     } else {  /* quad-port mode */
   1364         lane_start = pc->lane_num;
   1365         lane_end   = lane_start;
   1366     }
   1367 
   1368     for (i = lane_start; i <= lane_end; i++) {
   1369         if (enable) { 
   1370             /* enable sigdet status */ 
   1371             SOC_IF_ERROR_RETURN
   1372                 (WC40_REG_MODIFY(unit,pc,LANE0_ACCESS,
   1373                    0x80b1 + (0x10 * i), 
   1374                    RX0_ANARXCONTROL_STATUS_SEL_sigdetStatus,
   1375                    RX0_ANARXCONTROL_STATUS_SEL_MASK));
   1376         }
   1377 
   1378         /* Disable CL72 timers */
   1379         mask16 = CL72_USERB0_CL72_MISC2_CONTROL_DIS_MAX_WAIT_TIMER_FORCE_MASK |
   1380              CL72_USERB0_CL72_MISC2_CONTROL_DIS_MAX_WAIT_TIMER_FORCEVAL_MASK;
   1381         data16 = enable? mask16: 0;
   1382         SOC_IF_ERROR_RETURN
   1383             (MODIFY_WC40_CL72_USERB0_CL72_MISC2_CONTROLr(unit, pc, 
   1384                 ln_access[i], data16, mask16));
   1385 
   1386         /* 0x82e3[15:14]=0x3 force enable cl72
   1387          *              =0x2 force disable cl72
   1388          *              =0x0 controlled by autoneg
   1389          */
   1390         mask16 = CL72_USERB0_CL72_MISC1_CONTROL_LINK_CONTROL_FORCE_MASK |
   1391                  CL72_USERB0_CL72_MISC1_CONTROL_LINK_CONTROL_FORCEVAL_MASK;
   1392         data16 = enable? mask16: 
   1393                        CL72_USERB0_CL72_MISC1_CONTROL_LINK_CONTROL_FORCE_MASK;
   1394         SOC_IF_ERROR_RETURN
   1395             (MODIFY_WC40_CL72_USERB0_CL72_MISC1_CONTROLr(unit, pc, 
   1396                 ln_access[i], data16, mask16));
   1397     
   1398         if (!enable) {
   1399             (void)_phy_wc40_tx_disable(unit,port,lane_start,lane_end,FALSE);
   1400 
   1401             /* clear rx pi reset */
   1402             mask16 = DSC1B0_PI_CTRL0_PI_CW_RST_MASK;
   1403             data16 = 0;
   1404             SOC_IF_ERROR_RETURN
   1405                 (MODIFY_WC40_DSC1B0_PI_CTRL0r(unit, pc, ln_access[i], data16,
   1406                       mask16));
   1407 
   1408             /* clear rx_asic reset */
   1409             mask16 = DIGITAL5_MISC6_RESET_RX_ASIC_MASK;
   1410             data16 = 0;
   1411             SOC_IF_ERROR_RETURN
   1412              (MODIFY_WC40_DIGITAL5_MISC6r(unit, pc, ln_access[i], data16,
   1413                       mask16));
   1414         }   
   1415     }
   1416     if (enable) {
   1417         /* set uC firmware mode to default */
   1418         SOC_IF_ERROR_RETURN
   1419             (WRITE_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit, pc, 0x00, 0x0));
   1420 
   1421         /* configure the TX driver parameters, use AN entry  */
   1422         SOC_IF_ERROR_RETURN
   1423             (_phy_wc40_tx_control_get(unit, port,&tx_drv[0],TXDRV_AN_INX));
   1424         SOC_IF_ERROR_RETURN
   1425             (_phy_wc40_tx_control_set(unit, port,&tx_drv[0]));
   1426 
   1427         FORCE_CL72_STATE(pc) = WC40_CL72_STATE_LINK_CHECK;
   1428         FORCE_CL72_TICK_CNT(pc) = 0;
   1429     }
   1430     return SOC_E_NONE; 
   1431 }
   1432 
   1433 STATIC int
   1434 _phy_wc40_tx_disable(int unit, soc_port_t port, int lane_start, int lane_end, int disable)
   1435 {
   1436     uint16 data16;
   1437     uint16 mask16;
   1438     int i;
   1439     phy_ctrl_t     *pc;
   1440     pc = INT_PHY_SW_STATE(unit, port);
   1441 
   1442     for (i = lane_start; i <= lane_end; i++) {
   1443         /* tx enable */
   1444         mask16 = TXB_TX_DRIVER_ELECIDLE_MASK;
   1445         data16 = disable? mask16: 0;
   1446         SOC_IF_ERROR_RETURN
   1447                 (WC40_REG_MODIFY(unit,pc,LANE0_ACCESS,
   1448                    0x8067 + (0x10 * i), data16, mask16));
   1449     }
   1450     return SOC_E_NONE;
   1451 }
   1452 
   1453 STATIC int
   1454 _phy_wc40_force_cl72_init(int unit, soc_port_t port)
   1455 {
   1456     uint16 data16;
   1457     uint16 mask16;
   1458     uint16 ver;
   1459     int lane_start;
   1460     int lane_end;
   1461     int i;
   1462     phy_ctrl_t     *pc;
   1463     pc = INT_PHY_SW_STATE(unit, port);
   1464 
   1465     SOC_IF_ERROR_RETURN
   1466         (READ_WC40_UC_INFO_B1_VERSIONr(unit, pc, 0x00, &ver));
   1467 
   1468     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   1469         lane_start = 0;
   1470         lane_end   = 3;
   1471     } else if (IS_DUAL_LANE_PORT(pc)) {
   1472         lane_start = pc->lane_num;
   1473         lane_end = lane_start + 1;
   1474     } else {  /* quad-port mode */
   1475         lane_start = pc->lane_num;
   1476         lane_end   = lane_start;
   1477     }
   1478 
   1479     for (i = lane_start; i <= lane_end; i++) {
   1480          /* toggle reset_cl72 */
   1481          mask16 = CL72_USERB1_CL72_DEBUG_4_REGISTER_MICRO_REG_RESET_MASK;
   1482          data16 = 0;
   1483          SOC_IF_ERROR_RETURN
   1484              (MODIFY_WC40_CL72_USERB1_CL72_DEBUG_4_REGISTERr(unit, pc, 
   1485                     ln_access[i], data16,mask16));
   1486 
   1487          data16 = mask16;
   1488          SOC_IF_ERROR_RETURN
   1489              (MODIFY_WC40_CL72_USERB1_CL72_DEBUG_4_REGISTERr(unit, pc, 
   1490                     ln_access[i], data16,mask16));
   1491 
   1492          /* rx_asic_reset: put receiver in reset state */
   1493          mask16 = DIGITAL5_MISC6_RESET_RX_ASIC_MASK;
   1494          data16 = mask16;
   1495          SOC_IF_ERROR_RETURN
   1496              (MODIFY_WC40_DIGITAL5_MISC6r(unit, pc, ln_access[i], data16, 
   1497                       mask16));
   1498 
   1499          /* firmware version d109 and above doesn't need pi reset*/
   1500          if ((ver >= 0xd100) && (ver <= 0xd108)) {
   1501              /* toggle rx pi reset */
   1502              mask16 = DSC1B0_PI_CTRL0_PI_CW_RST_MASK;
   1503              data16 = mask16;
   1504              SOC_IF_ERROR_RETURN
   1505                  (MODIFY_WC40_DSC1B0_PI_CTRL0r(unit, pc, ln_access[i], data16, 
   1506                       mask16));
   1507 
   1508              data16 = 0;
   1509              SOC_IF_ERROR_RETURN
   1510                  (MODIFY_WC40_DSC1B0_PI_CTRL0r(unit, pc, ln_access[i], data16, 
   1511                       mask16));
   1512          }
   1513 
   1514          /* rxseqstart */
   1515          mask16 = DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_MASK;
   1516          data16 = mask16;
   1517          SOC_IF_ERROR_RETURN
   1518              (MODIFY_WC40_DSC2B0_DSC_MISC_CTRL0r(unit, pc, ln_access[i], 
   1519                       data16, mask16));
   1520 
   1521          data16 = 0;
   1522          SOC_IF_ERROR_RETURN
   1523              (MODIFY_WC40_DSC2B0_DSC_MISC_CTRL0r(unit, pc, ln_access[i],
   1524                       data16, mask16));
   1525 
   1526          /* restart_cl72_training */
   1527          mask16 = PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150_RESTART_TRAINING_MASK;
   1528          mask16 |=
   1529          PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150_TRAINING_ENABLE_MASK;
   1530          data16 = mask16;
   1531          SOC_IF_ERROR_RETURN
   1532           (MODIFY_WC40_PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150r(unit, 
   1533               pc, ln_access[i], data16, mask16));
   1534 
   1535         /* bring rx_asic out of reset */
   1536         mask16 = DIGITAL5_MISC6_RESET_RX_ASIC_MASK;
   1537         data16 = 0;
   1538         SOC_IF_ERROR_RETURN
   1539             (MODIFY_WC40_DIGITAL5_MISC6r(unit, pc, ln_access[i], 
   1540                     data16, mask16));
   1541 
   1542         /* remove transmit_disable */
   1543         (void)_phy_wc40_tx_disable(unit,port,lane_start,lane_end,FALSE);
   1544     }
   1545     return SOC_E_NONE;
   1546 }
   1547 
   1548 STATIC int 
   1549 _phy_wc40_firmware_force_cl72_state_machine(int unit, soc_port_t port,int link)
   1550 {
   1551     int lane;
   1552     int lane_start;
   1553     int lane_end;
   1554     int rv = SOC_E_NONE;
   1555     uint16 data16, mask16, pmd_restarted = 0x1;
   1556     phy_ctrl_t     *pc;
   1557     pc = INT_PHY_SW_STATE(unit, port);
   1558 
   1559     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   1560         lane_start = 0;
   1561         lane_end   = 3; 
   1562     } else if (IS_DUAL_LANE_PORT(pc)) {
   1563         lane_start = pc->lane_num;
   1564         lane_end = lane_start + 1;
   1565     } else {  /* quad-port mode */
   1566         lane_start = pc->lane_num;
   1567         lane_end   = lane_start;
   1568     }
   1569 
   1570 
   1571     switch (FORCE_CL72_STATE(pc)) {
   1572         case WC40_FORCED_CL72_STATE_RESET:
   1573              
   1574             for(lane = lane_start; lane <= lane_end; ++lane) {
   1575 
   1576                 /* wait for uC ready for command:  bit7=1 */
   1577                 rv = _phy_wc40_regbit_set_wait_check(pc,DSC1B0_UC_CTRLr,
   1578                                  DSC1B0_UC_CTRL_READY_FOR_CMD_MASK,
   1579                                  1, WC40_PLL_WAIT,ln_access[lane]);
   1580                 if (rv == SOC_E_TIMEOUT) {
   1581                     LOG_WARN(BSL_LS_SOC_PHY,
   1582                              (BSL_META_U(unit,
   1583                                          "WC: Force CL72 uController not ready: u=%d p=%d\n"), 
   1584                               unit, port));
   1585                     return (SOC_E_TIMEOUT);
   1586                 }
   1587 
   1588                 /* Write below values in one mdio write command. 
   1589                  * This write should be done before configuring any 
   1590                  * speed. 
   1591                  *  a. 0x820E[15:8] = 0x3 restart link 
   1592                  *  b. 0x820E[7:6] = 0x0  ready_cmd =0 , error =0 
   1593                  *  c. 0x820E[3:0] = 0x1  command restart 
   1594                  */
   1595                 data16 = 3 << DSC1B0_UC_CTRL_SUPPLEMENT_INFO_SHIFT;
   1596                 data16 |= 1;    
   1597                 mask16 = DSC1B0_UC_CTRL_SUPPLEMENT_INFO_MASK |
   1598                          DSC1B0_UC_CTRL_GP_UC_REQ_MASK;
   1599                 SOC_IF_ERROR_RETURN
   1600                     (MODIFY_WC40_DSC1B0_UC_CTRLr(unit, pc, 
   1601                                                  ln_access[lane], 
   1602                                                  data16,mask16));
   1603             }
   1604 
   1605             FORCE_CL72_STATE(pc) = WC40_FORCED_CL72_STATE_WAIT_4_LINK;
   1606             FORCE_CL72_TICK_CNT(pc) = 0;
   1607             LOG_INFO(BSL_LS_SOC_PHY,
   1608                      (BSL_META_U(unit,
   1609                                  "WC: force cl72: u=%d p=%d state STATE_RESET\n"), 
   1610                       unit, port));
   1611             break;
   1612 
   1613         case WC40_FORCED_CL72_STATE_WAIT_4_LINK:
   1614             if(link) {
   1615                 /* Set pmd_restarted=0 for uController.
   1616                    Reg 0x81F7..0x81FA[0]= 0
   1617                  */
   1618                 for(lane = lane_start; lane <= lane_end; ++lane) {
   1619                     SOC_IF_ERROR_RETURN
   1620                         (WC40_REG_MODIFY(unit, pc, LANE0_ACCESS, 
   1621                                  0x81f7 + (0x1 * lane), 0, 1));
   1622                 }
   1623                 FORCE_CL72_STATE(pc) = WC40_FORCED_CL72_STATE_LINK_GOOD;
   1624             } else { /* link down */
   1625                 FORCE_CL72_TICK_CNT(pc) += 1;
   1626                 if (FORCE_CL72_TICK_CNT(pc) > 
   1627                                   WC40_FORCED_CL72_LINK_WAIT_CNT_LIMIT) {
   1628                     /* Timer expired, do not wait anymore - restart*/
   1629                     FORCE_CL72_STATE(pc) = WC40_FORCED_CL72_STATE_RESET;
   1630                     FORCE_CL72_TICK_CNT(pc) = 0;
   1631                 }
   1632             } 
   1633             LOG_INFO(BSL_LS_SOC_PHY,
   1634                      (BSL_META_U(unit,
   1635                                  "WC: force cl72: u=%d p=%d state WAIT 4 LINK: "
   1636                                  "link: 0x%x\n"), unit, port, link));
   1637             break;
   1638 
   1639         case WC40_FORCED_CL72_STATE_LINK_GOOD:
   1640             if (link == FALSE) {
   1641                 pmd_restarted = 0x1; 
   1642                 for(lane = lane_start; lane <= lane_end; ++lane) {
   1643                     SOC_IF_ERROR_RETURN
   1644                         (WC40_REG_READ(unit, pc, LANE0_ACCESS, 
   1645                                  0x81f7 + (0x1 * lane), &data16));
   1646                     pmd_restarted &= (data16 & 0x1);
   1647                     if(!pmd_restarted) {
   1648                         LOG_INFO(BSL_LS_SOC_PHY,
   1649                                  (BSL_META_U(unit,
   1650                                              "WC: force cl72: u=%d p=%d state LINK GOOD "
   1651                                              "pmd_restarted=0: " "link: 0x%x\n"), unit, port, link));
   1652                         break;
   1653                     }
   1654 
   1655                 }
   1656                 FORCE_CL72_STATE(pc) = pmd_restarted ? 
   1657                                      WC40_FORCED_CL72_STATE_WAIT_4_LINK : 
   1658                                      WC40_FORCED_CL72_STATE_RESET;
   1659                 FORCE_CL72_TICK_CNT(pc) = 0;
   1660             
   1661                 LOG_INFO(BSL_LS_SOC_PHY,
   1662                          (BSL_META_U(unit,
   1663                                      "WC: force cl72: u=%d p=%d state LINK GOOD: "
   1664                                      "link: 0x%x\n"), unit, port, link));
   1665             }
   1666             break;
   1667         default:
   1668             break;
   1669     } 
   1670     return rv;
   1671 }
   1672 
   1673 STATIC int
   1674 _phy_wc40_force_cl72_state_machine(int unit, soc_port_t port,int link)
   1675 {
   1676     uint16 data16;
   1677     int i;
   1678     int lane_start;
   1679     int lane_end;
   1680     int sig_loss;
   1681     phy_ctrl_t     *pc;
   1682     pc = INT_PHY_SW_STATE(unit, port);
   1683     
   1684     /* Decide whether to use forced cl72 
   1685        software implementation or firmware implementation (hw)
   1686        For firmware version >= 0xd10a, use firmware implementation.
   1687     */
   1688     if(DEV_CFG_PTR(pc)->force_cl72_fw)
   1689     {
   1690         _phy_wc40_firmware_force_cl72_state_machine(unit, port, link);
   1691         return SOC_E_NONE;
   1692     }
   1693 
   1694     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   1695         lane_start = 0;
   1696         lane_end   = 3; 
   1697     } else if (IS_DUAL_LANE_PORT(pc)) {
   1698         lane_start = pc->lane_num;
   1699         lane_end = lane_start + 1;
   1700     } else {  /* quad-port mode */
   1701         lane_start = pc->lane_num;
   1702         lane_end   = lane_start;
   1703     }
   1704     
   1705     switch (FORCE_CL72_STATE(pc)) {
   1706         case WC40_CL72_STATE_TX_DISABLED:
   1707             FORCE_CL72_STATE(pc) = WC40_CL72_STATE_INIT_CL72;
   1708             LOG_VERBOSE(BSL_LS_SOC_PHY,
   1709                         (BSL_META_U(unit,
   1710                                     "force cl72: u=%d p=%d state TX_DISABLED\n"), unit, port));
   1711             break;
   1712 
   1713         case WC40_CL72_STATE_INIT_CL72:
   1714             (void)_phy_wc40_force_cl72_init(unit,port);
   1715             FORCE_CL72_TICK_CNT(pc) = 0;
   1716             FORCE_CL72_STATE(pc) = WC40_CL72_STATE_LINK_CHECK;
   1717             LOG_VERBOSE(BSL_LS_SOC_PHY,
   1718                         (BSL_META_U(unit,
   1719                                     "force cl72: u=%d p=%d state INIT_CL72\n"), unit, port));
   1720             break;
   1721 
   1722         case WC40_CL72_STATE_LINK_CHECK:
   1723             sig_loss = 0;
   1724             for (i = lane_start; i <= lane_end; i++) {
   1725                 data16 = 0;
   1726                 SOC_IF_ERROR_RETURN
   1727                         (WC40_REG_READ(unit,pc,LANE0_ACCESS,
   1728                             0x80b0 + (0x10 * i), &data16));
   1729                 sig_loss |= data16 & 
   1730                     RX0_ANARXSTATUS_SIGDET_STATUS_CS4_SIGDET_LL_MASK;
   1731             }
   1732             if (sig_loss) {
   1733                 for (i = lane_start; i <= lane_end; i++) {
   1734                     /* tx disable */
   1735                     (void)_phy_wc40_tx_disable(unit,port,lane_start,
   1736                             lane_end,TRUE);
   1737                 }
   1738                 FORCE_CL72_STATE(pc) = WC40_CL72_STATE_TX_DISABLED;
   1739             } else if (link == FALSE) {
   1740                 FORCE_CL72_TICK_CNT(pc) += 1;
   1741                 if (FORCE_CL72_TICK_CNT(pc) > WC40_CL72_LINK_WAIT_CNT_LIMIT) {
   1742                     for (i = lane_start; i <= lane_end; i++) {
   1743                         /* tx disable */
   1744                         (void)_phy_wc40_tx_disable(unit,port,lane_start,
   1745                                 lane_end,TRUE);
   1746                     }
   1747                     FORCE_CL72_STATE(pc) = WC40_CL72_STATE_TX_DISABLED;
   1748                 }
   1749             } else {  /* link up */
   1750                 FORCE_CL72_STATE(pc) = WC40_CL72_STATE_LINK_GOOD;
   1751             }
   1752             LOG_VERBOSE(BSL_LS_SOC_PHY,
   1753                         (BSL_META_U(unit,
   1754                                     "force cl72: u=%d p=%d state LINK_CHECK sig_loss: 0x%x "
   1755                                     "link: 0x%x\n"), unit, port,sig_loss,link));
   1756             break;
   1757 
   1758         case WC40_CL72_STATE_LINK_GOOD:
   1759             if (link == FALSE) {
   1760                 FORCE_CL72_STATE(pc) = WC40_CL72_STATE_TX_DISABLED;
   1761                 (void)_phy_wc40_tx_disable(unit,port,lane_start,
   1762                             lane_end,TRUE);
   1763             }
   1764             LOG_VERBOSE(BSL_LS_SOC_PHY,
   1765                         (BSL_META_U(unit,
   1766                                     "force cl72: u=%d p=%d state LINK_GOOD: link 0x%x\n"), 
   1767                          unit, port,link));
   1768             break;
   1769         default:
   1770             break;
   1771     } 
   1772     return SOC_E_NONE;
   1773 }
   1774 
   1775 STATIC int
   1776 _phy_wc40_tx_control_get(int unit, soc_port_t port, WC40_TX_DRIVE_t *tx_drv, int inx)
   1777 {
   1778     phy_ctrl_t     *pc;
   1779     int rv = SOC_E_NONE;
   1780     int size;
   1781     int i;
   1782 
   1783     pc = INT_PHY_SW_STATE(unit, port);
   1784 
   1785     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   1786         size = 4;
   1787     } else if (IS_DUAL_LANE_PORT(pc)) {
   1788         size = 2;
   1789     } else {
   1790         size = 1;
   1791     }
   1792 
   1793     for (i = 0; i < size; i++) {
   1794         if (DEV_CFG_PTR(pc)->idriver[i] == WC40_NO_CFG_VALUE) {
   1795             /* take from the default value table */
   1796             (tx_drv + i)->idrive    = DEV_CFG_PTR(pc)->tx_drive[inx].idrive;
   1797         } else {
   1798             /* taking from user */
   1799             (tx_drv + i)->idrive = DEV_CFG_PTR(pc)->idriver[i];
   1800         }
   1801         if (DEV_CFG_PTR(pc)->pdriver[i] == WC40_NO_CFG_VALUE) {
   1802             /* take from the default value table */
   1803             (tx_drv + i)->ipredrive = DEV_CFG_PTR(pc)->tx_drive[inx].ipredrive;
   1804         } else {
   1805             /* taking from user */
   1806             (tx_drv + i)->ipredrive = DEV_CFG_PTR(pc)->pdriver[i];
   1807         }
   1808 
   1809         /* in autoneg mode no forced preemphasis */
   1810         if ((DEV_CFG_PTR(pc)->preemph[i] == WC40_NO_CFG_VALUE) ||
   1811             ((inx == TXDRV_AN_INX)) ) {
   1812             /* take from the default value table */
   1813             (tx_drv + i)->u.preemph = TXDRV_PREEMPH(DEV_CFG_PTR(pc)->tx_drive[inx].u.tap);
   1814         } else {
   1815             /* taking from user */
   1816             (tx_drv + i)->u.preemph = DEV_CFG_PTR(pc)->preemph[i];
   1817         }
   1818         if (DEV_CFG_PTR(pc)->post2driver[i] == WC40_NO_CFG_VALUE) {
   1819             /* take from the default value table */
   1820             (tx_drv + i)->post2 = DEV_CFG_PTR(pc)->tx_drive[inx].post2;
   1821         } else {
   1822             /* taking from user */
   1823             (tx_drv + i)->post2 = DEV_CFG_PTR(pc)->post2driver[i];
   1824         }
   1825     }
   1826 
   1827     return rv;
   1828 }
   1829 
   1830 STATIC int
   1831 _phy_wc40_tx_control_set(int unit, soc_port_t port, WC40_TX_DRIVE_t *tx_drv)
   1832 {
   1833     phy_ctrl_t     *pc;
   1834     uint32          preemph;
   1835     uint32          idriver;
   1836     uint32          pdriver;
   1837     uint32          post2;
   1838     uint16          data16;
   1839     int lane_num;
   1840     int i;
   1841     int size;
   1842  
   1843     pc = INT_PHY_SW_STATE(unit, port);
   1844 
   1845     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   1846         size = 4;
   1847     } else if (IS_DUAL_LANE_PORT(pc)) {
   1848         size = 2;
   1849     } else {
   1850         size = 1;
   1851     }
   1852 
   1853     for (i = 0; i < size; i++) {
   1854         idriver = (tx_drv + i)->idrive;
   1855         pdriver = (tx_drv + i)->ipredrive;
   1856         post2   = (tx_drv + i)->post2;
   1857         preemph = (tx_drv + i)->u.preemph; 
   1858         lane_num = pc->lane_num + i;
   1859         /* WC40 SerDes
   1860          *  idriver[11:8], pdriver[7:4],post2[14:12] 
   1861          */
   1862         idriver = (idriver << TXB_TX_DRIVER_IDRIVER_SHIFT) & 
   1863               TXB_TX_DRIVER_IDRIVER_MASK;
   1864         pdriver = (pdriver << TXB_TX_DRIVER_IPREDRIVER_SHIFT) &
   1865               TXB_TX_DRIVER_IPREDRIVER_MASK;
   1866         post2   = (post2 << TXB_TX_DRIVER_POST2_COEFF_SHIFT) &
   1867               TXB_TX_DRIVER_POST2_COEFF_MASK;
   1868         data16  = (uint16)(idriver | pdriver | post2);
   1869 
   1870         if (lane_num == 0) {
   1871             SOC_IF_ERROR_RETURN
   1872                 (MODIFY_WC40_TX0_TX_DRIVERr(unit, pc, 0x00, data16,
   1873                               TXB_TX_DRIVER_IDRIVER_MASK |
   1874                               TXB_TX_DRIVER_IPREDRIVER_MASK |
   1875                               TXB_TX_DRIVER_POST2_COEFF_MASK));
   1876             if (IS_DUAL_LANE_PORT(pc)) {
   1877                 SOC_IF_ERROR_RETURN
   1878                     (MODIFY_WC40_TX1_TX_DRIVERr(unit, pc, 0x00, data16,
   1879                               TXB_TX_DRIVER_IDRIVER_MASK |
   1880                               TXB_TX_DRIVER_IPREDRIVER_MASK |
   1881                               TXB_TX_DRIVER_POST2_COEFF_MASK));
   1882             }
   1883         } else if (lane_num == 1) {
   1884             SOC_IF_ERROR_RETURN
   1885                 (MODIFY_WC40_TX1_TX_DRIVERr(unit, pc, 0x00, data16,
   1886                               TXB_TX_DRIVER_IDRIVER_MASK |
   1887                               TXB_TX_DRIVER_IPREDRIVER_MASK |
   1888                               TXB_TX_DRIVER_POST2_COEFF_MASK));
   1889         } else if (lane_num == 2) {
   1890             SOC_IF_ERROR_RETURN
   1891                 (MODIFY_WC40_TX2_TX_DRIVERr(unit, pc, 0x00, data16,
   1892                               TXB_TX_DRIVER_IDRIVER_MASK |
   1893                               TXB_TX_DRIVER_IPREDRIVER_MASK |
   1894                               TXB_TX_DRIVER_POST2_COEFF_MASK));
   1895             if (IS_DUAL_LANE_PORT(pc)) {
   1896                 SOC_IF_ERROR_RETURN
   1897                     (MODIFY_WC40_TX3_TX_DRIVERr(unit, pc, 0x00, data16,
   1898                               TXB_TX_DRIVER_IDRIVER_MASK |
   1899                               TXB_TX_DRIVER_IPREDRIVER_MASK |
   1900                               TXB_TX_DRIVER_POST2_COEFF_MASK));
   1901             }
   1902         } else {
   1903             SOC_IF_ERROR_RETURN
   1904                 (MODIFY_WC40_TX3_TX_DRIVERr(unit, pc, 0x00, data16,
   1905                               TXB_TX_DRIVER_IDRIVER_MASK |
   1906                               TXB_TX_DRIVER_IPREDRIVER_MASK |
   1907                               TXB_TX_DRIVER_POST2_COEFF_MASK));
   1908         }
   1909 
   1910         /* Warpcore preemphasis fields have been taken over by IEEE CL72.
   1911          * It is automatically handled by H/W by default. But application can override 
   1912          * these values by writing to 0x82e2. The value preemph should has the same
   1913          * format as the register 0x82e2.
   1914          */ 
   1915 
   1916         SOC_IF_ERROR_RETURN
   1917             (WRITE_WC40_CL72_USERB0_CL72_TX_FIR_TAP_REGISTERr(unit, pc, ln_access[lane_num],
   1918                   preemph));
   1919     }
   1920     return SOC_E_NONE;
   1921 }
   1922 
   1923 STATIC int
   1924 _phy_wc40_tx_fir_default_set(int unit, soc_port_t port,int lane)
   1925 {
   1926     uint16              data16, mask16;
   1927     phy_ctrl_t         *pc;
   1928     pc                       = INT_PHY_SW_STATE(unit, port);
   1929 
   1930     if (WC40_REVID_A0(pc) || WC40_REVID_A1(pc)) {
   1931         SOC_IF_ERROR_RETURN
   1932              (MODIFY_WC40_CL72_USERB0_CL72_MISC1_CONTROLr(unit, pc, ln_access[lane],
   1933                 63 << CL72_USERB0_CL72_MISC1_CONTROL_TX_FIR_TAP_MAIN_KX_INIT_VAL_SHIFT,
   1934                CL72_USERB0_CL72_MISC1_CONTROL_TX_FIR_TAP_MAIN_KX_INIT_VAL_MASK));
   1935 
   1936         mask16 = CL72_USERB0_CL72_KR_DEFAULT_CONTROL_TX_FIR_TAP_POST_KR_INIT_VAL_MASK |
   1937                  CL72_USERB0_CL72_KR_DEFAULT_CONTROL_TX_FIR_TAP_MAIN_KR_INIT_VAL_MASK |
   1938                  CL72_USERB0_CL72_KR_DEFAULT_CONTROL_TX_FIR_TAP_PRE_KR_INIT_VAL_MASK;
   1939         data16 = (22 << CL72_USERB0_CL72_KR_DEFAULT_CONTROL_TX_FIR_TAP_POST_KR_INIT_VAL_SHIFT) |
   1940                  (37 << CL72_USERB0_CL72_KR_DEFAULT_CONTROL_TX_FIR_TAP_MAIN_KR_INIT_VAL_SHIFT) |
   1941                  (4 << CL72_USERB0_CL72_KR_DEFAULT_CONTROL_TX_FIR_TAP_PRE_KR_INIT_VAL_SHIFT);
   1942     
   1943         SOC_IF_ERROR_RETURN
   1944             (MODIFY_WC40_CL72_USERB0_CL72_KR_DEFAULT_CONTROLr(unit, pc, ln_access[lane], 
   1945                             data16,mask16));
   1946     
   1947         mask16 = CL72_USERB0_CL72_BR_DEFAULT_CONTROL_TX_FIR_TAP_POST_BR_INIT_VAL_MASK;
   1948         data16 = 22 << CL72_USERB0_CL72_BR_DEFAULT_CONTROL_TX_FIR_TAP_POST_BR_INIT_VAL_SHIFT;
   1949         mask16 += CL72_USERB0_CL72_BR_DEFAULT_CONTROL_TX_FIR_TAP_MAIN_BR_INIT_VAL_MASK;
   1950         data16 += 37 << CL72_USERB0_CL72_BR_DEFAULT_CONTROL_TX_FIR_TAP_MAIN_BR_INIT_VAL_SHIFT;
   1951         mask16 += CL72_USERB0_CL72_BR_DEFAULT_CONTROL_TX_FIR_TAP_PRE_BR_INIT_VAL_MASK;
   1952         data16 += 4 << CL72_USERB0_CL72_BR_DEFAULT_CONTROL_TX_FIR_TAP_PRE_BR_INIT_VAL_SHIFT;
   1953     
   1954         SOC_IF_ERROR_RETURN
   1955             (MODIFY_WC40_CL72_USERB0_CL72_BR_DEFAULT_CONTROLr(unit, pc, ln_access[lane],
   1956                     data16,mask16));
   1957     
   1958         mask16 = CL72_USERB0_CL72_OS_DEFAULT_CONTROL_TX_FIR_TAP_POST_OS_INIT_VAL_MASK;
   1959         data16 = 0;
   1960         mask16 += CL72_USERB0_CL72_OS_DEFAULT_CONTROL_TX_FIR_TAP_MAIN_OS_INIT_VAL_MASK;
   1961         data16 += 63 << CL72_USERB0_CL72_OS_DEFAULT_CONTROL_TX_FIR_TAP_MAIN_OS_INIT_VAL_SHIFT;
   1962         mask16 += CL72_USERB0_CL72_OS_DEFAULT_CONTROL_TX_FIR_TAP_PRE_OS_INIT_VAL_MASK;
   1963         data16 += 0;
   1964     
   1965         SOC_IF_ERROR_RETURN
   1966             (MODIFY_WC40_CL72_USERB0_CL72_OS_DEFAULT_CONTROLr(unit, pc, ln_access[lane], 
   1967                 data16,mask16));
   1968     
   1969         mask16 = CL72_USERB0_CL72_2P5_DEFAULT_CONTROL_TX_FIR_TAP_POST_2P5_INIT_VAL_MASK;
   1970         data16 = 0;
   1971         mask16 += CL72_USERB0_CL72_2P5_DEFAULT_CONTROL_TX_FIR_TAP_MAIN_2P5_INIT_VAL_MASK;
   1972         data16 += 63 << CL72_USERB0_CL72_2P5_DEFAULT_CONTROL_TX_FIR_TAP_MAIN_2P5_INIT_VAL_SHIFT;
   1973         mask16 += CL72_USERB0_CL72_2P5_DEFAULT_CONTROL_TX_FIR_TAP_PRE_2P5_INIT_VAL_MASK;
   1974         data16 += 0;
   1975         SOC_IF_ERROR_RETURN
   1976             (MODIFY_WC40_CL72_USERB0_CL72_2P5_DEFAULT_CONTROLr(unit, pc, ln_access[lane], 
   1977                    data16,mask16));
   1978     
   1979         mask16 = CL72_USERB1_CL72_DEBUG_1_REGISTER_TAP_MAX_VAL_MASK;
   1980         data16 = 63 << CL72_USERB1_CL72_DEBUG_1_REGISTER_TAP_MAX_VAL_SHIFT;
   1981         mask16 += CL72_USERB1_CL72_DEBUG_1_REGISTER_TAP_MIN_VAL_MASK;
   1982         data16 += 27 << CL72_USERB1_CL72_DEBUG_1_REGISTER_TAP_MIN_VAL_SHIFT;
   1983         SOC_IF_ERROR_RETURN
   1984             (MODIFY_WC40_CL72_USERB1_CL72_DEBUG_1_REGISTERr(unit, pc, ln_access[lane],
   1985                       data16,mask16));
   1986     
   1987         mask16 = CL72_USERB1_CL72_DEBUG_4_REGISTER_TAP_V2_VAL_MASK;
   1988         data16 = 9 << CL72_USERB1_CL72_DEBUG_4_REGISTER_TAP_V2_VAL_SHIFT;
   1989         SOC_IF_ERROR_RETURN
   1990             (MODIFY_WC40_CL72_USERB1_CL72_DEBUG_4_REGISTERr(unit, pc, ln_access[lane], 
   1991                    data16,mask16));
   1992 
   1993         if (IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   1994             /* Write below values in one mdio write command.
   1995              * This write should be done before configuring any speed.
   1996              *  a. 0x820E[15:8] = 0x3 restart link
   1997              *  b. 0x820E[7:6] = 0x0  ready_cmd =0 , error =0
   1998              *  c. 0x820E[3:0] = 0x1  command restart
   1999              */
   2000             data16 = 3 << DSC1B0_UC_CTRL_SUPPLEMENT_INFO_SHIFT;
   2001             data16 |= 1;
   2002             mask16 = DSC1B0_UC_CTRL_SUPPLEMENT_INFO_MASK |
   2003                      DSC1B0_UC_CTRL_GP_UC_REQ_MASK;
   2004             SOC_IF_ERROR_RETURN
   2005                 (MODIFY_WC40_DSC1B0_UC_CTRLr(unit, pc, ln_access[lane], data16,mask16));
   2006         }
   2007     } else if (WC40_REVID_B(pc)) {
   2008         mask16 = CL72_USERB1_CL72_DEBUG_4_REGISTER_TAP_V2_VAL_MASK;
   2009         data16 = 9 << CL72_USERB1_CL72_DEBUG_4_REGISTER_TAP_V2_VAL_SHIFT;
   2010         SOC_IF_ERROR_RETURN
   2011             (MODIFY_WC40_CL72_USERB1_CL72_DEBUG_4_REGISTERr(unit, pc, ln_access[lane], 
   2012                    data16,mask16));
   2013 
   2014         if (IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   2015             /* Write below values in one mdio write command. 
   2016              * This write should be done before configuring any speed. 
   2017              *  a. 0x820E[15:8] = 0x3 restart link 
   2018              *  b. 0x820E[7:6] = 0x0  ready_cmd =0 , error =0 
   2019              *  c. 0x820E[3:0] = 0x1  command restart 
   2020              */
   2021             data16 = 3 << DSC1B0_UC_CTRL_SUPPLEMENT_INFO_SHIFT;
   2022             data16 |= 1;    
   2023             mask16 = DSC1B0_UC_CTRL_SUPPLEMENT_INFO_MASK |
   2024                      DSC1B0_UC_CTRL_GP_UC_REQ_MASK;
   2025             SOC_IF_ERROR_RETURN
   2026                 (MODIFY_WC40_DSC1B0_UC_CTRLr(unit, pc, ln_access[lane], data16,mask16));
   2027         }
   2028     }
   2029     return SOC_E_NONE; 
   2030 }
   2031 
   2032 STATIC int
   2033 _phy_wc40_independent_lane_init(int unit, soc_port_t port)
   2034 {
   2035     int                 fiber;
   2036     uint16              data16, mask16;
   2037     int                 rv;
   2038     phy_ctrl_t         *pc;
   2039     soc_port_ability_t  ability;
   2040     WC40_TX_DRIVE_t tx_drv[NUM_LANES];
   2041 
   2042     /* Only need to track fiber mode state.
   2043      * Copper mode state is tracked by external PHY.
   2044      */
   2045     pc                       = INT_PHY_SW_STATE(unit, port);
   2046     fiber                    = DEV_CFG_PTR(pc)->fiber_pref;
   2047     pc->fiber.enable         = fiber;
   2048     pc->fiber.preferred      = fiber;
   2049     pc->fiber.autoneg_enable = 1;
   2050     pc->fiber.force_speed    = 1000;
   2051     pc->fiber.force_duplex   = TRUE;
   2052     pc->fiber.master         = SOC_PORT_MS_NONE;
   2053     pc->fiber.mdix           = SOC_PORT_MDIX_NORMAL;
   2054 
   2055 
   2056     /* cannot do the RESET on lane0 for B0 and above. The div16/div33 clock configuration 
   2057      * for all lanes uses the per-lane register on lane0. 
   2058      */ 
   2059     if ((pc->lane_num != 0) || WC40_REVID_A0(pc) || WC40_REVID_A1(pc)) {
   2060         /* perform IEEE control register reset on each lane  */
   2061      
   2062         SOC_IF_ERROR_RETURN
   2063             (WRITE_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, MII_CTRL_RESET));
   2064 
   2065         rv = _phy_wc40_regbit_set_wait_check(pc,WC40_COMBO_IEEE0_MIICNTLr,
   2066                      MII_CTRL_RESET,0,10000,0);
   2067 
   2068         if (rv == SOC_E_TIMEOUT) {
   2069             LOG_WARN(BSL_LS_SOC_PHY,
   2070                      (BSL_META_U(unit,
   2071                                  "Combo SerDes reset failed: u=%d p=%d\n"),
   2072                       unit, port));
   2073         }
   2074     }
   2075 
   2076     WC40_UDELAY(25000);
   2077     if (IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   2078         data16 = 3 << DSC1B0_UC_CTRL_SUPPLEMENT_INFO_SHIFT;
   2079         data16 |= 1;
   2080         mask16 = DSC1B0_UC_CTRL_SUPPLEMENT_INFO_MASK |
   2081                      DSC1B0_UC_CTRL_GP_UC_REQ_MASK;
   2082         SOC_IF_ERROR_RETURN
   2083                 (MODIFY_WC40_DSC1B0_UC_CTRLr(unit, pc, ln_access[pc->lane_num], data16,mask16));
   2084     }
   2085 
   2086     /*disbale the tx lane disable for hexli4 */
   2087     if (SOC_IS_HELIX4(unit) || SOC_IS_KATANA2(unit)) { /* ToBeDeleted */
   2088         SOC_IF_ERROR_RETURN(MODIFY_WC40_DIGITAL4_MISC3r(unit, pc, 0,
   2089                                           0, DIGITAL4_MISC3_LANEDISABLE_MASK));
   2090     }
   2091 
   2092     /* restore tx fir setting after reset  */
   2093     SOC_IF_ERROR_RETURN
   2094         (_phy_wc40_tx_fir_default_set(unit,port,pc->lane_num));
   2095     if (IS_DUAL_LANE_PORT(pc)) {
   2096         SOC_IF_ERROR_RETURN
   2097             (_phy_wc40_tx_fir_default_set(unit,port,pc->lane_num + 1));
   2098     }
   2099 
   2100     /* configure autoneg default settings */
   2101     SOC_IF_ERROR_RETURN  /* OS CDR default */
   2102         (WRITE_WC40_CL72_USERB0_CL72_OS_DEFAULT_CONTROLr(unit, pc, 0x00,0x03f0));
   2103 
   2104     SOC_IF_ERROR_RETURN  /* BR CDR default */
   2105         (WRITE_WC40_CL72_USERB0_CL72_2P5_DEFAULT_CONTROLr(unit, pc, 0x00,0x03f0));
   2106 
   2107     SOC_IF_ERROR_RETURN  /* BR CDR default */
   2108         (MODIFY_WC40_CL72_USERB0_CL72_MISC1_CONTROLr(unit, pc, 0x00,
   2109                   0x3f << CL72_USERB0_CL72_MISC1_CONTROL_TX_FIR_TAP_MAIN_KX_INIT_VAL_SHIFT,
   2110                   CL72_USERB0_CL72_MISC1_CONTROL_TX_FIR_TAP_MAIN_KX_INIT_VAL_MASK));
   2111 
   2112     /* Warpcore B0 workaround in autoneg mode Jira# PHY-388 */
   2113     if (WC40_REVID_B(pc) && (!IS_DUAL_LANE_PORT(pc))) {
   2114         if (DEV_CFG_PTR(pc)->cl73an) {
   2115             SOC_IF_ERROR_RETURN
   2116                 (WC40_REG_MODIFY(unit,pc,LANE0_ACCESS,
   2117                     WC40_RX0_ANARXCONTROLPCIr + (0x10 * pc->lane_num), 
   2118                       RXB_ANARXCONTROLPCI_SYNC_STATUS_FORCE_R_SM_MASK,
   2119                       RXB_ANARXCONTROLPCI_SYNC_STATUS_FORCE_R_SM_MASK |
   2120                       RXB_ANARXCONTROLPCI_SYNC_STATUS_FORCE_R_MASK));
   2121         }
   2122     }
   2123 
   2124     /* Workaround Jira# SDK-32387, init. default IEEE 1G speed */
   2125     /* the right register to program is the PMD register 0x800_0000. not the IEEE
   2126         0x0000_0000 */
   2127     if (WC40_SDK32387_REVS(pc) && (!IS_DUAL_LANE_PORT(pc))) {
   2128         data16 = PMD_IEEE0BLK_PMD_IEEECONTROL1_SPEEDSELECTION1_MASK;
   2129         mask16 = PMD_IEEE0BLK_PMD_IEEECONTROL1_SPEEDSELECTION0_MASK |
   2130                  PMD_IEEE0BLK_PMD_IEEECONTROL1_SPEEDSELECTION1_MASK |
   2131                  PMD_IEEE0BLK_PMD_IEEECONTROL1_SPEEDSELECTION2_MASK;
   2132         SOC_IF_ERROR_RETURN
   2133              (MODIFY_WC40_PMD_IEEE0BLK_PMD_IEEECONTROL1r(unit, pc, 0x00,
   2134              data16, mask16));
   2135         SOC_IF_ERROR_RETURN
   2136             (MODIFY_WC40_XGXSBLK2_UNICOREMODE10Gr(unit, pc, 0x00, 
   2137                       XGXSBLK2_UNICOREMODE10G_RESERVED0_MASK,
   2138                       XGXSBLK2_UNICOREMODE10G_RESERVED0_MASK));
   2139     }
   2140 
   2141     /* 0x8357[10:9] = 2'b0
   2142      * Set new advertisement page count identifier(5 user pages) that differentiates it from 
   2143      * HyperCore or other legacy devices(3 user pages)
   2144      */
   2145     SOC_IF_ERROR_RETURN
   2146         (MODIFY_WC40_DIGITAL6_UD_FIELDr(unit, pc, 0x00, 
   2147                 DIGITAL6_UD_FIELD_UD_ADV_ID_WC, DIGITAL6_UD_FIELD_UD_ADV_ID_MASK));
   2148 
   2149     
   2150     /* Stop the cl73an tx fifo reset routine in f/w if it is active */
   2151     WC40_CL73_AN_TX_FIFO_RESET_STOP(pc);
   2152     
   2153     /* hold tx/rx in reset */
   2154     SOC_IF_ERROR_RETURN
   2155         (MODIFY_WC40_DIGITAL5_MISC6r(unit,pc,0x00,
   2156               DIGITAL5_MISC6_RESET_RX_ASIC_MASK | DIGITAL5_MISC6_RESET_TX_ASIC_MASK,
   2157               DIGITAL5_MISC6_RESET_RX_ASIC_MASK | DIGITAL5_MISC6_RESET_TX_ASIC_MASK));
   2158 
   2159     /* RX_LOS configuration */
   2160     mask16 = SERDESDIGITAL_CONTROL1000X1_SIGNAL_DETECT_EN_MASK |
   2161              SERDESDIGITAL_CONTROL1000X1_INVERT_SIGNAL_DETECT_MASK;
   2162     data16 = 0;
   2163     if (DEV_CFG_PTR(pc)->rx_los) {
   2164         SOC_IF_ERROR_RETURN
   2165             (WC40_REG_MODIFY(unit, pc, LANE0_ACCESS, 0x80b4 + (0x10*pc->lane_num),
   2166                    0x60, 0xfc));
   2167         data16 |= SERDESDIGITAL_CONTROL1000X1_SIGNAL_DETECT_EN_MASK;
   2168         SOC_IF_ERROR_RETURN
   2169             (MODIFY_WC40_EEE_USERB0_EEE_COMBO_CONTROL0r(unit, pc, 0x00,
   2170                0,
   2171                EEE_USERB0_EEE_COMBO_CONTROL0_EEE_BYPASS_SIGDET_FILT_MASK));
   2172     }
   2173     data16 |= DEV_CFG_PTR(pc)->rx_los_invert? 
   2174              SERDESDIGITAL_CONTROL1000X1_INVERT_SIGNAL_DETECT_MASK : 0;
   2175     SOC_IF_ERROR_RETURN
   2176         (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X1r(unit, pc, 0x00,data16,mask16));
   2177 
   2178     if (IS_DUAL_LANE_PORT(pc)) {
   2179         /* sync clock divider for dxgxs two lanes, B0 and above */
   2180         if (!(WC40_REVID_A0(pc) || WC40_REVID_A1(pc))) {
   2181             SOC_IF_ERROR_RETURN
   2182                 (MODIFY_WC40_CL49_USERB0_CONTROLr(unit, pc, 0x00, 0xc0, 0xc0));
   2183             SOC_IF_ERROR_RETURN
   2184                 (MODIFY_WC40_CL49_USERB0_CONTROLr(unit, pc, ln_access[pc->lane_num+1], 
   2185                              0xc0, 0xc0));
   2186         }
   2187    
   2188         /* workaround for KR2 speed status, select the PCS type as 40GBASE-R PCS */
   2189         if (WC40_REVID_B(pc)) {
   2190             SOC_IF_ERROR_RETURN
   2191                 (MODIFY_WC40_PCS_IEEE0BLK_PCS_IEEECONTROL2r(unit, pc, 0x00, 
   2192                          0x4, PCS_IEEE0BLK_PCS_IEEECONTROL2_PCS_TYPESEL_MASK));
   2193         }
   2194     }
   2195 
   2196     /* cannot be applied in dual-lane port */
   2197     if (!IS_DUAL_LANE_PORT(pc)) {
   2198         /* keep CL48 sync acquisition state machine in reset to avoid CL73 problem*/
   2199         if (WC40_REVID_A0(pc) || WC40_REVID_A1(pc)) {
   2200             SOC_IF_ERROR_RETURN
   2201                 (WC40_REG_MODIFY(unit, pc, LANE0_ACCESS, 0x80ba+(0x10*pc->lane_num),
   2202                        RX0_ANARXCONTROLPCI_LINK_EN_FORCE_SM_MASK,
   2203                        RX0_ANARXCONTROLPCI_LINK_EN_FORCE_SM_MASK |
   2204                        RX0_ANARXCONTROLPCI_LINK_EN_R_MASK));
   2205         }
   2206     }
   2207 
   2208     /* XXX not to control the speeds thru pma/pmd register */
   2209     SOC_IF_ERROR_RETURN
   2210         (MODIFY_WC40_SERDESDIGITAL_MISC2r(unit, pc, 0x00,
   2211                            0,
   2212                            SERDESDIGITAL_MISC2_PMA_PMD_FORCED_SPEED_ENC_EN_MASK));
   2213 
   2214     /* check if TX/RX polarities should be flipped */
   2215     SOC_IF_ERROR_RETURN
   2216         (_phy_wc40_ind_lane_polarity_set(unit,pc, TRUE));
   2217 
   2218     /* config RX clock compensation used in single-lane and dual-lane ports */
   2219     if (IS_DUAL_LANE_PORT(pc)) { 
   2220         if (WC40_REVID_A0(pc) || WC40_REVID_A1(pc)) {
   2221             SOC_IF_ERROR_RETURN
   2222                 (WRITE_WC40_XGXSBLK2_UNICOREMODE10Gr(unit, pc, 0x00,
   2223                          IND_CLOCK_COMP_DEFAULT_REV_A));
   2224         } else { /* B0 and other versions */ 
   2225             SOC_IF_ERROR_RETURN
   2226                 (WRITE_WC40_XGXSBLK2_UNICOREMODE10Gr(unit, pc, 0x00, 
   2227                  0x8000 | IND_CLOCK_COMP_DEFAULT));
   2228         }
   2229     } else { 
   2230         SOC_IF_ERROR_RETURN
   2231             (MODIFY_WC40_RX66_CONTROLr(unit, pc, 0x00,
   2232         RX66_CONTROL_CC_EN_MASK |RX66_CONTROL_CC_DATA_SEL_MASK, 
   2233                 RX66_CONTROL_CC_EN_MASK | RX66_CONTROL_CC_DATA_SEL_MASK));
   2234     }
   2235 
   2236     /*  support back to back packets in higig+/higig2 mode without IPG */
   2237     if (!(WC40_REVID_A0(pc) || WC40_REVID_A1(pc))) {
   2238         if (IS_DUAL_LANE_PORT(pc)) {
   2239             SOC_IF_ERROR_RETURN
   2240                 (MODIFY_WC40_XGXSBLK0_XGMIIRCONTROLr(unit, pc, 0x00,
   2241             DEV_CFG_PTR(pc)->hg_mode? XGXSBLK0_XGMIIRCONTROL_CKCMP_NOIPG_EN_MASK: 0, 
   2242                 XGXSBLK0_XGMIIRCONTROL_CKCMP_NOIPG_EN_MASK));
   2243         } else { /* quad-port mode */
   2244             SOC_IF_ERROR_RETURN
   2245                 (MODIFY_WC40_RX66_CONTROLr(unit, pc, 0x00,
   2246             DEV_CFG_PTR(pc)->hg_mode? RX66_CONTROL_CC_NOIPG_EN_MASK: 0, 
   2247                 RX66_CONTROL_CC_NOIPG_EN_MASK));
   2248         }
   2249     }
   2250 
   2251     /* Set Local Advertising Configuration */
   2252     SOC_IF_ERROR_RETURN
   2253         (phy_wc40_ability_local_get(unit, port, &ability));
   2254  
   2255     pc->fiber.advert_ability = ability;
   2256     SOC_IF_ERROR_RETURN
   2257         (phy_wc40_ability_advert_set(unit, port, &ability));
   2258 
   2259     data16 = SERDESDIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_MASK |
   2260              SERDESDIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_MASK;
   2261     mask16 = data16 | SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK;
   2262 
   2263     if (DEV_CFG_PTR(pc)->pdetect1000x) {
   2264         /* Enable 1000X parallel detect */
   2265         data16 |= SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK;
   2266     }
   2267     
   2268     SOC_IF_ERROR_RETURN
   2269         (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X2r(unit, pc, 0x00, data16, mask16));
   2270 
   2271     /* Configure default preemphasis, predriver, idriver values. Use
   2272      * KR entry as default
   2273      */
   2274     SOC_IF_ERROR_RETURN
   2275         (_phy_wc40_tx_control_get(unit, port,&tx_drv[0],TXDRV_DFT_INX));
   2276     SOC_IF_ERROR_RETURN
   2277         (_phy_wc40_tx_control_set(unit, port,&tx_drv[0]));
   2278 
   2279     /* Configuring operating mode */
   2280     data16 = SERDESDIGITAL_CONTROL1000X1_DISABLE_PLL_PWRDWN_MASK;
   2281     mask16 = SERDESDIGITAL_CONTROL1000X1_AUTODET_EN_MASK |
   2282              SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK |
   2283              SERDESDIGITAL_CONTROL1000X1_DISABLE_PLL_PWRDWN_MASK;
   2284 
   2285     /*
   2286      * Configure signal auto-detection between SGMII and fiber.
   2287      * This detection only works if auto-negotiation is enabled.
   2288      */
   2289     if (DEV_CFG_PTR(pc)->auto_medium) {
   2290         data16 |= SERDESDIGITAL_CONTROL1000X1_AUTODET_EN_MASK;
   2291     }
   2292 
   2293     /*
   2294      * Put the Serdes in Fiber or SGMII mode
   2295      */
   2296     if (DEV_CFG_PTR(pc)->fiber_pref) {
   2297         data16 |= SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK;
   2298     } else {
   2299         data16 &= ~SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK;
   2300     }
   2301 
   2302     if (DEV_CFG_PTR(pc)->sgmii_mstr) {
   2303         data16 |= SERDESDIGITAL_CONTROL1000X1_SGMII_MASTER_MODE_MASK;
   2304         mask16 |= SERDESDIGITAL_CONTROL1000X1_SGMII_MASTER_MODE_MASK;
   2305     }
   2306 
   2307     SOC_IF_ERROR_RETURN
   2308         (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X1r(unit, pc, 0x00, data16, mask16));
   2309 
   2310     /* Set FIFO Elasticity to 13.5k and
   2311      * Disable CRS generation on TX in half duplex mode
   2312      */
   2313     SOC_IF_ERROR_RETURN
   2314         (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X3r(unit, pc, 0x00,
   2315              SERDESDIGITAL_CONTROL1000X3_DISABLE_TX_CRS_MASK |
   2316              (1 << 2),
   2317              SERDESDIGITAL_CONTROL1000X3_DISABLE_TX_CRS_MASK |
   2318              SERDESDIGITAL_CONTROL1000X3_FIFO_ELASICITY_TX_MASK));
   2319 
   2320     /* Set the dswin to 7 as deskew fifo depth is reduced */
   2321     if (WC40_LINK_WAR_REVS(pc)) {
   2322         SOC_IF_ERROR_RETURN
   2323             (MODIFY_WC40_XGXSBLK2_ASWAP66CONTROL2r(unit, pc, 0x00, 0x7, 0x1F));
   2324     }
   2325 
   2326     if (IS_DUAL_LANE_PORT(pc)) {
   2327         DUAL_LANE_BCST_ENABLE(pc);
   2328         /* config the 64B/66B for 20g dxgxs, won't affect other speeds and AN  */
   2329         SOC_IF_ERROR_RETURN
   2330             (_wc40_xgmii_scw_config (unit,pc));
   2331 
   2332         DUAL_LANE_BCST_DISABLE(pc);
   2333     }
   2334 
   2335     if (IS_DUAL_LANE_PORT(pc)) {
   2336         if (WC40_CL73_SOFT_KR2(pc)) {
   2337             SOC_IF_ERROR_RETURN
   2338                 (_wc40_soft_an_cl73kr2_init(unit, port));
   2339         }
   2340     }
   2341 
   2342     /* autoneg is not supported in dual-port and custom1 mode */
   2343     if (CUSTOM1_MODE(pc) || IS_DUAL_LANE_PORT(pc)) {
   2344         uint16 sp_ctrl0;
   2345         uint16 sp_ctrl1;
   2346         uint16 speed_val = 0;
   2347         int    tx_inx;
   2348 
   2349         DUAL_LANE_BCST_ENABLE(pc);
   2350         SOC_IF_ERROR_RETURN
   2351             (MODIFY_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, 0, MII_CTRL_AE));
   2352 
   2353         
   2354         if (CUSTOM1_MODE(pc)) {
   2355             sp_ctrl0 = 0xf;
   2356             sp_ctrl1 = DIGITAL4_MISC3_FORCE_SPEED_B5_MASK;
   2357         } else { /* general dual-port mode, default 20G if supported, otherwise 10G*/
   2358             SOC_IF_ERROR_RETURN
   2359                 (_phy_wc40_ind_speed_ctrl_get(unit,port,pc->speed_max,&speed_val,&tx_inx));
   2360             sp_ctrl1 = (speed_val & 0x20)? DIGITAL4_MISC3_FORCE_SPEED_B5_MASK: 0;
   2361             sp_ctrl0 = speed_val & 0x1f;
   2362         }
   2363         
   2364         /* force to the speed */
   2365         SOC_IF_ERROR_RETURN
   2366              (MODIFY_WC40_SERDESDIGITAL_MISC1r(unit, pc, 0x00, sp_ctrl0, 
   2367                                   SERDESDIGITAL_MISC1_FORCE_SPEED_MASK));
   2368          SOC_IF_ERROR_RETURN
   2369              (MODIFY_WC40_DIGITAL4_MISC3r(unit, pc, 0x00, 
   2370                      sp_ctrl1,
   2371                      DIGITAL4_MISC3_FORCE_SPEED_B5_MASK));
   2372         DUAL_LANE_BCST_DISABLE(pc);
   2373 
   2374         if (SOC_IS_KATANA2(unit)) {
   2375             _phy_wc40_speed_set(unit, port, pc->speed_max);
   2376         }
   2377 
   2378     } else { /* all other modes, enable autoneg by default */
   2379         /* clear forced speed control. Some two-lane ports are strapped
   2380          * in forced dxgxs speed.
   2381          */
   2382         uint16 sp_ctrl0 = 0;
   2383         uint16 sp_ctrl1 = 0;
   2384         uint16 speed_val = 0;
   2385         int    tx_inx;
   2386         
   2387         DUAL_LANE_BCST_ENABLE(pc);
   2388 
   2389         if (WC40_SDK32387_REVS(pc) && (!IS_DUAL_LANE_PORT(pc))) {
   2390             SOC_IF_ERROR_RETURN
   2391                 (MODIFY_WC40_SERDESDIGITAL_MISC2r(unit, pc, 0x00,
   2392                                SERDESDIGITAL_MISC2_PMA_PMD_FORCED_SPEED_ENC_EN_MASK,
   2393                                SERDESDIGITAL_MISC2_PMA_PMD_FORCED_SPEED_ENC_EN_MASK));
   2394         }
   2395 
   2396         /* If CL37 and CL73 is disabled, apply forced speed */
   2397         if(!DEV_CFG_PTR(pc)->cl37an && !DEV_CFG_PTR(pc)->cl73an) {
   2398         SOC_IF_ERROR_RETURN
   2399                 (_phy_wc40_ind_speed_ctrl_get(unit,port,pc->speed_max,&speed_val,&tx_inx));
   2400             sp_ctrl1 = (speed_val & 0x20)? DIGITAL4_MISC3_FORCE_SPEED_B5_MASK: 0;
   2401             sp_ctrl0 = speed_val & 0x1f;
   2402 
   2403         }
   2404 
   2405         SOC_IF_ERROR_RETURN
   2406             (MODIFY_WC40_SERDESDIGITAL_MISC1r(unit, pc, 0x00, sp_ctrl0,
   2407                                SERDESDIGITAL_MISC1_FORCE_SPEED_MASK));
   2408         SOC_IF_ERROR_RETURN
   2409             (MODIFY_WC40_DIGITAL4_MISC3r(unit, pc, 0x00, sp_ctrl1,
   2410                     DIGITAL4_MISC3_FORCE_SPEED_B5_MASK));
   2411 
   2412         if (WC40_SDK32387_REVS(pc) && (!IS_DUAL_LANE_PORT(pc))) {
   2413             SOC_IF_ERROR_RETURN
   2414                 (MODIFY_WC40_SERDESDIGITAL_MISC2r(unit, pc, 0x00,
   2415                        0,
   2416                        SERDESDIGITAL_MISC2_PMA_PMD_FORCED_SPEED_ENC_EN_MASK));
   2417         }
   2418         DUAL_LANE_BCST_DISABLE(pc);
   2419 
   2420         if (SOC_IS_KATANA2(unit)) {
   2421             _phy_wc40_speed_set(unit, port, pc->speed_max);
   2422         }
   2423 
   2424         mask16 = MII_CTRL_AE | MII_CTRL_RAN;
   2425         
   2426         /* Enable CL37 Autoneg*/
   2427         data16 = 0;
   2428         if (DEV_CFG_PTR(pc)->cl37an) {
   2429             data16 = MII_CTRL_AE | MII_CTRL_RAN;
   2430         }
   2431         SOC_IF_ERROR_RETURN
   2432             (MODIFY_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, 
   2433                                                   data16, mask16));
   2434         
   2435         /* os8_txfifo_patch_en[3:0], which is a per-lane control 
   2436            bit to enable the war_tx_os8_fifo_reset routine via s/w; 
   2437 
   2438            MDIO Address: 0xFFC8.3:0 = mdio_uC_mailbox[3:0] 
   2439                                         = txfifo_patch_en[3:0]
   2440            where txfifo_p/RECiu/atch_en[N] controls lane(N).
   2441            Default: 0xFFC8.3:0 = txfifo_patch_en[3:0] = 4'h0
   2442           
   2443            S/W need to enable firmware WAR before enabling CL73
   2444 
   2445         */
   2446         if((DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status == ENABLE) 
   2447                 || (DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status == REACTIVATE)){
   2448             mask16 = 1 << pc->lane_num;
   2449             data16 = mask16;
   2450             SOC_IF_ERROR_RETURN
   2451                 (MODIFY_WC40_MICROBLK_MDIO_UC_MAILBOXr(unit, pc, 0x0,
   2452                                                     data16, mask16));
   2453             DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status = ACTIVE;
   2454         }
   2455 
   2456         data16 = 0; 
   2457         /* Enable CL73 Autoneg*/
   2458         if (DEV_CFG_PTR(pc)->cl73an) {
   2459             data16 = MII_CTRL_AE | MII_CTRL_RAN;
   2460         }
   2461         SOC_IF_ERROR_RETURN
   2462             (MODIFY_WC40_AN_IEEE0BLK_AN_IEEECONTROL1r(unit, pc, 
   2463                                                       0x00, data16, mask16)); 
   2464 
   2465     }
   2466 
   2467     if (WC40_REVID_A0(pc) || WC40_REVID_A1(pc)) {
   2468         /* put inband mdio rx in reset */
   2469         SOC_IF_ERROR_RETURN
   2470             (MODIFY_WC40_XGXSBLK3_LOCALCONTROL0r(unit,pc,0x00, (1 << 3), (1 << 3)));
   2471     }
   2472 
   2473     SOC_IF_ERROR_RETURN
   2474         (MODIFY_WC40_DIGITAL5_MISC6r(unit,pc,0x00,
   2475               0,
   2476               DIGITAL5_MISC6_RESET_RX_ASIC_MASK | DIGITAL5_MISC6_RESET_TX_ASIC_MASK));
   2477 
   2478     WC40_CL73_AN_TX_FIFO_RESET_START(pc);
   2479 
   2480     /* XXX 0x833d bit 15 set, enable the auto select of KR,KRx4,KXx4 KX link
   2481      * reporting selection of PCS device
   2482      */
   2483     SOC_IF_ERROR_RETURN
   2484             (MODIFY_WC40_DIGITAL4_MISC4r(unit, pc, 0x00, 
   2485                     DIGITAL4_MISC4_PCS_TYPE_AUTO_SELECT_MASK,
   2486                     DIGITAL4_MISC4_PCS_TYPE_AUTO_SELECT_MASK));
   2487 
   2488     /* enable the LPI pass-thru by default */
   2489     mask16 = (1 << 14) | (1 << 15);
   2490     data16 = mask16;
   2491     SOC_IF_ERROR_RETURN
   2492         (MODIFY_WC40_DIGITAL4_MISC5r(unit,pc,0x00, data16, mask16));
   2493     mask16 = XGXSBLK7_EEECONTROL_LPI_EN_TX_MASK |
   2494              XGXSBLK7_EEECONTROL_LPI_EN_RX_MASK |
   2495              XGXSBLK7_EEECONTROL_LPI_COL_DET_EN_MASK;
   2496     data16 = mask16;
   2497     SOC_IF_ERROR_RETURN
   2498         (MODIFY_WC40_XGXSBLK7_EEECONTROLr(unit,pc,0x00,data16,mask16));
   2499 
   2500     /* Clear the CL37 FEC advertisement */
   2501     mask16 = DIGITAL3_UP3_FEC_MASK;
   2502     data16 = 0;
   2503     SOC_IF_ERROR_RETURN
   2504         (MODIFY_WC40_DIGITAL3_UP3r(unit, pc, 0x00, data16, mask16));
   2505 
   2506     if (SOC_IS_HELIX4(unit) || SOC_IS_KATANA2(unit)) {
   2507      SOC_IF_ERROR_RETURN(phy_wc40_an_set(unit, port, 0)); 
   2508         _phy_wc40_ind_speed_set(unit, port, pc->speed_max);
   2509     }
   2510 
   2511     LOG_INFO(BSL_LS_SOC_PHY,
   2512              (BSL_META_U(unit,
   2513                          "_phy_wc40_independent_lane_init: u=%d p=%d %s\n"),
   2514               unit, port, (fiber) ? "Fiber" : "Copper"));
   2515     return SOC_E_NONE;
   2516 }
   2517 
   2518 STATIC int
   2519 _phy_wc40_combo_core_init(int unit, soc_port_t port)
   2520 {
   2521     phy_ctrl_t        *pc;
   2522     soc_port_ability_t ability;
   2523     uint16             data16, mask16;
   2524     uint8 *pdata;
   2525     int   ucode_len;
   2526     int   alloc_flag;
   2527     int   lane;
   2528     WC40_TX_DRIVE_t tx_drv[NUM_LANES];
   2529 
   2530     pc = INT_PHY_SW_STATE(unit, port);
   2531 
   2532     /* must be done after reset, otherwise will be cleared  */
   2533     data16 = (XGXSBLK0_XGXSCONTROL_MODE_10G_ComboCoreMode <<
   2534                         XGXSBLK0_XGXSCONTROL_MODE_10G_SHIFT);
   2535     SOC_IF_ERROR_RETURN
   2536             (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00,data16,
   2537                                        (XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK |
   2538                                         XGXSBLK0_XGXSCONTROL_MODE_10G_MASK)));
   2539 
   2540     /*disbale the tx lane disable for hexli4 */
   2541     if (SOC_IS_HELIX4(unit) || SOC_IS_KATANA2(unit)) { /* ToBeDeleted */
   2542         SOC_IF_ERROR_RETURN(MODIFY_WC40_DIGITAL4_MISC3r(unit, pc, LANE_BCST,
   2543                                           0, DIGITAL4_MISC3_LANEDISABLE_MASK));
   2544     }
   2545 
   2546     /* configure default fir settings for all lanes */
   2547     for (lane = 0; lane < 4; lane++) {
   2548         SOC_IF_ERROR_RETURN
   2549             (_phy_wc40_tx_fir_default_set(unit,port,lane));
   2550     }
   2551 
   2552     /* configure autoneg default settings */
   2553     SOC_IF_ERROR_RETURN  /* OS CDR default */
   2554         (WRITE_WC40_CL72_USERB0_CL72_OS_DEFAULT_CONTROLr(unit, pc, LANE_BCST,0x03f0));
   2555 
   2556     if (WC40_REVID_B(pc)) {
   2557         SOC_IF_ERROR_RETURN  /* BR CDR default */
   2558             (WRITE_WC40_CL72_USERB0_CL72_BR_DEFAULT_CONTROLr(unit, pc, LANE_BCST,0x035a));
   2559     }
   2560 
   2561     /* 0x8357[10:9] = 2'b0
   2562      * Set new advertisement page count identifier(5 user pages) that differentiates it from 
   2563      * HyperCore or other legacy devices(3 user pages)
   2564      */
   2565     SOC_IF_ERROR_RETURN
   2566         (MODIFY_WC40_DIGITAL6_UD_FIELDr(unit, pc, 0x00, 
   2567                 DIGITAL6_UD_FIELD_UD_ADV_ID_WC, DIGITAL6_UD_FIELD_UD_ADV_ID_MASK));
   2568 
   2569     /* XXX not to control the speeds thru pma/pmd register */
   2570     SOC_IF_ERROR_RETURN
   2571         (MODIFY_WC40_SERDESDIGITAL_MISC2r(unit, pc, 0x00,
   2572                            0,
   2573                            SERDESDIGITAL_MISC2_PMA_PMD_FORCED_SPEED_ENC_EN_MASK));
   2574 
   2575     /* configure txck/rx  */
   2576     SOC_IF_ERROR_RETURN
   2577         (MODIFY_WC40_XGXSBLK6_XGXSX2CONTROL2r(unit,pc,0x00, 
   2578                   WC40_TXCK_MASK | WC40_RXCK_OVERIDE_MASK,
   2579                   WC40_TXCK_MASK | WC40_RXCK_OVERIDE_MASK)); 
   2580 
   2581     /* RX_LOS configuration */
   2582     mask16 = SERDESDIGITAL_CONTROL1000X1_SIGNAL_DETECT_EN_MASK |
   2583              SERDESDIGITAL_CONTROL1000X1_INVERT_SIGNAL_DETECT_MASK;
   2584     data16 = 0;
   2585     if (DEV_CFG_PTR(pc)->rx_los) {
   2586         /* lane0 RX_LOS enable */
   2587         SOC_IF_ERROR_RETURN
   2588             (WC40_REG_MODIFY(unit, pc, LANE0_ACCESS, 0x80b4, 0x60, 0xfc));
   2589         data16 |= SERDESDIGITAL_CONTROL1000X1_SIGNAL_DETECT_EN_MASK;
   2590         SOC_IF_ERROR_RETURN
   2591             (MODIFY_WC40_EEE_USERB0_EEE_COMBO_CONTROL0r(unit, pc, 0x00,
   2592                0,
   2593                EEE_USERB0_EEE_COMBO_CONTROL0_EEE_BYPASS_SIGDET_FILT_MASK));
   2594     }
   2595     data16 |= DEV_CFG_PTR(pc)->rx_los_invert?
   2596              SERDESDIGITAL_CONTROL1000X1_INVERT_SIGNAL_DETECT_MASK : 0;
   2597     SOC_IF_ERROR_RETURN
   2598         (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X1r(unit, pc, 0x00,data16,mask16));
   2599 
   2600     /* disable CL73 BAM */
   2601     SOC_IF_ERROR_RETURN
   2602         (MODIFY_WC40_CL73_USERB0_CL73_BAMCTRL1r(unit,pc,0x00,0,
   2603                CL73_USERB0_CL73_BAMCTRL1_CL73_BAMEN_MASK));
   2604                                                                                 
   2605     /* disable CL73 AN device*/
   2606     SOC_IF_ERROR_RETURN
   2607         (WRITE_WC40_AN_IEEE0BLK_AN_IEEECONTROL1r(unit,pc,0x00,0));
   2608     
   2609     /* disable CL37 AN device*/
   2610     SOC_IF_ERROR_RETURN
   2611         (WRITE_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, 0));
   2612 
   2613     /* Clear the CL37 FEC advertisement */
   2614     mask16 = DIGITAL3_UP3_FEC_MASK;
   2615     data16 = 0;
   2616     SOC_IF_ERROR_RETURN
   2617         (MODIFY_WC40_DIGITAL3_UP3r(unit, pc, 0x00, data16, mask16));
   2618 
   2619     SOC_IF_ERROR_RETURN
   2620         (phy_wc40_ability_local_get(unit, port, &ability));
   2621     
   2622     SOC_IF_ERROR_RETURN
   2623         (phy_wc40_ability_advert_set(unit, port, &ability));
   2624 
   2625     data16 = 0;
   2626     mask16 = XGXSBLK5_PARDET10GCONTROL_PD_12G_TXDON_DISABLE_MASK |
   2627              XGXSBLK5_PARDET10GCONTROL_PD_12G_DISABLE_MASK |
   2628              XGXSBLK5_PARDET10GCONTROL_PARDET10G_EN_MASK;
   2629     if (DEV_CFG_PTR(pc)->pdetect10g) { 
   2630         data16 |=XGXSBLK5_PARDET10GCONTROL_PARDET10G_EN_MASK;
   2631         if (pc->speed_max <= 10000) {
   2632             /* Disable parallel detect for 12Gbps. */
   2633             data16 |= XGXSBLK5_PARDET10GCONTROL_PD_12G_TXDON_DISABLE_MASK |
   2634                       XGXSBLK5_PARDET10GCONTROL_PD_12G_DISABLE_MASK;
   2635         }
   2636     }
   2637     SOC_IF_ERROR_RETURN
   2638         (MODIFY_WC40_XGXSBLK5_PARDET10GCONTROLr(unit, pc, 0x00, data16, mask16));
   2639 
   2640     /* Configure default preemphasis, predriver, idriver values. Use
   2641      * KR4 entry as default
   2642      */
   2643     SOC_IF_ERROR_RETURN
   2644         (_phy_wc40_tx_control_get(unit, port,&tx_drv[0],TXDRV_DFT_INX));
   2645     SOC_IF_ERROR_RETURN
   2646         (_phy_wc40_tx_control_set(unit, port,&tx_drv[0]));
   2647 
   2648     /*
   2649      * Transform CX4 pin out on the board to HG pinout
   2650      */
   2651     if (DEV_CFG_PTR(pc)->cx42hg) {
   2652         /* If CX4 to HG conversion is enabled, do not allow individual lane
   2653          * swapping.
   2654          */
   2655         SOC_IF_ERROR_RETURN     /* Enable TX Lane swap */
   2656             (WRITE_WC40_XGXSBLK8_TXLNSWAP1r(unit, pc, 0x00, 0x80e4));
   2657 
   2658         SOC_IF_ERROR_RETURN     /* Flip TX Lane polarity */
   2659             (WRITE_WC40_TXB_ANATXACONTROL0r(unit, pc, 0x00, 0x1020));
   2660     } else {
   2661 
   2662         /* check if any tx/rx lanes are remapped */
   2663         SOC_IF_ERROR_RETURN
   2664             (_phy_wc40_rxlane_map_set(unit,pc,
   2665                  (uint16)(DEV_CFG_PTR(pc)->rxlane_map)));
   2666    
   2667         SOC_IF_ERROR_RETURN
   2668             (_phy_wc40_txlane_map_set(unit,pc,
   2669                  (uint16)(DEV_CFG_PTR(pc)->txlane_map)));
   2670         
   2671         /* Tx/Rx Polarity control */
   2672         SOC_IF_ERROR_RETURN
   2673             (_phy_wc40_combo_polarity_set(unit,pc,TRUE));
   2674 
   2675         /* select div16 clock */
   2676         SOC_IF_ERROR_RETURN
   2677             (_phy_wc40_rx_div16_clk_select(unit,pc));
   2678     }
   2679     /* Reset the value for this register to the recommended 
   2680        values before f/w is started.
   2681        This register is managed by firmware in cl73 mode
   2682 
   2683        Clear 0x80a1[3:2] for lane 0, lane 1, lane 2, lane 3 
   2684        Cannot broadcast it using 0x80a1 since lanes could 
   2685        have a different settings such as tx polarity.
   2686        Broadcasting will write over the same setting for 
   2687        all the lanes. Reset the bits individually per lane.
   2688     */
   2689     SOC_IF_ERROR_RETURN
   2690         (MODIFY_WC40_TX0_ANATXACONTROL0r(unit, pc, 0x0,
   2691             0x00,
   2692             TX0_ANATXACONTROL0_EDEN_FORCE_R_MASK 
   2693             | TX0_ANATXACONTROL0_EDEN_R_MASK));
   2694     SOC_IF_ERROR_RETURN
   2695         (MODIFY_WC40_TX1_ANATXACONTROL0r(unit, pc, 0x0,
   2696             0x00,
   2697             TX1_ANATXACONTROL0_EDEN_FORCE_R_MASK 
   2698             | TX1_ANATXACONTROL0_EDEN_R_MASK));
   2699     SOC_IF_ERROR_RETURN
   2700         (MODIFY_WC40_TX2_ANATXACONTROL0r(unit, pc, 0x0,
   2701             0x00,
   2702             TX2_ANATXACONTROL0_EDEN_FORCE_R_MASK 
   2703             | TX2_ANATXACONTROL0_EDEN_R_MASK));
   2704     SOC_IF_ERROR_RETURN
   2705         (MODIFY_WC40_TX3_ANATXACONTROL0r(unit, pc, 0x0,
   2706             0x00,
   2707             TX3_ANATXACONTROL0_EDEN_FORCE_R_MASK 
   2708             | TX3_ANATXACONTROL0_EDEN_R_MASK));
   2709 
   2710     if (DEV_CFG_PTR(pc)->refclk == 161) {
   2711         SOC_IF_ERROR_RETURN
   2712             (WRITE_WC40_SERDESDIGITAL_MISC1r(unit,pc,0x00,0xB900));
   2713     }
   2714 
   2715     /* broadcast to all lanes */
   2716     SOC_IF_ERROR_RETURN
   2717         (WRITE_WC40_AERBLK_AERr(unit,pc,0x00, WC_AER_BCST_OFS_STRAP));
   2718 
   2719     /* set BRCM 31G control */
   2720     SOC_IF_ERROR_RETURN
   2721         (MODIFY_WC40_DIGITAL5_MISC6r(unit, pc, 0x00, 
   2722                        DIGITAL5_MISC6_USE_BRCM6466_31500_CYA_MASK, 
   2723                        DIGITAL5_MISC6_USE_BRCM6466_31500_CYA_MASK));
   2724 
   2725     /* config the 64B/66B for 25G, won't affect other speeds and AN  */
   2726     SOC_IF_ERROR_RETURN
   2727         (_wc40_xgmii_scw_config (unit,pc));
   2728 
   2729     /* Set FIFO Elasticity to 13.5k and
   2730      * Disable CRS generation on TX in half duplex mode
   2731      */
   2732     SOC_IF_ERROR_RETURN
   2733         (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X3r(unit, pc, 0x00,
   2734              SERDESDIGITAL_CONTROL1000X3_DISABLE_TX_CRS_MASK |
   2735              (1 << 2),
   2736              SERDESDIGITAL_CONTROL1000X3_DISABLE_TX_CRS_MASK |
   2737              SERDESDIGITAL_CONTROL1000X3_FIFO_ELASICITY_TX_MASK));
   2738 
   2739     /* clock compensation configuration in combo mode */
   2740     if (WC40_REVID_A0(pc) || WC40_REVID_A1(pc)) {
   2741         SOC_IF_ERROR_RETURN
   2742             (WRITE_WC40_XGXSBLK2_UNICOREMODE10Gr(unit, pc, 0x00, 
   2743                           COMBO_CLOCK_COMP_DEFAULT));
   2744     } else {  /* B0 and ... */
   2745         SOC_IF_ERROR_RETURN
   2746             (WRITE_WC40_XGXSBLK2_UNICOREMODE10Gr(unit, pc, 0x00, 
   2747                 0x8000 | COMBO_CLOCK_COMP_DEFAULT));
   2748     }
   2749 
   2750     /* Reset the value for these registers to the recommended 
   2751        values before f/w is started.
   2752        These registers are managed by firmware in cl73 mode
   2753     */
   2754     /* Set 0x8370[1] */
   2755     SOC_IF_ERROR_RETURN
   2756         (MODIFY_WC40_CL73_USERB0_CL73_UCTRL1r(unit, pc, 0x0, 
   2757             CL73_USERB0_CL73_UCTRL1_CL73_USTAT1_MUXSEL_MASK,
   2758             CL73_USERB0_CL73_UCTRL1_CL73_USTAT1_MUXSEL_MASK));
   2759 
   2760     /* Clear 0x8378[1], 0x8378[3] & 0x8378[12] */
   2761     SOC_IF_ERROR_RETURN
   2762         (MODIFY_WC40_CL73_USERB0_CL73_UCTRL2r(unit, pc, 0x0, 
   2763             0x0000,
   2764             CL73_USERB0_CL73_UCTRL2_CONFIG_MATCH_DIS_MASK 
   2765             | CL73_USERB0_CL73_UCTRL2_SIGDET_TIMER_DIS_MASK
   2766             | 0x1000));
   2767     
   2768     /* Disable firmware war for OS8 CL73 tx fifo reset */            
   2769     SOC_IF_ERROR_RETURN
   2770         (MODIFY_WC40_MICROBLK_MDIO_UC_MAILBOXr(unit, pc, 0x0,
   2771                                                0, 0xf));
   2772     /* reset AER */
   2773     SOC_IF_ERROR_RETURN
   2774         (WRITE_WC40_AERBLK_AERr(unit,pc,0x00, 0));
   2775 
   2776     /* Set the dswin to 7 as deskew fifo depth is reduced */
   2777     if (WC40_LINK_WAR_REVS(pc)) {
   2778         SOC_IF_ERROR_RETURN
   2779             (MODIFY_WC40_XGXSBLK2_ASWAP66CONTROL2r(unit, pc, 0x00, 0x7, 0x1F));
   2780     }
   2781 
   2782     /*
   2783      * Configure signal auto-detection between SGMII and fiber.
   2784      */
   2785     data16 = SERDESDIGITAL_CONTROL1000X1_DISABLE_PLL_PWRDWN_MASK;
   2786     mask16 = SERDESDIGITAL_CONTROL1000X1_DISABLE_PLL_PWRDWN_MASK |
   2787              SERDESDIGITAL_CONTROL1000X1_AUTODET_EN_MASK |
   2788              SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK;
   2789 
   2790     if (DEV_CFG_PTR(pc)->auto_medium) {
   2791         data16 |= SERDESDIGITAL_CONTROL1000X1_AUTODET_EN_MASK;
   2792     }
   2793    
   2794     if (DEV_CFG_PTR(pc)->fiber_pref) {
   2795         data16 |= SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK;
   2796     }
   2797     SOC_IF_ERROR_RETURN
   2798         (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X1r(unit, pc, 0x00, data16, mask16));
   2799 
   2800     /* set filter_force_link and disable_false_link */
   2801 
   2802     mask16 = SERDESDIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_MASK |
   2803              SERDESDIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_MASK;
   2804     data16 = mask16;
   2805     SOC_IF_ERROR_RETURN
   2806         (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X2r(unit, pc, 0x00, data16, mask16));
   2807 
   2808     if (WC40_REVID_A0(pc) || WC40_REVID_A1(pc)) {
   2809         /* put inband mdio rx in reset */
   2810         SOC_IF_ERROR_RETURN
   2811             (MODIFY_WC40_XGXSBLK3_LOCALCONTROL0r(unit,pc,0x00, (1 << 3), (1 << 3)));
   2812     }
   2813 
   2814     /* uCode should be done in the last in init sequence. Firmware may do additional
   2815      * configuration.
   2816      */
   2817     if (DEV_CFG_PTR(pc)->load_mthd) {
   2818         SOC_IF_ERROR_RETURN
   2819             (_phy_wc40_ucode_get(unit,port,&pdata,&ucode_len,&alloc_flag));
   2820         SOC_IF_ERROR_RETURN
   2821             (phy_wc40_firmware_load(unit,port,0,pdata, ucode_len));
   2822         if (alloc_flag) {
   2823             sal_free(pdata);
   2824         }
   2825     } else {
   2826         LOG_WARN(BSL_LS_SOC_PHY,
   2827                  (BSL_META_U(unit,
   2828                              "WC40 combo mode : uC RAM download skipped: u=%d p=%d\n"),
   2829                   unit, port));
   2830     }
   2831 
   2832     mask16 = XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK;
   2833     data16 = mask16; 
   2834     /* Workaround: tx fifo recenter problem in aggregated mode */ 
   2835     if (WC40_REVID_A0(pc) || WC40_REVID_A1(pc)) {
   2836         mask16 |= XGXSBLK0_XGXSCONTROL_AFRST_EN_MASK;
   2837     }
   2838     SOC_IF_ERROR_RETURN
   2839          (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00, data16, mask16));
   2840 
   2841     (void) _phy_wc40_pll_lock_wait(unit, port);
   2842 
   2843     /* disable CL73 AN device in case it is not used*/
   2844     SOC_IF_ERROR_RETURN
   2845         (WRITE_WC40_AN_IEEE0BLK_AN_IEEECONTROL1r(unit,pc,0x00,0));
   2846     
   2847     /* put device in autoneg mode */
   2848     /* clear forced bit */
   2849     SOC_IF_ERROR_RETURN
   2850             (MODIFY_WC40_SERDESDIGITAL_MISC1r(unit, pc, 0x00, 0, 
   2851                          SERDESDIGITAL_MISC1_FORCE_SPEED_MASK));
   2852     SOC_IF_ERROR_RETURN
   2853         (MODIFY_WC40_DIGITAL4_MISC3r(unit, pc, 0x00, 0, 
   2854                          DIGITAL4_MISC3_FORCE_SPEED_B5_MASK));
   2855 
   2856     if (WC40_CL73_SOFT_KR2(pc)) {
   2857         SOC_IF_ERROR_RETURN
   2858             (_wc40_soft_an_cl73kr2_init(unit, port));
   2859     } else {
   2860         if (DEV_CFG_PTR(pc)->cl37an) {
   2861             SOC_IF_ERROR_RETURN
   2862                 (MODIFY_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00,
   2863                                           MII_CTRL_AE | MII_CTRL_RAN,
   2864                                           MII_CTRL_AE | MII_CTRL_RAN));
   2865         }
   2866         if (DEV_CFG_PTR(pc)->cl73an) {
   2867             SOC_IF_ERROR_RETURN
   2868                 (MODIFY_WC40_AN_IEEE0BLK_AN_IEEECONTROL1r(unit, pc, 0x00,
   2869                                           MII_CTRL_AE | MII_CTRL_RAN,
   2870                                           MII_CTRL_AE | MII_CTRL_RAN));
   2871         }
   2872     }
   2873 
   2874     /* XXX 0x833d bit 15 set, enable the auto select of KR,KRx4,KXx4 KX link
   2875      * reporting selection of PCS device
   2876      */
   2877     SOC_IF_ERROR_RETURN
   2878             (MODIFY_WC40_DIGITAL4_MISC4r(unit, pc, 0x00, 
   2879                     DIGITAL4_MISC4_PCS_TYPE_AUTO_SELECT_MASK,
   2880                     DIGITAL4_MISC4_PCS_TYPE_AUTO_SELECT_MASK));
   2881 
   2882     /* XXX set default speed mode */
   2883     /* SOC_IF_ERROR_RETURN(phy_wc40_an_set(unit, port, TRUE)); */
   2884     if (SOC_IS_HELIX4(unit) || SOC_IS_KATANA2(unit)) {
   2885      SOC_IF_ERROR_RETURN(phy_wc40_an_set(unit, port, 0)); 
   2886         _phy_wc40_speed_set(unit, port, pc->speed_max);
   2887     }
   2888 
   2889 
   2890     return SOC_E_NONE;
   2891 }
   2892 
   2893 STATIC int
   2894 _phy_wc40_interlaken_mode_init(int unit, soc_port_t port)
   2895 {
   2896     phy_ctrl_t         *pc;
   2897     uint16 pdetect;
   2898     uint16 ctrl0;
   2899     uint16             xgxs_ctrl;
   2900     uint16             misc2;
   2901     uint16 data16;
   2902     uint16 mask16;
   2903     uint8 *pdata;
   2904     int   ucode_len;
   2905     int   alloc_flag;
   2906 
   2907     pc = INT_PHY_SW_STATE(unit, port);
   2908 
   2909     if (!_wc40_chip_init_done(unit,pc->chip_num,pc->phy_mode)) {
   2910         /* configure and initialize the resource shared by all 4 lanes*/
   2911 
   2912         SOC_IF_ERROR_RETURN(_wc40_soft_reset(unit,pc)); /* reset once */
   2913 
   2914         /* select multi mmd and multi-port address mode */
   2915         data16 = XGXSBLK0_MMDSELECT_DEVCL22_EN_MASK |
   2916                  XGXSBLK0_MMDSELECT_DEVDEVAD_EN_MASK |
   2917                  XGXSBLK0_MMDSELECT_DEVPMD_EN_MASK  |
   2918                  XGXSBLK0_MMDSELECT_DEVAN_EN_MASK |
   2919                  XGXSBLK0_MMDSELECT_MULTIMMDS_EN_MASK;
   2920         mask16 = data16 |
   2921                  XGXSBLK0_MMDSELECT_MULTIPRTS_EN_MASK;
   2922 
   2923         if (!(pc->flags & PHYCTRL_MDIO_ADDR_SHARE)) {
   2924             data16 |= XGXSBLK0_MMDSELECT_MULTIPRTS_EN_MASK;
   2925         }
   2926         SOC_IF_ERROR_RETURN
   2927             (MODIFY_WC40_XGXSBLK0_MMDSELECTr(unit, pc, LANE0_ACCESS, data16,mask16));
   2928 
   2929         xgxs_ctrl = 5;
   2930         xgxs_ctrl <<= XGXSBLK0_XGXSCONTROL_MODE_10G_SHIFT;
   2931         SOC_IF_ERROR_RETURN
   2932             (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, LANE0_ACCESS,
   2933                        xgxs_ctrl,
   2934                        XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK |
   2935                        XGXSBLK0_XGXSCONTROL_MODE_10G_MASK));
   2936 
   2937         /* Turn off 8B10B */
   2938         SOC_IF_ERROR_RETURN
   2939             (WRITE_WC40_XGXSBLK1_LANECTRL2r(unit, pc, LANE0_ACCESS, 0));
   2940 
   2941         /* Turn off 64B66B endec and turn off cl36 pcs */
   2942         SOC_IF_ERROR_RETURN
   2943             (WRITE_WC40_XGXSBLK1_LANECTRL0r(unit, pc, LANE0_ACCESS, 0));
   2944 
   2945         if (DEV_CFG_PTR(pc)->custom == PHYCTRL_LANE_MODE_CUSTOM_3p125MHZ) {
   2946             /* Double wide data at 1/2 pll rate */ 
   2947             SOC_IF_ERROR_RETURN
   2948                 (WRITE_WC40_XGXSBLK1_LANECTRL1r(unit, pc, LANE0_ACCESS, 0xAAAA));
   2949         } else {
   2950             /* default 6.25G Double wide data at pll rate */
   2951             SOC_IF_ERROR_RETURN
   2952                 (WRITE_WC40_XGXSBLK1_LANECTRL1r(unit, pc, LANE0_ACCESS, 0xFFFF));
   2953         }
   2954 
   2955         /* disable 10G parallel detect */
   2956         SOC_IF_ERROR_RETURN
   2957             (MODIFY_WC40_XGXSBLK5_PARDET10GCONTROLr(unit, pc, LANE0_ACCESS,
   2958                       0,
   2959                       XGXSBLK5_PARDET10GCONTROL_PARDET10G_EN_MASK));
   2960 
   2961         SOC_IF_ERROR_RETURN
   2962             (READ_WC40_SERDESDIGITAL_CONTROL1000X2r(unit, pc, LANE0_ACCESS,&pdetect));
   2963     
   2964         SOC_IF_ERROR_RETURN
   2965             (READ_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, LANE0_ACCESS, &ctrl0));
   2966         pdetect &= ~SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK;
   2967         ctrl0 &= ~MII_CTRL_AE;
   2968 
   2969         /* XXX not to control the speeds thru pma/pmd register */
   2970         SOC_IF_ERROR_RETURN
   2971             (READ_WC40_SERDESDIGITAL_MISC2r(unit, pc, LANE0_ACCESS, &misc2));
   2972         misc2 &= ~SERDESDIGITAL_MISC2_PMA_PMD_FORCED_SPEED_ENC_EN_MASK;
   2973 
   2974         /* disable cl37,parallel detect 1G on all lanes*/
   2975         /* broadcast to all lanes */
   2976         SOC_IF_ERROR_RETURN
   2977             (WRITE_WC40_AERBLK_AERr(unit,pc,LANE0_ACCESS, WC_AER_BCST_OFS_STRAP));
   2978 
   2979         /* XXX not to control the speeds thru pma/pmd register */
   2980         SOC_IF_ERROR_RETURN
   2981             (WRITE_WC40_SERDESDIGITAL_MISC2r(unit, pc, LANE0_ACCESS, misc2));
   2982 
   2983         /* disable 1000X parallel detect */
   2984         SOC_IF_ERROR_RETURN
   2985               (WRITE_WC40_SERDESDIGITAL_CONTROL1000X2r(unit, pc, LANE0_ACCESS, pdetect));
   2986 
   2987         /* disable CL37 */
   2988         SOC_IF_ERROR_RETURN
   2989             (WRITE_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, LANE0_ACCESS, ctrl0));
   2990 
   2991         /* Clear the CL37 FEC advertisement */
   2992         mask16 = DIGITAL3_UP3_FEC_MASK;
   2993         data16 = 0;
   2994         SOC_IF_ERROR_RETURN
   2995             (MODIFY_WC40_DIGITAL3_UP3r(unit, pc, LANE0_ACCESS, data16, mask16));
   2996 
   2997         /* pll multiplier 40 with 156.25MHz refclkc */
   2998         SOC_IF_ERROR_RETURN
   2999             (WRITE_WC40_SERDESDIGITAL_MISC1r(unit, pc, LANE0_ACCESS, 0x721B));
   3000 
   3001         /* Reset the value for these registers to the recommended 
   3002            values before f/w is started.
   3003            These registers are managed by firmware in cl73 mode.
   3004         */
   3005         /* Set 0x8370[1] */
   3006         SOC_IF_ERROR_RETURN
   3007             (MODIFY_WC40_CL73_USERB0_CL73_UCTRL1r(unit, pc, LANE_BCST, 
   3008                 CL73_USERB0_CL73_UCTRL1_CL73_USTAT1_MUXSEL_MASK,
   3009                 CL73_USERB0_CL73_UCTRL1_CL73_USTAT1_MUXSEL_MASK));
   3010 
   3011         /* Clear 0x8378[1], 0x8378[3] & 0x8378[12] */
   3012         SOC_IF_ERROR_RETURN
   3013             (MODIFY_WC40_CL73_USERB0_CL73_UCTRL2r(unit, pc, LANE_BCST, 
   3014                 0x0000,
   3015                 CL73_USERB0_CL73_UCTRL2_CONFIG_MATCH_DIS_MASK 
   3016                 | CL73_USERB0_CL73_UCTRL2_SIGDET_TIMER_DIS_MASK
   3017                 | 0x1000));
   3018 
   3019         /* Clear 0x80a1[3:2] for lane 0, lane 1, lane 2, lane 3
   3020          */
   3021         SOC_IF_ERROR_RETURN
   3022             (MODIFY_WC40_TXB_ANATXACONTROL0r(unit, pc, LANE0_ACCESS,
   3023                 0x00,
   3024                 TX0_ANATXACONTROL0_EDEN_FORCE_R_MASK 
   3025                 | TX0_ANATXACONTROL0_EDEN_R_MASK));
   3026 
   3027         /* Disable firmware war for OS8 CL73 tx fifo reset */            
   3028         SOC_IF_ERROR_RETURN
   3029             (MODIFY_WC40_MICROBLK_MDIO_UC_MAILBOXr(unit, pc, LANE0_ACCESS,
   3030                                                    0, 0xf));
   3031 
   3032         /* restore AER */
   3033         SOC_IF_ERROR_RETURN
   3034             (WRITE_WC40_AERBLK_AERr(unit,pc,LANE0_ACCESS, 0));
   3035 
   3036         /* check if any tx/rx lanes are remapped */
   3037         SOC_IF_ERROR_RETURN
   3038             (_phy_wc40_rxlane_map_set(unit,pc,
   3039                  (uint16)(DEV_CFG_PTR(pc)->rxlane_map)));
   3040 
   3041         SOC_IF_ERROR_RETURN
   3042             (_phy_wc40_txlane_map_set(unit,pc,
   3043                  (uint16)(DEV_CFG_PTR(pc)->txlane_map)));
   3044 
   3045         /* Tx/Rx Polarity control */
   3046         SOC_IF_ERROR_RETURN
   3047             (_phy_wc40_combo_polarity_set(unit,pc,TRUE));
   3048 
   3049         if (DEV_CFG_PTR(pc)->load_mthd) { 
   3050             SOC_IF_ERROR_RETURN
   3051                 (_phy_wc40_ucode_get(unit,port,&pdata,&ucode_len,&alloc_flag));
   3052             SOC_IF_ERROR_RETURN
   3053                 (phy_wc40_firmware_load(unit,port,0,pdata, ucode_len));
   3054             if (alloc_flag) {
   3055                 sal_free(pdata);
   3056             }
   3057         } else {
   3058             LOG_WARN(BSL_LS_SOC_PHY,
   3059                      (BSL_META_U(unit,
   3060                                  "WC40 custom mode : uC RAM download skipped: u=%d p=%d\n"),
   3061                       unit, port));
   3062         }
   3063         /* put inband mdio rx in reset */
   3064         SOC_IF_ERROR_RETURN
   3065             (MODIFY_WC40_XGXSBLK3_LOCALCONTROL0r(unit,pc,LANE0_ACCESS, 
   3066                        (1 << 3), (1 << 3)));
   3067 
   3068         SOC_IF_ERROR_RETURN
   3069             (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, LANE0_ACCESS,
   3070                          XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK,
   3071                          XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
   3072 
   3073         /* PLL clock lock wait */
   3074         (void) _phy_wc40_pll_lock_wait(unit, port);
   3075         _phy_wc40_control_vco_disturbed_set(unit, port);
   3076     }
   3077 
   3078     pc->flags |= PHYCTRL_INIT_DONE;
   3079 
   3080     /* XXX a register 0x81f2  value to indicate this mode to allow ucontroller to tune*/
   3081 
   3082     LOG_INFO(BSL_LS_SOC_PHY,
   3083              (BSL_META_U(unit,
   3084                          "_phy_wc40_interlaken_mode_init: u=%d p=%d\n"),
   3085               unit, port));
   3086     return SOC_E_NONE;
   3087 }
   3088 
   3089 /*
   3090  * Function:
   3091  *      phy_wc40_ind_init
   3092  * Purpose:     
   3093  *      Initialize hc phys
   3094  * Parameters:
   3095  *      unit - StrataSwitch unit #.
   3096  *      port - StrataSwitch port #. 
   3097  * Returns:     
   3098  *      SOC_E_NONE
   3099  */
   3100 
   3101 STATIC int
   3102 _phy_wc40_ind_init(int unit, soc_port_t port)
   3103 {
   3104     phy_ctrl_t         *pc;               
   3105     uint16             xgxs_ctrl;
   3106     uint16             data16;
   3107     uint16             mask16;
   3108     uint16             txck_mode;
   3109     int vco_freq;
   3110     uint8 *pdata;
   3111     int   ucode_len;
   3112     int   alloc_flag;
   3113 
   3114     pc = INT_PHY_SW_STATE(unit, port);
   3115 
   3116     /* In this mode, the device's 4 lanes are usaually connected to more than
   3117      * one switch port.
   3118      * It is necessary to configure and initialize the shared resource
   3119      * once before going to each lane. 
   3120      */
   3121 
   3122     if (!_wc40_chip_init_done(unit,pc->chip_num,pc->phy_mode)) {
   3123         /* configure and initialize the resource shared by all 4 lanes*/
   3124 
   3125         SOC_IF_ERROR_RETURN(_wc40_soft_reset(unit,pc)); /* reset once */
   3126 
   3127         /* select multi mmd and multi-port address mode */
   3128         data16 = XGXSBLK0_MMDSELECT_DEVCL22_EN_MASK |
   3129                  XGXSBLK0_MMDSELECT_DEVDEVAD_EN_MASK |
   3130                  XGXSBLK0_MMDSELECT_DEVPMD_EN_MASK  |
   3131                  XGXSBLK0_MMDSELECT_DEVAN_EN_MASK |
   3132                  XGXSBLK0_MMDSELECT_MULTIMMDS_EN_MASK;
   3133         mask16 = data16 |
   3134                  XGXSBLK0_MMDSELECT_MULTIPRTS_EN_MASK;
   3135         if (!(pc->flags & PHYCTRL_MDIO_ADDR_SHARE)) {
   3136             data16 |= XGXSBLK0_MMDSELECT_MULTIPRTS_EN_MASK;
   3137         }
   3138         SOC_IF_ERROR_RETURN
   3139             (MODIFY_WC40_XGXSBLK0_MMDSELECTr(unit, pc, LANE0_ACCESS, data16,mask16));
   3140 
   3141         /* set mdio override control to send out 312.5MHz clock on txck_out[0].
   3142          * this allow lane1-lane3 to support 10G speed while lane 0 runs at 1G.
   3143          * Apply to a1/b0. No workaround for a0
   3144          */
   3145         if ((!IS_DUAL_LANE_PORT(pc)) && (WC40_REVID_A1(pc) || WC40_REVID_B(pc))) {
   3146             SOC_IF_ERROR_RETURN
   3147                 (MODIFY_WC40_XGXSBLK6_XGXSX2CONTROL2r(unit, pc, LANE0_ACCESS,
   3148                        (1 << 13), (1 << 13)));
   3149         }
   3150 
   3151         /* warpcore does not support os4(xgxs_ctrl=6). 
   3152          * Should use os8 for independent channel mode
   3153          */
   3154         xgxs_ctrl = DEV_CFG_PTR(pc)->lane_mode;
   3155 
   3156         xgxs_ctrl <<= XGXSBLK0_XGXSCONTROL_MODE_10G_SHIFT;
   3157 
   3158         /* set device's mode and disable PLL sequencer */
   3159         SOC_IF_ERROR_RETURN
   3160             (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, LANE0_ACCESS, 
   3161                        xgxs_ctrl,
   3162                        XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK |
   3163                        XGXSBLK0_XGXSCONTROL_MODE_10G_MASK));
   3164 
   3165         /* configure the txck/rxck for all lanes */
   3166         if (IS_DUAL_LANE_PORT(pc)) {
   3167             txck_mode = 0x9;
   3168         } else {
   3169             txck_mode = 0;
   3170         }
   3171         SOC_IF_ERROR_RETURN
   3172             (MODIFY_WC40_XGXSBLK6_XGXSX2CONTROL2r(unit,pc,LANE0_ACCESS, 
   3173                   (txck_mode << WC40_TXCK_SHIFTER) | WC40_RXCK_OVERIDE_MASK,
   3174                       WC40_TXCK_MASK | WC40_RXCK_OVERIDE_MASK)); 
   3175 
   3176         /* broadcast to all lanes */
   3177         SOC_IF_ERROR_RETURN
   3178             (WRITE_WC40_AERBLK_AERr(unit,pc,LANE0_ACCESS, WC_AER_BCST_OFS_STRAP));
   3179 
   3180         if (DEV_CFG_PTR(pc)->lane_mode == xgxs_operationModes_IndLane_OS5) {
   3181             vco_freq = WC40_OS5_VCO_FREQ;
   3182         } else  { /* OS8 */
   3183             vco_freq = WC40_OS8_VCO_FERQ;
   3184             if (DEV_CFG_PTR(pc)->refclk == 161) {
   3185                 vco_freq = 0xB900;
   3186             }
   3187         }
   3188 
   3189         /* configure VCO frequency */
   3190         SOC_IF_ERROR_RETURN
   3191             (WRITE_WC40_SERDESDIGITAL_MISC1r(unit,pc,LANE0_ACCESS,vco_freq));
   3192 
   3193         /* disable 10G parallel detect */
   3194         SOC_IF_ERROR_RETURN
   3195             (WRITE_WC40_XGXSBLK5_PARDET10GCONTROLr(unit, pc, LANE0_ACCESS, 0));
   3196 
   3197         /* Reset the value for these registers to the recommended 
   3198            values before f/w is started.
   3199            These registers are managed by firmware in cl73 mode.
   3200         */
   3201         /* Set 0x8370[1] */
   3202         SOC_IF_ERROR_RETURN
   3203             (MODIFY_WC40_CL73_USERB0_CL73_UCTRL1r(unit, pc, LANE_BCST, 
   3204                 CL73_USERB0_CL73_UCTRL1_CL73_USTAT1_MUXSEL_MASK,
   3205                 CL73_USERB0_CL73_UCTRL1_CL73_USTAT1_MUXSEL_MASK));
   3206 
   3207         /* Clear 0x8378[1], 0x8378[3] & 0x8378[12] */
   3208         SOC_IF_ERROR_RETURN
   3209             (MODIFY_WC40_CL73_USERB0_CL73_UCTRL2r(unit, pc, LANE_BCST, 
   3210                 0x0000,
   3211                 CL73_USERB0_CL73_UCTRL2_CONFIG_MATCH_DIS_MASK 
   3212                 | CL73_USERB0_CL73_UCTRL2_SIGDET_TIMER_DIS_MASK
   3213                 | 0x1000));
   3214 
   3215         /* Clear 0x80a1[3:2] for lane 0, lane 1, lane 2, lane 3
   3216          */
   3217         SOC_IF_ERROR_RETURN
   3218             (MODIFY_WC40_TXB_ANATXACONTROL0r(unit, pc, LANE0_ACCESS,
   3219                 0x00,
   3220                 TX0_ANATXACONTROL0_EDEN_FORCE_R_MASK 
   3221                 | TX0_ANATXACONTROL0_EDEN_R_MASK));
   3222 
   3223         /* Disable firmware war for OS8 CL73 tx fifo reset */            
   3224         SOC_IF_ERROR_RETURN
   3225             (MODIFY_WC40_MICROBLK_MDIO_UC_MAILBOXr(unit, pc, LANE0_ACCESS,
   3226                                                    0, 0xf));
   3227 
   3228         /* reset AER */
   3229         SOC_IF_ERROR_RETURN
   3230             (WRITE_WC40_AERBLK_AERr(unit,pc,LANE0_ACCESS, 0));
   3231 
   3232         /* check if any tx/rx lanes are remapped */
   3233         SOC_IF_ERROR_RETURN
   3234             (_phy_wc40_rxlane_map_set(unit,pc,
   3235                  (uint16)(DEV_CFG_PTR(pc)->rxlane_map)));
   3236    
   3237         SOC_IF_ERROR_RETURN
   3238             (_phy_wc40_txlane_map_set(unit,pc,
   3239                  (uint16)(DEV_CFG_PTR(pc)->txlane_map)));
   3240 
   3241         /* select div16 clock */
   3242         SOC_IF_ERROR_RETURN
   3243             (_phy_wc40_rx_div16_clk_select(unit,pc));
   3244 
   3245         if (DEV_CFG_PTR(pc)->load_mthd) { 
   3246             SOC_IF_ERROR_RETURN
   3247                 (_phy_wc40_ucode_get(unit,port,&pdata,&ucode_len,&alloc_flag));
   3248             SOC_IF_ERROR_RETURN
   3249                 (phy_wc40_firmware_load(unit,port,0,pdata, ucode_len));
   3250             if (alloc_flag) {
   3251                 sal_free(pdata);
   3252             }
   3253         } else {
   3254             LOG_WARN(BSL_LS_SOC_PHY,
   3255                      (BSL_META_U(unit,
   3256                                  "WC40 independent mode : uC RAM download skipped: u=%d p=%d\n"),
   3257                       unit, port));
   3258         }
   3259 
   3260         mask16 = XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK;
   3261         data16 = mask16;
   3262         /* Workaround: tx fifo recenter problem in aggregated mode */
   3263         if (WC40_REVID_A0(pc) || WC40_REVID_A1(pc)) {
   3264             if (IS_DUAL_LANE_PORT(pc)) {
   3265                 mask16 |= XGXSBLK0_XGXSCONTROL_AFRST_EN_MASK;
   3266             }
   3267         }
   3268 
   3269         /* enable PLL sequencer */
   3270         SOC_IF_ERROR_RETURN
   3271             (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, LANE0_ACCESS, data16, mask16));
   3272 
   3273         /* PLL clock lock wait */
   3274         (void) _phy_wc40_pll_lock_wait(unit, port);
   3275     }
   3276 
   3277     SOC_IF_ERROR_RETURN
   3278         (_phy_wc40_independent_lane_init(unit, port));
   3279 
   3280     pc->flags |= PHYCTRL_INIT_DONE;
   3281 
   3282     return SOC_E_NONE;
   3283 }
   3284     
   3285 /*
   3286  * Function:
   3287  *      phy_wc40_init
   3288  * Purpose:     
   3289  *      Initialize hc phys
   3290  * Parameters:
   3291  *      unit - StrataSwitch unit #.
   3292  *      port - StrataSwitch port #. 
   3293  * Returns:     
   3294  *      SOC_E_NONE
   3295  */
   3296 
   3297 STATIC int
   3298 phy_wc40_init(int unit, soc_port_t port)
   3299 {
   3300     phy_ctrl_t         *pc;               
   3301 
   3302     /* init the configuration value */
   3303     _phy_wc40_config_init(unit,port);
   3304 
   3305     pc = INT_PHY_SW_STATE(unit, port);
   3306 
   3307     if (!PHY_EXTERNAL_MODE(unit, port)) {
   3308          /* PHY reset callbacks: 
   3309          * It calls the user registered reset handler
   3310          * or the PHY driver's reset handler otherwise, 
   3311          * if the user did not register any of it's own
   3312          * reset routine 
   3313          */
   3314         SOC_IF_ERROR_RETURN
   3315             (soc_phy_reset(unit, port));
   3316     }
   3317 
   3318     if (PHY_INDEPENDENT_LANE_MODE(unit, port)) {
   3319         if (DEV_CFG_PTR(pc)->custom) {
   3320             SOC_IF_ERROR_RETURN
   3321                 (_phy_wc40_interlaken_mode_init(unit, port));
   3322         } else {
   3323             SOC_IF_ERROR_RETURN
   3324                 (_phy_wc40_ind_init(unit,port));
   3325         }
   3326     } else {
   3327         SOC_IF_ERROR_RETURN(_wc40_soft_reset(unit,pc)); /* soft reset */
   3328 
   3329         /* Force to comboCore mode.
   3330          * Support SGMII 10/100/1000Mbps, 1000X, 2500X, 10G, and 12G.
   3331          */
   3332         SOC_IF_ERROR_RETURN
   3333             (_phy_wc40_combo_core_init(unit, port));
   3334     }
   3335 	 
   3336 #ifdef BCM_PORT_DEFAULT_DISABLE
   3337     if (!PHY_EXTERNAL_MODE(unit, port) && !SOC_WARM_BOOT(unit)) {
   3338         phy_wc40_enable_set(unit, port, FALSE);
   3339     }
   3340 #endif
   3341 
   3342     LOG_INFO(BSL_LS_SOC_PHY,
   3343              (BSL_META_U(unit,
   3344                          "phy_wc40_init: u=%d p=%d\n"), unit, port));
   3345     return SOC_E_NONE;
   3346 }
   3347 
   3348 #define PCS_STATUS_LANE4_SYNC   0x80F
   3349 STATIC int
   3350 _phy_wc40_war_link_check(int unit, soc_port_t port)
   3351 {     
   3352     uint16 sync_stat;
   3353     uint16 sync_good;
   3354     uint16 link;
   3355     phy_ctrl_t         *pc;
   3356 
   3357     pc = INT_PHY_SW_STATE(unit, port);
   3358 
   3359     /* need to read the current link state */
   3360     SOC_IF_ERROR_RETURN
   3361         (READ_WC40_XGXSBLK4_XGXSSTATUS1r(unit, pc, 0x00, &link));
   3362 
   3363     if (link & XGXSBLK4_XGXSSTATUS1_LINK10G_MASK) {
   3364         link = TRUE;
   3365     } else {
   3366         link = FALSE;
   3367     }
   3368 
   3369     /* if not a valid state, such as in autoneg mode or not BRCM 64B/66B speeds,
   3370      * or if linkup, no need to go thru workaround check
   3371      */
   3372     if ((!WC40_SP_VALID(pc)) || (link==TRUE)) {
   3373         WC40_SP_CNT_CLEAR(pc);
   3374         return SOC_E_NONE;
   3375     }
   3376 
   3377     LOG_INFO(BSL_LS_SOC_PHY,
   3378              (BSL_META_U(unit,
   3379                          "_phy_wc40_war_link_check: u=%d p=%d: \n"), unit, port));
   3380 
   3381     sync_good = PCS_STATUS_LANE4_SYNC;
   3382 
   3383     /* now check the sync status on appropriate lanes. dxgxs0/dxgxs1 and combo
   3384      * should have the same sync status, i.e. 0x80F. dxgxs1 is read from lane 2.
   3385      */
   3386     SOC_IF_ERROR_RETURN
   3387         (READ_WC40_PCS_IEEE1BLK_PCS_LANESTATUSr(unit, pc, 0x00, &sync_stat));
   3388 
   3389     /* check if all lane sync'ed up */
   3390     if (sync_stat == sync_good) {
   3391         if (WC40_SP_CNT(pc)) {
   3392             LOG_INFO(BSL_LS_SOC_PHY,
   3393                      (BSL_META_U(unit,
   3394                                  "_phy_wc40_war_link_check workaround applied: u=%d p=%d: \n"), unit, port));
   3395 
   3396             if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   3397                 /* broadcast to all lanes */
   3398                 SOC_IF_ERROR_RETURN
   3399                     (WRITE_WC40_AERBLK_AERr(unit,pc,0x00, WC_AER_BCST_OFS_STRAP));
   3400 
   3401             } else { /* dual xgxs mode */
   3402                 DUAL_LANE_BCST_ENABLE(pc);
   3403             }
   3404                
   3405             /* if it is synced and no link, do the rx reset */
   3406             SOC_IF_ERROR_RETURN
   3407                 (MODIFY_WC40_DIGITAL5_MISC6r(unit, pc, 0x00,
   3408                                      DIGITAL5_MISC6_RESET_RX_ASIC_MASK,
   3409                                      DIGITAL5_MISC6_RESET_RX_ASIC_MASK));
   3410             SOC_IF_ERROR_RETURN
   3411                 (MODIFY_WC40_DIGITAL5_MISC6r(unit, pc, 0x00, 0,
   3412                                          DIGITAL5_MISC6_RESET_RX_ASIC_MASK));
   3413 
   3414             if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   3415                 /* restore AER */
   3416                 SOC_IF_ERROR_RETURN
   3417                     (WRITE_WC40_AERBLK_AERr(unit,pc,0x00, 0));
   3418             } else { /* dual xgxs mode */
   3419                 DUAL_LANE_BCST_DISABLE(pc);
   3420             }
   3421         } else {
   3422             WC40_SP_CNT_INC(pc);
   3423         }
   3424     }
   3425 
   3426     return SOC_E_NONE;
   3427 }
   3428 
   3429 /*
   3430  *      _phy_wc40_cl73_auto_recover
   3431  * Purpose: Recovers CL73 fsm from 
   3432  *          lockup during some of 
   3433  *          the problematic states
   3434  * Parameters:
   3435  *      unit - StrataSwitch unit #.
   3436  *      port - StrataSwitch port #. 
   3437  * Returns:     
   3438  *      SOC_E_NONE
   3439  */
   3440 STATIC int
   3441 _phy_wc40_cl73_auto_recover(int unit, soc_port_t port, int *link)
   3442 {
   3443    /* WC40_CL73_AUTO_RECOVER feature addresses a link issue 
   3444       found with WarpCore connected to a certain Broadcom PHY, 
   3445       primarily BCM8073. Following autoneg FSM states are 
   3446       known to be symptoms of the issue:
   3447        0x002: Transmit Disable
   3448        0x004: Ability Detect
   3449        0x008: Acknowledge
   3450        0x010: Acknowledge Complete
   3451        0x020: Next Page Wait
   3452     */
   3453     phy_ctrl_t *pc;
   3454     uint16 fsm_state1, fsm_state2, data16, temp_data;
   3455     WC40_CL73_AUTO_RECOVER_t *pdata; 
   3456 
   3457     pc = INT_PHY_SW_STATE(unit, port);
   3458     
   3459     pdata = &DEV_CFG_PTR(pc)->cl73_fsm_auto_recover;
   3460 
   3461     if (DEV_CFG_PTR(pc)->cl73_fsm_auto_recover.enable
   3462             && DEV_CFG_PTR(pc)->cl73an 
   3463             && !(COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode))) {
   3464 
   3465             /* Read RX0_ANARXSTATUS register to check for sig detect first. */
   3466             SOC_IF_ERROR_RETURN
   3467                 (WC40_REG_READ(unit, pc, LANE0_ACCESS,
   3468                                0x80b1 + (0x10 * pc->lane_num), &temp_data));
   3469             SOC_IF_ERROR_RETURN
   3470                 (WC40_REG_MODIFY(unit, pc, LANE0_ACCESS,
   3471                                  0x80b1 + (0x10 * pc->lane_num),
   3472                                  RXB_ANARXCONTROL_STATUS_SEL_sigdetStatus,
   3473                                  RXB_ANARXCONTROL_STATUS_SEL_MASK));
   3474             SOC_IF_ERROR_RETURN
   3475                 (WC40_REG_READ(unit, pc, LANE0_ACCESS, 
   3476                                0x80b0 + (0x10 * pc->lane_num), &data16));
   3477             SOC_IF_ERROR_RETURN
   3478                 (WC40_REG_MODIFY(unit, pc, LANE0_ACCESS,
   3479                                  0x80b1 + (0x10 * pc->lane_num),
   3480                                  temp_data,
   3481                                  RXB_ANARXCONTROL_STATUS_SEL_MASK));
   3482 
   3483             if ((*link == 0) && (DEV_CFG_PTR(pc)->cl73an) && 
   3484             (data16 & RX0_ANARXSTATUS_SIGDET_STATUS_CX4_SIGDET_MASK)) {
   3485 
   3486                 /* Enable cl73 fsm test mux */
   3487                 SOC_IF_ERROR_RETURN
   3488                     (MODIFY_WC40_CL73_USERB0_CL73_UCTRL1r(unit, pc, 0x00, 
   3489                                              CL73_USERB0_CL73_UCTRL1_CL73_USTAT1_MUXSEL_MASK,
   3490                                              CL73_USERB0_CL73_UCTRL1_CL73_USTAT1_MUXSEL_MASK));
   3491                 /* Read fsm status and ignore it first time */
   3492                 SOC_IF_ERROR_RETURN
   3493                     (READ_WC40_CL73_USERB0_CL73_USTAT1r(unit, pc, 0x00, &fsm_state1));
   3494                 /* Read fsm status second time */
   3495                 SOC_IF_ERROR_RETURN
   3496                     (READ_WC40_CL73_USERB0_CL73_USTAT1r(unit, pc, 0x00, &fsm_state1));
   3497                 fsm_state1 = fsm_state1 & 0x0fff;
   3498                 /* Read fsm status third time */
   3499                 SOC_IF_ERROR_RETURN
   3500                     (READ_WC40_CL73_USERB0_CL73_USTAT1r(unit, pc, 0x00, &fsm_state2));
   3501                 fsm_state2 = fsm_state2 & 0x0fff;
   3502 
   3503                 if (fsm_state1 == fsm_state2) {
   3504                     int apply_recovery = 0;
   3505 
   3506                     if (pdata->fsm_state_prev == fsm_state1) {
   3507                         /* The state is still the same as previous iteration.
   3508                            Track how many times we have seen this state. */
   3509                         pdata->fsm_state_count++;
   3510                     } else {
   3511                         /* New state seen compared to the previous iteration.
   3512                            Just save the new state data & start over. */
   3513                         pdata->fsm_state_prev  = fsm_state1;
   3514                         pdata->fsm_state_count = 1;
   3515                     }
   3516 
   3517                     /* FSM state 0x008 is handled differently. */
   3518                     if (0x008 == fsm_state1) {
   3519 
   3520                         if (pdata->fsm_state_count > CL73_AUTO_RECOVER_STATE08_WAIT_COUNT) {
   3521                             /* We've seen enough of state 0x008.  Clear
   3522                                the counter & apply recovery action. */
   3523                             pdata->fsm_state_prev  = 0;
   3524                             pdata->fsm_state_count = 0;
   3525                             apply_recovery = 1;
   3526 
   3527                             /* Update statistics for each recovery. */
   3528                             pdata->action_count_state08++;
   3529                         }
   3530 
   3531                     /* Not state 0x008. */
   3532                     } else {
   3533                         if (pdata->fsm_state_count > CL73_AUTO_RECOVER_LP_STATE_WAIT_COUNT) {
   3534                             /* We've seen enough of this state.  Clear
   3535                                the counter & apply recovery action if
   3536                                it's a state we care about. */
   3537                             pdata->fsm_state_prev  = 0;
   3538                             pdata->fsm_state_count = 0;
   3539 
   3540                             /* Update statistics for each recovery. */
   3541                             switch (fsm_state1) {
   3542                             case 0x002:
   3543                                     apply_recovery = 1;
   3544                                     pdata->action_count_state02++;
   3545                                     break;
   3546                             case 0x004:
   3547                                     apply_recovery = 1;
   3548                                     pdata->action_count_state04++;
   3549                                     break;
   3550                             case 0x010:
   3551                                     apply_recovery = 1;
   3552                                     pdata->action_count_state10++;
   3553                                     break;
   3554                             case 0x020:
   3555                                     apply_recovery = 1;
   3556                                     pdata->action_count_state20++;
   3557                                     break;
   3558                             }
   3559                         }
   3560                     }
   3561 
   3562                     if (apply_recovery) {
   3563                         LOG_INFO(BSL_LS_SOC_PHY,
   3564                                  (BSL_META_U(unit,
   3565                                              "WC: Applying recovery for u:0x%x p:0x%x "
   3566                                              "fsm_state:0x%x\n"), unit, port, fsm_state1));
   3567 
   3568                         WC40_CL73_AN_TX_FIFO_RESET_STOP(pc);
   3569 
   3570                         /* Toggle RX/TX ASIC reset */
   3571                         SOC_IF_ERROR_RETURN
   3572                             (MODIFY_WC40_DIGITAL5_MISC6r(unit, pc, 0x00,
   3573                                                   (DIGITAL5_MISC6_RESET_RX_ASIC_MASK
   3574                                                     | DIGITAL5_MISC6_RESET_TX_ASIC_MASK),
   3575                                                   (DIGITAL5_MISC6_RESET_RX_ASIC_MASK
   3576                                                     | DIGITAL5_MISC6_RESET_TX_ASIC_MASK)));
   3577                         SOC_IF_ERROR_RETURN
   3578                             (MODIFY_WC40_DIGITAL5_MISC6r(unit, pc, 0x00,
   3579                                                   0,
   3580                                                   (DIGITAL5_MISC6_RESET_RX_ASIC_MASK
   3581                                                     | DIGITAL5_MISC6_RESET_TX_ASIC_MASK)));
   3582 
   3583                         WC40_CL73_AN_TX_FIFO_RESET_START(pc);
   3584 
   3585                         LOG_INFO(BSL_LS_SOC_PHY,
   3586                                  (BSL_META_U(unit,
   3587                                              "\n WC: CL73 fsm recovery action counters u:0x%x p:0x%x \n"
   3588                                              " CL73 FSM state 0x%x - %d times\n"
   3589                                              " CL73 FSM state 0x%x - %d times\n"
   3590                                              " CL73 FSM state 0x%x - %d times\n"
   3591                                              " CL73 FSM state 0x%x - %d times\n" 
   3592                                              " CL73 FSM state 0x%x - %d times\n"),
   3593                                   unit, port, 0x2, pdata->action_count_state02,
   3594                                   0x4, pdata->action_count_state04, 
   3595                                   0x8, pdata->action_count_state08, 
   3596                                   0x10, pdata->action_count_state10,
   3597                                   0x20, pdata->action_count_state20));
   3598 
   3599                     }
   3600                 } else {
   3601                     /* (fsm_state1 != fsm_state2). Reset FSM data. */
   3602                     pdata->fsm_state_prev  = 0;
   3603                     pdata->fsm_state_count = 0;
   3604                 }
   3605 
   3606                 /* Disable cl73 fsm test mux */
   3607                 SOC_IF_ERROR_RETURN
   3608                     (MODIFY_WC40_CL73_USERB0_CL73_UCTRL1r(unit, pc, 0x00, 
   3609                                             0,
   3610                                             CL73_USERB0_CL73_UCTRL1_CL73_USTAT1_MUXSEL_MASK));
   3611             }
   3612     }
   3613 
   3614     return SOC_E_NONE;
   3615 }
   3616 
   3617 /*
   3618  *      _phy_wc40_softare_rx_los
   3619  * Purpose:
   3620  *      Psuedo rx los state machine
   3621  * Parameters:
   3622  *      unit - StrataSwitch unit #.
   3623  *      port - StrataSwitch port #. 
   3624  *      link - address of memory to store link up/down state.
   3625  * Returns:     
   3626  *      SOC_E_NONE
   3627  */
   3628 STATIC int
   3629 _phy_wc40_softare_rx_los(int unit, soc_port_t port, int *link)
   3630 {
   3631     uint16      data16 = 0, rx_seq_done = 0;
   3632     phy_ctrl_t *pc;
   3633     int pcs_link = 0;
   3634     uint8 sys_link = 0;
   3635     SOFTWARE_RX_LOS_STATES_t rx_los_state;
   3636     int lane_start = 0, lane_end = 0, index = 0;
   3637     int rv = SOC_E_NONE;
   3638 
   3639     pc = INT_PHY_SW_STATE(unit, port);
   3640 
   3641     if(DEV_CFG_PTR(pc)->sw_rx_los.enable) {
   3642         pcs_link = *link; 
   3643         sys_link = DEV_CFG_PTR(pc)->sw_rx_los.sys_link;
   3644         rx_los_state = DEV_CFG_PTR(pc)->sw_rx_los.state;
   3645         DEV_CFG_PTR(pc)->sw_rx_los.link_status = 0;
   3646        
   3647         if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   3648             lane_start = 0;
   3649             lane_end   = 3;
   3650         } else if (IS_DUAL_LANE_PORT(pc)) {
   3651             lane_start = pc->lane_num;
   3652             lane_end = lane_start + 1;
   3653         } else {  /* quad-port mode */
   3654             lane_start = pc->lane_num;
   3655             lane_end   = lane_start;
   3656         }
   3657 
   3658         /* Read RX SEQUENCE DONE status */
   3659         for (index = lane_start; index <= lane_end; index++) {
   3660             SOC_IF_ERROR_RETURN
   3661                 (WC40_REG_MODIFY(unit, pc, LANE0_ACCESS, 
   3662                                  0x80b1 + (0x10 * index), 
   3663                                  RXB_ANARXCONTROL_STATUS_SEL_sigdetStatus,
   3664                                  RXB_ANARXCONTROL_STATUS_SEL_MASK));
   3665             SOC_IF_ERROR_RETURN
   3666                 (WC40_REG_READ(unit, pc, LANE0_ACCESS, 
   3667                                  0x80b0 + (0x10 * index), &data16));
   3668 
   3669             if(data16 & RX1_ANARXSTATUS_SIGDET_STATUS_RXSEQDONE_MASK) {
   3670                 rx_seq_done = 1;
   3671             } else {
   3672                 rx_seq_done = 0;
   3673                 break;
   3674             }
   3675         }
   3676 
   3677         /* 
   3678           Current State: Don't Care
   3679           Next State: IDLE
   3680           If link was previously TRUE and is still true, 
   3681           set the state to IDLE
   3682         */
   3683         if((sys_link == TRUE) && (pcs_link == TRUE)) {
   3684             rx_los_state = IDLE;
   3685         }
   3686 
   3687         /* 
   3688           Current State: IDLE
   3689           Next State: RESET
   3690           If the state was IDLE(link up) but now link is down, 
   3691           enter the RESET state 
   3692         */
   3693         if((rx_los_state == IDLE) && (pcs_link == FALSE)) {
   3694             rx_los_state = RESET;
   3695             sys_link = FALSE;
   3696         } 
   3697 
   3698         /* 
   3699           Current State: RESET
   3700           Next State: INITIAL_LINK or START_TIMER
   3701           If state is RESET, it's next state could be INITIAL LINK
   3702           or START_TIMER depending upon the pcs_link state
   3703         */
   3704         if(rx_los_state == RESET) {
   3705             if ((pcs_link == TRUE) && (rx_seq_done)){
   3706                 rx_los_state = INITIAL_LINK;
   3707             } else if (rx_seq_done){
   3708             /*Do Nothing to allow rx_los_state to go into RESET atleast once */
   3709             }
   3710         }
   3711 
   3712         /* Take action depending upon the current state */
   3713         switch (rx_los_state) {
   3714             case IDLE:
   3715                 /* Do nothing */
   3716                 /* Link ON condition */
   3717                 break;
   3718 
   3719             case RESET:
   3720 #ifdef SW_RX_LOS_LINK_FLAP_WAR
   3721                 if(DEV_CFG_PTR(pc)->sw_rx_los.fault_report_dis) {
   3722                     SOC_IF_ERROR_RETURN
   3723                         (MAC_CONTROL_SET(DEV_CFG_PTR(pc)->macd, unit, port, 
   3724                                          SOC_MAC_CONTROL_FAULT_LOCAL_ENABLE, TRUE));
   3725                     DEV_CFG_PTR(pc)->sw_rx_los.fault_report_dis = 0;
   3726                 }
   3727                 /* Reset CL82 machine (Intermittent FSM errors) 0x8420.0=1->0 */
   3728                 SOC_IF_ERROR_RETURN
   3729                     (MODIFY_WC40_CL82_USERB0_TX_CONTROL_1r(unit,pc, 0x00, 
   3730                      CL82_USERB0_TX_CONTROL_1_CL82_EN_OVERRIDE_MASK,
   3731                      CL82_USERB0_TX_CONTROL_1_CL82_EN_OVERRIDE_MASK));
   3732                 SOC_IF_ERROR_RETURN
   3733                     (MODIFY_WC40_CL82_USERB0_TX_CONTROL_1r(unit,pc, 0x00, 
   3734                      0, CL82_USERB0_TX_CONTROL_1_CL82_EN_OVERRIDE_MASK));  
   3735 #endif
   3736                 sys_link = FALSE;
   3737                 if(rx_seq_done){
   3738                   rx_los_state = START_TIMER;
   3739                 }  
   3740                 break;
   3741 	
   3742             case INITIAL_LINK:
   3743 #ifdef SW_RX_LOS_LINK_FLAP_WAR
   3744                 /* Disable local fault reporting to avoid link flaps untill
   3745                   link stablizes
   3746                  */
   3747                 SOC_IF_ERROR_RETURN
   3748                     (MAC_CONTROL_SET(DEV_CFG_PTR(pc)->macd, unit, port, 
   3749                                      SOC_MAC_CONTROL_FAULT_LOCAL_ENABLE, FALSE));
   3750                 DEV_CFG_PTR(pc)->sw_rx_los.fault_report_dis = 1;
   3751 #endif
   3752 
   3753                 /* rxSeqStart */
   3754                 for (index = lane_start; index <= lane_end; index++) {
   3755                     SOC_IF_ERROR_RETURN
   3756                         (MODIFY_WC40_DSC2B0_DSC_MISC_CTRL0r(unit, pc, 
   3757                             ln_access[index], 
   3758                             DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_MASK, 
   3759                             DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_MASK));
   3760                 }
   3761 #ifdef SW_RX_LOS_LINK_FLAP_WAR
   3762                 
   3763                 /* Reset CL82 machine (Intermittent FSM errors) 0x8420.0=1->0 */
   3764                 SOC_IF_ERROR_RETURN
   3765                     (MODIFY_WC40_CL82_USERB0_TX_CONTROL_1r(unit,pc, 0x00, 
   3766                      CL82_USERB0_TX_CONTROL_1_CL82_EN_OVERRIDE_MASK,
   3767                      CL82_USERB0_TX_CONTROL_1_CL82_EN_OVERRIDE_MASK));
   3768                 SOC_IF_ERROR_RETURN
   3769                     (MODIFY_WC40_CL82_USERB0_TX_CONTROL_1r(unit,pc, 0x00, 
   3770                      0, CL82_USERB0_TX_CONTROL_1_CL82_EN_OVERRIDE_MASK)); 
   3771 #endif
   3772                 /* Skip the link transition for this rx reset */
   3773                 DEV_CFG_PTR(pc)->sw_rx_los.link_status = 1;
   3774                 rx_los_state = LINK;
   3775                 LOG_VERBOSE(BSL_LS_SOC_PHY,
   3776                             (BSL_META_U(unit,
   3777                                         "SOFTWARE RX LOS : u=%d p=%d state:0x%x \n"), 
   3778                              unit, port, rx_los_state));
   3779                 break;
   3780 
   3781             case LINK:
   3782                 if( pcs_link == TRUE) {
   3783                     sys_link = TRUE;
   3784                     rx_los_state = IDLE;
   3785                 } else {
   3786                     rx_los_state = RESET;
   3787                 }
   3788 #ifdef SW_RX_LOS_LINK_FLAP_WAR
   3789                 /* Enable local fault reporting disabled earlier.
   3790                  */
   3791                 SOC_IF_ERROR_RETURN
   3792                     (MAC_CONTROL_SET(DEV_CFG_PTR(pc)->macd, unit, port, 
   3793                                      SOC_MAC_CONTROL_FAULT_LOCAL_ENABLE, TRUE));
   3794                 DEV_CFG_PTR(pc)->sw_rx_los.fault_report_dis = 0;
   3795 #endif
   3796                 LOG_VERBOSE(BSL_LS_SOC_PHY,
   3797                             (BSL_META_U(unit,
   3798                                         "SOFTWARE RX LOS : u=%d p=%d state:0x%x \n"), 
   3799                              unit, port, rx_los_state));
   3800                 break;
   3801 
   3802             case START_TIMER:
   3803                 rx_los_state = RX_RESTART;  
   3804                 LOG_VERBOSE(BSL_LS_SOC_PHY,
   3805                             (BSL_META_U(unit,
   3806                                         "SOFTWARE RX LOS : u=%d p=%d state:0x%x \n"), 
   3807                              unit, port, rx_los_state));
   3808                 break;
   3809 
   3810             case RX_RESTART:
   3811 #ifdef SW_RX_LOS_LINK_FLAP_WAR
   3812                 /* Disable local fault reporting to avoid link flaps untill
   3813                   link stablizes
   3814                  */
   3815                 SOC_IF_ERROR_RETURN
   3816                     (MAC_CONTROL_SET(DEV_CFG_PTR(pc)->macd, unit, port, 
   3817                                      SOC_MAC_CONTROL_FAULT_LOCAL_ENABLE, FALSE));
   3818                 DEV_CFG_PTR(pc)->sw_rx_los.fault_report_dis = 1;
   3819 #endif
   3820                 /* rxSeqStart */ 
   3821                 for (index = lane_start; index <= lane_end; index++) {
   3822                     SOC_IF_ERROR_RETURN
   3823                         (MODIFY_WC40_DSC2B0_DSC_MISC_CTRL0r(unit, pc, 
   3824                             ln_access[index], 
   3825                             DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_MASK, 
   3826                             DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_MASK));
   3827                 }
   3828                 if( pcs_link == FALSE) {
   3829                     rx_los_state = RESET;
   3830                 } else {
   3831                     rx_los_state = LINK;
   3832                 }
   3833                 LOG_VERBOSE(BSL_LS_SOC_PHY,
   3834                             (BSL_META_U(unit,
   3835                                         "SOFTWARE RX LOS : u=%d p=%d state:0x%x \n"), 
   3836                              unit, port, rx_los_state));
   3837                 /* Skip the link transition for this rx reset */
   3838                 DEV_CFG_PTR(pc)->sw_rx_los.link_status = 1;
   3839                 break;
   3840 
   3841             default:
   3842                 break;
   3843         }
   3844         DEV_CFG_PTR(pc)->sw_rx_los.sys_link = sys_link;;
   3845         DEV_CFG_PTR(pc)->sw_rx_los.state = rx_los_state;
   3846         *link = sys_link;
   3847 
   3848 #ifdef BCM_WARM_BOOT_SUPPORT
   3849         rv |= wc40_wb_sc_handler(unit, port, WC40_WB_SC_UPDATE, WC40_WB_RXLOS) ;
   3850 #endif    
   3851     }
   3852 
   3853     return rv;
   3854 
   3855 }
   3856 
   3857 
   3858 
   3859 
   3860 /*
   3861  *      phy_wc40_link_get
   3862  * Purpose:
   3863  *      Get layer2 connection status.
   3864  * Parameters:
   3865  *      unit - StrataSwitch unit #.
   3866  *      port - StrataSwitch port #. 
   3867  *      link - address of memory to store link up/down state.
   3868  * Returns:     
   3869  *      SOC_E_NONE
   3870  */
   3871 
   3872 STATIC int
   3873 phy_wc40_link_get(int unit, soc_port_t port, int *link)
   3874 {
   3875     uint16      mask16;
   3876     uint16      mii_stat, data16 = 0;
   3877     phy_ctrl_t *pc;
   3878 
   3879     pc = INT_PHY_SW_STATE(unit, port);
   3880 
   3881     if (CUSTOM_MODE(pc)) {
   3882         /* interlaken mode */
   3883         /* configure the status register for sigdet */
   3884         SOC_IF_ERROR_RETURN
   3885             (WC40_REG_MODIFY(unit,pc,0x0,0x80b1 + (0x10 * pc->lane_num),
   3886                    RX0_ANARXCONTROL_STATUS_SEL_sigdetStatus,
   3887                    RX0_ANARXCONTROL_STATUS_SEL_MASK));
   3888 
   3889         SOC_IF_ERROR_RETURN
   3890             (WC40_REG_READ(unit, pc, 0x00, 0x80b0 + (0x10 * pc->lane_num),
   3891                            &data16));
   3892         mask16 = RX0_ANARXSTATUS_SIGDET_STATUS_RXSEQDONE_MASK |
   3893                  RX0_ANARXSTATUS_SIGDET_STATUS_CX4_SIGDET_MASK;
   3894         if ((data16 & mask16) == mask16) { 
   3895             *link = TRUE;
   3896         } else {
   3897             *link = FALSE;
   3898         }
   3899         return SOC_E_NONE;
   3900     }
   3901 
   3902     if (PHY_DISABLED_MODE(unit, port)) {
   3903         *link = FALSE;
   3904         return SOC_E_NONE;
   3905     }
   3906 
   3907     *link = FALSE;
   3908 
   3909     /* IF SW RX LOS is enabled and it's link_status is set, it means the 
   3910        lane is reset during the previous link get - read the link status 
   3911        again to skip the OFF link transition that was forced during the
   3912        SW RX LOS. */
   3913     if((DEV_CFG_PTR(pc)->sw_rx_los.enable) 
   3914          && (DEV_CFG_PTR(pc)->sw_rx_los.link_status)) {
   3915         SOC_IF_ERROR_RETURN
   3916             (READ_WC40_PCS_IEEE0BLK_PCS_IEEESTATUS1r(unit, pc, 0x00, &mii_stat));
   3917     }
   3918 
   3919     /* Check XAUI link first if XAUI mode */
   3920     SOC_IF_ERROR_RETURN
   3921         (READ_WC40_PCS_IEEE0BLK_PCS_IEEESTATUS1r(unit, pc, 0x00, &mii_stat));
   3922     if (mii_stat & MII_STAT_LA) {
   3923         *link = TRUE;
   3924     }
   3925 
   3926     if (FORCE_CL72_IS_ENABLED(pc)) {
   3927         (void)_phy_wc40_force_cl72_state_machine(unit,port,*link);
   3928     }
   3929 
   3930     /* Finally Check combo link */
   3931     if (*link == FALSE) {
   3932         /* IF SW RX LOS is enabled and it's link_status is set, it means 
   3933            the lane is reset during the previous link get - read the link 
   3934            status again to skip the OFF link transition that was forced 
   3935            during the SW RX LOS. */
   3936         if((DEV_CFG_PTR(pc)->sw_rx_los.enable) 
   3937              && (DEV_CFG_PTR(pc)->sw_rx_los.link_status)) {
   3938             SOC_IF_ERROR_RETURN
   3939                 (READ_WC40_COMBO_IEEE0_MIISTATr(unit, pc, 0x00, &mii_stat));
   3940         }
   3941         SOC_IF_ERROR_RETURN
   3942             (READ_WC40_COMBO_IEEE0_MIISTATr(unit, pc, 0x00, &mii_stat));
   3943 
   3944         if (mii_stat & MII_STAT_LA) {
   3945             *link = TRUE;
   3946         }
   3947     }
   3948 
   3949     /*To address the Synchronization issue related to a registered clock gate module
   3950       responsible for providing the 312.5MHz write clock to the TX over-sample FIFO.
   3951       Resetting the FIFO to fix the issue.
   3952      */ 
   3953     if (DEV_CFG_PTR(pc)->cl73an 
   3954             && !(COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode))
   3955             && !DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status) {
   3956         SOC_IF_ERROR_RETURN
   3957             (MODIFY_WC40_DIGITAL5_MISC6r(unit, pc, 0x00,
   3958                  (*link == TRUE)? 0: 
   3959                  DIGITAL5_MISC6_TX_OS8_AFRST_EN_MASK,
   3960                  DIGITAL5_MISC6_TX_OS8_AFRST_EN_MASK));
   3961     }
   3962 
   3963     if (WC40_LINK_WAR_REVS(pc)) {
   3964         (void)_phy_wc40_war_link_check(unit,port);
   3965     }
   3966 
   3967     /* restore mld local fault configuration one second after autoneg starts
   3968      * It needs to be disabled during autoneg
   3969      */
   3970     if (!WC40_CL73_SOFT_KR2(pc)) {
   3971         if (WC40_AN_VALID(pc)) {
   3972             if (WC40_AN_CHECK_TIMEOUT(pc)) {
   3973                 SOC_IF_ERROR_RETURN
   3974                     (WC40_REG_MODIFY(unit, pc, 0x00, 0x842A,0,(1 << 5)));
   3975                 WC40_AN_VALID_RESET(pc);
   3976             }
   3977         }
   3978     }
   3979 
   3980     if ((DEV_CFG_PTR(pc)->cl73an == WC40_CL73_KR2)
   3981            || (DEV_CFG_PTR(pc)->cl73an == WC40_CL73_KR2_WAR)) {
   3982         SOC_IF_ERROR_RETURN
   3983             (_wc40_soft_an_cl73kr2_check(unit,port));
   3984     } else if ((DEV_CFG_PTR(pc)->cl73an == WC40_CL73_KR2_CUSTOM)
   3985              || (DEV_CFG_PTR(pc)->cl73an == WC40_CL73_KR2_CUSTOM_WAR)) {
   3986         SOC_IF_ERROR_RETURN
   3987             (_wc40_soft_an_cl73kr2_custom_check(unit,port));
   3988     }
   3989 
   3990     /* Monitor the CL73 fsm for particular FSM states
   3991        and take action if it sees the same state for a 
   3992        a fixed number of times (implying stuck fsm) to 
   3993        recover fsm.
   3994        TO enable/disable this feature use PHY ctrl:
   3995        PORT_PHY_CONTROL_CL73_FSM_AUTO_RECOVER
   3996      */
   3997     SOC_IF_ERROR_RETURN
   3998         (_phy_wc40_cl73_auto_recover(unit, port, link));
   3999 
   4000 
   4001     /* The SOFTWARE RX LOS attaempts to handle the situation 
   4002        through s/w where no reliable LOS detect is available 
   4003        to WC. This feature can be enabled using phy control.
   4004      */
   4005     SOC_IF_ERROR_RETURN
   4006         (_phy_wc40_softare_rx_los(unit, port, link));
   4007 
   4008 
   4009     /* XXX probably need to qualify  with speed status */
   4010     return (SOC_E_NONE);
   4011 }
   4012 
   4013 /*
   4014  * Function:
   4015  *      phy_wc40_ind_enable_set
   4016  * Purpose:
   4017  *      Enable/Disable phy
   4018  * Parameters:
   4019  *      unit - StrataSwitch unit #.
   4020  *      port - StrataSwitch port #.
   4021  *      enable - on/off state to set
   4022  * Returns:
   4023  *      SOC_E_NONE
   4024  */
   4025 
   4026 STATIC int
   4027 _phy_wc40_ind_enable_set(int unit, soc_port_t port, int enable)
   4028 {
   4029     phy_ctrl_t *pc;
   4030     uint16 mask16;
   4031     uint16 data16;
   4032     uint16 ln_ctrl;
   4033     pc = INT_PHY_SW_STATE(unit, port);
   4034     /* Firmware manages the CL73 timer only if CL73 is enabled 
   4035        and mode10g = 0x4. Otherwise, s/w manages it */ 
   4036     if(!(IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode) 
   4037           && DEV_CFG_PTR(pc)->cl73an 
   4038           && DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status)) {
   4039     SOC_IF_ERROR_RETURN
   4040         (MODIFY_WC40_CL73_USERB0_CL73_UCTRL2r(unit,pc,0x00, 
   4041              enable? 0 : CL73_USERB0_CL73_UCTRL2_SIGDET_TIMER_DIS_MASK, 
   4042              CL73_USERB0_CL73_UCTRL2_SIGDET_TIMER_DIS_MASK));
   4043     }
   4044 
   4045     /* disable the TX */
   4046     mask16 = 1 << (XGXSBLK0_MISCCONTROL1_PMD_LANE0_TX_DISABLE_SHIFT + pc->lane_num); 
   4047     SOC_IF_ERROR_RETURN
   4048         (MODIFY_WC40_XGXSBLK0_MISCCONTROL1r(unit,pc,LANE0_ACCESS,
   4049                 enable? 0: mask16, mask16 ));
   4050 
   4051     /* now power down the lane if not used */
   4052     SOC_IF_ERROR_RETURN
   4053         (READ_WC40_XGXSBLK1_LANECTRL3r(unit,pc,0x00,&ln_ctrl));
   4054 
   4055     mask16 = (1 << pc->lane_num);    /* rx lane */
   4056     if (IS_DUAL_LANE_PORT(pc)) {
   4057         mask16 |= (mask16 << 1);
   4058     }
   4059 
   4060     mask16 |= (mask16 << 4); /* both tx and rx lane */
   4061 
   4062     if (!enable) {
   4063         mask16 |= 0x800;
   4064         /* MAC uses rx0_ck/tx0_ck clock from lane0 for all lanes.
   4065          * Only powerdown lane0 when all other three lane's are powered down
   4066          */ 
   4067         if ((pc->speed_max >= 10000) && (pc->lane_num == 0)) {
   4068             if (((ln_ctrl | mask16) & XGXSBLK1_LANECTRL3_PWRDN_RX_MASK) != 
   4069                 XGXSBLK1_LANECTRL3_PWRDN_RX_MASK) {
   4070                 mask16 &= ~0x11;  /* remove lane0 RX/TX control */
   4071             }
   4072         }
   4073         data16 = mask16;
   4074     } else {
   4075         data16 = 0;
   4076         mask16 |= 0x11;  /* always add lane0 RX when any lane is enabled */
   4077     }
   4078 
   4079     SOC_IF_ERROR_RETURN
   4080         (MODIFY_WC40_XGXSBLK1_LANECTRL3r(unit,pc,0x00,data16,mask16));
   4081 
   4082     if (pc->lane_num == 0) {
   4083         /* Digital Rx/Tx reset */
   4084         SOC_IF_ERROR_RETURN
   4085                 (MODIFY_WC40_DIGITAL5_MISC6r(unit,pc,0x00,
   4086                 enable? 0 : DIGITAL5_MISC6_RESET_RX_ASIC_MASK |
   4087                 DIGITAL5_MISC6_RESET_TX_ASIC_MASK,
   4088                 DIGITAL5_MISC6_RESET_RX_ASIC_MASK |
   4089                 DIGITAL5_MISC6_RESET_TX_ASIC_MASK));
   4090         /* Override analog Rx signal detect */
   4091         SOC_IF_ERROR_RETURN
   4092                 (MODIFY_WC40_RX0_ANARXCONTROLr(unit,pc,0x00,
   4093                  enable? 0 : RX0_ANARXCONTROL_OVERRIDE_SIGDET_EN_MASK,
   4094                  RX0_ANARXCONTROL_OVERRIDE_SIGDET_EN_MASK | 
   4095                  RX0_ANARXCONTROL_OVERRIDE_SIGDET_VAL_MASK));
   4096     }
   4097 
   4098     return SOC_E_NONE;
   4099 }
   4100 
   4101 STATIC int
   4102 _phy_wc40_enable_set(int unit, soc_port_t port, int enable)
   4103 {
   4104     phy_ctrl_t *pc;
   4105     uint16 mask16;
   4106     uint16 data16;
   4107 
   4108     pc = INT_PHY_SW_STATE(unit, port);
   4109     
   4110     /* Firmware manages the CL73 timer only if CL73 is enabled 
   4111        and mode10g = 0x4. Otherwise, s/w manages it */ 
   4112     if(!(IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode) 
   4113           && DEV_CFG_PTR(pc)->cl73an 
   4114           && DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status)) {
   4115     SOC_IF_ERROR_RETURN
   4116         (MODIFY_WC40_CL73_USERB0_CL73_UCTRL2r(unit,pc,0x00, 
   4117              enable? 0 : CL73_USERB0_CL73_UCTRL2_SIGDET_TIMER_DIS_MASK, 
   4118              CL73_USERB0_CL73_UCTRL2_SIGDET_TIMER_DIS_MASK));
   4119     }
   4120 
   4121     /* For WC-A0/A1, when Rx power down is asserted, cl82 pcs is not reset. 
   4122      * Clock switching to refclock from recovered clock while PCS is still
   4123      * running might have steered PCS into unrecoverable state. Disable/enable
   4124      * cl82 PCS accordingly when powering down the device.
   4125      */
   4126 
   4127     mask16 = XGXSBLK1_LANECTRL3_PWRDN_RX_MASK | XGXSBLK1_LANECTRL3_PWRDN_TX_MASK |
   4128              XGXSBLK1_LANECTRL3_PWRDWN_FORCE_MASK;
   4129     if (enable) {
   4130         data16 = 0;
   4131         SOC_IF_ERROR_RETURN
   4132             (MODIFY_WC40_XGXSBLK1_LANECTRL3r(unit,pc,0x00,data16,mask16));
   4133         SOC_IF_ERROR_RETURN
   4134             (MODIFY_WC40_XGXSBLK0_MISCCONTROL1r(unit, pc, 0x00, 0,
   4135                          XGXSBLK0_MISCCONTROL1_GLOBAL_PMD_TX_DISABLE_MASK));
   4136         if (WC40_REVID_A0(pc) || WC40_REVID_A1(pc)) {
   4137         SOC_IF_ERROR_RETURN
   4138             (MODIFY_WC40_CL82_USERB0_TX_CONTROL_1r(unit, pc, 0x00,
   4139                          0,
   4140                          CL82_USERB0_TX_CONTROL_1_CL82_EN_VAL_MASK |
   4141                          CL82_USERB0_TX_CONTROL_1_CL82_EN_OVERRIDE_MASK));
   4142         } else {
   4143             int i = 0;
   4144             /* restart the uc */
   4145             data16 = 3 << DSC1B0_UC_CTRL_SUPPLEMENT_INFO_SHIFT;
   4146             data16 |= 1;    
   4147             mask16 = DSC1B0_UC_CTRL_SUPPLEMENT_INFO_MASK |
   4148                      DSC1B0_UC_CTRL_GP_UC_REQ_MASK;
   4149             for (i= 0; i < 4; i++) {
   4150                 SOC_IF_ERROR_RETURN
   4151                     (MODIFY_WC40_DSC1B0_UC_CTRLr(unit, pc, 
   4152                                                  ln_access[i], 
   4153                                                  data16,mask16));
   4154             }
   4155         }
   4156     } else {
   4157         data16 = mask16;
   4158         if (WC40_REVID_A0(pc) || WC40_REVID_A1(pc)) {
   4159             SOC_IF_ERROR_RETURN
   4160                 (MODIFY_WC40_CL82_USERB0_TX_CONTROL_1r(unit, pc, 0x00,
   4161                          CL82_USERB0_TX_CONTROL_1_CL82_EN_OVERRIDE_MASK,
   4162                          CL82_USERB0_TX_CONTROL_1_CL82_EN_VAL_MASK |
   4163                          CL82_USERB0_TX_CONTROL_1_CL82_EN_OVERRIDE_MASK));
   4164         }
   4165         SOC_IF_ERROR_RETURN
   4166             (MODIFY_WC40_XGXSBLK1_LANECTRL3r(unit,pc,0x00,data16,mask16));
   4167         SOC_IF_ERROR_RETURN
   4168             (MODIFY_WC40_XGXSBLK0_MISCCONTROL1r(unit, pc, 0x00,
   4169                          XGXSBLK0_MISCCONTROL1_GLOBAL_PMD_TX_DISABLE_MASK,
   4170                          XGXSBLK0_MISCCONTROL1_GLOBAL_PMD_TX_DISABLE_MASK));
   4171     }
   4172     return SOC_E_NONE;
   4173 }
   4174 
   4175 /*
   4176  * Function:
   4177  *      phy_wc40_enable_set
   4178  * Purpose:
   4179  *      Enable/Disable phy 
   4180  * Parameters:
   4181  *      unit - StrataSwitch unit #.
   4182  *      port - StrataSwitch port #. 
   4183  *      enable - on/off state to set
   4184  * Returns:     
   4185  *      SOC_E_NONE
   4186  */
   4187 
   4188 STATIC int
   4189 phy_wc40_enable_set(int unit, soc_port_t port, int enable)
   4190 {
   4191     int rv;
   4192     phy_ctrl_t  *pc;
   4193 
   4194     pc = INT_PHY_SW_STATE(unit, port);
   4195     if (enable) {
   4196         PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE);
   4197     } else {
   4198         PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE);
   4199     }
   4200     if (CUSTOM_MODE(pc)) {
   4201         if (enable) {
   4202             SOC_IF_ERROR_RETURN
   4203                 (MODIFY_WC40_TXB_ANATXACONTROL0r(unit,pc,0x00,
   4204                     TXB_ANATXACONTROL0_TX1G_FIFO_RST_MASK, 
   4205                     TXB_ANATXACONTROL0_TX1G_FIFO_RST_MASK));
   4206             SOC_IF_ERROR_RETURN
   4207                 (MODIFY_WC40_TXB_ANATXACONTROL0r(unit,pc,0x00,
   4208                     0, 
   4209                     TXB_ANATXACONTROL0_TX1G_FIFO_RST_MASK));
   4210         }
   4211         return SOC_E_NONE;
   4212     }
   4213 
   4214     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   4215         rv = _phy_wc40_enable_set(unit,port,enable);
   4216     } else {
   4217         rv = _phy_wc40_ind_enable_set(unit, port, enable);
   4218     }
   4219     return rv;
   4220 }
   4221 
   4222 /* XXX VCO 10.3125: 10G,20G_dxgxs,1G,2.5,10M,100M, div66  autoneg
   4223  *          6.25:  10M,100M, 1G, 2.5G, 10G_dxgxs   div40  autoneg
   4224  *          6.5625: 10.5G_dxgxs and 12G_dxgxs      div42  force mode only in ind.
   4225  *          8.125:  15.77G_dxgxs                   div52  force mode only in ind.
   4226  * VCO is only controlled by lane0. All VCO settings, i.e. reg. 0x8308.[8:15]
   4227  * in all lanes must have the same value as for lane0. Switching VCO will bring down
   4228  * the link on all four lanes. 
   4229  * Generally the port configuration thru local_ability_get function should ensure the 
   4230  * supported speeds in a given port should not require switching the VCO in the independent
   4231  * channel mode. However the driver speed/autoneg function will not enforce this 
   4232  * restriction.  
   4233  */
   4234 STATIC int
   4235 _phy_wc40_vco_set(int unit, soc_port_t port, int speed,int speed_val)
   4236 {
   4237     phy_ctrl_t  *pc;
   4238     uint16 data16;
   4239     uint16 mask16;
   4240     uint16 vco_freq;
   4241     uint16 misc1_ctrl;
   4242     uint16 misc3_ctrl;
   4243     int vco_625 = 0;
   4244 
   4245     pc = INT_PHY_SW_STATE(unit, port);
   4246 
   4247     /* only need to check in dxgxs mode */
   4248 
   4249     if ((SOC_IS_HELIX4(unit) || SOC_IS_TD_TT(unit) || SOC_IS_KATANA2(unit)) && 
   4250         (!IS_DUAL_LANE_PORT(pc))) {
   4251         if (DEV_CFG_PTR(pc)->hg_mode) {
   4252             if (speed == 11000) {
   4253                 vco_freq = SERDESDIGITAL_MISC1_REFCLK_SEL_clk_156p25MHz << 
   4254                            SERDESDIGITAL_MISC1_REFCLK_SEL_SHIFT;
   4255                 vco_freq |= SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_BITS <<
   4256                             SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_SHIFT;
   4257                 vco_freq |= SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_div80 <<
   4258                             SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SHIFT;
   4259             } else {
   4260                 vco_freq = SERDESDIGITAL_MISC1_REFCLK_SEL_clk_156p25MHz << 
   4261                            SERDESDIGITAL_MISC1_REFCLK_SEL_SHIFT;
   4262             }
   4263         } else {
   4264             vco_freq = SERDESDIGITAL_MISC1_REFCLK_SEL_clk_156p25MHz << 
   4265                        SERDESDIGITAL_MISC1_REFCLK_SEL_SHIFT;
   4266         }
   4267     } else {
   4268         if (!IS_DUAL_LANE_PORT(pc)) {
   4269             return SOC_E_NONE;
   4270         }
   4271         vco_freq = SERDESDIGITAL_MISC1_REFCLK_SEL_clk_156p25MHz << 
   4272                    SERDESDIGITAL_MISC1_REFCLK_SEL_SHIFT;
   4273         vco_freq |= SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_BITS <<
   4274                     SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_SHIFT;
   4275 
   4276         if (DEV_CFG_PTR(pc)->custom1) {
   4277             vco_freq |= SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_div40 <<
   4278                         SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SHIFT;
   4279             vco_625 = 1;
   4280 
   4281         /* use 10G dxgxs for ethernet mode, 10.5G in HG mode to make it compatiable
   4282          * with HC.
   4283          */
   4284         } else if (speed == 10000) {
   4285             if (DEV_CFG_PTR(pc)->hg_mode) { 
   4286                 vco_freq |= SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_div42 <<
   4287                         SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SHIFT;
   4288             } else {
   4289                 vco_freq |= SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_div40 <<
   4290                         SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SHIFT;
   4291                 vco_625 = 1;
   4292             }
   4293         } else if (speed == 12000) {
   4294             vco_freq |= SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_div42 <<
   4295                         SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SHIFT;
   4296         } else if (speed == 15000) {
   4297             vco_freq |= SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_div52 <<
   4298                         SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SHIFT;
   4299         } else if (speed == 20000) {
   4300             vco_freq |= SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_div66 <<
   4301                         SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SHIFT;
   4302         } else if (speed == 21000) {
   4303             vco_freq |= SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_div80 <<
   4304                         SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SHIFT;
   4305         } else if (speed == 0) {
   4306           /* autoneg, vco needs to be div66 */
   4307           vco_freq |= SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_div66 <<
   4308                       SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SHIFT;
   4309         } else { /* default */
   4310           vco_freq |= SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_div66 <<
   4311                       SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SHIFT;
   4312         }
   4313     }
   4314 
   4315     /* configure recovery clock */
   4316     if (SOC_IS_HELIX4(unit) || SOC_IS_KATANA2(unit)) {
   4317         /* SINGLE_LANE_IN_DUAL_PORT_MODE indicates 1/2.5G @6.25G VCO in Katana2 */
   4318         if ((SOC_IS_HELIX4(unit) && (speed == 2500) && soc_property_port_get(unit, port, spn_SERDES_1000X_AT_6250_VCO, 0)) ||
   4319             (SOC_IS_KATANA2(unit) && IS_SINGLE_LANE_IN_DUAL_PORT_MODE(pc))) {
   4320             vco_625 = 1;
   4321         }
   4322 
   4323         /* Set rx_wclk20_sel(0x8141.12) and txckout33 (0x8141.14)
   4324          * core mode  serdes VCO  0x8141.12  0x8141.14  recovery clock frequency
   4325          *   OS5       6.25G       1'b1       1'b0          156.25Mhz
   4326          *   OS8       10.3125     1'b0       1'b0          156.25Mhz
   4327          */
   4328         if (vco_625 == 1 ) {
   4329             SOC_IF_ERROR_RETURN
   4330                 (MODIFY_WC40_XGXSBLK6_XGXSX2CONTROL2r(unit, pc, LANE0_ACCESS,
   4331                                                      (1 << 12), (1 << 12)));
   4332         } else {
   4333             SOC_IF_ERROR_RETURN
   4334                 (MODIFY_WC40_XGXSBLK6_XGXSX2CONTROL2r(unit, pc, LANE0_ACCESS,
   4335                                                     0, (1 << 12)));
   4336         }
   4337 
   4338     }
   4339 
   4340     /* read current vco freq */
   4341     if (SOC_IS_HELIX4(unit) || SOC_IS_TD_TT(unit) || SOC_IS_KATANA2(unit)) {
   4342         /* restore AER */ 
   4343         SOC_IF_ERROR_RETURN
   4344             (WRITE_WC40_AERBLK_AERr(unit,pc, LANE0_ACCESS, 0));
   4345         SOC_IF_ERROR_RETURN
   4346             (READ_WC40_SERDESDIGITAL_MISC1r(unit, pc, LANE0_ACCESS, &data16));
   4347     } else {
   4348         SOC_IF_ERROR_RETURN
   4349             (READ_WC40_SERDESDIGITAL_MISC1r(unit, pc, 0x00, &data16));
   4350     }
   4351 
   4352     mask16 = SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_MASK |
   4353              SERDESDIGITAL_MISC1_REFCLK_SEL_MASK |
   4354              SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_MASK;
   4355 
   4356     /* return if speed is in same vco frequency */
   4357     if ((data16  & mask16) == vco_freq) {
   4358         return SOC_E_NONE;
   4359     }
   4360 
   4361     LOG_INFO(BSL_LS_SOC_PHY,
   4362              (BSL_META_U(unit,
   4363                          "_phy_wc40_vco_set: u=%d p=%d: vco freq switched: 0x%x\n"), unit, port,
   4364               vco_freq));
   4365 
   4366     /* switch to desired VCO freq */
   4367 
   4368     /* read current speed value */
   4369     SOC_IF_ERROR_RETURN
   4370         (READ_WC40_SERDESDIGITAL_MISC1r(unit, pc, 0x00, &misc1_ctrl));
   4371     misc1_ctrl &= ~(SERDESDIGITAL_MISC1_REFCLK_SEL_MASK |
   4372                     SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_MASK |
   4373                     SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_MASK |
   4374                     SERDESDIGITAL_MISC1_FORCE_SPEED_MASK);                   
   4375     misc1_ctrl |= vco_freq;
   4376     misc1_ctrl |= (speed_val & SERDESDIGITAL_MISC1_FORCE_SPEED_MASK);
   4377 
   4378     SOC_IF_ERROR_RETURN
   4379         (READ_WC40_DIGITAL4_MISC3r(unit, pc, 0x00, &misc3_ctrl));
   4380     if (speed_val & 0x20) {
   4381         misc3_ctrl |= DIGITAL4_MISC3_FORCE_SPEED_B5_MASK;
   4382     } else {
   4383         misc3_ctrl &= ~DIGITAL4_MISC3_FORCE_SPEED_B5_MASK;
   4384     }
   4385 
   4386     /* stop PLL sequencer. Bring down link on all ports */
   4387     /* restore AER */
   4388     if (SOC_IS_HELIX4(unit) || SOC_IS_TD_TT(unit) || SOC_IS_KATANA2(unit)) { 
   4389         SOC_IF_ERROR_RETURN
   4390             (WRITE_WC40_AERBLK_AERr(unit,pc, LANE0_ACCESS, 0));
   4391     }
   4392     SOC_IF_ERROR_RETURN
   4393         (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, LANE0_ACCESS,
   4394                                        0,
   4395                                        XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
   4396 
   4397     /* broadcast to all lanes */
   4398     SOC_IF_ERROR_RETURN
   4399         (WRITE_WC40_AERBLK_AERr(unit,pc, LANE0_ACCESS, WC_AER_BCST_OFS_STRAP));
   4400 
   4401     SOC_IF_ERROR_RETURN
   4402         (WRITE_WC40_SERDESDIGITAL_MISC1r(unit, pc, LANE0_ACCESS, misc1_ctrl));
   4403    
   4404     SOC_IF_ERROR_RETURN
   4405         (WRITE_WC40_DIGITAL4_MISC3r(unit, pc, LANE0_ACCESS, misc3_ctrl));
   4406    
   4407     /* restore AER */ 
   4408     SOC_IF_ERROR_RETURN
   4409         (WRITE_WC40_AERBLK_AERr(unit,pc, LANE0_ACCESS, 0));
   4410 
   4411     /* start PLL sequencer */ 
   4412     SOC_IF_ERROR_RETURN
   4413         (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, LANE0_ACCESS,
   4414                                        XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK,
   4415                                        XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
   4416     (void) _phy_wc40_pll_lock_wait(unit, port);
   4417     _phy_wc40_control_vco_disturbed_set(unit, port);
   4418 
   4419     return SOC_E_NONE;
   4420 }
   4421 
   4422 /*
   4423  * Function:
   4424  *      phy_wc40_enable_get
   4425  * Purpose:
   4426  *      Get Enable/Disable status
   4427  * Parameters:
   4428  *      unit - StrataSwitch unit #.
   4429  *      port - StrataSwitch port #. 
   4430  *      enable - address of where to store on/off state
   4431  * Returns:     
   4432  *      SOC_E_NONE
   4433  */
   4434 
   4435 STATIC int
   4436 phy_wc40_enable_get(int unit, soc_port_t port, int *enable)
   4437 {
   4438     *enable = !PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE);
   4439 
   4440     return SOC_E_NONE;
   4441 }
   4442 
   4443 STATIC int
   4444 _phy_wc40_ind_speed_ctrl_get(int unit, soc_port_t port, int speed,
   4445                              uint16 *speed_val,int *tx_inx)
   4446 {
   4447     phy_ctrl_t  *pc;
   4448     int          hg10g_port = FALSE;
   4449 
   4450     pc = INT_PHY_SW_STATE(unit, port);
   4451 
   4452     if (DEV_CFG_PTR(pc)->hg_mode) { 
   4453         hg10g_port = TRUE;
   4454     }
   4455    
   4456     *speed_val = 0;
   4457     switch (speed) {
   4458     case 3000:
   4459     case 2500:
   4460         *speed_val = SERDESDIGITAL_MISC1_FORCE_SPEED_dr_2500BRCM_X1;
   4461         *tx_inx = TXDRV_6GOS2_INX; 
   4462         break;
   4463 
   4464     /* need to revisit here */
   4465     /* XXX VCO 10.3125: 10G,20G_dxgxs,1G,2.5,10M,100M, div66  autoneg
   4466      *          6.25:  10M,100M, 1G, 2.5G, 10G_dxgxs   div40  autoneg
   4467      *          6.5625: 10.5G_dxgxs and 12G_dxgxs      div42  force mode only in ind. 
   4468      *          8.125:  15.77G_dxgxs                   div52  force mode only in ind.
   4469      */
   4470     case 10000:  /* 10G_XFI, 10G_SFI, 10G dxgxs, 10G dxgxs hig */
   4471         /* speed_val = 0x25;  10G XFI */
   4472         /* speed_val = 0x29;  10G SFI */
   4473 
   4474         if (IS_DUAL_LANE_PORT(pc)) {
   4475             if (DEV_CFG_PTR(pc)->custom1) {
   4476                *speed_val = 0x30;  /* speed_x2_10000 */
   4477             } else if (hg10g_port == TRUE) {
   4478                 /* speed_val = 0x21;   10.5HiG dual-XGXS SCR only */
   4479                 /* speed_val = 0x2D 10GHig DXGXS SCR */
   4480                 *speed_val = 0x21;
   4481             } else {
   4482                 /* speed_val = 0x20;  10G ethernet dual-XGXS */
   4483                 /* speed_val = 0x2E 10G ethernet DXGXS SCR */
   4484                 *speed_val = DEV_CFG_PTR(pc)->scrambler_en? 0x2E: 0x20;
   4485                 *tx_inx = TXDRV_6GOS1_INX; 
   4486             }
   4487         } else {
   4488            if ((DEV_CFG_PTR(pc)->line_intf & WC40_IF_SFI) ||
   4489                (DEV_CFG_PTR(pc)->line_intf & WC40_IF_SR) ||
   4490                (DEV_CFG_PTR(pc)->line_intf & WC40_IF_CR)) {
   4491                *speed_val = SERDESDIGITAL_FORCE_SPEED_dr_10G_SFI;
   4492            } else if (DEV_CFG_PTR(pc)->line_intf & WC40_IF_XFI) {
   4493                *speed_val = SERDESDIGITAL_FORCE_SPEED_dr_10G_XFI;
   4494                *tx_inx = TXDRV_XFI_INX; 
   4495            } else {
   4496                /* XXX default to XFI */
   4497                *speed_val = SERDESDIGITAL_FORCE_SPEED_dr_10G_XFI;
   4498                *tx_inx = TXDRV_XFI_INX; 
   4499            }
   4500         }
   4501         break;
   4502     case 11000:  /* 11G higig solo  */
   4503         /* speed_val = 0x25;  10G XFI */
   4504         /* speed_val = 0x29;  10G SFI */
   4505 
   4506        if ((DEV_CFG_PTR(pc)->line_intf & WC40_IF_SFI) ||
   4507            (DEV_CFG_PTR(pc)->line_intf & WC40_IF_SR) ||
   4508            (DEV_CFG_PTR(pc)->line_intf & WC40_IF_CR)) {
   4509            *speed_val = SERDESDIGITAL_FORCE_SPEED_dr_10G_SFI;
   4510        } else if (DEV_CFG_PTR(pc)->line_intf & WC40_IF_XFI) {
   4511            *speed_val = SERDESDIGITAL_FORCE_SPEED_dr_10G_XFI;
   4512            *tx_inx = TXDRV_XFI_INX; 
   4513        } else {
   4514            /* XXX default to XFI */
   4515            *speed_val = SERDESDIGITAL_FORCE_SPEED_dr_10G_XFI;
   4516            *tx_inx = TXDRV_XFI_INX; 
   4517        }
   4518         break;
   4519     case 12000:  /* dxgxs */
   4520         /* 12.773G       0x23
   4521          * 12.773G CX4   0x24
   4522          * 12G X2        0x2F
   4523          */
   4524         if (DEV_CFG_PTR(pc)->custom1) {
   4525             *speed_val =  0x2F; /* custom1 12.7HiG dual-XGXS*/
   4526         } else if (hg10g_port) {
   4527             *speed_val = 0x23;
   4528         } else {
   4529             *speed_val = 0x24;
   4530         }
   4531         break;
   4532     /* XXX PLL mode sets to SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_div52*/ 
   4533     case 15000: /* speed_15750_hi_dxgxs */
   4534         *speed_val = 0x36; 
   4535         break;
   4536     case 20000: /* 20G dxgxs, 20G dxgxs hig */
   4537         *speed_val = (hg10g_port == TRUE) ?
   4538                      0x27:  /* 20GHiG dual-XGXS */
   4539                      0x28; /* 20G ethernet dual-XGXS */
   4540         if (DEV_CFG_PTR(pc)->line_intf & WC40_IF_KR) {
   4541             *speed_val = 0x3F;  /* 20G KR2 mld2 */
   4542 
   4543             /* part of workaround for KR2 speed status, 
   4544              * disable PCS type auto selection 
   4545              */
   4546             if (WC40_REVID_B(pc)) {
   4547                 SOC_IF_ERROR_RETURN
   4548                     (MODIFY_WC40_DIGITAL4_MISC4r(unit, pc, 0x00, 
   4549                          0,  
   4550                          DIGITAL4_MISC4_PCS_TYPE_AUTO_SELECT_MASK));
   4551             }
   4552         }
   4553         break;
   4554     case 21000:  /* only for HG, 20G speed mode + incresed VCO freq */
   4555         *speed_val = 0x27;
   4556         break;            
   4557     default:
   4558         return SOC_E_PARAM;
   4559     }
   4560     return SOC_E_NONE;
   4561 }
   4562 
   4563 STATIC int
   4564 _phy_wc40_ind_speed_set(int unit, soc_port_t port, int speed)
   4565 {
   4566     phy_ctrl_t  *pc;
   4567     uint16       speed_val, mask16, data16;
   4568     uint16       speed_mii;
   4569     uint16       sgmii_status = 0;
   4570 #ifdef BCM_HELIX4_SUPPORT
   4571     int config_speed = 0;
   4572 #endif
   4573     int tx_inx;
   4574     WC40_TX_DRIVE_t tx_drv[NUM_LANES];
   4575     int force_cl72;
   4576     int cur_mode = 0, new_mode = 0;
   4577 
   4578     pc = INT_PHY_SW_STATE(unit, port);
   4579 
   4580     /* set default entry first */
   4581     tx_inx = TXDRV_DFT_INX;
   4582 
   4583     /* part of workaround for KR2 speed status, 
   4584      * enable PCS type auto selection by default for all speeds
   4585      */
   4586     if (IS_DUAL_LANE_PORT(pc)) {
   4587         if (WC40_REVID_B(pc)) {
   4588             SOC_IF_ERROR_RETURN
   4589                 (MODIFY_WC40_DIGITAL4_MISC4r(unit, pc, 0x00, 
   4590                          DIGITAL4_MISC4_PCS_TYPE_AUTO_SELECT_MASK, 
   4591                          DIGITAL4_MISC4_PCS_TYPE_AUTO_SELECT_MASK));
   4592         }
   4593     }
   4594 #ifdef BCM_HELIX4_SUPPORT
   4595     if (SOC_IS_HELIX4(unit) &&
   4596         soc_property_port_get(unit, port, spn_PORT_MAX_SPEED, 0)) {
   4597         config_speed =  soc_property_port_get(unit, port, 
   4598                                               spn_PORT_MAX_SPEED, speed);
   4599         if (speed > config_speed) {
   4600             speed = config_speed;
   4601         }
   4602     }
   4603 #endif /* BCM_HELIX4_SUPPORT */
   4604     speed_val = 0;
   4605     speed_mii = 0;
   4606     switch (speed) {
   4607     case 0:
   4608         /* Do not change speed */
   4609         return SOC_E_NONE;
   4610     case 10:
   4611         tx_inx = TXDRV_6GOS2_INX;
   4612         speed_mii = MII_CTRL_SS_10;
   4613         break;
   4614     case 100:
   4615         tx_inx = TXDRV_6GOS2_INX;
   4616         speed_mii = MII_CTRL_SS_100;
   4617         break;
   4618     case 1000:
   4619         tx_inx = TXDRV_6GOS2_INX;
   4620         speed_mii = MII_CTRL_SS_1000;
   4621         break;
   4622     default:   /* check brcm speeds */
   4623         SOC_IF_ERROR_RETURN
   4624             (_phy_wc40_ind_speed_ctrl_get(unit,port,speed,&speed_val,&tx_inx));
   4625         break;
   4626     }
   4627 
   4628     /* configure uC for copper medium in SFI mode */
   4629     mask16 = WC40_UC_CTRL_SFP_DAC << (pc->lane_num * 4);
   4630     data16 = 0;
   4631     if (speed_val == SERDESDIGITAL_FORCE_SPEED_dr_10G_SFI) {
   4632         if (DEV_CFG_PTR(pc)->line_intf & WC40_IF_SR) {
   4633             data16 = 0;
   4634             tx_inx = TXDRV_SFI_INX;
   4635         } else if (DEV_CFG_PTR(pc)->line_intf & WC40_IF_CR) {
   4636             data16 = mask16;
   4637             tx_inx = TXDRV_SFIDAC_INX; 
   4638         } else if (DEV_CFG_PTR(pc)->medium == SOC_PORT_MEDIUM_COPPER) {
   4639             data16 =mask16;
   4640             tx_inx = TXDRV_SFIDAC_INX; 
   4641         }
   4642     }
   4643     
   4644     SOC_IF_ERROR_RETURN
   4645         (MODIFY_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit,pc,LANE0_ACCESS,data16,mask16));
   4646 
   4647     /* configure the TX driver parameters per speed mode */        
   4648     SOC_IF_ERROR_RETURN
   4649         (_phy_wc40_tx_control_get(unit, port,&tx_drv[0],tx_inx));
   4650     SOC_IF_ERROR_RETURN
   4651         (_phy_wc40_tx_control_set(unit, port,&tx_drv[0]));
   4652 
   4653     /* check if need to switch to a different VCO */
   4654     if (speed) {
   4655         SOC_IF_ERROR_RETURN
   4656             (_phy_wc40_vco_set(unit,port,speed,speed_val));
   4657     }
   4658 
   4659     DUAL_LANE_BCST_ENABLE(pc);
   4660 
   4661     WC40_CL73_AN_TX_FIFO_RESET_STOP(pc);
   4662 
   4663     /* hold tx/rx in reset */
   4664     SOC_IF_ERROR_RETURN
   4665         (MODIFY_WC40_DIGITAL5_MISC6r(unit,pc,0x00,
   4666               DIGITAL5_MISC6_RESET_RX_ASIC_MASK | DIGITAL5_MISC6_RESET_TX_ASIC_MASK, 
   4667               DIGITAL5_MISC6_RESET_RX_ASIC_MASK | DIGITAL5_MISC6_RESET_TX_ASIC_MASK));
   4668     /* When the VCO is operating at 6.25G, XMAC is receiving a clock from the WarpCore that is a divided version of the 6.25G clock.
   4669        This divided version is not of a high enough frequency in order for the XMAC to process the data at 2.5G on the GMII interface.
   4670        So 4x2.5G on Katana2 and Helix4 using a 6.25G VCO are not supported, only 2x2.5G using a 6.25G VCO is supported.
   4671        When works on 2x2.5G mode, property "serdes_1000x_at_6250_vco" should be configured to allow vco change.
   4672     */
   4673     if (SOC_IS_HELIX4(unit) || SOC_IS_KATANA2(unit)) {
   4674         SOC_IF_ERROR_RETURN(READ_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, LANE0_ACCESS, &data16));
   4675         cur_mode = (data16 & XGXSBLK0_XGXSCONTROL_MODE_10G_MASK) >> XGXSBLK0_XGXSCONTROL_MODE_10G_SHIFT;
   4676         /* SINGLE_LANE_IN_DUAL_PORT_MODE indicates 1/2.5G @6.25G VCO in Katana2 */
   4677         if ((SOC_IS_HELIX4(unit) && (speed == 2500) && soc_property_port_get(unit, port, spn_SERDES_1000X_AT_6250_VCO, 0)) ||
   4678             (SOC_IS_KATANA2(unit) && IS_SINGLE_LANE_IN_DUAL_PORT_MODE(pc))) {
   4679             /* OS5 mode to reduce transmit jitter */
   4680             new_mode = XGXSBLK0_XGXSCONTROL_MODE_10G_IndLane_OS5;
   4681         } else {
   4682             new_mode = XGXSBLK0_XGXSCONTROL_MODE_10G_Indlane_OS8;
   4683         }
   4684 
   4685         if (cur_mode != new_mode) {
   4686             DUAL_LANE_BCST_DISABLE(pc);
   4687             data16 = 0;
   4688             SOC_IF_ERROR_RETURN(READ_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, LANE0_ACCESS, &data16));
   4689             /* Switch to the new mode (os5 or os8) */
   4690             data16 &= ~(XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK);
   4691             data16 &= ~(XGXSBLK0_XGXSCONTROL_MODE_10G_MASK);
   4692             data16 |= new_mode << XGXSBLK0_XGXSCONTROL_MODE_10G_SHIFT;
   4693             SOC_IF_ERROR_RETURN(WRITE_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00, data16));
   4694             DUAL_LANE_BCST_ENABLE(pc);
   4695         }
   4696     }
   4697 
   4698     /* disable 100FX and 100FX auto-detect */
   4699     SOC_IF_ERROR_RETURN
   4700         (MODIFY_WC40_FX100_CONTROL1r(unit,pc,0x00,
   4701                               0,
   4702                               FX100_CONTROL1_AUTODET_EN_MASK |
   4703                               FX100_CONTROL1_ENABLE_MASK));
   4704 
   4705     /* disable 100FX idle detect */
   4706     SOC_IF_ERROR_RETURN
   4707             (MODIFY_WC40_FX100_CONTROL3r(unit,pc,0x00,
   4708                               FX100_CONTROL3_CORRELATOR_DISABLE_MASK,
   4709                               FX100_CONTROL3_CORRELATOR_DISABLE_MASK));
   4710 
   4711     /* Workaround Jira# SDK-32387 */
   4712     /* control the speeds thru pma/pmd register */
   4713     if (WC40_SDK32387_REVS(pc) && (!IS_DUAL_LANE_PORT(pc))) {
   4714         SOC_IF_ERROR_RETURN
   4715             (MODIFY_WC40_SERDESDIGITAL_MISC2r(unit, pc, 0x00,
   4716                            SERDESDIGITAL_MISC2_PMA_PMD_FORCED_SPEED_ENC_EN_MASK,
   4717                            SERDESDIGITAL_MISC2_PMA_PMD_FORCED_SPEED_ENC_EN_MASK));
   4718     }
   4719 
   4720     data16 = speed_val;
   4721     mask16 = SERDESDIGITAL_MISC1_FORCE_SPEED_MASK;
   4722 
   4723     SOC_IF_ERROR_RETURN
   4724         (MODIFY_WC40_SERDESDIGITAL_MISC1r(unit, pc, 0x00, data16, mask16));
   4725 
   4726     data16 = (speed_val & 0x20)?  DIGITAL4_MISC3_FORCE_SPEED_B5_MASK:0;
   4727     if (speed_val == SERDESDIGITAL_FORCE_SPEED_dr_10G_XFI ||
   4728         speed_val == SERDESDIGITAL_FORCE_SPEED_dr_10G_SFI) {
   4729         data16 |= DIGITAL4_MISC3_IND_40BITIF_MASK;
   4730     } 
   4731     mask16 = DIGITAL4_MISC3_FORCE_SPEED_B5_MASK | 
   4732              DIGITAL4_MISC3_IND_40BITIF_MASK;   
   4733     SOC_IF_ERROR_RETURN
   4734         (MODIFY_WC40_DIGITAL4_MISC3r(unit, pc, 0x00, data16, mask16));
   4735 
   4736     force_cl72 = FALSE;
   4737     if (speed == 11000) {
   4738         force_cl72 = DEV_CFG_PTR(pc)->force_cl72 ? TRUE : FALSE;
   4739     }
   4740 
   4741     if ((force_cl72 != FORCE_CL72_IS_ENABLED(pc)) || (force_cl72 == TRUE)) {
   4742         SOC_IF_ERROR_RETURN
   4743             (_phy_wc40_force_cl72_config(unit, port, force_cl72));
   4744         FORCE_CL72_ENABLE(pc) = force_cl72;
   4745     }
   4746 
   4747     /* Workaround Jira# SDK-32387 */
   4748     /* control the speeds thru pma/pmd register */
   4749     if (WC40_SDK32387_REVS(pc) && (!IS_DUAL_LANE_PORT(pc))) {
   4750         SOC_IF_ERROR_RETURN
   4751             (MODIFY_WC40_SERDESDIGITAL_MISC2r(unit, pc, 0x00,
   4752                            0,
   4753                            SERDESDIGITAL_MISC2_PMA_PMD_FORCED_SPEED_ENC_EN_MASK));
   4754     }
   4755 
   4756     if (speed <= 1000) {
   4757         SOC_IF_ERROR_RETURN
   4758             (READ_WC40_SERDESDIGITAL_STATUS1000X1r(unit, pc, 0x00, &sgmii_status));
   4759 
   4760         sgmii_status &= SERDESDIGITAL_STATUS1000X1_SGMII_MODE_MASK;
   4761         if (!sgmii_status && (speed == 100)) {
   4762 
   4763             /* fiber mode 100fx, enable */
   4764             SOC_IF_ERROR_RETURN
   4765                 (MODIFY_WC40_FX100_CONTROL1r(unit,pc,0x00,
   4766                                   FX100_CONTROL1_FAR_END_FAULT_EN_MASK |
   4767                                   FX100_CONTROL1_ENABLE_MASK,
   4768                                   FX100_CONTROL1_FAR_END_FAULT_EN_MASK |
   4769                                   FX100_CONTROL1_ENABLE_MASK));
   4770 
   4771             /* enable 100fx extended packet size */
   4772             SOC_IF_ERROR_RETURN
   4773                 (MODIFY_WC40_FX100_CONTROL2r(unit,pc,0x00,
   4774                                 FX100_CONTROL2_EXTEND_PKT_SIZE_MASK,
   4775                                 FX100_CONTROL2_EXTEND_PKT_SIZE_MASK));
   4776         } else {
   4777             SOC_IF_ERROR_RETURN
   4778                 (MODIFY_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, speed_mii,
   4779                                               MII_CTRL_SS_MASK));
   4780         }
   4781     }
   4782 
   4783     if (SOC_IS_HELIX4(unit) || SOC_IS_KATANA2(unit)) {
   4784         if (cur_mode != new_mode) {
   4785             DUAL_LANE_BCST_DISABLE(pc);
   4786             data16 = 0;
   4787             SOC_IF_ERROR_RETURN(READ_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, LANE0_ACCESS, &data16));
   4788             data16 |= XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK;
   4789             SOC_IF_ERROR_RETURN(WRITE_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00, data16));
   4790             DUAL_LANE_BCST_ENABLE(pc);
   4791 
   4792             (void) _phy_wc40_pll_lock_wait(unit, port);
   4793             _phy_wc40_control_vco_disturbed_set(unit, port);
   4794         }
   4795     }
   4796     /* release the tx/tx reset */
   4797     SOC_IF_ERROR_RETURN
   4798         (MODIFY_WC40_DIGITAL5_MISC6r(unit,pc,0x00,
   4799               0,
   4800               DIGITAL5_MISC6_RESET_RX_ASIC_MASK | DIGITAL5_MISC6_RESET_TX_ASIC_MASK));
   4801 
   4802     WC40_CL73_AN_TX_FIFO_RESET_START(pc);
   4803 
   4804     DUAL_LANE_BCST_DISABLE(pc);
   4805     return SOC_E_NONE;
   4806 }
   4807 
   4808 
   4809 STATIC int
   4810 _phy_wc40_speed_set(int unit, soc_port_t port, int speed)
   4811 {
   4812     phy_ctrl_t  *pc;
   4813     uint16       speed_val, mask;
   4814     uint16       speed_mii;
   4815     uint16       sgmii_status = 0;
   4816     uint16       data16;
   4817     int          hg10g_port = FALSE;
   4818     int          tx_inx;
   4819     int          force_cl72;
   4820     WC40_TX_DRIVE_t tx_drv[NUM_LANES];
   4821 
   4822     pc = INT_PHY_SW_STATE(unit, port);
   4823 
   4824     /* in case it was enabled in previous speed mode */
   4825     force_cl72 = FALSE;
   4826 
   4827     /* set default entry first */
   4828     tx_inx = TXDRV_DFT_INX;
   4829 
   4830     pc = INT_PHY_SW_STATE(unit, port);
   4831     if ((DEV_CFG_PTR(pc)->hg_mode) && (!DEV_CFG_PTR(pc)->cx4_10g)) { 
   4832         hg10g_port = TRUE;
   4833     }
   4834   
   4835     /* set to the default */ 
   4836     SOC_IF_ERROR_RETURN
   4837         (WRITE_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit, pc, 0x00, 0x0));
   4838 
   4839     /* don't reset to default if clock comp is enabled by user */
   4840     if (!(DEV_CTRL_PTR(pc)->clk_comp)) {
   4841         SOC_IF_ERROR_RETURN
   4842             (MODIFY_WC40_XGXSBLK2_UNICOREMODE10Gr(unit, pc, 0x00, 
   4843                   COMBO_HG_XGXS_nLQnCC,
   4844                   XGXSBLK2_UNICOREMODE10G_UNICOREMODE10GHIG_MASK));
   4845     }
   4846 
   4847     if (!(WC40_REVID_A0(pc) || WC40_REVID_A1(pc))) {
   4848         /* clear 42G control, PLL autotune */
   4849         if (DEV_CFG_PTR(pc)->refclk == 161) {
   4850             data16 = 0x900 |   /*div64 */
   4851                      SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_MASK;
   4852         } else {
   4853             data16 = 0;
   4854         }
   4855         SOC_IF_ERROR_RETURN
   4856             (MODIFY_WC40_SERDESDIGITAL_MISC1r(unit, pc, 0x00,
   4857                    data16, 
   4858                    SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_MASK |
   4859                    SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_MASK));
   4860     }
   4861 
   4862     speed_val = 0;
   4863     speed_mii = 0;
   4864     mask      =  SERDESDIGITAL_MISC1_FORCE_SPEED_MASK;
   4865     switch (speed) {
   4866     case 0:
   4867         /* Do not change speed */
   4868         return SOC_E_NONE;
   4869     case 10:
   4870         speed_mii = MII_CTRL_SS_10;
   4871         tx_inx = TXDRV_6GOS2_INX;
   4872         break;
   4873     case 100:
   4874         speed_mii = MII_CTRL_SS_100;
   4875         tx_inx = TXDRV_6GOS2_INX;
   4876         break;
   4877     case 1000:
   4878         speed_mii = MII_CTRL_SS_1000;
   4879         tx_inx = TXDRV_6GOS2_INX;
   4880         break;
   4881     case 2500:
   4882         speed_val = SERDESDIGITAL_MISC1_FORCE_SPEED_dr_2500BRCM_X1; 
   4883         tx_inx = TXDRV_6GOS2_INX;
   4884         break;
   4885     case 5000:
   4886         speed_val = SERDESDIGITAL_MISC1_FORCE_SPEED_dr_5000BRCM_X4;
   4887         tx_inx = TXDRV_6GOS2_INX;
   4888         break;
   4889     case 6000:
   4890         speed_val = SERDESDIGITAL_MISC1_FORCE_SPEED_dr_6000BRCM_X4;
   4891         tx_inx = TXDRV_6GOS2_INX;
   4892         break;
   4893     case 10000:
   4894         speed_val = SERDESDIGITAL_MISC1_FORCE_SPEED_dr_10GBASE_CX4; /* 10G CX4 */
   4895         tx_inx = TXDRV_6GOS2_CX4_INX;
   4896         if ((hg10g_port == TRUE) && DEV_CFG_PTR(pc)->rxaui) {
   4897             /* speed_val = 0x1f;   10HiG dual-XGXS */
   4898             /* speed_val = 0x2D 10GHig DXGXS SCR */
   4899             speed_val = DEV_CFG_PTR(pc)->scrambler_en? 0x2D: 0x1F;
   4900             tx_inx = TXDRV_6GOS1_INX;
   4901         } else if (DEV_CFG_PTR(pc)->rxaui) {
   4902             /* speed_val = 0x20;  10G ethernet dual-XGXS */
   4903             /* speed_val = 0x2E 10G ethernet DXGXS SCR */
   4904             speed_val = DEV_CFG_PTR(pc)->scrambler_en? 0x2E: 0x20;
   4905             tx_inx = TXDRV_6GOS1_INX;
   4906         } else if (hg10g_port == TRUE) {
   4907             speed_val = SERDESDIGITAL_MISC1_FORCE_SPEED_dr_10GHiGig_X4; /* 10G HiG */
   4908             tx_inx = TXDRV_6GOS2_INX;
   4909         }
   4910         break;
   4911     case 12000:
   4912         speed_val = DEV_CFG_PTR(pc)->rxaui? 0x23: /* 12.7HiG dual-XGXS*/
   4913                      SERDESDIGITAL_MISC1_FORCE_SPEED_dr_12GHiGig_X4;   /* 12 HiG */
   4914         tx_inx = TXDRV_6GOS2_INX;
   4915         break;
   4916     case 12500:
   4917         speed_val = SERDESDIGITAL_MISC1_FORCE_SPEED_dr_12p5GHiGig_X4;
   4918         tx_inx = TXDRV_6GOS2_INX;
   4919         break;
   4920     case 13000:
   4921         speed_val = SERDESDIGITAL_MISC1_FORCE_SPEED_dr_13GHiGig_X4;
   4922         tx_inx = TXDRV_6GOS2_INX;
   4923         break;
   4924     case 15000:
   4925         speed_val = SERDESDIGITAL_MISC1_FORCE_SPEED_dr_15GHiGig_X4;
   4926         tx_inx = TXDRV_6GOS2_INX;
   4927         break;
   4928     case 16000:
   4929         speed_val = SERDESDIGITAL_MISC1_FORCE_SPEED_dr_16GHiGig_X4;
   4930         tx_inx = TXDRV_6GOS2_INX;
   4931         break;
   4932     case 20000:
   4933         /* speed_val = 0x2C 20G_SCR */
   4934         speed_val = DEV_CFG_PTR(pc)->scrambler_en? 
   4935                     0x2C:
   4936                     SERDESDIGITAL_MISC1_FORCE_SPEED_dr_20GHiGig_X4;
   4937         if (!(DEV_CFG_PTR(pc)->hg_mode)) {
   4938             /* don't change  if clock comp is enabled by user */
   4939             if (!(DEV_CTRL_PTR(pc)->clk_comp)) {
   4940                 SOC_IF_ERROR_RETURN
   4941                     (MODIFY_WC40_XGXSBLK2_UNICOREMODE10Gr(unit, pc, 0x00,
   4942                       COMBO_HG_XGXS_nCC, 
   4943                       XGXSBLK2_UNICOREMODE10G_UNICOREMODE10GHIG_MASK));
   4944             }
   4945         }
   4946         tx_inx = TXDRV_6GOS1_INX;
   4947         break;
   4948     case 21000:
   4949         speed_val = SERDESDIGITAL_MISC1_FORCE_SPEED_dr_21GHiGig_X4;
   4950         break;
   4951     case 25000:
   4952         speed_val = SERDESDIGITAL_MISC1_FORCE_SPEED_dr_25p45GHiGig_X4;
   4953         break;
   4954     case 30000:
   4955         speed_val = 0x2a;
   4956         tx_inx = TXDRV_XLAUI_INX;
   4957         break;
   4958     case 40000:
   4959         if (DEV_CFG_PTR(pc)->hg_mode) {
   4960             tx_inx = TXDRV_XLAUI_INX;
   4961             if (DEV_CFG_PTR(pc)->line_intf & WC40_IF_KR4) {
   4962                 speed_val = 0x31;  /* 40GKR */
   4963             } else {
   4964                 speed_val = 0x26; /* brcm 40G */
   4965             }
   4966         } else {
   4967             if ((DEV_CFG_PTR(pc)->line_intf & WC40_IF_XLAUI) ||
   4968                 (DEV_CFG_PTR(pc)->line_intf & WC40_IF_KR4) ||
   4969                 (DEV_CFG_PTR(pc)->line_intf & WC40_IF_SR) || 
   4970                 (DEV_CFG_PTR(pc)->line_intf & WC40_IF_KR)) { 
   4971                 speed_val = 0x31;  /* 40GKR */
   4972                 tx_inx = TXDRV_XLAUI_INX;
   4973             } else if ((DEV_CFG_PTR(pc)->line_intf & WC40_IF_CR4) ||
   4974                        (DEV_CFG_PTR(pc)->line_intf & WC40_IF_CR) ) {
   4975                 speed_val = 0x32;  /* 40GCR4 */
   4976                 tx_inx = TXDRV_XLAUI_INX;
   4977             } else {
   4978                 speed_val = 0x31;  /* default 40GKR */
   4979                 tx_inx = TXDRV_XLAUI_INX;
   4980             }
   4981 
   4982             if (WC40_REVID_A0(pc) || WC40_REVID_A1(pc)) {
   4983                 SOC_IF_ERROR_RETURN
   4984                     (WC40_REG_MODIFY(unit, pc, 0x00, 0x00008420, 0x1, 0x3));
   4985             }
   4986         }
   4987         if (DEV_CFG_PTR(pc)->line_intf & WC40_IF_XLAUI) {
   4988             SOC_IF_ERROR_RETURN
   4989                 (WRITE_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit, pc, 0x00, WC40_UC_CTRL_XLAUI));
   4990             tx_inx = TXDRV_XLAUI_INX;
   4991         } else if (DEV_CFG_PTR(pc)->line_intf & WC40_IF_SR) {
   4992             SOC_IF_ERROR_RETURN
   4993                 (WRITE_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit, pc, 0x00, WC40_UC_CTRL_SR4));
   4994             tx_inx = TXDRV_SR4_INX;
   4995         }
   4996         break;
   4997 
   4998     /* only work for BRCM 40G */
   4999     case 42000:
   5000         if (!(WC40_REVID_A0(pc) || WC40_REVID_A1(pc))) {
   5001             speed_val = 0x26; /* use same brcm 40G speed setting */
   5002 
   5003             tx_inx = TXDRV_XLAUI_INX;
   5004             /* force the PLL multiplier x70 */
   5005             SOC_IF_ERROR_RETURN
   5006                 (MODIFY_WC40_SERDESDIGITAL_MISC1r(unit, pc, 0x00, 
   5007                        SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_MASK |
   5008                        (0xc << SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SHIFT),
   5009                        SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_MASK |
   5010                        SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_MASK));
   5011             if (DEV_CFG_PTR(pc)->line_intf & WC40_IF_XLAUI) {
   5012                 SOC_IF_ERROR_RETURN
   5013                     (WRITE_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit, pc, 0x00, 
   5014                                                           WC40_UC_CTRL_XLAUI));
   5015             } else if (DEV_CFG_PTR(pc)->line_intf & WC40_IF_SR) {
   5016                 SOC_IF_ERROR_RETURN
   5017                     (WRITE_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit, pc, 0x00, 
   5018                                                            WC40_UC_CTRL_SR4));
   5019             }
   5020             force_cl72 = DEV_CFG_PTR(pc)->force_cl72? TRUE : FALSE;
   5021         }
   5022         break;
   5023     default:
   5024         return SOC_E_PARAM;
   5025     }
   5026     
   5027     /* configure the TX driver parameters per speed mode */        
   5028     SOC_IF_ERROR_RETURN
   5029         (_phy_wc40_tx_control_get(unit, port,&tx_drv[0],tx_inx));
   5030     SOC_IF_ERROR_RETURN
   5031         (_phy_wc40_tx_control_set(unit, port,&tx_drv[0]));
   5032 
   5033     /* Puts PLL in reset state and forces all datapath into reset state */
   5034     SOC_IF_ERROR_RETURN
   5035         (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00, 0,
   5036                                   XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
   5037 
   5038     /* Select a different OS mode if possible to reduce jitter */
   5039     if (speed <= 2500) {
   5040         /* At 2.5G or less, use OS5 mode */
   5041         data16 = (XGXSBLK0_XGXSCONTROL_MODE_10G_IndLane_OS5 <<
   5042                         XGXSBLK0_XGXSCONTROL_MODE_10G_SHIFT);
   5043     } else {
   5044         /* For all other speeds, just use combo mode */
   5045         data16 = (XGXSBLK0_XGXSCONTROL_MODE_10G_ComboCoreMode <<
   5046                         XGXSBLK0_XGXSCONTROL_MODE_10G_SHIFT);
   5047     }
   5048     SOC_IF_ERROR_RETURN
   5049             (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00, data16,
   5050                                         XGXSBLK0_XGXSCONTROL_MODE_10G_MASK));
   5051 
   5052     if ((force_cl72 != FORCE_CL72_IS_ENABLED(pc)) || (force_cl72 == TRUE)) {
   5053         SOC_IF_ERROR_RETURN
   5054             (_phy_wc40_force_cl72_config(unit,port,force_cl72));
   5055         FORCE_CL72_ENABLE(pc) = force_cl72;
   5056     }
   5057 
   5058     /* 2wire XAUI configuration */
   5059     SOC_IF_ERROR_RETURN
   5060         (_wc40_rxaui_config(unit,pc,DEV_CFG_PTR(pc)->rxaui));
   5061 
   5062     /* disable 100FX and 100FX auto-detect */
   5063     SOC_IF_ERROR_RETURN
   5064         (MODIFY_WC40_FX100_CONTROL1r(unit,pc,0x00,
   5065                               0,
   5066                               FX100_CONTROL1_AUTODET_EN_MASK |
   5067                               FX100_CONTROL1_ENABLE_MASK));
   5068 
   5069     /* disable 100FX idle detect */
   5070     SOC_IF_ERROR_RETURN
   5071             (MODIFY_WC40_FX100_CONTROL3r(unit,pc,0x00,
   5072                               FX100_CONTROL3_CORRELATOR_DISABLE_MASK,
   5073                               FX100_CONTROL3_CORRELATOR_DISABLE_MASK));
   5074 
   5075     if ((speed == 42000) && (DEV_CFG_PTR(pc)->line_intf & WC40_IF_KR4)){
   5076         SOC_IF_ERROR_RETURN
   5077             (MODIFY_WC40_SERDESDIGITAL_MISC1r(unit, pc, 0x00,
   5078                 SERDESDIGITAL_MISC1_FORCE_SPEED_dr_40G_KR4,
   5079                 SERDESDIGITAL_MISC1_FORCE_SPEED_MASK));
   5080     } else {
   5081         SOC_IF_ERROR_RETURN
   5082             (MODIFY_WC40_SERDESDIGITAL_MISC1r(unit, pc, 0x00, speed_val, mask));
   5083     }
   5084 
   5085     SOC_IF_ERROR_RETURN
   5086         (MODIFY_WC40_DIGITAL4_MISC3r(unit, pc, 0x00, 
   5087                 (speed_val & 0x20)?  DIGITAL4_MISC3_FORCE_SPEED_B5_MASK:0,
   5088                 DIGITAL4_MISC3_FORCE_SPEED_B5_MASK));
   5089 
   5090     if (speed <= 1000) {
   5091         SOC_IF_ERROR_RETURN
   5092             (READ_WC40_SERDESDIGITAL_STATUS1000X1r(unit, pc, 0x00, &sgmii_status));
   5093 
   5094         sgmii_status &= SERDESDIGITAL_STATUS1000X1_SGMII_MODE_MASK;
   5095         if (!sgmii_status && (speed == 100)) {
   5096 
   5097             /* fiber mode 100fx, enable */
   5098             SOC_IF_ERROR_RETURN
   5099                 (MODIFY_WC40_FX100_CONTROL1r(unit,pc,0x00,
   5100                                   FX100_CONTROL1_FAR_END_FAULT_EN_MASK |
   5101                                   FX100_CONTROL1_ENABLE_MASK,
   5102                                   FX100_CONTROL1_FAR_END_FAULT_EN_MASK |
   5103                                   FX100_CONTROL1_ENABLE_MASK));
   5104 
   5105             /* enable 100fx extended packet size */
   5106             SOC_IF_ERROR_RETURN
   5107                 (MODIFY_WC40_FX100_CONTROL2r(unit,pc,0x00,
   5108                                 FX100_CONTROL2_EXTEND_PKT_SIZE_MASK,
   5109                                 FX100_CONTROL2_EXTEND_PKT_SIZE_MASK));
   5110         } else {
   5111             SOC_IF_ERROR_RETURN
   5112                 (MODIFY_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, speed_mii,
   5113                                               MII_CTRL_SS_MASK));
   5114         }
   5115     }
   5116 
   5117     /* Bring PLL out of reset */
   5118     SOC_IF_ERROR_RETURN
   5119         (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00,
   5120                               XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK,
   5121                               XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
   5122     (void) _phy_wc40_pll_lock_wait(unit, port);
   5123     _phy_wc40_control_vco_disturbed_set(unit, port);
   5124 
   5125     if ((WC40_REVID_A0(pc) || WC40_REVID_A1(pc)) && (speed == 40000) &&
   5126         (!DEV_CFG_PTR(pc)->hg_mode)) {
   5127                 SOC_IF_ERROR_RETURN
   5128                     (MODIFY_WC40_PCS_IEEE2BLK_PCS_TPCONTROLr(unit, pc, 0x00, (1U << 4),
   5129                         ((1U << 4)|(1U << 1))));
   5130                 sal_usleep(100);
   5131                 SOC_IF_ERROR_RETURN
   5132                     (WC40_REG_MODIFY(unit, pc, 0x00, 0x00008420, 0x0, 0x3));
   5133                 SOC_IF_ERROR_RETURN
   5134                     (WC40_REG_MODIFY(unit, pc, 0x00, 0x00008020, (1U << 2), (1U << 2)));
   5135                 SOC_IF_ERROR_RETURN
   5136                     (WC40_REG_MODIFY(unit, pc, 0x00, 0x00008020, 0, (1U << 2)));
   5137                 sal_usleep(100);
   5138                 SOC_IF_ERROR_RETURN
   5139                     (MODIFY_WC40_PCS_IEEE2BLK_PCS_TPCONTROLr(unit, pc, 0x00, 0x0, (1U << 4)));
   5140     }
   5141 
   5142        return SOC_E_NONE;
   5143 }
   5144 
   5145 STATIC int
   5146 _phy_wc40_interlaken_speed_set(int unit, soc_port_t port, int speed)
   5147 {
   5148     phy_ctrl_t *pc;
   5149     uint16 data16;
   5150     uint16 mask16;
   5151 
   5152     pc = INT_PHY_SW_STATE(unit, port);
   5153 
   5154     mask16 = 0x0303 << (pc->lane_num * 2);
   5155 
   5156     switch (speed) {
   5157         case 6250:
   5158         case 6000:
   5159             data16 = mask16;
   5160             break;
   5161         case 3125:
   5162         case 3000: 
   5163             data16 = 0x0202 << (pc->lane_num * 2);
   5164             break;
   5165         default:
   5166             return SOC_E_PARAM;
   5167     }
   5168     /* hold tx/rx in reset */
   5169     SOC_IF_ERROR_RETURN
   5170         (MODIFY_WC40_DIGITAL5_MISC6r(unit,pc,0x00,
   5171               DIGITAL5_MISC6_RESET_RX_ASIC_MASK | DIGITAL5_MISC6_RESET_TX_ASIC_MASK,
   5172               DIGITAL5_MISC6_RESET_RX_ASIC_MASK | DIGITAL5_MISC6_RESET_TX_ASIC_MASK));
   5173 
   5174     SOC_IF_ERROR_RETURN
   5175         (MODIFY_WC40_XGXSBLK1_LANECTRL1r(unit, pc, 0x00, data16,mask16));
   5176 
   5177     /* release tx/rx reset */
   5178     SOC_IF_ERROR_RETURN
   5179         (MODIFY_WC40_DIGITAL5_MISC6r(unit,pc,0x00,
   5180               0,
   5181               DIGITAL5_MISC6_RESET_RX_ASIC_MASK | DIGITAL5_MISC6_RESET_TX_ASIC_MASK));
   5182     return SOC_E_NONE;
   5183 }
   5184 
   5185 /*
   5186  * Function:
   5187  *      phy_wc40_speed_set
   5188  * Purpose:
   5189  *      Set PHY speed
   5190  * Parameters:
   5191  *      unit - StrataSwitch unit #.
   5192  *      port - StrataSwitch port #. 
   5193  *      speed - link speed in Mbps
   5194  * Returns:     
   5195  *      SOC_E_NONE
   5196  */
   5197 
   5198 STATIC int
   5199 phy_wc40_speed_set(int unit, soc_port_t port, int speed)
   5200 {
   5201     phy_ctrl_t  *pc;
   5202     int rv;
   5203 
   5204     pc = INT_PHY_SW_STATE(unit, port);
   5205 
   5206     if (WC40_LINK_WAR_REVS(pc)) {
   5207         WC40_SP_VALID_RESET(pc);
   5208     }
   5209     
   5210     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   5211         rv = _phy_wc40_speed_set(unit,port,speed);
   5212         if (WC40_LINK_WAR_REVS(pc)) {
   5213             if (speed >=25000) {  /* BRCM 64B/66B mode */
   5214                 WC40_SP_VALID_SET(pc);
   5215             }
   5216         }
   5217     } else {
   5218         if (DEV_CFG_PTR(pc)->custom) {
   5219             rv = _phy_wc40_interlaken_speed_set(unit, port, speed);
   5220         } else {
   5221             rv = _phy_wc40_ind_speed_set(unit,port,speed);
   5222             if (WC40_LINK_WAR_REVS(pc)) {
   5223                 if (speed >=12000) {  /* BRCM 64B/66B mode */
   5224                     WC40_SP_VALID_SET(pc);
   5225                 }
   5226             }
   5227         }
   5228     }
   5229     return rv;
   5230 }
   5231 
   5232 STATIC int
   5233 _phy_wc40_tx_fifo_reset(int unit, soc_port_t port,uint32 speed)
   5234 {
   5235     uint16 data16;
   5236     phy_ctrl_t  *pc;
   5237     pc = INT_PHY_SW_STATE(unit, port);
   5238 
   5239     if (speed == 100) {
   5240         /* check if it is in 100fx mode */
   5241         SOC_IF_ERROR_RETURN
   5242             (READ_WC40_FX100_CONTROL1r(unit,pc,0x00,&data16));
   5243 
   5244         if (data16 & FX100_CONTROL1_ENABLE_MASK) {
   5245             /* reset TX FIFO  */
   5246             SOC_IF_ERROR_RETURN
   5247                 (WC40_REG_MODIFY(unit,pc,LANE0_ACCESS,0x8061 + (0x10 * pc->lane_num),
   5248                                  TX0_ANATXACONTROL0_TX1G_FIFO_RST_MASK,
   5249                                  TX0_ANATXACONTROL0_TX1G_FIFO_RST_MASK));
   5250 
   5251             SOC_IF_ERROR_RETURN
   5252                 (WC40_REG_MODIFY(unit,pc,LANE0_ACCESS,0x8061 + (0x10 * pc->lane_num),
   5253                               0,
   5254                               TX0_ANATXACONTROL0_TX1G_FIFO_RST_MASK));
   5255         }
   5256     }
   5257     return SOC_E_NONE;
   5258 }
   5259 
   5260 /*
   5261  * Function:
   5262  *      _phy_wc40_notify_mac_loopback
   5263  * Purpose:
   5264  *      turn on rx clock compensation in mac loopback mode for
   5265  *      applicable XGXS devices
   5266  * Parameters:
   5267  *      unit - StrataSwitch unit #.
   5268  *      port - StrataSwitch port #.
   5269  *      enable - TRUE mac loopback mode, FALSE not in mac loopback mode
   5270  * Returns:
   5271  *      SOC_E_XXX
   5272  */
   5273 STATIC int
   5274 _phy_wc40_notify_mac_loopback(int unit, soc_port_t port, uint32 enable)
   5275 {
   5276     phy_ctrl_t  *pc;
   5277 
   5278     LOG_INFO(BSL_LS_SOC_PHY,
   5279              (BSL_META_U(unit,
   5280                          "_phy_wc40_notify_mac_loopback: u=%d p=%d enable=0x%x\n"),
   5281               unit, port, enable));
   5282 
   5283     pc = INT_PHY_SW_STATE(unit, port);
   5284 
   5285     /* XMAC loopback mode needs to enable clock comp for single-port mode */
   5286     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   5287         if ((DEV_CTRL_PTR(pc)->clk_comp && (!enable)) ||
   5288             ((!DEV_CTRL_PTR(pc)->clk_comp) && enable)) {
   5289             /* clock compensation configuration in combo mode */
   5290             SOC_IF_ERROR_RETURN
   5291                 (MODIFY_WC40_XGXSBLK2_UNICOREMODE10Gr(unit, pc, 0x00,
   5292                      enable? COMBO_HG_XGXS_nLQ | COMBO_XE_XGXS:
   5293                             COMBO_CLOCK_COMP_DEFAULT,
   5294                      COMBO_CLOCK_COMP_MASK));
   5295             DEV_CTRL_PTR(pc)->clk_comp = enable;
   5296         }
   5297     }
   5298     return SOC_E_NONE;
   5299 }
   5300 
   5301 STATIC int
   5302 _phy_wc40_speed_mode_decode(int speed_mode, int *speed, int *intf, int *scr)
   5303 {
   5304     *scr  = FALSE;
   5305     *intf = SOC_PORT_IF_XGMII;  /* default to XGMII */
   5306     switch (speed_mode) {
   5307         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10M:
   5308             *speed = 10;
   5309             *intf = SOC_PORT_IF_MII;
   5310             break;
   5311         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_100M:
   5312             *speed = 100;
   5313             *intf = SOC_PORT_IF_MII;
   5314             break;
   5315         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_1G:
   5316             *speed = 1000;
   5317             *intf = SOC_PORT_IF_GMII;
   5318             break;
   5319         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_2p5G:
   5320             *speed = 2500;
   5321             *intf = SOC_PORT_IF_GMII;
   5322             break;
   5323         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_5G_X4:
   5324             *speed = 5000;
   5325             break;
   5326         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_6G_X4:
   5327             *speed = 6000;
   5328             break;
   5329         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10G_HiG          :
   5330             *speed = 10000;
   5331             break;
   5332         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10G_CX4          :
   5333             *speed = 10000;
   5334             break;
   5335         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_12G_HiG          :
   5336             *speed = 12000;
   5337             break;
   5338         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_12p5G_X4         :
   5339             *speed = 12500;
   5340             break;
   5341         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_13G_X4           :
   5342             *speed = 13000;
   5343             break;
   5344         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_15G_X4           :
   5345             *speed = 15000;
   5346             break;
   5347         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_16G_X4           :
   5348             *speed = 16000;
   5349             break;
   5350         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_1G_KX            :
   5351             *speed = 1000;
   5352             *intf = SOC_PORT_IF_GMII;
   5353             break;
   5354         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10G_KX4          :
   5355             *speed = 10000;
   5356             break;
   5357         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10G_KR           :
   5358             *speed = 10000;
   5359             *intf = SOC_PORT_IF_KR;
   5360             break;
   5361         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_5G               :
   5362             *speed = 5000;
   5363             break;
   5364         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_6p4G             :
   5365             *speed = 6000;
   5366             break;
   5367         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_20G_X4           :
   5368             *speed = 20000;
   5369             break;
   5370         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_20G_KR2           :
   5371             *speed = 20000;
   5372             *intf = SOC_PORT_IF_KR;
   5373             break;
   5374         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_20G_CR2           :
   5375             *speed = 20000;
   5376             break;
   5377         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_21G_X4           :
   5378             *speed = 21000;
   5379             break;
   5380         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_25G_X4           :
   5381             *speed = 25000;
   5382             break;
   5383         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10G_HiG_DXGXS    :
   5384         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10G_DXGXS        :
   5385         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10p5G_HiG_DXGXS  :
   5386         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10p5G_DXGXS      :
   5387             *speed = 10000;
   5388             break;
   5389         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_12p773G_HiG_DXGXS:
   5390             *speed = 12000;
   5391             break;
   5392         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_12p773G_DXGXS    :
   5393             *speed = 12000;
   5394             break;
   5395         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10G_XFI          :
   5396             *speed = 10000;
   5397             *intf = SOC_PORT_IF_XFI;
   5398             break;
   5399         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_40G              :
   5400             *speed = 40000;
   5401             break;
   5402         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_20G_HiG_DXGXS    :
   5403             *speed = 20000;
   5404             break;
   5405         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_20G_DXGXS        :
   5406             *speed = 20000;
   5407             break;
   5408         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10G_SFI          :
   5409             *speed = 10000;
   5410             *intf = SOC_PORT_IF_SFI;
   5411             break;
   5412         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_31p5G            :
   5413             *speed = 30000;  /* MAC has only 30G speed*/
   5414             break;
   5415         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_32p7G            :
   5416             *speed = 32000;
   5417             break;
   5418         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_20G_SCR          :
   5419             *scr = TRUE;
   5420             *speed = 20000;
   5421             break;
   5422         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10G_HiG_DXGXS_SCR:
   5423             *scr = TRUE;
   5424             *speed = 10000;
   5425             break;
   5426         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10G_DXGXS_SCR    :
   5427             *scr = TRUE;
   5428             *speed = 10000;
   5429             break;
   5430         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_12G_R2           :
   5431             *speed = 12000;
   5432             break;
   5433         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10G_X2           :
   5434             *speed = 10000;
   5435             break;
   5436         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_40G_KR4          :
   5437             *speed = 40000;
   5438             *intf = SOC_PORT_IF_KR4;
   5439             break;
   5440         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_40G_CR4          :
   5441             *speed = 40000;
   5442             *intf = SOC_PORT_IF_CR4;
   5443             break;
   5444         case XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_100G_CR10        :
   5445             *speed = 100000;
   5446             *intf = SOC_PORT_IF_XLAUI;
   5447             break;
   5448         case 0x2c:
   5449             *speed = 15000;
   5450             break;
   5451         default:
   5452             break;
   5453     }
   5454 
   5455     return SOC_E_NONE;
   5456 }
   5457 
   5458 STATIC int
   5459 _phy_wc40_ind_speed_get(int unit, soc_port_t port, int *speed, int *intf, int *scr)
   5460 {
   5461     phy_ctrl_t *pc;
   5462     uint16 speed_mode, temp16;
   5463     int rv;
   5464 
   5465     pc = INT_PHY_SW_STATE(unit, port);
   5466 
   5467     *speed = 0;
   5468     if (pc->lane_num < 2) {
   5469         SOC_IF_ERROR_RETURN
   5470             (READ_WC40_GP2_REG_GP2_2r(unit,pc,0x00,&speed_mode));
   5471         if (pc->lane_num == 0) {
   5472             speed_mode &= GP2_REG_GP2_2_ACTUAL_SPEED_LN0_MASK;
   5473         } else {
   5474             speed_mode &= GP2_REG_GP2_2_ACTUAL_SPEED_LN1_MASK;
   5475             speed_mode >>= GP2_REG_GP2_2_ACTUAL_SPEED_LN1_SHIFT;
   5476         } 
   5477     } else {
   5478         SOC_IF_ERROR_RETURN
   5479             (READ_WC40_GP2_REG_GP2_3r(unit,pc,0x00,&speed_mode));
   5480         if (pc->lane_num == 2) {
   5481             speed_mode &= GP2_REG_GP2_3_ACTUAL_SPEED_LN2_MASK;
   5482         } else {
   5483             speed_mode &= GP2_REG_GP2_3_ACTUAL_SPEED_LN3_MASK;
   5484             speed_mode >>= GP2_REG_GP2_3_ACTUAL_SPEED_LN3_SHIFT;
   5485         } 
   5486     }
   5487     rv = _phy_wc40_speed_mode_decode(speed_mode, speed,intf,scr);
   5488      
   5489     if ((speed_mode == XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10G_SFI) ||
   5490         (speed_mode == XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10G_XFI)) {
   5491         /* PLL mode */
   5492         SOC_IF_ERROR_RETURN
   5493             (READ_WC40_GP2_REG_GP2_0r(unit, pc, 0x00, &temp16));
   5494 
   5495         /* Check PLL mode */
   5496         if( 0xC000 == (temp16 & 0xF000)) {
   5497             *speed = 11000;
   5498         }
   5499     }
   5500     
   5501     if( speed_mode == XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_20G_HiG_DXGXS) {
   5502         /* PLL mode */
   5503         SOC_IF_ERROR_RETURN
   5504             (READ_WC40_GP2_REG_GP2_0r(unit, pc, 0x00, &temp16));
   5505 
   5506         /* Check PLL mode */
   5507         if( 0xC000 == (temp16 & 0xF000)) {
   5508             *speed = 21000;
   5509         }
   5510     }
   5511     return rv;
   5512 }
   5513 
   5514 STATIC int
   5515 _phy_wc40_combo_speed_get(int unit, soc_port_t port, int *speed, int *intf, int *scr)
   5516 {
   5517     phy_ctrl_t *pc;
   5518     uint16 speed_mode;
   5519     uint16 data16;
   5520     int rv;
   5521 
   5522     pc = INT_PHY_SW_STATE(unit, port);
   5523     
   5524     /* XXX should use 0x81d2 same as the ind_speed_get */
   5525     *speed = 0;
   5526     SOC_IF_ERROR_RETURN
   5527         (READ_WC40_XGXSBLK5_XGXSSTATUS4r(unit,pc,0x00,&speed_mode));
   5528     speed_mode &= XGXSBLK5_XGXSSTATUS4_ACTUAL_SPEED_LN0_MASK;
   5529     rv = _phy_wc40_speed_mode_decode(speed_mode, speed,intf,scr);
   5530     if (*speed == 40000) {
   5531         SOC_IF_ERROR_RETURN
   5532             (READ_WC40_SERDESDIGITAL_MISC1r(unit, pc, 0x00,&data16));
   5533         if ((data16 & (SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_MASK |
   5534                       SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_MASK)) ==
   5535                    (SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_MASK |
   5536                    (0xc << SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SHIFT)) ) {
   5537             *speed = 42000;
   5538         } 
   5539     }
   5540     return rv;
   5541 }
   5542 
   5543 STATIC int
   5544 _phy_wc40_interlaken_speed_get(int unit, soc_port_t port, int *speed)
   5545 {
   5546     phy_ctrl_t *pc;
   5547     uint16 data16;
   5548     uint16 speed_mode;
   5549 
   5550     pc = INT_PHY_SW_STATE(unit, port);
   5551 
   5552     SOC_IF_ERROR_RETURN
   5553         (READ_WC40_XGXSBLK1_LANECTRL1r(unit, pc, 0x00, &data16));
   5554     speed_mode = (data16 >> (pc->lane_num * 2)) & 
   5555               XGXSBLK1_LANECTRL1_TX1G_MODE_LN0_MASK;
   5556 
   5557     switch (speed_mode) {
   5558         case XGXSBLK1_LANECTRL1_TX1G_MODE_LN0_DWSDR_div1:
   5559             *speed = 6250;
   5560             break;
   5561         case XGXSBLK1_LANECTRL1_TX1G_MODE_LN0_DWSDR_div2:
   5562             *speed = 3125;
   5563             break;
   5564         default:
   5565             *speed = 0;
   5566             break;
   5567     }
   5568     LOG_INFO(BSL_LS_SOC_PHY,
   5569              (BSL_META_U(unit,
   5570                          "_phy_wc40_interlaken_speed_get: u=%d p=%d LANECTRL1r %04x speed= %d\n"),
   5571               unit, port,data16, *speed));
   5572     return SOC_E_NONE;
   5573 }
   5574 
   5575 /*
   5576  * Function:
   5577  *      phy_wc40_speed_get
   5578  * Purpose:
   5579  *      Get PHY speed
   5580  * Parameters:
   5581  *      unit - StrataSwitch unit #.
   5582  *      port - StrataSwitch port #. 
   5583  *      speed - current link speed in Mbps
   5584  * Returns:     
   5585  *      SOC_E_NONE
   5586  */
   5587 STATIC int
   5588 phy_wc40_speed_get(int unit, soc_port_t port, int *speed)
   5589 {
   5590     phy_ctrl_t *pc;
   5591     int rv;
   5592     int intf;
   5593     int scr;
   5594 
   5595     pc = INT_PHY_SW_STATE(unit, port);
   5596 
   5597     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) { 
   5598         rv = _phy_wc40_combo_speed_get(unit, port, speed,&intf,&scr);
   5599     } else {
   5600         if (DEV_CFG_PTR(pc)->custom) {
   5601             rv = _phy_wc40_interlaken_speed_get(unit, port, speed);
   5602         } else {
   5603             rv = _phy_wc40_ind_speed_get(unit, port, speed,&intf,&scr);
   5604         }
   5605     }
   5606     return rv;
   5607 }
   5608 
   5609 /*
   5610  * software autoneg
   5611  */
   5612 STATIC int
   5613 _wc40_soft_an_cl73kr2_init(int unit, soc_port_t port)
   5614 {
   5615     phy_ctrl_t       *pc;
   5616     uint16 mask16;
   5617     int i;
   5618     uint16 data16;
   5619 
   5620     pc = INT_PHY_SW_STATE(unit, port);
   5621 
   5622     /* disable 1000X parallel detect */
   5623     SOC_IF_ERROR_RETURN
   5624         (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X2r(unit, pc, 0x00,
   5625           0,
   5626           SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK));
   5627 
   5628     /* disable 10G parallel detect */
   5629     SOC_IF_ERROR_RETURN
   5630         (MODIFY_WC40_XGXSBLK5_PARDET10GCONTROLr(unit, pc, 0x00,
   5631               0,
   5632               XGXSBLK5_PARDET10GCONTROL_PARDET10G_EN_MASK));
   5633 
   5634     /* diable CL37 BAM */
   5635     SOC_IF_ERROR_RETURN
   5636         (WRITE_WC40_DIGITAL6_MP5_NEXTPAGECTRLr(unit,pc,0x00,0));
   5637 
   5638     /* disable CL37 */
   5639     SOC_IF_ERROR_RETURN
   5640         (MODIFY_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, 0,
   5641                                          MII_CTRL_AE));
   5642 
   5643     /* diable the CL73 BAM */
   5644     /* need to enable these two bits even BAM is disabled to interop
   5645      * with other BRCM devices properly.
   5646      */
   5647     mask16 = CL73_USERB0_CL73_BAMCTRL1_CL73_BAM_STATION_MNGR_EN_MASK |
   5648                  CL73_USERB0_CL73_BAMCTRL1_CL73_BAMNP_AFTER_BP_EN_MASK |
   5649                  CL73_USERB0_CL73_BAMCTRL1_CL73_BAMEN_MASK;
   5650     SOC_IF_ERROR_RETURN
   5651         (MODIFY_WC40_CL73_USERB0_CL73_BAMCTRL1r(unit, pc, 0x00,
   5652                    0, mask16));
   5653 
   5654     /* Set cl73_suppress_mr_page_rx_dis: 0x8378[15:0]=0x100 */
   5655     SOC_IF_ERROR_RETURN
   5656         (MODIFY_WC40_CL73_USERB0_CL73_UCTRL2r(unit, pc, 0x00, 0x100, 0x100));
   5657 
   5658     DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_INIT;
   5659 
   5660     /* configure CL73 adv0 page: add next page */
   5661     /* BAM73 disabled and NP is set, in this mode, the autoneg will not continue until
   5662      * a null page is sent
   5663      */
   5664     SOC_IF_ERROR_RETURN
   5665         (MODIFY_WC40_AN_IEEE1BLK_AN_ADVERTISEMENT0r(unit,pc,0x0, 0x8001,0x8001));
   5666 
   5667     /* clear KR2 ETA bit */
   5668     SOC_IF_ERROR_RETURN
   5669         (WC40_REG_MODIFY(unit,pc,0x0,0x8450, 0, 1));
   5670 
   5671     SOC_IF_ERROR_RETURN
   5672         (READ_WC40_CL49_USERB0_CONTROLr(unit, pc, 0x00, &data16));
   5673     if ((data16 & (CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_VALUE_MASK |
   5674               CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_CTRL_MASK)) !=
   5675          (CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_VALUE_MASK |
   5676           CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_CTRL_MASK)) {
   5677 
   5678           /* restart the sequence */
   5679           SOC_IF_ERROR_RETURN
   5680               (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00,
   5681                               0,
   5682                               XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
   5683 
   5684           for (i = 0; i < NUM_LANES; i++) {
   5685               SOC_IF_ERROR_RETURN
   5686                   (MODIFY_WC40_CL49_USERB0_CONTROLr(unit, pc,
   5687                     ln_access[i],
   5688                     0,
   5689                     CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_VALUE_MASK |
   5690                     CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_CTRL_MASK));
   5691           }
   5692           SOC_IF_ERROR_RETURN
   5693               (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00,
   5694                               XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK,
   5695                               XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
   5696           /* wait for PLL lock */
   5697           _phy_wc40_pll_lock_wait(unit, port);
   5698           _phy_wc40_control_vco_disturbed_set(unit, port);
   5699 
   5700     }
   5701     return SOC_E_NONE;
   5702 }
   5703 
   5704 STATIC int
   5705 _wc40_soft_an_cl73kr2(int unit, soc_port_t port, int an)
   5706 {
   5707     phy_ctrl_t       *pc;
   5708     uint16 mask16;
   5709     int lane = 0, lane_end = 0, lane_start = 0;
   5710 
   5711     pc = INT_PHY_SW_STATE(unit, port);
   5712     
   5713     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   5714         lane_start = 0;
   5715         lane_end   = 3;
   5716     } else {
   5717         lane_start = pc->lane_num;
   5718         lane_end   = lane_start + 1;
   5719     }
   5720 
   5721     /* Set cl73_suppress_mr_page_rx_dis: 0x8378[15:0]=0x100 */
   5722     SOC_IF_ERROR_RETURN
   5723         (MODIFY_WC40_CL73_USERB0_CL73_UCTRL2r(unit, pc, 0x00, an? 0x100: 0,0x100));
   5724 
   5725     if (an) {
   5726         DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_INIT;
   5727 
   5728         /* disable BAM mode, set 0x8372[15:13]=0.  
   5729          * BAM73 disabled and NP is set, in this mode, the autoneg will be controlled by
   5730          * software and completed until a null page is sent
   5731          */
   5732         mask16 = CL73_USERB0_CL73_BAMCTRL1_CL73_BAM_STATION_MNGR_EN_MASK |
   5733                  CL73_USERB0_CL73_BAMCTRL1_CL73_BAMNP_AFTER_BP_EN_MASK |
   5734                  CL73_USERB0_CL73_BAMCTRL1_CL73_BAMEN_MASK;
   5735         SOC_IF_ERROR_RETURN
   5736             (MODIFY_WC40_CL73_USERB0_CL73_BAMCTRL1r(unit, pc, 0x00,
   5737                        0, mask16));
   5738 
   5739         SOC_IF_ERROR_RETURN
   5740             (MODIFY_WC40_AN_IEEE1BLK_AN_ADVERTISEMENT0r(unit,pc,0x0, 0x8001,0x8001));
   5741 
   5742         /* clear KR2 ETA bit */
   5743         SOC_IF_ERROR_RETURN
   5744             (WC40_REG_MODIFY(unit,pc,0x0,0x8450, 0, 1));
   5745     }
   5746 
   5747     /* restart CL73 AN */
   5748     SOC_IF_ERROR_RETURN
   5749         (WRITE_WC40_AN_IEEE0BLK_AN_IEEECONTROL1r(unit,pc,0x0, an? MII_CTRL_AE | MII_CTRL_RAN: 0));
   5750     /* Clean up: To cover the special case in SOFT KR2 in which tx is squelched */
   5751     if(SOFT_KR2_TIMER_VALID(pc)) {
   5752         SOFT_KR2_TIMER_DIS(pc);
   5753         for (lane = lane_start; lane <= lane_end; lane++) {
   5754             SOC_IF_ERROR_RETURN
   5755                 (WC40_REG_MODIFY(unit,pc,0,
   5756                                 WC40_PER_LANE_TX_DRIVERr(lane), 
   5757                                  0x0000, TX0_TX_DRIVER_ELECIDLE_MASK));
   5758         }
   5759     }
   5760     return SOC_E_NONE;
   5761 }
   5762 
   5763 STATIC int
   5764 _wc40_soft_an_cl73kr2_custom(int unit, soc_port_t port, int an)
   5765 {
   5766 
   5767     return SOC_E_NONE;
   5768 }
   5769 
   5770 
   5771 STATIC int
   5772 _wc40_soft_an_cl73kr2_custom_check(int unit, soc_port_t port)
   5773 {
   5774     return SOC_E_NONE;
   5775 }
   5776 
   5777 STATIC int
   5778 _wc40_soft_an_cl73kr2_check(int unit, soc_port_t port)
   5779 {
   5780     uint16 data16;
   5781     uint16 lp_nxp1;
   5782     uint16 ld_adv;
   5783     uint16 lp_adv = 0;
   5784     uint16 lp_nxp0, lp_nxp0_msg;
   5785     uint16 lp_nxp2, ld_nxp0 = 0, ld_nxp1 = 0, ld_nxp2 = 0;
   5786     phy_ctrl_t       *pc;
   5787     int msg_processed = FALSE;
   5788     int lane = 0, lane_end = 0, lane_start = 0;
   5789 
   5790     pc = INT_PHY_SW_STATE(unit, port);
   5791     
   5792     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   5793         lane_start = 0;
   5794         lane_end   = 3;
   5795     } else {
   5796         lane_start = pc->lane_num;
   5797         lane_end   = lane_start + 1;
   5798     }
   5799     
   5800     /* Waiting for cl73_mr_page_rx, wait for 0x1[6]=1, from linkscan thread */
   5801     SOC_IF_ERROR_RETURN
   5802         (READ_WC40_AN_IEEE0BLK_AN_IEEESTATUS1r(unit,pc,0x0, &data16));
   5803 
   5804     if (data16 & (1 << 6)) {
   5805         SOC_IF_ERROR_RETURN
   5806             (READ_WC40_AN_IEEE1BLK_AN_LP_XNP_ABILITY0r(unit, pc, 0x00,&lp_nxp0));
   5807         SOC_IF_ERROR_RETURN
   5808             (READ_WC40_AN_IEEE1BLK_AN_LP_XNP_ABILITY1r(unit, pc, 0x00, &lp_nxp1));
   5809         SOC_IF_ERROR_RETURN
   5810             (READ_WC40_AN_IEEE1BLK_AN_LP_XNP_ABILITY2r(unit, pc, 0x00, &lp_nxp2));
   5811         SOC_IF_ERROR_RETURN
   5812             (READ_WC40_CL73_USERB0_CL73_USTAT1r(unit, pc, 0x00, &data16));
   5813 
   5814         LOG_VERBOSE(BSL_LS_SOC_PHY,
   5815                     (BSL_META_U(unit,
   5816                                 "KR2 autoneg wait page_rx bit set: u=%d p=%d kr2_state:0x%x,nxp0:0x%x,nxp1:0x%x,nxp2:0x%x,fsm:0x%x\n"), 
   5817                      unit, port,DEV_CTRL_PTR(pc)->soft_kr2.state,lp_nxp0,lp_nxp1,lp_nxp2,data16));
   5818         lp_nxp0_msg = lp_nxp0 & AN_IEEE1BLK_AN_LP_XNP_ABILITY0_MSG_MASK;
   5819 
   5820         /* received base page, start soft autoneg */
   5821         if ((lp_nxp0_msg == 0) && (lp_nxp1 == 0) && (lp_nxp2 == 0)
   5822             && !(DEV_CTRL_PTR(pc)->soft_kr2.state == WC40_SOFT_KR2_STATE_WAIT_4_BP)) {
   5823            DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_INIT; 
   5824 
   5825             /* clear KR2 ETA bit */
   5826             SOC_IF_ERROR_RETURN
   5827                 (WC40_REG_MODIFY(unit,pc,0x0,0x8450, 0, 1));
   5828         }
   5829 
   5830         if((DEV_CFG_PTR(pc)->cl73an == WC40_CL73_KR2_WAR)
   5831           && (SOFT_KR2_TIMER_VALID(pc))) {
   5832             DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_TIMER;
   5833         }     
   5834 
   5835         if (DEV_CTRL_PTR(pc)->soft_kr2.state == WC40_SOFT_KR2_STATE_INIT) {
   5836             if ((lp_nxp0_msg == 0) && (lp_nxp1 == 0) && (lp_nxp2 == 0)) {
   5837                 /* all three Extend pages should be 0 when base page is received */
   5838                 /* store the link partner ability */
   5839                 SOC_IF_ERROR_RETURN
   5840                     (READ_WC40_AN_IEEE1BLK_AN_LP_BASEPAGEABILITY1r(unit, pc, 0x00, &data16));
   5841                 DEV_CTRL_PTR(pc)->soft_kr2.lp_adv = data16;
   5842 
   5843                 SOC_IF_ERROR_RETURN
   5844                     (READ_WC40_AN_IEEE1BLK_AN_LP_BASEPAGEABILITY0r(unit, pc, 0x00, &data16));
   5845 
   5846                 /* WAR to address interop issue with devices such as 8073 and similar.
   5847                    8073 get's into lock up state if we send it a base page with NP=1
   5848                    (already sent). It is found that in order to break that lock up state 
   5849                    WC must squelch the TX for a >= fixed amount of time.
   5850                 */ 
   5851                 if(!(data16 & AN_IEEE1BLK_AN_LP_BASEPAGEABILITY0_NP_MASK)
   5852                    && (DEV_CFG_PTR(pc)->cl73an == WC40_CL73_KR2_WAR)
   5853                    && (!SOFT_KR2_TIMER_VALID(pc))) {
   5854                     /* Base page, next page NP=0 */ 
   5855                     SOC_IF_ERROR_RETURN
   5856                         (MODIFY_WC40_AN_IEEE1BLK_AN_ADVERTISEMENT0r(unit,pc,0x0, 0x0001,0x8001));
   5857 
   5858                     /* restart CL73 AN */
   5859                     SOC_IF_ERROR_RETURN
   5860                         (WRITE_WC40_AN_IEEE0BLK_AN_IEEECONTROL1r(unit,pc,0x0, MII_CTRL_AE | MII_CTRL_RAN));
   5861 
   5862                     /* Start Tx Squelch */
   5863                     for (lane = lane_start; lane <= lane_end; lane++) {
   5864                         SOC_IF_ERROR_RETURN
   5865                             (WC40_REG_MODIFY(unit,pc,0,
   5866                                             WC40_PER_LANE_TX_DRIVERr(lane), 
   5867                                              TX0_TX_DRIVER_ELECIDLE_MASK, TX0_TX_DRIVER_ELECIDLE_MASK));
   5868                     }
   5869 
   5870                     SOFT_KR2_TIMER_EN(pc);
   5871                     SOFT_KR2_RECORD_TIME(pc);
   5872                     DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_TIMER;
   5873                     msg_processed = TRUE;
   5874                     return SOC_E_NONE;
   5875                 }
   5876                 
   5877                 /* Base page, next page NP=1 */ 
   5878                 SOC_IF_ERROR_RETURN
   5879                     (MODIFY_WC40_AN_IEEE1BLK_AN_ADVERTISEMENT0r(unit,pc,0x0, 0x8001,0x8001));
   5880 
   5881                 ld_nxp1 = WC40_BRCM_OUI0;
   5882                 /* BRCM method send BRCM next page */
   5883                 SOC_IF_ERROR_RETURN
   5884                     (WRITE_WC40_AN_IEEE1BLK_AN_XNP_TRANSMIT1r(unit, pc, 0x00, ld_nxp1));
   5885                 ld_nxp2 = WC40_BRCM_OUI1;
   5886                 SOC_IF_ERROR_RETURN
   5887                     (WRITE_WC40_AN_IEEE1BLK_AN_XNP_TRANSMIT2r(unit, pc, 0x00, ld_nxp2));
   5888 
   5889                 /* indicate MP-5 page and next page set */
   5890                 ld_nxp0 = 0x5 | AN_IEEE1BLK_AN_XNP_TRANSMIT0_NP_MASK |
   5891                        AN_IEEE1BLK_AN_XNP_TRANSMIT0_MP_MASK;
   5892                 SOC_IF_ERROR_RETURN
   5893                     (WRITE_WC40_AN_IEEE1BLK_AN_XNP_TRANSMIT0r(unit, pc, 0x00, ld_nxp0));
   5894                 DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_BASE_PAGE; 
   5895                 msg_processed = TRUE;
   5896             }
   5897         } else if (DEV_CTRL_PTR(pc)->soft_kr2.state == WC40_SOFT_KR2_STATE_BASE_PAGE) { 
   5898       
   5899            /* If (7.0019.13 = 1 and 7.0019.10:0 = h5) [MP5 is received], 
   5900               remote partner appears to be sending out next pages symmetrically 
   5901             */ 
   5902             if ((lp_nxp0 & AN_IEEE1BLK_AN_LP_XNP_ABILITY0_NP_MASK)
   5903                  &&(lp_nxp0_msg == WC40_AUTONEG_MSG_MP5) 
   5904                  && (lp_nxp1 == WC40_BRCM_OUI0) 
   5905                  && (lp_nxp2 == WC40_BRCM_OUI1)) {
   5906             
   5907                 /* match BRCM MP-5, now send BAM3 page indicating KR2 */
   5908                 ld_nxp1 = DEV_CTRL_PTR(pc)->soft_kr2.ld_kr2? WC40_BRCM_ETA_KR2: 0;
   5909                 SOC_IF_ERROR_RETURN
   5910                     (WRITE_WC40_AN_IEEE1BLK_AN_XNP_TRANSMIT1r(unit, pc, 0x00, ld_nxp1));
   5911 
   5912                 ld_nxp2 = 0x00;
   5913                 SOC_IF_ERROR_RETURN
   5914                     (WRITE_WC40_AN_IEEE1BLK_AN_XNP_TRANSMIT2r(unit, pc, 0x00, ld_nxp2));
   5915                 /* Send UP1 with KR2 ability set */
   5916                 ld_nxp0 = WC40_BRCM_CODE_BAM3 | AN_IEEE1BLK_AN_XNP_TRANSMIT0_NP_MASK;
   5917                 SOC_IF_ERROR_RETURN
   5918                     (WRITE_WC40_AN_IEEE1BLK_AN_XNP_TRANSMIT0r(unit, pc, 0x00, ld_nxp0));
   5919                 
   5920                 DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_MP5; 
   5921                 msg_processed = TRUE;
   5922             }
   5923         } else if (DEV_CTRL_PTR(pc)->soft_kr2.state == WC40_SOFT_KR2_STATE_MP5) {
   5924             if ((lp_nxp0_msg == WC40_BRCM_CODE_BAM3) && (lp_nxp2 == 0)) {
   5925                 /* KR2 match */
   5926                 if (lp_nxp0_msg == WC40_BRCM_CODE_BAM3 && lp_nxp1 == WC40_BRCM_ETA_KR2) {
   5927                     lp_adv = CL73_AN_ADV_TECH_20G_KR2;
   5928                 }
   5929                 DEV_CTRL_PTR(pc)->soft_kr2.lp_adv |= lp_adv; 
   5930                 DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_UP1;
   5931             }
   5932         } else if(DEV_CTRL_PTR(pc)->soft_kr2.state == WC40_SOFT_KR2_STATE_TIMER) {
   5933             /* Received a page:
   5934                Disable the timer if it is timed out. Remove the tx squelch.
   5935             */
   5936             if(SOFT_KR2_TIMER_VALID(pc)
   5937                && (DEV_CFG_PTR(pc)->cl73an == WC40_CL73_KR2_WAR)) {
   5938                if(SOFT_KR2_CHECK_TIMEOUT(pc)) {
   5939                    SOFT_KR2_TIMER_DIS(pc);
   5940                     for (lane = lane_start; lane <= lane_end; lane++) {
   5941                         SOC_IF_ERROR_RETURN
   5942                             (WC40_REG_MODIFY(unit,pc,0,
   5943                                             WC40_PER_LANE_TX_DRIVERr(lane), 
   5944                                              0x0000, TX0_TX_DRIVER_ELECIDLE_MASK));
   5945                     }
   5946                    DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_WAIT_4_BP;
   5947                }
   5948                msg_processed = TRUE;
   5949                return SOC_E_NONE;
   5950             }
   5951         } else if(DEV_CTRL_PTR(pc)->soft_kr2.state == WC40_SOFT_KR2_STATE_WAIT_4_BP) {
   5952 
   5953           if((lp_nxp0_msg == 0) && (lp_nxp1 == 0) && (lp_nxp2 == 0)) {
   5954               DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_INIT;
   5955           }
   5956           msg_processed = TRUE;
   5957           return SOC_E_NONE;
   5958 
   5959         } else if(DEV_CTRL_PTR(pc)->soft_kr2.state == WC40_SOFT_KR2_STATE_WAIT_4_NP) {
   5960             /* Added state WC40_SOFT_KR2_STATE_WAIT_4_NP to avoid sending extra NP*/ 
   5961             if(data16 & AN_IEEE1BLK_AN_LP_BASEPAGEABILITY0_NP_MASK) {
   5962                 /* If next page is still set, send NULL page */
   5963                 DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_DONE;
   5964                 msg_processed = TRUE;
   5965             } else if (lp_nxp0_msg == 0x1) {
   5966                 /* Recevied NULL page */
   5967                 DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_INIT;
   5968                 msg_processed = TRUE;
   5969                 return SOC_E_NONE;
   5970             }
   5971         }
   5972 
   5973         if(DEV_CTRL_PTR(pc)->soft_kr2.state == WC40_SOFT_KR2_STATE_UP1) {
   5974 
   5975             /* 
   5976                1. If remote partner is sending next pages symmetrically, 
   5977                then if (7.0019.10:0 = h1), the remote partner is sending 
   5978                null pages and is likely another BRCM device.
   5979                
   5980                OR
   5981 
   5982                2. If remote partner is sending next pages pre-MP5 and MP5 was received, 
   5983                then if (7.0019.15 = 0) [UP1 was received]
   5984              */ 
   5985 
   5986             if( (lp_nxp0_msg == WC40_AUTONEG_MSG_NULL) ||
   5987                 ((lp_nxp0 & AN_IEEE1BLK_AN_LP_XNP_ABILITY0_NP_MASK) == 0)) {
   5988 
   5989                 SOC_IF_ERROR_RETURN
   5990                     (READ_WC40_AN_IEEE1BLK_AN_ADVERTISEMENT1r(unit, pc, 0x00, &ld_adv));
   5991                 ld_adv |= DEV_CTRL_PTR(pc)->soft_kr2.ld_kr2? CL73_AN_ADV_TECH_20G_KR2: 0;
   5992                 lp_adv = DEV_CTRL_PTR(pc)->soft_kr2.lp_adv;
   5993                 
   5994                 /* use PCS type auto-selection for all speeds other than KR2 */
   5995                 if (WC40_REVID_B(pc)) {
   5996                         SOC_IF_ERROR_RETURN
   5997                             (MODIFY_WC40_DIGITAL4_MISC4r(unit, pc, 0x00, 
   5998                                      DIGITAL4_MISC4_PCS_TYPE_AUTO_SELECT_MASK, 
   5999                                      DIGITAL4_MISC4_PCS_TYPE_AUTO_SELECT_MASK));
   6000                 }
   6001                 /* resolve to KR4 */      
   6002                 if ((ld_adv & lp_adv & CL73_AN_ADV_PLUS_KR2_MASK) & 
   6003                     CL73_AN_ADV_TECH_40G_KR4) { 
   6004                     /* do nothing */ 
   6005                     LOG_VERBOSE(BSL_LS_SOC_PHY,
   6006                                 (BSL_META_U(unit,
   6007                                             "resolved to KR4 : u=%d p=%d\n"), unit, port));
   6008                 } else if ((ld_adv & lp_adv & CL73_AN_ADV_PLUS_KR2_MASK) & 
   6009                     CL73_AN_ADV_TECH_20G_KR2) {  
   6010 
   6011                     /* workaround for KR2 speed status, use fixed PCS type */
   6012                     if (WC40_REVID_B(pc)) {
   6013                         /* disable PCS type auto selection */
   6014                         SOC_IF_ERROR_RETURN
   6015                             (MODIFY_WC40_DIGITAL4_MISC4r(unit, pc, 0x00, 
   6016                                      0, 
   6017                                      DIGITAL4_MISC4_PCS_TYPE_AUTO_SELECT_MASK));
   6018 
   6019                         /* 40GBASE-R PCS type */ 
   6020                         SOC_IF_ERROR_RETURN
   6021                             (MODIFY_WC40_PCS_IEEE0BLK_PCS_IEEECONTROL2r(unit, pc, 0x00, 
   6022                                  0x4, PCS_IEEE0BLK_PCS_IEEECONTROL2_PCS_TYPESEL_MASK));
   6023                     }
   6024 
   6025                     /* set KR2 ETA bit */
   6026                     SOC_IF_ERROR_RETURN
   6027                         (WC40_REG_MODIFY(unit,pc,0x0,0x8450, 1, 1));
   6028                     LOG_VERBOSE(BSL_LS_SOC_PHY,
   6029                                 (BSL_META_U(unit,
   6030                                             "KR2 autoneg resolves to KR2: u=%d p=%d\n"), unit, port));
   6031 
   6032                 } else {  /* all other speeds */
   6033                     LOG_VERBOSE(BSL_LS_SOC_PHY,
   6034                                 (BSL_META_U(unit,
   6035                                             "resolved to non KR2/KR4 speeds: u=%d p=%d\n"), unit, port));
   6036                 }
   6037         
   6038                 DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_DONE; 
   6039                 msg_processed = TRUE;
   6040             }
   6041         }
   6042         /* handle unknow next page */
   6043         if (msg_processed == FALSE) {
   6044             if (lp_nxp0 & AN_IEEE1BLK_AN_LP_XNP_ABILITY0_NP_MASK) {
   6045                 /* Send a NULL next page */
   6046                 ld_nxp1 =0x00;
   6047                 SOC_IF_ERROR_RETURN
   6048                    (WRITE_WC40_AN_IEEE1BLK_AN_XNP_TRANSMIT1r(unit, pc, 0x00, ld_nxp1));
   6049                 ld_nxp2 =0x00;
   6050                 SOC_IF_ERROR_RETURN
   6051                     (WRITE_WC40_AN_IEEE1BLK_AN_XNP_TRANSMIT2r(unit, pc, 0x00, ld_nxp2));
   6052                 ld_nxp0 =0xA001;
   6053                 SOC_IF_ERROR_RETURN
   6054                     (WRITE_WC40_AN_IEEE1BLK_AN_XNP_TRANSMIT0r(unit, pc, 0x00, ld_nxp0));
   6055             } else { 
   6056                /* received autoneg termination null page, responds accordingly */
   6057                DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_DONE;
   6058             }
   6059         }
   6060 
   6061         if (DEV_CTRL_PTR(pc)->soft_kr2.state == WC40_SOFT_KR2_STATE_DONE) {
   6062             /* completes the autoneg by send out a null page with NP=0 */
   6063             ld_nxp1 =0x00;
   6064             SOC_IF_ERROR_RETURN
   6065                 (WRITE_WC40_AN_IEEE1BLK_AN_XNP_TRANSMIT1r(unit, pc, 0x00, ld_nxp1));
   6066             ld_nxp2 =0x00;
   6067             SOC_IF_ERROR_RETURN
   6068                 (WRITE_WC40_AN_IEEE1BLK_AN_XNP_TRANSMIT2r(unit, pc, 0x00, ld_nxp2));
   6069             ld_nxp0 =0x2001;
   6070             SOC_IF_ERROR_RETURN
   6071                 (WRITE_WC40_AN_IEEE1BLK_AN_XNP_TRANSMIT0r(unit, pc, 0x00, ld_nxp0));
   6072             DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_WAIT_4_NP;
   6073         }
   6074         LOG_VERBOSE(BSL_LS_SOC_PHY,
   6075                     (BSL_META_U(unit,
   6076                                 "KR2 autoneg tx page: u=%d p=%d kr2_state:0x%x,tx_nxp0:0x%x,tx_nxp1:0x%x,tx_nxp2:0x%x\n"), 
   6077                      unit, port,DEV_CTRL_PTR(pc)->soft_kr2.state,ld_nxp0,ld_nxp1,ld_nxp2));
   6078     } else {
   6079         /* No page received */
   6080         if(SOFT_KR2_TIMER_VALID(pc)
   6081            && (DEV_CFG_PTR(pc)->cl73an == WC40_CL73_KR2_WAR)) {
   6082             if(SOFT_KR2_CHECK_TIMEOUT(pc)) {
   6083                 SOFT_KR2_TIMER_DIS(pc);
   6084                 for (lane = lane_start; lane <= lane_end; lane++) {
   6085                     SOC_IF_ERROR_RETURN
   6086                         (WC40_REG_MODIFY(unit,pc,0,
   6087                                         WC40_PER_LANE_TX_DRIVERr(lane), 
   6088                                          0x0000, TX0_TX_DRIVER_ELECIDLE_MASK));
   6089                 }
   6090                 DEV_CTRL_PTR(pc)->soft_kr2.state = WC40_SOFT_KR2_STATE_WAIT_4_BP;
   6091                 LOG_VERBOSE(BSL_LS_SOC_PHY,
   6092                             (BSL_META_U(unit,
   6093                                         "KR2 autoneg (WAR) no page rcvd: u=%d p=%d kr2_state:0x%x\n"), 
   6094                              unit, port,DEV_CTRL_PTR(pc)->soft_kr2.state));
   6095             }
   6096         }
   6097     }
   6098 
   6099     return SOC_E_NONE;
   6100 }
   6101 
   6102 /*
   6103  * Function:    
   6104  *      phy_wc40_an_set
   6105  * Purpose:     
   6106  *      Enable or disabled auto-negotiation on the specified port.
   6107  * Parameters:
   6108  *      unit - StrataSwitch unit #.
   6109  *      port - StrataSwitch port #. 
   6110  *      an   - Boolean, if true, auto-negotiation is enabled 
   6111  *              (and/or restarted). If false, autonegotiation is disabled.
   6112  * Returns:     
   6113  *      SOC_E_XXX
   6114  */
   6115 int
   6116 phy_wc40_an_set(int unit, soc_port_t port, int an)
   6117 {
   6118     phy_ctrl_t  *pc;
   6119     uint16             an_enable;
   6120     uint16             auto_det;
   6121     uint16             mask16;
   6122     uint16             data16;
   6123     WC40_TX_DRIVE_t tx_drv[NUM_LANES];
   6124 
   6125     pc = INT_PHY_SW_STATE(unit, port);
   6126 
   6127     if (AUTONEG_MODE_UNAVAIL(pc)) {
   6128         return SOC_E_NONE;
   6129     }
   6130 
   6131     LOG_INFO(BSL_LS_SOC_PHY,
   6132              (BSL_META_U(unit,
   6133                          "phy_wc40_an_set: u=%d p=%d an=%d\n"),
   6134               unit, port, an));
   6135 
   6136     an_enable = 0;
   6137     auto_det  = 0;
   6138 
   6139     if (an) {
   6140         /* clear force cl72 configuration */
   6141         if (FORCE_CL72_IS_ENABLED(pc) == TRUE) {
   6142             SOC_IF_ERROR_RETURN
   6143                 (_phy_wc40_force_cl72_config(unit,port,FALSE));
   6144             FORCE_CL72_ENABLE(pc) = FALSE;
   6145         }
   6146     } 
   6147    /* Skip, not required if forced cl72 (f/w) is enabled and is active. 
   6148     */ 
   6149     if(!((DEV_CFG_PTR(pc)->force_cl72_fw) 
   6150                 && (FORCE_CL72_IS_ENABLED(pc) == TRUE))) {
   6151         /* enable cl72 device in autoneg mode and disable it in forced mode */
   6152         SOC_IF_ERROR_RETURN
   6153             (_phy_wc40_cl72_enable(unit,port,an));
   6154     }
   6155     
   6156     if (an) {
   6157         /* disable 100FX and 100FX auto-detect */
   6158         SOC_IF_ERROR_RETURN
   6159             (MODIFY_WC40_FX100_CONTROL1r(unit,pc,0x00,
   6160                                   0,
   6161                                   FX100_CONTROL1_AUTODET_EN_MASK |
   6162                                   FX100_CONTROL1_ENABLE_MASK));
   6163 
   6164         /* disable the cl82 local fault. Needed to allow device link up at 40G KR4
   6165          * when XMAC interface is still in XGMII mode. Once WC indicates 40G KR4 linkup,
   6166          * the port update function will set the XMAC in XLGMII mode.
   6167          */
   6168         SOC_IF_ERROR_RETURN
   6169             (WC40_REG_MODIFY(unit, pc, 0x00, 0x842A, (1 << 5),(1 << 5)));
   6170         WC40_AN_VALID_SET(pc);
   6171         WC40_AN_RECORD_TIME(pc);
   6172 
   6173         /* set to the default */ 
   6174         SOC_IF_ERROR_RETURN
   6175             (_phy_wc40_firmware_mode_set(unit, port, UC_INFO_B1_FIRMWARE_MODE_LN0_MODE_DEFAULT));
   6176 
   6177         if (WC40_LINK_WAR_REVS(pc)) {
   6178             WC40_SP_VALID_RESET(pc);
   6179         }
   6180 
   6181         if (IS_DUAL_LANE_PORT(pc)) {
   6182             if (WC40_REVID_B(pc)) {
   6183             /* part of workaround for KR2 speed status, enable PCS type auto selection */
   6184                 SOC_IF_ERROR_RETURN
   6185                     (MODIFY_WC40_DIGITAL4_MISC4r(unit, pc, 0x00, 
   6186                              DIGITAL4_MISC4_PCS_TYPE_AUTO_SELECT_MASK, 
   6187                              DIGITAL4_MISC4_PCS_TYPE_AUTO_SELECT_MASK));
   6188 
   6189                 /* for KR2,KR, no clock divider sync for dxgxs */
   6190                 SOC_IF_ERROR_RETURN
   6191                     (MODIFY_WC40_CL49_USERB0_CONTROLr(unit, pc,0x00,
   6192                       0,
   6193                       CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_VALUE_MASK |
   6194                       CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_CTRL_MASK));
   6195                 SOC_IF_ERROR_RETURN
   6196                     (MODIFY_WC40_CL49_USERB0_CONTROLr(unit, pc,
   6197                       ln_access[pc->lane_num+1],
   6198                       0,
   6199                       CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_VALUE_MASK |
   6200                       CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_CTRL_MASK));
   6201 
   6202                 /* cl49 single lane rx clock comp, needed for KR */
   6203                 SOC_IF_ERROR_RETURN
   6204                     (MODIFY_WC40_RX66_CONTROLr(unit, pc, 0x00,
   6205                     RX66_CONTROL_CC_EN_MASK |RX66_CONTROL_CC_DATA_SEL_MASK,
   6206                     RX66_CONTROL_CC_EN_MASK | RX66_CONTROL_CC_DATA_SEL_MASK));
   6207 
   6208             }
   6209             /* tx_out uses div33 clock. mixed speeds(10G/1G) on each lane */
   6210             SOC_IF_ERROR_RETURN
   6211                 (MODIFY_WC40_XGXSBLK6_XGXSX2CONTROL2r(unit, pc, LANE0_ACCESS,
   6212                        (1 << 13), (1 << 13)));
   6213         }
   6214 
   6215         /* configure the TX driver parameters for autoneg mode, use AN entry  */        
   6216         SOC_IF_ERROR_RETURN
   6217             (_phy_wc40_tx_control_get(unit, port,&tx_drv[0],TXDRV_AN_INX));
   6218         SOC_IF_ERROR_RETURN
   6219             (_phy_wc40_tx_control_set(unit, port,&tx_drv[0]));
   6220 
   6221         an_enable = MII_CTRL_AE | MII_CTRL_RAN;
   6222 
   6223         /*
   6224          * Should read one during init and cache it in Phy flags
   6225          */
   6226         if (DEV_CFG_PTR(pc)->auto_medium) {
   6227             auto_det = SERDESDIGITAL_CONTROL1000X1_AUTODET_EN_MASK; 
   6228         }
   6229 
   6230         /* check if need to switch to a different VCO */
   6231         SOC_IF_ERROR_RETURN
   6232             (_phy_wc40_vco_set(unit,port,0,0));
   6233 
   6234         /* stop rxseq and txfifo, need to properly configure for 1G speeds
   6235          * before doing AN. 
   6236          */
   6237         DUAL_LANE_BCST_ENABLE(pc);
   6238 
   6239         WC40_CL73_AN_TX_FIFO_RESET_STOP(pc);
   6240 
   6241         /* hold tx/rx in reset */
   6242         SOC_IF_ERROR_RETURN
   6243             (MODIFY_WC40_DIGITAL5_MISC6r(unit,pc,0x00,
   6244                   DIGITAL5_MISC6_RESET_RX_ASIC_MASK | DIGITAL5_MISC6_RESET_TX_ASIC_MASK,
   6245                   DIGITAL5_MISC6_RESET_RX_ASIC_MASK | DIGITAL5_MISC6_RESET_TX_ASIC_MASK));
   6246 
   6247         /* If auto-neg is enabled, make sure not forcing any speed */
   6248 
   6249         /* Workaround Jira# SDK-32387 */
   6250         /* control the speeds thru pma/pmd register */
   6251         if (WC40_SDK32387_REVS(pc)) {
   6252             SOC_IF_ERROR_RETURN
   6253                 (MODIFY_WC40_SERDESDIGITAL_MISC2r(unit, pc, 0x00,
   6254                            SERDESDIGITAL_MISC2_PMA_PMD_FORCED_SPEED_ENC_EN_MASK,
   6255                            SERDESDIGITAL_MISC2_PMA_PMD_FORCED_SPEED_ENC_EN_MASK));
   6256         }
   6257 
   6258         SOC_IF_ERROR_RETURN
   6259             (MODIFY_WC40_SERDESDIGITAL_MISC1r(unit, pc, 0x00, 0, 
   6260                                    SERDESDIGITAL_MISC1_FORCE_SPEED_MASK));
   6261         SOC_IF_ERROR_RETURN
   6262             (MODIFY_WC40_DIGITAL4_MISC3r(unit, pc, 0x00, DIGITAL4_MISC3_IND_40BITIF_MASK, 
   6263                            DIGITAL4_MISC3_IND_40BITIF_MASK | DIGITAL4_MISC3_FORCE_SPEED_B5_MASK));
   6264 
   6265         /* Workaround Jira# SDK-32387 */
   6266         /* control the speeds thru pma/pmd register */
   6267         if (WC40_SDK32387_REVS(pc)) {
   6268             SOC_IF_ERROR_RETURN
   6269                 (MODIFY_WC40_SERDESDIGITAL_MISC2r(unit, pc, 0x00,
   6270                                0,
   6271                                SERDESDIGITAL_MISC2_PMA_PMD_FORCED_SPEED_ENC_EN_MASK));
   6272         }
   6273 
   6274         /* release the tx/tx reset */
   6275         SOC_IF_ERROR_RETURN
   6276             (MODIFY_WC40_DIGITAL5_MISC6r(unit,pc,0x00,
   6277                   0,
   6278                   DIGITAL5_MISC6_RESET_RX_ASIC_MASK | DIGITAL5_MISC6_RESET_TX_ASIC_MASK));
   6279 
   6280 
   6281         WC40_CL73_AN_TX_FIFO_RESET_START(pc);
   6282 
   6283         DUAL_LANE_BCST_DISABLE(pc);
   6284 
   6285         /* Enable/Disable auto detect */
   6286         SOC_IF_ERROR_RETURN
   6287              (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X1r(unit, pc, 0x00, auto_det,
   6288                                  SERDESDIGITAL_CONTROL1000X1_AUTODET_EN_MASK));
   6289 
   6290         if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) { 
   6291 
   6292             /* clear 2wire XAUI configuration */
   6293             SOC_IF_ERROR_RETURN
   6294                 (_wc40_rxaui_config(unit,pc,FALSE));
   6295 
   6296             /* set default clock comp clear the configuration for 20X XE combo mode */
   6297             /* don't change  if clock comp is enabled by user */
   6298             if (!(DEV_CTRL_PTR(pc)->clk_comp)) {
   6299                 SOC_IF_ERROR_RETURN
   6300                     (MODIFY_WC40_XGXSBLK2_UNICOREMODE10Gr(unit, pc, 0x00,
   6301                           COMBO_HG_XGXS_nLQnCC, 
   6302                           XGXSBLK2_UNICOREMODE10G_UNICOREMODE10GHIG_MASK));
   6303             }
   6304 
   6305             if (!(WC40_REVID_A0(pc) || WC40_REVID_A1(pc))) {
   6306                 /* clear 42G control, PLL auto tune */
   6307                 SOC_IF_ERROR_RETURN
   6308                     (MODIFY_WC40_SERDESDIGITAL_MISC1r(unit, pc, 0x00,
   6309                            0, 
   6310                            SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_MASK |
   6311                            SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_MASK));
   6312             }
   6313 
   6314             /* only in combo mode, reset the sequence. In independent mode,
   6315              * resetting sequence affects all lanes
   6316              */
   6317             SOC_IF_ERROR_RETURN
   6318                 (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00, 0,
   6319                               XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
   6320 
   6321             if (!WC40_CL73_SOFT_KR2(pc)) {
   6322                 /* Enable 1000X parallel detect */
   6323                 SOC_IF_ERROR_RETURN
   6324                     (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X2r(unit, pc, 0x00, 
   6325                       SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK, 
   6326                       SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK));
   6327 
   6328                 /* enable 10G parallel detect */
   6329                 SOC_IF_ERROR_RETURN
   6330                     (MODIFY_WC40_XGXSBLK5_PARDET10GCONTROLr(unit, pc, 0x00,
   6331                           XGXSBLK5_PARDET10GCONTROL_PARDET10G_EN_MASK, 
   6332                           XGXSBLK5_PARDET10GCONTROL_PARDET10G_EN_MASK));
   6333             }
   6334         }
   6335         if (!WC40_CL73_SOFT_KR2(pc)) {
   6336     
   6337             if(DEV_CFG_PTR(pc)->cl37an == WC40_CL37_AND_CL37BAM) {
   6338                 /* set BAM/TETON enable */
   6339                 SOC_IF_ERROR_RETURN
   6340                     (WRITE_WC40_DIGITAL6_MP5_NEXTPAGECTRLr(unit,pc,0x00,
   6341                        DIGITAL6_MP5_NEXTPAGECTRL_BAM_MODE_MASK |
   6342                        DIGITAL6_MP5_NEXTPAGECTRL_TETON_MODE_MASK |
   6343                        DIGITAL6_MP5_NEXTPAGECTRL_TETON_MODE_UP3_EN_MASK));
   6344             } else {
   6345                 /* Disable Clause 37 BAM. */
   6346                 SOC_IF_ERROR_RETURN
   6347                     (WRITE_WC40_DIGITAL6_MP5_NEXTPAGECTRLr(unit,pc,0x00, 0));
   6348             }
   6349 
   6350             if(DEV_CFG_PTR(pc)->cl37an) {
   6351                 /* enable autoneg */
   6352                 SOC_IF_ERROR_RETURN
   6353                     (MODIFY_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, MII_CTRL_AE,
   6354                                               MII_CTRL_AE));
   6355             }
   6356 
   6357             if (DEV_CFG_PTR(pc)->cl73an) {
   6358                 /*To address the Synchronization issue related to a registered clock gate 
   6359                   module responsible for providing the 312.5MHz write clock to the TX 
   6360                   over-sample FIFO. Resetting the FIFO to fix the issue.
   6361                 */  
   6362                 if (!COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)
   6363                        && !DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status) {
   6364                     SOC_IF_ERROR_RETURN
   6365                         (MODIFY_WC40_DIGITAL5_MISC6r(unit, pc, 0x00,
   6366                                               DIGITAL5_MISC6_TX_OS8_AFRST_EN_MASK,
   6367                                              DIGITAL5_MISC6_TX_OS8_AFRST_EN_MASK));
   6368                 }
   6369 
   6370                 /* CL73 BAM setup, revisit BAMNP_AFTER_BP bit, any conflict
   6371                  * with EEE page?
   6372                  */
   6373                 mask16 = CL73_USERB0_CL73_BAMCTRL1_CL73_BAMEN_MASK |
   6374                      CL73_USERB0_CL73_BAMCTRL1_CL73_BAM_STATION_MNGR_EN_MASK |
   6375                      CL73_USERB0_CL73_BAMCTRL1_CL73_BAMNP_AFTER_BP_EN_MASK;
   6376                 /* not to enable CL73 BAM in independent channel mode:
   6377                  * has problem with 8073 phy
   6378                  */
   6379                 if (DEV_CFG_PTR(pc)->cl73an == WC40_CL73_WO_CL73BAM) {
   6380                     /* Disable Clause 37 BAM. */
   6381                     SOC_IF_ERROR_RETURN
   6382                         (WRITE_WC40_DIGITAL6_MP5_NEXTPAGECTRLr(unit,pc,0x00, 0));
   6383 
   6384                     /* If Individual lane mode and tx_fifo_reset is enable,
   6385                        skip for firmware to manage it.
   6386                      */
   6387                     if(!(IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)
   6388                          && DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status)) {
   6389                     SOC_IF_ERROR_RETURN
   6390                             (MODIFY_WC40_CL73_USERB0_CL73_UCTRL2r(unit, pc, 
   6391                                 0x00,
   6392                                           CL73_USERB0_CL73_UCTRL2_CONFIG_MATCH_DIS_MASK
   6393                                             | CL73_USERB0_CL73_UCTRL2_SIGDET_TIMER_DIS_MASK,
   6394                                           CL73_USERB0_CL73_UCTRL2_CONFIG_MATCH_DIS_MASK
   6395                                             | CL73_USERB0_CL73_UCTRL2_SIGDET_TIMER_DIS_MASK));
   6396                     }
   6397 
   6398                     /* need to enable these two bits even BAM is disabled 
   6399                        to interop with other BRCM devices properly. 
   6400                      */
   6401                     data16 = CL73_USERB0_CL73_BAMCTRL1_CL73_BAM_STATION_MNGR_EN_MASK |
   6402                              CL73_USERB0_CL73_BAMCTRL1_CL73_BAMNP_AFTER_BP_EN_MASK;
   6403                 } else {
   6404                     data16 = mask16;
   6405                 }
   6406 
   6407                 SOC_IF_ERROR_RETURN
   6408                     (MODIFY_WC40_CL73_USERB0_CL73_BAMCTRL1r(unit, pc, 0x00, 
   6409                            data16, mask16));
   6410 
   6411                 /* os8_txfifo_patch_en[3:0], which is a per-lane control 
   6412                    bit to enable the war_tx_os8_fifo_reset routine via s/w; 
   6413 
   6414                    MDIO Address: 0xFFC8.3:0 = mdio_uC_mailbox[3:0] 
   6415                                                 = txfifo_patch_en[3:0]
   6416                    where txfifo_p/RECiu/atch_en[N] controls lane(N).
   6417                    Default: 0xFFC8.3:0 = txfifo_patch_en[3:0] = 4'h0
   6418                   
   6419                    S/W need to enable firmware WAR before enabling CL73
   6420 
   6421                 */
   6422                 if((DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status == ENABLE) &&
   6423                     IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)){
   6424                     mask16 = 1 << pc->lane_num;
   6425                     data16 = mask16;
   6426                     SOC_IF_ERROR_RETURN
   6427                         (MODIFY_WC40_MICROBLK_MDIO_UC_MAILBOXr(unit, pc, 0x0,
   6428                                                             data16, mask16));
   6429                     DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status = ACTIVE;
   6430                 }
   6431                 SOC_IF_ERROR_RETURN
   6432                     (MODIFY_WC40_AN_IEEE0BLK_AN_IEEECONTROL1r(unit, pc, 0x00, 
   6433                                           MII_CTRL_AE,
   6434                                           MII_CTRL_AE));
   6435             }
   6436         }
   6437         if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) { 
   6438             /* restart the sequence */
   6439             SOC_IF_ERROR_RETURN
   6440                  (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00, 
   6441                               XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK,
   6442                               XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
   6443             /* wait for PLL lock */
   6444             _phy_wc40_pll_lock_wait(unit, port);
   6445             _phy_wc40_control_vco_disturbed_set(unit, port);
   6446         }
   6447     } else {
   6448         if (IS_DUAL_LANE_PORT(pc)) {
   6449             if (WC40_REVID_B(pc)) {
   6450                SOC_IF_ERROR_RETURN
   6451                     (MODIFY_WC40_CL49_USERB0_CONTROLr(unit, pc,0x00,
   6452                       CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_VALUE_MASK |
   6453                       CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_CTRL_MASK,
   6454                       CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_VALUE_MASK |
   6455                       CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_CTRL_MASK));
   6456                SOC_IF_ERROR_RETURN
   6457                     (MODIFY_WC40_CL49_USERB0_CONTROLr(unit, pc,
   6458                       ln_access[pc->lane_num+1],
   6459                       CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_VALUE_MASK |
   6460                       CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_CTRL_MASK,
   6461                       CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_VALUE_MASK |
   6462                       CL49_USERB0_CONTROL_CL82_CKGATE_EN_OVR_CTRL_MASK));
   6463                SOC_IF_ERROR_RETURN
   6464                    (MODIFY_WC40_RX66_CONTROLr(unit, pc, 0x00,
   6465                     0,
   6466                     RX66_CONTROL_CC_EN_MASK | RX66_CONTROL_CC_DATA_SEL_MASK));
   6467             }
   6468             SOC_IF_ERROR_RETURN
   6469                 (MODIFY_WC40_XGXSBLK6_XGXSX2CONTROL2r(unit, pc, LANE0_ACCESS,
   6470                        0, (1 << 13)));
   6471         }
   6472 
   6473         /* Disable auto detect */
   6474         SOC_IF_ERROR_RETURN
   6475              (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X1r(unit, pc, 0x00, auto_det,
   6476                                  SERDESDIGITAL_CONTROL1000X1_AUTODET_EN_MASK));
   6477 
   6478         if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   6479             SOC_IF_ERROR_RETURN
   6480                 (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00, 0,
   6481                               XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
   6482 
   6483             /* disable 1000X parallel detect */
   6484             SOC_IF_ERROR_RETURN
   6485                   (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X2r(unit, pc, 0x00,
   6486                   0,
   6487                   SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK));
   6488                                                                                 
   6489             /* disable 10G parallel detect */
   6490             SOC_IF_ERROR_RETURN
   6491                 (MODIFY_WC40_XGXSBLK5_PARDET10GCONTROLr(unit, pc, 0x00,
   6492                       0,
   6493                       XGXSBLK5_PARDET10GCONTROL_PARDET10G_EN_MASK));
   6494         }
   6495 
   6496         SOC_IF_ERROR_RETURN
   6497             (WRITE_WC40_DIGITAL6_MP5_NEXTPAGECTRLr(unit,pc,0x00,0));
   6498 
   6499         SOC_IF_ERROR_RETURN
   6500             (MODIFY_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, 0,
   6501                                          MII_CTRL_AE));
   6502         if (DEV_CFG_PTR(pc)->cl73an) {
   6503            if (!COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)
   6504                   && !DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status) {
   6505                 SOC_IF_ERROR_RETURN
   6506                     (MODIFY_WC40_DIGITAL5_MISC6r(unit, pc, 0x00,
   6507                                           0,
   6508                                          DIGITAL5_MISC6_TX_OS8_AFRST_EN_MASK));
   6509             } 
   6510             /* 
   6511                S/W need to disable TX FIFO RESET firmware WAR 
   6512                before disabling CL73.
   6513             */
   6514             if((DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status == ACTIVE) &&
   6515                 IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)){
   6516                 mask16 = 1 << pc->lane_num;
   6517                 data16 = 0;
   6518                 SOC_IF_ERROR_RETURN
   6519                     (MODIFY_WC40_MICROBLK_MDIO_UC_MAILBOXr(unit, pc, 0x0,
   6520                                                            data16, mask16));
   6521                 DEV_CFG_PTR(pc)->cl73an_tx_fifo_reset_status = ENABLE;
   6522             }
   6523             SOC_IF_ERROR_RETURN
   6524                 (MODIFY_WC40_AN_IEEE0BLK_AN_IEEECONTROL1r(unit, pc, 0x00, 
   6525                                           0,
   6526                                           MII_CTRL_AE));
   6527         }
   6528 
   6529         if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   6530             SOC_IF_ERROR_RETURN
   6531                  (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00, 
   6532                               XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK,
   6533                               XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
   6534             /* wait for PLL lock */
   6535             _phy_wc40_pll_lock_wait(unit, port);
   6536             _phy_wc40_control_vco_disturbed_set(unit, port);
   6537         }
   6538     }
   6539 
   6540     if (WC40_CL73_SOFT_KR2(pc)) {
   6541         if ((DEV_CFG_PTR(pc)->cl73an == WC40_CL73_KR2)
   6542            || (DEV_CFG_PTR(pc)->cl73an == WC40_CL73_KR2_WAR)) {
   6543             SOC_IF_ERROR_RETURN
   6544                 (_wc40_soft_an_cl73kr2(unit,port,an));
   6545         } else if ((DEV_CFG_PTR(pc)->cl73an == WC40_CL73_KR2_CUSTOM)
   6546                 || (DEV_CFG_PTR(pc)->cl73an == WC40_CL73_KR2_CUSTOM_WAR)) {
   6547             SOC_IF_ERROR_RETURN
   6548                 (_wc40_soft_an_cl73kr2_custom(unit,port,an));
   6549         }
   6550     } else {
   6551         /* restart the autoneg if enabled, or disable the autoneg */
   6552         if(DEV_CFG_PTR(pc)->cl37an) {
   6553             SOC_IF_ERROR_RETURN
   6554                 (MODIFY_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, an_enable,
   6555                                           MII_CTRL_AE | MII_CTRL_RAN));
   6556         }
   6557 
   6558         if (DEV_CFG_PTR(pc)->cl73an) { 
   6559             SOC_IF_ERROR_RETURN
   6560                 (MODIFY_WC40_AN_IEEE0BLK_AN_IEEECONTROL1r(unit, pc, 0x00, an_enable,
   6561                                           MII_CTRL_AE | MII_CTRL_RAN));
   6562         }
   6563     }
   6564 
   6565     pc->fiber.autoneg_enable = an;
   6566 
   6567     return SOC_E_NONE;
   6568 }
   6569 
   6570 /*
   6571  * Function:    
   6572  *      phy_wc40_an_get
   6573  * Purpose:     
   6574  *      Get the current auto-negotiation status (enabled/busy)
   6575  * Parameters:
   6576  *      unit - StrataSwitch unit #.
   6577  *      port - StrataSwitch port #. 
   6578  *      an   - (OUT) if true, auto-negotiation is enabled.
   6579  *      an_done - (OUT) if true, auto-negotiation is complete. This
   6580  *              value is undefined if an == false.
   6581  * Returns:     
   6582  *      SOC_E_XXX
   6583  */
   6584 
   6585 STATIC int
   6586 phy_wc40_an_get(int unit, soc_port_t port, int *an, int *an_done)
   6587 {
   6588     uint16      mii_ctrl;
   6589     uint16      mii_stat;
   6590     phy_ctrl_t *pc;
   6591 
   6592     pc = INT_PHY_SW_STATE(unit, port);
   6593 
   6594     if (AUTONEG_MODE_UNAVAIL(pc)) {
   6595         *an = FALSE;
   6596         *an_done = FALSE;
   6597         return SOC_E_NONE;
   6598     }
   6599 
   6600     if (WC40_CL73_SOFT_KR2(pc)) {
   6601         *an = FALSE;
   6602         *an_done = FALSE;
   6603     } else {        
   6604         SOC_IF_ERROR_RETURN
   6605             (READ_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, &mii_ctrl));
   6606         SOC_IF_ERROR_RETURN
   6607             (READ_WC40_GP2_REG_GP2_4r(unit, pc, LANE0_ACCESS, &mii_stat)); 
   6608         
   6609         *an = (mii_ctrl & MII_CTRL_AE) ? TRUE : FALSE;
   6610         *an_done = (mii_stat & (1 << (pc->lane_num + GP2_REG_GP2_4_AUTONEG_COMPLETE_SHIFT))) ? TRUE: FALSE;  
   6611     }
   6612 
   6613     if (!((*an == TRUE) && (*an_done == TRUE))) {
   6614         if (DEV_CFG_PTR(pc)->cl73an) { 
   6615             /* check clause 73 */
   6616             SOC_IF_ERROR_RETURN
   6617                 (READ_WC40_AN_IEEE0BLK_AN_IEEECONTROL1r(unit, pc, 0x00, &mii_ctrl));
   6618 
   6619             /* make sure it is autoneged link. don't use IEEE0BLK_AN_IEEESTATUS1r, 
   6620              * read by soft kr2 
   6621              */
   6622             SOC_IF_ERROR_RETURN
   6623                 (READ_WC40_GP2_REG_GP2_1r(unit, pc, LANE0_ACCESS, &mii_stat));
   6624 
   6625             *an = (mii_ctrl & MII_CTRL_AE) ? TRUE : FALSE;
   6626             *an_done = (GP2_REG_GP2_1_LINK_AN_MASK & mii_stat & (1 << pc->lane_num)) ?
   6627                        TRUE : FALSE;
   6628         }
   6629     }
   6630     return SOC_E_NONE; 
   6631 }
   6632 
   6633 STATIC int
   6634 _phy_wc40_c73_adv_local_set(int unit, soc_port_t port,
   6635                             soc_port_ability_t *ability)
   6636 {
   6637     uint16            an_adv;
   6638     uint16            pause;
   6639 #ifdef WC_EEE_SUPPORT
   6640     uint16            mask16;
   6641     uint16            data16;
   6642 #endif
   6643     phy_ctrl_t       *pc;
   6644 
   6645     pc = INT_PHY_SW_STATE(unit, port);
   6646 
   6647     if (WC40_CL73_SOFT_KR2(pc)) {
   6648         if (ability->speed_full_duplex & SOC_PA_SPEED_20GB) {
   6649             DEV_CTRL_PTR(pc)->soft_kr2.ld_kr2 = 1;
   6650         } else {
   6651             DEV_CTRL_PTR(pc)->soft_kr2.ld_kr2 = 0;
   6652         }
   6653     }
   6654 
   6655     an_adv = (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) ? 
   6656               CL73_AN_ADV_TECH_1G_KX : 0;
   6657 
   6658     if (IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   6659         an_adv |= (ability->speed_full_duplex & SOC_PA_SPEED_10GB) ? 
   6660                CL73_AN_ADV_TECH_10G_KR: 0;
   6661     }
   6662 
   6663     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   6664         an_adv |= (ability->speed_full_duplex & SOC_PA_SPEED_10GB) ? 
   6665               CL73_AN_ADV_TECH_10G_KX4: 0;
   6666     }    
   6667 
   6668     an_adv |= (ability->speed_full_duplex & SOC_PA_SPEED_40GB) ?
   6669           CL73_AN_ADV_TECH_40G_KR4: 0;
   6670     if (DEV_CFG_PTR(pc)->line_intf & WC40_IF_CR4) {
   6671         an_adv |= (ability->speed_full_duplex & SOC_PA_SPEED_40GB) ?
   6672               CL73_AN_ADV_TECH_40G_CR4: 0;
   6673     }
   6674 
   6675     SOC_IF_ERROR_RETURN
   6676         (MODIFY_WC40_AN_IEEE1BLK_AN_ADVERTISEMENT1r(unit, pc, 0x00, an_adv,
   6677                                      CL73_AN_ADV_TECH_SPEEDS_MASK));
   6678 
   6679 #ifdef WC_EEE_SUPPORT
   6680     /* EEE advertisement 0x3c: 
   6681      * 06 RW EEE_10G_KR 1 = EEE is supported for 10GBASE-KR.
   6682      *                  0 = EEE is not supported for 10GBASE-KR. 
   6683      * 05 RW EEE_10G_KX4 1 = EEE is supported for 10GBASE-KX4.
   6684      *                   0 = EEE is not supported for 10GBASE-KX4. 
   6685      * 04 RW EEE_1G_KX 1 = EEE is supported for 1000BASE-KX.
   6686      *                 0 = EEE is not supported for 1000BASE-KX.
   6687      * XXX assume supporting all speeds. use PA_EEE 
   6688      */
   6689     mask16 = AN_IEEE3BLK_EEE_ADV_EEE_10G_KR_MASK |
   6690              AN_IEEE3BLK_EEE_ADV_EEE_10G_KX4_MASK |
   6691              AN_IEEE3BLK_EEE_ADV_EEE_1G_KX_MASK;
   6692     data16 = (ability->eee & SOC_PA_EEE_10GB_KX) ? 
   6693               AN_IEEE3BLK_EEE_ADV_EEE_1G_KX_MASK : 0;
   6694     data16 |= (ability->eee & SOC_PA_EEE_10GB_KX4) ? 
   6695               AN_IEEE3BLK_EEE_ADV_EEE_10G_KX4_MASK:0;
   6696     data16 |= (ability->eee & SOC_PA_EEE_10GB_KR) ? 
   6697               AN_IEEE3BLK_EEE_ADV_EEE_10G_KR_MASK: 0;
   6698     SOC_IF_ERROR_RETURN
   6699         (MODIFY_WC40_AN_IEEE3BLK_EEE_ADVr(unit, pc, 0x00, data16, mask16));
   6700 #endif
   6701 
   6702     /* CL73 UD_code_field */
   6703     SOC_IF_ERROR_RETURN
   6704         (MODIFY_WC40_CL73_USERB0_CL73_BAMCTRL3r(unit,pc,0x00,1,
   6705                 CL73_USERB0_CL73_BAMCTRL3_UD_CODE_FIELD_MASK));
   6706 
   6707     switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) {
   6708     case SOC_PA_PAUSE_TX:
   6709         pause = CL73_AN_ADV_ASYM_PAUSE;
   6710         break;
   6711     case SOC_PA_PAUSE_RX:
   6712         pause = CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE;
   6713         break;
   6714     case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX:
   6715         pause = CL73_AN_ADV_PAUSE;
   6716         break;
   6717     default:
   6718         pause = 0;
   6719         break;
   6720     }
   6721 
   6722     SOC_IF_ERROR_RETURN
   6723         (MODIFY_WC40_AN_IEEE1BLK_AN_ADVERTISEMENT0r(unit, pc, 0x00, pause,
   6724                                      (CL73_AN_ADV_PAUSE |
   6725                                       CL73_AN_ADV_ASYM_PAUSE)));
   6726     
   6727     LOG_INFO(BSL_LS_SOC_PHY,
   6728              (BSL_META_U(unit,
   6729                          "_phy_wc40_c73_adv_local_set: u=%d p=%d pause=%08x speeds=%04x,adv=0x%x\n"),
   6730               unit, port, pause, an_adv,ability->speed_full_duplex));
   6731     return SOC_E_NONE;
   6732 }
   6733 
   6734 STATIC int
   6735 _phy_wc40_c73_adv_local_get(int unit, soc_port_t port,
   6736                             soc_port_ability_t *ability)
   6737 {
   6738     uint16            an_adv;
   6739     soc_port_mode_t   speeds,pause;
   6740     phy_ctrl_t       *pc;
   6741 
   6742     pc = INT_PHY_SW_STATE(unit, port);
   6743 
   6744     SOC_IF_ERROR_RETURN
   6745         (READ_WC40_AN_IEEE1BLK_AN_ADVERTISEMENT1r(unit, pc, 0x00, &an_adv));
   6746 
   6747     speeds = (an_adv & CL73_AN_ADV_TECH_1G_KX) ? SOC_PA_SPEED_1000MB : 0;
   6748     speeds |= (an_adv & CL73_AN_ADV_TECH_10G_KX4) ? SOC_PA_SPEED_10GB : 0;
   6749     speeds |= (an_adv & CL73_AN_ADV_TECH_10G_KR) ? SOC_PA_SPEED_10GB : 0;
   6750     speeds |= (an_adv & CL73_AN_ADV_TECH_40G_KR4) ? SOC_PA_SPEED_40GB : 0;
   6751     speeds |= (an_adv & CL73_AN_ADV_TECH_40G_CR4) ? SOC_PA_SPEED_40GB : 0;
   6752 
   6753     if (WC40_CL73_SOFT_KR2(pc)) {
   6754         speeds |= DEV_CTRL_PTR(pc)->soft_kr2.ld_kr2? SOC_PA_SPEED_20GB:0;
   6755     }
   6756 
   6757     ability->speed_full_duplex |= speeds;
   6758 #ifdef WC_EEE_SUPPORT
   6759     SOC_IF_ERROR_RETURN
   6760         (READ_WC40_AN_IEEE3BLK_EEE_ADVr(unit, pc, 0x00, &an_adv));
   6761     ability->eee = (an_adv & AN_IEEE3BLK_EEE_ADV_EEE_10G_KR_MASK)?
   6762                    SOC_PA_EEE_10GB_KR:0;
   6763     ability->eee |= (an_adv & AN_IEEE3BLK_EEE_ADV_EEE_10G_KX4_MASK)?
   6764                     SOC_PA_EEE_10GB_KX4:0;
   6765     ability->eee |= (an_adv & AN_IEEE3BLK_EEE_ADV_EEE_1G_KX_MASK)?
   6766                     SOC_PA_EEE_10GB_KX:0;
   6767 #endif
   6768 
   6769     /* advert register 0x12, bit 15 FEC requested,bit 14 FEC ability */
   6770     /* SOC_IF_ERROR_RETURN
   6771      *    (READ_WC40_AN_IEEE1BLK_AN_ADVERTISEMENT2r(unit, pc, 0x00, &an_adv));
   6772      */
   6773     /* (an_adv & AN_IEEE1BLK_AN_ADVERTISEMENT2_FEC_REQUESTED_MASK) */
   6774 
   6775     SOC_IF_ERROR_RETURN
   6776         (READ_WC40_AN_IEEE1BLK_AN_ADVERTISEMENT0r(unit, pc, 0x00, &an_adv));
   6777 
   6778     switch (an_adv & (CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE)) {
   6779         case CL73_AN_ADV_PAUSE:
   6780             pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   6781             break;
   6782         case CL73_AN_ADV_ASYM_PAUSE:
   6783             pause = SOC_PA_PAUSE_TX;
   6784             break;
   6785         case CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE:
   6786             pause = SOC_PA_PAUSE_RX;
   6787             break;
   6788         default:
   6789             pause = 0;
   6790             break;
   6791     }
   6792     ability->pause = pause;
   6793 
   6794     LOG_INFO(BSL_LS_SOC_PHY,
   6795              (BSL_META_U(unit,
   6796                          "_phy_wc40_c73_adv_local_get: u=%d p=%d pause=%08x speeds=%04x\n"),
   6797               unit, port, pause, speeds));
   6798     return SOC_E_NONE;
   6799 }
   6800 
   6801 /*
   6802  * Function:
   6803  *      phy_wc40_ability_advert_set
   6804  * Purpose:
   6805  *      Set the current advertisement for auto-negotiation.
   6806  * Parameters:
   6807  *      unit - StrataSwitch unit #.
   6808  *      port - StrataSwitch port #.
   6809  *      mode - Port mode mask indicating supported options/speeds.
   6810  * Returns:
   6811  *      SOC_E_XXX
   6812  * Notes:
   6813  *      The advertisement is set only for the ACTIVE medium.
   6814  *      No synchronization performed at this level.
   6815  */
   6816 
   6817 STATIC int
   6818 phy_wc40_ability_advert_set(int unit, soc_port_t port,
   6819                        soc_port_ability_t *ability)
   6820 {
   6821     uint16           an_adv = 0;
   6822     uint16           an_sp_20g;
   6823     soc_port_mode_t  mode;
   6824     phy_ctrl_t      *pc;
   6825     uint16 mask16;
   6826     uint16 data16;
   6827     uint16 up3;
   6828 
   6829     if (NULL == ability) {
   6830         return (SOC_E_PARAM);
   6831     }
   6832 
   6833     pc = INT_PHY_SW_STATE(unit, port);
   6834 
   6835     /* If the phy medium is copper, only set MII speed and advertised duplex. */
   6836     if (!DEV_CFG_PTR(pc)->fiber_pref) {
   6837         an_adv = 0;
   6838         if (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) {
   6839             an_adv = MII_CTRL_SS_1000;
   6840         } else if (ability->speed_full_duplex & SOC_PA_SPEED_100MB) {
   6841             an_adv = MII_CTRL_SS_100;
   6842         } else if (ability->speed_full_duplex & SOC_PA_SPEED_10MB) {
   6843             an_adv = MII_CTRL_SS_10;
   6844         }
   6845 
   6846         an_adv |= ability->speed_full_duplex ? (MII_CTRL_FD | MII_CTRL_AE) : 0;
   6847         SOC_IF_ERROR_RETURN
   6848             (MODIFY_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x0, an_adv,
   6849                 MII_CTRL_AE | MII_CTRL_FD | MII_CTRL_SS_LSB | MII_CTRL_SS_MSB));
   6850 
   6851         return SOC_E_NONE;
   6852     }
   6853 
   6854     /*
   6855      * Set advertised duplex (only FD supported) if CL37 is enabled
   6856      */
   6857     if (DEV_CFG_PTR(pc)->cl37an) { 
   6858         an_adv = ability->speed_full_duplex? MII_ANA_C37_FD : 0;
   6859 
   6860         /*
   6861          * Set advertised pause bits in link code word.
   6862          */
   6863         switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) {
   6864         case SOC_PA_PAUSE_TX:
   6865             an_adv |= MII_ANA_C37_ASYM_PAUSE;
   6866             break;
   6867         case SOC_PA_PAUSE_RX:
   6868             an_adv |= MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE;
   6869             break;
   6870         case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX:
   6871             an_adv |= MII_ANA_C37_PAUSE;
   6872             break;
   6873         }
   6874     }
   6875     /* Update less than 1G capability */ 
   6876     SOC_IF_ERROR_RETURN
   6877         (WRITE_WC40_COMBO_IEEE0_AUTONEGADVr(unit, pc, 0x00, an_adv));
   6878 
   6879     mode = ability->speed_full_duplex;
   6880     an_adv = 0;
   6881     an_sp_20g = 0;
   6882     an_adv |= (mode & SOC_PA_SPEED_2500MB) ? 
   6883                DIGITAL3_UP1_DATARATE_2P5GX1_MASK : 0;
   6884 
   6885     if (IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   6886         SOC_IF_ERROR_RETURN
   6887             (WRITE_WC40_DIGITAL3_UP1r(unit, pc, 0x00, an_adv));
   6888 
   6889         SOC_IF_ERROR_RETURN
   6890             (WRITE_WC40_DIGITAL3_UP3r(unit, pc, 0x00, 
   6891                           DIGITAL3_UP3_CL72_MASK | DIGITAL3_UP3_LAST_MASK)); 
   6892 
   6893         if (DEV_CFG_PTR(pc)->cl73an) { 
   6894             SOC_IF_ERROR_RETURN
   6895                 (_phy_wc40_c73_adv_local_set(unit, port, ability));
   6896         }
   6897 
   6898         /*next need to check FEC ability */
   6899         mask16 = AN_IEEE1BLK_AN_ADVERTISEMENT2_FEC_REQUESTED_MASK;
   6900         data16 = 0;
   6901         if (ability->fec == SOC_PA_FEC_CL74) {
   6902             data16 = mask16;
   6903             up3 = DIGITAL3_UP3_FEC_MASK;
   6904         } else {
   6905             data16 = 1 << AN_IEEE1BLK_AN_ADVERTISEMENT2_FEC_REQUESTED_SHIFT;
   6906             up3 = 0;
   6907         }
   6908         SOC_IF_ERROR_RETURN
   6909             (MODIFY_WC40_AN_IEEE1BLK_AN_ADVERTISEMENT2r(unit, pc, 0x00, data16, mask16));
   6910         SOC_IF_ERROR_RETURN
   6911             (MODIFY_WC40_DIGITAL3_UP3r(unit, pc, 0x00, up3, DIGITAL3_UP3_FEC_MASK));
   6912 
   6913         LOG_INFO(BSL_LS_SOC_PHY,
   6914                  (BSL_META_U(unit,
   6915                              "phy_wc40_ability_advert_set: u=%d p=%d pause=%08x OVER1G_UP1 %04x\n"),
   6916                   unit, port, ability->pause, an_adv));
   6917         return SOC_E_NONE;
   6918     }
   6919 
   6920     /* high speeds, 40G,30G and 20G, 20G/scrambler */ 
   6921     an_adv |= (mode & SOC_PA_SPEED_5000MB) ? 
   6922                 DIGITAL3_UP1_DATARATE_5GX4_MASK : 0;
   6923     an_adv |= (mode & SOC_PA_SPEED_6000MB) ? 
   6924                 DIGITAL3_UP1_DATARATE_6GX4_MASK : 0;
   6925     an_adv |= (mode & SOC_PA_SPEED_12GB) ? 
   6926                 DIGITAL3_UP1_DATARATE_12GX4_MASK : 0;
   6927     an_adv |= (mode & SOC_PA_SPEED_12P5GB) ? 
   6928                 DIGITAL3_UP1_DATARATE_12P5GX4_MASK : 0;
   6929     an_adv |= (mode & SOC_PA_SPEED_13GB) ? 
   6930                     DIGITAL3_UP1_DATARATE_13GX4_MASK : 0;
   6931     an_adv |= (mode & SOC_PA_SPEED_15GB) ? 
   6932                 DIGITAL3_UP1_DATARATE_15GX4_MASK : 0;
   6933     an_adv |= (mode & SOC_PA_SPEED_16GB) ? 
   6934                 DIGITAL3_UP1_DATARATE_16GX4_MASK : 0;
   6935     an_adv |= (mode & SOC_PA_SPEED_20GB) ? 
   6936               DIGITAL3_UP1_DATARATE_20GX4_MASK : 0;
   6937     /* advertise 20G with scrambler */
   6938     if (mode & SOC_PA_SPEED_20GB) {
   6939         data16 = DIGITAL6_UP4_DATARATE_20G_MASK;
   6940     } else {
   6941         data16 = 0;
   6942     }
   6943     SOC_IF_ERROR_RETURN
   6944         (MODIFY_WC40_DIGITAL6_UP4r(unit, pc, 0x00, 
   6945                  data16,
   6946                  DIGITAL6_UP4_DATARATE_20G_MASK));
   6947     
   6948     SOC_IF_ERROR_RETURN
   6949         (MODIFY_WC40_DIGITAL6_UP4r(unit, pc, 0x00, 
   6950                  DIGITAL6_UP4_LAST_MASK,
   6951                  DIGITAL6_UP4_LAST_MASK));
   6952 
   6953     an_sp_20g |= (mode & SOC_PA_SPEED_21GB) ? 
   6954                   DIGITAL3_UP3_DATARATE_21GX4_MASK : 0;
   6955     an_sp_20g |= (mode & SOC_PA_SPEED_25GB) ? 
   6956                   DIGITAL3_UP3_DATARATE_25P45GX4_MASK : 0;
   6957     an_sp_20g |= (mode & SOC_PA_SPEED_30GB) ? 
   6958                   DIGITAL3_UP3_DATARATE_31P5G_MASK : 0;
   6959 
   6960     if (DEV_CFG_PTR(pc)->hg_mode) {
   6961         an_sp_20g |= (mode & SOC_PA_SPEED_40GB) ? 
   6962                   DIGITAL3_UP3_DATARATE_40G_MASK : 0;
   6963     }
   6964 
   6965     if (mode & SOC_PA_SPEED_10GB) {
   6966         if (DEV_CFG_PTR(pc)->hg_mode) {
   6967             /* For Draco and Hercules, use pre-CX4 signalling */
   6968             an_adv |= DIGITAL3_UP1_DATARATE_10GX4_MASK; 
   6969             if (DEV_CFG_PTR(pc)->cx4_10g) {
   6970                 /* Also include 10G CX4 signalling by default */
   6971                 an_adv |= DIGITAL3_UP1_DATARATE_10GCX4_MASK; 
   6972             }
   6973         } else {
   6974             an_adv |= DIGITAL3_UP1_DATARATE_10GCX4_MASK; 
   6975         }
   6976     }
   6977     
   6978     SOC_IF_ERROR_RETURN
   6979         (WRITE_WC40_DIGITAL3_UP1r(unit, pc, 0x00, an_adv));
   6980 
   6981     /* CL72 and Higig2, check Higig2 cap on this port before adv 
   6982      * UP3 last page bit DIGITAL3_UP3_LAST_MASK needs to be set to work with HC/HL.
   6983      */
   6984     mask16 = OVER1G_UP3_20GPLUS_MASK;
   6985     data16 = an_sp_20g;
   6986     mask16 |= DIGITAL3_UP3_CL72_MASK | DIGITAL3_UP3_HIGIG2_MASK;
   6987 
   6988     /* 20G with CL72 advertised in WC B0 doesn't work. But cl72 should not
   6989      * be advertised below 21G anyway
   6990      */ 
   6991     if (!(DEV_CFG_PTR(pc)->hg_mode &&
   6992         (!(mode & (SOC_PA_SPEED_40GB | SOC_PA_SPEED_21GB |
   6993                  SOC_PA_SPEED_25GB | SOC_PA_SPEED_30GB)))) ) {
   6994         data16 |= DIGITAL3_UP3_CL72_MASK;
   6995     }
   6996 #if 0 
   6997     data16 |= DIGITAL3_UP3_FEC_MASK;
   6998 #endif
   6999 
   7000     /* XXX revisit: no autoneg in dxgxs mode */
   7001     
   7002     SOC_IF_ERROR_RETURN
   7003         (MODIFY_WC40_DIGITAL3_UP3r(unit, pc, 0x00, data16, mask16));
   7004 
   7005     /* preemphasis attributes */
   7006     /*
   7007      * mask16 = DIGITAL3_UP2_PREEMPHASIS_MASK | DIGITAL3_UP2_IDRIVER_MASK |
   7008      *          DIGITAL3_UP2_IPREDRIVER_MASK | DIGITAL3_UP2_VALID_MASK;
   7009      * data16 = (DEV_CFG_PTR(pc)->preemph << DIGITAL3_UP2_PREEMPHASIS_SHIFT) |
   7010      *          (DEV_CFG_PTR(pc)->idriver << DIGITAL3_UP2_IDRIVER_SHIFT) |
   7011      *          (DEV_CFG_PTR(pc)->pdriver << DIGITAL3_UP2_IPREDRIVER_SHIFT);
   7012      * data16 |= DIGITAL3_UP2_VALID_MASK;
   7013      * SOC_IF_ERROR_RETURN
   7014      *     (MODIFY_WC40_DIGITAL3_UP2r(unit, pc, 0x00, data16,mask16));
   7015      */
   7016 
   7017     if (DEV_CFG_PTR(pc)->cl73an) { 
   7018         SOC_IF_ERROR_RETURN
   7019             (_phy_wc40_c73_adv_local_set(unit, port, ability));
   7020     }
   7021 
   7022     /*next need to check FEC ability */
   7023     mask16 = AN_IEEE1BLK_AN_ADVERTISEMENT2_FEC_REQUESTED_MASK;
   7024     data16 = 0;
   7025     if (ability->fec == SOC_PA_FEC_CL74) {
   7026         data16 = mask16;
   7027         up3 = DIGITAL3_UP3_FEC_MASK;
   7028     } else {
   7029         data16 = 1 << AN_IEEE1BLK_AN_ADVERTISEMENT2_FEC_REQUESTED_SHIFT;
   7030         up3 = 0;
   7031     }
   7032     SOC_IF_ERROR_RETURN
   7033         (MODIFY_WC40_AN_IEEE1BLK_AN_ADVERTISEMENT2r(unit, pc, 0x00, data16, mask16));
   7034     SOC_IF_ERROR_RETURN
   7035         (MODIFY_WC40_DIGITAL3_UP3r(unit, pc, 0x00, up3, DIGITAL3_UP3_FEC_MASK));
   7036 
   7037     LOG_INFO(BSL_LS_SOC_PHY,
   7038              (BSL_META_U(unit,
   7039                          "phy_wc40_ability_advert_set: u=%d p=%d pause=%08x OVER1G_UP1 %04x\n"),
   7040               unit, port, ability->pause, an_adv));
   7041     return SOC_E_NONE;
   7042 }
   7043 
   7044 /*
   7045  * Function:
   7046  *      phy_wc40_ability_advert_get
   7047  * Purpose:
   7048  *      Get the current advertisement for auto-negotiation.
   7049  * Parameters:
   7050  *      unit - StrataSwitch unit #.
   7051  *      port - StrataSwitch port #.
   7052  *      mode - (OUT) Port mode mask indicating supported options/speeds.
   7053  * Returns:
   7054  *      SOC_E_XXX
   7055  * Notes:
   7056  *      The advertisement is retrieved for the ACTIVE medium.
   7057  *      No synchronization performed at this level.
   7058  */
   7059 
   7060 STATIC int
   7061 phy_wc40_ability_advert_get(int unit, soc_port_t port,
   7062                            soc_port_ability_t *ability)
   7063 {
   7064     uint16           an_adv;
   7065     uint16           up4;
   7066     uint16           up3;
   7067     uint16           up2;
   7068     soc_port_mode_t  mode;
   7069     phy_ctrl_t      *pc;
   7070     soc_port_mode_t  fec;
   7071 
   7072     if (NULL == ability) {
   7073         return (SOC_E_PARAM);
   7074     }
   7075 
   7076     pc = INT_PHY_SW_STATE(unit, port);
   7077 
   7078     WC40_MEM_SET(ability, 0, sizeof(*ability));
   7079 
   7080     if (!DEV_CFG_PTR(pc)->fiber_pref) {
   7081         SOC_IF_ERROR_RETURN
   7082           (READ_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, &an_adv));
   7083         mode = 0;
   7084         mode = (an_adv & MII_CTRL_SS_MSB) ? SOC_PA_SPEED_1000MB :
   7085                (an_adv & MII_CTRL_SS_LSB) ? SOC_PA_SPEED_100MB :
   7086                 SOC_PA_SPEED_10MB;
   7087         ability->speed_full_duplex = mode;
   7088 
   7089         return SOC_E_NONE;
   7090     }
   7091 
   7092     SOC_IF_ERROR_RETURN
   7093         (READ_WC40_DIGITAL3_UP1r(unit, pc, 0x00, &an_adv));
   7094 
   7095     SOC_IF_ERROR_RETURN
   7096         (READ_WC40_DIGITAL3_UP2r(unit, pc, 0x00, &up2));
   7097 
   7098     SOC_IF_ERROR_RETURN
   7099         (READ_WC40_DIGITAL3_UP3r(unit, pc, 0x00, &up3));
   7100 
   7101     SOC_IF_ERROR_RETURN
   7102         (READ_WC40_DIGITAL6_UP4r(unit, pc, 0x00, &up4));
   7103 
   7104     /* preemphasis settings */
   7105     /* preemphasis (up2 & DIGITAL3_UP2_PREEMPHASIS_MASK) >>
   7106      *              DIGITAL3_UP2_PREEMPHASIS_SHIFT
   7107      * idriver     (up2 & DIGITAL3_UP2_IDRIVER_MASK) >>
   7108      *              DIGITAL3_UP2_IDRIVER_SHIFT
   7109      * ipredriver  (up2 & DIGITAL3_UP2_IPREDRIVER_MASK) >>
   7110      *              DIGITAL3_UP2_IPREDRIVER_SHIFT
   7111      */
   7112     /* CL72,FEC and Higig2 
   7113      * CL72 cap - (up3 & DIGITAL3_UP3_CL72_MASK)
   7114      * FEC cap  - (up3 & DIGITAL3_UP3_FEC_MASK)
   7115      * Higig2   - (up3 & DIGITAL3_UP3_HIGIG2_MASK)
   7116      */
   7117     ability->encap = (up3 & DIGITAL3_UP3_HIGIG2_MASK)?
   7118                       SOC_PA_ENCAP_HIGIG2: 0;
   7119     
   7120     mode = 0;
   7121     mode |= (up3 & DIGITAL3_UP3_DATARATE_40G_MASK) ?
   7122               SOC_PA_SPEED_40GB : 0;
   7123     mode |= (up3 & DIGITAL3_UP3_DATARATE_31P5G_MASK) ?
   7124               SOC_PA_SPEED_30GB : 0;
   7125     mode |= (up3 & DIGITAL3_UP3_DATARATE_25P45GX4_MASK) ?
   7126               SOC_PA_SPEED_25GB : 0;
   7127     mode |= (up3 & DIGITAL3_UP3_DATARATE_21GX4_MASK) ?
   7128               SOC_PA_SPEED_21GB : 0;
   7129 
   7130     mode |= (up4 & DIGITAL6_UP4_DATARATE_20G_MASK) ? SOC_PA_SPEED_20GB : 0;
   7131     mode |= (an_adv & DIGITAL3_UP1_DATARATE_20GX4_MASK) ? SOC_PA_SPEED_20GB : 0;
   7132     mode |= (an_adv & DIGITAL3_UP1_DATARATE_16GX4_MASK) ? SOC_PA_SPEED_16GB : 0;
   7133     mode |= (an_adv & DIGITAL3_UP1_DATARATE_15GX4_MASK) ? SOC_PA_SPEED_15GB : 0;
   7134     mode |= (an_adv & DIGITAL3_UP1_DATARATE_13GX4_MASK) ? SOC_PA_SPEED_13GB : 0;
   7135     mode |= (an_adv & DIGITAL3_UP1_DATARATE_12P5GX4_MASK) ? 
   7136             SOC_PA_SPEED_12P5GB : 0;
   7137     mode |= (an_adv & DIGITAL3_UP1_DATARATE_12GX4_MASK) ? SOC_PA_SPEED_12GB : 0;
   7138     mode |= (an_adv & DIGITAL3_UP1_DATARATE_10GCX4_MASK) ? SOC_PA_SPEED_10GB: 0;
   7139     mode |= (an_adv & DIGITAL3_UP1_DATARATE_10GX4_MASK) ? SOC_PA_SPEED_10GB : 0;
   7140     mode |= (an_adv & DIGITAL3_UP1_DATARATE_6GX4_MASK)? SOC_PA_SPEED_6000MB : 0;
   7141     mode |= (an_adv & DIGITAL3_UP1_DATARATE_5GX4_MASK)? SOC_PA_SPEED_5000MB : 0;
   7142     mode |= (an_adv & DIGITAL3_UP1_DATARATE_2P5GX1_MASK) ? 
   7143                     SOC_PA_SPEED_2500MB : 0;
   7144 
   7145     SOC_IF_ERROR_RETURN
   7146         (READ_WC40_COMBO_IEEE0_AUTONEGADVr(unit, pc, 0x00, &an_adv));
   7147       
   7148     mode |= (an_adv & MII_ANA_C37_FD) ? SOC_PA_SPEED_1000MB : 0;
   7149     ability->speed_full_duplex = mode;
   7150 
   7151     mode = 0;
   7152     switch (an_adv & (MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE)) {
   7153         case MII_ANA_C37_PAUSE:
   7154             mode = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   7155             break;
   7156         case MII_ANA_C37_ASYM_PAUSE:
   7157             mode = SOC_PA_PAUSE_TX;
   7158             break;
   7159         case MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE:
   7160             mode = SOC_PA_PAUSE_RX;
   7161             break;
   7162     }
   7163     ability->pause = mode;
   7164 
   7165     /* check for clause73 */
   7166     if (DEV_CFG_PTR(pc)->cl73an) {
   7167         SOC_IF_ERROR_RETURN
   7168             (_phy_wc40_c73_adv_local_get(unit, port, ability));
   7169     }
   7170 
   7171     /* Check FEC base on AN and CL37BAM*/
   7172     SOC_IF_ERROR_RETURN
   7173         (READ_WC40_AN_IEEE1BLK_AN_ADVERTISEMENT2r(unit, pc, 0x00, &an_adv));
   7174     if ((an_adv & AN_IEEE1BLK_AN_ADVERTISEMENT2_FEC_REQUESTED_MASK) ==
   7175                     AN_IEEE1BLK_AN_ADVERTISEMENT2_FEC_REQUESTED_MASK) {
   7176         fec = SOC_PA_FEC_CL74;
   7177     } else if (an_adv & (1<<AN_IEEE1BLK_AN_ADVERTISEMENT2_FEC_REQUESTED_SHIFT)) {
   7178         fec = SOC_PA_FEC_NONE;
   7179     } else {
   7180         fec = 0;
   7181     }
   7182 
   7183     fec |= (up3 & DIGITAL3_UP3_FEC_MASK) ? SOC_PA_FEC_CL74 : SOC_PA_FEC_NONE;
   7184 
   7185     if (fec & SOC_PA_FEC_CL74) {
   7186         ability->fec = SOC_PA_FEC_CL74;
   7187     } else {
   7188         ability->fec = SOC_PA_FEC_NONE;
   7189     }
   7190 
   7191     LOG_INFO(BSL_LS_SOC_PHY,
   7192              (BSL_META_U(unit,
   7193                          "phy_wc40_ability_advert_get:unit=%d p=%d pause=%08x sp=%08x\n"),
   7194               unit, port, ability->pause, ability->speed_full_duplex));
   7195 
   7196     return SOC_E_NONE;
   7197 }
   7198 
   7199 STATIC int
   7200 _phy_wc40_c73_adv_remote_get(int unit, soc_port_t port,
   7201                              soc_port_ability_t *ability)
   7202 {
   7203     uint16            an_adv;
   7204     soc_port_mode_t   mode;
   7205     phy_ctrl_t       *pc;
   7206 
   7207     pc = INT_PHY_SW_STATE(unit, port);
   7208      SOC_IF_ERROR_RETURN
   7209         (READ_WC40_AN_IEEE1BLK_AN_LP_BASEPAGEABILITY1r(unit, pc, 0x00, &an_adv));
   7210 
   7211     mode =  (an_adv & CL73_AN_ADV_TECH_1G_KX) ? SOC_PA_SPEED_1000MB : 0;
   7212     mode |= (an_adv & CL73_AN_ADV_TECH_10G_KX4) ? SOC_PA_SPEED_10GB : 0;
   7213     mode |= (an_adv & CL73_AN_ADV_TECH_10G_KR) ? SOC_PA_SPEED_10GB : 0;
   7214     mode |= (an_adv & CL73_AN_ADV_TECH_40G_KR4) ? SOC_PA_SPEED_40GB : 0;
   7215     mode |= (an_adv & CL73_AN_ADV_TECH_40G_CR4) ? SOC_PA_SPEED_40GB : 0;
   7216 
   7217     SOC_IF_ERROR_RETURN
   7218         (READ_WC40_AN_IEEE1BLK_AN_LP_BASEPAGEABILITY2r(unit, pc, 0x00, &an_adv));
   7219     mode |= (an_adv & CL73_AN_ADV_TECH_20G_KR2) ? SOC_PA_SPEED_20GB : 0;
   7220 
   7221     ability->speed_full_duplex |= mode;
   7222 
   7223     /* advert register 0x12, bit 15 FEC requested,bit 14 FEC ability */
   7224     /* SOC_IF_ERROR_RETURN
   7225      *   (READ_WC40_AN_IEEE1BLK_AN_LP_BASEPAGEABILITY2r(unit, pc, 0x00, &an_adv));
   7226      */
   7227     /* (an_adv & AN_IEEE1BLK_AN_ADVERTISEMENT2_FEC_REQUESTED_MASK) */
   7228 
   7229 
   7230     SOC_IF_ERROR_RETURN
   7231         (READ_WC40_AN_IEEE1BLK_AN_LP_BASEPAGEABILITY0r(unit, pc, 0x00, &an_adv));
   7232 
   7233     mode = 0;
   7234     switch (an_adv & (CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE)) {
   7235         case CL73_AN_ADV_PAUSE:
   7236             mode = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   7237             break;
   7238         case CL73_AN_ADV_ASYM_PAUSE:
   7239             mode = SOC_PA_PAUSE_TX;
   7240             break;
   7241         case CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE:
   7242             mode = SOC_PA_PAUSE_RX;
   7243             break;
   7244     }
   7245     ability->pause = mode;
   7246 
   7247     return SOC_E_NONE;
   7248 }
   7249 
   7250 /*
   7251  * Function:
   7252  *      phy_wc40_ability_remote_get
   7253  * Purpose:
   7254  *      Get the current advertisement for auto-negotiation.
   7255  * Parameters:
   7256  *      unit - StrataSwitch unit #.
   7257  *      port - StrataSwitch port #.
   7258  *      mode - (OUT) Port mode mask indicating supported options/speeds.
   7259  * Returns:
   7260  *      SOC_E_XXX
   7261  * Notes:
   7262  *      The advertisement is retrieved for the ACTIVE medium.
   7263  *      No synchronization performed at this level.
   7264  */
   7265 
   7266 STATIC int
   7267 phy_wc40_ability_remote_get(int unit, soc_port_t port,
   7268                         soc_port_ability_t *ability)
   7269 {
   7270     uint16           an_adv;
   7271     uint16           up4 = 0;
   7272     uint16           up3 = 0;
   7273     uint16           up2 = 0;
   7274     uint16           data16;
   7275     uint16           mii_ctrl;
   7276     int              an_enable;
   7277     int              link_1000x = FALSE;
   7278     int              link_combo = FALSE;
   7279     soc_port_mode_t  mode;
   7280     phy_ctrl_t      *pc;
   7281     soc_port_mode_t  fec;
   7282 
   7283     pc = INT_PHY_SW_STATE(unit, port);
   7284 
   7285     SOC_IF_ERROR_RETURN
   7286         (READ_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, &data16));
   7287 
   7288     /* check clause 73 */
   7289     SOC_IF_ERROR_RETURN
   7290         (READ_WC40_AN_IEEE0BLK_AN_IEEECONTROL1r(unit, pc, 0x00, &mii_ctrl));
   7291 
   7292     an_enable = ((data16 & MII_CTRL_AE) || (mii_ctrl & MII_CTRL_AE)) ? TRUE : FALSE;
   7293 
   7294     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   7295         SOC_IF_ERROR_RETURN
   7296             (READ_WC40_XGXSBLK4_XGXSSTATUS1r(unit, pc, 0x00, &data16));
   7297         if (data16 & (XGXSBLK4_XGXSSTATUS1_LINKSTAT_MASK |
   7298                                XGXSBLK4_XGXSSTATUS1_LINK10G_MASK)) {
   7299             link_combo = TRUE;
   7300         }
   7301     } else {
   7302         SOC_IF_ERROR_RETURN
   7303             (READ_WC40_GP2_REG_GP2_1r(unit, pc, 0x00, &data16));
   7304         if (data16 & (1 << pc->lane_num)) {
   7305             link_1000x = TRUE;
   7306         }
   7307     } 
   7308 
   7309     LOG_INFO(BSL_LS_SOC_PHY,
   7310              (BSL_META_U(unit,
   7311                          "u=%d p=%d an_enable=%04x link_1000x=%04x link_combo=%04x\n"),
   7312               unit, port, an_enable, link_1000x,link_combo));
   7313 
   7314     WC40_MEM_SET(ability, 0, sizeof(*ability));
   7315     mode = 0;
   7316 
   7317     if (an_enable && (link_1000x || link_combo)) {
   7318         /* Decode remote advertisement only when link is up and autoneg is 
   7319          * completed.
   7320          */
   7321  
   7322         SOC_IF_ERROR_RETURN
   7323             (READ_WC40_DIGITAL3_LP_UP1r(unit, pc, 0x00, &an_adv));
   7324 
   7325         SOC_IF_ERROR_RETURN
   7326             (READ_WC40_DIGITAL3_LP_UP2r(unit, pc, 0x00, &up2));
   7327 
   7328         SOC_IF_ERROR_RETURN
   7329             (READ_WC40_DIGITAL3_LP_UP3r(unit, pc, 0x00, &up3));
   7330 
   7331         SOC_IF_ERROR_RETURN
   7332             (READ_WC40_DIGITAL5_LP_UP4r(unit, pc, 0x00, &up4));
   7333 
   7334         /* preemphasis settings */
   7335         /* preemphasis (up2 & DIGITAL3_UP2_PREEMPHASIS_MASK) >>
   7336          *              DIGITAL3_UP2_PREEMPHASIS_SHIFT
   7337          * idriver     (up2 & DIGITAL3_UP2_IDRIVER_MASK) >>
   7338          *              DIGITAL3_UP2_IDRIVER_SHIFT
   7339          * ipredriver  (up2 & DIGITAL3_UP2_IPREDRIVER_MASK) >>
   7340          *              DIGITAL3_UP2_IPREDRIVER_SHIFT
   7341          */
   7342         /* CL72,FEC and Higig2 
   7343          * CL72 cap - (up3 & DIGITAL3_UP3_CL72_MASK)
   7344          * FEC cap  - (up3 & DIGITAL3_UP3_FEC_MASK)
   7345          * Higig2   - (up3 & DIGITAL3_UP3_HIGIG2_MASK)
   7346          */
   7347         ability->encap = (up3 & DIGITAL3_UP3_HIGIG2_MASK)?
   7348                       SOC_PA_ENCAP_HIGIG2: 0;
   7349 
   7350         mode |= (up3 & DIGITAL3_LP_UP3_DATARATE_40G_MASK)?
   7351                 SOC_PA_SPEED_40GB: 0;
   7352         mode |= (up3 & DIGITAL3_LP_UP3_DATARATE_31P5G_MASK)?
   7353                 SOC_PA_SPEED_30GB: 0;
   7354         mode |= (up3 & DIGITAL3_LP_UP3_DATARATE_25P45GX4_MASK)?
   7355                 SOC_PA_SPEED_25GB: 0;
   7356         mode |= (up3 & DIGITAL3_LP_UP3_DATARATE_21GX4_MASK)?
   7357                 SOC_PA_SPEED_21GB: 0;
   7358         mode |= (an_adv & DIGITAL3_LP_UP1_DATARATE_20GX4_MASK) ? 
   7359                 SOC_PA_SPEED_20GB : 0;
   7360         mode |= (up4 & DIGITAL5_LP_UP4_DATARATE_20G_MASK) ? 
   7361                 SOC_PA_SPEED_20GB : 0;
   7362         mode |= (an_adv & DIGITAL3_LP_UP1_DATARATE_16GX4_MASK) ? 
   7363                 SOC_PA_SPEED_16GB : 0;
   7364         mode |= (an_adv & DIGITAL3_LP_UP1_DATARATE_15GX4_MASK) ? 
   7365                 SOC_PA_SPEED_15GB : 0;
   7366         mode |= (an_adv & DIGITAL3_LP_UP1_DATARATE_13GX4_MASK) ? 
   7367                 SOC_PA_SPEED_13GB : 0;
   7368         mode |= (an_adv & DIGITAL3_LP_UP1_DATARATE_12P5GX4_MASK) ? 
   7369                 SOC_PA_SPEED_12P5GB : 0;
   7370         mode |= (an_adv & DIGITAL3_LP_UP1_DATARATE_12GX4_MASK) ? 
   7371                 SOC_PA_SPEED_12GB : 0;
   7372         mode |= (an_adv & DIGITAL3_LP_UP1_DATARATE_10GCX4_MASK) ? 
   7373                 SOC_PA_SPEED_10GB : 0;
   7374         mode |= (an_adv & DIGITAL3_LP_UP1_DATARATE_10GX4_MASK) ? 
   7375                 SOC_PA_SPEED_10GB : 0;
   7376         mode |= (an_adv & DIGITAL3_LP_UP1_DATARATE_6GX4_MASK) ?
   7377                  SOC_PA_SPEED_6000MB : 0;
   7378         mode |= (an_adv & DIGITAL3_LP_UP1_DATARATE_5GX4_MASK) ?
   7379                  SOC_PA_SPEED_5000MB : 0;
   7380         mode |= (an_adv & DIGITAL3_LP_UP1_DATARATE_2P5GX1_MASK) ?
   7381                  SOC_PA_SPEED_2500MB : 0;
   7382 
   7383         LOG_INFO(BSL_LS_SOC_PHY,
   7384                  (BSL_META_U(unit,
   7385                              "u=%d p=%d over1G an_adv=%04x\n"),
   7386                   unit, port, an_adv));
   7387 
   7388         SOC_IF_ERROR_RETURN
   7389             (READ_WC40_COMBO_IEEE0_AUTONEGLPABILr(unit, pc, 0x00, &an_adv));
   7390 
   7391         LOG_INFO(BSL_LS_SOC_PHY,
   7392                  (BSL_META_U(unit,
   7393                              "u=%d p=%d combo an_adv=%04x\n"),
   7394                   unit, port, an_adv));
   7395 
   7396         mode |= (an_adv & MII_ANP_C37_FD) ? SOC_PA_SPEED_1000MB : 0;
   7397         ability->speed_full_duplex = mode;
   7398           
   7399         switch (an_adv & (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) {
   7400             case MII_ANP_C37_PAUSE:
   7401                 ability->pause |= SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   7402                 break;
   7403             case MII_ANP_C37_ASYM_PAUSE:
   7404                 ability->pause |= SOC_PA_PAUSE_TX;
   7405                 break;
   7406             case MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE:
   7407                 ability->pause |= SOC_PA_PAUSE_RX;
   7408                 break;
   7409         }
   7410         if (DEV_CFG_PTR(pc)->cl73an) {
   7411             /* make sure it is autoneged link, don't use IEEE0BLK_AN_IEEESTATUS1r,
   7412              * read by soft kr2
   7413              */
   7414             SOC_IF_ERROR_RETURN
   7415                 (READ_WC40_GP2_REG_GP2_1r(unit, pc, LANE0_ACCESS, &data16));
   7416             if (GP2_REG_GP2_1_LINK_AN_MASK & data16 & (1 << pc->lane_num)) {
   7417                 /* Only read when link partner has/enable CL73 ability. */
   7418                 SOC_IF_ERROR_RETURN
   7419                     (READ_WC40_GP2_REG_GP2_4r(unit, pc, LANE0_ACCESS, &data16)); 
   7420                 if (GP2_REG_GP2_4_CL73_MR_LP_AUTONEG_ABLE_MASK & data16 & 
   7421                     (1 << (pc->lane_num + GP2_REG_GP2_4_CL73_MR_LP_AUTONEG_ABLE_SHIFT))) {
   7422                     SOC_IF_ERROR_RETURN
   7423                         (_phy_wc40_c73_adv_remote_get(unit, port, ability));
   7424                 }
   7425             }
   7426         }
   7427     } else {
   7428         /* Simply return local abilities */
   7429         phy_wc40_ability_advert_get(unit, port, ability);
   7430     }
   7431 
   7432     /* Check FEC base on AN and CL37BAM*/
   7433     SOC_IF_ERROR_RETURN
   7434         (READ_WC40_AN_IEEE1BLK_AN_LP_BASEPAGEABILITY2r(unit, pc, 0x00, &an_adv));
   7435     if ((an_adv & AN_IEEE1BLK_AN_LP_BASEPAGEABILITY2_FEC_REQUESTED_MASK) ==
   7436                     AN_IEEE1BLK_AN_LP_BASEPAGEABILITY2_FEC_REQUESTED_MASK) {
   7437         fec = SOC_PA_FEC_CL74;
   7438     } else if (an_adv & (1<<AN_IEEE1BLK_AN_LP_BASEPAGEABILITY2_FEC_REQUESTED_SHIFT)) {
   7439         fec = SOC_PA_FEC_NONE;
   7440     } else {
   7441         fec = 0;
   7442     }
   7443 
   7444     fec |= (up3 & DIGITAL3_LP_UP3_FEC_MASK) ? SOC_PA_FEC_CL74 : SOC_PA_FEC_NONE;
   7445 
   7446     if (fec & SOC_PA_FEC_CL74) {
   7447         ability->fec = SOC_PA_FEC_CL74;
   7448     } else {
   7449         ability->fec = SOC_PA_FEC_NONE;
   7450     }
   7451 
   7452     LOG_INFO(BSL_LS_SOC_PHY,
   7453              (BSL_META_U(unit,
   7454                          "phy_wc40_ability_remote_get:unit=%d p=%d pause=%08x sp=%08x\n"),
   7455               unit, port, ability->pause, ability->speed_full_duplex));
   7456 
   7457     return SOC_E_NONE;
   7458 }
   7459 
   7460 /*
   7461  * Function:
   7462  *      phy_wc40_lb_set
   7463  * Purpose:
   7464  *      Put hc/FusionCore in PHY loopback
   7465  * Parameters:
   7466  *      unit - StrataSwitch unit #.
   7467  *      port - StrataSwitch port #. 
   7468  *      enable - binary value for on/off (1/0)
   7469  * Returns:     
   7470  *      SOC_E_NONE
   7471  */
   7472 
   7473 STATIC int
   7474 phy_wc40_lb_set(int unit, soc_port_t port, int enable)
   7475 {
   7476     phy_ctrl_t *pc;
   7477 
   7478     uint16 lane_mask;
   7479     uint16 lane;
   7480     uint16 data16;
   7481 
   7482     pc = INT_PHY_SW_STATE(unit, port);
   7483 
   7484     if (WC40_REVID_A0(pc) || WC40_REVID_A1(pc) || WC40_REVID_B(pc)) {
   7485         if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   7486             SOC_IF_ERROR_RETURN
   7487                 (MODIFY_WC40_XGXSBLK1_LANETESTr(unit,pc,0x00,
   7488                      enable? XGXSBLK1_LANETEST_PWRDN_SAFE_DIS_MASK: 0,
   7489                      XGXSBLK1_LANETEST_PWRDN_SAFE_DIS_MASK));
   7490         }
   7491     }
   7492 
   7493     /* Use register 0x8017 bit 3-0 gloop, set 0x8000 bit4 for all modes */
   7494      
   7495     if (IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   7496         if (IS_DUAL_LANE_PORT(pc)) {
   7497             lane_mask = 1 << pc->lane_num;
   7498             lane_mask |= (lane_mask << 1);
   7499         } else {
   7500             lane_mask = 1 << pc->lane_num;
   7501         }       
   7502     } else {  /* combo mode */
   7503             lane_mask = XGXSBLK1_LANECTRL2_GLOOP1G_MASK;
   7504     }
   7505     if (enable) {
   7506         lane = lane_mask;
   7507         SOC_IF_ERROR_RETURN
   7508             (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit,pc,0x00,
   7509                  XGXSBLK0_XGXSCONTROL_MDIO_CONT_EN_MASK,
   7510                  XGXSBLK0_XGXSCONTROL_MDIO_CONT_EN_MASK));
   7511 
   7512         if (IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   7513             /* reverse flipped TX/RX polarities if any*/
   7514             SOC_IF_ERROR_RETURN
   7515                 (_phy_wc40_ind_lane_polarity_set(unit,pc,FALSE));
   7516         } else {
   7517             /* reverse flipped Tx/Rx Polarity  */
   7518             SOC_IF_ERROR_RETURN
   7519                 (_phy_wc40_combo_polarity_set(unit,pc,FALSE));
   7520         }
   7521     } else { 
   7522         if (IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   7523             /* reverse flipped TX/RX polarities if any*/
   7524             SOC_IF_ERROR_RETURN
   7525                 (_phy_wc40_ind_lane_polarity_set(unit,pc, TRUE));
   7526         } else {
   7527             /* reverse flipped Tx/Rx Polarity  */
   7528             SOC_IF_ERROR_RETURN
   7529                 (_phy_wc40_combo_polarity_set(unit,pc,TRUE));
   7530         }
   7531         SOC_IF_ERROR_RETURN
   7532             (READ_WC40_XGXSBLK1_LANECTRL2r(unit,pc,0x00,&data16));
   7533         lane = ~lane_mask;
   7534         lane &= data16;
   7535         lane &= XGXSBLK1_LANECTRL2_GLOOP1G_MASK; 
   7536         if (!lane) {
   7537             SOC_IF_ERROR_RETURN
   7538                 (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit,pc,0x00,
   7539                      0,
   7540                      XGXSBLK0_XGXSCONTROL_MDIO_CONT_EN_MASK));
   7541         }
   7542     }
   7543     SOC_IF_ERROR_RETURN
   7544         (MODIFY_WC40_XGXSBLK1_LANECTRL2r(unit, pc, 0x00, lane, lane_mask));
   7545   
   7546     return SOC_E_NONE;
   7547 }
   7548 
   7549 /*
   7550  * Function:
   7551  *      phy_wc40_lb_get
   7552  * Purpose:
   7553  *      Get hc/FusionCore PHY loopback state
   7554  * Parameters:
   7555  *      unit - StrataSwitch unit #.
   7556  *      port - StrataSwitch port #. 
   7557  *      enable - address of location to store binary value for on/off (1/0)
   7558  * Returns:     
   7559  *      SOC_E_NONE
   7560  */
   7561 
   7562 STATIC int
   7563 phy_wc40_lb_get(int unit, soc_port_t port, int *enable)
   7564 {
   7565     phy_ctrl_t *pc;
   7566 
   7567     uint16 lane;
   7568     uint16 lane_mask;
   7569 
   7570     pc = INT_PHY_SW_STATE(unit, port);
   7571 
   7572     SOC_IF_ERROR_RETURN
   7573         (READ_WC40_XGXSBLK1_LANECTRL2r(unit,pc,0x00,&lane));
   7574 
   7575     lane &= XGXSBLK1_LANECTRL2_GLOOP1G_MASK;
   7576  
   7577     if (IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   7578         if (IS_DUAL_LANE_PORT(pc)) {
   7579             lane_mask = 1 << pc->lane_num;
   7580             lane_mask |= (lane_mask << 1);
   7581         } else {
   7582             lane_mask = 1 << pc->lane_num;
   7583         }
   7584     } else {  /* combo mode */
   7585             lane_mask = XGXSBLK1_LANECTRL2_GLOOP1G_MASK;
   7586     }
   7587     lane &= lane_mask;
   7588 
   7589     *enable = lane;
   7590 
   7591     return SOC_E_NONE;
   7592 }
   7593 
   7594 STATIC int
   7595 phy_wc40_interface_set(int unit, soc_port_t port, soc_port_if_t pif)
   7596 {
   7597     phy_ctrl_t      *pc;
   7598     uint32 intf;
   7599 
   7600     pc = INT_PHY_SW_STATE(unit, port);
   7601 
   7602     if (pif > 31) {
   7603         return SOC_E_PARAM;
   7604     }
   7605 
   7606     /* need to check valid interfaces
   7607      * ALL 40G/10G interfaces are mutually exclusive
   7608      */
   7609     intf = DEV_CFG_PTR(pc)->line_intf;
   7610 
   7611     if (WC40_40G_10G_INTF(pif)) {
   7612         intf &= ~WC40_40G_10G_INTF_ALL;  /* clear all 10G/40G interfaces */
   7613         intf |= 1 << pif;
   7614     } else {
   7615         intf |= 1 << pif;
   7616     }
   7617 
   7618     DEV_CFG_PTR(pc)->line_intf = intf;
   7619     return SOC_E_NONE;
   7620 }
   7621 
   7622 STATIC int
   7623 phy_wc40_interface_get(int unit, soc_port_t port, soc_port_if_t *pif)
   7624 {
   7625     phy_ctrl_t *pc;
   7626     int speed;
   7627     int intf;
   7628     int scr;
   7629     int rv;
   7630     uint16 data16;
   7631 
   7632     pc = INT_PHY_SW_STATE(unit, port);
   7633 
   7634     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   7635         rv = _phy_wc40_combo_speed_get(unit, port, &speed,&intf,&scr);
   7636     } else {
   7637         rv = _phy_wc40_ind_speed_get(unit, port, &speed,&intf,&scr);
   7638     }
   7639 
   7640     if (IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   7641         if (speed < 10000) {
   7642             if (DEV_CFG_PTR(pc)->fiber_pref) {
   7643                 *pif = SOC_PORT_IF_GMII;
   7644             } else {
   7645                 *pif = SOC_PORT_IF_SGMII;
   7646             }
   7647         } else {
   7648             if (intf == SOC_PORT_IF_SFI) {
   7649                 if (DEV_CFG_PTR(pc)->line_intf & WC40_IF_CR) {
   7650                     intf = SOC_PORT_IF_CR;
   7651                 }
   7652             }
   7653             *pif = intf;
   7654         }
   7655     } else { /* combo mode */
   7656         if (intf == SOC_PORT_IF_KR4) {
   7657             SOC_IF_ERROR_RETURN
   7658                 (READ_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit, pc, 0x00, &data16));
   7659             if (data16 == WC40_UC_CTRL_XLAUI) {
   7660                 intf = SOC_PORT_IF_XLAUI;
   7661             } else if ((data16 == WC40_UC_CTRL_SR4) || 
   7662                        (data16 == WC40_UC_CTRL_OPT_PF_TEMP_COMP)) {
   7663                 intf = SOC_PORT_IF_SR;
   7664             }
   7665         }
   7666         *pif = intf;
   7667     }
   7668 
   7669     return rv;
   7670 }
   7671 
   7672 STATIC int
   7673 phy_wc40_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   7674 {
   7675     phy_ctrl_t *pc;
   7676     uint8 cl73_bam = FALSE;
   7677 
   7678     if (NULL == ability) {
   7679         return SOC_E_PARAM;
   7680     }
   7681 
   7682     pc = INT_PHY_SW_STATE(unit, port);
   7683 
   7684     WC40_MEM_SET(ability, 0, sizeof(*ability));
   7685 
   7686     if(DEV_CFG_PTR(pc)->cl73an == WC40_CL73_AND_CL73BAM) {
   7687         cl73_bam = TRUE;
   7688     }
   7689 
   7690     if (CUSTOM_MODE(pc)) {
   7691         ability->speed_full_duplex  = SOC_PA_SPEED_3000MB; 
   7692         ability->medium    = SOC_PA_MEDIUM_FIBER;
   7693         ability->loopback  = SOC_PA_LB_PHY;
   7694         return (SOC_E_NONE);
   7695     }
   7696 
   7697     if (CUSTOM1_MODE(pc)) {    
   7698         ability->speed_full_duplex  = SOC_PA_SPEED_12GB;
   7699         ability->medium    = SOC_PA_MEDIUM_FIBER;
   7700         ability->loopback  = SOC_PA_LB_PHY;
   7701         ability->interface |= SOC_PA_INTF_XGMII;
   7702         return (SOC_E_NONE);
   7703     }
   7704     ability->fec = SOC_PA_FEC_NONE | SOC_PA_FEC_CL74;
   7705 
   7706     if (IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) { 
   7707         ability->speed_full_duplex  = SOC_PA_SPEED_1000MB;
   7708         if (DEV_CFG_PTR(pc)->fiber_pref)   {
   7709             ability->speed_full_duplex  |= cl73_bam ? SOC_PA_SPEED_2500MB : 0;
   7710             ability->speed_full_duplex  |= SOC_PA_SPEED_100MB;
   7711             ability->speed_half_duplex  = SOC_PA_SPEED_100MB;
   7712             /* Rest of the abilities based on max speed */
   7713         } else {
   7714             ability->speed_half_duplex  = SOC_PA_SPEED_10MB |
   7715                                           SOC_PA_SPEED_100MB;
   7716             ability->speed_full_duplex  |= SOC_PA_SPEED_10MB |
   7717                                            SOC_PA_SPEED_100MB;
   7718         }
   7719         switch(pc->speed_max) {
   7720             
   7721             /* coverity[unterminated_case:FALSE] */
   7722             case 21000:
   7723                 ability->speed_full_duplex |= SOC_PA_SPEED_21GB;
   7724             /* coverity[fallthrough:FALSE] */
   7725             case 20000:
   7726                 ability->speed_full_duplex |= SOC_PA_SPEED_20GB | SOC_PA_SPEED_21GB;
   7727                 /*passthru*/
   7728             case 15000:
   7729                 ability->speed_full_duplex |= SOC_PA_SPEED_15GB;
   7730                 /*passthru*/
   7731             case 13000:
   7732                 ability->speed_full_duplex |= SOC_PA_SPEED_13GB;
   7733                 /*passthru*/
   7734             case 12000:
   7735                 ability->speed_full_duplex |= SOC_PA_SPEED_12GB;
   7736                 /*passthru*/
   7737             case 11000:
   7738                 ability->speed_full_duplex |= SOC_PA_SPEED_11GB;
   7739                 /*passthru*/
   7740             case 10000:
   7741                 ability->speed_full_duplex |= SOC_PA_SPEED_10GB;
   7742                 if (soc_feature(unit, soc_feature_higig_misc_speed_support)) {
   7743                     ability->speed_full_duplex |= SOC_PA_SPEED_11GB;
   7744                 }
   7745                 if (IS_XE_PORT(unit, port) ) {
   7746                     ability->speed_full_duplex |= SOC_PA_SPEED_100MB;
   7747                     ability->speed_full_duplex |= SOC_PA_SPEED_1000MB;
   7748                     ability->speed_full_duplex |= SOC_PA_SPEED_2500MB;
   7749                 }
   7750                 /*passthru*/
   7751             default:
   7752                 break;
   7753         }
   7754         ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   7755         ability->interface = SOC_PA_INTF_GMII | SOC_PA_INTF_SGMII;
   7756         if (pc->speed_max >= 10000) {
   7757             ability->interface |= SOC_PA_INTF_XGMII;
   7758         } 
   7759         phy_wc40_medium_get(unit, port, &ability->medium);
   7760         ability->loopback  = SOC_PA_LB_PHY;
   7761         if (IS_DUAL_LANE_PORT(pc)) {
   7762             ability->flags     = 0;
   7763         } else {
   7764             ability->flags     = SOC_PA_AUTONEG;
   7765         }
   7766     } else {
   7767         /* XXX when XLPORT is in single port mode, it does not support 1G and 2.5G.
   7768          */
   7769         if ((pc->speed_max <= 10000) || IS_XE_PORT(unit, port)) {
   7770             ability->speed_half_duplex  = SOC_PA_ABILITY_NONE;
   7771             ability->speed_full_duplex  = SOC_PA_SPEED_1000MB;
   7772             if (DEV_CFG_PTR(pc)->fiber_pref)   {
   7773                 ability->speed_full_duplex  |= SOC_PA_SPEED_2500MB;
   7774                     ability->speed_full_duplex  |= SOC_PA_SPEED_100MB;
   7775                     ability->speed_half_duplex  = SOC_PA_SPEED_100MB;
   7776             } else {
   7777                 ability->speed_half_duplex  = SOC_PA_SPEED_10MB |
   7778                                           SOC_PA_SPEED_100MB;
   7779                 ability->speed_full_duplex  |= SOC_PA_SPEED_10MB |
   7780                                            SOC_PA_SPEED_100MB;
   7781             }
   7782         } else {
   7783             ability->speed_full_duplex  = 0;
   7784             ability->speed_half_duplex  = SOC_PA_ABILITY_NONE;
   7785         }
   7786         switch(pc->speed_max) {
   7787             case 42000:
   7788             case 40000:
   7789                 ability->speed_full_duplex |= SOC_PA_SPEED_40GB;
   7790                 if ((!(WC40_REVID_A0(pc) || WC40_REVID_A1(pc))) && 
   7791                 	  (IS_HG_PORT(unit, port))) {
   7792                     ability->speed_full_duplex |= SOC_PA_SPEED_42GB;
   7793                 }
   7794                 /* coverity[MISSING_BREAK:FALSE] */
   7795                 /* passthru */
   7796             case 32000:
   7797             case 30000:
   7798                 ability->speed_full_duplex |= SOC_PA_SPEED_30GB;
   7799                 /* coverity[MISSING_BREAK:FALSE] */
   7800                 /* passthru */
   7801             case 25000:
   7802                 ability->speed_full_duplex |= SOC_PA_SPEED_25GB;
   7803                 /* coverity[MISSING_BREAK:FALSE] */
   7804                 /* passthru */
   7805             case 21000:
   7806                 ability->speed_full_duplex |= SOC_PA_SPEED_21GB;
   7807                 /* coverity[MISSING_BREAK:FALSE] */
   7808                 /* passthru */
   7809             case 20000:
   7810                 ability->speed_full_duplex |= SOC_PA_SPEED_20GB;
   7811                 /* coverity[MISSING_BREAK:FALSE] */
   7812                 /* passthru */
   7813             case 16000:
   7814                 ability->speed_full_duplex |= SOC_PA_SPEED_16GB; 
   7815                 /* coverity[MISSING_BREAK:FALSE] */
   7816                 /* passthru */
   7817             case 15000:
   7818                 ability->speed_full_duplex |= SOC_PA_SPEED_15GB; 
   7819                 /* coverity[MISSING_BREAK:FALSE] */
   7820                 /* passthru */
   7821             case 13000:
   7822                 ability->speed_full_duplex |= SOC_PA_SPEED_13GB;
   7823                 /* coverity[MISSING_BREAK:FALSE] */
   7824                 /* passthru */
   7825             case 12000:
   7826                 ability->speed_full_duplex |= SOC_PA_SPEED_12GB;
   7827                 /* coverity[MISSING_BREAK:FALSE] */
   7828                 /* passthru */
   7829             default:
   7830                 ability->speed_full_duplex |= SOC_PA_SPEED_10GB;
   7831                 break; 
   7832         }
   7833         ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   7834         ability->interface = SOC_PA_INTF_XGMII;
   7835         phy_wc40_medium_get(unit, port, &ability->medium);
   7836         ability->loopback  = SOC_PA_LB_PHY;
   7837         ability->flags     = SOC_PA_AUTONEG;
   7838     }
   7839 
   7840     LOG_INFO(BSL_LS_SOC_PHY,
   7841              (BSL_META_U(unit,
   7842                          "phy_wc40_ability_local_get:unit=%d p=%d sp=%08x\n"),
   7843               unit, port, ability->speed_full_duplex));
   7844 
   7845     return (SOC_E_NONE);
   7846 }
   7847 
   7848 
   7849 #define PHY_WC40_LANEPRBS_LANE_SHIFT   4
   7850 
   7851 STATIC int
   7852 _phy_wc40_control_prbs_polynomial_set(int unit, soc_port_t port, uint32 value)
   7853 {
   7854     uint16 data16 = 0;
   7855     uint16 mask16 = 0;
   7856     int i;
   7857     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   7858        
   7859     if (DEV_CTRL_PTR(pc)->prbs.type == WC40_PRBS_TYPE_CL49) {
   7860         DEV_CTRL_PTR(pc)->prbs.poly = WC40_PRBS_CFG_POLY31;  /* only support the PRBS31 for now */
   7861         return SOC_E_NONE;
   7862     }
   7863     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   7864         /* configure for all four lanes */
   7865         for (i = 0; i < 4; i++) {
   7866             data16 |= value << (PHY_WC40_LANEPRBS_LANE_SHIFT * i);
   7867             mask16 |= XGXSBLK1_LANEPRBS_PRBS_ORDER0_MASK << 
   7868                       (PHY_WC40_LANEPRBS_LANE_SHIFT * i);
   7869         }
   7870     } else if (IS_DUAL_LANE_PORT(pc)) {
   7871         for (i = pc->lane_num; i <= pc->lane_num+1; i++) {
   7872             data16 |= value << (PHY_WC40_LANEPRBS_LANE_SHIFT * i);
   7873             mask16 |= XGXSBLK1_LANEPRBS_PRBS_ORDER0_MASK << 
   7874                       (PHY_WC40_LANEPRBS_LANE_SHIFT * i);
   7875         }
   7876     } else { /* single lane mode */
   7877         data16 = value << (PHY_WC40_LANEPRBS_LANE_SHIFT * pc->lane_num);
   7878         mask16 |= XGXSBLK1_LANEPRBS_PRBS_ORDER0_MASK << 
   7879                       (PHY_WC40_LANEPRBS_LANE_SHIFT * pc->lane_num);
   7880     }
   7881 
   7882     SOC_IF_ERROR_RETURN
   7883         (MODIFY_WC40_XGXSBLK1_LANEPRBSr(unit, pc, 0x00, data16, mask16));
   7884     DEV_CTRL_PTR(pc)->prbs.poly = value;
   7885 
   7886     return SOC_E_NONE;
   7887 }
   7888 
   7889 STATIC int
   7890 _phy_wc40_control_prbs_polynomial_get(int unit, soc_port_t port, uint32 *value)
   7891 {
   7892     uint16      data;
   7893     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);;
   7894 
   7895     if (DEV_CTRL_PTR(pc)->prbs.type == WC40_PRBS_TYPE_CL49) {
   7896         *value = WC40_PRBS_CFG_POLY31;  /*  prbs31 */
   7897         return SOC_E_NONE;  
   7898     }
   7899 
   7900     SOC_IF_ERROR_RETURN
   7901         (READ_WC40_XGXSBLK1_LANEPRBSr(unit, pc, 0x00, &data));
   7902 
   7903     /* Extract prbs polynomial setting from register */
   7904     data = ((data >> (XGXSBLK1_LANEPRBS_PRBS_ORDER1_SHIFT * pc->lane_num)) &
   7905             XGXSBLK1_LANEPRBS_PRBS_ORDER0_MASK);
   7906     *value = (uint32) data;
   7907 
   7908     return SOC_E_NONE;
   7909 }
   7910 
   7911 
   7912 #define INV_SHIFTER(ln)  (PHY_WC40_LANEPRBS_LANE_SHIFT * (ln))
   7913 
   7914 STATIC int
   7915 _phy_wc40_control_prbs_tx_invert_data_set(int unit, soc_port_t port, uint32 value)
   7916 {
   7917     int i;
   7918     uint16 data16 = 0;
   7919     uint16 mask16 = 0;
   7920     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   7921 
   7922     if (DEV_CTRL_PTR(pc)->prbs.type == WC40_PRBS_TYPE_CL49) {
   7923         return SOC_E_NONE;  /* not supported */
   7924     }
   7925 
   7926     value <<= XGXSBLK1_LANEPRBS_PRBS_INV0_SHIFT;
   7927     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   7928         /* configure for all four lanes */
   7929         for (i = 0; i < 4; i++) {
   7930             data16 |= value << INV_SHIFTER(i);
   7931             mask16 |= XGXSBLK1_LANEPRBS_PRBS_INV0_MASK <<
   7932                       INV_SHIFTER(i);
   7933         }
   7934     } else if (IS_DUAL_LANE_PORT(pc)) {
   7935         for (i = pc->lane_num; i <= pc->lane_num+1; i++) {
   7936             data16 |= value << INV_SHIFTER(i);
   7937             mask16 |= XGXSBLK1_LANEPRBS_PRBS_INV0_MASK <<
   7938                       INV_SHIFTER(i);
   7939         }
   7940     } else { /* single lane mode */
   7941         data16 = value << INV_SHIFTER(pc->lane_num);
   7942         mask16 |= XGXSBLK1_LANEPRBS_PRBS_INV0_MASK <<
   7943                       INV_SHIFTER(pc->lane_num);
   7944     }
   7945     SOC_IF_ERROR_RETURN
   7946         (MODIFY_WC40_XGXSBLK1_LANEPRBSr(unit, pc, 0x00, data16, mask16));
   7947     
   7948     return SOC_E_NONE;
   7949 }
   7950 
   7951 STATIC int
   7952 _phy_wc40_control_prbs_tx_invert_data_get(int unit, soc_port_t port, uint32 *value)
   7953 {
   7954     uint16      data;
   7955     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   7956     int inv_shifter;
   7957         
   7958     if (DEV_CTRL_PTR(pc)->prbs.type == WC40_PRBS_TYPE_CL49) {
   7959         *value = 0;  /* no inversion */
   7960         return SOC_E_NONE;  
   7961     }
   7962     inv_shifter = (PHY_WC40_LANEPRBS_LANE_SHIFT * pc->lane_num) +  
   7963                    XGXSBLK1_LANEPRBS_PRBS_INV0_SHIFT;
   7964 
   7965     SOC_IF_ERROR_RETURN
   7966         (READ_WC40_XGXSBLK1_LANEPRBSr(unit, pc, 0x00, &data));
   7967     
   7968     data &= 1 << inv_shifter;
   7969     
   7970     *value = (data) ?  1 : 0;
   7971     
   7972     return SOC_E_NONE;
   7973 }
   7974 
   7975 #define PRBS_LANES_MASK  (XGXSBLK1_LANEPRBS_PRBS_EN3_MASK | \
   7976                 XGXSBLK1_LANEPRBS_PRBS_EN2_MASK | \
   7977                 XGXSBLK1_LANEPRBS_PRBS_EN1_MASK | \
   7978                 XGXSBLK1_LANEPRBS_PRBS_EN0_MASK)
   7979 
   7980 /* PRBS test
   7981  * this routine enables the PRBS generator on applicable lanes depending on
   7982  * the port mode. Before calling this function, a forced speed mode should
   7983  * be set and either the external loopback or internal loopback should be
   7984  * configured. Once this function is called, application should wait to
   7985  * let the test run for a while and then calls the 
   7986  * _phy_wc40_control_prbs_rx_status_get() to retrieve PRBS test status.
   7987  * When calling this function to disable the PRBS test, the device or 
   7988  * specific lane will be re-initialized.  
   7989  */
   7990 
   7991 STATIC int
   7992 _phy_wc40_control_prbs_enable_set(int unit, soc_port_t port, 
   7993                                           uint32 enable)
   7994 {
   7995     uint16      data16;
   7996     uint16      mask16;
   7997     int an;
   7998     int an_done;
   7999     soc_port_if_t intf;
   8000     int prbs_lanes = 0;
   8001     int lane;
   8002     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   8003 
   8004     /* If mode is autoneg KR/KR4, do it thru CL49 PRBS and configure KR forced mode and disable autoneg
   8005      * This way the FIR settings negotiated thru CL72 is preserved
   8006      */
   8007 
   8008     if (DEV_CTRL_PTR(pc)->prbs.type != WC40_PRBS_TYPE_CL49) {
   8009         SOC_IF_ERROR_RETURN
   8010             (phy_wc40_an_get(unit,port,&an,&an_done));
   8011 
   8012         if (an && an_done) {
   8013             /* check interface */
   8014             SOC_IF_ERROR_RETURN
   8015                 (phy_wc40_interface_get(unit,port,&intf));
   8016             if ((intf == SOC_PORT_IF_KR) || (intf == SOC_PORT_IF_KR4) ) {
   8017                 DEV_CTRL_PTR(pc)->prbs.type = WC40_PRBS_TYPE_CL49;
   8018             }
   8019         }
   8020     }
   8021 
   8022     if (DEV_CTRL_PTR(pc)->prbs.type == WC40_PRBS_TYPE_CL49) {
   8023         SOC_IF_ERROR_RETURN
   8024             (phy_wc40_interface_get(unit,port,&intf));
   8025 
   8026         if (!enable) {  /* disable */
   8027             if (intf == SOC_PORT_IF_KR4) {
   8028                 for (lane = 0; lane < 4; lane++) {
   8029                     SOC_IF_ERROR_RETURN
   8030                         (WRITE_WC40_PCS_IEEE2BLK_PCS_TPCONTROLr(unit, pc, ln_access[lane], 0));
   8031                 }
   8032             } else {
   8033                 SOC_IF_ERROR_RETURN
   8034                     (WRITE_WC40_PCS_IEEE2BLK_PCS_TPCONTROLr(unit, pc, 0x00, 0));
   8035             }
   8036             DEV_CTRL_PTR(pc)->prbs.type = 0;
   8037         } 
   8038 
   8039         if (intf == SOC_PORT_IF_KR4) {
   8040             SOC_IF_ERROR_RETURN
   8041                 (MODIFY_WC40_SERDESDIGITAL_MISC1r(unit, pc, 0x00, 
   8042                       enable? 0x11: 0, 
   8043                       SERDESDIGITAL_MISC1_FORCE_SPEED_MASK));
   8044 
   8045             SOC_IF_ERROR_RETURN
   8046                 (MODIFY_WC40_DIGITAL4_MISC3r(unit, pc, 0x00,
   8047                         enable?  DIGITAL4_MISC3_FORCE_SPEED_B5_MASK:0,
   8048                         DIGITAL4_MISC3_FORCE_SPEED_B5_MASK));
   8049 
   8050         } else {  /* KR */
   8051             if (WC40_PHY400_REVS(pc)) {
   8052                 SOC_IF_ERROR_RETURN
   8053                     (MODIFY_WC40_DSC2B0_DSC_MISC_CTRL0r(unit, pc, 0x00,
   8054                              enable? DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_AN_DISABLE_MASK:0,
   8055                              DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_AN_DISABLE_MASK));
   8056                 SOC_IF_ERROR_RETURN
   8057                     (MODIFY_WC40_SERDESDIGITAL_MISC2r(unit, pc, 0x00,
   8058                              enable? SERDESDIGITAL_MISC2_AN_TXDISABLE_LN_MASK:0,
   8059                              SERDESDIGITAL_MISC2_AN_TXDISABLE_LN_MASK));
   8060             }
   8061 
   8062             /* force KR speed */
   8063             SOC_IF_ERROR_RETURN
   8064                 (MODIFY_WC40_SERDESDIGITAL_MISC2r(unit, pc, 0x00,
   8065                    enable? SERDESDIGITAL_MISC2_PMA_PMD_FORCED_SPEED_ENC_EN_MASK:0,
   8066                    SERDESDIGITAL_MISC2_PMA_PMD_FORCED_SPEED_ENC_EN_MASK));
   8067             mask16 =  PMD_IEEE0BLK_PMD_IEEECONTROL1_SPEEDSELECTION1_MASK |
   8068                       PMD_IEEE0BLK_PMD_IEEECONTROL1_SPEEDSELECTION0_MASK;
   8069             data16 = mask16;
   8070             mask16 |= PMD_IEEE0BLK_PMD_IEEECONTROL1_SPEEDSELECTION2_MASK;
   8071             SOC_IF_ERROR_RETURN
   8072                 (MODIFY_WC40_PMD_IEEE0BLK_PMD_IEEECONTROL1r(unit, pc, 0x00, 
   8073                              data16, mask16));
   8074             SOC_IF_ERROR_RETURN
   8075                 (MODIFY_WC40_PMD_IEEE0BLK_PMD_IEEECONTROL2r(unit, pc, 0x00, 
   8076                              0xb, 0xf));
   8077         }
   8078         /* disable cl73 */
   8079         SOC_IF_ERROR_RETURN
   8080             (MODIFY_WC40_AN_IEEE0BLK_AN_IEEECONTROL1r(unit, pc, 0x00, 
   8081                                           enable? 0: MII_CTRL_AE | MII_CTRL_RAN,
   8082                                               MII_CTRL_AE | MII_CTRL_RAN));
   8083         /* disable cl37 */
   8084         SOC_IF_ERROR_RETURN
   8085             (MODIFY_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, 
   8086                                   enable? 0: MII_CTRL_AE | MII_CTRL_RAN,
   8087                                       MII_CTRL_AE | MII_CTRL_RAN));
   8088 
   8089         SOC_IF_ERROR_RETURN
   8090             (READ_WC40_AN_IEEE0BLK_AN_IEEECONTROL1r(unit, pc, 0x00, 
   8091                                           &data16));
   8092         /* not to enable PRBS here. Once PRBS is enabled, the link will go down.
   8093          * Autoneg will be restarted by link partner and Tx settings will be lost.
   8094          * It will be enabled in get function when first time called 
   8095          */ 
   8096         return SOC_E_NONE;
   8097     }
   8098 
   8099     /* non-CL49 PRBS */ 
   8100 
   8101     /* A forced speed mode should be set before running PRBS */
   8102 
   8103     /* CDED & EDEN off: 0x8000 */
   8104     SOC_IF_ERROR_RETURN
   8105         (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00, 
   8106                enable? 0: XGXSBLK0_XGXSCONTROL_CDET_EN_MASK |
   8107                           XGXSBLK0_XGXSCONTROL_EDEN_MASK,
   8108                XGXSBLK0_XGXSCONTROL_CDET_EN_MASK |
   8109                XGXSBLK0_XGXSCONTROL_EDEN_MASK));
   8110 
   8111     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   8112         /* CDED & EDEN off: 0x8017 */
   8113         SOC_IF_ERROR_RETURN
   8114             (MODIFY_WC40_XGXSBLK1_LANECTRL2r(unit, pc, 0x00, 
   8115                    enable? 0: XGXSBLK1_LANECTRL2_CDET_EN1G_MASK |
   8116                               XGXSBLK1_LANECTRL2_EDEN1G_MASK,
   8117                    XGXSBLK1_LANECTRL2_CDET_EN1G_MASK |
   8118                    XGXSBLK1_LANECTRL2_EDEN1G_MASK));
   8119         
   8120         /* Turn off CL36 Tx PCS and 64/66 Endec: 0x8015 */
   8121         SOC_IF_ERROR_RETURN
   8122             (MODIFY_WC40_XGXSBLK1_LANECTRL0r(unit, pc, 0x00, 
   8123                      enable? 0: XGXSBLK1_LANECTRL0_CL36_PCS_EN_TX_MASK |
   8124                                 XGXSBLK1_LANECTRL0_ED66EN_MASK,
   8125                      XGXSBLK1_LANECTRL0_CL36_PCS_EN_TX_MASK |
   8126                      XGXSBLK1_LANECTRL0_ED66EN_MASK));
   8127     } else {
   8128         /* Turn off CL36 Tx PCS and 64/66 Endec for active lane(s): 0x8015 */
   8129         mask16 = 1 << pc->lane_num;
   8130         if (IS_DUAL_LANE_PORT(pc)) {
   8131             mask16 |= 1 << (pc->lane_num + 1);
   8132         }
   8133         mask16 |=  (mask16 << 12);
   8134         SOC_IF_ERROR_RETURN
   8135             (MODIFY_WC40_XGXSBLK1_LANECTRL0r(unit, pc, 0x00, 
   8136              enable? 0: mask16, mask16));
   8137 
   8138         /* CDED & EDEN off for the active lane(s): 0x8017 */
   8139         mask16 = 1 << pc->lane_num;
   8140         if (IS_DUAL_LANE_PORT(pc)) {
   8141             mask16 |= 1 << (pc->lane_num + 1);
   8142         }
   8143         mask16 =  (mask16 << 8) | (mask16 << 12);
   8144         SOC_IF_ERROR_RETURN
   8145             (MODIFY_WC40_XGXSBLK1_LANECTRL2r(unit, pc, 0x00, 
   8146                    enable? 0 : mask16, mask16));
   8147 
   8148         /* clear RX clock compensation which seems messed up PRBS function */
   8149         if (WC40_REVID_A0(pc) || WC40_REVID_A1(pc) || WC40_REVID_B(pc)) {
   8150             if (IS_DUAL_LANE_PORT(pc)) { 
   8151                 SOC_IF_ERROR_RETURN
   8152                     (WRITE_WC40_XGXSBLK2_UNICOREMODE10Gr(unit, pc, 0x00, 
   8153                              enable? 0 : 0x8091));
   8154             } else {
   8155                 SOC_IF_ERROR_RETURN
   8156                     (MODIFY_WC40_RX66_CONTROLr(unit, pc, 0x00,
   8157                         enable? 0 : RX66_CONTROL_CC_EN_MASK |
   8158                                     RX66_CONTROL_CC_DATA_SEL_MASK,
   8159                         RX66_CONTROL_CC_EN_MASK | RX66_CONTROL_CC_DATA_SEL_MASK));
   8160             }
   8161         }
   8162     }
   8163 
   8164     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   8165         /* Enable PRBS read on all lanes: 0x80f1=0x1c47 */ 
   8166         SOC_IF_ERROR_RETURN
   8167             (MODIFY_WC40_RXB_ANARXCONTROLr(unit, pc, 0x00,
   8168                         RXB_ANARXCONTROL_STATUS_SEL_prbsStatus, 
   8169                         RXB_ANARXCONTROL_STATUS_SEL_MASK));
   8170         prbs_lanes = PRBS_LANES_MASK;
   8171 
   8172     } else if (IS_DUAL_LANE_PORT(pc)) {
   8173         /* enable both lanes */
   8174         if (pc->lane_num == 0) {
   8175             prbs_lanes = XGXSBLK1_LANEPRBS_PRBS_EN1_MASK |
   8176                          XGXSBLK1_LANEPRBS_PRBS_EN0_MASK;
   8177             SOC_IF_ERROR_RETURN
   8178                 (MODIFY_WC40_RX0_ANARXCONTROLr(unit, pc, 0x00,
   8179                         RXB_ANARXCONTROL_STATUS_SEL_prbsStatus, 
   8180                         RXB_ANARXCONTROL_STATUS_SEL_MASK));
   8181             SOC_IF_ERROR_RETURN
   8182                 (MODIFY_WC40_RX1_ANARXCONTROLr(unit, pc, 0x00,
   8183                         RXB_ANARXCONTROL_STATUS_SEL_prbsStatus, 
   8184                         RXB_ANARXCONTROL_STATUS_SEL_MASK));
   8185 
   8186         } else { /* lane2 */
   8187             prbs_lanes = XGXSBLK1_LANEPRBS_PRBS_EN3_MASK |
   8188                          XGXSBLK1_LANEPRBS_PRBS_EN2_MASK;
   8189             SOC_IF_ERROR_RETURN
   8190                 (MODIFY_WC40_RX2_ANARXCONTROLr(unit, pc, 0x00,
   8191                         RXB_ANARXCONTROL_STATUS_SEL_prbsStatus, 
   8192                         RXB_ANARXCONTROL_STATUS_SEL_MASK));
   8193             SOC_IF_ERROR_RETURN
   8194                 (MODIFY_WC40_RX3_ANARXCONTROLr(unit, pc, 0x00,
   8195                         RXB_ANARXCONTROL_STATUS_SEL_prbsStatus, 
   8196                         RXB_ANARXCONTROL_STATUS_SEL_MASK));
   8197         }
   8198 
   8199     } else {  /* single lane mode */
   8200         prbs_lanes = 1 << ((XGXSBLK1_LANEPRBS_PRBS_ORDER1_SHIFT * 
   8201                         pc->lane_num) + XGXSBLK1_LANEPRBS_PRBS_EN0_SHIFT);
   8202         SOC_IF_ERROR_RETURN
   8203             (WC40_REG_MODIFY(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), 
   8204                    RX0_ANARXCONTROL_STATUS_SEL_prbsStatus,
   8205                    RX0_ANARXCONTROL_STATUS_SEL_MASK));
   8206     }
   8207     
   8208     /* enable PRBS generator on applicable lanes: 0x8019 */
   8209     SOC_IF_ERROR_RETURN
   8210         (MODIFY_WC40_XGXSBLK1_LANEPRBSr(unit, pc, 0x00, 
   8211                       enable? prbs_lanes : 0,
   8212                       prbs_lanes));
   8213     return SOC_E_NONE;
   8214 }
   8215 
   8216 
   8217 STATIC int
   8218 _phy_wc40_control_prbs_enable_get(int unit, soc_port_t port, 
   8219                                         uint32 *value)
   8220 {
   8221     uint16      data;
   8222     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);;
   8223 
   8224     if (DEV_CTRL_PTR(pc)->prbs.type == WC40_PRBS_TYPE_CL49) {
   8225         SOC_IF_ERROR_RETURN
   8226             (READ_WC40_PCS_IEEE2BLK_PCS_TPCONTROLr(unit, pc, 0x00, &data));
   8227         if (data == WC40_PRBS_CL49_POLY31) {
   8228             *value = 1; 
   8229         } else {
   8230             *value = 0; 
   8231         }
   8232         return SOC_E_NONE;
   8233     }
   8234 
   8235     /*
   8236      * Hypercore PRBS - note that in the Hypercore there is only 1 enable 
   8237      * for both TX/RX 
   8238      */
   8239     SOC_IF_ERROR_RETURN
   8240         (READ_WC40_XGXSBLK1_LANEPRBSr(unit, pc, 0x00, &data));
   8241 
   8242     data = data & ((1 << (XGXSBLK1_LANEPRBS_PRBS_ORDER1_SHIFT * pc->lane_num))
   8243                    << XGXSBLK1_LANEPRBS_PRBS_EN0_SHIFT);
   8244     
   8245     *value = (data) ?  1 : 0;
   8246   
   8247     return SOC_E_NONE;
   8248 }
   8249 
   8250 /*
   8251  * Returns value 
   8252  *      ==  0: PRBS receive is in sync
   8253  *      == -1: PRBS receive never got into sync
   8254  *      ==  n: number of errors
   8255  */
   8256 STATIC int
   8257 _phy_wc40_control_prbs_rx_status_get(int unit, soc_port_t port, 
   8258                                           uint32 *value)
   8259 {
   8260     int         lane;
   8261     int         lane_end;
   8262     uint16      data;
   8263     int         prbs_cfg;
   8264     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);;
   8265 
   8266     /* Get status for all 4 lanes and check for sync
   8267      * 0x80b0, 0x80c0, 0x80d0, 0x80e0 
   8268      */
   8269     *value = 0;
   8270     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   8271         /* combo mode, pc->lane_num = 0 */
   8272         lane_end = 3;  
   8273     } else if (IS_DUAL_LANE_PORT(pc)) {
   8274         lane_end = pc->lane_num + 1;  
   8275     } else {
   8276         lane_end = pc->lane_num;  
   8277     }
   8278 
   8279     if (DEV_CTRL_PTR(pc)->prbs.type == WC40_PRBS_TYPE_CL49) {
   8280         /* enable PRBS if not already. PRBS31 or PRBS9 */
   8281         for (lane = pc->lane_num; lane <= lane_end; lane++) {
   8282             prbs_cfg = TRUE;
   8283             SOC_IF_ERROR_RETURN
   8284                 (READ_WC40_PCS_IEEE2BLK_PCS_TPCONTROLr(unit, pc, ln_access[lane], &data));
   8285             if (DEV_CTRL_PTR(pc)->prbs.poly == WC40_PRBS_CFG_POLY31) {
   8286                 if (data == WC40_PRBS_CL49_POLY31) { /* prbs already in PRBS31 */
   8287                     prbs_cfg = FALSE;
   8288                 }
   8289             } else {
   8290                 DEV_CTRL_PTR(pc)->prbs.poly = WC40_PRBS_CFG_POLY31; /* support PRBS31 only */
   8291             }
   8292 
   8293             if (prbs_cfg) {
   8294                 SOC_IF_ERROR_RETURN
   8295                     (WRITE_WC40_PCS_IEEE2BLK_PCS_TPCONTROLr(unit, pc, ln_access[lane], 
   8296                               WC40_PRBS_CL49_POLY31));
   8297             }
   8298         }
   8299 
   8300         data = 0;
   8301         for (lane = pc->lane_num; lane <= lane_end; lane++) {
   8302             SOC_IF_ERROR_RETURN
   8303                 (READ_WC40_CL49_USERB0_STATUSr(unit,pc,ln_access[lane],&data));
   8304 
   8305             if (data & CL49_USERB0_STATUS_PRBS_LOCK_MASK) { /* PRBS lock */
   8306                 /* check error count */
   8307                 SOC_IF_ERROR_RETURN
   8308                     (READ_WC40_PCS_IEEE2BLK_PCS_TPERRCOUNTERr(unit,pc,ln_access[lane],&data));
   8309                 *value += data;
   8310                 LOG_INFO(BSL_LS_SOC_PHY,
   8311                          (BSL_META_U(unit,
   8312                                      "prbs_rx_status_get: u=%d p=%d (lane %d errors 0x%x)\n"), 
   8313                                      unit, port, lane, data));
   8314 
   8315             } else { /* PRBS not in sync */
   8316                 *value = -1;
   8317                 LOG_INFO(BSL_LS_SOC_PHY,
   8318                          (BSL_META_U(unit,
   8319                                      "prbs_rx_status_get: u=%d p=%d (lane %d not in sync)\n"),
   8320                                      unit, port, lane));
   8321                 break;
   8322             } 
   8323         }
   8324         return SOC_E_NONE;
   8325     }
   8326  
   8327     for (lane = pc->lane_num; lane <= lane_end; lane++) {
   8328         SOC_IF_ERROR_RETURN
   8329             (WC40_REG_READ(unit, pc, 0x00, 0x80b0 + (0x10 * lane), &data));
   8330 
   8331         if (data & RX0_ANARXSTATUS_PRBS_STATUS_PRBS_LOCK_MASK) {
   8332             if (data & RX0_ANARXSTATUS_PRBS_STATUS_PRBS_STKY_MASK) {
   8333                 /* locked now but loss before */
   8334                 *value = -2;
   8335                 continue;
   8336             } else {
   8337                 /* locked now and no loss before. Get errors */
   8338                 *value += data & RX0_ANARXSTATUS_PRBS_STATUS_PTBS_ERRORS_MASK;
   8339                 LOG_INFO(BSL_LS_SOC_PHY,
   8340                          (BSL_META_U(unit,
   8341                                      "prbs_rx_status_get: u=%d p=%d (lane %d errors 0x%x)\n"),
   8342                                      unit, port, lane, (data & RX0_ANARXSTATUS_PRBS_STATUS_PTBS_ERRORS_MASK)));
   8343             }
   8344         } else {
   8345             /* PRBS not in sync */
   8346             LOG_INFO(BSL_LS_SOC_PHY,
   8347                      (BSL_META_U(unit,
   8348                                  "prbs_rx_status_get: u=%d p=%d (lane %d not in sync)\n"),
   8349                                  unit, port, lane));
   8350             *value = -1;
   8351             break;
   8352         }
   8353     }
   8354     return SOC_E_NONE;
   8355 }
   8356 
   8357 STATIC int
   8358 _phy_wc40_control_8b10b_set(int unit, soc_port_t port, uint32 value)
   8359 {
   8360     uint16      data16;
   8361     uint16      mask16;
   8362     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   8363 
   8364     mask16 = 1 << (XGXSBLK1_LANECTRL2_CDET_EN1G_SHIFT + pc->lane_num);
   8365     mask16 |= 1 << (XGXSBLK1_LANECTRL2_EDEN1G_SHIFT + pc->lane_num);
   8366 
   8367     data16 = value? mask16: 0;
   8368  
   8369     SOC_IF_ERROR_RETURN
   8370         (MODIFY_WC40_XGXSBLK1_LANECTRL2r(unit, pc, 0x00, data16,mask16));
   8371 
   8372     return SOC_E_NONE;
   8373 }
   8374 
   8375 STATIC int
   8376 _phy_wc40_control_preemphasis_set(int unit, phy_ctrl_t *pc,
   8377                                 soc_phy_control_t type, uint32 value)
   8378 {
   8379     int     lane_ctrl;
   8380     int     lane_num = 0;
   8381     int     i;
   8382 
   8383     if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE0) {
   8384         lane_ctrl = LANE0_ACCESS;
   8385         lane_num  = 0;
   8386     } else if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE1) {
   8387         lane_ctrl = LANE1_ACCESS;
   8388         lane_num  = 1;
   8389     } else if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE2) {
   8390         lane_ctrl = LANE2_ACCESS;
   8391         lane_num  = 2;
   8392     
   8393       /* coverity[mixed_enums:FALSE] */
   8394     } else if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE3) {
   8395         lane_ctrl = LANE3_ACCESS;
   8396         lane_num  = 3;
   8397     } else {
   8398         lane_ctrl = TX_DRIVER_DFT_LN_CTRL;
   8399     }
   8400 
   8401    
   8402     /* write to specific lane */
   8403     if (lane_ctrl != TX_DRIVER_DFT_LN_CTRL) {
   8404         /* qualify the operation: only writes to its own lane. */
   8405         if (!COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) { 
   8406             if (IS_DUAL_LANE_PORT(pc)) {
   8407                 if ((lane_num < pc->lane_num) || (lane_num > (pc->lane_num + 1))) {
   8408                     return SOC_E_PARAM;
   8409                 } 
   8410             } else {
   8411                 if (lane_num != pc->lane_num) {
   8412                     return SOC_E_PARAM;
   8413                 }
   8414             }
   8415         }
   8416     
   8417         SOC_IF_ERROR_RETURN
   8418             (WRITE_WC40_CL72_USERB0_CL72_TX_FIR_TAP_REGISTERr(unit,pc,
   8419                      lane_ctrl,value));
   8420         DEV_CFG_PTR(pc)->preemph[lane_num - pc->lane_num] = value;
   8421     } else { /* default mode */
   8422         int size;
   8423 
   8424         if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   8425             size = 4;
   8426             /* broadcast to all lanes */
   8427             SOC_IF_ERROR_RETURN
   8428                 (WRITE_WC40_AERBLK_AERr(unit,pc,0x00, WC_AER_BCST_OFS_STRAP));
   8429 
   8430         } else { /* dual-lane bcst if in dxgxs mode */
   8431             size = IS_DUAL_LANE_PORT(pc)? 2: 1;
   8432             DUAL_LANE_BCST_ENABLE(pc);
   8433         }
   8434 
   8435         SOC_IF_ERROR_RETURN
   8436             (WRITE_WC40_CL72_USERB0_CL72_TX_FIR_TAP_REGISTERr(unit,pc,0x00,value));
   8437 
   8438         if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   8439             /* restore AER */
   8440             SOC_IF_ERROR_RETURN
   8441                 (WRITE_WC40_AERBLK_AERr(unit,pc,0x00, 0));
   8442         } else {
   8443             DUAL_LANE_BCST_DISABLE(pc);
   8444         }
   8445         for (i = 0; i < size; i++) {
   8446             DEV_CFG_PTR(pc)->preemph[i] = value;
   8447         }
   8448     }
   8449     return SOC_E_NONE;
   8450 }
   8451 
   8452 
   8453 STATIC int
   8454 _phy_wc40_tx_driver_field_get(soc_phy_control_t type,int *ln_ctrl,uint16 *mask,int *shfter)
   8455 {
   8456     int lane_ctrl;
   8457     
   8458     lane_ctrl = TX_DRIVER_DFT_LN_CTRL;
   8459     *mask = 0;
   8460     *shfter = 0;
   8461     /* _LANEn(n=0-3) control type only applies to combo mode or dxgxs in
   8462      * independent channel mode
   8463      */
   8464     switch(type) {
   8465     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0:
   8466     /*passthru*/
   8467     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1:
   8468     /*passthru*/
   8469     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2:
   8470     /*passthru*/
   8471     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3:
   8472     /*passthru*/
   8473     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   8474         *shfter = TXB_TX_DRIVER_IDRIVER_SHIFT;
   8475         *mask = TXB_TX_DRIVER_IDRIVER_MASK;
   8476         if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0) {
   8477             lane_ctrl = 0;
   8478         } else if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1) {
   8479             lane_ctrl = 1;
   8480         } else if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2) {
   8481             lane_ctrl = 2;
   8482         } else if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3) {
   8483             lane_ctrl = 3;
   8484         }
   8485         break;
   8486 
   8487     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0:
   8488     /*passthru*/
   8489     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1:
   8490     /*passthru*/
   8491     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2:
   8492     /*passthru*/
   8493     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3:
   8494     /*passthru*/
   8495     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   8496         *shfter = TXB_TX_DRIVER_IPREDRIVER_SHIFT;
   8497         *mask = TXB_TX_DRIVER_IPREDRIVER_MASK;
   8498         if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0) {
   8499             lane_ctrl = 0;
   8500         } else if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1) {
   8501             lane_ctrl = 1;
   8502         } else if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2) {
   8503             lane_ctrl = 2;
   8504 
   8505           /* coverity[mixed_enums:FALSE] */
   8506         } else if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3) {
   8507             lane_ctrl = 3;
   8508         }
   8509         break;
   8510     case SOC_PHY_CONTROL_DRIVER_POST2_CURRENT:
   8511         *shfter = TXB_TX_DRIVER_POST2_COEFF_SHIFT;
   8512         *mask = TXB_TX_DRIVER_POST2_COEFF_MASK;
   8513         break;
   8514     default:
   8515          /* should never get here */
   8516         return SOC_E_PARAM;
   8517     }
   8518     *ln_ctrl = lane_ctrl;
   8519     return SOC_E_NONE;
   8520 }
   8521 
   8522 STATIC int
   8523 _phy_wc40_control_tx_driver_set(int unit, phy_ctrl_t *pc,
   8524                                 soc_phy_control_t type, uint32 value)
   8525 {
   8526     uint16  data;             /* Temporary holder of reg value to be written */
   8527     uint16  mask;             /* Bit mask of reg value to be updated */
   8528     int     lane_ctrl;
   8529     int     lane_num;
   8530     int     shifter;
   8531     int     i;
   8532     int     size;
   8533 
   8534     SOC_IF_ERROR_RETURN
   8535         (_phy_wc40_tx_driver_field_get(type,&lane_ctrl,&mask,&shifter));
   8536 
   8537     data = value << shifter;
   8538 
   8539     /* qualify the operation: only writes to its own lane. */
   8540     if (lane_ctrl != TX_DRIVER_DFT_LN_CTRL) {
   8541         if (!COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   8542             if (IS_DUAL_LANE_PORT(pc)) {
   8543                 if ((lane_ctrl < pc->lane_num) || (lane_ctrl > (pc->lane_num + 1))) {
   8544                     return SOC_E_PARAM;
   8545                 }
   8546             } else {
   8547                 if (lane_ctrl != pc->lane_num) {
   8548                     return SOC_E_PARAM;
   8549                 }
   8550             }
   8551         }
   8552     }
   8553     if ((lane_ctrl != TX_DRIVER_DFT_LN_CTRL) ||
   8554         ((!COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) && (!IS_DUAL_LANE_PORT(pc))) ) {
   8555         if (lane_ctrl != TX_DRIVER_DFT_LN_CTRL) {
   8556             lane_num = lane_ctrl;
   8557         } else {
   8558             lane_num = pc->lane_num;         
   8559         }
   8560         if (shifter == TXB_TX_DRIVER_IDRIVER_SHIFT) {
   8561             DEV_CFG_PTR(pc)->idriver[lane_num - pc->lane_num] = value;
   8562         } else if (shifter == TXB_TX_DRIVER_IPREDRIVER_SHIFT) {
   8563             DEV_CFG_PTR(pc)->pdriver[lane_num - pc->lane_num] = value;
   8564         } else {
   8565             DEV_CFG_PTR(pc)->post2driver[lane_num - pc->lane_num] = value;
   8566         }
   8567 
   8568         if (lane_num == 0) {
   8569             SOC_IF_ERROR_RETURN
   8570                 (MODIFY_WC40_TX0_TX_DRIVERr(unit, pc, 0x00, data, mask));
   8571         } else if (lane_num == 1) {
   8572             SOC_IF_ERROR_RETURN
   8573                 (MODIFY_WC40_TX1_TX_DRIVERr(unit, pc, 0x00, data, mask));
   8574         } else if (lane_num == 2) {
   8575             SOC_IF_ERROR_RETURN
   8576                 (MODIFY_WC40_TX2_TX_DRIVERr(unit, pc, 0x00, data, mask));
   8577         } else if (lane_num == 3) {
   8578             SOC_IF_ERROR_RETURN
   8579                 (MODIFY_WC40_TX3_TX_DRIVERr(unit, pc, 0x00, data, mask));
   8580         }
   8581     } else { /* default control in combo mode, or dxgxs port */
   8582         if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   8583             size = 4;
   8584             SOC_IF_ERROR_RETURN
   8585                 (MODIFY_WC40_TX0_TX_DRIVERr(unit, pc, 0x00, data, mask));
   8586             SOC_IF_ERROR_RETURN
   8587                 (MODIFY_WC40_TX1_TX_DRIVERr(unit, pc, 0x00, data, mask));
   8588             SOC_IF_ERROR_RETURN
   8589                 (MODIFY_WC40_TX2_TX_DRIVERr(unit, pc, 0x00, data, mask));
   8590             SOC_IF_ERROR_RETURN
   8591                 (MODIFY_WC40_TX3_TX_DRIVERr(unit, pc, 0x00, data, mask));
   8592         } else if (IS_DUAL_LANE_PORT(pc)) {
   8593             size = 2;
   8594             if (pc->lane_num == 0) {
   8595                 SOC_IF_ERROR_RETURN
   8596                     (MODIFY_WC40_TX0_TX_DRIVERr(unit, pc,0x00, data, mask));
   8597                 SOC_IF_ERROR_RETURN
   8598                     (MODIFY_WC40_TX1_TX_DRIVERr(unit, pc,0x00, data, mask));
   8599             } else {
   8600                 SOC_IF_ERROR_RETURN
   8601                     (MODIFY_WC40_TX2_TX_DRIVERr(unit, pc, LANE0_ACCESS, data, mask));
   8602                 SOC_IF_ERROR_RETURN
   8603                     (MODIFY_WC40_TX3_TX_DRIVERr(unit, pc, LANE0_ACCESS, data, mask));
   8604             }
   8605         } else {
   8606             size = 0;
   8607         }
   8608         for (i = pc->lane_num; i < size; i++) {
   8609             if (shifter == TXB_TX_DRIVER_IDRIVER_SHIFT) {
   8610                 DEV_CFG_PTR(pc)->idriver[i] = value;
   8611             } else if (shifter == TXB_TX_DRIVER_IPREDRIVER_SHIFT) {
   8612                 DEV_CFG_PTR(pc)->pdriver[i] = value;
   8613             } else {
   8614                 DEV_CFG_PTR(pc)->post2driver[i] = value;
   8615             }
   8616         }
   8617 
   8618     }
   8619     return SOC_E_NONE;
   8620 }
   8621 
   8622 STATIC int
   8623 _phy_wc40_control_preemphasis_get(int unit, phy_ctrl_t *pc,
   8624                                 soc_phy_control_t type, uint32 *value)
   8625 {
   8626     uint16  data16;             /* Temporary holder of reg value to be written */
   8627     int     lane_ctrl;
   8628 
   8629     if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE0) {
   8630         lane_ctrl = LANE0_ACCESS;
   8631     } else if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE1) {
   8632         lane_ctrl = LANE1_ACCESS;
   8633     } else if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE2) {
   8634         lane_ctrl = LANE2_ACCESS;
   8635 
   8636       /* coverity[mixed_enums:FALSE] */
   8637     } else if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE3) {
   8638         lane_ctrl = LANE3_ACCESS;
   8639     } else {
   8640         lane_ctrl = TX_DRIVER_DFT_LN_CTRL;
   8641     }
   8642 
   8643     /* write to specific lane */
   8644     if (lane_ctrl != TX_DRIVER_DFT_LN_CTRL) {
   8645         SOC_IF_ERROR_RETURN
   8646             (READ_WC40_CL72_USERB0_CL72_TX_FIR_TAP_REGISTERr(unit,pc,
   8647                      lane_ctrl,&data16));
   8648     } else {
   8649         SOC_IF_ERROR_RETURN
   8650             (READ_WC40_CL72_USERB0_CL72_TX_FIR_TAP_REGISTERr(unit,pc,0x00,&data16));
   8651     }
   8652     *value = data16;
   8653 
   8654     return SOC_E_NONE;
   8655 }
   8656 STATIC int
   8657 _phy_wc40_control_tx_driver_get(int unit, phy_ctrl_t *pc,
   8658                                 soc_phy_control_t type, uint32 *value)
   8659 {
   8660     uint16  data16;           /* Temporary holder of 16 bit reg value */
   8661     uint16  mask;
   8662     int     shifter;
   8663     int     lane_ctrl;
   8664     int     lane_num;
   8665 
   8666     SOC_IF_ERROR_RETURN
   8667         (_phy_wc40_tx_driver_field_get(type,&lane_ctrl,&mask,&shifter));
   8668 
   8669     if (lane_ctrl != TX_DRIVER_DFT_LN_CTRL) {
   8670         lane_num = lane_ctrl;
   8671     } else {
   8672         lane_num = pc->lane_num;
   8673     }
   8674     if (lane_num == 0) {
   8675         SOC_IF_ERROR_RETURN
   8676             (READ_WC40_TX0_TX_DRIVERr(unit, pc, LANE0_ACCESS, &data16));
   8677     } else if (lane_num == 1) {
   8678         SOC_IF_ERROR_RETURN
   8679             (READ_WC40_TX1_TX_DRIVERr(unit, pc, LANE0_ACCESS, &data16));
   8680     } else if (lane_num == 2) {
   8681         SOC_IF_ERROR_RETURN
   8682             (READ_WC40_TX2_TX_DRIVERr(unit, pc, LANE0_ACCESS, &data16));
   8683     } else if (lane_num == 3) {
   8684         SOC_IF_ERROR_RETURN
   8685             (READ_WC40_TX3_TX_DRIVERr(unit, pc, LANE0_ACCESS, &data16));
   8686     } else {
   8687         return SOC_E_PARAM;
   8688     }
   8689     *value = (data16 & mask) >> shifter;
   8690 
   8691     return SOC_E_NONE;
   8692 }
   8693 
   8694 /*
   8695  * Works for 10GX4 8B/10B endec in forced mode. May not work with scrambler 
   8696  * enabled. Doesn't work for 1G/2.5G. Doesn't work for 10G XFI and 40G 
   8697  * using 64/66 endec yet.
   8698  */ 
   8699 STATIC int
   8700 _phy_wc40_control_bert_set(int unit, phy_ctrl_t *pc, int ctrl,
   8701                                 uint32 value)
   8702 {
   8703     uint16 data16 = 0;
   8704     uint16 mask16 = 0;
   8705     int rv = SOC_E_NONE;
   8706 
   8707     switch (ctrl) {
   8708         case SOC_PHY_CONTROL_BERT_PATTERN:   
   8709             if (value == SOC_PHY_CONTROL_BERT_CRPAT) {
   8710                 data16 = TXBERT_TXBERTCTRL_CRPAT_EN_MASK;
   8711             } else if (value == SOC_PHY_CONTROL_BERT_CJPAT) {
   8712                 data16 = TXBERT_TXBERTCTRL_CJPAT_EN_MASK;
   8713             } else {
   8714                 return SOC_E_PARAM;
   8715             }
   8716             SOC_IF_ERROR_RETURN
   8717                 (MODIFY_WC40_TXBERT_TXBERTCTRLr(unit, pc, 0x00,
   8718                      data16,
   8719                      TXBERT_TXBERTCTRL_CJPAT_EN_MASK |
   8720                      TXBERT_TXBERTCTRL_CRPAT_EN_MASK));
   8721             break;
   8722     
   8723         case SOC_PHY_CONTROL_BERT_RUN:    
   8724             if (value) {
   8725                 /* bert test setup */
   8726                 /* enable |E| monitor  */
   8727                 SOC_IF_ERROR_RETURN
   8728                     (MODIFY_WC40_RXB_ANARXCONTROL1Gr(unit,pc,0x00,
   8729                              RXB_ANARXCONTROL1G_EMON_EN_MASK,
   8730                              RXB_ANARXCONTROL1G_EMON_EN_MASK));
   8731 
   8732                 /* with |E| monitor enabled, this selects 8B/10B endec status*/
   8733                 SOC_IF_ERROR_RETURN
   8734                     (MODIFY_WC40_RXB_ANARXCONTROLr(unit, pc, 0x00,
   8735                             RXB_ANARXCONTROL_STATUS_SEL_prbsStatus, 
   8736                             RXB_ANARXCONTROL_STATUS_SEL_MASK));
   8737 
   8738                 /* enable pattern generator and comparator */
   8739                 mask16 = XGXSBLK0_XGXSCONTROL_PGEN_EN_MASK |
   8740                          XGXSBLK0_XGXSCONTROL_PCMP_EN_MASK;
   8741                 data16 = mask16;
   8742                 SOC_IF_ERROR_RETURN
   8743                     (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit,pc,0x00,
   8744                           data16, mask16));
   8745 
   8746                 /* enable CJ(R)PAT generator wiht Q_en and clear TX counter */
   8747                 mask16 = TXBERT_TXBERTCTRL_Q_EN_MASK |
   8748                          TXBERT_TXBERTCTRL_Q_LINK_EN_MASK |
   8749                          TXBERT_TXBERTCTRL_COUNT_CLR_MASK;
   8750                 data16 = mask16;
   8751                 SOC_IF_ERROR_RETURN
   8752                     (MODIFY_WC40_TXBERT_TXBERTCTRLr(unit, pc, 0x00, data16, mask16)); 
   8753 
   8754                 /* re-enable the TX counter */
   8755                 data16 = 0;
   8756                 mask16 = TXBERT_TXBERTCTRL_COUNT_CLR_MASK;
   8757                 SOC_IF_ERROR_RETURN
   8758                     (MODIFY_WC40_TXBERT_TXBERTCTRLr(unit, pc, 0x00, data16, mask16)); 
   8759  
   8760                 /* clear RX counters and enable RX CRC checker */ 
   8761                 mask16 = RXBERT_RXBERTCTRL_COUNT_CLR_MASK |
   8762                          RXBERT_RXBERTCTRL_ERR_CLR_MASK |
   8763                          RXBERT_RXBERTCTRL_CRCCHK_EN_MASK;
   8764                 data16 = mask16;               
   8765                 SOC_IF_ERROR_RETURN
   8766                     (MODIFY_WC40_RXBERT_RXBERTCTRLr(unit, pc, 0x00,
   8767                          data16, mask16));
   8768  
   8769                 /* re-enable the RX counters */
   8770                 data16 = 0;
   8771                 mask16 = RXBERT_RXBERTCTRL_COUNT_CLR_MASK |
   8772                          RXBERT_RXBERTCTRL_ERR_CLR_MASK;
   8773                 SOC_IF_ERROR_RETURN
   8774                     (MODIFY_WC40_RXBERT_RXBERTCTRLr(unit, pc, 0x00,
   8775                          data16, mask16));
   8776 
   8777                 /* enable packet transmission  */
   8778                 SOC_IF_ERROR_RETURN
   8779                     (MODIFY_WC40_TXBERT_TXBERTCTRLr(unit, pc, 0x00,
   8780                          TXBERT_TXBERTCTRL_PKT_EN_MASK,
   8781                          TXBERT_TXBERTCTRL_PKT_EN_MASK)); 
   8782             } else {
   8783                 /* clear bert test setup */
   8784                 SOC_IF_ERROR_RETURN
   8785                     (MODIFY_WC40_RXB_ANARXCONTROL1Gr(unit,pc,0x00,
   8786                              0,
   8787                              RXB_ANARXCONTROL1G_EMON_EN_MASK));
   8788 
   8789                 SOC_IF_ERROR_RETURN
   8790                     (MODIFY_WC40_RXB_ANARXCONTROLr(unit, pc, 0x00,
   8791                             0,
   8792                             RXB_ANARXCONTROL_STATUS_SEL_MASK));
   8793 
   8794                 /* disable packet transmission  */
   8795                 SOC_IF_ERROR_RETURN
   8796                     (MODIFY_WC40_TXBERT_TXBERTCTRLr(unit, pc, 0x00,
   8797                          0,
   8798                          TXBERT_TXBERTCTRL_PKT_EN_MASK));
   8799 
   8800                 /* this clears counters */
   8801                 /* disable pattern generator and comparator */
   8802                 /*SOC_IF_ERROR_RETURN
   8803                  *  (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit,pc,0x00,
   8804                  *        0,
   8805                  *        XGXSBLK0_XGXSCONTROL_PGEN_EN_MASK |
   8806                  *        XGXSBLK0_XGXSCONTROL_PCMP_EN_MASK));
   8807                  */
   8808             }
   8809             break;
   8810 
   8811         case SOC_PHY_CONTROL_BERT_PACKET_SIZE:
   8812             break;
   8813         case SOC_PHY_CONTROL_BERT_IPG:
   8814             break;
   8815         default:
   8816             rv = SOC_E_UNAVAIL;
   8817             break;
   8818     }
   8819     return rv;
   8820 }
   8821 
   8822 STATIC int
   8823 _phy_wc40_control_bert_get(int unit, phy_ctrl_t *pc, int ctrl,
   8824                                 uint32 *value)
   8825 {
   8826     uint16 data16;
   8827     int rv = SOC_E_NONE;
   8828 
   8829     switch (ctrl) {
   8830         case SOC_PHY_CONTROL_BERT_TX_PACKETS:
   8831             SOC_IF_ERROR_RETURN
   8832                 (READ_WC40_TXBERT_TXBERTPACKETUr(unit,pc,0x00,&data16));
   8833             *value = data16 << 16;
   8834             SOC_IF_ERROR_RETURN
   8835                 (READ_WC40_TXBERT_TXBERTPACKETLr(unit,pc,0x00,&data16));
   8836             *value |= data16;
   8837             break;
   8838 
   8839         case SOC_PHY_CONTROL_BERT_RX_PACKETS:
   8840             SOC_IF_ERROR_RETURN
   8841                 (READ_WC40_RXBERT_RXBERTPACKETUr(unit,pc,0x00,&data16));
   8842             *value = data16 << 16;
   8843             SOC_IF_ERROR_RETURN
   8844                 (READ_WC40_RXBERT_RXBERTPACKETLr(unit,pc,0x00,&data16));
   8845             *value |= data16;
   8846             break;
   8847 
   8848         case SOC_PHY_CONTROL_BERT_RX_ERROR_BITS:
   8849             SOC_IF_ERROR_RETURN
   8850                 (READ_WC40_RXBERT_RXBERTBITERRr(unit,pc,0x00,&data16));
   8851             *value = data16;
   8852             break;
   8853 
   8854         case SOC_PHY_CONTROL_BERT_RX_ERROR_BYTES:
   8855             SOC_IF_ERROR_RETURN
   8856                 (READ_WC40_RXBERT_RXBERTBYTEERRr(unit,pc,0x00,&data16));
   8857             *value = data16;
   8858             break;
   8859 
   8860         case SOC_PHY_CONTROL_BERT_RX_ERROR_PACKETS:
   8861             SOC_IF_ERROR_RETURN
   8862                 (READ_WC40_RXBERT_RXBERTPKTERRr(unit,pc,0x00,&data16));
   8863             *value = data16;
   8864             break;
   8865         case SOC_PHY_CONTROL_BERT_PATTERN:
   8866             SOC_IF_ERROR_RETURN
   8867                 (READ_WC40_TXBERT_TXBERTCTRLr(unit, pc, 0x00, &data16));
   8868             if (data16 & TXBERT_TXBERTCTRL_CRPAT_EN_MASK) {
   8869                 *value = SOC_PHY_CONTROL_BERT_CRPAT;
   8870             } else {
   8871                 *value = SOC_PHY_CONTROL_BERT_CJPAT;
   8872             }
   8873             break;
   8874         case SOC_PHY_CONTROL_BERT_PACKET_SIZE:
   8875             break;
   8876         case SOC_PHY_CONTROL_BERT_IPG:
   8877             break;
   8878         default:
   8879             rv = SOC_E_UNAVAIL;
   8880             break;
   8881     }
   8882     return rv;
   8883 }
   8884 
   8885 #ifdef WC_EEE_SUPPORT     
   8886 STATIC int
   8887 _phy_wc40_control_eee_set(int unit, phy_ctrl_t *pc, 
   8888                           soc_phy_control_t type,uint32 enable)
   8889 {
   8890     uint16 data0;
   8891     uint16 mask0;
   8892     uint16 data1;
   8893     uint16 mask1;
   8894 
   8895     switch (type) { 
   8896         case SOC_PHY_CONTROL_EEE:
   8897             mask0 = EEE_USERB0_EEE_COMBO_CONTROL0_EEE_EN_FORCE_VAL_MASK |
   8898                      EEE_USERB0_EEE_COMBO_CONTROL0_EEE_EN_FORCE_MASK |
   8899                      EEE_USERB0_EEE_COMBO_CONTROL0_LPI_EN_FORCE_MASK;
   8900             if (enable == 1) {
   8901                 data0 = mask0;
   8902                 /* enable EEE, disable the LPI pass-thru */
   8903                 SOC_IF_ERROR_RETURN
   8904                     (MODIFY_WC40_DIGITAL4_MISC5r(unit,pc,0x00, 0,
   8905                                 (1 << 14) | (1 << 15)));
   8906                 SOC_IF_ERROR_RETURN
   8907                     (MODIFY_WC40_XGXSBLK7_EEECONTROLr(unit,pc,0x00,0,
   8908                                 XGXSBLK7_EEECONTROL_LPI_EN_TX_MASK |
   8909                                 XGXSBLK7_EEECONTROL_LPI_EN_RX_MASK));
   8910             } else if (enable == 2) {
   8911                 /* enable the LPI pass-thru */
   8912                 data0 = mask0; 
   8913                 mask1 = (1 << 14) | (1 << 15);
   8914                 data1 = mask1;
   8915                 SOC_IF_ERROR_RETURN
   8916                     (MODIFY_WC40_DIGITAL4_MISC5r(unit,pc,0x00, data1, mask1));
   8917                 mask1 = XGXSBLK7_EEECONTROL_LPI_EN_TX_MASK |
   8918                         XGXSBLK7_EEECONTROL_LPI_EN_RX_MASK;
   8919                 data1 = mask1;
   8920                 SOC_IF_ERROR_RETURN
   8921                     (MODIFY_WC40_XGXSBLK7_EEECONTROLr(unit,pc,0x00,data1,mask1));
   8922             } else {
   8923                 /* disable EEE */
   8924                 data0 = EEE_USERB0_EEE_COMBO_CONTROL0_EEE_EN_FORCE_MASK;
   8925             }
   8926             /* forced EEE  */
   8927             SOC_IF_ERROR_RETURN
   8928                 (MODIFY_WC40_EEE_USERB0_EEE_COMBO_CONTROL0r(unit,pc,0x00,
   8929                       data0, mask0));
   8930             break;
   8931 
   8932         case SOC_PHY_CONTROL_EEE_AUTO:
   8933             /* EEE through autoneg */
   8934             mask0 = EEE_USERB0_EEE_COMBO_CONTROL0_EEE_EN_FORCE_MASK |
   8935                      EEE_USERB0_EEE_COMBO_CONTROL0_LPI_EN_FORCE_MASK;
   8936             if (enable == 1) {
   8937                 data0 = 0;
   8938             } else {
   8939                 data0 = mask0;
   8940             }
   8941             SOC_IF_ERROR_RETURN
   8942                 (MODIFY_WC40_EEE_USERB0_EEE_COMBO_CONTROL0r(unit,pc,0x00,data0,
   8943                       mask0));
   8944             break;
   8945 
   8946     default:
   8947          /* should never get here */
   8948          return SOC_E_UNAVAIL;
   8949     }
   8950     return SOC_E_NONE;
   8951 }
   8952 #endif
   8953 
   8954 STATIC int 
   8955 _phy_wc40_rloop_set(int unit, phy_ctrl_t *pc, uint32 enable)
   8956 {
   8957     uint16 mask16;
   8958     uint16 data16;
   8959     int speed;
   8960     int intf;
   8961     int scr;
   8962     int rv;
   8963 
   8964     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   8965         rv = _phy_wc40_combo_speed_get(unit, pc->port, &speed,&intf,&scr);
   8966     } else {
   8967         rv = _phy_wc40_ind_speed_get(unit, pc->port, &speed,&intf,&scr);
   8968     }
   8969     SOC_IF_ERROR_RETURN(rv);
   8970 
   8971     if (IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   8972         if (speed <= 2500) {
   8973             mask16 = SERDESDIGITAL_CONTROL1000X1_REMOTE_LOOPBACK_MASK;
   8974             data16 = enable? mask16: 0;
   8975             SOC_IF_ERROR_RETURN
   8976                 (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X1r(unit,pc,0x00, data16,mask16));
   8977            } else if (speed == 10000) { /* XFI/SFI/KR */
   8978             mask16 = TX66_CONTROL_RLOOP_EN_MASK;
   8979             data16 = enable? mask16: 0;
   8980             SOC_IF_ERROR_RETURN
   8981                 (MODIFY_WC40_TX66_CONTROLr(unit,pc,0x00, data16,mask16));
   8982 
   8983             /* need to enable RX clock compensation which is done already in the init */
   8984         } else if (speed > 10000) { /* dxgxs mode */
   8985             mask16 = XGXSBLK0_XGXSCONTROL_RLOOP_MASK;
   8986             data16 = enable? mask16: 0;
   8987             SOC_IF_ERROR_RETURN
   8988                 (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit,pc,0x00, data16,mask16));
   8989             /* clock compensation should be already enabled in init */
   8990         }
   8991     } else { /* combo mode */
   8992         mask16 = XGXSBLK0_XGXSCONTROL_RLOOP_MASK;
   8993         data16 = enable? mask16:0;
   8994 
   8995         SOC_IF_ERROR_RETURN
   8996             (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit,pc,0x00, data16,mask16));
   8997     }
   8998     return SOC_E_NONE;
   8999 }
   9000 
   9001 STATIC int
   9002 _phy_wc40_rloop_get(int unit, phy_ctrl_t *pc, uint32 *value)
   9003 {
   9004     uint16 mask16;
   9005     uint16 data16;
   9006 
   9007     if (IND_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   9008         mask16 = 1 << (XGXSBLK1_LANECTRL2_RLOOP1G_SHIFT + pc->lane_num);
   9009         SOC_IF_ERROR_RETURN
   9010             (READ_WC40_XGXSBLK1_LANECTRL2r(unit,pc,0x00, &data16));
   9011         *value = (mask16 & data16)? TRUE: FALSE;
   9012 
   9013     } else {
   9014         mask16 = XGXSBLK0_XGXSCONTROL_RLOOP_MASK;
   9015         SOC_IF_ERROR_RETURN
   9016             (READ_WC40_XGXSBLK0_XGXSCONTROLr(unit,pc,0x00, &data16));
   9017         *value = (mask16 & data16)? TRUE: FALSE;
   9018     }
   9019     return SOC_E_NONE;
   9020 }
   9021 
   9022 STATIC int
   9023 _phy_wc40_fec_set(int unit, phy_ctrl_t *pc, uint32 fec_ctrl)
   9024 {
   9025     int rv = SOC_E_NONE;
   9026     uint16 mask16;
   9027     uint16 data16;
   9028 	int lane_start, lane_end,index;
   9029 
   9030     mask16 = CL74_USERB0_UFECCONTROL3_FEC_ENABLE_OVR_VAL_MASK |
   9031              CL74_USERB0_UFECCONTROL3_FEC_ENABLE_OVR_MASK;
   9032 	
   9033     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   9034        lane_start = 0;
   9035        lane_end   = 3;
   9036     } else if (IS_DUAL_LANE_PORT(pc)) {
   9037        lane_start = pc->lane_num;
   9038        lane_end = lane_start + 1;
   9039     } else {  /* quad-port mode */
   9040        lane_start = pc->lane_num;
   9041        lane_end   = lane_start;
   9042     }
   9043 
   9044    for (index = lane_start; index <= lane_end; index++) {
   9045 	
   9046     switch (fec_ctrl) {
   9047         case SOC_PHY_CONTROL_FEC_OFF:
   9048             data16 = CL74_USERB0_UFECCONTROL3_FEC_ENABLE_OVR_MASK;
   9049             SOC_IF_ERROR_RETURN
   9050                 (MODIFY_WC40_CL74_USERB0_UFECCONTROL3r(unit,pc,ln_access[index],data16,mask16));
   9051             break;
   9052         case SOC_PHY_CONTROL_FEC_ON:
   9053             data16 = mask16;
   9054             SOC_IF_ERROR_RETURN
   9055                 (MODIFY_WC40_CL74_USERB0_UFECCONTROL3r(unit,pc,ln_access[index],data16,mask16));
   9056             break;
   9057         case SOC_PHY_CONTROL_FEC_AUTO:
   9058             /* turn off forced override */
   9059             data16 = 0; 
   9060             SOC_IF_ERROR_RETURN
   9061                 (MODIFY_WC40_CL74_USERB0_UFECCONTROL3r(unit,pc,ln_access[index],data16,mask16));
   9062 
   9063             /* configure the CL73 FEC advertisement */
   9064             mask16 = AN_IEEE1BLK_AN_ADVERTISEMENT2_FEC_REQUESTED_MASK;
   9065             data16 = mask16;
   9066             SOC_IF_ERROR_RETURN
   9067                 (MODIFY_WC40_AN_IEEE1BLK_AN_ADVERTISEMENT2r(unit, pc, ln_access[index], data16,
   9068                                      mask16));
   9069             /* configure the CL37 FEC advertisement */
   9070             data16 = mask16 = DIGITAL3_UP3_FEC_MASK;
   9071             SOC_IF_ERROR_RETURN
   9072                 (MODIFY_WC40_DIGITAL3_UP3r(unit, pc, ln_access[index], data16, mask16));
   9073 
   9074             break;
   9075         default:
   9076             rv = SOC_E_PARAM;
   9077             break;
   9078     } 
   9079 		}
   9080     return rv;
   9081 }
   9082 
   9083 STATIC int
   9084 _phy_wc40_fec_get(int unit, phy_ctrl_t *pc, uint32 *value)
   9085 {
   9086     uint16 data16;
   9087 
   9088     SOC_IF_ERROR_RETURN
   9089         (READ_WC40_CL74_USERB0_UFECCONTROL3r(unit,pc,0x00,&data16));
   9090     if (data16 & CL74_USERB0_UFECCONTROL3_FEC_ENABLE_OVR_MASK) {
   9091         *value = data16 & CL74_USERB0_UFECCONTROL3_FEC_ENABLE_OVR_VAL_MASK?
   9092                  SOC_PHY_CONTROL_FEC_ON:
   9093                  SOC_PHY_CONTROL_FEC_OFF; 
   9094     } else {
   9095         *value = SOC_PHY_CONTROL_FEC_AUTO;
   9096     }
   9097     return SOC_E_NONE;         
   9098 }
   9099 
   9100 STATIC int
   9101 _phy_wc40_control_linkdown_transmit_set(int unit, soc_port_t port, uint32 value)
   9102 {
   9103     uint16      ctrl2_data;
   9104     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   9105 
   9106     if (value) {
   9107         ctrl2_data = (SERDESDIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_BITS <<
   9108                       SERDESDIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_SHIFT) |
   9109                      (SERDESDIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_BITS  <<
   9110                       SERDESDIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_SHIFT) |
   9111                      (SERDESDIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_BITS <<
   9112                       SERDESDIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_SHIFT);
   9113         SOC_IF_ERROR_RETURN
   9114             (WRITE_WC40_SERDESDIGITAL_CONTROL1000X2r(unit, pc, 0x00, ctrl2_data));
   9115 
   9116     } else {
   9117         ctrl2_data = (SERDESDIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_BITS <<
   9118                       SERDESDIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_SHIFT) |
   9119                      (SERDESDIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_BITS <<
   9120                       SERDESDIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_SHIFT) |
   9121                      (SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_BITS <<
   9122                       SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_SHIFT);
   9123         SOC_IF_ERROR_RETURN
   9124             (WRITE_WC40_SERDESDIGITAL_CONTROL1000X2r(unit, pc, 0x00, ctrl2_data));
   9125     }
   9126 
   9127     return SOC_E_NONE;
   9128 }
   9129 STATIC int
   9130 _phy_wc40_control_linkdown_transmit_get(int unit, soc_port_t port, uint32 *value)
   9131 {
   9132     uint16      data;
   9133     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   9134 
   9135     SOC_IF_ERROR_RETURN
   9136         (READ_WC40_SERDESDIGITAL_CONTROL1000X2r(unit, pc, 0x00, &data));
   9137 
   9138     /* Check if FORCE_XMIT_DATA_ON_TXSIDE is set */
   9139     *value = (data & (SERDESDIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_BITS <<
   9140                       SERDESDIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_SHIFT))
   9141              ? 1 : 0;
   9142 
   9143     return SOC_E_NONE;
   9144 }
   9145 
   9146 STATIC int
   9147 _phy_wc40_control_vco_freq_get(int unit, soc_port_t port, uint32 *value)
   9148 {
   9149     uint16 data, divider = 32;
   9150     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   9151 
   9152     SOC_IF_ERROR_RETURN(READ_WC40_PLL_ANAPLLSTATUSr(unit, pc, 0x00, &data));
   9153     switch(data & PLL_ANAPLLSTATUS_PLL_MODE_AFE_MASK){
   9154         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div32: divider  = 32;  break;
   9155         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div36: divider  = 36;  break;
   9156         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div40: divider  = 40;  break;
   9157         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div42: divider  = 42;  break;
   9158         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div48: divider  = 48;  break;
   9159         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div50: divider  = 50;  break;
   9160         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div52: divider  = 52;  break;
   9161         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div54: divider  = 54;  break;
   9162         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div60: divider  = 60;  break;
   9163         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div64: divider  = 64;  break;
   9164         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div66: divider  = 66;  break;
   9165         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div68: divider  = 68;  break;
   9166         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div80: divider  = 70;  break;
   9167         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div120: divider  = 80;  break;
   9168         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div200: divider = 92; break;
   9169         case PLL_ANAPLLSTATUS_PLL_MODE_AFE_div240: divider = 100; break;
   9170         
   9171         /* default: return SOC_E_CONFIG; */
   9172     } 
   9173     *value = 156 * divider;
   9174     return(SOC_E_NONE);
   9175 }
   9176 
   9177 
   9178 /*
   9179  * Function:
   9180  *      phy_wc40_control_set
   9181  * Purpose:
   9182  *      Configure PHY device specific control fucntion. 
   9183  * Parameters:
   9184  *      unit  - StrataSwitch unit #.
   9185  *      port  - StrataSwitch port #. 
   9186  *      type  - Control to update 
   9187  *      value - New setting for the control 
   9188  * Returns:     
   9189  *      SOC_E_NONE
   9190  */
   9191 STATIC int
   9192 phy_wc40_control_set(int unit, soc_port_t port,
   9193                      soc_phy_control_t type, uint32 value)
   9194 {
   9195     int rv, lane_start = 0, lane_end = 0, index = 0;
   9196     phy_ctrl_t *pc;
   9197     int speed, intf, scr;
   9198     uint16 mask16, data16;
   9199     soc_port_if_t interface;
   9200     int an, an_done;
   9201     /* coverity[mixed_enums] */
   9202     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
   9203         return SOC_E_PARAM;
   9204     }
   9205 
   9206     pc = INT_PHY_SW_STATE(unit, port);
   9207     rv = SOC_E_UNAVAIL;
   9208     switch(type) {
   9209     case SOC_PHY_CONTROL_PREEMPHASIS_LANE0:
   9210         /*passthru*/
   9211     case SOC_PHY_CONTROL_PREEMPHASIS_LANE1:
   9212         /*passthru*/
   9213     case SOC_PHY_CONTROL_PREEMPHASIS_LANE2:
   9214         /*passthru*/
   9215     case SOC_PHY_CONTROL_PREEMPHASIS_LANE3:
   9216         /*passthru*/
   9217     case SOC_PHY_CONTROL_PREEMPHASIS:
   9218         rv = _phy_wc40_control_preemphasis_set(unit, pc, type, value);
   9219         break;
   9220 
   9221     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0:
   9222         /*passthru*/
   9223     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1:
   9224         /*passthru*/
   9225     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2:
   9226         /*passthru*/
   9227     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3:
   9228         /*passthru*/
   9229     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0:
   9230         /*passthru*/
   9231     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1:
   9232         /*passthru*/
   9233     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2:
   9234         /*passthru*/
   9235     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3:
   9236         /*passthru*/
   9237     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   9238         /*passthru*/
   9239     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   9240         /*passthru*/
   9241     case SOC_PHY_CONTROL_DRIVER_POST2_CURRENT:     
   9242         rv = _phy_wc40_control_tx_driver_set(unit, pc, type, value);
   9243         break;
   9244     case SOC_PHY_CONTROL_PRBS_POLYNOMIAL:
   9245         rv = _phy_wc40_control_prbs_polynomial_set(unit, port, value);
   9246         break;
   9247     case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA:
   9248         rv = _phy_wc40_control_prbs_tx_invert_data_set(unit, port, value);
   9249         break;
   9250     case SOC_PHY_CONTROL_PRBS_TX_ENABLE:
   9251         /* passthru */
   9252     case SOC_PHY_CONTROL_PRBS_RX_ENABLE:
   9253         rv = _phy_wc40_control_prbs_enable_set(unit, port, value);
   9254         rv = SOC_E_NONE;
   9255         break;
   9256     case SOC_PHY_CONTROL_8B10B:
   9257         rv = _phy_wc40_control_8b10b_set(unit, port, value);
   9258         break;
   9259 #ifdef WC_EEE_SUPPORT
   9260     case SOC_PHY_CONTROL_EEE:
   9261         /*passthru*/
   9262     case SOC_PHY_CONTROL_EEE_AUTO:
   9263         rv = _phy_wc40_control_eee_set(unit,pc,type,value);
   9264         break;
   9265 #endif
   9266     case SOC_PHY_CONTROL_LOOPBACK_REMOTE:
   9267         rv = _phy_wc40_rloop_set(unit,pc,value);
   9268         break;
   9269     case SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION:
   9270         rv = _phy_wc40_fec_set(unit,pc,value);
   9271         break;
   9272     /* XXX obsolete */
   9273     case SOC_PHY_CONTROL_CUSTOM1:
   9274         DEV_CFG_PTR(pc)->custom1 = value? TRUE: FALSE;
   9275         rv = SOC_E_NONE;
   9276         break;
   9277     case SOC_PHY_CONTROL_SCRAMBLER:
   9278         DEV_CFG_PTR(pc)->scrambler_en = value? TRUE: FALSE;
   9279         rv = SOC_E_NONE;
   9280         break;
   9281     case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT:
   9282         rv = _phy_wc40_control_linkdown_transmit_set(unit, port, value);
   9283         break;
   9284     case SOC_PHY_CONTROL_PARALLEL_DETECTION:
   9285         /* enable 1000X parallel detect */
   9286         SOC_IF_ERROR_RETURN
   9287             (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X2r(unit, pc, 0,
   9288               value? SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK:0,
   9289               SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK));
   9290         rv = SOC_E_NONE;
   9291         break;
   9292     case SOC_PHY_CONTROL_BERT_PATTERN:
   9293         /*passthru*/
   9294     case SOC_PHY_CONTROL_BERT_RUN:
   9295         /*passthru*/
   9296     case SOC_PHY_CONTROL_BERT_PACKET_SIZE:
   9297         /*passthru*/
   9298     case SOC_PHY_CONTROL_BERT_IPG:
   9299         rv = _phy_wc40_control_bert_set(unit,pc,type,value);
   9300         break;
   9301     case SOC_PHY_CONTROL_TX_PPM_ADJUST:
   9302 
   9303        /* value = offset
   9304         * ----------------------------------
   9305         * Reference Values:
   9306         * PPM   Offset  Setting
   9307         * -5    0xff99
   9308         * -10   0xff31
   9309         * -15   0xfec9
   9310         * -20   0xfe61
   9311         * -25   0xfdf9
   9312         * -30   0xfd91
   9313         * -35   0xfd29
   9314         * -40   0xfcc1
   9315         * -45   0xfc59
   9316         * -50   0xfbf1
   9317         * -55   0xfb89
   9318         * -60   0xfb21
   9319         * -65   0xfab9
   9320         * -70   0xfa51
   9321         *     
   9322         * 5     0x69
   9323         * 10    0xd1
   9324         * 15    0x139
   9325         * 20    0x1a1
   9326         * 25    0x209
   9327         * 30    0x271
   9328         * 35    0x2d0
   9329         * 40    0x341
   9330         * 45    0x3a9
   9331         * 50    0x411
   9332         * 55    0x479
   9333         * 60    0x4e1
   9334         * 65    0x549
   9335         * 70    0x5b1
   9336         * ----------------------------------
   9337        */
   9338 
   9339         if(value & 0x1) {
   9340             /* Enable Tx PI */
   9341             SOC_IF_ERROR_RETURN(
   9342                     (MODIFY_WC40_XGXSBLK8_TX_PI_CONTROL1r(unit, pc, 0x00, 
   9343                             1, 
   9344                             XGXSBLK8_TX_PI_CONTROL1_TX_PI_EN_MASK)));
   9345             /* TX PI Frequency Override Enable BIT[0]
   9346                Frequency Override value BIT[15:1] 
   9347              */
   9348             SOC_IF_ERROR_RETURN(
   9349                     (WRITE_WC40_XGXSBLK8_TX_PI_CONTROL3r(unit, pc, 0x00, value)));
   9350         } else {
   9351             /* Disable Tx PI */
   9352             SOC_IF_ERROR_RETURN(
   9353                     (MODIFY_WC40_XGXSBLK8_TX_PI_CONTROL1r(unit, pc, 0x00, 
   9354                      0,
   9355                      XGXSBLK8_TX_PI_CONTROL1_TX_PI_EN_MASK))); 
   9356             /* TX PI Frequency Override Enable BIT[0]
   9357                Frequency Override value BIT[15:1] 
   9358              */
   9359             SOC_IF_ERROR_RETURN(
   9360                     (WRITE_WC40_XGXSBLK8_TX_PI_CONTROL3r(unit, pc, 0x00, 0)));
   9361 
   9362         }
   9363         rv = SOC_E_NONE;
   9364         break; 
   9365     case SOC_PHY_CONTROL_RX_RESET:
   9366 
   9367         if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   9368             lane_start = 0;
   9369             lane_end   = 3;
   9370         } else if (IS_DUAL_LANE_PORT(pc)) {
   9371             lane_start = pc->lane_num;
   9372             lane_end = lane_start + 1;
   9373         } else {  /* quad-port mode */
   9374             lane_start = pc->lane_num;
   9375             lane_end   = lane_start;
   9376         }
   9377         for (index = lane_start; index <= lane_end; index++) {
   9378              SOC_IF_ERROR_RETURN
   9379                      (MODIFY_WC40_DSC2B0_DSC_MISC_CTRL0r(unit, pc, ln_access[index], 
   9380                       DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_MASK, 
   9381                       DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_MASK));
   9382         }
   9383         rv = SOC_E_NONE;
   9384         break;  
   9385     case SOC_PHY_CONTROL_SOFTWARE_RX_LOS:
   9386 #if 0 
   9387         rv = SOC_E_FAIL;
   9388         phy_wc40_interface_get(unit, port, &interface);
   9389         /* Only enable the feature for 10G/40G fiber */
   9390         if( (interface == SOC_PORT_IF_SFI) || (interface == SOC_PORT_IF_SR)) { 
   9391             SOC_IF_ERROR_RETURN
   9392                 (READ_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit, pc, 0x00, &data16));
   9393             if ((data16 == WC40_UC_CTRL_DEFAULT) 
   9394                 || (data16 == WC40_UC_CTRL_SR4) 
   9395                 || (data16 == WC40_UC_CTRL_OPT_PF_TEMP_COMP)) {
   9396 
   9397 #endif
   9398         /* Only enable the feature for 10G/40G fiber */
   9399 
   9400 #ifdef SW_RX_LOS_LINK_FLAP_WAR
   9401         SOC_IF_ERROR_RETURN
   9402             (soc_mac_probe(unit, port, &DEV_CFG_PTR(pc)->macd));
   9403 #endif
   9404 
   9405         DEV_CFG_PTR(pc)->sw_rx_los.enable = (value == 0? 0: 1);
   9406 #ifdef BCM_WARM_BOOT_SUPPORT
   9407         if(!SOC_WARM_BOOT(unit))
   9408 #endif
   9409         {
   9410             DEV_CFG_PTR(pc)->sw_rx_los.sys_link = 0; 
   9411             DEV_CFG_PTR(pc)->sw_rx_los.state = RESET;
   9412             DEV_CFG_PTR(pc)->sw_rx_los.link_status = 0;
   9413         }
   9414         /* Manage the _SERVICE_INT_PHY_LINK_GET flag so that 
   9415            if external phy is present link_get for 
   9416            internal phy is still called to process 
   9417            software rx los feature */ 
   9418         if(value) {
   9419             PHY_FLAGS_SET(unit, port, PHY_FLAGS_SERVICE_INT_PHY_LINK_GET);
   9420         } else {
   9421             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_SERVICE_INT_PHY_LINK_GET);
   9422         }
   9423         rv = SOC_E_NONE;
   9424         break;     
   9425     case SOC_PHY_CONTROL_RX_PEAK_FILTER_TEMP_COMP:
   9426  
   9427         /* Get speed */
   9428         if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   9429             rv = _phy_wc40_combo_speed_get(unit, port, &speed,&intf,&scr);
   9430         } else {
   9431             rv = _phy_wc40_ind_speed_get(unit, port, &speed,&intf,&scr);
   9432         }
   9433 
   9434         /* Get interface */
   9435         phy_wc40_interface_get(unit, port, &interface);
   9436 
   9437         if( (speed == 40000) && (interface == SOC_PORT_IF_SR) ) {
   9438             /* Puts PLL in reset state and forces all datapath
   9439                into reset state */
   9440             SOC_IF_ERROR_RETURN
   9441                 (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00, 0,
   9442                              XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
   9443             if(value) {
   9444                 data16 = WC40_UC_CTRL_OPT_PF_TEMP_COMP;
   9445             } else {
   9446                 data16 = WC40_UC_CTRL_SR4; /* default for SR4 */
   9447             }
   9448             SOC_IF_ERROR_RETURN
   9449                 (WRITE_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit, pc, 0x00,
   9450                                                       data16));
   9451             /* Brings PLL out of reset state */
   9452             SOC_IF_ERROR_RETURN
   9453                 (MODIFY_WC40_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x00,
   9454                              XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK,
   9455                              XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
   9456 
   9457 
   9458         } else if ( (speed == 10000) && ((interface == SOC_PORT_IF_SFI) 
   9459                    || (interface == SOC_PORT_IF_SR)) ) {
   9460             /* Do not apply for 10G SFP DAC */
   9461             SOC_IF_ERROR_RETURN
   9462                 (READ_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit,pc,LANE0_ACCESS,&data16));
   9463             if (((data16 >> (pc->lane_num * 4)) & 0xf) == WC40_UC_CTRL_SFP_DAC) {
   9464                 return SOC_E_NONE;
   9465             }
   9466     
   9467             WC40_CL73_AN_TX_FIFO_RESET_STOP(pc);
   9468             
   9469             /* Hold rx_asic_reset */
   9470             mask16 = DIGITAL5_MISC6_RESET_RX_ASIC_MASK;
   9471             data16 = mask16;
   9472             SOC_IF_ERROR_RETURN
   9473                 (MODIFY_WC40_DIGITAL5_MISC6r(unit,pc, ln_access[pc->lane_num], 
   9474                                              data16, mask16));
   9475             mask16 = 0xf << (4*pc->lane_num);
   9476             if( value) {
   9477                 /* Set the firmware mode to  OPT_PF_TEMP_COMP */
   9478                 data16 = WC40_UC_CTRL_OPT_PF_TEMP_COMP;  
   9479             } else {
   9480                 /* Set the firmware mode to default */
   9481                 data16 = 0x0000; 
   9482             }
   9483             SOC_IF_ERROR_RETURN
   9484                 (MODIFY_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit, pc, LANE0_ACCESS, 
   9485                                                        data16, mask16));
   9486             /* Release rx_asic_reset */
   9487             mask16 = DIGITAL5_MISC6_RESET_RX_ASIC_MASK;
   9488             data16 = 0;
   9489             SOC_IF_ERROR_RETURN
   9490                 (MODIFY_WC40_DIGITAL5_MISC6r(unit,pc, ln_access[pc->lane_num], 
   9491                                              data16, mask16));
   9492 
   9493             WC40_CL73_AN_TX_FIFO_RESET_START(pc);
   9494         } 
   9495         /* rv = SOC_E_NONE; */
   9496         break;
   9497     case SOC_PHY_CONTROL_CL73_FSM_AUTO_RECOVER:
   9498         DEV_CFG_PTR(pc)->cl73_fsm_auto_recover.enable = value? 1 : 0;
   9499         DEV_CFG_PTR(pc)->cl73_fsm_auto_recover.fsm_state_prev = 0;
   9500         DEV_CFG_PTR(pc)->cl73_fsm_auto_recover.fsm_state_count = 0;
   9501         DEV_CFG_PTR(pc)->cl73_fsm_auto_recover.action_count_state02 = 0;
   9502         DEV_CFG_PTR(pc)->cl73_fsm_auto_recover.action_count_state04 = 0;
   9503         DEV_CFG_PTR(pc)->cl73_fsm_auto_recover.action_count_state08 = 0;
   9504         DEV_CFG_PTR(pc)->cl73_fsm_auto_recover.action_count_state10 = 0;
   9505         DEV_CFG_PTR(pc)->cl73_fsm_auto_recover.action_count_state20 = 0;
   9506 
   9507         rv = SOC_E_NONE;     
   9508         break;
   9509     case SOC_PHY_CONTROL_CL72:
   9510         value = value? TRUE : FALSE;
   9511         SOC_IF_ERROR_RETURN(
   9512                 phy_wc40_an_get(unit, port, &an, &an_done));
   9513         if(!(an)) {
   9514             /* Autoneg OFF */
   9515             if (value != FORCE_CL72_IS_ENABLED(pc)) {
   9516                 SOC_IF_ERROR_RETURN
   9517                     (_phy_wc40_force_cl72_config(unit,port,value));
   9518                 FORCE_CL72_ENABLE(pc) = value;
   9519             }
   9520         } else {
   9521             /* Autoneg ON */
   9522             SOC_IF_ERROR_RETURN(
   9523                 _phy_wc40_cl72_enable(unit, port, value));
   9524         }
   9525         rv = SOC_E_NONE;     
   9526         break;
   9527     case SOC_PHY_CONTROL_FIRMWARE_MODE:
   9528         rv = _phy_wc40_firmware_mode_set(unit, port, value);
   9529         break;
   9530     case SOC_PHY_CONTROL_DFE:
   9531         rv = _phy_wc40_firmware_dfe_mode_set(unit, port, value);
   9532         break;
   9533     case SOC_PHY_CONTROL_AUTONEG_MODE:
   9534         rv = SOC_E_NONE;     
   9535         SOC_IF_ERROR_RETURN(
   9536                 phy_wc40_an_get(unit, port, &an, &an_done));
   9537         if(an) {
   9538             LOG_WARN(BSL_LS_SOC_PHY,
   9539                      (BSL_META_U(unit,
   9540                                  "phy_wc40_control_set: PHY_CONTROL_AUTONEG_MODE "
   9541                                  "-> disable autoneg u=%d p=%d\n"), unit, port));
   9542             return SOC_E_FAIL;
   9543         }
   9544         switch(value) {
   9545             case SOC_PHY_CONTROL_AUTONEG_MODE_CL37:
   9546                 DEV_CFG_PTR(pc)->cl37an = WC40_CL37_WO_CL37BAM;
   9547                 break;
   9548             case SOC_PHY_CONTROL_AUTONEG_MODE_CL37_BAM:
   9549                 DEV_CFG_PTR(pc)->cl37an = WC40_CL37_AND_CL37BAM;
   9550                 break;
   9551             case SOC_PHY_CONTROL_AUTONEG_MODE_CL73:
   9552                 DEV_CFG_PTR(pc)->cl73an = WC40_CL73_WO_CL73BAM;
   9553                 break;
   9554             case SOC_PHY_CONTROL_AUTONEG_MODE_CL73_BAM:
   9555                 DEV_CFG_PTR(pc)->cl73an = WC40_CL73_AND_CL73BAM;
   9556                 break;
   9557             case SOC_PHY_CONTROL_AUTONEG_MODE_CL37_CL73:
   9558                 DEV_CFG_PTR(pc)->cl37an = WC40_CL37_WO_CL37BAM;
   9559                 DEV_CFG_PTR(pc)->cl73an = WC40_CL73_WO_CL73BAM;
   9560                 break;    
   9561             case SOC_PHY_CONTROL_AUTONEG_MODE_CL37_CL73_BAM:
   9562                 DEV_CFG_PTR(pc)->cl37an = WC40_CL37_WO_CL37BAM;
   9563                 DEV_CFG_PTR(pc)->cl73an = WC40_CL73_AND_CL73BAM;
   9564                 break;    
   9565             case SOC_PHY_CONTROL_AUTONEG_MODE_CL37_BAM_CL73:
   9566                 DEV_CFG_PTR(pc)->cl37an = WC40_CL37_AND_CL37BAM;
   9567                 DEV_CFG_PTR(pc)->cl73an = WC40_CL73_WO_CL73BAM;
   9568                 break;    
   9569             case SOC_PHY_CONTROL_AUTONEG_MODE_CL37_BAM_CL73_BAM:
   9570                 DEV_CFG_PTR(pc)->cl37an = WC40_CL37_AND_CL37BAM;
   9571                 DEV_CFG_PTR(pc)->cl73an = WC40_CL73_AND_CL73BAM;
   9572                 break;    
   9573             default:
   9574                 rv = SOC_E_PARAM;
   9575                 break;    
   9576         }
   9577         break;        
   9578     default:
   9579         rv = SOC_E_UNAVAIL;
   9580         break; 
   9581     }
   9582     return rv;
   9583 }
   9584 
   9585 /* Make use of the TX0_ANATXACONTROL5.TX_PRBS_INV_DECOUPLE as a scratch pad for VCO status */
   9586 #define READ_WC40_TX0_ANATXACONTROL5r(_unit, _pc, _flags, _val) \
   9587         WC40_REG_READ((_unit), (_pc), (_flags), 0x00008069, (_val))
   9588 #define WRITE_WC40_TX0_ANATXACONTROL5r(_unit, _pc, _flags, _val) \
   9589         WC40_REG_WRITE((_unit), (_pc), (_flags), 0x00008069, (_val))
   9590 #define MODIFY_WC40_TX0_ANATXACONTROL5r(_unit, _pc, _flags, _val, _mask) \
   9591         WC40_REG_MODIFY((_unit), (_pc), (_flags), 0x00008069, (_val), (_mask))
   9592 
   9593 #define TX0_ANATXACONTROL5_VCO_DISTURBED_MASK                            0x0010
   9594 #define TX0_ANATXACONTROL5_VCO_DISTURBED_ALIGN                           0
   9595 #define TX0_ANATXACONTROL5_VCO_DISTURBED_BITS                            1
   9596 #define TX0_ANATXACONTROL5_VCO_DISTURBED_SHIFT                           4
   9597 
   9598 STATIC int
   9599 _phy_wc40_control_vco_disturbed_get(int unit, soc_port_t port, uint32 *value)
   9600 {
   9601     uint16 data;
   9602     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   9603     if(!pc) {
   9604         return SOC_E_NONE;
   9605     }
   9606     SOC_IF_ERROR_RETURN(READ_WC40_TX0_ANATXACONTROL5r(unit, pc, 0x00, &data));
   9607     SOC_IF_ERROR_RETURN(MODIFY_WC40_TX0_ANATXACONTROL5r(unit, pc, 0x00, 0, (1 << TX0_ANATXACONTROL5_VCO_DISTURBED_SHIFT)));
   9608     
   9609     *value = (data & TX0_ANATXACONTROL5_VCO_DISTURBED_MASK) ? 1 : 0;
   9610     
   9611     return SOC_E_NONE;
   9612 }
   9613 
   9614 STATIC int
   9615 _phy_wc40_control_vco_disturbed_set(int unit, soc_port_t port)
   9616 {
   9617     uint16 data, mask;
   9618     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   9619     if(!pc) {
   9620         return SOC_E_NONE;
   9621     }
   9622     data = 1 << TX0_ANATXACONTROL5_VCO_DISTURBED_SHIFT;
   9623     mask = data;
   9624     
   9625     SOC_IF_ERROR_RETURN(MODIFY_WC40_TX0_ANATXACONTROL5r(unit, pc, 0x00, data, mask));
   9626     
   9627     return SOC_E_NONE;
   9628 }
   9629 /*
   9630  * Function:
   9631  *      phy_wc40_control_get
   9632  * Purpose:
   9633  *      Get current control settign of the PHY. 
   9634  * Parameters:
   9635  *      unit  - StrataSwitch unit #.
   9636  *      port  - StrataSwitch port #. 
   9637  *      type  - Control to update 
   9638  *      value - (OUT)Current setting for the control 
   9639  * Returns:     
   9640  *      SOC_E_NONE
   9641  */
   9642 STATIC int
   9643 phy_wc40_control_get(int unit, soc_port_t port,
   9644                      soc_phy_control_t type, uint32 *value)
   9645 {
   9646     int rv;
   9647     uint16 data16;
   9648     int intf;
   9649     int scr;
   9650     int speed;
   9651     phy_ctrl_t *pc;
   9652     int cl37, cl73;
   9653 
   9654     if (NULL == value) {
   9655         return SOC_E_PARAM;
   9656     }
   9657     /* coverity[mixed_enums] */
   9658     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
   9659         return SOC_E_PARAM;
   9660     }
   9661    
   9662     pc = INT_PHY_SW_STATE(unit, port);
   9663     rv = SOC_E_UNAVAIL;
   9664     switch(type) {
   9665     case SOC_PHY_CONTROL_PREEMPHASIS_LANE0:
   9666         /*passthru*/
   9667     case SOC_PHY_CONTROL_PREEMPHASIS_LANE1:
   9668         /*passthru*/
   9669     case SOC_PHY_CONTROL_PREEMPHASIS_LANE2:
   9670         /*passthru*/
   9671     case SOC_PHY_CONTROL_PREEMPHASIS_LANE3:
   9672         /*passthru*/
   9673     case SOC_PHY_CONTROL_PREEMPHASIS:
   9674         rv = _phy_wc40_control_preemphasis_get(unit, pc, type, value);
   9675         break;
   9676 
   9677     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0:
   9678         /*passthru*/
   9679     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1:
   9680         /*passthru*/
   9681     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2:
   9682         /*passthru*/
   9683     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3:
   9684         /*passthru*/
   9685     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0:
   9686         /*passthru*/
   9687     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1:
   9688         /*passthru*/
   9689     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2:
   9690         /*passthru*/
   9691     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3:
   9692         /*passthru*/
   9693     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   9694         /*passthru*/
   9695     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   9696         /*passthru*/
   9697     case SOC_PHY_CONTROL_DRIVER_POST2_CURRENT:    
   9698         rv = _phy_wc40_control_tx_driver_get(unit, pc, type, value);
   9699         break;
   9700     case SOC_PHY_CONTROL_PRBS_POLYNOMIAL:
   9701         rv = _phy_wc40_control_prbs_polynomial_get(unit, port, value);
   9702         break;
   9703     case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA:
   9704         rv = _phy_wc40_control_prbs_tx_invert_data_get(unit, port, value);
   9705         break;
   9706     case SOC_PHY_CONTROL_PRBS_TX_ENABLE:
   9707         /*passthru*/
   9708     case SOC_PHY_CONTROL_PRBS_RX_ENABLE:
   9709         rv = _phy_wc40_control_prbs_enable_get(unit, port, value);
   9710         break;
   9711     case SOC_PHY_CONTROL_PRBS_RX_STATUS:
   9712         rv = _phy_wc40_control_prbs_rx_status_get(unit, port, value);
   9713         break;
   9714     case SOC_PHY_CONTROL_LOOPBACK_REMOTE:
   9715         rv = _phy_wc40_rloop_get(unit,pc,value);
   9716         break;
   9717     case SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION:
   9718         rv = _phy_wc40_fec_get(unit,pc,value);
   9719         break;
   9720     case SOC_PHY_CONTROL_CUSTOM1:
   9721         *value = DEV_CFG_PTR(pc)->custom1;
   9722         rv = SOC_E_NONE;
   9723         break;
   9724     case SOC_PHY_CONTROL_SCRAMBLER:
   9725         if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   9726             rv = _phy_wc40_combo_speed_get(unit, port, &speed,&intf,&scr);
   9727         } else {
   9728             rv = _phy_wc40_ind_speed_get(unit, port, &speed,&intf,&scr);
   9729         }
   9730         *value = scr;
   9731         break;
   9732     case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT:
   9733         rv = _phy_wc40_control_linkdown_transmit_get(unit, port, value);
   9734         break;
   9735     case SOC_PHY_CONTROL_PARALLEL_DETECTION:
   9736         SOC_IF_ERROR_RETURN
   9737             (READ_WC40_SERDESDIGITAL_CONTROL1000X2r(unit, pc, 0, &data16));
   9738         *value = data16 & SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK?
   9739                  TRUE: FALSE;
   9740         rv = SOC_E_NONE;
   9741         break;
   9742     case SOC_PHY_CONTROL_BERT_TX_PACKETS:
   9743         /*passthru*/
   9744     case SOC_PHY_CONTROL_BERT_RX_PACKETS:
   9745         /*passthru*/
   9746     case SOC_PHY_CONTROL_BERT_RX_ERROR_BITS:
   9747         /*passthru*/
   9748     case SOC_PHY_CONTROL_BERT_RX_ERROR_BYTES:
   9749         /*passthru*/
   9750     case SOC_PHY_CONTROL_BERT_RX_ERROR_PACKETS:
   9751         /*passthru*/
   9752     case SOC_PHY_CONTROL_BERT_PATTERN:
   9753         /*passthru*/
   9754     case SOC_PHY_CONTROL_BERT_PACKET_SIZE:
   9755         /*passthru*/
   9756     case SOC_PHY_CONTROL_BERT_IPG:
   9757         rv = _phy_wc40_control_bert_get(unit,pc,type,value);
   9758         break;
   9759     case SOC_PHY_CONTROL_TX_PPM_ADJUST:
   9760         SOC_IF_ERROR_RETURN(
   9761                     (READ_WC40_XGXSBLK8_TX_PI_CONTROL3r(unit, pc, 0x00, &data16)));
   9762         *value = data16;
   9763         rv = SOC_E_NONE;
   9764         break;
   9765     case SOC_PHY_CONTROL_RX_PEAK_FILTER_TEMP_COMP:
   9766         SOC_IF_ERROR_RETURN
   9767             (READ_WC40_UC_INFO_B1_FIRMWARE_MODEr(unit,pc,
   9768                                                  LANE0_ACCESS,&data16));
   9769         if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
   9770             *value = (data16 == WC40_UC_CTRL_OPT_PF_TEMP_COMP);
   9771         } else {
   9772             data16 = (data16 & (0xf << 4*pc->lane_num)) >> (4*pc->lane_num);
   9773             *value = (data16 == WC40_UC_CTRL_OPT_PF_TEMP_COMP_PER_LANE);
   9774         }
   9775         rv = SOC_E_NONE;
   9776         break;
   9777     case SOC_PHY_CONTROL_SOFTWARE_RX_LOS:
   9778         *value = DEV_CFG_PTR(pc)->sw_rx_los.enable;
   9779         rv = SOC_E_NONE;
   9780         break;
   9781     case SOC_PHY_CONTROL_CL73_FSM_AUTO_RECOVER:
   9782         *value = DEV_CFG_PTR(pc)->cl73_fsm_auto_recover.enable;
   9783         rv = SOC_E_NONE;
   9784         break;
   9785     case SOC_PHY_CONTROL_FIRMWARE_MODE:
   9786         rv = _phy_wc40_firmware_mode_get(unit, port, value);
   9787         break;       
   9788     case SOC_PHY_CONTROL_DFE:
   9789         rv = _phy_wc40_firmware_dfe_mode_get(unit, port, value);
   9790         break;       
   9791     case SOC_PHY_CONTROL_VCO_FREQ:
   9792       rv = _phy_wc40_control_vco_freq_get(unit, port, value);
   9793         break;       
   9794     case SOC_PHY_CONTROL_VCO_DISTURBED:
   9795       rv = _phy_wc40_control_vco_disturbed_get(unit, port, value);
   9796         break;
   9797     case SOC_PHY_CONTROL_AUTONEG_MODE:
   9798         rv = SOC_E_NONE;   
   9799         cl37 = 0;
   9800         cl73 = 0; 
   9801         switch(DEV_CFG_PTR(pc)->cl37an) {
   9802             case WC40_CL37_WO_CL37BAM:
   9803                 cl37 = SOC_PHY_CONTROL_AUTONEG_MODE_CL37;
   9804                 break;
   9805             case WC40_CL37_AND_CL37BAM:
   9806                 cl37 = SOC_PHY_CONTROL_AUTONEG_MODE_CL37_BAM;
   9807                 break;
   9808             default: 
   9809                 break;    
   9810         }
   9811         switch(DEV_CFG_PTR(pc)->cl73an) {
   9812             case WC40_CL73_WO_CL73BAM:
   9813                 cl73 = SOC_PHY_CONTROL_AUTONEG_MODE_CL73;
   9814                 break;
   9815             case WC40_CL73_AND_CL73BAM:
   9816                 cl73 = SOC_PHY_CONTROL_AUTONEG_MODE_CL73_BAM;
   9817                 break;
   9818             default: 
   9819                 break;    
   9820         }
   9821 
   9822         if(cl37 && cl73) {
   9823             if((cl37 == SOC_PHY_CONTROL_AUTONEG_MODE_CL37)
   9824                && (cl73 == SOC_PHY_CONTROL_AUTONEG_MODE_CL73)) {
   9825                 return *value = SOC_PHY_CONTROL_AUTONEG_MODE_CL37_CL73;
   9826             }     
   9827             if((cl37 == SOC_PHY_CONTROL_AUTONEG_MODE_CL37)
   9828                && (cl73 == SOC_PHY_CONTROL_AUTONEG_MODE_CL73_BAM)) {
   9829                 return *value = SOC_PHY_CONTROL_AUTONEG_MODE_CL37_CL73_BAM;
   9830             }     
   9831             if((cl37 == SOC_PHY_CONTROL_AUTONEG_MODE_CL37_BAM)
   9832                && (cl73 == SOC_PHY_CONTROL_AUTONEG_MODE_CL73)) {
   9833                 return *value = SOC_PHY_CONTROL_AUTONEG_MODE_CL37_BAM_CL73;
   9834             }     
   9835             if((cl37 == SOC_PHY_CONTROL_AUTONEG_MODE_CL37_BAM)
   9836                && (cl73 == SOC_PHY_CONTROL_AUTONEG_MODE_CL73_BAM)) {
   9837                 return *value = SOC_PHY_CONTROL_AUTONEG_MODE_CL37_BAM_CL73_BAM;
   9838             }     
   9839         }
   9840         *value = cl37 ?  cl37 : cl73;
   9841         break;        
   9842     
   9843     default:
   9844         rv = SOC_E_UNAVAIL;
   9845         break; 
   9846     }
   9847     return rv;
   9848 }     
   9849 
   9850 typedef struct {
   9851     uint16 start;
   9852     uint16 end;
   9853 } WC40_LANE0_REG_BLOCK;
   9854 
   9855 STATIC WC40_LANE0_REG_BLOCK wc40_lane0_reg_block[] = {
   9856     {0x8050,0x80FE},  /* register in this block only valid at lane0 */
   9857     {0x8000,0x8001},  /* valid at lane0 */
   9858     {0x8015,0x8019}  /* valid at lane0 */
   9859 };
   9860 
   9861 STATIC int
   9862 _wc40_lane0_reg_access(int unit, phy_ctrl_t *pc,uint16 reg_addr)
   9863 {
   9864     int ix = 0;
   9865     int num_blk;
   9866     WC40_LANE0_REG_BLOCK * pBlk;
   9867 
   9868     num_blk = sizeof(wc40_lane0_reg_block)/sizeof(wc40_lane0_reg_block[0]);
   9869     for (ix = 0; ix < num_blk; ix++) {
   9870         pBlk = &wc40_lane0_reg_block[ix];
   9871         if ((reg_addr >= pBlk->start) && (reg_addr <= pBlk->end)) {
   9872             return TRUE;
   9873         }
   9874     }
   9875     return FALSE;
   9876 }
   9877 
   9878 STATIC int
   9879 phy_wc40_reg_aer_read(int unit, phy_ctrl_t *pc, uint32 flags,
   9880                   uint32 phy_reg_addr, uint16 *phy_data)
   9881 {
   9882     uint16 data;     
   9883     uint32 lane;         /* lane to access, override the default lane */
   9884 
   9885     lane = flags & LANE_ACCESS_MASK;
   9886 
   9887     /* safety check */
   9888     if ((lane > 4) || (lane == LANE_BCST)) {
   9889         lane = LANE0_ACCESS;
   9890     }
   9891 
   9892     /* check if register only available on lane0 */
   9893     if (_wc40_lane0_reg_access(unit,pc,(uint16)(phy_reg_addr & 0xffff))) {
   9894         lane = LANE0_ACCESS;
   9895     }
   9896 
   9897     /* default lane override
   9898      * register access is done in AER mode
   9899      */
   9900     if (lane) { 
   9901         /* set the base address in multi mdio address mode */
   9902         if (!(pc->flags & PHYCTRL_MDIO_ADDR_SHARE)) {
   9903             pc->phy_id -= pc->lane_num;
   9904         }
   9905         phy_reg_addr |= ((lane - 1) << 16);
   9906         
   9907     } else { /* default lane access */ 
   9908         if (pc->flags & PHYCTRL_MDIO_ADDR_SHARE) {
   9909             phy_reg_addr |= (pc->lane_num << 16);
   9910         }
   9911     }
   9912 
   9913     /* don't set the lane number if it is access to AER ifself */
   9914     if ((phy_reg_addr & 0xffff) == PHY_AER_REG) {
   9915         phy_reg_addr &= 0xffff;
   9916     }
   9917 
   9918     SOC_IF_ERROR_RETURN
   9919         (phy_reg_aer_read(unit, pc,  phy_reg_addr, &data));
   9920 
   9921     /* restore the mdio address for current lane in multi mdio address mode */
   9922     if (lane) {
   9923         if (!(pc->flags & PHYCTRL_MDIO_ADDR_SHARE)) {
   9924             pc->phy_id += pc->lane_num;
   9925         }
   9926     }
   9927     *phy_data = data;
   9928 
   9929     return SOC_E_NONE;
   9930 }
   9931 
   9932 STATIC int
   9933 phy_wc40_reg_aer_write(int unit, phy_ctrl_t *pc, uint32 flags,
   9934                    uint32 phy_reg_addr, uint16 phy_data)
   9935 {
   9936     uint16               data;     
   9937     int dxgxs;
   9938     uint32 lane;
   9939 
   9940     dxgxs = DEV_CFG_PTR(pc)->dxgxs;
   9941     data  = (uint16) (phy_data & 0x0000FFFF);
   9942 
   9943     lane = flags & LANE_ACCESS_MASK;
   9944 
   9945     /* safety check */
   9946     if ((lane > 4) && (lane != LANE_BCST)) {
   9947         lane = LANE0_ACCESS;
   9948     }
   9949 
   9950     /* check if register only available on lane0 or should be done from lane0 */
   9951     if ((_wc40_lane0_reg_access(unit,pc,(uint16)(phy_reg_addr & 0xffff))) || dxgxs) {
   9952         lane = LANE0_ACCESS;
   9953     }
   9954 
   9955     /* default lane override
   9956      * register access is done in AER mode
   9957      */
   9958     if (lane) {
   9959         /* set AER to broadcast two lanes, dxgxs=1 1st dxgxs, dxgxs=2 2nd  */
   9960         if (dxgxs) {
   9961             phy_reg_addr |= (WC_AER_BCST_OFS_STRAP + dxgxs) << 16;
   9962         } else {
   9963             if (lane == LANE_BCST) {
   9964                 phy_reg_addr |= (WC_AER_BCST_OFS_STRAP << 16);
   9965             } else {
   9966                 phy_reg_addr |= ((lane - 1) << 16);
   9967             }
   9968         }
   9969         if (!(pc->flags & PHYCTRL_MDIO_ADDR_SHARE)) {
   9970             pc->phy_id -= pc->lane_num;
   9971         }
   9972     } else {
   9973         if (pc->flags & PHYCTRL_MDIO_ADDR_SHARE) {
   9974             phy_reg_addr |= (pc->lane_num << 16);
   9975         }
   9976     }
   9977 
   9978     /* don't set the lane number if it is access to AER ifself */
   9979     if ((phy_reg_addr & 0xffff) == PHY_AER_REG) {
   9980         phy_reg_addr &= 0xffff;
   9981     }
   9982 
   9983     SOC_IF_ERROR_RETURN
   9984         (phy_reg_aer_write(unit, pc,  phy_reg_addr, data));
   9985 
   9986     /* restore the mdio address for current lane in multi mdio address mode */
   9987     if (lane) {
   9988         if (!(pc->flags & PHYCTRL_MDIO_ADDR_SHARE)) {
   9989             pc->phy_id += pc->lane_num;
   9990         }
   9991     }
   9992 
   9993     return SOC_E_NONE;
   9994 }
   9995 
   9996 STATIC int
   9997 phy_wc40_reg_aer_modify(int unit, phy_ctrl_t *pc, uint32 flags,
   9998                     uint32 phy_reg_addr, uint16 phy_data,
   9999                     uint16 phy_data_mask)
  10000 {
  10001     uint16               data;     /* Temporary holder for phy_data */
  10002     uint16               mask;
  10003     uint16  tmp;
  10004 
  10005     data      = (uint16) (phy_data & 0x0000FFFF);
  10006     mask      = (uint16) (phy_data_mask & 0x0000FFFF);
  10007 
  10008     SOC_IF_ERROR_RETURN
  10009         (phy_wc40_reg_aer_read(unit, pc,  flags, phy_reg_addr, &tmp));
  10010 
  10011     data &= mask;
  10012     tmp &= ~(mask);
  10013     tmp |= data;
  10014 
  10015     SOC_IF_ERROR_RETURN
  10016         (phy_wc40_reg_aer_write(unit, pc,  flags, phy_reg_addr, tmp));
  10017 
  10018     return SOC_E_NONE;
  10019 }
  10020 
  10021 /*
  10022  * Function:
  10023  *      phy_wc40_reg_read
  10024  * Purpose:
  10025  *      Routine to read PHY register
  10026  * Parameters:
  10027  *      uint         - BCM unit number
  10028  *      pc           - PHY state
  10029  *      flags        - Flags which specify the register type
  10030  *      phy_reg_addr - Encoded register address
  10031  *      phy_data     - (OUT) Value read from PHY register
  10032  * Note:
  10033  *      This register read function is not thread safe. Higher level
  10034  * function that calls this function must obtain a per port lock
  10035  * to avoid overriding register page mapping between threads.
  10036  */
  10037 STATIC int
  10038 phy_wc40_reg_read(int unit, soc_port_t port, uint32 flags,
  10039                   uint32 phy_reg_addr, uint32 *phy_data)
  10040 {
  10041     uint16               data;     /* Temporary holder for phy_data */
  10042     phy_ctrl_t          *pc;      /* PHY software state */
  10043 
  10044     pc = INT_PHY_SW_STATE(unit, port);
  10045 
  10046     SOC_IF_ERROR_RETURN
  10047         (phy_wc40_reg_aer_read(unit, pc, 0x00, phy_reg_addr, &data));
  10048 
  10049     *phy_data = data;
  10050 
  10051     return SOC_E_NONE;
  10052 }
  10053 
  10054 /*
  10055  * Function:
  10056  *      phy_wc40_reg_write
  10057  * Purpose:
  10058  *      Routine to write PHY register
  10059  * Parameters:
  10060  *      uint         - BCM unit number
  10061  *      pc           - PHY state
  10062  *      flags        - Flags which specify the register type
  10063  *      phy_reg_addr - Encoded register address
  10064  *      phy_data     - Value write to PHY register
  10065  * Note:
  10066  *      This register read function is not thread safe. Higher level
  10067  * function that calls this function must obtain a per port lock
  10068  * to avoid overriding register page mapping between threads.
  10069  */
  10070 STATIC int
  10071 phy_wc40_reg_write(int unit, soc_port_t port, uint32 flags,
  10072                    uint32 phy_reg_addr, uint32 phy_data)
  10073 {
  10074     uint16               data;     /* Temporary holder for phy_data */
  10075     phy_ctrl_t          *pc;      /* PHY software state */
  10076 
  10077     pc = INT_PHY_SW_STATE(unit, port);
  10078 
  10079     data      = (uint16) (phy_data & 0x0000FFFF);
  10080 
  10081     SOC_IF_ERROR_RETURN
  10082         (phy_wc40_reg_aer_write(unit, pc, 0x00, phy_reg_addr, data));
  10083 
  10084     return SOC_E_NONE;
  10085 }  
  10086 
  10087 /*
  10088  * Function:
  10089  *      phy_wc40_reg_modify
  10090  * Purpose:
  10091  *      Routine to write PHY register
  10092  * Parameters:
  10093  *      uint         - BCM unit number
  10094  *      pc           - PHY state
  10095  *      flags        - Flags which specify the register type
  10096  *      phy_reg_addr - Encoded register address
  10097  *      phy_mo_data  - New value for the bits specified in phy_mo_mask
  10098  *      phy_mo_mask  - Bit mask to modify
  10099  * Note:
  10100  *      This register read function is not thread safe. Higher level
  10101  * function that calls this function must obtain a per port lock
  10102  * to avoid overriding register page mapping between threads.
  10103  */
  10104 STATIC int
  10105 phy_wc40_reg_modify(int unit, soc_port_t port, uint32 flags,
  10106                     uint32 phy_reg_addr, uint32 phy_data,
  10107                     uint32 phy_data_mask)
  10108 {
  10109     uint16               data;     /* Temporary holder for phy_data */
  10110     uint16               mask;
  10111     phy_ctrl_t    *pc;      /* PHY software state */
  10112 
  10113     pc = INT_PHY_SW_STATE(unit, port);
  10114 
  10115     data      = (uint16) (phy_data & 0x0000FFFF);
  10116     mask      = (uint16) (phy_data_mask & 0x0000FFFF);
  10117 
  10118     SOC_IF_ERROR_RETURN
  10119         (phy_wc40_reg_aer_modify(unit, pc, 0x00, phy_reg_addr, data, mask));
  10120 
  10121     return SOC_E_NONE;
  10122 }
  10123 
  10124 STATIC int
  10125 phy_wc40_probe(int unit, phy_ctrl_t *pc)
  10126 {
  10127     uint16      serdes_id0;
  10128 
  10129     SOC_IF_ERROR_RETURN
  10130         (READ_WC40_SERDESID_SERDESID0r(unit, pc, 0x00, &serdes_id0));
  10131 
  10132     if ((serdes_id0 & SERDESID_SERDESID0_MODEL_NUMBER_MASK) !=
  10133              SERDES_ID0_MODEL_NUMBER_WARPCORE) {
  10134         return SOC_E_NOT_FOUND;
  10135     }
  10136 
  10137     /* ask to allocate the driver specific descripor  */
  10138     pc->size = sizeof(WC40_DEV_DESC_t);
  10139     pc->dev_name = wc_device_name;
  10140     return SOC_E_NONE;
  10141 }
  10142 
  10143 STATIC int
  10144 phy_wc40_notify(int unit, soc_port_t port,
  10145                        soc_phy_event_t event, uint32 value)
  10146 {
  10147     int             rv;
  10148     phy_ctrl_t    *pc;      /* PHY software state */
  10149 
  10150     pc = INT_PHY_SW_STATE(unit, port);
  10151 
  10152     if (event >= phyEventCount) {
  10153         return SOC_E_PARAM;
  10154     }
  10155 
  10156     if (CUSTOM_MODE(pc)) {
  10157         return SOC_E_NONE;
  10158     }
  10159 
  10160     switch(event) {
  10161     case phyEventSpeed:
  10162     case phyEventStop:
  10163     case phyEventResume:
  10164     case phyEventAutoneg:
  10165     case phyEventInterface:
  10166         if (DEV_CFG_PTR(pc)->phy_passthru) {
  10167             return SOC_E_NONE;
  10168         }
  10169         break;
  10170     default:
  10171         break;
  10172     }
  10173 
  10174     rv = SOC_E_NONE;
  10175     switch(event) {
  10176     case phyEventInterface:
  10177         rv = (_phy_wc40_notify_interface(unit, port, value));
  10178         break;
  10179     case phyEventDuplex:
  10180         rv = (_phy_wc40_notify_duplex(unit, port, value));
  10181         break;
  10182     case phyEventSpeed:
  10183         rv = (_phy_wc40_notify_speed(unit, port, value));
  10184         break;
  10185     case phyEventStop:
  10186         rv = (_phy_wc40_notify_stop(unit, port, value));
  10187         break;
  10188     case phyEventResume:
  10189         rv = (_phy_wc40_notify_resume(unit, port, value));
  10190         break;
  10191     case phyEventAutoneg:
  10192         rv = (phy_wc40_an_set(unit, port, value));
  10193         break;
  10194     case phyEventTxFifoReset:
  10195         rv = (_phy_wc40_tx_fifo_reset(unit, port, value));
  10196         break;
  10197     case phyEventMacLoopback:
  10198         rv = (_phy_wc40_notify_mac_loopback(unit, port, value));
  10199         break;
  10200     default:
  10201         rv = SOC_E_UNAVAIL;
  10202         break;
  10203     }
  10204 
  10205     return rv;
  10206 }
  10207 
  10208 STATIC int
  10209 phy_wc40_linkup_evt (int unit, soc_port_t port)
  10210 {
  10211     phy_ctrl_t  *pc;
  10212 
  10213     pc = INT_PHY_SW_STATE(unit, port);
  10214     LOG_INFO(BSL_LS_SOC_PHY,
  10215              (BSL_META_U(unit,
  10216                          "phy_wc40_linkup_evt: "
  10217                          "u=%d p=%d\n"), unit, port));
  10218 
  10219     /* restore mld local fault configuration */
  10220     if (WC40_CL73_SOFT_KR2(pc)) {
  10221         if (WC40_AN_VALID(pc)) {
  10222             if (WC40_AN_CHECK_TIMEOUT(pc)) {
  10223                 SOC_IF_ERROR_RETURN
  10224                     (WC40_REG_MODIFY(unit, pc, 0x00, 0x842A,0,(1 << 5)));
  10225                 WC40_AN_VALID_RESET(pc);
  10226             }
  10227         }
  10228     }
  10229 
  10230     /* TX fifo recenter workaround in aggregated mode */
  10231     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode) || IS_DUAL_LANE_PORT(pc)) {
  10232         if (WC40_REVID_A0(pc) || WC40_REVID_A1(pc)) {
  10233             SOC_IF_ERROR_RETURN
  10234                 (MODIFY_WC40_TXBERT_TXBERTCTRLr(unit,pc,0x00,
  10235                        TXBERT_TXBERTCTRL_FIFO_RST_MASK,
  10236                        TXBERT_TXBERTCTRL_FIFO_RST_MASK));
  10237             SOC_IF_ERROR_RETURN
  10238                 (MODIFY_WC40_TXBERT_TXBERTCTRLr(unit,pc,0x00,
  10239                        0,
  10240                        TXBERT_TXBERTCTRL_FIFO_RST_MASK));
  10241         }
  10242     }
  10243     return SOC_E_NONE;
  10244 }
  10245 
  10246 /*
  10247  * Function:
  10248  *      phy_wc40_duplex_set
  10249  * Purpose:
  10250  *      Set the current duplex mode (forced).
  10251  * Parameters:
  10252  *      unit - StrataSwitch unit #.
  10253  *      port - StrataSwitch port #.
  10254  *      duplex - Boolean, true indicates full duplex, false indicates half.
  10255  * Returns:
  10256  *      SOC_E_XXX
  10257  */
  10258 
  10259 STATIC int
  10260 phy_wc40_duplex_set(int unit, soc_port_t port, int duplex)
  10261 {
  10262     uint16       data16;
  10263     phy_ctrl_t  *pc;
  10264     int duplex_value;
  10265 
  10266     pc = INT_PHY_SW_STATE(unit, port);
  10267     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode) ||
  10268         CUSTOMX_MODE(pc)) {
  10269         return SOC_E_NONE;
  10270     }
  10271 
  10272     SOC_IF_ERROR_RETURN
  10273         (READ_WC40_SERDESDIGITAL_STATUS1000X1r(unit, pc, 0x00, &data16));
  10274 
  10275     if (!(data16 & SERDESDIGITAL_STATUS1000X1_SGMII_MODE_MASK)) {
  10276 
  10277         /* 1000X fiber mode, 100fx  */
  10278             
  10279         duplex_value = duplex? FX100_CONTROL1_FULL_DUPLEX_MASK:0;
  10280         SOC_IF_ERROR_RETURN
  10281             (MODIFY_WC40_FX100_CONTROL1r(unit,pc,0x00,
  10282                    duplex_value,
  10283                    FX100_CONTROL1_FULL_DUPLEX_MASK));
  10284         
  10285         /* 1000X should always be full duplex */
  10286         duplex = TRUE;
  10287     }
  10288 
  10289     data16 = duplex? MII_CTRL_FD: 0;
  10290 
  10291     /* program the duplex setting */
  10292     SOC_IF_ERROR_RETURN
  10293         (MODIFY_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, data16,MII_CTRL_FD));
  10294 
  10295     return SOC_E_NONE;
  10296 }
  10297 
  10298 STATIC int
  10299 phy_wc40_duplex_get(int unit, soc_port_t port, int *duplex)
  10300 {
  10301     uint16       reg0_16;
  10302     uint16       mii_ctrl;
  10303     phy_ctrl_t  *pc;
  10304 
  10305     pc = INT_PHY_SW_STATE(unit, port);
  10306 
  10307     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode) ||
  10308         CUSTOMX_MODE(pc)) {
  10309         *duplex = TRUE;
  10310         return SOC_E_NONE;
  10311     }
  10312 
  10313     SOC_IF_ERROR_RETURN
  10314         (READ_WC40_SERDESDIGITAL_STATUS1000X1r(unit, pc, 0x00, &reg0_16));
  10315 
  10316     /* default to fiber mode duplex */
  10317     *duplex = (reg0_16 & SERDESDIGITAL_STATUS1000X1_DUPLEX_STATUS_MASK)?
  10318               TRUE:FALSE;
  10319 
  10320     if (reg0_16 & SERDESDIGITAL_STATUS1000X1_SGMII_MODE_MASK) {
  10321 
  10322     /* retrieve the duplex setting in SGMII mode */
  10323         SOC_IF_ERROR_RETURN
  10324             (READ_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, &mii_ctrl));
  10325 
  10326         if (mii_ctrl & MII_CTRL_AE) {
  10327             SOC_IF_ERROR_RETURN
  10328                 (READ_WC40_COMBO_IEEE0_AUTONEGLPABILr(unit,pc,0x00,&reg0_16));
  10329 
  10330             /* make sure link partner is also in SGMII mode
  10331              * otherwise fall through to use the FD bit in MII_CTRL reg
  10332              */
  10333             if (reg0_16 & MII_ANP_SGMII_MODE) {
  10334                 if (reg0_16 & MII_ANP_SGMII_FD) {
  10335                     *duplex = TRUE;
  10336                 } else {
  10337                     *duplex = FALSE;
  10338                 }
  10339                 return SOC_E_NONE;
  10340             }
  10341         }
  10342         *duplex = (mii_ctrl & MII_CTRL_FD) ? TRUE : FALSE;
  10343     } 
  10344 
  10345     return SOC_E_NONE;
  10346 }
  10347 
  10348 /*
  10349  * Function:
  10350  *      phy_wc40_firmware_set
  10351  * Purpose:
  10352  *      write the given firmware to the uController's RAM 
  10353  * Parameters:
  10354  *      unit - StrataSwitch unit #.
  10355  *      port - StrataSwitch port #.
  10356  *      offset - offset to the data stream
  10357  *      array  - the given data
  10358  *      datalen- the data length
  10359  * Returns:
  10360  *      SOC_E_NONE
  10361  */
  10362 
  10363 STATIC int
  10364 phy_wc40_firmware_set(int unit, int port, int offset, uint8 *array,int datalen)
  10365 {
  10366     return SOC_E_FAIL;
  10367 }
  10368 
  10369 STATIC int
  10370 phy_wc40_firmware_load(int unit, int port, int offset, uint8 *array,int datalen)
  10371 {
  10372     phy_ctrl_t  *pc;
  10373     int rv;
  10374     int i;
  10375     int len;
  10376     uint16 data16;
  10377     uint16 mask16;
  10378     uint16 ver;
  10379     uint16 cksum = 0;
  10380     int no_cksum;
  10381 
  10382     pc = INT_PHY_SW_STATE(unit, port);
  10383     no_cksum = !(DEV_CFG_PTR(pc)->uc_cksum);
  10384 
  10385     rv = SOC_E_NONE;
  10386 
  10387     /* initialize the RAM */
  10388     SOC_IF_ERROR_RETURN
  10389         (WRITE_WC40_MICROBLK_COMMANDr(unit, pc, 0x00,
  10390                                       MICROBLK_COMMAND_INIT_CMD_MASK));
  10391 
  10392    /* wait for init done */
  10393     rv = _phy_wc40_regbit_set_wait_check(pc,WC40_MICROBLK_DOWNLOAD_STATUSr,
  10394                      MICROBLK_DOWNLOAD_STATUS_INIT_DONE_MASK,1,2000000,0);
  10395 
  10396     if (rv == SOC_E_TIMEOUT) {
  10397         LOG_WARN(BSL_LS_SOC_PHY,
  10398                  (BSL_META_U(unit,
  10399                              "WC40 : uC init fails: u=%d p=%d\n"),
  10400                   unit, port));
  10401         return (SOC_E_TIMEOUT);
  10402     }
  10403 
  10404     /* enable uC timers */
  10405     SOC_IF_ERROR_RETURN
  10406         (MODIFY_WC40_MICROBLK_COMMAND2r(unit,pc,0x00,MICROBLK_COMMAND2_TMR_EN_MASK,
  10407                     MICROBLK_COMMAND2_TMR_EN_MASK));
  10408 
  10409    /* starting RAM location */
  10410     SOC_IF_ERROR_RETURN
  10411         (WRITE_WC40_MICROBLK_ADDRESSr(unit, pc, 0x00, offset));
  10412 
  10413     if ((_phy_wc40_firmware_set_helper[unit] != NULL) && (DEV_CFG_PTR(pc)->load_mthd == 2)) {
  10414 
  10415         /* transfer size, 16bytes quantity*/
  10416         if (datalen%16) {
  10417             len = (((datalen/16)+1) * 16) -1;
  10418         } else {
  10419             len = datalen -1;
  10420         }
  10421         SOC_IF_ERROR_RETURN
  10422             (WRITE_WC40_MICROBLK_RAMWORDr(unit, pc, 0x00, len));
  10423 
  10424         /* allow external access from Warpcore */
  10425         SOC_IF_ERROR_RETURN
  10426             (MODIFY_WC40_MICROBLK_COMMAND3r(unit, pc, 0x00,
  10427                             MICROBLK_COMMAND3_EXT_MEM_ENABLE_MASK,
  10428                             MICROBLK_COMMAND3_EXT_MEM_ENABLE_MASK));
  10429         WC40_UDELAY(1000);
  10430         SOC_IF_ERROR_RETURN
  10431             (MODIFY_WC40_MICROBLK_COMMAND3r(unit, pc, 0x00,
  10432                             MICROBLK_COMMAND3_EXT_CLK_ENABLE_MASK,
  10433                             MICROBLK_COMMAND3_EXT_CLK_ENABLE_MASK));
  10434         WC40_UDELAY(1000);
  10435 
  10436         _phy_wc40_firmware_set_helper[unit](unit,port,array,datalen);
  10437 
  10438         /* restore back no external access from Warpcore */
  10439         SOC_IF_ERROR_RETURN
  10440             (MODIFY_WC40_MICROBLK_COMMAND3r(unit, pc, 0x00, 0,
  10441                             MICROBLK_COMMAND3_EXT_MEM_ENABLE_MASK));
  10442         WC40_UDELAY(1000);
  10443         SOC_IF_ERROR_RETURN
  10444             (MODIFY_WC40_MICROBLK_COMMAND3r(unit, pc, 0x00, 0,
  10445                             MICROBLK_COMMAND3_EXT_CLK_ENABLE_MASK));
  10446         WC40_UDELAY(1000);
  10447 
  10448     } else {
  10449         /* transfer size */
  10450         SOC_IF_ERROR_RETURN
  10451             (WRITE_WC40_MICROBLK_RAMWORDr(unit, pc, 0x00, datalen - 1));
  10452 
  10453         /* start write operation */
  10454         SOC_IF_ERROR_RETURN
  10455             (WRITE_WC40_MICROBLK_COMMANDr(unit, pc, 0x00,
  10456                  MICROBLK_COMMAND_WRITE_MASK | MICROBLK_COMMAND_RUN_MASK));
  10457 
  10458 
  10459         /* write 16-bit word to data register */
  10460         for (i = 0; i < datalen/2; i++) {
  10461             data16 = array[2*i] | (array[2*i+1] << 8);
  10462             SOC_IF_ERROR_RETURN
  10463                 (WRITE_WC40_MICROBLK_WRDATAr(unit, pc, 0x00, data16));
  10464         }
  10465 
  10466         /* check if the firmware size is odd number */
  10467         if (datalen%2) {
  10468             data16 = array[datalen-1];
  10469             SOC_IF_ERROR_RETURN
  10470                 (WRITE_WC40_MICROBLK_WRDATAr(unit, pc, 0x00, data16));
  10471         }
  10472         /* complete the writing */
  10473         SOC_IF_ERROR_RETURN
  10474             (WRITE_WC40_MICROBLK_COMMANDr(unit, pc, 0x00, MICROBLK_COMMAND_STOP_MASK));
  10475     }
  10476 
  10477     SOC_IF_ERROR_RETURN
  10478             (READ_WC40_MICROBLK_DOWNLOAD_STATUSr(unit, pc, 0x00, &data16));
  10479 
  10480     mask16 = MICROBLK_DOWNLOAD_STATUS_ERR0_MASK | MICROBLK_DOWNLOAD_STATUS_ERR1_MASK;
  10481 
  10482     if (data16 & mask16) {
  10483         LOG_WARN(BSL_LS_SOC_PHY,
  10484                  (BSL_META_U(unit,
  10485                              "WC40 : uC RAM download fails: u=%d p=%d\n"),
  10486                   unit, port));
  10487         return (SOC_E_FAIL);
  10488     }
  10489 
  10490     /* write a non-zero value to this register to signal uC not perform cksum calculation */
  10491     if (no_cksum) {
  10492         SOC_IF_ERROR_RETURN
  10493             (WRITE_WC40_UC_INFO_B1_CRCr(unit, pc, 0x00, 0x1234));
  10494     }
  10495 
  10496     /* release uC's reset */
  10497     SOC_IF_ERROR_RETURN
  10498         (WRITE_WC40_MICROBLK_COMMANDr(unit, pc, 0x00,
  10499                             MICROBLK_COMMAND_MDIO_UC_RESET_N_MASK));
  10500 
  10501     /* wait for checksum to be written to this register by uC */
  10502 
  10503     if (!no_cksum) {
  10504         rv = _phy_wc40_regbit_set_wait_check(pc,0x81fe,0xffff,1,100000,0);
  10505         if (rv == SOC_E_TIMEOUT) {
  10506             LOG_WARN(BSL_LS_SOC_PHY,
  10507                      (BSL_META_U(unit,
  10508                                  "WC40 : uC download: u=%d p=%d timeout: wait for checksum\n"),
  10509                       unit, port));
  10510         } else {
  10511            SOC_IF_ERROR_RETURN
  10512             (READ_WC40_UC_INFO_B1_CRCr(unit, pc, 0x00, &cksum));
  10513         } 
  10514     } 
  10515 
  10516     SOC_IF_ERROR_RETURN
  10517         (READ_WC40_UC_INFO_B1_VERSIONr(unit, pc, 0x00, &ver));
  10518 
  10519     LOG_VERBOSE(BSL_LS_SOC_PHY,
  10520                 (BSL_META_U(unit,
  10521                             "WC40 : uC RAM download success: u=%d p=%d ver=%x"), unit, port,ver));
  10522 
  10523     if (!no_cksum) {
  10524         LOG_VERBOSE(BSL_LS_SOC_PHY,
  10525                     (BSL_META_U(unit,
  10526                                 " cksum=0x%x\n"), cksum));
  10527     } else {
  10528         LOG_VERBOSE(BSL_LS_SOC_PHY,
  10529                     (BSL_META_U(unit,
  10530                                 "\n")));
  10531     }
  10532     return rv;
  10533 }
  10534 
  10535 /*
  10536  * Function:
  10537  *      phy_wc40_medium_config_set
  10538  * Purpose:
  10539  *      set the configured medium the device is operating on.
  10540  * Parameters:
  10541  *      unit - StrataSwitch unit #
  10542  *      port - Port number
  10543  *      medium - SOC_PORT_MEDIUM_COPPER/FIBER
  10544  *      cfg - not used
  10545  * Returns:
  10546  *      SOC_E_XXX
  10547  */
  10548 STATIC int
  10549 phy_wc40_medium_config_set(int unit, soc_port_t port,
  10550                            soc_port_medium_t  medium,
  10551                            soc_phy_config_t  *cfg)
  10552 {
  10553     phy_ctrl_t       *pc;
  10554     WC40_DEV_DESC_t  *pDesc;
  10555     WC40_DEV_CFG_t   *pCfg;
  10556     uint16           fiber_mode = 0;
  10557 
  10558     pc            = INT_PHY_SW_STATE(unit, port);
  10559     pDesc = (WC40_DEV_DESC_t *)(pc + 1);
  10560     pCfg = &pDesc->cfg;
  10561 
  10562     switch (medium) {
  10563     case SOC_PORT_MEDIUM_COPPER:
  10564         DEV_CFG_PTR(pc)->medium = SOC_PORT_MEDIUM_COPPER;
  10565         fiber_mode = 0;
  10566         break;
  10567     case SOC_PORT_MEDIUM_FIBER:
  10568         DEV_CFG_PTR(pc)->medium = SOC_PORT_MEDIUM_FIBER;
  10569         fiber_mode = SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK;
  10570         break;
  10571     default:
  10572         return SOC_E_PARAM;
  10573     }
  10574 
  10575     SOC_IF_ERROR_RETURN
  10576         (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X1r(unit, pc, 0x00, fiber_mode,
  10577                            SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK));
  10578     pCfg->fiber_pref = fiber_mode;
  10579 
  10580     return SOC_E_NONE;
  10581 }
  10582 /*
  10583  * Function:
  10584  *      phy_wc40_medium_get
  10585  * Purpose:
  10586  *      Indicate the configured medium
  10587  * Parameters:
  10588  *      unit - StrataSwitch unit #.
  10589  *      port - StrataSwitch port #.
  10590  *      medium - (OUT) One of:
  10591  *              SOC_PORT_MEDIUM_COPPER
  10592  *              SOC_PORT_MEDIUM_FIBER
  10593  * Returns:
  10594  *      SOC_E_NONE
  10595  */
  10596 STATIC int
  10597 phy_wc40_medium_get(int unit, soc_port_t port, soc_port_medium_t *medium)
  10598 {
  10599     phy_ctrl_t       *pc;
  10600 
  10601     if (medium == NULL) {
  10602         return SOC_E_PARAM;
  10603     }
  10604 
  10605     pc            = INT_PHY_SW_STATE(unit, port);
  10606     *medium = DEV_CFG_PTR(pc)->medium;
  10607     return SOC_E_NONE;
  10608 }
  10609 
  10610 /*
  10611  * Function:
  10612  *      phy_wc40_master_get
  10613  * Purpose:
  10614  *      this function is meant for 1000Base-T PHY. Added here to support
  10615  *      internal PHY regression test
  10616  * Parameters:
  10617  *      unit - StrataSwitch unit #.
  10618  *      port - StrataSwitch port #.
  10619  *      master - (OUT) SOC_PORT_MS_*
  10620  * Returns:
  10621  *      SOC_E_NONE
  10622  * Notes:
  10623  *      The master mode is retrieved for the ACTIVE medium.
  10624  */
  10625 
  10626 STATIC int
  10627 phy_wc40_master_get(int unit, soc_port_t port, int *master)
  10628 {
  10629     *master = SOC_PORT_MS_NONE;
  10630     return SOC_E_NONE;
  10631 }
  10632 
  10633 /*
  10634  * Function:
  10635  *      phy_wc40_diag_ctrl
  10636  * Purpose:
  10637  * Parameters:
  10638  *      unit - StrataSwitch unit #.
  10639  *      port - StrataSwitch port #.
  10640  * Returns:
  10641  *      SOC_E_NONE
  10642  * Notes:
  10643  */
  10644 
  10645 STATIC int
  10646 phy_wc40_diag_ctrl(
  10647    int unit, /* unit */
  10648    soc_port_t port, /* port */
  10649    uint32 inst, /* the specific device block the control action directs to */
  10650    int op_type,  /* operation types: read,write or command sequence */
  10651    int op_cmd,   /* command code */
  10652    void *arg)     /* command argument based on op_type/op_cmd */
  10653 {
  10654     int rv;
  10655 
  10656     rv = SOC_E_NONE;
  10657 
  10658     switch(op_cmd) {
  10659         case PHY_DIAG_CTRL_EYE_MARGIN_VEYE:
  10660             (void)wc40_eye_margin(unit,port,WC_UTIL_VEYE);
  10661         break;
  10662 
  10663         case PHY_DIAG_CTRL_EYE_MARGIN_HEYE_LEFT:
  10664             (void)wc40_eye_margin(unit,port,WC_UTIL_HEYE_L);
  10665         break;
  10666 
  10667         case PHY_DIAG_CTRL_EYE_MARGIN_HEYE_RIGHT:
  10668             (void)wc40_eye_margin(unit,port,WC_UTIL_HEYE_R);
  10669         break;
  10670 
  10671         case PHY_DIAG_CTRL_DSC:
  10672              LOG_INFO(BSL_LS_SOC_PHY,
  10673                       (BSL_META_U(unit,
  10674                                   "phy_wc40_diag_ctrl: "
  10675                                   "u=%d p=%d PHY_DIAG_CTRL_DSC 0x%x\n"),
  10676                        unit, port, PHY_DIAG_CTRL_DSC));
  10677             (void)wc40_uc_status_dump(unit, port);
  10678         break;
  10679 
  10680         default:
  10681             if (op_type == PHY_DIAG_CTRL_SET) {
  10682                 rv = phy_wc40_control_set(unit, port, op_cmd, PTR_TO_INT(arg));
  10683             } else if (op_type == PHY_DIAG_CTRL_GET) {
  10684                 rv = phy_wc40_control_get(unit, port, op_cmd, (uint32 *)arg);
  10685             }
  10686         break;
  10687     }
  10688     return rv;
  10689 }
  10690 
  10691 /*
  10692  * Variable:
  10693  *      phy_wc40_drv
  10694  * Purpose:
  10695  *      Phy Driver for 10G (XAUI x 4) Serdes PHY. 
  10696  */
  10697 phy_driver_t phy_wc40_hg = {
  10698     /* .drv_name                      = */ "Warpcore PHY Driver",
  10699     /* .pd_init                       = */ phy_wc40_init,
  10700     /* .pd_reset                      = */ phy_null_reset,
  10701     /* .pd_link_get                   = */ phy_wc40_link_get,
  10702     /* .pd_enable_set                 = */ phy_wc40_enable_set,
  10703     /* .pd_enable_get                 = */ phy_wc40_enable_get,
  10704     /* .pd_duplex_set                 = */ phy_wc40_duplex_set,
  10705     /* .pd_duplex_get                 = */ phy_wc40_duplex_get,
  10706     /* .pd_speed_set                  = */ phy_wc40_speed_set,
  10707     /* .pd_speed_get                  = */ phy_wc40_speed_get,
  10708     /* .pd_master_set                 = */ phy_null_set,
  10709     /* .pd_master_get                 = */ phy_wc40_master_get,
  10710     /* .pd_an_set                     = */ phy_wc40_an_set,
  10711     /* .pd_an_get                     = */ phy_wc40_an_get,
  10712     /* .pd_adv_local_set              = */ NULL, /* Deprecated */
  10713     /* .pd_adv_local_get              = */ NULL, /* Deprecated */
  10714     /* .pd_adv_remote_get             = */ NULL, /* Deprecated */
  10715     /* .pd_lb_set                     = */ phy_wc40_lb_set,
  10716     /* .pd_lb_get                     = */ phy_wc40_lb_get,
  10717     /* .pd_interface_set              = */ phy_wc40_interface_set,
  10718     /* .pd_interface_get              = */ phy_wc40_interface_get,
  10719     /* .pd_ability                    = */ NULL, /* Deprecated */
  10720     /* .pd_linkup_evt                 = */ phy_wc40_linkup_evt,
  10721     /* .pd_linkdn_evt                 = */ NULL,
  10722     /* .pd_mdix_set                   = */ phy_null_mdix_set,
  10723     /* .pd_mdix_get                   = */ phy_null_mdix_get,
  10724     /* .pd_mdix_status_get            = */ phy_null_mdix_status_get,
  10725     /* .pd_medium_config_set          = */ phy_wc40_medium_config_set,
  10726     /* .pd_medium_config_get          = */ NULL, 
  10727     /* .pd_medium_get                 = */ phy_wc40_medium_get,
  10728     /* .pd_cable_diag                 = */ NULL,
  10729     /* .pd_link_change                = */ NULL,
  10730     /* .pd_control_set                = */ phy_wc40_control_set,    
  10731     /* .pd_control_get                = */ phy_wc40_control_get,
  10732     /* .pd_reg_read                   = */ phy_wc40_reg_read,
  10733     /* .pd_reg_write                  = */ phy_wc40_reg_write, 
  10734     /* .pd_reg_modify                 = */ phy_wc40_reg_modify,
  10735     /* .pd_notify                     = */ phy_wc40_notify,
  10736     /* .pd_probe                      = */ phy_wc40_probe,
  10737     /* .pd_ability_advert_set         = */ phy_wc40_ability_advert_set,
  10738     /* .pd_ability_advert_get         = */ phy_wc40_ability_advert_get,
  10739     /* .pd_ability_remote_get         = */ phy_wc40_ability_remote_get,
  10740     /* .pd_ability_local_get          = */ phy_wc40_ability_local_get,
  10741     /* .pd_firmware_set               = */ phy_wc40_firmware_set,
  10742     /* .pdpd_timesync_config_set      = */ NULL,
  10743     /* .pdpd_timesync_config_get      = */ NULL,
  10744     /* .pdpd_timesync_control_set     = */ NULL,
  10745     /* .pdpd_timesync_control_set     = */ NULL,
  10746     /* .pd_diag_ctrl                  = */ phy_wc40_diag_ctrl
  10747 };
  10748 
  10749 /***********************************************************************
  10750  *
  10751  * PASS-THROUGH NOTIFY ROUTINES
  10752  */
  10753 
  10754 /*
  10755  * Function:
  10756  *      _phy_wc40_notify_duplex
  10757  * Purpose:
  10758  *      Program duplex if (and only if) serdeswc40 is an intermediate PHY.
  10759  * Parameters:
  10760  *      unit - StrataSwitch unit #.
  10761  *      port - StrataSwitch port #.
  10762  *      duplex - Boolean, TRUE indicates full duplex, FALSE
  10763  *              indicates half.
  10764  * Returns:
  10765  *      SOC_E_XXX
  10766  * Notes:
  10767  *      If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to
  10768  *      talk directly to an external fiber module.
  10769  *
  10770  *      If PHY_FLAGS_FIBER is clear, the PHY is being used in
  10771  *      pass-through mode to talk to an external SGMII PHY.
  10772  *
  10773  *      When used in pass-through mode, autoneg must be turned off and
  10774  *      the speed/duplex forced to match that of the external PHY.
  10775  */
  10776 
  10777 STATIC int
  10778 _phy_wc40_notify_duplex(int unit, soc_port_t port, uint32 duplex)
  10779 {
  10780     int                 fiber;
  10781     uint16              mii_ctrl;
  10782     phy_ctrl_t  *pc;
  10783 
  10784     pc    = INT_PHY_SW_STATE(unit, port);
  10785     fiber = DEV_CFG_PTR(pc)->fiber_pref;
  10786     LOG_INFO(BSL_LS_SOC_PHY,
  10787              (BSL_META_U(unit,
  10788                          "_phy_wc40_notify_duplex: "
  10789                          "u=%d p=%d duplex=%d fiber=%d\n"),
  10790               unit, port, duplex, fiber));
  10791 
  10792     if (SAL_BOOT_SIMULATION) {
  10793         return SOC_E_NONE;
  10794     }
  10795 
  10796     if (fiber) {
  10797         SOC_IF_ERROR_RETURN
  10798             (MODIFY_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00,
  10799                                           MII_CTRL_FD, MII_CTRL_FD));
  10800         return SOC_E_NONE;
  10801     }
  10802 
  10803     /* Put SERDES PHY in reset */
  10804 
  10805     SOC_IF_ERROR_RETURN
  10806         (_phy_wc40_notify_stop(unit, port, PHY_STOP_DUPLEX_CHG));
  10807 
  10808     /* Update duplexity */
  10809     mii_ctrl = (duplex) ? MII_CTRL_FD : 0;
  10810     SOC_IF_ERROR_RETURN
  10811         (MODIFY_WC40_COMBO_IEEE0_MIICNTLr(unit, pc, 0x00, mii_ctrl, MII_CTRL_FD));
  10812 
  10813     /* Take SERDES PHY out of reset */
  10814     SOC_IF_ERROR_RETURN
  10815         (_phy_wc40_notify_resume(unit, port, PHY_STOP_DUPLEX_CHG));
  10816 
  10817     /* Autonegotiation must be turned off to talk to external PHY if
  10818      * SGMII autoneg is not enabled.
  10819      */
  10820     if ((!PHY_SGMII_AUTONEG_MODE(unit, port)) && 
  10821         (!DEV_CFG_PTR(pc)->phy_passthru)) {
  10822         SOC_IF_ERROR_RETURN
  10823             (phy_wc40_an_set(unit, port, FALSE));
  10824     }
  10825     return SOC_E_NONE;
  10826 }
  10827 
  10828 /*
  10829  * Function:
  10830  *      _phy_wc40_notify_speed
  10831  * Purpose:
  10832  *      Program duplex if (and only if) serdeswc40 is an intermediate PHY.
  10833  * Parameters:
  10834  *      unit - StrataSwitch unit #.
  10835  *      port - StrataSwitch port #.
  10836  *      speed - Speed to program.
  10837  * Returns:
  10838  *      SOC_E_XXX
  10839  * Notes:
  10840  *      If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to
  10841  *      talk directly to an external fiber module.
  10842  *
  10843  *      If PHY_FLAGS_FIBER is clear, the PHY is being used in
  10844  *      pass-through mode to talk to an external SGMII PHY.
  10845  *
  10846  *      When used in pass-through mode, autoneg must be turned off and
  10847  *      the speed/duplex forced to match that of the external PHY.
  10848  */
  10849 
  10850 STATIC int
  10851 _phy_wc40_notify_speed(int unit, soc_port_t port, uint32 speed)
  10852 {
  10853     int          fiber;
  10854     uint16       sgmii_status;
  10855     phy_ctrl_t  *pc;
  10856 
  10857     pc    = INT_PHY_SW_STATE(unit, port);
  10858     fiber = DEV_CFG_PTR(pc)->fiber_pref;
  10859 
  10860     LOG_INFO(BSL_LS_SOC_PHY,
  10861              (BSL_META_U(unit,
  10862                          "_phy_wc40_notify_speed: "
  10863                          "u=%d p=%d speed=%d fiber=%d\n"),
  10864               unit, port, speed, fiber));
  10865 
  10866     if (SAL_BOOT_SIMULATION) {
  10867         return SOC_E_NONE;
  10868     }
  10869 
  10870     SOC_IF_ERROR_RETURN
  10871         (READ_WC40_SERDESDIGITAL_STATUS1000X1r(unit, pc, 0x00, &sgmii_status));
  10872 
  10873     /* Put SERDES PHY in reset */
  10874     SOC_IF_ERROR_RETURN
  10875         (_phy_wc40_notify_stop(unit, port, PHY_STOP_SPEED_CHG));
  10876 
  10877     /* Update speed */
  10878     SOC_IF_ERROR_RETURN
  10879         (phy_wc40_speed_set(unit, port, speed));
  10880 
  10881     /* Take SERDES PHY out of reset */
  10882     SOC_IF_ERROR_RETURN
  10883         (_phy_wc40_notify_resume(unit, port, PHY_STOP_SPEED_CHG));
  10884 
  10885     /* Autonegotiation must be turned off to talk to external PHY */
  10886     if (!PHY_SGMII_AUTONEG_MODE(unit, port) && PHY_EXTERNAL_MODE(unit, port)) {
  10887         SOC_IF_ERROR_RETURN
  10888             (phy_wc40_an_set(unit, port, FALSE));
  10889     }
  10890 
  10891     /* Toggle TX FIFO reset if SGMII mode.
  10892        Necessary to address traffic corruption
  10893      */  
  10894     if((speed <= 1000) && 
  10895             (sgmii_status & SERDESDIGITAL_STATUS1000X1_SGMII_MODE_MASK)) {
  10896         SOC_IF_ERROR_RETURN
  10897             (MODIFY_WC40_DIGITAL5_MISC6r(unit,pc,0x00, 
  10898                              DIGITAL5_MISC6_TX_OS8_FRST_SM_MASK, 
  10899                              DIGITAL5_MISC6_TX_OS8_FRST_SM_MASK));
  10900         SOC_IF_ERROR_RETURN
  10901             (MODIFY_WC40_DIGITAL5_MISC6r(unit,pc,0x00, 
  10902                              0, 
  10903                              DIGITAL5_MISC6_TX_OS8_FRST_SM_MASK));
  10904         LOG_VERBOSE(BSL_LS_SOC_PHY,
  10905                     (BSL_META_U(unit,
  10906                                 "_phy_wc40_notify_speed: APPLY TX FIFO RST u=%d p=%d \n"),
  10907                      unit, port));
  10908     }
  10909 
  10910 
  10911     return SOC_E_NONE;
  10912 }
  10913 
  10914 /*
  10915  * Function:
  10916  *      _phy_wc40_stop
  10917  * Purpose:
  10918  *      Put serdeswc40 SERDES in or out of reset depending on conditions
  10919  */
  10920 
  10921 STATIC int
  10922 _phy_wc40_stop(int unit, soc_port_t port)
  10923 {
  10924     int                 stop, copper;
  10925     uint16 mask16,data16;
  10926     phy_ctrl_t  *pc;
  10927     int speed;
  10928 
  10929     pc = INT_PHY_SW_STATE(unit, port);
  10930 
  10931     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
  10932         return SOC_E_NONE;
  10933     }
  10934 
  10935     /* 'Stop' only for speeds < 10G. 
  10936      */  
  10937     SOC_IF_ERROR_RETURN
  10938         (phy_wc40_speed_get(unit,port,&speed));
  10939     if(10000 <= speed) {
  10940         return SOC_E_NONE;
  10941     }
  10942 
  10943     copper = (pc->stop &
  10944               PHY_STOP_COPPER) != 0;
  10945 
  10946     stop = ((pc->stop &
  10947              (PHY_STOP_PHY_DIS |
  10948               PHY_STOP_DRAIN)) != 0 ||
  10949             (copper &&
  10950              (pc->stop &
  10951               (PHY_STOP_MAC_DIS |
  10952                PHY_STOP_DUPLEX_CHG |
  10953                PHY_STOP_SPEED_CHG)) != 0));
  10954 
  10955     LOG_INFO(BSL_LS_SOC_PHY,
  10956              (BSL_META_U(unit,
  10957                          "phy_wc40_stop: u=%d p=%d copper=%d stop=%d flg=0x%x\n"),
  10958               unit, port, copper, stop,
  10959               pc->stop));
  10960 
  10961     /* tx/rx reset */
  10962     mask16 = DIGITAL5_MISC6_RESET_RX_ASIC_MASK | DIGITAL5_MISC6_RESET_TX_ASIC_MASK;
  10963     data16 = stop? mask16: 0;
  10964     SOC_IF_ERROR_RETURN
  10965         (MODIFY_WC40_DIGITAL5_MISC6r(unit,pc,0x00, data16, mask16));
  10966 
  10967     LOG_INFO(BSL_LS_SOC_PHY,
  10968              (BSL_META_U(unit,
  10969                          "phy_wc40_stop: u=%d p=%d mask=0x%x value=0x%x\n"),
  10970               unit, port, mask16, data16));
  10971 
  10972     return SOC_E_NONE;
  10973 }
  10974 
  10975 /*
  10976  * Function:
  10977  *      _phy_wc40_notify_stop
  10978  * Purpose:
  10979  *      Add a reason to put serdeswc40 PHY in reset.
  10980  * Parameters:
  10981  *      unit - StrataSwitch unit #.
  10982  *      port - StrataSwitch port #.
  10983  *      flags - Reason to stop
  10984  * Returns:     
  10985  *      SOC_E_XXX
  10986  */
  10987 
  10988 STATIC int
  10989 _phy_wc40_notify_stop(int unit, soc_port_t port, uint32 flags)
  10990 {
  10991     INT_PHY_SW_STATE(unit, port)->stop |= flags;
  10992 
  10993     return _phy_wc40_stop(unit, port);
  10994 }
  10995 
  10996 /*  
  10997  * Function:
  10998  *      _phy_wc40_notify_resume
  10999  * Purpose:
  11000  *      Remove a reason to put serdeswc40 PHY in reset.
  11001  * Parameters:
  11002  *      unit - StrataSwitch unit #.
  11003  *      port - StrataSwitch port #.
  11004  *      flags - Reason to stop
  11005  * Returns:     
  11006  *      SOC_E_XXX
  11007  */
  11008 
  11009 STATIC int
  11010 _phy_wc40_notify_resume(int unit, soc_port_t port, uint32 flags)
  11011 {   
  11012     INT_PHY_SW_STATE(unit, port)->stop &= ~flags;
  11013     
  11014     return _phy_wc40_stop(unit, port);
  11015 }
  11016 
  11017 /*
  11018  * Function:
  11019  *      phy_wc40_media_setup
  11020  * Purpose:     
  11021  *      Configure 
  11022  * Parameters:
  11023  *      unit - StrataSwitch unit #.
  11024  *      port - StrataSwitch port #.
  11025  *      fiber_mode - Configure for fiber mode
  11026  *      fiber_pref - Fiber preferrred (if fiber mode)
  11027  * Returns:     
  11028  *      SOC_E_XXX
  11029  */
  11030 STATIC int
  11031 _phy_wc40_notify_interface(int unit, soc_port_t port, uint32 intf)
  11032 {
  11033     phy_ctrl_t  *pc;
  11034     uint16       data16;
  11035     
  11036     pc = INT_PHY_SW_STATE(unit, port);
  11037 
  11038     data16 = 0;
  11039     if (intf != SOC_PORT_IF_SGMII) {
  11040         data16 = SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK;
  11041     }
  11042  
  11043     SOC_IF_ERROR_RETURN
  11044         (MODIFY_WC40_SERDESDIGITAL_CONTROL1000X1r(unit, pc, 0x00, data16,
  11045                            SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK));
  11046  
  11047     return SOC_E_NONE;
  11048 }
  11049 
  11050 STATIC
  11051 int _wc40_xgmii_scw_config (int unit, phy_ctrl_t *pc)
  11052 {
  11053     /* Dual Broadcast mode write */
  11054     SOC_IF_ERROR_RETURN
  11055         (WRITE_WC40_RX66_SCW0r(unit,pc,0x00,0xE070));
  11056     SOC_IF_ERROR_RETURN
  11057         (WRITE_WC40_RX66_SCW1r(unit,pc,0x00,0xC0D0));
  11058     SOC_IF_ERROR_RETURN
  11059         (WRITE_WC40_RX66_SCW2r(unit,pc,0x00,0xA0B0));
  11060     SOC_IF_ERROR_RETURN
  11061         (WRITE_WC40_RX66_SCW3r(unit,pc,0x00,0x8090));
  11062     SOC_IF_ERROR_RETURN
  11063         (WRITE_WC40_RX66_SCW0_MASKr(unit,pc,0x00,0xF0F0));
  11064     SOC_IF_ERROR_RETURN
  11065         (WRITE_WC40_RX66_SCW1_MASKr(unit,pc,0x00,0xF0F0));
  11066     SOC_IF_ERROR_RETURN
  11067         (WRITE_WC40_RX66_SCW2_MASKr(unit,pc,0x00,0xF0F0));
  11068     SOC_IF_ERROR_RETURN
  11069         (WRITE_WC40_RX66_SCW3_MASKr(unit,pc,0x00,0xF0F0));
  11070     return(SOC_E_NONE);
  11071 }
  11072 
  11073 STATIC 
  11074 int _wc40_rxaui_config(int unit, phy_ctrl_t  *pc,int rxaui)
  11075 {
  11076     uint16 mask16,data16;
  11077     mask16 = XGXSBLK1_LANECTRL3_PWRDWN_FORCE_MASK |
  11078                 0xc |    /* lane 2 and 3 RX */
  11079                 (0xc << XGXSBLK1_LANECTRL3_PWRDN_TX_SHIFT);  /* TX */
  11080 
  11081     /* if in reduced XAUI mode, disable lane 2 and 3 */
  11082     data16 = rxaui? mask16: 0;
  11083 
  11084     SOC_IF_ERROR_RETURN
  11085         (MODIFY_WC40_XGXSBLK1_LANECTRL3r(unit,pc,0x00, data16,mask16));
  11086     return(SOC_E_NONE);
  11087 }
  11088 
  11089 STATIC
  11090 int _wc40_soft_reset(int unit, phy_ctrl_t  *pc)
  11091 {
  11092    uint16 data16;
  11093    uint16 mask16;
  11094 
  11095    data16 = XGXSBLK0_MMDSELECT_DEVCL22_EN_MASK |
  11096                  XGXSBLK0_MMDSELECT_DEVDEVAD_EN_MASK |
  11097                  XGXSBLK0_MMDSELECT_DEVPMD_EN_MASK  |
  11098                  XGXSBLK0_MMDSELECT_DEVAN_EN_MASK |
  11099                  XGXSBLK0_MMDSELECT_MULTIMMDS_EN_MASK;
  11100    mask16 = data16 |
  11101             XGXSBLK0_MMDSELECT_MULTIPRTS_EN_MASK;
  11102 
  11103     if (DEV_CFG_PTR(pc)->lane0_rst) {
  11104         /* reset entire device */
  11105         SOC_IF_ERROR_RETURN
  11106             (MODIFY_WC40_XGXSBLK2_LANERESETr(unit,pc,LANE0_ACCESS, 
  11107                           XGXSBLK2_LANERESET_RESET_MDIO_MASK,
  11108                           XGXSBLK2_LANERESET_RESET_MDIO_MASK));
  11109         
  11110         /* wait 10us for reset to complete */
  11111         WC40_UDELAY(10);
  11112     }
  11113     /* select multi mmd */
  11114     SOC_IF_ERROR_RETURN
  11115         (MODIFY_WC40_XGXSBLK0_MMDSELECTr(unit, pc, LANE0_ACCESS, data16,mask16));
  11116 
  11117     return(SOC_E_NONE);
  11118 }
  11119 
  11120 STATIC
  11121 int _wc40_chip_init_done(int unit,int chip_num,int phy_mode)
  11122 {
  11123     int port;
  11124     phy_ctrl_t  *pc;
  11125 
  11126     PBMP_PORT_ITER(unit, port) {
  11127         pc = INT_PHY_SW_STATE(unit, port);
  11128         if (pc == NULL) {
  11129             continue;
  11130         }
  11131         if (!pc->dev_name || pc->dev_name != wc_device_name) {
  11132             continue;
  11133         }
  11134         if (pc->chip_num != chip_num) {
  11135             continue;
  11136         }
  11137 
  11138         if ((pc->flags & PHYCTRL_INIT_DONE) && (phy_mode == pc->phy_mode)) {
  11139             return TRUE;
  11140         }
  11141     }
  11142     return FALSE;
  11143 }
  11144 
  11145 #ifdef BCM_WARM_BOOT_SUPPORT
  11146 STATIC 
  11147 int wc40_wb_id_command(int unit, soc_port_t port, int offset, 
  11148                          WC40_WB_HANDLER_TYPE_t type, WC40_WB_DATA_ID_t id, int *size) {
  11149     phy_ctrl_t *pc;
  11150     uint8 *wc_scache_ptr;
  11151     int rv, vsize, loc_off;
  11152     uint16 ver;
  11153     
  11154     pc    = INT_PHY_SW_STATE(unit, port);
  11155     wc_scache_ptr = DEV_CFG_PTR(pc)->scache_ptr ;
  11156     ver            = DEV_CFG_PTR(pc)->scache_ver ;
  11157     vsize = 0 ; 
  11158     loc_off = offset ;
  11159     rv = SOC_E_NONE ;
  11160     
  11161     if(type==WC40_WB_SC_COUNT){
  11162         /* no basic check at this moment */
  11163     } else {
  11164         /* check for ptr */
  11165         if(wc_scache_ptr==NULL) {
  11166             return rv ;
  11167         }
  11168     }
  11169     switch(id) {
  11170     case WC40_WB_SC_VER:
  11171         if(ver >= BCM_WB_VERSION_1_0) {
  11172             WC40_WB_ID_CMD(wc_scache_ptr, DEV_CFG_PTR(pc)->scache_ver,type,&loc_off,&vsize);
  11173         }
  11174         break ;
  11175     case WC40_WB_RXLOS:
  11176         if(ver >= BCM_WB_VERSION_1_0) {
  11177             WC40_WB_ID_CMD(wc_scache_ptr, DEV_CFG_PTR(pc)->sw_rx_los.state, type,&loc_off,&vsize);
  11178             WC40_WB_ID_CMD(wc_scache_ptr, DEV_CFG_PTR(pc)->sw_rx_los.sys_link, type,&loc_off,&vsize);
  11179             WC40_WB_ID_CMD(wc_scache_ptr, DEV_CFG_PTR(pc)->sw_rx_los.link_status, type,&loc_off,&vsize);
  11180         }
  11181         break ;
  11182     case WC40_WB_SC_LAST:
  11183         break ;
  11184     default:
  11185         rv = SOC_E_PARAM ;
  11186         break ;
  11187     }
  11188     *size = vsize ;
  11189     return rv ;    
  11190 }
  11191 
  11192 STATIC 
  11193 int wc40_wb_sc_handler(int unit, soc_port_t port, WC40_WB_HANDLER_TYPE_t type, WC40_WB_DATA_ID_t id) 
  11194 {
  11195     int i, rv, size, offset ;
  11196     rv   = SOC_E_NONE ; 
  11197     size   = 0 ;
  11198     offset = 0 ;
  11199     
  11200     for(i=0; i<WC40_WB_SC_LAST;i++) {
  11201         if(i==id) {
  11202             rv |= wc40_wb_id_command(unit,port, offset, type, id, &size) ;
  11203             break ;
  11204         } else {
  11205             rv |= wc40_wb_id_command(unit, port, 0, WC40_WB_SC_COUNT, i, &size) ;
  11206             offset += size ;
  11207         }
  11208     }
  11209 
  11210     return rv ;
  11211 }
  11212 
  11213 STATIC 
  11214 int wc40_wb_sc_size_count(int unit, soc_port_t port, int *size) 
  11215 {
  11216     int i, rv, total, sz ;
  11217     rv   = SOC_E_NONE ;
  11218     sz    = 0 ;
  11219     total = 0 ;
  11220     for(i=0; i<WC40_WB_SC_LAST;i++) {
  11221         rv |= wc40_wb_id_command(unit, port, 0, WC40_WB_SC_COUNT, i, &sz) ;
  11222         total += sz ;
  11223     }
  11224     *size = total ;
  11225 
  11226     return rv ;
  11227 }
  11228 
  11229 STATIC 
  11230 int wc40_wb_sc_sync(int unit, soc_port_t port) 
  11231 {
  11232     int i, rv, offset, size ;
  11233 
  11234     rv     = SOC_E_NONE ;
  11235     size   = 0 ;
  11236     offset = 0 ;
  11237     for(i=0; i<WC40_WB_SC_LAST;i++) {
  11238         rv |= wc40_wb_id_command(unit, port, offset, WC40_WB_SC_UPDATE, i, &size) ;
  11239         offset += size ;
  11240     }
  11241     
  11242     return rv ;
  11243 }
  11244 
  11245 /* retrieve all variables from SCache */
  11246 STATIC 
  11247 int wc40_wb_sc_reinit(int unit, soc_port_t port) 
  11248 {
  11249     int i, rv, offset, size ;
  11250     soc_scache_handle_t scache_handle;
  11251     uint8 *wc_scache_ptr;
  11252     uint32 alloc_get;
  11253     int    alloc_size ;
  11254     phy_ctrl_t *pc;
  11255     int    current_ver = BCM_WB_DEFAULT_VERSION;
  11256 
  11257 
  11258     pc = INT_PHY_SW_STATE(unit, port);
  11259 
  11260     rv     = SOC_E_NONE ;
  11261     size   = 0 ;
  11262     offset = 0 ;
  11263     alloc_size = 0 ;
  11264     alloc_get  = 0 ;
  11265 
  11266     /* init default status */
  11267     if(current_ver >= BCM_WB_VERSION_1_0) {
  11268          DEV_CFG_PTR(pc)->sw_rx_los.sys_link = 0;
  11269          DEV_CFG_PTR(pc)->sw_rx_los.state = RESET;
  11270          DEV_CFG_PTR(pc)->sw_rx_los.link_status = 0;
  11271      }
  11272 
  11273 
  11274     SOC_SCACHE_HANDLE_SET(scache_handle, unit,
  11275                           SOC_SCACHE_SERDES_HANDLE, port);
  11276     /* Get the pointer for the  cache */
  11277     rv = soc_scache_ptr_get(unit, scache_handle,
  11278                             &wc_scache_ptr, &alloc_get);
  11279     
  11280     if(rv) {
  11281        DEV_CFG_PTR(pc)->scache_ptr = NULL ;
  11282        DEV_CFG_PTR(pc)->scache_ver = 0 ;
  11283 
  11284        return rv ;
  11285     } else {
  11286         /* to find out the existing scache is an old version or not */
  11287        if(alloc_get < sizeof(DEV_CFG_PTR(pc)->scache_ver)) {
  11288            DEV_CFG_PTR(pc)->scache_ptr = NULL ;
  11289            DEV_CFG_PTR(pc)->scache_ver = 0 ;
  11290            return SOC_E_INTERNAL;
  11291        } else {
  11292            DEV_CFG_PTR(pc)->scache_ptr = wc_scache_ptr ;
  11293            DEV_CFG_PTR(pc)->scache_size= alloc_size ;
  11294            /* copy from tsc_scache_ptr to pCfg->scache_ver */
  11295            sal_memcpy(&DEV_CFG_PTR(pc)->scache_ver, wc_scache_ptr, sizeof(DEV_CFG_PTR(pc)->scache_ver));
  11296        }
  11297        rv = wc40_wb_sc_size_count(unit, port, &alloc_size) ;
  11298        if((alloc_get < alloc_size)||(alloc_get > (alloc_size+15))) {
  11299             /* Expected size doesn't match retrieved size */
  11300             DEV_CFG_PTR(pc)->scache_ptr = NULL ;
  11301             DEV_CFG_PTR(pc)->scache_ver = 0 ;
  11302             return SOC_E_INTERNAL;
  11303        }
  11304        rv = SOC_E_NONE ;
  11305     }
  11306     
  11307     for(i=0; i<WC40_WB_SC_LAST;i++) {
  11308         rv |= wc40_wb_id_command(unit, port, offset, WC40_WB_SC_RETRIEVE, i, &size) ;
  11309         offset += size ;
  11310     }
  11311 
  11312     return rv ;
  11313 }
  11314 
  11315 /* initialize the space, only be called when !SOC_WARM_BOOT(unit) */
  11316 STATIC 
  11317 int wc40_wb_sc_init(int unit, soc_port_t port)
  11318 {
  11319     phy_ctrl_t *pc;
  11320     soc_scache_handle_t scache_handle;
  11321     uint8 *wc_scache_ptr;
  11322     uint32 alloc_get =0;
  11323     int    alloc_size =0;
  11324     int    current_ver = BCM_WB_DEFAULT_VERSION;
  11325     int rv = SOC_E_NONE;
  11326     
  11327     pc = INT_PHY_SW_STATE(unit, port);
  11328         
  11329     SOC_SCACHE_HANDLE_SET(scache_handle, unit,
  11330                           SOC_SCACHE_SERDES_HANDLE, port);
  11331     rv = soc_scache_ptr_get(unit, scache_handle,
  11332                             &wc_scache_ptr, &alloc_get);
  11333     
  11334     if (SOC_E_NOT_FOUND == rv) {
  11335         DEV_CFG_PTR(pc)->scache_ver = current_ver ;
  11336         rv = wc40_wb_sc_size_count(unit, port, &alloc_size) ;
  11337         SOC_IF_ERROR_RETURN
  11338             (soc_scache_alloc(unit, scache_handle, alloc_size));
  11339         rv = soc_scache_ptr_get(unit, scache_handle,
  11340                                 &wc_scache_ptr, &alloc_get);
  11341 
  11342         if (SOC_FAILURE(rv)) {
  11343             return rv;
  11344         } else if ((alloc_get < alloc_size)||(alloc_get > (alloc_size+15))) {
  11345             /* Expected size doesn't match retrieved size */
  11346             return SOC_E_INTERNAL;
  11347         } else if (NULL == wc_scache_ptr) {
  11348             return SOC_E_MEMORY;
  11349         }
  11350         DEV_CFG_PTR(pc)->scache_ptr = wc_scache_ptr ;
  11351         DEV_CFG_PTR(pc)->scache_size= alloc_size ;
  11352         
  11353         /* set up version */
  11354         DEV_CFG_PTR(pc)->scache_ver = current_ver ;  
  11355         sal_memcpy(wc_scache_ptr, &DEV_CFG_PTR(pc)->scache_ver, sizeof(DEV_CFG_PTR(pc)->scache_ver));
  11356     } else if(SOC_E_PARAM ==rv) {
  11357         DEV_CFG_PTR(pc)->scache_ver = 0 ;
  11358         DEV_CFG_PTR(pc)->scache_ptr = NULL ;
  11359         DEV_CFG_PTR(pc)->scache_size= 0 ;
  11360     } else {
  11361         /* mem space has been created already */
  11362         DEV_CFG_PTR(pc)->scache_ver = current_ver ;
  11363         rv = wc40_wb_sc_size_count(unit, port, &alloc_size) ;
  11364         if((alloc_get < alloc_size)||(alloc_get > (alloc_size+15))) {
  11365             /* Expected size doesn't match retrieved size */
  11366             DEV_CFG_PTR(pc)->scache_ptr = NULL ;
  11367             return SOC_E_INTERNAL;
  11368         }
  11369         DEV_CFG_PTR(pc)->scache_ptr = wc_scache_ptr ;
  11370         DEV_CFG_PTR(pc)->scache_size= alloc_size ;
  11371         DEV_CFG_PTR(pc)->scache_ver = current_ver ;    
  11372         sal_memcpy(wc_scache_ptr, &DEV_CFG_PTR(pc)->scache_ver, sizeof(DEV_CFG_PTR(pc)->scache_ver));
  11373     }
  11374     
  11375     return rv ;
  11376 }
  11377 
  11378 STATIC int wc40_wb_sc_realloc_init(int unit, soc_port_t port) 
  11379 {
  11380     phy_ctrl_t *pc;
  11381     soc_scache_handle_t scache_handle;
  11382     uint8 *wc_scache_ptr;
  11383     uint32 alloc_get = 0;
  11384     int    alloc_size1 = 0 ;
  11385     int    alloc_size2 = 0;
  11386     int    current_ver  = BCM_WB_DEFAULT_VERSION;
  11387     int rv =  SOC_E_NONE;
  11388 
  11389     pc = INT_PHY_SW_STATE(unit, port);
  11390         
  11391     SOC_SCACHE_HANDLE_SET(scache_handle, unit,
  11392                           SOC_SCACHE_SERDES_HANDLE, port);
  11393 
  11394     /* Get the pointer for the  cache */
  11395     rv = soc_scache_ptr_get(unit, scache_handle,
  11396                             &wc_scache_ptr, &alloc_get);
  11397      if ( rv) {
  11398         DEV_CFG_PTR(pc)->scache_ver = 0 ;
  11399         DEV_CFG_PTR(pc)->scache_ptr = NULL ;
  11400         DEV_CFG_PTR(pc)->scache_size= 0 ;
  11401         }else {
  11402         /* mem space has been created already */
  11403         rv = wc40_wb_sc_size_count(unit, port, &alloc_size1) ;
  11404         DEV_CFG_PTR(pc)->scache_ver = current_ver ;
  11405         rv = wc40_wb_sc_size_count(unit, port, &alloc_size2) ;
  11406         SOC_IF_ERROR_RETURN
  11407             (soc_scache_realloc(unit, scache_handle, (alloc_size2-alloc_size1)));
  11408 
  11409         rv = soc_scache_ptr_get(unit, scache_handle,
  11410                                 &wc_scache_ptr, &alloc_get);
  11411         if((alloc_get < alloc_size2)||(alloc_get > (alloc_size2+15))) {
  11412             /* Expected size doesn't match retrieved size */
  11413             DEV_CFG_PTR(pc)->scache_ptr = NULL ;
  11414             return SOC_E_INTERNAL;
  11415         }
  11416         DEV_CFG_PTR(pc)->scache_ptr = wc_scache_ptr ;
  11417         DEV_CFG_PTR(pc)->scache_size= alloc_size2 ;
  11418         DEV_CFG_PTR(pc)->scache_ver = current_ver ;    
  11419         sal_memcpy(wc_scache_ptr, &DEV_CFG_PTR(pc)->scache_ver, sizeof(DEV_CFG_PTR(pc)->scache_ver));
  11420     }
  11421     return rv ;   
  11422 }
  11423 
  11424 #endif
  11425 
  11426 
  11427 /******************************************************************************
  11428 *              Begin Diagnostic Code                                          *
  11429  */
  11430 #ifdef BROADCOM_DEBUG
  11431 int
  11432 _phy_wc40_cfg_dump(int unit, soc_port_t port)
  11433 {
  11434     phy_ctrl_t  *pc;
  11435     WC40_DEV_CFG_t *pCfg;
  11436     WC40_DEV_INFO_t  *pInfo;
  11437     WC40_DEV_DESC_t *pDesc;
  11438     soc_phy_info_t *pi;
  11439     int i;
  11440     int size;
  11441 
  11442     pc = INT_PHY_SW_STATE(unit, port);
  11443     pDesc = (WC40_DEV_DESC_t *)(pc + 1);
  11444     pi = &SOC_PHY_INFO(unit, port);
  11445 
  11446     pCfg = &pDesc->cfg;
  11447     pInfo = &pDesc->info;
  11448     if (COMBO_LANE_MODE(DEV_CFG_PTR(pc)->lane_mode)) {
  11449         size = 4;
  11450     } else if (IS_DUAL_LANE_PORT(pc)) {
  11451         size = 2;
  11452     } else {
  11453         size = 1;
  11454     }
  11455  
  11456     LOG_CLI((BSL_META_U(unit,
  11457                         "pc = 0x%x, pCfg = 0x%x, pInfo = 0x%x\n"), (int)(size_t)pc,
  11458              (int)(size_t)pCfg,(int)(size_t)pInfo));
  11459     for (i = 0; i < size; i++) { 
  11460         LOG_CLI((BSL_META_U(unit,
  11461                             "preemph%d     0x%x\n"),
  11462                  i,pCfg->preemph[i]));
  11463         LOG_CLI((BSL_META_U(unit,
  11464                             "idriver%d     0x%04x\n"),
  11465                  i, pCfg->idriver[i]));
  11466         LOG_CLI((BSL_META_U(unit,
  11467                             "pdriver%d     0x%04x\n"),
  11468                  i, pCfg->pdriver[i]));
  11469         LOG_CLI((BSL_META_U(unit,
  11470                             "post2driver%d 0x%04x\n"),
  11471                  i, pCfg->post2driver[i]));
  11472     }
  11473     LOG_CLI((BSL_META_U(unit,
  11474                         "auto_medium  0x%04x\n"),
  11475              pCfg->auto_medium));
  11476     LOG_CLI((BSL_META_U(unit,
  11477                         "fiber_pref   0x%04x\n"),
  11478              pCfg->fiber_pref));
  11479     LOG_CLI((BSL_META_U(unit,
  11480                         "sgmii_mstr   0x%04x\n"),
  11481              pCfg->sgmii_mstr));
  11482     LOG_CLI((BSL_META_U(unit,
  11483                         "pdetect10g   0x%04x\n"),
  11484              pCfg->pdetect10g));
  11485     LOG_CLI((BSL_META_U(unit,
  11486                         "pdetect1000x 0x%04x\n"),
  11487              pCfg->pdetect1000x));
  11488     LOG_CLI((BSL_META_U(unit,
  11489                         "cx42hg       0x%04x\n"), pCfg->cx42hg));
  11490     LOG_CLI((BSL_META_U(unit,
  11491                         "rxlane_map   0x%04x\n"), pCfg->rxlane_map));
  11492     LOG_CLI((BSL_META_U(unit,
  11493                         "txlane_map   0x%04x\n"), pCfg->txlane_map));
  11494     LOG_CLI((BSL_META_U(unit,
  11495                         "rxpol        0x%04x\n"), pCfg->rxpol));
  11496     LOG_CLI((BSL_META_U(unit,
  11497                         "txpol        0x%04x\n"), pCfg->txpol));
  11498     LOG_CLI((BSL_META_U(unit,
  11499                         "cl73an       0x%04x\n"), pCfg->cl73an));
  11500     LOG_CLI((BSL_META_U(unit,
  11501                         "phy_mode     0x%04x\n"), pc->phy_mode));
  11502     LOG_CLI((BSL_META_U(unit,
  11503                         "cx4_10g      0x%04x\n"), pCfg->cx4_10g));
  11504     LOG_CLI((BSL_META_U(unit,
  11505                         "lane0_rst    0x%04x\n"), pCfg->lane0_rst));
  11506     LOG_CLI((BSL_META_U(unit,
  11507                         "rxaui        0x%04x\n"), pCfg->rxaui));
  11508     LOG_CLI((BSL_META_U(unit,
  11509                         "dxgxs        0x%04x\n"), pCfg->dxgxs));
  11510     LOG_CLI((BSL_META_U(unit,
  11511                         "line_intf    0x%04x\n"), pCfg->line_intf));
  11512     LOG_CLI((BSL_META_U(unit,
  11513                         "hg_mode      0x%04x\n"), pCfg->hg_mode));
  11514     LOG_CLI((BSL_META_U(unit,
  11515                         "chip_num     0x%04x\n"), pc->chip_num));
  11516     LOG_CLI((BSL_META_U(unit,
  11517                         "lane_num     0x%04x\n"), pc->lane_num));
  11518     LOG_CLI((BSL_META_U(unit,
  11519                         "speedMax     0x%04x\n"), pc->speed_max));
  11520     LOG_CLI((BSL_META_U(unit,
  11521                         "pc->flags    0x%04x\n"), pc->flags));
  11522     LOG_CLI((BSL_META_U(unit,
  11523                         "pc->stop     0x%04x\n"), pc->stop));
  11524     LOG_CLI((BSL_META_U(unit,
  11525                         "pi->phy_flags   0x%04x\n"), pi->phy_flags));
  11526 
  11527     return SOC_E_NONE;
  11528 }
  11529 #endif
  11530 
  11531 #define WC_UC_DEBUG
  11532 #ifdef WC_UC_DEBUG
  11533 typedef struct {
  11534     int tx_pre_cursor;
  11535     int tx_main;
  11536     int tx_post_cursor;
  11537     char *vga_bias_reduced;
  11538     int postc_metric;
  11539     int pf_ctrl;
  11540     int vga_sum;
  11541     int dfe1_bin;
  11542     int dfe2_bin;
  11543     int dfe3_bin;
  11544     int dfe4_bin;
  11545     int dfe5_bin;
  11546     int integ_reg;
  11547     int integ_reg_xfer;
  11548     int clk90_offset;
  11549     int slicer_target;
  11550     int offset_pe;
  11551     int offset_ze;
  11552     int offset_me;
  11553     int offset_po;
  11554     int offset_zo;
  11555     int offset_mo;
  11556 } UC_DESC;
  11557 
  11558 #define MAX_LANES 4
  11559 static UC_DESC uc_desc[MAX_LANES];
  11560 static int lanes[MAX_LANES] = {LANE0_ACCESS,LANE1_ACCESS,LANE2_ACCESS,LANE3_ACCESS};
  11561 
  11562 int
  11563 wc40_uc_status_dump(int unit, soc_port_t port)
  11564 {
  11565     phy_ctrl_t  *pc;
  11566     UC_DESC * pDesc;
  11567     int i;
  11568     int reg;
  11569     uint16 data16;
  11570     uint16 mask16; 
  11571     int regval;
  11572     pc = INT_PHY_SW_STATE(unit, port);
  11573 /*
  11574  *Const DSC_1_ADDR = &H8200&
  11575  *Const DSC_2_ADDR = &H8210&
  11576  *Const DSC_3_ADDR = &H8220&
  11577  *Const DSC_4_ADDR = &H8230&
  11578  *Const DSC_5_ADDR = &H8240&
  11579  * 0x822c,2d,2e,
  11580 */
  11581     WC40_MEM_SET((char *)&uc_desc[0], 0, (sizeof(UC_DESC))*MAX_LANES);
  11582     for (i = 0; i < MAX_LANES; i++) {
  11583         pDesc = &uc_desc[i];
  11584 
  11585         /* tx_pre_cursor */
  11586         reg = 0x8063 + 0x10*i;      
  11587         mask16 = (1 << 14) | (1 << 15);
  11588         data16 = 1 << 14;
  11589         SOC_IF_ERROR_RETURN
  11590             (WC40_REG_MODIFY(unit, pc, LANE0_ACCESS, reg, data16,mask16));
  11591 
  11592         reg = 0x8060 + 0x10*i;      
  11593         SOC_IF_ERROR_RETURN
  11594             (WC40_REG_READ(unit, pc, LANE0_ACCESS, reg, &data16));
  11595         regval = data16 & 0xF;
  11596         pDesc->tx_pre_cursor = regval;
  11597 
  11598         /* tx_main */
  11599         regval = (data16 >> 4) & 0x3F;
  11600         pDesc->tx_main = regval;
  11601 
  11602         /* tx_post_cursor */
  11603         regval = (data16 >> 10) & 0x1F;
  11604         pDesc->tx_post_cursor = regval;
  11605 
  11606         /* restore 0x8063 */
  11607         reg = 0x8063 + 0x10*i;      
  11608         mask16 = (1 << 14) | (1 << 15);
  11609         data16 = 0;
  11610         SOC_IF_ERROR_RETURN
  11611             (WC40_REG_MODIFY(unit, pc, LANE0_ACCESS, reg, data16,mask16));
  11612 
  11613         /* vga_bias_reduced */ 
  11614         reg = 0x80BD + 0x10*i;      
  11615         SOC_IF_ERROR_RETURN
  11616             (WC40_REG_READ(unit, pc, LANE0_ACCESS, reg, &data16));
  11617         regval = data16 & (1 << 4);
  11618         if (regval) {
  11619             pDesc->vga_bias_reduced = "88%";
  11620         } else {
  11621             pDesc->vga_bias_reduced = "100%";
  11622         }
  11623     }
  11624 
  11625     for (i = 0; i < MAX_LANES; i++) {
  11626         pDesc = &uc_desc[i];
  11627         /* postc_metric(lane) = rd22_postc_metric (phy, lane), DSC_5_ADDR=0x8240 */
  11628         reg = 0x8241;      
  11629         SOC_IF_ERROR_RETURN
  11630             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11631         regval = data16;
  11632         regval &= 0x7ff;
  11633         if (regval >=1024) {
  11634             regval -= 2048;
  11635         } 
  11636         pDesc->postc_metric = regval;
  11637 
  11638         /* pf_ctrl(lane) = rd22_pf_ctrl (phy, lane) DSC_3_ADDR=0x8220 */
  11639         reg = 0x822b;
  11640         SOC_IF_ERROR_RETURN
  11641             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11642         regval = data16;
  11643         regval &= 0xf;
  11644         pDesc->pf_ctrl = regval;
  11645 
  11646         /* vga_sum(lane) = rd22_vga_sum (phy, lane) DSC_3_ADDR=0x8220  */
  11647         reg = 0x8225;
  11648         SOC_IF_ERROR_RETURN
  11649             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11650         regval = data16;
  11651         regval &= 63;
  11652         pDesc->vga_sum = regval;
  11653 
  11654         /* dfe1_bin(lane) = rd22_dfe_tap_1_bin (phy, lane) DSC_3_ADDR=0x8220  */
  11655         reg = 0x8225;
  11656         SOC_IF_ERROR_RETURN
  11657             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11658         regval = data16;
  11659         regval /= 64; 
  11660         regval &= 63;
  11661         pDesc->dfe1_bin = regval;
  11662 
  11663         /* dfe2_bin(lane) = rd22_dfe_tap_2_bin (phy, lane) DSC_3_ADDR=0x8220  */
  11664         reg = 0x8226;
  11665         SOC_IF_ERROR_RETURN
  11666             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11667         regval = data16;
  11668         regval &= 63;
  11669         if (regval >= 32) {
  11670             regval -=64;
  11671         }
  11672         pDesc->dfe2_bin = regval;
  11673         
  11674         /* dfe3_bin(lane) = rd22_dfe_tap_3_bin (phy, lane) DSC_3_ADDR=0x8220  */
  11675         reg = 0x8226;
  11676         SOC_IF_ERROR_RETURN
  11677             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11678         regval = data16;
  11679         regval /= 64;
  11680         regval &= 63;
  11681         if (regval >= 32) {
  11682             regval -=64;
  11683         }
  11684         pDesc->dfe3_bin = regval;
  11685         
  11686         /* dfe4_bin(lane) = rd22_dfe_tap_4_bin (phy, lane) DSC_3_ADDR=0x8220  */
  11687         reg = 0x8227;
  11688         SOC_IF_ERROR_RETURN
  11689             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11690         regval = data16;
  11691         regval &= 31;
  11692         if (regval >= 16) {
  11693             regval -=32;
  11694         }
  11695         pDesc->dfe4_bin = regval;
  11696   
  11697         /* dfe5_bin(lane) = rd22_dfe_tap_5_bin (phy, lane) DSC_3_ADDR=0x8220  */
  11698         reg = 0x8227;
  11699         SOC_IF_ERROR_RETURN
  11700             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11701         regval = data16;
  11702         regval /= 32;
  11703         regval &= 31;
  11704         if (regval >= 16) {
  11705             regval -=32;
  11706         }
  11707         pDesc->dfe5_bin = regval;
  11708 
  11709         /* integ_reg(lane) = rd22_integ_reg (phy, lane) DSC_3_ADDR=0x8220  */
  11710         reg = 0x8220;
  11711         SOC_IF_ERROR_RETURN
  11712             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11713         regval = data16;
  11714         regval &= 65535;
  11715         if (regval >= 32768) {
  11716             regval -=65536;
  11717         }
  11718         regval /= 84;
  11719         pDesc->integ_reg = regval;
  11720 
  11721         /* integ_reg_xfer(lane) = rd22_integ_reg_xfer (phy, lane)   */
  11722         reg = 0x8221;
  11723         SOC_IF_ERROR_RETURN
  11724             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11725         regval = data16;
  11726         regval &= 65535;
  11727         if (regval >= 32768) {
  11728             regval -=65536;
  11729         }
  11730         pDesc->integ_reg_xfer = regval;
  11731 
  11732         /* clk90_offset(lane) = rd22_clk90_phase_offset (phy, lane)   */
  11733         reg = 0x8223;
  11734         SOC_IF_ERROR_RETURN
  11735             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11736         regval = data16;
  11737         regval /= 128;
  11738         regval &= 127;
  11739         pDesc->clk90_offset = regval;
  11740 
  11741         /* slicer_target(lane) = ((25*rd22_rx_thresh_sel (phy, lane)) + 125)   */
  11742         reg = 0x821c;
  11743         SOC_IF_ERROR_RETURN
  11744             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11745         regval = data16;
  11746         regval /= 32;
  11747         regval &= 3;
  11748         pDesc->slicer_target = regval * 25 + 125;
  11749 
  11750         /* offset_pe(lane) = rd22_slicer_offset_pe (phy, lane)   */
  11751         reg = 0x822c;
  11752         SOC_IF_ERROR_RETURN
  11753             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11754         regval = data16;
  11755         regval &= 63;
  11756         if (regval >= 32) {
  11757             regval -=64;
  11758         }
  11759         pDesc->offset_pe = regval;
  11760 
  11761         /* offset_ze(lane) = rd22_slicer_offset_ze (phy, lane)   */
  11762         reg = 0x822d;
  11763         SOC_IF_ERROR_RETURN
  11764             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11765         regval = data16;
  11766         regval &= 63;
  11767         if (regval >= 32) {
  11768             regval -=64;
  11769         }
  11770         pDesc->offset_ze = regval;
  11771 
  11772         /* offset_me(lane) = rd22_slicer_offset_me (phy, lane)   */
  11773         reg = 0x822e;
  11774         SOC_IF_ERROR_RETURN
  11775             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11776         regval = data16;
  11777         regval &= 63;
  11778         if (regval >= 32) {
  11779             regval -=64;
  11780         }
  11781         pDesc->offset_me = regval;
  11782 
  11783         /* offset_po(lane) = rd22_slicer_offset_po (phy, lane) */
  11784         reg = 0x822c;
  11785         SOC_IF_ERROR_RETURN
  11786             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11787         regval = data16;
  11788         regval /= 64;
  11789         regval &= 63;
  11790         if (regval >= 32) {
  11791             regval -=64;
  11792         }
  11793         pDesc->offset_po = regval;
  11794 
  11795         /* offset_zo(lane) = rd22_slicer_offset_zo (phy, lane) */
  11796         reg = 0x822d;
  11797         SOC_IF_ERROR_RETURN
  11798             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11799         regval = data16;
  11800         regval /= 64;
  11801         regval &= 63;
  11802         if (regval >= 32) {
  11803             regval -=64;
  11804         }
  11805         pDesc->offset_zo = regval;
  11806 
  11807         /* offset_mo(lane) = rd22_slicer_offset_mo (phy, lane) */
  11808         reg = 0x822e;
  11809         SOC_IF_ERROR_RETURN
  11810             (WC40_REG_READ(unit, pc, lanes[i], reg, &data16));
  11811         regval = data16;
  11812         regval /= 64;
  11813         regval &= 63;
  11814         if (regval >= 32) {
  11815             regval -=64;
  11816         }
  11817         pDesc->offset_mo = regval;
  11818     }
  11819 
  11820     /* 0x8058, bits [13:6].  */
  11821     SOC_IF_ERROR_RETURN
  11822             (WC40_REG_READ(unit, pc, LANE0_ACCESS, 0x8058, &data16));
  11823     data16 = (data16 >> 6) & 0xff;
  11824 
  11825     /* display */
  11826     LOG_CLI((BSL_META_U(unit,
  11827                         "\n\nDSC parameters for port %d\n\n"), port));
  11828     LOG_CLI((BSL_META_U(unit,
  11829                         "PLL Range: %d\n\n"),data16));
  11830 
  11831     LOG_CLI((BSL_META_U(unit,
  11832                         "LN  PPM PPM_XFR clk90_ofs PF SL_TRGT VGA BIAS DFE1 DFE2 "
  11833                         "DFE3 DFE4 DFE5 PREC MAIN POSTC MTRC PE   ZE   "
  11834                         "ME  PO  ZO  MO\n")));
  11835     for (i = 0; i < MAX_LANES; i++) {
  11836         pDesc = &uc_desc[i];
  11837         LOG_CLI((BSL_META_U(unit,
  11838                             "%02d %04d %07d %09d %04d %04d %04d %4s %04d %04d %04d %04d "
  11839                             "%04d %04d %04d %04d  %04d %04d %04d %2d %3d %3d %2d\n"),
  11840                  i, pDesc->integ_reg, pDesc->integ_reg_xfer,
  11841                  pDesc->clk90_offset,
  11842                  pDesc->pf_ctrl, pDesc->slicer_target,
  11843                  pDesc->vga_sum, pDesc->vga_bias_reduced,
  11844                  pDesc->dfe1_bin, pDesc->dfe2_bin,
  11845                  pDesc->dfe3_bin, pDesc->dfe4_bin,
  11846                  pDesc->dfe5_bin, pDesc->tx_pre_cursor,
  11847                  pDesc->tx_main, pDesc->tx_post_cursor,
  11848                  pDesc->postc_metric, pDesc->offset_pe,
  11849                  pDesc->offset_ze, pDesc->offset_me,
  11850                  pDesc->offset_po, pDesc->offset_zo, pDesc->offset_mo));
  11851 
  11852     }
  11853     return SOC_E_NONE;
  11854 
  11855 }
  11856 #endif
  11857 
  11858 /********   Eye Margin Diagnostic  **********/
  11859 
  11860 #ifndef __KERNEL__
  11861 #include <math.h> 
  11862 
  11863 /* #define BER_EXTRAP_SPD_UP */
  11864 #define MAX_LOOPS 47
  11865 #define MIN_RUNTIME  1  
  11866 #define INDEX_UNINITIALIZED  (-1)
  11867 #define SPD_UP_MAX_RUNTIME 64
  11868 #ifdef BER_EXTRAP_SPD_UP
  11869 #define MAX_RUNTIME SPD_UP_MAX_RUNTIME
  11870 #else
  11871 #define MAX_RUNTIME 256
  11872 #endif 
  11873 #define HI_CONFIDENCE_ERR_CNT 100    /* bit errors to determine high confidence */
  11874 #define LO_CONFIDENCE_MIN_ERR_CNT 10 /* bit errors, exit condition for low confidence */
  11875 #define HI_CONFIDENCE_MIN_ERR_CNT 20 /* bit errors exit condition for high confidence */
  11876 #define VEYE_UNIT 1.75
  11877 #define HEYE_UNIT 3.125
  11878 #define DSC1B0_UC_CTRLr 0x820e
  11879 #define WC_UTIL_MAX_ROUND_DIGITS (8) 
  11880 
  11881 typedef struct {
  11882     int total_errs[MAX_LOOPS];
  11883     int total_elapsed_time[MAX_LOOPS];
  11884     int mono_flags[MAX_LOOPS];
  11885     int max_loops;
  11886     int offset_max;
  11887     int veye_cnt;
  11888     uint32 rate;      /* frequency in KHZ */
  11889     int first_good_ber_idx;
  11890     int first_small_errcnt_idx;
  11891 } WC40_EYE_DIAG_INFOt;
  11892 
  11893 static char *eye_test_name_str[] = {"Vertical Eye","Right Eye","Left Eye"};
  11894 
  11895 STATIC int 
  11896 _wc40_veye_margin_data_get( int unit, int port, int lane, WC40_EYE_DIAG_INFOt *pInfo,int type); 
  11897 STATIC int  
  11898 _wc40_eye_margin_diagram_cal(WC40_EYE_DIAG_INFOt *pInfo,int type); 
  11899 STATIC int 
  11900 _wc40_eye_margin_ber_cal(WC40_EYE_DIAG_INFOt *pInfo,int type); 
  11901 
  11902 
  11903 #ifdef BROADCOM_DEBUG 
  11904 /* DEBUG function: manually construct a set of test data to test
  11905  * extrapolation algorithem. 
  11906  * type: 0 vertical eye, 1 horizontal right eye, 2 horizontal left eye
  11907  * max_offset: the slicer max offset, for example 23
  11908  * the clock rate is hardcoded to 10312500Khz
  11909  */ 
  11910 STATIC WC40_EYE_DIAG_INFOt wc40_eye_test_data;
  11911 
  11912 int wc40_eye_margin_test(int type, int max_offset) 
  11913 {
  11914     WC40_EYE_DIAG_INFOt *pInfo;
  11915     int cnt;
  11916 
  11917 /*
  11918  *  WC_UTIL_VEYE           0   vertical eye 
  11919  *  WC_UTIL_HEYE_R         1   horizontal right eye 
  11920  *  WC_UTIL_HEYE_L         2   horizontal left eye 
  11921 */
  11922 
  11923 
  11924     WC40_MEM_SET(&wc40_eye_test_data, 0, sizeof(wc40_eye_test_data));
  11925     pInfo = &wc40_eye_test_data;
  11926     pInfo->max_loops = MAX_LOOPS;
  11927     pInfo->offset_max = max_offset; /*24 */
  11928     cnt = 0;
  11929 
  11930     /* SFP-DAC test data from serdes team set 1 */
  11931     pInfo->total_errs[cnt]         = 9786;
  11932     pInfo->total_elapsed_time[cnt] = 1;
  11933     cnt++;
  11934     pInfo->total_errs[cnt]         = 10020;
  11935     pInfo->total_elapsed_time[cnt] = 1;
  11936     cnt++;
  11937     pInfo->total_errs[cnt]         = 8443;
  11938     pInfo->total_elapsed_time[cnt] = 1;
  11939     cnt++;
  11940     pInfo->total_errs[cnt]         = 8422;
  11941     pInfo->total_elapsed_time[cnt] = 1;
  11942     cnt++;
  11943     pInfo->total_errs[cnt]         = 8312;
  11944     pInfo->total_elapsed_time[cnt] = 1;
  11945     cnt++;
  11946     pInfo->total_errs[cnt]         = 144;
  11947     pInfo->total_elapsed_time[cnt] = 4;
  11948     cnt++;
  11949     pInfo->total_errs[cnt]         = 100;
  11950     pInfo->total_elapsed_time[cnt] = 8;
  11951     cnt++;
  11952     pInfo->total_errs[cnt]         = 107;
  11953     pInfo->total_elapsed_time[cnt] = 32;
  11954     cnt++;
  11955     pInfo->total_errs[cnt]         = 31;
  11956     pInfo->total_elapsed_time[cnt] = 64;
  11957     cnt++;
  11958     pInfo->total_errs[cnt]         = 3;
  11959     pInfo->total_elapsed_time[cnt] = 64;
  11960     cnt++;
  11961 
  11962     pInfo->veye_cnt   = cnt;
  11963     pInfo->rate   = 10312500;
  11964     pInfo->first_good_ber_idx = INDEX_UNINITIALIZED;
  11965     pInfo->first_small_errcnt_idx = INDEX_UNINITIALIZED;
  11966 
  11967     SOC_IF_ERROR_RETURN
  11968         (_wc40_eye_margin_ber_cal(pInfo,type)); 
  11969     SOC_IF_ERROR_RETURN
  11970         (_wc40_eye_margin_diagram_cal(pInfo,type));
  11971     return SOC_E_NONE;
  11972 }
  11973 #endif /* end debug function */
  11974 
  11975 int
  11976 wc40_eye_margin(int unit, soc_port_t port, int type)
  11977 {
  11978     phy_ctrl_t      *pc;
  11979     int lane_start;
  11980     int lane_end;
  11981     int i;
  11982     WC40_EYE_DIAG_INFOt veye_info[4];
  11983 
  11984     pc = INT_PHY_SW_STATE(unit, port);
  11985 
  11986     /* clear the memory */
  11987     WC40_MEM_SET(veye_info, 0, sizeof(veye_info));
  11988     for (i = 0; i < 4; i++) {
  11989          veye_info[i].first_good_ber_idx = INDEX_UNINITIALIZED;
  11990          veye_info[i].first_small_errcnt_idx = INDEX_UNINITIALIZED;
  11991     }
  11992 
  11993     if (pc->phy_mode == PHYCTRL_ONE_LANE_PORT || pc->phy_mode == PHYCTRL_SINGLE_LANE_IN_DUAL_PORT_MODE) {
  11994         lane_start = pc->lane_num;
  11995         lane_end   = lane_start;
  11996     } else if (pc->phy_mode == PHYCTRL_DUAL_LANE_PORT) {
  11997         lane_start = pc->lane_num;
  11998         lane_end   = lane_start + 1;
  11999     } else {
  12000         lane_start = 0;
  12001         lane_end   = 3;
  12002     }
  12003     LOG_CLI((BSL_META_U(unit,
  12004                         "\nPort %d : Start BER extrapolation for %s\n"),
  12005              port, eye_test_name_str[type]));
  12006     LOG_CLI((BSL_META_U(unit,
  12007                         "Port %d : Test time varies from a few minutes to "
  12008                         "over 20 minutes. " 
  12009                         "Please wait ...\n"), port));
  12010 
  12011     for (i = lane_start; i <= lane_end; i++) {
  12012         if (lane_start != lane_end) {
  12013             LOG_CLI((BSL_META_U(unit,
  12014                                 "\nStart test for lane %d\n"), i));
  12015         }
  12016         SOC_IF_ERROR_RETURN
  12017             (_wc40_veye_margin_data_get(unit,port,i,&veye_info[i],type));
  12018         SOC_IF_ERROR_RETURN
  12019             (_wc40_eye_margin_ber_cal(&veye_info[i],type)); 
  12020         SOC_IF_ERROR_RETURN
  12021             (_wc40_eye_margin_diagram_cal(&veye_info[i],type));
  12022     }
  12023 
  12024     return SOC_E_NONE;
  12025 }
  12026 int
  12027 _wc40_lane_prbs_rx_status_get(int unit, soc_port_t port, int lane, 
  12028                                           uint32 *value)
  12029 {
  12030     uint16      data;
  12031     int prbs_cfg;
  12032     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
  12033 
  12034     *value = 0;
  12035     if (DEV_CTRL_PTR(pc)->prbs.type == WC40_PRBS_TYPE_CL49) {
  12036         data = 0;
  12037         /* enable PRBS if not already. PRBS31 or PRBS9 */
  12038         prbs_cfg = TRUE;
  12039         SOC_IF_ERROR_RETURN
  12040             (READ_WC40_PCS_IEEE2BLK_PCS_TPCONTROLr(unit, pc, ln_access[lane], &data));
  12041         if (DEV_CTRL_PTR(pc)->prbs.poly == WC40_PRBS_CFG_POLY31) {
  12042             if (data == WC40_PRBS_CL49_POLY31) { /* prbs already in PRBS31 */
  12043                 prbs_cfg = FALSE;
  12044             }
  12045         } else {
  12046             DEV_CTRL_PTR(pc)->prbs.poly = WC40_PRBS_CFG_POLY31; /* only support PRBS31 for now*/
  12047         }
  12048 
  12049         if (prbs_cfg) {
  12050             SOC_IF_ERROR_RETURN
  12051                 (WRITE_WC40_PCS_IEEE2BLK_PCS_TPCONTROLr(unit, pc, ln_access[lane],
  12052                         WC40_PRBS_CL49_POLY31));
  12053         }
  12054 
  12055         SOC_IF_ERROR_RETURN
  12056             (READ_WC40_CL49_USERB0_STATUSr(unit,pc,ln_access[lane],&data));
  12057 
  12058         if (data & CL49_USERB0_STATUS_PRBS_LOCK_MASK) { /* PRBS lock */
  12059             /* check error count */
  12060             SOC_IF_ERROR_RETURN
  12061                 (READ_WC40_PCS_IEEE2BLK_PCS_TPERRCOUNTERr(unit,pc,ln_access[lane],&data));
  12062             *value = data;
  12063 
  12064         } else { /* PRBS not in sync */
  12065             *value = -1;
  12066         }
  12067         return SOC_E_NONE;
  12068     }
  12069 
  12070     /* Get status for all 4 lanes and check for sync
  12071      * 0x80b0, 0x80c0, 0x80d0, 0x80e0
  12072      */
  12073     SOC_IF_ERROR_RETURN
  12074         (WC40_REG_READ(unit, pc, LANE0_ACCESS, 0x80b0 + (0x10 * lane), &data));
  12075 
  12076     if (data == (RX0_ANARXSTATUS_PRBS_STATUS_PRBS_LOCK_BITS  <<
  12077                      RX0_ANARXSTATUS_PRBS_STATUS_PRBS_LOCK_SHIFT)) {
  12078         /* PRBS is in sync and error free */
  12079     } else if (!(data & RX0_ANARXSTATUS_PRBS_STATUS_PRBS_LOCK_MASK)) {
  12080         /* PRBS not in sync */
  12081         *value = -1;
  12082     } else if (data & RX0_ANARXSTATUS_PRBS_STATUS_PRBS_STKY_MASK) {
  12083         /* PRBS momentarily lose sync, error cnt not accurate */
  12084         *value = -2;
  12085     } else {
  12086         /* Get errors */
  12087         *value = data & RX0_ANARXSTATUS_PRBS_STATUS_PTBS_ERRORS_MASK;
  12088     }
  12089     return SOC_E_NONE;
  12090 }
  12091 
  12092 STATIC int 
  12093 _wc40_avg_vga_dfe( int unit, int port, int lane, int tapsel, int *avg_value) 
  12094 {
  12095     uint16 vga_frzval;
  12096     uint16 vga_frcfrz;
  12097     uint16 dfe_frzval;
  12098     uint16 dfe_frcfrz;
  12099     uint16 frzval;
  12100     uint16 frcfrz;
  12101     int val_min = 0;
  12102     int val_max = 0;
  12103     int val_avg;
  12104     int val_curr = 0;
  12105     uint16 avg_cnt;   
  12106     uint16 loop_var;
  12107     uint16 data16;
  12108     int rem;
  12109     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
  12110 
  12111    avg_cnt = 40;
  12112    val_avg = 0;
  12113 
  12114     SOC_IF_ERROR_RETURN
  12115         (READ_WC40_DSC2B0_ACQ_SM_CTRL1r(unit, pc, ln_access[lane], &data16));
  12116     vga_frzval = (data16 & DSC2B0_ACQ_SM_CTRL1_VGA_FRZVAL_MASK) >>
  12117                  DSC2B0_ACQ_SM_CTRL1_VGA_FRZVAL_SHIFT;
  12118     vga_frcfrz = (data16 & DSC2B0_ACQ_SM_CTRL1_VGA_FRCFRZ_MASK) >>
  12119                   DSC2B0_ACQ_SM_CTRL1_VGA_FRCFRZ_SHIFT;
  12120     dfe_frzval = (data16 & DSC2B0_ACQ_SM_CTRL1_DFE_FRZVAL_MASK) >>
  12121                   DSC2B0_ACQ_SM_CTRL1_DFE_FRZVAL_SHIFT;
  12122     dfe_frcfrz = (data16 & DSC2B0_ACQ_SM_CTRL1_DFE_FRCFRZ_MASK) >>
  12123                   DSC2B0_ACQ_SM_CTRL1_DFE_FRCFRZ_SHIFT;
  12124 
  12125    if (tapsel == 0) {
  12126        frzval = vga_frzval;
  12127        frcfrz = vga_frcfrz;
  12128        val_min = 47;
  12129        val_max = 0;
  12130    } else {
  12131        frzval = (dfe_frzval & (1 << (tapsel-1)))/(1 << (tapsel-1));
  12132        frcfrz = dfe_frcfrz; 
  12133        if (tapsel == 1) {
  12134            val_min = 63;
  12135            val_max = 0;
  12136        } else if ((tapsel == 2) || (tapsel == 3)) {
  12137            val_min = 31;
  12138            val_max = -31;
  12139        } else if ((tapsel == 4) || (tapsel == 5)) {
  12140            val_min = 15;
  12141            val_max = -15;
  12142        } 
  12143    } 
  12144 
  12145    if ((frzval == 1) && (frcfrz == 1)) {
  12146        avg_cnt = 1;
  12147    } 
  12148 
  12149    /* Const DSC_3_ADDR = &H8220 */
  12150    for (loop_var = 0; loop_var < avg_cnt; loop_var++) {
  12151        switch(tapsel) {
  12152            case 0:
  12153                SOC_IF_ERROR_RETURN
  12154                    (READ_WC40_DSC3B0_DFE_VGA_STATUS0r(unit, pc,
  12155                        ln_access[lane], &data16));
  12156                val_curr = data16 & DSC3B0_DFE_VGA_STATUS0_VGA_SUM_MASK;
  12157                break;
  12158 
  12159            case 1:
  12160                SOC_IF_ERROR_RETURN
  12161                    (READ_WC40_DSC3B0_DFE_VGA_STATUS0r(unit, pc,
  12162                        ln_access[lane], &data16));
  12163                val_curr = (data16 & DSC3B0_DFE_VGA_STATUS0_DFE_TAP_1_BIN_MASK) >>
  12164                           DSC3B0_DFE_VGA_STATUS0_DFE_TAP_1_BIN_SHIFT;
  12165                break;
  12166 
  12167            case 2:
  12168                SOC_IF_ERROR_RETURN
  12169                    (READ_WC40_DSC3B0_DFE_VGA_STATUS1r(unit, pc,
  12170                        ln_access[lane], &data16));
  12171                val_curr = data16 & DSC3B0_DFE_VGA_STATUS1_DFE_TAP_2_BIN_MASK;
  12172                if (val_curr >= 32) {
  12173                    val_curr -= 64;
  12174                }
  12175                break;
  12176 
  12177            case 3:
  12178                SOC_IF_ERROR_RETURN
  12179                    (READ_WC40_DSC3B0_DFE_VGA_STATUS1r(unit, pc,
  12180                        ln_access[lane], &data16));
  12181                val_curr = (data16 & DSC3B0_DFE_VGA_STATUS1_DFE_TAP_3_BIN_MASK) >>
  12182                           DSC3B0_DFE_VGA_STATUS1_DFE_TAP_3_BIN_SHIFT;
  12183                if (val_curr >= 32) {
  12184                    val_curr -= 64;
  12185                }
  12186                break;
  12187 
  12188            case 4:
  12189                SOC_IF_ERROR_RETURN
  12190                    (READ_WC40_DSC3B0_DFE_VGA_STATUS2r(unit, pc,
  12191                        ln_access[lane], &data16));
  12192                val_curr = data16 & DSC3B0_DFE_VGA_STATUS2_DFE_TAP_4_BIN_MASK;
  12193                if (val_curr >= 16) {
  12194                    val_curr -= 32;
  12195                }
  12196                break;
  12197 
  12198            case 5:
  12199                SOC_IF_ERROR_RETURN
  12200                    (READ_WC40_DSC3B0_DFE_VGA_STATUS2r(unit, pc,
  12201                        ln_access[lane], &data16));
  12202                val_curr = (data16 & DSC3B0_DFE_VGA_STATUS2_DFE_TAP_5_BIN_MASK) >>
  12203                           DSC3B0_DFE_VGA_STATUS2_DFE_TAP_5_BIN_SHIFT;
  12204                if (val_curr >= 16) {
  12205                    val_curr -= 32;
  12206                }
  12207                break;
  12208 
  12209            default:
  12210                break;
  12211       } 
  12212 
  12213       LOG_INFO(BSL_LS_SOC_PHY,
  12214                (BSL_META_U(unit,
  12215                            "WC_VEYE : val_curr = %d, val_avg = %d, tap_select = %d\n"), 
  12216                 val_curr,val_avg,tapsel));
  12217       val_avg = (val_avg + val_curr);
  12218 
  12219       if (val_curr < val_min) {
  12220           val_min = val_curr;
  12221       }
  12222 
  12223       if (val_curr > val_max) {
  12224           val_max = val_curr;
  12225       } 
  12226       /* delay 20ms */
  12227       sal_usleep(20000);
  12228    } /* end for loop */ 
  12229 
  12230    /* average value */
  12231    rem = val_avg%avg_cnt;
  12232    val_avg = val_avg/avg_cnt;
  12233    
  12234    /* add one if remainder is more than half */ 
  12235    val_avg += (2*rem)/avg_cnt;
  12236    *avg_value = val_avg;
  12237 
  12238    return SOC_E_NONE;
  12239 }
  12240 
  12241 STATIC int 
  12242 _wc40_veye_margin_data_get( int unit, int port, int lane, WC40_EYE_DIAG_INFOt *pInfo,int type) 
  12243 {
  12244     int runtime_loop;
  12245     int max_runtime_loop;
  12246     int curr_runtime = 0;
  12247     int offset[MAX_LOOPS];
  12248     int offset_max;
  12249     int loop_var;
  12250     int veye_cnt;
  12251     int hi_confidence_cnt;
  12252     uint32 prbs_status;
  12253     phy_ctrl_t *pc;
  12254     int rv = SOC_E_NONE;
  12255     uint16 data16;
  12256     uint16 vga_frzval;
  12257     uint16 vga_frcfrz;
  12258     uint16 dfe_frzval;
  12259     uint16 dfe_frcfrz;
  12260     int pll_div[16] = {32,36,40,42,48,50,52,54,60,64,66,68,80,120,200,240};
  12261     int ref_clk_freq[8] = {25000,100000,125000,156250,187500,161250,50000,106250};
  12262     uint16 clk90_p_offset;
  12263     int dfe_vga[6];
  12264     int tmp;
  12265     int max_total_time;
  12266     int prbs_stky_flag;
  12267     int prbs_stky_cnt;
  12268     int max_stky_cnt;
  12269 
  12270 
  12271     pc = INT_PHY_SW_STATE(unit, port);
  12272 
  12273     /* check what rate the test will run for */
  12274     SOC_IF_ERROR_RETURN
  12275         (READ_WC40_PLL_ANAPLLSTATUSr(unit,pc,ln_access[0],&data16));
  12276 
  12277     /* get the ref_clk divider first */
  12278     pInfo->rate = pll_div[data16 & PLL_ANAPLLSTATUS_PLL_MODE_AFE_MASK];
  12279 
  12280     /* get the ref_clk frequency frequency */    
  12281     SOC_IF_ERROR_RETURN
  12282         (READ_WC40_SERDESDIGITAL_MISC1r(unit,pc,ln_access[0],&data16));
  12283     data16 = (data16 >> SERDESDIGITAL_MISC1_REFCLK_SEL_SHIFT) & 7;
  12284     pInfo->rate *= ref_clk_freq[data16];
  12285 
  12286     max_total_time = MAX_RUNTIME;
  12287 
  12288     /* max loop_cnt for BER test with test time doubling every iteration */
  12289     /* max_runtime_loop = log(MAX_RUNTIME/MIN_RUNTIME)/log(2); */  
  12290     max_runtime_loop = 80;  
  12291     pInfo->max_loops = MAX_LOOPS;
  12292 
  12293     LOG_INFO(BSL_LS_SOC_PHY,
  12294              (BSL_META_U(unit,
  12295                          "WC_VEYE : max_runtime_loop: %d u=%d p=%d\n"), 
  12296               max_runtime_loop,unit, port));
  12297 
  12298     /* Initialize BER array */
  12299     for( loop_var = 0; loop_var < pInfo->max_loops; loop_var++ ) {
  12300         pInfo->total_errs[loop_var] = 0;
  12301     }
  12302 
  12303     /* 0x820d[0]=1 enable diagnostic */ 
  12304     SOC_IF_ERROR_RETURN
  12305         (MODIFY_WC40_DSC1B0_DSC_DIAG_CTRL0r(unit, pc, ln_access[lane], 
  12306                DSC1B0_DSC_DIAG_CTRL0_DIAGNOSTICS_EN_MASK,
  12307                DSC1B0_DSC_DIAG_CTRL0_DIAGNOSTICS_EN_MASK));
  12308 
  12309     /* save original DFE/VGA settings */
  12310     SOC_IF_ERROR_RETURN
  12311         (READ_WC40_DSC2B0_ACQ_SM_CTRL1r(unit, pc, ln_access[lane], &data16));
  12312     vga_frzval = data16 & DSC2B0_ACQ_SM_CTRL1_VGA_FRZVAL_MASK; 
  12313     vga_frcfrz = data16 & DSC2B0_ACQ_SM_CTRL1_VGA_FRCFRZ_MASK;
  12314     dfe_frzval = data16 & DSC2B0_ACQ_SM_CTRL1_DFE_FRZVAL_MASK; 
  12315     dfe_frcfrz = data16 & DSC2B0_ACQ_SM_CTRL1_DFE_FRCFRZ_MASK;
  12316 
  12317     for (loop_var = 0; loop_var <= 5; loop_var++) {
  12318         (void)_wc40_avg_vga_dfe (unit, port,lane, loop_var,&dfe_vga[loop_var]);
  12319         if (loop_var == 0) {
  12320             /* freeze VGA */
  12321             SOC_IF_ERROR_RETURN
  12322                 (MODIFY_WC40_DSC2B0_ACQ_SM_CTRL1r(unit, pc, ln_access[lane], 
  12323                       DSC2B0_ACQ_SM_CTRL1_VGA_FRZVAL_MASK |
  12324                       DSC2B0_ACQ_SM_CTRL1_VGA_FRCFRZ_MASK,
  12325                       DSC2B0_ACQ_SM_CTRL1_VGA_FRZVAL_MASK |
  12326                       DSC2B0_ACQ_SM_CTRL1_VGA_FRCFRZ_MASK));
  12327 
  12328             /* select VGA */
  12329             SOC_IF_ERROR_RETURN
  12330                 (MODIFY_WC40_DSC1B0_DFE_VGA_CTRL2r(unit, pc, ln_access[lane], 
  12331                   loop_var << DSC1B0_DFE_VGA_CTRL2_DFE_VGA_WRITE_TAPSEL_SHIFT,
  12332                   DSC1B0_DFE_VGA_CTRL2_DFE_VGA_WRITE_TAPSEL_MASK));
  12333 
  12334             /* set the VGA value */
  12335             /* coverity[uninit_use:FALSE] */
  12336             SOC_IF_ERROR_RETURN
  12337                 (MODIFY_WC40_DSC1B0_DFE_VGA_CTRL2r(unit, pc, ln_access[lane], 
  12338                    dfe_vga[loop_var] << DSC1B0_DFE_VGA_CTRL2_DFE_VGA_WRITE_VAL_SHIFT,
  12339                   DSC1B0_DFE_VGA_CTRL2_DFE_VGA_WRITE_VAL_MASK));
  12340 
  12341             /* VGA/DFE write enable */
  12342             SOC_IF_ERROR_RETURN
  12343                 (MODIFY_WC40_DSC1B0_DFE_VGA_CTRL2r(unit, pc, ln_access[lane], 
  12344                   DSC1B0_DFE_VGA_CTRL2_DFE_VGA_WRITE_EN_MASK,
  12345                   DSC1B0_DFE_VGA_CTRL2_DFE_VGA_WRITE_EN_MASK));
  12346 
  12347             /* VGA/DFE write disable */
  12348             SOC_IF_ERROR_RETURN
  12349                 (MODIFY_WC40_DSC1B0_DFE_VGA_CTRL2r(unit, pc, ln_access[lane], 
  12350                   0,
  12351                   DSC1B0_DFE_VGA_CTRL2_DFE_VGA_WRITE_EN_MASK));
  12352         }
  12353     }
  12354     /* freeze the DFE */ 
  12355     SOC_IF_ERROR_RETURN
  12356         (MODIFY_WC40_DSC2B0_ACQ_SM_CTRL1r(unit, pc, ln_access[lane], 
  12357           (0x1f << DSC2B0_ACQ_SM_CTRL1_DFE_FRZVAL_SHIFT) |
  12358           DSC2B0_ACQ_SM_CTRL1_DFE_FRCFRZ_MASK,
  12359           DSC2B0_ACQ_SM_CTRL1_DFE_FRZVAL_MASK |
  12360           DSC2B0_ACQ_SM_CTRL1_DFE_FRCFRZ_MASK));
  12361 
  12362     for (loop_var = 1; loop_var <= 5; loop_var++) {
  12363         /* set DFE taps */
  12364         SOC_IF_ERROR_RETURN
  12365             (MODIFY_WC40_DSC1B0_DFE_VGA_CTRL2r(unit, pc, ln_access[lane], 
  12366               loop_var << DSC1B0_DFE_VGA_CTRL2_DFE_VGA_WRITE_TAPSEL_SHIFT,
  12367               DSC1B0_DFE_VGA_CTRL2_DFE_VGA_WRITE_TAPSEL_MASK));
  12368 
  12369         /* set the DFE tap value */
  12370         SOC_IF_ERROR_RETURN
  12371             (MODIFY_WC40_DSC1B0_DFE_VGA_CTRL2r(unit, pc, ln_access[lane], 
  12372                dfe_vga[loop_var] << DSC1B0_DFE_VGA_CTRL2_DFE_VGA_WRITE_VAL_SHIFT,
  12373               DSC1B0_DFE_VGA_CTRL2_DFE_VGA_WRITE_VAL_MASK));
  12374 
  12375         /* VGA/DFE write enable */
  12376         SOC_IF_ERROR_RETURN
  12377             (MODIFY_WC40_DSC1B0_DFE_VGA_CTRL2r(unit, pc, ln_access[lane], 
  12378               DSC1B0_DFE_VGA_CTRL2_DFE_VGA_WRITE_EN_MASK,
  12379               DSC1B0_DFE_VGA_CTRL2_DFE_VGA_WRITE_EN_MASK));
  12380 
  12381         /* VGA/DFE write disable */
  12382         SOC_IF_ERROR_RETURN
  12383             (MODIFY_WC40_DSC1B0_DFE_VGA_CTRL2r(unit, pc, ln_access[lane], 
  12384               0,
  12385               DSC1B0_DFE_VGA_CTRL2_DFE_VGA_WRITE_EN_MASK));
  12386     }
  12387 
  12388     /* display the average value written to VGA/DFE */ 
  12389     LOG_INFO(BSL_LS_SOC_PHY,
  12390              (BSL_META_U(unit,
  12391                          "WC_EYE avg dfe/vga: u=%d p=%d, VGA:0x%x, dfe1:0x%x, dfe2:0x%x, dfe3:0x%x, "
  12392                          "dfe4:0x%x, dfe5:0x%x\n"), unit, port, dfe_vga[0],dfe_vga[1],
  12393               dfe_vga[2],dfe_vga[3],dfe_vga[4],dfe_vga[5]));
  12394 
  12395 #if 0   
  12396     /* first time, uC seems always indicating not ready */
  12397     /* wait for uC ready for command bit7 */
  12398     rv = _phy_wc40_regbit_set_wait_check(pc,DSC1B0_UC_CTRLr,
  12399                      DSC1B0_UC_CTRL_READY_FOR_CMD_MASK,1,WC40_PLL_WAIT,ln_access[lane]);
  12400 
  12401     if (rv == SOC_E_TIMEOUT) {
  12402         LOG_WARN(BSL_LS_SOC_PHY,
  12403                  (BSL_META_U(unit,
  12404                              "WC_EYE : uController not ready!!!: u=%d p=%d\n"), unit, port));
  12405         return (SOC_E_TIMEOUT);
  12406     }
  12407 #endif
  12408 
  12409     if (type == WC_UTIL_HEYE_L) {
  12410         /* Write max to get left eye offset range */
  12411         SOC_IF_ERROR_RETURN
  12412             (WRITE_WC40_DSC1B0_UC_CTRLr(unit, pc, ln_access[lane], 0x7f02));
  12413 
  12414     } else if (type == WC_UTIL_HEYE_R) {
  12415         /* Write min to get right eye offset range */
  12416         SOC_IF_ERROR_RETURN
  12417             (WRITE_WC40_DSC1B0_UC_CTRLr(unit, pc, ln_access[lane],0x8002));
  12418 
  12419     } else {  /* vertical eye */
  12420         /* write max to get vertical offset range */
  12421         SOC_IF_ERROR_RETURN
  12422             (WRITE_WC40_DSC1B0_UC_CTRLr(unit, pc, ln_access[lane], 0x7f03));
  12423     }
  12424 
  12425     /* wait for uC ready for command:  bit7=1 */
  12426     rv = _phy_wc40_regbit_set_wait_check(pc,DSC1B0_UC_CTRLr,
  12427                      DSC1B0_UC_CTRL_READY_FOR_CMD_MASK,1,WC40_PLL_WAIT,ln_access[lane]);
  12428 
  12429     if (rv == SOC_E_TIMEOUT) {
  12430         LOG_WARN(BSL_LS_SOC_PHY,
  12431                  (BSL_META_U(unit,
  12432                              "WC_EYE : uController not ready pass 1!!!: u=%d p=%d\n"), 
  12433                   unit, port));
  12434         return (SOC_E_TIMEOUT);
  12435     }
  12436 
  12437     /* read out the max value */
  12438     SOC_IF_ERROR_RETURN
  12439         (READ_WC40_DSC1B0_UC_CTRLr(unit, pc, ln_access[lane], &data16));
  12440     offset_max = (data16 >> 8) & 0xff;
  12441 
  12442     if (type == WC_UTIL_HEYE_L || type == WC_UTIL_HEYE_R) {
  12443         offset_max -= 4;
  12444         pInfo->offset_max = offset_max;
  12445     } else {
  12446         pInfo->offset_max = offset_max;
  12447     }   
  12448     
  12449     SOC_IF_ERROR_RETURN
  12450         (READ_WC40_DSC2B0_ACQ_SM_CTRL1r(unit, pc, ln_access[lane], &data16));
  12451 
  12452     LOG_INFO(BSL_LS_SOC_PHY,
  12453              (BSL_META_U(unit,
  12454                          "WC_EYE : offset_max %d DSC2B0_ctrl 0x%x u=%d p=%d\n"), 
  12455               offset_max,data16,unit, port));
  12456 
  12457     if (offset_max >= MAX_LOOPS) {
  12458         LOG_ERROR(BSL_LS_SOC_PHY,
  12459                   (BSL_META_U(unit,
  12460                               "WC_EYE ERROR: offset_max %d greater than MAX %d  u=%d p=%d\n"), 
  12461                    offset_max,MAX_LOOPS,unit, port));
  12462         return SOC_E_NONE;
  12463     }
  12464  
  12465     sal_usleep(10000);  /* 10ms */
  12466 
  12467     hi_confidence_cnt = 0;
  12468     veye_cnt = 0;
  12469 
  12470     for (loop_var = 0; loop_var < offset_max; loop_var++) { 
  12471         offset[loop_var] = offset_max-loop_var;
  12472         veye_cnt += 1;
  12473         /*
  12474          * Set a offset
  12475          */
  12476         if (type == WC_UTIL_HEYE_R) {
  12477             data16 =-offset[loop_var];
  12478         } else {
  12479             data16 = offset[loop_var];
  12480         }
  12481         /* write vertical offset */
  12482         SOC_IF_ERROR_RETURN
  12483             (MODIFY_WC40_DSC1B0_UC_CTRLr(unit, pc, ln_access[lane], 
  12484                       data16 << DSC1B0_UC_CTRL_SUPPLEMENT_INFO_SHIFT,
  12485                       DSC1B0_UC_CTRL_SUPPLEMENT_INFO_MASK));
  12486 
  12487         /* 0x8223 register read out */
  12488         SOC_IF_ERROR_RETURN
  12489             (READ_WC40_DSC3B0_PI_STATUS0r(unit, pc, ln_access[lane], &clk90_p_offset));
  12490         clk90_p_offset >>= 7;
  12491         clk90_p_offset &= 0x7f;
  12492         tmp = (short)data16;
  12493         LOG_INFO(BSL_LS_SOC_PHY,
  12494                  (BSL_META_U(unit,
  12495                              "Starting BER measurement at offset: %d clk90_p_offset: 0x%x u=%d p=%d\n"),
  12496                   tmp,clk90_p_offset,unit, port));
  12497 
  12498         if (type == WC_UTIL_HEYE_L || type == WC_UTIL_HEYE_R) {
  12499             data16 = 2;
  12500         } else {
  12501             data16 = 3;
  12502         }
  12503 
  12504         /* set offset cmd */
  12505         SOC_IF_ERROR_RETURN
  12506             (MODIFY_WC40_DSC1B0_UC_CTRLr(unit, pc, ln_access[lane], 
  12507                   data16,
  12508                   DSC1B0_UC_CTRL_GP_UC_REQ_MASK));
  12509 
  12510         /* wait for uC ready for command:  bit7=1 */
  12511         rv = _phy_wc40_regbit_set_wait_check(pc,DSC1B0_UC_CTRLr,
  12512                          DSC1B0_UC_CTRL_READY_FOR_CMD_MASK,1,WC40_PLL_WAIT,ln_access[lane]);
  12513 
  12514         if (rv == SOC_E_TIMEOUT) {
  12515             LOG_WARN(BSL_LS_SOC_PHY,
  12516                      (BSL_META_U(unit,
  12517                                  "WC_EYE : uC waits for offset fail!!!: u=%d p=%d\n"), 
  12518                       unit, port));
  12519             return (SOC_E_TIMEOUT);
  12520         }
  12521 
  12522         pInfo->total_errs[loop_var] = 0;
  12523         pInfo->total_elapsed_time[loop_var] = 0;
  12524 
  12525         /* PRBS should be enabled before this function called. clear PRBS error. read a few times */
  12526         SOC_IF_ERROR_RETURN
  12527             ( _wc40_lane_prbs_rx_status_get(unit,port, lane,&prbs_status));
  12528         SOC_IF_ERROR_RETURN
  12529             ( _wc40_lane_prbs_rx_status_get(unit,port, lane,&prbs_status));
  12530         SOC_IF_ERROR_RETURN
  12531             ( _wc40_lane_prbs_rx_status_get(unit,port, lane,&prbs_status));
  12532 
  12533         for (runtime_loop = 0; runtime_loop <= max_runtime_loop; runtime_loop++) {
  12534             if (runtime_loop == 0) {
  12535                 curr_runtime = 1 * MIN_RUNTIME;
  12536             } else if (curr_runtime < (4 * MIN_RUNTIME)) {
  12537                 curr_runtime = (1 << (runtime_loop - 1)) * MIN_RUNTIME;
  12538             }
  12539             LOG_INFO(BSL_LS_SOC_PHY,
  12540                      (BSL_META_U(unit,
  12541                                  "Starting prbs run for %d seconds : u=%d p=%d\n"), curr_runtime,
  12542                       unit, port));
  12543             /* XXX total_errs[loop_var] +=Round(check_prbs(phy, lane, curr_runtime)/2);*/
  12544 
  12545             prbs_stky_flag = 1;
  12546             prbs_stky_cnt = 0;
  12547             if (curr_runtime < 4) {
  12548                 max_stky_cnt = 4;
  12549             } else {
  12550                 max_stky_cnt = 2;
  12551             }
  12552 
  12553             while (prbs_stky_flag) {
  12554                 /* wait for specified amount of time to collect the PRBS error */
  12555                 sal_usleep(curr_runtime * 1000000);
  12556 
  12557                 SOC_IF_ERROR_RETURN
  12558                     ( _wc40_lane_prbs_rx_status_get(unit,port, lane,&prbs_status));
  12559 
  12560                 prbs_stky_flag = 0;
  12561                 if (prbs_status == -1) { /* not lock */
  12562                       LOG_WARN(BSL_LS_SOC_PHY,
  12563                                (BSL_META_U(unit,
  12564                                            "PRBS not locked, loop_num %d status=%d u=%d p=%d\n"), 
  12565                                 loop_var,prbs_status,unit, port));
  12566                     prbs_status = 0x7fff;  /* max error */
  12567                 } else if (prbs_status == -2) {
  12568                       LOG_WARN(BSL_LS_SOC_PHY,
  12569                                (BSL_META_U(unit,
  12570                                            "PRBS momentarily lost lock, loop_num %d u=%d p=%d\n"), 
  12571                                 loop_var,unit, port));
  12572                     /* legacy PRBS momentarily lose link, retry limited times */
  12573                     prbs_stky_cnt += 1;
  12574                     if (prbs_stky_cnt < max_stky_cnt) { 
  12575                         prbs_stky_flag = 1;
  12576                     } else {
  12577                         prbs_status = 0x7fff; /* default if retry fails */
  12578                     }
  12579                 }
  12580             }
  12581  
  12582             pInfo->total_errs[loop_var] +=  prbs_status/2;
  12583             pInfo->total_elapsed_time[loop_var] +=  curr_runtime;
  12584 
  12585             if ((pInfo->total_errs[loop_var] >= HI_CONFIDENCE_ERR_CNT) ||
  12586                 (pInfo->total_elapsed_time[loop_var] >= max_total_time)) {
  12587                  LOG_INFO(BSL_LS_SOC_PHY,
  12588                           (BSL_META_U(unit,
  12589                                       "WC_EYE: done PRBS err count: u=%d p=%d, total_err: %d"
  12590                                       " elapsed_time: %d, loop_num: %d\n"), unit, port,
  12591                            pInfo->total_errs[loop_var],pInfo->total_elapsed_time[loop_var],loop_var));
  12592                 break;
  12593             }
  12594         }
  12595 
  12596         /* Determine high-confidence iterations */
  12597         if (pInfo->total_errs[loop_var] >= HI_CONFIDENCE_ERR_CNT) {
  12598             hi_confidence_cnt = hi_confidence_cnt + 1;
  12599         } 
  12600 
  12601         if (((hi_confidence_cnt >= 2) && (pInfo->total_errs[loop_var] < 
  12602              HI_CONFIDENCE_MIN_ERR_CNT)) || 
  12603             ((hi_confidence_cnt <  2) && 
  12604              (pInfo->total_errs[loop_var] < LO_CONFIDENCE_MIN_ERR_CNT)) ) {
  12605              break;  /* exit for loop */
  12606         }
  12607     }   /* for loop_var */
  12608 
  12609     /* Undo setup */
  12610     if (type == WC_UTIL_HEYE_L || type == WC_UTIL_HEYE_R) {
  12611         data16 = 2;
  12612     } else {
  12613         data16 = 3;
  12614     }
  12615  
  12616     /* set vertical offset back to 0 */
  12617     SOC_IF_ERROR_RETURN
  12618         (WRITE_WC40_DSC1B0_UC_CTRLr(unit, pc, ln_access[lane], data16));
  12619 
  12620     /* wait for uC ready for command:  bit7=1 */
  12621     rv = _phy_wc40_regbit_set_wait_check(pc,DSC1B0_UC_CTRLr,
  12622                      DSC1B0_UC_CTRL_READY_FOR_CMD_MASK,1,WC40_PLL_WAIT,ln_access[lane]);
  12623 
  12624     if (rv == SOC_E_TIMEOUT) {
  12625         LOG_WARN(BSL_LS_SOC_PHY,
  12626                  (BSL_META_U(unit,
  12627                              "WC_VEYE : uC waits for offset=0 fail!!!: u=%d p=%d\n"),
  12628                   unit, port));
  12629         return (SOC_E_TIMEOUT);
  12630     }
  12631 
  12632     SOC_IF_ERROR_RETURN
  12633         (MODIFY_WC40_DSC2B0_ACQ_SM_CTRL1r(unit, pc, ln_access[lane],
  12634                       vga_frzval,
  12635                       DSC2B0_ACQ_SM_CTRL1_VGA_FRZVAL_MASK));
  12636     SOC_IF_ERROR_RETURN
  12637         (MODIFY_WC40_DSC2B0_ACQ_SM_CTRL1r(unit, pc, ln_access[lane],
  12638                       dfe_frzval,
  12639                       DSC2B0_ACQ_SM_CTRL1_DFE_FRZVAL_MASK));
  12640     SOC_IF_ERROR_RETURN
  12641         (MODIFY_WC40_DSC2B0_ACQ_SM_CTRL1r(unit, pc, ln_access[lane],
  12642                       vga_frcfrz,
  12643                       DSC2B0_ACQ_SM_CTRL1_VGA_FRCFRZ_MASK));
  12644     SOC_IF_ERROR_RETURN
  12645         (MODIFY_WC40_DSC2B0_ACQ_SM_CTRL1r(unit, pc, ln_access[lane],
  12646                       dfe_frcfrz,
  12647                       DSC2B0_ACQ_SM_CTRL1_DFE_FRCFRZ_MASK));
  12648 
  12649     /* disable diagnostics */
  12650     SOC_IF_ERROR_RETURN
  12651         (MODIFY_WC40_DSC1B0_DSC_DIAG_CTRL0r(unit, pc, ln_access[lane],
  12652                0,
  12653                DSC1B0_DSC_DIAG_CTRL0_DIAGNOSTICS_EN_MASK));
  12654 
  12655     /* Clear prbs monitor */
  12656     SOC_IF_ERROR_RETURN
  12657         ( _wc40_lane_prbs_rx_status_get(unit,port, lane,&prbs_status));
  12658 
  12659     pInfo->veye_cnt = veye_cnt;
  12660 
  12661     return SOC_E_NONE;
  12662 }
  12663 
  12664 #ifdef COMPILER_HAS_DOUBLE
  12665 STATIC COMPILER_DOUBLE
  12666 _wc40_util_round_real( COMPILER_DOUBLE original_value, int decimal_places ) 
  12667 {
  12668     COMPILER_DOUBLE shift_digits[WC_UTIL_MAX_ROUND_DIGITS+1] = { 0.0, 10.0, 100.0, 1000.0, 
  12669                           10000.0, 100000.0, 1000000.0, 10000000.0, 100000000.0 };
  12670     COMPILER_DOUBLE shifted;
  12671     COMPILER_DOUBLE rounded;   
  12672     if (decimal_places > WC_UTIL_MAX_ROUND_DIGITS ) {
  12673         LOG_CLI((BSL_META("ERROR: Maximum digits to the right of decimal for rounding "
  12674                           "exceeded. Max %d, requested %d\n"), 
  12675                  WC_UTIL_MAX_ROUND_DIGITS, decimal_places));
  12676         return 0.0;
  12677     } 
  12678     /* shift to preserve the desired digits to the right of the decimal */   
  12679     shifted = original_value * shift_digits[decimal_places];
  12680 
  12681     /* convert to integer and back to COMPILER_DOUBLE to truncate undesired precision */
  12682     shifted = (COMPILER_DOUBLE)(floor(shifted+0.5));
  12683 
  12684     /* shift back to place decimal point correctly */   
  12685     rounded = shifted / shift_digits[decimal_places];
  12686     return rounded;
  12687 }
  12688 #endif
  12689 /*
  12690  * enable PRBS31 on both ports before executing this function
  12691  * Example:
  12692  * phy prbs xe0,xe1 set mode=hc p=3
  12693  */
  12694 STATIC int 
  12695 _wc40_eye_margin_ber_cal(WC40_EYE_DIAG_INFOt *pInfo, int type) 
  12696 {
  12697 #ifdef COMPILER_HAS_DOUBLE
  12698 
  12699     COMPILER_DOUBLE bers[MAX_LOOPS]; /* computed bit error rate */
  12700     COMPILER_DOUBLE margins[MAX_LOOPS]; /* Eye margin @ each measurement*/
  12701     int loop_var;
  12702     COMPILER_DOUBLE eye_unit;
  12703     COMPILER_DOUBLE curr_ber_log;
  12704     COMPILER_DOUBLE prev_ber_log = 0;
  12705     COMPILER_DOUBLE good_ber_level = -7.8;
  12706 
  12707     /* Initialize BER array */
  12708     for( loop_var = 0; loop_var < MAX_LOOPS; loop_var++ ) {
  12709         bers[loop_var] = 0.0;
  12710     }
  12711 
  12712     if (type == WC_UTIL_HEYE_L || type == WC_UTIL_HEYE_R) {
  12713         eye_unit = HEYE_UNIT;
  12714     } else {
  12715         eye_unit = VEYE_UNIT;
  12716     }
  12717  
  12718     LOG_INFO(BSL_LS_SOC_PHY,
  12719              (BSL_META("\nBER measurement at each offset, num_data_points: %d\n"),
  12720 pInfo->veye_cnt));
  12721 
  12722     for (loop_var = 0; loop_var < pInfo->veye_cnt; loop_var++) { 
  12723         margins[loop_var] = (pInfo->offset_max-loop_var)*eye_unit;
  12724         LOG_INFO(BSL_LS_SOC_PHY,
  12725                  (BSL_META("BER measurement at offset: %f\n"), margins[loop_var]));
  12726              
  12727         /* Compute BER */
  12728         if (pInfo->total_errs[loop_var] == 0) { 
  12729             bers[loop_var] = 1.0/(COMPILER_DOUBLE)pInfo->total_elapsed_time[loop_var]/pInfo->rate;
  12730             bers[loop_var] /= 1000;
  12731 
  12732             LOG_WARN(BSL_LS_SOC_PHY,
  12733                      (BSL_META("BER @ %04f %% = 1e%04f (%d errors in %d seconds)\n"),
  12734 (COMPILER_DOUBLE)((pInfo->offset_max-loop_var)*eye_unit), 
  12735                       1.0*(log10(bers[loop_var])),
  12736                       pInfo->total_errs[loop_var],
  12737                       pInfo->total_elapsed_time[loop_var]));
  12738         } else { 
  12739             bers[loop_var] = (COMPILER_DOUBLE)(pInfo->total_errs[loop_var])/
  12740                              (COMPILER_DOUBLE)pInfo->total_elapsed_time[loop_var]/pInfo->rate;
  12741 
  12742             /* the rate unit is KHZ, add -3(log10(1/1000)) for actual display  */
  12743             bers[loop_var] /= 1000;
  12744             LOG_WARN(BSL_LS_SOC_PHY,
  12745                      (BSL_META("BER @ %2.2f%% = 1e%2.2f (%d errors in %d seconds)\n"),
  12746 (pInfo->offset_max-loop_var)*eye_unit,
  12747                       log10(bers[loop_var]),
  12748                       pInfo->total_errs[loop_var],
  12749                       pInfo->total_elapsed_time[loop_var]));
  12750         }
  12751         curr_ber_log = log10(bers[loop_var]);
  12752 
  12753         /* Detect and record nonmonotonic data points */
  12754         if ((loop_var > 0) && (curr_ber_log > prev_ber_log)) {
  12755             pInfo->mono_flags[loop_var] = 1;
  12756         }
  12757         prev_ber_log = curr_ber_log;
  12758         
  12759         LOG_INFO(BSL_LS_SOC_PHY,
  12760                  (BSL_META("cur_be_log %2.2f\n"), curr_ber_log));
  12761         /* find the first data point with good BER */
  12762         if ((curr_ber_log <= good_ber_level) && 
  12763             (pInfo->first_good_ber_idx == INDEX_UNINITIALIZED)) { 
  12764             LOG_INFO(BSL_LS_SOC_PHY,
  12765                      (BSL_META("cur_be_log %2.2f, loop_var %d\n"), 
  12766 curr_ber_log,loop_var));
  12767             pInfo->first_good_ber_idx = loop_var;
  12768         }
  12769         if ((pInfo->total_errs[loop_var] < HI_CONFIDENCE_MIN_ERR_CNT) &&
  12770             (pInfo->first_small_errcnt_idx == INDEX_UNINITIALIZED)) {
  12771              /* find the first data point with small error count */
  12772              pInfo->first_small_errcnt_idx = loop_var;
  12773         }
  12774         
  12775     }   /* for loop_var */
  12776 
  12777     return SOC_E_NONE;
  12778 #else
  12779     return SOC_E_UNAVAIL;
  12780 #endif
  12781 }
  12782 
  12783 
  12784 STATIC int  
  12785 _wc40_eye_margin_diagram_cal(WC40_EYE_DIAG_INFOt *pInfo, int type) 
  12786 {
  12787 #ifdef COMPILER_HAS_DOUBLE
  12788     COMPILER_DOUBLE lbers[MAX_LOOPS]; /*Internal linear scale sqrt(-log(ber))*/
  12789     COMPILER_DOUBLE margins[MAX_LOOPS]; /* Eye margin @ each measurement*/
  12790     COMPILER_DOUBLE bers[MAX_LOOPS]; /* computed bit error rate */
  12791     int delta_n;
  12792     COMPILER_DOUBLE Exy = 0.0;
  12793     COMPILER_DOUBLE Eyy = 0.0;
  12794     COMPILER_DOUBLE Exx = 0.0;
  12795     COMPILER_DOUBLE Ey  = 0.0;
  12796     COMPILER_DOUBLE Ex  = 0.0;
  12797     COMPILER_DOUBLE alpha;
  12798     COMPILER_DOUBLE beta;
  12799     COMPILER_DOUBLE proj_ber;
  12800     COMPILER_DOUBLE proj_margin_12;
  12801     COMPILER_DOUBLE proj_margin_15;
  12802     COMPILER_DOUBLE proj_margin_18;
  12803     COMPILER_DOUBLE sq_err2;
  12804     COMPILER_DOUBLE ierr;
  12805     int beta_max=0;
  12806     int ber_conf_scale[20];
  12807     int start_n;
  12808     int stop_n;
  12809     int low_confidence;
  12810     int loop_index;
  12811     COMPILER_DOUBLE outputs[4];
  12812     COMPILER_DOUBLE eye_unit;
  12813     int n_mono;
  12814 
  12815     /* Initialize BER confidence scale */
  12816     ber_conf_scale[0] = 3.02;
  12817     ber_conf_scale[1] = 4.7863;
  12818     ber_conf_scale[2] = 3.1623;
  12819     ber_conf_scale[3] = 2.6303;
  12820     ber_conf_scale[4] = 2.2909;
  12821     ber_conf_scale[5] = 2.138;
  12822     ber_conf_scale[6] = 1.9953;
  12823     ber_conf_scale[7] = 1.9055;
  12824     ber_conf_scale[8] = 1.8197;
  12825     ber_conf_scale[9] = 1.7783;
  12826     ber_conf_scale[10] = 1.6982;
  12827     ber_conf_scale[11] = 1.6596;
  12828     ber_conf_scale[12] = 1.6218;
  12829     ber_conf_scale[13] = 1.6218;
  12830     ber_conf_scale[14] = 1.5849;
  12831     ber_conf_scale[15] = 1.5488;
  12832     ber_conf_scale[16] = 1.5488;
  12833     ber_conf_scale[17] = 1.5136;
  12834     ber_conf_scale[18] = 1.5136;
  12835     ber_conf_scale[19] = 1.4791;
  12836 
  12837     LOG_INFO(BSL_LS_SOC_PHY,
  12838              (BSL_META("first_good_ber_idx: %d, first_small_errcnt_idx: %d\n"),
  12839 pInfo->first_good_ber_idx,pInfo->first_small_errcnt_idx));
  12840 
  12841     /* Find the highest data point to use, currently based on at least 1E-8 BER level */
  12842     if (pInfo->first_good_ber_idx == INDEX_UNINITIALIZED) {
  12843         start_n = pInfo->veye_cnt;
  12844     } else {
  12845         start_n = pInfo->first_good_ber_idx;
  12846     }
  12847     stop_n = pInfo->veye_cnt;
  12848 
  12849     /* Find the lowest data point to use */
  12850     if (pInfo->first_small_errcnt_idx == INDEX_UNINITIALIZED) {
  12851         stop_n = pInfo->veye_cnt;
  12852     } else { 
  12853         stop_n = pInfo->first_small_errcnt_idx;
  12854     }
  12855 
  12856     /* determine the number of non-monotonic outliers */
  12857     n_mono = 0;
  12858     for (loop_index = start_n; loop_index < stop_n; loop_index++) {
  12859         if (pInfo->mono_flags[loop_index] == 1) {
  12860             n_mono = n_mono + 1;
  12861         }
  12862     } 
  12863 
  12864     if (type == WC_UTIL_HEYE_L || type == WC_UTIL_HEYE_R) {
  12865         eye_unit = HEYE_UNIT;
  12866     } else {
  12867         eye_unit = VEYE_UNIT;
  12868     }
  12869 
  12870     for (loop_index = 0; loop_index < pInfo->veye_cnt; loop_index++) {
  12871         if (pInfo->total_errs[loop_index] == 0) {
  12872             bers[loop_index] = 1.0/(COMPILER_DOUBLE)pInfo->total_elapsed_time[loop_index]/pInfo->rate;
  12873         } else {
  12874             bers[loop_index] = (COMPILER_DOUBLE)pInfo->total_errs[loop_index]/
  12875                                (COMPILER_DOUBLE)pInfo->total_elapsed_time[loop_index]/pInfo->rate;
  12876         }
  12877         bers[loop_index] /= 1000;
  12878         margins[loop_index] = (pInfo->offset_max-loop_index)*eye_unit;
  12879     }
  12880 
  12881     if( start_n >= pInfo->veye_cnt ) {
  12882         outputs[0] = -_wc40_util_round_real(log(bers[pInfo->veye_cnt-1])/log(10), 1);
  12883         outputs[1] = -100.0;
  12884         outputs[2] = -100.0;
  12885         outputs[3] = -100.0;
  12886     /*  No need to print out the decimal portion of the BER */
  12887     LOG_CLI((BSL_META("BER *worse* than 1e-%d\n"), (int)outputs[0]));
  12888     LOG_CLI((BSL_META("Negative margin @ 1e-12, 1e-15 & 1e-18\n")));
  12889     } else {
  12890         low_confidence = 0;
  12891     if( (stop_n-start_n - n_mono) < 2  ) {
  12892         /* Code triggered when less than 2 statistically valid extrapolation points */
  12893             for( loop_index = stop_n; loop_index < pInfo->veye_cnt; loop_index++ ) {
  12894             if( pInfo->total_errs[loop_index] < 20 ) {
  12895             bers[loop_index] = ber_conf_scale[pInfo->total_errs[loop_index]] * bers[loop_index];
  12896         } else {
  12897             bers[loop_index] = ber_conf_scale[19] * bers[loop_index];
  12898         }
  12899                 pInfo->mono_flags[loop_index] = 0;    /* remove flags; or assess again */
  12900         }
  12901         /* Add artificial point at 100% margin to enable interpolation */
  12902             margins[pInfo->veye_cnt] = 100.0;
  12903             bers[pInfo->veye_cnt] = 0.1;
  12904             low_confidence = 1;
  12905             stop_n = pInfo->veye_cnt + 1;
  12906     }
  12907 
  12908     /* Below this point the code assumes statistically valid point available */
  12909         delta_n = stop_n - start_n - n_mono;
  12910 
  12911         LOG_INFO(BSL_LS_SOC_PHY,
  12912                  (BSL_META("start_n: %d, stop_n: %d, veye: %d, n_mono: %d\n"),
  12913 start_n,stop_n,pInfo->veye_cnt,n_mono));
  12914 
  12915     /* Find all the correlations */
  12916     for( loop_index = start_n; loop_index < stop_n; loop_index++ ) {
  12917         lbers[loop_index] = (COMPILER_DOUBLE)sqrt(-log(bers[loop_index]));
  12918     }
  12919 
  12920         LOG_INFO(BSL_LS_SOC_PHY,
  12921                  (BSL_META("\tstart=%d, stop=%d, low_confidence=%d\n"),
  12922 start_n, stop_n, low_confidence));
  12923         for (loop_index=start_n; loop_index < stop_n; loop_index++){
  12924             LOG_INFO(BSL_LS_SOC_PHY,
  12925                      (BSL_META("\ttotal_errs[%d]=0x%08x\n"),
  12926 loop_index,(int)pInfo->total_errs[loop_index]));
  12927             LOG_INFO(BSL_LS_SOC_PHY,
  12928                      (BSL_META("\tbers[%d]=%f\n"),
  12929 loop_index,bers[loop_index]));
  12930             LOG_INFO(BSL_LS_SOC_PHY,
  12931                      (BSL_META("\tlbers[%d]=%f\n"),
  12932 loop_index,lbers[loop_index]));
  12933     }
  12934 
  12935     for( loop_index = start_n; loop_index < stop_n; loop_index++ ) {
  12936             if (pInfo->mono_flags[loop_index] == 0) {
  12937             Exy = Exy + margins[loop_index] * lbers[loop_index]/(COMPILER_DOUBLE)delta_n;
  12938             Eyy = Eyy + lbers[loop_index]*lbers[loop_index]/(COMPILER_DOUBLE)delta_n;
  12939             Exx = Exx + margins[loop_index]*margins[loop_index]/(COMPILER_DOUBLE)delta_n;
  12940             Ey  = Ey + lbers[loop_index]/(COMPILER_DOUBLE)delta_n;
  12941             Ex  = Ex + margins[loop_index]/(COMPILER_DOUBLE)delta_n;
  12942             }
  12943     }
  12944 
  12945     /* Compute fit slope and offset */
  12946         alpha = (Exy - Ey * Ex)/(Exx - Ex * Ex);
  12947         beta = Ey - Ex * alpha;
  12948     
  12949     LOG_INFO(BSL_LS_SOC_PHY,
  12950              (BSL_META("Exy=%f, Eyy=%f, Exx=%f, Ey=%f,Ex=%f alpha=%f, beta=%f\n"),
  12951 Exy,Eyy,Exx,Ey,Ex,alpha,beta));
  12952 
  12953     /* JPA> Due to the limit of floats, I need to test for a maximum Beta of 9.32 */
  12954     if(beta > 9.32){
  12955       beta_max=1;
  12956       LOG_CLI((BSL_META("\n\tWARNING: intermediate float variable is maxed out, "
  12957                         "what this means is:\n")));
  12958       LOG_CLI((BSL_META("\t\t- The *extrapolated* minimum BER will be reported "
  12959                         "as 1E-37.\n")));
  12960       LOG_CLI((BSL_META("\t\t- This may occur if the channel is near ideal "
  12961                         "(e.g. test loopback)\n")));
  12962       LOG_CLI((BSL_META("\t\t- While not discrete, reporting an extrapolated "
  12963                         "BER < 1E-37 is numerically corect, and informative\n\n")));
  12964     }
  12965 
  12966        
  12967         proj_ber = exp(-beta * beta);
  12968         proj_margin_12 = (sqrt(-log(1e-12)) - beta)/alpha;
  12969         proj_margin_15 = (sqrt(-log(1e-15)) - beta)/alpha;
  12970         proj_margin_18 = (sqrt(-log(1e-18)) - beta)/alpha;
  12971 
  12972         sq_err2 = 0;
  12973     for( loop_index = start_n; loop_index < stop_n; loop_index++ ) {
  12974       /* coverity[uninit_use:FALSE] */
  12975       ierr = (lbers[loop_index] - (alpha*margins[loop_index] + beta));
  12976       sq_err2 = sq_err2 + ierr*ierr/(COMPILER_DOUBLE)delta_n;
  12977         }
  12978 
  12979         outputs[0] = -_wc40_util_round_real(log(proj_ber)/log(10),1);
  12980     outputs[1] = _wc40_util_round_real(proj_margin_18,1);
  12981         outputs[2] = _wc40_util_round_real(proj_margin_12,1);
  12982         outputs[3] = _wc40_util_round_real(proj_margin_15,1);
  12983 
  12984         LOG_INFO(BSL_LS_SOC_PHY,
  12985                  (BSL_META("\t\tlog1e-12=%f, sq=%f\n"),(COMPILER_DOUBLE)log(1e-12),(COMPILER_DOUBLE)sqrt(-log(1e-12))));
  12986         LOG_INFO(BSL_LS_SOC_PHY,
  12987                  (BSL_META("\t\talpha=%f\n"),alpha));
  12988         LOG_INFO(BSL_LS_SOC_PHY,
  12989                  (BSL_META("\t\tbeta=%f\n"),beta));
  12990         LOG_INFO(BSL_LS_SOC_PHY,
  12991                  (BSL_META("\t\tproj_ber=%f\n"),proj_ber));
  12992         LOG_INFO(BSL_LS_SOC_PHY,
  12993                  (BSL_META("\t\tproj_margin12=%f\n"),proj_margin_12));
  12994         LOG_INFO(BSL_LS_SOC_PHY,
  12995                  (BSL_META("\t\tproj_margin12=%f\n"),proj_margin_15));
  12996         LOG_INFO(BSL_LS_SOC_PHY,
  12997                  (BSL_META("\t\tproj_margin18=%f\n"),proj_margin_18));
  12998         LOG_INFO(BSL_LS_SOC_PHY,
  12999                  (BSL_META("\t\toutputs[0]=%f\n"),outputs[0]));
  13000         LOG_INFO(BSL_LS_SOC_PHY,
  13001                  (BSL_META("\t\toutputs[1]=%f\n"),outputs[1]));
  13002         LOG_INFO(BSL_LS_SOC_PHY,
  13003                  (BSL_META("\t\toutputs[2]=%f\n"),outputs[2]));
  13004 
  13005         /* Extrapolated results, low confidence */
  13006         if( low_confidence == 1 ) {
  13007           if(beta_max){
  13008             LOG_CLI((BSL_META("BER(extrapolated) is *better* than 1e-37\n")));
  13009             LOG_CLI((BSL_META("Margin @ 1e-12    is *better* than %f\n"), outputs[2]));
  13010             LOG_CLI((BSL_META("Margin @ 1e-15    is *better* than %f\n"), outputs[3]));
  13011             LOG_CLI((BSL_META("Margin @ 1e-18    is *better* than %f\n"), outputs[1]));
  13012           }
  13013           else{
  13014             LOG_CLI((BSL_META("BER(extrapolated) is *better* than 1e-%f\n"),
  13015                      outputs[0]));
  13016             LOG_CLI((BSL_META("Margin @ 1e-12    is *better* than %f\n"), outputs[2]));
  13017             LOG_CLI((BSL_META("Margin @ 1e-15    is *better* than %f\n"), outputs[3]));
  13018             LOG_CLI((BSL_META("Margin @ 1e-18    is *better* than %f\n"), outputs[1]));
  13019           }
  13020 
  13021         /* JPA> Extrapolated results, high confidence */
  13022         } else {           
  13023           if(beta_max){
  13024             LOG_CLI((BSL_META("BER(extrapolated) = 1e-37\n")));
  13025             LOG_CLI((BSL_META("Margin @ 1e-12    is *better* than %f\n"), outputs[2]));
  13026             LOG_CLI((BSL_META("Margin @ 1e-15    is *better* than %f\n"), outputs[3]));
  13027             LOG_CLI((BSL_META("Margin @ 1e-18    is *better* than %f\n"), outputs[1]));
  13028           }
  13029           else{
  13030           LOG_CLI((BSL_META("BER(extrapolated) = 1e-%4.2f\n"), outputs[0]));
  13031           LOG_CLI((BSL_META("Margin @ 1e-12    = %4.2f%%\n"), outputs[2]));
  13032           LOG_CLI((BSL_META("Margin @ 1e-15    = %4.2f%%\n"), outputs[3]));
  13033           LOG_CLI((BSL_META("Margin @ 1e-18    = %4.2f%%\n"), outputs[1]));
  13034           }
  13035         }
  13036     }
  13037     return SOC_E_NONE;
  13038 #else
  13039     return SOC_E_UNAVAIL;
  13040 #endif
  13041 } 
  13042 #else   /* #ifndef __KERNEL__ */
  13043 
  13044 int
  13045 wc40_eye_margin(int unit, soc_port_t port, int type)
  13046 {
  13047     LOG_CLI((BSL_META_U(unit,
  13048                         "\nThis function is not supported in Linux kernel mode\n")));
  13049     return SOC_E_NONE;
  13050 }
  13051 #endif /* #ifndef __KERNEL__ */
  13052 #else /* INCLUDE_XGXS_WC40 */
  13053 int _xgxs_wc40_not_empty;
  13054 #endif /* INCLUDE_XGXS_WC40 */