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