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

phyfege.c (53001B)


      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:    phy.c
      8  * Purpose: Defines PHY driver routines, and standard 802.3 10/100/1000
      9  *      PHY interface routines.
     10  */
     11 
     12 
     13 #include <sal/types.h>
     14 #include <sal/core/spl.h>
     15 #include <shared/bsl.h>
     16 #include <soc/drv.h>
     17 #include <soc/debug.h>
     18 #include <soc/error.h>
     19 #include <soc/phyreg.h>
     20 #include <soc/phy.h>
     21 
     22 #include <soc/phy.h>
     23 #include <soc/phy/phyctrl.h>
     24 #include <soc/phy/drv.h>
     25 
     26 #include "phyident.h"
     27 #include "phyreg.h"
     28 #include "phynull.h"
     29 #include "phyfege.h"
     30 
     31 #define BCM5400_LOOPBACK_WAR
     32 
     33 /* Variable:
     34  *  phy_drv_fe
     35  * Purpose:
     36  *  Phy driver callouts for a standard phy (IEEE 802.3)
     37  */
     38 
     39 phy_driver_t phy_drv_fe = {
     40     "Fast Ethernet PHY Driver",
     41     phy_fe_init, 
     42     phy_fe_ge_reset,
     43     phy_fe_ge_link_get, 
     44     phy_fe_ge_enable_set, 
     45     phy_fe_ge_enable_get, 
     46     phy_fe_ge_duplex_set, 
     47     phy_fe_ge_duplex_get, 
     48     phy_fe_ge_speed_set, 
     49     phy_fe_ge_speed_get, 
     50     phy_fe_ge_master_set, 
     51     phy_fe_ge_master_get, 
     52     phy_fe_ge_an_set, 
     53     phy_fe_ge_an_get, 
     54     phy_fe_adv_local_set,
     55     phy_fe_adv_local_get, 
     56     phy_fe_adv_remote_get,
     57     phy_fe_ge_lb_set,
     58     phy_fe_ge_lb_get,
     59     phy_fe_interface_set, 
     60     phy_fe_interface_get, 
     61     phy_fe_ability_get,
     62     NULL,
     63     NULL,
     64     phy_null_mdix_set,
     65     phy_null_mdix_get,
     66     phy_null_mdix_status_get,
     67     NULL,
     68     NULL,
     69     phy_fe_ge_medium_get,
     70     NULL,
     71     NULL
     72 };
     73 
     74 /*
     75  * Variable:
     76  *  phy_drv_ge
     77  * Purpose:
     78  *  Phy driver callouts for a Gigabit phy (IEEE 802.3)
     79  */
     80 
     81 phy_driver_t phy_drv_ge = {
     82     "Gigabit PHY Driver",
     83     phy_ge_init, 
     84     phy_fe_ge_reset,
     85     phy_fe_ge_link_get, 
     86     phy_fe_ge_enable_set, 
     87     phy_fe_ge_enable_get, 
     88     phy_fe_ge_duplex_set, 
     89     phy_fe_ge_duplex_get, 
     90     phy_fe_ge_speed_set, 
     91     phy_fe_ge_speed_get, 
     92     phy_fe_ge_master_set, 
     93     phy_fe_ge_master_get, 
     94     phy_fe_ge_an_set, 
     95     phy_fe_ge_an_get, 
     96     phy_ge_adv_local_set,
     97     phy_ge_adv_local_get, 
     98     phy_ge_adv_remote_get,
     99     phy_fe_ge_lb_set,
    100     phy_fe_ge_lb_get,
    101     phy_ge_interface_set, 
    102     phy_ge_interface_get, 
    103     phy_ge_ability_get,
    104     NULL,
    105     NULL,
    106     phy_null_mdix_set,
    107     phy_null_mdix_get,
    108     phy_null_mdix_status_get,
    109     NULL,
    110     NULL,
    111     phy_fe_ge_medium_get,
    112     NULL,                       /* phy_cable_diag */
    113     NULL                       /* phy_link_change */
    114 };
    115 
    116 /*
    117  * Function:    
    118  *  phy_fe_ge_reset
    119  * Purpose: 
    120  *  Reset PHY and wait for it to come out of reset.
    121  * Parameters:
    122  *  unit - StrataSwitch unit #.
    123  *  port - StrataSwitch port #. 
    124  * Returns: 
    125  *  SOC_E_XXX
    126  */
    127 
    128 int
    129 phy_fe_ge_reset(int unit, soc_port_t port, void *user_arg)
    130 {
    131     phy_ctrl_t          *pc;
    132     uint16      ctrl, tmp;
    133     soc_timeout_t   to;
    134     int         timeout = 0;
    135 
    136     COMPILER_REFERENCE(user_arg);
    137 
    138     pc = EXT_PHY_SW_STATE(unit, port);
    139     SOC_IF_ERROR_RETURN
    140         (READ_PHYFEGE_MII_CTRLr(unit, pc, &ctrl));
    141 
    142     SOC_IF_ERROR_RETURN
    143         (WRITE_PHYFEGE_MII_CTRLr(unit, pc, (ctrl | MII_CTRL_RESET)));
    144 
    145     soc_timeout_init(&to,
    146              soc_property_get(unit,
    147                       spn_PHY_RESET_TIMEOUT,
    148                       PHY_RESET_TIMEOUT_USEC), 1);
    149 
    150     do {
    151     SOC_IF_ERROR_RETURN
    152             (READ_PHYFEGE_MII_CTRLr(unit, pc, &tmp));
    153     if (soc_timeout_check(&to)) {
    154         timeout = 1;
    155         break;
    156     }
    157     } while ((tmp & MII_CTRL_RESET) != 0);
    158 
    159     if (timeout) {
    160         LOG_WARN(BSL_LS_SOC_PHY,
    161                  (BSL_META_U(unit,
    162                              "phy_fe_ge_reset: timeout on u=%d p=%d\n"),
    163                   unit, port));
    164     SOC_IF_ERROR_RETURN
    165             (WRITE_PHYFEGE_MII_CTRLr(unit, pc, ctrl));
    166     }
    167 
    168     return (SOC_E_NONE);
    169 }
    170 
    171 /*
    172  * Function:    
    173  *  phy_fe_ge_enable_set
    174  * Purpose: 
    175  *  Enable or disable the physical interface.
    176  * Parameters:
    177  *  unit - StrataSwitch unit #.
    178  *  port - StrataSwitch port #. 
    179  *  enable - Boolean, true = enable PHY, false = disable.
    180  * Returns: 
    181  *  SOC_E_XXX
    182  * Notes:
    183  *  There does not seem to be a way to truly disable the external
    184  *  link on standard PHYs.  Isolate mode disables the MII side but
    185  *  not the wire side.  Super-isolate mode disables the MII and
    186  *  link pulses; however disabling MII causes duplex-switch hangs.
    187  *
    188  *  This code uses a PHY flag to keep track of enable state.
    189  *  This is important because linkscan copies the PHY enable state
    190  *  to the MAC enable state.
    191  */
    192 
    193 int
    194 phy_fe_ge_enable_set(int unit, soc_port_t port, int enable)
    195 {
    196     if (enable) {
    197         PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE);
    198     } else {
    199         PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE);
    200     }
    201 
    202     return (SOC_E_NONE);
    203 }
    204 
    205 /*
    206  * Function:    
    207  *  phy_fe_ge_enable_get
    208  * Purpose: 
    209  *  Return physical interface enable/disable state.
    210  * Parameters:
    211  *  unit - StrataSwitch unit #.
    212  *  port - StrataSwitch port #. 
    213  *  enable - (OUT) Boolean, true = enable PHY, false = disable.
    214  * Returns: 
    215  *  SOC_E_XXX
    216  */
    217 
    218 int
    219 phy_fe_ge_enable_get(int unit, soc_port_t port, int *enable)
    220 {
    221     *enable = !PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE);
    222     return(SOC_E_NONE);
    223 }
    224 
    225 /*
    226  * Function:    
    227  *  phy_fe_init
    228  * Purpose: 
    229  *  Initialize the PHY to a known good state.
    230  * Parameters:
    231  *  unit - StrataSwitch unit #.
    232  *  port - StrataSwitch port #. 
    233  * Returns: 
    234  *  SOC_E_XXX
    235  * Notes: 
    236  *  No synchronization performed at this level. By default, phy set
    237  *  in autonegotiation mode, with maximum abilities advertised.
    238  */
    239 
    240 int
    241 phy_fe_init(int unit, soc_port_t port)
    242 {
    243     uint16  mii_ana, mii_ctrl;
    244     phy_ctrl_t  *pc;
    245 
    246     /* Reset PHY */
    247     SOC_IF_ERROR_RETURN(soc_phy_reset(unit, port));
    248 
    249     pc = EXT_PHY_SW_STATE(unit, port);
    250 
    251     mii_ana = MII_ANA_HD_10 | MII_ANA_FD_10 | MII_ANA_HD_100 | 
    252           MII_ANA_FD_100 | MII_ANA_ASF_802_3;
    253     mii_ctrl = MII_CTRL_FD | MII_CTRL_SS_100 | MII_CTRL_AE | MII_CTRL_RAN;
    254 
    255     SOC_IF_ERROR_RETURN
    256         (WRITE_PHYFEGE_MII_CTRLr(unit, pc, mii_ctrl));
    257     SOC_IF_ERROR_RETURN
    258         (WRITE_PHYFEGE_MII_ANAr(unit, pc, mii_ana));
    259 
    260 
    261     return(SOC_E_NONE);
    262 }
    263 
    264 /*
    265  * Function:    
    266  *  phy_ge_init
    267  * Purpose: 
    268  *  Initialize the PHY (MII mode) to a known good state.
    269  * Parameters:
    270  *  unit - StrataSwitch unit #.
    271  *  port - StrataSwitch port #. 
    272  * Returns: 
    273  *  SOC_E_XXX
    274 
    275  * Notes: 
    276  *  No synchronization performed at this level.
    277  */
    278 
    279 int
    280 phy_ge_init(int unit, soc_port_t port)
    281 {
    282     uint16      mii_ctrl, mii_gb_ctrl;
    283     soc_port_if_t   pif;
    284     phy_ctrl_t          *pc;
    285 
    286     /* Reset PHY */
    287     SOC_IF_ERROR_RETURN(soc_phy_reset(unit, port));
    288 
    289     pc = EXT_PHY_SW_STATE(unit, port);
    290 
    291     mii_ctrl = MII_CTRL_FD | MII_CTRL_SS_1000 | MII_CTRL_AE | MII_CTRL_RAN;
    292     mii_gb_ctrl = MII_GB_CTRL_ADV_1000FD | MII_GB_CTRL_PT;
    293 
    294     if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_10B)) {
    295         pif = SOC_PORT_IF_TBI;
    296     } else {
    297         pif = SOC_PORT_IF_GMII;
    298     }
    299 
    300     SOC_IF_ERROR_RETURN(phy_ge_interface_set(unit, port, pif));
    301 
    302     SOC_IF_ERROR_RETURN
    303         (WRITE_PHYFEGE_MII_GB_CTRLr(unit, pc, mii_gb_ctrl));
    304     SOC_IF_ERROR_RETURN
    305         (WRITE_PHYFEGE_MII_CTRLr(unit, pc, mii_ctrl));
    306 
    307 #if defined(INCLUDE_PHY_54XX) && defined(BCM5400_LOOPBACK_WAR)
    308     /* Workaround for loop back w/5400; use a pseudo-random value */
    309     if (PHY_IS_BCM5400(pc)) {
    310         uint16 seed = (uint16) (sal_time_usecs() + port) & MII_MSSEED_SEED;
    311 
    312         /* Set up test reg/seed reg for external loopback */
    313         SOC_IF_ERROR_RETURN
    314             (WRITE_PHYFEGE_MII_TEST2r(unit, pc, MII_TEST2_MS_SEL));
    315         SOC_IF_ERROR_RETURN
    316             (WRITE_PHYFEGE_MII_MSSEEDr(unit, pc, seed));
    317     }
    318 #endif
    319 
    320     return(SOC_E_NONE);
    321 }
    322 
    323 /*
    324  * Function:    
    325  *  phy_fe_ge_link_get
    326  * Purpose: 
    327  *  Determine the current link up/down status
    328  * Parameters:
    329  *  unit - StrataSwitch unit #.
    330  *  port - StrataSwitch port #. 
    331  *  link - (OUT) Boolean, true indicates link established.
    332  * Returns:
    333  *  SOC_E_XXX
    334  * Notes: 
    335  *  No synchronization performed at this level.
    336  */
    337 
    338 int
    339 phy_fe_ge_link_get(int unit, soc_port_t port, int *link)
    340 {
    341     uint16      mii_ctrl, mii_stat;
    342     soc_timeout_t   to;
    343     phy_ctrl_t          *pc;
    344 
    345     *link = FALSE;      /* Default */
    346     if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) {
    347         return SOC_E_NONE;
    348     }
    349    
    350     pc = EXT_PHY_SW_STATE(unit, port);
    351     SOC_IF_ERROR_RETURN
    352         (READ_PHYFEGE_MII_STATr(unit, pc, &mii_stat));
    353 
    354     if (!(mii_stat & MII_STAT_LA) || (mii_stat == 0xffff)) {
    355     /* mii_stat == 0xffff check is to handle removable PHY daughter cards */
    356         return SOC_E_NONE;
    357     }
    358 
    359     /* Link appears to be up; we are done if autoneg is off. */
    360 
    361     SOC_IF_ERROR_RETURN
    362         (READ_PHYFEGE_MII_CTRLr(unit, pc, &mii_ctrl));
    363 
    364     if (!(mii_ctrl & MII_CTRL_AE)) {
    365     *link = TRUE;
    366     return SOC_E_NONE;
    367     }
    368 
    369     /*
    370      * If link appears to be up but autonegotiation is still in
    371      * progress, wait for it to complete.  For BCM5228, autoneg can
    372      * still be busy up to about 200 usec after link is indicated.  Also
    373      * continue to check link state in case it goes back down.
    374      */
    375     soc_timeout_init(&to, SOC_PHY_INFO(unit, port).an_timeout, 0);
    376     for (;;) {
    377     SOC_IF_ERROR_RETURN
    378             (READ_PHYFEGE_MII_STATr(unit, pc, &mii_stat));
    379 
    380     if (!(mii_stat & MII_STAT_LA)) {
    381         return SOC_E_NONE;
    382     }
    383 
    384     if (mii_stat & MII_STAT_AN_DONE) {
    385         break;
    386     }
    387 
    388     if (soc_timeout_check(&to)) {
    389         return SOC_E_BUSY;
    390     }
    391     }
    392 
    393     /* Return link state at end of polling */
    394 
    395     *link = ((mii_stat & MII_STAT_LA) != 0);
    396 
    397     return SOC_E_NONE;
    398 }
    399 
    400 /*
    401  * Function:     
    402  *    _phy_auto_negotiate_gcd (greatest common denominator).
    403  * Purpose:    
    404  *    Determine the current greatest common denominator between 
    405  *    two ends of a link
    406  * Parameters:
    407  *    unit - StrataSwitch unit #.
    408  *    port - StrataSwitch port #. 
    409  *    speed - (OUT) greatest common speed.
    410  *    duplex - (OUT) greatest common duplex.
    411  *    link - (OUT) Boolean, true indicates link established.
    412  * Returns:    
    413  *    SOC_E_XXX
    414  * Notes: 
    415  *    No synchronization performed at this level.
    416  */
    417 
    418 static int
    419 _phy_auto_negotiate_gcd(int unit, soc_port_t port, int *speed, int *duplex)
    420 {
    421     int        t_speed, t_duplex;
    422     uint16     mii_ana, mii_anp, mii_stat;
    423     uint16     mii_gb_stat, mii_esr, mii_gb_ctrl;
    424     phy_ctrl_t *pc;
    425 
    426     mii_gb_stat = 0;            /* Start off 0 */
    427     mii_gb_ctrl = 0;            /* Start off 0 */
    428 
    429     pc = EXT_PHY_SW_STATE(unit, port);
    430     SOC_IF_ERROR_RETURN
    431         (READ_PHYFEGE_MII_ANAr(unit, pc, &mii_ana));
    432     SOC_IF_ERROR_RETURN
    433         (READ_PHYFEGE_MII_ANPr(unit, pc, &mii_anp));
    434     SOC_IF_ERROR_RETURN
    435         (READ_PHYFEGE_MII_STATr(unit, pc, &mii_stat));
    436 
    437     if (mii_stat & MII_STAT_ES) {    /* Supports extended status */
    438         /*
    439          * If the PHY supports extended status, check if it is 1000MB
    440          * capable.  If it is, check the 1000Base status register to see
    441          * if 1000MB negotiated.
    442          */
    443         SOC_IF_ERROR_RETURN
    444             (READ_PHYFEGE_MII_ESRr(unit, pc, &mii_esr));
    445 
    446         if (mii_esr & (MII_ESR_1000_X_FD | MII_ESR_1000_X_HD | 
    447                        MII_ESR_1000_T_FD | MII_ESR_1000_T_HD)) {
    448             SOC_IF_ERROR_RETURN
    449                 (READ_PHYFEGE_MII_GB_STATr(unit, pc, &mii_gb_stat));
    450             SOC_IF_ERROR_RETURN
    451                 (READ_PHYFEGE_MII_GB_CTRLr(unit, pc, &mii_gb_ctrl));
    452         }
    453     }
    454 
    455     /*
    456      * At this point, if we did not see Gig status, one of mii_gb_stat or 
    457      * mii_gb_ctrl will be 0. This will cause the first 2 cases below to 
    458      * fail and fall into the default 10/100 cases.
    459      */
    460 
    461     mii_ana &= mii_anp;
    462 
    463     if ((mii_gb_ctrl & MII_GB_CTRL_ADV_1000FD) &&
    464         (mii_gb_stat & MII_GB_STAT_LP_1000FD)) {
    465         t_speed  = 1000;
    466         t_duplex = 1;
    467     } else if ((mii_gb_ctrl & MII_GB_CTRL_ADV_1000HD) &&
    468                (mii_gb_stat & MII_GB_STAT_LP_1000HD)) {
    469         t_speed  = 1000;
    470         t_duplex = 0;
    471     } else if (mii_ana & MII_ANA_FD_100) {         /* [a] */
    472         t_speed = 100;
    473         t_duplex = 1;
    474     } else if (mii_ana & MII_ANA_T4) {            /* [b] */
    475         t_speed = 100;
    476         t_duplex = 0;
    477     } else if (mii_ana & MII_ANA_HD_100) {        /* [c] */
    478         t_speed = 100;
    479         t_duplex = 0;
    480     } else if (mii_ana & MII_ANA_FD_10) {        /* [d] */
    481         t_speed = 10;
    482         t_duplex = 1 ;
    483     } else if (mii_ana & MII_ANA_HD_10) {        /* [e] */
    484         t_speed = 10;
    485         t_duplex = 0;
    486     } else {
    487         return(SOC_E_FAIL);
    488     }
    489 
    490     if (speed)  *speed  = t_speed;
    491     if (duplex)    *duplex = t_duplex;
    492 
    493     return(SOC_E_NONE);
    494 }
    495 
    496 /*
    497  * Function:     
    498  *    _phy_auto_negotiate_ew (Autoneg-ed mode with E@W on).
    499  * Purpose:    
    500  *    Determine autoneg-ed mode between
    501  *    two ends of a link
    502  * Parameters:
    503  *    unit - StrataSwitch unit #.
    504  *    port - StrataSwitch port #. 
    505  *    speed - (OUT) greatest common speed.
    506  *    duplex - (OUT) greatest common duplex.
    507  *    link - (OUT) Boolean, true indicates link established.
    508  * Returns:    
    509  *    SOC_E_XXX
    510  * Notes: 
    511  *    No synchronization performed at this level.
    512  */
    513 
    514 static int
    515 _phy_auto_negotiate_ew(int unit, soc_port_t port, int *speed, int *duplex)
    516 {
    517     int        t_speed, t_duplex;
    518     uint16     mii_assr;
    519     phy_ctrl_t *pc;
    520 
    521     pc = EXT_PHY_SW_STATE(unit, port);
    522 
    523     SOC_IF_ERROR_RETURN
    524         (READ_PHYFEGE_MII_ASSRr(unit, pc, &mii_assr));
    525 
    526     switch ((mii_assr >> 8) & 0x7) {
    527     case 0x7:
    528         t_speed = 1000;
    529         t_duplex = TRUE;
    530         break;
    531     case 0x6:
    532         t_speed = 1000;
    533         t_duplex = FALSE;
    534         break;
    535     case 0x5:
    536         t_speed = 100;
    537         t_duplex = TRUE;
    538         break;
    539     case 0x3:
    540         t_speed = 100;
    541         t_duplex = FALSE;
    542         break;
    543     case 0x2:
    544         t_speed = 10;
    545         t_duplex = TRUE;
    546         break;
    547     case 0x1:
    548         t_speed = 10;
    549         t_duplex = FALSE;
    550         break;
    551     default:
    552         t_speed = 0; /* 0x4 is 100BASE-T4 which is not supported */
    553         t_duplex = FALSE;
    554         break;
    555     }
    556 
    557     if (speed)  *speed  = t_speed;
    558     if (duplex)    *duplex = t_duplex;
    559 
    560     return(SOC_E_NONE);
    561 }
    562 
    563 /*
    564  * Function:    
    565  *  phy_fe_ge_duplex_set
    566  * Purpose: 
    567  *  Set the current duplex mode (forced).
    568  * Parameters:
    569  *  unit - StrataSwitch unit #.
    570  *  port - StrataSwitch port #. 
    571  *  duplex - Boolean, true indicates full duplex, false indicates half.
    572  * Returns: 
    573  *  SOC_E_XXX
    574  * Notes: 
    575  *  No synchronization performed at this level. Autonegotiation is 
    576  *  not manipulated. 
    577  */
    578 
    579 int
    580 phy_fe_ge_duplex_set(int unit, soc_port_t port, int duplex)
    581 {
    582     uint16  mii_ctrl;
    583     phy_ctrl_t  *pc;
    584 
    585     pc = EXT_PHY_SW_STATE(unit, port);
    586     SOC_IF_ERROR_RETURN
    587         (READ_PHYFEGE_MII_CTRLr(unit, pc, &mii_ctrl));
    588 
    589     if (duplex) {
    590     mii_ctrl |= MII_CTRL_FD;
    591     } else {
    592     mii_ctrl &= ~MII_CTRL_FD;
    593     }
    594 
    595     SOC_IF_ERROR_RETURN
    596         (WRITE_PHYFEGE_MII_CTRLr(unit, pc, mii_ctrl));
    597 
    598     return(SOC_E_NONE);
    599 }
    600 
    601 /*
    602  * Function:    
    603  *  phy_fe_ge_duplex_get
    604  * Purpose: 
    605  *  Get the current operating duplex mode. If autoneg is enabled, 
    606  *  then operating mode is returned, otherwise forced mode is returned.
    607  * Parameters:
    608  *  unit - StrataSwitch unit #.
    609  *  port - StrataSwitch port #. 
    610  *  duplex - (OUT) Boolean, TRUE indicates full duplex, FALSE 
    611  *      indicates half.
    612  * Returns: 
    613  *  SOC_E_XXX
    614  * Notes: 
    615  *  Returns a duplex of FALSE if autonegotiation is not complete.
    616  *  No synchronization performed at this level. Autonegotiation is 
    617  *  not manipulated. 
    618  */
    619 
    620 int
    621 phy_fe_ge_duplex_get(int unit, soc_port_t port, int *duplex)
    622 {
    623     int     rv;
    624     uint16  mii_ctrl, mii_stat;
    625     phy_ctrl_t  *pc;
    626 
    627     pc = EXT_PHY_SW_STATE(unit, port);
    628 
    629     SOC_IF_ERROR_RETURN
    630         (READ_PHYFEGE_MII_CTRLr(unit, pc, &mii_ctrl));
    631     SOC_IF_ERROR_RETURN
    632         (READ_PHYFEGE_MII_STATr(unit, pc, &mii_stat));
    633 
    634     rv = SOC_E_NONE;
    635     if (mii_ctrl & MII_CTRL_AE) {     /* Auto-negotiation enabled */
    636         if (!(mii_stat & MII_STAT_AN_DONE)) { /* Auto-neg NOT complete */
    637             *duplex = FALSE;
    638         } else 
    639         if (IS_GE_PORT(unit, port)) {
    640             uint16 misc_ctrl;
    641             SOC_IF_ERROR_RETURN
    642                 (phy_reg_ge_read(unit, pc, 0x00, 0x0007, 0x18, &misc_ctrl));
    643             /* First check for Ethernet@Wirespeed */
    644             if (misc_ctrl & (1U << 4)) {   /* Ethernet@Wirespeed enabled */
    645                 rv = _phy_auto_negotiate_ew(unit, port, NULL, duplex);
    646             } else {
    647                 rv = _phy_auto_negotiate_gcd(unit, port, NULL, duplex);
    648             }
    649         } else {
    650             rv = _phy_auto_negotiate_gcd(unit, port, NULL, duplex);
    651         }
    652     } else {                /* Auto-negotiation disabled */
    653         *duplex = (mii_ctrl & MII_CTRL_FD) ? TRUE : FALSE;
    654     }
    655 
    656     return(rv);
    657 }
    658 
    659 /*
    660  * Function:    
    661  *  phy_fe_ge_speed_set
    662  * Purpose: 
    663  *  Set the current operating speed (forced).
    664  * Parameters:
    665  *  unit - StrataSwitch unit #.
    666  *  port - StrataSwitch port #. 
    667  *  duplex - (OUT) Boolean, true indicates full duplex, false 
    668  *      indicates half.
    669  * Returns: 
    670  *  SOC_E_XXX
    671  * Notes: 
    672  *  No synchronization performed at this level. Autonegotiation is 
    673  *  not manipulated. 
    674  */
    675 
    676 int
    677 phy_fe_ge_speed_set(int unit, soc_port_t port, int speed)
    678 {
    679     uint16  mii_ctrl;
    680     phy_ctrl_t  *pc;
    681     soc_pbmp_t pbmp_100fx;
    682 
    683     if (speed == 0) {
    684         return SOC_E_NONE;
    685     }
    686 
    687     /*
    688       * Get 100-FX ports from config.bcm.
    689       */
    690     pbmp_100fx = soc_property_get_pbmp(unit, spn_PBMP_FE_100FX, 0);
    691     if (SOC_PBMP_MEMBER(pbmp_100fx, port) && (speed != 100)) {
    692         return SOC_E_CONFIG;
    693     }
    694     
    695     pc = EXT_PHY_SW_STATE(unit, port);
    696 
    697     SOC_IF_ERROR_RETURN
    698         (READ_PHYFEGE_MII_CTRLr(unit, pc, &mii_ctrl));
    699 
    700     mii_ctrl &= ~(MII_CTRL_SS_LSB | MII_CTRL_SS_MSB);
    701     switch(speed) {
    702     case 10:
    703     mii_ctrl |= MII_CTRL_SS_10;
    704     break;
    705     case 100:
    706     mii_ctrl |= MII_CTRL_SS_100;
    707     break;
    708     case 1000:  
    709     mii_ctrl |= MII_CTRL_SS_1000;
    710     break;
    711     default:
    712     return(SOC_E_CONFIG);
    713     }
    714 
    715     SOC_IF_ERROR_RETURN
    716         (WRITE_PHYFEGE_MII_CTRLr(unit, pc, mii_ctrl));
    717 
    718     return(SOC_E_NONE);
    719 }
    720 
    721 /*
    722  * Function:    
    723  *  phy_fe_ge_speed_get
    724  * Purpose: 
    725  *  Get the current operating speed. If autoneg is enabled, 
    726  *  then operating mode is returned, otherwise forced mode is returned.
    727  * Parameters:
    728  *  unit - StrataSwitch unit #.
    729  *  port - StrataSwitch port #. 
    730  *  duplex - (OUT) Boolean, true indicates full duplex, false 
    731  *      indicates half.
    732  * Returns: 
    733  *  SOC_E_XXX
    734  * Notes: 
    735  *  Returns a speed of 0 if autonegotiation is not complete.
    736  *  No synchronization performed at this level. Autonegotiation is 
    737  *  not manipulated. 
    738  */
    739 
    740 int
    741 phy_fe_ge_speed_get(int unit, soc_port_t port, int *speed)
    742 {
    743     int     rv;
    744     uint16  mii_ctrl, mii_stat;
    745     phy_ctrl_t  *pc;
    746 
    747     pc = EXT_PHY_SW_STATE(unit, port);
    748 
    749     SOC_IF_ERROR_RETURN
    750         (READ_PHYFEGE_MII_CTRLr(unit, pc, &mii_ctrl));
    751     SOC_IF_ERROR_RETURN
    752         (READ_PHYFEGE_MII_STATr(unit, pc, &mii_stat));
    753 
    754     if (mii_ctrl & MII_CTRL_AE) {   /* Auto-negotiation enabled */
    755         if (!(mii_stat & MII_STAT_AN_DONE)) { /* Auto-neg NOT complete */
    756             *speed = 0;
    757             rv = SOC_E_NONE;
    758         } else
    759         if (IS_GE_PORT(unit, port)) {
    760             uint16 misc_ctrl;
    761             SOC_IF_ERROR_RETURN
    762                 (phy_reg_ge_read(unit, pc, 0x00, 0x0007, 0x18, &misc_ctrl));
    763             /* First check for Ethernet@Wirespeed */
    764             if (misc_ctrl & (1U << 4)) {   /* Ethernet@Wirespeed enabled */
    765                 rv = _phy_auto_negotiate_ew(unit, port, speed, NULL);
    766             } else {
    767                 rv = _phy_auto_negotiate_gcd(unit, port, speed, NULL);
    768             }
    769         } else {
    770             rv = _phy_auto_negotiate_gcd(unit, port, speed, NULL);
    771         }
    772     } else {                /* Auto-negotiation disabled */
    773     /*
    774      * Simply pick up the values we force in CTRL register.
    775      */
    776     switch(MII_CTRL_SS(mii_ctrl)) {
    777     case MII_CTRL_SS_10:
    778         *speed = 10;
    779         break;
    780     case MII_CTRL_SS_100:
    781         *speed = 100;
    782         break;
    783     case MII_CTRL_SS_1000:
    784         *speed = 1000;
    785         break;
    786     default:            /* Just pass error back */
    787         return(SOC_E_UNAVAIL);
    788     }
    789     rv = SOC_E_NONE;
    790     }
    791 
    792     return(rv);
    793 }
    794 
    795 /*
    796  * Function:    
    797  *  phy_fe_ge_master_get
    798  * Purpose: 
    799  *  Get the master mode for the PHY.  If mode is forced, then
    800  *  forced mode is returned; otherwise operating mode is returned.
    801  * Parameters:
    802  *  unit - StrataSwitch unit #.
    803  *  port - StrataSwitch port #. 
    804  *  master - (OUT) SOC_PORT_MS_*
    805  * Returns: 
    806  *  SOC_E_XXX
    807  * Notes: 
    808  *  No synchronization performed at this level. Autonegotiation is 
    809  *  not manipulated. 
    810  */
    811 
    812 int
    813 phy_fe_ge_master_get(int unit, soc_port_t port, int *master)
    814 {
    815     int an = 0, an_done = 0, speed = 0;
    816     uint16  mii_gb_ctrl, mii_gb_stat;
    817     phy_ctrl_t  *pc;
    818 
    819     pc = EXT_PHY_SW_STATE(unit, port);
    820 
    821     if (IS_FE_PORT(unit, port)) {
    822         *master = SOC_PORT_MS_NONE;
    823     } else {
    824         SOC_IF_ERROR_RETURN
    825             (READ_PHYFEGE_MII_GB_CTRLr(unit, pc, &mii_gb_ctrl));
    826 
    827         if (!(mii_gb_ctrl & MII_GB_CTRL_MS_MAN)) {
    828              *master = SOC_PORT_MS_AUTO;
    829             return SOC_E_NONE;
    830         }
    831 
    832 
    833         SOC_IF_ERROR_RETURN
    834             (phy_fe_ge_an_get(unit, port, &an, &an_done));
    835 
    836         SOC_IF_ERROR_RETURN
    837             (phy_fe_ge_speed_get(unit, port, &speed));
    838 
    839         /* 
    840          * Master/Slave Status check can be skipped if :
    841          *     - autoneg is off
    842          * or  - speed not 1000Mbps
    843          *
    844          * Here we just return the Manually configured result
    845          */
    846         if (!an || speed != 1000) {
    847             if (mii_gb_ctrl & MII_GB_CTRL_MS) {
    848                 *master = SOC_PORT_MS_MASTER;
    849             } else {
    850                 *master = SOC_PORT_MS_SLAVE;
    851             }
    852             return SOC_E_NONE;
    853         }
    854 
    855         /* Status check needed for 1000Mbps with autoneg */
    856         SOC_IF_ERROR_RETURN
    857             (READ_PHYFEGE_MII_GB_STATr(unit, pc, &mii_gb_stat));
    858 
    859         if (mii_gb_stat & MII_GB_STAT_MS_FAULT) {
    860             *master = SOC_PORT_MS_NONE;
    861         } else if (mii_gb_stat & MII_GB_STAT_MS) {
    862             *master = SOC_PORT_MS_MASTER;
    863         } else {
    864             *master = SOC_PORT_MS_SLAVE;
    865         }
    866     }
    867 
    868     return(SOC_E_NONE);
    869 }
    870 
    871 /*
    872  * Function:    
    873  *  phy_fe_ge_master_set
    874  * Purpose: 
    875  *  Set the master mode for the PHY.
    876  * Parameters:
    877  *  unit - StrataSwitch unit #.
    878  *  port - StrataSwitch port #. 
    879  *  master - SOC_PORT_MS_*
    880  * Returns: 
    881  *  SOC_E_XXX
    882  * Notes: 
    883  *  No synchronization performed at this level. Autonegotiation is 
    884  *  not manipulated. 
    885  */
    886 
    887 int
    888 phy_fe_ge_master_set(int unit, soc_port_t port, int master)
    889 {
    890     uint16  mii_gb_ctrl;
    891     phy_ctrl_t  *pc;
    892 
    893     if (IS_FE_PORT(unit, port)) {
    894     return(SOC_E_NONE);
    895     }
    896 
    897     pc = EXT_PHY_SW_STATE(unit, port);
    898 
    899     SOC_IF_ERROR_RETURN
    900         (READ_PHYFEGE_MII_GB_CTRLr(unit, pc, &mii_gb_ctrl));
    901 
    902     switch (master) {
    903     case SOC_PORT_MS_SLAVE:
    904     mii_gb_ctrl |= MII_GB_CTRL_MS_MAN;
    905     mii_gb_ctrl &= ~MII_GB_CTRL_MS;
    906     break;
    907     case SOC_PORT_MS_MASTER:
    908     mii_gb_ctrl |= MII_GB_CTRL_MS_MAN;
    909     mii_gb_ctrl |= MII_GB_CTRL_MS;
    910     break;
    911     case SOC_PORT_MS_AUTO:
    912     mii_gb_ctrl &= ~MII_GB_CTRL_MS_MAN;
    913     break;
    914     }
    915 
    916     SOC_IF_ERROR_RETURN
    917         (WRITE_PHYFEGE_MII_GB_CTRLr(unit, pc, mii_gb_ctrl));
    918 
    919     return(SOC_E_NONE);
    920 }
    921 
    922 /*
    923  * Function:    
    924  *  phy_fe_ge_an_set
    925  * Purpose: 
    926  *  Enable or disabled auto-negotiation on the specified port.
    927  * Parameters:
    928  *  unit - StrataSwitch unit #.
    929  *  port - StrataSwitch port #. 
    930  *  an   - Boolean, if true, auto-negotiation is enabled 
    931  *      (and/or restarted). If false, autonegotiation is disabled.
    932  * Returns: 
    933  *  SOC_E_XXX
    934  */
    935 
    936 int
    937 phy_fe_ge_an_set(int unit, soc_port_t port, int an)
    938 {
    939     uint16  mii_ctrl;
    940     phy_ctrl_t  *pc;
    941 
    942     pc = EXT_PHY_SW_STATE(unit, port);
    943     SOC_IF_ERROR_RETURN
    944         (READ_PHYFEGE_MII_CTRLr(unit, pc, &mii_ctrl));
    945 
    946     if (an) {
    947     mii_ctrl |= MII_CTRL_AE | MII_CTRL_RAN;
    948     } else {
    949     mii_ctrl &= ~(MII_CTRL_AE | MII_CTRL_RAN);
    950     }
    951 
    952     SOC_IF_ERROR_RETURN
    953         (WRITE_PHYFEGE_MII_CTRLr(unit, pc, mii_ctrl));
    954 
    955     return(SOC_E_NONE);
    956 }
    957 
    958 /*
    959  * Function:    
    960  *  phy_fe_ge_an_get
    961  * Purpose: 
    962  *  Get the current auto-negotiation status (enabled/busy)
    963  * Parameters:
    964  *  unit - StrataSwitch unit #.
    965  *  port - StrataSwitch port #. 
    966  *  an   - (OUT) if true, auto-negotiation is enabled.
    967  *  an_done - (OUT) if true, auto-negotiation is complete. This
    968  *          value is undefined if an == false.
    969  * Returns: 
    970  *  SOC_E_XXX
    971  */
    972 
    973 int
    974 phy_fe_ge_an_get(int unit, soc_port_t port, int *an, int *an_done)
    975 {
    976     uint16  mii_ctrl, mii_stat;
    977     phy_ctrl_t  *pc;
    978 
    979     pc = EXT_PHY_SW_STATE(unit, port);
    980 
    981     SOC_IF_ERROR_RETURN
    982         (READ_PHYFEGE_MII_CTRLr(unit, pc, &mii_ctrl));
    983     SOC_IF_ERROR_RETURN
    984         (READ_PHYFEGE_MII_STATr(unit, pc, &mii_stat));
    985 
    986     *an = (mii_ctrl & MII_CTRL_AE) ? TRUE : FALSE;
    987     *an_done = (mii_stat & MII_STAT_AN_DONE) ? TRUE : FALSE;
    988 
    989     return(SOC_E_NONE);
    990 }
    991 
    992 /*
    993  * Function:    
    994  *  phy_fe_adv_local_set
    995  * Purpose: 
    996  *  Set the current advertisement for auto-negotiation.
    997  * Parameters:
    998  *  unit - StrataSwitch unit #.
    999  *  port - StrataSwitch port #. 
   1000  *  mode - Port mode mask indicating supported options/speeds.
   1001  * Returns: 
   1002  *  SOC_E_XXX
   1003  */
   1004 
   1005 int 
   1006 phy_fe_adv_local_set(int unit, soc_port_t port, soc_port_mode_t mode)
   1007 {
   1008     uint16  mii_adv, mii_ctrl;
   1009     phy_ctrl_t  *pc;
   1010 
   1011     pc = EXT_PHY_SW_STATE(unit, port);
   1012 
   1013     mii_adv = MII_ANA_ASF_802_3;
   1014 
   1015     if (mode & SOC_PM_10MB_HD)  mii_adv |= MII_ANA_HD_10;
   1016     if (mode & SOC_PM_10MB_FD)  mii_adv |= MII_ANA_FD_10;
   1017     if (mode & SOC_PM_100MB_HD) mii_adv |= MII_ANA_HD_100;
   1018     if (mode & SOC_PM_100MB_FD) mii_adv |= MII_ANA_FD_100;
   1019 
   1020     switch(mode & SOC_PM_PAUSE) {
   1021     case 0:
   1022     break;
   1023     case SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX:
   1024     mii_adv |= MII_ANA_PAUSE;
   1025     break;
   1026     default:
   1027     return(SOC_E_UNAVAIL);          /* Parameter error */
   1028     }
   1029 
   1030     SOC_IF_ERROR_RETURN
   1031         (WRITE_PHYFEGE_MII_ANAr(unit, pc, mii_adv));
   1032 
   1033     /* Restart auto-neg if enabled */
   1034 
   1035     SOC_IF_ERROR_RETURN
   1036         (READ_PHYFEGE_MII_CTRLr(unit, pc, &mii_ctrl));
   1037 
   1038     if (mii_ctrl & MII_CTRL_AE) {
   1039     SOC_IF_ERROR_RETURN
   1040             (WRITE_PHYFEGE_MII_CTRLr(unit, pc, mii_ctrl | MII_CTRL_RAN));
   1041     }
   1042 
   1043     return(SOC_E_NONE);
   1044 }
   1045 
   1046 /*
   1047  * Function:    
   1048  *  phy_fe_adv_local_get
   1049  * Purpose: 
   1050  *  Get the current advertisement for auto-negotiation.
   1051  * Parameters:
   1052  *  unit - StrataSwitch unit #.
   1053  *  port - StrataSwitch port #. 
   1054  *  mode - (OUT) Port mode mask indicating supported options/speeds.
   1055  * Returns: 
   1056  *  SOC_E_XXX
   1057  */
   1058 
   1059 int
   1060 phy_fe_adv_local_get(int unit, soc_port_t port, soc_port_mode_t *mode)
   1061 {
   1062     uint16  mii_ana;
   1063     phy_ctrl_t  *pc;
   1064 
   1065     pc = EXT_PHY_SW_STATE(unit, port);
   1066 
   1067     *mode = 0;
   1068 
   1069     SOC_IF_ERROR_RETURN
   1070         (READ_PHYFEGE_MII_ANAr(unit, pc, &mii_ana));
   1071 
   1072     if (mii_ana & MII_ANA_HD_10)    *mode |= SOC_PM_10MB_HD;
   1073     if (mii_ana & MII_ANA_FD_10)    *mode |= SOC_PM_10MB_FD;
   1074     if (mii_ana & MII_ANA_HD_100)   *mode |= SOC_PM_100MB_HD;
   1075     if (mii_ana & MII_ANA_FD_100)   *mode |= SOC_PM_100MB_FD;
   1076     if (mii_ana & MII_ANA_PAUSE)    *mode |= SOC_PM_PAUSE;
   1077 
   1078     return(SOC_E_NONE);
   1079 }
   1080 
   1081 /*
   1082  * Function:    
   1083  *  phy_fe_adv_remote_get
   1084  * Purpose: 
   1085  *  Get link partner's current advertisement for auto-negotiation.
   1086  * Parameters:
   1087  *  unit - StrataSwitch unit #.
   1088  *  port - StrataSwitch port #. 
   1089  *  mode - (OUT) Port mode mask indicating supported options/speeds.
   1090  * Returns:
   1091  *  SOC_E_XXX
   1092  * Notes:
   1093  *  Returns an empty mask if autonegotiation is not complete.
   1094  */
   1095 
   1096 int
   1097 phy_fe_adv_remote_get(int unit, soc_port_t port, soc_port_mode_t *mode)
   1098 {
   1099     uint16  mii_anp, mii_ctrl, mii_stat;
   1100     phy_ctrl_t  *pc;
   1101 
   1102     pc = EXT_PHY_SW_STATE(unit, port);
   1103 
   1104     *mode = 0;
   1105 
   1106     /* ORDER: must read control, then stat, then anp */
   1107 
   1108     SOC_IF_ERROR_RETURN
   1109         (READ_PHYFEGE_MII_CTRLr(unit, pc, &mii_ctrl));
   1110     SOC_IF_ERROR_RETURN
   1111         (READ_PHYFEGE_MII_STATr(unit, pc, &mii_stat));
   1112     SOC_IF_ERROR_RETURN
   1113         (READ_PHYFEGE_MII_ANPr(unit, pc, &mii_anp));
   1114 
   1115     if (!(mii_ctrl & MII_CTRL_AE)) {
   1116     return(SOC_E_DISABLED);
   1117     } else if (!(mii_stat & MII_STAT_AN_DONE)) {
   1118     return(SOC_E_NONE);
   1119     }
   1120 
   1121     /* Figure out what it means */
   1122 
   1123     if (mii_anp & MII_ANA_HD_10)    *mode |= SOC_PM_10MB_HD;
   1124     if (mii_anp & MII_ANA_FD_10)    *mode |= SOC_PM_10MB_FD;
   1125     if (mii_anp & MII_ANA_HD_100)   *mode |= SOC_PM_100MB_HD;
   1126     if (mii_anp & MII_ANA_FD_100)   *mode |= SOC_PM_100MB_FD;
   1127 
   1128     if (mii_anp & MII_ANA_PAUSE) {
   1129     *mode |= SOC_PM_PAUSE;
   1130     }
   1131 
   1132     return(SOC_E_NONE);
   1133 }
   1134 
   1135 /*
   1136  * Function:    
   1137  *  phy_ge_adv_local_set
   1138  * Purpose: 
   1139  *  Set the current advertisement for auto-negotiation.
   1140  * Parameters:
   1141  *  unit - StrataSwitch unit #.
   1142  *  port - StrataSwitch port #. 
   1143  *  mode - Port mode mask indicating supported options/speeds.
   1144  * Returns: 
   1145  *  SOC_E_XXX
   1146  */
   1147 
   1148 int 
   1149 phy_ge_adv_local_set(int unit, soc_port_t port, soc_port_mode_t mode)
   1150 {
   1151     uint16  mii_ctrl, mii_adv, mii_gb_ctrl;
   1152     phy_ctrl_t  *pc;
   1153 
   1154     pc          = EXT_PHY_SW_STATE(unit, port);
   1155     mii_adv = MII_ANA_ASF_802_3;
   1156 
   1157     SOC_IF_ERROR_RETURN
   1158         (READ_PHYFEGE_MII_GB_CTRLr(unit, pc,  &mii_gb_ctrl));
   1159 
   1160     mii_gb_ctrl &= ~(MII_GB_CTRL_ADV_1000HD | MII_GB_CTRL_ADV_1000FD);
   1161 
   1162     if (mode & SOC_PM_10MB_HD)  mii_adv |= MII_ANA_HD_10;
   1163     if (mode & SOC_PM_10MB_FD)  mii_adv |= MII_ANA_FD_10;
   1164     if (mode & SOC_PM_100MB_HD) mii_adv |= MII_ANA_HD_100;
   1165     if (mode & SOC_PM_100MB_FD) mii_adv |= MII_ANA_FD_100;
   1166     if (mode & SOC_PM_1000MB_HD) mii_gb_ctrl |= MII_GB_CTRL_ADV_1000HD;
   1167     if (mode & SOC_PM_1000MB_FD) mii_gb_ctrl |= MII_GB_CTRL_ADV_1000FD;
   1168 
   1169     if ((mode & SOC_PM_PAUSE) == SOC_PM_PAUSE) {
   1170         /* Advertise symmetric pause */
   1171         mii_adv |= MII_ANA_PAUSE;
   1172     } else {
   1173         /*
   1174          * For Asymmetric pause, 
   1175          *   if (Bit 10)
   1176          *       then pause frames flow toward the Transceiver
   1177          *       else pause frames flow toward link partner.
   1178          */
   1179         if (mode & SOC_PM_PAUSE_TX) {
   1180             mii_adv |= MII_ANA_ASYM_PAUSE;
   1181         } else if (mode & SOC_PM_PAUSE_RX) {
   1182             mii_adv |= MII_ANA_ASYM_PAUSE;
   1183             mii_adv |= MII_ANA_PAUSE;
   1184         }
   1185     }
   1186 
   1187     SOC_IF_ERROR_RETURN
   1188         (WRITE_PHYFEGE_MII_ANAr(unit, pc, mii_adv));
   1189     SOC_IF_ERROR_RETURN
   1190         (WRITE_PHYFEGE_MII_GB_CTRLr(unit, pc, mii_gb_ctrl));
   1191 
   1192     /* Restart auto-neg if enabled */
   1193 
   1194     SOC_IF_ERROR_RETURN
   1195         (READ_PHYFEGE_MII_CTRLr(unit, pc, &mii_ctrl));
   1196 
   1197     if (mii_ctrl & MII_CTRL_AE) {
   1198     SOC_IF_ERROR_RETURN
   1199             (WRITE_PHYFEGE_MII_CTRLr(unit, pc, mii_ctrl | MII_CTRL_RAN));
   1200     }
   1201 
   1202     return(SOC_E_NONE);
   1203 }
   1204 
   1205 /*
   1206  * Function:    
   1207  *  phy_ge_adv_local_get
   1208  * Purpose: 
   1209  *  Get the current advertisement for auto-negotiation.
   1210  * Parameters:
   1211  *  unit - StrataSwitch unit #.
   1212  *  port - StrataSwitch port #. 
   1213  *  mode - (OUT) Port mode mask indicating supported options/speeds.
   1214  * Returns: 
   1215  *  SOC_E_XXX
   1216  */
   1217 
   1218 int
   1219 phy_ge_adv_local_get(int unit, soc_port_t port, soc_port_mode_t *mode)
   1220 {
   1221     uint16  mii_ana, mii_gb_ctrl;
   1222     phy_ctrl_t  *pc;
   1223 
   1224     pc = EXT_PHY_SW_STATE(unit, port);
   1225     SOC_IF_ERROR_RETURN
   1226         (READ_PHYFEGE_MII_ANAr(unit, pc, &mii_ana));
   1227     SOC_IF_ERROR_RETURN
   1228         (READ_PHYFEGE_MII_GB_CTRLr(unit, pc, &mii_gb_ctrl));
   1229 
   1230     *mode = 0;
   1231 
   1232     if (mii_ana & MII_ANA_HD_10)    *mode |= SOC_PM_10MB_HD;
   1233     if (mii_ana & MII_ANA_FD_10)    *mode |= SOC_PM_10MB_FD;
   1234     if (mii_ana & MII_ANA_HD_100)   *mode |= SOC_PM_100MB_HD;
   1235     if (mii_ana & MII_ANA_FD_100)   *mode |= SOC_PM_100MB_FD;
   1236 
   1237     if (mii_ana & MII_ANA_ASYM_PAUSE) {
   1238     if (mii_ana & MII_ANA_PAUSE) {
   1239         *mode |= SOC_PM_PAUSE_RX;
   1240     } else {
   1241         *mode |= SOC_PM_PAUSE_TX;
   1242     }
   1243     } else if (mii_ana & MII_ANA_PAUSE) {
   1244     *mode |= SOC_PM_PAUSE;
   1245     }
   1246 
   1247     /* GE Specific values */
   1248 
   1249     if (mii_gb_ctrl & MII_GB_CTRL_ADV_1000FD)   *mode |= SOC_PM_1000MB_FD;
   1250     if (mii_gb_ctrl & MII_GB_CTRL_ADV_1000HD)   *mode |= SOC_PM_1000MB_HD;
   1251 
   1252     return(SOC_E_NONE);
   1253 }
   1254 
   1255 /*
   1256  * Function:    
   1257  *  phy_ge_adv_remote_get
   1258  * Purpose: 
   1259  *  Get partner's current advertisement for auto-negotiation.
   1260  * Parameters:
   1261  *  unit - StrataSwitch unit #.
   1262  *  port - StrataSwitch port #. 
   1263  *  mode - (OUT) Port mode mask indicating supported options/speeds.
   1264  * Returns:
   1265  *  SOC_E_XXX
   1266  * Notes:
   1267  *  Returns an empty mask if autonegotiation is not complete.
   1268  */
   1269 
   1270 int
   1271 phy_ge_adv_remote_get(int unit, soc_port_t port, soc_port_mode_t *mode)
   1272 {
   1273     uint16  mii_ctrl, mii_stat, mii_gb_stat, mii_anp;
   1274     phy_ctrl_t  *pc;
   1275 
   1276     pc = EXT_PHY_SW_STATE(unit, port);
   1277 
   1278     *mode = 0;
   1279 
   1280     /* ORDER: must read control, then stat, then anp */
   1281 
   1282     SOC_IF_ERROR_RETURN
   1283         (READ_PHYFEGE_MII_CTRLr(unit, pc, &mii_ctrl));
   1284     SOC_IF_ERROR_RETURN
   1285         (READ_PHYFEGE_MII_STATr(unit, pc, &mii_stat));
   1286     SOC_IF_ERROR_RETURN
   1287         (READ_PHYFEGE_MII_ANPr(unit, pc, &mii_anp));
   1288     SOC_IF_ERROR_RETURN
   1289         (READ_PHYFEGE_MII_GB_STATr(unit, pc, &mii_gb_stat));
   1290 
   1291     if (!(mii_ctrl & MII_CTRL_AE)) {
   1292     return(SOC_E_DISABLED);
   1293     } else if (!(mii_stat & MII_STAT_AN_DONE)) {
   1294     return(SOC_E_NONE);
   1295     }
   1296 
   1297     /* Figure out what it means */
   1298 
   1299     if (mii_anp & MII_ANA_HD_10)    *mode |= SOC_PM_10MB_HD;
   1300     if (mii_anp & MII_ANA_FD_10)    *mode |= SOC_PM_10MB_FD;
   1301     if (mii_anp & MII_ANA_HD_100)   *mode |= SOC_PM_100MB_HD;
   1302     if (mii_anp & MII_ANA_FD_100)   *mode |= SOC_PM_100MB_FD;
   1303 
   1304     if (mii_gb_stat & MII_GB_STAT_LP_1000FD)    *mode |= SOC_PM_1000MB_FD;
   1305     if (mii_gb_stat & MII_GB_STAT_LP_1000HD)    *mode |= SOC_PM_1000MB_HD;
   1306 
   1307     if (mii_anp & MII_ANA_ASYM_PAUSE) {
   1308     if (mii_anp & MII_ANA_PAUSE) {
   1309         *mode |= SOC_PM_PAUSE_RX;
   1310     } else {
   1311         *mode |= SOC_PM_PAUSE_TX;
   1312     }
   1313     } else if (mii_anp & MII_ANA_PAUSE) {
   1314     *mode |= SOC_PM_PAUSE;
   1315     }
   1316 
   1317     return(SOC_E_NONE);
   1318 }
   1319 
   1320 /*
   1321  * Function:    
   1322  *  phy_fe_ge_lb_set
   1323  * Purpose: 
   1324  *  Set the local PHY loopback mode.
   1325  * Parameters:
   1326  *  unit - StrataSwitch unit #.
   1327  *  port - StrataSwitch port #. 
   1328  *  loopback - Boolean: true = enable loopback, false = disable.
   1329  * Returns: 
   1330  *  SOC_E_XXX
   1331  */
   1332 
   1333 int
   1334 phy_fe_ge_lb_set(int unit, soc_port_t port, int enable)
   1335 {
   1336     uint16  mii_ctrl;
   1337     phy_ctrl_t  *pc;
   1338 
   1339     pc = EXT_PHY_SW_STATE(unit, port);
   1340 
   1341     SOC_IF_ERROR_RETURN
   1342         (READ_PHYFEGE_MII_CTRLr(unit, pc, &mii_ctrl));
   1343 
   1344     mii_ctrl &= ~MII_CTRL_LE;
   1345     mii_ctrl |= enable ? MII_CTRL_LE : 0;
   1346 
   1347     SOC_IF_ERROR_RETURN
   1348         (WRITE_PHYFEGE_MII_CTRLr(unit, pc, mii_ctrl));
   1349 
   1350     return(SOC_E_NONE);
   1351 }
   1352 
   1353 /*
   1354  * Function:    
   1355  *  phy_fe_ge_lb_get
   1356  * Purpose: 
   1357  *  Get the local PHY loopback mode.
   1358  * Parameters:
   1359  *  unit - StrataSwitch unit #.
   1360  *  port - StrataSwitch port #. 
   1361  *  loopback - (OUT) Boolean: true = enable loopback, false = disable.
   1362  * Returns: 
   1363  *  SOC_E_XXX
   1364  */
   1365 
   1366 int
   1367 phy_fe_ge_lb_get(int unit, soc_port_t port, int *enable)
   1368 {
   1369     uint16  mii_ctrl;
   1370     phy_ctrl_t  *pc;
   1371 
   1372     pc = EXT_PHY_SW_STATE(unit, port);
   1373 
   1374     SOC_IF_ERROR_RETURN
   1375         (READ_PHYFEGE_MII_CTRLr(unit, pc, &mii_ctrl));
   1376 
   1377     *enable = (mii_ctrl & MII_CTRL_LE) ? 1 : 0;
   1378 
   1379     return(SOC_E_NONE);
   1380 }
   1381 
   1382 /*
   1383  * Function:
   1384  *  phy_fe_interface_set
   1385  * Purpose:
   1386  *  Set the current operating mode of the PHY (SOC_PORT_IF_*)
   1387  *  For example: TBI or MII/GMII.
   1388  * Parameters:
   1389  *  unit - StrataSwitch unit #.
   1390  *  port - StrataSwitch port #. 
   1391  *  pif - one of SOC_PORT_IF_*
   1392  * Returns:
   1393  *  SOC_E_XXX
   1394  */
   1395 
   1396 int
   1397 phy_fe_interface_set(int unit, soc_port_t port, soc_port_if_t pif)
   1398 {
   1399     COMPILER_REFERENCE(unit);
   1400     COMPILER_REFERENCE(port);
   1401 
   1402     switch (pif) {
   1403     case SOC_PORT_IF_MII:
   1404     case SOC_PORT_IF_NOCXN:
   1405     break;
   1406     default:
   1407     return SOC_E_UNAVAIL;
   1408     }
   1409 
   1410     return (SOC_E_NONE);
   1411 }
   1412 
   1413 /*
   1414  * Function:
   1415  *  phy_fe_interface_get
   1416  * Purpose:
   1417  *  Get the current operating mode of the PHY.
   1418  * Parameters:
   1419  *  unit - StrataSwitch unit #.
   1420  *  port - StrataSwitch port #. 
   1421  *  pif - (OUT) one of SORT_PORT_IF_*
   1422  * Returns:
   1423  *  SOC_E_XXX
   1424  */
   1425 
   1426 int
   1427 phy_fe_interface_get(int unit, soc_port_t port, soc_port_if_t *pif)
   1428 {
   1429     COMPILER_REFERENCE(unit);
   1430     COMPILER_REFERENCE(port);
   1431 
   1432     *pif = SOC_PORT_IF_MII;
   1433 
   1434     return(SOC_E_NONE);
   1435 }
   1436 
   1437 /*
   1438  * Function:
   1439  *  phy_ge_interface_set
   1440  * Purpose:
   1441  *  Set the current operating mode of the PHY.
   1442  *  (Pertaining to the MAC/PHY interface, not the line interface).
   1443  *      For example: TBI or MII/GMII.
   1444  * Parameters:
   1445  *  unit - StrataSwitch unit #.
   1446  *  port - StrataSwitch port #. 
   1447  *  pif - one of SOC_PORT_IF_*
   1448  * Returns:
   1449  *  SOC_E_XXX
   1450  */
   1451 
   1452 int
   1453 phy_ge_interface_set(int unit, soc_port_t port, soc_port_if_t pif)
   1454 {
   1455     uint16      mii_ecr;
   1456     int             mii;            /* MII if true, TBI otherwise */
   1457     phy_ctrl_t         *pc;
   1458 
   1459     pc = EXT_PHY_SW_STATE(unit, port);
   1460 
   1461     switch (pif) {
   1462     case SOC_PORT_IF_MII:
   1463     case SOC_PORT_IF_GMII:
   1464     case SOC_PORT_IF_SGMII:
   1465         mii = TRUE;
   1466         break;
   1467     case SOC_PORT_IF_NOCXN:
   1468     return (SOC_E_NONE);
   1469     case SOC_PORT_IF_TBI:
   1470         mii = FALSE;
   1471         break;
   1472     default:
   1473         return SOC_E_UNAVAIL;
   1474     }
   1475 
   1476     SOC_IF_ERROR_RETURN
   1477         (READ_PHYFEGE_MII_ECRr(unit, pc, &mii_ecr));
   1478 
   1479     if (mii) {
   1480         mii_ecr &= ~MII_ECR_10B;
   1481         PHY_FLAGS_CLR(unit, port, PHY_FLAGS_10B);
   1482     } else {
   1483         mii_ecr |= MII_ECR_10B;
   1484         PHY_FLAGS_SET(unit, port, PHY_FLAGS_10B);
   1485     }
   1486 
   1487     SOC_IF_ERROR_RETURN
   1488         (WRITE_PHYFEGE_MII_ECRr(unit, pc, mii_ecr));
   1489 
   1490     return(SOC_E_NONE);
   1491 }
   1492 
   1493 /*
   1494  * Function:
   1495  *  phy_ge_interface_get
   1496  * Purpose:
   1497  *  Get the current operating mode of the PHY.
   1498  *  (Pertaining to the MAC/PHY interface, not the line interface).
   1499  * Parameters:
   1500  *  unit - StrataSwitch unit #.
   1501  *  port - StrataSwitch port #. 
   1502  *  pif - (OUT) one of SOC_PORT_IF_*
   1503  * Returns:
   1504  *  SOC_E_XXX
   1505  */
   1506 
   1507 int
   1508 phy_ge_interface_get(int unit, soc_port_t port, soc_port_if_t *pif)
   1509 {
   1510     if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_10B)) {
   1511         *pif = SOC_PORT_IF_TBI;
   1512     } else {
   1513         *pif = SOC_PORT_IF_GMII;
   1514     }
   1515 
   1516     return(SOC_E_NONE);
   1517 }
   1518 
   1519 /*
   1520  * Function:    
   1521  *  phy_fe_ability_get
   1522  * Purpose: 
   1523  *  Get the abilities of the local phy.
   1524  * Parameters:
   1525  *  unit - StrataSwitch unit #.
   1526  *  port - StrataSwitch port #. 
   1527  *  mode - (OUT) Port mode mask indicating supported options/speeds.
   1528  * Returns:
   1529  *  SOC_E_XXX
   1530  */
   1531 
   1532 int
   1533 phy_fe_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode)
   1534 {
   1535     uint16  mii_status;
   1536 
   1537     phy_ctrl_t  *pc;
   1538 
   1539     pc = EXT_PHY_SW_STATE(unit, port);
   1540     *mode = SOC_PM_LB_PHY | SOC_PM_MII | SOC_PM_PAUSE;  /* No PAUSE_ASYMM */
   1541     *mode |= SOC_PM_AN;
   1542     SOC_IF_ERROR_RETURN
   1543         (READ_PHYFEGE_MII_STATr(unit, pc, &mii_status));
   1544 
   1545     if (mii_status & MII_STAT_100_T4)       *mode |= SOC_PM_100MB_FD;
   1546     if (mii_status & MII_STAT_FD_100_T2)    *mode |= SOC_PM_100MB_FD;
   1547     if (mii_status & MII_STAT_HD_100_T2)    *mode |= SOC_PM_100MB_HD;
   1548     if (mii_status & MII_STAT_FD_10)        *mode |= SOC_PM_10MB_FD;
   1549     if (mii_status & MII_STAT_HD_10)        *mode |= SOC_PM_10MB_HD;
   1550     if (mii_status & MII_STAT_FD_100)       *mode |= SOC_PM_100MB_FD;
   1551     if (mii_status & MII_STAT_HD_100)       *mode |= SOC_PM_100MB_HD;
   1552 
   1553     return(SOC_E_NONE);
   1554 }
   1555 
   1556 /*
   1557  * Function:    
   1558  *  phy_ge_ability_get
   1559  * Purpose: 
   1560  *  Get the abilities of the local gigabit phy.
   1561  * Parameters:
   1562  *  unit - StrataSwitch unit #.
   1563  *  port - StrataSwitch port #. 
   1564  *  mode - (OUT) Port mode mask indicating supported options/speeds.
   1565  * Returns: 
   1566  *  SOC_E_XXX
   1567  */
   1568 
   1569 int
   1570 phy_ge_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode)
   1571 {
   1572     uint16  mii_esr;
   1573     phy_ctrl_t  *pc;
   1574 
   1575     pc = EXT_PHY_SW_STATE(unit, port);
   1576 
   1577     SOC_IF_ERROR_RETURN
   1578     (phy_fe_ability_get(unit, port, mode));
   1579 
   1580     *mode |= (SOC_PM_PAUSE | SOC_PM_PAUSE_ASYMM | SOC_PM_GMII | SOC_PM_SGMII);
   1581 
   1582     SOC_IF_ERROR_RETURN
   1583         (READ_PHYFEGE_MII_ESRr(unit, pc, &mii_esr));
   1584 
   1585     
   1586 
   1587     if (mii_esr & MII_ESR_1000_T_FD)    *mode |= SOC_PM_1000MB_FD;
   1588     if (mii_esr & MII_ESR_1000_T_HD)    *mode |= SOC_PM_1000MB_HD;
   1589     if (mii_esr & MII_ESR_1000_X_FD)    *mode |= SOC_PM_1000MB_FD;
   1590     if (mii_esr & MII_ESR_1000_X_HD)    *mode |= SOC_PM_1000MB_HD;
   1591 
   1592     return(SOC_E_NONE);
   1593 }
   1594 
   1595 /*
   1596  * Function:
   1597  *      phy_fe_ge_medium_get
   1598  * Description:
   1599  *      Get the currently chosen medium for the dual-medium PHY
   1600  * Parameters:
   1601  *      unit    -- Device number
   1602  *      port    -- Port number
   1603  *      medium  -- (Out) One of
   1604  *                 SOC_PORT_MEDIUM_NONE  
   1605  *                 SOC_PORT_MEDIUM_COPPER
   1606  *                 SOC_PORT_MEDIUM_FIBER
   1607  *
   1608  * Return value:
   1609  *      SOC_E_NONE
   1610  *      SOC_E_PARAM
   1611  *      SOC_E_UNAVAIL
   1612  */
   1613 int
   1614 phy_fe_ge_medium_get(int unit, soc_port_t port,
   1615                     soc_port_medium_t *medium)
   1616 {
   1617     int rv;
   1618     soc_pbmp_t pbmp_100fx;
   1619 
   1620     COMPILER_REFERENCE(unit);
   1621     COMPILER_REFERENCE(port);
   1622 
   1623     if (medium != NULL) {
   1624         /*
   1625           * Get 100-FX ports from config.bcm.
   1626           */
   1627         pbmp_100fx = soc_property_get_pbmp(unit, spn_PBMP_FE_100FX, 0);
   1628         if (SOC_PBMP_MEMBER(pbmp_100fx, port)) {
   1629             *medium = SOC_PORT_MEDIUM_FIBER;
   1630             return SOC_E_NONE;
   1631         }
   1632 
   1633         *medium = SOC_PORT_MEDIUM_COPPER;
   1634         rv = SOC_E_NONE;
   1635     } else {    
   1636         rv = SOC_E_PARAM;
   1637     }
   1638     
   1639     return (rv);
   1640 }
   1641 
   1642 /*
   1643  * Function:
   1644  *      phy_fe_ge_ability_advert_set
   1645  * Purpose:
   1646  *      Set the current advertisement for auto-negotiation.
   1647  * Parameters:
   1648  *      unit    - StrataSwitch unit #.
   1649  *      port    - StrataSwitch port #.
   1650  *      ability - Port ability indicating supported options/speeds.
   1651  * Returns:
   1652  *      SOC_E_XXX
   1653  */
   1654 
   1655 int
   1656 phy_fe_ge_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability)
   1657 {
   1658     phy_ctrl_t      *pc;
   1659     uint16       mii_adv, mii_gb_ctrl;
   1660 
   1661     if (NULL == ability) {
   1662         return (SOC_E_PARAM);
   1663     }
   1664 
   1665     pc = EXT_PHY_SW_STATE(unit, port);
   1666 
   1667     mii_adv     = MII_ANA_ASF_802_3;
   1668 
   1669     if (ability->speed_half_duplex & SOC_PA_SPEED_10MB)  {
   1670         mii_adv |= MII_ANA_HD_10;
   1671     }
   1672     if (ability->speed_half_duplex & SOC_PA_SPEED_100MB) {
   1673         mii_adv |= MII_ANA_HD_100;
   1674     }
   1675     if (ability->speed_full_duplex & SOC_PA_SPEED_10MB)  {
   1676         mii_adv |= MII_ANA_FD_10;
   1677     }
   1678     if (ability->speed_full_duplex & SOC_PA_SPEED_100MB) {
   1679         mii_adv |= MII_ANA_FD_100;
   1680     }
   1681 
   1682     switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) {
   1683     case SOC_PA_PAUSE_TX:
   1684         mii_adv |= MII_ANA_ASYM_PAUSE;
   1685         break;
   1686     case SOC_PA_PAUSE_RX:
   1687         mii_adv |= MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE;
   1688         break;
   1689     case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX:
   1690         mii_adv |= MII_ANA_PAUSE;
   1691         break;
   1692     }
   1693 
   1694     SOC_IF_ERROR_RETURN
   1695         (MODIFY_PHYFEGE_MII_ANAr(unit, pc, mii_adv,
   1696         MII_ANA_PAUSE|MII_ANA_ASYM_PAUSE|MII_ANA_FD_100|MII_ANA_HD_100|
   1697         MII_ANA_FD_10|MII_ANA_HD_10|MII_ANA_ASF_802_3));
   1698 
   1699     if (IS_GE_PORT(unit, port)) {
   1700         SOC_IF_ERROR_RETURN
   1701             (READ_PHYFEGE_MII_GB_CTRLr(unit, pc,  &mii_gb_ctrl));
   1702 
   1703         mii_gb_ctrl &= ~(MII_GB_CTRL_ADV_1000HD | MII_GB_CTRL_ADV_1000FD);
   1704         mii_gb_ctrl |= MII_GB_CTRL_PT; /* repeater / switch port */
   1705 
   1706         if (ability->speed_half_duplex & SOC_PA_SPEED_1000MB) {
   1707             mii_gb_ctrl |= MII_GB_CTRL_ADV_1000HD;
   1708         }
   1709         if (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) {
   1710             mii_gb_ctrl |= MII_GB_CTRL_ADV_1000FD;
   1711         }
   1712         SOC_IF_ERROR_RETURN
   1713             (MODIFY_PHYFEGE_MII_GB_CTRLr(unit, pc, mii_gb_ctrl,
   1714             MII_GB_CTRL_PT|MII_GB_CTRL_ADV_1000FD|MII_GB_CTRL_ADV_1000HD));
   1715     }
   1716 
   1717     return SOC_E_NONE;
   1718 
   1719 }
   1720 
   1721 /*
   1722  * Function:
   1723  *      phy_fe_ge_ability_advert_get
   1724  * Purpose:
   1725  *      Get the current advertisement for auto-negotiation.
   1726  * Parameters:
   1727  *      unit    - StrataSwitch unit #.
   1728  *      port    - StrataSwitch port #.
   1729  *      ability - Port ability indicating supported options/speeds.
   1730  * Returns:
   1731  *      SOC_E_XXX
   1732  * Notes:
   1733  *      The advertisement is retrieved for the ACTIVE medium.
   1734  *      No synchronization performed at this level.
   1735  */
   1736 
   1737 int
   1738 phy_fe_ge_ability_advert_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   1739 {
   1740     phy_ctrl_t *pc;
   1741     uint16      mii_ana;
   1742     uint16      mii_gb_ctrl;
   1743 
   1744     if (NULL == ability) {
   1745         return (SOC_E_PARAM);
   1746     }
   1747 
   1748     pc = EXT_PHY_SW_STATE(unit, port);
   1749 
   1750     SOC_IF_ERROR_RETURN
   1751         (READ_PHYFEGE_MII_ANAr(unit, pc, &mii_ana));
   1752 
   1753     sal_memset(ability, 0, sizeof(*ability));
   1754 
   1755     if (mii_ana & MII_ANA_HD_10) {
   1756        ability->speed_half_duplex |= SOC_PA_SPEED_10MB;
   1757     }
   1758     if (mii_ana & MII_ANA_HD_100) {
   1759       ability->speed_half_duplex |= SOC_PA_SPEED_100MB;
   1760     }
   1761     if (mii_ana & MII_ANA_FD_10) {
   1762       ability->speed_full_duplex |= SOC_PA_SPEED_10MB;
   1763     }
   1764     if (mii_ana & MII_ANA_FD_100) {
   1765       ability->speed_full_duplex |= SOC_PA_SPEED_100MB;
   1766     }
   1767 
   1768     switch (mii_ana & (MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE)) {
   1769         case MII_ANA_PAUSE:
   1770             ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   1771             break;
   1772         case MII_ANA_ASYM_PAUSE:
   1773             ability->pause = SOC_PA_PAUSE_TX;
   1774             break;
   1775         case MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE:
   1776             ability->pause = SOC_PA_PAUSE_RX;
   1777             break;
   1778     }
   1779 
   1780     /* GE Specific values */
   1781     if (IS_GE_PORT(unit, port)) {
   1782          SOC_IF_ERROR_RETURN
   1783              (READ_PHYFEGE_MII_GB_CTRLr(unit, pc, &mii_gb_ctrl));
   1784 
   1785          if (mii_gb_ctrl & MII_GB_CTRL_ADV_1000HD) {
   1786             ability->speed_half_duplex |= SOC_PA_SPEED_1000MB;
   1787          }
   1788          if (mii_gb_ctrl & MII_GB_CTRL_ADV_1000FD) {
   1789             ability->speed_full_duplex |= SOC_PA_SPEED_1000MB;
   1790         }
   1791     }
   1792 
   1793     return SOC_E_NONE;
   1794 }
   1795 
   1796 /*
   1797  * Function:
   1798  *      phy_fe_ge_ability_remote_get
   1799  * Purpose:
   1800  *      Get partners current advertisement for auto-negotiation.
   1801  * Parameters:
   1802  *      unit    - StrataSwitch unit #.
   1803  *      port    - StrataSwitch port #.
   1804  *      ability - Port ability indicating supported options/speeds.
   1805  * Returns:
   1806  *      SOC_E_XXX
   1807  * Notes:
   1808  *      The remote advertisement is retrieved for the ACTIVE medium.
   1809  *      No synchronization performed at this level. If Autonegotiation is
   1810  *      disabled or in progress, this routine will return an error.
   1811  */
   1812 
   1813 int
   1814 phy_fe_ge_ability_remote_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   1815 {
   1816     phy_ctrl_t       *pc;
   1817     uint16            mii_stat;
   1818     uint16            mii_anp;
   1819     uint16            mii_gb_stat;
   1820 
   1821     if (NULL == ability) {
   1822         return (SOC_E_PARAM);
   1823     }
   1824 
   1825     pc = EXT_PHY_SW_STATE(unit, port);
   1826 
   1827     SOC_IF_ERROR_RETURN
   1828         (READ_PHYFEGE_MII_STATr(unit, pc, &mii_stat));
   1829 
   1830     sal_memset(ability, 0, sizeof(*ability));
   1831 
   1832     if ((mii_stat & (MII_STAT_AN_DONE | MII_STAT_LA))
   1833                    == (MII_STAT_AN_DONE | MII_STAT_LA)) {
   1834         /* Decode remote advertisement only when link is up and autoneg is
   1835          * completed.
   1836          */
   1837         SOC_IF_ERROR_RETURN
   1838             (READ_PHYFEGE_MII_ANPr(unit, pc, &mii_anp));
   1839 
   1840         if (mii_anp & MII_ANA_HD_10) {
   1841             ability->speed_half_duplex |= SOC_PA_SPEED_10MB;
   1842         }
   1843         if (mii_anp & MII_ANA_HD_100) {
   1844             ability->speed_half_duplex |= SOC_PA_SPEED_100MB;
   1845         }
   1846         if (mii_anp & MII_ANA_FD_10) {
   1847            ability->speed_full_duplex |= SOC_PA_SPEED_10MB;
   1848         }
   1849         if (mii_anp & MII_ANA_FD_100) {
   1850            ability->speed_full_duplex |= SOC_PA_SPEED_100MB;
   1851         }
   1852 
   1853         switch (mii_anp & (MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE)) {
   1854             case MII_ANA_PAUSE:
   1855                 ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   1856                 break;
   1857             case MII_ANA_ASYM_PAUSE:
   1858                 ability->pause = SOC_PA_PAUSE_TX;
   1859                 break;
   1860             case MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE:
   1861                 ability->pause = SOC_PA_PAUSE_RX;
   1862                 break;
   1863        }
   1864 
   1865         /* GE Specific values */
   1866        if (IS_GE_PORT(unit, port)) {
   1867             SOC_IF_ERROR_RETURN
   1868                 (READ_PHYFEGE_MII_GB_STATr(unit, pc, &mii_gb_stat));
   1869 
   1870             if (mii_gb_stat & MII_GB_STAT_LP_1000HD) {
   1871             ability->speed_half_duplex |= SOC_PA_SPEED_1000MB;
   1872             }
   1873             if (mii_gb_stat & MII_GB_STAT_LP_1000FD) {
   1874                 ability->speed_full_duplex |= SOC_PA_SPEED_1000MB;
   1875             }
   1876         }
   1877 
   1878     } else {
   1879         /* Simply return local abilities */
   1880         SOC_IF_ERROR_RETURN
   1881                 (phy_fe_ge_ability_advert_get(unit, port, ability));
   1882     }
   1883     LOG_INFO(BSL_LS_SOC_PHY,
   1884              (BSL_META_U(unit,
   1885                          "phy_fe_ge_ability_remote_get:unit=%d p=%d pause=%08x sp=%08x\n"),
   1886               unit, port, ability->pause, ability->speed_full_duplex));
   1887 
   1888     return SOC_E_NONE;
   1889 }
   1890 
   1891 /*
   1892  * Function:
   1893  *  phy_fe_cable_diag
   1894  * Purpose:
   1895  *  Run 5248 cable diagnostics
   1896  * Parameters:
   1897  *  unit - device number
   1898  *  port - port number
   1899  *  status - (OUT) cable diagnotic status structure
   1900  * Returns: 
   1901  *  SOC_E_XXX
   1902  */
   1903 
   1904 int
   1905 phy_fe_cable_diag(int unit, soc_port_t port,
   1906                 soc_port_cable_diag_t *status)
   1907 {
   1908 
   1909     return SOC_E_UNAVAIL;
   1910 }
   1911 
   1912 /*
   1913  * Function:
   1914  *      phy_ge_reg_read
   1915  * Purpose:
   1916  *      Routine to read PHY register
   1917  * Parameters:
   1918  *      uint         - BCM unit number
   1919  *      pc           - PHY state
   1920  *      flags        - Flags which specify the register type
   1921  *      phy_reg_addr - Encoded register address
   1922  *      phy_data     - (OUT) Value read from PHY register
   1923  * Note:
   1924  *      This register read function is not thread safe. Higher level
   1925  * function that calls this function must obtain a per port lock
   1926  * to avoid overriding register page mapping between threads.
   1927  */
   1928 int
   1929 phy_ge_reg_read(int unit, soc_port_t port, uint32 flags,
   1930                   uint32 phy_reg_addr, uint32 *phy_data)
   1931 {
   1932     uint32               reg_flags;
   1933     uint16               reg_bank;
   1934     uint8                reg_addr;
   1935     uint16               data;     /* Temporary holder for phy_data */
   1936     phy_ctrl_t           *pc;      /* PHY software state */
   1937 
   1938     COMPILER_REFERENCE(flags);
   1939 
   1940     pc   = EXT_PHY_SW_STATE(unit, port);
   1941 
   1942     reg_flags = SOC_PHY_REG_FLAGS(phy_reg_addr);
   1943     reg_bank  = SOC_PHY_REG_BANK(phy_reg_addr);
   1944     reg_addr  = SOC_PHY_REG_ADDR(phy_reg_addr);
   1945 
   1946     SOC_IF_ERROR_RETURN
   1947         (phy_reg_ge_read(unit, pc, reg_flags, reg_bank, reg_addr, &data));
   1948 
   1949    *phy_data = data;
   1950 
   1951     return SOC_E_NONE;
   1952 }
   1953 
   1954 /*
   1955  * Function:
   1956  *      phy_ge_reg_write
   1957  * Purpose:
   1958  *      Routine to write PHY register
   1959  * Parameters:
   1960  *      uint         - BCM unit number
   1961  *      pc           - PHY state
   1962  *      flags        - Flags which specify the register type
   1963  *      phy_reg_addr - Encoded register address
   1964  *      phy_data     - Value write to PHY register
   1965  * Note:
   1966  *      This register read function is not thread safe. Higher level
   1967  * function that calls this function must obtain a per port lock
   1968  * to avoid overriding register page mapping between threads.
   1969  */
   1970 int
   1971 phy_ge_reg_write(int unit, soc_port_t port, uint32 flags,
   1972                    uint32 phy_reg_addr, uint32 phy_data)
   1973 {
   1974     uint32               reg_flags;
   1975     uint16               reg_bank;
   1976     uint8                reg_addr;
   1977     uint16               data;     /* Temporary holder for phy_data */
   1978     phy_ctrl_t           *pc;      /* PHY software state */
   1979 
   1980     COMPILER_REFERENCE(flags);
   1981 
   1982 
   1983     pc   = EXT_PHY_SW_STATE(unit, port);
   1984     data = (uint16) (phy_data & 0x0000FFFF);
   1985 
   1986     reg_flags = SOC_PHY_REG_FLAGS(phy_reg_addr);
   1987     reg_bank  = SOC_PHY_REG_BANK(phy_reg_addr);
   1988     reg_addr  = SOC_PHY_REG_ADDR(phy_reg_addr);
   1989 
   1990     return phy_reg_ge_write(unit, pc, reg_flags, reg_bank, reg_addr, data);
   1991 }
   1992 
   1993 /*
   1994  * Function:
   1995  *      phy_ge_reg_modify
   1996  * Purpose:
   1997  *      Routine to write PHY register
   1998  * Parameters:
   1999  *      uint         - BCM unit number
   2000  *      pc           - PHY state
   2001  *      flags        - Flags which specify the register type
   2002  *      phy_reg_addr - Encoded register address
   2003  *      phy_mo_data  - New value for the bits specified in phy_mo_mask
   2004  *      phy_mo_mask  - Bit mask to modify
   2005  * Note:
   2006  *      This register read function is not thread safe. Higher level
   2007  * function that calls this function must obtain a per port lock
   2008  * to avoid overriding register page mapping between threads.
   2009  */
   2010 int
   2011 phy_ge_reg_modify(int unit, soc_port_t port, uint32 flags,
   2012                     uint32 phy_reg_addr, uint32 phy_data,
   2013                     uint32 phy_data_mask)
   2014 {
   2015     uint32               reg_flags;
   2016     uint16               reg_bank;
   2017     uint8                reg_addr;
   2018     uint16               data;     /* Temporary holder for phy_data */
   2019     uint16               mask;     /* Temporary holder for phy_data_mask */
   2020     phy_ctrl_t           *pc;      /* PHY software state */
   2021 
   2022     COMPILER_REFERENCE(flags);
   2023 
   2024     pc   = EXT_PHY_SW_STATE(unit, port);
   2025     data = (uint16) (phy_data & 0x0000FFFF);
   2026     mask = (uint16) (phy_data_mask & 0x0000FFFF);
   2027 
   2028     reg_flags = SOC_PHY_REG_FLAGS(phy_reg_addr);
   2029     reg_bank  = SOC_PHY_REG_BANK(phy_reg_addr);
   2030     reg_addr  = SOC_PHY_REG_ADDR(phy_reg_addr);
   2031 
   2032     return phy_reg_ge_modify(unit, pc, reg_flags, reg_bank,
   2033                              reg_addr, data, mask);
   2034 }
   2035