hl65.c (239226B)
1 /* 2 * 3 * 4 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 5 * 6 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 7 * 8 * File: hl65.c 9 * Purpose: Broadcom 10/100/1000/2500/10000/12000/13000/16000/20000 SerDes 10 * (HyperLite 65nm with x1 and x4 lane support) 11 */ 12 13 #include <shared/bsl.h> 14 15 #include <sal/types.h> 16 #include <sal/core/spl.h> 17 #include <soc/drv.h> 18 #include <soc/error.h> 19 #include <soc/phyreg.h> 20 #include <soc/port_ability.h> 21 #include <soc/phyctrl.h> 22 23 #include <soc/phy.h> 24 #include <soc/phy/phyctrl.h> 25 #include <soc/phy/drv.h> 26 27 #include "phydefs.h" /* Must include before other phy related includes */ 28 29 #if defined(INCLUDE_XGXS_HL65) 30 #include "phyconfig.h" /* Must include before other phy related includes */ 31 #include "phyreg.h" 32 #include "phyfege.h" 33 #include "phynull.h" 34 #include "serdesid.h" 35 #include "hl65.h" 36 37 /* 38 * HL/HC defines not contained in hl65.h which is generated from RDB files 39 */ 40 41 #define HL65_PLL_WAIT 250000 42 #define HL65_AN_WAIT 400000 /* 400ms */ 43 #define HL65_NUM_LANES 4 44 #define TX_DRIVER_DFT_LN_CTRL 0x4 45 46 #define HL_SERDES_ID0_REVID_A0 0x0000 47 #define HL_SERDES_ID0_REVID_A1 0x0800 48 #define HL_SERDES_ID0_REVID_B0 0x4000 49 #define HL_SERDES_ID0_REVID_C0 0x8000 50 #define HL_SERDES_ID0_REVID_D0 0xc000 51 52 #define HL_ALL_LANES 0xf 53 #define HL_AER_BCST_OFS_STRAP 0x3ff 54 55 #define HL65_A0A1_DSC_DFE_BRCDR 0x2180 56 #define HL65_B0C0_DSC_DFE_BRCDR 0x2300 57 #define OVER1G_UP3_20GPLUS_MASK (DIGITAL3_UP3_DATARATE_25P45GX4_MASK | \ 58 DIGITAL3_UP3_DATARATE_21GX4_MASK) 59 #define PLL_PLLACONTROL4_BIT12_MASK 0x1000 60 61 /* Broadcast to all lanes with AER::MMD_PORT set to aer_bcst_ofs_strap */ 62 #define HL65_BROADCAST_WRITE(_unit, _pc, _bcst_strap, _reg_addr, _data) \ 63 HL65_REG_WRITE((_unit), (_pc), 0x00, \ 64 ((_bcst_strap) << 16) | (_reg_addr), (_data)) 65 66 typedef enum { 67 PHY_HL65_DSC_CFG_1X_OSR, 68 PHY_HL65_DSC_CFG_2X_OSR, 69 PHY_HL65_DSC_CFG_4X_OSR, 70 PHY_HL65_DSC_CFG_5X_OSR, 71 PHY_HL65_DSC_CFG_BR_CDR, 72 PHY_HL65_DSC_CFG_UNKNOWN 73 } phy_hl65_dsc_cfg_t; 74 75 /* function forward declaration */ 76 STATIC int _phy_hl65_notify_duplex(int unit, soc_port_t port, uint32 duplex); 77 STATIC int _phy_hl65_notify_speed(int unit, soc_port_t port, uint32 speed); 78 STATIC int _phy_hl65_notify_stop(int unit, soc_port_t port, uint32 flags); 79 STATIC int _phy_hl65_notify_resume(int unit, soc_port_t port, uint32 flags); 80 STATIC int _phy_hl65_notify_interface(int unit, soc_port_t port, uint32 intf); 81 STATIC int phy_hl65_an_set(int unit, soc_port_t port, int an); 82 STATIC int phy_hl65_lb_set(int unit, soc_port_t port, int enable); 83 STATIC int phy_hl65_ability_advert_set(int unit, soc_port_t port, 84 soc_port_ability_t *ability); 85 STATIC int phy_hl65_ability_local_get(int unit, soc_port_t port, 86 soc_port_ability_t *ability); 87 STATIC int phy_hl65_diag_ctrl(int, soc_port_t, uint32, int, int, void *); 88 STATIC int phy_hl65_speed_set(int unit, soc_port_t port, int speed); 89 STATIC int phy_hl65_speed_get(int unit, soc_port_t port, int *speed); 90 STATIC int phy_hl65_an_get(int unit, soc_port_t port, int *an, int *an_done); 91 STATIC int _phy_hl65_analog_dsc_init (int unit,int port,int lane); 92 STATIC int _hl65_xgmii_scw_config (int unit, phy_ctrl_t *pc); 93 STATIC int _hl65_rxaui_config(int unit, phy_ctrl_t *pc,int rxaui); 94 STATIC int _hl65_soft_reset(int unit, phy_ctrl_t *pc); 95 STATIC int _hl65_lane_reg_init(int unit, phy_ctrl_t *pc); 96 STATIC int phy_hl65_uc_status_dump(int unit, soc_port_t port); 97 98 99 100 STATIC int 101 _phy_hl65_pll_lock_wait(int unit, soc_port_t port) 102 { 103 uint16 data16; 104 phy_ctrl_t *pc; 105 soc_timeout_t to; 106 int rv; 107 108 pc = INT_PHY_SW_STATE(unit, port); 109 soc_timeout_init(&to, HL65_PLL_WAIT, 0); 110 do { 111 rv = READ_HL65_XGXSBLK0_XGXSSTATUSr(unit, pc, &data16); 112 if ((data16 & XGXSBLK0_XGXSSTATUS_TXPLL_LOCK_MASK) || 113 SOC_FAILURE(rv)) { 114 break; 115 } 116 } while (!soc_timeout_check(&to)); 117 if ((data16 & XGXSBLK0_XGXSSTATUS_TXPLL_LOCK_MASK) == 0) { 118 LOG_WARN(BSL_LS_SOC_PHY, 119 (BSL_META_U(unit, 120 "HL65 : TXPLL did not lock: u=%d p=%d\n"), 121 unit, port)); 122 return (SOC_E_TIMEOUT); 123 } 124 return (SOC_E_NONE); 125 } 126 127 STATIC int 128 _phy_hl65_half_rate_set(int unit, soc_port_t port,int speed) 129 { 130 phy_ctrl_t *pc; 131 int tx_halfrate_bit; 132 uint16 serdes_id0; 133 134 pc = INT_PHY_SW_STATE(unit, port); 135 136 SOC_IF_ERROR_RETURN 137 (READ_HL65_TEST_SERDESID0r(unit, pc, &serdes_id0)); 138 139 serdes_id0 = serdes_id0 & (TEST_SERDESID0_REV_NUMBER_MASK | 140 TEST_SERDESID0_REV_LETTER_MASK); 141 142 /* only apply to these revisions */ 143 144 if ((serdes_id0 == HL_SERDES_ID0_REVID_A0) || 145 (serdes_id0 == HL_SERDES_ID0_REVID_A1) || 146 (serdes_id0 == HL_SERDES_ID0_REVID_B0)) { 147 148 if (speed == 2500 || speed == 10000) { 149 tx_halfrate_bit = TX0_ANATXACONTROL1_TX_SEL_HALFRATE_MASK; 150 } else { 151 tx_halfrate_bit = 0; 152 } 153 154 /* set tx half rate bits after the link is established at 2.5G or 10G 155 * in both force mode or autoneg mode. 156 */ 157 SOC_IF_ERROR_RETURN 158 (MODIFY_HL65_TX0_ANATXACONTROL1r(unit, pc, 159 tx_halfrate_bit, 160 TX0_ANATXACONTROL1_TX_SEL_HALFRATE_MASK)); 161 if (!PHY_INDEPENDENT_LANE_MODE(unit, port)) { 162 SOC_IF_ERROR_RETURN 163 (MODIFY_HL65_TX1_ANATXACONTROL1r(unit, pc, 164 tx_halfrate_bit, 165 TX0_ANATXACONTROL1_TX_SEL_HALFRATE_MASK)); 166 SOC_IF_ERROR_RETURN 167 (MODIFY_HL65_TX2_ANATXACONTROL1r(unit, pc, 168 tx_halfrate_bit, 169 TX0_ANATXACONTROL1_TX_SEL_HALFRATE_MASK)); 170 SOC_IF_ERROR_RETURN 171 (MODIFY_HL65_TX3_ANATXACONTROL1r(unit, pc, 172 tx_halfrate_bit, 173 TX0_ANATXACONTROL1_TX_SEL_HALFRATE_MASK)); 174 } 175 } 176 return (SOC_E_NONE); 177 } 178 179 STATIC int 180 _phy_hl65_tx_control_set(int unit, soc_port_t port) 181 { 182 phy_ctrl_t *pc; 183 uint32 preemph; 184 uint32 idriver; 185 uint32 pdriver; 186 uint16 data16; 187 188 pc = INT_PHY_SW_STATE(unit, port); 189 190 191 if (PHY_EXTERNAL_MODE(unit, port)) { 192 /* HL65 connected to external PHY */ 193 if (IS_HG_PORT(unit, port)) { 194 preemph = 0x0; 195 idriver = 0x9; 196 pdriver = 0x9; 197 } else if (IS_XE_PORT(unit, port)) { 198 preemph = 0x0; 199 idriver = 0x9; 200 pdriver = 0x9; 201 } else { 202 preemph = 0x0; 203 idriver = 0x9; 204 pdriver = 0x9; 205 } 206 } else { 207 /* No external PHY */ 208 if (IS_HG_PORT(unit, port)) { 209 preemph = 0x0; 210 idriver = 0x9; 211 pdriver = 0x9; 212 } else if (IS_XE_PORT(unit, port)) { 213 preemph = 0x0; 214 idriver = 0x9; 215 pdriver = 0x9; 216 } else { 217 preemph = 0x0; 218 idriver = 0x9; 219 pdriver = 0x9; 220 } 221 } 222 223 /* Read config override */ 224 preemph = soc_property_port_get(unit, port, 225 spn_SERDES_PREEMPHASIS, preemph); 226 idriver = soc_property_port_get(unit, port, 227 spn_SERDES_DRIVER_CURRENT, idriver); 228 pdriver = soc_property_port_get(unit, port, 229 spn_SERDES_PRE_DRIVER_CURRENT, pdriver); 230 231 232 preemph = (preemph << TXB_TX_OS_DRIVER_PREEMPHASIS_POST_SHIFT) & 233 TXB_TX_OS_DRIVER_PREEMPHASIS_POST_MASK; 234 idriver = (idriver << TXB_TX_OS_DRIVER_IDRIVER_SHIFT) & 235 TXB_TX_OS_DRIVER_IDRIVER_MASK; 236 pdriver = (pdriver << TXB_TX_OS_DRIVER_IPREDRIVER_SHIFT) & 237 TXB_TX_OS_DRIVER_IPREDRIVER_MASK; 238 data16 = (uint16)(preemph | idriver | pdriver); 239 240 SOC_IF_ERROR_RETURN 241 (MODIFY_HL65_TXB_TX_OS_DRIVERr(unit, pc, data16, 242 TXB_TX_OS_DRIVER_PREEMPHASIS_POST_MASK | 243 TXB_TX_OS_DRIVER_IDRIVER_MASK | 244 TXB_TX_OS_DRIVER_IPREDRIVER_MASK)); 245 246 /* set for BR-CDR mode as well */ 247 SOC_IF_ERROR_RETURN 248 (MODIFY_HL65_TXB_TX_BR_DRIVERr(unit, pc, data16, 249 TXB_TX_OS_DRIVER_PREEMPHASIS_POST_MASK | 250 TXB_TX_OS_DRIVER_IDRIVER_MASK | 251 TXB_TX_OS_DRIVER_IPREDRIVER_MASK)); 252 return SOC_E_NONE; 253 } 254 255 STATIC int 256 _hl65_ind_lane_polarity_set (int unit, soc_port_t port) 257 { 258 int rxpol; 259 int txpol; 260 uint16 data16; 261 uint16 mask16; 262 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 263 264 txpol = soc_property_port_get(unit, port, 265 spn_PHY_XAUI_TX_POLARITY_FLIP, 0); 266 rxpol = soc_property_port_get(unit, port, 267 spn_PHY_XAUI_RX_POLARITY_FLIP, 0); 268 if (rxpol) { 269 /* Flip Rx polarity */ 270 mask16 = RX0_ANARXCONTROLPCI_RX_POLARITY_FORCE_SM_MASK | 271 RX0_ANARXCONTROLPCI_RX_POLARITY_R_MASK; 272 data16 = mask16; 273 if (pc->lane_num == 0) { 274 SOC_IF_ERROR_RETURN 275 (MODIFY_HL65_RX0_ANARXCONTROLPCIr(unit,pc,data16,mask16)); 276 } else if (pc->lane_num == 1) { 277 SOC_IF_ERROR_RETURN 278 (MODIFY_HL65_RX1_ANARXCONTROLPCIr(unit,pc,data16,mask16)); 279 } else if (pc->lane_num == 2) { 280 SOC_IF_ERROR_RETURN 281 (MODIFY_HL65_RX2_ANARXCONTROLPCIr(unit,pc,data16,mask16)); 282 } else if (pc->lane_num == 3) { 283 SOC_IF_ERROR_RETURN 284 (MODIFY_HL65_RX3_ANARXCONTROLPCIr(unit,pc,data16,mask16)); 285 } 286 if (pc->phy_mode == PHYCTRL_DUAL_LANE_PORT) { 287 /* Also flip for the next lane */ 288 if (pc->lane_num == 0) { 289 SOC_IF_ERROR_RETURN 290 (MODIFY_HL65_RX1_ANARXCONTROLPCIr(unit,pc,data16,mask16)); 291 } else if (pc->lane_num == 2) { 292 SOC_IF_ERROR_RETURN 293 (MODIFY_HL65_RX3_ANARXCONTROLPCIr(unit,pc,data16,mask16)); 294 } 295 } 296 } 297 if (txpol) { 298 /* Flip TX polarity */ 299 data16 = TX0_ANATXACONTROL0_TXPOL_FLIP_MASK; 300 mask16 = TX0_ANATXACONTROL0_TXPOL_FLIP_MASK; 301 if (pc->lane_num == 0) { 302 SOC_IF_ERROR_RETURN 303 (MODIFY_HL65_TX0_ANATXACONTROL0r(unit, pc, data16, mask16)); 304 } else if (pc->lane_num == 1) { 305 SOC_IF_ERROR_RETURN 306 (MODIFY_HL65_TX1_ANATXACONTROL0r(unit, pc, data16, mask16)); 307 } else if (pc->lane_num == 2) { 308 SOC_IF_ERROR_RETURN 309 (MODIFY_HL65_TX2_ANATXACONTROL0r(unit, pc, data16, mask16)); 310 } else if (pc->lane_num == 3) { 311 SOC_IF_ERROR_RETURN 312 (MODIFY_HL65_TX3_ANATXACONTROL0r(unit, pc, data16, mask16)); 313 } 314 if (pc->phy_mode == PHYCTRL_DUAL_LANE_PORT) { 315 /* Also flip for the next lane */ 316 if (pc->lane_num == 0) { 317 SOC_IF_ERROR_RETURN 318 (MODIFY_HL65_TX1_ANATXACONTROL0r(unit, pc, data16, mask16)); 319 } else if (pc->lane_num == 2) { 320 SOC_IF_ERROR_RETURN 321 (MODIFY_HL65_TX3_ANATXACONTROL0r(unit, pc, data16, mask16)); 322 } 323 } 324 } 325 return SOC_E_NONE; 326 } 327 328 STATIC int 329 _hl65_combo_lane_polarity_set (int unit, soc_port_t port) 330 { 331 int rxpol; 332 int txpol; 333 uint16 data16; 334 uint16 mask16; 335 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 336 337 txpol = soc_property_port_get(unit, port, 338 spn_PHY_XAUI_TX_POLARITY_FLIP, 0); 339 rxpol = soc_property_port_get(unit, port, 340 spn_PHY_XAUI_RX_POLARITY_FLIP, 0); 341 342 if (txpol) { /* Flip TX polarity */ 343 data16 = TX0_ANATXACONTROL0_TXPOL_FLIP_MASK; 344 mask16 = TX0_ANATXACONTROL0_TXPOL_FLIP_MASK; 345 if (txpol == 1) { 346 SOC_IF_ERROR_RETURN 347 (MODIFY_HL65_TXB_ANATXACONTROL0r(unit, pc, data16, mask16)); 348 } 349 if ((txpol & 0x000F) == 0x000F) { 350 SOC_IF_ERROR_RETURN 351 (MODIFY_HL65_TX0_ANATXACONTROL0r(unit, pc, data16, mask16)); 352 } 353 if ((txpol & 0x00F0) == 0x00F0) { 354 SOC_IF_ERROR_RETURN 355 (MODIFY_HL65_TX1_ANATXACONTROL0r(unit, pc, data16, mask16)); 356 } 357 if ((txpol & 0x0F00) == 0x0F00) { 358 SOC_IF_ERROR_RETURN 359 (MODIFY_HL65_TX2_ANATXACONTROL0r(unit, pc, data16, mask16)); 360 } 361 if ((txpol & 0xF000) == 0xF000) { 362 SOC_IF_ERROR_RETURN 363 (MODIFY_HL65_TX3_ANATXACONTROL0r(unit, pc, data16, mask16)); 364 } 365 } 366 if (rxpol) { 367 /* Flip Rx polarity */ 368 mask16 = RX0_ANARXCONTROLPCI_RX_POLARITY_FORCE_SM_MASK | 369 RX0_ANARXCONTROLPCI_RX_POLARITY_R_MASK; 370 data16 = mask16; 371 if (rxpol == 1) { 372 SOC_IF_ERROR_RETURN 373 (MODIFY_HL65_RXB_ANARXCONTROLPCIr(unit,pc,data16,mask16)); 374 } 375 if ((rxpol & 0x000F) == 0x000F) { 376 SOC_IF_ERROR_RETURN 377 (MODIFY_HL65_RX0_ANARXCONTROLPCIr(unit,pc,data16,mask16)); 378 } 379 if ((rxpol & 0x00F0) == 0x00F0) { 380 SOC_IF_ERROR_RETURN 381 (MODIFY_HL65_RX1_ANARXCONTROLPCIr(unit,pc,data16,mask16)); 382 } 383 if ((rxpol & 0x0F00) == 0x0F00) { 384 SOC_IF_ERROR_RETURN 385 (MODIFY_HL65_RX2_ANARXCONTROLPCIr(unit,pc,data16,mask16)); 386 } 387 if ((rxpol & 0xF000) == 0xF000) { 388 SOC_IF_ERROR_RETURN 389 (MODIFY_HL65_RX3_ANARXCONTROLPCIr(unit,pc,data16,mask16)); 390 } 391 } 392 return SOC_E_NONE; 393 } 394 395 STATIC int 396 _phy_hl65_independent_lane_init(int unit, soc_port_t port) 397 { 398 int fiber; 399 uint16 data16, mask16; 400 uint16 mode_1000x; 401 int rv; 402 soc_timeout_t to; 403 phy_ctrl_t *pc; 404 soc_port_ability_t ability; 405 406 if (SOC_IS_RELOADING(unit)) { 407 return SOC_E_NONE; 408 } 409 410 /* Only need to track fiber mode state. 411 * Copper mode state is tracked by external PHY. 412 */ 413 pc = INT_PHY_SW_STATE(unit, port); 414 fiber = PHY_FIBER_MODE(unit, port); 415 pc->fiber.enable = fiber; 416 pc->fiber.preferred = fiber; 417 pc->fiber.autoneg_enable = 1; 418 pc->fiber.force_speed = 1000; 419 pc->fiber.force_duplex = TRUE; 420 pc->fiber.master = SOC_PORT_MS_NONE; 421 pc->fiber.mdix = SOC_PORT_MDIX_NORMAL; 422 423 /* if the port is using two lanes and not using as dxgxs mode, 424 * then disable the second lane 425 */ 426 if ((pc->phy_mode == PHYCTRL_DUAL_LANE_PORT) && IS_GE_PORT(unit,port)) { 427 int mdio_addr_share = FALSE; 428 429 /* clear next lane default dxgxs configuration */ 430 if (!(pc->flags & PHYCTRL_MDIO_ADDR_SHARE)) { 431 pc->phy_id++; 432 } else { 433 pc->lane_num++; 434 } 435 SOC_IF_ERROR_RETURN 436 (MODIFY_HL65_DIGITAL_MISC1r(unit, pc, 0, 0x1f)); 437 438 SOC_IF_ERROR_RETURN 439 (MODIFY_HL65_DIGITAL4_MISC3r(unit, pc, 0, 440 DIGITAL4_MISC3_FORCE_SPEED_B5_MASK)); 441 if (!(pc->flags & PHYCTRL_MDIO_ADDR_SHARE)) { 442 pc->phy_id--; 443 } else { 444 pc->lane_num--; 445 } 446 447 /* disable the next lane 448 * the lane disable register can only be accessed from lane 0 449 */ 450 if (pc->flags & PHYCTRL_MDIO_ADDR_SHARE) { 451 mdio_addr_share = TRUE; 452 pc->flags &= ~PHYCTRL_MDIO_ADDR_SHARE; 453 } else { 454 pc->phy_id -= pc->lane_num; 455 } 456 457 mask16 = (1 << (pc->lane_num + 1)); /* rx lane */ 458 mask16 |= (mask16 << 4); /* add tx lane */ 459 mask16 |= 0x800; /* add force bit */ 460 data16 = mask16; 461 462 SOC_IF_ERROR_RETURN 463 (MODIFY_HL65_XGXSBLK1_LANECTRL3r(unit,pc,data16,mask16)); 464 465 /* restore the previous MDIO address mode */ 466 if (mdio_addr_share == TRUE) { 467 pc->flags |= PHYCTRL_MDIO_ADDR_SHARE; 468 } else { 469 pc->phy_id += pc->lane_num; 470 } 471 } 472 473 /* Since driver reset function vector does not reset 474 * the SerDes, reset the SerDes in initialization first. 475 * The internal SERDES PHY's reset bit is self-clearing. 476 */ 477 SOC_IF_ERROR_RETURN 478 (WRITE_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, MII_CTRL_RESET)); 479 480 soc_timeout_init(&to, 10000, 0); 481 while (!soc_timeout_check(&to)) { 482 rv = READ_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, &data16); 483 if (((data16 & MII_CTRL_RESET) == 0) || 484 SOC_FAILURE(rv)) { 485 break; 486 } 487 } 488 if ((data16 & MII_CTRL_RESET) != 0) { 489 LOG_WARN(BSL_LS_SOC_PHY, 490 (BSL_META_U(unit, 491 "Combo SerDes reset failed: u=%d p=%d\n"), 492 unit, port)); 493 } 494 495 /* disable in-band MDIO. PHY-443 */ 496 SOC_IF_ERROR_RETURN 497 (MODIFY_HL65_XGXSBLK3_LOCALCONTROL0r(unit,pc, 498 XGXSBLK3_LOCALCONTROL0_RX_INBANDMDIO_RST_MASK, 499 XGXSBLK3_LOCALCONTROL0_RX_INBANDMDIO_RST_MASK)); 500 501 /* check if need to flip any polarity for the lane */ 502 SOC_IF_ERROR_RETURN 503 (_hl65_ind_lane_polarity_set (unit, port)); 504 505 /* Select recovered clock from MII fifo read */ 506 if (IS_GE_PORT(unit, port) && (fiber == 0)) { 507 mask16 = DIGITAL4_MISC3_RXCK_MII_OVERRIDE_VAL_MASK | 508 DIGITAL4_MISC3_RXCK_MII_OVERRIDE_MASK; 509 data16 = mask16; 510 SOC_IF_ERROR_RETURN 511 (MODIFY_HL65_DIGITAL4_MISC3r(unit, pc, data16, mask16)); 512 } 513 514 /* Enable output clock to be present when the core is commanded into 515 * power down state. 516 */ 517 data16 = XGXSBLK1_LANETEST_PWRDWN_CLKS_EN_MASK; 518 SOC_IF_ERROR_RETURN 519 (WRITE_HL65_XGXSBLK1_LANETESTr(unit, pc, data16)); 520 521 /* Set Local Advertising Configuration */ 522 SOC_IF_ERROR_RETURN 523 (phy_hl65_ability_local_get(unit, port, &ability)); 524 /* Do not advertise 2.5G. 2.5 Gbps AN is not supported */ 525 ability.speed_full_duplex &= ~SOC_PA_SPEED_2500MB; 526 527 pc->fiber.advert_ability = ability; 528 SOC_IF_ERROR_RETURN 529 (phy_hl65_ability_advert_set(unit, port, &ability)); 530 531 /* Disable BAM in Independent Lance mode. Over1G AN not supported */ 532 SOC_IF_ERROR_RETURN 533 (WRITE_HL65_DIGITAL6_MP5_NEXTPAGECTRLr(unit, pc, 0)); 534 SOC_IF_ERROR_RETURN 535 (WRITE_HL65_DIGITAL6_UD_FIELDr(unit, pc, 0)); 536 537 data16 = DIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_MASK | 538 DIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_MASK; 539 mask16 = data16 | DIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK; 540 541 if ((PHY_FIBER_MODE(unit, port) && !PHY_EXTERNAL_MODE(unit, port)) || 542 PHY_PASSTHRU_MODE(unit, port) || 543 PHY_SGMII_AUTONEG_MODE(unit, port)) { 544 /* Enable 1000X parallel detect */ 545 data16 |= DIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK; 546 } 547 548 SOC_IF_ERROR_RETURN 549 (MODIFY_HL65_DIGITAL_CONTROL1000X2r(unit, pc, data16, mask16)); 550 551 /* Initialialize autoneg and fullduplex */ 552 data16 = MII_CTRL_FD | MII_CTRL_SS_1000; 553 if ((PHY_FIBER_MODE(unit, port) && !PHY_EXTERNAL_MODE(unit, port)) || 554 PHY_PASSTHRU_MODE(unit, port) || 555 PHY_SGMII_AUTONEG_MODE(unit, port)) { 556 data16 |= MII_CTRL_AE | MII_CTRL_RAN; 557 } 558 SOC_IF_ERROR_RETURN 559 (WRITE_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, data16)); 560 561 /* Configure default preemphasis, predriver, idriver values */ 562 SOC_IF_ERROR_RETURN 563 (_phy_hl65_tx_control_set(unit, port)); 564 565 /* Configuring operating mode */ 566 data16 = DIGITAL_CONTROL1000X1_DISABLE_PLL_PWRDWN_MASK; 567 mask16 = DIGITAL_CONTROL1000X1_AUTODET_EN_MASK | 568 DIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK | 569 DIGITAL_CONTROL1000X1_DISABLE_PLL_PWRDWN_MASK; 570 /* 571 * Configure signal auto-detection between SGMII and fiber. 572 * This detection only works if auto-negotiation is enabled. 573 */ 574 if (soc_property_port_get(unit, port, 575 spn_SERDES_AUTOMEDIUM, FALSE)) { 576 data16 |= DIGITAL_CONTROL1000X1_AUTODET_EN_MASK; 577 } 578 579 /* 580 * Put the Serdes in Fiber or SGMII mode 581 */ 582 mode_1000x = 0; 583 if ((PHY_FIBER_MODE(unit, port) && !PHY_EXTERNAL_MODE(unit, port)) || 584 PHY_PASSTHRU_MODE(unit, port)) { 585 mode_1000x = DIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK; 586 } 587 /* Allow property to override */ 588 if (soc_property_port_get(unit, port, 589 spn_SERDES_FIBER_PREF, mode_1000x)) { 590 data16 |= DIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK; 591 } else { 592 data16 &= ~DIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK; 593 } 594 if (soc_property_port_get(unit, port, 595 spn_SERDES_SGMII_MASTER, FALSE)) { 596 data16 |= DIGITAL_CONTROL1000X1_SGMII_MASTER_MODE_MASK; 597 mask16 |= DIGITAL_CONTROL1000X1_SGMII_MASTER_MODE_MASK; 598 } 599 600 SOC_IF_ERROR_RETURN 601 (MODIFY_HL65_DIGITAL_CONTROL1000X1r(unit, pc, data16, mask16)); 602 603 SOC_IF_ERROR_RETURN 604 (_hl65_lane_reg_init(unit,pc)); 605 606 SOC_IF_ERROR_RETURN 607 (_phy_hl65_analog_dsc_init(unit,port,pc->lane_num)); 608 609 /* config the 64B/66B for dxgxs mode */ 610 SOC_IF_ERROR_RETURN 611 (_hl65_xgmii_scw_config (unit,pc)); 612 613 /* autoneg is not supported in dxgxs mode */ 614 if ((pc->phy_mode == PHYCTRL_DUAL_LANE_PORT) && 615 (IS_HG_PORT(unit,port) || IS_XE_PORT(unit,port))) { 616 SOC_IF_ERROR_RETURN 617 (MODIFY_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, 0, MII_CTRL_AE)); 618 SOC_IF_ERROR_RETURN 619 (MODIFY_HL65_DIGITAL_MISC1r(unit, pc, 0x1, 0x1f)); 620 621 SOC_IF_ERROR_RETURN 622 (MODIFY_HL65_DIGITAL4_MISC3r(unit, pc, DIGITAL4_MISC3_FORCE_SPEED_B5_MASK, 623 DIGITAL4_MISC3_FORCE_SPEED_B5_MASK)); 624 } else { /* all other modes, enable autoneg by default */ 625 /* clear forced speed control. Some two-lane ports are strapped 626 * in forced dxgxs speed. 627 */ 628 SOC_IF_ERROR_RETURN 629 (MODIFY_HL65_DIGITAL_MISC1r(unit, pc, 0, 630 DIGITAL_MISC1_FORCE_SPEED_MASK)); 631 SOC_IF_ERROR_RETURN 632 (MODIFY_HL65_DIGITAL4_MISC3r(unit, pc, 0, 633 DIGITAL4_MISC3_FORCE_SPEED_B5_MASK)); 634 635 /* enable autoneg */ 636 SOC_IF_ERROR_RETURN 637 (MODIFY_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, MII_CTRL_AE, 638 MII_CTRL_AE)); 639 } 640 /* PRBS Polynomial for all lanes: 0x8019=0x0000 */ 641 642 SOC_IF_ERROR_RETURN 643 (WRITE_HL65_XGXSBLK1_LANEPRBSr(unit, pc, 0)); 644 645 LOG_INFO(BSL_LS_SOC_PHY, 646 (BSL_META_U(unit, 647 "phy_hl65_init: u=%d p=%d %s\n"), 648 unit, port, (fiber) ? "Fiber" : "Copper")); 649 return SOC_E_NONE; 650 } 651 652 STATIC int 653 _phy_hl65_combo_core_init(int unit, soc_port_t port) 654 { 655 phy_ctrl_t *pc; 656 soc_port_ability_t ability; 657 uint16 data16, mask16; 658 659 pc = INT_PHY_SW_STATE(unit, port); 660 661 /* must be done after reset, otherwise will be cleared */ 662 data16 = (XGXSBLK0_XGXSCONTROL_MODE_10G_ComboCoreMode << 663 XGXSBLK0_XGXSCONTROL_MODE_10G_SHIFT); 664 SOC_IF_ERROR_RETURN 665 (MODIFY_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc,data16, 666 (XGXSBLK0_XGXSCONTROL_MODE_10G_MASK))); 667 668 /* disable in-band MDIO. PHY-443 */ 669 SOC_IF_ERROR_RETURN 670 (MODIFY_HL65_XGXSBLK3_LOCALCONTROL0r(unit,pc, 671 XGXSBLK3_LOCALCONTROL0_RX_INBANDMDIO_RST_MASK, 672 XGXSBLK3_LOCALCONTROL0_RX_INBANDMDIO_RST_MASK)); 673 674 /* check if need to flip any polarity for the lanes */ 675 SOC_IF_ERROR_RETURN 676 (_hl65_combo_lane_polarity_set (unit, port)); 677 678 /* disable CL73 BAM */ 679 SOC_IF_ERROR_RETURN 680 (HL65_REG_MODIFY(unit,pc,0,0x38008372, 681 0, 682 CL73_USERB0_CL73_BAMCTRL1_CL73_BAMEN_MASK)); 683 684 if (!PHY_CLAUSE73_MODE(unit, port)) { 685 /* disable CL73 AN device*/ 686 SOC_IF_ERROR_RETURN 687 (WRITE_HL65_AN_IEEE0BLK_AN_IEEECONTROL1r(unit,pc,0)); 688 } 689 690 /* PLL VCO step time */ 691 SOC_IF_ERROR_RETURN 692 (WRITE_HL65_TXPLL_ANAPLLTIMER1r(unit, pc, 0x04ff)); 693 694 /* Disable IEEE block select auto-detect. 695 * The driver will select desired block as necessary. 696 * By default, the driver keeps the mapping for XAUI block in 697 * IEEE address space. 698 */ 699 SOC_IF_ERROR_RETURN 700 (MODIFY_HL65_XGXSBLK0_MISCCONTROL1r(unit, pc, 701 XGXSBLK0_MISCCONTROL1_IEEE_BLKSEL_VAL_MASK, 702 XGXSBLK0_MISCCONTROL1_IEEE_BLKSEL_AUTODET_MASK | 703 XGXSBLK0_MISCCONTROL1_IEEE_BLKSEL_VAL_MASK)); 704 705 SOC_IF_ERROR_RETURN 706 (phy_hl65_ability_local_get(unit, port, &ability)); 707 if (PHY_EXTERNAL_MODE(unit, port)) { 708 ability.speed_full_duplex = SOC_PA_SPEED_10GB; 709 } 710 SOC_IF_ERROR_RETURN 711 (phy_hl65_ability_advert_set(unit, port, &ability)); 712 713 /* Configure 10G parallel detect */ 714 SOC_IF_ERROR_RETURN /* Adjust parallel detect link timer to 60ms */ 715 (WRITE_HL65_AN73_PDET_PARDET10GLINKr(unit, pc, 0x16E2)); 716 717 data16 = 0; 718 mask16 = AN73_PDET_PARDET10GCONTROL_PD_12G_TXDON_DISABLE_MASK | 719 AN73_PDET_PARDET10GCONTROL_PD_12G_DISABLE_MASK | 720 AN73_PDET_PARDET10GCONTROL_PARDET10G_EN_MASK; 721 if (soc_property_port_get(unit, port, spn_XGXS_PDETECT_10G, 1)) { 722 data16 |= AN73_PDET_PARDET10GCONTROL_PARDET10G_EN_MASK; 723 if (pc->speed_max <= 10000) { 724 /* Disable parallel detect for 12Gbps. */ 725 data16 |= AN73_PDET_PARDET10GCONTROL_PD_12G_TXDON_DISABLE_MASK | 726 AN73_PDET_PARDET10GCONTROL_PD_12G_DISABLE_MASK; 727 } 728 } 729 SOC_IF_ERROR_RETURN 730 (MODIFY_HL65_AN73_PDET_PARDET10GCONTROLr(unit, pc, data16, mask16)); 731 732 /* Configure default preemphasis, predriver, idriver values */ 733 SOC_IF_ERROR_RETURN 734 (_phy_hl65_tx_control_set(unit, port)); 735 736 /* Enable output clock to be present when the core is commanded into 737 * power down state. 738 */ 739 data16 = XGXSBLK1_LANETEST_PWRDWN_CLKS_EN_MASK | 740 XGXSBLK1_LANETEST_PWRDN_SAFE_DIS_MASK; 741 SOC_IF_ERROR_RETURN 742 (WRITE_HL65_XGXSBLK1_LANETESTr(unit, pc, data16)); 743 744 /* 745 * Transform CX4 pin out on the board to HG pinout 746 */ 747 if (soc_property_port_get(unit, port, spn_CX4_TO_HIGIG, FALSE)) { 748 SOC_IF_ERROR_RETURN /* Enable TX Lane swap */ 749 (WRITE_HL65_XGXSBLK2_TXLNSWAPr(unit, pc, 0x80e4)); 750 751 SOC_IF_ERROR_RETURN /* Flip TX Lane polarity */ 752 (WRITE_HL65_TXB_ANATXACONTROL0r(unit, pc, 0x1020)); 753 } else { 754 /* If CX4 to HG conversion is enabled, do not allow individual lane 755 * swapping. 756 */ 757 uint16 lane_map, i; 758 uint16 lane, hw_map, chk_map; 759 760 /* Update RX lane map */ 761 lane_map = soc_property_port_get(unit, port, 762 spn_XGXS_RX_LANE_MAP, 0x0123) & 0xffff; 763 if (lane_map != 0x0123) { 764 hw_map = 0; 765 chk_map = 0; 766 for (i = 0; i < 4; i++) { 767 lane = (lane_map >> (i * 4)) & 0xf; 768 hw_map |= lane << (i * 2); 769 chk_map |= 1 << lane; 770 } 771 if (chk_map == 0xf) { 772 SOC_IF_ERROR_RETURN /* Enable RX Lane swap */ 773 (MODIFY_HL65_XGXSBLK2_RXLNSWAPr(unit, pc, 774 XGXSBLK2_RXLNSWAP_RX_LNSWAP_EN_MASK | 775 XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE_EN_MASK | hw_map, 776 XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE_EN_MASK | 777 XGXSBLK2_RXLNSWAP_RX_LNSWAP_EN_MASK | 778 XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE0_MASK | 779 XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE1_MASK | 780 XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE2_MASK | 781 XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE3_MASK)); 782 } else { 783 LOG_ERROR(BSL_LS_SOC_PHY, 784 (BSL_META_U(unit, 785 "unit %d port %s: Invalid RX lane map 0x%04x.\n"), 786 unit, SOC_PORT_NAME(unit, port), lane_map)); 787 } 788 } 789 790 /* Update TX lane map */ 791 lane_map = soc_property_port_get(unit, port, 792 spn_XGXS_TX_LANE_MAP, 0x0123) & 0xffff; 793 if (lane_map != 0x0123) { 794 hw_map = 0; 795 chk_map = 0; 796 for (i = 0; i < 4; i++) { 797 lane = (lane_map >> (i * 4)) & 0xf; 798 hw_map |= lane << (i * 2); 799 chk_map |= 1 << lane; 800 } 801 if (chk_map == 0xf) { 802 SOC_IF_ERROR_RETURN /* Enable TX Lane swap */ 803 (MODIFY_HL65_XGXSBLK2_TXLNSWAPr(unit, pc, 0x8000 | hw_map, 804 0x80ff)); 805 } else { 806 LOG_ERROR(BSL_LS_SOC_PHY, 807 (BSL_META_U(unit, 808 "unit %d port %s: Invalid TX lane map 0x%04x.\n"), 809 unit, SOC_PORT_NAME(unit, port), lane_map)); 810 } 811 } 812 } 813 814 SOC_IF_ERROR_RETURN 815 (MODIFY_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, 0, 816 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK)); 817 818 SOC_IF_ERROR_RETURN 819 (_phy_hl65_analog_dsc_init(unit,port,HL_ALL_LANES)); 820 821 /* config the 64B/66B for 25G, won't affect other speeds and AN */ 822 SOC_IF_ERROR_RETURN 823 (_hl65_xgmii_scw_config (unit,pc)); 824 825 /* broadcast to all lanes */ 826 SOC_IF_ERROR_RETURN 827 (WRITE_HL65_AERBLK_AERr(unit,pc, HL_AER_BCST_OFS_STRAP)); 828 829 SOC_IF_ERROR_RETURN 830 (_hl65_lane_reg_init(unit,pc)); 831 832 /* reset AER */ 833 SOC_IF_ERROR_RETURN 834 (WRITE_HL65_AERBLK_AERr(unit,pc, 0)); 835 836 /* enable autoneg or force a speed depending on the port type */ 837 838 if (PHY_EXTERNAL_MODE(unit, port) && 839 (IS_XE_PORT(unit, port) || IS_HG_PORT(unit, port))) { 840 int force_speed; 841 842 if (soc_property_port_get(unit, port, spn_10G_IS_CX4, TRUE)) { 843 force_speed= DIGITAL_MISC1_FORCE_SPEED_dr_10GBASE_CX4; /* 10G CX4 */ 844 } else { 845 force_speed= DIGITAL_MISC1_FORCE_SPEED_dr_10GHiGig_X4; /* 10G HiG */ 846 } 847 848 /* disable autoneg */ 849 SOC_IF_ERROR_RETURN 850 (MODIFY_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, 851 0, 852 MII_CTRL_AE)); 853 if (PHY_CLAUSE73_MODE(unit, port)) { 854 SOC_IF_ERROR_RETURN 855 (MODIFY_HL65_AN_IEEE0BLK_AN_IEEECONTROL1r(unit, pc, 856 0, 857 MII_CTRL_AE)); 858 } 859 860 /* force speed to 10G */ 861 SOC_IF_ERROR_RETURN 862 (MODIFY_HL65_DIGITAL_MISC1r(unit, pc, force_speed, 863 DIGITAL_MISC1_FORCE_SPEED_MASK)); 864 } else { /* autoneg */ 865 /* clear forced bit */ 866 SOC_IF_ERROR_RETURN 867 (MODIFY_HL65_DIGITAL_MISC1r(unit, pc, 0, 0x10)); 868 869 SOC_IF_ERROR_RETURN 870 (MODIFY_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, 871 MII_CTRL_AE | MII_CTRL_RAN, 872 MII_CTRL_AE | MII_CTRL_RAN)); 873 if (PHY_CLAUSE73_MODE(unit, port)) { 874 SOC_IF_ERROR_RETURN 875 (MODIFY_HL65_AN_IEEE0BLK_AN_IEEECONTROL1r(unit, pc, 876 MII_CTRL_AE | MII_CTRL_RAN, 877 MII_CTRL_AE | MII_CTRL_RAN)); 878 } 879 } 880 881 SOC_IF_ERROR_RETURN 882 (MODIFY_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, 883 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK, 884 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK)); 885 886 /* 887 * Configure signal auto-detection between SGMII and fiber. 888 */ 889 data16 = DIGITAL_CONTROL1000X1_DISABLE_PLL_PWRDWN_MASK; 890 mask16 = DIGITAL_CONTROL1000X1_DISABLE_PLL_PWRDWN_MASK | 891 DIGITAL_CONTROL1000X1_AUTODET_EN_MASK | 892 DIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK; 893 if (soc_property_port_get(unit, port, spn_SERDES_AUTOMEDIUM, TRUE)) { 894 data16 |= DIGITAL_CONTROL1000X1_AUTODET_EN_MASK; 895 } 896 if (soc_property_port_get(unit, port, spn_SERDES_FIBER_PREF, TRUE)) { 897 data16 |= DIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK; 898 } 899 SOC_IF_ERROR_RETURN 900 (MODIFY_HL65_DIGITAL_CONTROL1000X1r(unit, pc, data16, mask16)); 901 902 /* set filter_force_link and disable_false_link */ 903 904 mask16 = DIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_MASK | 905 DIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_MASK; 906 data16 = mask16; 907 SOC_IF_ERROR_RETURN 908 (MODIFY_HL65_DIGITAL_CONTROL1000X2r(unit, pc, data16, mask16)); 909 910 (void) _phy_hl65_pll_lock_wait(unit, port); 911 912 /* select recovery clock from lane0 for rxck0_10g */ 913 SOC_IF_ERROR_RETURN 914 (MODIFY_HL65_XGXSBLK1_TESTTXr(unit,pc, 915 0, 916 XGXSBLK1_TESTTX_RX_CK4X1MUXSEL_MASK)); 917 return SOC_E_NONE; 918 } 919 920 921 STATIC int 922 _phy_hl65_fabric_init(int unit, soc_port_t port) 923 { 924 uint16 data; 925 uint16 serdes_id0; 926 uint16 aer_bcst_ofs_strap; 927 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 928 929 LOG_INFO(BSL_LS_SOC_PHY, 930 (BSL_META_U(unit, 931 "phy_hl65_fabric_init: u=%d p=%d\n"), unit, port)); 932 SOC_IF_ERROR_RETURN 933 (READ_HL65_TEST_SERDESID0r(unit, pc, &serdes_id0)); 934 935 serdes_id0 = serdes_id0 & (TEST_SERDESID0_REV_NUMBER_MASK | 936 TEST_SERDESID0_REV_LETTER_MASK); 937 938 if (serdes_id0 == HL_SERDES_ID0_REVID_C0) { 939 aer_bcst_ofs_strap = 0x1ff; 940 } else { 941 aer_bcst_ofs_strap = 0x3ff; 942 } 943 944 PHY_FLAGS_SET(unit, port, PHY_FLAGS_INDEPENDENT_LANE); 945 946 /* Broadcast all lanes only when initializing the first lane */ 947 if (pc->lane_num == 0) { 948 /* 949 * Force the sync character to the lower byte of the parallel 950 * interface 951 */ 952 /* hwBm9600HcBroadcastWrite(pInitParams, HC_ffde_ADDR, 0x03ff) */ 953 /* hwBm9600HcRead(pInitParams, HC_PORT_ZERO, HC_80b9_ADDR, &uReadData)*/ 954 SOC_IF_ERROR_RETURN 955 (HL65_REG_READ(unit, pc, 0x00, 0x80b9, &data)); 956 957 /* data = data | 0x0020;*/ 958 data = data | (RX0_ANARXCONTROL1G_COMMA_LOW_BYTE_SM_BITS << 959 RX0_ANARXCONTROL1G_COMMA_LOW_BYTE_SM_SHIFT); 960 961 /* Enable the comma byte adjust on the opposite byte */ 962 data = data | (RX0_ANARXCONTROL1G_COMMA_BYTE_ADJ_EN_SM_BITS << 963 RX0_ANARXCONTROL1G_COMMA_BYTE_ADJ_EN_SM_SHIFT); 964 965 966 /* hwBm9600HcBroadcastWrite(pInitParams, HC_80b9_ADDR, uReadData) */ 967 SOC_IF_ERROR_RETURN 968 (HL65_BROADCAST_WRITE(unit, pc, aer_bcst_ofs_strap, 0x80b9, data)); 969 } 970 971 /* PLL Sequencer disable */ 972 /* soc_bm9600_mdio_hc_write(pInitParams->m_nBaseAddr, uPhyAddr, 0, 973 * 0x8000, 0x062f) 974 * >> Clear START_SEQUENCER_BITS 13 975 */ 976 SOC_IF_ERROR_RETURN 977 (WRITE_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x062f)); 978 979 /* Set force_lane_mode so that lane rates can be configured independently */ 980 /* soc_bm9600_mdio_hc_read(pInitParams->m_nBaseAddr, uPhyAddr, uLane, 981 * 0x8308, &uData) 982 */ 983 SOC_IF_ERROR_RETURN 984 (READ_HL65_DIGITAL_MISC1r(unit, pc, &data)); 985 986 /* uData |= 0x0020 */ 987 data |= (DIGITAL_MISC1_FORCE_LN_MODE_BITS << DIGITAL_MISC1_FORCE_LN_MODE_SHIFT); 988 989 /* soc_bm9600_mdio_hc_write(pInitParams->m_nBaseAddr, uPhyAddr, uLane, 0x8308, uData) */ 990 SOC_IF_ERROR_RETURN 991 (WRITE_HL65_DIGITAL_MISC1r(unit, pc, data)); 992 993 if (serdes_id0 == HL_SERDES_ID0_REVID_C0) { 994 995 SOC_IF_ERROR_RETURN 996 (READ_HL65_XGXSBLK1_LANECTRL0r(unit, pc, &data)); 997 998 /* XgxsBlk1 Lanectrl0 (8015) :: Clear CL36- keep already set up 64/66 settings */ 999 data &= 0xff00; 1000 1001 SOC_IF_ERROR_RETURN 1002 (WRITE_HL65_XGXSBLK1_LANECTRL0r(unit, pc, data)); 1003 1004 /* 1005 * XgxsBlk1 Shared (0x800d) :: 1006 * Clear SELECT_DEVPMD_EN_BITS | MMDSELECT_DEVAN_EN_BITS 1007 * This setup matches other SBX fabric (88130) 1008 */ 1009 data = (XGXSBLK0_MMDSELECT_DEVDEVAD_EN_BITS << 1010 XGXSBLK0_MMDSELECT_DEVDEVAD_EN_SHIFT) | 1011 (XGXSBLK0_MMDSELECT_DEVCL22_EN_BITS << 1012 XGXSBLK0_MMDSELECT_DEVCL22_EN_SHIFT); 1013 SOC_IF_ERROR_RETURN 1014 (WRITE_HL65_XGXSBLK0_MMDSELECTr(unit, pc, data)); 1015 1016 /* SerdesDigital_Control1000X3 (0x8302) */ 1017 SOC_IF_ERROR_RETURN 1018 (WRITE_HL65_DIGITAL_CONTROL1000X3r(unit, pc, 0)); 1019 1020 /* Set pf_br_init to 4 for C0 */ 1021 /* DSC2B0_SM_CTRL7 uRegAddr = 0x8267 + (uLane*0x10) */ 1022 SOC_IF_ERROR_RETURN 1023 (HL65_REG_WRITE(unit, pc, 0x0, 0x8267 + (0x10 * pc->lane_num), 0x14A5)); 1024 1025 1026 /* Enable hysteresis, enable tuning state machine set postc_metric_ctrl to 1 */ 1027 /* DSC2B0_SM_CTRL0 uRegAddr = 0x8260 + (uLane*0x10) */ 1028 /* soc_bm9600_mdio_hc_write(pInitParams->m_nBaseAddr, uPhyAddr, 0, uRegAddr, 0x0021) */ 1029 SOC_IF_ERROR_RETURN 1030 (HL65_REG_WRITE(unit, pc, 0x0, 0x8260 + (0x10 * pc->lane_num), 0x1821)); 1031 1032 } else { 1033 1034 /* Perform suggested writes during init */ 1035 /* Set DSC2B0_SM_CTRL11[14:10] msr_br_vga_timeout = 0 */ 1036 /* uRegAddr = 0x826b + (uLane*0x10) */ 1037 /* soc_bm9600_mdio_hc_write(pInitParams->m_nBaseAddr, uPhyAddr, 0, uRegAddr, 0x0312) */ 1038 SOC_IF_ERROR_RETURN 1039 (HL65_REG_WRITE(unit, pc, 0x0, 0x826b + (0x10 * pc->lane_num), 0x0312)); 1040 1041 /* Set DSC2B0_SM_CTRL12[13:12] br_vga_lms_gain= 0 */ 1042 /* uRegAddr = 0x826c + (uLane*0x10); */ 1043 /* soc_bm9600_mdio_hc_write(pInitParams->m_nBaseAddr, uPhyAddr, 0, uRegAddr, 0x046a) */ 1044 SOC_IF_ERROR_RETURN 1045 (HL65_REG_WRITE(unit, pc, 0x0, 0x826c + (0x10 * pc->lane_num), 0x046a)); 1046 1047 /* Disable hysteresis, enable tuning state machine */ 1048 /* DSC2B0_SM_CTRL0 uRegAddr = 0x8260 + (uLane*0x10) */ 1049 /* soc_bm9600_mdio_hc_write(pInitParams->m_nBaseAddr, uPhyAddr, 0, uRegAddr, 0x0021) */ 1050 SOC_IF_ERROR_RETURN 1051 (HL65_REG_WRITE(unit, pc, 0x0, 0x8260 + (0x10 * pc->lane_num), 0x0021)); 1052 1053 /* Increase ACQVGA timeout to 580K bits */ 1054 /* DSC2B0_SM_CTRL2 uRegAddr = 0x8262 + (uLane*0x10) */ 1055 /* soc_bm9600_mdio_hc_write(pInitParams->m_nBaseAddr, uPhyAddr, 0, uRegAddr, 0x3800)*/ 1056 SOC_IF_ERROR_RETURN 1057 (HL65_REG_WRITE(unit, pc, 0x0, 0x8262 + (0x10 * pc->lane_num), 0x3800)); 1058 1059 /* Set pf_br_init to 2 */ 1060 /* DSC2B0_SM_CTRL7 uRegAddr = 0x8267 + (uLane*0x10) */ 1061 /* rv = soc_bm9600_mdio_hc_write(pInitParams->m_nBaseAddr, uPhyAddr, 0, uRegAddr, 0x1495) */ 1062 SOC_IF_ERROR_RETURN 1063 (HL65_REG_WRITE(unit, pc, 0x0, 0x8267 + (0x10 * pc->lane_num), 0x1495)); 1064 1065 1066 /* Set vga_min=0, vga_max=31 */ 1067 /* DSC2B0_SM_CTRL8 uRegAddr = 0x8268 + (uLane*0x10) */ 1068 /* soc_bm9600_mdio_hc_write(pInitParams->m_nBaseAddr, uPhyAddr, 0, uRegAddr, 0x03e0) */ 1069 SOC_IF_ERROR_RETURN 1070 (HL65_REG_WRITE(unit, pc, 0x0, 0x8268 + (0x10 * pc->lane_num), 0x03e0)); 1071 1072 /* Set dfe_min=0, dfe_max=63 */ 1073 /* DSC2B0_SM_CTRL9 uRegAddr = 0x8269 + (uLane*0x10) */ 1074 /* soc_bm9600_mdio_hc_write(pInitParams->m_nBaseAddr, uPhyAddr, 0, uRegAddr, 0x0fc0) */ 1075 SOC_IF_ERROR_RETURN 1076 (HL65_REG_WRITE(unit, pc, 0x0, 0x8269 + (0x10 * pc->lane_num), 0x0fc0)); 1077 1078 /* Set BR ACQCDR kp=4 */ 1079 /* DSC2B0_SM_CTRL3 uRegAddr = 0x8263 + (uLane*0x10) */ 1080 /* soc_bm9600_mdio_hc_write(pInitParams->m_nBaseAddr, uPhyAddr, 0, uRegAddr, 0x421b) */ 1081 SOC_IF_ERROR_RETURN 1082 (HL65_REG_WRITE(unit, pc, 0x0, 0x8263 + (0x10 * pc->lane_num), 0x421b)); 1083 1084 /* Set BR ACQ1, ACQ2 kp=4 */ 1085 /* DSC2B0_SM_CTRL4 uRegAddr = 0x8264 + (uLane*0x10) */ 1086 /* soc_bm9600_mdio_hc_write(pInitParams->m_nBaseAddr, uPhyAddr, 0, uRegAddr, 0x53e4) */ 1087 SOC_IF_ERROR_RETURN 1088 (HL65_REG_WRITE(unit, pc, 0x0, 0x8264 + (0x10 * pc->lane_num), 0x53e4)); 1089 1090 /* Jitter performance improvement over PVT (process voltage temperature) */ 1091 /* soc_bm9600_mdio_hc_read(pInitParams->m_nBaseAddr, uPhyAddr, 0, 0x805e, &uData) */ 1092 SOC_IF_ERROR_RETURN 1093 (READ_HL65_TXPLL_ANAPLLACONTROL4r(unit, pc, &data)); 1094 1095 /* uData |= 0x1000 */ 1096 data |= 0x1000; 1097 1098 /*soc_bm9600_mdio_hc_write(pInitParams->m_nBaseAddr, uPhyAddr, 0, 0x805e, uData) */ 1099 SOC_IF_ERROR_RETURN 1100 (WRITE_HL65_TXPLL_ANAPLLACONTROL4r(unit, pc, data)); 1101 } 1102 1103 1104 /* Set IQP to 200 uA 0x805c */ 1105 SOC_IF_ERROR_RETURN 1106 (READ_HL65_TXPLL_ANAPLLACONTROL2r(unit, pc, &data)); 1107 1108 /* uData |= 0x0004 */ 1109 data |= 0x0004; 1110 1111 /*soc_bm9600_mdio_hc_write(pInitParams->m_nBaseAddr, uPhyAddr, 0, 0x805c, uData) */ 1112 SOC_IF_ERROR_RETURN 1113 (WRITE_HL65_TXPLL_ANAPLLACONTROL2r(unit, pc, data)); 1114 1115 1116 1117 /* PLL Sequencer enable */ 1118 /* soc_bm9600_mdio_hc_write(pInitParams->m_nBaseAddr, uPhyAddr, 0, 0x8000, 0x262f) */ 1119 SOC_IF_ERROR_RETURN 1120 (WRITE_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x262f)); 1121 1122 return SOC_E_NONE; 1123 } 1124 1125 /* 1126 * Function: 1127 * phy_hl65_init 1128 * Purpose: 1129 * Initialize hc phys 1130 * Parameters: 1131 * unit - StrataSwitch unit #. 1132 * port - StrataSwitch port #. 1133 * Returns: 1134 * SOC_E_NONE 1135 */ 1136 1137 STATIC int 1138 phy_hl65_init(int unit, soc_port_t port) 1139 { 1140 phy_ctrl_t *pc; 1141 uint16 xgxs_ctrl; 1142 uint16 vco_freq; 1143 int mode_1000x; 1144 uint16 id_rev; 1145 1146 if (PHY_HC65_FABRIC_MODE(unit, port)) { 1147 return _phy_hl65_fabric_init(unit, port); 1148 } 1149 1150 pc = INT_PHY_SW_STATE(unit, port); 1151 1152 if (!PHY_EXTERNAL_MODE(unit, port)) { 1153 /* PHY reset callbacks */ 1154 SOC_IF_ERROR_RETURN(soc_phy_reset(unit, port)); 1155 1156 if (soc_property_port_get(unit, port, 1157 spn_SERDES_FIBER_PREF, 1)) { 1158 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER); 1159 } else { 1160 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER); 1161 } 1162 1163 1164 if (soc_property_port_get(unit, port, 1165 spn_PHY_AN_C73, FALSE)) { 1166 PHY_FLAGS_SET(unit, port, PHY_FLAGS_C73); 1167 } 1168 } 1169 1170 if (PHY_INDEPENDENT_LANE_MODE(unit, port)) { 1171 /* In this mode, the device's 4 lanes connect to 4 different ports. 1172 * It is necessary to configure and initialize the shared resource 1173 * once before going to each lane. It is assumed the port connecting 1174 * to lane 0 must be initialized first. 1175 */ 1176 1177 if ((!PHY_FLAGS_TST(unit, port, PHY_FLAGS_INIT_DONE)) && 1178 (pc->lane_num == 0)) { 1179 /* configure and initialize the resource shared by all 4 lanes*/ 1180 1181 SOC_IF_ERROR_RETURN(_hl65_soft_reset(unit,pc)); /* reset once */ 1182 1183 /* Force to asymetric 1G/2.5G independent lane mode. 1184 * Support SGMII 10/100/100Mbps, 1000X, and 2500X speeds. 1185 */ 1186 /* workaround for a Rx problem running at 10M bps(PR20236). 1187 * Use mode 6 for speed at 10/100/1000M bps, SGMII interface 1188 * Use mode 5 for speed at 1000/2500 bps, optical device. 1189 * 1190 * Rev B and up has fixed the problem. No need to switch mode 1191 * between fiber and SGMII. 1192 */ 1193 1194 SOC_IF_ERROR_RETURN 1195 (READ_HL65_TEST_SERDESID0r(unit,pc,&id_rev)); 1196 if (!(id_rev & TEST_SERDESID0_REV_LETTER_MASK)) { 1197 1198 mode_1000x = FALSE; 1199 if (PHY_FIBER_MODE(unit, port) && 1200 (!PHY_EXTERNAL_MODE(unit, port))) { 1201 mode_1000x = TRUE; 1202 } 1203 1204 /* Allow property to override */ 1205 mode_1000x = soc_property_port_get(unit, port, 1206 spn_SERDES_FIBER_PREF, mode_1000x); 1207 1208 if (mode_1000x) { 1209 xgxs_ctrl = 5; 1210 } else { 1211 xgxs_ctrl = 6; 1212 } 1213 } else { 1214 /* REV B and above, use mode 6 if speed =<1000 */ 1215 if (pc->speed_max > 1000) { 1216 xgxs_ctrl = 5; 1217 } else { 1218 xgxs_ctrl = 6; 1219 } 1220 } 1221 1222 /* allow mode override by configuration */ 1223 1224 xgxs_ctrl = soc_property_port_get(unit, port, 1225 spn_PHY_HL65_1LANE_MODE, xgxs_ctrl); 1226 if (IS_HG_PORT(unit, port)) { 1227 vco_freq = 0x7800; 1228 } else { 1229 vco_freq = xgxs_ctrl == 5? 0x7700:0x7500; 1230 } 1231 xgxs_ctrl <<= XGXSBLK0_XGXSCONTROL_MODE_10G_SHIFT; 1232 1233 /* set device's mode and disable PLL sequencer */ 1234 SOC_IF_ERROR_RETURN 1235 (MODIFY_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, 1236 xgxs_ctrl, 1237 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK | 1238 XGXSBLK0_XGXSCONTROL_MODE_10G_MASK)); 1239 1240 /* broadcast to all lanes */ 1241 SOC_IF_ERROR_RETURN 1242 (WRITE_HL65_AERBLK_AERr(unit,pc, HL_AER_BCST_OFS_STRAP)); 1243 1244 /* configure VCO frequency */ 1245 SOC_IF_ERROR_RETURN 1246 (WRITE_HL65_DIGITAL_MISC1r(unit,pc,vco_freq)); 1247 1248 /* disable 10G parallel detect */ 1249 SOC_IF_ERROR_RETURN 1250 (MODIFY_HL65_AN73_PDET_PARDET10GCONTROLr(unit, pc, 1251 0, 1252 AN73_PDET_PARDET10GCONTROL_PARDET10G_EN_MASK)); 1253 1254 /* reset AER */ 1255 SOC_IF_ERROR_RETURN 1256 (WRITE_HL65_AERBLK_AERr(unit,pc, 0)); 1257 1258 /* enable PLL sequencer */ 1259 SOC_IF_ERROR_RETURN 1260 (MODIFY_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, 1261 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK, 1262 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK)); 1263 1264 /* select recovery clock from lane0 for rxck0_10g */ 1265 SOC_IF_ERROR_RETURN 1266 (MODIFY_HL65_XGXSBLK1_TESTTXr(unit,pc, 1267 0, 1268 XGXSBLK1_TESTTX_RX_CK4X1MUXSEL_MASK)); 1269 } 1270 1271 SOC_IF_ERROR_RETURN 1272 (_phy_hl65_independent_lane_init(unit, port)); 1273 } else { 1274 SOC_IF_ERROR_RETURN(_hl65_soft_reset(unit,pc)); /* soft reset */ 1275 1276 /* Force to comboCore mode. 1277 * Support SGMII 10/100/1000Mbps, 1000X, 2500X, 10G, and 12G. 1278 */ 1279 SOC_IF_ERROR_RETURN 1280 (_phy_hl65_combo_core_init(unit, port)); 1281 } 1282 1283 LOG_INFO(BSL_LS_SOC_PHY, 1284 (BSL_META_U(unit, 1285 "phy_hl65_init: u=%d p=%d\n"), unit, port)); 1286 return SOC_E_NONE; 1287 } 1288 1289 /* 1290 * phy_hl65_link_get 1291 * Purpose: 1292 * Get layer2 connection status. 1293 * Parameters: 1294 * unit - StrataSwitch unit #. 1295 * port - StrataSwitch port #. 1296 * link - address of memory to store link up/down state. 1297 * Returns: 1298 * SOC_E_NONE 1299 */ 1300 1301 STATIC int 1302 phy_hl65_link_get(int unit, soc_port_t port, int *link) 1303 { 1304 uint16 mii_stat; 1305 phy_ctrl_t *pc; 1306 1307 if (PHY_DISABLED_MODE(unit, port)) { 1308 *link = FALSE; 1309 return SOC_E_NONE; 1310 } 1311 1312 pc = INT_PHY_SW_STATE(unit, port); 1313 1314 *link = FALSE; 1315 /* Check XAUI link first if XAUI mode */ 1316 if (!PHY_INDEPENDENT_LANE_MODE(unit, port)) { 1317 SOC_IF_ERROR_RETURN 1318 (READ_HL65_DTE_IEEE0BLK_DTE_IEEESTATUS1r(unit, pc, &mii_stat)); 1319 if (mii_stat & MII_STAT_LA) { 1320 *link = TRUE; 1321 } 1322 } 1323 1324 /* Check combo link only if no XAUI link */ 1325 if (*link == FALSE) { 1326 SOC_IF_ERROR_RETURN 1327 (READ_HL65_COMBO_IEEE0_MIISTATr(unit, pc, &mii_stat)); 1328 if (mii_stat & MII_STAT_LA) { 1329 *link = TRUE; 1330 } else if (PHY_INDEPENDENT_LANE_MODE(unit,port)) { 1331 /* Check dxgxs link */ 1332 if ((pc->phy_mode == PHYCTRL_DUAL_LANE_PORT) && 1333 (IS_HG_PORT(unit,port) || IS_XE_PORT(unit,port))) { 1334 SOC_IF_ERROR_RETURN 1335 (READ_HL65_DTE_IEEE0BLK_DTE_IEEESTATUS1r(unit, pc, 1336 &mii_stat)); 1337 if (mii_stat & MII_STAT_LA) { 1338 *link = TRUE; 1339 } 1340 } 1341 } 1342 } 1343 1344 return (SOC_E_NONE); 1345 } 1346 1347 1348 /* 1349 * Function: 1350 * phy_hl65_enable_set 1351 * Purpose: 1352 * Enable/Disable phy 1353 * Parameters: 1354 * unit - StrataSwitch unit #. 1355 * port - StrataSwitch port #. 1356 * enable - on/off state to set 1357 * Returns: 1358 * SOC_E_NONE 1359 */ 1360 1361 STATIC int 1362 phy_hl65_enable_set(int unit, soc_port_t port, int enable) 1363 { 1364 int rv; 1365 phy_ctrl_t *pc; 1366 1367 pc = INT_PHY_SW_STATE(unit, port); 1368 1369 rv = SOC_E_NONE; 1370 if (PHY_INDEPENDENT_LANE_MODE(unit, port)) { 1371 if (enable) { 1372 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE); 1373 rv = _phy_hl65_notify_resume(unit, port, PHY_STOP_PHY_DIS); 1374 } else { 1375 PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE); 1376 rv = _phy_hl65_notify_stop(unit, port, PHY_STOP_PHY_DIS); 1377 } 1378 } else { 1379 if (enable) { 1380 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE); 1381 rv = MODIFY_HL65_XGXSBLK0_MISCCONTROL1r(unit, pc, 0, 1382 XGXSBLK0_MISCCONTROL1_GLOBAL_PMD_TX_DISABLE_MASK); 1383 1384 /* enable Rx */ 1385 rv = MODIFY_HL65_DSC2BB_DSC_MISC_CTRL0r(unit, pc, 0, 1386 DSC2BB_DSC_MISC_CTRL0_RXSEQSTART_MASK); 1387 1388 } else { 1389 PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE); 1390 rv = MODIFY_HL65_XGXSBLK0_MISCCONTROL1r(unit, pc, 1391 XGXSBLK0_MISCCONTROL1_GLOBAL_PMD_TX_DISABLE_MASK, 1392 XGXSBLK0_MISCCONTROL1_GLOBAL_PMD_TX_DISABLE_MASK); 1393 1394 /* disable Rx */ 1395 rv = MODIFY_HL65_DSC2BB_DSC_MISC_CTRL0r(unit, pc, 1396 DSC2BB_DSC_MISC_CTRL0_RXSEQSTART_MASK, 1397 DSC2BB_DSC_MISC_CTRL0_RXSEQSTART_MASK); 1398 } 1399 } 1400 return rv; 1401 } 1402 1403 /* 1404 * Function: 1405 * phy_hl65_enable_get 1406 * Purpose: 1407 * Get Enable/Disable status 1408 * Parameters: 1409 * unit - StrataSwitch unit #. 1410 * port - StrataSwitch port #. 1411 * enable - address of where to store on/off state 1412 * Returns: 1413 * SOC_E_NONE 1414 */ 1415 1416 STATIC int 1417 phy_hl65_enable_get(int unit, soc_port_t port, int *enable) 1418 { 1419 *enable = !PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE); 1420 1421 return SOC_E_NONE; 1422 } 1423 1424 STATIC int 1425 _phy_hl65_dsp_cfg (int unit, phy_ctrl_t *pc, int speed) 1426 { 1427 uint16 serdes_id0; 1428 uint16 brcdr; 1429 1430 /* For speed at 20G, configure the device for BR CDR. */ 1431 if (speed == 20000) { 1432 SOC_IF_ERROR_RETURN 1433 (READ_HL65_TEST_SERDESID0r(unit, pc, &serdes_id0)); 1434 1435 serdes_id0 = serdes_id0 & (TEST_SERDESID0_REV_NUMBER_MASK | 1436 TEST_SERDESID0_REV_LETTER_MASK); 1437 1438 if ((serdes_id0 == HL_SERDES_ID0_REVID_A0) || 1439 (serdes_id0 == HL_SERDES_ID0_REVID_A1) ) { 1440 brcdr = HL65_A0A1_DSC_DFE_BRCDR; 1441 } else if ((serdes_id0 == HL_SERDES_ID0_REVID_B0) || 1442 (serdes_id0 == HL_SERDES_ID0_REVID_C0) ) { 1443 brcdr = HL65_B0C0_DSC_DFE_BRCDR; 1444 } else { 1445 LOG_WARN(BSL_LS_SOC_PHY, 1446 (BSL_META_U(unit, 1447 "HL65 : BR-CDR setting may not be correct: u=%d p=%d\n"), unit, pc->port)); 1448 brcdr = HL65_B0C0_DSC_DFE_BRCDR; /* assumed for future versions */ 1449 } 1450 1451 /* enable DFE/BR CDR */ 1452 1453 SOC_IF_ERROR_RETURN 1454 (WRITE_HL65_DSC2BB_DSC_MISC_CTRL0r(unit, pc, brcdr)); 1455 } else { 1456 /* default value for CDR */ 1457 SOC_IF_ERROR_RETURN 1458 (WRITE_HL65_DSC2BB_DSC_MISC_CTRL0r(unit, pc, 0x2000)); 1459 } 1460 return SOC_E_NONE; 1461 } 1462 1463 /* 1464 * Function: 1465 * phy_hl65_fabric_mode_speed_set 1466 * Purpose: 1467 * Set PHY speed 1468 * Parameters: 1469 * unit - SBX device unit #. 1470 * port - SBX device port #. 1471 * speed - link speed in Mbps 1472 * Returns: 1473 * SOC_E_NONE 1474 */ 1475 1476 STATIC int 1477 phy_hl65_fabric_mode_speed_set(int unit, soc_port_t port, int speed) 1478 { 1479 phy_ctrl_t *pc; 1480 uint16 data; 1481 int rv = SOC_E_NONE; 1482 uint16 serdes_id0; 1483 1484 if (SOC_IS_RELOADING(unit)) { 1485 return SOC_E_NONE; 1486 } 1487 1488 pc = INT_PHY_SW_STATE(unit, port); 1489 1490 SOC_IF_ERROR_RETURN 1491 (READ_HL65_TEST_SERDESID0r(unit, pc, &serdes_id0)); 1492 1493 serdes_id0 = serdes_id0 & (TEST_SERDESID0_REV_NUMBER_MASK | 1494 TEST_SERDESID0_REV_LETTER_MASK); 1495 1496 switch (speed) { 1497 1498 case 3125: 1499 /* Disable baud rate CDR */ 1500 /* uRegAddr = 0x826e + (uLaneAddr*0x10)*/ 1501 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, uRegAddr, 0x2000) */ 1502 SOC_IF_ERROR_RETURN 1503 (HL65_REG_WRITE(unit, pc, 0x0, 0x826E + (0x10 * pc->lane_num), 1504 DSC2B0_DSC_MISC_CTRL0_ENABLE_ACOR_PICW_BITS << 1505 DSC2B0_DSC_MISC_CTRL0_ENABLE_ACOR_PICW_SHIFT)); 1506 1507 1508 1509 /* 6.25G rate half speed 0x603a */ 1510 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, 0x8308, 0x603A)*/ 1511 SOC_IF_ERROR_RETURN 1512 (WRITE_HL65_DIGITAL_MISC1r(unit, pc, 0x603a)); 1513 1514 /* Set 6.25G speed through the backdoor method clock divisor is in shared lane register */ 1515 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, 0, 0x8016, &uData) */ 1516 SOC_IF_ERROR_RETURN 1517 (READ_HL65_XGXSBLK1_LANECTRL1r(unit, pc, &data)); 1518 1519 /* clear bits */ 1520 data &= ~(0x0303 << (pc->lane_num * 2)); 1521 data |= (0x0202 << (pc->lane_num * 2)); 1522 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, 0x8016, uData) */ 1523 SOC_IF_ERROR_RETURN 1524 (WRITE_HL65_XGXSBLK1_LANECTRL1r(unit, pc, data)); 1525 1526 /* Set half-rate indicator for equalization algorithm to work */ 1527 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, 0x8065, &uData) */ 1528 SOC_IF_ERROR_RETURN 1529 (READ_HL65_TX0_ANATXACONTROL1r(unit, pc, &data)); 1530 1531 /* uData &= ~(BM9600_HYPERCORE_8065_TX_SEL_HALF_RATE_MASK << BM9600_HYPERCORE_8065_TX_SEL_HALF_RATE_SHIFT) */ 1532 /* uData |= (1 << BM9600_HYPERCORE_8065_TX_SEL_HALF_RATE_SHIFT) */ 1533 data &= ~(TX0_ANATXACONTROL1_TX_SEL_HALFRATE_BITS << 1534 TX0_ANATXACONTROL1_TX_SEL_HALFRATE_SHIFT); 1535 data |= (TX0_ANATXACONTROL1_TX_SEL_HALFRATE_BITS << 1536 TX0_ANATXACONTROL1_TX_SEL_HALFRATE_SHIFT); 1537 1538 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, 0x8065, uData) */ 1539 SOC_IF_ERROR_RETURN 1540 (WRITE_HL65_TX0_ANATXACONTROL1r(unit, pc, data)); 1541 1542 break; 1543 1544 case 6250: 1545 1546 /* Force baud rate CDR */ 1547 /* uRegAddr = 0x826e + (uLaneAddr*0x10) */ 1548 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, uRegAddr, 0x2180) */ 1549 if ((serdes_id0 == HL_SERDES_ID0_REVID_A0) || 1550 (serdes_id0 == HL_SERDES_ID0_REVID_A1)) { 1551 SOC_IF_ERROR_RETURN 1552 (HL65_REG_WRITE(unit, pc, 0x0, 0x826E + (0x10 * pc->lane_num), 1553 0x2180)); 1554 } else { 1555 SOC_IF_ERROR_RETURN 1556 (HL65_REG_WRITE(unit, pc, 0x0, 0x826E + (0x10 * pc->lane_num), 1557 0x2300)); 1558 } 1559 1560 /* 6.25G rate 156.25MHz then mult by 40 + independent lane mode setting */ 1561 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, 0x8308, 0x7720) */ 1562 SOC_IF_ERROR_RETURN 1563 (WRITE_HL65_DIGITAL_MISC1r(unit, pc, 0x7720)); 1564 1565 /* Set 6.25G speed through the backdoor method clock divisor is in shared lane register */ 1566 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, 0, 0x8016, &uData) */ 1567 SOC_IF_ERROR_RETURN 1568 (READ_HL65_XGXSBLK1_LANECTRL1r(unit, pc, &data)); 1569 1570 /* DWSDR_div1 = 0x3 for receive and transmit */ 1571 /* uData |= 0x0303 << (uLaneAddr * 2) */ 1572 data |= 0x0303 << (pc->lane_num * 2); 1573 1574 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, 0x8016, uData) */ 1575 SOC_IF_ERROR_RETURN 1576 (WRITE_HL65_XGXSBLK1_LANECTRL1r(unit, pc, data)); 1577 1578 1579 /* Clear half-rate indicator for equalization algorithm to work */ 1580 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, 0x8065, &uData) */ 1581 SOC_IF_ERROR_RETURN 1582 (READ_HL65_TX0_ANATXACONTROL1r(unit, pc, &data)); 1583 1584 /* uData &= ~(BM9600_HYPERCORE_8065_TX_SEL_HALF_RATE_MASK << BM9600_HYPERCORE_8065_TX_SEL_HALF_RATE_SHIFT) */ 1585 /* uData |= (0 << BM9600_HYPERCORE_8065_TX_SEL_HALF_RATE_SHIFT) */ 1586 data &= ~(TX0_ANATXACONTROL1_TX_SEL_HALFRATE_BITS << 1587 TX0_ANATXACONTROL1_TX_SEL_HALFRATE_SHIFT); 1588 1589 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, 0x8065, uData) */ 1590 SOC_IF_ERROR_RETURN 1591 (WRITE_HL65_TX0_ANATXACONTROL1r(unit, pc, data)); 1592 1593 break; 1594 1595 1596 case 6500: 1597 /* Jitter performance improvement over PVT - kvh_force=1 */ 1598 1599 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, 0x805e, 0x1877) */ 1600 SOC_IF_ERROR_RETURN 1601 (WRITE_HL65_TXPLL_ANAPLLACONTROL4r(unit, pc, 0x1877)); 1602 1603 1604 /* Force baud rate CDR */ 1605 /* uRegAddr = 0x826e + (uLaneAddr*0x10) */ 1606 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, uRegAddr, 0x2180) */ 1607 if ((serdes_id0 == HL_SERDES_ID0_REVID_A0) || 1608 (serdes_id0 == HL_SERDES_ID0_REVID_A1)) { 1609 SOC_IF_ERROR_RETURN 1610 (HL65_REG_WRITE(unit, pc, 0x0, 0x826E + (0x10 * pc->lane_num), 1611 0x2180)); 1612 } else { 1613 SOC_IF_ERROR_RETURN 1614 (HL65_REG_WRITE(unit, pc, 0x0, 0x826E + (0x10 * pc->lane_num), 1615 0x2300)); 1616 } 1617 1618 /* 6.5G independent lane mode setting */ 1619 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, 0x8308, 0x7820) */ 1620 SOC_IF_ERROR_RETURN 1621 (WRITE_HL65_DIGITAL_MISC1r(unit, pc, 0x7820)); 1622 1623 1624 /* Set 6.5G speed through the backdoor method clock divisor is in shared lane register */ 1625 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, 0, 0x8016, &uData) */ 1626 SOC_IF_ERROR_RETURN 1627 (READ_HL65_XGXSBLK1_LANECTRL1r(unit, pc, &data)); 1628 1629 /* DWSDR_div1 = 0x3 for receive and transmit */ 1630 /* uData |= 0x0303 << (uLaneAddr * 2) */ 1631 data |= 0x0303 << (pc->lane_num * 2); 1632 1633 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, 0x8016, uData) */ 1634 SOC_IF_ERROR_RETURN 1635 (WRITE_HL65_XGXSBLK1_LANECTRL1r(unit, pc, data)); 1636 1637 1638 /* Clear half-rate indicator for equalization algorithm to work */ 1639 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, 0x8065, &uData) */ 1640 SOC_IF_ERROR_RETURN 1641 (READ_HL65_TX0_ANATXACONTROL1r(unit, pc, &data)); 1642 1643 /* uData &= ~(BM9600_HYPERCORE_8065_TX_SEL_HALF_RATE_MASK << BM9600_HYPERCORE_8065_TX_SEL_HALF_RATE_SHIFT) */ 1644 /* uData |= (0 << BM9600_HYPERCORE_8065_TX_SEL_HALF_RATE_SHIFT) */ 1645 data &= ~(TX0_ANATXACONTROL1_TX_SEL_HALFRATE_BITS << 1646 TX0_ANATXACONTROL1_TX_SEL_HALFRATE_SHIFT); 1647 1648 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, 0x8065, uData) */ 1649 SOC_IF_ERROR_RETURN 1650 (WRITE_HL65_TX0_ANATXACONTROL1r(unit, pc, data)); 1651 1652 break; 1653 1654 default: 1655 rv = SOC_E_PARAM; 1656 } 1657 1658 return rv; 1659 } 1660 1661 1662 /* 1663 * Function: 1664 * phy_hl65_speed_set 1665 * Purpose: 1666 * Set PHY speed 1667 * Parameters: 1668 * unit - StrataSwitch unit #. 1669 * port - StrataSwitch port #. 1670 * speed - link speed in Mbps 1671 * Returns: 1672 * SOC_E_NONE 1673 */ 1674 1675 STATIC int 1676 phy_hl65_speed_set(int unit, soc_port_t port, int speed) 1677 { 1678 phy_ctrl_t *pc; 1679 uint16 speed_val, mask; 1680 uint16 speed_mii; 1681 uint16 sgmii_status = 0; 1682 int hg10g_port = FALSE; 1683 int rxaui; 1684 1685 if (PHY_HC65_FABRIC_MODE(unit, port)) { 1686 return phy_hl65_fabric_mode_speed_set(unit, port, speed); 1687 } 1688 1689 pc = INT_PHY_SW_STATE(unit, port); 1690 1691 if (PHY_INDEPENDENT_LANE_MODE(unit, port) && (speed > 12000)) { 1692 return SOC_E_PARAM; 1693 } 1694 1695 /* check if RXAUI is set in combo mode */ 1696 rxaui = soc_property_port_get(unit, port, 1697 spn_SERDES_2WIRE_XAUI, FALSE); 1698 1699 /* HC rev D0 supports 10G and 12G speeds in dxgxs mode in ind. lane mode */ 1700 if (pc->phy_mode == PHYCTRL_DUAL_LANE_PORT) { 1701 rxaui = TRUE; 1702 } 1703 1704 if (IS_HG_PORT(unit, port) && 1705 soc_property_port_get(unit, port, spn_10G_IS_CX4, TRUE) == FALSE) { 1706 hg10g_port = TRUE; 1707 } 1708 1709 speed_val = 0; 1710 speed_mii = 0; 1711 mask = DIGITAL_MISC1_FORCE_SPEED_MASK; 1712 switch (speed) { 1713 case 0: 1714 /* Do not change speed */ 1715 return SOC_E_NONE; 1716 case 10: 1717 speed_mii = MII_CTRL_SS_10; 1718 break; 1719 case 100: 1720 speed_mii = MII_CTRL_SS_100; 1721 break; 1722 case 1000: 1723 speed_mii = MII_CTRL_SS_1000; 1724 break; 1725 case 2500: 1726 speed_val = DIGITAL_MISC1_FORCE_SPEED_dr_2500BRCM_X1; 1727 break; 1728 case 10000: 1729 speed_val = DIGITAL_MISC1_FORCE_SPEED_dr_10GBASE_CX4; /* 10G CX4 */ 1730 if ((hg10g_port == TRUE) && rxaui) { 1731 speed_val = 0x21; /* 10.5HiG dual-XGXS */ 1732 } else if (rxaui) { 1733 speed_val = 0x20; /* 10G ethernet dual-XGXS */ 1734 } else if (hg10g_port == TRUE) { 1735 speed_val = DIGITAL_MISC1_FORCE_SPEED_dr_10GHiGig_X4; /* 10G HiG */ 1736 } 1737 break; 1738 case 12000: 1739 speed_val = rxaui? 0x23: /* 12.7HiG dual-XGXS*/ 1740 DIGITAL_MISC1_FORCE_SPEED_dr_12GHiGig_X4; /* 12 HiG */ 1741 break; 1742 case 13000: 1743 speed_val = DIGITAL_MISC1_FORCE_SPEED_dr_13GHiGig_X4; 1744 break; 1745 case 16000: 1746 speed_val = DIGITAL_MISC1_FORCE_SPEED_dr_16GHiGig_X4; 1747 break; 1748 case 20000: 1749 speed_val = DIGITAL_MISC1_FORCE_SPEED_dr_20GHiGig_X4; 1750 break; 1751 case 21000: 1752 speed_val = DIGITAL_MISC1_FORCE_SPEED_dr_21GHiGig_X4; 1753 break; 1754 case 25000: 1755 speed_val = DIGITAL_MISC1_FORCE_SPEED_dr_25p45GHiGig_X4; 1756 break; 1757 default: 1758 return SOC_E_PARAM; 1759 } 1760 1761 if (!PHY_INDEPENDENT_LANE_MODE(unit, port)) { 1762 /* set scrambler controls */ 1763 if (speed == 20000) { 1764 SOC_IF_ERROR_RETURN 1765 (MODIFY_HL65_XGXSBLK0_XGMIIRCONTROLr(unit,pc, 1766 XGXSBLK0_XGMIIRCONTROL_SCR_EN_4LANE_MASK, 1767 XGXSBLK0_XGMIIRCONTROL_SCR_EN_4LANE_MASK)); 1768 } else { 1769 SOC_IF_ERROR_RETURN 1770 (MODIFY_HL65_XGXSBLK0_XGMIIRCONTROLr(unit,pc, 1771 0, 1772 XGXSBLK0_XGMIIRCONTROL_SCR_EN_4LANE_MASK)); 1773 } 1774 _phy_hl65_dsp_cfg(unit,pc,speed); 1775 1776 /* Puts PLL in reset state and forces all datapath into reset state */ 1777 SOC_IF_ERROR_RETURN 1778 (MODIFY_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, 0, 1779 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK)); 1780 1781 /* 2wire XAUI configuration */ 1782 SOC_IF_ERROR_RETURN 1783 (_hl65_rxaui_config(unit,pc,rxaui)); 1784 1785 } else { 1786 /* Hold rxSeqStart */ 1787 SOC_IF_ERROR_RETURN 1788 (HL65_REG_MODIFY(unit,pc,0x0,0x826E + (0x10 * pc->lane_num), 1789 DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_MASK, 1790 DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_MASK)); 1791 1792 /* hold TX FIFO in reset */ 1793 SOC_IF_ERROR_RETURN 1794 (MODIFY_HL65_DIGITAL_CONTROL1000X3r(unit, pc, 1795 DIGITAL_CONTROL1000X3_TX_FIFO_RST_MASK, 1796 DIGITAL_CONTROL1000X3_TX_FIFO_RST_MASK)); 1797 } 1798 1799 /* disable 100FX and 100FX auto-detect */ 1800 SOC_IF_ERROR_RETURN 1801 (MODIFY_HL65_FX100_CONTROL1r(unit,pc, 1802 0, 1803 FX100_CONTROL1_AUTODET_EN_MASK | 1804 FX100_CONTROL1_ENABLE_MASK)); 1805 1806 /* disable 100FX idle detect */ 1807 SOC_IF_ERROR_RETURN 1808 (MODIFY_HL65_FX100_CONTROL3r(unit,pc, 1809 FX100_CONTROL3_CORRELATOR_DISABLE_MASK, 1810 FX100_CONTROL3_CORRELATOR_DISABLE_MASK)); 1811 1812 SOC_IF_ERROR_RETURN 1813 (MODIFY_HL65_DIGITAL_MISC1r(unit, pc, speed_val, mask)); 1814 1815 SOC_IF_ERROR_RETURN 1816 (MODIFY_HL65_DIGITAL4_MISC3r(unit, pc, 1817 (speed_val & 0x20)? DIGITAL4_MISC3_FORCE_SPEED_B5_MASK:0, 1818 DIGITAL4_MISC3_FORCE_SPEED_B5_MASK)); 1819 1820 if (speed <= 1000) { 1821 SOC_IF_ERROR_RETURN 1822 (READ_HL65_DIGITAL_STATUS1000X1r(unit, pc, &sgmii_status)); 1823 1824 sgmii_status &= DIGITAL_STATUS1000X1_SGMII_MODE_MASK; 1825 if (!sgmii_status && (speed == 100)) { 1826 1827 /* fiber mode 100fx, enable */ 1828 SOC_IF_ERROR_RETURN 1829 (MODIFY_HL65_FX100_CONTROL1r(unit,pc, 1830 FX100_CONTROL1_FAR_END_FAULT_EN_MASK | 1831 FX100_CONTROL1_ENABLE_MASK, 1832 FX100_CONTROL1_FAR_END_FAULT_EN_MASK | 1833 FX100_CONTROL1_ENABLE_MASK)); 1834 1835 /* enable 100fx extended packet size */ 1836 SOC_IF_ERROR_RETURN 1837 (MODIFY_HL65_FX100_CONTROL2r(unit,pc, 1838 FX100_CONTROL2_EXTEND_PKT_SIZE_MASK, 1839 FX100_CONTROL2_EXTEND_PKT_SIZE_MASK)); 1840 } else { 1841 SOC_IF_ERROR_RETURN 1842 (MODIFY_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, speed_mii, 1843 MII_CTRL_SS_MASK)); 1844 } 1845 } 1846 1847 /* for speed above 10G, txcko_div must be cleared */ 1848 speed_val = (speed > 10000) ? 0: XGXSBLK0_XGXSCONTROL_TXCKO_DIV_MASK; 1849 SOC_IF_ERROR_RETURN 1850 (MODIFY_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, speed_val, 1851 XGXSBLK0_XGXSCONTROL_TXCKO_DIV_MASK)); 1852 1853 /* set tx half rate based on speed */ 1854 SOC_IF_ERROR_RETURN 1855 (_phy_hl65_half_rate_set(unit,port,speed)); 1856 1857 if (!PHY_INDEPENDENT_LANE_MODE(unit, port)) { 1858 /* Bring PLL out of reset */ 1859 SOC_IF_ERROR_RETURN 1860 (MODIFY_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, 1861 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK, 1862 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK)); 1863 (void) _phy_hl65_pll_lock_wait(unit, port); 1864 } else { 1865 /* release rxSeqStart */ 1866 SOC_IF_ERROR_RETURN 1867 (HL65_REG_MODIFY(unit,pc,0x0,0x826E + (0x10 * pc->lane_num), 1868 0, 1869 DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_MASK)); 1870 1871 /* release TX FIFO reset */ 1872 SOC_IF_ERROR_RETURN 1873 (MODIFY_HL65_DIGITAL_CONTROL1000X3r(unit, pc, 1874 0, 1875 DIGITAL_CONTROL1000X3_TX_FIFO_RST_MASK)); 1876 } 1877 1878 return SOC_E_NONE; 1879 } 1880 1881 STATIC int 1882 _phy_hl65_tx_fifo_reset(int unit, soc_port_t port,uint32 speed) 1883 { 1884 uint16 data16; 1885 phy_ctrl_t *pc; 1886 pc = INT_PHY_SW_STATE(unit, port); 1887 1888 if (speed == 100) { 1889 /* check if it is in 100fx mode */ 1890 SOC_IF_ERROR_RETURN 1891 (READ_HL65_FX100_CONTROL1r(unit,pc,&data16)); 1892 1893 if (data16 & FX100_CONTROL1_ENABLE_MASK) { 1894 /* reset TX FIFO */ 1895 SOC_IF_ERROR_RETURN 1896 (HL65_REG_MODIFY(unit,pc,0x0,0x8061 + (0x10 * pc->lane_num), 1897 TX0_ANATXACONTROL0_TX1G_FIFO_RST_MASK, 1898 TX0_ANATXACONTROL0_TX1G_FIFO_RST_MASK)); 1899 1900 SOC_IF_ERROR_RETURN 1901 (HL65_REG_MODIFY(unit,pc,0x0,0x8061 + (0x10 * pc->lane_num), 1902 0, 1903 TX0_ANATXACONTROL0_TX1G_FIFO_RST_MASK)); 1904 } 1905 } 1906 return SOC_E_NONE; 1907 } 1908 1909 /* 1910 * Function: 1911 * phy_hl65_fabric_mode_speed_get 1912 * Purpose: 1913 * Get PHY speed 1914 * Parameters: 1915 * unit - SBX device unit #. 1916 * port - SBX device port #. 1917 * speed - link speed in Mbps 1918 * Returns: 1919 * SOC_E_NONE 1920 */ 1921 1922 STATIC int 1923 phy_hl65_fabric_mode_speed_get(int unit, soc_port_t port, int *speed) 1924 { 1925 phy_ctrl_t *pc; 1926 uint16 data; 1927 1928 pc = INT_PHY_SW_STATE(unit, port); 1929 1930 /* read speed from hardware */ 1931 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, 0x8308, &uData) */ 1932 SOC_IF_ERROR_RETURN 1933 (READ_HL65_DIGITAL_MISC1r(unit, pc, &data)); 1934 1935 if (data == 0x7720) { 1936 *speed = 6250; 1937 } else if (data == 0x7820) { 1938 *speed = 6500; 1939 } else { 1940 *speed = 3125; 1941 } 1942 return SOC_E_NONE; 1943 1944 } 1945 1946 /* 1947 * Function: 1948 * phy_hl65_speed_get 1949 * Purpose: 1950 * Get PHY speed 1951 * Parameters: 1952 * unit - StrataSwitch unit #. 1953 * port - StrataSwitch port #. 1954 * speed - current link speed in Mbps 1955 * Returns: 1956 * SOC_E_NONE 1957 */ 1958 STATIC int 1959 phy_hl65_speed_get(int unit, soc_port_t port, int *speed) 1960 { 1961 phy_ctrl_t *pc; 1962 uint16 speed_val; 1963 1964 if (PHY_HC65_FABRIC_MODE(unit, port)) { 1965 return phy_hl65_fabric_mode_speed_get(unit, port, speed); 1966 } 1967 1968 pc = INT_PHY_SW_STATE(unit, port); 1969 1970 if (PHY_INDEPENDENT_LANE_MODE(unit, port)) { 1971 uint16 sd_stat; 1972 1973 SOC_IF_ERROR_RETURN 1974 (READ_HL65_DIGITAL_STATUS1000X1r(unit, pc, &sd_stat)); 1975 sd_stat = (sd_stat & DIGITAL_STATUS1000X1_SPEED_STATUS_MASK) 1976 >> DIGITAL_STATUS1000X1_SPEED_STATUS_SHIFT; 1977 switch (sd_stat) { 1978 case 2: 1979 *speed = 1000; 1980 break; 1981 case 3: 1982 *speed = 2500; 1983 break; 1984 case 0: 1985 *speed = 10; 1986 break; 1987 case 1: 1988 *speed = 100; 1989 break; 1990 default: 1991 *speed = 0; 1992 } 1993 /* check dxgxs speeds 1994 * There is no speed status for second dxgxs block. We'll simply 1995 * check what the speed is set. It should be OK since the dxgxs mode 1996 * does not support autoneg 1997 */ 1998 if ((pc->phy_mode == PHYCTRL_DUAL_LANE_PORT) && 1999 (IS_HG_PORT(unit,port) || IS_XE_PORT(unit,port))) { 2000 SOC_IF_ERROR_RETURN 2001 (READ_HL65_DIGITAL4_MISC3r(unit, pc, &speed_val)); 2002 if (speed_val & DIGITAL4_MISC3_FORCE_SPEED_B5_MASK) { 2003 SOC_IF_ERROR_RETURN 2004 (READ_HL65_DIGITAL_MISC1r(unit, pc, &speed_val)); 2005 if ((speed_val & DIGITAL_MISC1_FORCE_SPEED_MASK) == 3) { 2006 *speed=12000; 2007 } else if ((speed_val & DIGITAL_MISC1_FORCE_SPEED_MASK) == 0 || 2008 (speed_val & DIGITAL_MISC1_FORCE_SPEED_MASK) == 1) { 2009 *speed=10000; 2010 } 2011 } 2012 } 2013 } else { 2014 uint16 xgxs_stat; 2015 uint16 xgxs20g_stat = 0; 2016 2017 SOC_IF_ERROR_RETURN 2018 (READ_HL65_GP_STATUS_XGXSSTATUS1r(unit, pc, &xgxs_stat)); 2019 2020 switch (xgxs_stat & GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_MASK) { 2021 case GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_dr_10M: 2022 *speed = 10; 2023 break; 2024 case GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_dr_100M: 2025 *speed = 100; 2026 break; 2027 case GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_dr_1G: 2028 *speed = 1000; 2029 break; 2030 case GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_dr_2p5G: 2031 *speed = 2500; 2032 break; 2033 case GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_dr_5G_X4: 2034 *speed = 5000; 2035 break; 2036 case GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_dr_6G_X4: 2037 *speed = 6000; 2038 break; 2039 case GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_dr_10G_HiG: 2040 /* fall through */ 2041 case GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_dr_10G_CX4: 2042 *speed = 10000; 2043 break; 2044 case GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_dr_12G_HiG: 2045 case GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_dr_12p5G_X4: 2046 *speed = 12000; 2047 break; 2048 case GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_dr_13G_X4: 2049 *speed = 13000; 2050 break; 2051 case GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_dr_15G_X4: 2052 *speed = 15000; 2053 break; 2054 case GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_dr_16G_X4: 2055 *speed = 16000; 2056 break; 2057 case GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_dr_1G_KX: 2058 *speed = 1000; 2059 break; 2060 case GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_dr_10G_KX4: 2061 *speed = 10000; 2062 break; 2063 default: 2064 *speed = 0; 2065 } 2066 2067 /* check 20G and above and dxgxs speed */ 2068 SOC_IF_ERROR_RETURN 2069 (READ_HL65_AN73_PDET_XGXSSTATUS4r(unit, pc, &xgxs20g_stat)); 2070 xgxs20g_stat &= AN73_PDET_XGXSSTATUS4_ACTUAL_SPEED_LN0_MASK; 2071 switch (xgxs20g_stat) { 2072 case AN73_PDET_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_20G_X4: 2073 *speed=20000; 2074 break; 2075 case AN73_PDET_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_21G_X4: 2076 *speed=21000; 2077 break; 2078 case AN73_PDET_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_25G_X4: 2079 *speed=25000; 2080 break; 2081 case AN73_PDET_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10G_HiG_DXGXS: 2082 /* fall through */ 2083 case AN73_PDET_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10G_DXGXS: 2084 /* fall through */ 2085 case AN73_PDET_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10p5G_HiG_DXGXS: 2086 /* fall through */ 2087 case AN73_PDET_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_10p5G_DXGXS: 2088 *speed = 10000; 2089 break; 2090 case AN73_PDET_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_12p773G_HiG_DXGXS: /* fall through */ 2091 case AN73_PDET_XGXSSTATUS4_ACTUAL_SPEED_LN0_dr_12p773G_DXGXS: 2092 *speed = 12000; 2093 break; 2094 default: 2095 break; 2096 } 2097 2098 LOG_INFO(BSL_LS_SOC_PHY, 2099 (BSL_META_U(unit, 2100 "phy_hl65_speed_get: u=%d p=%d GP_STATUS_TOPANSTATUS1 %04x speed= %d\n"), 2101 unit, port, 2102 ((xgxs_stat & GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_MASK) >> 2103 GP_STATUS_XGXSSTATUS1_ACTUAL_SPEED_LN0_SHIFT), *speed)); 2104 2105 } 2106 return SOC_E_NONE; 2107 } 2108 2109 /* 2110 * Function: 2111 * phy_hl65_an_set 2112 * Purpose: 2113 * Enable or disabled auto-negotiation on the specified port. 2114 * Parameters: 2115 * unit - StrataSwitch unit #. 2116 * port - StrataSwitch port #. 2117 * an - Boolean, if true, auto-negotiation is enabled 2118 * (and/or restarted). If false, autonegotiation is disabled. 2119 * Returns: 2120 * SOC_E_XXX 2121 */ 2122 int 2123 phy_hl65_an_set(int unit, soc_port_t port, int an) 2124 { 2125 phy_ctrl_t *pc; 2126 uint16 an_enable; 2127 uint16 auto_det; 2128 uint16 data16; 2129 uint16 mask16; 2130 2131 pc = INT_PHY_SW_STATE(unit, port); 2132 2133 LOG_INFO(BSL_LS_SOC_PHY, 2134 (BSL_META_U(unit, 2135 "phy_hl65_an_set: u=%d p=%d an=%d\n"), 2136 unit, port, an)); 2137 2138 an_enable = 0; 2139 auto_det = 0; 2140 2141 if (!PHY_INDEPENDENT_LANE_MODE(unit, port)) { 2142 data16 = 0; 2143 mask16 = AN73_PDET_PARDET10GCONTROL_PARDET10G_EN_MASK; 2144 if (soc_property_port_get(unit, port, spn_XGXS_PDETECT_10G, 1) && an) { 2145 data16 = AN73_PDET_PARDET10GCONTROL_PARDET10G_EN_MASK; 2146 } 2147 SOC_IF_ERROR_RETURN 2148 (MODIFY_HL65_AN73_PDET_PARDET10GCONTROLr(unit, pc, data16, 2149 mask16)); 2150 2151 /* Always enable 1000X parallel detect */ 2152 SOC_IF_ERROR_RETURN 2153 (MODIFY_HL65_DIGITAL_CONTROL1000X2r(unit, pc, 2154 DIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK, 2155 DIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK)); 2156 } 2157 2158 if (an) { 2159 2160 /* disable 100FX and 100FX auto-detect */ 2161 SOC_IF_ERROR_RETURN 2162 (MODIFY_HL65_FX100_CONTROL1r(unit,pc, 2163 0, 2164 FX100_CONTROL1_AUTODET_EN_MASK | 2165 FX100_CONTROL1_ENABLE_MASK)); 2166 2167 /* disable 100FX idle detect */ 2168 SOC_IF_ERROR_RETURN 2169 (MODIFY_HL65_FX100_CONTROL3r(unit,pc, 2170 FX100_CONTROL3_CORRELATOR_DISABLE_MASK, 2171 FX100_CONTROL3_CORRELATOR_DISABLE_MASK)); 2172 2173 /* set tx half rate with default value before starting AN */ 2174 SOC_IF_ERROR_RETURN 2175 (_phy_hl65_half_rate_set(unit,port,0)); 2176 2177 an_enable = MII_CTRL_AE | MII_CTRL_RAN; 2178 2179 /* 2180 * Should read one during init and cache it in Phy flags 2181 */ 2182 if (soc_property_port_get(unit, port, 2183 spn_SERDES_AUTOMEDIUM, 2184 (PHY_INDEPENDENT_LANE_MODE(unit, port)) ? 2185 FALSE : TRUE)) { 2186 auto_det = DIGITAL_CONTROL1000X1_AUTODET_EN_MASK; 2187 } 2188 2189 /* If auto-neg is enabled, make sure not forcing any speed */ 2190 SOC_IF_ERROR_RETURN 2191 (MODIFY_HL65_DIGITAL_MISC1r(unit, pc, 0, 2192 DIGITAL_MISC1_FORCE_SPEED_MASK)); 2193 /* Enable/Disable auto detect */ 2194 SOC_IF_ERROR_RETURN 2195 (MODIFY_HL65_DIGITAL_CONTROL1000X1r(unit, pc, auto_det, 2196 DIGITAL_CONTROL1000X1_AUTODET_EN_MASK)); 2197 2198 if (!PHY_INDEPENDENT_LANE_MODE(unit, port)) { 2199 2200 /* 2201 * Set the default value for DSP related registers which may be 2202 * changed for 20G forced speed mode, otherwise AN won't work 2203 */ 2204 /* clear scrambler controls */ 2205 SOC_IF_ERROR_RETURN 2206 (MODIFY_HL65_XGXSBLK0_XGMIIRCONTROLr(unit,pc, 2207 0, 2208 XGXSBLK0_XGMIIRCONTROL_SCR_EN_4LANE_MASK)); 2209 2210 _phy_hl65_dsp_cfg(unit,pc,0); 2211 2212 /* clear 2wire XAUI configuration */ 2213 SOC_IF_ERROR_RETURN 2214 (_hl65_rxaui_config(unit,pc,FALSE)); 2215 2216 /* only in combo mode, reset the sequence. In independent mode, 2217 * resetting sequence affects all lanes 2218 */ 2219 SOC_IF_ERROR_RETURN 2220 (MODIFY_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, 0, 2221 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK)); 2222 2223 2224 /* set BAM enable */ 2225 SOC_IF_ERROR_RETURN 2226 (WRITE_HL65_DIGITAL6_MP5_NEXTPAGECTRLr(unit,pc,1)); 2227 2228 /* enable autoneg */ 2229 SOC_IF_ERROR_RETURN 2230 (MODIFY_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, MII_CTRL_AE, 2231 MII_CTRL_AE)); 2232 if (PHY_CLAUSE73_MODE(unit, port)) { 2233 SOC_IF_ERROR_RETURN 2234 (MODIFY_HL65_AN_IEEE0BLK_AN_IEEECONTROL1r(unit, pc, 2235 MII_CTRL_AE, 2236 MII_CTRL_AE)); 2237 } 2238 /* restart the sequence */ 2239 SOC_IF_ERROR_RETURN 2240 (MODIFY_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, 2241 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK, 2242 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK)); 2243 /* wait for PLL lock */ 2244 _phy_hl65_pll_lock_wait(unit, port); 2245 } 2246 } else { 2247 /* Disable auto detect */ 2248 SOC_IF_ERROR_RETURN 2249 (MODIFY_HL65_DIGITAL_CONTROL1000X1r(unit, pc, auto_det, 2250 DIGITAL_CONTROL1000X1_AUTODET_EN_MASK)); 2251 2252 if (!PHY_INDEPENDENT_LANE_MODE(unit, port)) { 2253 SOC_IF_ERROR_RETURN 2254 (MODIFY_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, 0, 2255 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK)); 2256 2257 /* reset BAM enable */ 2258 SOC_IF_ERROR_RETURN 2259 (WRITE_HL65_DIGITAL6_MP5_NEXTPAGECTRLr(unit,pc,0)); 2260 2261 SOC_IF_ERROR_RETURN 2262 (MODIFY_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, 0, 2263 MII_CTRL_AE)); 2264 if (PHY_CLAUSE73_MODE(unit, port)) { 2265 SOC_IF_ERROR_RETURN 2266 (MODIFY_HL65_AN_IEEE0BLK_AN_IEEECONTROL1r(unit, pc, 2267 0, 2268 MII_CTRL_AE)); 2269 } 2270 SOC_IF_ERROR_RETURN 2271 (MODIFY_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, 2272 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK, 2273 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK)); 2274 /* wait for PLL lock */ 2275 _phy_hl65_pll_lock_wait(unit, port); 2276 } 2277 } 2278 2279 /* restart the autoneg if enabled, or disable the autoneg */ 2280 SOC_IF_ERROR_RETURN 2281 (MODIFY_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, an_enable, 2282 MII_CTRL_AE | MII_CTRL_RAN)); 2283 2284 if (PHY_CLAUSE73_MODE(unit, port)) { 2285 SOC_IF_ERROR_RETURN 2286 (MODIFY_HL65_AN_IEEE0BLK_AN_IEEECONTROL1r(unit, pc, an_enable, 2287 MII_CTRL_AE | MII_CTRL_RAN)); 2288 } 2289 pc->fiber.autoneg_enable = an; 2290 2291 return SOC_E_NONE; 2292 } 2293 2294 /* 2295 * Function: 2296 * phy_hl65_an_get 2297 * Purpose: 2298 * Get the current auto-negotiation status (enabled/busy) 2299 * Parameters: 2300 * unit - StrataSwitch unit #. 2301 * port - StrataSwitch port #. 2302 * an - (OUT) if true, auto-negotiation is enabled. 2303 * an_done - (OUT) if true, auto-negotiation is complete. This 2304 * value is undefined if an == false. 2305 * Returns: 2306 * SOC_E_XXX 2307 */ 2308 2309 STATIC int 2310 phy_hl65_an_get(int unit, soc_port_t port, int *an, int *an_done) 2311 { 2312 uint16 mii_ctrl; 2313 uint16 mii_stat; 2314 phy_ctrl_t *pc; 2315 2316 pc = INT_PHY_SW_STATE(unit, port); 2317 2318 SOC_IF_ERROR_RETURN 2319 (READ_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, &mii_ctrl)); 2320 SOC_IF_ERROR_RETURN 2321 (READ_HL65_COMBO_IEEE0_MIISTATr(unit, pc, &mii_stat)); 2322 2323 *an = (mii_ctrl & MII_CTRL_AE) ? TRUE : FALSE; 2324 *an_done = (mii_stat & MII_STAT_AN_DONE) ? TRUE : FALSE; 2325 if (!((*an == TRUE) && (*an_done == TRUE))) { 2326 if (PHY_CLAUSE73_MODE(unit, port)) { 2327 /* check clause 73 */ 2328 SOC_IF_ERROR_RETURN 2329 (READ_HL65_AN_IEEE0BLK_AN_IEEECONTROL1r(unit, pc, &mii_ctrl)); 2330 SOC_IF_ERROR_RETURN 2331 (READ_HL65_AN_IEEE0BLK_AN_IEEESTATUS1r(unit, pc, &mii_stat)); 2332 2333 *an = (mii_ctrl & MII_CTRL_AE) ? TRUE : FALSE; 2334 *an_done = (mii_stat & MII_STAT_AN_DONE) ? TRUE : FALSE; 2335 } 2336 } 2337 return SOC_E_NONE; 2338 } 2339 2340 STATIC int 2341 _phy_hl65_c73_adv_local_set(int unit, soc_port_t port, 2342 soc_port_ability_t *ability) 2343 { 2344 uint16 an_adv; 2345 uint16 pause; 2346 phy_ctrl_t *pc; 2347 2348 pc = INT_PHY_SW_STATE(unit, port); 2349 2350 an_adv = (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) ? 2351 CL73_AN_ADV_TECH_1G_KX : 0; 2352 an_adv |= (ability->speed_full_duplex & SOC_PA_SPEED_10GB) ? 2353 CL73_AN_ADV_TECH_10G_KX4 : 0; 2354 2355 SOC_IF_ERROR_RETURN 2356 (MODIFY_HL65_AN_IEEE1BLK_AN_ADVERTISEMENT1r(unit, pc, an_adv, 2357 CL73_AN_ADV_TECH_SPEEDS_MASK)); 2358 2359 switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) { 2360 case SOC_PA_PAUSE_TX: 2361 pause = CL73_AN_ADV_ASYM_PAUSE; 2362 break; 2363 case SOC_PA_PAUSE_RX: 2364 pause = CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE; 2365 break; 2366 case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX: 2367 pause = CL73_AN_ADV_PAUSE; 2368 break; 2369 default: 2370 pause = 0; 2371 } 2372 2373 SOC_IF_ERROR_RETURN 2374 (MODIFY_HL65_AN_IEEE1BLK_AN_ADVERTISEMENT0r(unit, pc, pause, 2375 (CL73_AN_ADV_PAUSE | 2376 CL73_AN_ADV_ASYM_PAUSE))); 2377 2378 LOG_INFO(BSL_LS_SOC_PHY, 2379 (BSL_META_U(unit, 2380 "_phy_hl65_c73_adv_local_set: u=%d p=%d pause=%08x speeds=%04x,adv=0x%x\n"), 2381 unit, port, pause, an_adv,ability->speed_full_duplex)); 2382 return SOC_E_NONE; 2383 } 2384 2385 STATIC int 2386 _phy_hl65_c73_adv_local_get(int unit, soc_port_t port, 2387 soc_port_ability_t *ability) 2388 { 2389 uint16 an_adv; 2390 soc_port_mode_t speeds,pause; 2391 phy_ctrl_t *pc; 2392 2393 pc = INT_PHY_SW_STATE(unit, port); 2394 2395 SOC_IF_ERROR_RETURN 2396 (READ_HL65_AN_IEEE1BLK_AN_ADVERTISEMENT1r(unit, pc, &an_adv)); 2397 2398 speeds = (an_adv & CL73_AN_ADV_TECH_1G_KX) ? SOC_PA_SPEED_1000MB : 0; 2399 speeds |= (an_adv & CL73_AN_ADV_TECH_10G_KX4) ? SOC_PA_SPEED_10GB : 0; 2400 ability->speed_full_duplex |= speeds; 2401 2402 SOC_IF_ERROR_RETURN 2403 (READ_HL65_AN_IEEE1BLK_AN_ADVERTISEMENT0r(unit, pc, &an_adv)); 2404 2405 switch (an_adv & (CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE)) { 2406 case CL73_AN_ADV_PAUSE: 2407 pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 2408 break; 2409 case CL73_AN_ADV_ASYM_PAUSE: 2410 pause = SOC_PA_PAUSE_TX; 2411 break; 2412 case CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE: 2413 pause = SOC_PA_PAUSE_RX; 2414 break; 2415 default: 2416 pause = 0; 2417 } 2418 ability->pause = pause; 2419 2420 LOG_INFO(BSL_LS_SOC_PHY, 2421 (BSL_META_U(unit, 2422 "_phy_hl65_c73_adv_local_get: u=%d p=%d pause=%08x speeds=%04x\n"), 2423 unit, port, pause, speeds)); 2424 return SOC_E_NONE; 2425 } 2426 2427 /* 2428 * Function: 2429 * phy_hl65_ability_advert_set 2430 * Purpose: 2431 * Set the current advertisement for auto-negotiation. 2432 * Parameters: 2433 * unit - StrataSwitch unit #. 2434 * port - StrataSwitch port #. 2435 * mode - Port mode mask indicating supported options/speeds. 2436 * Returns: 2437 * SOC_E_XXX 2438 * Notes: 2439 * The advertisement is set only for the ACTIVE medium. 2440 * No synchronization performed at this level. 2441 */ 2442 2443 STATIC int 2444 phy_hl65_ability_advert_set(int unit, soc_port_t port, 2445 soc_port_ability_t *ability) 2446 { 2447 uint16 an_adv; 2448 uint16 an_sp_20g; 2449 soc_port_mode_t mode; 2450 phy_ctrl_t *pc; 2451 2452 if (NULL == ability) { 2453 return (SOC_E_PARAM); 2454 } 2455 2456 pc = INT_PHY_SW_STATE(unit, port); 2457 2458 /* 2459 * Set advertised duplex (only FD supported). 2460 */ 2461 an_adv = (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) ? MII_ANA_C37_FD : 0; 2462 2463 /* 2464 * Set advertised pause bits in link code word. 2465 */ 2466 switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) { 2467 case SOC_PA_PAUSE_TX: 2468 an_adv |= MII_ANA_C37_ASYM_PAUSE; 2469 break; 2470 case SOC_PA_PAUSE_RX: 2471 an_adv |= MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE; 2472 break; 2473 case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX: 2474 an_adv |= MII_ANA_C37_PAUSE; 2475 break; 2476 } 2477 /* Update less than 1G capability */ 2478 SOC_IF_ERROR_RETURN 2479 (WRITE_HL65_COMBO_IEEE0_AUTONEGADVr(unit, pc, an_adv)); 2480 2481 mode = ability->speed_full_duplex; 2482 an_adv = 0; 2483 an_sp_20g = 0; 2484 if (!PHY_INDEPENDENT_LANE_MODE(unit, port)) { 2485 an_adv |= (mode & SOC_PA_SPEED_2500MB) ? 2486 DIGITAL3_UP1_DATARATE_2P5GX1_MASK : 0; 2487 an_adv |= (mode & SOC_PA_SPEED_12GB) ? 2488 DIGITAL3_UP1_DATARATE_12GX4_MASK : 0; 2489 an_adv |= (mode & SOC_PA_SPEED_13GB) ? 2490 DIGITAL3_UP1_DATARATE_13GX4_MASK : 0; 2491 an_adv |= (mode & SOC_PA_SPEED_16GB) ? 2492 DIGITAL3_UP1_DATARATE_16GX4_MASK : 0; 2493 2494 /* 20G operation in autoneg is not reliable. 2495 * Use forced mode only. 2496 *an_adv |= (mode & SOC_PA_SPEED_20GB) ? 2497 * DIGITAL3_UP1_DATARATE_20GX4_MASK : 0; 2498 */ 2499 2500 an_sp_20g |= (mode & SOC_PA_SPEED_21GB) ? 2501 DIGITAL3_UP3_DATARATE_21GX4_MASK : 0; 2502 an_sp_20g |= (mode & SOC_PA_SPEED_25GB) ? 2503 DIGITAL3_UP3_DATARATE_25P45GX4_MASK : 0; 2504 } 2505 2506 if (mode & SOC_PA_SPEED_10GB) { 2507 if (IS_HG_PORT(unit, port)) { 2508 /* For Draco and Hercules, use pre-CX4 signalling */ 2509 an_adv |= DIGITAL3_UP1_DATARATE_10GX4_MASK; 2510 if (soc_property_port_get(unit, port, spn_10G_IS_CX4, TRUE)) { 2511 /* Also include 10G CX4 signalling by default */ 2512 an_adv |= DIGITAL3_UP1_DATARATE_10GCX4_MASK; 2513 } 2514 } else { 2515 an_adv |= DIGITAL3_UP1_DATARATE_10GCX4_MASK; 2516 } 2517 } 2518 SOC_IF_ERROR_RETURN 2519 (WRITE_HL65_DIGITAL3_UP1r(unit, pc, an_adv)); 2520 2521 SOC_IF_ERROR_RETURN 2522 (MODIFY_HL65_DIGITAL3_UP3r(unit, pc, an_sp_20g, 2523 OVER1G_UP3_20GPLUS_MASK)); 2524 2525 if (PHY_CLAUSE73_MODE(unit, port)) { 2526 SOC_IF_ERROR_RETURN 2527 (_phy_hl65_c73_adv_local_set(unit, port, ability)); 2528 } 2529 2530 LOG_INFO(BSL_LS_SOC_PHY, 2531 (BSL_META_U(unit, 2532 "phy_hl65_ability_advert_set: u=%d p=%d pause=%08x OVER1G_UP1 %04x\n"), 2533 unit, port, ability->pause, an_adv)); 2534 return SOC_E_NONE; 2535 } 2536 2537 /* 2538 * Function: 2539 * phy_hl65_ability_advert_get 2540 * Purpose: 2541 * Get the current advertisement for auto-negotiation. 2542 * Parameters: 2543 * unit - StrataSwitch unit #. 2544 * port - StrataSwitch port #. 2545 * mode - (OUT) Port mode mask indicating supported options/speeds. 2546 * Returns: 2547 * SOC_E_XXX 2548 * Notes: 2549 * The advertisement is retrieved for the ACTIVE medium. 2550 * No synchronization performed at this level. 2551 */ 2552 2553 STATIC int 2554 phy_hl65_ability_advert_get(int unit, soc_port_t port, 2555 soc_port_ability_t *ability) 2556 { 2557 uint16 an_adv; 2558 uint16 an_sp_20g; 2559 soc_port_mode_t mode; 2560 phy_ctrl_t *pc; 2561 2562 if (NULL == ability) { 2563 return (SOC_E_PARAM); 2564 } 2565 2566 pc = INT_PHY_SW_STATE(unit, port); 2567 2568 sal_memset(ability, 0, sizeof(*ability)); 2569 SOC_IF_ERROR_RETURN 2570 (READ_HL65_DIGITAL3_UP1r(unit, pc, &an_adv)); 2571 2572 SOC_IF_ERROR_RETURN 2573 (READ_HL65_DIGITAL3_UP3r(unit, pc, &an_sp_20g)); 2574 2575 mode = 0; 2576 mode |= (an_sp_20g & DIGITAL3_UP3_DATARATE_25P45GX4_MASK) ? 2577 SOC_PA_SPEED_25GB : 0; 2578 mode |= (an_sp_20g & DIGITAL3_UP3_DATARATE_21GX4_MASK) ? 2579 SOC_PA_SPEED_21GB : 0; 2580 mode |= (an_adv & DIGITAL3_UP1_DATARATE_20GX4_MASK) ? SOC_PA_SPEED_20GB : 0; 2581 mode |= (an_adv & DIGITAL3_UP1_DATARATE_16GX4_MASK) ? SOC_PA_SPEED_16GB : 0; 2582 mode |= (an_adv & DIGITAL3_UP1_DATARATE_13GX4_MASK) ? SOC_PA_SPEED_13GB : 0; 2583 mode |= (an_adv & DIGITAL3_UP1_DATARATE_12GX4_MASK) ? SOC_PA_SPEED_12GB : 0; 2584 mode |= (an_adv & DIGITAL3_UP1_DATARATE_10GCX4_MASK) ? SOC_PA_SPEED_10GB: 0; 2585 mode |= (an_adv & DIGITAL3_UP1_DATARATE_10GX4_MASK) ? SOC_PA_SPEED_10GB : 0; 2586 mode |= (an_adv & DIGITAL3_UP1_DATARATE_2P5GX1_MASK) ? 2587 SOC_PA_SPEED_2500MB : 0; 2588 2589 SOC_IF_ERROR_RETURN 2590 (READ_HL65_COMBO_IEEE0_AUTONEGADVr(unit, pc, &an_adv)); 2591 2592 mode |= (an_adv & MII_ANA_C37_FD) ? SOC_PA_SPEED_1000MB : 0; 2593 ability->speed_full_duplex = mode; 2594 2595 mode = 0; 2596 switch (an_adv & (MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE)) { 2597 case MII_ANA_C37_PAUSE: 2598 mode = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 2599 break; 2600 case MII_ANA_C37_ASYM_PAUSE: 2601 mode = SOC_PA_PAUSE_TX; 2602 break; 2603 case MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE: 2604 mode = SOC_PA_PAUSE_RX; 2605 break; 2606 } 2607 ability->pause = mode; 2608 2609 /* check for clause73 */ 2610 if (PHY_CLAUSE73_MODE(unit, port)) { 2611 SOC_IF_ERROR_RETURN 2612 (_phy_hl65_c73_adv_local_get(unit, port, ability)); 2613 } 2614 2615 LOG_INFO(BSL_LS_SOC_PHY, 2616 (BSL_META_U(unit, 2617 "phy_hl65_ability_advert_get:unit=%d p=%d pause=%08x sp=%08x\n"), 2618 unit, port, ability->pause, ability->speed_full_duplex)); 2619 2620 return SOC_E_NONE; 2621 } 2622 2623 STATIC int 2624 _phy_hl65_c73_adv_remote_get(int unit, soc_port_t port, 2625 soc_port_ability_t *ability) 2626 { 2627 uint16 an_adv; 2628 soc_port_mode_t mode; 2629 phy_ctrl_t *pc; 2630 2631 pc = INT_PHY_SW_STATE(unit, port); 2632 SOC_IF_ERROR_RETURN 2633 (READ_HL65_AN_IEEE1BLK_AN_LP_BASEPAGEABILITY1r(unit, pc, &an_adv)); 2634 2635 mode = (an_adv & CL73_AN_ADV_TECH_1G_KX) ? SOC_PA_SPEED_1000MB : 0; 2636 mode |= (an_adv & CL73_AN_ADV_TECH_10G_KX4) ? SOC_PA_SPEED_10GB : 0; 2637 ability->speed_full_duplex |= mode; 2638 2639 SOC_IF_ERROR_RETURN 2640 (READ_HL65_AN_IEEE1BLK_AN_LP_BASEPAGEABILITY0r(unit, pc, &an_adv)); 2641 2642 mode = 0; 2643 switch (an_adv & (CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE)) { 2644 case CL73_AN_ADV_PAUSE: 2645 mode = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 2646 break; 2647 case CL73_AN_ADV_ASYM_PAUSE: 2648 mode = SOC_PA_PAUSE_TX; 2649 break; 2650 case CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE: 2651 mode = SOC_PA_PAUSE_RX; 2652 break; 2653 } 2654 ability->pause = mode; 2655 2656 return SOC_E_NONE; 2657 } 2658 2659 /* 2660 * Function: 2661 * phy_hl65_ability_remote_get 2662 * Purpose: 2663 * Get the current advertisement for auto-negotiation. 2664 * Parameters: 2665 * unit - StrataSwitch unit #. 2666 * port - StrataSwitch port #. 2667 * mode - (OUT) Port mode mask indicating supported options/speeds. 2668 * Returns: 2669 * SOC_E_XXX 2670 * Notes: 2671 * The advertisement is retrieved for the ACTIVE medium. 2672 * No synchronization performed at this level. 2673 */ 2674 2675 STATIC int 2676 phy_hl65_ability_remote_get(int unit, soc_port_t port, 2677 soc_port_ability_t *ability) 2678 { 2679 uint16 an_adv; 2680 uint16 an_sp_20g; 2681 uint16 data16; 2682 int an_enable; 2683 int link_1000x = FALSE; 2684 int link_combo = FALSE; 2685 soc_port_mode_t mode; 2686 phy_ctrl_t *pc; 2687 2688 pc = INT_PHY_SW_STATE(unit, port); 2689 2690 SOC_IF_ERROR_RETURN 2691 (READ_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, &data16)); 2692 2693 an_enable = (data16 & MII_CTRL_AE) ? TRUE : FALSE; 2694 2695 if (PHY_INDEPENDENT_LANE_MODE(unit, port)) { 2696 SOC_IF_ERROR_RETURN 2697 (READ_HL65_DIGITAL_STATUS1000X1r(unit, pc, &data16)); 2698 if (data16 & DIGITAL_STATUS1000X1_LINK_STATUS_MASK) { 2699 link_1000x = TRUE; 2700 } 2701 } else { 2702 SOC_IF_ERROR_RETURN 2703 (READ_HL65_GP_STATUS_XGXSSTATUS1r(unit, pc, &data16)); 2704 if (data16 & (GP_STATUS_XGXSSTATUS1_LINKSTAT_MASK | 2705 GP_STATUS_XGXSSTATUS1_LINK10G_MASK)) { 2706 link_combo = TRUE; 2707 } 2708 } 2709 2710 LOG_INFO(BSL_LS_SOC_PHY, 2711 (BSL_META_U(unit, 2712 "u=%d p=%d an_enable=%04x link_1000x=%04x link_combo=%04x\n"), 2713 unit, port, an_enable, link_1000x,link_combo)); 2714 2715 sal_memset(ability, 0, sizeof(*ability)); 2716 mode = 0; 2717 if (an_enable && (link_1000x || link_combo)) { 2718 /* Decode remote advertisement only when link is up and autoneg is 2719 * completed. 2720 */ 2721 2722 SOC_IF_ERROR_RETURN 2723 (READ_HL65_GP_STATUS_LP_UP3r(unit, pc, &an_sp_20g)); 2724 2725 SOC_IF_ERROR_RETURN 2726 (READ_HL65_GP_STATUS_LP_UP1r(unit, pc, &an_adv)); 2727 2728 mode |= (an_sp_20g & GP_STATUS_LP_UP3_DATARATE_25P45GX4_MASK)? 2729 SOC_PA_SPEED_25GB: 0; 2730 mode |= (an_sp_20g & GP_STATUS_LP_UP3_DATARATE_21GX4_MASK)? 2731 SOC_PA_SPEED_21GB: 0; 2732 mode |= (an_adv & GP_STATUS_LP_UP1_DATARATE_20GX4_MASK) ? 2733 SOC_PA_SPEED_20GB : 0; 2734 mode |= (an_adv & GP_STATUS_LP_UP1_DATARATE_16GX4_MASK) ? 2735 SOC_PA_SPEED_16GB : 0; 2736 mode |= (an_adv & GP_STATUS_LP_UP1_DATARATE_13GX4_MASK) ? 2737 SOC_PA_SPEED_13GB : 0; 2738 mode |= (an_adv & GP_STATUS_LP_UP1_DATARATE_12GX4_MASK) ? 2739 SOC_PA_SPEED_12GB : 0; 2740 mode |= (an_adv & GP_STATUS_LP_UP1_DATARATE_10GCX4_MASK) ? 2741 SOC_PA_SPEED_10GB : 0; 2742 mode |= (an_adv & GP_STATUS_LP_UP1_DATARATE_10GX4_MASK) ? 2743 SOC_PA_SPEED_10GB : 0; 2744 mode |= (an_adv & GP_STATUS_LP_UP1_DATARATE_2P5GX1_MASK) ? 2745 SOC_PA_SPEED_2500MB : 0; 2746 2747 LOG_INFO(BSL_LS_SOC_PHY, 2748 (BSL_META_U(unit, 2749 "u=%d p=%d over1G an_adv=%04x\n"), 2750 unit, port, an_adv)); 2751 2752 SOC_IF_ERROR_RETURN 2753 (READ_HL65_COMBO_IEEE0_AUTONEGLPABILr(unit, pc, &an_adv)); 2754 2755 LOG_INFO(BSL_LS_SOC_PHY, 2756 (BSL_META_U(unit, 2757 "u=%d p=%d combo an_adv=%04x\n"), 2758 unit, port, an_adv)); 2759 2760 mode |= (an_adv & MII_ANP_C37_FD) ? SOC_PA_SPEED_1000MB : 0; 2761 ability->speed_full_duplex = mode; 2762 2763 switch (an_adv & (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) { 2764 case MII_ANP_C37_PAUSE: 2765 ability->pause |= SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 2766 break; 2767 case MII_ANP_C37_ASYM_PAUSE: 2768 ability->pause |= SOC_PA_PAUSE_TX; 2769 break; 2770 case MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE: 2771 ability->pause |= SOC_PA_PAUSE_RX; 2772 break; 2773 } 2774 if (PHY_CLAUSE73_MODE(unit, port)) { 2775 SOC_IF_ERROR_RETURN 2776 (READ_HL65_AN_IEEE0BLK_AN_IEEESTATUS1r(unit, pc, &data16)); 2777 if (data16 & MII_STAT_AN_DONE) { 2778 SOC_IF_ERROR_RETURN 2779 (_phy_hl65_c73_adv_remote_get(unit, port, ability)); 2780 } 2781 } 2782 } else { 2783 /* Simply return local abilities */ 2784 phy_hl65_ability_advert_get(unit, port, ability); 2785 } 2786 2787 LOG_INFO(BSL_LS_SOC_PHY, 2788 (BSL_META_U(unit, 2789 "phy_hl65_ability_remote_get:unit=%d p=%d pause=%08x sp=%08x\n"), 2790 unit, port, ability->pause, ability->speed_full_duplex)); 2791 2792 return SOC_E_NONE; 2793 } 2794 2795 /* 2796 * Function: 2797 * phy_hl65_lb_set 2798 * Purpose: 2799 * Put hc/FusionCore in PHY loopback 2800 * Parameters: 2801 * unit - StrataSwitch unit #. 2802 * port - StrataSwitch port #. 2803 * enable - binary value for on/off (1/0) 2804 * Returns: 2805 * SOC_E_NONE 2806 */ 2807 2808 STATIC int 2809 phy_hl65_lb_set(int unit, soc_port_t port, int enable) 2810 { 2811 phy_ctrl_t *pc; 2812 uint16 serdes_id0; 2813 2814 pc = INT_PHY_SW_STATE(unit, port); 2815 SOC_IF_ERROR_RETURN 2816 (READ_HL65_TEST_SERDESID0r(unit, pc, &serdes_id0)); 2817 2818 serdes_id0 = serdes_id0 & (TEST_SERDESID0_REV_NUMBER_MASK | 2819 TEST_SERDESID0_REV_LETTER_MASK); 2820 2821 if ((serdes_id0 == HL_SERDES_ID0_REVID_A0) || 2822 (serdes_id0 == HL_SERDES_ID0_REVID_A1) || 2823 (serdes_id0 == HL_SERDES_ID0_REVID_B0)) { 2824 SOC_IF_ERROR_RETURN(MODIFY_HL65_DSC2BB_SM_CTRL0r(unit, pc, 2825 enable? 0x0: DSC2BB_SM_CTRL0_TUNING_SM_EN_MASK, 2826 DSC2BB_SM_CTRL0_TUNING_SM_EN_MASK)); 2827 } 2828 2829 if (PHY_HC65_FABRIC_MODE(unit, port)) { 2830 uint16 lane_mask = 1 << pc->lane_num; 2831 2832 if (enable) { 2833 /* Set global and individual loopback control */ 2834 SOC_IF_ERROR_RETURN 2835 (MODIFY_HL65_IEEE0BLK_MIICNTLr(unit, pc, MII_CTRL_LE, 2836 MII_CTRL_LE)); 2837 2838 SOC_IF_ERROR_RETURN 2839 (MODIFY_HL65_XGXSBLK1_LANECTRL2r(unit, pc, lane_mask, lane_mask)); 2840 } else { 2841 /* Clear global and individual loopback control */ 2842 SOC_IF_ERROR_RETURN 2843 (MODIFY_HL65_IEEE0BLK_MIICNTLr(unit, pc, 0, 2844 MII_CTRL_LE)); 2845 SOC_IF_ERROR_RETURN 2846 (MODIFY_HL65_XGXSBLK1_LANECTRL2r(unit, pc, 0, lane_mask)); 2847 } 2848 } else if (PHY_INDEPENDENT_LANE_MODE(unit, port)) { 2849 if (enable) { 2850 SOC_IF_ERROR_RETURN 2851 (MODIFY_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, 2852 MII_CTRL_LE, 2853 MII_CTRL_AE | MII_CTRL_RAN | 2854 MII_CTRL_LE)); 2855 if(!IS_GE_PORT(unit, port)) { 2856 /* in case it is in dxgxs mode */ 2857 SOC_IF_ERROR_RETURN 2858 (MODIFY_HL65_DTE_IEEE0BLK_DTE_IEEECONTROL1r(unit, pc, 2859 MII_CTRL_LE,MII_CTRL_LE)); 2860 } 2861 } else { 2862 SOC_IF_ERROR_RETURN 2863 (MODIFY_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, 2864 0, 2865 MII_CTRL_LE)); 2866 if(!IS_GE_PORT(unit, port)) { 2867 /* in case it is in dxgxs mode */ 2868 SOC_IF_ERROR_RETURN 2869 (MODIFY_HL65_DTE_IEEE0BLK_DTE_IEEECONTROL1r(unit, pc, 2870 0,MII_CTRL_LE)); 2871 } 2872 } 2873 } else { 2874 uint16 misc_ctrl; 2875 uint16 lb_bit; 2876 uint16 lb_mask; 2877 2878 if (enable) { 2879 /* Disable TX serializer output in gloopback mode. Link partner will 2880 * show link off 2881 */ 2882 SOC_IF_ERROR_RETURN 2883 (MODIFY_HL65_TXB_ANATXACONTROL0r(unit, pc, 0x200,0x200)); 2884 2885 } else { 2886 SOC_IF_ERROR_RETURN 2887 (MODIFY_HL65_TXB_ANATXACONTROL0r(unit, pc, 0x000,0x200)); 2888 } 2889 /* Configure Loopback in XAUI */ 2890 SOC_IF_ERROR_RETURN 2891 (READ_HL65_XGXSBLK0_MISCCONTROL1r(unit, pc, &misc_ctrl)); 2892 if (misc_ctrl & XGXSBLK0_MISCCONTROL1_PCS_DEV_EN_OVERRIDE_MASK) { 2893 /* PCS */ 2894 lb_bit = (enable) ? IEEE0BLK_MIICNTL_GLOOPBACK_MASK : 0; 2895 lb_mask = IEEE0BLK_MIICNTL_GLOOPBACK_MASK; 2896 SOC_IF_ERROR_RETURN 2897 (MODIFY_HL65_DTE_IEEE0BLK_DTE_IEEECONTROL1r(unit, pc, 2898 lb_bit, lb_mask)); 2899 } else if (misc_ctrl & XGXSBLK0_MISCCONTROL1_PMD_DEV_EN_OVERRIDE_MASK) { 2900 /* PMA/PMD */ 2901 lb_bit = (enable) ? 1 : 0; 2902 lb_mask = 1; 2903 SOC_IF_ERROR_RETURN 2904 (MODIFY_HL65_PMD_IEEE0BLK_PMD_IEEECONTROL1r(unit, pc, 2905 lb_bit, lb_mask)); 2906 } else { 2907 /* PHY XS, DTE XS */ 2908 lb_bit = (enable) ? IEEE0BLK_MIICNTL_GLOOPBACK_MASK : 0; 2909 lb_mask = IEEE0BLK_MIICNTL_GLOOPBACK_MASK; 2910 SOC_IF_ERROR_RETURN 2911 (MODIFY_HL65_DTE_IEEE0BLK_DTE_IEEECONTROL1r(unit, pc, 2912 lb_bit, lb_mask)); 2913 } 2914 2915 SOC_IF_ERROR_RETURN 2916 (MODIFY_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, 2917 (enable) ? MII_CTRL_LE : 0, 2918 MII_CTRL_LE)); 2919 } 2920 2921 return SOC_E_NONE; 2922 } 2923 2924 /* 2925 * Function: 2926 * phy_hl65_lb_get 2927 * Purpose: 2928 * Get hc/FusionCore PHY loopback state 2929 * Parameters: 2930 * unit - StrataSwitch unit #. 2931 * port - StrataSwitch port #. 2932 * enable - address of location to store binary value for on/off (1/0) 2933 * Returns: 2934 * SOC_E_NONE 2935 */ 2936 2937 STATIC int 2938 phy_hl65_lb_get(int unit, soc_port_t port, int *enable) 2939 { 2940 phy_ctrl_t *pc; 2941 uint16 mii_ctrl; 2942 2943 pc = INT_PHY_SW_STATE(unit, port); 2944 2945 if (PHY_HC65_FABRIC_MODE(unit, port)) { 2946 uint16 data; 2947 uint16 lane_mask = 1 << pc->lane_num; 2948 2949 SOC_IF_ERROR_RETURN 2950 (READ_HL65_XGXSBLK1_LANECTRL2r(unit, pc, &data)); 2951 2952 *enable = ((data & lane_mask) == lane_mask); 2953 LOG_INFO(BSL_LS_SOC_PHY, 2954 (BSL_META_U(unit, 2955 "phy_hc65_loopback_get: " 2956 "u=%d p=%d lb=%d\n"), unit, port, *enable)); 2957 2958 } else { 2959 SOC_IF_ERROR_RETURN 2960 (READ_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, &mii_ctrl)); 2961 2962 *enable = mii_ctrl & MII_CTRL_LE; 2963 } 2964 return SOC_E_NONE; 2965 } 2966 2967 STATIC int 2968 phy_hl65_interface_set(int unit, soc_port_t port, soc_port_if_t pif) 2969 { 2970 COMPILER_REFERENCE(unit); 2971 COMPILER_REFERENCE(port); 2972 COMPILER_REFERENCE(pif); 2973 2974 return SOC_E_NONE; 2975 } 2976 2977 STATIC int 2978 phy_hl65_interface_get(int unit, soc_port_t port, soc_port_if_t *pif) 2979 { 2980 COMPILER_REFERENCE(unit); 2981 COMPILER_REFERENCE(port); 2982 2983 if (PHY_INDEPENDENT_LANE_MODE(unit, port)) { 2984 *pif = SOC_PORT_IF_SGMII; 2985 } else { 2986 *pif = SOC_PORT_IF_XGMII; 2987 } 2988 return SOC_E_NONE; 2989 } 2990 2991 STATIC int 2992 phy_hl65_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 2993 { 2994 phy_ctrl_t *pc; 2995 uint16 id_rev; 2996 2997 if (NULL == ability) { 2998 return SOC_E_PARAM; 2999 } 3000 3001 pc = INT_PHY_SW_STATE(unit, port); 3002 3003 sal_memset(ability, 0, sizeof(*ability)); 3004 3005 if (PHY_INDEPENDENT_LANE_MODE(unit, port)) { 3006 /* dxgxs mode */ 3007 if (IS_HG_PORT(unit, port)) { 3008 ability->speed_full_duplex = SOC_PA_SPEED_10GB | 3009 SOC_PA_SPEED_12GB; 3010 ability->pause = 0; 3011 ability->interface = SOC_PA_INTF_XGMII; 3012 ability->medium = SOC_PA_MEDIUM_FIBER; 3013 ability->loopback = SOC_PA_LB_PHY; 3014 ability->flags = 0; 3015 } else { 3016 ability->speed_full_duplex = SOC_PA_SPEED_1000MB; 3017 if (IS_XE_PORT(unit,port)) { 3018 ability->speed_full_duplex += SOC_PA_SPEED_10GB; 3019 } 3020 3021 ability->speed_half_duplex = SOC_PA_ABILITY_NONE; 3022 if (PHY_FIBER_MODE(unit, port)) { 3023 ability->speed_full_duplex |= SOC_PA_SPEED_2500MB; 3024 SOC_IF_ERROR_RETURN 3025 (READ_HL65_TEST_SERDESID0r(unit,pc,&id_rev)); 3026 if (id_rev & TEST_SERDESID0_REV_LETTER_MASK) { 3027 ability->speed_full_duplex |= SOC_PA_SPEED_100MB; 3028 ability->speed_half_duplex = SOC_PA_SPEED_100MB; 3029 } 3030 } else { 3031 ability->speed_half_duplex = SOC_PA_SPEED_10MB | 3032 SOC_PA_SPEED_100MB; 3033 ability->speed_full_duplex |= SOC_PA_SPEED_10MB | 3034 SOC_PA_SPEED_100MB; 3035 } 3036 3037 ability->interface = SOC_PA_INTF_GMII | SOC_PA_INTF_SGMII; 3038 ability->pause = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 3039 ability->medium = SOC_PA_MEDIUM_FIBER; 3040 ability->loopback = SOC_PA_LB_PHY; 3041 ability->flags = SOC_PA_AUTONEG; 3042 } 3043 } else { 3044 3045 if ( PHY_EXTERNAL_MODE(unit, port) ) { 3046 ability->speed_half_duplex = SOC_PA_SPEED_100MB | 3047 SOC_PA_SPEED_10MB; 3048 ability->speed_full_duplex = SOC_PA_SPEED_2500MB | 3049 SOC_PA_SPEED_1000MB | 3050 SOC_PA_SPEED_100MB | 3051 SOC_PA_SPEED_10MB; 3052 } else { 3053 ability->speed_half_duplex = SOC_PA_ABILITY_NONE; 3054 ability->speed_full_duplex = SOC_PA_SPEED_1000MB | 3055 SOC_PA_SPEED_2500MB; 3056 } 3057 3058 switch(pc->speed_max) { 3059 case 25000: 3060 ability->speed_full_duplex |= SOC_PA_SPEED_25GB; 3061 /* fall through */ 3062 case 21000: 3063 ability->speed_full_duplex |= SOC_PA_SPEED_21GB; 3064 /* fall through */ 3065 case 20000: 3066 ability->speed_full_duplex |= SOC_PA_SPEED_20GB; 3067 /* fall through */ 3068 case 16000: 3069 ability->speed_full_duplex |= SOC_PA_SPEED_16GB; 3070 /* fall through */ 3071 case 13000: 3072 ability->speed_full_duplex |= SOC_PA_SPEED_13GB; 3073 /* fall through */ 3074 case 12000: 3075 ability->speed_full_duplex |= SOC_PA_SPEED_12GB; 3076 /* fall through */ 3077 default: 3078 ability->speed_full_duplex |= SOC_PA_SPEED_10GB; 3079 } 3080 ability->pause = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 3081 ability->interface = SOC_PA_INTF_XGMII; 3082 ability->medium = SOC_PA_MEDIUM_FIBER; 3083 ability->loopback = SOC_PA_LB_PHY; 3084 ability->flags = SOC_PA_AUTONEG; 3085 } 3086 3087 return (SOC_E_NONE); 3088 } 3089 3090 3091 STATIC int 3092 _phy_hl65_control_scrambler_set(int unit, soc_port_t port, uint32 value) 3093 { 3094 uint16 data; 3095 phy_ctrl_t *pc; 3096 int rv = SOC_E_NONE; 3097 3098 if (SOC_IS_RELOADING(unit)) { 3099 return SOC_E_NONE; 3100 } 3101 3102 pc = INT_PHY_SW_STATE(unit, port); 3103 if (PHY_HC65_FABRIC_MODE(unit, port)) { 3104 3105 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, 0x833c, &uData);*/ 3106 SOC_IF_ERROR_RETURN 3107 (READ_HL65_DIGITAL4_MISC3r(unit, pc, &data)); 3108 3109 if (value) { 3110 data |= (DIGITAL4_MISC3_SCR_EN_PER_LANE_BITS << 3111 DIGITAL4_MISC3_SCR_EN_PER_LANE_SHIFT); 3112 } else { 3113 data &= ~(DIGITAL4_MISC3_SCR_EN_PER_LANE_BITS << 3114 DIGITAL4_MISC3_SCR_EN_PER_LANE_SHIFT); 3115 } 3116 3117 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, 0x833c, uData);*/ 3118 SOC_IF_ERROR_RETURN 3119 (WRITE_HL65_DIGITAL4_MISC3r(unit, pc, data)); 3120 3121 } else { 3122 rv = SOC_E_UNAVAIL; 3123 } 3124 return rv; 3125 } 3126 3127 STATIC int 3128 _phy_hl65_control_scrambler_get(int unit, soc_port_t port, uint32 *value) 3129 { 3130 uint16 data; 3131 phy_ctrl_t *pc; 3132 int rv = SOC_E_NONE; 3133 3134 pc = INT_PHY_SW_STATE(unit, port); 3135 if (PHY_HC65_FABRIC_MODE(unit, port)) { 3136 3137 SOC_IF_ERROR_RETURN 3138 (READ_HL65_DIGITAL4_MISC3r(unit, pc, &data)); 3139 3140 *value = ((data & DIGITAL4_MISC3_SCR_EN_PER_LANE_MASK) == 0x100); 3141 3142 } else { 3143 rv = SOC_E_UNAVAIL; 3144 } 3145 return rv; 3146 } 3147 3148 STATIC int 3149 _phy_hl65_control_encoding_set(int unit, soc_port_t port, uint32 value) 3150 { 3151 uint16 data; 3152 phy_ctrl_t *pc; 3153 int rv = SOC_E_NONE; 3154 3155 if (SOC_IS_RELOADING(unit)) { 3156 return SOC_E_NONE; 3157 } 3158 3159 pc = INT_PHY_SW_STATE(unit, port); 3160 if (PHY_HC65_FABRIC_MODE(unit, port)) { 3161 switch (value) { 3162 case phyControlEncoding8b10b: 3163 3164 /* 3165 * 8b10b only, disable 64/66 3166 * soc_bm9600_mdio_hc_read(unit, uPhyAddr, 0, 0x8015, &uData); 3167 */ 3168 SOC_IF_ERROR_RETURN 3169 (READ_HL65_XGXSBLK1_LANECTRL0r(unit, pc, &data)); 3170 3171 data &= ~(1 << (pc->lane_num + 12)); 3172 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, 0x8015, uData); */ 3173 SOC_IF_ERROR_RETURN 3174 (WRITE_HL65_XGXSBLK1_LANECTRL0r(unit, pc, data)); 3175 3176 /* 3177 * Force the sync character to the lower byte of the parallel 3178 * interface 3179 * uRegAddr = 0x80b9 + (uLaneAddr * 0x10); 3180 * soc_bm9600_mdio_hc_read(unit, uPhyAddr, 0, uRegAddr, &uData); 3181 */ 3182 SOC_IF_ERROR_RETURN 3183 (HL65_REG_READ(unit, pc, 0x0, 0x80b9 + (0x10 * pc->lane_num), 3184 &data)); 3185 data = data | 0x0020; 3186 3187 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, uRegAddr, uData); */ 3188 SOC_IF_ERROR_RETURN 3189 (HL65_REG_WRITE(unit, pc, 0x0, 0x80b9 + (0x10 * pc->lane_num), 3190 data)); 3191 break; 3192 3193 case phyControlEncoding64b66b: 3194 3195 /* 3196 * Force the sync character to the upper byte of the parallel 3197 * interface 3198 * uRegAddr = 0x80b9 + (uLaneAddr * 0x10); 3199 * soc_bm9600_mdio_hc_read(unit, uPhyAddr, 0, uRegAddr, &uData); 3200 */ 3201 SOC_IF_ERROR_RETURN 3202 (HL65_REG_READ(unit, pc, 0x0, 0x80b9 + (0x10 * pc->lane_num), 3203 &data)); 3204 3205 data = data & ~0x0020; 3206 3207 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, uRegAddr, uData); */ 3208 SOC_IF_ERROR_RETURN 3209 (HL65_REG_WRITE(unit, pc, 0x0, 0x80b9 + (0x10 * pc->lane_num), 3210 data)); 3211 3212 /* 3213 * enable 64b66b 3214 * socd c_bm9600_mdio_hc_read(unit, uPhyAddr, 0, 0x8015, &uData); 3215 */ 3216 SOC_IF_ERROR_RETURN 3217 (READ_HL65_XGXSBLK1_LANECTRL0r(unit, pc, &data)); 3218 3219 data |= 1 << (pc->lane_num + 12); 3220 3221 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, 0x8015, uData); */ 3222 SOC_IF_ERROR_RETURN 3223 (WRITE_HL65_XGXSBLK1_LANECTRL0r(unit, pc, data)); 3224 3225 break; 3226 3227 default: 3228 rv = SOC_E_UNAVAIL; 3229 } 3230 } else { 3231 rv = SOC_E_UNAVAIL; 3232 } 3233 3234 return rv; 3235 } 3236 3237 #define PHY_HL65_LANEPRBS_LANE_SHIFT 4 3238 3239 STATIC int 3240 _phy_hl65_control_prbs_polynomial_set(int unit, soc_port_t port, uint32 value) 3241 { 3242 uint16 data = 0; 3243 3244 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 3245 3246 SOC_IF_ERROR_RETURN 3247 (READ_HL65_XGXSBLK1_LANEPRBSr(unit, pc, &data)); 3248 3249 if (PHY_HC65_FABRIC_MODE(unit, pc->port)) { 3250 uint32 prbs_lane_mask = 0; 3251 prbs_lane_mask = 0x3 << (PHY_HL65_LANEPRBS_LANE_SHIFT * pc->lane_num); 3252 data &= ~prbs_lane_mask; 3253 data |= value << (PHY_HL65_LANEPRBS_LANE_SHIFT * pc->lane_num); 3254 } else { 3255 data &= ~(XGXSBLK1_LANEPRBS_PRBS_ORDER0_MASK | 3256 XGXSBLK1_LANEPRBS_PRBS_ORDER1_MASK | 3257 XGXSBLK1_LANEPRBS_PRBS_ORDER2_MASK | 3258 XGXSBLK1_LANEPRBS_PRBS_ORDER3_MASK); 3259 3260 data |= ((value << XGXSBLK1_LANEPRBS_PRBS_ORDER0_SHIFT) | 3261 (value << XGXSBLK1_LANEPRBS_PRBS_ORDER1_SHIFT) | 3262 (value << XGXSBLK1_LANEPRBS_PRBS_ORDER2_SHIFT) | 3263 (value << XGXSBLK1_LANEPRBS_PRBS_ORDER3_SHIFT)); 3264 } 3265 3266 SOC_IF_ERROR_RETURN 3267 (WRITE_HL65_XGXSBLK1_LANEPRBSr(unit, pc, data)); 3268 3269 return SOC_E_NONE; 3270 } 3271 3272 STATIC int 3273 _phy_hl65_control_prbs_polynomial_get(int unit, soc_port_t port, uint32 *value) 3274 { 3275 uint16 data; 3276 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);; 3277 3278 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, 0x8019, &uData);*/ 3279 SOC_IF_ERROR_RETURN 3280 (READ_HL65_XGXSBLK1_LANEPRBSr(unit, pc, &data)); 3281 3282 if (PHY_HC65_FABRIC_MODE(unit, pc->port)) { 3283 /* Extract prbs polynomial setting from register */ 3284 *value = ((data >> (XGXSBLK1_LANEPRBS_PRBS_ORDER1_SHIFT * pc->lane_num)) & 3285 XGXSBLK1_LANEPRBS_PRBS_ORDER0_MASK); 3286 } else { 3287 *value = ((data & 0x0003) | ((data >> 4) & 0x0003) | 3288 ((data >> 8) & 0x0003) | ((data >> 12) & 0x0003)); 3289 } 3290 3291 return SOC_E_NONE; 3292 } 3293 3294 3295 STATIC int 3296 _phy_hl65_control_prbs_tx_invert_data_set(int unit, soc_port_t port, uint32 value) 3297 { 3298 uint16 data = 0; 3299 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 3300 3301 SOC_IF_ERROR_RETURN 3302 (READ_HL65_XGXSBLK1_LANEPRBSr(unit, pc, &data)); 3303 3304 if (PHY_HC65_FABRIC_MODE(unit, pc->port)) { 3305 uint32 lane_mask = 0; 3306 lane_mask = 0x4 << (PHY_HL65_LANEPRBS_LANE_SHIFT * pc->lane_num); 3307 data &= ~lane_mask; 3308 data |= value << (PHY_HL65_LANEPRBS_LANE_SHIFT * pc->lane_num); 3309 } else { 3310 data &= ~(XGXSBLK1_LANEPRBS_PRBS_INV0_MASK | 3311 XGXSBLK1_LANEPRBS_PRBS_INV1_MASK | 3312 XGXSBLK1_LANEPRBS_PRBS_INV2_MASK | 3313 XGXSBLK1_LANEPRBS_PRBS_INV3_MASK); 3314 3315 value &= (1 << XGXSBLK1_LANEPRBS_PRBS_INV0_BITS) - 1; 3316 data |= ((value << XGXSBLK1_LANEPRBS_PRBS_INV0_SHIFT) | 3317 (value << XGXSBLK1_LANEPRBS_PRBS_INV1_SHIFT) | 3318 (value << XGXSBLK1_LANEPRBS_PRBS_INV2_SHIFT) | 3319 (value << XGXSBLK1_LANEPRBS_PRBS_INV3_SHIFT)); 3320 } 3321 3322 SOC_IF_ERROR_RETURN 3323 (WRITE_HL65_XGXSBLK1_LANEPRBSr(unit, pc, data)); 3324 3325 return SOC_E_NONE; 3326 } 3327 3328 STATIC int 3329 _phy_hl65_control_prbs_tx_invert_data_get(int unit, soc_port_t port, uint32 *value) 3330 { 3331 uint16 data; 3332 uint16 inv_shifter = 0; 3333 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 3334 3335 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, 0x8019, &uData) */ 3336 SOC_IF_ERROR_RETURN 3337 (READ_HL65_XGXSBLK1_LANEPRBSr(unit, pc, &data)); 3338 inv_shifter = (XGXSBLK1_LANEPRBS_PRBS_ORDER1_SHIFT * pc->lane_num) + 3339 XGXSBLK1_LANEPRBS_PRBS_INV0_SHIFT; 3340 data &= (1 << inv_shifter); 3341 *value = (data) ? 1 : 0; 3342 3343 return SOC_E_NONE; 3344 } 3345 3346 STATIC int 3347 _phy_hl65_control_fabric_prbs_tx_enable_set(int unit, soc_port_t port, 3348 uint32 value) 3349 { 3350 uint16 data; 3351 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 3352 uint32 lane_mask = 1 << (PHY_HL65_LANEPRBS_LANE_SHIFT * pc->lane_num); 3353 3354 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, 0x8019, &uData) */ 3355 SOC_IF_ERROR_RETURN 3356 (READ_HL65_XGXSBLK1_LANEPRBSr(unit, pc, &data)); 3357 3358 if (value) { 3359 data |= lane_mask << XGXSBLK1_LANEPRBS_PRBS_EN0_SHIFT; 3360 } else { 3361 data &= ~(lane_mask << XGXSBLK1_LANEPRBS_PRBS_EN0_SHIFT); 3362 } 3363 /* write back updated configuration */ 3364 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, 0x8019, uData) */ 3365 SOC_IF_ERROR_RETURN 3366 (WRITE_HL65_XGXSBLK1_LANEPRBSr(unit, pc, data)); 3367 3368 SOC_IF_ERROR_RETURN( 3369 phy_hl65_lb_set(unit, port, (value & 0x8000) ? 1 : 0)); 3370 3371 return SOC_E_NONE; 3372 } 3373 3374 STATIC int 3375 _phy_hl65_control_xgxs_prbs_tx_enable_set(int unit, soc_port_t port, 3376 uint32 value) 3377 { 3378 uint16 data; 3379 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 3380 uint16 pll_mode; 3381 3382 if (value) { 3383 /* Assume that the core has already been forced to the desired speed */ 3384 /* Get the current PLL operating mode */ 3385 SOC_IF_ERROR_RETURN(READ_HL65_TXPLL_ANAPLLSTATUSr(unit, pc, &data)); 3386 pll_mode = data & TXPLL_ANAPLLSTATUS_PLL_MODE_AFE_MASK; 3387 3388 /* Change to independent lane mode */ 3389 SOC_IF_ERROR_RETURN(READ_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, &data)); 3390 data &= ~(XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK | 3391 XGXSBLK0_XGXSCONTROL_MODE_10G_MASK); 3392 data |= ((XGXSBLK0_XGXSCONTROL_MODE_10G_Indlanes << 3393 XGXSBLK0_XGXSCONTROL_MODE_10G_SHIFT) | 3394 XGXSBLK0_XGXSCONTROL_MDIO_CONT_EN_MASK); 3395 SOC_IF_ERROR_RETURN(WRITE_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, data)); 3396 3397 /* Set appropriate data width mode */ 3398 if (data & XGXSBLK0_XGXSCONTROL_TXCKO_DIV_MASK) { 3399 /* Half rate mode */ 3400 SOC_IF_ERROR_RETURN(WRITE_HL65_XGXSBLK1_LANECTRL1r(unit, pc, 3401 0x5555)); 3402 } else { 3403 /* Full rate mode */ 3404 SOC_IF_ERROR_RETURN(WRITE_HL65_XGXSBLK1_LANECTRL1r(unit, pc, 3405 0xffff)); 3406 } 3407 3408 /* Force the VCO based on the previously read mode */ 3409 SOC_IF_ERROR_RETURN(READ_HL65_DIGITAL_MISC1r(unit, pc, &data)); 3410 data &= ~(DIGITAL_MISC1_FORCE_PLL_MODE_AFE_MASK | 3411 DIGITAL_MISC1_FORCE_LN_MODE_MASK | 3412 DIGITAL_MISC1_FORCE_SPEED_MASK); 3413 data |= (DIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_MASK | 3414 (pll_mode << DIGITAL_MISC1_FORCE_PLL_MODE_AFE_SHIFT) | 3415 DIGITAL_MISC1_FORCE_LN_MODE_MASK); 3416 SOC_IF_ERROR_RETURN(WRITE_HL65_DIGITAL_MISC1r(unit, pc, data)); 3417 3418 /* Disable CL36 PCS */ 3419 SOC_IF_ERROR_RETURN(READ_HL65_XGXSBLK1_LANECTRL0r(unit, pc, &data)); 3420 data &= ~(XGXSBLK1_LANECTRL0_CL36_PCS_EN_RX_MASK | 3421 XGXSBLK1_LANECTRL0_CL36_PCS_EN_TX_MASK); 3422 SOC_IF_ERROR_RETURN(WRITE_HL65_XGXSBLK1_LANECTRL0r(unit, pc, data)); 3423 3424 /* Disable comma detect, error detect */ 3425 SOC_IF_ERROR_RETURN(READ_HL65_XGXSBLK1_LANECTRL2r(unit, pc, &data)); 3426 data &= ~(XGXSBLK1_LANECTRL2_CDET_EN1G_MASK | 3427 XGXSBLK1_LANECTRL2_EDEN1G_MASK); 3428 SOC_IF_ERROR_RETURN(WRITE_HL65_XGXSBLK1_LANECTRL2r(unit, pc, data)); 3429 3430 /* Set loopback (if requested) */ 3431 if (value & 0x8000) { 3432 SOC_IF_ERROR_RETURN(WRITE_HL65_XGXSBLK1_LANECTRL2r(unit, pc, 3433 XGXSBLK1_LANECTRL2_GLOOP1G_MASK)); 3434 } 3435 3436 /* Enable PRBS transmit function */ 3437 SOC_IF_ERROR_RETURN(READ_HL65_XGXSBLK1_LANEPRBSr(unit, pc, &data)); 3438 data |= (XGXSBLK1_LANEPRBS_PRBS_EN0_MASK | 3439 XGXSBLK1_LANEPRBS_PRBS_EN1_MASK | 3440 XGXSBLK1_LANEPRBS_PRBS_EN2_MASK | 3441 XGXSBLK1_LANEPRBS_PRBS_EN3_MASK); 3442 SOC_IF_ERROR_RETURN(WRITE_HL65_XGXSBLK1_LANEPRBSr(unit, pc, data)); 3443 3444 /* Set receiver status to PRBS */ 3445 SOC_IF_ERROR_RETURN(READ_HL65_RXB_ANARXCONTROLr(unit, pc, &data)); 3446 data &= ~RXB_ANARXCONTROL_STATUS_SEL_MASK; 3447 data |= 0x7; /* PRBS status */ 3448 SOC_IF_ERROR_RETURN(WRITE_HL65_RXB_ANARXCONTROLr(unit, pc, data)); 3449 3450 /* Start the PLL sequencer */ 3451 SOC_IF_ERROR_RETURN(READ_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, &data)); 3452 data |= XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK; 3453 SOC_IF_ERROR_RETURN(WRITE_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, data)); 3454 3455 /* Delay a while */ 3456 sal_usleep(250000); 3457 } else { 3458 /* Restore port */ 3459 return phy_hl65_init(unit, port); 3460 } 3461 return SOC_E_NONE; 3462 } 3463 3464 STATIC int 3465 _phy_hl65_control_prbs_tx_enable_set(int unit, soc_port_t port, uint32 value) 3466 { 3467 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 3468 3469 if (PHY_HC65_FABRIC_MODE(unit, pc->port)) { 3470 SOC_IF_ERROR_RETURN( 3471 _phy_hl65_control_fabric_prbs_tx_enable_set(unit, port, value)); 3472 } else { 3473 SOC_IF_ERROR_RETURN( 3474 _phy_hl65_control_xgxs_prbs_tx_enable_set(unit, port, value)); 3475 } 3476 3477 return SOC_E_NONE; 3478 } 3479 3480 3481 STATIC int 3482 _phy_hl65_control_prbs_tx_rx_enable_get(int unit, soc_port_t port, 3483 uint32 *value) 3484 { 3485 uint16 data; 3486 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);; 3487 3488 /* 3489 * Hypercore PRBS - note that in the Hypercore there is only 1 enable 3490 * for both TX/RX 3491 */ 3492 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, 0x8019, &uData) */ 3493 SOC_IF_ERROR_RETURN 3494 (READ_HL65_XGXSBLK1_LANEPRBSr(unit, pc, &data)); 3495 3496 data = data & ((1 << (XGXSBLK1_LANEPRBS_PRBS_ORDER1_SHIFT * pc->lane_num)) 3497 << XGXSBLK1_LANEPRBS_PRBS_EN0_SHIFT); 3498 3499 *value = (data) ? 1 : 0; 3500 3501 return SOC_E_NONE; 3502 } 3503 3504 STATIC int 3505 _phy_hl65_control_prbs_tx_enable_get(int unit, soc_port_t port, uint32 *value) 3506 { 3507 return _phy_hl65_control_prbs_tx_rx_enable_get(unit, port, value); 3508 } 3509 3510 STATIC int 3511 _phy_hl65_control_prbs_rx_enable_set(int unit, soc_port_t port, uint32 value) 3512 { 3513 uint16 data; 3514 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 3515 uint32 lane_mask = 1 << (PHY_HL65_LANEPRBS_LANE_SHIFT * pc->lane_num); 3516 3517 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, 0x8019, &uData) */ 3518 SOC_IF_ERROR_RETURN 3519 (READ_HL65_XGXSBLK1_LANEPRBSr(unit, pc, &data)); 3520 3521 /* if (value) { 3522 * uData |= uLaneMask << BM9600_HYPERCORE_8019_PRBS_ENABLE_SHIFT; 3523 * } else { 3524 * uData &= ~(uLaneMask << BM9600_HYPERCORE_8019_PRBS_ENABLE_SHIFT); 3525 * } 3526 */ 3527 if (value) { 3528 data |= lane_mask << XGXSBLK1_LANEPRBS_PRBS_EN0_SHIFT; 3529 } else { 3530 data &= ~(lane_mask << XGXSBLK1_LANEPRBS_PRBS_EN0_SHIFT); 3531 } 3532 3533 /* write back updated configuration */ 3534 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, 0x8019, uData) */ 3535 SOC_IF_ERROR_RETURN 3536 (WRITE_HL65_XGXSBLK1_LANEPRBSr(unit, pc, data)); 3537 3538 /* Set up status collection */ 3539 /* uPrbsRxControlReg = 0x80b1; 3540 * uPrbsRxControlReg += uLaneAddr * 0x10; 3541 * soc_bm9600_mdio_hc_read(unit, uPhyAddr, 0, uPrbsRxControlReg, &uData) 3542 */ 3543 SOC_IF_ERROR_RETURN 3544 (HL65_REG_READ(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), &data)); 3545 3546 /* if (value) { 3547 * uData &= ~BM9600_HYPERCORE_80B1_STATUS_MASK; 3548 * uData |= BM9600_HYPERCORE_80B1_PRBS_STATUS_VALUE; 3549 * } else { 3550 * uData &= ~BM9600_HYPERCORE_80B1_STATUS_MASK; 3551 * uData &= ~BM9600_HYPERCORE_80B1_PRBS_STATUS_VALUE; 3552 * } 3553 */ 3554 data &= ~RX0_ANARXCONTROL_STATUS_SEL_MASK; 3555 if (value) { 3556 data |= RX0_ANARXCONTROL_STATUS_SEL_prbsStatus; 3557 } else { 3558 data &= ~RX0_ANARXCONTROL_STATUS_SEL_prbsStatus; 3559 } 3560 3561 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, uPrbsRxControlReg, uData) */ 3562 SOC_IF_ERROR_RETURN 3563 (HL65_REG_WRITE(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), data)); 3564 3565 return SOC_E_NONE; 3566 } 3567 3568 STATIC int 3569 _phy_hl65_control_prbs_rx_enable_get(int unit, soc_port_t port, uint32 *value) 3570 { 3571 return _phy_hl65_control_prbs_tx_rx_enable_get(unit, port, value); 3572 } 3573 3574 /* 3575 * Returns value 3576 * == 0: PRBS receive is in sync 3577 * == -1: PRBS receive never got into sync 3578 * == n: number of errors 3579 */ 3580 STATIC int 3581 _phy_hl65_control_fabric_prbs_rx_status_get(int unit, soc_port_t port, 3582 uint32 *value) 3583 { 3584 uint16 data; 3585 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);; 3586 3587 /* Get status */ 3588 /* uPrbsRxControlReg = 0x80b0; 3589 * uPrbsRxControlReg += uLaneAddr * 0x10; 3590 * soc_bm9600_mdio_hc_read(unit, uPhyAddr, 0, uPrbsRxControlReg, &uData); 3591 */ 3592 SOC_IF_ERROR_RETURN 3593 (HL65_REG_READ(unit, pc, 0x0, 0x80b0 + (0x10 * pc->lane_num), &data)); 3594 3595 3596 if (data == (RX0_ANARXSTATUS_PRBS_STATUS_PRBS_LOCK_BITS << 3597 RX0_ANARXSTATUS_PRBS_STATUS_PRBS_LOCK_SHIFT)) { 3598 /* PRBS is in sync */ 3599 *value = 0; 3600 } else if (data == 0) { 3601 /* PRBS not in sync */ 3602 *value = -1; 3603 } else { 3604 /* Get errors */ 3605 *value = data & RX0_ANARXSTATUS_PRBS_STATUS_PTBS_ERRORS_MASK; 3606 } 3607 3608 return SOC_E_NONE; 3609 } 3610 /* 3611 * Returns value 3612 * == 0: PRBS receive is in sync 3613 * == -1: PRBS receive never got into sync 3614 * == n: number of errors 3615 */ 3616 STATIC int 3617 _phy_hl65_control_xgxs_prbs_rx_status_get(int unit, soc_port_t port, 3618 uint32 *value) 3619 { 3620 int lane; 3621 uint16 data; 3622 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);; 3623 3624 /* JOE */ 3625 /* Get status for all 4 lanes and check for sync 3626 * 0x80b0, 0x80c0, 0x80d0, 0x80e0 3627 */ 3628 *value = 0; 3629 for (lane = 0; lane < 4; lane++) { 3630 SOC_IF_ERROR_RETURN 3631 (HL65_REG_READ(unit, pc, 0x0, 0x80b0 + (0x10 * lane), &data)); 3632 if (data == (RX0_ANARXSTATUS_PRBS_STATUS_PRBS_LOCK_BITS << 3633 RX0_ANARXSTATUS_PRBS_STATUS_PRBS_LOCK_SHIFT)) { 3634 /* PRBS is in sync */ 3635 continue; 3636 } else if (data == 0) { 3637 /* PRBS not in sync */ 3638 *value = -1; 3639 break; 3640 } else { 3641 /* Get errors */ 3642 *value += data & RX0_ANARXSTATUS_PRBS_STATUS_PTBS_ERRORS_MASK; 3643 } 3644 } 3645 return SOC_E_NONE; 3646 } 3647 3648 3649 STATIC int 3650 _phy_hl65_control_prbs_rx_status_get(int unit, soc_port_t port, uint32 *value) 3651 { 3652 int rv; 3653 uint16 rx_sts, saved_rx_sts; 3654 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 3655 3656 /* Set up prbs rx status collection */ 3657 SOC_IF_ERROR_RETURN 3658 (HL65_REG_READ(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), &rx_sts)); 3659 saved_rx_sts = rx_sts; 3660 rx_sts = (rx_sts & ~RX0_ANARXCONTROL_STATUS_SEL_MASK) | 3661 RX0_ANARXCONTROL_STATUS_SEL_prbsStatus; 3662 SOC_IF_ERROR_RETURN 3663 (HL65_REG_WRITE(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), rx_sts)); 3664 3665 if (PHY_HC65_FABRIC_MODE(unit, pc->port)) { 3666 rv = _phy_hl65_control_fabric_prbs_rx_status_get(unit, port, value); 3667 } else { 3668 rv = _phy_hl65_control_xgxs_prbs_rx_status_get(unit, port, value); 3669 } 3670 3671 /* Restore rx status */ 3672 SOC_IF_ERROR_RETURN 3673 (HL65_REG_WRITE(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), saved_rx_sts)); 3674 3675 return rv; 3676 } 3677 3678 3679 3680 STATIC int 3681 _phy_hl65_control_serdes_driver_tune_set(int unit, soc_port_t port, 3682 int lane_num, 3683 uint32 value) 3684 { 3685 uint16 data; 3686 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 3687 3688 if (SOC_IS_RELOADING(unit)) { 3689 return SOC_E_NONE; 3690 } 3691 3692 /* Start receive tuning via rxSeqStart */ 3693 /* uRegAddr = 0x826e + (uLaneAddr*0x10); 3694 * soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, uRegAddr , &uData) 3695 */ 3696 SOC_IF_ERROR_RETURN 3697 (HL65_REG_READ(unit, pc, 0x0, 0x826E + (0x10 * lane_num), &data)); 3698 3699 /* tune by toggling rxSeqStart */ 3700 /* uData |= 0x8000; */ 3701 data |= (DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_BITS << 3702 DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_SHIFT); 3703 3704 /* write back updated configuration */ 3705 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData) */ 3706 SOC_IF_ERROR_RETURN 3707 (HL65_REG_WRITE(unit, pc, 0x0, 0x826E + (0x10 * lane_num), data)); 3708 3709 /* tune by toggling rxSeqStart */ 3710 data &= ~ (DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_BITS << 3711 DSC2B0_DSC_MISC_CTRL0_RXSEQSTART_SHIFT); 3712 3713 /* write back updated configuration */ 3714 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData) */ 3715 SOC_IF_ERROR_RETURN 3716 (HL65_REG_WRITE(unit, pc, 0x0, 0x826E + (0x10 * lane_num), data)); 3717 3718 LOG_INFO(BSL_LS_SOC_PHY, 3719 (BSL_META_U(unit, 3720 "hl_65: Equalization tune start\n"))); 3721 return SOC_E_NONE; 3722 } 3723 3724 STATIC int 3725 _phy_hl65_control_64b66b_set(int unit, soc_port_t port, uint32 value) 3726 { 3727 uint16 data; 3728 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 3729 uint32 lane_mask = 1 << pc->lane_num; 3730 3731 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, 0, 0x8015, &uData) */ 3732 SOC_IF_ERROR_RETURN 3733 (READ_HL65_XGXSBLK1_LANECTRL0r(unit, pc, &data)); 3734 3735 if (value) { 3736 data |= lane_mask << XGXSBLK1_LANECTRL0_ED66EN_SHIFT; 3737 3738 3739 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, 0x8015, uData);*/ 3740 SOC_IF_ERROR_RETURN 3741 (WRITE_HL65_XGXSBLK1_LANECTRL0r(unit, pc, data)); 3742 } else { 3743 3744 data &= ~(lane_mask << XGXSBLK1_LANECTRL0_ED66EN_SHIFT); 3745 3746 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, 0x8015, uData);*/ 3747 SOC_IF_ERROR_RETURN 3748 (WRITE_HL65_XGXSBLK1_LANECTRL0r(unit, pc, data)); 3749 } 3750 return SOC_E_NONE; 3751 } 3752 3753 3754 STATIC int 3755 _phy_hl65_control_8b10b_set(int unit, soc_port_t port, uint32 value) 3756 { 3757 uint16 data; 3758 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 3759 uint32 lane_mask = 1 << pc->lane_num; 3760 3761 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, 0, 0x8017, &uData) */ 3762 SOC_IF_ERROR_RETURN 3763 (READ_HL65_XGXSBLK1_LANECTRL2r(unit, pc, &data)); 3764 3765 if (value) { 3766 /* uData |= uLaneMask << BM9600_HYPERCORE_8017_8B10B_SHIFT; 3767 * uData |= uLaneMask << BM9600_HYPERCORE_8017_KCHAR_SHIFT; 3768 */ 3769 data |= lane_mask << XGXSBLK1_LANECTRL2_CDET_EN1G_SHIFT; 3770 data |= lane_mask << XGXSBLK1_LANECTRL2_EDEN1G_SHIFT; 3771 3772 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, 0x8017, uData);*/ 3773 SOC_IF_ERROR_RETURN 3774 (WRITE_HL65_XGXSBLK1_LANECTRL2r(unit, pc, data)); 3775 } else { 3776 /* uData &= ~(uLaneMask << BM9600_HYPERCORE_8017_8B10B_SHIFT); 3777 * uData &= ~(uLaneMask << BM9600_HYPERCORE_8017_KCHAR_SHIFT); 3778 */ 3779 data &= ~(lane_mask << XGXSBLK1_LANECTRL2_CDET_EN1G_SHIFT); 3780 data &= ~(lane_mask << XGXSBLK1_LANECTRL2_EDEN1G_SHIFT); 3781 3782 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, 0x8017, uData);*/ 3783 SOC_IF_ERROR_RETURN 3784 (WRITE_HL65_XGXSBLK1_LANECTRL2r(unit, pc, data)); 3785 } 3786 return SOC_E_NONE; 3787 } 3788 3789 3790 3791 STATIC int 3792 _phy_hl65_tx_driver_field_get(soc_phy_control_t type,int *ln_ctrl,uint16 *mask,int *shfter) 3793 { 3794 int lane_ctrl; 3795 3796 lane_ctrl = TX_DRIVER_DFT_LN_CTRL; 3797 *mask = 0; 3798 *shfter = 0; 3799 /* _LANEn(n=0-3) control type only applies to combo mode or dxgxs in 3800 * independent channel mode 3801 */ 3802 switch(type) { 3803 case SOC_PHY_CONTROL_PREEMPHASIS_LANE0: 3804 /* fall through */ 3805 case SOC_PHY_CONTROL_PREEMPHASIS_LANE1: 3806 /* fall through */ 3807 case SOC_PHY_CONTROL_PREEMPHASIS_LANE2: 3808 /* fall through */ 3809 case SOC_PHY_CONTROL_PREEMPHASIS_LANE3: 3810 /* fall through */ 3811 case SOC_PHY_CONTROL_PREEMPHASIS: 3812 *shfter = TXB_TX_OS_DRIVER_PREEMPHASIS_POST_SHIFT; 3813 *mask = TXB_TX_OS_DRIVER_PREEMPHASIS_POST_MASK; 3814 if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE0) { 3815 lane_ctrl = 0; 3816 } else if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE1) { 3817 lane_ctrl = 1; 3818 } else if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE2) { 3819 lane_ctrl = 2; 3820 } else if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE3) { 3821 lane_ctrl = 3; 3822 } 3823 break; 3824 3825 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0: 3826 /* fall through */ 3827 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1: 3828 /* fall through */ 3829 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2: 3830 /* fall through */ 3831 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3: 3832 /* fall through */ 3833 case SOC_PHY_CONTROL_DRIVER_CURRENT: 3834 *shfter = TXB_TX_OS_DRIVER_IDRIVER_SHIFT; 3835 *mask = TXB_TX_OS_DRIVER_IDRIVER_MASK; 3836 if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0) { 3837 lane_ctrl = 0; 3838 } else if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1) { 3839 lane_ctrl = 1; 3840 } else if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2) { 3841 lane_ctrl = 2; 3842 } else if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3) { 3843 lane_ctrl = 3; 3844 } 3845 break; 3846 3847 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0: 3848 /* fall through */ 3849 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1: 3850 /* fall through */ 3851 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2: 3852 /* fall through */ 3853 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3: 3854 /* fall through */ 3855 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 3856 *shfter = TXB_TX_OS_DRIVER_IPREDRIVER_SHIFT; 3857 *mask = TXB_TX_OS_DRIVER_IPREDRIVER_MASK; 3858 if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0) { 3859 lane_ctrl = 0; 3860 } else if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1) { 3861 lane_ctrl = 1; 3862 } else if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2) { 3863 lane_ctrl = 2; 3864 /* coverity[mixed_enums:FALSE] */ 3865 } else if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3) { 3866 lane_ctrl = 3; 3867 } 3868 break; 3869 3870 case SOC_PHY_CONTROL_PRE_PREEMPHASIS: 3871 *shfter = TXB_TX_OS_DRIVER_PREEMPHASIS_PRE_SHIFT; 3872 *mask = TXB_TX_OS_DRIVER_PREEMPHASIS_PRE_MASK; 3873 break; 3874 default: 3875 /* should never get here */ 3876 return SOC_E_PARAM; 3877 } 3878 *ln_ctrl = lane_ctrl; 3879 return SOC_E_NONE; 3880 } 3881 3882 STATIC int 3883 _phy_hl65_control_tx_driver_set(int unit, phy_ctrl_t *pc, 3884 soc_phy_control_t type, uint32 value) 3885 { 3886 uint16 data; /* Temporary holder of reg value to be written */ 3887 uint16 mask; /* Bit mask of reg value to be updated */ 3888 uint16 ivalue; 3889 int lane_ctrl; 3890 int lane_num; 3891 int shifter; 3892 3893 /* Both cases 6.5G/3.125G handled the same, ignore MSB though it may be passed in*/ 3894 ivalue = value & 0x7fff; 3895 if (ivalue > 15) { 3896 return SOC_E_PARAM; 3897 } 3898 3899 SOC_IF_ERROR_RETURN 3900 (_phy_hl65_tx_driver_field_get(type,&lane_ctrl,&mask,&shifter)); 3901 3902 data = ivalue << shifter; 3903 3904 if ((lane_ctrl != TX_DRIVER_DFT_LN_CTRL) || 3905 PHY_INDEPENDENT_LANE_MODE(unit, pc->port) || 3906 PHY_HC65_FABRIC_MODE(unit, pc->port)) { 3907 if (lane_ctrl != TX_DRIVER_DFT_LN_CTRL) { 3908 lane_num = lane_ctrl; 3909 } else { 3910 lane_num = pc->lane_num; 3911 } 3912 3913 if (lane_num == 0) { 3914 SOC_IF_ERROR_RETURN 3915 (MODIFY_HL65_TX0_TX_BR_DRIVERr(unit, pc, data, mask)); 3916 SOC_IF_ERROR_RETURN 3917 (MODIFY_HL65_TX0_TX_OS_DRIVERr(unit, pc, data, mask)); 3918 } else if (lane_num == 1) { 3919 SOC_IF_ERROR_RETURN 3920 (MODIFY_HL65_TX1_TX_BR_DRIVERr(unit, pc, data, mask)); 3921 SOC_IF_ERROR_RETURN 3922 (MODIFY_HL65_TX1_TX_OS_DRIVERr(unit, pc, data, mask)); 3923 } else if (lane_num == 2) { 3924 SOC_IF_ERROR_RETURN 3925 (MODIFY_HL65_TX2_TX_BR_DRIVERr(unit, pc, data, mask)); 3926 SOC_IF_ERROR_RETURN 3927 (MODIFY_HL65_TX2_TX_OS_DRIVERr(unit, pc, data, mask)); 3928 } else if (lane_num == 3) { 3929 SOC_IF_ERROR_RETURN 3930 (MODIFY_HL65_TX3_TX_BR_DRIVERr(unit, pc, data, mask)); 3931 SOC_IF_ERROR_RETURN 3932 (MODIFY_HL65_TX3_TX_OS_DRIVERr(unit, pc, data, mask)); 3933 } 3934 } else { /* default control in combo mode: bcst to all lanes */ 3935 /* set for both BR mode and OS mode */ 3936 SOC_IF_ERROR_RETURN 3937 (MODIFY_HL65_TX0_TX_BR_DRIVERr(unit, pc, data, mask)); 3938 SOC_IF_ERROR_RETURN 3939 (MODIFY_HL65_TX0_TX_OS_DRIVERr(unit, pc, data, mask)); 3940 SOC_IF_ERROR_RETURN 3941 (MODIFY_HL65_TX1_TX_BR_DRIVERr(unit, pc, data, mask)); 3942 SOC_IF_ERROR_RETURN 3943 (MODIFY_HL65_TX1_TX_OS_DRIVERr(unit, pc, data, mask)); 3944 SOC_IF_ERROR_RETURN 3945 (MODIFY_HL65_TX2_TX_BR_DRIVERr(unit, pc, data, mask)); 3946 SOC_IF_ERROR_RETURN 3947 (MODIFY_HL65_TX2_TX_OS_DRIVERr(unit, pc, data, mask)); 3948 SOC_IF_ERROR_RETURN 3949 (MODIFY_HL65_TX3_TX_BR_DRIVERr(unit, pc, data, mask)); 3950 SOC_IF_ERROR_RETURN 3951 (MODIFY_HL65_TX3_TX_OS_DRIVERr(unit, pc, data, mask)); 3952 } 3953 3954 return SOC_E_NONE; 3955 } 3956 3957 STATIC int 3958 _phy_hl65_control_tx_driver_get(int unit, phy_ctrl_t *pc, 3959 soc_phy_control_t type, uint32 *value) 3960 { 3961 uint16 data16; /* Temporary holder of 16 bit reg value */ 3962 uint16 mask; 3963 int shifter; 3964 int lane_ctrl; 3965 int lane_num; 3966 3967 SOC_IF_ERROR_RETURN 3968 (_phy_hl65_tx_driver_field_get(type,&lane_ctrl,&mask,&shifter)); 3969 3970 3971 /* Read preemphasis/driver/pre-driver current */ 3972 if ((lane_ctrl != TX_DRIVER_DFT_LN_CTRL) || 3973 PHY_INDEPENDENT_LANE_MODE(unit, pc->port) || 3974 PHY_HC65_FABRIC_MODE(unit, pc->port)) { 3975 if (lane_ctrl != TX_DRIVER_DFT_LN_CTRL) { 3976 lane_num = lane_ctrl; 3977 } else { 3978 lane_num = pc->lane_num; 3979 } 3980 if (lane_num == 0) { 3981 SOC_IF_ERROR_RETURN 3982 (READ_HL65_TX0_TX_OS_DRIVERr(unit, pc, &data16)); 3983 } else if (lane_num == 1) { 3984 SOC_IF_ERROR_RETURN 3985 (READ_HL65_TX1_TX_OS_DRIVERr(unit, pc, &data16)); 3986 } else if (lane_num == 2) { 3987 SOC_IF_ERROR_RETURN 3988 (READ_HL65_TX2_TX_OS_DRIVERr(unit, pc, &data16)); 3989 } else if (lane_num == 3) { 3990 SOC_IF_ERROR_RETURN 3991 (READ_HL65_TX3_TX_OS_DRIVERr(unit, pc, &data16)); 3992 } else { 3993 return (SOC_E_PARAM); 3994 } 3995 } else { 3996 SOC_IF_ERROR_RETURN 3997 (READ_HL65_TX0_TX_OS_DRIVERr(unit, pc, &data16)); 3998 } 3999 4000 *value = (data16 & mask) >> shifter; 4001 4002 return SOC_E_NONE; 4003 } 4004 4005 4006 STATIC int 4007 _phy_hl65_tuning_done_get(int unit, soc_port_t port,int lane_num, uint16 *done) 4008 { 4009 uint16 data; 4010 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 4011 4012 /* *bTuningDone = FALSE;*/ 4013 *done = 0; 4014 4015 /* Read tuning status */ 4016 /* uRegAddr = 0x82b7 + (uLaneAddr*0x10); 4017 * rv = soc_bm9600_mdio_hc_read(unit, uPhyAddr, 0, uRegAddr, &uData); 4018 */ 4019 SOC_IF_ERROR_RETURN 4020 (HL65_REG_READ(unit,pc,0x0,0x82B7 + (0x10 * lane_num), &data)); 4021 4022 #if 0 4023 /* If tuning is done */ 4024 if (uData & 0x2000) { 4025 LOG_ERROR(BSL_LS_SOC_PHY, 4026 (BSL_META_U(unit, 4027 "hc(%02d:%02d) Tuning Done indication received\n"), 4028 uPhyAddr, uLaneAddr)); 4029 *bTuningDone = TRUE; 4030 } 4031 #endif 4032 *done = (data & 4033 (DSC3B0_SM_STATUS0_TUNING_DONE_BITS << 4034 DSC3B0_SM_STATUS0_TUNING_DONE_SHIFT)) ? 1 : 0; 4035 4036 return SOC_E_NONE; 4037 } 4038 4039 4040 /* #define BCM_BM9600_HYPERCORE_PORT_TUNING_AVG 40 */ 4041 #define PHY_HL65_PORT_TUNING_AVG 40 4042 4043 STATIC int 4044 _phy_hl65_tuning_status_get(int unit, soc_port_t port, 4045 int lane_num, 4046 uint16 *vga_sum_avg, 4047 uint16 *dfe_tap_bin_avg) 4048 { 4049 uint16 data, cnt; 4050 uint16 cur_vga, avg_vga, cur_dfe, avg_dfe; 4051 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 4052 4053 avg_vga = 0; 4054 avg_dfe = 0; 4055 4056 for (cnt=0; cnt < PHY_HL65_PORT_TUNING_AVG; cnt++) { 4057 4058 /* uRegAddr = 0x82b5 + (uLaneAddr*0x10); 4059 * rv = soc_bm9600_mdio_hc_read(unit, uPhyAddr, 0, uRegAddr, &uData); 4060 */ 4061 SOC_IF_ERROR_RETURN 4062 (HL65_REG_READ(unit,pc,0x0,0x82b5 + (0x10 * lane_num), &data)); 4063 4064 /* uCurrentVga = (uData & 0x07c0)>>6; 4065 * uCurrentDfe = (uData & 0x003f); 4066 */ 4067 cur_vga = (data & DSC3B0_DFE_VGA_STATUS0_VGA_SUM_MASK) >> 4068 DSC3B0_DFE_VGA_STATUS0_VGA_SUM_SHIFT; 4069 cur_dfe = (data & DSC3B0_DFE_VGA_STATUS0_DFE_TAP_BIN_MASK); 4070 4071 /*uAvgVga += uCurrentVga; 4072 *uAvgDfe += uCurrentDfe; 4073 */ 4074 avg_vga += cur_vga; 4075 avg_dfe += cur_dfe; 4076 } 4077 4078 /* Divide to get the average value */ 4079 /* uAvgVga = uAvgVga/BCM_BM9600_HYPERCORE_PORT_TUNING_AVG; 4080 * uAvgDfe = uAvgDfe/BCM_BM9600_HYPERCORE_PORT_TUNING_AVG; 4081 */ 4082 avg_vga = avg_vga / PHY_HL65_PORT_TUNING_AVG; 4083 avg_dfe = avg_dfe / PHY_HL65_PORT_TUNING_AVG; 4084 4085 /* *pVgaSumAvg = uAvgVga; 4086 * *pDfeTapBinAvg = uAvgDfe; 4087 */ 4088 *vga_sum_avg = avg_vga; 4089 4090 4091 *dfe_tap_bin_avg = avg_dfe; 4092 4093 #if 0 4094 LOG_ERROR(BSL_LS_SOC_PHY, 4095 (BSL_META_U(unit, 4096 "hc(%02d:%02d) VGA avg(%d)\n"), 4097 uPhyAddr, uLaneAddr, uAvgVga)); 4098 LOG_ERROR(BSL_LS_SOC_PHY, 4099 (BSL_META_U(unit, 4100 "hc(%02d:%02d) DFE avg(%d)\n"), 4101 uPhyAddr, uLaneAddr, uAvgDfe)); 4102 #endif 4103 LOG_INFO(BSL_LS_SOC_PHY, 4104 (BSL_META_U(unit, 4105 "hc(%02d) VGA avg(%d)\n"), port, avg_vga)); 4106 LOG_INFO(BSL_LS_SOC_PHY, 4107 (BSL_META_U(unit, 4108 "hc(%02d) DFE avg(%d)\n"), port, avg_dfe)); 4109 4110 return SOC_E_NONE; 4111 } 4112 4113 STATIC int 4114 _phy_hl65_fine_tune(int unit, soc_port_t port, int lane_num) 4115 { 4116 uint16 data, cnt; 4117 uint16 tuning_done; 4118 uint32 reg_addr; 4119 int avg_vga_sum; 4120 int rv = SOC_E_NONE; 4121 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 4122 uint16 serdes_id0; 4123 4124 SOC_IF_ERROR_RETURN 4125 (READ_HL65_TEST_SERDESID0r(unit, pc, &serdes_id0)); 4126 4127 serdes_id0 = serdes_id0 & (TEST_SERDESID0_REV_NUMBER_MASK | 4128 TEST_SERDESID0_REV_LETTER_MASK); 4129 4130 if ((serdes_id0 == HL_SERDES_ID0_REVID_A0) || 4131 (serdes_id0 == HL_SERDES_ID0_REVID_A1) || 4132 (serdes_id0 == HL_SERDES_ID0_REVID_B0)) { 4133 /* Disable DSC tuning state machine */ 4134 /* uRegAddr = 0x8260 + (uLaneAddr*0x10); 4135 * rv = soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, uRegAddr, &uData); 4136 */ 4137 reg_addr = 0x8260 + (lane_num * 0x10); 4138 SOC_IF_ERROR_RETURN 4139 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4140 4141 /* tuning_sm_en: bit 0 */ 4142 /* uData &= ~0x1; */ 4143 data &= ~DSC2B0_SM_CTRL0_TUNING_SM_EN_BITS; 4144 4145 /*rv = soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData);*/ 4146 SOC_IF_ERROR_RETURN 4147 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4148 4149 /* Enable training mode in state machine */ 4150 /* uRegAddr = 0x8262 + (uLaneAddr*0x10); 4151 * rv = soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, uRegAddr, &uData); 4152 */ 4153 reg_addr = 0x8262 + (lane_num * 0x10); 4154 SOC_IF_ERROR_RETURN 4155 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4156 4157 /* uData |= 1; */ /* train_mode_en */ 4158 data |= DSC2B0_SM_CTRL2_TRAIN_MODE_EN_BITS; 4159 4160 /*rv = soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData);*/ 4161 SOC_IF_ERROR_RETURN 4162 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4163 } 4164 4165 /* Bypass BR peaking filter calibration */ 4166 /* uRegAddr = 0x8260 + (uLaneAddr*0x10); 4167 * soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, uRegAddr, &uData); 4168 */ 4169 reg_addr = 0x8260 + (lane_num * 0x10); 4170 SOC_IF_ERROR_RETURN 4171 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4172 4173 /* bypass_br_pf_cal */ 4174 /* uData |= 0x200; */ 4175 data |= (DSC2B0_SM_CTRL0_BYPASS_BR_PF_CAL_BITS << 4176 DSC2B0_SM_CTRL0_BYPASS_BR_PF_CAL_SHIFT); 4177 4178 if (serdes_id0 == HL_SERDES_ID0_REVID_C0) { 4179 /* bypass _tx_postc_calibration */ 4180 data |= (DSC2B0_SM_CTRL0_BYPASS_TX_POSTC_CAL_BITS << 4181 DSC2B0_SM_CTRL0_BYPASS_TX_POSTC_CAL_SHIFT); 4182 } 4183 /*rv = soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData);*/ 4184 SOC_IF_ERROR_RETURN 4185 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4186 4187 if ((serdes_id0 == HL_SERDES_ID0_REVID_A0) || 4188 (serdes_id0 == HL_SERDES_ID0_REVID_A1) || 4189 (serdes_id0 == HL_SERDES_ID0_REVID_B0)) { 4190 4191 /* DSC Analog control 0 odd ctrl register setup */ 4192 /* uRegAddr = 0x821a + (uLaneAddr*0x10); 4193 * uData = 0x8000; 4194 */ 4195 /* Write 0 to p1_odd_ctrl, d_odd_ctrl and m1_odd_ctrl and set force_odd_ctrl to 1 */ 4196 reg_addr = 0x821a + (lane_num * 0x10); 4197 data = (DSC1B0_DSC_ANA_CTRL0_FORCE_ODD_CTRL_BITS << 4198 DSC1B0_DSC_ANA_CTRL0_FORCE_ODD_CTRL_SHIFT); 4199 4200 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData);*/ 4201 SOC_IF_ERROR_RETURN 4202 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4203 4204 4205 /* DSC Analog control 0 even ctrl register setup */ 4206 /* uRegAddr = 0x821b + (uLaneAddr*0x10); 4207 * uData = 0x8000; 4208 */ 4209 reg_addr = 0x821b + (lane_num * 0x10); 4210 /* Write 0 to p1_evn_ctrl, d_evn_ctrl and m1_evn_ctrl and set force_evn_ctrl to 1 */ 4211 data = (DSC1B0_DSC_ANA_CTRL1_FORCE_EVN_CTRL_BITS << 4212 DSC1B0_DSC_ANA_CTRL1_FORCE_EVN_CTRL_SHIFT); 4213 4214 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData);*/ 4215 SOC_IF_ERROR_RETURN 4216 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4217 4218 4219 /* read vga_sum 10 times and average */ 4220 /* uRegAddr = 0x82b5 + (uLaneAddr*0x10); 4221 * uAvgVgaSum = 0; 4222 */ 4223 reg_addr = 0x82b5 + (lane_num * 0x10); 4224 avg_vga_sum = 0; 4225 for (cnt=0; cnt < 10; cnt++) { 4226 /* rv = soc_bm9600_mdio_hc_read(unit, uPhyAddr, 0, uRegAddr, &uData); */ 4227 SOC_IF_ERROR_RETURN 4228 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4229 /*uAvgVgaSum += (uData & 0x07c0) >> 6;*/ 4230 avg_vga_sum += ((data & DSC3B0_DFE_VGA_STATUS0_VGA_SUM_MASK) >> 4231 DSC3B0_DFE_VGA_STATUS0_VGA_SUM_SHIFT); 4232 } 4233 /* uAvgVgaSum = uAvgVgaSum/10; */ 4234 avg_vga_sum = avg_vga_sum / 10; 4235 4236 LOG_INFO(BSL_LS_SOC_PHY, 4237 (BSL_META_U(unit, 4238 "hc(%02d) VGA avg sum(%d)\n"), 4239 port, avg_vga_sum)); 4240 4241 if (avg_vga_sum > 31) { 4242 LOG_ERROR(BSL_LS_SOC_PHY, 4243 (BSL_META_U(unit, 4244 "ERROR: hc(%02d) VGA avg sum out of range(%d) maximum allowed 31\n"), 4245 port, avg_vga_sum)); 4246 return SOC_E_FAIL; 4247 } 4248 4249 /* write vga average into vga_write_val */ 4250 /* uRegAddr = 0x8215 + (uLaneAddr*0x10); 4251 * rv = soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, uRegAddr, &uData); 4252 */ 4253 reg_addr = 0x8215 + (lane_num * 0x10); 4254 SOC_IF_ERROR_RETURN 4255 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4256 4257 /*uData = uData & ~0x03e; 4258 * uData |= uAvgVgaSum << 1; 4259 */ 4260 data = data & (~DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_VAL_MASK); 4261 data |= (avg_vga_sum << DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_VAL_SHIFT); 4262 4263 /* rv = soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData);*/ 4264 SOC_IF_ERROR_RETURN 4265 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4266 4267 4268 /* Toggle vga_write_en to complete the VGA write */ 4269 /* uData |= 1;*/ 4270 data |= DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_EN_BITS; 4271 4272 /*rv = soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData);*/ 4273 SOC_IF_ERROR_RETURN 4274 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4275 4276 /* uData &=~1; */ 4277 data &= ~DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_EN_BITS; 4278 4279 /*rv = soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData);*/ 4280 SOC_IF_ERROR_RETURN 4281 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4282 4283 4284 4285 /* DSC Analog control 0 odd ctrl register setup */ 4286 /* uRegAddr = 0x821a + (uLaneAddr*0x10); 4287 * uData = 0x0000; 4288 */ 4289 /* Write 0 to p1_odd_ctrl, d_odd_ctrl and m1_odd_ctrl and set force_odd_ctrl to 0 */ 4290 reg_addr = 0x821a + (lane_num * 0x10); 4291 data = 0; 4292 4293 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData);*/ 4294 SOC_IF_ERROR_RETURN 4295 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4296 4297 4298 /* DSC Analog control 0 even ctrl register setup */ 4299 /* uRegAddr = 0x821b + (uLaneAddr*0x10); 4300 * uData = 0x0000; 4301 */ 4302 reg_addr = 0x821b + (lane_num * 0x10); 4303 /* Write 0 to p1_evn_ctrl, d_evn_ctrl and m1_evn_ctrl and set force_evn_ctrl to 0 */ 4304 data = 0; 4305 4306 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData);*/ 4307 SOC_IF_ERROR_RETURN 4308 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4309 4310 } 4311 /* Enable DSC tuning state machine */ 4312 /* uRegAddr = 0x8260 + (uLaneAddr*0x10);*/ 4313 reg_addr = 0x8260 + (lane_num * 0x10 ); 4314 /*rv = soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, uRegAddr, &uData);*/ 4315 SOC_IF_ERROR_RETURN 4316 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4317 4318 /* uData |= 0x1; */ 4319 /* tuning_sm_en: bit 0 */ 4320 data |= DSC2B0_SM_CTRL0_TUNING_SM_EN_BITS; 4321 4322 /*rv = soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData);*/ 4323 SOC_IF_ERROR_RETURN 4324 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4325 4326 /* Restart tuning */ 4327 /* uData |= 2;*/ 4328 data |= (DSC2B0_SM_CTRL0_RESTART_TUNING_BITS << 4329 DSC2B0_SM_CTRL0_RESTART_TUNING_SHIFT); 4330 4331 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData);*/ 4332 SOC_IF_ERROR_RETURN 4333 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4334 4335 4336 /* Wait for tuning done signal (timeout) */ 4337 for (cnt = 0; cnt < 50; cnt++) { 4338 /* _bcm_bm9600_hypercore_tuning_done_get(unit, uPhyAddr, uLaneAddr, &bTuningDone);*/ 4339 SOC_IF_ERROR_RETURN 4340 (_phy_hl65_tuning_done_get(unit, port, lane_num,&tuning_done)); 4341 4342 if (tuning_done) { 4343 break; 4344 } 4345 4346 /*thin_delay(10000000);*/ 4347 /* 10 milliseconds */ 4348 sal_usleep(10000); 4349 } 4350 4351 if (!tuning_done) { 4352 LOG_ERROR(BSL_LS_SOC_PHY, 4353 (BSL_META_U(unit, 4354 "ERROR: hc(%02d) tuning done timed out during BR fine tuning\n"), 4355 port)); 4356 4357 rv = SOC_E_TIMEOUT; 4358 } 4359 4360 /* restore br_pf_calibration and disable training mode */ 4361 /* uRegAddr = 0x8260 + (uLaneAddr*0x10);*/ 4362 reg_addr = 0x8260 + (lane_num * 0x10); 4363 4364 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, uRegAddr, &uData);*/ 4365 SOC_IF_ERROR_RETURN 4366 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4367 4368 /*uData &= ~0x200; */ 4369 /* bypass_br_pf_cal */ 4370 data &= ~(DSC2B0_SM_CTRL0_BYPASS_BR_PF_CAL_BITS << 4371 DSC2B0_SM_CTRL0_BYPASS_BR_PF_CAL_SHIFT); 4372 4373 if (serdes_id0 == HL_SERDES_ID0_REVID_C0) { 4374 /* bypass _tx_postc_calibration */ 4375 data &= ~(DSC2B0_SM_CTRL0_BYPASS_TX_POSTC_CAL_BITS << 4376 DSC2B0_SM_CTRL0_BYPASS_TX_POSTC_CAL_SHIFT); 4377 } 4378 4379 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData);*/ 4380 SOC_IF_ERROR_RETURN 4381 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4382 4383 /* disable training mode */ 4384 /* uRegAddr = 0x8262 + (uLaneAddr*0x10); */ 4385 reg_addr = 0x8262 + (lane_num * 0x10); 4386 4387 /* soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, uRegAddr, &uData);*/ 4388 SOC_IF_ERROR_RETURN 4389 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4390 4391 /* uData &= ~1; */ 4392 /* train_mode_en */ 4393 data &= ~DSC2B0_SM_CTRL2_TRAIN_MODE_EN_BITS; 4394 4395 /* soc_bm9600_mdio_hc_write(unit, uPhyAddr, uLaneAddr, uRegAddr, uData);*/ 4396 SOC_IF_ERROR_RETURN 4397 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4398 4399 return rv; 4400 } 4401 4402 4403 STATIC int 4404 _phy_hl65_control_eq_tune_status_get(int unit, 4405 soc_port_t port, 4406 int lane_num, 4407 uint32 *value) 4408 { 4409 uint16 data; 4410 uint16 sig_detected; 4411 uint16 saved_status_select; 4412 uint16 tuning_done; 4413 uint16 avg_vga, avg_dfe; 4414 uint16 postc_metric, negative; 4415 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 4416 int cnt; 4417 uint16 serdes_id0; 4418 4419 SOC_IF_ERROR_RETURN 4420 (READ_HL65_TEST_SERDESID0r(unit, pc, &serdes_id0)); 4421 4422 serdes_id0 = serdes_id0 & (TEST_SERDESID0_REV_NUMBER_MASK | 4423 TEST_SERDESID0_REV_LETTER_MASK); 4424 4425 4426 *value = FALSE; 4427 4428 /* Make sure we have signal detect */ 4429 /* status = _bcm_bm9600_hypercore_sigdet_status_get(unit, uPhyAddr, uLaneAddr, &bSigDetected) 4430 * ---> code for this function brought here--- 4431 * uRegAddr = 0x80b1; 4432 * uRegAddr += uLaneAddr * 0x10; 4433 * 4434 * Save off current value of 0x80b1 status_sel 4435 * 4436 * rv = soc_bm9600_mdio_hc_read(unit, uPhyAddr, 0, uRegAddr, &uData); 4437 */ 4438 SOC_IF_ERROR_RETURN 4439 (HL65_REG_READ(unit,pc,0x0,0x80B1 + (0x10 * lane_num), &data)); 4440 4441 /* uSavedStatusSelect = uData; */ 4442 saved_status_select = data; 4443 4444 /* Set register 0x80b1 status_sel to get sigDetStatus=0 */ 4445 /* uData &= ~BM9600_HYPERCORE_80B1_STATUS_MASK; 4446 * uData |= BM9600_HYPERCORE_80B1_SIGDET_STATUS_VALUE; 4447 */ 4448 data &= ~RX0_ANARXCONTROL_STATUS_SEL_MASK; 4449 data |= RX0_ANARXCONTROL_STATUS_SEL_sigdetStatus; 4450 4451 /*rv = soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, uRegAddr, uData);*/ 4452 SOC_IF_ERROR_RETURN 4453 (HL65_REG_WRITE(unit,pc,0x0,0x80B1 + (0x10 * lane_num), data)); 4454 4455 /* read to clear latched status */ 4456 SOC_IF_ERROR_RETURN 4457 (HL65_REG_READ(unit,pc,0x0,0x80B0 + (0x10 * lane_num), &data)); 4458 4459 /* read register 0x80b0 to get status and fill in bSigDetected */ 4460 /* uRegAddr = 0x80b0; 4461 * uRegAddr += uLaneAddr * 0x10; 4462 * rv = soc_bm9600_mdio_hc_read(unit, uPhyAddr, 0, uRegAddr, &uData); 4463 */ 4464 SOC_IF_ERROR_RETURN 4465 (HL65_REG_READ(unit,pc,0x0,0x80B0 + (0x10 * lane_num), &data)); 4466 4467 /* if (uData & 0x8000) { 4468 * *bSigDetected = TRUE; 4469 * }else { 4470 * *bSigDetected = FALSE; 4471 * } 4472 */ 4473 sig_detected = (data & 4474 (RX0_ANARXSTATUS_SIGDET_STATUS_CX4_SIGDET_BITS << 4475 RX0_ANARXSTATUS_SIGDET_STATUS_CX4_SIGDET_SHIFT)) ? 1 : 0; 4476 4477 /* write back old value of 0x80b1 status_sel */ 4478 /*rv = soc_bm9600_mdio_hc_write(unit, uPhyAddr, 0, uRegAddr, uSavedStatusSelect); */ 4479 SOC_IF_ERROR_RETURN 4480 (HL65_REG_WRITE(unit,pc,0x0,0x80B1 + (0x10 * lane_num), saved_status_select)); 4481 4482 #if 0 4483 if (!bSigDetected) { 4484 LOG_ERROR(BSL_LS_SOC_PHY, 4485 (BSL_META_U(unit, 4486 "ERROR: Receiver indicates that no signal detected, check far end enable.\n"))); 4487 } 4488 #endif 4489 if (!sig_detected) { 4490 LOG_ERROR(BSL_LS_SOC_PHY, 4491 (BSL_META_U(unit, 4492 "Receiver indicates that no signal detected. " 4493 "Checking far end enable.\n"))); 4494 } 4495 4496 /* Wait for tuning done signal (timeout) */ 4497 for (cnt = 0; cnt < 50; cnt++) { 4498 /* _bcm_bm9600_hypercore_tuning_done_get(unit, uPhyAddr, uLaneAddr, &bTuningDone);*/ 4499 SOC_IF_ERROR_RETURN 4500 (_phy_hl65_tuning_done_get(unit, port, lane_num,&tuning_done)); 4501 4502 if (tuning_done) { 4503 break; 4504 } 4505 4506 /*thin_delay(10000000);*/ /* 10 milliseconds */ 4507 sal_usleep(10000); 4508 } 4509 4510 #if 0 4511 if (!bTuningDone) { 4512 LOG_ERROR(BSL_LS_SOC_PHY, 4513 (BSL_META_U(unit, 4514 "ERROR: Tuning error port(%d), no tuning done indication from hardware\n"), 4515 port)); 4516 } 4517 #endif 4518 if (!tuning_done) { 4519 LOG_ERROR(BSL_LS_SOC_PHY, 4520 (BSL_META_U(unit, 4521 "No tune done indication received on port %d\n"), 4522 port)); 4523 4524 } else { 4525 /* _bcm_bm9600_hypercore_tuning_status_get(unit, uPhyAddr, uLaneAddr, &uAvgVga, &uAvgDfe);*/ 4526 SOC_IF_ERROR_RETURN 4527 (_phy_hl65_tuning_status_get(unit, port, lane_num, 4528 &avg_vga, &avg_dfe)); 4529 4530 if ((serdes_id0 == HL_SERDES_ID0_REVID_A0) || 4531 (serdes_id0 == HL_SERDES_ID0_REVID_A1) || 4532 (serdes_id0 == HL_SERDES_ID0_REVID_B0)) { 4533 4534 /* If (uAvgDfe < 8) { 4535 * postc_metric = 0x400; -1023 11 bit 2s complement number 4536 * } else if (uAvgDfe > 56) { 4537 * postc_metric = 0x3ff; 1023 11 bit 2s complement number 4538 * } else { 4539 */ 4540 if (avg_dfe < 8) { 4541 postc_metric = 0x400; /* -1023 11 bit 2s complement number */ 4542 } else if (avg_dfe > 56) { 4543 postc_metric = 0x3ff; /* 1023 11 bit 2s complement number */ 4544 } else { 4545 /* uRegAddr = 0x82b8 + (uLaneAddr*0x10); 4546 * status = soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, uRegAddr, &uData); 4547 */ 4548 SOC_IF_ERROR_RETURN 4549 (HL65_REG_READ(unit,pc,0x0,0x82b8 + (0x10 * lane_num), &data)); 4550 4551 /* postc_metric = uData & 0x7ff;*/ 4552 postc_metric = data & DSC3B0_SM_STATUS1_POSTC_METRIC_MASK; 4553 } 4554 } else { /* C0 */ 4555 /* uRegAddr = 0x82b8 + (uLaneAddr*0x10); 4556 * status = soc_bm9600_mdio_hc_read(unit, uPhyAddr, uLaneAddr, uRegAddr, &uData); 4557 */ 4558 SOC_IF_ERROR_RETURN 4559 (HL65_REG_READ(unit,pc,0x0,0x82b8 + (0x10 * lane_num), &data)); 4560 4561 /* postc_metric = uData & 0x7ff;*/ 4562 postc_metric = data & DSC3B0_SM_STATUS1_POSTC_METRIC_MASK; 4563 } 4564 4565 /* negative = postc_metric >> 10; */ 4566 /* Extract the sign bit */ 4567 negative = postc_metric >> (DSC3B0_SM_STATUS1_POSTC_METRIC_BITS - 1); 4568 4569 /* Get rid of the sign on the metric now */ 4570 if (postc_metric > 1023) postc_metric -= 1024; 4571 4572 /* if (!negative && (uAvgDfe < 30) && (postc_metric < 15)) { */ 4573 if ((!negative) && (avg_dfe < 30)) { 4574 LOG_WARN(BSL_LS_SOC_PHY, 4575 (BSL_META_U(unit, 4576 "port(%d) postc_metric(0x%x) is positive\n"), 4577 port, postc_metric)); 4578 4579 *value = FALSE; 4580 4581 } else { 4582 LOG_INFO(BSL_LS_SOC_PHY, 4583 (BSL_META_U(unit, 4584 "port(%d) remote equalization calibration complete\n"), 4585 port)); 4586 4587 *value = TRUE; 4588 } 4589 4590 /* Perform fine tuning operation */ 4591 /*status = _bcm_bm9600_hypercore_fine_tune(unit, uPhyAddr, uLaneAddr);*/ 4592 4593 if (_phy_hl65_fine_tune(unit, port,lane_num) != SOC_E_NONE) { 4594 LOG_WARN(BSL_LS_SOC_PHY, 4595 (BSL_META_U(unit, 4596 "port(%d) hl65_fine_tune fail\n"), port)); 4597 } 4598 } 4599 return SOC_E_NONE; 4600 } 4601 4602 4603 STATIC int 4604 _phy_hl65_control_linkdown_transmit_set(int unit, soc_port_t port, uint32 value) 4605 { 4606 uint16 ctrl2_data; 4607 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 4608 4609 if (value) { 4610 ctrl2_data = (DIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_BITS << 4611 DIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_SHIFT) | 4612 (DIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_BITS << 4613 DIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_SHIFT) | 4614 (DIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_BITS << 4615 DIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_SHIFT); 4616 SOC_IF_ERROR_RETURN 4617 (WRITE_HL65_DIGITAL_CONTROL1000X2r(unit, pc, ctrl2_data)); 4618 4619 } else { 4620 ctrl2_data = (DIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_BITS << 4621 DIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_SHIFT) | 4622 (DIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_BITS << 4623 DIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_SHIFT) | 4624 (DIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_BITS << 4625 DIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_SHIFT); 4626 SOC_IF_ERROR_RETURN 4627 (WRITE_HL65_DIGITAL_CONTROL1000X2r(unit, pc, ctrl2_data)); 4628 } 4629 4630 return SOC_E_NONE; 4631 } 4632 4633 STATIC int 4634 _phy_hl65_control_linkdown_transmit_get(int unit, soc_port_t port, uint32 *value) 4635 { 4636 uint16 data; 4637 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 4638 4639 SOC_IF_ERROR_RETURN 4640 (READ_HL65_DIGITAL_CONTROL1000X2r(unit, pc, &data)); 4641 4642 /* Check if FORCE_XMIT_DATA_ON_TXSIDE is set */ 4643 *value = (data & (DIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_BITS << 4644 DIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_SHIFT)) 4645 ? 1 : 0; 4646 4647 return SOC_E_NONE; 4648 } 4649 4650 4651 4652 /* 4653 * Get current DSC config 4654 */ 4655 STATIC int 4656 _phy_hl65_dsc_cfg_get(int unit, soc_port_t port, int lane_num, 4657 phy_hl65_dsc_cfg_t *dsc_cfg) 4658 4659 { 4660 int rv = SOC_E_NONE; 4661 uint16 data; 4662 uint32 reg_addr; 4663 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 4664 4665 reg_addr = 0x82b2 + (lane_num * 0x10); 4666 SOC_IF_ERROR_RETURN 4667 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4668 4669 if (data & DSC3B0_CDR_STATUS2_BR_CDR_ENABLED_MASK) { 4670 *dsc_cfg = PHY_HL65_DSC_CFG_BR_CDR; 4671 } else { 4672 data = (data & DSC3B0_CDR_STATUS2_OSCDR_MODE_MASK) >> 4673 DSC3B0_CDR_STATUS2_OSCDR_MODE_SHIFT; 4674 switch (data) { 4675 case 0: 4676 *dsc_cfg = PHY_HL65_DSC_CFG_1X_OSR; 4677 break; 4678 case 1: 4679 *dsc_cfg = PHY_HL65_DSC_CFG_2X_OSR; 4680 break; 4681 case 2: 4682 *dsc_cfg = PHY_HL65_DSC_CFG_4X_OSR; 4683 break; 4684 case 3: 4685 *dsc_cfg = PHY_HL65_DSC_CFG_5X_OSR; 4686 break; 4687 default: 4688 *dsc_cfg = PHY_HL65_DSC_CFG_UNKNOWN; 4689 rv = SOC_E_INTERNAL; 4690 break; 4691 } 4692 } 4693 4694 return rv; 4695 } 4696 4697 /* 4698 * Return value range 4699 */ 4700 STATIC int 4701 _phy_hl65_control_serdes_tune_margin_max_get(int unit, soc_port_t port, 4702 int lane_num, uint32 *max) 4703 4704 { 4705 phy_hl65_dsc_cfg_t dsc_cfg; 4706 4707 /* Get DSC config */ 4708 SOC_IF_ERROR_RETURN 4709 (_phy_hl65_dsc_cfg_get(unit, port, lane_num, &dsc_cfg)); 4710 4711 switch (dsc_cfg) { 4712 case PHY_HL65_DSC_CFG_BR_CDR: 4713 /* vertical diag */ 4714 *max = (1 << DSC1B0_DSC_ANA_CTRL1_D_EVN_CTRL_BITS); 4715 break; 4716 case PHY_HL65_DSC_CFG_1X_OSR: 4717 case PHY_HL65_DSC_CFG_2X_OSR: 4718 /* horizontal diag 1xOSR 4719 * pi_phase_delta for 1xOSR == 1 so return full range 4720 */ 4721 *max = (1 << DSC3B0_PI_STATUS0_CLK90_PHASE_OFFSET_BITS); 4722 break; 4723 default: 4724 LOG_ERROR(BSL_LS_SOC_PHY, 4725 (BSL_META_U(unit, 4726 "Tune margin supported for 1XOSR, 2XOSR, " 4727 "BR CDR DSC"))); 4728 return SOC_E_UNAVAIL; 4729 } 4730 return SOC_E_NONE; 4731 4732 } 4733 4734 STATIC int 4735 _phy_hl65_serdes_tune_margin_common_start(int unit, soc_port_t port, 4736 int lane_num) 4737 { 4738 uint16 data; 4739 uint16 vga_sum_avg; 4740 uint16 dfe_tap_bin_avg; 4741 uint32 reg_addr; 4742 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 4743 4744 /* Step 1: check tuning done */ 4745 LOG_INFO(BSL_LS_SOC_PHY, 4746 (BSL_META_U(unit, 4747 "Step 1: check tuning done\n"))); 4748 reg_addr = 0x82b7 + (lane_num * 0x10); 4749 SOC_IF_ERROR_RETURN 4750 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4751 4752 if (!(data & DSC3B0_SM_STATUS0_TUNING_DONE_MASK)) { 4753 LOG_ERROR(BSL_LS_SOC_PHY, 4754 (BSL_META_U(unit, 4755 "ERROR: hc(%02d) tuning has not finished\n"), port)); 4756 return SOC_E_FAIL; 4757 } 4758 4759 /* Step 2: average vga_sum and dfe_tap_bin */ 4760 LOG_INFO(BSL_LS_SOC_PHY, 4761 (BSL_META_U(unit, 4762 "Step 2: compute vga_sum, dfe_tap_bin average\n"))); 4763 SOC_IF_ERROR_RETURN 4764 (_phy_hl65_tuning_status_get(unit, port, pc->lane_num, 4765 &vga_sum_avg, &dfe_tap_bin_avg)); 4766 4767 /* Step 3: fix vga_sum and dfe_tab_bin */ 4768 LOG_INFO(BSL_LS_SOC_PHY, 4769 (BSL_META_U(unit, 4770 "Step 3: fix vga_sum, dfe_tap_bin\n"))); 4771 reg_addr = 0x8215 + (lane_num * 0x10); 4772 SOC_IF_ERROR_RETURN 4773 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4774 4775 data &= ~(DSC1B0_DFE_VGA_CTRL1_DFE_WRITE_VAL_MASK | 4776 DSC1B0_DFE_VGA_CTRL1_DFE_WRITE_EN_MASK | 4777 DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_VAL_MASK | 4778 DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_EN_MASK); 4779 data |= (vga_sum_avg << DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_VAL_SHIFT) | 4780 (dfe_tap_bin_avg << DSC1B0_DFE_VGA_CTRL1_DFE_WRITE_VAL_SHIFT); 4781 4782 SOC_IF_ERROR_RETURN 4783 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4784 4785 /* Now toggle the write enable bits */ 4786 data &= ~((DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_EN_BITS << 4787 DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_EN_SHIFT) | 4788 (DSC1B0_DFE_VGA_CTRL1_DFE_WRITE_EN_BITS << 4789 DSC1B0_DFE_VGA_CTRL1_DFE_WRITE_EN_SHIFT)); 4790 4791 SOC_IF_ERROR_RETURN 4792 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4793 4794 data |= (DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_EN_BITS << 4795 DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_EN_SHIFT) | 4796 (DSC1B0_DFE_VGA_CTRL1_DFE_WRITE_EN_BITS << 4797 DSC1B0_DFE_VGA_CTRL1_DFE_WRITE_EN_SHIFT); 4798 4799 SOC_IF_ERROR_RETURN 4800 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4801 /* 4802 * Leave vga_write and dfe_write enabled - will be disabled 4803 * when diag stops 4804 */ 4805 return SOC_E_NONE; 4806 } 4807 4808 STATIC int 4809 _phy_hl65_serdes_tune_margin_horizontal_start(int unit, soc_port_t port, 4810 int lane_num, 4811 phy_hl65_dsc_cfg_t dsc_cfg) 4812 { 4813 uint16 data, delta, exp_clk90_po; 4814 uint32 reg_addr; 4815 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 4816 4817 SOC_IF_ERROR_RETURN 4818 (_phy_hl65_serdes_tune_margin_common_start(unit, port, lane_num)); 4819 4820 /* 4821 * Step 4: verify clk90_phase_offset 4822 * ==32 1xOSR 4823 * ==0 2xOSR 4824 */ 4825 LOG_INFO(BSL_LS_SOC_PHY, 4826 (BSL_META_U(unit, 4827 "Step 4: verify clk90_phase_offset\n"))); 4828 reg_addr = 0x82b3 + (lane_num * 0x10); 4829 SOC_IF_ERROR_RETURN 4830 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4831 data = (data & DSC3B0_PI_STATUS0_CLK90_PHASE_OFFSET_MASK) >> 4832 DSC3B0_PI_STATUS0_CLK90_PHASE_OFFSET_SHIFT; 4833 4834 exp_clk90_po = (dsc_cfg == PHY_HL65_DSC_CFG_1X_OSR) ? 32 : 0; 4835 if (data != exp_clk90_po) { 4836 LOG_WARN(BSL_LS_SOC_PHY, 4837 (BSL_META_U(unit, 4838 "WARNING: hc(%02d) diag clk90 phase offset=%d " 4839 "expected %d\nMake sure DSC is properly configured " 4840 "and tuning is done before running diag\n"), 4841 port, data, exp_clk90_po)); 4842 } 4843 4844 /* Step 5: clk90 offset override */ 4845 LOG_INFO(BSL_LS_SOC_PHY, 4846 (BSL_META_U(unit, 4847 "Step 5: enable clk90 offset override\n"))); 4848 reg_addr = 0x8213 + (lane_num * 0x10); 4849 SOC_IF_ERROR_RETURN 4850 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4851 data |= (DSC1B0_PI_CTRL0_PI_CLK90_OFFSET_OVERRIDE_BITS << 4852 DSC1B0_PI_CTRL0_PI_CLK90_OFFSET_OVERRIDE_SHIFT); 4853 SOC_IF_ERROR_RETURN 4854 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4855 4856 /* Step 6: pi_phase_delta */ 4857 LOG_INFO(BSL_LS_SOC_PHY, 4858 (BSL_META_U(unit, 4859 "Step 6: set pi_phase_delta\n"))); 4860 if (dsc_cfg == PHY_HL65_DSC_CFG_1X_OSR) { 4861 /* 1xOSR */ 4862 delta = 1; 4863 } else if (dsc_cfg == PHY_HL65_DSC_CFG_2X_OSR) { 4864 delta = 2; 4865 } else { 4866 LOG_ERROR(BSL_LS_SOC_PHY, 4867 (BSL_META_U(unit, 4868 "ERROR: hc(%02d) invalid DSC config\n"), 4869 port)); 4870 return SOC_E_PARAM; 4871 } 4872 4873 data = (data & ~(DSC1B0_PI_CTRL0_PI_PHASE_DELTA_MASK)) | 4874 (delta << DSC1B0_PI_CTRL0_PI_PHASE_DELTA_SHIFT); 4875 SOC_IF_ERROR_RETURN 4876 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4877 4878 return SOC_E_NONE; 4879 } 4880 4881 STATIC int 4882 _phy_hl65_serdes_tune_margin_horizontal_adjust(int unit, soc_port_t port, 4883 int lane_num, uint32 inc) 4884 { 4885 uint16 data; 4886 uint32 reg_addr; 4887 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 4888 4889 /* 4890 * Step 7: set phase offset moving direction 4891 */ 4892 LOG_INFO(BSL_LS_SOC_PHY, 4893 (BSL_META_U(unit, 4894 "Step 7: set phase offset moving direction\n"))); 4895 reg_addr = 0x8213 + (lane_num * 0x10); 4896 SOC_IF_ERROR_RETURN 4897 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4898 4899 data &= ~(DSC1B0_PI_CTRL0_PI_PHASE_INC_MASK | 4900 DSC1B0_PI_CTRL0_PI_PHASE_DEC_MASK); 4901 4902 if (inc == 1) { 4903 data |= (DSC1B0_PI_CTRL0_PI_PHASE_INC_BITS << 4904 DSC1B0_PI_CTRL0_PI_PHASE_INC_SHIFT); 4905 } else if (inc == 0) { 4906 data |= (DSC1B0_PI_CTRL0_PI_PHASE_DEC_BITS << 4907 DSC1B0_PI_CTRL0_PI_PHASE_DEC_SHIFT); 4908 } else { 4909 LOG_ERROR(BSL_LS_SOC_PHY, 4910 (BSL_META_U(unit, 4911 "ERROR: hc(%02d) diag invalid adjust\n"), 4912 port)); 4913 return SOC_E_PARAM; 4914 } 4915 4916 /* Step 8: toggle pi phase strobe */ 4917 LOG_INFO(BSL_LS_SOC_PHY, 4918 (BSL_META_U(unit, 4919 "Step 8: toggle pi phase strobe\n"))); 4920 data &= ~(DSC1B0_PI_CTRL0_PI_PHASE_STROBE_BITS << 4921 DSC1B0_PI_CTRL0_PI_PHASE_STROBE_SHIFT); 4922 SOC_IF_ERROR_RETURN 4923 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4924 4925 data |= (DSC1B0_PI_CTRL0_PI_PHASE_STROBE_BITS << 4926 DSC1B0_PI_CTRL0_PI_PHASE_STROBE_SHIFT); 4927 SOC_IF_ERROR_RETURN 4928 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4929 4930 data &= ~(DSC1B0_PI_CTRL0_PI_PHASE_STROBE_BITS << 4931 DSC1B0_PI_CTRL0_PI_PHASE_STROBE_SHIFT); 4932 SOC_IF_ERROR_RETURN 4933 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4934 4935 return SOC_E_NONE; 4936 } 4937 4938 4939 STATIC int 4940 _phy_hl65_serdes_tune_margin_horizontal_stop(int unit, soc_port_t port, 4941 int lane_num, 4942 phy_hl65_dsc_cfg_t dsc_cfg) 4943 4944 { 4945 uint16 data; 4946 uint32 reg_addr; 4947 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 4948 4949 /* 4950 * Step 11: restore pi_clk90_offset_override, 4951 * pi_phase_data, pi_phase_inc/dec 4952 */ 4953 LOG_INFO(BSL_LS_SOC_PHY, 4954 (BSL_META_U(unit, 4955 "Step 11: restore values\n"))); 4956 reg_addr = 0x8213 + (lane_num * 0x10); 4957 SOC_IF_ERROR_RETURN 4958 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4959 4960 data &= ~(DSC1B0_PI_CTRL0_PI_CLK90_OFFSET_OVERRIDE_MASK | 4961 DSC1B0_PI_CTRL0_PI_PHASE_DELTA_MASK | 4962 DSC1B0_PI_CTRL0_PI_PHASE_INC_MASK | 4963 DSC1B0_PI_CTRL0_PI_PHASE_DEC_MASK); 4964 SOC_IF_ERROR_RETURN 4965 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4966 4967 /* Step 12,13: release vga_write and dfe_write */ 4968 LOG_INFO(BSL_LS_SOC_PHY, 4969 (BSL_META_U(unit, 4970 "Step 12: release vga_write, dfe_write enable\n"))); 4971 reg_addr = 0x8215 + (lane_num * 0x10); 4972 SOC_IF_ERROR_RETURN 4973 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 4974 data &= ~(DSC1B0_DFE_VGA_CTRL1_DFE_WRITE_VAL_MASK | 4975 DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_VAL_MASK); 4976 SOC_IF_ERROR_RETURN 4977 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4978 4979 data &= ~((DSC1B0_DFE_VGA_CTRL1_DFE_WRITE_EN_BITS << 4980 DSC1B0_DFE_VGA_CTRL1_DFE_WRITE_EN_SHIFT) | 4981 (DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_EN_BITS << 4982 DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_EN_SHIFT)); 4983 SOC_IF_ERROR_RETURN 4984 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 4985 4986 return SOC_E_NONE; 4987 } 4988 4989 STATIC int 4990 _phy_hl65_serdes_tune_margin_horizontal_value_get(int unit, soc_port_t port, 4991 int lane_num, 4992 uint32 *value) 4993 { 4994 uint16 data; 4995 uint32 reg_addr; 4996 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 4997 4998 reg_addr = 0x82b3 + (lane_num * 0x10); 4999 SOC_IF_ERROR_RETURN 5000 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 5001 5002 *value = (data & DSC3B0_PI_STATUS0_CLK90_PHASE_OFFSET_MASK) >> 5003 DSC3B0_PI_STATUS0_CLK90_PHASE_OFFSET_SHIFT; 5004 5005 /* 5006 * External values are scaled 5007 * 5008 * Internal range 0..127 5009 * 5010 * Internal Value Scaled Value 5011 * Signed / Unsigned Unsigned 5012 * 0 0 64 5013 * 1 1 65 5014 * 2 2 66 5015 * .. .. .. 5016 * 63 63 127 5017 * -64 64 0 5018 * -63 65 1 5019 * -1 127 63 5020 */ 5021 *value = (*value + 64) & 5022 (DSC3B0_PI_STATUS0_CLK90_PHASE_OFFSET_MASK >> 5023 DSC3B0_PI_STATUS0_CLK90_PHASE_OFFSET_SHIFT); 5024 return SOC_E_NONE; 5025 } 5026 5027 /* 5028 * Horizontal adjust 5029 */ 5030 STATIC int 5031 _phy_hl65_serdes_tune_margin_horizontal_value_set(int unit, soc_port_t port, 5032 int lane_num, 5033 phy_hl65_dsc_cfg_t dsc_cfg, 5034 uint32 value) 5035 { 5036 uint32 max, cur_value, 5037 inc = 0; 5038 int i, steps; 5039 5040 SOC_IF_ERROR_RETURN 5041 (_phy_hl65_control_serdes_tune_margin_max_get(unit, port, lane_num, 5042 &max)); 5043 5044 if (value > max) { 5045 LOG_ERROR(BSL_LS_SOC_PHY, 5046 (BSL_META_U(unit, 5047 "Invalid value %d (0..%d)\n"), 5048 value, max-1)); 5049 return SOC_E_PARAM; 5050 } 5051 5052 SOC_IF_ERROR_RETURN 5053 (_phy_hl65_serdes_tune_margin_horizontal_value_get(unit, port, 5054 lane_num, 5055 &cur_value)); 5056 if (value < cur_value) { 5057 steps = cur_value - value; 5058 inc = 0; 5059 } else if (value > cur_value) { 5060 steps = value - cur_value; 5061 inc = 1; 5062 } else { 5063 return SOC_E_NONE; 5064 } 5065 if (dsc_cfg == PHY_HL65_DSC_CFG_2X_OSR) { 5066 /* 2xOSR steps by 2 */ 5067 steps /= 2; 5068 } 5069 5070 LOG_INFO(BSL_LS_SOC_PHY, 5071 (BSL_META_U(unit, 5072 "horizontal adjusting to %d from %d steps %d\n"), 5073 value, cur_value, steps)); 5074 5075 /* Adjust to value */ 5076 for (i = 0; i < steps; i++) { 5077 SOC_IF_ERROR_RETURN 5078 (_phy_hl65_serdes_tune_margin_horizontal_adjust(unit, port, 5079 lane_num, inc)); 5080 } 5081 5082 /* Verify if got there */ 5083 SOC_IF_ERROR_RETURN 5084 (_phy_hl65_serdes_tune_margin_horizontal_value_get(unit, port, 5085 lane_num, 5086 &cur_value)); 5087 5088 /* Adjust if 2xOSR to increment in steps by 2 */ 5089 if ((dsc_cfg == PHY_HL65_DSC_CFG_2X_OSR) && (value % 2)) { 5090 value--; 5091 } 5092 5093 if (cur_value != value) { 5094 LOG_WARN(BSL_LS_SOC_PHY, 5095 (BSL_META_U(unit, 5096 "WARNING: Adjusted value %d does not match requested " 5097 "value %d\n"), cur_value, value)); 5098 } 5099 return SOC_E_NONE; 5100 } 5101 5102 5103 STATIC int 5104 _phy_hl65_serdes_tune_margin_vertical_start(int unit, soc_port_t port, 5105 int lane_num) 5106 { 5107 uint16 data; 5108 uint16 slicer_offset_me, slicer_offset_ze, slicer_offset_pe; 5109 uint32 reg_addr; 5110 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 5111 5112 5113 SOC_IF_ERROR_RETURN 5114 (_phy_hl65_serdes_tune_margin_common_start(unit, port, lane_num)); 5115 5116 /* Step 4: read slicer offset status */ 5117 LOG_INFO(BSL_LS_SOC_PHY, 5118 (BSL_META_U(unit, 5119 "Step 4: read slice offset status\n"))); 5120 reg_addr = 0x82ba + (lane_num * 0x10); 5121 SOC_IF_ERROR_RETURN 5122 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 5123 5124 slicer_offset_me = (data & DSC3B0_SM_STATUS3_SLICER_OFFSET_ME_MASK) >> 5125 DSC3B0_SM_STATUS3_SLICER_OFFSET_ME_SHIFT; 5126 5127 slicer_offset_ze = (data & DSC3B0_SM_STATUS3_SLICER_OFFSET_ZE_MASK) >> 5128 DSC3B0_SM_STATUS3_SLICER_OFFSET_ZE_SHIFT; 5129 5130 slicer_offset_pe = (data & DSC3B0_SM_STATUS3_SLICER_OFFSET_PE_MASK) >> 5131 DSC3B0_SM_STATUS3_SLICER_OFFSET_PE_SHIFT; 5132 5133 /* Step 5: write slicer offsets to control */ 5134 LOG_INFO(BSL_LS_SOC_PHY, 5135 (BSL_META_U(unit, 5136 "Step 5: write slice offset status\n"))); 5137 reg_addr = 0x821b + (lane_num * 0x10); 5138 SOC_IF_ERROR_RETURN 5139 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 5140 5141 data &= ~( DSC1B0_DSC_ANA_CTRL1_P1_EVN_CTRL_MASK | 5142 DSC1B0_DSC_ANA_CTRL1_D_EVN_CTRL_MASK | 5143 DSC1B0_DSC_ANA_CTRL1_M1_EVN_CTRL_MASK); 5144 data |= (slicer_offset_me << DSC1B0_DSC_ANA_CTRL1_M1_EVN_CTRL_SHIFT) | 5145 (slicer_offset_ze << DSC1B0_DSC_ANA_CTRL1_D_EVN_CTRL_SHIFT) | 5146 (slicer_offset_pe << DSC1B0_DSC_ANA_CTRL1_P1_EVN_CTRL_SHIFT); 5147 SOC_IF_ERROR_RETURN 5148 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 5149 5150 return SOC_E_NONE; 5151 } 5152 5153 STATIC int 5154 _phy_hl65_serdes_tune_margin_vertical_adjust(int unit, soc_port_t port, 5155 int lane_num, uint32 inc) 5156 { 5157 uint16 data; 5158 int16 tmp; 5159 uint32 reg_addr; 5160 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 5161 5162 /* 5163 * Step 6: perturb data even slicer 5164 */ 5165 LOG_INFO(BSL_LS_SOC_PHY, 5166 (BSL_META_U(unit, 5167 "Step 6: perturb data even slicer\n"))); 5168 reg_addr = 0x821b + (lane_num * 0x10); 5169 SOC_IF_ERROR_RETURN 5170 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 5171 5172 tmp = (data & DSC1B0_DSC_ANA_CTRL1_D_EVN_CTRL_MASK) 5173 >> DSC1B0_DSC_ANA_CTRL1_D_EVN_CTRL_SHIFT; 5174 5175 if (inc == 1) { 5176 /* increment */ 5177 if (tmp == 0xf) { 5178 LOG_ERROR(BSL_LS_SOC_PHY, 5179 (BSL_META_U(unit, 5180 "ERROR: hc(%02d) cannot increment anymore\n"), 5181 port)); 5182 return SOC_E_PARAM; 5183 } 5184 tmp++; 5185 } else if (inc == 0) { 5186 /* decrement */ 5187 if (tmp == 0x10) { 5188 LOG_ERROR(BSL_LS_SOC_PHY, 5189 (BSL_META_U(unit, 5190 "ERROR: hc(%02d) cannot decrement anymore\n"), 5191 port)); 5192 return SOC_E_PARAM; 5193 } 5194 tmp--; 5195 } else { 5196 LOG_ERROR(BSL_LS_SOC_PHY, 5197 (BSL_META_U(unit, 5198 "ERROR: hc(%02d) diag invalid operation\n"), 5199 port)); 5200 return SOC_E_PARAM; 5201 } 5202 data &= ~(DSC1B0_DSC_ANA_CTRL1_D_EVN_CTRL_MASK); 5203 data |= (tmp << DSC1B0_DSC_ANA_CTRL1_D_EVN_CTRL_SHIFT) | 5204 (DSC1B0_DSC_ANA_CTRL1_FORCE_EVN_CTRL_BITS << 5205 DSC1B0_DSC_ANA_CTRL1_FORCE_EVN_CTRL_SHIFT); 5206 SOC_IF_ERROR_RETURN 5207 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 5208 5209 /* Toggle force even - required? */ 5210 data &= ~(DSC1B0_DSC_ANA_CTRL1_FORCE_EVN_CTRL_BITS << 5211 DSC1B0_DSC_ANA_CTRL1_FORCE_EVN_CTRL_SHIFT); 5212 SOC_IF_ERROR_RETURN 5213 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 5214 5215 return SOC_E_NONE; 5216 } 5217 5218 5219 STATIC int 5220 _phy_hl65_serdes_tune_margin_vertical_value_get(int unit, soc_port_t port, 5221 int lane_num, uint32 *value) 5222 { 5223 uint16 data; 5224 uint32 reg_addr; 5225 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 5226 5227 reg_addr = 0x821b + (lane_num * 0x10); 5228 SOC_IF_ERROR_RETURN 5229 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 5230 5231 *value = (data & DSC1B0_DSC_ANA_CTRL1_D_EVN_CTRL_MASK) 5232 >> DSC1B0_DSC_ANA_CTRL1_D_EVN_CTRL_SHIFT; 5233 5234 /* Scale value */ 5235 *value = (*value + 16) & 5236 (DSC1B0_DSC_ANA_CTRL1_D_EVN_CTRL_MASK >> 5237 DSC1B0_DSC_ANA_CTRL1_D_EVN_CTRL_SHIFT); 5238 return SOC_E_NONE; 5239 } 5240 5241 STATIC int 5242 _phy_hl65_serdes_tune_margin_vertical_value_set(int unit, soc_port_t port, 5243 int lane_num, uint32 value) 5244 { 5245 int i, steps; 5246 uint32 cur_value, max, inc = 0; 5247 5248 5249 SOC_IF_ERROR_RETURN 5250 (_phy_hl65_control_serdes_tune_margin_max_get(unit, port, lane_num, 5251 &max)); 5252 5253 if (value > max) { 5254 LOG_ERROR(BSL_LS_SOC_PHY, 5255 (BSL_META_U(unit, 5256 "Invalid value %d (0..%d)\n"), value, max)); 5257 return SOC_E_PARAM; 5258 } 5259 5260 SOC_IF_ERROR_RETURN 5261 (_phy_hl65_serdes_tune_margin_vertical_value_get(unit, port, 5262 lane_num, 5263 &cur_value)); 5264 if (value < cur_value) { 5265 steps = cur_value - value; 5266 inc = 0; 5267 } else if (value > cur_value) { 5268 steps = value - cur_value; 5269 inc = 1; 5270 } else { 5271 return SOC_E_NONE; 5272 } 5273 5274 /* Adjust to value */ 5275 for (i = 0; i < steps; i++) { 5276 SOC_IF_ERROR_RETURN 5277 (_phy_hl65_serdes_tune_margin_vertical_adjust(unit, port, 5278 lane_num, 5279 inc)); 5280 } 5281 5282 /* Verify if got there */ 5283 SOC_IF_ERROR_RETURN 5284 (_phy_hl65_serdes_tune_margin_vertical_value_get(unit, port, 5285 lane_num, 5286 &cur_value)); 5287 if (cur_value != value) { 5288 LOG_WARN(BSL_LS_SOC_PHY, 5289 (BSL_META_U(unit, 5290 "Adjusted value %d does not match " 5291 "requested value %d\n"), cur_value, value)); 5292 } 5293 return SOC_E_NONE; 5294 } 5295 5296 STATIC int 5297 _phy_hl65_serdes_tune_margin_vertical_stop(int unit, soc_port_t port, 5298 int lane_num) 5299 { 5300 uint16 data; 5301 uint32 reg_addr; 5302 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 5303 5304 /* 5305 * Step 9: restore all slice offset control registers to 0 5306 */ 5307 LOG_INFO(BSL_LS_SOC_PHY, 5308 (BSL_META_U(unit, 5309 "Step 9: restore slice offset\n"))); 5310 reg_addr = 0x821b + (lane_num * 0x10); 5311 SOC_IF_ERROR_RETURN 5312 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 5313 5314 data &= ~( DSC1B0_DSC_ANA_CTRL1_P1_EVN_CTRL_MASK | 5315 DSC1B0_DSC_ANA_CTRL1_D_EVN_CTRL_MASK | 5316 DSC1B0_DSC_ANA_CTRL1_M1_EVN_CTRL_MASK); 5317 SOC_IF_ERROR_RETURN 5318 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 5319 5320 /* 5321 * Step 10: release and restore vga_write and dfe_write 5322 */ 5323 LOG_INFO(BSL_LS_SOC_PHY, 5324 (BSL_META_U(unit, 5325 "Step 10: release vga_write, dfe_write enable\n"))); 5326 reg_addr = 0x8215 + (lane_num * 0x10); 5327 SOC_IF_ERROR_RETURN 5328 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 5329 data &= ~(DSC1B0_DFE_VGA_CTRL1_DFE_WRITE_VAL_MASK | 5330 DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_VAL_MASK); 5331 SOC_IF_ERROR_RETURN 5332 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 5333 5334 data &= ~((DSC1B0_DFE_VGA_CTRL1_DFE_WRITE_EN_BITS << 5335 DSC1B0_DFE_VGA_CTRL1_DFE_WRITE_EN_SHIFT) | 5336 (DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_EN_BITS << 5337 DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_EN_SHIFT)); 5338 SOC_IF_ERROR_RETURN 5339 (HL65_REG_WRITE(unit,pc,0x0,reg_addr, data)); 5340 5341 return SOC_E_NONE; 5342 } 5343 5344 5345 STATIC int 5346 _phy_hl65_serdes_tune_margin_horizontal_mode_set(int unit, 5347 soc_port_t port, int lane_num, 5348 uint32 start, 5349 phy_hl65_dsc_cfg_t dsc_cfg) 5350 { 5351 if (start) { 5352 SOC_IF_ERROR_RETURN 5353 (_phy_hl65_serdes_tune_margin_horizontal_start(unit, port, 5354 lane_num, 5355 dsc_cfg)); 5356 } else { 5357 SOC_IF_ERROR_RETURN 5358 (_phy_hl65_serdes_tune_margin_horizontal_stop(unit, port, 5359 lane_num, 5360 dsc_cfg)); 5361 } 5362 return SOC_E_NONE; 5363 } 5364 5365 5366 STATIC int 5367 _phy_hl65_serdes_tune_margin_vertical_mode_set(int unit, 5368 soc_port_t port, 5369 int lane_num, 5370 uint32 start) 5371 { 5372 if (start) { 5373 SOC_IF_ERROR_RETURN 5374 (_phy_hl65_serdes_tune_margin_vertical_start(unit, port, 5375 lane_num)); 5376 } else { 5377 SOC_IF_ERROR_RETURN 5378 (_phy_hl65_serdes_tune_margin_vertical_stop(unit, port, 5379 lane_num)); 5380 } 5381 return SOC_E_NONE; 5382 5383 } 5384 5385 /* 5386 * Start/stop HC diag 5387 */ 5388 STATIC int 5389 _phy_hl65_control_serdes_tune_margin_mode_set(int unit, soc_port_t port, 5390 int lane_num, uint32 start) 5391 5392 { 5393 phy_hl65_dsc_cfg_t dsc_cfg; 5394 5395 /* Get DSC config */ 5396 SOC_IF_ERROR_RETURN 5397 (_phy_hl65_dsc_cfg_get(unit, port, lane_num, &dsc_cfg)); 5398 5399 switch (dsc_cfg) { 5400 case PHY_HL65_DSC_CFG_BR_CDR: 5401 /* vertical diag */ 5402 SOC_IF_ERROR_RETURN 5403 (_phy_hl65_serdes_tune_margin_vertical_mode_set(unit, port, 5404 lane_num, start)); 5405 break; 5406 case PHY_HL65_DSC_CFG_1X_OSR: 5407 case PHY_HL65_DSC_CFG_2X_OSR: 5408 /* horizontal diag */ 5409 SOC_IF_ERROR_RETURN 5410 (_phy_hl65_serdes_tune_margin_horizontal_mode_set(unit, port, 5411 lane_num, start, 5412 dsc_cfg)); 5413 break; 5414 default: 5415 LOG_WARN(BSL_LS_SOC_PHY, 5416 (BSL_META_U(unit, 5417 "Tune margin supported for 1XOSR, 2XOSR, BR CDR DSC"))); 5418 return SOC_E_UNAVAIL; 5419 } 5420 return SOC_E_NONE; 5421 } 5422 5423 /* 5424 * Check whether diag is running or not 5425 */ 5426 STATIC int 5427 _phy_hl65_control_serdes_tune_margin_mode_get(int unit, soc_port_t port, 5428 int lane_num, uint32 *value) 5429 5430 { 5431 5432 uint16 data; 5433 uint32 reg_addr; 5434 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 5435 5436 /* Read write enable */ 5437 reg_addr = 0x8215 + (lane_num * 0x10); 5438 SOC_IF_ERROR_RETURN 5439 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data)); 5440 5441 /* 5442 * Assumption here is that DFE and VGA write is only enabled 5443 * while running diag 5444 */ 5445 *value = ((data & DSC1B0_DFE_VGA_CTRL1_DFE_WRITE_EN_MASK) && 5446 (data & DSC1B0_DFE_VGA_CTRL1_VGA_WRITE_EN_MASK)) ? 1 : 0; 5447 5448 return SOC_E_NONE; 5449 } 5450 5451 5452 5453 /* 5454 * Return value depending on DSC configuration 5455 */ 5456 STATIC int 5457 _phy_hl65_control_serdes_tune_margin_value_get(int unit, soc_port_t port, 5458 int lane_num, uint32 *value) 5459 5460 { 5461 phy_hl65_dsc_cfg_t dsc_cfg; 5462 5463 /* Get DSC config */ 5464 SOC_IF_ERROR_RETURN 5465 (_phy_hl65_dsc_cfg_get(unit, port, lane_num, &dsc_cfg)); 5466 5467 switch (dsc_cfg) { 5468 case PHY_HL65_DSC_CFG_BR_CDR: 5469 /* vertical diag */ 5470 SOC_IF_ERROR_RETURN 5471 (_phy_hl65_serdes_tune_margin_vertical_value_get(unit, port, 5472 lane_num, 5473 value)); 5474 break; 5475 case PHY_HL65_DSC_CFG_1X_OSR: 5476 case PHY_HL65_DSC_CFG_2X_OSR: 5477 /* horizontal diag 1xOSR */ 5478 SOC_IF_ERROR_RETURN 5479 (_phy_hl65_serdes_tune_margin_horizontal_value_get(unit, port, 5480 lane_num, 5481 value)); 5482 break; 5483 default: 5484 LOG_WARN(BSL_LS_SOC_PHY, 5485 (BSL_META_U(unit, 5486 "Tune margin supported for 1XOSR, 2XOSR, " 5487 "BR CDR DSC\n"))); 5488 return SOC_E_UNAVAIL; 5489 } 5490 return SOC_E_NONE; 5491 } 5492 5493 5494 /* 5495 * Adjust to requested value 5496 */ 5497 STATIC int 5498 _phy_hl65_control_serdes_tune_margin_value_set(int unit, soc_port_t port, 5499 int lane_num, uint32 value) 5500 5501 { 5502 phy_hl65_dsc_cfg_t dsc_cfg; 5503 5504 /* Get DSC config */ 5505 SOC_IF_ERROR_RETURN 5506 (_phy_hl65_dsc_cfg_get(unit, port, lane_num, &dsc_cfg)); 5507 5508 switch (dsc_cfg) { 5509 case PHY_HL65_DSC_CFG_BR_CDR: 5510 /* vertical diag */ 5511 SOC_IF_ERROR_RETURN 5512 (_phy_hl65_serdes_tune_margin_vertical_value_set(unit, port, 5513 lane_num, value)); 5514 break; 5515 case PHY_HL65_DSC_CFG_1X_OSR: 5516 case PHY_HL65_DSC_CFG_2X_OSR: 5517 SOC_IF_ERROR_RETURN 5518 (_phy_hl65_serdes_tune_margin_horizontal_value_set(unit, port, 5519 lane_num, 5520 dsc_cfg, 5521 value)); 5522 break; 5523 default: 5524 LOG_WARN(BSL_LS_SOC_PHY, 5525 (BSL_META_U(unit, 5526 "Tune margin supported for 1XOSR, 2XOSR, BR CDR DSC"))); 5527 return SOC_E_UNAVAIL; 5528 } 5529 return SOC_E_NONE; 5530 } 5531 5532 /* 5533 * Function: 5534 * phy_hl65_control_set 5535 * Purpose: 5536 * Configure PHY device specific control fucntion. 5537 * Parameters: 5538 * unit - StrataSwitch unit #. 5539 * port - StrataSwitch port #. 5540 * type - Control to update 5541 * value - New setting for the control 5542 * Returns: 5543 * SOC_E_NONE 5544 */ 5545 STATIC int 5546 phy_hl65_control_set(int unit, soc_port_t port, 5547 soc_phy_control_t type, uint32 value) 5548 { 5549 int rv; 5550 phy_ctrl_t *pc; 5551 int i; 5552 /* coverity[mixed_enums] */ 5553 if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) { 5554 return SOC_E_PARAM; 5555 } 5556 5557 pc = INT_PHY_SW_STATE(unit, port); 5558 rv = SOC_E_UNAVAIL; 5559 switch(type) { 5560 case SOC_PHY_CONTROL_PREEMPHASIS: 5561 /* fall through */ 5562 case SOC_PHY_CONTROL_PREEMPHASIS_LANE0: 5563 /* fall through */ 5564 case SOC_PHY_CONTROL_PREEMPHASIS_LANE1: 5565 /* fall through */ 5566 case SOC_PHY_CONTROL_PREEMPHASIS_LANE2: 5567 /* fall through */ 5568 case SOC_PHY_CONTROL_PREEMPHASIS_LANE3: 5569 /* fall through */ 5570 case SOC_PHY_CONTROL_DRIVER_CURRENT: 5571 /* fall through */ 5572 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0: 5573 /* fall through */ 5574 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1: 5575 /* fall through */ 5576 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2: 5577 /* fall through */ 5578 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3: 5579 /* fall through */ 5580 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 5581 /* fall through */ 5582 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0: 5583 /* fall through */ 5584 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1: 5585 /* fall through */ 5586 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2: 5587 /* fall through */ 5588 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3: 5589 /* fall through */ 5590 case SOC_PHY_CONTROL_PRE_PREEMPHASIS: 5591 rv = _phy_hl65_control_tx_driver_set(unit, pc, type, value); 5592 break; 5593 case SOC_PHY_CONTROL_ENCODING: 5594 rv = _phy_hl65_control_encoding_set(unit, port, value); 5595 break; 5596 case SOC_PHY_CONTROL_SCRAMBLER: 5597 rv = _phy_hl65_control_scrambler_set(unit, port, value); 5598 break; 5599 case SOC_PHY_CONTROL_PRBS_POLYNOMIAL: 5600 rv = _phy_hl65_control_prbs_polynomial_set(unit, port, value); 5601 break; 5602 case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA: 5603 rv = _phy_hl65_control_prbs_tx_invert_data_set(unit, port, value); 5604 break; 5605 case SOC_PHY_CONTROL_PRBS_TX_ENABLE: 5606 rv = _phy_hl65_control_prbs_tx_enable_set(unit, port, value); 5607 break; 5608 case SOC_PHY_CONTROL_PRBS_RX_ENABLE: 5609 rv = _phy_hl65_control_prbs_rx_enable_set(unit, port, value); 5610 break; 5611 case SOC_PHY_CONTROL_SERDES_DRIVER_TUNE: 5612 if (PHY_INDEPENDENT_LANE_MODE(unit, port) || 5613 PHY_HC65_FABRIC_MODE(unit, port)) { 5614 rv = _phy_hl65_control_serdes_driver_tune_set(unit, port, 5615 pc->lane_num,value); 5616 } else { 5617 for (i = 0; i < HL65_NUM_LANES; i++) { 5618 rv = _phy_hl65_control_serdes_driver_tune_set(unit, port, 5619 i ,value); 5620 if (rv != SOC_E_NONE) { 5621 break; 5622 } 5623 } 5624 } 5625 break; 5626 case SOC_PHY_CONTROL_8B10B: 5627 rv = _phy_hl65_control_8b10b_set(unit, port, value); 5628 break; 5629 case SOC_PHY_CONTROL_64B66B: 5630 rv = _phy_hl65_control_64b66b_set(unit, port, value); 5631 break; 5632 case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT: 5633 rv = _phy_hl65_control_linkdown_transmit_set(unit, port, value); 5634 break; 5635 case SOC_PHY_CONTROL_SERDES_TUNE_MARGIN_MODE: 5636 if (PHY_HC65_FABRIC_MODE(unit, port)) { 5637 rv = _phy_hl65_control_serdes_tune_margin_mode_set(unit, port, 5638 pc->lane_num, 5639 value); 5640 } else { 5641 rv = SOC_E_UNAVAIL; 5642 } 5643 break; 5644 case SOC_PHY_CONTROL_SERDES_TUNE_MARGIN_VALUE: 5645 if (PHY_HC65_FABRIC_MODE(unit, port)) { 5646 rv = _phy_hl65_control_serdes_tune_margin_value_set(unit, port, 5647 pc->lane_num, 5648 value); 5649 } else { 5650 rv = SOC_E_UNAVAIL; 5651 } 5652 break; 5653 case SOC_PHY_CONTROL_PARALLEL_DETECTION: 5654 /* enable 1000X parallel detect */ 5655 SOC_IF_ERROR_RETURN 5656 (MODIFY_HL65_DIGITAL_CONTROL1000X2r(unit, pc, 5657 value? DIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK:0, 5658 DIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK)); 5659 rv = SOC_E_NONE; 5660 break; 5661 case SOC_PHY_CONTROL_EQUALIZER_BOOST: 5662 /* 5663 RX Equalizer Boost settings for stack ports 5664 So modifying register 0x1C(RX0/1/2/3_ANACONTROL) 5665 of block 0x8250 (reg 0x825C) 5666 */ 5667 SOC_IF_ERROR_RETURN 5668 (HL65_REG_WRITE(unit, pc, 0x0, 0x825C, value)); 5669 rv = SOC_E_NONE; 5670 break; 5671 default: 5672 rv = SOC_E_UNAVAIL; 5673 break; 5674 } 5675 return rv; 5676 } 5677 5678 /* 5679 * Function: 5680 * phy_hl65_control_get 5681 * Purpose: 5682 * Get current control settign of the PHY. 5683 * Parameters: 5684 * unit - StrataSwitch unit #. 5685 * port - StrataSwitch port #. 5686 * type - Control to update 5687 * value - (OUT)Current setting for the control 5688 * Returns: 5689 * SOC_E_NONE 5690 */ 5691 STATIC int 5692 phy_hl65_control_get(int unit, soc_port_t port, 5693 soc_phy_control_t type, uint32 *value) 5694 { 5695 int rv; 5696 phy_ctrl_t *pc; 5697 int i; 5698 uint16 data16 = 0; 5699 5700 if (NULL == value) { 5701 return SOC_E_PARAM; 5702 } 5703 /* coverity[mixed_enums] */ 5704 if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) { 5705 return SOC_E_PARAM; 5706 } 5707 5708 pc = INT_PHY_SW_STATE(unit, port); 5709 rv = SOC_E_UNAVAIL; 5710 switch(type) { 5711 case SOC_PHY_CONTROL_PREEMPHASIS_LANE0: 5712 /* fall through */ 5713 case SOC_PHY_CONTROL_PREEMPHASIS_LANE1: 5714 /* fall through */ 5715 case SOC_PHY_CONTROL_PREEMPHASIS_LANE2: 5716 /* fall through */ 5717 case SOC_PHY_CONTROL_PREEMPHASIS_LANE3: 5718 /* fall through */ 5719 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0: 5720 /* fall through */ 5721 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1: 5722 /* fall through */ 5723 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2: 5724 /* fall through */ 5725 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3: 5726 /* fall through */ 5727 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0: 5728 /* fall through */ 5729 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1: 5730 /* fall through */ 5731 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2: 5732 /* fall through */ 5733 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3: 5734 /* fall through */ 5735 case SOC_PHY_CONTROL_PREEMPHASIS: 5736 /* fall through */ 5737 case SOC_PHY_CONTROL_PRE_PREEMPHASIS: 5738 /* fall through */ 5739 case SOC_PHY_CONTROL_DRIVER_CURRENT: 5740 /* fall through */ 5741 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 5742 rv = _phy_hl65_control_tx_driver_get(unit, pc, type, value); 5743 break; 5744 case SOC_PHY_CONTROL_SCRAMBLER: 5745 rv = _phy_hl65_control_scrambler_get(unit, port, value); 5746 break; 5747 case SOC_PHY_CONTROL_PRBS_POLYNOMIAL: 5748 rv = _phy_hl65_control_prbs_polynomial_get(unit, port, value); 5749 break; 5750 case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA: 5751 rv = _phy_hl65_control_prbs_tx_invert_data_get(unit, port, value); 5752 break; 5753 case SOC_PHY_CONTROL_PRBS_TX_ENABLE: 5754 rv = _phy_hl65_control_prbs_tx_enable_get(unit, port, value); 5755 break; 5756 case SOC_PHY_CONTROL_PRBS_RX_ENABLE: 5757 rv = _phy_hl65_control_prbs_rx_enable_get(unit, port, value); 5758 break; 5759 case SOC_PHY_CONTROL_PRBS_RX_STATUS: 5760 rv = _phy_hl65_control_prbs_rx_status_get(unit, port, value); 5761 break; 5762 case SOC_PHY_CONTROL_SERDES_DRIVER_EQUALIZATION_TUNE_STATUS_FAR_END: 5763 if (PHY_INDEPENDENT_LANE_MODE(unit, port) || 5764 PHY_HC65_FABRIC_MODE(unit, port)) { 5765 rv = _phy_hl65_control_eq_tune_status_get(unit, port, 5766 pc->lane_num,value); 5767 } else { 5768 for (i = 0; i < HL65_NUM_LANES; i++) { 5769 rv = _phy_hl65_control_eq_tune_status_get(unit, port, 5770 i,value); 5771 if ((*value != TRUE) || (rv != SOC_E_NONE)) { 5772 break; 5773 } 5774 } 5775 } 5776 break; 5777 case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT: 5778 rv = _phy_hl65_control_linkdown_transmit_get(unit, port, value); 5779 break; 5780 case SOC_PHY_CONTROL_SERDES_TUNE_MARGIN_MODE: 5781 if (PHY_HC65_FABRIC_MODE(unit, port)) { 5782 rv = _phy_hl65_control_serdes_tune_margin_mode_get(unit, port, 5783 pc->lane_num, 5784 value); 5785 } else { 5786 rv = SOC_E_UNAVAIL; 5787 } 5788 break; 5789 case SOC_PHY_CONTROL_SERDES_TUNE_MARGIN_MAX: 5790 if (PHY_HC65_FABRIC_MODE(unit, port)) { 5791 rv = _phy_hl65_control_serdes_tune_margin_max_get(unit, port, 5792 pc->lane_num, 5793 value); 5794 } else { 5795 rv = SOC_E_UNAVAIL; 5796 } 5797 break; 5798 case SOC_PHY_CONTROL_SERDES_TUNE_MARGIN_VALUE: 5799 if (PHY_HC65_FABRIC_MODE(unit, port)) { 5800 rv = _phy_hl65_control_serdes_tune_margin_value_get(unit, port, 5801 pc->lane_num, 5802 value); 5803 } else { 5804 rv = SOC_E_UNAVAIL; 5805 } 5806 break; 5807 case SOC_PHY_CONTROL_PARALLEL_DETECTION: 5808 SOC_IF_ERROR_RETURN 5809 (READ_HL65_DIGITAL_CONTROL1000X2r(unit, pc,&data16)); 5810 *value = data16 & DIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK? 5811 TRUE: FALSE; 5812 rv = SOC_E_NONE; 5813 break; 5814 case SOC_PHY_CONTROL_EQUALIZER_BOOST: 5815 /* 5816 RX Equalizer Boost settings for stack ports 5817 Reading register 0x1C(RX0/1/2/3_ANACONTROL) 5818 of block 0x8250 (reg 0x825C) 5819 */ 5820 SOC_IF_ERROR_RETURN 5821 (HL65_REG_READ(unit, pc, 0x0, 0x825C, &data16)); 5822 *value = data16; 5823 rv = SOC_E_NONE; 5824 break; 5825 default: 5826 rv = SOC_E_UNAVAIL; 5827 break; 5828 } 5829 return rv; 5830 } 5831 5832 /* 5833 * Function: 5834 * phy_hl65_reg_read 5835 * Purpose: 5836 * Routine to read PHY register 5837 * Parameters: 5838 * uint - BCM unit number 5839 * pc - PHY state 5840 * flags - Flags which specify the register type 5841 * phy_reg_addr - Encoded register address 5842 * phy_data - (OUT) Value read from PHY register 5843 * Note: 5844 * This register read function is not thread safe. Higher level 5845 * function that calls this function must obtain a per port lock 5846 * to avoid overriding register page mapping between threads. 5847 */ 5848 STATIC int 5849 phy_hl65_reg_read(int unit, soc_port_t port, uint32 flags, 5850 uint32 phy_reg_addr, uint32 *phy_data) 5851 { 5852 uint16 data; /* Temporary holder for phy_data */ 5853 phy_ctrl_t *pc; /* PHY software state */ 5854 5855 pc = INT_PHY_SW_STATE(unit, port); 5856 5857 SOC_IF_ERROR_RETURN 5858 (phy_reg_aer_read(unit, pc, phy_reg_addr, &data)); 5859 5860 *phy_data = data; 5861 5862 return SOC_E_NONE; 5863 } 5864 5865 /* 5866 * Function: 5867 * phy_hl65_reg_write 5868 * Purpose: 5869 * Routine to write PHY register 5870 * Parameters: 5871 * uint - BCM unit number 5872 * pc - PHY state 5873 * flags - Flags which specify the register type 5874 * phy_reg_addr - Encoded register address 5875 * phy_data - Value write to PHY register 5876 * Note: 5877 * This register read function is not thread safe. Higher level 5878 * function that calls this function must obtain a per port lock 5879 * to avoid overriding register page mapping between threads. 5880 */ 5881 STATIC int 5882 phy_hl65_reg_write(int unit, soc_port_t port, uint32 flags, 5883 uint32 phy_reg_addr, uint32 phy_data) 5884 { 5885 uint16 data; /* Temporary holder for phy_data */ 5886 phy_ctrl_t *pc; /* PHY software state */ 5887 5888 pc = INT_PHY_SW_STATE(unit, port); 5889 5890 data = (uint16) (phy_data & 0x0000FFFF); 5891 5892 SOC_IF_ERROR_RETURN 5893 (phy_reg_aer_write(unit, pc, phy_reg_addr, data)); 5894 5895 return SOC_E_NONE; 5896 } 5897 5898 /* 5899 * Function: 5900 * phy_hl65_reg_modify 5901 * Purpose: 5902 * Routine to write PHY register 5903 * Parameters: 5904 * uint - BCM unit number 5905 * pc - PHY state 5906 * flags - Flags which specify the register type 5907 * phy_reg_addr - Encoded register address 5908 * phy_mo_data - New value for the bits specified in phy_mo_mask 5909 * phy_mo_mask - Bit mask to modify 5910 * Note: 5911 * This register read function is not thread safe. Higher level 5912 * function that calls this function must obtain a per port lock 5913 * to avoid overriding register page mapping between threads. 5914 */ 5915 STATIC int 5916 phy_hl65_reg_modify(int unit, soc_port_t port, uint32 flags, 5917 uint32 phy_reg_addr, uint32 phy_data, 5918 uint32 phy_data_mask) 5919 { 5920 uint16 data; /* Temporary holder for phy_data */ 5921 uint16 mask; 5922 phy_ctrl_t *pc; /* PHY software state */ 5923 5924 pc = INT_PHY_SW_STATE(unit, port); 5925 5926 data = (uint16) (phy_data & 0x0000FFFF); 5927 mask = (uint16) (phy_data_mask & 0x0000FFFF); 5928 5929 SOC_IF_ERROR_RETURN 5930 (phy_reg_aer_modify(unit, pc, phy_reg_addr, data, mask)); 5931 5932 return SOC_E_NONE; 5933 } 5934 5935 STATIC int 5936 phy_hl65_probe(int unit, phy_ctrl_t *pc) 5937 { 5938 uint16 serdes_id0; 5939 5940 SOC_IF_ERROR_RETURN 5941 (READ_HL65_TEST_SERDESID0r(unit, pc, &serdes_id0)); 5942 5943 if (!(((serdes_id0 & TEST_SERDESID0_MODEL_NUMBER_MASK) == 5944 SERDES_ID0_MODEL_NUMBER_HYPERLITE) || 5945 ((serdes_id0 & TEST_SERDESID0_MODEL_NUMBER_MASK) == 5946 SERDES_ID0_MODEL_NUMBER_HYPERCORE))) { 5947 return SOC_E_NOT_FOUND; 5948 } 5949 5950 if ((serdes_id0 & TEST_SERDESID0_TECH_PROC_MASK) != 5951 SERDES_ID0_TECH_PROC_65NM) { 5952 return SOC_E_NOT_FOUND; 5953 } 5954 5955 return SOC_E_NONE; 5956 } 5957 5958 STATIC int 5959 phy_hl65_notify(int unit, soc_port_t port, 5960 soc_phy_event_t event, uint32 value) 5961 { 5962 int rv; 5963 5964 if (event >= phyEventCount) { 5965 return SOC_E_PARAM; 5966 } 5967 5968 rv = SOC_E_NONE; 5969 switch(event) { 5970 case phyEventInterface: 5971 rv = (_phy_hl65_notify_interface(unit, port, value)); 5972 break; 5973 case phyEventDuplex: 5974 rv = (_phy_hl65_notify_duplex(unit, port, value)); 5975 break; 5976 case phyEventSpeed: 5977 rv = (_phy_hl65_notify_speed(unit, port, value)); 5978 break; 5979 case phyEventStop: 5980 rv = (_phy_hl65_notify_stop(unit, port, value)); 5981 break; 5982 case phyEventResume: 5983 rv = (_phy_hl65_notify_resume(unit, port, value)); 5984 break; 5985 case phyEventAutoneg: 5986 rv = (phy_hl65_an_set(unit, port, value)); 5987 break; 5988 case phyEventTxFifoReset: 5989 rv = (_phy_hl65_tx_fifo_reset(unit, port, value)); 5990 break; 5991 default: 5992 rv = SOC_E_UNAVAIL; 5993 } 5994 5995 return rv; 5996 } 5997 5998 STATIC int 5999 phy_hl65_linkup_evt (int unit, soc_port_t port) 6000 { 6001 phy_ctrl_t *pc; 6002 int an,an_done,speed; 6003 6004 pc = INT_PHY_SW_STATE(unit, port); 6005 6006 phy_hl65_an_get(unit,port,&an,&an_done); 6007 6008 LOG_INFO(BSL_LS_SOC_PHY, 6009 (BSL_META_U(unit, 6010 "phy_hl65_linkup_evt: " 6011 "u=%d p=%d an=%d\n"), unit, port, an)); 6012 /* check if the link is established due to the auto-negotiation. If so, 6013 * configure the tx half rate and DSP related registers. These settings 6014 * can only be done after the autoneg speed is determined. 6015 */ 6016 if (an == TRUE) { 6017 6018 /* check the autoneg speed */ 6019 phy_hl65_speed_get(unit,port,&speed); 6020 6021 /* set tx half rate. */ 6022 SOC_IF_ERROR_RETURN 6023 (_phy_hl65_half_rate_set(unit,port,speed)); 6024 6025 if (!PHY_INDEPENDENT_LANE_MODE(unit, port)) { 6026 6027 /* configure DSP related registers based on speed */ 6028 _phy_hl65_dsp_cfg(unit,pc,speed); 6029 } 6030 6031 /* for speed above 10G, txcko_div must be cleared */ 6032 if (speed > 10000) { 6033 SOC_IF_ERROR_RETURN 6034 (MODIFY_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, 6035 0, 6036 XGXSBLK0_XGXSCONTROL_TXCKO_DIV_MASK)); 6037 } else { 6038 SOC_IF_ERROR_RETURN 6039 (MODIFY_HL65_XGXSBLK0_XGXSCONTROLr(unit, pc, 6040 XGXSBLK0_XGXSCONTROL_TXCKO_DIV_MASK, 6041 XGXSBLK0_XGXSCONTROL_TXCKO_DIV_MASK)); 6042 } 6043 } 6044 return SOC_E_NONE; 6045 } 6046 6047 STATIC int 6048 phy_hl65_linkdown_evt (int unit, soc_port_t port) 6049 { 6050 phy_ctrl_t *pc; 6051 int an,an_done; 6052 uint16 dfe_brcdr; 6053 6054 pc = INT_PHY_SW_STATE(unit, port); 6055 6056 phy_hl65_an_get(unit,port,&an,&an_done); 6057 6058 LOG_INFO(BSL_LS_SOC_PHY, 6059 (BSL_META_U(unit, 6060 "phy_hl65_linkdown_evt: " 6061 "u=%d p=%d an=%d\n"), unit, port, an)); 6062 6063 /* The DSP related registers must be set to the default 6064 * values before the autoneg starts. 6065 */ 6066 if (an == TRUE) { 6067 if (!PHY_INDEPENDENT_LANE_MODE(unit, port)) { 6068 6069 /* check if DFE/BR CDR(20G speed). if so, restart AN */ 6070 SOC_IF_ERROR_RETURN 6071 (READ_HL65_DSC2BB_DSC_MISC_CTRL0r(unit, pc, &dfe_brcdr)); 6072 6073 if ((dfe_brcdr == HL65_A0A1_DSC_DFE_BRCDR) || 6074 (dfe_brcdr == HL65_B0C0_DSC_DFE_BRCDR) ) { 6075 phy_hl65_an_set(unit,port,TRUE); 6076 } 6077 } 6078 } 6079 return SOC_E_NONE; 6080 } 6081 6082 /* 6083 * Function: 6084 * phy_hl65_duplex_set 6085 * Purpose: 6086 * Set the current duplex mode (forced). 6087 * Parameters: 6088 * unit - StrataSwitch unit #. 6089 * port - StrataSwitch port #. 6090 * duplex - Boolean, true indicates full duplex, false indicates half. 6091 * Returns: 6092 * SOC_E_XXX 6093 */ 6094 6095 STATIC int 6096 phy_hl65_duplex_set(int unit, soc_port_t port, int duplex) 6097 { 6098 uint16 data16; 6099 phy_ctrl_t *pc; 6100 uint16 serdes_id0; 6101 int duplex_value; 6102 6103 if (!PHY_INDEPENDENT_LANE_MODE(unit, port)) { 6104 return SOC_E_NONE; 6105 } 6106 6107 pc = INT_PHY_SW_STATE(unit, port); 6108 6109 SOC_IF_ERROR_RETURN 6110 (READ_HL65_DIGITAL_STATUS1000X1r(unit, pc, &data16)); 6111 6112 if (!(data16 & DIGITAL_STATUS1000X1_SGMII_MODE_MASK)) { 6113 6114 SOC_IF_ERROR_RETURN 6115 (READ_HL65_TEST_SERDESID0r(unit, pc, &serdes_id0)); 6116 6117 /* 1000X fiber mode, 100fx */ 6118 6119 if ((serdes_id0 & TEST_SERDESID0_REV_LETTER_MASK) > 0) { 6120 duplex_value = duplex? FX100_CONTROL1_FULL_DUPLEX_MASK:0; 6121 SOC_IF_ERROR_RETURN 6122 (MODIFY_HL65_FX100_CONTROL1r(unit,pc, 6123 duplex_value, 6124 FX100_CONTROL1_FULL_DUPLEX_MASK)); 6125 } 6126 /* 1000X should always be full duplex */ 6127 duplex = TRUE; 6128 } 6129 6130 data16 = duplex? MII_CTRL_FD: 0; 6131 6132 /* program the duplex setting */ 6133 SOC_IF_ERROR_RETURN 6134 (MODIFY_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, data16,MII_CTRL_FD)); 6135 6136 return SOC_E_NONE; 6137 } 6138 6139 STATIC int 6140 phy_hl65_duplex_get(int unit, soc_port_t port, int *duplex) 6141 { 6142 uint16 reg0_16; 6143 uint16 mii_ctrl; 6144 phy_ctrl_t *pc; 6145 6146 pc = INT_PHY_SW_STATE(unit, port); 6147 6148 if (!PHY_INDEPENDENT_LANE_MODE(unit, port)) { 6149 *duplex = TRUE; 6150 return SOC_E_NONE; 6151 } 6152 6153 SOC_IF_ERROR_RETURN 6154 (READ_HL65_DIGITAL_STATUS1000X1r(unit, pc, ®0_16)); 6155 6156 /* default to fiber mode duplex */ 6157 *duplex = (reg0_16 & DIGITAL_STATUS1000X1_DUPLEX_STATUS_MASK)? 6158 TRUE:FALSE; 6159 6160 if (reg0_16 & DIGITAL_STATUS1000X1_SGMII_MODE_MASK) { 6161 6162 /* retrieve the duplex setting in SGMII mode */ 6163 SOC_IF_ERROR_RETURN 6164 (READ_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, &mii_ctrl)); 6165 6166 if (mii_ctrl & MII_CTRL_AE) { 6167 SOC_IF_ERROR_RETURN 6168 (READ_HL65_COMBO_IEEE0_AUTONEGLPABILr(unit,pc,®0_16)); 6169 6170 /* make sure link partner is also in SGMII mode 6171 * otherwise fall through to use the FD bit in MII_CTRL reg 6172 */ 6173 if (reg0_16 & MII_ANP_SGMII_MODE) { 6174 if (reg0_16 & MII_ANP_SGMII_FD) { 6175 *duplex = TRUE; 6176 } else { 6177 *duplex = FALSE; 6178 } 6179 return SOC_E_NONE; 6180 } 6181 } 6182 *duplex = (mii_ctrl & MII_CTRL_FD) ? TRUE : FALSE; 6183 } 6184 6185 return SOC_E_NONE; 6186 } 6187 6188 /* 6189 * Function: 6190 * phy_hl65_diag_ctrl 6191 * Purpose: 6192 * Parameters: 6193 * unit - StrataSwitch unit #. 6194 * port - StrataSwitch port #. 6195 * Returns: 6196 * SOC_E_NONE 6197 * Notes: 6198 */ 6199 6200 STATIC int 6201 phy_hl65_diag_ctrl( 6202 int unit, /* unit */ 6203 soc_port_t port, /* port */ 6204 uint32 inst, /* the specific device block the control action directs to */ 6205 int op_type, /* operation types: read,write or command sequence */ 6206 int op_cmd, /* command code */ 6207 void *arg) /* command argument based on op_type/op_cmd */ 6208 { 6209 int rv; 6210 6211 rv = SOC_E_NONE; 6212 6213 switch(op_cmd) { 6214 6215 case PHY_DIAG_CTRL_DSC: 6216 LOG_INFO(BSL_LS_SOC_PHY, 6217 (BSL_META_U(unit, 6218 "phy_hl65_diag_ctrl: " 6219 "u=%d p=%d PHY_DIAG_CTRL_DSC 0x%x\n"), 6220 unit, port, PHY_DIAG_CTRL_DSC)); 6221 (void)phy_hl65_uc_status_dump(unit, port); 6222 break; 6223 6224 default: 6225 if (op_type == PHY_DIAG_CTRL_SET) { 6226 rv = phy_hl65_control_set(unit, port, op_cmd, PTR_TO_INT(arg)); 6227 } else if (op_type == PHY_DIAG_CTRL_GET) { 6228 rv = phy_hl65_control_get(unit, port, op_cmd, (uint32 *)arg); 6229 } 6230 break; 6231 } 6232 return rv; 6233 } 6234 6235 #define HL65_UC_DEBUG 6236 #ifdef HL65_UC_DEBUG 6237 typedef struct { 6238 int postc_metric; 6239 int pf_ctrl; 6240 int vga_sum; 6241 int dfe_bin; 6242 int integ_reg; 6243 int integ_reg_xfer; 6244 int clk90_offset; 6245 int slicer_target; 6246 int offset_pe; 6247 int offset_ze; 6248 int offset_me; 6249 int offset_po; 6250 int offset_zo; 6251 int offset_mo; 6252 int tx_os; 6253 int tx_br; 6254 } HL65_DESC; 6255 #define LANE0_ACCESS 1 6256 #define LANE1_ACCESS 2 6257 #define LANE2_ACCESS 3 6258 #define LANE3_ACCESS 4 6259 #define MAX_LANES 4 6260 static HL65_DESC hl65_desc; 6261 6262 int 6263 phy_hl65_uc_status_dump(int unit, soc_port_t port) 6264 { 6265 phy_ctrl_t *pc; 6266 HL65_DESC * pDesc; 6267 int lane_num; 6268 uint16 data16; 6269 int regval, reg_addr; 6270 uint8 print_menu = TRUE; 6271 6272 pc = INT_PHY_SW_STATE(unit, port); 6273 6274 for (lane_num = 0; lane_num < MAX_LANES; lane_num++) { 6275 sal_memset((char *)&hl65_desc, 0, (sizeof(HL65_DESC))); 6276 pDesc = &hl65_desc; 6277 6278 /* integ_reg(lane) = rd22_integ_reg (phy, lane) */ 6279 reg_addr = 0x82b0 + (lane_num * 0x10); 6280 SOC_IF_ERROR_RETURN 6281 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data16)); 6282 regval = data16; 6283 regval &= 65535; 6284 if (regval >= 32768) { 6285 regval -=65536; 6286 } 6287 regval /= 84; 6288 pDesc->integ_reg = regval; 6289 6290 /* integ_reg_xfer(lane) = rd22_integ_reg_xfer (phy, lane) */ 6291 reg_addr = 0x82b1 + (lane_num * 0x10); 6292 SOC_IF_ERROR_RETURN 6293 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data16)); 6294 regval = data16; 6295 regval &= 65535; 6296 if (regval >= 32768) { 6297 regval -=65536; 6298 } 6299 regval /= 84; 6300 pDesc->integ_reg_xfer = regval; 6301 6302 /* clk90_offset(lane) = rd22_clk90_phase_offset (phy, lane) */ 6303 reg_addr = 0x82b3 + (lane_num * 0x10); 6304 SOC_IF_ERROR_RETURN 6305 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data16)); 6306 regval = data16; 6307 regval /= 128; 6308 regval &= 127; 6309 pDesc->clk90_offset = regval; 6310 6311 /* pf_ctrl(lane) = rd22_pf_ctrl (phy, lane) */ 6312 reg_addr = 0x82bb + (lane_num * 0x10); 6313 SOC_IF_ERROR_RETURN 6314 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data16)); 6315 regval = data16; 6316 regval &= 0x7; 6317 pDesc->pf_ctrl = regval; 6318 6319 /* slicer_target(lane) = ((25*rd22_rx_thresh_sel (phy, lane)) + 125) */ 6320 reg_addr = 0x821c + (lane_num * 0x10); 6321 SOC_IF_ERROR_RETURN 6322 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data16)); 6323 regval = data16; 6324 regval /= 32; 6325 regval &= 3; 6326 pDesc->slicer_target = regval * 25 + 125; 6327 6328 /* vga_sum(lane) = rd22_vga_sum (phy, lane) */ 6329 reg_addr = 0x82b5 + (lane_num * 0x10); 6330 SOC_IF_ERROR_RETURN 6331 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data16)); 6332 regval = data16; 6333 regval /= 64; 6334 regval &= 0x1f; 6335 pDesc->vga_sum = regval; 6336 6337 /* dfe_bin(lane) = rd22_dfe_tap_bin (phy, lane) */ 6338 reg_addr = 0x82b5 + (lane_num * 0x10); 6339 SOC_IF_ERROR_RETURN 6340 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data16)); 6341 regval = data16; 6342 regval &= 0x3f; 6343 pDesc->dfe_bin = regval; 6344 6345 /* postc_metric(lane) = rd22_postc_metric (phy, lane)*/ 6346 reg_addr = 0x82b8 + (lane_num * 0x10); 6347 SOC_IF_ERROR_RETURN 6348 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data16)); 6349 regval = data16; 6350 regval &= 0x7ff; 6351 if (regval >=1024) { 6352 regval -= 2048; 6353 } 6354 pDesc->postc_metric = regval; 6355 6356 /* offset_mo(lane) = rd22_slicer_offset_mo (phy, lane) */ 6357 reg_addr = 0x82b9 + (lane_num * 0x10); 6358 SOC_IF_ERROR_RETURN 6359 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data16)); 6360 regval = data16; 6361 regval &= 0x1f; 6362 if(regval > 16) { 6363 regval -= 32; 6364 } 6365 pDesc->offset_mo = regval; 6366 6367 /* offset_zo(lane) = rd22_slicer_offset_zo (phy, lane) */ 6368 regval = data16; 6369 regval /= 32; 6370 regval &= 0x1f; 6371 if(regval > 16) { 6372 regval -= 32; 6373 } 6374 pDesc->offset_zo = regval; 6375 6376 /* offset_po(lane) = rd22_slicer_offset_po (phy, lane) */ 6377 regval = data16; 6378 regval /= 1024; 6379 regval &= 0x1f; 6380 if(regval > 16) { 6381 regval -= 32; 6382 } 6383 pDesc->offset_po = regval; 6384 6385 /* offset_me(lane) = rd22_slicer_offset_me (phy, lane) */ 6386 reg_addr = 0x82ba + (lane_num * 0x10); 6387 SOC_IF_ERROR_RETURN 6388 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data16)); 6389 regval = data16; 6390 regval &= 0x1f; 6391 if(regval > 16) { 6392 regval -= 32; 6393 } 6394 pDesc->offset_me = regval; 6395 6396 /* offset_ze(lane) = rd22_slicer_offset_ze (phy, lane) */ 6397 regval = data16; 6398 regval /= 32; 6399 regval &= 0x1f; 6400 if(regval > 16) { 6401 regval -= 32; 6402 } 6403 pDesc->offset_ze = regval; 6404 6405 /* offset_pe(lane) = rd22_slicer_offset_pe (phy, lane) */ 6406 regval = data16; 6407 regval /= 1024; 6408 regval &= 0x1f; 6409 if(regval > 16) { 6410 regval -= 32; 6411 } 6412 pDesc->offset_pe = regval; 6413 6414 reg_addr = 0x8067 + (lane_num * 0x10); 6415 SOC_IF_ERROR_RETURN 6416 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data16)); 6417 regval = data16; 6418 pDesc->tx_os = regval; 6419 6420 reg_addr = 0x8068 + (lane_num * 0x10); 6421 SOC_IF_ERROR_RETURN 6422 (HL65_REG_READ(unit,pc,0x0,reg_addr, &data16)); 6423 regval = data16; 6424 pDesc->tx_br = regval; 6425 6426 SOC_IF_ERROR_RETURN 6427 (READ_HL65_TXPLL_ANAPLLASTATUS1r(unit, pc, &data16)); 6428 /* regval = (data16 >> 8) & 0xf; */ 6429 6430 if( print_menu == TRUE) { 6431 LOG_CLI((BSL_META_U(unit, 6432 "\n\nDSC parameters for port %d\n\n"), port)); 6433 LOG_CLI((BSL_META_U(unit, 6434 "PLL Range: %d\n\n"),data16)); 6435 6436 LOG_CLI((BSL_META_U(unit, 6437 "LN PPM PPM_XFR clk90_ofs " 6438 "PF SL_TRGT VGA DFE " 6439 "TXDIR_OS TXDR_BR MTRC PE " 6440 "ZE ME PO ZO " 6441 "MO\n"))); 6442 print_menu = FALSE; 6443 } 6444 LOG_CLI((BSL_META_U(unit, 6445 "%02d %04d %07d %09d " 6446 "%04d %07d %04d %04d " 6447 "0x%06x 0x%06x %04d %04d " 6448 "%04d %2d %3d %3d " 6449 "%2d\n"), 6450 lane_num, pDesc->integ_reg, pDesc->integ_reg_xfer, 6451 pDesc->clk90_offset, pDesc->pf_ctrl, 6452 pDesc->slicer_target, pDesc->vga_sum, pDesc->dfe_bin, 6453 pDesc->tx_os, pDesc->tx_br, 6454 pDesc->postc_metric, pDesc->offset_pe, 6455 pDesc->offset_ze, pDesc->offset_me, 6456 pDesc->offset_po, pDesc->offset_zo, 6457 pDesc->offset_mo)); 6458 6459 } 6460 6461 return SOC_E_NONE; 6462 } 6463 #endif 6464 6465 /* 6466 * Variable: 6467 * phy_hl65_drv 6468 * Purpose: 6469 * Phy Driver for 10G (XAUI x 4) Serdes PHY. 6470 */ 6471 phy_driver_t phy_hl65_hg = { 6472 /* .drv_name = */ "HyperLite PHY Driver", 6473 /* .pd_init = */ phy_hl65_init, 6474 /* .pd_reset = */ phy_null_reset, 6475 /* .pd_link_get = */ phy_hl65_link_get, 6476 /* .pd_enable_set = */ phy_hl65_enable_set, 6477 /* .pd_enable_get = */ phy_hl65_enable_get, 6478 /* .pd_duplex_set = */ phy_hl65_duplex_set, 6479 /* .pd_duplex_get = */ phy_hl65_duplex_get, 6480 /* .pd_speed_set = */ phy_hl65_speed_set, 6481 /* .pd_speed_get = */ phy_hl65_speed_get, 6482 /* .pd_master_set = */ phy_null_set, 6483 /* .pd_master_get = */ phy_null_zero_get, 6484 /* .pd_an_set = */ phy_hl65_an_set, 6485 /* .pd_an_get = */ phy_hl65_an_get, 6486 /* .pd_adv_local_set = */ NULL, /* Deprecated */ 6487 /* .pd_adv_local_get = */ NULL, /* Deprecated */ 6488 /* .pd_adv_remote_get = */ NULL, /* Deprecated */ 6489 /* .pd_lb_set = */ phy_hl65_lb_set, 6490 /* .pd_lb_get = */ phy_hl65_lb_get, 6491 /* .pd_interface_set = */ phy_hl65_interface_set, 6492 /* .pd_interface_get = */ phy_hl65_interface_get, 6493 /* .pd_ability = */ NULL, /* Deprecated */ 6494 /* .pd_linkup_evt = */ phy_hl65_linkup_evt, 6495 /* .pd_linkdn_evt = */ phy_hl65_linkdown_evt, 6496 /* .pd_mdix_set = */ phy_null_mdix_set, 6497 /* .pd_mdix_get = */ phy_null_mdix_get, 6498 /* .pd_mdix_status_get = */ phy_null_mdix_status_get, 6499 /* .pd_medium_config_set = */ NULL, 6500 /* .pd_medium_config_get = */ NULL, 6501 /* .pd_medium_get = */ phy_null_medium_get, 6502 /* .pd_cable_diag = */ NULL, 6503 /* .pd_link_change = */ NULL, 6504 /* .pd_control_set = */ phy_hl65_control_set, 6505 /* .pd_control_get = */ phy_hl65_control_get, 6506 /* .pd_reg_read = */ phy_hl65_reg_read, 6507 /* .pd_reg_write = */ phy_hl65_reg_write, 6508 /* .pd_reg_modify = */ phy_hl65_reg_modify, 6509 /* .pd_notify = */ phy_hl65_notify, 6510 /* .pd_probe = */ phy_hl65_probe, 6511 /* .pd_ability_advert_set = */ phy_hl65_ability_advert_set, 6512 /* .pd_ability_advert_get = */ phy_hl65_ability_advert_get, 6513 /* .pd_ability_remote_get = */ phy_hl65_ability_remote_get, 6514 /* .pd_ability_local_get = */ phy_hl65_ability_local_get, 6515 /* .pd_firmware_set = */ NULL, 6516 /* .pdpd_timesync_config_set = */ NULL, 6517 /* .pdpd_timesync_config_get = */ NULL, 6518 /* .pdpd_timesync_control_set = */ NULL, 6519 /* .pdpd_timesync_control_set = */ NULL, 6520 /* .pd_diag_ctrl = */ phy_hl65_diag_ctrl 6521 }; 6522 6523 /*********************************************************************** 6524 * 6525 * PASS-THROUGH NOTIFY ROUTINES 6526 */ 6527 6528 /* 6529 * Function: 6530 * _phy_hl65_notify_duplex 6531 * Purpose: 6532 * Program duplex if (and only if) serdeshl65 is an intermediate PHY. 6533 * Parameters: 6534 * unit - StrataSwitch unit #. 6535 * port - StrataSwitch port #. 6536 * duplex - Boolean, TRUE indicates full duplex, FALSE 6537 * indicates half. 6538 * Returns: 6539 * SOC_E_XXX 6540 * Notes: 6541 * If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to 6542 * talk directly to an external fiber module. 6543 * 6544 * If PHY_FLAGS_FIBER is clear, the PHY is being used in 6545 * pass-through mode to talk to an external SGMII PHY. 6546 * 6547 * When used in pass-through mode, autoneg must be turned off and 6548 * the speed/duplex forced to match that of the external PHY. 6549 */ 6550 6551 STATIC int 6552 _phy_hl65_notify_duplex(int unit, soc_port_t port, uint32 duplex) 6553 { 6554 int fiber; 6555 uint16 mii_ctrl; 6556 phy_ctrl_t *pc; 6557 6558 fiber = PHY_FIBER_MODE(unit, port); 6559 pc = INT_PHY_SW_STATE(unit, port); 6560 LOG_INFO(BSL_LS_SOC_PHY, 6561 (BSL_META_U(unit, 6562 "_phy_hl65_notify_duplex: " 6563 "u=%d p=%d duplex=%d fiber=%d\n"), 6564 unit, port, duplex, fiber)); 6565 6566 if (SAL_BOOT_SIMULATION) { 6567 return SOC_E_NONE; 6568 } 6569 6570 if (fiber) { 6571 SOC_IF_ERROR_RETURN 6572 (MODIFY_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, 6573 MII_CTRL_FD, MII_CTRL_FD)); 6574 return SOC_E_NONE; 6575 } 6576 6577 /* Put SERDES PHY in reset */ 6578 6579 SOC_IF_ERROR_RETURN 6580 (_phy_hl65_notify_stop(unit, port, PHY_STOP_DUPLEX_CHG)); 6581 6582 /* Update duplexity */ 6583 mii_ctrl = (duplex) ? MII_CTRL_FD : 0; 6584 SOC_IF_ERROR_RETURN 6585 (MODIFY_HL65_COMBO_IEEE0_MIICNTLr(unit, pc, mii_ctrl, MII_CTRL_FD)); 6586 6587 /* Take SERDES PHY out of reset */ 6588 SOC_IF_ERROR_RETURN 6589 (_phy_hl65_notify_resume(unit, port, PHY_STOP_DUPLEX_CHG)); 6590 6591 /* Autonegotiation must be turned off to talk to external PHY if 6592 * SGMII autoneg is not enabled. 6593 */ 6594 if (!PHY_SGMII_AUTONEG_MODE(unit, port)) { 6595 SOC_IF_ERROR_RETURN 6596 (phy_hl65_an_set(unit, port, FALSE)); 6597 } 6598 return SOC_E_NONE; 6599 } 6600 6601 /* 6602 * Function: 6603 * _phy_hl65_notify_speed 6604 * Purpose: 6605 * Program duplex if (and only if) serdeshl65 is an intermediate PHY. 6606 * Parameters: 6607 * unit - StrataSwitch unit #. 6608 * port - StrataSwitch port #. 6609 * speed - Speed to program. 6610 * Returns: 6611 * SOC_E_XXX 6612 * Notes: 6613 * If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to 6614 * talk directly to an external fiber module. 6615 * 6616 * If PHY_FLAGS_FIBER is clear, the PHY is being used in 6617 * pass-through mode to talk to an external SGMII PHY. 6618 * 6619 * When used in pass-through mode, autoneg must be turned off and 6620 * the speed/duplex forced to match that of the external PHY. 6621 */ 6622 6623 STATIC int 6624 _phy_hl65_notify_speed(int unit, soc_port_t port, uint32 speed) 6625 { 6626 int fiber; 6627 uint16 fiber_status; 6628 phy_ctrl_t *pc; 6629 6630 pc = INT_PHY_SW_STATE(unit, port); 6631 fiber = PHY_FIBER_MODE(unit, port); 6632 6633 LOG_INFO(BSL_LS_SOC_PHY, 6634 (BSL_META_U(unit, 6635 "_phy_hl65_notify_speed: " 6636 "u=%d p=%d speed=%d fiber=%d\n"), 6637 unit, port, speed, fiber)); 6638 6639 if (SAL_BOOT_SIMULATION) { 6640 return SOC_E_NONE; 6641 } 6642 6643 SOC_IF_ERROR_RETURN 6644 (READ_HL65_DIGITAL_STATUS1000X1r(unit, pc, &fiber_status)); 6645 6646 /* Put SERDES PHY in reset */ 6647 SOC_IF_ERROR_RETURN 6648 (_phy_hl65_notify_stop(unit, port, PHY_STOP_SPEED_CHG)); 6649 6650 /* Update speed */ 6651 SOC_IF_ERROR_RETURN 6652 (phy_hl65_speed_set(unit, port, speed)); 6653 6654 /* Take SERDES PHY out of reset */ 6655 SOC_IF_ERROR_RETURN 6656 (_phy_hl65_notify_resume(unit, port, PHY_STOP_SPEED_CHG)); 6657 6658 /* Autonegotiation must be turned off to talk to external PHY */ 6659 if (!PHY_SGMII_AUTONEG_MODE(unit, port) && PHY_EXTERNAL_MODE(unit, port)) { 6660 SOC_IF_ERROR_RETURN 6661 (phy_hl65_an_set(unit, port, FALSE)); 6662 } 6663 6664 return SOC_E_NONE; 6665 } 6666 6667 /* 6668 * Function: 6669 * _phy_hl65_stop 6670 * Purpose: 6671 * Put serdeshl65 SERDES in or out of reset depending on conditions 6672 */ 6673 6674 STATIC int 6675 _phy_hl65_stop(int unit, soc_port_t port) 6676 { 6677 int stop, copper; 6678 uint16 mask16,data16; 6679 phy_ctrl_t *pc; 6680 int mdio_addr_share = FALSE; 6681 6682 if (!PHY_INDEPENDENT_LANE_MODE(unit, port)) { 6683 return SOC_E_NONE; 6684 } 6685 6686 pc = INT_PHY_SW_STATE(unit, port); 6687 6688 copper = (pc->stop & 6689 PHY_STOP_COPPER) != 0; 6690 6691 stop = ((pc->stop & 6692 (PHY_STOP_PHY_DIS | 6693 PHY_STOP_DRAIN)) != 0 || 6694 (copper && 6695 (pc->stop & 6696 (PHY_STOP_MAC_DIS | 6697 PHY_STOP_DUPLEX_CHG | 6698 PHY_STOP_SPEED_CHG)) != 0)); 6699 6700 LOG_INFO(BSL_LS_SOC_PHY, 6701 (BSL_META_U(unit, 6702 "phy_hl65_stop: u=%d p=%d copper=%d stop=%d flg=0x%x\n"), 6703 unit, port, copper, stop, 6704 pc->stop)); 6705 6706 /* check for dxgxs ports. Don't disable RX lane, we're using rx_ck clock 6707 * for MAC Rx block registers in 10G mode 6708 */ 6709 mask16 = (1 << pc->lane_num); /* rx lane */ 6710 if (IS_HG_PORT(unit, port) || IS_XE_PORT(unit,port)) { 6711 mask16 <<= 4; /* assign tx lane */ 6712 } else { 6713 mask16 |= (mask16 << 4); /* add tx lane */ 6714 } 6715 6716 if (stop) { 6717 mask16 |= 0x800; 6718 data16 = mask16; 6719 } else { 6720 data16 = 0; 6721 } 6722 6723 /* point to lane0 mdio addressing. 6724 * This register can only be accessed from lane0. 6725 */ 6726 if (pc->flags & PHYCTRL_MDIO_ADDR_SHARE) { 6727 mdio_addr_share = TRUE; 6728 pc->flags &= ~PHYCTRL_MDIO_ADDR_SHARE; 6729 } else { 6730 pc->phy_id -= pc->lane_num; 6731 } 6732 6733 SOC_IF_ERROR_RETURN 6734 (MODIFY_HL65_XGXSBLK1_LANECTRL3r(unit,pc,data16,mask16)); 6735 6736 /* restore the previous MDIO address mode */ 6737 if (mdio_addr_share == TRUE) { 6738 pc->flags |= PHYCTRL_MDIO_ADDR_SHARE; 6739 } else { 6740 pc->phy_id += pc->lane_num; 6741 } 6742 6743 LOG_INFO(BSL_LS_SOC_PHY, 6744 (BSL_META_U(unit, 6745 "phy_hl65_stop: u=%d p=%d mask=0x%x value=0x%x\n"), 6746 unit, port, mask16, data16)); 6747 6748 return SOC_E_NONE; 6749 } 6750 6751 /* 6752 * Function: 6753 * _phy_hl65_notify_stop 6754 * Purpose: 6755 * Add a reason to put serdeshl65 PHY in reset. 6756 * Parameters: 6757 * unit - StrataSwitch unit #. 6758 * port - StrataSwitch port #. 6759 * flags - Reason to stop 6760 * Returns: 6761 * SOC_E_XXX 6762 */ 6763 6764 STATIC int 6765 _phy_hl65_notify_stop(int unit, soc_port_t port, uint32 flags) 6766 { 6767 INT_PHY_SW_STATE(unit, port)->stop |= flags; 6768 6769 return _phy_hl65_stop(unit, port); 6770 } 6771 6772 /* 6773 * Function: 6774 * _phy_hl65_notify_resume 6775 * Purpose: 6776 * Remove a reason to put serdeshl65 PHY in reset. 6777 * Parameters: 6778 * unit - StrataSwitch unit #. 6779 * port - StrataSwitch port #. 6780 * flags - Reason to stop 6781 * Returns: 6782 * SOC_E_XXX 6783 */ 6784 6785 STATIC int 6786 _phy_hl65_notify_resume(int unit, soc_port_t port, uint32 flags) 6787 { 6788 INT_PHY_SW_STATE(unit, port)->stop &= ~flags; 6789 6790 return _phy_hl65_stop(unit, port); 6791 } 6792 6793 /* 6794 * Function: 6795 * phy_hl65_media_setup 6796 * Purpose: 6797 * Configure 6798 * Parameters: 6799 * unit - StrataSwitch unit #. 6800 * port - StrataSwitch port #. 6801 * fiber_mode - Configure for fiber mode 6802 * fiber_pref - Fiber preferrred (if fiber mode) 6803 * Returns: 6804 * SOC_E_XXX 6805 */ 6806 STATIC int 6807 _phy_hl65_notify_interface(int unit, soc_port_t port, uint32 intf) 6808 { 6809 phy_ctrl_t *pc; 6810 uint16 data16; 6811 6812 pc = INT_PHY_SW_STATE(unit, port); 6813 6814 data16 = 0; 6815 if (intf != SOC_PORT_IF_SGMII) { 6816 data16 = DIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK; 6817 } 6818 6819 SOC_IF_ERROR_RETURN 6820 (MODIFY_HL65_DIGITAL_CONTROL1000X1r(unit, pc, data16, 6821 DIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK)); 6822 6823 return SOC_E_NONE; 6824 } 6825 6826 STATIC 6827 int _phy_hl65_analog_dsc_init (int unit,int port, int lane) 6828 { 6829 uint16 serdes_id0; 6830 int reg; 6831 phy_ctrl_t *pc; 6832 6833 pc = INT_PHY_SW_STATE(unit, port); 6834 6835 SOC_IF_ERROR_RETURN 6836 (READ_HL65_TEST_SERDESID0r(unit, pc, &serdes_id0)); 6837 6838 serdes_id0 = serdes_id0 & (TEST_SERDESID0_REV_NUMBER_MASK | 6839 TEST_SERDESID0_REV_LETTER_MASK); 6840 6841 /* use default if wrong lane specified */ 6842 if (lane < 0 || lane > 3) { 6843 lane = HL_ALL_LANES; 6844 } 6845 6846 if (lane == HL_ALL_LANES) { 6847 reg = 0x82A0; 6848 } else { 6849 reg = 0x8260 + lane * 0x10; 6850 } 6851 6852 if ((serdes_id0 == HL_SERDES_ID0_REVID_A0) || 6853 (serdes_id0 == HL_SERDES_ID0_REVID_A1) || 6854 (serdes_id0 == HL_SERDES_ID0_REVID_B0) ) { 6855 6856 if ((serdes_id0 == HL_SERDES_ID0_REVID_A0) || 6857 (serdes_id0 == HL_SERDES_ID0_REVID_A1)) { 6858 6859 /* Set this bit for the best possible PLL jitter performance */ 6860 SOC_IF_ERROR_RETURN 6861 (MODIFY_HL65_TXPLL_ANAPLLACONTROL4r(unit, pc, 6862 PLL_PLLACONTROL4_BIT12_MASK, 6863 PLL_PLLACONTROL4_BIT12_MASK)); 6864 } 6865 6866 /* Set lpq = 200uA */ 6867 SOC_IF_ERROR_RETURN 6868 (MODIFY_HL65_TXPLL_ANAPLLACONTROL2r(unit, pc, (1 << 2),(1 << 2))); 6869 6870 SOC_IF_ERROR_RETURN 6871 (HL65_REG_WRITE(unit, pc, 0, reg + 0x0, 0x21)); 6872 SOC_IF_ERROR_RETURN 6873 (HL65_REG_WRITE(unit, pc, 0, reg + 0x2, 0x3800)); 6874 SOC_IF_ERROR_RETURN 6875 (HL65_REG_WRITE(unit, pc, 0, reg + 0x3, 0x421b)); 6876 SOC_IF_ERROR_RETURN 6877 (HL65_REG_WRITE(unit, pc, 0, reg + 0x4, 0x53e4)); 6878 SOC_IF_ERROR_RETURN 6879 (HL65_REG_WRITE(unit, pc, 0, reg + 0x7, 0x14A5)); 6880 SOC_IF_ERROR_RETURN 6881 (HL65_REG_WRITE(unit, pc, 0, reg + 0x8, 0x03e0)); 6882 SOC_IF_ERROR_RETURN 6883 (HL65_REG_WRITE(unit, pc, 0, reg + 0x9, 0x0fc0)); 6884 SOC_IF_ERROR_RETURN 6885 (HL65_REG_WRITE(unit, pc, 0, reg + 0xb, 0x0312)); 6886 SOC_IF_ERROR_RETURN 6887 (HL65_REG_WRITE(unit, pc, 0, reg + 0xc, 0x046a)); 6888 6889 } else if (serdes_id0 == HL_SERDES_ID0_REVID_C0) { 6890 /* Set lpq = 200uA */ 6891 SOC_IF_ERROR_RETURN 6892 (MODIFY_HL65_TXPLL_ANAPLLACONTROL2r(unit, pc, (1 << 2),(1 << 2))); 6893 } 6894 return SOC_E_NONE; 6895 } 6896 6897 STATIC 6898 int _hl65_xgmii_scw_config (int unit, phy_ctrl_t *pc) 6899 { 6900 uint16 serdes_id0; 6901 6902 /* only apply to hypercore */ 6903 6904 SOC_IF_ERROR_RETURN 6905 (READ_HL65_TEST_SERDESID0r(unit, pc, &serdes_id0)); 6906 6907 if ((serdes_id0 & TEST_SERDESID0_MODEL_NUMBER_MASK) == 6908 SERDES_ID0_MODEL_NUMBER_HYPERLITE) { 6909 return(SOC_E_NONE); 6910 } 6911 6912 SOC_IF_ERROR_RETURN 6913 (WRITE_HL65_RX66_A_SCW0r(unit,pc,0xE070)); 6914 SOC_IF_ERROR_RETURN 6915 (WRITE_HL65_RX66_A_SCW1r(unit,pc,0xC0D0)); 6916 SOC_IF_ERROR_RETURN 6917 (WRITE_HL65_RX66_A_SCW2r(unit,pc,0xA0B0)); 6918 SOC_IF_ERROR_RETURN 6919 (WRITE_HL65_RX66_A_SCW3r(unit,pc,0x8090)); 6920 SOC_IF_ERROR_RETURN 6921 (WRITE_HL65_RX66_A_SCW0_MASKr(unit,pc,0xF0F0)); 6922 SOC_IF_ERROR_RETURN 6923 (WRITE_HL65_RX66_A_SCW1_MASKr(unit,pc,0xF0F0)); 6924 SOC_IF_ERROR_RETURN 6925 (WRITE_HL65_RX66_A_SCW2_MASKr(unit,pc,0xF0F0)); 6926 SOC_IF_ERROR_RETURN 6927 (WRITE_HL65_RX66_A_SCW3_MASKr(unit,pc,0xF0F0)); 6928 6929 return(SOC_E_NONE); 6930 } 6931 6932 STATIC 6933 int _hl65_rxaui_config(int unit, phy_ctrl_t *pc,int rxaui) 6934 { 6935 uint16 mask16,data16; 6936 mask16 = XGXSBLK1_LANECTRL3_PWRDWN_FORCE_MASK | 6937 0xc | /* lane 2 and 3 RX */ 6938 (0xc << XGXSBLK1_LANECTRL3_PWRDN_TX_SHIFT); /* TX */ 6939 6940 /* if in reduced XAUI mode, disable lane 2 and 3 */ 6941 data16 = rxaui? mask16: 0; 6942 6943 SOC_IF_ERROR_RETURN 6944 (MODIFY_HL65_XGXSBLK1_LANECTRL3r(unit,pc, data16,mask16)); 6945 6946 return(SOC_E_NONE); 6947 } 6948 6949 STATIC 6950 int _hl65_soft_reset(int unit, phy_ctrl_t *pc) 6951 { 6952 /* Set AER to DTE */ 6953 SOC_IF_ERROR_RETURN 6954 (WRITE_HL65_AERBLK_AERr(unit,pc, 0x2800)); 6955 6956 /* select multi mmd */ 6957 SOC_IF_ERROR_RETURN 6958 (WRITE_HL65_XGXSBLK0_MMDSELECTr(unit, pc, 0x400F)); 6959 6960 if (soc_property_get(unit, spn_SERDES_LANE0_RESET, 1)) { 6961 /* soft reset via DTE */ 6962 SOC_IF_ERROR_RETURN 6963 (WRITE_HL65_IEEE0BLK_MIICNTLr(unit,pc, 0xA040)); 6964 6965 /* wait 2us for reset to complete */ 6966 sal_usleep(2); 6967 } 6968 /* restore the AER to default */ 6969 SOC_IF_ERROR_RETURN 6970 (WRITE_HL65_AERBLK_AERr(unit,pc, 0x0)); 6971 6972 return(SOC_E_NONE); 6973 } 6974 6975 /* 6976 * This routine initializes some of the device's lane specific registers 6977 * applying to all modes. In the combo mode, the AER register should be 6978 * set to broadcast to all lanes before entering this function. 6979 */ 6980 STATIC 6981 int _hl65_lane_reg_init(int unit, phy_ctrl_t *pc) 6982 { 6983 uint16 serdes_id0; 6984 uint16 data16; 6985 6986 SOC_IF_ERROR_RETURN 6987 (READ_HL65_TEST_SERDESID0r(unit, pc, &serdes_id0)); 6988 6989 serdes_id0 = serdes_id0 & (TEST_SERDESID0_REV_NUMBER_MASK | 6990 TEST_SERDESID0_REV_LETTER_MASK); 6991 6992 if ((serdes_id0 == HL_SERDES_ID0_REVID_B0) || 6993 (serdes_id0 == HL_SERDES_ID0_REVID_C0)) { 6994 6995 /* Revert Back to original Rx fifo if C0/B0 version */ 6996 SOC_IF_ERROR_RETURN 6997 (MODIFY_HL65_DIGITAL4_MISC3r(unit, pc, 6998 0, 6999 DIGITAL4_MISC3_FIFO_IPG_CYA_MASK)); 7000 } 7001 7002 data16 = (1 << 2); /* Set FIFO Elasticity to 13.5k */ 7003 data16 |= soc_feature(unit, soc_feature_unimac_tx_crs)? 7004 DIGITAL_CONTROL1000X3_DISABLE_TX_CRS_MASK: 7005 0; /* set disable_tx_crs bit accordingly */ 7006 7007 SOC_IF_ERROR_RETURN 7008 (MODIFY_HL65_DIGITAL_CONTROL1000X3r(unit, pc, 7009 data16, 7010 DIGITAL_CONTROL1000X3_DISABLE_TX_CRS_MASK | 7011 DIGITAL_CONTROL1000X3_FIFO_ELASICITY_TX_RX_MASK)); 7012 7013 return(SOC_E_NONE); 7014 } 7015 7016 7017 #else /* INCLUDE_XGXS_HL65 */ 7018 int _xgxs_hl65_not_empty; 7019 #endif /* INCLUDE_XGXS_HL65 */