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, ®0_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,®0_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 */