phyctrl.c (143996B)
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 * StrataSwitch PHY control API 8 * All access to PHY drivers should call the following soc functions. 9 */ 10 11 #include <shared/bsl.h> 12 13 #include <sal/core/libc.h> 14 #include <shared/alloc.h> 15 #include <sal/core/spl.h> 16 17 #include <soc/drv.h> 18 #include <soc/port_ability.h> 19 #include <soc/phy.h> 20 #include <soc/phyreg.h> 21 #include <soc/phyctrl.h> 22 #include <soc/phy/phyctrl.h> 23 #include <soc/phy/drv.h> 24 #include <soc/error.h> 25 #include <soc/counter.h> 26 #ifdef BCM_TRIDENT_SUPPORT 27 #include <soc/trident.h> 28 #endif 29 #ifdef BCM_KATANA2_SUPPORT 30 #include <soc/katana2.h> 31 #endif 32 #ifdef BCM_GREYHOUND2_SUPPORT 33 #include <soc/greyhound2.h> 34 #endif 35 #ifdef INCLUDE_MACSEC 36 #include <soc/macsecphy.h> 37 #endif 38 #ifdef INCLUDE_FCMAP 39 #include <soc/fcmapphy.h> 40 #endif 41 #ifdef BCM_DFE_SUPPORT 42 #include <soc/dfe/cmn/dfe_drv.h> 43 #endif 44 #ifdef BCM_ESW_SUPPORT 45 #include <bcm_int/esw/port.h> 46 #endif 47 48 /* PHY address to port re-mapping */ 49 int *phy_rmap[SOC_MAX_NUM_DEVICES]; 50 51 /* Per port data structure to manage PHY drivers */ 52 soc_phy_info_t *phy_port_info[SOC_MAX_NUM_DEVICES]; 53 54 /* Per PHY data structure to manage PHY drivers */ 55 phy_ctrl_t **int_phy_ctrl[SOC_MAX_NUM_DEVICES]; 56 phy_ctrl_t **ext_phy_ctrl[SOC_MAX_NUM_DEVICES]; 57 58 #define SOC_PHYCTRL_INIT_CHECK(_ext_pc, _int_pc) \ 59 if ((NULL == (_ext_pc)) && (NULL == (_int_pc))) { \ 60 return SOC_E_INIT; \ 61 } 62 63 #define SOC_NULL_PARAM_CHECK(_param) \ 64 if (NULL == (_param)) { \ 65 return SOC_E_PARAM; \ 66 } 67 68 #define SOC_PORT_PARAM_CHECK(_port) \ 69 if ((_port) >= SOC_MAX_NUM_PORTS || (_port) < 0) { \ 70 return SOC_E_PARAM; \ 71 } 72 73 #ifdef PHYCTRL_DEBUG_PRINT 74 #define PHYCTRL_WARN(_stuff) LOG_WARN(BSL_LS_SOC_PHY, _stuff) 75 #define PHYCTRL_VERBOSE(_stuff) LOG_VERBOSE(BSL_LS_SOC_PHY, _stuff) 76 #else 77 #define PHYCTRL_WARN(_stuff) 78 #define PHYCTRL_VERBOSE(_stuff) 79 #endif 80 81 #define MAC_WAN_MODE_THROTTLE_10G_TO_5G 256 82 #define MAC_WAN_MODE_THROTTLE_10G_TO_2P5G 257 83 84 STATIC void 85 soc_phyctrl_phymod_free(phy_ctrl_t *pc) 86 { 87 #ifdef PHYMOD_SUPPORT 88 if (pc && pc->phymod_ctrl.cleanup) { 89 pc->phymod_ctrl.cleanup(&pc->phymod_ctrl); 90 } 91 #endif 92 } 93 94 STATIC void 95 soc_phyctrl_free(phy_ctrl_t *pc) 96 { 97 /* Free PHYMOD resources */ 98 soc_phyctrl_phymod_free(pc); 99 #ifdef INCLUDE_FCMAP 100 if (pc->fcmap_enable) { 101 soc_fcmapphy_uninit(pc->unit, pc->port); 102 } 103 #endif 104 /* Free main structure */ 105 sal_free(pc); 106 } 107 108 int 109 soc_phyctrl_software_deinit(int unit) 110 { 111 int port; 112 113 LOG_VERBOSE(BSL_LS_SOC_PHY, 114 (BSL_META_U(unit, 115 "entered soc_phyctrl_software_deinit: unit %d\n"), unit)); 116 117 if (NULL != phy_port_info[unit]) { 118 PBMP_PORT_ITER(unit, port) { 119 if (NULL != phy_port_info[unit][port].chip_info) { 120 sal_free(phy_port_info[unit][port].chip_info); 121 phy_port_info[unit][port].chip_info = NULL; 122 } 123 } 124 sal_free(phy_port_info[unit]); 125 phy_port_info[unit] = NULL; 126 } 127 128 if (NULL != int_phy_ctrl[unit]) { 129 PBMP_PORT_ITER(unit, port) { 130 if (NULL != int_phy_ctrl[unit][port]) { 131 soc_phyctrl_free(int_phy_ctrl[unit][port]); 132 int_phy_ctrl[unit][port] = NULL; 133 } 134 } 135 sal_free(int_phy_ctrl[unit]); 136 int_phy_ctrl[unit] = NULL; 137 } 138 139 if (NULL != ext_phy_ctrl[unit]) { 140 PBMP_PORT_ITER(unit, port) { 141 if (NULL != ext_phy_ctrl[unit][port]) { 142 soc_phyctrl_free(ext_phy_ctrl[unit][port]); 143 ext_phy_ctrl[unit][port] = NULL; 144 } 145 } 146 sal_free(ext_phy_ctrl[unit]); 147 ext_phy_ctrl[unit] = NULL; 148 } 149 150 if (NULL != phy_rmap[unit]) { 151 sal_free(phy_rmap[unit]); 152 phy_rmap[unit] = NULL; 153 } 154 155 SOC_IF_ERROR_RETURN (soc_phy_deinit(unit)); 156 157 return (SOC_E_NONE); 158 } 159 160 /* Validate phy address, TRUE is valid, FALSE is bad */ 161 STATIC uint8 162 soc_phy_addr_valid(int unit, int port, int phy_addr) 163 { 164 uint8 valid = TRUE; 165 int bus_num; 166 167 if (SOC_IS_TRIDENT2(unit)) { 168 bus_num = PHY_ID_BUS_NUM(phy_addr); 169 170 /* Only 0 to 5 MDIO rings are supported for Ethernet on TD2 */ 171 if ((bus_num < 0) || (bus_num >= 6)) { 172 valid = FALSE; 173 } 174 } 175 176 return valid; 177 } 178 179 int 180 soc_phyctrl_software_init(int unit) 181 { 182 int port; 183 184 LOG_VERBOSE(BSL_LS_SOC_PHY, 185 (BSL_META_U(unit, 186 "entered soc_phyctrl_software_init: unit %d\n"), unit)); 187 188 if ((phy_port_info[unit] != NULL) || 189 (int_phy_ctrl[unit] != NULL) || 190 (ext_phy_ctrl[unit] != NULL) || 191 (phy_rmap[unit] != NULL)) { 192 soc_phyctrl_software_deinit(unit); 193 } 194 195 phy_port_info[unit] = sal_alloc(sizeof(soc_phy_info_t) * 196 SOC_MAX_NUM_PORTS, 197 "phy_port_info"); 198 if (phy_port_info[unit] == NULL) { 199 return SOC_E_MEMORY; 200 } 201 sal_memset(phy_port_info[unit], 0, 202 sizeof(soc_phy_info_t) * SOC_MAX_NUM_PORTS); 203 204 int_phy_ctrl[unit] = sal_alloc(sizeof(phy_ctrl_t *) * 205 SOC_MAX_NUM_PORTS, 206 "int_phy_ctrl"); 207 if (int_phy_ctrl[unit] == NULL) { 208 soc_phyctrl_software_deinit(unit); 209 return SOC_E_MEMORY; 210 } 211 sal_memset(int_phy_ctrl[unit], 0, 212 sizeof(phy_ctrl_t *) * SOC_MAX_NUM_PORTS); 213 214 215 ext_phy_ctrl[unit] = sal_alloc(sizeof(phy_ctrl_t *) * 216 SOC_MAX_NUM_PORTS, 217 "ext_phy_ctrl"); 218 if (ext_phy_ctrl[unit] == NULL) { 219 soc_phyctrl_software_deinit(unit); 220 return SOC_E_MEMORY; 221 } 222 sal_memset(ext_phy_ctrl[unit], 0, 223 sizeof(phy_ctrl_t *) * SOC_MAX_NUM_PORTS); 224 225 phy_rmap[unit] = sal_alloc(sizeof(int) * EXT_PHY_ADDR_MAX, 226 "phy_rmap"); 227 if (phy_rmap[unit] == NULL) { 228 soc_phyctrl_software_deinit(unit); 229 return SOC_E_MEMORY; 230 } 231 sal_memset(phy_rmap[unit], -1, sizeof(int) * EXT_PHY_ADDR_MAX); 232 233 /* Initialize PHY driver table and assign default PHY address */ 234 SOC_IF_ERROR_RETURN 235 (soc_phy_init(unit)); 236 237 PBMP_PORT_ITER(unit, port) { 238 if (PHY_ADDR(unit, port) >= EXT_PHY_ADDR_MAX || 239 PHY_ADDR_INT(unit, port) >= EXT_PHY_ADDR_MAX || 240 !soc_phy_addr_valid(unit, port, PHY_ADDR(unit, port))) { 241 LOG_ERROR(BSL_LS_SOC_PHY, 242 (BSL_META_U(unit, 243 "soc_phyctrl_software_init: intPhyAddr 0x%x " 244 "or extPhyAddr 0x%x exceeds max size u=%d p=%d FAILED "), 245 PHY_ADDR_INT(unit, port),PHY_ADDR(unit, port),unit, port)); 246 return SOC_E_PARAM; 247 } 248 PHY_ADDR_TO_PORT(unit, PHY_ADDR(unit, port)) = port; 249 PHY_ADDR_TO_PORT(unit, PHY_ADDR_INT(unit, port)) = port; 250 } 251 252 PHYCTRL_VERBOSE(("soc_phyctrl_software_init Unit %d\n", 253 unit)); 254 255 return SOC_E_NONE; 256 } 257 258 int 259 soc_phyctrl_software_port_init(int unit, soc_port_t port) 260 { 261 262 LOG_VERBOSE(BSL_LS_SOC_PHY, 263 (BSL_META_U(unit, 264 "entered soc_phyctrl_software_port_init: " 265 "unit %d, port %d\n"), unit, port)); 266 267 /* Assign default PHY address */ 268 SOC_IF_ERROR_RETURN 269 (soc_phy_port_init(unit, port)); 270 271 if (PHY_ADDR(unit, port) >= EXT_PHY_ADDR_MAX || 272 PHY_ADDR_INT(unit, port) >= EXT_PHY_ADDR_MAX) { 273 LOG_ERROR(BSL_LS_SOC_PHY, 274 (BSL_META_U(unit, 275 "soc_phyctrl_software_init: intPhyAddr 0x%x " 276 "or extPhyAddr 0x%x exceeds max size u=%d p=%d FAILED "), 277 PHY_ADDR_INT(unit, port),PHY_ADDR(unit, port),unit, port)); 278 return SOC_E_PARAM; 279 } 280 PHY_ADDR_TO_PORT(unit, PHY_ADDR(unit, port)) = port; 281 PHY_ADDR_TO_PORT(unit, PHY_ADDR_INT(unit, port)) = port; 282 283 284 PHYCTRL_VERBOSE(("soc_phyctrl_software_port_init Unit %d Port %d\n", 285 unit, port)); 286 287 return SOC_E_NONE; 288 } 289 290 /* 291 * Function: 292 * soc_phyctrl_drv_name_get 293 * Purpose: 294 * Get PHY driver name. 295 * Parameters: 296 * unit - SOC Unit #. 297 * port - Port number. 298 * name - Buffer for PHY driver name. 299 * len - Length of buffer. 300 * Returns: 301 * SOC_E_XXX 302 */ 303 int 304 soc_phyctrl_drv_name_get(int unit, soc_port_t port, char *name, int len) 305 { 306 static char unknown_driver[] = "unknown driver"; 307 phy_driver_t *pd; 308 int string_len; 309 310 LOG_VERBOSE(BSL_LS_SOC_PHY, 311 (BSL_META_U(unit, 312 "entered soc_phyctrl_drv_name_get: " 313 "unit %d, port %d, name %s, len %d\n"), unit, port, name, len)); 314 315 pd = NULL; 316 if (NULL != EXT_PHY_SW_STATE(unit, port)) { 317 pd = EXT_PHY_SW_STATE(unit, port)->pd; 318 } else if (NULL != INT_PHY_SW_STATE(unit, port)) { 319 pd = INT_PHY_SW_STATE(unit, port)->pd; 320 } 321 322 if (NULL == pd) { 323 string_len = (int)sizeof(unknown_driver); 324 if (string_len <= len) { 325 sal_strncpy(name, unknown_driver, len); 326 } 327 return SOC_E_NOT_FOUND; 328 } 329 330 string_len = (int)sal_strlen(pd->drv_name); 331 if (string_len > len) { 332 return SOC_E_MEMORY; 333 } 334 335 sal_strncpy(name, pd->drv_name, len); 336 337 return SOC_E_NONE; 338 } 339 340 STATIC int 341 soc_phy_sbus_read(int unit, uint32 phy_id, 342 uint32 phy_reg_addr, uint16 *phy_rd_data) 343 { 344 soc_sbus_mdio_read_f sbus_read; 345 uint32 data32; 346 347 sbus_read = SOC_FUNCTIONS(unit)->soc_sbus_mdio_read; 348 if (sbus_read == NULL) { 349 return SOC_E_INTERNAL; 350 } 351 352 SOC_IF_ERROR_RETURN( 353 sbus_read(unit, phy_id, phy_reg_addr, &data32)); 354 355 *phy_rd_data = data32; 356 357 return SOC_E_NONE; 358 } 359 360 STATIC int 361 soc_phy_sbus_wrmask(int unit, uint32 phy_id, 362 uint32 phy_reg_addr, uint16 phy_wr_data, uint16 wr_mask) 363 { 364 soc_sbus_mdio_write_f sbus_write; 365 uint32 wr_data; 366 367 sbus_write = SOC_FUNCTIONS(unit)->soc_sbus_mdio_write; 368 if (sbus_write == NULL) { 369 return SOC_E_INTERNAL; 370 } 371 372 wr_data = wr_mask; 373 wr_data <<= 16; 374 wr_data |= phy_wr_data; 375 376 return sbus_write(unit, phy_id, phy_reg_addr, wr_data); 377 } 378 379 STATIC int 380 soc_phy_sbus_write(int unit, uint32 phy_id, 381 uint32 phy_reg_addr, uint16 phy_wr_data) 382 { 383 return soc_phy_sbus_wrmask(unit, phy_id, phy_reg_addr, phy_wr_data, 0); 384 } 385 386 /* 387 * Function: 388 * soc_phyctrl_probe 389 * Purpose: 390 * Probe for internal and external PHYs attached to the port. 391 * Parameters: 392 * unit - SOC Unit #. 393 * port - Port number. 394 * Returns: 395 * SOC_E_XXX 396 */ 397 int 398 soc_phyctrl_probe(int unit, soc_port_t port) 399 { 400 int rv; 401 phy_driver_t *ext_pd; 402 phy_driver_t *int_pd; 403 phy_ctrl_t ext_pc; 404 phy_ctrl_t int_pc; 405 phy_ctrl_t *pc; 406 rv = SOC_E_NONE; 407 408 sal_memset(&ext_pc, 0, sizeof(phy_ctrl_t)); 409 sal_memset(&int_pc, 0, sizeof(phy_ctrl_t)); 410 411 LOG_VERBOSE(BSL_LS_SOC_PHY, 412 (BSL_META_U(unit, 413 "entered soc_phyctrl_probe: " 414 "unit %d, port %d\n"), unit, port)); 415 416 /* Free previously allocated PHYMOD resources, otherwise the probe 417 * function may fail because the phy and core IDs we want to 418 * assign already exist. This situation can happen if the BCM 419 * layer is initialized multiple times without a full system 420 * initialization. 421 */ 422 soc_phyctrl_phymod_free(INT_PHY_SW_STATE(unit, port)); 423 soc_phyctrl_phymod_free(EXT_PHY_SW_STATE(unit, port)); 424 425 /* The soc layer probe function always uses the default PHY addresses 426 * instead of PHY address stored in phy_info from previous probe. 427 * This make sure that the external PHY probe works correctly even 428 * when the device is hot plugged. 429 */ 430 int_pc.unit = unit; 431 int_pc.port = port; 432 int_pc.speed_max = SOC_INFO(unit).port_init_speed[port] ? 433 SOC_INFO(unit).port_init_speed[port] : 434 SOC_INFO(unit).port_speed_max[port]; 435 ext_pc.unit = unit; 436 ext_pc.port = port; 437 ext_pc.speed_max = SOC_INFO(unit).port_init_speed[port] ? 438 SOC_INFO(unit).port_init_speed[port] : 439 SOC_INFO(unit).port_speed_max[port]; 440 441 if (soc_feature(unit, soc_feature_port_encap_speed_max_config)){ 442 /* 443 * Using the soc_feature_port_encap_speed_max_config would imply 444 * port_init_speed as the max supported speed of ethernet port and 445 * port_speed_max as the max supported speed of Higig port. 446 */ 447 if (IS_HG_PORT(unit, port)) { 448 /* for Higig port, giving the port_speed_max */ 449 int_pc.speed_max = SOC_INFO(unit).port_speed_max[port]; 450 ext_pc.speed_max = SOC_INFO(unit).port_speed_max[port]; 451 } 452 } 453 #ifdef BCM_DFE_SUPPORT 454 if (SOC_IS_DFE(unit)) { 455 int phy_clause = 22; 456 457 /* Clause 45 instead of Clause 22 MDIO access */ 458 phy_clause = soc_property_port_get(unit, port, spn_PORT_PHY_CLAUSE, phy_clause); 459 460 int_pc.read = soc_dcmn_miim_cl22_read; 461 int_pc.write = soc_dcmn_miim_cl22_write; 462 463 /* ARAD version of register access */ 464 if (45 == phy_clause) { 465 ext_pc.read = soc_dcmn_miim_cl45_read; 466 ext_pc.write = soc_dcmn_miim_cl45_write; 467 ext_pc.wb_write = NULL; 468 } else { 469 ext_pc.read = soc_dcmn_miim_cl22_read; 470 ext_pc.write = soc_dcmn_miim_cl22_write; 471 } 472 473 if (SOC_IS_FE1600_B0_AND_ABOVE(unit) && SOC_DFE_CONFIG(unit).serdes_mixed_rate_enable) { 474 PHY_FLAGS_SET(unit, port, PHY_FLAGS_SUPPORT_DUAL_RATE); 475 } 476 } else 477 #endif /* BCM_DFE_SUPPORT */ 478 479 480 481 #ifdef BCM_PETRA_SUPPORT 482 if (SOC_IS_ARAD(unit)) { 483 484 int phy_clause = 22; 485 486 /* Clause 45 instead of Clause 22 MDIO access */ 487 phy_clause = soc_property_port_get(unit, port, spn_PORT_PHY_CLAUSE, phy_clause); 488 489 if (!SOC_IS_ARDON(unit)) { 490 int_pc.read = soc_dcmn_miim_cl22_read; 491 int_pc.write = soc_dcmn_miim_cl22_write; 492 } 493 494 /* ARAD version of register access */ 495 if (45 == phy_clause) { 496 ext_pc.read = soc_dcmn_miim_cl45_read; 497 ext_pc.write = soc_dcmn_miim_cl45_write; 498 ext_pc.wb_write = NULL; 499 if (SOC_IS_ARDON(unit)) { 500 int_pc.read = soc_dcmn_miim_cl45_read; 501 int_pc.write = soc_dcmn_miim_cl45_write; 502 } 503 } else { 504 ext_pc.read = soc_dcmn_miim_cl22_read; 505 ext_pc.write = soc_dcmn_miim_cl22_write; 506 ext_pc.wb_write = NULL; 507 if (SOC_IS_ARDON(unit)) { 508 int_pc.read = soc_dcmn_miim_cl22_read; 509 int_pc.write = soc_dcmn_miim_cl22_write; 510 } 511 } 512 } else 513 #endif /* BCM_PETRA_SUPPORT */ 514 { 515 #ifdef BCM_ESW_SUPPORT 516 int phy_clause = 22; 517 int_pc.read = soc_esw_miim_read; 518 int_pc.write = soc_esw_miim_write; 519 if (IS_XE_PORT(unit, port) || IS_HG_PORT(unit, port) || IS_CE_PORT(unit,port)) { 520 phy_clause = 45; 521 } 522 /* Clause 45 instead of Clause 22 MDIO access */ 523 phy_clause = soc_property_port_get(unit, port, spn_PORT_PHY_CLAUSE, 524 phy_clause); 525 526 if (phy_clause == 45) { 527 ext_pc.read = soc_esw_miimc45_read; 528 ext_pc.write = soc_esw_miimc45_write; 529 ext_pc.data_write = soc_esw_miimc45_data_write; 530 ext_pc.addr_write = soc_esw_miimc45_addr_write; 531 ext_pc.wb_write = soc_esw_miimc45_wb_write; 532 } else { 533 ext_pc.read = soc_esw_miim_read; 534 ext_pc.write = soc_esw_miim_write; 535 } 536 #ifdef INCLUDE_I2C 537 if (soc_property_port_get(unit, port, 538 spn_PHY_BUS_I2C, 0)) { 539 ext_pc.read = phy_i2c_miireg_read; 540 ext_pc.write = phy_i2c_miireg_write; 541 } 542 #endif 543 #endif /* BCM_ESW_SUPPORT */ 544 } 545 546 if (SOC_FUNCTIONS(unit) && SOC_FUNCTIONS(unit)->soc_sbus_mdio_write && 547 PHY_ADDR_INT(unit, port)) { 548 if (SOC_IS_SABER2(unit)) { 549 if (IS_XL_PORT(unit, port)) { 550 int_pc.read = soc_phy_sbus_read; 551 int_pc.write = soc_phy_sbus_write; 552 int_pc.wrmask = soc_phy_sbus_wrmask; 553 } 554 #if defined(BCM_GREYHOUND2_SUPPORT) 555 } else if (SOC_IS_GREYHOUND2(unit)) { 556 int pport = 0, blk = 0; 557 558 pport = SOC_INFO(unit).port_l2p_mapping[port]; 559 if (soc_greyhound2_sbus_tsc_block(unit, pport, &blk) != 560 SOC_E_PORT) { 561 /* no SOC_E_PORT return means SBus-MDIO can be served */ 562 int_pc.read = soc_phy_sbus_read; 563 int_pc.write = soc_phy_sbus_write; 564 int_pc.wrmask = soc_phy_sbus_wrmask; 565 } 566 #endif /* BCM_GREYHOUND2_SUPPORT */ 567 } else { 568 int_pc.read = soc_phy_sbus_read; 569 int_pc.write = soc_phy_sbus_write; 570 int_pc.wrmask = soc_phy_sbus_wrmask; 571 } 572 } 573 574 /* Check for software simulators */ 575 soc_phy_check_sim(unit, port, &int_pc); 576 577 SOC_IF_ERROR_RETURN 578 (soc_phy_probe(unit, port, &ext_pc, &int_pc)); 579 580 ext_pd = ext_pc.pd; 581 int_pd = int_pc.pd; 582 if (ext_pd == int_pd) { 583 /* If external PHY driver and internal PHY driver are the same, 584 * config setting must have override the PHY driver selection. 585 * In this case just attach internal PHY driver. 586 * Internal driver is needed for all devices with internal 587 * SerDes because MAC driver performs notify calls to internal 588 * PHY driver. 589 */ 590 ext_pd = NULL; 591 } 592 593 if (NULL != ext_pd) { 594 /* If there is allocated memory for 595 * external PHY driver, free it then re-alloc. 596 */ 597 if (NULL != EXT_PHY_SW_STATE(unit, port)) { 598 soc_phyctrl_free(EXT_PHY_SW_STATE(unit, port)); 599 EXT_PHY_SW_STATE(unit, port) = NULL; 600 } 601 if (NULL == EXT_PHY_SW_STATE(unit, port)) { 602 EXT_PHY_SW_STATE(unit, port) = 603 sal_alloc (sizeof (phy_ctrl_t) + ext_pc.size, ext_pd->drv_name); 604 if (NULL == EXT_PHY_SW_STATE(unit, port)) { 605 rv = SOC_E_MEMORY; 606 } 607 } 608 if (SOC_SUCCESS(rv)) { 609 pc = EXT_PHY_SW_STATE(unit, port); 610 sal_memcpy(pc, &ext_pc, sizeof(phy_ctrl_t)); 611 sal_memset(pc+1, 0, pc->size); 612 rv = soc_phy_reset_register(unit, port, pc->pd->pd_reset, 613 NULL, TRUE); 614 PHY_ADDR_TO_PORT(unit, PHY_ADDR(unit, port)) = port; 615 616 /* 617 * Make sure resolved port MDIO address is updated in CMIC external 618 * PHY address for hardware linkscan 619 */ 620 soc_linkscan_pause(unit); 621 622 rv = soc_linkscan_hw_port_update(unit, port); 623 624 soc_linkscan_continue(unit); 625 626 LOG_INFO(BSL_LS_SOC_PHY, 627 (BSL_META_U(unit, 628 "soc_phyctrl_probe external: u=%d p=%d %s\n"), 629 unit, port, ext_pd->drv_name)); 630 } 631 } else { 632 /* No external PHY detected. If there is allocated memory for 633 * external PHY driver, free it. 634 */ 635 if (NULL != EXT_PHY_SW_STATE(unit, port)) { 636 soc_phyctrl_free(EXT_PHY_SW_STATE(unit, port)); 637 EXT_PHY_SW_STATE(unit, port) = NULL; 638 } 639 } 640 641 if (SOC_SUCCESS(rv) && NULL != int_pd) { 642 if (NULL == INT_PHY_SW_STATE(unit, port)) { 643 INT_PHY_SW_STATE(unit, port) = 644 sal_alloc (sizeof (phy_ctrl_t) + int_pc.size, int_pd->drv_name); 645 if (NULL == INT_PHY_SW_STATE(unit, port)) { 646 rv = SOC_E_MEMORY; 647 } 648 } else { 649 phy_ctrl_t *ppc = INT_PHY_SW_STATE(unit, port); 650 if (ppc->driver_data && ppc->size == 0) { 651 /* If driver data allocated, must free it */ 652 sal_free(ppc->driver_data); 653 } 654 if (int_pc.size != ppc->size) { 655 soc_phyctrl_free(ppc); 656 INT_PHY_SW_STATE(unit, port) = 657 sal_alloc (sizeof (phy_ctrl_t) + int_pc.size, int_pd->drv_name); 658 if (NULL == INT_PHY_SW_STATE(unit, port)) { 659 rv = SOC_E_MEMORY; 660 } 661 } 662 } 663 if (SOC_SUCCESS(rv)) { 664 pc = INT_PHY_SW_STATE(unit, port); 665 sal_memcpy(pc, &int_pc, sizeof(phy_ctrl_t)); 666 sal_memset(pc+1, 0, pc->size); 667 PHY_ADDR_TO_PORT(unit, PHY_ADDR_INT(unit, port)) = port; 668 if (NULL == ext_pd) { 669 /* If there is no external PHY, the internal PHY 670 * must be in fiber mode. 671 */ 672 if (soc_property_port_get(unit, port, 673 spn_SERDES_FIBER_PREF, 1)) { 674 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER); 675 } else { 676 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER); 677 } 678 rv = soc_phy_reset_register(unit, port, pc->pd->pd_reset, 679 NULL, TRUE); 680 } 681 682 LOG_INFO(BSL_LS_SOC_PHY, 683 (BSL_META_U(unit, 684 "soc_phyctrl_probe internal: u=%d p=%d %s\n"), 685 unit, port, int_pd->drv_name)); 686 } 687 } else { 688 /* No internal PHY detected. If there is allocated memory for 689 * internal PHY driver, free it. 690 */ 691 if (NULL != INT_PHY_SW_STATE(unit, port)) { 692 phy_ctrl_t *ppc = INT_PHY_SW_STATE(unit, port); 693 if (ppc->driver_data && ppc->size == 0) { 694 /* If driver data allocated, must free it */ 695 sal_free(ppc->driver_data); 696 } 697 soc_phyctrl_free(ppc); 698 INT_PHY_SW_STATE(unit, port) = NULL; 699 } 700 } 701 702 703 704 if (SOC_SUCCESS(rv)) { 705 /* Set SOC related restriction/configuration/flags first */ 706 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_SGMII_AUTONEG); 707 if (soc_property_port_get(unit, port, spn_PHY_SGMII_AUTONEG, FALSE) && 708 soc_feature(unit, soc_feature_sgmii_autoneg)) { 709 710 PHY_FLAGS_SET(unit, port, PHY_FLAGS_SGMII_AUTONEG); 711 } 712 } else { 713 if (NULL != EXT_PHY_SW_STATE(unit, port)) { 714 soc_phyctrl_free(EXT_PHY_SW_STATE(unit, port)); 715 EXT_PHY_SW_STATE(unit, port) = NULL; 716 } 717 718 if (NULL != INT_PHY_SW_STATE(unit, port)) { 719 phy_ctrl_t *ppc = INT_PHY_SW_STATE(unit, port); 720 if (ppc->driver_data && ppc->size == 0) { 721 /* If driver data allocated, must free it */ 722 sal_free(ppc->driver_data); 723 } 724 soc_phyctrl_free(ppc); 725 INT_PHY_SW_STATE(unit, port) = NULL; 726 } 727 } 728 729 return rv; 730 } 731 732 soc_error_t 733 soc_phyctrl_set_speed_max(int unit, soc_port_t port, int speed_max) 734 { 735 phy_ctrl_t *int_pc; 736 phy_ctrl_t *ext_pc; 737 738 int_pc = INT_PHY_SW_STATE(unit, port); 739 ext_pc = EXT_PHY_SW_STATE(unit, port); 740 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 741 742 if (NULL != int_pc) { 743 int_pc->speed_max = speed_max; 744 } 745 if (NULL != ext_pc) { 746 ext_pc->speed_max = speed_max; 747 } 748 return SOC_E_NONE; 749 } 750 751 /* 752 * Function: 753 * soc_phyctrl_init 754 * Purpose: 755 * Initialize the PHY drivers attached to the port. 756 * Parameters: 757 * unit - SOC Unit #. 758 * port - Port number. 759 * Returns: 760 * SOC_E_XXX 761 */ 762 int 763 soc_phyctrl_init(int unit, soc_port_t port) 764 { 765 int rv; 766 phy_ctrl_t *int_pc; 767 phy_ctrl_t *ext_pc; 768 #ifdef BCM_SWITCHMACSEC_SUPPORT 769 uint32 switchmacsec_attached; 770 #endif /* BCM_SWITCHMACSEC_SUPPORT */ 771 #ifdef BCM_KATANA2_SUPPORT 772 uint32 rval=0; 773 #endif 774 775 LOG_VERBOSE(BSL_LS_SOC_PHY, 776 (BSL_META_U(unit, 777 "entered soc_phyctrl_init: " 778 "unit %d, port %d\n"), unit, port)); 779 780 int_pc = INT_PHY_SW_STATE(unit, port); 781 ext_pc = EXT_PHY_SW_STATE(unit, port); 782 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 783 784 { 785 #ifdef BCM_ESW_SUPPORT 786 if (SOC_IS_BRADLEY(unit)) { 787 PHY_FLAGS_SET(unit, port, PHY_FLAGS_SGMII_AUTONEG); 788 } 789 if (IS_LMD_ENABLED_PORT(unit, port)) { 790 PHY_FLAGS_SET(unit, port, PHY_FLAGS_SINGLE_LANE); 791 } 792 #endif /* BCM_ESW_SUPPORT */ 793 } 794 795 rv = SOC_E_NONE; 796 /* arbiter lock */ 797 INT_MCU_LOCK(unit); 798 if (NULL != int_pc) { 799 rv = (PHY_INIT(int_pc->pd, unit, port)); 800 } 801 802 if (NULL != ext_pc) { 803 rv = (PHY_INIT(ext_pc->pd, unit, port)); 804 if (!SOC_SUCCESS(rv)) { 805 LOG_ERROR(BSL_LS_SOC_PHY, 806 (BSL_META_U(unit, 807 "soc_phyctrl_probe: Init failed for" 808 " u=%d p=%d FAILED "), unit, port)); 809 return SOC_E_FAIL; 810 } 811 } 812 INT_MCU_UNLOCK(unit); 813 814 PHY_FLAGS_SET(unit, port, PHY_FLAGS_INIT_DONE); 815 816 PHYCTRL_VERBOSE(("soc_phyctrl_init: u=%d p=%d %s rv=%d\n", 817 unit, port, (ext_pc) ? "EXT" : "INT", rv)); 818 819 #ifdef BCM_KATANA2_SUPPORT 820 if (SOC_IS_KATANA2(unit) && !(SOC_IS_SABER2(unit))) { 821 /* To recover from clock glitch(not always), Serdes init sequence 822 requires write to reset frequency downsizer logic in MXQPORT. */ 823 SOC_IF_ERROR_RETURN(READ_XPORT_MODE_REGr(unit, port, &rval)); 824 soc_reg_field_set(unit, XPORT_MODE_REGr, &rval, SW_RESET_DOWNSIZERf , 1); 825 SOC_IF_ERROR_RETURN(WRITE_XPORT_MODE_REGr(unit, port, rval)); 826 soc_reg_field_set(unit, XPORT_MODE_REGr, &rval, SW_RESET_DOWNSIZERf , 0); 827 SOC_IF_ERROR_RETURN(WRITE_XPORT_MODE_REGr(unit, port, rval)); 828 829 if ((port == KT2_OLP_PORT) && (SOC_INFO(unit).olp_port[0])) { 830 SOC_IF_ERROR_RETURN(soc_phyctrl_auto_negotiate_set(unit, port, 0)); 831 SOC_IF_ERROR_RETURN(soc_phyctrl_speed_set(unit, port, 2500)); 832 } 833 } 834 #endif 835 836 #ifdef BCM_SWITCHMACSEC_SUPPORT 837 /* Switch_MACSEC init section. 838 * 839 * For the MACSEC-in-SWITCH solution, the attached PHY is expected as 840 * the PHY device without MACSEC feature. 841 * 842 * In the MACSEC-in-PHY solution, the MACSEC device is designed to be 843 * init as well through PHY driver init process. 844 * 845 * For MACSEC-in-Switch solution, the simular init procedure is provided 846 * through SOC driver, soc_switchmacsec_init(), which is exectued after 847 * nomal PHY driver for thsi port is attached and init. 848 */ 849 SOC_IF_ERROR_RETURN(soc_macsecphy_dev_info_get(unit, port, 850 SOC_MACSECPHY_DEV_INFO_SWITCHMACSEC_ATTACHED, 851 &switchmacsec_attached)); 852 853 if (switchmacsec_attached) { 854 rv = soc_switchmacsec_init(unit, port); 855 if (!SOC_SUCCESS(rv)) { 856 LOG_ERROR(BSL_LS_SOC_PHY, 857 (BSL_META_U(unit, 858 "Switch-MACSEC Init failed!u=%d p=%d rv=%d\n"), 859 unit, port, rv)); 860 } 861 } 862 #endif /* BCM_SWITCHMACSEC_SUPPORT */ 863 864 return rv; 865 } 866 867 STATIC int 868 soc_phyctrl_pd_get(int unit, soc_port_t port, phy_driver_t **pd) 869 { 870 phy_ctrl_t *int_pc; 871 phy_ctrl_t *ext_pc; 872 873 ext_pc = EXT_PHY_SW_STATE(unit, port); 874 int_pc = INT_PHY_SW_STATE(unit, port); 875 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 876 877 if (NULL != ext_pc) { 878 *pd = ext_pc->pd; 879 } else { 880 *pd = int_pc->pd; 881 } 882 883 return SOC_E_NONE; 884 } 885 886 STATIC int 887 soc_phyctrl_passthru_pd_get(int unit, soc_port_t port, phy_driver_t **pd) 888 { 889 phy_ctrl_t *int_pc; 890 phy_ctrl_t *ext_pc; 891 892 ext_pc = EXT_PHY_SW_STATE(unit, port); 893 int_pc = INT_PHY_SW_STATE(unit, port); 894 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 895 896 if (PHY_PASSTHRU_MODE(unit, port)) { 897 if (NULL != int_pc) { 898 *pd = int_pc->pd; 899 } else { 900 *pd = ext_pc->pd; 901 } 902 } else { 903 if (NULL != ext_pc) { 904 *pd = ext_pc->pd; 905 } else { 906 *pd = int_pc->pd; 907 } 908 } 909 910 return SOC_E_NONE; 911 } 912 913 int 914 soc_phyctrl_passthru_pc_get(int unit, soc_port_t port, phy_ctrl_t **pc) 915 { 916 phy_ctrl_t *int_pc; 917 phy_ctrl_t *ext_pc; 918 919 ext_pc = EXT_PHY_SW_STATE(unit, port); 920 int_pc = INT_PHY_SW_STATE(unit, port); 921 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 922 923 if (PHY_PASSTHRU_MODE(unit, port)) { 924 if (NULL != int_pc) { 925 *pc = int_pc; 926 } else { 927 *pc = ext_pc; 928 } 929 } else { 930 if (NULL != ext_pc) { 931 *pc = ext_pc; 932 } else { 933 *pc = int_pc; 934 } 935 } 936 937 return SOC_E_NONE; 938 } 939 940 int 941 soc_phyctrl_phyn_pc_get(int unit, soc_port_t port, int phyn, phy_ctrl_t **pc, 942 phy_ctrl_t **pc_ptr) 943 { 944 int phy_index = 0; 945 phy_ctrl_t *int_pc; 946 phy_ctrl_t *ext_pc; 947 948 ext_pc = EXT_PHY_SW_STATE(unit, port); 949 int_pc = INT_PHY_SW_STATE(unit, port); 950 951 /* Check if both int pc & ext pc are not zero */ 952 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 953 954 /* Start with int pc if != zero, otherwise start with ext pc */ 955 *pc_ptr = *pc = (int_pc) ? int_pc : ext_pc; 956 957 /* PHYN out of limit */ 958 if (phyn > SOC_PHYCTRL_PHYN_MAX_LIMIT) { 959 return SOC_E_PARAM; 960 } 961 962 /* Default */ 963 if (0 == phyn) { 964 SOC_IF_ERROR_RETURN 965 (soc_phyctrl_passthru_pc_get(unit, port, pc)); 966 *pc_ptr = *pc; 967 return SOC_E_NONE; 968 } 969 970 for (phy_index = 1; phy_index <= phyn; ++phy_index) { 971 972 if (phy_index == phyn) { 973 /* Found */ 974 if ((*pc_ptr != int_pc) && (*pc_ptr != ext_pc) && (*pc_ptr != NULL)) { 975 (*pc_ptr)->flags |= PHYCTRL_CHAINED_PHY_CTRL; 976 } 977 return SOC_E_NONE; 978 } 979 980 /* Go through internal phy chain */ 981 if (*pc == int_pc) { 982 if (PHY_IS_CHAINED(unit, port)) { 983 *pc_ptr = (*pc_ptr)->driver_data; 984 985 if (!(*pc_ptr)) { 986 if (ext_pc) { 987 /* End of int_phy phy chain. Move to ext phy */ 988 *pc_ptr = *pc = ext_pc; 989 continue; 990 } else { 991 /* End of phy chain. 992 Return default value i.e int phy in this case */ 993 *pc_ptr = *pc; 994 return SOC_E_NONE; 995 } 996 } 997 } else { 998 /* Not a chained internal phy, move onto external phy */ 999 *pc_ptr = *pc = ext_pc? ext_pc : int_pc; 1000 continue; 1001 } 1002 } 1003 1004 /* Go through external phy chain */ 1005 if ((*pc == ext_pc) && (PHY_IS_CHAINED(unit, port))) { 1006 *pc_ptr = (*pc_ptr)->driver_data; 1007 1008 if (!(*pc_ptr)) { 1009 /* End of ext_phy phy chain. 1010 Return default value i.e ext phy in this case */ 1011 *pc_ptr = *pc; 1012 return SOC_E_NONE; 1013 } 1014 } 1015 } 1016 return SOC_E_NONE; 1017 } 1018 1019 /* 1020 * Function: 1021 * soc_phyctrl_reset 1022 * Purpose: 1023 * Reset the PHY drivers attached to the port. 1024 * Parameters: 1025 * unit - SOC Unit #. 1026 * port - Port number. 1027 * Returns: 1028 * SOC_E_XXX 1029 */ 1030 int 1031 soc_phyctrl_reset(int unit, soc_port_t port, void *user_arg) 1032 { 1033 int rv; 1034 phy_driver_t *pd=NULL; 1035 1036 LOG_VERBOSE(BSL_LS_SOC_PHY, 1037 (BSL_META_U(unit, 1038 "entered soc_phyctrl_reset: " 1039 "unit %d, port %d\n"), unit, port)); 1040 1041 rv = soc_phyctrl_pd_get(unit, port, &pd); 1042 1043 INT_MCU_LOCK(unit); 1044 if (SOC_SUCCESS(rv)) { 1045 rv = (PHY_RESET(pd, unit, port)); 1046 } 1047 INT_MCU_UNLOCK(unit); 1048 1049 if (SOC_FAILURE(rv)) { 1050 PHYCTRL_WARN(("soc_phyctrl_reset: u=%d p=%d rv=%d\n", 1051 unit, port, rv)); 1052 } 1053 return rv; 1054 } 1055 1056 /* 1057 * Function: 1058 * soc_phyctrl_drv_name 1059 * Purpose: 1060 * Get pointer to driver name. 1061 * Parameters: 1062 * unit - SOC Unit #. 1063 * port - Port number. 1064 * name - driver name. 1065 * Returns: 1066 * SOC_E_XXX 1067 */ 1068 char * 1069 soc_phyctrl_drv_name(int unit, soc_port_t port) 1070 { 1071 int rv; 1072 phy_driver_t *pd=NULL; 1073 1074 LOG_VERBOSE(BSL_LS_SOC_PHY, 1075 (BSL_META_U(unit, 1076 "entered soc_phyctrl_drv_name: " 1077 "unit %d, port %d\n"), unit, port)); 1078 1079 rv = soc_phyctrl_pd_get(unit, port, &pd); 1080 1081 if (SOC_SUCCESS(rv)) { 1082 return pd->drv_name; 1083 } 1084 return NULL; 1085 } 1086 1087 1088 /* 1089 * Function: 1090 * soc_phyctrl_link_get 1091 * Purpose: 1092 * Read link status of the PHY driver. 1093 * Parameters: 1094 * unit - SOC Unit #. 1095 * port - Port number. 1096 * link - Link status 1097 * Returns: 1098 * SOC_E_XXX 1099 */ 1100 int 1101 soc_phyctrl_link_get(int unit, soc_port_t port, int *link) 1102 { 1103 int rv; 1104 phy_driver_t *pd=NULL; 1105 phy_ctrl_t *int_pc; 1106 1107 int_pc = INT_PHY_SW_STATE(unit, port); 1108 1109 SOC_NULL_PARAM_CHECK(link); 1110 1111 LOG_VERBOSE(BSL_LS_SOC_PHY, 1112 (BSL_META_U(unit, 1113 "entered soc_phyctrl_link_get: " 1114 "unit %d, port %d\n"), unit, port)); 1115 1116 *link = FALSE; 1117 1118 rv = soc_phyctrl_pd_get(unit, port, &pd); 1119 1120 INT_MCU_LOCK(unit); 1121 1122 /* Handles cases where internal phy's link_get 1123 needs to be called for linkscan(link_get) based 1124 tasks that need processing context. 1125 NOTE- Not being used for link status. 1126 */ 1127 if (SOC_SUCCESS(rv) 1128 && (int_pc != NULL)) { 1129 if ((int_pc->pd != pd) 1130 && PHY_FLAGS_TST(unit, port, PHY_FLAGS_SERVICE_INT_PHY_LINK_GET) 1131 && !PHY_FLAGS_TST(unit, port, PHY_FLAGS_REPEATER) 1132 && !PHY_FLAGS_TST(unit, port, PHY_FLAGS_PASSTHRU)) { 1133 /* Passthru/Repeater devices such as 84328 call 1134 internal phy's link_get on their own. 1135 */ 1136 rv = (PHY_LINK_GET(int_pc->pd, unit, port, link)); 1137 } 1138 } 1139 1140 if (SOC_SUCCESS(rv)) { 1141 rv = (PHY_LINK_GET(pd, unit, port, link)); 1142 } 1143 INT_MCU_UNLOCK(unit); 1144 1145 if (SOC_FAILURE(rv)) { 1146 PHYCTRL_WARN(("soc_phyctrl_link_get failed %d\n", rv)); 1147 } 1148 1149 return rv; 1150 } 1151 1152 1153 /* 1154 * Function: 1155 * soc_phyctrl_linkfault_get 1156 * Purpose: 1157 * Read fault status of the PHY driver. 1158 * This is used for external PHYs where the fault status is not propagated to the switch 1159 * Parameters: 1160 * unit - SOC Unit #. 1161 * port - Port number. 1162 * fault - fault status 1163 * Returns: 1164 * SOC_E_XXX 1165 */ 1166 int 1167 soc_phyctrl_linkfault_get(int unit, soc_port_t port, int *fault) 1168 { 1169 int rv; 1170 phy_driver_t *pd=NULL; 1171 1172 SOC_NULL_PARAM_CHECK(fault); 1173 1174 LOG_VERBOSE(BSL_LS_SOC_PHY, 1175 (BSL_META_U(unit, 1176 "entered soc_phyctrl_linkfault_get: " 1177 "unit %d, port %d\n"), unit, port)); 1178 1179 *fault = FALSE; 1180 1181 rv = soc_phyctrl_pd_get(unit, port, &pd); 1182 1183 INT_MCU_LOCK(unit); 1184 1185 if (SOC_SUCCESS(rv)) { 1186 rv = (PHY_LINKFAULT_GET(pd, unit, port, fault)); 1187 } 1188 INT_MCU_UNLOCK(unit); 1189 1190 if (SOC_FAILURE(rv)) { 1191 PHYCTRL_WARN(("soc_phyctrl_linkfault_get failed %d\n", rv)); 1192 } 1193 1194 return rv; 1195 } 1196 1197 /* 1198 * Function: 1199 * soc_phyctrl_enable_set 1200 * Purpose: 1201 * Enable/Disable the PHY driver attached to the port. 1202 * Parameters: 1203 * unit - SOC Unit #. 1204 * port - Port number. 1205 * enable - enable/disable PHY driver 1206 * Returns: 1207 * SOC_E_XXX 1208 */ 1209 int 1210 soc_phyctrl_enable_set(int unit, soc_port_t port, int enable) 1211 { 1212 int rv1 = SOC_E_NONE, rv2 = SOC_E_NONE; 1213 phy_ctrl_t *int_pc; 1214 phy_ctrl_t *ext_pc; 1215 phy_driver_t *pd=NULL; 1216 1217 LOG_VERBOSE(BSL_LS_SOC_PHY, 1218 (BSL_META_U(unit, 1219 "entered soc_phyctrl_enable_set: " 1220 "unit %d, port %d, enable %d\n"), unit, port, enable)); 1221 1222 ext_pc = EXT_PHY_SW_STATE(unit, port); 1223 int_pc = INT_PHY_SW_STATE(unit, port); 1224 1225 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 1226 1227 INT_MCU_LOCK(unit); 1228 if (ext_pc != NULL) { 1229 if (enable && (int_pc != NULL)) { /* for plugin ext. PHYs */ 1230 pd = int_pc->pd; 1231 rv2 = (PHY_ENABLE_SET(pd, unit, port, enable)); 1232 } 1233 pd = ext_pc->pd; 1234 rv1 = (PHY_ENABLE_SET(pd, unit, port, enable)); 1235 } else { 1236 pd = int_pc->pd; 1237 rv2 = (PHY_ENABLE_SET(pd, unit, port, enable)); 1238 } 1239 1240 INT_MCU_UNLOCK(unit); 1241 1242 if (SOC_FAILURE(rv1) || SOC_FAILURE(rv2)) { 1243 PHYCTRL_WARN(("soc_phyctrl_enable_set: u=%d p=%d e=%d rv1=%d rv2=%d\n", 1244 unit, port, enable, rv1, rv2)); 1245 return rv1 ? rv1 : rv2; 1246 } 1247 1248 return SOC_E_NONE; 1249 } 1250 1251 /* 1252 * Function: 1253 * soc_phyctrl_enable_get 1254 * Purpose: 1255 * Get the enable/disable state of the PHY driver. 1256 * Parameters: 1257 * unit - SOC Unit #. 1258 * port - Port number. 1259 * enable - Current enable/disable state. 1260 * Returns: 1261 * SOC_E_XXX 1262 */ 1263 int 1264 soc_phyctrl_enable_get(int unit, soc_port_t port, int *enable) 1265 { 1266 phy_driver_t *pd = NULL; 1267 int rv; 1268 1269 SOC_NULL_PARAM_CHECK(enable); 1270 1271 LOG_VERBOSE(BSL_LS_SOC_PHY, 1272 (BSL_META_U(unit, 1273 "entered soc_phyctrl_enable_get: " 1274 "unit %d, port %d\n"), unit, port)); 1275 1276 rv = soc_phyctrl_passthru_pd_get(unit, port, &pd); 1277 1278 INT_MCU_LOCK(unit); 1279 if (SOC_SUCCESS(rv)) { 1280 rv = (PHY_ENABLE_GET(pd, unit, port, enable)); 1281 } 1282 INT_MCU_UNLOCK(unit); 1283 1284 if (SOC_FAILURE(rv)) { 1285 PHYCTRL_WARN(("soc_phyctrl_enable_get failed %d\n", rv)); 1286 } 1287 1288 return rv; 1289 } 1290 1291 /* 1292 * Function: 1293 * soc_phyctrl_duplex_set 1294 * Purpose: 1295 * Set duplex of the PHY. 1296 * Parameters: 1297 * unit - SOC Unit #. 1298 * port - Port number. 1299 * duplex - (1) Full duplex 1300 * (0) Half duplex 1301 * Returns: 1302 * SOC_E_XXX 1303 */ 1304 int 1305 soc_phyctrl_duplex_set(int unit, soc_port_t port, int duplex) 1306 { 1307 int rv; 1308 phy_driver_t *pd=NULL; 1309 1310 LOG_VERBOSE(BSL_LS_SOC_PHY, 1311 (BSL_META_U(unit, 1312 "entered soc_phyctrl_duplex_set: " 1313 "unit %d, port %d, duplex %d\n"), unit, port, duplex)); 1314 1315 rv = soc_phyctrl_pd_get(unit, port, &pd); 1316 1317 INT_MCU_LOCK(unit); 1318 if (SOC_SUCCESS(rv)) { 1319 rv = (PHY_DUPLEX_SET(pd, unit, port, duplex)); 1320 } 1321 INT_MCU_UNLOCK(unit); 1322 1323 if (SOC_FAILURE(rv)) { 1324 PHYCTRL_WARN(("soc_phyctrl_duplex_set: u=%d p=%d d=%d rv=%d\n", 1325 unit, port, duplex, rv)); 1326 } 1327 1328 return rv; 1329 } 1330 1331 /* 1332 * Function: 1333 * soc_phyctrl_duplex_get 1334 * Purpose: 1335 * Get current duplex setting of the PHY 1336 * Parameters: 1337 * unit - SOC Unit #. 1338 * port - Port number. 1339 * duplex - (1) Full duplex 1340 * (0) Half duplex 1341 * Returns: 1342 * SOC_E_XXX 1343 */ 1344 int 1345 soc_phyctrl_duplex_get(int unit, soc_port_t port, int *duplex) 1346 { 1347 int rv; 1348 phy_driver_t *pd=NULL; 1349 1350 LOG_VERBOSE(BSL_LS_SOC_PHY, 1351 (BSL_META_U(unit, 1352 "entered soc_phyctrl_duplex_get: " 1353 "unit %d, port %d\n"), unit, port)); 1354 1355 rv = soc_phyctrl_pd_get(unit, port, &pd); 1356 1357 INT_MCU_LOCK(unit); 1358 if (SOC_SUCCESS(rv)) { 1359 rv = (PHY_DUPLEX_GET(pd, unit, port, duplex)); 1360 } 1361 INT_MCU_UNLOCK(unit); 1362 1363 if (SOC_FAILURE(rv)) { 1364 PHYCTRL_WARN(("soc_phyctrl_duplex_get: u=%d p=%d rv=%d\n", 1365 unit, port, rv)); 1366 } 1367 return rv; 1368 } 1369 1370 /* 1371 * Function: 1372 * soc_phyctrl_speed_set 1373 * Purpose: 1374 * Set PHY speed. 1375 * Parameters: 1376 * unit - SOC Unit #. 1377 * port - Port number. 1378 * speed - new speed of the PHY 1379 * Returns: 1380 * SOC_E_XXX 1381 */ 1382 int 1383 soc_phyctrl_speed_set(int unit, soc_port_t port, int speed) 1384 { 1385 int rv; 1386 phy_driver_t *pd=NULL; 1387 1388 LOG_VERBOSE(BSL_LS_SOC_PHY, 1389 (BSL_META_U(unit, 1390 "entered soc_phyctrl_speed_set: " 1391 "unit %d, port %d, speed %d\n"), unit, port, speed)); 1392 1393 rv = soc_phyctrl_pd_get(unit, port, &pd); 1394 1395 INT_MCU_LOCK(unit); 1396 if (SOC_SUCCESS(rv)) { 1397 rv = (PHY_SPEED_SET(pd, unit, port, speed)); 1398 } 1399 INT_MCU_UNLOCK(unit); 1400 1401 if (SOC_FAILURE(rv)) { 1402 PHYCTRL_WARN(("soc_phyctrl_speed_set: u=%d p=%d s=%d rv=%d\n", 1403 unit, port, speed, rv)); 1404 } 1405 return rv; 1406 } 1407 1408 /* 1409 * Function: 1410 * soc_phyctrl_speed_get 1411 * Purpose: 1412 * Read current PHY speed 1413 * Parameters: 1414 * unit - SOC Unit #. 1415 * port - Port number. 1416 * speed - Current speed of PHY. 1417 * Returns: 1418 * SOC_E_XXX 1419 */ 1420 int 1421 soc_phyctrl_speed_get(int unit, soc_port_t port, int *speed) 1422 { 1423 int rv; 1424 phy_driver_t *pd = NULL; 1425 1426 SOC_NULL_PARAM_CHECK(speed); 1427 1428 LOG_VERBOSE(BSL_LS_SOC_PHY, 1429 (BSL_META_U(unit, 1430 "entered soc_phyctrl_speed_get: " 1431 "unit %d, port %d\n"), unit, port)); 1432 1433 *speed = 0; 1434 1435 rv = soc_phyctrl_passthru_pd_get(unit, port, &pd); 1436 1437 INT_MCU_LOCK(unit); 1438 if (SOC_SUCCESS(rv)) { 1439 rv = (PHY_SPEED_GET(pd, unit, port, speed)); 1440 } 1441 INT_MCU_UNLOCK(unit); 1442 1443 if (SOC_FAILURE(rv)) { 1444 PHYCTRL_WARN(("soc_phyctrl_speed_get failed %d\n", rv)); 1445 } 1446 return rv; 1447 } 1448 1449 /* 1450 * Function: 1451 * soc_phyctrl_master_set 1452 * Purpose: 1453 * Ser Master/Slave configuration of the PHY. 1454 * Parameters: 1455 * unit - SOC Unit #. 1456 * port - Port number. 1457 * master - (1) master mode. 1458 * (0) slave mode. 1459 * Returns: 1460 * SOC_E_XXX 1461 */ 1462 int 1463 soc_phyctrl_master_set(int unit, soc_port_t port, int master) 1464 { 1465 int rv; 1466 phy_driver_t *pd=NULL; 1467 1468 LOG_VERBOSE(BSL_LS_SOC_PHY, 1469 (BSL_META_U(unit, 1470 "entered soc_phyctrl_master_set: " 1471 "unit %d, port %d, master %d\n"), unit, port, master)); 1472 1473 rv = soc_phyctrl_pd_get(unit, port, &pd); 1474 1475 INT_MCU_LOCK(unit); 1476 if (SOC_SUCCESS(rv)) { 1477 rv = (PHY_MASTER_SET(pd, unit, port, master)); 1478 } 1479 INT_MCU_UNLOCK(unit); 1480 1481 if (SOC_FAILURE(rv)) { 1482 PHYCTRL_WARN(("soc_phyctrl_master_set: u=%d p=%d m=%d rv=%d\n", 1483 unit, port, master, rv)); 1484 } 1485 return rv; 1486 } 1487 1488 /* 1489 * Function: 1490 * soc_phyctrl_master_get 1491 * Purpose: 1492 * Read current Master/Slave setting 1493 * Parameters: 1494 * unit - SOC Unit #. 1495 * port - Port number. 1496 * master - (1) master mode. 1497 * (0) slave mode. 1498 * Returns: 1499 * SOC_E_XXX 1500 */ 1501 int 1502 soc_phyctrl_master_get(int unit, soc_port_t port, int *master) 1503 { 1504 int rv; 1505 phy_driver_t *pd = NULL; 1506 1507 SOC_NULL_PARAM_CHECK(master); 1508 1509 LOG_VERBOSE(BSL_LS_SOC_PHY, 1510 (BSL_META_U(unit, 1511 "entered soc_phyctrl_master_get: " 1512 "unit %d, port %d\n"), unit, port)); 1513 1514 rv = soc_phyctrl_passthru_pd_get(unit, port, &pd); 1515 1516 INT_MCU_LOCK(unit); 1517 if (SOC_SUCCESS(rv)) { 1518 rv = (PHY_MASTER_GET(pd, unit, port, master)); 1519 } 1520 INT_MCU_UNLOCK(unit); 1521 1522 if (SOC_FAILURE(rv)) { 1523 PHYCTRL_WARN(("soc_phyctrl_master_get failed %d\n", rv)); 1524 } 1525 return rv; 1526 } 1527 1528 /* 1529 * Function: 1530 * soc_phyctrl_auto_negotiate_set 1531 * Purpose: 1532 * Enable/Disable autonegotiation of the PHY 1533 * Parameters: 1534 * unit - SOC Unit #. 1535 * port - Port number. 1536 * an - new autoneg setting 1537 * Returns: 1538 * SOC_E_XXX 1539 */ 1540 int 1541 soc_phyctrl_auto_negotiate_set(int unit, soc_port_t port, int an) 1542 { 1543 int rv; 1544 phy_driver_t *pd=NULL; 1545 1546 LOG_VERBOSE(BSL_LS_SOC_PHY, 1547 (BSL_META_U(unit, 1548 "entered soc_phyctrl_auto_negotiate_set: " 1549 "unit %d, port %d, an %d\n"), unit, port, an)); 1550 1551 rv = soc_phyctrl_pd_get(unit, port, &pd); 1552 1553 INT_MCU_LOCK(unit); 1554 if (SOC_SUCCESS(rv)) { 1555 rv = (PHY_AUTO_NEGOTIATE_SET(pd, unit, port, an)); 1556 } 1557 INT_MCU_UNLOCK(unit); 1558 1559 if (SOC_FAILURE(rv)) { 1560 PHYCTRL_WARN(("soc_phyctrl_auto_negotiate_set: u=%d p=%d an=%d rv=%d\n", 1561 unit, port, an, rv)); 1562 } 1563 1564 return rv; 1565 } 1566 1567 /* 1568 * Function: 1569 * soc_phyctrl_redirect_auto_negotiate_set 1570 * Purpose: 1571 * Enable/Disable autonegotiation for PHY specific port 1572 * Parameters: 1573 * unit - SOC Unit #. 1574 * port - Port number. 1575 * phyn - Phy number 1576 * phy_lane - Lane number 1577 * sys - Control set to be applied 1578 * on system side(1)or line side(0). 1579 * an - new autoneg setting 1580 * Returns: 1581 * SOC_E_XXX 1582 */ 1583 int 1584 soc_phyctrl_redirect_auto_negotiate_set(int unit, soc_port_t port, int phyn, 1585 int phy_lane, int sys_side, int an) 1586 { 1587 int rv; 1588 /* 1589 If chained phy, pc_ptr points to the pc of chained phy. Otherwise 1590 to int/ext phy. 1591 */ 1592 phy_ctrl_t *pc_ptr = NULL; 1593 1594 /* 1595 Either chanied phy or directly attached, pc_head points to the 1596 *pc of head of the phy chain i.e int/ext phy. 1597 */ 1598 phy_ctrl_t *pc_head = NULL; 1599 1600 1601 /*phyn - int/ext/chained*/ 1602 rv = soc_phyctrl_phyn_pc_get (unit, port, phyn, &pc_head, &pc_ptr); 1603 if (SOC_FAILURE(rv)) { 1604 PHYCTRL_WARN(("soc_phyctrl_redirect_auto_negotiate_set failed: " 1605 "u=%d p=%d an=%d rv=%d\n", 1606 unit, port, an, rv)); 1607 } 1608 1609 /* sys_side */ 1610 pc_ptr->flags |= (sys_side ? PHYCTRL_SYS_SIDE_CTRL:0); 1611 1612 INT_MCU_LOCK(unit); 1613 if (SOC_SUCCESS(rv)) { 1614 rv = (PHY_AUTO_NEGOTIATE_SET(pc_head->pd, unit, port, an)); 1615 } 1616 INT_MCU_UNLOCK(unit); 1617 1618 /* Clear flags set earlier for PHY_CONTROL_SET(). Clear them anyway..*/ 1619 pc_ptr->flags &= ~PHYCTRL_CHAINED_PHY_CTRL; 1620 pc_ptr->flags &= ~PHYCTRL_SYS_SIDE_CTRL; 1621 1622 if (SOC_FAILURE(rv)) { 1623 PHYCTRL_WARN(("soc_phyctrl_redirect_auto_negotiate_set: " 1624 "u=%d p=%d an=%d rv=%d\n", 1625 unit, port, an, rv)); 1626 } 1627 1628 return rv; 1629 } 1630 1631 /* 1632 * Function: 1633 * soc_phyctrl_auto_negotiate_get 1634 * Purpose: 1635 * Get current auto neg setting 1636 * Parameters: 1637 * unit - SOC Unit #. 1638 * port - Port number. 1639 * an - current autoneg setting 1640 * an_done - autoneg completed 1641 * Returns: 1642 * SOC_E_XXX 1643 */ 1644 int 1645 soc_phyctrl_auto_negotiate_get(int unit, soc_port_t port, int *an, int *an_done) 1646 { 1647 int rv; 1648 phy_driver_t *pd = NULL; 1649 1650 SOC_NULL_PARAM_CHECK(an); 1651 SOC_NULL_PARAM_CHECK(an_done); 1652 1653 LOG_VERBOSE(BSL_LS_SOC_PHY, 1654 (BSL_META_U(unit, 1655 "entered soc_phyctrl_auto_negotiate_get: " 1656 "unit %d, port %d\n"), 1657 unit, port)); 1658 1659 rv = soc_phyctrl_passthru_pd_get(unit, port, &pd); 1660 INT_MCU_LOCK(unit); 1661 if (SOC_SUCCESS(rv)) { 1662 rv = (PHY_AUTO_NEGOTIATE_GET(pd, unit, port, an, an_done)); 1663 } 1664 INT_MCU_UNLOCK(unit); 1665 if (SOC_FAILURE(rv)) { 1666 PHYCTRL_WARN(("soc_phyctrl_auto_negotiate_get failed %d\n", 1667 rv)); 1668 } 1669 return rv; 1670 } 1671 1672 /* 1673 * Function: 1674 * soc_phyctrl_redirect_auto_negotiate_get 1675 * Purpose: 1676 * Get current autonegotiation settings for PHY specific port 1677 * Parameters: 1678 * unit - SOC Unit #. 1679 * port - Port number. 1680 * phyn - Phy number 1681 * phy_lane - Lane number 1682 * sys - Control set to be applied 1683 * on system side(1)or line side(0). 1684 * an - current autoneg setting 1685 * an_done - autoneg completed 1686 * Returns: 1687 * SOC_E_XXX 1688 */ 1689 int 1690 soc_phyctrl_redirect_auto_negotiate_get(int unit, soc_port_t port, int phyn, 1691 int phy_lane, int sys_side, int *an, 1692 int *an_done) 1693 { 1694 int rv; 1695 /* 1696 If chained phy, pc_ptr points to the pc of chained phy. Otherwise 1697 to int/ext phy. 1698 */ 1699 phy_ctrl_t *pc_ptr = NULL; 1700 1701 /* 1702 Either chanied phy or directly attached, pc_head points to the 1703 *pc of head of the phy chain i.e int/ext phy. 1704 */ 1705 phy_ctrl_t *pc_head = NULL; 1706 1707 1708 /*phyn - int/ext/chained*/ 1709 rv = soc_phyctrl_phyn_pc_get(unit, port, phyn, &pc_head, &pc_ptr); 1710 if (SOC_FAILURE(rv)) { 1711 PHYCTRL_WARN(("soc_phyctrl_redirect_auto_negotiate_get failed %d\n", 1712 rv)); 1713 } 1714 1715 /* sys_side */ 1716 pc_ptr->flags |= (sys_side ? PHYCTRL_SYS_SIDE_CTRL:0); 1717 1718 INT_MCU_LOCK(unit); 1719 if (SOC_SUCCESS(rv)) { 1720 rv = (PHY_AUTO_NEGOTIATE_GET(pc_head->pd, unit, port, an, an_done)); 1721 } 1722 INT_MCU_UNLOCK(unit); 1723 1724 /* Clear flags set earlier for PHY_CONTROL_SET(). Clear them anyway..*/ 1725 pc_ptr->flags &= ~PHYCTRL_CHAINED_PHY_CTRL; 1726 pc_ptr->flags &= ~PHYCTRL_SYS_SIDE_CTRL; 1727 1728 if (SOC_FAILURE(rv)) { 1729 PHYCTRL_WARN(("soc_phyctrl_redirect_auto_negotiate_get failed %d\n", 1730 rv)); 1731 } 1732 1733 return rv; 1734 } 1735 1736 /* 1737 * Function: 1738 * soc_phyctrl_adv_local_set 1739 * Purpose: 1740 * Configure local advertising setting. 1741 * Parameters: 1742 * unit - SOC Unit #. 1743 * port - Port number. 1744 * mode - Advertising mode 1745 * Returns: 1746 * SOC_E_XXX 1747 */ 1748 int 1749 soc_phyctrl_adv_local_set(int unit, soc_port_t port, soc_port_mode_t mode) 1750 { 1751 int rv; 1752 phy_driver_t *pd = NULL; 1753 soc_port_ability_t ability; 1754 1755 LOG_VERBOSE(BSL_LS_SOC_PHY, 1756 (BSL_META_U(unit, 1757 "entered soc_phyctrl_adv_local_set: " 1758 "unit %d, port %d, mode %d\n"), unit, port, mode)); 1759 1760 rv = soc_phyctrl_passthru_pd_get(unit, port, &pd); 1761 1762 INT_MCU_LOCK(unit); 1763 if (SOC_SUCCESS(rv)) { 1764 rv = (PHY_ADV_SET(pd, unit, port, mode)); 1765 if (SOC_E_UNAVAIL == rv) { 1766 rv = PHY_ABILITY_ADVERT_GET(pd, unit, port, &ability); /* Read the currently configured value. 1767 So attributes are not available from *_PA_* */ 1768 if (SOC_SUCCESS(rv)) { 1769 rv = soc_port_mode_to_ability(mode, &ability); 1770 if (SOC_SUCCESS(rv)) { 1771 rv = (PHY_ABILITY_ADVERT_SET(pd, unit, port, &ability)); 1772 } 1773 } 1774 } 1775 } 1776 INT_MCU_UNLOCK(unit); 1777 1778 if (SOC_FAILURE(rv)) { 1779 PHYCTRL_WARN(("soc_phyctrl_adv_local_set: u=%d p=%d " 1780 "m=%x rv=%d\n", unit, port, mode, rv)); 1781 } 1782 return rv; 1783 } 1784 1785 /* 1786 * Function: 1787 * soc_phyctrl_adv_local_get 1788 * Purpose: 1789 * Get current local advertising setting 1790 * Parameters: 1791 * unit - SOC Unit #. 1792 * port - Port number. 1793 * mode - Current advertised mode. 1794 * Returns: 1795 * SOC_E_XXX 1796 */ 1797 int 1798 soc_phyctrl_adv_local_get(int unit, soc_port_t port, soc_port_mode_t *mode) 1799 { 1800 int rv; 1801 phy_driver_t *pd = NULL; 1802 soc_port_ability_t ability; 1803 1804 SOC_NULL_PARAM_CHECK(mode); 1805 1806 LOG_VERBOSE(BSL_LS_SOC_PHY, 1807 (BSL_META_U(unit, 1808 "entered soc_phyctrl_adv_local_get: " 1809 "unit %d, port %d\n"), unit, port)); 1810 1811 rv = soc_phyctrl_passthru_pd_get(unit, port, &pd); 1812 1813 INT_MCU_LOCK(unit); 1814 if (SOC_SUCCESS(rv)) { 1815 rv = (PHY_ADV_GET(pd, unit, port, mode)); 1816 if (rv == SOC_E_UNAVAIL) { 1817 rv = (PHY_ABILITY_ADVERT_GET(pd, unit, port, &ability)); 1818 if (SOC_SUCCESS(rv)) { 1819 rv = soc_port_ability_to_mode(&ability, mode); 1820 } 1821 } 1822 } 1823 INT_MCU_UNLOCK(unit); 1824 1825 if (SOC_FAILURE(rv)) { 1826 PHYCTRL_WARN(("soc_phyctrl_adv_local_get failed %d\n", rv)); 1827 } 1828 return rv; 1829 } 1830 1831 /* 1832 * Function: 1833 * soc_phyctrl_adv_remote_get 1834 * Purpose: 1835 * Get link partner advertised mode 1836 * Parameters: 1837 * unit - SOC Unit #. 1838 * port - Port number. 1839 * mode - Link partner advertised mode 1840 * Returns: 1841 * SOC_E_XXX 1842 */ 1843 int 1844 soc_phyctrl_adv_remote_get(int unit, soc_port_t port, soc_port_mode_t *mode) 1845 { 1846 int rv; 1847 phy_driver_t *pd = NULL; 1848 soc_port_ability_t ability; 1849 1850 SOC_NULL_PARAM_CHECK(mode); 1851 1852 LOG_VERBOSE(BSL_LS_SOC_PHY, 1853 (BSL_META_U(unit, 1854 "entered soc_phyctrl_adv_remote_get: " 1855 "unit %d, port %d\n"), unit, port)); 1856 1857 rv = soc_phyctrl_passthru_pd_get(unit, port, &pd); 1858 INT_MCU_LOCK(unit); 1859 if (SOC_SUCCESS(rv)) { 1860 rv = (PHY_ADV_REMOTE_GET(pd, unit, port, mode)); 1861 1862 if (rv == SOC_E_UNAVAIL) { 1863 rv = (PHY_ABILITY_REMOTE_GET(pd, unit, port, &ability)); 1864 if (SOC_SUCCESS(rv)) { 1865 rv = soc_port_ability_to_mode(&ability, mode); 1866 } 1867 } 1868 } 1869 INT_MCU_UNLOCK(unit); 1870 if (SOC_FAILURE(rv)) { 1871 PHYCTRL_WARN(("soc_phyctrl_adv_remote_get failed %d\n", rv)); 1872 } 1873 1874 return rv; 1875 } 1876 1877 /* 1878 * Function: 1879 * soc_phyctrl_loopback_set 1880 * Purpose: 1881 * Enable/disable loopback mode. 1882 * Parameters: 1883 * unit - SOC Unit #. 1884 * port - Port number. 1885 * enable - (1) Enable loopback mode. 1886 * (0) Disable loopback mode. 1887 * serdes_linkup_wait - (1) Wait for Linkup for serdes 1888 * (0) Don't wait for Linkup 1889 * Returns: 1890 * SOC_E_XXX 1891 */ 1892 int 1893 soc_phyctrl_loopback_set(int unit, soc_port_t port, int enable, int serdes_linkup_wait) 1894 { 1895 int rv; 1896 int port_enable; 1897 phy_ctrl_t *int_pc; 1898 phy_ctrl_t *ext_pc; 1899 phy_driver_t *pd; 1900 1901 LOG_VERBOSE(BSL_LS_SOC_PHY, 1902 (BSL_META_U(unit, 1903 "entered soc_phyctrl_loopback_set: " 1904 "unit %d, port %d, enable %d\n"), unit, port, enable)); 1905 1906 rv = SOC_E_NONE; 1907 int_pc = INT_PHY_SW_STATE(unit, port); 1908 ext_pc = EXT_PHY_SW_STATE(unit, port); 1909 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 1910 1911 if (NULL != ext_pc) { 1912 pd = ext_pc->pd; 1913 } else { 1914 pd = int_pc->pd; 1915 } 1916 INT_MCU_LOCK(unit); 1917 rv = (PHY_LOOPBACK_SET(pd, unit, port, enable)); 1918 if (SOC_SUCCESS(rv)) { 1919 rv = PHY_ENABLE_GET(pd, unit, port, &port_enable); 1920 } 1921 1922 if (serdes_linkup_wait && !SOC_IS_SAND(unit) && 1923 !SOC_IS_TRIUMPH3(unit)) { 1924 if (SOC_SUCCESS(rv) && enable && (NULL != int_pc) && (port_enable)) { 1925 if ((PHY_PASSTHRU_MODE(unit, port)) || (NULL == ext_pc)) { 1926 int link; 1927 soc_timeout_t to; 1928 1929 /* Wait up to 5000 msec for link up */ 1930 soc_timeout_init(&to, 5000000, 0); 1931 link = 0; 1932 /* 1933 * Needs more than one read to clear Latched Link down bits. 1934 */ 1935 rv = (PHY_LINK_GET(int_pc->pd, unit, port, &link)); 1936 do { 1937 rv = (PHY_LINK_GET(int_pc->pd, unit, port, &link)); 1938 if (link || SOC_FAILURE(rv)) { 1939 break; 1940 } 1941 } while (!soc_timeout_check(&to)); 1942 if (!link) { 1943 LOG_WARN(BSL_LS_SOC_PHY, 1944 (BSL_META_U(unit, 1945 "soc_phyctrl_loopback_set: u=%d p=%d TIMEOUT\n"), 1946 unit, port)); 1947 rv = SOC_E_TIMEOUT; 1948 } 1949 } 1950 } 1951 } 1952 INT_MCU_UNLOCK(unit); 1953 1954 if (SOC_FAILURE(rv)) { 1955 PHYCTRL_WARN(("soc_phyctrl_loopback_set: u=%d p=%d l=%d rv=%d\n", 1956 unit, port, enable, rv)); 1957 } 1958 1959 return rv; 1960 } 1961 1962 /* 1963 * Function: 1964 * soc_phyctrl_redirect_loopback_set 1965 * Purpose: 1966 * Enable/disable loopback mode. 1967 * Parameters: 1968 * unit - SOC Unit #. 1969 * port - Port number. 1970 * phyn - Phy number 1971 * phy_lane - Lane number 1972 * sys - Control set to be applied 1973 * on system side(1)or line side(0). 1974 * enable - (1) Enable loopback mode. 1975 * (0) Disable loopback mode. 1976 * serdes_linkup_wait - (1) Wait for Linkup for serdes 1977 * (0) Don't wait for Linkup 1978 * Returns: 1979 * SOC_E_XXX 1980 */ 1981 int 1982 soc_phyctrl_redirect_loopback_set(int unit, soc_port_t port, int phyn, 1983 int phy_lane, int sys_side, int enable, 1984 int serdes_linkup_wait) 1985 { 1986 int rv; 1987 phy_ctrl_t *int_pc; 1988 phy_ctrl_t *ext_pc; 1989 1990 /* 1991 If chained phy, pc_ptr points to the pc of chained phy. Otherwise 1992 to int/ext phy. 1993 */ 1994 phy_ctrl_t *pc_ptr = NULL; 1995 1996 /* 1997 Either chanied phy or directly attached, pc_head points to the 1998 *pc of head of the phy chain i.e int/ext phy. 1999 */ 2000 phy_ctrl_t *pc_head = NULL; 2001 2002 2003 LOG_VERBOSE(BSL_LS_SOC_PHY, 2004 (BSL_META_U(unit, 2005 "entered soc_phyctrl_redirect_loopback_set: " 2006 "unit %d, port %d, enable %d\n"), unit, port, enable)); 2007 2008 /*phyn - int/ext/chained*/ 2009 rv = soc_phyctrl_phyn_pc_get(unit, port, phyn, &pc_head, &pc_ptr); 2010 if (SOC_FAILURE(rv)) { 2011 PHYCTRL_WARN(("soc_phyctrl_redirect_loopback_set: u=%d p=%d l=%d rv=%d\n", 2012 unit, port, enable, rv)); 2013 } 2014 2015 /* sys_side */ 2016 pc_ptr->flags |= (sys_side ? PHYCTRL_SYS_SIDE_CTRL:0); 2017 2018 2019 rv = SOC_E_NONE; 2020 int_pc = INT_PHY_SW_STATE(unit, port); 2021 ext_pc = EXT_PHY_SW_STATE(unit, port); 2022 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 2023 2024 INT_MCU_LOCK(unit); 2025 rv = (PHY_LOOPBACK_SET(pc_head->pd, unit, port, enable)); 2026 2027 /* Wait until link up if internal PHY is put into loopback */ 2028 2029 if(serdes_linkup_wait && !SOC_IS_SAND(unit) && 2030 !SOC_IS_TRIUMPH3(unit)) { 2031 if (SOC_SUCCESS(rv) && enable && (NULL != int_pc)) { 2032 if ((PHY_PASSTHRU_MODE(unit, port)) || (NULL == ext_pc)) { 2033 int link; 2034 soc_timeout_t to; 2035 2036 /* Wait up to 5000 msec for link up */ 2037 soc_timeout_init(&to, 5000000, 0); 2038 link = 0; 2039 /* 2040 * Needs more than one read to clear Latched Link down bits. 2041 */ 2042 rv = (PHY_LINK_GET(int_pc->pd, unit, port, &link)); 2043 do { 2044 rv = (PHY_LINK_GET(int_pc->pd, unit, port, &link)); 2045 if (link || SOC_FAILURE(rv)) { 2046 break; 2047 } 2048 } while (!soc_timeout_check(&to)); 2049 if (!link) { 2050 LOG_WARN(BSL_LS_SOC_PHY, 2051 (BSL_META_U(unit, 2052 "soc_phyctrl_redirect_loopback_set: u=%d p=%d TIMEOUT\n"), 2053 unit, port)); 2054 rv = SOC_E_TIMEOUT; 2055 } 2056 } 2057 } 2058 } 2059 INT_MCU_UNLOCK(unit); 2060 2061 /* Clear flags set earlier for PHY_CONTROL_SET(). Clear them anyway..*/ 2062 pc_ptr->flags &= ~PHYCTRL_CHAINED_PHY_CTRL; 2063 pc_ptr->flags &= ~PHYCTRL_SYS_SIDE_CTRL; 2064 2065 if (SOC_FAILURE(rv)) { 2066 PHYCTRL_WARN(("soc_phyctrl_redirect_loopback_set: u=%d p=%d l=%d rv=%d\n", 2067 unit, port, enable, rv)); 2068 } 2069 2070 return rv; 2071 } 2072 2073 /* 2074 * Function: 2075 * soc_phyctrl_loopback_extended_set 2076 * Purpose: 2077 * Enable/disable loopback mode. 2078 * Parameters: 2079 * unit - SOC Unit #. 2080 * port - Port number. 2081 * enable - (1) Enable loopback mode. 2082 * (0) Disable loopback mode. 2083 * serdes_linkup_wait - (1) Wait for Linkup for serdes 2084 * (0) Don't wait for Linkup 2085 * en_int_phy - (1) Enable internal PHY lpbk by default 2086 * (0) Same operation as soc_phyctrl_loopback_set 2087 * Returns: 2088 * SOC_E_XXX 2089 */ 2090 int 2091 soc_phyctrl_loopback_extended_set(int unit, soc_port_t port, int enable, 2092 int serdes_linkup_wait, uint32 en_int_phy) 2093 { 2094 int rv; 2095 phy_ctrl_t *int_pc; 2096 phy_ctrl_t *ext_pc; 2097 phy_driver_t *pd; 2098 2099 if (en_int_phy == FALSE) { 2100 return soc_phyctrl_loopback_set(unit, port, enable, serdes_linkup_wait); 2101 } 2102 2103 LOG_VERBOSE(BSL_LS_SOC_PHY, 2104 (BSL_META_U(unit, 2105 "entered soc_phyctrl_loopback_extended_set: " 2106 "unit %d, port %d, enable %d\n"), unit, port, enable)); 2107 2108 rv = SOC_E_NONE; 2109 int_pc = INT_PHY_SW_STATE(unit, port); 2110 ext_pc = EXT_PHY_SW_STATE(unit, port); 2111 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 2112 2113 INT_MCU_LOCK(unit); 2114 if (NULL != ext_pc) { 2115 pd = ext_pc->pd; 2116 rv = (PHY_LOOPBACK_SET(pd, unit, port, enable)); 2117 } 2118 pd = int_pc->pd; 2119 rv = (PHY_LOOPBACK_SET(pd, unit, port, enable)); 2120 2121 INT_MCU_UNLOCK(unit); 2122 2123 if (SOC_FAILURE(rv)) { 2124 PHYCTRL_WARN(("soc_phyctrl_loopback_extended_set: u=%d p=%d l=%d rv=%d\n", 2125 unit, port, enable, rv)); 2126 } 2127 2128 return rv; 2129 } 2130 2131 2132 /* 2133 * Function: 2134 * soc_phyctrl_loopback_get 2135 * Purpose: 2136 * Get current loopback setting 2137 * Parameters: 2138 * unit - SOC Unit #. 2139 * port - Port number. 2140 * enable - (1) Enable loopback mode. 2141 * (0) Disable loopback mode. 2142 * Returns: 2143 * SOC_E_XXX 2144 */ 2145 int 2146 soc_phyctrl_loopback_get(int unit, soc_port_t port, int *enable) 2147 { 2148 int rv; 2149 phy_ctrl_t *int_pc; 2150 phy_ctrl_t *ext_pc; 2151 phy_driver_t *pd = NULL; 2152 2153 SOC_NULL_PARAM_CHECK(enable); 2154 2155 LOG_VERBOSE(BSL_LS_SOC_PHY, 2156 (BSL_META_U(unit, 2157 "entered soc_phyctrl_loopback_get: " 2158 "unit %d, port %d\n"), unit, port)); 2159 2160 int_pc = INT_PHY_SW_STATE(unit, port); 2161 ext_pc = EXT_PHY_SW_STATE(unit, port); 2162 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 2163 2164 if (NULL != ext_pc) { 2165 pd = ext_pc->pd; 2166 } else { 2167 pd = int_pc->pd; 2168 } 2169 2170 INT_MCU_LOCK(unit); 2171 2172 rv = (PHY_LOOPBACK_GET(pd, unit, port, enable)); 2173 2174 INT_MCU_UNLOCK(unit); 2175 if (SOC_FAILURE(rv)) { 2176 PHYCTRL_WARN(("soc_phyctrl_loopback_get failed %d\n", rv)); 2177 } 2178 return rv; 2179 } 2180 2181 /* 2182 * Function: 2183 * soc_phyctrl_redirect_loopback_get 2184 * Purpose: 2185 * Get current loopback mode for phy specific port 2186 * Parameters: 2187 * unit - SOC Unit #. 2188 * port - Port number. 2189 * phyn - Phy number 2190 * phy_lane - Lane number 2191 * sys - Control set to be applied 2192 * on system side(1)or line side(0). 2193 * enable - (1) Enable loopback mode. 2194 * (0) Disable loopback mode. 2195 * Returns: 2196 * SOC_E_XXX 2197 */ 2198 int 2199 soc_phyctrl_redirect_loopback_get(int unit, soc_port_t port, int phyn, 2200 int phy_lane, int sys_side, int *enable) 2201 { 2202 int rv; 2203 /* 2204 If chained phy, pc_ptr points to the pc of chained phy. Otherwise 2205 to int/ext phy. 2206 */ 2207 phy_ctrl_t *pc_ptr = NULL; 2208 2209 /* 2210 Either chanied phy or directly attached, pc_head points to the 2211 *pc of head of the phy chain i.e int/ext phy. 2212 */ 2213 phy_ctrl_t *pc_head = NULL; 2214 2215 2216 /*phyn - int/ext/chained*/ 2217 rv = soc_phyctrl_phyn_pc_get(unit, port, phyn, &pc_head, &pc_ptr); 2218 if (SOC_FAILURE(rv)) { 2219 PHYCTRL_WARN(("soc_phyctrl_redirect_loopback_get failed %d\n", rv)); 2220 } 2221 2222 /* sys_side */ 2223 pc_ptr->flags |= (sys_side ? PHYCTRL_SYS_SIDE_CTRL:0); 2224 2225 INT_MCU_LOCK(unit); 2226 if (SOC_SUCCESS(rv)) { 2227 rv = (PHY_LOOPBACK_GET(pc_head->pd, unit, port, enable)); 2228 } 2229 INT_MCU_UNLOCK(unit); 2230 if (SOC_FAILURE(rv)) { 2231 PHYCTRL_WARN(("soc_phyctrl_redirect_loopback_get failed %d\n", rv)); 2232 } 2233 return rv; 2234 } 2235 2236 /* 2237 * Function: 2238 * soc_phyctrl_interface_set 2239 * Purpose: 2240 * Set the interface between MAC and PHY 2241 * Parameters: 2242 * unit - SOC Unit #. 2243 * port - Port number. 2244 * pif - Interface type 2245 * Returns: 2246 * SOC_E_XXX 2247 */ 2248 int 2249 soc_phyctrl_interface_set(int unit, soc_port_t port, soc_port_if_t pif) 2250 { 2251 int rv; 2252 phy_driver_t *pd=NULL; 2253 2254 LOG_VERBOSE(BSL_LS_SOC_PHY, 2255 (BSL_META_U(unit, 2256 "entered soc_phyctrl_interface_set: " 2257 "unit %d, port %d, pif %d\n"), unit, port, pif)); 2258 2259 rv = soc_phyctrl_pd_get(unit, port, &pd); 2260 2261 INT_MCU_LOCK(unit); 2262 if (SOC_SUCCESS(rv)) { 2263 rv = (PHY_INTERFACE_SET(pd, unit, port, pif)); 2264 } 2265 INT_MCU_UNLOCK(unit); 2266 2267 if (SOC_FAILURE(rv)) { 2268 PHYCTRL_WARN(("soc_phyctrl_interface_set: u=%d p=%d i=%d rv=%d\n", 2269 unit, port, pif, rv)); 2270 } 2271 return rv; 2272 } 2273 2274 /* 2275 * Function: 2276 * soc_phyctrl_interface_get 2277 * Purpose: 2278 * Get current interface setting between MAC and PHY 2279 * Parameters: 2280 * unit - SOC Unit #. 2281 * port - Port number. 2282 * pif - current interface setting 2283 * Returns: 2284 * SOC_E_XXX 2285 */ 2286 int 2287 soc_phyctrl_interface_get(int unit, soc_port_t port, soc_port_if_t *pif) 2288 { 2289 int rv; 2290 phy_driver_t *pd=NULL; 2291 2292 LOG_VERBOSE(BSL_LS_SOC_PHY, 2293 (BSL_META_U(unit, 2294 "entered soc_phyctrl_interface_get: " 2295 "unit %d, port %d\n"), unit, port)); 2296 2297 rv = soc_phyctrl_pd_get(unit, port, &pd); 2298 2299 INT_MCU_LOCK(unit); 2300 if (SOC_SUCCESS(rv)) { 2301 rv = (PHY_INTERFACE_GET(pd, unit, port, pif)); 2302 } 2303 INT_MCU_UNLOCK(unit); 2304 2305 if (SOC_FAILURE(rv)) { 2306 PHYCTRL_WARN(("soc_phyctrl_interface_get failed %d\n", rv)); 2307 } 2308 return rv; 2309 } 2310 2311 STATIC int 2312 _soc_phy_ability_get(int unit, soc_port_t port, 2313 phy_driver_t *pd, soc_port_mode_t *mode) 2314 { 2315 int rv; 2316 soc_port_ability_t ability; 2317 2318 LOG_VERBOSE(BSL_LS_SOC_PHY, 2319 (BSL_META_U(unit, 2320 "entered soc_phy_ability_get: " 2321 "unit %d, port %d\n"), unit, port)); 2322 2323 INT_MCU_LOCK(unit); 2324 rv = (PHY_ABILITY_GET(pd, unit, port, mode)); 2325 2326 if (SOC_E_UNAVAIL == rv) { 2327 rv = (PHY_ABILITY_LOCAL_GET(pd, unit, port, &ability)); 2328 if (SOC_SUCCESS(rv)) { 2329 rv = soc_port_ability_to_mode(&ability, mode); 2330 } 2331 } 2332 INT_MCU_UNLOCK(unit); 2333 2334 if (SOC_FAILURE(rv)) { 2335 PHYCTRL_WARN(("_soc_phy_ability_get failed %d\n", rv)); 2336 } 2337 return rv; 2338 } 2339 2340 /* 2341 * Function: 2342 * soc_phyctrl_ability_get 2343 * Purpose: 2344 * Get PHY ability 2345 * Parameters: 2346 * unit - SOC Unit #. 2347 * port - Port number. 2348 * mode - PHY ability 2349 * Returns: 2350 * SOC_E_XXX 2351 */ 2352 int 2353 soc_phyctrl_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode) 2354 { 2355 int rv; 2356 soc_port_mode_t mode_speed_int; 2357 soc_port_mode_t mode_speed_ext; 2358 phy_ctrl_t *int_pc; 2359 phy_ctrl_t *ext_pc; 2360 2361 LOG_VERBOSE(BSL_LS_SOC_PHY, 2362 (BSL_META_U(unit, 2363 "entered soc_phyctrl_ability_get: " 2364 "unit %d, port %d\n"), unit, port)); 2365 2366 ext_pc = EXT_PHY_SW_STATE(unit, port); 2367 int_pc = INT_PHY_SW_STATE(unit, port); 2368 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 2369 rv = SOC_E_NONE; 2370 2371 mode_speed_int = mode_speed_ext = SOC_PM_SPEED_ALL; 2372 if (NULL != int_pc) { 2373 2374 if (int_pc->speed_max > 16000) { 2375 LOG_ERROR(BSL_LS_SOC_PHY, 2376 (BSL_META_U(unit, 2377 "soc_phyctrl_ability_get: Speed support above 16Gbps will" 2378 "not work. Use soc_phyctrl_ability_local_get\n"))); 2379 } 2380 2381 rv = _soc_phy_ability_get(unit, port, int_pc->pd, mode); 2382 mode_speed_int = *mode & SOC_PM_SPEED_ALL; 2383 } 2384 if (SOC_SUCCESS(rv) && NULL != ext_pc) { 2385 rv = _soc_phy_ability_get(unit, port, ext_pc->pd, mode); 2386 mode_speed_ext = *mode & SOC_PM_SPEED_ALL; 2387 } 2388 2389 if (SOC_SUCCESS(rv)) { 2390 *mode &= ~(SOC_PM_SPEED_ALL); 2391 *mode |= (mode_speed_int & mode_speed_ext); 2392 } 2393 2394 if (SOC_FAILURE(rv)) { 2395 PHYCTRL_WARN(("soc_phyctrl_ability_get failed %d\n", rv)); 2396 } 2397 LOG_INFO(BSL_LS_SOC_PHY, 2398 (BSL_META_U(unit, 2399 "soc_phyctrl_ability_get E=%08x I=%08x C=%08x\n"), 2400 mode_speed_ext, mode_speed_int,*mode)); 2401 return rv; 2402 } 2403 2404 /* 2405 * Function: 2406 * soc_phyctrl_linkup_evt 2407 * Purpose: 2408 * Force link up event to PHY. 2409 * Parameters: 2410 * unit - SOC Unit #. 2411 * port - Port number. 2412 * Returns: 2413 * SOC_E_XXX 2414 */ 2415 int 2416 soc_phyctrl_linkup_evt(int unit, soc_port_t port) 2417 { 2418 int rv; 2419 phy_driver_t *pd; 2420 2421 LOG_VERBOSE(BSL_LS_SOC_PHY, 2422 (BSL_META_U(unit, 2423 "entered soc_phyctrl_linkup_evt: " 2424 "unit %d, port %d\n"), unit, port)); 2425 2426 pd = NULL; 2427 rv = soc_phyctrl_pd_get(unit, port, &pd); 2428 2429 INT_MCU_LOCK(unit); 2430 if (SOC_SUCCESS(rv)) { 2431 rv = (PHY_LINKUP_EVT(pd, unit, port)); 2432 } 2433 INT_MCU_UNLOCK(unit); 2434 2435 return rv; 2436 } 2437 2438 /* 2439 * Function: 2440 * soc_phyctrl_linkdn_evt 2441 * Purpose: 2442 * Force link down event to PHY 2443 * Parameters: 2444 * unit - SOC Unit #. 2445 * port - Port number. 2446 * Returns: 2447 * SOC_E_XXX 2448 */ 2449 int 2450 soc_phyctrl_linkdn_evt(int unit, soc_port_t port) 2451 { 2452 int rv; 2453 phy_driver_t *pd; 2454 2455 LOG_VERBOSE(BSL_LS_SOC_PHY, 2456 (BSL_META_U(unit, 2457 "entered soc_phyctrl_linkdn_evt: " 2458 "unit %d, port %d\n"), unit, port)); 2459 2460 pd = NULL; 2461 rv = soc_phyctrl_pd_get(unit, port, &pd); 2462 2463 INT_MCU_LOCK(unit); 2464 if (SOC_SUCCESS(rv)) { 2465 rv = (PHY_LINKDN_EVT(pd, unit, port)); 2466 } 2467 INT_MCU_UNLOCK(unit); 2468 2469 return rv; 2470 } 2471 2472 /* 2473 * Function: 2474 * soc_phyctrl_port_phy_multi_get 2475 * Description: 2476 * General PHY register read 2477 * Parameters: 2478 * unit - Device number 2479 * port - Port number 2480 * flags - TBD 2481 * dev_addr - Device address on the PHY's bus (ex. I2C addr) 2482 * offset - Offset within device 2483 * max_size - Requested data size 2484 * data - Data buffer 2485 * actual_size - Received data size 2486 * Returns: 2487 * BCM_E_XXX 2488 */ 2489 int 2490 soc_phyctrl_port_phy_multi_get(int unit, soc_port_t port, uint32 flags, 2491 uint32 dev_addr, uint32 offset, int max_size, uint8 *data, int *actual_size) 2492 { 2493 int rv; 2494 phy_driver_t *pd=NULL; 2495 2496 LOG_VERBOSE(BSL_LS_SOC_PHY, 2497 (BSL_META_U(unit, 2498 "entered soc_phyctrl_port_phy_multi_get: " 2499 "unit=%d, port=%d\n"), unit, port)); 2500 2501 rv = soc_phyctrl_pd_get(unit, port, &pd); 2502 2503 INT_MCU_LOCK(unit); 2504 if (SOC_SUCCESS(rv)) { 2505 rv = (PHY_MULTI_GET(pd, unit, port, flags, dev_addr, offset, max_size, data, actual_size)); 2506 } 2507 INT_MCU_UNLOCK(unit); 2508 2509 if (SOC_FAILURE(rv)) { 2510 PHYCTRL_WARN(("soc_phyctrl_port_phy_multi_get: u=%d p=%d rv=%d\n", 2511 unit, port, rv)); 2512 } 2513 return rv; 2514 } 2515 2516 /* 2517 * Function: 2518 * soc_phyctrl_mdix_set 2519 * Purpose: 2520 * Set new mdix setting 2521 * Parameters: 2522 * unit - SOC Unit #. 2523 * port - Port number. 2524 * mdix - new mdix mode 2525 * Returns: 2526 * SOC_E_XXX 2527 */ 2528 int 2529 soc_phyctrl_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mdix) 2530 { 2531 int rv; 2532 phy_driver_t *pd=NULL; 2533 2534 LOG_VERBOSE(BSL_LS_SOC_PHY, 2535 (BSL_META_U(unit, 2536 "entered soc_phyctrl_mdix_set: " 2537 "unit %d, port %d, mdix %d\n"), unit, port, mdix)); 2538 2539 rv = soc_phyctrl_pd_get(unit, port, &pd); 2540 2541 INT_MCU_LOCK(unit); 2542 if (SOC_SUCCESS(rv)) { 2543 rv = (PHY_MDIX_SET(pd, unit, port, mdix)); 2544 } 2545 INT_MCU_UNLOCK(unit); 2546 2547 if (SOC_FAILURE(rv)) { 2548 PHYCTRL_WARN(("soc_phyctrl_mdix_set: u=%d p=%d m=%d rv=%d\n", 2549 unit, port, mdix, rv)); 2550 } 2551 return rv; 2552 } 2553 2554 /* 2555 * Function: 2556 * soc_phyctrl_mdix_get 2557 * Purpose: 2558 * Get current mdix setting 2559 * Parameters: 2560 * unit - SOC Unit #. 2561 * port - Port number. 2562 * mdix - current mdix mode. 2563 * Returns: 2564 * SOC_E_XXX 2565 */ 2566 int 2567 soc_phyctrl_mdix_get(int unit, soc_port_t port, soc_port_mdix_t *mdix) 2568 { 2569 int rv; 2570 phy_driver_t *pd=NULL; 2571 2572 SOC_NULL_PARAM_CHECK(mdix); 2573 2574 LOG_VERBOSE(BSL_LS_SOC_PHY, 2575 (BSL_META_U(unit, 2576 "entered soc_phyctrl_mdix_get: " 2577 "unit %d, port %d\n"), unit, port)); 2578 2579 rv = soc_phyctrl_pd_get(unit, port, &pd); 2580 2581 INT_MCU_LOCK(unit); 2582 if (SOC_SUCCESS(rv)) { 2583 rv = (PHY_MDIX_GET(pd, unit, port, mdix)); 2584 } 2585 INT_MCU_UNLOCK(unit); 2586 2587 if (SOC_FAILURE(rv)) { 2588 PHYCTRL_WARN(("soc_phyctrl_mdix_get failed %d\n", rv)); 2589 } 2590 return rv; 2591 } 2592 2593 /* 2594 * Function: 2595 * soc_phyctrl_mdix_status_get 2596 * Purpose: 2597 * Current resolved mdix status. 2598 * Parameters: 2599 * unit - SOC Unit #. 2600 * port - Port number. 2601 * status - Current resolved mdix status. 2602 * Returns: 2603 * SOC_E_XXX 2604 */ 2605 int 2606 soc_phyctrl_mdix_status_get(int unit, soc_port_t port, 2607 soc_port_mdix_status_t *status) 2608 { 2609 int rv; 2610 phy_driver_t *pd=NULL; 2611 2612 SOC_NULL_PARAM_CHECK(status); 2613 2614 LOG_VERBOSE(BSL_LS_SOC_PHY, 2615 (BSL_META_U(unit, 2616 "entered soc_phyctrl_mdix_status_get: " 2617 "unit %d, port %d\n"), unit, port)); 2618 2619 rv = soc_phyctrl_pd_get(unit, port, &pd); 2620 2621 INT_MCU_LOCK(unit); 2622 if (SOC_SUCCESS(rv)) { 2623 rv = (PHY_MDIX_STATUS_GET(pd, unit, port, status)); 2624 } 2625 INT_MCU_UNLOCK(unit); 2626 2627 if (SOC_FAILURE(rv)) { 2628 PHYCTRL_WARN(("soc_phyctrl_mdix_status_get failed %d\n", rv)); 2629 } 2630 return rv; 2631 } 2632 2633 /* 2634 * Function: 2635 * soc_phyctrl_medium_config_set 2636 * Purpose: 2637 * Set configuration of selected medium 2638 * Parameters: 2639 * unit - SOC Unit #. 2640 * port - Port number. 2641 * medium - Selected medium 2642 * cfg - New configuration of the selected medium 2643 * Returns: 2644 * SOC_E_XXX 2645 */ 2646 int 2647 soc_phyctrl_medium_config_set(int unit, soc_port_t port, 2648 soc_port_medium_t medium, 2649 soc_phy_config_t *cfg) 2650 { 2651 int rv; 2652 phy_driver_t *pd=NULL; 2653 2654 SOC_NULL_PARAM_CHECK(cfg); 2655 2656 LOG_VERBOSE(BSL_LS_SOC_PHY, 2657 (BSL_META_U(unit, 2658 "entered soc_phyctrl_medium_config_set: " 2659 "unit %d, port %d, medium %d\n"), 2660 unit, port, medium)); 2661 2662 rv = soc_phyctrl_pd_get(unit, port, &pd); 2663 2664 INT_MCU_LOCK(unit); 2665 if (SOC_SUCCESS(rv)) { 2666 rv = (PHY_MEDIUM_CONFIG_SET(pd, unit, port, medium, cfg)); 2667 } 2668 INT_MCU_UNLOCK(unit); 2669 2670 if (SOC_FAILURE(rv)) { 2671 PHYCTRL_WARN(("soc_phyctrl_medium_config_set: u=%d p=%d m=%d rv=%d\n", 2672 unit, port, medium, rv)); 2673 } 2674 return rv; 2675 } 2676 2677 /* 2678 * Function: 2679 * soc_phyctrl_medium_config_get 2680 * Purpose: 2681 * Get current configuration of the selected medium 2682 * Parameters: 2683 * unit - SOC Unit #. 2684 * port - Port number. 2685 * medium - Selected medium 2686 * cfg - Current configuration of the selected medium 2687 * Returns: 2688 * SOC_E_XXX 2689 */ 2690 int 2691 soc_phyctrl_medium_config_get(int unit, soc_port_t port, 2692 soc_port_medium_t medium, 2693 soc_phy_config_t *cfg) 2694 { 2695 int rv; 2696 phy_driver_t *pd=NULL; 2697 2698 SOC_NULL_PARAM_CHECK(cfg); 2699 2700 LOG_VERBOSE(BSL_LS_SOC_PHY, 2701 (BSL_META_U(unit, 2702 "entered soc_phyctrl_medium_config_get: " 2703 "unit %d, port %d, medium %d\n"), 2704 unit, port, medium)); 2705 2706 rv = soc_phyctrl_pd_get(unit, port, &pd); 2707 2708 INT_MCU_LOCK(unit); 2709 if (SOC_SUCCESS(rv)) { 2710 rv = (PHY_MEDIUM_CONFIG_GET(pd, unit, port, medium, cfg)); 2711 } 2712 INT_MCU_UNLOCK(unit); 2713 2714 if (SOC_FAILURE(rv)) { 2715 PHYCTRL_WARN(("soc_phyctrl_medium_config_get failed %d\n", 2716 rv)); 2717 } 2718 return rv; 2719 } 2720 2721 /* 2722 * Function: 2723 * soc_phyctrl_medium_get 2724 * Purpose: 2725 * Get active medium type 2726 * Parameters: 2727 * unit - SOC Unit #. 2728 * port - Port number. 2729 * medium - active medium 2730 * Returns: 2731 * SOC_E_XXX 2732 */ 2733 int 2734 soc_phyctrl_medium_get(int unit, soc_port_t port, soc_port_medium_t *medium) 2735 { 2736 int rv; 2737 phy_driver_t *pd=NULL; 2738 2739 SOC_NULL_PARAM_CHECK(medium); 2740 2741 LOG_VERBOSE(BSL_LS_SOC_PHY, 2742 (BSL_META_U(unit, 2743 "entered soc_phyctrl_medium_get: " 2744 "unit %d, port %d\n"), unit, port)); 2745 2746 rv = soc_phyctrl_pd_get(unit, port, &pd); 2747 2748 INT_MCU_LOCK(unit); 2749 if (SOC_SUCCESS(rv)) { 2750 rv = (PHY_MEDIUM_GET(pd, unit, port, medium)); 2751 } 2752 INT_MCU_UNLOCK(unit); 2753 2754 if (SOC_FAILURE(rv)) { 2755 PHYCTRL_WARN(("soc_phyctrl_medium_get failed %d\n", rv)); 2756 } 2757 return rv; 2758 } 2759 2760 /* 2761 * Function: 2762 * soc_phyctrl_cable_diag 2763 * Purpose: 2764 * Run cable diag on the PHY 2765 * Parameters: 2766 * unit - SOC Unit #. 2767 * port - Port number. 2768 * status - Cable status 2769 * Returns: 2770 * SOC_E_XXX 2771 */ 2772 int 2773 soc_phyctrl_cable_diag(int unit, soc_port_t port, soc_port_cable_diag_t *status) 2774 { 2775 int rv; 2776 phy_ctrl_t *ext_pc; 2777 2778 SOC_NULL_PARAM_CHECK(status); 2779 2780 LOG_VERBOSE(BSL_LS_SOC_PHY, 2781 (BSL_META_U(unit, 2782 "entered soc_phyctrl_cable_diag: " 2783 "unit %d, port %d\n"), unit, port)); 2784 2785 rv = SOC_E_UNAVAIL; 2786 ext_pc = EXT_PHY_SW_STATE(unit, port); 2787 2788 if (NULL != ext_pc) { 2789 INT_MCU_LOCK(unit); 2790 rv = (PHY_CABLE_DIAG(ext_pc->pd, unit, port, status)); 2791 INT_MCU_UNLOCK(unit); 2792 2793 if (SOC_FAILURE(rv)) { 2794 PHYCTRL_WARN(("soc_phyctrl_cable_diag failed %d\n", rv)); 2795 } 2796 } 2797 return rv; 2798 } 2799 2800 /* 2801 * Function: 2802 * soc_phyctrl_link_change 2803 * Purpose: 2804 * Force link change on the PHY 2805 * Parameters: 2806 * unit - SOC Unit #. 2807 * port - Port number. 2808 * link - Link status to change 2809 * Returns: 2810 * SOC_E_XXX 2811 */ 2812 int 2813 soc_phyctrl_link_change(int unit, soc_port_t port, int *link) 2814 { 2815 int rv; 2816 phy_driver_t *pd=NULL; 2817 2818 SOC_NULL_PARAM_CHECK(link); 2819 2820 LOG_VERBOSE(BSL_LS_SOC_PHY, 2821 (BSL_META_U(unit, 2822 "entered soc_phyctrl_link_change: " 2823 "unit %d, port %d\n"), unit, port)); 2824 2825 rv = soc_phyctrl_pd_get(unit, port, &pd); 2826 2827 INT_MCU_LOCK(unit); 2828 if (SOC_SUCCESS(rv)) { 2829 rv = (PHY_LINK_CHANGE(pd, unit, port, link)); 2830 } 2831 INT_MCU_UNLOCK(unit); 2832 2833 if (SOC_FAILURE(rv)) { 2834 PHYCTRL_WARN(("soc_phyctrl_link_change failed %d\n", rv)); 2835 } 2836 return rv; 2837 } 2838 2839 /* 2840 * Function: 2841 * soc_phyctrl_control_set 2842 * Purpose: 2843 * Set PHY specific configuration 2844 * Parameters: 2845 * unit - SOC Unit #. 2846 * port - Port number. 2847 * phy_ctrl - PHY control type to change 2848 * value - New setting for the PHY control 2849 * Returns: 2850 * SOC_E_XXX 2851 */ 2852 int 2853 soc_phyctrl_control_set(int unit, soc_port_t port, 2854 soc_phy_control_t phy_ctrl, uint32 value) 2855 { 2856 2857 int rv; 2858 phy_ctrl_t *int_pc; 2859 phy_ctrl_t *ext_pc; 2860 phy_driver_t *pd = NULL; 2861 2862 LOG_VERBOSE(BSL_LS_SOC_PHY, 2863 (BSL_META_U(unit, 2864 "entered soc_phyctrl_control_set: " 2865 "unit %d, port %d, phy_ctrl %d, value %u\n"), 2866 unit, port, phy_ctrl, value)); 2867 2868 int_pc = INT_PHY_SW_STATE(unit, port); 2869 ext_pc = EXT_PHY_SW_STATE(unit, port); 2870 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 2871 2872 if (NULL != ext_pc) { 2873 pd = ext_pc->pd; 2874 } else { 2875 pd = int_pc->pd; 2876 } 2877 2878 2879 INT_MCU_LOCK(unit); 2880 2881 rv = (PHY_CONTROL_SET(pd, unit, port, phy_ctrl, value)); 2882 2883 INT_MCU_UNLOCK(unit); 2884 2885 if (SOC_FAILURE(rv)) { 2886 PHYCTRL_WARN(("soc_phyctrl_control_set: u=%d p=%d c=%d rv=%d\n", 2887 unit, port, phy_ctrl, rv)); 2888 } 2889 return rv; 2890 } 2891 2892 /* 2893 * Function: 2894 * soc_phyctrl_control_get 2895 * Purpose: 2896 * Get current setting of the PHY control 2897 * Parameters: 2898 * unit - SOC Unit #. 2899 * port - Port number. 2900 * phy_ctrl - PHY control type to read 2901 * value - Current setting for the PHY control 2902 * Returns: 2903 * SOC_E_XXX 2904 */ 2905 int 2906 soc_phyctrl_control_get(int unit, soc_port_t port, 2907 soc_phy_control_t phy_ctrl, uint32 *value) 2908 { 2909 int rv; 2910 phy_ctrl_t *int_pc; 2911 phy_ctrl_t *ext_pc; 2912 phy_driver_t *pd = NULL; 2913 2914 SOC_NULL_PARAM_CHECK(value); 2915 2916 LOG_VERBOSE(BSL_LS_SOC_PHY, 2917 (BSL_META_U(unit, 2918 "entered soc_phyctrl_control_get: " 2919 "unit %d, port %d, phy_ctrl %d\n"), 2920 unit, port, phy_ctrl)); 2921 2922 int_pc = INT_PHY_SW_STATE(unit, port); 2923 ext_pc = EXT_PHY_SW_STATE(unit, port); 2924 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 2925 2926 if (NULL != ext_pc) { 2927 pd = ext_pc->pd; 2928 } else { 2929 pd = int_pc->pd; 2930 } 2931 2932 INT_MCU_LOCK(unit); 2933 2934 rv = (PHY_CONTROL_GET(pd, unit, port, phy_ctrl, value)); 2935 2936 INT_MCU_UNLOCK(unit); 2937 2938 if (SOC_FAILURE(rv)) { 2939 PHYCTRL_WARN(("soc_phyctrl_control_get failed %d\n", rv)); 2940 } 2941 return rv; 2942 } 2943 2944 /* 2945 * Function: 2946 * soc_phyctrl_redirect_control_set 2947 * Purpose: 2948 * Set PHY specific configuration 2949 * Parameters: 2950 * unit - SOC Unit #. 2951 * port - Port number. 2952 * phyn - Phy number 2953 * phy_lane - Lane number 2954 * sys - Control set to be applied 2955 * on system side(1)or line side(0). 2956 * phy_ctrl - PHY control type to change 2957 * value - New setting for the PHY control 2958 * Returns: 2959 * SOC_E_XXX 2960 */ 2961 int 2962 soc_phyctrl_redirect_control_set(int unit, soc_port_t port, int phyn, 2963 int phy_lane, int sys_side, 2964 soc_phy_control_t phy_ctrl, uint32 value) 2965 { 2966 int rv; 2967 /* 2968 If chained phy, pc_ptr points to the pc of chained phy. Otherwise 2969 to int/ext phy. 2970 */ 2971 phy_ctrl_t *pc_ptr = NULL; 2972 2973 /* 2974 Either chanied phy or directly attached, pc_head points to the 2975 *pc of head of the phy chain i.e int/ext phy. 2976 */ 2977 phy_ctrl_t *pc_head = NULL; 2978 2979 2980 /*phyn - int/ext/chained*/ 2981 rv = soc_phyctrl_phyn_pc_get(unit, port, phyn, &pc_head, &pc_ptr); 2982 if (SOC_FAILURE(rv)) { 2983 PHYCTRL_WARN(("soc_phyctrl_redirect_control_set failed: u=%d p=%d c=%d rv=%d\n", 2984 unit, port, phy_ctrl, rv)); 2985 } 2986 2987 /* sys_side */ 2988 pc_ptr->flags |= (sys_side ? PHYCTRL_SYS_SIDE_CTRL : PHYCTRL_LINE_SIDE_CTRL); 2989 2990 /* Lane */ 2991 INT_MCU_LOCK(unit); 2992 2993 /* In current system design, for chained phys phy_control flows 2994 through/to the phy that is directly attached. Use *pc_head 2995 which points to either int or ext phy (head of the chain) 2996 */ 2997 if (phy_lane >= 0) { 2998 rv = (PHY_LANE_CONTROL_SET(pc_head->pd, unit, port, phy_lane, phy_ctrl, value)); 2999 } else { 3000 rv = (PHY_CONTROL_SET(pc_head->pd, unit, port, phy_ctrl, value)); 3001 } 3002 INT_MCU_UNLOCK(unit); 3003 3004 3005 /* Clear flags set earlier for PHY_CONTROL_SET(). Clear them anyway..*/ 3006 pc_ptr->flags &= ~PHYCTRL_CHAINED_PHY_CTRL; 3007 pc_ptr->flags &= ~(PHYCTRL_SYS_SIDE_CTRL | PHYCTRL_LINE_SIDE_CTRL); 3008 3009 3010 if (SOC_FAILURE(rv)) { 3011 PHYCTRL_WARN(("soc_phyctrl_redirect_control_set failed: u=%d p=%d c=%d rv=%d\n", 3012 unit, port, phy_ctrl, rv)); 3013 } 3014 return rv; 3015 } 3016 3017 3018 /* 3019 * Function: 3020 * soc_phyctrl_redirect_control_get 3021 * Purpose: 3022 * Set PHY specific configuration 3023 * Parameters: 3024 * unit - SOC Unit #. 3025 * port - Port number. 3026 * phyn - Phy number 3027 * phy_lane - Lane number 3028 * sys - Control get to be applied 3029 * on system side(1)or line side(0). 3030 * phy_ctrl - PHY control type to read 3031 * value - Current setting for the PHY control 3032 * Returns: 3033 * SOC_E_XXX 3034 */ 3035 int 3036 soc_phyctrl_redirect_control_get(int unit, soc_port_t port, int phyn, 3037 int phy_lane, int sys_side, 3038 soc_phy_control_t phy_ctrl, uint32 *value) 3039 { 3040 int rv; 3041 /* 3042 If chained phy, pc_ptr points to the pc of chained phy. Otherwise 3043 to int/ext phy. 3044 */ 3045 phy_ctrl_t *pc_ptr = NULL; 3046 3047 /* 3048 Either chanied phy or directly attached, pc_head points to the 3049 *pc of head of the phy chain i.e int/ext phy. 3050 */ 3051 phy_ctrl_t *pc_head = NULL; 3052 3053 3054 /*phyn - int/ext/chained*/ 3055 rv = soc_phyctrl_phyn_pc_get(unit, port, phyn, &pc_head, &pc_ptr); 3056 if (SOC_FAILURE(rv)) { 3057 PHYCTRL_WARN(("soc_phyctrl_redirect_control_get failed: u=%d p=%d c=%d rv=%d\n", 3058 unit, port, phy_ctrl, rv)); 3059 return rv; 3060 } 3061 3062 /* sys_side */ 3063 pc_ptr->flags |= (sys_side ? PHYCTRL_SYS_SIDE_CTRL : PHYCTRL_LINE_SIDE_CTRL); 3064 3065 /* Lane */ 3066 INT_MCU_LOCK(unit); 3067 3068 /* In current system design, for chained phys phy_control flows 3069 through/to the phy that is directly attached. Use *pc_head 3070 which points to either int or ext phy (head of the chain) 3071 */ 3072 if (phy_lane >= 0) { 3073 rv = (PHY_LANE_CONTROL_GET(pc_head->pd, unit, port, phy_lane, phy_ctrl, value)); 3074 } else { 3075 rv = (PHY_CONTROL_GET(pc_head->pd, unit, port, phy_ctrl, value)); 3076 } 3077 INT_MCU_UNLOCK(unit); 3078 3079 3080 /* Clear flags set earlier for PHY_CONTROL_SET(). Clear them anyway..*/ 3081 pc_ptr->flags &= ~PHYCTRL_CHAINED_PHY_CTRL; 3082 pc_ptr->flags &= ~(PHYCTRL_SYS_SIDE_CTRL | PHYCTRL_LINE_SIDE_CTRL); 3083 3084 if (SOC_FAILURE(rv)) { 3085 PHYCTRL_WARN(("soc_phyctrl_control_get failed : u=%d p=%d c=%d rv=%d\n", 3086 unit, port, phy_ctrl, rv)); 3087 } 3088 return rv; 3089 } 3090 3091 /* 3092 * Function: 3093 * soc_phyctrl_reg_read 3094 * Purpose: 3095 * Read PHY register 3096 * Parameters: 3097 * unit - SOC Unit #. 3098 * port - Port number. 3099 * flags - Flags 3100 * addr - PHY register address 3101 * data - data read 3102 * Returns: 3103 * SOC_E_XXX 3104 */ 3105 int 3106 soc_phyctrl_reg_read(int unit, soc_port_t port, uint32 flags, 3107 uint32 addr, uint32 *data) 3108 { 3109 int rv; 3110 phy_ctrl_t *pc; 3111 3112 SOC_NULL_PARAM_CHECK(data); 3113 SOC_PORT_PARAM_CHECK(port); 3114 3115 LOG_VERBOSE(BSL_LS_SOC_PHY, 3116 (BSL_META_U(unit, 3117 "entered soc_phyctrl_reg_read: " 3118 "unit %d, port %d, flags %u, addr %u\n"), 3119 unit, port, flags, addr)); 3120 3121 rv = SOC_E_UNAVAIL; 3122 3123 if (flags & SOC_PHY_INTERNAL) { 3124 pc = INT_PHY_SW_STATE(unit, port); 3125 } else { 3126 pc = EXT_PHY_SW_STATE(unit, port); 3127 } 3128 3129 if (NULL != pc) { 3130 rv = PHY_REG_READ(pc->pd, unit, port, flags, addr, data); 3131 } 3132 3133 if (SOC_FAILURE(rv)) { 3134 PHYCTRL_WARN(("soc_phyctrl_reg_read failed %d\n", rv)); 3135 } 3136 return rv; 3137 } 3138 3139 /* 3140 * Function: 3141 * soc_phyctrl_reg_write 3142 * Purpose: 3143 * Write to PHY register 3144 * Parameters: 3145 * unit - SOC Unit #. 3146 * port - Port number. 3147 * flags - Flags 3148 * addr - PHY register address 3149 * data - data to be written 3150 * Returns: 3151 * SOC_E_XXX 3152 */ 3153 int 3154 soc_phyctrl_reg_write(int unit, soc_port_t port, uint32 flags, 3155 uint32 addr, uint32 data) 3156 { 3157 int rv; 3158 phy_ctrl_t *pc; 3159 3160 SOC_PORT_PARAM_CHECK(port); 3161 3162 LOG_VERBOSE(BSL_LS_SOC_PHY, 3163 (BSL_META_U(unit, 3164 "entered soc_phyctrl_reg_write: " 3165 "unit %d, port %d, flags %u, addr %u, data %u\n"), 3166 unit, port, flags, addr, data)); 3167 3168 rv = SOC_E_UNAVAIL; 3169 3170 if (flags & SOC_PHY_INTERNAL) { 3171 pc = INT_PHY_SW_STATE(unit, port); 3172 } else { 3173 pc = EXT_PHY_SW_STATE(unit, port); 3174 } 3175 3176 if (NULL != pc) { 3177 rv = PHY_REG_WRITE(pc->pd, unit, port, flags, addr, data); 3178 } 3179 3180 if (SOC_FAILURE(rv)) { 3181 PHYCTRL_WARN(("soc_phyctrl_reg_write failed %d\n", rv)); 3182 } 3183 3184 return rv; 3185 } 3186 3187 /* 3188 * Function: 3189 * soc_phyctrl_lane_control_set 3190 * Purpose: 3191 * Set PHY specific per-lane configuration 3192 * Parameters: 3193 * unit - SOC Unit #. 3194 * port - Port number. 3195 * lane - PHY lane number. 3196 * phy_ctrl - PHY control type to change 3197 * value - New setting for the PHY control 3198 * Returns: 3199 * SOC_E_XXX 3200 */ 3201 int 3202 soc_phyctrl_lane_control_set(int unit, soc_port_t port, int lane, 3203 soc_phy_control_t phy_ctrl, uint32 value) 3204 { 3205 3206 int rv; 3207 phy_driver_t *pd = NULL; 3208 3209 LOG_VERBOSE(BSL_LS_SOC_PHY, 3210 (BSL_META_U(unit, 3211 "entered soc_phyctrl_lane_conrol_set: " 3212 "unit %d, port %d, lane %d, phy_ctrl %d, value %u\n"), 3213 unit, port, lane, phy_ctrl, value)); 3214 3215 rv = soc_phyctrl_passthru_pd_get(unit, port, &pd); 3216 3217 INT_MCU_LOCK(unit); 3218 if (SOC_SUCCESS(rv)) { 3219 rv = (PHY_LANE_CONTROL_SET(pd, unit, port, lane, phy_ctrl, value)); 3220 } 3221 INT_MCU_UNLOCK(unit); 3222 3223 if (SOC_FAILURE(rv)) { 3224 PHYCTRL_WARN(("soc_phyctrl_lane_control_set: u=%d p=%d l=%d c=%d rv=%d\n", 3225 unit, port, lane, phy_ctrl, rv)); 3226 } 3227 return rv; 3228 } 3229 3230 /* 3231 * Function: 3232 * soc_phyctrl_lane_control_get 3233 * Purpose: 3234 * Get current setting of the PHY control per-lane 3235 * Parameters: 3236 * unit - SOC Unit #. 3237 * port - Port number. 3238 * lane - PHY lane number. 3239 * phy_ctrl - PHY control type to read 3240 * value - Current setting for the PHY control 3241 * Returns: 3242 * SOC_E_XXX 3243 */ 3244 int 3245 soc_phyctrl_lane_control_get(int unit, soc_port_t port, int lane, 3246 soc_phy_control_t phy_ctrl, uint32 *value) 3247 { 3248 int rv; 3249 phy_driver_t *pd = NULL; 3250 3251 SOC_NULL_PARAM_CHECK(value); 3252 3253 LOG_VERBOSE(BSL_LS_SOC_PHY, 3254 (BSL_META_U(unit, 3255 "entered soc_phyctrl_lane_control_get: " 3256 "unit %d, port %d, lane %d, phy_ctrl %d\n"), 3257 unit, port, lane, phy_ctrl)); 3258 3259 rv = soc_phyctrl_passthru_pd_get(unit, port, &pd); 3260 3261 INT_MCU_LOCK(unit); 3262 if (SOC_SUCCESS(rv)) { 3263 rv = (PHY_LANE_CONTROL_GET(pd, unit, port, lane, phy_ctrl, value)); 3264 } 3265 INT_MCU_UNLOCK(unit); 3266 3267 if (SOC_FAILURE(rv)) { 3268 PHYCTRL_WARN(("soc_phyctrl_lane_control_get: u=%d p=%d l=%d c=%d rv=%d\n", 3269 unit, port, lane, phy_ctrl, rv)); 3270 } 3271 return rv; 3272 } 3273 3274 /* 3275 * Function: 3276 * soc_phyctrl_lane_reg_read 3277 * Purpose: 3278 * Read per-lane PHY register 3279 * Parameters: 3280 * unit - SOC Unit #. 3281 * port - Port number. 3282 * lane - PHY lane number. 3283 * flags - Flags 3284 * addr - PHY register address 3285 * data - data read 3286 * Returns: 3287 * SOC_E_XXX 3288 */ 3289 int 3290 soc_phyctrl_lane_reg_read(int unit, soc_port_t port, int lane, 3291 uint32 flags, uint32 addr, uint32 *data) 3292 { 3293 int rv; 3294 phy_ctrl_t *pc; 3295 3296 SOC_NULL_PARAM_CHECK(data); 3297 3298 LOG_VERBOSE(BSL_LS_SOC_PHY, 3299 (BSL_META_U(unit, 3300 "entered soc_phyctrl_lane_reg_read: " 3301 "unit %d, port %d, lane %d, flags %u, addr %u\n"), 3302 unit, port, lane, flags, addr)); 3303 3304 rv = SOC_E_UNAVAIL; 3305 3306 if (flags & SOC_PHY_INTERNAL) { 3307 pc = INT_PHY_SW_STATE(unit, port); 3308 } else { 3309 pc = EXT_PHY_SW_STATE(unit, port); 3310 } 3311 3312 if (NULL != pc) { 3313 rv = PHY_LANE_REG_READ(pc->pd, unit, port, lane, flags, addr, data); 3314 } 3315 3316 if (SOC_FAILURE(rv)) { 3317 PHYCTRL_WARN(("soc_phyctrl_lane_reg_read: " 3318 "u=%d p=%d l=%d f=x0%08x addr=0x%08x rv=%d\n", 3319 unit, port, lane, flags, addr, rv)); 3320 } 3321 return rv; 3322 } 3323 3324 /* 3325 * Function: 3326 * soc_phyctrl_lane_reg_write 3327 * Purpose: 3328 * Write to per-lane PHY register 3329 * Parameters: 3330 * unit - SOC Unit #. 3331 * port - Port number. 3332 * lane - PHY lane number. 3333 * flags - Flags 3334 * addr - PHY register address 3335 * data - data to be written 3336 * Returns: 3337 * SOC_E_XXX 3338 */ 3339 int 3340 soc_phyctrl_lane_reg_write(int unit, soc_port_t port, int lane, 3341 uint32 flags, uint32 addr, uint32 data) 3342 { 3343 int rv; 3344 phy_ctrl_t *pc; 3345 3346 LOG_VERBOSE(BSL_LS_SOC_PHY, 3347 (BSL_META_U(unit, 3348 "entered soc_phyctrl_lane_reg_write: " 3349 "unit %d, port %d, lane %d, flags %u, addr %u, data %u\n"), 3350 unit, port, lane, flags, addr, data)); 3351 3352 rv = SOC_E_UNAVAIL; 3353 3354 if (flags & SOC_PHY_INTERNAL) { 3355 pc = INT_PHY_SW_STATE(unit, port); 3356 } else { 3357 pc = EXT_PHY_SW_STATE(unit, port); 3358 } 3359 3360 if (NULL != pc) { 3361 rv = PHY_LANE_REG_WRITE(pc->pd, unit, port, lane, flags, addr, data); 3362 } 3363 3364 if (SOC_FAILURE(rv)) { 3365 PHYCTRL_WARN(("soc_phyctrl_lane_reg_write: " 3366 "u=%d p=%d l=%d f=x0%08x addr=0x%08x rv=%d\n", 3367 unit, port, lane, flags, addr, rv)); 3368 } 3369 3370 return rv; 3371 } 3372 3373 /* 3374 * Function: 3375 * soc_phyctrl_reg_modify 3376 * Purpose: 3377 * Modify PHY register 3378 * Parameters: 3379 * unit - SOC Unit #. 3380 * port - Port number. 3381 * flags - Flags 3382 * addr - PHY register address 3383 * data - data to be written 3384 * mask - bit mask of data to be modified 3385 * Returns: 3386 * SOC_E_XXX 3387 */ 3388 int 3389 soc_phyctrl_reg_modify(int unit, soc_port_t port, uint32 flags, 3390 uint32 addr, uint32 data, uint32 mask) 3391 { 3392 int rv; 3393 phy_ctrl_t *pc; 3394 3395 LOG_VERBOSE(BSL_LS_SOC_PHY, 3396 (BSL_META_U(unit, 3397 "entered soc_phyctrl_reg_modify: " 3398 "unit %d, port %d, flags %u, addr %u, data %u, mask %u\n"), 3399 unit, port, flags, addr, data, mask)); 3400 3401 rv = SOC_E_UNAVAIL; 3402 3403 if (flags & SOC_PHY_INTERNAL) { 3404 pc = INT_PHY_SW_STATE(unit, port); 3405 } else { 3406 pc = EXT_PHY_SW_STATE(unit, port); 3407 } 3408 3409 if (NULL != pc) { 3410 INT_MCU_LOCK(unit); 3411 rv = PHY_REG_MODIFY(pc->pd, unit, port, flags, addr, data, mask); 3412 INT_MCU_UNLOCK(unit); 3413 } 3414 3415 if (SOC_FAILURE(rv)) { 3416 PHYCTRL_WARN(("soc_phyctrl_reg_modify failed %d\n", rv)); 3417 } 3418 return rv; 3419 } 3420 3421 /* 3422 * Function: 3423 * soc_phyctrl_ability_advert_get 3424 * Purpose: 3425 * Get local PHY advertised ability 3426 * Parameters: 3427 * unit - SOC Unit #. 3428 * port - Port number. 3429 * ability - PHY ability 3430 * Returns: 3431 * SOC_E_XXX 3432 */ 3433 int 3434 soc_phyctrl_ability_advert_get(int unit, soc_port_t port, 3435 soc_port_ability_t * ability) 3436 { 3437 int rv; 3438 phy_driver_t *pd = NULL; 3439 soc_port_mode_t mode; 3440 3441 SOC_NULL_PARAM_CHECK(ability); 3442 3443 LOG_VERBOSE(BSL_LS_SOC_PHY, 3444 (BSL_META_U(unit, 3445 "entered soc_phyctrl_ability_advert_get: " 3446 "unit %d, port %d\n"), unit, port)); 3447 3448 rv = soc_phyctrl_passthru_pd_get(unit, port, &pd); 3449 3450 INT_MCU_LOCK(unit); 3451 if (SOC_SUCCESS(rv)) { 3452 rv = PHY_ABILITY_ADVERT_GET(pd, unit, port, ability); 3453 } 3454 3455 if (SOC_E_UNAVAIL == rv) { 3456 rv = PHY_ADV_GET(pd, unit, port, &mode); 3457 if (SOC_SUCCESS(rv)) { 3458 sal_memset(ability, 0, sizeof(*ability)); 3459 rv = soc_port_mode_to_ability(mode, ability); 3460 } 3461 } 3462 INT_MCU_UNLOCK(unit); 3463 3464 if (SOC_FAILURE(rv)) { 3465 PHYCTRL_WARN(("soc_phyctrl_ability_advert_get failed %d\n", rv)); 3466 } 3467 3468 return rv; 3469 } 3470 3471 /* 3472 * Function: 3473 * soc_phyctrl_ability_advert_set 3474 * Purpose: 3475 * Set local PHY advertised ability 3476 * Parameters: 3477 * unit - SOC Unit #. 3478 * port - Port number. 3479 * ability - PHY ability 3480 * Returns: 3481 * SOC_E_XXX 3482 */ 3483 int 3484 soc_phyctrl_ability_advert_set(int unit, soc_port_t port, 3485 soc_port_ability_t * ability) 3486 { 3487 int rv; 3488 phy_driver_t *pd = NULL; 3489 soc_port_mode_t mode; 3490 3491 SOC_NULL_PARAM_CHECK(ability); 3492 3493 LOG_VERBOSE(BSL_LS_SOC_PHY, 3494 (BSL_META_U(unit, 3495 "entered soc_phyctrl_ability_advert_set: " 3496 "unit %d, port %d\n"), unit, port)); 3497 3498 rv = soc_phyctrl_passthru_pd_get(unit, port, &pd); 3499 3500 INT_MCU_LOCK(unit); 3501 if (SOC_SUCCESS(rv)) { 3502 rv = PHY_ABILITY_ADVERT_SET(pd, unit, port, ability); 3503 } 3504 3505 if (SOC_E_UNAVAIL == rv) { 3506 rv = soc_port_ability_to_mode(ability, &mode); 3507 if (SOC_SUCCESS(rv)) { 3508 rv = PHY_ADV_SET(pd, unit, port, mode); 3509 } 3510 } 3511 INT_MCU_UNLOCK(unit); 3512 3513 if (SOC_FAILURE(rv)) { 3514 PHYCTRL_WARN(("soc_phyctrl_ability_advert_set failed %d\n", rv)); 3515 } 3516 return rv; 3517 } 3518 3519 /* 3520 * Function: 3521 * soc_phyctrl_ability_remote_get 3522 * Purpose: 3523 * Get remote PHY advertsied ability 3524 * Parameters: 3525 * unit - SOC Unit #. 3526 * port - Port number. 3527 * ability - PHY ability 3528 * Returns: 3529 * SOC_E_XXX 3530 */ 3531 int 3532 soc_phyctrl_ability_remote_get(int unit, soc_port_t port, 3533 soc_port_ability_t * ability) 3534 { 3535 int rv; 3536 phy_driver_t *pd = NULL; 3537 soc_port_mode_t mode; 3538 3539 SOC_NULL_PARAM_CHECK(ability); 3540 3541 LOG_VERBOSE(BSL_LS_SOC_PHY, 3542 (BSL_META_U(unit, 3543 "entered soc_phyctrl_ability_remote_get: " 3544 "unit %d, port %d\n"), unit, port)); 3545 3546 rv = soc_phyctrl_passthru_pd_get(unit, port, &pd); 3547 3548 INT_MCU_LOCK(unit); 3549 if (SOC_SUCCESS(rv)) { 3550 rv = PHY_ABILITY_REMOTE_GET(pd, unit, port, ability); 3551 } 3552 3553 if (SOC_E_UNAVAIL == rv) { 3554 rv = PHY_ADV_REMOTE_GET(pd, unit, port, &mode); 3555 if (SOC_SUCCESS(rv)) { 3556 sal_memset(ability, 0, sizeof(*ability)); 3557 rv = soc_port_mode_to_ability(mode, ability); 3558 } 3559 } 3560 INT_MCU_UNLOCK(unit); 3561 3562 if (SOC_FAILURE(rv)) { 3563 PHYCTRL_WARN(("soc_phyctrl_ability_remote_get failed %d\n", rv)); 3564 } 3565 3566 return rv; 3567 } 3568 3569 STATIC int 3570 _soc_phy_ability_local_get(int unit, soc_port_t port, 3571 phy_driver_t *pd, soc_port_ability_t *ability) 3572 { 3573 int rv; 3574 soc_port_mode_t mode; 3575 3576 LOG_VERBOSE(BSL_LS_SOC_PHY, 3577 (BSL_META_U(unit, 3578 "entered soc_phy_ability_local_get: " 3579 "unit %d, port %d\n"), unit, port)); 3580 3581 INT_MCU_LOCK(unit); 3582 rv = PHY_ABILITY_LOCAL_GET(pd, unit, port, ability); 3583 3584 if (SOC_E_UNAVAIL == rv) { 3585 rv = PHY_ABILITY_GET(pd, unit, port, &mode); 3586 if (SOC_SUCCESS(rv)) { 3587 sal_memset(ability, 0, sizeof(*ability)); 3588 rv = soc_port_mode_to_ability(mode, ability); 3589 } 3590 } 3591 INT_MCU_UNLOCK(unit); 3592 3593 return rv; 3594 } 3595 3596 /* 3597 * Function: 3598 * soc_phyctrl_ability_local_get 3599 * Purpose: 3600 * Get PHY ability 3601 * Parameters: 3602 * unit - SOC Unit #. 3603 * port - Port number. 3604 * mode - PHY ability 3605 * Returns: 3606 * SOC_E_XXX 3607 */ 3608 int 3609 soc_phyctrl_ability_local_get(int unit, soc_port_t port, 3610 soc_port_ability_t *ability) 3611 { 3612 int rv; 3613 soc_port_ability_t ability_int; 3614 soc_port_ability_t ability_ext; 3615 phy_ctrl_t *int_pc; 3616 phy_ctrl_t *ext_pc; 3617 3618 SOC_NULL_PARAM_CHECK(ability); 3619 3620 LOG_VERBOSE(BSL_LS_SOC_PHY, 3621 (BSL_META_U(unit, 3622 "entered soc_phyctrl_ability_local_get: " 3623 "unit %d, port %d\n"), unit, port)); 3624 3625 ext_pc = EXT_PHY_SW_STATE(unit, port); 3626 int_pc = INT_PHY_SW_STATE(unit, port); 3627 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 3628 3629 ability_int.speed_half_duplex = ability_ext.speed_half_duplex = SOC_PA_SPEED_ALL; 3630 ability_int.speed_full_duplex = ability_ext.speed_full_duplex = SOC_PA_SPEED_ALL; 3631 3632 rv = SOC_E_NONE; 3633 if (NULL != int_pc) { 3634 #ifdef PORTMOD_SUPPORT 3635 if (!soc_feature(unit, soc_feature_portmod)) { 3636 #endif 3637 rv = _soc_phy_ability_local_get(unit, port, int_pc->pd, ability); 3638 ability_int.speed_full_duplex = ability->speed_full_duplex; 3639 ability_int.speed_half_duplex = ability->speed_half_duplex; 3640 #ifdef PORTMOD_SUPPORT 3641 } /* if portmod feature enabled */ 3642 #endif 3643 } 3644 3645 if (SOC_SUCCESS(rv) && NULL != ext_pc) { 3646 /* next make sure it's not phy_null_driver */ 3647 if (ext_pc->write != NULL) { 3648 ability->speed_half_duplex = ability->speed_full_duplex = 0; 3649 rv = _soc_phy_ability_local_get(unit, port, ext_pc->pd, ability); 3650 ability_ext.speed_full_duplex = ability->speed_full_duplex; 3651 ability_ext.speed_half_duplex = ability->speed_half_duplex; 3652 } 3653 } 3654 3655 if (SOC_SUCCESS(rv)) { 3656 #ifdef PORTMOD_SUPPORT 3657 if (!soc_feature(unit, soc_feature_portmod)) { 3658 #endif 3659 ability->speed_half_duplex = ability_int.speed_half_duplex & ability_ext.speed_half_duplex; 3660 ability->speed_full_duplex = ability_int.speed_full_duplex & ability_ext.speed_full_duplex; 3661 #ifdef PORTMOD_SUPPORT 3662 } 3663 #endif 3664 } 3665 3666 if (SOC_FAILURE(rv)) { 3667 PHYCTRL_WARN(("soc_phyctrl_ability_get failed %d\n", rv)); 3668 } 3669 return rv; 3670 } 3671 3672 /* 3673 * Function: 3674 * soc_phyctrl_firmware_set 3675 * Purpose: 3676 * Update the phy device's firmware 3677 * Parameters: 3678 * unit - SOC Unit #. 3679 * port - Port number. 3680 * flags - Flags 3681 * offset - offset to the data stream 3682 * addr - PHY register address 3683 * data - data to be written 3684 * mask - bit mask of data to be modified 3685 * Returns: 3686 * SOC_E_XXX 3687 */ 3688 int 3689 soc_phyctrl_firmware_set(int unit, soc_port_t port, uint32 flags, 3690 int offset, uint8 *array, int len) 3691 { 3692 int rv; 3693 phy_ctrl_t *pc; 3694 3695 LOG_VERBOSE(BSL_LS_SOC_PHY, 3696 (BSL_META_U(unit, 3697 "entered soc_phyctrl_firmare_set: " 3698 "unit %d, port %d, flags %u, offset %d, len %d\n"), 3699 unit, port, flags, offset, len)); 3700 3701 rv = SOC_E_UNAVAIL; 3702 3703 if (flags & SOC_PHY_INTERNAL) { 3704 pc = INT_PHY_SW_STATE(unit, port); 3705 } else { 3706 pc = EXT_PHY_SW_STATE(unit, port); 3707 } 3708 3709 if (NULL != pc) { 3710 INT_MCU_LOCK(unit); 3711 rv = PHY_FIRMWARE_SET(pc->pd, unit, port, offset, array, len); 3712 INT_MCU_UNLOCK(unit); 3713 } 3714 3715 if (SOC_FAILURE(rv)) { 3716 PHYCTRL_WARN(("soc_phyctrl_firmware_set failed %d\n", rv)); 3717 } 3718 return rv; 3719 } 3720 3721 /* 3722 * Function: 3723 * soc_phyctrl_synce_clock_set 3724 * Purpose: 3725 * configure SyncE clock 3726 * Parameters: 3727 * unit - SOC Unit #. 3728 * port - Port number. 3729 * mode0 - Stage0 mode 3730 * mode1 - Stage1 mode 3731 * sdm_value - SDM value of stage0 3732 * Returns: 3733 * SOC_E_XXX 3734 */ 3735 int 3736 soc_phyctrl_synce_clock_set(int unit, soc_port_t port, uint32 mode0, 3737 uint32 mode1, uint32 sdm_value) 3738 { 3739 int rv; 3740 phy_ctrl_t *pc; 3741 3742 LOG_VERBOSE(BSL_LS_SOC_PHY, 3743 (BSL_META_U(unit, 3744 "entered soc_phyctrl_synce_clock_set: " 3745 "unit %d, port %d, mode0 %u, mode1 %u, sdm_value %u\n"), 3746 unit, port, mode0, mode1, sdm_value)); 3747 3748 rv = SOC_E_UNAVAIL; 3749 3750 pc = INT_PHY_SW_STATE(unit, port); 3751 3752 if (NULL != pc) { 3753 INT_MCU_LOCK(unit); 3754 rv = PHY_SYNCE_CLK_SET(pc->pd, unit, port, mode0, mode1, sdm_value); 3755 INT_MCU_UNLOCK(unit); 3756 } 3757 3758 if (SOC_FAILURE(rv)) { 3759 PHYCTRL_WARN(("soc_phyctrl_synce_clock_set failed %d\n", rv)); 3760 } 3761 3762 return rv; 3763 } 3764 3765 /* 3766 * Function: 3767 * soc_phyctrl_synce_clock_get 3768 * Purpose: 3769 * configure SyncE clock 3770 * Parameters: 3771 * unit - SOC Unit #. 3772 * port - Port number. 3773 * mode0 - Stage0 mode 3774 * mode1 - Stage1 mode 3775 * sdm_value - SDM value of stage0 3776 * Returns: 3777 * SOC_E_XXX 3778 */ 3779 int 3780 soc_phyctrl_synce_clock_get(int unit, soc_port_t port, uint32 *mode0, 3781 uint32 *mode1, uint32 *sdm_value) 3782 { 3783 int rv; 3784 phy_ctrl_t *pc; 3785 3786 LOG_VERBOSE(BSL_LS_SOC_PHY, 3787 (BSL_META_U(unit, 3788 "entered soc_phyctrl_synce_clock_set: " 3789 "unit %d, port %d\n"),unit, port)); 3790 3791 rv = SOC_E_UNAVAIL; 3792 3793 pc = INT_PHY_SW_STATE(unit, port); 3794 3795 if (NULL != pc) { 3796 INT_MCU_LOCK(unit); 3797 rv = PHY_SYNCE_CLK_GET(pc->pd, unit, port, mode0, mode1, sdm_value); 3798 INT_MCU_UNLOCK(unit); 3799 } 3800 3801 if (SOC_FAILURE(rv)) { 3802 PHYCTRL_WARN(("soc_phyctrl_synce_clock_get failed %d\n", rv)); 3803 } 3804 3805 return rv; 3806 } 3807 3808 /* 3809 * Function: 3810 * soc_phyctrl_diag_ctrl 3811 * Purpose: 3812 * Call underlying driver's routine to perform a range of diagnostic 3813 * functions on the serdes and phy devices. This function allows a control 3814 * action to be addressed to a specific instance of the device on the port. 3815 * In a scenario where a port is connected with a serdes device and a PHY 3816 * device, This function can be used to access both devices. 3817 * This function doesn't provide mutual exclusion access to the device. 3818 * Caller should obtain it before calling this function. 3819 * 3820 * Parameters: 3821 * unit - SOC Unit #. 3822 * port - Port number. 3823 * instance - the specific device block the control action directs to 3824 * op_type - operation types: read,write or command sequence 3825 * op_cmd - command code 3826 * arg - command argument based on op_type/op_cmd 3827 * Returns: 3828 * SOC_E_XXX 3829 */ 3830 int 3831 soc_phyctrl_diag_ctrl( 3832 int unit, /* unit */ 3833 soc_port_t port, /* port */ 3834 uint32 inst, /* the specific device block the control action directs to */ 3835 int op_type, /* operation types: read,write or command sequence */ 3836 int op_cmd, /* command code */ 3837 void *arg) /* command argument based on op_type/op_cmd */ 3838 { 3839 int rv; 3840 phy_ctrl_t *pc; 3841 int dev = PHY_DIAG_INST_DEV(inst); 3842 phy_ctrl_t *int_pc; 3843 phy_ctrl_t *ext_pc; 3844 3845 LOG_VERBOSE(BSL_LS_SOC_PHY, 3846 (BSL_META_U(unit, 3847 "entered soc_phyctrl_diag_ctrl: " 3848 "unit %d, port %d, inst %u, op_type %d, op_cmd %d\n"), 3849 unit, port, inst, op_type, op_cmd)); 3850 3851 ext_pc = EXT_PHY_SW_STATE(unit, port); 3852 int_pc = INT_PHY_SW_STATE(unit, port); 3853 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 3854 3855 rv = SOC_E_UNAVAIL; 3856 3857 LOG_INFO(BSL_LS_SOC_PHY, 3858 (BSL_META_U(unit, 3859 "u=%d p=%d inst=0x%x op_type=0x%x, op_cmd=0x%x, arg=0x%x\n"), 3860 unit, port, inst, op_type, op_cmd, PTR_TO_INT(arg))); 3861 3862 if (dev == PHY_DIAG_DEV_DFLT) { 3863 pc = ext_pc? ext_pc: int_pc; 3864 } else if (dev == PHY_DIAG_DEV_INT) { 3865 pc = int_pc; 3866 } else { 3867 pc = ext_pc; 3868 } 3869 3870 if (NULL != pc) { 3871 rv = PHY_DIAG_CTRL(pc->pd, unit, port,PHY_DIAG_INST_INTF_LN(inst), 3872 op_type,op_cmd,arg); 3873 } 3874 3875 if (SOC_FAILURE(rv)) { 3876 PHYCTRL_WARN(("soc_phyctrl_diag_ctrl failed %d\n", rv)); 3877 } 3878 return rv; 3879 } 3880 3881 /* 3882 * Function: 3883 * soc_phyctrl_primary_set 3884 * Purpose: 3885 * Set primary port 3886 * Parameters: 3887 * unit - SOC Unit #. 3888 * port - Port number. 3889 * primary - primary port of the phy chip 3890 * Returns: 3891 * SOC_E_XXX 3892 */ 3893 int 3894 soc_phyctrl_primary_set(int unit, soc_port_t port, soc_port_t primary) 3895 { 3896 soc_phy_chip_info_t *chip_info; 3897 3898 LOG_VERBOSE(BSL_LS_SOC_PHY, 3899 (BSL_META_U(unit, 3900 "entered soc_phyctrl_primary_set: " 3901 "unit %d, port %d, primary %d\n"), unit, port, primary)); 3902 3903 if (SOC_PHY_INFO(unit, port).chip_info == NULL) { 3904 SOC_PHY_INFO(unit, port).chip_info = sal_alloc(sizeof(soc_phy_chip_info_t), 3905 "phy_chip_info"); 3906 if (SOC_PHY_INFO(unit, port).chip_info == NULL) { 3907 return SOC_E_MEMORY; 3908 } 3909 sal_memset(SOC_PHY_INFO(unit, port).chip_info, -1, sizeof(soc_phy_chip_info_t)); 3910 } 3911 3912 chip_info = SOC_PHY_INFO(unit, port).chip_info; 3913 3914 chip_info->primary = primary; 3915 3916 return SOC_E_NONE; 3917 3918 } 3919 3920 /* 3921 * Function: 3922 * soc_phyctrl_primary_get 3923 * Purpose: 3924 * Get primary port 3925 * Parameters: 3926 * unit - SOC Unit #. 3927 * port - Port number. 3928 * primary - primary port of the phy chip 3929 * Returns: 3930 * SOC_E_XXX 3931 */ 3932 int 3933 soc_phyctrl_primary_get(int unit, soc_port_t port, soc_port_t *primary) 3934 { 3935 soc_phy_chip_info_t *chip_info; 3936 3937 LOG_VERBOSE(BSL_LS_SOC_PHY, 3938 (BSL_META_U(unit, 3939 "entered soc_phyctrl_primary_get: " 3940 "unit %d, port %d\n"), unit, port)); 3941 3942 chip_info = SOC_PHY_INFO(unit, port).chip_info; 3943 3944 if ((chip_info == NULL) || (chip_info->primary == -1)) { 3945 return SOC_E_UNAVAIL; 3946 } 3947 3948 *primary = chip_info->primary; 3949 3950 return SOC_E_NONE; 3951 3952 } 3953 3954 /* 3955 * Function: 3956 * soc_phyctrl_offset_set 3957 * Purpose: 3958 * Set port offset 3959 * Parameters: 3960 * unit - SOC Unit #. 3961 * port - Port number. 3962 * offset - offset of the port 3963 * Returns: 3964 * SOC_E_XXX 3965 */ 3966 int 3967 soc_phyctrl_offset_set(int unit, soc_port_t port, int offset) 3968 { 3969 soc_phy_chip_info_t *chip_info, *primary_chip_info; 3970 3971 LOG_VERBOSE(BSL_LS_SOC_PHY, 3972 (BSL_META_U(unit, 3973 "entered soc_phyctrl_offset_set: " 3974 "unit %d, port %d, offset %d\n"), unit, port, offset)); 3975 3976 chip_info = SOC_PHY_INFO(unit, port).chip_info; 3977 3978 if ((chip_info == NULL) || (chip_info->primary == -1) || (!PHY_OFFSET_VALID(offset))) { 3979 /* set primary first and make sure that the offset is valid */ 3980 return SOC_E_UNAVAIL; 3981 } 3982 3983 if (SOC_PHY_INFO(unit, chip_info->primary).chip_info == NULL) { 3984 SOC_PHY_INFO(unit, chip_info->primary).chip_info = sal_alloc(sizeof(soc_phy_chip_info_t), 3985 "phy_chip_info"); 3986 if (SOC_PHY_INFO(unit, chip_info->primary).chip_info == NULL) { 3987 return SOC_E_MEMORY; 3988 } 3989 sal_memset(SOC_PHY_INFO(unit, chip_info->primary).chip_info, -1, sizeof(soc_phy_chip_info_t)); 3990 } 3991 3992 primary_chip_info = SOC_PHY_INFO(unit, chip_info->primary).chip_info; 3993 primary_chip_info->offset_to_port[offset] = port; 3994 chip_info->offset = offset; 3995 3996 return SOC_E_NONE; 3997 3998 } 3999 4000 /* 4001 * Function: 4002 * soc_phyctrl_offset_get 4003 * Purpose: 4004 * Get port offset 4005 * Parameters: 4006 * unit - SOC Unit #. 4007 * port - Port number. 4008 * offset - offset of the port 4009 * Returns: 4010 * SOC_E_XXX 4011 */ 4012 int 4013 soc_phyctrl_offset_get(int unit, soc_port_t port, soc_port_t *offset) 4014 { 4015 soc_phy_chip_info_t *chip_info, *primary_chip_info; 4016 4017 LOG_VERBOSE(BSL_LS_SOC_PHY, 4018 (BSL_META_U(unit, 4019 "entered soc_phyctrl_offset_get: " 4020 "unit %d, port %d\n"), unit, port)); 4021 4022 chip_info = SOC_PHY_INFO(unit, port).chip_info; 4023 4024 if ((chip_info == NULL) || (!PHY_OFFSET_VALID(chip_info->offset))) { 4025 return SOC_E_UNAVAIL; 4026 } 4027 primary_chip_info = SOC_PHY_INFO(unit, chip_info->primary).chip_info; 4028 4029 if (primary_chip_info == NULL) { 4030 return SOC_E_UNAVAIL; 4031 } 4032 4033 /* integrity check */ 4034 *offset = (primary_chip_info->offset_to_port[chip_info->offset] == port) ? chip_info->offset : -1 ; 4035 4036 return SOC_E_NONE; 4037 4038 } 4039 4040 /* 4041 * Function: 4042 * soc_phy_primary_and_offset_get 4043 * Purpose: 4044 * Get primary port offset 4045 * Parameters: 4046 * unit - SOC Unit #. 4047 * port - Port number. 4048 * *primary_port - primary port of the phy chip 4049 * *offset - offset of the curent phy port 4050 * Returns: 4051 * SOC_E_XXX 4052 */ 4053 int 4054 soc_phy_primary_and_offset_get(int unit, soc_port_t port, soc_port_t *primary_port, int *offset) 4055 { 4056 uint32 primary_and_offset; 4057 4058 LOG_VERBOSE(BSL_LS_SOC_PHY, 4059 (BSL_META_U(unit, 4060 "entered soc_phy_primary_and_offset_get: " 4061 "unit %d, port %d\n"), unit, port)); 4062 4063 if ((primary_and_offset = soc_property_port_get(unit, port, spn_PHY_PORT_PRIMARY_AND_OFFSET, -1)) == -1) { 4064 *primary_port = -1; 4065 *offset = -1; 4066 return SOC_E_FAIL; 4067 } 4068 4069 *primary_port = (primary_and_offset >> 8) & 0xffff; 4070 4071 *offset = primary_and_offset & 0xff; 4072 4073 return SOC_E_NONE; 4074 4075 } 4076 4077 /* 4078 * Function: 4079 * soc_phy_boot_master_get 4080 * Purpose: 4081 * Get boot master and chip master settings 4082 * Parameters: 4083 * unit - SOC Unit #. 4084 * port - Port number. 4085 * *bm - port is a bootmaster 4086 * *cm - port is also a chipmaster 4087 * Returns: 4088 * SOC_E_XXX 4089 */ 4090 int 4091 soc_phy_boot_master_get(int unit, soc_port_t port, int *bm, int *cm) 4092 { 4093 char *config_str, *sub_str, *sub_str_end; 4094 int val; 4095 4096 4097 LOG_VERBOSE(BSL_LS_SOC_PHY, 4098 (BSL_META_U(unit, 4099 "entered soc_phy_boot_master_get: " 4100 "unit %d, port %d\n"), unit, port)); 4101 4102 config_str = soc_property_port_get_str(unit, port, spn_PHY_BOOT_MASTER); 4103 4104 if (config_str == NULL) { 4105 return SOC_E_FAIL; 4106 } 4107 4108 sub_str = config_str; 4109 4110 val = sal_ctoi(sub_str, &sub_str_end); 4111 4112 *bm = (val == 1) ? 1 : 0; 4113 4114 if ((sub_str == sub_str_end) || (val != 1)) { 4115 *cm = 0; 4116 return SOC_E_NONE; 4117 } 4118 4119 /* Skip ':' */ 4120 sub_str = sub_str_end; 4121 if (*sub_str != ':') { 4122 *cm = 0; 4123 return SOC_E_NONE; 4124 } 4125 sub_str++; 4126 4127 *cm = (*sub_str == 'c') ? 1 : 0; 4128 4129 return SOC_E_NONE; 4130 4131 } 4132 4133 /* 4134 * Function: 4135 * soc_phyctrl_toplvl_reg_read 4136 * Purpose: 4137 * Read a top level register from a supporting chip 4138 * Parameters: 4139 * unit - SOC Unit #. 4140 * port - Port number. 4141 * primary_port - Primary Port number. 4142 * reg_offset - Offset to the reg 4143 * data - Pointer to data returned 4144 * Returns: 4145 * SOC_E_XXX 4146 */ 4147 int 4148 soc_phyctrl_toplvl_reg_read(int unit, soc_port_t port, soc_port_t primary_port, 4149 uint8 reg_offset, uint16 *data) 4150 4151 { 4152 phy_ctrl_t *pc, *pc_port3, *pc_port5; 4153 uint16 reg_data, status; 4154 soc_phy_chip_info_t *chip_info; 4155 int rv = SOC_E_NONE; 4156 4157 LOG_VERBOSE(BSL_LS_SOC_PHY, 4158 (BSL_META_U(unit, 4159 "entered soc_phyctrl_toplvl_reg_read: " 4160 "unit %d, port %d, primary_port %d, reg_offset %u\n"), 4161 unit, port, primary_port, reg_offset)); 4162 4163 if ((primary_port == -1) || (SOC_PHY_INFO(unit, primary_port).chip_info == NULL)) { 4164 return SOC_E_FAIL; 4165 } 4166 4167 chip_info = SOC_PHY_INFO(unit, primary_port).chip_info; 4168 4169 if ((chip_info->offset_to_port[2] == -1) || 4170 (chip_info->offset_to_port[4] == -1)) { 4171 4172 return SOC_E_FAIL; 4173 } 4174 4175 pc = EXT_PHY_SW_STATE(unit, port); 4176 pc_port3 = EXT_PHY_SW_STATE(unit, chip_info->offset_to_port[2]); 4177 pc_port5 = EXT_PHY_SW_STATE(unit, chip_info->offset_to_port[4]); 4178 4179 if ((!pc) || (!pc_port3) || (!pc_port5)) { 4180 return SOC_E_FAIL; 4181 } 4182 4183 /* Write Reg address to Port 5's register 0x1C, shadow 0x0B */ 4184 /* Status READ from Port 3's register 0x15 */ 4185 4186 /* Write Reg offset to Port 5's register 0x1C, shadow 0x0B */ 4187 reg_data = (0xAC00 | reg_offset); 4188 INT_MCU_LOCK(unit); 4189 rv = pc->write(unit, pc_port5->phy_id, 0x1c, reg_data); 4190 if (SOC_FAILURE(rv)) { 4191 INT_MCU_UNLOCK(unit); 4192 return rv; 4193 } 4194 4195 /* Read data from Top level MII Status register(0x15h) */ 4196 rv = pc->write(unit, pc_port3->phy_id, 0x17, 0x8F0B); 4197 if (SOC_FAILURE(rv)) { 4198 INT_MCU_UNLOCK(unit); 4199 return rv; 4200 } 4201 rv = pc->read(unit, pc_port3->phy_id, 0x15, &status); 4202 INT_MCU_UNLOCK(unit); 4203 if (SOC_FAILURE(rv)) { 4204 return rv; 4205 } 4206 4207 *data = (status & 0xff); 4208 4209 return SOC_E_NONE; 4210 } 4211 4212 /* 4213 * Function: 4214 * soc_phyctrl_toplvl_reg_write 4215 * Purpose: 4216 * Write to a top level register from a supporting chip 4217 * Parameters: 4218 * unit - SOC Unit #. 4219 * port - Port number. 4220 * primary_port - Primary Port number. 4221 * reg_offset - Offset to the reg 4222 * data - Data to be written 4223 * Returns: 4224 * SOC_E_XXX 4225 */ 4226 int 4227 soc_phyctrl_toplvl_reg_write(int unit, soc_port_t port, soc_port_t primary_port, 4228 uint8 reg_offset, uint16 data) 4229 4230 { 4231 phy_ctrl_t *pc, *pc_port3, *pc_port5, *pc_port6; 4232 uint16 reg_data; 4233 #ifdef BROADCOM_DEBUG 4234 uint16 status; 4235 #endif 4236 soc_phy_chip_info_t *chip_info; 4237 int rv = SOC_E_NONE; 4238 4239 LOG_VERBOSE(BSL_LS_SOC_PHY, 4240 (BSL_META_U(unit, 4241 "entered soc_phyctrl_toplvl_reg_write: " 4242 "unit %d, port %d, primary_port %d, reg_offset %u, data %u\n"), 4243 unit, port, primary_port, reg_offset, data)); 4244 4245 if ((primary_port == -1) || (SOC_PHY_INFO(unit, primary_port).chip_info == NULL)) { 4246 return SOC_E_FAIL; 4247 } 4248 4249 chip_info = SOC_PHY_INFO(unit, primary_port).chip_info; 4250 4251 if ((chip_info->offset_to_port[2] == -1) || 4252 (chip_info->offset_to_port[4] == -1) || 4253 (chip_info->offset_to_port[5] == -1)) { 4254 4255 return SOC_E_FAIL; 4256 } 4257 4258 pc = EXT_PHY_SW_STATE(unit, port); 4259 pc_port3 = EXT_PHY_SW_STATE(unit, chip_info->offset_to_port[2]); 4260 pc_port5 = EXT_PHY_SW_STATE(unit, chip_info->offset_to_port[4]); 4261 pc_port6 = EXT_PHY_SW_STATE(unit, chip_info->offset_to_port[5]); 4262 4263 if ((!pc) || (!pc_port3) || (!pc_port5) || (!pc_port6)) { 4264 return SOC_E_FAIL; 4265 } 4266 4267 /* Write Reg address to Port 5's register 0x1C, shadow 0x0B */ 4268 /* Write data to Port 6's register 0x1C, shadow 0x0c */ 4269 /* Status READ from Port 3's register 0x15 */ 4270 4271 /* Write Data to port6, register 0x1C, shadow 0x0c */ 4272 INT_MCU_LOCK(unit); 4273 reg_data = (0xB000 | (data & 0xff)); 4274 rv = pc->write(unit, pc_port6->phy_id, 0x1c, reg_data); 4275 if (SOC_FAILURE(rv)) { 4276 INT_MCU_UNLOCK(unit); 4277 return rv; 4278 } 4279 4280 /* Write Reg address to Port 5's register 0x1C, shadow 0x0B */ 4281 /* Enable Write ( Port 5's register 0x1C, shadow 0x0B) Bit 7 = 1 */ 4282 reg_data = (0xAC80 | reg_offset); 4283 rv = pc->write(unit, pc_port5->phy_id, 0x1c, reg_data); 4284 if (SOC_FAILURE(rv)) { 4285 INT_MCU_UNLOCK(unit); 4286 return rv; 4287 } 4288 4289 /* Disable Write ( Port 5's register 0x1C, shadow 0x0B) Bit 7 = 0 */ 4290 reg_data = (0xAC00 | reg_offset); 4291 rv = pc->write(unit, pc_port5->phy_id, 0x1c, reg_data); 4292 if (SOC_FAILURE(rv)) { 4293 INT_MCU_UNLOCK(unit); 4294 return rv; 4295 } 4296 4297 #ifdef BROADCOM_DEBUG 4298 /* Read data from Top level MII Status register(0x15h) */ 4299 rv = pc->write(unit, pc_port3->phy_id, 0x17, 0x8F0B); 4300 if (SOC_FAILURE(rv)) { 4301 INT_MCU_UNLOCK(unit); 4302 return rv; 4303 } 4304 rv = pc->read(unit, pc_port3->phy_id, 0x15, &status); 4305 4306 #endif 4307 4308 INT_MCU_UNLOCK(unit); 4309 if (SOC_FAILURE(rv)) { 4310 return rv; 4311 } 4312 4313 return SOC_E_NONE; 4314 } 4315 4316 /* 4317 * Function: 4318 * soc_phyctrl_detach 4319 * Purpose: 4320 * Remove PHY driver. 4321 * Parameters: 4322 * unit - SOC Unit #. 4323 * port - Port number. 4324 * Returns: 4325 * SOC_E_XXX 4326 */ 4327 int 4328 soc_phyctrl_detach(int unit, soc_port_t port) 4329 { 4330 phy_driver_t *phyd; 4331 phy_ctrl_t *ext_pc; 4332 phy_ctrl_t *int_pc; 4333 4334 LOG_VERBOSE(BSL_LS_SOC_PHY, 4335 (BSL_META_U(unit, 4336 "entered soc_phyctrl_detach: " 4337 "unit %d, port %d\n"), unit, port)); 4338 4339 ext_pc = EXT_PHY_SW_STATE(unit, port); 4340 int_pc = INT_PHY_SW_STATE(unit, port); 4341 4342 soc_phyctrl_phymod_free(int_pc); 4343 soc_phyctrl_phymod_free(ext_pc); 4344 4345 if (NULL != int_pc) { 4346 /* indicate to re-initialize the port. Needed for flex port op on wc */ 4347 int_pc->flags &= ~PHYCTRL_INIT_DONE; 4348 int_pc->block_init_flag = 0; 4349 } 4350 4351 SOC_IF_ERROR_RETURN(soc_phy_nocxn(unit, &phyd)); 4352 4353 if (NULL == ext_pc) { 4354 /* This function is used for Hot Swapping external PHY driver. 4355 * Therefore, always attach no connection driver to external PHY. 4356 */ 4357 ext_pc = sal_alloc (sizeof (phy_ctrl_t), phyd->drv_name); 4358 if (NULL == ext_pc) { 4359 return SOC_E_MEMORY; 4360 } 4361 4362 sal_memset(ext_pc, 0, sizeof(phy_ctrl_t)); 4363 ext_pc->unit = unit; 4364 ext_pc->port = port; 4365 ext_pc->phy_id = PHY_ADDR(unit, port); 4366 EXT_PHY_SW_STATE(unit, port) = ext_pc; 4367 } 4368 4369 ext_pc->pd = phyd; 4370 4371 /* Clear info displayed in 'phy info' */ 4372 PHY_NAME(unit, port) = "Null"; 4373 PHY_ID0_REG(unit, port) = 0; 4374 PHY_ID1_REG(unit, port) = 0; 4375 4376 /* don't clear the init done flag in independent lane mode */ 4377 if (PHY_INDEPENDENT_LANE_MODE(unit, port)) { 4378 PHY_FLAGS_CLR(unit,port,~PHY_FLAGS_INIT_DONE); 4379 } else { 4380 /* Clear the PHY configuration flags */ 4381 PHY_FLAGS_CLR_ALL(unit, port); 4382 } 4383 return SOC_E_NONE; 4384 } 4385 4386 #define PHYDEV_TYPE_MAX 20 4387 #define MDIO_BUS_NUM_MAX 8 4388 4389 STATIC int 4390 _soc_phyctrl_bcst_init(int unit, pbmp_t pbmp,char *dev_name,int bus_num,int ctrl,int ext_bus) 4391 { 4392 soc_port_t port; 4393 phy_ctrl_t *pc; 4394 int rv; 4395 char pfmt[SOC_PBMP_FMT_LEN]; 4396 4397 LOG_VERBOSE(BSL_LS_SOC_PHY, 4398 (BSL_META_U(unit, 4399 "entered soc_phyctrl_bcst_init: " 4400 "unit %d, pbmp %s, dev_name %s, bus_num %d, ctrl %d, ext_bus %d\n"), 4401 unit, SOC_PBMP_FMT(pbmp, pfmt), dev_name, bus_num, ctrl, ext_bus)); 4402 4403 PBMP_ITER(pbmp, port) { 4404 pc = ext_bus? EXT_PHY_SW_STATE(unit, port): 4405 INT_PHY_SW_STATE(unit, port); 4406 if (pc == NULL) { 4407 continue; 4408 } 4409 4410 if (((pc->dev_name != NULL) && 4411 (sal_strcmp(pc->dev_name, dev_name) == 0)) && /* match device name*/ 4412 (PHY_ID_BUS_NUM(pc->phy_id) == bus_num) && /* match bus num*/ 4413 (pc->flags & (PHYCTRL_MDIO_BCST | PHYCTRL_MDIO_BCST2))) { 4414 4415 if ((ctrl == PHYCTRL_UCODE_BCST_LOAD2) && !(pc->flags & PHYCTRL_MDIO_BCST2)) 4416 continue; 4417 if (((ctrl == PHYCTRL_UCODE_BCST_uC_SETUP || ctrl == PHYCTRL_UCODE_BCST_LOAD) && 4418 (pc->flags & PHYCTRL_MDIO_BCST)) || 4419 ((ctrl == PHYCTRL_UCODE_BCST_LOAD2) && (pc->flags & PHYCTRL_MDIO_BCST2))){ 4420 rv = soc_phyctrl_firmware_set(unit,port,ext_bus?0:SOC_PHY_INTERNAL, 4421 ctrl,NULL,0); 4422 break; 4423 } 4424 rv = soc_phyctrl_firmware_set(unit,port,ext_bus?0:SOC_PHY_INTERNAL, 4425 ctrl,NULL,0); 4426 4427 if (rv != SOC_E_NONE) { 4428 LOG_WARN(BSL_LS_SOC_PHY, 4429 (BSL_META_U(unit, 4430 "u=%d p=%d: Firmware download failed.\n"), unit, port)); 4431 } 4432 4433 if (ctrl == PHYCTRL_UCODE_BCST_END) { 4434 pc->flags |= PHYCTRL_UCODE_BCST_DONE; 4435 } 4436 } 4437 } 4438 return SOC_E_NONE; 4439 } 4440 4441 STATIC int 4442 _soc_phyctrl_ucode_bcst(int unit, pbmp_t pbmp, int ext_bus) 4443 { 4444 soc_port_t port; 4445 int dev_types; 4446 int i; 4447 int j; 4448 int bcst_num; 4449 phy_ctrl_t *pc; 4450 int rv = SOC_E_NONE; 4451 char *dev_name[PHYDEV_TYPE_MAX]; 4452 char pfmt[SOC_PBMP_FMT_LEN]; 4453 4454 LOG_VERBOSE(BSL_LS_SOC_PHY, 4455 (BSL_META_U(unit, 4456 "entered soc_phyctrl_ucode_bcst: " 4457 "unit %d, pbmp %s, ext_bus %d\n"), 4458 unit, SOC_PBMP_FMT(pbmp, pfmt), ext_bus)); 4459 4460 /* first check if bcst is requested */ 4461 bcst_num = 0; 4462 PBMP_ITER(pbmp, port) { 4463 pc = ext_bus? EXT_PHY_SW_STATE(unit, port): 4464 INT_PHY_SW_STATE(unit, port); 4465 if ((pc != NULL) && (pc->flags & (PHYCTRL_MDIO_BCST | PHYCTRL_MDIO_BCST2))) { 4466 bcst_num++; 4467 } 4468 } 4469 4470 /* if number doesn't seem valid, exit */ 4471 if (bcst_num < 1) { 4472 return SOC_E_NONE; 4473 } 4474 4475 for (i = 0; i < PHYDEV_TYPE_MAX; i++) { 4476 dev_name[i] = NULL; 4477 } 4478 4479 /* find out all PHY device types */ 4480 dev_types = 0; 4481 PBMP_ITER(pbmp, port) { 4482 pc = ext_bus? EXT_PHY_SW_STATE(unit, port): 4483 INT_PHY_SW_STATE(unit, port); 4484 if (pc == NULL) { 4485 continue; 4486 } 4487 for (i = 0; i < dev_types; i++) { 4488 if ((pc->dev_name == NULL) || 4489 (dev_name[i] == NULL) || 4490 (sal_strcmp(pc->dev_name, dev_name[i]) == 0)) { 4491 break; 4492 } 4493 } 4494 if (i >= dev_types) { 4495 if (pc->dev_name) { 4496 dev_name[dev_types++] = pc->dev_name; 4497 4498 /* exceed device name array limit */ 4499 if (dev_types >= PHYDEV_TYPE_MAX) { 4500 break; 4501 } 4502 } 4503 } 4504 } 4505 4506 /* walk through each device type */ 4507 for (i = 0; i < dev_types; i++) { 4508 4509 /* walk through each MDIO bus */ 4510 for (j = 0; j < MDIO_BUS_NUM_MAX; j++) { 4511 4512 /* pass 1: setup bcst mode for same type devices on the 4513 * same MDIO bus. go through each device 4514 */ 4515 rv = _soc_phyctrl_bcst_init(unit,pbmp,dev_name[i],j, 4516 PHYCTRL_UCODE_BCST_SETUP,ext_bus); 4517 } /* mdio bus loop */ 4518 4519 for (j = 0; j < MDIO_BUS_NUM_MAX; j++) { 4520 /* pass 2: first encounterd device's function is called. 4521 * bcst setup 4522 */ 4523 if (rv == SOC_E_NONE) { 4524 rv = _soc_phyctrl_bcst_init(unit,pbmp,dev_name[i],j, 4525 PHYCTRL_UCODE_BCST_uC_SETUP,ext_bus); 4526 } 4527 } /* mdio bus loop */ 4528 4529 for (j = 0; j < MDIO_BUS_NUM_MAX; j++) { 4530 /* pass 3: all device's functions are called. 4531 * 84740 do a reset to signal uC start of download. 4532 * However this reset clears bcst configuration register 4533 */ 4534 if (rv == SOC_E_NONE) { 4535 rv = _soc_phyctrl_bcst_init(unit,pbmp,dev_name[i],j, 4536 PHYCTRL_UCODE_BCST_ENABLE,ext_bus); 4537 } 4538 } /* mdio bus loop */ 4539 4540 for (j = 0; j < MDIO_BUS_NUM_MAX; j++) { 4541 /* pass 4: first encounterd device's function is called. 4542 * bcst data to MDIO bus. 4543 */ 4544 if (rv == SOC_E_NONE) { 4545 rv = _soc_phyctrl_bcst_init(unit,pbmp,dev_name[i],j, 4546 PHYCTRL_UCODE_BCST_LOAD,ext_bus); 4547 } 4548 } /* mdio bus loop */ 4549 4550 for (j = 0; j < MDIO_BUS_NUM_MAX; j++) { 4551 /* pass 5: first encounterd FC device's function is called. 4552 * bcst data to MDIO bus. 4553 */ 4554 if (rv == SOC_E_NONE) { 4555 rv = _soc_phyctrl_bcst_init(unit,pbmp,dev_name[i],j, 4556 PHYCTRL_UCODE_BCST_LOAD2,ext_bus); 4557 } 4558 } /* mdio bus loop */ 4559 4560 for (j = 0; j < MDIO_BUS_NUM_MAX; j++) { 4561 /* pass 6: all device's functions are called. 4562 * read and check status. At the end, the bcst mode 4563 * must be turned off 4564 */ 4565 SOC_IF_ERROR_RETURN 4566 (_soc_phyctrl_bcst_init(unit,pbmp,dev_name[i],j, 4567 PHYCTRL_UCODE_BCST_END,ext_bus)); 4568 } /* mdio bus loop */ 4569 } /* device type loop */ 4570 4571 return SOC_E_NONE; 4572 } 4573 4574 STATIC int 4575 soc_phyctrl_mdio_ucode_bcst(int unit, pbmp_t pbmp) 4576 { 4577 int rv = SOC_E_NONE; 4578 char pfmt[SOC_PBMP_FMT_LEN]; 4579 4580 LOG_VERBOSE(BSL_LS_SOC_PHY, 4581 (BSL_META_U(unit, 4582 "entered soc_phyctrl_mdio_ucode_bcst: " 4583 "unit %d, pbmp %s\n"), unit, SOC_PBMP_FMT(pbmp, pfmt))); 4584 4585 /* do external PHY device first */ 4586 rv = _soc_phyctrl_ucode_bcst(unit,pbmp,TRUE); 4587 4588 /* do internal serdes */ 4589 /* fow now skip the internal serdes */ 4590 return rv; 4591 } 4592 4593 int 4594 soc_phyctrl_pbm_probe_init(int unit, pbmp_t pbmp, pbmp_t *okay_pbmp) 4595 { 4596 int rv = SOC_E_NONE; 4597 soc_port_t port; 4598 phy_ctrl_t *int_pc; 4599 phy_ctrl_t *ext_pc; 4600 char pfmt[SOC_PBMP_FMT_LEN]; 4601 4602 LOG_VERBOSE(BSL_LS_SOC_PHY, 4603 (BSL_META_U(unit, 4604 "entered soc_phyctrl_pbm_probe_init: " 4605 "unit %d, pbmp %s,\n"), 4606 unit, SOC_PBMP_FMT(pbmp, pfmt))); 4607 4608 #ifdef INCLUDE_FCMAP 4609 #ifdef BCM_WARM_BOOT_SUPPORT 4610 if (SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit)){ 4611 /* Block blmi accesses */ 4612 SOC_IF_ERROR_RETURN( 4613 soc_fcmapphy_blmi_enable(0)); 4614 } 4615 #endif 4616 #endif 4617 4618 SOC_PBMP_CLEAR(*okay_pbmp); 4619 4620 PBMP_ITER(pbmp, port) { 4621 LOG_VERBOSE(BSL_LS_SOC_PORT, 4622 (BSL_META_U(unit, 4623 "Init port %d PHY...\n"), port)); 4624 4625 if ((rv = soc_phyctrl_probe(unit, port)) < 0) { 4626 LOG_WARN(BSL_LS_SOC_PHY, 4627 (BSL_META_U(unit, 4628 "Port %s: Failed to probe PHY: %s\n"), 4629 SOC_PORT_NAME(unit, port), soc_errmsg(rv))); 4630 break; 4631 } 4632 4633 ext_pc = EXT_PHY_SW_STATE(unit, port); 4634 int_pc = INT_PHY_SW_STATE(unit, port); 4635 4636 if (ext_pc) { 4637 PHYCTRL_INIT_STATE_SET(ext_pc,PHYCTRL_INIT_STATE_PASS1); 4638 } 4639 if (int_pc) { 4640 PHYCTRL_INIT_STATE_SET(int_pc,PHYCTRL_INIT_STATE_PASS1); 4641 } 4642 4643 /* do PHY init pass1 */ 4644 if ((rv = soc_phyctrl_init(unit, port)) < 0) { 4645 LOG_WARN(BSL_LS_SOC_PHY, 4646 (BSL_META_U(unit, 4647 "Port %s: Failed to initialize PHY: %s\n"), 4648 SOC_PORT_NAME(unit, port), soc_errmsg(rv))); 4649 break; 4650 } 4651 4652 SOC_PBMP_PORT_ADD(*okay_pbmp, port); 4653 #if defined(BCM_ESW_SUPPORT) 4654 if(!SOC_IS_SAND(unit)) { 4655 soc_counter_port_pbmp_add(unit, port); 4656 } 4657 #endif 4658 } 4659 4660 /* check/perform PHY ucode broadcast if requested on valid pbmp */ 4661 (void)soc_phyctrl_mdio_ucode_bcst(unit,*okay_pbmp); 4662 4663 /* Releases the acquired firmware as it's no longer needed. This also 4664 means that the firmware will have to be re-acquired if bcm_init is run again. */ 4665 soc_phy_fw_put_all(); 4666 4667 /* do PHY init pass2 if requested */ 4668 PBMP_ITER(*okay_pbmp, port) { 4669 ext_pc = EXT_PHY_SW_STATE(unit, port); 4670 int_pc = INT_PHY_SW_STATE(unit, port); 4671 4672 if (int_pc) { 4673 if (PHYCTRL_INIT_STATE(int_pc) == PHYCTRL_INIT_STATE_PASS2) { 4674 rv = (PHY_INIT(int_pc->pd, unit, port)); 4675 } 4676 } 4677 if (ext_pc) { 4678 if (PHYCTRL_INIT_STATE(ext_pc) == PHYCTRL_INIT_STATE_PASS2) { 4679 rv = (PHY_INIT(ext_pc->pd, unit, port)); 4680 } 4681 } 4682 } 4683 4684 /* do PHY init pass3 if requested */ 4685 PBMP_ITER(*okay_pbmp, port) { 4686 ext_pc = EXT_PHY_SW_STATE(unit, port); 4687 int_pc = INT_PHY_SW_STATE(unit, port); 4688 4689 if (int_pc) { 4690 if (PHYCTRL_INIT_STATE(int_pc) == PHYCTRL_INIT_STATE_PASS3) { 4691 rv = (PHY_INIT(int_pc->pd, unit, port)); 4692 } 4693 } 4694 if (ext_pc) { 4695 if (PHYCTRL_INIT_STATE(ext_pc) == PHYCTRL_INIT_STATE_PASS3) { 4696 rv = (PHY_INIT(ext_pc->pd, unit, port)); 4697 } 4698 } 4699 } 4700 4701 /* do PHY init pass4 if requested */ 4702 PBMP_ITER(*okay_pbmp, port) { 4703 ext_pc = EXT_PHY_SW_STATE(unit, port); 4704 int_pc = INT_PHY_SW_STATE(unit, port); 4705 4706 if (int_pc) { 4707 if (PHYCTRL_INIT_STATE(int_pc) == PHYCTRL_INIT_STATE_PASS4) { 4708 rv = (PHY_INIT(int_pc->pd, unit, port)); 4709 } 4710 } 4711 if (ext_pc) { 4712 if (PHYCTRL_INIT_STATE(ext_pc) == PHYCTRL_INIT_STATE_PASS4) { 4713 rv = (PHY_INIT(ext_pc->pd, unit, port)); 4714 } 4715 } 4716 } 4717 4718 /* do PHY init pass5 if requested */ 4719 PBMP_ITER(*okay_pbmp, port) { 4720 ext_pc = EXT_PHY_SW_STATE(unit, port); 4721 int_pc = INT_PHY_SW_STATE(unit, port); 4722 4723 if (int_pc) { 4724 if (PHYCTRL_INIT_STATE(int_pc) == PHYCTRL_INIT_STATE_PASS5) { 4725 rv = (PHY_INIT(int_pc->pd, unit, port)); 4726 } 4727 } 4728 if (ext_pc) { 4729 if (PHYCTRL_INIT_STATE(ext_pc) == PHYCTRL_INIT_STATE_PASS5) { 4730 rv = (PHY_INIT(ext_pc->pd, unit, port)); 4731 } 4732 } 4733 } 4734 4735 PBMP_ITER(*okay_pbmp, port) { 4736 ext_pc = EXT_PHY_SW_STATE(unit, port); 4737 int_pc = INT_PHY_SW_STATE(unit, port); 4738 4739 if (ext_pc) { 4740 PHYCTRL_INIT_STATE_SET(ext_pc,PHYCTRL_INIT_STATE_DEFAULT); 4741 } 4742 if (int_pc) { 4743 PHYCTRL_INIT_STATE_SET(int_pc,PHYCTRL_INIT_STATE_DEFAULT); 4744 } 4745 } 4746 4747 return rv; 4748 } 4749 4750 char * 4751 soc_phyctrl_event_string(soc_phy_event_t event) 4752 { 4753 static char *phy_event[] = PHY_EVENT_STRING; 4754 4755 LOG_VERBOSE(BSL_LS_SOC_PHY, 4756 (BSL_META("entered soc_phyctrl_event_string: " 4757 "event %d\n"), event)); 4758 4759 assert((sizeof(phy_event) / sizeof(phy_event[0])) == phyEventCount); 4760 4761 if (event >= phyEventCount) { 4762 return "Unknown Event"; 4763 } 4764 4765 return phy_event[event]; 4766 } 4767 4768 /* 4769 * Function: 4770 * soc_phyctrl_notify 4771 * Purpose: 4772 * Notify events to internal PHY driver. 4773 * Parameters: 4774 * unit - SOC Unit #. 4775 * port - Port number. 4776 * Returns: 4777 * SOC_E_XXX 4778 */ 4779 int 4780 soc_phyctrl_notify(int unit, soc_port_t port, 4781 soc_phy_event_t event, uint32 data) 4782 { 4783 int rv; 4784 phy_ctrl_t *int_pc; 4785 phy_ctrl_t *ext_pc; 4786 #ifdef BCM_ESW_SUPPORT 4787 _bcm_port_info_t *pinfo; 4788 int sys_speed, spacing_value = 0; 4789 #endif 4790 4791 LOG_VERBOSE(BSL_LS_SOC_PHY, 4792 (BSL_META_U(unit, 4793 "entered soc_phyctrl_notify: " 4794 "unit %d, port %d, event %d, data %u\n"), 4795 unit, port, event, data)); 4796 4797 ext_pc = EXT_PHY_SW_STATE(unit, port); 4798 int_pc = INT_PHY_SW_STATE(unit, port); 4799 4800 4801 4802 /* check events target to the internal serdes in all conditions */ 4803 switch(event) { 4804 case phyEventTxFifoReset: 4805 case phyEventMacLoopback: 4806 case phyEventLpiBypass: 4807 case phyEventTxSquelch: 4808 if (NULL == int_pc) { 4809 return SOC_E_INIT; 4810 } 4811 rv = (PHY_NOTIFY(int_pc->pd, unit, port, event, data)); 4812 break; 4813 case phyEventSpeedLine: 4814 #ifdef BCM_ESW_SUPPORT 4815 #ifdef PORTMOD_SUPPORT 4816 if (!soc_feature(unit, soc_feature_portmod)) { 4817 #endif 4818 SOC_IF_ERROR_RETURN(PHY_SPEED_GET(int_pc->pd, unit, port, &sys_speed)); 4819 if ((data == 2500) && (sys_speed == 10000)) { 4820 spacing_value = MAC_WAN_MODE_THROTTLE_10G_TO_2P5G; 4821 } else if ((data == 5000) && (sys_speed == 10000)) { 4822 spacing_value = MAC_WAN_MODE_THROTTLE_10G_TO_5G; 4823 } 4824 SOC_IF_ERROR_RETURN(_bcm_port_info_get(unit, port, &pinfo)); 4825 return (MAC_CONTROL_SET(pinfo->p_mac, unit, port, 4826 SOC_MAC_CONTROL_FRAME_SPACING_STRETCH, 4827 spacing_value)); 4828 #ifdef PORTMOD_SUPPORT 4829 }/* if portmod feature enabled */ 4830 #endif 4831 #endif /* BCM_ESW_SUPPORT */ 4832 break; 4833 default: 4834 break; 4835 4836 } 4837 4838 SOC_PHYCTRL_INIT_CHECK(ext_pc, int_pc); 4839 4840 rv = SOC_E_NONE; 4841 4842 if ((NULL != ext_pc) && (NULL != int_pc)) { 4843 if (!PHY_SGMII_AUTONEG_MODE(unit, port)) { 4844 rv = (PHY_NOTIFY(int_pc->pd, unit, port, event, data)); 4845 4846 PHYCTRL_VERBOSE(("u=%d p=%d event=%s data=0x%08x\n", 4847 unit, port, soc_phyctrl_event_string(event), data)); 4848 } 4849 } 4850 4851 if (SOC_FAILURE(rv)) { 4852 PHYCTRL_WARN(("soc_phyctrl_notify failed %d\n", rv)); 4853 } 4854 4855 return rv; 4856 } 4857 4858 int 4859 soc_cmic_rate_param_get(int unit, int *dividend, int *divisor) 4860 { 4861 LOG_VERBOSE(BSL_LS_SOC_PHY, 4862 (BSL_META_U(unit, 4863 "entered soc_cmic_rate_param_get: " 4864 "unit %d\n"), unit)); 4865 4866 #ifdef BCM_TRIDENT_SUPPORT 4867 if (SOC_IS_TD_TT(unit)) { 4868 return (soc_trident_cmic_rate_param_get(unit, dividend, divisor)); 4869 } else 4870 #endif /* BCM_TRIDENT_SUPPORT */ 4871 { 4872 return SOC_E_UNAVAIL; 4873 } 4874 } 4875 4876 int 4877 soc_cmic_rate_param_set(int unit, int dividend, int divisor) 4878 { 4879 LOG_VERBOSE(BSL_LS_SOC_PHY, 4880 (BSL_META_U(unit, 4881 "entered soc_cmic_rate_param_set: " 4882 "unit %d, dividend %d, divisor %d\n"), unit, dividend, divisor)); 4883 4884 #ifdef BCM_TRIDENT_SUPPORT 4885 if (SOC_IS_TD_TT(unit)) { 4886 return (soc_trident_cmic_rate_param_set(unit, dividend, divisor)); 4887 } else 4888 #endif /* BCM_TRIDENT_SUPPORT */ 4889 { 4890 return SOC_E_UNAVAIL; 4891 } 4892 } 4893 4894 STATIC void 4895 _soc_phyctrl_dump(phy_ctrl_t *pc) 4896 { 4897 static char * if_string[] = {"NOCXN", "NULL", 4898 "MII", "GMII", 4899 "SGMII", "TBI", 4900 "XGMII", "RGMII", 4901 "RvMII", "1000X"}; 4902 4903 LOG_VERBOSE(BSL_LS_SOC_PHY, 4904 (BSL_META("entered soc_phyctrl_dump\n"))); 4905 4906 4907 LOG_CLI((BSL_META("%s\n"), pc->pd->drv_name)); 4908 LOG_CLI((BSL_META("port %d\n"), pc->port)); 4909 LOG_CLI((BSL_META("phy_id0 0x%04x\n"), pc->phy_id0)); 4910 LOG_CLI((BSL_META("phy_id1 0x%04x\n"), pc->phy_id1)); 4911 LOG_CLI((BSL_META("phy_model 0x%04x\n"), pc->phy_model)); 4912 LOG_CLI((BSL_META("phy_rev 0x%04x\n"), pc->phy_rev)); 4913 LOG_CLI((BSL_META("phy_oui 0x%04x\n"), pc->phy_oui)); 4914 LOG_CLI((BSL_META("phy_id 0x%02x\n"), pc->phy_id)); 4915 LOG_CLI((BSL_META("ledmode 0x%02x, 0x%02x, 0x%02x, 0x%02x\n"), 4916 pc->ledmode[0], pc->ledmode[1], 4917 pc->ledmode[2], pc->ledmode[3])); 4918 LOG_CLI((BSL_META("ledctrl 0x%04x\n"), pc->ledctrl)); 4919 LOG_CLI((BSL_META("ledselect 0x%04x\n"), pc->ledselect)); 4920 LOG_CLI((BSL_META("automedium %s\n"), pc->automedium ? "Y" : "N")); 4921 LOG_CLI((BSL_META("tbi_capable %s\n"), pc->tbi_capable ? "Y" : "N")); 4922 LOG_CLI((BSL_META("medium %x\n"), pc->medium)); 4923 LOG_CLI((BSL_META("fiber_detect %d\n"), pc->fiber_detect)); 4924 LOG_CLI((BSL_META("halfout %d\n"), pc->halfout)); 4925 LOG_CLI((BSL_META("interface %s\n"), if_string[pc->interface])); 4926 } 4927 4928 STATIC void 4929 _soc_phyinfo_dump(int unit, soc_port_t port) 4930 { 4931 LOG_CLI((BSL_META_U(unit, 4932 "phy_id0 0x%04x\n"), PHY_ID0_REG(unit, port))); 4933 LOG_CLI((BSL_META_U(unit, 4934 "phy_id1 0x%04x\n"), PHY_ID1_REG(unit, port))); 4935 LOG_CLI((BSL_META_U(unit, 4936 "phy_addr 0x%02x\n"), PHY_ADDR(unit, port))); 4937 LOG_CLI((BSL_META_U(unit, 4938 "phy_addr_int 0x%02x\n"), PHY_ADDR_INT(unit, port))); 4939 LOG_CLI((BSL_META_U(unit, 4940 "phy_name %s\n"), PHY_NAME(unit, port))); 4941 LOG_CLI((BSL_META_U(unit, 4942 "phy_flags %s%s%s%s%s%s\n"), 4943 PHY_COPPER_MODE(unit, port) ? "COPPER\t" : "", 4944 PHY_FIBER_MODE(unit, port) ? "FIBER\t" : "", 4945 PHY_PASSTHRU_MODE(unit, port) ? "PASSTHRU\t" : "", 4946 PHY_TBI_MODE(unit, port) ? "TBI\t" : "", 4947 PHY_FIBER_100FX_MODE(unit, port) ? "100FX\t" : "", 4948 PHY_SGMII_AUTONEG_MODE(unit, port) ? "SGMII_AN\t" : "")); 4949 LOG_CLI((BSL_META_U(unit, 4950 "phy_flags %s%s%s%s%s%s\n"), 4951 PHY_WAN_MODE(unit, port) ? "WAN\t" : "", 4952 PHY_EXTERNAL_MODE(unit, port) ? "EXTERNAL\t" : "", 4953 PHY_MEDIUM_CHANGED(unit, port) ? "MEDIUM_CHANGED\t" : "", 4954 PHY_SERDES_FIBER_MODE(unit, port) ? "SERDES_FIBER\t" : "", 4955 PHY_FORCED_SGMII_MODE(unit, port) ? "FORCED_SGMII\t" : "", 4956 PHY_FORCED_COPPER_MODE(unit, port) ? "FORCED_COPPER\t" : "")); 4957 LOG_CLI((BSL_META_U(unit, 4958 "phy_flags %s%s%s\n"), 4959 PHY_CLAUSE45_MODE(unit, port) ? "C45\t" : "", 4960 PHY_DISABLED_MODE(unit, port) ? "DISABLED" : "", 4961 PHY_EEE_CAPABLE(unit, port) ? "EEE Capable" : "Not EEE Capable")); 4962 LOG_CLI((BSL_META_U(unit, 4963 "an_timeout %d\n"), PHY_AN_TIMEOUT(unit, port))); 4964 } 4965 4966 void 4967 soc_phyctrl_port_dump(int unit, soc_port_t port) 4968 { 4969 phy_ctrl_t *pc; 4970 4971 LOG_VERBOSE(BSL_LS_SOC_PHY, 4972 (BSL_META_U(unit, 4973 "entered soc_phyctrl_port_dump: " 4974 "unit %d, port %d\n"), unit, port)); 4975 4976 if (NULL == phy_port_info[unit]) { 4977 LOG_CLI((BSL_META_U(unit, 4978 "----------------------\n"))); 4979 LOG_CLI((BSL_META_U(unit, 4980 "PHY SW not initialized\n"))); 4981 LOG_CLI((BSL_META_U(unit, 4982 "----------------------\n"))); 4983 } else { 4984 _soc_phyinfo_dump(unit, port); 4985 pc = INT_PHY_SW_STATE(unit, port); 4986 if (NULL != pc) { 4987 LOG_CLI((BSL_META_U(unit, 4988 "--------------------\n"))); 4989 LOG_CLI((BSL_META_U(unit, 4990 "Internal PHY Control\n"))); 4991 LOG_CLI((BSL_META_U(unit, 4992 "--------------------\n"))); 4993 _soc_phyctrl_dump(pc); 4994 } 4995 4996 pc = EXT_PHY_SW_STATE(unit, port); 4997 if (NULL != pc) { 4998 LOG_CLI((BSL_META_U(unit, 4999 "--------------------\n"))); 5000 LOG_CLI((BSL_META_U(unit, 5001 "External PHY Control\n"))); 5002 LOG_CLI((BSL_META_U(unit, 5003 "--------------------\n"))); 5004 _soc_phyctrl_dump(pc); 5005 } 5006 } 5007 } 5008