xgxs1.c (15789B)
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: xgxs.c 8 * Purpose: Broadcom 10/100/1000/2500/10000/12000/13000/16000 SerDes 9 * (SerDes-XGXS/Unicore) 10 */ 11 12 #include <sal/types.h> 13 #include <sal/core/spl.h> 14 #include <shared/bsl.h> 15 #include <soc/drv.h> 16 #include <soc/debug.h> 17 #include <soc/error.h> 18 #include <soc/phy.h> 19 #include <soc/phyreg.h> 20 21 #include <soc/phy.h> 22 #include <soc/phy/phyctrl.h> 23 #include <soc/phy/drv.h> 24 25 #include "phydefs.h" /* Must include before other phy related includes */ 26 27 #if defined(INCLUDE_PHY_XGXS1) 28 #include "phyconfig.h" /* Must be the first phy include after phydefs.h */ 29 #include "phyident.h" 30 #include "phyreg.h" 31 #include "phynull.h" 32 #include "xgxs.h" 33 #include "xgxs1.h" 34 35 STATIC int phy_xgxs1_lb_set(int unit, soc_port_t port, int enable); 36 37 /* 38 * Function: 39 * phy_xgxs1_init 40 * Purpose: 41 * Initialize xgxs phys 42 * Parameters: 43 * unit - StrataSwitch unit #. 44 * port - StrataSwitch port #. 45 * Returns: 46 * SOC_E_NONE 47 */ 48 49 STATIC int 50 phy_xgxs1_init(int unit, soc_port_t port) 51 { 52 phy_ctrl_t *pc; 53 54 pc = INT_PHY_SW_STATE(unit, port); 55 56 /* NOTE: FusionCore/Unicore init is performed in BigMAC init */ 57 if (PHY_EXTERNAL_MODE(unit, port)) { 58 if (IS_HG_PORT(unit, port)) { 59 uint16 value; 60 61 /* Enable XgxsNoCC if the HiGig port has external PHY. 62 * XgxsNoCC enables in-band link signaling, per the 802.3ae 63 * standard (|Q| ordered sets). XgxsNoLssQNoCC is legacy 64 * HiG mode, which does not support in-band link signaling. 65 * Current XAUI cores support both 802.3ae compliant 66 * signaling, as well as backwards compatibility with 67 * prior (legacy) protocols. 68 */ 69 SOC_IF_ERROR_RETURN 70 (READ_PHYXGXS_BLK0_CTRLr(unit, pc, &value)); 71 value &= ~(0x0f00); 72 value |= (1 << 8); 73 SOC_IF_ERROR_RETURN 74 (WRITE_PHYXGXS_BLK0_CTRLr(unit, pc, value)); 75 } 76 } 77 78 /* clear loopback (just in case) */ 79 SOC_IF_ERROR_RETURN 80 (phy_xgxs1_lb_set(unit, port, FALSE)); 81 82 LOG_INFO(BSL_LS_SOC_PHY, 83 (BSL_META_U(unit, 84 "phy_xgxs1_init: u=%d p=%d\n"), 85 unit, port)); 86 87 return SOC_E_NONE; 88 } 89 90 /* 91 * Function: 92 * phy_xgxs1_link_get 93 * Purpose: 94 * Get layer2 connection status. 95 * Parameters: 96 * unit - StrataSwitch unit #. 97 * port - StrataSwitch port #. 98 * link - address of memory to store link up/down state. 99 * Returns: 100 * SOC_E_NONE 101 */ 102 103 STATIC int 104 phy_xgxs1_link_get(int unit, soc_port_t port, int *link) 105 { 106 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) { 107 *link = FALSE; 108 return SOC_E_NONE; 109 } 110 111 if (IS_LMD_ENABLED_PORT(unit, port)) { 112 uint16 o_misctrl1; 113 uint16 n_misctrl1; 114 uint16 sync_stat; 115 phy_ctrl_t *pc; 116 117 pc = INT_PHY_SW_STATE(unit, port); 118 119 SOC_IF_ERROR_RETURN /* Get mdio reg mapping mode */ 120 (READ_PHYXGXS_BLK0_MISC_CTRL1r(unit, pc, &o_misctrl1)); 121 n_misctrl1 = 0x0000; 122 if (n_misctrl1 != o_misctrl1) { 123 SOC_IF_ERROR_RETURN 124 (WRITE_PHYXGXS_BLK0_MISC_CTRL1r(unit, pc, n_misctrl1)); 125 } 126 SOC_IF_ERROR_RETURN 127 (READ_PHYXGXS_IEEE1_LANE_STATr(unit, pc, &sync_stat)); 128 129 if (n_misctrl1 != o_misctrl1) { /* Restore PMA/PMD mdio reg mapping */ 130 SOC_IF_ERROR_RETURN 131 (WRITE_PHYXGXS_BLK0_MISC_CTRL1r(unit, pc, o_misctrl1)); 132 } 133 134 *link = (sync_stat & 1) ? TRUE : FALSE; 135 } else { 136 uint64 xgxs_stat; 137 138 SOC_IF_ERROR_RETURN 139 (READ_MAC_XGXS_STATr(unit, port, &xgxs_stat)); 140 *link = soc_reg64_field32_get 141 (unit, MAC_XGXS_STATr, xgxs_stat, 142 LINKf) ? TRUE : FALSE; 143 } 144 145 return SOC_E_NONE; 146 } 147 148 /* 149 * Function: 150 * phy_xgxs1_enable_set 151 * Purpose: 152 * Enable/Disable phy 153 * Parameters: 154 * unit - StrataSwitch unit #. 155 * port - StrataSwitch port #. 156 * enable - on/off state to set 157 * Returns: 158 * SOC_E_NONE 159 */ 160 161 STATIC int 162 phy_xgxs1_enable_set(int unit, soc_port_t port, int enable) 163 { 164 uint16 disable_tx_xe; 165 uint16 disable_tx_hg; 166 phy_ctrl_t *pc; 167 168 pc = INT_PHY_SW_STATE(unit, port); 169 170 /* PMA/PMD mapping are different between HG and XE ports. 171 * Therefore, we need two different settings for HG and XE ports. 172 */ 173 if (enable) { 174 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE); 175 disable_tx_xe = 0; /* Clear Tx disable bit for XE*/ 176 disable_tx_hg = 0; /* Clear Tx disable bit for HG*/ 177 } else { 178 PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE); 179 disable_tx_xe = (1 << 0); /* Set disable Global PMD TX bit for XE */ 180 disable_tx_hg = (1 << 11); /* Set disable Global PMD TX bit for HG */ 181 } 182 183 if (IS_XE_PORT(unit, port)) { 184 SOC_IF_ERROR_RETURN 185 (MODIFY_PHYXGXS_XAUI_TX_DISABLEr(unit, pc, disable_tx_xe, 1 << 0)); 186 } else { 187 SOC_IF_ERROR_RETURN 188 (MODIFY_PHYXGXS_BLK0_MISC_CTRL1r(unit, pc, disable_tx_hg, 189 (1 << 11))); 190 } 191 192 return SOC_E_NONE; 193 } 194 195 /* 196 * Function: 197 * phy_xgxs1_speed_get 198 * Purpose: 199 * Get PHY speed 200 * Parameters: 201 * unit - StrataSwitch unit #. 202 * port - StrataSwitch port #. 203 * speed - current link speed in Mbps 204 * Returns: 205 * SOC_E_NONE 206 */ 207 208 STATIC int 209 phy_xgxs1_speed_get(int unit, soc_port_t port, int *speed) 210 { 211 /* Default speed */ 212 *speed = 10000; 213 if (IS_LMD_ENABLED_PORT(unit, port)) { 214 *speed >>= 2; /* Div by 4 */ 215 } 216 217 COMPILER_REFERENCE(unit); 218 COMPILER_REFERENCE(port); 219 220 return SOC_E_NONE; 221 } 222 223 /* 224 * Function: 225 * phy_xgxs1_lb_set 226 * Purpose: 227 * Put XGXS/FusionCore in PHY loopback 228 * Parameters: 229 * unit - StrataSwitch unit #. 230 * port - StrataSwitch port #. 231 * enable - binary value for on/off (1/0) 232 * Returns: 233 * SOC_E_NONE 234 */ 235 236 STATIC int 237 phy_xgxs1_lb_set(int unit, soc_port_t port, int enable) 238 { 239 int rv; 240 phy_ctrl_t *pc; 241 uint16 lb_bit; 242 243 rv = SOC_E_NONE; 244 245 pc = INT_PHY_SW_STATE(unit, port); 246 247 if (IS_LMD_ENABLED_PORT(unit, port)) { 248 SOC_IF_ERROR_RETURN 249 (WRITE_PHYXGXS_BLK1_LANE_CTRL2r(unit, pc, 250 (enable) ? 0xFF0F : 0xFF00)); 251 return SOC_E_NONE; 252 } 253 254 /* 255 * control RX signal detect, so that a cable is not needed for loopback 256 */ 257 SOC_IF_ERROR_RETURN 258 (MODIFY_PHYXGXS_RXALL_CTRLr(unit, pc, (enable) ? 0x0010 : 0, 0x0010)); 259 260 /* 261 * control the actual loopback bit 262 */ 263 lb_bit = XGXS_IEEE_CTRL_LB_ENA; 264 if (IS_XE_PORT(unit, port)) { 265 if (soc_feature(unit, soc_feature_xgxs_v5)) { 266 lb_bit = 1; 267 } 268 } 269 SOC_IF_ERROR_RETURN 270 (MODIFY_PHYXGXS_XAUI_MII_CTRLr(unit, pc, 271 (enable) ? lb_bit : 0, lb_bit)); 272 273 return rv; 274 } 275 276 /* 277 * Function: 278 * phy_xgxs1_lb_get 279 * Purpose: 280 * Get XGXS/FusionCore PHY loopback state 281 * Parameters: 282 * unit - StrataSwitch unit #. 283 * port - StrataSwitch port #. 284 * enable - address of location to store binary value for on/off (1/0) 285 * Returns: 286 * SOC_E_NONE 287 */ 288 289 STATIC int 290 phy_xgxs1_lb_get(int unit, soc_port_t port, int *enable) 291 { 292 uint16 reg_val; 293 uint16 lb_bit; 294 phy_ctrl_t *pc; 295 296 pc = INT_PHY_SW_STATE(unit, port); 297 298 if (IS_LMD_ENABLED_PORT(unit, port)) { 299 SOC_IF_ERROR_RETURN /* Get Loopback status*/ 300 (READ_PHYXGXS_BLK1_LANE_CTRL2r(unit, pc, ®_val)); 301 302 *enable = ((reg_val & 0x000F) == 0x000f) ? TRUE : FALSE; 303 return SOC_E_NONE; 304 } 305 306 lb_bit = XGXS_IEEE_CTRL_LB_ENA; 307 if (IS_XE_PORT(unit, port)) { 308 if (soc_feature(unit, soc_feature_xgxs_v5) || 309 soc_feature(unit, soc_feature_xgxs_v6)) { 310 lb_bit = 1; 311 } 312 } 313 314 SOC_IF_ERROR_RETURN 315 (READ_PHYXGXS_XAUI_MII_CTRLr(unit, pc, ®_val)); 316 317 *enable = (reg_val & lb_bit) ? TRUE : FALSE; 318 319 return SOC_E_NONE; 320 } 321 322 STATIC int 323 phy_xgxs1_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode) 324 { 325 if (NULL == mode) { 326 return SOC_E_PARAM; 327 } 328 329 *mode = SOC_PM_MII | SOC_PM_XGMII | SOC_PM_LB_PHY | 330 SOC_PM_PAUSE | SOC_PM_PAUSE_ASYMM; 331 332 if (IS_LMD_ENABLED_PORT(unit, port)) { 333 *mode |= SOC_PM_2500MB_FD; 334 } else { 335 *mode |= SOC_PM_10GB_FD; 336 } 337 338 return SOC_E_NONE; 339 } 340 341 STATIC int 342 _phy_xgxs1_control_tx_driver_set(int unit, phy_ctrl_t *pc, 343 soc_phy_control_t type, uint32 value) 344 { 345 uint16 data; /* Temporary holder of reg value to be written */ 346 uint16 mask; /* Bit mask of reg value to be updated */ 347 348 if (value > 15) { 349 return SOC_E_PARAM; 350 } 351 352 data = mask = 0; 353 switch(type) { 354 case SOC_PHY_CONTROL_PREEMPHASIS: 355 data = _shr_bit_rev8((uint8)value) << 8; 356 mask = 0xF000; 357 break; 358 case SOC_PHY_CONTROL_DRIVER_CURRENT: 359 data = _shr_bit_rev8((uint8)value) << 4; 360 mask = 0x0F00; 361 break; 362 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 363 data = _shr_bit_rev8((uint8)value); 364 mask = 0x00F0; 365 break; 366 default: 367 /* should never get here */ 368 return SOC_E_PARAM; 369 } 370 371 /* Update preemphasis/driver/pre-driver current */ 372 SOC_IF_ERROR_RETURN 373 (MODIFY_PHYXGXS_TXALL_DRIVERr(unit, pc, data, mask)); 374 375 return SOC_E_NONE; 376 } 377 378 STATIC int 379 _phy_xgxs1_control_tx_driver_get(int unit, phy_ctrl_t *pc, 380 soc_phy_control_t type, uint32 *value) 381 { 382 uint16 data16; /* Temporary holder of 16 bit reg value */ 383 uint8 data8; /* Temporary holder of 8 bit reg value */ 384 385 /* Read preemphasis/driver/pre-driver current */ 386 SOC_IF_ERROR_RETURN 387 (READ_PHYXGXS_TXALL_DRIVERr(unit, pc, &data16)); 388 389 switch(type) { 390 case SOC_PHY_CONTROL_PREEMPHASIS: 391 data8 = (uint8)((data16 & 0xF000) >> 8); 392 *value = _shr_bit_rev8(data8); 393 break; 394 case SOC_PHY_CONTROL_DRIVER_CURRENT: 395 data8 = (uint8)((data16 & 0x0F00) >> 4); 396 *value = _shr_bit_rev8(data8); 397 break; 398 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 399 data8 = (uint8)(data16 & 0x00F0); 400 *value = _shr_bit_rev8(data8); 401 break; 402 default: 403 /* should never get here */ 404 return SOC_E_PARAM; 405 } 406 407 return SOC_E_NONE; 408 } 409 410 /* 411 * Function: 412 * phy_xgxs1_control_set 413 * Purpose: 414 * Configure PHY device specific control fucntion. 415 * Parameters: 416 * unit - StrataSwitch unit #. 417 * port - StrataSwitch port #. 418 * type - Control to update 419 * value - New setting for the control 420 * Returns: 421 * SOC_E_NONE 422 */ 423 STATIC int 424 phy_xgxs1_control_set(int unit, soc_port_t port, 425 soc_phy_control_t type, uint32 value) 426 { 427 int rv; 428 phy_ctrl_t *pc; 429 /* coverity[mixed_enums] */ 430 if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) { 431 return SOC_E_PARAM; 432 } 433 434 pc = INT_PHY_SW_STATE(unit, port); 435 rv = SOC_E_UNAVAIL; 436 switch(type) { 437 case SOC_PHY_CONTROL_PREEMPHASIS: 438 /* fall through */ 439 case SOC_PHY_CONTROL_DRIVER_CURRENT: 440 /* fall through */ 441 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 442 rv = _phy_xgxs1_control_tx_driver_set(unit, pc, type, value); 443 break; 444 case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT: 445 /* No support for force link tx */ 446 rv = SOC_E_UNAVAIL; 447 break; 448 default: 449 rv = SOC_E_UNAVAIL; 450 break; 451 } 452 return rv; 453 } 454 455 /* 456 * Function: 457 * phy_xgxs1_control_get 458 * Purpose: 459 * Get current control settign of the PHY. 460 * Parameters: 461 * unit - StrataSwitch unit #. 462 * port - StrataSwitch port #. 463 * type - Control to update 464 * value - (OUT)Current setting for the control 465 * Returns: 466 * SOC_E_NONE 467 */ 468 STATIC int 469 phy_xgxs1_control_get(int unit, soc_port_t port, 470 soc_phy_control_t type, uint32 *value) 471 { 472 int rv; 473 phy_ctrl_t *pc; 474 475 if (NULL == value) { 476 return SOC_E_PARAM; 477 } 478 /* coverity[mixed_enums] */ 479 if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) { 480 return SOC_E_PARAM; 481 } 482 483 pc = INT_PHY_SW_STATE(unit, port); 484 rv = SOC_E_UNAVAIL; 485 switch(type) { 486 case SOC_PHY_CONTROL_PREEMPHASIS: 487 /* fall through */ 488 case SOC_PHY_CONTROL_DRIVER_CURRENT: 489 /* fall through */ 490 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 491 rv = _phy_xgxs1_control_tx_driver_get(unit, pc, type, value); 492 break; 493 case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT: 494 /* No support for force link tx */ 495 rv = SOC_E_UNAVAIL; 496 break; 497 default: 498 rv = SOC_E_UNAVAIL; 499 break; 500 } 501 502 return rv; 503 } 504 505 STATIC int 506 phy_xgxs1_notify(int unit, soc_port_t port, 507 soc_phy_event_t event, uint32 value) 508 { 509 int rv; 510 511 if (event >= phyEventCount) { 512 return SOC_E_PARAM; 513 } 514 515 rv = SOC_E_NONE; 516 switch(event) { 517 case phyEventInterface: 518 case phyEventDuplex: 519 case phyEventSpeed: 520 case phyEventStop: 521 case phyEventResume: 522 case phyEventAutoneg: 523 break; 524 default: 525 rv = SOC_E_UNAVAIL; 526 break; 527 } 528 529 return rv; 530 } 531 532 #ifdef XGXS1_QUICK_LINK_FLAPPING_FIX 533 STATIC int 534 phy_xgxs1_linkdown(int unit, soc_port_t port) 535 { 536 /* Workaround for Pass 0 silicon */ 537 return soc_fusioncore_reset(unit, port, -1); 538 } 539 #else /* no flapping */ 540 541 #define phy_xgxs1_linkdown NULL 542 543 #endif /* XGXS1_QUICK_LINK_FLAPPING_FIX */ 544 545 /* 546 * Variable: 547 * phy_xgxs1_drv 548 * Purpose: 549 * Phy Driver for 10G (XAUI x 4) Serdes PHY. 550 */ 551 552 phy_driver_t phy_xgxs1_hg = { 553 "XGXS 10G PHY Driver", 554 phy_xgxs1_init, /* Init */ 555 phy_null_reset, /* Reset (dummy) */ 556 phy_xgxs1_link_get, /* Link get */ 557 phy_xgxs1_enable_set, /* Enable set */ 558 phy_null_enable_get, /* Enable get */ 559 phy_null_set, /* Duplex set */ 560 phy_null_one_get, /* Duplex get */ 561 phy_null_speed_set, /* Speed set */ 562 phy_xgxs1_speed_get, /* Speed get */ 563 phy_null_set, /* Master set */ 564 phy_null_zero_get, /* Master get */ 565 phy_null_set, /* ANA set */ 566 phy_null_an_get, /* ANA get */ 567 phy_null_mode_set, /* Local Advert set */ 568 phy_null_mode_get, /* Local Advert get */ 569 phy_null_mode_get, /* Remote Advert get */ 570 phy_xgxs1_lb_set, /* PHY loopback set */ 571 phy_xgxs1_lb_get, /* PHY loopback set */ 572 phy_null_interface_set, /* IO Interface set */ 573 phy_null_interface_get, /* IO Interface get */ 574 phy_xgxs1_ability_get, /* PHY abilities mask */ 575 NULL, 576 phy_xgxs1_linkdown, 577 phy_null_mdix_set, 578 phy_null_mdix_get, 579 phy_null_mdix_status_get, 580 NULL, 581 NULL, 582 phy_null_medium_get, 583 NULL, /* phy_cable_diag */ 584 NULL, /* phy_link_change */ 585 phy_xgxs1_control_set, 586 phy_xgxs1_control_get, 587 phy_xgxs_reg_read, 588 phy_xgxs_reg_write, 589 phy_xgxs_reg_modify, 590 phy_xgxs1_notify /* phy_notify */ 591 }; 592 593 #endif /* INCLUDE_PHY_XGXS1 */ 594 595 int _phy_xgxs1_not_empty;