phy54616.c (147807B)
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: phy54616.c 8 * Purpose: PHY driver for BCM54616 and BCM54616S 9 */ 10 11 #include <sal/types.h> 12 #include <sal/core/spl.h> 13 #include <shared/bsl.h> 14 #include <soc/drv.h> 15 #include <soc/debug.h> 16 #include <soc/error.h> 17 #include <soc/phyreg.h> 18 19 #include <soc/phy.h> 20 #include <soc/phy/phyctrl.h> 21 #include <soc/phy/drv.h> 22 23 #include "phydefs.h" /* Must include before other phy related includes */ 24 25 #if defined(INCLUDE_PHY_54616) || defined(INCLUDE_PHY_54618SE) || defined(INCLUDE_PHY_54618E) 26 #include "phyconfig.h" /* Must be the first phy include after phydefs.h */ 27 #include "phyident.h" 28 #include "phyreg.h" 29 #include "phyfege.h" 30 #include "phy54616.h" 31 32 #define AUTO_MDIX_WHEN_AN_DIS 0 /* Non-standard-compliant option */ 33 #define DISABLE_CLK125 0 /* Disable if unused to reduce */ 34 /* EMI emissions */ 35 36 #define PHY_IS_BCM54616S(_pc) PHY_FLAGS_TST((_pc)->unit, (_pc)->port, \ 37 PHY_FLAGS_SECONDARY_SERDES) 38 #define PHY_IS_BCM54618E(_pc) PHY_MODEL_CHECK((_pc), \ 39 PHY_BCM54618E_OUI, \ 40 PHY_BCM54618E_MODEL) 41 #define PHY_IS_BCM54618SE(_pc) PHY_MODEL_CHECK((_pc), \ 42 PHY_BCM54618SE_OUI, \ 43 PHY_BCM54618SE_MODEL) 44 #define PHY_IS_BCM54618SE_OR_BCM54618E(_pc) \ 45 (PHY_IS_BCM54618SE((_pc)) || PHY_IS_BCM54618E((_pc))) 46 47 #define SOC_IF_ERROR_BREAK(op, __rv__) \ 48 if ( ((__rv__) = (op)) < 0 ) { \ 49 break; \ 50 } 51 52 STATIC int _phy_54616_no_reset_setup(int unit, soc_port_t port); 53 STATIC int _phy_54616_medium_change(int unit, soc_port_t port,int force_update); 54 STATIC int _phy_54616_copper_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability); 55 STATIC int _phy_54616_fiber_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability); 56 STATIC int _phy_54616_fiber_ability_advert_set(int unit, soc_port_t port,soc_port_ability_t *ability); 57 STATIC int phy_54616_duplex_set(int unit, soc_port_t port, int duplex); 58 STATIC int phy_54616_speed_set(int unit, soc_port_t port, int speed); 59 STATIC int phy_54616_master_set(int unit, soc_port_t port, int master); 60 STATIC int phy_54616_autoneg_set(int unit, soc_port_t port, int autoneg); 61 STATIC int phy_54616_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode); 62 STATIC int phy_54616_speed_get(int unit, soc_port_t port, int *speed); 63 STATIC int phy_54616_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability); 64 65 /* 66 * Function: 67 * _phy_54618e_cl45_reg_read 68 * Purpose: 69 * Read Clause 45 Register using Clause 22 register access 70 * Parameters: 71 * unit - StrataSwitch unit #. 72 * pc - Phy control 73 * flags - Flags 74 * dev_addr - Clause 45 Device 75 * reg_addr - Register Address to read 76 * val - Value Read 77 * Returns: 78 * SOC_E_XXX 79 */ 80 81 STATIC int 82 _phy_54618e_cl45_reg_read(int unit, phy_ctrl_t *pc, uint32 flags, 83 uint8 dev_addr, uint16 reg_addr, uint16 *val) 84 { 85 /* Write Device Address to register 0x0D (Set Function field to Address)*/ 86 SOC_IF_ERROR_RETURN 87 (PHY54616_REG_WRITE(unit, pc, flags, 0x00, 0x0D, (dev_addr & 0x001f))); 88 89 /* Select the register by writing to register address to register 0x0E */ 90 SOC_IF_ERROR_RETURN 91 (PHY54616_REG_WRITE(unit, pc, flags, 0x00, 0x0E, reg_addr)); 92 93 /* Write Device Address to register 0x0D (Set Function field to Data)*/ 94 SOC_IF_ERROR_RETURN 95 (PHY54616_REG_WRITE(unit, pc, flags, 0x00, 0x0D, 96 ((0x4000) | (dev_addr & 0x001f)))); 97 98 /* Read register 0x0E to get the value */ 99 SOC_IF_ERROR_RETURN 100 (PHY54616_REG_READ(unit, pc, flags, 0x00, 0x0E, val)); 101 102 return SOC_E_NONE; 103 } 104 105 /* 106 * Function: 107 * _phy_54618e_cl45_reg_write 108 * Purpose: 109 * Write Clause 45 Register content using Clause 22 register access 110 * Parameters: 111 * unit - StrataSwitch unit #. 112 * pc - Phy control 113 * flags - Flags 114 * dev_addr - Clause 45 Device 115 * reg_addr - Register Address to read 116 * val - Value to be written 117 * Returns: 118 * SOC_E_XXX 119 */ 120 121 STATIC int 122 _phy_54618e_cl45_reg_write(int unit, phy_ctrl_t *pc, uint32 flags, 123 uint8 dev_addr, uint16 reg_addr, uint16 val) 124 { 125 /* Write Device Address to register 0x0D (Set Function field to Address)*/ 126 SOC_IF_ERROR_RETURN 127 (PHY54616_REG_WRITE(unit, pc, flags, 0x00, 0x0D, (dev_addr & 0x001f))); 128 129 /* Select the register by writing to register address to register 0x0E */ 130 SOC_IF_ERROR_RETURN 131 (PHY54616_REG_WRITE(unit, pc, flags, 0x00, 0x0E, reg_addr)); 132 133 /* Write Device Address to register 0x0D (Set Function field to Data)*/ 134 SOC_IF_ERROR_RETURN 135 (PHY54616_REG_WRITE(unit, pc, flags, 0x00, 0x0D, 136 ((0x4000) | (dev_addr & 0x001f)))); 137 138 /* Write register 0x0E to write the value */ 139 SOC_IF_ERROR_RETURN 140 (PHY54616_REG_WRITE(unit, pc, flags, 0x00, 0x0E, val)); 141 142 return SOC_E_NONE; 143 } 144 145 /* 146 * Function: 147 * _phy_54618e_cl45_reg_modify 148 * Purpose: 149 * Modify Clause 45 Register contents using Clause 22 register access 150 * Parameters: 151 * unit - StrataSwitch unit #. 152 * pc - Phy control 153 * flags - Flags 154 * reg_bank - Register bank 155 * dev_addr - Clause 45 Device 156 * reg_addr - Register Address to read 157 * val - Value 158 * mask - Mask for modifying the contents of the register 159 * Returns: 160 * SOC_E_XXX 161 */ 162 163 STATIC int 164 _phy_54618e_cl45_reg_modify(int unit, phy_ctrl_t *pc, uint32 flags, 165 uint8 dev_addr, uint16 reg_addr, uint16 val, 166 uint16 mask) 167 { 168 uint16 value = 0; 169 170 SOC_IF_ERROR_RETURN 171 (PHY54618E_CL45_REG_READ(unit, pc, flags, dev_addr, reg_addr, &value)); 172 173 value = (val & mask) | (value & ~mask); 174 175 SOC_IF_ERROR_RETURN 176 (PHY54618E_CL45_REG_WRITE(unit, pc, flags, dev_addr, reg_addr, value)); 177 178 return SOC_E_NONE; 179 } 180 181 /*********************************************************************** 182 * 183 * HELPER FUNCTIONS 184 */ 185 /* 186 * Function: 187 * _phy_54616_medium_check 188 * Purpose: 189 * Determine if chip should operate in copper or fiber mode. 190 * Parameters: 191 * unit - StrataSwitch unit #. 192 * port - StrataSwitch port #. 193 * medium - (OUT) SOC_PORT_MEDIUM_XXX 194 * Returns: 195 * SOC_E_XXX 196 */ 197 STATIC int 198 _phy_54616_medium_check(int unit, soc_port_t port, int *medium) 199 { 200 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 201 uint16 tmp = 0xffff; 202 203 *medium = SOC_PORT_MEDIUM_COPPER; 204 205 if (PHY_PRIMARY_SERDES_MODE(unit, port)) { 206 /* Ie fiber capable */ 207 208 if (pc->automedium) { 209 /* Read Mode Register (0x1c shadow 11111) */ 210 SOC_IF_ERROR_RETURN 211 (READ_PHY54616_MODE_CTRLr(unit, pc, &tmp)); 212 213 if (pc->fiber.preferred) { 214 /* 0x10 Fiber Signal Detect 215 * 0x20 Copper Energy Detect 216 */ 217 if ((tmp & 0x30) == 0x20) { 218 /* Only copper is link up */ 219 *medium = SOC_PORT_MEDIUM_COPPER; 220 } else { 221 *medium = SOC_PORT_MEDIUM_FIBER; 222 } 223 } else { 224 if ((tmp & 0x30) == 0x10) { 225 /* Only fiber is link up */ 226 *medium = SOC_PORT_MEDIUM_FIBER; 227 } else { 228 *medium = SOC_PORT_MEDIUM_COPPER; 229 } 230 } 231 } else { 232 *medium = pc->fiber.preferred ? SOC_PORT_MEDIUM_FIBER: 233 SOC_PORT_MEDIUM_COPPER; 234 } 235 } 236 237 LOG_VERBOSE(BSL_LS_SOC_PHY, 238 (BSL_META_U(unit, 239 "_phy_54616_medium_check: " 240 "u=%d p=%d fiber_pref=%d 0x1c(11111)=%04x fiber=%d\n"), 241 unit, port, pc->fiber.preferred, tmp, 242 (*medium == SOC_PORT_MEDIUM_FIBER) ? 1 : 0)); 243 244 return SOC_E_NONE; 245 } 246 247 /* 248 * Function: 249 * phy_54616_medium_status 250 * Purpose: 251 * Indicate the current active medium 252 * Parameters: 253 * unit - StrataSwitch unit #. 254 * port - StrataSwitch port #. 255 * medium - (OUT) One of: 256 * SOC_PORT_MEDIUM_COPPER 257 * SOC_PORT_MEDIUM_FIBER 258 * Returns: 259 * SOC_E_NONE 260 */ 261 262 STATIC int 263 phy_54616_medium_status(int unit, soc_port_t port, soc_port_medium_t *medium) 264 { 265 if (PHY_COPPER_MODE(unit, port)) { 266 *medium = SOC_PORT_MEDIUM_COPPER; 267 } else { 268 *medium = SOC_PORT_MEDIUM_FIBER; 269 } 270 return SOC_E_NONE; 271 } 272 273 /* 274 * Function: 275 * _phy_54616_medium_config_update 276 * Purpose: 277 * Update the PHY with config parameters 278 * Parameters: 279 * unit - StrataSwitch unit #. 280 * port - StrataSwitch port #. 281 * cfg - Config structure. 282 * Returns: 283 * SOC_E_XXX 284 */ 285 286 STATIC int 287 _phy_54616_medium_config_update(int unit, soc_port_t port, 288 soc_phy_config_t *cfg) 289 { 290 SOC_IF_ERROR_RETURN 291 (phy_54616_speed_set(unit, port, cfg->force_speed)); 292 SOC_IF_ERROR_RETURN 293 (phy_54616_duplex_set(unit, port, cfg->force_duplex)); 294 SOC_IF_ERROR_RETURN 295 (phy_54616_master_set(unit, port, cfg->master)); 296 SOC_IF_ERROR_RETURN 297 (phy_54616_ability_advert_set(unit, port, &cfg->advert_ability)); 298 SOC_IF_ERROR_RETURN 299 (phy_54616_autoneg_set(unit, port, cfg->autoneg_enable)); 300 SOC_IF_ERROR_RETURN 301 (phy_54616_mdix_set(unit, port, cfg->mdix)); 302 303 return SOC_E_NONE; 304 } 305 306 /*********************************************************************** 307 * 308 * PHY54616 DRIVER ROUTINES 309 */ 310 311 /* 312 * Function: 313 * phy_54616_medium_config_set 314 * Purpose: 315 * Set the operating parameters that are automatically selected 316 * when medium switches type. 317 * Parameters: 318 * unit - StrataSwitch unit # 319 * port - Port number 320 * medium - SOC_PORT_MEDIUM_COPPER/FIBER 321 * cfg - Operating parameters 322 * Returns: 323 * SOC_E_XXX 324 */ 325 326 STATIC int 327 phy_54616_medium_config_set(int unit, soc_port_t port, 328 soc_port_medium_t medium, 329 soc_phy_config_t *cfg) 330 { 331 phy_ctrl_t *pc; 332 soc_phy_config_t *active_medium; /* Currently active medium */ 333 soc_phy_config_t *change_medium; /* Requested medium */ 334 soc_phy_config_t *other_medium; /* The other medium */ 335 int medium_update; 336 337 if (NULL == cfg) { 338 return SOC_E_PARAM; 339 } 340 341 pc = EXT_PHY_SW_STATE(unit, port); 342 medium_update = FALSE; 343 344 switch (medium) { 345 case SOC_PORT_MEDIUM_COPPER: 346 if (!pc->automedium) { 347 if (!PHY_COPPER_MODE(unit, port)) { 348 return SOC_E_UNAVAIL; 349 } 350 /* check if device is fiber capable before switching */ 351 if (cfg->preferred == 0) { 352 353 if (!PHY_IS_BCM54616S(pc)) { 354 /* return if not fiber capable*/ 355 return SOC_E_UNAVAIL; 356 } 357 } 358 } 359 360 change_medium = &pc->copper; 361 other_medium = &pc->fiber; 362 break; 363 case SOC_PORT_MEDIUM_FIBER: 364 if (!pc->automedium && !PHY_FIBER_MODE(unit, port)) { 365 return SOC_E_UNAVAIL; 366 } 367 change_medium = &pc->fiber; 368 other_medium = &pc->copper; 369 break; 370 default: 371 return SOC_E_PARAM; 372 } 373 374 /* 375 * Changes take effect immediately if the target medium is active or 376 * the preferred medium changes. 377 */ 378 if (change_medium->enable != cfg->enable) { 379 medium_update = TRUE; 380 } 381 if (change_medium->preferred != cfg->preferred) { 382 /* Make sure that only one medium is preferred */ 383 other_medium->preferred = !cfg->preferred; 384 medium_update = TRUE; 385 } 386 387 sal_memcpy(change_medium, cfg, sizeof(*change_medium)); 388 389 if (medium_update) { 390 /* The new configuration may cause medium change. Check 391 * and update medium. 392 */ 393 SOC_IF_ERROR_RETURN 394 (_phy_54616_medium_change(unit, port,TRUE)); 395 } else { 396 active_medium = (PHY_COPPER_MODE(unit, port)) ? 397 &pc->copper : &pc->fiber; 398 if (active_medium == change_medium) { 399 /* If the medium to update is active, update the configuration */ 400 SOC_IF_ERROR_RETURN 401 (_phy_54616_medium_config_update(unit, port, change_medium)); 402 } 403 } 404 return SOC_E_NONE; 405 } 406 407 /* 408 * Function: 409 * phy_54616_medium_config_get 410 * Purpose: 411 * Get the operating parameters that are automatically selected 412 * when medium switches type. 413 * Parameters: 414 * unit - StrataSwitch unit # 415 * port - Port number 416 * medium - SOC_PORT_MEDIUM_COPPER/FIBER 417 * cfg - (OUT) Operating parameters 418 * Returns: 419 * SOC_E_XXX 420 */ 421 422 STATIC int 423 phy_54616_medium_config_get(int unit, soc_port_t port, 424 soc_port_medium_t medium, 425 soc_phy_config_t *cfg) 426 { 427 int rv; 428 phy_ctrl_t *pc; 429 430 pc = EXT_PHY_SW_STATE(unit, port); 431 rv = SOC_E_NONE; 432 433 switch (medium) { 434 case SOC_PORT_MEDIUM_COPPER: 435 if (pc->automedium || PHY_COPPER_MODE(unit, port)) { 436 sal_memcpy(cfg, &pc->copper, sizeof (*cfg)); 437 } else { 438 rv = SOC_E_UNAVAIL; 439 } 440 break; 441 case SOC_PORT_MEDIUM_FIBER: 442 if (pc->automedium || PHY_FIBER_MODE(unit, port)) { 443 sal_memcpy(cfg, &pc->fiber, sizeof (*cfg)); 444 } else { 445 rv = SOC_E_UNAVAIL; 446 } 447 break; 448 default: 449 rv = SOC_E_PARAM; 450 break; 451 } 452 453 return rv; 454 } 455 456 /* 457 * Function: 458 * _phy_54616_reset_setup 459 * Purpose: 460 * Function to reset the PHY and set up initial operating registers. 461 * Parameters: 462 * unit - StrataSwitch unit #. 463 * port - StrataSwitch port #. 464 * Returns: 465 * SOC_E_XXX 466 * Notes: 467 * Configures for copper/fiber according to the current 468 * setting of PHY_FLAGS_FIBER. 469 */ 470 471 STATIC int 472 _phy_54616_reset_setup(int unit, soc_port_t port) 473 { 474 phy_ctrl_t *pc; 475 476 pc = EXT_PHY_SW_STATE(unit, port); 477 478 /* Reset the PHY with previously registered callback function. */ 479 SOC_IF_ERROR_RETURN(soc_phy_reset(unit, port)); 480 481 sal_usleep(10000); 482 483 /* Disable super-isolate */ 484 SOC_IF_ERROR_RETURN 485 (MODIFY_PHY54616_MII_POWER_CTRLr(unit, pc, 0x0, 1U<<5)); 486 487 /* BCM54618E/SE is EEE capable */ 488 if ( PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) { 489 /* disable AutogrEEEn (default EEE Native node) */ 490 SOC_IF_ERROR_RETURN 491 (MODIFY_PHY54618_EEE_AUTOEEECTRLr(unit, pc, 0x0000, 0x0001)); 492 493 PHY_FLAGS_SET(unit, port, PHY_FLAGS_EEE_CAPABLE); 494 } 495 496 SOC_IF_ERROR_RETURN 497 (_phy_54616_no_reset_setup(unit, port)); 498 499 return SOC_E_NONE; 500 } 501 502 STATIC int 503 _phy_54616_no_reset_setup(int unit, soc_port_t port) 504 { 505 phy_ctrl_t *int_pc; 506 phy_ctrl_t *pc; 507 uint16 data, mask; 508 509 LOG_INFO(BSL_LS_SOC_PHY, 510 (BSL_META_U(unit, 511 "_phy_54616_reset_setup: u=%d p=%d medium=%s\n"), 512 unit, port, 513 PHY_COPPER_MODE(unit, port) ? "COPPER" : "FIBER")); 514 515 pc = EXT_PHY_SW_STATE(unit, port); 516 int_pc = INT_PHY_SW_STATE(unit, port); 517 518 519 /* copper regs */ 520 if (!pc->copper.enable || (!pc->automedium && pc->fiber.preferred)) { 521 /* Copper interface is not used. Powered down. */ 522 LOG_INFO(BSL_LS_SOC_PHY, 523 (BSL_META_U(unit, 524 "%s: u=%d p=%d Copper PowerDown=%d!\n"), 525 FUNCTION_NAME(), unit, port, 1)); 526 SOC_IF_ERROR_RETURN 527 (MODIFY_PHY54616_MII_CTRLr(unit, pc, MII_CTRL_PD, MII_CTRL_PD)); 528 } else { 529 LOG_INFO(BSL_LS_SOC_PHY, 530 (BSL_META_U(unit, 531 "%s: u=%d p=%d Copper PowerDown=%d!\n"), 532 FUNCTION_NAME(), unit, port, 0)); 533 SOC_IF_ERROR_RETURN 534 (MODIFY_PHY54616_MII_CTRLr(unit, pc, 0, MII_CTRL_PD)); 535 SOC_IF_ERROR_RETURN 536 (WRITE_PHY54616_MII_GB_CTRLr(unit, pc, 537 MII_GB_CTRL_ADV_1000FD | MII_GB_CTRL_PT)); 538 SOC_IF_ERROR_RETURN 539 (WRITE_PHY54616_MII_CTRLr(unit, pc, 540 MII_CTRL_FD | MII_CTRL_SS_1000 | MII_CTRL_AE)); 541 } 542 543 if (NULL != int_pc) { 544 SOC_IF_ERROR_RETURN 545 (PHY_INIT(int_pc->pd, unit, port)); 546 } 547 548 /* Configure Auto-detect Medium (0x1c shadow 11110) */ 549 mask = 0x33f; /* Auto-detect bit mask */ 550 551 /* In BCM54616S the SD pin is internally tied. For proper operation 552 SD_INV and QUALIFY_SD_WITH_SYNC should be set. */ 553 data = (1 << 8) | (1 << 5); 554 555 if (pc->automedium) { 556 data |= 1 << 0; /* Enable auto-detect medium */ 557 } 558 /* When no link partner exists, fiber should be default medium */ 559 /* When both link partners exipc, fiber should be prefered medium 560 * for the following reasons. 561 * 1. Most fiber module generates signal detect when the fiber cable is 562 * plugged in regardless of any activity even if the link partner is 563 * powered down. 564 * 2. Fiber mode consume much lesser power than copper mode. 565 */ 566 if (pc->fiber.preferred) { 567 data |= 1 << 1; /* Fiber selected when both media are active */ 568 data |= 1 << 2; /* Fiber selected when no medium is active */ 569 } 570 571 SOC_IF_ERROR_RETURN 572 (MODIFY_PHY54616_AUTO_DETECT_MEDIUMr(unit, pc, data, mask)); 573 574 #if DISABLE_CLK125 575 /* Reduce EMI emissions by disabling the CLK125 pin if not used */ 576 data = 0x001c; /* When write, bit 9 and 7 must be zero and */ 577 data = 0x029c; /* bit 2, 3, and 4 must be one. */ 578 SOC_IF_ERROR_RETURN 579 (MODIFY_PHY54616_SPARE_CTRL_3r(unit, pc, 0, 1)); 580 #endif 581 582 #if AUTO_MDIX_WHEN_AN_DIS 583 /* Enable Auto-MDIX When autoneg disabled */ 584 SOC_IF_ERROR_RETURN 585 (MODIFY_PHY54616_MII_MISC_CTRLr(unit, pc, 0x200, 0x200)); 586 #endif 587 /* 588 * Configure Auxiliary 1000BASE-X control register to turn off 589 * carrier extension. The Intel 7131 NIC does not accept carrier 590 * extension and gets CRC errors. 591 */ 592 SOC_IF_ERROR_RETURN 593 (MODIFY_PHY54616_AUX_1000X_CTRLr(unit, pc, 0x0040, 0x0040)); 594 /* Enable LPI pass through on PHY for native EEE */ /* 595 if ( PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) { 596 SOC_IF_ERROR_RETURN 597 (phy_reg_aer_modify(unit, pc, 0x833e, 0xc000, 0xc000)); 598 } 599 */ 600 601 /* Configure extended control register for led mode and jumbo frame support */ 602 mask = (1 << 5) | (1 << 0); 603 604 /* if using led link/activity mode, disable led traffic mode */ 605 if (pc->ledctrl & 0x10 || pc->ledselect == 0x01) { 606 data = 0; 607 } else { 608 data = 1 << 5; /* Enable LEDs to indicate traffic status */ 609 } 610 /* Configure Extended Control Register for Jumbo frames support */ 611 data |= 1 << 0; /* Set high FIFO elasticity to support jumbo frames */ 612 SOC_IF_ERROR_RETURN 613 (MODIFY_PHY54616_MII_ECRr(unit, pc, data, mask)); 614 /* Enable extended packet length (4.5k through 25k) */ 615 SOC_IF_ERROR_RETURN 616 (MODIFY_PHY54616_MII_AUX_CTRLr(unit, pc, 0x4000, 0x4000)); 617 /* 1000BASE-T PCS Transmit FIFO Elasticity *\ 618 \* enable jumbo frame for SGMII-Copper or GBIC mode */ 619 SOC_IF_ERROR_RETURN 620 (MODIFY_PHY54616_AUTO_DETECT_SGMII_MEDIAr(unit, pc, 0x4, 0x4)); 621 622 /* Configure LED selectors */ 623 data = ((pc->ledmode[1] & 0xf) << 4) | (pc->ledmode[0] & 0xf); 624 SOC_IF_ERROR_RETURN 625 (WRITE_PHY54616_LED_SELECTOR_1r(unit, pc, data)); 626 627 data = ((pc->ledmode[3] & 0xf) << 4) | (pc->ledmode[2] & 0xf); 628 SOC_IF_ERROR_RETURN 629 (WRITE_PHY54616_LED_SELECTOR_2r(unit, pc, data)); 630 631 data = (pc->ledctrl & 0x3ff); 632 SOC_IF_ERROR_RETURN 633 (WRITE_PHY54616_LED_CTRLr(unit, pc, data)); 634 635 SOC_IF_ERROR_RETURN 636 (WRITE_PHY54616_EXP_LED_SELECTORr(unit, pc, pc->ledselect)); 637 638 /* 639 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 640 return SOC_E_NONE; 641 } 642 */ 643 644 /* 100BASE-TX initialization change for EEE and autogreen mode */ 645 /* 646 SOC_IF_ERROR_RETURN 647 (MODIFY_PHY54618_MII_AUX_CTRLr(unit, pc, 0x0c00, 0x0c00)); 648 SOC_IF_ERROR_RETURN( 649 WRITE_PHY_REG(unit, pc, 0x17, 0x4022)); 650 SOC_IF_ERROR_RETURN( 651 WRITE_PHY_REG(unit, pc, 0x15, 0x017b)); 652 SOC_IF_ERROR_RETURN 653 (MODIFY_PHY54618_MII_AUX_CTRLr(unit, pc, 0x0400, 0x0c00)); 654 */ 655 656 return SOC_E_NONE; 657 } 658 659 /* 660 * Function: 661 * phy_54616_init 662 * Purpose: 663 * Init function for 54616 PHY. 664 * Parameters: 665 * unit - StrataSwitch unit #. 666 * port - StrataSwitch port #. 667 * Returns: 668 * SOC_E_NONE 669 */ 670 671 STATIC int 672 phy_54616_init(int unit, soc_port_t port) 673 { 674 phy_ctrl_t *pc; 675 int fiber_capable; 676 int fiber_preferred; 677 uint16 data; 678 679 LOG_INFO(BSL_LS_SOC_PHY, 680 (BSL_META_U(unit, 681 "phy_54616_init: u=%d p=%d\n"), 682 unit, port)); 683 684 pc = EXT_PHY_SW_STATE(unit, port); 685 686 if ( PHY_IS_BCM54616S(pc) ) { 687 /* check the for the precense of the SERDES block and and read 688 the INTF_SEL[1:0] strap values */ 689 690 SOC_IF_ERROR_RETURN 691 (READ_PHY54616_MODE_CTRLr(unit, pc, &data)); 692 693 if ((data & (0x2 << 1)) == (0x2 << 1)) { 694 pc->interface = SOC_PORT_IF_SGMII; 695 fiber_capable = FALSE; 696 } else { 697 /* pc->interface = SOC_PORT_IF_RGMII; */ 698 pc->interface = SOC_PORT_IF_GMII; /* MAC unable to handle SOC_PORT_IF_RGMII */ 699 PHY_FLAGS_SET(pc->unit, pc->port, PHY_FLAGS_PRIMARY_SERDES); 700 fiber_capable = TRUE; 701 } 702 } else { 703 pc->interface = SOC_PORT_IF_GMII; 704 fiber_capable = FALSE; 705 } 706 707 /* 708 * In automedium mode, the property phy_fiber_pref_port<X> is used 709 * to set a preference for fiber mode in the event both copper and 710 * fiber links are up. 711 * 712 * If NOT in automedium mode, phy_fiber_pref_port<X> is used to 713 * select which of fiber or copper is forced. 714 */ 715 if (!fiber_capable) { 716 fiber_preferred = 0; 717 pc->automedium = 0; 718 } else { 719 fiber_preferred = 720 soc_property_port_get(unit, port, spn_PHY_FIBER_PREF, 1); 721 pc->automedium = 722 soc_property_port_get(unit, port, spn_PHY_AUTOMEDIUM, 1); 723 } 724 725 LOG_INFO(BSL_LS_SOC_PHY, 726 (BSL_META_U(unit, 727 "phy_54616_init: " 728 "u=%d p=%d type=54616%s automedium=%d fiber_pref=%d\n"), 729 unit, port, fiber_capable ? "S" : "", 730 pc->automedium, fiber_preferred)); 731 732 pc->copper.enable = TRUE; 733 pc->copper.preferred = !fiber_preferred; 734 pc->copper.autoneg_enable = TRUE; 735 pc->copper.force_speed = 1000; 736 pc->copper.force_duplex = TRUE; 737 pc->copper.master = SOC_PORT_MS_AUTO; 738 pc->copper.mdix = SOC_PORT_MDIX_AUTO; 739 740 pc->fiber.enable = fiber_capable; 741 pc->fiber.preferred = fiber_preferred; 742 pc->fiber.autoneg_enable = fiber_capable; 743 pc->fiber.force_speed = 1000; 744 pc->fiber.force_duplex = TRUE; 745 pc->fiber.master = SOC_PORT_MS_NONE; 746 pc->fiber.mdix = SOC_PORT_MDIX_NORMAL; 747 748 SOC_IF_ERROR_RETURN 749 (_phy_54616_copper_ability_local_get(unit, port, &pc->copper.advert_ability)); 750 if (fiber_capable) { 751 (_phy_54616_fiber_ability_local_get(unit, port, &pc->fiber.advert_ability)); 752 } 753 754 /* Initially configure for the preferred medium. */ 755 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_COPPER); 756 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER); 757 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_PASSTHRU); 758 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX); 759 PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_ENABLED); 760 PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_MODE); 761 762 if (pc->fiber.preferred) { 763 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER); 764 } else { 765 PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER); 766 } 767 768 /* Get Requested LED selectors (defaults are hardware defaults) */ 769 pc->ledmode[0] = soc_property_port_get(unit, port, spn_PHY_LED1_MODE, 0); 770 pc->ledmode[1] = soc_property_port_get(unit, port, spn_PHY_LED2_MODE, 1); 771 pc->ledmode[2] = soc_property_port_get(unit, port, spn_PHY_LED3_MODE, 3); 772 pc->ledmode[3] = soc_property_port_get(unit, port, spn_PHY_LED4_MODE, 6); 773 pc->ledctrl = soc_property_port_get(unit, port, spn_PHY_LED_CTRL, 0x8); 774 pc->ledselect = soc_property_port_get(unit, port, spn_PHY_LED_SELECT, 0); 775 776 SOC_IF_ERROR_RETURN 777 (_phy_54616_reset_setup(unit, port)); 778 779 SOC_IF_ERROR_RETURN 780 (_phy_54616_medium_config_update(unit, port, 781 PHY_COPPER_MODE(unit, port) ? 782 &pc->copper : 783 &pc->fiber)); 784 return SOC_E_NONE; 785 } 786 787 /* 788 * Function: 789 * phy_54616_enable_set 790 * Purpose: 791 * Enable or disable the physical interface. 792 * Parameters: 793 * unit - StrataSwitch unit #. 794 * port - StrataSwitch port #. 795 * enable - Boolean, true = enable PHY, false = disable. 796 * Returns: 797 * SOC_E_XXX 798 */ 799 800 STATIC int 801 phy_54616_enable_set(int unit, soc_port_t port, int enable) 802 { 803 uint16 power; 804 phy_ctrl_t *pc; 805 806 pc = EXT_PHY_SW_STATE(unit, port); 807 power = (enable) ? 0 : MII_CTRL_PD; 808 809 /* Do not incorrectly Power up the interface if medium is disabled and 810 * global enable = true 811 */ 812 if (pc->copper.enable && (pc->automedium || PHY_COPPER_MODE(unit, port))) { 813 SOC_IF_ERROR_RETURN 814 (MODIFY_PHY54616_MII_CTRLr(unit, pc, power, MII_CTRL_PD)); 815 816 LOG_INFO(BSL_LS_SOC_PHY, 817 (BSL_META_U(unit, 818 "phy_54616_enable_set: " 819 "Power %s copper medium\n"), (enable) ? "up" : "down")); 820 } 821 822 if (pc->fiber.enable && (pc->automedium || PHY_FIBER_MODE(unit, port))) { 823 SOC_IF_ERROR_RETURN 824 (MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc, power, 825 MII_CTRL_PD)); 826 827 LOG_INFO(BSL_LS_SOC_PHY, 828 (BSL_META_U(unit, 829 "phy_54616_enable_set: " 830 "Power %s fiber medium\n"), (enable) ? "up" : "down")); 831 } 832 833 /* Update software state */ 834 SOC_IF_ERROR_RETURN(phy_fe_ge_enable_set(unit, port, enable)); 835 836 return SOC_E_NONE; 837 } 838 839 /* 840 * Function: 841 * phy_54616_enable_get 842 * Purpose: 843 * Enable or disable the physical interface for a 54616 device. 844 * Parameters: 845 * unit - StrataSwitch unit #. 846 * port - StrataSwitch port #. 847 * enable - (OUT) Boolean, true = enable PHY, false = disable. 848 * Returns: 849 * SOC_E_XXX 850 */ 851 852 STATIC int 853 phy_54616_enable_get(int unit, soc_port_t port, int *enable) 854 { 855 return phy_fe_ge_enable_get(unit, port, enable); 856 } 857 858 /* 859 * Function: 860 * _phy_54616_100fx_setup 861 * Purpose: 862 * Switch from 1000X mode to 100FX. 863 * Parameters: 864 * unit - StrataSwitch unit #. 865 * port - StrataSwitch port #. 866 * Returns: 867 * SOC_E_XXX 868 */ 869 STATIC int 870 _phy_54616_fiber_100fx_setup(int unit, soc_port_t port) 871 { 872 phy_ctrl_t *pc; 873 uint16 data; 874 875 pc = EXT_PHY_SW_STATE(unit, port); 876 877 LOG_VERBOSE(BSL_LS_SOC_PHY, 878 (BSL_META_U(unit, 879 "_phy_54616_1000x_to_100fx: u=%d p=%d \n"), 880 unit, port)); 881 882 /* clear the power down bit of the SerDes */ 883 LOG_INFO(BSL_LS_SOC_PHY, 884 (BSL_META_U(unit, 885 "%s:p=%d,Pri-SerDes mode. Fiber PowerDown(%s)!\n"), 886 FUNCTION_NAME(), port, "No")); 887 SOC_IF_ERROR_RETURN( 888 MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc, 0, MII_CTRL_PD)); 889 890 /* set to fiber mode */ /* bit[2:1]=1 */ 891 SOC_IF_ERROR_RETURN( 892 MODIFY_PHY54616_MODE_CTRLr(unit, pc, 0x2,0x6)); 893 894 /* set loopback */ 895 SOC_IF_ERROR_RETURN( 896 MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc, MII_CTRL_LE, MII_CTRL_LE)); 897 898 /* select 100FX mode */ 899 /* bit[0]=1 */ 900 data = 1; 901 data |= pc->fiber.force_duplex? PHY_54616_PRIMARY_SERDES_100FX_FD:0; 902 903 SOC_IF_ERROR_RETURN( 904 MODIFY_PHY54616_100FX_CTRLr(unit, pc, data, 905 1 | PHY_54616_PRIMARY_SERDES_100FX_FD)); 906 907 /* Power down SerDes RX path (Expention register)*/ 908 /* Power up SerDes RX path */ /* select Exp_reg 05 */ 909 SOC_IF_ERROR_RETURN( 910 WRITE_PHY54616_EXP_LED_FLASH_CTRLr(unit, pc, 0x0C3B)); 911 SOC_IF_ERROR_RETURN( 912 WRITE_PHY54616_EXP_LED_FLASH_CTRLr(unit, pc, 0x0C3A)); 913 914 /* reset loopback to switch clock back to SerDes RX clock */ 915 /* bit[14]=0 */ 916 SOC_IF_ERROR_RETURN( 917 MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc, 918 PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE) ? MII_CTRL_PD : 0, 919 MII_CTRL_LE | MII_CTRL_PD)); 920 921 PHY_FLAGS_SET(unit, port, PHY_FLAGS_100FX); 922 pc->fiber.force_speed = 100; 923 pc->fiber.autoneg_enable = FALSE; 924 925 return SOC_E_NONE; 926 } 927 928 /* 929 * Function: 930 * _phy_54616_1000x_setup 931 * Purpose: 932 * Switch from 100FX mode to 1000X. 933 * Parameters: 934 * unit - StrataSwitch unit #. 935 * port - StrataSwitch port #. 936 * Returns: 937 * SOC_E_XXX 938 */ 939 STATIC int 940 _phy_54616_fiber_1000x_setup(int unit, soc_port_t port) 941 { 942 phy_ctrl_t *pc; 943 944 pc = EXT_PHY_SW_STATE(unit, port); 945 946 LOG_VERBOSE(BSL_LS_SOC_PHY, 947 (BSL_META_U(unit, 948 "_phy_54616_fiber_1000x_setup: u=%d p=%d \n"), 949 unit, port)); 950 951 /* set to Fiber mode and enable primary SerDes register */ 952 /* bit[2:1]=01*/ 953 SOC_IF_ERROR_RETURN( 954 MODIFY_PHY54616_MODE_CTRLr(unit, pc, 0x2,0x6)); 955 /* enable 1000X, ie. disable 100FX */ 956 /* bit[0]=0 */ 957 SOC_IF_ERROR_RETURN( 958 MODIFY_PHY54616_100FX_CTRLr(unit,pc, 0, 1)); 959 960 /* clear the SerDes power down bit */ 961 /* bit[11]=0 */ 962 LOG_INFO(BSL_LS_SOC_PHY, 963 (BSL_META_U(unit, 964 "%s:p=%d,Pri-SerDes Mode. Fiber PowerDown(%s)!\n"), 965 FUNCTION_NAME(), port, "No")); 966 SOC_IF_ERROR_RETURN( 967 MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc, 968 PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE) ? MII_CTRL_PD : 0, 969 MII_CTRL_PD)); 970 971 pc->fiber.force_duplex = TRUE; 972 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX); 973 974 return SOC_E_NONE; 975 } 976 977 STATIC int 978 _phy_54616_medium_change(int unit, soc_port_t port, int force_update) 979 { 980 phy_ctrl_t *pc; 981 int medium; 982 983 pc = EXT_PHY_SW_STATE(unit, port); 984 985 SOC_IF_ERROR_RETURN 986 (_phy_54616_medium_check(unit, port, &medium)); 987 988 if (medium == SOC_PORT_MEDIUM_COPPER) { 989 if ((!PHY_COPPER_MODE(unit, port)) || force_update) { /* Was fiber */ 990 PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER); 991 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER); 992 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX); 993 PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 994 /* BCM54618E/SE is EEE capable */ 995 if ( PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) { 996 PHY_FLAGS_SET(unit, port, PHY_FLAGS_EEE_CAPABLE); 997 } 998 SOC_IF_ERROR_RETURN 999 (_phy_54616_no_reset_setup(unit, port)); 1000 1001 /* Do not power up the interface if medium is disabled. */ 1002 if (pc->copper.enable) { 1003 SOC_IF_ERROR_RETURN 1004 (_phy_54616_medium_config_update(unit, port, &pc->copper)); 1005 } 1006 LOG_INFO(BSL_LS_SOC_PHY, 1007 (BSL_META_U(unit, 1008 "_phy_54616_link_auto_detect: u=%d p=%d [F->C]\n"), 1009 unit, port)); 1010 } 1011 } else { /* Fiber */ 1012 if (PHY_COPPER_MODE(unit, port) || force_update) { /* Was copper */ 1013 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_COPPER); 1014 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_EEE_CAPABLE); 1015 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER); 1016 PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 1017 SOC_IF_ERROR_RETURN 1018 (_phy_54616_no_reset_setup(unit, port)); 1019 1020 if (pc->fiber.enable) { 1021 SOC_IF_ERROR_RETURN 1022 (_phy_54616_medium_config_update(unit, port, &pc->fiber)); 1023 } 1024 LOG_INFO(BSL_LS_SOC_PHY, 1025 (BSL_META_U(unit, 1026 "_phy_54616_link_auto_detect: u=%d p=%d [C->F]\n"), 1027 unit, port)); 1028 } 1029 } 1030 return SOC_E_NONE; 1031 } 1032 1033 /* 1034 * Function: 1035 * phy_54616_link_get 1036 * Purpose: 1037 * Determine the current link up/down status for a 54616 device. 1038 * Parameters: 1039 * unit - StrataSwitch unit #. 1040 * port - StrataSwitch port #. 1041 * link - (OUT) Boolean, true indicates link established. 1042 * Returns: 1043 * SOC_E_XXX 1044 * Notes: 1045 * If using automedium, also switches the mode. 1046 */ 1047 STATIC int 1048 phy_54616_link_get(int unit, soc_port_t port, int *link) 1049 { 1050 phy_ctrl_t *pc; 1051 uint16 data; 1052 uint16 mask; 1053 1054 pc = EXT_PHY_SW_STATE(unit, port); 1055 *link = FALSE; /* Default return */ 1056 1057 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) { 1058 return SOC_E_NONE; 1059 } 1060 1061 if (!pc->fiber.enable && !pc->copper.enable) { 1062 return SOC_E_NONE; 1063 } 1064 1065 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_MEDIUM_CHANGE); 1066 if (pc->automedium) { 1067 /* Check for medium change and update HW/SW accordingly. */ 1068 SOC_IF_ERROR_RETURN 1069 (_phy_54616_medium_change(unit, port,FALSE)); 1070 } 1071 if (PHY_COPPER_MODE(unit, port)) { 1072 SOC_IF_ERROR_RETURN(phy_fe_ge_link_get(unit, port, link)); 1073 } else { 1074 SOC_IF_ERROR_RETURN 1075 (READ_PHY54616_1000X_MII_STATr(unit, pc, &data)); 1076 *link = (data & MII_STAT_LA) ? TRUE : FALSE; 1077 } 1078 1079 /* If preferred medium is up, disable the other medium 1080 * to prevent false link. */ 1081 if (pc->automedium) { 1082 mask = MII_CTRL_PD; 1083 if (pc->copper.preferred) { 1084 if (pc->fiber.enable) { 1085 /* power down secondary serdes */ 1086 data = (*link && PHY_COPPER_MODE(unit, port)) ? MII_CTRL_PD : 0; 1087 } else { 1088 data = MII_CTRL_PD; 1089 } 1090 SOC_IF_ERROR_RETURN 1091 (MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc, data, mask)); 1092 } else { /* pc->fiber.preferred */ 1093 if (pc->copper.enable) { 1094 data = (*link && PHY_FIBER_MODE(unit, port)) ? MII_CTRL_PD : 0; 1095 } else { 1096 data = MII_CTRL_PD; 1097 } 1098 SOC_IF_ERROR_RETURN 1099 (MODIFY_PHY54616_MII_CTRLr(unit, pc, data, mask)); 1100 } 1101 } 1102 1103 LOG_VERBOSE(BSL_LS_SOC_PHY, 1104 (BSL_META_U(unit, 1105 "phy_54616_link_get: u=%d p=%d mode=%s%s link=%d\n"), 1106 unit, port, 1107 PHY_COPPER_MODE(unit, port) ? "C" : "F", 1108 PHY_FIBER_100FX_MODE(unit, port)? "(100FX)" : "", 1109 *link)); 1110 1111 return SOC_E_NONE; 1112 } 1113 1114 /* 1115 * Function: 1116 * phy_54616_duplex_set 1117 * Purpose: 1118 * Set the current duplex mode (forced). 1119 * Parameters: 1120 * unit - StrataSwitch unit #. 1121 * port - StrataSwitch port #. 1122 * duplex - Boolean, true indicates full duplex, false indicates half. 1123 * Returns: 1124 * SOC_E_NONE 1125 * SOC_E_UNAVAIL - Half duplex requested, and not supported. 1126 * Notes: 1127 * The duplex is set only for the ACTIVE medium. 1128 * No synchronization performed at this level. 1129 * Autonegotiation is not manipulated. 1130 */ 1131 1132 STATIC int 1133 phy_54616_duplex_set(int unit, soc_port_t port, int duplex) 1134 { 1135 int rv; 1136 phy_ctrl_t *pc; 1137 1138 pc = EXT_PHY_SW_STATE(unit, port); 1139 rv = SOC_E_NONE; 1140 if (PHY_COPPER_MODE(unit, port)) { 1141 rv = phy_fe_ge_duplex_set(unit, port, duplex); 1142 if (SOC_SUCCESS(rv)) { 1143 pc->copper.force_duplex = duplex; 1144 } 1145 } else { /* Fiber */ 1146 if (PHY_FIBER_100FX_MODE(unit, port)) { 1147 SOC_IF_ERROR_RETURN 1148 (MODIFY_PHY54616_100FX_CTRLr(unit, pc, 1149 duplex? PHY_54616_PRIMARY_SERDES_100FX_FD:0, PHY_54616_PRIMARY_SERDES_100FX_FD)); 1150 pc->fiber.force_duplex = duplex; 1151 } else { /* 1000X always full duplex */ 1152 if (!duplex) { 1153 rv = SOC_E_UNAVAIL; 1154 } 1155 } 1156 } 1157 LOG_INFO(BSL_LS_SOC_PHY, 1158 (BSL_META_U(unit, 1159 "phy_54616_duplex_set: u=%d p=%d d=%d rv=%d\n"), 1160 unit, port, duplex, rv)); 1161 1162 return rv; 1163 } 1164 1165 /* 1166 * Function: 1167 * phy_54616_duplex_get 1168 * Purpose: 1169 * Get the current operating duplex mode. If autoneg is enabled, 1170 * then operating mode is returned, otherwise forced mode is returned. 1171 * Parameters: 1172 * unit - StrataSwitch unit #. 1173 * port - StrataSwitch port #. 1174 * duplex - (OUT) Boolean, true indicates full duplex, false 1175 * indicates half. 1176 * Returns: 1177 * SOC_E_NONE 1178 * Notes: 1179 * The duplex is retrieved for the ACTIVE medium. 1180 * No synchronization performed at this level. Autonegotiation is 1181 * not manipulated. 1182 */ 1183 1184 STATIC int 1185 phy_54616_duplex_get(int unit, soc_port_t port, int *duplex) 1186 { 1187 phy_ctrl_t *pc; 1188 uint16 data16; 1189 1190 pc = EXT_PHY_SW_STATE(unit, port); 1191 1192 if (PHY_COPPER_MODE(unit, port)) { 1193 return phy_fe_ge_duplex_get(unit, port, duplex); 1194 } else { 1195 if (PHY_FIBER_100FX_MODE(unit, port)) { 1196 SOC_IF_ERROR_RETURN 1197 (READ_PHY54616_100FX_CTRLr(unit, pc, &data16)); 1198 *duplex = (data16 & PHY_54616_PRIMARY_SERDES_100FX_FD) ? 1199 TRUE: FALSE; 1200 } else { /* 1000X */ 1201 *duplex = TRUE; 1202 } 1203 } 1204 1205 return SOC_E_NONE; 1206 } 1207 1208 /* 1209 * Function: 1210 * phy_54616_speed_set 1211 * Purpose: 1212 * Set the current operating speed (forced). 1213 * Parameters: 1214 * unit - StrataSwitch unit #. 1215 * port - StrataSwitch port #. 1216 * speed - Requested speed, only 1000 supported. 1217 * Returns: 1218 * SOC_E_XXX 1219 * Notes: 1220 * The speed is set only for the ACTIVE medium. 1221 */ 1222 1223 STATIC int 1224 phy_54616_speed_set(int unit, soc_port_t port, int speed) 1225 { 1226 int rv; 1227 phy_ctrl_t *pc; 1228 1229 pc = EXT_PHY_SW_STATE(unit, port); 1230 rv = SOC_E_NONE; 1231 if (PHY_COPPER_MODE(unit, port)) { 1232 /* Note: mac.c uses phy_5690_notify_speed to update 5690 */ 1233 rv = phy_fe_ge_speed_set(unit, port, speed); 1234 if (SOC_SUCCESS(rv)) { 1235 pc->copper.force_speed = speed; 1236 } 1237 } else { /* Fiber */ 1238 if (speed == 100) { 1239 rv = _phy_54616_fiber_100fx_setup(unit, port); 1240 } else if (speed == 0 || speed == 1000) { 1241 rv = _phy_54616_fiber_1000x_setup(unit, port); 1242 } else { 1243 rv = SOC_E_CONFIG; 1244 } 1245 if (SOC_SUCCESS(rv)) { 1246 pc->fiber.force_speed = speed; 1247 } 1248 } 1249 if (SOC_SUCCESS(rv) && !PHY_SGMII_AUTONEG_MODE(unit, port)) { 1250 uint16 mii_ctrl; 1251 1252 SOC_IF_ERROR_RETURN 1253 (READ_PHY54616_1000X_MII_CTRLr(unit, pc, &mii_ctrl)); 1254 1255 mii_ctrl &= ~(MII_CTRL_SS_LSB | MII_CTRL_SS_MSB); 1256 switch(speed) { 1257 case 10: 1258 mii_ctrl |= MII_CTRL_SS_10; 1259 break; 1260 case 100: 1261 mii_ctrl |= MII_CTRL_SS_100; 1262 break; 1263 case 0: 1264 case 1000: 1265 mii_ctrl |= MII_CTRL_SS_1000; 1266 break; 1267 default: 1268 return(SOC_E_CONFIG); 1269 } 1270 1271 SOC_IF_ERROR_RETURN 1272 (WRITE_PHY54616_1000X_MII_CTRLr(unit, pc, mii_ctrl)); 1273 } 1274 1275 LOG_INFO(BSL_LS_SOC_PHY, 1276 (BSL_META_U(unit, 1277 "phy_54616_speed_set: u=%d p=%d s=%d fiber=%d rv=%d\n"), 1278 unit, port, speed, PHY_FIBER_MODE(unit, port), rv)); 1279 1280 return rv; 1281 } 1282 1283 /* 1284 * Function: 1285 * phy_54616_speed_get 1286 * Purpose: 1287 * Get the current operating speed for a 54616 device. 1288 * Parameters: 1289 * unit - StrataSwitch unit #. 1290 * port - StrataSwitch port #. 1291 * duplex - (OUT) Boolean, true indicates full duplex, false 1292 * indicates half. 1293 * Returns: 1294 * SOC_E_NONE 1295 * Notes: 1296 * The speed is retrieved for the ACTIVE medium. 1297 */ 1298 1299 STATIC int 1300 phy_54616_speed_get(int unit, soc_port_t port, int *speed) 1301 { 1302 phy_ctrl_t *pc; 1303 uint16 opt_mode; 1304 1305 pc = EXT_PHY_SW_STATE(unit, port); 1306 1307 if (PHY_COPPER_MODE(unit, port)) { 1308 return phy_fe_ge_speed_get(unit, port, speed); 1309 } else { 1310 *speed = 1000; 1311 SOC_IF_ERROR_RETURN 1312 (READ_PHY54616_EXP_OPT_MODE_STATr(unit, pc, &opt_mode)); 1313 switch(opt_mode & (0x3 << 13)) { 1314 case (0 << 13): 1315 *speed = 10; 1316 break; 1317 case (1 << 13): 1318 *speed = 100; 1319 break; 1320 case (2 << 13): 1321 *speed = 1000; 1322 break; 1323 default: 1324 LOG_WARN(BSL_LS_SOC_PHY, 1325 (BSL_META_U(unit, 1326 "phy_54616_speed_get: u=%d p=%d invalid speed\n"), 1327 unit, port)); 1328 } 1329 } 1330 1331 return SOC_E_NONE; 1332 } 1333 1334 /* 1335 * Function: 1336 * phy_54616_master_set 1337 * Purpose: 1338 * Set the current master mode 1339 * Parameters: 1340 * unit - StrataSwitch unit #. 1341 * port - StrataSwitch port #. 1342 * master - SOC_PORT_MS_* 1343 * Returns: 1344 * SOC_E_XXX 1345 * Notes: 1346 * The master mode is set only for the ACTIVE medium. 1347 */ 1348 STATIC int 1349 phy_54616_master_set(int unit, soc_port_t port, int master) 1350 { 1351 int rv; 1352 phy_ctrl_t *pc; 1353 1354 pc = EXT_PHY_SW_STATE(unit, port); 1355 rv = SOC_E_NONE; 1356 if (PHY_COPPER_MODE(unit, port)) { 1357 rv = phy_fe_ge_master_set(unit, port, master); 1358 if (SOC_SUCCESS(rv)) { 1359 pc->copper.master = master; 1360 } 1361 } 1362 LOG_INFO(BSL_LS_SOC_PHY, 1363 (BSL_META_U(unit, 1364 "phy_54616_master_set: u=%d p=%d master=%d fiber=%d rv=%d\n"), 1365 unit, port, master, PHY_FIBER_MODE(unit, port), rv)); 1366 return rv; 1367 } 1368 1369 /* 1370 * Function: 1371 * phy_54616_master_get 1372 * Purpose: 1373 * Get the current master mode for a 54616 device. 1374 * Parameters: 1375 * unit - StrataSwitch unit #. 1376 * port - StrataSwitch port #. 1377 * master - (OUT) SOC_PORT_MS_* 1378 * Returns: 1379 * SOC_E_NONE 1380 * Notes: 1381 * The master mode is retrieved for the ACTIVE medium. 1382 */ 1383 1384 STATIC int 1385 phy_54616_master_get(int unit, soc_port_t port, int *master) 1386 { 1387 if (PHY_COPPER_MODE(unit, port)) { 1388 return phy_fe_ge_master_get(unit, port, master); 1389 } else { 1390 *master = SOC_PORT_MS_NONE; 1391 return SOC_E_NONE; 1392 } 1393 } 1394 1395 /* 1396 * Function: 1397 * phy_54616_autoneg_set 1398 * Purpose: 1399 * Enable or disable auto-negotiation on the specified port. 1400 * Parameters: 1401 * unit - StrataSwitch unit #. 1402 * port - StrataSwitch port #. 1403 * autoneg - Boolean, if true, auto-negotiation is enabled 1404 * (and/or restarted). If false, autonegotiation is disabled. 1405 * Returns: 1406 * SOC_E_XXX 1407 * Notes: 1408 * The autoneg mode is set only for the ACTIVE medium. 1409 */ 1410 1411 STATIC int 1412 phy_54616_autoneg_set(int unit, soc_port_t port, int autoneg) 1413 { 1414 int rv; 1415 uint16 data, mask; 1416 phy_ctrl_t *pc; 1417 1418 /* don't allow AN if port is disabled */ 1419 1420 if (autoneg) { 1421 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) { 1422 return SOC_E_NONE; 1423 } 1424 } 1425 1426 pc = EXT_PHY_SW_STATE(unit, port); 1427 rv = SOC_E_NONE; 1428 if (PHY_COPPER_MODE(unit, port)) { 1429 rv = phy_fe_ge_an_set(unit, port, autoneg); 1430 if (SOC_SUCCESS(rv)) { 1431 pc->copper.autoneg_enable = autoneg ? 1 : 0; 1432 } 1433 } else { 1434 data = (autoneg) ? MII_CTRL_AE | MII_CTRL_RAN : 0; 1435 mask = MII_CTRL_AE | MII_CTRL_RAN | MII_CTRL_FD; 1436 SOC_IF_ERROR_RETURN 1437 (MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc, data, mask)); 1438 1439 pc->fiber.autoneg_enable = autoneg ? TRUE : FALSE; 1440 } 1441 1442 LOG_INFO(BSL_LS_SOC_PHY, 1443 (BSL_META_U(unit, 1444 "phy_54616_autoneg_set: u=%d p=%d autoneg=%d rv=%d\n"), 1445 unit, port, autoneg, rv)); 1446 1447 return rv; 1448 } 1449 1450 /* 1451 * Function: 1452 * phy_54616_autoneg_get 1453 * Purpose: 1454 * Get the current auto-negotiation status (enabled/busy). 1455 * Parameters: 1456 * unit - StrataSwitch unit #. 1457 * port - StrataSwitch port #. 1458 * autoneg - (OUT) if true, auto-negotiation is enabled. 1459 * autoneg_done - (OUT) if true, auto-negotiation is complete. This 1460 * value is undefined if autoneg == FALSE. 1461 * Returns: 1462 * SOC_E_XXX 1463 * Notes: 1464 * The autoneg mode is retrieved for the ACTIVE medium. 1465 */ 1466 1467 STATIC int 1468 phy_54616_autoneg_get(int unit, soc_port_t port, 1469 int *autoneg, int *autoneg_done) 1470 { 1471 int rv; 1472 uint16 data; 1473 phy_ctrl_t *pc; 1474 1475 pc = EXT_PHY_SW_STATE(unit, port); 1476 1477 rv = SOC_E_NONE; 1478 *autoneg = FALSE; 1479 *autoneg_done = FALSE; 1480 if (PHY_COPPER_MODE(unit, port)) { 1481 rv = phy_fe_ge_an_get(unit, port, autoneg, autoneg_done); 1482 } else { 1483 /* autoneg is not enabled in 100FX mode */ 1484 if (PHY_FIBER_100FX_MODE(unit, port)) { 1485 *autoneg = FALSE; 1486 *autoneg_done = TRUE; 1487 return rv; 1488 } 1489 SOC_IF_ERROR_RETURN 1490 (READ_PHY54616_1000X_MII_CTRLr(unit, pc, &data)); 1491 if (data & MII_CTRL_AE) { 1492 *autoneg = TRUE; 1493 1494 SOC_IF_ERROR_RETURN 1495 (READ_PHY54616_1000X_MII_STATr(unit, pc, &data)); 1496 if (data & MII_STAT_AN_DONE) { 1497 *autoneg_done = TRUE; 1498 } 1499 } 1500 1501 } 1502 1503 return rv; 1504 } 1505 1506 /* 1507 * Function: 1508 * phy_54616_ability_advert_set 1509 * Purpose: 1510 * Set the current advertisement for auto-negotiation. 1511 * Parameters: 1512 * unit - StrataSwitch unit #. 1513 * port - StrataSwitch port #. 1514 * ability - Port ability indicating supported options/speeds. 1515 * Returns: 1516 * SOC_E_XXX 1517 * Notes: 1518 * The advertisement is set only for the ACTIVE medium. 1519 * No synchronization performed at this level. 1520 */ 1521 1522 STATIC int 1523 _phy_54616_fiber_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability) 1524 { 1525 phy_ctrl_t *pc; 1526 uint16 an_adv; 1527 1528 pc = EXT_PHY_SW_STATE(unit, port); 1529 1530 /* Support only full duplex */ 1531 an_adv = (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) ? MII_ANP_C37_FD : 0; 1532 switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) { 1533 case SOC_PA_PAUSE_TX: 1534 an_adv |= MII_ANP_C37_ASYM_PAUSE; 1535 break; 1536 case SOC_PA_PAUSE_RX: 1537 an_adv |= MII_ANP_C37_ASYM_PAUSE | MII_ANP_C37_PAUSE; 1538 break; 1539 case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX: 1540 an_adv |= MII_ANP_C37_PAUSE; 1541 break; 1542 } 1543 1544 SOC_IF_ERROR_RETURN 1545 (WRITE_PHY54616_1000X_MII_ANAr(unit, pc, an_adv)); 1546 1547 return SOC_E_NONE; 1548 } 1549 1550 1551 STATIC int 1552 phy_54616_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability) 1553 { 1554 phy_ctrl_t *pc; 1555 1556 pc = EXT_PHY_SW_STATE(unit, port); 1557 1558 if ( PHY_COPPER_MODE(unit, port) ) { 1559 SOC_IF_ERROR_RETURN 1560 (phy_fe_ge_ability_advert_set(unit, port, ability)); 1561 pc->copper.advert_ability = *ability; 1562 } else { 1563 SOC_IF_ERROR_RETURN 1564 (_phy_54616_fiber_ability_advert_set(unit, port, ability)); 1565 pc->fiber.advert_ability = *ability; 1566 } 1567 1568 /* EEE settings */ 1569 if ( PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE) ) { 1570 uint16 eee_ability = 0; 1571 1572 if ( ability->eee & SOC_PA_EEE_1GB_BASET ) { 1573 eee_ability |= 0x4; 1574 } 1575 if ( ability->eee & SOC_PA_EEE_100MB_BASETX ) { 1576 eee_ability |= 0x2; 1577 } 1578 if ( PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_ENABLED) ) { 1579 SOC_IF_ERROR_RETURN 1580 (MODIFY_PHY54618_EEE_ADVr(unit, pc, eee_ability, 0x0006)); 1581 } else { 1582 SOC_IF_ERROR_RETURN 1583 (MODIFY_PHY54618_EEE_ADVr(unit, pc, 0x0000, 0x0006)); 1584 } 1585 } 1586 1587 return SOC_E_NONE; 1588 } 1589 1590 /* 1591 * Function: 1592 * phy_54616_ability_advert_get 1593 * Purpose: 1594 * Get the current advertisement for auto-negotiation. 1595 * Parameters: 1596 * unit - StrataSwitch unit #. 1597 * port - StrataSwitch port #. 1598 * ability - Port ability indicating supported options/speeds. 1599 * Returns: 1600 * SOC_E_XXX 1601 * Notes: 1602 * The advertisement is retrieved for the ACTIVE medium. 1603 * No synchronization performed at this level. 1604 */ 1605 1606 STATIC int 1607 _phy_54616_fiber_ability_advert_get(int unit, soc_port_t port,soc_port_ability_t *ability) 1608 { 1609 phy_ctrl_t *pc; 1610 uint16 an_adv; 1611 1612 pc = EXT_PHY_SW_STATE(unit, port); 1613 1614 sal_memset(ability, 0, sizeof(*ability)); 1615 1616 SOC_IF_ERROR_RETURN 1617 (READ_PHY54616_1000X_MII_ANAr(unit, pc, &an_adv)); 1618 1619 switch ( an_adv & (MII_ANP_C37_ASYM_PAUSE | MII_ANP_C37_PAUSE) ) { 1620 case MII_ANP_C37_ASYM_PAUSE: 1621 ability->pause |= SOC_PA_PAUSE_TX; 1622 break; 1623 case (MII_ANP_C37_ASYM_PAUSE | MII_ANP_C37_PAUSE): 1624 ability->pause |= SOC_PA_PAUSE_RX; 1625 break; 1626 case MII_ANP_C37_PAUSE: 1627 ability->pause |= SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 1628 break; 1629 } 1630 1631 ability->speed_full_duplex |= (an_adv & MII_ANP_C37_FD) ? SOC_PA_SPEED_1000MB : 0; 1632 1633 return SOC_E_NONE; 1634 } 1635 1636 STATIC int 1637 phy_54616_ability_advert_get(int unit, soc_port_t port, soc_port_ability_t *ability) 1638 { 1639 if ( PHY_COPPER_MODE(unit, port) ) { 1640 SOC_IF_ERROR_RETURN 1641 (phy_fe_ge_ability_advert_get(unit, port, ability)); 1642 1643 /* EEE settings */ 1644 if ( PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE) ) { 1645 uint16 eee_ability = 0; 1646 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1647 1648 SOC_IF_ERROR_RETURN 1649 (READ_PHY54618_EEE_ADVr(unit, pc, &eee_ability)); 1650 if ( eee_ability & 0x04 ) { 1651 ability->eee |= SOC_PA_EEE_1GB_BASET; 1652 } 1653 if ( eee_ability & 0x02 ) { 1654 ability->eee |= SOC_PA_EEE_100MB_BASETX; 1655 } 1656 } 1657 } else { /* PHY_FIBER_MODE */ 1658 SOC_IF_ERROR_RETURN 1659 (_phy_54616_fiber_ability_advert_get(unit, port, ability)); 1660 } 1661 return SOC_E_NONE; 1662 } 1663 1664 /* 1665 * Function: 1666 * phy_54616_ability_remote_get 1667 * Purpose: 1668 * Get partners current advertisement for auto-negotiation. 1669 * Parameters: 1670 * unit - StrataSwitch unit #. 1671 * port - StrataSwitch port #. 1672 * ability - Port ability indicating supported options/speeds. 1673 * Returns: 1674 * SOC_E_XXX 1675 * Notes: 1676 * The remote advertisement is retrieved for the ACTIVE medium. 1677 * No synchronization performed at this level. If Autonegotiation is 1678 * disabled or in progress, this routine will return an error. 1679 */ 1680 1681 STATIC int 1682 _phy_54616_fiber_ability_remote_get(int unit, soc_port_t port, 1683 soc_port_ability_t *ability) 1684 { 1685 uint16 an_adv, data; 1686 phy_ctrl_t *pc; 1687 1688 pc = EXT_PHY_SW_STATE(unit, port); 1689 1690 sal_memset(ability, 0, sizeof(*ability)); 1691 1692 SOC_IF_ERROR_RETURN 1693 (READ_PHY54616_1000X_MII_CTRLr(unit, pc, &data)); 1694 if (!(data & MII_CTRL_AE)) { 1695 return SOC_E_DISABLED; 1696 } 1697 SOC_IF_ERROR_RETURN 1698 (READ_PHY54616_1000X_MII_STATr(unit, pc, &data)); 1699 1700 if (data & MII_STAT_AN_DONE) { 1701 /* Decode remote advertisement only when link is up and autoneg is 1702 * completed. 1703 */ 1704 1705 SOC_IF_ERROR_RETURN 1706 (READ_PHY54616_1000X_MII_ANPr(unit, pc, &an_adv)); 1707 1708 ability->speed_full_duplex |= (an_adv & MII_ANP_C37_FD) ? SOC_PA_SPEED_1000MB : 0; 1709 ability->speed_half_duplex |= (an_adv & MII_ANP_C37_HD) ? SOC_PA_SPEED_1000MB : 0; 1710 1711 switch (an_adv & (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) { 1712 case MII_ANP_C37_PAUSE: 1713 ability->pause |= SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 1714 break; 1715 case MII_ANP_C37_ASYM_PAUSE: 1716 ability->pause |= SOC_PA_PAUSE_TX; 1717 break; 1718 case MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE: 1719 ability->pause |= SOC_PA_PAUSE_RX; 1720 break; 1721 } 1722 1723 } else { 1724 /* Simply return local abilities */ 1725 SOC_IF_ERROR_RETURN 1726 (phy_54616_ability_advert_get(unit, port, ability)); 1727 } 1728 1729 return (SOC_E_NONE); 1730 } 1731 1732 STATIC int 1733 phy_54616_ability_remote_get(int unit, soc_port_t port, soc_port_ability_t *ability) 1734 { 1735 if ( PHY_COPPER_MODE(unit, port) ) { 1736 /* EEE settings */ 1737 if ( PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE) ) { 1738 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1739 uint16 eee_resolution; 1740 1741 SOC_IF_ERROR_RETURN 1742 (READ_PHY54618_EEE_RESOLUTION_STATr(unit, pc, &eee_resolution)); 1743 if ( eee_resolution & 0x04 ) { 1744 ability->eee |= SOC_PA_EEE_1GB_BASET; 1745 } 1746 if ( eee_resolution & 0x02 ) { 1747 ability->eee |= SOC_PA_EEE_100MB_BASETX; 1748 } 1749 } 1750 1751 SOC_IF_ERROR_RETURN 1752 (phy_fe_ge_ability_remote_get(unit, port, ability)); 1753 } else { /* PHY_FIBER_MODE */ 1754 SOC_IF_ERROR_RETURN 1755 (_phy_54616_fiber_ability_remote_get(unit, port, ability)); 1756 } 1757 return SOC_E_NONE; 1758 } 1759 1760 /* 1761 * Function: 1762 * phy_54616_lb_set 1763 * Purpose: 1764 * Set the local PHY loopback mode. 1765 * Parameters: 1766 * unit - StrataSwitch unit #. 1767 * port - StrataSwitch port #. 1768 * loopback - Boolean: true = enable loopback, false = disable. 1769 * Returns: 1770 * SOC_E_XXX 1771 * Notes: 1772 * The loopback mode is set only for the ACTIVE medium. 1773 * No synchronization performed at this level. 1774 */ 1775 1776 STATIC int 1777 phy_54616_lb_set(int unit, soc_port_t port, int enable) 1778 { 1779 phy_ctrl_t *pc; 1780 1781 pc = EXT_PHY_SW_STATE(unit, port); 1782 1783 #if AUTO_MDIX_WHEN_AN_DIS 1784 { 1785 /* Disable Auto-MDIX When autoneg disabled */ 1786 /* Enable Auto-MDIX When autoneg disabled */ 1787 uint16 data = (enable) ? 0x0000 : 0x0200; 1788 SOC_IF_ERROR_RETURN 1789 (MODIFY_PHY_54616_MII_MISC_CTRLr(unit, pc, data, 0x0200)); 1790 } 1791 #endif 1792 1793 if (PHY_COPPER_MODE(unit, port)) { 1794 SOC_IF_ERROR_RETURN 1795 (phy_fe_ge_lb_set(unit, port, enable)); 1796 } else { 1797 SOC_IF_ERROR_RETURN 1798 (MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc, (enable) ? MII_CTRL_LE : 0, MII_CTRL_LE)); 1799 1800 } 1801 LOG_INFO(BSL_LS_SOC_PHY, 1802 (BSL_META_U(unit, 1803 "phy_54616_lb_set: u=%d p=%d en=%d\n"), unit, port, enable)); 1804 1805 return SOC_E_NONE; 1806 } 1807 1808 /* 1809 * Function: 1810 * phy_54616_lb_get 1811 * Purpose: 1812 * Get the local PHY loopback mode. 1813 * Parameters: 1814 * unit - StrataSwitch unit #. 1815 * port - StrataSwitch port #. 1816 * loopback - (OUT) Boolean: true = enable loopback, false = disable. 1817 * Returns: 1818 * SOC_E_XXX 1819 * Notes: 1820 * The loopback mode is retrieved for the ACTIVE medium. 1821 */ 1822 1823 STATIC int 1824 phy_54616_lb_get(int unit, soc_port_t port, int *enable) 1825 { 1826 uint16 data; 1827 phy_ctrl_t *pc; 1828 1829 pc = EXT_PHY_SW_STATE(unit, port); 1830 1831 if (PHY_COPPER_MODE(unit, port)) { 1832 SOC_IF_ERROR_RETURN 1833 (phy_fe_ge_lb_get(unit, port, enable)); 1834 } else { 1835 SOC_IF_ERROR_RETURN 1836 (READ_PHY54616_1000X_MII_CTRLr(unit, pc, &data)); 1837 *enable = (data & MII_CTRL_LE) ? 1 : 0; 1838 } 1839 1840 return SOC_E_NONE; 1841 } 1842 1843 /* 1844 * Function: 1845 * phy_54616_interface_set 1846 * Purpose: 1847 * Set the current operating mode of the PHY. 1848 * Parameters: 1849 * unit - StrataSwitch unit #. 1850 * port - StrataSwitch port #. 1851 * pif - one of SOC_PORT_IF_* 1852 * Returns: 1853 * SOC_E_NONE - success 1854 * SOC_E_UNAVAIL - unsupported interface 1855 */ 1856 1857 STATIC int 1858 phy_54616_interface_set(int unit, soc_port_t port, soc_port_if_t pif) 1859 { 1860 COMPILER_REFERENCE(unit); 1861 COMPILER_REFERENCE(port); 1862 COMPILER_REFERENCE(pif); 1863 1864 return SOC_E_NONE; 1865 } 1866 1867 /* 1868 * Function: 1869 * phy_54616_interface_get 1870 * Purpose: 1871 * Get the current operating mode of the PHY. 1872 * Parameters: 1873 * unit - StrataSwitch unit #. 1874 * port - StrataSwitch port #. 1875 * pif - (OUT) one of SOC_PORT_IF_* 1876 * Returns: 1877 * SOC_E_NONE 1878 */ 1879 1880 STATIC int 1881 phy_54616_interface_get(int unit, soc_port_t port, soc_port_if_t *pif) 1882 { 1883 phy_ctrl_t *pc; 1884 1885 pc = EXT_PHY_SW_STATE(unit, port); 1886 1887 *pif = pc->interface; 1888 return SOC_E_NONE; 1889 } 1890 1891 /* 1892 * Function: 1893 * phy_54616_ability_local_get 1894 * Purpose: 1895 * Get the abilities of the local gigabit PHY. 1896 * Parameters: 1897 * unit - StrataSwitch unit #. 1898 * port - StrataSwitch port #. 1899 * ability - return device's abilities. 1900 * Returns: 1901 * SOC_E_NONE 1902 * Notes: 1903 * The ability is retrieved only for the ACTIVE medium. 1904 */ 1905 1906 STATIC int 1907 _phy_54616_copper_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 1908 { 1909 ability->speed_half_duplex = SOC_PA_SPEED_100MB | SOC_PA_SPEED_10MB; 1910 ability->speed_full_duplex = SOC_PA_SPEED_1000MB | SOC_PA_SPEED_100MB | SOC_PA_SPEED_10MB; 1911 1912 ability->pause = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 1913 ability->interface = SOC_PA_INTF_SGMII | SOC_PA_INTF_RGMII; 1914 ability->medium = SOC_PA_MEDIUM_COPPER; 1915 ability->loopback = SOC_PA_LB_PHY; 1916 ability->flags = SOC_PA_AUTONEG; 1917 1918 return (SOC_E_NONE); 1919 } 1920 1921 STATIC int 1922 _phy_54616_fiber_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 1923 { 1924 1925 ability->speed_half_duplex = SOC_PA_SPEED_1000MB; 1926 ability->speed_full_duplex = SOC_PA_SPEED_1000MB; 1927 1928 ability->pause = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 1929 ability->interface = SOC_PA_INTF_RGMII; 1930 ability->medium = SOC_PA_MEDIUM_FIBER; 1931 ability->loopback = SOC_PA_LB_PHY; 1932 ability->flags = SOC_PA_ABILITY_NONE; 1933 1934 return (SOC_E_NONE); 1935 } 1936 1937 STATIC int 1938 phy_54616_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 1939 { 1940 if (NULL == ability) { 1941 return SOC_E_PARAM; 1942 } 1943 1944 if (PHY_COPPER_MODE(unit, port)) { 1945 SOC_IF_ERROR_RETURN(_phy_54616_copper_ability_local_get(unit, port, ability)); 1946 } else { 1947 SOC_IF_ERROR_RETURN(_phy_54616_fiber_ability_local_get(unit, port, ability)); 1948 } 1949 1950 return (SOC_E_NONE); 1951 } 1952 1953 1954 /* 1955 * Function: 1956 * phy_54616_mdix_set 1957 * Description: 1958 * Set the Auto-MDIX mode of a port/PHY 1959 * Parameters: 1960 * unit - Device number 1961 * port - Port number 1962 * mode - One of: 1963 * SOC_PORT_MDIX_AUTO 1964 * Enable auto-MDIX when autonegotiation is enabled 1965 * SOC_PORT_MDIX_FORCE_AUTO 1966 * Enable auto-MDIX always 1967 * SOC_PORT_MDIX_NORMAL 1968 * Disable auto-MDIX 1969 * SOC_PORT_MDIX_XOVER 1970 * Disable auto-MDIX, and swap cable pairs 1971 * Return Value: 1972 * SOC_E_XXX 1973 */ 1974 STATIC int 1975 phy_54616_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode) 1976 { 1977 phy_ctrl_t *pc; 1978 int speed; 1979 1980 pc = EXT_PHY_SW_STATE(unit, port); 1981 if (PHY_COPPER_MODE(unit, port)) { 1982 switch (mode) { 1983 case SOC_PORT_MDIX_AUTO: 1984 /* Clear bit 14 for automatic MDI crossover */ 1985 SOC_IF_ERROR_RETURN 1986 (MODIFY_PHY54616_MII_ECRr(unit, pc, 0, 0x4000)); 1987 1988 /* Clear bit 9 to disable forced auto MDI xover */ 1989 SOC_IF_ERROR_RETURN 1990 (MODIFY_PHY54616_MII_MISC_CTRLr(unit, pc, 0, 0x0200)); 1991 break; 1992 1993 case SOC_PORT_MDIX_FORCE_AUTO: 1994 /* Clear bit 14 for automatic MDI crossover */ 1995 SOC_IF_ERROR_RETURN 1996 (MODIFY_PHY54616_MII_ECRr(unit, pc, 0, 0x4000)); 1997 1998 /* Set bit 9 to disable forced auto MDI xover */ 1999 SOC_IF_ERROR_RETURN 2000 (MODIFY_PHY54616_MII_MISC_CTRLr(unit, pc, 0x0200, 0x0200)); 2001 break; 2002 2003 case SOC_PORT_MDIX_NORMAL: 2004 SOC_IF_ERROR_RETURN(phy_54616_speed_get(unit, port, &speed)); 2005 if (speed == 0 || speed == 10 || speed == 100) { 2006 /* Set bit 14 for automatic MDI crossover */ 2007 SOC_IF_ERROR_RETURN 2008 (MODIFY_PHY54616_MII_ECRr(unit, pc, 0x4000, 0x4000)); 2009 2010 SOC_IF_ERROR_RETURN 2011 (WRITE_PHY54616_TEST1r(unit, pc, 0)); 2012 } else { 2013 return SOC_E_UNAVAIL; 2014 } 2015 break; 2016 2017 case SOC_PORT_MDIX_XOVER: 2018 SOC_IF_ERROR_RETURN(phy_54616_speed_get(unit, port, &speed)); 2019 if (speed == 0 || speed == 10 || speed == 100) { 2020 /* Set bit 14 for automatic MDI crossover */ 2021 SOC_IF_ERROR_RETURN 2022 (MODIFY_PHY54616_MII_ECRr(unit, pc, 0x4000, 0x4000)); 2023 2024 SOC_IF_ERROR_RETURN 2025 (WRITE_PHY54616_TEST1r(unit, pc, 0x0080)); 2026 } else { 2027 return SOC_E_UNAVAIL; 2028 } 2029 break; 2030 2031 default: 2032 return SOC_E_PARAM; 2033 } 2034 pc->copper.mdix = mode; 2035 } else { /* fiber */ 2036 if (mode != SOC_PORT_MDIX_NORMAL) { 2037 return SOC_E_UNAVAIL; 2038 } 2039 } 2040 return SOC_E_NONE; 2041 } 2042 2043 #if defined(BCM_WARM_BOOT_SUPPORT) 2044 /* 2045 * Function: 2046 * phy_54616_mdix_wb_update 2047 * Description: 2048 * Read the hw, derive the mode and update the mdix mode in sw structure 2049 * during wb. 2050 * Parameters: 2051 * unit - (IN) Device number 2052 * port - (IN) Port number 2053 * mode - (OUT) :One of: 2054 * SOC_PORT_MDIX_AUTO 2055 * Enable auto-MDIX when autonegotiation is enabled 2056 * SOC_PORT_MDIX_FORCE_AUTO 2057 * Enable auto-MDIX always 2058 * SOC_PORT_MDIX_NORMAL 2059 * Disable auto-MDIX 2060 * SOC_PORT_MDIX_XOVER 2061 * Disable auto-MDIX, and swap cable pairs 2062 * Return Value: 2063 * SOC_E_XXX 2064 */ 2065 STATIC int 2066 phy_54616_mdix_wb_update(int unit, soc_port_t port) 2067 { 2068 phy_ctrl_t *pc; 2069 int speed; 2070 int mode = 0; 2071 uint16 val = 0; 2072 2073 pc = EXT_PHY_SW_STATE(unit, port); 2074 2075 if (PHY_COPPER_MODE(unit, port)) { 2076 /* Check bit 14 for automatic MDI crossover */ 2077 SOC_IF_ERROR_RETURN (READ_PHY54616_MII_ECRr(unit, pc, &val)); 2078 if(val & 0x4000) { 2079 SOC_IF_ERROR_RETURN(phy_54616_speed_get(unit, port, &speed)); 2080 if (speed == 0 || speed == 10 || speed == 100) { 2081 SOC_IF_ERROR_RETURN (READ_PHY54616_TEST1r(unit, pc, &val)); 2082 if (0 == val) { 2083 mode = SOC_PORT_MDIX_NORMAL; 2084 } else if (0x80 == val) { 2085 mode = SOC_PORT_MDIX_XOVER; 2086 } else { 2087 return SOC_E_UNAVAIL; 2088 } 2089 } else { 2090 return SOC_E_UNAVAIL; 2091 } 2092 } else { 2093 /* Check bit 9 forced auto MDI xover */ 2094 SOC_IF_ERROR_RETURN (READ_PHY54616_MII_MISC_CTRLr(unit, pc,&val)); 2095 if (val & 0x200) { 2096 /* bit 9 Set, forced auto MDI xover */ 2097 mode = SOC_PORT_MDIX_FORCE_AUTO; 2098 } else { 2099 /* bit 9 Clear, forced auto MDI xover */ 2100 mode = SOC_PORT_MDIX_AUTO; 2101 } 2102 } 2103 pc->copper.mdix = mode; 2104 } else { 2105 /* fiber */ 2106 mode = SOC_PORT_MDIX_NORMAL; 2107 } 2108 return SOC_E_NONE; 2109 } 2110 #endif /* defined(BCM_WARM_BOOT_SUPPORT) */ 2111 2112 2113 /* 2114 * Function: 2115 * phy_54616_mdix_get 2116 * Description: 2117 * Get the Auto-MDIX mode of a port/PHY 2118 * Parameters: 2119 * unit - Device number 2120 * port - Port number 2121 * mode - (Out) One of: 2122 * SOC_PORT_MDIX_AUTO 2123 * Enable auto-MDIX when autonegotiation is enabled 2124 * SOC_PORT_MDIX_FORCE_AUTO 2125 * Enable auto-MDIX always 2126 * SOC_PORT_MDIX_NORMAL 2127 * Disable auto-MDIX 2128 * SOC_PORT_MDIX_XOVER 2129 * Disable auto-MDIX, and swap cable pairs 2130 * Return Value: 2131 * SOC_E_XXX 2132 */ 2133 STATIC int 2134 phy_54616_mdix_get(int unit, soc_port_t port, soc_port_mdix_t *mode) 2135 { 2136 phy_ctrl_t *pc; 2137 int speed; 2138 2139 if (mode == NULL) { 2140 return SOC_E_PARAM; 2141 } 2142 2143 #if defined(BCM_WARM_BOOT_SUPPORT) 2144 if (SOC_WARM_BOOT(unit)) { 2145 return phy_54616_mdix_wb_update(unit, port); 2146 } 2147 #endif /* defined(BCM_WARM_BOOT_SUPPORT) */ 2148 2149 pc = EXT_PHY_SW_STATE(unit, port); 2150 2151 if (PHY_COPPER_MODE(unit, port)) { 2152 SOC_IF_ERROR_RETURN(phy_54616_speed_get(unit, port, &speed)); 2153 if (speed == 1000) { 2154 *mode = SOC_PORT_MDIX_AUTO; 2155 } else { 2156 *mode = pc->copper.mdix; 2157 } 2158 } else { 2159 *mode = SOC_PORT_MDIX_NORMAL; 2160 } 2161 2162 return SOC_E_NONE; 2163 } 2164 2165 /* 2166 * Function: 2167 * phy_54616_mdix_status_get 2168 * Description: 2169 * Get the current MDIX status on a port/PHY 2170 * Parameters: 2171 * unit - Device number 2172 * port - Port number 2173 * status - (OUT) One of: 2174 * SOC_PORT_MDIX_STATUS_NORMAL 2175 * Straight connection 2176 * SOC_PORT_MDIX_STATUS_XOVER 2177 * Crossover has been performed 2178 * Return Value: 2179 * SOC_E_XXX 2180 */ 2181 STATIC int 2182 phy_54616_mdix_status_get(int unit, soc_port_t port, 2183 soc_port_mdix_status_t *status) 2184 { 2185 phy_ctrl_t *pc; 2186 uint16 data; 2187 2188 if (status == NULL) { 2189 return SOC_E_PARAM; 2190 } 2191 2192 pc = EXT_PHY_SW_STATE(unit, port); 2193 2194 if (PHY_COPPER_MODE(unit, port)) { 2195 SOC_IF_ERROR_RETURN 2196 (READ_PHY54616_MII_ESRr(unit, pc, &data)); 2197 if (data & 0x2000) { 2198 *status = SOC_PORT_MDIX_STATUS_XOVER; 2199 } else { 2200 *status = SOC_PORT_MDIX_STATUS_NORMAL; 2201 } 2202 } else { 2203 *status = SOC_PORT_MDIX_STATUS_NORMAL; 2204 } 2205 2206 return SOC_E_NONE; 2207 } 2208 2209 STATIC int 2210 _phy_54616_power_mode_set (int unit, soc_port_t port, int mode) 2211 { 2212 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 2213 2214 if (pc->power_mode == mode) { 2215 return SOC_E_NONE; 2216 } 2217 2218 /* Auto Power-Down Reg.0x1C, shadow 0x0A, bit[5] Auto Power Down Mode */ 2219 /* Autodetect Medium Reg.0x1C, shadow 0x1E, bit[5] Auto Fiber Power Mode */ 2220 if ( (mode == SOC_PHY_CONTROL_POWER_FULL) || 2221 (mode == SOC_PHY_CONTROL_POWER_AUTO_DISABLE) ) { 2222 /* disable the auto power mode */ 2223 SOC_IF_ERROR_RETURN( 2224 MODIFY_PHY54616_AUTO_POWER_DOWNr(unit,pc, 2225 0 , PHY_54616_AUTO_PWRDWN_EN) ); 2226 SOC_IF_ERROR_RETURN( 2227 MODIFY_PHY54616_AUTO_DETECT_MEDIUMr(unit,pc, 2228 0 , PHY_54616_FiBER_AUTO_PWRDWN_EN) ); 2229 } else if ( (mode == SOC_PHY_CONTROL_POWER_AUTO) || 2230 (mode == SOC_PHY_CONTROL_POWER_AUTO_FULL) ) { 2231 /* enable the auto power mode */ 2232 SOC_IF_ERROR_RETURN( 2233 MODIFY_PHY54616_AUTO_POWER_DOWNr(unit,pc, 2234 PHY_54616_AUTO_PWRDWN_EN, 2235 PHY_54616_AUTO_PWRDWN_EN) ); 2236 SOC_IF_ERROR_RETURN( 2237 MODIFY_PHY54616_AUTO_DETECT_MEDIUMr(unit,pc, 2238 PHY_54616_FiBER_AUTO_PWRDWN_EN, 2239 PHY_54616_FiBER_AUTO_PWRDWN_EN) ); 2240 } /* support only FULL & AUTO, discard POWER_LOW & POWER_AUTO_LOW modes */ 2241 2242 pc->power_mode = mode; 2243 return SOC_E_NONE; 2244 } 2245 2246 /* 2247 * Function: 2248 * _phy_54618_eee_enable 2249 * Purpose: 2250 * Enable or disable EEE (Native) 2251 * Parameters: 2252 * unit - StrataSwitch unit #. 2253 * port - StrataSwitch port #. 2254 * enable - Enable Native EEE 2255 * Returns: 2256 * SOC_E_NONE 2257 */ 2258 STATIC int 2259 _phy_54618_eee_enable(int unit, soc_port_t port, int enable) 2260 { 2261 phy_ctrl_t *pc; 2262 2263 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2264 return SOC_E_UNAVAIL; 2265 } 2266 pc = EXT_PHY_SW_STATE(unit, port); 2267 2268 if ( enable == 1 ) { 2269 SOC_IF_ERROR_RETURN 2270 (MODIFY_PHY54618_EEE_CTRLr(unit, pc, 0x8000, 0x8000)); /* 7.803d enable EEE */ 2271 SOC_IF_ERROR_RETURN 2272 (MODIFY_PHY54618_EEE_ADVr(unit, pc, 0x0006, 0x0006)); 2273 pc->copper.advert_ability.eee |= (SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX); 2274 2275 SOC_IF_ERROR_RETURN /* native mode, disable AutogrEEEn */ 2276 (MODIFY_PHY54618_EEE_AUTOEEECTRLr(unit, pc, 0x0000, 0x0001)); 2277 SOC_IF_ERROR_RETURN(PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x1, 0x1)); /* exp af */ 2278 } else { /* enable==0 */ 2279 SOC_IF_ERROR_RETURN(PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 0x1)); /* exp af */ 2280 pc->copper.advert_ability.eee &= ~(SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX); 2281 SOC_IF_ERROR_RETURN 2282 (MODIFY_PHY54618_EEE_ADVr(unit, pc, 0x0000, 0x0006)); 2283 SOC_IF_ERROR_RETURN 2284 (MODIFY_PHY54618_EEE_CTRLr(unit, pc, 0x0000, 0x8000)); /* 7.803d disable EEE */ 2285 } 2286 2287 return SOC_E_NONE; 2288 } 2289 2290 /* 2291 * Function: 2292 * _phy_54618_eee_auto_enable 2293 * Purpose: 2294 * Enable or disable EEE (Native) 2295 * Parameters: 2296 * unit - StrataSwitch unit #. 2297 * port - StrataSwitch port #. 2298 * enable - Enable Native EEE 2299 * Returns: 2300 * SOC_E_NONE 2301 */ 2302 STATIC int 2303 _phy_54618_eee_auto_enable(int unit, soc_port_t port, int enable) 2304 { 2305 phy_ctrl_t *pc; 2306 2307 if ( ! PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE) ) { 2308 return SOC_E_UNAVAIL; 2309 } 2310 pc = EXT_PHY_SW_STATE(unit, port); 2311 2312 if ( enable == 1 ) { 2313 SOC_IF_ERROR_RETURN 2314 (MODIFY_PHY54618_EEE_CTRLr(unit, pc, 0x8000, 0x8000)); /* 7.803d enable EEE */ 2315 SOC_IF_ERROR_RETURN 2316 (MODIFY_PHY54618_EEE_ADVr(unit, pc, 0x0006, 0x0006)); 2317 pc->copper.advert_ability.eee |= (SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX); 2318 2319 SOC_IF_ERROR_RETURN /* enable AutogrEEEn */ 2320 (MODIFY_PHY54618_EEE_AUTOEEECTRLr(unit, pc, 0x0001, 0x0001)); 2321 SOC_IF_ERROR_RETURN(PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x1, 0x1)); /* exp af */ 2322 } else { /*enable == 0 */ 2323 SOC_IF_ERROR_RETURN(PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 0x3)); /* exp af */ 2324 pc->copper.advert_ability.eee &= ~(SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX); 2325 SOC_IF_ERROR_RETURN 2326 (MODIFY_PHY54618_EEE_ADVr(unit, pc, 0x0000, 0x0006)); 2327 SOC_IF_ERROR_RETURN 2328 (MODIFY_PHY54618_EEE_CTRLr(unit, pc, 0x0000, 0x8000)); /* 7.803d disable EEE */ 2329 } 2330 2331 return SOC_E_NONE; 2332 } 2333 2334 2335 /* 2336 * Function: 2337 * phy_54616_control_set 2338 * Purpose: 2339 * Configure PHY device specific control fucntion. 2340 * Parameters: 2341 * unit - StrataSwitch unit #. 2342 * port - StrataSwitch port #. 2343 * type - Control to update 2344 * value - New setting for the control 2345 * Returns: 2346 * SOC_E_NONE 2347 */ 2348 STATIC int 2349 phy_54616_control_set(int unit, soc_port_t port, 2350 soc_phy_control_t type, uint32 value) 2351 { 2352 int rv; 2353 phy_ctrl_t *pc; 2354 uint16 data16; 2355 int saved_autoneg; 2356 2357 PHY_CONTROL_TYPE_CHECK(type); 2358 2359 pc = EXT_PHY_SW_STATE(unit, port); 2360 rv = SOC_E_NONE; 2361 2362 switch(type) { 2363 case SOC_PHY_CONTROL_CLOCK_ENABLE: 2364 if ( PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) { 2365 /* RXC SyncE on/off. Expansion Register 0Eh, bit[4] */ 2366 SOC_IF_ERROR_RETURN 2367 (MODIFY_PHY54616_EXP_SYNCE_CTRLr(unit, pc, 2368 value ? (1U << 4) : 0, 1U << 4)); 2369 } 2370 else if ( pc->phy_rev == 0xB ) { /* BCM54616 Rev.B only */ 2371 SOC_IF_ERROR_RETURN 2372 (WRITE_PHY54616_EXP_SGMII_REC_CTRLr(unit, pc, 2373 value ? (1U << 4) : 0)); 2374 } 2375 break; 2376 2377 case SOC_PHY_CONTROL_CLOCK_SECONDARY_ENABLE: 2378 if ( PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) { 2379 /* CLK125 SyncE on/off. Top-Level Expansion Reg. 34h, bit[3] */ 2380 SOC_IF_ERROR_RETURN 2381 (MODIFY_PHY54616_TOPLVL_CLK125_ADCr(unit, pc, 2382 value ? (1U << 3) : 0, 1U << 3)); 2383 } 2384 break; 2385 2386 case SOC_PHY_CONTROL_POWER: 2387 rv = _phy_54616_power_mode_set(unit,port,value); 2388 break; 2389 2390 case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME: 2391 if (value <= PHY_54616_AUTO_PWRDWN_WAKEUP_MAX) { 2392 2393 /* at least one unit */ 2394 if (value < PHY_54616_AUTO_PWRDWN_WAKEUP_UNIT) { 2395 value = PHY_54616_AUTO_PWRDWN_WAKEUP_UNIT; 2396 } 2397 } else { /* anything more then max, set to the max */ 2398 value = PHY_54616_AUTO_PWRDWN_WAKEUP_MAX; 2399 } 2400 SOC_IF_ERROR_RETURN 2401 (MODIFY_PHY54616_AUTO_POWER_DOWNr(unit,pc, 2402 value/PHY_54616_AUTO_PWRDWN_WAKEUP_UNIT, 2403 PHY_54616_AUTO_PWRDWN_WAKEUP_MASK)); 2404 break; 2405 2406 case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME: 2407 /* sleep time configuration is either 2.7s or 5.4 s, default is 2.7s */ 2408 if (value < PHY_54616_AUTO_PWRDWN_SLEEP_MAX) { 2409 data16 = 0; /* anything less than 5.4s, default to 2.7s */ 2410 } else { 2411 data16 = PHY_54616_AUTO_PWRDWN_SLEEP_MASK; 2412 } 2413 SOC_IF_ERROR_RETURN 2414 (MODIFY_PHY54616_AUTO_POWER_DOWNr(unit,pc, 2415 data16, 2416 PHY_54616_AUTO_PWRDWN_SLEEP_MASK)); 2417 break; 2418 2419 case SOC_PHY_CONTROL_EEE: 2420 if ( ! PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE) ) { 2421 rv = SOC_E_UNAVAIL; 2422 } 2423 2424 if (value == 1) { 2425 /* Enable Native EEE */ 2426 SOC_IF_ERROR_RETURN 2427 (_phy_54618_eee_enable(unit, port, 1)); 2428 saved_autoneg = pc->copper.autoneg_enable; 2429 /* Initiate AN */ 2430 SOC_IF_ERROR_RETURN 2431 (phy_54616_autoneg_set(unit, port, 1)); /* must AN=on for EEE */ 2432 pc->copper.autoneg_enable = saved_autoneg; 2433 PHY_FLAGS_SET(unit, pc->port, PHY_FLAGS_EEE_ENABLED); 2434 PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_MODE); /* nativeEEE */ 2435 } else { 2436 SOC_IF_ERROR_RETURN 2437 (_phy_54618_eee_enable(unit, port, 0)); 2438 /* Initiate AN if administratively enabled */ 2439 SOC_IF_ERROR_RETURN 2440 (phy_54616_autoneg_set(unit, port, pc->copper.autoneg_enable ? 1 : 0)); 2441 PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_ENABLED); 2442 } 2443 break; 2444 2445 case SOC_PHY_CONTROL_EEE_AUTO: 2446 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2447 rv = SOC_E_UNAVAIL; 2448 } 2449 2450 if (value == 1) { 2451 /* Disable Native EEE */ 2452 SOC_IF_ERROR_RETURN 2453 (_phy_54618_eee_enable(unit, port, 0)); 2454 /* Enable Auto EEE */ 2455 SOC_IF_ERROR_RETURN 2456 (_phy_54618_eee_auto_enable(unit, port, 1)); 2457 saved_autoneg = pc->copper.autoneg_enable; 2458 /* Initiate AN */ 2459 SOC_IF_ERROR_RETURN 2460 (phy_54616_autoneg_set(unit, port, 1)); 2461 pc->copper.autoneg_enable = saved_autoneg; 2462 PHY_FLAGS_SET(unit, pc->port, PHY_FLAGS_EEE_ENABLED); 2463 PHY_FLAGS_SET(unit, pc->port, PHY_FLAGS_EEE_MODE); /* autoEEE */ 2464 } else { 2465 /* Disable Auto EEE */ 2466 SOC_IF_ERROR_RETURN 2467 (_phy_54618_eee_auto_enable(unit, port, 0)); 2468 /* Initiate AN if administratively enabled */ 2469 SOC_IF_ERROR_RETURN 2470 (phy_54616_autoneg_set(unit, port, pc->copper.autoneg_enable ? 1 : 0)); 2471 PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_ENABLED); 2472 } 2473 break; 2474 2475 case SOC_PHY_CONTROL_EEE_AUTO_IDLE_THRESHOLD: 2476 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2477 rv = SOC_E_UNAVAIL; 2478 } 2479 2480 if (value > 7) { /* Values needs to between 0 to 7 (inclusive) */ 2481 rv = SOC_E_CONFIG; 2482 } 2483 2484 SOC_IF_ERROR_RETURN 2485 (MODIFY_PHY54618_EEE_AUTOEEECTRLr(unit, pc, value<<8, 0x0700)); 2486 /* Setting GPHY core, MII buffer register as well */ 2487 SOC_IF_ERROR_RETURN 2488 (MODIFY_PHY54618_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 2489 value<<8, 0x0700)); 2490 break; 2491 2492 case SOC_PHY_CONTROL_EEE_AUTO_FIXED_LATENCY: 2493 if ( ! PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE) ) { 2494 rv = SOC_E_UNAVAIL; 2495 } 2496 /* Fixed latency can have only 0 or 1 value */ 2497 if ((value != FALSE) && (value != TRUE)) { 2498 return SOC_E_PARAM; 2499 } 2500 if ( value == FALSE ) { 2501 /* Sets Variable Latency */ 2502 SOC_IF_ERROR_RETURN 2503 (MODIFY_PHY54618_EEE_AUTOEEECTRLr(unit, pc, 0x0004, 0x0004)); 2504 /* Setting GPHY core, MII buffer register as well */ 2505 SOC_IF_ERROR_RETURN 2506 (MODIFY_PHY54618_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 2507 0x0004, 0x0004)); 2508 } else { 2509 /* Sets Fixed Latency */ 2510 SOC_IF_ERROR_RETURN 2511 (MODIFY_PHY54618_EEE_AUTOEEECTRLr(unit, pc, 0x0000, 0x0004)); 2512 /* Setting GPHY core, MII buffer register as well */ 2513 SOC_IF_ERROR_RETURN 2514 (MODIFY_PHY54618_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 2515 0x0000, 0x0004)); 2516 } 2517 break; 2518 2519 case SOC_PHY_CONTROL_EEE_AUTO_BUFFER_LIMIT: 2520 /* Buffer limit modification is not allowed */ 2521 case SOC_PHY_CONTROL_EEE_TRANSMIT_WAKE_TIME: 2522 case SOC_PHY_CONTROL_EEE_RECEIVE_WAKE_TIME: 2523 case SOC_PHY_CONTROL_EEE_TRANSMIT_SLEEP_TIME: 2524 case SOC_PHY_CONTROL_EEE_RECEIVE_SLEEP_TIME: 2525 case SOC_PHY_CONTROL_EEE_TRANSMIT_QUIET_TIME: 2526 case SOC_PHY_CONTROL_EEE_RECEIVE_QUIET_TIME: 2527 case SOC_PHY_CONTROL_EEE_TRANSMIT_REFRESH_TIME: 2528 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2529 rv = SOC_E_UNAVAIL; 2530 } 2531 2532 /* Time modification not allowed, IEEE EEE spec constants */ 2533 rv = SOC_E_UNAVAIL; 2534 break; 2535 2536 case SOC_PHY_CONTROL_EEE_STATISTICS_CLEAR: 2537 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2538 rv = SOC_E_UNAVAIL; 2539 } 2540 2541 if (value == 1) { 2542 /* Clearing the stats: Enable clear on Read */ 2543 SOC_IF_ERROR_RETURN 2544 (MODIFY_PHY54618_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 2545 0x1000, 0x1000)); 2546 /* Read all the stats to clear */ 2547 SOC_IF_ERROR_RETURN 2548 (READ_PHY54618_EXP_EEE_TX_EVENTSr(unit, pc, &data16)); 2549 SOC_IF_ERROR_RETURN 2550 (READ_PHY54618_EXP_EEE_TX_EVENTSr(unit, pc, &data16)); 2551 SOC_IF_ERROR_RETURN 2552 (READ_PHY54618_EXP_EEE_TX_DURATIONr(unit, pc, &data16)); 2553 SOC_IF_ERROR_RETURN 2554 (READ_PHY54618_EXP_EEE_TX_DURATIONr(unit, pc, &data16)); 2555 SOC_IF_ERROR_RETURN 2556 (READ_PHY54618_EXP_EEE_RX_EVENTSr(unit, pc, &data16)); 2557 SOC_IF_ERROR_RETURN 2558 (READ_PHY54618_EXP_EEE_RX_EVENTSr(unit, pc, &data16)); 2559 SOC_IF_ERROR_RETURN 2560 (READ_PHY54618_EXP_EEE_RX_DURATIONr(unit, pc, &data16)); 2561 SOC_IF_ERROR_RETURN 2562 (READ_PHY54618_EXP_EEE_RX_DURATIONr(unit, pc, &data16)); 2563 2564 /* Disable Clear on Read */ 2565 SOC_IF_ERROR_RETURN 2566 (MODIFY_PHY54618_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 2567 0x0000, 0x1000)); 2568 } 2569 2570 break; 2571 2572 default: 2573 rv = SOC_E_UNAVAIL; 2574 break; 2575 } 2576 return rv; 2577 } 2578 2579 /* 2580 * Function: 2581 * phy_54616_control_get 2582 * Purpose: 2583 * Get current control settign of the PHY. 2584 * Parameters: 2585 * unit - StrataSwitch unit #. 2586 * port - StrataSwitch port #. 2587 * type - Control to update 2588 * value - (OUT)Current setting for the control 2589 * Returns: 2590 * SOC_E_NONE 2591 */ 2592 STATIC int 2593 phy_54616_control_get(int unit, soc_port_t port, 2594 soc_phy_control_t type, uint32 *value) 2595 { 2596 int rv; 2597 phy_ctrl_t *pc; 2598 uint16 data; 2599 uint32 temp; 2600 2601 PHY_CONTROL_TYPE_CHECK(type); 2602 2603 pc = EXT_PHY_SW_STATE(unit, port); 2604 rv = SOC_E_NONE; 2605 2606 switch(type) { 2607 case SOC_PHY_CONTROL_CLOCK_ENABLE: 2608 if ( PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) { 2609 /* RXC SyncE on/off. Expansion Register 0Eh, bit[4] */ 2610 SOC_IF_ERROR_RETURN 2611 (READ_PHY54616_EXP_SYNCE_CTRLr(unit, pc, &data)); 2612 *value = (data & (1U << 4)) ? TRUE : FALSE; 2613 } 2614 else if ( pc->phy_rev == 0xB ) { /* BCM54616 Rev.B only */ 2615 SOC_IF_ERROR_RETURN 2616 (READ_PHY54616_EXP_SGMII_REC_CTRLr(unit, pc, &data)); 2617 *value = (data & (1U << 4)) ? TRUE : FALSE; 2618 } 2619 break; 2620 2621 case SOC_PHY_CONTROL_CLOCK_SECONDARY_ENABLE: 2622 if ( PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) { 2623 /* CLK125 SyncE on/off. Top-Level Expansion Reg. 34h, bit[3] */ 2624 SOC_IF_ERROR_RETURN 2625 (READ_PHY54616_TOPLVL_CLK125_ADCr(unit, pc, &data)); 2626 *value = (*value || (data & (1U << 3))) ? TRUE : FALSE; 2627 } 2628 break; 2629 2630 case SOC_PHY_CONTROL_POWER: 2631 *value = pc->power_mode; 2632 break; 2633 2634 case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME: 2635 SOC_IF_ERROR_RETURN 2636 (READ_PHY54616_AUTO_POWER_DOWNr(unit,pc, &data)); 2637 2638 if (data & PHY_54616_AUTO_PWRDWN_SLEEP_MASK) { 2639 *value = PHY_54616_AUTO_PWRDWN_SLEEP_MAX; 2640 } else { 2641 *value = 2700; 2642 } 2643 break; 2644 2645 case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME: 2646 SOC_IF_ERROR_RETURN 2647 (READ_PHY54616_AUTO_POWER_DOWNr(unit,pc, &data)); 2648 2649 data &= PHY_54616_AUTO_PWRDWN_WAKEUP_MASK; 2650 *value = data * PHY_54616_AUTO_PWRDWN_WAKEUP_UNIT; 2651 break; 2652 2653 case SOC_PHY_CONTROL_EEE: 2654 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2655 rv = SOC_E_UNAVAIL; 2656 } 2657 *value = (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_ENABLED) && 2658 !PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_MODE)) ? 1 : 0; 2659 break; 2660 2661 case SOC_PHY_CONTROL_EEE_AUTO: 2662 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2663 rv = SOC_E_UNAVAIL; 2664 } 2665 *value = (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_ENABLED) && 2666 PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_MODE)) ? 1 : 0; 2667 break; 2668 2669 case SOC_PHY_CONTROL_EEE_AUTO_FIXED_LATENCY: 2670 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2671 rv = SOC_E_UNAVAIL; 2672 } 2673 SOC_IF_ERROR_RETURN 2674 (READ_PHY54618_EXP_MII_BUF_CNTL_STAT1r(unit, pc, &data)); 2675 *value = ((data & 0x0004) != 0); 2676 break; 2677 2678 case SOC_PHY_CONTROL_EEE_AUTO_IDLE_THRESHOLD: 2679 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2680 rv = SOC_E_UNAVAIL; 2681 } 2682 SOC_IF_ERROR_RETURN 2683 (READ_PHY54618_EXP_MII_BUF_CNTL_STAT1r(unit, pc, &data)); 2684 *value = ((data & 0x0700) >> 8); 2685 break; 2686 2687 case SOC_PHY_CONTROL_EEE_TRANSMIT_EVENTS: 2688 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2689 rv = SOC_E_UNAVAIL; 2690 } 2691 SOC_IF_ERROR_RETURN 2692 (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */ 2693 SOC_IF_ERROR_RETURN 2694 (READ_PHY54618_EXP_EEE_TX_EVENTSr(unit, pc, &data)); 2695 temp = data; 2696 SOC_IF_ERROR_RETURN 2697 (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */ 2698 SOC_IF_ERROR_RETURN 2699 (READ_PHY54618_EXP_EEE_TX_EVENTSr(unit, pc, &data)); 2700 temp |= (data << 16); 2701 *value = temp; 2702 2703 break; 2704 2705 case SOC_PHY_CONTROL_EEE_TRANSMIT_DURATION: 2706 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2707 rv = SOC_E_UNAVAIL; 2708 } 2709 SOC_IF_ERROR_RETURN 2710 (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */ 2711 SOC_IF_ERROR_RETURN 2712 (READ_PHY54618_EXP_EEE_TX_DURATIONr(unit, pc, &data)); 2713 temp = data; 2714 SOC_IF_ERROR_RETURN 2715 (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */ 2716 SOC_IF_ERROR_RETURN 2717 (READ_PHY54618_EXP_EEE_TX_DURATIONr(unit, pc, &data)); 2718 temp |= (data << 16); 2719 *value = temp; 2720 2721 break; 2722 2723 case SOC_PHY_CONTROL_EEE_RECEIVE_EVENTS: 2724 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2725 rv = SOC_E_UNAVAIL; 2726 } 2727 SOC_IF_ERROR_RETURN 2728 (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */ 2729 SOC_IF_ERROR_RETURN 2730 (READ_PHY54618_EXP_EEE_RX_EVENTSr(unit, pc, &data)); 2731 temp = data; 2732 SOC_IF_ERROR_RETURN 2733 (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */ 2734 SOC_IF_ERROR_RETURN 2735 (READ_PHY54618_EXP_EEE_RX_EVENTSr(unit, pc, &data)); 2736 temp |= (data << 16); 2737 *value = temp; 2738 2739 break; 2740 2741 case SOC_PHY_CONTROL_EEE_RECEIVE_DURATION: 2742 if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { 2743 rv = SOC_E_UNAVAIL; 2744 } 2745 SOC_IF_ERROR_RETURN 2746 (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */ 2747 SOC_IF_ERROR_RETURN 2748 (READ_PHY54618_EXP_EEE_RX_DURATIONr(unit, pc, &data)); 2749 temp = data; 2750 SOC_IF_ERROR_RETURN 2751 (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */ 2752 SOC_IF_ERROR_RETURN 2753 (READ_PHY54618_EXP_EEE_RX_DURATIONr(unit, pc, &data)); 2754 temp |= (data << 16); 2755 *value = temp; 2756 break; 2757 2758 2759 default: 2760 rv = SOC_E_UNAVAIL; 2761 break; 2762 } 2763 return rv; 2764 } 2765 2766 /* 2767 * Function: 2768 * phy_54616_cable_diag 2769 * Purpose: 2770 * Run 546x cable diagnostics 2771 * Parameters: 2772 * unit - device number 2773 * port - port number 2774 * status - (OUT) cable diagnotic status structure 2775 * Returns: 2776 * SOC_E_XXX 2777 */ 2778 STATIC int 2779 phy_54616_cable_diag(int unit, soc_port_t port, 2780 soc_port_cable_diag_t *status) 2781 { 2782 int rv=SOC_E_NONE, rv2, i; 2783 2784 extern int phy_5464_cable_diag_sw(int, soc_port_t , 2785 soc_port_cable_diag_t *); 2786 2787 if (status == NULL) { 2788 return SOC_E_PARAM; 2789 } 2790 2791 status->state = SOC_PORT_CABLE_STATE_OK; 2792 status->npairs = 4; 2793 status->fuzz_len = 0; 2794 for (i = 0; i < 4; i++) { 2795 status->pair_state[i] = SOC_PORT_CABLE_STATE_OK; 2796 } 2797 2798 MIIM_LOCK(unit); /* this locks out linkscan, essentially */ 2799 rv = phy_5464_cable_diag_sw(unit,port, status); 2800 MIIM_UNLOCK(unit); 2801 rv2 = 0; 2802 if (rv <= 0) { /* don't reset if > 0 -- link was up */ 2803 rv2 = _phy_54616_reset_setup(unit, port); 2804 } 2805 if (rv >= 0 && rv2 < 0) { 2806 return rv2; 2807 } 2808 return rv; 2809 } 2810 2811 /*---------------- BCM54618SE TimeSync support ----------------------------------*/ 2812 2813 void _phy_54618e_encode_egress_message_mode(soc_port_phy_timesync_event_message_egress_mode_t mode, 2814 int offset, uint16 *value) 2815 { 2816 switch ( mode ) { 2817 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_NONE: 2818 *value |= (0x0 << offset); 2819 break; 2820 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_UPDATE_CORRECTIONFIELD: 2821 *value |= (0x1 << offset); 2822 break; 2823 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_REPLACE_CORRECTIONFIELD_ORIGIN: 2824 *value |= (0x2 << offset); 2825 break; 2826 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_CAPTURE_TIMESTAMP: 2827 *value |= (0x3 << offset); 2828 break; 2829 default: 2830 break; 2831 } 2832 } 2833 2834 void _phy_54618e_encode_ingress_message_mode(soc_port_phy_timesync_event_message_ingress_mode_t mode, 2835 int offset, uint16 *value) 2836 { 2837 switch ( mode ) { 2838 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_NONE: 2839 *value |= (0x0 << offset); 2840 break; 2841 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_UPDATE_CORRECTIONFIELD: 2842 *value |= (0x1 << offset); 2843 break; 2844 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_TIMESTAMP: 2845 *value |= (0x2 << offset); 2846 break; 2847 case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_DELAYTIME: 2848 *value |= (0x3 << offset); 2849 break; 2850 default: 2851 break; 2852 } 2853 } 2854 2855 void _phy_54618e_decode_egress_message_mode(uint16 value, int offset, 2856 soc_port_phy_timesync_event_message_egress_mode_t *mode) 2857 { 2858 switch ( (value >> offset) & 0x3 ) { 2859 case 0x0: 2860 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_NONE; 2861 break; 2862 case 0x1: 2863 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_UPDATE_CORRECTIONFIELD; 2864 break; 2865 case 0x2: 2866 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_REPLACE_CORRECTIONFIELD_ORIGIN; 2867 break; 2868 case 0x3: 2869 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_CAPTURE_TIMESTAMP; 2870 break; 2871 } 2872 } 2873 2874 void _phy_54618e_decode_ingress_message_mode(uint16 value, int offset, 2875 soc_port_phy_timesync_event_message_ingress_mode_t *mode) 2876 { 2877 switch ( (value >> offset) & 0x3 ) { 2878 case 0x0: 2879 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_NONE; 2880 break; 2881 case 0x1: 2882 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_UPDATE_CORRECTIONFIELD; 2883 break; 2884 case 0x2: 2885 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_TIMESTAMP; 2886 break; 2887 case 0x3: 2888 *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_DELAYTIME; 2889 break; 2890 } 2891 } 2892 2893 void _phy_54618e_encode_gmode(soc_port_phy_timesync_global_mode_t mode, 2894 uint16 *value) 2895 { 2896 switch ( mode ) { 2897 case SOC_PORT_PHY_TIMESYNC_MODE_FREE: 2898 *value = 0x1; 2899 break; 2900 case SOC_PORT_PHY_TIMESYNC_MODE_SYNCIN: 2901 *value = 0x2; 2902 break; 2903 case SOC_PORT_PHY_TIMESYNC_MODE_CPU: 2904 *value = 0x3; 2905 break; 2906 default: 2907 break; 2908 } 2909 } 2910 2911 void _phy_54618e_decode_gmode(uint16 value, 2912 soc_port_phy_timesync_global_mode_t *mode) 2913 { 2914 switch ( value & 0x3 ) { 2915 case 0x1: 2916 *mode = SOC_PORT_PHY_TIMESYNC_MODE_FREE; 2917 break; 2918 case 0x2: 2919 *mode = SOC_PORT_PHY_TIMESYNC_MODE_SYNCIN; 2920 break; 2921 case 0x3: 2922 *mode = SOC_PORT_PHY_TIMESYNC_MODE_CPU; 2923 break; 2924 default: 2925 break; 2926 } 2927 } 2928 2929 void _phy_54618e_encode_framesync_mode(soc_port_phy_timesync_framesync_mode_t mode, 2930 uint16 *value) 2931 { 2932 switch ( mode ) { 2933 case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN0: 2934 *value = 1U << 0; 2935 break; 2936 case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN1: 2937 *value = 1U << 1; 2938 break; 2939 case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCOUT: 2940 *value = 1U << 2; 2941 break; 2942 case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_CPU: 2943 *value = 1U << 3; 2944 break; 2945 default: 2946 break; 2947 } 2948 } 2949 2950 void _phy_54618e_decode_framesync_mode(uint16 value, 2951 soc_port_phy_timesync_framesync_mode_t *mode) 2952 { 2953 switch ( value & 0xf ) { 2954 case 1U << 0: 2955 *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN0; 2956 break; 2957 case 1U << 1: 2958 *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN1; 2959 break; 2960 case 1U << 2: 2961 *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCOUT; 2962 break; 2963 case 1U << 3: 2964 *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_CPU; 2965 break; 2966 default: 2967 break; 2968 } 2969 } 2970 2971 void _phy_54618e_encode_syncout_mode(soc_port_phy_timesync_syncout_mode_t mode, 2972 uint16 *value) 2973 { 2974 switch ( mode ) { 2975 case SOC_PORT_PHY_TIMESYNC_SYNCOUT_DISABLE: 2976 *value = 0x0; 2977 break; 2978 case SOC_PORT_PHY_TIMESYNC_SYNCOUT_ONE_TIME: 2979 *value = 0x1; 2980 break; 2981 case SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN: 2982 *value = 0x2; 2983 break; 2984 case SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN_WITH_SYNC: 2985 *value = 0x3; 2986 break; 2987 default: 2988 break; 2989 } 2990 } 2991 2992 void _phy_54618e_decode_syncout_mode(uint16 value, 2993 soc_port_phy_timesync_syncout_mode_t *mode) 2994 { 2995 switch ( value & 0x3 ) { 2996 case 0x0: 2997 *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_DISABLE; 2998 break; 2999 case 0x1: 3000 *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_ONE_TIME; 3001 break; 3002 case 0x2: 3003 *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN; 3004 break; 3005 case 0x3: 3006 *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN_WITH_SYNC; 3007 break; 3008 } 3009 } 3010 3011 STATIC int 3012 phy_54618_timesync_config_set(int unit, soc_port_t port, 3013 soc_port_phy_timesync_config_t *conf) 3014 { 3015 phy_ctrl_t *pc; 3016 int rv = SOC_E_NONE; 3017 uint16 rx_control_reg = 0, tx_control_reg = 0, rx_crc_control_reg = 0, 3018 en_control_reg = 0, tx_capture_en_reg = 0, rx_capture_en_reg = 0, 3019 nse_nco_6 = 0, nse_nco_2c = 0, value, mask, 3020 gmode = 0, framesync_mode = 0, syncout_mode = 0, 3021 pulse_1_length, pulse_2_length, length_threshold, event_offset; 3022 uint32 interval; 3023 3024 pc = EXT_PHY_SW_STATE(unit, port); 3025 3026 if ( ! PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) { 3027 return SOC_E_UNAVAIL; 3028 } 3029 3030 do { 3031 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FLAGS) { 3032 3033 if (conf->flags & SOC_PORT_PHY_TIMESYNC_ENABLE) { 3034 en_control_reg |= ((1U << 1) | (1U << 0)); 3035 nse_nco_6 |= (1U << 12); /* NSE init */ 3036 } 3037 3038 /* Top-Level Expansion Reg. 00h[1:0] IEEE 1588 Slice Enable Control */ 3039 SOC_IF_ERROR_BREAK 3040 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x00, en_control_reg, 3041 0x3), rv); 3042 /* Top-Level Expansion Reg. 03h[1:0] 1588 TX/RX SOP Timestamp Capture Enable */ 3043 if (conf->flags & SOC_PORT_PHY_TIMESYNC_CAPTURE_TS_ENABLE) { 3044 tx_capture_en_reg |= (1U << 0); 3045 rx_capture_en_reg |= (1U << 1); 3046 } 3047 SOC_IF_ERROR_BREAK 3048 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x03, 3049 (tx_capture_en_reg | rx_capture_en_reg), 0x3), rv); 3050 3051 /* Top-Level Expansion Register 31h[13:12] NSE NCO Register 6 */ 3052 if (conf->flags & SOC_PORT_PHY_TIMESYNC_HEARTBEAT_TS_ENABLE) { 3053 nse_nco_6 |= (1U << 13); /* TS_CAPTURE */ 3054 } 3055 SOC_IF_ERROR_BREAK 3056 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x31, nse_nco_6, 3057 (0x3U << 12)), rv); 3058 3059 /* Top-Level Expansion Register 14h: IEEE 1588 Tx/Rx CRC control register */ 3060 if (conf->flags & SOC_PORT_PHY_TIMESYNC_RX_CRC_ENABLE) { 3061 rx_crc_control_reg |= (1U << 3); 3062 } 3063 SOC_IF_ERROR_BREAK 3064 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x14, rx_crc_control_reg), rv); 3065 3066 /* Top-Level Expansion Register 12h: IEEE 1588 Transmit/Receive Control Register */ 3067 if (conf->flags & SOC_PORT_PHY_TIMESYNC_8021AS_ENABLE) { 3068 rx_control_reg |= (1U << 3); /* RX_AS_EN */ 3069 tx_control_reg |= (1U << 3); /* TX_AS_EN */ 3070 } 3071 3072 if (conf->flags & SOC_PORT_PHY_TIMESYNC_L2_ENABLE) { 3073 rx_control_reg |= (1U << 2); /* RX_L2_EN */ 3074 tx_control_reg |= (1U << 2); /* TX_L2_EN */ 3075 } 3076 3077 if (conf->flags & SOC_PORT_PHY_TIMESYNC_IP4_ENABLE) { 3078 rx_control_reg |= (1U << 1); /* RX_IPV4_UDP_EN */ 3079 tx_control_reg |= (1U << 1); /* TX_IPV4_UDP_EN */ 3080 } 3081 3082 if (conf->flags & SOC_PORT_PHY_TIMESYNC_IP6_ENABLE) { 3083 rx_control_reg |= (1U << 0); /* RX_IPV6_UDP_EN */ 3084 tx_control_reg |= (1U << 0); /* TX_IPV6_UDP_EN */ 3085 } 3086 3087 /* Top-Level Expansion Register 12h: IEEE 1588 Tx/Rx Control Register */ 3088 SOC_IF_ERROR_BREAK /* Rx[15:8] , Tx[7:0] */ 3089 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x12, 3090 ((rx_control_reg << 8) | tx_control_reg)), rv); 3091 3092 /* Top-Level Expansion Register 26h[14] NSE NCO Register 2-1 */ 3093 if (conf->flags & SOC_PORT_PHY_TIMESYNC_CLOCK_SRC_EXT) { 3094 nse_nco_2c &= (uint16) ~(1U << 14); 3095 } else { 3096 nse_nco_2c |= (1U << 14); 3097 } 3098 SOC_IF_ERROR_BREAK /* FREQ_mdio_sel[14] */ 3099 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x26, nse_nco_2c, 3100 (1U << 14)), rv); 3101 } 3102 3103 /* Top-Level Expansion Register 15h: VLAN1 Tags ITPID Register */ 3104 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ITPID) { 3105 SOC_IF_ERROR_BREAK 3106 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x15, conf->itpid), rv); 3107 } 3108 3109 /* Top-Level Expansion Register 16h: VLAN2 Tags OTPID Register */ 3110 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID) { 3111 SOC_IF_ERROR_BREAK 3112 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x16, conf->otpid), rv); 3113 } 3114 3115 /* Top-Level Expansion Register 17h: VLAN2 Tags OTPID2 Register */ 3116 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID2) { 3117 SOC_IF_ERROR_BREAK 3118 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x17, conf->otpid2), rv); 3119 } 3120 3121 /* Top-Level Expansion Register 2Dh[11:0] NCO Register 4, nse_reg_ts_divider */ 3122 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TS_DIVIDER) { 3123 SOC_IF_ERROR_BREAK 3124 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x2d, conf->ts_divider & 0xfff), rv); 3125 } 3126 3127 /* Top-Level Expansion Register 5Ch/5Dh: Linkdelay1/2 */ 3128 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_LINK_DELAY) { 3129 SOC_IF_ERROR_BREAK 3130 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x5c, conf->rx_link_delay & 0xffff), rv); 3131 SOC_IF_ERROR_BREAK 3132 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x5d, (conf->rx_link_delay >> 16) & 0xffff), rv); 3133 } 3134 3135 /* Top-Level Expansion Register 07h~0Bh: IEEE 1588 Original Time Code */ 3136 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ORIGINAL_TIMECODE) { 3137 SOC_IF_ERROR_BREAK 3138 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x07, (uint16)(conf->original_timecode.nanoseconds & 0xffff)), rv); 3139 3140 SOC_IF_ERROR_BREAK 3141 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x08, (uint16)((conf->original_timecode.nanoseconds >> 16) & 0xffff)), rv); 3142 3143 SOC_IF_ERROR_BREAK 3144 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x09, (uint16)(COMPILER_64_LO(conf->original_timecode.seconds) & 0xffff)), rv); 3145 3146 SOC_IF_ERROR_BREAK 3147 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x0a, (uint16)((COMPILER_64_LO(conf->original_timecode.seconds) >> 16) & 0xffff)), rv); 3148 3149 SOC_IF_ERROR_BREAK 3150 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x0b, (uint16)(COMPILER_64_HI(conf->original_timecode.seconds) & 0xffff)), rv); 3151 3152 } 3153 mask = 0; 3154 3155 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_GMODE) { 3156 _phy_54618e_encode_gmode(conf->gmode,&gmode); 3157 mask |= (0x3 << 14); 3158 } 3159 3160 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FRAMESYNC_MODE) { 3161 _phy_54618e_encode_framesync_mode(conf->framesync.mode, &framesync_mode); 3162 mask |= (0xf << 2) | (0x1 << 11); 3163 3164 /* Divide by 8 */ 3165 length_threshold = conf->framesync.length_threshold >> 3; 3166 event_offset = conf->framesync.event_offset >> 3; 3167 3168 /* Top-Level Expansion Register 32h, 1588 Length Threshold */ 3169 SOC_IF_ERROR_BREAK 3170 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x32, length_threshold), rv); 3171 /* Top-Level Expansion Register 33h, 1588 Event Offset */ 3172 SOC_IF_ERROR_BREAK 3173 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x33, event_offset), rv); 3174 } 3175 3176 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_SYNCOUT_MODE) { 3177 _phy_54618e_encode_syncout_mode(conf->syncout.mode, &syncout_mode); 3178 mask |= (0x3 << 0); 3179 3180 /* Divide by 8 */ 3181 interval = conf->syncout.interval >> 3; 3182 pulse_1_length = conf->syncout.pulse_1_length >> 3; /* framesync pulse length */ 3183 pulse_2_length = conf->syncout.pulse_2_length >> 3; /* pulse train length */ 3184 3185 /* Top-Level Expansion Register 29h[15:0], 2Ah[13:0]. Interval_Length */ 3186 SOC_IF_ERROR_BREAK 3187 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x29, 3188 interval & 0xffff), rv); 3189 SOC_IF_ERROR_BREAK 3190 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x2a, 3191 (interval >> 16) & 0x3fff), rv); 3192 3193 /* Top-Level Expansion Register 2bh[8:0], PULSE_TRAIN_length */ 3194 SOC_IF_ERROR_BREAK 3195 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x2b, 3196 (pulse_2_length & 0x1ff)), rv); 3197 /* Top-Level Expansion Register 2ch[8:0], FRMSYNC_PULSE_length */ 3198 SOC_IF_ERROR_BREAK 3199 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x2c, 3200 (pulse_1_length & 0x1ff)), rv); 3201 3202 /* Top-Level Expansion Register 2Eh~30h. Synout_ts_reg */ 3203 SOC_IF_ERROR_BREAK 3204 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x2e, 3205 (uint16)(COMPILER_64_LO(conf->syncout.syncout_ts) & 0xffff)), rv); 3206 SOC_IF_ERROR_BREAK 3207 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x2f, 3208 (uint16)((COMPILER_64_LO(conf->syncout.syncout_ts) >> 16) & 0xffff)), rv); 3209 SOC_IF_ERROR_BREAK 3210 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x30, 3211 (uint16)(COMPILER_64_HI(conf->syncout.syncout_ts) & 0xffff)), rv); 3212 } 3213 3214 /* Top-Level Expansion Reg.31h, NSE NCO Reg. 6 */ 3215 /* GMODE[15:14], FRAMESYNC_MODE[5:2], SYNCOUT_mode[1:0] */ 3216 SOC_IF_ERROR_BREAK 3217 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x31, (gmode << 14) | 3218 ((framesync_mode & 0x2) ? (1U << 11) : (1U << 6)) | /* if bits 1 or 2 are set, turn off syncout */ 3219 (framesync_mode << 2) | (syncout_mode << 0), mask), rv); 3220 3221 /* Top-Level Expansion Register 05h[11:0] IEEE 1588 Tx Timestamp Offset */ 3222 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_TIMESTAMP_OFFSET) { 3223 value = (uint16) (conf->tx_timestamp_offset & 0x0fff); /* TS_OFFSET_TX[11:0] */ 3224 value |= (uint16)((conf->rx_timestamp_offset >> 4) & 0xf000); /* TS_OFFSET_RX_MSB[15:12] */ 3225 SOC_IF_ERROR_BREAK 3226 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x05, value), rv); 3227 } 3228 /* Top-Level Expansion Register 05h[15:12]+06h[15:0] IEEE 1588 Rx Timestamp Offset */ 3229 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_TIMESTAMP_OFFSET) { 3230 SOC_IF_ERROR_BREAK 3231 (_phy_54618e_toplvl_exp_reg_write( unit, pc, 0, 0x06, 3232 (uint16)(conf->rx_timestamp_offset & 0xffff) ), rv); 3233 } 3234 3235 /* Tx Event Message Mode Selection */ 3236 value = 0; 3237 mask = 0; 3238 3239 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_SYNC_MODE) { 3240 _phy_54618e_encode_egress_message_mode(conf->tx_sync_mode, 0, &value); 3241 mask |= 0x3 << 0; 3242 } 3243 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_DELAY_REQUEST_MODE) { 3244 _phy_54618e_encode_egress_message_mode(conf->tx_delay_request_mode, 2, &value); 3245 mask |= 0x3 << 2; 3246 } 3247 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_REQUEST_MODE) { 3248 _phy_54618e_encode_egress_message_mode(conf->tx_pdelay_request_mode, 4, &value); 3249 mask |= 0x3 << 4; 3250 } 3251 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_RESPONSE_MODE) { 3252 _phy_54618e_encode_egress_message_mode(conf->tx_pdelay_response_mode, 6, &value); 3253 mask |= 0x3 << 6; 3254 } 3255 3256 /* Top-Level Expansion Register 01h: IEEE 1588 TX Event Message Mode Selection */ 3257 SOC_IF_ERROR_BREAK 3258 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x01, value, mask), rv); 3259 3260 /* Rx Event Message Mode Selection */ 3261 value = 0; 3262 mask = 0; 3263 3264 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_SYNC_MODE) { 3265 _phy_54618e_encode_ingress_message_mode(conf->rx_sync_mode, 0, &value); 3266 mask |= 0x3 << 0; 3267 } 3268 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_DELAY_REQUEST_MODE) { 3269 _phy_54618e_encode_ingress_message_mode(conf->rx_delay_request_mode, 2, &value); 3270 mask |= 0x3 << 2; 3271 } 3272 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_REQUEST_MODE) { 3273 _phy_54618e_encode_ingress_message_mode(conf->rx_pdelay_request_mode, 4, &value); 3274 mask |= 0x3 << 4; 3275 } 3276 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_RESPONSE_MODE) { 3277 _phy_54618e_encode_ingress_message_mode(conf->rx_pdelay_response_mode, 6, &value); 3278 mask |= 0x3 << 6; 3279 } 3280 3281 /* Top-Level Expansion Register 02h: IEEE 1588 RX Event Message Mode Selection */ 3282 SOC_IF_ERROR_BREAK 3283 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x02, value, mask), rv); 3284 3285 /* Top-Level Expansion Register 19h~1Bh: NSE DPLL Register 2, REF_PHASE */ 3286 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE) { 3287 /* Initial ref phase [15:0] */ 3288 SOC_IF_ERROR_BREAK 3289 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x19, (uint16)(COMPILER_64_LO(conf->phy_1588_dpll_ref_phase) & 0xffff)), rv); 3290 3291 /* Initial ref phase [31:16] */ 3292 SOC_IF_ERROR_BREAK 3293 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x1a, (uint16)((COMPILER_64_LO(conf->phy_1588_dpll_ref_phase) >> 16) & 0xffff)), rv); 3294 3295 /* Initial ref phase [47:32] */ 3296 SOC_IF_ERROR_BREAK 3297 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x1b, (uint16)(COMPILER_64_HI(conf->phy_1588_dpll_ref_phase) & 0xffff)), rv); 3298 } 3299 3300 /* Top-Level Expansion Register 1Ch~1Dh: NSE DPLL Register 3, REF_PHASE_DELTA */ 3301 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE_DELTA) { 3302 /* Ref phase delta [15:0] */ 3303 SOC_IF_ERROR_BREAK 3304 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x1c, (uint16)(conf->phy_1588_dpll_ref_phase_delta & 0xffff)), rv); 3305 3306 /* Ref phase delta [31:16] */ 3307 SOC_IF_ERROR_BREAK 3308 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x1d, (uint16)((conf->phy_1588_dpll_ref_phase_delta >> 16) & 0xffff)), rv); 3309 } 3310 3311 /* DPLL K1 & K2 */ 3312 mask = 0; 3313 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K1) { 3314 mask |= 0xff; /* bit[7:0] */ 3315 } 3316 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K2) { 3317 mask |= 0xff << 8; /* bit[15:8] */ 3318 } 3319 if ( mask != 0 ) { 3320 /* Top-Level Expansion Register 1Eh: NSE DPLL K1/K2 */ 3321 SOC_IF_ERROR_BREAK 3322 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x1e, (conf->phy_1588_dpll_k1 & 0xff)<<8 | (conf->phy_1588_dpll_k2 & 0xff), mask ), rv); 3323 } 3324 3325 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K3) { 3326 /* Top-Level Expansion Register 1Fh: NSE DPLL K3 */ 3327 SOC_IF_ERROR_BREAK 3328 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x1f, conf->phy_1588_dpll_k3 & 0xff), rv); 3329 } 3330 3331 /* Top-Level Expansion Register 20h~23h: NSE DPLL Register 7, LOOP_FILTER */ 3332 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_LOOP_FILTER) { 3333 /* Initial loop filter[15:0] */ 3334 SOC_IF_ERROR_BREAK 3335 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x20, (uint16)(COMPILER_64_LO(conf->phy_1588_dpll_loop_filter) & 0xffff)), rv); 3336 3337 /* Initial loop filter[31:16] */ 3338 SOC_IF_ERROR_BREAK 3339 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x21, (uint16)((COMPILER_64_LO(conf->phy_1588_dpll_loop_filter) >> 16) & 0xffff)), rv); 3340 3341 /* Initial loop filter[47:32] */ 3342 SOC_IF_ERROR_BREAK 3343 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x22, (uint16)(COMPILER_64_HI(conf->phy_1588_dpll_loop_filter) & 0xffff)), rv); 3344 3345 /* Initial loop filter[63:48] */ 3346 SOC_IF_ERROR_BREAK 3347 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x23, (uint16)((COMPILER_64_HI(conf->phy_1588_dpll_loop_filter) >> 16) & 0xffff)), rv); 3348 } 3349 } while ( 0 ); 3350 3351 return SOC_E_NONE; 3352 } 3353 3354 STATIC int 3355 phy_54618_timesync_config_get(int unit, soc_port_t port, 3356 soc_port_phy_timesync_config_t *conf) 3357 { 3358 int rv = SOC_E_NONE; 3359 uint16 tx_control_reg = 0, rx_crc_control_reg = 0, 3360 en_control_reg = 0, tx_capture_en_reg = 0, 3361 nse_nco_6 = 0, nse_nco_2c = 0, temp1, temp2, temp3, temp4, value; 3362 phy_ctrl_t *pc; 3363 soc_port_phy_timesync_global_mode_t gmode = SOC_PORT_PHY_TIMESYNC_MODE_FREE; 3364 soc_port_phy_timesync_framesync_mode_t framesync_mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_NONE; 3365 soc_port_phy_timesync_syncout_mode_t syncout_mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_DISABLE; 3366 3367 pc = EXT_PHY_SW_STATE(unit, port); 3368 3369 if ( ! PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) { 3370 return SOC_E_UNAVAIL; 3371 } 3372 conf->flags = 0; 3373 3374 do { 3375 /* Top-Level Expansion Register 31h NSE NCO Register 6 */ 3376 SOC_IF_ERROR_BREAK 3377 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x31, &nse_nco_6), rv); 3378 3379 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FLAGS) { 3380 /* Top-Level Expansion Reg. 00h[1:0] IEEE 1588 Slice Enable Control */ 3381 SOC_IF_ERROR_BREAK 3382 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x00, &en_control_reg), rv); 3383 3384 if (en_control_reg & (1U << 0)) { 3385 conf->flags |= SOC_PORT_PHY_TIMESYNC_ENABLE; 3386 } 3387 3388 /* Top-Level Expansion Reg. 03h[1:0] 1588 Rx/Tx SOP Timestamp Capture Enable */ 3389 SOC_IF_ERROR_BREAK 3390 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x03, &tx_capture_en_reg), rv); 3391 if (tx_capture_en_reg & (1U << 0)) { /* bit[0] Tx TS Capture Enable */ 3392 conf->flags |= SOC_PORT_PHY_TIMESYNC_CAPTURE_TS_ENABLE; 3393 } 3394 3395 if (nse_nco_6 & (1U << 13)) { /* TopLvl Exp. 31h[13]: TS_CAPTURE */ 3396 conf->flags |= SOC_PORT_PHY_TIMESYNC_HEARTBEAT_TS_ENABLE; 3397 } 3398 3399 /* Top-Level Expansion Register 14h: IEEE 1588 Tx/Rx CRC control register */ 3400 SOC_IF_ERROR_BREAK 3401 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x14, &rx_crc_control_reg), rv); 3402 3403 if (rx_crc_control_reg & (1U << 3)) { 3404 conf->flags |= SOC_PORT_PHY_TIMESYNC_RX_CRC_ENABLE; 3405 } 3406 3407 /* Top-Level Expansion Register 12h: IEEE 1588 Tx/Rx Control Register */ 3408 SOC_IF_ERROR_BREAK 3409 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x12, &tx_control_reg), rv); 3410 3411 if (tx_control_reg & (1U << 3)) { 3412 conf->flags |= SOC_PORT_PHY_TIMESYNC_8021AS_ENABLE; 3413 } 3414 3415 if (tx_control_reg & (1U << 2)) { 3416 conf->flags |= SOC_PORT_PHY_TIMESYNC_L2_ENABLE; 3417 } 3418 3419 if (tx_control_reg & (1U << 1)) { 3420 conf->flags |= SOC_PORT_PHY_TIMESYNC_IP4_ENABLE; 3421 } 3422 3423 if (tx_control_reg & (1U << 0)) { 3424 conf->flags |= SOC_PORT_PHY_TIMESYNC_IP6_ENABLE; 3425 } 3426 3427 /* Top-Level Expansion Register 26h[14] NSE NCO Register 2-1 */ 3428 SOC_IF_ERROR_BREAK 3429 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x26, &nse_nco_2c), rv); 3430 3431 if (!(nse_nco_2c & (1U << 14))) { /* FREQ_mdio_sel[14] */ 3432 conf->flags |= SOC_PORT_PHY_TIMESYNC_CLOCK_SRC_EXT; 3433 } 3434 } 3435 3436 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_GMODE) { 3437 _phy_54618e_decode_gmode((nse_nco_6 >> 14),&gmode); 3438 conf->gmode = gmode; 3439 } 3440 3441 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FRAMESYNC_MODE) { 3442 _phy_54618e_decode_framesync_mode((nse_nco_6 >> 2), &framesync_mode); 3443 conf->framesync.mode = framesync_mode; 3444 /* Top-Level Expansion Register 32h, 1588 Length Threshold */ 3445 SOC_IF_ERROR_BREAK 3446 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x32, &temp1), rv); 3447 /* Top-Level Expansion Register 33h, 1588 Event Offset */ 3448 SOC_IF_ERROR_BREAK 3449 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x33, &temp2), rv); 3450 3451 /* Multiply by 8 */ 3452 conf->framesync.length_threshold = temp1 << 3; 3453 conf->framesync.event_offset = temp2 << 3; 3454 } 3455 3456 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_SYNCOUT_MODE) { 3457 _phy_54618e_decode_syncout_mode((nse_nco_6 >> 0), &syncout_mode); 3458 conf->syncout.mode = syncout_mode; 3459 3460 /* Top-Level Expansion Register 29h[15:0], 2Ah[13:0]. Interval_Length */ 3461 SOC_IF_ERROR_BREAK 3462 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x29, &temp1), rv); 3463 SOC_IF_ERROR_BREAK 3464 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x2a, &temp2), rv); 3465 conf->syncout.interval = ((temp2 & 0x3ff)<< 16) | temp1; 3466 3467 /* Top-Level Expansion Register 2bh[8:0], PULSE_TRAIN_length */ 3468 SOC_IF_ERROR_BREAK 3469 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x2b, &temp2), rv); 3470 /* Top-Level Expansion Register 2ch[8:0], FRMSYNC_PULSE_length */ 3471 SOC_IF_ERROR_BREAK 3472 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x2c, &temp1), rv); 3473 3474 /* Multiply by 8 (unit = 8ns) */ 3475 conf->syncout.pulse_1_length = (temp1 & 0x1ff) << 3; /* FrmSync pulse length */ 3476 conf->syncout.pulse_2_length = (temp2 & 0x1ff) << 3; /* pulse train length */ 3477 3478 /* Top-Level Expansion Register 2Eh~30h. Synout_ts_reg (48 bits) */ 3479 SOC_IF_ERROR_BREAK 3480 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x2e, &temp1), rv); 3481 SOC_IF_ERROR_BREAK 3482 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x2f, &temp2), rv); 3483 SOC_IF_ERROR_BREAK 3484 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x30, &temp3), rv); 3485 3486 COMPILER_64_SET( conf->syncout.syncout_ts, (uint32) temp3, 3487 ((uint32) temp2 << 16) | ((uint32) temp1) ); 3488 } 3489 3490 /* Top-Level Expansion Register 15h: VLAN1 Tags ITPID Register */ 3491 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ITPID) { 3492 SOC_IF_ERROR_BREAK 3493 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x15, &conf->itpid), rv); 3494 } 3495 3496 /* Top-Level Expansion Register 16h: VLAN2 Tags OTPID Register */ 3497 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID) { 3498 SOC_IF_ERROR_BREAK 3499 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x16, &conf->otpid), rv); 3500 } 3501 3502 /* Top-Level Expansion Register 17h: VLAN2 Tags OTPID2 Register */ 3503 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID2) { 3504 SOC_IF_ERROR_BREAK 3505 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x17, &conf->otpid2), rv); 3506 } 3507 3508 /* Top-Level Expansion Register 2Dh[11:0] NCO Register 4, nse_reg_ts_divider */ 3509 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TS_DIVIDER) { 3510 SOC_IF_ERROR_BREAK 3511 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x2d, &conf->ts_divider), rv); 3512 } 3513 3514 /* Top-Level Expansion Register 5Ch/5Dh: Linkdelay1/2 */ 3515 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_LINK_DELAY) { 3516 SOC_IF_ERROR_BREAK 3517 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x5c, &temp1), rv); 3518 SOC_IF_ERROR_BREAK 3519 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x5d, &temp2), rv); 3520 3521 conf->rx_link_delay = ((uint32)temp2 << 16) | temp1; 3522 } 3523 3524 /* Top-Level Expansion Register 07h~0Bh: IEEE 1588 Original Time Code */ 3525 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ORIGINAL_TIMECODE) { 3526 SOC_IF_ERROR_BREAK 3527 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x07, &temp1), rv); 3528 3529 SOC_IF_ERROR_BREAK 3530 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x08, &temp2), rv); 3531 3532 conf->original_timecode.nanoseconds = ((uint32)temp2 << 16) | temp1; 3533 3534 SOC_IF_ERROR_BREAK 3535 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x09, &temp1), rv); 3536 3537 SOC_IF_ERROR_BREAK 3538 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x0a, &temp2), rv); 3539 3540 SOC_IF_ERROR_BREAK 3541 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x0b, &temp3), rv); 3542 3543 COMPILER_64_SET(conf->original_timecode.seconds, ((uint32)temp3), (((uint32)temp2<<16)|((uint32)temp1))); 3544 } 3545 3546 /* Top-Level Expansion Register 05h[11:0] IEEE 1588 Tx Timestamp Offset */ 3547 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_TIMESTAMP_OFFSET) { 3548 SOC_IF_ERROR_BREAK 3549 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x05, &temp2), rv); 3550 conf->tx_timestamp_offset = temp2 & 0x0fff; 3551 } 3552 3553 /* Top-Level Expansion Register 05h[15:12]+06h[15:0] IEEE 1588 Rx Timestamp Offset */ 3554 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_TIMESTAMP_OFFSET) { 3555 SOC_IF_ERROR_BREAK 3556 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x06, &temp1), rv); 3557 conf->rx_timestamp_offset = (uint32) temp1; /* TS_OFFSET_RX[15:0] */ 3558 conf->rx_timestamp_offset |= ((uint32) (temp2 & 0xf000)) << 4 ; /* TS_OFFSET_RX_MSB[15:12] */ 3559 } 3560 3561 /* Top-Level Expansion Register 01h: IEEE 1588 TX Event Message Mode Selection */ 3562 SOC_IF_ERROR_BREAK 3563 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x01, &value), rv); 3564 3565 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_SYNC_MODE) { 3566 _phy_54618e_decode_egress_message_mode(value, 0, &conf->tx_sync_mode); 3567 } 3568 3569 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_DELAY_REQUEST_MODE) { 3570 _phy_54618e_decode_egress_message_mode(value, 2, &conf->tx_delay_request_mode); 3571 } 3572 3573 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_REQUEST_MODE) { 3574 _phy_54618e_decode_egress_message_mode(value, 4, &conf->tx_pdelay_request_mode); 3575 } 3576 3577 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_RESPONSE_MODE) { 3578 _phy_54618e_decode_egress_message_mode(value, 6, &conf->tx_pdelay_response_mode); 3579 } 3580 3581 /* Top-Level Expansion Register 02h: IEEE 1588 RX Event Message Mode Selection */ 3582 SOC_IF_ERROR_BREAK 3583 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x02, &value), rv); 3584 3585 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_SYNC_MODE) { 3586 _phy_54618e_decode_ingress_message_mode(value, 0, &conf->rx_sync_mode); 3587 } 3588 3589 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_DELAY_REQUEST_MODE) { 3590 _phy_54618e_decode_ingress_message_mode(value, 2, &conf->rx_delay_request_mode); 3591 } 3592 3593 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_REQUEST_MODE) { 3594 _phy_54618e_decode_ingress_message_mode(value, 4, &conf->rx_pdelay_request_mode); 3595 } 3596 3597 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_RESPONSE_MODE) { 3598 _phy_54618e_decode_ingress_message_mode(value, 6, &conf->rx_pdelay_response_mode); 3599 } 3600 3601 /* Top-Level Expansion Register 19h~1Bh: NSE DPLL Register 2, REF_PHASE */ 3602 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE) { 3603 /* Initial ref phase [15:0] */ 3604 SOC_IF_ERROR_BREAK 3605 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x19, &temp1), rv); 3606 3607 /* Initial ref phase [31:16] */ 3608 SOC_IF_ERROR_BREAK 3609 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x1a, &temp2), rv); 3610 3611 /* Initial ref phase [47:32] */ 3612 SOC_IF_ERROR_BREAK 3613 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x1b, &temp3), rv); 3614 3615 COMPILER_64_SET(conf->phy_1588_dpll_ref_phase, ((uint32)temp3), (((uint32)temp2<<16)|((uint32)temp1))); 3616 } 3617 3618 /* Top-Level Expansion Register 1Ch~1Dh: NSE DPLL Register 3, REF_PHASE_DELTA */ 3619 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE_DELTA) { 3620 /* Ref phase delta [15:0] */ 3621 SOC_IF_ERROR_BREAK 3622 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x1c, &temp1), rv); 3623 3624 /* Ref phase delta [31:16] */ 3625 SOC_IF_ERROR_BREAK 3626 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x1d, &temp2), rv); 3627 3628 conf->phy_1588_dpll_ref_phase_delta = (temp2 << 16) | temp1; 3629 } 3630 3631 /* Top-Level Expansion Register 1Eh: NSE DPLL K1/K2 */ 3632 SOC_IF_ERROR_BREAK 3633 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x1e, &temp1 ), rv); 3634 3635 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K1) { 3636 conf->phy_1588_dpll_k1 = (temp1 >> 8 ) & 0xff; 3637 } 3638 3639 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K2) { 3640 conf->phy_1588_dpll_k2 = temp1 & 0xff; 3641 } 3642 3643 /* Top-Level Expansion Register 1Fh: NSE DPLL K3 */ 3644 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K3) { 3645 SOC_IF_ERROR_BREAK 3646 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x1f, &temp1), rv); 3647 conf->phy_1588_dpll_k3 = temp1 & 0xff; 3648 } 3649 3650 /* Top-Level Expansion Register 20h~23h: NSE DPLL Register 7, LOOP_FILTER */ 3651 if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_LOOP_FILTER) { 3652 /* Initial loop filter[15:0] */ 3653 SOC_IF_ERROR_BREAK 3654 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x20, &temp1), rv); 3655 3656 /* Initial loop filter[31:16] */ 3657 SOC_IF_ERROR_BREAK 3658 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x21, &temp2), rv); 3659 3660 /* Initial loop filter[47:32] */ 3661 SOC_IF_ERROR_BREAK 3662 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x22, &temp3), rv); 3663 3664 /* Initial loop filter[63:48] */ 3665 SOC_IF_ERROR_BREAK 3666 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x23, &temp4), rv); 3667 3668 COMPILER_64_SET(conf->phy_1588_dpll_loop_filter, (((uint32)temp4<<16)|((uint32)temp3)), (((uint32)temp2<<16)|((uint32)temp1))); 3669 } 3670 } while ( 0 ); 3671 3672 return SOC_E_NONE; 3673 } 3674 3675 STATIC int 3676 phy_54618_timesync_control_set(int unit, soc_port_t port, 3677 soc_port_control_phy_timesync_t type, uint64 value) 3678 { 3679 uint16 temp1, temp2; 3680 uint32 value0; 3681 int rv = SOC_E_NONE; 3682 phy_ctrl_t *pc; 3683 3684 pc = EXT_PHY_SW_STATE(unit, port); 3685 3686 if ( ! PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) { 3687 return SOC_E_UNAVAIL; 3688 } 3689 3690 do { 3691 switch ( type ) { 3692 case SOC_PORT_CONTROL_PHY_TIMESYNC_CAPTURE_TIMESTAMP: 3693 case SOC_PORT_CONTROL_PHY_TIMESYNC_HEARTBEAT_TIMESTAMP: 3694 return SOC_E_UNAVAIL; 3695 3696 case SOC_PORT_CONTROL_PHY_TIMESYNC_NCOADDEND: 3697 value0 = COMPILER_64_LO(value); /* nse_reg_nco_freqcntrl[31:0] */ 3698 /* Top-Level Expansion Register 24h~25h: NSE NCO Register 1, NSE_REQ_NCO_FREQCNTRL */ 3699 SOC_IF_ERROR_BREAK /* nse_reg_nco_freqcntrl[15:0] LSB */ 3700 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x24, (uint16) (value0 & 0xffff)), rv); 3701 SOC_IF_ERROR_BREAK /* nse_reg_nco_freqcntrl[31:16] MSB */ 3702 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x25, (uint16) ((value0 >> 16) & 0xffff)), rv); 3703 break; 3704 3705 case SOC_PORT_CONTROL_PHY_TIMESYNC_FRAMESYNC: 3706 /* Top-Level Expansion Register 31h NSE NCO Register 6 */ 3707 SOC_IF_ERROR_BREAK 3708 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x31, &temp1), rv); 3709 temp2 = ((temp1 | (0x3 << 14) | (0x1 << 12)) & ~(0xf << 2)) | (0x1 << 5); 3710 SOC_IF_ERROR_BREAK 3711 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x31, temp2), rv); 3712 sal_udelay(1); 3713 temp2 &= ~((0x1 << 5) | (0x1 << 12)); 3714 SOC_IF_ERROR_BREAK 3715 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x31, temp2), rv); 3716 sal_udelay(1); 3717 SOC_IF_ERROR_BREAK 3718 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x31, temp1), rv); 3719 3720 break; 3721 3722 case SOC_PORT_CONTROL_PHY_TIMESYNC_LOCAL_TIME: 3723 COMPILER_64_SHR(value, 4); 3724 /* Top-Level Expansion Register 26h~28h NSE NCO Register 2, Local Time */ 3725 SOC_IF_ERROR_BREAK 3726 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x28, (uint16)(COMPILER_64_LO(value) & 0xffff)), rv); 3727 SOC_IF_ERROR_BREAK 3728 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x27, (uint16)((COMPILER_64_LO(value) >> 16) & 0xffff)), rv); 3729 SOC_IF_ERROR_BREAK 3730 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x26, (uint16)(COMPILER_64_HI(value) & 0x0fff), 0x0fff), rv); 3731 break; 3732 3733 case SOC_PORT_CONTROL_PHY_TIMESYNC_LOAD_CONTROL: 3734 temp1 = 0; 3735 temp2 = 0; 3736 value0 = COMPILER_64_LO(value); 3737 3738 if (value0 & SOC_PORT_PHY_TIMESYNC_TN_LOAD) { 3739 temp1 |= 1U << 11; 3740 } 3741 if (value0 & SOC_PORT_PHY_TIMESYNC_TN_ALWAYS_LOAD) { 3742 temp2 |= 1U << 11; 3743 } 3744 if (value0 & SOC_PORT_PHY_TIMESYNC_TIMECODE_LOAD) { 3745 temp1 |= 1U << 10; 3746 } 3747 if (value0 & SOC_PORT_PHY_TIMESYNC_TIMECODE_ALWAYS_LOAD) { 3748 temp2 |= 1U << 10; 3749 } 3750 if (value0 & SOC_PORT_PHY_TIMESYNC_SYNCOUT_LOAD) { 3751 temp1 |= 1U << 9; 3752 } 3753 if (value0 & SOC_PORT_PHY_TIMESYNC_SYNCOUT_ALWAYS_LOAD) { 3754 temp2 |= 1U << 9; 3755 } 3756 if (value0 & SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_LOAD) { 3757 temp1 |= 1U << 8; 3758 } 3759 if (value0 & SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_ALWAYS_LOAD) { 3760 temp2 |= 1U << 8; 3761 } 3762 if (value0 & SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_LOAD) { 3763 temp1 |= 1U << 7; 3764 } 3765 if (value0 & SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_ALWAYS_LOAD) { 3766 temp2 |= 1U << 7; 3767 } 3768 if (value0 & SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_LOAD) { 3769 temp1 |= 1U << 6; 3770 } 3771 if (value0 & SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_ALWAYS_LOAD) { 3772 temp2 |= 1U << 6; 3773 } 3774 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_LOAD) { 3775 temp1 |= 1U << 5; 3776 } 3777 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_ALWAYS_LOAD) { 3778 temp2 |= 1U << 5; 3779 } 3780 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_LOAD) { 3781 temp1 |= 1U << 4; 3782 } 3783 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_ALWAYS_LOAD) { 3784 temp2 |= 1U << 4; 3785 } 3786 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_LOAD) { 3787 temp1 |= 1U << 3; 3788 } 3789 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_ALWAYS_LOAD) { 3790 temp2 |= 1U << 3; 3791 } 3792 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_K3_LOAD) { 3793 temp1 |= 1U << 2; 3794 } 3795 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_K3_ALWAYS_LOAD) { 3796 temp2 |= 1U << 2; 3797 } 3798 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_K2_LOAD) { 3799 temp1 |= 1U << 1; 3800 } 3801 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_K2_ALWAYS_LOAD) { 3802 temp2 |= 1U << 1; 3803 } 3804 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_K1_LOAD) { 3805 temp1 |= 1U << 0; 3806 } 3807 if (value0 & SOC_PORT_PHY_TIMESYNC_DPLL_K1_ALWAYS_LOAD) { 3808 temp2 |= 1U << 0; 3809 } 3810 /* Top-Level Expansion Register 0Fh: IEEE 1588 Shadow Register Control */ 3811 SOC_IF_ERROR_BREAK 3812 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x0f, temp1), rv); 3813 /* Top-Level Expansion Register 10h: IEEE 1588 Shadow Register Load */ 3814 SOC_IF_ERROR_BREAK 3815 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x10, temp2), rv); 3816 break; 3817 3818 case SOC_PORT_CONTROL_PHY_TIMESYNC_INTERRUPT_MASK: 3819 temp1 = 0; 3820 value0 = COMPILER_64_LO(value); 3821 3822 if (value0 & SOC_PORT_PHY_TIMESYNC_TIMESTAMP_INTERRUPT_MASK) { 3823 temp1 |= 1U << 9; /* bit[9] INTC_SOP_MASK */ 3824 } 3825 if (value0 & SOC_PORT_PHY_TIMESYNC_FRAMESYNC_INTERRUPT_MASK) { 3826 temp1 |= 1U << 8; /* bit[8] INTC_FSYNC_MASK */ 3827 } 3828 /* Top-Level Expansion Register 11h: IEEE 1588 Interrupt/Interrupt Mask */ 3829 SOC_IF_ERROR_BREAK 3830 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x11, temp1), rv); 3831 break; 3832 3833 case SOC_PORT_CONTROL_PHY_TIMESYNC_TX_TIMESTAMP_OFFSET: 3834 value0 = COMPILER_64_LO(value); 3835 3836 /* Top-Level Expansion Register 05h[11:0] IEEE 1588 Tx Timestamp Offset */ 3837 SOC_IF_ERROR_BREAK 3838 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x05, (uint16)(value0 & 0x0fff), 0x0fff), rv); 3839 break; 3840 3841 case SOC_PORT_CONTROL_PHY_TIMESYNC_RX_TIMESTAMP_OFFSET: 3842 value0 = COMPILER_64_LO(value); 3843 3844 /* Top-Level Expansion Register 05h[15:12]+06h[15:0] IEEE 1588 Rx Timestamp Offset */ 3845 SOC_IF_ERROR_BREAK 3846 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x05, (uint16)(value0 & 0xf000), 0xf000), rv); 3847 SOC_IF_ERROR_BREAK 3848 (_phy_54618e_toplvl_exp_reg_write( unit, pc, 0, 0x06, (uint16)(value0 & 0xffff)), rv); 3849 3850 break; 3851 3852 default: 3853 return SOC_E_UNAVAIL; 3854 } 3855 } while ( 0 ); 3856 3857 return SOC_E_NONE; 3858 } 3859 3860 STATIC int 3861 phy_54618_timesync_control_get(int unit, soc_port_t port, 3862 soc_port_control_phy_timesync_t type, uint64 *value) 3863 { 3864 uint16 value0, value1, value2; 3865 int rv = SOC_E_NONE; 3866 phy_ctrl_t *pc; 3867 3868 pc = EXT_PHY_SW_STATE(unit, port); 3869 if ( ! PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) { 3870 return SOC_E_UNAVAIL; 3871 } 3872 3873 do { 3874 switch ( type ) { 3875 case SOC_PORT_CONTROL_PHY_TIMESYNC_HEARTBEAT_TIMESTAMP: 3876 /* Start a Heartbeat Read. Expansion Reg. F3h[0], Heartbeat_Start=1 */ 3877 SOC_IF_ERROR_BREAK 3878 (WRITE_PHY54618_EXP_READ_START_END_CTRLr(unit, pc, 0x1), rv); 3879 3880 /* Top-Level Expansion Register 57h~55h: Heartbeat Timestamp (48 bits) */ 3881 SOC_IF_ERROR_BREAK 3882 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x55, &value0), rv); 3883 SOC_IF_ERROR_BREAK 3884 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x56, &value1), rv); 3885 SOC_IF_ERROR_BREAK 3886 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x57, &value2), rv); 3887 3888 /* Stop a Heartbeat Read. Expansion Reg. F3h[1], Heartbeat_Stop=1 */ 3889 SOC_IF_ERROR_BREAK 3890 (WRITE_PHY54618_EXP_READ_START_END_CTRLr(unit, pc, 0x2), rv); 3891 SOC_IF_ERROR_BREAK 3892 (WRITE_PHY54618_EXP_READ_START_END_CTRLr(unit, pc, 0x0), rv); 3893 3894 COMPILER_64_SET((*value), ((uint32)value2), (((uint32)value1<<16) | ((uint32)value0))); 3895 /* *value = (((uint64)value2) << 32) | (((uint64)value1) << 16) | ((uint64)value0); */ 3896 break; 3897 3898 case SOC_PORT_CONTROL_PHY_TIMESYNC_CAPTURE_TIMESTAMP: 3899 /* Start a Timestamp Read. Expansion Reg. F3h[2], TS_START=1 */ 3900 SOC_IF_ERROR_BREAK 3901 (WRITE_PHY54618_EXP_READ_START_END_CTRLr(unit, pc, 0x4), rv); 3902 3903 /* Top-Level Expansion Register 52h~50h: SOP Timestamp (48 bits) */ 3904 SOC_IF_ERROR_BREAK 3905 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x50, &value0), rv); 3906 SOC_IF_ERROR_BREAK 3907 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x51, &value1), rv); 3908 SOC_IF_ERROR_BREAK 3909 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x52, &value2), rv); 3910 3911 /* Start a Timestamp Read. Expansion Reg. F3h[3], TS_END=1 */ 3912 SOC_IF_ERROR_BREAK 3913 (WRITE_PHY54618_EXP_READ_START_END_CTRLr(unit, pc, 0x8), rv); 3914 SOC_IF_ERROR_BREAK 3915 (WRITE_PHY54618_EXP_READ_START_END_CTRLr(unit, pc, 0x0), rv); 3916 3917 COMPILER_64_SET((*value), ((uint32)value2), (((uint32)value1<<16) | ((uint32)value0))); 3918 /* *value = (((uint64)value2) << 32) | (((uint64)value1) << 16) | ((uint64)value0); */ 3919 break; 3920 3921 case SOC_PORT_CONTROL_PHY_TIMESYNC_NCOADDEND: 3922 /* Top-Level Expansion Register 24h~25h: NSE NCO Register 1, NSE_REQ_NCO_FREQCNTRL */ 3923 SOC_IF_ERROR_BREAK 3924 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x24, &value0), rv); 3925 SOC_IF_ERROR_BREAK 3926 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x25, &value1), rv); 3927 COMPILER_64_SET( (*value), 0, ((uint32)value1 << 16) | (uint32)value0 ); 3928 break; 3929 3930 case SOC_PORT_CONTROL_PHY_TIMESYNC_LOCAL_TIME: 3931 /* Top-Level Expansion Register 26h~28h NSE NCO Register 2, Local Time (44 bits) */ 3932 SOC_IF_ERROR_BREAK 3933 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x28, &value0), rv); 3934 SOC_IF_ERROR_BREAK 3935 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x27, &value1), rv); 3936 SOC_IF_ERROR_BREAK 3937 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x26, &value2), rv); 3938 /* Local_Time_MSB [43:32] [31:16] [15:0] */ 3939 COMPILER_64_SET((*value), (value2 & 0x0fff), ((uint32)value1 << 16) | value0 ); 3940 COMPILER_64_SHL((*value), 4); 3941 break; 3942 3943 case SOC_PORT_CONTROL_PHY_TIMESYNC_LOAD_CONTROL: 3944 /* Top-Level Expansion Register 0Fh: IEEE 1588 Shadow Register Control */ 3945 SOC_IF_ERROR_BREAK 3946 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x0f, &value1), rv); 3947 /* Top-Level Expansion Register 10h: IEEE 1588 Shadow Register Load */ 3948 SOC_IF_ERROR_BREAK 3949 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x10, &value2), rv); 3950 3951 value0 = 0; 3952 if (value1 & (1U << 11)) { 3953 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TN_LOAD; 3954 } 3955 if (value2 & (1U << 11)) { 3956 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TN_ALWAYS_LOAD; 3957 } 3958 if (value1 & (1U << 10)) { 3959 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TIMECODE_LOAD; 3960 } 3961 if (value2 & (1U << 10)) { 3962 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TIMECODE_ALWAYS_LOAD; 3963 } 3964 if (value1 & (1U << 9)) { 3965 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_SYNCOUT_LOAD; 3966 } 3967 if (value2 & (1U << 9)) { 3968 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_SYNCOUT_ALWAYS_LOAD; 3969 } 3970 if (value1 & (1U << 8)) { 3971 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_LOAD; 3972 } 3973 if (value1 & (1U << 8)) { 3974 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_ALWAYS_LOAD; 3975 } 3976 if (value1 & (1U << 7)) { 3977 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_LOAD; 3978 } 3979 if (value1 & (1U << 7)) { 3980 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_ALWAYS_LOAD; 3981 } 3982 if (value1 & (1U << 6)) { 3983 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_LOAD; 3984 } 3985 if (value2 & (1U << 6)) { 3986 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_ALWAYS_LOAD; 3987 } 3988 if (value1 & (1U << 5)) { 3989 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_LOAD; 3990 } 3991 if (value2 & (1U << 5)) { 3992 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_ALWAYS_LOAD; 3993 } 3994 if (value1 & (1U << 4)) { 3995 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_LOAD; 3996 } 3997 if (value2 & (1U << 4)) { 3998 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_ALWAYS_LOAD; 3999 } 4000 if (value1 & (1U << 3)) { 4001 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_LOAD; 4002 } 4003 if (value2 & (1U << 3)) { 4004 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_ALWAYS_LOAD; 4005 } 4006 if (value1 & (1U << 2)) { 4007 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K3_LOAD; 4008 } 4009 if (value2 & (1U << 2)) { 4010 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K3_ALWAYS_LOAD; 4011 } 4012 if (value1 & (1U << 1)) { 4013 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K2_LOAD; 4014 } 4015 if (value2 & (1U << 1)) { 4016 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K2_ALWAYS_LOAD; 4017 } 4018 if (value1 & (1U << 0)) { 4019 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K1_LOAD; 4020 } 4021 if (value2 & (1U << 0)) { 4022 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K1_ALWAYS_LOAD; 4023 } 4024 COMPILER_64_SET((*value), 0, (uint32)value0); 4025 break; 4026 4027 case SOC_PORT_CONTROL_PHY_TIMESYNC_INTERRUPT: 4028 /* Top-Level Expansion Register 11h: IEEE 1588 Interrupt/Interrupt Mask */ 4029 SOC_IF_ERROR_BREAK 4030 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x11, &value1), rv); 4031 value0 = 0; 4032 if (value1 & (1U << 1)) { /* bit[1] INTC_SOP */ 4033 value0 |= SOC_PORT_PHY_TIMESYNC_TIMESTAMP_INTERRUPT; 4034 } 4035 if (value1 & (1U << 0)) { /* bit[0] INTC_FSYNC */ 4036 value0 |= SOC_PORT_PHY_TIMESYNC_FRAMESYNC_INTERRUPT; 4037 } 4038 COMPILER_64_SET((*value), 0, (uint32)value0); 4039 break; 4040 4041 case SOC_PORT_CONTROL_PHY_TIMESYNC_INTERRUPT_MASK: 4042 /* Top-Level Expansion Register 11h: IEEE 1588 Interrupt/Interrupt Mask */ 4043 SOC_IF_ERROR_BREAK 4044 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x11, &value1), rv); 4045 value0 = 0; 4046 if (value1 & (1U << 9)) { /* bit[9] INTC_SOP_MASK */ 4047 value0 |= SOC_PORT_PHY_TIMESYNC_TIMESTAMP_INTERRUPT_MASK; 4048 } 4049 if (value1 & (1U << 8)) { /* bit[8] INTC_FSYNC_MASK */ 4050 value0 |= SOC_PORT_PHY_TIMESYNC_FRAMESYNC_INTERRUPT_MASK; 4051 } 4052 COMPILER_64_SET((*value), 0, (uint32)value0); 4053 break; 4054 4055 case SOC_PORT_CONTROL_PHY_TIMESYNC_TX_TIMESTAMP_OFFSET: 4056 /* Top-Level Expansion Register 05h[11:0] IEEE 1588 Tx Timestamp Offset */ 4057 SOC_IF_ERROR_BREAK 4058 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x05, &value0), rv); 4059 COMPILER_64_SET((*value), 0, ((uint32)value0 & 0x0fff)); 4060 break; 4061 4062 case SOC_PORT_CONTROL_PHY_TIMESYNC_RX_TIMESTAMP_OFFSET: 4063 /* Top-Level Expansion Register 05h[15:12]+06h[15:0] IEEE 1588 Rx Timestamp Offset */ 4064 SOC_IF_ERROR_BREAK /* TS_OFFSET_RX_MSB[15:12] */ 4065 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x05, &value1), rv); 4066 SOC_IF_ERROR_BREAK /* TS_OFFSET_RX[15:0] */ 4067 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x06, &value0), rv); 4068 COMPILER_64_SET((*value), 0, (((uint32)value1 & 0xf000) << 4) | value0); 4069 break; 4070 4071 default: 4072 return SOC_E_UNAVAIL; 4073 } 4074 } while ( 0 ); 4075 4076 return SOC_E_NONE; 4077 } 4078 4079 4080 /* 4081 * Function: 4082 * phy_54616_probe 4083 * Purpose: 4084 * Complement the generic phy probe routine to identify this phy when its 4085 * phy id0 and id1 is same as some other phy's. 4086 * Parameters: 4087 * unit - StrataSwitch unit #. 4088 * pc - phy ctrl descriptor. 4089 * Returns: 4090 * SOC_E_NONE,SOC_E_NOT_FOUND and SOC_E_<error> 4091 */ 4092 STATIC int 4093 phy_54616_probe(int unit, phy_ctrl_t *pc) 4094 { 4095 uint16 id0, id1, data; 4096 soc_phy_info_t *pi; 4097 4098 if (READ_PHY54616_MII_PHY_ID0r(unit, pc, &id0) < 0) { 4099 return SOC_E_NOT_FOUND; 4100 } 4101 if (READ_PHY54616_MII_PHY_ID1r(unit, pc, &id1) < 0) { 4102 return SOC_E_NOT_FOUND; 4103 } 4104 4105 pi = &SOC_PHY_INFO(unit, pc->port); 4106 4107 switch (PHY_MODEL(id0, id1)) { 4108 case PHY_BCM54616_MODEL: 4109 SOC_IF_ERROR_RETURN 4110 (READ_PHY54616_MODE_CTRLr(unit, pc, &data)); 4111 if (data & (1U << 3)) { 4112 /* Serdes present so it's a 54616S */ 4113 pi->phy_name = "BCM54616S"; 4114 PHY_FLAGS_SET(pc->unit, pc->port, PHY_FLAGS_SECONDARY_SERDES); 4115 } 4116 break; 4117 4118 case PHY_BCM54618E_MODEL: 4119 case PHY_BCM54618SE_MODEL: 4120 return SOC_E_NONE; 4121 4122 default: 4123 return SOC_E_NOT_FOUND; 4124 } 4125 4126 return SOC_E_NONE; 4127 } 4128 4129 4130 #ifdef BROADCOM_DEBUG 4131 4132 /* 4133 * Function: 4134 * phy_54616_shadow_dump 4135 * Purpose: 4136 * Debug routine to dump all shadow registers. 4137 * Parameters: 4138 * unit - StrataSwitch unit #. 4139 * port - StrataSwitch port #. 4140 */ 4141 4142 void 4143 phy_54616_shadow_dump(int unit, soc_port_t port) 4144 { 4145 phy_ctrl_t *pc; 4146 uint16 tmp; 4147 int i; 4148 4149 pc = EXT_PHY_SW_STATE(unit, port); 4150 4151 /* Register 0x18 Shadows */ 4152 for (i = 0; i <= 7; i++) { 4153 WRITE_PHY_REG(unit, pc, 0x18, (i << 12) | 0x7); 4154 READ_PHY_REG(unit, pc, 0x18, &tmp); 4155 if ((tmp & ~7) == 0x0000) { 4156 continue; 4157 } 4158 LOG_CLI((BSL_META_U(unit, 4159 "0x18[0x%x]=0x%04x\n"), i, tmp)); 4160 } 4161 4162 /* Register 0x1c Shadows */ 4163 for (i = 0; i <= 0x1f; i++) { 4164 WRITE_PHY_REG(unit, pc, 0x1c, i << 10); 4165 READ_PHY_REG(unit, pc, 0x1c, &tmp); 4166 if ((tmp & ~0x7c00) == 0x0000) { 4167 continue; 4168 } 4169 LOG_CLI((BSL_META_U(unit, 4170 "0x1c[0x%x]=0x%04x\n"), i, tmp)); 4171 } 4172 4173 /* Register 0x17/0x15 Shadows */ 4174 for (i = 0; i <= 0x13; i++) { 4175 WRITE_PHY_REG(unit, pc, 0x17, 0xf00 | i); 4176 READ_PHY_REG(unit, pc, 0x15, &tmp); 4177 if (tmp == 0x0000) { 4178 continue; 4179 } 4180 LOG_CLI((BSL_META_U(unit, 4181 "0x17[0x%x]=0x%04x\n"), i, tmp)); 4182 } 4183 } 4184 4185 #endif /* BROADCOM_DEBUG */ 4186 4187 /* 4188 * Variable: phy_54616drv_ge 4189 * Purpose: PHY driver for 54616 4190 */ 4191 4192 phy_driver_t phy_54616drv_ge = { 4193 "54616/801x Gigabit PHY Driver", 4194 phy_54616_init, 4195 phy_fe_ge_reset, 4196 phy_54616_link_get, 4197 phy_54616_enable_set, 4198 phy_54616_enable_get, 4199 phy_54616_duplex_set, 4200 phy_54616_duplex_get, 4201 phy_54616_speed_set, 4202 phy_54616_speed_get, 4203 phy_54616_master_set, 4204 phy_54616_master_get, 4205 phy_54616_autoneg_set, 4206 phy_54616_autoneg_get, 4207 NULL, /* Local Advert set, deprecated */ 4208 NULL, /* Local Advert get, deprecated */ 4209 NULL, /* Remote Advert get, deprecated */ 4210 phy_54616_lb_set, 4211 phy_54616_lb_get, 4212 phy_54616_interface_set, 4213 phy_54616_interface_get, 4214 NULL, 4215 NULL, /* Phy link up event */ 4216 NULL, /* Phy link down event */ 4217 phy_54616_mdix_set, 4218 phy_54616_mdix_get, 4219 phy_54616_mdix_status_get, 4220 phy_54616_medium_config_set, 4221 phy_54616_medium_config_get, 4222 phy_54616_medium_status, 4223 phy_54616_cable_diag, 4224 NULL, /* phy_link_change */ 4225 phy_54616_control_set, /* phy_control_set */ 4226 phy_54616_control_get, /* phy_control_get */ 4227 phy_ge_reg_read, 4228 phy_ge_reg_write, 4229 phy_ge_reg_modify, 4230 NULL, /* Phy event notify */ 4231 phy_54616_probe, /* pd_probe */ 4232 phy_54616_ability_advert_set, /* pd_ability_advert_set */ 4233 phy_54616_ability_advert_get, /* pd_ability_advert_get */ 4234 phy_54616_ability_remote_get, /* pd_ability_remote_get */ 4235 phy_54616_ability_local_get, /* pd_ability_local_get */ 4236 NULL, /* pd_firmware_set */ 4237 phy_54618_timesync_config_set, 4238 phy_54618_timesync_config_get, 4239 phy_54618_timesync_control_set, 4240 phy_54618_timesync_control_get 4241 }; 4242 4243 #else /* INCLUDE_PHY_54616_ESW */ 4244 int _soc_phy_54616_not_empty; 4245 #endif /* INCLUDE_PHY_54616 || INCLUDE_PHY_54618SE || INCLUDE_PHY_54618E */ 4246