phy54880.c (101669B)
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: phy54880.c 8 * Purpose: PHY driver for BCM54880 9 */ 10 #include <sal/types.h> 11 #include <sal/core/spl.h> 12 #include <shared/bsl.h> 13 #include <soc/drv.h> 14 #include <soc/debug.h> 15 #include <soc/error.h> 16 #include <soc/phyreg.h> 17 18 #include <soc/phy.h> 19 #include <soc/phy/phyctrl.h> 20 #include <soc/phy/drv.h> 21 22 #include "phydefs.h" /* Must include before other phy related includes */ 23 24 #if defined(INCLUDE_PHY_54880) 25 #include "phyconfig.h" /* Must be the first phy include after phydefs.h */ 26 27 #include "phyident.h" 28 #include "phyreg.h" 29 #include "phyfege.h" 30 #include "phynull.h" 31 #include "phy54880.h" 32 33 #define PHY_IEEE_MODE(unit, port) (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_BR)) 34 35 36 #define SOC_PORT_MEDIUM_IEEE SOC_PORT_MEDIUM_COPPER 37 #define SOC_PORT_MEDIUM_BR SOC_PORT_MEDIUM_FIBER 38 #define SOC_PA_MEDIUM_IEEE SOC_PA_MEDIUM_COPPER 39 40 #define PHY_IS_BCM54880_A0(_pc) (PHY_MODEL_CHECK((_pc), \ 41 PHY_BCM54880_OUI, \ 42 PHY_BCM54880_MODEL) \ 43 && ((_pc)->phy_rev == 0x0 )) 44 45 #define PHY_IS_BCM54880(_pc) (PHY_MODEL_CHECK((_pc), \ 46 PHY_BCM54880_OUI, \ 47 PHY_BCM54880_MODEL)) 48 49 #define PHY_IS_BCM54881(_pc) (PHY_MODEL_CHECK((_pc), \ 50 PHY_BCM54881_OUI, \ 51 PHY_BCM54881_MODEL)) 52 53 #define PHY_IS_BCM54811(_pc) (PHY_MODEL_CHECK((_pc), \ 54 PHY_BCM54811_OUI, \ 55 PHY_BCM54811_MODEL) \ 56 && ((_pc)->phy_rev == 0x5 )) 57 58 59 #define PHY_IS_B0(_pc) ((PHY_IS_BCM54880(_pc) || PHY_IS_BCM54881(_pc)) \ 60 && ((_pc)->phy_rev == 0x1)) 61 62 #define PHY_BCM54880_A0_ID0 PHY_ID0(PHY_BCM54880_OUI,PHY_BCM54880_MODEL,0) 63 #define PHY_BCM54880_A0_ID1 PHY_ID1(PHY_BCM54880_OUI,PHY_BCM54880_MODEL,0) 64 65 #ifndef DISABLE_CLK125 66 #define DISABLE_CLK125 0 67 #endif 68 69 #ifndef AUTO_MDIX_WHEN_AN_DIS 70 #define AUTO_MDIX_WHEN_AN_DIS 0 71 #endif 72 73 #define DISABLE_TEST_PORT 1 74 /* #define A0_AUTO_FILL_PORT_INDEX 1 */ 75 76 #define LONGREACH_ABILITY_54880 ( SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR |\ 77 SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR |\ 78 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR |\ 79 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR |\ 80 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR |\ 81 SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX |\ 82 SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX ) 83 84 #define LONGREACH_ABILITY_54881 ( SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR |\ 85 SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR |\ 86 SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_1PAIR |\ 87 SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_2PAIR |\ 88 SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_1PAIR |\ 89 SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_2PAIR |\ 90 SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_1PAIR |\ 91 SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_2PAIR |\ 92 SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_1PAIR |\ 93 SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_2PAIR |\ 94 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR |\ 95 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR |\ 96 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR |\ 97 SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX |\ 98 SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX ) 99 100 #define LONGREACH_ABILITY_54811 ( SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR |\ 101 SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR |\ 102 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR |\ 103 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR |\ 104 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR |\ 105 SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX |\ 106 SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX ) 107 108 109 #define LONGREACH_ABILITY_ALL(_pc) ( PHY_IS_BCM54881((_pc)) ? LONGREACH_ABILITY_54881 : \ 110 ( PHY_IS_BCM54811((_pc)) ? LONGREACH_ABILITY_54811 : \ 111 LONGREACH_ABILITY_54880)) 112 113 #define LDS_ADVA_MASK(_pc) ( PHY_IS_BCM54881((_pc)) ? \ 114 LDS_ADVA_ASYM_PAUSE|LDS_ADVA_PAUSE|\ 115 LDS_ADVA_2_50|LDS_ADVA_2_33|LDS_ADVA_2_25|LDS_ADVA_2_20|\ 116 LDS_ADVA_1_50|LDS_ADVA_1_33|LDS_ADVA_1_25|LDS_ADVA_1_20|\ 117 LDS_ADVA_1_100|LDS_ADVA_4_100|LDS_ADVA_2_100|LDS_ADVA_2_10|LDS_ADVA_1_10 :\ 118 LDS_ADVA_ASYM_PAUSE|LDS_ADVA_PAUSE|\ 119 LDS_ADVA_1_100|LDS_ADVA_4_100|LDS_ADVA_2_100|LDS_ADVA_2_10|LDS_ADVA_1_10 ) 120 121 122 123 #define LONGREACH_ABILITY_10M ( SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR | \ 124 SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR ) 125 #define LONGREACH_ABILITY_20M ( SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_1PAIR | \ 126 SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_2PAIR ) 127 #define LONGREACH_ABILITY_25M ( SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_1PAIR | \ 128 SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_2PAIR ) 129 #define LONGREACH_ABILITY_33M ( SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_1PAIR | \ 130 SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_2PAIR ) 131 #define LONGREACH_ABILITY_50M ( SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_1PAIR | \ 132 SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_2PAIR ) 133 #define LONGREACH_ABILITY_100M ( SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR | \ 134 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR | \ 135 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR ) 136 137 typedef struct _phy_br_config_t { 138 int enable; 139 int lds_enable; 140 uint32 lds_advert_ability; 141 int force_speed; 142 int force_pairs; 143 int master; 144 int gain; 145 int bypass_reset; 146 } phy_br_config_t; 147 148 #define SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR(op) \ 149 do { \ 150 int __rv__; \ 151 if (((__rv__ = (op)) < 0)) { \ 152 if ((__rv__ == SOC_E_DISABLED)) { \ 153 __rv__ = SOC_E_NONE; \ 154 } \ 155 return(__rv__); \ 156 } \ 157 } while(0) 158 159 STATIC int 160 _phy_54880_ieee_speed_set(int unit, soc_port_t port, int speed); 161 STATIC int 162 _phy_54880_ieee_duplex_set(int unit, soc_port_t port, int duplex); 163 STATIC int 164 _phy_54880_ieee_master_set(int unit, soc_port_t port, int master); 165 STATIC int 166 _phy_54880_ieee_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability); 167 STATIC int 168 _phy_54880_ieee_autoneg_set(int unit, soc_port_t port, int autoneg); 169 STATIC int 170 _phy_54880_ieee_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode); 171 STATIC int 172 _phy_54880_ieee_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability); 173 STATIC int 174 _phy_54880_medium_change(int unit, soc_port_t port, int force_update); 175 176 STATIC int 177 _phy_54880_br_speed_set(int unit, soc_port_t port, int speed); 178 STATIC int 179 _phy_54880_br_pairs_set(int unit, soc_port_t port, int pairs); 180 STATIC int 181 _phy_54880_br_master_set(int unit, soc_port_t port, int master); 182 STATIC int 183 _phy_54880_br_ability_advert_set(int unit, soc_port_t port, uint32 ability); 184 STATIC int 185 _phy_54880_br_autoneg_set(int unit, soc_port_t port, int autoneg); 186 STATIC int 187 _phy_54880_br_gain_set(int unit, soc_port_t port, int gain); 188 189 STATIC int 190 phy_54880_control_set(int unit, soc_port_t port, 191 soc_phy_control_t type, uint32 value); 192 193 extern int 194 phy_ecd_cable_diag_init(int unit, soc_port_t port); 195 196 extern int 197 phy_ecd_cable_diag(int unit, soc_port_t port, 198 soc_port_cable_diag_t *status); 199 200 extern int 201 phy_acd_cable_diag_init(int unit, soc_port_t port); 202 203 extern int 204 phy_acd_cable_diag(int unit, soc_port_t port, 205 soc_port_cable_diag_t *status); 206 207 STATIC int 208 _SW2IEEE(int unit,phy_ctrl_t *pc) 209 { 210 uint16 lds_acc; 211 /* BCM54811 */ 212 if (PHY_IS_BCM54811(pc)) { 213 SOC_IF_ERROR_RETURN 214 (MODIFY_PHY54811_EXP_BR_LDS_CHAN_STATUSr(unit, pc, 215 (PHY54811_LDS_BR_IEEE_REG_ACCESS_OVERRIDE_EN 216 | PHY54811_LDS_BR_IEEE_REG_ACCESS_OVERRIDE_VAL), 217 (PHY54811_LDS_BR_IEEE_REG_ACCESS_OVERRIDE_EN 218 | PHY54811_LDS_BR_IEEE_REG_ACCESS_OVERRIDE_VAL))); 219 SOC_IF_ERROR_RETURN 220 (READ_PHY54811_EXP_BR_LDS_CHAN_STATUSr(unit, pc, &lds_acc)); 221 if(lds_acc & PHY54811_LDS_BR_IEEE_REG_ACCESS_CTRL_STATUS) { 222 return SOC_E_DISABLED; 223 } 224 return 0; 225 } 226 227 228 SOC_IF_ERROR_RETURN 229 (WRITE_PHY54880_LDS_ACCr(unit, pc, 0x6)); 230 231 SOC_IF_ERROR_RETURN 232 (READ_PHY54880_LDS_ACCr((unit), (pc), &lds_acc)); 233 if (lds_acc & LDS_ACC_STAT) { 234 return SOC_E_DISABLED; 235 } 236 return 0; 237 } 238 239 STATIC int 240 _SW2BR(int unit,phy_ctrl_t *pc) 241 { 242 uint16 lds_acc; 243 phy_br_config_t *br_config; 244 245 /* BCM54811 */ 246 if (PHY_IS_BCM54811(pc)) { 247 SOC_IF_ERROR_RETURN 248 (MODIFY_PHY54811_EXP_BR_LDS_CHAN_STATUSr(unit, pc, 249 PHY54811_LDS_BR_IEEE_REG_ACCESS_OVERRIDE_EN, 250 (PHY54811_LDS_BR_IEEE_REG_ACCESS_OVERRIDE_EN 251 | PHY54811_LDS_BR_IEEE_REG_ACCESS_OVERRIDE_VAL))); 252 SOC_IF_ERROR_RETURN 253 (READ_PHY54811_EXP_BR_LDS_CHAN_STATUSr(unit, pc, &lds_acc)); 254 if( 0 == (lds_acc & PHY54811_LDS_BR_IEEE_REG_ACCESS_CTRL_STATUS)) { 255 return SOC_E_DISABLED; 256 } 257 return 0; 258 } 259 260 br_config = (phy_br_config_t *) &pc->fiber; 261 if (br_config->enable && !br_config->lds_enable) { 262 return 0; 263 } 264 265 SOC_IF_ERROR_RETURN 266 (WRITE_PHY54880_LDS_ACCr(unit, pc, 0x4)); 267 268 SOC_IF_ERROR_RETURN 269 (READ_PHY54880_LDS_ACCr((unit), (pc), &lds_acc)); 270 if ((lds_acc & LDS_ACC_STAT) == 0) { 271 return SOC_E_DISABLED; 272 } 273 return 0; 274 } 275 276 /* 277 * Function: 278 * phy_54880_medium_status 279 * Purpose: 280 * Indicate the current active medium 281 * Parameters: 282 * unit - StrataSwitch unit #. 283 * port - StrataSwitch port #. 284 * medium - (OUT) One of: 285 * SOC_PORT_MEDIUM_COPPER 286 * SOC_PORT_MEDIUM_FIBER 287 * Returns: 288 * SOC_E_NONE. 289 */ 290 STATIC int 291 phy_54880_medium_status(int unit, soc_port_t port, soc_port_medium_t *medium) 292 { 293 *medium = SOC_PORT_MEDIUM_IEEE; 294 295 return SOC_E_NONE; 296 } 297 298 /* 299 * Function: 300 * _phy_54880_ieee_medium_config_update 301 * Purpose: 302 * Update the operating parameters that are automatically selected 303 * when medium switches type. 304 * Parameters: 305 * unit - StrataSwitch unit # 306 * port - Port number 307 * cfg - Operating parameters 308 * Returns: 309 * SOC_E_XXX 310 */ 311 STATIC int 312 _phy_54880_ieee_medium_config_update(int unit, soc_port_t port, 313 soc_phy_config_t *cfg) 314 { 315 SOC_IF_ERROR_RETURN 316 (_phy_54880_ieee_speed_set(unit, port, cfg->force_speed)); 317 SOC_IF_ERROR_RETURN 318 (_phy_54880_ieee_duplex_set(unit, port, cfg->force_duplex)); 319 SOC_IF_ERROR_RETURN 320 (_phy_54880_ieee_master_set(unit, port, cfg->master)); 321 SOC_IF_ERROR_RETURN 322 (_phy_54880_ieee_ability_advert_set(unit, port, &cfg->advert_ability)); 323 SOC_IF_ERROR_RETURN 324 (_phy_54880_ieee_autoneg_set(unit, port, cfg->autoneg_enable)); 325 SOC_IF_ERROR_RETURN 326 (_phy_54880_ieee_mdix_set(unit, port, cfg->mdix)); 327 328 return SOC_E_NONE; 329 } 330 331 STATIC int 332 _phy_54880_br_medium_config_update(int unit, soc_port_t port, 333 phy_br_config_t *cfg) 334 { 335 /* Notice the order. Speed, pairs and master could be written to the regs 336 only if LDS is disabled. 337 */ 338 339 SOC_IF_ERROR_RETURN 340 (_phy_54880_br_ability_advert_set(unit, port, cfg->lds_advert_ability)); 341 SOC_IF_ERROR_RETURN 342 (_phy_54880_br_autoneg_set(unit, port, cfg->lds_enable)); 343 344 if ( !cfg->lds_enable ) { 345 SOC_IF_ERROR_RETURN 346 (_phy_54880_br_speed_set(unit, port, cfg->force_speed)); 347 SOC_IF_ERROR_RETURN 348 (_phy_54880_br_pairs_set(unit, port, cfg->force_pairs)); 349 SOC_IF_ERROR_RETURN 350 (_phy_54880_br_master_set(unit, port, cfg->master)); 351 SOC_IF_ERROR_RETURN 352 (_phy_54880_br_gain_set(unit, port, cfg->gain)); 353 } 354 355 return SOC_E_NONE; 356 } 357 358 STATIC int 359 phy_54880_medium_config_set(int unit, soc_port_t port, 360 soc_port_medium_t medium, 361 soc_phy_config_t *cfg) 362 { 363 phy_ctrl_t *pc; 364 soc_port_ability_t ability; 365 366 pc = EXT_PHY_SW_STATE(unit, port); 367 368 /* 369 * Changes take effect immediately if the target medium is active. 370 */ 371 if (medium == SOC_PORT_MEDIUM_COPPER) { 372 373 sal_memcpy(&pc->copper, cfg, sizeof (pc->copper)); 374 375 SOC_IF_ERROR_RETURN 376 (_phy_54880_ieee_ability_local_get(unit, port, &ability)); 377 378 pc->copper.advert_ability.speed_half_duplex &= ability.speed_half_duplex; 379 pc->copper.advert_ability.speed_full_duplex &= ability.speed_full_duplex; 380 pc->copper.advert_ability.pause &= ability.pause; 381 382 if (PHY_IEEE_MODE(unit, port)) { 383 SOC_IF_ERROR_RETURN 384 (_phy_54880_ieee_medium_config_update(unit, port, &pc->copper)); 385 } 386 return SOC_E_NONE; 387 } 388 389 return SOC_E_CONFIG; 390 } 391 392 393 /* 394 * Function: 395 * phy_54880_medium_config_get 396 * Purpose: 397 * Get the operating parameters that are automatically selected 398 * when medium switches type. 399 * Parameters: 400 * unit - StrataSwitch unit # 401 * port - Port number 402 * medium - SOC_PORT_MEDIUM_COPPER/FIBER 403 * cfg - (OUT) Operating parameters 404 * Returns: 405 * SOC_E_XXX 406 */ 407 408 STATIC int 409 phy_54880_medium_config_get(int unit, soc_port_t port, 410 soc_port_medium_t medium, 411 soc_phy_config_t *cfg) 412 { 413 phy_ctrl_t *pc; 414 415 COMPILER_REFERENCE(medium); 416 417 pc = EXT_PHY_SW_STATE(unit, port); 418 419 sal_memcpy(cfg, &pc->copper, sizeof (*cfg)); 420 421 return SOC_E_NONE; 422 } 423 424 /* 425 * Function: 426 * _phy_54880_reset_setup 427 * Purpose: 428 * Function to reset the PHY and set up initial operating registers. 429 * Parameters: 430 * unit - StrataSwitch unit #. 431 * port - StrataSwitch port #. 432 * Returns: 433 * SOC_E_XXX 434 */ 435 436 STATIC int 437 _phy_54880_reset_setup(int unit, soc_port_t port) 438 { 439 phy_ctrl_t *pc; 440 uint16 tmp; 441 uint16 phy_addr; 442 uint16 id0, id1; 443 int index; 444 445 pc = EXT_PHY_SW_STATE(unit, port); 446 447 SOC_IF_ERROR_RETURN(phy_ge_init(unit, port)); 448 449 phy_addr = pc->phy_id; 450 index = phy_addr & 7; 451 452 /* set the default values that are valid for many boards */ 453 SOC_IF_ERROR_RETURN 454 (phy_54880_control_set( unit, port, SOC_PHY_CONTROL_PORT_PRIMARY, 455 (port - index) < 0 ? 0:(port - index))); 456 SOC_IF_ERROR_RETURN 457 (phy_54880_control_set( unit, port, SOC_PHY_CONTROL_PORT_OFFSET, index )); 458 459 #ifdef DISABLE_TEST_PORT 460 if (PHY_IS_BCM54880_A0(pc)) { 461 /* Disable test port */ 462 463 phy_addr = pc->phy_id + 1; 464 465 SOC_IF_ERROR_RETURN 466 (pc->read(unit, phy_addr, MII_PHY_ID0_REG, &id0)); 467 468 SOC_IF_ERROR_RETURN 469 (pc->read(unit, phy_addr, MII_PHY_ID1_REG, &id1)); 470 471 if ( ( id0 != PHY_BCM54880_A0_ID0 ) || ( id1 != PHY_BCM54880_A0_ID1 ) ) { 472 473 SOC_IF_ERROR_RETURN 474 (pc->write(unit, phy_addr, 0x1f, 0xffd0)); 475 476 SOC_IF_ERROR_RETURN 477 (pc->write(unit, phy_addr, 0x1e, 0x001f)); 478 479 SOC_IF_ERROR_RETURN 480 (pc->write(unit, phy_addr, 0x1f, 0x8000)); 481 482 SOC_IF_ERROR_RETURN 483 (pc->write(unit, phy_addr, 0x1d, 0x4002)); 484 485 SOC_IF_ERROR_RETURN 486 (pc->write(unit, phy_addr, 0x00, MII_CTRL_RESET)); 487 488 #ifdef A0_AUTO_FILL_PORT_INDEX 489 { 490 int i; 491 492 for (i = 0; i < 8; i++) { 493 SOC_IF_ERROR_RETURN 494 (phy_54880_control_set(unit, port - i, SOC_PHY_CONTROL_PORT_PRIMARY, port - 7)); 495 SOC_IF_ERROR_RETURN 496 (phy_54880_control_set(unit, port - i, SOC_PHY_CONTROL_PORT_OFFSET, 7 - i )); 497 } 498 } 499 #endif 500 } 501 } 502 #endif 503 504 /* remove power down */ 505 if (pc->copper.enable) { 506 tmp = PHY_DISABLED_MODE(unit, port) ? MII_CTRL_PD : 0; 507 } else { 508 tmp = MII_CTRL_PD; 509 } 510 SOC_IF_ERROR_RETURN 511 (MODIFY_PHY54880_MII_CTRLr(unit, pc, tmp, MII_CTRL_PD)); 512 513 #if DISABLE_CLK125 514 /* Reduce EMI emissions by disabling the CLK125 pin if not used */ 515 SOC_IF_ERROR_RETURN 516 (MODIFY_PHY54880_SPARE_CTRL_3r(unit, pc, 0, 1)); 517 #endif 518 519 /* Configure Extended Control Register */ 520 /* Enable LEDs to indicate traffic status */ 521 SOC_IF_ERROR_RETURN 522 (MODIFY_PHY54880_MII_ECRr(unit, pc, 0x0020, 0x0020)); 523 524 #if AUTO_MDIX_WHEN_AN_DIS 525 /* Enable Auto-MDIX When autoneg disabled */ 526 SOC_IF_ERROR_RETURN 527 (MODIFY_PHY54880_MII_MISC_CTRLr(unit, pc, 0x0200, 0x0200)); 528 #endif 529 530 /* Enable extended packet length (4.5k through 25k) */ 531 SOC_IF_ERROR_RETURN 532 (MODIFY_PHY54880_MII_AUX_CTRLr(unit, pc, 0x4000, 0x4000)); 533 534 SOC_IF_ERROR_RETURN 535 (MODIFY_PHY54880_MISC_1000X_CTRL2r(unit, pc, 0x0001, 0x0001)); 536 537 SOC_IF_ERROR_RETURN 538 (MODIFY_PHY54880_AUX_CTRLr(unit, pc, 0x0002, 0x0002)); 539 540 /* Configure LED selectors */ 541 tmp = ((pc->ledmode[1] & 0xf) << 4) | (pc->ledmode[0] & 0xf); 542 SOC_IF_ERROR_RETURN 543 (WRITE_PHY54880_LED_SELECTOR_1r(unit, pc, tmp)); 544 545 tmp = ((pc->ledmode[3] & 0xf) << 4) | (pc->ledmode[2] & 0xf); 546 SOC_IF_ERROR_RETURN 547 (WRITE_PHY54880_LED_SELECTOR_2r(unit, pc, tmp)); 548 549 tmp = (pc->ledctrl & 0x3ff); 550 SOC_IF_ERROR_RETURN 551 (WRITE_PHY54880_LED_CTRLr(unit, pc, tmp)); 552 553 SOC_IF_ERROR_RETURN 554 (WRITE_PHY54880_EXP_LED_SELECTORr(unit, pc, pc->ledselect)); 555 556 /* LDS parameters */ 557 558 SOC_IF_ERROR_RETURN 559 (WRITE_PHY54880_EXP_BR_LDS_RX_CTRL1r(unit, pc, 0x0e1b)); 560 561 SOC_IF_ERROR_RETURN 562 (WRITE_PHY54880_EXP_BR_LDS_RX_CTRL2r(unit, pc, 0x0306)); 563 564 /* 565 * Configure Auxiliary control register to turn off 566 * carrier extension. The Intel 7131 NIC does not accept carrier 567 * extension and gets CRC errors. 568 */ 569 /* Disable carrier extension */ 570 SOC_IF_ERROR_RETURN 571 (MODIFY_PHY54880_AUX_CTRLr(unit, pc, 0x0040, 0x0040)); 572 573 if (PHY_IS_B0(pc)) { 574 /* B0 errata */ 575 SOC_IF_ERROR_RETURN 576 (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL2r(unit, pc, 1U<<3, 1U<<3)); 577 } 578 579 if ((PHY_IS_BCM54880(pc)) && ((pc->phy_rev & 0xf) > 0x1)) { 580 SOC_IF_ERROR_RETURN( 581 phy_ecd_cable_diag_init(unit, port)); 582 } 583 584 return SOC_E_NONE; 585 586 } 587 588 /* 589 * Function: 590 * _phy_54811_reset_setup 591 * Purpose: 592 * Function to reset the PHY and set up initial operating registers. 593 * Parameters: 594 * unit - StrataSwitch unit #. 595 * port - StrataSwitch port #. 596 * Returns: 597 * SOC_E_XXX 598 */ 599 600 STATIC int 601 _phy_54811_reset_setup(int unit, soc_port_t port) 602 { 603 phy_ctrl_t *pc; 604 uint16 tmp; 605 uint16 phy_addr; 606 int index; 607 608 SOC_IF_ERROR_RETURN(phy_ge_init(unit, port)); 609 610 pc = EXT_PHY_SW_STATE(unit, port); 611 612 phy_addr = pc->phy_id; 613 index = phy_addr & 7; 614 615 /* set the default values that are valid for many boards */ 616 SOC_IF_ERROR_RETURN 617 (phy_54880_control_set( unit, port, SOC_PHY_CONTROL_PORT_PRIMARY, 618 (port - index) < 0 ? 0:(port - index))); 619 SOC_IF_ERROR_RETURN 620 (phy_54880_control_set( unit, port, SOC_PHY_CONTROL_PORT_OFFSET, index )); 621 622 /* remove power down */ 623 if (pc->copper.enable) { 624 tmp = PHY_DISABLED_MODE(unit, port) ? MII_CTRL_PD : 0; 625 } else { 626 tmp = MII_CTRL_PD; 627 } 628 SOC_IF_ERROR_RETURN 629 (MODIFY_PHY54880_MII_CTRLr(unit, pc, tmp, MII_CTRL_PD)); 630 631 /* Configure Extended Control Register */ 632 /* Enable LEDs to indicate traffic status */ 633 SOC_IF_ERROR_RETURN 634 (MODIFY_PHY54880_MII_ECRr(unit, pc, 0x0020, 0x0020)); 635 636 #if AUTO_MDIX_WHEN_AN_DIS 637 /* Enable Auto-MDIX When autoneg disabled */ 638 SOC_IF_ERROR_RETURN 639 (MODIFY_PHY54880_MII_MISC_CTRLr(unit, pc, 0x0200, 0x0200)); 640 #endif 641 642 /* Enable extended packet length (4.5k through 25k) */ 643 SOC_IF_ERROR_RETURN 644 (MODIFY_PHY54880_MII_AUX_CTRLr(unit, pc, 0x4000, 0x4000)); 645 646 #if 0 647 648 SOC_IF_ERROR_RETURN 649 (MODIFY_PHY54880_MISC_1000X_CTRL2r(unit, pc, 0x0001, 0x0001)); 650 651 SOC_IF_ERROR_RETURN 652 (MODIFY_PHY54880_AUX_CTRLr(unit, pc, 0x0002, 0x0002)); 653 #endif 654 655 /* Configure LED selectors */ 656 tmp = ((pc->ledmode[1] & 0xf) << 4) | (pc->ledmode[0] & 0xf); 657 SOC_IF_ERROR_RETURN 658 (WRITE_PHY54880_LED_SELECTOR_1r(unit, pc, tmp)); 659 660 tmp = ((pc->ledmode[3] & 0xf) << 4) | (pc->ledmode[2] & 0xf); 661 SOC_IF_ERROR_RETURN 662 (WRITE_PHY54880_LED_SELECTOR_2r(unit, pc, tmp)); 663 664 tmp = (pc->ledctrl & 0x3ff); 665 SOC_IF_ERROR_RETURN 666 (WRITE_PHY54880_LED_CTRLr(unit, pc, tmp)); 667 668 SOC_IF_ERROR_RETURN 669 (WRITE_PHY54880_EXP_LED_SELECTORr(unit, pc, pc->ledselect)); 670 671 #if 0 672 673 /* LDS parameters */ 674 675 SOC_IF_ERROR_RETURN 676 (WRITE_PHY54880_EXP_BR_LDS_RX_CTRL1r(unit, pc, 0x0e1b)); 677 678 SOC_IF_ERROR_RETURN 679 (WRITE_PHY54880_EXP_BR_LDS_RX_CTRL2r(unit, pc, 0x0306)); 680 681 /* 682 * Configure Auxiliary control register to turn off 683 * carrier extension. The Intel 7131 NIC does not accept carrier 684 * extension and gets CRC errors. 685 */ 686 /* Disable carrier extension */ 687 SOC_IF_ERROR_RETURN 688 (MODIFY_PHY54880_AUX_CTRLr(unit, pc, 0x0040, 0x0040)); 689 690 if (PHY_IS_B0(pc)) { 691 /* B0 errata */ 692 SOC_IF_ERROR_RETURN 693 (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL2r(unit, pc, 1U<<3, 1U<<3)); 694 } 695 696 #endif 697 698 return SOC_E_NONE; 699 700 } 701 702 703 /* 704 * Function: 705 * phy_54880_init 706 * Purpose: 707 * Init function for 54880 PHY. 708 * Parameters: 709 * unit - StrataSwitch unit #. 710 * port - StrataSwitch port #. 711 * Returns: 712 * SOC_E_XXX 713 */ 714 STATIC int 715 phy_54880_init(int unit, soc_port_t port) 716 { 717 phy_ctrl_t *pc; 718 soc_phy_config_t *copper_config; 719 phy_br_config_t *br_config; 720 int lr_initial_mode; 721 int lr_initial_ctrl; 722 int lr_initial_adva; 723 724 pc = EXT_PHY_SW_STATE(unit, port); 725 726 copper_config = (soc_phy_config_t *) &pc->copper; 727 br_config = (phy_br_config_t *) &pc->fiber; 728 729 pc->automedium = FALSE; 730 731 copper_config->enable = TRUE; 732 copper_config->autoneg_enable = TRUE; 733 if (PHY_IS_BCM54881(pc)) { 734 copper_config->force_speed = 100; 735 } else { 736 copper_config->force_speed = 1000; 737 } 738 copper_config->force_duplex = TRUE; 739 copper_config->master = SOC_PORT_MS_AUTO; 740 copper_config->mdix = SOC_PORT_MDIX_AUTO; 741 742 br_config->bypass_reset = 0; 743 744 /* Initial Setting for BR mode */ 745 lr_initial_mode = 746 soc_property_port_get(unit, port, spn_PHY_LR_INITIAL_MODE, -1); 747 lr_initial_ctrl = 748 soc_property_port_get(unit, port, spn_PHY_LR_INITIAL_CTRL, -1); 749 lr_initial_adva = 750 soc_property_port_get(unit, port, spn_PHY_LR_INITIAL_ADVA, -1); 751 752 /* Initial BR mode settings */ 753 if (lr_initial_mode != -1) { 754 br_config->enable = 755 (lr_initial_mode & LR_INITIAL_MODE_LR_ENABLE) ? TRUE : FALSE; 756 } else { 757 br_config->enable = FALSE; 758 } 759 760 /* Initial BR ctrl settings */ 761 if (lr_initial_ctrl != -1) { 762 br_config->lds_enable = 763 (lr_initial_ctrl & LR_INITIAL_CTRL_LDS_ENABLE) ? TRUE : FALSE; 764 765 if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_PS_MASK) == 766 LR_INITIAL_CTRL_LR_PS_1P) { 767 br_config->force_pairs = 1; 768 } else if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_PS_MASK) == 769 LR_INITIAL_CTRL_LR_PS_2P) { 770 br_config->force_pairs = 2; 771 } else if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_PS_MASK) == 772 LR_INITIAL_CTRL_LR_PS_4P) { 773 br_config->force_pairs = 4; 774 } else { 775 br_config->force_pairs = 0; 776 } 777 778 br_config->master = 779 (lr_initial_ctrl & LR_INITIAL_CTRL_LR_MS) ? 780 SOC_PORT_MS_MASTER : SOC_PORT_MS_SLAVE; 781 782 if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_SS_MASK) == 783 LR_INITIAL_CTRL_LR_SS_10) { 784 br_config->force_speed = 10; 785 } else if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_SS_MASK) == 786 LR_INITIAL_CTRL_LR_SS_20) { 787 br_config->force_speed = 20; 788 } else if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_SS_MASK) == 789 LR_INITIAL_CTRL_LR_SS_25) { 790 br_config->force_speed = 25; 791 } else if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_SS_MASK) == 792 LR_INITIAL_CTRL_LR_SS_33) { 793 br_config->force_speed = 33; 794 } else if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_SS_MASK) == 795 LR_INITIAL_CTRL_LR_SS_50) { 796 br_config->force_speed = 50; 797 } else if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_SS_MASK) == 798 LR_INITIAL_CTRL_LR_SS_100) { 799 br_config->force_speed = 100; 800 } else { 801 br_config->force_speed = 100; 802 } 803 804 } else { 805 br_config->lds_enable = TRUE; 806 br_config->force_pairs = 0; 807 br_config->master = SOC_PORT_MS_AUTO; 808 br_config->force_speed = 100; 809 } 810 811 /* Initial advert ability, valid only if LDS is enabled */ 812 if (lr_initial_adva != -1) { 813 br_config->lds_advert_ability = 0; 814 if(lr_initial_adva & LR_INITIAL_ADVA_1_10) { 815 br_config->lds_advert_ability |= 816 SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR; 817 } 818 if(lr_initial_adva & LR_INITIAL_ADVA_2_10) { 819 br_config->lds_advert_ability |= 820 SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR; 821 } 822 if(lr_initial_adva & LR_INITIAL_ADVA_1_20) { 823 br_config->lds_advert_ability |= 824 SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_1PAIR; 825 } 826 if(lr_initial_adva & LR_INITIAL_ADVA_2_20) { 827 br_config->lds_advert_ability |= 828 SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_2PAIR; 829 } 830 if(lr_initial_adva & LR_INITIAL_ADVA_1_33) { 831 br_config->lds_advert_ability |= 832 SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_1PAIR; 833 } 834 if(lr_initial_adva & LR_INITIAL_ADVA_2_33) { 835 br_config->lds_advert_ability |= 836 SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_2PAIR; 837 } 838 if(lr_initial_adva & LR_INITIAL_ADVA_1_50) { 839 br_config->lds_advert_ability |= 840 SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_1PAIR; 841 } 842 if(lr_initial_adva & LR_INITIAL_ADVA_2_50) { 843 br_config->lds_advert_ability |= 844 SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_2PAIR; 845 } 846 if(lr_initial_adva & LR_INITIAL_ADVA_1_100) { 847 br_config->lds_advert_ability |= 848 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR; 849 } 850 if(lr_initial_adva & LR_INITIAL_ADVA_2_100) { 851 br_config->lds_advert_ability |= 852 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR; 853 } 854 if(lr_initial_adva & LR_INITIAL_ADVA_4_100) { 855 br_config->lds_advert_ability |= 856 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR; 857 } 858 if(lr_initial_adva & LR_INITIAL_ADVA_PAUSE_RX) { 859 br_config->lds_advert_ability |= 860 SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX; 861 } 862 if(lr_initial_adva & LR_INITIAL_ADVA_PAUSE_TX) { 863 br_config->lds_advert_ability |= 864 SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX; 865 } 866 } else { 867 br_config->lds_advert_ability = LONGREACH_ABILITY_ALL(pc); 868 } 869 870 br_config->gain = 2; 871 872 /* Initially configure for the preferred medium. */ 873 874 PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER); 875 if (br_config->enable) { 876 PHY_FLAGS_SET(unit, port, PHY_FLAGS_BR); 877 } else { 878 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_BR); 879 } 880 881 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_PASSTHRU); 882 883 /* Get Requested LED selectors (defaults are hardware defaults) */ 884 pc->ledmode[0] = soc_property_port_get(unit, port, spn_PHY_LED1_MODE, 0); 885 pc->ledmode[1] = soc_property_port_get(unit, port, spn_PHY_LED2_MODE, 1); 886 pc->ledmode[2] = soc_property_port_get(unit, port, spn_PHY_LED3_MODE, 3); 887 pc->ledmode[3] = soc_property_port_get(unit, port, spn_PHY_LED4_MODE, 6); 888 pc->ledctrl = soc_property_port_get(unit, port, spn_PHY_LED_CTRL, 0x8); 889 pc->ledselect = soc_property_port_get(unit, port, spn_PHY_LED_SELECT, 0); 890 891 /* Get half amplitude setting */ 892 /* pc->halfout = soc_property_port_get(unit, port, spn_PHY_HALF_POWER, 0); */ 893 894 if( PHY_IS_BCM54811(pc)) { 895 SOC_IF_ERROR_RETURN 896 (_phy_54811_reset_setup(unit, port)); 897 /* Disable BR by default */ 898 SOC_IF_ERROR_RETURN 899 (MODIFY_PHY54811_EXP_BR_LRE_MISC_CTRLr(unit, pc, 0x0, 0x1)); 900 } else { 901 if (!br_config->bypass_reset) { 902 SOC_IF_ERROR_RETURN 903 (_phy_54880_reset_setup(unit, port)); 904 } 905 906 if (br_config->enable) { 907 SOC_IF_ERROR_RETURN 908 (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL1r(unit, pc, 0x1, 0x1)); 909 } else { 910 /* Disable BR by default */ 911 SOC_IF_ERROR_RETURN 912 (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL1r(unit, pc, 0x0, 0x1)); 913 } 914 } 915 if (PHY_IS_BCM54881(pc)) { 916 /* Enabling half duplex in 54881 */ 917 SOC_IF_ERROR_RETURN 918 (MODIFY_PHY54880_MII_MISC_CTRLr(unit, pc, 1U<<7, 1U<<7)); 919 } 920 921 /* Advertise all possible by default */ 922 SOC_IF_ERROR_RETURN 923 (_phy_54880_ieee_ability_local_get(unit, port, &pc->copper.advert_ability)); 924 925 if (br_config->enable) { 926 SOC_IF_ERROR_RETURN 927 (_phy_54880_br_medium_config_update(unit, port, br_config)); 928 } else { 929 SOC_IF_ERROR_RETURN 930 (_phy_54880_ieee_medium_config_update(unit, port, &pc->copper)); 931 } 932 933 return SOC_E_NONE; 934 935 } 936 937 /* 938 * Function: 939 * phy_54880_enable_set 940 * Purpose: 941 * Enable or disable the physical interface. 942 * Parameters: 943 * unit - StrataSwitch unit #. 944 * port - StrataSwitch port #. 945 * enable - Boolean, true = enable PHY, false = disable. 946 * Returns: 947 * SOC_E_XXX 948 */ 949 950 STATIC int 951 phy_54880_enable_set(int unit, soc_port_t port, int enable) 952 { 953 phy_ctrl_t *pc; 954 uint16 power_down; 955 956 pc = EXT_PHY_SW_STATE(unit, port); 957 958 power_down = (enable) ? 0 : MII_CTRL_PD; 959 960 if (pc->copper.enable) { 961 SOC_IF_ERROR_RETURN 962 (MODIFY_PHY54880_MII_CTRLr(unit, pc, power_down, MII_CTRL_PD)); 963 } 964 965 SOC_IF_ERROR_RETURN 966 (phy_fe_ge_enable_set(unit, port, enable)); 967 968 return SOC_E_NONE; 969 970 } 971 972 /* 973 * Function: 974 * phy_54880_enable_get 975 * Purpose: 976 * Enable or disable the physical interface for a 54880 device. 977 * Parameters: 978 * unit - StrataSwitch unit #. 979 * port - StrataSwitch port #. 980 * enable - (OUT) Boolean, true = enable PHY, false = disable. 981 * Returns: 982 * SOC_E_XXX 983 */ 984 985 STATIC int 986 phy_54880_enable_get(int unit, soc_port_t port, int *enable) 987 { 988 SOC_IF_ERROR_RETURN 989 (phy_fe_ge_enable_get(unit, port, enable)); 990 991 return SOC_E_NONE; 992 } 993 994 STATIC int 995 _phy_54880_medium_check(int unit, soc_port_t port, int *medium) 996 { 997 phy_ctrl_t *pc; 998 uint16 status; 999 phy_br_config_t *br_config; 1000 1001 pc = EXT_PHY_SW_STATE(unit, port); 1002 1003 br_config = (phy_br_config_t *) &pc->fiber; 1004 1005 /* Force to br mode first to avoid locking up in ieee */ 1006 SOC_IF_ERROR_RETURN 1007 (WRITE_PHY54880_LDS_ACCr(unit, pc, 0x4)); 1008 1009 /* Force to auto mode */ 1010 SOC_IF_ERROR_RETURN 1011 (WRITE_PHY54880_LDS_ACCr(unit, pc, 0x0)); 1012 1013 SOC_IF_ERROR_RETURN 1014 (READ_PHY54880_LDS_ACCr(unit, pc, &status)); 1015 1016 if ( status & LDS_ACC_STAT ) { 1017 *medium = SOC_PORT_MEDIUM_BR; 1018 } else { 1019 if (br_config->enable && !br_config->lds_enable) { 1020 *medium = SOC_PORT_MEDIUM_BR; 1021 } else { 1022 *medium = SOC_PORT_MEDIUM_IEEE; 1023 } 1024 } 1025 return SOC_E_NONE; 1026 } 1027 1028 1029 STATIC int 1030 _phy_54880_medium_change(int unit, soc_port_t port, int force_update) 1031 { 1032 phy_ctrl_t *pc; 1033 int medium; 1034 soc_phy_config_t *copper_config; 1035 phy_br_config_t *br_config; 1036 1037 pc = EXT_PHY_SW_STATE(unit, port); 1038 1039 copper_config = (soc_phy_config_t *) &pc->copper; 1040 br_config = (phy_br_config_t *) &pc->fiber; 1041 1042 SOC_IF_ERROR_RETURN 1043 (_phy_54880_medium_check(unit, port, &medium)); 1044 1045 if (medium == SOC_PORT_MEDIUM_IEEE) { 1046 if ((!PHY_IEEE_MODE(unit, port)) || force_update) { /* Was BR */ 1047 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_BR); 1048 PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 1049 1050 /* Do not power up the interface if medium is disabled. */ 1051 if (copper_config->enable) { 1052 SOC_IF_ERROR_RETURN 1053 (_phy_54880_ieee_medium_config_update(unit, port,copper_config)); 1054 } 1055 LOG_INFO(BSL_LS_SOC_PHY, 1056 (BSL_META_U(unit, 1057 "_phy_54880_link_auto_detect: u=%d p=%d [F->X]\n"), 1058 unit, port)); 1059 } else { 1060 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 1061 } 1062 } else { 1063 if (PHY_IEEE_MODE(unit, port) || force_update) { /* Was IEEE */ 1064 PHY_FLAGS_SET(unit, port, PHY_FLAGS_BR); 1065 PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 1066 1067 if (br_config->enable) { 1068 SOC_IF_ERROR_RETURN 1069 (_phy_54880_br_medium_config_update(unit, port,br_config)); 1070 } 1071 LOG_INFO(BSL_LS_SOC_PHY, 1072 (BSL_META_U(unit, 1073 "_phy_54880_link_auto_detect: u=%d p=%d [C->X]\n"), 1074 unit, port)); 1075 } else { 1076 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 1077 } 1078 } 1079 1080 return SOC_E_NONE; 1081 } 1082 1083 int 1084 _phy_54880_br_link_get(int unit, soc_port_t port, int *link) 1085 { 1086 uint16 lre_ctrl, lre_stat; 1087 soc_timeout_t to; 1088 phy_ctrl_t *pc; 1089 1090 *link = FALSE; /* Default */ 1091 1092 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) { 1093 return SOC_E_NONE; 1094 } 1095 1096 pc = EXT_PHY_SW_STATE(unit, port); 1097 1098 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1099 (_SW2BR(unit, pc)); 1100 1101 SOC_IF_ERROR_RETURN 1102 (READ_PHY54880_LRE_STATr(unit, pc, &lre_stat)); 1103 1104 if (!(lre_stat & LRE_STAT_LA)) { 1105 return SOC_E_NONE; 1106 } 1107 1108 /* Link appears to be up; we are done if autoneg is off. */ 1109 1110 SOC_IF_ERROR_RETURN 1111 (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl)); 1112 1113 if (!(lre_ctrl & LRE_CTRL_LDSE)) { 1114 *link = TRUE; 1115 return SOC_E_NONE; 1116 } 1117 1118 soc_timeout_init(&to, SOC_PHY_INFO(unit, port).an_timeout, 0); 1119 for (;;) { 1120 SOC_IF_ERROR_RETURN 1121 (READ_PHY54880_LRE_STATr(unit, pc, &lre_stat)); 1122 1123 if (!(lre_stat & LRE_STAT_LA)) { 1124 return SOC_E_NONE; 1125 } 1126 1127 if (lre_stat & LRE_STAT_LDS_DONE) { 1128 break; 1129 } 1130 1131 if (soc_timeout_check(&to)) { 1132 return SOC_E_BUSY; 1133 } 1134 } 1135 1136 /* Return link state at end of polling */ 1137 1138 *link = ((lre_stat & LRE_STAT_LA) != 0); 1139 1140 return SOC_E_NONE; 1141 } 1142 1143 1144 /* 1145 * Function: 1146 * phy_54880_link_get 1147 * Purpose: 1148 * Determine the current link up/down status for a 54880 device. 1149 * Parameters: 1150 * unit - StrataSwitch unit #. 1151 * port - StrataSwitch port #. 1152 * link - (OUT) Boolean, true indicates link established. 1153 * Returns: 1154 * SOC_E_XXX 1155 * Notes: 1156 * If using automedium, also switches the mode. 1157 */ 1158 1159 STATIC int 1160 phy_54880_link_get(int unit, soc_port_t port, int *link) 1161 { 1162 1163 phy_ctrl_t *pc; 1164 1165 pc = EXT_PHY_SW_STATE(unit, port); 1166 1167 if (link == NULL) { 1168 return SOC_E_NONE; 1169 } 1170 1171 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) { 1172 *link = FALSE; 1173 return SOC_E_NONE; 1174 } 1175 1176 SOC_IF_ERROR_RETURN 1177 (_phy_54880_medium_change(unit, port,FALSE)); 1178 1179 if (PHY_IEEE_MODE(unit, port)) { 1180 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1181 (_SW2IEEE(unit, pc)); 1182 SOC_IF_ERROR_RETURN 1183 (phy_fe_ge_link_get(unit, port, link)); 1184 } else { 1185 SOC_IF_ERROR_RETURN 1186 (_phy_54880_br_link_get(unit, port, link)); 1187 } 1188 1189 return SOC_E_NONE; 1190 1191 } 1192 1193 /* 1194 * Function: 1195 * phy_54880_duplex_set 1196 * Purpose: 1197 * Set the current duplex mode (forced). 1198 * Parameters: 1199 * unit - StrataSwitch unit #. 1200 * port - StrataSwitch port #. 1201 * duplex - Boolean, true indicates full duplex, false indicates half. 1202 * Returns: 1203 * SOC_E_XXX 1204 * SOC_E_UNAVAIL - Half duplex requested, and not supported. 1205 * Notes: 1206 * The duplex is set only for the ACTIVE medium. 1207 * No synchronization performed at this level. 1208 * Autonegotiation is not manipulated. 1209 */ 1210 1211 STATIC int 1212 _phy_54880_ieee_duplex_set(int unit, soc_port_t port, int duplex) 1213 { 1214 phy_ctrl_t *pc; 1215 1216 pc = EXT_PHY_SW_STATE(unit, port); 1217 1218 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1219 (_SW2IEEE(unit, pc)); 1220 1221 SOC_IF_ERROR_RETURN 1222 (phy_fe_ge_duplex_set(unit, port, duplex)); 1223 pc->copper.force_duplex = duplex; 1224 1225 return SOC_E_NONE; 1226 } 1227 1228 STATIC int 1229 phy_54880_duplex_set(int unit, soc_port_t port, int duplex) 1230 { 1231 phy_ctrl_t *pc; 1232 1233 pc = EXT_PHY_SW_STATE(unit, port); 1234 1235 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1236 (_SW2IEEE(unit, pc)); 1237 1238 if (PHY_IEEE_MODE(unit, port)) { 1239 SOC_IF_ERROR_RETURN 1240 (_phy_54880_ieee_duplex_set(unit, port, duplex)); 1241 } else { 1242 if ( !duplex ) { 1243 return SOC_E_CONFIG; 1244 } 1245 } 1246 1247 return SOC_E_NONE; 1248 } 1249 1250 /* 1251 * Function: 1252 * phy_54880_duplex_get 1253 * Purpose: 1254 * Get the current operating duplex mode. If autoneg is enabled, 1255 * then operating mode is returned, otherwise forced mode is returned. 1256 * Parameters: 1257 * unit - StrataSwitch unit #. 1258 * port - StrataSwitch port #. 1259 * duplex - (OUT) Boolean, true indicates full duplex, false 1260 * indicates half. 1261 * Returns: 1262 * SOC_E_XXX 1263 * Notes: 1264 * The duplex is retrieved for the ACTIVE medium. 1265 * No synchronization performed at this level. Autonegotiation is 1266 * not manipulated. 1267 */ 1268 1269 STATIC int 1270 phy_54880_duplex_get(int unit, soc_port_t port, int *duplex) 1271 { 1272 phy_ctrl_t *pc; 1273 1274 pc = EXT_PHY_SW_STATE(unit, port); 1275 1276 if (PHY_IEEE_MODE(unit, port)) { 1277 1278 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1279 (_SW2IEEE(unit, pc)); 1280 1281 SOC_IF_ERROR_RETURN 1282 (phy_fe_ge_duplex_get(unit, port, duplex)); 1283 } else { 1284 *duplex = TRUE; 1285 } 1286 1287 return SOC_E_NONE; 1288 } 1289 1290 int 1291 _phy_54880_br_speed_set(int unit, soc_port_t port, int speed) 1292 { 1293 uint16 lre_ctrl; 1294 phy_ctrl_t *pc; 1295 1296 if (speed == 0) { 1297 return SOC_E_NONE; 1298 } 1299 1300 pc = EXT_PHY_SW_STATE(unit, port); 1301 1302 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1303 (_SW2BR(unit, pc)); 1304 1305 SOC_IF_ERROR_RETURN 1306 (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl)); 1307 1308 lre_ctrl &= ~LRE_CTRL_SS_MASK; 1309 switch(speed) { 1310 case 10: 1311 lre_ctrl |= LRE_CTRL_SS_10; 1312 break; 1313 case 20: 1314 lre_ctrl |= LRE_CTRL_SS_20; 1315 break; 1316 case 25: 1317 lre_ctrl |= LRE_CTRL_SS_25; 1318 break; 1319 case 33: 1320 lre_ctrl |= LRE_CTRL_SS_33; 1321 break; 1322 case 50: 1323 lre_ctrl |= LRE_CTRL_SS_50; 1324 break; 1325 case 100: 1326 lre_ctrl |= LRE_CTRL_SS_100; 1327 break; 1328 default: 1329 return(SOC_E_CONFIG); 1330 } 1331 1332 SOC_IF_ERROR_RETURN 1333 (WRITE_PHY54880_LRE_CTRLr(unit, pc, lre_ctrl)); 1334 1335 return(SOC_E_NONE); 1336 } 1337 1338 1339 /* 1340 * Function: 1341 * phy_54880_ieee_speed_set 1342 * Purpose: 1343 * Set the current operating speed (forced). 1344 * Parameters: 1345 * unit - StrataSwitch unit #. 1346 * port - StrataSwitch port #. 1347 * speed - Requested speed. 1348 * Returns: 1349 * SOC_E_XXX 1350 * Notes: 1351 * The speed is set only for the IEEE mode. 1352 */ 1353 1354 STATIC int 1355 _phy_54880_ieee_speed_set(int unit, soc_port_t port, int speed) 1356 { 1357 phy_ctrl_t *pc; 1358 1359 pc = EXT_PHY_SW_STATE(unit, port); 1360 1361 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1362 (_SW2IEEE(unit, pc)); 1363 1364 SOC_IF_ERROR_RETURN 1365 (phy_fe_ge_speed_set(unit, port, speed)); 1366 1367 return SOC_E_NONE; 1368 } 1369 1370 STATIC int 1371 phy_54880_speed_set(int unit, soc_port_t port, int speed) 1372 { 1373 phy_ctrl_t *pc; 1374 phy_br_config_t *br_config; 1375 1376 pc = EXT_PHY_SW_STATE(unit, port); 1377 br_config = (phy_br_config_t *) &pc->fiber; 1378 1379 if (PHY_IEEE_MODE(unit, port)) { 1380 SOC_IF_ERROR_RETURN 1381 (_phy_54880_ieee_speed_set(unit, port, speed)); 1382 } else { 1383 SOC_IF_ERROR_RETURN 1384 (_phy_54880_br_speed_set(unit, port, speed)); 1385 if (br_config->force_pairs == 0) { 1386 SOC_IF_ERROR_RETURN 1387 (_phy_54880_br_pairs_set(unit, port, (speed==100) ? 4 : 2)); 1388 } 1389 } 1390 1391 return SOC_E_NONE; 1392 } 1393 1394 1395 1396 int 1397 _phy_54880_br_speed_get(int unit, soc_port_t port, int *speed) 1398 { 1399 int rv; 1400 uint16 lre_ctrl, lre_stat, br_lds_scan; 1401 phy_ctrl_t *pc; 1402 1403 pc = EXT_PHY_SW_STATE(unit, port); 1404 1405 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1406 (_SW2BR(unit, pc)); 1407 1408 SOC_IF_ERROR_RETURN 1409 (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl)); 1410 1411 if (lre_ctrl & LRE_CTRL_LDSE) { /* LDS enabled */ 1412 SOC_IF_ERROR_RETURN 1413 (READ_PHY54880_LRE_STATr(unit, pc, &lre_stat)); 1414 if (!(lre_stat & LRE_STAT_LDS_DONE)) { /* LDS NOT complete */ 1415 *speed = 0; 1416 rv = SOC_E_NONE; 1417 } else { 1418 /* Examine the BR EXP regs */ 1419 SOC_IF_ERROR_RETURN 1420 (READ_PHY54880_EXP_BR_LDS_SCANr(unit, pc, &br_lds_scan)); 1421 1422 switch(br_lds_scan & PHY54880_EXP_BR_LDS_SCAN_SS_MASK) { 1423 1424 case PHY54880_EXP_BR_LDS_SCAN_SS_10: 1425 *speed = 10; 1426 break; 1427 case PHY54880_EXP_BR_LDS_SCAN_SS_20: 1428 *speed = 20; 1429 break; 1430 case PHY54880_EXP_BR_LDS_SCAN_SS_25: 1431 *speed = 25; 1432 break; 1433 case PHY54880_EXP_BR_LDS_SCAN_SS_33: 1434 *speed = 33; 1435 break; 1436 case PHY54880_EXP_BR_LDS_SCAN_SS_50: 1437 *speed = 50; 1438 break; 1439 case PHY54880_EXP_BR_LDS_SCAN_SS_100: 1440 *speed = 100; 1441 break; 1442 default: 1443 *speed = 0; 1444 break; 1445 } 1446 rv = SOC_E_NONE; 1447 } 1448 } else { /* LDS disabled */ 1449 /* 1450 * Simply pick up the values we force in CTRL register. 1451 */ 1452 switch(lre_ctrl & LRE_CTRL_SS_MASK) { 1453 1454 case LRE_CTRL_SS_10: 1455 *speed = 10; 1456 break; 1457 case LRE_CTRL_SS_20: 1458 *speed = 20; 1459 break; 1460 case LRE_CTRL_SS_25: 1461 *speed = 25; 1462 break; 1463 case LRE_CTRL_SS_33: 1464 *speed = 33; 1465 break; 1466 case LRE_CTRL_SS_50: 1467 *speed = 50; 1468 break; 1469 case LRE_CTRL_SS_100: 1470 *speed = 100; 1471 break; 1472 default: 1473 *speed = 0; 1474 break; 1475 } 1476 rv = SOC_E_NONE; 1477 } 1478 1479 return(rv); 1480 } 1481 1482 /* 1483 * Function: 1484 * phy_54880_speed_get 1485 * Purpose: 1486 * Get the current operating speed for a 54880 device. 1487 * Parameters: 1488 * unit - StrataSwitch unit #. 1489 * port - StrataSwitch port #. 1490 * duplex - (OUT) Boolean, true indicates full duplex, false 1491 * indicates half. 1492 * Returns: 1493 * SOC_E_XXX 1494 * Notes: 1495 * The speed is retrieved for the ACTIVE medium. 1496 */ 1497 1498 STATIC int 1499 phy_54880_speed_get(int unit, soc_port_t port, int *speed) 1500 { 1501 phy_ctrl_t *pc; 1502 1503 pc = EXT_PHY_SW_STATE(unit, port); 1504 1505 if (PHY_IEEE_MODE(unit, port)) { 1506 1507 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1508 (_SW2IEEE(unit, pc)); 1509 1510 SOC_IF_ERROR_RETURN(phy_fe_ge_speed_get(unit, port, speed)); 1511 } else { 1512 SOC_IF_ERROR_RETURN(_phy_54880_br_speed_get(unit, port, speed)); 1513 } 1514 1515 return SOC_E_NONE; 1516 } 1517 1518 STATIC int 1519 _phy_54880_br_pairs_set(int unit, soc_port_t port, int pairs) 1520 { 1521 uint16 lre_ctrl; 1522 phy_ctrl_t *pc; 1523 1524 pc = EXT_PHY_SW_STATE(unit, port); 1525 1526 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1527 (_SW2BR(unit, pc)); 1528 1529 SOC_IF_ERROR_RETURN 1530 (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl)); 1531 1532 lre_ctrl &= ~LRE_CTRL_PS_MASK; 1533 switch(pairs) { 1534 case 1: 1535 lre_ctrl |= LRE_CTRL_PS_1P; 1536 break; 1537 case 2: 1538 lre_ctrl |= LRE_CTRL_PS_2P; 1539 break; 1540 case 4: 1541 lre_ctrl |= LRE_CTRL_PS_4P; 1542 break; 1543 default: 1544 return(SOC_E_CONFIG); 1545 } 1546 1547 SOC_IF_ERROR_RETURN 1548 (WRITE_PHY54880_LRE_CTRLr(unit, pc, lre_ctrl)); 1549 1550 return(SOC_E_NONE); 1551 } 1552 1553 STATIC int 1554 _phy_54880_br_pairs_get(int unit, soc_port_t port, int *pairs) 1555 { 1556 int rv; 1557 uint16 lre_ctrl, lre_stat, lds_exp; 1558 phy_ctrl_t *pc; 1559 1560 pc = EXT_PHY_SW_STATE(unit, port); 1561 1562 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1563 (_SW2BR(unit, pc)); 1564 1565 SOC_IF_ERROR_RETURN 1566 (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl)); 1567 SOC_IF_ERROR_RETURN 1568 (READ_PHY54880_LRE_STATr(unit, pc, &lre_stat)); 1569 1570 if (lre_ctrl & LRE_CTRL_LDSE) { /* LDS enabled */ 1571 if (!(lre_stat & LRE_STAT_LDS_DONE)) { /* LDS NOT complete */ 1572 *pairs = 0; 1573 rv = SOC_E_NONE; 1574 } else { 1575 /* Examine the LDS EXP reg (0xa) */ 1576 SOC_IF_ERROR_RETURN 1577 (READ_PHY54880_LDS_EXPr(unit, pc, &lds_exp)); 1578 1579 switch(lds_exp & (0x3U<<12)) { 1580 case 0x0: 1581 *pairs = 1; 1582 break; 1583 case (0x1<<12): 1584 *pairs = 2; 1585 break; 1586 case (0x2<<12): 1587 *pairs = 4; 1588 break; 1589 default: 1590 *pairs = 0; 1591 break; 1592 } 1593 rv = SOC_E_NONE; 1594 } 1595 } else { /* LDS disabled */ 1596 1597 switch(lre_ctrl & LRE_CTRL_PS_MASK) { 1598 case LRE_CTRL_PS_1P: 1599 *pairs = 1; 1600 break; 1601 case LRE_CTRL_PS_2P: 1602 *pairs = 2; 1603 break; 1604 case LRE_CTRL_PS_4P: 1605 *pairs = 4; 1606 break; 1607 default: 1608 *pairs = 0; 1609 break; 1610 } 1611 rv = SOC_E_NONE; 1612 } 1613 1614 return(rv); 1615 } 1616 1617 STATIC int 1618 _phy_54880_br_enable_set(int unit, soc_port_t port, int enable) 1619 { 1620 phy_ctrl_t *pc; 1621 1622 pc = EXT_PHY_SW_STATE(unit, port); 1623 1624 if( PHY_IS_BCM54811(pc) ) { 1625 SOC_IF_ERROR_RETURN 1626 (MODIFY_PHY54811_EXP_BR_LRE_MISC_CTRLr(unit, pc, (enable) ? (1U<<0):0, (1U<<0))); 1627 } else { 1628 SOC_IF_ERROR_RETURN 1629 (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL1r(unit, pc, (enable) ? (1U<<0):0, (1U<<0))); 1630 } 1631 1632 return SOC_E_NONE; 1633 1634 } 1635 1636 STATIC int 1637 _phy_54880_br_enable_get(int unit, soc_port_t port, int *enable) 1638 { 1639 phy_ctrl_t *pc; 1640 uint16 lre_misc_ctrl; 1641 1642 pc = EXT_PHY_SW_STATE(unit, port); 1643 1644 if( PHY_IS_BCM54811(pc)) { 1645 SOC_IF_ERROR_RETURN 1646 (READ_PHY54811_EXP_BR_LRE_MISC_CTRLr(unit, pc, &lre_misc_ctrl)); 1647 } else { 1648 SOC_IF_ERROR_RETURN 1649 (READ_PHY54880_EXP_BR_LRE_MISC_CTRL1r(unit, pc, &lre_misc_ctrl)); 1650 } 1651 1652 *enable = (lre_misc_ctrl & (1U<<0)) ? TRUE: FALSE; 1653 1654 return SOC_E_NONE; 1655 } 1656 1657 STATIC int 1658 _phy_54880_br_active_get(int unit, soc_port_t port, int *active) 1659 { 1660 *active = (PHY_IEEE_MODE(unit, port)) ? FALSE: TRUE; 1661 1662 return SOC_E_NONE; 1663 } 1664 1665 STATIC int 1666 _phy_54880_br_gain_set(int unit, soc_port_t port, int gain) 1667 { 1668 phy_ctrl_t *pc; 1669 1670 pc = EXT_PHY_SW_STATE(unit, port); 1671 1672 switch(gain) { 1673 case 0: 1674 case 1: 1675 case 2: 1676 case 4: 1677 if( PHY_IS_BCM54811(pc) ) { 1678 SOC_IF_ERROR_RETURN 1679 (MODIFY_PHY54811_EXP_BR_LRE_MISC_CTRL2r(unit, pc, (gain&0x7)<<9, 0x7<<9)); 1680 } else { 1681 SOC_IF_ERROR_RETURN 1682 (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL2r(unit, pc, (gain&0x7)<<9, 0x7<<9)); 1683 } 1684 break; 1685 default: 1686 return(SOC_E_CONFIG); 1687 } 1688 1689 return(SOC_E_NONE); 1690 } 1691 1692 STATIC int 1693 _phy_54880_br_gain_get(int unit, soc_port_t port, int *gain) 1694 { 1695 phy_ctrl_t *pc; 1696 uint16 temp; 1697 1698 pc = EXT_PHY_SW_STATE(unit, port); 1699 1700 if( PHY_IS_BCM54811(pc) ) { 1701 SOC_IF_ERROR_RETURN 1702 (READ_PHY54811_EXP_BR_LRE_MISC_CTRL2r(unit, pc, &temp)); 1703 } else { 1704 SOC_IF_ERROR_RETURN 1705 (READ_PHY54880_EXP_BR_LRE_MISC_CTRL2r(unit, pc, &temp)); 1706 } 1707 1708 *gain = (temp>>9) & 0x7; 1709 1710 return(SOC_E_NONE); 1711 } 1712 1713 1714 /* 1715 * Function: 1716 * phy_54880_master_set 1717 * Purpose: 1718 * Set the current master mode 1719 * Parameters: 1720 * unit - StrataSwitch unit #. 1721 * port - StrataSwitch port #. 1722 * master - SOC_PORT_MS_* 1723 * Returns: 1724 * SOC_E_XXX 1725 * Notes: 1726 * The master mode is set only for the ACTIVE medium. 1727 */ 1728 STATIC int 1729 _phy_54880_br_master_set(int unit, soc_port_t port, int master) 1730 { 1731 uint16 lre_ctrl; 1732 phy_ctrl_t *pc; 1733 1734 pc = EXT_PHY_SW_STATE(unit, port); 1735 1736 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1737 (_SW2BR(unit, pc)); 1738 1739 SOC_IF_ERROR_RETURN 1740 (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl)); 1741 1742 switch (master) { 1743 case SOC_PORT_MS_SLAVE: 1744 lre_ctrl &= ~LRE_CTRL_MS; 1745 break; 1746 case SOC_PORT_MS_MASTER: 1747 lre_ctrl |= LRE_CTRL_MS; 1748 break; 1749 case SOC_PORT_MS_AUTO: 1750 return(SOC_E_NONE); 1751 default: 1752 return(SOC_E_CONFIG); 1753 } 1754 1755 SOC_IF_ERROR_RETURN 1756 (WRITE_PHY54880_LRE_CTRLr(unit, pc, lre_ctrl)); 1757 1758 return(SOC_E_NONE); 1759 } 1760 1761 1762 STATIC int 1763 _phy_54880_ieee_master_set(int unit, soc_port_t port, int master) 1764 { 1765 phy_ctrl_t *pc; 1766 1767 pc = EXT_PHY_SW_STATE(unit, port); 1768 1769 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1770 (_SW2IEEE(unit, pc)); 1771 1772 SOC_IF_ERROR_RETURN 1773 (phy_fe_ge_master_set(unit, port, master)); 1774 1775 pc->copper.master = master; 1776 1777 return SOC_E_NONE; 1778 } 1779 1780 STATIC int 1781 phy_54880_master_set(int unit, soc_port_t port, int master) 1782 { 1783 if (PHY_IEEE_MODE(unit, port)) { 1784 SOC_IF_ERROR_RETURN 1785 (_phy_54880_ieee_master_set(unit, port, master)); 1786 } else { 1787 SOC_IF_ERROR_RETURN 1788 (_phy_54880_br_master_set(unit, port, master)); 1789 } 1790 1791 return SOC_E_NONE; 1792 } 1793 1794 1795 /* 1796 * Function: 1797 * phy_54880_master_get 1798 * Purpose: 1799 * Get the current master mode for a 54880 device. 1800 * Parameters: 1801 * unit - StrataSwitch unit #. 1802 * port - StrataSwitch port #. 1803 * master - (OUT) SOC_PORT_MS_* 1804 * Returns: 1805 * SOC_E_XXX 1806 * Notes: 1807 * The master mode is retrieved for the ACTIVE medium. 1808 */ 1809 STATIC int 1810 _phy_54880_br_master_get(int unit, soc_port_t port, int *master) 1811 { 1812 uint16 lre_ctrl, lre_stat, lds_exp; 1813 phy_ctrl_t *pc; 1814 1815 pc = EXT_PHY_SW_STATE(unit, port); 1816 1817 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1818 (_SW2BR(unit, pc)); 1819 1820 SOC_IF_ERROR_RETURN 1821 (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl)); 1822 1823 if (lre_ctrl & LRE_CTRL_LDSE) { 1824 SOC_IF_ERROR_RETURN 1825 (READ_PHY54880_LRE_STATr(unit, pc, &lre_stat)); 1826 if (!(lre_stat & LRE_STAT_LDS_DONE)) { /* LDS NOT complete */ 1827 *master = SOC_PORT_MS_NONE; 1828 } else { 1829 /* Examine the LDS EXP reg (0xa) */ 1830 SOC_IF_ERROR_RETURN 1831 (READ_PHY54880_LDS_EXPr(unit, pc, &lds_exp)); 1832 *master = (lds_exp & (1U<<14)) ? SOC_PORT_MS_MASTER : SOC_PORT_MS_SLAVE; 1833 } 1834 } else if (lre_ctrl & LRE_CTRL_MS) { 1835 *master = SOC_PORT_MS_MASTER; 1836 } else { 1837 *master = SOC_PORT_MS_SLAVE; 1838 } 1839 1840 return SOC_E_NONE; 1841 } 1842 1843 STATIC int 1844 phy_54880_master_get(int unit, soc_port_t port, int *master) 1845 { 1846 phy_ctrl_t *pc; 1847 1848 pc = EXT_PHY_SW_STATE(unit, port); 1849 1850 if (PHY_IEEE_MODE(unit, port)) { 1851 1852 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1853 (_SW2IEEE(unit, pc)); 1854 1855 SOC_IF_ERROR_RETURN 1856 (phy_fe_ge_master_get(unit, port, master)); 1857 } else { 1858 SOC_IF_ERROR_RETURN 1859 (_phy_54880_br_master_get(unit, port, master)); 1860 } 1861 1862 return SOC_E_NONE; 1863 } 1864 1865 1866 STATIC int 1867 _phy_54880_br_autoneg_set(int unit, soc_port_t port, int an) 1868 { 1869 phy_ctrl_t *pc; 1870 1871 pc = EXT_PHY_SW_STATE(unit, port); 1872 1873 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1874 (_SW2BR(unit, pc)); 1875 1876 SOC_IF_ERROR_RETURN 1877 (MODIFY_PHY54880_LRE_CTRLr(unit, pc, 1878 an ? LRE_CTRL_LDSE|LRE_CTRL_RLDS : 0, 1879 LRE_CTRL_LDSE|LRE_CTRL_RLDS)); 1880 1881 return SOC_E_NONE; 1882 } 1883 1884 /* 1885 * Function: 1886 * phy_54880_autoneg_set 1887 * Purpose: 1888 * Enable or disable auto-negotiation on the specified port. 1889 * Parameters: 1890 * unit - StrataSwitch unit #. 1891 * port - StrataSwitch port #. 1892 * autoneg - Boolean, if true, auto-negotiation is enabled 1893 * (and/or restarted). If false, autonegotiation is disabled. 1894 * Returns: 1895 * SOC_E_XXX 1896 * Notes: 1897 * The autoneg mode is set only for the ACTIVE medium. 1898 */ 1899 1900 STATIC int 1901 _phy_54880_ieee_autoneg_set(int unit, soc_port_t port, int autoneg) 1902 { 1903 int rv; 1904 phy_ctrl_t *pc; 1905 1906 pc = EXT_PHY_SW_STATE(unit, port); 1907 rv = SOC_E_NONE; 1908 1909 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1910 (_SW2IEEE(unit, pc)); 1911 1912 /* Set auto-neg on PHY */ 1913 rv = phy_fe_ge_an_set(unit, port, autoneg); 1914 if (SOC_SUCCESS(rv)) { 1915 pc->copper.autoneg_enable = autoneg ? 1 : 0; 1916 } 1917 1918 return rv; 1919 } 1920 1921 STATIC int 1922 phy_54880_autoneg_set(int unit, soc_port_t port, int autoneg) 1923 { 1924 int rv = SOC_E_NONE; 1925 1926 if (PHY_IEEE_MODE(unit, port)) { 1927 SOC_IF_ERROR_RETURN 1928 (_phy_54880_ieee_autoneg_set(unit, port, autoneg)); 1929 } else { 1930 SOC_IF_ERROR_RETURN 1931 (_phy_54880_br_autoneg_set(unit, port, autoneg)); 1932 } 1933 1934 return rv; 1935 } 1936 1937 STATIC int 1938 _phy_54880_br_autoneg_get(int unit, soc_port_t port, int *an, int *an_done) 1939 { 1940 phy_ctrl_t *pc; 1941 uint16 lre_ctrl, lre_stat; 1942 1943 pc = EXT_PHY_SW_STATE(unit, port); 1944 1945 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1946 (_SW2BR(unit, pc)); 1947 1948 SOC_IF_ERROR_RETURN 1949 (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl)); 1950 SOC_IF_ERROR_RETURN 1951 (READ_PHY54880_LRE_STATr(unit, pc, &lre_stat)); 1952 1953 *an = (lre_ctrl & LRE_CTRL_LDSE) ? TRUE : FALSE; 1954 1955 if ( an_done ) { 1956 *an_done = (lre_stat & LRE_STAT_LDS_DONE) ? TRUE : FALSE; 1957 } 1958 1959 return SOC_E_NONE; 1960 } 1961 1962 /* 1963 * Function: 1964 * phy_54880_autoneg_get 1965 * Purpose: 1966 * Get the current auto-negotiation status (enabled/busy). 1967 * Parameters: 1968 * unit - StrataSwitch unit #. 1969 * port - StrataSwitch port #. 1970 * autoneg - (OUT) if true, auto-negotiation is enabled. 1971 * autoneg_done - (OUT) if true, auto-negotiation is complete. This 1972 * value is undefined if autoneg == FALSE. 1973 * Returns: 1974 * SOC_E_XXX 1975 * Notes: 1976 * The autoneg mode is retrieved for the ACTIVE medium. 1977 */ 1978 1979 STATIC int 1980 phy_54880_autoneg_get(int unit, soc_port_t port, 1981 int *autoneg, int *autoneg_done) 1982 { 1983 phy_ctrl_t *pc; 1984 1985 pc = EXT_PHY_SW_STATE(unit, port); 1986 1987 if (PHY_IEEE_MODE(unit, port)) { 1988 1989 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 1990 (_SW2IEEE(unit, pc)); 1991 1992 SOC_IF_ERROR_RETURN 1993 (phy_fe_ge_an_get(unit, port, autoneg, autoneg_done)); 1994 } else { 1995 SOC_IF_ERROR_RETURN 1996 (_phy_54880_br_autoneg_get(unit, port, autoneg, autoneg_done)); 1997 } 1998 1999 return SOC_E_NONE; 2000 } 2001 2002 /* 2003 * Function: 2004 * phy_54880_ability_advert_set 2005 * Purpose: 2006 * Set the current advertisement for auto-negotiation. 2007 * Parameters: 2008 * unit - StrataSwitch unit #. 2009 * port - StrataSwitch port #. 2010 * ability - Port ability indicating supported options/speeds. 2011 * Returns: 2012 * SOC_E_XXX 2013 */ 2014 2015 STATIC int 2016 _phy_54880_ieee_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability) 2017 { 2018 phy_ctrl_t *pc; 2019 2020 pc = EXT_PHY_SW_STATE(unit, port); 2021 2022 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 2023 (_SW2IEEE(unit, pc)); 2024 2025 SOC_IF_ERROR_RETURN 2026 (phy_fe_ge_ability_advert_set(unit, port, ability)); 2027 2028 return SOC_E_NONE; 2029 } 2030 2031 STATIC int 2032 _phy_54880_br_ability_advert_set(int unit, soc_port_t port, uint32 ability) 2033 { 2034 phy_ctrl_t *pc; 2035 uint16 lds_adv; 2036 2037 pc = EXT_PHY_SW_STATE(unit, port); 2038 2039 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 2040 (_SW2BR(unit, pc)); 2041 2042 ability &= LONGREACH_ABILITY_ALL(pc); 2043 2044 lds_adv = 0; 2045 2046 if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR) { 2047 lds_adv |= LDS_ADVA_1_10; 2048 } 2049 if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR) { 2050 lds_adv |= LDS_ADVA_2_10; 2051 } 2052 if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_1PAIR) { 2053 lds_adv |= LDS_ADVA_1_20; 2054 } 2055 if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_2PAIR) { 2056 lds_adv |= LDS_ADVA_2_20; 2057 } 2058 if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_1PAIR) { 2059 lds_adv |= LDS_ADVA_1_25; 2060 } 2061 if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_2PAIR) { 2062 lds_adv |= LDS_ADVA_2_25; 2063 } 2064 if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_1PAIR) { 2065 lds_adv |= LDS_ADVA_1_33; 2066 } 2067 if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_2PAIR) { 2068 lds_adv |= LDS_ADVA_2_33; 2069 } 2070 if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_1PAIR) { 2071 lds_adv |= LDS_ADVA_1_50; 2072 } 2073 if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_2PAIR) { 2074 lds_adv |= LDS_ADVA_2_50; 2075 } 2076 if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR) { 2077 lds_adv |= LDS_ADVA_1_100; 2078 } 2079 if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR) { 2080 lds_adv |= LDS_ADVA_2_100; 2081 } 2082 if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR) { 2083 lds_adv |= LDS_ADVA_4_100; 2084 } 2085 2086 switch (ability & (SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX | 2087 SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX)) { 2088 2089 case SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX: 2090 lds_adv |= LDS_ADVA_ASYM_PAUSE; 2091 break; 2092 case SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX: 2093 lds_adv |= LDS_ADVA_PAUSE | LDS_ADVA_ASYM_PAUSE; 2094 break; 2095 case SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX | 2096 SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX: 2097 lds_adv |= LDS_ADVA_PAUSE; 2098 break; 2099 } 2100 2101 SOC_IF_ERROR_RETURN 2102 (MODIFY_PHY54880_LDS_ADVAr(unit, pc, lds_adv, LDS_ADVA_MASK(pc))); 2103 2104 return SOC_E_NONE; 2105 } 2106 2107 STATIC int 2108 _phy_54880_br_ability_advert_std_set(int unit, soc_port_t port, soc_port_ability_t *ability) 2109 { 2110 uint32 adv_ability = 0; 2111 2112 if (ability->speed_full_duplex & SOC_PA_SPEED_10MB) { 2113 adv_ability |= LONGREACH_ABILITY_10M; 2114 } 2115 if (ability->speed_full_duplex & SOC_PA_SPEED_100MB) { 2116 adv_ability |= LONGREACH_ABILITY_100M; 2117 } 2118 2119 if (ability->pause & SOC_PA_PAUSE_TX) { 2120 adv_ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX; 2121 } 2122 if (ability->pause & SOC_PA_PAUSE_RX) { 2123 adv_ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX; 2124 } 2125 2126 SOC_IF_ERROR_RETURN 2127 (_phy_54880_br_ability_advert_set(unit, port, adv_ability)); 2128 2129 return SOC_E_NONE; 2130 } 2131 2132 STATIC int 2133 phy_54880_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability) 2134 { 2135 2136 if (PHY_IEEE_MODE(unit, port)) { 2137 SOC_IF_ERROR_RETURN 2138 (_phy_54880_ieee_ability_advert_set(unit, port, ability)); 2139 } else { 2140 SOC_IF_ERROR_RETURN 2141 (_phy_54880_br_ability_advert_std_set(unit, port, ability)); 2142 } 2143 2144 return SOC_E_NONE; 2145 } 2146 2147 2148 /* 2149 * Function: 2150 * phy_54880_ability_advert_get 2151 * Purpose: 2152 * Get the current advertisement for auto-negotiation. 2153 * Parameters: 2154 * unit - StrataSwitch unit #. 2155 * port - StrataSwitch port #. 2156 * ability - Port ability indicating supported options/speeds. 2157 * Returns: 2158 * SOC_E_XXX 2159 * Notes: 2160 * The advertisement is retrieved for the ACTIVE medium. 2161 * No synchronization performed at this level. 2162 */ 2163 2164 STATIC int 2165 _phy_54880_ieee_ability_advert_get(int unit, soc_port_t port, soc_port_ability_t *ability) 2166 { 2167 phy_ctrl_t *pc; 2168 2169 pc = EXT_PHY_SW_STATE(unit, port); 2170 2171 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 2172 (_SW2IEEE(unit, pc)); 2173 2174 SOC_IF_ERROR_RETURN 2175 (phy_fe_ge_ability_advert_get(unit, port, ability)); 2176 2177 return SOC_E_NONE; 2178 } 2179 2180 STATIC int 2181 _phy_54880_br_ability_advert_get(int unit, soc_port_t port, uint32 *ability) 2182 { 2183 phy_ctrl_t *pc; 2184 uint16 lds_adv; 2185 2186 pc = EXT_PHY_SW_STATE(unit, port); 2187 2188 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 2189 (_SW2BR(unit, pc)); 2190 2191 SOC_IF_ERROR_RETURN 2192 (READ_PHY54880_LDS_ADVAr(unit, pc, &lds_adv)); 2193 2194 *ability = 0; 2195 2196 if (lds_adv & LDS_ADVA_1_10) { 2197 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR; 2198 } 2199 if (lds_adv & LDS_ADVA_2_10) { 2200 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR; 2201 } 2202 if (lds_adv & LDS_ADVA_1_20) { 2203 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_1PAIR; 2204 } 2205 if (lds_adv & LDS_ADVA_2_20) { 2206 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_2PAIR; 2207 } 2208 if (lds_adv & LDS_ADVA_1_25) { 2209 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_1PAIR; 2210 } 2211 if (lds_adv & LDS_ADVA_2_25) { 2212 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_2PAIR; 2213 } 2214 if (lds_adv & LDS_ADVA_1_33) { 2215 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_1PAIR; 2216 } 2217 if (lds_adv & LDS_ADVA_2_33) { 2218 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_2PAIR; 2219 } 2220 if (lds_adv & LDS_ADVA_1_50) { 2221 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_1PAIR; 2222 } 2223 if (lds_adv & LDS_ADVA_2_50) { 2224 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_2PAIR; 2225 } 2226 if (lds_adv & LDS_ADVA_1_100) { 2227 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR; 2228 } 2229 if (lds_adv & LDS_ADVA_2_100) { 2230 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR; 2231 } 2232 if (lds_adv & LDS_ADVA_4_100) { 2233 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR; 2234 } 2235 2236 switch (lds_adv & (LDS_ADVA_PAUSE | LDS_ADVA_ASYM_PAUSE)) { 2237 case LDS_ADVA_PAUSE: 2238 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX | 2239 SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX; 2240 break; 2241 case LDS_ADVA_ASYM_PAUSE: 2242 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX; 2243 break; 2244 case LDS_ADVA_PAUSE | LDS_ADVA_ASYM_PAUSE: 2245 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX; 2246 break; 2247 } 2248 2249 return SOC_E_NONE; 2250 } 2251 2252 STATIC int 2253 _phy_54880_br_ability_advert_std_get(int unit, soc_port_t port, soc_port_ability_t *ability) 2254 { 2255 uint32 adv_ability; 2256 2257 sal_memset(ability, 0, sizeof(*ability)); 2258 adv_ability = 0; 2259 2260 SOC_IF_ERROR_RETURN 2261 (_phy_54880_br_ability_advert_get(unit, port, &adv_ability)); 2262 2263 if (adv_ability & LONGREACH_ABILITY_10M) { 2264 ability->speed_full_duplex |= SOC_PA_SPEED_10MB; 2265 } 2266 if (adv_ability & LONGREACH_ABILITY_100M) { 2267 ability->speed_full_duplex |= SOC_PA_SPEED_100MB; 2268 } 2269 2270 if (adv_ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX) { 2271 ability->pause |= SOC_PA_PAUSE_TX; 2272 } 2273 2274 if (adv_ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX) { 2275 ability->pause |= SOC_PA_PAUSE_RX; 2276 } 2277 2278 return SOC_E_NONE; 2279 } 2280 2281 2282 STATIC int 2283 phy_54880_ability_advert_get(int unit, soc_port_t port, soc_port_ability_t *ability) 2284 { 2285 if (NULL == ability) { 2286 return (SOC_E_PARAM); 2287 } 2288 2289 if (PHY_IEEE_MODE(unit, port)) { 2290 SOC_IF_ERROR_RETURN 2291 (_phy_54880_ieee_ability_advert_get(unit, port, ability)); 2292 } else { 2293 SOC_IF_ERROR_RETURN 2294 (_phy_54880_br_ability_advert_std_get(unit, port, ability)); 2295 } 2296 2297 return SOC_E_NONE; 2298 } 2299 2300 /* 2301 * Function: 2302 * phy_54880_ability_remote_get 2303 * Purpose: 2304 * Get partners current advertisement for auto-negotiation. 2305 * Parameters: 2306 * unit - StrataSwitch unit #. 2307 * port - StrataSwitch port #. 2308 * ability - Port ability indicating supported options/speeds. 2309 * Returns: 2310 * SOC_E_XXX 2311 * Notes: 2312 * The remote advertisement is retrieved for the ACTIVE medium. 2313 * No synchronization performed at this level. If Autonegotiation is 2314 * disabled or in progress, this routine will return an error. 2315 */ 2316 2317 STATIC int 2318 _phy_54880_ieee_ability_remote_get(int unit, soc_port_t port, soc_port_ability_t *ability) 2319 { 2320 phy_ctrl_t *pc; 2321 2322 pc = EXT_PHY_SW_STATE(unit, port); 2323 2324 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 2325 (_SW2IEEE(unit, pc)); 2326 2327 SOC_IF_ERROR_RETURN 2328 (phy_fe_ge_ability_remote_get(unit, port, ability)); 2329 2330 return SOC_E_NONE; 2331 } 2332 2333 STATIC int 2334 _phy_54880_br_ability_remote_get(int unit, soc_port_t port, uint32 *ability) 2335 { 2336 phy_ctrl_t *pc; 2337 uint16 lds_adv; 2338 2339 pc = EXT_PHY_SW_STATE(unit, port); 2340 2341 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 2342 (_SW2BR(unit, pc)); 2343 2344 SOC_IF_ERROR_RETURN 2345 (READ_PHY54880_LDS_LPABr(unit, pc, &lds_adv)); 2346 2347 *ability = 0; 2348 2349 if (lds_adv & LDS_ADVA_1_10) { 2350 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR; 2351 } 2352 if (lds_adv & LDS_ADVA_2_10) { 2353 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR; 2354 } 2355 if (lds_adv & LDS_ADVA_1_20) { 2356 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_1PAIR; 2357 } 2358 if (lds_adv & LDS_ADVA_2_20) { 2359 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_2PAIR; 2360 } 2361 if (lds_adv & LDS_ADVA_1_25) { 2362 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_1PAIR; 2363 } 2364 if (lds_adv & LDS_ADVA_2_25) { 2365 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_2PAIR; 2366 } 2367 if (lds_adv & LDS_ADVA_1_33) { 2368 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_1PAIR; 2369 } 2370 if (lds_adv & LDS_ADVA_2_33) { 2371 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_2PAIR; 2372 } 2373 if (lds_adv & LDS_ADVA_1_50) { 2374 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_1PAIR; 2375 } 2376 if (lds_adv & LDS_ADVA_2_50) { 2377 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_2PAIR; 2378 } 2379 if (lds_adv & LDS_ADVA_1_100) { 2380 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR; 2381 } 2382 if (lds_adv & LDS_ADVA_2_100) { 2383 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR; 2384 } 2385 if (lds_adv & LDS_ADVA_4_100) { 2386 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR; 2387 } 2388 2389 switch (lds_adv & (LDS_ADVA_PAUSE | LDS_ADVA_ASYM_PAUSE)) { 2390 case LDS_ADVA_PAUSE: 2391 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX | 2392 SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX; 2393 break; 2394 case LDS_ADVA_ASYM_PAUSE: 2395 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX; 2396 break; 2397 case LDS_ADVA_PAUSE | LDS_ADVA_ASYM_PAUSE: 2398 *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX; 2399 break; 2400 } 2401 2402 return SOC_E_NONE; 2403 } 2404 2405 STATIC int 2406 _phy_54880_br_ability_remote_std_get(int unit, soc_port_t port, soc_port_ability_t *ability) 2407 { 2408 2409 uint32 rem_ability; 2410 2411 sal_memset(ability, 0, sizeof(*ability)); 2412 rem_ability = 0; 2413 2414 SOC_IF_ERROR_RETURN 2415 (_phy_54880_br_ability_remote_get(unit, port, &rem_ability)); 2416 2417 if (rem_ability & LONGREACH_ABILITY_10M) { 2418 ability->speed_full_duplex |= SOC_PA_SPEED_10MB; 2419 } 2420 if (rem_ability & LONGREACH_ABILITY_100M) { 2421 ability->speed_full_duplex |= SOC_PA_SPEED_100MB; 2422 } 2423 2424 if (rem_ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX) { 2425 ability->pause |= SOC_PA_PAUSE_TX; 2426 } 2427 2428 if (rem_ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX) { 2429 ability->pause |= SOC_PA_PAUSE_RX; 2430 } 2431 2432 return SOC_E_NONE; 2433 2434 } 2435 2436 STATIC int 2437 phy_54880_ability_remote_get(int unit, soc_port_t port, soc_port_ability_t *ability) 2438 { 2439 if (NULL == ability) { 2440 return (SOC_E_PARAM); 2441 } 2442 2443 if (PHY_IEEE_MODE(unit, port)) { 2444 SOC_IF_ERROR_RETURN 2445 (_phy_54880_ieee_ability_remote_get(unit, port, ability)); 2446 } else { 2447 SOC_IF_ERROR_RETURN 2448 (_phy_54880_br_ability_remote_std_get(unit, port, ability)); 2449 } 2450 2451 return SOC_E_NONE; 2452 } 2453 2454 STATIC int 2455 _phy_54880_ieee_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 2456 { 2457 phy_ctrl_t *pc; 2458 2459 pc = EXT_PHY_SW_STATE(unit, port); 2460 2461 if (PHY_IS_BCM54881(pc)) { 2462 ability->speed_full_duplex = SOC_PA_SPEED_100MB | SOC_PA_SPEED_10MB; 2463 } else { 2464 ability->speed_full_duplex = SOC_PA_SPEED_1000MB |SOC_PA_SPEED_100MB | 2465 SOC_PA_SPEED_10MB; 2466 } 2467 ability->speed_half_duplex = SOC_PA_SPEED_100MB | SOC_PA_SPEED_10MB; 2468 2469 ability->pause = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 2470 ability->interface = SOC_PA_INTF_SGMII; 2471 ability->medium = SOC_PA_MEDIUM_IEEE; 2472 ability->loopback = SOC_PA_LB_PHY; 2473 ability->flags = SOC_PA_AUTONEG; 2474 2475 return SOC_E_NONE; 2476 } 2477 2478 STATIC int 2479 _phy_54880_br_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 2480 { 2481 #if 1 2482 ability->speed_full_duplex = SOC_PA_SPEED_100MB |SOC_PA_SPEED_10MB; 2483 #endif 2484 ability->speed_half_duplex = SOC_PA_ABILITY_NONE; 2485 2486 ability->pause = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 2487 ability->interface = SOC_PA_INTF_SGMII; 2488 ability->medium = SOC_PA_MEDIUM_IEEE; 2489 ability->loopback = SOC_PA_LB_PHY; 2490 ability->flags = SOC_PA_AUTONEG; 2491 2492 return SOC_E_NONE; 2493 } 2494 2495 /* 2496 * Function: 2497 * phy_54880_ability_local_get 2498 * Purpose: 2499 * Get the device's complete abilities. 2500 * Parameters: 2501 * unit - StrataSwitch unit #. 2502 * port - StrataSwitch port #. 2503 * ability - return device's abilities. 2504 * Returns: 2505 * SOC_E_XXX 2506 */ 2507 2508 STATIC int 2509 phy_54880_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 2510 { 2511 if (NULL == ability) { 2512 return (SOC_E_PARAM); 2513 } 2514 2515 if (PHY_IEEE_MODE(unit, port)) { 2516 SOC_IF_ERROR_RETURN 2517 (_phy_54880_ieee_ability_local_get(unit, port, ability)); 2518 } else { 2519 SOC_IF_ERROR_RETURN 2520 (_phy_54880_br_ability_local_get(unit, port, ability)); 2521 } 2522 2523 return SOC_E_NONE; 2524 } 2525 2526 STATIC int 2527 _phy_54880_br_ability_current_get(int unit, soc_port_t port, uint32 *ability) 2528 { 2529 uint16 lre_ctrl, lre_stat; 2530 phy_ctrl_t *pc; 2531 uint32 ability_local, ability_remote; 2532 int speed, pairs; 2533 2534 pc = EXT_PHY_SW_STATE(unit, port); 2535 2536 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 2537 (_SW2BR(unit, pc)); 2538 2539 SOC_IF_ERROR_RETURN 2540 (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl)); 2541 2542 if (lre_ctrl & LRE_CTRL_LDSE) { 2543 SOC_IF_ERROR_RETURN 2544 (READ_PHY54880_LRE_STATr(unit, pc, &lre_stat)); 2545 if (!(lre_stat & LRE_STAT_LDS_DONE)) { /* LDS NOT complete */ 2546 *ability = 0; 2547 } else { 2548 ability_local = 0; 2549 ability_remote = 0; 2550 2551 SOC_IF_ERROR_RETURN 2552 (_phy_54880_br_ability_advert_get(unit, port, &ability_local)); 2553 SOC_IF_ERROR_RETURN 2554 (_phy_54880_br_ability_remote_get(unit, port, &ability_remote)); 2555 SOC_IF_ERROR_RETURN 2556 (_phy_54880_br_speed_get(unit, port, &speed)); 2557 SOC_IF_ERROR_RETURN 2558 (_phy_54880_br_pairs_get(unit, port, &pairs)); 2559 *ability = (ability_local & ability_remote & (3U<<13)) | 2560 (((speed == 100) ? (1U << 10): 2561 (speed == 50) ? (1U << 8): 2562 (speed == 33) ? (1U << 6): 2563 (speed == 25) ? (1U << 4): 2564 (speed == 20) ? (1U << 2): 2565 (speed == 10) ? (1U << 0):0) 2566 << (((unsigned) pairs) >> 1)); 2567 } 2568 } else { 2569 *ability = 0; 2570 } 2571 2572 2573 return SOC_E_NONE; 2574 } 2575 2576 /* 2577 * Function: 2578 * phy_54880_lb_set 2579 * Purpose: 2580 * Set the local PHY loopback mode. 2581 * Parameters: 2582 * unit - StrataSwitch unit #. 2583 * port - StrataSwitch port #. 2584 * loopback - Boolean: true = enable loopback, false = disable. 2585 * Returns: 2586 * SOC_E_XXX 2587 * Notes: 2588 * The loopback mode is set only for the ACTIVE medium. 2589 * No synchronization performed at this level. 2590 */ 2591 2592 STATIC int 2593 _phy_54880_ieee_lb_set(int unit, soc_port_t port, int enable) 2594 { 2595 phy_ctrl_t *pc; 2596 2597 pc = EXT_PHY_SW_STATE(unit, port); 2598 2599 #if AUTO_MDIX_WHEN_AN_DIS 2600 { 2601 uint16 tmp; 2602 2603 /* Disable Auto-MDIX When autoneg disabled */ 2604 /* Enable Auto-MDIX When autoneg disabled */ 2605 tmp = (enable) ? 0x0000: 0x0200; 2606 SOC_IF_ERROR_RETURN 2607 (MODIFY_PHY54880_MII_MISC_CTRLr(unit, pc, tmp, 0x0200)); 2608 } 2609 #endif 2610 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 2611 (_SW2IEEE(unit, pc)); 2612 2613 SOC_IF_ERROR_RETURN 2614 (phy_fe_ge_lb_set(unit, port, enable)); 2615 2616 return SOC_E_NONE; 2617 } 2618 2619 STATIC int 2620 _phy_54880_br_lb_set(int unit, soc_port_t port, int enable) 2621 { 2622 phy_ctrl_t *pc; 2623 2624 pc = EXT_PHY_SW_STATE(unit, port); 2625 2626 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 2627 (_SW2BR(unit, pc)); 2628 2629 SOC_IF_ERROR_RETURN 2630 (MODIFY_PHY54880_LRE_CTRLr(unit, pc, (enable ? MII_CTRL_LE : 0), MII_CTRL_LE)); 2631 2632 return SOC_E_NONE; 2633 } 2634 2635 STATIC int 2636 phy_54880_lb_set(int unit, soc_port_t port, int enable) 2637 { 2638 if (PHY_IEEE_MODE(unit, port)) { 2639 SOC_IF_ERROR_RETURN 2640 (_phy_54880_ieee_lb_set(unit, port, enable)); 2641 } else { 2642 SOC_IF_ERROR_RETURN 2643 (_phy_54880_br_lb_set(unit, port, enable)); 2644 } 2645 2646 return SOC_E_NONE; 2647 } 2648 2649 /* 2650 * Function: 2651 * phy_54880_lb_get 2652 * Purpose: 2653 * Get the local PHY loopback mode. 2654 * Parameters: 2655 * unit - StrataSwitch unit #. 2656 * port - StrataSwitch port #. 2657 * loopback - (OUT) Boolean: true = enable loopback, false = disable. 2658 * Returns: 2659 * SOC_E_XXX 2660 * Notes: 2661 * The loopback mode is retrieved for the ACTIVE medium. 2662 */ 2663 2664 STATIC int 2665 _phy_54880_br_lb_get(int unit, soc_port_t port, int *enable) 2666 { 2667 uint16 lre_ctrl; 2668 phy_ctrl_t *pc; 2669 2670 pc = EXT_PHY_SW_STATE(unit, port); 2671 2672 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 2673 (_SW2BR(unit, pc)); 2674 2675 SOC_IF_ERROR_RETURN 2676 (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl)); 2677 2678 *enable = (lre_ctrl & MII_CTRL_LE) ? 1 : 0; 2679 2680 return SOC_E_NONE; 2681 } 2682 2683 STATIC int 2684 phy_54880_lb_get(int unit, soc_port_t port, int *enable) 2685 { 2686 phy_ctrl_t *pc; 2687 2688 pc = EXT_PHY_SW_STATE(unit, port); 2689 2690 if (PHY_IEEE_MODE(unit, port)) { 2691 2692 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 2693 (_SW2IEEE(unit, pc)); 2694 2695 SOC_IF_ERROR_RETURN 2696 (phy_fe_ge_lb_get(unit, port, enable)); 2697 } else { 2698 SOC_IF_ERROR_RETURN 2699 (_phy_54880_br_lb_get(unit, port, enable)); 2700 } 2701 2702 return SOC_E_NONE; 2703 } 2704 2705 /* 2706 * Function: 2707 * phy_54880_interface_set 2708 * Purpose: 2709 * Set the current operating mode of the internal PHY. 2710 * (Pertaining to the MAC/PHY interface, not the line interface). 2711 * Parameters: 2712 * unit - StrataSwitch unit #. 2713 * port - StrataSwitch port #. 2714 * pif - one of SOC_PORT_IF_* 2715 * Returns: 2716 * SOC_E_XXX 2717 */ 2718 2719 STATIC int 2720 phy_54880_interface_set(int unit, soc_port_t port, soc_port_if_t pif) 2721 { 2722 COMPILER_REFERENCE(unit); 2723 COMPILER_REFERENCE(port); 2724 COMPILER_REFERENCE(pif); 2725 2726 return SOC_E_NONE; 2727 2728 } 2729 2730 /* 2731 * Function: 2732 * phy_54880_interface_get 2733 * Purpose: 2734 * Get the current operating mode of the internal PHY. 2735 * (Pertaining to the MAC/PHY interface, not the line interface). 2736 * Parameters: 2737 * unit - StrataSwitch unit #. 2738 * port - StrataSwitch port #. 2739 * pif - (OUT) one of SOC_PORT_IF_* 2740 * Returns: 2741 * SOC_E_XXX 2742 */ 2743 2744 STATIC int 2745 phy_54880_interface_get(int unit, soc_port_t port, soc_port_if_t *pif) 2746 { 2747 phy_ctrl_t *pc; 2748 2749 pc = EXT_PHY_SW_STATE(unit, port); 2750 2751 if (PHY_IS_BCM54881(pc)) { 2752 *pif = SOC_PORT_IF_MII; 2753 } else { 2754 *pif = SOC_PORT_IF_SGMII; 2755 } 2756 2757 return(SOC_E_NONE); 2758 } 2759 2760 /* 2761 * Function: 2762 * phy_54880_mdix_set 2763 * Description: 2764 * Set the Auto-MDIX mode of a port/PHY 2765 * Parameters: 2766 * unit - Device number 2767 * port - Port number 2768 * mode - One of: 2769 * SOC_PORT_MDIX_AUTO 2770 * Enable auto-MDIX when autonegotiation is enabled 2771 * SOC_PORT_MDIX_FORCE_AUTO 2772 * Enable auto-MDIX always 2773 * SOC_PORT_MDIX_NORMAL 2774 * Disable auto-MDIX 2775 * SOC_PORT_MDIX_XOVER 2776 * Disable auto-MDIX, and swap cable pairs 2777 * Return Value: 2778 * SOC_E_XXX 2779 */ 2780 STATIC int 2781 _phy_54880_ieee_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode) 2782 { 2783 phy_ctrl_t *pc; 2784 int speed; 2785 2786 pc = EXT_PHY_SW_STATE(unit, port); 2787 2788 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 2789 (_SW2IEEE(unit, pc)); 2790 2791 switch (mode) { 2792 case SOC_PORT_MDIX_AUTO: 2793 /* Clear bit 14 for automatic MDI crossover */ 2794 SOC_IF_ERROR_RETURN 2795 (MODIFY_PHY54880_MII_ECRr(unit, pc, 0, 0x4000)); 2796 2797 /* 2798 * Write the result in the register 0x18, shadow copy 7 2799 */ 2800 /* Clear bit 9 to disable forced auto MDI xover */ 2801 SOC_IF_ERROR_RETURN 2802 (MODIFY_PHY54880_MII_MISC_CTRLr(unit, pc, 0, 0x0200)); 2803 break; 2804 2805 case SOC_PORT_MDIX_FORCE_AUTO: 2806 /* Clear bit 14 for automatic MDI crossover */ 2807 SOC_IF_ERROR_RETURN 2808 (MODIFY_PHY54880_MII_ECRr(unit, pc, 0, 0x4000)); 2809 2810 /* 2811 * Write the result in the register 0x18, shadow copy 7 2812 */ 2813 /* Set bit 9 to force automatic MDI crossover */ 2814 SOC_IF_ERROR_RETURN 2815 (MODIFY_PHY54880_MII_MISC_CTRLr(unit, pc, 0x0200, 0x0200)); 2816 break; 2817 2818 case SOC_PORT_MDIX_NORMAL: 2819 SOC_IF_ERROR_RETURN(phy_54880_speed_get(unit, port, &speed)); 2820 if (speed == 0 || speed == 10 || speed == 100) { 2821 /* Set bit 14 for manual MDI crossover */ 2822 SOC_IF_ERROR_RETURN 2823 (MODIFY_PHY54880_MII_ECRr(unit, pc, 0x4000, 0x4000)); 2824 2825 SOC_IF_ERROR_RETURN 2826 (WRITE_PHY54880_TEST1r(unit, pc, 0)); 2827 } else { 2828 return SOC_E_UNAVAIL; 2829 } 2830 break; 2831 2832 case SOC_PORT_MDIX_XOVER: 2833 SOC_IF_ERROR_RETURN(phy_54880_speed_get(unit, port, &speed)); 2834 if (speed == 0 || speed == 10 || speed == 100) { 2835 /* Set bit 14 for manual MDI crossover */ 2836 SOC_IF_ERROR_RETURN 2837 (MODIFY_PHY54880_MII_ECRr(unit, pc, 0x4000, 0x4000)); 2838 2839 SOC_IF_ERROR_RETURN 2840 (WRITE_PHY54880_TEST1r(unit, pc, 0x0080)); 2841 } else { 2842 return SOC_E_UNAVAIL; 2843 } 2844 break; 2845 2846 default: 2847 return SOC_E_PARAM; 2848 } 2849 2850 return SOC_E_NONE; 2851 2852 } 2853 2854 STATIC int 2855 phy_54880_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode) 2856 { 2857 phy_ctrl_t *pc; 2858 2859 pc = EXT_PHY_SW_STATE(unit, port); 2860 2861 if (PHY_IEEE_MODE(unit, port)) { 2862 SOC_IF_ERROR_RETURN 2863 (_phy_54880_ieee_mdix_set(unit, port, mode)); 2864 pc->copper.mdix = mode; 2865 } else { 2866 return(SOC_E_CONFIG); 2867 } 2868 2869 return SOC_E_NONE; 2870 } 2871 2872 /* 2873 * Function: 2874 * phy_54880_mdix_get 2875 * Description: 2876 * Get the Auto-MDIX mode of a port/PHY 2877 * Parameters: 2878 * unit - Device number 2879 * port - Port number 2880 * mode - (Out) One of: 2881 * SOC_PORT_MDIX_AUTO 2882 * Enable auto-MDIX when autonegotiation is enabled 2883 * SOC_PORT_MDIX_FORCE_AUTO 2884 * Enable auto-MDIX always 2885 * SOC_PORT_MDIX_NORMAL 2886 * Disable auto-MDIX 2887 * SOC_PORT_MDIX_XOVER 2888 * Disable auto-MDIX, and swap cable pairs 2889 * Return Value: 2890 * SOC_E_XXX 2891 */ 2892 STATIC int 2893 _phy_54880_ieee_mdix_get(int unit, soc_port_t port, soc_port_mdix_t *mode) 2894 { 2895 phy_ctrl_t *pc; 2896 int speed; 2897 2898 pc = EXT_PHY_SW_STATE(unit, port); 2899 2900 SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR 2901 (_SW2IEEE(unit, pc)); 2902 2903 SOC_IF_ERROR_RETURN(phy_54880_speed_get(unit, port, &speed)); 2904 if (speed == 1000) { 2905 *mode = SOC_PORT_MDIX_AUTO; 2906 } else { 2907 *mode = pc->copper.mdix; 2908 } 2909 2910 return SOC_E_NONE; 2911 } 2912 2913 STATIC int 2914 phy_54880_mdix_get(int unit, soc_port_t port, soc_port_mdix_t *mode) 2915 { 2916 if (PHY_IEEE_MODE(unit, port)) { 2917 SOC_IF_ERROR_RETURN 2918 (_phy_54880_ieee_mdix_get(unit, port, mode)); 2919 } else { 2920 *mode = SOC_PORT_MDIX_AUTO; 2921 } 2922 2923 return SOC_E_NONE; 2924 } 2925 2926 /* 2927 * Function: 2928 * phy_54880_mdix_status_get 2929 * Description: 2930 * Get the current MDIX status on a port/PHY 2931 * Parameters: 2932 * unit - Device number 2933 * port - Port number 2934 * status - (OUT) One of: 2935 * SOC_PORT_MDIX_STATUS_NORMAL 2936 * Straight connection 2937 * SOC_PORT_MDIX_STATUS_XOVER 2938 * Crossover has been performed 2939 * Return Value: 2940 * SOC_E_XXX 2941 */ 2942 STATIC int 2943 phy_54880_mdix_status_get(int unit, soc_port_t port, 2944 soc_port_mdix_status_t *status) 2945 { 2946 phy_ctrl_t *pc; 2947 uint16 tmp; 2948 2949 pc = EXT_PHY_SW_STATE(unit, port); 2950 2951 SOC_IF_ERROR_RETURN 2952 (READ_PHY54880_MII_ESRr(unit, pc, &tmp)); 2953 if (tmp & 0x2000) { 2954 *status = SOC_PORT_MDIX_STATUS_XOVER; 2955 } else { 2956 *status = SOC_PORT_MDIX_STATUS_NORMAL; 2957 } 2958 2959 return SOC_E_NONE; 2960 } 2961 2962 STATIC int 2963 phy_54880_link_up(int unit, soc_port_t port) 2964 { 2965 phy_ctrl_t *pc; 2966 int pairs, master; 2967 int speed; 2968 2969 pc = EXT_PHY_SW_STATE(unit, port); 2970 2971 SOC_IF_ERROR_RETURN 2972 (phy_54880_speed_get(unit, port, &speed)); 2973 2974 if (PHY_IS_B0(pc)) { 2975 if (PHY_BR_MODE(unit, port)) { 2976 /* B0 errata */ 2977 SOC_IF_ERROR_RETURN 2978 (_phy_54880_br_pairs_get(unit, port, &pairs)); 2979 SOC_IF_ERROR_RETURN 2980 (_phy_54880_br_master_get(unit, port, &master)); 2981 2982 switch(pairs) { 2983 case 4: 2984 if (master == SOC_PORT_MS_MASTER) { 2985 SOC_IF_ERROR_RETURN 2986 (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL3r(unit, pc, 1U<<15, 1U<<15)); 2987 } 2988 break; 2989 2990 case 2: 2991 case 1: 2992 SOC_IF_ERROR_RETURN 2993 (PHY54880_REG_WRITE(unit, pc, 0x00, 0x0ffd, 0x15, 0x0038)); 2994 SOC_IF_ERROR_RETURN 2995 (PHY54880_REG_WRITE(unit, pc, 0x00, 0x0ffe, 0x15, 0x0038)); 2996 break; 2997 2998 default: 2999 break; 3000 } 3001 } 3002 3003 } 3004 3005 /* Notify interface to internal PHY */ 3006 SOC_IF_ERROR_RETURN 3007 (soc_phyctrl_notify(unit, port, phyEventInterface, SOC_PORT_IF_SGMII)); 3008 3009 /* Situation observed with Saber devices XGXS16g1l+BCM54640E 3010 Linkscan is not updating speed for internal phy xgxs16g1l. 3011 It was observed that when speed is set to 100M the int phy 3012 is still set to 1G and traffic does not flow through untill 3013 int phy speed is also update to 100M. This applies to other 3014 speeds as well. 3015 Explicitly send speed notify to int phy from ext phy. 3016 */ 3017 SOC_IF_ERROR_RETURN 3018 (soc_phyctrl_notify(unit, port, phyEventSpeed, speed)); 3019 3020 return SOC_E_NONE; 3021 } 3022 3023 STATIC int 3024 phy_54880_link_down(int unit, soc_port_t port) 3025 { 3026 phy_ctrl_t *pc; 3027 3028 pc = EXT_PHY_SW_STATE(unit, port); 3029 3030 if (PHY_IS_B0(pc)) { 3031 if (PHY_BR_MODE(unit, port)) { 3032 /* B0 errata */ 3033 SOC_IF_ERROR_RETURN 3034 (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL3r(unit, pc, 0, 1U<<15)); 3035 SOC_IF_ERROR_RETURN 3036 (PHY54880_REG_WRITE(unit, pc, 0x00, 0x0ffd, 0x15, 0)); 3037 SOC_IF_ERROR_RETURN 3038 (PHY54880_REG_WRITE(unit, pc, 0x00, 0x0ffe, 0x15, 0)); 3039 } 3040 } 3041 3042 return SOC_E_NONE; 3043 } 3044 3045 STATIC int 3046 _phy_54880_power_mode_set (int unit, soc_port_t port, int mode) 3047 { 3048 phy_ctrl_t *pc; 3049 3050 pc = EXT_PHY_SW_STATE(unit, port); 3051 3052 if (pc->power_mode == mode) { 3053 return SOC_E_NONE; 3054 } 3055 3056 if (mode == SOC_PHY_CONTROL_POWER_LOW) { 3057 /* enable dsp clock */ 3058 SOC_IF_ERROR_RETURN 3059 (MODIFY_PHY54880_MII_AUX_CTRLr(unit,pc,0x0c00,0x0c00)); 3060 3061 /* enable low power 136 */ 3062 SOC_IF_ERROR_RETURN 3063 (MODIFY_PHY54880_AUTO_POWER_DOWNr(unit,pc,0x80,0x80)); 3064 3065 /* reduce tx bias current to -20% */ 3066 SOC_IF_ERROR_RETURN 3067 (WRITE_PHY_REG(unit, pc, 0x17, 0x0f75)); 3068 SOC_IF_ERROR_RETURN 3069 (WRITE_PHY_REG(unit, pc, 0x15, 0x1555)); 3070 3071 /* disable dsp clock */ 3072 SOC_IF_ERROR_RETURN 3073 (MODIFY_PHY54880_MII_AUX_CTRLr(unit,pc,0x0400,0x0c00)); 3074 pc->power_mode = mode; 3075 3076 } else if (mode == SOC_PHY_CONTROL_POWER_FULL) { 3077 3078 /* back to normal mode */ 3079 /* enable dsp clock */ 3080 SOC_IF_ERROR_RETURN 3081 (MODIFY_PHY54880_MII_AUX_CTRLr(unit,pc,0x0c00,0x0c00)); 3082 3083 /* disable low power 136 */ 3084 SOC_IF_ERROR_RETURN 3085 (MODIFY_PHY54880_AUTO_POWER_DOWNr(unit,pc,0x00,0x80)); 3086 3087 /* set tx bias current to nominal */ 3088 SOC_IF_ERROR_RETURN 3089 (WRITE_PHY_REG(unit, pc, 0x17, 0x0f75)); 3090 SOC_IF_ERROR_RETURN 3091 (WRITE_PHY_REG(unit, pc, 0x15, 0x0)); 3092 3093 /* disable dsp clock */ 3094 SOC_IF_ERROR_RETURN 3095 (MODIFY_PHY54880_MII_AUX_CTRLr(unit,pc,0x0400,0x0c00)); 3096 3097 /* disable the auto power mode */ 3098 SOC_IF_ERROR_RETURN 3099 (MODIFY_PHY54880_AUTO_POWER_DOWNr(unit,pc, 3100 0, 3101 PHY_54880_AUTO_PWRDWN_EN)); 3102 pc->power_mode = mode; 3103 } else if (mode == SOC_PHY_CONTROL_POWER_AUTO) { 3104 SOC_IF_ERROR_RETURN 3105 (MODIFY_PHY54880_AUTO_POWER_DOWNr(unit,pc, 3106 PHY_54880_AUTO_PWRDWN_EN, 3107 PHY_54880_AUTO_PWRDWN_EN)); 3108 pc->power_mode = mode; 3109 } 3110 return SOC_E_NONE; 3111 } 3112 3113 /* 3114 * Function: 3115 * phy_54880_control_set 3116 * Purpose: 3117 * Configure PHY device specific control fucntion. 3118 * Parameters: 3119 * unit - StrataSwitch unit #. 3120 * port - StrataSwitch port #. 3121 * type - Control to update 3122 * value - New setting for the control 3123 * Returns: 3124 * SOC_E_NONE 3125 */ 3126 STATIC int 3127 phy_54880_control_set(int unit, soc_port_t port, 3128 soc_phy_control_t type, uint32 value) 3129 { 3130 int rv; 3131 phy_ctrl_t *pc; 3132 phy_br_config_t *br_config; 3133 uint16 data; 3134 soc_port_t primary; 3135 int offset; 3136 3137 PHY_CONTROL_TYPE_CHECK(type); 3138 3139 pc = EXT_PHY_SW_STATE(unit, port); 3140 rv = SOC_E_NONE; 3141 br_config = (phy_br_config_t *) &pc->fiber; 3142 3143 switch(type) { 3144 case SOC_PHY_CONTROL_PREEMPHASIS: 3145 rv = SOC_E_UNAVAIL; 3146 break; 3147 3148 case SOC_PHY_CONTROL_DRIVER_CURRENT: 3149 rv = SOC_E_UNAVAIL; 3150 break; 3151 3152 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 3153 rv = SOC_E_UNAVAIL; 3154 break; 3155 3156 case SOC_PHY_CONTROL_POWER: 3157 rv = _phy_54880_power_mode_set(unit,port,value); 3158 break; 3159 3160 case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME: 3161 if (value <= PHY_54880_AUTO_PWRDWN_WAKEUP_MAX) { 3162 3163 /* at least one unit */ 3164 if (value < PHY_54880_AUTO_PWRDWN_WAKEUP_UNIT) { 3165 value = PHY_54880_AUTO_PWRDWN_WAKEUP_UNIT; 3166 } 3167 } else { /* anything more then max, set to the max */ 3168 value = PHY_54880_AUTO_PWRDWN_WAKEUP_MAX; 3169 } 3170 SOC_IF_ERROR_RETURN 3171 (MODIFY_PHY54880_AUTO_POWER_DOWNr(unit,pc, 3172 value/PHY_54880_AUTO_PWRDWN_WAKEUP_UNIT, 3173 PHY_54880_AUTO_PWRDWN_WAKEUP_MASK)); 3174 break; 3175 3176 case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME: 3177 /* sleep time configuration is either 2.7s or 5.4 s, default is 2.7s */ 3178 if (value < PHY_54880_AUTO_PWRDWN_SLEEP_MAX) { 3179 data = 0; /* anything less than 5.4s, default to 2.7s */ 3180 } else { 3181 data = PHY_54880_AUTO_PWRDWN_SLEEP_MASK; 3182 } 3183 SOC_IF_ERROR_RETURN 3184 (MODIFY_PHY54880_AUTO_POWER_DOWNr(unit,pc, 3185 data, 3186 PHY_54880_AUTO_PWRDWN_SLEEP_MASK)); 3187 break; 3188 3189 case SOC_PHY_CONTROL_LONGREACH_SPEED: 3190 rv = _phy_54880_br_speed_set(unit, port, value); 3191 br_config->force_speed = value; 3192 break; 3193 3194 case SOC_PHY_CONTROL_LONGREACH_PAIRS: 3195 rv = _phy_54880_br_pairs_set(unit, port, value); 3196 br_config->force_pairs = value; 3197 break; 3198 3199 case SOC_PHY_CONTROL_LONGREACH_GAIN: 3200 rv = _phy_54880_br_gain_set(unit, port, value); 3201 br_config->gain = value; 3202 break; 3203 3204 case SOC_PHY_CONTROL_LONGREACH_AUTONEG: 3205 rv = _phy_54880_br_autoneg_set(unit, port, value); 3206 br_config->lds_enable = value; 3207 break; 3208 3209 case SOC_PHY_CONTROL_LONGREACH_LOCAL_ABILITY: 3210 rv = _phy_54880_br_ability_advert_set(unit, port, value); 3211 SOC_IF_ERROR_RETURN 3212 (_phy_54880_br_autoneg_set(unit, port, br_config->lds_enable)); 3213 br_config->lds_advert_ability = value & LONGREACH_ABILITY_ALL(pc); 3214 break; 3215 3216 case SOC_PHY_CONTROL_LONGREACH_MASTER: 3217 rv = _phy_54880_br_master_set(unit, port, value); 3218 br_config->master = value; 3219 break; 3220 3221 case SOC_PHY_CONTROL_LONGREACH_ENABLE: 3222 rv = _phy_54880_br_enable_set(unit, port, value); 3223 br_config->enable = value; 3224 break; 3225 3226 case SOC_PHY_CONTROL_LONGREACH_REMOTE_ABILITY: 3227 case SOC_PHY_CONTROL_LONGREACH_CURRENT_ABILITY: 3228 case SOC_PHY_CONTROL_LONGREACH_ACTIVE: 3229 /* Do nothing for the read only commands */ 3230 rv = SOC_E_CONFIG; 3231 break; 3232 3233 case SOC_PHY_CONTROL_PORT_PRIMARY: 3234 SOC_IF_ERROR_RETURN 3235 (soc_phyctrl_primary_set(unit, port, (soc_port_t)value)); 3236 break; 3237 3238 case SOC_PHY_CONTROL_PORT_OFFSET: 3239 SOC_IF_ERROR_RETURN 3240 (soc_phyctrl_offset_set(unit, port, (int)value)); 3241 break; 3242 3243 case SOC_PHY_CONTROL_CLOCK_ENABLE: 3244 SOC_IF_ERROR_RETURN 3245 (soc_phyctrl_primary_get(unit, port, &primary)); 3246 SOC_IF_ERROR_RETURN 3247 (soc_phyctrl_offset_get(unit, port, &offset)); 3248 SOC_IF_ERROR_RETURN 3249 (soc_phyctrl_toplvl_reg_read(unit, port, primary, 0x0, &data)); 3250 if ( value ) { 3251 SOC_IF_ERROR_RETURN 3252 (soc_phyctrl_toplvl_reg_write(unit, port, primary, 0x0, 3253 ( data & 0xf0 ) | ( offset & 0x7 ))); 3254 } else { 3255 SOC_IF_ERROR_RETURN 3256 (soc_phyctrl_toplvl_reg_write(unit, port, primary, 0x0, 3257 ( data & 0xf0 ) | 0x8 )); 3258 } 3259 break; 3260 3261 case SOC_PHY_CONTROL_CLOCK_SECONDARY_ENABLE: 3262 SOC_IF_ERROR_RETURN 3263 (soc_phyctrl_primary_get(unit, port, &primary)); 3264 SOC_IF_ERROR_RETURN 3265 (soc_phyctrl_offset_get(unit, port, &offset)); 3266 SOC_IF_ERROR_RETURN 3267 (soc_phyctrl_toplvl_reg_read(unit, port, primary, 0x0, &data)); 3268 if ( value ) { 3269 SOC_IF_ERROR_RETURN 3270 (soc_phyctrl_toplvl_reg_write(unit, port, primary, 0x0, 3271 ( data & 0x0f ) | (( offset & 0x7 )<<4 ))); 3272 } else { 3273 SOC_IF_ERROR_RETURN 3274 (soc_phyctrl_toplvl_reg_write(unit, port, primary, 0x0, 3275 ( data & 0x0f ) | (0x8<<4) )); 3276 } 3277 break; 3278 3279 case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT: 3280 /* Not supported for 10/100/1000BASE-T interfaces */ 3281 rv = SOC_E_UNAVAIL; 3282 break; 3283 3284 default: 3285 rv = SOC_E_UNAVAIL; 3286 break; 3287 } 3288 return rv; 3289 } 3290 3291 /* 3292 * Function: 3293 * phy_54880_control_get 3294 * Purpose: 3295 * Get current control settign of the PHY. 3296 * Parameters: 3297 * unit - StrataSwitch unit #. 3298 * port - StrataSwitch port #. 3299 * type - Control to update 3300 * value - (OUT)Current setting for the control 3301 * Returns: 3302 * SOC_E_NONE 3303 */ 3304 STATIC int 3305 phy_54880_control_get(int unit, soc_port_t port, 3306 soc_phy_control_t type, uint32 *value) 3307 { 3308 int rv; 3309 phy_ctrl_t *pc; 3310 int temp; 3311 uint16 data; 3312 soc_port_t primary; 3313 int offset; 3314 3315 PHY_CONTROL_TYPE_CHECK(type); 3316 3317 pc = EXT_PHY_SW_STATE(unit, port); 3318 rv = SOC_E_NONE; 3319 temp = 0; 3320 3321 switch(type) { 3322 3323 case SOC_PHY_CONTROL_PREEMPHASIS: 3324 rv = SOC_E_UNAVAIL; 3325 break; 3326 3327 case SOC_PHY_CONTROL_DRIVER_CURRENT: 3328 rv = SOC_E_UNAVAIL; 3329 break; 3330 3331 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 3332 rv = SOC_E_UNAVAIL; 3333 break; 3334 3335 case SOC_PHY_CONTROL_POWER: 3336 *value = pc->power_mode; 3337 rv = SOC_E_NONE; 3338 break; 3339 3340 case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME: 3341 SOC_IF_ERROR_RETURN 3342 (READ_PHY54880_AUTO_POWER_DOWNr(unit,pc, &data)); 3343 3344 if (data & PHY_54880_AUTO_PWRDWN_SLEEP_MASK) { 3345 *value = PHY_54880_AUTO_PWRDWN_SLEEP_MAX; 3346 } else { 3347 *value = 2700; 3348 } 3349 break; 3350 3351 case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME: 3352 SOC_IF_ERROR_RETURN 3353 (READ_PHY54880_AUTO_POWER_DOWNr(unit,pc, &data)); 3354 3355 data &= PHY_54880_AUTO_PWRDWN_WAKEUP_MASK; 3356 *value = data * PHY_54880_AUTO_PWRDWN_WAKEUP_UNIT; 3357 break; 3358 3359 case SOC_PHY_CONTROL_LONGREACH_SPEED: 3360 rv = _phy_54880_br_speed_get(unit, port, &temp); 3361 *value = (uint32)temp; 3362 break; 3363 3364 case SOC_PHY_CONTROL_LONGREACH_PAIRS: 3365 rv = _phy_54880_br_pairs_get(unit, port, &temp); 3366 *value = (uint32)temp; 3367 break; 3368 3369 case SOC_PHY_CONTROL_LONGREACH_GAIN: 3370 rv = _phy_54880_br_gain_get(unit, port, &temp); 3371 *value = (uint32)temp; 3372 break; 3373 3374 case SOC_PHY_CONTROL_LONGREACH_AUTONEG: 3375 rv = _phy_54880_br_autoneg_get(unit, port, &temp, NULL); 3376 *value = (uint32)temp; 3377 break; 3378 3379 case SOC_PHY_CONTROL_LONGREACH_LOCAL_ABILITY: 3380 rv = _phy_54880_br_ability_advert_get(unit, port, value); 3381 break; 3382 3383 case SOC_PHY_CONTROL_LONGREACH_REMOTE_ABILITY: 3384 rv = _phy_54880_br_ability_remote_get(unit, port, value); 3385 break; 3386 3387 case SOC_PHY_CONTROL_LONGREACH_CURRENT_ABILITY: 3388 rv = _phy_54880_br_ability_current_get(unit, port, value); 3389 break; 3390 3391 case SOC_PHY_CONTROL_LONGREACH_MASTER: 3392 rv = _phy_54880_br_master_get(unit, port, &temp); 3393 *value = (uint32)temp; 3394 break; 3395 3396 case SOC_PHY_CONTROL_LONGREACH_ACTIVE: 3397 rv = _phy_54880_br_active_get(unit, port, &temp); 3398 *value = (uint32)temp; 3399 break; 3400 3401 case SOC_PHY_CONTROL_LONGREACH_ENABLE: 3402 rv = _phy_54880_br_enable_get(unit, port, &temp); 3403 *value = (uint32)temp; 3404 break; 3405 3406 case SOC_PHY_CONTROL_PORT_PRIMARY: 3407 SOC_IF_ERROR_RETURN 3408 (soc_phyctrl_primary_get(unit, port, &primary)); 3409 *value = (uint32) primary; 3410 break; 3411 3412 case SOC_PHY_CONTROL_PORT_OFFSET: 3413 SOC_IF_ERROR_RETURN 3414 (soc_phyctrl_offset_get(unit, port, &offset)); 3415 *value = (uint32) offset; 3416 break; 3417 3418 case SOC_PHY_CONTROL_CLOCK_ENABLE: 3419 SOC_IF_ERROR_RETURN 3420 (soc_phyctrl_primary_get(unit, port, &primary)); 3421 SOC_IF_ERROR_RETURN 3422 (soc_phyctrl_offset_get(unit, port, &offset)); 3423 if (soc_phyctrl_toplvl_reg_read(unit, port, primary, 0x0, &data) == SOC_E_NONE) { 3424 if (( data & 0x8 ) || (( data & 0x7 ) != offset)) { 3425 *value = FALSE; 3426 } else { 3427 *value = TRUE; 3428 } 3429 } 3430 break; 3431 3432 case SOC_PHY_CONTROL_CLOCK_SECONDARY_ENABLE: 3433 SOC_IF_ERROR_RETURN 3434 (soc_phyctrl_primary_get(unit, port, &primary)); 3435 SOC_IF_ERROR_RETURN 3436 (soc_phyctrl_offset_get(unit, port, &offset)); 3437 if (soc_phyctrl_toplvl_reg_read(unit, port, primary, 0x0, &data) == SOC_E_NONE) { 3438 if (( data & (0x8<<4) ) || (( data & (0x7<<4) ) != (offset<<4) )) { 3439 *value = FALSE; 3440 } else { 3441 *value = TRUE; 3442 } 3443 } 3444 break; 3445 3446 case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT: 3447 /* Not supported for 10/100/1000BASE-T interfaces */ 3448 rv = SOC_E_UNAVAIL; 3449 break; 3450 3451 default: 3452 rv = SOC_E_UNAVAIL; 3453 break; 3454 } 3455 3456 return rv; 3457 } 3458 3459 /* 3460 * Function: 3461 * phy_54880_cable_diag 3462 * Purpose: 3463 * Run 546x cable diagnostics 3464 * Parameters: 3465 * unit - device number 3466 * port - port number 3467 * status - (OUT) cable diagnotic status structure 3468 * Returns: 3469 * SOC_E_XXX 3470 */ 3471 STATIC int 3472 phy_54880_cable_diag(int unit, soc_port_t port, 3473 soc_port_cable_diag_t *status) 3474 { 3475 int rv, rv2, i; 3476 3477 extern int phy_5464_cable_diag_sw(int, soc_port_t , 3478 soc_port_cable_diag_t *); 3479 3480 if (status == NULL) { 3481 return SOC_E_PARAM; 3482 } 3483 3484 status->state = SOC_PORT_CABLE_STATE_OK; 3485 status->npairs = 4; 3486 status->fuzz_len = 0; 3487 for (i = 0; i < 4; i++) { 3488 status->pair_state[i] = SOC_PORT_CABLE_STATE_OK; 3489 } 3490 3491 MIIM_LOCK(unit); /* this locks out linkscan, essentially */ 3492 rv = phy_5464_cable_diag_sw(unit,port, status); 3493 MIIM_UNLOCK(unit); 3494 rv2 = 0; 3495 if (rv <= 0) { /* don't reset if > 0 -- link was up */ 3496 rv2 = _phy_54880_reset_setup(unit, port); 3497 } 3498 if (rv >= 0 && rv2 < 0) { 3499 return rv2; 3500 } 3501 return rv; 3502 } 3503 3504 STATIC int 3505 phy_54880_cable_diag_dispatch(int unit, soc_port_t port, 3506 soc_port_cable_diag_t *status) 3507 { 3508 phy_ctrl_t *pc; 3509 3510 pc = EXT_PHY_SW_STATE(unit, port); 3511 3512 if ((PHY_IS_BCM54880(pc)) && ((pc->phy_rev & 0xf) > 0x1)) { 3513 SOC_IF_ERROR_RETURN( 3514 phy_ecd_cable_diag(unit, port, status)); 3515 } else { 3516 SOC_IF_ERROR_RETURN( 3517 phy_54880_cable_diag(unit, port, status)); 3518 } 3519 SOC_IF_ERROR_RETURN( 3520 _phy_54880_reset_setup(unit, port)); 3521 3522 return SOC_E_NONE; 3523 } 3524 3525 /* 3526 * Variable: phy_54880drv_ge 3527 * Purpose: PHY driver for 54880 3528 */ 3529 3530 phy_driver_t phy_54880drv_ge = { 3531 "54880 Gigabit PHY Driver", 3532 phy_54880_init, 3533 phy_fe_ge_reset, 3534 phy_54880_link_get, 3535 phy_54880_enable_set, 3536 phy_54880_enable_get, 3537 phy_54880_duplex_set, 3538 phy_54880_duplex_get, 3539 phy_54880_speed_set, 3540 phy_54880_speed_get, 3541 phy_54880_master_set, 3542 phy_54880_master_get, 3543 phy_54880_autoneg_set, 3544 phy_54880_autoneg_get, 3545 NULL, 3546 NULL, 3547 NULL, 3548 phy_54880_lb_set, 3549 phy_54880_lb_get, 3550 phy_54880_interface_set, 3551 phy_54880_interface_get, 3552 NULL, /* Deprecated */ 3553 phy_54880_link_up, /* Link up event */ 3554 phy_54880_link_down, /* Link down event */ 3555 phy_54880_mdix_set, 3556 phy_54880_mdix_get, 3557 phy_54880_mdix_status_get, 3558 phy_54880_medium_config_set, 3559 phy_54880_medium_config_get, 3560 phy_54880_medium_status, 3561 phy_54880_cable_diag_dispatch, 3562 NULL, /* phy_link_change */ 3563 phy_54880_control_set, /* phy_control_set */ 3564 phy_54880_control_get, /* phy_control_get */ 3565 phy_ge_reg_read, 3566 phy_ge_reg_write, 3567 phy_ge_reg_modify, 3568 NULL, /* Phy notify event */ 3569 NULL, /* pd_probe */ 3570 phy_54880_ability_advert_set,/* pd_ability_advert_set */ 3571 phy_54880_ability_advert_get,/* pd_ability_advert_get */ 3572 phy_54880_ability_remote_get,/* pd_ability_remote_get */ 3573 phy_54880_ability_local_get /* pd_ability_local_get */ 3574 }; 3575 3576 #else /* INCLUDE_PHY_54880_ESW */ 3577 int _phy_54880_not_empty; 3578 #endif /* INCLUDE_PHY_54880_ESW */ 3579