phy54682.c (189309B)
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: phy54682.c 8 * Purpose: PHY driver for BCM54682 9 * 10 * Supported BCM54682 PHY device: 11 * 12 * Device Ports Media MAC Interface 13 * 54682 8 Copper/Serdes Combo QSGMII 14 * 15 * Workarounds: 16 * 17 * References: 18 * 54682-DS00-RDS.pdf BCM54682 Data Sheet 19 * 20 * Notes: 21 */ 22 23 #include <sal/types.h> 24 #include <sal/core/spl.h> 25 #include <shared/bsl.h> 26 #include <soc/drv.h> 27 #include <soc/debug.h> 28 #include <soc/error.h> 29 #include <soc/phyreg.h> 30 31 #include <soc/phy.h> 32 #include <soc/phy/phyctrl.h> 33 #include <soc/phy/drv.h> 34 35 #include "phydefs.h" /* Must include before other phy related includes */ 36 37 #if defined(INCLUDE_PHY_54682) 38 #include "phyconfig.h" /* Must be the first phy include after phydefs.h */ 39 #include "phyident.h" 40 #include "phyreg.h" 41 #include "phyfege.h" 42 #include "phy54682.h" 43 44 #define AUTO_MDIX_WHEN_AN_DIS 0 /* Non-standard-compliant option */ 45 46 #define ECD_ENABLE 0 47 48 #define ADVERT_ALL_COPPER \ 49 (SOC_PM_PAUSE | SOC_PM_10MB | SOC_PM_100MB | SOC_PM_1000MB) 50 #define ADVERT_ALL_FIBER \ 51 (SOC_PM_PAUSE | SOC_PM_1000MB_FD) 52 53 54 #define PHY_IS_BCM54682E(_pc) (PHY_MODEL_CHECK((_pc), \ 55 PHY_BCM54682E_OUI, \ 56 PHY_BCM54682E_MODEL) \ 57 && (((_pc)->phy_rev & 0x08) == 0x0 )) 58 59 #define PHY_IS_BCM54685E(_pc) (PHY_MODEL_CHECK((_pc), \ 60 PHY_BCM54682E_OUI, \ 61 PHY_BCM54682E_MODEL) \ 62 && (((_pc)->phy_rev & 0x08) == 0x8 )) 63 64 #define PHY_IS_BCM54682E_OR_BCM54685E(_pc) (PHY_MODEL_CHECK((_pc), \ 65 PHY_BCM54682E_OUI, \ 66 PHY_BCM54682E_MODEL)) 67 68 #define PHY_IS_BCM54684E(_pc) (PHY_MODEL_CHECK((_pc), \ 69 PHY_BCM54684E_OUI, \ 70 PHY_BCM54684E_MODEL)) 71 72 #define PHY_IS_BCM54685E_A0(_pc) (PHY_MODEL_CHECK((_pc), \ 73 PHY_BCM54682E_OUI, \ 74 PHY_BCM54682E_MODEL) \ 75 && ((_pc)->phy_rev == 0x8 )) 76 77 #define PHY_IS_BCM54685E_A1(_pc) (PHY_MODEL_CHECK((_pc), \ 78 PHY_BCM54682E_OUI, \ 79 PHY_BCM54682E_MODEL) \ 80 && ((_pc)->phy_rev == 0x9 )) 81 82 #define PHY_IS_BCM54685E_A0A1(_pc) (PHY_MODEL_CHECK((_pc), \ 83 PHY_BCM54682E_OUI, \ 84 PHY_BCM54682E_MODEL) \ 85 && (((_pc)->phy_rev & 0xe) == 0x8 )) 86 87 #define PHY_IS_BCM54682E_OR_BCM54685E_A0A1(_pc) (PHY_MODEL_CHECK((_pc), \ 88 PHY_BCM54682E_OUI, \ 89 PHY_BCM54682E_MODEL) \ 90 && (((_pc)->phy_rev & 0x6) == 0x0 )) 91 92 #define PHY_BCM54682_QSGMII_DEV_ADDR(_pc) \ 93 (PHY54682_FLAGS((_pc)) & PHY54682_PHYA_REV) ? (PHY54682_DEV_PHY_ID_BASE(_pc) + 1) : \ 94 (PHY54682_DEV_PHY_ID_BASE(_pc) + 8) 95 96 #define SOC_IF_ERROR_BREAK(op, __rv__) \ 97 if (((__rv__) = (op)) < 0) { \ 98 break; \ 99 } 100 101 STATIC int _phy_54682_qsgmii_aer[2] = {0x0, 0x4}; 102 103 STATIC int _phy_54682_tx_control_set(int unit, soc_port_t port, 104 soc_phy_control_t type, uint32 value); 105 STATIC int _phy_54682_tx_control_get(int unit, soc_port_t port, 106 soc_phy_control_t type, uint32 *value); 107 108 STATIC int _phy_54682_no_reset_setup(int unit, soc_port_t port); 109 STATIC int _phy_54682_medium_change(int unit, soc_port_t port, int force_update); 110 STATIC int phy_54682_duplex_set(int unit, soc_port_t port, int duplex); 111 STATIC int phy_54682_speed_set(int unit, soc_port_t port, int speed); 112 STATIC int phy_54682_master_set(int unit, soc_port_t port, int master); 113 STATIC int phy_54682_autoneg_set(int unit, soc_port_t port, int autoneg); 114 STATIC int phy_54682_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode); 115 STATIC int phy_54682_speed_get(int unit, soc_port_t port, int *speed); 116 STATIC int phy_54682_ability_local_get(int unit, soc_port_t port, 117 soc_port_ability_t *ability); 118 STATIC int _phy_54682_ability_cu_local_get(int unit, soc_port_t port, 119 soc_port_ability_t *ability); 120 STATIC int _phy_54682_ability_fiber_local_get(int unit, soc_port_t port, 121 soc_port_ability_t *ability); 122 STATIC int phy_54682_ability_advert_set(int unit, soc_port_t port, 123 soc_port_ability_t *ability); 124 STATIC int phy_54682_control_set(int unit, soc_port_t port, 125 soc_phy_control_t type, uint32 value); 126 STATIC int phy_54682_control_get(int unit, soc_port_t port, 127 soc_phy_control_t type, uint32 *value); 128 extern int 129 phy_ecd_cable_diag_init(int unit, soc_port_t port); 130 131 extern int 132 phy_ecd_cable_diag(int unit, soc_port_t port, 133 soc_port_cable_diag_t *status); 134 135 /*********************************************************************** 136 * 137 * HELPER FUNCTIONS 138 */ 139 140 /* 141 * Function: 142 * _phy_54682e_cl45_reg_read 143 * Purpose: 144 * Read Clause 45 Register using Clause 22 register access 145 * Parameters: 146 * unit - StrataSwitch unit #. 147 * pc - Phy control 148 * flags - Flags 149 * dev_addr - Clause 45 Device 150 * reg_addr - Register Address to read 151 * val - Value Read 152 * Returns: 153 * SOC_E_XXX 154 */ 155 156 STATIC int 157 _phy_54682e_cl45_reg_read(int unit, phy_ctrl_t *pc, uint32 flags, 158 uint8 dev_addr, uint16 reg_addr, uint16 *val) 159 { 160 161 /* Write Device Address to register 0x0D (Set Function field to Address)*/ 162 SOC_IF_ERROR_RETURN 163 (PHY54682_REG_WRITE(unit, pc, flags, 0x00, 0x0D, (dev_addr & 0x001f))); 164 165 /* Select the register by writing to register address to register 0x0E */ 166 SOC_IF_ERROR_RETURN 167 (PHY54682_REG_WRITE(unit, pc, flags, 0x00, 0x0E, reg_addr)); 168 169 /* Write Device Address to register 0x0D (Set Function field to Data)*/ 170 SOC_IF_ERROR_RETURN 171 (PHY54682_REG_WRITE(unit, pc, flags, 0x00, 0x0D, 172 ((0x4000) | (dev_addr & 0x001f)))); 173 174 /* Read register 0x0E to get the value */ 175 SOC_IF_ERROR_RETURN 176 (PHY54682_REG_READ(unit, pc, flags, 0x00, 0x0E, val)); 177 178 return SOC_E_NONE; 179 } 180 181 /* 182 * Function: 183 * _phy_54682e_cl45_reg_write 184 * Purpose: 185 * Write Clause 45 Register content using Clause 22 register access 186 * Parameters: 187 * unit - StrataSwitch unit #. 188 * pc - Phy control 189 * flags - Flags 190 * dev_addr - Clause 45 Device 191 * reg_addr - Register Address to read 192 * val - Value to be written 193 * Returns: 194 * SOC_E_XXX 195 */ 196 197 STATIC int 198 _phy_54682e_cl45_reg_write(int unit, phy_ctrl_t *pc, uint32 flags, 199 uint8 dev_addr, uint16 reg_addr, uint16 val) 200 { 201 202 /* Write Device Address to register 0x0D (Set Function field to Address)*/ 203 SOC_IF_ERROR_RETURN 204 (PHY54682_REG_WRITE(unit, pc, flags, 0x00, 0x0D, (dev_addr & 0x001f))); 205 206 /* Select the register by writing to register address to register 0x0E */ 207 SOC_IF_ERROR_RETURN 208 (PHY54682_REG_WRITE(unit, pc, flags, 0x00, 0x0E, reg_addr)); 209 210 /* Write Device Address to register 0x0D (Set Function field to Data)*/ 211 SOC_IF_ERROR_RETURN 212 (PHY54682_REG_WRITE(unit, pc, flags, 0x00, 0x0D, 213 ((0x4000) | (dev_addr & 0x001f)))); 214 215 /* Write register 0x0E to write the value */ 216 SOC_IF_ERROR_RETURN 217 (PHY54682_REG_WRITE(unit, pc, flags, 0x00, 0x0E, val)); 218 219 return SOC_E_NONE; 220 } 221 222 /* 223 * Function: 224 * _phy_54682e_cl45_reg_modify 225 * Purpose: 226 * Modify Clause 45 Register contents using Clause 22 register access 227 * Parameters: 228 * unit - StrataSwitch unit #. 229 * pc - Phy control 230 * flags - Flags 231 * reg_bank - Register bank 232 * dev_addr - Clause 45 Device 233 * reg_addr - Register Address to read 234 * val - Value 235 * mask - Mask for modifying the contents of the register 236 * Returns: 237 * SOC_E_XXX 238 */ 239 240 STATIC int 241 _phy_54682e_cl45_reg_modify(int unit, phy_ctrl_t *pc, uint32 flags, 242 uint8 dev_addr, uint16 reg_addr, uint16 val, 243 uint16 mask) 244 { 245 246 uint16 value = 0; 247 248 SOC_IF_ERROR_RETURN 249 (PHY54682E_CL45_REG_READ(unit, pc, flags, dev_addr, reg_addr, &value)); 250 251 value = (val & mask) | (value & ~mask); 252 253 SOC_IF_ERROR_RETURN 254 (PHY54682E_CL45_REG_WRITE(unit, pc, flags, dev_addr, reg_addr, value)); 255 256 return SOC_E_NONE; 257 } 258 259 /* 260 * Function: 261 * _phy_54682e_blk_top_lvl_reg_read 262 * Purpose: 263 * New mechanism to Read Top Level Registers for EEE and 1588. 264 * Parameters: 265 * unit - StrataSwitch unit #. 266 * pc - Phy control 267 * flags - Flags 268 * reg_offset - Register Address to read 269 * val - Value Read 270 * Returns: 271 * SOC_E_XXX 272 */ 273 274 STATIC int 275 _phy_54682e_blk_top_lvl_reg_read(int unit, phy_ctrl_t *pc, uint32 flags, 276 uint16 reg_offset, uint16 *val) 277 { 278 /* Write register 0x17 with the top level reg offset to read (handled in PHY54682_REG_READ) */ 279 /* Read register 0x15 to get the value */ 280 SOC_IF_ERROR_RETURN 281 (PHY54682_REG_READ(unit, pc, flags, (0x0D00|(reg_offset & 0xff)), 0x15, val)); 282 283 return SOC_E_NONE; 284 } 285 286 /* 287 * Function: 288 * _phy_54682e_blk_top_lvl_reg_write 289 * Purpose: 290 * New mechanism to Write Top Level Registers for EEE and 1588 291 * Parameters: 292 * unit - StrataSwitch unit #. 293 * pc - Phy control 294 * flags - Flags 295 * reg_offset - Register Address to read 296 * val - Value to be written 297 * Returns: 298 * SOC_E_XXX 299 */ 300 301 STATIC int 302 _phy_54682e_blk_top_lvl_reg_write(int unit, phy_ctrl_t *pc, uint32 flags, 303 uint16 reg_offset, uint16 val) 304 { 305 /* Write register 0x17 with the top level reg offset to write (handled in PHY54682_REG_WRITE) */ 306 /* Write register 0x15 the value to write to the top level register offset */ 307 SOC_IF_ERROR_RETURN 308 (PHY54682_REG_WRITE(unit, pc, flags, (0x0D00|(reg_offset & 0xff)), 0x15, val)); 309 310 return SOC_E_NONE; 311 } 312 313 /* 314 * Function: 315 * _phy_54682e_blk_top_lvl_reg_modify 316 * Purpose: 317 * Modify Clause 45 Register contents using Clause 22 register access 318 * Parameters: 319 * unit - StrataSwitch unit #. 320 * pc - Phy control 321 * flags - Flags 322 * reg_bank - Register bank 323 * dev_addr - Clause 45 Device 324 * reg_addr - Register Address to read 325 * val - Value 326 * mask - Mask for modifying the contents of the register 327 * Returns: 328 * SOC_E_XXX 329 */ 330 331 STATIC int 332 _phy_54682e_blk_top_lvl_reg_modify(int unit, phy_ctrl_t *pc, uint32 flags, 333 uint16 reg_offset, uint16 val, uint16 mask) 334 { 335 336 uint16 value = 0; 337 338 /* Write register 0x17 with the top level reg offset to read */ 339 SOC_IF_ERROR_RETURN 340 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, flags, 341 reg_offset, &value)); 342 343 value = (val & mask) | (value & ~mask); 344 345 /* Write register 0x17 with the top level reg offset to read */ 346 SOC_IF_ERROR_RETURN 347 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, flags, 348 reg_offset, value)); 349 return SOC_E_NONE; 350 } 351 352 /* 353 * Function: 354 * phy_54682_toplvl_reg_read 355 * Purpose: 356 * Read a top level register from a supporting chip 357 * Parameters: 358 * unit - SOC Unit #. 359 * port - Port number. 360 * flags - 361 * reg_offset - Offset to the reg 362 * data - Pointer to data returned 363 * Returns: 364 * SOC_E_XXX 365 */ 366 int 367 phy_54682_toplvl_reg_read(int unit, soc_port_t port, int flags, uint8 reg_offset, uint16 *data) 368 { 369 phy_ctrl_t *pc; 370 uint16 reg_data, status; 371 int rv = SOC_E_NONE; 372 373 LOG_VERBOSE(BSL_LS_SOC_PHY, 374 (BSL_META_U(unit, 375 "entered phy_54682_toplvl_reg_read: " 376 "unit %d, port %d, flags %x reg_offset %u\n"), 377 unit, port, flags, reg_offset)); 378 379 pc = EXT_PHY_SW_STATE(unit, port); 380 381 /* Write Reg address to Port 5's (offset=4) register 0x1C, shadow 0x0B */ 382 /* Status READ from Port 3's (offset=2) register 0x15 */ 383 384 /* Write Reg offset to Port 5's register 0x1C, shadow 0x0B */ 385 reg_data = (0xAC00 | reg_offset); 386 INT_MCU_LOCK(unit); 387 pc->phy_id = PHY54682_SLICE_ADDR(pc, 4); 388 rv = pc->write(unit, pc->phy_id, 0x1c, reg_data); 389 if (SOC_FAILURE(rv)) { 390 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 391 INT_MCU_UNLOCK(unit); 392 return rv; 393 } 394 395 pc->phy_id = PHY54682_SLICE_ADDR(pc, 2); 396 /* Read data from Top level MII Status register(0x15h) */ 397 rv = pc->write(unit, pc->phy_id, 0x17, 0x8F0B); 398 if (SOC_FAILURE(rv)) { 399 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 400 INT_MCU_UNLOCK(unit); 401 return rv; 402 } 403 rv = pc->read(unit, pc->phy_id, 0x15, &status); 404 INT_MCU_UNLOCK(unit); 405 if (SOC_FAILURE(rv)) { 406 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 407 return rv; 408 } 409 410 *data = (status & 0xff); 411 412 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 413 414 return SOC_E_NONE; 415 } 416 417 /* 418 * Function: 419 * phy_54682_toplvl_reg_write 420 * Purpose: 421 * Write to a top level register from a supporting chip 422 * Parameters: 423 * unit - SOC Unit #. 424 * port - Port number. 425 * flags - 426 * reg_offset - Offset to the reg 427 * data - Data to be written 428 * Returns: 429 * SOC_E_XXX 430 */ 431 int 432 phy_54682_toplvl_reg_write(int unit, soc_port_t port, int flags, uint8 reg_offset, uint16 data) 433 { 434 phy_ctrl_t *pc; 435 uint16 reg_data; 436 #ifdef BROADCOM_DEBUG 437 uint16 status; 438 #endif 439 int rv = SOC_E_NONE; 440 441 LOG_VERBOSE(BSL_LS_SOC_PHY, 442 (BSL_META_U(unit, 443 "entered phy_54682_toplvl_reg_write: " 444 "unit %d, port %d, flags %x reg_offset %u, data %u\n"), 445 unit, port, flags, reg_offset, data)); 446 447 pc = EXT_PHY_SW_STATE(unit, port); 448 449 /* Write Reg address to Port 5's register 0x1C, shadow 0x0B */ 450 /* Write data to Port 6's register 0x1C, shadow 0x0c */ 451 /* Status READ from Port 3's register 0x15 */ 452 453 /* Write Data to port6 (offset = 5), register 0x1C, shadow 0x0c */ 454 INT_MCU_LOCK(unit); 455 pc->phy_id = PHY54682_SLICE_ADDR(pc, 5); 456 reg_data = (0xB000 | (data & 0xff)); 457 rv = pc->write(unit, pc->phy_id, 0x1c, reg_data); 458 if (SOC_FAILURE(rv)) { 459 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 460 INT_MCU_UNLOCK(unit); 461 return rv; 462 } 463 464 pc->phy_id = PHY54682_SLICE_ADDR(pc, 4); 465 /* Write Reg address to Port 5's (offset = 4) register 0x1C, shadow 0x0B */ 466 /* Enable Write ( Port 5's register 0x1C, shadow 0x0B) Bit 7 = 1 */ 467 reg_data = (0xAC80 | reg_offset); 468 rv = pc->write(unit, pc->phy_id, 0x1c, reg_data); 469 if (SOC_FAILURE(rv)) { 470 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 471 INT_MCU_UNLOCK(unit); 472 return rv; 473 } 474 475 /* Disable Write ( Port 5's register 0x1C, shadow 0x0B) Bit 7 = 0 */ 476 reg_data = (0xAC00 | reg_offset); 477 rv = pc->write(unit, pc->phy_id, 0x1c, reg_data); 478 if (SOC_FAILURE(rv)) { 479 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 480 INT_MCU_UNLOCK(unit); 481 return rv; 482 } 483 484 #ifdef BROADCOM_DEBUG 485 pc->phy_id = PHY54682_SLICE_ADDR(pc, 2); 486 /* Read data from Top level MII Status register(0x15h) */ 487 rv = pc->write(unit, pc->phy_id, 0x17, 0x8F0B); 488 if (SOC_FAILURE(rv)) { 489 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 490 INT_MCU_UNLOCK(unit); 491 return rv; 492 } 493 rv = pc->read(unit, pc->phy_id, 0x15, &status); 494 495 if (SOC_FAILURE(rv)) { 496 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 497 INT_MCU_UNLOCK(unit); 498 return rv; 499 } 500 #endif 501 502 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 503 INT_MCU_UNLOCK(unit); 504 505 return SOC_E_NONE; 506 } 507 508 /* 509 * Function: 510 * _phy_54682_medium_check 511 * Purpose: 512 * Determine if chip should operate in copper or fiber mode. 513 * Parameters: 514 * unit - StrataSwitch unit #. 515 * port - StrataSwitch port #. 516 * medium - (OUT) SOC_PORT_MEDIUM_XXX 517 * Returns: 518 * SOC_E_XXX 519 */ 520 STATIC int 521 _phy_54682_medium_check(int unit, soc_port_t port, int *medium) 522 { 523 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 524 uint16 tmp = 0xffff; 525 526 *medium = SOC_PORT_MEDIUM_COPPER; 527 528 if (pc->automedium) { 529 /* Read Mode Register (0x1c shadow 11111) */ 530 SOC_IF_ERROR_RETURN 531 (READ_PHY54682_MODE_CTRLr(unit, pc, &tmp)); 532 533 if (pc->fiber.preferred) { 534 /* 0x10 Fiber Signal Detect 535 * 0x20 Copper Energy Detect 536 */ 537 if ((tmp & 0x30) == 0x20) { 538 /* Only copper is link up */ 539 *medium = SOC_PORT_MEDIUM_COPPER; 540 } else { 541 *medium = SOC_PORT_MEDIUM_FIBER; 542 } 543 } else { 544 if ((tmp & 0x30) == 0x10) { 545 /* Only fiber is link up */ 546 *medium = SOC_PORT_MEDIUM_FIBER; 547 } else { 548 *medium = SOC_PORT_MEDIUM_COPPER; 549 } 550 } 551 } else { 552 *medium = pc->fiber.preferred ? SOC_PORT_MEDIUM_FIBER: 553 SOC_PORT_MEDIUM_COPPER; 554 } 555 556 LOG_VERBOSE(BSL_LS_SOC_PHY, 557 (BSL_META_U(unit, 558 "_phy_54682_medium_check: " 559 "u=%d p=%d fiber_pref=%d 0x1c(11111)=%04x fiber=%d\n"), 560 unit, port, pc->fiber.preferred, tmp, 561 (*medium == SOC_PORT_MEDIUM_FIBER) ? 1 : 0)); 562 563 return SOC_E_NONE; 564 } 565 566 /* 567 * Function: 568 * phy_54682_medium_status 569 * Purpose: 570 * Indicate the current active medium 571 * Parameters: 572 * unit - StrataSwitch unit #. 573 * port - StrataSwitch port #. 574 * medium - (OUT) One of: 575 * SOC_PORT_MEDIUM_COPPER 576 * SOC_PORT_MEDIUM_FIBER 577 * Returns: 578 * SOC_E_NONE 579 */ 580 581 STATIC int 582 phy_54682_medium_status(int unit, soc_port_t port, soc_port_medium_t *medium) 583 { 584 if (PHY_COPPER_MODE(unit, port)) { 585 *medium = SOC_PORT_MEDIUM_COPPER; 586 } else { 587 *medium = SOC_PORT_MEDIUM_FIBER; 588 } 589 return SOC_E_NONE; 590 } 591 592 /* 593 * Function: 594 * _phy_54682_medium_config_update 595 * Purpose: 596 * Update the PHY with config parameters 597 * Parameters: 598 * unit - StrataSwitch unit #. 599 * port - StrataSwitch port #. 600 * cfg - Config structure. 601 * Returns: 602 * SOC_E_XXX 603 */ 604 605 STATIC int 606 _phy_54682_medium_config_update(int unit, soc_port_t port, 607 soc_phy_config_t *cfg) 608 { 609 SOC_IF_ERROR_RETURN 610 (phy_54682_speed_set(unit, port, cfg->force_speed)); 611 SOC_IF_ERROR_RETURN 612 (phy_54682_duplex_set(unit, port, cfg->force_duplex)); 613 SOC_IF_ERROR_RETURN 614 (phy_54682_master_set(unit, port, cfg->master)); 615 SOC_IF_ERROR_RETURN 616 (phy_54682_ability_advert_set(unit, port, &cfg->advert_ability)); 617 SOC_IF_ERROR_RETURN 618 (phy_54682_autoneg_set(unit, port, cfg->autoneg_enable)); 619 SOC_IF_ERROR_RETURN 620 (phy_54682_mdix_set(unit, port, cfg->mdix)); 621 622 return SOC_E_NONE; 623 } 624 625 /*********************************************************************** 626 * 627 * PHY54682 DRIVER ROUTINES 628 */ 629 630 /* 631 * Function: 632 * phy_54682_medium_config_set 633 * Purpose: 634 * Set the operating parameters that are automatically selected 635 * when medium switches type. 636 * Parameters: 637 * unit - StrataSwitch unit # 638 * port - Port number 639 * medium - SOC_PORT_MEDIUM_COPPER/FIBER 640 * cfg - Operating parameters 641 * Returns: 642 * SOC_E_XXX 643 */ 644 645 STATIC int 646 phy_54682_medium_config_set(int unit, soc_port_t port, 647 soc_port_medium_t medium, 648 soc_phy_config_t *cfg) 649 { 650 phy_ctrl_t *pc; 651 soc_phy_config_t *active_medium; /* Currently active medium */ 652 soc_phy_config_t *change_medium; /* Requested medium */ 653 soc_phy_config_t *other_medium; /* The other medium */ 654 int medium_update; 655 soc_port_mode_t advert_mask; 656 657 if (NULL == cfg) { 658 return SOC_E_PARAM; 659 } 660 661 pc = EXT_PHY_SW_STATE(unit, port); 662 medium_update = FALSE; 663 664 switch (medium) { 665 case SOC_PORT_MEDIUM_COPPER: 666 if (!pc->automedium) { 667 if (!PHY_COPPER_MODE(unit, port)) { 668 return SOC_E_UNAVAIL; 669 } 670 /* check if device is fiber capable before switching */ 671 if (cfg->preferred == 0) { 672 uint16 data; 673 674 SOC_IF_ERROR_RETURN 675 (READ_PHY54682_MODE_CTRLr(unit, pc, &data)); 676 677 /* return if not fiber capable*/ 678 if (!(data & 0x8)) { 679 return SOC_E_UNAVAIL; 680 } 681 } 682 } 683 684 change_medium = &pc->copper; 685 other_medium = &pc->fiber; 686 advert_mask = ADVERT_ALL_COPPER; 687 break; 688 case SOC_PORT_MEDIUM_FIBER: 689 if (!pc->automedium && !PHY_FIBER_MODE(unit, port)) { 690 return SOC_E_UNAVAIL; 691 } 692 change_medium = &pc->fiber; 693 other_medium = &pc->copper; 694 advert_mask = ADVERT_ALL_FIBER; 695 break; 696 default: 697 return SOC_E_PARAM; 698 } 699 700 /* 701 * Changes take effect immediately if the target medium is active or 702 * the preferred medium changes. 703 */ 704 if (change_medium->enable != cfg->enable) { 705 medium_update = TRUE; 706 } 707 if (change_medium->preferred != cfg->preferred) { 708 /* Make sure that only one medium is preferred */ 709 other_medium->preferred = !cfg->preferred; 710 medium_update = TRUE; 711 } 712 713 sal_memcpy(change_medium, cfg, sizeof(*change_medium)); 714 change_medium->autoneg_advert &= advert_mask; 715 716 if (medium_update) { 717 /* The new configuration may cause medium change. Check 718 * and update medium. 719 */ 720 SOC_IF_ERROR_RETURN 721 (_phy_54682_medium_change(unit, port, TRUE)); 722 } else { 723 active_medium = (PHY_COPPER_MODE(unit, port)) ? 724 &pc->copper : &pc->fiber; 725 if (active_medium == change_medium) { 726 /* If the medium to update is active, update the configuration */ 727 SOC_IF_ERROR_RETURN 728 (_phy_54682_medium_config_update(unit, port, change_medium)); 729 } 730 } 731 return SOC_E_NONE; 732 } 733 734 /* 735 * Function: 736 * phy_54682_medium_config_get 737 * Purpose: 738 * Get the operating parameters that are automatically selected 739 * when medium switches type. 740 * Parameters: 741 * unit - StrataSwitch unit # 742 * port - Port number 743 * medium - SOC_PORT_MEDIUM_COPPER/FIBER 744 * cfg - (OUT) Operating parameters 745 * Returns: 746 * SOC_E_XXX 747 */ 748 749 STATIC int 750 phy_54682_medium_config_get(int unit, soc_port_t port, 751 soc_port_medium_t medium, 752 soc_phy_config_t *cfg) 753 { 754 int rv; 755 phy_ctrl_t *pc; 756 757 pc = EXT_PHY_SW_STATE(unit, port); 758 rv = SOC_E_NONE; 759 760 switch (medium) { 761 case SOC_PORT_MEDIUM_COPPER: 762 if (pc->automedium || PHY_COPPER_MODE(unit, port)) { 763 sal_memcpy(cfg, &pc->copper, sizeof (*cfg)); 764 } else { 765 rv = SOC_E_UNAVAIL; 766 } 767 break; 768 case SOC_PORT_MEDIUM_FIBER: 769 if (pc->automedium || PHY_FIBER_MODE(unit, port)) { 770 sal_memcpy(cfg, &pc->fiber, sizeof (*cfg)); 771 } else { 772 rv = SOC_E_UNAVAIL; 773 } 774 break; 775 default: 776 rv = SOC_E_PARAM; 777 break; 778 } 779 780 return rv; 781 } 782 783 #define FIBER_POWER_UP 1 784 #define FIBER_POWER_DOWN 0 785 786 STATIC int 787 _phy_54685_fiber_power_control(int unit, phy_ctrl_t *pc, int power_up) 788 { 789 if ( PHY54682_DEV_PHY_SLICE_IS_LAST2(pc) ) { 790 /* WAR for the last 2 ports in the chip */ 791 if ( power_up ) { 792 /* Enable TX. Misc 1000-X Control Reg. (1C shadow 17h) bit[6]=0 */ 793 SOC_IF_ERROR_RETURN( 794 MODIFY_PHY54682_MISC_1000X_CONTROLr(unit, pc, 795 PHY_54682_MISC_1000X_SERDES_TX_ENABLE, 796 PHY_54682_MISC_1000X_SERDES_TX_MASK) ); 797 /* Reset PHY. 1000-x MII Control Reg. (1000X Reg. 00h) bit[15] */ 798 SOC_IF_ERROR_RETURN( 799 MODIFY_PHY54682_1000X_MII_CTRLr(unit, pc, 800 MII_CTRL_RESET, 801 MII_CTRL_RESET | MII_CTRL_PD) ); 802 } else { /* power down */ 803 /* Invert SD. Auto-Detect Medium Reg. (1C shadow 1eh) bit[8]=1 */ 804 SOC_IF_ERROR_RETURN 805 (MODIFY_PHY54682_AUTO_DETECT_MEDIUMr(unit, pc, 806 PHY_54682_AUTO_DETECT_MEDIUM_INVERT_SD, 807 PHY_54682_AUTO_DETECT_MEDIUM_INVERT_SD) ); 808 /* Disable TX. Misc 1000-X Control Reg. (1C shadow 17h) bit[6]=1 */ 809 SOC_IF_ERROR_RETURN( 810 MODIFY_PHY54682_MISC_1000X_CONTROLr(unit, pc, 811 PHY_54682_MISC_1000X_SERDES_TX_DISABLE, 812 PHY_54682_MISC_1000X_SERDES_TX_MASK) ); 813 } 814 815 } else { 816 /* normal power up/down sequence for first 6 ports */ 817 SOC_IF_ERROR_RETURN( 818 MODIFY_PHY54682_1000X_MII_CTRLr(unit, pc, 819 (power_up) ? 0 : MII_CTRL_PD, MII_CTRL_PD) ); 820 } 821 return SOC_E_NONE; 822 } 823 824 /* 825 * Function: 826 * _phy_54682_reset_setup 827 * Purpose: 828 * Function to reset the PHY and set up initial operating registers. 829 * Parameters: 830 * unit - StrataSwitch unit #. 831 * port - StrataSwitch port #. 832 * Returns: 833 * SOC_E_XXX 834 * Notes: 835 * Configures for copper/fiber according to the current 836 * setting of PHY_FLAGS_FIBER. 837 */ 838 839 STATIC int 840 _phy_54682_reset_setup(int unit, soc_port_t port) 841 { 842 phy_ctrl_t *pc; 843 soc_port_t primary_port; 844 int index; 845 846 pc = EXT_PHY_SW_STATE(unit, port); 847 848 /* Reset the PHY with previously registered callback function. */ 849 SOC_IF_ERROR_RETURN(soc_phy_reset(unit, port)); 850 851 if ( soc_phy_primary_and_offset_get(unit, port, &primary_port, &index) 852 == SOC_E_NONE ) { 853 /* determine the order of logical ports on a PHY chip */ 854 if ( index & 0x80 ) { 855 PHY54682_FLAGS(pc) |= ( PHY54682_PHYA_REV); /* reverse order */ 856 } else { 857 PHY54682_FLAGS(pc) &= (~PHY54682_PHYA_REV); /* normal order */ 858 } 859 } else { 860 /* config variable 'phy_port_primary_and_offset' not specified *\ 861 |* Assign default values in a 4-alignment basis : *| 862 |* e.g. port = 2 3 4 5 6 7 8 9 *| 863 |* index = 0 1 2 3 0 1 2 3 *| 864 \* primary_port = 2 2 2 2 6 6 6 6 */ 865 index = pc->phy_id & ( PHY54682_DEV_PHY_SLICE_MASK); 866 primary_port = ((port - index) <= 0) ? 0 : (port - index); 867 PHY54682_FLAGS(pc) &= (~PHY54682_PHYA_REV); /* normal order */ 868 LOG_WARN(BSL_LS_SOC_PHY, 869 (BSL_META_U(unit, 870 "Config property 'phy_port_primary_and_offset' " 871 "not set for unit %d, port %d. " 872 "Default to slice=0x%x, base=0x%x\n"), 873 unit, port, index, primary_port)); 874 } 875 pc->lane_num = index; 876 877 /* keep the original MDIO address. Set slice ID & base PHY address */ 878 /* Do not change the order to the following four lines */ 879 index &= ~0x80; /* clear reverse bit (PHYA_REV) */ 880 PHY54682_DEV_PHY_ID_ORIG(pc) = pc->phy_id; 881 PHY54682_DEV_PHY_SLICE(pc) = index; 882 PHY54682_DEV_SET_BASE_ADDR(pc); /* phy address of port 0 of this chip */ 883 884 SOC_IF_ERROR_RETURN 885 (phy_54682_control_set( unit, port, SOC_PHY_CONTROL_PORT_PRIMARY, 886 primary_port)); 887 SOC_IF_ERROR_RETURN 888 (phy_54682_control_set( unit, port, SOC_PHY_CONTROL_PORT_OFFSET, 889 index )); 890 /* Disable super-isolate */ 891 SOC_IF_ERROR_RETURN 892 (MODIFY_PHY54682_MII_POWER_CTRLr(unit, pc, 0x0, 1U<<5)); 893 894 /* BCM54682E is EEE capable */ 895 if ( PHY_IS_BCM54682E_OR_BCM54685E(pc) || PHY_IS_BCM54684E(pc) ) { 896 SOC_IF_ERROR_RETURN 897 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 7, 0x0000, 0x0003)); 898 PHY_FLAGS_SET(unit, port, PHY_FLAGS_EEE_CAPABLE); 899 900 SOC_IF_ERROR_RETURN 901 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0F7F,0x15, 0x0, 0x7)); /* exp 7f */ 902 } 903 904 if ( ECD_ENABLE && 905 ( ((PHY_IS_BCM54682E_OR_BCM54685E(pc)) || (PHY_IS_BCM54684E(pc))) && 906 ((pc->phy_rev & 0x7) > 0x2) ) ) { 907 SOC_IF_ERROR_RETURN( 908 phy_ecd_cable_diag_init(unit, port)); 909 } 910 911 SOC_IF_ERROR_RETURN(_phy_54682_no_reset_setup(unit, port)); 912 return SOC_E_NONE; 913 } 914 915 STATIC int 916 _phy_54682_no_reset_setup(int unit, soc_port_t port) 917 { 918 phy_ctrl_t *pc; 919 uint16 data, mask; 920 921 LOG_INFO(BSL_LS_SOC_PHY, 922 (BSL_META_U(unit, 923 "_phy_54682_reset_setup: u=%d p=%d medium=%s\n"), 924 unit, port, 925 PHY_COPPER_MODE(unit, port) ? "COPPER" : "FIBER")); 926 927 pc = EXT_PHY_SW_STATE(unit, port); 928 929 /* 930 * Workaround for BCM54682 B0 chip 931 * (not necessary for B1 and C0 chip) 932 * Description: BCM54682 defaults into the SGMII/QSGMII-to-copper split 933 * mode after reset. The BCM54682 device mode should default into the 934 * QSMII-to-Copper mode after reset. 935 */ 936 if(PHY_REVISION_CHECK(pc, PHY_BCM54682E_MODEL, PHY_BCM54682E_OUI, 0x0)) { 937 SOC_IF_ERROR_RETURN 938 (MODIFY_PHY54682_MODE_CTRLr(unit, pc, 0x0000, 0x0006)); 939 } 940 941 /* SGMII interface to MAC */ 942 943 /* soc_phy_reset has reset the phy, power down the unstrapped interface. *\ 944 \* Make sure enabled interfaces are powered up. */ 945 SOC_IF_ERROR_RETURN( 946 _phy_54685_fiber_power_control(unit, pc, FIBER_POWER_UP) ); 947 948 /* 1000Base-X FullDuplex will be clear after the phy been reset in 54682 */ 949 data = MII_CTRL_FD | MII_CTRL_SS_1000 | MII_CTRL_RAN | MII_CTRL_AE; 950 951 SOC_IF_ERROR_RETURN 952 (WRITE_PHY54682_1000X_MII_CTRLr(unit, pc, data)); 953 954 /* copper regs */ 955 if ( !pc->copper.enable || (!pc->automedium && pc->fiber.preferred) ) { 956 /* Copper interface is not used. Powered down. */ 957 SOC_IF_ERROR_RETURN 958 (MODIFY_PHY54682_MII_CTRLr(unit, pc, MII_CTRL_PD, MII_CTRL_PD)); 959 } else { 960 SOC_IF_ERROR_RETURN 961 (MODIFY_PHY54682_MII_CTRLr(unit, pc, 0, MII_CTRL_PD)); 962 SOC_IF_ERROR_RETURN 963 (WRITE_PHY54682_MII_GB_CTRLr(unit, pc, 964 MII_GB_CTRL_ADV_1000FD | MII_GB_CTRL_PT)); 965 SOC_IF_ERROR_RETURN 966 (WRITE_PHY54682_MII_CTRLr(unit, pc, 967 MII_CTRL_FD | MII_CTRL_SS_10 | 968 MII_CTRL_SS_100 | MII_CTRL_AE)); 969 } 970 971 /* Adjust timing and enable link speed led mode */ 972 SOC_IF_ERROR_RETURN 973 (MODIFY_PHY54682_SPARE_CTRLr(unit, pc, 0x0006, 0x0006)); 974 975 /* Power down SerDes */ 976 SOC_IF_ERROR_RETURN( 977 _phy_54685_fiber_power_control(unit, pc, FIBER_POWER_DOWN) ) ; 978 979 if (pc->fiber.enable && (pc->automedium || pc->fiber.preferred)) { 980 /* remove power down of SerDes */ 981 SOC_IF_ERROR_RETURN( 982 _phy_54685_fiber_power_control(unit, pc, FIBER_POWER_UP) ); 983 984 /* set the advertisement of serdes */ 985 /* Disable half-duplex, full-duplex capable */ 986 SOC_IF_ERROR_RETURN 987 (MODIFY_PHY54682_1000X_MII_ANAr(unit, pc, (1 << 5), 988 (1 << 5) | (1 << 6))); 989 /* Enable auto-detection between SGMII-slave and 1000BASE-X */ 990 SOC_IF_ERROR_RETURN 991 (MODIFY_PHY54682_SGMII_SLAVEr(unit, pc, 1, 1)); 992 993 /* Restart SerDes autonegotiation */ 994 SOC_IF_ERROR_RETURN 995 (WRITE_PHY54682_1000X_MII_CTRLr(unit, pc, 996 MII_CTRL_FD | MII_CTRL_SS_1000 | MII_CTRL_AE)); 997 998 switch (pc->fiber_detect) { 999 case 2: /* LED 2 */ 1000 case -2: 1001 case 4: /* LED 4 : kept for backward compatibility */ 1002 case -4: 1003 case 10: /* EN_10B for signal detect */ 1004 case -10: 1005 case 0: /* default */ 1006 /* GPIO Control/Status Register (0x1c shadow 01111) */ 1007 /* Change LED2 pin into an input */ 1008 SOC_IF_ERROR_RETURN 1009 (MODIFY_PHY54682_LED_GPIO_CTRLr(unit, pc, 0x08, 0x08)); 1010 break; 1011 case 1: /* PECL , no such pin in 54682 data sheet */ 1012 case -1: 1013 default: 1014 return SOC_E_CONFIG; 1015 } 1016 SOC_IF_ERROR_RETURN 1017 (MODIFY_PHY54682_MODE_CTRLr(unit, pc, 0x0002, 0x0006)); 1018 } 1019 1020 /* In BCM546682 the SD pin is internally tied. Ignore SD pin for 1021 proper operation. 1022 */ 1023 SOC_IF_ERROR_RETURN 1024 (MODIFY_PHY54682_MISC_1000X_CONTROLr(unit, pc, 0x0000, 0x0020)); 1025 1026 /* Configure Auto-detect Medium (0x1c shadow 11110) */ 1027 mask = 0x33f; /* Auto-detect bit mask */ 1028 data = 0; 1029 1030 /* In BCM546682 the SD pin is internally tied. For proper operation 1031 SD_INV and QUALIFY_SD_WITH_SYNC should be set. 1032 */ 1033 data = (1 << 8) | (1 << 5); 1034 1035 if (pc->automedium) { 1036 data |= 1 << 0; /* Enable auto-detect medium */ 1037 } 1038 1039 /* When no link partner exists, fiber should be default medium */ 1040 /* When both link partners exipc, fiber should be prefered medium 1041 * for the following reasons. 1042 * 1. Most fiber module generates signal detect when the fiber cable is 1043 * plugged in regardless of any activity even if the link partner is 1044 * powered down. 1045 * 2. Fiber mode consume much lesser power than copper mode. 1046 */ 1047 if (pc->fiber.preferred) { 1048 data |= 1 << 1; /* Fiber selected when both media are active */ 1049 data |= 1 << 2; /* Fiber selected when no medium is active */ 1050 } 1051 1052 SOC_IF_ERROR_RETURN 1053 (MODIFY_PHY54682_AUTO_DETECT_MEDIUMr(unit, pc, data, mask)); 1054 1055 #if AUTO_MDIX_WHEN_AN_DIS 1056 /* Enable Auto-MDIX When autoneg disabled */ 1057 SOC_IF_ERROR_RETURN 1058 (MODIFY_PHY54682_MII_MISC_CTRLr(unit, pc, 0x200, 0x200)); 1059 #endif 1060 1061 /* 1062 * Configure 1000X control2 register (0x8301 Bit[7] = 1) to turn off 1063 * carrier extension. The Intel 7131 NIC does not accept carrier 1064 * extension and gets CRC errors. 1065 */ 1066 if(pc->lane_num == 0){ 1067 /* The phy address of QSGMII is the phy address pins + 8 */ 1068 pc->phy_id = pc->phy_id + 8; 1069 1070 SOC_IF_ERROR_RETURN 1071 (PHY54682_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS, 1072 0x0000, 0x1f, 0xffd0)); 1073 SOC_IF_ERROR_RETURN 1074 (PHY54682_REG_WRITE(unit, pc, 0x00, 0x0000, 0x1e, 0x1f)); 1075 SOC_IF_ERROR_RETURN 1076 (PHY54682_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS, 1077 0x0000, 0x1f, 0x8300)); 1078 SOC_IF_ERROR_RETURN 1079 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x11, 0x0080, 0x0080)); 1080 1081 /* QSGMII FIFO settings */ 1082 SOC_IF_ERROR_RETURN 1083 (PHY54682_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS, 1084 0x0000, 0x1f, 0xffd0)); 1085 SOC_IF_ERROR_RETURN 1086 (PHY54682_REG_WRITE(unit, pc, 0x00, 0x0000, 0x1e, 0x1f)); 1087 SOC_IF_ERROR_RETURN 1088 (PHY54682_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS, 1089 0x0000, 0x1f, 0x8330)); 1090 SOC_IF_ERROR_RETURN 1091 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x1c, 0x0080, 0x0080)); 1092 1093 1094 if (PHY_IS_BCM54682E_OR_BCM54685E(pc) || PHY_IS_BCM54684E(pc)) { 1095 /* Enable LPI pass through on PHY for native EEE */ 1096 SOC_IF_ERROR_RETURN 1097 (phy_reg_aer_modify(unit, pc, 0x833e, 0xc000, 0xc000)); 1098 } 1099 1100 /* Revert the phy_id */ 1101 pc->phy_id = pc->phy_id - 8; 1102 } 1103 1104 /* Configure extended control register for led mode and jumbo frame support 1105 */ 1106 mask = (1 << 5) | (1 << 0); 1107 1108 /* if using led link/activity mode, disable led traffic mode */ 1109 if (pc->ledctrl & 0x10 || pc->ledselect == 0x01) { 1110 data = 0; 1111 } else { 1112 data = 1 << 5; /* Enable LEDs to indicate traffic status */ 1113 } 1114 /* Configure Extended Control Register for Jumbo frames support */ 1115 data |= 1 << 0; /* Set high FIFO elasticity to support jumbo frames */ 1116 SOC_IF_ERROR_RETURN 1117 (MODIFY_PHY54682_MII_ECRr(unit, pc, data, mask)); 1118 1119 /* Enable extended packet length (4.5k through 25k) */ 1120 SOC_IF_ERROR_RETURN 1121 (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0x4000, 0x4000)); 1122 1123 SOC_IF_ERROR_RETURN 1124 (MODIFY_PHY54682_MISC_1000X_CTRL2r(unit, pc, 0x0001, 0x0001)); 1125 1126 SOC_IF_ERROR_RETURN 1127 (MODIFY_PHY54682_AUX_CTRLr(unit, pc, 0x0002, 0x0002)); 1128 1129 /* Configure LED selectors */ 1130 data = ((pc->ledmode[1] & 0xf) << 4) | (pc->ledmode[0] & 0xf); 1131 SOC_IF_ERROR_RETURN 1132 (WRITE_PHY54682_LED_SELECTOR_1r(unit, pc, data)); 1133 1134 data = ((pc->ledmode[3] & 0xf) << 4) | (pc->ledmode[2] & 0xf); 1135 SOC_IF_ERROR_RETURN 1136 (WRITE_PHY54682_LED_SELECTOR_2r(unit, pc, data)); 1137 1138 data = (pc->ledctrl & 0x3ff); 1139 SOC_IF_ERROR_RETURN 1140 (WRITE_PHY54682_LED_CTRLr(unit, pc, data)); 1141 1142 SOC_IF_ERROR_RETURN 1143 (WRITE_PHY54682_EXP_LED_SELECTORr(unit, pc, pc->ledselect)); 1144 1145 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 1146 return SOC_E_NONE; 1147 } 1148 1149 /* 100BASE-TX initialization change for EEE and autogreen mode */ 1150 SOC_IF_ERROR_RETURN 1151 (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0x0c00, 0x0c00)); 1152 SOC_IF_ERROR_RETURN( 1153 WRITE_PHY_REG(unit, pc, 0x17, 0x4022)); 1154 SOC_IF_ERROR_RETURN( 1155 WRITE_PHY_REG(unit, pc, 0x15, 0x017b)); 1156 SOC_IF_ERROR_RETURN 1157 (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0x0400, 0x0c00)); 1158 1159 return SOC_E_NONE; 1160 } 1161 1162 /* 1163 * Function: 1164 * phy_54682_init 1165 * Purpose: 1166 * Init function for 54682 PHY. 1167 * Parameters: 1168 * unit - StrataSwitch unit #. 1169 * port - StrataSwitch port #. 1170 * Returns: 1171 * SOC_E_NONE 1172 */ 1173 1174 STATIC int 1175 phy_54682_init(int unit, soc_port_t port) 1176 { 1177 phy_ctrl_t *pc; 1178 int fiber_capable; 1179 int fiber_preferred; 1180 1181 LOG_INFO(BSL_LS_SOC_PHY, 1182 (BSL_META_U(unit, 1183 "phy_54682_init: u=%d p=%d\n"), 1184 unit, port)); 1185 1186 /* Only SGMII interface to switch MAC is supported */ 1187 if (IS_GMII_PORT(unit, port)) { 1188 return SOC_E_CONFIG; 1189 } 1190 1191 pc = EXT_PHY_SW_STATE(unit, port); 1192 pc->interface = SOC_PORT_IF_SGMII; 1193 1194 fiber_capable = 1; 1195 1196 fiber_preferred = 1197 soc_property_port_get(unit, port, spn_PHY_FIBER_PREF, 0); 1198 pc->automedium = 1199 soc_property_port_get(unit, port, spn_PHY_AUTOMEDIUM, 0); 1200 pc->fiber_detect = 1201 soc_property_port_get(unit, port, spn_PHY_FIBER_DETECT, -4); 1202 1203 LOG_INFO(BSL_LS_SOC_PHY, 1204 (BSL_META_U(unit, 1205 "phy_54682_init: " 1206 "u=%d p=%d type=54682%s automedium=%d fiber_pref=%d detect=%d\n"), 1207 unit, port, fiber_capable ? "S" : "", 1208 pc->automedium, fiber_preferred, pc->fiber_detect)); 1209 1210 pc->copper.enable = TRUE; 1211 pc->copper.preferred = !fiber_preferred; 1212 pc->copper.autoneg_enable = TRUE; 1213 pc->copper.autoneg_advert = ADVERT_ALL_COPPER; 1214 SOC_IF_ERROR_RETURN 1215 (_phy_54682_ability_cu_local_get(unit, port, &(pc->copper.advert_ability))); 1216 pc->copper.force_speed = 1000; 1217 pc->copper.force_duplex = TRUE; 1218 pc->copper.master = SOC_PORT_MS_AUTO; 1219 pc->copper.mdix = SOC_PORT_MDIX_AUTO; 1220 1221 pc->fiber.enable = fiber_capable; 1222 pc->fiber.preferred = fiber_preferred; 1223 pc->fiber.autoneg_enable = fiber_capable; 1224 pc->fiber.autoneg_advert = ADVERT_ALL_FIBER; 1225 SOC_IF_ERROR_RETURN 1226 (_phy_54682_ability_fiber_local_get(unit, port, &(pc->fiber.advert_ability))); 1227 pc->copper.advert_ability.medium = SOC_PA_MEDIUM_FIBER; 1228 pc->fiber.force_speed = 1000; 1229 pc->fiber.force_duplex = TRUE; 1230 pc->fiber.master = SOC_PORT_MS_NONE; 1231 pc->fiber.mdix = SOC_PORT_MDIX_NORMAL; 1232 1233 /* Initially configure for the preferred medium. */ 1234 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_COPPER); 1235 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER); 1236 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_PASSTHRU); 1237 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX); 1238 PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_ENABLED); 1239 PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_MODE); 1240 1241 if (pc->fiber.preferred) { 1242 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER); 1243 } else { 1244 PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER); 1245 } 1246 1247 /* Get Requested LED selectors (defaults are hardware defaults) */ 1248 pc->ledmode[0] = soc_property_port_get(unit, port, spn_PHY_LED1_MODE, 0); 1249 pc->ledmode[1] = soc_property_port_get(unit, port, spn_PHY_LED2_MODE, 1); 1250 pc->ledmode[2] = soc_property_port_get(unit, port, spn_PHY_LED3_MODE, 3); 1251 pc->ledmode[3] = soc_property_port_get(unit, port, spn_PHY_LED4_MODE, 6); 1252 pc->ledctrl = soc_property_port_get(unit, port, spn_PHY_LED_CTRL, 0x8); 1253 pc->ledselect = soc_property_port_get(unit, port, spn_PHY_LED_SELECT, 0); 1254 1255 SOC_IF_ERROR_RETURN 1256 (_phy_54682_reset_setup(unit, port)); 1257 1258 SOC_IF_ERROR_RETURN 1259 (_phy_54682_medium_config_update(unit, port, 1260 PHY_COPPER_MODE(unit, port) ? 1261 &pc->copper : 1262 &pc->fiber)); 1263 return SOC_E_NONE; 1264 } 1265 1266 /* 1267 * Function: 1268 * phy_54682_enable_set 1269 * Purpose: 1270 * Enable or disable the physical interface. 1271 * Parameters: 1272 * unit - StrataSwitch unit #. 1273 * port - StrataSwitch port #. 1274 * enable - Boolean, true = enable PHY, false = disable. 1275 * Returns: 1276 * SOC_E_XXX 1277 */ 1278 1279 STATIC int 1280 phy_54682_enable_set(int unit, soc_port_t port, int enable) 1281 { 1282 uint16 power, mii_stat; 1283 soc_timeout_t to; 1284 phy_ctrl_t *pc; 1285 1286 pc = EXT_PHY_SW_STATE(unit, port); 1287 power = (enable) ? 0 : MII_CTRL_PD; 1288 1289 /* Do not incorrectly Power up the interface if medium is disabled and 1290 * global enable = true 1291 */ 1292 if (pc->copper.enable && (pc->automedium || PHY_COPPER_MODE(unit, port))) { 1293 SOC_IF_ERROR_RETURN 1294 (MODIFY_PHY54682_MII_CTRLr(unit, pc, power, MII_CTRL_PD)); 1295 1296 if (!enable) { 1297 if ((PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) && 1298 ((pc->phy_rev & 0x4) == 0x0) ){ /* A0,A1,B0,B1 */ 1299 soc_timeout_init(&to, 2000000, 0); 1300 do { 1301 SOC_IF_ERROR_RETURN 1302 (READ_PHY54682_MII_STATr(unit, pc, &mii_stat)); 1303 if (soc_timeout_check(&to)) { 1304 LOG_WARN(BSL_LS_SOC_PHY, 1305 (BSL_META_U(unit, 1306 "phy54682.c: copper link didn't go down after power down: u=%d p=%d\n"), 1307 unit, port)); 1308 break; 1309 } 1310 } while(mii_stat & MII_STAT_LA); 1311 } 1312 } 1313 1314 LOG_INFO(BSL_LS_SOC_PHY, 1315 (BSL_META_U(unit, 1316 "phy_54682_enable_set: " 1317 "Power %s copper medium\n"), (enable) ? "up" : "down")); 1318 } 1319 1320 if (pc->fiber.enable && (pc->automedium || PHY_FIBER_MODE(unit, port))) { 1321 SOC_IF_ERROR_RETURN( 1322 _phy_54685_fiber_power_control(unit, pc, enable) ); 1323 /* 1324 * When enable/disable the fiber port, 1325 * the Tx disable bit of Expansion register 0x52 should be set also. 1326 * Otherwise the following issue happens. 1327 * After the fiber port is powered down 1328 * (verified bit 11 MII cotnrol register 0 is set to 1), 1329 * the link partner still shows linkup 1330 */ 1331 SOC_IF_ERROR_RETURN 1332 (MODIFY_PHY54682_EXP_SERDES_SGMII_RX_CTRLr(unit, pc, enable?0:1, 0x1)); 1333 SOC_IF_ERROR_RETURN 1334 (MODIFY_PHY54682_EXP_SERDES_SGMII_CTRLr(unit, pc, enable?0:1, 0x1)); 1335 1336 if (!enable) { 1337 soc_timeout_init(&to, 2000000, 0); 1338 do { 1339 SOC_IF_ERROR_RETURN 1340 (READ_PHY54682_1000X_MII_STATr(unit, pc, &mii_stat)); 1341 1342 if (soc_timeout_check(&to)) { 1343 LOG_WARN(BSL_LS_SOC_PHY, 1344 (BSL_META_U(unit, 1345 "phy54682.c: fiber link didn't go down after power down: u=%d p=%d\n"), 1346 unit, port)); 1347 break; 1348 } 1349 } while(mii_stat & MII_STAT_LA); 1350 } 1351 1352 LOG_INFO(BSL_LS_SOC_PHY, 1353 (BSL_META_U(unit, 1354 "phy_54682_enable_set: " 1355 "Power %s fiber medium\n"), (enable) ? "up" : "down")); 1356 } 1357 1358 /* Update software state */ 1359 SOC_IF_ERROR_RETURN(phy_fe_ge_enable_set(unit, port, enable)); 1360 1361 return SOC_E_NONE; 1362 } 1363 1364 /* 1365 * Function: 1366 * phy_54682_enable_get 1367 * Purpose: 1368 * Enable or disable the physical interface for a 54682 device. 1369 * Parameters: 1370 * unit - StrataSwitch unit #. 1371 * port - StrataSwitch port #. 1372 * enable - (OUT) Boolean, true = enable PHY, false = disable. 1373 * Returns: 1374 * SOC_E_XXX 1375 */ 1376 1377 STATIC int 1378 phy_54682_enable_get(int unit, soc_port_t port, int *enable) 1379 { 1380 return phy_fe_ge_enable_get(unit, port, enable); 1381 } 1382 1383 /* 1384 * Function: 1385 * _phy_54682_fiber_100fx_setup 1386 * Purpose: 1387 * Switch from 1000X mode to 100FX. 1388 * Parameters: 1389 * unit - StrataSwitch unit #. 1390 * port - StrataSwitch port #. 1391 * Returns: 1392 * SOC_E_XXX 1393 */ 1394 STATIC int 1395 _phy_54682_fiber_100fx_setup(int unit, soc_port_t port) 1396 { 1397 phy_ctrl_t *pc; 1398 1399 pc = EXT_PHY_SW_STATE(unit, port); 1400 1401 LOG_VERBOSE(BSL_LS_SOC_PHY, 1402 (BSL_META_U(unit, 1403 "_phy_54682_1000x_to_100fx: u=%d p=%d \n"), 1404 unit, port)); 1405 1406 /* Power up the SerDes */ 1407 SOC_IF_ERROR_RETURN( 1408 _phy_54685_fiber_power_control(unit, pc, 1409 PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE) 1410 ? FIBER_POWER_DOWN : FIBER_POWER_UP) ); 1411 1412 /* Operate SerDes in 100FX */ 1413 1414 /* SerDes 100FX control register - register 1CH shadow 13H *\ 1415 \* bit[0]: 100FX link SerDes enable , bit[1]: 100FX SerDes full duplex */ 1416 if(pc->fiber.force_duplex) { 1417 SOC_IF_ERROR_RETURN 1418 (MODIFY_PHY54682_SERDES_100FX_CTRLr(unit, pc, 0x3, 0x3)); 1419 } else { 1420 SOC_IF_ERROR_RETURN 1421 (MODIFY_PHY54682_SERDES_100FX_CTRLr(unit, pc, 0x1, 0x3)); 1422 } 1423 1424 /* Set speed/AN/duplex. 1000-x MII Control Reg. (1000X Reg. 00h) */ 1425 SOC_IF_ERROR_RETURN 1426 (WRITE_PHY54682_1000X_MII_CTRLr(unit, pc, 1427 MII_CTRL_AE | MII_CTRL_FD | MII_CTRL_SS_100) ); 1428 1429 PHY_FLAGS_SET(unit, port, PHY_FLAGS_100FX); 1430 pc->fiber.autoneg_enable = FALSE; 1431 1432 return SOC_E_NONE; 1433 } 1434 1435 /* 1436 * Function: 1437 * _phy_54682_fiber_1000x_setup 1438 * Purpose: 1439 * Switch from 100FX mode to 1000X. 1440 * Parameters: 1441 * unit - StrataSwitch unit #. 1442 * port - StrataSwitch port #. 1443 * Returns: 1444 * SOC_E_XXX 1445 */ 1446 STATIC int 1447 _phy_54682_fiber_1000x_setup(int unit, soc_port_t port) 1448 { 1449 uint16 data; 1450 phy_ctrl_t *pc; 1451 1452 pc = EXT_PHY_SW_STATE(unit, port); 1453 1454 LOG_VERBOSE(BSL_LS_SOC_PHY, 1455 (BSL_META_U(unit, 1456 "_phy_54682_fiber_1000x_setup: u=%d p=%d \n"), 1457 unit, port)); 1458 1459 /* Power up the SerDes */ 1460 SOC_IF_ERROR_RETURN( 1461 _phy_54685_fiber_power_control(unit, pc, 1462 PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE) 1463 ? FIBER_POWER_DOWN : FIBER_POWER_UP) ); 1464 1465 /* Operate SerDes in 1000X */ 1466 SOC_IF_ERROR_RETURN 1467 (MODIFY_PHY54682_SERDES_100FX_CTRLr(unit, pc, 0x0, 0x1)); 1468 if (pc->fiber.autoneg_enable) { 1469 data = MII_CTRL_AE | MII_CTRL_RAN | MII_CTRL_FD | MII_CTRL_SS_1000; 1470 } else { 1471 data = MII_CTRL_RAN | MII_CTRL_FD | MII_CTRL_SS_1000; 1472 } 1473 SOC_IF_ERROR_RETURN 1474 (WRITE_PHY54682_1000X_MII_CTRLr(unit, pc, data)); 1475 1476 /* When speed is 1000Mbps, set duplex to HD mode. *\ 1477 \* This is because our MAC does not support 1G half duplex. */ 1478 pc->fiber.force_duplex = TRUE; 1479 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX); 1480 1481 return SOC_E_NONE; 1482 } 1483 1484 STATIC int 1485 _phy_54682_medium_change(int unit, soc_port_t port, int force_update) 1486 { 1487 phy_ctrl_t *pc; 1488 int medium; 1489 1490 pc = EXT_PHY_SW_STATE(unit, port); 1491 1492 SOC_IF_ERROR_RETURN 1493 (_phy_54682_medium_check(unit, port, &medium)); 1494 1495 if (medium == SOC_PORT_MEDIUM_COPPER) { 1496 if ((!PHY_COPPER_MODE(unit, port)) || force_update) { /* Was fiber */ 1497 PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER); 1498 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER); 1499 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX); 1500 PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 1501 /* BCM54682E is EEE capable */ 1502 if (PHY_IS_BCM54682E_OR_BCM54685E(pc) || PHY_IS_BCM54684E(pc)) { 1503 PHY_FLAGS_SET(unit, port, PHY_FLAGS_EEE_CAPABLE); 1504 } 1505 SOC_IF_ERROR_RETURN 1506 (_phy_54682_no_reset_setup(unit, port)); 1507 1508 /* Do not power up the interface if medium is disabled. */ 1509 if (pc->copper.enable) { 1510 SOC_IF_ERROR_RETURN 1511 (_phy_54682_medium_config_update(unit, port, &pc->copper)); 1512 } 1513 LOG_INFO(BSL_LS_SOC_PHY, 1514 (BSL_META_U(unit, 1515 "_phy_54682_link_auto_detect: u=%d p=%d [F->C]\n"), 1516 unit, port)); 1517 } 1518 1519 } else { /* Fiber */ 1520 if (PHY_COPPER_MODE(unit, port) || force_update) { /* Was copper */ 1521 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_COPPER); 1522 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_EEE_CAPABLE); 1523 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER); 1524 PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 1525 SOC_IF_ERROR_RETURN 1526 (_phy_54682_no_reset_setup(unit, port)); 1527 1528 /* 1529 * When enable/disable the fiber port, 1530 * the Tx disable bit of Expansion register 0x52 should be set also. 1531 * Otherwise the following issue happens. 1532 * After the fiber port is powered down 1533 * (verified bit 11 MII cotnrol register 0 is set to 1), 1534 * the link partner still shows linkup 1535 */ 1536 SOC_IF_ERROR_RETURN 1537 (MODIFY_PHY54682_EXP_SERDES_SGMII_RX_CTRLr(unit, pc, 1538 pc->fiber.enable?0:1, 0x1)); 1539 SOC_IF_ERROR_RETURN 1540 (MODIFY_PHY54682_EXP_SERDES_SGMII_CTRLr(unit, pc, 1541 pc->fiber.enable?0:1, 0x1)); 1542 1543 if (pc->fiber.enable) { 1544 SOC_IF_ERROR_RETURN 1545 (_phy_54682_medium_config_update(unit, port, &pc->fiber)); 1546 } 1547 LOG_INFO(BSL_LS_SOC_PHY, 1548 (BSL_META_U(unit, 1549 "_phy_54682_link_auto_detect: u=%d p=%d [C->F]\n"), 1550 unit, port)); 1551 } 1552 } 1553 return SOC_E_NONE; 1554 } 1555 1556 /* 1557 * Function: 1558 * phy_54682_link_get 1559 * Purpose: 1560 * Determine the current link up/down status for a 54682 device. 1561 * Parameters: 1562 * unit - StrataSwitch unit #. 1563 * port - StrataSwitch port #. 1564 * link - (OUT) Boolean, true indicates link established. 1565 * Returns: 1566 * SOC_E_XXX 1567 * Notes: 1568 * If using automedium, also switches the mode. 1569 */ 1570 STATIC int 1571 phy_54682_link_get(int unit, soc_port_t port, int *link) 1572 { 1573 phy_ctrl_t *pc; 1574 uint16 data; 1575 uint16 mask; 1576 1577 pc = EXT_PHY_SW_STATE(unit, port); 1578 *link = FALSE; /* Default return */ 1579 1580 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) { 1581 return SOC_E_NONE; 1582 } 1583 1584 if (!pc->fiber.enable && !pc->copper.enable) { 1585 return SOC_E_NONE; 1586 } 1587 1588 SOC_IF_ERROR_RETURN 1589 (READ_PHY54682_EXP_OPT_MODE_STATr(unit, pc, &data)); 1590 1591 if (!(data & (1U << 5))) { /* no sync */ 1592 SOC_IF_ERROR_RETURN 1593 (READ_PHY54682_1000X_MII_ANPr(unit, pc, &data)); 1594 1595 if (data & MII_ANP_SGMII_MODE) { /* Link partner is SGMII master */ 1596 /* Disable auto-detection between SGMII-slave and 1000BASE-X and set mode to 1000BASE-X */ 1597 SOC_IF_ERROR_RETURN 1598 (MODIFY_PHY54682_SGMII_SLAVEr(unit, pc, 0, 0x3)); 1599 1600 /* Now enable auto-detection between SGMII-slave and 1000BASE-X */ 1601 SOC_IF_ERROR_RETURN 1602 (MODIFY_PHY54682_SGMII_SLAVEr(unit, pc, 1, 1)); 1603 } 1604 } 1605 1606 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 1607 if ( pc->automedium ) { 1608 /* Check for medium change and update HW/SW accordingly. */ 1609 SOC_IF_ERROR_RETURN 1610 (_phy_54682_medium_change(unit, port,FALSE)); 1611 } 1612 if (PHY_COPPER_MODE(unit, port)) { 1613 SOC_IF_ERROR_RETURN(phy_fe_ge_link_get(unit, port, link)); 1614 } else { 1615 SOC_IF_ERROR_RETURN 1616 (READ_PHY54682_1000X_MII_STATr(unit, pc, &data)); 1617 *link = (data & MII_STAT_LA) ? TRUE : FALSE; 1618 } 1619 1620 /* If preferred medium is up, disable the other medium 1621 * to prevent false link. */ 1622 if ( pc->automedium ) { 1623 mask = MII_CTRL_PD; 1624 1625 if ( pc->copper.preferred ) { 1626 if ( pc->fiber.enable ) { 1627 /* power down the serdes if copper preferred && copper is up */ 1628 data = (*link && PHY_COPPER_MODE(unit, port)) 1629 ? FIBER_POWER_DOWN : FIBER_POWER_UP; 1630 } else { 1631 /* fiber is disabled, power down the serdes */ 1632 data = FIBER_POWER_DOWN; 1633 } 1634 SOC_IF_ERROR_RETURN( 1635 _phy_54685_fiber_power_control(unit, pc, data) ); 1636 1637 } else { /* pc->fiber.preferred */ 1638 if ( pc->copper.enable ) { 1639 data = (*link && PHY_FIBER_MODE(unit, port)) ? MII_CTRL_PD : 0; 1640 } else { 1641 data = MII_CTRL_PD; 1642 } 1643 SOC_IF_ERROR_RETURN 1644 (MODIFY_PHY54682_MII_CTRLr(unit, pc, data, mask)); 1645 } 1646 } 1647 1648 LOG_VERBOSE(BSL_LS_SOC_PHY, 1649 (BSL_META_U(unit, 1650 "phy_54682_link_get: u=%d p=%d mode=%s%s link=%d\n"), 1651 unit, port, 1652 PHY_COPPER_MODE(unit, port) ? "C" : "F", 1653 PHY_FIBER_100FX_MODE(unit, port)? "(100FX)" : "", 1654 *link)); 1655 1656 return SOC_E_NONE; 1657 } 1658 1659 /* 1660 * Function: 1661 * phy_54682_duplex_set 1662 * Purpose: 1663 * Set the current duplex mode (forced). 1664 * Parameters: 1665 * unit - StrataSwitch unit #. 1666 * port - StrataSwitch port #. 1667 * duplex - Boolean, true indicates full duplex, false indicates half. 1668 * Returns: 1669 * SOC_E_NONE 1670 * SOC_E_UNAVAIL - Half duplex requested, and not supported. 1671 * Notes: 1672 * The duplex is set only for the ACTIVE medium. 1673 * No synchronization performed at this level. 1674 * Autonegotiation is not manipulated. 1675 */ 1676 1677 STATIC int 1678 phy_54682_duplex_set(int unit, soc_port_t port, int duplex) 1679 { 1680 int rv; 1681 phy_ctrl_t *pc; 1682 1683 pc = EXT_PHY_SW_STATE(unit, port); 1684 rv = SOC_E_NONE; 1685 if (PHY_COPPER_MODE(unit, port)) { 1686 /* Note: mac.c uses phy_5690_notify_duplex to update 5690 */ 1687 rv = phy_fe_ge_duplex_set(unit, port, duplex); 1688 if (SOC_SUCCESS(rv)) { 1689 pc->copper.force_duplex = duplex; 1690 } 1691 } else { /* Fiber */ 1692 if (PHY_FIBER_100FX_MODE(unit, port)) { 1693 SOC_IF_ERROR_RETURN 1694 (MODIFY_PHY54682_SERDES_100FX_CTRLr(unit, pc, duplex? 0x2:0x0, 0x2)); 1695 pc->fiber.force_duplex = duplex; 1696 } else { 1697 if(!duplex) { 1698 return SOC_E_UNAVAIL; 1699 } 1700 } 1701 } 1702 1703 LOG_INFO(BSL_LS_SOC_PHY, 1704 (BSL_META_U(unit, 1705 "phy_54682_duplex_set: u=%d p=%d d=%d rv=%d\n"), 1706 unit, port, duplex, rv)); 1707 1708 return rv; 1709 } 1710 1711 /* 1712 * Function: 1713 * phy_54682_duplex_get 1714 * Purpose: 1715 * Get the current operating duplex mode. If autoneg is enabled, 1716 * then operating mode is returned, otherwise forced mode is returned. 1717 * Parameters: 1718 * unit - StrataSwitch unit #. 1719 * port - StrataSwitch port #. 1720 * duplex - (OUT) Boolean, true indicates full duplex, false 1721 * indicates half. 1722 * Returns: 1723 * SOC_E_NONE 1724 * Notes: 1725 * The duplex is retrieved for the ACTIVE medium. 1726 * No synchronization performed at this level. Autonegotiation is 1727 * not manipulated. 1728 */ 1729 1730 STATIC int 1731 phy_54682_duplex_get(int unit, soc_port_t port, int *duplex) 1732 { 1733 phy_ctrl_t *pc; 1734 uint16 opt_mode; 1735 1736 pc = EXT_PHY_SW_STATE(unit, port); 1737 1738 if (PHY_COPPER_MODE(unit, port)) { 1739 return phy_fe_ge_duplex_get(unit, port, duplex); 1740 } else { /* Fiber (1000BaseX, 100BaseFX, SGMII-Slave */ 1741 SOC_IF_ERROR_RETURN 1742 (READ_PHY54682_EXP_OPT_MODE_STATr(unit, pc, &opt_mode)); 1743 /* The bit 12 of register EXP_OPT_MODE_STAT is serdes duplex */ 1744 *duplex = (opt_mode & 0x1000) ? TRUE : FALSE; 1745 } 1746 1747 return SOC_E_NONE; 1748 } 1749 1750 /* 1751 * Function: 1752 * phy_54682_speed_set 1753 * Purpose: 1754 * Set the current operating speed (forced). 1755 * Parameters: 1756 * unit - StrataSwitch unit #. 1757 * port - StrataSwitch port #. 1758 * speed - Requested speed, only 1000 supported. 1759 * Returns: 1760 * SOC_E_XXX 1761 * Notes: 1762 * The speed is set only for the ACTIVE medium. 1763 */ 1764 1765 STATIC int 1766 phy_54682_speed_set(int unit, soc_port_t port, int speed) 1767 { 1768 int rv; 1769 phy_ctrl_t *pc; 1770 1771 pc = EXT_PHY_SW_STATE(unit, port); 1772 rv = SOC_E_NONE; 1773 if (PHY_COPPER_MODE(unit, port)) { 1774 /* Note: mac.c uses phy_5690_notify_speed to update 5690 */ 1775 rv = phy_fe_ge_speed_set(unit, port, speed); 1776 if (SOC_SUCCESS(rv)) { 1777 pc->copper.force_speed = speed; 1778 } 1779 } else { /* Fiber */ 1780 if (speed == 100) { 1781 rv = _phy_54682_fiber_100fx_setup(unit, port); 1782 } else if (speed == 0 || speed == 1000) { 1783 rv = _phy_54682_fiber_1000x_setup(unit, port); 1784 } else { 1785 rv = SOC_E_CONFIG; 1786 } 1787 if (SOC_SUCCESS(rv)) { 1788 pc->fiber.force_speed = speed; 1789 } 1790 } 1791 1792 LOG_INFO(BSL_LS_SOC_PHY, 1793 (BSL_META_U(unit, 1794 "phy_54682_speed_set: u=%d p=%d s=%d fiber=%d rv=%d\n"), 1795 unit, port, speed, PHY_FIBER_MODE(unit, port), rv)); 1796 1797 return rv; 1798 } 1799 1800 /* 1801 * Function: 1802 * phy_54682_speed_get 1803 * Purpose: 1804 * Get the current operating speed for a 54682 device. 1805 * Parameters: 1806 * unit - StrataSwitch unit #. 1807 * port - StrataSwitch port #. 1808 * duplex - (OUT) Boolean, true indicates full duplex, false 1809 * indicates half. 1810 * Returns: 1811 * SOC_E_NONE 1812 * Notes: 1813 * The speed is retrieved for the ACTIVE medium. 1814 */ 1815 1816 STATIC int 1817 phy_54682_speed_get(int unit, soc_port_t port, int *speed) 1818 { 1819 phy_ctrl_t *pc; 1820 uint16 opt_mode; 1821 1822 pc = EXT_PHY_SW_STATE(unit, port); 1823 1824 if (PHY_COPPER_MODE(unit, port)) { 1825 return phy_fe_ge_speed_get(unit, port, speed); 1826 } else { 1827 *speed = 1000; 1828 SOC_IF_ERROR_RETURN 1829 (READ_PHY54682_EXP_OPT_MODE_STATr(unit, pc, &opt_mode)); 1830 switch(opt_mode & (0x3 << 13)) { 1831 case (0 << 13): 1832 *speed = 10; 1833 break; 1834 case (1 << 13): 1835 *speed = 100; 1836 break; 1837 case (2 << 13): 1838 *speed = 1000; 1839 break; 1840 default: 1841 LOG_WARN(BSL_LS_SOC_PHY, 1842 (BSL_META_U(unit, 1843 "phy_54682_speed_get: u=%d p=%d invalid speed\n"), 1844 unit, port)); 1845 } 1846 } 1847 1848 return SOC_E_NONE; 1849 } 1850 1851 /* 1852 * Function: 1853 * phy_54682_master_set 1854 * Purpose: 1855 * Set the current master mode 1856 * Parameters: 1857 * unit - StrataSwitch unit #. 1858 * port - StrataSwitch port #. 1859 * master - SOC_PORT_MS_* 1860 * Returns: 1861 * SOC_E_XXX 1862 * Notes: 1863 * The master mode is set only for the ACTIVE medium. 1864 */ 1865 STATIC int 1866 phy_54682_master_set(int unit, soc_port_t port, int master) 1867 { 1868 int rv; 1869 phy_ctrl_t *pc; 1870 1871 pc = EXT_PHY_SW_STATE(unit, port); 1872 rv = SOC_E_NONE; 1873 if (PHY_COPPER_MODE(unit, port)) { 1874 rv = phy_fe_ge_master_set(unit, port, master); 1875 if (SOC_SUCCESS(rv)) { 1876 pc->copper.master = master; 1877 } 1878 } 1879 LOG_INFO(BSL_LS_SOC_PHY, 1880 (BSL_META_U(unit, 1881 "phy_54682_master_set: u=%d p=%d master=%d fiber=%d rv=%d\n"), 1882 unit, port, master, PHY_FIBER_MODE(unit, port), rv)); 1883 return rv; 1884 } 1885 1886 /* 1887 * Function: 1888 * phy_54682_master_get 1889 * Purpose: 1890 * Get the current master mode for a 54682 device. 1891 * Parameters: 1892 * unit - StrataSwitch unit #. 1893 * port - StrataSwitch port #. 1894 * master - (OUT) SOC_PORT_MS_* 1895 * Returns: 1896 * SOC_E_NONE 1897 * Notes: 1898 * The master mode is retrieved for the ACTIVE medium. 1899 */ 1900 1901 STATIC int 1902 phy_54682_master_get(int unit, soc_port_t port, int *master) 1903 { 1904 if (PHY_COPPER_MODE(unit, port)) { 1905 return phy_fe_ge_master_get(unit, port, master); 1906 } else { 1907 *master = SOC_PORT_MS_NONE; 1908 return SOC_E_NONE; 1909 } 1910 } 1911 1912 /* 1913 * Function: 1914 * phy_54682_autoneg_set 1915 * Purpose: 1916 * Enable or disable auto-negotiation on the specified port. 1917 * Parameters: 1918 * unit - StrataSwitch unit #. 1919 * port - StrataSwitch port #. 1920 * autoneg - Boolean, if true, auto-negotiation is enabled 1921 * (and/or restarted). If false, autonegotiation is disabled. 1922 * Returns: 1923 * SOC_E_XXX 1924 * Notes: 1925 * The autoneg mode is set only for the ACTIVE medium. 1926 */ 1927 1928 STATIC int 1929 phy_54682_autoneg_set(int unit, soc_port_t port, int autoneg) 1930 { 1931 int rv; 1932 uint16 data, mask; 1933 phy_ctrl_t *pc; 1934 1935 pc = EXT_PHY_SW_STATE(unit, port); 1936 rv = SOC_E_NONE; 1937 if (PHY_COPPER_MODE(unit, port)) { 1938 rv = phy_fe_ge_an_set(unit, port, autoneg); 1939 if (SOC_SUCCESS(rv)) { 1940 pc->copper.autoneg_enable = autoneg ? 1 : 0; 1941 } 1942 } else { 1943 if (autoneg) { 1944 /* When enabling autoneg, set the default speed to 1000Mbps first. 1945 * PHY will not enable autoneg if the PHY is in 100FX mode. 1946 */ 1947 SOC_IF_ERROR_RETURN 1948 (phy_54682_speed_set(unit, port, 1000)); 1949 } 1950 1951 /* Disable/Enable auto-detection between SGMII-slave and 1000BASE-X */ 1952 SOC_IF_ERROR_RETURN 1953 (MODIFY_PHY54682_SGMII_SLAVEr(unit, pc, (autoneg ? 1 : 0), 1)); 1954 1955 SOC_IF_ERROR_RETURN 1956 (phy_54682_ability_advert_set(unit, port, 1957 &(pc->fiber.advert_ability))); 1958 data = MII_CTRL_FD; 1959 data |= (autoneg) ? MII_CTRL_AE | MII_CTRL_RAN : 0; 1960 mask = MII_CTRL_AE | MII_CTRL_RAN | MII_CTRL_FD; 1961 SOC_IF_ERROR_RETURN 1962 (MODIFY_PHY54682_1000X_MII_CTRLr(unit, pc, data, mask)); 1963 1964 pc->fiber.autoneg_enable = autoneg ? TRUE : FALSE; 1965 } 1966 1967 LOG_INFO(BSL_LS_SOC_PHY, 1968 (BSL_META_U(unit, 1969 "phy_54682_autoneg_set: u=%d p=%d autoneg=%d rv=%d\n"), 1970 unit, port, autoneg, rv)); 1971 1972 return rv; 1973 } 1974 1975 /* 1976 * Function: 1977 * phy_54682_autoneg_get 1978 * Purpose: 1979 * Get the current auto-negotiation status (enabled/busy). 1980 * Parameters: 1981 * unit - StrataSwitch unit #. 1982 * port - StrataSwitch port #. 1983 * autoneg - (OUT) if true, auto-negotiation is enabled. 1984 * autoneg_done - (OUT) if true, auto-negotiation is complete. This 1985 * value is undefined if autoneg == FALSE. 1986 * Returns: 1987 * SOC_E_XXX 1988 * Notes: 1989 * The autoneg mode is retrieved for the ACTIVE medium. 1990 */ 1991 1992 STATIC int 1993 phy_54682_autoneg_get(int unit, soc_port_t port, 1994 int *autoneg, int *autoneg_done) 1995 { 1996 int rv; 1997 uint16 data; 1998 phy_ctrl_t *pc; 1999 2000 pc = EXT_PHY_SW_STATE(unit, port); 2001 2002 rv = SOC_E_NONE; 2003 *autoneg = FALSE; 2004 *autoneg_done = FALSE; 2005 if (PHY_COPPER_MODE(unit, port)) { 2006 rv = phy_fe_ge_an_get(unit, port, autoneg, autoneg_done); 2007 } else { 2008 /* autoneg is not enabled in 100FX mode */ 2009 if (PHY_FIBER_100FX_MODE(unit, port)) { 2010 *autoneg = FALSE; 2011 *autoneg_done = TRUE; 2012 return rv; 2013 } 2014 2015 SOC_IF_ERROR_RETURN 2016 (READ_PHY54682_1000X_MII_CTRLr(unit, pc, &data)); 2017 if (data & MII_CTRL_AE) { 2018 *autoneg = TRUE; 2019 2020 SOC_IF_ERROR_RETURN 2021 (READ_PHY54682_1000X_MII_STATr(unit, pc, &data)); 2022 if (data & MII_STAT_AN_DONE) { 2023 *autoneg_done = TRUE; 2024 } 2025 } 2026 2027 } 2028 2029 return rv; 2030 } 2031 2032 /* 2033 * Function: 2034 * phy_54682_ability_advert_set 2035 * Purpose: 2036 * Set the current advertisement for auto-negotiation. 2037 * Parameters: 2038 * unit - StrataSwitch unit #. 2039 * port - StrataSwitch port #. 2040 * ability - Port ability indicating supported options/speeds. 2041 * Returns: 2042 * SOC_E_XXX 2043 */ 2044 2045 STATIC int 2046 phy_54682_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability) 2047 { 2048 int rv; 2049 phy_ctrl_t *pc; 2050 uint16 mii_adv, mii_gb_ctrl, eee_ability = 0; 2051 2052 if ( NULL == ability ) { 2053 return SOC_E_PARAM; 2054 } 2055 2056 pc = EXT_PHY_SW_STATE(unit, port); 2057 rv = SOC_E_NONE; 2058 2059 if ( PHY_COPPER_MODE(unit, port) ) { 2060 mii_adv = MII_ANA_ASF_802_3; 2061 2062 SOC_IF_ERROR_RETURN 2063 (READ_PHY54682_MII_GB_CTRLr(unit, pc, &mii_gb_ctrl)); 2064 2065 mii_gb_ctrl &= ~(MII_GB_CTRL_ADV_1000HD | MII_GB_CTRL_ADV_1000FD); 2066 mii_gb_ctrl |= MII_GB_CTRL_PT; /* repeater / switch port */ 2067 2068 if (ability->speed_half_duplex & SOC_PA_SPEED_10MB) { 2069 mii_adv |= MII_ANA_HD_10; 2070 } 2071 if (ability->speed_half_duplex & SOC_PA_SPEED_100MB) { 2072 mii_adv |= MII_ANA_HD_100; 2073 } 2074 if (ability->speed_half_duplex & SOC_PA_SPEED_1000MB) { 2075 mii_gb_ctrl |= MII_GB_CTRL_ADV_1000HD; 2076 } 2077 if (ability->speed_full_duplex & SOC_PA_SPEED_10MB) { 2078 mii_adv |= MII_ANA_FD_10; 2079 } 2080 if (ability->speed_full_duplex & SOC_PA_SPEED_100MB) { 2081 mii_adv |= MII_ANA_FD_100; 2082 } 2083 if (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) { 2084 mii_gb_ctrl |= MII_GB_CTRL_ADV_1000FD; 2085 } 2086 2087 switch ( ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX) ) { 2088 case SOC_PA_PAUSE_TX: 2089 mii_adv |= MII_ANA_ASYM_PAUSE; 2090 break; 2091 case SOC_PA_PAUSE_RX: 2092 mii_adv |= MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE; 2093 break; 2094 case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX: 2095 mii_adv |= MII_ANA_PAUSE; 2096 break; 2097 } 2098 2099 /* EEE settings */ 2100 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2101 eee_ability = 0; 2102 if (ability->eee & SOC_PA_EEE_1GB_BASET) { 2103 eee_ability |= 0x4; 2104 } 2105 if (ability->eee & SOC_PA_EEE_100MB_BASETX) { 2106 eee_ability |= 0x2; 2107 } 2108 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_ENABLED)) { 2109 SOC_IF_ERROR_RETURN 2110 (MODIFY_PHY54682_EEE_ADVr(unit, pc, eee_ability, 0x0006)); 2111 } else { 2112 SOC_IF_ERROR_RETURN 2113 (MODIFY_PHY54682_EEE_ADVr(unit, pc, 0x0000, 0x0006)); 2114 } 2115 } 2116 2117 SOC_IF_ERROR_RETURN 2118 (MODIFY_PHY54682_MII_ANAr(unit, pc, mii_adv, 2119 MII_ANA_PAUSE|MII_ANA_ASYM_PAUSE|MII_ANA_FD_100|MII_ANA_HD_100| 2120 MII_ANA_FD_10|MII_ANA_HD_10|MII_ANA_ASF_802_3)); 2121 2122 SOC_IF_ERROR_RETURN 2123 (MODIFY_PHY54682_MII_GB_CTRLr(unit, pc, mii_gb_ctrl, 2124 MII_GB_CTRL_PT|MII_GB_CTRL_ADV_1000FD|MII_GB_CTRL_ADV_1000HD)); 2125 2126 /* update the PHY property software table (phy_ctrl_t) */ 2127 sal_memcpy( &(pc->copper.advert_ability), ability, 2128 sizeof(soc_port_ability_t) ); 2129 2130 } else { /* PHY_FIBER_MODE */ 2131 mii_adv = MII_ANA_C37_FD; /* Always advertise 1000X full duplex */ 2132 2133 switch ( ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX) ) { 2134 case SOC_PA_PAUSE_TX: 2135 mii_adv |= MII_ANA_C37_ASYM_PAUSE; 2136 break; 2137 case SOC_PA_PAUSE_RX: 2138 mii_adv |= (MII_ANA_C37_ASYM_PAUSE | MII_ANA_C37_PAUSE); 2139 break; 2140 case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX: 2141 mii_adv |= MII_ANA_C37_PAUSE; 2142 break; 2143 } 2144 /* Write to SerDes Auto-Neg Advertisement Reg */ 2145 rv = WRITE_PHY54682_1000X_MII_ANAr(unit, pc, mii_adv); 2146 2147 /* update the PHY property software table (phy_ctrl_t) */ 2148 sal_memcpy( &(pc->fiber.advert_ability), ability, 2149 sizeof(soc_port_ability_t) ); 2150 } 2151 return rv; 2152 } 2153 2154 /* 2155 * Function: 2156 * phy_54682_ability_advert_get 2157 * Purpose: 2158 * Get the current advertisement for auto-negotiation. 2159 * Parameters: 2160 * unit - StrataSwitch unit #. 2161 * port - StrataSwitch port #. 2162 * ability - Port ability indicating supported options/speeds. 2163 * Returns: 2164 * SOC_E_XXX 2165 * Notes: 2166 * The advertisement is retrieved for the ACTIVE medium. 2167 * No synchronization performed at this level. 2168 */ 2169 2170 STATIC int 2171 phy_54682_ability_advert_get(int unit, soc_port_t port, soc_port_ability_t *ability) 2172 { 2173 phy_ctrl_t *pc; 2174 uint16 mii_ana; 2175 uint16 mii_gb_ctrl; 2176 uint16 eee_ability = 0; 2177 2178 if (NULL == ability) { 2179 return (SOC_E_PARAM); 2180 } 2181 2182 pc = EXT_PHY_SW_STATE(unit, port); 2183 2184 if (PHY_COPPER_MODE(unit, port)) { 2185 2186 SOC_IF_ERROR_RETURN 2187 (READ_PHY54682_MII_ANAr(unit, pc, &mii_ana)); 2188 SOC_IF_ERROR_RETURN 2189 (READ_PHY54682_MII_GB_CTRLr(unit, pc, &mii_gb_ctrl)); 2190 2191 sal_memset(ability, 0, sizeof(*ability)); 2192 2193 if (mii_ana & MII_ANA_HD_10) { 2194 ability->speed_half_duplex |= SOC_PA_SPEED_10MB; 2195 } 2196 if (mii_ana & MII_ANA_HD_100) { 2197 ability->speed_half_duplex |= SOC_PA_SPEED_100MB; 2198 } 2199 if (mii_ana & MII_ANA_FD_10) { 2200 ability->speed_full_duplex |= SOC_PA_SPEED_10MB; 2201 } 2202 if (mii_ana & MII_ANA_FD_100) { 2203 ability->speed_full_duplex |= SOC_PA_SPEED_100MB; 2204 } 2205 2206 switch (mii_ana & (MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE)) { 2207 case MII_ANA_PAUSE: 2208 ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 2209 break; 2210 case MII_ANA_ASYM_PAUSE: 2211 ability->pause = SOC_PA_PAUSE_TX; 2212 break; 2213 case MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE: 2214 ability->pause = SOC_PA_PAUSE_RX; 2215 break; 2216 } 2217 2218 /* GE Specific values */ 2219 2220 if (mii_gb_ctrl & MII_GB_CTRL_ADV_1000HD) { 2221 ability->speed_half_duplex |= SOC_PA_SPEED_1000MB; 2222 } 2223 if (mii_gb_ctrl & MII_GB_CTRL_ADV_1000FD) { 2224 ability->speed_full_duplex |= SOC_PA_SPEED_1000MB; 2225 } 2226 2227 /* EEE settings */ 2228 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2229 SOC_IF_ERROR_RETURN 2230 (READ_PHY54682_EEE_ADVr(unit, pc, &eee_ability)); 2231 if (eee_ability & 0x04) { 2232 ability->eee |= SOC_PA_EEE_1GB_BASET; 2233 } 2234 if (eee_ability & 0x02) { 2235 ability->eee |= SOC_PA_EEE_100MB_BASETX; 2236 } 2237 } 2238 } else { /* PHY_FIBER_MODE */ 2239 uint16 mii_adv; 2240 2241 /* read the 1000BASE-X Auto-Neg Advertisement Reg ( Address 0x04 ) */ 2242 SOC_IF_ERROR_RETURN 2243 (READ_PHY54682_1000X_MII_ANAr(unit, pc, &mii_adv)); 2244 2245 if (mii_adv & MII_ANA_C37_FD) { 2246 ability->speed_full_duplex |= SOC_PA_SPEED_1000MB; 2247 } 2248 if (mii_adv & MII_ANA_C37_HD) { 2249 ability->speed_half_duplex |= SOC_PA_SPEED_1000MB; 2250 } 2251 switch (mii_adv & (MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE)) { 2252 case MII_ANA_C37_PAUSE: 2253 ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 2254 break; 2255 case MII_ANA_C37_ASYM_PAUSE: 2256 ability->pause = SOC_PA_PAUSE_TX; 2257 break; 2258 case (MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE): 2259 ability->pause = SOC_PA_PAUSE_RX; 2260 break; 2261 } 2262 } 2263 return SOC_E_NONE; 2264 } 2265 2266 /* 2267 * Function: 2268 * phy_54682_ability_remote_get 2269 * Purpose: 2270 * Get partners current advertisement for auto-negotiation. 2271 * Parameters: 2272 * unit - StrataSwitch unit #. 2273 * port - StrataSwitch port #. 2274 * ability - Port ability indicating supported options/speeds. 2275 * Returns: 2276 * SOC_E_XXX 2277 * Notes: 2278 * The remote advertisement is retrieved for the ACTIVE medium. 2279 * No synchronization performed at this level. If Autonegotiation is 2280 * disabled or in progress, this routine will return an error. 2281 */ 2282 2283 STATIC int 2284 phy_54682_ability_remote_get(int unit, soc_port_t port, soc_port_ability_t *ability) 2285 { 2286 phy_ctrl_t *pc; 2287 uint16 mii_stat; 2288 uint16 mii_anp; 2289 uint16 mii_gb_stat; 2290 uint16 eee_resolution; 2291 uint16 data; 2292 2293 if (NULL == ability) { 2294 return (SOC_E_PARAM); 2295 } 2296 2297 pc = EXT_PHY_SW_STATE(unit, port); 2298 if (PHY_COPPER_MODE(unit, port)) { 2299 SOC_IF_ERROR_RETURN 2300 (READ_PHY54682_MII_STATr(unit, pc, &mii_stat)); 2301 2302 sal_memset(ability, 0, sizeof(*ability)); 2303 2304 if ((mii_stat & MII_STAT_AN_DONE & MII_STAT_LA) 2305 == (MII_STAT_AN_DONE & MII_STAT_LA)) { 2306 /* Decode remote advertisement only when link is up and autoneg is 2307 * completed. 2308 */ 2309 SOC_IF_ERROR_RETURN 2310 (READ_PHY54682_MII_ANPr(unit, pc, &mii_anp)); 2311 SOC_IF_ERROR_RETURN 2312 (READ_PHY54682_MII_GB_STATr(unit, pc, &mii_gb_stat)); 2313 2314 if (mii_anp & MII_ANA_HD_10) { 2315 ability->speed_half_duplex |= SOC_PA_SPEED_10MB; 2316 } 2317 if (mii_anp & MII_ANA_HD_100) { 2318 ability->speed_half_duplex |= SOC_PA_SPEED_100MB; 2319 } 2320 if (mii_anp & MII_ANA_FD_10) { 2321 ability->speed_full_duplex |= SOC_PA_SPEED_10MB; 2322 } 2323 if (mii_anp & MII_ANA_FD_100) { 2324 ability->speed_full_duplex |= SOC_PA_SPEED_100MB; 2325 } 2326 2327 switch (mii_anp & (MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE)) { 2328 case MII_ANA_PAUSE: 2329 ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 2330 break; 2331 case MII_ANA_ASYM_PAUSE: 2332 ability->pause = SOC_PA_PAUSE_TX; 2333 break; 2334 case MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE: 2335 ability->pause = SOC_PA_PAUSE_RX; 2336 break; 2337 } 2338 2339 /* GE Specific values */ 2340 2341 if (mii_gb_stat & MII_GB_STAT_LP_1000HD) { 2342 ability->speed_half_duplex |= SOC_PA_SPEED_1000MB; 2343 } 2344 if (mii_gb_stat & MII_GB_STAT_LP_1000FD) { 2345 ability->speed_full_duplex |= SOC_PA_SPEED_1000MB; 2346 } 2347 /* EEE settings */ 2348 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2349 SOC_IF_ERROR_RETURN 2350 (READ_PHY54682_EEE_RESOLUTION_STATr(unit, pc, &eee_resolution)); 2351 if (eee_resolution & 0x04) { 2352 ability->eee |= SOC_PA_EEE_1GB_BASET; 2353 } 2354 if (eee_resolution & 0x02) { 2355 ability->eee |= SOC_PA_EEE_100MB_BASETX; 2356 } 2357 } 2358 2359 } else { 2360 /* Simply return local abilities */ 2361 phy_54682_ability_advert_get(unit, port, ability); 2362 } 2363 } else { /* PHY_FIBER_MODE */ 2364 2365 /* read the 1000BASE-X Control Reg ( Address 0x00 ), 2366 * Auto-Neg Link Partner Ability Reg ( Address 0x05 ) 2367 */ 2368 SOC_IF_ERROR_RETURN 2369 (READ_PHY54682_1000X_MII_CTRLr(unit, pc, &data)); 2370 if (!(data & MII_CTRL_AE)) { 2371 return SOC_E_DISABLED; 2372 } 2373 2374 SOC_IF_ERROR_RETURN 2375 (READ_PHY54682_1000X_MII_ANPr(unit, pc, &data)); 2376 2377 if (data & MII_ANP_SGMII_MODE) { 2378 /* Unable to determine remote link partner's advertisement */ 2379 return SOC_E_NONE; 2380 } 2381 2382 if (data & MII_ANP_C37_FD) { 2383 ability->speed_full_duplex |= SOC_PA_SPEED_1000MB; 2384 } 2385 if (data & MII_ANP_C37_HD) { 2386 ability->speed_half_duplex |= SOC_PA_SPEED_1000MB; 2387 } 2388 switch (data & (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) { 2389 case MII_ANP_C37_PAUSE: 2390 ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 2391 break; 2392 case MII_ANP_C37_ASYM_PAUSE: 2393 ability->pause = SOC_PA_PAUSE_TX; 2394 break; 2395 case (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE): 2396 ability->pause = SOC_PA_PAUSE_RX; 2397 break; 2398 } 2399 } 2400 LOG_INFO(BSL_LS_SOC_PHY, 2401 (BSL_META_U(unit, 2402 "phy_54682_ability_remote_get:unit=%d p=%d pause=%08x sp=%08x\n"), 2403 unit, port, ability->pause, ability->speed_full_duplex)); 2404 2405 return SOC_E_NONE; 2406 } 2407 2408 /* 2409 * Function: 2410 * phy_54682_ability_local_get 2411 * Purpose: 2412 * Get the device's complete abilities. 2413 * Parameters: 2414 * unit - StrataSwitch unit #. 2415 * port - StrataSwitch port #. 2416 * ability - return device's abilities. 2417 * Returns: 2418 * SOC_E_XXX 2419 */ 2420 STATIC int 2421 _phy_54682_ability_cu_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 2422 { 2423 phy_ctrl_t *pc; 2424 2425 pc = EXT_PHY_SW_STATE(unit, port); 2426 2427 2428 if (NULL == ability) { 2429 return SOC_E_PARAM; 2430 } 2431 2432 ability->speed_half_duplex = SOC_PA_SPEED_100MB | SOC_PA_SPEED_10MB; 2433 ability->speed_full_duplex = SOC_PA_SPEED_1000MB |SOC_PA_SPEED_100MB | 2434 SOC_PA_SPEED_10MB; 2435 2436 ability->pause = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 2437 ability->interface = SOC_PA_INTF_SGMII; 2438 ability->medium = SOC_PA_MEDIUM_COPPER; 2439 ability->loopback = SOC_PA_LB_PHY; 2440 ability->flags = SOC_PA_AUTONEG; 2441 2442 /* EEE settings */ 2443 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2444 ability->eee |= SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX; 2445 } 2446 2447 if (pc->automedium) { 2448 ability->flags |= SOC_PA_COMBO; 2449 } 2450 return SOC_E_NONE; 2451 } 2452 2453 STATIC int 2454 _phy_54682_ability_fiber_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 2455 { 2456 phy_ctrl_t *pc; 2457 2458 pc = EXT_PHY_SW_STATE(unit, port); 2459 2460 if (NULL == ability) { 2461 return SOC_E_PARAM; 2462 } 2463 2464 ability->speed_half_duplex = SOC_PA_SPEED_100MB; 2465 ability->speed_full_duplex = SOC_PA_SPEED_1000MB |SOC_PA_SPEED_100MB; 2466 2467 ability->pause = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 2468 ability->interface = SOC_PA_INTF_SGMII; 2469 ability->medium = SOC_PA_MEDIUM_FIBER; 2470 ability->loopback = SOC_PA_LB_PHY; 2471 ability->flags = SOC_PA_AUTONEG; 2472 2473 if (pc->automedium) { 2474 ability->flags |= SOC_PA_COMBO; 2475 } 2476 return SOC_E_NONE; 2477 } 2478 2479 2480 STATIC int 2481 phy_54682_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 2482 { 2483 if (PHY_COPPER_MODE(unit, port)) { 2484 SOC_IF_ERROR_RETURN 2485 (_phy_54682_ability_cu_local_get(unit, port, ability)); 2486 } else { 2487 SOC_IF_ERROR_RETURN 2488 (_phy_54682_ability_fiber_local_get(unit, port, ability)); 2489 } 2490 return SOC_E_NONE; 2491 } 2492 2493 /* 2494 * Function: 2495 * phy_54682_lb_set 2496 * Purpose: 2497 * Set the local PHY loopback mode. 2498 * Parameters: 2499 * unit - StrataSwitch unit #. 2500 * port - StrataSwitch port #. 2501 * loopback - Boolean: true = enable loopback, false = disable. 2502 * Returns: 2503 * SOC_E_XXX 2504 * Notes: 2505 * The loopback mode is set only for the ACTIVE medium. 2506 * No synchronization performed at this level. 2507 */ 2508 2509 STATIC int 2510 phy_54682_lb_set(int unit, soc_port_t port, int enable) 2511 { 2512 int rv; 2513 uint16 data; 2514 phy_ctrl_t *pc; 2515 2516 pc = EXT_PHY_SW_STATE(unit, port); 2517 rv = SOC_E_NONE; 2518 2519 #if AUTO_MDIX_WHEN_AN_DIS 2520 { 2521 /* Disable Auto-MDIX When autoneg disabled */ 2522 /* Enable Auto-MDIX When autoneg disabled */ 2523 data = (enable) ? 0x0000 : 0x0200; 2524 SOC_IF_ERROR_RETURN 2525 (MODIFY_PHY_54682_MII_MISC_CTRLr(unit, pc, data, 0x0200)); 2526 } 2527 #endif 2528 2529 if (PHY_COPPER_MODE(unit, port)) { 2530 rv = phy_fe_ge_lb_set(unit, port, enable); 2531 2532 } else { 2533 data = (enable) ? MII_CTRL_LE : 0; 2534 rv = MODIFY_PHY54682_1000X_MII_CTRLr(unit, pc, data, MII_CTRL_LE); 2535 if (enable && SOC_SUCCESS(rv)) { 2536 uint16 stat; 2537 int link; 2538 soc_timeout_t to; 2539 2540 /* Wait up to 5000 msec for link up */ 2541 soc_timeout_init(&to, 5000000, 0); 2542 link = 0; 2543 while (!soc_timeout_check(&to)) { 2544 rv = READ_PHY54682_1000X_MII_STATr(unit, pc, &stat); 2545 link = stat & MII_STAT_LA; 2546 if (link || SOC_FAILURE(rv)) { 2547 break; 2548 } 2549 } 2550 if (!link) { 2551 LOG_WARN(BSL_LS_SOC_PHY, 2552 (BSL_META_U(unit, 2553 "phy_54682_lb_set: u=%d p=%d TIMEOUT\n"), 2554 unit, port)); 2555 2556 rv = SOC_E_TIMEOUT; 2557 } 2558 } 2559 } 2560 LOG_INFO(BSL_LS_SOC_PHY, 2561 (BSL_META_U(unit, 2562 "phy_54682_lb_set: u=%d p=%d en=%d rv=%d\n"), 2563 unit, port, enable, rv)); 2564 2565 return rv; 2566 } 2567 2568 /* 2569 * Function: 2570 * phy_54682_lb_get 2571 * Purpose: 2572 * Get the local PHY loopback mode. 2573 * Parameters: 2574 * unit - StrataSwitch unit #. 2575 * port - StrataSwitch port #. 2576 * loopback - (OUT) Boolean: true = enable loopback, false = disable. 2577 * Returns: 2578 * SOC_E_XXX 2579 * Notes: 2580 * The loopback mode is retrieved for the ACTIVE medium. 2581 */ 2582 2583 STATIC int 2584 phy_54682_lb_get(int unit, soc_port_t port, int *enable) 2585 { 2586 uint16 data; 2587 phy_ctrl_t *pc; 2588 2589 pc = EXT_PHY_SW_STATE(unit, port); 2590 2591 if (PHY_COPPER_MODE(unit, port)) { 2592 SOC_IF_ERROR_RETURN 2593 (phy_fe_ge_lb_get(unit, port, enable)); 2594 } else { 2595 SOC_IF_ERROR_RETURN 2596 (READ_PHY54682_1000X_MII_CTRLr(unit, pc, &data)); 2597 *enable = (data & MII_CTRL_LE) ? 1 : 0; 2598 } 2599 2600 return SOC_E_NONE; 2601 } 2602 2603 /* 2604 * Function: 2605 * phy_54682_interface_set 2606 * Purpose: 2607 * Set the current operating mode of the PHY. 2608 * Parameters: 2609 * unit - StrataSwitch unit #. 2610 * port - StrataSwitch port #. 2611 * pif - one of SOC_PORT_IF_* 2612 * Returns: 2613 * SOC_E_NONE - success 2614 * SOC_E_UNAVAIL - unsupported interface 2615 */ 2616 2617 STATIC int 2618 phy_54682_interface_set(int unit, soc_port_t port, soc_port_if_t pif) 2619 { 2620 COMPILER_REFERENCE(unit); 2621 COMPILER_REFERENCE(port); 2622 2623 switch (pif) { 2624 case SOC_PORT_IF_SGMII: 2625 case SOC_PORT_IF_GMII: 2626 return SOC_E_NONE; 2627 default: 2628 return SOC_E_UNAVAIL; 2629 } 2630 } 2631 2632 /* 2633 * Function: 2634 * phy_54682_interface_get 2635 * Purpose: 2636 * Get the current operating mode of the PHY. 2637 * Parameters: 2638 * unit - StrataSwitch unit #. 2639 * port - StrataSwitch port #. 2640 * pif - (OUT) one of SOC_PORT_IF_* 2641 * Returns: 2642 * SOC_E_NONE 2643 */ 2644 2645 STATIC int 2646 phy_54682_interface_get(int unit, soc_port_t port, soc_port_if_t *pif) 2647 { 2648 COMPILER_REFERENCE(unit); 2649 COMPILER_REFERENCE(port); 2650 2651 *pif = SOC_PORT_IF_SGMII; 2652 2653 return SOC_E_NONE; 2654 } 2655 2656 /* 2657 * Function: 2658 * phy_54682_mdix_set 2659 * Description: 2660 * Set the Auto-MDIX mode of a port/PHY 2661 * Parameters: 2662 * unit - Device number 2663 * port - Port number 2664 * mode - One of: 2665 * SOC_PORT_MDIX_AUTO 2666 * Enable auto-MDIX when autonegotiation is enabled 2667 * SOC_PORT_MDIX_FORCE_AUTO 2668 * Enable auto-MDIX always 2669 * SOC_PORT_MDIX_NORMAL 2670 * Disable auto-MDIX 2671 * SOC_PORT_MDIX_XOVER 2672 * Disable auto-MDIX, and swap cable pairs 2673 * Return Value: 2674 * SOC_E_XXX 2675 */ 2676 STATIC int 2677 phy_54682_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode) 2678 { 2679 phy_ctrl_t *pc; 2680 int speed; 2681 2682 pc = EXT_PHY_SW_STATE(unit, port); 2683 if (PHY_COPPER_MODE(unit, port)) { 2684 switch (mode) { 2685 case SOC_PORT_MDIX_AUTO: 2686 /* Clear bit 14 for automatic MDI crossover */ 2687 SOC_IF_ERROR_RETURN 2688 (MODIFY_PHY54682_MII_ECRr(unit, pc, 0, 0x4000)); 2689 2690 /* Clear bit 9 to disable forced auto MDI xover */ 2691 SOC_IF_ERROR_RETURN 2692 (MODIFY_PHY54682_MII_MISC_CTRLr(unit, pc, 0, 0x0200)); 2693 break; 2694 2695 case SOC_PORT_MDIX_FORCE_AUTO: 2696 /* Clear bit 14 for automatic MDI crossover */ 2697 SOC_IF_ERROR_RETURN 2698 (MODIFY_PHY54682_MII_ECRr(unit, pc, 0, 0x4000)); 2699 2700 /* Set bit 9 to disable forced auto MDI xover */ 2701 SOC_IF_ERROR_RETURN 2702 (MODIFY_PHY54682_MII_MISC_CTRLr(unit, pc, 0x0200, 0x0200)); 2703 break; 2704 2705 case SOC_PORT_MDIX_NORMAL: 2706 SOC_IF_ERROR_RETURN(phy_54682_speed_get(unit, port, &speed)); 2707 if (speed == 0 || speed == 10 || speed == 100) { 2708 /* Set bit 14 for automatic MDI crossover */ 2709 SOC_IF_ERROR_RETURN 2710 (MODIFY_PHY54682_MII_ECRr(unit, pc, 0x4000, 0x4000)); 2711 2712 SOC_IF_ERROR_RETURN 2713 (WRITE_PHY54682_TEST1r(unit, pc, 0)); 2714 } else { 2715 return SOC_E_UNAVAIL; 2716 } 2717 break; 2718 2719 case SOC_PORT_MDIX_XOVER: 2720 SOC_IF_ERROR_RETURN(phy_54682_speed_get(unit, port, &speed)); 2721 if (speed == 0 || speed == 10 || speed == 100) { 2722 /* Set bit 14 for automatic MDI crossover */ 2723 SOC_IF_ERROR_RETURN 2724 (MODIFY_PHY54682_MII_ECRr(unit, pc, 0x4000, 0x4000)); 2725 2726 SOC_IF_ERROR_RETURN 2727 (WRITE_PHY54682_TEST1r(unit, pc, 0x0080)); 2728 } else { 2729 return SOC_E_UNAVAIL; 2730 } 2731 break; 2732 2733 default: 2734 return SOC_E_PARAM; 2735 } 2736 pc->copper.mdix = mode; 2737 } else { /* fiber */ 2738 if (mode != SOC_PORT_MDIX_NORMAL) { 2739 return SOC_E_UNAVAIL; 2740 } 2741 } 2742 return SOC_E_NONE; 2743 } 2744 2745 #if defined(BCM_WARM_BOOT_SUPPORT) 2746 /* 2747 * Function: 2748 * _phy_54682_mdix_wb_update 2749 * Description: 2750 * Read the hw, derive the mode and update the mdix mode in sw structure 2751 * during wb. 2752 * Parameters: 2753 * unit - (IN) Device number 2754 * port - (IN) Port number 2755 * mode - (OUT) :One of: 2756 * SOC_PORT_MDIX_AUTO 2757 * Enable auto-MDIX when autonegotiation is enabled 2758 * SOC_PORT_MDIX_FORCE_AUTO 2759 * Enable auto-MDIX always 2760 * SOC_PORT_MDIX_NORMAL 2761 * Disable auto-MDIX 2762 * SOC_PORT_MDIX_XOVER 2763 * Disable auto-MDIX, and swap cable pairs 2764 * Return Value: 2765 * SOC_E_XXX 2766 */ 2767 STATIC int 2768 _phy_54682_mdix_wb_update(int unit, soc_port_t port) 2769 { 2770 phy_ctrl_t *pc; 2771 int speed; 2772 int mode = 0; 2773 uint16 val = 0; 2774 2775 pc = EXT_PHY_SW_STATE(unit, port); 2776 2777 /* Check bit 14 for automatic MDI crossover */ 2778 SOC_IF_ERROR_RETURN (READ_PHY54682_MII_ECRr(unit, pc, &val)); 2779 if(val & 0x4000) { 2780 SOC_IF_ERROR_RETURN(phy_54682_speed_get(unit, port, &speed)); 2781 if (speed == 0 || speed == 10 || speed == 100) { 2782 SOC_IF_ERROR_RETURN (READ_PHY54682_TEST1r(unit, pc, &val)); 2783 if (0 == val) { 2784 mode = SOC_PORT_MDIX_NORMAL; 2785 } else if (0x80 == val) { 2786 mode = SOC_PORT_MDIX_XOVER; 2787 } else { 2788 return SOC_E_UNAVAIL; 2789 } 2790 } else { 2791 return SOC_E_UNAVAIL; 2792 } 2793 } else { 2794 /* Check bit 9 forced auto MDI xover */ 2795 SOC_IF_ERROR_RETURN (READ_PHY54682_MII_MISC_CTRLr(unit, pc,&val)); 2796 if (val & 0x200) { 2797 /* bit 9 Set, forced auto MDI xover */ 2798 mode = SOC_PORT_MDIX_FORCE_AUTO; 2799 } else { 2800 /* bit 9 Clear, forced auto MDI xover */ 2801 mode = SOC_PORT_MDIX_AUTO; 2802 } 2803 } 2804 pc->copper.mdix = mode; 2805 2806 return SOC_E_NONE; 2807 } 2808 #endif /* defined(BCM_WARM_BOOT_SUPPORT) */ 2809 2810 /* 2811 * Function: 2812 * phy_54682_mdix_get 2813 * Description: 2814 * Get the Auto-MDIX mode of a port/PHY 2815 * Parameters: 2816 * unit - Device number 2817 * port - Port number 2818 * mode - (Out) One of: 2819 * SOC_PORT_MDIX_AUTO 2820 * Enable auto-MDIX when autonegotiation is enabled 2821 * SOC_PORT_MDIX_FORCE_AUTO 2822 * Enable auto-MDIX always 2823 * SOC_PORT_MDIX_NORMAL 2824 * Disable auto-MDIX 2825 * SOC_PORT_MDIX_XOVER 2826 * Disable auto-MDIX, and swap cable pairs 2827 * Return Value: 2828 * SOC_E_XXX 2829 */ 2830 STATIC int 2831 phy_54682_mdix_get(int unit, soc_port_t port, soc_port_mdix_t *mode) 2832 { 2833 phy_ctrl_t *pc; 2834 int speed; 2835 2836 if (mode == NULL) { 2837 return SOC_E_PARAM; 2838 } 2839 2840 #if defined(BCM_WARM_BOOT_SUPPORT) 2841 if (SOC_WARM_BOOT(unit)) { 2842 return _phy_54682_mdix_wb_update(unit, port); 2843 } 2844 #endif /* defined(BCM_WARM_BOOT_SUPPORT) */ 2845 2846 pc = EXT_PHY_SW_STATE(unit, port); 2847 2848 if (PHY_COPPER_MODE(unit, port)) { 2849 SOC_IF_ERROR_RETURN(phy_54682_speed_get(unit, port, &speed)); 2850 if (speed == 1000) { 2851 *mode = SOC_PORT_MDIX_AUTO; 2852 } else { 2853 *mode = pc->copper.mdix; 2854 } 2855 } else { 2856 *mode = SOC_PORT_MDIX_NORMAL; 2857 } 2858 2859 return SOC_E_NONE; 2860 } 2861 2862 /* 2863 * Function: 2864 * phy_54682_mdix_status_get 2865 * Description: 2866 * Get the current MDIX status on a port/PHY 2867 * Parameters: 2868 * unit - Device number 2869 * port - Port number 2870 * status - (OUT) One of: 2871 * SOC_PORT_MDIX_STATUS_NORMAL 2872 * Straight connection 2873 * SOC_PORT_MDIX_STATUS_XOVER 2874 * Crossover has been performed 2875 * Return Value: 2876 * SOC_E_XXX 2877 */ 2878 STATIC int 2879 phy_54682_mdix_status_get(int unit, soc_port_t port, 2880 soc_port_mdix_status_t *status) 2881 { 2882 phy_ctrl_t *pc; 2883 uint16 data; 2884 2885 if (status == NULL) { 2886 return SOC_E_PARAM; 2887 } 2888 2889 pc = EXT_PHY_SW_STATE(unit, port); 2890 2891 if (PHY_COPPER_MODE(unit, port)) { 2892 SOC_IF_ERROR_RETURN 2893 (READ_PHY54682_MII_ESRr(unit, pc, &data)); 2894 if (data & 0x2000) { 2895 *status = SOC_PORT_MDIX_STATUS_XOVER; 2896 } else { 2897 *status = SOC_PORT_MDIX_STATUS_NORMAL; 2898 } 2899 } else { 2900 *status = SOC_PORT_MDIX_STATUS_NORMAL; 2901 } 2902 2903 return SOC_E_NONE; 2904 } 2905 2906 STATIC int 2907 _phy_54682_power_mode_set (int unit, soc_port_t port, int mode) 2908 { 2909 phy_ctrl_t *pc; 2910 2911 pc = EXT_PHY_SW_STATE(unit, port); 2912 2913 if (pc->power_mode == mode) { 2914 return SOC_E_NONE; 2915 } 2916 2917 if ((mode == SOC_PHY_CONTROL_POWER_LOW) || (mode == SOC_PHY_CONTROL_POWER_AUTO_LOW)) { 2918 /* enable dsp clock */ 2919 SOC_IF_ERROR_RETURN 2920 (MODIFY_PHY54682_MII_AUX_CTRLr(unit,pc,0x0c00,0x0c00)); 2921 2922 /* enable low power 136 */ 2923 SOC_IF_ERROR_RETURN 2924 (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc,0x80,0x80)); 2925 2926 /* reduce tx bias current to -20% */ 2927 SOC_IF_ERROR_RETURN 2928 (WRITE_PHY_REG(unit, pc, 0x17, 0x0f75)); 2929 SOC_IF_ERROR_RETURN 2930 (WRITE_PHY_REG(unit, pc, 0x15, 0x1555)); 2931 2932 /* disable dsp clock */ 2933 SOC_IF_ERROR_RETURN 2934 (MODIFY_PHY54682_MII_AUX_CTRLr(unit,pc,0x0400,0x0c00)); 2935 2936 /* set the auto power down setting */ 2937 SOC_IF_ERROR_RETURN 2938 (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc, 2939 (mode == SOC_PHY_CONTROL_POWER_AUTO_LOW) ? PHY_54682_AUTO_PWRDWN_EN : 0, 2940 PHY_54682_AUTO_PWRDWN_EN)); 2941 pc->power_mode = mode; 2942 2943 } else if ((mode == SOC_PHY_CONTROL_POWER_FULL) || (mode == SOC_PHY_CONTROL_POWER_AUTO_FULL)) { 2944 2945 /* back to normal mode */ 2946 /* enable dsp clock */ 2947 SOC_IF_ERROR_RETURN 2948 (MODIFY_PHY54682_MII_AUX_CTRLr(unit,pc,0x0c00,0x0c00)); 2949 2950 /* disable low power 136 */ 2951 SOC_IF_ERROR_RETURN 2952 (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc,0x00,0x80)); 2953 2954 /* set tx bias current to nominal */ 2955 SOC_IF_ERROR_RETURN 2956 (WRITE_PHY_REG(unit, pc, 0x17, 0x0f75)); 2957 SOC_IF_ERROR_RETURN 2958 (WRITE_PHY_REG(unit, pc, 0x15, 0x0)); 2959 2960 /* disable dsp clock */ 2961 SOC_IF_ERROR_RETURN 2962 (MODIFY_PHY54682_MII_AUX_CTRLr(unit,pc,0x0400,0x0c00)); 2963 2964 /* set the auto power down setting */ 2965 SOC_IF_ERROR_RETURN 2966 (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc, 2967 (mode == SOC_PHY_CONTROL_POWER_AUTO_FULL) ? PHY_54682_AUTO_PWRDWN_EN : 0, 2968 PHY_54682_AUTO_PWRDWN_EN)); 2969 pc->power_mode = mode; 2970 } else if (mode == SOC_PHY_CONTROL_POWER_AUTO) { 2971 SOC_IF_ERROR_RETURN 2972 (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc, 2973 PHY_54682_AUTO_PWRDWN_EN, 2974 PHY_54682_AUTO_PWRDWN_EN)); 2975 pc->power_mode = mode; 2976 } else if (mode == SOC_PHY_CONTROL_POWER_AUTO_DISABLE) { 2977 SOC_IF_ERROR_RETURN 2978 (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc, 2979 0, 2980 PHY_54682_AUTO_PWRDWN_EN)); 2981 pc->power_mode = mode; 2982 } 2983 return SOC_E_NONE; 2984 } 2985 2986 /* 2987 * Function: 2988 * _phy_54682_eee_enable 2989 * Purpose: 2990 * Enable or disable EEE (Native) 2991 * Parameters: 2992 * unit - StrataSwitch unit #. 2993 * port - StrataSwitch port #. 2994 * enable - Enable Native EEE 2995 * Returns: 2996 * SOC_E_NONE 2997 */ 2998 STATIC int 2999 _phy_54682_eee_enable(int unit, soc_port_t port, int enable) 3000 { 3001 phy_ctrl_t *pc; 3002 3003 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3004 return SOC_E_FAIL; 3005 } 3006 pc = EXT_PHY_SW_STATE(unit, port); 3007 3008 if (enable == 1) { 3009 if (PHY_IS_BCM54685E_A0A1(pc)) { 3010 SOC_IF_ERROR_RETURN 3011 (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0x0c00, 0x0c00)); 3012 3013 SOC_IF_ERROR_RETURN( 3014 WRITE_PHY_REG(unit, pc, 0x17, 0x0ffe)); 3015 SOC_IF_ERROR_RETURN( 3016 WRITE_PHY_REG(unit, pc, 0x15, 0x0100)); 3017 3018 SOC_IF_ERROR_RETURN( 3019 WRITE_PHY_REG(unit, pc, 0x17, 0x0fff)); 3020 SOC_IF_ERROR_RETURN( 3021 WRITE_PHY_REG(unit, pc, 0x15, 0x4000)); 3022 3023 SOC_IF_ERROR_RETURN( 3024 WRITE_PHY_REG(unit, pc, 0x17, 0x2022)); 3025 SOC_IF_ERROR_RETURN( 3026 WRITE_PHY_REG(unit, pc, 0x15, 0x01f1)); 3027 3028 SOC_IF_ERROR_RETURN( 3029 WRITE_PHY_REG(unit, pc, 0x17, 0x4021)); 3030 SOC_IF_ERROR_RETURN( 3031 WRITE_PHY_REG(unit, pc, 0x15, 0x0887)); 3032 3033 SOC_IF_ERROR_RETURN( 3034 WRITE_PHY_REG(unit, pc, 0x17, 0x2021)); 3035 SOC_IF_ERROR_RETURN( 3036 WRITE_PHY_REG(unit, pc, 0x15, 0x8983)); 3037 3038 SOC_IF_ERROR_RETURN( 3039 WRITE_PHY_REG(unit, pc, 0x17, 0x0021)); 3040 SOC_IF_ERROR_RETURN( 3041 WRITE_PHY_REG(unit, pc, 0x15, 0x4600)); 3042 3043 SOC_IF_ERROR_RETURN( 3044 WRITE_PHY_REG(unit, pc, 0x17, 0x0e40)); 3045 SOC_IF_ERROR_RETURN( 3046 WRITE_PHY_REG(unit, pc, 0x15, 0x0000)); 3047 3048 SOC_IF_ERROR_RETURN 3049 (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0x0400, 0x0c00)); 3050 3051 SOC_IF_ERROR_RETURN 3052 (MODIFY_PHY54682_EEE_TEST_CTRL_Br(unit, pc, 0xc000, 0xc000)); 3053 SOC_IF_ERROR_RETURN 3054 (MODIFY_PHY54682_EEE_TEST_CTRL_Ar(unit, pc, 0xf300, 0xf300)); 3055 } else { 3056 SOC_IF_ERROR_RETURN 3057 (MODIFY_PHY54682_EEE_803Dr(unit, pc, 0xc000, 0xc000)); /* 7.803d */ 3058 } 3059 SOC_IF_ERROR_RETURN 3060 (MODIFY_PHY54682_EEE_ADVr(unit, pc, 0x0006, 0x0006)); 3061 pc->copper.advert_ability.eee |= (SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX); 3062 3063 SOC_IF_ERROR_RETURN 3064 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x1, 0x1)); /* exp af */ 3065 3066 } else { /* enable != 1 */ 3067 if (PHY_IS_BCM54685E_A0A1(pc)) { 3068 SOC_IF_ERROR_RETURN 3069 (MODIFY_PHY54682_EEE_TEST_CTRL_Br(unit, pc, 0x0000, 0xc000)); 3070 SOC_IF_ERROR_RETURN 3071 (MODIFY_PHY54682_EEE_TEST_CTRL_Ar(unit, pc, 0x0000, 0xf300)); 3072 } else { 3073 SOC_IF_ERROR_RETURN 3074 (MODIFY_PHY54682_EEE_803Dr(unit, pc, 0x0000, 0xc000)); /* 7.803d */ 3075 } 3076 SOC_IF_ERROR_RETURN 3077 (MODIFY_PHY54682_EEE_ADVr(unit, pc, 0x0000, 0x0006)); 3078 pc->copper.advert_ability.eee &= ~(SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX); 3079 3080 SOC_IF_ERROR_RETURN 3081 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 0x1)); /* exp af */ 3082 } 3083 3084 return SOC_E_NONE; 3085 } 3086 3087 /* 3088 * Function: 3089 * _phy_54682_eee_auto_enable 3090 * Purpose: 3091 * Enable or disable EEE (Native) 3092 * Parameters: 3093 * unit - StrataSwitch unit #. 3094 * port - StrataSwitch port #. 3095 * enable - Enable Native EEE 3096 * Returns: 3097 * SOC_E_NONE 3098 */ 3099 STATIC int 3100 _phy_54682_eee_auto_enable(int unit, soc_port_t port, int enable) 3101 { 3102 phy_ctrl_t *pc; 3103 3104 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3105 return SOC_E_FAIL; 3106 } 3107 pc = EXT_PHY_SW_STATE(unit, port); 3108 3109 if (enable == 1) { 3110 if (PHY_IS_BCM54685E_A0A1(pc)) { 3111 SOC_IF_ERROR_RETURN 3112 (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0x0c00, 0x0c00)); 3113 3114 SOC_IF_ERROR_RETURN( 3115 WRITE_PHY_REG(unit, pc, 0x17, 0x0ffe)); 3116 SOC_IF_ERROR_RETURN( 3117 WRITE_PHY_REG(unit, pc, 0x15, 0x0900)); 3118 3119 SOC_IF_ERROR_RETURN( 3120 WRITE_PHY_REG(unit, pc, 0x17, 0x0fff)); 3121 SOC_IF_ERROR_RETURN( 3122 WRITE_PHY_REG(unit, pc, 0x15, 0x4000)); 3123 3124 SOC_IF_ERROR_RETURN( 3125 WRITE_PHY_REG(unit, pc, 0x17, 0x2022)); 3126 SOC_IF_ERROR_RETURN( 3127 WRITE_PHY_REG(unit, pc, 0x15, 0x01f1)); 3128 3129 SOC_IF_ERROR_RETURN( 3130 WRITE_PHY_REG(unit, pc, 0x17, 0x2021)); 3131 SOC_IF_ERROR_RETURN( 3132 WRITE_PHY_REG(unit, pc, 0x15, 0x8983)); 3133 3134 SOC_IF_ERROR_RETURN( 3135 WRITE_PHY_REG(unit, pc, 0x17, 0x4021)); 3136 SOC_IF_ERROR_RETURN( 3137 WRITE_PHY_REG(unit, pc, 0x15, 0x0887)); 3138 3139 SOC_IF_ERROR_RETURN( 3140 WRITE_PHY_REG(unit, pc, 0x17, 0x0021)); 3141 SOC_IF_ERROR_RETURN( 3142 WRITE_PHY_REG(unit, pc, 0x15, 0x4600)); 3143 3144 SOC_IF_ERROR_RETURN( 3145 WRITE_PHY_REG(unit, pc, 0x17, 0x0fc0)); 3146 SOC_IF_ERROR_RETURN( 3147 WRITE_PHY_REG(unit, pc, 0x15, 0x0000)); 3148 3149 SOC_IF_ERROR_RETURN( 3150 WRITE_PHY_REG(unit, pc, 0x17, 0x0faf)); 3151 SOC_IF_ERROR_RETURN( 3152 WRITE_PHY_REG(unit, pc, 0x15, 0x0001)); 3153 /* 3154 SOC_IF_ERROR_RETURN( 3155 WRITE_PHY_REG(unit, pc, 0x17, 0x0d07)); 3156 SOC_IF_ERROR_RETURN( 3157 WRITE_PHY_REG(unit, pc, 0x15, 0x0001)); 3158 */ 3159 SOC_IF_ERROR_RETURN 3160 (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0x0400, 0x0c00)); 3161 3162 SOC_IF_ERROR_RETURN 3163 (MODIFY_PHY54682_EEE_TEST_CTRL_Br(unit, pc, 0xc000, 0xc000)); 3164 3165 SOC_IF_ERROR_RETURN 3166 (MODIFY_PHY54682_EEE_TEST_CTRL_Ar(unit, pc, 0xf300, 0x1300)); 3167 3168 } else { /* ! PHY_IS_BCM54685E_A0A1 */ 3169 SOC_IF_ERROR_RETURN 3170 (MODIFY_PHY54682_EEE_803Dr(unit, pc, 0xc000, 0xc000)); /* 7.803d */ 3171 } 3172 SOC_IF_ERROR_RETURN 3173 (MODIFY_PHY54682_EEE_ADVr(unit, pc, 0x0006, 0x0006)); 3174 pc->copper.advert_ability.eee |= (SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX); 3175 3176 SOC_IF_ERROR_RETURN 3177 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 7, 3178 0x0001, 0x0003)); 3179 SOC_IF_ERROR_RETURN 3180 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x1, 0x1)); /* exp af */ 3181 3182 } else { /* enable != 1 */ 3183 SOC_IF_ERROR_RETURN 3184 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 0x3)); /* exp af */ 3185 SOC_IF_ERROR_RETURN 3186 (MODIFY_PHY54682_EEE_ADVr(unit, pc, 0x0000, 0x0006)); 3187 pc->copper.advert_ability.eee &= ~(SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX); 3188 3189 if (PHY_IS_BCM54685E_A0A1(pc)) { 3190 SOC_IF_ERROR_RETURN 3191 (MODIFY_PHY54682_EEE_TEST_CTRL_Br(unit, pc, 0x0000, 0xc000)); /* 7.8031 */ 3192 SOC_IF_ERROR_RETURN 3193 (MODIFY_PHY54682_EEE_TEST_CTRL_Ar(unit, pc, 0x0000, 0xf300)); /* 7.8030 2 ops */ 3194 } else { 3195 SOC_IF_ERROR_RETURN 3196 (MODIFY_PHY54682_EEE_803Dr(unit, pc, 0x0000, 0xc000)); /* 7.803d */ 3197 } 3198 } 3199 3200 return SOC_E_NONE; 3201 } 3202 3203 /* 3204 * Function: 3205 * phy_54682_control_set 3206 * Purpose: 3207 * Configure PHY device specific control fucntion. 3208 * Parameters: 3209 * unit - StrataSwitch unit #. 3210 * port - StrataSwitch port #. 3211 * type - Control to update 3212 * value - New setting for the control 3213 * Returns: 3214 * SOC_E_NONE 3215 */ 3216 STATIC int 3217 phy_54682_control_set(int unit, soc_port_t port, 3218 soc_phy_control_t type, uint32 value) 3219 { 3220 int rv; 3221 phy_ctrl_t *pc; 3222 uint16 data, freq; 3223 soc_port_t primary; 3224 int offset, saved_autoneg; 3225 3226 PHY_CONTROL_TYPE_CHECK(type); 3227 3228 pc = EXT_PHY_SW_STATE(unit, port); 3229 rv = SOC_E_NONE; 3230 switch(type) { 3231 case SOC_PHY_CONTROL_PREEMPHASIS: 3232 /* fall through */ 3233 case SOC_PHY_CONTROL_DRIVER_CURRENT: 3234 rv = _phy_54682_tx_control_set(unit, port, type, value); 3235 break; 3236 3237 case SOC_PHY_CONTROL_POWER: 3238 rv = _phy_54682_power_mode_set(unit,port,value); 3239 break; 3240 3241 case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME: 3242 if (value <= PHY_54682_AUTO_PWRDWN_WAKEUP_MAX) { 3243 3244 /* at least one unit */ 3245 if (value < PHY_54682_AUTO_PWRDWN_WAKEUP_UNIT) { 3246 value = PHY_54682_AUTO_PWRDWN_WAKEUP_UNIT; 3247 } 3248 } else { /* anything more then max, set to the max */ 3249 value = PHY_54682_AUTO_PWRDWN_WAKEUP_MAX; 3250 } 3251 SOC_IF_ERROR_RETURN 3252 (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc, 3253 value/PHY_54682_AUTO_PWRDWN_WAKEUP_UNIT, 3254 PHY_54682_AUTO_PWRDWN_WAKEUP_MASK)); 3255 break; 3256 3257 case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME: 3258 /* sleep time configuration is either 2.7s or 5.4 s, default is 2.7s */ 3259 if (value < PHY_54682_AUTO_PWRDWN_SLEEP_MAX) { 3260 data = 0; /* anything less than 5.4s, default to 2.7s */ 3261 } else { 3262 data = PHY_54682_AUTO_PWRDWN_SLEEP_MASK; 3263 } 3264 SOC_IF_ERROR_RETURN 3265 (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc, 3266 data, 3267 PHY_54682_AUTO_PWRDWN_SLEEP_MASK)); 3268 break; 3269 3270 3271 case SOC_PHY_CONTROL_PORT_PRIMARY: 3272 SOC_IF_ERROR_RETURN 3273 (soc_phyctrl_primary_set(unit, port, (soc_port_t)value)); 3274 break; 3275 3276 case SOC_PHY_CONTROL_PORT_OFFSET: 3277 SOC_IF_ERROR_RETURN 3278 (soc_phyctrl_offset_set(unit, port, (int)value)); 3279 break; 3280 3281 case SOC_PHY_CONTROL_CLOCK_ENABLE: 3282 SOC_IF_ERROR_RETURN 3283 (soc_phyctrl_primary_get(unit, port, &primary)); 3284 SOC_IF_ERROR_RETURN 3285 (soc_phyctrl_offset_get(unit, port, &offset)); 3286 SOC_IF_ERROR_RETURN 3287 (phy_54682_toplvl_reg_read(unit, port, primary, 0x0, &data)); 3288 if ( value ) { 3289 SOC_IF_ERROR_RETURN 3290 (phy_54682_toplvl_reg_write(unit, port, primary, 0x0, 3291 ( data & 0xf0 ) | ( offset & 0x7 ))); 3292 } else { 3293 SOC_IF_ERROR_RETURN 3294 (phy_54682_toplvl_reg_write(unit, port, primary, 0x0, 3295 ( data & 0xf0 ) | 0x8 )); 3296 } 3297 break; 3298 3299 case SOC_PHY_CONTROL_CLOCK_SECONDARY_ENABLE: 3300 SOC_IF_ERROR_RETURN 3301 (soc_phyctrl_primary_get(unit, port, &primary)); 3302 SOC_IF_ERROR_RETURN 3303 (soc_phyctrl_offset_get(unit, port, &offset)); 3304 SOC_IF_ERROR_RETURN 3305 (phy_54682_toplvl_reg_read(unit, port, primary, 0x0, &data)); 3306 if ( value ) { 3307 SOC_IF_ERROR_RETURN 3308 (phy_54682_toplvl_reg_write(unit, port, primary, 0x0, 3309 ( data & 0x0f ) | (( offset & 0x7 )<<4 ))); 3310 } else { 3311 SOC_IF_ERROR_RETURN 3312 (phy_54682_toplvl_reg_write(unit, port, primary, 0x0, 3313 ( data & 0x0f ) | (0x8<<4) )); 3314 } 3315 break; 3316 3317 case SOC_PHY_CONTROL_CLOCK_FREQUENCY: 3318 switch (value) { 3319 case 125000: 3320 freq = 0x0; 3321 break; 3322 case 156250: 3323 freq = 0x1; 3324 break; 3325 default: 3326 return SOC_E_CONFIG; 3327 break; 3328 } 3329 do { 3330 pc->phy_id = PHY54682_SLICE_ADDR(pc, 1); 3331 SOC_IF_ERROR_BREAK 3332 (MODIFY_PHY54682_EXP_SERDES_MULTIPLIER_CTRLr(unit, pc, (freq << 9), 3333 (0x1 << 9)), rv); 3334 pc->phy_id = PHY54682_SLICE_ADDR(pc, 5); 3335 SOC_IF_ERROR_BREAK 3336 (MODIFY_PHY54682_EXP_SERDES_MULTIPLIER_CTRLr(unit, pc, (freq << 9), 3337 (0x1 << 9)), rv); 3338 } while(0); 3339 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 3340 break; 3341 3342 case SOC_PHY_CONTROL_EEE: 3343 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3344 rv = SOC_E_UNAVAIL; 3345 } 3346 3347 if (value == 1) { 3348 /* Enable Native EEE */ 3349 SOC_IF_ERROR_RETURN 3350 (_phy_54682_eee_enable(unit, port, 1)); 3351 saved_autoneg = pc->copper.autoneg_enable; 3352 /* Initiate AN */ 3353 SOC_IF_ERROR_RETURN 3354 (phy_54682_autoneg_set(unit, port, 1)); 3355 pc->copper.autoneg_enable = saved_autoneg; 3356 PHY_FLAGS_SET(unit, pc->port, PHY_FLAGS_EEE_ENABLED); 3357 PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_MODE); 3358 } else { 3359 SOC_IF_ERROR_RETURN 3360 (_phy_54682_eee_enable(unit, port, 0)); 3361 /* Initiate AN if administratively enabled */ 3362 SOC_IF_ERROR_RETURN 3363 (phy_54682_autoneg_set(unit, port, pc->copper.autoneg_enable ? 1 : 0)); 3364 PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_ENABLED); 3365 } 3366 break; 3367 3368 case SOC_PHY_CONTROL_EEE_AUTO: 3369 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3370 rv = SOC_E_UNAVAIL; 3371 } 3372 3373 if (value == 1) { 3374 /* Disable Native EEE */ 3375 SOC_IF_ERROR_RETURN 3376 (_phy_54682_eee_enable(unit, port, 0)); 3377 /* Enable Auto EEE */ 3378 SOC_IF_ERROR_RETURN 3379 (_phy_54682_eee_auto_enable(unit, port, 1)); 3380 saved_autoneg = pc->copper.autoneg_enable; 3381 /* Initiate AN */ 3382 SOC_IF_ERROR_RETURN 3383 (phy_54682_autoneg_set(unit, port, 1)); 3384 pc->copper.autoneg_enable = saved_autoneg; 3385 PHY_FLAGS_SET(unit, pc->port, PHY_FLAGS_EEE_ENABLED); 3386 PHY_FLAGS_SET(unit, pc->port, PHY_FLAGS_EEE_MODE); 3387 } else { 3388 /* Disable Auto EEE */ 3389 SOC_IF_ERROR_RETURN 3390 (_phy_54682_eee_auto_enable(unit, port, 0)); 3391 /* Initiate AN if administratively enabled */ 3392 SOC_IF_ERROR_RETURN 3393 (phy_54682_autoneg_set(unit, port, pc->copper.autoneg_enable ? 1 : 0)); 3394 PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_ENABLED); 3395 } 3396 break; 3397 3398 case SOC_PHY_CONTROL_EEE_AUTO_IDLE_THRESHOLD: 3399 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3400 rv = SOC_E_UNAVAIL; 3401 } 3402 3403 if (value > 7) { /* Values needs to between 0 to 7 (inclusive) */ 3404 rv = SOC_E_CONFIG; 3405 } 3406 3407 SOC_IF_ERROR_RETURN 3408 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 7, 3409 value<<8, 0x0700)); 3410 /* Setting GPHY core, MII buffer register as well */ 3411 SOC_IF_ERROR_RETURN 3412 (MODIFY_PHY54682_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 3413 value<<8, 0x0700)); 3414 break; 3415 3416 3417 case SOC_PHY_CONTROL_EEE_AUTO_FIXED_LATENCY: 3418 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3419 rv = SOC_E_UNAVAIL; 3420 } 3421 /* Fixed latency can have only 0 or 1 value */ 3422 if ((value != FALSE) && (value != TRUE)) { 3423 return SOC_E_PARAM; 3424 } 3425 if (value == FALSE) { 3426 /* Sets Variable Latency */ 3427 SOC_IF_ERROR_RETURN 3428 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 7, 3429 0x0004, 0x0004)); 3430 /* Setting GPHY core, MII buffer register as well */ 3431 SOC_IF_ERROR_RETURN 3432 (MODIFY_PHY54682_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 3433 0x0004, 0x0004)); 3434 } else { 3435 /* Sets Fixed Latency */ 3436 SOC_IF_ERROR_RETURN 3437 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 7, 3438 0x0000, 0x0004)); 3439 /* Setting GPHY core, MII buffer register as well */ 3440 SOC_IF_ERROR_RETURN 3441 (MODIFY_PHY54682_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 3442 0x0000, 0x0004)); 3443 } 3444 break; 3445 3446 3447 case SOC_PHY_CONTROL_EEE_AUTO_BUFFER_LIMIT: 3448 /* Buffer limit modification is not allowed */ 3449 3450 case SOC_PHY_CONTROL_EEE_TRANSMIT_WAKE_TIME: 3451 case SOC_PHY_CONTROL_EEE_RECEIVE_WAKE_TIME: 3452 case SOC_PHY_CONTROL_EEE_TRANSMIT_SLEEP_TIME: 3453 case SOC_PHY_CONTROL_EEE_RECEIVE_SLEEP_TIME: 3454 case SOC_PHY_CONTROL_EEE_TRANSMIT_QUIET_TIME: 3455 case SOC_PHY_CONTROL_EEE_RECEIVE_QUIET_TIME: 3456 case SOC_PHY_CONTROL_EEE_TRANSMIT_REFRESH_TIME: 3457 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3458 rv = SOC_E_UNAVAIL; 3459 } 3460 3461 /* Time modification not allowed, IEEE EEE spec constants */ 3462 rv = SOC_E_UNAVAIL; 3463 break; 3464 3465 case SOC_PHY_CONTROL_EEE_STATISTICS_CLEAR: 3466 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3467 rv = SOC_E_UNAVAIL; 3468 } 3469 3470 if (value == 1) { 3471 /* Clearing the stats: Enable clear on Read */ 3472 SOC_IF_ERROR_RETURN 3473 (MODIFY_PHY54682_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 3474 0x1000, 0x1000)); 3475 3476 /* Read all the stats to clear */ 3477 SOC_IF_ERROR_RETURN 3478 (READ_PHY54682_EXP_EEE_TX_EVENTSr(unit, pc, &data)); 3479 SOC_IF_ERROR_RETURN 3480 (READ_PHY54682_EXP_EEE_TX_EVENTSr(unit, pc, &data)); 3481 SOC_IF_ERROR_RETURN 3482 (READ_PHY54682_EXP_EEE_TX_DURATIONr(unit, pc, &data)); 3483 SOC_IF_ERROR_RETURN 3484 (READ_PHY54682_EXP_EEE_TX_DURATIONr(unit, pc, &data)); 3485 SOC_IF_ERROR_RETURN 3486 (READ_PHY54682_EXP_EEE_RX_EVENTSr(unit, pc, &data)); 3487 SOC_IF_ERROR_RETURN 3488 (READ_PHY54682_EXP_EEE_RX_EVENTSr(unit, pc, &data)); 3489 SOC_IF_ERROR_RETURN 3490 (READ_PHY54682_EXP_EEE_RX_DURATIONr(unit, pc, &data)); 3491 SOC_IF_ERROR_RETURN 3492 (READ_PHY54682_EXP_EEE_RX_DURATIONr(unit, pc, &data)); 3493 3494 /* Disable Clear on Read */ 3495 SOC_IF_ERROR_RETURN 3496 (MODIFY_PHY54682_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 3497 0x0000, 0x1000)); 3498 } 3499 3500 break; 3501 3502 case SOC_PHY_CONTROL_LOOPBACK_EXTERNAL: 3503 if (value) { 3504 int saved_autoneg, saved_speed; 3505 3506 saved_autoneg = pc->copper.autoneg_enable; 3507 SOC_IF_ERROR_RETURN 3508 (phy_54682_autoneg_set(unit, port, 0)); 3509 pc->copper.autoneg_enable = saved_autoneg; 3510 3511 saved_speed = pc->copper.force_speed; 3512 SOC_IF_ERROR_RETURN 3513 (phy_54682_speed_set(unit, port, 1000)); 3514 pc->copper.force_speed = saved_speed; 3515 3516 SOC_IF_ERROR_RETURN 3517 (MODIFY_PHY54682_MII_GB_CTRLr(unit, pc, (1U << 12 | 1U << 11), (1U << 12 | 1U << 11))); 3518 SOC_IF_ERROR_RETURN 3519 (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, (1U << 15 | 1U << 10), (1U << 15 | 1U << 10))); 3520 } else { 3521 SOC_IF_ERROR_RETURN 3522 (MODIFY_PHY54682_MII_GB_CTRLr(unit, pc, 0, (1U << 12 | 1U << 11))); 3523 SOC_IF_ERROR_RETURN 3524 (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0, (1U << 15 | 1U << 10))); 3525 SOC_IF_ERROR_RETURN 3526 (phy_54682_speed_set(unit, port, pc->copper.force_speed)); 3527 SOC_IF_ERROR_RETURN 3528 (phy_54682_autoneg_set(unit, port, pc->copper.autoneg_enable ? 1 : 0)); 3529 } 3530 break; 3531 3532 default: 3533 rv = SOC_E_UNAVAIL; 3534 break; 3535 } 3536 return rv; 3537 } 3538 /* 3539 * Function: 3540 * phy_54682_control_get 3541 * Purpose: 3542 * Get current control settign of the PHY. 3543 * Parameters: 3544 * unit - StrataSwitch unit #. 3545 * port - StrataSwitch port #. 3546 * type - Control to update 3547 * value - (OUT)Current setting for the control 3548 * Returns: 3549 * SOC_E_NONE 3550 */ 3551 STATIC int 3552 phy_54682_control_get(int unit, soc_port_t port, 3553 soc_phy_control_t type, uint32 *value) 3554 { 3555 int rv; 3556 phy_ctrl_t *pc; 3557 uint16 data; 3558 uint32 temp; 3559 soc_port_t primary; 3560 int offset; 3561 3562 PHY_CONTROL_TYPE_CHECK(type); 3563 3564 pc = EXT_PHY_SW_STATE(unit, port); 3565 rv = SOC_E_NONE; 3566 switch(type) { 3567 case SOC_PHY_CONTROL_PREEMPHASIS: 3568 /* fall through */ 3569 case SOC_PHY_CONTROL_DRIVER_CURRENT: 3570 rv = _phy_54682_tx_control_get(unit, port, type, value); 3571 break; 3572 3573 case SOC_PHY_CONTROL_POWER: 3574 *value = pc->power_mode; 3575 break; 3576 3577 case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME: 3578 SOC_IF_ERROR_RETURN 3579 (READ_PHY54682_AUTO_POWER_DOWNr(unit,pc, &data)); 3580 3581 if (data & PHY_54682_AUTO_PWRDWN_SLEEP_MASK) { 3582 *value = PHY_54682_AUTO_PWRDWN_SLEEP_MAX; 3583 } else { 3584 *value = 2700; 3585 } 3586 break; 3587 3588 case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME: 3589 SOC_IF_ERROR_RETURN 3590 (READ_PHY54682_AUTO_POWER_DOWNr(unit,pc, &data)); 3591 3592 data &= PHY_54682_AUTO_PWRDWN_WAKEUP_MASK; 3593 *value = data * PHY_54682_AUTO_PWRDWN_WAKEUP_UNIT; 3594 break; 3595 3596 case SOC_PHY_CONTROL_PORT_PRIMARY: 3597 SOC_IF_ERROR_RETURN 3598 (soc_phyctrl_primary_get(unit, port, &primary)); 3599 *value = (uint32) primary; 3600 break; 3601 3602 case SOC_PHY_CONTROL_PORT_OFFSET: 3603 SOC_IF_ERROR_RETURN 3604 (soc_phyctrl_offset_get(unit, port, &offset)); 3605 *value = (uint32) offset; 3606 break; 3607 3608 case SOC_PHY_CONTROL_CLOCK_ENABLE: 3609 SOC_IF_ERROR_RETURN 3610 (soc_phyctrl_primary_get(unit, port, &primary)); 3611 SOC_IF_ERROR_RETURN 3612 (soc_phyctrl_offset_get(unit, port, &offset)); 3613 if (phy_54682_toplvl_reg_read(unit, port, primary, 0x0, &data) == SOC_E_NONE) { 3614 if (( data & 0x8 ) || (( data & 0x7 ) != offset)) { 3615 *value = FALSE; 3616 } else { 3617 *value = TRUE; 3618 } 3619 } 3620 break; 3621 3622 case SOC_PHY_CONTROL_CLOCK_SECONDARY_ENABLE: 3623 SOC_IF_ERROR_RETURN 3624 (soc_phyctrl_primary_get(unit, port, &primary)); 3625 SOC_IF_ERROR_RETURN 3626 (soc_phyctrl_offset_get(unit, port, &offset)); 3627 if (phy_54682_toplvl_reg_read(unit, port, primary, 0x0, &data) == SOC_E_NONE) { 3628 if (( data & (0x8<<4) ) || (( data & (0x7<<4) ) != (offset<<4) )) { 3629 *value = FALSE; 3630 } else { 3631 *value = TRUE; 3632 } 3633 } 3634 break; 3635 3636 case SOC_PHY_CONTROL_CLOCK_FREQUENCY: 3637 do { 3638 pc->phy_id = PHY54682_SLICE_ADDR(pc, 1); 3639 SOC_IF_ERROR_BREAK 3640 (READ_PHY54682_EXP_SERDES_MULTIPLIER_CTRLr(unit, pc, &data), rv); 3641 if ((data >> 9) & 0x1) { 3642 *value = 156250; 3643 } else { 3644 *value = 125000; 3645 } 3646 } while(0); 3647 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 3648 break; 3649 3650 case SOC_PHY_CONTROL_EEE: 3651 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3652 rv = SOC_E_UNAVAIL; 3653 } 3654 *value = (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_ENABLED) && 3655 !PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_MODE)) ? 1 : 0; 3656 break; 3657 3658 case SOC_PHY_CONTROL_EEE_AUTO: 3659 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3660 rv = SOC_E_UNAVAIL; 3661 } 3662 *value = (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_ENABLED) && 3663 PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_MODE)) ? 1 : 0; 3664 break; 3665 3666 case SOC_PHY_CONTROL_EEE_AUTO_FIXED_LATENCY: 3667 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3668 rv = SOC_E_UNAVAIL; 3669 } 3670 SOC_IF_ERROR_RETURN 3671 (READ_PHY54682_EXP_MII_BUF_CNTL_STAT1r(unit, pc, &data)); 3672 *value = ((data & 0x0004) == 0); 3673 break; 3674 3675 case SOC_PHY_CONTROL_EEE_AUTO_IDLE_THRESHOLD: 3676 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3677 rv = SOC_E_UNAVAIL; 3678 } 3679 SOC_IF_ERROR_RETURN 3680 (READ_PHY54682_EXP_MII_BUF_CNTL_STAT1r(unit, pc, &data)); 3681 *value = ((data & 0x0700) >> 8); 3682 break; 3683 3684 case SOC_PHY_CONTROL_EEE_TRANSMIT_EVENTS: 3685 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3686 rv = SOC_E_UNAVAIL; 3687 } 3688 SOC_IF_ERROR_RETURN 3689 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */ 3690 SOC_IF_ERROR_RETURN 3691 (READ_PHY54682_EXP_EEE_TX_EVENTSr(unit, pc, &data)); 3692 temp = data; 3693 SOC_IF_ERROR_RETURN 3694 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */ 3695 SOC_IF_ERROR_RETURN 3696 (READ_PHY54682_EXP_EEE_TX_EVENTSr(unit, pc, &data)); 3697 temp |= (data << 16); 3698 *value = temp; 3699 3700 break; 3701 3702 case SOC_PHY_CONTROL_EEE_TRANSMIT_DURATION: 3703 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3704 rv = SOC_E_UNAVAIL; 3705 } 3706 SOC_IF_ERROR_RETURN 3707 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */ 3708 SOC_IF_ERROR_RETURN 3709 (READ_PHY54682_EXP_EEE_TX_DURATIONr(unit, pc, &data)); 3710 temp = data; 3711 SOC_IF_ERROR_RETURN 3712 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */ 3713 SOC_IF_ERROR_RETURN 3714 (READ_PHY54682_EXP_EEE_TX_DURATIONr(unit, pc, &data)); 3715 temp |= (data << 16); 3716 *value = temp; 3717 3718 break; 3719 3720 case SOC_PHY_CONTROL_EEE_RECEIVE_EVENTS: 3721 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3722 rv = SOC_E_UNAVAIL; 3723 } 3724 SOC_IF_ERROR_RETURN 3725 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */ 3726 SOC_IF_ERROR_RETURN 3727 (READ_PHY54682_EXP_EEE_RX_EVENTSr(unit, pc, &data)); 3728 temp = data; 3729 SOC_IF_ERROR_RETURN 3730 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */ 3731 SOC_IF_ERROR_RETURN 3732 (READ_PHY54682_EXP_EEE_RX_EVENTSr(unit, pc, &data)); 3733 temp |= (data << 16); 3734 *value = temp; 3735 3736 break; 3737 3738 case SOC_PHY_CONTROL_EEE_RECEIVE_DURATION: 3739 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 3740 rv = SOC_E_UNAVAIL; 3741 } 3742 SOC_IF_ERROR_RETURN 3743 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */ 3744 SOC_IF_ERROR_RETURN 3745 (READ_PHY54682_EXP_EEE_RX_DURATIONr(unit, pc, &data)); 3746 temp = data; 3747 SOC_IF_ERROR_RETURN 3748 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */ 3749 SOC_IF_ERROR_RETURN 3750 (READ_PHY54682_EXP_EEE_RX_DURATIONr(unit, pc, &data)); 3751 temp |= (data << 16); 3752 *value = temp; 3753 break; 3754 3755 case SOC_PHY_CONTROL_LOOPBACK_EXTERNAL: 3756 SOC_IF_ERROR_RETURN 3757 (READ_PHY54682_MII_AUX_CTRLr(unit, pc, &data)); 3758 *value = data & (1U<<15) ? 1 : 0; 3759 break; 3760 3761 default: 3762 rv = SOC_E_UNAVAIL; 3763 break; 3764 } 3765 return rv; 3766 } 3767 3768 /* 3769 * Function: 3770 * phy_54682_cable_diag 3771 * Purpose: 3772 * Run 546x cable diagnostics 3773 * Parameters: 3774 * unit - device number 3775 * port - port number 3776 * status - (OUT) cable diagnotic status structure 3777 * Returns: 3778 * SOC_E_XXX 3779 */ 3780 STATIC int 3781 phy_54682_cable_diag(int unit, soc_port_t port, 3782 soc_port_cable_diag_t *status) 3783 { 3784 int rv, rv2, i; 3785 phy_ctrl_t *pc; 3786 3787 extern int phy_5464_cable_diag_sw(int, soc_port_t , 3788 soc_port_cable_diag_t *); 3789 pc = EXT_PHY_SW_STATE(unit, port); 3790 3791 if (status == NULL) { 3792 return SOC_E_PARAM; 3793 } 3794 3795 status->state = SOC_PORT_CABLE_STATE_OK; 3796 status->npairs = 4; 3797 status->fuzz_len = 0; 3798 for (i = 0; i < 4; i++) { 3799 status->pair_state[i] = SOC_PORT_CABLE_STATE_OK; 3800 } 3801 3802 MIIM_LOCK(unit); /* this locks out linkscan, essentially */ 3803 rv = phy_5464_cable_diag_sw(unit,port, status); 3804 MIIM_UNLOCK(unit); 3805 rv2 = 0; 3806 if (rv <= 0) { /* don't reset if > 0 -- link was up */ 3807 rv2 = _phy_54682_reset_setup(unit, port); 3808 if (SOC_SUCCESS(rv2)) { 3809 rv2 = _phy_54682_medium_config_update(unit, port, &pc->copper); 3810 } 3811 } 3812 if (rv >= 0 && rv2 < 0) { 3813 return rv2; 3814 } 3815 return rv; 3816 } 3817 3818 STATIC int 3819 phy54682_cable_diag_dispatch(int unit, soc_port_t port, 3820 soc_port_cable_diag_t *status) 3821 { 3822 phy_ctrl_t *pc; 3823 3824 pc = EXT_PHY_SW_STATE(unit, port); 3825 3826 if (ECD_ENABLE && (((PHY_IS_BCM54682E_OR_BCM54685E(pc)) || (PHY_IS_BCM54684E(pc))) && ((pc->phy_rev & 0x7) > 0x2))) { 3827 SOC_IF_ERROR_RETURN( 3828 phy_ecd_cable_diag(unit, port, status)); 3829 SOC_IF_ERROR_RETURN( 3830 _phy_54682_reset_setup(unit, port)); 3831 } else { 3832 SOC_IF_ERROR_RETURN( 3833 phy_54682_cable_diag(unit, port, status)); 3834 } 3835 3836 return SOC_E_NONE; 3837 } 3838 3839 /* 3840 * Function: 3841 * phy_54682_probe 3842 * Purpose: 3843 * Complement the generic phy probe routine to identify this phy when its 3844 * phy id0 and id1 is same as some other phy's. 3845 * Parameters: 3846 * unit - StrataSwitch unit #. 3847 * pc - phy ctrl descriptor. 3848 * Returns: 3849 * SOC_E_NONE,SOC_E_NOT_FOUND 3850 */ 3851 3852 STATIC int 3853 phy_54682_probe(int unit, phy_ctrl_t *pc) 3854 { 3855 uint16 id0, id1; 3856 soc_phy_info_t *pi; 3857 3858 if (READ_PHY54682_MII_PHY_ID0r(unit, pc, &id0) < 0) { 3859 return SOC_E_NOT_FOUND; 3860 } 3861 if (READ_PHY54682_MII_PHY_ID1r(unit, pc, &id1) < 0) { 3862 return SOC_E_NOT_FOUND; 3863 } 3864 if (id1 & 0x8) { 3865 pi = &SOC_PHY_INFO(unit, pc->port); 3866 pi->phy_name = "BCM54685E"; 3867 } 3868 return SOC_E_NONE; 3869 } 3870 3871 STATIC int 3872 phy_54682_link_up(int unit, soc_port_t port) 3873 { 3874 phy_ctrl_t *pc; 3875 int speed = 0; 3876 uint16 value; 3877 3878 pc = EXT_PHY_SW_STATE(unit, port); 3879 3880 SOC_IF_ERROR_RETURN 3881 (phy_54682_speed_get(unit, port, &speed)); 3882 3883 if (speed == 100) { 3884 SOC_IF_ERROR_RETURN( 3885 READ_PHY_REG(unit, pc, 0x11, &value)); 3886 if(value & (1U << 13)) { 3887 SOC_IF_ERROR_RETURN 3888 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FF5,0x15, 0x0<<10, 0x3<<10)); /* exp reg f5 */ 3889 } else { 3890 SOC_IF_ERROR_RETURN 3891 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FF5,0x15, 0x1<<10, 0x3<<10)); /* exp reg f5 */ 3892 } 3893 } 3894 3895 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { /*non EEE */ 3896 /* do nothing */ 3897 } else 3898 if ((pc->phy_rev & 0x6) == 0x0) { 3899 /* revs A0 and A1 of supported PHYs */ 3900 uint32 eee_auto; 3901 3902 SOC_IF_ERROR_RETURN 3903 (phy_54682_control_get(unit, port, 3904 SOC_PHY_CONTROL_EEE_AUTO, &eee_auto)); 3905 if ((speed == 100) && (eee_auto == 1)) { 3906 SOC_IF_ERROR_RETURN( 3907 WRITE_PHY_REG(unit, pc, 0x17, 0x0d10)); 3908 SOC_IF_ERROR_RETURN( 3909 WRITE_PHY_REG(unit, pc, 0x15, 0x00ff)); 3910 3911 } else { 3912 SOC_IF_ERROR_RETURN( 3913 WRITE_PHY_REG(unit, pc, 0x17, 0x0d10)); 3914 SOC_IF_ERROR_RETURN( 3915 WRITE_PHY_REG(unit, pc, 0x15, 0x0000)); 3916 } 3917 } else if ((pc->phy_rev & 0x6) == 0x2) { 3918 /* revs B0 and B1 of supported PHYs */ 3919 sal_usleep(10000); 3920 SOC_IF_ERROR_RETURN( 3921 MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, (1U << 11), (1U << 11))); 3922 SOC_IF_ERROR_RETURN( 3923 WRITE_PHY_REG(unit, pc, 0x17, 0x001a)); 3924 SOC_IF_ERROR_RETURN( 3925 WRITE_PHY_REG(unit, pc, 0x15, 0x0003)); 3926 SOC_IF_ERROR_RETURN( 3927 MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0, (1U << 11))); 3928 } 3929 3930 /* Notify interface to internal PHY */ 3931 SOC_IF_ERROR_RETURN 3932 (soc_phyctrl_notify(unit, port, phyEventInterface, SOC_PORT_IF_SGMII)); 3933 3934 /* Situation observed with Saber devices XGXS16g1l+BCM54682E 3935 Linkscan is not updating speed for internal phy xgxs16g1l. 3936 It was observed that when speed is set to 100M the int phy 3937 is still set to 1G and traffic does not flow through untill 3938 int phy speed is also update to 100M. This applies to other 3939 speeds as well. 3940 Explicitly send speed notify to int phy from ext phy. 3941 */ 3942 SOC_IF_ERROR_RETURN 3943 (soc_phyctrl_notify(unit, port, phyEventSpeed, speed)); 3944 3945 return SOC_E_NONE; 3946 } 3947 3948 STATIC int 3949 phy_54682_link_down(int unit, soc_port_t port) 3950 { 3951 phy_ctrl_t *pc; 3952 3953 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { /*non EEE */ 3954 return SOC_E_NONE; 3955 } 3956 3957 pc = EXT_PHY_SW_STATE(unit, port); 3958 3959 if ((pc->phy_rev & 0x6) == 0x2) { 3960 /* revs B0 and B1 of supported PHYs */ 3961 SOC_IF_ERROR_RETURN( 3962 MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, (1U << 11), (1U << 11))); 3963 SOC_IF_ERROR_RETURN( 3964 WRITE_PHY_REG(unit, pc, 0x17, 0x001a)); 3965 SOC_IF_ERROR_RETURN( 3966 WRITE_PHY_REG(unit, pc, 0x15, 0x0007)); 3967 SOC_IF_ERROR_RETURN( 3968 MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0, (1U << 11))); 3969 3970 } 3971 3972 return (SOC_E_NONE); 3973 } 3974 3975 void _phy_54682e_encode_egress_message_mode(soc_port_phy_timesync_event_message_egress_mode_t mode, 3976 int offset, uint16 *value) 3977 { 3978 3979 switch (mode) { 3980 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_NONE: 3981 *value |= (0x0 << offset); 3982 break; 3983 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_UPDATE_CORRECTIONFIELD: 3984 *value |= (0x1 << offset); 3985 break; 3986 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_REPLACE_CORRECTIONFIELD_ORIGIN: 3987 *value |= (0x2 << offset); 3988 break; 3989 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_CAPTURE_TIMESTAMP: 3990 *value |= (0x3 << offset); 3991 break; 3992 default: 3993 break; 3994 } 3995 3996 } 3997 3998 void _phy_54682e_encode_ingress_message_mode(soc_port_phy_timesync_event_message_ingress_mode_t mode, 3999 int offset, uint16 *value) 4000 { 4001 4002 switch (mode) { 4003 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_NONE: 4004 *value |= (0x0 << offset); 4005 break; 4006 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_UPDATE_CORRECTIONFIELD: 4007 *value |= (0x1 << offset); 4008 break; 4009 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_TIMESTAMP: 4010 *value |= (0x2 << offset); 4011 break; 4012 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_DELAYTIME: 4013 *value |= (0x3 << offset); 4014 break; 4015 default: 4016 break; 4017 } 4018 4019 } 4020 4021 void _phy_54682e_decode_egress_message_mode(uint16 value, int offset, 4022 soc_port_phy_timesync_event_message_egress_mode_t *mode) 4023 { 4024 4025 switch ((value >> offset) & 0x3) { 4026 case 0x0: 4027 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_NONE; 4028 break; 4029 case 0x1: 4030 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_UPDATE_CORRECTIONFIELD; 4031 break; 4032 case 0x2: 4033 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_REPLACE_CORRECTIONFIELD_ORIGIN; 4034 break; 4035 case 0x3: 4036 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_CAPTURE_TIMESTAMP; 4037 break; 4038 } 4039 4040 } 4041 4042 void _phy_54682e_decode_ingress_message_mode(uint16 value, int offset, 4043 soc_port_phy_timesync_event_message_ingress_mode_t *mode) 4044 { 4045 4046 switch ((value >> offset) & 0x3) { 4047 case 0x0: 4048 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_NONE; 4049 break; 4050 case 0x1: 4051 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_UPDATE_CORRECTIONFIELD; 4052 break; 4053 case 0x2: 4054 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_TIMESTAMP; 4055 break; 4056 case 0x3: 4057 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_DELAYTIME; 4058 break; 4059 } 4060 4061 } 4062 4063 void _phy_54682e_encode_gmode(soc_port_phy_timesync_global_mode_t mode, 4064 uint16 *value) 4065 { 4066 4067 switch (mode) { 4068 case SOC_PORT_PHY_TIMESYNC_MODE_FREE: 4069 *value = 0x1; 4070 break; 4071 case SOC_PORT_PHY_TIMESYNC_MODE_SYNCIN: 4072 *value = 0x2; 4073 break; 4074 case SOC_PORT_PHY_TIMESYNC_MODE_CPU: 4075 *value = 0x3; 4076 break; 4077 default: 4078 break; 4079 } 4080 4081 } 4082 4083 void _phy_54682e_decode_gmode(uint16 value, 4084 soc_port_phy_timesync_global_mode_t *mode) 4085 { 4086 4087 switch (value & 0x3) { 4088 case 0x1: 4089 *mode = SOC_PORT_PHY_TIMESYNC_MODE_FREE; 4090 break; 4091 case 0x2: 4092 *mode = SOC_PORT_PHY_TIMESYNC_MODE_SYNCIN; 4093 break; 4094 case 0x3: 4095 *mode = SOC_PORT_PHY_TIMESYNC_MODE_CPU; 4096 break; 4097 default: 4098 break; 4099 } 4100 4101 } 4102 4103 void _phy_54682e_encode_framesync_mode(soc_port_phy_timesync_framesync_mode_t mode, 4104 uint16 *value) 4105 { 4106 4107 switch (mode) { 4108 case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN0: 4109 *value = 1U << 0; 4110 break; 4111 case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN1: 4112 *value = 1U << 1; 4113 break; 4114 case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCOUT: 4115 *value = 1U << 2; 4116 break; 4117 case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_CPU: 4118 *value = 1U << 3; 4119 break; 4120 default: 4121 break; 4122 } 4123 4124 } 4125 4126 void _phy_54682e_decode_framesync_mode(uint16 value, 4127 soc_port_phy_timesync_framesync_mode_t *mode) 4128 { 4129 4130 switch (value & 0xf) { 4131 case 1U << 0: 4132 *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN0; 4133 break; 4134 case 1U << 1: 4135 *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN1; 4136 break; 4137 case 1U << 2: 4138 *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCOUT; 4139 break; 4140 case 1U << 3: 4141 *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_CPU; 4142 break; 4143 default: 4144 break; 4145 } 4146 4147 } 4148 4149 void _phy_54682e_encode_syncout_mode(soc_port_phy_timesync_syncout_mode_t mode, 4150 uint16 *value) 4151 { 4152 4153 switch (mode) { 4154 case SOC_PORT_PHY_TIMESYNC_SYNCOUT_DISABLE: 4155 *value = 0x0; 4156 break; 4157 case SOC_PORT_PHY_TIMESYNC_SYNCOUT_ONE_TIME: 4158 *value = 0x1; 4159 break; 4160 case SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN: 4161 *value = 0x2; 4162 break; 4163 case SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN_WITH_SYNC: 4164 *value = 0x3; 4165 break; 4166 default: 4167 break; 4168 } 4169 4170 } 4171 4172 void _phy_54682e_decode_syncout_mode(uint16 value, 4173 soc_port_phy_timesync_syncout_mode_t *mode) 4174 { 4175 4176 switch (value & 0x3) { 4177 case 0x0: 4178 *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_DISABLE; 4179 break; 4180 case 0x1: 4181 *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_ONE_TIME; 4182 break; 4183 case 0x2: 4184 *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN; 4185 break; 4186 case 0x3: 4187 *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN_WITH_SYNC; 4188 break; 4189 } 4190 4191 } 4192 4193 4194 STATIC int 4195 phy_54682_timesync_config_set(int unit, soc_port_t port, soc_port_phy_timesync_config_t *conf) 4196 { 4197 phy_ctrl_t *pc; 4198 int offset, rv = SOC_E_NONE; 4199 uint16 rx_control_reg = 0, tx_control_reg = 0, rx_crc_control_reg = 0, 4200 en_control_reg = 0, tx_capture_en_reg = 0, rx_capture_en_reg = 0, 4201 nse_nco_6 = 0, nse_nco_2c = 0, value, mask, 4202 gmode = 0, framesync_mode = 0, syncout_mode = 0, 4203 pulse_1_length, pulse_2_length, length_threshold, event_offset; 4204 uint32 interval; 4205 4206 pc = EXT_PHY_SW_STATE(unit, port); 4207 4208 if ((!(PHY_IS_BCM54682E_OR_BCM54685E(pc) || PHY_IS_BCM54684E(pc))) || PHY_IS_BCM54682E_OR_BCM54685E_A0A1(pc)) { 4209 return SOC_E_UNAVAIL; 4210 } 4211 4212 offset = PHY54682_DEV_PHY_SLICE(pc); 4213 4214 do { 4215 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FLAGS) { 4216 4217 if (conf->flags & SOC_PORT_PHY_TIMESYNC_ENABLE) { 4218 en_control_reg |= ((1U << (offset + 8)) | (1U << offset)); 4219 nse_nco_6 |= (1U << 12); /* NSE init */ 4220 4221 SOC_IF_ERROR_BREAK 4222 (MODIFY_PHY54682_SGMII_SLAVEr(unit, pc, 0x02, 0x02), rv); 4223 4224 SOC_IF_ERROR_BREAK 4225 (MODIFY_PHY54682_EXT_SERDES_CTRLr(unit, pc, 0x00, 0x01), rv); 4226 4227 SOC_IF_ERROR_BREAK 4228 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FF5,0x15, 1U<<0, 1U<<0), rv); /* exp reg f5 */ 4229 } else { 4230 4231 SOC_IF_ERROR_BREAK 4232 (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FF5,0x15, 0, 1U<<0), rv); /* exp reg f5 */ 4233 4234 } 4235 4236 /* pc->phy_id = PHY54682_SLICE_ADDR(pc, 0); */ 4237 pc->phy_id = PHY54682_DEV_PHY_ID_BASE(pc); 4238 4239 SOC_IF_ERROR_BREAK 4240 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x10, en_control_reg, 4241 ((1U << (offset + 8)) | (1U << offset))), rv); 4242 4243 SOC_IF_ERROR_BREAK 4244 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x10, &en_control_reg), rv); 4245 4246 if (conf->flags & SOC_PORT_PHY_TIMESYNC_CAPTURE_TS_ENABLE) { 4247 tx_capture_en_reg |= (1U << offset); 4248 rx_capture_en_reg |= (1U << (offset + 8)); 4249 } 4250 4251 SOC_IF_ERROR_BREAK 4252 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x12, tx_capture_en_reg, 4253 (1U << offset)), rv); 4254 4255 SOC_IF_ERROR_BREAK 4256 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x13, rx_capture_en_reg, 4257 (1U << (offset + 8))), rv); 4258 4259 if (conf->flags & SOC_PORT_PHY_TIMESYNC_HEARTBEAT_TS_ENABLE) { 4260 nse_nco_6 |= (1U << 13); 4261 } 4262 4263 SOC_IF_ERROR_BREAK 4264 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x4f, nse_nco_6, 4265 (1U << 13)), rv); 4266 4267 if (conf->flags & SOC_PORT_PHY_TIMESYNC_RX_CRC_ENABLE) { 4268 rx_crc_control_reg |= (1U << 3); 4269 } 4270 4271 SOC_IF_ERROR_BREAK 4272 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x34, rx_crc_control_reg), rv); 4273 4274 if (conf->flags & SOC_PORT_PHY_TIMESYNC_8021AS_ENABLE) { 4275 rx_control_reg |= (1U << 3); 4276 tx_control_reg |= (1U << 3); 4277 } 4278 4279 if (conf->flags & SOC_PORT_PHY_TIMESYNC_L2_ENABLE) { 4280 rx_control_reg |= (1U << 2); 4281 tx_control_reg |= (1U << 2); 4282 } 4283 4284 if (conf->flags & SOC_PORT_PHY_TIMESYNC_IP4_ENABLE) { 4285 rx_control_reg |= (1U << 1); 4286 tx_control_reg |= (1U << 1); 4287 } 4288 4289 if (conf->flags & SOC_PORT_PHY_TIMESYNC_IP6_ENABLE) { 4290 rx_control_reg |= (1U << 0); 4291 tx_control_reg |= (1U << 0); 4292 } 4293 4294 SOC_IF_ERROR_BREAK 4295 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x32, tx_control_reg), rv); 4296 4297 SOC_IF_ERROR_BREAK 4298 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x33, rx_control_reg), rv); 4299 4300 if (conf->flags & SOC_PORT_PHY_TIMESYNC_CLOCK_SRC_EXT) { 4301 nse_nco_2c &= (uint16) ~(1U << 14); 4302 } else { 4303 nse_nco_2c |= (1U << 14); 4304 } 4305 4306 SOC_IF_ERROR_BREAK 4307 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x47, nse_nco_2c, 4308 (1U << 14)), rv); 4309 } 4310 4311 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ITPID) { 4312 /* VLAN TAG register */ 4313 SOC_IF_ERROR_BREAK 4314 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x35, conf->itpid), rv); 4315 } 4316 4317 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID) { 4318 /* OUTER VLAN TAG register */ 4319 SOC_IF_ERROR_BREAK 4320 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x36, conf->otpid), rv); 4321 } 4322 4323 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID2) { 4324 /* INNER VLAN TAG register */ 4325 SOC_IF_ERROR_BREAK 4326 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x52, conf->otpid2), rv); 4327 } 4328 4329 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TS_DIVIDER) { 4330 SOC_IF_ERROR_BREAK 4331 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4b, conf->ts_divider & 0xfff), rv); 4332 } 4333 4334 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_LINK_DELAY) { 4335 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 4336 4337 SOC_IF_ERROR_BREAK 4338 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x6f, conf->rx_link_delay & 0xffff), rv); 4339 SOC_IF_ERROR_BREAK 4340 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x70, (conf->rx_link_delay >> 16) & 0xffff), rv); 4341 4342 /* pc->phy_id = PHY54682_SLICE_ADDR(pc, 0); */ 4343 pc->phy_id = PHY54682_DEV_PHY_ID_BASE(pc); 4344 } 4345 4346 4347 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ORIGINAL_TIMECODE) { 4348 SOC_IF_ERROR_BREAK 4349 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x25, (uint16)(conf->original_timecode.nanoseconds & 0xffff)), rv); 4350 4351 SOC_IF_ERROR_BREAK 4352 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x26, (uint16)((conf->original_timecode.nanoseconds >> 16) & 0xffff)), rv); 4353 4354 SOC_IF_ERROR_BREAK 4355 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x27, (uint16)(COMPILER_64_LO(conf->original_timecode.seconds) & 0xffff)), rv); 4356 4357 SOC_IF_ERROR_BREAK 4358 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x28, (uint16)((COMPILER_64_LO(conf->original_timecode.seconds) >> 16) & 0xffff)), rv); 4359 4360 SOC_IF_ERROR_BREAK 4361 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x29, (uint16)(COMPILER_64_HI(conf->original_timecode.seconds) & 0xffff)), rv); 4362 } 4363 mask = 0; 4364 4365 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_GMODE) { 4366 _phy_54682e_encode_gmode(conf->gmode,&gmode); 4367 mask |= (0x3 << 14); 4368 } 4369 4370 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FRAMESYNC_MODE) { 4371 _phy_54682e_encode_framesync_mode(conf->framesync.mode, &framesync_mode); 4372 mask |= (0xf << 2) | (0x1 << 11); 4373 4374 /* Divide by 8 */ 4375 length_threshold = conf->framesync.length_threshold >> 3; 4376 event_offset = conf->framesync.event_offset >> 3; 4377 4378 SOC_IF_ERROR_BREAK 4379 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x51, length_threshold), rv); 4380 SOC_IF_ERROR_BREAK 4381 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x50, event_offset), rv); 4382 } 4383 4384 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_SYNCOUT_MODE) { 4385 _phy_54682e_encode_syncout_mode(conf->syncout.mode, &syncout_mode); 4386 mask |= (0x3 << 0); 4387 4388 /* Divide by 8 */ 4389 interval = conf->syncout.interval >> 3; 4390 pulse_1_length = conf->syncout.pulse_1_length >> 3; 4391 pulse_2_length = conf->syncout.pulse_2_length >> 3; 4392 4393 SOC_IF_ERROR_BREAK 4394 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x48, interval & 0xffff), rv); 4395 SOC_IF_ERROR_BREAK 4396 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x49, 4397 ((pulse_2_length & 0x3) << 14) | ((interval >> 16) & 0x3fff)), rv); 4398 SOC_IF_ERROR_BREAK 4399 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4a, 4400 ((pulse_1_length & 0x1ff) << 7) | ((pulse_2_length >> 2) & 0x7f)), rv); 4401 4402 SOC_IF_ERROR_BREAK 4403 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4e, 4404 (uint16)(COMPILER_64_LO(conf->syncout.syncout_ts) & 0xffff)), rv); 4405 SOC_IF_ERROR_BREAK 4406 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4d, 4407 (uint16)((COMPILER_64_LO(conf->syncout.syncout_ts) >> 16) & 0xffff)), rv); 4408 SOC_IF_ERROR_BREAK 4409 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4c, 4410 (uint16)(COMPILER_64_HI(conf->syncout.syncout_ts) & 0xffff)), rv); 4411 } 4412 4413 SOC_IF_ERROR_BREAK 4414 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x4f, (gmode << 14) | 4415 ((framesync_mode & 0x2) ? (1U << 11) : (1U << 6)) | /* if bits 1 or 2 are set, turn off syncout */ 4416 (framesync_mode << 2) | (syncout_mode << 0), mask), rv); 4417 4418 4419 /* tx_timestamp_offset */ 4420 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_TIMESTAMP_OFFSET) { 4421 SOC_IF_ERROR_BREAK 4422 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x15 + offset, (uint16)(conf->tx_timestamp_offset & 0xffff)), rv); 4423 4424 if (offset < 4 ) { 4425 SOC_IF_ERROR_BREAK 4426 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x63, 4427 ((conf->tx_timestamp_offset & 0xf0000) >> ((4 - offset) << 2)), 0xf << (offset << 2)), rv); 4428 } else { 4429 uint16 offset1 = offset - 4; 4430 SOC_IF_ERROR_BREAK 4431 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x64, 4432 ((conf->tx_timestamp_offset & 0xf0000) >> ((4 - offset1) << 2)), 0xf << (offset1 << 2)), rv); 4433 } 4434 } 4435 4436 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_TIMESTAMP_OFFSET) { 4437 /* rx_timestamp_offset */ 4438 SOC_IF_ERROR_BREAK 4439 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x1d + offset, (uint16)(conf->rx_timestamp_offset & 0xffff)), rv); 4440 4441 if (offset < 4 ) { 4442 SOC_IF_ERROR_BREAK 4443 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x65, 4444 ((conf->rx_timestamp_offset & 0xf0000) >> ((4 - offset) << 2)), 0xf << (offset << 2)), rv); 4445 } else { 4446 uint16 offset1 = offset - 4; 4447 SOC_IF_ERROR_BREAK 4448 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x66, 4449 ((conf->rx_timestamp_offset & 0xf0000) >> ((4 - offset1) << 2)), 0xf << (offset1 << 2)), rv); 4450 } 4451 } 4452 4453 value = 0; 4454 mask = 0; 4455 4456 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_SYNC_MODE) { 4457 _phy_54682e_encode_egress_message_mode(conf->tx_sync_mode, 0, &value); 4458 mask |= 0x3 << 0; 4459 } 4460 4461 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_DELAY_REQUEST_MODE) { 4462 _phy_54682e_encode_egress_message_mode(conf->tx_delay_request_mode, 2, &value); 4463 mask |= 0x3 << 2; 4464 } 4465 4466 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_REQUEST_MODE) { 4467 _phy_54682e_encode_egress_message_mode(conf->tx_pdelay_request_mode, 4, &value); 4468 mask |= 0x3 << 4; 4469 } 4470 4471 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_RESPONSE_MODE) { 4472 _phy_54682e_encode_egress_message_mode(conf->tx_pdelay_response_mode, 6, &value); 4473 mask |= 0x3 << 6; 4474 } 4475 4476 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 4477 4478 SOC_IF_ERROR_BREAK 4479 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x11, value, mask), rv); 4480 4481 value = 0; 4482 mask = 0; 4483 4484 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_SYNC_MODE) { 4485 _phy_54682e_encode_ingress_message_mode(conf->rx_sync_mode, 0, &value); 4486 mask |= 0x3 << 0; 4487 } 4488 4489 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_DELAY_REQUEST_MODE) { 4490 _phy_54682e_encode_ingress_message_mode(conf->rx_delay_request_mode, 2, &value); 4491 mask |= 0x3 << 2; 4492 } 4493 4494 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_REQUEST_MODE) { 4495 _phy_54682e_encode_ingress_message_mode(conf->rx_pdelay_request_mode, 4, &value); 4496 mask |= 0x3 << 4; 4497 } 4498 4499 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_RESPONSE_MODE) { 4500 _phy_54682e_encode_ingress_message_mode(conf->rx_pdelay_response_mode, 6, &value); 4501 mask |= 0x3 << 6; 4502 } 4503 4504 4505 SOC_IF_ERROR_BREAK 4506 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x12, value << 8, mask << 8), rv); 4507 4508 4509 /* pc->phy_id = PHY54682_SLICE_ADDR(pc, 0); */ 4510 pc->phy_id = PHY54682_DEV_PHY_ID_BASE(pc); 4511 4512 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE) { 4513 /* Initial ref phase [15:0] */ 4514 SOC_IF_ERROR_BREAK 4515 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x38, (uint16)(COMPILER_64_LO(conf->phy_1588_dpll_ref_phase) & 0xffff)), rv); 4516 4517 /* Initial ref phase [31:16] */ 4518 SOC_IF_ERROR_BREAK 4519 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x39, (uint16)((COMPILER_64_LO(conf->phy_1588_dpll_ref_phase) >> 16) & 0xffff)), rv); 4520 4521 /* Initial ref phase [47:32] */ 4522 SOC_IF_ERROR_BREAK 4523 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x3a, (uint16)(COMPILER_64_HI(conf->phy_1588_dpll_ref_phase) & 0xffff)), rv); 4524 } 4525 4526 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE_DELTA) { 4527 /* Ref phase delta [15:0] */ 4528 SOC_IF_ERROR_BREAK 4529 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x3b, (uint16)(conf->phy_1588_dpll_ref_phase_delta & 0xffff)), rv); 4530 4531 /* Ref phase delta [31:16] */ 4532 SOC_IF_ERROR_BREAK 4533 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x3c, (uint16)((conf->phy_1588_dpll_ref_phase_delta >> 16) & 0xffff)), rv); 4534 } 4535 4536 /* DPLL K1 & K2 */ 4537 mask = 0; 4538 4539 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K1) { 4540 mask |= 0xff << 8; 4541 } 4542 4543 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K2) { 4544 mask |= 0xff; 4545 } 4546 SOC_IF_ERROR_BREAK 4547 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x3d, (conf->phy_1588_dpll_k1 & 0xff)<<8 | (conf->phy_1588_dpll_k2 & 0xff), mask ), rv); 4548 4549 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K3) { 4550 /* DPLL K3 */ 4551 SOC_IF_ERROR_BREAK 4552 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x3e, conf->phy_1588_dpll_k3 & 0xff), rv); 4553 } 4554 4555 4556 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_LOOP_FILTER) { 4557 /* Initial loop filter[15:0] */ 4558 SOC_IF_ERROR_BREAK 4559 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x3f, (uint16)(COMPILER_64_LO(conf->phy_1588_dpll_loop_filter) & 0xffff)), rv); 4560 4561 /* Initial loop filter[31:16] */ 4562 SOC_IF_ERROR_BREAK 4563 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x40, (uint16)((COMPILER_64_LO(conf->phy_1588_dpll_loop_filter) >> 16) & 0xffff)), rv); 4564 4565 /* Initial loop filter[47:32] */ 4566 SOC_IF_ERROR_BREAK 4567 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x41, (uint16)(COMPILER_64_HI(conf->phy_1588_dpll_loop_filter) & 0xffff)), rv); 4568 4569 /* Initial loop filter[63:48] */ 4570 SOC_IF_ERROR_BREAK 4571 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x42, (uint16)((COMPILER_64_HI(conf->phy_1588_dpll_loop_filter) >> 16) & 0xffff)), rv); 4572 } 4573 } while(0); 4574 4575 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 4576 4577 return SOC_E_NONE; 4578 } 4579 4580 STATIC int 4581 phy_54682_timesync_config_get(int unit, soc_port_t port, soc_port_phy_timesync_config_t *conf) 4582 { 4583 phy_ctrl_t *pc; 4584 int offset, rv = SOC_E_NONE; 4585 uint16 tx_control_reg = 0, rx_crc_control_reg = 0, 4586 en_control_reg = 0, tx_capture_en_reg = 0, 4587 nse_nco_6 = 0, nse_nco_2c = 0, temp1, temp2, temp3, temp4, value; 4588 soc_port_phy_timesync_global_mode_t gmode = SOC_PORT_PHY_TIMESYNC_MODE_FREE; 4589 soc_port_phy_timesync_framesync_mode_t framesync_mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_NONE; 4590 soc_port_phy_timesync_syncout_mode_t syncout_mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_DISABLE; 4591 4592 pc = EXT_PHY_SW_STATE(unit, port); 4593 4594 offset = PHY54682_DEV_PHY_SLICE(pc); 4595 4596 if ((!(PHY_IS_BCM54682E_OR_BCM54685E(pc) || PHY_IS_BCM54684E(pc))) || PHY_IS_BCM54682E_OR_BCM54685E_A0A1(pc)) { 4597 return SOC_E_UNAVAIL; 4598 } 4599 4600 conf->flags = 0; 4601 4602 do { 4603 /* pc->phy_id = PHY54682_SLICE_ADDR(pc, 0); */ 4604 pc->phy_id = PHY54682_DEV_PHY_ID_BASE(pc); 4605 4606 SOC_IF_ERROR_BREAK 4607 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4f, &nse_nco_6), rv); 4608 4609 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FLAGS) { 4610 SOC_IF_ERROR_BREAK 4611 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x10, &en_control_reg), rv); 4612 4613 if (en_control_reg & (1U << offset)) { 4614 conf->flags |= SOC_PORT_PHY_TIMESYNC_ENABLE; 4615 } 4616 4617 SOC_IF_ERROR_BREAK 4618 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x12, &tx_capture_en_reg), rv); 4619 4620 if (tx_capture_en_reg & (1U << offset)) { 4621 conf->flags |= SOC_PORT_PHY_TIMESYNC_CAPTURE_TS_ENABLE; 4622 } 4623 4624 /* 4625 SOC_IF_ERROR_BREAK 4626 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4f, &nse_nco_6), rv); 4627 */ 4628 4629 if (nse_nco_6 & (1U << 13)) { 4630 conf->flags |= SOC_PORT_PHY_TIMESYNC_HEARTBEAT_TS_ENABLE; 4631 } 4632 4633 SOC_IF_ERROR_BREAK 4634 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x34, &rx_crc_control_reg), rv); 4635 4636 if (rx_crc_control_reg & (1U << 3)) { 4637 conf->flags |= SOC_PORT_PHY_TIMESYNC_RX_CRC_ENABLE; 4638 } 4639 4640 SOC_IF_ERROR_BREAK 4641 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x32, &tx_control_reg), rv); 4642 4643 if (tx_control_reg & (1U << 3)) { 4644 conf->flags |= SOC_PORT_PHY_TIMESYNC_8021AS_ENABLE; 4645 } 4646 4647 if (tx_control_reg & (1U << 2)) { 4648 conf->flags |= SOC_PORT_PHY_TIMESYNC_L2_ENABLE; 4649 } 4650 4651 if (tx_control_reg & (1U << 1)) { 4652 conf->flags |= SOC_PORT_PHY_TIMESYNC_IP4_ENABLE; 4653 } 4654 4655 if (tx_control_reg & (1U << 0)) { 4656 conf->flags |= SOC_PORT_PHY_TIMESYNC_IP6_ENABLE; 4657 } 4658 4659 SOC_IF_ERROR_BREAK 4660 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x47, &nse_nco_2c), rv); 4661 4662 if (!(nse_nco_2c & (1U << 14))) { 4663 conf->flags |= SOC_PORT_PHY_TIMESYNC_CLOCK_SRC_EXT; 4664 } 4665 } 4666 4667 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_GMODE) { 4668 _phy_54682e_decode_gmode((nse_nco_6 >> 14),&gmode); 4669 conf->gmode = gmode; 4670 } 4671 4672 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FRAMESYNC_MODE) { 4673 _phy_54682e_decode_framesync_mode((nse_nco_6 >> 2), &framesync_mode); 4674 conf->framesync.mode = framesync_mode; 4675 4676 SOC_IF_ERROR_BREAK 4677 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x51, &temp1), rv); 4678 SOC_IF_ERROR_BREAK 4679 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x50, &temp2), rv); 4680 4681 /* Multiply by 8 */ 4682 conf->framesync.length_threshold = temp1 << 3; 4683 conf->framesync.event_offset = temp2 << 3; 4684 } 4685 4686 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_SYNCOUT_MODE) { 4687 _phy_54682e_decode_syncout_mode((nse_nco_6 >> 0), &syncout_mode); 4688 conf->syncout.mode = syncout_mode; 4689 4690 SOC_IF_ERROR_BREAK 4691 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x48, &temp1), rv); 4692 SOC_IF_ERROR_BREAK 4693 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x49, &temp2), rv); 4694 SOC_IF_ERROR_BREAK 4695 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4a, &temp3), rv); 4696 4697 /* Multiply by 8 */ 4698 conf->syncout.pulse_1_length = ((temp3 >> 7) & 0x1ff) << 3; 4699 conf->syncout.pulse_2_length = (((temp3 & 0x7f) << 2) | ((temp2 >> 14) & 0x3)) << 3; 4700 conf->syncout.interval = (((temp2 & 0x3fff) << 16) | temp1) << 3; 4701 4702 SOC_IF_ERROR_BREAK 4703 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4e, &temp1), rv); 4704 SOC_IF_ERROR_BREAK 4705 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4d, &temp2), rv); 4706 SOC_IF_ERROR_BREAK 4707 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4c, &temp3), rv); 4708 4709 COMPILER_64_SET(conf->syncout.syncout_ts, ((uint32)temp3), (((uint32)temp2<<16)|((uint32)temp1))); 4710 } 4711 4712 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ITPID) { 4713 SOC_IF_ERROR_BREAK 4714 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x35, &conf->itpid), rv); 4715 } 4716 4717 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID) { 4718 SOC_IF_ERROR_BREAK 4719 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x36, &conf->otpid), rv); 4720 } 4721 4722 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID2) { 4723 SOC_IF_ERROR_BREAK 4724 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x52, &conf->otpid2), rv); 4725 } 4726 4727 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TS_DIVIDER) { 4728 SOC_IF_ERROR_BREAK 4729 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4b, &conf->ts_divider), rv); 4730 } 4731 4732 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_LINK_DELAY) { 4733 offset = PHY54682_DEV_PHY_SLICE(pc); 4734 4735 SOC_IF_ERROR_BREAK 4736 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x6f, &temp1), rv); 4737 SOC_IF_ERROR_BREAK 4738 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x70, &temp2), rv); 4739 4740 conf->rx_link_delay = ((uint32)temp2 << 16) | temp1; 4741 4742 /* pc->phy_id = PHY54682_SLICE_ADDR(pc, 0); */ 4743 pc->phy_id = PHY54682_DEV_PHY_ID_BASE(pc); 4744 } 4745 4746 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ORIGINAL_TIMECODE) { 4747 SOC_IF_ERROR_BREAK 4748 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x25, &temp1), rv); 4749 4750 SOC_IF_ERROR_BREAK 4751 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x26, &temp2), rv); 4752 4753 conf->original_timecode.nanoseconds = ((uint32)temp2 << 16) | temp1; 4754 4755 SOC_IF_ERROR_BREAK 4756 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x27, &temp1), rv); 4757 4758 SOC_IF_ERROR_BREAK 4759 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x28, &temp2), rv); 4760 4761 SOC_IF_ERROR_BREAK 4762 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x29, &temp3), rv); 4763 4764 /* conf->original_timecode.seconds = ((uint64)temp3 << 32) | ((uint32)temp2 << 16) | temp1; */ 4765 4766 COMPILER_64_SET(conf->original_timecode.seconds, ((uint32)temp3), (((uint32)temp2<<16)|((uint32)temp1))); 4767 } 4768 4769 /* tx_timestamp_offset */ 4770 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_TIMESTAMP_OFFSET) { 4771 uint32 temp32; 4772 4773 SOC_IF_ERROR_BREAK 4774 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x15 + offset, &temp1), rv); 4775 if (offset < 4 ) { 4776 SOC_IF_ERROR_BREAK 4777 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x63, &temp2), rv); 4778 temp32 = (temp2 & (0xf << (offset << 2))) << ((4 - offset) << 2); 4779 } else { 4780 uint16 offset1 = offset - 4; 4781 SOC_IF_ERROR_BREAK 4782 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x64, &temp2), rv); 4783 temp32 = (temp2 & (0xf << (offset1 << 2))) << ((4 - offset1) << 2); 4784 } 4785 conf->tx_timestamp_offset = temp32 | temp1; 4786 } 4787 4788 /* rx_timestamp_offset */ 4789 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_TIMESTAMP_OFFSET) { 4790 uint32 temp32; 4791 4792 SOC_IF_ERROR_BREAK 4793 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x1d + offset, &temp1), rv); 4794 if (offset < 4 ) { 4795 SOC_IF_ERROR_BREAK 4796 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x65, &temp2), rv); 4797 temp32 = (temp2 & (0xf << (offset << 2))) << ((4 - offset) << 2); 4798 } else { 4799 uint16 offset1 = offset - 4; 4800 SOC_IF_ERROR_BREAK 4801 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x66, &temp2), rv); 4802 temp32 = (temp2 & (0xf << (offset1 << 2))) << ((4 - offset1) << 2); 4803 } 4804 conf->rx_timestamp_offset = temp32 | temp1; 4805 } 4806 4807 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 4808 4809 SOC_IF_ERROR_BREAK 4810 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x11, &value), rv); 4811 4812 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_SYNC_MODE) { 4813 _phy_54682e_decode_egress_message_mode(value, 0, &conf->tx_sync_mode); 4814 } 4815 4816 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_DELAY_REQUEST_MODE) { 4817 _phy_54682e_decode_egress_message_mode(value, 2, &conf->tx_delay_request_mode); 4818 } 4819 4820 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_REQUEST_MODE) { 4821 _phy_54682e_decode_egress_message_mode(value, 4, &conf->tx_pdelay_request_mode); 4822 } 4823 4824 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_RESPONSE_MODE) { 4825 _phy_54682e_decode_egress_message_mode(value, 6, &conf->tx_pdelay_response_mode); 4826 } 4827 4828 SOC_IF_ERROR_BREAK 4829 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x12, &value), rv); 4830 4831 value >>= 8; 4832 4833 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_SYNC_MODE) { 4834 _phy_54682e_decode_ingress_message_mode(value, 0, &conf->rx_sync_mode); 4835 } 4836 4837 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_DELAY_REQUEST_MODE) { 4838 _phy_54682e_decode_ingress_message_mode(value, 2, &conf->rx_delay_request_mode); 4839 } 4840 4841 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_REQUEST_MODE) { 4842 _phy_54682e_decode_ingress_message_mode(value, 4, &conf->rx_pdelay_request_mode); 4843 } 4844 4845 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_RESPONSE_MODE) { 4846 _phy_54682e_decode_ingress_message_mode(value, 6, &conf->rx_pdelay_response_mode); 4847 } 4848 4849 /* pc->phy_id = PHY54682_SLICE_ADDR(pc, 0); */ 4850 pc->phy_id = PHY54682_DEV_PHY_ID_BASE(pc); 4851 4852 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE) { 4853 /* Initial ref phase [15:0] */ 4854 SOC_IF_ERROR_BREAK 4855 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x38, &temp1), rv); 4856 4857 /* Initial ref phase [31:16] */ 4858 SOC_IF_ERROR_BREAK 4859 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x39, &temp2), rv); 4860 4861 /* Initial ref phase [47:32] */ 4862 SOC_IF_ERROR_BREAK 4863 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x3a, &temp3), rv); 4864 4865 COMPILER_64_SET(conf->phy_1588_dpll_ref_phase, ((uint32)temp3), (((uint32)temp2<<16)|((uint32)temp1))); 4866 } 4867 4868 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE_DELTA) { 4869 /* Ref phase delta [15:0] */ 4870 SOC_IF_ERROR_BREAK 4871 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x3b, &temp1), rv); 4872 4873 /* Ref phase delta [31:16] */ 4874 SOC_IF_ERROR_BREAK 4875 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x3c, &temp2), rv); 4876 4877 conf->phy_1588_dpll_ref_phase_delta = (temp2 << 16) | temp1; 4878 } 4879 4880 /* DPLL K1 & K2 */ 4881 SOC_IF_ERROR_BREAK 4882 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x3d, &temp1 ), rv); 4883 4884 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K1) { 4885 conf->phy_1588_dpll_k1 = (temp1 >> 8 ) & 0xff; 4886 } 4887 4888 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K2) { 4889 conf->phy_1588_dpll_k2 = temp1 & 0xff; 4890 } 4891 4892 /* DPLL K3 */ 4893 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K3) { 4894 SOC_IF_ERROR_BREAK 4895 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x3e, &temp1), rv); 4896 conf->phy_1588_dpll_k3 = temp1 & 0xff; 4897 } 4898 4899 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_LOOP_FILTER) { 4900 /* Initial loop filter[15:0] */ 4901 SOC_IF_ERROR_BREAK 4902 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x3f, &temp1), rv); 4903 4904 /* Initial loop filter[31:16] */ 4905 SOC_IF_ERROR_BREAK 4906 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x40, &temp2), rv); 4907 4908 /* Initial loop filter[47:32] */ 4909 SOC_IF_ERROR_BREAK 4910 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x41, &temp3), rv); 4911 4912 /* Initial loop filter[63:48] */ 4913 SOC_IF_ERROR_BREAK 4914 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x42, &temp4), rv); 4915 4916 COMPILER_64_SET(conf->phy_1588_dpll_loop_filter, (((uint32)temp4<<16)|((uint32)temp3)), (((uint32)temp2<<16)|((uint32)temp1))); 4917 } 4918 } while(0); 4919 4920 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 4921 4922 return SOC_E_NONE; 4923 } 4924 4925 STATIC int 4926 phy_54682_timesync_control_set(int unit, soc_port_t port, soc_port_control_phy_timesync_t type, uint64 value) 4927 { 4928 phy_ctrl_t *pc; 4929 uint16 temp1, temp2; 4930 uint32 value0; 4931 int offset, rv = SOC_E_NONE; 4932 4933 4934 pc = EXT_PHY_SW_STATE(unit, port); 4935 4936 offset = PHY54682_DEV_PHY_SLICE(pc); 4937 4938 if ((!(PHY_IS_BCM54682E_OR_BCM54685E(pc) || PHY_IS_BCM54684E(pc))) || PHY_IS_BCM54682E_OR_BCM54685E_A0A1(pc)) { 4939 return SOC_E_UNAVAIL; 4940 } 4941 4942 do { 4943 /* pc->phy_id = PHY54682_SLICE_ADDR(pc, 0); */ 4944 pc->phy_id = PHY54682_DEV_PHY_ID_BASE(pc); 4945 4946 switch (type) { 4947 case SOC_PORT_CONTROL_PHY_TIMESYNC_CAPTURE_TIMESTAMP: 4948 case SOC_PORT_CONTROL_PHY_TIMESYNC_HEARTBEAT_TIMESTAMP: 4949 return SOC_E_FAIL; 4950 4951 case SOC_PORT_CONTROL_PHY_TIMESYNC_NCOADDEND: 4952 SOC_IF_ERROR_BREAK 4953 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x44, (uint16)COMPILER_64_LO(value)), rv); 4954 break; 4955 4956 case SOC_PORT_CONTROL_PHY_TIMESYNC_FRAMESYNC: 4957 SOC_IF_ERROR_BREAK 4958 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4f, &temp1), rv); 4959 temp2 = ((temp1 | (0x3 << 14) | (0x1 << 12)) & ~(0xf << 2)) | (0x1 << 5); 4960 SOC_IF_ERROR_BREAK 4961 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4f, temp2), rv); 4962 sal_udelay(1); 4963 temp2 &= ~((0x1 << 5) | (0x1 << 12)); 4964 SOC_IF_ERROR_BREAK 4965 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4f, temp2), rv); 4966 sal_udelay(1); 4967 SOC_IF_ERROR_BREAK 4968 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4f, temp1), rv); 4969 4970 break; 4971 4972 case SOC_PORT_CONTROL_PHY_TIMESYNC_LOCAL_TIME: 4973 COMPILER_64_SHR(value, 4); 4974 SOC_IF_ERROR_BREAK 4975 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x45, (uint16)(COMPILER_64_LO(value) & 0xffff)), rv); 4976 SOC_IF_ERROR_BREAK 4977 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x46, (uint16)((COMPILER_64_LO(value) >> 16) & 0xffff)), rv); 4978 SOC_IF_ERROR_BREAK 4979 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x47, (uint16)(COMPILER_64_HI(value) & 0xfff), 0xfff), rv); 4980 break; 4981 4982 case SOC_PORT_CONTROL_PHY_TIMESYNC_LOAD_CONTROL: 4983 temp1 = 0; 4984 temp2 = 0; 4985 value0 = COMPILER_64_LO(value); 4986 if (value0 & SOC_PORT_PHY_TIMESYNC_TN_LOAD) { 4987 temp1 |= 1U << 11; 4988 } 4989 if (value0 & SOC_PORT_PHY_TIMESYNC_TN_ALWAYS_LOAD) { 4990 temp2 |= 1U << 11; 4991 } 4992 if (value0 & SOC_PORT_PHY_TIMESYNC_TIMECODE_LOAD) { 4993 temp1 |= 1U << 10; 4994 } 4995 if (value0 & SOC_PORT_PHY_TIMESYNC_TIMECODE_ALWAYS_LOAD) { 4996 temp2 |= 1U << 10; 4997 } 4998 if (value0 & SOC_PORT_PHY_TIMESYNC_SYNCOUT_LOAD) { 4999 temp1 |= 1U << 9; 5000 } 5001 if (value0 & SOC_PORT_PHY_TIMESYNC_SYNCOUT_ALWAYS_LOAD) { 5002 temp2 |= 1U << 9; 5003 } 5004 if (value0 & SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_LOAD) { 5005 temp1 |= 1U << 8; 5006 } 5007 if (value0 & SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_ALWAYS_LOAD) { 5008 temp2 |= 1U << 8; 5009 } 5010 if (value0 & SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_LOAD) { 5011 temp1 |= 1U << 7; 5012 } 5013 if (value0 & SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_ALWAYS_LOAD) { 5014 temp2 |= 1U << 7; 5015 } 5016 if (value0 & SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_LOAD) { 5017 temp1 |= 1U << 6; 5018 } 5019 if (value0 & SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_ALWAYS_LOAD) { 5020 temp2 |= 1U << 6; 5021 } 5022 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_LOAD) { 5023 temp1 |= 1U << 5; 5024 } 5025 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_ALWAYS_LOAD) { 5026 temp2 |= 1U << 5; 5027 } 5028 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_LOAD) { 5029 temp1 |= 1U << 4; 5030 } 5031 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_ALWAYS_LOAD) { 5032 temp2 |= 1U << 4; 5033 } 5034 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_LOAD) { 5035 temp1 |= 1U << 3; 5036 } 5037 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_ALWAYS_LOAD) { 5038 temp2 |= 1U << 3; 5039 } 5040 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_K3_LOAD) { 5041 temp1 |= 1U << 2; 5042 } 5043 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_K3_ALWAYS_LOAD) { 5044 temp2 |= 1U << 2; 5045 } 5046 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_K2_LOAD) { 5047 temp1 |= 1U << 1; 5048 } 5049 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_K2_ALWAYS_LOAD) { 5050 temp2 |= 1U << 1; 5051 } 5052 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_K1_LOAD) { 5053 temp1 |= 1U << 0; 5054 } 5055 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_K1_ALWAYS_LOAD) { 5056 temp2 |= 1U << 0; 5057 } 5058 SOC_IF_ERROR_BREAK 5059 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x2e, temp1), rv); 5060 SOC_IF_ERROR_BREAK 5061 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x2f, temp2), rv); 5062 break; 5063 5064 case SOC_PORT_CONTROL_PHY_TIMESYNC_INTERRUPT_MASK: 5065 temp1 = 0; 5066 value0 = COMPILER_64_LO(value); 5067 if (value0 & SOC_PORT_PHY_TIMESYNC_TIMESTAMP_INTERRUPT_MASK) { 5068 temp1 |= 1U << 1; 5069 } 5070 if (value0 & SOC_PORT_PHY_TIMESYNC_FRAMESYNC_INTERRUPT_MASK) { 5071 temp1 |= 1U << 0; 5072 } 5073 SOC_IF_ERROR_BREAK 5074 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x30, temp1), rv); 5075 break; 5076 5077 case SOC_PORT_CONTROL_PHY_TIMESYNC_TX_TIMESTAMP_OFFSET: 5078 value0 = COMPILER_64_LO(value); 5079 5080 /* tx_timestamp_offset */ 5081 SOC_IF_ERROR_BREAK 5082 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x15 + offset, (uint16)(value0 & 0xffff)), rv); 5083 5084 if (offset < 4 ) { 5085 SOC_IF_ERROR_BREAK 5086 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x63, 5087 ((value0 & 0xf0000) >> ((4 - offset) << 2)), 0xf << (offset << 2)), rv); 5088 } else { 5089 uint16 offset1 = offset - 4; 5090 SOC_IF_ERROR_BREAK 5091 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x64, 5092 ((value0 & 0xf0000) >> ((4 - offset1) << 2)), 0xf << (offset1 << 2)), rv); 5093 } 5094 break; 5095 5096 case SOC_PORT_CONTROL_PHY_TIMESYNC_RX_TIMESTAMP_OFFSET: 5097 value0 = COMPILER_64_LO(value); 5098 5099 /* rx_timestamp_offset */ 5100 SOC_IF_ERROR_BREAK 5101 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x1d + offset, (uint16)(value0 & 0xffff)), rv); 5102 5103 if (offset < 4 ) { 5104 SOC_IF_ERROR_BREAK 5105 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x65, 5106 ((value0 & 0xf0000) >> ((4 - offset) << 2)), 0xf << (offset << 2)), rv); 5107 } else { 5108 uint16 offset1 = offset - 4; 5109 SOC_IF_ERROR_BREAK 5110 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x66, 5111 ((value0 & 0xf0000) >> ((4 - offset1) << 2)), 0xf << (offset1 << 2)), rv); 5112 } 5113 break; 5114 5115 default: 5116 return SOC_E_FAIL; 5117 } 5118 } while(0); 5119 5120 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 5121 5122 return SOC_E_NONE; 5123 } 5124 5125 STATIC int 5126 phy_54682_timesync_control_get(int unit, soc_port_t port, soc_port_control_phy_timesync_t type, uint64 *value) 5127 { 5128 phy_ctrl_t *pc; 5129 uint16 value0; 5130 uint16 value1; 5131 uint16 value2; 5132 uint32 temp32; 5133 int offset, rv = SOC_E_NONE; 5134 5135 pc = EXT_PHY_SW_STATE(unit, port); 5136 5137 offset = PHY54682_DEV_PHY_SLICE(pc); 5138 5139 if ((!(PHY_IS_BCM54682E_OR_BCM54685E(pc) || PHY_IS_BCM54684E(pc))) || PHY_IS_BCM54682E_OR_BCM54685E_A0A1(pc)) { 5140 return SOC_E_UNAVAIL; 5141 } 5142 5143 do { 5144 /* pc->phy_id = PHY54682_SLICE_ADDR(pc, 0); */ 5145 pc->phy_id = PHY54682_DEV_PHY_ID_BASE(pc); 5146 5147 switch (type) { 5148 case SOC_PORT_CONTROL_PHY_TIMESYNC_HEARTBEAT_TIMESTAMP: 5149 SOC_IF_ERROR_BREAK 5150 (WRITE_PHY54682_EXP_READ_START_END_CTRLr(unit, pc, 0x1), rv); 5151 5152 SOC_IF_ERROR_BREAK 5153 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x56, &value0), rv); 5154 SOC_IF_ERROR_BREAK 5155 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x57, &value1), rv); 5156 SOC_IF_ERROR_BREAK 5157 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x58, &value2), rv); 5158 5159 SOC_IF_ERROR_BREAK 5160 (WRITE_PHY54682_EXP_READ_START_END_CTRLr(unit, pc, 0x2), rv); 5161 SOC_IF_ERROR_BREAK 5162 (WRITE_PHY54682_EXP_READ_START_END_CTRLr(unit, pc, 0x0), rv); 5163 5164 COMPILER_64_SET((*value), ((uint32)value2), (((uint32)value1<<16)|((uint32)value0))); 5165 5166 /* *value = (((uint64)value2) << 32) | (((uint64)value1) << 16) | ((uint64)value0); */ 5167 break; 5168 5169 case SOC_PORT_CONTROL_PHY_TIMESYNC_CAPTURE_TIMESTAMP: 5170 SOC_IF_ERROR_BREAK 5171 (WRITE_PHY54682_EXP_READ_START_END_CTRLr(unit, pc, 0x4), rv); 5172 5173 SOC_IF_ERROR_BREAK 5174 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x53, &value0), rv); 5175 SOC_IF_ERROR_BREAK 5176 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x54, &value1), rv); 5177 SOC_IF_ERROR_BREAK 5178 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x55, &value2), rv); 5179 5180 SOC_IF_ERROR_BREAK 5181 (WRITE_PHY54682_EXP_READ_START_END_CTRLr(unit, pc, 0x8), rv); 5182 SOC_IF_ERROR_BREAK 5183 (WRITE_PHY54682_EXP_READ_START_END_CTRLr(unit, pc, 0x0), rv); 5184 5185 COMPILER_64_SET((*value), ((uint32)value2), (((uint32)value1<<16)|((uint32)value0))); 5186 5187 /* *value = (((uint64)value2) << 32) | (((uint64)value1) << 16) | ((uint64)value0); */ 5188 break; 5189 5190 case SOC_PORT_CONTROL_PHY_TIMESYNC_NCOADDEND: 5191 SOC_IF_ERROR_BREAK 5192 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x44, &value0), rv); 5193 /* *value = value0; */ 5194 COMPILER_64_SET((*value), 0, (uint32)value0); 5195 break; 5196 5197 case SOC_PORT_CONTROL_PHY_TIMESYNC_LOCAL_TIME: 5198 SOC_IF_ERROR_BREAK 5199 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x45, &value0), rv); 5200 SOC_IF_ERROR_BREAK 5201 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x46, &value1), rv); 5202 SOC_IF_ERROR_BREAK 5203 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x47, &value2), rv); 5204 5205 COMPILER_64_SET((*value), (value2 & 0x0fff), ((uint32)value1 << 16) | value0 ); 5206 COMPILER_64_SHL((*value), 4); 5207 break; 5208 5209 case SOC_PORT_CONTROL_PHY_TIMESYNC_LOAD_CONTROL: 5210 SOC_IF_ERROR_BREAK 5211 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x2e, &value1), rv); 5212 SOC_IF_ERROR_BREAK 5213 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x2f, &value2), rv); 5214 value0 = 0; 5215 if (value1 & (1U << 11)) { 5216 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TN_LOAD; 5217 } 5218 if (value2 & (1U << 11)) { 5219 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TN_ALWAYS_LOAD; 5220 } 5221 if (value1 & (1U << 10)) { 5222 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TIMECODE_LOAD; 5223 } 5224 if (value2 & (1U << 10)) { 5225 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TIMECODE_ALWAYS_LOAD; 5226 } 5227 if (value1 & (1U << 9)) { 5228 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_SYNCOUT_LOAD; 5229 } 5230 if (value2 & (1U << 9)) { 5231 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_SYNCOUT_ALWAYS_LOAD; 5232 } 5233 if (value1 & (1U << 8)) { 5234 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_LOAD; 5235 } 5236 if (value1 & (1U << 8)) { 5237 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_ALWAYS_LOAD; 5238 } 5239 if (value1 & (1U << 7)) { 5240 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_LOAD; 5241 } 5242 if (value1 & (1U << 7)) { 5243 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_ALWAYS_LOAD; 5244 } 5245 if (value1 & (1U << 6)) { 5246 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_LOAD; 5247 } 5248 if (value2 & (1U << 6)) { 5249 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_ALWAYS_LOAD; 5250 } 5251 if (value1 & (1U << 5)) { 5252 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_LOAD; 5253 } 5254 if (value2 & (1U << 5)) { 5255 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_ALWAYS_LOAD; 5256 } 5257 if (value1 & (1U << 4)) { 5258 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_LOAD; 5259 } 5260 if (value2 & (1U << 4)) { 5261 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_ALWAYS_LOAD; 5262 } 5263 if (value1 & (1U << 3)) { 5264 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_LOAD; 5265 } 5266 if (value2 & (1U << 3)) { 5267 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_ALWAYS_LOAD; 5268 } 5269 if (value1 & (1U << 2)) { 5270 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K3_LOAD; 5271 } 5272 if (value2 & (1U << 2)) { 5273 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K3_ALWAYS_LOAD; 5274 } 5275 if (value1 & (1U << 1)) { 5276 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K2_LOAD; 5277 } 5278 if (value2 & (1U << 1)) { 5279 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K2_ALWAYS_LOAD; 5280 } 5281 if (value1 & (1U << 0)) { 5282 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K1_LOAD; 5283 } 5284 if (value2 & (1U << 0)) { 5285 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K1_ALWAYS_LOAD; 5286 } 5287 COMPILER_64_SET((*value), 0, (uint32)value0); 5288 break; 5289 5290 case SOC_PORT_CONTROL_PHY_TIMESYNC_INTERRUPT: 5291 SOC_IF_ERROR_BREAK 5292 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x31, &value1), rv); 5293 value0 = 0; 5294 if (value1 & (1U << 1)) { 5295 value0 |= SOC_PORT_PHY_TIMESYNC_TIMESTAMP_INTERRUPT; 5296 } 5297 if (value1 & (1U << 0)) { 5298 value0 |= SOC_PORT_PHY_TIMESYNC_FRAMESYNC_INTERRUPT; 5299 } 5300 COMPILER_64_SET((*value), 0, (uint32)value0); 5301 break; 5302 5303 case SOC_PORT_CONTROL_PHY_TIMESYNC_INTERRUPT_MASK: 5304 SOC_IF_ERROR_BREAK 5305 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x30, &value1), rv); 5306 value0 = 0; 5307 if (value1 & (1U << 1)) { 5308 value0 |= SOC_PORT_PHY_TIMESYNC_TIMESTAMP_INTERRUPT_MASK; 5309 } 5310 if (value1 & (1U << 0)) { 5311 value0 |= SOC_PORT_PHY_TIMESYNC_FRAMESYNC_INTERRUPT_MASK; 5312 } 5313 COMPILER_64_SET((*value), 0, (uint32)value0); 5314 break; 5315 5316 case SOC_PORT_CONTROL_PHY_TIMESYNC_TX_TIMESTAMP_OFFSET: 5317 /* tx_timestamp_offset */ 5318 SOC_IF_ERROR_BREAK 5319 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x15 + offset, &value1), rv); 5320 if (offset < 4 ) { 5321 SOC_IF_ERROR_BREAK 5322 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x63, &value2), rv); 5323 temp32 = (value2 & (0xf << (offset << 2))) << ((4 - offset) << 2); 5324 } else { 5325 uint16 offset1 = offset - 4; 5326 SOC_IF_ERROR_BREAK 5327 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x64, &value2), rv); 5328 temp32 = (value2 & (0xf << (offset1 << 2))) << ((4 - offset1) << 2); 5329 } 5330 /* *value = temp32 | value1; */ 5331 COMPILER_64_SET((*value), 0, (uint32)(temp32 | value1)); 5332 break; 5333 5334 case SOC_PORT_CONTROL_PHY_TIMESYNC_RX_TIMESTAMP_OFFSET: 5335 /* rx_timestamp_offset */ 5336 SOC_IF_ERROR_BREAK 5337 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x1d + offset, &value1), rv); 5338 if (offset < 4 ) { 5339 SOC_IF_ERROR_BREAK 5340 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x65, &value2), rv); 5341 temp32 = (value2 & (0xf << (offset << 2))) << ((4 - offset) << 2); 5342 } else { 5343 uint16 offset1 = offset - 4; 5344 SOC_IF_ERROR_BREAK 5345 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x66, &value2), rv); 5346 temp32 = (value2 & (0xf << (offset1 << 2))) << ((4 - offset1) << 2); 5347 } 5348 /* *value = temp32 | value1; */ 5349 COMPILER_64_SET((*value), 0, (uint32)(temp32 | value1)); 5350 break; 5351 5352 default: 5353 return SOC_E_FAIL; 5354 } 5355 } while(0); 5356 5357 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 5358 5359 return SOC_E_NONE; 5360 } 5361 5362 #ifdef BROADCOM_DEBUG 5363 5364 /* 5365 * Function: 5366 * phy_54682_shadow_dump 5367 * Purpose: 5368 * Debug routine to dump all shadow registers. 5369 * Parameters: 5370 * unit - StrataSwitch unit #. 5371 * port - StrataSwitch port #. 5372 */ 5373 5374 void 5375 phy_54682_shadow_dump(int unit, soc_port_t port) 5376 { 5377 phy_ctrl_t *pc; 5378 uint16 tmp; 5379 int i; 5380 5381 pc = EXT_PHY_SW_STATE(unit, port); 5382 5383 /* Register 0x18 Shadows */ 5384 for (i = 0; i <= 7; i++) { 5385 WRITE_PHY_REG(unit, pc, 0x18, (i << 12) | 0x7); 5386 READ_PHY_REG(unit, pc, 0x18, &tmp); 5387 if ((tmp & ~7) == 0x0000) { 5388 continue; 5389 } 5390 LOG_CLI((BSL_META_U(unit, "0x18[0x%x]=0x%04x\n"), i, tmp)); 5391 } 5392 5393 /* Register 0x1c Shadows */ 5394 for (i = 0; i <= 0x1f; i++) { 5395 WRITE_PHY_REG(unit, pc, 0x1c, i << 10); 5396 READ_PHY_REG(unit, pc, 0x1c, &tmp); 5397 if ((tmp & ~0x7c00) == 0x0000) { 5398 continue; 5399 } 5400 LOG_CLI((BSL_META_U(unit, "0x1c[0x%x]=0x%04x\n"), i, tmp)); 5401 } 5402 5403 /* Register 0x17/0x15 Shadows */ 5404 for (i = 0; i <= 0x13; i++) { 5405 WRITE_PHY_REG(unit, pc, 0x17, 0xf00 | i); 5406 READ_PHY_REG(unit, pc, 0x15, &tmp); 5407 if (tmp == 0x0000) { 5408 continue; 5409 } 5410 LOG_CLI((BSL_META_U(unit,"0x17[0x%x]=0x%04x\n"), i, tmp)); 5411 } 5412 } 5413 5414 #endif /* BROADCOM_DEBUG */ 5415 5416 STATIC int 5417 _phy_54682_tx_control_set(int unit, soc_port_t port, 5418 soc_phy_control_t type, uint32 value) 5419 { 5420 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 5421 uint16 data; 5422 int qsgmii_port; 5423 uint32 qsgmii_aer_reg; 5424 5425 /* Support only system side - for now */ 5426 if(!(pc->flags & PHYCTRL_SYS_SIDE_CTRL)) { 5427 return SOC_E_UNAVAIL; 5428 } 5429 5430 qsgmii_port = ((PHY54682_DEV_PHY_SLICE(pc)) < 4) ? 0 : 1; 5431 qsgmii_aer_reg = (_phy_54682_qsgmii_aer[qsgmii_port] << 16) | 0x8067; 5432 data = (uint16) (value & 0xf); 5433 5434 switch( type ) { 5435 case SOC_PHY_CONTROL_PREEMPHASIS: 5436 pc->phy_id = PHY_BCM54682_QSGMII_DEV_ADDR(pc); 5437 data <<= 12; 5438 SOC_IF_ERROR_RETURN 5439 (phy_reg_aer_modify(unit, pc, qsgmii_aer_reg, data, 0xf000)); 5440 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 5441 break; 5442 5443 case SOC_PHY_CONTROL_DRIVER_CURRENT: 5444 pc->phy_id = PHY_BCM54682_QSGMII_DEV_ADDR(pc); 5445 data <<= 8; 5446 SOC_IF_ERROR_RETURN 5447 (phy_reg_aer_modify(unit, pc, qsgmii_aer_reg, data, 0x0f00)); 5448 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 5449 break; 5450 5451 default: 5452 return SOC_E_PARAM; 5453 } 5454 5455 return SOC_E_NONE; 5456 } 5457 5458 STATIC int 5459 _phy_54682_tx_control_get(int unit, soc_port_t port, 5460 soc_phy_control_t type, uint32 *value) 5461 { 5462 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 5463 uint16 data; 5464 int qsgmii_port; 5465 uint32 qsgmii_aer_reg; 5466 5467 /* Support only system side - for now */ 5468 if(!(pc->flags & PHYCTRL_SYS_SIDE_CTRL)) { 5469 return SOC_E_UNAVAIL; 5470 } 5471 5472 qsgmii_port = ((PHY54682_DEV_PHY_SLICE(pc)) < 4) ? 0 : 1; 5473 qsgmii_aer_reg = (_phy_54682_qsgmii_aer[qsgmii_port] << 16) | 0x8067; 5474 5475 data = 0; 5476 5477 switch(type) { 5478 case SOC_PHY_CONTROL_PREEMPHASIS: 5479 pc->phy_id = PHY_BCM54682_QSGMII_DEV_ADDR(pc); 5480 SOC_IF_ERROR_RETURN 5481 (phy_reg_aer_read(unit, pc, qsgmii_aer_reg, &data)); 5482 *value = (data & 0xf000) >> 12; 5483 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 5484 break; 5485 case SOC_PHY_CONTROL_DRIVER_CURRENT: 5486 pc->phy_id = PHY_BCM54682_QSGMII_DEV_ADDR(pc); 5487 SOC_IF_ERROR_RETURN 5488 (phy_reg_aer_read(unit, pc, qsgmii_aer_reg, &data)); 5489 *value = (data & 0x0f00) >> 8; 5490 pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc); 5491 break; 5492 default: 5493 return SOC_E_PARAM; 5494 } 5495 5496 return SOC_E_NONE; 5497 } 5498 5499 /* 5500 * Variable: phy_54682drv_ge 5501 * Purpose: PHY driver for 54682 5502 */ 5503 5504 phy_driver_t phy_54682drv_ge = { 5505 "54682 Gigabit PHY Driver", 5506 phy_54682_init, 5507 phy_fe_ge_reset, 5508 phy_54682_link_get, 5509 phy_54682_enable_set, 5510 phy_54682_enable_get, 5511 phy_54682_duplex_set, 5512 phy_54682_duplex_get, 5513 phy_54682_speed_set, 5514 phy_54682_speed_get, 5515 phy_54682_master_set, 5516 phy_54682_master_get, 5517 phy_54682_autoneg_set, 5518 phy_54682_autoneg_get, 5519 NULL, 5520 NULL, 5521 NULL, 5522 phy_54682_lb_set, 5523 phy_54682_lb_get, 5524 phy_54682_interface_set, 5525 phy_54682_interface_get, 5526 NULL, 5527 phy_54682_link_up, /* Phy link up event */ 5528 phy_54682_link_down, /* Phy link down event */ 5529 phy_54682_mdix_set, 5530 phy_54682_mdix_get, 5531 phy_54682_mdix_status_get, 5532 phy_54682_medium_config_set, 5533 phy_54682_medium_config_get, 5534 phy_54682_medium_status, 5535 phy54682_cable_diag_dispatch, 5536 NULL, /* phy_link_change */ 5537 phy_54682_control_set, /* phy_control_set */ 5538 phy_54682_control_get, /* phy_control_get */ 5539 phy_ge_reg_read, 5540 phy_ge_reg_write, 5541 phy_ge_reg_modify, 5542 NULL, /* Phy event notify */ 5543 phy_54682_probe, /* pd_probe */ 5544 phy_54682_ability_advert_set, 5545 phy_54682_ability_advert_get, 5546 phy_54682_ability_remote_get, 5547 phy_54682_ability_local_get, 5548 NULL, /* f/w set */ 5549 phy_54682_timesync_config_set, 5550 phy_54682_timesync_config_get, 5551 phy_54682_timesync_control_set, 5552 phy_54682_timesync_control_get 5553 5554 }; 5555 #else /* INCLUDE_PHY_54682 */ 5556 int _soc_phy_54682_not_empty; 5557 #endif /* INCLUDE_PHY_54682 */ 5558