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

serdes.c (18613B)


      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:        serdes.c
      8  * Purpose:     Defines common PHY driver routines for Broadcom SerDes core.
      9  */
     10 
     11 #include <sal/types.h>
     12 #include <sal/core/spl.h>
     13 #include <shared/bsl.h>
     14 #include <soc/drv.h>
     15 #include <soc/debug.h>
     16 #include <soc/error.h>
     17 #include <soc/phy.h>
     18 #include <soc/phyreg.h>
     19 
     20 #include <soc/phy.h>
     21 #include <soc/phy/phyctrl.h>
     22 #include <soc/phy/drv.h>
     23 
     24 #include "phydefs.h"      /* Must include before other phy related includes */
     25 
     26 #if defined(INCLUDE_SERDES)
     27 #include "phyconfig.h"    /* Must be the first phy include after phydefs.h */
     28 #include "phyreg.h"
     29 #include "serdes.h"
     30 
     31 /*
     32  * Function:
     33  *      phy_serdes_link_get
     34  * Purpose:
     35  *      Determine the current link up/down status
     36  * Parameters:
     37  *      unit - StrataSwitch unit #.
     38  *      port - StrataSwitch port #.
     39  *      link - (OUT) Boolean, true indicates link established.
     40  * Returns:
     41  *      SOC_E_XXX
     42  * Notes:
     43  *      MII_STATUS bit 2 reflects link state.
     44  */
     45 
     46 int
     47 phy_serdes_link_get(int unit, soc_port_t port, int *link)
     48 {
     49     uint16       mii_stat;
     50     uint16       mii_ctrl;
     51     uint16       ctrl2;
     52     int          an_done;
     53     phy_ctrl_t  *pc;
     54 
     55     if (PHY_DISABLED_MODE(unit, port)) {
     56         *link = FALSE;
     57     } else {
     58         pc = INT_PHY_SW_STATE(unit, port);
     59 
     60         SOC_IF_ERROR_RETURN
     61             (READ_SERDES_MII_STATr(unit, pc, &mii_stat));
     62 
     63         *link = ((mii_stat & MII_STAT_LA) != 0);
     64 
     65         SOC_IF_ERROR_RETURN
     66             (READ_SERDES_MII_CTRLr(unit, pc, &mii_ctrl));
     67 
     68         SOC_IF_ERROR_RETURN
     69             (READ_SERDES_1000X_CTRL2r(unit, pc, &ctrl2));
     70 
     71         /* qualify the link with autoneg done only when autoneg is enabled
     72          * and paralell detect is disabled.
     73          */ 
     74         if ((mii_ctrl & MII_CTRL_AE) && 
     75             (!(ctrl2 & SERDES_1000X_CTRL2_PAR_DET_EN))) {
     76             an_done = ((mii_stat & MII_STAT_AN_DONE) != 0);
     77 
     78             *link = (*link) && (an_done);
     79         }
     80     }
     81 
     82     return SOC_E_NONE;
     83 }
     84 
     85 /*
     86  * Function:
     87  *      phy_serdes_duplex_set
     88  * Purpose:
     89  *      Set the current duplex mode (forced).
     90  * Parameters:
     91  *      unit - StrataSwitch unit #.
     92  *      port - StrataSwitch port #.
     93  *      duplex - Boolean, TRUE indicates full duplex, FALSE indicates half.
     94  * Returns:
     95  *      SOC_E_XXX
     96  */
     97 
     98 int
     99 phy_serdes_duplex_set(int unit, soc_port_t port, int duplex)
    100 {
    101     int rv;
    102 
    103     COMPILER_REFERENCE(unit);
    104     COMPILER_REFERENCE(port);
    105 
    106     rv = duplex ? SOC_E_NONE : SOC_E_UNAVAIL;
    107 
    108     LOG_INFO(BSL_LS_SOC_PHY,
    109              (BSL_META_U(unit,
    110                          "phy_serdes_duplex_set: u=%d p=%d duplex=%d rv=%d\n"),
    111               unit, port, duplex, rv));
    112 
    113     return rv;
    114 }
    115 
    116 /*
    117  * Function:
    118  *      phy_serdes_an_get
    119  * Purpose:
    120  *      Get the current auto-negotiation status (enabled/busy)
    121  * Parameters:
    122  *      unit - StrataSwitch unit #.
    123  *      port - StrataSwitch port #.
    124  *      an - (OUT) if true, auto-negotiation is enabled.
    125  *      an_done - (OUT) if true, auto-negotiation is complete.
    126  *              This value is undefined if an == false.
    127  * Returns:
    128  *      SOC_E_XXX
    129  */
    130 
    131 int
    132 phy_serdes_an_get(int unit, soc_port_t port, int *an, int *an_done)
    133 {
    134     uint16      ctrl, stat;
    135     phy_ctrl_t  *pc;
    136 
    137     pc = INT_PHY_SW_STATE(unit, port);
    138 
    139     SOC_IF_ERROR_RETURN
    140         (READ_SERDES_MII_CTRLr(unit, pc, &ctrl));
    141 
    142     *an = (ctrl & MII_CTRL_AE) != 0;
    143 
    144     SOC_IF_ERROR_RETURN
    145         (READ_SERDES_MII_STATr(unit, pc, &stat));
    146 
    147     *an_done = (stat & MII_STAT_AN_DONE) != 0;
    148 
    149     LOG_INFO(BSL_LS_SOC_PHY,
    150              (BSL_META_U(unit,
    151                          "phy_serdes_an_get: u=%d p=%d an=%d an_done=%d\n"),
    152               unit, port, *an, *an_done));
    153 
    154     return SOC_E_NONE;
    155 }
    156 
    157 /*
    158  * Function:
    159  *      phy_serdes_adv_local_set
    160  * Purpose:
    161  *      Set the current advertisement for auto-negotiation.
    162  * Parameters:
    163  *      unit - StrataSwitch unit #.
    164  *      port - StrataSwitch port #.
    165  *      mode - Port mode mask indicating supported options/speeds.
    166  * Returns:
    167  *      SOC_E_XXX
    168  */
    169 int
    170 phy_serdes_adv_local_set(int unit, soc_port_t port, soc_port_mode_t mode)
    171 {
    172     uint16              an_adv;
    173     phy_ctrl_t  *pc;
    174 
    175     /* Note:
    176      * We assume that switch SerDes is always used as slave when
    177      * the port is in SGMII mode. Therefore, the adv_local_set is applicable
    178      * only for 1000BASE-X mode and supported only clause 37 autoneg.
    179      */
    180     pc = INT_PHY_SW_STATE(unit, port);
    181 
    182     an_adv  = 0;
    183 
    184     /*
    185      * Set advertised duplex (only FD supported).
    186      */
    187     if (mode & SOC_PM_1000MB_FD) {
    188         an_adv |= MII_ANA_C37_FD;
    189     }
    190 
    191     /*
    192      * Set advertised pause bits in link code word.
    193      */
    194     switch (mode & SOC_PM_PAUSE) {
    195     case SOC_PM_PAUSE_TX:
    196         an_adv |= MII_ANA_C37_ASYM_PAUSE;
    197         break;
    198     case SOC_PM_PAUSE_RX:
    199         an_adv |= MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE;
    200         break;
    201     case SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX:
    202         an_adv |= MII_ANA_C37_PAUSE;
    203         break;
    204     }
    205 
    206     SOC_IF_ERROR_RETURN
    207         (MODIFY_SERDES_MII_ANAr(unit, pc, an_adv,
    208                                 MII_ANA_C37_ASYM_PAUSE | MII_ANA_C37_PAUSE |
    209                                 MII_ANA_C37_FD | MII_ANA_C37_HD));
    210 
    211     LOG_INFO(BSL_LS_SOC_PHY,
    212              (BSL_META_U(unit,
    213                          "phy_serdes_adv_local_set: u=%d p=%d adv=%s%s%s\n"),
    214               unit, port,
    215               (mode & SOC_PM_1000MB_FD) ? "1000MB " : "",
    216               (mode & SOC_PM_PAUSE_TX)  ? "PAUSE_TX " : "",
    217               (mode & SOC_PM_PAUSE_RX)  ? "PAUSE_TX " : ""));
    218     return SOC_E_NONE;
    219 }
    220 
    221 /*
    222  * Function:   
    223  *      phy_serdes_adv_local_get
    224  * Purpose:    
    225  *      Get the current advertisement for auto-negotiation.
    226  * Parameters:
    227  *      unit - StrataSwitch unit #.
    228  *      port - StrataSwitch port #.
    229  *      mode - (OUT) Port mode mask indicating supported options/speeds.
    230  * Returns:    
    231  *      SOC_E_XXX
    232  */
    233 
    234 int
    235 phy_serdes_adv_local_get(int unit, soc_port_t port, soc_port_mode_t *mode)
    236 {
    237     uint16      an_adv;
    238     phy_ctrl_t  *pc;
    239 
    240     pc = INT_PHY_SW_STATE(unit, port);
    241 
    242     *mode = 0;
    243 
    244     SOC_IF_ERROR_RETURN
    245         (READ_SERDES_MII_ANAr(unit, pc, &an_adv));
    246 
    247     if (an_adv & MII_ANA_C37_FD) {
    248         *mode |= SOC_PM_1000MB_FD;
    249     }
    250 
    251     switch (an_adv & (MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE)) {
    252     case MII_ANA_C37_PAUSE:
    253         *mode |= SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX;
    254         break;
    255     case MII_ANA_C37_ASYM_PAUSE:
    256         *mode |= SOC_PM_PAUSE_TX;
    257         break;
    258     case MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE:
    259         *mode |= SOC_PM_PAUSE_RX;
    260         break;
    261     }
    262 
    263     return SOC_E_NONE;
    264 }
    265 
    266 STATIC int
    267 _phy_serdes_sgmii_adv_remote_get(int unit, soc_port_t port,
    268                                 soc_port_mode_t *mode)
    269 {
    270     uint16              anlpa;
    271     soc_port_mode_t     duplex;
    272     phy_ctrl_t  *pc;
    273 
    274     pc = INT_PHY_SW_STATE(unit, port);
    275 
    276     *mode = 0;
    277 
    278     SOC_IF_ERROR_RETURN
    279         (READ_SERDES_MII_ANPr(unit, pc, &anlpa));
    280 
    281     switch (anlpa & MII_ANP_SGMII_SS_MASK) {
    282     case MII_ANP_SGMII_SS_10:
    283         *mode = SOC_PM_10MB;
    284         break;
    285     case MII_ANP_SGMII_SS_100:
    286         *mode = SOC_PM_100MB;
    287         break;
    288     case MII_ANP_SGMII_SS_1000:
    289         *mode = SOC_PM_1000MB;
    290         break;
    291     }
    292 
    293     duplex = (anlpa & MII_ANP_SGMII_FD) ? SOC_PM_FD : SOC_PM_HD;
    294 
    295     *mode = (*mode) & duplex;
    296 
    297     return SOC_E_NONE;
    298 }
    299 
    300 STATIC int
    301 _phy_serdes_1000x_adv_remote_get(int unit, soc_port_t port,
    302                                 soc_port_mode_t *mode)
    303 {
    304     uint16              anlpa;
    305     phy_ctrl_t  *pc;
    306 
    307     pc = INT_PHY_SW_STATE(unit, port);
    308 
    309     *mode = 0;
    310 
    311     SOC_IF_ERROR_RETURN
    312         (READ_SERDES_MII_ANPr(unit, pc, &anlpa));
    313 
    314     if (anlpa & MII_ANP_C37_FD) {
    315         *mode |= SOC_PM_1000MB_FD;
    316     }
    317 
    318     if (anlpa & MII_ANP_C37_HD) {
    319         *mode |= SOC_PM_1000MB_HD;
    320     }
    321     
    322     switch (anlpa &
    323             (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) {
    324     case MII_ANP_C37_PAUSE:
    325         *mode |= SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX;
    326         break;
    327     case MII_ANP_C37_ASYM_PAUSE:
    328         *mode |= SOC_PM_PAUSE_TX;
    329         break;
    330     case MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE:
    331         *mode |= SOC_PM_PAUSE_RX;
    332         break;
    333     }
    334 
    335     return SOC_E_NONE;
    336 }
    337 
    338 /*
    339  * Function:
    340  *      phy_serdes_adv_remote_get
    341  * Purpose:
    342  *      Get partner's current advertisement for auto-negotiation.
    343  * Parameters:
    344  *      unit - StrataSwitch unit #.
    345  *      port - StrataSwitch port #.
    346  *      mode - (OUT) Port mode mask indicating supported options/speeds.
    347  * Returns:
    348  *      SOC_E_XXX
    349  */
    350 
    351 int
    352 phy_serdes_adv_remote_get(int unit, soc_port_t port, soc_port_mode_t *mode)
    353 {
    354     uint16              fiber_status;
    355     phy_ctrl_t  *pc;
    356 
    357     pc = INT_PHY_SW_STATE(unit, port);
    358 
    359     SOC_IF_ERROR_RETURN
    360         (READ_SERDES_1000X_STAT1r(unit, pc, &fiber_status));
    361 
    362     if (fiber_status & SERDES_1000X_STAT1_SGMII_MODE) {
    363         SOC_IF_ERROR_RETURN
    364             (_phy_serdes_sgmii_adv_remote_get(unit, port, mode));
    365     } else {
    366         SOC_IF_ERROR_RETURN
    367             (_phy_serdes_1000x_adv_remote_get(unit, port, mode));
    368     }
    369 
    370     LOG_INFO(BSL_LS_SOC_PHY,
    371              (BSL_META_U(unit,
    372                          "phy_serdes_adv_remote_get: u=%d p=%d adv=%s%s%s\n"),
    373               unit, port,
    374               (*mode & SOC_PM_1000MB_FD) ? "1000MB " : "",
    375               (*mode & SOC_PM_PAUSE_TX)  ? "PAUSE_TX " : "",
    376               (*mode & SOC_PM_PAUSE_RX)  ? "PAUSE_TX " : ""));
    377 
    378     return SOC_E_NONE;
    379 }
    380 
    381 /*  
    382  * Function:    
    383  *      phy_serdes_lb_set
    384  * Purpose:     
    385  *      Set the internal PHY loopback mode.
    386  * Parameters:
    387  *      unit - StrataSwitch unit #.
    388  *      port - StrataSwitch port #.
    389  *      loopback - Boolean: true = enable loopback, false = disable.
    390  * Returns:     
    391  *      SOC_E_XXX
    392  */ 
    393     
    394 int
    395 phy_serdes_lb_set(int unit, soc_port_t port, int enable)
    396 {   
    397     uint16              ctrl;
    398     phy_ctrl_t  *pc;
    399     int                 rv;
    400     
    401     pc = INT_PHY_SW_STATE(unit, port);
    402     
    403     ctrl = (enable) ?MII_CTRL_LE : 0;
    404 
    405     rv = MODIFY_SERDES_MII_CTRLr(unit, pc,
    406                                ctrl, MII_CTRL_LE);
    407  
    408     LOG_INFO(BSL_LS_SOC_PHY,
    409              (BSL_META_U(unit,
    410                          "phy_serdes_lb_set: u=%d p=%d lb=%d rv=%d\n"),
    411               unit, port, enable, rv));
    412 
    413     return rv;
    414 }
    415 
    416 /*
    417  * Function:   
    418  *      phy_serdes_lb_get
    419  * Purpose:    
    420  *      Get the local PHY loopback mode.
    421  * Parameters:
    422  *      unit - StrataSwitch unit #.
    423  *      port - StrataSwitch port #.
    424  *      loopback - (OUT) Boolean: true = enable loopback, false = disable.
    425  * Returns:    
    426  *      SOC_E_XXX
    427  */
    428 
    429 int
    430 phy_serdes_lb_get(int unit, soc_port_t port, int *enable)
    431 {
    432     uint16      ctrl;
    433     phy_ctrl_t  *pc;
    434 
    435     pc = INT_PHY_SW_STATE(unit, port);
    436     SOC_IF_ERROR_RETURN
    437         (READ_SERDES_MII_CTRLr(unit, pc, &ctrl));
    438 
    439     *enable = (ctrl & MII_CTRL_LE) != 0;
    440 
    441     return SOC_E_NONE;
    442 }
    443 
    444 /*
    445  * Function:
    446  *      phy_serdes_interface_set
    447  * Purpose:
    448  *      Set the current operating mode of the internal PHY.
    449  *      (Pertaining to the MAC/PHY interface, not the line interface).
    450  * Parameters:
    451  *      unit - StrataSwitch unit #.
    452  *      port - StrataSwitch port #.
    453  *      pif - one of SOC_PORT_IF_*
    454  * Returns:
    455  *      SOC_E_XXX
    456  */
    457 
    458 int
    459 phy_serdes_interface_set(int unit, soc_port_t port, soc_port_if_t pif)
    460 {
    461     int                 rv;
    462 
    463     switch (pif) {
    464     case SOC_PORT_IF_MII:
    465     case SOC_PORT_IF_GMII:
    466     case SOC_PORT_IF_SGMII:
    467     case SOC_PORT_IF_NOCXN:
    468         rv = SOC_E_NONE;
    469         break;
    470     default:
    471         rv = SOC_E_UNAVAIL;
    472         break;
    473     }
    474 
    475     LOG_INFO(BSL_LS_SOC_PHY,
    476              (BSL_META_U(unit,
    477                          "phy_serdes_interface_set: u=%d p=%d pif=%d rv=%d\n"),
    478               unit, port, pif, rv));
    479 
    480     return rv;
    481 }
    482 
    483 /*
    484  * Function:
    485  *      phy_serdes_interface_get
    486  * Purpose:
    487  *      Get the current operating mode of the internal PHY.
    488  *      (Pertaining to the MAC/PHY interface, not the line interface).
    489  * Parameters:
    490  *      unit - StrataSwitch unit #.
    491  *      port - StrataSwitch port #.
    492  *      pif - (OUT) one of SOC_PORT_IF_*
    493  * Returns:
    494  *      SOC_E_XXX
    495  */
    496 
    497 int
    498 phy_serdes_interface_get(int unit, soc_port_t port, soc_port_if_t *pif)
    499 {
    500     *pif = SOC_PORT_IF_GMII;
    501 
    502     return(SOC_E_NONE);
    503 }
    504 
    505 /*
    506  * Function:
    507  *      phy_serdes_medium_config_get
    508  * Purpose:
    509  *      Get the operating parameters that are automatically selected
    510  *      when medium switches type.
    511  * Parameters:
    512  *      unit - StrataSwitch unit #
    513  *      port - Port number
    514  *      medium - SOC_PORT_MEDIUM_COPPER/FIBER
    515  *      cfg - (OUT) Operating parameters
    516  * Returns:
    517  *      SOC_E_XXX
    518  */
    519 
    520 int
    521 phy_serdes_medium_config_get(int unit, soc_port_t port,
    522                            soc_port_medium_t medium,
    523                            soc_phy_config_t *cfg)
    524 {
    525     phy_ctrl_t    *pc;
    526 
    527     pc = INT_PHY_SW_STATE(unit, port);
    528 
    529     switch (medium) {
    530     case SOC_PORT_MEDIUM_FIBER:
    531         sal_memcpy(cfg, &pc->fiber, sizeof (*cfg));
    532         return SOC_E_NONE;
    533     case SOC_PORT_MEDIUM_COPPER:
    534         return SOC_E_UNAVAIL;
    535     default:
    536         return SOC_E_PARAM;
    537     }
    538 }
    539 
    540 /*
    541  * Function:
    542  *      phy_serdes_medium_status
    543  * Purpose:
    544  *      Indicate the current active medium
    545  * Parameters:
    546  *      unit - StrataSwitch unit #.
    547  *      port - StrataSwitch port #.
    548  *      medium - (OUT) One of:
    549  *              SOC_PORT_MEDIUM_COPPER
    550  *              SOC_PORT_MEDIUM_FIBER
    551  * Returns:
    552  *      SOC_E_NONE
    553  */
    554 int
    555 phy_serdes_medium_status(int unit, soc_port_t port, soc_port_medium_t *medium)
    556 {
    557     COMPILER_REFERENCE(unit);
    558     COMPILER_REFERENCE(port);
    559 
    560     *medium = SOC_PORT_MEDIUM_FIBER;
    561 
    562     return SOC_E_NONE;
    563 }
    564 /*
    565  * Function:
    566  *      phy_serdes_master_set
    567  * Purpose:
    568  *      Configure PHY master mode
    569  * Parameters:
    570  *      unit - StrataSwitch unit #.
    571  *      port - StrataSwitch port #.
    572  *      master - PHY master mode.
    573  * Returns:
    574  *      SOC_E_UNAVAIL
    575  */
    576 int
    577 phy_serdes_master_set(int unit, soc_port_t port, int master)
    578 {
    579     COMPILER_REFERENCE(unit);
    580     COMPILER_REFERENCE(port);
    581 
    582     if (master == SOC_PORT_MS_NONE) {
    583         return SOC_E_NONE;
    584     }
    585     return SOC_E_PARAM;
    586 }
    587 
    588 /*
    589  * Function:
    590  *      phy_serdes_master_get
    591  * Purpose:
    592  *      Get current master mode setting
    593  * Parameters:
    594  *      unit - StrataSwitch unit #.
    595  *      port - StrataSwitch port #.
    596  *      master - (OUT) BCM_PORT_MS_NONE
    597  * Returns:
    598  *      SOC_E_NONE
    599  */
    600 int
    601 phy_serdes_master_get(int unit, soc_port_t port, int *master)
    602 {
    603     /* When in SGMII mode, the switch SerDes is always slave.  
    604      * However, we returns SOC_PORT_MS_NONE because SerDes driver
    605      * doesn't allow to change master mode.
    606      */
    607 
    608     *master = SOC_PORT_MS_NONE;
    609     return SOC_E_NONE;
    610 }
    611 
    612 /*
    613  * Function:
    614  *      phy_serdes_reg_read
    615  * Purpose:
    616  *      Routine to read PHY register
    617  * Parameters:
    618  *      uint         - BCM unit number
    619  *      pc           - PHY state
    620  *      flags        - Flags which specify the register type
    621  *      phy_reg_addr - Encoded register address
    622  *      phy_data     - (OUT) Value read from PHY register
    623  * Note:
    624  *      This register read function is not thread safe. Higher level
    625  * function that calls this function must obtain a per port lock
    626  * to avoid overriding register page mapping between threads.
    627  */
    628 int
    629 phy_serdes_reg_read(int unit, soc_port_t port, uint32 flags,
    630                   uint32 phy_reg_addr, uint32 *phy_data)
    631 {
    632     uint16               reg_bank;
    633     uint8                reg_addr;
    634     uint16               data;     /* Temporary holder for phy_data */
    635     phy_ctrl_t          *pc;      /* PHY software state */
    636 
    637     pc = INT_PHY_SW_STATE(unit, port);
    638 
    639     reg_bank  = SOC_PHY_REG_BANK(phy_reg_addr);
    640     reg_addr  = SOC_PHY_REG_ADDR(phy_reg_addr);
    641 
    642     SOC_IF_ERROR_RETURN
    643         (phy_reg_serdes_read(unit, pc, reg_bank, reg_addr, &data));
    644 
    645    *phy_data = data;
    646 
    647     return SOC_E_NONE;
    648 }
    649 /*
    650  * Function:
    651  *      phy_serdes_reg_write
    652  * Purpose:
    653  *      Routine to write PHY register
    654  * Parameters:
    655  *      uint         - BCM unit number
    656  *      pc           - PHY state
    657  *      flags        - Flags which specify the register type
    658  *      phy_reg_addr - Encoded register address
    659  *      phy_data     - Value write to PHY register
    660  * Note:
    661  *      This register read function is not thread safe. Higher level
    662  * function that calls this function must obtain a per port lock
    663  * to avoid overriding register page mapping between threads.
    664  */
    665 int
    666 phy_serdes_reg_write(int unit, soc_port_t port, uint32 flags,
    667                    uint32 phy_reg_addr, uint32 phy_data)
    668 {
    669     uint16               reg_bank;
    670     uint8                reg_addr;
    671     uint16               data;     /* Temporary holder for phy_data */
    672     phy_ctrl_t          *pc;      /* PHY software state */
    673 
    674     pc = INT_PHY_SW_STATE(unit, port);
    675 
    676     data      = (uint16) (phy_data & 0x0000FFFF);
    677     reg_bank  = SOC_PHY_REG_BANK(phy_reg_addr);
    678     reg_addr  = SOC_PHY_REG_ADDR(phy_reg_addr);
    679 
    680     SOC_IF_ERROR_RETURN
    681         (phy_reg_serdes_write(unit, pc, reg_bank, reg_addr, data));
    682 
    683     return SOC_E_NONE;
    684 }
    685 
    686 /*
    687  * Function:
    688  *      phy_serdes_reg_modify
    689  * Purpose:
    690  *      Routine to write PHY register
    691  * Parameters:
    692  *      uint         - BCM unit number
    693  *      pc           - PHY state
    694  *      flags        - Flags which specify the register type
    695  *      phy_reg_addr - Encoded register address
    696  *      phy_mo_data  - New value for the bits specified in phy_mo_mask
    697  *      phy_mo_mask  - Bit mask to modify
    698  * Note:
    699  *      This register read function is not thread safe. Higher level
    700  * function that calls this function must obtain a per port lock
    701  * to avoid overriding register page mapping between threads.
    702  */
    703 int
    704 phy_serdes_reg_modify(int unit, soc_port_t port, uint32 flags,
    705                     uint32 phy_reg_addr, uint32 phy_data, uint32 phy_data_mask)
    706 {
    707     uint16               reg_bank;
    708     uint8                reg_addr;
    709     uint16               data;     /* Temporary holder for phy_data */
    710     uint16               mask;
    711     phy_ctrl_t    *pc;      /* PHY software state */
    712 
    713     pc = INT_PHY_SW_STATE(unit, port);
    714 
    715     data      = (uint16) (phy_data & 0x0000FFFF);
    716     mask      = (uint16) (phy_data_mask & 0x0000FFFF);
    717     reg_bank  = SOC_PHY_REG_BANK(phy_reg_addr);
    718     reg_addr  = SOC_PHY_REG_ADDR(phy_reg_addr);
    719 
    720     SOC_IF_ERROR_RETURN
    721         (phy_reg_serdes_modify(unit, pc, reg_bank, reg_addr, data, mask));
    722 
    723     return SOC_E_NONE;
    724 }
    725 
    726 
    727 #else /* INCLUDE_PHY_SERDES */
    728 int _phy_serdes_not_empty;
    729 #endif /* INCLUDE_PHY_SERDES */
    730