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

physfp.c (8892B)


      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:    physfp.c
      8  * Purpose: Provide PHY driver support for the PHY device embedded in the 
      9  *          copper SFP module. It is assumed that PHY device's register 
     10  *          implementation conforms to IEEE 802.3 MII register specification. 
     11  *          Device features implemented in the vendor specific registers generally
     12  *          will not be supported.
     13  *          This driver has tested with Broadcom 54810S copper SFP and 
     14  *          Finisars 1000BASE-T SFP (FCxx-8520/1-3).
     15  */
     16 
     17 #include <sal/types.h>
     18 #include <sal/core/spl.h>
     19 #include <shared/bsl.h>
     20 #include <soc/drv.h>
     21 #include <soc/debug.h>
     22 #include <soc/error.h>
     23 #include <soc/phyreg.h>
     24 #include <soc/phy.h>
     25 
     26 #include <soc/phy.h>
     27 #include <soc/phy/phyctrl.h>
     28 #include <soc/phy/drv.h>
     29 
     30 #include "phyident.h"
     31 #include "phyreg.h"
     32 #include "phynull.h"
     33 #include "phyfege.h"
     34 
     35 
     36 #define PHY_BRCM_54810S_ID0   0x0362 
     37 #define PHY_BRCM_54810S_ID1   0x5d01
     38 #define PHY_MRVL_88E1111_ID0  0x0141
     39 #define PHY_MRVL_88E1111_ID1  0x0cc1
     40 
     41 STATIC int
     42 phy_copper_sfp_an_set(int unit, soc_port_t port, int an);
     43 STATIC int
     44 phy_copper_sfp_init(int unit, soc_port_t port);
     45 STATIC int
     46 phy_copper_sfp_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode);
     47 STATIC int
     48 phy_copper_sfp_enable_set(int unit, soc_port_t port, int enable);
     49 STATIC int
     50 phy_copper_sfp_speed_set(int unit, soc_port_t port, int speed);
     51 
     52 
     53 /*
     54  * Variable:
     55  *  phy_drv_copper_sfp
     56  * Purpose:
     57  *  Phy driver callouts for a Gigabit phy (IEEE 802.3)
     58  */
     59 phy_driver_t phy_copper_sfp_drv = {
     60     "Copper SFP PHY Driver",
     61     phy_copper_sfp_init,
     62     phy_fe_ge_reset,
     63     phy_fe_ge_link_get,
     64     phy_copper_sfp_enable_set,
     65     phy_fe_ge_enable_get,
     66     phy_fe_ge_duplex_set,
     67     phy_fe_ge_duplex_get,
     68     phy_copper_sfp_speed_set,
     69     phy_fe_ge_speed_get,
     70     phy_fe_ge_master_set,
     71     phy_fe_ge_master_get,
     72     phy_copper_sfp_an_set,
     73     phy_fe_ge_an_get,
     74     phy_ge_adv_local_set,
     75     phy_ge_adv_local_get,
     76     phy_ge_adv_remote_get,
     77     phy_fe_ge_lb_set,
     78     phy_fe_ge_lb_get,
     79     phy_ge_interface_set,
     80     phy_ge_interface_get,
     81     phy_copper_sfp_ability_get,
     82     NULL,
     83     NULL,
     84     phy_null_mdix_set,
     85     phy_null_mdix_get,
     86     phy_null_mdix_status_get,
     87     NULL,
     88     NULL,
     89     phy_fe_ge_medium_get,
     90     NULL,                       /* phy_cable_diag  */
     91     NULL,                       /* phy_link_change */
     92     NULL,                       /* .pd_control_set */ 
     93     NULL,                       /* .pd_control_get */ 
     94     NULL,                       /* .pd_reg_read    */
     95     NULL,                       /* .pd_reg_write   */
     96     NULL,                       /* .pd_reg_modify  */
     97     NULL,                       /* .pd_notify      */
     98     NULL                        /* .pd_probe       */ 
     99 };
    100 
    101  
    102 /*
    103  * Function:    
    104  *  phy_finisar_sfp_init
    105  * Purpose: 
    106  *  Initialize the PHY (MII mode) to a known good state.
    107  * Parameters:
    108  *  unit - StrataSwitch unit #.
    109  *  port - StrataSwitch port #. 
    110  * Returns: 
    111  *  SOC_E_XXX
    112  */
    113 
    114 STATIC int
    115 phy_finisar_sfp_init(int unit, soc_port_t port)
    116 {
    117     phy_ctrl_t          *pc;
    118     pc = EXT_PHY_SW_STATE(unit, port);
    119 
    120     LOG_INFO(BSL_LS_SOC_PHY,
    121              (BSL_META_U(unit,
    122                          "phy_finisar_sfp_init : u=%d p=%d\n"),
    123               unit, port));
    124 
    125     if (PHY_SGMII_AUTONEG_MODE(unit, port)) {
    126         /* if it is in SGMII mode */
    127         SOC_IF_ERROR_RETURN
    128             (WRITE_PHY_REG(unit,pc,0x1B,0x9084));
    129         SOC_IF_ERROR_RETURN
    130             (WRITE_PHY_REG(unit,pc,0x9,0x0f00));
    131         SOC_IF_ERROR_RETURN
    132             (WRITE_PHY_REG(unit,pc,0x0,0x8140));
    133         SOC_IF_ERROR_RETURN
    134             (WRITE_PHY_REG(unit,pc,0x4,0x0de1));
    135         SOC_IF_ERROR_RETURN
    136             (WRITE_PHY_REG(unit,pc,0x0,0x9140));
    137     } else {
    138         SOC_IF_ERROR_RETURN
    139             (WRITE_PHY_REG(unit,pc,0x1B,0x9088));
    140         SOC_IF_ERROR_RETURN
    141             (WRITE_PHY_REG(unit,pc,0x9,0x0e00));
    142         SOC_IF_ERROR_RETURN
    143             (WRITE_PHY_REG(unit,pc,0x4,0x0c01));
    144         SOC_IF_ERROR_RETURN
    145             (WRITE_PHY_REG(unit,pc,0x0,0x8140));
    146     }
    147 
    148     return(SOC_E_NONE);
    149 }
    150 
    151 /*
    152  * Function:
    153  *  phy_copper_sfp_init
    154  * Purpose:
    155  *  Initialize the PHY (MII mode) to a known good state.
    156  * Parameters:
    157  *  unit - StrataSwitch unit #.
    158  *  port - StrataSwitch port #.
    159  * Returns:
    160  *  SOC_E_XXX
    161 
    162  * Notes:
    163  *  No synchronization performed at this level.
    164  */
    165 
    166 STATIC int
    167 phy_copper_sfp_init(int unit, soc_port_t port)
    168 {
    169     phy_ctrl_t  *pc;
    170     int rv;
    171 
    172     pc = EXT_PHY_SW_STATE(unit, port);
    173 
    174     if ((pc->phy_id0 == PHY_MRVL_88E1111_ID0) && 
    175         (pc->phy_id1 == PHY_MRVL_88E1111_ID1) ) {
    176          rv = phy_finisar_sfp_init(unit,port);
    177     } else if ((pc->phy_id0 == PHY_BRCM_54810S_ID0) && 
    178                (pc->phy_id1 == PHY_BRCM_54810S_ID1) ) {
    179          rv = phy_ge_init(unit,port);
    180          
    181          /* disable the broadreach mode for now */
    182          SOC_IF_ERROR_RETURN
    183             (WRITE_PHY_REG(unit,pc,0x17,0xf90));
    184          SOC_IF_ERROR_RETURN
    185             (WRITE_PHY_REG(unit,pc,0x15,0));
    186                   
    187     } else {
    188          rv = phy_ge_init(unit,port);
    189     }
    190     return rv;         
    191 }
    192 
    193 /*
    194  * Function:
    195  *  phy_copper_sfp_an_set
    196  * Purpose:
    197  *  Enable or disabled auto-negotiation on the specified port.
    198  * Parameters:
    199  *  unit - StrataSwitch unit #.
    200  *  port - StrataSwitch port #.
    201  *  an   - Boolean, if true, auto-negotiation is enabled
    202  *      (and/or restarted). If false, autonegotiation is disabled.
    203  * Returns:
    204  *  SOC_E_XXX
    205  */
    206 
    207 STATIC int
    208 phy_copper_sfp_an_set(int unit, soc_port_t port, int an)
    209 {
    210     phy_ctrl_t  *pc;
    211     int rv;
    212 
    213     pc = EXT_PHY_SW_STATE(unit, port);
    214 
    215     rv = phy_fe_ge_an_set(unit,port,an);
    216     if ((pc->phy_id0 == PHY_MRVL_88E1111_ID0) &&
    217         (pc->phy_id1 == PHY_MRVL_88E1111_ID1) ) {
    218         SOC_IF_ERROR_RETURN
    219             (MODIFY_PHYFEGE_MII_CTRLr(unit, pc, MII_CTRL_RESET,MII_CTRL_RESET));
    220     } else if ((pc->phy_id0 == PHY_BRCM_54810S_ID0) &&
    221                (pc->phy_id1 == PHY_BRCM_54810S_ID1) ) {
    222     } else {
    223     }
    224     return rv;
    225 }
    226 
    227 /*
    228  * Function:
    229  *  phy_ge_ability_get
    230  * Purpose:
    231  *  Get the abilities of the local gigabit phy.
    232  * Parameters:
    233  *  unit - StrataSwitch unit #.
    234  *  port - StrataSwitch port #.
    235  *  mode - (OUT) Port mode mask indicating supported options/speeds.
    236  * Returns:
    237  *  SOC_E_XXX
    238  */
    239 
    240 STATIC int
    241 phy_copper_sfp_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode)
    242 {
    243     uint16  mii_esr;
    244     phy_ctrl_t  *pc;
    245 
    246     pc = EXT_PHY_SW_STATE(unit, port);
    247 
    248     SOC_IF_ERROR_RETURN
    249     (phy_fe_ability_get(unit, port, mode));
    250 
    251     *mode |= (SOC_PM_PAUSE | SOC_PM_PAUSE_ASYMM | SOC_PM_GMII | SOC_PM_SGMII);
    252 
    253     SOC_IF_ERROR_RETURN
    254         (READ_PHYFEGE_MII_ESRr(unit, pc, &mii_esr));
    255 
    256 #if 0
    257     
    258 
    259     if (mii_esr & MII_ESR_1000_T_FD)    *mode |= SOC_PM_1000MB_FD;
    260     if (mii_esr & MII_ESR_1000_T_HD)    *mode |= SOC_PM_1000MB_HD;
    261     if (mii_esr & MII_ESR_1000_X_FD)    *mode |= SOC_PM_1000MB_FD;
    262     if (mii_esr & MII_ESR_1000_X_HD)    *mode |= SOC_PM_1000MB_HD;
    263 #else
    264     *mode |= SOC_PM_1000MB_HD | SOC_PM_1000MB_FD;
    265 #endif
    266 
    267     return(SOC_E_NONE);
    268 }
    269 
    270 /*
    271  * Function:
    272  *  phy_copper_sfp_enable_set
    273  * Purpose:
    274  *  Enable or disable the physical interface.
    275  * Parameters:
    276  *  unit - StrataSwitch unit #.
    277  *  port - StrataSwitch port #.
    278  *  enable - Boolean, true = enable PHY, false = disable.
    279  * Returns:
    280  *  SOC_E_XXX
    281  */
    282 
    283 STATIC int
    284 phy_copper_sfp_enable_set(int unit, soc_port_t port, int enable)
    285 {
    286     int value;
    287     phy_ctrl_t          *pc;
    288 
    289     pc = EXT_PHY_SW_STATE(unit, port);
    290     if (enable) {
    291         PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE);
    292     } else {
    293         PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE);
    294     }
    295 
    296     value = enable? 0: MII_CTRL_PD;
    297     SOC_IF_ERROR_RETURN
    298         (MODIFY_PHYFEGE_MII_CTRLr(unit, pc,value,MII_CTRL_PD));
    299 
    300     LOG_INFO(BSL_LS_SOC_PHY,
    301              (BSL_META_U(unit,
    302                          "phy_copper_sfp_enable_set: u=%d p=%d value=%d\n"),
    303               unit, port,value));
    304     return (SOC_E_NONE);
    305 }
    306 
    307 /*
    308  * Function:
    309  *  phy_copper_sfp_speed_set
    310  * Purpose:
    311  *  Set the current operating speed (forced).
    312  * Parameters:
    313  *  unit - StrataSwitch unit #.
    314  *  port - StrataSwitch port #.
    315  *  duplex - (OUT) Boolean, true indicates full duplex, false
    316  *      indicates half.
    317  * Returns:
    318  *  SOC_E_XXX
    319  */
    320 
    321 STATIC int
    322 phy_copper_sfp_speed_set(int unit, soc_port_t port, int speed)
    323 {
    324     phy_ctrl_t          *pc;
    325 
    326     pc = EXT_PHY_SW_STATE(unit, port);
    327 
    328     SOC_IF_ERROR_RETURN
    329         (phy_fe_ge_speed_set(unit,port,speed));
    330 
    331     if ((pc->phy_id0 == PHY_MRVL_88E1111_ID0) &&
    332         (pc->phy_id1 == PHY_MRVL_88E1111_ID1) ) {
    333         SOC_IF_ERROR_RETURN
    334             (MODIFY_PHYFEGE_MII_CTRLr(unit, pc, MII_CTRL_RESET,MII_CTRL_RESET));
    335     }
    336     return SOC_E_NONE;
    337 }