phy5421S.c (62838B)
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: phy5421S.c 8 * 9 * Please see sdk/doc/combo-ports.txt for more information. 10 * 11 * The BCM5421S connects to virtually any MAC interface and dynamically 12 * supports both fiber and copper line interfaces. 13 * 14 * This driver allows the StrataSwitch to talk to the 5421S using either 15 * the GMII interface or TBI (Ten Bit Interface). Upon initialization, 16 * one interface or the other is statically configured based on the 17 * if_tbi_portXX property. The MDIO must be connected for either mode. 18 * The default is GMII and is recommended for both fiber and copper. 19 * 20 * When used with BCM5690, this driver switches to SGMII mode. There is 21 * also a special check in phy5690.c to enable autonegotiation for 22 * SGMII. WARNING: this configuration is not represented in any 23 * Broadcom SDK, so proper operation cannot be guaranteed. 24 * 25 * This driver allows the 5421S to use either the copper or fiber line 26 * interface. If the phy_automedium property is true, the mode is 27 * selected dynamically on link up using the energy/signal detect. 28 * If both copper and fiber signals are detected, the driver will 29 * consult the configuration property phy_fiber_pref<_portXX>. It will 30 * select fiber if the property is 1, and copper if it is 0. The 31 * default value of the property is 1, since fiber is more likely to be 32 * preferred. 33 * 34 * If the phy_automedium property is false, then the mode is fixed 35 * according to the phy_fiber_pref<_portXX> property. 36 * 37 * This driver does not support autonegotiation with TBI+copper. 38 * 39 * If LINK_DOWN_RESET_WAR is 1, then the PHY will be reset each time 40 * link down is detected on copper. BCM5421SA2 has difficulty obtaining 41 * link with certain other gigabit PHYs if not reset when link goes down 42 * (see errata). 43 * 44 * Fiber de-glitch: some GBICs may cause a brief fiber energy detect 45 * when inserted, even without a link. This could cause the copper link 46 * to be dropped, so an energy detect de-glitch is provided. The 47 * property phy_fiber_deglitch_usecs is the de-glitch time in usec. 48 * 49 * Autoneg defaults may be different for copper and fiber. The routines 50 * phy_5421S_medium_config_set change the default port modes for a 51 * specific medium type. The default port modes are installed as soon 52 * as possible after signal detect indicates a change of medium. The 53 * standard PHY set/get routines operate only on the currently active 54 * medium. 55 */ 56 57 #ifdef INCLUDE_PHY_5421S 58 59 #include <sal/types.h> 60 #include <sal/core/spl.h> 61 #include <shared/bsl.h> 62 #include <soc/drv.h> 63 #include <soc/debug.h> 64 #include <soc/error.h> 65 #include <soc/phy.h> 66 #include <soc/phyreg.h> 67 68 #include <soc/phy.h> 69 #include <soc/phy/phyctrl.h> 70 #include <soc/phy/drv.h> 71 #include "phyident.h" 72 #include "phyreg.h" 73 #include "phyfege.h" 74 #include "phy5421S.h" 75 76 #ifndef INCLUDE_PHY_SERDES 77 #error "SERDES support required." 78 #endif 79 80 #define LINK_DOWN_RESET_WAR 1 /* Needed for A0, A1, A2 */ 81 #define REGULATOR_GAMMA_WAR 1 /* Needed if using external regulators */ 82 #define SERDES_COPPER_AMP_WAR 0 /* Needed for A0 only, NOT A1/A2 */ 83 #define ADC_PERF_WAR 1 /* Needed for A0, A1, A2 */ 84 85 #define DPRINTF(_s) LOG_INFO(BSL_LS_SOC_PHY, _s) 86 87 #define GMII_MODE(unit, port) (!PHY_TBI_MODE(unit, port)) 88 89 #define ADVERT_ALL_COPPER \ 90 (SOC_PM_PAUSE | SOC_PM_10MB | SOC_PM_100MB | SOC_PM_1000MB) 91 #define ADVERT_ALL_FIBER \ 92 (SOC_PM_PAUSE | SOC_PM_1000MB_FD) 93 94 /* 95 * See comments above about fiber energy de-glitch. De-glitch time is 96 * specified in microseconds but precision is limited to the linkscan 97 * period. A de-glitch time of 0 disables de-glitching. 98 */ 99 100 STATIC int phy_5421S_interface_set(int unit, soc_port_t port, 101 soc_port_if_t pif); 102 103 STATIC int _phy_5421S_medium_config_update(int unit, soc_port_t port, 104 soc_phy_config_t *cfg); 105 106 STATIC int phy_5421S_duplex_set(int unit, soc_port_t port, int duplex); 107 STATIC int phy_5421S_speed_set(int unit, soc_port_t port, int speed); 108 STATIC int phy_5421S_master_set(int unit, soc_port_t port, int master); 109 STATIC int phy_5421S_adv_local_set(int unit, soc_port_t port, 110 soc_port_mode_t mode); 111 STATIC int phy_5421S_autoneg_set(int unit, soc_port_t port, int an); 112 113 STATIC int phy_5421S_link_down(int unit, soc_port_t port); 114 STATIC int phy_5421S_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode); 115 116 /* 117 * Function: 118 * _phy_5421S_medium_check 119 * Purpose: 120 * Returns preferred medium based on current signal detects 121 * Parameters: 122 * unit - StrataSwitch unit #. 123 * port - StrataSwitch port #. 124 * medium - (OUT) SOC_PORT_MEDIUM_XXX 125 * Returns: 126 * SOC_E_XXX 127 * Notes: 128 * Optionally implements fiber signal de-glitch. 129 * Uses the preferred medium property and mode enables, 130 * combined with the energy signals that are present. 131 */ 132 133 STATIC int 134 _phy_5421S_medium_check(int unit, soc_port_t port, int *medium) 135 { 136 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 137 uint16 tmp; 138 int fiber_detect, copper_detect; 139 int elapsed_time; 140 141 /* 142 * If medium automedium is not disabled, ignore the energy signals 143 * and return a fixed medium type according to phy_fiber_pref. 144 */ 145 146 if (!pc->automedium) { 147 if (pc->fiber.preferred) { 148 *medium = SOC_PORT_MEDIUM_FIBER; 149 } else { 150 *medium = SOC_PORT_MEDIUM_COPPER; 151 } 152 153 return SOC_E_NONE; 154 } 155 156 *medium = SOC_PORT_MEDIUM_NONE; 157 158 SOC_IF_ERROR_RETURN 159 (READ_PHY5421_SGMII_1000X_STATr(unit, pc, &tmp)); 160 161 copper_detect = pc->copper.enable && ((tmp & 0x8000) != 0); 162 fiber_detect = pc->fiber.enable && ((tmp & 0x2000) != 0); 163 164 /* De-glitch fiber detect */ 165 166 if (!fiber_detect) { 167 pc->fiber_plug_wait = 0; 168 } else if (!pc->fiber_plug_wait) { 169 /* Fiber just now detected; start timer how long to ignore it */ 170 if (pc->fiber_plug_dely > 0) { 171 pc->fiber_plug_wait = 1; 172 pc->fiber_plug_time = sal_time_usecs(); 173 pc->fiber_plug_done = 0; 174 fiber_detect = FALSE; 175 } 176 } else if (!pc->fiber_plug_done) { 177 /* Ignoring fiber until timer expiry */ 178 elapsed_time = SAL_USECS_SUB(sal_time_usecs(), pc->fiber_plug_time); 179 if ((elapsed_time < 0) || 180 (elapsed_time >= pc->fiber_plug_dely)) { 181 pc->fiber_plug_done = 1; 182 } else { 183 fiber_detect = FALSE; 184 } 185 } 186 187 /* Detect which medium should be active, if any */ 188 189 if (fiber_detect && copper_detect) { 190 *medium = (pc->fiber.preferred ? 191 SOC_PORT_MEDIUM_FIBER : 192 SOC_PORT_MEDIUM_COPPER); 193 } else if (fiber_detect) { 194 *medium = SOC_PORT_MEDIUM_FIBER; 195 } else if (copper_detect) { 196 *medium = SOC_PORT_MEDIUM_COPPER; 197 } else { 198 *medium = SOC_PORT_MEDIUM_NONE; 199 } 200 201 return SOC_E_NONE; 202 } 203 204 /* 205 * Function: 206 * _phy_5421S_medium_select 207 * Purpose: 208 * Program the PHY to copper or fiber mode based on specified medium. 209 * Parameters: 210 * unit - StrataSwitch unit #. 211 * port - StrataSwitch port #. 212 * medium - One of: 213 * SOC_PORT_MEDIUM_COPPER 214 * SOC_PORT_MEDIUM_FIBER 215 * SOC_PORT_MEDIUM_NONE 216 * Returns: 217 * SOC_E_XXX 218 */ 219 220 STATIC int 221 _phy_5421S_medium_select(int unit, soc_port_t port, int medium) 222 { 223 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 224 uint16 tmp; 225 int allow_mode_switch; 226 227 DPRINTF((BSL_META_U(unit, 228 "5421S_medium_select: port=%d medium=%d fp=%d\n"), 229 port, medium, pc->fiber.preferred)); 230 231 /* 232 * Inform outside world of the current mode, including phy5690.c for 233 * notify routines and bcm/link.c for printing the link type. 234 */ 235 236 if (medium == SOC_PORT_MEDIUM_FIBER) { 237 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_COPPER); 238 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER); 239 } else { 240 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER); 241 PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER); 242 } 243 244 /* 245 * Program medium. If no neither medium is active, put the PHY in 246 * fiber mode because it's lower power. 247 */ 248 249 if (medium == SOC_PORT_MEDIUM_COPPER) { 250 /* 251 * Clear SGMII enable when using GMII, as is the case for 252 * StrataSwitches, and set it when using SGMII, which is the 253 * case for BCM5690 only (shadow 010, power control). 254 */ 255 tmp = 0; 256 SOC_IF_ERROR_RETURN 257 (MODIFY_PHY5421_POWER_CTRLr(unit, pc, tmp, 0x0800)); 258 259 /* Set full duplex */ 260 SOC_IF_ERROR_RETURN 261 (MODIFY_PHY5421_MII_CTRLr(unit, pc, MII_CTRL_FD, MII_CTRL_FD)); 262 263 if (PHY_TBI_MODE(unit, port)) { 264 /* Partial TBI+COPPER support - ANCTL.ANEN must be 0 */ 265 phy_ctrl_t *int_pc; 266 267 int_pc = INT_PHY_SW_STATE(unit, port); 268 SOC_IF_ERROR_RETURN 269 (PHYCTRL_AUTO_NEGOTIATE_SET(int_pc, unit, port, FALSE)); 270 } 271 } else { /* SOC_PORT_MEDIUM_FIBER/NONE */ 272 /* Set SGMII enable (shadow 010, power control) */ 273 SOC_IF_ERROR_RETURN 274 (MODIFY_PHY5421_POWER_CTRLr(unit, pc, 0x0800, 0x0800)); 275 276 277 /* 278 * Set Fiber mode (shadow 00100, spare control register 2). 279 * This can remain even in copper mode. However, it may be set 280 * ONLY after setting SGMII enable or link will be messed up. 281 */ 282 SOC_IF_ERROR_RETURN 283 (MODIFY_PHY5421_SPARE_CTRL2r(unit, pc, 0x0020, 0x0020)); 284 } 285 286 /* 287 * Decide whether to enable the non-selected medium to send link 288 * pulses, which could cause certain partners to assume link is up. 289 * Link pulses should ONLY be sent on the non-selected medium if it 290 * is the preferred medium, or if neither medium has signal. 291 */ 292 293 switch (medium) { 294 case SOC_PORT_MEDIUM_FIBER: 295 allow_mode_switch = !pc->fiber.preferred; 296 break; 297 case SOC_PORT_MEDIUM_COPPER: 298 allow_mode_switch = pc->fiber.preferred; 299 break; 300 default: 301 allow_mode_switch = TRUE; 302 break; 303 } 304 305 /* Spare Control Register 3 */ 306 if (allow_mode_switch) { 307 tmp = 0; /* Enable pulses on non-selected medium */ 308 } else { 309 tmp = 0x08; /* Disable pulses on non-selected medium */ 310 } 311 SOC_IF_ERROR_RETURN 312 (MODIFY_PHY5421_SPARE_CTRL3r(unit, pc, tmp, 0x0008)); 313 314 /* 315 * Before link comes up, set the PHY parameters including autoneg 316 * enable and advertisement, according to saved defaults for this 317 * port type (copper/fiber). 318 */ 319 320 if (medium == SOC_PORT_MEDIUM_COPPER) { 321 SOC_IF_ERROR_RETURN 322 (_phy_5421S_medium_config_update(unit, port, &pc->copper)); 323 } 324 325 if (medium == SOC_PORT_MEDIUM_FIBER) { 326 SOC_IF_ERROR_RETURN 327 (_phy_5421S_medium_config_update(unit, port, &pc->fiber)); 328 } 329 330 return SOC_E_NONE; 331 } 332 333 /* 334 * Function: 335 * phy_5421S_medium_status 336 * Purpose: 337 * Indicate the current active medium 338 * Parameters: 339 * unit - StrataSwitch unit #. 340 * port - StrataSwitch port #. 341 * medium - (OUT) One of: 342 * SOC_PORT_MEDIUM_COPPER 343 * SOC_PORT_MEDIUM_FIBER 344 * SOC_PORT_MEDIUM_NONE 345 * Returns: 346 * SOC_E_NONE 347 */ 348 349 STATIC int 350 phy_5421S_medium_status(int unit, soc_port_t port, soc_port_medium_t *medium) 351 { 352 *medium = EXT_PHY_SW_STATE(unit, port)->medium; 353 return SOC_E_NONE; 354 } 355 356 /* 357 * Function: 358 * _phy_5421S_medium_config_update 359 * Purpose: 360 * Update the PHY with config parameters 361 * Parameters: 362 * unit - StrataSwitch unit #. 363 * port - StrataSwitch port #. 364 * cfg - Config structure. 365 * Returns: 366 * SOC_E_XXX 367 */ 368 369 STATIC int 370 _phy_5421S_medium_config_update(int unit, soc_port_t port, 371 soc_phy_config_t *cfg) 372 { 373 SOC_IF_ERROR_RETURN 374 (phy_5421S_speed_set(unit, port, cfg->force_speed)); 375 SOC_IF_ERROR_RETURN 376 (phy_5421S_duplex_set(unit, port, cfg->force_duplex)); 377 SOC_IF_ERROR_RETURN 378 (phy_5421S_master_set(unit, port, cfg->master)); 379 SOC_IF_ERROR_RETURN 380 (phy_5421S_adv_local_set(unit, port, cfg->autoneg_advert)); 381 SOC_IF_ERROR_RETURN 382 (phy_5421S_autoneg_set(unit, port, cfg->autoneg_enable)); 383 SOC_IF_ERROR_RETURN 384 (phy_5421S_mdix_set(unit, port, cfg->mdix)); 385 386 return SOC_E_NONE; 387 } 388 389 /* 390 * Function: 391 * phy_5421S_medium_config_set 392 * Purpose: 393 * Set the operating parameters that are automatically selected 394 * when medium switches type. 395 * Parameters: 396 * unit - StrataSwitch unit # 397 * port - Port number 398 * medium - SOC_PORT_MEDIUM_COPPER/FIBER 399 * cfg - Operating parameters 400 * Returns: 401 * SOC_E_XXX 402 */ 403 404 STATIC int 405 phy_5421S_medium_config_set(int unit, soc_port_t port, 406 soc_port_medium_t medium, 407 soc_phy_config_t *cfg) 408 { 409 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 410 411 /* 412 * Changes take effect immediately if the target medium is active. 413 */ 414 415 if (medium == SOC_PORT_MEDIUM_COPPER) { 416 if (!pc->automedium && !PHY_COPPER_MODE(unit, port)) { 417 return SOC_E_UNAVAIL; 418 } 419 sal_memcpy(&pc->copper, cfg, sizeof (pc->copper)); 420 421 pc->copper.autoneg_advert &= ADVERT_ALL_COPPER; 422 423 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 424 SOC_IF_ERROR_RETURN 425 (_phy_5421S_medium_config_update(unit, port, &pc->copper)); 426 } 427 } else if (medium == SOC_PORT_MEDIUM_FIBER) { 428 if (!pc->automedium && !PHY_FIBER_MODE(unit, port)) { 429 return SOC_E_UNAVAIL; 430 } 431 sal_memcpy(&pc->fiber, cfg, sizeof (pc->fiber)); 432 433 pc->fiber.autoneg_advert &= ADVERT_ALL_FIBER; 434 435 if (pc->medium == SOC_PORT_MEDIUM_FIBER) { 436 SOC_IF_ERROR_RETURN 437 (_phy_5421S_medium_config_update(unit, port, &pc->fiber)); 438 } 439 } else { 440 return SOC_E_PARAM; 441 } 442 443 return SOC_E_NONE; 444 } 445 446 /* 447 * Function: 448 * phy_5421S_medium_config_get 449 * Purpose: 450 * Get the operating parameters that are automatically selected 451 * when medium switches type. 452 * Parameters: 453 * unit - StrataSwitch unit # 454 * port - Port number 455 * medium - SOC_PORT_MEDIUM_COPPER/FIBER 456 * cfg - (OUT) Operating parameters 457 * Returns: 458 * SOC_E_XXX 459 */ 460 461 STATIC int 462 phy_5421S_medium_config_get(int unit, soc_port_t port, 463 soc_port_medium_t medium, 464 soc_phy_config_t *cfg) 465 { 466 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 467 468 if (medium == SOC_PORT_MEDIUM_COPPER) { 469 if (!pc->automedium && !PHY_COPPER_MODE(unit, port)) { 470 return SOC_E_UNAVAIL; 471 } 472 sal_memcpy(cfg, &pc->copper, sizeof (*cfg)); 473 } else if (medium == SOC_PORT_MEDIUM_FIBER) { 474 if (!pc->automedium && !PHY_FIBER_MODE(unit, port)) { 475 return SOC_E_UNAVAIL; 476 } 477 sal_memcpy(cfg, &pc->fiber, sizeof (*cfg)); 478 } else { 479 return SOC_E_PARAM; 480 } 481 482 return SOC_E_NONE; 483 } 484 485 /* 486 * Function: 487 * _phy_5421S_reset_setup 488 * Purpose: 489 * Function to reset the PHY and set up initial operating registers. 490 * Parameters: 491 * unit - StrataSwitch unit #. 492 * port - StrataSwitch port #. 493 * Returns: 494 * SOC_E_XXX 495 */ 496 497 STATIC int 498 _phy_5421S_reset_setup(int unit, soc_port_t port) 499 { 500 uint16 tmp; 501 soc_port_if_t pif; 502 int rv; 503 phy_ctrl_t *pc; 504 phy_ctrl_t *int_pc; 505 506 pc = EXT_PHY_SW_STATE(unit, port); 507 int_pc = INT_PHY_SW_STATE(unit, port); 508 509 DPRINTF((BSL_META_U(unit, 510 "_phy_5421S_reset_setup: u=%d p=%d\n"), 511 unit, port)); 512 513 /* Reset PHY */ 514 SOC_IF_ERROR_RETURN(soc_phy_reset(unit, port)); 515 516 /* Enable SGMII registers */ 517 SOC_IF_ERROR_RETURN 518 (WRITE_PHY5421_SGMII_REG_ENBLEr(unit, pc, 0xfc01)); 519 520 /* Put chip in TBI or SGMII mode (retain current PHY_FLAG_10B setting) */ 521 if (PHY_TBI_MODE(unit, port)) { 522 pif = SOC_PORT_IF_TBI; 523 } else { 524 pif = SOC_PORT_IF_GMII; 525 } 526 527 SOC_IF_ERROR_RETURN(phy_5421S_interface_set(unit, port, pif)); 528 529 /* Initialize the switch MAC PCS in case TBI mode is used now or later */ 530 rv = PHYCTRL_INIT(int_pc, unit, port); 531 /* If the SOC chip does not support TBI, and the system is */ 532 /* configured for TBI, return the error code. If the system */ 533 /* is not configured for TBI, ignore the phy_serdes_init error */ 534 /* and save the TBI capability status for use elsewhere. */ 535 if (rv < 0) { 536 EXT_PHY_SW_STATE(unit, port)->tbi_capable = FALSE; 537 if (PHY_TBI_MODE(unit, port)) { 538 539 #if 0 /* Should we take the PHY out of TBI mode? */ 540 SOC_IF_ERROR_RETURN(phy_5421S_interface_set(unit, port, 541 SOC_PORT_IF_GMII)); 542 #endif 543 return (rv); 544 } 545 } 546 547 #if SERDES_COPPER_AMP_WAR 548 /* 549 * Supply Sensitivity Errata for BCM5421SA0; reduces amplitude out 550 * of compliance if used on BCM5421SA1 or later parts. 551 */ 552 SOC_IF_ERROR_RETURN 553 (phy_reg_ge_write(unit, pc, 0x00, 0x0000, 0x18, 0x0c00)); 554 SOC_IF_ERROR_RETURN 555 (phy_reg_ge_write(unit, pc, 0x00, 0x003e, 0x15, 0x0380)); 556 #endif 557 558 #if ADC_PERF_WAR 559 /* 560 * Proprietary fix for unusual board/cabling arrangement. 561 * Can compromise cable length performance if used unnecessarily. 562 */ 563 SOC_IF_ERROR_RETURN 564 (phy_reg_ge_write(unit, pc, 0x00, 0x0000, 0x18, 0x0c00)); 565 SOC_IF_ERROR_RETURN 566 (phy_reg_ge_write(unit, pc, 0x00, 0x201f, 0x15, 0x2aaa)); 567 #endif 568 569 #if REGULATOR_GAMMA_WAR 570 /* 571 * Gamma fix needed if not using internal regulators; 572 * does not hurt if used either way. 573 */ 574 SOC_IF_ERROR_RETURN 575 (phy_reg_ge_write(unit, pc, 0x00, 0x0000, 0x18, 0x0c00)); 576 SOC_IF_ERROR_RETURN 577 (phy_reg_ge_write(unit, pc, 0x00, 0x000a, 0x15, 0x0323)); 578 #endif 579 580 /* Clear RGMII enable (shadow 111, misc control) */ 581 SOC_IF_ERROR_RETURN 582 (MODIFY_PHY5421_MISC_CTRLr(unit, pc, 0, 0x0080)); 583 584 /* 585 * Configure Spare Control Register 3. 586 * Enabling LEDs to work in fiber mode is important because this 587 * signal is used to indicate link in _phy_5421S_link_gmii_fiber(). 588 */ 589 tmp = 0x20; /* Enable signal/energy detect interrupt */ 590 tmp |= 0x40; /* Enable LEDs to work in fiber mode */ 591 SOC_IF_ERROR_RETURN 592 (MODIFY_PHY5421_SPARE_CTRL3r(unit, pc, tmp, 0x0060)); 593 594 /* Configure Extended Control Register */ 595 tmp = 0x0020; /* Enable LEDs to indicate traffic status */ 596 tmp |= 0x0001; /* Set high FIFO elasticity to support jumbo frames */ 597 SOC_IF_ERROR_RETURN 598 (MODIFY_PHY5421_MII_ECRr(unit, pc, tmp, 0x0021)); 599 600 /* Enable extended packet length (4.5k through 25k) */ 601 SOC_IF_ERROR_RETURN 602 (MODIFY_PHY5421_MISC_CTRLr(unit, pc, 0x4000, 0x4000)); 603 604 return(SOC_E_NONE); 605 } 606 607 /* 608 * Function: 609 * phy_5421S_init 610 * Purpose: 611 * Init function for 5421S PHY. 612 * Parameters: 613 * unit - StrataSwitch unit #. 614 * port - StrataSwitch port #. 615 * Returns: 616 * SOC_E_XXX 617 */ 618 619 STATIC int 620 phy_5421S_init(int unit, soc_port_t port) 621 { 622 phy_ctrl_t *pc; 623 int fiber_preferred; 624 625 DPRINTF((BSL_META_U(unit, 626 "phy_5421S_init: u=%d p=%d\n"), 627 unit, port)); 628 629 pc = EXT_PHY_SW_STATE(unit, port); 630 631 /* phyident.c has already set PHY_FLAGS_10B if required */ 632 633 PHY_FLAGS_SET(unit, port, PHY_FLAGS_5421S); 634 635 /* 636 * Set the default settings for copper and fiber. The upper layer 637 * application can change these using phy_5421S_medium_config_set. 638 * 639 * The settings are also updated by individual calls such as 640 * phy_5421S_adv_local_set, phy_5421S_speed_set, etc. In this case, 641 * they operate on the currently-selected medium type. 642 * 643 * The property phy_fiber_pref_port<X> is used to set a preference 644 * for fiber mode in the event both copper and fiber links are up. 645 * Default is to prefer fiber. 646 */ 647 648 pc->automedium = 649 soc_property_port_get(unit, port, 650 spn_PHY_AUTOMEDIUM, 1); 651 652 fiber_preferred = 653 soc_property_port_get(unit, port, spn_PHY_FIBER_PREF, 1); 654 655 pc->fiber_plug_dely = 656 soc_property_port_get(unit, port, 657 spn_PHY_FIBER_DEGLITCH_USECS, 0); 658 659 pc->copper.enable = TRUE; 660 pc->copper.preferred = !fiber_preferred; 661 pc->copper.autoneg_enable = TRUE; 662 pc->copper.autoneg_advert = ADVERT_ALL_COPPER; 663 pc->copper.force_speed = 1000; 664 pc->copper.force_duplex = TRUE; 665 pc->copper.master = SOC_PORT_MS_AUTO; 666 pc->copper.mdix = SOC_PORT_MDIX_AUTO; 667 668 pc->fiber.enable = TRUE; 669 pc->fiber.preferred = fiber_preferred; 670 pc->fiber.autoneg_enable = !PHY_TBI_MODE(unit, port); 671 pc->fiber.autoneg_advert = ADVERT_ALL_FIBER; 672 pc->fiber.force_speed = 1000; 673 pc->fiber.force_duplex = TRUE; 674 pc->fiber.master = SOC_PORT_MS_NONE; 675 pc->fiber.mdix = SOC_PORT_MDIX_NORMAL; 676 677 /* This PHY is TBI capable (although the SOC */ 678 /* chip may ultimately turn out not to be). */ 679 pc->tbi_capable = TRUE; 680 681 /* Start with no medium */ 682 683 pc->medium = SOC_PORT_MEDIUM_NONE; 684 685 /* Hardware initialization */ 686 687 SOC_IF_ERROR_RETURN(_phy_5421S_reset_setup(unit, port)); 688 689 return SOC_E_NONE; 690 } 691 692 /* 693 * Function: 694 * phy_5421S_enable_set 695 * Purpose: 696 * Enable or disable the physical interface. 697 * Parameters: 698 * unit - StrataSwitch unit #. 699 * port - StrataSwitch port #. 700 * enable - Boolean, true = enable PHY, false = disable. 701 * Returns: 702 * SOC_E_XXX 703 * Notes: 704 * This is a software enable/disable for the entire PHY. 705 * See phy_fe_ge_enable_set for an explanation. 706 */ 707 708 STATIC int 709 phy_5421S_enable_set(int unit, soc_port_t port, int enable) 710 { 711 if (GMII_MODE(unit, port)) { 712 if (enable) { 713 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE); 714 } else { 715 PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE); 716 } 717 return SOC_E_NONE; 718 } else { 719 phy_ctrl_t *int_pc; 720 721 int_pc = INT_PHY_SW_STATE(unit, port); 722 return PHYCTRL_ENABLE_SET(int_pc, unit, port, enable); 723 } 724 } 725 726 /* 727 * Function: 728 * phy_5421S_enable_get 729 * Purpose: 730 * Enable or disable the physical interface for a 5421S device. 731 * Parameters: 732 * unit - StrataSwitch unit #. 733 * port - StrataSwitch port #. 734 * enable - (OUT) Boolean, true = enable PHY, false = disable. 735 * Returns: 736 * SOC_E_XXX 737 */ 738 739 STATIC int 740 phy_5421S_enable_get(int unit, soc_port_t port, int *enable) 741 { 742 if (GMII_MODE(unit, port)) { 743 *enable = !PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE); 744 return SOC_E_NONE; 745 } else { 746 phy_ctrl_t *int_pc; 747 748 int_pc = INT_PHY_SW_STATE(unit, port); 749 return PHYCTRL_ENABLE_GET(int_pc, unit, port, enable); 750 } 751 } 752 753 /* 754 * Function: 755 * _phy_5421S_link_gmii_fiber (internal) 756 * Purpose: 757 * Determine the current link up/down status for a 5421S device when 758 * operating in GMII+FIBER mode. 759 * Parameters: 760 * unit - StrataSwitch unit #. 761 * port - StrataSwitch port #. 762 * link - (OUT) Boolean, true indicates link established. 763 * Returns: 764 * SOC_E_XXX 765 */ 766 STATIC int 767 _phy_5421S_link_gmii_fiber(int unit, soc_port_t port, int *link) 768 { 769 uint16 tmp; 770 int autoneg_enabled, autoneg_complete; 771 int autoneg_local_fault, autoneg_remote_fault; 772 int led_link; 773 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 774 775 /* 776 * Read LED link status (shadow 01000, LED status register). 777 * This works because the init routine has configured the Fiber LED 778 * mode. It provides real time indication of true link, whether or 779 * not autonegotiation is enabled. 780 */ 781 SOC_IF_ERROR_RETURN 782 (READ_PHY5421_LED_STATr(unit, pc, &tmp)); 783 784 led_link = ((tmp & 0x20) == 0); 785 786 SOC_IF_ERROR_RETURN 787 (READ_PHY5421_SGMII_1000X_CTRLr(unit, pc, &tmp)); 788 789 autoneg_enabled = ((tmp & 0x4) == 0); 790 791 if (!autoneg_enabled) { 792 /* If autonegotiation is off, go by LED signal */ 793 *link = led_link; 794 return SOC_E_NONE; 795 } 796 797 SOC_IF_ERROR_RETURN 798 (READ_PHY5421_SGMII_1000X_STATr(unit, pc, &tmp)); 799 800 autoneg_complete = ((tmp & 0x2) != 0); 801 802 if (!autoneg_complete) { 803 *link = FALSE; 804 return SOC_E_NONE; 805 } 806 807 autoneg_local_fault = ((tmp & 1) != 0); /* Autoneg Error */ 808 809 if (autoneg_local_fault) { 810 autoneg_remote_fault = 0; 811 } else { 812 SOC_IF_ERROR_RETURN 813 (READ_PHY5421_1000X_ANPr(unit, pc, &tmp)); 814 autoneg_remote_fault = ((tmp & 0x60) != 0); 815 } 816 817 if (autoneg_local_fault || autoneg_remote_fault) { 818 /* Restart autonegotiation */ 819 SOC_IF_ERROR_RETURN 820 (WRITE_PHY5421_SGMII_1000X_MISCr(unit, pc, 0x0001)); 821 *link = FALSE; 822 return SOC_E_NONE; 823 } 824 825 *link = TRUE; 826 827 return SOC_E_NONE; 828 } 829 830 /* 831 * Function: 832 * phy_5421S_link_get 833 * Purpose: 834 * Determine the current link up/down status for a 5421S device. 835 * Parameters: 836 * unit - StrataSwitch unit #. 837 * port - StrataSwitch port #. 838 * link - (OUT) Boolean, true indicates link established. 839 * Returns: 840 * SOC_E_XXX 841 * Notes: 842 * No synchronization performed at this level. 843 */ 844 845 STATIC int 846 phy_5421S_link_get(int unit, soc_port_t port, int *link) 847 { 848 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 849 int medium; 850 851 SOC_IF_ERROR_RETURN(_phy_5421S_medium_check(unit, port, &medium)); 852 853 if (medium != pc->medium) { 854 PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 855 DPRINTF((BSL_META_U(unit, 856 "phy_5421S_link_get: u=%d p=%d: medium %d-->%d\n"), 857 unit, port, pc->medium, medium)); 858 859 pc->medium = medium; 860 861 SOC_IF_ERROR_RETURN(_phy_5421S_medium_select(unit, port, medium)); 862 863 /* Ensure linkscan sees link down at least once */ 864 865 *link = FALSE; 866 return SOC_E_NONE; 867 } else { 868 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 869 } 870 871 /* 872 * Use the appropriate method to check for link up. 873 */ 874 875 if (GMII_MODE(unit, port)) { 876 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 877 return phy_fe_ge_link_get(unit, port, link); 878 } else if (pc->medium == SOC_PORT_MEDIUM_FIBER) { 879 return _phy_5421S_link_gmii_fiber(unit, port, link); 880 } else { 881 *link = FALSE; 882 return SOC_E_NONE; 883 } 884 } else { 885 phy_ctrl_t *int_pc; 886 887 int_pc = INT_PHY_SW_STATE(unit, port); 888 return PHYCTRL_LINK_GET(int_pc, unit, port, link); 889 } 890 } 891 892 /* 893 * Function: 894 * phy_5421S_duplex_set 895 * Purpose: 896 * Set the current duplex mode (forced). 897 * Parameters: 898 * unit - StrataSwitch unit #. 899 * port - StrataSwitch port #. 900 * duplex - Boolean, true indicates full duplex, false indicates half. 901 * Returns: 902 * SOC_E_NONE 903 * SOC_E_UNAVAIL - Half duplex requested, and not supported. 904 * SOC_E_XXX 905 * Notes: 906 * The duplex is set only for the ACTIVE medium. 907 * No synchronization performed at this level. 908 * Autonegotiation is not manipulated. 909 */ 910 911 STATIC int 912 phy_5421S_duplex_set(int unit, soc_port_t port, int duplex) 913 { 914 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 915 916 DPRINTF((BSL_META_U(unit, 917 "phy_5421S_duplex_set: u=%d p=%d d=%d m=%d\n"), 918 unit, port, duplex, pc->medium)); 919 920 if (GMII_MODE(unit, port)) { 921 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 922 SOC_IF_ERROR_RETURN(phy_fe_ge_duplex_set(unit, port, duplex)); 923 pc->copper.force_duplex = duplex; 924 } 925 926 if (pc->medium == SOC_PORT_MEDIUM_FIBER && !duplex) { 927 return SOC_E_UNAVAIL; 928 } 929 } else { 930 phy_ctrl_t *int_pc; 931 932 int_pc = INT_PHY_SW_STATE(unit, port); 933 934 SOC_IF_ERROR_RETURN 935 (PHYCTRL_DUPLEX_SET(int_pc, unit, port, duplex)); 936 937 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 938 pc->copper.force_duplex = duplex; 939 } 940 941 if (pc->medium == SOC_PORT_MEDIUM_FIBER) { 942 pc->fiber.force_duplex = duplex; 943 } 944 } 945 946 return SOC_E_NONE; 947 } 948 949 /* 950 * Function: 951 * phy_5421S_duplex_get 952 * Purpose: 953 * Get the current operating duplex mode. If autoneg is enabled, 954 * then operating mode is returned, otherwise forced mode is returned. 955 * Parameters: 956 * unit - StrataSwitch unit #. 957 * port - StrataSwitch port #. 958 * duplex - (OUT) Boolean, true indicates full duplex, false 959 * indicates half. 960 * Returns: 961 * SOC_E_NONE 962 * Notes: 963 * The duplex is retrieved for the ACTIVE medium. 964 * No synchronization performed at this level. Autonegotiation is 965 * not manipulated. 966 */ 967 968 STATIC int 969 phy_5421S_duplex_get(int unit, soc_port_t port, int *duplex) 970 { 971 phy_ctrl_t *pc; 972 973 if (GMII_MODE(unit, port)) { 974 pc = EXT_PHY_SW_STATE(unit, port); 975 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 976 SOC_IF_ERROR_RETURN(phy_fe_ge_duplex_get(unit, port, duplex)); 977 } else { 978 *duplex = TRUE; 979 } 980 return SOC_E_NONE; 981 } else { 982 pc = INT_PHY_SW_STATE(unit, port); 983 984 return PHYCTRL_DUPLEX_GET(pc, unit, port, duplex); 985 } 986 } 987 988 /* 989 * Function: 990 * phy_5421S_speed_set 991 * Purpose: 992 * Set the current operating speed (forced). 993 * Parameters: 994 * unit - StrataSwitch unit #. 995 * port - StrataSwitch port #. 996 * speed - Requested speed, only 1000 supported. 997 * Returns: 998 * SOC_E_XXX 999 * Notes: 1000 * The speed is set only for the ACTIVE medium. 1001 */ 1002 1003 STATIC int 1004 phy_5421S_speed_set(int unit, soc_port_t port, int speed) 1005 { 1006 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1007 1008 DPRINTF((BSL_META_U(unit, 1009 "phy_5421S_speed_set: u=%d p=%d s=%d m=%d\n"), 1010 unit, port, speed, pc->medium)); 1011 1012 if (GMII_MODE(unit, port)) { 1013 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 1014 SOC_IF_ERROR_RETURN(phy_fe_ge_speed_set(unit, port, speed)); 1015 pc->copper.force_speed = speed; 1016 } 1017 1018 if (pc->medium == SOC_PORT_MEDIUM_FIBER && speed != 1000) { 1019 return SOC_E_CONFIG; 1020 } 1021 } else { 1022 phy_ctrl_t *int_pc; 1023 1024 int_pc = INT_PHY_SW_STATE(unit, port); 1025 1026 SOC_IF_ERROR_RETURN 1027 (PHYCTRL_SPEED_SET(int_pc, unit, port, speed)); 1028 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 1029 pc->copper.force_speed = speed; 1030 } 1031 1032 if (pc->medium == SOC_PORT_MEDIUM_FIBER) { 1033 pc->fiber.force_speed = speed; 1034 } 1035 } 1036 1037 return SOC_E_NONE; 1038 } 1039 1040 /* 1041 * Function: 1042 * phy_5421S_speed_get 1043 * Purpose: 1044 * Get the current operating speed for a 5421S device. 1045 * Parameters: 1046 * unit - StrataSwitch unit #. 1047 * port - StrataSwitch port #. 1048 * speed - (OUT) Boolean, true indicates full duplex, false 1049 * indicates half. 1050 * Returns: 1051 * SOC_E_XXX 1052 * Notes: 1053 * The speed is retrieved for the ACTIVE medium, 0 if none. 1054 */ 1055 1056 STATIC int 1057 phy_5421S_speed_get(int unit, soc_port_t port, int *speed) 1058 { 1059 phy_ctrl_t *pc; 1060 1061 if (GMII_MODE(unit, port)) { 1062 pc = EXT_PHY_SW_STATE(unit, port); 1063 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 1064 SOC_IF_ERROR_RETURN(phy_fe_ge_speed_get(unit, port, speed)); 1065 } else if (pc->medium == SOC_PORT_MEDIUM_FIBER) { 1066 *speed = 1000; 1067 } else { 1068 *speed = 0; 1069 } 1070 return SOC_E_NONE; 1071 } else { 1072 pc = INT_PHY_SW_STATE(unit, port); 1073 return PHYCTRL_SPEED_GET(pc, unit, port, speed); 1074 } 1075 } 1076 1077 /* 1078 * Function: 1079 * phy_5421S_master_set 1080 * Purpose: 1081 * Set the current master mode 1082 * Parameters: 1083 * unit - StrataSwitch unit #. 1084 * port - StrataSwitch port #. 1085 * master - SOC_PORT_MS_* 1086 * Returns: 1087 * SOC_E_XXX 1088 * Notes: 1089 * The master mode is set only for the ACTIVE medium. 1090 */ 1091 1092 STATIC int 1093 phy_5421S_master_set(int unit, soc_port_t port, int master) 1094 { 1095 phy_ctrl_t *pc; 1096 1097 if (GMII_MODE(unit, port)) { 1098 pc = EXT_PHY_SW_STATE(unit, port); 1099 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 1100 SOC_IF_ERROR_RETURN(phy_fe_ge_master_set(unit, port, master)); 1101 pc->copper.master = master; 1102 } 1103 } else { 1104 pc = INT_PHY_SW_STATE(unit, port); 1105 1106 return (PHYCTRL_MASTER_SET(pc, unit, port, master)); 1107 } 1108 1109 return SOC_E_NONE; 1110 } 1111 1112 /* 1113 * Function: 1114 * phy_5421S_master_get 1115 * Purpose: 1116 * Get the current master mode for a 5421S device. 1117 * Parameters: 1118 * unit - StrataSwitch unit #. 1119 * port - StrataSwitch port #. 1120 * master - (OUT) SOC_PORT_MS_* 1121 * Returns: 1122 * SOC_E_XXX 1123 * Notes: 1124 * The master mode is retrieved for the ACTIVE medium. 1125 */ 1126 1127 STATIC int 1128 phy_5421S_master_get(int unit, soc_port_t port, int *master) 1129 { 1130 phy_ctrl_t *pc; 1131 1132 if (GMII_MODE(unit, port)) { 1133 pc = EXT_PHY_SW_STATE(unit, port); 1134 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 1135 SOC_IF_ERROR_RETURN(phy_fe_ge_master_get(unit, port, master)); 1136 } else { 1137 *master = SOC_PORT_MS_NONE; 1138 } 1139 } else { 1140 pc = INT_PHY_SW_STATE(unit, port); 1141 1142 return (PHYCTRL_MASTER_GET(pc, unit, port, master)); 1143 } 1144 1145 return SOC_E_NONE; 1146 } 1147 1148 /* 1149 * Function: 1150 * phy_5421S_autoneg_set 1151 * Purpose: 1152 * Enable or disable auto-negotiation on the specified port. 1153 * Parameters: 1154 * unit - StrataSwitch unit #. 1155 * port - StrataSwitch port #. 1156 * an - Boolean, if true, auto-negotiation is enabled 1157 * (and/or restarted). If false, autonegotiation is disabled. 1158 * Returns: 1159 * SOC_E_XXX 1160 * Notes: 1161 * The autoneg mode is set only for the ACTIVE medium. 1162 */ 1163 1164 STATIC int 1165 phy_5421S_autoneg_set(int unit, soc_port_t port, int autoneg) 1166 { 1167 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1168 1169 DPRINTF((BSL_META_U(unit, 1170 "phy_5421S_autoneg_set: u=%d p=%d autoneg=%d m=%d\n"), 1171 unit, port, autoneg, pc->medium)); 1172 1173 if (GMII_MODE(unit, port)) { 1174 uint16 tmp; 1175 1176 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 1177 SOC_IF_ERROR_RETURN(phy_fe_ge_an_set(unit, port, autoneg)); 1178 pc->copper.autoneg_enable = autoneg ? 1 : 0; 1179 } 1180 1181 if (pc->medium == SOC_PORT_MEDIUM_FIBER) { 1182 if (autoneg) { 1183 tmp = 0; /* Clear AUTONEG DISABLE */ 1184 } else { 1185 tmp = 0x4; /* Set AUTONEG DISABLE */ 1186 } 1187 1188 SOC_IF_ERROR_RETURN 1189 (MODIFY_PHY5421_SGMII_1000X_CTRLr(unit, pc, tmp, 0x0004)); 1190 1191 /* Restart autoneg */ 1192 SOC_IF_ERROR_RETURN 1193 (WRITE_PHY5421_SGMII_1000X_MISCr(unit, pc, 0x0001)); 1194 1195 pc->fiber.autoneg_enable = autoneg ? 1 : 0; 1196 } 1197 } else { 1198 phy_ctrl_t *int_pc; 1199 int_pc = INT_PHY_SW_STATE(unit, port); 1200 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 1201 /* Partial TBI+COPPER support - ANCTL.ANEN must be 0 */ 1202 1203 SOC_IF_ERROR_RETURN 1204 (PHYCTRL_AUTO_NEGOTIATE_SET(int_pc, unit, port, FALSE)); 1205 1206 pc->copper.autoneg_enable = FALSE; 1207 } 1208 1209 if (pc->medium == SOC_PORT_MEDIUM_FIBER) { 1210 SOC_IF_ERROR_RETURN 1211 (PHYCTRL_AUTO_NEGOTIATE_SET(int_pc, unit, port, autoneg)); 1212 1213 pc->fiber.autoneg_enable = autoneg ? 1 : 0; 1214 } 1215 } 1216 1217 return SOC_E_NONE; 1218 } 1219 1220 /* 1221 * Function: 1222 * phy_5421S_autoneg_get 1223 * Purpose: 1224 * Get the current auto-negotiation status (enabled/busy). 1225 * Parameters: 1226 * unit - StrataSwitch unit #. 1227 * port - StrataSwitch port #. 1228 * autoneg - (OUT) if true, auto-negotiation is enabled. 1229 * autoneg_done - (OUT) if true, auto-negotiation is complete. This 1230 * value is undefined if autoneg == FALSE. 1231 * Returns: 1232 * SOC_E_XXX 1233 * Notes: 1234 * The autoneg mode is retrieved for the ACTIVE medium. 1235 */ 1236 1237 STATIC int 1238 phy_5421S_autoneg_get(int unit, soc_port_t port, 1239 int *autoneg, int *autoneg_done) 1240 { 1241 phy_ctrl_t *pc; 1242 1243 if (GMII_MODE(unit, port)) { 1244 pc = EXT_PHY_SW_STATE(unit, port); 1245 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 1246 SOC_IF_ERROR_RETURN 1247 (phy_fe_ge_an_get(unit, port, autoneg, autoneg_done)); 1248 } else if (pc->medium == SOC_PORT_MEDIUM_FIBER) { 1249 uint16 tmp; 1250 1251 SOC_IF_ERROR_RETURN 1252 (READ_PHY5421_SGMII_1000X_CTRLr(unit, pc, &tmp)); 1253 *autoneg = ((tmp & 0x4) == 0); /* AUTONEG DISABLE bit clear */ 1254 1255 SOC_IF_ERROR_RETURN 1256 (READ_PHY5421_SGMII_1000X_STATr(unit, pc, &tmp)); 1257 1258 *autoneg_done = ((tmp & 0x2) != 0); /* AUTONEG DONE */ 1259 } else { 1260 *autoneg = FALSE; 1261 *autoneg_done = FALSE; 1262 } 1263 } else { 1264 pc = INT_PHY_SW_STATE(unit, port); 1265 SOC_IF_ERROR_RETURN 1266 (PHYCTRL_AUTO_NEGOTIATE_GET(pc, unit, port, autoneg, autoneg_done)); 1267 } 1268 1269 return SOC_E_NONE; 1270 } 1271 1272 /* 1273 * Function: 1274 * phy_5421S_adv_local_set 1275 * Purpose: 1276 * Set the current advertisement for auto-negotiation. 1277 * Parameters: 1278 * unit - StrataSwitch unit #. 1279 * port - StrataSwitch port #. 1280 * mode - Port mode mask indicating supported options/speeds. 1281 * Returns: 1282 * SOC_E_XXX 1283 * Notes: 1284 * The advertisement is set only for the ACTIVE medium. 1285 * No synchronization performed at this level. 1286 */ 1287 1288 STATIC int 1289 phy_5421S_adv_local_set(int unit, soc_port_t port, soc_port_mode_t mode) 1290 { 1291 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1292 1293 DPRINTF((BSL_META_U(unit, 1294 "phy_5421S_adv_local_set: u=%d p=%d mode=0x%x m=%d\n"), 1295 unit, port, mode, pc->medium)); 1296 1297 if (GMII_MODE(unit, port)) { 1298 uint16 tmp; 1299 int autoneg; 1300 1301 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 1302 SOC_IF_ERROR_RETURN(phy_ge_adv_local_set(unit, port, mode)); 1303 pc->copper.autoneg_advert = mode; 1304 } 1305 1306 if (pc->medium == SOC_PORT_MEDIUM_FIBER) { 1307 1308 SOC_IF_ERROR_RETURN 1309 (READ_PHY5421_SGMII_1000X_CTRLr(unit, pc, &tmp)); 1310 1311 autoneg = ((tmp & 0x4) == 0); 1312 1313 tmp &= ~0x6000; /* Transmit "No-Failure" to partner */ 1314 1315 switch (mode & SOC_PM_PAUSE) { 1316 default: 1317 tmp &= ~(0x1000 | 0x0800); /* ASYMM=0 and PAUSE=0 */ 1318 break; 1319 case SOC_PM_PAUSE_TX: 1320 tmp |= 0x1000; /* ASYMM=1 and PAUSE(dir)=0 */ 1321 tmp &= ~0x0800; 1322 break; 1323 case SOC_PM_PAUSE_RX: 1324 tmp |= (0x1000 | 0x0800); /* ASYMM=1 and PAUSE(dir)=1 */ 1325 break; 1326 case SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX: 1327 tmp &= ~0x1000; /* ASYMM=0 and PAUSE=1 */ 1328 tmp |= 0x0800; 1329 break; 1330 } 1331 1332 SOC_IF_ERROR_RETURN 1333 (WRITE_PHY5421_SGMII_1000X_CTRLr(unit, pc, tmp)); 1334 1335 if (autoneg) { 1336 /* Restart autonegotiation */ 1337 SOC_IF_ERROR_RETURN 1338 (WRITE_PHY5421_SGMII_1000X_MISCr(unit, pc, 0x0001)); 1339 } 1340 1341 pc->fiber.autoneg_advert = mode; 1342 } 1343 } else { 1344 phy_ctrl_t *int_pc; 1345 1346 int_pc = INT_PHY_SW_STATE(unit, port); 1347 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 1348 SOC_IF_ERROR_RETURN 1349 (PHYCTRL_ADV_SET(int_pc, unit, port, mode)); 1350 pc->copper.autoneg_advert = mode; 1351 } 1352 if (pc->medium == SOC_PORT_MEDIUM_FIBER) { 1353 SOC_IF_ERROR_RETURN 1354 (PHYCTRL_ADV_SET(int_pc, unit, port, mode)); 1355 pc->fiber.autoneg_advert = mode; 1356 } 1357 } 1358 1359 return SOC_E_NONE; 1360 } 1361 1362 /* 1363 * Function: 1364 * phy_5421S_adv_local_get 1365 * Purpose: 1366 * Get the current advertisement for auto-negotiation. 1367 * Parameters: 1368 * unit - StrataSwitch unit #. 1369 * port - StrataSwitch port #. 1370 * mode - (OUT) Port mode mask indicating supported options/speeds. 1371 * Returns: 1372 * SOC_E_XXX 1373 * Notes: 1374 * The advertisement is retrieved for the ACTIVE medium. 1375 * No synchronization performed at this level. 1376 */ 1377 1378 STATIC int 1379 phy_5421S_adv_local_get(int unit, soc_port_t port, soc_port_mode_t *mode) 1380 { 1381 phy_ctrl_t *pc; 1382 1383 if (GMII_MODE(unit, port)) { 1384 pc = EXT_PHY_SW_STATE(unit, port); 1385 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 1386 SOC_IF_ERROR_RETURN(phy_ge_adv_local_get(unit, port, mode)); 1387 } else if (pc->medium == SOC_PORT_MEDIUM_FIBER) { 1388 uint16 tmp; 1389 1390 SOC_IF_ERROR_RETURN 1391 (READ_PHY5421_SGMII_1000X_CTRLr(unit, pc, &tmp)); 1392 1393 *mode = SOC_PM_1000MB_FD; 1394 1395 switch (tmp & 0x1800) { 1396 case 0x0000: 1397 break; 1398 case 0x0800: 1399 *mode |= SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX; 1400 break; 1401 case 0x1000: 1402 *mode |= SOC_PM_PAUSE_TX; 1403 break; 1404 case 0x1800: 1405 *mode |= SOC_PM_PAUSE_RX; 1406 break; 1407 } 1408 } else { 1409 *mode = 0; 1410 } 1411 } else { 1412 pc = INT_PHY_SW_STATE(unit, port); 1413 SOC_IF_ERROR_RETURN 1414 (PHYCTRL_ADV_GET(pc, unit, port, mode)); 1415 } 1416 1417 return SOC_E_NONE; 1418 } 1419 1420 /* 1421 * Function: 1422 * phy_5421S_adv_remote_get 1423 * Purpose: 1424 * Get partner's current advertisement for auto-negotiation. 1425 * Parameters: 1426 * unit - StrataSwitch unit #. 1427 * port - StrataSwitch port #. 1428 * mode - (OUT) Port mode mask indicating supported options/speeds. 1429 * Returns: 1430 * SOC_E_XXX 1431 * Notes: 1432 * The remote advertisement is retrieved for the ACTIVE medium. 1433 * No synchronization performed at this level. If Autonegotiation is 1434 * disabled or in progress, this routine will return an error. 1435 */ 1436 1437 STATIC int 1438 phy_5421S_adv_remote_get(int unit, soc_port_t port, soc_port_mode_t *mode) 1439 { 1440 phy_ctrl_t *pc; 1441 1442 if (GMII_MODE(unit, port)) { 1443 pc = EXT_PHY_SW_STATE(unit, port); 1444 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 1445 SOC_IF_ERROR_RETURN(phy_ge_adv_remote_get(unit, port, mode)); 1446 } else if (pc->medium == SOC_PORT_MEDIUM_FIBER) { 1447 uint16 tmp; 1448 int link; 1449 1450 *mode = 0; 1451 1452 SOC_IF_ERROR_RETURN 1453 (READ_PHY5421_SGMII_1000X_CTRLr(unit, pc, &tmp)); 1454 1455 if (tmp & 0x4) { 1456 return SOC_E_DISABLED; 1457 } 1458 1459 SOC_IF_ERROR_RETURN 1460 (_phy_5421S_link_gmii_fiber(unit, port, &link)); 1461 1462 if (!link) { 1463 return SOC_E_BUSY; 1464 } 1465 1466 SOC_IF_ERROR_RETURN 1467 (READ_PHY5421_1000X_ANPr(unit, pc, &tmp)); 1468 1469 if (tmp & 0x10) { 1470 *mode |= SOC_PM_PAUSE_ASYMM; 1471 } 1472 1473 if (tmp & 0x8) { 1474 *mode |= SOC_PM_PAUSE; 1475 } 1476 1477 if (tmp & 0x4) { 1478 *mode |= SOC_PM_1000MB_HD; 1479 } 1480 1481 if (tmp & 0x2) { 1482 *mode |= SOC_PM_1000MB_FD; 1483 } 1484 } else { 1485 *mode = 0; 1486 } 1487 } else { 1488 pc = INT_PHY_SW_STATE(unit, port); 1489 return (PHYCTRL_ADV_REMOTE_GET(pc, unit, port, mode)); 1490 1491 } 1492 1493 return SOC_E_NONE; 1494 } 1495 1496 /* 1497 * Function: 1498 * phy_5421S_lb_set 1499 * Purpose: 1500 * Set the local PHY loopback mode. 1501 * Parameters: 1502 * unit - StrataSwitch unit #. 1503 * port - StrataSwitch port #. 1504 * loopback - Boolean: true = enable loopback, false = disable. 1505 * Returns: 1506 * SOC_E_XXX 1507 * Notes: 1508 * The loopback mode is set only for the ACTIVE medium. 1509 * No synchronization performed at this level. 1510 */ 1511 1512 STATIC int 1513 phy_5421S_lb_set(int unit, soc_port_t port, int enable) 1514 { 1515 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1516 1517 DPRINTF((BSL_META_U(unit, 1518 "phy_5421S_lb_set: u=%d p=%d en=%d m=%d\n"), 1519 unit, port, enable, pc->medium)); 1520 1521 if (GMII_MODE(unit, port) && pc->medium == SOC_PORT_MEDIUM_COPPER) { 1522 SOC_IF_ERROR_RETURN(phy_fe_ge_lb_set(unit, port, enable)); 1523 } else { 1524 uint16 tmp; 1525 1526 SOC_IF_ERROR_RETURN 1527 (READ_PHY5421_SGMII_1000X_CTRLr(unit, pc, &tmp)); 1528 1529 if (enable) { 1530 tmp |= 1; 1531 } else { 1532 tmp &= ~1; 1533 } 1534 1535 SOC_IF_ERROR_RETURN 1536 (WRITE_PHY5421_SGMII_1000X_CTRLr(unit, pc, tmp)); 1537 } 1538 1539 return SOC_E_NONE; 1540 } 1541 1542 /* 1543 * Function: 1544 * phy_5421S_lb_get 1545 * Purpose: 1546 * Get the local PHY loopback mode. 1547 * Parameters: 1548 * unit - StrataSwitch unit #. 1549 * port - StrataSwitch port #. 1550 * loopback - (OUT) Boolean: true = enable loopback, false = disable. 1551 * Returns: 1552 * SOC_E_XXX 1553 * Notes: 1554 * The loopback mode is retrieved for the ACTIVE medium. 1555 */ 1556 1557 STATIC int 1558 phy_5421S_lb_get(int unit, soc_port_t port, int *enable) 1559 { 1560 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1561 1562 if (GMII_MODE(unit, port) && pc->medium == SOC_PORT_MEDIUM_COPPER) { 1563 SOC_IF_ERROR_RETURN(phy_fe_ge_lb_get(unit, port, enable)); 1564 } else { 1565 uint16 tmp; 1566 1567 SOC_IF_ERROR_RETURN 1568 (READ_PHY5421_SGMII_1000X_CTRLr(unit, pc, &tmp)); 1569 1570 *enable = ((tmp & 1)) != 0; 1571 } 1572 1573 return SOC_E_NONE; 1574 } 1575 1576 /* 1577 * Function: 1578 * phy_5421S_interface_set 1579 * Purpose: 1580 * Set the current operating mode of the PHY (TBI or MII/GMII) 1581 * Parameters: 1582 * unit - StrataSwitch unit #. 1583 * port - StrataSwitch port #. 1584 * pif - One of SOC_PORT_IF_* 1585 * Returns: 1586 * SOC_E_XXX 1587 */ 1588 1589 STATIC int 1590 phy_5421S_interface_set(int unit, soc_port_t port, soc_port_if_t pif) 1591 { 1592 #if defined(BCM_ESW_SUPPORT) 1593 uint32 gpcsc; 1594 #endif 1595 uint16 mii_ecr; 1596 int tbi; 1597 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1598 1599 DPRINTF((BSL_META_U(unit, 1600 "phy_5421S_interface_set: u=%d p=%d pif=%d\n"), 1601 unit, port, pif)); 1602 1603 /* 1604 * On SDKs with 5421S daughterboards, for even N, the port N EWRAP 1605 * line is used to select TBI mode on port N and N+1, and port N+1 1606 * EWRAP is ignored. MII management registers are used to select 1607 * loopback. 1608 */ 1609 1610 tbi = (pif == SOC_PORT_IF_TBI); 1611 1612 if (tbi) { 1613 if (EXT_PHY_SW_STATE(unit, port)->tbi_capable == TRUE) { 1614 PHY_FLAGS_SET(unit, port, PHY_FLAGS_10B); 1615 } else { 1616 return SOC_E_UNAVAIL; 1617 } 1618 } else { 1619 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_10B); 1620 } 1621 1622 #if defined(BCM_ESW_SUPPORT) 1623 if (SOC_IS_ESW(unit)) { 1624 SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, port, &gpcsc)); 1625 soc_reg_field_set(unit, GPCSCr, &gpcsc, EWRAPf, tbi); 1626 SOC_IF_ERROR_RETURN(WRITE_GPCSCr(unit, port, gpcsc)); 1627 } 1628 #endif /* BCM_ESW_SUPPORT */ 1629 /* 1630 * There is a strange "TBI Toggle" bit in this PHY that must be 1631 * written if the PHY comes up in GMII mode. The initial mode is 1632 * latched from a pin and may vary depending if link is present. 1633 */ 1634 1635 SOC_IF_ERROR_RETURN 1636 (READ_PHY5421_MII_ECRr(unit, pc, &mii_ecr)); 1637 1638 DPRINTF((BSL_META_U(unit, 1639 "5421S_if_set: port=%d tbi=%d reg 0x10=0x%x\n"), 1640 port, tbi, mii_ecr)); 1641 1642 if ((tbi && !(mii_ecr & MII_ECR_10B)) || 1643 (!tbi && (mii_ecr & MII_ECR_10B))) { 1644 1645 /* Update ECR */ 1646 mii_ecr ^= MII_ECR_10B; 1647 1648 DPRINTF((BSL_META_U(unit, 1649 "5421S_if_set: port=%d set reg 0x10=0x%x " 1650 "and toggle TBI\n"), 1651 port, mii_ecr)); 1652 1653 SOC_IF_ERROR_RETURN 1654 (WRITE_PHY5421_MII_ECRr(unit, pc, mii_ecr)); 1655 1656 /* Write 1 to TBI Toggle (shadow 00100, spare control register 2) */ 1657 SOC_IF_ERROR_RETURN 1658 (WRITE_PHY5421_SPARE_CTRL2r(unit, pc, 0x0040)); 1659 } 1660 1661 return SOC_E_NONE; 1662 } 1663 1664 /* 1665 * Function: 1666 * phy_5421S_interface_get 1667 * Purpose: 1668 * Get the current operating mode of the PHY (TBI or GMII). 1669 * Parameters: 1670 * unit - StrataSwitch unit #. 1671 * port - StrataSwitch port #. 1672 * mii - (OUT) TRUE --> MII/GMII, FALSE --> TBI. 1673 * Returns: 1674 * SOC_E_XXX 1675 */ 1676 1677 STATIC int 1678 phy_5421S_interface_get(int unit, soc_port_t port, soc_port_if_t *pif) 1679 { 1680 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_10B)) { 1681 *pif = SOC_PORT_IF_TBI; 1682 } else { 1683 *pif = SOC_PORT_IF_GMII; 1684 } 1685 1686 return SOC_E_NONE; 1687 } 1688 1689 /* 1690 * Function: 1691 * phy_5421S_ability_get 1692 * Purpose: 1693 * Get the abilities of the local gigabit PHY. 1694 * Parameters: 1695 * unit - StrataSwitch unit #. 1696 * port - StrataSwitch port #. 1697 * mode - (OUT) Port mode mask indicating supported options/speeds. 1698 * Returns: 1699 * SOC_E_NONE 1700 * Notes: 1701 * The ability is retrieved only for the ACTIVE medium. 1702 */ 1703 1704 STATIC int 1705 phy_5421S_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode) 1706 { 1707 phy_ctrl_t *pc; 1708 1709 /* 1710 * This should return both GMII and TBI abilities, but with the 1711 * current code that causes problems in _bcm_port_mode_setup(). 1712 */ 1713 1714 if (GMII_MODE(unit, port)) { 1715 pc = EXT_PHY_SW_STATE(unit, port); 1716 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 1717 SOC_IF_ERROR_RETURN(phy_ge_ability_get(unit, port, mode)); 1718 } else if (pc->medium == SOC_PORT_MEDIUM_FIBER) { 1719 *mode = (SOC_PM_AN | SOC_PM_LB_PHY | 1720 SOC_PM_PAUSE | SOC_PM_PAUSE_ASYMM | 1721 SOC_PM_GMII | SOC_PM_1000MB_FD); 1722 } else { 1723 *mode = SOC_PM_GMII; 1724 } 1725 } else { 1726 pc = INT_PHY_SW_STATE(unit, port); 1727 SOC_IF_ERROR_RETURN 1728 (PHYCTRL_ABILITY_GET(pc, unit, port, mode)); 1729 1730 } 1731 1732 if (pc->automedium) { 1733 *mode |= SOC_PM_COMBO; 1734 } 1735 1736 if (PHY_TBI_MODE(unit, port)) { 1737 *mode |= SOC_PM_TBI; 1738 } 1739 1740 DPRINTF((BSL_META_U(unit, 1741 "phy_5421S_ability_get: u=%d p=%d mode=0x%x\n"), 1742 unit, port, *mode)); 1743 1744 return(SOC_E_NONE); 1745 } 1746 1747 /* 1748 * Function: 1749 * phy_5421S_mdix_set 1750 * Description: 1751 * Set the Auto-MDIX mode of a port/PHY 1752 * Parameters: 1753 * unit - Device number 1754 * port - Port number 1755 * mode - One of: 1756 * BCM_PORT_MDIX_AUTO 1757 * Enable auto-MDIX when autonegotiation is enabled 1758 * BCM_PORT_MDIX_FORCE_AUTO 1759 * Enable auto-MDIX always 1760 * BCM_PORT_MDIX_NORMAL 1761 * Disable auto-MDIX 1762 * BCM_PORT_MDIX_XOVER 1763 * Disable auto-MDIX, and swap cable pairs 1764 * Return Value: 1765 * SOC_E_UNAVAIL - feature unsupported by hardware 1766 * SOC_E_XXX - other error 1767 */ 1768 STATIC int 1769 phy_5421S_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode) 1770 { 1771 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1772 int speed; 1773 int rv = SOC_E_NONE; 1774 1775 if (pc == NULL) { 1776 return SOC_E_PARAM; 1777 } 1778 1779 switch (pc->medium) { 1780 case SOC_PORT_MEDIUM_FIBER: 1781 if (mode != SOC_PORT_MDIX_NORMAL) { 1782 rv = SOC_E_UNAVAIL; 1783 } 1784 1785 if (rv == SOC_E_NONE) { 1786 pc->fiber.mdix = mode; 1787 } 1788 break; 1789 1790 case SOC_PORT_MEDIUM_COPPER: 1791 switch (mode) { 1792 case SOC_PORT_MDIX_AUTO: 1793 /* Clear bit 14 for automatic MDI crossover */ 1794 SOC_IF_ERROR_RETURN 1795 (MODIFY_PHY5421_MII_ECRr(unit, pc, 0, 0x4000)); 1796 break; 1797 1798 case SOC_PORT_MDIX_FORCE_AUTO: 1799 rv = SOC_E_UNAVAIL; 1800 break; 1801 1802 case SOC_PORT_MDIX_NORMAL: 1803 SOC_IF_ERROR_RETURN(phy_5421S_speed_get(unit, port, &speed)); 1804 if (speed == 10 || speed == 100) { 1805 /* Set bit 14 for manual MDI crossover */ 1806 SOC_IF_ERROR_RETURN 1807 (MODIFY_PHY5421_MII_ECRr(unit, pc, 0x4000, 0x4000)); 1808 1809 SOC_IF_ERROR_RETURN 1810 (WRITE_PHY5421_TEST1r(unit, pc, 0x0000)); 1811 } else { 1812 return SOC_E_UNAVAIL; 1813 } 1814 break; 1815 1816 case SOC_PORT_MDIX_XOVER: 1817 SOC_IF_ERROR_RETURN(phy_5421S_speed_get(unit, port, &speed)); 1818 if (speed == 10 || speed == 100) { 1819 /* Set bit 14 for manual MDI crossover */ 1820 SOC_IF_ERROR_RETURN 1821 (MODIFY_PHY5421_MII_ECRr(unit, pc, 0x4000, 0x4000)); 1822 1823 SOC_IF_ERROR_RETURN 1824 (WRITE_PHY5421_TEST1r(unit, pc, 0x0080)); 1825 } else { 1826 return SOC_E_PARAM; 1827 } 1828 break; 1829 default: 1830 rv = SOC_E_UNAVAIL; 1831 } 1832 1833 if (rv == SOC_E_NONE) { 1834 pc->copper.mdix = mode; 1835 } 1836 1837 break; 1838 1839 default: 1840 if (mode != SOC_PORT_MDIX_NORMAL) { 1841 rv = SOC_E_UNAVAIL; 1842 } 1843 break; 1844 } 1845 1846 return (rv); 1847 } 1848 1849 /* 1850 * Function: 1851 * phy_5421S_mdix_get 1852 * Description: 1853 * Get the Auto-MDIX mode of a port/PHY 1854 * Parameters: 1855 * unit - Device number 1856 * port - Port number 1857 * mode - (Out) One of: 1858 * BCM_PORT_MDIX_AUTO 1859 * Enable auto-MDIX when autonegotiation is enabled 1860 * BCM_PORT_MDIX_FORCE_AUTO 1861 * Enable auto-MDIX always 1862 * BCM_PORT_MDIX_NORMAL 1863 * Disable auto-MDIX 1864 * BCM_PORT_MDIX_XOVER 1865 * Disable auto-MDIX, and swap cable pairs 1866 * Return Value: 1867 * SOC_E_UNAVAIL - feature unsupported by hardware 1868 * SOC_E_XXX - other error 1869 */ 1870 STATIC int 1871 phy_5421S_mdix_get(int unit, soc_port_t port, soc_port_mdix_t *mode) 1872 { 1873 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1874 1875 if (mode == NULL || pc == NULL) { 1876 return SOC_E_PARAM; 1877 } 1878 1879 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 1880 *mode = pc->copper.mdix; 1881 } else { 1882 *mode = SOC_PORT_MDIX_NORMAL; 1883 } 1884 1885 return SOC_E_NONE; 1886 } 1887 1888 /* 1889 * Function: 1890 * phy_5421S_mdix_status_get 1891 * Description: 1892 * Get the current MDIX status on a port/PHY 1893 * Parameters: 1894 * unit - Device number 1895 * port - Port number 1896 * status - (OUT) One of: 1897 * BCM_PORT_MDIX_STATUS_NORMAL 1898 * Straight connection 1899 * BCM_PORT_MDIX_STATUS_XOVER 1900 * Crossover has been performed 1901 * Return Value: 1902 * SOC_E_UNAVAIL - feature unsupported by hardware 1903 * SOC_E_XXX - other error 1904 */ 1905 STATIC int 1906 phy_5421S_mdix_status_get(int unit, soc_port_t port, 1907 soc_port_mdix_status_t *status) 1908 { 1909 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1910 uint16 tmp; 1911 1912 if (status == NULL || pc == NULL) { 1913 return SOC_E_PARAM; 1914 } 1915 1916 if (pc->medium == SOC_PORT_MEDIUM_COPPER) { 1917 SOC_IF_ERROR_RETURN 1918 (READ_PHY5421_MII_ESRr(unit, pc, &tmp)); 1919 if (tmp & 0x2000) { 1920 *status = SOC_PORT_MDIX_STATUS_XOVER; 1921 } else { 1922 *status = SOC_PORT_MDIX_STATUS_NORMAL; 1923 } 1924 } else { 1925 *status = SOC_PORT_MDIX_STATUS_NORMAL; 1926 } 1927 1928 return SOC_E_NONE; 1929 } 1930 1931 #if LINK_DOWN_RESET_WAR 1932 1933 /* 1934 * Function: 1935 * phy_5421S_link_down 1936 * Purpose: 1937 * Perform reset work-around on link down. 1938 * Parameters: 1939 * unit - StrataSwitch unit #. 1940 * port - StrataSwitch port #. 1941 * Returns: 1942 * SOC_E_XXX 1943 * Notes: 1944 * This work-around is necessary to ensure interoperability with 1945 * different PHYs. 1946 */ 1947 1948 STATIC int 1949 phy_5421S_link_down(int unit, soc_port_t port) 1950 { 1951 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1952 uint16 mii_ctrl, mii_gb_ctrl, mii_advert, mii_fiber; 1953 1954 DPRINTF((BSL_META_U(unit, 1955 "5421S_link_down: port=%d m=%d\n"), 1956 port, pc->medium)); 1957 1958 /* Only applies to copper link down */ 1959 1960 if (pc->medium != SOC_PORT_MEDIUM_COPPER) { 1961 return SOC_E_NONE; 1962 } 1963 1964 /* Save settings managed by the driver. */ 1965 SOC_IF_ERROR_RETURN 1966 (READ_PHY5421_MII_CTRLr(unit, pc, &mii_ctrl)); 1967 SOC_IF_ERROR_RETURN 1968 (READ_PHY5421_MII_ANAr(unit, pc, &mii_advert)); 1969 SOC_IF_ERROR_RETURN 1970 (READ_PHY5421_MII_GB_CTRLr(unit, pc, &mii_gb_ctrl)); 1971 SOC_IF_ERROR_RETURN 1972 (READ_PHY5421_SGMII_1000X_CTRLr(unit, pc, &mii_fiber)); 1973 1974 /* Perform normal reset and initialization. */ 1975 1976 SOC_IF_ERROR_RETURN(_phy_5421S_reset_setup(unit, port)); 1977 1978 /* Restore settings managed by the driver. */ 1979 SOC_IF_ERROR_RETURN 1980 (WRITE_PHY5421_MII_CTRLr(unit, pc, mii_ctrl)); 1981 SOC_IF_ERROR_RETURN 1982 (WRITE_PHY5421_MII_ANAr(unit, pc, mii_advert)); 1983 SOC_IF_ERROR_RETURN 1984 (WRITE_PHY5421_MII_GB_CTRLr(unit, pc, mii_gb_ctrl)); 1985 SOC_IF_ERROR_RETURN 1986 (WRITE_PHY5421_SGMII_1000X_CTRLr(unit, pc, mii_fiber)); 1987 1988 return SOC_E_NONE; 1989 } 1990 1991 #else 1992 #define phy_5421S_link_down NULL 1993 #endif /* LINK_DOWN_RESET_WAR */ 1994 1995 #ifdef BROADCOM_DEBUG 1996 1997 /* 1998 * Function: 1999 * phy_5421S_shadow_dump 2000 * Purpose: 2001 * Debug routine to dump all shadow registers. 2002 * Parameters: 2003 * unit - StrataSwitch unit #. 2004 * port - StrataSwitch port #. 2005 */ 2006 2007 void 2008 phy_5421S_shadow_dump(int unit, soc_port_t port) 2009 { 2010 uint16 tmp; 2011 phy_ctrl_t *pc; 2012 2013 pc = EXT_PHY_SW_STATE(unit, port); 2014 /* Hideous Register 0x18 */ 2015 2016 WRITE_PHY_REG(unit, pc, 0x18, 0x0007); 2017 READ_PHY_REG(unit, pc, 0x18, &tmp); 2018 LOG_CLI((BSL_META_U(unit, 2019 "0x18[000]=0x%04x\n"), tmp)); 2020 WRITE_PHY_REG(unit, pc, 0x18, 0x1007); 2021 READ_PHY_REG(unit, pc, 0x18, &tmp); 2022 LOG_CLI((BSL_META_U(unit, 2023 "0x18[001]=0x%04x\n"), tmp)); 2024 WRITE_PHY_REG(unit, pc, 0x18, 0x2007); 2025 READ_PHY_REG(unit, pc, 0x18, &tmp); 2026 LOG_CLI((BSL_META_U(unit, 2027 "0x18[010]=0x%04x\n"), tmp)); 2028 WRITE_PHY_REG(unit, pc, 0x18, 0x4007); 2029 READ_PHY_REG(unit, pc, 0x18, &tmp); 2030 LOG_CLI((BSL_META_U(unit, 2031 "0x18[100]=0x%04x\n"), tmp)); 2032 WRITE_PHY_REG(unit, pc, 0x18, 0x7007); 2033 READ_PHY_REG(unit, pc, 0x18, &tmp); 2034 LOG_CLI((BSL_META_U(unit, 2035 "0x18[111]=0x%04x\n"), tmp)); 2036 2037 /* Hideous Register 0x1c */ 2038 2039 WRITE_PHY_REG(unit, pc, 0x1c, 0x0800); 2040 READ_PHY_REG(unit, pc, 0x1c, &tmp); 2041 LOG_CLI((BSL_META_U(unit, 2042 "0x1c[00010]=0x%04x\n"), tmp)); 2043 WRITE_PHY_REG(unit, pc, 0x1c, 0x1000); 2044 READ_PHY_REG(unit, pc, 0x1c, &tmp); 2045 LOG_CLI((BSL_META_U(unit, 2046 "0x1c[00100]=0x%04x\n"), tmp)); 2047 WRITE_PHY_REG(unit, pc, 0x1c, 0x1400); 2048 READ_PHY_REG(unit, pc, 0x1c, &tmp); 2049 LOG_CLI((BSL_META_U(unit, 2050 "0x1c[00101]=0x%04x\n"), tmp)); 2051 WRITE_PHY_REG(unit, pc, 0x1c, 0x2000); 2052 READ_PHY_REG(unit, pc, 0x1c, &tmp); 2053 LOG_CLI((BSL_META_U(unit, 2054 "0x1c[01000]=0x%04x\n"), tmp)); 2055 WRITE_PHY_REG(unit, pc, 0x1c, 0x2400); 2056 READ_PHY_REG(unit, pc, 0x1c, &tmp); 2057 LOG_CLI((BSL_META_U(unit, 2058 "0x1c[01001]=0x%04x\n"), tmp)); 2059 WRITE_PHY_REG(unit, pc, 0x1c, 0x2800); 2060 READ_PHY_REG(unit, pc, 0x1c, &tmp); 2061 LOG_CLI((BSL_META_U(unit, 2062 "0x1c[01010]=0x%04x\n"), tmp)); 2063 WRITE_PHY_REG(unit, pc, 0x1c, 0x7c00); 2064 READ_PHY_REG(unit, pc, 0x1c, &tmp); 2065 LOG_CLI((BSL_META_U(unit, 2066 "0x1c[11111]=0x%04x\n"), tmp)); 2067 } 2068 2069 #endif /* BROADCOM_DEBUG */ 2070 2071 2072 2073 2074 /* 2075 * Variable: phy_5421Sdrv_ge 2076 * Purpose: PHY driver for 5421S 2077 */ 2078 phy_driver_t phy_5421Sdrv_ge = { 2079 "5421S Gigabit PHY Driver", 2080 phy_5421S_init, 2081 phy_fe_ge_reset, 2082 phy_5421S_link_get, 2083 phy_5421S_enable_set, 2084 phy_5421S_enable_get, 2085 phy_5421S_duplex_set, 2086 phy_5421S_duplex_get, 2087 phy_5421S_speed_set, 2088 phy_5421S_speed_get, 2089 phy_5421S_master_set, 2090 phy_5421S_master_get, 2091 phy_5421S_autoneg_set, 2092 phy_5421S_autoneg_get, 2093 phy_5421S_adv_local_set, 2094 phy_5421S_adv_local_get, 2095 phy_5421S_adv_remote_get, 2096 phy_5421S_lb_set, 2097 phy_5421S_lb_get, 2098 phy_5421S_interface_set, 2099 phy_5421S_interface_get, 2100 phy_5421S_ability_get, 2101 NULL, /* Link up event */ 2102 phy_5421S_link_down, 2103 phy_5421S_mdix_set, 2104 phy_5421S_mdix_get, 2105 phy_5421S_mdix_status_get, 2106 phy_5421S_medium_config_set, 2107 phy_5421S_medium_config_get, 2108 phy_5421S_medium_status, 2109 NULL, /* phy_cable_diag */ 2110 NULL, /* phy_link_change */ 2111 NULL, /* phy_control_set */ 2112 NULL, /* phy_control_get */ 2113 phy_ge_reg_read, 2114 phy_ge_reg_write, 2115 phy_ge_reg_modify, 2116 NULL /* Phy event notify */ 2117 }; 2118 2119 #endif /* INCLUDE_PHY_5421S */ 2120 2121 int _soc_phy_5421S_not_empty;