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