phy8705.c (17444B)
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: phy8705.c 8 * Purpose: Phys driver support for Broadcom Serial 10Gig 9 * transceiver with XAUI interface. 10 */ 11 12 13 #include <sal/types.h> 14 #include <shared/bsl.h> 15 #include <soc/drv.h> 16 #include <soc/debug.h> 17 #include <soc/error.h> 18 #include <soc/phyreg.h> 19 20 #include <soc/phy.h> 21 #include <soc/phy/phyctrl.h> 22 #include <soc/phy/drv.h> 23 24 #include "phydefs.h" /* Must include before other phy related includes */ 25 #ifdef INCLUDE_PHY_8705 26 #include "phyconfig.h" /* Must be the first phy include after phydefs.h */ 27 #include "phyident.h" 28 #include "phyreg.h" 29 #include "phynull.h" 30 #include "phyxehg.h" 31 #include "phy8705.h" 32 33 #define LAN_MODE 0 34 #define WAN_MODE 1 35 36 STATIC int 37 _phy_8705_mode_set(int unit, soc_port_t port, uint32 mode); 38 39 /* 40 * Function: 41 * phy_8705_init 42 * Purpose: 43 * Initialize 8705 phys 44 * Parameters: 45 * unit - StrataSwitch unit #. 46 * port - StrataSwitch port #. 47 * Returns: 48 * SOC_E_NONE 49 */ 50 51 static int 52 phy_8705_init(int unit, soc_port_t port) 53 { 54 int wan_mode; 55 uint16 tmp; 56 uint16 invert_txrx; 57 phy_ctrl_t *pc; 58 59 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER | PHY_FLAGS_C45); 60 61 wan_mode = soc_property_port_get(unit, port, spn_PHY_WAN_MODE, FALSE); 62 63 pc = EXT_PHY_SW_STATE(unit, port); 64 65 /* Reset the device */ 66 SOC_IF_ERROR_RETURN 67 (MODIFY_PHY8705_PMA_PMD_CTRLr(unit, pc, 68 MII_CTRL_RESET, MII_CTRL_RESET)); 69 if (wan_mode) { 70 SOC_IF_ERROR_RETURN 71 (MODIFY_PHY8705_WIS_CTRLr(unit, pc, 72 MII_CTRL_RESET, MII_CTRL_RESET)); 73 } 74 75 SOC_IF_ERROR_RETURN 76 (MODIFY_PHY8705_PCS_CTRLr(unit, pc, 77 MII_CTRL_RESET, MII_CTRL_RESET)); 78 79 SOC_IF_ERROR_RETURN 80 (MODIFY_PHY8705_PHYXS_CTRLr(unit, pc, 81 MII_CTRL_RESET, MII_CTRL_RESET)); 82 83 /* P_DOWN/OPTXRST1 */ 84 SOC_IF_ERROR_RETURN 85 (READ_PHY8705_IDENTIFIERr(unit, pc, &tmp)); 86 87 if (soc_property_port_get(unit, port, spn_FORCE_OPTTXENBLVL, FALSE)) { 88 tmp |= 0x8000; /* Set OPTXENB_LVL */ 89 } else { 90 tmp &= ~0x8000; 91 } 92 93 if (soc_property_port_get(unit, port, spn_FORCE_OPTTXRSTLVL, TRUE)) { 94 tmp |= 0x4000; /* Set OPTXRST_LVL */ 95 } else { 96 tmp &= ~0x4000; 97 } 98 99 if (soc_property_port_get(unit, port, spn_FORCE_OPTBIASFLTLVL, TRUE)) { 100 tmp |= 0x2000; /* Set OPBIASFLT_LVL */ 101 } else { 102 tmp &= ~0x2000; 103 } 104 105 if (soc_property_port_get(unit, port, spn_FORCE_OPTTEMPFLTLVL, TRUE)) { 106 tmp |= 0x1000; /* Set OPMPFLT_LVL */ 107 } else { 108 tmp &= ~0x1000; 109 } 110 111 if (soc_property_port_get(unit, port, spn_FORCE_OPTPRFLTLVL, TRUE)) { 112 tmp |= 0x0800; /* Set OPPRFLT_LVL */ 113 } else { 114 tmp &= ~0x0800; 115 } 116 117 if (soc_property_port_get(unit, port, spn_FORCE_OPTTXFLLVL, TRUE)) { 118 tmp |= 0x0400; /* Set OPTXFLT_LVL */ 119 } else { 120 tmp &= ~0x0400; 121 } 122 123 if (soc_property_port_get(unit, port, spn_FORCE_OPTRXLOSLVL, TRUE)) { 124 tmp |= 0x0200; /* Set OPRXLOS_LVL */ 125 } else { 126 tmp &= ~0x0200; 127 } 128 129 if (soc_property_port_get(unit, port, spn_FORCE_OPTRXFLTLVL, TRUE)) { 130 tmp |= 0x0100; /* Set OPRXFLT_LVL */ 131 } else { 132 tmp &= ~0x0100; 133 } 134 135 if (soc_property_port_get(unit, port, spn_FORCE_OPTTXONLVL, TRUE)) { 136 tmp |= 0x0080; /* Set OPTXON_LVL */ 137 } else { 138 tmp &= ~0x0080; 139 } 140 141 /* P_DOWN/OPTXRST1 */ 142 SOC_IF_ERROR_RETURN 143 (WRITE_PHY8705_IDENTIFIERr(unit, pc, tmp)); 144 145 if (soc_property_port_get(unit, port, spn_PHY_XCLKSEL_OVRD, FALSE)) { 146 /* set clock override bit to 1 and clear bit6,7*/ 147 tmp = (1 << 7) | (1 << 6) | (1 << 4); 148 SOC_IF_ERROR_RETURN 149 (MODIFY_PHY8705_PMD_MISC_CTRLr(unit, pc, (1 << 4), tmp)); 150 } 151 152 tmp = 0; 153 154 if (soc_property_port_get(unit, port, spn_PHY_CLOCK_ENABLE, FALSE)) { 155 tmp = (0x1 << 15); 156 } 157 158 SOC_IF_ERROR_RETURN 159 (MODIFY_PHY8705_PMA_PMD_REG(unit, pc, 0xCA08, tmp, (0x1 << 15))); 160 161 if (wan_mode) { 162 SOC_IF_ERROR_RETURN 163 (_phy_8705_mode_set(unit, port, WAN_MODE)); 164 } 165 LOG_INFO(BSL_LS_SOC_PHY, 166 (BSL_META_U(unit, 167 "8705: u=%d port=%d mode=%s : init.\n"), 168 unit, port, wan_mode ? "WAN" : "LAN")); 169 170 /* 171 * Enable 8705 XFP clock output 172 */ 173 if (soc_property_port_get(unit, port, spn_PHY_XFP_CLOCK, TRUE)) { 174 SOC_IF_ERROR_RETURN 175 (MODIFY_PHY8705_PMD_MISC_CTRLr(unit, pc, 0x0008, 0x0008)); 176 } 177 178 invert_txrx = 0; 179 if (soc_property_port_get(unit, port, spn_PHY_TX_INVERT, FALSE)) { 180 invert_txrx |= (1 << 10); 181 } 182 if (soc_property_port_get(unit, port, spn_PHY_RX_INVERT, FALSE)) { 183 invert_txrx |= (1 << 9); 184 } 185 if (invert_txrx) { 186 SOC_IF_ERROR_RETURN 187 (MODIFY_PHY8705_PMD_DIGI_CTRLr(unit, pc, 188 invert_txrx, (1 << 10) | (1 << 9))); 189 } 190 191 /* Override the lock detect signal in the PMD PLL. */ 192 SOC_IF_ERROR_RETURN 193 (MODIFY_PHY8705_OVERRIDE_CTRLr(unit, pc, (1 << 8), (1 << 8))); 194 195 return SOC_E_NONE; 196 } 197 198 /* 199 * Function: 200 * phy_8705_link_get 201 * Purpose: 202 * Get layer2 connection status. 203 * Parameters: 204 * unit - StrataSwitch unit #. 205 * port - StrataSwitch port #. 206 * link - address of memory to store link up/down state. 207 * Returns: 208 * SOC_E_NONE 209 */ 210 211 int 212 phy_8705_link_get(int unit, soc_port_t port, int *link) 213 { 214 phy_ctrl_t *pc; 215 uint16 pma_mii_stat, pcs_mii_stat, pxs_mii_stat, wis_mii_stat; 216 uint16 link_stat; 217 218 if (link == NULL) { 219 return SOC_E_PARAM; 220 } 221 222 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) { 223 *link = FALSE; 224 return SOC_E_NONE; 225 } 226 227 pc = EXT_PHY_SW_STATE(unit, port); 228 SOC_IF_ERROR_RETURN 229 (READ_PHY8705_PMA_PMD_STATr(unit, pc, &pma_mii_stat)); 230 231 /* Receive Link status */ 232 SOC_IF_ERROR_RETURN 233 (READ_PHY8705_PCS_STATr(unit, pc, &pcs_mii_stat)); 234 235 /* Transmit Link status */ 236 SOC_IF_ERROR_RETURN 237 (READ_PHY8705_PHYXS_STATr(unit, pc, &pxs_mii_stat)); 238 239 link_stat = pma_mii_stat & pcs_mii_stat & pxs_mii_stat; 240 241 if (PHY_WAN_MODE(unit, port)) { 242 /* WIS status */ 243 SOC_IF_ERROR_RETURN 244 (READ_PHY8705_WIS_STATr(unit, pc, &wis_mii_stat)); 245 link_stat &= wis_mii_stat; 246 } 247 248 *link = (link_stat & MII_STAT_LA) ? TRUE : FALSE; 249 250 LOG_INFO(BSL_LS_SOC_PHY, 251 (BSL_META_U(unit, 252 "phy_8705_link_get: u=%d port%d: link:%s\n"), 253 unit, port, *link ? "Up": "Down")); 254 255 return SOC_E_NONE; 256 } 257 258 /* 259 * Function: 260 * phy_8705_enable_set 261 * Purpose: 262 * Enable/Disable phy 263 * Parameters: 264 * unit - StrataSwitch unit #. 265 * port - StrataSwitch port #. 266 * enable - on/off state to set 267 * Returns: 268 * SOC_E_NONE 269 */ 270 271 int 272 phy_8705_enable_set(int unit, soc_port_t port, int enable) 273 { 274 uint16 data; /* Holder for new value to write to PHY reg */ 275 uint16 mask; /* Holder for bit mask to update in PHY reg */ 276 phy_ctrl_t *pc; 277 278 pc = EXT_PHY_SW_STATE(unit, port); 279 280 data = 0; 281 mask = 1 << 0; /* Global PMD transmit disable */ 282 if (enable) { 283 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE); 284 } else { 285 data = 1 << 0; /* Global PMD transmit disable */ 286 PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE); 287 } 288 289 SOC_IF_ERROR_RETURN 290 (MODIFY_PHY8705_PMA_PMD_TX_DISABLEr(unit, pc, data, mask)); 291 return (SOC_E_NONE); 292 } 293 294 295 /* 296 * Function: 297 * phy_8705_lb_set 298 * Purpose: 299 * Put 8705 in PHY PCS/PMA/PMD loopback 300 * Parameters: 301 * unit - StrataSwitch unit #. 302 * port - StrataSwitch port #. 303 * enable - binary value for on/off (1/0) 304 * Returns: 305 * SOC_E_NONE 306 */ 307 308 int 309 phy_8705_lb_set(int unit, soc_port_t port, int enable) 310 { 311 uint16 tmp; 312 phy_ctrl_t *pc; 313 314 LOG_INFO(BSL_LS_SOC_PHY, 315 (BSL_META_U(unit, 316 "phy_8705_lb_set: u=%d port%d: %s %s loopback.\n"), 317 unit, port, enable ? "Enabling": "Disabling", 318 PHY_WAN_MODE(unit, port) ? "WAN" : "PMA/PMD")); 319 320 pc = EXT_PHY_SW_STATE(unit, port); 321 322 if (PHY_WAN_MODE(unit, port)) { 323 /* Remove PMA/PMD loopback first */ 324 SOC_IF_ERROR_RETURN 325 (MODIFY_PHY8705_PMA_PMD_CTRLr(unit, pc, 326 0, MII_CTRL_PMA_LOOPBACK)); 327 tmp = enable ? MII_CTRL_WIS_LOOP_BACK : 0; 328 329 SOC_IF_ERROR_RETURN 330 (MODIFY_PHY8705_WIS_CTRLr(unit, pc, 331 tmp, MII_CTRL_WIS_LOOP_BACK)); 332 } else { 333 /* Remove WAN loopback first */ 334 SOC_IF_ERROR_RETURN 335 (MODIFY_PHY8705_WIS_CTRLr(unit, pc, 336 0, MII_CTRL_WIS_LOOP_BACK)); 337 tmp = enable ? MII_CTRL_PMA_LOOPBACK : 0; 338 339 SOC_IF_ERROR_RETURN 340 (MODIFY_PHY8705_PMA_PMD_CTRLr(unit, pc, 341 tmp, MII_CTRL_PMA_LOOPBACK)); 342 } 343 return SOC_E_NONE; 344 } 345 346 /* 347 * Function: 348 * phy_8705_lb_get 349 * Purpose: 350 * Get 8705 PHY loopback state 351 * Parameters: 352 * unit - StrataSwitch unit #. 353 * port - StrataSwitch port #. 354 * enable - address of location to store binary value for on/off (1/0) 355 * Returns: 356 * SOC_E_NONE 357 */ 358 359 int 360 phy_8705_lb_get(int unit, soc_port_t port, int *enable) 361 { 362 uint16 tmp; 363 phy_ctrl_t *pc; 364 365 pc = EXT_PHY_SW_STATE(unit, port); 366 367 if (PHY_WAN_MODE(unit, port)) { 368 SOC_IF_ERROR_RETURN 369 (READ_PHY8705_WIS_CTRLr(unit, pc, &tmp)); 370 371 *enable = (tmp & MII_CTRL_WIS_LOOP_BACK) ? TRUE : FALSE; 372 } else { 373 SOC_IF_ERROR_RETURN 374 (READ_PHY8705_PMA_PMD_CTRLr(unit, pc, &tmp)); 375 376 *enable = (tmp & MII_CTRL_PMA_LOOPBACK) ? TRUE : FALSE; 377 } 378 379 LOG_INFO(BSL_LS_SOC_PHY, 380 (BSL_META_U(unit, 381 "phy_8705_lb_get: u=%d port%d: loopback:%s\n"), 382 unit, port, *enable ? "Enabled": "Disabled")); 383 384 return SOC_E_NONE; 385 } 386 387 STATIC int 388 _phy_8705_mode_set(int unit, soc_port_t port, uint32 mode) { 389 uint16 dev_reg, mask,data16, tmp; 390 phy_ctrl_t *pc; 391 392 pc = EXT_PHY_SW_STATE(unit, port); 393 394 switch(mode) { 395 case WAN_MODE: 396 if (PHY_WAN_MODE(unit, port)) { 397 /* Already in WAN mode */ 398 return SOC_E_NONE; 399 } 400 SOC_IF_ERROR_RETURN 401 (READ_PHY8705_WIS_DEV_IN_PKGr(unit, pc, &dev_reg)); 402 /* Check WIS present */ 403 if (!(dev_reg & 0x0004)) { 404 return SOC_E_UNAVAIL; 405 } 406 /* To configure WAN mode clock, 407 * CKMODE_SEL 3.3V 408 * MODE_SEL 3.3V 409 * XCLKMODE_OVRD 1 410 * P_IN_MUXSEL 0 411 * X_IN_MUXSEL 0 412 */ 413 mask = (1 << 7) | (1 << 6) | (1 << 4); 414 SOC_IF_ERROR_RETURN 415 (MODIFY_PHY8705_PMD_MISC_CTRLr(unit, pc, (1 << 4), mask)); 416 417 /* put device in WAN mode */ 418 SOC_IF_ERROR_RETURN 419 (MODIFY_PHY8705_IDENTIFIERr(unit, pc, PMAD_IDr_WAN_MODE, 420 PMAD_IDr_WAN_MODE)); 421 422 tmp = 0; 423 if (soc_property_port_get(unit, port, spn_PHY_CLOCK_ENABLE, FALSE)) { 424 tmp = (0x1 << 15); 425 } 426 SOC_IF_ERROR_RETURN 427 (MODIFY_PHY8705_PMA_PMD_REG(unit, pc, 0xCA08, tmp, (0x1 << 15))); 428 429 PHY_FLAGS_SET(unit, port, PHY_FLAGS_WAN); 430 break; 431 432 case LAN_MODE: 433 if (!PHY_WAN_MODE(unit, port)) { 434 /* Already in LAN mode */ 435 return SOC_E_NONE; 436 } 437 /* To configure LAN mode clock, 438 * CKMODE_SEL 3.3V 439 * MODE_SEL GND 440 * XCLKMODE_OVRD 0 ( Bit 4: Address 0xCA0A ) 441 * P_IN_MXSEL 1 ( Bit 7: Address 0xCA0A ) 442 * X_IN_MXSEL 0 ( Bit 6: Address 0xCA0A ) 443 */ 444 mask = (1 << 7) | (1 << 6) | (1 << 4); 445 if (soc_property_port_get(unit, port, spn_PHY_XCLKSEL_OVRD,FALSE)) { 446 data16 = (1 << 4); 447 } else { 448 data16 = (1 << 7); 449 } 450 SOC_IF_ERROR_RETURN 451 (MODIFY_PHY8705_PMD_MISC_CTRLr(unit, pc, data16, mask)); 452 453 /* put device in LAN mode */ 454 SOC_IF_ERROR_RETURN 455 (MODIFY_PHY8705_IDENTIFIERr(unit, pc, 0, 456 PMAD_IDr_WAN_MODE)); 457 tmp = 0; 458 if (soc_property_port_get(unit, port, spn_PHY_CLOCK_ENABLE, FALSE)) { 459 tmp = (0x1 << 15); 460 } 461 SOC_IF_ERROR_RETURN 462 (MODIFY_PHY8705_PMA_PMD_REG(unit, pc, 0xCA08, tmp, (0x1 << 15))); 463 464 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_WAN); 465 break; 466 default: 467 return SOC_E_UNAVAIL; 468 } 469 470 LOG_INFO(BSL_LS_SOC_PHY, 471 (BSL_META_U(unit, 472 "phy_8705_mode_set: u=%d port=%d mode=%d\n"), 473 unit, port, mode)); 474 475 return SOC_E_NONE; 476 } 477 478 /* 479 * Function: 480 * phy_8705_control_set 481 * Purpose: 482 * Configure PHY device specific control fucntion. 483 * Parameters: 484 * unit - StrataSwitch unit #. 485 * port - StrataSwitch port #. 486 * type - Control to update 487 * value - New setting for the control 488 * Returns: 489 * SOC_E_NONE 490 */ 491 STATIC int 492 phy_8705_control_set(int unit, soc_port_t port, 493 soc_phy_control_t type, uint32 value) 494 { 495 int rv; 496 phy_ctrl_t *pc; 497 498 PHY_CONTROL_TYPE_CHECK(type); 499 500 pc = EXT_PHY_SW_STATE(unit, port); 501 rv = SOC_E_UNAVAIL; 502 503 switch(type) { 504 case SOC_PHY_CONTROL_WAN: 505 rv = _phy_8705_mode_set(unit, port, 506 value ? WAN_MODE : LAN_MODE); 507 break; 508 509 case SOC_PHY_CONTROL_CLOCK_ENABLE: 510 SOC_IF_ERROR_RETURN 511 (MODIFY_PHY8705_PMA_PMD_REG(unit, pc, 0xCA08, value ? (0x1 << 15) : 0, (0x1 << 15))); 512 rv = SOC_E_NONE; 513 break; 514 515 default: 516 break; 517 } 518 return rv; 519 } 520 521 /* 522 * Function: 523 * phy_8705_control_get 524 * Purpose: 525 * Get current control settign of the PHY. 526 * Parameters: 527 * unit - StrataSwitch unit #. 528 * port - StrataSwitch port #. 529 * type - Control to update 530 * value - (OUT)Current setting for the control 531 * Returns: 532 * SOC_E_NONE 533 */ 534 STATIC int 535 phy_8705_control_get(int unit, soc_port_t port, 536 soc_phy_control_t type, uint32 *value) 537 { 538 int rv; 539 uint16 temp16; 540 phy_ctrl_t *pc; 541 542 if (NULL == value) { 543 return SOC_E_PARAM; 544 } 545 546 PHY_CONTROL_TYPE_CHECK(type); 547 548 pc = EXT_PHY_SW_STATE(unit, port); 549 rv = SOC_E_UNAVAIL; 550 551 switch(type) { 552 case SOC_PHY_CONTROL_WAN: 553 *value = PHY_WAN_MODE(unit, port) ? 1 : 0; 554 rv = SOC_E_NONE; 555 break; 556 557 case SOC_PHY_CONTROL_CLOCK_ENABLE: 558 SOC_IF_ERROR_RETURN 559 (READ_PHY8705_PMA_PMD_REG(unit, pc, 0xCA08, &temp16)); 560 *value = temp16 & (0x1<<15) ? TRUE : FALSE; 561 rv = SOC_E_NONE; 562 break; 563 564 default: 565 break; 566 } 567 return rv; 568 } 569 570 /* 571 * Variable: 572 * phy_8705_drv 573 * Purpose: 574 * Phy Driver for 10G (XAUI x 4) Serdes PHY. 575 */ 576 577 phy_driver_t phy_8705drv_xe = { 578 "8705/8724/8725 10-Gigabit PHY Driver", 579 phy_8705_init, /* Init */ 580 phy_null_reset, /* Reset (dummy) */ 581 phy_8705_link_get, /* Link get */ 582 phy_8705_enable_set, /* Enable set */ 583 phy_null_enable_get, /* Enable get */ 584 phy_null_set, /* Duplex set */ 585 phy_null_one_get, /* Duplex get */ 586 phy_xehg_speed_set, /* Speed set */ 587 phy_xehg_speed_get, /* Speed get */ 588 phy_null_set, /* Master set */ 589 phy_null_zero_get, /* Master get */ 590 phy_null_set, /* ANA set */ 591 phy_null_an_get, /* ANA get */ 592 phy_null_mode_set, /* Local Advert set */ 593 phy_null_mode_get, /* Local Advert get */ 594 phy_null_mode_get, /* Remote Advert get */ 595 phy_8705_lb_set, /* PHY loopback set */ 596 phy_8705_lb_get, /* PHY loopback set */ 597 phy_null_interface_set, /* IO Interface set */ 598 phy_xehg_interface_get, /* IO Interface get */ 599 phy_xehg_ability_get, /* PHY abilities mask */ 600 NULL, 601 NULL, 602 phy_null_mdix_set, 603 phy_null_mdix_get, 604 phy_null_mdix_status_get, 605 NULL, 606 NULL, 607 phy_null_medium_get, 608 NULL, /* phy_cable_diag */ 609 NULL, /* phy_link_change */ 610 phy_8705_control_set, /* phy_control_set */ 611 phy_8705_control_get, /* phy_control_get */ 612 NULL, /* phy_reg_read */ 613 NULL, /* phy_reg_write */ 614 NULL, /* phy_reg_modify */ 615 NULL /* phy_notify */ 616 }; 617 618 #else /* INCLUDE_PHY_8705 */ 619 int _phy_8705_not_empty; 620 #endif /* INCLUDE_PHY_8705 */ 621