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

serdescombo65.c (56453B)


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