xgxs6.c (40596B)
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: xgxs6.c 8 * Purpose: Broadcom 10/100/1000/2500/10000/12000/13000/16000 SerDes 9 * (SerDes-XGXS6/Unicore) 10 */ 11 12 #include <sal/types.h> 13 14 #include <sal/types.h> 15 #include <sal/core/spl.h> 16 #include <shared/bsl.h> 17 #include <soc/drv.h> 18 #include <soc/debug.h> 19 #include <soc/error.h> 20 #include <soc/phyreg.h> 21 22 #include <soc/phy.h> 23 #include <soc/phy/phyctrl.h> 24 #include <soc/phy/drv.h> 25 26 #include "phydefs.h" /* Must include before other phy related includes */ 27 28 #if defined(INCLUDE_PHY_XGXS6) 29 #include "phyconfig.h" /* Must include before other phy related includes */ 30 #include "phyident.h" 31 #include "phyreg.h" 32 #include "phynull.h" 33 #include "xgxs.h" 34 #include "xgxs6.h" 35 36 #define XGXS6_PLL_WAIT 250000 37 38 STATIC int phy_xgxs6_lb_set(int unit, soc_port_t port, int enable); 39 STATIC int phy_xgxs6_an_set(int unit, soc_port_t port, int an); 40 STATIC int phy_xgxs6_an_get(int unit, soc_port_t port, int *an, int *an_done); 41 STATIC int phy_xgxs6_speed_get(int unit, soc_port_t port, int *speed); 42 43 STATIC int 44 _phy_xgxs6_pll_lock_wait(int unit, soc_port_t port) 45 { 46 uint16 data16; 47 phy_ctrl_t *pc; 48 soc_timeout_t to; 49 int rv; 50 51 pc = INT_PHY_SW_STATE(unit, port); 52 soc_timeout_init(&to, XGXS6_PLL_WAIT, 0); 53 do { 54 rv = READ_PHYXGXS6_BLK0_STATr(unit, pc, &data16); 55 if ((data16 & XGXSBLK0_XGXSSTATUS_TXPLL_LOCK) || 56 SOC_FAILURE(rv)) { 57 break; 58 } 59 } while (!soc_timeout_check(&to)); 60 if ((data16 & XGXSBLK0_XGXSSTATUS_TXPLL_LOCK) == 0) { 61 LOG_WARN(BSL_LS_SOC_PHY, 62 (BSL_META_U(unit, 63 "XGXS6 : TXPLL did not lock: u=%d p=%d\n"), 64 unit, port)); 65 return (SOC_E_TIMEOUT); 66 } 67 return (SOC_E_NONE); 68 } 69 70 /* 71 * Function: 72 * phy_xgxs6_init 73 * Purpose: 74 * Initialize xgxs6 phys 75 * Parameters: 76 * unit - StrataSwitch unit #. 77 * port - StrataSwitch port #. 78 * Returns: 79 * SOC_E_NONE 80 */ 81 82 STATIC int 83 phy_xgxs6_init(int unit, soc_port_t port) 84 { 85 int rv; /* Return value */ 86 uint16 mii_ctrl; 87 phy_ctrl_t *pc; 88 89 /* NOTE: FusionCore/Unicore init is performed in BigMAC init */ 90 91 /* clear loopback (just in case) */ 92 rv = phy_xgxs6_lb_set(unit, port, FALSE); 93 94 /* Initialize the software state */ 95 pc = INT_PHY_SW_STATE(unit, port); 96 97 SOC_IF_ERROR_RETURN 98 (READ_PHYXGXS6_SERDES_MII_CTRLr(unit, pc, &mii_ctrl)); 99 pc->fiber.autoneg_enable = ((mii_ctrl & MII_CTRL_AE) != 0); 100 101 /* set elasticity fifo size to 13.5k to support 12k jumbo pkt size*/ 102 SOC_IF_ERROR_RETURN 103 (MODIFY_PHYXGXS6_SERDES_DIGITAL_1000X_CTRL3r(unit,pc, 0x4, 0x6)); 104 105 /* disable in-band MDIO. PHY-443 */ 106 SOC_IF_ERROR_RETURN 107 (PHYXGXS6_REG_MODIFY(unit, pc, 0x00, 0x8110, 0x11, 1 << 3, 1 << 3)); 108 109 LOG_INFO(BSL_LS_SOC_PHY, 110 (BSL_META_U(unit, 111 "phy_xgxs6_init: u=%d p=%d rv=%d\n"), 112 unit, port, rv)); 113 114 return rv; 115 } 116 117 /* 118 * Function: 119 * phy_xgxs6_link_get 120 * Purpose: 121 * Get layer2 connection status. 122 * Parameters: 123 * unit - StrataSwitch unit #. 124 * port - StrataSwitch port #. 125 * link - address of memory to store link up/down state. 126 * Returns: 127 * SOC_E_NONE 128 */ 129 130 STATIC int 131 phy_xgxs6_link_get(int unit, soc_port_t port, int *link) 132 { 133 phy_ctrl_t *pc; 134 135 if (PHY_DISABLED_MODE(unit, port)) { 136 *link = FALSE; 137 return SOC_E_NONE; 138 } 139 140 pc = INT_PHY_SW_STATE(unit, port); 141 if (IS_LMD_ENABLED_PORT(unit, port)) { 142 uint16 o_misctrl1; 143 uint16 n_misctrl1; 144 uint16 sync_stat; 145 146 147 SOC_IF_ERROR_RETURN /* Get mdio reg mapping mode */ 148 (READ_PHYXGXS6_BLK0_MISC_CTRL1r(unit, pc, &o_misctrl1)); 149 n_misctrl1 = 0x0000; 150 if (n_misctrl1 != o_misctrl1) { 151 SOC_IF_ERROR_RETURN 152 (WRITE_PHYXGXS6_BLK0_MISC_CTRL1r(unit, pc, n_misctrl1)); 153 } 154 SOC_IF_ERROR_RETURN 155 (READ_PHYXGXS6_IEEE1_LANE_STATr(unit, pc, &sync_stat)); 156 157 if (n_misctrl1 != o_misctrl1) { /* Restore PMA/PMD mdio reg mapping */ 158 SOC_IF_ERROR_RETURN 159 (WRITE_PHYXGXS6_BLK0_MISC_CTRL1r(unit, pc, o_misctrl1)); 160 } 161 162 *link = (sync_stat & 1) ? TRUE : FALSE; 163 } else { 164 uint16 mii_serdes_stat; 165 uint16 mii_xaui_stat; 166 uint16 xgxs_stat1; 167 int an_done; 168 169 /* Link status on both SERDES_MII_STAT and XAUI_MII_STAT registers 170 * are latched low. 171 */ 172 SOC_IF_ERROR_RETURN 173 (READ_PHYXGXS6_SERDES_MII_STATr(unit, pc, &mii_serdes_stat)); 174 SOC_IF_ERROR_RETURN 175 (READ_PHYXGXS6_XAUI_MII_STATr(unit, pc, &mii_xaui_stat)); 176 177 *link = ((mii_serdes_stat & MII_STAT_LA) != 0) || 178 ((mii_xaui_stat & MII_STAT_LA) != 0); 179 180 if (pc->fiber.autoneg_enable) { 181 SOC_IF_ERROR_RETURN 182 (READ_PHYXGXS6_GPSTAT_XGXS_STAT1r(unit, pc, &xgxs_stat1)); 183 /* If autoneg is enabled, check for autoneg done. */ 184 an_done = ((xgxs_stat1 & XGXS_STAT1_AUTONEG_DONE) != 0); 185 186 *link = (*link) && (an_done); 187 } 188 } 189 190 return SOC_E_NONE; 191 } 192 193 STATIC int 194 _phy_xgxs6_enable_set(int unit, soc_port_t port, int enable) 195 { 196 uint16 disable_tx_xe; 197 uint16 disable_tx_hg; 198 phy_ctrl_t *pc; 199 200 pc = INT_PHY_SW_STATE(unit, port); 201 202 /* PMA/PMD mapping are different between HG and XE ports. 203 * Therefore, we need two different settings for HG and XE ports. 204 */ 205 if (enable) { 206 disable_tx_xe = 0; /* Clear Tx disable bit for XE*/ 207 disable_tx_hg = 0; /* Clear Tx disable bit for HG*/ 208 } else { 209 disable_tx_xe = (1 << 0); /* Set disable Global PMD TX bit for XE */ 210 disable_tx_hg = (1 << 11); /* Set disable Global PMD TX bit for HG */ 211 } 212 213 if (IS_XE_PORT(unit, port)) { 214 SOC_IF_ERROR_RETURN 215 (MODIFY_PHYXGXS6_XAUI_TX_DISABLEr(unit, pc, disable_tx_xe, 1 << 0)); 216 } else { 217 SOC_IF_ERROR_RETURN 218 (MODIFY_PHYXGXS6_BLK0_MISC_CTRL1r(unit, pc, disable_tx_hg, 219 (1 << 11))); 220 } 221 222 /* hold/release rxSeqStart to disable/enable the Rx */ 223 SOC_IF_ERROR_RETURN 224 (MODIFY_PHYXGXS6_RXALL_CTRLr(unit, pc, 225 (enable) ? 0 : (1 << 15), (1 << 15))); 226 227 228 return SOC_E_NONE; 229 } 230 231 232 /* 233 * Function: 234 * phy_xgxs6_enable_set 235 * Purpose: 236 * Enable/Disable phy 237 * Parameters: 238 * unit - StrataSwitch unit #. 239 * port - StrataSwitch port #. 240 * enable - on/off state to set 241 * Returns: 242 * SOC_E_NONE 243 */ 244 245 STATIC int 246 phy_xgxs6_enable_set(int unit, soc_port_t port, int enable) 247 { 248 if (enable) { 249 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE); 250 } else { 251 PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE); 252 } 253 return _phy_xgxs6_enable_set(unit,port,enable); 254 } 255 256 /* 257 * Function: 258 * _phy_xgxs6_speed_set 259 * Purpose: 260 * Get current Unicore speed. 261 * Parameters: 262 * unit - XGS unit #. 263 * port - Port number on unit. 264 * speed - new XGXS speed. 265 * Returns: 266 * SOC_E_XXX 267 * Notes: 268 * The Start Sequencer bit in the xgxsControl register should 269 * be deasserted before calling this function to guarantee a 270 * glitch-free clock change. 271 */ 272 STATIC int 273 _phy_xgxs6_speed_set(int unit, soc_port_t port, int speed) 274 { 275 int speed_val; 276 uint8 phy_addr = PORT_TO_PHY_ADDR_INT(unit, port); 277 uint16 mii_ctrl, misc1, misc_ctrl; 278 uint16 block_select; 279 280 if (IS_HG_PORT(unit, port)) { 281 if ((speed != 0) && (speed < 10000)) { 282 return SOC_E_PARAM; 283 } 284 if (SOC_INFO(unit).port_speed_max[port] > 0 && 285 speed > SOC_INFO(unit).port_speed_max[port]) { 286 return SOC_E_PARAM; 287 } 288 } else if (IS_XE_PORT(unit, port)) { 289 if ((speed != 0) && ((speed < 1000) || (speed > 10000))) { 290 return SOC_E_PARAM; 291 } 292 } else { 293 if ((speed < 0) || (speed > 2500)) { 294 return SOC_E_PARAM; 295 } 296 } 297 298 switch (speed) { 299 case 13000: 300 speed_val = 7; 301 break; 302 case 12500: 303 speed_val = 6; 304 break; 305 case 12000: 306 speed_val = 5; 307 break; 308 case 10000: 309 speed_val = 4; /* 10G CX4 */ 310 if (IS_HG_PORT(unit, port) && 311 soc_property_port_get(unit, port, spn_10G_IS_CX4, TRUE) == FALSE) { 312 speed_val = 3; /* 10G HiG */ 313 } 314 break; 315 case 2500: 316 speed_val = 0; 317 break; 318 case 1000: 319 case 100: 320 case 10: 321 speed_val = -1; 322 break; 323 case 0: 324 return SOC_E_NONE; 325 case 16000: 326 case 15000: 327 case 6000: 328 case 5000: 329 default: 330 return SOC_E_PARAM; 331 } 332 333 /* Save original block select mapping */ 334 SOC_IF_ERROR_RETURN 335 (soc_miim_read(unit, phy_addr, 0x1f, &block_select)); 336 337 /* Select block DIGITAL (0x30) */ 338 SOC_IF_ERROR_RETURN 339 (soc_miim_write(unit, phy_addr, 0x1f, 0x0300)); 340 341 /* Set speed in Misc1 register */ 342 SOC_IF_ERROR_RETURN 343 (soc_miim_read(unit, phy_addr, 0x18, &misc1)); 344 misc1 &= ~0x001f; 345 if (speed_val >= 0) { 346 misc1 |= 0x0010 | speed_val; 347 } 348 SOC_IF_ERROR_RETURN 349 (soc_miim_write(unit, phy_addr, 0x18, misc1)); 350 351 /* Select block BLOCK0 */ 352 SOC_IF_ERROR_RETURN 353 (soc_miim_write(unit, phy_addr, 0x1f, 0x0000)); 354 355 /* Map XAUI or SerDes IEEE registers */ 356 SOC_IF_ERROR_RETURN 357 (soc_miim_read(unit, phy_addr, 0x1e, &misc_ctrl)); 358 /* Disable dynamic IEEE address space mapping and 359 * map Serdes IEEE address space. 360 */ 361 misc_ctrl &= ~0x0003; 362 if (speed > 2500) { 363 misc_ctrl |= 0x0001; /* Select XAUI registers */ 364 } 365 366 /* Write final IEEE register mapping */ 367 SOC_IF_ERROR_RETURN 368 (soc_miim_write(unit, phy_addr, 0x1e, misc_ctrl)); 369 370 /* 371 * Speeds of 2.5 Gbps and below must be set in IEEE registers. 372 */ 373 if (speed <= 2500) { 374 SOC_IF_ERROR_RETURN 375 (soc_miim_read(unit, phy_addr, MII_CTRL_REG, &mii_ctrl)); 376 mii_ctrl &= ~(MII_CTRL_SS_MASK | MII_CTRL_FS_2500); 377 if (speed == 2500) { 378 /* Force 2.5 Gbps */ 379 mii_ctrl |= MII_CTRL_FS_2500; 380 } else if (speed == 1000) { 381 mii_ctrl |= MII_CTRL_SS_1000; 382 } else if (speed == 100) { 383 mii_ctrl |= MII_CTRL_SS_100; 384 } else { 385 mii_ctrl |= MII_CTRL_SS_10; 386 } 387 SOC_IF_ERROR_RETURN 388 (soc_miim_write(unit, phy_addr, MII_CTRL_REG, mii_ctrl)); 389 } 390 391 /* Restore Original Block select mapping */ 392 SOC_IF_ERROR_RETURN 393 (soc_miim_write(unit, phy_addr, 0x1f, block_select)); 394 395 return SOC_E_NONE; 396 } 397 /* 398 * Function: 399 * phy_xgxs6_speed_set 400 * Purpose: 401 * Set PHY speed 402 * Parameters: 403 * unit - StrataSwitch unit #. 404 * port - StrataSwitch port #. 405 * speed - link speed in Mbps 406 * Returns: 407 * SOC_E_NONE 408 */ 409 410 STATIC int 411 phy_xgxs6_speed_set(int unit, soc_port_t port, int speed) 412 { 413 int rv; 414 int an; 415 int cur_speed; 416 phy_ctrl_t *pc; 417 418 /* If already forced to requested speed, don't change anything */ 419 SOC_IF_ERROR_RETURN 420 (phy_xgxs6_an_get(unit, port, &an, NULL)); 421 if (!an) { 422 SOC_IF_ERROR_RETURN 423 (phy_xgxs6_speed_get(unit, port, &cur_speed)); 424 if (cur_speed == speed) { 425 return SOC_E_NONE; 426 } 427 } 428 429 rv = SOC_E_NONE; 430 pc = INT_PHY_SW_STATE(unit, port); 431 432 /* Stop sequencer */ 433 SOC_IF_ERROR_RETURN 434 (MODIFY_PHYXGXS6_BLK0_CTRLr(unit, pc, 0, 0x2000)); 435 436 /* Disable autoneg if needed */ 437 if (an) { 438 rv = (phy_xgxs6_an_set(unit, port, FALSE)); 439 } 440 441 if (SOC_SUCCESS(rv)) { 442 rv = _phy_xgxs6_speed_set(unit, port, speed); 443 } 444 445 /* Need to restart sequencer even if speed_set failed */ 446 SOC_IF_ERROR_RETURN 447 (MODIFY_PHYXGXS6_BLK0_CTRLr(unit, pc, 0x2000, 0x2000)); 448 449 /* Wait for Tx PLL lock */ 450 if (SOC_SUCCESS(rv)) { 451 rv = _phy_xgxs6_pll_lock_wait(unit, port); 452 } 453 454 return rv; 455 } 456 457 /* 458 * Function: 459 * phy_xgxs6_speed_get 460 * Purpose: 461 * Get PHY speed 462 * Parameters: 463 * unit - StrataSwitch unit #. 464 * port - StrataSwitch port #. 465 * speed - current link speed in Mbps 466 * Returns: 467 * SOC_E_NONE 468 */ 469 STATIC int 470 phy_xgxs6_speed_get(int unit, soc_port_t port, int *speed) 471 { 472 uint16 xgxs_stat; 473 int an; 474 int an_done; 475 phy_ctrl_t *pc; 476 477 /* Default speed */ 478 *speed = 10000; 479 480 pc = INT_PHY_SW_STATE(unit, port); 481 482 SOC_IF_ERROR_RETURN 483 (phy_xgxs6_an_get(unit, port, &an, &an_done)); 484 if (an && !an_done) { 485 *speed = 0; 486 return (SOC_E_NONE); 487 } 488 489 SOC_IF_ERROR_RETURN 490 (READ_PHYXGXS6_GPSTAT_XGXS_STAT1r(unit, pc, &xgxs_stat)); 491 switch (xgxs_stat & XGXS_STAT1_ACTUAL_SPEED_MASK) { 492 case XGXS_STAT1_ACTUAL_SPEED_10: *speed = 10; break; 493 case XGXS_STAT1_ACTUAL_SPEED_100: *speed = 100; break; 494 case XGXS_STAT1_ACTUAL_SPEED_1000: *speed = 1000; break; 495 case XGXS_STAT1_ACTUAL_SPEED_2500: *speed = 2500; break; 496 case XGXS_STAT1_ACTUAL_SPEED_5000: *speed = 5000; break; 497 case XGXS_STAT1_ACTUAL_SPEED_6000: *speed = 6000; break; 498 case XGXS_STAT1_ACTUAL_SPEED_10000: /* fall through */ 499 case XGXS_STAT1_ACTUAL_SPEED_10000CX4: *speed = 10000; break; 500 case XGXS_STAT1_ACTUAL_SPEED_12000: *speed = 12000; break; 501 case XGXS_STAT1_ACTUAL_SPEED_12500: *speed = 12500; break; 502 case XGXS_STAT1_ACTUAL_SPEED_13000: *speed = 13000; break; 503 case XGXS_STAT1_ACTUAL_SPEED_15000: *speed = 15000; break; 504 case XGXS_STAT1_ACTUAL_SPEED_16000: *speed = 16000; break; 505 default: 506 return SOC_E_INTERNAL; 507 } 508 509 return SOC_E_NONE; 510 } 511 512 /* 513 * Function: 514 * phy_xgxs6_an_set 515 * Purpose: 516 * Enable or disabled auto-negotiation on the specified port. 517 * Parameters: 518 * unit - StrataSwitch unit #. 519 * port - StrataSwitch port #. 520 * an - Boolean, if true, auto-negotiation is enabled 521 * (and/or restarted). If false, autonegotiation is disabled. 522 * Returns: 523 * SOC_E_XXX 524 */ 525 int 526 phy_xgxs6_an_set(int unit, soc_port_t port, int an) 527 { 528 int rv; 529 uint16 mii_ctrl; 530 uint16 xgxs_ctrl; 531 uint16 mreg_val; 532 phy_ctrl_t *pc; 533 534 rv = SOC_E_NONE; 535 pc = INT_PHY_SW_STATE(unit, port); 536 537 /* 538 * Configure signal auto-detection between SGMII and fiber. 539 * This detection only works if auto-negotiation is enabled. 540 */ 541 SOC_IF_ERROR_RETURN 542 (READ_PHYXGXS6_SERDES_DIGITAL_1000X_CTRL1r(unit, pc, &mreg_val)); 543 544 mreg_val &= ~(1 << 4); /* Clear auto-detect */ 545 if (an) { 546 if (soc_property_port_get(unit, port, 547 spn_SERDES_AUTOMEDIUM, TRUE)) { 548 mreg_val |= (1 << 4); /* Set auto-detect */ 549 } 550 } 551 SOC_IF_ERROR_RETURN 552 (WRITE_PHYXGXS6_SERDES_DIGITAL_1000X_CTRL1r(unit, pc, mreg_val)); 553 554 /* Stop sequencer */ 555 SOC_IF_ERROR_RETURN 556 (READ_PHYXGXS6_BLK0_CTRLr(unit, pc, &xgxs_ctrl)); 557 SOC_IF_ERROR_RETURN 558 (WRITE_PHYXGXS6_BLK0_CTRLr(unit, pc, xgxs_ctrl & ~0x2000)); 559 560 /* Autoneg enable bit in SerDes block is for both SerDes 561 * and XAUI core */ 562 mii_ctrl = (an) ? MII_CTRL_AE | MII_CTRL_RAN : 0; 563 rv = MODIFY_PHYXGXS6_SERDES_MII_CTRLr(unit, pc, mii_ctrl, 564 MII_CTRL_AE | MII_CTRL_RAN); 565 566 /* Restore sequencer */ 567 SOC_IF_ERROR_RETURN 568 (WRITE_PHYXGXS6_BLK0_CTRLr(unit, pc, xgxs_ctrl)); 569 570 if (rv < 0) { 571 return rv; 572 } 573 574 /* Wait for Tx PLL lock if sequencer was restarted */ 575 if (xgxs_ctrl & 0x2000) { 576 rv = _phy_xgxs6_pll_lock_wait(unit, port); 577 } 578 579 /* Save autoneg state in software */ 580 pc->fiber.autoneg_enable = an; 581 582 return rv; 583 } 584 585 /* 586 * Function: 587 * phy_xgxs6_an_get 588 * Purpose: 589 * Get the current auto-negotiation status (enabled/busy) 590 * Parameters: 591 * unit - StrataSwitch unit #. 592 * port - StrataSwitch port #. 593 * an - (OUT) if true, auto-negotiation is enabled. 594 * an_done - (OUT) if true, auto-negotiation is complete. This 595 * value is undefined if an == false. 596 * Returns: 597 * SOC_E_XXX 598 */ 599 600 int 601 phy_xgxs6_an_get(int unit, soc_port_t port, int *an, int *an_done) 602 { 603 uint16 mii_ctrl; 604 uint16 mii_stat; 605 phy_ctrl_t *pc; 606 607 pc = INT_PHY_SW_STATE(unit, port); 608 609 SOC_IF_ERROR_RETURN 610 (READ_PHYXGXS6_SERDES_MII_CTRLr(unit, pc, &mii_ctrl)); 611 SOC_IF_ERROR_RETURN 612 (READ_PHYXGXS6_SERDES_MII_STATr(unit, pc, &mii_stat)); 613 614 *an = (mii_ctrl & MII_CTRL_AE) ? TRUE : FALSE; 615 616 if (NULL != an_done) { 617 *an_done = (mii_stat & MII_STAT_AN_DONE) ? TRUE : FALSE; 618 } 619 620 return SOC_E_NONE; 621 } 622 623 /* 624 * Function: 625 * phy_xgxs6_adv_local_set 626 * Purpose: 627 * Set the current advertisement for auto-negotiation. 628 * Parameters: 629 * unit - StrataSwitch unit #. 630 * port - StrataSwitch port #. 631 * mode - Port mode mask indicating supported options/speeds. 632 * Returns: 633 * SOC_E_XXX 634 * Notes: 635 * The advertisement is set only for the ACTIVE medium. 636 * No synchronization performed at this level. 637 */ 638 639 STATIC int 640 phy_xgxs6_adv_local_set(int unit, soc_port_t port, soc_port_mode_t mode) 641 { 642 uint16 an_adv; 643 uint16 speed_10g; 644 phy_ctrl_t *pc; 645 646 pc = INT_PHY_SW_STATE(unit, port); 647 648 /* 649 * Set advertised duplex (only FD supported). 650 */ 651 an_adv = (mode & SOC_PM_1000MB_FD) ? XGXS6_ANA_FD : 0; 652 653 /* 654 * Set advertised pause bits in link code word. 655 */ 656 switch (mode & SOC_PM_PAUSE) { 657 case SOC_PM_PAUSE_TX: 658 an_adv |= XGXS6_ANA_PAUSE_ASYM; 659 break; 660 case SOC_PM_PAUSE_RX: 661 an_adv |= XGXS6_ANA_PAUSE_SYM | XGXS6_ANA_PAUSE_ASYM; 662 break; 663 case SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX: 664 an_adv |= XGXS6_ANA_PAUSE_SYM; 665 break; 666 } 667 668 /* Update less than 1G capability */ 669 SOC_IF_ERROR_RETURN 670 (WRITE_PHYXGXS6_SERDES_MII_ANAr(unit, pc, an_adv)); 671 672 /* Over 1G advertising */ 673 if (IS_HG_PORT(unit, port)) { 674 /* For Draco and Hercules, use pre-CX4 signalling */ 675 speed_10g = (1 << 3); 676 if (soc_property_port_get(unit, port, spn_10G_IS_CX4, TRUE)) { 677 /* Also include 10G CX4 signalling by default */ 678 speed_10g |= (1 << 4); 679 } 680 681 /* Advertise 10G */ 682 an_adv = (mode & SOC_PM_10GB) ? speed_10g : 0; 683 an_adv |= (mode & SOC_PM_12GB) ? (1 << 5) : 0; 684 an_adv |= (mode & SOC_PM_13GB) ? (1 << 7) : 0; 685 } else { 686 /* Advertise 10G CX4 */ 687 an_adv = (mode & SOC_PM_10GB) ? (1 << 4) : 0; 688 an_adv |= (mode & SOC_PM_2500MB) ? (1 << 0) : 0; 689 } 690 SOC_IF_ERROR_RETURN 691 (WRITE_PHYXGXS6_OVER1G_UP1r(unit, pc, an_adv)); 692 693 LOG_INFO(BSL_LS_SOC_PHY, 694 (BSL_META_U(unit, 695 "phy_xgxs6_adv_local_set:unit=%d p=%d mode=0x%08x\n"), 696 unit, port, mode)); 697 698 return SOC_E_NONE; 699 } 700 701 /* 702 * Function: 703 * phy_xgxs6_adv_local_get 704 * Purpose: 705 * Get the current advertisement for auto-negotiation. 706 * Parameters: 707 * unit - StrataSwitch unit #. 708 * port - StrataSwitch port #. 709 * mode - (OUT) Port mode mask indicating supported options/speeds. 710 * Returns: 711 * SOC_E_XXX 712 * Notes: 713 * The advertisement is retrieved for the ACTIVE medium. 714 * No synchronization performed at this level. 715 */ 716 717 STATIC int 718 phy_xgxs6_adv_local_get(int unit, soc_port_t port, soc_port_mode_t *mode) 719 { 720 uint16 an_adv; 721 phy_ctrl_t *pc; 722 723 pc = INT_PHY_SW_STATE(unit, port); 724 725 SOC_IF_ERROR_RETURN 726 (READ_PHYXGXS6_OVER1G_UP1r(unit, pc, &an_adv)); 727 728 *mode = 0; 729 if (IS_HG_PORT(unit, port)) { 730 *mode = (an_adv & ((1 << 3) | (1 << 4))) ? SOC_PM_10GB_FD : 0; 731 *mode |= (an_adv & (1 << 5)) ? SOC_PM_12GB_FD : 0; 732 *mode |= (an_adv & (1 << 7)) ? SOC_PM_13GB_FD : 0; 733 } else { 734 *mode = (an_adv & (1 << 4)) ? SOC_PM_10GB_FD : 0; 735 *mode |= (an_adv & (1 << 0)) ? SOC_PM_2500MB_FD : 0; 736 737 SOC_IF_ERROR_RETURN 738 (READ_PHYXGXS6_SERDES_MII_ANAr(unit, pc, &an_adv)); 739 740 *mode |= (an_adv & XGXS6_ANA_FD) ? SOC_PM_1000MB_FD : 0; 741 742 switch (an_adv & (XGXS6_ANA_PAUSE_SYM | XGXS6_ANA_PAUSE_ASYM)) { 743 case XGXS6_ANA_PAUSE_SYM: 744 *mode |= SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX; 745 break; 746 case XGXS6_ANA_PAUSE_ASYM: 747 *mode |= SOC_PM_PAUSE_TX; 748 break; 749 case XGXS6_ANA_PAUSE_SYM | XGXS6_ANA_PAUSE_ASYM: 750 *mode |= SOC_PM_PAUSE_RX; 751 break; 752 } 753 754 } 755 756 LOG_INFO(BSL_LS_SOC_PHY, 757 (BSL_META_U(unit, 758 "phy_xgxs6_adv_local_get:unit=%d p=%d mode=0x%08x\n"), 759 unit, port, *mode)); 760 761 return SOC_E_NONE; 762 } 763 764 /* 765 * Function: 766 * phy_xgxs6_adv_remote_get 767 * Purpose: 768 * Get the current advertisement for auto-negotiation. 769 * Parameters: 770 * unit - StrataSwitch unit #. 771 * port - StrataSwitch port #. 772 * mode - (OUT) Port mode mask indicating supported options/speeds. 773 * Returns: 774 * SOC_E_XXX 775 * Notes: 776 * The advertisement is retrieved for the ACTIVE medium. 777 * No synchronization performed at this level. 778 */ 779 780 STATIC int 781 phy_xgxs6_adv_remote_get(int unit, soc_port_t port, soc_port_mode_t *mode) 782 { 783 uint16 an_adv; 784 phy_ctrl_t *pc; 785 786 pc = INT_PHY_SW_STATE(unit, port); 787 788 SOC_IF_ERROR_RETURN 789 (READ_PHYXGXS6_OVER1G_LP_UP1r(unit, pc, &an_adv)); 790 791 *mode = 0; 792 if (IS_HG_PORT(unit, port)) { 793 *mode = (an_adv & ((1 << 3) | (1 << 4))) ? SOC_PM_10GB_FD : 0; 794 *mode |= (an_adv & (1 << 5)) ? SOC_PM_12GB_FD : 0; 795 *mode |= (an_adv & (1 << 7)) ? SOC_PM_13GB_FD : 0; 796 } else { 797 *mode = (an_adv & (1 << 4)) ? SOC_PM_10GB_FD : 0; 798 *mode |= (an_adv & (1 << 0)) ? SOC_PM_2500MB_FD : 0; 799 800 SOC_IF_ERROR_RETURN 801 (READ_PHYXGXS6_SERDES_MII_ANPr(unit, pc, &an_adv)); 802 803 *mode |= (an_adv & XGXS6_ANP_FD) ? SOC_PM_1000MB_FD : 0; 804 805 switch (an_adv & (XGXS6_ANP_PAUSE_SYM | XGXS6_ANP_PAUSE_ASYM)) { 806 case XGXS6_ANP_PAUSE_SYM: 807 *mode |= SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX; 808 break; 809 case XGXS6_ANP_PAUSE_ASYM: 810 *mode |= SOC_PM_PAUSE_TX; 811 break; 812 case XGXS6_ANP_PAUSE_SYM | XGXS6_ANP_PAUSE_ASYM: 813 *mode |= SOC_PM_PAUSE_RX; 814 break; 815 } 816 } 817 818 LOG_INFO(BSL_LS_SOC_PHY, 819 (BSL_META_U(unit, 820 "phy_xgxs6_adv_remote_get:unit=%d p=%d mode=0x%08x\n"), 821 unit, port, *mode)); 822 823 return SOC_E_NONE; 824 } 825 826 827 /* 828 * Function: 829 * phy_xgxs6_lb_set 830 * Purpose: 831 * Put XGXS6/FusionCore in PHY loopback 832 * Parameters: 833 * unit - StrataSwitch unit #. 834 * port - StrataSwitch port #. 835 * enable - binary value for on/off (1/0) 836 * Returns: 837 * SOC_E_NONE 838 */ 839 840 STATIC int 841 phy_xgxs6_lb_set(int unit, soc_port_t port, int enable) 842 { 843 int rv; 844 phy_ctrl_t *pc; 845 uint16 lb_bit; 846 847 rv = SOC_E_NONE; 848 849 pc = INT_PHY_SW_STATE(unit, port); 850 851 if (IS_LMD_ENABLED_PORT(unit, port)) { 852 SOC_IF_ERROR_RETURN 853 (WRITE_PHYXGXS6_BLK1_LANE_CTRL2r(unit, pc, 854 (enable) ? 0xFF0F : 0xFF00)); 855 return SOC_E_NONE; 856 } 857 858 /* 859 * control RX signal detect, so that a cable is not needed for loopback 860 */ 861 SOC_IF_ERROR_RETURN 862 (MODIFY_PHYXGXS6_RXALL_CTRLr(unit, pc, (enable) ? 0x0010 : 0, 0x0010)); 863 864 /* 865 * control the actual loopback bit 866 */ 867 lb_bit = XGXS6_IEEE_CTRL_LB_ENA; 868 if (IS_XE_PORT(unit, port)) { 869 lb_bit = 1; 870 } 871 SOC_IF_ERROR_RETURN 872 (MODIFY_PHYXGXS6_XAUI_MII_CTRLr(unit, pc, 873 (enable) ? lb_bit : 0, lb_bit)); 874 875 SOC_IF_ERROR_RETURN 876 (MODIFY_PHYXGXS6_SERDES_MII_CTRLr(unit, pc, 877 (enable) ? MII_CTRL_LE : 0, 878 MII_CTRL_LE)); 879 880 return rv; 881 } 882 883 /* 884 * Function: 885 * phy_xgxs6_lb_get 886 * Purpose: 887 * Get XGXS6/FusionCore PHY loopback state 888 * Parameters: 889 * unit - StrataSwitch unit #. 890 * port - StrataSwitch port #. 891 * enable - address of location to store binary value for on/off (1/0) 892 * Returns: 893 * SOC_E_NONE 894 */ 895 896 STATIC int 897 phy_xgxs6_lb_get(int unit, soc_port_t port, int *enable) 898 { 899 uint16 reg_val; 900 uint16 lb_bit; 901 phy_ctrl_t *pc; 902 903 pc = INT_PHY_SW_STATE(unit, port); 904 905 if (IS_LMD_ENABLED_PORT(unit, port)) { 906 SOC_IF_ERROR_RETURN /* Get Loopback status*/ 907 (READ_PHYXGXS6_BLK1_LANE_CTRL2r(unit, pc, ®_val)); 908 909 *enable = ((reg_val & 0x000F) == 0x000f) ? TRUE : FALSE; 910 return SOC_E_NONE; 911 } 912 913 lb_bit = XGXS6_IEEE_CTRL_LB_ENA; 914 if (IS_XE_PORT(unit, port)) { 915 lb_bit = 1; 916 } 917 918 SOC_IF_ERROR_RETURN 919 (READ_PHYXGXS6_XAUI_MII_CTRLr(unit, pc, ®_val)); 920 921 *enable = (reg_val & lb_bit) ? TRUE : FALSE; 922 923 return SOC_E_NONE; 924 } 925 926 927 STATIC int 928 phy_xgxs6_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode) 929 { 930 phy_ctrl_t *pc; 931 932 pc = INT_PHY_SW_STATE(unit, port); 933 934 *mode = (SOC_PM_1000MB_FD | SOC_PM_2500MB_FD | 935 SOC_PM_MII | SOC_PM_XGMII | SOC_PM_LB_PHY | SOC_PM_AN | 936 SOC_PM_PAUSE | SOC_PM_PAUSE_ASYMM); 937 switch(pc->speed_max) { 938 case 13000: 939 *mode |= SOC_PM_13GB_FD; 940 /* fall through */ 941 case 12000: 942 *mode |= SOC_PM_12GB_FD; 943 /* fall through */ 944 default: 945 *mode |= SOC_PM_10GB_FD; 946 } 947 948 return SOC_E_NONE; 949 } 950 951 STATIC int 952 _phy_xgxs6_control_tx_driver_set(int unit, phy_ctrl_t *pc, 953 soc_phy_control_t type, uint32 value) 954 { 955 uint16 data; /* Temporary holder of reg value to be written */ 956 uint16 mask; /* Bit mask of reg value to be updated */ 957 958 if (value > 15) { 959 return SOC_E_PARAM; 960 } 961 962 data = mask = 0; 963 switch(type) { 964 case SOC_PHY_CONTROL_PREEMPHASIS: 965 data = _shr_bit_rev8((uint8)value) << 8; 966 mask = 0xF000; 967 break; 968 case SOC_PHY_CONTROL_DRIVER_CURRENT: 969 data = _shr_bit_rev8((uint8)value) << 4; 970 mask = 0x0F00; 971 break; 972 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 973 data = _shr_bit_rev8((uint8)value); 974 mask = 0x00F0; 975 break; 976 default: 977 /* should never get here */ 978 return SOC_E_PARAM; 979 } 980 981 /* Update preemphasis/driver/pre-driver current */ 982 SOC_IF_ERROR_RETURN 983 (MODIFY_PHYXGXS6_TXALL_DRIVERr(unit, pc, data, mask)); 984 985 return SOC_E_NONE; 986 } 987 988 STATIC int 989 _phy_xgxs6_control_tx_driver_get(int unit, phy_ctrl_t *pc, 990 soc_phy_control_t type, uint32 *value) 991 { 992 uint16 data16; /* Temporary holder of 16 bit reg value */ 993 uint8 data8; /* Temporary holder of 8 bit reg value */ 994 995 /* Read preemphasis/driver/pre-driver current */ 996 SOC_IF_ERROR_RETURN 997 (READ_PHYXGXS6_TXALL_DRIVERr(unit, pc, &data16)); 998 999 switch(type) { 1000 case SOC_PHY_CONTROL_PREEMPHASIS: 1001 data8 = (uint8)((data16 & 0xF000) >> 8); 1002 *value = _shr_bit_rev8(data8); 1003 break; 1004 case SOC_PHY_CONTROL_DRIVER_CURRENT: 1005 data8 = (uint8)((data16 & 0x0F00) >> 4); 1006 *value = _shr_bit_rev8(data8); 1007 break; 1008 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 1009 data8 = (uint8)(data16 & 0x00F0); 1010 *value = _shr_bit_rev8(data8); 1011 break; 1012 default: 1013 /* should never get here */ 1014 return SOC_E_PARAM; 1015 } 1016 1017 return SOC_E_NONE; 1018 } 1019 1020 1021 /* 1022 * Function: 1023 * phy_xgxs6_control_set 1024 * Purpose: 1025 * Configure PHY device specific control fucntion. 1026 * Parameters: 1027 * unit - StrataSwitch unit #. 1028 * port - StrataSwitch port #. 1029 * type - Control to update 1030 * value - New setting for the control 1031 * Returns: 1032 * SOC_E_NONE 1033 */ 1034 STATIC int 1035 phy_xgxs6_control_set(int unit, soc_port_t port, 1036 soc_phy_control_t type, uint32 value) 1037 { 1038 int rv; 1039 phy_ctrl_t *pc; 1040 /* coverity[mixed_enums] */ 1041 if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) { 1042 return SOC_E_PARAM; 1043 } 1044 1045 pc = INT_PHY_SW_STATE(unit, port); 1046 rv = SOC_E_UNAVAIL; 1047 switch(type) { 1048 case SOC_PHY_CONTROL_PREEMPHASIS: 1049 /* fall through */ 1050 case SOC_PHY_CONTROL_DRIVER_CURRENT: 1051 /* fall through */ 1052 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 1053 rv = _phy_xgxs6_control_tx_driver_set(unit, pc, type, value); 1054 break; 1055 default: 1056 rv = SOC_E_UNAVAIL; 1057 break; 1058 } 1059 return rv; 1060 } 1061 1062 /* 1063 * Function: 1064 * phy_xgxs6_control_get 1065 * Purpose: 1066 * Get current control settign of the PHY. 1067 * Parameters: 1068 * unit - StrataSwitch unit #. 1069 * port - StrataSwitch port #. 1070 * type - Control to update 1071 * value - (OUT)Current setting for the control 1072 * Returns: 1073 * SOC_E_NONE 1074 */ 1075 STATIC int 1076 phy_xgxs6_control_get(int unit, soc_port_t port, 1077 soc_phy_control_t type, uint32 *value) 1078 { 1079 int rv; 1080 phy_ctrl_t *pc; 1081 1082 if (NULL == value) { 1083 return SOC_E_PARAM; 1084 } 1085 /* coverity[mixed_enums] */ 1086 if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) { 1087 return SOC_E_PARAM; 1088 } 1089 1090 pc = INT_PHY_SW_STATE(unit, port); 1091 rv = SOC_E_UNAVAIL; 1092 switch(type) { 1093 case SOC_PHY_CONTROL_PREEMPHASIS: 1094 /* fall through */ 1095 case SOC_PHY_CONTROL_DRIVER_CURRENT: 1096 /* fall through */ 1097 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 1098 rv = _phy_xgxs6_control_tx_driver_get(unit, pc, type, value); 1099 break; 1100 default: 1101 rv = SOC_E_UNAVAIL; 1102 break; 1103 } 1104 1105 return rv; 1106 } 1107 1108 /* 1109 * Function: 1110 * phy_xgxs6_reg_read 1111 * Purpose: 1112 * Routine to read PHY register 1113 * Parameters: 1114 * uint - BCM unit number 1115 * pc - PHY state 1116 * flags - Flags which specify the register type 1117 * phy_reg_addr - Encoded register address 1118 * phy_data - (OUT) Value read from PHY register 1119 * Note: 1120 * This register read function is not thread safe. Higher level 1121 * function that calls this function must obtain a per port lock 1122 * to avoid overriding register page mapping between threads. 1123 */ 1124 STATIC int 1125 phy_xgxs6_reg_read(int unit, soc_port_t port, uint32 flags, 1126 uint32 phy_reg_addr, uint32 *phy_data) 1127 { 1128 uint32 reg_flags; 1129 uint16 reg_bank; 1130 uint8 reg_addr; 1131 uint16 data; /* Temporary holder for phy_data */ 1132 phy_ctrl_t *pc; /* PHY software state */ 1133 1134 COMPILER_REFERENCE(flags); 1135 1136 pc = INT_PHY_SW_STATE(unit, port); 1137 1138 reg_flags = SOC_PHY_REG_FLAGS(phy_reg_addr); 1139 reg_bank = SOC_PHY_REG_BANK(phy_reg_addr); 1140 reg_addr = SOC_PHY_REG_ADDR(phy_reg_addr); 1141 1142 SOC_IF_ERROR_RETURN 1143 (phy_reg_xgxs6_read(unit, pc, reg_flags, reg_bank, reg_addr, &data)); 1144 1145 *phy_data = data; 1146 1147 return SOC_E_NONE; 1148 } 1149 1150 /* 1151 * Function: 1152 * phy_xgxs6_reg_write 1153 * Purpose: 1154 * Routine to write PHY register 1155 * Parameters: 1156 * uint - BCM unit number 1157 * pc - PHY state 1158 * flags - Flags which specify the register type 1159 * phy_reg_addr - Encoded register address 1160 * phy_data - Value write to PHY register 1161 * Note: 1162 * This register read function is not thread safe. Higher level 1163 * function that calls this function must obtain a per port lock 1164 * to avoid overriding register page mapping between threads. 1165 */ 1166 STATIC int 1167 phy_xgxs6_reg_write(int unit, soc_port_t port, uint32 flags, 1168 uint32 phy_reg_addr, uint32 phy_data) 1169 { 1170 uint32 reg_flags; 1171 uint16 reg_bank; 1172 uint8 reg_addr; 1173 uint16 data; /* Temporary holder for phy_data */ 1174 phy_ctrl_t *pc; /* PHY software state */ 1175 1176 COMPILER_REFERENCE(flags); 1177 1178 1179 pc = INT_PHY_SW_STATE(unit, port); 1180 data = (uint16) (phy_data & 0x0000FFFF); 1181 1182 reg_flags = SOC_PHY_REG_FLAGS(phy_reg_addr); 1183 reg_bank = SOC_PHY_REG_BANK(phy_reg_addr); 1184 reg_addr = SOC_PHY_REG_ADDR(phy_reg_addr); 1185 1186 return phy_reg_xgxs6_write(unit, pc, reg_flags, reg_bank, reg_addr, data); 1187 } 1188 1189 /* 1190 * Function: 1191 * phy_xgxs6_reg_modify 1192 * Purpose: 1193 * Routine to write PHY register 1194 * Parameters: 1195 * uint - BCM unit number 1196 * pc - PHY state 1197 * flags - Flags which specify the register type 1198 * phy_reg_addr - Encoded register address 1199 * phy_mo_data - New value for the bits specified in phy_mo_mask 1200 * phy_mo_mask - Bit mask to modify 1201 * Note: 1202 * This register read function is not thread safe. Higher level 1203 * function that calls this function must obtain a per port lock 1204 * to avoid overriding register page mapping between threads. 1205 */ 1206 STATIC int 1207 phy_xgxs6_reg_modify(int unit, soc_port_t port, uint32 flags, 1208 uint32 phy_reg_addr, uint32 phy_data, 1209 uint32 phy_data_mask) 1210 { 1211 uint32 reg_flags; 1212 uint16 reg_bank; 1213 uint8 reg_addr; 1214 uint16 data; /* Temporary holder for phy_data */ 1215 uint16 mask; /* Temporary holder for phy_data_mask */ 1216 phy_ctrl_t *pc; /* PHY software state */ 1217 1218 COMPILER_REFERENCE(flags); 1219 1220 pc = INT_PHY_SW_STATE(unit, port); 1221 data = (uint16) (phy_data & 0x0000FFFF); 1222 mask = (uint16) (phy_data_mask & 0x0000FFFF); 1223 1224 reg_flags = SOC_PHY_REG_FLAGS(phy_reg_addr); 1225 reg_bank = SOC_PHY_REG_BANK(phy_reg_addr); 1226 reg_addr = SOC_PHY_REG_ADDR(phy_reg_addr); 1227 1228 return phy_reg_xgxs6_modify(unit, pc, reg_flags, 1229 reg_bank, reg_addr, data, mask); 1230 } 1231 1232 STATIC int 1233 _phy_xgxs6_stop(int unit, soc_port_t port) 1234 { 1235 int stop, copper; 1236 phy_ctrl_t *pc; 1237 1238 pc = INT_PHY_SW_STATE(unit, port); 1239 1240 copper = (pc->stop & 1241 PHY_STOP_COPPER) != 0; 1242 1243 stop = ((pc->stop & 1244 (PHY_STOP_PHY_DIS | 1245 PHY_STOP_DRAIN)) != 0 || 1246 (copper && 1247 (pc->stop & 1248 (PHY_STOP_MAC_DIS | 1249 PHY_STOP_DUPLEX_CHG | 1250 PHY_STOP_SPEED_CHG)) != 0)); 1251 1252 LOG_INFO(BSL_LS_SOC_PHY, 1253 (BSL_META_U(unit, 1254 "phy_xgxs6_stop: u=%d p=%d copper=%d stop=%d flg=0x%x\n"), 1255 unit, port, copper, stop, 1256 pc->stop)); 1257 1258 1259 return _phy_xgxs6_enable_set(unit,port,stop?FALSE:TRUE); 1260 } 1261 1262 1263 /* 1264 * Function: 1265 * _phy_xgxs6_notify_stop 1266 * Purpose: 1267 * Add a reason to put serdesxgxs6 PHY in reset. 1268 * Parameters: 1269 * unit - StrataSwitch unit #. 1270 * port - StrataSwitch port #. 1271 * flags - Reason to stop 1272 * Returns: 1273 * SOC_E_XXX 1274 */ 1275 1276 STATIC int 1277 _phy_xgxs6_notify_stop(int unit, soc_port_t port, uint32 flags) 1278 { 1279 INT_PHY_SW_STATE(unit, port)->stop |= flags; 1280 return _phy_xgxs6_stop(unit, port); 1281 } 1282 1283 /* 1284 * Function: 1285 * _phy_xgxs6_notify_resume 1286 * Purpose: 1287 * Remove a reason to put serdesxgxs6 PHY in reset. 1288 * Parameters: 1289 * unit - StrataSwitch unit #. 1290 * port - StrataSwitch port #. 1291 * flags - Reason to stop 1292 * Returns: 1293 * SOC_E_XXX 1294 */ 1295 1296 STATIC int 1297 _phy_xgxs6_notify_resume(int unit, soc_port_t port, uint32 flags) 1298 { 1299 INT_PHY_SW_STATE(unit, port)->stop &= ~flags; 1300 return _phy_xgxs6_stop(unit, port); 1301 } 1302 1303 /* 1304 * Function: 1305 * _phy_xgxs6_notify_speed 1306 * Purpose: 1307 * Program speed if (and only if) serdesxgxs6 is an intermediate PHY. 1308 * Parameters: 1309 * unit - StrataSwitch unit #. 1310 * port - StrataSwitch port #. 1311 * speed - Speed to program. 1312 * Returns: 1313 * SOC_E_XXX 1314 * Notes: 1315 * If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to 1316 * talk directly to an external fiber module. 1317 * 1318 * If PHY_FLAGS_FIBER is clear, the PHY is being used in 1319 * pass-through mode to talk to an external SGMII PHY. 1320 * 1321 * When used in pass-through mode, autoneg must be turned off and 1322 * the speed/duplex forced to match that of the external PHY. 1323 */ 1324 1325 STATIC int 1326 _phy_xgxs6_notify_speed(int unit, soc_port_t port, uint32 speed) 1327 { 1328 int fiber; 1329 1330 fiber = PHY_FIBER_MODE(unit, port); 1331 1332 LOG_INFO(BSL_LS_SOC_PHY, 1333 (BSL_META_U(unit, 1334 "_phy_xgxs6_notify_speed: " 1335 "u=%d p=%d speed=%d fiber=%d\n"), 1336 unit, port, speed, fiber)); 1337 1338 if (SAL_BOOT_SIMULATION) { 1339 return SOC_E_NONE; 1340 } 1341 1342 /* Update speed */ 1343 SOC_IF_ERROR_RETURN 1344 (phy_xgxs6_speed_set(unit, port, speed)); 1345 1346 /* Autonegotiation must be turned off to talk to external PHY */ 1347 if (!PHY_SGMII_AUTONEG_MODE(unit, port) && PHY_EXTERNAL_MODE(unit, port)) { 1348 SOC_IF_ERROR_RETURN 1349 (phy_xgxs6_an_set(unit, port, FALSE)); 1350 } 1351 LOG_INFO(BSL_LS_SOC_PHY, 1352 (BSL_META_U(unit, 1353 "_phy_xgxs6_notify_speed: " 1354 "u=%d p=%d speed=%d fiber=%d rv=%d\n"), 1355 unit, port, speed, fiber,SOC_E_NONE)); 1356 1357 return SOC_E_NONE; 1358 } 1359 1360 STATIC int 1361 phy_xgxs6_notify(int unit, soc_port_t port, 1362 soc_phy_event_t event, uint32 value) 1363 { 1364 int rv; 1365 1366 if (event >= phyEventCount) { 1367 return SOC_E_PARAM; 1368 } 1369 1370 rv = SOC_E_NONE; 1371 switch(event) { 1372 case phyEventInterface: 1373 break; 1374 case phyEventDuplex: 1375 break; 1376 case phyEventSpeed: 1377 rv = (_phy_xgxs6_notify_speed(unit, port, value)); 1378 break; 1379 case phyEventStop: 1380 rv = (_phy_xgxs6_notify_stop(unit, port, value)); 1381 break; 1382 case phyEventResume: 1383 rv = (_phy_xgxs6_notify_resume(unit, port, value)); 1384 break; 1385 case phyEventAutoneg: 1386 rv = (phy_xgxs6_an_set(unit, port, value)); 1387 break; 1388 default: 1389 rv = SOC_E_UNAVAIL; 1390 } 1391 1392 return rv; 1393 } 1394 1395 1396 /* 1397 * Variable: 1398 * phy_xgxs6_drv 1399 * Purpose: 1400 * Phy Driver for 10G (XAUI x 4) Serdes PHY. 1401 */ 1402 1403 phy_driver_t phy_xgxs6_hg = { 1404 "XGXS6 Unicore PHY Driver", 1405 phy_xgxs6_init, /* Init */ 1406 phy_null_reset, /* Reset (dummy) */ 1407 phy_xgxs6_link_get, /* Link get */ 1408 phy_xgxs6_enable_set, /* Enable set */ 1409 phy_null_enable_get, /* Enable get */ 1410 phy_null_set, /* Duplex set */ 1411 phy_null_one_get, /* Duplex get */ 1412 phy_xgxs6_speed_set, /* Speed set */ 1413 phy_xgxs6_speed_get, /* Speed get */ 1414 phy_null_set, /* Master set */ 1415 phy_null_zero_get, /* Master get */ 1416 phy_xgxs6_an_set, /* ANA set */ 1417 phy_xgxs6_an_get, /* ANA get */ 1418 phy_xgxs6_adv_local_set, /* Local Advert set */ 1419 phy_xgxs6_adv_local_get, /* Local Advert get */ 1420 phy_xgxs6_adv_remote_get, /* Remote Advert get */ 1421 phy_xgxs6_lb_set, /* PHY loopback set */ 1422 phy_xgxs6_lb_get, /* PHY loopback set */ 1423 phy_null_interface_set, /* IO Interface set */ 1424 phy_null_interface_get, /* IO Interface get */ 1425 phy_xgxs6_ability_get, /* PHY abilities mask */ 1426 NULL, /* phy_linkup_evnt */ 1427 NULL, /* phy_linkdn_evnt */ 1428 phy_null_mdix_set, 1429 phy_null_mdix_get, 1430 phy_null_mdix_status_get, 1431 NULL, /* Medium config set */ 1432 NULL, /* Medium config get */ 1433 phy_null_medium_get, 1434 NULL, /* phy_cable_diag */ 1435 NULL, /* phy_link_change */ 1436 phy_xgxs6_control_set, 1437 phy_xgxs6_control_get, 1438 phy_xgxs6_reg_read, 1439 phy_xgxs6_reg_write, 1440 phy_xgxs6_reg_modify, 1441 phy_xgxs6_notify /* phy_notify */ 1442 }; 1443 1444 #endif /* INCLUDE_PHY_XGXS6 */ 1445 1446 int _phy_xgxs6_not_empty;