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

phy54880.c (101669B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:        phy54880.c
      8  * Purpose:     PHY driver for BCM54880
      9  */
     10 #include <sal/types.h>
     11 #include <sal/core/spl.h>
     12 #include <shared/bsl.h>
     13 #include <soc/drv.h>
     14 #include <soc/debug.h>
     15 #include <soc/error.h>
     16 #include <soc/phyreg.h>
     17 
     18 #include <soc/phy.h>
     19 #include <soc/phy/phyctrl.h>
     20 #include <soc/phy/drv.h>
     21 
     22 #include "phydefs.h"      /* Must include before other phy related includes */
     23 
     24 #if defined(INCLUDE_PHY_54880)
     25 #include "phyconfig.h"    /* Must be the first phy include after phydefs.h */
     26 
     27 #include "phyident.h"
     28 #include "phyreg.h"
     29 #include "phyfege.h"
     30 #include "phynull.h"
     31 #include "phy54880.h"
     32 
     33 #define PHY_IEEE_MODE(unit, port)   (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_BR))
     34                                   
     35 
     36 #define SOC_PORT_MEDIUM_IEEE        SOC_PORT_MEDIUM_COPPER
     37 #define SOC_PORT_MEDIUM_BR          SOC_PORT_MEDIUM_FIBER
     38 #define SOC_PA_MEDIUM_IEEE          SOC_PA_MEDIUM_COPPER
     39 
     40 #define PHY_IS_BCM54880_A0(_pc)   (PHY_MODEL_CHECK((_pc), \
     41                                                 PHY_BCM54880_OUI, \
     42                                                 PHY_BCM54880_MODEL) \
     43                                    && ((_pc)->phy_rev == 0x0 ))
     44 
     45 #define PHY_IS_BCM54880(_pc)   (PHY_MODEL_CHECK((_pc), \
     46                                                 PHY_BCM54880_OUI, \
     47                                                 PHY_BCM54880_MODEL))
     48 
     49 #define PHY_IS_BCM54881(_pc)   (PHY_MODEL_CHECK((_pc), \
     50                                                 PHY_BCM54881_OUI, \
     51                                                 PHY_BCM54881_MODEL))
     52 
     53 #define PHY_IS_BCM54811(_pc)   (PHY_MODEL_CHECK((_pc), \
     54                                                 PHY_BCM54811_OUI, \
     55                                                 PHY_BCM54811_MODEL) \
     56                                                 && ((_pc)->phy_rev == 0x5 ))
     57 
     58 
     59 #define PHY_IS_B0(_pc)   ((PHY_IS_BCM54880(_pc) || PHY_IS_BCM54881(_pc)) \
     60                                    && ((_pc)->phy_rev == 0x1))
     61 
     62 #define PHY_BCM54880_A0_ID0    PHY_ID0(PHY_BCM54880_OUI,PHY_BCM54880_MODEL,0)
     63 #define PHY_BCM54880_A0_ID1    PHY_ID1(PHY_BCM54880_OUI,PHY_BCM54880_MODEL,0)
     64 
     65 #ifndef DISABLE_CLK125
     66 #define DISABLE_CLK125 0
     67 #endif
     68 
     69 #ifndef AUTO_MDIX_WHEN_AN_DIS
     70 #define AUTO_MDIX_WHEN_AN_DIS 0
     71 #endif
     72 
     73 #define DISABLE_TEST_PORT 1
     74 /* #define A0_AUTO_FILL_PORT_INDEX 1 */
     75 
     76 #define LONGREACH_ABILITY_54880 ( SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR |\
     77                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR |\
     78                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR |\
     79                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR |\
     80                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR |\
     81                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX |\
     82                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX )
     83 
     84 #define LONGREACH_ABILITY_54881 ( SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR |\
     85                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR |\
     86                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_1PAIR |\
     87                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_2PAIR |\
     88                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_1PAIR |\
     89                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_2PAIR |\
     90                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_1PAIR |\
     91                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_2PAIR |\
     92                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_1PAIR |\
     93                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_2PAIR |\
     94                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR |\
     95                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR |\
     96                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR |\
     97                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX |\
     98                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX )
     99 
    100 #define LONGREACH_ABILITY_54811 ( SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR |\
    101                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR |\
    102                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR |\
    103                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR |\
    104                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR |\
    105                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX |\
    106                                   SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX )
    107 
    108 
    109 #define LONGREACH_ABILITY_ALL(_pc) ( PHY_IS_BCM54881((_pc)) ? LONGREACH_ABILITY_54881 : \
    110                                      ( PHY_IS_BCM54811((_pc)) ? LONGREACH_ABILITY_54811 : \
    111                                        LONGREACH_ABILITY_54880)) 
    112 
    113 #define LDS_ADVA_MASK(_pc)   ( PHY_IS_BCM54881((_pc)) ?  \
    114                                LDS_ADVA_ASYM_PAUSE|LDS_ADVA_PAUSE|\
    115                                LDS_ADVA_2_50|LDS_ADVA_2_33|LDS_ADVA_2_25|LDS_ADVA_2_20|\
    116                                LDS_ADVA_1_50|LDS_ADVA_1_33|LDS_ADVA_1_25|LDS_ADVA_1_20|\
    117                                LDS_ADVA_1_100|LDS_ADVA_4_100|LDS_ADVA_2_100|LDS_ADVA_2_10|LDS_ADVA_1_10 :\
    118                                LDS_ADVA_ASYM_PAUSE|LDS_ADVA_PAUSE|\
    119                                LDS_ADVA_1_100|LDS_ADVA_4_100|LDS_ADVA_2_100|LDS_ADVA_2_10|LDS_ADVA_1_10 )
    120 
    121           
    122 
    123 #define LONGREACH_ABILITY_10M  ( SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR | \
    124                                  SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR )
    125 #define LONGREACH_ABILITY_20M  ( SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_1PAIR | \
    126                                  SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_2PAIR )
    127 #define LONGREACH_ABILITY_25M  ( SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_1PAIR | \
    128                                  SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_2PAIR )
    129 #define LONGREACH_ABILITY_33M  ( SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_1PAIR | \
    130                                  SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_2PAIR )
    131 #define LONGREACH_ABILITY_50M  ( SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_1PAIR | \
    132                                  SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_2PAIR )
    133 #define LONGREACH_ABILITY_100M ( SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR | \
    134                                  SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR | \
    135                                  SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR )
    136 
    137 typedef struct _phy_br_config_t {
    138     int                 enable;
    139     int                 lds_enable;
    140     uint32              lds_advert_ability;
    141     int                 force_speed;
    142     int                 force_pairs;
    143     int                 master;
    144     int                 gain;
    145     int                 bypass_reset;
    146 } phy_br_config_t;
    147 
    148 #define SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR(op)                      \
    149     do {                                                                \
    150         int __rv__;                                                     \
    151         if (((__rv__ = (op)) < 0)) {                                    \
    152             if ((__rv__ == SOC_E_DISABLED)) {                           \
    153                __rv__ = SOC_E_NONE;                                     \
    154             }                                                           \
    155             return(__rv__);                                             \
    156         }                                                               \
    157     } while(0)
    158 
    159 STATIC int
    160 _phy_54880_ieee_speed_set(int unit, soc_port_t port, int speed);
    161 STATIC int
    162 _phy_54880_ieee_duplex_set(int unit, soc_port_t port, int duplex);
    163 STATIC int
    164 _phy_54880_ieee_master_set(int unit, soc_port_t port, int master);
    165 STATIC int
    166 _phy_54880_ieee_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability);
    167 STATIC int
    168 _phy_54880_ieee_autoneg_set(int unit, soc_port_t port, int autoneg);
    169 STATIC int
    170 _phy_54880_ieee_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode);
    171 STATIC int
    172 _phy_54880_ieee_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability);
    173 STATIC int
    174 _phy_54880_medium_change(int unit, soc_port_t port, int force_update);
    175 
    176 STATIC int
    177 _phy_54880_br_speed_set(int unit, soc_port_t port, int speed);
    178 STATIC int
    179 _phy_54880_br_pairs_set(int unit, soc_port_t port, int pairs);
    180 STATIC int
    181 _phy_54880_br_master_set(int unit, soc_port_t port, int master);
    182 STATIC int
    183 _phy_54880_br_ability_advert_set(int unit, soc_port_t port, uint32 ability);
    184 STATIC int
    185 _phy_54880_br_autoneg_set(int unit, soc_port_t port, int autoneg);
    186 STATIC int
    187 _phy_54880_br_gain_set(int unit, soc_port_t port, int gain);
    188 
    189 STATIC int
    190 phy_54880_control_set(int unit, soc_port_t port,
    191                      soc_phy_control_t type, uint32 value);
    192 
    193 extern int
    194 phy_ecd_cable_diag_init(int unit, soc_port_t port);
    195 
    196 extern int
    197 phy_ecd_cable_diag(int unit, soc_port_t port,
    198             soc_port_cable_diag_t *status);
    199 
    200 extern int
    201 phy_acd_cable_diag_init(int unit, soc_port_t port);
    202 
    203 extern int
    204 phy_acd_cable_diag(int unit, soc_port_t port,
    205             soc_port_cable_diag_t *status);
    206 
    207 STATIC int
    208 _SW2IEEE(int unit,phy_ctrl_t *pc) 
    209 {
    210     uint16              lds_acc;
    211     /* BCM54811 */
    212     if (PHY_IS_BCM54811(pc)) {
    213         SOC_IF_ERROR_RETURN
    214             (MODIFY_PHY54811_EXP_BR_LDS_CHAN_STATUSr(unit, pc, 
    215                              (PHY54811_LDS_BR_IEEE_REG_ACCESS_OVERRIDE_EN
    216                               | PHY54811_LDS_BR_IEEE_REG_ACCESS_OVERRIDE_VAL), 
    217                              (PHY54811_LDS_BR_IEEE_REG_ACCESS_OVERRIDE_EN
    218                               | PHY54811_LDS_BR_IEEE_REG_ACCESS_OVERRIDE_VAL)));
    219         SOC_IF_ERROR_RETURN
    220             (READ_PHY54811_EXP_BR_LDS_CHAN_STATUSr(unit, pc, &lds_acc));
    221         if(lds_acc & PHY54811_LDS_BR_IEEE_REG_ACCESS_CTRL_STATUS) {
    222             return SOC_E_DISABLED;
    223         } 
    224         return 0;
    225     }
    226 
    227 
    228     SOC_IF_ERROR_RETURN
    229         (WRITE_PHY54880_LDS_ACCr(unit, pc, 0x6));
    230 
    231     SOC_IF_ERROR_RETURN
    232         (READ_PHY54880_LDS_ACCr((unit), (pc), &lds_acc));
    233     if (lds_acc & LDS_ACC_STAT) {
    234         return SOC_E_DISABLED;
    235     }
    236     return 0;
    237 }
    238 
    239 STATIC int
    240 _SW2BR(int unit,phy_ctrl_t *pc) 
    241 {
    242     uint16              lds_acc;    
    243     phy_br_config_t    *br_config;
    244 
    245     /* BCM54811 */
    246     if (PHY_IS_BCM54811(pc)) {
    247         SOC_IF_ERROR_RETURN
    248             (MODIFY_PHY54811_EXP_BR_LDS_CHAN_STATUSr(unit, pc, 
    249                              PHY54811_LDS_BR_IEEE_REG_ACCESS_OVERRIDE_EN,
    250                               (PHY54811_LDS_BR_IEEE_REG_ACCESS_OVERRIDE_EN
    251                               | PHY54811_LDS_BR_IEEE_REG_ACCESS_OVERRIDE_VAL)));
    252         SOC_IF_ERROR_RETURN
    253             (READ_PHY54811_EXP_BR_LDS_CHAN_STATUSr(unit, pc, &lds_acc));
    254         if( 0 == (lds_acc & PHY54811_LDS_BR_IEEE_REG_ACCESS_CTRL_STATUS)) {
    255             return SOC_E_DISABLED;
    256         } 
    257         return 0;
    258     }
    259 
    260     br_config     = (phy_br_config_t *)  &pc->fiber;
    261     if (br_config->enable && !br_config->lds_enable) {
    262         return 0;
    263     }
    264 
    265     SOC_IF_ERROR_RETURN
    266         (WRITE_PHY54880_LDS_ACCr(unit, pc, 0x4));
    267 
    268     SOC_IF_ERROR_RETURN
    269         (READ_PHY54880_LDS_ACCr((unit), (pc), &lds_acc));
    270     if ((lds_acc & LDS_ACC_STAT) == 0) {
    271         return SOC_E_DISABLED;
    272     }
    273     return 0;
    274 }
    275 
    276 /*
    277  * Function:
    278  *      phy_54880_medium_status
    279  * Purpose:
    280  *      Indicate the current active medium
    281  * Parameters:
    282  *      unit - StrataSwitch unit #.
    283  *      port - StrataSwitch port #.
    284  *      medium - (OUT) One of:
    285  *              SOC_PORT_MEDIUM_COPPER
    286  *              SOC_PORT_MEDIUM_FIBER
    287  * Returns:
    288  *      SOC_E_NONE.
    289  */
    290 STATIC int
    291 phy_54880_medium_status(int unit, soc_port_t port, soc_port_medium_t *medium)
    292 {
    293     *medium = SOC_PORT_MEDIUM_IEEE;
    294 
    295     return SOC_E_NONE;
    296 }
    297 
    298 /*
    299  * Function:
    300  *      _phy_54880_ieee_medium_config_update
    301  * Purpose:
    302  *      Update the operating parameters that are automatically selected
    303  *      when medium switches type.
    304  * Parameters:
    305  *      unit - StrataSwitch unit #
    306  *      port - Port number
    307  *      cfg - Operating parameters
    308  * Returns:
    309  *      SOC_E_XXX
    310  */
    311 STATIC int
    312 _phy_54880_ieee_medium_config_update(int unit, soc_port_t port, 
    313                            soc_phy_config_t  *cfg)
    314 {
    315     SOC_IF_ERROR_RETURN
    316         (_phy_54880_ieee_speed_set(unit, port, cfg->force_speed));
    317     SOC_IF_ERROR_RETURN
    318         (_phy_54880_ieee_duplex_set(unit, port, cfg->force_duplex));
    319     SOC_IF_ERROR_RETURN
    320         (_phy_54880_ieee_master_set(unit, port, cfg->master));
    321     SOC_IF_ERROR_RETURN
    322         (_phy_54880_ieee_ability_advert_set(unit, port, &cfg->advert_ability));
    323     SOC_IF_ERROR_RETURN
    324         (_phy_54880_ieee_autoneg_set(unit, port, cfg->autoneg_enable));
    325     SOC_IF_ERROR_RETURN
    326         (_phy_54880_ieee_mdix_set(unit, port, cfg->mdix));
    327 
    328     return SOC_E_NONE;
    329 }
    330 
    331 STATIC int
    332 _phy_54880_br_medium_config_update(int unit, soc_port_t port, 
    333                            phy_br_config_t  *cfg)
    334 {
    335     /* Notice the order. Speed, pairs and master could be written to the regs
    336        only if LDS is disabled. 
    337      */
    338 
    339     SOC_IF_ERROR_RETURN
    340         (_phy_54880_br_ability_advert_set(unit, port, cfg->lds_advert_ability));
    341     SOC_IF_ERROR_RETURN
    342         (_phy_54880_br_autoneg_set(unit, port, cfg->lds_enable));
    343 
    344     if ( !cfg->lds_enable ) {
    345         SOC_IF_ERROR_RETURN
    346             (_phy_54880_br_speed_set(unit, port, cfg->force_speed));
    347         SOC_IF_ERROR_RETURN
    348             (_phy_54880_br_pairs_set(unit, port, cfg->force_pairs));
    349         SOC_IF_ERROR_RETURN
    350             (_phy_54880_br_master_set(unit, port, cfg->master));
    351         SOC_IF_ERROR_RETURN
    352             (_phy_54880_br_gain_set(unit, port, cfg->gain));
    353     }
    354 
    355     return SOC_E_NONE;
    356 }
    357 
    358 STATIC int
    359 phy_54880_medium_config_set(int unit, soc_port_t port,
    360                            soc_port_medium_t  medium,
    361                            soc_phy_config_t  *cfg)
    362 {
    363     phy_ctrl_t        *pc;
    364     soc_port_ability_t ability;
    365 
    366     pc = EXT_PHY_SW_STATE(unit, port);
    367 
    368     /*
    369      * Changes take effect immediately if the target medium is active.
    370      */
    371     if (medium == SOC_PORT_MEDIUM_COPPER) {
    372 
    373         sal_memcpy(&pc->copper, cfg, sizeof (pc->copper));
    374 
    375         SOC_IF_ERROR_RETURN
    376             (_phy_54880_ieee_ability_local_get(unit, port, &ability));
    377 
    378         pc->copper.advert_ability.speed_half_duplex &= ability.speed_half_duplex;
    379         pc->copper.advert_ability.speed_full_duplex &= ability.speed_full_duplex;
    380         pc->copper.advert_ability.pause &= ability.pause;
    381 
    382         if (PHY_IEEE_MODE(unit, port)) {
    383             SOC_IF_ERROR_RETURN
    384                 (_phy_54880_ieee_medium_config_update(unit, port, &pc->copper));
    385         }
    386         return SOC_E_NONE;
    387     }
    388 
    389     return SOC_E_CONFIG;
    390 }
    391 
    392 
    393 /*
    394  * Function:
    395  *      phy_54880_medium_config_get
    396  * Purpose:
    397  *      Get the operating parameters that are automatically selected
    398  *      when medium switches type.
    399  * Parameters:
    400  *      unit - StrataSwitch unit #
    401  *      port - Port number
    402  *      medium - SOC_PORT_MEDIUM_COPPER/FIBER
    403  *      cfg - (OUT) Operating parameters
    404  * Returns:
    405  *      SOC_E_XXX
    406  */
    407 
    408 STATIC int
    409 phy_54880_medium_config_get(int unit, soc_port_t port, 
    410                            soc_port_medium_t medium,
    411                            soc_phy_config_t *cfg)
    412 {
    413     phy_ctrl_t    *pc;
    414 
    415     COMPILER_REFERENCE(medium);
    416 
    417     pc = EXT_PHY_SW_STATE(unit, port);
    418 
    419     sal_memcpy(cfg, &pc->copper, sizeof (*cfg));
    420 
    421     return SOC_E_NONE;
    422 }
    423 
    424 /*
    425  * Function:
    426  *      _phy_54880_reset_setup
    427  * Purpose:
    428  *      Function to reset the PHY and set up initial operating registers.
    429  * Parameters:
    430  *      unit - StrataSwitch unit #.
    431  *      port - StrataSwitch port #.
    432  * Returns:
    433  *      SOC_E_XXX
    434  */
    435 
    436 STATIC int
    437 _phy_54880_reset_setup(int unit, soc_port_t port)
    438 {
    439     phy_ctrl_t        *pc;
    440     uint16             tmp;
    441     uint16             phy_addr;
    442     uint16             id0, id1;
    443     int                index;
    444 
    445     pc     = EXT_PHY_SW_STATE(unit, port);
    446 
    447     SOC_IF_ERROR_RETURN(phy_ge_init(unit, port));
    448 
    449     phy_addr = pc->phy_id;
    450     index = phy_addr & 7;
    451 
    452     /* set the default values that are valid for many boards */
    453     SOC_IF_ERROR_RETURN
    454         (phy_54880_control_set( unit, port, SOC_PHY_CONTROL_PORT_PRIMARY, 
    455         (port - index) < 0 ? 0:(port - index)));
    456     SOC_IF_ERROR_RETURN
    457         (phy_54880_control_set( unit, port, SOC_PHY_CONTROL_PORT_OFFSET, index ));
    458 
    459 #ifdef DISABLE_TEST_PORT
    460     if (PHY_IS_BCM54880_A0(pc))  {
    461         /* Disable test port */
    462 
    463         phy_addr = pc->phy_id + 1;
    464 
    465         SOC_IF_ERROR_RETURN
    466             (pc->read(unit, phy_addr, MII_PHY_ID0_REG, &id0));
    467 
    468         SOC_IF_ERROR_RETURN
    469             (pc->read(unit, phy_addr, MII_PHY_ID1_REG, &id1));
    470 
    471         if ( ( id0 != PHY_BCM54880_A0_ID0 ) || ( id1 != PHY_BCM54880_A0_ID1 ) ) {
    472 
    473             SOC_IF_ERROR_RETURN
    474                 (pc->write(unit, phy_addr, 0x1f, 0xffd0));
    475 
    476             SOC_IF_ERROR_RETURN
    477                 (pc->write(unit, phy_addr, 0x1e, 0x001f));
    478 
    479             SOC_IF_ERROR_RETURN
    480                 (pc->write(unit, phy_addr, 0x1f, 0x8000));
    481 
    482             SOC_IF_ERROR_RETURN
    483                 (pc->write(unit, phy_addr, 0x1d, 0x4002));
    484 
    485             SOC_IF_ERROR_RETURN
    486                 (pc->write(unit, phy_addr, 0x00, MII_CTRL_RESET));
    487 
    488 #ifdef A0_AUTO_FILL_PORT_INDEX
    489             {
    490                 int i;
    491 
    492                 for (i = 0; i < 8; i++) {
    493                     SOC_IF_ERROR_RETURN
    494                         (phy_54880_control_set(unit, port - i, SOC_PHY_CONTROL_PORT_PRIMARY, port - 7));
    495                     SOC_IF_ERROR_RETURN
    496                         (phy_54880_control_set(unit, port - i, SOC_PHY_CONTROL_PORT_OFFSET, 7 - i ));
    497                 }
    498             }
    499 #endif
    500         }
    501     }
    502 #endif
    503 
    504     /* remove power down */
    505     if (pc->copper.enable) {
    506         tmp = PHY_DISABLED_MODE(unit, port) ? MII_CTRL_PD : 0;
    507     } else {
    508         tmp = MII_CTRL_PD;
    509     }
    510     SOC_IF_ERROR_RETURN
    511         (MODIFY_PHY54880_MII_CTRLr(unit, pc, tmp, MII_CTRL_PD));
    512 
    513 #if DISABLE_CLK125
    514     /* Reduce EMI emissions by disabling the CLK125 pin if not used */
    515     SOC_IF_ERROR_RETURN
    516         (MODIFY_PHY54880_SPARE_CTRL_3r(unit, pc, 0, 1));
    517 #endif
    518 
    519     /* Configure Extended Control Register */
    520     /* Enable LEDs to indicate traffic status */
    521     SOC_IF_ERROR_RETURN
    522         (MODIFY_PHY54880_MII_ECRr(unit, pc, 0x0020, 0x0020));
    523 
    524 #if AUTO_MDIX_WHEN_AN_DIS
    525     /* Enable Auto-MDIX When autoneg disabled */
    526     SOC_IF_ERROR_RETURN
    527         (MODIFY_PHY54880_MII_MISC_CTRLr(unit, pc, 0x0200, 0x0200));
    528 #endif
    529 
    530     /* Enable extended packet length (4.5k through 25k) */
    531     SOC_IF_ERROR_RETURN
    532         (MODIFY_PHY54880_MII_AUX_CTRLr(unit, pc, 0x4000, 0x4000));
    533 
    534     SOC_IF_ERROR_RETURN
    535         (MODIFY_PHY54880_MISC_1000X_CTRL2r(unit, pc, 0x0001, 0x0001));
    536 
    537     SOC_IF_ERROR_RETURN
    538         (MODIFY_PHY54880_AUX_CTRLr(unit, pc, 0x0002, 0x0002));
    539 
    540     /* Configure LED selectors */
    541     tmp = ((pc->ledmode[1] & 0xf) << 4) | (pc->ledmode[0] & 0xf);
    542     SOC_IF_ERROR_RETURN
    543         (WRITE_PHY54880_LED_SELECTOR_1r(unit, pc, tmp));
    544 
    545     tmp = ((pc->ledmode[3] & 0xf) << 4) | (pc->ledmode[2] & 0xf);
    546     SOC_IF_ERROR_RETURN
    547         (WRITE_PHY54880_LED_SELECTOR_2r(unit, pc, tmp));
    548 
    549     tmp = (pc->ledctrl & 0x3ff);
    550     SOC_IF_ERROR_RETURN
    551         (WRITE_PHY54880_LED_CTRLr(unit, pc, tmp));
    552 
    553     SOC_IF_ERROR_RETURN
    554         (WRITE_PHY54880_EXP_LED_SELECTORr(unit, pc, pc->ledselect));
    555 
    556     /* LDS parameters */
    557 
    558     SOC_IF_ERROR_RETURN
    559         (WRITE_PHY54880_EXP_BR_LDS_RX_CTRL1r(unit, pc, 0x0e1b));
    560 
    561     SOC_IF_ERROR_RETURN
    562         (WRITE_PHY54880_EXP_BR_LDS_RX_CTRL2r(unit, pc, 0x0306));
    563 
    564     /*
    565      * Configure Auxiliary control register to turn off
    566      * carrier extension.  The Intel 7131 NIC does not accept carrier
    567      * extension and gets CRC errors.
    568      */
    569     /* Disable carrier extension */
    570     SOC_IF_ERROR_RETURN
    571         (MODIFY_PHY54880_AUX_CTRLr(unit, pc, 0x0040, 0x0040));
    572 
    573     if (PHY_IS_B0(pc)) {
    574         /* B0 errata */
    575         SOC_IF_ERROR_RETURN
    576             (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL2r(unit, pc, 1U<<3, 1U<<3));
    577     }
    578 
    579     if ((PHY_IS_BCM54880(pc)) && ((pc->phy_rev & 0xf) > 0x1))  {
    580         SOC_IF_ERROR_RETURN(
    581             phy_ecd_cable_diag_init(unit, port));
    582     }
    583 
    584     return SOC_E_NONE;
    585 
    586 }
    587 
    588 /*
    589  * Function:  
    590  *      _phy_54811_reset_setup
    591  * Purpose:
    592  *      Function to reset the PHY and set up initial operating registers.
    593  * Parameters:
    594  *      unit - StrataSwitch unit #.
    595  *      port - StrataSwitch port #.
    596  * Returns:
    597  *      SOC_E_XXX
    598  */
    599 
    600 STATIC int
    601 _phy_54811_reset_setup(int unit, soc_port_t port)
    602 {
    603     phy_ctrl_t        *pc;
    604     uint16             tmp;
    605     uint16             phy_addr;
    606     int                index;
    607 
    608     SOC_IF_ERROR_RETURN(phy_ge_init(unit, port));
    609 
    610     pc     = EXT_PHY_SW_STATE(unit, port);
    611 
    612     phy_addr = pc->phy_id;
    613     index = phy_addr & 7;
    614 
    615     /* set the default values that are valid for many boards */
    616     SOC_IF_ERROR_RETURN
    617         (phy_54880_control_set( unit, port, SOC_PHY_CONTROL_PORT_PRIMARY, 
    618         (port - index) < 0 ? 0:(port - index)));
    619     SOC_IF_ERROR_RETURN
    620         (phy_54880_control_set( unit, port, SOC_PHY_CONTROL_PORT_OFFSET, index ));
    621 
    622     /* remove power down */
    623     if (pc->copper.enable) {
    624         tmp = PHY_DISABLED_MODE(unit, port) ? MII_CTRL_PD : 0;
    625     } else {
    626         tmp = MII_CTRL_PD;
    627     }
    628     SOC_IF_ERROR_RETURN
    629         (MODIFY_PHY54880_MII_CTRLr(unit, pc, tmp, MII_CTRL_PD));
    630 
    631     /* Configure Extended Control Register */
    632     /* Enable LEDs to indicate traffic status */
    633     SOC_IF_ERROR_RETURN
    634         (MODIFY_PHY54880_MII_ECRr(unit, pc, 0x0020, 0x0020));
    635 
    636 #if AUTO_MDIX_WHEN_AN_DIS
    637     /* Enable Auto-MDIX When autoneg disabled */
    638     SOC_IF_ERROR_RETURN
    639         (MODIFY_PHY54880_MII_MISC_CTRLr(unit, pc, 0x0200, 0x0200));
    640 #endif
    641 
    642     /* Enable extended packet length (4.5k through 25k) */
    643     SOC_IF_ERROR_RETURN
    644         (MODIFY_PHY54880_MII_AUX_CTRLr(unit, pc, 0x4000, 0x4000));
    645 
    646 #if 0 
    647 
    648     SOC_IF_ERROR_RETURN
    649         (MODIFY_PHY54880_MISC_1000X_CTRL2r(unit, pc, 0x0001, 0x0001));
    650 
    651     SOC_IF_ERROR_RETURN
    652         (MODIFY_PHY54880_AUX_CTRLr(unit, pc, 0x0002, 0x0002));
    653 #endif
    654 
    655     /* Configure LED selectors */
    656     tmp = ((pc->ledmode[1] & 0xf) << 4) | (pc->ledmode[0] & 0xf);
    657     SOC_IF_ERROR_RETURN
    658         (WRITE_PHY54880_LED_SELECTOR_1r(unit, pc, tmp));
    659 
    660     tmp = ((pc->ledmode[3] & 0xf) << 4) | (pc->ledmode[2] & 0xf);
    661     SOC_IF_ERROR_RETURN
    662         (WRITE_PHY54880_LED_SELECTOR_2r(unit, pc, tmp));
    663 
    664     tmp = (pc->ledctrl & 0x3ff);
    665     SOC_IF_ERROR_RETURN
    666         (WRITE_PHY54880_LED_CTRLr(unit, pc, tmp));
    667 
    668     SOC_IF_ERROR_RETURN
    669         (WRITE_PHY54880_EXP_LED_SELECTORr(unit, pc, pc->ledselect));
    670 
    671 #if 0 
    672 
    673     /* LDS parameters */
    674 
    675     SOC_IF_ERROR_RETURN
    676         (WRITE_PHY54880_EXP_BR_LDS_RX_CTRL1r(unit, pc, 0x0e1b));
    677 
    678     SOC_IF_ERROR_RETURN
    679         (WRITE_PHY54880_EXP_BR_LDS_RX_CTRL2r(unit, pc, 0x0306));
    680 
    681     /*
    682      * Configure Auxiliary control register to turn off
    683      * carrier extension.  The Intel 7131 NIC does not accept carrier
    684      * extension and gets CRC errors.
    685      */
    686     /* Disable carrier extension */
    687     SOC_IF_ERROR_RETURN
    688         (MODIFY_PHY54880_AUX_CTRLr(unit, pc, 0x0040, 0x0040));
    689 
    690     if (PHY_IS_B0(pc)) {
    691         /* B0 errata */
    692         SOC_IF_ERROR_RETURN
    693             (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL2r(unit, pc, 1U<<3, 1U<<3));
    694     }
    695 
    696 #endif
    697 
    698     return SOC_E_NONE;
    699 
    700 }
    701 
    702 
    703 /*
    704  * Function:
    705  *      phy_54880_init
    706  * Purpose:
    707  *      Init function for 54880 PHY.
    708  * Parameters:
    709  *      unit - StrataSwitch unit #.
    710  *      port - StrataSwitch port #.
    711  * Returns:
    712  *      SOC_E_XXX
    713  */
    714 STATIC int
    715 phy_54880_init(int unit, soc_port_t port)
    716 {
    717     phy_ctrl_t         *pc;
    718     soc_phy_config_t   *copper_config;
    719     phy_br_config_t    *br_config;
    720     int                lr_initial_mode;
    721     int                lr_initial_ctrl;
    722     int                lr_initial_adva;
    723 
    724     pc    = EXT_PHY_SW_STATE(unit, port);
    725 
    726     copper_config = (soc_phy_config_t *) &pc->copper;
    727     br_config     = (phy_br_config_t *)  &pc->fiber;
    728 
    729     pc->automedium = FALSE;
    730 
    731     copper_config->enable = TRUE;
    732     copper_config->autoneg_enable = TRUE;
    733     if (PHY_IS_BCM54881(pc)) {
    734         copper_config->force_speed = 100;
    735     } else {
    736         copper_config->force_speed = 1000;
    737     }
    738     copper_config->force_duplex = TRUE;
    739     copper_config->master = SOC_PORT_MS_AUTO;
    740     copper_config->mdix = SOC_PORT_MDIX_AUTO;
    741 
    742     br_config->bypass_reset = 0;
    743 
    744     /* Initial Setting for BR mode */
    745     lr_initial_mode = 
    746         soc_property_port_get(unit, port, spn_PHY_LR_INITIAL_MODE, -1);
    747     lr_initial_ctrl = 
    748         soc_property_port_get(unit, port, spn_PHY_LR_INITIAL_CTRL, -1);
    749     lr_initial_adva = 
    750         soc_property_port_get(unit, port, spn_PHY_LR_INITIAL_ADVA, -1);
    751 
    752     /* Initial BR mode settings */
    753     if (lr_initial_mode != -1) {
    754         br_config->enable = 
    755             (lr_initial_mode & LR_INITIAL_MODE_LR_ENABLE) ? TRUE : FALSE; 
    756     } else {
    757         br_config->enable = FALSE;
    758     }
    759 
    760     /* Initial BR ctrl settings */
    761     if (lr_initial_ctrl != -1) {
    762         br_config->lds_enable = 
    763             (lr_initial_ctrl & LR_INITIAL_CTRL_LDS_ENABLE) ? TRUE : FALSE;
    764 
    765         if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_PS_MASK) == 
    766             LR_INITIAL_CTRL_LR_PS_1P) {
    767             br_config->force_pairs = 1;
    768         } else if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_PS_MASK) == 
    769                     LR_INITIAL_CTRL_LR_PS_2P) {
    770             br_config->force_pairs = 2;
    771         } else if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_PS_MASK) == 
    772                     LR_INITIAL_CTRL_LR_PS_4P) {
    773             br_config->force_pairs = 4;
    774         } else {
    775             br_config->force_pairs = 0;
    776         }
    777 
    778         br_config->master = 
    779             (lr_initial_ctrl & LR_INITIAL_CTRL_LR_MS) ? 
    780                         SOC_PORT_MS_MASTER : SOC_PORT_MS_SLAVE;
    781 
    782         if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_SS_MASK) == 
    783             LR_INITIAL_CTRL_LR_SS_10) {
    784             br_config->force_speed = 10;
    785         } else if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_SS_MASK) == 
    786                     LR_INITIAL_CTRL_LR_SS_20) {
    787             br_config->force_speed = 20;
    788         } else if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_SS_MASK) == 
    789                     LR_INITIAL_CTRL_LR_SS_25) {
    790             br_config->force_speed = 25;
    791         } else if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_SS_MASK) == 
    792                     LR_INITIAL_CTRL_LR_SS_33) {
    793             br_config->force_speed = 33;
    794         } else if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_SS_MASK) == 
    795                     LR_INITIAL_CTRL_LR_SS_50) {
    796             br_config->force_speed = 50;
    797         } else if ((lr_initial_ctrl & LR_INITIAL_CTRL_LR_SS_MASK) == 
    798                     LR_INITIAL_CTRL_LR_SS_100) {
    799             br_config->force_speed = 100;
    800         } else {
    801             br_config->force_speed = 100;
    802         }
    803             
    804     } else {
    805         br_config->lds_enable = TRUE;
    806         br_config->force_pairs = 0;
    807         br_config->master = SOC_PORT_MS_AUTO;
    808         br_config->force_speed = 100;
    809     }
    810 
    811     /* Initial advert ability, valid only if LDS is enabled */
    812     if (lr_initial_adva != -1) {
    813         br_config->lds_advert_ability = 0;
    814         if(lr_initial_adva & LR_INITIAL_ADVA_1_10) {
    815             br_config->lds_advert_ability |= 
    816                 SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR;
    817         }
    818         if(lr_initial_adva & LR_INITIAL_ADVA_2_10) {
    819             br_config->lds_advert_ability |= 
    820                 SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR;
    821         }
    822         if(lr_initial_adva & LR_INITIAL_ADVA_1_20) {
    823             br_config->lds_advert_ability |= 
    824                 SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_1PAIR;
    825         }
    826         if(lr_initial_adva & LR_INITIAL_ADVA_2_20) {
    827             br_config->lds_advert_ability |= 
    828                 SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_2PAIR;
    829         }
    830         if(lr_initial_adva & LR_INITIAL_ADVA_1_33) {
    831             br_config->lds_advert_ability |= 
    832                 SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_1PAIR;
    833         }
    834         if(lr_initial_adva & LR_INITIAL_ADVA_2_33) {
    835             br_config->lds_advert_ability |= 
    836                 SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_2PAIR;
    837         }
    838         if(lr_initial_adva & LR_INITIAL_ADVA_1_50) {
    839             br_config->lds_advert_ability |= 
    840                 SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_1PAIR;
    841         }
    842         if(lr_initial_adva & LR_INITIAL_ADVA_2_50) {
    843             br_config->lds_advert_ability |= 
    844                 SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_2PAIR;
    845         }
    846         if(lr_initial_adva & LR_INITIAL_ADVA_1_100) {
    847             br_config->lds_advert_ability |= 
    848                 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR;
    849         }
    850         if(lr_initial_adva & LR_INITIAL_ADVA_2_100) {
    851             br_config->lds_advert_ability |= 
    852                 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR;
    853         }
    854         if(lr_initial_adva & LR_INITIAL_ADVA_4_100) {
    855             br_config->lds_advert_ability |= 
    856                 SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR;
    857         }
    858         if(lr_initial_adva & LR_INITIAL_ADVA_PAUSE_RX) {
    859             br_config->lds_advert_ability |= 
    860                 SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX;
    861         }
    862         if(lr_initial_adva & LR_INITIAL_ADVA_PAUSE_TX) {
    863             br_config->lds_advert_ability |= 
    864                 SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX;
    865         }
    866     } else {
    867         br_config->lds_advert_ability = LONGREACH_ABILITY_ALL(pc);    
    868     }
    869 
    870     br_config->gain = 2;
    871 
    872     /* Initially configure for the preferred medium. */
    873 
    874     PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER);
    875     if (br_config->enable) {
    876         PHY_FLAGS_SET(unit, port, PHY_FLAGS_BR);
    877     } else {
    878         PHY_FLAGS_CLR(unit, port, PHY_FLAGS_BR);
    879     }
    880 
    881     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_PASSTHRU);
    882 
    883     /* Get Requested LED selectors (defaults are hardware defaults) */
    884     pc->ledmode[0] = soc_property_port_get(unit, port, spn_PHY_LED1_MODE, 0);
    885     pc->ledmode[1] = soc_property_port_get(unit, port, spn_PHY_LED2_MODE, 1);
    886     pc->ledmode[2] = soc_property_port_get(unit, port, spn_PHY_LED3_MODE, 3);
    887     pc->ledmode[3] = soc_property_port_get(unit, port, spn_PHY_LED4_MODE, 6);
    888     pc->ledctrl    = soc_property_port_get(unit, port, spn_PHY_LED_CTRL, 0x8);
    889     pc->ledselect  = soc_property_port_get(unit, port, spn_PHY_LED_SELECT, 0);
    890 
    891     /* Get half amplitude setting */
    892     /* pc->halfout = soc_property_port_get(unit, port, spn_PHY_HALF_POWER, 0); */
    893    
    894     if( PHY_IS_BCM54811(pc)) {
    895         SOC_IF_ERROR_RETURN
    896             (_phy_54811_reset_setup(unit, port));
    897         /* Disable BR by default */
    898         SOC_IF_ERROR_RETURN
    899             (MODIFY_PHY54811_EXP_BR_LRE_MISC_CTRLr(unit, pc, 0x0, 0x1));
    900     } else { 
    901         if (!br_config->bypass_reset) {
    902             SOC_IF_ERROR_RETURN
    903                 (_phy_54880_reset_setup(unit, port));
    904         }
    905 
    906         if (br_config->enable) {
    907             SOC_IF_ERROR_RETURN
    908                 (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL1r(unit, pc, 0x1, 0x1));
    909         } else {
    910             /* Disable BR by default */
    911             SOC_IF_ERROR_RETURN
    912                 (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL1r(unit, pc, 0x0, 0x1));
    913         }
    914     }
    915     if (PHY_IS_BCM54881(pc)) {
    916         /* Enabling half duplex in 54881 */
    917         SOC_IF_ERROR_RETURN
    918             (MODIFY_PHY54880_MII_MISC_CTRLr(unit, pc, 1U<<7, 1U<<7));
    919     }
    920 
    921     /* Advertise all possible by default */
    922     SOC_IF_ERROR_RETURN
    923         (_phy_54880_ieee_ability_local_get(unit, port, &pc->copper.advert_ability));
    924 
    925     if (br_config->enable) {
    926         SOC_IF_ERROR_RETURN
    927             (_phy_54880_br_medium_config_update(unit, port, br_config));
    928     } else {
    929         SOC_IF_ERROR_RETURN
    930             (_phy_54880_ieee_medium_config_update(unit, port, &pc->copper)); 
    931     }
    932 
    933     return SOC_E_NONE;
    934 
    935 }
    936 
    937 /*
    938  * Function:
    939  *      phy_54880_enable_set
    940  * Purpose:
    941  *      Enable or disable the physical interface.
    942  * Parameters:
    943  *      unit - StrataSwitch unit #.
    944  *      port - StrataSwitch port #.
    945  *      enable - Boolean, true = enable PHY, false = disable.
    946  * Returns:
    947  *      SOC_E_XXX
    948  */
    949 
    950 STATIC int
    951 phy_54880_enable_set(int unit, soc_port_t port, int enable)
    952 {
    953     phy_ctrl_t    *pc;
    954     uint16 power_down;
    955 
    956     pc = EXT_PHY_SW_STATE(unit, port);
    957 
    958     power_down = (enable) ? 0 : MII_CTRL_PD;
    959 
    960     if (pc->copper.enable) {
    961         SOC_IF_ERROR_RETURN
    962             (MODIFY_PHY54880_MII_CTRLr(unit, pc, power_down, MII_CTRL_PD));
    963     }
    964 
    965     SOC_IF_ERROR_RETURN
    966         (phy_fe_ge_enable_set(unit, port, enable));
    967 
    968     return SOC_E_NONE;
    969 
    970 }
    971 
    972 /*
    973  * Function:
    974  *      phy_54880_enable_get
    975  * Purpose:
    976  *      Enable or disable the physical interface for a 54880 device.
    977  * Parameters:
    978  *      unit - StrataSwitch unit #.
    979  *      port - StrataSwitch port #.
    980  *      enable - (OUT) Boolean, true = enable PHY, false = disable.
    981  * Returns:
    982  *      SOC_E_XXX
    983  */
    984 
    985 STATIC int
    986 phy_54880_enable_get(int unit, soc_port_t port, int *enable)
    987 {
    988     SOC_IF_ERROR_RETURN
    989         (phy_fe_ge_enable_get(unit, port, enable));
    990 
    991     return SOC_E_NONE;
    992 }
    993 
    994 STATIC int
    995 _phy_54880_medium_check(int unit, soc_port_t port, int *medium)
    996 {
    997     phy_ctrl_t   *pc;
    998     uint16    status;
    999     phy_br_config_t    *br_config;
   1000 
   1001     pc = EXT_PHY_SW_STATE(unit, port);
   1002 
   1003     br_config     = (phy_br_config_t *)  &pc->fiber;
   1004 
   1005     /* Force to br mode first to avoid locking up in ieee */
   1006     SOC_IF_ERROR_RETURN
   1007         (WRITE_PHY54880_LDS_ACCr(unit, pc, 0x4));
   1008 
   1009     /* Force to auto mode */
   1010     SOC_IF_ERROR_RETURN
   1011         (WRITE_PHY54880_LDS_ACCr(unit, pc, 0x0));
   1012 
   1013     SOC_IF_ERROR_RETURN
   1014         (READ_PHY54880_LDS_ACCr(unit, pc, &status));
   1015 
   1016     if ( status & LDS_ACC_STAT ) {
   1017         *medium = SOC_PORT_MEDIUM_BR;
   1018     } else {
   1019         if (br_config->enable && !br_config->lds_enable) {
   1020             *medium = SOC_PORT_MEDIUM_BR;
   1021         } else {
   1022             *medium = SOC_PORT_MEDIUM_IEEE;
   1023         }
   1024     }
   1025     return SOC_E_NONE;
   1026 }
   1027 
   1028 
   1029 STATIC int
   1030 _phy_54880_medium_change(int unit, soc_port_t port, int force_update)
   1031 {
   1032     phy_ctrl_t       *pc;
   1033     int               medium;
   1034     soc_phy_config_t *copper_config;
   1035     phy_br_config_t  *br_config;
   1036 
   1037     pc    = EXT_PHY_SW_STATE(unit, port);
   1038 
   1039     copper_config = (soc_phy_config_t *) &pc->copper;
   1040     br_config     = (phy_br_config_t *)  &pc->fiber;
   1041 
   1042     SOC_IF_ERROR_RETURN
   1043         (_phy_54880_medium_check(unit, port, &medium));
   1044 
   1045     if (medium == SOC_PORT_MEDIUM_IEEE) {
   1046         if ((!PHY_IEEE_MODE(unit, port)) || force_update) { /* Was BR */
   1047             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_BR);
   1048             PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE);
   1049 
   1050             /* Do not power up the interface if medium is disabled. */
   1051             if (copper_config->enable) {
   1052                 SOC_IF_ERROR_RETURN
   1053                     (_phy_54880_ieee_medium_config_update(unit, port,copper_config));
   1054             }
   1055             LOG_INFO(BSL_LS_SOC_PHY,
   1056                      (BSL_META_U(unit,
   1057                                  "_phy_54880_link_auto_detect: u=%d p=%d [F->X]\n"),
   1058                       unit, port));
   1059         } else {
   1060             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_MEDIUM_CHANGE);
   1061         }
   1062     } else {
   1063         if (PHY_IEEE_MODE(unit, port) || force_update) { /* Was IEEE */
   1064             PHY_FLAGS_SET(unit, port, PHY_FLAGS_BR);
   1065             PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE);
   1066 
   1067             if (br_config->enable) {
   1068                 SOC_IF_ERROR_RETURN
   1069                     (_phy_54880_br_medium_config_update(unit, port,br_config));
   1070             }
   1071             LOG_INFO(BSL_LS_SOC_PHY,
   1072                      (BSL_META_U(unit,
   1073                                  "_phy_54880_link_auto_detect: u=%d p=%d [C->X]\n"),
   1074                       unit, port));
   1075         } else {
   1076             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_MEDIUM_CHANGE);
   1077         }
   1078     }
   1079 
   1080     return SOC_E_NONE;
   1081 }
   1082 
   1083 int
   1084 _phy_54880_br_link_get(int unit, soc_port_t port, int *link)
   1085 {
   1086     uint16              lre_ctrl, lre_stat;
   1087     soc_timeout_t       to;
   1088     phy_ctrl_t          *pc;
   1089 
   1090     *link = FALSE;              /* Default */
   1091 
   1092     if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) {
   1093         return SOC_E_NONE;
   1094     }
   1095 
   1096     pc = EXT_PHY_SW_STATE(unit, port);
   1097 
   1098     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1099         (_SW2BR(unit, pc));
   1100 
   1101     SOC_IF_ERROR_RETURN
   1102         (READ_PHY54880_LRE_STATr(unit, pc, &lre_stat));
   1103 
   1104     if (!(lre_stat & LRE_STAT_LA)) {
   1105         return SOC_E_NONE;
   1106     }
   1107 
   1108     /* Link appears to be up; we are done if autoneg is off. */
   1109 
   1110     SOC_IF_ERROR_RETURN
   1111         (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl));
   1112 
   1113     if (!(lre_ctrl & LRE_CTRL_LDSE)) {
   1114         *link = TRUE;
   1115         return SOC_E_NONE;
   1116     }
   1117 
   1118     soc_timeout_init(&to, SOC_PHY_INFO(unit, port).an_timeout, 0);
   1119     for (;;) {
   1120         SOC_IF_ERROR_RETURN
   1121             (READ_PHY54880_LRE_STATr(unit, pc, &lre_stat));
   1122 
   1123         if (!(lre_stat & LRE_STAT_LA)) {
   1124             return SOC_E_NONE;
   1125         }
   1126 
   1127         if (lre_stat & LRE_STAT_LDS_DONE) {
   1128             break;
   1129         }
   1130 
   1131         if (soc_timeout_check(&to)) {
   1132             return SOC_E_BUSY;
   1133         }
   1134     }
   1135 
   1136     /* Return link state at end of polling */
   1137 
   1138     *link = ((lre_stat & LRE_STAT_LA) != 0);
   1139 
   1140     return SOC_E_NONE;
   1141 }
   1142 
   1143 
   1144 /*
   1145  * Function:
   1146  *      phy_54880_link_get
   1147  * Purpose:
   1148  *      Determine the current link up/down status for a 54880 device.
   1149  * Parameters:
   1150  *      unit - StrataSwitch unit #.
   1151  *      port - StrataSwitch port #.
   1152  *      link - (OUT) Boolean, true indicates link established.
   1153  * Returns:
   1154  *      SOC_E_XXX
   1155  * Notes:
   1156  *      If using automedium, also switches the mode.
   1157  */
   1158 
   1159 STATIC int
   1160 phy_54880_link_get(int unit, soc_port_t port, int *link)
   1161 {
   1162 
   1163     phy_ctrl_t *pc;
   1164 
   1165     pc = EXT_PHY_SW_STATE(unit, port);
   1166 
   1167     if (link == NULL) {
   1168         return SOC_E_NONE;
   1169     }
   1170 
   1171     if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) {
   1172         *link = FALSE;
   1173         return SOC_E_NONE;
   1174     }
   1175 
   1176     SOC_IF_ERROR_RETURN
   1177         (_phy_54880_medium_change(unit, port,FALSE));
   1178 
   1179     if (PHY_IEEE_MODE(unit, port)) {
   1180         SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1181             (_SW2IEEE(unit, pc));
   1182         SOC_IF_ERROR_RETURN
   1183             (phy_fe_ge_link_get(unit, port, link));
   1184     } else {
   1185         SOC_IF_ERROR_RETURN
   1186             (_phy_54880_br_link_get(unit, port, link));
   1187     }
   1188 
   1189     return SOC_E_NONE;
   1190 
   1191 }
   1192 
   1193 /*
   1194  * Function:
   1195  *      phy_54880_duplex_set
   1196  * Purpose:
   1197  *      Set the current duplex mode (forced).
   1198  * Parameters:
   1199  *      unit - StrataSwitch unit #.
   1200  *      port - StrataSwitch port #.
   1201  *      duplex - Boolean, true indicates full duplex, false indicates half.
   1202  * Returns:
   1203  *      SOC_E_XXX
   1204  *      SOC_E_UNAVAIL - Half duplex requested, and not supported.
   1205  * Notes:
   1206  *      The duplex is set only for the ACTIVE medium.
   1207  *      No synchronization performed at this level.
   1208  *      Autonegotiation is not manipulated.
   1209  */
   1210 
   1211 STATIC int
   1212 _phy_54880_ieee_duplex_set(int unit, soc_port_t port, int duplex)
   1213 {
   1214     phy_ctrl_t    *pc;
   1215 
   1216     pc = EXT_PHY_SW_STATE(unit, port);
   1217 
   1218     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1219         (_SW2IEEE(unit, pc));
   1220 
   1221     SOC_IF_ERROR_RETURN
   1222         (phy_fe_ge_duplex_set(unit, port, duplex));
   1223     pc->copper.force_duplex = duplex;
   1224 
   1225     return SOC_E_NONE;
   1226 }
   1227 
   1228 STATIC int
   1229 phy_54880_duplex_set(int unit, soc_port_t port, int duplex)
   1230 {
   1231     phy_ctrl_t    *pc;
   1232 
   1233     pc = EXT_PHY_SW_STATE(unit, port);
   1234 
   1235     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1236         (_SW2IEEE(unit, pc));
   1237 
   1238     if (PHY_IEEE_MODE(unit, port)) {
   1239         SOC_IF_ERROR_RETURN
   1240             (_phy_54880_ieee_duplex_set(unit, port, duplex));
   1241     } else {
   1242         if ( !duplex ) {
   1243             return SOC_E_CONFIG;
   1244         }
   1245     }
   1246 
   1247     return SOC_E_NONE;
   1248 }
   1249 
   1250 /*
   1251  * Function:
   1252  *      phy_54880_duplex_get
   1253  * Purpose:
   1254  *      Get the current operating duplex mode. If autoneg is enabled,
   1255  *      then operating mode is returned, otherwise forced mode is returned.
   1256  * Parameters:
   1257  *      unit - StrataSwitch unit #.
   1258  *      port - StrataSwitch port #.
   1259  *      duplex - (OUT) Boolean, true indicates full duplex, false
   1260  *              indicates half.
   1261  * Returns:
   1262  *      SOC_E_XXX
   1263  * Notes:
   1264  *      The duplex is retrieved for the ACTIVE medium.
   1265  *      No synchronization performed at this level. Autonegotiation is
   1266  *      not manipulated.
   1267  */
   1268 
   1269 STATIC int
   1270 phy_54880_duplex_get(int unit, soc_port_t port, int *duplex)
   1271 {
   1272     phy_ctrl_t    *pc;
   1273 
   1274     pc = EXT_PHY_SW_STATE(unit, port);
   1275 
   1276     if (PHY_IEEE_MODE(unit, port)) {
   1277 
   1278         SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1279             (_SW2IEEE(unit, pc));
   1280 
   1281         SOC_IF_ERROR_RETURN
   1282             (phy_fe_ge_duplex_get(unit, port, duplex));
   1283     } else {
   1284         *duplex = TRUE;
   1285     }
   1286 
   1287     return SOC_E_NONE;
   1288 }
   1289 
   1290 int
   1291 _phy_54880_br_speed_set(int unit, soc_port_t port, int speed)
   1292 {
   1293     uint16      lre_ctrl;
   1294     phy_ctrl_t  *pc;
   1295 
   1296     if (speed == 0) {
   1297         return SOC_E_NONE;
   1298     }
   1299 
   1300     pc = EXT_PHY_SW_STATE(unit, port);
   1301 
   1302     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1303         (_SW2BR(unit, pc));
   1304 
   1305     SOC_IF_ERROR_RETURN
   1306         (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl));
   1307 
   1308     lre_ctrl &= ~LRE_CTRL_SS_MASK;
   1309     switch(speed) {
   1310     case 10:
   1311         lre_ctrl |= LRE_CTRL_SS_10;
   1312         break;
   1313     case 20:
   1314         lre_ctrl |= LRE_CTRL_SS_20;
   1315         break;
   1316     case 25:
   1317         lre_ctrl |= LRE_CTRL_SS_25;
   1318         break;
   1319     case 33:
   1320         lre_ctrl |= LRE_CTRL_SS_33;
   1321         break;
   1322     case 50:
   1323         lre_ctrl |= LRE_CTRL_SS_50;
   1324         break;
   1325     case 100:
   1326         lre_ctrl |= LRE_CTRL_SS_100;
   1327         break;
   1328     default:
   1329         return(SOC_E_CONFIG);
   1330     }
   1331 
   1332     SOC_IF_ERROR_RETURN
   1333         (WRITE_PHY54880_LRE_CTRLr(unit, pc, lre_ctrl));
   1334 
   1335     return(SOC_E_NONE);
   1336 }
   1337 
   1338 
   1339 /*
   1340  * Function:
   1341  *      phy_54880_ieee_speed_set
   1342  * Purpose:
   1343  *      Set the current operating speed (forced).
   1344  * Parameters:
   1345  *      unit - StrataSwitch unit #.
   1346  *      port - StrataSwitch port #.
   1347  *      speed - Requested speed.
   1348  * Returns:
   1349  *      SOC_E_XXX
   1350  * Notes:
   1351  *      The speed is set only for the IEEE mode.
   1352  */
   1353 
   1354 STATIC int
   1355 _phy_54880_ieee_speed_set(int unit, soc_port_t port, int speed)
   1356 {
   1357     phy_ctrl_t    *pc;
   1358 
   1359     pc = EXT_PHY_SW_STATE(unit, port);
   1360 
   1361     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1362         (_SW2IEEE(unit, pc));
   1363 
   1364     SOC_IF_ERROR_RETURN
   1365         (phy_fe_ge_speed_set(unit, port, speed));
   1366 
   1367     return SOC_E_NONE;
   1368 }
   1369 
   1370 STATIC int
   1371 phy_54880_speed_set(int unit, soc_port_t port, int speed)
   1372 {
   1373     phy_ctrl_t  *pc;
   1374     phy_br_config_t    *br_config;
   1375 
   1376     pc = EXT_PHY_SW_STATE(unit, port);
   1377     br_config     = (phy_br_config_t *)  &pc->fiber;
   1378 
   1379     if (PHY_IEEE_MODE(unit, port)) {
   1380         SOC_IF_ERROR_RETURN
   1381             (_phy_54880_ieee_speed_set(unit, port, speed));
   1382     } else {
   1383         SOC_IF_ERROR_RETURN
   1384             (_phy_54880_br_speed_set(unit, port, speed));
   1385         if (br_config->force_pairs == 0) {
   1386             SOC_IF_ERROR_RETURN
   1387                 (_phy_54880_br_pairs_set(unit, port, (speed==100) ? 4 : 2));
   1388         }
   1389     }
   1390 
   1391     return SOC_E_NONE;
   1392 }
   1393 
   1394 
   1395 
   1396 int
   1397 _phy_54880_br_speed_get(int unit, soc_port_t port, int *speed)
   1398 {
   1399     int         rv;
   1400     uint16      lre_ctrl, lre_stat, br_lds_scan;
   1401     phy_ctrl_t  *pc;
   1402 
   1403     pc = EXT_PHY_SW_STATE(unit, port);
   1404 
   1405     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1406         (_SW2BR(unit, pc));
   1407 
   1408     SOC_IF_ERROR_RETURN
   1409         (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl));
   1410 
   1411     if (lre_ctrl & LRE_CTRL_LDSE) {       /* LDS enabled */
   1412         SOC_IF_ERROR_RETURN
   1413             (READ_PHY54880_LRE_STATr(unit, pc, &lre_stat));
   1414         if (!(lre_stat & LRE_STAT_LDS_DONE)) { /* LDS NOT complete */
   1415             *speed = 0;
   1416             rv = SOC_E_NONE;
   1417         } else {
   1418         /* Examine the BR EXP regs */
   1419             SOC_IF_ERROR_RETURN
   1420                 (READ_PHY54880_EXP_BR_LDS_SCANr(unit, pc, &br_lds_scan));
   1421 
   1422             switch(br_lds_scan & PHY54880_EXP_BR_LDS_SCAN_SS_MASK) {
   1423 
   1424             case PHY54880_EXP_BR_LDS_SCAN_SS_10:
   1425                 *speed = 10;
   1426                 break;
   1427             case PHY54880_EXP_BR_LDS_SCAN_SS_20:
   1428                 *speed = 20;
   1429                 break;
   1430             case PHY54880_EXP_BR_LDS_SCAN_SS_25:
   1431                 *speed = 25;
   1432                 break;
   1433             case PHY54880_EXP_BR_LDS_SCAN_SS_33:
   1434                 *speed = 33;
   1435                 break;
   1436             case PHY54880_EXP_BR_LDS_SCAN_SS_50:
   1437                 *speed = 50;
   1438                 break;
   1439             case PHY54880_EXP_BR_LDS_SCAN_SS_100:
   1440                 *speed = 100;
   1441                 break;
   1442             default:
   1443                 *speed = 0;
   1444                 break;
   1445             }
   1446             rv = SOC_E_NONE;
   1447         }
   1448     } else {                            /* LDS disabled */
   1449         /*
   1450          * Simply pick up the values we force in CTRL register.
   1451          */
   1452         switch(lre_ctrl & LRE_CTRL_SS_MASK) {
   1453 
   1454         case LRE_CTRL_SS_10:
   1455             *speed = 10;
   1456             break;
   1457         case LRE_CTRL_SS_20:
   1458             *speed = 20;
   1459             break;
   1460         case LRE_CTRL_SS_25:
   1461             *speed = 25;
   1462             break;
   1463         case LRE_CTRL_SS_33:
   1464             *speed = 33;
   1465             break;
   1466         case LRE_CTRL_SS_50:
   1467             *speed = 50;
   1468             break;
   1469         case LRE_CTRL_SS_100:
   1470             *speed = 100;
   1471             break;
   1472         default:
   1473             *speed = 0;
   1474             break;
   1475         }
   1476         rv = SOC_E_NONE;
   1477     }
   1478 
   1479     return(rv);
   1480 }
   1481 
   1482 /*
   1483  * Function:
   1484  *      phy_54880_speed_get
   1485  * Purpose:
   1486  *      Get the current operating speed for a 54880 device.
   1487  * Parameters:
   1488  *      unit - StrataSwitch unit #.
   1489  *      port - StrataSwitch port #.
   1490  *      duplex - (OUT) Boolean, true indicates full duplex, false
   1491  *              indicates half.
   1492  * Returns:
   1493  *      SOC_E_XXX
   1494  * Notes:
   1495  *      The speed is retrieved for the ACTIVE medium.
   1496  */
   1497 
   1498 STATIC int
   1499 phy_54880_speed_get(int unit, soc_port_t port, int *speed)
   1500 {
   1501     phy_ctrl_t    *pc;
   1502 
   1503     pc = EXT_PHY_SW_STATE(unit, port);
   1504 
   1505     if (PHY_IEEE_MODE(unit, port)) {
   1506 
   1507         SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1508             (_SW2IEEE(unit, pc));
   1509 
   1510         SOC_IF_ERROR_RETURN(phy_fe_ge_speed_get(unit, port, speed));
   1511     } else {
   1512         SOC_IF_ERROR_RETURN(_phy_54880_br_speed_get(unit, port, speed));
   1513     }
   1514 
   1515     return SOC_E_NONE;
   1516 }
   1517 
   1518 STATIC int
   1519 _phy_54880_br_pairs_set(int unit, soc_port_t port, int pairs)
   1520 {
   1521     uint16      lre_ctrl;
   1522     phy_ctrl_t  *pc;
   1523 
   1524     pc = EXT_PHY_SW_STATE(unit, port);
   1525     
   1526     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1527         (_SW2BR(unit, pc));
   1528 
   1529     SOC_IF_ERROR_RETURN
   1530         (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl));
   1531 
   1532     lre_ctrl &= ~LRE_CTRL_PS_MASK;
   1533     switch(pairs) {
   1534     case 1:
   1535         lre_ctrl |= LRE_CTRL_PS_1P;
   1536         break;
   1537     case 2:
   1538         lre_ctrl |= LRE_CTRL_PS_2P;
   1539         break;
   1540     case 4:
   1541         lre_ctrl |= LRE_CTRL_PS_4P;
   1542         break;
   1543     default:
   1544         return(SOC_E_CONFIG);
   1545     }
   1546 
   1547     SOC_IF_ERROR_RETURN
   1548         (WRITE_PHY54880_LRE_CTRLr(unit, pc, lre_ctrl));
   1549 
   1550     return(SOC_E_NONE);
   1551 }
   1552 
   1553 STATIC int
   1554 _phy_54880_br_pairs_get(int unit, soc_port_t port, int *pairs)
   1555 {
   1556     int         rv;
   1557     uint16      lre_ctrl, lre_stat, lds_exp;
   1558     phy_ctrl_t  *pc;
   1559 
   1560     pc = EXT_PHY_SW_STATE(unit, port);
   1561 
   1562     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1563         (_SW2BR(unit, pc));
   1564 
   1565     SOC_IF_ERROR_RETURN
   1566         (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl));
   1567     SOC_IF_ERROR_RETURN
   1568         (READ_PHY54880_LRE_STATr(unit, pc, &lre_stat));
   1569 
   1570     if (lre_ctrl & LRE_CTRL_LDSE) {       /* LDS enabled */
   1571         if (!(lre_stat & LRE_STAT_LDS_DONE)) { /* LDS NOT complete */
   1572             *pairs = 0;
   1573             rv = SOC_E_NONE;
   1574         } else {
   1575         /* Examine the LDS EXP reg (0xa) */
   1576             SOC_IF_ERROR_RETURN
   1577                 (READ_PHY54880_LDS_EXPr(unit, pc, &lds_exp));
   1578 
   1579             switch(lds_exp & (0x3U<<12)) {
   1580             case 0x0:
   1581                 *pairs = 1;
   1582                 break;
   1583             case (0x1<<12):
   1584                 *pairs = 2;
   1585                 break;
   1586             case (0x2<<12):
   1587                 *pairs = 4;
   1588                 break;
   1589             default:
   1590                 *pairs = 0;
   1591                 break;
   1592             }
   1593             rv = SOC_E_NONE;
   1594         }
   1595     } else {                            /* LDS disabled */
   1596 
   1597         switch(lre_ctrl & LRE_CTRL_PS_MASK) {
   1598         case LRE_CTRL_PS_1P:
   1599             *pairs = 1;
   1600             break;
   1601         case LRE_CTRL_PS_2P:
   1602             *pairs = 2;
   1603             break;
   1604         case LRE_CTRL_PS_4P:
   1605             *pairs = 4;
   1606             break;
   1607         default:
   1608             *pairs = 0;
   1609             break;
   1610         }
   1611         rv = SOC_E_NONE;
   1612     }
   1613 
   1614     return(rv);
   1615 }
   1616 
   1617 STATIC int
   1618 _phy_54880_br_enable_set(int unit, soc_port_t port, int enable)
   1619 {
   1620     phy_ctrl_t    *pc;
   1621 
   1622     pc = EXT_PHY_SW_STATE(unit, port);
   1623 
   1624     if( PHY_IS_BCM54811(pc) ) {
   1625         SOC_IF_ERROR_RETURN
   1626             (MODIFY_PHY54811_EXP_BR_LRE_MISC_CTRLr(unit, pc, (enable) ? (1U<<0):0, (1U<<0)));
   1627     } else {
   1628         SOC_IF_ERROR_RETURN
   1629             (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL1r(unit, pc, (enable) ? (1U<<0):0, (1U<<0)));
   1630     }
   1631 
   1632     return SOC_E_NONE;
   1633 
   1634 }
   1635 
   1636 STATIC int
   1637 _phy_54880_br_enable_get(int unit, soc_port_t port, int *enable)
   1638 {
   1639     phy_ctrl_t    *pc;
   1640     uint16 lre_misc_ctrl;
   1641 
   1642     pc = EXT_PHY_SW_STATE(unit, port);
   1643 
   1644     if( PHY_IS_BCM54811(pc)) {
   1645         SOC_IF_ERROR_RETURN
   1646             (READ_PHY54811_EXP_BR_LRE_MISC_CTRLr(unit, pc, &lre_misc_ctrl));
   1647     } else {
   1648         SOC_IF_ERROR_RETURN
   1649             (READ_PHY54880_EXP_BR_LRE_MISC_CTRL1r(unit, pc, &lre_misc_ctrl));
   1650     }
   1651 
   1652     *enable = (lre_misc_ctrl & (1U<<0)) ? TRUE: FALSE;
   1653 
   1654     return SOC_E_NONE;
   1655 }
   1656 
   1657 STATIC int
   1658 _phy_54880_br_active_get(int unit, soc_port_t port, int *active)
   1659 {
   1660     *active = (PHY_IEEE_MODE(unit, port)) ? FALSE: TRUE;
   1661 
   1662     return SOC_E_NONE;
   1663 }
   1664 
   1665 STATIC int
   1666 _phy_54880_br_gain_set(int unit, soc_port_t port, int gain)
   1667 {
   1668     phy_ctrl_t  *pc;
   1669 
   1670     pc = EXT_PHY_SW_STATE(unit, port);
   1671 
   1672     switch(gain) {
   1673     case 0:
   1674     case 1:
   1675     case 2:
   1676     case 4:
   1677         if( PHY_IS_BCM54811(pc) ) {
   1678             SOC_IF_ERROR_RETURN
   1679                 (MODIFY_PHY54811_EXP_BR_LRE_MISC_CTRL2r(unit, pc, (gain&0x7)<<9, 0x7<<9));
   1680         } else {
   1681             SOC_IF_ERROR_RETURN
   1682                 (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL2r(unit, pc, (gain&0x7)<<9, 0x7<<9));
   1683         }
   1684         break;
   1685     default:
   1686         return(SOC_E_CONFIG);
   1687     }
   1688 
   1689     return(SOC_E_NONE);
   1690 }
   1691 
   1692 STATIC int
   1693 _phy_54880_br_gain_get(int unit, soc_port_t port, int *gain)
   1694 {
   1695     phy_ctrl_t  *pc;
   1696     uint16 temp;
   1697 
   1698     pc = EXT_PHY_SW_STATE(unit, port);
   1699 
   1700     if( PHY_IS_BCM54811(pc) ) {
   1701         SOC_IF_ERROR_RETURN
   1702             (READ_PHY54811_EXP_BR_LRE_MISC_CTRL2r(unit, pc, &temp));
   1703     } else {
   1704         SOC_IF_ERROR_RETURN
   1705             (READ_PHY54880_EXP_BR_LRE_MISC_CTRL2r(unit, pc, &temp));
   1706     }
   1707 
   1708     *gain = (temp>>9) & 0x7;
   1709 
   1710     return(SOC_E_NONE);
   1711 }
   1712 
   1713 
   1714 /*
   1715  * Function:
   1716  *      phy_54880_master_set
   1717  * Purpose:
   1718  *      Set the current master mode
   1719  * Parameters:
   1720  *      unit - StrataSwitch unit #.
   1721  *      port - StrataSwitch port #.
   1722  *      master - SOC_PORT_MS_*
   1723  * Returns:
   1724  *      SOC_E_XXX
   1725  * Notes:
   1726  *      The master mode is set only for the ACTIVE medium.
   1727  */
   1728 STATIC int
   1729 _phy_54880_br_master_set(int unit, soc_port_t port, int master)
   1730 {
   1731     uint16      lre_ctrl;
   1732     phy_ctrl_t  *pc;
   1733 
   1734     pc = EXT_PHY_SW_STATE(unit, port);
   1735 
   1736     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1737         (_SW2BR(unit, pc));
   1738 
   1739     SOC_IF_ERROR_RETURN
   1740         (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl));
   1741 
   1742     switch (master) {
   1743     case SOC_PORT_MS_SLAVE:
   1744         lre_ctrl &= ~LRE_CTRL_MS;
   1745         break;
   1746     case SOC_PORT_MS_MASTER:
   1747         lre_ctrl |= LRE_CTRL_MS;
   1748         break;
   1749     case SOC_PORT_MS_AUTO:
   1750         return(SOC_E_NONE);
   1751     default:
   1752         return(SOC_E_CONFIG);
   1753     }
   1754 
   1755     SOC_IF_ERROR_RETURN
   1756         (WRITE_PHY54880_LRE_CTRLr(unit, pc, lre_ctrl));
   1757 
   1758     return(SOC_E_NONE);
   1759 }
   1760 
   1761 
   1762 STATIC int
   1763 _phy_54880_ieee_master_set(int unit, soc_port_t port, int master)
   1764 {
   1765     phy_ctrl_t    *pc;
   1766 
   1767     pc = EXT_PHY_SW_STATE(unit, port);
   1768 
   1769     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1770         (_SW2IEEE(unit, pc));
   1771 
   1772     SOC_IF_ERROR_RETURN
   1773         (phy_fe_ge_master_set(unit, port, master));
   1774 
   1775     pc->copper.master = master;
   1776 
   1777     return SOC_E_NONE;
   1778 }
   1779 
   1780 STATIC int
   1781 phy_54880_master_set(int unit, soc_port_t port, int master)
   1782 {
   1783     if (PHY_IEEE_MODE(unit, port)) {
   1784         SOC_IF_ERROR_RETURN
   1785             (_phy_54880_ieee_master_set(unit, port, master));
   1786     } else {
   1787         SOC_IF_ERROR_RETURN
   1788             (_phy_54880_br_master_set(unit, port, master));
   1789     }
   1790 
   1791     return SOC_E_NONE;
   1792 }
   1793 
   1794 
   1795 /*
   1796  * Function:
   1797  *      phy_54880_master_get
   1798  * Purpose:
   1799  *      Get the current master mode for a 54880 device.
   1800  * Parameters:
   1801  *      unit - StrataSwitch unit #.
   1802  *      port - StrataSwitch port #.
   1803  *      master - (OUT) SOC_PORT_MS_*
   1804  * Returns:
   1805  *      SOC_E_XXX
   1806  * Notes:
   1807  *      The master mode is retrieved for the ACTIVE medium.
   1808  */
   1809 STATIC int
   1810 _phy_54880_br_master_get(int unit, soc_port_t port, int *master)
   1811 {
   1812     uint16      lre_ctrl, lre_stat, lds_exp;
   1813     phy_ctrl_t  *pc;
   1814 
   1815     pc = EXT_PHY_SW_STATE(unit, port);
   1816 
   1817     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1818         (_SW2BR(unit, pc));
   1819 
   1820     SOC_IF_ERROR_RETURN
   1821         (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl));
   1822 
   1823     if (lre_ctrl & LRE_CTRL_LDSE) {
   1824         SOC_IF_ERROR_RETURN
   1825             (READ_PHY54880_LRE_STATr(unit, pc, &lre_stat));
   1826         if (!(lre_stat & LRE_STAT_LDS_DONE)) { /* LDS NOT complete */
   1827             *master = SOC_PORT_MS_NONE;
   1828         } else {
   1829             /* Examine the LDS EXP reg (0xa) */
   1830             SOC_IF_ERROR_RETURN
   1831                 (READ_PHY54880_LDS_EXPr(unit, pc, &lds_exp));
   1832             *master = (lds_exp & (1U<<14)) ? SOC_PORT_MS_MASTER : SOC_PORT_MS_SLAVE;
   1833         }
   1834     } else if (lre_ctrl & LRE_CTRL_MS) {
   1835         *master = SOC_PORT_MS_MASTER;
   1836     } else {
   1837         *master = SOC_PORT_MS_SLAVE;
   1838     }
   1839 
   1840     return SOC_E_NONE;
   1841 }
   1842 
   1843 STATIC int
   1844 phy_54880_master_get(int unit, soc_port_t port, int *master)
   1845 {
   1846     phy_ctrl_t    *pc;
   1847 
   1848     pc = EXT_PHY_SW_STATE(unit, port);
   1849 
   1850     if (PHY_IEEE_MODE(unit, port)) {
   1851 
   1852         SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1853             (_SW2IEEE(unit, pc));
   1854 
   1855         SOC_IF_ERROR_RETURN
   1856             (phy_fe_ge_master_get(unit, port, master));
   1857     } else {
   1858         SOC_IF_ERROR_RETURN
   1859             (_phy_54880_br_master_get(unit, port, master));
   1860     }
   1861 
   1862     return SOC_E_NONE;
   1863 }
   1864 
   1865 
   1866 STATIC int
   1867 _phy_54880_br_autoneg_set(int unit, soc_port_t port, int an)
   1868 {
   1869     phy_ctrl_t  *pc;
   1870 
   1871     pc = EXT_PHY_SW_STATE(unit, port);
   1872 
   1873     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1874         (_SW2BR(unit, pc));
   1875 
   1876     SOC_IF_ERROR_RETURN
   1877         (MODIFY_PHY54880_LRE_CTRLr(unit, pc,
   1878         an ? LRE_CTRL_LDSE|LRE_CTRL_RLDS : 0,
   1879         LRE_CTRL_LDSE|LRE_CTRL_RLDS));
   1880 
   1881     return SOC_E_NONE;
   1882 }
   1883 
   1884 /*
   1885  * Function:
   1886  *      phy_54880_autoneg_set
   1887  * Purpose:
   1888  *      Enable or disable auto-negotiation on the specified port.
   1889  * Parameters:
   1890  *      unit - StrataSwitch unit #.
   1891  *      port - StrataSwitch port #.
   1892  *      autoneg - Boolean, if true, auto-negotiation is enabled
   1893  *              (and/or restarted). If false, autonegotiation is disabled.
   1894  * Returns:
   1895  *      SOC_E_XXX
   1896  * Notes:
   1897  *      The autoneg mode is set only for the ACTIVE medium.
   1898  */
   1899 
   1900 STATIC int
   1901 _phy_54880_ieee_autoneg_set(int unit, soc_port_t port, int autoneg)
   1902 {
   1903     int           rv;
   1904     phy_ctrl_t    *pc;
   1905 
   1906     pc             = EXT_PHY_SW_STATE(unit, port);
   1907     rv             = SOC_E_NONE;
   1908 
   1909     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1910         (_SW2IEEE(unit, pc));
   1911 
   1912     /* Set auto-neg on PHY */
   1913     rv = phy_fe_ge_an_set(unit, port, autoneg);
   1914     if (SOC_SUCCESS(rv)) {
   1915         pc->copper.autoneg_enable = autoneg ? 1 : 0;
   1916     }
   1917 
   1918     return rv;
   1919 }
   1920 
   1921 STATIC int
   1922 phy_54880_autoneg_set(int unit, soc_port_t port, int autoneg)
   1923 {
   1924     int rv  = SOC_E_NONE;
   1925 
   1926     if (PHY_IEEE_MODE(unit, port)) {
   1927         SOC_IF_ERROR_RETURN
   1928             (_phy_54880_ieee_autoneg_set(unit, port, autoneg));
   1929     } else {
   1930         SOC_IF_ERROR_RETURN
   1931             (_phy_54880_br_autoneg_set(unit, port, autoneg));
   1932     }
   1933 
   1934     return rv;
   1935 }
   1936 
   1937 STATIC int
   1938 _phy_54880_br_autoneg_get(int unit, soc_port_t port, int *an, int *an_done)
   1939 {
   1940     phy_ctrl_t *pc;
   1941     uint16 lre_ctrl, lre_stat;
   1942 
   1943     pc = EXT_PHY_SW_STATE(unit, port);
   1944 
   1945     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1946         (_SW2BR(unit, pc));
   1947 
   1948     SOC_IF_ERROR_RETURN
   1949         (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl));
   1950     SOC_IF_ERROR_RETURN
   1951         (READ_PHY54880_LRE_STATr(unit, pc, &lre_stat));
   1952 
   1953     *an = (lre_ctrl & LRE_CTRL_LDSE) ? TRUE : FALSE;
   1954 
   1955     if ( an_done ) {
   1956         *an_done = (lre_stat & LRE_STAT_LDS_DONE) ? TRUE : FALSE;
   1957     }
   1958 
   1959     return SOC_E_NONE;
   1960 }
   1961 
   1962 /*
   1963  * Function:
   1964  *      phy_54880_autoneg_get
   1965  * Purpose:
   1966  *      Get the current auto-negotiation status (enabled/busy).
   1967  * Parameters:
   1968  *      unit - StrataSwitch unit #.
   1969  *      port - StrataSwitch port #.
   1970  *      autoneg - (OUT) if true, auto-negotiation is enabled.
   1971  *      autoneg_done - (OUT) if true, auto-negotiation is complete. This
   1972  *              value is undefined if autoneg == FALSE.
   1973  * Returns:
   1974  *      SOC_E_XXX
   1975  * Notes:
   1976  *      The autoneg mode is retrieved for the ACTIVE medium.
   1977  */
   1978 
   1979 STATIC int
   1980 phy_54880_autoneg_get(int unit, soc_port_t port,
   1981                      int *autoneg, int *autoneg_done)
   1982 {
   1983     phy_ctrl_t    *pc;
   1984 
   1985     pc = EXT_PHY_SW_STATE(unit, port);
   1986 
   1987     if (PHY_IEEE_MODE(unit, port)) {
   1988 
   1989         SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   1990             (_SW2IEEE(unit, pc));
   1991 
   1992         SOC_IF_ERROR_RETURN
   1993             (phy_fe_ge_an_get(unit, port, autoneg, autoneg_done));
   1994     } else {
   1995         SOC_IF_ERROR_RETURN
   1996             (_phy_54880_br_autoneg_get(unit, port, autoneg, autoneg_done));
   1997     }
   1998 
   1999     return SOC_E_NONE;
   2000 }
   2001 
   2002 /*
   2003  * Function:
   2004  *      phy_54880_ability_advert_set
   2005  * Purpose:
   2006  *      Set the current advertisement for auto-negotiation.
   2007  * Parameters:
   2008  *      unit    - StrataSwitch unit #.
   2009  *      port    - StrataSwitch port #.
   2010  *      ability - Port ability indicating supported options/speeds.
   2011  * Returns:
   2012  *      SOC_E_XXX
   2013  */
   2014 
   2015 STATIC int
   2016 _phy_54880_ieee_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability)
   2017 {
   2018     phy_ctrl_t      *pc;
   2019 
   2020     pc = EXT_PHY_SW_STATE(unit, port);
   2021 
   2022     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   2023         (_SW2IEEE(unit, pc));
   2024 
   2025     SOC_IF_ERROR_RETURN
   2026         (phy_fe_ge_ability_advert_set(unit, port, ability));
   2027 
   2028     return SOC_E_NONE;
   2029 }
   2030 
   2031 STATIC int
   2032 _phy_54880_br_ability_advert_set(int unit, soc_port_t port, uint32 ability)
   2033 {
   2034     phy_ctrl_t      *pc;
   2035     uint16       lds_adv;
   2036 
   2037     pc = EXT_PHY_SW_STATE(unit, port);
   2038 
   2039     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   2040         (_SW2BR(unit, pc));
   2041 
   2042     ability &= LONGREACH_ABILITY_ALL(pc);
   2043 
   2044     lds_adv = 0;
   2045 
   2046     if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR)  {
   2047         lds_adv |= LDS_ADVA_1_10;
   2048     }
   2049     if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR)  {
   2050         lds_adv |= LDS_ADVA_2_10;
   2051     }
   2052     if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_1PAIR)  {
   2053         lds_adv |= LDS_ADVA_1_20;
   2054     }
   2055     if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_2PAIR)  {
   2056         lds_adv |= LDS_ADVA_2_20;
   2057     }
   2058     if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_1PAIR)  {
   2059         lds_adv |= LDS_ADVA_1_25;
   2060     }
   2061     if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_2PAIR)  {
   2062         lds_adv |= LDS_ADVA_2_25;
   2063     }
   2064     if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_1PAIR)  {
   2065         lds_adv |= LDS_ADVA_1_33;
   2066     }
   2067     if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_2PAIR)  {
   2068         lds_adv |= LDS_ADVA_2_33;
   2069     }
   2070     if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_1PAIR)  {
   2071         lds_adv |= LDS_ADVA_1_50;
   2072     }
   2073     if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_2PAIR)  {
   2074         lds_adv |= LDS_ADVA_2_50;
   2075     }
   2076     if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR) {
   2077         lds_adv |= LDS_ADVA_1_100;
   2078     }
   2079     if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR) {
   2080         lds_adv |= LDS_ADVA_2_100;
   2081     }
   2082     if (ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR) {
   2083         lds_adv |= LDS_ADVA_4_100;
   2084     }
   2085 
   2086     switch (ability & (SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX | 
   2087                        SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX)) {
   2088 
   2089     case SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX:
   2090         lds_adv |= LDS_ADVA_ASYM_PAUSE;
   2091         break;
   2092     case SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX:
   2093         lds_adv |= LDS_ADVA_PAUSE | LDS_ADVA_ASYM_PAUSE;
   2094         break;
   2095     case SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX |
   2096          SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX:
   2097         lds_adv |= LDS_ADVA_PAUSE;
   2098         break;
   2099     }
   2100 
   2101     SOC_IF_ERROR_RETURN
   2102         (MODIFY_PHY54880_LDS_ADVAr(unit, pc, lds_adv, LDS_ADVA_MASK(pc)));
   2103 
   2104     return SOC_E_NONE;
   2105 }
   2106 
   2107 STATIC int
   2108 _phy_54880_br_ability_advert_std_set(int unit, soc_port_t port, soc_port_ability_t *ability)
   2109 {
   2110     uint32 adv_ability = 0;
   2111 
   2112     if (ability->speed_full_duplex & SOC_PA_SPEED_10MB)  {
   2113         adv_ability |= LONGREACH_ABILITY_10M;
   2114     }
   2115     if (ability->speed_full_duplex & SOC_PA_SPEED_100MB)  {
   2116         adv_ability |= LONGREACH_ABILITY_100M;
   2117     }
   2118 
   2119     if (ability->pause & SOC_PA_PAUSE_TX)  {
   2120         adv_ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX;
   2121     }
   2122     if (ability->pause & SOC_PA_PAUSE_RX)  {
   2123         adv_ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX;
   2124     }
   2125 
   2126     SOC_IF_ERROR_RETURN
   2127         (_phy_54880_br_ability_advert_set(unit, port, adv_ability));
   2128 
   2129     return SOC_E_NONE;
   2130 }
   2131 
   2132 STATIC int
   2133 phy_54880_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability)
   2134 {
   2135 
   2136     if (PHY_IEEE_MODE(unit, port)) {
   2137         SOC_IF_ERROR_RETURN
   2138             (_phy_54880_ieee_ability_advert_set(unit, port, ability));
   2139     } else {
   2140         SOC_IF_ERROR_RETURN
   2141             (_phy_54880_br_ability_advert_std_set(unit, port, ability));
   2142     }
   2143 
   2144     return SOC_E_NONE;
   2145 }
   2146 
   2147 
   2148 /*
   2149  * Function:
   2150  *      phy_54880_ability_advert_get
   2151  * Purpose:
   2152  *      Get the current advertisement for auto-negotiation.
   2153  * Parameters:
   2154  *      unit    - StrataSwitch unit #.
   2155  *      port    - StrataSwitch port #.
   2156  *      ability - Port ability indicating supported options/speeds.
   2157  * Returns:
   2158  *      SOC_E_XXX
   2159  * Notes:
   2160  *      The advertisement is retrieved for the ACTIVE medium.
   2161  *      No synchronization performed at this level.
   2162  */
   2163 
   2164 STATIC int
   2165 _phy_54880_ieee_ability_advert_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   2166 {
   2167     phy_ctrl_t *pc;
   2168 
   2169     pc = EXT_PHY_SW_STATE(unit, port);
   2170 
   2171     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   2172         (_SW2IEEE(unit, pc));
   2173 
   2174     SOC_IF_ERROR_RETURN
   2175         (phy_fe_ge_ability_advert_get(unit, port, ability));
   2176 
   2177     return SOC_E_NONE;
   2178 }
   2179 
   2180 STATIC int
   2181 _phy_54880_br_ability_advert_get(int unit, soc_port_t port, uint32 *ability)
   2182 {
   2183     phy_ctrl_t *pc;
   2184     uint16      lds_adv;
   2185 
   2186     pc = EXT_PHY_SW_STATE(unit, port);
   2187 
   2188     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   2189         (_SW2BR(unit, pc));
   2190 
   2191     SOC_IF_ERROR_RETURN
   2192         (READ_PHY54880_LDS_ADVAr(unit, pc, &lds_adv));
   2193 
   2194     *ability = 0;
   2195 
   2196     if (lds_adv & LDS_ADVA_1_10) {
   2197         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR;
   2198     }
   2199     if (lds_adv & LDS_ADVA_2_10) {
   2200         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR;
   2201     }
   2202     if (lds_adv & LDS_ADVA_1_20) {
   2203         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_1PAIR;
   2204     }
   2205     if (lds_adv & LDS_ADVA_2_20) {
   2206         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_2PAIR;
   2207     }
   2208     if (lds_adv & LDS_ADVA_1_25) {
   2209         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_1PAIR;
   2210     }
   2211     if (lds_adv & LDS_ADVA_2_25) {
   2212         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_2PAIR;
   2213     }
   2214     if (lds_adv & LDS_ADVA_1_33) {
   2215         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_1PAIR;
   2216     }
   2217     if (lds_adv & LDS_ADVA_2_33) {
   2218         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_2PAIR;
   2219     }
   2220     if (lds_adv & LDS_ADVA_1_50) {
   2221         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_1PAIR;
   2222     }
   2223     if (lds_adv & LDS_ADVA_2_50) {
   2224         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_2PAIR;
   2225     }
   2226     if (lds_adv & LDS_ADVA_1_100) {
   2227         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR;
   2228     }
   2229     if (lds_adv & LDS_ADVA_2_100) {
   2230         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR;
   2231     }
   2232     if (lds_adv & LDS_ADVA_4_100) {
   2233         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR;
   2234     }
   2235 
   2236     switch (lds_adv & (LDS_ADVA_PAUSE | LDS_ADVA_ASYM_PAUSE)) {
   2237     case LDS_ADVA_PAUSE:
   2238         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX | 
   2239                      SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX;
   2240         break;
   2241     case LDS_ADVA_ASYM_PAUSE:
   2242         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX;
   2243         break;
   2244     case LDS_ADVA_PAUSE | LDS_ADVA_ASYM_PAUSE:
   2245         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX;
   2246         break;
   2247     }
   2248 
   2249     return SOC_E_NONE;
   2250 }
   2251 
   2252 STATIC int
   2253 _phy_54880_br_ability_advert_std_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   2254 {
   2255     uint32 adv_ability;
   2256 
   2257     sal_memset(ability, 0, sizeof(*ability));
   2258     adv_ability = 0;
   2259 
   2260     SOC_IF_ERROR_RETURN
   2261         (_phy_54880_br_ability_advert_get(unit, port, &adv_ability));
   2262 
   2263     if (adv_ability & LONGREACH_ABILITY_10M) {
   2264       ability->speed_full_duplex |= SOC_PA_SPEED_10MB;
   2265     }
   2266     if (adv_ability & LONGREACH_ABILITY_100M) {
   2267       ability->speed_full_duplex |= SOC_PA_SPEED_100MB;
   2268     }
   2269 
   2270     if (adv_ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX) {
   2271       ability->pause |= SOC_PA_PAUSE_TX;
   2272     }
   2273 
   2274     if (adv_ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX) {
   2275       ability->pause |= SOC_PA_PAUSE_RX;
   2276     }
   2277 
   2278     return SOC_E_NONE;
   2279 }
   2280 
   2281 
   2282 STATIC int
   2283 phy_54880_ability_advert_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   2284 {
   2285     if (NULL == ability) {
   2286         return (SOC_E_PARAM);
   2287     }
   2288 
   2289     if (PHY_IEEE_MODE(unit, port)) {
   2290         SOC_IF_ERROR_RETURN
   2291             (_phy_54880_ieee_ability_advert_get(unit, port, ability));
   2292     } else {
   2293         SOC_IF_ERROR_RETURN
   2294             (_phy_54880_br_ability_advert_std_get(unit, port, ability));
   2295     }
   2296 
   2297     return SOC_E_NONE;
   2298 }
   2299 
   2300 /*
   2301  * Function:
   2302  *      phy_54880_ability_remote_get
   2303  * Purpose:
   2304  *      Get partners current advertisement for auto-negotiation.
   2305  * Parameters:
   2306  *      unit    - StrataSwitch unit #.
   2307  *      port    - StrataSwitch port #.
   2308  *      ability - Port ability indicating supported options/speeds.
   2309  * Returns:
   2310  *      SOC_E_XXX
   2311  * Notes:
   2312  *      The remote advertisement is retrieved for the ACTIVE medium.
   2313  *      No synchronization performed at this level. If Autonegotiation is
   2314  *      disabled or in progress, this routine will return an error.
   2315  */
   2316 
   2317 STATIC int
   2318 _phy_54880_ieee_ability_remote_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   2319 {
   2320     phy_ctrl_t       *pc;
   2321 
   2322     pc = EXT_PHY_SW_STATE(unit, port);
   2323 
   2324     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   2325         (_SW2IEEE(unit, pc));
   2326 
   2327     SOC_IF_ERROR_RETURN
   2328         (phy_fe_ge_ability_remote_get(unit, port, ability));
   2329 
   2330     return SOC_E_NONE;
   2331 }
   2332 
   2333 STATIC int
   2334 _phy_54880_br_ability_remote_get(int unit, soc_port_t port, uint32 *ability)
   2335 {
   2336     phy_ctrl_t *pc;
   2337     uint16      lds_adv;
   2338 
   2339     pc = EXT_PHY_SW_STATE(unit, port);
   2340 
   2341     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   2342         (_SW2BR(unit, pc));
   2343 
   2344     SOC_IF_ERROR_RETURN
   2345         (READ_PHY54880_LDS_LPABr(unit, pc, &lds_adv));
   2346 
   2347     *ability = 0;
   2348 
   2349     if (lds_adv & LDS_ADVA_1_10) {
   2350         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR;
   2351     }
   2352     if (lds_adv & LDS_ADVA_2_10) {
   2353         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR;
   2354     }
   2355     if (lds_adv & LDS_ADVA_1_20) {
   2356         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_1PAIR;
   2357     }
   2358     if (lds_adv & LDS_ADVA_2_20) {
   2359         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_2PAIR;
   2360     }
   2361     if (lds_adv & LDS_ADVA_1_25) {
   2362         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_1PAIR;
   2363     }
   2364     if (lds_adv & LDS_ADVA_2_25) {
   2365         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_2PAIR;
   2366     }
   2367     if (lds_adv & LDS_ADVA_1_33) {
   2368         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_1PAIR;
   2369     }
   2370     if (lds_adv & LDS_ADVA_2_33) {
   2371         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_2PAIR;
   2372     }
   2373     if (lds_adv & LDS_ADVA_1_50) {
   2374         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_1PAIR;
   2375     }
   2376     if (lds_adv & LDS_ADVA_2_50) {
   2377         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_2PAIR;
   2378     }
   2379     if (lds_adv & LDS_ADVA_1_100) {
   2380         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR;
   2381     }
   2382     if (lds_adv & LDS_ADVA_2_100) {
   2383         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR;
   2384     }
   2385     if (lds_adv & LDS_ADVA_4_100) {
   2386         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR;
   2387     }
   2388 
   2389     switch (lds_adv & (LDS_ADVA_PAUSE | LDS_ADVA_ASYM_PAUSE)) {
   2390     case LDS_ADVA_PAUSE:
   2391         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX | 
   2392                      SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX;
   2393         break;
   2394     case LDS_ADVA_ASYM_PAUSE:
   2395         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX;
   2396         break;
   2397     case LDS_ADVA_PAUSE | LDS_ADVA_ASYM_PAUSE:
   2398         *ability |= SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX;
   2399         break;
   2400     }
   2401 
   2402     return SOC_E_NONE;
   2403 }
   2404 
   2405 STATIC int
   2406 _phy_54880_br_ability_remote_std_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   2407 {
   2408 
   2409     uint32 rem_ability;
   2410 
   2411     sal_memset(ability, 0, sizeof(*ability));
   2412     rem_ability = 0;
   2413 
   2414     SOC_IF_ERROR_RETURN
   2415         (_phy_54880_br_ability_remote_get(unit, port, &rem_ability));
   2416 
   2417     if (rem_ability & LONGREACH_ABILITY_10M) {
   2418       ability->speed_full_duplex |= SOC_PA_SPEED_10MB;
   2419     }
   2420     if (rem_ability & LONGREACH_ABILITY_100M) {
   2421       ability->speed_full_duplex |= SOC_PA_SPEED_100MB;
   2422     }
   2423 
   2424     if (rem_ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX) {
   2425       ability->pause |= SOC_PA_PAUSE_TX;
   2426     }
   2427 
   2428     if (rem_ability & SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX) {
   2429       ability->pause |= SOC_PA_PAUSE_RX;
   2430     }
   2431 
   2432     return SOC_E_NONE;
   2433 
   2434 }
   2435 
   2436 STATIC int
   2437 phy_54880_ability_remote_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   2438 {
   2439     if (NULL == ability) {
   2440         return (SOC_E_PARAM);
   2441     }
   2442 
   2443     if (PHY_IEEE_MODE(unit, port)) {
   2444         SOC_IF_ERROR_RETURN
   2445             (_phy_54880_ieee_ability_remote_get(unit, port, ability));
   2446     } else {
   2447         SOC_IF_ERROR_RETURN
   2448             (_phy_54880_br_ability_remote_std_get(unit, port, ability));
   2449     }
   2450 
   2451     return SOC_E_NONE;
   2452 }
   2453 
   2454 STATIC int
   2455 _phy_54880_ieee_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   2456 {
   2457     phy_ctrl_t *pc;
   2458 
   2459     pc = EXT_PHY_SW_STATE(unit, port);
   2460 
   2461     if (PHY_IS_BCM54881(pc)) {
   2462         ability->speed_full_duplex  = SOC_PA_SPEED_100MB | SOC_PA_SPEED_10MB;
   2463     } else {
   2464         ability->speed_full_duplex  = SOC_PA_SPEED_1000MB |SOC_PA_SPEED_100MB | 
   2465                                       SOC_PA_SPEED_10MB;
   2466     }
   2467     ability->speed_half_duplex  = SOC_PA_SPEED_100MB | SOC_PA_SPEED_10MB;
   2468 
   2469     ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   2470     ability->interface = SOC_PA_INTF_SGMII;
   2471     ability->medium    = SOC_PA_MEDIUM_IEEE; 
   2472     ability->loopback  = SOC_PA_LB_PHY;
   2473     ability->flags     = SOC_PA_AUTONEG;
   2474 
   2475     return SOC_E_NONE;
   2476 }
   2477 
   2478 STATIC int
   2479 _phy_54880_br_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   2480 {
   2481 #if 1
   2482     ability->speed_full_duplex  = SOC_PA_SPEED_100MB |SOC_PA_SPEED_10MB; 
   2483 #endif
   2484     ability->speed_half_duplex  = SOC_PA_ABILITY_NONE;
   2485 
   2486     ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   2487     ability->interface = SOC_PA_INTF_SGMII;
   2488     ability->medium    = SOC_PA_MEDIUM_IEEE; 
   2489     ability->loopback  = SOC_PA_LB_PHY;
   2490     ability->flags     = SOC_PA_AUTONEG;
   2491 
   2492     return SOC_E_NONE;
   2493 }
   2494 
   2495 /*
   2496  * Function:
   2497  *      phy_54880_ability_local_get
   2498  * Purpose:
   2499  *      Get the device's complete abilities.
   2500  * Parameters:
   2501  *      unit - StrataSwitch unit #.
   2502  *      port - StrataSwitch port #.
   2503  *      ability - return device's abilities.
   2504  * Returns:
   2505  *      SOC_E_XXX
   2506  */
   2507 
   2508 STATIC int
   2509 phy_54880_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   2510 {
   2511     if (NULL == ability) {
   2512         return (SOC_E_PARAM);
   2513     }
   2514 
   2515     if (PHY_IEEE_MODE(unit, port)) {
   2516         SOC_IF_ERROR_RETURN
   2517             (_phy_54880_ieee_ability_local_get(unit, port, ability));
   2518     } else {
   2519         SOC_IF_ERROR_RETURN
   2520             (_phy_54880_br_ability_local_get(unit, port, ability));
   2521     }
   2522 
   2523     return SOC_E_NONE;
   2524 }
   2525 
   2526 STATIC int
   2527 _phy_54880_br_ability_current_get(int unit, soc_port_t port, uint32 *ability)
   2528 {
   2529     uint16      lre_ctrl, lre_stat;
   2530     phy_ctrl_t  *pc;
   2531     uint32 ability_local, ability_remote;
   2532     int speed, pairs;
   2533 
   2534     pc = EXT_PHY_SW_STATE(unit, port);
   2535 
   2536     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   2537         (_SW2BR(unit, pc));
   2538 
   2539     SOC_IF_ERROR_RETURN
   2540         (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl));
   2541 
   2542     if (lre_ctrl & LRE_CTRL_LDSE) {
   2543         SOC_IF_ERROR_RETURN
   2544             (READ_PHY54880_LRE_STATr(unit, pc, &lre_stat));
   2545         if (!(lre_stat & LRE_STAT_LDS_DONE)) { /* LDS NOT complete */
   2546             *ability = 0;
   2547         } else {
   2548             ability_local = 0;
   2549             ability_remote = 0;
   2550 
   2551             SOC_IF_ERROR_RETURN
   2552                 (_phy_54880_br_ability_advert_get(unit, port, &ability_local));
   2553             SOC_IF_ERROR_RETURN
   2554                 (_phy_54880_br_ability_remote_get(unit, port, &ability_remote));
   2555             SOC_IF_ERROR_RETURN
   2556                 (_phy_54880_br_speed_get(unit, port, &speed));
   2557             SOC_IF_ERROR_RETURN
   2558                 (_phy_54880_br_pairs_get(unit, port, &pairs));
   2559             *ability = (ability_local & ability_remote & (3U<<13)) |
   2560                        (((speed == 100) ? (1U << 10): 
   2561                          (speed == 50)  ? (1U << 8): 
   2562                          (speed == 33)  ? (1U << 6): 
   2563                          (speed == 25)  ? (1U << 4): 
   2564                          (speed == 20)  ? (1U << 2): 
   2565                          (speed == 10)  ? (1U << 0):0) 
   2566                          << (((unsigned) pairs) >> 1));
   2567         }
   2568     } else {
   2569         *ability = 0;
   2570     }
   2571 
   2572 
   2573     return SOC_E_NONE;
   2574 }
   2575 
   2576 /*
   2577  * Function:
   2578  *      phy_54880_lb_set
   2579  * Purpose:
   2580  *      Set the local PHY loopback mode.
   2581  * Parameters:
   2582  *      unit - StrataSwitch unit #.
   2583  *      port - StrataSwitch port #.
   2584  *      loopback - Boolean: true = enable loopback, false = disable.
   2585  * Returns:
   2586  *      SOC_E_XXX
   2587  * Notes:
   2588  *      The loopback mode is set only for the ACTIVE medium.
   2589  *      No synchronization performed at this level.
   2590  */
   2591 
   2592 STATIC int
   2593 _phy_54880_ieee_lb_set(int unit, soc_port_t port, int enable)
   2594 {
   2595     phy_ctrl_t    *pc;
   2596 
   2597     pc = EXT_PHY_SW_STATE(unit, port);
   2598 
   2599 #if AUTO_MDIX_WHEN_AN_DIS
   2600         {
   2601         uint16          tmp;
   2602 
   2603         /* Disable Auto-MDIX When autoneg disabled */
   2604         /* Enable Auto-MDIX When autoneg disabled */
   2605         tmp = (enable) ? 0x0000: 0x0200;
   2606         SOC_IF_ERROR_RETURN
   2607             (MODIFY_PHY54880_MII_MISC_CTRLr(unit, pc, tmp, 0x0200));
   2608         }
   2609 #endif
   2610     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   2611         (_SW2IEEE(unit, pc));
   2612 
   2613     SOC_IF_ERROR_RETURN
   2614         (phy_fe_ge_lb_set(unit, port, enable));
   2615 
   2616     return SOC_E_NONE;
   2617 }
   2618 
   2619 STATIC int
   2620 _phy_54880_br_lb_set(int unit, soc_port_t port, int enable)
   2621 {
   2622     phy_ctrl_t  *pc;
   2623 
   2624     pc = EXT_PHY_SW_STATE(unit, port);
   2625 
   2626     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   2627         (_SW2BR(unit, pc));
   2628 
   2629     SOC_IF_ERROR_RETURN
   2630         (MODIFY_PHY54880_LRE_CTRLr(unit, pc, (enable ? MII_CTRL_LE : 0), MII_CTRL_LE));
   2631 
   2632     return SOC_E_NONE;
   2633 }
   2634 
   2635 STATIC int
   2636 phy_54880_lb_set(int unit, soc_port_t port, int enable)
   2637 {
   2638     if (PHY_IEEE_MODE(unit, port)) {
   2639         SOC_IF_ERROR_RETURN
   2640             (_phy_54880_ieee_lb_set(unit, port, enable));
   2641     } else {
   2642         SOC_IF_ERROR_RETURN
   2643             (_phy_54880_br_lb_set(unit, port, enable));
   2644     }
   2645 
   2646     return SOC_E_NONE;
   2647 }
   2648 
   2649 /*
   2650  * Function:
   2651  *      phy_54880_lb_get
   2652  * Purpose:
   2653  *      Get the local PHY loopback mode.
   2654  * Parameters:
   2655  *      unit - StrataSwitch unit #.
   2656  *      port - StrataSwitch port #.
   2657  *      loopback - (OUT) Boolean: true = enable loopback, false = disable.
   2658  * Returns:
   2659  *      SOC_E_XXX
   2660  * Notes:
   2661  *      The loopback mode is retrieved for the ACTIVE medium.
   2662  */
   2663 
   2664 STATIC int
   2665 _phy_54880_br_lb_get(int unit, soc_port_t port, int *enable)
   2666 {
   2667     uint16      lre_ctrl;
   2668     phy_ctrl_t  *pc;
   2669 
   2670     pc = EXT_PHY_SW_STATE(unit, port);
   2671 
   2672     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   2673         (_SW2BR(unit, pc));
   2674 
   2675     SOC_IF_ERROR_RETURN
   2676         (READ_PHY54880_LRE_CTRLr(unit, pc, &lre_ctrl));
   2677 
   2678     *enable = (lre_ctrl & MII_CTRL_LE) ? 1 : 0;
   2679 
   2680     return SOC_E_NONE;
   2681 }
   2682 
   2683 STATIC int
   2684 phy_54880_lb_get(int unit, soc_port_t port, int *enable)
   2685 {
   2686     phy_ctrl_t    *pc;
   2687 
   2688     pc = EXT_PHY_SW_STATE(unit, port);
   2689 
   2690     if (PHY_IEEE_MODE(unit, port)) {
   2691 
   2692         SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   2693             (_SW2IEEE(unit, pc));
   2694 
   2695         SOC_IF_ERROR_RETURN
   2696             (phy_fe_ge_lb_get(unit, port, enable));
   2697     } else {
   2698         SOC_IF_ERROR_RETURN
   2699             (_phy_54880_br_lb_get(unit, port, enable));
   2700     }
   2701 
   2702     return SOC_E_NONE;
   2703 }
   2704 
   2705 /*
   2706  * Function:
   2707  *      phy_54880_interface_set
   2708  * Purpose:
   2709  *      Set the current operating mode of the internal PHY.
   2710  *      (Pertaining to the MAC/PHY interface, not the line interface).
   2711  * Parameters:
   2712  *      unit - StrataSwitch unit #.
   2713  *      port - StrataSwitch port #.
   2714  *      pif - one of SOC_PORT_IF_*
   2715  * Returns:
   2716  *      SOC_E_XXX
   2717  */
   2718 
   2719 STATIC int
   2720 phy_54880_interface_set(int unit, soc_port_t port, soc_port_if_t pif)
   2721 {
   2722     COMPILER_REFERENCE(unit);
   2723     COMPILER_REFERENCE(port);
   2724     COMPILER_REFERENCE(pif);
   2725 
   2726     return SOC_E_NONE;
   2727 
   2728 }
   2729 
   2730 /*
   2731  * Function:
   2732  *      phy_54880_interface_get
   2733  * Purpose:
   2734  *      Get the current operating mode of the internal PHY.
   2735  *      (Pertaining to the MAC/PHY interface, not the line interface).
   2736  * Parameters:
   2737  *      unit - StrataSwitch unit #.
   2738  *      port - StrataSwitch port #.
   2739  *      pif - (OUT) one of SOC_PORT_IF_*
   2740  * Returns:
   2741  *      SOC_E_XXX
   2742  */
   2743 
   2744 STATIC int
   2745 phy_54880_interface_get(int unit, soc_port_t port, soc_port_if_t *pif)
   2746 {
   2747     phy_ctrl_t    *pc;
   2748 
   2749     pc = EXT_PHY_SW_STATE(unit, port);
   2750 
   2751     if (PHY_IS_BCM54881(pc)) {
   2752         *pif = SOC_PORT_IF_MII;
   2753     } else {
   2754         *pif = SOC_PORT_IF_SGMII;
   2755     }
   2756 
   2757     return(SOC_E_NONE);
   2758 }
   2759 
   2760 /*
   2761  * Function:
   2762  *      phy_54880_mdix_set
   2763  * Description:
   2764  *      Set the Auto-MDIX mode of a port/PHY
   2765  * Parameters:
   2766  *      unit - Device number
   2767  *      port - Port number
   2768  *      mode - One of:
   2769  *              SOC_PORT_MDIX_AUTO
   2770  *                      Enable auto-MDIX when autonegotiation is enabled
   2771  *              SOC_PORT_MDIX_FORCE_AUTO
   2772  *                      Enable auto-MDIX always
   2773  *              SOC_PORT_MDIX_NORMAL
   2774  *                      Disable auto-MDIX
   2775  *              SOC_PORT_MDIX_XOVER
   2776  *                      Disable auto-MDIX, and swap cable pairs
   2777  * Return Value:
   2778  *      SOC_E_XXX
   2779  */
   2780 STATIC int
   2781 _phy_54880_ieee_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode)
   2782 {
   2783     phy_ctrl_t    *pc;
   2784     int            speed;
   2785 
   2786     pc = EXT_PHY_SW_STATE(unit, port);
   2787 
   2788     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   2789         (_SW2IEEE(unit, pc));
   2790 
   2791     switch (mode) {
   2792     case SOC_PORT_MDIX_AUTO:
   2793         /* Clear bit 14 for automatic MDI crossover */
   2794         SOC_IF_ERROR_RETURN
   2795             (MODIFY_PHY54880_MII_ECRr(unit, pc, 0, 0x4000));
   2796 
   2797         /*
   2798          * Write the result in the register 0x18, shadow copy 7
   2799          */
   2800         /* Clear bit 9 to disable forced auto MDI xover */
   2801         SOC_IF_ERROR_RETURN
   2802             (MODIFY_PHY54880_MII_MISC_CTRLr(unit, pc, 0, 0x0200));
   2803         break;
   2804 
   2805     case SOC_PORT_MDIX_FORCE_AUTO:
   2806         /* Clear bit 14 for automatic MDI crossover */
   2807         SOC_IF_ERROR_RETURN
   2808             (MODIFY_PHY54880_MII_ECRr(unit, pc, 0, 0x4000));
   2809 
   2810         /*
   2811          * Write the result in the register 0x18, shadow copy 7
   2812          */
   2813         /* Set bit 9 to force automatic MDI crossover */
   2814         SOC_IF_ERROR_RETURN
   2815             (MODIFY_PHY54880_MII_MISC_CTRLr(unit, pc, 0x0200, 0x0200));
   2816         break;
   2817 
   2818     case SOC_PORT_MDIX_NORMAL:
   2819         SOC_IF_ERROR_RETURN(phy_54880_speed_get(unit, port, &speed));
   2820         if (speed == 0 || speed == 10 || speed == 100) {
   2821             /* Set bit 14 for manual MDI crossover */
   2822             SOC_IF_ERROR_RETURN
   2823                 (MODIFY_PHY54880_MII_ECRr(unit, pc, 0x4000, 0x4000));
   2824 
   2825             SOC_IF_ERROR_RETURN
   2826                 (WRITE_PHY54880_TEST1r(unit, pc, 0));
   2827         } else {
   2828             return SOC_E_UNAVAIL;
   2829         }
   2830         break;
   2831 
   2832     case SOC_PORT_MDIX_XOVER:
   2833         SOC_IF_ERROR_RETURN(phy_54880_speed_get(unit, port, &speed));
   2834         if (speed == 0 || speed == 10 || speed == 100) {
   2835              /* Set bit 14 for manual MDI crossover */
   2836             SOC_IF_ERROR_RETURN
   2837                 (MODIFY_PHY54880_MII_ECRr(unit, pc, 0x4000, 0x4000));
   2838 
   2839             SOC_IF_ERROR_RETURN
   2840                 (WRITE_PHY54880_TEST1r(unit, pc, 0x0080));
   2841         } else {
   2842             return SOC_E_UNAVAIL;
   2843         }
   2844         break;
   2845 
   2846     default:
   2847         return SOC_E_PARAM;
   2848     }
   2849 
   2850     return SOC_E_NONE;
   2851 
   2852 }        
   2853 
   2854 STATIC int
   2855 phy_54880_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode)
   2856 {
   2857     phy_ctrl_t    *pc;
   2858 
   2859     pc = EXT_PHY_SW_STATE(unit, port);
   2860 
   2861     if (PHY_IEEE_MODE(unit, port)) {
   2862         SOC_IF_ERROR_RETURN
   2863             (_phy_54880_ieee_mdix_set(unit, port, mode));
   2864         pc->copper.mdix = mode;
   2865     } else {
   2866         return(SOC_E_CONFIG);
   2867     }
   2868 
   2869     return SOC_E_NONE;
   2870 }
   2871 
   2872 /*
   2873  * Function:
   2874  *      phy_54880_mdix_get
   2875  * Description:
   2876  *      Get the Auto-MDIX mode of a port/PHY
   2877  * Parameters:
   2878  *      unit - Device number
   2879  *      port - Port number
   2880  *      mode - (Out) One of:
   2881  *              SOC_PORT_MDIX_AUTO
   2882  *                      Enable auto-MDIX when autonegotiation is enabled
   2883  *              SOC_PORT_MDIX_FORCE_AUTO
   2884  *                      Enable auto-MDIX always
   2885  *              SOC_PORT_MDIX_NORMAL
   2886  *                      Disable auto-MDIX
   2887  *              SOC_PORT_MDIX_XOVER
   2888  *                      Disable auto-MDIX, and swap cable pairs
   2889  * Return Value:
   2890  *      SOC_E_XXX
   2891  */
   2892 STATIC int
   2893 _phy_54880_ieee_mdix_get(int unit, soc_port_t port, soc_port_mdix_t *mode)
   2894 {
   2895     phy_ctrl_t    *pc;
   2896     int            speed;
   2897 
   2898     pc = EXT_PHY_SW_STATE(unit, port);
   2899 
   2900     SOC_IF_ERROR_NOT_DISABLED_RETURN_ERROR
   2901         (_SW2IEEE(unit, pc));
   2902 
   2903     SOC_IF_ERROR_RETURN(phy_54880_speed_get(unit, port, &speed));
   2904     if (speed == 1000) {
   2905        *mode = SOC_PORT_MDIX_AUTO;
   2906     } else {
   2907         *mode = pc->copper.mdix;
   2908     }
   2909 
   2910     return SOC_E_NONE;
   2911 }    
   2912 
   2913 STATIC int
   2914 phy_54880_mdix_get(int unit, soc_port_t port, soc_port_mdix_t *mode)
   2915 {
   2916     if (PHY_IEEE_MODE(unit, port)) {
   2917         SOC_IF_ERROR_RETURN
   2918             (_phy_54880_ieee_mdix_get(unit, port, mode));
   2919     } else {
   2920         *mode = SOC_PORT_MDIX_AUTO;
   2921     }
   2922 
   2923     return SOC_E_NONE;
   2924 }
   2925 
   2926 /*
   2927  * Function:
   2928  *      phy_54880_mdix_status_get
   2929  * Description:
   2930  *      Get the current MDIX status on a port/PHY
   2931  * Parameters:
   2932  *      unit    - Device number
   2933  *      port    - Port number
   2934  *      status  - (OUT) One of:
   2935  *              SOC_PORT_MDIX_STATUS_NORMAL
   2936  *                      Straight connection
   2937  *              SOC_PORT_MDIX_STATUS_XOVER
   2938  *                      Crossover has been performed
   2939  * Return Value:
   2940  *      SOC_E_XXX
   2941  */
   2942 STATIC int
   2943 phy_54880_mdix_status_get(int unit, soc_port_t port, 
   2944                          soc_port_mdix_status_t *status)
   2945 {
   2946     phy_ctrl_t    *pc;
   2947     uint16               tmp;
   2948 
   2949     pc = EXT_PHY_SW_STATE(unit, port);
   2950 
   2951     SOC_IF_ERROR_RETURN
   2952         (READ_PHY54880_MII_ESRr(unit, pc, &tmp));
   2953     if (tmp & 0x2000) {
   2954         *status = SOC_PORT_MDIX_STATUS_XOVER;
   2955     } else {
   2956         *status = SOC_PORT_MDIX_STATUS_NORMAL;
   2957     }
   2958 
   2959     return SOC_E_NONE;
   2960 }    
   2961 
   2962 STATIC int
   2963 phy_54880_link_up(int unit, soc_port_t port)
   2964 {
   2965     phy_ctrl_t *pc;
   2966     int pairs, master;
   2967     int speed;
   2968 
   2969     pc = EXT_PHY_SW_STATE(unit, port);
   2970 
   2971     SOC_IF_ERROR_RETURN
   2972         (phy_54880_speed_get(unit, port, &speed));
   2973     
   2974     if (PHY_IS_B0(pc)) {
   2975         if (PHY_BR_MODE(unit, port)) {
   2976             /* B0 errata */
   2977             SOC_IF_ERROR_RETURN
   2978                 (_phy_54880_br_pairs_get(unit, port, &pairs));
   2979             SOC_IF_ERROR_RETURN
   2980                 (_phy_54880_br_master_get(unit, port, &master));
   2981 
   2982             switch(pairs) {
   2983             case 4:
   2984                 if (master == SOC_PORT_MS_MASTER) {
   2985                     SOC_IF_ERROR_RETURN
   2986                         (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL3r(unit, pc, 1U<<15, 1U<<15));
   2987                 }
   2988                 break;
   2989 
   2990             case 2:
   2991             case 1:
   2992                 SOC_IF_ERROR_RETURN
   2993                     (PHY54880_REG_WRITE(unit, pc, 0x00, 0x0ffd, 0x15, 0x0038));
   2994                 SOC_IF_ERROR_RETURN
   2995                     (PHY54880_REG_WRITE(unit, pc, 0x00, 0x0ffe, 0x15, 0x0038));
   2996                 break;
   2997 
   2998             default:
   2999                 break;
   3000             }
   3001         }
   3002 
   3003     }
   3004 
   3005     /* Notify interface to internal PHY */
   3006     SOC_IF_ERROR_RETURN
   3007         (soc_phyctrl_notify(unit, port, phyEventInterface, SOC_PORT_IF_SGMII));
   3008 
   3009     /* Situation observed with Saber devices XGXS16g1l+BCM54640E
   3010        Linkscan is not updating speed for internal phy xgxs16g1l. 
   3011        It was observed that when speed is set to 100M the int phy 
   3012        is still set to 1G and traffic does not flow through untill 
   3013        int phy speed is also update to 100M. This applies to other 
   3014        speeds as well. 
   3015        Explicitly send speed notify to int phy from ext phy.
   3016     */
   3017     SOC_IF_ERROR_RETURN
   3018         (soc_phyctrl_notify(unit, port, phyEventSpeed, speed));
   3019 
   3020     return SOC_E_NONE;
   3021 }
   3022 
   3023 STATIC int
   3024 phy_54880_link_down(int unit, soc_port_t port)
   3025 {
   3026     phy_ctrl_t *pc;
   3027 
   3028     pc = EXT_PHY_SW_STATE(unit, port);
   3029 
   3030     if (PHY_IS_B0(pc)) {
   3031         if (PHY_BR_MODE(unit, port)) {
   3032             /* B0 errata */
   3033             SOC_IF_ERROR_RETURN
   3034                 (MODIFY_PHY54880_EXP_BR_LRE_MISC_CTRL3r(unit, pc, 0, 1U<<15));
   3035             SOC_IF_ERROR_RETURN
   3036                 (PHY54880_REG_WRITE(unit, pc, 0x00, 0x0ffd, 0x15, 0));
   3037             SOC_IF_ERROR_RETURN
   3038                 (PHY54880_REG_WRITE(unit, pc, 0x00, 0x0ffe, 0x15, 0));
   3039         }
   3040     }
   3041 
   3042     return SOC_E_NONE;
   3043 }
   3044 
   3045 STATIC int
   3046 _phy_54880_power_mode_set (int unit, soc_port_t port, int mode)
   3047 {
   3048     phy_ctrl_t    *pc;
   3049 
   3050     pc       = EXT_PHY_SW_STATE(unit, port);
   3051 
   3052     if (pc->power_mode == mode) {
   3053         return SOC_E_NONE;
   3054     }
   3055 
   3056     if (mode == SOC_PHY_CONTROL_POWER_LOW) {
   3057         /* enable dsp clock */
   3058         SOC_IF_ERROR_RETURN
   3059             (MODIFY_PHY54880_MII_AUX_CTRLr(unit,pc,0x0c00,0x0c00));
   3060 
   3061         /* enable low power 136 */
   3062         SOC_IF_ERROR_RETURN
   3063             (MODIFY_PHY54880_AUTO_POWER_DOWNr(unit,pc,0x80,0x80));
   3064 
   3065         /* reduce tx bias current to -20% */
   3066         SOC_IF_ERROR_RETURN
   3067             (WRITE_PHY_REG(unit, pc, 0x17, 0x0f75));
   3068         SOC_IF_ERROR_RETURN
   3069             (WRITE_PHY_REG(unit, pc, 0x15, 0x1555));
   3070 
   3071         /* disable dsp clock */
   3072         SOC_IF_ERROR_RETURN
   3073             (MODIFY_PHY54880_MII_AUX_CTRLr(unit,pc,0x0400,0x0c00));
   3074         pc->power_mode = mode;
   3075 
   3076     } else if (mode == SOC_PHY_CONTROL_POWER_FULL) {
   3077 
   3078         /* back to normal mode */
   3079         /* enable dsp clock */
   3080         SOC_IF_ERROR_RETURN
   3081             (MODIFY_PHY54880_MII_AUX_CTRLr(unit,pc,0x0c00,0x0c00));
   3082 
   3083         /* disable low power 136 */
   3084         SOC_IF_ERROR_RETURN
   3085             (MODIFY_PHY54880_AUTO_POWER_DOWNr(unit,pc,0x00,0x80));
   3086 
   3087         /* set tx bias current to nominal */
   3088         SOC_IF_ERROR_RETURN
   3089             (WRITE_PHY_REG(unit, pc, 0x17, 0x0f75));
   3090         SOC_IF_ERROR_RETURN
   3091             (WRITE_PHY_REG(unit, pc, 0x15, 0x0));
   3092 
   3093         /* disable dsp clock */
   3094         SOC_IF_ERROR_RETURN
   3095             (MODIFY_PHY54880_MII_AUX_CTRLr(unit,pc,0x0400,0x0c00));
   3096 
   3097         /* disable the auto power mode */
   3098         SOC_IF_ERROR_RETURN
   3099             (MODIFY_PHY54880_AUTO_POWER_DOWNr(unit,pc,
   3100                         0,
   3101                         PHY_54880_AUTO_PWRDWN_EN));
   3102         pc->power_mode = mode;
   3103     } else if (mode == SOC_PHY_CONTROL_POWER_AUTO) {
   3104         SOC_IF_ERROR_RETURN
   3105             (MODIFY_PHY54880_AUTO_POWER_DOWNr(unit,pc,
   3106                         PHY_54880_AUTO_PWRDWN_EN,
   3107                         PHY_54880_AUTO_PWRDWN_EN));
   3108         pc->power_mode = mode;
   3109     }
   3110     return SOC_E_NONE;
   3111 }
   3112 
   3113 /*
   3114  * Function:
   3115  *      phy_54880_control_set
   3116  * Purpose:
   3117  *      Configure PHY device specific control fucntion.
   3118  * Parameters:
   3119  *      unit  - StrataSwitch unit #.
   3120  *      port  - StrataSwitch port #.
   3121  *      type  - Control to update
   3122  *      value - New setting for the control
   3123  * Returns:
   3124  *      SOC_E_NONE
   3125  */
   3126 STATIC int
   3127 phy_54880_control_set(int unit, soc_port_t port,
   3128                      soc_phy_control_t type, uint32 value)
   3129 {
   3130     int rv;
   3131     phy_ctrl_t *pc;
   3132     phy_br_config_t  *br_config;
   3133     uint16 data;
   3134     soc_port_t primary;
   3135     int offset;
   3136 
   3137     PHY_CONTROL_TYPE_CHECK(type);
   3138 
   3139     pc = EXT_PHY_SW_STATE(unit, port);
   3140     rv = SOC_E_NONE;
   3141     br_config     = (phy_br_config_t *)  &pc->fiber;
   3142 
   3143     switch(type) {
   3144     case SOC_PHY_CONTROL_PREEMPHASIS:
   3145         rv = SOC_E_UNAVAIL;
   3146         break;
   3147 
   3148     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   3149         rv = SOC_E_UNAVAIL;
   3150         break;
   3151 
   3152     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   3153         rv = SOC_E_UNAVAIL;
   3154         break;
   3155 
   3156     case SOC_PHY_CONTROL_POWER:
   3157         rv = _phy_54880_power_mode_set(unit,port,value);
   3158         break;
   3159 
   3160     case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME:
   3161         if (value <= PHY_54880_AUTO_PWRDWN_WAKEUP_MAX) {
   3162 
   3163             /* at least one unit */
   3164             if (value < PHY_54880_AUTO_PWRDWN_WAKEUP_UNIT) {
   3165                 value = PHY_54880_AUTO_PWRDWN_WAKEUP_UNIT;
   3166             }
   3167         } else { /* anything more then max, set to the max */
   3168             value = PHY_54880_AUTO_PWRDWN_WAKEUP_MAX;
   3169         }
   3170         SOC_IF_ERROR_RETURN
   3171             (MODIFY_PHY54880_AUTO_POWER_DOWNr(unit,pc,
   3172                       value/PHY_54880_AUTO_PWRDWN_WAKEUP_UNIT,
   3173                       PHY_54880_AUTO_PWRDWN_WAKEUP_MASK));
   3174         break;
   3175 
   3176     case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME:
   3177         /* sleep time configuration is either 2.7s or 5.4 s, default is 2.7s */
   3178         if (value < PHY_54880_AUTO_PWRDWN_SLEEP_MAX) {
   3179             data = 0; /* anything less than 5.4s, default to 2.7s */
   3180         } else {
   3181             data = PHY_54880_AUTO_PWRDWN_SLEEP_MASK;
   3182         }
   3183         SOC_IF_ERROR_RETURN
   3184             (MODIFY_PHY54880_AUTO_POWER_DOWNr(unit,pc,
   3185                       data,
   3186                       PHY_54880_AUTO_PWRDWN_SLEEP_MASK));
   3187         break;
   3188 
   3189     case SOC_PHY_CONTROL_LONGREACH_SPEED:
   3190         rv = _phy_54880_br_speed_set(unit, port, value);
   3191         br_config->force_speed = value;
   3192         break;
   3193 
   3194     case SOC_PHY_CONTROL_LONGREACH_PAIRS:
   3195         rv = _phy_54880_br_pairs_set(unit, port, value);
   3196         br_config->force_pairs = value;
   3197         break;
   3198 
   3199     case SOC_PHY_CONTROL_LONGREACH_GAIN:
   3200         rv = _phy_54880_br_gain_set(unit, port, value);
   3201         br_config->gain = value;
   3202         break;
   3203 
   3204     case SOC_PHY_CONTROL_LONGREACH_AUTONEG:
   3205         rv = _phy_54880_br_autoneg_set(unit, port, value);
   3206         br_config->lds_enable = value;
   3207         break;
   3208 
   3209     case SOC_PHY_CONTROL_LONGREACH_LOCAL_ABILITY:
   3210         rv = _phy_54880_br_ability_advert_set(unit, port, value);
   3211         SOC_IF_ERROR_RETURN
   3212             (_phy_54880_br_autoneg_set(unit, port, br_config->lds_enable));
   3213         br_config->lds_advert_ability = value & LONGREACH_ABILITY_ALL(pc);
   3214         break;
   3215 
   3216     case SOC_PHY_CONTROL_LONGREACH_MASTER:
   3217         rv = _phy_54880_br_master_set(unit, port, value);
   3218         br_config->master = value;
   3219         break;
   3220 
   3221     case SOC_PHY_CONTROL_LONGREACH_ENABLE:
   3222         rv = _phy_54880_br_enable_set(unit, port, value);
   3223         br_config->enable = value;
   3224         break;
   3225 
   3226     case SOC_PHY_CONTROL_LONGREACH_REMOTE_ABILITY:
   3227     case SOC_PHY_CONTROL_LONGREACH_CURRENT_ABILITY:
   3228     case SOC_PHY_CONTROL_LONGREACH_ACTIVE:
   3229         /* Do nothing for the read only commands */
   3230         rv = SOC_E_CONFIG;
   3231         break;
   3232 
   3233     case SOC_PHY_CONTROL_PORT_PRIMARY:
   3234             SOC_IF_ERROR_RETURN
   3235                 (soc_phyctrl_primary_set(unit, port, (soc_port_t)value));
   3236         break;
   3237 
   3238         case SOC_PHY_CONTROL_PORT_OFFSET:
   3239             SOC_IF_ERROR_RETURN
   3240                 (soc_phyctrl_offset_set(unit, port, (int)value));
   3241         break;
   3242 
   3243     case SOC_PHY_CONTROL_CLOCK_ENABLE:
   3244         SOC_IF_ERROR_RETURN
   3245             (soc_phyctrl_primary_get(unit, port, &primary));
   3246         SOC_IF_ERROR_RETURN
   3247             (soc_phyctrl_offset_get(unit, port, &offset));
   3248         SOC_IF_ERROR_RETURN
   3249             (soc_phyctrl_toplvl_reg_read(unit, port, primary, 0x0, &data));
   3250         if ( value ) {
   3251             SOC_IF_ERROR_RETURN
   3252                 (soc_phyctrl_toplvl_reg_write(unit, port, primary, 0x0,
   3253                      ( data & 0xf0 ) | ( offset & 0x7 )));
   3254         } else {
   3255             SOC_IF_ERROR_RETURN
   3256                 (soc_phyctrl_toplvl_reg_write(unit, port, primary, 0x0,
   3257                      ( data & 0xf0 ) | 0x8 ));
   3258         }
   3259         break;
   3260 
   3261     case SOC_PHY_CONTROL_CLOCK_SECONDARY_ENABLE:
   3262         SOC_IF_ERROR_RETURN
   3263             (soc_phyctrl_primary_get(unit, port, &primary));
   3264         SOC_IF_ERROR_RETURN
   3265             (soc_phyctrl_offset_get(unit, port, &offset));
   3266         SOC_IF_ERROR_RETURN
   3267             (soc_phyctrl_toplvl_reg_read(unit, port, primary, 0x0, &data));
   3268         if ( value ) {
   3269             SOC_IF_ERROR_RETURN
   3270                 (soc_phyctrl_toplvl_reg_write(unit, port, primary, 0x0,
   3271                      ( data & 0x0f ) | (( offset & 0x7 )<<4 )));
   3272         } else {
   3273             SOC_IF_ERROR_RETURN
   3274                 (soc_phyctrl_toplvl_reg_write(unit, port, primary, 0x0,
   3275                      ( data & 0x0f ) | (0x8<<4) ));
   3276         }
   3277         break;
   3278 
   3279     case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT:
   3280         /* Not supported for 10/100/1000BASE-T interfaces */
   3281         rv = SOC_E_UNAVAIL;
   3282         break;
   3283 
   3284     default:
   3285         rv = SOC_E_UNAVAIL;
   3286         break;
   3287     }
   3288     return rv;
   3289 }
   3290 
   3291 /*
   3292  * Function:
   3293  *      phy_54880_control_get
   3294  * Purpose:
   3295  *      Get current control settign of the PHY.
   3296  * Parameters:
   3297  *      unit  - StrataSwitch unit #.
   3298  *      port  - StrataSwitch port #.
   3299  *      type  - Control to update
   3300  *      value - (OUT)Current setting for the control
   3301  * Returns:
   3302  *      SOC_E_NONE
   3303  */
   3304 STATIC int
   3305 phy_54880_control_get(int unit, soc_port_t port,
   3306                      soc_phy_control_t type, uint32 *value)
   3307 {
   3308     int rv;
   3309     phy_ctrl_t *pc;
   3310     int temp;
   3311     uint16 data;
   3312     soc_port_t primary;
   3313     int offset;
   3314 
   3315     PHY_CONTROL_TYPE_CHECK(type);
   3316 
   3317     pc = EXT_PHY_SW_STATE(unit, port);
   3318     rv = SOC_E_NONE;
   3319     temp = 0;
   3320 
   3321     switch(type) {
   3322 
   3323     case SOC_PHY_CONTROL_PREEMPHASIS:
   3324         rv = SOC_E_UNAVAIL;
   3325         break;
   3326 
   3327     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   3328         rv = SOC_E_UNAVAIL;
   3329         break;
   3330 
   3331     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   3332         rv = SOC_E_UNAVAIL;
   3333         break;
   3334 
   3335     case SOC_PHY_CONTROL_POWER:
   3336         *value = pc->power_mode;
   3337         rv = SOC_E_NONE;
   3338         break;
   3339 
   3340     case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME:
   3341         SOC_IF_ERROR_RETURN
   3342             (READ_PHY54880_AUTO_POWER_DOWNr(unit,pc, &data));
   3343 
   3344         if (data & PHY_54880_AUTO_PWRDWN_SLEEP_MASK) {
   3345             *value = PHY_54880_AUTO_PWRDWN_SLEEP_MAX;
   3346         } else {
   3347             *value = 2700;
   3348         }
   3349         break;
   3350 
   3351     case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME:
   3352         SOC_IF_ERROR_RETURN
   3353             (READ_PHY54880_AUTO_POWER_DOWNr(unit,pc, &data));
   3354 
   3355         data &= PHY_54880_AUTO_PWRDWN_WAKEUP_MASK;
   3356         *value = data * PHY_54880_AUTO_PWRDWN_WAKEUP_UNIT;
   3357         break;
   3358 
   3359     case SOC_PHY_CONTROL_LONGREACH_SPEED:
   3360         rv = _phy_54880_br_speed_get(unit, port, &temp);
   3361         *value = (uint32)temp;
   3362         break;
   3363 
   3364     case SOC_PHY_CONTROL_LONGREACH_PAIRS:
   3365         rv = _phy_54880_br_pairs_get(unit, port, &temp);
   3366         *value = (uint32)temp;
   3367         break;
   3368 
   3369     case SOC_PHY_CONTROL_LONGREACH_GAIN:
   3370         rv = _phy_54880_br_gain_get(unit, port, &temp);
   3371         *value = (uint32)temp;
   3372         break;
   3373 
   3374     case SOC_PHY_CONTROL_LONGREACH_AUTONEG:
   3375         rv = _phy_54880_br_autoneg_get(unit, port, &temp, NULL);
   3376         *value = (uint32)temp;
   3377         break;
   3378 
   3379     case SOC_PHY_CONTROL_LONGREACH_LOCAL_ABILITY:
   3380         rv = _phy_54880_br_ability_advert_get(unit, port, value);
   3381         break;
   3382 
   3383     case SOC_PHY_CONTROL_LONGREACH_REMOTE_ABILITY:
   3384         rv = _phy_54880_br_ability_remote_get(unit, port, value);
   3385         break;
   3386 
   3387     case SOC_PHY_CONTROL_LONGREACH_CURRENT_ABILITY:
   3388         rv = _phy_54880_br_ability_current_get(unit, port, value);
   3389         break;
   3390 
   3391     case SOC_PHY_CONTROL_LONGREACH_MASTER:
   3392         rv = _phy_54880_br_master_get(unit, port, &temp);
   3393         *value = (uint32)temp;
   3394         break;
   3395 
   3396     case SOC_PHY_CONTROL_LONGREACH_ACTIVE:
   3397         rv = _phy_54880_br_active_get(unit, port, &temp);
   3398         *value = (uint32)temp;
   3399         break;
   3400 
   3401     case SOC_PHY_CONTROL_LONGREACH_ENABLE:
   3402         rv = _phy_54880_br_enable_get(unit, port, &temp);
   3403         *value = (uint32)temp;
   3404         break;
   3405 
   3406     case SOC_PHY_CONTROL_PORT_PRIMARY:
   3407             SOC_IF_ERROR_RETURN
   3408                 (soc_phyctrl_primary_get(unit, port, &primary));
   3409             *value = (uint32) primary;
   3410         break;
   3411 
   3412     case SOC_PHY_CONTROL_PORT_OFFSET:
   3413             SOC_IF_ERROR_RETURN
   3414                 (soc_phyctrl_offset_get(unit, port, &offset));
   3415             *value = (uint32) offset;
   3416         break;
   3417 
   3418     case SOC_PHY_CONTROL_CLOCK_ENABLE:
   3419         SOC_IF_ERROR_RETURN
   3420             (soc_phyctrl_primary_get(unit, port, &primary));
   3421         SOC_IF_ERROR_RETURN
   3422             (soc_phyctrl_offset_get(unit, port, &offset));
   3423         if (soc_phyctrl_toplvl_reg_read(unit, port, primary, 0x0, &data) == SOC_E_NONE) {
   3424             if (( data & 0x8 ) || (( data & 0x7 ) != offset)) {
   3425                 *value = FALSE;
   3426             } else {
   3427                 *value = TRUE;
   3428             }
   3429         }
   3430         break;
   3431 
   3432     case SOC_PHY_CONTROL_CLOCK_SECONDARY_ENABLE:
   3433         SOC_IF_ERROR_RETURN
   3434             (soc_phyctrl_primary_get(unit, port, &primary));
   3435         SOC_IF_ERROR_RETURN
   3436             (soc_phyctrl_offset_get(unit, port, &offset));
   3437         if (soc_phyctrl_toplvl_reg_read(unit, port, primary, 0x0, &data) == SOC_E_NONE) {
   3438             if (( data & (0x8<<4) ) || (( data & (0x7<<4) ) != (offset<<4) )) {
   3439                 *value = FALSE;
   3440             } else {
   3441                 *value = TRUE;
   3442             }
   3443         }
   3444         break;
   3445 
   3446     case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT:
   3447         /* Not supported for 10/100/1000BASE-T interfaces */
   3448         rv = SOC_E_UNAVAIL;
   3449         break;
   3450 
   3451     default:
   3452         rv = SOC_E_UNAVAIL;
   3453         break;
   3454     }
   3455 
   3456     return rv;
   3457 }
   3458 
   3459 /*
   3460  * Function:
   3461  *      phy_54880_cable_diag
   3462  * Purpose:
   3463  *      Run 546x cable diagnostics
   3464  * Parameters:
   3465  *      unit - device number
   3466  *      port - port number
   3467  *      status - (OUT) cable diagnotic status structure
   3468  * Returns:
   3469  *      SOC_E_XXX
   3470  */
   3471 STATIC int
   3472 phy_54880_cable_diag(int unit, soc_port_t port,
   3473                     soc_port_cable_diag_t *status)
   3474 {
   3475     int                 rv, rv2, i;
   3476 
   3477     extern int phy_5464_cable_diag_sw(int, soc_port_t ,
   3478                                       soc_port_cable_diag_t *);
   3479 
   3480     if (status == NULL) {
   3481         return SOC_E_PARAM;
   3482     }
   3483 
   3484     status->state = SOC_PORT_CABLE_STATE_OK;
   3485     status->npairs = 4;
   3486     status->fuzz_len = 0;
   3487     for (i = 0; i < 4; i++) {
   3488         status->pair_state[i] = SOC_PORT_CABLE_STATE_OK;
   3489     }
   3490 
   3491     MIIM_LOCK(unit);    /* this locks out linkscan, essentially */
   3492     rv = phy_5464_cable_diag_sw(unit,port, status);
   3493     MIIM_UNLOCK(unit);
   3494     rv2 = 0;
   3495     if (rv <= 0) {      /* don't reset if > 0 -- link was up */
   3496         rv2 = _phy_54880_reset_setup(unit, port);
   3497     }
   3498     if (rv >= 0 && rv2 < 0) {
   3499         return rv2;
   3500     }
   3501     return rv;
   3502 }
   3503 
   3504 STATIC int
   3505 phy_54880_cable_diag_dispatch(int unit, soc_port_t port,
   3506             soc_port_cable_diag_t *status)
   3507 {
   3508     phy_ctrl_t *pc;
   3509 
   3510     pc = EXT_PHY_SW_STATE(unit, port);
   3511 
   3512     if ((PHY_IS_BCM54880(pc)) && ((pc->phy_rev & 0xf) > 0x1))  {
   3513         SOC_IF_ERROR_RETURN(
   3514             phy_ecd_cable_diag(unit, port, status));
   3515     } else {
   3516         SOC_IF_ERROR_RETURN(
   3517             phy_54880_cable_diag(unit, port, status));
   3518     }
   3519     SOC_IF_ERROR_RETURN(
   3520         _phy_54880_reset_setup(unit, port));
   3521 
   3522     return SOC_E_NONE;
   3523 }
   3524 
   3525 /*
   3526  * Variable:    phy_54880drv_ge
   3527  * Purpose:     PHY driver for 54880
   3528  */
   3529 
   3530 phy_driver_t phy_54880drv_ge = {
   3531     "54880 Gigabit PHY Driver",
   3532     phy_54880_init,
   3533     phy_fe_ge_reset,
   3534     phy_54880_link_get,
   3535     phy_54880_enable_set,
   3536     phy_54880_enable_get,
   3537     phy_54880_duplex_set,
   3538     phy_54880_duplex_get,
   3539     phy_54880_speed_set,
   3540     phy_54880_speed_get,
   3541     phy_54880_master_set,
   3542     phy_54880_master_get,
   3543     phy_54880_autoneg_set,
   3544     phy_54880_autoneg_get,
   3545     NULL,
   3546     NULL,
   3547     NULL,
   3548     phy_54880_lb_set,
   3549     phy_54880_lb_get,
   3550     phy_54880_interface_set,
   3551     phy_54880_interface_get,
   3552     NULL,                       /* Deprecated */
   3553     phy_54880_link_up,          /* Link up event */
   3554     phy_54880_link_down,        /* Link down event */
   3555     phy_54880_mdix_set,
   3556     phy_54880_mdix_get,
   3557     phy_54880_mdix_status_get,
   3558     phy_54880_medium_config_set,
   3559     phy_54880_medium_config_get,
   3560     phy_54880_medium_status,
   3561     phy_54880_cable_diag_dispatch,
   3562     NULL,                        /* phy_link_change */
   3563     phy_54880_control_set,       /* phy_control_set */ 
   3564     phy_54880_control_get,       /* phy_control_get */
   3565     phy_ge_reg_read,
   3566     phy_ge_reg_write,
   3567     phy_ge_reg_modify,
   3568     NULL,                        /* Phy notify event */    
   3569     NULL,                        /* pd_probe  */
   3570     phy_54880_ability_advert_set,/* pd_ability_advert_set */
   3571     phy_54880_ability_advert_get,/* pd_ability_advert_get */
   3572     phy_54880_ability_remote_get,/* pd_ability_remote_get */
   3573     phy_54880_ability_local_get  /* pd_ability_local_get  */
   3574 };
   3575 
   3576 #else /* INCLUDE_PHY_54880_ESW */
   3577 int _phy_54880_not_empty;
   3578 #endif /* INCLUDE_PHY_54880_ESW */
   3579