phy54684.c (83764B)
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: phy54684.c 8 * Purpose: PHY driver for BCM54684 9 * 10 * Supported BCM546X Family of PHY devices: 11 * 12 * Device Ports Media MAC Interface 13 * 54684 8 Copper, Serdes SGMII 14 * 15 * Workarounds: 16 * 17 * References: 18 * 54684-DS00-RDS.pdf BCM54684 Data Sheet 19 * MCS54684-ES100-RDS.pdf Octal 1000/100/10BASE-T Gigabit Ethernet Transceiver 20 * 21 * +----------+ +---------------------------+ 22 * | | | +->Copper |<--> Magnetic 23 * | SGMII |<->| SGMII <-+ | 24 * | (SerDes) | | | | 25 * | | | +->SGMII/ |<--> (PHY)SFP (10/100/1000) 26 * +----------+ | 1000BASE-X/ |<--> 1000BASE-X SFP 27 * MAC | 100BASE-FX |<--> 100BASE-FX SFP 28 * | | 29 * | | 30 * +---------------------------+ 31 * 54684 32 * 33 * Notes: 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_PHY_54684) 51 #include "phyconfig.h" /* Must be the first phy include after phydefs.h */ 52 #include "phyident.h" 53 #include "phyreg.h" 54 #include "phyfege.h" 55 #include "phy54684.h" 56 57 #define AUTO_MDIX_WHEN_AN_DIS 0 /* Non-standard-compliant option */ 58 #define WORKAROUND_FIX 1 59 60 #define ADVERT_ALL_COPPER \ 61 (SOC_PM_PAUSE | SOC_PM_10MB | SOC_PM_100MB | SOC_PM_1000MB) 62 #define ADVERT_ALL_FIBER \ 63 (SOC_PM_PAUSE | SOC_PM_1000MB_FD) 64 65 STATIC int _phy_54684_no_reset_setup(int unit, soc_port_t port); 66 STATIC int _phy_54684_medium_change(int unit, soc_port_t port, int force_update); 67 STATIC int phy_54684_duplex_set(int unit, soc_port_t port, int duplex); 68 STATIC int phy_54684_speed_set(int unit, soc_port_t port, int speed); 69 STATIC int phy_54684_master_set(int unit, soc_port_t port, int master); 70 STATIC int phy_54684_adv_local_set(int unit, soc_port_t port, 71 soc_port_mode_t mode); 72 STATIC int phy_54684_autoneg_set(int unit, soc_port_t port, int autoneg); 73 STATIC int phy_54684_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode); 74 STATIC int phy_54684_speed_get(int unit, soc_port_t port, int *speed); 75 76 /*********************************************************************** 77 * 78 * HELPER FUNCTIONS 79 */ 80 /* 81 * Function: 82 * _phy_54684_medium_check 83 * Purpose: 84 * Determine if chip should operate in copper or fiber mode. 85 * Parameters: 86 * unit - StrataSwitch unit #. 87 * port - StrataSwitch port #. 88 * medium - (OUT) SOC_PORT_MEDIUM_XXX 89 * Returns: 90 * SOC_E_XXX 91 */ 92 STATIC int 93 _phy_54684_medium_check(int unit, soc_port_t port, int *medium) 94 { 95 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 96 uint16 tmp = 0xffff; 97 98 *medium = SOC_PORT_MEDIUM_COPPER; 99 100 if (pc->automedium) { 101 /* Read Mode Register (0x1c shadow 11111) */ 102 SOC_IF_ERROR_RETURN 103 (READ_PHY54684_MODE_CTRLr(unit, pc, &tmp)); 104 105 if (pc->fiber.preferred) { 106 /* 0x10 Fiber Signal Detect 107 * 0x20 Copper Energy Detect 108 */ 109 if ((tmp & 0x30) == 0x20) { 110 /* Only copper is link up */ 111 *medium = SOC_PORT_MEDIUM_COPPER; 112 } else { 113 *medium = SOC_PORT_MEDIUM_FIBER; 114 } 115 } else { 116 if ((tmp & 0x30) == 0x10) { 117 /* Only fiber is link up */ 118 *medium = SOC_PORT_MEDIUM_FIBER; 119 } else { 120 *medium = SOC_PORT_MEDIUM_COPPER; 121 } 122 } 123 } else { 124 *medium = pc->fiber.preferred ? SOC_PORT_MEDIUM_FIBER: 125 SOC_PORT_MEDIUM_COPPER; 126 } 127 128 LOG_VERBOSE(BSL_LS_SOC_PHY, 129 (BSL_META_U(unit, 130 "_phy_54684_medium_check: " 131 "u=%d p=%d fiber_pref=%d 0x1c(11111)=%04x fiber=%d\n"), 132 unit, port, pc->fiber.preferred, tmp, 133 (*medium == SOC_PORT_MEDIUM_FIBER) ? 1 : 0)); 134 135 return SOC_E_NONE; 136 } 137 138 /* 139 * Function: 140 * phy_54684_medium_status 141 * Purpose: 142 * Indicate the current active medium 143 * Parameters: 144 * unit - StrataSwitch unit #. 145 * port - StrataSwitch port #. 146 * medium - (OUT) One of: 147 * SOC_PORT_MEDIUM_COPPER 148 * SOC_PORT_MEDIUM_FIBER 149 * Returns: 150 * SOC_E_NONE 151 */ 152 153 STATIC int 154 phy_54684_medium_status(int unit, soc_port_t port, soc_port_medium_t *medium) 155 { 156 if (PHY_COPPER_MODE(unit, port)) { 157 *medium = SOC_PORT_MEDIUM_COPPER; 158 } else { 159 *medium = SOC_PORT_MEDIUM_FIBER; 160 } 161 return SOC_E_NONE; 162 } 163 164 /* 165 * Function: 166 * _phy_54684_medium_config_update 167 * Purpose: 168 * Update the PHY with config parameters 169 * Parameters: 170 * unit - StrataSwitch unit #. 171 * port - StrataSwitch port #. 172 * cfg - Config structure. 173 * Returns: 174 * SOC_E_XXX 175 */ 176 177 STATIC int 178 _phy_54684_medium_config_update(int unit, soc_port_t port, 179 soc_phy_config_t *cfg) 180 { 181 SOC_IF_ERROR_RETURN 182 (phy_54684_speed_set(unit, port, cfg->force_speed)); 183 SOC_IF_ERROR_RETURN 184 (phy_54684_duplex_set(unit, port, cfg->force_duplex)); 185 SOC_IF_ERROR_RETURN 186 (phy_54684_master_set(unit, port, cfg->master)); 187 SOC_IF_ERROR_RETURN 188 (phy_54684_adv_local_set(unit, port, cfg->autoneg_advert)); 189 SOC_IF_ERROR_RETURN 190 (phy_54684_autoneg_set(unit, port, cfg->autoneg_enable)); 191 SOC_IF_ERROR_RETURN 192 (phy_54684_mdix_set(unit, port, cfg->mdix)); 193 194 return SOC_E_NONE; 195 } 196 197 /*********************************************************************** 198 * 199 * PHY54684 DRIVER ROUTINES 200 */ 201 202 /* 203 * Function: 204 * phy_54684_medium_config_set 205 * Purpose: 206 * Set the operating parameters that are automatically selected 207 * when medium switches type. 208 * Parameters: 209 * unit - StrataSwitch unit # 210 * port - Port number 211 * medium - SOC_PORT_MEDIUM_COPPER/FIBER 212 * cfg - Operating parameters 213 * Returns: 214 * SOC_E_XXX 215 */ 216 217 STATIC int 218 phy_54684_medium_config_set(int unit, soc_port_t port, 219 soc_port_medium_t medium, 220 soc_phy_config_t *cfg) 221 { 222 phy_ctrl_t *pc; 223 soc_phy_config_t *active_medium; /* Currently active medium */ 224 soc_phy_config_t *change_medium; /* Requested medium */ 225 soc_phy_config_t *other_medium; /* The other medium */ 226 int medium_update; 227 soc_port_mode_t advert_mask; 228 229 if (NULL == cfg) { 230 return SOC_E_PARAM; 231 } 232 233 pc = EXT_PHY_SW_STATE(unit, port); 234 medium_update = FALSE; 235 236 switch (medium) { 237 case SOC_PORT_MEDIUM_COPPER: 238 if (!pc->automedium) { 239 if (!PHY_COPPER_MODE(unit, port)) { 240 return SOC_E_UNAVAIL; 241 } 242 /* check if device is fiber capable before switching */ 243 if (cfg->preferred == 0) { 244 uint16 data; 245 246 SOC_IF_ERROR_RETURN 247 (READ_PHY54684_MODE_CTRLr(unit, pc, &data)); 248 249 /* return if not fiber capable*/ 250 if (!(data & 0x8)) { 251 return SOC_E_UNAVAIL; 252 } 253 } 254 } 255 256 change_medium = &pc->copper; 257 other_medium = &pc->fiber; 258 advert_mask = ADVERT_ALL_COPPER; 259 break; 260 case SOC_PORT_MEDIUM_FIBER: 261 if (!pc->automedium && !PHY_FIBER_MODE(unit, port)) { 262 return SOC_E_UNAVAIL; 263 } 264 change_medium = &pc->fiber; 265 other_medium = &pc->copper; 266 advert_mask = ADVERT_ALL_FIBER; 267 break; 268 default: 269 return SOC_E_PARAM; 270 } 271 272 /* 273 * Changes take effect immediately if the target medium is active or 274 * the preferred medium changes. 275 */ 276 if (change_medium->enable != cfg->enable) { 277 medium_update = TRUE; 278 } 279 if (change_medium->preferred != cfg->preferred) { 280 /* Make sure that only one medium is preferred */ 281 other_medium->preferred = !cfg->preferred; 282 medium_update = TRUE; 283 } 284 285 sal_memcpy(change_medium, cfg, sizeof(*change_medium)); 286 change_medium->autoneg_advert &= advert_mask; 287 288 if (medium_update) { 289 /* The new configuration may cause medium change. Check 290 * and update medium. 291 */ 292 SOC_IF_ERROR_RETURN 293 (_phy_54684_medium_change(unit, port, TRUE)); 294 } else { 295 active_medium = (PHY_COPPER_MODE(unit, port)) ? 296 &pc->copper : &pc->fiber; 297 if (active_medium == change_medium) { 298 /* If the medium to update is active, update the configuration */ 299 SOC_IF_ERROR_RETURN 300 (_phy_54684_medium_config_update(unit, port, change_medium)); 301 } 302 } 303 return SOC_E_NONE; 304 } 305 306 /* 307 * Function: 308 * phy_54684_medium_config_get 309 * Purpose: 310 * Get the operating parameters that are automatically selected 311 * when medium switches type. 312 * Parameters: 313 * unit - StrataSwitch unit # 314 * port - Port number 315 * medium - SOC_PORT_MEDIUM_COPPER/FIBER 316 * cfg - (OUT) Operating parameters 317 * Returns: 318 * SOC_E_XXX 319 */ 320 321 STATIC int 322 phy_54684_medium_config_get(int unit, soc_port_t port, 323 soc_port_medium_t medium, 324 soc_phy_config_t *cfg) 325 { 326 int rv; 327 phy_ctrl_t *pc; 328 329 pc = EXT_PHY_SW_STATE(unit, port); 330 rv = SOC_E_NONE; 331 332 switch (medium) { 333 case SOC_PORT_MEDIUM_COPPER: 334 if (pc->automedium || PHY_COPPER_MODE(unit, port)) { 335 sal_memcpy(cfg, &pc->copper, sizeof (*cfg)); 336 } else { 337 rv = SOC_E_UNAVAIL; 338 } 339 break; 340 case SOC_PORT_MEDIUM_FIBER: 341 if (pc->automedium || PHY_FIBER_MODE(unit, port)) { 342 sal_memcpy(cfg, &pc->fiber, sizeof (*cfg)); 343 } else { 344 rv = SOC_E_UNAVAIL; 345 } 346 break; 347 default: 348 rv = SOC_E_PARAM; 349 break; 350 } 351 352 return rv; 353 } 354 355 /* 356 * Function: 357 * _phy_54684_reset_setup 358 * Purpose: 359 * Function to reset the PHY and set up initial operating registers. 360 * Parameters: 361 * unit - StrataSwitch unit #. 362 * port - StrataSwitch port #. 363 * Returns: 364 * SOC_E_XXX 365 * Notes: 366 * Configures for copper/fiber according to the current 367 * setting of PHY_FLAGS_FIBER. 368 */ 369 370 STATIC int 371 _phy_54684_reset_setup(int unit, soc_port_t port) 372 { 373 374 phy_ctrl_t *pc; 375 soc_port_t primary_port; 376 int index; 377 378 pc = EXT_PHY_SW_STATE(unit, port); 379 380 if (soc_phy_primary_and_offset_get(unit, port, &primary_port, &index) == SOC_E_NONE) { 381 pc->lane_num = index; 382 } 383 384 /* Reset the PHY with previously registered callback function. 385 */ 386 SOC_IF_ERROR_RETURN(soc_phy_reset(unit, port)); 387 388 /* Disable super-isolate */ 389 SOC_IF_ERROR_RETURN 390 (MODIFY_PHY54684_MII_POWER_CTRLr(unit, pc, 0x0, 1U<<5)); 391 392 SOC_IF_ERROR_RETURN 393 (_phy_54684_no_reset_setup(unit, port)); 394 395 return SOC_E_NONE; 396 } 397 398 STATIC int 399 _phy_54684_no_reset_setup(int unit, soc_port_t port) 400 { 401 phy_ctrl_t *int_pc; 402 phy_ctrl_t *pc; 403 uint16 data, mask; 404 405 LOG_INFO(BSL_LS_SOC_PHY, 406 (BSL_META_U(unit, 407 "_phy_54684_reset_setup: u=%d p=%d medium=%s\n"), 408 unit, port, 409 PHY_COPPER_MODE(unit, port) ? "COPPER" : "FIBER")); 410 411 pc = EXT_PHY_SW_STATE(unit, port); 412 int_pc = INT_PHY_SW_STATE(unit, port); 413 414 /* 415 * Workaround for BCM54684 B0 chip 416 * (not necessary for B1 and C0 chip) 417 * Description: BCM54684 defaults into the SGMII/QSGMII-to-copper split 418 * mode after reset. The BCM54684 device mode should default into the 419 * QSMII-to-Copper mode after reset. 420 */ 421 if(PHY_REVISION_CHECK(pc, PHY_BCM54684_MODEL, PHY_BCM54684_OUI, 0x0)) { 422 SOC_IF_ERROR_RETURN 423 (MODIFY_PHY54684_MODE_CTRLr(unit, pc, 0x0000, 0x0006)); 424 } 425 426 /* 427 * Workaround for BCM54684 B0 chip 428 * Description: disable signal detect from pin to make fiber mode work 429 */ 430 if(PHY_REVISION_CHECK(pc, PHY_BCM54684_MODEL, PHY_BCM54684_OUI, 0x0)) { 431 SOC_IF_ERROR_RETURN 432 (MODIFY_PHY54684_MISC_1000X_CONTROLr(unit, pc, 0x0000, 0x0020)); 433 } 434 435 /* SGMII interface to MAC */ 436 /* soc_phy_reset has reset the phy, powering down the unstrapped interface. 437 * Make sure enabled interfaces are powered up. 438 */ 439 SOC_IF_ERROR_RETURN 440 (MODIFY_PHY54684_1000X_MII_CTRLr(unit, pc, 0, MII_CTRL_PD)); 441 442 /* 1000Base-X FullDuplex will be clear after the phy been 443 * reset in phy54684 444 */ 445 data = MII_CTRL_FD | MII_CTRL_SS_1000 | MII_CTRL_RAN | MII_CTRL_AE; 446 447 SOC_IF_ERROR_RETURN 448 (WRITE_PHY54684_1000X_MII_CTRLr(unit, pc, data)); 449 450 /* copper regs */ 451 if (!pc->copper.enable || (!pc->automedium && pc->fiber.preferred)) { 452 /* Copper interface is not used. Powered down. */ 453 SOC_IF_ERROR_RETURN 454 (MODIFY_PHY54684_MII_CTRLr(unit, pc, MII_CTRL_PD, MII_CTRL_PD)); 455 } else { 456 SOC_IF_ERROR_RETURN 457 (MODIFY_PHY54684_MII_CTRLr(unit, pc, 0, MII_CTRL_PD)); 458 SOC_IF_ERROR_RETURN 459 (WRITE_PHY54684_MII_GB_CTRLr(unit, pc, 460 MII_GB_CTRL_ADV_1000FD | MII_GB_CTRL_PT)); 461 SOC_IF_ERROR_RETURN 462 (WRITE_PHY54684_MII_CTRLr(unit, pc, 463 MII_CTRL_FD | MII_CTRL_SS_10 | 464 MII_CTRL_SS_100 | MII_CTRL_AE)); 465 } 466 467 /* Adjust timing and enable link speed led mode */ 468 SOC_IF_ERROR_RETURN 469 (MODIFY_PHY54684_SPARE_CTRLr(unit, pc, 0x0006, 0x0006)); 470 471 if (NULL != int_pc) { 472 SOC_IF_ERROR_RETURN 473 (PHY_INIT(int_pc->pd, unit, port)); 474 475 if (PHY_FIBER_MODE(unit, port)) { 476 /* Interface to MAC or internal SerDes is always SGMII mode. 477 * Typical internal SerDes driver set the interface to 1000BASE-X, 478 * if the media is fiber. Therefore, we need to force the interface 479 * of internal SerDes Driver to SGMII. */ 480 SOC_IF_ERROR_RETURN 481 (PHY_NOTIFY(int_pc->pd, unit, port, phyEventInterface, 482 SOC_PORT_IF_SGMII)); 483 } 484 485 if (PHY_COPPER_MODE(unit, port) && 486 !PHY_SGMII_AUTONEG_MODE(unit, port)) { 487 /* Make sure internal SerDes is in power down state 488 * until the MAC is ready. */ 489 SOC_IF_ERROR_RETURN 490 (PHY_NOTIFY(int_pc->pd, unit, port, 491 phyEventStop, PHY_STOP_COPPER)); 492 } 493 } 494 495 /* Power down SerDes */ 496 SOC_IF_ERROR_RETURN 497 (MODIFY_PHY54684_1000X_MII_CTRLr(unit, pc, MII_CTRL_PD, 498 MII_CTRL_PD)); 499 500 if (pc->fiber.enable && (pc->automedium || pc->fiber.preferred)) { 501 /* remove power down of SerDes */ 502 SOC_IF_ERROR_RETURN 503 (MODIFY_PHY54684_1000X_MII_CTRLr(unit, pc, 0, MII_CTRL_PD)); 504 505 /* set the advertisement of serdes */ 506 /* Disable half-duplex, full-duplex capable */ 507 SOC_IF_ERROR_RETURN 508 (MODIFY_PHY54684_1000X_MII_ANAr(unit, pc, (1 << 5), 509 (1 << 5) | (1 << 6))); 510 511 /* Enable auto-detection between SGMII-slave and 1000BASE-X */ 512 SOC_IF_ERROR_RETURN 513 (MODIFY_PHY54684_SGMII_SLAVEr(unit, pc, 1, 1)); 514 515 /* Restart SerDes autonegotiation */ 516 SOC_IF_ERROR_RETURN 517 (WRITE_PHY54684_1000X_MII_CTRLr(unit, pc, 518 MII_CTRL_FD | MII_CTRL_SS_1000 | MII_CTRL_AE)); 519 520 switch (pc->fiber_detect) { 521 case 2: /* LED 2 */ 522 case -2: 523 case 4: /* LED 4 : kept for backward compatibility */ 524 case -4: 525 case 10: /* EN_10B for signal detect */ 526 case -10: 527 case 0: /* default */ 528 /* GPIO Control/Status Register (0x1c shadow 01111) */ 529 /* Change LED2 pin into an input */ 530 SOC_IF_ERROR_RETURN 531 (MODIFY_PHY54684_LED_GPIO_CTRLr(unit, pc, 0x08, 0x08)); 532 break; 533 case 1: /* PECL , no such pin in 54684 data sheet */ 534 case -1: 535 default: 536 return SOC_E_CONFIG; 537 } 538 SOC_IF_ERROR_RETURN 539 (MODIFY_PHY54684_MODE_CTRLr(unit, pc, 0x0002, 0x0006)); 540 } 541 542 /* Configure Auto-detect Medium (0x1c shadow 11110) */ 543 mask = 0x33f; /* Auto-detect bit mask */ 544 data = 0; 545 if (pc->automedium) { 546 data |= 1 << 0; /* Enable auto-detect medium */ 547 } 548 /* When no link partner exists, fiber should be default medium */ 549 /* When both link partners exipc, fiber should be prefered medium 550 * for the following reasons. 551 * 1. Most fiber module generates signal detect when the fiber cable is 552 * plugged in regardless of any activity even if the link partner is 553 * powered down. 554 * 2. Fiber mode consume much lesser power than copper mode. 555 */ 556 if (pc->fiber.preferred) { 557 data |= 1 << 1; /* Fiber selected when both media are active */ 558 data |= 1 << 2; /* Fiber selected when no medium is active */ 559 } 560 561 /* 562 * Enable internal inversion of LED2/SD input pin. Used only if 563 * the fiber module provides RX_LOS instead of Signal Detect. 564 */ 565 if (pc->fiber_detect < 0) { 566 data |= 1 << 8; /* Fiber signal detect is active low from pin */ 567 } 568 SOC_IF_ERROR_RETURN 569 (MODIFY_PHY54684_AUTO_DETECT_MEDIUMr(unit, pc, data, mask)); 570 571 #if AUTO_MDIX_WHEN_AN_DIS 572 /* Enable Auto-MDIX When autoneg disabled */ 573 SOC_IF_ERROR_RETURN 574 (MODIFY_PHY54684_MII_MISC_CTRLr(unit, pc, 0x200, 0x200)); 575 #endif 576 577 /* 578 * Configure 1000X control2 register (0x8301 Bit[7] = 1) to turn off 579 * carrier extension. The Intel 7131 NIC does not accept carrier 580 * extension and gets CRC errors. 581 */ 582 if(pc->lane_num == 0){ 583 /* The phy address of QSGMII is the phy address pins + 8 */ 584 pc->phy_id = pc->phy_id + 8; 585 SOC_IF_ERROR_RETURN 586 (PHY54684_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS, 587 0x0000, 0x1f, 0xffd0)); 588 SOC_IF_ERROR_RETURN 589 (PHY54684_REG_WRITE(unit, pc, 0x00, 0x0000, 0x1e, 0x1f)); 590 SOC_IF_ERROR_RETURN 591 (PHY54684_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS, 592 0x0000, 0x1f, 0x8300)); 593 SOC_IF_ERROR_RETURN 594 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x11, 0x0080, 0x0080)); 595 596 /* Revert the phy_id */ 597 pc->phy_id = pc->phy_id - 8; 598 } 599 600 /* Configure extended control register for led mode and jumbo frame support 601 */ 602 mask = (1 << 5) | (1 << 0); 603 604 /* if using led link/activity mode, disable led traffic mode */ 605 if (pc->ledctrl & 0x10 || pc->ledselect == 0x01) { 606 data = 0; 607 } else { 608 data = 1 << 5; /* Enable LEDs to indicate traffic status */ 609 } 610 /* Configure Extended Control Register for Jumbo frames support */ 611 data |= 1 << 0; /* Set high FIFO elasticity to support jumbo frames */ 612 SOC_IF_ERROR_RETURN 613 (MODIFY_PHY54684_MII_ECRr(unit, pc, data, mask)); 614 615 /* Enable extended packet length (4.5k through 25k) */ 616 SOC_IF_ERROR_RETURN 617 (MODIFY_PHY54684_MII_AUX_CTRLr(unit, pc, 0x4000, 0x4000)); 618 619 /* Configure LED selectors */ 620 data = ((pc->ledmode[1] & 0xf) << 4) | (pc->ledmode[0] & 0xf); 621 SOC_IF_ERROR_RETURN 622 (WRITE_PHY54684_LED_SELECTOR_1r(unit, pc, data)); 623 624 data = ((pc->ledmode[3] & 0xf) << 4) | (pc->ledmode[2] & 0xf); 625 SOC_IF_ERROR_RETURN 626 (WRITE_PHY54684_LED_SELECTOR_2r(unit, pc, data)); 627 628 data = (pc->ledctrl & 0x3ff); 629 SOC_IF_ERROR_RETURN 630 (WRITE_PHY54684_LED_CTRLr(unit, pc, data)); 631 632 SOC_IF_ERROR_RETURN 633 (WRITE_PHY54684_EXP_LED_SELECTORr(unit, pc, pc->ledselect)); 634 635 #ifdef BCM_HURRICANE1_SUPPORT 636 637 if (SOC_IS_HURRICANE(unit)) 638 { 639 if (!pc->fiber.preferred) 640 { 641 /* LED initialization sequence for Hurricane*/ 642 /* Disable current LED mode. Write 1s to bits[3:0] of 643 GPIO control register (reg 1Ch, Shadow Fh).*/ 644 SOC_IF_ERROR_RETURN 645 (MODIFY_PHY54684_LED_GPIO_CTRLr(unit, pc, 0xbc0f, 0xbc0f)); 646 /* Enable multimode LED mode. Write AAh to bits[7:0] of 647 LED selectro register (reg 1Ch, Shadow Dh). */ 648 SOC_IF_ERROR_RETURN 649 (MODIFY_PHY54684_LED_SELECTOR_1r(unit, pc, 0xb4aa, 0xb4aa)); 650 SOC_IF_ERROR_RETURN 651 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x17, 0x0f04, 0x0f04)); 652 SOC_IF_ERROR_RETURN 653 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x15, 0x0128, 0x0128)); 654 655 } 656 } 657 #endif 658 659 #if WORKAROUND_FIX 660 if(PHY_REVISION_CHECK(pc, PHY_BCM54684_MODEL, PHY_BCM54684_OUI, 0x0)) { 661 /* 662 * Workaround for BCM54684 B0 chip 663 * (not necessary for B1 and C0 chip) 664 * Description Device does not initialized to correct value. 665 * Workaround The following script code should run to 666 * initialize the device after reset before normal operation. 667 * Step 1) Perform the following write operations for 668 * port 1 through port 8 669 * Write register 18h = 0C00h 670 * Write register 17h = 001fh 671 * Write register 15h = 0300h 672 * Write register 17h = 0601fh 673 * Write register 15h = 0002h 674 * Write register 17h = 0f75h 675 * Write register 15h = 0028h 676 * Step 2) Perform the following write operations to port 4 only 677 * Write register 1C = AC60h 678 * Write register 1C = 0002h 679 * Step 3) Perform the following write operations to port 3 only 680 * Write register 1C = AC5Eh 681 * Step 4) Perform the following write operations to port 8 only 682 * Write register 1Ch = AC60h 683 * Write register 1Ch = B012h 684 * Step 5) Perform the following write operations to port 7 only 685 * Write register 1Ch = AC5Eh 686 */ 687 688 /* Step 1 */ 689 SOC_IF_ERROR_RETURN 690 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x18, 691 0x0C00, 0x0C00)); 692 SOC_IF_ERROR_RETURN 693 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x17, 694 0x001F, 0x001F)); 695 SOC_IF_ERROR_RETURN 696 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x15, 697 0x0300, 0x0300)); 698 SOC_IF_ERROR_RETURN 699 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x17, 700 0x601F, 0x601F)); 701 SOC_IF_ERROR_RETURN 702 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x15, 703 0x0002, 0x0002)); 704 SOC_IF_ERROR_RETURN 705 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x17, 706 0x0F75, 0x0F75)); 707 SOC_IF_ERROR_RETURN 708 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x15, 709 0x0028, 0x0028)); 710 711 if(pc->lane_num == 3) { 712 /* Step 2 */ 713 SOC_IF_ERROR_RETURN 714 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x000B, 0x1C, 715 0x0060, 0x0060)); 716 SOC_IF_ERROR_RETURN 717 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x1C, 718 0x0002, 0x0002)); 719 } 720 721 if(pc->lane_num == 2) { 722 /* Step 3 */ 723 SOC_IF_ERROR_RETURN 724 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x000B, 0x1C, 725 0x005E, 0x005E)); 726 } 727 728 if(pc->lane_num == 7) { 729 /* Step 4 */ 730 SOC_IF_ERROR_RETURN 731 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x000B, 0x1C, 732 0x0060, 0x0060)); 733 SOC_IF_ERROR_RETURN 734 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x000C, 0x1C, 735 0x0012, 0x0012)); 736 } 737 738 if(pc->lane_num == 6) { 739 /* Step 5 */ 740 SOC_IF_ERROR_RETURN 741 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x000B, 0x1C, 742 0x005E, 0x005E)); 743 } 744 } 745 746 if(PHY_REVISION_CHECK(pc, PHY_BCM54684_MODEL, PHY_BCM54684_OUI, 0x1)) { 747 /* 748 * Apply workaround for BCM54684 C0. 749 * Perform the following writes to power up the dual 1.25 Gig SerDes. 750 */ 751 if((pc->lane_num == 6) || (pc->lane_num == 7)){ 752 SOC_IF_ERROR_RETURN 753 (MODIFY_PHY54684_EXP_SERDES_SGMII_RX_CTRLr(unit, pc, 0x0, 0x1)); 754 SOC_IF_ERROR_RETURN 755 (MODIFY_PHY54684_EXP_SERDES_SGMII_CTRLr(unit, pc, 0x0, 0x1)); 756 } 757 if(pc->lane_num == 4) { 758 SOC_IF_ERROR_RETURN 759 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x0f55, 0x15, 0x0, 0x1)); 760 } 761 } 762 763 if(PHY_REVISION_CHECK(pc, PHY_BCM54684_MODEL, PHY_BCM54684_OUI, 0x0)) { 764 /* Workaround for BCM54684 B0 chip : 765 Operate at -20% TX-bias current versus the +20% setting. 766 This will drop the power by 40 mW/port but use shorter cable < 100m. 767 How to reduce tx bias current to 20% : 768 Perform a modify to VDACCTRL<7:0> of Expansion Register 0x75 769 Set the VDACCTRL<7:0>="00010100" to get -20% TX */ 770 SOC_IF_ERROR_RETURN 771 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x0f75, 0x15, 0x14, 0xff)); 772 } 773 774 if(PHY_REVISION_CHECK(pc, PHY_BCM54684_MODEL, PHY_BCM54684_OUI, 0x2)) { 775 /* For bcm54684_D0 only. 776 * 777 * Workaround for two tests: 778 * 1. IEEE symmetry test 779 * 2. EMI test 780 */ 781 SOC_IF_ERROR_RETURN 782 (PHY54684_REG_WRITE(unit, pc, 0x00, 0x0f76, 0x15, 0x100)); 783 SOC_IF_ERROR_RETURN 784 (PHY54684_REG_WRITE(unit, pc, 0x00, 0x0f75, 0x15, 0x29)); 785 SOC_IF_ERROR_RETURN 786 (PHY54684_REG_WRITE(unit, pc, 0x00, 0x0f74, 0x15, 0xd087)); 787 SOC_IF_ERROR_RETURN 788 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x18, 0x0800, 0x0800)); 789 SOC_IF_ERROR_RETURN 790 (PHY54684_REG_WRITE(unit, pc, 0x00, 0x601f, 0x15, 0x0110)); 791 792 /* Issue for bcm54684_D0: Unstable link issue with Marvell PHY 793 * Workaroud (PHY team confirmed workaround has been identified) : 794 * Set Exp register 0x08.bit[9]=0. 795 * (BIT9 is AUTO EARLY DAC WAKE power savings mode) 796 */ 797 SOC_IF_ERROR_RETURN 798 (MODIFY_PHY54684_10BT_CTRLr(unit, pc, 0x0000, 0x0200)); 799 } 800 801 if (soc_property_get(unit, spn_PHY_53314_CLK156, 1)) { 802 /* Workaroud : 803 * If the bit9 of GPHY port5 (port0--7) Exp Reg55h is 0, 804 * the fiber will be operating 25% faster. 805 * Thus it will cause link problem. 806 * So we set the bit9 of GPHY port5 (port0--7) Exp Reg55h to 1 here 807 * It is for 156.25MHz only. 808 */ 809 if(pc->lane_num == 5) { 810 /* The phy address of QSGMII is the phy address pins + 8 */ 811 SOC_IF_ERROR_RETURN 812 (PHY54684_REG_MODIFY(unit, pc, 0x00, 0x0F55, 0x15, 813 0x0200, 0x0200)); 814 } 815 } 816 817 if (soc_feature(unit, soc_feature_hawkeye_a0_war)) { 818 /* Workaroud : Fix predriver and driver settings 819 * in TX DFS registers of QSGMII 820 * (Enhancement based on analog designer feedback) 821 * change the TX driver register to value 170H 822 * for revision A0 of HAWKEYE and PHY 54684 823 * (Addr : 0x8067) 824 */ 825 if(pc->lane_num == 0) { 826 /* The phy address of QSGMII is the phy address pins + 8 */ 827 pc->phy_id = pc->phy_id + 8; 828 SOC_IF_ERROR_RETURN 829 (PHY54684_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS, 830 0x0000, 0x1f, 0xffd0)); 831 SOC_IF_ERROR_RETURN 832 (PHY54684_REG_WRITE(unit, pc, 0x00, 0x0000, 0x1e, 0x1f)); 833 SOC_IF_ERROR_RETURN 834 (PHY54684_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS, 835 0x0000, 0x1f, 0x8060)); 836 SOC_IF_ERROR_RETURN 837 (PHY54684_REG_WRITE(unit, pc, 0x00, 0x0000, 0x17, 0x170)); 838 /* Revert the phy_id */ 839 pc->phy_id = pc->phy_id - 8; 840 } 841 842 /* Workaroud : 843 * Make disparity error check configuration in 844 * A0 and B0 to reflect the behavior in C0 845 * write 0xF000 to reg address 0x8105 for all AERs 846 * write 0x00D0 to reg address 0x80BA for all AERs 847 */ 848 if(pc->lane_num == 0){ 849 /* The phy address of QSGMII is the phy address pins + 8 */ 850 pc->phy_id = pc->phy_id + 8; 851 SOC_IF_ERROR_RETURN 852 (PHY54684_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS, 853 0x0000, 0x1f, 0xffd0)); 854 SOC_IF_ERROR_RETURN 855 (PHY54684_REG_WRITE(unit, pc, 0x00, 0x0000, 0x1e, 0x1f)); 856 SOC_IF_ERROR_RETURN 857 (PHY54684_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS, 858 0x0000, 0x1f, 0x80b0)); 859 SOC_IF_ERROR_RETURN 860 (PHY54684_REG_WRITE(unit, pc, 0x00, 0x0000, 0x1a, 0x00d0)); 861 SOC_IF_ERROR_RETURN 862 (PHY54684_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS, 863 0x0000, 0x1f, 0x8100)); 864 SOC_IF_ERROR_RETURN 865 (PHY54684_REG_WRITE(unit, pc, 0x00, 0x0000, 0x15, 0xf000)); 866 /* Revert the phy_id */ 867 pc->phy_id = pc->phy_id - 8; 868 } 869 } 870 871 /* Issue : TX/RX can't work on 10/100 HD mode after cable plug/unplug. 872 * Workaroud : 873 * One of the "Remote PHY" registers in the QSGMII block 874 * of the BCM54684 PHY was modified to fix this issue. 875 * The register is located at address 0x833C. Bit 8 of that register 876 * was cleared to use the legacy TX FIFO of the QSGMII block of BCM54684 PHY. 877 */ 878 if(pc->lane_num == 0){ 879 /* The phy address of QSGMII is the phy address pins + 8 */ 880 pc->phy_id = pc->phy_id + 8; 881 SOC_IF_ERROR_RETURN 882 (PHY54684_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS, 883 0x0000, 0x1f, 0xffd0)); 884 SOC_IF_ERROR_RETURN 885 (PHY54684_REG_WRITE(unit, pc, 0x00, 0x0000, 0x1e, 0x1f)); 886 SOC_IF_ERROR_RETURN 887 (PHY54684_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS, 888 0x0000, 0x1f, 0x8330)); 889 SOC_IF_ERROR_RETURN 890 (PHY54684_REG_WRITE(unit, pc, 0x00, 0x0000, 0x1c, 0x0080)); 891 892 /* Revert the phy_id */ 893 pc->phy_id = pc->phy_id - 8; 894 } 895 #endif 896 return SOC_E_NONE; 897 } 898 899 /* 900 * Function: 901 * phy_54684_init 902 * Purpose: 903 * Init function for 54684 PHY. 904 * Parameters: 905 * unit - StrataSwitch unit #. 906 * port - StrataSwitch port #. 907 * Returns: 908 * SOC_E_NONE 909 */ 910 911 STATIC int 912 phy_54684_init(int unit, soc_port_t port) 913 { 914 phy_ctrl_t *pc; 915 int fiber_capable; 916 int fiber_preferred; 917 918 LOG_INFO(BSL_LS_SOC_PHY, 919 (BSL_META_U(unit, 920 "phy_54684_init: u=%d p=%d\n"), 921 unit, port)); 922 923 /* Only SGMII interface to switch MAC is supported */ 924 if (IS_GMII_PORT(unit, port)) { 925 return SOC_E_CONFIG; 926 } 927 928 pc = EXT_PHY_SW_STATE(unit, port); 929 pc->interface = SOC_PORT_IF_SGMII; 930 931 fiber_capable = 1; 932 933 fiber_preferred = 934 soc_property_port_get(unit, port, spn_PHY_FIBER_PREF, 0); 935 pc->automedium = 936 soc_property_port_get(unit, port, spn_PHY_AUTOMEDIUM, 0); 937 pc->fiber_detect = 938 soc_property_port_get(unit, port, spn_PHY_FIBER_DETECT, -4); 939 940 LOG_INFO(BSL_LS_SOC_PHY, 941 (BSL_META_U(unit, 942 "phy_54684_init: " 943 "u=%d p=%d type=54684%s automedium=%d fiber_pref=%d detect=%d\n"), 944 unit, port, fiber_capable ? "S" : "", 945 pc->automedium, fiber_preferred, pc->fiber_detect)); 946 947 pc->copper.enable = TRUE; 948 pc->copper.preferred = !fiber_preferred; 949 pc->copper.autoneg_enable = TRUE; 950 pc->copper.autoneg_advert = ADVERT_ALL_COPPER; 951 pc->copper.force_speed = 1000; 952 pc->copper.force_duplex = TRUE; 953 pc->copper.master = SOC_PORT_MS_AUTO; 954 pc->copper.mdix = SOC_PORT_MDIX_AUTO; 955 956 pc->fiber.enable = fiber_capable; 957 pc->fiber.preferred = fiber_preferred; 958 pc->fiber.autoneg_enable = fiber_capable; 959 pc->fiber.autoneg_advert = ADVERT_ALL_FIBER; 960 pc->fiber.force_speed = 1000; 961 pc->fiber.force_duplex = TRUE; 962 pc->fiber.master = SOC_PORT_MS_NONE; 963 pc->fiber.mdix = SOC_PORT_MDIX_NORMAL; 964 965 /* Initially configure for the preferred medium. */ 966 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_COPPER); 967 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER); 968 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_PASSTHRU); 969 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX); 970 if (pc->fiber.preferred) { 971 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER); 972 } else { 973 PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER); 974 } 975 976 /* Get Requested LED selectors (defaults are hardware defaults) */ 977 pc->ledmode[0] = soc_property_port_get(unit, port, spn_PHY_LED1_MODE, 0); 978 pc->ledmode[1] = soc_property_port_get(unit, port, spn_PHY_LED2_MODE, 1); 979 pc->ledmode[2] = soc_property_port_get(unit, port, spn_PHY_LED3_MODE, 3); 980 pc->ledmode[3] = soc_property_port_get(unit, port, spn_PHY_LED4_MODE, 6); 981 pc->ledctrl = soc_property_port_get(unit, port, spn_PHY_LED_CTRL, 0x8); 982 pc->ledselect = soc_property_port_get(unit, port, spn_PHY_LED_SELECT, 0); 983 984 SOC_IF_ERROR_RETURN 985 (_phy_54684_reset_setup(unit, port)); 986 987 SOC_IF_ERROR_RETURN 988 (_phy_54684_medium_config_update(unit, port, 989 PHY_COPPER_MODE(unit, port) ? 990 &pc->copper : 991 &pc->fiber)); 992 return SOC_E_NONE; 993 } 994 995 /* 996 * Function: 997 * phy_54684_enable_set 998 * Purpose: 999 * Enable or disable the physical interface. 1000 * Parameters: 1001 * unit - StrataSwitch unit #. 1002 * port - StrataSwitch port #. 1003 * enable - Boolean, true = enable PHY, false = disable. 1004 * Returns: 1005 * SOC_E_XXX 1006 */ 1007 1008 STATIC int 1009 phy_54684_enable_set(int unit, soc_port_t port, int enable) 1010 { 1011 uint16 power; 1012 phy_ctrl_t *pc; 1013 1014 pc = EXT_PHY_SW_STATE(unit, port); 1015 power = (enable) ? 0 : MII_CTRL_PD; 1016 1017 /* Do not incorrectly Power up the interface if medium is disabled and 1018 * global enable = true 1019 */ 1020 if (pc->copper.enable && (pc->automedium || PHY_COPPER_MODE(unit, port))) { 1021 SOC_IF_ERROR_RETURN 1022 (MODIFY_PHY54684_MII_CTRLr(unit, pc, power, MII_CTRL_PD)); 1023 1024 LOG_INFO(BSL_LS_SOC_PHY, 1025 (BSL_META_U(unit, 1026 "phy_54684_enable_set: " 1027 "Power %s copper medium\n"), (enable) ? "up" : "down")); 1028 } 1029 1030 if (pc->fiber.enable && (pc->automedium || PHY_FIBER_MODE(unit, port))) { 1031 phy_ctrl_t *int_pc; 1032 SOC_IF_ERROR_RETURN 1033 (MODIFY_PHY54684_1000X_MII_CTRLr(unit, pc, power, 1034 MII_CTRL_PD)); 1035 1036 int_pc = INT_PHY_SW_STATE(unit, port); 1037 if (NULL != int_pc) { 1038 SOC_IF_ERROR_RETURN 1039 (PHY_ENABLE_SET(int_pc->pd, unit, port, enable)); 1040 } 1041 1042 /* 1043 * When enable/disable the fiber port, 1044 * the Tx disable bit of Expansion register 0x52 should be set also. 1045 * Otherwise the following issue happens. 1046 * After the fiber port is powered down 1047 * (verified bit 11 MII cotnrol register 0 is set to 1), 1048 * the link partner still shows linkup 1049 */ 1050 SOC_IF_ERROR_RETURN 1051 (MODIFY_PHY54684_EXP_SERDES_SGMII_RX_CTRLr(unit, pc, enable?0:1, 0x1)); 1052 SOC_IF_ERROR_RETURN 1053 (MODIFY_PHY54684_EXP_SERDES_SGMII_CTRLr(unit, pc, enable?0:1, 0x1)); 1054 1055 LOG_INFO(BSL_LS_SOC_PHY, 1056 (BSL_META_U(unit, 1057 "phy_54684_enable_set: " 1058 "Power %s fiber medium\n"), (enable) ? "up" : "down")); 1059 } 1060 1061 /* Update software state */ 1062 SOC_IF_ERROR_RETURN(phy_fe_ge_enable_set(unit, port, enable)); 1063 1064 return SOC_E_NONE; 1065 } 1066 1067 /* 1068 * Function: 1069 * phy_54684_enable_get 1070 * Purpose: 1071 * Enable or disable the physical interface for a 54684 device. 1072 * Parameters: 1073 * unit - StrataSwitch unit #. 1074 * port - StrataSwitch port #. 1075 * enable - (OUT) Boolean, true = enable PHY, false = disable. 1076 * Returns: 1077 * SOC_E_XXX 1078 */ 1079 1080 STATIC int 1081 phy_54684_enable_get(int unit, soc_port_t port, int *enable) 1082 { 1083 return phy_fe_ge_enable_get(unit, port, enable); 1084 } 1085 1086 /* 1087 * Function: 1088 * _phy_54684_fiber_100fx_setup 1089 * Purpose: 1090 * Switch from 1000X mode to 100FX. 1091 * Parameters: 1092 * unit - StrataSwitch unit #. 1093 * port - StrataSwitch port #. 1094 * Returns: 1095 * SOC_E_XXX 1096 */ 1097 STATIC int 1098 _phy_54684_fiber_100fx_setup(int unit, soc_port_t port) 1099 { 1100 phy_ctrl_t *pc; 1101 1102 pc = EXT_PHY_SW_STATE(unit, port); 1103 1104 LOG_VERBOSE(BSL_LS_SOC_PHY, 1105 (BSL_META_U(unit, 1106 "_phy_54684_1000x_to_100fx: u=%d p=%d \n"), 1107 unit, port)); 1108 /* Operate SerDes in 100FX */ 1109 1110 /* SerDes 100FX control register - register 1CH shadow 13H 1111 * BIT0 : 100FX link SerDes enable 1112 * BIT1 : 100FX SerDes full duplex 1113 */ 1114 if(pc->fiber.force_duplex) { 1115 SOC_IF_ERROR_RETURN 1116 (MODIFY_PHY54684_SERDES_100FX_CTRLr(unit, pc, 0x3, 0x3)); 1117 } else { 1118 SOC_IF_ERROR_RETURN 1119 (MODIFY_PHY54684_SERDES_100FX_CTRLr(unit, pc, 0x1, 0x3)); 1120 } 1121 1122 /* Power up the SerDes */ 1123 SOC_IF_ERROR_RETURN 1124 (WRITE_PHY54684_1000X_MII_CTRLr(unit, pc, 1125 MII_CTRL_AE | MII_CTRL_FD | MII_CTRL_SS_100)); 1126 1127 PHY_FLAGS_SET(unit, port, PHY_FLAGS_100FX); 1128 pc->fiber.autoneg_enable = FALSE; 1129 1130 return SOC_E_NONE; 1131 } 1132 1133 /* 1134 * Function: 1135 * _phy_54684_fiber_1000x_setup 1136 * Purpose: 1137 * Switch from 100FX mode to 1000X. 1138 * Parameters: 1139 * unit - StrataSwitch unit #. 1140 * port - StrataSwitch port #. 1141 * Returns: 1142 * SOC_E_XXX 1143 */ 1144 STATIC int 1145 _phy_54684_fiber_1000x_setup(int unit, soc_port_t port) 1146 { 1147 uint16 data; 1148 phy_ctrl_t *pc; 1149 1150 pc = EXT_PHY_SW_STATE(unit, port); 1151 1152 LOG_VERBOSE(BSL_LS_SOC_PHY, 1153 (BSL_META_U(unit, 1154 "_phy_54684_fiber_1000x_setup: u=%d p=%d \n"), 1155 unit, port)); 1156 1157 /* Operate SerDes in 1000X */ 1158 SOC_IF_ERROR_RETURN 1159 (MODIFY_PHY54684_SERDES_100FX_CTRLr(unit, pc, 0x0, 0x1)); 1160 1161 /* Power up the SerDes */ 1162 if (pc->fiber.autoneg_enable) { 1163 data = MII_CTRL_AE | MII_CTRL_RAN | MII_CTRL_FD | MII_CTRL_SS_1000; 1164 } else { 1165 data = MII_CTRL_RAN | MII_CTRL_FD | MII_CTRL_SS_1000; 1166 } 1167 1168 SOC_IF_ERROR_RETURN 1169 (WRITE_PHY54684_1000X_MII_CTRLr(unit, pc, data)); 1170 1171 /* When speed is 1000Mbps, set duplex to HD mode. 1172 * This is because our MAC does not support 1G half duplex. 1173 */ 1174 pc->fiber.force_duplex = TRUE; 1175 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX); 1176 1177 return SOC_E_NONE; 1178 } 1179 1180 STATIC int 1181 _phy_54684_medium_change(int unit, soc_port_t port, int force_update) 1182 { 1183 phy_ctrl_t *pc; 1184 int medium; 1185 1186 pc = EXT_PHY_SW_STATE(unit, port); 1187 1188 SOC_IF_ERROR_RETURN 1189 (_phy_54684_medium_check(unit, port, &medium)); 1190 1191 if (medium == SOC_PORT_MEDIUM_COPPER) { 1192 if ((!PHY_COPPER_MODE(unit, port)) || force_update) { /* Was fiber */ 1193 PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER); 1194 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER); 1195 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX); 1196 PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 1197 SOC_IF_ERROR_RETURN 1198 (_phy_54684_no_reset_setup(unit, port)); 1199 1200 /* Do not power up the interface if medium is disabled. */ 1201 if (pc->copper.enable) { 1202 SOC_IF_ERROR_RETURN 1203 (_phy_54684_medium_config_update(unit, port, &pc->copper)); 1204 } 1205 LOG_INFO(BSL_LS_SOC_PHY, 1206 (BSL_META_U(unit, 1207 "_phy_54684_link_auto_detect: u=%d p=%d [F->C]\n"), 1208 unit, port)); 1209 } 1210 } else { /* Fiber */ 1211 if (PHY_COPPER_MODE(unit, port) || force_update) { /* Was copper */ 1212 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_COPPER); 1213 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER); 1214 PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 1215 SOC_IF_ERROR_RETURN 1216 (_phy_54684_no_reset_setup(unit, port)); 1217 1218 /* 1219 * When enable/disable the fiber port, 1220 * the Tx disable bit of Expansion register 0x52 should be set also. 1221 * Otherwise the following issue happens. 1222 * After the fiber port is powered down 1223 * (verified bit 11 MII cotnrol register 0 is set to 1), 1224 * the link partner still shows linkup 1225 */ 1226 SOC_IF_ERROR_RETURN 1227 (MODIFY_PHY54684_EXP_SERDES_SGMII_RX_CTRLr(unit, pc, 1228 pc->fiber.enable?0:1, 0x1)); 1229 SOC_IF_ERROR_RETURN 1230 (MODIFY_PHY54684_EXP_SERDES_SGMII_CTRLr(unit, pc, 1231 pc->fiber.enable?0:1, 0x1)); 1232 1233 if (pc->fiber.enable) { 1234 SOC_IF_ERROR_RETURN 1235 (_phy_54684_medium_config_update(unit, port, &pc->fiber)); 1236 } 1237 LOG_INFO(BSL_LS_SOC_PHY, 1238 (BSL_META_U(unit, 1239 "_phy_54684_link_auto_detect: u=%d p=%d [C->F]\n"), 1240 unit, port)); 1241 } 1242 } 1243 return SOC_E_NONE; 1244 } 1245 1246 /* 1247 * Function: 1248 * phy_54684_link_get 1249 * Purpose: 1250 * Determine the current link up/down status for a 54684 device. 1251 * Parameters: 1252 * unit - StrataSwitch unit #. 1253 * port - StrataSwitch port #. 1254 * link - (OUT) Boolean, true indicates link established. 1255 * Returns: 1256 * SOC_E_XXX 1257 * Notes: 1258 * If using automedium, also switches the mode. 1259 */ 1260 STATIC int 1261 phy_54684_link_get(int unit, soc_port_t port, int *link) 1262 { 1263 phy_ctrl_t *pc; 1264 uint16 data; 1265 uint16 mask; 1266 1267 pc = EXT_PHY_SW_STATE(unit, port); 1268 *link = FALSE; /* Default return */ 1269 1270 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) { 1271 return SOC_E_NONE; 1272 } 1273 1274 if (!pc->fiber.enable && !pc->copper.enable) { 1275 return SOC_E_NONE; 1276 } 1277 1278 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 1279 if (pc->automedium) { 1280 /* Check for medium change and update HW/SW accordingly. */ 1281 SOC_IF_ERROR_RETURN 1282 (_phy_54684_medium_change(unit, port,FALSE)); 1283 } 1284 if (PHY_COPPER_MODE(unit, port)) { 1285 SOC_IF_ERROR_RETURN(phy_fe_ge_link_get(unit, port, link)); 1286 } else { 1287 SOC_IF_ERROR_RETURN 1288 (READ_PHY54684_1000X_MII_STATr(unit, pc, &data)); 1289 *link = (data & MII_STAT_LA) ? TRUE : FALSE; 1290 } 1291 1292 /* If preferred medium is up, disable the other medium 1293 * to prevent false link. */ 1294 if (pc->automedium) { 1295 mask = MII_CTRL_PD; 1296 if (pc->copper.preferred) { 1297 if (pc->fiber.enable) { 1298 /* power down the serdes */ 1299 data = (*link && PHY_COPPER_MODE(unit, port)) ? MII_CTRL_PD : 0; 1300 } else { 1301 data = MII_CTRL_PD; 1302 } 1303 SOC_IF_ERROR_RETURN 1304 (MODIFY_PHY54684_1000X_MII_CTRLr(unit, pc, data, mask)); 1305 } else { /* pc->fiber.preferred */ 1306 if (pc->copper.enable) { 1307 data = (*link && PHY_FIBER_MODE(unit, port)) ? MII_CTRL_PD : 0; 1308 } else { 1309 data = MII_CTRL_PD; 1310 } 1311 SOC_IF_ERROR_RETURN 1312 (MODIFY_PHY54684_MII_CTRLr(unit, pc, data, mask)); 1313 } 1314 } 1315 1316 LOG_VERBOSE(BSL_LS_SOC_PHY, 1317 (BSL_META_U(unit, 1318 "phy_54684_link_get: u=%d p=%d mode=%s%s link=%d\n"), 1319 unit, port, 1320 PHY_COPPER_MODE(unit, port) ? "C" : "F", 1321 PHY_FIBER_100FX_MODE(unit, port)? "(100FX)" : "", 1322 *link)); 1323 1324 return SOC_E_NONE; 1325 } 1326 1327 /* 1328 * Function: 1329 * phy_54684_duplex_set 1330 * Purpose: 1331 * Set the current duplex mode (forced). 1332 * Parameters: 1333 * unit - StrataSwitch unit #. 1334 * port - StrataSwitch port #. 1335 * duplex - Boolean, true indicates full duplex, false indicates half. 1336 * Returns: 1337 * SOC_E_NONE 1338 * SOC_E_UNAVAIL - Half duplex requested, and not supported. 1339 * Notes: 1340 * The duplex is set only for the ACTIVE medium. 1341 * No synchronization performed at this level. 1342 * Autonegotiation is not manipulated. 1343 */ 1344 1345 STATIC int 1346 phy_54684_duplex_set(int unit, soc_port_t port, int duplex) 1347 { 1348 int rv; 1349 phy_ctrl_t *pc; 1350 1351 pc = EXT_PHY_SW_STATE(unit, port); 1352 rv = SOC_E_NONE; 1353 if (PHY_COPPER_MODE(unit, port)) { 1354 /* Note: mac.c uses phy_5690_notify_duplex to update 5690 */ 1355 rv = phy_fe_ge_duplex_set(unit, port, duplex); 1356 if (SOC_SUCCESS(rv)) { 1357 pc->copper.force_duplex = duplex; 1358 } 1359 } else { /* Fiber */ 1360 if (PHY_FIBER_100FX_MODE(unit, port)) { 1361 SOC_IF_ERROR_RETURN 1362 (MODIFY_PHY54684_SERDES_100FX_CTRLr(unit, pc, duplex? 0x2:0x0, 0x2)); 1363 pc->fiber.force_duplex = duplex; 1364 } else { 1365 if(!duplex) { 1366 return SOC_E_UNAVAIL; 1367 } 1368 } 1369 } 1370 1371 LOG_INFO(BSL_LS_SOC_PHY, 1372 (BSL_META_U(unit, 1373 "phy_54684_duplex_set: u=%d p=%d d=%d rv=%d\n"), 1374 unit, port, duplex, rv)); 1375 1376 return rv; 1377 } 1378 1379 /* 1380 * Function: 1381 * phy_54684_duplex_get 1382 * Purpose: 1383 * Get the current operating duplex mode. If autoneg is enabled, 1384 * then operating mode is returned, otherwise forced mode is returned. 1385 * Parameters: 1386 * unit - StrataSwitch unit #. 1387 * port - StrataSwitch port #. 1388 * duplex - (OUT) Boolean, true indicates full duplex, false 1389 * indicates half. 1390 * Returns: 1391 * SOC_E_NONE 1392 * Notes: 1393 * The duplex is retrieved for the ACTIVE medium. 1394 * No synchronization performed at this level. Autonegotiation is 1395 * not manipulated. 1396 */ 1397 1398 STATIC int 1399 phy_54684_duplex_get(int unit, soc_port_t port, int *duplex) 1400 { 1401 phy_ctrl_t *pc; 1402 uint16 opt_mode; 1403 1404 pc = EXT_PHY_SW_STATE(unit, port); 1405 1406 if (PHY_COPPER_MODE(unit, port)) { 1407 return phy_fe_ge_duplex_get(unit, port, duplex); 1408 } else { /* Fiber */ 1409 if (PHY_FIBER_100FX_MODE(unit, port)) { 1410 SOC_IF_ERROR_RETURN 1411 (READ_PHY54684_EXP_OPT_MODE_STATr(unit, pc, &opt_mode)); 1412 /* The bit 12 of register EXP_OPT_MODE_STAT is serdes duplex */ 1413 if(opt_mode & 0x1000) { 1414 *duplex = TRUE; 1415 } else { 1416 *duplex = FALSE; 1417 } 1418 } else { /* 1000X */ 1419 *duplex = TRUE; 1420 } 1421 } 1422 1423 return SOC_E_NONE; 1424 } 1425 1426 /* 1427 * Function: 1428 * phy_54684_speed_set 1429 * Purpose: 1430 * Set the current operating speed (forced). 1431 * Parameters: 1432 * unit - StrataSwitch unit #. 1433 * port - StrataSwitch port #. 1434 * speed - Requested speed, only 1000 supported. 1435 * Returns: 1436 * SOC_E_XXX 1437 * Notes: 1438 * The speed is set only for the ACTIVE medium. 1439 */ 1440 1441 STATIC int 1442 phy_54684_speed_set(int unit, soc_port_t port, int speed) 1443 { 1444 int rv; 1445 phy_ctrl_t *pc; 1446 1447 pc = EXT_PHY_SW_STATE(unit, port); 1448 rv = SOC_E_NONE; 1449 if (PHY_COPPER_MODE(unit, port)) { 1450 /* Note: mac.c uses phy_5690_notify_speed to update 5690 */ 1451 rv = phy_fe_ge_speed_set(unit, port, speed); 1452 if (SOC_SUCCESS(rv)) { 1453 pc->copper.force_speed = speed; 1454 } 1455 } else { /* Fiber */ 1456 if (speed == 100) { 1457 rv = _phy_54684_fiber_100fx_setup(unit, port); 1458 } else if (speed == 0 || speed == 1000) { 1459 rv = _phy_54684_fiber_1000x_setup(unit, port); 1460 } else { 1461 rv = SOC_E_CONFIG; 1462 } 1463 if (SOC_SUCCESS(rv)) { 1464 pc->fiber.force_speed = speed; 1465 } 1466 } 1467 1468 LOG_INFO(BSL_LS_SOC_PHY, 1469 (BSL_META_U(unit, 1470 "phy_54684_speed_set: u=%d p=%d s=%d fiber=%d rv=%d\n"), 1471 unit, port, speed, PHY_FIBER_MODE(unit, port), rv)); 1472 1473 return rv; 1474 } 1475 1476 /* 1477 * Function: 1478 * phy_54684_speed_get 1479 * Purpose: 1480 * Get the current operating speed for a 54684 device. 1481 * Parameters: 1482 * unit - StrataSwitch unit #. 1483 * port - StrataSwitch port #. 1484 * duplex - (OUT) Boolean, true indicates full duplex, false 1485 * indicates half. 1486 * Returns: 1487 * SOC_E_NONE 1488 * Notes: 1489 * The speed is retrieved for the ACTIVE medium. 1490 */ 1491 1492 STATIC int 1493 phy_54684_speed_get(int unit, soc_port_t port, int *speed) 1494 { 1495 phy_ctrl_t *pc; 1496 uint16 opt_mode; 1497 1498 pc = EXT_PHY_SW_STATE(unit, port); 1499 1500 if (PHY_COPPER_MODE(unit, port)) { 1501 return phy_fe_ge_speed_get(unit, port, speed); 1502 } else { 1503 *speed = 1000; 1504 SOC_IF_ERROR_RETURN 1505 (READ_PHY54684_EXP_OPT_MODE_STATr(unit, pc, &opt_mode)); 1506 switch(opt_mode & (0x3 << 13)) { 1507 case (0 << 13): 1508 *speed = 10; 1509 break; 1510 case (1 << 13): 1511 *speed = 100; 1512 break; 1513 case (2 << 13): 1514 *speed = 1000; 1515 break; 1516 default: 1517 LOG_WARN(BSL_LS_SOC_PHY, 1518 (BSL_META_U(unit, 1519 "phy_54684_speed_get: u=%d p=%d invalid speed\n"), 1520 unit, port)); 1521 } 1522 } 1523 1524 return SOC_E_NONE; 1525 } 1526 1527 /* 1528 * Function: 1529 * phy_54684_master_set 1530 * Purpose: 1531 * Set the current master mode 1532 * Parameters: 1533 * unit - StrataSwitch unit #. 1534 * port - StrataSwitch port #. 1535 * master - SOC_PORT_MS_* 1536 * Returns: 1537 * SOC_E_XXX 1538 * Notes: 1539 * The master mode is set only for the ACTIVE medium. 1540 */ 1541 STATIC int 1542 phy_54684_master_set(int unit, soc_port_t port, int master) 1543 { 1544 int rv; 1545 phy_ctrl_t *pc; 1546 1547 pc = EXT_PHY_SW_STATE(unit, port); 1548 rv = SOC_E_NONE; 1549 if (PHY_COPPER_MODE(unit, port)) { 1550 rv = phy_fe_ge_master_set(unit, port, master); 1551 if (SOC_SUCCESS(rv)) { 1552 pc->copper.master = master; 1553 } 1554 } 1555 LOG_INFO(BSL_LS_SOC_PHY, 1556 (BSL_META_U(unit, 1557 "phy_54684_master_set: u=%d p=%d master=%d fiber=%d rv=%d\n"), 1558 unit, port, master, PHY_FIBER_MODE(unit, port), rv)); 1559 return rv; 1560 } 1561 1562 /* 1563 * Function: 1564 * phy_54684_master_get 1565 * Purpose: 1566 * Get the current master mode for a 54684 device. 1567 * Parameters: 1568 * unit - StrataSwitch unit #. 1569 * port - StrataSwitch port #. 1570 * master - (OUT) SOC_PORT_MS_* 1571 * Returns: 1572 * SOC_E_NONE 1573 * Notes: 1574 * The master mode is retrieved for the ACTIVE medium. 1575 */ 1576 1577 STATIC int 1578 phy_54684_master_get(int unit, soc_port_t port, int *master) 1579 { 1580 if (PHY_COPPER_MODE(unit, port)) { 1581 return phy_fe_ge_master_get(unit, port, master); 1582 } else { 1583 *master = SOC_PORT_MS_NONE; 1584 return SOC_E_NONE; 1585 } 1586 } 1587 1588 /* 1589 * Function: 1590 * phy_54684_autoneg_set 1591 * Purpose: 1592 * Enable or disable auto-negotiation on the specified port. 1593 * Parameters: 1594 * unit - StrataSwitch unit #. 1595 * port - StrataSwitch port #. 1596 * autoneg - Boolean, if true, auto-negotiation is enabled 1597 * (and/or restarted). If false, autonegotiation is disabled. 1598 * Returns: 1599 * SOC_E_XXX 1600 * Notes: 1601 * The autoneg mode is set only for the ACTIVE medium. 1602 */ 1603 1604 STATIC int 1605 phy_54684_autoneg_set(int unit, soc_port_t port, int autoneg) 1606 { 1607 int rv; 1608 uint16 data, mask; 1609 phy_ctrl_t *pc; 1610 1611 pc = EXT_PHY_SW_STATE(unit, port); 1612 rv = SOC_E_NONE; 1613 if (PHY_COPPER_MODE(unit, port)) { 1614 rv = phy_fe_ge_an_set(unit, port, autoneg); 1615 if (SOC_SUCCESS(rv)) { 1616 pc->copper.autoneg_enable = autoneg ? 1 : 0; 1617 } 1618 } else { 1619 if (autoneg) { 1620 /* When enabling autoneg, set the default speed to 1000Mbps first. 1621 * PHY will not enable autoneg if the PHY is in 100FX mode. 1622 */ 1623 SOC_IF_ERROR_RETURN 1624 (phy_54684_speed_set(unit, port, 1000)); 1625 } 1626 1627 /* Disable/Enable auto-detection between SGMII-slave and 1000BASE-X */ 1628 SOC_IF_ERROR_RETURN 1629 (MODIFY_PHY54684_SGMII_SLAVEr(unit, pc, autoneg ?1:0, 1)); 1630 1631 SOC_IF_ERROR_RETURN 1632 (phy_54684_adv_local_set(unit, port, pc->fiber.autoneg_advert)); 1633 1634 data = MII_CTRL_FD; 1635 data |= (autoneg) ? MII_CTRL_AE | MII_CTRL_RAN : 0; 1636 mask = MII_CTRL_AE | MII_CTRL_RAN | MII_CTRL_FD; 1637 SOC_IF_ERROR_RETURN 1638 (MODIFY_PHY54684_1000X_MII_CTRLr(unit, pc, data, mask)); 1639 1640 1641 pc->fiber.autoneg_enable = autoneg ? TRUE : FALSE; 1642 } 1643 1644 LOG_INFO(BSL_LS_SOC_PHY, 1645 (BSL_META_U(unit, 1646 "phy_54684_autoneg_set: u=%d p=%d autoneg=%d rv=%d\n"), 1647 unit, port, autoneg, rv)); 1648 1649 return rv; 1650 } 1651 1652 /* 1653 * Function: 1654 * phy_54684_autoneg_get 1655 * Purpose: 1656 * Get the current auto-negotiation status (enabled/busy). 1657 * Parameters: 1658 * unit - StrataSwitch unit #. 1659 * port - StrataSwitch port #. 1660 * autoneg - (OUT) if true, auto-negotiation is enabled. 1661 * autoneg_done - (OUT) if true, auto-negotiation is complete. This 1662 * value is undefined if autoneg == FALSE. 1663 * Returns: 1664 * SOC_E_XXX 1665 * Notes: 1666 * The autoneg mode is retrieved for the ACTIVE medium. 1667 */ 1668 1669 STATIC int 1670 phy_54684_autoneg_get(int unit, soc_port_t port, 1671 int *autoneg, int *autoneg_done) 1672 { 1673 int rv; 1674 uint16 data; 1675 phy_ctrl_t *pc; 1676 1677 pc = EXT_PHY_SW_STATE(unit, port); 1678 1679 rv = SOC_E_NONE; 1680 *autoneg = FALSE; 1681 *autoneg_done = FALSE; 1682 if (PHY_COPPER_MODE(unit, port)) { 1683 rv = phy_fe_ge_an_get(unit, port, autoneg, autoneg_done); 1684 } else { 1685 /* autoneg is not enabled in 100FX mode */ 1686 if (PHY_FIBER_100FX_MODE(unit, port)) { 1687 *autoneg = FALSE; 1688 *autoneg_done = TRUE; 1689 return rv; 1690 } 1691 1692 SOC_IF_ERROR_RETURN 1693 (READ_PHY54684_1000X_MII_CTRLr(unit, pc, &data)); 1694 if (data & MII_CTRL_AE) { 1695 *autoneg = TRUE; 1696 1697 SOC_IF_ERROR_RETURN 1698 (READ_PHY54684_1000X_MII_STATr(unit, pc, &data)); 1699 if (data & MII_STAT_AN_DONE) { 1700 *autoneg_done = TRUE; 1701 } 1702 } 1703 1704 } 1705 1706 return rv; 1707 } 1708 1709 /* 1710 * Function: 1711 * phy_54684_adv_local_set 1712 * Purpose: 1713 * Set the current advertisement for auto-negotiation. 1714 * Parameters: 1715 * unit - StrataSwitch unit #. 1716 * port - StrataSwitch port #. 1717 * mode - Port mode mask indicating supported options/speeds. 1718 * Returns: 1719 * SOC_E_XXX 1720 * Notes: 1721 * The advertisement is set only for the ACTIVE medium. 1722 * No synchronization performed at this level. 1723 */ 1724 1725 STATIC int 1726 phy_54684_adv_local_set(int unit, soc_port_t port, soc_port_mode_t mode) 1727 { 1728 int rv; 1729 phy_ctrl_t *pc; 1730 1731 pc = EXT_PHY_SW_STATE(unit, port); 1732 rv = SOC_E_NONE; 1733 if (PHY_COPPER_MODE(unit, port)) { 1734 rv = phy_ge_adv_local_set(unit, port, mode); 1735 if (SOC_SUCCESS(rv)) { 1736 pc->copper.autoneg_advert = mode & ADVERT_ALL_COPPER; 1737 } 1738 } else { 1739 uint16 mii_adv; 1740 1741 mii_adv = MII_ANA_C37_FD; /* Always advertise 1000X full duplex */ 1742 switch (mode & SOC_PM_PAUSE) { 1743 case SOC_PM_PAUSE: 1744 mii_adv |= MII_ANA_C37_PAUSE; 1745 break; 1746 case SOC_PM_PAUSE_TX: 1747 mii_adv |= MII_ANA_C37_ASYM_PAUSE; 1748 break; 1749 case SOC_PM_PAUSE_RX: 1750 mii_adv |= (MII_ANA_C37_ASYM_PAUSE | MII_ANA_C37_PAUSE); 1751 break; 1752 } 1753 /* Write to SerDes Auto-Neg Advertisement Reg */ 1754 rv = WRITE_PHY54684_1000X_MII_ANAr(unit, pc, mii_adv); 1755 if (SOC_SUCCESS(rv)) { 1756 pc->fiber.autoneg_advert = mode & ADVERT_ALL_FIBER; 1757 } 1758 } 1759 LOG_INFO(BSL_LS_SOC_PHY, 1760 (BSL_META_U(unit, 1761 "phy_54684_adv_local_set: u=%d p=%d mode=0x%x, rv=%d\n"), 1762 unit, port, mode, rv)); 1763 return rv; 1764 } 1765 1766 /* 1767 * Function: 1768 * phy_54684_adv_local_get 1769 * Purpose: 1770 * Get the current advertisement for auto-negotiation. 1771 * Parameters: 1772 * unit - StrataSwitch unit #. 1773 * port - StrataSwitch port #. 1774 * mode - (OUT) Port mode mask indicating supported options/speeds. 1775 * Returns: 1776 * SOC_E_XXX 1777 * Notes: 1778 * The advertisement is retrieved for the ACTIVE medium. 1779 * No synchronization performed at this level. 1780 */ 1781 1782 STATIC int 1783 phy_54684_adv_local_get(int unit, soc_port_t port, soc_port_mode_t *mode) 1784 { 1785 uint16 mii_adv; 1786 phy_ctrl_t *pc; 1787 1788 pc = EXT_PHY_SW_STATE(unit, port); 1789 1790 if (PHY_COPPER_MODE(unit, port)) { 1791 return phy_ge_adv_local_get(unit, port, mode); 1792 } else { /* PHY_FIBER_MODE */ 1793 /* read the 1000BASE-X Auto-Neg Advertisement Reg ( Address 0x04 ) */ 1794 SOC_IF_ERROR_RETURN 1795 (READ_PHY54684_1000X_MII_ANAr(unit, pc, &mii_adv)); 1796 1797 *mode = 0; 1798 *mode |= (mii_adv & MII_ANA_C37_FD) ? SOC_PM_1000MB_FD : 0; 1799 *mode |= (mii_adv & MII_ANA_C37_HD) ? SOC_PM_1000MB_HD : 0; 1800 switch (mii_adv & (MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE)) { 1801 case MII_ANA_C37_PAUSE: 1802 *mode |= SOC_PM_PAUSE; 1803 break; 1804 case MII_ANA_C37_ASYM_PAUSE: 1805 *mode |= SOC_PM_PAUSE_TX; 1806 break; 1807 case (MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE): 1808 *mode |= SOC_PM_PAUSE_RX; 1809 break; 1810 } 1811 } 1812 return SOC_E_NONE; 1813 } 1814 1815 /* 1816 * Function: 1817 * phy_54684_adv_remote_get 1818 * Purpose: 1819 * Get partners current advertisement for auto-negotiation. 1820 * Parameters: 1821 * unit - StrataSwitch unit #. 1822 * port - StrataSwitch port #. 1823 * mode - (OUT) Port mode mask indicating supported options/speeds. 1824 * Returns: 1825 * SOC_E_XXX 1826 * Notes: 1827 * The remote advertisement is retrieved for the ACTIVE medium. 1828 * No synchronization performed at this level. If Autonegotiation is 1829 * disabled or in progress, this routine will return an error. 1830 */ 1831 1832 STATIC int 1833 phy_54684_adv_remote_get(int unit, soc_port_t port, soc_port_mode_t *mode) 1834 { 1835 uint16 data; 1836 phy_ctrl_t *pc; 1837 1838 pc = EXT_PHY_SW_STATE(unit, port); 1839 if (PHY_COPPER_MODE(unit, port)) { 1840 return phy_ge_adv_remote_get(unit, port, mode); 1841 } else { /* PHY_FIBER_MODE */ 1842 1843 *mode = 0; 1844 /* read the 1000BASE-X Control Reg ( Address 0x00 ), 1845 * Auto-Neg Link Partner Ability Reg ( Address 0x05 ) 1846 */ 1847 SOC_IF_ERROR_RETURN 1848 (READ_PHY54684_1000X_MII_CTRLr(unit, pc, &data)); 1849 if (!(data & MII_CTRL_AE)) { 1850 return SOC_E_DISABLED; 1851 } 1852 1853 SOC_IF_ERROR_RETURN 1854 (READ_PHY54684_1000X_MII_ANPr(unit, pc, &data)); 1855 if (data & MII_ANP_SGMII_MODE) { 1856 /* Link partner is SGMII master */ 1857 switch(data & MII_ANP_SGMII_SS_MASK) { 1858 case MII_ANP_SGMII_SS_10: 1859 *mode = SOC_PM_10MB; 1860 break; 1861 case MII_ANP_SGMII_SS_100: 1862 *mode = SOC_PM_100MB; 1863 break; 1864 case MII_ANP_SGMII_SS_1000: 1865 *mode = SOC_PM_1000MB; 1866 break; 1867 } 1868 1869 *mode &= (data & MII_ANP_SGMII_FD) ? SOC_PM_FD : SOC_PM_HD; 1870 } else { 1871 *mode |= (data & MII_ANP_C37_FD) ? SOC_PM_1000MB_FD : 0; 1872 *mode |= (data & MII_ANP_C37_HD) ? SOC_PM_1000MB_HD : 0; 1873 switch (data & (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) { 1874 case MII_ANP_C37_PAUSE: 1875 *mode |= SOC_PM_PAUSE; 1876 break; 1877 case MII_ANP_C37_ASYM_PAUSE: 1878 *mode |= SOC_PM_PAUSE_TX; 1879 break; 1880 case (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE): 1881 *mode |= SOC_PM_PAUSE_RX; 1882 break; 1883 } 1884 } 1885 } 1886 return SOC_E_NONE; 1887 } 1888 1889 /* 1890 * Function: 1891 * phy_54684_lb_set 1892 * Purpose: 1893 * Set the local PHY loopback mode. 1894 * Parameters: 1895 * unit - StrataSwitch unit #. 1896 * port - StrataSwitch port #. 1897 * loopback - Boolean: true = enable loopback, false = disable. 1898 * Returns: 1899 * SOC_E_XXX 1900 * Notes: 1901 * The loopback mode is set only for the ACTIVE medium. 1902 * No synchronization performed at this level. 1903 */ 1904 1905 STATIC int 1906 phy_54684_lb_set(int unit, soc_port_t port, int enable) 1907 { 1908 int rv; 1909 uint16 data; 1910 phy_ctrl_t *pc; 1911 1912 pc = EXT_PHY_SW_STATE(unit, port); 1913 rv = SOC_E_NONE; 1914 1915 #if AUTO_MDIX_WHEN_AN_DIS 1916 { 1917 /* Disable Auto-MDIX When autoneg disabled */ 1918 /* Enable Auto-MDIX When autoneg disabled */ 1919 data = (enable) ? 0x0000 : 0x0200; 1920 SOC_IF_ERROR_RETURN 1921 (MODIFY_PHY_54684_MII_MISC_CTRLr(unit, pc, data, 0x0200)); 1922 } 1923 #endif 1924 1925 if (PHY_COPPER_MODE(unit, port)) { 1926 rv = phy_fe_ge_lb_set(unit, port, enable); 1927 } else { 1928 data = (enable) ? MII_CTRL_LE : 0; 1929 rv = MODIFY_PHY54684_1000X_MII_CTRLr 1930 (unit, pc, data, MII_CTRL_LE); 1931 if (enable && SOC_SUCCESS(rv)) { 1932 uint16 stat; 1933 int link; 1934 soc_timeout_t to; 1935 1936 /* Wait up to 5000 msec for link up */ 1937 soc_timeout_init(&to, 5000000, 0); 1938 link = 0; 1939 while (!soc_timeout_check(&to)) { 1940 rv = READ_PHY54684_1000X_MII_STATr(unit, pc, &stat); 1941 link = stat & MII_STAT_LA; 1942 if (link || SOC_FAILURE(rv)) { 1943 break; 1944 } 1945 } 1946 if (!link) { 1947 LOG_WARN(BSL_LS_SOC_PHY, 1948 (BSL_META_U(unit, 1949 "phy_54684_lb_set: u=%d p=%d TIMEOUT\n"), 1950 unit, port)); 1951 1952 rv = SOC_E_TIMEOUT; 1953 } 1954 } 1955 } 1956 LOG_INFO(BSL_LS_SOC_PHY, 1957 (BSL_META_U(unit, 1958 "phy_54684_lb_set: u=%d p=%d en=%d rv=%d\n"), 1959 unit, port, enable, rv)); 1960 1961 return rv; 1962 } 1963 1964 /* 1965 * Function: 1966 * phy_54684_lb_get 1967 * Purpose: 1968 * Get the local PHY loopback mode. 1969 * Parameters: 1970 * unit - StrataSwitch unit #. 1971 * port - StrataSwitch port #. 1972 * loopback - (OUT) Boolean: true = enable loopback, false = disable. 1973 * Returns: 1974 * SOC_E_XXX 1975 * Notes: 1976 * The loopback mode is retrieved for the ACTIVE medium. 1977 */ 1978 1979 STATIC int 1980 phy_54684_lb_get(int unit, soc_port_t port, int *enable) 1981 { 1982 uint16 data; 1983 phy_ctrl_t *pc; 1984 1985 pc = EXT_PHY_SW_STATE(unit, port); 1986 1987 if (PHY_COPPER_MODE(unit, port)) { 1988 SOC_IF_ERROR_RETURN 1989 (phy_fe_ge_lb_get(unit, port, enable)); 1990 } else { 1991 SOC_IF_ERROR_RETURN 1992 (READ_PHY54684_1000X_MII_CTRLr(unit, pc, &data)); 1993 *enable = (data & MII_CTRL_LE) ? 1 : 0; 1994 } 1995 1996 return SOC_E_NONE; 1997 } 1998 1999 /* 2000 * Function: 2001 * phy_54684_interface_set 2002 * Purpose: 2003 * Set the current operating mode of the PHY. 2004 * Parameters: 2005 * unit - StrataSwitch unit #. 2006 * port - StrataSwitch port #. 2007 * pif - one of SOC_PORT_IF_* 2008 * Returns: 2009 * SOC_E_NONE - success 2010 * SOC_E_UNAVAIL - unsupported interface 2011 */ 2012 2013 STATIC int 2014 phy_54684_interface_set(int unit, soc_port_t port, soc_port_if_t pif) 2015 { 2016 COMPILER_REFERENCE(unit); 2017 COMPILER_REFERENCE(port); 2018 2019 switch (pif) { 2020 case SOC_PORT_IF_SGMII: 2021 case SOC_PORT_IF_GMII: 2022 return SOC_E_NONE; 2023 default: 2024 return SOC_E_UNAVAIL; 2025 } 2026 } 2027 2028 /* 2029 * Function: 2030 * phy_54684_interface_get 2031 * Purpose: 2032 * Get the current operating mode of the PHY. 2033 * Parameters: 2034 * unit - StrataSwitch unit #. 2035 * port - StrataSwitch port #. 2036 * pif - (OUT) one of SOC_PORT_IF_* 2037 * Returns: 2038 * SOC_E_NONE 2039 */ 2040 2041 STATIC int 2042 phy_54684_interface_get(int unit, soc_port_t port, soc_port_if_t *pif) 2043 { 2044 COMPILER_REFERENCE(unit); 2045 COMPILER_REFERENCE(port); 2046 2047 *pif = SOC_PORT_IF_SGMII; 2048 2049 return SOC_E_NONE; 2050 } 2051 2052 /* 2053 * Function: 2054 * phy_54684_ability_get 2055 * Purpose: 2056 * Get the abilities of the local gigabit PHY. 2057 * Parameters: 2058 * unit - StrataSwitch unit #. 2059 * port - StrataSwitch port #. 2060 * mode - (OUT) Port mode mask indicating supported options/speeds. 2061 * Returns: 2062 * SOC_E_NONE 2063 * Notes: 2064 * The ability is retrieved only for the ACTIVE medium. 2065 */ 2066 2067 STATIC int 2068 phy_54684_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode) 2069 { 2070 int rv; 2071 phy_ctrl_t *pc; 2072 2073 rv = SOC_E_NONE; 2074 if (PHY_COPPER_MODE(unit, port)) { 2075 rv = phy_ge_ability_get(unit, port, mode); 2076 } else { /* fiber mode */ 2077 *mode = (SOC_PM_AN | SOC_PM_LB_PHY | 2078 SOC_PM_PAUSE | SOC_PM_PAUSE_ASYMM | 2079 SOC_PM_GMII | SOC_PM_SGMII | SOC_PM_1000MB_FD | 2080 SOC_PM_100MB_FD | SOC_PM_100MB_HD); 2081 } 2082 2083 pc = EXT_PHY_SW_STATE(unit, port); 2084 if (pc->automedium) { 2085 *mode |= SOC_PM_COMBO; 2086 } 2087 2088 return rv; 2089 } 2090 2091 /* 2092 * Function: 2093 * phy_54684_mdix_set 2094 * Description: 2095 * Set the Auto-MDIX mode of a port/PHY 2096 * Parameters: 2097 * unit - Device number 2098 * port - Port number 2099 * mode - One of: 2100 * SOC_PORT_MDIX_AUTO 2101 * Enable auto-MDIX when autonegotiation is enabled 2102 * SOC_PORT_MDIX_FORCE_AUTO 2103 * Enable auto-MDIX always 2104 * SOC_PORT_MDIX_NORMAL 2105 * Disable auto-MDIX 2106 * SOC_PORT_MDIX_XOVER 2107 * Disable auto-MDIX, and swap cable pairs 2108 * Return Value: 2109 * SOC_E_XXX 2110 */ 2111 STATIC int 2112 phy_54684_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode) 2113 { 2114 phy_ctrl_t *pc; 2115 int speed; 2116 2117 pc = EXT_PHY_SW_STATE(unit, port); 2118 if (PHY_COPPER_MODE(unit, port)) { 2119 switch (mode) { 2120 case SOC_PORT_MDIX_AUTO: 2121 /* Clear bit 14 for automatic MDI crossover */ 2122 SOC_IF_ERROR_RETURN 2123 (MODIFY_PHY54684_MII_ECRr(unit, pc, 0, 0x4000)); 2124 2125 /* Clear bit 9 to disable forced auto MDI xover */ 2126 SOC_IF_ERROR_RETURN 2127 (MODIFY_PHY54684_MII_MISC_CTRLr(unit, pc, 0, 0x0200)); 2128 break; 2129 2130 case SOC_PORT_MDIX_FORCE_AUTO: 2131 /* Clear bit 14 for automatic MDI crossover */ 2132 SOC_IF_ERROR_RETURN 2133 (MODIFY_PHY54684_MII_ECRr(unit, pc, 0, 0x4000)); 2134 2135 /* Set bit 9 to disable forced auto MDI xover */ 2136 SOC_IF_ERROR_RETURN 2137 (MODIFY_PHY54684_MII_MISC_CTRLr(unit, pc, 0x0200, 0x0200)); 2138 break; 2139 2140 case SOC_PORT_MDIX_NORMAL: 2141 SOC_IF_ERROR_RETURN(phy_54684_speed_get(unit, port, &speed)); 2142 if (speed == 0 || speed == 10 || speed == 100) { 2143 /* Set bit 14 for automatic MDI crossover */ 2144 SOC_IF_ERROR_RETURN 2145 (MODIFY_PHY54684_MII_ECRr(unit, pc, 0x4000, 0x4000)); 2146 2147 SOC_IF_ERROR_RETURN 2148 (WRITE_PHY54684_TEST1r(unit, pc, 0)); 2149 } else { 2150 return SOC_E_UNAVAIL; 2151 } 2152 break; 2153 2154 case SOC_PORT_MDIX_XOVER: 2155 SOC_IF_ERROR_RETURN(phy_54684_speed_get(unit, port, &speed)); 2156 if (speed == 0 || speed == 10 || speed == 100) { 2157 /* Set bit 14 for automatic MDI crossover */ 2158 SOC_IF_ERROR_RETURN 2159 (MODIFY_PHY54684_MII_ECRr(unit, pc, 0x4000, 0x4000)); 2160 2161 SOC_IF_ERROR_RETURN 2162 (WRITE_PHY54684_TEST1r(unit, pc, 0x0080)); 2163 } else { 2164 return SOC_E_UNAVAIL; 2165 } 2166 break; 2167 2168 default: 2169 return SOC_E_PARAM; 2170 } 2171 pc->copper.mdix = mode; 2172 } else { /* fiber */ 2173 if (mode != SOC_PORT_MDIX_NORMAL) { 2174 return SOC_E_UNAVAIL; 2175 } 2176 } 2177 return SOC_E_NONE; 2178 } 2179 2180 #if defined(BCM_WARM_BOOT_SUPPORT) 2181 /* 2182 * Function: 2183 * _phy_54684_mdix_wb_update 2184 * Description: 2185 * Read the hw, derive the mode and update the mdix mode in sw structure 2186 * during wb. 2187 * Parameters: 2188 * unit - (IN) Device number 2189 * port - (IN) Port number 2190 * mode - (OUT) :One of: 2191 * SOC_PORT_MDIX_AUTO 2192 * Enable auto-MDIX when autonegotiation is enabled 2193 * SOC_PORT_MDIX_FORCE_AUTO 2194 * Enable auto-MDIX always 2195 * SOC_PORT_MDIX_NORMAL 2196 * Disable auto-MDIX 2197 * SOC_PORT_MDIX_XOVER 2198 * Disable auto-MDIX, and swap cable pairs 2199 * Return Value: 2200 * SOC_E_XXX 2201 */ 2202 STATIC int 2203 _phy_54684_mdix_wb_update(int unit, soc_port_t port) 2204 { 2205 phy_ctrl_t *pc; 2206 int speed; 2207 int mode = 0; 2208 uint16 val = 0; 2209 2210 pc = EXT_PHY_SW_STATE(unit, port); 2211 2212 /* Check bit 14 for automatic MDI crossover */ 2213 SOC_IF_ERROR_RETURN (READ_PHY54684_MII_ECRr(unit, pc, &val)); 2214 if(val & 0x4000) { 2215 SOC_IF_ERROR_RETURN(phy_54684_speed_get(unit, port, &speed)); 2216 if (speed == 0 || speed == 10 || speed == 100) { 2217 SOC_IF_ERROR_RETURN (READ_PHY54684_TEST1r(unit, pc, &val)); 2218 if (0 == val) { 2219 mode = SOC_PORT_MDIX_NORMAL; 2220 } else if (0x80 == val) { 2221 mode = SOC_PORT_MDIX_XOVER; 2222 } else { 2223 return SOC_E_UNAVAIL; 2224 } 2225 } else { 2226 return SOC_E_UNAVAIL; 2227 } 2228 } else { 2229 /* Check bit 9 forced auto MDI xover */ 2230 SOC_IF_ERROR_RETURN (READ_PHY54684_MII_MISC_CTRLr(unit, pc,&val)); 2231 if (val & 0x200) { 2232 /* bit 9 Set, forced auto MDI xover */ 2233 mode = SOC_PORT_MDIX_FORCE_AUTO; 2234 } else { 2235 /* bit 9 Clear, forced auto MDI xover */ 2236 mode = SOC_PORT_MDIX_AUTO; 2237 } 2238 } 2239 pc->copper.mdix = mode; 2240 2241 return SOC_E_NONE; 2242 } 2243 #endif /* defined(BCM_WARM_BOOT_SUPPORT) */ 2244 2245 /* 2246 * Function: 2247 * phy_54684_mdix_get 2248 * Description: 2249 * Get the Auto-MDIX mode of a port/PHY 2250 * Parameters: 2251 * unit - Device number 2252 * port - Port number 2253 * mode - (Out) One of: 2254 * SOC_PORT_MDIX_AUTO 2255 * Enable auto-MDIX when autonegotiation is enabled 2256 * SOC_PORT_MDIX_FORCE_AUTO 2257 * Enable auto-MDIX always 2258 * SOC_PORT_MDIX_NORMAL 2259 * Disable auto-MDIX 2260 * SOC_PORT_MDIX_XOVER 2261 * Disable auto-MDIX, and swap cable pairs 2262 * Return Value: 2263 * SOC_E_XXX 2264 */ 2265 STATIC int 2266 phy_54684_mdix_get(int unit, soc_port_t port, soc_port_mdix_t *mode) 2267 { 2268 phy_ctrl_t *pc; 2269 int speed; 2270 2271 if (mode == NULL) { 2272 return SOC_E_PARAM; 2273 } 2274 2275 #if defined(BCM_WARM_BOOT_SUPPORT) 2276 if (SOC_WARM_BOOT(unit)) { 2277 return _phy_54684_mdix_wb_update(unit, port); 2278 } 2279 #endif /* defined(BCM_WARM_BOOT_SUPPORT) */ 2280 2281 pc = EXT_PHY_SW_STATE(unit, port); 2282 2283 if (PHY_COPPER_MODE(unit, port)) { 2284 SOC_IF_ERROR_RETURN(phy_54684_speed_get(unit, port, &speed)); 2285 if (speed == 1000) { 2286 *mode = SOC_PORT_MDIX_AUTO; 2287 } else { 2288 *mode = pc->copper.mdix; 2289 } 2290 } else { 2291 *mode = SOC_PORT_MDIX_NORMAL; 2292 } 2293 2294 return SOC_E_NONE; 2295 } 2296 2297 /* 2298 * Function: 2299 * phy_54684_mdix_status_get 2300 * Description: 2301 * Get the current MDIX status on a port/PHY 2302 * Parameters: 2303 * unit - Device number 2304 * port - Port number 2305 * status - (OUT) One of: 2306 * SOC_PORT_MDIX_STATUS_NORMAL 2307 * Straight connection 2308 * SOC_PORT_MDIX_STATUS_XOVER 2309 * Crossover has been performed 2310 * Return Value: 2311 * SOC_E_XXX 2312 */ 2313 STATIC int 2314 phy_54684_mdix_status_get(int unit, soc_port_t port, 2315 soc_port_mdix_status_t *status) 2316 { 2317 phy_ctrl_t *pc; 2318 uint16 data; 2319 2320 if (status == NULL) { 2321 return SOC_E_PARAM; 2322 } 2323 2324 pc = EXT_PHY_SW_STATE(unit, port); 2325 2326 if (PHY_COPPER_MODE(unit, port)) { 2327 SOC_IF_ERROR_RETURN 2328 (READ_PHY54684_MII_ESRr(unit, pc, &data)); 2329 if (data & 0x2000) { 2330 *status = SOC_PORT_MDIX_STATUS_XOVER; 2331 } else { 2332 *status = SOC_PORT_MDIX_STATUS_NORMAL; 2333 } 2334 } else { 2335 *status = SOC_PORT_MDIX_STATUS_NORMAL; 2336 } 2337 2338 return SOC_E_NONE; 2339 } 2340 2341 STATIC int 2342 _phy_54684_power_mode_set (int unit, soc_port_t port, int mode) 2343 { 2344 phy_ctrl_t *pc; 2345 2346 pc = EXT_PHY_SW_STATE(unit, port); 2347 2348 if (pc->power_mode == mode) { 2349 return SOC_E_NONE; 2350 } 2351 2352 if (mode == SOC_PHY_CONTROL_POWER_LOW) { 2353 /* enable dsp clock */ 2354 SOC_IF_ERROR_RETURN 2355 (MODIFY_PHY54684_MII_AUX_CTRLr(unit,pc,0x0c00,0x0c00)); 2356 2357 /* enable low power 136 */ 2358 SOC_IF_ERROR_RETURN 2359 (MODIFY_PHY54684_AUTO_POWER_DOWNr(unit,pc,0x80,0x80)); 2360 2361 /* reduce tx bias current to -20% */ 2362 SOC_IF_ERROR_RETURN 2363 (WRITE_PHY_REG(unit, pc, 0x17, 0x0f75)); 2364 SOC_IF_ERROR_RETURN 2365 (WRITE_PHY_REG(unit, pc, 0x15, 0x1555)); 2366 2367 /* disable dsp clock */ 2368 SOC_IF_ERROR_RETURN 2369 (MODIFY_PHY54684_MII_AUX_CTRLr(unit,pc,0x0400,0x0c00)); 2370 pc->power_mode = mode; 2371 2372 } else if (mode == SOC_PHY_CONTROL_POWER_FULL) { 2373 2374 /* back to normal mode */ 2375 /* enable dsp clock */ 2376 SOC_IF_ERROR_RETURN 2377 (MODIFY_PHY54684_MII_AUX_CTRLr(unit,pc,0x0c00,0x0c00)); 2378 2379 /* disable low power 136 */ 2380 SOC_IF_ERROR_RETURN 2381 (MODIFY_PHY54684_AUTO_POWER_DOWNr(unit,pc,0x00,0x80)); 2382 2383 /* set tx bias current to nominal */ 2384 SOC_IF_ERROR_RETURN 2385 (WRITE_PHY_REG(unit, pc, 0x17, 0x0f75)); 2386 SOC_IF_ERROR_RETURN 2387 (WRITE_PHY_REG(unit, pc, 0x15, 0x0)); 2388 2389 /* disable dsp clock */ 2390 SOC_IF_ERROR_RETURN 2391 (MODIFY_PHY54684_MII_AUX_CTRLr(unit,pc,0x0400,0x0c00)); 2392 2393 /* disable the auto power mode */ 2394 SOC_IF_ERROR_RETURN 2395 (MODIFY_PHY54684_AUTO_POWER_DOWNr(unit,pc, 2396 0, 2397 PHY_54684_AUTO_PWRDWN_EN)); 2398 pc->power_mode = mode; 2399 } else if (mode == SOC_PHY_CONTROL_POWER_AUTO) { 2400 SOC_IF_ERROR_RETURN 2401 (MODIFY_PHY54684_AUTO_POWER_DOWNr(unit,pc, 2402 PHY_54684_AUTO_PWRDWN_EN, 2403 PHY_54684_AUTO_PWRDWN_EN)); 2404 pc->power_mode = mode; 2405 } 2406 2407 return SOC_E_NONE; 2408 } 2409 2410 /* 2411 * Function: 2412 * phy_54684_control_set 2413 * Purpose: 2414 * Configure PHY device specific control fucntion. 2415 * Parameters: 2416 * unit - StrataSwitch unit #. 2417 * port - StrataSwitch port #. 2418 * type - Control to update 2419 * value - New setting for the control 2420 * Returns: 2421 * SOC_E_NONE 2422 */ 2423 STATIC int 2424 phy_54684_control_set(int unit, soc_port_t port, 2425 soc_phy_control_t type, uint32 value) 2426 { 2427 int rv; 2428 phy_ctrl_t *pc; 2429 uint16 data; 2430 2431 PHY_CONTROL_TYPE_CHECK(type); 2432 2433 pc = EXT_PHY_SW_STATE(unit, port); 2434 rv = SOC_E_NONE; 2435 switch(type) { 2436 case SOC_PHY_CONTROL_POWER: 2437 rv = _phy_54684_power_mode_set(unit,port,value); 2438 break; 2439 2440 case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME: 2441 if (value <= PHY_54684_AUTO_PWRDWN_WAKEUP_MAX) { 2442 2443 /* at least one unit */ 2444 if (value < PHY_54684_AUTO_PWRDWN_WAKEUP_UNIT) { 2445 value = PHY_54684_AUTO_PWRDWN_WAKEUP_UNIT; 2446 } 2447 } else { /* anything more then max, set to the max */ 2448 value = PHY_54684_AUTO_PWRDWN_WAKEUP_MAX; 2449 } 2450 SOC_IF_ERROR_RETURN 2451 (MODIFY_PHY54684_AUTO_POWER_DOWNr(unit,pc, 2452 value/PHY_54684_AUTO_PWRDWN_WAKEUP_UNIT, 2453 PHY_54684_AUTO_PWRDWN_WAKEUP_MASK)); 2454 break; 2455 2456 case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME: 2457 /* sleep time configuration is either 2.7s or 5.4 s, default is 2.7s */ 2458 if (value < PHY_54684_AUTO_PWRDWN_SLEEP_MAX) { 2459 data = 0; /* anything less than 5.4s, default to 2.7s */ 2460 } else { 2461 data = PHY_54684_AUTO_PWRDWN_SLEEP_MASK; 2462 } 2463 SOC_IF_ERROR_RETURN 2464 (MODIFY_PHY54684_AUTO_POWER_DOWNr(unit,pc, 2465 data, 2466 PHY_54684_AUTO_PWRDWN_SLEEP_MASK)); 2467 break; 2468 2469 default: 2470 rv = SOC_E_UNAVAIL; 2471 break; 2472 } 2473 return rv; 2474 } 2475 /* 2476 * Function: 2477 * phy_54684_control_get 2478 * Purpose: 2479 * Get current control settign of the PHY. 2480 * Parameters: 2481 * unit - StrataSwitch unit #. 2482 * port - StrataSwitch port #. 2483 * type - Control to update 2484 * value - (OUT)Current setting for the control 2485 * Returns: 2486 * SOC_E_NONE 2487 */ 2488 STATIC int 2489 phy_54684_control_get(int unit, soc_port_t port, 2490 soc_phy_control_t type, uint32 *value) 2491 { 2492 int rv; 2493 phy_ctrl_t *pc; 2494 uint16 data; 2495 2496 PHY_CONTROL_TYPE_CHECK(type); 2497 2498 pc = EXT_PHY_SW_STATE(unit, port); 2499 rv = SOC_E_NONE; 2500 switch(type) { 2501 case SOC_PHY_CONTROL_POWER: 2502 *value = pc->power_mode; 2503 break; 2504 2505 case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME: 2506 SOC_IF_ERROR_RETURN 2507 (READ_PHY54684_AUTO_POWER_DOWNr(unit,pc, &data)); 2508 2509 if (data & PHY_54684_AUTO_PWRDWN_SLEEP_MASK) { 2510 *value = PHY_54684_AUTO_PWRDWN_SLEEP_MAX; 2511 } else { 2512 *value = 2700; 2513 } 2514 break; 2515 2516 case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME: 2517 SOC_IF_ERROR_RETURN 2518 (READ_PHY54684_AUTO_POWER_DOWNr(unit,pc, &data)); 2519 2520 data &= PHY_54684_AUTO_PWRDWN_WAKEUP_MASK; 2521 *value = data * PHY_54684_AUTO_PWRDWN_WAKEUP_UNIT; 2522 break; 2523 2524 default: 2525 rv = SOC_E_UNAVAIL; 2526 break; 2527 } 2528 return rv; 2529 } 2530 2531 /* 2532 * Function: 2533 * phy_54684_cable_diag 2534 * Purpose: 2535 * Run 546x cable diagnostics 2536 * Parameters: 2537 * unit - device number 2538 * port - port number 2539 * status - (OUT) cable diagnotic status structure 2540 * Returns: 2541 * SOC_E_XXX 2542 */ 2543 STATIC int 2544 phy_54684_cable_diag(int unit, soc_port_t port, 2545 soc_port_cable_diag_t *status) 2546 { 2547 int rv=SOC_E_NONE, rv2, i; 2548 2549 extern int phy_5464_cable_diag_sw(int, soc_port_t , 2550 soc_port_cable_diag_t *); 2551 2552 if (status == NULL) { 2553 return SOC_E_PARAM; 2554 } 2555 2556 status->state = SOC_PORT_CABLE_STATE_OK; 2557 status->npairs = 4; 2558 status->fuzz_len = 0; 2559 for (i = 0; i < 4; i++) { 2560 status->pair_state[i] = SOC_PORT_CABLE_STATE_OK; 2561 } 2562 2563 MIIM_LOCK(unit); /* this locks out linkscan, essentially */ 2564 rv = phy_5464_cable_diag_sw(unit,port, status); 2565 MIIM_UNLOCK(unit); 2566 rv2 = 0; 2567 if (rv <= 0) { /* don't reset if > 0 -- link was up */ 2568 rv2 = _phy_54684_reset_setup(unit, port); 2569 } 2570 if (rv >= 0 && rv2 < 0) { 2571 return rv2; 2572 } 2573 return rv; 2574 } 2575 2576 #ifdef BROADCOM_DEBUG 2577 2578 /* 2579 * Function: 2580 * phy_54684_shadow_dump 2581 * Purpose: 2582 * Debug routine to dump all shadow registers. 2583 * Parameters: 2584 * unit - StrataSwitch unit #. 2585 * port - StrataSwitch port #. 2586 */ 2587 2588 void 2589 phy_54684_shadow_dump(int unit, soc_port_t port) 2590 { 2591 phy_ctrl_t *pc; 2592 uint16 tmp; 2593 int i; 2594 2595 pc = EXT_PHY_SW_STATE(unit, port); 2596 2597 /* Register 0x18 Shadows */ 2598 for (i = 0; i <= 7; i++) { 2599 WRITE_PHY_REG(unit, pc, 0x18, (i << 12) | 0x7); 2600 READ_PHY_REG(unit, pc, 0x18, &tmp); 2601 if ((tmp & ~7) == 0x0000) { 2602 continue; 2603 } 2604 LOG_CLI((BSL_META_U(unit, 2605 "0x18[0x%x]=0x%04x\n"), i, tmp)); 2606 } 2607 2608 /* Register 0x1c Shadows */ 2609 for (i = 0; i <= 0x1f; i++) { 2610 WRITE_PHY_REG(unit, pc, 0x1c, i << 10); 2611 READ_PHY_REG(unit, pc, 0x1c, &tmp); 2612 if ((tmp & ~0x7c00) == 0x0000) { 2613 continue; 2614 } 2615 LOG_CLI((BSL_META_U(unit, 2616 "0x1c[0x%x]=0x%04x\n"), i, tmp)); 2617 } 2618 2619 /* Register 0x17/0x15 Shadows */ 2620 for (i = 0; i <= 0x13; i++) { 2621 WRITE_PHY_REG(unit, pc, 0x17, 0xf00 | i); 2622 READ_PHY_REG(unit, pc, 0x15, &tmp); 2623 if (tmp == 0x0000) { 2624 continue; 2625 } 2626 LOG_CLI((BSL_META_U(unit, 2627 "0x17[0x%x]=0x%04x\n"), i, tmp)); 2628 } 2629 } 2630 2631 #endif /* BROADCOM_DEBUG */ 2632 2633 /* 2634 * Variable: phy_54684drv_ge 2635 * Purpose: PHY driver for 54684 2636 */ 2637 2638 phy_driver_t phy_54684drv_ge = { 2639 "54684 Gigabit PHY Driver", 2640 phy_54684_init, 2641 phy_fe_ge_reset, 2642 phy_54684_link_get, 2643 phy_54684_enable_set, 2644 phy_54684_enable_get, 2645 phy_54684_duplex_set, 2646 phy_54684_duplex_get, 2647 phy_54684_speed_set, 2648 phy_54684_speed_get, 2649 phy_54684_master_set, 2650 phy_54684_master_get, 2651 phy_54684_autoneg_set, 2652 phy_54684_autoneg_get, 2653 phy_54684_adv_local_set, 2654 phy_54684_adv_local_get, 2655 phy_54684_adv_remote_get, 2656 phy_54684_lb_set, 2657 phy_54684_lb_get, 2658 phy_54684_interface_set, 2659 phy_54684_interface_get, 2660 phy_54684_ability_get, 2661 NULL, /* Phy link up event */ 2662 NULL, /* Phy link down event */ 2663 phy_54684_mdix_set, 2664 phy_54684_mdix_get, 2665 phy_54684_mdix_status_get, 2666 phy_54684_medium_config_set, 2667 phy_54684_medium_config_get, 2668 phy_54684_medium_status, 2669 phy_54684_cable_diag, 2670 NULL, /* phy_link_change */ 2671 phy_54684_control_set, /* phy_control_set */ 2672 phy_54684_control_get, /* phy_control_get */ 2673 phy_ge_reg_read, 2674 phy_ge_reg_write, 2675 phy_ge_reg_modify, 2676 NULL /* Phy event notify */ 2677 }; 2678 2679 #else /* INCLUDE_PHY_54684 */ 2680 int _soc_phy_54684_not_empty; 2681 #endif /* INCLUDE_PHY_54684 */ 2682