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

xgxs5.c (24218B)


      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:        xgxs.c
      8  * Purpose:     Broadcom 10/100/1000/2500/10000/12000/13000/16000 SerDes 
      9  *              (SerDes-XGXS5/Unicore)
     10  */
     11 
     12 #include <sal/types.h>
     13 #include <sal/core/spl.h>
     14 #include <shared/bsl.h>
     15 #include <soc/drv.h>
     16 #include <soc/debug.h>
     17 #include <soc/error.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_PHY_XGXS5)
     27 #include "phyconfig.h"    /* Must be the first phy include after phydefs.h */
     28 #include "phyident.h"
     29 #include "phyreg.h"
     30 #include "phynull.h"
     31 #include "xgxs.h"
     32 #include "xgxs5.h"
     33 
     34 STATIC int phy_xgxs5_lb_set(int unit, soc_port_t port, int enable);
     35 
     36 /*
     37  *      Configure specified port for Independent channel mode operation
     38  */
     39 STATIC int
     40 _xgxs5_independent_channel_mode_set(int unit, phy_ctrl_t *pc)
     41 {
     42     SOC_IF_ERROR_RETURN         /* Independent Channdel Mode */
     43         (WRITE_PHYXGXS5_BLK0_CTRLr(unit, pc, 0x261f));
     44 
     45     /* Set all lanes to full rate mode */
     46     SOC_IF_ERROR_RETURN         /* Div  /1 mode select */
     47         (WRITE_PHYXGXS5_BLK1_LANE_CTRL1r(unit, pc, 0xffff));
     48 
     49     SOC_IF_ERROR_RETURN         /* Set Comma detect and 8/B/10B ON */
     50         (WRITE_PHYXGXS5_BLK1_LANE_CTRL2r(unit, pc, 0xff00));
     51 
     52     SOC_IF_ERROR_RETURN         /* Set 1G link enable & comma_adj_sync_sel */
     53         (WRITE_PHYXGXS5_RXALL_CTRL_PCIEr(unit, pc, 0x9130));
     54 
     55     return SOC_E_NONE;
     56 }
     57 
     58 /*
     59  * Function:
     60  *      phy_xgxs5_init
     61  * Purpose:     
     62  *      Initialize xgxs phys
     63  * Parameters:
     64  *      unit - StrataSwitch unit #.
     65  *      port - StrataSwitch port #. 
     66  * Returns:     
     67  *      SOC_E_NONE
     68  */
     69 
     70 STATIC int
     71 phy_xgxs5_init(int unit, soc_port_t port)
     72 {
     73     int            preemph, idriver, pdriver;
     74     int            locked;
     75     uint16         pll_stat;
     76     phy_ctrl_t    *pc;
     77     soc_timeout_t  to; 
     78 
     79     pc = INT_PHY_SW_STATE(unit, port);
     80 
     81     if (PHY_SINGLE_LANE_MODE(unit, port)) {
     82         SOC_IF_ERROR_RETURN
     83             (_xgxs5_independent_channel_mode_set(unit, pc));
     84     }
     85 
     86     /* Power on the Core */
     87     SOC_IF_ERROR_RETURN
     88         (MODIFY_PHYXGXS5_BLK1_LANE_TESTr(unit, pc, (1 << 10), (1 << 10)));
     89 
     90     /* Disable PLL State Machine */
     91     SOC_IF_ERROR_RETURN
     92         (WRITE_PHYXGXS5_PLL_CTRLr(unit, pc, 0x5006));
     93 
     94     /* Turn off slowdn_xor */
     95     SOC_IF_ERROR_RETURN
     96         (WRITE_PHYXGXS5_PLL_CAP_CTRLr(unit, pc, 0x0000));
     97 
     98     if (IS_HG_PORT(unit,port)) {
     99         if (!PHY_SINGLE_LANE_MODE(unit, port)) {
    100             /*
    101              * Do this only for regular 10G/12G mode.
    102              * Independent Lane mode is configured above.
    103              */
    104             SOC_IF_ERROR_RETURN         /* Disable LssQ */
    105                 (WRITE_PHYXGXS5_BLK0_CTRLr(unit, pc, 0x292f));
    106         }
    107         SOC_IF_ERROR_RETURN         /* Enable DTE mdio reg mapping */
    108             (WRITE_PHYXGXS5_BLK0_MISC_CTRL1r(unit, pc, 0x0000));
    109         preemph = 0x8;
    110         idriver = 0x7;
    111         pdriver = 0x9;
    112     } else {
    113         SOC_IF_ERROR_RETURN         /* Enable PMA/PMD mdio reg mapping */
    114             (WRITE_PHYXGXS5_BLK0_MISC_CTRL1r(unit, pc, 0x0200)); 
    115         preemph = 0xa;
    116         idriver = 0xf;
    117         pdriver = 0xf;
    118     }
    119 
    120     /* Enable PLL state machine */
    121     SOC_IF_ERROR_RETURN             
    122         (WRITE_PHYXGXS5_PLL_CTRLr(unit, pc, 0xf01e));
    123  
    124     /*
    125      * Transform CX4 pin out on the board to HG pinout
    126      */
    127     if (soc_property_port_get(unit, port, spn_CX4_TO_HIGIG, FALSE)) {
    128         /* Swap TX lanes */
    129         SOC_IF_ERROR_RETURN         /* Enable TX Lane swap */
    130             (WRITE_PHYXGXS5_BLK2_TX_LANE_SWAPr(unit, pc, 0x80e4));
    131         /* Flip TX Lane polarity */
    132         SOC_IF_ERROR_RETURN         /* Flip TX Lane polarity */
    133             (WRITE_PHYXGXS5_TXALL_ACTRL0r(unit, pc, 0x1020));
    134     } else {
    135         /* If CX4 to HG conversion is enabled, do not allow individual lane
    136          * swapping.
    137          */
    138         uint16 lane_map, i;
    139         uint16 lane, hw_map, chk_map;
    140 
    141         /* Update RX lane map */
    142         lane_map = soc_property_port_get(unit, port,
    143                                    spn_XGXS_RX_LANE_MAP, 0x0123) & 0xffff;
    144 
    145         if (lane_map != 0x0123) {
    146             hw_map  = 0;
    147             chk_map = 0;
    148             for (i = 0; i < 4; i++) {
    149                 lane     = (lane_map >> (i * 4)) & 0xf;
    150                 hw_map  |= lane << (i * 2);
    151                 chk_map |= 1 << lane;
    152             }
    153             if (chk_map == 0xf) {
    154                 SOC_IF_ERROR_RETURN     /* Enable RX Lane swap */
    155                    (MODIFY_PHYXGXS5_BLK2_RX_LANE_SWAPr(unit, pc,
    156                                                     0x8000 | hw_map, 0x80ff));
    157             } else {
    158                 LOG_ERROR(BSL_LS_SOC_PHY,
    159                           (BSL_META_U(unit,
    160                                       "unit %d port %s: Invalid RX lane map 0x%04x.\n"),
    161                            unit, SOC_PORT_NAME(unit, port), lane_map));
    162             }
    163         }
    164 
    165         /* Update TX lane map */
    166         lane_map = soc_property_port_get(unit, port,
    167                                   spn_XGXS_TX_LANE_MAP, 0x0123) & 0xffff;
    168 
    169         if (lane_map != 0x0123) {
    170             hw_map  = 0;
    171             chk_map = 0;
    172             for (i = 0; i < 4; i++) {
    173                 lane     = (lane_map >> (i * 4)) & 0xf;
    174                 hw_map  |= lane << (i * 2);
    175                 chk_map |= 1 << lane;
    176             }
    177             if (chk_map == 0xf) {
    178                 SOC_IF_ERROR_RETURN     /* Enable TX Lane swap */
    179                    (MODIFY_PHYXGXS5_BLK2_TX_LANE_SWAPr(unit, pc,
    180                                                     0x8000 | hw_map, 0x80ff));
    181             } else {
    182                 LOG_ERROR(BSL_LS_SOC_PHY,
    183                           (BSL_META_U(unit,
    184                                       "unit %d port %s: Invalid TX lane map 0x%04x.\n"),
    185                            unit, SOC_PORT_NAME(unit, port), lane_map));
    186             }
    187         }
    188     }
    189 
    190     /*
    191      * Flip TX lane polarity
    192      */
    193     if (soc_property_port_get(unit, port, "polarity_swap", FALSE)) {
    194         /* Flip TX Lane polarity */
    195         SOC_IF_ERROR_RETURN         /* Flip TX Lane polarity */
    196             (WRITE_PHYXGXS5_TXALL_ACTRL0r(unit, pc, 0x1020));
    197     }
    198 
    199     /* Allow config setting to override preemphasis, driver current, 
    200      * and pre-driver current.
    201      */
    202     preemph = soc_property_port_get(unit, port,
    203                                     spn_XGXS_PREEMPHASIS, preemph);
    204     preemph = _shr_bit_rev8(preemph) >> 4;
    205     idriver = soc_property_port_get(unit, port,
    206                                     spn_XGXS_DRIVER_CURRENT, idriver);
    207     idriver = _shr_bit_rev8(idriver) >> 4;
    208     pdriver = soc_property_port_get(unit, port,
    209                                     spn_XGXS_PRE_DRIVER_CURRENT, pdriver);
    210     pdriver = _shr_bit_rev8(pdriver) >> 4;
    211 
    212     SOC_IF_ERROR_RETURN
    213         (WRITE_PHYXGXS5_TXALL_DRIVERr(unit, pc, ((preemph & 0xf) << 12) |
    214                                                 ((idriver & 0xf) << 8) |
    215                                                     ((pdriver & 0xf) << 4)));
    216 
    217     /* Wait up to 0.1 sec for TX PLL lock. */
    218     soc_timeout_init(&to, 100000, 0);
    219 
    220     locked = 0;
    221     while (!soc_timeout_check(&to)) {
    222         SOC_IF_ERROR_RETURN
    223             (READ_PHYXGXS5_PLL_STATr(unit, pc, &pll_stat));
    224         /* Check pllSeqDone, freqDone, capDone, and ampDone */
    225         locked = ((pll_stat & (0xf000)) == 0xf000);
    226         if (locked) {
    227             break;
    228         }
    229     }
    230 
    231     if (!locked) {
    232         LOG_ERROR(BSL_LS_SOC_PHY,
    233                   (BSL_META_U(unit,
    234                               "unit %d port %s: XGXS PLL did not lock PLL_STAT %04x\n"),
    235                    unit, SOC_PORT_NAME(unit, port), pll_stat));
    236     } else {
    237         LOG_VERBOSE(BSL_LS_SOC_PHY,
    238                     (BSL_META_U(unit,
    239                                 "unit %d port %s: XGXS PLL locked in %d usec\n"),
    240                      unit, SOC_PORT_NAME(unit, port),
    241                      soc_timeout_elapsed(&to)));
    242     }
    243 
    244     if (PHY_EXTERNAL_MODE(unit, port)) {
    245         if (IS_HG_PORT(unit, port)) {
    246             uint16 value;
    247             
    248             /* Enable XgxsNoCC if the HiGig port has external PHY.
    249              * XgxsNoCC enables in-band link signaling, per the 802.3ae
    250              * standard (|Q| ordered sets).  XgxsNoLssQNoCC is legacy 
    251              * HiG mode, which does not support in-band link signaling.
    252              * Current XAUI cores support both 802.3ae compliant 
    253              * signaling, as well as backwards compatibility with 
    254              * prior (legacy) protocols.
    255              */
    256             SOC_IF_ERROR_RETURN
    257                 (READ_PHYXGXS5_BLK0_CTRLr(unit, pc, &value));
    258             value &= ~(0x0f00);
    259             value |= (1 << 8);
    260             SOC_IF_ERROR_RETURN
    261                 (WRITE_PHYXGXS5_BLK0_CTRLr(unit, pc, value));
    262         }
    263     }
    264 
    265     /* clear loopback (just in case) */
    266     SOC_IF_ERROR_RETURN
    267         (phy_xgxs5_lb_set(unit, port, FALSE));
    268 
    269     LOG_INFO(BSL_LS_SOC_PHY,
    270              (BSL_META_U(unit,
    271                          "phy_xgxs5_init: u=%d p=%d\n"),
    272               unit, port));
    273     return SOC_E_NONE;
    274 }
    275 
    276 /*
    277  * Function:
    278  *      phy_xgxs5_link_get
    279  * Purpose:
    280  *      Get layer2 connection status.
    281  * Parameters:
    282  *      unit - StrataSwitch unit #.
    283  *      port - StrataSwitch port #. 
    284  *      link - address of memory to store link up/down state.
    285  * Returns:     
    286  *      SOC_E_NONE
    287  */
    288 
    289 STATIC int
    290 phy_xgxs5_link_get(int unit, soc_port_t port, int *link)
    291 {
    292     phy_ctrl_t *pc;
    293 
    294     if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) {
    295         *link = FALSE;
    296         return SOC_E_NONE;
    297     }
    298 
    299     pc = INT_PHY_SW_STATE(unit, port);
    300 
    301     if (PHY_SINGLE_LANE_MODE(unit, port)) {
    302         uint16      o_misctrl1;
    303         uint16      n_misctrl1;
    304         uint16      sync_stat;
    305 
    306         SOC_IF_ERROR_RETURN         /* Get mdio reg mapping mode */
    307             (READ_PHYXGXS5_BLK0_MISC_CTRL1r(unit, pc, &o_misctrl1));
    308         n_misctrl1 = 0x0000;
    309         if (n_misctrl1 != o_misctrl1) {
    310             SOC_IF_ERROR_RETURN
    311                 (WRITE_PHYXGXS5_BLK0_MISC_CTRL1r(unit, pc, n_misctrl1));
    312         }
    313         SOC_IF_ERROR_RETURN
    314             (READ_PHYXGXS5_IEEE1_LANE_STATr(unit, pc, &sync_stat));
    315     
    316         if (n_misctrl1 != o_misctrl1) {  /* Restore PMA/PMD mdio reg mapping */
    317             SOC_IF_ERROR_RETURN
    318                 (WRITE_PHYXGXS5_BLK0_MISC_CTRL1r(unit, pc, o_misctrl1));
    319         }
    320      
    321         *link = (sync_stat & 1) ? TRUE : FALSE;
    322     } else {
    323         uint16  mii_stat;
    324 
    325         SOC_IF_ERROR_RETURN
    326             (READ_PHYXGXS5_XAUI_MII_STATr(unit, pc, &mii_stat));
    327         *link = (mii_stat & MII_STAT_LA) ? TRUE : FALSE; 
    328     }
    329 
    330     return SOC_E_NONE;
    331 }
    332 
    333 STATIC int
    334 _phy_xgxs5_enable_set(int unit, soc_port_t port, int enable)
    335 {
    336     uint16      disable_tx_xe;
    337     uint16      disable_tx_hg;
    338     phy_ctrl_t *pc;
    339 
    340     pc = INT_PHY_SW_STATE(unit, port);
    341 
    342     /* PMA/PMD mapping are different between HG and XE ports.
    343      * Therefore, we need two different settings for HG and XE ports.
    344      */
    345     if (enable) {
    346         disable_tx_xe = 0; /* Clear Tx disable bit for XE*/
    347         disable_tx_hg = 0; /* Clear Tx disable bit for HG*/
    348     } else {
    349         disable_tx_xe = (1 << 0);  /* Set disable Global PMD TX bit for XE */
    350         disable_tx_hg = (1 << 11); /* Set disable Global PMD TX bit for HG */
    351     }
    352 
    353     if (IS_XE_PORT(unit, port)) {
    354         SOC_IF_ERROR_RETURN
    355             (MODIFY_PHYXGXS5_XAUI_TX_DISABLEr(unit, pc, disable_tx_xe, 1 << 0));
    356     } else {
    357         SOC_IF_ERROR_RETURN
    358             (MODIFY_PHYXGXS5_BLK0_MISC_CTRL1r(unit, pc, disable_tx_hg, 
    359                                              (1 << 11)));
    360     }
    361 
    362     /* hold/release rxSeqStart to disable/enable the Rx */ 
    363     SOC_IF_ERROR_RETURN 
    364         (MODIFY_PHYXGXS5_RXALL_CTRLr(unit, pc, 
    365                  (enable) ? 0 : (1 << 15), (1 << 15))); 
    366 
    367     return SOC_E_NONE;
    368 }
    369 
    370 /*
    371  * Function:
    372  *      phy_xgxs5_enable_set
    373  * Purpose:
    374  *      Enable/Disable phy
    375  * Parameters:
    376  *      unit - StrataSwitch unit #.
    377  *      port - StrataSwitch port #.
    378  *      enable - on/off state to set
    379  * Returns:
    380  *      SOC_E_NONE
    381  */
    382 
    383 STATIC int
    384 phy_xgxs5_enable_set(int unit, soc_port_t port, int enable)
    385 {
    386     if (enable) {
    387         PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE);
    388     } else {
    389         PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE);
    390     }
    391     return _phy_xgxs5_enable_set(unit,port,enable);
    392 }
    393 /*
    394  * Function:
    395  *      phy_xgxs5_speed_get
    396  * Purpose:
    397  *      Get PHY speed
    398  * Parameters:
    399  *      unit - StrataSwitch unit #.
    400  *      port - StrataSwitch port #. 
    401  *      speed - current link speed in Mbps
    402  * Returns:     
    403  *      SOC_E_NONE
    404  */
    405 
    406 STATIC int
    407 phy_xgxs5_speed_get(int unit, soc_port_t port, int *speed)
    408 {
    409     /* Default speed */
    410     *speed = 10000;
    411 
    412     if (PHY_SINGLE_LANE_MODE(unit, port)) {
    413         *speed >>= 2;   /* Div by 4 */
    414     }
    415 
    416     COMPILER_REFERENCE(unit);
    417     COMPILER_REFERENCE(port);
    418  
    419     return SOC_E_NONE;
    420 }
    421 
    422 /*
    423  * Function:
    424  *      phy_xgxs5_lb_set
    425  * Purpose:
    426  *      Put XGXS5/FusionCore in PHY loopback
    427  * Parameters:
    428  *      unit - StrataSwitch unit #.
    429  *      port - StrataSwitch port #. 
    430  *      enable - binary value for on/off (1/0)
    431  * Returns:     
    432  *      SOC_E_NONE
    433  */
    434 
    435 STATIC int
    436 phy_xgxs5_lb_set(int unit, soc_port_t port, int enable)
    437 {
    438     int         rv;
    439     phy_ctrl_t *pc;
    440     uint16      lb_bit;
    441 
    442     rv = SOC_E_NONE;
    443 
    444     pc = INT_PHY_SW_STATE(unit, port);
    445 
    446     if (PHY_SINGLE_LANE_MODE(unit, port)) {
    447         SOC_IF_ERROR_RETURN
    448             (WRITE_PHYXGXS5_BLK1_LANE_CTRL2r(unit, pc, 
    449                                              (enable) ? 0xFF0F : 0xFF00)); 
    450         return SOC_E_NONE;
    451     }
    452 
    453     /*
    454      * control RX signal detect, so that a cable is not needed for loopback
    455      */
    456     SOC_IF_ERROR_RETURN
    457         (MODIFY_PHYXGXS5_RXALL_CTRLr(unit, pc, (enable) ? 0x0010 : 0, 0x0010));
    458 
    459     /*
    460      * control the actual loopback bit
    461      */
    462     lb_bit = XGXS5_IEEE_CTRL_LB_ENA;
    463     if (IS_XE_PORT(unit, port)) {
    464         if (soc_feature(unit, soc_feature_xgxs_v5)) {
    465             lb_bit = 1;
    466         }
    467     }
    468     SOC_IF_ERROR_RETURN
    469         (MODIFY_PHYXGXS5_XAUI_MII_CTRLr(unit, pc,
    470                                         (enable) ? lb_bit : 0, lb_bit)); 
    471 
    472     return rv;
    473 }
    474 
    475 /*
    476  * Function:
    477  *      phy_xgxs5_lb_get
    478  * Purpose:
    479  *      Get XGXS5/FusionCore PHY loopback state
    480  * Parameters:
    481  *      unit - StrataSwitch unit #.
    482  *      port - StrataSwitch port #. 
    483  *      enable - address of location to store binary value for on/off (1/0)
    484  * Returns:     
    485  *      SOC_E_NONE
    486  */
    487 
    488 STATIC int
    489 phy_xgxs5_lb_get(int unit, soc_port_t port, int *enable)
    490 {
    491     uint16      reg_val; 
    492     uint16      lb_bit;
    493     phy_ctrl_t *pc;
    494  
    495     pc = INT_PHY_SW_STATE(unit, port);
    496 
    497     if (PHY_SINGLE_LANE_MODE(unit, port)) {
    498         SOC_IF_ERROR_RETURN             /* Get Loopback status*/
    499             (READ_PHYXGXS5_BLK1_LANE_CTRL2r(unit, pc, &reg_val));
    500 
    501         *enable = ((reg_val & 0x000F) == 0x000f) ? TRUE : FALSE;
    502         return SOC_E_NONE;
    503     }
    504 
    505     lb_bit = XGXS5_IEEE_CTRL_LB_ENA;
    506     if (IS_XE_PORT(unit, port)) {
    507          lb_bit = 1;
    508     }
    509  
    510     SOC_IF_ERROR_RETURN
    511         (READ_PHYXGXS5_XAUI_MII_CTRLr(unit, pc, &reg_val));
    512 
    513     *enable = (reg_val & lb_bit) ? TRUE : FALSE;
    514 
    515     return SOC_E_NONE;
    516 }
    517 
    518 STATIC int
    519 phy_xgxs5_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode)
    520 {
    521     *mode =  SOC_PM_MII | SOC_PM_XGMII | SOC_PM_LB_PHY |
    522              SOC_PM_PAUSE | SOC_PM_PAUSE_ASYMM;
    523 
    524     if (PHY_SINGLE_LANE_MODE(unit, port)) {
    525         *mode |= SOC_PM_2500MB_FD | SOC_PM_3000MB_FD;
    526     } else {
    527         *mode |= SOC_PM_10GB_FD | SOC_PM_12GB_FD;
    528     }
    529 
    530     return SOC_E_NONE;
    531 }
    532 
    533 STATIC int
    534 _phy_xgxs5_control_tx_driver_set(int unit, phy_ctrl_t *pc,
    535                                 soc_phy_control_t type, uint32 value)
    536 {
    537     uint16  data;             /* Temporary holder of reg value to be written */
    538     uint16  mask;             /* Bit mask of reg value to be updated */
    539 
    540     if (value > 15) {
    541         return SOC_E_PARAM;
    542     }
    543 
    544     data = mask = 0;
    545     switch(type) {
    546     case SOC_PHY_CONTROL_PREEMPHASIS:
    547          data = _shr_bit_rev8((uint8)value) << 8;
    548          mask = 0xF000;
    549          break;
    550     case SOC_PHY_CONTROL_DRIVER_CURRENT:
    551          data = _shr_bit_rev8((uint8)value) << 4;
    552          mask = 0x0F00;
    553          break;
    554     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
    555          data = _shr_bit_rev8((uint8)value);
    556          mask = 0x00F0;
    557          break;
    558     default:
    559          /* should never get here */
    560          return SOC_E_PARAM;
    561     }
    562 
    563     /* Update preemphasis/driver/pre-driver current */
    564     SOC_IF_ERROR_RETURN
    565         (MODIFY_PHYXGXS5_TXALL_DRIVERr(unit, pc, data, mask));
    566 
    567     return SOC_E_NONE;
    568 }
    569 
    570 STATIC int
    571 _phy_xgxs5_control_tx_driver_get(int unit, phy_ctrl_t *pc,
    572                                 soc_phy_control_t type, uint32 *value)
    573 {
    574     uint16  data16;           /* Temporary holder of 16 bit reg value */
    575     uint8   data8;            /* Temporary holder of 8 bit reg value */
    576 
    577     /* Read preemphasis/driver/pre-driver current */
    578     SOC_IF_ERROR_RETURN
    579         (READ_PHYXGXS5_TXALL_DRIVERr(unit, pc, &data16));
    580 
    581     switch(type) {
    582     case SOC_PHY_CONTROL_PREEMPHASIS:
    583          data8 = (uint8)((data16 & 0xF000) >> 8);
    584          *value = _shr_bit_rev8(data8);
    585          break;
    586     case SOC_PHY_CONTROL_DRIVER_CURRENT:
    587          data8 = (uint8)((data16 & 0x0F00) >> 4);
    588          *value = _shr_bit_rev8(data8);
    589          break;
    590     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
    591          data8 = (uint8)(data16 & 0x00F0);
    592          *value = _shr_bit_rev8(data8);
    593          break;
    594     default:
    595          /* should never get here */
    596          return SOC_E_PARAM;
    597     }
    598 
    599     return SOC_E_NONE;
    600 }
    601 
    602 
    603 /*
    604  * Function:
    605  *      phy_xgxs5_control_set
    606  * Purpose:
    607  *      Configure PHY device specific control fucntion. 
    608  * Parameters:
    609  *      unit  - StrataSwitch unit #.
    610  *      port  - StrataSwitch port #. 
    611  *      type  - Control to update 
    612  *      value - New setting for the control 
    613  * Returns:     
    614  *      SOC_E_NONE
    615  */
    616 STATIC int
    617 phy_xgxs5_control_set(int unit, soc_port_t port,
    618                      soc_phy_control_t type, uint32 value)
    619 {
    620     int rv;
    621     phy_ctrl_t *pc;
    622     /* coverity[mixed_enums] */
    623     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
    624         return SOC_E_PARAM;
    625     }
    626    
    627     pc = INT_PHY_SW_STATE(unit, port);
    628     rv = SOC_E_UNAVAIL;
    629     switch(type) {
    630     case SOC_PHY_CONTROL_PREEMPHASIS:
    631         /* fall through */
    632     case SOC_PHY_CONTROL_DRIVER_CURRENT:
    633         /* fall through */
    634     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
    635         rv = _phy_xgxs5_control_tx_driver_set(unit, pc, type, value);
    636         break;
    637     default:
    638         rv = SOC_E_UNAVAIL;
    639         break; 
    640     }
    641     return rv;
    642 }
    643 
    644 /*
    645  * Function:
    646  *      phy_xgxs5_control_get
    647  * Purpose:
    648  *      Get current control settign of the PHY. 
    649  * Parameters:
    650  *      unit  - StrataSwitch unit #.
    651  *      port  - StrataSwitch port #. 
    652  *      type  - Control to update 
    653  *      value - (OUT)Current setting for the control 
    654  * Returns:     
    655  *      SOC_E_NONE
    656  */
    657 STATIC int
    658 phy_xgxs5_control_get(int unit, soc_port_t port,
    659                      soc_phy_control_t type, uint32 *value)
    660 {
    661     int rv;
    662     phy_ctrl_t *pc;
    663  
    664     if (NULL == value) {
    665         return SOC_E_PARAM;
    666     }
    667     /* coverity[mixed_enums] */
    668     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
    669         return SOC_E_PARAM;
    670     }
    671    
    672     pc = INT_PHY_SW_STATE(unit, port);
    673     rv = SOC_E_UNAVAIL;
    674     switch(type) {
    675     case SOC_PHY_CONTROL_PREEMPHASIS:
    676         /* fall through */
    677     case SOC_PHY_CONTROL_DRIVER_CURRENT:
    678         /* fall through */
    679     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
    680         rv = _phy_xgxs5_control_tx_driver_get(unit, pc, type, value);
    681         break;
    682     default:
    683         rv = SOC_E_UNAVAIL;
    684         break; 
    685     }
    686 
    687     return rv;
    688 }
    689 
    690 STATIC int
    691 _phy_xgxs5_stop(int unit, soc_port_t port)
    692 {
    693     int                 stop, copper;
    694     phy_ctrl_t  *pc;
    695 
    696     pc = INT_PHY_SW_STATE(unit, port);
    697 
    698     copper = (pc->stop &
    699               PHY_STOP_COPPER) != 0;
    700 
    701     stop = ((pc->stop &
    702              (PHY_STOP_PHY_DIS |
    703               PHY_STOP_DRAIN)) != 0 ||
    704             (copper &&
    705              (pc->stop &
    706               (PHY_STOP_MAC_DIS |
    707                PHY_STOP_DUPLEX_CHG |
    708                PHY_STOP_SPEED_CHG)) != 0));
    709 
    710     LOG_INFO(BSL_LS_SOC_PHY,
    711              (BSL_META_U(unit,
    712                          "phy_xgxs5_stop: u=%d p=%d copper=%d stop=%d flg=0x%x\n"),
    713               unit, port, copper, stop,
    714               pc->stop));
    715 
    716 
    717     return _phy_xgxs5_enable_set(unit,port,stop?FALSE:TRUE);
    718 }
    719 
    720 /*
    721  * Function:
    722  *      _phy_xgxs5_notify_stop
    723  * Purpose:
    724  *      Add a reason to put serdesxgxs5 PHY in reset.
    725  * Parameters:
    726  *      unit - StrataSwitch unit #.
    727  *      port - StrataSwitch port #.
    728  *      flags - Reason to stop
    729  * Returns:
    730  *      SOC_E_XXX
    731  */
    732 
    733 STATIC int
    734 _phy_xgxs5_notify_stop(int unit, soc_port_t port, uint32 flags)
    735 {
    736     INT_PHY_SW_STATE(unit, port)->stop |= flags;
    737     return _phy_xgxs5_stop(unit, port);
    738 }
    739 
    740 /*
    741  * Function:
    742  *      _phy_xgxs5_notify_resume
    743  * Purpose:
    744  *      Remove a reason to put serdesxgxs5 PHY in reset.
    745  * Parameters:
    746  *      unit - StrataSwitch unit #.
    747  *      port - StrataSwitch port #.
    748  *      flags - Reason to stop
    749  * Returns:
    750  *      SOC_E_XXX
    751  */
    752 
    753 STATIC int
    754 _phy_xgxs5_notify_resume(int unit, soc_port_t port, uint32 flags)
    755 {
    756     INT_PHY_SW_STATE(unit, port)->stop &= ~flags;
    757     return _phy_xgxs5_stop(unit, port);
    758 }
    759 
    760 STATIC int
    761 phy_xgxs5_notify(int unit, soc_port_t port,
    762                        soc_phy_event_t event, uint32 value)
    763 {
    764     int             rv;
    765 
    766     if (event >= phyEventCount) {
    767         return SOC_E_PARAM;
    768     }
    769 
    770     rv = SOC_E_NONE;
    771     switch(event) {
    772     case phyEventInterface:
    773         break;
    774     case phyEventDuplex:
    775         break;
    776     case phyEventSpeed:
    777         break;
    778     case phyEventStop:
    779         rv = (_phy_xgxs5_notify_stop(unit, port, value));
    780         break;
    781     case phyEventResume:
    782         rv = (_phy_xgxs5_notify_resume(unit, port, value));
    783         break;
    784     case phyEventAutoneg:
    785         break;
    786     default:
    787         rv = SOC_E_UNAVAIL;
    788         break;
    789     }
    790 
    791     return rv;
    792 }
    793 
    794 /*
    795  * Variable:
    796  *      phy_xgxs5_drv
    797  * Purpose:
    798  *      Phy Driver for 10G (XAUI x 4) Serdes PHY. 
    799  */
    800 
    801 phy_driver_t phy_xgxs5_hg = {
    802     "XGXS5 10G PHY Driver",
    803     phy_xgxs5_init,           /* Init */
    804     phy_null_reset,           /* Reset (dummy) */
    805     phy_xgxs5_link_get,       /* Link get   */
    806     phy_xgxs5_enable_set,     /* Enable set */
    807     phy_null_enable_get,      /* Enable get */
    808     phy_null_set,             /* Duplex set */
    809     phy_null_one_get,         /* Duplex get */
    810     phy_null_speed_set,       /* Speed set  */
    811     phy_xgxs5_speed_get,      /* Speed get  */
    812     phy_null_set,             /* Master set */
    813     phy_null_zero_get,        /* Master get */
    814     phy_null_set,             /* ANA set */
    815     phy_null_an_get,          /* ANA get */
    816     phy_null_mode_set,        /* Local Advert set */
    817     phy_null_mode_get,        /* Local Advert get */
    818     phy_null_mode_get,        /* Remote Advert get */
    819     phy_xgxs5_lb_set,         /* PHY loopback set */
    820     phy_xgxs5_lb_get,         /* PHY loopback set */
    821     phy_null_interface_set,   /* IO Interface set */
    822     phy_null_interface_get,   /* IO Interface get */
    823     phy_xgxs5_ability_get,    /* PHY abilities mask */
    824     NULL,                     /* Link up event */
    825     NULL,                     /* Link down event */
    826     phy_null_mdix_set,       
    827     phy_null_mdix_get,
    828     phy_null_mdix_status_get,
    829     NULL,                     /* Medium config set */
    830     NULL,                     /* Medium config get */
    831     phy_null_medium_get,
    832     NULL,                     /* phy_cable_diag  */
    833     NULL,                     /* phy_link_change */
    834     phy_xgxs5_control_set,
    835     phy_xgxs5_control_get,
    836     phy_xgxs_reg_read,
    837     phy_xgxs_reg_write, 
    838     phy_xgxs_reg_modify, 
    839     phy_xgxs5_notify          /* Notify event */
    840 };
    841 
    842 #else /* BCM_XGS5_SUPPORT */
    843 int _phy_xgxs5_not_empty;
    844 #endif /* BCM_XGS5_SUPPORT */
    845