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

qsgmii65.c (55029B)


      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:
      8  *      qsgmii65.c
      9  * Purpose:
     10  *      Fiber driver for serdes 65nm Low Power using internal Serdes PHY.
     11  *
     12  * When operating with an external PHY, this driver is not used.
     13  * However the speed/duplex of the internal PHY must be programmed to
     14  * match the MAC and external PHY settings so the data can pass through.
     15  * This file supplies some routines to allow mac.c to accomplish this
     16  * (think of the internal PHY as part of the MAC in this case):
     17  *
     18  *      phy_qsgmii65_notify_duplex
     19  *      phy_qsgmii65_notify_speed
     20  *      phy_qsgmii65_notify_stop
     21  *      phy_qsgmii65_notify_resume
     22  */
     23 
     24 #include <sal/types.h>
     25 #include <sal/core/spl.h>
     26 #include <shared/bsl.h>
     27 #include <soc/drv.h>
     28 #include <soc/debug.h>
     29 #include <soc/error.h>
     30 #include <soc/phy.h>
     31 #include <soc/phyreg.h>
     32 
     33 #include <soc/phy.h>
     34 #include <soc/phy/phyctrl.h>
     35 #include <soc/phy/drv.h>
     36 
     37 #include "phydefs.h"      /* Must include before other phy related includes */
     38 
     39 #if defined(INCLUDE_XGXS_QSGMII65)
     40 #include "phyconfig.h"    /* Must be the first phy include after phydefs.h */
     41 #include "phyident.h"
     42 #include "phyreg.h"
     43 #include "phynull.h"
     44 #include "serdes.h"
     45 #include "qsgmii65.h"
     46 
     47 #define WORKAROUND_FIX           1
     48 
     49 #define ADVERT_ALL_FIBER \
     50             (SOC_PM_PAUSE | SOC_PM_1000MB_FD)
     51 
     52 /* Notify event forward declaration */
     53 STATIC int 
     54 _phy_qsgmii65_notify_duplex(int unit, soc_port_t port, uint32 duplex);
     55 STATIC int 
     56 _phy_qsgmii65_notify_speed(int unit, soc_port_t port, uint32 speed);
     57 STATIC int 
     58 _phy_qsgmii65_notify_stop(int unit, soc_port_t port, uint32 flags);
     59 STATIC int 
     60 _phy_qsgmii65_notify_resume(int unit, soc_port_t port, uint32 flags);
     61 STATIC int
     62 _phy_qsgmii65_notify_interface(int unit, soc_port_t port, uint32 intf);
     63 
     64 /***********************************************************************
     65  *
     66  * FIBER DRIVER ROUTINES
     67  */
     68 STATIC int
     69 _phy_qsgmii65_tx_control_set(int unit, phy_ctrl_t *pc,
     70                           soc_port_t port)
     71 {
     72     uint32 preemph;
     73     uint32 idriver;
     74     uint32 pdriver;
     75     uint16 data;
     76     uint16 mask;
     77 
     78     SOC_IF_ERROR_RETURN
     79         (READ_QSGMII65_1000X_STAT1r(unit, pc, &data));
     80 
     81     if (data & LP_1000X_STATUS1_SGMII_MODE) {
     82         /* SGMII mode */
     83         idriver = 0x1;
     84         pdriver = 0x7;
     85     } else {
     86         /* 1000X mode */
     87         idriver = 0x1;
     88         pdriver = 0x7;
     89     }
     90     preemph = 0x0;
     91 
     92     /* Read config override */
     93     preemph = soc_property_port_get(unit, port,
     94                                     spn_SERDES_PREEMPHASIS, preemph);
     95     idriver = soc_property_port_get(unit, port,
     96                                     spn_SERDES_DRIVER_CURRENT, idriver);
     97     pdriver = soc_property_port_get(unit, port,
     98                                     spn_SERDES_PRE_DRIVER_CURRENT, pdriver);
     99 
    100     if (data & LP_1000X_STATUS1_SGMII_MODE) {
    101         /* SGMII mode */
    102         data = ((preemph & 0xf) << 12) | ((idriver & 0xf) << 8) | ((pdriver & 0xf) << 4);
    103         mask = 0xfff0;
    104         SOC_IF_ERROR_RETURN
    105             (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask));
    106     } else {
    107         /* 1000X mode */
    108         data = ((preemph & 0xf) << 12) | ((idriver & 0xf) << 8) | ((pdriver & 0xf) << 4);
    109         mask = 0xfff0;
    110         SOC_IF_ERROR_RETURN
    111             (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask));
    112     }
    113     return SOC_E_NONE;
    114 }
    115 
    116 STATIC int
    117 _phy_qsgmii65_init_no_reset(int unit, soc_port_t port)
    118 {
    119     uint16             data16, mask16;
    120     uint16             mode_1000x;
    121     soc_timeout_t      to;
    122     phy_ctrl_t        *pc;
    123     int                rv;
    124 
    125     pc                       = INT_PHY_SW_STATE(unit, port);
    126     pc->fiber.enable         = PHY_FIBER_MODE(unit, port);
    127     pc->fiber.preferred      = PHY_FIBER_MODE(unit, port);
    128     pc->fiber.autoneg_enable = 1;
    129     pc->fiber.autoneg_advert = ADVERT_ALL_FIBER;
    130     pc->fiber.force_speed    = 1000;
    131     pc->fiber.force_duplex   = TRUE;
    132     pc->fiber.master         = SOC_PORT_MS_NONE;
    133     pc->fiber.mdix           = SOC_PORT_MDIX_NORMAL;
    134 
    135     /* Since phyqsgmii65 driver reset function vector does not reset
    136      * the SerDes, reset the SerDes in initialization first. 
    137      * The internal SERDES PHY's reset bit is self-clearing.
    138      */
    139     SOC_IF_ERROR_RETURN
    140         (MODIFY_QSGMII65_MII_CTRLr(unit, pc,
    141                                MII_CTRL_RESET, MII_CTRL_RESET));
    142 
    143     soc_timeout_init(&to, 10000, 0);
    144     while (!soc_timeout_check(&to)) {
    145         rv = READ_QSGMII65_MII_CTRLr(unit, pc, &data16);
    146         if (((data16 & MII_CTRL_RESET) == 0) || SOC_FAILURE(rv)) {
    147             break;
    148         }
    149     }
    150    if ((data16 & MII_CTRL_RESET) != 0) {
    151         LOG_WARN(BSL_LS_SOC_PHY,
    152                  (BSL_META_U(unit,
    153                              "Combo SerDes reset failed: u=%d p=%d\n"),
    154                   unit, port));
    155     }
    156    
    157     if (pc->lane_num == 0) {
    158         data16 = 0x0000;
    159         switch (soc_property_port_get(unit, port, 
    160                                   spn_SERDES_QSGMII_SGMII_OVERRIDE, 0)) {
    161             case 1:     /* QSGMII mode */
    162                 data16 = 0x1100;
    163                 /* Fall Thru */
    164             case 2:     /* SGMII mode */
    165                 SOC_IF_ERROR_RETURN
    166                     (MODIFY_QSGMII65_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x0000, 0x2000));
    167 
    168                 mask16 = 0xff00;
    169                 SOC_IF_ERROR_RETURN
    170                     (MODIFY_QSGMII65_LANE_CTRL0r(unit, pc, data16, mask16));
    171 
    172                 SOC_IF_ERROR_RETURN
    173                     (MODIFY_QSGMII65_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x2000, 0x2000));
    174 
    175                 pc->lane_num = 4;
    176 
    177                 SOC_IF_ERROR_RETURN
    178                     (MODIFY_QSGMII65_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x0000, 0x2000));
    179 
    180                 SOC_IF_ERROR_RETURN
    181                     (MODIFY_QSGMII65_LANE_CTRL0r(unit, pc, data16, mask16));
    182 
    183                 SOC_IF_ERROR_RETURN
    184                     (MODIFY_QSGMII65_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x2000, 0x2000));
    185 
    186                 pc->lane_num = 0;
    187             default: /* H/W default */
    188                 break;
    189         }
    190     }
    191 
    192     /* Set the default speed/duplex/autoneg */
    193     data16 = MII_CTRL_FD | MII_CTRL_SS_1000;
    194     if ((PHY_FIBER_MODE(unit, port) && !PHY_EXTERNAL_MODE(unit, port)) ||
    195         PHY_PASSTHRU_MODE(unit, port) ||
    196         PHY_SGMII_AUTONEG_MODE(unit, port)) {
    197         data16 |= MII_CTRL_AE | MII_CTRL_RAN;
    198     }
    199 
    200     /* If enabling autoneg, make sure that the default speed and duplex
    201      * are set correctly.
    202      */
    203     if (data16 & MII_CTRL_AE) {
    204         /* Advertise default speed and duplex */
    205         SOC_IF_ERROR_RETURN
    206             (WRITE_QSGMII65_MII_ANAr(unit, pc, MII_ANA_C37_FD | 
    207                                                  MII_ANA_C37_PAUSE |
    208                                                  MII_ANA_C37_ASYM_PAUSE));
    209     }
    210     SOC_IF_ERROR_RETURN
    211         (WRITE_QSGMII65_MII_CTRLr(unit, pc, data16));
    212 
    213     /* Configure auto-detect and fiber vs. sgmii mode */
    214     data16 = LP_1000X_PLL_PWRDWN;
    215     mask16 = LP_1000X_PLL_PWRDWN | 
    216              LP_1000X_AUTO_DETECT | LP_1000X_FIBER_MODE;
    217     /*
    218      * Configure signal auto-detection between SGMII and fiber.
    219      * This detection only works if auto-negotiation is enabled.
    220      */
    221     if (soc_property_port_get(unit, port, 
    222                               spn_SERDES_AUTOMEDIUM, FALSE)) {
    223         data16 |= LP_1000X_AUTO_DETECT;
    224     }
    225 
    226     /*
    227      * Put the Serdes in Fiber or SGMII mode
    228      */
    229     mode_1000x = 0;
    230     if ((PHY_FIBER_MODE(unit, port) && !PHY_EXTERNAL_MODE(unit, port)) ||
    231         PHY_PASSTHRU_MODE(unit, port)) {
    232         mode_1000x = LP_1000X_FIBER_MODE;
    233     }
    234     /* Allow property to override */
    235     if (soc_property_port_get(unit, port,
    236                               spn_SERDES_FIBER_PREF, mode_1000x)) {
    237         data16 |= LP_1000X_FIBER_MODE;
    238     } else {
    239         data16 &= ~LP_1000X_FIBER_MODE;
    240     }
    241     if (soc_property_port_get(unit, port, 
    242                               spn_SERDES_SGMII_MASTER, FALSE)) {
    243         data16 |= LP_1000X_SGMII_MASTER;
    244         mask16 |= LP_1000X_SGMII_MASTER;
    245     }
    246 
    247     SOC_IF_ERROR_RETURN
    248         (MODIFY_QSGMII65_1000X_CTRL1r(unit, pc, data16, mask16));   
    249 
    250     data16 = LP_1000X_PAR_DET_EN; 
    251     mask16 = LP_1000X_FILTER_FORCE_EN | 
    252              LP_1000X_FORCE_XMIT_DATA_ON_TXSIDE |
    253              LP_1000X_PAR_DET_EN;
    254     if ((PHY_EXTERNAL_MODE(unit, port) && PHY_PASSTHRU_MODE(unit, port)) ||
    255         (!PHY_EXTERNAL_MODE(unit, port) && PHY_FIBER_MODE(unit, port))) {
    256         /* Wait 10ms for sync status before a valid link is 
    257          * established when auto-negotiation is disabled.
    258          */
    259         data16 |= LP_1000X_FILTER_FORCE_EN;
    260     } 
    261    
    262     SOC_IF_ERROR_RETURN
    263         (MODIFY_QSGMII65_1000X_CTRL2r(unit, pc, data16, mask16));
    264 
    265     if (soc_property_port_get(unit, port, "serdes_fifo_low_latency", 0)) {
    266         data16 = LP_1000X_FREQ_LOCK_ELASTICITY_RX |
    267                  LP_1000X_FREQ_LOCK_ELASTICITY_TX;
    268         mask16 = LP_1000X_FIFO_ELASTICITY_MASK |
    269                  LP_1000X_FREQ_LOCK_ELASTICITY_RX |
    270                  LP_1000X_FREQ_LOCK_ELASTICITY_TX;
    271         SOC_IF_ERROR_RETURN
    272             (MODIFY_QSGMII65_1000X_CTRL3r(unit, pc, data16, mask16));
    273     }
    274 
    275 #if WORKAROUND_FIX
    276 #ifdef BCM_HAWKEYE_SUPPORT  
    277     if (soc_feature(unit, soc_feature_hawkeye_a0_war)) {
    278         /* Workaroud :
    279          * change the TX driver register to value 170H 
    280          * for revision A0 of HAWKEYE and PHY 54684
    281          * (Addr : 0x8067)
    282          */
    283         if(pc->lane_num == 0){
    284             SOC_IF_ERROR_RETURN
    285                 (_phy_qsgmii65_tx_control_set(unit, pc, port));
    286         }   
    287 
    288         /* Workaroud :
    289          * Make disparity error check configuration 
    290          */
    291         if((pc->lane_num == 0) || (pc->lane_num == 4)){
    292                 SOC_IF_ERROR_RETURN   
    293                     (QSGMII65_REG_WRITE(unit, pc, 0x00, 0x000080ba, 0x00d0));   
    294                 SOC_IF_ERROR_RETURN   
    295                     (QSGMII65_REG_WRITE(unit, pc, 0x00, 0x00008105, 0xf000));   
    296         }   
    297     }
    298 #endif
    299 #endif
    300     LOG_INFO(BSL_LS_SOC_PHY,
    301              (BSL_META_U(unit,
    302                          "phy_qsgmii65_init: u=%d p=%d %s\n"),
    303               unit, port, 
    304               PHY_FIBER_MODE(unit, port)? "Fiber" : "Copper"));
    305 
    306     return SOC_E_NONE;
    307 }
    308 
    309 
    310 /*
    311  * Function:
    312  *      phy_qsgmii65_init
    313  * Purpose:     
    314  *      Initialize qsgmii65 internal PHY driver
    315  * Parameters:
    316  *      unit - StrataSwitch unit #.
    317  *      port - StrataSwitch port #. 
    318  * Returns:     
    319  *      SOC_E_NONE
    320  * Notes:
    321  *      This function implements the bulk part of phy_qsgmii65_init and
    322  *      provides a method for initializing the SerDes when it is used
    323  *      as an intermediate PHY between the MAC and an external PHY. 
    324  *      In the latter case the PHY driver reset callback should be
    325  *      called only once, and this has already been done by the 
    326  *      external PHY driver init function.
    327  */
    328 
    329 STATIC int
    330 phy_qsgmii65_init(int unit, soc_port_t port)
    331 {
    332 
    333     LOG_INFO(BSL_LS_SOC_PHY,
    334              (BSL_META_U(unit,
    335                          "phy_qsgmii65_init: u=%d p=%d\n"),
    336               unit, port));
    337 
    338     if (!PHY_EXTERNAL_MODE(unit, port)) {
    339          /* PHY reset callbacks */
    340         SOC_IF_ERROR_RETURN(soc_phy_reset(unit, port));
    341 
    342         /* No external PHY. SerDes is always in fiber mode. */
    343         if (soc_property_port_get(unit, port,
    344                                   spn_SERDES_FIBER_PREF, 1)) {
    345             PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER);
    346         } else {
    347             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER);
    348         }
    349 
    350     }
    351 
    352     SOC_IF_ERROR_RETURN
    353         (_phy_qsgmii65_init_no_reset(unit, port));
    354 
    355     return SOC_E_NONE;
    356 }
    357 
    358 /*
    359  * Function:    
    360  *      phy_qsgmii65_link_get
    361  * Purpose:
    362  *      Determine the current link up/down status
    363  * Parameters:
    364  *      unit - StrataSwitch unit #.
    365  *      port - StrataSwitch port #.
    366  *      link - (OUT) Boolean, true indicates link established.
    367  * Returns:
    368  *      SOC_E_XXX
    369  * Notes:
    370  *      MII_STATUS bit 2 reflects link state.
    371  */
    372 
    373 STATIC int
    374 phy_qsgmii65_link_get(int unit, soc_port_t port, int *link)
    375 {
    376     uint16       mii_stat;
    377     int          an_done;
    378     phy_ctrl_t  *pc;
    379 
    380     if (PHY_DISABLED_MODE(unit, port)) {
    381         *link = FALSE;
    382     } else {
    383         pc = INT_PHY_SW_STATE(unit, port);
    384 
    385         SOC_IF_ERROR_RETURN
    386             (READ_QSGMII65_MII_STATr(unit, pc, &mii_stat));
    387 
    388         *link = ((mii_stat & MII_STAT_LA) != 0);
    389 
    390         if (pc->fiber.autoneg_enable) {
    391             /* If autoneg is enabled, check for autoneg done. */
    392             an_done = ((mii_stat & MII_STAT_AN_DONE) != 0);
    393 
    394             *link = (*link) && (an_done);
    395         }
    396     }
    397 
    398     return SOC_E_NONE;
    399 }
    400 
    401 /*
    402  * Function:    
    403  *      phy_qsgmii65_enable_set
    404  * Purpose:     
    405  *      Enable or disable the physical interface.
    406  * Parameters:
    407  *      unit - StrataSwitch unit #.
    408  *      port - StrataSwitch port #. 
    409  *      enable - Boolean, true = enable PHY, false = disable.
    410  * Returns:     
    411  *      SOC_E_XXX
    412  * Notes:
    413  *      The PHY is held in reset when disabled.  Also, the
    414  *      MISC_CONTROL.IDDQ bit must be set to 1 so the remote partner
    415  *      sees link down.
    416  */
    417 
    418 STATIC int
    419 phy_qsgmii65_enable_set(int unit, soc_port_t port, int enable)
    420 {
    421     LOG_INFO(BSL_LS_SOC_PHY,
    422              (BSL_META_U(unit,
    423                          "phy_qsgmii65_enable_set: u=%d p=%d en=%d\n"),
    424               unit, port, enable));
    425     if (enable) {
    426         PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE);
    427 
    428         SOC_IF_ERROR_RETURN
    429             (_phy_qsgmii65_notify_resume(unit, port, PHY_STOP_PHY_DIS));
    430     } else {
    431         PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE);
    432 
    433         SOC_IF_ERROR_RETURN
    434             (_phy_qsgmii65_notify_stop(unit, port, PHY_STOP_PHY_DIS));
    435     }
    436 
    437     return SOC_E_NONE;
    438 }
    439 
    440 
    441 STATIC int
    442 _phy_qsgmii65_sgmii_speed_set(int unit, soc_port_t port, int speed)
    443 {
    444     uint16 mii_ctrl;
    445     phy_ctrl_t  *pc;
    446 
    447     pc = INT_PHY_SW_STATE(unit, port);
    448 
    449     switch (speed) {
    450         case 10:
    451             mii_ctrl = MII_CTRL_SS_10;
    452             break;
    453         case 100:
    454             mii_ctrl = MII_CTRL_SS_100;
    455             break;
    456         case 0:
    457         case 1000:  
    458             mii_ctrl = MII_CTRL_SS_1000;
    459             break;
    460         default:
    461             return SOC_E_CONFIG;
    462     } 
    463     SOC_IF_ERROR_RETURN
    464         (MODIFY_QSGMII65_MII_CTRLr(unit, pc, mii_ctrl, MII_CTRL_SS_MASK));
    465     return SOC_E_NONE;
    466 }
    467 
    468 STATIC int
    469 _phy_qsgmii65_1000x_speed_set(int unit, soc_port_t port, int speed)
    470 {
    471     if (speed != 1000) { 
    472         return SOC_E_CONFIG;
    473     }
    474     return SOC_E_NONE;
    475 }
    476 
    477 /*
    478  * Function:    
    479  *      phy_qsgmii65_speed_set
    480  * Purpose:     
    481  *      Set the current operating speed (forced).
    482  * Parameters:
    483  *      unit - StrataSwitch unit #.
    484  *      port - StrataSwitch port #. 
    485  *      speed - Speed to set.
    486  * Returns:     
    487  *      SOC_E_XXX
    488  */
    489 
    490 STATIC int
    491 phy_qsgmii65_speed_set(int unit, soc_port_t port, int speed)
    492 {
    493     uint16              fiber_status;
    494     phy_ctrl_t  *pc;
    495     int                 rv;
    496 
    497     pc = INT_PHY_SW_STATE(unit, port);
    498     rv = SOC_E_NONE;
    499 
    500     SOC_IF_ERROR_RETURN
    501         (READ_QSGMII65_1000X_STAT1r(unit, pc, &fiber_status));
    502 
    503     if (fiber_status & LP_1000X_STATUS1_SGMII_MODE) {
    504         rv = _phy_qsgmii65_sgmii_speed_set(unit, port, speed);
    505     } else {
    506         rv = _phy_qsgmii65_1000x_speed_set(unit, port, speed);
    507     }
    508 
    509     if (SOC_SUCCESS(rv)) {
    510         pc->fiber.force_speed = speed;
    511     }
    512 
    513     LOG_INFO(BSL_LS_SOC_PHY,
    514              (BSL_META_U(unit,
    515                          "phy_qsgmii65_speed_set: u=%d p=%d speed=%d rv=%d\n"),
    516               unit, port, speed, rv));
    517     
    518     return rv;
    519 }
    520 
    521 STATIC int 
    522 _phy_qsgmii65_sgmii_speed_get(int unit, soc_port_t port, int *speed)
    523 {
    524     uint16 mii_ctrl, mii_stat, mii_anp;
    525     phy_ctrl_t  *pc;
    526 
    527     pc = INT_PHY_SW_STATE(unit, port);
    528 
    529     SOC_IF_ERROR_RETURN
    530         (READ_QSGMII65_MII_CTRLr(unit, pc, &mii_ctrl));
    531     SOC_IF_ERROR_RETURN
    532         (READ_QSGMII65_MII_STATr(unit, pc, &mii_stat));
    533  
    534     if (mii_ctrl & MII_CTRL_AE) { /*Auto-negotiation enabled */  
    535         if (!(mii_stat & MII_STAT_AN_DONE)) { /* Auto-neg NOT complete */
    536             *speed = 0;
    537             return SOC_E_NONE;
    538         } else { /* Read Advertise link partner */
    539             SOC_IF_ERROR_RETURN
    540                 (READ_QSGMII65_MII_ANPr(unit, pc, &mii_anp));
    541             if (mii_anp & MII_ANP_SGMII_MODE) {
    542                 switch(mii_anp & MII_ANP_SGMII_SS_MASK) {
    543                 case MII_ANP_SGMII_SS_1000:
    544                     *speed = 1000;
    545                     break;
    546                 case MII_ANP_SGMII_SS_100:
    547                     *speed = 100;
    548                     break;
    549                 case MII_ANP_SGMII_SS_10:
    550                     *speed = 10;
    551                     break;
    552                 default:
    553                     return SOC_E_INTERNAL;
    554                 }
    555             }
    556         }
    557     } else {  /* Forced speed */
    558         switch(mii_ctrl & MII_CTRL_SS_MASK) {
    559         case MII_CTRL_SS_10:
    560             *speed = 10; 
    561             break;
    562         case MII_CTRL_SS_100:
    563             *speed = 100;
    564             break;
    565         case MII_CTRL_SS_1000:
    566             *speed = 1000;
    567             break;
    568         default:
    569             return SOC_E_INTERNAL;
    570         } 
    571     }
    572     return SOC_E_NONE;
    573 }
    574 
    575 STATIC int
    576 _phy_qsgmii65_1000x_speed_get(int unit, soc_port_t port, int *speed)
    577 {
    578     *speed = 1000;
    579 
    580     return SOC_E_NONE;
    581 }
    582 
    583 /*
    584  * Function:    
    585  *      phy_qsgmii65_speed_get
    586  * Purpose:     
    587  *      Get the current operating speed. If autoneg is enabled, 
    588  *      then operating mode is returned, otherwise forced mode is returned.
    589  * Parameters:
    590  *      unit - StrataSwitch unit #.
    591  *      port - StrataSwitch port #. 
    592  *      speed - Current port speed. 
    593  * Returns:     
    594  *      SOC_E_XXX
    595  */
    596 
    597 STATIC int
    598 phy_qsgmii65_speed_get(int unit, soc_port_t port, int *speed)
    599 {
    600     uint16              fiber_status;
    601     phy_ctrl_t  *pc;
    602 
    603     pc = INT_PHY_SW_STATE(unit, port);
    604 
    605     *speed = 1000;
    606 
    607     SOC_IF_ERROR_RETURN
    608         (READ_QSGMII65_1000X_STAT1r(unit, pc, &fiber_status));
    609 
    610     if (fiber_status & LP_1000X_STATUS1_SGMII_MODE) {
    611         SOC_IF_ERROR_RETURN
    612             (_phy_qsgmii65_sgmii_speed_get(unit, port, speed));
    613     } else {
    614         SOC_IF_ERROR_RETURN
    615             (_phy_qsgmii65_1000x_speed_get(unit, port, speed));
    616     }
    617 
    618     return SOC_E_NONE;
    619 }
    620 
    621 /*
    622  * Function:    
    623  *      phy_qsgmii65_an_set
    624  * Purpose:     
    625  *      Enable or disabled auto-negotiation on the specified port.
    626  * Parameters:
    627  *      unit - StrataSwitch unit #.
    628  *      port - StrataSwitch port #. 
    629  *      an - Boolean, if true, auto-negotiation is enabled 
    630  *              (and/or restarted). If false, autonegotiation is disabled.
    631  * Returns:     
    632  *      SOC_E_XXX
    633  */
    634 
    635 STATIC int
    636 phy_qsgmii65_an_set(int unit, soc_port_t port, int an)
    637 {
    638     phy_ctrl_t  *pc;
    639     uint16             an_enable;
    640     uint16             auto_det;
    641 
    642     pc = INT_PHY_SW_STATE(unit, port);
    643 
    644     LOG_INFO(BSL_LS_SOC_PHY,
    645              (BSL_META_U(unit,
    646                          "phy_qsgmii65_an_set: u=%d p=%d an=%d\n"),
    647               unit, port, an));
    648 
    649     an_enable = 0; 
    650     auto_det  = 0;
    651     if (an) {
    652         an_enable = MII_CTRL_AE | MII_CTRL_RAN;
    653         if (soc_property_port_get(unit, port,
    654                                   spn_SERDES_AUTOMEDIUM, FALSE)) {
    655             auto_det = LP_1000X_AUTO_DETECT; 
    656         }
    657     }
    658 
    659     SOC_IF_ERROR_RETURN
    660         (MODIFY_QSGMII65_1000X_CTRL1r(unit, pc, 
    661                        auto_det, LP_1000X_AUTO_DETECT));
    662 
    663     /* Enable/Disable and Restart autonegotiation (self-clearing bit) */
    664     SOC_IF_ERROR_RETURN
    665         (MODIFY_QSGMII65_MII_CTRLr(unit, pc, an_enable,
    666                        MII_CTRL_AE | MII_CTRL_RAN));
    667 
    668     pc->fiber.autoneg_enable = an;
    669 
    670     return SOC_E_NONE;
    671 }
    672 
    673 /*
    674  * Function:    
    675  *      phy_qsgmii65_an_get
    676  * Purpose:
    677  *      Get the current auto-negotiation status (enabled/busy)
    678  * Parameters:
    679  *      unit - StrataSwitch unit #.
    680  *      port - StrataSwitch port #.
    681  *      an - (OUT) if true, auto-negotiation is enabled.
    682  *      an_done - (OUT) if true, auto-negotiation is complete.
    683  *              This value is undefined if an == false.
    684  * Returns:
    685  *      SOC_E_XXX
    686  */
    687 
    688 STATIC int
    689 phy_qsgmii65_an_get(int unit, soc_port_t port, int *an, int *an_done)
    690 {
    691     uint16      ctrl, stat;
    692     phy_ctrl_t  *pc;
    693 
    694     pc = INT_PHY_SW_STATE(unit, port);
    695 
    696     SOC_IF_ERROR_RETURN
    697         (READ_QSGMII65_MII_CTRLr(unit, pc, &ctrl));
    698 
    699     *an = (ctrl & MII_CTRL_AE) != 0;
    700 
    701     SOC_IF_ERROR_RETURN
    702         (READ_QSGMII65_MII_STATr(unit, pc, &stat));
    703 
    704     *an_done = (stat & MII_STAT_AN_DONE) != 0;
    705 
    706     LOG_INFO(BSL_LS_SOC_PHY,
    707              (BSL_META_U(unit,
    708                          "phy_serdes_an_get: u=%d p=%d an=%d an_done=%d\n"),
    709               unit, port, *an, *an_done));
    710 
    711     return SOC_E_NONE;
    712 }
    713 
    714 /*
    715  * Function:
    716  *      phy_qsgmii65_adv_local_set
    717  * Purpose:
    718  *      Set the current advertisement for auto-negotiation.
    719  * Parameters:
    720  *      unit - StrataSwitch unit #.
    721  *      port - StrataSwitch port #.
    722  *      mode - Port mode mask indicating supported options/speeds.
    723  * Returns:
    724  *      SOC_E_XXX
    725  */
    726 STATIC int
    727 phy_qsgmii65_adv_local_set(int unit, soc_port_t port, soc_port_mode_t mode)
    728 {
    729     uint16              an_adv;
    730     phy_ctrl_t  *pc;
    731 
    732     /* Note:
    733      * We assume that switch SerDes is always used as slave when
    734      * the port is in SGMII mode. Therefore, the adv_local_set is applicable
    735      * only for 1000BASE-X mode and supported only clause 37 autoneg.
    736      */
    737     pc = INT_PHY_SW_STATE(unit, port);
    738 
    739     an_adv  = 0;
    740 
    741     /*
    742      * Set advertised duplex (only FD supported).
    743      */
    744     if (mode & SOC_PM_1000MB_FD) {
    745         an_adv |= MII_ANA_C37_FD;
    746     }
    747 
    748     /*
    749      * Set advertised pause bits in link code word.
    750      */
    751     switch (mode & SOC_PM_PAUSE) {
    752     case SOC_PM_PAUSE_TX:
    753         an_adv |= MII_ANA_C37_ASYM_PAUSE;
    754         break;
    755     case SOC_PM_PAUSE_RX:
    756         an_adv |= MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE;
    757         break;
    758     case SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX:
    759         an_adv |= MII_ANA_C37_PAUSE;
    760         break;
    761     }
    762 
    763     SOC_IF_ERROR_RETURN
    764         (MODIFY_QSGMII65_MII_ANAr(unit, pc, an_adv,
    765                                 MII_ANA_C37_ASYM_PAUSE | MII_ANA_C37_PAUSE |
    766                                 MII_ANA_C37_FD | MII_ANA_C37_HD));
    767 
    768     LOG_INFO(BSL_LS_SOC_PHY,
    769              (BSL_META_U(unit,
    770                          "phy_serdes_adv_local_set: u=%d p=%d adv=%s%s%s\n"),
    771               unit, port,
    772               (mode & SOC_PM_1000MB_FD) ? "1000MB " : "",
    773               (mode & SOC_PM_PAUSE_TX)  ? "PAUSE_TX " : "",
    774               (mode & SOC_PM_PAUSE_RX)  ? "PAUSE_TX " : ""));
    775     return SOC_E_NONE;
    776 }
    777 
    778 /*
    779  * Function:   
    780  *      phy_qsgmii65_adv_local_get
    781  * Purpose:    
    782  *      Get the current advertisement for auto-negotiation.
    783  * Parameters:
    784  *      unit - StrataSwitch unit #.
    785  *      port - StrataSwitch port #.
    786  *      mode - (OUT) Port mode mask indicating supported options/speeds.
    787  * Returns:    
    788  *      SOC_E_XXX
    789  */
    790 
    791 STATIC int
    792 phy_qsgmii65_adv_local_get(int unit, soc_port_t port, soc_port_mode_t *mode)
    793 {
    794     uint16      an_adv;
    795     phy_ctrl_t  *pc;
    796 
    797     pc = INT_PHY_SW_STATE(unit, port);
    798 
    799     *mode = 0;
    800 
    801     SOC_IF_ERROR_RETURN
    802         (READ_QSGMII65_MII_ANAr(unit, pc, &an_adv));
    803 
    804     if (an_adv & MII_ANA_C37_FD) {
    805         *mode |= SOC_PM_1000MB_FD;
    806     }
    807 
    808     switch (an_adv & (MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE)) {
    809     case MII_ANA_C37_PAUSE:
    810         *mode |= SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX;
    811         break;
    812     case MII_ANA_C37_ASYM_PAUSE:
    813         *mode |= SOC_PM_PAUSE_TX;
    814         break;
    815     case MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE:
    816         *mode |= SOC_PM_PAUSE_RX;
    817         break;
    818     }
    819 
    820     return SOC_E_NONE;
    821 }
    822 
    823 STATIC int
    824 _phy_qsgmii65_sgmii_adv_remote_get(int unit, soc_port_t port,
    825                                 soc_port_mode_t *mode)
    826 {
    827     uint16              anlpa;
    828     soc_port_mode_t     duplex;
    829     phy_ctrl_t  *pc;
    830 
    831     pc = INT_PHY_SW_STATE(unit, port);
    832 
    833     *mode = 0;
    834 
    835     SOC_IF_ERROR_RETURN
    836         (READ_QSGMII65_MII_ANPr(unit, pc, &anlpa));
    837 
    838     switch (anlpa & MII_ANP_SGMII_SS_MASK) {
    839     case MII_ANP_SGMII_SS_10:
    840         *mode = SOC_PM_10MB;
    841         break;
    842     case MII_ANP_SGMII_SS_100:
    843         *mode = SOC_PM_100MB;
    844         break;
    845     case MII_ANP_SGMII_SS_1000:
    846         *mode = SOC_PM_1000MB;
    847         break;
    848     }
    849 
    850     duplex = (anlpa & MII_ANP_SGMII_FD) ? SOC_PM_FD : SOC_PM_HD;
    851 
    852     *mode = (*mode) & duplex;
    853 
    854     return SOC_E_NONE;
    855 }
    856 
    857 STATIC int
    858 _phy_qsgmii65_1000x_adv_remote_get(int unit, soc_port_t port,
    859                                 soc_port_mode_t *mode)
    860 {
    861     uint16              anlpa;
    862     phy_ctrl_t  *pc;
    863 
    864     pc = INT_PHY_SW_STATE(unit, port);
    865 
    866     *mode = 0;
    867 
    868     SOC_IF_ERROR_RETURN
    869         (READ_QSGMII65_MII_ANPr(unit, pc, &anlpa));
    870 
    871     if (anlpa & MII_ANP_C37_FD) {
    872         *mode |= SOC_PM_1000MB_FD;
    873     }
    874 
    875     if (anlpa & MII_ANP_C37_HD) {
    876         *mode |= SOC_PM_1000MB_HD;
    877     }
    878     
    879     switch (anlpa &
    880             (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) {
    881     case MII_ANP_C37_PAUSE:
    882         *mode |= SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX;
    883         break;
    884     case MII_ANP_C37_ASYM_PAUSE:
    885         *mode |= SOC_PM_PAUSE_TX;
    886         break;
    887     case MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE:
    888         *mode |= SOC_PM_PAUSE_RX;
    889         break;
    890     }
    891 
    892     return SOC_E_NONE;
    893 }
    894 
    895 /*
    896  * Function:
    897  *      phy_qsgmii65_adv_remote_get
    898  * Purpose:
    899  *      Get partner's current advertisement for auto-negotiation.
    900  * Parameters:
    901  *      unit - StrataSwitch unit #.
    902  *      port - StrataSwitch port #.
    903  *      mode - (OUT) Port mode mask indicating supported options/speeds.
    904  * Returns:
    905  *      SOC_E_XXX
    906  */
    907 
    908 int
    909 phy_qsgmii65_adv_remote_get(int unit, soc_port_t port, soc_port_mode_t *mode)
    910 {
    911     uint16              fiber_status;
    912     phy_ctrl_t  *pc;
    913 
    914     pc = INT_PHY_SW_STATE(unit, port);
    915 
    916     SOC_IF_ERROR_RETURN
    917         (READ_QSGMII65_1000X_STAT1r(unit, pc, &fiber_status));
    918 
    919     if (fiber_status & SERDES_1000X_STAT1_SGMII_MODE) {
    920         SOC_IF_ERROR_RETURN
    921             (_phy_qsgmii65_sgmii_adv_remote_get(unit, port, mode));
    922     } else {
    923         SOC_IF_ERROR_RETURN
    924             (_phy_qsgmii65_1000x_adv_remote_get(unit, port, mode));
    925     }
    926 
    927     LOG_INFO(BSL_LS_SOC_PHY,
    928              (BSL_META_U(unit,
    929                          "phy_serdes_adv_remote_get: u=%d p=%d adv=%s%s%s\n"),
    930               unit, port,
    931               (*mode & SOC_PM_1000MB_FD) ? "1000MB " : "",
    932               (*mode & SOC_PM_PAUSE_TX)  ? "PAUSE_TX " : "",
    933               (*mode & SOC_PM_PAUSE_RX)  ? "PAUSE_TX " : ""));
    934 
    935     return SOC_E_NONE;
    936 }
    937     
    938 /*  
    939  * Function:    
    940  *      phy_qsgmii65_lb_set
    941  * Purpose:     
    942  *      Set the internal PHY loopback mode.
    943  * Parameters:
    944  *      unit - StrataSwitch unit #.
    945  *      port - StrataSwitch port #.
    946  *      loopback - Boolean: true = enable loopback, false = disable.
    947  * Returns:     
    948  *      SOC_E_XXX
    949  */ 
    950     
    951 STATIC int
    952 phy_qsgmii65_lb_set(int unit, soc_port_t port, int enable)
    953 {   
    954     uint16              ctrl;
    955     phy_ctrl_t  *pc;
    956     int                 rv;
    957     
    958     pc = INT_PHY_SW_STATE(unit, port);
    959     
    960     ctrl = (enable) ?MII_CTRL_LE : 0;
    961 
    962     rv = MODIFY_QSGMII65_MII_CTRLr(unit, pc,
    963                                ctrl, MII_CTRL_LE);
    964  
    965     LOG_INFO(BSL_LS_SOC_PHY,
    966              (BSL_META_U(unit,
    967                          "phy_serdes_lb_set: u=%d p=%d lb=%d rv=%d\n"),
    968               unit, port, enable, rv));
    969 
    970     return rv;
    971 }
    972 
    973 /*
    974  * Function:   
    975  *      phy_serdes_lb_get
    976  * Purpose:    
    977  *      Get the local PHY loopback mode.
    978  * Parameters:
    979  *      unit - StrataSwitch unit #.
    980  *      port - StrataSwitch port #.
    981  *      loopback - (OUT) Boolean: true = enable loopback, false = disable.
    982  * Returns:    
    983  *      SOC_E_XXX
    984  */
    985 
    986 STATIC int
    987 phy_qsgmii65_lb_get(int unit, soc_port_t port, int *enable)
    988 {
    989     uint16      ctrl;
    990     phy_ctrl_t  *pc;
    991 
    992     pc = INT_PHY_SW_STATE(unit, port);
    993     SOC_IF_ERROR_RETURN
    994         (READ_QSGMII65_MII_CTRLr(unit, pc, &ctrl));
    995 
    996     *enable = (ctrl & MII_CTRL_LE) != 0;
    997 
    998     return SOC_E_NONE;
    999 }
   1000 
   1001 
   1002 /*
   1003  * Function:    
   1004  *      phy_qsgmii65_ability_get
   1005  * Purpose:     
   1006  *      Get the abilities of the internal PHY.
   1007  * Parameters:
   1008  *      unit - StrataSwitch unit #.
   1009  *      port - StrataSwitch port #. 
   1010  *      mode - (OUT) Port mode mask indicating supported options/speeds.
   1011  * Returns:     
   1012  *      SOC_E_XXX
   1013  */
   1014 
   1015 STATIC int
   1016 phy_qsgmii65_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode)
   1017 {
   1018     uint16      fiber_status;
   1019     phy_ctrl_t *pc;
   1020 
   1021     pc = INT_PHY_SW_STATE(unit, port);
   1022     SOC_IF_ERROR_RETURN
   1023         (READ_QSGMII65_1000X_STAT1r(unit, pc, &fiber_status));
   1024 
   1025     if (fiber_status & LP_1000X_STATUS1_SGMII_MODE) {
   1026         *mode = (SOC_PM_10MB | SOC_PM_100MB | SOC_PM_1000MB_FD |
   1027                  SOC_PM_LB_PHY | SOC_PM_GMII);
   1028     } else {
   1029         *mode = (SOC_PM_1000MB_FD | SOC_PM_100MB_FD |
   1030                  SOC_PM_PAUSE | SOC_PM_PAUSE_ASYMM | SOC_PM_AN | 
   1031                  SOC_PM_LB_PHY | SOC_PM_GMII);
   1032     }
   1033 
   1034 
   1035     
   1036     return SOC_E_NONE;
   1037 }
   1038 
   1039 /*
   1040  * Function:
   1041  *      _phy_qsgmii65_medium_config_update
   1042  * Purpose:
   1043  *      Update the PHY with config parameters
   1044  * Parameters:
   1045  *      unit - StrataSwitch unit #.
   1046  *      port - StrataSwitch port #.
   1047  *      cfg - Config structure.
   1048  * Returns:
   1049  *      SOC_E_XXX
   1050  */
   1051 
   1052 STATIC int
   1053 _phy_qsgmii65_medium_config_update(int unit, soc_port_t port,
   1054                                 soc_phy_config_t *cfg)
   1055 {
   1056     SOC_IF_ERROR_RETURN
   1057         (phy_qsgmii65_speed_set(unit, port, cfg->force_speed));
   1058     SOC_IF_ERROR_RETURN
   1059         (phy_serdes_duplex_set(unit, port, cfg->force_duplex));
   1060     SOC_IF_ERROR_RETURN
   1061         (phy_serdes_adv_local_set(unit, port, cfg->autoneg_advert));
   1062     SOC_IF_ERROR_RETURN
   1063         (phy_qsgmii65_an_set(unit, port, cfg->autoneg_enable));
   1064 
   1065     return SOC_E_NONE;
   1066 }
   1067 
   1068 /*
   1069  * Function:
   1070  *      phy_qsgmii65_medium_config_set
   1071  * Purpose:
   1072  *      Set the operating parameters that are automatically selected
   1073  *      when medium switches type.
   1074  * Parameters:
   1075  *      unit - StrataSwitch unit #
   1076  *      port - Port number
   1077  *      medium - SOC_PORT_MEDIUM_COPPER/FIBER
   1078  *      cfg - Operating parameters
   1079  * Returns:
   1080  *      SOC_E_XXX
   1081  */
   1082 
   1083 STATIC int
   1084 phy_qsgmii65_medium_config_set(int unit, soc_port_t port, 
   1085                            soc_port_medium_t  medium,
   1086                            soc_phy_config_t  *cfg)
   1087 {
   1088 
   1089     phy_ctrl_t    *pc;
   1090 
   1091     pc = INT_PHY_SW_STATE(unit, port);
   1092 
   1093     /*
   1094      * Changes take effect immediately if the target medium is active.
   1095      */
   1096     switch (medium) {
   1097     case SOC_PORT_MEDIUM_FIBER:
   1098         /* Change the fiber modes */
   1099 
   1100         sal_memcpy(&pc->fiber, cfg, sizeof (pc->fiber));
   1101 
   1102         pc->fiber.autoneg_advert &= ADVERT_ALL_FIBER;
   1103         if (PHY_FIBER_MODE(unit, port)) {
   1104             SOC_IF_ERROR_RETURN
   1105                 (_phy_qsgmii65_medium_config_update(unit, port, &pc->fiber));
   1106         }
   1107         return SOC_E_NONE;
   1108     case SOC_PORT_MEDIUM_COPPER:
   1109         return SOC_E_UNAVAIL;
   1110     default:
   1111         return SOC_E_PARAM;
   1112     }
   1113 }
   1114 
   1115 STATIC int
   1116 _phy_qsgmii65_control_tx_driver_set(int unit, soc_port_t port,
   1117                                 soc_phy_control_t type, uint32 value)
   1118 {
   1119     uint16       data;  /* Temporary holder of reg value to be written */
   1120     uint16       mask;  /* Bit mask of reg value to be updated */
   1121     phy_ctrl_t  *pc;    /* PHY software state */
   1122 
   1123     pc = INT_PHY_SW_STATE(unit, port);
   1124 
   1125     SOC_IF_ERROR_RETURN
   1126         (READ_QSGMII65_1000X_STAT1r(unit, pc, &data));
   1127 
   1128     if (data & LP_1000X_STATUS1_SGMII_MODE) {
   1129         /* SGMII mode */
   1130         switch(type) {
   1131         case SOC_PHY_CONTROL_PREEMPHASIS:
   1132              data = (uint16)(value & 0xF);
   1133              data = data << 12;
   1134              mask = 0xf000;
   1135              SOC_IF_ERROR_RETURN
   1136                  (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask));
   1137              break;
   1138         case SOC_PHY_CONTROL_DRIVER_CURRENT:
   1139              data = (uint16)(value & 0xF);
   1140              data = data << 8;
   1141              mask = 0x0f00;
   1142              SOC_IF_ERROR_RETURN
   1143                  (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask));
   1144              break;
   1145         case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   1146              data = (uint16)(value & 0xF);
   1147              data = data << 4;
   1148              mask = 0x00f0;
   1149              SOC_IF_ERROR_RETURN
   1150                  (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask));
   1151              break;
   1152         default:
   1153              /* should never get here */
   1154              return SOC_E_PARAM;
   1155         }
   1156     } else {
   1157         /* 1000X mode */
   1158         switch(type) {
   1159         case SOC_PHY_CONTROL_PREEMPHASIS:
   1160              data = (uint16)(value & 0xF);
   1161              data = data << 12;
   1162              mask = 0xf000;
   1163              SOC_IF_ERROR_RETURN
   1164                  (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask));
   1165              break;
   1166         case SOC_PHY_CONTROL_DRIVER_CURRENT:
   1167              data = (uint16)(value & 0xF);
   1168              data = data << 8;
   1169              mask = 0x0f00;
   1170              SOC_IF_ERROR_RETURN
   1171                  (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask));
   1172              break;
   1173         case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   1174              data = (uint16)(value & 0xF);
   1175              data = data << 4;
   1176              mask = 0x00f0;
   1177              SOC_IF_ERROR_RETURN
   1178                  (MODIFY_QSGMII65_ANALOG_TX1r(unit, pc, data, mask));
   1179              break;
   1180         default:
   1181              /* should never get here */
   1182              return SOC_E_PARAM;
   1183         }
   1184     }
   1185 
   1186     return SOC_E_NONE;
   1187 }
   1188 
   1189 STATIC int
   1190 _phy_qsgmii65_control_tx_driver_get(int unit, soc_port_t port,
   1191                                 soc_phy_control_t type, uint32 *value)
   1192 {
   1193     uint16         data;   /* Temporary holder of a reg value */
   1194     phy_ctrl_t    *pc;     /* PHY software state */
   1195 
   1196     pc = INT_PHY_SW_STATE(unit, port);
   1197 
   1198     SOC_IF_ERROR_RETURN
   1199         (READ_QSGMII65_1000X_STAT1r(unit, pc, &data));
   1200 
   1201     if (data & LP_1000X_STATUS1_SGMII_MODE) {
   1202         /* SGMII mode */
   1203         switch(type) {
   1204         case SOC_PHY_CONTROL_PREEMPHASIS:
   1205              SOC_IF_ERROR_RETURN
   1206                  (READ_QSGMII65_ANALOG_TX1r(unit, pc, &data));
   1207              *value = (data & 0xf000) >> 12;
   1208              break;
   1209         case SOC_PHY_CONTROL_DRIVER_CURRENT:
   1210              SOC_IF_ERROR_RETURN
   1211                  (READ_QSGMII65_ANALOG_TX1r(unit, pc, &data));
   1212              *value = (data & 0x0f00) >> 8;
   1213              break;
   1214         case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   1215              SOC_IF_ERROR_RETURN
   1216                  (READ_QSGMII65_ANALOG_TX1r(unit, pc, &data));
   1217              *value = (data & 0x00f0) >> 4;
   1218              break;
   1219         default:
   1220              /* should never get here */
   1221              return SOC_E_PARAM;
   1222         }
   1223     } else {
   1224         /* 1000X mode */
   1225         switch(type) {
   1226         case SOC_PHY_CONTROL_PREEMPHASIS:
   1227              SOC_IF_ERROR_RETURN
   1228                  (READ_QSGMII65_ANALOG_TX1r(unit, pc, &data));
   1229              *value = (data & 0xf000) >> 12;
   1230              break;
   1231         case SOC_PHY_CONTROL_DRIVER_CURRENT:
   1232              SOC_IF_ERROR_RETURN
   1233                  (READ_QSGMII65_ANALOG_TX1r(unit, pc, &data));
   1234              *value = (data & 0x0f00) >> 8;
   1235              break;
   1236         case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   1237              SOC_IF_ERROR_RETURN
   1238                  (READ_QSGMII65_ANALOG_TX1r(unit, pc, &data));
   1239              *value = (data & 0x00f0) >> 4;
   1240              break;
   1241         default:
   1242              /* should never get here */
   1243              return SOC_E_PARAM;
   1244         }
   1245     }
   1246 
   1247     return SOC_E_NONE;
   1248 }
   1249 
   1250 /*
   1251  * Function:
   1252  *      phy_phyqsgmii65_control_set
   1253  * Purpose:
   1254  *      Configure PHY device specific control fucntion.
   1255  * Parameters:
   1256  *      unit  - StrataSwitch unit #.
   1257  *      port  - StrataSwitch port #.
   1258  *      type  - Control to update
   1259  *      value - New setting for the control
   1260  * Returns:
   1261  *      SOC_E_NONE
   1262  */
   1263 STATIC int
   1264 phy_qsgmii65_control_set(int unit, soc_port_t port,
   1265                      soc_phy_control_t type, uint32 value)
   1266 {
   1267     int rv;
   1268     /* coverity[mixed_enums] */
   1269     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
   1270         return SOC_E_PARAM;
   1271     }
   1272   
   1273     rv = SOC_E_UNAVAIL;
   1274     switch(type) {
   1275     case SOC_PHY_CONTROL_PREEMPHASIS:
   1276         /* fall through */
   1277     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   1278         /* fall through */
   1279     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   1280         rv = _phy_qsgmii65_control_tx_driver_set(unit, port, type, value);
   1281         break;
   1282     default:
   1283         rv = SOC_E_UNAVAIL;
   1284         break;
   1285     }
   1286     return rv;
   1287 }
   1288 /*
   1289  * Function:
   1290  *      phy_qsgmii65_control_get
   1291  * Purpose:
   1292  *      Get current control settign of the PHY.
   1293  * Parameters:
   1294  *      unit  - StrataSwitch unit #.
   1295  *      port  - StrataSwitch port #.
   1296  *      type  - Control to update
   1297  *      value - (OUT)Current setting for the control
   1298  * Returns:    
   1299  *      SOC_E_NONE
   1300  */
   1301 STATIC int
   1302 phy_qsgmii65_control_get(int unit, soc_port_t port,
   1303                      soc_phy_control_t type, uint32 *value)
   1304 {
   1305     int rv;
   1306 
   1307     if (NULL == value) {
   1308         return SOC_E_PARAM;
   1309     }
   1310     /* coverity[mixed_enums] */
   1311     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
   1312         return SOC_E_PARAM;
   1313     }
   1314   
   1315     rv = SOC_E_UNAVAIL;
   1316     switch(type) {
   1317     case SOC_PHY_CONTROL_PREEMPHASIS:
   1318         /* fall through */
   1319     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   1320         /* fall through */
   1321     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   1322         rv = _phy_qsgmii65_control_tx_driver_get(unit, port, type, value);
   1323         break;
   1324     default:
   1325         rv = SOC_E_UNAVAIL;
   1326         break;
   1327     }
   1328 
   1329     return rv;
   1330 }
   1331 
   1332 /*
   1333  * Function:
   1334  *      phy_qsgmii65_reg_read
   1335  * Purpose:
   1336  *      Routine to read PHY register
   1337  * Parameters:
   1338  *      uint         - BCM unit number
   1339  *      pc           - PHY state
   1340  *      flags        - Flags which specify the register type
   1341  *      phy_reg_addr - Encoded register address
   1342  *      phy_data     - (OUT) Value read from PHY register
   1343  * Note:
   1344  *      This register read function is not thread safe. Higher level
   1345  * function that calls this function must obtain a per port lock
   1346  * to avoid overriding register page mapping between threads.
   1347  */
   1348 STATIC int
   1349 phy_qsgmii65_reg_read(int unit, soc_port_t port, uint32 flags,
   1350                   uint32 phy_reg_addr, uint32 *phy_data)
   1351 {
   1352     uint16               data;     /* Temporary holder for phy_data */
   1353     phy_ctrl_t          *pc;      /* PHY software state */
   1354 
   1355     pc = INT_PHY_SW_STATE(unit, port);
   1356 
   1357     SOC_IF_ERROR_RETURN
   1358         (phy_reg_qsgmii_aer_read(unit, pc, phy_reg_addr, &data));
   1359 
   1360    *phy_data = data;
   1361 
   1362     return SOC_E_NONE;
   1363 }
   1364 
   1365 /*
   1366  * Function:
   1367  *      phy_qsgmii65_reg_write
   1368  * Purpose:
   1369  *      Routine to write PHY register
   1370  * Parameters:
   1371  *      uint         - BCM unit number
   1372  *      pc           - PHY state
   1373  *      flags        - Flags which specify the register type
   1374  *      phy_reg_addr - Encoded register address
   1375  *      phy_data     - Value write to PHY register
   1376  * Note:
   1377  *      This register read function is not thread safe. Higher level
   1378  * function that calls this function must obtain a per port lock
   1379  * to avoid overriding register page mapping between threads.
   1380  */
   1381 STATIC int
   1382 phy_qsgmii65_reg_write(int unit, soc_port_t port, uint32 flags,
   1383                    uint32 phy_reg_addr, uint32 phy_data)
   1384 {
   1385     uint16               data;     /* Temporary holder for phy_data */
   1386     phy_ctrl_t          *pc;      /* PHY software state */
   1387 
   1388     pc = INT_PHY_SW_STATE(unit, port);
   1389 
   1390     data      = (uint16) (phy_data & 0x0000FFFF);
   1391 
   1392     SOC_IF_ERROR_RETURN
   1393         (phy_reg_qsgmii_aer_write(unit, pc, phy_reg_addr, data));
   1394 
   1395     return SOC_E_NONE;
   1396 }  
   1397 
   1398 /*
   1399  * Function:
   1400  *      phy_qsgmii65_reg_modify
   1401  * Purpose:
   1402  *      Routine to write PHY register
   1403  * Parameters:
   1404  *      uint         - BCM unit number
   1405  *      pc           - PHY state
   1406  *      flags        - Flags which specify the register type
   1407  *      phy_reg_addr - Encoded register address
   1408  *      phy_mo_data  - New value for the bits specified in phy_mo_mask
   1409  *      phy_mo_mask  - Bit mask to modify
   1410  * Note:
   1411  *      This register read function is not thread safe. Higher level
   1412  * function that calls this function must obtain a per port lock
   1413  * to avoid overriding register page mapping between threads.
   1414  */
   1415 STATIC int
   1416 phy_qsgmii65_reg_modify(int unit, soc_port_t port, uint32 flags,
   1417                     uint32 phy_reg_addr, uint32 phy_data,
   1418                     uint32 phy_data_mask)
   1419 {
   1420     uint16               data;     /* Temporary holder for phy_data */
   1421     uint16               mask;
   1422     phy_ctrl_t    *pc;      /* PHY software state */
   1423 
   1424     pc = INT_PHY_SW_STATE(unit, port);
   1425 
   1426     data      = (uint16) (phy_data & 0x0000FFFF);
   1427     mask      = (uint16) (phy_data_mask & 0x0000FFFF);
   1428 
   1429     SOC_IF_ERROR_RETURN
   1430         (phy_reg_qsgmii_aer_modify(unit, pc, phy_reg_addr, data, mask));
   1431 
   1432     return SOC_E_NONE;
   1433 }
   1434 
   1435 STATIC int
   1436 phy_qsgmii65_notify(int unit, soc_port_t port,
   1437                  soc_phy_event_t event, uint32 value)
   1438 {
   1439     int             rv;
   1440 
   1441     if (event >= phyEventCount) {
   1442         return SOC_E_PARAM;
   1443     }
   1444 
   1445     rv = SOC_E_NONE;
   1446     switch(event) {
   1447     case phyEventInterface:
   1448         rv = (_phy_qsgmii65_notify_interface(unit, port, value));
   1449         break;
   1450     case phyEventDuplex:
   1451         rv = (_phy_qsgmii65_notify_duplex(unit, port, value));
   1452         break;
   1453     case phyEventSpeed:
   1454         rv = (_phy_qsgmii65_notify_speed(unit, port, value));
   1455         break;
   1456     case phyEventStop:
   1457         rv = (_phy_qsgmii65_notify_stop(unit, port, value));
   1458         break;
   1459     case phyEventResume:
   1460         rv = (_phy_qsgmii65_notify_resume(unit, port, value));
   1461         break;
   1462     case phyEventAutoneg:
   1463         rv = (phy_qsgmii65_an_set(unit, port, value));
   1464         break;
   1465     default:
   1466         rv = SOC_E_PARAM;
   1467         break;
   1468     }
   1469 
   1470     return rv;
   1471 }
   1472 
   1473 STATIC int
   1474 phy_qsgmii65_duplex_get(int unit, soc_port_t port, int *duplex)
   1475 {
   1476     uint16       reg0_16;
   1477     uint16       mii_ctrl;
   1478     phy_ctrl_t  *pc;
   1479 
   1480     pc = INT_PHY_SW_STATE(unit, port);
   1481     *duplex = TRUE;
   1482 
   1483     SOC_IF_ERROR_RETURN
   1484         (READ_QSGMII65_1000X_STAT1r(unit, pc, &reg0_16));
   1485 
   1486     if (reg0_16 & LP_1000X_STATUS1_SGMII_MODE) {
   1487     /* retrieve the duplex setting in SGMII mode */
   1488 
   1489         SOC_IF_ERROR_RETURN
   1490             (READ_QSGMII65_MII_CTRLr(unit, pc, &mii_ctrl));
   1491 
   1492         if (mii_ctrl & MII_CTRL_AE) {
   1493             SOC_IF_ERROR_RETURN
   1494                 (READ_QSGMII65_MII_ANPr(unit,pc,&reg0_16));
   1495 
   1496             /* make sure link partner is also in SGMII mode
   1497              * otherwise fall through to use the FD bit in MII_CTRL reg
   1498              */
   1499             if (reg0_16 & MII_ANP_SGMII_MODE) {
   1500                 if (reg0_16 & MII_ANP_SGMII_FD) {
   1501                     *duplex = TRUE;
   1502                 } else {
   1503                     *duplex = FALSE;
   1504                 }
   1505                 return SOC_E_NONE;
   1506             }
   1507         }
   1508         *duplex = (mii_ctrl & MII_CTRL_FD) ? TRUE : FALSE;
   1509     }
   1510     return SOC_E_NONE;
   1511 }
   1512 
   1513 /*
   1514  * Variable:    phy_qsgmii65drv_ge
   1515  * Purpose:     PHY Driver for Dozen SerDes Serdes PHY internal to Draco, 
   1516  */
   1517 phy_driver_t phy_qsgmii65_ge = {
   1518     "Internal QSGMII 65nm SERDES PHY Driver",
   1519     phy_qsgmii65_init,
   1520     phy_null_reset,
   1521     phy_qsgmii65_link_get, 
   1522     phy_qsgmii65_enable_set, 
   1523     phy_null_enable_get, 
   1524     phy_serdes_duplex_set, 
   1525     phy_qsgmii65_duplex_get,          /* duplex_get */
   1526     phy_qsgmii65_speed_set, 
   1527     phy_qsgmii65_speed_get, 
   1528     phy_serdes_master_set,              /* master_set */
   1529     phy_serdes_master_get,              /* master_get */
   1530     phy_qsgmii65_an_set,
   1531     phy_qsgmii65_an_get,
   1532     phy_qsgmii65_adv_local_set,
   1533     phy_qsgmii65_adv_local_get,
   1534     phy_qsgmii65_adv_remote_get,
   1535     phy_qsgmii65_lb_set,
   1536     phy_qsgmii65_lb_get,
   1537     phy_serdes_interface_set, 
   1538     phy_serdes_interface_get, 
   1539     phy_qsgmii65_ability_get,
   1540     NULL,
   1541     NULL,
   1542     phy_null_mdix_set,
   1543     phy_null_mdix_get,
   1544     phy_null_mdix_status_get,
   1545     phy_qsgmii65_medium_config_set,
   1546     phy_serdes_medium_config_get,
   1547     phy_serdes_medium_status,
   1548     NULL,                               /* phy_cable_diag  */
   1549     NULL,                               /* phy_link_change */
   1550     phy_qsgmii65_control_set,         /* phy_control_set */
   1551     phy_qsgmii65_control_get,         /* phy_control_get */
   1552     phy_qsgmii65_reg_read,
   1553     phy_qsgmii65_reg_write,
   1554     phy_qsgmii65_reg_modify,
   1555     phy_qsgmii65_notify
   1556 };
   1557 
   1558 /***********************************************************************
   1559  *
   1560  * PASS-THROUGH NOTIFY ROUTINES
   1561  */
   1562 
   1563 /*
   1564  * Function:
   1565  *      _phy_qsgmii65_notify_duplex
   1566  * Purpose:     
   1567  *      Program duplex if (and only if) qsgmii65 is an intermediate PHY.
   1568  * Parameters:
   1569  *      unit - StrataSwitch unit #.
   1570  *      port - StrataSwitch port #. 
   1571  *      duplex - Boolean, TRUE indicates full duplex, FALSE
   1572  *              indicates half.
   1573  * Returns:     
   1574  *      SOC_E_XXX
   1575  * Notes:
   1576  *      If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to
   1577  *      talk directly to an external fiber module.
   1578  *
   1579  *      If PHY_FLAGS_FIBER is clear, the PHY is being used in
   1580  *      pass-through mode to talk to an external SGMII PHY.
   1581  *
   1582  *      When used in pass-through mode, autoneg must be turned off and
   1583  *      the speed/duplex forced to match that of the external PHY.
   1584  */
   1585 
   1586 STATIC int
   1587 _phy_qsgmii65_notify_duplex(int unit, soc_port_t port, uint32 duplex)
   1588 {
   1589     int                 fiber;
   1590     uint16              mii_ctrl;
   1591     phy_ctrl_t  *pc;
   1592 
   1593     fiber = PHY_FIBER_MODE(unit, port);
   1594     pc    = INT_PHY_SW_STATE(unit, port);
   1595     LOG_INFO(BSL_LS_SOC_PHY,
   1596              (BSL_META_U(unit,
   1597                          "phy_qsgmii65_notify_duplex: "
   1598                          "u=%d p=%d duplex=%d fiber=%d\n"),
   1599               unit, port, duplex, fiber));
   1600 
   1601     if (SAL_BOOT_SIMULATION) {
   1602         return SOC_E_NONE;
   1603     }
   1604 
   1605     if (fiber) {
   1606         SOC_IF_ERROR_RETURN
   1607             (MODIFY_QSGMII65_MII_CTRLr(unit, pc, 
   1608                                   MII_CTRL_FD, MII_CTRL_FD));
   1609         return SOC_E_NONE;
   1610     }
   1611 
   1612     /* Put SERDES PHY in reset */
   1613 
   1614     SOC_IF_ERROR_RETURN
   1615         (_phy_qsgmii65_notify_stop(unit, port, PHY_STOP_DUPLEX_CHG));
   1616 
   1617     /* Update duplexity */
   1618     mii_ctrl = (duplex) ?MII_CTRL_FD : 0;
   1619     SOC_IF_ERROR_RETURN
   1620         (MODIFY_QSGMII65_MII_CTRLr(unit, pc, mii_ctrl, MII_CTRL_FD));
   1621 
   1622     /* Take SERDES PHY out of reset */
   1623     SOC_IF_ERROR_RETURN
   1624         (_phy_qsgmii65_notify_resume(unit, port, PHY_STOP_DUPLEX_CHG));
   1625 
   1626     /* Autonegotiation must be turned off to talk to external PHY if
   1627      * SGMII autoneg is not enabled.
   1628      */
   1629     if (!PHY_SGMII_AUTONEG_MODE(unit, port)) {
   1630         SOC_IF_ERROR_RETURN
   1631             (phy_qsgmii65_an_set(unit, port, FALSE));
   1632     }
   1633     return SOC_E_NONE;
   1634 }
   1635 
   1636 /*
   1637  * Function:
   1638  *      _phy_qsgmii65_notify_speed
   1639  * Purpose:     
   1640  *      Program duplex if (and only if) qsgmii65 is an intermediate PHY.
   1641  * Parameters:
   1642  *      unit - StrataSwitch unit #.
   1643  *      port - StrataSwitch port #. 
   1644  *      speed - Speed to program.
   1645  * Returns:     
   1646  *      SOC_E_XXX
   1647  * Notes:
   1648  *      If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to
   1649  *      talk directly to an external fiber module.
   1650  *
   1651  *      If PHY_FLAGS_FIBER is clear, the PHY is being used in
   1652  *      pass-through mode to talk to an external SGMII PHY.
   1653  *
   1654  *      When used in pass-through mode, autoneg must be turned off and
   1655  *      the speed/duplex forced to match that of the external PHY.
   1656  */
   1657 
   1658 STATIC int
   1659 _phy_qsgmii65_notify_speed(int unit, soc_port_t port, uint32 speed)
   1660 {
   1661     int          fiber;
   1662     uint16       fiber_status;
   1663     phy_ctrl_t  *pc;
   1664 
   1665     pc    = INT_PHY_SW_STATE(unit, port);
   1666     fiber = PHY_FIBER_MODE(unit, port);
   1667 
   1668     LOG_INFO(BSL_LS_SOC_PHY,
   1669              (BSL_META_U(unit,
   1670                          "_phy_qsgmii65_notify_speed: "
   1671                          "u=%d p=%d speed=%d fiber=%d\n"),
   1672               unit, port, speed, fiber));
   1673 
   1674     if (SAL_BOOT_SIMULATION) {
   1675         return SOC_E_NONE;
   1676     }
   1677  
   1678     SOC_IF_ERROR_RETURN
   1679         (READ_QSGMII65_1000X_STAT1r(unit, pc, &fiber_status));
   1680 
   1681     if (fiber && !(fiber_status & LP_1000X_STATUS1_SGMII_MODE)) {
   1682         if ((speed != 0) && (speed != 100) && (speed != 1000)) {
   1683             return SOC_E_CONFIG;
   1684         }
   1685     }
   1686 
   1687     /* Put SERDES PHY in reset */
   1688     SOC_IF_ERROR_RETURN
   1689         (_phy_qsgmii65_notify_stop(unit, port, PHY_STOP_SPEED_CHG));
   1690 
   1691     /* Update speed */
   1692     SOC_IF_ERROR_RETURN
   1693         (_phy_qsgmii65_sgmii_speed_set(unit, port, speed));
   1694 
   1695     /* Take SERDES PHY out of reset */
   1696     SOC_IF_ERROR_RETURN
   1697         (_phy_qsgmii65_notify_resume(unit, port, PHY_STOP_SPEED_CHG));
   1698 
   1699     /* Autonegotiation must be turned off to talk to external PHY */
   1700     if (!PHY_SGMII_AUTONEG_MODE(unit, port) && !fiber) {
   1701         SOC_IF_ERROR_RETURN
   1702             (phy_qsgmii65_an_set(unit, port, FALSE));
   1703     }
   1704 
   1705     return SOC_E_NONE;
   1706 }
   1707 
   1708 /*
   1709  * Function:
   1710  *      _phy_qsgmii65_stop
   1711  * Purpose:
   1712  *      Put qsgmii65 SERDES in or out of reset depending on conditions
   1713  */
   1714 
   1715 STATIC int
   1716 _phy_qsgmii65_stop(int unit, soc_port_t port)
   1717 {
   1718     uint16              mii_ctrl;
   1719     int                 stop, copper;
   1720     phy_ctrl_t  *pc;
   1721 
   1722     pc = INT_PHY_SW_STATE(unit, port);
   1723 
   1724     copper = (pc->stop & 
   1725               PHY_STOP_COPPER) != 0;
   1726 
   1727     stop = ((pc->stop &
   1728              (PHY_STOP_PHY_DIS |
   1729               PHY_STOP_DRAIN)) != 0 ||
   1730             (copper &&
   1731              (pc->stop &
   1732               (PHY_STOP_MAC_DIS |
   1733                PHY_STOP_DUPLEX_CHG |
   1734                PHY_STOP_SPEED_CHG)) != 0));
   1735 
   1736     LOG_INFO(BSL_LS_SOC_PHY,
   1737              (BSL_META_U(unit,
   1738                          "phy_qsgmii65_stop: u=%d p=%d copper=%d"
   1739                          " stop=%d flg=0x%x\n"),
   1740               unit, port, copper, stop,
   1741               pc->stop));
   1742 
   1743     mii_ctrl = (stop) ?MII_CTRL_PD : 0;
   1744 #ifdef BCM_HAWKEYE_SUPPORT
   1745     if (SOC_IS_HAWKEYE(unit)) {
   1746         uint16 dev_id = 0;   
   1747         uint8 rev_id = 0;   
   1748     
   1749         soc_cm_get_id(unit, &dev_id, &rev_id);
   1750         if ((pc->lane_num == 0) && 
   1751            ((dev_id == BCM53313_DEVICE_ID) || (dev_id == BCM53312_DEVICE_ID))) { 
   1752              /* Issue : BCM53312 have four SGMII ports (GE8,9,10,11).
   1753              *      If power down GE8 or GE10, 
   1754              *      the GE9 or GE11 is powered down also.
   1755              *
   1756              * Analysis : When set the QSGMII in sgmii dual mode,
   1757              *      if you power down lane 4, 
   1758              *      only lane4 is powered down.
   1759              *      But if you power down lane0, not only lane0
   1760              *      is powered down but also pll get powered down. 
   1761              *
   1762              * Solution : We can set laneCtrl3 to 0xAFF for AER 0, not AER 4.
   1763              *      The laneCtrl3 (addr:0X8018) is the reg in 
   1764              *      XGXS Block1(default is 0x200). 
   1765              *          pwrdwn_rx = laneCtrl3[3:0];
   1766              *          pwrdwn_tx = laneCtrl3[7:4];
   1767              *          pwrdwn_pll = laneCtrl3[8];
   1768              *          pwrdwn10g_pll_dis = laneCtrl3[9];
   1769              *          lock_ref_en = laneCtrl3[10];
   1770              *          pwrdwn_force = laneCtrl3[11];
   1771              */
   1772             SOC_IF_ERROR_RETURN
   1773                 (WRITE_QSGMII65_LANE_CTRL3r(unit, pc, (stop ? 0xAFF : 0x200)));
   1774         } else {
   1775             if (soc_feature (unit, soc_feature_eee)) {
   1776                 /* If link on port1 (second port) of a QSGMII octet is  
   1777                  *        down, Tx/Rx LPI_DURATION counters of all ports 
   1778                  *        in that octet stop running. 
   1779                  * So NOT to set the power-down bit for second port
   1780                  *       of QSGMII serdes on HKEEE.
   1781                  *       And MAC.SW_RESET in HKEEE essentially kill the traffic
   1782                  *       in both Tx and Rx direction.
   1783                  */
   1784                 if(pc->lane_num == 1) {
   1785                     /* Do nothing */
   1786                 } else {
   1787                     SOC_IF_ERROR_RETURN
   1788                         (MODIFY_QSGMII65_MII_CTRLr
   1789                                 (unit, pc, mii_ctrl, MII_CTRL_PD));
   1790                 }
   1791             } else {
   1792                 SOC_IF_ERROR_RETURN
   1793                     (MODIFY_QSGMII65_MII_CTRLr(unit, pc, mii_ctrl, MII_CTRL_PD));
   1794             }
   1795         }        
   1796     } else
   1797 #endif /* BCM_HAWKEYE_SUPPORT */
   1798 #ifdef BCM_HURRICANE1_SUPPORT
   1799         if (SOC_IS_HURRICANE(unit)) {
   1800             uint16 lctrl;
   1801             SOC_IF_ERROR_RETURN
   1802                 (READ_QSGMII65_LANE_CTRL0r(unit, pc,&lctrl));
   1803             if ((pc->lane_num == 0) && ((lctrl & 0xff00)  == 0)) {
   1804                 /* SGMII Mode */
   1805                 SOC_IF_ERROR_RETURN
   1806                     (WRITE_QSGMII65_LANE_CTRL3r(unit, pc, (stop ? 0xAFF : 0x200)));
   1807             } else {
   1808                 if (soc_feature (unit, soc_feature_eee)) {
   1809                     if(pc->lane_num == 1) {
   1810                         /* Do nothing */
   1811                     } else {
   1812                         SOC_IF_ERROR_RETURN
   1813                             (MODIFY_QSGMII65_MII_CTRLr
   1814                                     (unit, pc, mii_ctrl, MII_CTRL_PD));
   1815                     }
   1816                 } else {
   1817                     SOC_IF_ERROR_RETURN
   1818                         (MODIFY_QSGMII65_MII_CTRLr(unit, pc, mii_ctrl, MII_CTRL_PD));
   1819                 }
   1820             }        
   1821         } else
   1822 #endif /* BCM_HURRICANE_SUPPORT */
   1823     {
   1824         SOC_IF_ERROR_RETURN
   1825             (MODIFY_QSGMII65_MII_CTRLr(unit, pc, mii_ctrl, MII_CTRL_PD));
   1826     }
   1827 
   1828     return SOC_E_NONE; 
   1829 }
   1830 
   1831 /*
   1832  * Function:
   1833  *      _phy_qsgmii65_notify_stop
   1834  * Purpose:     
   1835  *      Add a reason to put qsgmii65 PHY in reset.
   1836  * Parameters:
   1837  *      unit - StrataSwitch unit #.
   1838  *      port - StrataSwitch port #. 
   1839  *      flags - Reason to stop
   1840  * Returns:     
   1841  *      SOC_E_XXX
   1842  */
   1843 
   1844 STATIC int
   1845 _phy_qsgmii65_notify_stop(int unit, soc_port_t port, uint32 flags)
   1846 {
   1847     INT_PHY_SW_STATE(unit, port)->stop |= flags;
   1848 
   1849     return _phy_qsgmii65_stop(unit, port);
   1850 }
   1851 
   1852 /*
   1853  * Function:
   1854  *      phy_qsgmii65_notify_resume
   1855  * Purpose:     
   1856  *      Remove a reason to put qsgmii65 PHY in reset.
   1857  * Parameters:
   1858  *      unit - StrataSwitch unit #.
   1859  *      port - StrataSwitch port #. 
   1860  *      flags - Reason to stop
   1861  * Returns:     
   1862  *      SOC_E_XXX
   1863  */
   1864 
   1865 STATIC int
   1866 _phy_qsgmii65_notify_resume(int unit, soc_port_t port, uint32 flags)
   1867 {
   1868     INT_PHY_SW_STATE(unit, port)->stop &= ~flags;
   1869 
   1870     return _phy_qsgmii65_stop(unit, port);
   1871 }
   1872 
   1873 /*
   1874  * Function:
   1875  *      phy_qsgmii65_media_setup
   1876  * Purpose:     
   1877  *      Configure 
   1878  * Parameters:
   1879  *      unit - StrataSwitch unit #.
   1880  *      port - StrataSwitch port #. 
   1881  *      PHY_FIBER_MODE - Configure for fiber mode
   1882  *      fiber_pref - Fiber preferrred (if fiber mode)
   1883  * Returns:     
   1884  *      SOC_E_XXX
   1885  */
   1886 STATIC int
   1887 _phy_qsgmii65_notify_interface(int unit, soc_port_t port, uint32 intf)
   1888 {
   1889     phy_ctrl_t  *pc;
   1890     uint16       data16;
   1891 
   1892     pc = INT_PHY_SW_STATE(unit, port);
   1893   
   1894     data16 = 0;
   1895     if (intf != SOC_PORT_IF_SGMII) {
   1896         data16 = LP_1000X_FIBER_MODE;
   1897     }
   1898     SOC_IF_ERROR_RETURN
   1899         (MODIFY_QSGMII65_1000X_CTRL1r(unit, pc,
   1900                                          data16, LP_1000X_FIBER_MODE));
   1901 
   1902     return SOC_E_NONE;
   1903 }
   1904 #else /* INCLUDE_XGXS_QSGMII65 */
   1905 int _phy_qsgmii65_not_empty;
   1906 #endif /* INCLUDE_XGXS_QSGMII65 */