phy545xx.c (90987B)
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 8 /* 9 * File: phy54580.c 10 * Purpose: PHY driver for BCM54580 (MACSec) 11 * 12 * Supported BCM546X Family of PHY devices: 13 * 14 * Device Ports Media MAC Interface 15 * 54584 8 6 Copper + 2 Fiber/Copper QSGMII 16 * 54580 8 Copper(no Fiber) SGMII 17 * 54540 4 Copper/Fiber Combo SGMII 18 * 54585 8 Copper QSGMII 19 * 20 * Workarounds: 21 * 22 * References: 23 * 24 * +----------+ +---------------------------+ 25 * | | | +->Copper |<--> Magnetic 26 * | QSGMII |<->| QSGMII <-+ | 27 * | (SerDes) | | | | 28 * | | | +->SGMII/ |<--> (PHY)SFP (10/100/1000) 29 * +----------+ | 1000BASE-X/ |<--> 1000BASE-X SFP 30 * Switch | 100BASE-FX |<--> 100BASE-FX SFP 31 * | | 32 * | | 33 * +---------------------------+ 34 * 54580 35 * 36 * Notes: 37 */ 38 39 40 #include <sal/types.h> 41 #include <sal/core/spl.h> 42 #include <shared/bsl.h> 43 #include <soc/drv.h> 44 #include <soc/debug.h> 45 #include <soc/error.h> 46 #include <soc/phyreg.h> 47 48 #include <soc/phy.h> 49 #include <soc/phy/phyctrl.h> 50 #include <soc/phy/drv.h> 51 52 #include "phydefs.h" /* Must include before other phy related includes */ 53 54 55 56 #ifdef INCLUDE_MACSEC 57 #if defined(INCLUDE_PHY_54580) 58 #include "phyconfig.h" /* Must be the first phy include after phydefs.h */ 59 #include "phyident.h" 60 #include "phyreg.h" 61 #include "phyfege.h" 62 #include "phy545xx.h" 63 #include <soc/macsecphy.h> 64 65 #define AUTO_MDIX_WHEN_AN_DIS 0 /* Non-standard-compliant option */ 66 #define DISABLE_CLK125 0 /* Disable if unused to reduce */ 67 /* EMI emissions */ 68 #define WORKAROUND_FIX 1 69 70 #define ADVERT_ALL_COPPER \ 71 (SOC_PM_PAUSE | SOC_PM_10MB | SOC_PM_100MB | SOC_PM_1000MB) 72 73 #define ADVERT_ALL_FIBER \ 74 (SOC_PM_PAUSE | SOC_PM_100MB_FD | SOC_PM_1000MB_FD) 75 76 static bmacsec_error_t error_tbl[] = { 77 SOC_E_NONE, 78 SOC_E_INTERNAL, 79 SOC_E_MEMORY, 80 SOC_E_PARAM, 81 SOC_E_EMPTY, 82 SOC_E_FULL, 83 SOC_E_NOT_FOUND, 84 SOC_E_EXISTS, 85 SOC_E_TIMEOUT, 86 SOC_E_FAIL, 87 SOC_E_DISABLED, 88 SOC_E_BADID, 89 SOC_E_RESOURCE, 90 SOC_E_CONFIG, 91 SOC_E_UNAVAIL, 92 SOC_E_INIT, 93 SOC_E_PORT, 94 }; 95 /* 96 * Convert BMACSEC return codes to SOC return code. 97 */ 98 #define SOC_ERROR(e) error_tbl[(-e)] 99 100 #define MACSEC_READ_PHY_REG(_unit, _pc, _mdio, _reg, _value) \ 101 ((_pc->read)((_unit), (_mdio), (_reg), (_value))) 102 #define MACSEC_WRITE_PHY_REG(_unit, _pc, _mdio, _reg, _value) \ 103 ((_pc->write)((_unit), (_mdio), (_reg), (_value))) 104 105 106 STATIC int _phy_54580_medium_change(int unit, soc_port_t port, 107 int force_update, soc_port_medium_t force_medium); 108 STATIC int phy_54580_duplex_set(int unit, soc_port_t port, int duplex); 109 STATIC int phy_54580_speed_set(int unit, soc_port_t port, int speed); 110 STATIC int phy_54580_master_set(int unit, soc_port_t port, int master); 111 STATIC int phy_54580_adv_local_set(int unit, soc_port_t port, 112 soc_port_mode_t mode); 113 STATIC int phy_54580_autoneg_set(int unit, soc_port_t port, int autoneg); 114 STATIC int phy_54580_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode); 115 STATIC int phy_54580_speed_get(int unit, soc_port_t port, int *speed); 116 STATIC int _macsec_54580_rev0_init(phy_ctrl_t *pc, int dev_port, int dev_addr, 117 int macsec_enable); 118 STATIC int _macsec_54580_rev1_init(phy_ctrl_t *pc, int dev_port, int dev_addr, 119 int macsec_enable); 120 121 /*********************************************************************** 122 * 123 * HELPER FUNCTIONS 124 */ 125 /* 126 * Function: 127 * _phy_54580_medium_check 128 * Purpose: 129 * Determine if chip should operate in copper or fiber mode. 130 * Parameters: 131 * unit - StrataSwitch unit #. 132 * port - StrataSwitch port #. 133 * medium - (OUT) SOC_PORT_MEDIUM_XXX 134 * Returns: 135 * SOC_E_XXX 136 */ 137 STATIC int 138 _phy_54580_medium_check(int unit, soc_port_t port, int *medium) 139 { 140 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 141 int rv; 142 bmacsec_dev_addr_t phy_dev_addr; 143 bmacsec_phy54580_port_medium_t bmacsec_port_medium; 144 145 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 146 rv = bmacsec_phy54580_medium_get(phy_dev_addr, &bmacsec_port_medium); 147 if(!BMACSEC_E_SUCCESS(rv)) { 148 return SOC_E_FAIL; 149 } 150 151 *medium = SOC_PORT_MEDIUM_COPPER; 152 153 if (pc->automedium) { 154 if (pc->fiber.preferred) { 155 if (bmacsec_port_medium == BMACSEC_PHY_MEDIUM_COPPER) { 156 /* Only Copper is lined up */ 157 *medium = SOC_PORT_MEDIUM_COPPER; 158 } else { 159 *medium = SOC_PORT_MEDIUM_FIBER; 160 } 161 } else { 162 if (bmacsec_port_medium == BMACSEC_PHY_MEDIUM_FIBER) { 163 /* Only Fiber is linked up */ 164 *medium = SOC_PORT_MEDIUM_FIBER; 165 } else { 166 *medium = SOC_PORT_MEDIUM_COPPER; 167 } 168 } 169 } else { 170 *medium = pc->fiber.preferred ? SOC_PORT_MEDIUM_FIBER: 171 SOC_PORT_MEDIUM_COPPER; 172 } 173 174 LOG_VERBOSE(BSL_LS_SOC_PHY, 175 (BSL_META_U(unit, 176 "_phy_54580_medium_check: " 177 "u=%d p=%d fiber_pref=%d fiber=%d\n"), 178 unit, port, pc->fiber.preferred, 179 (*medium == SOC_PORT_MEDIUM_FIBER) ? 1 : 0)); 180 181 return SOC_E_NONE; 182 } 183 184 /* 185 * Function: 186 * phy_54580_medium_status 187 * Purpose: 188 * Indicate the current active medium 189 * Parameters: 190 * unit - StrataSwitch unit #. 191 * port - StrataSwitch port #. 192 * medium - (OUT) One of: 193 * SOC_PORT_MEDIUM_COPPER 194 * SOC_PORT_MEDIUM_FIBER 195 * Returns: 196 * SOC_E_NONE 197 */ 198 199 STATIC int 200 phy_54580_medium_status(int unit, soc_port_t port, soc_port_medium_t *medium) 201 { 202 if (PHY_COPPER_MODE(unit, port)) { 203 *medium = SOC_PORT_MEDIUM_COPPER; 204 } else { 205 *medium = SOC_PORT_MEDIUM_FIBER; 206 } 207 return SOC_E_NONE; 208 } 209 210 /* 211 * Function: 212 * _phy_54580_medium_config_update 213 * Purpose: 214 * Update the PHY with config parameters 215 * Parameters: 216 * unit - StrataSwitch unit #. 217 * port - StrataSwitch port #. 218 * cfg - Config structure. 219 * Returns: 220 * SOC_E_XXX 221 */ 222 223 STATIC int 224 _phy_54580_medium_config_update(int unit, soc_port_t port, 225 soc_phy_config_t *cfg) 226 { 227 SOC_IF_ERROR_RETURN 228 (phy_54580_speed_set(unit, port, cfg->force_speed)); 229 SOC_IF_ERROR_RETURN 230 (phy_54580_duplex_set(unit, port, cfg->force_duplex)); 231 SOC_IF_ERROR_RETURN 232 (phy_54580_master_set(unit, port, cfg->master)); 233 SOC_IF_ERROR_RETURN 234 (phy_54580_adv_local_set(unit, port, cfg->autoneg_advert)); 235 SOC_IF_ERROR_RETURN 236 (phy_54580_autoneg_set(unit, port, cfg->autoneg_enable)); 237 SOC_IF_ERROR_RETURN 238 (phy_54580_mdix_set(unit, port, cfg->mdix)); 239 240 return SOC_E_NONE; 241 } 242 243 /*********************************************************************** 244 * 245 * PHY54580 DRIVER ROUTINES 246 */ 247 248 /* 249 * Function: 250 * phy_54580_medium_config_set 251 * Purpose: 252 * Set the operating parameters that are automatically selected 253 * when medium switches type. 254 * Parameters: 255 * unit - StrataSwitch unit # 256 * port - Port number 257 * medium - SOC_PORT_MEDIUM_COPPER/FIBER 258 * cfg - Operating parameters 259 * Returns: 260 * SOC_E_XXX 261 */ 262 263 STATIC int 264 phy_54580_medium_config_set(int unit, soc_port_t port, 265 soc_port_medium_t medium, 266 soc_phy_config_t *cfg) 267 { 268 phy_ctrl_t *pc; 269 soc_phy_config_t *active_medium; /* Currently active medium */ 270 soc_phy_config_t *change_medium; /* Requested medium */ 271 soc_phy_config_t *other_medium; /* The other medium */ 272 int medium_update; 273 soc_port_mode_t advert_mask; 274 275 if (NULL == cfg) { 276 return SOC_E_PARAM; 277 } 278 279 pc = EXT_PHY_SW_STATE(unit, port); 280 medium_update = FALSE; 281 282 switch (medium) { 283 case SOC_PORT_MEDIUM_COPPER: 284 if (!pc->automedium && !PHY_COPPER_MODE(unit, port)) { 285 return SOC_E_UNAVAIL; 286 } 287 change_medium = &pc->copper; 288 other_medium = &pc->fiber; 289 advert_mask = ADVERT_ALL_COPPER; 290 break; 291 case SOC_PORT_MEDIUM_FIBER: 292 if (!pc->automedium && !PHY_FIBER_MODE(unit, port)) { 293 return SOC_E_UNAVAIL; 294 } 295 change_medium = &pc->fiber; 296 other_medium = &pc->copper; 297 advert_mask = ADVERT_ALL_FIBER; 298 break; 299 default: 300 return SOC_E_PARAM; 301 } 302 303 /* 304 * Changes take effect immediately if the target medium is active or 305 * the preferred medium changes. 306 */ 307 if (change_medium->enable != cfg->enable) { 308 medium_update = TRUE; 309 } 310 if (change_medium->preferred != cfg->preferred) { 311 /* Make sure that only one medium is preferred */ 312 other_medium->preferred = !cfg->preferred; 313 medium_update = TRUE; 314 } 315 316 sal_memcpy(change_medium, cfg, sizeof(*change_medium)); 317 change_medium->autoneg_advert &= advert_mask; 318 319 if (medium_update) { 320 /* The new configuration may cause medium change. Check 321 * and update medium. 322 */ 323 SOC_IF_ERROR_RETURN 324 (_phy_54580_medium_change(unit, port, TRUE, medium)); 325 } else { 326 active_medium = (PHY_COPPER_MODE(unit, port)) ? 327 &pc->copper : &pc->fiber; 328 if (active_medium == change_medium) { 329 /* If the medium to update is active, update the configuration */ 330 SOC_IF_ERROR_RETURN 331 (_phy_54580_medium_config_update(unit, port, change_medium)); 332 } 333 } 334 return SOC_E_NONE; 335 } 336 337 /* 338 * Function: 339 * phy_54580_medium_config_get 340 * Purpose: 341 * Get the operating parameters that are automatically selected 342 * when medium switches type. 343 * Parameters: 344 * unit - StrataSwitch unit # 345 * port - Port number 346 * medium - SOC_PORT_MEDIUM_COPPER/FIBER 347 * cfg - (OUT) Operating parameters 348 * Returns: 349 * SOC_E_XXX 350 */ 351 352 STATIC int 353 phy_54580_medium_config_get(int unit, soc_port_t port, 354 soc_port_medium_t medium, 355 soc_phy_config_t *cfg) 356 { 357 int rv; 358 phy_ctrl_t *pc; 359 360 pc = EXT_PHY_SW_STATE(unit, port); 361 rv = SOC_E_NONE; 362 363 switch (medium) { 364 case SOC_PORT_MEDIUM_COPPER: 365 if (pc->automedium || PHY_COPPER_MODE(unit, port)) { 366 sal_memcpy(cfg, &pc->copper, sizeof (*cfg)); 367 } else { 368 rv = SOC_E_UNAVAIL; 369 } 370 break; 371 case SOC_PORT_MEDIUM_FIBER: 372 if (pc->automedium || PHY_FIBER_MODE(unit, port)) { 373 sal_memcpy(cfg, &pc->fiber, sizeof (*cfg)); 374 } else { 375 rv = SOC_E_UNAVAIL; 376 } 377 break; 378 default: 379 rv = SOC_E_PARAM; 380 break; 381 } 382 383 return rv; 384 } 385 386 387 /* 388 * Function: 389 * _phy_54580_no_reset_setup 390 * Purpose: 391 * Setup the operating parameters of the PHY without resetting PHY 392 * Parameters: 393 * unit - StrataSwitch unit # 394 * port - Port number 395 * Returns: 396 * SOC_E_XXX 397 */ 398 399 STATIC int 400 _phy_54580_no_reset_setup(int unit, soc_port_t port, int fiber) 401 { 402 phy_ctrl_t *int_pc; 403 phy_ctrl_t *pc; 404 bmacsec_dev_addr_t phy_dev_addr; 405 int rv = SOC_E_NONE; 406 int fiber_capable = 0; 407 408 LOG_INFO(BSL_LS_SOC_PHY, 409 (BSL_META_U(unit, 410 "_phy_54580_reset_setup: u=%d p=%d medium=%s\n"), 411 unit, port, 412 PHY_COPPER_MODE(unit, port) ? "COPPER" : "FIBER")); 413 414 pc = EXT_PHY_SW_STATE(unit, port); 415 int_pc = INT_PHY_SW_STATE(unit, port); 416 417 if (NULL != int_pc) { 418 SOC_IF_ERROR_RETURN 419 (PHY_INIT(int_pc->pd, unit, port)); 420 421 if (PHY_FIBER_MODE(unit, port)) { 422 /* Interface to MAC or internal SerDes is always SGMII mode. 423 * Typical internal SerDes driver set the interface to 1000BASE-X, 424 * if the media is fiber. Therefore, we need to force the interface 425 * of internal SerDes Driver to SGMII. */ 426 SOC_IF_ERROR_RETURN 427 (PHY_NOTIFY(int_pc->pd, unit, port, phyEventInterface, 428 SOC_PORT_IF_SGMII)); 429 } 430 431 if (PHY_COPPER_MODE(unit, port) && 432 !PHY_SGMII_AUTONEG_MODE(unit, port)) { 433 /* Make sure internal SerDes is in power down state 434 * until the MAC is ready. */ 435 SOC_IF_ERROR_RETURN 436 (PHY_NOTIFY(int_pc->pd, unit, port, 437 phyEventStop, PHY_STOP_COPPER)); 438 } 439 } 440 441 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 442 rv = bmacsec_phy54580_init(phy_dev_addr, 0, 443 pc->automedium, 444 fiber, 445 pc->fiber_detect, 446 pc->macsec_enable, 447 &fiber_capable); 448 if (rv != BMACSEC_E_NONE) { 449 return SOC_E_FAIL; 450 } 451 return SOC_E_NONE; 452 } 453 454 /* 455 * Function: 456 * phy_54580_init 457 * Purpose: 458 * Init function for 54580 PHY. 459 * Parameters: 460 * unit - StrataSwitch unit #. 461 * port - StrataSwitch port #. 462 * Returns: 463 * SOC_E_NONE 464 */ 465 466 STATIC int 467 phy_54580_init(int unit, soc_port_t port) 468 { 469 phy_ctrl_t *pc; 470 int fiber_capable, rv; 471 int fiber_preferred; 472 int qsgmii_mdio; 473 bmacsec_dev_addr_t macsec_dev_addr, qsgmii_dev_addr, phy_dev_addr; 474 int mmi_mdio_addr, port_index, macsec_enable; 475 476 LOG_INFO(BSL_LS_SOC_PHY, 477 (BSL_META_U(unit, 478 "phy_54xxx_init: u=%d p=%d\n"), 479 unit, port)); 480 481 /* Only SGMII interface to switch MAC is supported */ 482 if (IS_GMII_PORT(unit, port)) { 483 return SOC_E_CONFIG; 484 } 485 486 pc = EXT_PHY_SW_STATE(unit, port); 487 pc->interface = SOC_PORT_IF_SGMII; 488 489 qsgmii_mdio = (pc->phy_id - pc->macsec_dev_port + 8); 490 491 /* 492 * For 54540 the qsgmii_mdio will contain MDIO address 493 * of SGMII 494 */ 495 if (pc->phy_model == BMACSEC_PHY_BCM54540_MODEL) { 496 qsgmii_mdio = (pc->phy_id + 4); 497 } 498 499 mmi_mdio_addr = soc_property_port_get(unit, port, spn_MACSEC_DEV_ADDR, -1); 500 if (mmi_mdio_addr == -1) { 501 LOG_WARN(BSL_LS_SOC_PHY, 502 (BSL_META_U(unit, 503 "phy_54580_init: " 504 "MACSEC_DEV_ADDR property " 505 "not configured for u=%d p=%d\n"), unit, port)); 506 return SOC_E_CONFIG; 507 } 508 509 port_index = soc_property_port_get(unit, port, spn_MACSEC_PORT_INDEX, -1); 510 if (port_index == -1) { 511 LOG_WARN(BSL_LS_SOC_PHY, 512 (BSL_META_U(unit, 513 "phy_54580_init: " 514 "MACSEC_PORT_INDEX property not configured for " 515 "u=%d p=%d\n"), unit, port)); 516 return SOC_E_CONFIG; 517 } 518 519 pc->macsec_dev_addr = mmi_mdio_addr; 520 pc->macsec_dev_port = port_index; 521 522 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 523 macsec_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->macsec_dev_addr, 0); 524 qsgmii_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, qsgmii_mdio, 0); 525 526 macsec_enable = soc_property_port_get(unit, port, spn_MACSEC_ENABLE, 0); 527 pc->macsec_enable = macsec_enable; 528 529 if (pc->phy_rev == 0) { 530 rv = _macsec_54580_rev0_init(pc, pc->macsec_dev_port, pc->macsec_dev_addr, 531 macsec_enable); 532 } else if (pc->phy_rev == 1) { 533 rv = _macsec_54580_rev1_init(pc, pc->macsec_dev_port, pc->macsec_dev_addr, 534 macsec_enable); 535 } else { 536 rv = SOC_E_UNAVAIL; 537 } 538 if (!SOC_SUCCESS(rv)) { 539 return SOC_E_FAIL; 540 } 541 542 if (pc->phy_model == BMACSEC_PHY_BCM54540_MODEL) { 543 pc->macsec_dev_port = port_index + 4; 544 } 545 546 /* call common soc function to create port and setyp defaults */ 547 if (pc->phy_rev == 0) { 548 rv = soc_macsecphy_init(unit, port, pc, 549 BMACSEC_CORE_BCM5458X, bmacsec_io_mmi); 550 } else { 551 rv = soc_macsecphy_init(unit, port, pc, 552 BMACSEC_CORE_BCM5458X_B0, bmacsec_io_mmi1); 553 } 554 if (!SOC_SUCCESS(rv)) { 555 LOG_ERROR(BSL_LS_SOC_PHY, 556 (BSL_META_U(unit, 557 "soc_macsecphy_init: MACSEC init for" 558 " u=%d p=%d FAILED "), unit, port)); 559 return SOC_E_FAIL; 560 } else { 561 LOG_INFO(BSL_LS_SOC_PHY, 562 (BSL_META_U(unit, 563 "soc_macsecphy_init: MACSEC init for" 564 " u=%d p=%d SUCCESS "), unit, port)); 565 } 566 567 rv = bmacsec_phy54580_phy_mac_addr_set(phy_dev_addr, macsec_dev_addr, 568 qsgmii_dev_addr, 569 qsgmii_mdio, pc->macsec_dev_port, 570 (pc->phy_rev) ? bmacsec_io_mmi1 : bmacsec_io_mmi); 571 if(rv != BMACSEC_E_NONE) { 572 LOG_WARN(BSL_LS_SOC_PHY, 573 (BSL_META_U(unit, 574 "phy_54580_init: bmacsec_phy_mac_addr_set " 575 "returned error for u=%d p=%d\n"), unit, port)); 576 return SOC_E_FAIL; 577 } 578 579 fiber_capable = 1; 580 581 /* Change it to copper prefer for default. 582 * Because the SD of fiber doesn't work in BCM54580 583 */ 584 fiber_preferred = 585 soc_property_port_get(unit, port, spn_PHY_FIBER_PREF, 0); 586 pc->automedium = 587 soc_property_port_get(unit, port, spn_PHY_AUTOMEDIUM, 1); 588 pc->fiber_detect = 589 soc_property_port_get(unit, port, spn_PHY_FIBER_DETECT, 0); 590 591 LOG_INFO(BSL_LS_SOC_PHY, 592 (BSL_META_U(unit, 593 "phy_54580_init: " 594 "u=%d p=%d type=54580%s automedium=%d fiber_pref=%d detect=%d\n"), 595 unit, port, fiber_capable ? "S" : "", 596 pc->automedium, fiber_preferred, pc->fiber_detect)); 597 598 /* Init PHYS and MACs to defaults */ 599 rv = bmacsec_phy54580_init(phy_dev_addr, 1, 600 pc->automedium, 601 fiber_preferred, 602 pc->fiber_detect, 603 pc->macsec_enable, 604 &fiber_capable); 605 606 if (rv != BMACSEC_E_NONE) { 607 return SOC_E_FAIL; 608 } 609 610 /* Based on automedium, fiber_preferred and the PHY model, fiber enable is 611 * set to 1 or 0. 612 * For 54584 devices only port 7 and port 8 are fiber capable hence 613 * fiber properties apply to port 7 and port 8. 614 * 54580 is copper only PHY, hence only copper properties are set 615 */ 616 if (fiber_capable == 0) { /* not fiber capable */ 617 fiber_preferred = 0; 618 pc->automedium = 0; 619 pc->fiber_detect = 0; 620 } 621 622 if (pc->phy_model == BMACSEC_PHY_BCM54540_MODEL) { 623 if (pc->automedium == 0) { 624 /* Power down non-preferred media */ 625 if (fiber_preferred == 0) { /* Power Down Fiber */ 626 rv = bmacsec_phy54580_enable_set(phy_dev_addr, 0, 627 BMACSEC_PHY_FIBER, 0); 628 } else { /* Power down copper */ 629 rv = bmacsec_phy54580_enable_set(phy_dev_addr, 0, 630 BMACSEC_PHY_COPPER, 0); 631 } 632 } 633 } 634 if (rv != BMACSEC_E_NONE) { 635 return SOC_E_FAIL; 636 } 637 638 pc->copper.enable = TRUE; 639 pc->copper.preferred = !fiber_preferred; 640 pc->copper.autoneg_enable = TRUE; 641 pc->copper.autoneg_advert = ADVERT_ALL_COPPER; 642 pc->copper.force_speed = 1000; 643 pc->copper.force_duplex = TRUE; 644 pc->copper.master = SOC_PORT_MS_AUTO; 645 pc->copper.mdix = SOC_PORT_MDIX_AUTO; 646 647 pc->fiber.enable = fiber_capable; 648 pc->fiber.preferred = fiber_preferred; 649 pc->fiber.autoneg_enable = fiber_capable; 650 pc->fiber.autoneg_advert = ADVERT_ALL_FIBER; 651 pc->fiber.force_speed = 1000; 652 pc->fiber.force_duplex = TRUE; 653 pc->fiber.master = SOC_PORT_MS_NONE; 654 pc->fiber.mdix = SOC_PORT_MDIX_NORMAL; 655 656 /* Initially configure for the preferred medium. */ 657 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_COPPER); 658 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER); 659 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_PASSTHRU); 660 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX); 661 if (pc->fiber.preferred) { 662 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER); 663 } else { 664 PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER); 665 } 666 667 /* Get Requested LED selectors (defaults are hardware defaults) */ 668 pc->ledmode[0] = soc_property_port_get(unit, port, spn_PHY_LED1_MODE, 0); 669 pc->ledmode[1] = soc_property_port_get(unit, port, spn_PHY_LED2_MODE, 1); 670 pc->ledmode[2] = soc_property_port_get(unit, port, spn_PHY_LED3_MODE, 3); 671 pc->ledmode[3] = soc_property_port_get(unit, port, spn_PHY_LED4_MODE, 6); 672 pc->ledctrl = soc_property_port_get(unit, port, spn_PHY_LED_CTRL, 0x8); 673 pc->ledselect = soc_property_port_get(unit, port, spn_PHY_LED_SELECT, 0); 674 675 /* 676 * Some reasonable defaults 677 */ 678 pc->macsec_switch_fixed = 0; 679 pc->macsec_switch_fixed_speed = 1000; 680 pc->macsec_switch_fixed_duplex = 1; 681 pc->macsec_switch_fixed_pause = 1; 682 pc->macsec_pause_rx_fwd = 0; 683 pc->macsec_pause_tx_fwd = 0; 684 pc->macsec_line_ipg = 0xc; 685 pc->macsec_switch_ipg = 0xc; 686 687 688 /* Set LED Modes and Control */ 689 rv = bmacsec_phy54580_set_led_selectors(phy_dev_addr, pc->ledmode[0], 690 pc->ledmode[1], pc->ledmode[2], 691 pc->ledmode[3], pc->ledselect, 692 pc->ledctrl); 693 if (rv != BMACSEC_E_NONE) { 694 return SOC_E_FAIL; 695 } 696 697 if (0) { 698 SOC_IF_ERROR_RETURN 699 (_phy_54580_medium_config_update(unit, port, 700 PHY_COPPER_MODE(unit, port) ? 701 &pc->copper : 702 &pc->fiber)); 703 } 704 return SOC_E_NONE; 705 } 706 707 708 /* 709 * Function: 710 * phy_54580_reset 711 * Purpose: 712 * Reset PHY and wait for it to come out of reset. 713 * Parameters: 714 * unit - StrataSwitch unit #. 715 * port - StrataSwitch port #. 716 * Returns: 717 * SOC_E_XXX 718 */ 719 720 int 721 phy_54580_reset(int unit, soc_port_t port, void *user_arg) 722 { 723 724 int rv; 725 phy_ctrl_t *pc; 726 bmacsec_dev_addr_t phy_dev_addr; 727 728 pc = EXT_PHY_SW_STATE(unit, port); 729 730 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 731 rv = bmacsec_phy54580_reset(phy_dev_addr); 732 733 return (SOC_ERROR(rv)); 734 } 735 736 /* 737 * Function: 738 * phy_54580_enable_set 739 * Purpose: 740 * Enable or disable the physical interface. 741 * Parameters: 742 * unit - StrataSwitch unit #. 743 * port - StrataSwitch port #. 744 * enable - Boolean, true = enable PHY, false = disable. 745 * Returns: 746 * SOC_E_XXX 747 */ 748 749 STATIC int 750 phy_54580_enable_set(int unit, soc_port_t port, int enable) 751 { 752 phy_ctrl_t *pc; 753 int rv = SOC_E_NONE; 754 bmacsec_dev_addr_t phy_dev_addr; 755 bmacsec_phy54580_port_mode_t port_mode = 0; 756 757 pc = EXT_PHY_SW_STATE(unit, port); 758 759 if(PHY_COPPER_MODE(unit, port)) { 760 port_mode = BMACSEC_PHY_COPPER; 761 } else { 762 if(PHY_FIBER_MODE(unit, port)) { 763 port_mode = BMACSEC_PHY_FIBER; 764 } 765 } 766 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 767 rv = bmacsec_phy54580_enable_set(phy_dev_addr, pc->automedium, 768 port_mode, enable); 769 if(rv != BMACSEC_E_NONE) { 770 return SOC_E_FAIL; 771 } 772 773 if (pc->automedium || PHY_FIBER_MODE(unit, port)) { 774 phy_ctrl_t *int_pc; 775 776 int_pc = INT_PHY_SW_STATE(unit, port); 777 if (NULL != int_pc) { 778 SOC_IF_ERROR_RETURN 779 (PHY_ENABLE_SET(int_pc->pd, unit, port, enable)); 780 } 781 782 LOG_INFO(BSL_LS_SOC_PHY, 783 (BSL_META_U(unit, 784 "phy_54580_enable_set: " 785 "Power %s fiber medium\n"), (enable) ? "up" : "down")); 786 } 787 788 /* Update software state */ 789 SOC_IF_ERROR_RETURN(phy_fe_ge_enable_set(unit, port, enable)); 790 791 return SOC_E_NONE; 792 } 793 794 /* 795 * Function: 796 * phy_54580_enable_get 797 * Purpose: 798 * Enable or disable the physical interface for a 54580 device. 799 * Parameters: 800 * unit - StrataSwitch unit #. 801 * port - StrataSwitch port #. 802 * enable - (OUT) Boolean, true = enable PHY, false = disable. 803 * Returns: 804 * SOC_E_XXX 805 */ 806 807 STATIC int 808 phy_54580_enable_get(int unit, soc_port_t port, int *enable) 809 { 810 return phy_fe_ge_enable_get(unit, port, enable); 811 } 812 813 /* 814 * Function: 815 * _phy_54580_medium_change 816 * Purpose: 817 * Change medium when media change detected or forced 818 * Parameters: 819 * unit - StrataSwitch unit #. 820 * port - StrataSwitch port #. 821 * force_update - Force update 822 * force_medium - Force update medium 823 * Returns: 824 * SOC_E_XXX 825 */ 826 STATIC int 827 _phy_54580_medium_change(int unit, soc_port_t port, int force_update, 828 soc_port_medium_t force_medium) 829 { 830 phy_ctrl_t *pc; 831 int medium; 832 833 pc = EXT_PHY_SW_STATE(unit, port); 834 835 if (force_update == TRUE) { 836 medium = force_medium; 837 } else { 838 SOC_IF_ERROR_RETURN 839 (_phy_54580_medium_check(unit, port, &medium)); 840 } 841 842 if (medium == SOC_PORT_MEDIUM_COPPER) { 843 if (!PHY_COPPER_MODE(unit, port) || force_update) { /* Was fiber */ 844 PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER); 845 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER); 846 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX); 847 PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 848 SOC_IF_ERROR_RETURN 849 (_phy_54580_no_reset_setup(unit, port, 0)); 850 851 /* Do Not power up the interface if medium is disabled */ 852 if (pc->copper.enable) { 853 SOC_IF_ERROR_RETURN 854 (_phy_54580_medium_config_update(unit, port, &pc->copper)); 855 } 856 LOG_INFO(BSL_LS_SOC_PHY, 857 (BSL_META_U(unit, 858 "_phy_54580_link_auto_detect: u=%d p=%d [F->C]\n"), 859 unit, port)); 860 } 861 } else { /* Fiber */ 862 if (PHY_COPPER_MODE(unit, port) || force_update) { /* Was copper */ 863 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_COPPER); 864 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER); 865 PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 866 SOC_IF_ERROR_RETURN 867 (_phy_54580_no_reset_setup(unit, port, 1)); 868 869 SOC_IF_ERROR_RETURN 870 (_phy_54580_medium_config_update(unit, port, &pc->fiber)); 871 LOG_INFO(BSL_LS_SOC_PHY, 872 (BSL_META_U(unit, 873 "_phy_54580_link_auto_detect: u=%d p=%d [C->F]\n"), 874 unit, port)); 875 } 876 } 877 878 return SOC_E_NONE; 879 } 880 881 /* 882 * Function: 883 * phy_54580_link_get 884 * Purpose: 885 * Determine the current link up/down status for a 54580 device. 886 * Parameters: 887 * unit - StrataSwitch unit #. 888 * port - StrataSwitch port #. 889 * link - (OUT) Boolean, true indicates link established. 890 * Returns: 891 * SOC_E_XXX 892 * Notes: 893 * If using automedium, also switches the mode. 894 */ 895 STATIC int 896 phy_54580_link_get(int unit, soc_port_t port, int *link) 897 { 898 phy_ctrl_t *pc; 899 uint16 data; 900 int rv = SOC_E_NONE; 901 bmacsec_phy54580_port_mode_t port_mode = 0; 902 bmacsec_dev_addr_t phy_dev_addr; 903 int bmacsec_link; 904 905 906 pc = EXT_PHY_SW_STATE(unit, port); 907 *link = FALSE; /* Default return */ 908 909 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) { 910 return SOC_E_NONE; 911 } 912 913 if (!pc->fiber.enable && !pc->copper.enable) { 914 return SOC_E_NONE; 915 } 916 917 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 918 if (pc->automedium) { 919 /* Check for medium change and update HW/SW accordingly. */ 920 SOC_IF_ERROR_RETURN 921 (_phy_54580_medium_change(unit, port, FALSE, 0)); 922 } 923 924 if(PHY_COPPER_MODE(unit, port)) { 925 port_mode = BMACSEC_PHY_COPPER; 926 } else { 927 if(PHY_FIBER_MODE(unit, port)) { 928 port_mode = BMACSEC_PHY_FIBER; 929 } 930 } 931 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 932 rv = bmacsec_phy_54580_link_get(phy_dev_addr, port_mode, &bmacsec_link); 933 if (!BMACSEC_E_SUCCESS(rv)) { 934 return SOC_E_FAIL; 935 } 936 if (bmacsec_link == 1) { 937 *link = TRUE; 938 } else { 939 *link = FALSE; 940 } 941 942 /* If preferred medium is up, disable the other medium 943 * to prevent false link. */ 944 if (pc->automedium) { 945 if (pc->copper.preferred) { 946 if (pc->fiber.enable) { 947 /* Power down Serdes if Copper mode is up */ 948 data = (*link && PHY_COPPER_MODE(unit, port)) ? 0 : 1; 949 } else { 950 data = 0; 951 952 } 953 port_mode = BMACSEC_PHY_FIBER; 954 (void)bmacsec_phy54580_enable_set(phy_dev_addr, pc->automedium, 955 port_mode, data); 956 } else { /* pc->fiber.preferred */ 957 if (pc->copper.enable) { 958 data = (*link && PHY_FIBER_MODE(unit, port)) ? 0 : 1; 959 } else { 960 data = 0; 961 } 962 port_mode = BMACSEC_PHY_COPPER; 963 (void)bmacsec_phy54580_enable_set(phy_dev_addr, pc->automedium, 964 port_mode, data); 965 } 966 } 967 968 LOG_VERBOSE(BSL_LS_SOC_PHY, 969 (BSL_META_U(unit, 970 "phy_54580_link_get: u=%d p=%d mode=%s%s link=%d\n"), 971 unit, port, 972 PHY_COPPER_MODE(unit, port) ? "C" : "F", 973 PHY_FIBER_100FX_MODE(unit, port)? "(100FX)" : "", 974 *link)); 975 976 return SOC_E_NONE; 977 } 978 979 980 /* 981 * Function: 982 * phy_54580_duplex_set 983 * Purpose: 984 * Set the current duplex mode (forced). 985 * Parameters: 986 * unit - StrataSwitch unit #. 987 * port - StrataSwitch port #. 988 * duplex - Boolean, true indicates full duplex, false indicates half. 989 * Returns: 990 * SOC_E_NONE 991 * SOC_E_UNAVAIL - Half duplex requested, and not supported. 992 * Notes: 993 * The duplex is set only for the ACTIVE medium. 994 * No synchronization performed at this level. 995 * Autonegotiation is not manipulated. 996 */ 997 998 STATIC int 999 phy_54580_duplex_set(int unit, soc_port_t port, int duplex) 1000 { 1001 int rv; 1002 phy_ctrl_t *pc; 1003 bmacsec_phy54580_port_mode_t port_mode = 0; 1004 bmacsec_dev_addr_t phy_dev_addr; 1005 bmacsec_phy54580_duplex_t bmacsec_duplex; 1006 1007 pc = EXT_PHY_SW_STATE(unit, port); 1008 rv = SOC_E_NONE; 1009 1010 if(PHY_COPPER_MODE(unit, port)) { 1011 port_mode = BMACSEC_PHY_COPPER; 1012 } else { 1013 if(PHY_FIBER_MODE(unit, port)) { 1014 port_mode = BMACSEC_PHY_FIBER; 1015 if (duplex == 0) { 1016 return SOC_E_UNAVAIL; 1017 } 1018 } 1019 } 1020 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 1021 if (duplex) { 1022 bmacsec_duplex = BMACSEC_FULL_DUPLEX; 1023 } else { 1024 bmacsec_duplex = BMACSEC_HALF_DUPLEX; 1025 } 1026 rv = bmacsec_phy54580_duplex_set(phy_dev_addr, port_mode, 1027 bmacsec_duplex); 1028 1029 if(BMACSEC_E_SUCCESS(rv)) { 1030 pc->copper.force_duplex = duplex; 1031 } 1032 1033 LOG_INFO(BSL_LS_SOC_PHY, 1034 (BSL_META_U(unit, 1035 "phy_54580_duplex_set: u=%d p=%d d=%d rv=%d\n"), 1036 unit, port, duplex, rv)); 1037 return (SOC_ERROR(rv)); 1038 } 1039 1040 /* 1041 * Function: 1042 * phy_54580_duplex_get 1043 * Purpose: 1044 * Get the current operating duplex mode. If autoneg is enabled, 1045 * then operating mode is returned, otherwise forced mode is returned. 1046 * Parameters: 1047 * unit - StrataSwitch unit #. 1048 * port - StrataSwitch port #. 1049 * duplex - (OUT) Boolean, true indicates full duplex, false 1050 * indicates half. 1051 * Returns: 1052 * SOC_E_NONE 1053 * Notes: 1054 * The duplex is retrieved for the ACTIVE medium. 1055 * No synchronization performed at this level. Autonegotiation is 1056 * not manipulated. 1057 */ 1058 1059 STATIC int 1060 phy_54580_duplex_get(int unit, soc_port_t port, int *duplex) 1061 { 1062 1063 int rv = SOC_E_NONE; 1064 bmacsec_phy54580_port_mode_t port_mode = 0; 1065 phy_ctrl_t *pc; 1066 bmacsec_dev_addr_t phy_dev_addr; 1067 bmacsec_phy54580_duplex_t bmacsec_duplex; 1068 1069 pc = EXT_PHY_SW_STATE(unit, port); 1070 1071 if(PHY_COPPER_MODE(unit, port)) { 1072 port_mode = BMACSEC_PHY_COPPER; 1073 } else { 1074 if(PHY_FIBER_MODE(unit, port)) { 1075 port_mode = BMACSEC_PHY_FIBER; 1076 *duplex = TRUE; 1077 return SOC_E_NONE; 1078 } 1079 } 1080 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 1081 rv = bmacsec_phy54580_duplex_get(phy_dev_addr, port_mode, 1082 &bmacsec_duplex); 1083 if (rv != BMACSEC_E_NONE) { 1084 return SOC_E_FAIL; 1085 } 1086 if (bmacsec_duplex == BMACSEC_FULL_DUPLEX) { 1087 *duplex = TRUE; 1088 } else { 1089 *duplex = FALSE; 1090 } 1091 1092 return SOC_E_NONE; 1093 } 1094 1095 /* 1096 * Function: 1097 * phy_54580_speed_set 1098 * Purpose: 1099 * Set the current operating speed (forced). 1100 * Parameters: 1101 * unit - StrataSwitch unit #. 1102 * port - StrataSwitch port #. 1103 * speed - Requested speed, only 1000 supported. 1104 * Returns: 1105 * SOC_E_XXX 1106 * Notes: 1107 * The speed is set only for the ACTIVE medium. 1108 */ 1109 1110 STATIC int 1111 phy_54580_speed_set(int unit, soc_port_t port, int speed) 1112 { 1113 int rv; 1114 phy_ctrl_t *pc; 1115 bmacsec_dev_addr_t phy_dev_addr; 1116 bmacsec_phy54580_port_mode_t port_mode = 0; 1117 1118 pc = EXT_PHY_SW_STATE(unit, port); 1119 rv = SOC_E_NONE; 1120 1121 if(PHY_COPPER_MODE(unit, port)) { 1122 port_mode = BMACSEC_PHY_COPPER; 1123 } else { 1124 if(PHY_FIBER_MODE(unit, port)) { 1125 port_mode = BMACSEC_PHY_FIBER; 1126 if (speed == 10) { 1127 return SOC_E_UNAVAIL; 1128 } 1129 } 1130 } 1131 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 1132 rv = bmacsec_phy54580_speed_set(phy_dev_addr, port_mode, speed); 1133 1134 if(BMACSEC_E_SUCCESS(rv)) { 1135 if(PHY_COPPER_MODE(unit, port)) { 1136 pc->copper.force_speed = speed; 1137 } else { 1138 if(PHY_FIBER_MODE(unit, port)) { 1139 pc->fiber.force_speed = speed; 1140 1141 if (speed == 100) { 1142 PHY_FLAGS_SET(unit, port, PHY_FLAGS_100FX); 1143 pc->fiber.autoneg_enable = FALSE; 1144 phy_54580_autoneg_set(unit, port, 0); 1145 } 1146 1147 if (speed == 1000) { 1148 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX); 1149 phy_54580_autoneg_set(unit, port, 1150 pc->fiber.autoneg_enable); 1151 } 1152 } 1153 } 1154 } 1155 LOG_INFO(BSL_LS_SOC_PHY, 1156 (BSL_META_U(unit, 1157 "phy_54580_speed_set: u=%d p=%d s=%d fiber=%d rv=%d\n"), 1158 unit, port, speed, PHY_FIBER_MODE(unit, port), rv)); 1159 1160 return SOC_ERROR(rv); 1161 } 1162 1163 /* 1164 * Function: 1165 * phy_54580_speed_get 1166 * Purpose: 1167 * Get the current operating speed for a 54580 device. 1168 * Parameters: 1169 * unit - StrataSwitch unit #. 1170 * port - StrataSwitch port #. 1171 * duplex - (OUT) Boolean, true indicates full duplex, false 1172 * indicates half. 1173 * Returns: 1174 * SOC_E_NONE 1175 * Notes: 1176 * The speed is retrieved for the ACTIVE medium. 1177 */ 1178 1179 STATIC int 1180 phy_54580_speed_get(int unit, soc_port_t port, int *speed) 1181 { 1182 int rv = SOC_E_NONE; 1183 bmacsec_phy54580_port_mode_t port_mode = 0; 1184 bmacsec_dev_addr_t phy_dev_addr; 1185 phy_ctrl_t *pc; 1186 1187 pc = EXT_PHY_SW_STATE(unit, port); 1188 1189 if(PHY_COPPER_MODE(unit, port)) { 1190 port_mode = BMACSEC_PHY_COPPER; 1191 } else { 1192 if(PHY_FIBER_MODE(unit, port)) { 1193 port_mode = BMACSEC_PHY_FIBER; 1194 } 1195 } 1196 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 1197 rv = bmacsec_phy54580_speed_get(phy_dev_addr, port_mode, speed); 1198 1199 if(!BMACSEC_E_SUCCESS(rv)) { 1200 LOG_WARN(BSL_LS_SOC_PHY, 1201 (BSL_META_U(unit, 1202 "phy_54580_speed_get: u=%d p=%d invalid speed\n"), 1203 unit, port)); 1204 } else { 1205 LOG_INFO(BSL_LS_SOC_PHY, 1206 (BSL_META_U(unit, 1207 "phy_54580_speed_get: u=%d p=%d speed=%d"), 1208 unit, port, *speed)); 1209 } 1210 1211 return SOC_ERROR(rv); 1212 } 1213 1214 /* 1215 * Function: 1216 * phy_54580_master_set 1217 * Purpose: 1218 * Set the current master mode 1219 * Parameters: 1220 * unit - StrataSwitch unit #. 1221 * port - StrataSwitch port #. 1222 * master - SOC_PORT_MS_* 1223 * Returns: 1224 * SOC_E_XXX 1225 * Notes: 1226 * The master mode is set only for the ACTIVE medium. 1227 */ 1228 STATIC int 1229 phy_54580_master_set(int unit, soc_port_t port, int master) 1230 { 1231 int rv; 1232 phy_ctrl_t *pc; 1233 bmacsec_phy54580_port_mode_t port_mode = 0; 1234 bmacsec_dev_addr_t phy_dev_addr; 1235 1236 pc = EXT_PHY_SW_STATE(unit, port); 1237 rv = SOC_E_NONE; 1238 1239 if(PHY_COPPER_MODE(unit, port)) { 1240 port_mode = BMACSEC_PHY_COPPER; 1241 } else { 1242 if(PHY_FIBER_MODE(unit, port)) { 1243 port_mode = BMACSEC_PHY_FIBER; 1244 } 1245 } 1246 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 1247 rv = bmacsec_phy54580_master_set(phy_dev_addr, port_mode, master); 1248 if(BMACSEC_E_SUCCESS(rv)) { 1249 pc->copper.master = master; 1250 } 1251 1252 LOG_INFO(BSL_LS_SOC_PHY, 1253 (BSL_META_U(unit, 1254 "phy_54580_master_set: u=%d p=%d master=%d fiber=%d rv=%d\n"), 1255 unit, port, master, PHY_FIBER_MODE(unit, port), rv)); 1256 1257 return SOC_ERROR(rv); 1258 } 1259 1260 /* 1261 * Function: 1262 * phy_54580_master_get 1263 * Purpose: 1264 * Get the current master mode for a 54580 device. 1265 * Parameters: 1266 * unit - StrataSwitch unit #. 1267 * port - StrataSwitch port #. 1268 * master - (OUT) SOC_PORT_MS_* 1269 * Returns: 1270 * SOC_E_NONE 1271 * Notes: 1272 * The master mode is retrieved for the ACTIVE medium. 1273 */ 1274 1275 STATIC int 1276 phy_54580_master_get(int unit, soc_port_t port, int *master) 1277 { 1278 int rv; 1279 phy_ctrl_t *pc; 1280 bmacsec_phy54580_port_mode_t port_mode = 0; 1281 bmacsec_dev_addr_t phy_dev_addr; 1282 1283 pc = EXT_PHY_SW_STATE(unit, port); 1284 rv = SOC_E_NONE; 1285 1286 if(PHY_COPPER_MODE(unit, port)) { 1287 port_mode = BMACSEC_PHY_COPPER; 1288 } else { 1289 if(PHY_FIBER_MODE(unit, port)) { 1290 port_mode = BMACSEC_PHY_FIBER; 1291 *master = SOC_PORT_MS_NONE; 1292 return SOC_E_NONE; 1293 } 1294 } 1295 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 1296 rv = bmacsec_phy54580_master_get(phy_dev_addr, port_mode, master); 1297 1298 return SOC_ERROR(rv); 1299 } 1300 1301 /* 1302 * Function: 1303 * phy_54580_autoneg_set 1304 * Purpose: 1305 * Enable or disable auto-negotiation on the specified port. 1306 * Parameters: 1307 * unit - StrataSwitch unit #. 1308 * port - StrataSwitch port #. 1309 * autoneg - Boolean, if true, auto-negotiation is enabled 1310 * (and/or restarted). If false, autonegotiation is disabled. 1311 * Returns: 1312 * SOC_E_XXX 1313 * Notes: 1314 * The autoneg mode is set only for the ACTIVE medium. 1315 */ 1316 1317 STATIC int 1318 phy_54580_autoneg_set(int unit, soc_port_t port, int autoneg) 1319 { 1320 int rv; 1321 phy_ctrl_t *pc; 1322 int autoneg_advert = 0; 1323 bmacsec_phy54580_port_mode_t port_mode = 0; 1324 bmacsec_dev_addr_t phy_dev_addr; 1325 1326 1327 pc = EXT_PHY_SW_STATE(unit, port); 1328 rv = SOC_E_NONE; 1329 1330 if(PHY_COPPER_MODE(unit, port)) { 1331 port_mode = BMACSEC_PHY_COPPER; 1332 autoneg_advert = 0; 1333 } else { 1334 if(PHY_FIBER_MODE(unit, port)) { 1335 port_mode = BMACSEC_PHY_FIBER; 1336 autoneg_advert = pc->fiber.autoneg_advert; 1337 } 1338 } 1339 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 1340 rv = bmacsec_phy54580_an_set(phy_dev_addr, port_mode, 1341 autoneg, autoneg_advert); 1342 if(BMACSEC_E_SUCCESS(rv)) { 1343 if(PHY_COPPER_MODE(unit, port)) { 1344 pc->copper.autoneg_enable = autoneg ? TRUE : FALSE; 1345 } else { 1346 if(PHY_FIBER_MODE(unit, port)) { 1347 pc->fiber.autoneg_enable = autoneg ? TRUE : FALSE; 1348 } 1349 } 1350 } 1351 1352 LOG_INFO(BSL_LS_SOC_PHY, 1353 (BSL_META_U(unit, 1354 "phy_54580_autoneg_set: u=%d p=%d autoneg=%d rv=%d\n"), 1355 unit, port, autoneg, rv)); 1356 return SOC_ERROR(rv); 1357 } 1358 1359 /* 1360 * Function: 1361 * phy_54580_autoneg_get 1362 * Purpose: 1363 * Get the current auto-negotiation status (enabled/busy). 1364 * Parameters: 1365 * unit - StrataSwitch unit #. 1366 * port - StrataSwitch port #. 1367 * autoneg - (OUT) if true, auto-negotiation is enabled. 1368 * autoneg_done - (OUT) if true, auto-negotiation is complete. This 1369 * value is undefined if autoneg == FALSE. 1370 * Returns: 1371 * SOC_E_XXX 1372 * Notes: 1373 * The autoneg mode is retrieved for the ACTIVE medium. 1374 */ 1375 1376 STATIC int 1377 phy_54580_autoneg_get(int unit, soc_port_t port, 1378 int *autoneg, int *autoneg_done) 1379 { 1380 int rv; 1381 phy_ctrl_t *pc; 1382 bmacsec_phy54580_port_mode_t port_mode = 0; 1383 bmacsec_dev_addr_t phy_dev_addr; 1384 1385 pc = EXT_PHY_SW_STATE(unit, port); 1386 1387 rv = SOC_E_NONE; 1388 *autoneg = FALSE; 1389 *autoneg_done = FALSE; 1390 1391 if(PHY_COPPER_MODE(unit, port)) { 1392 port_mode = BMACSEC_PHY_COPPER; 1393 } else { 1394 if(PHY_FIBER_MODE(unit, port)) { 1395 port_mode = BMACSEC_PHY_FIBER; 1396 } 1397 } 1398 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 1399 rv = bmacsec_phy54580_an_get(phy_dev_addr, port_mode, autoneg, 1400 autoneg_done); 1401 1402 return SOC_ERROR(rv); 1403 } 1404 1405 /* 1406 * Function: 1407 * phy_54580_adv_local_set 1408 * Purpose: 1409 * Set the current advertisement for auto-negotiation. 1410 * Parameters: 1411 * unit - StrataSwitch unit #. 1412 * port - StrataSwitch port #. 1413 * mode - Port mode mask indicating supported options/speeds. 1414 * Returns: 1415 * SOC_E_XXX 1416 * Notes: 1417 * The advertisement is set only for the ACTIVE medium. 1418 * No synchronization performed at this level. 1419 */ 1420 1421 STATIC int 1422 phy_54580_adv_local_set(int unit, soc_port_t port, soc_port_mode_t mode) 1423 { 1424 int rv; 1425 phy_ctrl_t *pc; 1426 bmacsec_phy54580_port_mode_t port_mode = 0; 1427 bmacsec_dev_addr_t phy_dev_addr; 1428 bmacsec_port_mode_t bmacsec_mode = 0; 1429 1430 pc = EXT_PHY_SW_STATE(unit, port); 1431 rv = SOC_E_NONE; 1432 1433 if(PHY_COPPER_MODE(unit, port)) { 1434 port_mode = BMACSEC_PHY_COPPER; 1435 } else { 1436 if(PHY_FIBER_MODE(unit, port)) { 1437 port_mode = BMACSEC_PHY_FIBER; 1438 } 1439 } 1440 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 1441 if(mode & SOC_PM_10MB_HD) { 1442 bmacsec_mode |= BMACSEC_PM_10MB_HD; 1443 } 1444 if(mode & SOC_PM_10MB_FD) { 1445 bmacsec_mode |= BMACSEC_PM_10MB_FD; 1446 } 1447 if(mode & SOC_PM_100MB_HD) { 1448 bmacsec_mode |= BMACSEC_PM_100MB_HD; 1449 } 1450 if(mode & SOC_PM_100MB_FD) { 1451 bmacsec_mode |= BMACSEC_PM_100MB_FD; 1452 } 1453 if(mode & SOC_PM_1000MB_HD) { 1454 bmacsec_mode |= BMACSEC_PM_1000MB_HD; 1455 } 1456 if(mode & SOC_PM_1000MB_FD) { 1457 bmacsec_mode |= BMACSEC_PM_1000MB_FD; 1458 } 1459 if((mode & SOC_PM_PAUSE) == SOC_PM_PAUSE) { 1460 bmacsec_mode |= BMACSEC_PM_PAUSE; 1461 } 1462 if(mode & SOC_PM_PAUSE_TX) { 1463 bmacsec_mode |= BMACSEC_PM_PAUSE_TX; 1464 } 1465 if(mode & SOC_PM_PAUSE_RX) { 1466 bmacsec_mode |= BMACSEC_PM_PAUSE_RX; 1467 } 1468 1469 1470 rv = bmacsec_phy54580_adv_local_set(phy_dev_addr, port_mode, bmacsec_mode); 1471 1472 if(BMACSEC_E_SUCCESS(rv)) { 1473 if(PHY_COPPER_MODE(unit, port)) { 1474 pc->copper.autoneg_advert = mode & ADVERT_ALL_COPPER; 1475 } else { 1476 if(PHY_FIBER_MODE(unit, port)) { 1477 pc->fiber.autoneg_advert = mode & ADVERT_ALL_FIBER; 1478 } 1479 } 1480 } 1481 1482 LOG_INFO(BSL_LS_SOC_PHY, 1483 (BSL_META_U(unit, 1484 "phy_54580_adv_local_set: u=%d p=%d mode=0x%x, rv=%d\n"), 1485 unit, port, mode, rv)); 1486 return (SOC_ERROR(rv)); 1487 } 1488 1489 /* 1490 * Function: 1491 * phy_54580_adv_local_get 1492 * Purpose: 1493 * Get the current advertisement for auto-negotiation. 1494 * Parameters: 1495 * unit - StrataSwitch unit #. 1496 * port - StrataSwitch port #. 1497 * mode - (OUT) Port mode mask indicating supported options/speeds. 1498 * Returns: 1499 * SOC_E_XXX 1500 * Notes: 1501 * The advertisement is retrieved for the ACTIVE medium. 1502 * No synchronization performed at this level. 1503 */ 1504 1505 STATIC int 1506 phy_54580_adv_local_get(int unit, soc_port_t port, soc_port_mode_t *mode) 1507 { 1508 1509 int rv; 1510 bmacsec_phy54580_port_mode_t port_mode = BMACSEC_PHY_COPPER; 1511 phy_ctrl_t *pc; 1512 bmacsec_dev_addr_t phy_dev_addr; 1513 bmacsec_port_mode_t bmacsec_mode = 0; 1514 1515 pc = EXT_PHY_SW_STATE(unit, port); 1516 rv = SOC_E_NONE; 1517 1518 if(PHY_COPPER_MODE(unit, port)) { 1519 port_mode = BMACSEC_PHY_COPPER; 1520 } else { 1521 if(PHY_FIBER_MODE(unit, port)) { 1522 port_mode = BMACSEC_PHY_FIBER; 1523 } 1524 } 1525 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 1526 rv = bmacsec_phy54580_adv_local_get(phy_dev_addr, port_mode, 1527 &bmacsec_mode); 1528 *mode = 0; 1529 if (rv == BMACSEC_E_NONE) { 1530 if(bmacsec_mode & BMACSEC_PM_10MB_HD) { 1531 *mode |= SOC_PM_10MB_HD; 1532 } 1533 if(bmacsec_mode & BMACSEC_PM_10MB_FD) { 1534 *mode |= SOC_PM_10MB_FD; 1535 } 1536 if(bmacsec_mode & BMACSEC_PM_100MB_HD) { 1537 *mode |= SOC_PM_100MB_HD; 1538 } 1539 if(bmacsec_mode & BMACSEC_PM_100MB_FD) { 1540 *mode |= SOC_PM_100MB_FD; 1541 } 1542 if(bmacsec_mode & BMACSEC_PM_1000MB_HD) { 1543 *mode |= SOC_PM_1000MB_HD; 1544 } 1545 if(bmacsec_mode & BMACSEC_PM_1000MB_FD) { 1546 *mode |= SOC_PM_1000MB_FD; 1547 } 1548 if((bmacsec_mode & BMACSEC_PM_PAUSE) == BMACSEC_PM_PAUSE) { 1549 *mode |= SOC_PM_PAUSE; 1550 } 1551 if(bmacsec_mode & BMACSEC_PM_PAUSE_TX) { 1552 *mode |= SOC_PM_PAUSE_TX; 1553 } 1554 if(bmacsec_mode & BMACSEC_PM_PAUSE_RX) { 1555 *mode |= SOC_PM_PAUSE_RX; 1556 } 1557 } 1558 LOG_INFO(BSL_LS_SOC_PHY, 1559 (BSL_META_U(unit, 1560 "phy_54580_adv_local_get: u=%d p=%d mode=0x%x, rv=%d\n"), 1561 unit, port, *mode, rv)); 1562 return (SOC_ERROR(rv)); 1563 1564 } 1565 1566 /* 1567 * Function: 1568 * phy_54580_adv_remote_get 1569 * Purpose: 1570 * Get partners current advertisement for auto-negotiation. 1571 * Parameters: 1572 * unit - StrataSwitch unit #. 1573 * port - StrataSwitch port #. 1574 * mode - (OUT) Port mode mask indicating supported options/speeds. 1575 * Returns: 1576 * SOC_E_XXX 1577 * Notes: 1578 * The remote advertisement is retrieved for the ACTIVE medium. 1579 * No synchronization performed at this level. If Autonegotiation is 1580 * disabled or in progress, this routine will return an error. 1581 */ 1582 1583 STATIC int 1584 phy_54580_adv_remote_get(int unit, soc_port_t port, soc_port_mode_t *mode) 1585 { 1586 int rv; 1587 phy_ctrl_t *pc; 1588 bmacsec_phy54580_port_mode_t port_mode = BMACSEC_PHY_COPPER; 1589 bmacsec_dev_addr_t phy_dev_addr; 1590 bmacsec_port_mode_t bmacsec_mode = 0; 1591 1592 1593 pc = EXT_PHY_SW_STATE(unit, port); 1594 rv = SOC_E_NONE; 1595 1596 if(PHY_COPPER_MODE(unit, port)) { 1597 port_mode = BMACSEC_PHY_COPPER; 1598 } else { 1599 if(PHY_FIBER_MODE(unit, port)) { 1600 port_mode = BMACSEC_PHY_FIBER; 1601 } 1602 } 1603 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 1604 rv = bmacsec_phy54580_adv_remote_get(phy_dev_addr, port_mode, 1605 &bmacsec_mode); 1606 *mode = 0; 1607 if (rv == BMACSEC_E_NONE) { 1608 if(bmacsec_mode & BMACSEC_PM_10MB_HD) { 1609 *mode |= SOC_PM_10MB_HD; 1610 } 1611 if(bmacsec_mode & BMACSEC_PM_10MB_FD) { 1612 *mode |= SOC_PM_10MB_FD; 1613 } 1614 if(bmacsec_mode & BMACSEC_PM_100MB_HD) { 1615 *mode |= SOC_PM_100MB_HD; 1616 } 1617 if(bmacsec_mode & BMACSEC_PM_100MB_FD) { 1618 *mode |= SOC_PM_100MB_FD; 1619 } 1620 if(bmacsec_mode & BMACSEC_PM_1000MB_HD) { 1621 *mode |= SOC_PM_1000MB_HD; 1622 } 1623 if(bmacsec_mode & BMACSEC_PM_1000MB_FD) { 1624 *mode |= SOC_PM_1000MB_FD; 1625 } 1626 if((bmacsec_mode & BMACSEC_PM_PAUSE) == BMACSEC_PM_PAUSE) { 1627 *mode |= SOC_PM_PAUSE; 1628 } 1629 if(bmacsec_mode & BMACSEC_PM_PAUSE_TX) { 1630 *mode |= SOC_PM_PAUSE_TX; 1631 } 1632 if(bmacsec_mode & BMACSEC_PM_PAUSE_RX) { 1633 *mode |= SOC_PM_PAUSE_RX; 1634 } 1635 } 1636 1637 LOG_INFO(BSL_LS_SOC_PHY, 1638 (BSL_META_U(unit, 1639 "phy_54580_adv_remote_get: u=%d p=%d mode=0x%x, rv=%d\n"), 1640 unit, port, *mode, rv)); 1641 return (SOC_ERROR(rv)); 1642 } 1643 1644 /* 1645 * Function: 1646 * phy_54580_lb_set 1647 * Purpose: 1648 * Set the local PHY loopback mode. 1649 * Parameters: 1650 * unit - StrataSwitch unit #. 1651 * port - StrataSwitch port #. 1652 * loopback - Boolean: true = enable loopback, false = disable. 1653 * Returns: 1654 * SOC_E_XXX 1655 * Notes: 1656 * The loopback mode is set only for the ACTIVE medium. 1657 * No synchronization performed at this level. 1658 */ 1659 1660 STATIC int 1661 phy_54580_lb_set(int unit, soc_port_t port, int enable) 1662 { 1663 int rv; 1664 phy_ctrl_t *pc; 1665 bmacsec_phy54580_port_mode_t port_mode = BMACSEC_PHY_COPPER; 1666 bmacsec_dev_addr_t phy_dev_addr; 1667 1668 pc = EXT_PHY_SW_STATE(unit, port); 1669 rv = SOC_E_NONE; 1670 1671 #if AUTO_MDIX_WHEN_AN_DIS 1672 { 1673 /* Disable Auto-MDIX When autoneg disabled */ 1674 /* Enable Auto-MDIX When autoneg disabled */ 1675 data = (enable) ? 0x0000 : 0x0200; 1676 rv = BMACSEC_MODIFY_PHY_54580_MII_MISC_CTRLr(pc->phy_id, data, 0x0200); 1677 if(!BMACSEC_E_SUCCESS(rv)) { 1678 return SOC_ERROR(rv); 1679 } 1680 1681 } 1682 #endif 1683 1684 pc = EXT_PHY_SW_STATE(unit, port); 1685 rv = SOC_E_NONE; 1686 1687 if(PHY_COPPER_MODE(unit, port)) { 1688 port_mode = BMACSEC_PHY_COPPER; 1689 } else { 1690 if(PHY_FIBER_MODE(unit, port)) { 1691 port_mode = BMACSEC_PHY_FIBER; 1692 } 1693 } 1694 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 1695 rv = bmacsec_phy54580_loopback_set(phy_dev_addr, port_mode, enable); 1696 1697 LOG_INFO(BSL_LS_SOC_PHY, 1698 (BSL_META_U(unit, 1699 "phy_54580_lb_set: u=%d p=%d en=%d rv=%d\n"), 1700 unit, port, enable, rv)); 1701 1702 return SOC_ERROR(rv); 1703 } 1704 1705 /* 1706 * Function: 1707 * phy_54580_lb_get 1708 * Purpose: 1709 * Get the local PHY loopback mode. 1710 * Parameters: 1711 * unit - StrataSwitch unit #. 1712 * port - StrataSwitch port #. 1713 * loopback - (OUT) Boolean: true = enable loopback, false = disable. 1714 * Returns: 1715 * SOC_E_XXX 1716 * Notes: 1717 * The loopback mode is retrieved for the ACTIVE medium. 1718 */ 1719 1720 STATIC int 1721 phy_54580_lb_get(int unit, soc_port_t port, int *enable) 1722 { 1723 int rv; 1724 phy_ctrl_t *pc; 1725 bmacsec_phy54580_port_mode_t port_mode = BMACSEC_PHY_COPPER; 1726 bmacsec_dev_addr_t phy_dev_addr; 1727 1728 pc = EXT_PHY_SW_STATE(unit, port); 1729 rv = SOC_E_NONE; 1730 1731 if(PHY_COPPER_MODE(unit, port)) { 1732 port_mode = BMACSEC_PHY_COPPER; 1733 } else { 1734 if(PHY_FIBER_MODE(unit, port)) { 1735 port_mode = BMACSEC_PHY_FIBER; 1736 } 1737 } 1738 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 1739 rv = bmacsec_phy54580_loopback_get(phy_dev_addr, port_mode, enable); 1740 1741 return SOC_ERROR(rv); 1742 } 1743 1744 /* 1745 * Function: 1746 * phy_54580_interface_set 1747 * Purpose: 1748 * Set the current operating mode of the PHY. 1749 * Parameters: 1750 * unit - StrataSwitch unit #. 1751 * port - StrataSwitch port #. 1752 * pif - one of SOC_PORT_IF_* 1753 * Returns: 1754 * SOC_E_NONE - success 1755 * SOC_E_UNAVAIL - unsupported interface 1756 */ 1757 1758 STATIC int 1759 phy_54580_interface_set(int unit, soc_port_t port, soc_port_if_t pif) 1760 { 1761 COMPILER_REFERENCE(unit); 1762 COMPILER_REFERENCE(port); 1763 1764 switch (pif) { 1765 case SOC_PORT_IF_SGMII: 1766 case SOC_PORT_IF_GMII: 1767 return SOC_E_NONE; 1768 default: 1769 return SOC_E_UNAVAIL; 1770 } 1771 } 1772 1773 /* 1774 * Function: 1775 * phy_54580_interface_get 1776 * Purpose: 1777 * Get the current operating mode of the PHY. 1778 * Parameters: 1779 * unit - StrataSwitch unit #. 1780 * port - StrataSwitch port #. 1781 * pif - (OUT) one of SOC_PORT_IF_* 1782 * Returns: 1783 * SOC_E_NONE 1784 */ 1785 1786 STATIC int 1787 phy_54580_interface_get(int unit, soc_port_t port, soc_port_if_t *pif) 1788 { 1789 COMPILER_REFERENCE(unit); 1790 COMPILER_REFERENCE(port); 1791 1792 *pif = SOC_PORT_IF_SGMII; 1793 1794 return SOC_E_NONE; 1795 } 1796 1797 /* 1798 * Function: 1799 * phy_54580_ability_get 1800 * Purpose: 1801 * Get the abilities of the local gigabit PHY. 1802 * Parameters: 1803 * unit - StrataSwitch unit #. 1804 * port - StrataSwitch port #. 1805 * mode - (OUT) Port mode mask indicating supported options/speeds. 1806 * Returns: 1807 * SOC_E_NONE 1808 * Notes: 1809 * The ability is retrieved only for the ACTIVE medium. 1810 */ 1811 1812 STATIC int 1813 phy_54580_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode) 1814 { 1815 int rv; 1816 phy_ctrl_t *pc; 1817 bmacsec_phy54580_port_mode_t port_mode = BMACSEC_PHY_COPPER; 1818 bmacsec_port_mode_t ability = 0; 1819 bmacsec_dev_addr_t phy_dev_addr; 1820 1821 rv = SOC_E_NONE; 1822 1823 if(PHY_COPPER_MODE(unit, port)) { 1824 port_mode = BMACSEC_PHY_COPPER; 1825 } else { 1826 if(PHY_FIBER_MODE(unit, port)) { 1827 port_mode = BMACSEC_PHY_FIBER; 1828 } 1829 } 1830 1831 pc = EXT_PHY_SW_STATE(unit, port); 1832 1833 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 1834 rv = bmacsec_phy54580_ability_get(phy_dev_addr, port_mode, &ability); 1835 if (rv != BMACSEC_E_NONE) { 1836 return SOC_E_FAIL; 1837 } 1838 1839 *mode = 0; 1840 if(ability & BMACSEC_PM_10MB_HD) { 1841 *mode |= SOC_PM_10MB_HD; 1842 } 1843 if(ability & BMACSEC_PM_10MB_FD) { 1844 *mode |= SOC_PM_10MB_FD; 1845 } 1846 if(ability & BMACSEC_PM_100MB_HD) { 1847 *mode |= SOC_PM_100MB_HD; 1848 } 1849 if(ability & BMACSEC_PM_100MB_FD) { 1850 *mode |= SOC_PM_100MB_FD ; 1851 } 1852 if(ability & BMACSEC_PM_1000MB_HD) { 1853 *mode |= SOC_PM_1000MB_HD; 1854 } 1855 if(ability & BMACSEC_PM_1000MB_FD) { 1856 *mode |= SOC_PM_1000MB_FD; 1857 } 1858 if(ability & BMACSEC_PM_PAUSE_TX) { 1859 *mode |= SOC_PM_PAUSE_TX; 1860 } 1861 if(ability & BMACSEC_PM_PAUSE_RX) { 1862 *mode |= SOC_PM_PAUSE_RX; 1863 } 1864 if(ability & BMACSEC_PM_PAUSE_ASYMM) { 1865 *mode |= SOC_PM_PAUSE_ASYMM; 1866 } 1867 if(ability & BMACSEC_PM_TBI) { 1868 *mode |= SOC_PM_TBI; 1869 } 1870 if(ability & BMACSEC_PM_MII) { 1871 *mode |= SOC_PM_MII; 1872 } 1873 if(ability & BMACSEC_PM_GMII) { 1874 *mode |= SOC_PM_GMII; 1875 } 1876 if(ability & BMACSEC_PM_SGMII) { 1877 *mode |= SOC_PM_SGMII; 1878 } 1879 if(ability & BMACSEC_PM_LB_NONE) { 1880 *mode |= SOC_PM_LB_NONE; 1881 } 1882 if(ability & BMACSEC_PM_LB_PHY) { 1883 *mode |= SOC_PM_LB_PHY; 1884 } 1885 if(ability & BMACSEC_PM_AN) { 1886 *mode |= SOC_PM_AN; 1887 } 1888 1889 if (pc->automedium) { 1890 *mode |= SOC_PM_COMBO; 1891 } 1892 1893 return SOC_E_NONE; 1894 } 1895 1896 /* 1897 * Function: 1898 * phy_54580_mdix_set 1899 * Description: 1900 * Set the Auto-MDIX mode of a port/PHY 1901 * Parameters: 1902 * unit - Device number 1903 * port - Port number 1904 * mode - One of: 1905 * SOC_PORT_MDIX_AUTO 1906 * Enable auto-MDIX when autonegotiation is enabled 1907 * SOC_PORT_MDIX_FORCE_AUTO 1908 * Enable auto-MDIX always 1909 * SOC_PORT_MDIX_NORMAL 1910 * Disable auto-MDIX 1911 * SOC_PORT_MDIX_XOVER 1912 * Disable auto-MDIX, and swap cable pairs 1913 * Return Value: 1914 * SOC_E_XXX 1915 */ 1916 STATIC int 1917 phy_54580_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode) 1918 { 1919 1920 int rv; 1921 phy_ctrl_t *pc; 1922 bmacsec_phy54580_port_mode_t port_mode = BMACSEC_PHY_COPPER; 1923 bmacsec_dev_addr_t phy_dev_addr; 1924 bmacsec_port_mdix_t bmacsec_mode; 1925 1926 pc = EXT_PHY_SW_STATE(unit, port); 1927 1928 if(PHY_COPPER_MODE(unit, port)) { 1929 port_mode = BMACSEC_PHY_COPPER; 1930 } else { 1931 if(PHY_FIBER_MODE(unit, port)) { 1932 port_mode = BMACSEC_PHY_FIBER; 1933 if (mode != SOC_PORT_MDIX_NORMAL) { 1934 return SOC_E_UNAVAIL; 1935 } 1936 } 1937 } 1938 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 1939 switch(mode) { 1940 case SOC_PORT_MDIX_AUTO: 1941 bmacsec_mode = BMACSEC_PORT_MDIX_AUTO; 1942 break; 1943 case SOC_PORT_MDIX_FORCE_AUTO: 1944 bmacsec_mode = BMACSEC_PORT_MDIX_FORCE_AUTO; 1945 break; 1946 case SOC_PORT_MDIX_NORMAL: 1947 bmacsec_mode = BMACSEC_PORT_MDIX_NORMAL; 1948 break; 1949 case SOC_PORT_MDIX_XOVER: 1950 bmacsec_mode = BMACSEC_PORT_MDIX_XOVER; 1951 break; 1952 default : 1953 return SOC_E_CONFIG; 1954 } 1955 1956 rv = bmacsec_phy54580_mdix_set(phy_dev_addr, port_mode, bmacsec_mode); 1957 1958 if(BMACSEC_E_SUCCESS(rv)) { 1959 if(PHY_COPPER_MODE(unit, port)) { 1960 pc->copper.mdix = mode; 1961 } 1962 } 1963 return SOC_ERROR(rv); 1964 } 1965 1966 /* 1967 * Function: 1968 * phy_54580_mdix_get 1969 * Description: 1970 * Get the Auto-MDIX mode of a port/PHY 1971 * Parameters: 1972 * unit - Device number 1973 * port - Port number 1974 * mode - (Out) One of: 1975 * SOC_PORT_MDIX_AUTO 1976 * Enable auto-MDIX when autonegotiation is enabled 1977 * SOC_PORT_MDIX_FORCE_AUTO 1978 * Enable auto-MDIX always 1979 * SOC_PORT_MDIX_NORMAL 1980 * Disable auto-MDIX 1981 * SOC_PORT_MDIX_XOVER 1982 * Disable auto-MDIX, and swap cable pairs 1983 * Return Value: 1984 * SOC_E_XXX 1985 */ 1986 STATIC int 1987 phy_54580_mdix_get(int unit, soc_port_t port, soc_port_mdix_t *mode) 1988 { 1989 phy_ctrl_t *pc; 1990 int speed; 1991 1992 if (mode == NULL) { 1993 return SOC_E_PARAM; 1994 } 1995 1996 pc = EXT_PHY_SW_STATE(unit, port); 1997 1998 if (PHY_COPPER_MODE(unit, port)) { 1999 SOC_IF_ERROR_RETURN(phy_54580_speed_get(unit, port, &speed)); 2000 if (speed == 1000) { 2001 *mode = SOC_PORT_MDIX_AUTO; 2002 } else { 2003 *mode = pc->copper.mdix; 2004 } 2005 } else { 2006 *mode = SOC_PORT_MDIX_NORMAL; 2007 } 2008 2009 return SOC_E_NONE; 2010 } 2011 2012 /* 2013 * Function: 2014 * phy_54580_mdix_status_get 2015 * Description: 2016 * Get the current MDIX status on a port/PHY 2017 * Parameters: 2018 * unit - Device number 2019 * port - Port number 2020 * status - (OUT) One of: 2021 * SOC_PORT_MDIX_STATUS_NORMAL 2022 * Straight connection 2023 * SOC_PORT_MDIX_STATUS_XOVER 2024 * Crossover has been performed 2025 * Return Value: 2026 * SOC_E_XXX 2027 */ 2028 STATIC int 2029 phy_54580_mdix_status_get(int unit, soc_port_t port, 2030 soc_port_mdix_status_t *status) 2031 { 2032 int rv; 2033 phy_ctrl_t *pc; 2034 2035 bmacsec_phy54580_port_mode_t port_mode = BMACSEC_PHY_COPPER; 2036 bmacsec_dev_addr_t phy_dev_addr; 2037 bmacsec_port_mdix_status_t mdix_status; 2038 2039 if (status == NULL) { 2040 return SOC_E_PARAM; 2041 } 2042 2043 pc = EXT_PHY_SW_STATE(unit, port); 2044 2045 if(PHY_COPPER_MODE(unit, port)) { 2046 port_mode = BMACSEC_PHY_COPPER; 2047 } else { 2048 if(PHY_FIBER_MODE(unit, port)) { 2049 port_mode = BMACSEC_PHY_FIBER; 2050 } 2051 } 2052 2053 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 2054 rv = bmacsec_phy54580_mdix_status_get(phy_dev_addr, port_mode, 2055 &mdix_status); 2056 if(BMACSEC_E_SUCCESS(rv)) { 2057 if(mdix_status == BMACSEC_PORT_MDIX_STATUS_NORMAL) { 2058 *status = SOC_PORT_MDIX_STATUS_NORMAL; 2059 } 2060 if(mdix_status == BMACSEC_PORT_MDIX_STATUS_XOVER) { 2061 *status = SOC_PORT_MDIX_STATUS_XOVER; 2062 } 2063 return SOC_E_NONE; 2064 } 2065 2066 return SOC_ERROR(rv); 2067 } 2068 2069 /* 2070 * Function: 2071 * phy_54580_cable_diag 2072 * Purpose: 2073 * Run 546x cable diagnostics 2074 * Parameters: 2075 * unit - device number 2076 * port - port number 2077 * status - (OUT) cable diagnotic status structure 2078 * Returns: 2079 * SOC_E_XXX 2080 */ 2081 STATIC int 2082 phy_54580_cable_diag(int unit, soc_port_t port, 2083 soc_port_cable_diag_t *status) 2084 { 2085 int rv, rv2, i; 2086 bmacsec_dev_addr_t phy_dev_addr; 2087 phy_ctrl_t *pc; 2088 int fiber_capable = 0; 2089 2090 extern int phy_5464_cable_diag_sw(int, soc_port_t , 2091 soc_port_cable_diag_t *); 2092 pc = EXT_PHY_SW_STATE(unit, port); 2093 2094 if (status == NULL) { 2095 return SOC_E_PARAM; 2096 } 2097 2098 status->state = SOC_PORT_CABLE_STATE_OK; 2099 status->npairs = 4; 2100 status->fuzz_len = 0; 2101 for (i = 0; i < 4; i++) { 2102 status->pair_state[i] = SOC_PORT_CABLE_STATE_OK; 2103 } 2104 2105 MIIM_LOCK(unit); /* this locks out linkscan, essentially */ 2106 rv = phy_5464_cable_diag_sw(unit,port, status); 2107 MIIM_UNLOCK(unit); 2108 rv2 = 0; 2109 if (rv <= 0) { /* don't reset if > 0 -- link was up */ 2110 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 2111 rv2 = bmacsec_phy54580_init(phy_dev_addr, 1, 2112 pc->automedium, 2113 pc->fiber.preferred, 2114 pc->fiber_detect, 2115 pc->macsec_enable, 2116 &fiber_capable); 2117 } 2118 if (rv >= 0 && rv2 < 0) { 2119 return rv2; 2120 } 2121 return rv; 2122 } 2123 2124 /* 2125 * Function: 2126 * phy_54580_control_set 2127 * Purpose: 2128 * Configure PHY device specific control fucntion. 2129 * Parameters: 2130 * unit - StrataSwitch unit #. 2131 * port - StrataSwitch port #. 2132 * type - Control to update 2133 * value - New setting for the control 2134 * Returns: 2135 * SOC_E_NONE 2136 */ 2137 STATIC int 2138 phy_54580_control_set(int unit, soc_port_t port, 2139 soc_phy_control_t type, uint32 value) 2140 { 2141 int rv, pause_fwd = 0; 2142 phy_ctrl_t *pc; 2143 bmacsec_phy54580_port_mode_t port_mode = BMACSEC_PHY_COPPER; 2144 bmacsec_dev_addr_t phy_dev_addr; 2145 2146 pc = EXT_PHY_SW_STATE(unit, port); 2147 2148 if (pc->macsec_enable != 1) { 2149 return SOC_E_UNAVAIL; 2150 } 2151 2152 if(PHY_COPPER_MODE(unit, port)) { 2153 port_mode = BMACSEC_PHY_COPPER; 2154 } else { 2155 if(PHY_FIBER_MODE(unit, port)) { 2156 port_mode = BMACSEC_PHY_FIBER; 2157 } else { 2158 return SOC_E_NONE; 2159 } 2160 } 2161 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 2162 2163 rv = BMACSEC_E_NONE; 2164 switch(type) { 2165 case SOC_PHY_CONTROL_MACSEC_SWITCH_FIXED: 2166 pc->macsec_switch_fixed = value; 2167 if(value) { 2168 rv = bmacsec_phy54580_switch_side_set_params(phy_dev_addr, 2169 port_mode, 2170 BMACSEC_SWITCH_FIXED, 2171 pc->macsec_switch_fixed_speed, 2172 pc->macsec_switch_fixed_duplex, 2173 pc->macsec_switch_fixed_pause); 2174 } else { /* Switch side follows line side */ 2175 rv = bmacsec_phy54580_switch_side_set_params(phy_dev_addr, 2176 port_mode, 2177 BMACSEC_SWITCH_FOLLOWS_LINE, 2178 -1, -1, -1); 2179 } 2180 2181 break; 2182 case SOC_PHY_CONTROL_MACSEC_SWITCH_FIXED_SPEED: 2183 /* Switch fixed speed is allowed only to be 1000Mbps */ 2184 if (value != 1000) { 2185 return SOC_E_CONFIG; 2186 } 2187 if(pc->macsec_switch_fixed_speed != value) { 2188 int line_speed; 2189 2190 pc->macsec_switch_fixed_speed = value; 2191 2192 /* 2193 * If PHY is 54584 then switch side speed need to line side 2194 * speed. 2195 */ 2196 if ((pc->phy_oui == BMACSEC_PHY_BRCM_OUI2) && 2197 (pc->phy_model == BMACSEC_PHY_BCM54584_MODEL)) { 2198 2199 SOC_IF_ERROR_RETURN 2200 (phy_54580_speed_get(unit, port, &line_speed)); 2201 pc->macsec_switch_fixed_speed = line_speed; 2202 2203 } 2204 2205 2206 } 2207 break; 2208 case SOC_PHY_CONTROL_MACSEC_SWITCH_FIXED_DUPLEX: 2209 /* Switch fixed Duplex is allowed only to be Full Duplex mode */ 2210 if (value != 1) { 2211 return SOC_E_CONFIG; 2212 } 2213 if(pc->macsec_switch_fixed_duplex != value) { 2214 pc->macsec_switch_fixed_duplex = value; 2215 } 2216 break; 2217 case SOC_PHY_CONTROL_MACSEC_SWITCH_FIXED_PAUSE: 2218 if(pc->macsec_switch_fixed_pause != value) { 2219 pc->macsec_switch_fixed_pause = value; 2220 } 2221 break; 2222 case SOC_PHY_CONTROL_MACSEC_PAUSE_RX_FORWARD: 2223 pc->macsec_pause_rx_fwd = value; 2224 pause_fwd = (value == 1) ? 1 : 0; 2225 2226 rv = bmacsec_phy54580_line_side_pause_forward(phy_dev_addr, 2227 pause_fwd); 2228 if (rv == BMACSEC_E_NONE) { 2229 rv = bmacsec_phy54580_switch_side_pause_forward( 2230 phy_dev_addr, pause_fwd); 2231 } 2232 break; 2233 case SOC_PHY_CONTROL_MACSEC_PAUSE_TX_FORWARD: 2234 pc->macsec_pause_tx_fwd = value; 2235 pause_fwd = (value == 1) ? 1 : 0; 2236 2237 rv = bmacsec_phy54580_line_side_pause_forward(phy_dev_addr, 2238 pause_fwd); 2239 if (rv == BMACSEC_E_NONE) { 2240 rv = bmacsec_phy54580_switch_side_pause_forward(phy_dev_addr, 2241 pause_fwd); 2242 } 2243 break; 2244 case SOC_PHY_CONTROL_MACSEC_LINE_IPG: 2245 pc->macsec_line_ipg = value; 2246 rv = bmacsec_phy54580_line_side_ipg_set(phy_dev_addr, value); 2247 break; 2248 case SOC_PHY_CONTROL_MACSEC_SWITCH_IPG: 2249 pc->macsec_switch_ipg = value; 2250 rv = bmacsec_phy54580_switch_side_ipg_set(phy_dev_addr, value); 2251 break; 2252 default: 2253 return SOC_E_UNAVAIL; 2254 } 2255 2256 if (rv != BMACSEC_E_NONE) { 2257 return SOC_ERROR(rv); 2258 } 2259 return SOC_E_NONE; 2260 } 2261 2262 /* 2263 * Function: 2264 * phy_54580_control_get 2265 * Purpose: 2266 * Get current control settign of the PHY. 2267 * Parameters: 2268 * unit - StrataSwitch unit #. 2269 * port - StrataSwitch port #. 2270 * type - Control to update 2271 * value - (OUT)Current setting for the control 2272 * Returns: 2273 * SOC_E_NONE 2274 */ 2275 STATIC int 2276 phy_54580_control_get(int unit, soc_port_t port, 2277 soc_phy_control_t type, uint32 *value) 2278 { 2279 int rv; 2280 phy_ctrl_t *pc; 2281 2282 pc = EXT_PHY_SW_STATE(unit, port); 2283 2284 if (pc->macsec_enable != 1) { 2285 return SOC_E_UNAVAIL; 2286 } 2287 2288 if (NULL == value) { 2289 return SOC_E_PARAM; 2290 } 2291 2292 if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) { 2293 return SOC_E_PARAM; 2294 } 2295 2296 rv = SOC_E_NONE; 2297 switch(type) { 2298 case SOC_PHY_CONTROL_MACSEC_SWITCH_FIXED: 2299 *value = pc->macsec_switch_fixed; 2300 break; 2301 case SOC_PHY_CONTROL_MACSEC_SWITCH_FIXED_SPEED: 2302 *value = pc->macsec_switch_fixed_speed; 2303 break; 2304 case SOC_PHY_CONTROL_MACSEC_SWITCH_FIXED_DUPLEX: 2305 *value = pc->macsec_switch_fixed_duplex; 2306 break; 2307 case SOC_PHY_CONTROL_MACSEC_SWITCH_FIXED_PAUSE: 2308 *value = pc->macsec_switch_fixed_pause; 2309 break; 2310 case SOC_PHY_CONTROL_MACSEC_PAUSE_RX_FORWARD: 2311 *value = pc->macsec_pause_rx_fwd; 2312 break; 2313 case SOC_PHY_CONTROL_MACSEC_PAUSE_TX_FORWARD: 2314 *value = pc->macsec_pause_tx_fwd; 2315 break; 2316 case SOC_PHY_CONTROL_MACSEC_LINE_IPG: 2317 *value = pc->macsec_line_ipg; 2318 break; 2319 case SOC_PHY_CONTROL_MACSEC_SWITCH_IPG: 2320 *value = pc->macsec_switch_ipg; 2321 break; 2322 default: 2323 rv = SOC_E_UNAVAIL; 2324 break; 2325 } 2326 return rv; 2327 } 2328 2329 /* 2330 * Function: 2331 * phy_54580_linkup 2332 * Purpose: 2333 * Link up handler 2334 * Parameters: 2335 * unit - StrataSwitch unit #. 2336 * port - StrataSwitch port #. 2337 * Returns: 2338 * SOC_E_NONE 2339 */ 2340 STATIC int 2341 phy_54580_linkup(int unit, soc_port_t port) 2342 { 2343 int rv; 2344 int line_speed; 2345 phy_ctrl_t *pc; 2346 bmacsec_phy54580_port_mode_t port_mode = BMACSEC_PHY_COPPER; 2347 bmacsec_dev_addr_t phy_dev_addr; 2348 2349 2350 pc = EXT_PHY_SW_STATE(unit, port); 2351 2352 if (pc->macsec_enable != 1) { 2353 return SOC_E_NONE; 2354 } 2355 2356 /* 2357 * For 54584 PHYs when in switch fixed mode, the line speed 2358 * has to follow the switch side otherwise the switch fixed will 2359 * not work 2360 */ 2361 if ((pc->phy_oui == BMACSEC_PHY_BRCM_OUI2) && 2362 (pc->phy_model == BMACSEC_PHY_BCM54584_MODEL)) { 2363 2364 SOC_IF_ERROR_RETURN 2365 (phy_54580_speed_get(unit, port, &line_speed)); 2366 pc->macsec_switch_fixed_speed = line_speed; 2367 2368 if (pc->macsec_switch_fixed == 1) { 2369 2370 if(PHY_COPPER_MODE(unit, port)) { 2371 port_mode = BMACSEC_PHY_COPPER; 2372 } else { 2373 port_mode = BMACSEC_PHY_FIBER; 2374 } 2375 2376 phy_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, pc->phy_id, 0); 2377 rv = bmacsec_phy54580_switch_side_set_params(phy_dev_addr, 2378 port_mode, 2379 BMACSEC_SWITCH_FIXED, 2380 pc->macsec_switch_fixed_speed, 2381 pc->macsec_switch_fixed_duplex, 2382 pc->macsec_switch_fixed_pause); 2383 if (BMACSEC_E_FAILURE(rv)) { 2384 return SOC_E_FAIL; 2385 } 2386 } 2387 2388 } 2389 return SOC_E_NONE; 2390 } 2391 2392 /* 2393 * 54580 Top level register Read 2394 */ 2395 STATIC int 2396 macsecphy_54580_toplvl_reg_read(phy_ctrl_t *pc, uint8 phy_base_addr, 2397 uint8 reg_offset, uint16 *data) 2398 2399 { 2400 int unit; 2401 uint8 port3_phy_id, port5_phy_id; 2402 uint16 reg_data, status; 2403 2404 if (!pc) { 2405 return SOC_E_FAIL; 2406 } 2407 unit = pc->unit; 2408 port3_phy_id = phy_base_addr + 2; 2409 port5_phy_id = phy_base_addr + 4; 2410 /* port6_phy_id = phy_base_addr + 6; Used for writes only */ 2411 2412 /* Write Reg address to Port 5's register 0x1C, shadow 0x0B */ 2413 /* Status READ from Port 3's register 0x15 */ 2414 2415 2416 /* Write Reg offset to Port 5's register 0x1C, shadow 0x0B */ 2417 reg_data = (0xAC00 | reg_offset); 2418 SOC_IF_ERROR_RETURN 2419 (MACSEC_WRITE_PHY_REG(unit, pc, port5_phy_id, 0x1c, reg_data)); 2420 2421 /* Read data from Top level MII Status register(0x15h) */ 2422 SOC_IF_ERROR_RETURN 2423 (MACSEC_WRITE_PHY_REG(unit, pc, port3_phy_id, 0x17, 0x8F0B)); 2424 SOC_IF_ERROR_RETURN 2425 (MACSEC_READ_PHY_REG(unit, pc, port3_phy_id, 0x15, &status)); 2426 2427 *data = (status & 0xff); 2428 2429 return SOC_E_NONE; 2430 } 2431 2432 2433 /* 2434 * 54580 Top level register Write 2435 */ 2436 STATIC int 2437 macsecphy_54580_toplvl_reg_write(phy_ctrl_t *pc, uint8 phy_base_addr, 2438 uint8 reg_offset, uint16 data) 2439 2440 { 2441 int unit; 2442 uint8 port3_phy_id, port6_phy_id, port5_phy_id; 2443 uint16 status, reg_data; 2444 2445 if (!pc) { 2446 return SOC_E_FAIL; 2447 } 2448 unit = pc->unit; 2449 2450 port3_phy_id = phy_base_addr + 2; 2451 port5_phy_id = phy_base_addr + 4; 2452 port6_phy_id = phy_base_addr + 5; 2453 2454 /* Write Reg address to Port 5's register 0x1C, shadow 0x0B */ 2455 /* Write data to Port 6's register 0x1C, shadow 0x0c */ 2456 /* Status READ from Port 3's register 0x15 */ 2457 2458 /* Write Data to port6, register 0x1C, shadow 0x0c */ 2459 reg_data = (0xB000 | (data & 0xff)); 2460 SOC_IF_ERROR_RETURN 2461 (MACSEC_WRITE_PHY_REG(unit, pc, port6_phy_id, 0x1c, reg_data)); 2462 2463 /* Write Reg address to Port 5's register 0x1C, shadow 0x0B */ 2464 /* Enable Write ( Port 5's register 0x1C, shadow 0x0B) Bit 7 = 1 */ 2465 reg_data = (0xAC80 | reg_offset); 2466 SOC_IF_ERROR_RETURN 2467 (MACSEC_WRITE_PHY_REG(unit, pc, port5_phy_id, 0x1c, reg_data)); 2468 2469 /* Disable Write ( Port 5's register 0x1C, shadow 0x0B) Bit 7 = 0 */ 2470 reg_data = (0xAC00 | reg_offset); 2471 SOC_IF_ERROR_RETURN 2472 (MACSEC_WRITE_PHY_REG(unit, pc, port5_phy_id, 0x1c, reg_data)); 2473 2474 status = 0; 2475 #ifdef BROADCOM_DEBUG 2476 /* Read data from Top level MII Status register(0x15h) */ 2477 SOC_IF_ERROR_RETURN 2478 (MACSEC_WRITE_PHY_REG(unit, pc, port3_phy_id, 0x17, 0x8F0B)); 2479 SOC_IF_ERROR_RETURN 2480 (MACSEC_READ_PHY_REG(unit, pc, port3_phy_id, 0x15, &status)); 2481 2482 #endif 2483 2484 return SOC_E_NONE; 2485 } 2486 2487 /* 2488 * Function: 2489 * _macsec_54580_rev0_init 2490 * Purpose: 2491 * Initialize MACSEC Top Level configuration 2492 * 2493 * Parameters: 2494 * pc - Phy control structure 2495 * dev_port - Port in the MACSEC device 2496 * dev_addr - MMI address 2497 * 2498 * Returns: 2499 * SOC_E_XXX 2500 */ 2501 2502 STATIC int 2503 _macsec_54580_rev0_init(phy_ctrl_t *pc, int dev_port, int dev_addr, 2504 int macsec_enable) 2505 { 2506 int unit, port, rev; 2507 uint8 phy_base_add, reg_offset; 2508 uint16 data; 2509 2510 #define MACSEC_MDIO_ENABLE (1U << 5) 2511 #define MACSEC_MDIO_ADDR_MASK 0x1F 2512 #define MACSEC_INTERRUPT_ENABLE (1U << 3) 2513 #define MACSEC_TOP_LVL_PORT_PASS_THRU_REG_OFFSET 0x2C 2514 #define MACSEC_TOP_LVL_PORT_GLOBAL_PASS_THRU_REG_OFFSET 0x2D 2515 #define MACSEC_TOP_LVL_MDIO_ENABLE_REG_OFFSET 0x2E 2516 #define MACSEC_TOP_LVL_QUAD_MEDIA_DETECT_REG_OFFSET 0x0A 2517 #define MACSEC_TOP_LVL_DUAL_SERDES_ENABLE 0x2F 2518 2519 if (!pc) { 2520 return SOC_E_FAIL; 2521 } 2522 unit = pc->unit; 2523 port = pc->port; 2524 rev = pc->phy_rev; 2525 2526 phy_base_add = pc->phy_id - dev_port; 2527 2528 if (macsec_enable) { 2529 2530 /* Enable MACSEC in Top level register 0x2D */ 2531 reg_offset = MACSEC_TOP_LVL_PORT_GLOBAL_PASS_THRU_REG_OFFSET; 2532 if (macsecphy_54580_toplvl_reg_read(pc, phy_base_add, 2533 reg_offset, &data) < 0) { 2534 return SOC_E_FAIL; 2535 } 2536 /* Write to register 0x2D to Enable MACSEC GLOBALLY */ 2537 if ((data & 0x1) == 0) { 2538 int ii; 2539 uint16 aer_addr; 2540 2541 data |= 1; /* Enable MACSEC GLOBALLY */ 2542 if (macsecphy_54580_toplvl_reg_write(pc, phy_base_add, 2543 reg_offset, data) < 0) { 2544 return SOC_E_FAIL; 2545 } 2546 if ((pc->phy_model == BMACSEC_PHY_BCM54584_MODEL) || 2547 (pc->phy_model == BMACSEC_PHY_BCM54585_MODEL)) { 2548 /* 2549 * Reset QSGMII 2550 */ 2551 for(ii = 0; ii < 8; ii++) { 2552 aer_addr = phy_base_add + 8 + ii; 2553 SOC_IF_ERROR_RETURN 2554 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add + 8, 2555 0x1f, 0xffd0)); 2556 SOC_IF_ERROR_RETURN 2557 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add + 8, 2558 0x1e, aer_addr)); 2559 SOC_IF_ERROR_RETURN 2560 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add+8, 2561 0x1f, 0x0000)); 2562 SOC_IF_ERROR_RETURN 2563 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add+8, 2564 0x00, 0x9140)); 2565 } 2566 } 2567 if ((pc->phy_model == BMACSEC_PHY_BCM54580_MODEL) || 2568 (pc->phy_model == BMACSEC_PHY_BCM54540_MODEL)) { 2569 /* 2570 * Reset SGMII 2571 */ 2572 for(ii = 0; ii < 8; ii++) { 2573 uint16 blk_sel; 2574 2575 /* Map 1000X page */ 2576 SOC_IF_ERROR_RETURN 2577 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add + ii, 2578 0x1c, 0x7c00)); 2579 SOC_IF_ERROR_RETURN 2580 (MACSEC_READ_PHY_REG(unit, pc, phy_base_add + ii, 2581 0x1c, &blk_sel)); 2582 SOC_IF_ERROR_RETURN 2583 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add + ii, 2584 0x1c, blk_sel | 0x8001)); 2585 2586 /* Write 1000X IEEE register */ 2587 SOC_IF_ERROR_RETURN 2588 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add + ii, 2589 0x0, 0x8000)); 2590 2591 /* Restore IEEE mapping */ 2592 SOC_IF_ERROR_RETURN 2593 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add + ii, 2594 0x1c, 2595 (blk_sel & 0xfffe) | 0x8000)); 2596 } 2597 } 2598 if (pc->phy_model == BMACSEC_PHY_BCM54540_MODEL) { 2599 reg_offset = MACSEC_TOP_LVL_QUAD_MEDIA_DETECT_REG_OFFSET; 2600 if (macsecphy_54580_toplvl_reg_read(pc, phy_base_add, 2601 reg_offset, &data) < 0) { 2602 return SOC_E_FAIL; 2603 } 2604 data &= ~(0x1f); 2605 data |= 0x10; /* Enable MACSEC GLOBALLY */ 2606 if (macsecphy_54580_toplvl_reg_write(pc, phy_base_add, 2607 reg_offset, data) < 0) { 2608 return SOC_E_FAIL; 2609 } 2610 } 2611 } 2612 2613 #if 0 2614 /* Enable MACSEC in Top level register 0x2c */ 2615 reg_offset = MACSEC_TOP_LVL_PORT_PASS_THRU_REG_OFFSET; 2616 if (macsecphy_54580_toplvl_reg_read(pc, phy_base_add, 2617 reg_offset, &data) < 0) { 2618 return SOC_E_FAIL; 2619 } 2620 /* Write to register 0x2C to Enable MACSEC */ 2621 data |= (1 << dev_port); /* Enable MACSEC on given port */ 2622 if (macsecphy_54580_toplvl_reg_write(pc, phy_base_add, 2623 reg_offset, data) < 0) { 2624 return SOC_E_FAIL; 2625 } 2626 #endif 2627 2628 /* Enable MACSEC MDIO and program MACSEC core MDIO address */ 2629 reg_offset = MACSEC_TOP_LVL_MDIO_ENABLE_REG_OFFSET; 2630 if (macsecphy_54580_toplvl_reg_read(pc, phy_base_add, 2631 reg_offset, &data) < 0) { 2632 return SOC_E_FAIL; 2633 } 2634 data &= ~(0x3f); 2635 data |= (MACSEC_MDIO_ENABLE | (dev_addr & MACSEC_MDIO_ADDR_MASK)); 2636 if (macsecphy_54580_toplvl_reg_write(pc, phy_base_add, 2637 reg_offset, data) < 0) { 2638 return SOC_E_FAIL; 2639 } 2640 2641 /* Enable MACSEC interrupts */ 2642 reg_offset = MACSEC_TOP_LVL_PORT_GLOBAL_PASS_THRU_REG_OFFSET; 2643 if (macsecphy_54580_toplvl_reg_read(pc, phy_base_add, 2644 reg_offset, &data) < 0) { 2645 return SOC_E_FAIL; 2646 } 2647 data &= ~(0x08); 2648 data |= MACSEC_INTERRUPT_ENABLE; 2649 if (macsecphy_54580_toplvl_reg_write(pc, phy_base_add, 2650 reg_offset, data) < 0) { 2651 return SOC_E_FAIL; 2652 } 2653 2654 } else { 2655 /* Disable MACSEC in Top level register 0x2D */ 2656 reg_offset = MACSEC_TOP_LVL_PORT_GLOBAL_PASS_THRU_REG_OFFSET; 2657 if (macsecphy_54580_toplvl_reg_read(pc, phy_base_add, 2658 reg_offset, &data) < 0) { 2659 return SOC_E_FAIL; 2660 } 2661 /* Write to register 0x2D to Disable MACSEC GLOBALLY */ 2662 data &= 0xfffe; /* Disable MACSEC GLOBALLY (bit 0 = 0) */ 2663 if (macsecphy_54580_toplvl_reg_write(pc, phy_base_add, 2664 reg_offset, data) < 0) { 2665 return SOC_E_FAIL; 2666 } 2667 } 2668 if (pc->phy_model == BMACSEC_PHY_BCM54584_MODEL) { 2669 /* Enable Serders in 0x2F reg */ 2670 reg_offset = MACSEC_TOP_LVL_DUAL_SERDES_ENABLE; 2671 if (macsecphy_54580_toplvl_reg_read(pc, phy_base_add, 2672 reg_offset, &data) < 0) { 2673 return SOC_E_FAIL; 2674 } 2675 data |= 0x00c0; /* set Bits 6 and 7 */ 2676 if (macsecphy_54580_toplvl_reg_write(pc, phy_base_add, 2677 reg_offset, data) < 0) { 2678 return SOC_E_FAIL; 2679 } 2680 2681 } 2682 2683 2684 return SOC_E_NONE; 2685 } 2686 2687 /* 2688 * 54580 rev 1 Top level register Read 2689 */ 2690 STATIC int 2691 macsecphy_54580_rev1_toplvl_reg_read(phy_ctrl_t *pc, uint8 mdio_addr, 2692 uint8 reg_offset, uint16 *data) 2693 2694 { 2695 int unit = pc->unit; 2696 2697 SOC_IF_ERROR_RETURN( 2698 MACSEC_WRITE_PHY_REG(unit, pc, mdio_addr, 2699 0x17, (0x0D00|(reg_offset & 0xff)))); 2700 SOC_IF_ERROR_RETURN( 2701 MACSEC_READ_PHY_REG(unit, pc, mdio_addr, 0x15, data)); 2702 2703 return SOC_E_NONE; 2704 } 2705 2706 2707 /* 2708 * 54580 rev 1Top level register Write 2709 */ 2710 STATIC int 2711 macsecphy_54580_rev1_toplvl_reg_write(phy_ctrl_t *pc, uint8 mdio_addr, 2712 uint8 reg_offset, uint16 val) 2713 2714 { 2715 int unit = pc->unit; 2716 2717 SOC_IF_ERROR_RETURN( 2718 MACSEC_WRITE_PHY_REG(unit, pc, mdio_addr, 2719 0x17, (0x0D00|(reg_offset & 0xff)))); 2720 SOC_IF_ERROR_RETURN( 2721 MACSEC_WRITE_PHY_REG(unit, pc, mdio_addr, 0x15, val)); 2722 2723 return SOC_E_NONE; 2724 } 2725 2726 /* 2727 * Function: 2728 * _macsec_54580_rev1_init 2729 * Purpose: 2730 * Initialize MACSEC Top Level configuration 2731 * 2732 * Parameters: 2733 * pc - Phy control structure 2734 * dev_port - Port in the MACSEC device 2735 * dev_addr - MMI address 2736 * 2737 * Returns: 2738 * SOC_E_XXX 2739 */ 2740 2741 STATIC int 2742 _macsec_54580_rev1_init(phy_ctrl_t *pc, int dev_port, int dev_addr, 2743 int macsec_enable) 2744 { 2745 int unit, port, rev; 2746 uint8 phy_base_add; 2747 uint16 data; 2748 2749 #define MACSEC_R1_MDIO_ENABLE (1U << 13) 2750 #define MACSEC_R1_INTERRUPT_ENABLE (1U << 0) 2751 #define MACSEC_R1_BYPASS_ENABLE (1U << 13) 2752 2753 unit = pc->unit; 2754 port = pc->port; 2755 rev = pc->phy_rev; 2756 2757 phy_base_add = pc->phy_id - dev_port; 2758 2759 #if 0 2760 SOC_IF_ERROR_RETURN( 2761 MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add, 0x17, 0xf7f)); 2762 SOC_IF_ERROR_RETURN( 2763 MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add, 0x15, 0x3)); 2764 #endif 2765 /* Enable MACSEC in Top level register 0xC8 */ 2766 if (macsecphy_54580_rev1_toplvl_reg_read(pc, phy_base_add, 2767 0xC8, &data) < 0) { 2768 return SOC_E_FAIL; 2769 } 2770 /* Write to register 0x2D to Enable MACSEC GLOBALLY */ 2771 if ((data & MACSEC_R1_MDIO_ENABLE) == 0) { 2772 /* Enable MACSEC GLOBALLY and program dev_addr */ 2773 data = MACSEC_R1_MDIO_ENABLE | MACSEC_R1_INTERRUPT_ENABLE | 2774 ((dev_addr & 0x1f) << 8); 2775 if (macsecphy_54580_rev1_toplvl_reg_write(pc, phy_base_add, 2776 0xC8, data) < 0) { 2777 return SOC_E_FAIL; 2778 } 2779 } 2780 2781 /* Enable/Disable MACSEC bypass */ 2782 if (macsecphy_54580_rev1_toplvl_reg_read(pc, pc->phy_id, 2783 0x07, &data) < 0) { 2784 return SOC_E_FAIL; 2785 } 2786 data &= ~MACSEC_R1_BYPASS_ENABLE; 2787 if (!macsec_enable) { 2788 data |= MACSEC_R1_BYPASS_ENABLE; 2789 } 2790 2791 if (macsecphy_54580_rev1_toplvl_reg_write(pc, pc->phy_id, 2792 0x07, data)< 0) { 2793 return SOC_E_FAIL; 2794 } 2795 2796 #if 0 2797 if ((pc->phy_model == BMACSEC_PHY_BCM54584_MODEL) || 2798 (pc->phy_model == BMACSEC_PHY_BCM54585_MODEL)) { 2799 /* 2800 * Reset QSGMII 2801 */ 2802 for(ii = 0; ii < 8; ii++) { 2803 aer_addr = phy_base_add + 8 + ii; 2804 SOC_IF_ERROR_RETURN 2805 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add + 8, 2806 0x1f, 0xffd0)); 2807 SOC_IF_ERROR_RETURN 2808 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add + 8, 2809 0x1e, aer_addr)); 2810 SOC_IF_ERROR_RETURN 2811 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add+8, 2812 0x1f, 0x0000)); 2813 SOC_IF_ERROR_RETURN 2814 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add+8, 2815 0x00, 0x9140)); 2816 } 2817 } 2818 if ((pc->phy_model == BMACSEC_PHY_BCM54580_MODEL) || 2819 (pc->phy_model == BMACSEC_PHY_BCM54540_MODEL)) { 2820 /* 2821 * Reset SGMII 2822 */ 2823 for(ii = 0; ii < 8; ii++) { 2824 uint16 blk_sel; 2825 2826 /* Map 1000X page */ 2827 SOC_IF_ERROR_RETURN 2828 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add + ii, 2829 0x1c, 0x7c00)); 2830 SOC_IF_ERROR_RETURN 2831 (MACSEC_READ_PHY_REG(unit, pc, phy_base_add + ii, 2832 0x1c, &blk_sel)); 2833 SOC_IF_ERROR_RETURN 2834 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add + ii, 2835 0x1c, blk_sel | 0x8001)); 2836 2837 /* Write 1000X IEEE register */ 2838 SOC_IF_ERROR_RETURN 2839 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add + ii, 2840 0x0, 0x8000)); 2841 2842 /* Restore IEEE mapping */ 2843 SOC_IF_ERROR_RETURN 2844 (MACSEC_WRITE_PHY_REG(unit, pc, phy_base_add + ii, 2845 0x1c, 2846 (blk_sel & 0xfffe) | 0x8000)); 2847 } 2848 } 2849 if (pc->phy_model == BMACSEC_PHY_BCM54540_MODEL) { 2850 reg_offset = MACSEC_TOP_LVL_QUAD_MEDIA_DETECT_REG_OFFSET; 2851 if (macsecphy_54580_toplvl_reg_read(pc, phy_base_add, 2852 reg_offset, &data) < 0) { 2853 return SOC_E_FAIL; 2854 } 2855 data &= ~(0x1f); 2856 data |= 0x10; /* Enable MACSEC GLOBALLY */ 2857 if (macsecphy_54580_toplvl_reg_write(pc, phy_base_add, 2858 reg_offset, data) < 0) { 2859 return SOC_E_FAIL; 2860 } 2861 } 2862 #endif 2863 2864 #if 0 2865 if (pc->phy_model == BMACSEC_PHY_BCM54584_MODEL) { 2866 /* Enable Serders in 0x2F reg */ 2867 reg_offset = MACSEC_TOP_LVL_DUAL_SERDES_ENABLE; 2868 if (macsecphy_54580_toplvl_reg_read(pc, phy_base_add, 2869 reg_offset, &data) < 0) { 2870 return SOC_E_FAIL; 2871 } 2872 data |= 0x00c0; /* set Bits 6 and 7 */ 2873 if (macsecphy_54580_toplvl_reg_write(pc, phy_base_add, 2874 reg_offset, data) < 0) { 2875 return SOC_E_FAIL; 2876 } 2877 2878 } 2879 #endif 2880 2881 2882 return SOC_E_NONE; 2883 } 2884 2885 2886 #ifdef BROADCOM_DEBUG 2887 2888 /* 2889 * Function: 2890 * phy_54580_shadow_dump 2891 * Purpose: 2892 * Debug routine to dump all shadow registers. 2893 * Parameters: 2894 * unit - StrataSwitch unit #. 2895 * port - StrataSwitch port #. 2896 */ 2897 2898 void 2899 phy_54580_shadow_dump(int unit, soc_port_t port) 2900 { 2901 phy_ctrl_t *pc; 2902 uint16 tmp; 2903 int i; 2904 2905 pc = EXT_PHY_SW_STATE(unit, port); 2906 2907 /* Register 0x18 Shadows */ 2908 for (i = 0; i <= 7; i++) { 2909 WRITE_PHY_REG(unit, pc, 0x18, (i << 12) | 0x7); 2910 READ_PHY_REG(unit, pc, 0x18, &tmp); 2911 if ((tmp & ~7) == 0x0000) { 2912 continue; 2913 } 2914 LOG_CLI((BSL_META_U(unit, 2915 "0x18[0x%x]=0x%04x\n"), i, tmp)); 2916 } 2917 2918 /* Register 0x1c Shadows */ 2919 for (i = 0; i <= 0x1f; i++) { 2920 WRITE_PHY_REG(unit, pc, 0x1c, i << 10); 2921 READ_PHY_REG(unit, pc, 0x1c, &tmp); 2922 if ((tmp & ~0x7c00) == 0x0000) { 2923 continue; 2924 } 2925 LOG_CLI((BSL_META_U(unit, 2926 "0x1c[0x%x]=0x%04x\n"), i, tmp)); 2927 } 2928 2929 /* Register 0x17/0x15 Shadows */ 2930 for (i = 0; i <= 0x13; i++) { 2931 WRITE_PHY_REG(unit, pc, 0x17, 0xf00 | i); 2932 READ_PHY_REG(unit, pc, 0x15, &tmp); 2933 if (tmp == 0x0000) { 2934 continue; 2935 } 2936 LOG_CLI((BSL_META_U(unit, 2937 "0x17[0x%x]=0x%04x\n"), i, tmp)); 2938 } 2939 } 2940 2941 #endif /* BROADCOM_DEBUG */ 2942 2943 /* 2944 * Variable: phy_54580drv_ge 2945 * Purpose: PHY driver for 54580 2946 */ 2947 phy_driver_t phy_54580drv_ge = { 2948 "54580 (MACSec PHY) Gigabit PHY Driver", 2949 phy_54580_init, 2950 phy_54580_reset, 2951 phy_54580_link_get, 2952 phy_54580_enable_set, 2953 phy_54580_enable_get, 2954 phy_54580_duplex_set, 2955 phy_54580_duplex_get, 2956 phy_54580_speed_set, 2957 phy_54580_speed_get, 2958 phy_54580_master_set, 2959 phy_54580_master_get, 2960 phy_54580_autoneg_set, 2961 phy_54580_autoneg_get, 2962 phy_54580_adv_local_set, 2963 phy_54580_adv_local_get, 2964 phy_54580_adv_remote_get, 2965 phy_54580_lb_set, 2966 phy_54580_lb_get, 2967 phy_54580_interface_set, 2968 phy_54580_interface_get, 2969 phy_54580_ability_get, 2970 phy_54580_linkup, /* Phy link up event */ 2971 NULL, /* Phy link down event */ 2972 phy_54580_mdix_set, 2973 phy_54580_mdix_get, 2974 phy_54580_mdix_status_get, 2975 phy_54580_medium_config_set, 2976 phy_54580_medium_config_get, 2977 phy_54580_medium_status, 2978 phy_54580_cable_diag, 2979 NULL, /* phy_link_change */ 2980 phy_54580_control_set, /* phy_control_set */ 2981 phy_54580_control_get, /* phy_control_get */ 2982 phy_ge_reg_read, 2983 phy_ge_reg_write, 2984 phy_ge_reg_modify, 2985 NULL /* Phy event notify */ 2986 }; 2987 2988 #else /* INCLUDE_PHY_54580 */ 2989 int _soc_phy_54580_not_empty; 2990 #endif /* INCLUDE_PHY_54580 */ 2991 #endif /* INCLUDE_MACSEC */