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

xgxs1.c (15789B)


      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-XGXS/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/phy.h>
     19 #include <soc/phyreg.h>
     20 
     21 #include <soc/phy.h>
     22 #include <soc/phy/phyctrl.h>
     23 #include <soc/phy/drv.h>
     24 
     25 #include "phydefs.h"      /* Must include before other phy related includes */
     26 
     27 #if defined(INCLUDE_PHY_XGXS1)
     28 #include "phyconfig.h"    /* Must be the first phy include after phydefs.h */ 
     29 #include "phyident.h"
     30 #include "phyreg.h"
     31 #include "phynull.h"
     32 #include "xgxs.h"
     33 #include "xgxs1.h"
     34 
     35 STATIC int phy_xgxs1_lb_set(int unit, soc_port_t port, int enable);
     36 
     37 /*
     38  * Function:
     39  *      phy_xgxs1_init
     40  * Purpose:     
     41  *      Initialize xgxs phys
     42  * Parameters:
     43  *      unit - StrataSwitch unit #.
     44  *      port - StrataSwitch port #. 
     45  * Returns:     
     46  *      SOC_E_NONE
     47  */
     48 
     49 STATIC int
     50 phy_xgxs1_init(int unit, soc_port_t port)
     51 {
     52     phy_ctrl_t *pc;
     53 
     54     pc = INT_PHY_SW_STATE(unit, port);
     55 
     56     /* NOTE: FusionCore/Unicore init is performed in BigMAC init */
     57     if (PHY_EXTERNAL_MODE(unit, port)) {
     58         if (IS_HG_PORT(unit, port)) {
     59             uint16 value;
     60             
     61             /* Enable XgxsNoCC if the HiGig port has external PHY.
     62              * XgxsNoCC enables in-band link signaling, per the 802.3ae
     63              * standard (|Q| ordered sets).  XgxsNoLssQNoCC is legacy 
     64              * HiG mode, which does not support in-band link signaling.
     65              * Current XAUI cores support both 802.3ae compliant 
     66              * signaling, as well as backwards compatibility with 
     67              * prior (legacy) protocols.
     68              */
     69             SOC_IF_ERROR_RETURN
     70                 (READ_PHYXGXS_BLK0_CTRLr(unit, pc, &value));
     71             value &= ~(0x0f00);
     72             value |= (1 << 8);
     73             SOC_IF_ERROR_RETURN
     74                 (WRITE_PHYXGXS_BLK0_CTRLr(unit, pc, value));
     75         }
     76     }
     77 
     78     /* clear loopback (just in case) */
     79     SOC_IF_ERROR_RETURN
     80         (phy_xgxs1_lb_set(unit, port, FALSE));
     81 
     82     LOG_INFO(BSL_LS_SOC_PHY,
     83              (BSL_META_U(unit,
     84                          "phy_xgxs1_init: u=%d p=%d\n"),
     85               unit, port));
     86 
     87     return SOC_E_NONE;
     88 }
     89 
     90 /*
     91  * Function:
     92  *      phy_xgxs1_link_get
     93  * Purpose:
     94  *      Get layer2 connection status.
     95  * Parameters:
     96  *      unit - StrataSwitch unit #.
     97  *      port - StrataSwitch port #. 
     98  *      link - address of memory to store link up/down state.
     99  * Returns:     
    100  *      SOC_E_NONE
    101  */
    102 
    103 STATIC int
    104 phy_xgxs1_link_get(int unit, soc_port_t port, int *link)
    105 {
    106     if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) {
    107         *link = FALSE;
    108         return SOC_E_NONE;
    109     }
    110 
    111     if (IS_LMD_ENABLED_PORT(unit, port)) {
    112         uint16      o_misctrl1;
    113         uint16      n_misctrl1;
    114         uint16      sync_stat;
    115         phy_ctrl_t *pc;
    116 
    117         pc = INT_PHY_SW_STATE(unit, port);
    118 
    119         SOC_IF_ERROR_RETURN         /* Get mdio reg mapping mode */
    120             (READ_PHYXGXS_BLK0_MISC_CTRL1r(unit, pc, &o_misctrl1));
    121         n_misctrl1 = 0x0000;
    122         if (n_misctrl1 != o_misctrl1) {
    123             SOC_IF_ERROR_RETURN
    124                 (WRITE_PHYXGXS_BLK0_MISC_CTRL1r(unit, pc, n_misctrl1));
    125         }
    126         SOC_IF_ERROR_RETURN
    127             (READ_PHYXGXS_IEEE1_LANE_STATr(unit, pc, &sync_stat));
    128     
    129         if (n_misctrl1 != o_misctrl1) {  /* Restore PMA/PMD mdio reg mapping */
    130             SOC_IF_ERROR_RETURN
    131                 (WRITE_PHYXGXS_BLK0_MISC_CTRL1r(unit, pc, o_misctrl1));
    132         }
    133      
    134         *link = (sync_stat & 1) ? TRUE : FALSE;
    135     } else {
    136         uint64  xgxs_stat;
    137 
    138         SOC_IF_ERROR_RETURN
    139             (READ_MAC_XGXS_STATr(unit, port, &xgxs_stat)); 
    140         *link = soc_reg64_field32_get
    141                         (unit, MAC_XGXS_STATr, xgxs_stat, 
    142                          LINKf) ? TRUE : FALSE;
    143     }
    144 
    145     return SOC_E_NONE;
    146 }
    147 
    148 /*
    149  * Function:
    150  *      phy_xgxs1_enable_set
    151  * Purpose:
    152  *      Enable/Disable phy 
    153  * Parameters:
    154  *      unit - StrataSwitch unit #.
    155  *      port - StrataSwitch port #. 
    156  *      enable - on/off state to set
    157  * Returns:     
    158  *      SOC_E_NONE
    159  */
    160 
    161 STATIC int
    162 phy_xgxs1_enable_set(int unit, soc_port_t port, int enable)
    163 {
    164     uint16      disable_tx_xe;
    165     uint16      disable_tx_hg;
    166     phy_ctrl_t *pc;
    167 
    168     pc = INT_PHY_SW_STATE(unit, port);
    169 
    170     /* PMA/PMD mapping are different between HG and XE ports.
    171      * Therefore, we need two different settings for HG and XE ports.
    172      */
    173     if (enable) {
    174         PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE);
    175         disable_tx_xe = 0; /* Clear Tx disable bit for XE*/
    176         disable_tx_hg = 0; /* Clear Tx disable bit for HG*/
    177     } else {
    178         PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE);
    179         disable_tx_xe = (1 << 0);  /* Set disable Global PMD TX bit for XE */
    180         disable_tx_hg = (1 << 11); /* Set disable Global PMD TX bit for HG */
    181     }
    182 
    183     if (IS_XE_PORT(unit, port)) {
    184         SOC_IF_ERROR_RETURN
    185             (MODIFY_PHYXGXS_XAUI_TX_DISABLEr(unit, pc, disable_tx_xe, 1 << 0));
    186     } else {
    187         SOC_IF_ERROR_RETURN
    188             (MODIFY_PHYXGXS_BLK0_MISC_CTRL1r(unit, pc, disable_tx_hg, 
    189                                              (1 << 11)));
    190     }
    191 
    192     return SOC_E_NONE;
    193 }
    194 
    195 /*
    196  * Function:
    197  *      phy_xgxs1_speed_get
    198  * Purpose:
    199  *      Get PHY speed
    200  * Parameters:
    201  *      unit - StrataSwitch unit #.
    202  *      port - StrataSwitch port #. 
    203  *      speed - current link speed in Mbps
    204  * Returns:     
    205  *      SOC_E_NONE
    206  */
    207 
    208 STATIC int
    209 phy_xgxs1_speed_get(int unit, soc_port_t port, int *speed)
    210 {
    211     /* Default speed */
    212     *speed = 10000;
    213     if (IS_LMD_ENABLED_PORT(unit, port)) {
    214         *speed >>= 2;   /* Div by 4 */
    215     }
    216 
    217     COMPILER_REFERENCE(unit);
    218     COMPILER_REFERENCE(port);
    219  
    220     return SOC_E_NONE;
    221 }
    222 
    223 /*
    224  * Function:
    225  *      phy_xgxs1_lb_set
    226  * Purpose:
    227  *      Put XGXS/FusionCore in PHY loopback
    228  * Parameters:
    229  *      unit - StrataSwitch unit #.
    230  *      port - StrataSwitch port #. 
    231  *      enable - binary value for on/off (1/0)
    232  * Returns:     
    233  *      SOC_E_NONE
    234  */
    235 
    236 STATIC int
    237 phy_xgxs1_lb_set(int unit, soc_port_t port, int enable)
    238 {
    239     int         rv;
    240     phy_ctrl_t *pc;
    241     uint16      lb_bit;
    242 
    243     rv = SOC_E_NONE;
    244 
    245     pc = INT_PHY_SW_STATE(unit, port);
    246 
    247     if (IS_LMD_ENABLED_PORT(unit, port)) {
    248         SOC_IF_ERROR_RETURN
    249             (WRITE_PHYXGXS_BLK1_LANE_CTRL2r(unit, pc, 
    250                                              (enable) ? 0xFF0F : 0xFF00)); 
    251         return SOC_E_NONE;
    252     }
    253 
    254     /*
    255      * control RX signal detect, so that a cable is not needed for loopback
    256      */
    257     SOC_IF_ERROR_RETURN
    258         (MODIFY_PHYXGXS_RXALL_CTRLr(unit, pc, (enable) ? 0x0010 : 0, 0x0010));
    259 
    260     /*
    261      * control the actual loopback bit
    262      */
    263     lb_bit = XGXS_IEEE_CTRL_LB_ENA;
    264     if (IS_XE_PORT(unit, port)) {
    265         if (soc_feature(unit, soc_feature_xgxs_v5)) {
    266             lb_bit = 1;
    267         }
    268     }
    269     SOC_IF_ERROR_RETURN
    270         (MODIFY_PHYXGXS_XAUI_MII_CTRLr(unit, pc,
    271                                         (enable) ? lb_bit : 0, lb_bit)); 
    272 
    273     return rv;
    274 }
    275 
    276 /*
    277  * Function:
    278  *      phy_xgxs1_lb_get
    279  * Purpose:
    280  *      Get XGXS/FusionCore PHY loopback state
    281  * Parameters:
    282  *      unit - StrataSwitch unit #.
    283  *      port - StrataSwitch port #. 
    284  *      enable - address of location to store binary value for on/off (1/0)
    285  * Returns:     
    286  *      SOC_E_NONE
    287  */
    288 
    289 STATIC int
    290 phy_xgxs1_lb_get(int unit, soc_port_t port, int *enable)
    291 {
    292     uint16      reg_val; 
    293     uint16      lb_bit;
    294     phy_ctrl_t *pc;
    295  
    296     pc = INT_PHY_SW_STATE(unit, port);
    297 
    298     if (IS_LMD_ENABLED_PORT(unit, port)) {
    299         SOC_IF_ERROR_RETURN             /* Get Loopback status*/
    300             (READ_PHYXGXS_BLK1_LANE_CTRL2r(unit, pc, &reg_val));
    301 
    302         *enable = ((reg_val & 0x000F) == 0x000f) ? TRUE : FALSE;
    303         return SOC_E_NONE;
    304     }
    305 
    306     lb_bit = XGXS_IEEE_CTRL_LB_ENA;
    307     if (IS_XE_PORT(unit, port)) {
    308         if (soc_feature(unit, soc_feature_xgxs_v5) ||
    309             soc_feature(unit, soc_feature_xgxs_v6)) {
    310             lb_bit = 1;
    311         }
    312     }
    313  
    314     SOC_IF_ERROR_RETURN
    315         (READ_PHYXGXS_XAUI_MII_CTRLr(unit, pc, &reg_val));
    316 
    317     *enable = (reg_val & lb_bit) ? TRUE : FALSE;
    318 
    319     return SOC_E_NONE;
    320 }
    321 
    322 STATIC int
    323 phy_xgxs1_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode)
    324 {
    325     if (NULL == mode) {
    326         return SOC_E_PARAM;
    327     }
    328 
    329     *mode =  SOC_PM_MII | SOC_PM_XGMII | SOC_PM_LB_PHY |
    330              SOC_PM_PAUSE | SOC_PM_PAUSE_ASYMM;
    331 
    332     if (IS_LMD_ENABLED_PORT(unit, port)) {
    333         *mode |= SOC_PM_2500MB_FD;
    334     } else {
    335         *mode |= SOC_PM_10GB_FD;
    336     }
    337 
    338     return SOC_E_NONE;
    339 }
    340 
    341 STATIC int
    342 _phy_xgxs1_control_tx_driver_set(int unit, phy_ctrl_t *pc,
    343                                 soc_phy_control_t type, uint32 value)
    344 {
    345     uint16  data;             /* Temporary holder of reg value to be written */
    346     uint16  mask;             /* Bit mask of reg value to be updated */
    347 
    348     if (value > 15) {
    349         return SOC_E_PARAM;
    350     }
    351 
    352     data = mask = 0;
    353     switch(type) {
    354     case SOC_PHY_CONTROL_PREEMPHASIS:
    355          data = _shr_bit_rev8((uint8)value) << 8;
    356          mask = 0xF000;
    357          break;
    358     case SOC_PHY_CONTROL_DRIVER_CURRENT:
    359          data = _shr_bit_rev8((uint8)value) << 4;
    360          mask = 0x0F00;
    361          break;
    362     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
    363          data = _shr_bit_rev8((uint8)value);
    364          mask = 0x00F0;
    365          break;
    366     default:
    367          /* should never get here */
    368          return SOC_E_PARAM;
    369     }
    370 
    371     /* Update preemphasis/driver/pre-driver current */
    372     SOC_IF_ERROR_RETURN
    373         (MODIFY_PHYXGXS_TXALL_DRIVERr(unit, pc, data, mask));
    374 
    375     return SOC_E_NONE;
    376 }
    377 
    378 STATIC int
    379 _phy_xgxs1_control_tx_driver_get(int unit, phy_ctrl_t *pc,
    380                                 soc_phy_control_t type, uint32 *value)
    381 {
    382     uint16  data16;           /* Temporary holder of 16 bit reg value */
    383     uint8   data8;            /* Temporary holder of 8 bit reg value */
    384 
    385     /* Read preemphasis/driver/pre-driver current */
    386     SOC_IF_ERROR_RETURN
    387         (READ_PHYXGXS_TXALL_DRIVERr(unit, pc, &data16));
    388 
    389     switch(type) {
    390     case SOC_PHY_CONTROL_PREEMPHASIS:
    391          data8 = (uint8)((data16 & 0xF000) >> 8);
    392          *value = _shr_bit_rev8(data8);
    393          break;
    394     case SOC_PHY_CONTROL_DRIVER_CURRENT:
    395          data8 = (uint8)((data16 & 0x0F00) >> 4);
    396          *value = _shr_bit_rev8(data8);
    397          break;
    398     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
    399          data8 = (uint8)(data16 & 0x00F0);
    400          *value = _shr_bit_rev8(data8);
    401          break;
    402     default:
    403          /* should never get here */
    404          return SOC_E_PARAM;
    405     }
    406 
    407     return SOC_E_NONE;
    408 }
    409 
    410 /*
    411  * Function:
    412  *      phy_xgxs1_control_set
    413  * Purpose:
    414  *      Configure PHY device specific control fucntion. 
    415  * Parameters:
    416  *      unit  - StrataSwitch unit #.
    417  *      port  - StrataSwitch port #. 
    418  *      type  - Control to update 
    419  *      value - New setting for the control 
    420  * Returns:     
    421  *      SOC_E_NONE
    422  */
    423 STATIC int
    424 phy_xgxs1_control_set(int unit, soc_port_t port,
    425                      soc_phy_control_t type, uint32 value)
    426 {
    427     int rv;
    428     phy_ctrl_t *pc;
    429     /* coverity[mixed_enums] */
    430     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
    431         return SOC_E_PARAM;
    432     }
    433    
    434     pc = INT_PHY_SW_STATE(unit, port);
    435     rv = SOC_E_UNAVAIL;
    436     switch(type) {
    437     case SOC_PHY_CONTROL_PREEMPHASIS:
    438         /* fall through */
    439     case SOC_PHY_CONTROL_DRIVER_CURRENT:
    440         /* fall through */
    441     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
    442         rv = _phy_xgxs1_control_tx_driver_set(unit, pc, type, value);
    443         break;
    444     case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT:
    445         /* No support for force link tx */
    446         rv = SOC_E_UNAVAIL;
    447         break;
    448     default:
    449         rv = SOC_E_UNAVAIL;
    450         break; 
    451     }
    452     return rv;
    453 }
    454 
    455 /*
    456  * Function:
    457  *      phy_xgxs1_control_get
    458  * Purpose:
    459  *      Get current control settign of the PHY. 
    460  * Parameters:
    461  *      unit  - StrataSwitch unit #.
    462  *      port  - StrataSwitch port #. 
    463  *      type  - Control to update 
    464  *      value - (OUT)Current setting for the control 
    465  * Returns:     
    466  *      SOC_E_NONE
    467  */
    468 STATIC int
    469 phy_xgxs1_control_get(int unit, soc_port_t port,
    470                      soc_phy_control_t type, uint32 *value)
    471 {
    472     int rv;
    473     phy_ctrl_t *pc;
    474  
    475     if (NULL == value) {
    476         return SOC_E_PARAM;
    477     }
    478     /* coverity[mixed_enums] */
    479     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
    480         return SOC_E_PARAM;
    481     }
    482    
    483     pc = INT_PHY_SW_STATE(unit, port);
    484     rv = SOC_E_UNAVAIL;
    485     switch(type) {
    486     case SOC_PHY_CONTROL_PREEMPHASIS:
    487         /* fall through */
    488     case SOC_PHY_CONTROL_DRIVER_CURRENT:
    489         /* fall through */
    490     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
    491         rv = _phy_xgxs1_control_tx_driver_get(unit, pc, type, value);
    492         break;
    493     case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT:
    494         /* No support for force link tx */
    495         rv = SOC_E_UNAVAIL;
    496         break;
    497     default:
    498         rv = SOC_E_UNAVAIL;
    499         break; 
    500     }
    501 
    502     return rv;
    503 }
    504 
    505 STATIC int
    506 phy_xgxs1_notify(int unit, soc_port_t port,
    507                        soc_phy_event_t event, uint32 value)
    508 {
    509     int             rv;
    510 
    511     if (event >= phyEventCount) {
    512         return SOC_E_PARAM;
    513     }
    514 
    515     rv = SOC_E_NONE;
    516     switch(event) {
    517     case phyEventInterface:
    518     case phyEventDuplex:
    519     case phyEventSpeed:
    520     case phyEventStop:
    521     case phyEventResume:
    522     case phyEventAutoneg:
    523         break;
    524     default:
    525         rv = SOC_E_UNAVAIL;
    526         break;
    527     }
    528 
    529     return rv;
    530 }
    531 
    532 #ifdef XGXS1_QUICK_LINK_FLAPPING_FIX
    533 STATIC int
    534 phy_xgxs1_linkdown(int unit, soc_port_t port)
    535 {
    536     /* Workaround for Pass 0 silicon */
    537     return soc_fusioncore_reset(unit, port, -1);
    538 }
    539 #else /* no flapping */
    540 
    541 #define phy_xgxs1_linkdown       NULL
    542 
    543 #endif  /* XGXS1_QUICK_LINK_FLAPPING_FIX */
    544 
    545 /*
    546  * Variable:
    547  *      phy_xgxs1_drv
    548  * Purpose:
    549  *      Phy Driver for 10G (XAUI x 4) Serdes PHY. 
    550  */
    551 
    552 phy_driver_t phy_xgxs1_hg = {
    553     "XGXS 10G PHY Driver",
    554     phy_xgxs1_init,           /* Init */
    555     phy_null_reset,           /* Reset (dummy) */
    556     phy_xgxs1_link_get,       /* Link get   */
    557     phy_xgxs1_enable_set,     /* Enable set */
    558     phy_null_enable_get,      /* Enable get */
    559     phy_null_set,             /* Duplex set */
    560     phy_null_one_get,         /* Duplex get */
    561     phy_null_speed_set,       /* Speed set  */
    562     phy_xgxs1_speed_get,      /* Speed get  */
    563     phy_null_set,             /* Master set */
    564     phy_null_zero_get,        /* Master get */
    565     phy_null_set,             /* ANA set */
    566     phy_null_an_get,          /* ANA get */
    567     phy_null_mode_set,        /* Local Advert set */
    568     phy_null_mode_get,        /* Local Advert get */
    569     phy_null_mode_get,        /* Remote Advert get */
    570     phy_xgxs1_lb_set,         /* PHY loopback set */
    571     phy_xgxs1_lb_get,         /* PHY loopback set */
    572     phy_null_interface_set,   /* IO Interface set */
    573     phy_null_interface_get,   /* IO Interface get */
    574     phy_xgxs1_ability_get,    /* PHY abilities mask */
    575     NULL,
    576     phy_xgxs1_linkdown,
    577     phy_null_mdix_set,
    578     phy_null_mdix_get,
    579     phy_null_mdix_status_get,
    580     NULL,
    581     NULL,
    582     phy_null_medium_get,
    583     NULL,                     /* phy_cable_diag  */
    584     NULL,                     /* phy_link_change */
    585     phy_xgxs1_control_set,
    586     phy_xgxs1_control_get,
    587     phy_xgxs_reg_read,
    588     phy_xgxs_reg_write, 
    589     phy_xgxs_reg_modify,
    590     phy_xgxs1_notify                      /* phy_notify */ 
    591 };
    592 
    593 #endif /* INCLUDE_PHY_XGXS1 */
    594 
    595 int _phy_xgxs1_not_empty;