qsgmii65.c (55029B)
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: 8 * qsgmii65.c 9 * Purpose: 10 * Fiber driver for serdes 65nm Low Power using internal Serdes PHY. 11 * 12 * When operating with an external PHY, this driver is not used. 13 * However the speed/duplex of the internal PHY must be programmed to 14 * match the MAC and external PHY settings so the data can pass through. 15 * This file supplies some routines to allow mac.c to accomplish this 16 * (think of the internal PHY as part of the MAC in this case): 17 * 18 * phy_qsgmii65_notify_duplex 19 * phy_qsgmii65_notify_speed 20 * phy_qsgmii65_notify_stop 21 * phy_qsgmii65_notify_resume 22 */ 23 24 #include <sal/types.h> 25 #include <sal/core/spl.h> 26 #include <shared/bsl.h> 27 #include <soc/drv.h> 28 #include <soc/debug.h> 29 #include <soc/error.h> 30 #include <soc/phy.h> 31 #include <soc/phyreg.h> 32 33 #include <soc/phy.h> 34 #include <soc/phy/phyctrl.h> 35 #include <soc/phy/drv.h> 36 37 #include "phydefs.h" /* Must include before other phy related includes */ 38 39 #if defined(INCLUDE_XGXS_QSGMII65) 40 #include "phyconfig.h" /* Must be the first phy include after phydefs.h */ 41 #include "phyident.h" 42 #include "phyreg.h" 43 #include "phynull.h" 44 #include "serdes.h" 45 #include "qsgmii65.h" 46 47 #define WORKAROUND_FIX 1 48 49 #define ADVERT_ALL_FIBER \ 50 (SOC_PM_PAUSE | SOC_PM_1000MB_FD) 51 52 /* Notify event forward declaration */ 53 STATIC int 54 _phy_qsgmii65_notify_duplex(int unit, soc_port_t port, uint32 duplex); 55 STATIC int 56 _phy_qsgmii65_notify_speed(int unit, soc_port_t port, uint32 speed); 57 STATIC int 58 _phy_qsgmii65_notify_stop(int unit, soc_port_t port, uint32 flags); 59 STATIC int 60 _phy_qsgmii65_notify_resume(int unit, soc_port_t port, uint32 flags); 61 STATIC int 62 _phy_qsgmii65_notify_interface(int unit, soc_port_t port, uint32 intf); 63 64 /*********************************************************************** 65 * 66 * FIBER DRIVER ROUTINES 67 */ 68 STATIC int 69 _phy_qsgmii65_tx_control_set(int unit, phy_ctrl_t *pc, 70 soc_port_t port) 71 { 72 uint32 preemph; 73 uint32 idriver; 74 uint32 pdriver; 75 uint16 data; 76 uint16 mask; 77 78 SOC_IF_ERROR_RETURN 79 (READ_QSGMII65_1000X_STAT1r(unit, pc, &data)); 80 81 if (data & LP_1000X_STATUS1_SGMII_MODE) { 82 /* SGMII mode */ 83 idriver = 0x1; 84 pdriver = 0x7; 85 } else { 86 /* 1000X mode */ 87 idriver = 0x1; 88 pdriver = 0x7; 89 } 90 preemph = 0x0; 91 92 /* Read config override */ 93 preemph = soc_property_port_get(unit, port, 94 spn_SERDES_PREEMPHASIS, preemph); 95 idriver = soc_property_port_get(unit, port, 96 spn_SERDES_DRIVER_CURRENT, idriver); 97 pdriver = soc_property_port_get(unit, port, 98 spn_SERDES_PRE_DRIVER_CURRENT, pdriver); 99 100 if (data & LP_1000X_STATUS1_SGMII_MODE) { 101 /* SGMII mode */ 102 data = ((preemph & 0xf) << 12) | ((idriver & 0xf) << 8) | ((pdriver & 0xf) << 4); 103 mask = 0xfff0; 104 SOC_IF_ERROR_RETURN 105 (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask)); 106 } else { 107 /* 1000X mode */ 108 data = ((preemph & 0xf) << 12) | ((idriver & 0xf) << 8) | ((pdriver & 0xf) << 4); 109 mask = 0xfff0; 110 SOC_IF_ERROR_RETURN 111 (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask)); 112 } 113 return SOC_E_NONE; 114 } 115 116 STATIC int 117 _phy_qsgmii65_init_no_reset(int unit, soc_port_t port) 118 { 119 uint16 data16, mask16; 120 uint16 mode_1000x; 121 soc_timeout_t to; 122 phy_ctrl_t *pc; 123 int rv; 124 125 pc = INT_PHY_SW_STATE(unit, port); 126 pc->fiber.enable = PHY_FIBER_MODE(unit, port); 127 pc->fiber.preferred = PHY_FIBER_MODE(unit, port); 128 pc->fiber.autoneg_enable = 1; 129 pc->fiber.autoneg_advert = ADVERT_ALL_FIBER; 130 pc->fiber.force_speed = 1000; 131 pc->fiber.force_duplex = TRUE; 132 pc->fiber.master = SOC_PORT_MS_NONE; 133 pc->fiber.mdix = SOC_PORT_MDIX_NORMAL; 134 135 /* Since phyqsgmii65 driver reset function vector does not reset 136 * the SerDes, reset the SerDes in initialization first. 137 * The internal SERDES PHY's reset bit is self-clearing. 138 */ 139 SOC_IF_ERROR_RETURN 140 (MODIFY_QSGMII65_MII_CTRLr(unit, pc, 141 MII_CTRL_RESET, MII_CTRL_RESET)); 142 143 soc_timeout_init(&to, 10000, 0); 144 while (!soc_timeout_check(&to)) { 145 rv = READ_QSGMII65_MII_CTRLr(unit, pc, &data16); 146 if (((data16 & MII_CTRL_RESET) == 0) || SOC_FAILURE(rv)) { 147 break; 148 } 149 } 150 if ((data16 & MII_CTRL_RESET) != 0) { 151 LOG_WARN(BSL_LS_SOC_PHY, 152 (BSL_META_U(unit, 153 "Combo SerDes reset failed: u=%d p=%d\n"), 154 unit, port)); 155 } 156 157 if (pc->lane_num == 0) { 158 data16 = 0x0000; 159 switch (soc_property_port_get(unit, port, 160 spn_SERDES_QSGMII_SGMII_OVERRIDE, 0)) { 161 case 1: /* QSGMII mode */ 162 data16 = 0x1100; 163 /* Fall Thru */ 164 case 2: /* SGMII mode */ 165 SOC_IF_ERROR_RETURN 166 (MODIFY_QSGMII65_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x0000, 0x2000)); 167 168 mask16 = 0xff00; 169 SOC_IF_ERROR_RETURN 170 (MODIFY_QSGMII65_LANE_CTRL0r(unit, pc, data16, mask16)); 171 172 SOC_IF_ERROR_RETURN 173 (MODIFY_QSGMII65_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x2000, 0x2000)); 174 175 pc->lane_num = 4; 176 177 SOC_IF_ERROR_RETURN 178 (MODIFY_QSGMII65_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x0000, 0x2000)); 179 180 SOC_IF_ERROR_RETURN 181 (MODIFY_QSGMII65_LANE_CTRL0r(unit, pc, data16, mask16)); 182 183 SOC_IF_ERROR_RETURN 184 (MODIFY_QSGMII65_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x2000, 0x2000)); 185 186 pc->lane_num = 0; 187 default: /* H/W default */ 188 break; 189 } 190 } 191 192 /* Set the default speed/duplex/autoneg */ 193 data16 = MII_CTRL_FD | MII_CTRL_SS_1000; 194 if ((PHY_FIBER_MODE(unit, port) && !PHY_EXTERNAL_MODE(unit, port)) || 195 PHY_PASSTHRU_MODE(unit, port) || 196 PHY_SGMII_AUTONEG_MODE(unit, port)) { 197 data16 |= MII_CTRL_AE | MII_CTRL_RAN; 198 } 199 200 /* If enabling autoneg, make sure that the default speed and duplex 201 * are set correctly. 202 */ 203 if (data16 & MII_CTRL_AE) { 204 /* Advertise default speed and duplex */ 205 SOC_IF_ERROR_RETURN 206 (WRITE_QSGMII65_MII_ANAr(unit, pc, MII_ANA_C37_FD | 207 MII_ANA_C37_PAUSE | 208 MII_ANA_C37_ASYM_PAUSE)); 209 } 210 SOC_IF_ERROR_RETURN 211 (WRITE_QSGMII65_MII_CTRLr(unit, pc, data16)); 212 213 /* Configure auto-detect and fiber vs. sgmii mode */ 214 data16 = LP_1000X_PLL_PWRDWN; 215 mask16 = LP_1000X_PLL_PWRDWN | 216 LP_1000X_AUTO_DETECT | LP_1000X_FIBER_MODE; 217 /* 218 * Configure signal auto-detection between SGMII and fiber. 219 * This detection only works if auto-negotiation is enabled. 220 */ 221 if (soc_property_port_get(unit, port, 222 spn_SERDES_AUTOMEDIUM, FALSE)) { 223 data16 |= LP_1000X_AUTO_DETECT; 224 } 225 226 /* 227 * Put the Serdes in Fiber or SGMII mode 228 */ 229 mode_1000x = 0; 230 if ((PHY_FIBER_MODE(unit, port) && !PHY_EXTERNAL_MODE(unit, port)) || 231 PHY_PASSTHRU_MODE(unit, port)) { 232 mode_1000x = LP_1000X_FIBER_MODE; 233 } 234 /* Allow property to override */ 235 if (soc_property_port_get(unit, port, 236 spn_SERDES_FIBER_PREF, mode_1000x)) { 237 data16 |= LP_1000X_FIBER_MODE; 238 } else { 239 data16 &= ~LP_1000X_FIBER_MODE; 240 } 241 if (soc_property_port_get(unit, port, 242 spn_SERDES_SGMII_MASTER, FALSE)) { 243 data16 |= LP_1000X_SGMII_MASTER; 244 mask16 |= LP_1000X_SGMII_MASTER; 245 } 246 247 SOC_IF_ERROR_RETURN 248 (MODIFY_QSGMII65_1000X_CTRL1r(unit, pc, data16, mask16)); 249 250 data16 = LP_1000X_PAR_DET_EN; 251 mask16 = LP_1000X_FILTER_FORCE_EN | 252 LP_1000X_FORCE_XMIT_DATA_ON_TXSIDE | 253 LP_1000X_PAR_DET_EN; 254 if ((PHY_EXTERNAL_MODE(unit, port) && PHY_PASSTHRU_MODE(unit, port)) || 255 (!PHY_EXTERNAL_MODE(unit, port) && PHY_FIBER_MODE(unit, port))) { 256 /* Wait 10ms for sync status before a valid link is 257 * established when auto-negotiation is disabled. 258 */ 259 data16 |= LP_1000X_FILTER_FORCE_EN; 260 } 261 262 SOC_IF_ERROR_RETURN 263 (MODIFY_QSGMII65_1000X_CTRL2r(unit, pc, data16, mask16)); 264 265 if (soc_property_port_get(unit, port, "serdes_fifo_low_latency", 0)) { 266 data16 = LP_1000X_FREQ_LOCK_ELASTICITY_RX | 267 LP_1000X_FREQ_LOCK_ELASTICITY_TX; 268 mask16 = LP_1000X_FIFO_ELASTICITY_MASK | 269 LP_1000X_FREQ_LOCK_ELASTICITY_RX | 270 LP_1000X_FREQ_LOCK_ELASTICITY_TX; 271 SOC_IF_ERROR_RETURN 272 (MODIFY_QSGMII65_1000X_CTRL3r(unit, pc, data16, mask16)); 273 } 274 275 #if WORKAROUND_FIX 276 #ifdef BCM_HAWKEYE_SUPPORT 277 if (soc_feature(unit, soc_feature_hawkeye_a0_war)) { 278 /* Workaroud : 279 * change the TX driver register to value 170H 280 * for revision A0 of HAWKEYE and PHY 54684 281 * (Addr : 0x8067) 282 */ 283 if(pc->lane_num == 0){ 284 SOC_IF_ERROR_RETURN 285 (_phy_qsgmii65_tx_control_set(unit, pc, port)); 286 } 287 288 /* Workaroud : 289 * Make disparity error check configuration 290 */ 291 if((pc->lane_num == 0) || (pc->lane_num == 4)){ 292 SOC_IF_ERROR_RETURN 293 (QSGMII65_REG_WRITE(unit, pc, 0x00, 0x000080ba, 0x00d0)); 294 SOC_IF_ERROR_RETURN 295 (QSGMII65_REG_WRITE(unit, pc, 0x00, 0x00008105, 0xf000)); 296 } 297 } 298 #endif 299 #endif 300 LOG_INFO(BSL_LS_SOC_PHY, 301 (BSL_META_U(unit, 302 "phy_qsgmii65_init: u=%d p=%d %s\n"), 303 unit, port, 304 PHY_FIBER_MODE(unit, port)? "Fiber" : "Copper")); 305 306 return SOC_E_NONE; 307 } 308 309 310 /* 311 * Function: 312 * phy_qsgmii65_init 313 * Purpose: 314 * Initialize qsgmii65 internal PHY driver 315 * Parameters: 316 * unit - StrataSwitch unit #. 317 * port - StrataSwitch port #. 318 * Returns: 319 * SOC_E_NONE 320 * Notes: 321 * This function implements the bulk part of phy_qsgmii65_init and 322 * provides a method for initializing the SerDes when it is used 323 * as an intermediate PHY between the MAC and an external PHY. 324 * In the latter case the PHY driver reset callback should be 325 * called only once, and this has already been done by the 326 * external PHY driver init function. 327 */ 328 329 STATIC int 330 phy_qsgmii65_init(int unit, soc_port_t port) 331 { 332 333 LOG_INFO(BSL_LS_SOC_PHY, 334 (BSL_META_U(unit, 335 "phy_qsgmii65_init: u=%d p=%d\n"), 336 unit, port)); 337 338 if (!PHY_EXTERNAL_MODE(unit, port)) { 339 /* PHY reset callbacks */ 340 SOC_IF_ERROR_RETURN(soc_phy_reset(unit, port)); 341 342 /* No external PHY. SerDes is always in fiber mode. */ 343 if (soc_property_port_get(unit, port, 344 spn_SERDES_FIBER_PREF, 1)) { 345 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER); 346 } else { 347 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER); 348 } 349 350 } 351 352 SOC_IF_ERROR_RETURN 353 (_phy_qsgmii65_init_no_reset(unit, port)); 354 355 return SOC_E_NONE; 356 } 357 358 /* 359 * Function: 360 * phy_qsgmii65_link_get 361 * Purpose: 362 * Determine the current link up/down status 363 * Parameters: 364 * unit - StrataSwitch unit #. 365 * port - StrataSwitch port #. 366 * link - (OUT) Boolean, true indicates link established. 367 * Returns: 368 * SOC_E_XXX 369 * Notes: 370 * MII_STATUS bit 2 reflects link state. 371 */ 372 373 STATIC int 374 phy_qsgmii65_link_get(int unit, soc_port_t port, int *link) 375 { 376 uint16 mii_stat; 377 int an_done; 378 phy_ctrl_t *pc; 379 380 if (PHY_DISABLED_MODE(unit, port)) { 381 *link = FALSE; 382 } else { 383 pc = INT_PHY_SW_STATE(unit, port); 384 385 SOC_IF_ERROR_RETURN 386 (READ_QSGMII65_MII_STATr(unit, pc, &mii_stat)); 387 388 *link = ((mii_stat & MII_STAT_LA) != 0); 389 390 if (pc->fiber.autoneg_enable) { 391 /* If autoneg is enabled, check for autoneg done. */ 392 an_done = ((mii_stat & MII_STAT_AN_DONE) != 0); 393 394 *link = (*link) && (an_done); 395 } 396 } 397 398 return SOC_E_NONE; 399 } 400 401 /* 402 * Function: 403 * phy_qsgmii65_enable_set 404 * Purpose: 405 * Enable or disable the physical interface. 406 * Parameters: 407 * unit - StrataSwitch unit #. 408 * port - StrataSwitch port #. 409 * enable - Boolean, true = enable PHY, false = disable. 410 * Returns: 411 * SOC_E_XXX 412 * Notes: 413 * The PHY is held in reset when disabled. Also, the 414 * MISC_CONTROL.IDDQ bit must be set to 1 so the remote partner 415 * sees link down. 416 */ 417 418 STATIC int 419 phy_qsgmii65_enable_set(int unit, soc_port_t port, int enable) 420 { 421 LOG_INFO(BSL_LS_SOC_PHY, 422 (BSL_META_U(unit, 423 "phy_qsgmii65_enable_set: u=%d p=%d en=%d\n"), 424 unit, port, enable)); 425 if (enable) { 426 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE); 427 428 SOC_IF_ERROR_RETURN 429 (_phy_qsgmii65_notify_resume(unit, port, PHY_STOP_PHY_DIS)); 430 } else { 431 PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE); 432 433 SOC_IF_ERROR_RETURN 434 (_phy_qsgmii65_notify_stop(unit, port, PHY_STOP_PHY_DIS)); 435 } 436 437 return SOC_E_NONE; 438 } 439 440 441 STATIC int 442 _phy_qsgmii65_sgmii_speed_set(int unit, soc_port_t port, int speed) 443 { 444 uint16 mii_ctrl; 445 phy_ctrl_t *pc; 446 447 pc = INT_PHY_SW_STATE(unit, port); 448 449 switch (speed) { 450 case 10: 451 mii_ctrl = MII_CTRL_SS_10; 452 break; 453 case 100: 454 mii_ctrl = MII_CTRL_SS_100; 455 break; 456 case 0: 457 case 1000: 458 mii_ctrl = MII_CTRL_SS_1000; 459 break; 460 default: 461 return SOC_E_CONFIG; 462 } 463 SOC_IF_ERROR_RETURN 464 (MODIFY_QSGMII65_MII_CTRLr(unit, pc, mii_ctrl, MII_CTRL_SS_MASK)); 465 return SOC_E_NONE; 466 } 467 468 STATIC int 469 _phy_qsgmii65_1000x_speed_set(int unit, soc_port_t port, int speed) 470 { 471 if (speed != 1000) { 472 return SOC_E_CONFIG; 473 } 474 return SOC_E_NONE; 475 } 476 477 /* 478 * Function: 479 * phy_qsgmii65_speed_set 480 * Purpose: 481 * Set the current operating speed (forced). 482 * Parameters: 483 * unit - StrataSwitch unit #. 484 * port - StrataSwitch port #. 485 * speed - Speed to set. 486 * Returns: 487 * SOC_E_XXX 488 */ 489 490 STATIC int 491 phy_qsgmii65_speed_set(int unit, soc_port_t port, int speed) 492 { 493 uint16 fiber_status; 494 phy_ctrl_t *pc; 495 int rv; 496 497 pc = INT_PHY_SW_STATE(unit, port); 498 rv = SOC_E_NONE; 499 500 SOC_IF_ERROR_RETURN 501 (READ_QSGMII65_1000X_STAT1r(unit, pc, &fiber_status)); 502 503 if (fiber_status & LP_1000X_STATUS1_SGMII_MODE) { 504 rv = _phy_qsgmii65_sgmii_speed_set(unit, port, speed); 505 } else { 506 rv = _phy_qsgmii65_1000x_speed_set(unit, port, speed); 507 } 508 509 if (SOC_SUCCESS(rv)) { 510 pc->fiber.force_speed = speed; 511 } 512 513 LOG_INFO(BSL_LS_SOC_PHY, 514 (BSL_META_U(unit, 515 "phy_qsgmii65_speed_set: u=%d p=%d speed=%d rv=%d\n"), 516 unit, port, speed, rv)); 517 518 return rv; 519 } 520 521 STATIC int 522 _phy_qsgmii65_sgmii_speed_get(int unit, soc_port_t port, int *speed) 523 { 524 uint16 mii_ctrl, mii_stat, mii_anp; 525 phy_ctrl_t *pc; 526 527 pc = INT_PHY_SW_STATE(unit, port); 528 529 SOC_IF_ERROR_RETURN 530 (READ_QSGMII65_MII_CTRLr(unit, pc, &mii_ctrl)); 531 SOC_IF_ERROR_RETURN 532 (READ_QSGMII65_MII_STATr(unit, pc, &mii_stat)); 533 534 if (mii_ctrl & MII_CTRL_AE) { /*Auto-negotiation enabled */ 535 if (!(mii_stat & MII_STAT_AN_DONE)) { /* Auto-neg NOT complete */ 536 *speed = 0; 537 return SOC_E_NONE; 538 } else { /* Read Advertise link partner */ 539 SOC_IF_ERROR_RETURN 540 (READ_QSGMII65_MII_ANPr(unit, pc, &mii_anp)); 541 if (mii_anp & MII_ANP_SGMII_MODE) { 542 switch(mii_anp & MII_ANP_SGMII_SS_MASK) { 543 case MII_ANP_SGMII_SS_1000: 544 *speed = 1000; 545 break; 546 case MII_ANP_SGMII_SS_100: 547 *speed = 100; 548 break; 549 case MII_ANP_SGMII_SS_10: 550 *speed = 10; 551 break; 552 default: 553 return SOC_E_INTERNAL; 554 } 555 } 556 } 557 } else { /* Forced speed */ 558 switch(mii_ctrl & MII_CTRL_SS_MASK) { 559 case MII_CTRL_SS_10: 560 *speed = 10; 561 break; 562 case MII_CTRL_SS_100: 563 *speed = 100; 564 break; 565 case MII_CTRL_SS_1000: 566 *speed = 1000; 567 break; 568 default: 569 return SOC_E_INTERNAL; 570 } 571 } 572 return SOC_E_NONE; 573 } 574 575 STATIC int 576 _phy_qsgmii65_1000x_speed_get(int unit, soc_port_t port, int *speed) 577 { 578 *speed = 1000; 579 580 return SOC_E_NONE; 581 } 582 583 /* 584 * Function: 585 * phy_qsgmii65_speed_get 586 * Purpose: 587 * Get the current operating speed. If autoneg is enabled, 588 * then operating mode is returned, otherwise forced mode is returned. 589 * Parameters: 590 * unit - StrataSwitch unit #. 591 * port - StrataSwitch port #. 592 * speed - Current port speed. 593 * Returns: 594 * SOC_E_XXX 595 */ 596 597 STATIC int 598 phy_qsgmii65_speed_get(int unit, soc_port_t port, int *speed) 599 { 600 uint16 fiber_status; 601 phy_ctrl_t *pc; 602 603 pc = INT_PHY_SW_STATE(unit, port); 604 605 *speed = 1000; 606 607 SOC_IF_ERROR_RETURN 608 (READ_QSGMII65_1000X_STAT1r(unit, pc, &fiber_status)); 609 610 if (fiber_status & LP_1000X_STATUS1_SGMII_MODE) { 611 SOC_IF_ERROR_RETURN 612 (_phy_qsgmii65_sgmii_speed_get(unit, port, speed)); 613 } else { 614 SOC_IF_ERROR_RETURN 615 (_phy_qsgmii65_1000x_speed_get(unit, port, speed)); 616 } 617 618 return SOC_E_NONE; 619 } 620 621 /* 622 * Function: 623 * phy_qsgmii65_an_set 624 * Purpose: 625 * Enable or disabled auto-negotiation on the specified port. 626 * Parameters: 627 * unit - StrataSwitch unit #. 628 * port - StrataSwitch port #. 629 * an - Boolean, if true, auto-negotiation is enabled 630 * (and/or restarted). If false, autonegotiation is disabled. 631 * Returns: 632 * SOC_E_XXX 633 */ 634 635 STATIC int 636 phy_qsgmii65_an_set(int unit, soc_port_t port, int an) 637 { 638 phy_ctrl_t *pc; 639 uint16 an_enable; 640 uint16 auto_det; 641 642 pc = INT_PHY_SW_STATE(unit, port); 643 644 LOG_INFO(BSL_LS_SOC_PHY, 645 (BSL_META_U(unit, 646 "phy_qsgmii65_an_set: u=%d p=%d an=%d\n"), 647 unit, port, an)); 648 649 an_enable = 0; 650 auto_det = 0; 651 if (an) { 652 an_enable = MII_CTRL_AE | MII_CTRL_RAN; 653 if (soc_property_port_get(unit, port, 654 spn_SERDES_AUTOMEDIUM, FALSE)) { 655 auto_det = LP_1000X_AUTO_DETECT; 656 } 657 } 658 659 SOC_IF_ERROR_RETURN 660 (MODIFY_QSGMII65_1000X_CTRL1r(unit, pc, 661 auto_det, LP_1000X_AUTO_DETECT)); 662 663 /* Enable/Disable and Restart autonegotiation (self-clearing bit) */ 664 SOC_IF_ERROR_RETURN 665 (MODIFY_QSGMII65_MII_CTRLr(unit, pc, an_enable, 666 MII_CTRL_AE | MII_CTRL_RAN)); 667 668 pc->fiber.autoneg_enable = an; 669 670 return SOC_E_NONE; 671 } 672 673 /* 674 * Function: 675 * phy_qsgmii65_an_get 676 * Purpose: 677 * Get the current auto-negotiation status (enabled/busy) 678 * Parameters: 679 * unit - StrataSwitch unit #. 680 * port - StrataSwitch port #. 681 * an - (OUT) if true, auto-negotiation is enabled. 682 * an_done - (OUT) if true, auto-negotiation is complete. 683 * This value is undefined if an == false. 684 * Returns: 685 * SOC_E_XXX 686 */ 687 688 STATIC int 689 phy_qsgmii65_an_get(int unit, soc_port_t port, int *an, int *an_done) 690 { 691 uint16 ctrl, stat; 692 phy_ctrl_t *pc; 693 694 pc = INT_PHY_SW_STATE(unit, port); 695 696 SOC_IF_ERROR_RETURN 697 (READ_QSGMII65_MII_CTRLr(unit, pc, &ctrl)); 698 699 *an = (ctrl & MII_CTRL_AE) != 0; 700 701 SOC_IF_ERROR_RETURN 702 (READ_QSGMII65_MII_STATr(unit, pc, &stat)); 703 704 *an_done = (stat & MII_STAT_AN_DONE) != 0; 705 706 LOG_INFO(BSL_LS_SOC_PHY, 707 (BSL_META_U(unit, 708 "phy_serdes_an_get: u=%d p=%d an=%d an_done=%d\n"), 709 unit, port, *an, *an_done)); 710 711 return SOC_E_NONE; 712 } 713 714 /* 715 * Function: 716 * phy_qsgmii65_adv_local_set 717 * Purpose: 718 * Set the current advertisement for auto-negotiation. 719 * Parameters: 720 * unit - StrataSwitch unit #. 721 * port - StrataSwitch port #. 722 * mode - Port mode mask indicating supported options/speeds. 723 * Returns: 724 * SOC_E_XXX 725 */ 726 STATIC int 727 phy_qsgmii65_adv_local_set(int unit, soc_port_t port, soc_port_mode_t mode) 728 { 729 uint16 an_adv; 730 phy_ctrl_t *pc; 731 732 /* Note: 733 * We assume that switch SerDes is always used as slave when 734 * the port is in SGMII mode. Therefore, the adv_local_set is applicable 735 * only for 1000BASE-X mode and supported only clause 37 autoneg. 736 */ 737 pc = INT_PHY_SW_STATE(unit, port); 738 739 an_adv = 0; 740 741 /* 742 * Set advertised duplex (only FD supported). 743 */ 744 if (mode & SOC_PM_1000MB_FD) { 745 an_adv |= MII_ANA_C37_FD; 746 } 747 748 /* 749 * Set advertised pause bits in link code word. 750 */ 751 switch (mode & SOC_PM_PAUSE) { 752 case SOC_PM_PAUSE_TX: 753 an_adv |= MII_ANA_C37_ASYM_PAUSE; 754 break; 755 case SOC_PM_PAUSE_RX: 756 an_adv |= MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE; 757 break; 758 case SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX: 759 an_adv |= MII_ANA_C37_PAUSE; 760 break; 761 } 762 763 SOC_IF_ERROR_RETURN 764 (MODIFY_QSGMII65_MII_ANAr(unit, pc, an_adv, 765 MII_ANA_C37_ASYM_PAUSE | MII_ANA_C37_PAUSE | 766 MII_ANA_C37_FD | MII_ANA_C37_HD)); 767 768 LOG_INFO(BSL_LS_SOC_PHY, 769 (BSL_META_U(unit, 770 "phy_serdes_adv_local_set: u=%d p=%d adv=%s%s%s\n"), 771 unit, port, 772 (mode & SOC_PM_1000MB_FD) ? "1000MB " : "", 773 (mode & SOC_PM_PAUSE_TX) ? "PAUSE_TX " : "", 774 (mode & SOC_PM_PAUSE_RX) ? "PAUSE_TX " : "")); 775 return SOC_E_NONE; 776 } 777 778 /* 779 * Function: 780 * phy_qsgmii65_adv_local_get 781 * Purpose: 782 * Get the current advertisement for auto-negotiation. 783 * Parameters: 784 * unit - StrataSwitch unit #. 785 * port - StrataSwitch port #. 786 * mode - (OUT) Port mode mask indicating supported options/speeds. 787 * Returns: 788 * SOC_E_XXX 789 */ 790 791 STATIC int 792 phy_qsgmii65_adv_local_get(int unit, soc_port_t port, soc_port_mode_t *mode) 793 { 794 uint16 an_adv; 795 phy_ctrl_t *pc; 796 797 pc = INT_PHY_SW_STATE(unit, port); 798 799 *mode = 0; 800 801 SOC_IF_ERROR_RETURN 802 (READ_QSGMII65_MII_ANAr(unit, pc, &an_adv)); 803 804 if (an_adv & MII_ANA_C37_FD) { 805 *mode |= SOC_PM_1000MB_FD; 806 } 807 808 switch (an_adv & (MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE)) { 809 case MII_ANA_C37_PAUSE: 810 *mode |= SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX; 811 break; 812 case MII_ANA_C37_ASYM_PAUSE: 813 *mode |= SOC_PM_PAUSE_TX; 814 break; 815 case MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE: 816 *mode |= SOC_PM_PAUSE_RX; 817 break; 818 } 819 820 return SOC_E_NONE; 821 } 822 823 STATIC int 824 _phy_qsgmii65_sgmii_adv_remote_get(int unit, soc_port_t port, 825 soc_port_mode_t *mode) 826 { 827 uint16 anlpa; 828 soc_port_mode_t duplex; 829 phy_ctrl_t *pc; 830 831 pc = INT_PHY_SW_STATE(unit, port); 832 833 *mode = 0; 834 835 SOC_IF_ERROR_RETURN 836 (READ_QSGMII65_MII_ANPr(unit, pc, &anlpa)); 837 838 switch (anlpa & MII_ANP_SGMII_SS_MASK) { 839 case MII_ANP_SGMII_SS_10: 840 *mode = SOC_PM_10MB; 841 break; 842 case MII_ANP_SGMII_SS_100: 843 *mode = SOC_PM_100MB; 844 break; 845 case MII_ANP_SGMII_SS_1000: 846 *mode = SOC_PM_1000MB; 847 break; 848 } 849 850 duplex = (anlpa & MII_ANP_SGMII_FD) ? SOC_PM_FD : SOC_PM_HD; 851 852 *mode = (*mode) & duplex; 853 854 return SOC_E_NONE; 855 } 856 857 STATIC int 858 _phy_qsgmii65_1000x_adv_remote_get(int unit, soc_port_t port, 859 soc_port_mode_t *mode) 860 { 861 uint16 anlpa; 862 phy_ctrl_t *pc; 863 864 pc = INT_PHY_SW_STATE(unit, port); 865 866 *mode = 0; 867 868 SOC_IF_ERROR_RETURN 869 (READ_QSGMII65_MII_ANPr(unit, pc, &anlpa)); 870 871 if (anlpa & MII_ANP_C37_FD) { 872 *mode |= SOC_PM_1000MB_FD; 873 } 874 875 if (anlpa & MII_ANP_C37_HD) { 876 *mode |= SOC_PM_1000MB_HD; 877 } 878 879 switch (anlpa & 880 (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) { 881 case MII_ANP_C37_PAUSE: 882 *mode |= SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX; 883 break; 884 case MII_ANP_C37_ASYM_PAUSE: 885 *mode |= SOC_PM_PAUSE_TX; 886 break; 887 case MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE: 888 *mode |= SOC_PM_PAUSE_RX; 889 break; 890 } 891 892 return SOC_E_NONE; 893 } 894 895 /* 896 * Function: 897 * phy_qsgmii65_adv_remote_get 898 * Purpose: 899 * Get partner's current advertisement for auto-negotiation. 900 * Parameters: 901 * unit - StrataSwitch unit #. 902 * port - StrataSwitch port #. 903 * mode - (OUT) Port mode mask indicating supported options/speeds. 904 * Returns: 905 * SOC_E_XXX 906 */ 907 908 int 909 phy_qsgmii65_adv_remote_get(int unit, soc_port_t port, soc_port_mode_t *mode) 910 { 911 uint16 fiber_status; 912 phy_ctrl_t *pc; 913 914 pc = INT_PHY_SW_STATE(unit, port); 915 916 SOC_IF_ERROR_RETURN 917 (READ_QSGMII65_1000X_STAT1r(unit, pc, &fiber_status)); 918 919 if (fiber_status & SERDES_1000X_STAT1_SGMII_MODE) { 920 SOC_IF_ERROR_RETURN 921 (_phy_qsgmii65_sgmii_adv_remote_get(unit, port, mode)); 922 } else { 923 SOC_IF_ERROR_RETURN 924 (_phy_qsgmii65_1000x_adv_remote_get(unit, port, mode)); 925 } 926 927 LOG_INFO(BSL_LS_SOC_PHY, 928 (BSL_META_U(unit, 929 "phy_serdes_adv_remote_get: u=%d p=%d adv=%s%s%s\n"), 930 unit, port, 931 (*mode & SOC_PM_1000MB_FD) ? "1000MB " : "", 932 (*mode & SOC_PM_PAUSE_TX) ? "PAUSE_TX " : "", 933 (*mode & SOC_PM_PAUSE_RX) ? "PAUSE_TX " : "")); 934 935 return SOC_E_NONE; 936 } 937 938 /* 939 * Function: 940 * phy_qsgmii65_lb_set 941 * Purpose: 942 * Set the internal PHY loopback mode. 943 * Parameters: 944 * unit - StrataSwitch unit #. 945 * port - StrataSwitch port #. 946 * loopback - Boolean: true = enable loopback, false = disable. 947 * Returns: 948 * SOC_E_XXX 949 */ 950 951 STATIC int 952 phy_qsgmii65_lb_set(int unit, soc_port_t port, int enable) 953 { 954 uint16 ctrl; 955 phy_ctrl_t *pc; 956 int rv; 957 958 pc = INT_PHY_SW_STATE(unit, port); 959 960 ctrl = (enable) ?MII_CTRL_LE : 0; 961 962 rv = MODIFY_QSGMII65_MII_CTRLr(unit, pc, 963 ctrl, MII_CTRL_LE); 964 965 LOG_INFO(BSL_LS_SOC_PHY, 966 (BSL_META_U(unit, 967 "phy_serdes_lb_set: u=%d p=%d lb=%d rv=%d\n"), 968 unit, port, enable, rv)); 969 970 return rv; 971 } 972 973 /* 974 * Function: 975 * phy_serdes_lb_get 976 * Purpose: 977 * Get the local PHY loopback mode. 978 * Parameters: 979 * unit - StrataSwitch unit #. 980 * port - StrataSwitch port #. 981 * loopback - (OUT) Boolean: true = enable loopback, false = disable. 982 * Returns: 983 * SOC_E_XXX 984 */ 985 986 STATIC int 987 phy_qsgmii65_lb_get(int unit, soc_port_t port, int *enable) 988 { 989 uint16 ctrl; 990 phy_ctrl_t *pc; 991 992 pc = INT_PHY_SW_STATE(unit, port); 993 SOC_IF_ERROR_RETURN 994 (READ_QSGMII65_MII_CTRLr(unit, pc, &ctrl)); 995 996 *enable = (ctrl & MII_CTRL_LE) != 0; 997 998 return SOC_E_NONE; 999 } 1000 1001 1002 /* 1003 * Function: 1004 * phy_qsgmii65_ability_get 1005 * Purpose: 1006 * Get the abilities of the internal PHY. 1007 * Parameters: 1008 * unit - StrataSwitch unit #. 1009 * port - StrataSwitch port #. 1010 * mode - (OUT) Port mode mask indicating supported options/speeds. 1011 * Returns: 1012 * SOC_E_XXX 1013 */ 1014 1015 STATIC int 1016 phy_qsgmii65_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode) 1017 { 1018 uint16 fiber_status; 1019 phy_ctrl_t *pc; 1020 1021 pc = INT_PHY_SW_STATE(unit, port); 1022 SOC_IF_ERROR_RETURN 1023 (READ_QSGMII65_1000X_STAT1r(unit, pc, &fiber_status)); 1024 1025 if (fiber_status & LP_1000X_STATUS1_SGMII_MODE) { 1026 *mode = (SOC_PM_10MB | SOC_PM_100MB | SOC_PM_1000MB_FD | 1027 SOC_PM_LB_PHY | SOC_PM_GMII); 1028 } else { 1029 *mode = (SOC_PM_1000MB_FD | SOC_PM_100MB_FD | 1030 SOC_PM_PAUSE | SOC_PM_PAUSE_ASYMM | SOC_PM_AN | 1031 SOC_PM_LB_PHY | SOC_PM_GMII); 1032 } 1033 1034 1035 1036 return SOC_E_NONE; 1037 } 1038 1039 /* 1040 * Function: 1041 * _phy_qsgmii65_medium_config_update 1042 * Purpose: 1043 * Update the PHY with config parameters 1044 * Parameters: 1045 * unit - StrataSwitch unit #. 1046 * port - StrataSwitch port #. 1047 * cfg - Config structure. 1048 * Returns: 1049 * SOC_E_XXX 1050 */ 1051 1052 STATIC int 1053 _phy_qsgmii65_medium_config_update(int unit, soc_port_t port, 1054 soc_phy_config_t *cfg) 1055 { 1056 SOC_IF_ERROR_RETURN 1057 (phy_qsgmii65_speed_set(unit, port, cfg->force_speed)); 1058 SOC_IF_ERROR_RETURN 1059 (phy_serdes_duplex_set(unit, port, cfg->force_duplex)); 1060 SOC_IF_ERROR_RETURN 1061 (phy_serdes_adv_local_set(unit, port, cfg->autoneg_advert)); 1062 SOC_IF_ERROR_RETURN 1063 (phy_qsgmii65_an_set(unit, port, cfg->autoneg_enable)); 1064 1065 return SOC_E_NONE; 1066 } 1067 1068 /* 1069 * Function: 1070 * phy_qsgmii65_medium_config_set 1071 * Purpose: 1072 * Set the operating parameters that are automatically selected 1073 * when medium switches type. 1074 * Parameters: 1075 * unit - StrataSwitch unit # 1076 * port - Port number 1077 * medium - SOC_PORT_MEDIUM_COPPER/FIBER 1078 * cfg - Operating parameters 1079 * Returns: 1080 * SOC_E_XXX 1081 */ 1082 1083 STATIC int 1084 phy_qsgmii65_medium_config_set(int unit, soc_port_t port, 1085 soc_port_medium_t medium, 1086 soc_phy_config_t *cfg) 1087 { 1088 1089 phy_ctrl_t *pc; 1090 1091 pc = INT_PHY_SW_STATE(unit, port); 1092 1093 /* 1094 * Changes take effect immediately if the target medium is active. 1095 */ 1096 switch (medium) { 1097 case SOC_PORT_MEDIUM_FIBER: 1098 /* Change the fiber modes */ 1099 1100 sal_memcpy(&pc->fiber, cfg, sizeof (pc->fiber)); 1101 1102 pc->fiber.autoneg_advert &= ADVERT_ALL_FIBER; 1103 if (PHY_FIBER_MODE(unit, port)) { 1104 SOC_IF_ERROR_RETURN 1105 (_phy_qsgmii65_medium_config_update(unit, port, &pc->fiber)); 1106 } 1107 return SOC_E_NONE; 1108 case SOC_PORT_MEDIUM_COPPER: 1109 return SOC_E_UNAVAIL; 1110 default: 1111 return SOC_E_PARAM; 1112 } 1113 } 1114 1115 STATIC int 1116 _phy_qsgmii65_control_tx_driver_set(int unit, soc_port_t port, 1117 soc_phy_control_t type, uint32 value) 1118 { 1119 uint16 data; /* Temporary holder of reg value to be written */ 1120 uint16 mask; /* Bit mask of reg value to be updated */ 1121 phy_ctrl_t *pc; /* PHY software state */ 1122 1123 pc = INT_PHY_SW_STATE(unit, port); 1124 1125 SOC_IF_ERROR_RETURN 1126 (READ_QSGMII65_1000X_STAT1r(unit, pc, &data)); 1127 1128 if (data & LP_1000X_STATUS1_SGMII_MODE) { 1129 /* SGMII mode */ 1130 switch(type) { 1131 case SOC_PHY_CONTROL_PREEMPHASIS: 1132 data = (uint16)(value & 0xF); 1133 data = data << 12; 1134 mask = 0xf000; 1135 SOC_IF_ERROR_RETURN 1136 (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask)); 1137 break; 1138 case SOC_PHY_CONTROL_DRIVER_CURRENT: 1139 data = (uint16)(value & 0xF); 1140 data = data << 8; 1141 mask = 0x0f00; 1142 SOC_IF_ERROR_RETURN 1143 (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask)); 1144 break; 1145 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 1146 data = (uint16)(value & 0xF); 1147 data = data << 4; 1148 mask = 0x00f0; 1149 SOC_IF_ERROR_RETURN 1150 (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask)); 1151 break; 1152 default: 1153 /* should never get here */ 1154 return SOC_E_PARAM; 1155 } 1156 } else { 1157 /* 1000X mode */ 1158 switch(type) { 1159 case SOC_PHY_CONTROL_PREEMPHASIS: 1160 data = (uint16)(value & 0xF); 1161 data = data << 12; 1162 mask = 0xf000; 1163 SOC_IF_ERROR_RETURN 1164 (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask)); 1165 break; 1166 case SOC_PHY_CONTROL_DRIVER_CURRENT: 1167 data = (uint16)(value & 0xF); 1168 data = data << 8; 1169 mask = 0x0f00; 1170 SOC_IF_ERROR_RETURN 1171 (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask)); 1172 break; 1173 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 1174 data = (uint16)(value & 0xF); 1175 data = data << 4; 1176 mask = 0x00f0; 1177 SOC_IF_ERROR_RETURN 1178 (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask)); 1179 break; 1180 default: 1181 /* should never get here */ 1182 return SOC_E_PARAM; 1183 } 1184 } 1185 1186 return SOC_E_NONE; 1187 } 1188 1189 STATIC int 1190 _phy_qsgmii65_control_tx_driver_get(int unit, soc_port_t port, 1191 soc_phy_control_t type, uint32 *value) 1192 { 1193 uint16 data; /* Temporary holder of a reg value */ 1194 phy_ctrl_t *pc; /* PHY software state */ 1195 1196 pc = INT_PHY_SW_STATE(unit, port); 1197 1198 SOC_IF_ERROR_RETURN 1199 (READ_QSGMII65_1000X_STAT1r(unit, pc, &data)); 1200 1201 if (data & LP_1000X_STATUS1_SGMII_MODE) { 1202 /* SGMII mode */ 1203 switch(type) { 1204 case SOC_PHY_CONTROL_PREEMPHASIS: 1205 SOC_IF_ERROR_RETURN 1206 (READ_QSGMII65_ANALOG_TX1r(unit, pc, &data)); 1207 *value = (data & 0xf000) >> 12; 1208 break; 1209 case SOC_PHY_CONTROL_DRIVER_CURRENT: 1210 SOC_IF_ERROR_RETURN 1211 (READ_QSGMII65_ANALOG_TX1r(unit, pc, &data)); 1212 *value = (data & 0x0f00) >> 8; 1213 break; 1214 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 1215 SOC_IF_ERROR_RETURN 1216 (READ_QSGMII65_ANALOG_TX1r(unit, pc, &data)); 1217 *value = (data & 0x00f0) >> 4; 1218 break; 1219 default: 1220 /* should never get here */ 1221 return SOC_E_PARAM; 1222 } 1223 } else { 1224 /* 1000X mode */ 1225 switch(type) { 1226 case SOC_PHY_CONTROL_PREEMPHASIS: 1227 SOC_IF_ERROR_RETURN 1228 (READ_QSGMII65_ANALOG_TX1r(unit, pc, &data)); 1229 *value = (data & 0xf000) >> 12; 1230 break; 1231 case SOC_PHY_CONTROL_DRIVER_CURRENT: 1232 SOC_IF_ERROR_RETURN 1233 (READ_QSGMII65_ANALOG_TX1r(unit, pc, &data)); 1234 *value = (data & 0x0f00) >> 8; 1235 break; 1236 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 1237 SOC_IF_ERROR_RETURN 1238 (READ_QSGMII65_ANALOG_TX1r(unit, pc, &data)); 1239 *value = (data & 0x00f0) >> 4; 1240 break; 1241 default: 1242 /* should never get here */ 1243 return SOC_E_PARAM; 1244 } 1245 } 1246 1247 return SOC_E_NONE; 1248 } 1249 1250 /* 1251 * Function: 1252 * phy_phyqsgmii65_control_set 1253 * Purpose: 1254 * Configure PHY device specific control fucntion. 1255 * Parameters: 1256 * unit - StrataSwitch unit #. 1257 * port - StrataSwitch port #. 1258 * type - Control to update 1259 * value - New setting for the control 1260 * Returns: 1261 * SOC_E_NONE 1262 */ 1263 STATIC int 1264 phy_qsgmii65_control_set(int unit, soc_port_t port, 1265 soc_phy_control_t type, uint32 value) 1266 { 1267 int rv; 1268 /* coverity[mixed_enums] */ 1269 if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) { 1270 return SOC_E_PARAM; 1271 } 1272 1273 rv = SOC_E_UNAVAIL; 1274 switch(type) { 1275 case SOC_PHY_CONTROL_PREEMPHASIS: 1276 /* fall through */ 1277 case SOC_PHY_CONTROL_DRIVER_CURRENT: 1278 /* fall through */ 1279 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 1280 rv = _phy_qsgmii65_control_tx_driver_set(unit, port, type, value); 1281 break; 1282 default: 1283 rv = SOC_E_UNAVAIL; 1284 break; 1285 } 1286 return rv; 1287 } 1288 /* 1289 * Function: 1290 * phy_qsgmii65_control_get 1291 * Purpose: 1292 * Get current control settign of the PHY. 1293 * Parameters: 1294 * unit - StrataSwitch unit #. 1295 * port - StrataSwitch port #. 1296 * type - Control to update 1297 * value - (OUT)Current setting for the control 1298 * Returns: 1299 * SOC_E_NONE 1300 */ 1301 STATIC int 1302 phy_qsgmii65_control_get(int unit, soc_port_t port, 1303 soc_phy_control_t type, uint32 *value) 1304 { 1305 int rv; 1306 1307 if (NULL == value) { 1308 return SOC_E_PARAM; 1309 } 1310 /* coverity[mixed_enums] */ 1311 if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) { 1312 return SOC_E_PARAM; 1313 } 1314 1315 rv = SOC_E_UNAVAIL; 1316 switch(type) { 1317 case SOC_PHY_CONTROL_PREEMPHASIS: 1318 /* fall through */ 1319 case SOC_PHY_CONTROL_DRIVER_CURRENT: 1320 /* fall through */ 1321 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 1322 rv = _phy_qsgmii65_control_tx_driver_get(unit, port, type, value); 1323 break; 1324 default: 1325 rv = SOC_E_UNAVAIL; 1326 break; 1327 } 1328 1329 return rv; 1330 } 1331 1332 /* 1333 * Function: 1334 * phy_qsgmii65_reg_read 1335 * Purpose: 1336 * Routine to read PHY register 1337 * Parameters: 1338 * uint - BCM unit number 1339 * pc - PHY state 1340 * flags - Flags which specify the register type 1341 * phy_reg_addr - Encoded register address 1342 * phy_data - (OUT) Value read from PHY register 1343 * Note: 1344 * This register read function is not thread safe. Higher level 1345 * function that calls this function must obtain a per port lock 1346 * to avoid overriding register page mapping between threads. 1347 */ 1348 STATIC int 1349 phy_qsgmii65_reg_read(int unit, soc_port_t port, uint32 flags, 1350 uint32 phy_reg_addr, uint32 *phy_data) 1351 { 1352 uint16 data; /* Temporary holder for phy_data */ 1353 phy_ctrl_t *pc; /* PHY software state */ 1354 1355 pc = INT_PHY_SW_STATE(unit, port); 1356 1357 SOC_IF_ERROR_RETURN 1358 (phy_reg_qsgmii_aer_read(unit, pc, phy_reg_addr, &data)); 1359 1360 *phy_data = data; 1361 1362 return SOC_E_NONE; 1363 } 1364 1365 /* 1366 * Function: 1367 * phy_qsgmii65_reg_write 1368 * Purpose: 1369 * Routine to write PHY register 1370 * Parameters: 1371 * uint - BCM unit number 1372 * pc - PHY state 1373 * flags - Flags which specify the register type 1374 * phy_reg_addr - Encoded register address 1375 * phy_data - Value write to PHY register 1376 * Note: 1377 * This register read function is not thread safe. Higher level 1378 * function that calls this function must obtain a per port lock 1379 * to avoid overriding register page mapping between threads. 1380 */ 1381 STATIC int 1382 phy_qsgmii65_reg_write(int unit, soc_port_t port, uint32 flags, 1383 uint32 phy_reg_addr, uint32 phy_data) 1384 { 1385 uint16 data; /* Temporary holder for phy_data */ 1386 phy_ctrl_t *pc; /* PHY software state */ 1387 1388 pc = INT_PHY_SW_STATE(unit, port); 1389 1390 data = (uint16) (phy_data & 0x0000FFFF); 1391 1392 SOC_IF_ERROR_RETURN 1393 (phy_reg_qsgmii_aer_write(unit, pc, phy_reg_addr, data)); 1394 1395 return SOC_E_NONE; 1396 } 1397 1398 /* 1399 * Function: 1400 * phy_qsgmii65_reg_modify 1401 * Purpose: 1402 * Routine to write PHY register 1403 * Parameters: 1404 * uint - BCM unit number 1405 * pc - PHY state 1406 * flags - Flags which specify the register type 1407 * phy_reg_addr - Encoded register address 1408 * phy_mo_data - New value for the bits specified in phy_mo_mask 1409 * phy_mo_mask - Bit mask to modify 1410 * Note: 1411 * This register read function is not thread safe. Higher level 1412 * function that calls this function must obtain a per port lock 1413 * to avoid overriding register page mapping between threads. 1414 */ 1415 STATIC int 1416 phy_qsgmii65_reg_modify(int unit, soc_port_t port, uint32 flags, 1417 uint32 phy_reg_addr, uint32 phy_data, 1418 uint32 phy_data_mask) 1419 { 1420 uint16 data; /* Temporary holder for phy_data */ 1421 uint16 mask; 1422 phy_ctrl_t *pc; /* PHY software state */ 1423 1424 pc = INT_PHY_SW_STATE(unit, port); 1425 1426 data = (uint16) (phy_data & 0x0000FFFF); 1427 mask = (uint16) (phy_data_mask & 0x0000FFFF); 1428 1429 SOC_IF_ERROR_RETURN 1430 (phy_reg_qsgmii_aer_modify(unit, pc, phy_reg_addr, data, mask)); 1431 1432 return SOC_E_NONE; 1433 } 1434 1435 STATIC int 1436 phy_qsgmii65_notify(int unit, soc_port_t port, 1437 soc_phy_event_t event, uint32 value) 1438 { 1439 int rv; 1440 1441 if (event >= phyEventCount) { 1442 return SOC_E_PARAM; 1443 } 1444 1445 rv = SOC_E_NONE; 1446 switch(event) { 1447 case phyEventInterface: 1448 rv = (_phy_qsgmii65_notify_interface(unit, port, value)); 1449 break; 1450 case phyEventDuplex: 1451 rv = (_phy_qsgmii65_notify_duplex(unit, port, value)); 1452 break; 1453 case phyEventSpeed: 1454 rv = (_phy_qsgmii65_notify_speed(unit, port, value)); 1455 break; 1456 case phyEventStop: 1457 rv = (_phy_qsgmii65_notify_stop(unit, port, value)); 1458 break; 1459 case phyEventResume: 1460 rv = (_phy_qsgmii65_notify_resume(unit, port, value)); 1461 break; 1462 case phyEventAutoneg: 1463 rv = (phy_qsgmii65_an_set(unit, port, value)); 1464 break; 1465 default: 1466 rv = SOC_E_PARAM; 1467 break; 1468 } 1469 1470 return rv; 1471 } 1472 1473 STATIC int 1474 phy_qsgmii65_duplex_get(int unit, soc_port_t port, int *duplex) 1475 { 1476 uint16 reg0_16; 1477 uint16 mii_ctrl; 1478 phy_ctrl_t *pc; 1479 1480 pc = INT_PHY_SW_STATE(unit, port); 1481 *duplex = TRUE; 1482 1483 SOC_IF_ERROR_RETURN 1484 (READ_QSGMII65_1000X_STAT1r(unit, pc, ®0_16)); 1485 1486 if (reg0_16 & LP_1000X_STATUS1_SGMII_MODE) { 1487 /* retrieve the duplex setting in SGMII mode */ 1488 1489 SOC_IF_ERROR_RETURN 1490 (READ_QSGMII65_MII_CTRLr(unit, pc, &mii_ctrl)); 1491 1492 if (mii_ctrl & MII_CTRL_AE) { 1493 SOC_IF_ERROR_RETURN 1494 (READ_QSGMII65_MII_ANPr(unit,pc,®0_16)); 1495 1496 /* make sure link partner is also in SGMII mode 1497 * otherwise fall through to use the FD bit in MII_CTRL reg 1498 */ 1499 if (reg0_16 & MII_ANP_SGMII_MODE) { 1500 if (reg0_16 & MII_ANP_SGMII_FD) { 1501 *duplex = TRUE; 1502 } else { 1503 *duplex = FALSE; 1504 } 1505 return SOC_E_NONE; 1506 } 1507 } 1508 *duplex = (mii_ctrl & MII_CTRL_FD) ? TRUE : FALSE; 1509 } 1510 return SOC_E_NONE; 1511 } 1512 1513 /* 1514 * Variable: phy_qsgmii65drv_ge 1515 * Purpose: PHY Driver for Dozen SerDes Serdes PHY internal to Draco, 1516 */ 1517 phy_driver_t phy_qsgmii65_ge = { 1518 "Internal QSGMII 65nm SERDES PHY Driver", 1519 phy_qsgmii65_init, 1520 phy_null_reset, 1521 phy_qsgmii65_link_get, 1522 phy_qsgmii65_enable_set, 1523 phy_null_enable_get, 1524 phy_serdes_duplex_set, 1525 phy_qsgmii65_duplex_get, /* duplex_get */ 1526 phy_qsgmii65_speed_set, 1527 phy_qsgmii65_speed_get, 1528 phy_serdes_master_set, /* master_set */ 1529 phy_serdes_master_get, /* master_get */ 1530 phy_qsgmii65_an_set, 1531 phy_qsgmii65_an_get, 1532 phy_qsgmii65_adv_local_set, 1533 phy_qsgmii65_adv_local_get, 1534 phy_qsgmii65_adv_remote_get, 1535 phy_qsgmii65_lb_set, 1536 phy_qsgmii65_lb_get, 1537 phy_serdes_interface_set, 1538 phy_serdes_interface_get, 1539 phy_qsgmii65_ability_get, 1540 NULL, 1541 NULL, 1542 phy_null_mdix_set, 1543 phy_null_mdix_get, 1544 phy_null_mdix_status_get, 1545 phy_qsgmii65_medium_config_set, 1546 phy_serdes_medium_config_get, 1547 phy_serdes_medium_status, 1548 NULL, /* phy_cable_diag */ 1549 NULL, /* phy_link_change */ 1550 phy_qsgmii65_control_set, /* phy_control_set */ 1551 phy_qsgmii65_control_get, /* phy_control_get */ 1552 phy_qsgmii65_reg_read, 1553 phy_qsgmii65_reg_write, 1554 phy_qsgmii65_reg_modify, 1555 phy_qsgmii65_notify 1556 }; 1557 1558 /*********************************************************************** 1559 * 1560 * PASS-THROUGH NOTIFY ROUTINES 1561 */ 1562 1563 /* 1564 * Function: 1565 * _phy_qsgmii65_notify_duplex 1566 * Purpose: 1567 * Program duplex if (and only if) qsgmii65 is an intermediate PHY. 1568 * Parameters: 1569 * unit - StrataSwitch unit #. 1570 * port - StrataSwitch port #. 1571 * duplex - Boolean, TRUE indicates full duplex, FALSE 1572 * indicates half. 1573 * Returns: 1574 * SOC_E_XXX 1575 * Notes: 1576 * If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to 1577 * talk directly to an external fiber module. 1578 * 1579 * If PHY_FLAGS_FIBER is clear, the PHY is being used in 1580 * pass-through mode to talk to an external SGMII PHY. 1581 * 1582 * When used in pass-through mode, autoneg must be turned off and 1583 * the speed/duplex forced to match that of the external PHY. 1584 */ 1585 1586 STATIC int 1587 _phy_qsgmii65_notify_duplex(int unit, soc_port_t port, uint32 duplex) 1588 { 1589 int fiber; 1590 uint16 mii_ctrl; 1591 phy_ctrl_t *pc; 1592 1593 fiber = PHY_FIBER_MODE(unit, port); 1594 pc = INT_PHY_SW_STATE(unit, port); 1595 LOG_INFO(BSL_LS_SOC_PHY, 1596 (BSL_META_U(unit, 1597 "phy_qsgmii65_notify_duplex: " 1598 "u=%d p=%d duplex=%d fiber=%d\n"), 1599 unit, port, duplex, fiber)); 1600 1601 if (SAL_BOOT_SIMULATION) { 1602 return SOC_E_NONE; 1603 } 1604 1605 if (fiber) { 1606 SOC_IF_ERROR_RETURN 1607 (MODIFY_QSGMII65_MII_CTRLr(unit, pc, 1608 MII_CTRL_FD, MII_CTRL_FD)); 1609 return SOC_E_NONE; 1610 } 1611 1612 /* Put SERDES PHY in reset */ 1613 1614 SOC_IF_ERROR_RETURN 1615 (_phy_qsgmii65_notify_stop(unit, port, PHY_STOP_DUPLEX_CHG)); 1616 1617 /* Update duplexity */ 1618 mii_ctrl = (duplex) ?MII_CTRL_FD : 0; 1619 SOC_IF_ERROR_RETURN 1620 (MODIFY_QSGMII65_MII_CTRLr(unit, pc, mii_ctrl, MII_CTRL_FD)); 1621 1622 /* Take SERDES PHY out of reset */ 1623 SOC_IF_ERROR_RETURN 1624 (_phy_qsgmii65_notify_resume(unit, port, PHY_STOP_DUPLEX_CHG)); 1625 1626 /* Autonegotiation must be turned off to talk to external PHY if 1627 * SGMII autoneg is not enabled. 1628 */ 1629 if (!PHY_SGMII_AUTONEG_MODE(unit, port)) { 1630 SOC_IF_ERROR_RETURN 1631 (phy_qsgmii65_an_set(unit, port, FALSE)); 1632 } 1633 return SOC_E_NONE; 1634 } 1635 1636 /* 1637 * Function: 1638 * _phy_qsgmii65_notify_speed 1639 * Purpose: 1640 * Program duplex if (and only if) qsgmii65 is an intermediate PHY. 1641 * Parameters: 1642 * unit - StrataSwitch unit #. 1643 * port - StrataSwitch port #. 1644 * speed - Speed to program. 1645 * Returns: 1646 * SOC_E_XXX 1647 * Notes: 1648 * If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to 1649 * talk directly to an external fiber module. 1650 * 1651 * If PHY_FLAGS_FIBER is clear, the PHY is being used in 1652 * pass-through mode to talk to an external SGMII PHY. 1653 * 1654 * When used in pass-through mode, autoneg must be turned off and 1655 * the speed/duplex forced to match that of the external PHY. 1656 */ 1657 1658 STATIC int 1659 _phy_qsgmii65_notify_speed(int unit, soc_port_t port, uint32 speed) 1660 { 1661 int fiber; 1662 uint16 fiber_status; 1663 phy_ctrl_t *pc; 1664 1665 pc = INT_PHY_SW_STATE(unit, port); 1666 fiber = PHY_FIBER_MODE(unit, port); 1667 1668 LOG_INFO(BSL_LS_SOC_PHY, 1669 (BSL_META_U(unit, 1670 "_phy_qsgmii65_notify_speed: " 1671 "u=%d p=%d speed=%d fiber=%d\n"), 1672 unit, port, speed, fiber)); 1673 1674 if (SAL_BOOT_SIMULATION) { 1675 return SOC_E_NONE; 1676 } 1677 1678 SOC_IF_ERROR_RETURN 1679 (READ_QSGMII65_1000X_STAT1r(unit, pc, &fiber_status)); 1680 1681 if (fiber && !(fiber_status & LP_1000X_STATUS1_SGMII_MODE)) { 1682 if ((speed != 0) && (speed != 100) && (speed != 1000)) { 1683 return SOC_E_CONFIG; 1684 } 1685 } 1686 1687 /* Put SERDES PHY in reset */ 1688 SOC_IF_ERROR_RETURN 1689 (_phy_qsgmii65_notify_stop(unit, port, PHY_STOP_SPEED_CHG)); 1690 1691 /* Update speed */ 1692 SOC_IF_ERROR_RETURN 1693 (_phy_qsgmii65_sgmii_speed_set(unit, port, speed)); 1694 1695 /* Take SERDES PHY out of reset */ 1696 SOC_IF_ERROR_RETURN 1697 (_phy_qsgmii65_notify_resume(unit, port, PHY_STOP_SPEED_CHG)); 1698 1699 /* Autonegotiation must be turned off to talk to external PHY */ 1700 if (!PHY_SGMII_AUTONEG_MODE(unit, port) && !fiber) { 1701 SOC_IF_ERROR_RETURN 1702 (phy_qsgmii65_an_set(unit, port, FALSE)); 1703 } 1704 1705 return SOC_E_NONE; 1706 } 1707 1708 /* 1709 * Function: 1710 * _phy_qsgmii65_stop 1711 * Purpose: 1712 * Put qsgmii65 SERDES in or out of reset depending on conditions 1713 */ 1714 1715 STATIC int 1716 _phy_qsgmii65_stop(int unit, soc_port_t port) 1717 { 1718 uint16 mii_ctrl; 1719 int stop, copper; 1720 phy_ctrl_t *pc; 1721 1722 pc = INT_PHY_SW_STATE(unit, port); 1723 1724 copper = (pc->stop & 1725 PHY_STOP_COPPER) != 0; 1726 1727 stop = ((pc->stop & 1728 (PHY_STOP_PHY_DIS | 1729 PHY_STOP_DRAIN)) != 0 || 1730 (copper && 1731 (pc->stop & 1732 (PHY_STOP_MAC_DIS | 1733 PHY_STOP_DUPLEX_CHG | 1734 PHY_STOP_SPEED_CHG)) != 0)); 1735 1736 LOG_INFO(BSL_LS_SOC_PHY, 1737 (BSL_META_U(unit, 1738 "phy_qsgmii65_stop: u=%d p=%d copper=%d" 1739 " stop=%d flg=0x%x\n"), 1740 unit, port, copper, stop, 1741 pc->stop)); 1742 1743 mii_ctrl = (stop) ?MII_CTRL_PD : 0; 1744 #ifdef BCM_HAWKEYE_SUPPORT 1745 if (SOC_IS_HAWKEYE(unit)) { 1746 uint16 dev_id = 0; 1747 uint8 rev_id = 0; 1748 1749 soc_cm_get_id(unit, &dev_id, &rev_id); 1750 if ((pc->lane_num == 0) && 1751 ((dev_id == BCM53313_DEVICE_ID) || (dev_id == BCM53312_DEVICE_ID))) { 1752 /* Issue : BCM53312 have four SGMII ports (GE8,9,10,11). 1753 * If power down GE8 or GE10, 1754 * the GE9 or GE11 is powered down also. 1755 * 1756 * Analysis : When set the QSGMII in sgmii dual mode, 1757 * if you power down lane 4, 1758 * only lane4 is powered down. 1759 * But if you power down lane0, not only lane0 1760 * is powered down but also pll get powered down. 1761 * 1762 * Solution : We can set laneCtrl3 to 0xAFF for AER 0, not AER 4. 1763 * The laneCtrl3 (addr:0X8018) is the reg in 1764 * XGXS Block1(default is 0x200). 1765 * pwrdwn_rx = laneCtrl3[3:0]; 1766 * pwrdwn_tx = laneCtrl3[7:4]; 1767 * pwrdwn_pll = laneCtrl3[8]; 1768 * pwrdwn10g_pll_dis = laneCtrl3[9]; 1769 * lock_ref_en = laneCtrl3[10]; 1770 * pwrdwn_force = laneCtrl3[11]; 1771 */ 1772 SOC_IF_ERROR_RETURN 1773 (WRITE_QSGMII65_LANE_CTRL3r(unit, pc, (stop ? 0xAFF : 0x200))); 1774 } else { 1775 if (soc_feature (unit, soc_feature_eee)) { 1776 /* If link on port1 (second port) of a QSGMII octet is 1777 * down, Tx/Rx LPI_DURATION counters of all ports 1778 * in that octet stop running. 1779 * So NOT to set the power-down bit for second port 1780 * of QSGMII serdes on HKEEE. 1781 * And MAC.SW_RESET in HKEEE essentially kill the traffic 1782 * in both Tx and Rx direction. 1783 */ 1784 if(pc->lane_num == 1) { 1785 /* Do nothing */ 1786 } else { 1787 SOC_IF_ERROR_RETURN 1788 (MODIFY_QSGMII65_MII_CTRLr 1789 (unit, pc, mii_ctrl, MII_CTRL_PD)); 1790 } 1791 } else { 1792 SOC_IF_ERROR_RETURN 1793 (MODIFY_QSGMII65_MII_CTRLr(unit, pc, mii_ctrl, MII_CTRL_PD)); 1794 } 1795 } 1796 } else 1797 #endif /* BCM_HAWKEYE_SUPPORT */ 1798 #ifdef BCM_HURRICANE1_SUPPORT 1799 if (SOC_IS_HURRICANE(unit)) { 1800 uint16 lctrl; 1801 SOC_IF_ERROR_RETURN 1802 (READ_QSGMII65_LANE_CTRL0r(unit, pc,&lctrl)); 1803 if ((pc->lane_num == 0) && ((lctrl & 0xff00) == 0)) { 1804 /* SGMII Mode */ 1805 SOC_IF_ERROR_RETURN 1806 (WRITE_QSGMII65_LANE_CTRL3r(unit, pc, (stop ? 0xAFF : 0x200))); 1807 } else { 1808 if (soc_feature (unit, soc_feature_eee)) { 1809 if(pc->lane_num == 1) { 1810 /* Do nothing */ 1811 } else { 1812 SOC_IF_ERROR_RETURN 1813 (MODIFY_QSGMII65_MII_CTRLr 1814 (unit, pc, mii_ctrl, MII_CTRL_PD)); 1815 } 1816 } else { 1817 SOC_IF_ERROR_RETURN 1818 (MODIFY_QSGMII65_MII_CTRLr(unit, pc, mii_ctrl, MII_CTRL_PD)); 1819 } 1820 } 1821 } else 1822 #endif /* BCM_HURRICANE_SUPPORT */ 1823 { 1824 SOC_IF_ERROR_RETURN 1825 (MODIFY_QSGMII65_MII_CTRLr(unit, pc, mii_ctrl, MII_CTRL_PD)); 1826 } 1827 1828 return SOC_E_NONE; 1829 } 1830 1831 /* 1832 * Function: 1833 * _phy_qsgmii65_notify_stop 1834 * Purpose: 1835 * Add a reason to put qsgmii65 PHY in reset. 1836 * Parameters: 1837 * unit - StrataSwitch unit #. 1838 * port - StrataSwitch port #. 1839 * flags - Reason to stop 1840 * Returns: 1841 * SOC_E_XXX 1842 */ 1843 1844 STATIC int 1845 _phy_qsgmii65_notify_stop(int unit, soc_port_t port, uint32 flags) 1846 { 1847 INT_PHY_SW_STATE(unit, port)->stop |= flags; 1848 1849 return _phy_qsgmii65_stop(unit, port); 1850 } 1851 1852 /* 1853 * Function: 1854 * phy_qsgmii65_notify_resume 1855 * Purpose: 1856 * Remove a reason to put qsgmii65 PHY in reset. 1857 * Parameters: 1858 * unit - StrataSwitch unit #. 1859 * port - StrataSwitch port #. 1860 * flags - Reason to stop 1861 * Returns: 1862 * SOC_E_XXX 1863 */ 1864 1865 STATIC int 1866 _phy_qsgmii65_notify_resume(int unit, soc_port_t port, uint32 flags) 1867 { 1868 INT_PHY_SW_STATE(unit, port)->stop &= ~flags; 1869 1870 return _phy_qsgmii65_stop(unit, port); 1871 } 1872 1873 /* 1874 * Function: 1875 * phy_qsgmii65_media_setup 1876 * Purpose: 1877 * Configure 1878 * Parameters: 1879 * unit - StrataSwitch unit #. 1880 * port - StrataSwitch port #. 1881 * PHY_FIBER_MODE - Configure for fiber mode 1882 * fiber_pref - Fiber preferrred (if fiber mode) 1883 * Returns: 1884 * SOC_E_XXX 1885 */ 1886 STATIC int 1887 _phy_qsgmii65_notify_interface(int unit, soc_port_t port, uint32 intf) 1888 { 1889 phy_ctrl_t *pc; 1890 uint16 data16; 1891 1892 pc = INT_PHY_SW_STATE(unit, port); 1893 1894 data16 = 0; 1895 if (intf != SOC_PORT_IF_SGMII) { 1896 data16 = LP_1000X_FIBER_MODE; 1897 } 1898 SOC_IF_ERROR_RETURN 1899 (MODIFY_QSGMII65_1000X_CTRL1r(unit, pc, 1900 data16, LP_1000X_FIBER_MODE)); 1901 1902 return SOC_E_NONE; 1903 } 1904 #else /* INCLUDE_XGXS_QSGMII65 */ 1905 int _phy_qsgmii65_not_empty; 1906 #endif /* INCLUDE_XGXS_QSGMII65 */