xgxs16g.c (105290B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: xgxs16g.c 8 * Purpose: Support Broadcom 1000/2500/10000/12000/13000/16000 SerDes(XGXS-16G) 9 * Support BCM 40nm Xenia core XGXS_13G_040_FC 10 */ 11 12 #include <sal/types.h> 13 #include <shared/bsl.h> 14 #include <sal/types.h> 15 #include <sal/core/spl.h> 16 17 #include <soc/drv.h> 18 #include <soc/debug.h> 19 #include <soc/error.h> 20 #include <soc/phyreg.h> 21 #include <soc/port_ability.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_16G) 30 #include "phyconfig.h" /* Must include before other phy related includes */ 31 #include "phyident.h" 32 #include "phyreg.h" 33 #include "phynull.h" 34 #include "xgxs.h" 35 #include "serdesid.h" 36 #include "xgxs16g.h" 37 38 #define TX_DRIVER_DFT_LN_CTRL 0x4 39 #define PHY_XGXS16G_LANEPRBS_LANE_SHIFT 4 40 41 /* Notify event forward declaration */ 42 STATIC int phy_xgxs16g_interface_get(int unit, soc_port_t port, 43 soc_port_if_t *pif); 44 STATIC int phy_xgxs16g_master_get(int unit, soc_port_t port, int *master); 45 STATIC int _phy_xgxs16g_notify_duplex(int unit, soc_port_t port, uint32 duplex); 46 STATIC int _phy_xgxs16g_notify_speed(int unit, soc_port_t port, uint32 speed); 47 STATIC int _phy_xgxs16g_notify_stop(int unit, soc_port_t port, uint32 flags); 48 STATIC int _phy_xgxs16g_notify_resume(int unit, soc_port_t port, uint32 flags); 49 STATIC int _phy_xgxs16g_notify_interface(int unit, soc_port_t port, uint32 intf); 50 STATIC int _phy_xgxs16g_notify_mac_loopback(int unit, soc_port_t port, uint32 enable); 51 #define XGXS16G_PLL_WAIT 250000 52 STATIC int phy_xgxs16g_an_set(int unit, soc_port_t port, int an); 53 STATIC int phy_xgxs16g_an_get(int unit, soc_port_t port, 54 int *an, int *an_done); 55 STATIC int phy_xgxs16g_speed_get(int unit, soc_port_t port, int *speed); 56 STATIC int phy_xgxs16g_ability_advert_set(int unit, soc_port_t port, 57 soc_port_ability_t *ability); 58 STATIC int phy_xgxs16g_ability_advert_get(int unit, soc_port_t port, 59 soc_port_ability_t *ability); 60 STATIC int phy_xgxs16g_ability_local_get(int unit, soc_port_t port, 61 soc_port_ability_t *ability); 62 STATIC int phy_xgxs16g_speed_set(int unit, soc_port_t port, int speed); 63 STATIC int _phy_xgxs16g_control_vco_disturbed_set(int unit, soc_port_t port); 64 STATIC int _phy_xgxs16g_control_vco_disturbed_get(int unit, soc_port_t port, 65 uint32 *value); 66 67 STATIC int 68 _phy_xgxs16g_pll_lock_wait(int unit, soc_port_t port) 69 { 70 uint16 data16; 71 phy_ctrl_t *pc; 72 soc_timeout_t to; 73 int rv; 74 75 pc = INT_PHY_SW_STATE(unit, port); 76 _phy_xgxs16g_control_vco_disturbed_set(unit, port); 77 soc_timeout_init(&to, XGXS16G_PLL_WAIT, 0); 78 do { 79 rv = READ_XGXS16G_XGXSBLK0_XGXSSTATUSr(unit, pc, &data16); 80 if ((data16 & XGXSBLK0_XGXSSTATUS_TXPLL_LOCK_MASK) || 81 SOC_FAILURE(rv)) { 82 break; 83 } 84 } while (!soc_timeout_check(&to)); 85 if ((data16 & XGXSBLK0_XGXSSTATUS_TXPLL_LOCK_MASK) == 0) { 86 LOG_WARN(BSL_LS_SOC_PHY, 87 (BSL_META_U(unit, 88 "XGXS_16G : TXPLL did not lock: u=%d p=%d\n"), 89 unit, port)); 90 return (SOC_E_TIMEOUT); 91 } 92 return (SOC_E_NONE); 93 } 94 95 STATIC int 96 _phy_xgxs16g_pin_out_set(int unit, soc_port_t port) 97 { 98 uint16 data16; 99 uint16 mask16; 100 phy_ctrl_t *pc; 101 uint32 phy_xaui_tx_polarity_flip; 102 uint32 phy_xaui_rx_polarity_flip=0; 103 104 pc = INT_PHY_SW_STATE(unit, port); 105 106 /* 107 * Transform CX4 pin out on the board to HG pinout 108 */ 109 if (soc_property_port_get(unit, port, spn_CX4_TO_HIGIG, FALSE)) { 110 if (FEATURE_NEW_LANESWAP(pc)) { 111 SOC_IF_ERROR_RETURN /* Enable TX Lane swap */ 112 (WRITE_XGXS16G_XGXSBLK8_TXLNSWAP1r(unit, pc, 0x80e4)); 113 } else { 114 /* Swap TX lanes */ 115 data16 = XGXSBLK2_TXLNSWAP_TX_LNSWAP_EN_MASK; 116 mask16 = XGXSBLK2_TXLNSWAP_TX_LNSWAP_EN_MASK; 117 SOC_IF_ERROR_RETURN 118 (MODIFY_XGXS16G_XGXSBLK2_TXLNSWAPr(unit, pc, data16, mask16)); 119 } 120 121 /* Flip TX polarity */ 122 data16 = TX0_TX_ACONTROL0_TXPOL_FLIP_MASK; 123 mask16 = TX0_TX_ACONTROL0_TXPOL_FLIP_MASK; 124 SOC_IF_ERROR_RETURN 125 (MODIFY_XGXS16G_TX_ALL_TX_ACONTROL0r(unit, pc, data16, mask16)); 126 } else { 127 /* If CX4 to HG conversion is enabled, do not allow individual lane 128 * swapping. 129 */ 130 int i; 131 uint16 lane_map; 132 uint16 lane, hw_map, chk_map; 133 134 /* Update RX lane map */ 135 lane_map = soc_property_port_get(unit, port, 136 spn_XGXS_RX_LANE_MAP, 0x0123) & 0xffff; 137 if (lane_map != 0x0123) { 138 hw_map = 0; 139 chk_map = 0; 140 for (i = 0; i < 4; i++) { 141 lane = (lane_map >> (i * 4)) & 0xf; 142 hw_map |= lane << (i * 2); 143 chk_map |= 1 << lane; 144 } 145 if (chk_map == 0xf) { 146 if (FEATURE_NEW_LANESWAP(pc)) { 147 /* swap the hw_map */ 148 for (hw_map=0, i = 3; i >= 0; i--) { 149 lane = (lane_map >> (i * 4)) & 0xf; 150 hw_map |= lane << ((3 - i) * 2); 151 } 152 SOC_IF_ERROR_RETURN /* Enable RX Lane swap */ 153 (MODIFY_XGXS16G_XGXSBLK8_RXLNSWAP1r(unit, pc, 154 hw_map, 155 XGXSBLK2_RXLNSWAP_RX_LNSWAP_EN_MASK | 156 XGXSBLK8_RXLNSWAP1_RX0_LNSWAP_SEL_MASK | 157 XGXSBLK8_RXLNSWAP1_RX1_LNSWAP_SEL_MASK | 158 XGXSBLK8_RXLNSWAP1_RX2_LNSWAP_SEL_MASK | 159 XGXSBLK8_RXLNSWAP1_RX3_LNSWAP_SEL_MASK)); 160 161 } else { 162 hw_map |= XGXSBLK2_RXLNSWAP_RX_LNSWAP_EN_MASK | 163 XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE_EN_MASK; 164 mask16 = XGXSBLK2_RXLNSWAP_RX_LNSWAP_EN_MASK | 165 XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE_EN_MASK | 166 XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE0_MASK | 167 XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE1_MASK | 168 XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE2_MASK | 169 XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE3_MASK; 170 SOC_IF_ERROR_RETURN 171 (MODIFY_XGXS16G_XGXSBLK2_RXLNSWAPr(unit, pc, 172 hw_map, mask16)); 173 } 174 } else { 175 LOG_WARN(BSL_LS_SOC_PHY, 176 (BSL_META_U(unit, 177 "unit %d port %s: Invalid RX lane map 0x%04x.\n"), 178 unit, SOC_PORT_NAME(unit, port), lane_map)); 179 } 180 } 181 182 /* Update TX lane map */ 183 lane_map = soc_property_port_get(unit, port, 184 spn_XGXS_TX_LANE_MAP, 0x0123) & 0xffff; 185 186 if (lane_map != 0x0123) { 187 hw_map = 0; 188 chk_map = 0; 189 for (i = 0; i < 4; i++) { 190 lane = (lane_map >> (i * 4)) & 0xf; 191 hw_map |= lane << (i * 2); 192 chk_map |= 1 << lane; 193 } 194 if (chk_map == 0xf) { 195 if (FEATURE_NEW_LANESWAP(pc)) { 196 /* swap the hw_map */ 197 for (hw_map=0, i = 3; i >= 0; i--) { 198 lane = (lane_map >> (i * 4)) & 0xf; 199 hw_map |= lane << ((3 - i) * 2); 200 } 201 SOC_IF_ERROR_RETURN /* Enable TX Lane swap */ 202 (MODIFY_XGXS16G_XGXSBLK8_TXLNSWAP1r(unit, pc, 203 hw_map, 204 XGXSBLK8_TXLNSWAP1_TX3_LNSWAP_SEL_MASK | 205 XGXSBLK8_TXLNSWAP1_TX2_LNSWAP_SEL_MASK | 206 XGXSBLK8_TXLNSWAP1_TX1_LNSWAP_SEL_MASK | 207 XGXSBLK8_TXLNSWAP1_TX0_LNSWAP_SEL_MASK)); 208 } else { 209 hw_map |= XGXSBLK2_TXLNSWAP_TX_LNSWAP_EN_MASK; 210 mask16 = XGXSBLK2_TXLNSWAP_TX_LNSWAP_EN_MASK | 211 XGXSBLK2_TXLNSWAP_TX_LNSWAP_FORCE0_MASK | 212 XGXSBLK2_TXLNSWAP_TX_LNSWAP_FORCE1_MASK | 213 XGXSBLK2_TXLNSWAP_TX_LNSWAP_FORCE2_MASK | 214 XGXSBLK2_TXLNSWAP_TX_LNSWAP_FORCE3_MASK; 215 SOC_IF_ERROR_RETURN 216 (MODIFY_XGXS16G_XGXSBLK2_TXLNSWAPr(unit, pc, 217 hw_map, mask16)); 218 } 219 } else { 220 LOG_WARN(BSL_LS_SOC_PHY, 221 (BSL_META_U(unit, 222 "unit %d port %s: Invalid TX lane map 0x%04x.\n"), 223 unit, SOC_PORT_NAME(unit, port), lane_map)); 224 } 225 } 226 phy_xaui_tx_polarity_flip = soc_property_port_get(unit, port, 227 spn_PHY_XAUI_TX_POLARITY_FLIP, 0); 228 if (phy_xaui_tx_polarity_flip) { 229 /* Flip TX polarity */ 230 data16 = TX0_TX_ACONTROL0_TXPOL_FLIP_MASK; 231 mask16 = TX0_TX_ACONTROL0_TXPOL_FLIP_MASK; 232 LOG_WARN(BSL_LS_SOC_PHY, 233 (BSL_META_U(unit, 234 "unit %d port %s: TX Polarity swap 0x%04x.\n"), 235 unit, SOC_PORT_NAME(unit, port), data16)); 236 if (phy_xaui_tx_polarity_flip == 1) { 237 SOC_IF_ERROR_RETURN 238 (MODIFY_XGXS16G_TX_ALL_TX_ACONTROL0r(unit, pc, data16, mask16)); 239 } 240 if ((phy_xaui_tx_polarity_flip & 0x000F) == 0x000F) { 241 SOC_IF_ERROR_RETURN 242 (MODIFY_XGXS16G_TX0_TX_ACONTROL0r(unit, pc, data16, mask16)); 243 } 244 if ((phy_xaui_tx_polarity_flip & 0x00F0) == 0x00F0) { 245 SOC_IF_ERROR_RETURN 246 (MODIFY_XGXS16G_TX1_TX_ACONTROL0r(unit, pc, data16, mask16)); 247 } 248 if ((phy_xaui_tx_polarity_flip & 0x0F00) == 0x0F00) { 249 SOC_IF_ERROR_RETURN 250 (MODIFY_XGXS16G_TX2_TX_ACONTROL0r(unit, pc, data16, mask16)); 251 } 252 if ((phy_xaui_tx_polarity_flip & 0xF000) == 0xF000) { 253 SOC_IF_ERROR_RETURN 254 (MODIFY_XGXS16G_TX3_TX_ACONTROL0r(unit, pc, data16, mask16)); 255 } 256 } 257 phy_xaui_rx_polarity_flip = soc_property_port_get(unit, port, 258 spn_PHY_XAUI_RX_POLARITY_FLIP, 0); 259 if (phy_xaui_rx_polarity_flip) { 260 /* Flip RX polarity */ 261 data16 = 0x06; /* RX_POLARITY_FORCE_R | RX_POLARIRT_R */ 262 mask16 = 0x06; 263 LOG_WARN(BSL_LS_SOC_PHY, 264 (BSL_META_U(unit, 265 "unit %d port %s: RX Polarity swap 0x%04x.\n"), 266 unit, SOC_PORT_NAME(unit, port), data16)); 267 if (phy_xaui_rx_polarity_flip == 1) { 268 SOC_IF_ERROR_RETURN 269 (MODIFY_XGXS16G_RX_CONTROL_PCIEr(unit, pc, data16, mask16)); 270 } 271 if ((phy_xaui_rx_polarity_flip & 0x000F) == 0x000F) { 272 SOC_IF_ERROR_RETURN 273 (MODIFY_XGXS16G_RX0_ANA_RX_CONTROL_PCIEr(unit, pc, data16, mask16)); 274 } 275 if ((phy_xaui_rx_polarity_flip & 0x00F0) == 0x00F0) { 276 SOC_IF_ERROR_RETURN 277 (MODIFY_XGXS16G_RX1_ANA_RX_CONTROL_PCIEr(unit, pc, data16, mask16)); 278 } 279 if ((phy_xaui_rx_polarity_flip & 0x0F00) == 0x0F00) { 280 SOC_IF_ERROR_RETURN 281 (MODIFY_XGXS16G_RX2_ANA_RX_CONTROL_PCIEr(unit, pc, data16, mask16)); 282 } 283 if ((phy_xaui_rx_polarity_flip & 0xF000) == 0xF000) { 284 SOC_IF_ERROR_RETURN 285 (MODIFY_XGXS16G_RX3_ANA_RX_CONTROL_PCIEr(unit, pc, data16, mask16)); 286 } 287 } 288 } 289 return (SOC_E_NONE); 290 } 291 292 /* 293 * Function: 294 * phy_xgxs16g_init 295 * Purpose: 296 * Initialize xgxs6 phys 297 * Parameters: 298 * unit - StrataSwitch unit #. 299 * port - StrataSwitch port #. 300 * Returns: 301 * SOC_E_NONE 302 */ 303 304 STATIC int 305 phy_xgxs16g_init(int unit, soc_port_t port) 306 { 307 uint16 data16; 308 uint16 mask16; 309 int preemph, idriver, pdriver; 310 soc_port_ability_t ability; 311 phy_ctrl_t *pc; 312 int serdes_fiber_pref_def; 313 XGXS16G_DEV_DESC *pDesc; 314 soc_phy_info_t *pi; 315 int len; 316 int serdes_id0; 317 318 pc = INT_PHY_SW_STATE(unit, port); 319 pDesc = (XGXS16G_DEV_DESC *)(pc + 1); 320 321 SOC_IF_ERROR_RETURN 322 (READ_XGXS16G_SERDESID_SERDESID2r(unit, pc, &pDesc->serdes_id0)); 323 serdes_id0 = pDesc->serdes_id0; 324 SOC_IF_ERROR_RETURN 325 (READ_XGXS16G_SERDESID_SERDESID2r(unit, pc, &pDesc->serdes_id2)); 326 327 /* compose device name/instance/lane information for display 328 * XGXS_16G device uses existing method 329 */ 330 if (XGXS16G_13G_ID(pc)) { 331 /* 332 * COVERITY 333 * 334 * Checked that buffer overflow will not happen for destination string. 335 */ 336 /* coverity[secure-coding] */ 337 338 sal_strcpy(pDesc->name,"XGXS13G-"); 339 len = sal_strlen(pDesc->name); 340 /* add rev letter */ 341 pDesc->name[len++] = 'A' + ((serdes_id0 >> 342 SERDESID_SERDESID0_REV_LETTER_SHIFT) & 0x3); 343 /* add rev number */ 344 pDesc->name[len++] = '0' + ((serdes_id0 >> 345 SERDESID_SERDESID0_REV_NUMBER_SHIFT) & 0x7); 346 pDesc->name[len++] = '/'; 347 pDesc->name[len++] = (pc->chip_num/10)%10 + '0'; 348 pDesc->name[len++] = pc->chip_num%10 + '0'; 349 pDesc->name[len++] = '/'; 350 pDesc->name[len++] = '4'; 351 pDesc->name[len] = 0; /* string terminator */ 352 353 if (len > XGXS16G_LANE_NAME_LEN) { 354 LOG_ERROR(BSL_LS_SOC_PHY, 355 (BSL_META_U(unit, 356 "XGXS13G info string length %d exceeds max length 0x%x: u=%d p=%d\n"), 357 len,XGXS16G_LANE_NAME_LEN,unit, port)); 358 return SOC_E_MEMORY; 359 } 360 361 pi = &SOC_PHY_INFO(unit, port); 362 if (!PHY_EXTERNAL_MODE(unit, port)) { 363 pi->phy_name = pDesc->name; 364 } 365 366 } 367 368 /* Reset the core */ 369 370 /* Stop PLL Sequencer and configure the core into correct mode */ 371 data16 = (XGXSBLK0_XGXSCONTROL_MODE_10G_ComboCoreMode << 372 XGXSBLK0_XGXSCONTROL_MODE_10G_SHIFT) | 373 XGXSBLK0_XGXSCONTROL_HSTL_MASK | 374 XGXSBLK0_XGXSCONTROL_CDET_EN_MASK | 375 XGXSBLK0_XGXSCONTROL_EDEN_MASK | 376 XGXSBLK0_XGXSCONTROL_AFRST_EN_MASK | 377 XGXSBLK0_XGXSCONTROL_TXCKO_DIV_MASK; 378 SOC_IF_ERROR_RETURN 379 (WRITE_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, data16)); 380 381 /* disable in-band MDIO. PHY-443 */ 382 SOC_IF_ERROR_RETURN 383 (XGXS16G_REG_MODIFY(unit, pc, 0x00, 0x8111, 1 << 3, 1 << 3)); 384 385 if (soc_property_port_get(unit, port, 386 spn_PHY_AN_C73, FALSE)) { 387 PHY_FLAGS_SET(unit, port, PHY_FLAGS_C73); 388 } 389 390 /* disable CL73 BAM */ 391 SOC_IF_ERROR_RETURN 392 (MODIFY_XGXS16G_AN_CL73_REG(unit,pc,0x8372, 393 0, 394 CL73_USERB0_CL73_BAMCTRL1_CL73_BAMEN_MASK)); 395 396 if (!PHY_CLAUSE73_MODE(unit, port)) { 397 /* disable CL73 AN device*/ 398 SOC_IF_ERROR_RETURN 399 (WRITE_XGXS16G_AN_CL73_REG(unit,pc,MII_CTRL_REG,0)); 400 } 401 402 /* Disable IEEE block select auto-detect. 403 * The driver will select desired block as necessary. 404 * By default, the driver keeps the mapping for XAUI block in 405 * IEEE address space. 406 */ 407 SOC_IF_ERROR_RETURN 408 (MODIFY_XGXS16G_XGXSBLK0_MISCCONTROL1r(unit, pc, 409 XGXSBLK0_MISCCONTROL1_IEEE_BLKSEL_VAL_MASK, 410 XGXSBLK0_MISCCONTROL1_IEEE_BLKSEL_AUTODET_MASK | 411 XGXSBLK0_MISCCONTROL1_IEEE_BLKSEL_VAL_MASK)); 412 413 /* 414 * Configure signal auto-detection between SGMII and fiber. 415 */ 416 data16 = SERDESDIGITAL_CONTROL1000X1_CRC_CHECKER_DISABLE_MASK; 417 mask16 = SERDESDIGITAL_CONTROL1000X1_AUTODET_EN_MASK | 418 SERDESDIGITAL_CONTROL1000X1_CRC_CHECKER_DISABLE_MASK | 419 SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK; 420 if (soc_property_port_get(unit, port, spn_SERDES_AUTOMEDIUM, TRUE)) { 421 data16 |= SERDESDIGITAL_CONTROL1000X1_AUTODET_EN_MASK; 422 } 423 serdes_fiber_pref_def = TRUE; 424 if (PHY_EXTERNAL_MODE(unit, port) && IS_GE_PORT(unit, port)) { 425 serdes_fiber_pref_def = FALSE; 426 } 427 if (soc_property_port_get(unit, port, spn_SERDES_FIBER_PREF, 428 serdes_fiber_pref_def)) { 429 data16 |= SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK; 430 } 431 if (soc_property_port_get(unit, port, 432 spn_SERDES_SGMII_MASTER, FALSE)) { 433 data16 |= SERDESDIGITAL_CONTROL1000X1_SGMII_MASTER_MODE_MASK; 434 mask16 |= SERDESDIGITAL_CONTROL1000X1_SGMII_MASTER_MODE_MASK; 435 } 436 SOC_IF_ERROR_RETURN 437 (MODIFY_XGXS16G_SERDESDIGITAL_CONTROL1000X1r(unit, pc, data16, mask16)); 438 439 /* Disable SerDes parallel detect */ 440 SOC_IF_ERROR_RETURN 441 (WRITE_XGXS16G_SERDESDIGITAL_CONTROL1000X2r(unit, pc, 0)); 442 443 /* Initialize combo SerDes to reasonable default settings */ 444 SOC_IF_ERROR_RETURN 445 (WRITE_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, 446 MII_CTRL_AE | MII_CTRL_FD | MII_CTRL_SS_1000)); 447 448 /* Disable 10G parallel detect */ 449 SOC_IF_ERROR_RETURN 450 (WRITE_XGXS16G_AN73_PDET_PARDET10GCONTROLr(unit, pc, 0)); 451 452 /* Enable BAM mode */ 453 SOC_IF_ERROR_RETURN 454 (WRITE_XGXS16G_BAM_NEXTPAGE_MP5_NEXTPAGECTRLr(unit, pc, 1)); 455 456 /* Initialize XAUI to reasonable default settings */ 457 if (XGXS16G_13G_ID(pc)) { 458 /* 40nm */ 459 preemph = soc_property_port_get(unit, port, spn_XGXS_PREEMPHASIS, 0); 460 idriver = soc_property_port_get(unit, port, spn_XGXS_DRIVER_CURRENT, 4); 461 data16 = ((preemph & 0xf) << TX_ALL_040_TX_DRIVER_PREEMPHASIS_POST_SHIFT) | 462 ((idriver & 0x7) << TX_ALL_040_TX_DRIVER_IDRIVER_SHIFT); 463 mask16 = TX_ALL_040_TX_DRIVER_PREEMPHASIS_POST_MASK | 464 TX_ALL_040_TX_DRIVER_IDRIVER_MASK; 465 SOC_IF_ERROR_RETURN 466 (MODIFY_XGXS13G_040_TX_ALL_ACONTROL1r(unit, pc, data16, mask16)); 467 } else { 468 preemph = soc_property_port_get(unit, port, spn_XGXS_PREEMPHASIS, 0); 469 idriver = soc_property_port_get(unit, port, spn_XGXS_DRIVER_CURRENT, 9); 470 pdriver = soc_property_port_get(unit, port, spn_XGXS_PRE_DRIVER_CURRENT, 9); 471 data16 = ((preemph & 0xf) << TX_ALL_TX_DRIVER_PREEMPHASIS_SHIFT) | 472 ((idriver & 0xf) << TX_ALL_TX_DRIVER_IDRIVER_SHIFT) | 473 ((pdriver & 0xf) << TX_ALL_TX_DRIVER_IPREDRIVER_SHIFT); 474 mask16 = TX_ALL_TX_DRIVER_PREEMPHASIS_MASK | 475 TX_ALL_TX_DRIVER_IDRIVER_MASK | 476 TX_ALL_TX_DRIVER_IPREDRIVER_MASK; 477 SOC_IF_ERROR_RETURN 478 (MODIFY_XGXS16G_TX_ALL_TX_DRIVERr(unit, pc, data16, mask16)); 479 } 480 481 /* Advertise all property by default */ 482 SOC_IF_ERROR_RETURN 483 (phy_xgxs16g_ability_local_get(unit, port, &ability)); 484 485 SOC_IF_ERROR_RETURN 486 (phy_xgxs16g_ability_advert_set(unit, port, &ability)); 487 488 /* Adjust parallel detect link timer to 60ms */ 489 SOC_IF_ERROR_RETURN 490 (WRITE_XGXS16G_AN73_PDET_PARDET10GLINKr(unit, pc, 0x16E2)); 491 492 /* Enable 10G parallel detect by default */ 493 data16 = 0; 494 mask16 = AN73_PDET_PARDET10GCONTROL_PARDET10G_EN_MASK; 495 if (soc_property_port_get(unit, port, spn_XGXS_PDETECT_10G, 1)) { 496 data16 = AN73_PDET_PARDET10GCONTROL_PARDET10G_EN_MASK; 497 } 498 SOC_IF_ERROR_RETURN 499 (MODIFY_XGXS16G_AN73_PDET_PARDET10GCONTROLr(unit, pc, data16, mask16)); 500 501 /* Allow config settings to adjust pin out for XAUI lane */ 502 SOC_IF_ERROR_RETURN 503 (_phy_xgxs16g_pin_out_set(unit, port)); 504 505 /* set elasticity fifo size to 13.5k to support 12k jumbo pkt size*/ 506 SOC_IF_ERROR_RETURN 507 (MODIFY_XGXS16G_SERDESDIGITAL_CONTROL1000X3r(unit,pc, 508 (1 << 2), 509 SERDESDIGITAL_CONTROL1000X3_FIFO_ELASICITY_TX_RX_MASK)); 510 511 /* enable autoneg or force a speed depending on the port type */ 512 513 if (PHY_EXTERNAL_MODE(unit, port) && 514 (IS_XE_PORT(unit, port) || IS_HG_PORT(unit, port))) { 515 int force_speed; 516 517 force_speed = SERDESDIGITAL_MISC1_FORCE_SPEED_SEL_MASK; 518 if (soc_property_port_get(unit, port, spn_10G_IS_CX4, TRUE)) { 519 force_speed |= 4; /* 10G CX4 */ 520 } else { 521 force_speed |= 3; /* 10G HiG */ 522 } 523 524 /* disable autoneg */ 525 SOC_IF_ERROR_RETURN 526 (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, 527 0, 528 MII_CTRL_AE)); 529 if (PHY_CLAUSE73_MODE(unit, port)) { 530 SOC_IF_ERROR_RETURN 531 (MODIFY_XGXS16G_AN_CL73_REG(unit, pc,MII_CTRL_REG, 532 0, 533 MII_CTRL_AE)); 534 } 535 536 /* force speed to 10G */ 537 SOC_IF_ERROR_RETURN 538 (MODIFY_XGXS16G_SERDESDIGITAL_MISC1r(unit, pc, force_speed, 539 SERDESDIGITAL_MISC1_FORCE_SPEED_SEL_MASK | 540 SERDESDIGITAL_MISC1_FORCE_SPEED_MASK)); 541 } else { /* autoneg */ 542 SOC_IF_ERROR_RETURN 543 (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, 544 MII_CTRL_AE | MII_CTRL_RAN, 545 MII_CTRL_AE | MII_CTRL_RAN)); 546 if (PHY_CLAUSE73_MODE(unit, port)) { 547 SOC_IF_ERROR_RETURN 548 (MODIFY_XGXS16G_AN_CL73_REG(unit, pc,MII_CTRL_REG, 549 MII_CTRL_AE | MII_CTRL_RAN, 550 MII_CTRL_AE | MII_CTRL_RAN)); 551 } 552 } 553 554 if (XGXS16G_13G_ID(pc)) { 555 /* Enabble LPI passthru' for native mode EEE */ 556 SOC_IF_ERROR_RETURN 557 (MODIFY_XGXS16G_REMOTEPHY_MISC5r(unit, pc, 0xc000, 0xc000)); 558 SOC_IF_ERROR_RETURN 559 (MODIFY_XGXS16G_XGXSBLK7_EEECONTROLr(unit, pc, 0x0007, 0x0007)); 560 } 561 562 /* Start PLL Sequencer and wait for PLL to lock */ 563 SOC_IF_ERROR_RETURN 564 (MODIFY_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, 565 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK, 566 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK)); 567 (void) _phy_xgxs16g_pll_lock_wait(unit, port); 568 569 /* PRBS Polynomial for all lanes: 0x8019=0x0000 */ 570 SOC_IF_ERROR_RETURN 571 (WRITE_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, 0)); 572 573 return (SOC_E_NONE); 574 } 575 576 /* 577 * Function: 578 * phy_xgxs16g_link_get 579 * Purpose: 580 * Get layer2 connection status. 581 * Parameters: 582 * unit - StrataSwitch unit #. 583 * port - StrataSwitch port #. 584 * link - address of memory to store link up/down state. 585 * Returns: 586 * SOC_E_NONE 587 */ 588 589 STATIC int 590 phy_xgxs16g_link_get(int unit, soc_port_t port, int *link) 591 { 592 phy_ctrl_t *pc; 593 uint16 xgxs_stat1; 594 uint16 xgxs_stat3; 595 int autoneg; 596 int an_done; 597 598 if (PHY_DISABLED_MODE(unit, port)) { 599 *link = FALSE; 600 return SOC_E_NONE; 601 } 602 603 pc = INT_PHY_SW_STATE(unit, port); 604 605 SOC_IF_ERROR_RETURN 606 (READ_XGXS16G_GP_STATUS_XGXSSTATUS3r(unit, pc, &xgxs_stat3)); 607 608 *link = (xgxs_stat3 & GP_STATUS_XGXSSTATUS3_LINK_LATCHDOWN_MASK) ? 1 : 0; 609 610 /* 611 * Following logic is to ensure that there is no false link up status 612 * in an mode. Link status is set as UP only if an_done is complete. 613 */ 614 SOC_IF_ERROR_RETURN 615 (phy_xgxs16g_an_get(unit, port, &autoneg, NULL)); 616 617 if (autoneg) { 618 /* If autoneg is enabled, check for autoneg done. */ 619 SOC_IF_ERROR_RETURN 620 (READ_XGXS16G_GP_STATUS_XGXSSTATUS1r(unit, pc, &xgxs_stat1)); 621 622 an_done = ((xgxs_stat1 & GP_STATUS_XGXSSTATUS1_AUTONEG_COMPLETE_MASK) 623 != 0); 624 if (!an_done) { 625 uint16 an_status; 626 627 /* check Clause73 autoneg */ 628 if (PHY_CLAUSE73_MODE(unit, port)) { 629 SOC_IF_ERROR_RETURN 630 (READ_XGXS16G_GP_STATUS_TOPANSTATUS1r(unit, pc, &an_status)); 631 632 if (an_status & 633 GP_STATUS_TOPANSTATUS1_CL73_AUTONEG_COMPLETE_MASK) { 634 an_done = TRUE; 635 } 636 } 637 } 638 639 *link = (*link) && (an_done); 640 } 641 642 return (SOC_E_NONE); 643 } 644 645 /* 646 * Function: 647 * phy_xgxs16g_enable_set 648 * Purpose: 649 * Enable/Disable phy 650 * Parameters: 651 * unit - StrataSwitch unit #. 652 * port - StrataSwitch port #. 653 * enable - on/off state to set 654 * Returns: 655 * SOC_E_NONE 656 */ 657 658 STATIC int 659 phy_xgxs16g_enable_set(int unit, soc_port_t port, int enable) 660 { 661 uint16 pmd_tx_disable; 662 phy_ctrl_t *pc; 663 664 pc = INT_PHY_SW_STATE(unit, port); 665 666 if (enable) { 667 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE); 668 pmd_tx_disable = 0; 669 } else { 670 pmd_tx_disable = XGXSBLK0_MISCCONTROL1_GLOBAL_PMD_TX_DISABLE_MASK; 671 PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE); 672 } 673 674 /* disable the Tx */ 675 SOC_IF_ERROR_RETURN 676 (MODIFY_XGXS16G_XGXSBLK0_MISCCONTROL1r(unit, pc, pmd_tx_disable, 677 XGXSBLK0_MISCCONTROL1_GLOBAL_PMD_TX_DISABLE_MASK)); 678 679 /* disable the Rx */ 680 SOC_IF_ERROR_RETURN 681 (MODIFY_XGXS16G_RX_ALL_RX_CONTROLr(unit, pc, 682 enable? 0:DSC_2_0_DSC_CTRL0_RXSEQSTART_MASK, 683 DSC_2_0_DSC_CTRL0_RXSEQSTART_MASK)); 684 685 return (SOC_E_NONE); 686 } 687 688 /* 689 * Function: 690 * phy_xgxs16g_speed_set 691 * Purpose: 692 * Set PHY speed 693 * Parameters: 694 * unit - StrataSwitch unit #. 695 * port - StrataSwitch port #. 696 * speed - link speed in Mbps 697 * Returns: 698 * SOC_E_NONE 699 */ 700 701 STATIC int 702 phy_xgxs16g_speed_set(int unit, soc_port_t port, int speed) 703 { 704 phy_ctrl_t *pc; 705 uint16 force_speed; 706 uint16 data16; 707 uint16 speed_mii; 708 uint16 sgmii_status; 709 710 speed_mii = 0; 711 712 /* Check for valid speed and convert valid speed to HW values */ 713 force_speed = SERDESDIGITAL_MISC1_FORCE_SPEED_SEL_MASK; 714 switch (speed) { 715 case 10: 716 speed_mii = MII_CTRL_SS_10; 717 break; 718 case 100: 719 speed_mii = MII_CTRL_SS_100; 720 break; 721 case 1000: 722 speed_mii = MII_CTRL_SS_1000; 723 force_speed = 0; 724 break; 725 case 2500: 726 speed_mii = MII_CTRL_SS_MSB | MII_CTRL_SS_LSB; 727 force_speed |= 0; 728 break; 729 case 5000: 730 force_speed |= 1; 731 break; 732 case 6000: 733 force_speed |= 2; 734 break; 735 case 0: /* set to reasonable speed */ 736 /* fall through */ 737 case 10000: 738 if (soc_property_port_get(unit, port, spn_10G_IS_CX4, TRUE)) { 739 force_speed |= 4; /* 10G CX4 */ 740 } else { 741 force_speed |= 3; /* 10G HiG */ 742 } 743 break; 744 case 12000: 745 force_speed |= 5; 746 break; 747 case 12500: 748 force_speed |= 6; 749 break; 750 case 13000: 751 force_speed |= 7; 752 break; 753 case 15000: 754 force_speed |= 8; 755 break; 756 case 16000: 757 force_speed |= 9; 758 break; 759 default: 760 return (SOC_E_PARAM); 761 } 762 763 pc = INT_PHY_SW_STATE(unit, port); 764 765 /* Disable autoneg */ 766 SOC_IF_ERROR_RETURN 767 (phy_xgxs16g_an_set(unit, port, 0)); 768 769 /* Puts PLL in reset state and forces all datapath into reset state */ 770 SOC_IF_ERROR_RETURN 771 (MODIFY_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, 0, 772 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK)); 773 774 if (FEATURE_SPEED_100FX(pc)) { 775 /* disable 100FX and 100FX auto-detect */ 776 SOC_IF_ERROR_RETURN 777 (MODIFY_XGXS16G_FX100_CONTROL1r(unit,pc, 778 0, 779 FX100_CONTROL1_AUTODET_EN_MASK | 780 FX100_CONTROL1_ENABLE_MASK)); 781 782 /* disable 100FX idle detect */ 783 SOC_IF_ERROR_RETURN 784 (MODIFY_XGXS16G_FX100_CONTROL3r(unit,pc, 785 FX100_CONTROL3_CORRELATOR_DISABLE_MASK, 786 FX100_CONTROL3_CORRELATOR_DISABLE_MASK)); 787 } 788 789 /* Set force speed */ 790 SOC_IF_ERROR_RETURN 791 (MODIFY_XGXS16G_SERDESDIGITAL_MISC1r(unit, pc, force_speed, 792 SERDESDIGITAL_MISC1_FORCE_SPEED_SEL_MASK | 793 SERDESDIGITAL_MISC1_FORCE_SPEED_MASK)); 794 795 /* Set forced speed in IEEE control register. */ 796 797 if (speed <= 2500) { 798 if (FEATURE_SPEED_100FX(pc)) { 799 SOC_IF_ERROR_RETURN 800 (READ_XGXS16G_SERDESDIGITAL_STATUS1000X1r(unit, pc, &sgmii_status)); 801 802 sgmii_status &= SERDESDIGITAL_STATUS1000X1_SGMII_MODE_MASK; 803 if (!sgmii_status && (speed == 100)) { 804 805 /* fiber mode 100fx, enable */ 806 SOC_IF_ERROR_RETURN 807 (MODIFY_XGXS16G_FX100_CONTROL1r(unit,pc, 808 FX100_CONTROL1_FAR_END_FAULT_EN_MASK | 809 FX100_CONTROL1_ENABLE_MASK, 810 FX100_CONTROL1_FAR_END_FAULT_EN_MASK | 811 FX100_CONTROL1_ENABLE_MASK)); 812 813 /* enable 100fx extended packet size */ 814 SOC_IF_ERROR_RETURN 815 (MODIFY_XGXS16G_FX100_CONTROL2r(unit,pc, 816 FX100_CONTROL2_EXTEND_PKT_SIZE_MASK, 817 FX100_CONTROL2_EXTEND_PKT_SIZE_MASK)); 818 } else { 819 SOC_IF_ERROR_RETURN 820 (READ_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, &data16)); 821 data16 &= ~(MII_CTRL_SS_LSB | MII_CTRL_SS_MSB); 822 data16 |= speed_mii; 823 SOC_IF_ERROR_RETURN 824 (WRITE_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, data16)); 825 } 826 827 } else { 828 SOC_IF_ERROR_RETURN 829 (READ_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, &data16)); 830 data16 &= ~(MII_CTRL_SS_LSB | MII_CTRL_SS_MSB); 831 data16 |= speed_mii; 832 SOC_IF_ERROR_RETURN 833 (WRITE_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, data16)); 834 } 835 } 836 837 /* Bring PLL out of reset */ 838 SOC_IF_ERROR_RETURN 839 (MODIFY_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, 840 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK, 841 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK)); 842 (void) _phy_xgxs16g_pll_lock_wait(unit, port); 843 844 return (SOC_E_NONE); 845 } 846 847 /* 848 * Function: 849 * phy_xgxs16g_speed_get 850 * Purpose: 851 * Get PHY speed 852 * Parameters: 853 * unit - StrataSwitch unit #. 854 * port - StrataSwitch port #. 855 * speed - current link speed in Mbps 856 * Returns: 857 * SOC_E_NONE 858 */ 859 STATIC int 860 phy_xgxs16g_speed_get(int unit, soc_port_t port, int *speed) 861 { 862 phy_ctrl_t *pc; 863 uint16 hw_speed; 864 int autoneg; 865 866 static int actual_speed[] = {10, /* 0 */ 867 100, /* 1 */ 868 1000, /* 2 */ 869 2500, /* 3 */ 870 5000, /* 4 */ 871 6000, /* 5 */ 872 10000, /* 6 */ 873 10000, /* 7 */ 874 12000, /* 8 */ 875 12500, /* 9 */ 876 13000, /* A */ 877 15000, /* B */ 878 16000, /* C */ 879 1000, /* D KX */ 880 10000}; /* E KX4*/ 881 static int forced_speed[] = {2500, /* 0 */ 882 5000, /* 1 */ 883 6000, /* 2 */ 884 10000, /* 3 */ 885 10000, /* 4 */ 886 12000, /* 5 */ 887 12500, /* 6 */ 888 13000, /* 7 */ 889 15000, /* 8 */ 890 16000}; /* 9 */ 891 892 SOC_IF_ERROR_RETURN 893 (phy_xgxs16g_an_get(unit, port, &autoneg, NULL)); 894 895 /* Set reasonable default speed */ 896 *speed = 10000; 897 pc = INT_PHY_SW_STATE(unit, port); 898 if (autoneg) { 899 /* Get actual speed */ 900 SOC_IF_ERROR_RETURN 901 (READ_XGXS16G_GP_STATUS_TOPANSTATUS1r(unit, pc, &hw_speed)); 902 hw_speed = (hw_speed & GP_STATUS_TOPANSTATUS1_ACTUAL_SPEED_MASK) >> 903 GP_STATUS_TOPANSTATUS1_ACTUAL_SPEED_SHIFT; 904 if (hw_speed < COUNTOF(actual_speed)) { 905 *speed = actual_speed[hw_speed]; 906 } else { 907 return (SOC_E_INTERNAL); 908 } 909 } else { 910 /* Get forced speed */ 911 SOC_IF_ERROR_RETURN 912 (READ_XGXS16G_SERDESDIGITAL_MISC1r(unit, pc, &hw_speed)); 913 if (hw_speed & SERDESDIGITAL_MISC1_FORCE_SPEED_SEL_MASK) { 914 hw_speed = (hw_speed & SERDESDIGITAL_MISC1_FORCE_SPEED_MASK) >> 915 SERDESDIGITAL_MISC1_FORCE_SPEED_SHIFT; 916 if (hw_speed < COUNTOF(forced_speed)){ 917 *speed = forced_speed[hw_speed]; 918 } else { 919 return (SOC_E_INTERNAL); 920 } 921 } else { 922 uint16 speed_mii; 923 SOC_IF_ERROR_RETURN 924 (READ_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, &speed_mii)); 925 speed_mii &= (MII_CTRL_SS_LSB | MII_CTRL_SS_MSB); 926 switch (speed_mii) { 927 case MII_CTRL_SS_10: 928 *speed = 10; 929 break; 930 case MII_CTRL_SS_100: 931 *speed = 100; 932 break; 933 case MII_CTRL_SS_1000: 934 *speed = 1000; 935 break; 936 case (MII_CTRL_SS_MSB | MII_CTRL_SS_LSB): 937 *speed = 2500; 938 break; 939 default: 940 *speed = pc->speed_max; 941 break; 942 } 943 } 944 } 945 946 LOG_INFO(BSL_LS_SOC_PHY, 947 (BSL_META_U(unit, 948 "phy_xgxs16g_speed_get: u=%d p=%d GP_STATUS_TOPANSTATUS1 %04x speed= %d\n"), 949 unit, port, hw_speed,*speed)); 950 951 return (SOC_E_NONE); 952 } 953 /* 954 * Function: 955 * phy_xgxs16g_master_get 956 * Purpose: 957 * this function is meant for 1000Base-T PHY. Added here to support 958 * internal PHY regression test 959 * Parameters: 960 * unit - StrataSwitch unit #. 961 * port - StrataSwitch port #. 962 * master - (OUT) SOC_PORT_MS_* 963 * Returns: 964 * SOC_E_NONE 965 * Notes: 966 * The master mode is retrieved for the ACTIVE medium. 967 */ 968 969 STATIC int 970 phy_xgxs16g_master_get(int unit, soc_port_t port, int *master) 971 { 972 *master = SOC_PORT_MS_NONE; 973 return SOC_E_NONE; 974 } 975 /* 976 * Function: 977 * phy_xgxs16g_interface_get 978 * Purpose: 979 * this function is meant for 1000Base-T PHY. Added here to support 980 * internal PHY regression test 981 * Parameters: 982 * unit - StrataSwitch unit #. 983 * port - StrataSwitch port #. 984 * master - (OUT) SOC_PORT_IF_* 985 * Returns: 986 * SOC_E_NONE 987 * Notes: 988 * Interface mode is retrieved for the ACTIVE medium. 989 */ 990 991 STATIC int 992 phy_xgxs16g_interface_get(int unit, soc_port_t port, soc_port_if_t *pif) 993 { 994 int serdes_fiber_pref = 0; 995 int speed = 0; 996 SOC_IF_ERROR_RETURN(phy_xgxs16g_speed_get(unit, port, &speed)); 997 switch(speed) 998 { 999 case 10: 1000 case 100: 1001 *pif = SOC_PORT_IF_MII; 1002 break; 1003 case 1000: 1004 serdes_fiber_pref = soc_property_port_get(unit, port, spn_SERDES_FIBER_PREF, 1005 0); 1006 if(serdes_fiber_pref == TRUE) { 1007 *pif = SOC_PORT_IF_GMII; 1008 } else { 1009 *pif = SOC_PORT_IF_SGMII; 1010 } 1011 break; 1012 case 2500: 1013 *pif = SOC_PORT_IF_GMII; 1014 break; 1015 case 10000: 1016 case 13000: 1017 default: 1018 *pif = SOC_PORT_IF_XGMII; 1019 break; 1020 } 1021 return SOC_E_NONE; 1022 } 1023 1024 1025 /* 1026 * Function: 1027 * phy_xgxs16g_an_set 1028 * Purpose: 1029 * Enable or disabled auto-negotiation on the specified port. 1030 * Parameters: 1031 * unit - StrataSwitch unit #. 1032 * port - StrataSwitch port #. 1033 * an - Boolean, if true, auto-negotiation is enabled 1034 * (and/or restarted). If false, autonegotiation is disabled. 1035 * Returns: 1036 * SOC_E_XXX 1037 */ 1038 STATIC int 1039 phy_xgxs16g_an_set(int unit, soc_port_t port, int an) 1040 { 1041 uint16 data16; 1042 uint16 mask16; 1043 int cur_autoneg; 1044 phy_ctrl_t *pc; 1045 1046 pc = INT_PHY_SW_STATE(unit, port); 1047 1048 SOC_IF_ERROR_RETURN 1049 (phy_xgxs16g_an_get(unit, port, &cur_autoneg, NULL)); 1050 1051 /* If request to disable autoneg and autoneg is already disabled, 1052 * do nothing. 1053 */ 1054 if ((!cur_autoneg) && (!an)) { 1055 return (SOC_E_NONE); 1056 } 1057 1058 SOC_IF_ERROR_RETURN 1059 (WRITE_XGXS16G_BAM_NEXTPAGE_MP5_NEXTPAGECTRLr(unit, pc, an ? 1 : 0)); 1060 1061 /* If request to enable autoneg and autoneg is already enabled, 1062 * restart autoneg. 1063 */ 1064 if (cur_autoneg && an) { 1065 SOC_IF_ERROR_RETURN 1066 (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, 1067 MII_CTRL_AE | MII_CTRL_RAN, 1068 MII_CTRL_AE | MII_CTRL_RAN)); 1069 if (PHY_CLAUSE73_MODE(unit, port)) { 1070 SOC_IF_ERROR_RETURN 1071 (MODIFY_XGXS16G_AN_CL73_REG(unit, pc,MII_CTRL_REG, 1072 MII_CTRL_AE, 1073 MII_CTRL_AE)); 1074 } 1075 } 1076 1077 /* Do the following sequence if changing autoneg setting. */ 1078 /* Stop PLL Sequencer */ 1079 SOC_IF_ERROR_RETURN 1080 (MODIFY_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, 0, 1081 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK)); 1082 1083 /* Disable/Enable 10G parallel detect */ 1084 data16 = 0; 1085 mask16 = AN73_PDET_PARDET10GCONTROL_PARDET10G_EN_MASK; 1086 if (soc_property_port_get(unit, port, spn_XGXS_PDETECT_10G, 1) && an) { 1087 data16 = AN73_PDET_PARDET10GCONTROL_PARDET10G_EN_MASK; 1088 } 1089 SOC_IF_ERROR_RETURN 1090 (MODIFY_XGXS16G_AN73_PDET_PARDET10GCONTROLr(unit, pc, data16, mask16)); 1091 1092 /* Disable/Enable 1000X parallel detect */ 1093 data16 = SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK; 1094 mask16 = SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK; 1095 SOC_IF_ERROR_RETURN 1096 (MODIFY_XGXS16G_SERDESDIGITAL_CONTROL1000X2r(unit, pc, data16, mask16)); 1097 1098 /* Clause 73 backplane support */ 1099 if (PHY_CLAUSE73_MODE(unit, port)) { 1100 1101 } 1102 1103 /* Enable autoneg and restart autoneg */ 1104 data16 = (an) ? MII_CTRL_AE | MII_CTRL_RAN : 0; 1105 mask16 = MII_CTRL_AE | MII_CTRL_RAN; 1106 SOC_IF_ERROR_RETURN 1107 (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, data16, mask16)); 1108 1109 if (PHY_CLAUSE73_MODE(unit, port)) { 1110 SOC_IF_ERROR_RETURN 1111 (MODIFY_XGXS16G_AN_CL73_REG(unit, pc, MII_CTRL_REG, 1112 data16, 1113 mask16)); 1114 } 1115 1116 /* Start PLL Sequencer and wait for PLL to lock */ 1117 SOC_IF_ERROR_RETURN 1118 (MODIFY_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, 1119 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK, 1120 XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK)); 1121 (void) _phy_xgxs16g_pll_lock_wait(unit, port); 1122 1123 return (SOC_E_NONE); 1124 } 1125 1126 /* 1127 * Function: 1128 * phy_xgxs16g_an_get 1129 * Purpose: 1130 * Get the current auto-negotiation status (enabled/busy) 1131 * Parameters: 1132 * unit - StrataSwitch unit #. 1133 * port - StrataSwitch port #. 1134 * an - (OUT) if true, auto-negotiation is enabled. 1135 * an_done - (OUT) if true, auto-negotiation is complete. This 1136 * value is undefined if an == false. 1137 * Returns: 1138 * SOC_E_XXX 1139 */ 1140 1141 STATIC int 1142 phy_xgxs16g_an_get(int unit, soc_port_t port, int *an, int *an_done) 1143 { 1144 uint16 mii_ctrl; 1145 uint16 an_status; 1146 phy_ctrl_t *pc; 1147 1148 pc = INT_PHY_SW_STATE(unit, port); 1149 1150 SOC_IF_ERROR_RETURN 1151 (READ_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, &mii_ctrl)); 1152 *an = ((mii_ctrl & MII_CTRL_AE) != 0); 1153 1154 if (NULL != an_done) { 1155 SOC_IF_ERROR_RETURN 1156 (READ_XGXS16G_GP_STATUS_TOPANSTATUS1r(unit, pc, &an_status)); 1157 *an_done = ((an_status & 1158 GP_STATUS_TOPANSTATUS1_CL37_AUTONEG_COMPLETE_MASK) != 0); 1159 1160 if (PHY_CLAUSE73_MODE(unit, port)) { 1161 *an_done |= ((an_status & 1162 GP_STATUS_TOPANSTATUS1_CL73_AUTONEG_COMPLETE_MASK) != 1163 0); 1164 } 1165 } 1166 1167 return (SOC_E_NONE); 1168 } 1169 1170 STATIC int 1171 _phy_xgxs16g_c73_adv_local_set(int unit, soc_port_t port, 1172 soc_port_ability_t *ability) 1173 { 1174 uint16 an_adv; 1175 uint16 pause; 1176 phy_ctrl_t *pc; 1177 1178 pc = INT_PHY_SW_STATE(unit, port); 1179 1180 an_adv = (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) ? 1181 CL73_AN_ADV_TECH_1G_KX : 0; 1182 an_adv |= (ability->speed_full_duplex & SOC_PA_SPEED_10GB) ? 1183 CL73_AN_ADV_TECH_10G_KX4 : 0; 1184 1185 SOC_IF_ERROR_RETURN 1186 (MODIFY_XGXS16G_AN_CL73_REG(unit, pc, CL73_AN_ADVERT1_REG, an_adv, 1187 CL73_AN_ADV_TECH_SPEEDS_MASK)); 1188 1189 switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) { 1190 case SOC_PA_PAUSE_TX: 1191 pause = CL73_AN_ADV_ASYM_PAUSE; 1192 break; 1193 case SOC_PA_PAUSE_RX: 1194 pause = CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE; 1195 break; 1196 case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX: 1197 pause = CL73_AN_ADV_PAUSE; 1198 break; 1199 default: 1200 pause = 0; 1201 break; 1202 } 1203 1204 SOC_IF_ERROR_RETURN 1205 (MODIFY_XGXS16G_AN_CL73_REG(unit, pc, CL73_AN_ADVERT0_REG, pause, 1206 (CL73_AN_ADV_PAUSE | 1207 CL73_AN_ADV_ASYM_PAUSE))); 1208 1209 LOG_INFO(BSL_LS_SOC_PHY, 1210 (BSL_META_U(unit, 1211 "_phy_xgxs16g_c73_adv_local_set: u=%d p=%d pause=%08x speeds=%04x,adv=0x%x\n"), 1212 unit, port, pause, an_adv,ability->speed_full_duplex)); 1213 return SOC_E_NONE; 1214 } 1215 1216 STATIC int 1217 _phy_xgxs16g_c73_adv_local_get(int unit, soc_port_t port, 1218 soc_port_ability_t *ability) 1219 { 1220 uint16 an_adv; 1221 soc_port_mode_t speeds,pause; 1222 phy_ctrl_t *pc; 1223 1224 pc = INT_PHY_SW_STATE(unit, port); 1225 1226 SOC_IF_ERROR_RETURN 1227 (READ_XGXS16G_AN_CL73_REG(unit, pc, CL73_AN_ADVERT1_REG, &an_adv)); 1228 1229 speeds = (an_adv & CL73_AN_ADV_TECH_1G_KX) ? SOC_PA_SPEED_1000MB : 0; 1230 speeds |= (an_adv & CL73_AN_ADV_TECH_10G_KX4) ? SOC_PA_SPEED_10GB : 0; 1231 ability->speed_full_duplex |= speeds; 1232 1233 SOC_IF_ERROR_RETURN 1234 (READ_XGXS16G_AN_CL73_REG(unit, pc, CL73_AN_ADVERT0_REG, &an_adv)); 1235 1236 switch (an_adv & (CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE)) { 1237 case CL73_AN_ADV_PAUSE: 1238 pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 1239 break; 1240 case CL73_AN_ADV_ASYM_PAUSE: 1241 pause = SOC_PA_PAUSE_TX; 1242 break; 1243 case CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE: 1244 pause = SOC_PA_PAUSE_RX; 1245 break; 1246 default: 1247 pause = 0; 1248 break; 1249 } 1250 ability->pause = pause; 1251 1252 LOG_INFO(BSL_LS_SOC_PHY, 1253 (BSL_META_U(unit, 1254 "_phy_xgxs16g_c73_adv_local_get: u=%d p=%d pause=%08x speeds=%04x\n"), 1255 unit, port, pause, speeds)); 1256 return SOC_E_NONE; 1257 } 1258 1259 STATIC int 1260 _phy_xgxs16g_c73_adv_remote_get(int unit, soc_port_t port, 1261 soc_port_ability_t *ability) 1262 { 1263 uint16 an_adv; 1264 soc_port_mode_t mode; 1265 phy_ctrl_t *pc; 1266 pc = INT_PHY_SW_STATE(unit, port); 1267 SOC_IF_ERROR_RETURN 1268 (READ_XGXS16G_AN_CL73_REG(unit, pc,CL73_AN_LP_ABILITY1_REG, &an_adv)); 1269 1270 mode = (an_adv & CL73_AN_ADV_TECH_1G_KX) ? SOC_PA_SPEED_1000MB : 0; 1271 mode |= (an_adv & CL73_AN_ADV_TECH_10G_KX4) ? SOC_PA_SPEED_10GB : 0; 1272 ability->speed_full_duplex |= mode; 1273 1274 SOC_IF_ERROR_RETURN 1275 (READ_XGXS16G_AN_CL73_REG(unit, pc, CL73_AN_LP_ABILITY0_REG,&an_adv)); 1276 1277 mode = 0; 1278 switch (an_adv & (CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE)) { 1279 case CL73_AN_ADV_PAUSE: 1280 mode = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 1281 break; 1282 case CL73_AN_ADV_ASYM_PAUSE: 1283 mode = SOC_PA_PAUSE_TX; 1284 break; 1285 case CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE: 1286 mode = SOC_PA_PAUSE_RX; 1287 break; 1288 } 1289 ability->pause = mode; 1290 1291 return SOC_E_NONE; 1292 } 1293 1294 /* 1295 * Function: 1296 * phy_xgxs16g_ability_advert_set 1297 * Purpose: 1298 * Set the current advertisement for auto-negotiation. 1299 * Parameters: 1300 * unit - StrataSwitch unit #. 1301 * port - StrataSwitch port #. 1302 * mode - Port mode mask indicating supported options/speeds. 1303 * Returns: 1304 * SOC_E_XXX 1305 * Notes: 1306 * The advertisement is set only for the ACTIVE medium. 1307 * No synchronization performed at this level. 1308 */ 1309 1310 STATIC int 1311 phy_xgxs16g_ability_advert_set(int unit, soc_port_t port, 1312 soc_port_ability_t *ability) 1313 { 1314 uint16 adv_over1g; 1315 uint16 an_adv; 1316 soc_port_mode_t mode; 1317 phy_ctrl_t *pc; 1318 1319 if (NULL == ability) { 1320 return (SOC_E_PARAM); 1321 } 1322 1323 pc = INT_PHY_SW_STATE(unit, port); 1324 1325 /* Support only full duplex */ 1326 an_adv = (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) ? MII_ANP_C37_FD : 0; 1327 switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) { 1328 case SOC_PA_PAUSE_TX: 1329 an_adv |= MII_ANP_C37_ASYM_PAUSE; 1330 break; 1331 case SOC_PA_PAUSE_RX: 1332 an_adv |= MII_ANP_C37_ASYM_PAUSE | MII_ANP_C37_PAUSE; 1333 break; 1334 case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX: 1335 an_adv |= MII_ANP_C37_PAUSE; 1336 break; 1337 } 1338 SOC_IF_ERROR_RETURN 1339 (WRITE_XGXS16G_COMBO_IEEE0_AUTONEGADVr(unit, pc, an_adv)); 1340 1341 mode = ability->speed_full_duplex; 1342 adv_over1g = 0; 1343 adv_over1g |= (mode & SOC_PA_SPEED_2500MB) ? OVER1G_UP1_DATARATE_2P5GX1_MASK : 0; 1344 if (mode & SOC_PA_SPEED_10GB) { 1345 if (soc_property_port_get(unit, port, spn_10G_IS_CX4, TRUE)) { 1346 adv_over1g |= OVER1G_UP1_DATARATE_10GCX4_MASK; 1347 } else { 1348 adv_over1g |= OVER1G_UP1_DATARATE_10GX4_MASK; 1349 } 1350 } 1351 adv_over1g |= (mode & SOC_PA_SPEED_12GB) ? OVER1G_UP1_DATARATE_12GX4_MASK : 0; 1352 adv_over1g |= (mode & SOC_PA_SPEED_13GB) ? OVER1G_UP1_DATARATE_13GX4_MASK : 0; 1353 adv_over1g |= (mode & SOC_PA_SPEED_16GB) ? OVER1G_UP1_DATARATE_16GX4_MASK : 0; 1354 SOC_IF_ERROR_RETURN 1355 (WRITE_XGXS16G_OVER1G_UP1r(unit, pc, adv_over1g)); 1356 1357 if (PHY_CLAUSE73_MODE(unit, port)) { 1358 SOC_IF_ERROR_RETURN 1359 (_phy_xgxs16g_c73_adv_local_set(unit, port, ability)); 1360 } 1361 1362 LOG_INFO(BSL_LS_SOC_PHY, 1363 (BSL_META_U(unit, 1364 "phy_xgxs16g_ability_advert_set:u=%d p=%d pause=%08x OVER1G_UP1 %04x\n"), 1365 unit, port, ability->pause, an_adv)); 1366 1367 return (SOC_E_NONE); 1368 } 1369 1370 /* 1371 * Function: 1372 * phy_xgxs16g_ability_advert_get 1373 * Purpose: 1374 * Get the current advertisement for auto-negotiation. 1375 * Parameters: 1376 * unit - StrataSwitch unit #. 1377 * port - StrataSwitch port #. 1378 * mode - (OUT) Port mode mask indicating supported options/speeds. 1379 * Returns: 1380 * SOC_E_XXX 1381 * Notes: 1382 * The advertisement is retrieved for the ACTIVE medium. 1383 * No synchronization performed at this level. 1384 */ 1385 1386 STATIC int 1387 phy_xgxs16g_ability_advert_get(int unit, soc_port_t port, 1388 soc_port_ability_t *ability) 1389 { 1390 uint16 adv_over1g; 1391 uint16 an_adv; 1392 soc_port_mode_t mode; 1393 phy_ctrl_t *pc; 1394 1395 if (NULL == ability) { 1396 return (SOC_E_PARAM); 1397 } 1398 1399 pc = INT_PHY_SW_STATE(unit, port); 1400 1401 sal_memset(ability, 0, sizeof(*ability)); 1402 mode = 0; 1403 SOC_IF_ERROR_RETURN 1404 (READ_XGXS16G_COMBO_IEEE0_AUTONEGADVr(unit, pc, &an_adv)); 1405 1406 switch (an_adv & (MII_ANP_C37_ASYM_PAUSE | MII_ANP_C37_PAUSE)) { 1407 case MII_ANP_C37_ASYM_PAUSE: 1408 mode |= SOC_PA_PAUSE_TX; 1409 break; 1410 case (MII_ANP_C37_ASYM_PAUSE | MII_ANP_C37_PAUSE): 1411 mode |= SOC_PA_PAUSE_RX; 1412 break; 1413 case MII_ANP_C37_PAUSE: 1414 mode |= SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 1415 break; 1416 } 1417 ability->pause = mode; 1418 1419 mode = 0; 1420 mode |= (an_adv & MII_ANP_C37_FD) ? SOC_PA_SPEED_1000MB : 0; 1421 SOC_IF_ERROR_RETURN 1422 (READ_XGXS16G_OVER1G_UP1r(unit, pc, &adv_over1g)); 1423 mode |= (adv_over1g & OVER1G_UP1_DATARATE_2P5GX1_MASK) ? 1424 SOC_PA_SPEED_2500MB : 0; 1425 mode |= (adv_over1g & OVER1G_UP1_DATARATE_10GCX4_MASK) ? 1426 SOC_PA_SPEED_10GB : 0; 1427 mode |= (adv_over1g & OVER1G_UP1_DATARATE_10GX4_MASK) ? 1428 SOC_PA_SPEED_10GB : 0; 1429 mode |= (adv_over1g & OVER1G_UP1_DATARATE_12GX4_MASK) ? 1430 SOC_PA_SPEED_12GB : 0; 1431 mode |= (adv_over1g & OVER1G_UP1_DATARATE_13GX4_MASK) ? 1432 SOC_PA_SPEED_13GB : 0; 1433 mode |= (adv_over1g & OVER1G_UP1_DATARATE_16GX4_MASK) ? 1434 SOC_PA_SPEED_16GB : 0; 1435 1436 ability->speed_full_duplex = mode; 1437 1438 /* check for clause73 */ 1439 if (PHY_CLAUSE73_MODE(unit, port)) { 1440 SOC_IF_ERROR_RETURN 1441 (_phy_xgxs16g_c73_adv_local_get(unit, port, ability)); 1442 } 1443 1444 LOG_INFO(BSL_LS_SOC_PHY, 1445 (BSL_META_U(unit, 1446 "phy_xgxs16g_ability_advert_get:unit=%d p=%d pause=%08x sp=%08x\n"), 1447 unit, port, ability->pause, ability->speed_full_duplex)); 1448 1449 return (SOC_E_NONE); 1450 } 1451 1452 /* 1453 * Function: 1454 * phy_xgxs16g_ability_remote_get 1455 * Purpose: 1456 * Get the current advertisement for auto-negotiation. 1457 * Parameters: 1458 * unit - StrataSwitch unit #. 1459 * port - StrataSwitch port #. 1460 * mode - (OUT) Port mode mask indicating supported options/speeds. 1461 * Returns: 1462 * SOC_E_XXX 1463 * Notes: 1464 * The advertisement is retrieved for the ACTIVE medium. 1465 * No synchronization performed at this level. 1466 */ 1467 1468 STATIC int 1469 phy_xgxs16g_ability_remote_get(int unit, soc_port_t port, 1470 soc_port_ability_t *ability) 1471 { 1472 uint16 an_status; 1473 uint16 an_done; 1474 uint16 link_stat_gp; 1475 uint16 an_adv; 1476 soc_port_mode_t mode; 1477 phy_ctrl_t *pc; 1478 1479 if (NULL == ability) { 1480 return (SOC_E_PARAM); 1481 } 1482 1483 pc = INT_PHY_SW_STATE(unit, port); 1484 1485 SOC_IF_ERROR_RETURN 1486 (READ_XGXS16G_GP_STATUS_TOPANSTATUS1r(unit, pc, &an_status)); 1487 1488 an_done = an_status & (GP_STATUS_TOPANSTATUS1_CL37_AUTONEG_COMPLETE_MASK | 1489 GP_STATUS_TOPANSTATUS1_CL73_AUTONEG_COMPLETE_MASK); 1490 link_stat_gp = an_status & GP_STATUS_TOPANSTATUS1_LINK_STATUS_MASK; 1491 LOG_INFO(BSL_LS_SOC_PHY, 1492 (BSL_META_U(unit, 1493 "u=%d p=%d an_status=%04x link_stat_gp=%04x\n"), 1494 unit, port, an_status, link_stat_gp)); 1495 1496 sal_memset(ability, 0, sizeof(*ability)); 1497 1498 mode = 0; 1499 if (link_stat_gp && an_done) { 1500 /* Decode remote advertisement only when link is up and autoneg is 1501 * completed. 1502 */ 1503 1504 if (an_status & GP_STATUS_TOPANSTATUS1_CL37_AUTONEG_COMPLETE_MASK) { 1505 SOC_IF_ERROR_RETURN 1506 (READ_XGXS16G_GP_STATUS_LP_UP1r(unit, pc, &an_adv)); 1507 mode |= (an_adv & OVER1G_LP_UP1_DATARATE_16GX4_MASK) ? 1508 SOC_PA_SPEED_16GB : 0; 1509 mode |= (an_adv & OVER1G_LP_UP1_DATARATE_13GX4_MASK) ? 1510 SOC_PA_SPEED_13GB : 0; 1511 mode |= (an_adv & OVER1G_LP_UP1_DATARATE_12GX4_MASK) ? 1512 SOC_PA_SPEED_12GB : 0; 1513 mode |= (an_adv & OVER1G_LP_UP1_DATARATE_10GCX4_MASK) ? 1514 SOC_PA_SPEED_10GB : 0; 1515 mode |= (an_adv & OVER1G_LP_UP1_DATARATE_10GX4_MASK) ? 1516 SOC_PA_SPEED_10GB : 0; 1517 mode |= (an_adv & OVER1G_LP_UP1_DATARATE_2P5GX1_MASK) ? 1518 SOC_PA_SPEED_2500MB : 0; 1519 1520 LOG_INFO(BSL_LS_SOC_PHY, 1521 (BSL_META_U(unit, 1522 "u=%d p=%d over1G an_adv=%04x\n"), 1523 unit, port, an_adv)); 1524 SOC_IF_ERROR_RETURN 1525 (READ_XGXS16G_COMBO_IEEE0_AUTONEGLPABILr(unit, pc, &an_adv)); 1526 LOG_INFO(BSL_LS_SOC_PHY, 1527 (BSL_META_U(unit, 1528 "u=%d p=%d combo an_adv=%04x\n"), 1529 unit, port, an_adv)); 1530 1531 mode |= (an_adv & MII_ANP_C37_FD) ? SOC_PA_SPEED_1000MB : 0; 1532 ability->speed_full_duplex = mode; 1533 1534 mode = 0; 1535 switch (an_adv & (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) { 1536 case MII_ANP_C37_PAUSE: 1537 mode |= SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 1538 break; 1539 case MII_ANP_C37_ASYM_PAUSE: 1540 mode |= SOC_PA_PAUSE_TX; 1541 break; 1542 case MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE: 1543 mode |= SOC_PA_PAUSE_RX; 1544 break; 1545 } 1546 ability->pause = mode; 1547 } 1548 if (an_status & GP_STATUS_TOPANSTATUS1_CL73_AUTONEG_COMPLETE_MASK) { 1549 if (PHY_CLAUSE73_MODE(unit, port)) { 1550 SOC_IF_ERROR_RETURN 1551 (_phy_xgxs16g_c73_adv_remote_get(unit, port, ability)); 1552 } 1553 } 1554 } else { 1555 /* Simply return local abilities */ 1556 phy_xgxs16g_ability_advert_get(unit, port, ability); 1557 } 1558 LOG_INFO(BSL_LS_SOC_PHY, 1559 (BSL_META_U(unit, 1560 "phy_xgxs16g_ability_remote_get:unit=%d p=%d pause=%08x sp=%08x\n"), 1561 unit, port, ability->pause, ability->speed_full_duplex)); 1562 1563 return (SOC_E_NONE); 1564 } 1565 1566 1567 /* 1568 * Function: 1569 * phy_xgxs16g_lb_set 1570 * Purpose: 1571 * Put XGXS6/FusionCore in PHY loopback 1572 * Parameters: 1573 * unit - StrataSwitch unit #. 1574 * port - StrataSwitch port #. 1575 * enable - binary value for on/off (1/0) 1576 * Returns: 1577 * SOC_E_NONE 1578 */ 1579 1580 STATIC int 1581 phy_xgxs16g_lb_set(int unit, soc_port_t port, int enable) 1582 { 1583 uint16 misc_ctrl; 1584 uint16 lb_bit; 1585 uint16 lb_mask; 1586 phy_ctrl_t *pc; 1587 1588 pc = INT_PHY_SW_STATE(unit, port); 1589 1590 /* Configure Loopback in XAUI */ 1591 SOC_IF_ERROR_RETURN 1592 (READ_XGXS16G_XGXSBLK0_MISCCONTROL1r(unit, pc, &misc_ctrl)); 1593 if (misc_ctrl & XGXSBLK0_MISCCONTROL1_PCS_DEV_EN_OVERRIDE_MASK) { 1594 /* PCS */ 1595 lb_bit = (enable) ? IEEE0BLK_IEEECONTROL0_GLOOPBACK_MASK : 0; 1596 lb_mask = IEEE0BLK_IEEECONTROL0_GLOOPBACK_MASK; 1597 } else if (misc_ctrl & XGXSBLK0_MISCCONTROL1_PMD_DEV_EN_OVERRIDE_MASK) { 1598 /* PMA/PMD */ 1599 lb_bit = (enable) ? 1 : 0; 1600 lb_mask = 1; 1601 } else { 1602 /* PHY XS, DTE XS */ 1603 lb_bit = (enable) ? IEEE0BLK_IEEECONTROL0_GLOOPBACK_MASK : 0; 1604 lb_mask = IEEE0BLK_IEEECONTROL0_GLOOPBACK_MASK; 1605 } 1606 SOC_IF_ERROR_RETURN 1607 (MODIFY_XGXS16G_IEEE0BLK_IEEECONTROL0r(unit, pc, lb_bit, lb_mask)); 1608 1609 /* Configure Loopback in SerDes */ 1610 SOC_IF_ERROR_RETURN 1611 (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, 1612 (enable) ? MII_CTRL_LE : 0, 1613 MII_CTRL_LE)); 1614 1615 return (SOC_E_NONE); 1616 } 1617 1618 /* 1619 * Function: 1620 * phy_xgxs16g_lb_get 1621 * Purpose: 1622 * Get XGXS6/FusionCore PHY loopback state 1623 * Parameters: 1624 * unit - StrataSwitch unit #. 1625 * port - StrataSwitch port #. 1626 * enable - address of location to store binary value for on/off (1/0) 1627 * Returns: 1628 * SOC_E_NONE 1629 */ 1630 1631 STATIC int 1632 phy_xgxs16g_lb_get(int unit, soc_port_t port, int *enable) 1633 { 1634 uint16 mii_ctrl; 1635 phy_ctrl_t *pc; 1636 1637 pc = INT_PHY_SW_STATE(unit, port); 1638 1639 SOC_IF_ERROR_RETURN 1640 (READ_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, &mii_ctrl)); 1641 *enable = ((mii_ctrl & MII_CTRL_LE) == MII_CTRL_LE); 1642 1643 return (SOC_E_NONE); 1644 } 1645 1646 1647 STATIC int 1648 phy_xgxs16g_ability_local_get(int unit, soc_port_t port, 1649 soc_port_ability_t *ability) 1650 { 1651 phy_ctrl_t *pc; 1652 1653 if (NULL == ability) { 1654 return (SOC_E_PARAM); 1655 } 1656 1657 pc = INT_PHY_SW_STATE(unit, port); 1658 1659 ability->speed_half_duplex = SOC_PA_ABILITY_NONE; 1660 ability->pause = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 1661 ability->interface = SOC_PA_INTF_XGMII; 1662 ability->medium = SOC_PA_MEDIUM_COPPER; 1663 ability->loopback = SOC_PA_LB_PHY; 1664 ability->flags = SOC_PA_AUTONEG; 1665 1666 ability->speed_full_duplex = SOC_PA_SPEED_1000MB | SOC_PA_SPEED_2500MB; 1667 if (FEATURE_SPEED_100FX(pc)) { 1668 ability->speed_full_duplex |= SOC_PA_SPEED_100MB; 1669 } 1670 1671 /* 1672 * If not in fiber mode or in copper mode, advertise 10/100 Mbps 1673 * capability. Other wise assume 1000X mode of operation for 1674 * below 10Gbps speed operation. 1675 */ 1676 if (!PHY_FIBER_MODE(unit, port) || PHY_COPPER_MODE(unit, port)) { 1677 if (IS_XE_PORT(unit, port)) { 1678 ability->speed_half_duplex |= SOC_PA_SPEED_10MB | 1679 SOC_PA_SPEED_100MB; 1680 ability->speed_full_duplex |= SOC_PA_SPEED_10MB | 1681 SOC_PA_SPEED_100MB; 1682 } else if (IS_GE_PORT(unit, port)) { 1683 ability->speed_half_duplex |= SOC_PA_SPEED_10MB | 1684 SOC_PA_SPEED_100MB; 1685 ability->speed_full_duplex |= SOC_PA_SPEED_10MB | 1686 SOC_PA_SPEED_100MB; 1687 ability->speed_full_duplex &= ~SOC_PA_SPEED_2500MB; 1688 } 1689 } 1690 switch(pc->speed_max) { 1691 case 16000: 1692 ability->speed_full_duplex |= SOC_PA_SPEED_16GB; 1693 /* fall through */ 1694 case 13000: 1695 ability->speed_full_duplex |= SOC_PA_SPEED_13GB; 1696 /* fall through */ 1697 case 12000: 1698 ability->speed_full_duplex |= SOC_PA_SPEED_12GB; 1699 /* fall through */ 1700 default: 1701 ability->speed_full_duplex |= SOC_PA_SPEED_10GB; 1702 break; 1703 } 1704 1705 return (SOC_E_NONE); 1706 } 1707 1708 1709 STATIC int 1710 _phy_xgxs16g_tx_driver_field_get(phy_ctrl_t *pc, soc_phy_control_t type, 1711 int *ln_ctrl, uint16 *mask, int *shfter) 1712 { 1713 int lane_ctrl; 1714 int is_40nm; 1715 1716 is_40nm = XGXS16G_13G_ID(pc); 1717 lane_ctrl = TX_DRIVER_DFT_LN_CTRL; 1718 *mask = 0; 1719 *shfter = 0; 1720 /* _LANEn(n=0-3) control type only applies to combo mode or dxgxs in 1721 * independent channel mode 1722 */ 1723 1724 switch(type) { 1725 case SOC_PHY_CONTROL_PREEMPHASIS_LANE0: 1726 /* fall through */ 1727 case SOC_PHY_CONTROL_PREEMPHASIS_LANE1: 1728 /* fall through */ 1729 case SOC_PHY_CONTROL_PREEMPHASIS_LANE2: 1730 /* fall through */ 1731 case SOC_PHY_CONTROL_PREEMPHASIS_LANE3: 1732 /* fall through */ 1733 case SOC_PHY_CONTROL_PREEMPHASIS: 1734 *shfter = is_40nm ? TX_ALL_040_TX_DRIVER_PREEMPHASIS_POST_SHIFT : 1735 TX_ALL_TX_DRIVER_PREEMPHASIS_SHIFT; 1736 *mask = is_40nm ? TX_ALL_040_TX_DRIVER_PREEMPHASIS_POST_MASK : 1737 TX_ALL_TX_DRIVER_PREEMPHASIS_MASK; 1738 if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE0) { 1739 lane_ctrl = 0; 1740 } else if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE1) { 1741 lane_ctrl = 1; 1742 } else if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE2) { 1743 lane_ctrl = 2; 1744 } else if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE3) { 1745 lane_ctrl = 3; 1746 } 1747 break; 1748 1749 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0: 1750 /* fall through */ 1751 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1: 1752 /* fall through */ 1753 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2: 1754 /* fall through */ 1755 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3: 1756 /* fall through */ 1757 case SOC_PHY_CONTROL_DRIVER_CURRENT: 1758 *shfter = is_40nm ? TX_ALL_040_TX_DRIVER_IDRIVER_SHIFT : 1759 TX_ALL_TX_DRIVER_IDRIVER_SHIFT; 1760 *mask = is_40nm ? TX_ALL_040_TX_DRIVER_IDRIVER_MASK : 1761 TX_ALL_TX_DRIVER_IDRIVER_MASK; 1762 if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0) { 1763 lane_ctrl = 0; 1764 } else if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1) { 1765 lane_ctrl = 1; 1766 } else if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2) { 1767 lane_ctrl = 2; 1768 } else if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3) { 1769 lane_ctrl = 3; 1770 } 1771 break; 1772 1773 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0: 1774 /* fall through */ 1775 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1: 1776 /* fall through */ 1777 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2: 1778 /* fall through */ 1779 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3: 1780 /* fall through */ 1781 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 1782 if(is_40nm) { 1783 /* 40nm analog does not support pre driver configuration */ 1784 *shfter = 0; 1785 *mask = 0; 1786 } else { 1787 *shfter = TX_ALL_TX_DRIVER_IPREDRIVER_SHIFT; 1788 *mask = TX_ALL_TX_DRIVER_IPREDRIVER_MASK; 1789 } 1790 if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0) { 1791 lane_ctrl = 0; 1792 } else if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1) { 1793 lane_ctrl = 1; 1794 } else if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2) { 1795 lane_ctrl = 2; 1796 1797 /* coverity[mixed_enums:FALSE] */ 1798 } else if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3) { 1799 lane_ctrl = 3; 1800 } 1801 break; 1802 default: 1803 /* should never get here */ 1804 return SOC_E_PARAM; 1805 } 1806 *ln_ctrl = lane_ctrl; 1807 return SOC_E_NONE; 1808 } 1809 1810 STATIC int 1811 _phy_xgxs16g_control_tx_driver_set(int unit, phy_ctrl_t *pc, 1812 soc_phy_control_t type, uint32 value) 1813 { 1814 uint16 data; /* Temporary holder of reg value to be written */ 1815 uint16 mask; /* Bit mask of reg value to be updated */ 1816 int lane_ctrl; 1817 int shifter; 1818 int is_40nm; 1819 1820 if (value > 15) { 1821 return SOC_E_PARAM; 1822 } 1823 1824 SOC_IF_ERROR_RETURN 1825 (_phy_xgxs16g_tx_driver_field_get(pc, type,&lane_ctrl,&mask,&shifter)); 1826 1827 is_40nm = XGXS16G_13G_ID(pc); 1828 data = value << shifter; 1829 1830 switch (lane_ctrl) { 1831 case 0: 1832 SOC_IF_ERROR_RETURN 1833 (is_40nm ? 1834 MODIFY_XGXS13G_040_TX0_ACONTROL1r(unit, pc, data, mask) : 1835 MODIFY_XGXS16G_TX0_TX_DRIVERr(unit, pc, data, mask)); 1836 break; 1837 case 1: 1838 SOC_IF_ERROR_RETURN 1839 (is_40nm ? 1840 MODIFY_XGXS13G_040_TX1_ACONTROL1r(unit, pc, data, mask) : 1841 MODIFY_XGXS16G_TX1_TX_DRIVERr(unit, pc, data, mask)); 1842 break; 1843 case 2: 1844 SOC_IF_ERROR_RETURN 1845 (is_40nm ? 1846 MODIFY_XGXS13G_040_TX2_ACONTROL1r(unit, pc, data, mask) : 1847 MODIFY_XGXS16G_TX2_TX_DRIVERr(unit, pc, data, mask)); 1848 break; 1849 case 3: 1850 SOC_IF_ERROR_RETURN 1851 (is_40nm ? 1852 MODIFY_XGXS13G_040_TX3_ACONTROL1r(unit, pc, data, mask) : 1853 MODIFY_XGXS16G_TX3_TX_DRIVERr(unit, pc, data, mask)); 1854 break; 1855 case TX_DRIVER_DFT_LN_CTRL: 1856 SOC_IF_ERROR_RETURN 1857 (is_40nm ? 1858 MODIFY_XGXS13G_040_TX_ALL_ACONTROL1r(unit, pc, data, mask) : 1859 MODIFY_XGXS16G_TX_ALL_TX_DRIVERr(unit, pc, data, mask)); 1860 break; 1861 default: 1862 break; 1863 } 1864 #if 0 1865 int lane_num; 1866 if (lane_ctrl != TX_DRIVER_DFT_LN_CTRL) { 1867 lane_num = lane_ctrl; 1868 if (lane_num == 0) { 1869 SOC_IF_ERROR_RETURN 1870 (MODIFY_XGXS16G_TX0_TX_DRIVERr(unit, pc, data, mask)); 1871 } else if (lane_num == 1) { 1872 SOC_IF_ERROR_RETURN 1873 (MODIFY_XGXS16G_TX1_TX_DRIVERr(unit, pc, data, mask)); 1874 } else if (lane_num == 2) { 1875 SOC_IF_ERROR_RETURN 1876 (MODIFY_XGXS16G_TX2_TX_DRIVERr(unit, pc, data, mask)); 1877 } else if (lane_num == 3) { 1878 SOC_IF_ERROR_RETURN 1879 (MODIFY_XGXS16G_TX3_TX_DRIVERr(unit, pc, data, mask)); 1880 } 1881 } else { 1882 /* Update preemphasis/driver/pre-driver current */ 1883 SOC_IF_ERROR_RETURN 1884 (MODIFY_XGXS16G_TX0_TX_DRIVERr(unit, pc, data, mask)); 1885 SOC_IF_ERROR_RETURN 1886 (MODIFY_XGXS16G_TX1_TX_DRIVERr(unit, pc, data, mask)); 1887 SOC_IF_ERROR_RETURN 1888 (MODIFY_XGXS16G_TX2_TX_DRIVERr(unit, pc, data, mask)); 1889 SOC_IF_ERROR_RETURN 1890 (MODIFY_XGXS16G_TX3_TX_DRIVERr(unit, pc, data, mask)); 1891 } 1892 #endif 1893 return SOC_E_NONE; 1894 } 1895 1896 1897 STATIC int 1898 _phy_xgxs16g_control_linkdown_transmit_set(int unit, soc_port_t port, 1899 uint32 value) 1900 { 1901 uint16 data; 1902 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 1903 1904 if (value) { 1905 data = (SERDESDIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_BITS << 1906 SERDESDIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_SHIFT) | 1907 (SERDESDIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_BITS << 1908 SERDESDIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_SHIFT) | 1909 (SERDESDIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_BITS << 1910 SERDESDIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_SHIFT); 1911 SOC_IF_ERROR_RETURN 1912 (WRITE_XGXS16G_SERDESDIGITAL_CONTROL1000X2r(unit, pc, data)); 1913 } else { 1914 data = (SERDESDIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_BITS << 1915 SERDESDIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_SHIFT) | 1916 (SERDESDIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_BITS << 1917 SERDESDIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_SHIFT) | 1918 (SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_BITS << 1919 SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_SHIFT); 1920 SOC_IF_ERROR_RETURN 1921 (WRITE_XGXS16G_SERDESDIGITAL_CONTROL1000X2r(unit, pc, data)); 1922 } 1923 return SOC_E_NONE; 1924 } 1925 1926 STATIC int 1927 _phy_xgxs16g_control_linkdown_transmit_get(int unit, soc_port_t port, 1928 uint32 *value) 1929 { 1930 uint16 data; 1931 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 1932 1933 SOC_IF_ERROR_RETURN 1934 (READ_XGXS16G_SERDESDIGITAL_CONTROL1000X2r(unit, pc, &data)); 1935 1936 *value = (data & 1937 (SERDESDIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_BITS << 1938 SERDESDIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_SHIFT)) 1939 ? 1 : 0; 1940 1941 return SOC_E_NONE; 1942 } 1943 1944 1945 1946 STATIC int 1947 _phy_xgxs16g_control_prbs_polynomial_set(int unit, soc_port_t port, uint32 value) 1948 { 1949 uint16 data; 1950 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 1951 1952 value &= 7; 1953 data = 0x8888 | value 1954 |(value << PHY_XGXS16G_LANEPRBS_LANE_SHIFT) 1955 |(value << (PHY_XGXS16G_LANEPRBS_LANE_SHIFT*2)) 1956 |(value << (PHY_XGXS16G_LANEPRBS_LANE_SHIFT*3)); 1957 1958 1959 /* 1960 * write back updated configuration 1961 */ 1962 SOC_IF_ERROR_RETURN 1963 (WRITE_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, data)); 1964 1965 return SOC_E_NONE; 1966 } 1967 1968 STATIC int 1969 _phy_xgxs16g_control_prbs_polynomial_get(int unit, soc_port_t port, uint32 *value) 1970 { 1971 uint16 data; 1972 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);; 1973 1974 SOC_IF_ERROR_RETURN 1975 (READ_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, &data)); 1976 1977 /* Extract prbs polynomial setting from register */ 1978 data = ((data >> (XGXSBLK1_LANEPRBS_PRBS_ORDER1_SHIFT * pc->lane_num)) & 1979 XGXSBLK1_LANEPRBS_PRBS_ORDER0_MASK); 1980 *value = (uint32) data; 1981 1982 return SOC_E_NONE; 1983 } 1984 1985 1986 STATIC int 1987 _phy_xgxs16g_control_prbs_tx_invert_data_set(int unit, soc_port_t port, uint32 value) 1988 { 1989 uint16 data = 0; 1990 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 1991 uint32 lane_mask = 1 << (PHY_XGXS16G_LANEPRBS_LANE_SHIFT * pc->lane_num); 1992 1993 SOC_IF_ERROR_RETURN 1994 (READ_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, &data)); 1995 1996 /* prbs_inv is bit 2 per lane */ 1997 if (value) { 1998 data |= lane_mask << XGXSBLK1_LANEPRBS_PRBS_INV0_SHIFT; 1999 } else { 2000 data &= ~(lane_mask << XGXSBLK1_LANEPRBS_PRBS_INV0_SHIFT); 2001 } 2002 2003 /* write back updated configuration */ 2004 if (value > 0x8000) { 2005 SOC_IF_ERROR_RETURN 2006 (WRITE_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, value)); 2007 } else { 2008 SOC_IF_ERROR_RETURN 2009 (WRITE_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, data)); 2010 } 2011 2012 return SOC_E_NONE; 2013 2014 } 2015 2016 STATIC int 2017 _phy_xgxs16g_control_prbs_tx_invert_data_get(int unit, soc_port_t port, uint32 *value) 2018 { 2019 uint16 data; 2020 uint16 inv_shifter = 0; 2021 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 2022 2023 SOC_IF_ERROR_RETURN 2024 (READ_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, &data)); 2025 2026 2027 inv_shifter = (XGXSBLK1_LANEPRBS_PRBS_ORDER1_SHIFT * pc->lane_num) + 2028 XGXSBLK1_LANEPRBS_PRBS_INV0_SHIFT; 2029 data &= (1 << inv_shifter); 2030 2031 *value = (data) ? 1 : 0; 2032 2033 return SOC_E_NONE; 2034 } 2035 2036 2037 STATIC int 2038 _phy_xgxs16g_control_xgxs_prbs_tx_enable_set(int unit, soc_port_t port, 2039 uint32 value) 2040 { 2041 uint16 data = 0; 2042 uint16 pll_mode = 0; 2043 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 2044 2045 if (value) { 2046 2047 /* First set XAUI mode: 0x8000 = 0x203f */ 2048 SOC_IF_ERROR_RETURN 2049 (WRITE_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x203f)); 2050 2051 sal_usleep(1000); 2052 2053 /* Set double wide div/1: 0x8016=0xffff */ 2054 SOC_IF_ERROR_RETURN 2055 (WRITE_XGXS16G_XGXSBLK1_LANECTRL1r(unit, pc, 0xffff)); 2056 2057 /* clear multiPRT mode: 0x800d=0x0003 */ 2058 /*SOC_IF_ERROR_RETURN 2059 (WRITE_XGXS16G_XGXSBLK0_MMDSELECTr(unit, pc, 0x4003)); 2060 */ 2061 2062 /* Set in individual lane mode, Disable PLL Sequencer: 0x8000=0x063f */ 2063 SOC_IF_ERROR_RETURN 2064 (WRITE_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x063f)); 2065 2066 /* Force VCO based on current operating frequency */ 2067 SOC_IF_ERROR_RETURN 2068 (READ_XGXS16G_PLL_PLLSTATUSr(unit, pc, &pll_mode)); 2069 pll_mode &= 2070 (PLL_PLLSTATUS_PLL_MODE_AFE_MASK | PLL_PLLSTATUS_RESERVED0_MASK); 2071 SOC_IF_ERROR_RETURN 2072 (READ_XGXS16G_SERDESDIGITAL_MISC1r(unit, pc, &data)); 2073 data &= ~SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_MASK; 2074 data |= SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_MASK | 2075 (pll_mode << SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SHIFT); 2076 SOC_IF_ERROR_RETURN 2077 (WRITE_XGXS16G_SERDESDIGITAL_MISC1r(unit, pc, data)); 2078 2079 /* Disable asymmetric mode for 40nm UC_B0 */ 2080 if(XGXS16G_13G_REV_B0(pc)){ 2081 SOC_IF_ERROR_RETURN 2082 (MODIFY_XGXS16G_XGXSBLK8_TXLNSWAP1r(unit, pc, 0, 2083 XGXSBLK8_TXLNSWAP1_ASYMM_EN_MASK)); 2084 } 2085 /* Turn AN off: 0x0=0x0 */ 2086 SOC_IF_ERROR_RETURN 2087 (WRITE_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, 0)); 2088 2089 /* Turn CL36 PCS off: 0x8015=0x0 */ 2090 SOC_IF_ERROR_RETURN 2091 (WRITE_XGXS16G_XGXSBLK1_LANECTRL0r(unit, pc, 0)); 2092 2093 /* Put port in loopback if requested */ 2094 data = ((value & 0x8000) == 0x8000) ? 2095 XGXSBLK1_LANECTRL2_GLOOP1G_MASK : 0; 2096 /* CDED & EDEN off: 0x8017 */ 2097 SOC_IF_ERROR_RETURN 2098 (WRITE_XGXS16G_XGXSBLK1_LANECTRL2r(unit, pc, data)); 2099 2100 /* PRBS Polynomial for all lanes: 0x8019=0x8888 */ 2101 SOC_IF_ERROR_RETURN 2102 (READ_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, &data)); 2103 data |= 0x8888; 2104 SOC_IF_ERROR_RETURN 2105 (WRITE_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, data)); 2106 2107 2108 /* Enable PRBS read: 0x80f1=0x1c47 */ 2109 SOC_IF_ERROR_RETURN 2110 (WRITE_XGXS16G_RX_ALL_RX_CONTROLr(unit, pc, 0x1c47)); 2111 2112 /* Enable PLL Sequencer: 0x8000=0x263f */ 2113 SOC_IF_ERROR_RETURN 2114 (WRITE_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x263f)); 2115 2116 /* Delay a while */ 2117 sal_usleep(250000); 2118 } else { 2119 /* Restore port */ 2120 return phy_xgxs16g_init(unit, port); 2121 } 2122 return SOC_E_NONE; 2123 } 2124 2125 STATIC int 2126 _phy_xgxs16g_control_prbs_tx_enable_set(int unit, soc_port_t port, uint32 value) 2127 { 2128 2129 SOC_IF_ERROR_RETURN( 2130 _phy_xgxs16g_control_xgxs_prbs_tx_enable_set(unit, port, value)); 2131 return SOC_E_NONE; 2132 } 2133 2134 2135 STATIC int 2136 _phy_xgxs16g_control_prbs_tx_rx_enable_get(int unit, soc_port_t port, 2137 uint32 *value) 2138 { 2139 uint16 data; 2140 uint16 inv_shifter = 0; 2141 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 2142 2143 /* 2144 * Hypercore PRBS - note that in the Hypercore there is only 1 enable 2145 * for both TX/RX 2146 */ 2147 SOC_IF_ERROR_RETURN 2148 (READ_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, &data)); 2149 2150 inv_shifter = (XGXSBLK1_LANEPRBS_PRBS_ORDER1_SHIFT * pc->lane_num) + 2151 XGXSBLK1_LANEPRBS_PRBS_EN0_SHIFT; 2152 data &= (1 << inv_shifter); 2153 2154 *value = (data) ? 1 : 0; 2155 2156 return SOC_E_NONE; 2157 } 2158 2159 STATIC int 2160 _phy_xgxs16g_control_prbs_tx_enable_get(int unit, soc_port_t port, uint32 *value) 2161 { 2162 return _phy_xgxs16g_control_prbs_tx_rx_enable_get(unit, port, value); 2163 } 2164 2165 STATIC int 2166 _phy_xgxs16g_control_prbs_rx_enable_set(int unit, soc_port_t port, uint32 value) 2167 { 2168 uint16 data; 2169 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 2170 uint32 lane_mask = 1 << (PHY_XGXS16G_LANEPRBS_LANE_SHIFT * pc->lane_num); 2171 2172 SOC_IF_ERROR_RETURN 2173 (READ_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, &data)); 2174 2175 if (value) { 2176 data |= lane_mask << XGXSBLK1_LANEPRBS_PRBS_EN0_SHIFT; 2177 } else { 2178 data &= ~(lane_mask << XGXSBLK1_LANEPRBS_PRBS_EN0_SHIFT); 2179 } 2180 2181 /* write back updated configuration */ 2182 SOC_IF_ERROR_RETURN 2183 (WRITE_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, data)); 2184 2185 /* Set up status collection */ 2186 /* uPrbsRxControlReg = 0x80b1; 2187 * uPrbsRxControlReg += uLaneAddr * 0x10; 2188 */ 2189 SOC_IF_ERROR_RETURN 2190 (XGXS16G_REG_READ(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), &data)); 2191 2192 data &= ~RX0_RX_CONTROL_STATUS_SEL_MASK; 2193 if (value) { 2194 data |= RX0_RX_CONTROL_STATUS_SEL_prbsStatus; 2195 } else { 2196 data &= ~RX0_RX_CONTROL_STATUS_SEL_prbsStatus; 2197 } 2198 2199 SOC_IF_ERROR_RETURN 2200 (XGXS16G_REG_WRITE(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), data)); 2201 2202 return SOC_E_NONE; 2203 } 2204 2205 STATIC int 2206 _phy_xgxs16g_control_prbs_rx_enable_get(int unit, soc_port_t port, uint32 *value) 2207 { 2208 return _phy_xgxs16g_control_prbs_tx_rx_enable_get(unit, port, value); 2209 } 2210 2211 /* 2212 * Returns value 2213 * == 0: PRBS receive is in sync 2214 * == -1: PRBS receive never got into sync 2215 * == n: number of errors 2216 */ 2217 STATIC int 2218 _phy_xgxs16g_control_xgxs_prbs_rx_status_get(int unit, soc_port_t port, 2219 uint32 *value) 2220 { 2221 int lane; 2222 uint16 data; 2223 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);; 2224 2225 2226 /* Get status for all 4 lanes and check for sync 2227 * 0x80b0, 0x80c0, 0x80d0, 0x80e0 2228 */ 2229 *value = 0; 2230 for (lane = 0; lane < 4; lane++) { 2231 SOC_IF_ERROR_RETURN 2232 (XGXS16G_REG_READ(unit, pc, 0x0, 0x80b0 + (0x10 * lane), &data)); 2233 if (data == (RX0_RX_STATUS_PRBS_STATUS_PRBS_LOCK_BITS << 2234 RX0_RX_STATUS_PRBS_STATUS_PRBS_LOCK_SHIFT)) { 2235 /* PRBS is in sync */ 2236 continue; 2237 } else if (data == 0) { 2238 /* PRBS not in sync */ 2239 *value = -1; 2240 break; 2241 } else { 2242 /* Get errors */ 2243 *value += data & RX0_RX_STATUS_PRBS_STATUS_PTBS_ERRORS_MASK; 2244 } 2245 } 2246 return SOC_E_NONE; 2247 } 2248 2249 2250 STATIC int 2251 _phy_xgxs16g_control_prbs_rx_status_get(int unit, soc_port_t port, uint32 *value) 2252 { 2253 int rv; 2254 uint16 rx_sts, saved_rx_sts; 2255 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 2256 2257 /* Set up prbs rx status collection */ 2258 SOC_IF_ERROR_RETURN 2259 (XGXS16G_REG_READ(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), &rx_sts)); 2260 saved_rx_sts = rx_sts; 2261 rx_sts = (rx_sts & ~RX0_RX_CONTROL_STATUS_SEL_MASK) | 2262 RX0_RX_CONTROL_STATUS_SEL_prbsStatus; 2263 SOC_IF_ERROR_RETURN 2264 (XGXS16G_REG_WRITE(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), rx_sts)); 2265 2266 rv = _phy_xgxs16g_control_xgxs_prbs_rx_status_get(unit, port, value); 2267 2268 2269 /* Restore rx status */ 2270 SOC_IF_ERROR_RETURN 2271 (XGXS16G_REG_WRITE(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), saved_rx_sts)); 2272 2273 return rv; 2274 } 2275 2276 2277 2278 /* 2279 * Function: 2280 * phy_xgxs16g_control_set 2281 * Purpose: 2282 * Configure PHY device specific control fucntion. 2283 * Parameters: 2284 * unit - StrataSwitch unit #. 2285 * port - StrataSwitch port #. 2286 * type - Control to update 2287 * value - New setting for the control 2288 * Returns: 2289 * SOC_E_NONE 2290 */ 2291 STATIC int 2292 phy_xgxs16g_control_set(int unit, soc_port_t port, 2293 soc_phy_control_t type, uint32 value) 2294 { 2295 int rv; 2296 phy_ctrl_t *pc; 2297 /* coverity[mixed_enums] */ 2298 if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) { 2299 return SOC_E_PARAM; 2300 } 2301 2302 2303 pc = INT_PHY_SW_STATE(unit, port); 2304 rv = SOC_E_UNAVAIL; 2305 switch(type) { 2306 case SOC_PHY_CONTROL_PREEMPHASIS_LANE0: 2307 /* fall through */ 2308 case SOC_PHY_CONTROL_PREEMPHASIS_LANE1: 2309 /* fall through */ 2310 case SOC_PHY_CONTROL_PREEMPHASIS_LANE2: 2311 /* fall through */ 2312 case SOC_PHY_CONTROL_PREEMPHASIS_LANE3: 2313 /* fall through */ 2314 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0: 2315 /* fall through */ 2316 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1: 2317 /* fall through */ 2318 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2: 2319 /* fall through */ 2320 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3: 2321 /* fall through */ 2322 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0: 2323 /* fall through */ 2324 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1: 2325 /* fall through */ 2326 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2: 2327 /* fall through */ 2328 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3: 2329 /* fall through */ 2330 case SOC_PHY_CONTROL_PREEMPHASIS: 2331 /* fall through */ 2332 case SOC_PHY_CONTROL_DRIVER_CURRENT: 2333 /* fall through */ 2334 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 2335 rv = _phy_xgxs16g_control_tx_driver_set(unit, pc, type, value); 2336 break; 2337 case SOC_PHY_CONTROL_EQUALIZER_BOOST: 2338 rv = MODIFY_XGXS16G_RX_ALL_RX_ANALOGBIAS0r(unit, pc, value, 2339 RX_ALL_RX_EQ_BOOST_EQUALIZER_CONTROL_MASK); 2340 break; 2341 case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT: 2342 rv = _phy_xgxs16g_control_linkdown_transmit_set(unit, port, value); 2343 break; 2344 case SOC_PHY_CONTROL_PRBS_POLYNOMIAL: 2345 rv = _phy_xgxs16g_control_prbs_polynomial_set(unit, port, value); 2346 break; 2347 case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA: 2348 rv = _phy_xgxs16g_control_prbs_tx_invert_data_set(unit, port, value); 2349 break; 2350 case SOC_PHY_CONTROL_PRBS_TX_ENABLE: 2351 rv = _phy_xgxs16g_control_prbs_tx_enable_set(unit, port, value); 2352 break; 2353 case SOC_PHY_CONTROL_PRBS_RX_ENABLE: 2354 rv = _phy_xgxs16g_control_prbs_rx_enable_set(unit, port, value); 2355 break; 2356 2357 case SOC_PHY_CONTROL_PARALLEL_DETECTION: 2358 /* enable 1000X parallel detect */ 2359 SOC_IF_ERROR_RETURN 2360 (MODIFY_XGXS16G_SERDESDIGITAL_CONTROL1000X2r(unit, pc, 2361 value? SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK:0, SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK)); 2362 rv = SOC_E_NONE; 2363 break; 2364 2365 default: 2366 rv = (SOC_E_UNAVAIL); 2367 break; 2368 } 2369 return rv; 2370 } 2371 2372 STATIC int 2373 _phy_xgxs16g_control_tx_driver_get(int unit, phy_ctrl_t *pc, 2374 soc_phy_control_t type, uint32 *value) 2375 { 2376 uint16 data16; /* Temporary holder of 16 bit reg value */ 2377 uint16 mask; 2378 int shifter; 2379 int lane_ctrl; 2380 int is_40nm; 2381 2382 SOC_IF_ERROR_RETURN 2383 (_phy_xgxs16g_tx_driver_field_get(pc, type,&lane_ctrl,&mask,&shifter)); 2384 2385 is_40nm = XGXS16G_13G_ID(pc); 2386 2387 /* Read preemphasis/driver/pre-driver current */ 2388 switch (lane_ctrl) { 2389 case 0: 2390 SOC_IF_ERROR_RETURN 2391 (is_40nm ? 2392 READ_XGXS13G_040_TX0_ACONTROL1r(unit, pc, &data16) : 2393 READ_XGXS16G_TX0_TX_DRIVERr(unit, pc, &data16)); 2394 break; 2395 case 1: 2396 SOC_IF_ERROR_RETURN 2397 (is_40nm ? 2398 READ_XGXS13G_040_TX1_ACONTROL1r(unit, pc, &data16) : 2399 READ_XGXS16G_TX1_TX_DRIVERr(unit, pc, &data16)); 2400 break; 2401 case 2: 2402 SOC_IF_ERROR_RETURN 2403 (is_40nm ? 2404 READ_XGXS13G_040_TX2_ACONTROL1r(unit, pc, &data16) : 2405 READ_XGXS16G_TX2_TX_DRIVERr(unit, pc, &data16)); 2406 break; 2407 case 3: 2408 SOC_IF_ERROR_RETURN 2409 (is_40nm ? 2410 READ_XGXS13G_040_TX3_ACONTROL1r(unit, pc, &data16) : 2411 READ_XGXS16G_TX3_TX_DRIVERr(unit, pc, &data16)); 2412 break; 2413 case TX_DRIVER_DFT_LN_CTRL: 2414 SOC_IF_ERROR_RETURN 2415 (is_40nm ? 2416 READ_XGXS13G_040_TX_ALL_ACONTROL1r(unit, pc, &data16) : 2417 READ_XGXS16G_TX_ALL_TX_DRIVERr(unit, pc, &data16)); 2418 break; 2419 default: 2420 return SOC_E_NONE; 2421 } 2422 2423 *value = (data16 & mask) >> shifter; 2424 2425 return (SOC_E_NONE); 2426 } 2427 2428 /* Make use of the SERDESDIGITAL_PATGENCTRL.PKT_SIZE[0] as a scratch pad for VCO status */ 2429 STATIC int 2430 _phy_xgxs16g_control_vco_disturbed_get(int unit, soc_port_t port, uint32 *value) 2431 { 2432 uint16 data; 2433 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 2434 if(!pc) { 2435 return SOC_E_NONE; 2436 } 2437 SOC_IF_ERROR_RETURN(READ_XGXS16G_SERDESDIGITAL_PATGENCTRLr(unit, pc, &data)); 2438 SOC_IF_ERROR_RETURN(MODIFY_XGXS16G_SERDESDIGITAL_PATGENCTRLr(unit, pc, 0, SERDESDIGITAL_PATGENCTRL_PKT_SIZE_MASK)); 2439 2440 *value = (data & SERDESDIGITAL_PATGENCTRL_PKT_SIZE_MASK) ? 1 : 0; 2441 2442 return SOC_E_NONE; 2443 } 2444 2445 STATIC int 2446 _phy_xgxs16g_control_vco_disturbed_set(int unit, soc_port_t port) 2447 { 2448 uint16 data, mask; 2449 phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port); 2450 if(!pc) { 2451 return SOC_E_NONE; 2452 } 2453 data = 1 << SERDESDIGITAL_PATGENCTRL_PKT_SIZE_SHIFT; 2454 mask = SERDESDIGITAL_PATGENCTRL_PKT_SIZE_MASK; 2455 2456 SOC_IF_ERROR_RETURN(MODIFY_XGXS16G_SERDESDIGITAL_PATGENCTRLr(unit, pc, data, mask)); 2457 2458 return SOC_E_NONE; 2459 } 2460 2461 /* 2462 * Function: 2463 * phy_xgxs16g_control_get 2464 * Purpose: 2465 * Get current control settign of the PHY. 2466 * Parameters: 2467 * unit - StrataSwitch unit #. 2468 * port - StrataSwitch port #. 2469 * type - Control to update 2470 * value - (OUT)Current setting for the control 2471 * Returns: 2472 * SOC_E_NONE 2473 */ 2474 STATIC int 2475 phy_xgxs16g_control_get(int unit, soc_port_t port, 2476 soc_phy_control_t type, uint32 *value) 2477 { 2478 int rv; 2479 phy_ctrl_t *pc; 2480 uint16 data16; 2481 /* coverity[mixed_enums] */ 2482 if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) { 2483 return (SOC_E_PARAM); 2484 } 2485 2486 pc = INT_PHY_SW_STATE(unit, port); 2487 rv = SOC_E_UNAVAIL; 2488 switch(type) { 2489 case SOC_PHY_CONTROL_PREEMPHASIS_LANE0: 2490 /* fall through */ 2491 case SOC_PHY_CONTROL_PREEMPHASIS_LANE1: 2492 /* fall through */ 2493 case SOC_PHY_CONTROL_PREEMPHASIS_LANE2: 2494 /* fall through */ 2495 case SOC_PHY_CONTROL_PREEMPHASIS_LANE3: 2496 /* fall through */ 2497 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0: 2498 /* fall through */ 2499 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1: 2500 /* fall through */ 2501 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2: 2502 /* fall through */ 2503 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3: 2504 /* fall through */ 2505 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0: 2506 /* fall through */ 2507 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1: 2508 /* fall through */ 2509 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2: 2510 /* fall through */ 2511 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3: 2512 /* fall through */ 2513 case SOC_PHY_CONTROL_PREEMPHASIS: 2514 /* fall through */ 2515 case SOC_PHY_CONTROL_DRIVER_CURRENT: 2516 /* fall through */ 2517 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 2518 rv = _phy_xgxs16g_control_tx_driver_get(unit, pc, type, value); 2519 break; 2520 case SOC_PHY_CONTROL_PRBS_POLYNOMIAL: 2521 rv = _phy_xgxs16g_control_prbs_polynomial_get(unit, port, value); 2522 break; 2523 case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA: 2524 rv = _phy_xgxs16g_control_prbs_tx_invert_data_get(unit, port, value); 2525 break; 2526 case SOC_PHY_CONTROL_PRBS_TX_ENABLE: 2527 rv = _phy_xgxs16g_control_prbs_tx_enable_get(unit, port, value); 2528 break; 2529 case SOC_PHY_CONTROL_PRBS_RX_ENABLE: 2530 rv = _phy_xgxs16g_control_prbs_rx_enable_get(unit, port, value); 2531 break; 2532 case SOC_PHY_CONTROL_PRBS_RX_STATUS: 2533 rv = _phy_xgxs16g_control_prbs_rx_status_get(unit, port, value); 2534 break; 2535 2536 case SOC_PHY_CONTROL_EQUALIZER_BOOST: 2537 SOC_IF_ERROR_RETURN 2538 (READ_XGXS16G_RX_ALL_RX_ANALOGBIAS0r(unit, pc, &data16)); 2539 *value = data16 & RX_ALL_RX_EQ_BOOST_EQUALIZER_CONTROL_MASK; 2540 rv = SOC_E_NONE; 2541 break; 2542 case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT: 2543 rv = _phy_xgxs16g_control_linkdown_transmit_get(unit, port, value); 2544 break; 2545 case SOC_PHY_CONTROL_PARALLEL_DETECTION: 2546 SOC_IF_ERROR_RETURN 2547 (READ_XGXS16G_SERDESDIGITAL_CONTROL1000X2r(unit, pc,&data16)); 2548 *value = 2549 data16 & SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK? 2550 TRUE: FALSE; 2551 rv = SOC_E_NONE; 2552 break; 2553 case SOC_PHY_CONTROL_VCO_DISTURBED: 2554 rv = _phy_xgxs16g_control_vco_disturbed_get(unit, port, value); 2555 break; 2556 default: 2557 rv = (SOC_E_UNAVAIL); 2558 break; 2559 } 2560 return rv; 2561 } 2562 2563 /* 2564 * Function: 2565 * phy_xgxs16g_reg_read 2566 * Purpose: 2567 * Routine to read PHY register 2568 * Parameters: 2569 * uint - BCM unit number 2570 * pc - PHY state 2571 * flags - Flags which specify the register type 2572 * phy_reg_addr - Encoded register address 2573 * phy_data - (OUT) Value read from PHY register 2574 * Note: 2575 * This register read function is not thread safe. Higher level 2576 * function that calls this function must obtain a per port lock 2577 * to avoid overriding register page mapping between threads. 2578 */ 2579 STATIC int 2580 phy_xgxs16g_reg_read(int unit, soc_port_t port, uint32 flags, 2581 uint32 phy_reg_addr, uint32 *phy_data) 2582 { 2583 uint16 data; /* Temporary holder for phy_data */ 2584 phy_ctrl_t *pc; /* PHY software state */ 2585 2586 pc = INT_PHY_SW_STATE(unit, port); 2587 2588 SOC_IF_ERROR_RETURN 2589 (phy_reg_aer_read(unit, pc, phy_reg_addr, &data)); 2590 2591 *phy_data = data; 2592 2593 return (SOC_E_NONE); 2594 } 2595 2596 /* 2597 * Function: 2598 * phy_xgxs16g_reg_write 2599 * Purpose: 2600 * Routine to write PHY register 2601 * Parameters: 2602 * uint - BCM unit number 2603 * pc - PHY state 2604 * flags - Flags which specify the register type 2605 * phy_reg_addr - Encoded register address 2606 * phy_data - Value write to PHY register 2607 * Note: 2608 * This register read function is not thread safe. Higher level 2609 * function that calls this function must obtain a per port lock 2610 * to avoid overriding register page mapping between threads. 2611 */ 2612 STATIC int 2613 phy_xgxs16g_reg_write(int unit, soc_port_t port, uint32 flags, 2614 uint32 phy_reg_addr, uint32 phy_data) 2615 { 2616 uint16 data; /* Temporary holder for phy_data */ 2617 phy_ctrl_t *pc; /* PHY software state */ 2618 2619 pc = INT_PHY_SW_STATE(unit, port); 2620 2621 data = (uint16) (phy_data & 0x0000FFFF); 2622 2623 SOC_IF_ERROR_RETURN 2624 (phy_reg_aer_write(unit, pc, phy_reg_addr, data)); 2625 2626 return (SOC_E_NONE); 2627 } 2628 2629 /* 2630 * Function: 2631 * phy_xgxs16g_reg_modify 2632 * Purpose: 2633 * Routine to write PHY register 2634 * Parameters: 2635 * uint - BCM unit number 2636 * pc - PHY state 2637 * flags - Flags which specify the register type 2638 * phy_reg_addr - Encoded register address 2639 * phy_mo_data - New value for the bits specified in phy_mo_mask 2640 * phy_mo_mask - Bit mask to modify 2641 * Note: 2642 * This register read function is not thread safe. Higher level 2643 * function that calls this function must obtain a per port lock 2644 * to avoid overriding register page mapping between threads. 2645 */ 2646 STATIC int 2647 phy_xgxs16g_reg_modify(int unit, soc_port_t port, uint32 flags, 2648 uint32 phy_reg_addr, uint32 phy_data, 2649 uint32 phy_data_mask) 2650 { 2651 uint16 data; /* Temporary holder for phy_data */ 2652 uint16 mask; 2653 phy_ctrl_t *pc; /* PHY software state */ 2654 2655 pc = INT_PHY_SW_STATE(unit, port); 2656 2657 data = (uint16) (phy_data & 0x0000FFFF); 2658 mask = (uint16) (phy_data_mask & 0x0000FFFF); 2659 2660 SOC_IF_ERROR_RETURN 2661 (phy_reg_aer_modify(unit, pc, phy_reg_addr, data, mask)); 2662 2663 return (SOC_E_NONE); 2664 } 2665 2666 STATIC int 2667 phy_xgxs16g_probe(int unit, phy_ctrl_t *pc) 2668 { 2669 uint16 serdes_id0; 2670 uint16 serdes_id2; 2671 soc_info_t *si; 2672 int phy_port; /* physical port number */ 2673 2674 si = &SOC_INFO(unit); 2675 if (soc_feature(unit, soc_feature_logical_port_num)) { 2676 phy_port = si->port_l2p_mapping[pc->port]; 2677 } else { 2678 phy_port = pc->port; 2679 } 2680 2681 SOC_IF_ERROR_RETURN 2682 (READ_XGXS16G_SERDESID_SERDESID0r(unit, pc, &serdes_id0)); 2683 SOC_IF_ERROR_RETURN 2684 (READ_XGXS16G_SERDESID_SERDESID2r(unit, pc, &serdes_id2)); 2685 2686 if ((serdes_id0 & SERDESID_SERDESID0_MODEL_NUMBER_MASK) != 2687 SERDES_ID0_MODEL_NUMBER_XGXS_16G) { 2688 return SOC_E_NOT_FOUND; 2689 } 2690 2691 if (serdes_id2 & SERDESID_SERDESID2_DR_16G_4L_MASK) { 2692 /* XGXS16G */ 2693 pc->size = sizeof(XGXS16G_DEV_DESC); 2694 return SOC_E_NONE; 2695 } 2696 2697 if (serdes_id2 & SERDESID_SERDESID2_DR_13G_4L_MASK) { 2698 /* XGXS13G new 40nm serdes */ 2699 pc->lane_num = SOC_PORT_BINDEX(unit, phy_port); 2700 pc->chip_num = SOC_BLOCK_NUMBER(unit, SOC_PORT_BLOCK(unit, phy_port)); 2701 if (pc->lane_num) { 2702 LOG_WARN(BSL_LS_SOC_PHY, 2703 (BSL_META_U(unit, 2704 "_phy_xgxs16g_probe u=%d p=%d: wrong lane# 0x%x, set to 0\n"), 2705 unit, pc->port, pc->lane_num)); 2706 pc->lane_num = 0; 2707 } 2708 2709 pc->dev_name = "XGXS13G"; 2710 2711 pc->size = sizeof(XGXS16G_DEV_DESC); 2712 return SOC_E_NONE; 2713 } 2714 return SOC_E_NOT_FOUND; 2715 } 2716 2717 STATIC int 2718 phy_xgxs16g_notify(int unit, soc_port_t port, 2719 soc_phy_event_t event, uint32 value) 2720 { 2721 int rv; 2722 2723 if (event >= phyEventCount) { 2724 return SOC_E_PARAM; 2725 } 2726 2727 rv = SOC_E_NONE; 2728 switch(event) { 2729 case phyEventInterface: 2730 rv = (_phy_xgxs16g_notify_interface(unit, port, value)); 2731 break; 2732 case phyEventDuplex: 2733 rv = (_phy_xgxs16g_notify_duplex(unit, port, value)); 2734 break; 2735 case phyEventSpeed: 2736 rv = (_phy_xgxs16g_notify_speed(unit, port, value)); 2737 break; 2738 case phyEventStop: 2739 rv = (_phy_xgxs16g_notify_stop(unit, port, value)); 2740 break; 2741 case phyEventResume: 2742 rv = (_phy_xgxs16g_notify_resume(unit, port, value)); 2743 break; 2744 case phyEventAutoneg: 2745 rv = (phy_xgxs16g_an_set(unit, port, value)); 2746 break; 2747 case phyEventMacLoopback: 2748 rv = (_phy_xgxs16g_notify_mac_loopback(unit, port, value)); 2749 break; 2750 default: 2751 rv = SOC_E_UNAVAIL; 2752 break; 2753 } 2754 2755 return rv; 2756 } 2757 2758 STATIC int 2759 phy_xgxs16g_duplex_get(int unit, soc_port_t port, int *duplex) 2760 { 2761 uint16 reg0_16; 2762 uint16 mii_ctrl; 2763 phy_ctrl_t *pc; 2764 2765 pc = INT_PHY_SW_STATE(unit, port); 2766 2767 *duplex = TRUE; 2768 2769 SOC_IF_ERROR_RETURN 2770 (READ_XGXS16G_GP_STATUS_STATUS1000X1r(unit, pc, ®0_16)); 2771 2772 if (reg0_16 & GP_STATUS_STATUS1000X1_SGMII_MODE_MASK) { 2773 2774 /* retrieve the duplex setting in SGMII mode */ 2775 SOC_IF_ERROR_RETURN 2776 (READ_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, &mii_ctrl)); 2777 2778 if (mii_ctrl & MII_CTRL_AE) { 2779 SOC_IF_ERROR_RETURN 2780 (READ_XGXS16G_COMBO_IEEE0_AUTONEGLPABILr(unit,pc,®0_16)); 2781 2782 /* make sure link partner is also in SGMII mode 2783 * otherwise fall through to use the FD bit in MII_CTRL reg 2784 */ 2785 if (reg0_16 & MII_ANP_SGMII_MODE) { 2786 if (reg0_16 & MII_ANP_SGMII_FD) { 2787 *duplex = TRUE; 2788 } else { 2789 *duplex = FALSE; 2790 } 2791 return SOC_E_NONE; 2792 } 2793 } 2794 *duplex = (mii_ctrl & MII_CTRL_FD) ? TRUE : FALSE; 2795 } 2796 return SOC_E_NONE; 2797 } 2798 2799 /* 2800 * Variable: 2801 * phy_xgxs16g_drv 2802 * Purpose: 2803 * Phy Driver for 10G (XAUI x 4) Serdes PHY. 2804 */ 2805 2806 phy_driver_t phy_xgxs16g_hg = { 2807 /* .drv_name = */ "XGXS16G Unicore PHY Driver", 2808 /* .pd_init = */ phy_xgxs16g_init, 2809 /* .pd_reset = */ phy_null_reset, 2810 /* .pd_link_get = */ phy_xgxs16g_link_get, 2811 /* .pd_enable_set = */ phy_xgxs16g_enable_set, 2812 /* .pd_enable_get = */ phy_null_enable_get, 2813 /* .pd_duplex_set = */ phy_null_set, 2814 /* .pd_duplex_get = */ phy_xgxs16g_duplex_get, 2815 /* .pd_speed_set = */ phy_xgxs16g_speed_set, 2816 /* .pd_speed_get = */ phy_xgxs16g_speed_get, 2817 /* .pd_master_set = */ phy_null_set, 2818 /* .pd_master_get = */ phy_xgxs16g_master_get, 2819 /* .pd_an_set = */ phy_xgxs16g_an_set, 2820 /* .pd_an_get = */ phy_xgxs16g_an_get, 2821 /* .pd_adv_local_set = */ NULL, /* Deprecated */ 2822 /* .pd_adv_local_get = */ NULL, /* Deprecated */ 2823 /* .pd_adv_remote_get = */ NULL, /* Deprecated */ 2824 /* .pd_lb_set = */ phy_xgxs16g_lb_set, 2825 /* .pd_lb_get = */ phy_xgxs16g_lb_get, 2826 /* .pd_interface_set = */ phy_null_interface_set, 2827 /* .pd_interface_get = */ phy_xgxs16g_interface_get, 2828 /* .pd_ability = */ NULL, /* Deprecated */ 2829 /* .pd_linkup_evt = */ NULL, 2830 /* .pd_linkdn_evt = */ NULL, 2831 /* .pd_mdix_set = */ phy_null_mdix_set, 2832 /* .pd_mdix_get = */ phy_null_mdix_get, 2833 /* .pd_mdix_status_get = */ phy_null_mdix_status_get, 2834 /* .pd_medium_config_set = */ NULL, 2835 /* .pd_medium_config_get = */ NULL, 2836 /* .pd_medium_get = */ phy_null_medium_get, 2837 /* .pd_cable_diag = */ NULL, 2838 /* .pd_link_change = */ NULL, 2839 /* .pd_control_set = */ phy_xgxs16g_control_set, 2840 /* .pd_control_get = */ phy_xgxs16g_control_get, 2841 /* .pd_reg_read = */ phy_xgxs16g_reg_read, 2842 /* .pd_reg_write = */ phy_xgxs16g_reg_write, 2843 /* .pd_reg_modify = */ phy_xgxs16g_reg_modify, 2844 /* .pd_notify = */ phy_xgxs16g_notify, 2845 /* .pd_probe = */ phy_xgxs16g_probe, 2846 /* .pd_ability_advert_set = */ phy_xgxs16g_ability_advert_set, 2847 /* .pd_ability_advert_get = */ phy_xgxs16g_ability_advert_get, 2848 /* .pd_ability_remote_get = */ phy_xgxs16g_ability_remote_get, 2849 /* .pd_ability_local_get = */ phy_xgxs16g_ability_local_get 2850 }; 2851 2852 2853 /*********************************************************************** 2854 * 2855 * PASS-THROUGH NOTIFY ROUTINES 2856 */ 2857 2858 /* 2859 * Function: 2860 * _phy_xgxs16g_notify_duplex 2861 * Purpose: 2862 * Program duplex if (and only if) serdesxgxs16g is an intermediate PHY. 2863 * Parameters: 2864 * unit - StrataSwitch unit #. 2865 * port - StrataSwitch port #. 2866 * duplex - Boolean, TRUE indicates full duplex, FALSE 2867 * indicates half. 2868 * Returns: 2869 * SOC_E_XXX 2870 * Notes: 2871 * If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to 2872 * talk directly to an external fiber module. 2873 * 2874 * If PHY_FLAGS_FIBER is clear, the PHY is being used in 2875 * pass-through mode to talk to an external SGMII PHY. 2876 * 2877 * When used in pass-through mode, autoneg must be turned off and 2878 * the speed/duplex forced to match that of the external PHY. 2879 */ 2880 2881 STATIC int 2882 _phy_xgxs16g_notify_duplex(int unit, soc_port_t port, uint32 duplex) 2883 { 2884 int fiber; 2885 uint16 mii_ctrl; 2886 phy_ctrl_t *pc; 2887 2888 fiber = PHY_FIBER_MODE(unit, port); 2889 pc = INT_PHY_SW_STATE(unit, port); 2890 LOG_INFO(BSL_LS_SOC_PHY, 2891 (BSL_META_U(unit, 2892 "_phy_xgxs16g_notify_duplex: " 2893 "u=%d p=%d duplex=%d fiber=%d\n"), 2894 unit, port, duplex, fiber)); 2895 2896 if (SAL_BOOT_SIMULATION) { 2897 return SOC_E_NONE; 2898 } 2899 2900 if (fiber) { 2901 SOC_IF_ERROR_RETURN 2902 (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, 2903 MII_CTRL_FD, MII_CTRL_FD)); 2904 return SOC_E_NONE; 2905 } 2906 2907 /* Put SERDES PHY in reset */ 2908 2909 SOC_IF_ERROR_RETURN 2910 (_phy_xgxs16g_notify_stop(unit, port, PHY_STOP_DUPLEX_CHG)); 2911 2912 /* Update duplexity */ 2913 mii_ctrl = (duplex) ? MII_CTRL_FD : 0; 2914 SOC_IF_ERROR_RETURN 2915 (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, mii_ctrl, MII_CTRL_FD)); 2916 2917 /* Take SERDES PHY out of reset */ 2918 SOC_IF_ERROR_RETURN 2919 (_phy_xgxs16g_notify_resume(unit, port, PHY_STOP_DUPLEX_CHG)); 2920 2921 /* Autonegotiation must be turned off to talk to external PHY if 2922 * SGMII autoneg is not enabled. 2923 */ 2924 if (!PHY_SGMII_AUTONEG_MODE(unit, port)) { 2925 SOC_IF_ERROR_RETURN 2926 (phy_xgxs16g_an_set(unit, port, FALSE)); 2927 } 2928 return SOC_E_NONE; 2929 } 2930 2931 /* 2932 * Function: 2933 * _phy_xgxs16g_notify_speed 2934 * Purpose: 2935 * Program duplex if (and only if) serdesxgxs16g is an intermediate PHY. 2936 * Parameters: 2937 * unit - StrataSwitch unit #. 2938 * port - StrataSwitch port #. 2939 * speed - Speed to program. 2940 * Returns: 2941 * SOC_E_XXX 2942 * Notes: 2943 * If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to 2944 * talk directly to an external fiber module. 2945 * 2946 * If PHY_FLAGS_FIBER is clear, the PHY is being used in 2947 * pass-through mode to talk to an external SGMII PHY. 2948 * 2949 * When used in pass-through mode, autoneg must be turned off and 2950 * the speed/duplex forced to match that of the external PHY. 2951 */ 2952 2953 STATIC int 2954 _phy_xgxs16g_notify_speed(int unit, soc_port_t port, uint32 speed) 2955 { 2956 int fiber; 2957 uint16 fiber_status; 2958 phy_ctrl_t *pc; 2959 2960 pc = INT_PHY_SW_STATE(unit, port); 2961 fiber = PHY_FIBER_MODE(unit, port); 2962 2963 LOG_INFO(BSL_LS_SOC_PHY, 2964 (BSL_META_U(unit, 2965 "_phy_xgxs16g_notify_speed: " 2966 "u=%d p=%d speed=%d fiber=%d\n"), 2967 unit, port, speed, fiber)); 2968 2969 if (SAL_BOOT_SIMULATION) { 2970 return SOC_E_NONE; 2971 } 2972 2973 SOC_IF_ERROR_RETURN 2974 (READ_XGXS16G_SERDESDIGITAL_STATUS1000X1r(unit, pc, &fiber_status)); 2975 2976 /* Put SERDES PHY in reset */ 2977 SOC_IF_ERROR_RETURN 2978 (_phy_xgxs16g_notify_stop(unit, port, PHY_STOP_SPEED_CHG)); 2979 2980 /* Update speed */ 2981 SOC_IF_ERROR_RETURN 2982 (phy_xgxs16g_speed_set(unit, port, speed)); 2983 2984 /* Take SERDES PHY out of reset */ 2985 SOC_IF_ERROR_RETURN 2986 (_phy_xgxs16g_notify_resume(unit, port, PHY_STOP_SPEED_CHG)); 2987 2988 /* Autonegotiation must be turned off to talk to external PHY */ 2989 if (!PHY_SGMII_AUTONEG_MODE(unit, port) && PHY_EXTERNAL_MODE(unit, port)) { 2990 SOC_IF_ERROR_RETURN 2991 (phy_xgxs16g_an_set(unit, port, FALSE)); 2992 } 2993 LOG_INFO(BSL_LS_SOC_PHY, 2994 (BSL_META_U(unit, 2995 "_phy_xgxs16g_notify_speed: " 2996 "u=%d p=%d speed=%d fiber=%d rv=%d\n"), 2997 unit, port, speed, fiber,SOC_E_NONE)); 2998 2999 return SOC_E_NONE; 3000 } 3001 3002 /* 3003 * Function: 3004 * _phy_xgxs16g_stop 3005 * Purpose: 3006 * Put serdesxgxs16g SERDES in or out of reset depending on conditions 3007 */ 3008 3009 STATIC int 3010 _phy_xgxs16g_stop(int unit, soc_port_t port) 3011 { 3012 uint16 mii_ctrl; 3013 int stop, copper; 3014 phy_ctrl_t *pc; 3015 3016 pc = INT_PHY_SW_STATE(unit, port); 3017 3018 copper = (pc->stop & 3019 PHY_STOP_COPPER) != 0; 3020 3021 stop = ((pc->stop & 3022 (PHY_STOP_PHY_DIS | 3023 PHY_STOP_DRAIN)) != 0 || 3024 (copper && 3025 (pc->stop & 3026 (PHY_STOP_MAC_DIS | 3027 PHY_STOP_DUPLEX_CHG | 3028 PHY_STOP_SPEED_CHG)) != 0)); 3029 3030 LOG_INFO(BSL_LS_SOC_PHY, 3031 (BSL_META_U(unit, 3032 "phy_xgxs16g_stop: u=%d p=%d copper=%d stop=%d flg=0x%x\n"), 3033 unit, port, copper, stop, 3034 pc->stop)); 3035 3036 mii_ctrl = (stop) ? MII_CTRL_PD : 0; 3037 SOC_IF_ERROR_RETURN 3038 (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, mii_ctrl, MII_CTRL_PD)); 3039 3040 return SOC_E_NONE; 3041 } 3042 3043 /* 3044 * Function: 3045 * _phy_xgxs16g_notify_stop 3046 * Purpose: 3047 * Add a reason to put serdesxgxs16g PHY in reset. 3048 * Parameters: 3049 * unit - StrataSwitch unit #. 3050 * port - StrataSwitch port #. 3051 * flags - Reason to stop 3052 * Returns: 3053 * SOC_E_XXX 3054 */ 3055 3056 STATIC int 3057 _phy_xgxs16g_notify_stop(int unit, soc_port_t port, uint32 flags) 3058 { 3059 INT_PHY_SW_STATE(unit, port)->stop |= flags; 3060 3061 return SOC_E_NONE; 3062 /* return _phy_xgxs16g_stop(unit, port); */ 3063 } 3064 3065 /* 3066 * Function: 3067 * _phy_xgxs16g_notify_resume 3068 * Purpose: 3069 * Remove a reason to put serdesxgxs16g PHY in reset. 3070 * Parameters: 3071 * unit - StrataSwitch unit #. 3072 * port - StrataSwitch port #. 3073 * flags - Reason to stop 3074 * Returns: 3075 * SOC_E_XXX 3076 */ 3077 3078 STATIC int 3079 _phy_xgxs16g_notify_resume(int unit, soc_port_t port, uint32 flags) 3080 { 3081 INT_PHY_SW_STATE(unit, port)->stop &= ~flags; 3082 3083 return _phy_xgxs16g_stop(unit, port); 3084 } 3085 3086 /* 3087 * Function: 3088 * phy_xgxs16g_media_setup 3089 * Purpose: 3090 * Configure 3091 * Parameters: 3092 * unit - StrataSwitch unit #. 3093 * port - StrataSwitch port #. 3094 * fiber_mode - Configure for fiber mode 3095 * fiber_pref - Fiber preferrred (if fiber mode) 3096 * Returns: 3097 * SOC_E_XXX 3098 */ 3099 STATIC int 3100 _phy_xgxs16g_notify_interface(int unit, soc_port_t port, uint32 intf) 3101 { 3102 phy_ctrl_t *pc; 3103 uint16 data16; 3104 3105 LOG_INFO(BSL_LS_SOC_PHY, 3106 (BSL_META_U(unit, 3107 "_phy_xgxs16g_notify_interface: u=%d p=%d IF=0x%x\n"), 3108 unit, port, intf)); 3109 3110 3111 pc = INT_PHY_SW_STATE(unit, port); 3112 3113 data16 = 0; 3114 if (intf != SOC_PORT_IF_SGMII) { 3115 data16 = SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK; 3116 } 3117 3118 SOC_IF_ERROR_RETURN 3119 (MODIFY_XGXS16G_SERDESDIGITAL_CONTROL1000X1r(unit, pc, data16, 3120 SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK)); 3121 3122 return SOC_E_NONE; 3123 } 3124 3125 /* 3126 * Function: 3127 * _phy_xgxs16g_notify_mac_loopback 3128 * Purpose: 3129 * turn on rx clock compensation in mac loopback mode for 3130 * applicable XGXS devices 3131 * Parameters: 3132 * unit - StrataSwitch unit #. 3133 * port - StrataSwitch port #. 3134 * enable - TRUE mac loopback mode, FALSE not in mac loopback mode 3135 * Returns: 3136 * SOC_E_XXX 3137 */ 3138 STATIC int 3139 _phy_xgxs16g_notify_mac_loopback(int unit, soc_port_t port, uint32 enable) 3140 { 3141 phy_ctrl_t *pc; 3142 3143 LOG_INFO(BSL_LS_SOC_PHY, 3144 (BSL_META_U(unit, 3145 "_phy_xgxs16g_notify_mac_loopback: u=%d p=%d enable=0x%x\n"), 3146 unit, port, enable)); 3147 3148 pc = INT_PHY_SW_STATE(unit, port); 3149 3150 /* XMAC loopback mode needs to enable clock comp */ 3151 if (XGXS16G_13G_ID(pc)) { 3152 SOC_IF_ERROR_RETURN 3153 (MODIFY_XGXS16G_XGXSBLK2_UNICOREMODE10Gr(unit, pc, 3154 enable? 0x80: 0x91, 3155 XGXSBLK2_UNICOREMODE10G_UNICOREMODE10GHIG_MASK | 3156 XGXSBLK2_UNICOREMODE10G_UNICOREMODE10GCX4_MASK)); 3157 } 3158 return SOC_E_NONE; 3159 } 3160 3161 #ifdef BROADCOM_DEBUG 3162 void 3163 phy_xgxs16g_state_dump(int unit, soc_port_t port) 3164 { 3165 3166 /* Show PHY configuration summary */ 3167 /* lane status */ 3168 3169 3170 /* Show Counters */ 3171 /* Digital.CrcErr_RxPkt_A */ 3172 /* ieee0Blk_A.MIIStat_A */ 3173 3174 /* Dump Registers */ 3175 } 3176 #endif /* BROADCOM_DEBUG */ 3177 3178 #else 3179 int _phy_xgxs16g_not_empty; 3180 #endif /* INCLUDE_XGXS_16G */ 3181