phy82109.c (90710B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: phy82109.c 8 * Purpose: Support for Huracan external PHY 9 */ 10 11 /* 12 * This module implements an NTSW SDK Phy driver for the phy82109 External PHY. 13 * 14 * LAYERING. 15 * 16 * This driver is built on top of the PHYMOD library, which is a PHY 17 * driver library that can operate on a family of PHYs, including 18 * phy82109 and Sesto and etc.., PHYMOD can be built in a standalone enviroment and be 19 * provided independently from the SDK. PHYMOD APIs consist of 20 * "core" APIs and "phy" APIs. 21 * 22 * 23 * KEY IDEAS AND MAIN FUNCTIONS 24 * 25 * Some key ideas in this architecture are: 26 * 27 * o A PHMOD "phy" consists of one more more lanes, all residing in a single 28 * core. An SDK "phy" is a logical port, which can consist of one or 29 * more lanes in a single core, OR, can consist of multiples lanes in 30 * more than one core. 31 * o PHYMOD code is "stateless" in the sense that all calls to PHYMOD 32 * APIs are fully parameterized and no per-phy state is held by a PHYMOD 33 * driver. 34 * o PHYMOD APIs do not map 1-1 with SDK .pd_control_set or .pd_control_get 35 * APIs (nor ".pd_xx" calls, nor to .phy82109_per_lane_control_set and 36 * .phy82109_per_lane_control_get APIs. 37 * 38 * The purpose of this code, then, is to provide the necessary translations 39 * between the SDK interfaces and the PHYMOD interfaces. This includes: 40 * 41 * o Looping over the cores in a logical PHY in order to operate on the 42 * supporting PHMOD PHYs 43 * o Determining the configuration data for the phy, based on programmed 44 * defaults and SOC properties. 45 * o Managing the allocation and freeing of phy data structures required for 46 * working storage. Locating these structures on procedure invocation. 47 * o Mapping SDK API concepts to PHYMOD APIs. In some cases, local state is 48 * required in this module in order to present the legacy API. 49 * 50 * 51 * MAIN DATA STRUCTURES 52 * 53 * phy_ctrl_t 54 * The PHY control structure defines the SDK notion of a PHY 55 * (existing) structure owned by SDK phy driver modules. In order 56 * to support PHYMOD PHYs, one addition was made to this structure 57 * (soc_phymod_ctrl_t phymod_ctrl;) 58 * 59 * xxx_config_t 60 * Driver specific data. This structure is used by Huracan to hold 61 * logical port specific working storage. 62 * 63 * soc_phymod_ctrl_t 64 * PHYMOD drivers. Resides in phy_ctrl_t specifies how many cores 65 * are in this phy and contains an array of pointers to 66 * soc_phymod_phy_t structures, which define a PHYMOD PHY. 67 * 68 * soc_phymod_phy_t 69 * This structure contains a pointer to phymod_phy_access_t and a 70 * pointer to the associated soc_phymod_core_t. Instances if this 71 * structure are created during device probe/init and are maintained 72 * by the SOC. 73 * 74 * soc_phymod_core_t 75 * This structure contains per-core information. Multiple PHYMOD 76 * PHYS can point to a single core. 77 * 78 * phymod_phy_access_t 79 * This structure contains information about how to read/write PHY 80 * registers. A required parameter for PHYMOD PHY APIs 81 * 82 * phymod_core_access_t 83 * This structure contains information about how to read/write PHY 84 * registers. A required parameter for PHYMOD core APIs. 85 */ 86 87 #include <shared/bsl.h> 88 89 #include <sal/types.h> 90 #include <sal/types.h> 91 #include <sal/core/spl.h> 92 #include <shared/bsl.h> 93 #include <soc/drv.h> 94 #include <soc/debug.h> 95 #include <soc/error.h> 96 #include <soc/phyreg.h> 97 #include <soc/port_ability.h> 98 #include <soc/phy.h> 99 #include <soc/phy/phyctrl.h> 100 #include <soc/phy/drv.h> 101 #include <soc/phy/phymod_ids.h> 102 103 #include "phydefs.h" /* Must include before other phy related includes */ 104 105 #include "phyconfig.h" /* Must include before other phy related includes */ 106 #include "phyident.h" 107 #include "phyreg.h" 108 #include "phynull.h" 109 #include "xgxs.h" 110 111 #define PHYMOD_HURACAN_SUPPORT 112 113 #if defined(INCLUDE_PHY_82109) 114 115 #include <phymod/phymod.h> 116 #include <phymod/phymod_debug.h> 117 #include <phymod/phymod_diagnostics.h> 118 119 #define NUM_LANES 4 /* num of lanes per core */ 120 #define MAX_NUM_LANES 4 /* max num of lanes per port */ 121 #define PHY82109_NO_CFG_VALUE (-1) 122 #define PHY82109_DBG_REGACC 0x2 123 #define PHY82109_DBG_MEM 0x3 124 #define PHY82109_PORT_NO_LANES_4 4 125 #define PHY82109_PORT_NO_LANES_2 2 126 #define PHY82109_PORT_NO_LANES_1 1 127 #define PHY82109_SPD_100G 100000 128 #define PHY82109_SPD_10G 10000 129 #define PHY82109_SPD_20G 20000 130 #define PHY82109_SPD_25G 25000 131 #define PHY82109_SPD_40G 40000 132 #define PHY82109_SPD_50G 50000 133 #define PHY82109_SPD_6G 6000 134 #define INTERFACE_SIDE_SHIFT 31 135 #define HURACAN_ID_82109 0x82109 136 #define PHY82109_MAX_LANE 8 137 #define PHY82109_CHIP_ID_SIZE 25 138 typedef struct phy82109_speed_config_s { 139 uint32 port_refclk_int; 140 int speed; 141 int port_num_lanes; 142 uint32 line_interface; 143 int pll_divider_req ; 144 int higig_port; 145 } phy82109_speed_config_t; 146 147 typedef enum PHY82109_INTF_SIDE { 148 PHY82109_LINE_SIDE, 149 PHY82109_SYS_SIDE 150 }PHY82109_INTF_SIDE; 151 152 153 #define HURACAN_IS_SIMPLEX(devid)\ 154 ((devid) == HURACAN_ID_82109) 155 156 #define HURACAN_IS_DUPLEX(devid)\ 157 ((devid) != HURACAN_ID_82109) 158 159 /* 160 Config - per logical port 161 */ 162 typedef struct { 163 phymod_polarity_t phy_polarity_config; 164 phymod_phy_reset_t phy_reset_config; 165 phy82109_speed_config_t speed_config; 166 int an_master_lane; 167 int ull_datapath; 168 uint32_t devid; 169 char dev_name[PHY82109_CHIP_ID_SIZE]; 170 int auto_mod_detect; 171 int simplex_tx; 172 unsigned int port_phy_lane_mask; 173 } phy82109_config_t; 174 175 #define DEVID(_pc) (((phy82109_config_t *)((_pc) + 1))->devid) 176 #define DEV_NAME(_pc) (((phy82109_config_t *)((_pc) + 1))->dev_name) 177 #define SIMPLEX_TX(_pc) (((phy82109_config_t *)((_pc) + 1))->simplex_tx) 178 #define PORT_PHY_LANE_MASK(_pc) (((phy82109_config_t *)((_pc) + 1))->port_phy_lane_mask) 179 /* int is_eye_scan_enabled = 0; */ 180 181 STATIC int 182 phy_82109_ability_advert_set(int unit, soc_port_t port, 183 soc_port_ability_t *ability); 184 185 STATIC int 186 phy_82109_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability); 187 STATIC int 188 _phy_82109_find_soc_phy_lane(soc_phymod_ctrl_t *pmc, uint32_t lane, 189 soc_phymod_phy_t **p_phy, uint32 *lane_map); 190 191 STATIC int 192 phy_82109_power_set(phy_ctrl_t *pc, int32 intf, uint32 value); 193 STATIC int 194 phy_82109_power_get(phy_ctrl_t *pc, int32 intf, uint32 *value); 195 STATIC int 196 phy_82109_tx_lane_squelch_get(phy_ctrl_t *pc, int32 intf, uint32 *value); 197 STATIC int 198 phy_82109_per_lane_tx_lane_squelch_get(phy_ctrl_t *pc, int32 intf, int lane, uint32 *value); 199 STATIC int 200 _phy_82109_get_intf_side(uint32_t chip_id, int32 intf, uint32 simplex_tx, uint32 tx_rx, uint32_t *if_side); 201 202 /* 203 * Function: 204 * _phy82109_reg_read 205 * Doc: 206 * register read operations 207 * Parameters: 208 * unit - (IN) unit number 209 * core_addr - (IN) core address 210 * reg_addr - (IN) address to read 211 * val - (OUT) read value 212 */ 213 STATIC int 214 _phy82109_reg_read(void* user_acc, uint32_t core_addr, uint32_t reg_addr, uint32_t *val) 215 { 216 uint16 data16; 217 int rv; 218 soc_phymod_core_t *core = (soc_phymod_core_t *)user_acc; 219 220 rv = core->read(core->unit, core_addr, reg_addr, &data16); 221 *val = data16; 222 PHYMOD_VDBG(PHY82109_DBG_REGACC, NULL,("-22%s: core_addr: 0x%08x reg_addr: 0x%08x, data: 0x%04x\n", __func__, core_addr, reg_addr, *val )); 223 224 return rv; 225 } 226 227 /* 228 * Function: 229 * _phy82109_reg_write 230 * Doc: 231 * register write operations 232 * Parameters: 233 * unit - (IN) unit number 234 * core_addr - (IN) core address 235 * reg_addr - (IN) address to write 236 * val - (IN) write value 237 */ 238 STATIC int 239 _phy82109_reg_write(void* user_acc, uint32_t core_addr, uint32_t reg_addr, uint32_t val) 240 { 241 soc_phymod_core_t *core = (soc_phymod_core_t *)user_acc; 242 uint16 data16 = (uint16)val; 243 uint16 mask = (uint16)(val >> 16); 244 245 if (mask) { 246 if (core->wrmask) { 247 return core->wrmask(core->unit, core_addr, reg_addr, data16, mask); 248 } 249 (void)core->read(core->unit, core_addr, reg_addr, &data16); 250 data16 &= ~mask; 251 data16 |= (val & mask); 252 } 253 PHYMOD_VDBG(PHY82109_DBG_REGACC, NULL,("-22%s: core_addr: 0x%08x reg_addr: 0x%08x, data: 0x%04x\n", __func__, core_addr, reg_addr, val )); 254 return core->write(core->unit, core_addr, reg_addr, data16); 255 } 256 257 /* 258 * Function: 259 * phy82109_speed_set 260 * Purpose: 261 * Set PHY speed 262 * Parameters: 263 * unit - BCM unit number. 264 * port - Port number. 265 * speed - link speed in Mbps 266 * Returns: 267 * SOC_E_XXX 268 */ 269 270 STATIC int 271 phy82109_speed_set(int unit, soc_port_t port, int speed) 272 { 273 phy_ctrl_t *int_pc; 274 int int_speed; 275 /* locate phy control */ 276 int_pc = INT_PHY_SW_STATE(unit, port); 277 if (int_pc == NULL) { 278 return SOC_E_INTERNAL; 279 } 280 281 if (speed == 0) { 282 return SOC_E_NONE; 283 } 284 SOC_IF_ERROR_RETURN(PHY_SPEED_GET(int_pc->pd, unit, port, &int_speed)); 285 286 if (int_speed != speed) { 287 SOC_IF_ERROR_RETURN(PHY_SPEED_SET(int_pc->pd, unit, port, speed)); 288 SOC_IF_ERROR_RETURN(PHY_SPEED_GET(int_pc->pd, unit, port, &int_speed)); 289 if (int_speed != speed) { 290 return SOC_E_CONFIG; 291 } 292 } 293 return (SOC_E_NONE); 294 } 295 296 297 /* 298 * Function: 299 * phy82109_speed_get 300 * Purpose: 301 * Get PHY speed 302 * Parameters: 303 * unit - BCM unit number. 304 * port - Port number. 305 * speed - current link speed in Mbps 306 * Returns: 307 * SOC_E_XXX 308 */ 309 STATIC int 310 phy82109_speed_get(int unit, soc_port_t port, int *speed) 311 { 312 phy_ctrl_t *int_pc; 313 int int_speed; 314 315 /* locate phy control */ 316 int_pc = INT_PHY_SW_STATE(unit, port); 317 if (int_pc == NULL) { 318 return SOC_E_INTERNAL; 319 } 320 SOC_IF_ERROR_RETURN 321 (PHY_SPEED_GET(int_pc->pd, unit, port, &int_speed)); 322 *speed = int_speed; 323 return (SOC_E_NONE); 324 325 } 326 327 /* 328 * Function: 329 * phy82109_interface_set 330 * Purpose: 331 * Set PHY interface type 332 * Parameters: 333 * unit - BCM unit number. 334 * port - Port number. 335 * interface - soc interface type 336 * Returns: 337 * SOC_E_XXX 338 */ 339 340 341 STATIC int 342 phy82109_interface_set(int unit, soc_port_t port, soc_port_if_t pif) 343 { 344 phy_ctrl_t *int_pc; 345 int_pc = INT_PHY_SW_STATE(unit,port); 346 if (int_pc == NULL) { 347 return SOC_E_INTERNAL; 348 } 349 if (pif >= SOC_PORT_IF_COUNT) { 350 return SOC_E_PARAM; 351 } 352 if (pif == SOC_PORT_IF_MII || pif == SOC_PORT_IF_XGMII || pif == SOC_PORT_IF_GMII) { 353 return phy_null_interface_set(unit, port, pif); 354 } 355 SOC_IF_ERROR_RETURN 356 (PHY_INTERFACE_SET(int_pc->pd,unit,port,pif)); 357 return SOC_E_NONE; 358 } 359 360 /* 361 * Function: 362 * phy82109_interface_get 363 * Purpose: 364 * Get PHY interface type 365 * Parameters: 366 * unit - BCM unit number. 367 * port - Port number. 368 * pif - (OUT) interface type 369 * Returns: 370 * SOC_E_XXX 371 */ 372 373 STATIC int 374 phy82109_interface_get(int unit, soc_port_t port, soc_port_if_t *pif) 375 { 376 phy_ctrl_t *int_pc; 377 /* locate phy control */ 378 int_pc = INT_PHY_SW_STATE(unit,port); 379 if (int_pc == NULL) { 380 return SOC_E_INTERNAL; 381 } 382 SOC_IF_ERROR_RETURN 383 (PHY_INTERFACE_GET(int_pc->pd,unit,port,pif)); 384 return (SOC_E_NONE); 385 386 } 387 388 /* 389 * Function: 390 * phy82109_reg_read 391 * Purpose: 392 * Routine to read PHY register 393 * Parameters: 394 * unit - BCM unit number 395 * port - Port number 396 * flags - Flags which specify the register type 397 * phy_reg_addr - Encoded register address 398 * phy_data - (OUT) Value read from PHY register 399 * Returns: 400 * SOC_E_XXX 401 * Note: 402 * This register read function is not thread safe. Higher level 403 * function that calls this function must obtain a per port lock 404 * to avoid overriding register page mapping between threads. 405 */ 406 STATIC int 407 phy82109_reg_read(int unit, soc_port_t port, uint32 flags, 408 uint32 phy_reg_addr, uint32 *phy_reg_data) 409 { 410 phy_ctrl_t *pc; 411 soc_phymod_ctrl_t *pmc; 412 phymod_phy_access_t *pm_phy; 413 int idx = 0; 414 415 pc = EXT_PHY_SW_STATE(unit, port); 416 if (pc == NULL) { 417 return SOC_E_INTERNAL; 418 } 419 420 pmc = &pc->phymod_ctrl; 421 idx = pmc->main_phy ; 422 pm_phy = &pmc->phy[idx]->pm_phy; 423 424 SOC_IF_ERROR_RETURN 425 (phymod_phy_reg_read(pm_phy, phy_reg_addr, phy_reg_data)); 426 return SOC_E_NONE; 427 } 428 429 /* 430 * Function: 431 * phy82109_reg_write 432 * Purpose: 433 * Routine to write PHY register 434 * Parameters: 435 * uint - BCM unit number 436 * pc - PHY state 437 * flags - Flags which specify the register type 438 * phy_reg_addr - Encoded register address 439 * phy_data - Value write to PHY register 440 * Returns: 441 * SOC_E_XXX 442 * Note: 443 * This register read function is not thread safe. Higher level 444 * function that calls this function must obtain a per port lock 445 * to avoid overriding register page mapping between threads. 446 */ 447 STATIC int 448 phy82109_reg_write(int unit, soc_port_t port, uint32 flags, 449 uint32 phy_reg_addr, uint32 phy_reg_data) 450 { 451 phy_ctrl_t *pc; 452 soc_phymod_ctrl_t *pmc; 453 phymod_phy_access_t *pm_phy; 454 int idx; 455 pc = EXT_PHY_SW_STATE(unit, port); 456 if (pc == NULL) { 457 return SOC_E_INTERNAL; 458 } 459 460 pmc = &pc->phymod_ctrl; 461 for (idx = 0; idx < pmc->num_phys; idx++) { 462 pm_phy = &pmc->phy[idx]->pm_phy; 463 SOC_IF_ERROR_RETURN 464 (phymod_phy_reg_write(pm_phy, phy_reg_addr, phy_reg_data)); 465 } 466 return SOC_E_NONE; 467 } 468 469 /* 470 * Function: 471 * phy82109_reg_modify 472 * Purpose: 473 * Routine to write PHY register 474 * Parameters: 475 * uint - BCM unit number 476 * pc - PHY state 477 * flags - Flags which specify the register type 478 * phy_reg_addr - Encoded register address 479 * phy_mo_data - New value for the bits specified in phy_mo_mask 480 * phy_mo_mask - Bit mask to modify 481 * Returns: 482 * SOC_E_XXX 483 * Note: 484 * This function is not thread safe. Higher level 485 * function that calls this function must obtain a per port lock 486 * to avoid overriding register page mapping between threads. 487 */ 488 STATIC int 489 phy82109_reg_modify(int unit, soc_port_t port, uint32 flags, 490 uint32 phy_reg_addr, uint32 phy_data, 491 uint32 phy_data_mask) 492 { 493 phy_ctrl_t *pc; 494 soc_phymod_ctrl_t *pmc; 495 phymod_phy_access_t *pm_phy; 496 uint32 data32, tmp; 497 int idx; 498 499 pc = EXT_PHY_SW_STATE(unit, port); 500 if (pc == NULL) { 501 return SOC_E_INTERNAL; 502 } 503 504 pmc = &pc->phymod_ctrl; 505 for (idx = 0; idx < pmc->num_phys; idx++) { 506 pm_phy = &pmc->phy[idx]->pm_phy; 507 SOC_IF_ERROR_RETURN 508 (phymod_phy_reg_read(pm_phy, phy_reg_addr, &data32)); 509 tmp = data32; 510 data32 &= ~(phy_data_mask); 511 data32 |= (phy_data & phy_data_mask); 512 if (data32 != tmp) { 513 SOC_IF_ERROR_RETURN 514 (phymod_phy_reg_write(pm_phy, phy_reg_addr, data32)); 515 } 516 } 517 return SOC_E_NONE; 518 } 519 520 /* 521 * Function: 522 * phy82109_core_init 523 * Purpose: 524 * initializes phy mode core object 525 * Parameters: 526 * pc - pointer to phy control structure 527 * core - pointer to soc phy mode core object 528 * core_bus - pointer to phy mode bus driver struct 529 * core_addr - address of the phy mode core 530 * Returns: 531 * none 532 */ 533 STATIC void 534 phy82109_core_init(phy_ctrl_t *pc, soc_phymod_core_t *core, 535 phymod_bus_t *core_bus, uint32 core_addr) 536 { 537 phymod_core_access_t *pm_core; 538 phymod_access_t *pm_acc; 539 540 core->unit = pc->unit; 541 core->port = pc->port; 542 core->read = pc->read; 543 core->write = pc->write; 544 core->wrmask = pc->wrmask; 545 546 pm_core = &core->pm_core; 547 phymod_core_access_t_init(pm_core); 548 pm_acc = &pm_core->access; 549 phymod_access_t_init(pm_acc); 550 PHYMOD_ACC_USER_ACC(pm_acc) = core; 551 PHYMOD_ACC_BUS(pm_acc) = core_bus; 552 PHYMOD_ACC_ADDR(pm_acc) = core_addr; 553 554 if (soc_property_port_get(pc->unit, pc->port, "phy82109", 0) == 45) { 555 PHYMOD_ACC_F_CLAUSE45_SET(pm_acc); 556 } 557 558 return; 559 } 560 /* 561 * Function: 562 * phy82109_cleanup 563 * Purpose: 564 * clean up phy device and phy mode core object 565 * Parameters: 566 * pmc - pointer to soc phy mode control structure 567 * Returns: 568 * SOC_E_XXX 569 */ 570 STATIC void 571 phy82109_cleanup(soc_phymod_ctrl_t *pmc) 572 { 573 int idx; 574 soc_phymod_phy_t *phy; 575 soc_phymod_core_t *core; 576 for (idx = 0; idx < pmc->num_phys ; idx++) { 577 phy = pmc->phy[idx]; 578 if (phy == NULL) { 579 LOG_WARN(BSL_LS_SOC_PHY, 580 (BSL_META_U(pmc->unit, 581 "phy object is empty"))); 582 continue; 583 } 584 585 core = phy->core; 586 /* Destroy core object if not used anymore */ 587 if (core && core->ref_cnt) { 588 if (--core->ref_cnt == 0) { 589 PHYMOD_VDBG(PHY82109_DBG_MEM, NULL,("clean_up core_p=%p\n", (void *)core)) ; 590 591 soc_phymod_core_destroy(pmc->unit, core); 592 } 593 } 594 595 /* Destroy phy object */ 596 if (phy) { 597 PHYMOD_VDBG(PHY82109_DBG_MEM, NULL,("clean_up phy=%p\n", (void *)phy)) ; 598 soc_phymod_phy_destroy(pmc->unit, phy); 599 } 600 } 601 pmc->num_phys = 0; 602 } 603 604 /* 605 * Function: 606 * _phy82109_chip_id_get 607 * Purpose: 608 * read phy chip id 609 * Parameters: 610 * pm_phy - pointer to phy mode phy structure 611 * unit - switch unit number 612 * chip_id - (OUT) chip id after read 613 * Returns: 614 * SOC_E_XXX 615 */ 616 STATIC int32 617 _phy_82109_chip_id_get(phymod_phy_access_t *pm_phy, uint32 *chip_id) 618 { 619 uint32 chip_id_msb = 0, chip_id_lsb = 0; 620 621 chip_id_msb = (chip_id_msb & 0xF000) >> 12; 622 623 SOC_IF_ERROR_RETURN( 624 phymod_phy_reg_read(pm_phy, 0x8000, &chip_id_lsb)); 625 626 if (chip_id_msb == 0x0) { 627 if (chip_id_lsb == 0x2109) { 628 *chip_id = 0x82109; 629 } 630 } else { 631 LOG_WARN(BSL_LS_SOC_PHY, (BSL_META_U(0, 632 "Chip ID not found for \n"))); 633 return SOC_E_NOT_FOUND; 634 } 635 636 return SOC_E_NONE; 637 } 638 639 /* 640 * Function: 641 * phy82109_probe 642 * Purpose: 643 * xx 644 * Parameters: 645 * pc->phy_id (IN) 646 * pc->unit (IN) 647 * pc->port (IN) 648 * pc->size (OUT) - memory required by phy port 649 * pc->dev_name (OUT) - set to port device name 650 * Returns: 651 * SOC_E_XXX 652 * 653 * Note: 654 */ 655 STATIC int 656 phy82109_probe(int unit, phy_ctrl_t *pc) 657 { 658 int rv, idx; 659 uint32 lane_map, num_phys, core_id, phy_id, found; 660 phymod_bus_t core_bus; 661 phymod_dispatch_type_t phy_type; 662 phymod_core_access_t *pm_core; 663 phymod_phy_access_t *pm_phy; 664 phymod_access_t *pm_acc; 665 soc_phymod_ctrl_t *pmc; 666 soc_phymod_phy_t *phy; 667 soc_phymod_core_t *core; 668 soc_phymod_core_t core_probe; 669 soc_info_t *si; 670 phyident_core_info_t core_info[8]; 671 int array_max = 8; 672 int array_size = 0; 673 int port; 674 int phy_port; /* physical port number */ 675 uint16 chip_id = 0; 676 /* Initialize PHY bus */ 677 SOC_IF_ERROR_RETURN(phymod_bus_t_init(&core_bus)); 678 core_bus.bus_name = "phy82109"; 679 core_bus.read = _phy82109_reg_read; 680 core_bus.write = _phy82109_reg_write; 681 682 /* Configure PHY bus properties */ 683 if (pc->wrmask) { 684 PHYMOD_BUS_CAP_WR_MODIFY_SET(&core_bus); 685 PHYMOD_BUS_CAP_LANE_CTRL_SET(&core_bus); 686 } 687 688 LOG_WARN(BSL_LS_SOC_PHY, 689 (BSL_META_U(unit, 690 "port %d: probe 82109 enter !!\n"), 691 pc->port)); 692 693 port = pc->port; 694 pmc = &pc->phymod_ctrl; 695 si = &SOC_INFO(unit); 696 if (soc_feature(unit, soc_feature_logical_port_num)) { 697 phy_port = si->port_l2p_mapping[port]; 698 } else { 699 phy_port = port; 700 } 701 /* Install clean up function */ 702 pmc->unit = pc->unit; 703 pmc->cleanup = phy82109_cleanup; 704 /*pmc->symbols = &bcmi_tscf_xgxs_symbols;*/ 705 706 pc->lane_num = SOC_PORT_BINDEX(unit, phy_port); 707 pc->chip_num = SOC_BLOCK_NUMBER(unit, SOC_PORT_BLOCK(unit, phy_port)); 708 709 /* request memory for the configuration structure */ 710 pc->size = sizeof(phy82109_config_t); 711 /* Read the lane_mask config variable */ 712 PORT_PHY_LANE_MASK(pc) = soc_property_port_get(unit, port, spn_PORT_PHY_LANE_MASK, 0); 713 714 /* Bit N corresponds to lane N in lane_map */ 715 lane_map = 0xf; 716 num_phys = 1; 717 switch (si->port_num_lanes[port]) { 718 case 10: 719 pc->phy_mode = PHYCTRL_MULTI_CORE_PORT; 720 break; 721 case 4: 722 pc->phy_mode = PHYCTRL_QUAD_LANE_PORT; 723 break; 724 case 2: 725 lane_map = 0x3; 726 pc->phy_mode = PHYCTRL_DUAL_LANE_PORT; 727 break; 728 case 1: 729 case 0: 730 lane_map = 0x1; 731 pc->phy_mode = PHYCTRL_ONE_LANE_PORT; 732 break; 733 default: 734 return SOC_E_CONFIG; 735 } 736 SOC_IF_ERROR_RETURN( 737 READ_PHY_REG(unit, pc,0x18000 ,&chip_id)); 738 739 if (!PORT_PHY_LANE_MASK(pc)) { 740 if (chip_id == 0x2109) { 741 lane_map <<= (pc->lane_num | (4 * (pc->chip_num%2))); 742 } else { 743 lane_map <<= pc->lane_num; 744 } 745 } else { 746 lane_map = PORT_PHY_LANE_MASK(pc); 747 } 748 /* we need to get the other core id if more than 1 core per port */ 749 if (num_phys > 1) { 750 /* get the other core address */ 751 SOC_IF_ERROR_RETURN 752 /* 753 * COVERITY 754 * This is unreachable. It is kept intentionally as a defensive 755 * default for future development. 756 */ 757 /* coverity[dead_error_begin] */ 758 (soc_phy_addr_multi_get(unit, port, array_max, &array_size, &core_info[0])); 759 } else { 760 core_info[0].mdio_addr = pc->phy_id; 761 } 762 763 phy_type = phymodDispatchTypeHuracan; 764 765 /* Probe cores */ 766 for (idx = 0; idx < num_phys ; idx++) { 767 phy82109_core_init(pc, &core_probe, &core_bus, 768 core_info[idx].mdio_addr); 769 /* Check that core is indeed an Huracan core */ 770 pm_core = &core_probe.pm_core; 771 pm_core->type = phy_type; 772 rv = phymod_core_identify(pm_core, 0, &found); 773 if (SOC_FAILURE(rv)) { 774 LOG_WARN(BSL_LS_SOC_PHY, 775 (BSL_META_U(unit, 776 "port %d: ERROR!!!\n"), 777 pc->port)); 778 779 return rv; 780 } 781 if (!found) { 782 LOG_WARN(BSL_LS_SOC_PHY, 783 (BSL_META_U(unit, 784 "port %d: NOT FOUND!!\n"), 785 pc->port)); 786 787 return SOC_E_NOT_FOUND; 788 } 789 } 790 791 rv = SOC_E_NONE; 792 for (idx = 0; idx < num_phys ; idx++) { 793 /* Set core and phy IDs based on PHY address */ 794 core_id = pc->phy_id + idx; 795 phy_id = (lane_map << 16) | core_id; 796 /* Create PHY object */ 797 rv = soc_phymod_phy_create(unit, phy_id, &pmc->phy[idx]); 798 if (SOC_FAILURE(rv)) { 799 break; 800 } 801 pmc->num_phys++; 802 803 /* Initialize phy object */ 804 phy = pmc->phy[idx]; 805 pm_phy = &phy->pm_phy; 806 phymod_phy_access_t_init(pm_phy); 807 808 /* Find or create associated core object */ 809 rv = soc_phymod_core_find_by_id(unit, core_id, &phy->core); 810 if (rv == SOC_E_NOT_FOUND) { 811 rv = soc_phymod_core_create(unit, core_id, &phy->core); 812 } 813 if (SOC_FAILURE(rv)) { 814 break; 815 } 816 } 817 if (SOC_FAILURE(rv)) { 818 phy82109_cleanup(pmc); 819 return rv; 820 } 821 822 for (idx = 0; idx < num_phys ; idx++) { 823 phy = pmc->phy[idx]; 824 core = phy->core; 825 pm_core = &core->pm_core; 826 827 /* Initialize core object if newly created */ 828 if (core->ref_cnt == 0) { 829 sal_memcpy(&core->pm_bus, &core_bus, sizeof(core->pm_bus)); 830 phy82109_core_init(pc, core, &core->pm_bus, 831 core_info[idx].mdio_addr); 832 /* Set dispatch type */ 833 pm_core->type = phy_type; 834 } 835 core->port = pc->port; 836 core->ref_cnt++; 837 838 /* Initialize phy access based on associated core */ 839 pm_acc = &phy->pm_phy.access; 840 sal_memcpy(pm_acc, &pm_core->access, sizeof(*pm_acc)); 841 phy->pm_phy.type = phy_type; 842 PHYMOD_ACC_LANE_MASK(pm_acc) = lane_map; 843 } 844 845 return SOC_E_NONE; 846 } 847 848 849 /* 850 * Function: 851 * phy82109_config_init 852 * Purpose: 853 * Determine phy configuration data for purposes of PHYMOD initialization. 854 * 855 * A side effect of this procedure is to save some per-logical port 856 * information in (phy82109_cfg_t *) &pc->driver_data; 857 * 858 * Parameters: 859 * unit - BCM unit number. 860 * port - Port number. 861 * logical_lane_offset - starting logical lane number 862 * Returns: 863 * SOC_E_XXX 864 */ 865 STATIC int 866 phy82109_config_init(int unit, soc_port_t port, int logical_lane_offset, 867 phymod_core_init_config_t *core_init_config, 868 phymod_phy_init_config_t *pm_phy_init_config) 869 { 870 phy_ctrl_t *pc; 871 phy82109_speed_config_t *speed_config; 872 phy82109_config_t *pCfg; 873 int port_num_lanes; 874 int core_num; 875 int phy_num_lanes; 876 877 pc = EXT_PHY_SW_STATE(unit, port); 878 if (pc == NULL) { 879 return SOC_E_INTERNAL; 880 } 881 pCfg = (phy82109_config_t *) pc->driver_data; 882 883 port_num_lanes = SOC_INFO(unit).port_num_lanes[port]; 884 885 /* figure out how many lanes are in this phy */ 886 core_num = (logical_lane_offset / 4); 887 phy_num_lanes = (port_num_lanes - logical_lane_offset); 888 if (phy_num_lanes > MAX_NUM_LANES) { 889 phy_num_lanes = MAX_NUM_LANES; 890 } 891 892 SIMPLEX_TX(pc) = soc_property_port_get(unit, port, spn_PORT_PHY_MODE_REVERSE, 0); 893 /*CORE configuration*/ 894 phymod_core_init_config_t_init(core_init_config); 895 core_init_config->firmware_load_method = phymodFirmwareLoadMethodNone; 896 core_init_config->lane_map.num_of_lanes = NUM_LANES; 897 core_init_config->flags = PHYMOD_CORE_INIT_F_FIRMWARE_LOAD_VERIFY; 898 899 speed_config = &(pCfg->speed_config); 900 speed_config->port_refclk_int = 156; 901 speed_config->port_num_lanes = phy_num_lanes; 902 if (port_num_lanes == 1) { 903 if (pc->speed_max == PHY82109_SPD_25G) { 904 speed_config->line_interface = SOC_PORT_IF_LR; 905 speed_config->speed = PHY82109_SPD_25G; 906 } else { 907 speed_config->line_interface = SOC_PORT_IF_SR; 908 speed_config->speed = PHY82109_SPD_10G; 909 } 910 } else if (port_num_lanes == 4) { 911 if (pc->speed_max == PHY82109_SPD_40G) { 912 speed_config->speed = PHY82109_SPD_40G; 913 speed_config->line_interface = SOC_PORT_IF_SR4; 914 } else { 915 speed_config->speed = PHY82109_SPD_100G; 916 speed_config->line_interface = SOC_PORT_IF_LR4; 917 } 918 } else if (port_num_lanes == 2) { 919 if (pc->speed_max == PHY82109_SPD_50G) { 920 speed_config->speed = PHY82109_SPD_50G; 921 speed_config->line_interface = SOC_PORT_IF_KR2; 922 } else { 923 speed_config->speed = PHY82109_SPD_20G; 924 speed_config->line_interface = SOC_PORT_IF_LR; 925 } 926 } else { 927 LOG_CLI((BSL_META_U(unit,"Invalid number of lanes:%d\n "), port_num_lanes)); 928 return SOC_E_CONFIG; 929 } 930 LOG_CLI((BSL_META_U(unit,"number of lanes:%d\n "), port_num_lanes)); 931 932 /* PHY configuration */ 933 phymod_phy_init_config_t_init(pm_phy_init_config); 934 935 pm_phy_init_config->polarity.rx_polarity 936 = soc_property_port_get(unit, port, 937 spn_PHY_RX_POLARITY_FLIP, 938 0xFFFF); 939 pm_phy_init_config->polarity.tx_polarity 940 = soc_property_port_get(unit, port, 941 spn_PHY_TX_POLARITY_FLIP, 942 0xFFFF); 943 944 /* Only do this once, for the first core of the logical port*/ 945 if (core_num == 0) { 946 /* phy_mode, PHYCTRL_MDIO_ADDR_SHARE, PHY_FLAGS_INDEPENDENT_LANE */ 947 if (port_num_lanes == 4) { 948 pc->phy_mode = PHYCTRL_QUAD_LANE_PORT; 949 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_INDEPENDENT_LANE); 950 } else if (port_num_lanes == 2) { 951 pc->phy_mode = PHYCTRL_DUAL_LANE_PORT; 952 pc->flags |= PHYCTRL_MDIO_ADDR_SHARE; 953 PHY_FLAGS_SET(unit, port, PHY_FLAGS_INDEPENDENT_LANE); 954 } else if (port_num_lanes == 1) { 955 pc->phy_mode = PHYCTRL_ONE_LANE_PORT; 956 pc->flags |= PHYCTRL_MDIO_ADDR_SHARE; 957 PHY_FLAGS_SET(unit, port, PHY_FLAGS_INDEPENDENT_LANE); 958 } 959 960 } 961 962 return SOC_E_NONE; 963 } 964 965 /* 966 * Function: 967 * _phy82109_init_pass1 968 * Purpose: 969 * pass1 of multipass phy initialization. 970 * 971 * Parameters: 972 * unit - BCM unit number. 973 * port - Port number. 974 * Returns: 975 * SOC_E_XXX 976 */ 977 STATIC int 978 _phy_82109_init_pass1(int unit, soc_port_t port) 979 { 980 phy_ctrl_t *pc; 981 soc_phymod_ctrl_t *pmc; 982 soc_phymod_phy_t *phy = NULL; 983 soc_phymod_core_t *core; 984 phy82109_config_t *pCfg; 985 phymod_phy_inf_config_t interface_config; 986 phymod_core_status_t core_status; 987 phymod_core_info_t core_info; 988 int idx; 989 int logical_lane_offset; 990 soc_port_ability_t ability; 991 soc_phy_info_t *pi; 992 char *dev_name; 993 int len = 0; 994 uint32 chip_id = 0; 995 996 pc = EXT_PHY_SW_STATE(unit, port); 997 998 if (pc == NULL) { 999 return SOC_E_INTERNAL; 1000 } 1001 1002 pc->driver_data = (void*)(pc+1); 1003 pmc = &pc->phymod_ctrl; 1004 pCfg = (phy82109_config_t *) pc->driver_data; 1005 1006 sal_memset(pCfg, 0, sizeof(*pCfg)); 1007 1008 sal_memset(&ability, 0, sizeof(ability)); 1009 sal_memset(&interface_config, 0, sizeof(interface_config)); 1010 1011 dev_name = DEV_NAME(pc); 1012 phy = pmc->phy[0]; 1013 1014 SOC_IF_ERROR_RETURN( 1015 _phy_82109_chip_id_get(&phy->pm_phy, &chip_id)); 1016 DEVID(pc) = chip_id; 1017 1018 pi = &SOC_PHY_INFO(unit, port); 1019 if (DEVID(pc) == HURACAN_ID_82109) { 1020 /* coverity[secure_coding] */ 1021 sal_strncpy (dev_name, "BCM82109", sal_strlen("BCM82109")); 1022 } else { 1023 /* coverity[secure_coding] */ 1024 sal_strncpy (dev_name, "Huracan", sal_strlen("Huracan")); 1025 } 1026 1027 len = sal_strlen(dev_name); 1028 1029 dev_name[len++] = '/'; 1030 dev_name[len++] = pc->lane_num + '0'; 1031 dev_name[len] = 0; 1032 pc->dev_name = dev_name; /* string terminator */ 1033 pi->phy_name = dev_name; 1034 1035 /* Loop through all phymod phys that support this SDK phy */ 1036 logical_lane_offset = 0; 1037 for (idx = 0; idx < pmc->num_phys; idx++) { 1038 phy = pmc->phy[idx]; 1039 core = phy->core; 1040 /* determine configuration data structure to default values, based on SOC properties */ 1041 SOC_IF_ERROR_RETURN 1042 (phy82109_config_init(unit, port, 1043 logical_lane_offset, 1044 &core->init_config, &phy->init_config)); 1045 /* set the port to its max or init_speed */ 1046 interface_config.interface_type = phymodInterfaceXFI; 1047 interface_config.ref_clock = phymodRefClk106Mhz; 1048 sal_memcpy(&core->init_config.interface, &interface_config, sizeof(interface_config)); 1049 1050 if (!core->init) { 1051 core_status.pmd_active = 0; 1052 SOC_IF_ERROR_RETURN 1053 (phymod_core_init(&core->pm_core, &core->init_config, &core_status)); 1054 core->init = TRUE; 1055 } 1056 1057 /*phy->init_config.an_link_qualifier*/ 1058 SOC_IF_ERROR_RETURN 1059 (phymod_phy_init(&phy->pm_phy, &phy->init_config)); 1060 1061 /*read serdes id info */ 1062 SOC_IF_ERROR_RETURN 1063 (phymod_core_info_get(&core->pm_core, &core_info)); 1064 1065 /* for multicore phys, need to ratchet up to the next batch of lanes */ 1066 logical_lane_offset += core->init_config.lane_map.num_of_lanes; 1067 } 1068 /* indicate second pass of init is needed */ 1069 PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS2); 1070 1071 return SOC_E_NONE; 1072 } 1073 /* 1074 * Function: 1075 * _phy82109_init_pass2 1076 * Purpose: 1077 * pass2 of multipass phy initialization. 1078 * 1079 * Parameters: 1080 * unit - BCM unit number. 1081 * port - Port number. 1082 * Returns: 1083 * SOC_E_XXX 1084 */ 1085 STATIC int 1086 _phy_82109_init_pass2(int unit, soc_port_t port) 1087 { 1088 phy_ctrl_t *pc; 1089 soc_phymod_ctrl_t *pmc; 1090 soc_phymod_phy_t *phy = NULL; 1091 phymod_phy_inf_config_t interface_config; 1092 soc_port_ability_t ability; 1093 1094 pc = EXT_PHY_SW_STATE(unit, port); 1095 1096 if (pc == NULL) { 1097 return SOC_E_INTERNAL; 1098 } 1099 1100 sal_memset(&interface_config, 0, sizeof(interface_config)); 1101 sal_memset(&ability, 0, sizeof(ability)); 1102 pc->driver_data = (void*)(pc+1); 1103 pmc = &pc->phymod_ctrl; 1104 phy = pmc->phy[0]; 1105 1106 /* 1107 * even though huracan does not has any interface type 1108 * phymod layer expects a valid interface config, without 1109 * which core initialization can not happen, so 1110 * initializing interface type with valid values for 1111 * phymod. Huracan does not make use of this interface 1112 * settings. 1113 */ 1114 1115 interface_config.interface_type = phymodInterfaceXFI; 1116 interface_config.ref_clock = phymodRefClk106Mhz; 1117 SOC_IF_ERROR_RETURN 1118 (phymod_phy_interface_config_set(&phy->pm_phy, 1119 0 /* flags */, &interface_config)); 1120 /* setup the port's an cap */ 1121 SOC_IF_ERROR_RETURN 1122 (phy_82109_ability_local_get(unit, port, &ability)); 1123 1124 LOG_INFO(BSL_LS_SOC_PHY, 1125 (BSL_META_U(pc->unit, 1126 "phy82109_init_pass2: u=%d p=%d\n"), unit, port)); 1127 1128 if (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS2) { 1129 /* indicate third pass of init is needed */ 1130 PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS3); 1131 } 1132 1133 return SOC_E_NONE; 1134 } 1135 1136 /* 1137 * Function: 1138 * _phy82109_init_pass3 1139 * Purpose: 1140 * pass3 of multipass phy initialization. 1141 * 1142 * Parameters: 1143 * unit - BCM unit number. 1144 * port - Port number. 1145 * Returns: 1146 * SOC_E_XXX 1147 */ 1148 STATIC int 1149 _phy_82109_init_pass3(int unit, soc_port_t port) 1150 { 1151 phy_ctrl_t *pc; 1152 pc = EXT_PHY_SW_STATE(unit, port); 1153 1154 if (pc == NULL) { 1155 return SOC_E_INTERNAL; 1156 } 1157 return SOC_E_NONE; 1158 } 1159 1160 /* 1161 * Function: 1162 * phy82109_init 1163 * 1164 * An SDK "phy" is a logical port, which can consist of from 1-10 lanes, 1165 * (A phy with more than 4 lanes requires more than one core). 1166 * Per-logical port information is saved in &pc->driver_data. 1167 * An SDK phy is implemented as one or more PHYMOD "phy"s. 1168 * 1169 * A PHYMOD "phy" resides completely within a single core, which can be 1170 * from 1 to 4 lanes. 1171 * Per-phymod phy information is kept in (soc_phymod_ctrl_t) *pc->phymod_ctrl 1172 * A phymod phy points to its core. Up to 4 phymod phys can be on a single core 1173 * 1174 * Purpose: 1175 * Initialize a phy82109 1176 * Parameters: 1177 * unit - BCM unit number. 1178 * port - Port number. 1179 * Returns: 1180 * SOC_E_XXX 1181 */ 1182 STATIC int 1183 phy_82109_init(int unit, soc_port_t port) 1184 { 1185 phy_ctrl_t *pc; 1186 1187 pc = EXT_PHY_SW_STATE(unit, port); 1188 if (pc == NULL) { 1189 return SOC_E_INTERNAL; 1190 } 1191 if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS1) || 1192 (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) { 1193 1194 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER | PHY_FLAGS_C45 | PHY_FLAGS_REPEATER); 1195 SOC_IF_ERROR_RETURN(_phy_82109_init_pass1(unit, port)); 1196 1197 if (PHYCTRL_INIT_STATE(pc) != PHYCTRL_INIT_STATE_DEFAULT) { 1198 return SOC_E_NONE; 1199 } 1200 } 1201 if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS2) || 1202 (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) { 1203 1204 SOC_IF_ERROR_RETURN( _phy_82109_init_pass2(unit, port)); 1205 1206 LOG_INFO(BSL_LS_SOC_PHY, 1207 (BSL_META_U(unit, 1208 "82109 init pass2 completed: u=%d p=%d\n"), unit, port)); 1209 if (PHYCTRL_INIT_STATE(pc) != PHYCTRL_INIT_STATE_DEFAULT) { 1210 return SOC_E_NONE; 1211 } 1212 } 1213 1214 if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS3) || 1215 (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) { 1216 1217 SOC_IF_ERROR_RETURN(_phy_82109_init_pass3(unit, port)); 1218 1219 LOG_INFO(BSL_LS_SOC_PHY, 1220 (BSL_META_U(unit, 1221 "PHY82109 init pass3 completed: u=%d p=%d\n"), unit, port)); 1222 PHYCTRL_INIT_STATE_SET(pc, PHYCTRL_INIT_STATE_DEFAULT); 1223 return SOC_E_NONE; 1224 } 1225 return SOC_E_NONE; 1226 } 1227 1228 /* 1229 * Function: 1230 * phy_82109_ability_local_get 1231 * Purpose: 1232 * returns soc local port ability 1233 * Parameters: 1234 * unit - BCM unit number. 1235 * port - Port number. 1236 * ability - (OUT) soc port ability structure 1237 * Returns: 1238 * SOC_E_XXX 1239 */ 1240 STATIC int 1241 phy_82109_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 1242 { 1243 phy_ctrl_t *pc; 1244 uint32_t pa_speed = 0; 1245 1246 pc = EXT_PHY_SW_STATE(unit, port); 1247 1248 if (NULL == ability) { 1249 return SOC_E_PARAM; 1250 } 1251 1252 sal_memset(ability, 0, sizeof(*ability)); 1253 if (pc->speed_max == PHY82109_SPD_100G) { 1254 pa_speed = SOC_PA_SPEED_100GB | SOC_PA_SPEED_40GB | SOC_PA_SPEED_20GB 1255 | SOC_PA_SPEED_25GB | SOC_PA_SPEED_50GB | SOC_PA_SPEED_10GB 1256 | SOC_PA_SPEED_6000MB | SOC_PA_SPEED_1000MB; 1257 } else if (pc->speed_max == PHY82109_SPD_50G) { 1258 pa_speed = SOC_PA_SPEED_50GB | SOC_PA_SPEED_40GB | SOC_PA_SPEED_20GB 1259 | SOC_PA_SPEED_25GB | SOC_PA_SPEED_10GB | SOC_PA_SPEED_6000MB | SOC_PA_SPEED_1000MB; 1260 } else if (pc->speed_max == PHY82109_SPD_40G) { 1261 pa_speed = SOC_PA_SPEED_40GB | SOC_PA_SPEED_20GB 1262 | SOC_PA_SPEED_25GB | SOC_PA_SPEED_10GB | SOC_PA_SPEED_6000MB | 1263 SOC_PA_SPEED_1000MB; 1264 } else if (pc->speed_max == PHY82109_SPD_25G) { 1265 pa_speed = SOC_PA_SPEED_20GB | SOC_PA_SPEED_6000MB | SOC_PA_SPEED_1000MB 1266 | SOC_PA_SPEED_25GB | SOC_PA_SPEED_10GB; 1267 } else if (pc->speed_max == PHY82109_SPD_20G) { 1268 pa_speed = SOC_PA_SPEED_20GB | SOC_PA_SPEED_10GB | SOC_PA_SPEED_6000MB | SOC_PA_SPEED_1000MB; 1269 } else if (pc->speed_max == PHY82109_SPD_10G) { 1270 pa_speed = SOC_PA_SPEED_10GB | SOC_PA_SPEED_6000MB | SOC_PA_SPEED_1000MB; 1271 } else { 1272 pa_speed = SOC_PA_SPEED_100GB | SOC_PA_SPEED_40GB | SOC_PA_SPEED_20GB 1273 | SOC_PA_SPEED_25GB | SOC_PA_SPEED_50GB | SOC_PA_SPEED_10GB 1274 | SOC_PA_SPEED_6000MB | SOC_PA_SPEED_1000MB; 1275 } 1276 1277 ability->loopback = SOC_PA_LB_PHY; 1278 ability->medium = SOC_PA_MEDIUM_COPPER; 1279 ability->pause = 0; 1280 ability->flags = SOC_PA_AUTONEG; 1281 ability->speed_full_duplex = pa_speed; 1282 1283 1284 LOG_INFO(BSL_LS_SOC_PHY, 1285 (BSL_META_U(pc->unit, 1286 "phy82109_ability_local_get:unit=%d p=%d sp=%08x\n"), 1287 unit, port, ability->speed_full_duplex)); 1288 return (SOC_E_NONE); 1289 } 1290 1291 /* 1292 * Function: 1293 * phy_82109_link_get 1294 * Purpose: gets the phy link 1295 * state 1296 * 1297 * Parameters: 1298 * unit - BCM unit number. 1299 * port - Port number. 1300 * link - (OUT) link state 1301 * Returns: 1302 * SOC_E_XXX 1303 */ 1304 STATIC int 1305 phy_82109_link_get(int unit, soc_port_t port, int *link) 1306 { 1307 phy_ctrl_t *pc; 1308 soc_phymod_ctrl_t *pmc; 1309 phymod_phy_access_t *pm_phy; 1310 phy_ctrl_t *int_pc; 1311 int32 int_phy_link = 0; 1312 uint32 chip_id = 0; 1313 *link = 0; 1314 int_pc = INT_PHY_SW_STATE(unit, port); 1315 pc = EXT_PHY_SW_STATE(unit, port); 1316 if (pc == NULL) { 1317 return SOC_E_INTERNAL; 1318 } 1319 pmc = &pc->phymod_ctrl; 1320 pm_phy = &pmc->phy[pmc->main_phy]->pm_phy; 1321 if (int_pc != NULL) { 1322 SOC_IF_ERROR_RETURN(PHY_LINK_GET(int_pc->pd, unit, port, &int_phy_link)); 1323 } 1324 chip_id = DEVID(pc); 1325 if (HURACAN_IS_SIMPLEX(chip_id) && (!SIMPLEX_TX(pc))) { 1326 /* why we need to clear it ???*/ 1327 pm_phy->access.flags &= ~(1 << INTERFACE_SIDE_SHIFT); 1328 pm_phy->access.flags |= (1 << INTERFACE_SIDE_SHIFT); 1329 } 1330 /* Get the external phy link status if external phy is duplex or simplex package connected in Rx side */ 1331 if (HURACAN_IS_DUPLEX(chip_id) || (HURACAN_IS_SIMPLEX(chip_id) && (!SIMPLEX_TX(pc)))) { 1332 SOC_IF_ERROR_RETURN 1333 (phymod_phy_link_status_get(pm_phy, (uint32_t *) link)); 1334 /* When PMD lock of 82109 is not Set, Leave the port link as 1335 * PMD status of 82109. When PMD lock of 82109 is set use 1336 * PCS status of internal serdes as port link status. 1337 * When internal serdes is not there use 82109 PMS as link status*/ 1338 #ifdef PHY82109_DEBUG 1339 if (*link == 1 && int_phy_link == 0) { 1340 LOG_CLI((BSL_META_U(unit,"PMD UP PCS Down: port:%d\n "), port)); 1341 } 1342 if (*link == 0 && int_phy_link == 1) { 1343 LOG_CLI((BSL_META_U(unit,"PMD DOWN PCS UP port:%d\n "), port)); 1344 } 1345 #endif 1346 if (*link && int_pc) { 1347 *link = int_phy_link; 1348 } 1349 } else { 1350 *link = int_phy_link; 1351 } 1352 pm_phy->access.flags &= ~(1 << INTERFACE_SIDE_SHIFT); 1353 return SOC_E_NONE; 1354 } 1355 1356 /* 1357 * Function: 1358 * phy_82109_enable_set 1359 * Purpose: set's Phy's power 1360 * state 1361 * Parameters: 1362 * unit - BCM unit number. 1363 * port - Port number. 1364 * enable - value to be set 1365 * (on/off) 1366 * Returns: 1367 * SOC_E_XXX 1368 */ 1369 STATIC int 1370 phy_82109_enable_set(int unit, soc_port_t port, int enable) 1371 { 1372 phy_ctrl_t *pc; 1373 int32 intf; 1374 phy_ctrl_t *int_pc; 1375 /* locate phy control */ 1376 int_pc = INT_PHY_SW_STATE(unit, port); 1377 pc = EXT_PHY_SW_STATE(unit, port); 1378 if (pc == NULL) { 1379 return SOC_E_INTERNAL; 1380 } 1381 intf = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? PHY82109_SYS_SIDE : PHY82109_LINE_SIDE; 1382 1383 1384 SOC_IF_ERROR_RETURN 1385 (phy_82109_power_set(pc, intf, enable)); 1386 SOC_IF_ERROR_RETURN(PHY_ENABLE_SET(int_pc->pd, unit, port, enable)); 1387 1388 if (enable) { 1389 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE); 1390 } else { 1391 PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE); 1392 } 1393 1394 return SOC_E_NONE; 1395 } 1396 1397 /* 1398 * Function: 1399 * phy_82109_enable_get 1400 * Purpose: read's Phy's power 1401 * state 1402 * Parameters: 1403 * unit - BCM unit number. 1404 * port - Port number. 1405 * enable - (OUT)returned value 1406 * (on/off) 1407 * Returns: 1408 * SOC_E_XXX 1409 */ 1410 STATIC int 1411 phy_82109_enable_get(int unit, soc_port_t port, int *enable) 1412 { 1413 phy_ctrl_t *pc; 1414 int32 intf; 1415 uint32_t ena_dis; 1416 *enable = 0; 1417 1418 /* locate phy control */ 1419 pc = EXT_PHY_SW_STATE(unit, port); 1420 if (pc == NULL) { 1421 return SOC_E_INTERNAL; 1422 } 1423 intf = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? PHY82109_SYS_SIDE : PHY82109_LINE_SIDE; 1424 SOC_IF_ERROR_RETURN 1425 (phy_82109_power_get(pc, intf, &ena_dis)); 1426 *enable = ena_dis; 1427 return SOC_E_NONE; 1428 } 1429 1430 /* 1431 * Function: 1432 * phy_82109_lb_set 1433 * Purpose: sets loopback 1434 * 1435 * Parameters: 1436 * unit - BCM unit number. 1437 * port - Port number. 1438 * enable - (OUT)value to set 1439 * (on/off) 1440 * Returns: 1441 * SOC_E_XXX 1442 */ 1443 STATIC int 1444 phy_82109_lb_set(int unit, soc_port_t port, int enable) 1445 { 1446 return SOC_E_NONE; 1447 } 1448 1449 /* 1450 * Function: 1451 * phy_82109_firmware_set 1452 * Purpose: 1453 * Sets firmware for phy download. 1454 * Parameters: 1455 * unit - BCM unit number 1456 * port - Port number 1457 * array - pointer to firmware c array 1458 * offset - byte offset in the array . 1459 * datalen - length of the firmware array 1460 * Returns: 1461 * SOC_E_XXX 1462 */ 1463 STATIC int 1464 phy_82109_firmware_set(int unit, int port, int offset, uint8 *array,int datalen) 1465 { 1466 return SOC_E_UNAVAIL; 1467 1468 } 1469 1470 /* 1471 * Function: 1472 * phy_82109_rx_seq_done_get 1473 * Purpose: 1474 * Reads the rx pmd lock status. 1475 * Parameters: 1476 * pc - phy control structure. 1477 * value - (OUT) value returned 1478 * after read 1479 * intf - interface side 1480 * Returns: 1481 * SOC_E_XXX 1482 */ 1483 STATIC int 1484 phy_82109_rx_seq_done_get(phy_ctrl_t *pc, int32 intf, uint32 *value) 1485 { 1486 phymod_phy_access_t *pm_phy; 1487 phymod_phy_access_t pm_phy_copy; 1488 uint32_t if_side = 0; 1489 uint32_t chip_id = 0; 1490 uint32 simplex_tx = 0; 1491 soc_phymod_ctrl_t *pmc; 1492 pmc = &pc->phymod_ctrl; 1493 1494 1495 /* just take the value from the first phy */ 1496 if (pmc->phy[0] == NULL) { 1497 return SOC_E_INTERNAL; 1498 } 1499 pm_phy = &pmc->phy[0]->pm_phy; 1500 1501 if (pm_phy == NULL) { 1502 return SOC_E_INTERNAL; 1503 } 1504 1505 simplex_tx = SIMPLEX_TX(pc); 1506 chip_id = DEVID(pc); 1507 SOC_IF_ERROR_RETURN 1508 (_phy_82109_get_intf_side(chip_id, intf, simplex_tx, 1, &if_side)); 1509 1510 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 1511 pm_phy_copy.access.flags &= ~(1 << INTERFACE_SIDE_SHIFT); 1512 pm_phy_copy.access.flags |= if_side; 1513 1514 SOC_IF_ERROR_RETURN(phymod_phy_rx_pmd_locked_get(&pm_phy_copy, value)); 1515 1516 return(SOC_E_NONE); 1517 } 1518 /* 1519 * Function: 1520 * phy_82109_rx_signal_detect_get 1521 * Purpose: 1522 * Reads the rx signal detect status. 1523 * Parameters: 1524 * intf - interface side 1525 * pc - phy control structure. 1526 * value - (OUT) value returned 1527 * after read 1528 * Returns: 1529 * SOC_E_XXX 1530 */ 1531 STATIC int 1532 phy_82109_rx_signal_detect_get(phy_ctrl_t *pc, int32 intf, uint32 *value) 1533 { 1534 /* $$$ Need to add diagnostic API */ 1535 return(SOC_E_UNAVAIL); 1536 } 1537 /* 1538 * phy_82109_rx_ppm_get 1539 */ 1540 STATIC int 1541 phy_82109_rx_ppm_get(phy_ctrl_t *pc, int32 intf, uint32 *value) 1542 { 1543 /* $$$ Need to add diagnostic API */ 1544 return(SOC_E_UNAVAIL); 1545 } 1546 /* 1547 * Function: 1548 * phy_82109_per_lane_power_get 1549 * Purpose: 1550 * Reads the lanewise power state of phy. 1551 * Parameters: 1552 * intf - interface side 1553 * pc - phy control structure. 1554 * value - (OUT) value returned 1555 * after read 1556 * Returns: 1557 * SOC_E_XXX 1558 */ 1559 STATIC int 1560 phy_82109_per_lane_power_get(phy_ctrl_t *pc, int32 intf, int lane, uint32 *value) 1561 { 1562 phymod_phy_access_t *pm_phy; 1563 phymod_phy_power_t power; 1564 soc_phymod_phy_t *p_phy; 1565 uint32 lane_map; 1566 phymod_phy_access_t pm_phy_copy; 1567 uint32_t if_side = 0; 1568 uint32_t chip_id = 0; 1569 uint32 simplex_tx = 0; 1570 soc_phymod_ctrl_t *pmc; 1571 pmc = &pc->phymod_ctrl; 1572 *value = 0; 1573 /* locate the desired phy and lane */ 1574 SOC_IF_ERROR_RETURN(_phy_82109_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map)); 1575 1576 /* Make a copy of the phy access and overwrite the desired lane */ 1577 pm_phy = &p_phy->pm_phy; 1578 1579 simplex_tx = SIMPLEX_TX(pc); 1580 chip_id = DEVID(pc); 1581 if(HURACAN_IS_SIMPLEX(chip_id)){ 1582 if (!simplex_tx) { /* Rx simplex package */ 1583 if (intf == PHY82109_SYS_SIDE) { 1584 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 1585 } else { 1586 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 1587 if_side |= (1 << INTERFACE_SIDE_SHIFT); 1588 } 1589 } else { /* Tx simplex package */ 1590 if (intf == PHY82109_SYS_SIDE) { 1591 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 1592 if_side |= (1 << INTERFACE_SIDE_SHIFT); 1593 } else { 1594 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 1595 } 1596 } 1597 } else { 1598 if (intf == PHY82109_SYS_SIDE) { 1599 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 1600 if_side |= (1 << INTERFACE_SIDE_SHIFT); 1601 } else { 1602 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 1603 } 1604 } 1605 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 1606 pm_phy_copy.access.lane_mask = lane_map; 1607 pm_phy_copy.access.flags &= ~(1 << INTERFACE_SIDE_SHIFT); 1608 pm_phy_copy.access.flags |= if_side; 1609 1610 phymod_phy_power_t_init(&power); 1611 1612 SOC_IF_ERROR_RETURN(phymod_phy_power_get(&pm_phy_copy, &power)); 1613 1614 if(HURACAN_IS_SIMPLEX(chip_id)) { 1615 if(simplex_tx) { 1616 if(intf == PHY82109_SYS_SIDE) { 1617 if(power.rx == phymodPowerOn) 1618 *value = 1; 1619 } else { 1620 if(power.tx == phymodPowerOn) 1621 *value = 1; 1622 } 1623 } else { 1624 if(intf == PHY82109_SYS_SIDE) { 1625 if(power.tx == phymodPowerOn) 1626 *value = 1; 1627 } else { 1628 if(power.rx == phymodPowerOn) 1629 *value = 1; 1630 } 1631 } 1632 } else { 1633 if(power.tx == phymodPowerOn && power.rx == phymodPowerOn) { 1634 *value = 1; 1635 } else { 1636 *value = 0; 1637 } 1638 } 1639 return(SOC_E_NONE); 1640 } 1641 /* 1642 * Function: 1643 * phy_82109_power_get 1644 * Purpose: 1645 * Reads the power phy's state. 1646 * Parameters: 1647 * intf - interface side 1648 * pc - phy control structure. 1649 * value - (OUT) value returned 1650 * after read 1651 * Returns: 1652 * SOC_E_XXX 1653 */ 1654 STATIC int 1655 phy_82109_power_get(phy_ctrl_t *pc, int32 intf, uint32 *value) 1656 { 1657 phymod_phy_access_t *pm_phy; 1658 phymod_phy_power_t power; 1659 phymod_phy_access_t pm_phy_copy; 1660 uint32_t if_side = 0; 1661 uint32_t chip_id = 0; 1662 uint32 simplex_tx = 0; 1663 soc_phymod_ctrl_t *pmc; 1664 pmc = &pc->phymod_ctrl; 1665 *value = 0; 1666 1667 /* just take the value from the first phy */ 1668 if (pmc->phy[0] == NULL) { 1669 return SOC_E_INTERNAL; 1670 } 1671 pm_phy = &pmc->phy[0]->pm_phy; 1672 1673 if (pm_phy == NULL) { 1674 return SOC_E_INTERNAL; 1675 } 1676 1677 1678 simplex_tx = SIMPLEX_TX(pc); 1679 chip_id = DEVID(pc); 1680 if(HURACAN_IS_SIMPLEX(chip_id)){ 1681 if (!simplex_tx) { /* Rx simplex package */ 1682 if (intf == PHY82109_SYS_SIDE) { 1683 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 1684 } else { 1685 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 1686 if_side |= (1 << INTERFACE_SIDE_SHIFT); 1687 } 1688 } else { /* Tx simplex package */ 1689 if (intf == PHY82109_SYS_SIDE) { 1690 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 1691 if_side |= (1 << INTERFACE_SIDE_SHIFT); 1692 } else { 1693 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 1694 } 1695 } 1696 } else { 1697 if (intf == PHY82109_SYS_SIDE) { 1698 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 1699 if_side |= (1 << INTERFACE_SIDE_SHIFT); 1700 } else { 1701 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 1702 } 1703 } 1704 1705 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 1706 phymod_phy_power_t_init(&power); 1707 pm_phy_copy.access.flags &= ~(1 << INTERFACE_SIDE_SHIFT); 1708 pm_phy_copy.access.flags |= if_side; 1709 1710 SOC_IF_ERROR_RETURN(phymod_phy_power_get(&pm_phy_copy, &power)); 1711 1712 if(HURACAN_IS_SIMPLEX(chip_id)) { 1713 if(simplex_tx) { 1714 if(intf == PHY82109_SYS_SIDE) { 1715 if(power.rx == phymodPowerOn) 1716 *value = 1; 1717 } else { 1718 if(power.tx == phymodPowerOn) 1719 *value = 1; 1720 } 1721 } else { 1722 if(intf == PHY82109_SYS_SIDE) { 1723 if(power.tx == phymodPowerOn) 1724 *value = 1; 1725 } else { 1726 if(power.rx == phymodPowerOn) 1727 *value = 1; 1728 } 1729 } 1730 } else { 1731 if(power.tx == phymodPowerOn && power.rx == phymodPowerOn) { 1732 *value = 1; 1733 } else { 1734 *value = 0; 1735 } 1736 } 1737 return(SOC_E_NONE); 1738 } 1739 1740 /* 1741 * Function: 1742 * phy_82109_gpio_config_get 1743 * Purpose: 1744 * Reads the gpio line config. 1745 * Parameters: 1746 * pc - phy control structure. 1747 * value - (OUT) value returned 1748 * after read 1749 * Returns: 1750 * SOC_E_XXX 1751 */ 1752 STATIC int 1753 phy_82109_gpio_config_get(phy_ctrl_t *pc, uint32 *value) 1754 { 1755 phymod_phy_access_t *pm_phy; 1756 phymod_phy_access_t pm_phy_copy; 1757 phymod_gpio_mode_t gpio_mode; 1758 int gpio_pin_no = 0; 1759 soc_phymod_ctrl_t *pmc; 1760 pmc = &pc->phymod_ctrl; 1761 *value = 0; 1762 1763 /* just take the value from the first phy */ 1764 if (pmc->phy[0] == NULL) { 1765 return SOC_E_INTERNAL; 1766 } 1767 pm_phy = &pmc->phy[0]->pm_phy; 1768 1769 if (pm_phy == NULL) { 1770 return SOC_E_INTERNAL; 1771 } 1772 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 1773 1774 for (gpio_pin_no = 0; gpio_pin_no < 2; gpio_pin_no++) { 1775 SOC_IF_ERROR_RETURN(phymod_phy_gpio_config_get(&pm_phy_copy, gpio_pin_no, &gpio_mode)); 1776 *value |= (gpio_mode << (4 * gpio_pin_no)); 1777 } 1778 1779 return(SOC_E_NONE); 1780 } 1781 /* 1782 * Function: 1783 * phy_82109_gpio_value_get 1784 * Purpose: 1785 * Programmes the gpio pin. 1786 * Parameters: 1787 * pc - phy control structure. 1788 * value - (OUT)returned value after 1789 * read 1790 * Returns: 1791 * SOC_E_XXX 1792 */ 1793 STATIC int 1794 phy_82109_gpio_value_get(phy_ctrl_t *pc, uint32 *value) 1795 { 1796 phymod_phy_access_t *pm_phy; 1797 phymod_phy_access_t pm_phy_copy; 1798 int gpio_pin_no = 0; 1799 int pin_value = 0; 1800 soc_phymod_ctrl_t *pmc; 1801 pmc = &pc->phymod_ctrl; 1802 *value = 0; 1803 1804 /* just take the value from the first phy */ 1805 if (pmc->phy[0] == NULL) { 1806 return SOC_E_INTERNAL; 1807 } 1808 pm_phy = &pmc->phy[0]->pm_phy; 1809 1810 if (pm_phy == NULL) { 1811 return SOC_E_INTERNAL; 1812 } 1813 1814 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 1815 1816 for (gpio_pin_no = 0; gpio_pin_no < 2; gpio_pin_no++) { 1817 SOC_IF_ERROR_RETURN(phymod_phy_gpio_pin_value_get(&pm_phy_copy, gpio_pin_no, &pin_value)); 1818 *value |= (pin_value << (4 * gpio_pin_no)); 1819 } 1820 1821 return(SOC_E_NONE); 1822 } 1823 /* 1824 * Function: 1825 * phy82109_control_get 1826 * Purpose: 1827 * Get current control settings of the PHY. 1828 * Parameters: 1829 * unit - BCM unit number. 1830 * port - Port number. 1831 * type - Control to update 1832 * value - (OUT) Current setting for the control 1833 * Returns: 1834 * SOC_E_XXX 1835 */ 1836 STATIC int 1837 phy_82109_control_get(int unit, soc_port_t port, soc_phy_control_t type, uint32 *value) 1838 { 1839 int rv = SOC_E_UNAVAIL; 1840 phy_ctrl_t *pc; 1841 int32 intf; 1842 *value = 0; 1843 PHY_CONTROL_TYPE_CHECK(type); 1844 1845 /* locate phy control */ 1846 pc = EXT_PHY_SW_STATE(unit, port); 1847 if (pc == NULL) { 1848 return SOC_E_INTERNAL; 1849 } 1850 intf = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? PHY82109_SYS_SIDE : PHY82109_LINE_SIDE; 1851 1852 switch(type) { 1853 /* RX SIGNAL DETECT */ 1854 case SOC_PHY_CONTROL_RX_SIGNAL_DETECT: 1855 rv = phy_82109_rx_signal_detect_get(pc, intf, value); 1856 break; 1857 case SOC_PHY_CONTROL_RX_SEQ_DONE: 1858 rv = phy_82109_rx_seq_done_get(pc, intf, value); 1859 break; 1860 case SOC_PHY_CONTROL_RX_PPM: 1861 rv = phy_82109_rx_ppm_get(pc, intf, value); 1862 break; 1863 case SOC_PHY_CONTROL_POWER: 1864 rv = phy_82109_power_get(pc, intf, value); 1865 break; 1866 case SOC_PHY_CONTROL_TX_LANE_SQUELCH: 1867 rv = phy_82109_tx_lane_squelch_get(pc, intf, value); 1868 break; 1869 case SOC_PHY_CONTROL_GPIO_CONFIG: 1870 rv = phy_82109_gpio_config_get(pc, value); 1871 break; 1872 case SOC_PHY_CONTROL_GPIO_VALUE: 1873 rv = phy_82109_gpio_value_get(pc, value); 1874 break; 1875 default: 1876 rv = SOC_E_UNAVAIL; 1877 break; 1878 } 1879 return rv; 1880 } 1881 1882 /* 1883 * Function: 1884 * phy_82109_per_lane_control_get 1885 * Purpose: 1886 * Configure PHY device specific control fucntion. 1887 * Parameters: 1888 * unit - StrataSwitch unit #. 1889 * port - StrataSwitch port #. 1890 * lane - lane number 1891 * type - Control to update 1892 * value - New setting for the control 1893 * Returns: 1894 * SOC_E_XXX 1895 */ 1896 STATIC int 1897 phy_82109_per_lane_control_get(int unit, soc_port_t port, int lane, 1898 soc_phy_control_t type, uint32 *value) 1899 { 1900 int rv = SOC_E_UNAVAIL; 1901 phy_ctrl_t *pc; 1902 int32 intf; 1903 *value = 0; 1904 1905 /* locate phy control, phymod control, and the configuration data */ 1906 pc = EXT_PHY_SW_STATE(unit, port); 1907 if (pc == NULL) { 1908 return SOC_E_INTERNAL; 1909 } 1910 PHY_CONTROL_TYPE_CHECK(type); 1911 intf = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? PHY82109_SYS_SIDE : PHY82109_LINE_SIDE; 1912 1913 switch(type) { 1914 case SOC_PHY_CONTROL_POWER: 1915 1916 rv = phy_82109_per_lane_power_get(pc, intf, lane, value); 1917 break; 1918 case SOC_PHY_CONTROL_TX_LANE_SQUELCH: 1919 rv = phy_82109_per_lane_tx_lane_squelch_get(pc, intf, lane, value); 1920 break; 1921 1922 default: 1923 rv = SOC_E_UNAVAIL; 1924 break; 1925 } 1926 return rv; 1927 } 1928 1929 /* 1930 * Function: 1931 * phy82109_duplex_get 1932 * Purpose: 1933 * Get PHY duplex mode 1934 * Parameters: 1935 * unit - BCM unit number. 1936 * port - Port number. 1937 * duplex - current duplex mode 1938 * Returns: 1939 * SOC_E_XXX 1940 */ 1941 STATIC int 1942 phy82109_duplex_get(int unit, soc_port_t port, int *duplex) 1943 { 1944 *duplex = TRUE; 1945 return SOC_E_NONE; 1946 } 1947 1948 /* 1949 * Function: 1950 * phy_82109_an_set 1951 * Purpose: 1952 * Enable or disable auto-negotiation on the specified port. 1953 * Parameters: 1954 * unit - BCM unit number. 1955 * port - Port number. 1956 * an - Boolean, if true, auto-negotiation is enabled 1957 * (and/or restarted). If false, autonegotiation is disabled. 1958 * Returns: 1959 * SOC_E_XXX _soc_triumph_tx 1960 */ 1961 STATIC int 1962 phy_82109_an_set(int unit, soc_port_t port, int enable) 1963 { 1964 return (SOC_E_NONE); 1965 } 1966 /* 1967 * Function: 1968 * phy_82109_an_get 1969 * Purpose: 1970 * Get the current auto-negotiation status (enabled/busy) 1971 * Parameters: 1972 * unit - BCM unit number. 1973 * port - Port number. 1974 * an - (OUT) if true, auto-negotiation is enabled. 1975 * an_done - (OUT) if true, auto-negotiation is complete. This 1976 * value is undefined if an == false. 1977 * Returns: 1978 * SOC_E_XXX 1979 */ 1980 1981 STATIC int 1982 phy_82109_an_get(int unit, soc_port_t port, int *an, int *an_done) 1983 { 1984 *an = 0; 1985 *an_done = 0; 1986 return SOC_E_NONE; 1987 } 1988 /* 1989 * Function: 1990 * phy_82109_ability_advert_set 1991 * Purpose: 1992 * Set the current advertisement for auto-negotiation. 1993 * Parameters: 1994 * unit - BCM unit number. 1995 * port - Port number. 1996 * ability - Port mode mask indicating supported options/speeds. 1997 * Returns: 1998 * SOC_E_XXX 1999 * Notes: 2000 * The advertisement is set only for the ACTIVE medium. 2001 * No synchronization performed at this level. 2002 */ 2003 2004 STATIC int 2005 phy_82109_ability_advert_set(int unit, soc_port_t port, 2006 soc_port_ability_t *ability) 2007 { 2008 return SOC_E_NONE; 2009 } 2010 2011 /* 2012 * Function: 2013 * phy_82109_ability_advert_get 2014 * Purpose: 2015 * Get the current advertisement for auto-negotiation. 2016 * Parameters: 2017 * unit - BCM unit number. 2018 * port - Port number. 2019 * ability - (OUT) Port mode mask indicating supported options/speeds. 2020 * Returns: 2021 * SOC_E_XXX 2022 * Notes: 2023 * The advertisement is retrieved for the ACTIVE medium. 2024 * No synchronization performed at this level. 2025 */ 2026 2027 STATIC int 2028 phy_82109_ability_advert_get(int unit, soc_port_t port, 2029 soc_port_ability_t *ability) 2030 { 2031 return SOC_E_NONE; 2032 } 2033 2034 /* 2035 * Function: 2036 * phy82109_lb_get 2037 * Purpose: 2038 * Get current PHY loopback mode 2039 * Parameters: 2040 * unit - BCM unit number. 2041 * port - Port number. 2042 * enable - address of location to store binary value for on/off (1/0) 2043 * Returns: 2044 * SOC_E_XXX 2045 */ 2046 STATIC int 2047 phy82109_lb_get(int unit, soc_port_t port, int *enable) 2048 { 2049 *enable = 0; 2050 return SOC_E_NONE; 2051 } 2052 2053 STATIC int 2054 _phy_82109_get_intf_side(uint32_t chip_id, int32 intf, uint32 simplex_tx, uint32 tx_rx, uint32_t *if_side) 2055 { 2056 *if_side = 0; 2057 if (HURACAN_IS_SIMPLEX(chip_id)) { /* Simplex package */ 2058 if (tx_rx) { /* Rx side */ 2059 if (!simplex_tx) { /* Simplex Rx package */ 2060 if (intf == PHY82109_SYS_SIDE) { 2061 LOG_CLI((BSL_META_U(0,"No Rx available at SYS SIDE in Simplex Rx package\n"))); 2062 return SOC_E_UNAVAIL; 2063 } else { 2064 *if_side |= (1 << INTERFACE_SIDE_SHIFT); 2065 } 2066 } else { /* Simplex Tx package */ 2067 if (intf == PHY82109_SYS_SIDE) { 2068 *if_side |= (1 << INTERFACE_SIDE_SHIFT); 2069 } else { 2070 LOG_CLI((BSL_META_U(0,"No Rx available at LINE SIDE in Simplex Tx package\n"))); 2071 return SOC_E_UNAVAIL; 2072 } 2073 } 2074 } else { /* Tx side */ 2075 if (!simplex_tx) { /* Simplex Rx package */ 2076 if (intf == PHY82109_SYS_SIDE) { 2077 *if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 2078 } else { 2079 LOG_CLI((BSL_META_U(0,"No Tx available at LINE SIDE in Simplex Rx package\n"))); 2080 return SOC_E_UNAVAIL; 2081 } 2082 } else { /* Simplex Tx package */ 2083 if (intf == PHY82109_SYS_SIDE) { 2084 LOG_CLI((BSL_META_U(0, "No Tx available at SYS SIDE in Simplex Tx package\n"))); 2085 return SOC_E_UNAVAIL; 2086 } else { 2087 *if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 2088 } 2089 } 2090 } 2091 } else { /* Duplex package */ 2092 if (intf == PHY82109_SYS_SIDE) { 2093 *if_side |= (1 << INTERFACE_SIDE_SHIFT); 2094 } else { 2095 *if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 2096 } 2097 } 2098 return(SOC_E_NONE); 2099 } 2100 2101 /* 2102 * Function: 2103 * phy_82109_find_soc_phy_lane 2104 * Purpose: 2105 * given a pc (phymod_ctrl_t) and logical lane number, 2106 * find the correct soc_phymod_phy_t object and lane 2107 * Parameters: 2108 * pmc - soc phy control structure. 2109 * lane - lane number 2110 * lane_map - lane map 2111 * p_phy - (OUT)soc phy mod phy structure 2112 * Returns: 2113 * SOC_E_XXX 2114 */ 2115 STATIC int 2116 _phy_82109_find_soc_phy_lane(soc_phymod_ctrl_t *pmc, uint32_t lane, 2117 soc_phymod_phy_t **p_phy, uint32 *lane_map) 2118 { 2119 phymod_phy_access_t *pm_phy; 2120 int idx, lnx, ln_cnt, found; 2121 uint32 lane_map_copy; 2122 uint32 chip_id = 0; 2123 int num_lanes = 0; 2124 /* Traverse lanes belonging to this port */ 2125 found = 0; 2126 ln_cnt = 0; 2127 for (idx = 0; idx < pmc->num_phys; idx++) { 2128 pm_phy = &pmc->phy[idx]->pm_phy; 2129 if (pm_phy == NULL) { 2130 return SOC_E_INTERNAL; 2131 } 2132 lane_map_copy = pm_phy->access.lane_mask; 2133 SOC_IF_ERROR_RETURN( 2134 _phy_82109_chip_id_get(pm_phy, &chip_id)); 2135 if(HURACAN_IS_SIMPLEX(chip_id)){ 2136 num_lanes = 8; 2137 } else { 2138 num_lanes = 4; 2139 } 2140 for (lnx = 0; lnx < num_lanes; lnx++) { 2141 if ((1 << lnx) & lane_map_copy) { 2142 if ((ln_cnt == lane) || (lane == 0)) { 2143 found = 1; 2144 break; 2145 } 2146 ln_cnt++; 2147 } 2148 } 2149 if (found) { 2150 *p_phy = pmc->phy[idx]; 2151 *lane_map = (1 << lnx); 2152 break; 2153 } 2154 } 2155 2156 if (!found) { 2157 LOG_CLI((BSL_META_U(pmc->unit,"\nInvalid lane \n"))); 2158 /* No such lane */ 2159 return SOC_E_PARAM; 2160 } 2161 return (SOC_E_NONE); 2162 } 2163 /* 2164 * Function: 2165 * phy_82109_per_lane_tx_lane_squelch 2166 * Purpose: 2167 * sets/clears lanewise tx squelch 2168 * 2169 * Parameters: 2170 * pc - phy control structure. 2171 * intf - interface side 2172 * lane - lane number 2173 * value - value to set 2174 * Returns: 2175 * SOC_E_XXX 2176 */ 2177 STATIC int 2178 phy_82109_per_lane_tx_lane_squelch(phy_ctrl_t *pc, int32 intf, int lane, uint32 value) 2179 { 2180 phymod_phy_access_t *pm_phy; 2181 phymod_phy_tx_lane_control_t tx_control; 2182 int idx; 2183 phymod_phy_access_t pm_phy_copy; 2184 soc_phymod_phy_t *p_phy; 2185 uint32 lane_map; 2186 uint32_t if_side = 0; 2187 uint32_t chip_id = 0; 2188 uint32 simplex_tx = 0; 2189 soc_phymod_ctrl_t *pmc; 2190 pmc = &pc->phymod_ctrl; 2191 2192 2193 /* locate the desired phy and lane */ 2194 SOC_IF_ERROR_RETURN(_phy_82109_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map)); 2195 2196 /* loop through all cores */ 2197 for (idx = 0; idx < pmc->num_phys; idx++) { 2198 pm_phy = &pmc->phy[idx]->pm_phy; 2199 2200 if (pm_phy == NULL) { 2201 return SOC_E_INTERNAL; 2202 } 2203 2204 simplex_tx = SIMPLEX_TX(pc); 2205 chip_id = DEVID(pc); 2206 SOC_IF_ERROR_RETURN 2207 (_phy_82109_get_intf_side(chip_id, intf, simplex_tx, 0, &if_side)); 2208 2209 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 2210 pm_phy_copy.access.lane_mask = lane_map; 2211 pm_phy_copy.access.flags &= ~(1 << INTERFACE_SIDE_SHIFT); 2212 pm_phy_copy.access.flags |= if_side; 2213 2214 if (value == 1) { 2215 tx_control = phymodTxSquelchOn; 2216 } else { 2217 tx_control = phymodTxSquelchOff; 2218 } 2219 SOC_IF_ERROR_RETURN 2220 (phymod_phy_tx_lane_control_set(&pm_phy_copy, tx_control)); 2221 2222 } 2223 return(SOC_E_NONE); 2224 } 2225 2226 /* 2227 * Function: 2228 * phy_82109_per_lane_tx_lane_squelch_get 2229 * Purpose: 2230 * gets lanewise tx squelch status 2231 * 2232 * Parameters: 2233 * pc - phy control structure. 2234 * intf - interface side 2235 * lane - lane number 2236 * value - (OUT) returned value after read 2237 * Returns: 2238 * SOC_E_XXX 2239 */ 2240 STATIC int 2241 phy_82109_per_lane_tx_lane_squelch_get(phy_ctrl_t *pc, int32 intf, int lane, uint32 *value) 2242 { 2243 phymod_phy_access_t *pm_phy; 2244 phymod_phy_tx_lane_control_t tx_control; 2245 int idx; 2246 phymod_phy_access_t pm_phy_copy; 2247 soc_phymod_phy_t *p_phy; 2248 uint32 lane_map; 2249 uint32_t if_side = 0; 2250 uint32_t chip_id = 0; 2251 uint32 simplex_tx = 0; 2252 soc_phymod_ctrl_t *pmc; 2253 pmc = &pc->phymod_ctrl; 2254 2255 2256 /* locate the desired phy and lane */ 2257 SOC_IF_ERROR_RETURN(_phy_82109_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map)); 2258 2259 /* loop through all cores */ 2260 for (idx = 0; idx < pmc->num_phys; idx++) { 2261 pm_phy = &pmc->phy[idx]->pm_phy; 2262 2263 if (pm_phy == NULL) { 2264 return SOC_E_INTERNAL; 2265 } 2266 simplex_tx = SIMPLEX_TX(pc); 2267 chip_id = DEVID(pc); 2268 SOC_IF_ERROR_RETURN 2269 (_phy_82109_get_intf_side(chip_id, intf, simplex_tx, 0, &if_side)); 2270 2271 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 2272 pm_phy_copy.access.lane_mask = lane_map; 2273 pm_phy_copy.access.flags &= ~(1 << INTERFACE_SIDE_SHIFT); 2274 pm_phy_copy.access.flags |= if_side; 2275 2276 tx_control = phymodTxSquelchOn; 2277 SOC_IF_ERROR_RETURN 2278 (phymod_phy_tx_lane_control_get(&pm_phy_copy, &tx_control)); 2279 *value = tx_control; 2280 } 2281 return(SOC_E_NONE); 2282 } 2283 2284 /* 2285 * Function: 2286 * phy_82109_tx_lane_squelch 2287 * Purpose: 2288 * sets/clear's tx lane squelch 2289 * 2290 * Parameters: 2291 * pc - phy control structure. 2292 * intf - interface side 2293 * lane - 2294 * value - value to be programmed (on/off) 2295 * Returns: 2296 * SOC_E_XXX 2297 */ 2298 STATIC int 2299 phy_82109_tx_lane_squelch(phy_ctrl_t *pc, int32 intf, uint32 value) 2300 { 2301 phymod_phy_access_t *pm_phy; 2302 phymod_phy_tx_lane_control_t tx_control; 2303 int idx; 2304 phymod_phy_access_t pm_phy_copy; 2305 uint32_t if_side = 0; 2306 uint32_t chip_id = 0; 2307 uint32 simplex_tx = 0; 2308 soc_phymod_ctrl_t *pmc; 2309 pmc = &pc->phymod_ctrl; 2310 2311 /* loop through all cores */ 2312 for (idx = 0; idx < pmc->num_phys; idx++) { 2313 pm_phy = &pmc->phy[idx]->pm_phy; 2314 2315 if (pm_phy == NULL) { 2316 return SOC_E_INTERNAL; 2317 } 2318 2319 simplex_tx = SIMPLEX_TX(pc); 2320 chip_id = DEVID(pc); 2321 SOC_IF_ERROR_RETURN 2322 (_phy_82109_get_intf_side(chip_id, intf, simplex_tx, 0, &if_side)); 2323 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 2324 pm_phy_copy.access.flags &= ~(1 << INTERFACE_SIDE_SHIFT); 2325 pm_phy_copy.access.flags |= if_side; 2326 2327 if (value == 1) { 2328 tx_control = phymodTxSquelchOn; 2329 } else { 2330 tx_control = phymodTxSquelchOff; 2331 } 2332 SOC_IF_ERROR_RETURN 2333 (phymod_phy_tx_lane_control_set(&pm_phy_copy, tx_control)); 2334 2335 } 2336 return(SOC_E_NONE); 2337 } 2338 2339 /* 2340 * Function: 2341 * phy_82109_per_lane_power_set 2342 * Purpose: 2343 * Sets the lanewise interface side 2344 * power state. 2345 * Parameters: 2346 * pc - phy control structure. 2347 * intf - interface side 2348 * lane - lane number 2349 * value - value to be programmed (on/off) 2350 * Returns: 2351 * SOC_E_XXX 2352 */ 2353 STATIC int 2354 phy_82109_tx_lane_squelch_get(phy_ctrl_t *pc, int32 intf, uint32 *value) 2355 { 2356 phymod_phy_access_t *pm_phy; 2357 phymod_phy_tx_lane_control_t tx_control; 2358 int idx; 2359 phymod_phy_access_t pm_phy_copy; 2360 uint32_t if_side = 0; 2361 uint32_t chip_id = 0; 2362 uint32 simplex_tx = 0; 2363 soc_phymod_ctrl_t *pmc; 2364 pmc = &pc->phymod_ctrl; 2365 2366 /* loop through all cores */ 2367 for (idx = 0; idx < pmc->num_phys; idx++) { 2368 pm_phy = &pmc->phy[idx]->pm_phy; 2369 2370 if (pm_phy == NULL) { 2371 return SOC_E_INTERNAL; 2372 } 2373 simplex_tx = SIMPLEX_TX(pc); 2374 chip_id = DEVID(pc); 2375 SOC_IF_ERROR_RETURN 2376 (_phy_82109_get_intf_side(chip_id, intf, simplex_tx, 0, &if_side)); 2377 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 2378 pm_phy_copy.access.flags &= ~(1 << INTERFACE_SIDE_SHIFT); 2379 pm_phy_copy.access.flags |= if_side; 2380 tx_control = phymodTxSquelchOn; 2381 SOC_IF_ERROR_RETURN 2382 (phymod_phy_tx_lane_control_get(&pm_phy_copy, &tx_control)); 2383 *value = tx_control; 2384 } 2385 return(SOC_E_NONE); 2386 } 2387 /* 2388 * Function: 2389 * phy_82109_per_lane_power_set 2390 * Purpose: 2391 * Sets the lanewise interface side 2392 * power state. 2393 * Parameters: 2394 * pc - phy control structure. 2395 * intf - interface side 2396 * lane - lane number 2397 * value - value to be programmed (on/off) 2398 * Returns: 2399 * SOC_E_XXX 2400 */ 2401 STATIC int 2402 phy_82109_per_lane_power_set(phy_ctrl_t *pc, int32 intf, int lane, uint32 value) 2403 { 2404 phymod_phy_access_t *pm_phy; 2405 phymod_phy_power_t power; 2406 uint32 lane_map; 2407 phymod_phy_access_t pm_phy_copy; 2408 soc_phymod_phy_t *p_phy; 2409 uint32_t if_side = 0; 2410 uint32_t chip_id = 0; 2411 uint32 simplex_tx = 0; 2412 soc_phymod_ctrl_t *pmc; 2413 pmc = &pc->phymod_ctrl; 2414 2415 /* locate the desired phy and lane */ 2416 SOC_IF_ERROR_RETURN(_phy_82109_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map)); 2417 2418 /* Make a copy of the phy access and overwrite the desired lane */ 2419 pm_phy = &p_phy->pm_phy; 2420 2421 simplex_tx = SIMPLEX_TX(pc); 2422 chip_id = DEVID(pc); 2423 2424 phymod_phy_power_t_init(&power); 2425 if(HURACAN_IS_SIMPLEX(chip_id)){ 2426 if (!simplex_tx) { /* Rx simplex package */ 2427 if (intf == PHY82109_SYS_SIDE) { 2428 if (value) { 2429 power.tx = phymodPowerOn; 2430 power.rx = phymodPowerOn; 2431 } else { 2432 power.tx = phymodPowerOff; 2433 power.rx = phymodPowerOn; 2434 } 2435 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 2436 } else { 2437 if (value) { 2438 power.rx = phymodPowerOn; 2439 power.tx = phymodPowerOn; 2440 } else { 2441 power.rx = phymodPowerOff; 2442 power.tx = phymodPowerOn; 2443 } 2444 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 2445 if_side |= (1 << INTERFACE_SIDE_SHIFT); 2446 } 2447 } else { /* Tx simplex package */ 2448 if (intf == PHY82109_SYS_SIDE) { 2449 if (value) { 2450 power.rx = phymodPowerOn; 2451 power.tx = phymodPowerOn; 2452 } else { 2453 power.rx = phymodPowerOff; 2454 power.tx = phymodPowerOn; 2455 } 2456 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 2457 if_side |= (1 << INTERFACE_SIDE_SHIFT); 2458 } else { 2459 if (value) { 2460 power.tx = phymodPowerOn; 2461 power.rx = phymodPowerOn; 2462 } else { 2463 power.tx = phymodPowerOff; 2464 power.rx = phymodPowerOn; 2465 } 2466 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 2467 } 2468 } 2469 } else { 2470 if (value) { 2471 power.tx = phymodPowerOn; 2472 power.rx = phymodPowerOn; 2473 } else { 2474 power.tx = phymodPowerOff; 2475 power.rx = phymodPowerOff; 2476 } 2477 if (intf == PHY82109_SYS_SIDE) { 2478 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 2479 if_side |= (1 << INTERFACE_SIDE_SHIFT); 2480 } else { 2481 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 2482 } 2483 } 2484 2485 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 2486 pm_phy_copy.access.lane_mask = lane_map; 2487 pm_phy_copy.access.flags &= ~(1 << INTERFACE_SIDE_SHIFT); 2488 pm_phy_copy.access.flags |= if_side; 2489 2490 SOC_IF_ERROR_RETURN(phymod_phy_power_set(&pm_phy_copy, &power)); 2491 2492 return(SOC_E_NONE); 2493 } 2494 /* 2495 * Function: 2496 * phy_82109_power_set 2497 * Purpose: 2498 * Sets the interface side power state. 2499 * Parameters: 2500 * pc - phy control structure. 2501 * intf - interface side 2502 * value - value to be programmed (on/off) 2503 * Returns: 2504 * SOC_E_XXX 2505 */ 2506 STATIC int 2507 phy_82109_power_set(phy_ctrl_t *pc, int32 intf, uint32 value) 2508 { 2509 phymod_phy_access_t *pm_phy; 2510 phymod_phy_power_t power; 2511 int idx; 2512 phymod_phy_access_t pm_phy_copy; 2513 uint32_t if_side = 0; 2514 uint32_t chip_id = 0; 2515 uint32 simplex_tx = 0; 2516 soc_phymod_ctrl_t *pmc; 2517 pmc = &pc->phymod_ctrl; 2518 2519 /* loop through all cores */ 2520 for (idx = 0; idx < pmc->num_phys; idx++) { 2521 pm_phy = &pmc->phy[idx]->pm_phy; 2522 2523 if (pm_phy == NULL) { 2524 return SOC_E_INTERNAL; 2525 } 2526 2527 simplex_tx = SIMPLEX_TX(pc); 2528 chip_id = DEVID(pc); 2529 2530 phymod_phy_power_t_init(&power); 2531 if(HURACAN_IS_SIMPLEX(chip_id)){ 2532 if (!simplex_tx) { /* Rx simplex package */ 2533 if (intf == PHY82109_SYS_SIDE) { 2534 if (value) { 2535 power.tx = phymodPowerOn; 2536 } else { 2537 power.tx = phymodPowerOff; 2538 } 2539 power.rx = phymodPowerNoChange; 2540 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 2541 } else { 2542 if (value) { 2543 power.rx = phymodPowerOn; 2544 } else { 2545 power.rx = phymodPowerOff; 2546 } 2547 power.tx = phymodPowerNoChange; 2548 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 2549 if_side |= (1 << INTERFACE_SIDE_SHIFT); 2550 } 2551 } else { /* Tx simplex package */ 2552 if (intf == PHY82109_SYS_SIDE) { 2553 if (value) { 2554 power.rx = phymodPowerOn; 2555 } else { 2556 power.rx = phymodPowerOff; 2557 } 2558 power.tx = phymodPowerNoChange; 2559 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 2560 if_side |= (1 << INTERFACE_SIDE_SHIFT); 2561 } else { 2562 if (value) { 2563 power.tx = phymodPowerOn; 2564 } else { 2565 power.tx = phymodPowerOff; 2566 } 2567 power.rx = phymodPowerNoChange; 2568 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 2569 } 2570 } 2571 } else { 2572 if (value) { 2573 power.tx = phymodPowerOn; 2574 power.rx = phymodPowerOn; 2575 } else { 2576 power.tx = phymodPowerOff; 2577 power.rx = phymodPowerOff; 2578 } 2579 if (intf == PHY82109_SYS_SIDE) { 2580 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 2581 if_side |= (1 << INTERFACE_SIDE_SHIFT); 2582 } else { 2583 if_side &= ~(1 << INTERFACE_SIDE_SHIFT); 2584 } 2585 } 2586 2587 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 2588 pm_phy_copy.access.flags &= ~(1 << INTERFACE_SIDE_SHIFT); 2589 pm_phy_copy.access.flags |= if_side; 2590 /*sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));*/ 2591 2592 SOC_IF_ERROR_RETURN(phymod_phy_power_set(&pm_phy_copy, &power)); 2593 } 2594 2595 return(SOC_E_NONE); 2596 } 2597 /* 2598 * Function: 2599 * phy_82109_phy_dump 2600 * Purpose: 2601 * Reads the phy registers. 2602 * Parameters: 2603 * pc - phy control structure. 2604 * intf - interface side 2605 * Returns: 2606 * SOC_E_XXX 2607 */ 2608 STATIC int 2609 phy_82109_phy_dump(phy_ctrl_t *pc, int32 intf) 2610 { 2611 phymod_phy_access_t *pm_phy; 2612 int idx; 2613 phymod_phy_access_t pm_phy_copy; 2614 soc_phymod_ctrl_t *pmc; 2615 pmc = &pc->phymod_ctrl; 2616 2617 /* loop through all cores */ 2618 for (idx = 0; idx < pmc->num_phys; idx++) { 2619 pm_phy = &pmc->phy[idx]->pm_phy; 2620 2621 if (pm_phy == NULL) { 2622 return SOC_E_INTERNAL; 2623 } 2624 2625 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 2626 pm_phy_copy.access.flags &= ~(1 << INTERFACE_SIDE_SHIFT); 2627 if(intf == PHY82109_SYS_SIDE) { 2628 pm_phy_copy.access.flags |= (1 << INTERFACE_SIDE_SHIFT); 2629 } 2630 SOC_IF_ERROR_RETURN(phymod_phy_status_dump(&pm_phy_copy)); 2631 2632 } 2633 2634 return(SOC_E_NONE); 2635 } 2636 /* 2637 * Function: 2638 * phy_82109_per_lane_phy_dump 2639 * Purpose: 2640 * Reads the lanewise phy registers. 2641 * Parameters: 2642 * pc - phy control structure. 2643 * lane - lane number 2644 * intf - interface side 2645 * Returns: 2646 * SOC_E_XXX 2647 */ 2648 STATIC int 2649 phy_82109_per_lane_phy_dump(phy_ctrl_t *pc, int32 intf, int lane) 2650 { 2651 phymod_phy_access_t *pm_phy; 2652 uint32 lane_map; 2653 phymod_phy_access_t pm_phy_copy; 2654 soc_phymod_phy_t *p_phy; 2655 soc_phymod_ctrl_t *pmc; 2656 pmc = &pc->phymod_ctrl; 2657 2658 /* locate the desired phy and lane */ 2659 SOC_IF_ERROR_RETURN(_phy_82109_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map)); 2660 2661 /* Make a copy of the phy access and overwrite the desired lane */ 2662 pm_phy = &p_phy->pm_phy; 2663 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 2664 pm_phy_copy.access.lane_mask = lane_map; 2665 pm_phy_copy.access.flags &= ~(1 << INTERFACE_SIDE_SHIFT); 2666 if(intf == PHY82109_SYS_SIDE) { 2667 pm_phy_copy.access.flags |= (1 << INTERFACE_SIDE_SHIFT); 2668 } 2669 2670 SOC_IF_ERROR_RETURN(phymod_phy_status_dump(&pm_phy_copy)); 2671 return(SOC_E_NONE); 2672 } 2673 /* 2674 * Function: 2675 * phy_82109_gpio_config_set 2676 * Purpose: 2677 * Configures the gpio line. 2678 * Parameters: 2679 * pc - phy control structure. 2680 * value - value to be programmed 2681 * Returns: 2682 * SOC_E_XXX 2683 */ 2684 STATIC int 2685 phy_82109_gpio_config_set(phy_ctrl_t *pc, uint32 value) 2686 { 2687 phymod_phy_access_t *pm_phy; 2688 int idx; 2689 phymod_phy_access_t pm_phy_copy; 2690 int gpio_mode = 0; 2691 int gpio_pin_no = 0; 2692 soc_phymod_ctrl_t *pmc; 2693 pmc = &pc->phymod_ctrl; 2694 2695 /* loop through all cores */ 2696 for (idx = 0; idx < pmc->num_phys; idx++) { 2697 pm_phy = &pmc->phy[idx]->pm_phy; 2698 2699 if (pm_phy == NULL) { 2700 return SOC_E_INTERNAL; 2701 } 2702 2703 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 2704 2705 for (gpio_pin_no = 0; gpio_pin_no < 2; gpio_pin_no++) { 2706 gpio_mode = (value >> (4 * gpio_pin_no)) & 0xF; 2707 SOC_IF_ERROR_RETURN(phymod_phy_gpio_config_set(&pm_phy_copy, gpio_pin_no, (phymod_gpio_mode_t)gpio_mode)); 2708 } 2709 } 2710 2711 return(SOC_E_NONE); 2712 } 2713 2714 /* 2715 * Function: 2716 * phy_82109_gpio_value_set 2717 * Purpose: 2718 * Programmes the gpio pin. 2719 * Parameters: 2720 * pc - phy control structure. 2721 * value - value to be programmed 2722 * Returns: 2723 * SOC_E_XXX 2724 */ 2725 STATIC int 2726 phy_82109_gpio_value_set(phy_ctrl_t *pc, uint32 value) 2727 { 2728 phymod_phy_access_t *pm_phy; 2729 int idx; 2730 phymod_phy_access_t pm_phy_copy; 2731 int pin_value = 0; 2732 int gpio_pin_no = 0; 2733 soc_phymod_ctrl_t *pmc; 2734 pmc = &pc->phymod_ctrl; 2735 2736 /* loop through all cores */ 2737 for (idx = 0; idx < pmc->num_phys; idx++) { 2738 pm_phy = &pmc->phy[idx]->pm_phy; 2739 2740 if (pm_phy == NULL) { 2741 return SOC_E_INTERNAL; 2742 } 2743 2744 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 2745 2746 for (gpio_pin_no = 0; gpio_pin_no < 2; gpio_pin_no++) { 2747 pin_value = (value >> (4 * gpio_pin_no)) & 0xF; 2748 SOC_IF_ERROR_RETURN(phymod_phy_gpio_pin_value_set(&pm_phy_copy, gpio_pin_no, pin_value)); 2749 } 2750 } 2751 2752 return(SOC_E_NONE); 2753 } 2754 /* 2755 * Function: 2756 * phy_82109_control_set 2757 * Purpose: 2758 * Configure PHY device specific control function. 2759 * Parameters: 2760 * unit - BCM unit number. 2761 * port - Port number. 2762 * type - Control to update 2763 * value - New setting for the control 2764 * Returns: 2765 * SOC_E_XXX 2766 */ 2767 STATIC int 2768 phy_82109_control_set(int unit, soc_port_t port, soc_phy_control_t type, uint32 value) 2769 { 2770 int rv; 2771 phy_ctrl_t *pc; 2772 int32 intf; 2773 rv = SOC_E_UNAVAIL; 2774 PHY_CONTROL_TYPE_CHECK(type); 2775 /* locate phy control, phymod control, and the configuration data */ 2776 pc = EXT_PHY_SW_STATE(unit, port); 2777 if (pc == NULL) { 2778 return SOC_E_INTERNAL; 2779 } 2780 intf = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? PHY82109_SYS_SIDE : PHY82109_LINE_SIDE; 2781 switch(type) { 2782 /* TX LANE SQUELCH */ 2783 case SOC_PHY_CONTROL_TX_LANE_SQUELCH: 2784 rv = phy_82109_tx_lane_squelch(pc, intf, value); 2785 break; 2786 /* POWER */ 2787 case SOC_PHY_CONTROL_POWER: 2788 { 2789 phy_ctrl_t *int_pc; 2790 int_pc = INT_PHY_SW_STATE(unit, port); 2791 SOC_IF_ERROR_RETURN(PHY_ENABLE_SET(int_pc->pd, unit, port, value)); 2792 rv = phy_82109_power_set(pc, intf, value); 2793 } 2794 break; 2795 case SOC_PHY_CONTROL_DUMP: 2796 rv = phy_82109_phy_dump(pc, intf); 2797 break; 2798 case SOC_PHY_CONTROL_GPIO_CONFIG: 2799 rv = phy_82109_gpio_config_set(pc, value); 2800 break; 2801 case SOC_PHY_CONTROL_GPIO_VALUE: 2802 rv = phy_82109_gpio_value_set(pc, value); 2803 break; 2804 default: 2805 rv = SOC_E_UNAVAIL; 2806 break; 2807 } 2808 return rv; 2809 } 2810 /* 2811 * Function: 2812 * phy_82109_per_lane_control_set 2813 * Purpose: 2814 * Configure PHY device specific control function. 2815 * Parameters: 2816 * unit - StrataSwitch unit #. 2817 * port - StrataSwitch port #. 2818 * lane - lane number 2819 * type - Control to update 2820 * value - New setting for the control 2821 * Returns: 2822 * SOC_E_XXX 2823 */ 2824 STATIC int 2825 phy_82109_per_lane_control_set(int unit, soc_port_t port, int lane, soc_phy_control_t type, uint32 value) 2826 { 2827 int rv = SOC_E_UNAVAIL; 2828 phy_ctrl_t *pc; 2829 int32 intf; 2830 /* locate phy control, phymod control, and the configuration data */ 2831 pc = EXT_PHY_SW_STATE(unit, port); 2832 if (pc == NULL) { 2833 return SOC_E_INTERNAL; 2834 } 2835 PHY_CONTROL_TYPE_CHECK(type); 2836 2837 intf = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? PHY82109_SYS_SIDE : PHY82109_LINE_SIDE; 2838 2839 switch(type) { 2840 /* TX LANE SQUELCH */ 2841 case SOC_PHY_CONTROL_TX_LANE_SQUELCH: 2842 rv = phy_82109_per_lane_tx_lane_squelch(pc, intf, lane, value); 2843 break; 2844 /*POWER */ 2845 case SOC_PHY_CONTROL_POWER: 2846 rv = phy_82109_per_lane_power_set(pc, intf, lane, value); 2847 break; 2848 case SOC_PHY_CONTROL_DUMP: 2849 rv = phy_82109_per_lane_phy_dump(pc, intf, lane); 2850 break; 2851 default: 2852 rv = SOC_E_UNAVAIL; 2853 break; 2854 } 2855 2856 return rv; 2857 } 2858 /* 2859 * Function: 2860 * phy_82109_diag_ctrl 2861 * Purpose: 2862 * xx 2863 * Parameters: 2864 * unit - BCM unit number. 2865 * port - Port number. 2866 2867 * Returns: 2868 * SOC_E_XXX 2869 */ 2870 2871 STATIC int 2872 phy_82109_diag_ctrl( 2873 int unit, /* unit */ 2874 soc_port_t port, /* port */ 2875 uint32 inst, /* the specific device block the control action directs to */ 2876 int op_type, /* operation types: read,write or command sequence */ 2877 int op_cmd, /* command code */ 2878 void *arg) /* command argument based on op_type/op_cmd */ 2879 { 2880 int rv = -1; 2881 phy_ctrl_t *pc; 2882 /* locate phy control, phymod control, and the configuration data */ 2883 pc = EXT_PHY_SW_STATE(unit, port); 2884 if (pc == NULL) { 2885 return SOC_E_INTERNAL; 2886 } 2887 switch(op_cmd) { 2888 case PHY_DIAG_CTRL_DSC: 2889 case PHY_DIAG_CTRL_LINKMON_MODE: 2890 case PHY_DIAG_CTRL_LINKMON_STATUS: 2891 rv = SOC_E_UNAVAIL; 2892 break; 2893 default: 2894 if (op_type == PHY_DIAG_CTRL_SET) { 2895 rv = phy_82109_control_set(unit,port,op_cmd,PTR_TO_INT(arg)); 2896 } else if (op_type == PHY_DIAG_CTRL_GET) { 2897 rv = phy_82109_control_get(unit,port,op_cmd,(uint32 *)arg); 2898 } 2899 break ; 2900 } 2901 return rv; 2902 } 2903 2904 /* 2905 * Function: 2906 * _phy_82109_core_reset 2907 * Purpose: 2908 * Reset's the phy core. 2909 * Parameters: 2910 * unit - StrataSwitch unit #. 2911 * port - StrataSwitch port #. 2912 * not_used - don't care. 2913 * Returns: 2914 * SOC_E_XXX 2915 */ 2916 int32 phy_82109_core_reset(int32 unit, soc_port_t port, void *not_used) 2917 { 2918 phy_ctrl_t *pc; 2919 soc_phymod_core_t *pmc_core; 2920 int idx; 2921 phymod_core_access_t *pm_core; 2922 soc_phymod_ctrl_t *pmc; 2923 phymod_reset_direction_t reset_direction; 2924 /* locate phy control */ 2925 pc = EXT_PHY_SW_STATE(unit, port); 2926 if (pc == NULL) { 2927 return SOC_E_INTERNAL; 2928 } 2929 reset_direction = phymodResetDirectionIn; 2930 pmc = &pc->phymod_ctrl; 2931 2932 /* loop through all cores */ 2933 for (idx = 0; idx < pmc->num_phys; idx++) { 2934 pmc_core = pmc->phy[idx]->core; 2935 pm_core = &pmc_core->pm_core; 2936 if (pm_core == NULL) { 2937 return SOC_E_INTERNAL; 2938 } 2939 /* Soft reset is not supported in Huracan */ 2940 SOC_IF_ERROR_RETURN(phymod_core_reset_set(pm_core, phymodResetModeHard, reset_direction)); 2941 } 2942 return(SOC_E_NONE); 2943 } 2944 /* 2945 * Function: 2946 * _phy_82109_ability_remote_get 2947 * Purpose: 2948 * Get the device's complete abilities. 2949 * Parameters: 2950 * unit - StrataSwitch unit #. 2951 * port - StrataSwitch port #. 2952 * ability - return device's abilities. 2953 * Returns: 2954 * SOC_E_XXX 2955 */ 2956 STATIC int 2957 phy_82109_ability_remote_get(int unit, soc_port_t port, 2958 soc_port_ability_t *ability) 2959 { 2960 return SOC_E_NONE; 2961 } 2962 /* 2963 * Variable: 2964 * phy82109_drv 2965 * Purpose: 2966 * Phy Driver for phy82109 2967 */ 2968 phy_driver_t phy82109_drv = { 2969 /* .drv_name = */ "PHY82109 PHYMOD PHY Driver", 2970 /* .pd_init = */ phy_82109_init, 2971 /* .pd_reset = */ phy_82109_core_reset, 2972 /* .pd_link_get = */ phy_82109_link_get, 2973 /* .pd_enable_set = */ phy_82109_enable_set, 2974 /* .pd_enable_get = */ phy_82109_enable_get, 2975 /* .pd_duplex_set = */ phy_null_set, 2976 /* .pd_duplex_get = */ phy82109_duplex_get, 2977 /* .pd_speed_set = */ phy82109_speed_set, 2978 /* .pd_speed_get = */ phy82109_speed_get, 2979 /* .pd_master_set = */ phy_null_set, 2980 /* .pd_master_get = */ phy_null_zero_get, 2981 /* .pd_an_set = */ phy_82109_an_set, 2982 /* .pd_an_get = */ phy_82109_an_get, 2983 2984 /* .pd_adv_local_set = */ NULL, /* Deprecated */ 2985 /* .pd_adv_local_get = */ NULL, /* Deprecated */ 2986 /* .pd_adv_remote_get = */ NULL, /* Deprecated */ 2987 /* .pd_lb_set = */ phy_82109_lb_set, 2988 /* .pd_lb_get = */ phy82109_lb_get, 2989 /* .pd_interface_set = */ phy82109_interface_set, 2990 /* .pd_interface_get = */ phy82109_interface_get, 2991 /* .pd_ability = */ NULL, /* Deprecated */ 2992 /* .pd_linkup_evt = */ NULL, 2993 /* .pd_linkdn_evt = */ NULL, 2994 /* .pd_mdix_set = */ phy_null_mdix_set, 2995 /* .pd_mdix_get = */ phy_null_mdix_get, 2996 /* .pd_mdix_status_get = */ phy_null_mdix_status_get, 2997 /* .pd_medium_config_set = */ NULL, 2998 /* .pd_medium_config_get = */ NULL, 2999 /* .pd_medium_get = */ phy_null_medium_get, 3000 /* .pd_cable_diag = */ NULL, 3001 /* .pd_link_change = */ NULL, 3002 /* .pd_control_set = */ phy_82109_control_set, 3003 /* .pd_control_get = */ phy_82109_control_get, 3004 /* .pd_reg_read = */ phy82109_reg_read, 3005 /* .pd_reg_write = */ phy82109_reg_write, 3006 /* .pd_reg_modify = */ phy82109_reg_modify, 3007 /* .pd_notify = */ NULL, 3008 /* .pd_probe = */ phy82109_probe, 3009 /* .pd_ability_advert_set = */ phy_82109_ability_advert_set, 3010 /* .pd_ability_advert_get = */ phy_82109_ability_advert_get, 3011 /* .pd_ability_remote_get = */ phy_82109_ability_remote_get, 3012 /* .pd_ability_local_get = */ phy_82109_ability_local_get, 3013 /* .pd_firmware_set = */ phy_82109_firmware_set, 3014 /* .pd_timesync_config_set = */ NULL, 3015 /* .pd_timesync_config_get = */ NULL, 3016 /* .pd_timesync_control_set = */ NULL, 3017 /* .pd_timesync_control_set = */ NULL, 3018 /* .pd_diag_ctrl = */ phy_82109_diag_ctrl, 3019 /* .pd_lane_control_set = */ phy_82109_per_lane_control_set, 3020 /* .pd_lane_control_get = */ phy_82109_per_lane_control_get 3021 }; 3022 3023 #else 3024 int _phy82109_not_empty; 3025 3026 #endif /* INCLUDE_PHY_82109 */ 3027