openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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