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

xgxs6.c (40596B)


      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:        xgxs6.c
      8  * Purpose:     Broadcom 10/100/1000/2500/10000/12000/13000/16000 SerDes 
      9  *              (SerDes-XGXS6/Unicore)
     10  */
     11 
     12 #include <sal/types.h>
     13 
     14 #include <sal/types.h>
     15 #include <sal/core/spl.h>
     16 #include <shared/bsl.h>
     17 #include <soc/drv.h>
     18 #include <soc/debug.h>
     19 #include <soc/error.h>
     20 #include <soc/phyreg.h>
     21 
     22 #include <soc/phy.h>
     23 #include <soc/phy/phyctrl.h>
     24 #include <soc/phy/drv.h>
     25 
     26 #include "phydefs.h"      /* Must include before other phy related includes */ 
     27 
     28 #if defined(INCLUDE_PHY_XGXS6)
     29 #include "phyconfig.h"     /* Must include before other phy related includes */
     30 #include "phyident.h"
     31 #include "phyreg.h"
     32 #include "phynull.h"
     33 #include "xgxs.h"
     34 #include "xgxs6.h"
     35 
     36 #define XGXS6_PLL_WAIT          250000
     37 
     38 STATIC int phy_xgxs6_lb_set(int unit, soc_port_t port, int enable);
     39 STATIC int phy_xgxs6_an_set(int unit, soc_port_t port, int an);
     40 STATIC int phy_xgxs6_an_get(int unit, soc_port_t port, int *an, int *an_done);
     41 STATIC int phy_xgxs6_speed_get(int unit, soc_port_t port, int *speed);
     42 
     43 STATIC int
     44 _phy_xgxs6_pll_lock_wait(int unit, soc_port_t port)
     45 {
     46     uint16           data16;
     47     phy_ctrl_t      *pc;
     48     soc_timeout_t    to;
     49     int              rv;
     50 
     51     pc = INT_PHY_SW_STATE(unit, port);
     52     soc_timeout_init(&to, XGXS6_PLL_WAIT, 0);
     53     do {
     54         rv = READ_PHYXGXS6_BLK0_STATr(unit, pc, &data16);
     55         if ((data16 & XGXSBLK0_XGXSSTATUS_TXPLL_LOCK) ||
     56             SOC_FAILURE(rv)) {
     57             break;
     58         }
     59     } while (!soc_timeout_check(&to));
     60     if ((data16 & XGXSBLK0_XGXSSTATUS_TXPLL_LOCK) == 0) {
     61         LOG_WARN(BSL_LS_SOC_PHY,
     62                  (BSL_META_U(unit,
     63                              "XGXS6 : TXPLL did not lock: u=%d p=%d\n"),
     64                   unit, port));
     65         return (SOC_E_TIMEOUT);
     66     }
     67     return (SOC_E_NONE);
     68 }
     69 
     70 /*
     71  * Function:
     72  *      phy_xgxs6_init
     73  * Purpose:     
     74  *      Initialize xgxs6 phys
     75  * Parameters:
     76  *      unit - StrataSwitch unit #.
     77  *      port - StrataSwitch port #. 
     78  * Returns:     
     79  *      SOC_E_NONE
     80  */
     81 
     82 STATIC int
     83 phy_xgxs6_init(int unit, soc_port_t port)
     84 {
     85     int                 rv;               /* Return value */
     86     uint16              mii_ctrl;
     87     phy_ctrl_t         *pc;
     88 
     89     /* NOTE: FusionCore/Unicore init is performed in BigMAC init */
     90 
     91     /* clear loopback (just in case) */
     92     rv = phy_xgxs6_lb_set(unit, port, FALSE);
     93 
     94     /* Initialize the software state */
     95     pc = INT_PHY_SW_STATE(unit, port);
     96 
     97     SOC_IF_ERROR_RETURN
     98         (READ_PHYXGXS6_SERDES_MII_CTRLr(unit, pc, &mii_ctrl));
     99     pc->fiber.autoneg_enable = ((mii_ctrl & MII_CTRL_AE) != 0);
    100 
    101     /* set elasticity fifo size to 13.5k to support 12k jumbo pkt size*/
    102     SOC_IF_ERROR_RETURN
    103         (MODIFY_PHYXGXS6_SERDES_DIGITAL_1000X_CTRL3r(unit,pc, 0x4, 0x6));
    104 
    105      /* disable in-band MDIO. PHY-443 */ 
    106     SOC_IF_ERROR_RETURN 
    107         (PHYXGXS6_REG_MODIFY(unit, pc, 0x00, 0x8110, 0x11, 1 << 3, 1 << 3)); 
    108 
    109     LOG_INFO(BSL_LS_SOC_PHY,
    110              (BSL_META_U(unit,
    111                          "phy_xgxs6_init: u=%d p=%d rv=%d\n"),
    112               unit, port, rv));
    113 
    114     return rv;
    115 }
    116 
    117 /*
    118  * Function:
    119  *      phy_xgxs6_link_get
    120  * Purpose:
    121  *      Get layer2 connection status.
    122  * Parameters:
    123  *      unit - StrataSwitch unit #.
    124  *      port - StrataSwitch port #. 
    125  *      link - address of memory to store link up/down state.
    126  * Returns:     
    127  *      SOC_E_NONE
    128  */
    129 
    130 STATIC int
    131 phy_xgxs6_link_get(int unit, soc_port_t port, int *link)
    132 {
    133     phy_ctrl_t *pc;
    134 
    135     if (PHY_DISABLED_MODE(unit, port)) {
    136         *link = FALSE;
    137         return SOC_E_NONE;
    138     }
    139 
    140     pc = INT_PHY_SW_STATE(unit, port);
    141     if (IS_LMD_ENABLED_PORT(unit, port)) {
    142         uint16      o_misctrl1;
    143         uint16      n_misctrl1;
    144         uint16      sync_stat;
    145 
    146 
    147         SOC_IF_ERROR_RETURN         /* Get mdio reg mapping mode */
    148             (READ_PHYXGXS6_BLK0_MISC_CTRL1r(unit, pc, &o_misctrl1));
    149         n_misctrl1 = 0x0000;
    150         if (n_misctrl1 != o_misctrl1) {
    151             SOC_IF_ERROR_RETURN
    152                 (WRITE_PHYXGXS6_BLK0_MISC_CTRL1r(unit, pc, n_misctrl1));
    153         }
    154         SOC_IF_ERROR_RETURN
    155             (READ_PHYXGXS6_IEEE1_LANE_STATr(unit, pc, &sync_stat));
    156     
    157         if (n_misctrl1 != o_misctrl1) {  /* Restore PMA/PMD mdio reg mapping */
    158             SOC_IF_ERROR_RETURN
    159                 (WRITE_PHYXGXS6_BLK0_MISC_CTRL1r(unit, pc, o_misctrl1));
    160         }
    161      
    162         *link = (sync_stat & 1) ? TRUE : FALSE;
    163     } else {
    164         uint16  mii_serdes_stat;
    165         uint16  mii_xaui_stat;
    166         uint16  xgxs_stat1;
    167         int     an_done;
    168 
    169         /* Link status on both SERDES_MII_STAT and XAUI_MII_STAT registers
    170          * are latched low.
    171          */
    172         SOC_IF_ERROR_RETURN
    173             (READ_PHYXGXS6_SERDES_MII_STATr(unit, pc, &mii_serdes_stat));
    174         SOC_IF_ERROR_RETURN
    175             (READ_PHYXGXS6_XAUI_MII_STATr(unit, pc, &mii_xaui_stat));
    176 
    177         *link = ((mii_serdes_stat & MII_STAT_LA) != 0) ||
    178                 ((mii_xaui_stat & MII_STAT_LA) != 0);
    179 
    180         if (pc->fiber.autoneg_enable) {
    181             SOC_IF_ERROR_RETURN
    182                 (READ_PHYXGXS6_GPSTAT_XGXS_STAT1r(unit, pc, &xgxs_stat1));
    183             /* If autoneg is enabled, check for autoneg done. */
    184             an_done = ((xgxs_stat1 & XGXS_STAT1_AUTONEG_DONE) != 0);
    185 
    186             *link = (*link) && (an_done);
    187         }
    188     }
    189 
    190     return SOC_E_NONE;
    191 }
    192 
    193 STATIC int
    194 _phy_xgxs6_enable_set(int unit, soc_port_t port, int enable)
    195 {
    196     uint16      disable_tx_xe;
    197     uint16      disable_tx_hg;
    198     phy_ctrl_t *pc;
    199 
    200     pc = INT_PHY_SW_STATE(unit, port);
    201 
    202     /* PMA/PMD mapping are different between HG and XE ports.
    203      * Therefore, we need two different settings for HG and XE ports.
    204      */
    205     if (enable) {
    206         disable_tx_xe = 0; /* Clear Tx disable bit for XE*/
    207         disable_tx_hg = 0; /* Clear Tx disable bit for HG*/
    208     } else {
    209         disable_tx_xe = (1 << 0);  /* Set disable Global PMD TX bit for XE */
    210         disable_tx_hg = (1 << 11); /* Set disable Global PMD TX bit for HG */
    211     }
    212 
    213     if (IS_XE_PORT(unit, port)) {
    214         SOC_IF_ERROR_RETURN
    215             (MODIFY_PHYXGXS6_XAUI_TX_DISABLEr(unit, pc, disable_tx_xe, 1 << 0));
    216     } else {
    217         SOC_IF_ERROR_RETURN
    218             (MODIFY_PHYXGXS6_BLK0_MISC_CTRL1r(unit, pc, disable_tx_hg, 
    219                                              (1 << 11)));
    220     }
    221 
    222     /* hold/release rxSeqStart to disable/enable the Rx */
    223     SOC_IF_ERROR_RETURN
    224         (MODIFY_PHYXGXS6_RXALL_CTRLr(unit, pc,
    225                  (enable) ? 0 : (1 << 15), (1 << 15)));
    226 
    227 
    228     return SOC_E_NONE;
    229 }
    230 
    231 
    232 /*
    233  * Function:
    234  *      phy_xgxs6_enable_set
    235  * Purpose:
    236  *      Enable/Disable phy 
    237  * Parameters:
    238  *      unit - StrataSwitch unit #.
    239  *      port - StrataSwitch port #. 
    240  *      enable - on/off state to set
    241  * Returns:     
    242  *      SOC_E_NONE
    243  */
    244 
    245 STATIC int
    246 phy_xgxs6_enable_set(int unit, soc_port_t port, int enable)
    247 {
    248     if (enable) {
    249         PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE);
    250     } else {
    251         PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE);
    252     }
    253     return _phy_xgxs6_enable_set(unit,port,enable);
    254 }
    255 
    256 /*
    257  * Function:
    258  *     _phy_xgxs6_speed_set
    259  * Purpose:
    260  *     Get current Unicore speed.
    261  * Parameters:
    262  *     unit - XGS unit #.
    263  *     port - Port number on unit.
    264  *     speed - new XGXS speed.
    265  * Returns:
    266  *     SOC_E_XXX
    267  * Notes:
    268  *      The Start Sequencer bit in the xgxsControl register should
    269  *      be deasserted before calling this function to guarantee a
    270  *      glitch-free clock change.
    271  */
    272 STATIC int
    273 _phy_xgxs6_speed_set(int unit, soc_port_t port, int speed)
    274 {
    275     int    speed_val;
    276     uint8  phy_addr = PORT_TO_PHY_ADDR_INT(unit, port);
    277     uint16 mii_ctrl, misc1, misc_ctrl;
    278     uint16 block_select;
    279 
    280     if (IS_HG_PORT(unit, port)) {
    281         if ((speed != 0) && (speed < 10000)) {
    282             return SOC_E_PARAM;
    283         }
    284         if (SOC_INFO(unit).port_speed_max[port] > 0 &&
    285             speed > SOC_INFO(unit).port_speed_max[port]) {
    286             return SOC_E_PARAM;
    287         }
    288     } else if (IS_XE_PORT(unit, port)) {
    289         if ((speed != 0) && ((speed < 1000) || (speed > 10000))) {
    290             return SOC_E_PARAM;
    291         }
    292     } else {
    293         if ((speed < 0) || (speed > 2500)) {
    294             return SOC_E_PARAM;
    295         }
    296     }
    297 
    298     switch (speed) {
    299     case 13000:
    300         speed_val = 7;
    301         break;
    302     case 12500:
    303         speed_val = 6;
    304         break;
    305     case 12000:
    306         speed_val = 5;
    307         break;
    308     case 10000:
    309         speed_val = 4; /* 10G CX4 */
    310         if (IS_HG_PORT(unit, port) && 
    311             soc_property_port_get(unit, port, spn_10G_IS_CX4, TRUE) == FALSE) {
    312             speed_val = 3; /* 10G HiG */
    313         }
    314         break;
    315     case 2500:
    316         speed_val = 0;
    317         break;
    318     case 1000:
    319     case 100:
    320     case 10:
    321         speed_val = -1;
    322         break;
    323     case 0:
    324         return SOC_E_NONE;
    325     case 16000:
    326                                 case 15000:
    327     case 6000:
    328     case 5000:
    329     default:
    330         return SOC_E_PARAM;
    331     }
    332 
    333     /* Save original block select mapping */
    334     SOC_IF_ERROR_RETURN
    335         (soc_miim_read(unit, phy_addr, 0x1f, &block_select));
    336 
    337     /* Select block DIGITAL (0x30) */
    338     SOC_IF_ERROR_RETURN
    339         (soc_miim_write(unit, phy_addr, 0x1f, 0x0300));
    340 
    341     /* Set speed in Misc1 register */
    342     SOC_IF_ERROR_RETURN
    343         (soc_miim_read(unit, phy_addr, 0x18, &misc1));
    344     misc1 &= ~0x001f;
    345     if (speed_val >= 0) {
    346         misc1 |= 0x0010 | speed_val;
    347     }
    348     SOC_IF_ERROR_RETURN
    349         (soc_miim_write(unit, phy_addr, 0x18, misc1));
    350 
    351     /* Select block BLOCK0 */
    352     SOC_IF_ERROR_RETURN
    353         (soc_miim_write(unit, phy_addr, 0x1f, 0x0000));
    354 
    355     /* Map XAUI or SerDes IEEE registers */
    356     SOC_IF_ERROR_RETURN
    357         (soc_miim_read(unit, phy_addr, 0x1e, &misc_ctrl));
    358     /* Disable dynamic IEEE address space mapping and
    359      * map Serdes IEEE address space.
    360      */
    361     misc_ctrl &= ~0x0003;
    362     if (speed > 2500) {
    363         misc_ctrl |= 0x0001; /* Select XAUI registers */
    364     }
    365 
    366     /* Write final IEEE register mapping */
    367     SOC_IF_ERROR_RETURN
    368         (soc_miim_write(unit, phy_addr, 0x1e, misc_ctrl));
    369 
    370     /*
    371      * Speeds of 2.5 Gbps and below must be set in IEEE registers.
    372      */
    373     if (speed <= 2500) {
    374         SOC_IF_ERROR_RETURN
    375             (soc_miim_read(unit, phy_addr, MII_CTRL_REG, &mii_ctrl));
    376         mii_ctrl &= ~(MII_CTRL_SS_MASK | MII_CTRL_FS_2500);
    377         if (speed == 2500) {
    378             /* Force 2.5 Gbps */
    379             mii_ctrl |= MII_CTRL_FS_2500;
    380         } else if (speed == 1000) {
    381             mii_ctrl |= MII_CTRL_SS_1000;
    382         } else if (speed == 100) {
    383             mii_ctrl |= MII_CTRL_SS_100;
    384         } else {
    385             mii_ctrl |= MII_CTRL_SS_10;
    386         }
    387         SOC_IF_ERROR_RETURN
    388             (soc_miim_write(unit, phy_addr, MII_CTRL_REG, mii_ctrl));
    389     }
    390 
    391     /* Restore Original Block select mapping */
    392     SOC_IF_ERROR_RETURN
    393         (soc_miim_write(unit, phy_addr, 0x1f, block_select));
    394 
    395     return SOC_E_NONE;
    396 }
    397 /*
    398  * Function:
    399  *      phy_xgxs6_speed_set
    400  * Purpose:
    401  *      Set PHY speed
    402  * Parameters:
    403  *      unit - StrataSwitch unit #.
    404  *      port - StrataSwitch port #. 
    405  *      speed - link speed in Mbps
    406  * Returns:     
    407  *      SOC_E_NONE
    408  */
    409 
    410 STATIC int
    411 phy_xgxs6_speed_set(int unit, soc_port_t port, int speed)
    412 {
    413     int         rv;
    414     int         an;
    415     int         cur_speed;
    416     phy_ctrl_t *pc;
    417 
    418     /* If already forced to requested speed, don't change anything */
    419     SOC_IF_ERROR_RETURN
    420         (phy_xgxs6_an_get(unit, port, &an, NULL));
    421     if (!an) {
    422         SOC_IF_ERROR_RETURN
    423             (phy_xgxs6_speed_get(unit, port, &cur_speed));
    424         if (cur_speed == speed) {
    425             return SOC_E_NONE;
    426         }
    427     }
    428 
    429     rv = SOC_E_NONE;
    430     pc = INT_PHY_SW_STATE(unit, port);
    431 
    432     /* Stop sequencer */
    433     SOC_IF_ERROR_RETURN
    434         (MODIFY_PHYXGXS6_BLK0_CTRLr(unit, pc, 0, 0x2000));
    435 
    436     /* Disable autoneg if needed */
    437     if (an) {
    438         rv = (phy_xgxs6_an_set(unit, port, FALSE));
    439     }
    440 
    441     if (SOC_SUCCESS(rv)) {
    442         rv = _phy_xgxs6_speed_set(unit, port, speed);
    443     }
    444 
    445     /* Need to restart sequencer even if speed_set failed */
    446     SOC_IF_ERROR_RETURN
    447         (MODIFY_PHYXGXS6_BLK0_CTRLr(unit, pc, 0x2000, 0x2000));
    448 
    449     /* Wait for Tx PLL lock */
    450     if (SOC_SUCCESS(rv)) {
    451         rv =  _phy_xgxs6_pll_lock_wait(unit, port);
    452     }
    453 
    454     return rv;
    455 }
    456 
    457 /*
    458  * Function:
    459  *      phy_xgxs6_speed_get
    460  * Purpose:
    461  *      Get PHY speed
    462  * Parameters:
    463  *      unit - StrataSwitch unit #.
    464  *      port - StrataSwitch port #. 
    465  *      speed - current link speed in Mbps
    466  * Returns:     
    467  *      SOC_E_NONE
    468  */
    469 STATIC int
    470 phy_xgxs6_speed_get(int unit, soc_port_t port, int *speed)
    471 {
    472     uint16      xgxs_stat;
    473     int         an;
    474     int         an_done;
    475     phy_ctrl_t *pc;
    476 
    477     /* Default speed */
    478     *speed = 10000;
    479 
    480     pc = INT_PHY_SW_STATE(unit, port);
    481 
    482     SOC_IF_ERROR_RETURN
    483         (phy_xgxs6_an_get(unit, port, &an, &an_done));
    484     if (an && !an_done) {
    485         *speed = 0;
    486         return (SOC_E_NONE);
    487     }
    488 
    489     SOC_IF_ERROR_RETURN
    490         (READ_PHYXGXS6_GPSTAT_XGXS_STAT1r(unit, pc, &xgxs_stat));
    491     switch (xgxs_stat & XGXS_STAT1_ACTUAL_SPEED_MASK) {
    492     case XGXS_STAT1_ACTUAL_SPEED_10:       *speed = 10; break;
    493     case XGXS_STAT1_ACTUAL_SPEED_100:      *speed = 100; break;
    494     case XGXS_STAT1_ACTUAL_SPEED_1000:     *speed = 1000; break;
    495     case XGXS_STAT1_ACTUAL_SPEED_2500:     *speed = 2500; break;
    496     case XGXS_STAT1_ACTUAL_SPEED_5000:     *speed = 5000; break;
    497     case XGXS_STAT1_ACTUAL_SPEED_6000:     *speed = 6000; break;
    498     case XGXS_STAT1_ACTUAL_SPEED_10000:    /* fall through */
    499     case XGXS_STAT1_ACTUAL_SPEED_10000CX4: *speed = 10000; break;
    500     case XGXS_STAT1_ACTUAL_SPEED_12000:    *speed = 12000; break;
    501     case XGXS_STAT1_ACTUAL_SPEED_12500:    *speed = 12500; break;
    502     case XGXS_STAT1_ACTUAL_SPEED_13000:    *speed = 13000; break;
    503     case XGXS_STAT1_ACTUAL_SPEED_15000:    *speed = 15000; break;
    504     case XGXS_STAT1_ACTUAL_SPEED_16000:    *speed = 16000; break;
    505     default:
    506         return SOC_E_INTERNAL;
    507     } 
    508 
    509     return SOC_E_NONE;
    510 }
    511 
    512 /*
    513  * Function:    
    514  *      phy_xgxs6_an_set
    515  * Purpose:     
    516  *      Enable or disabled auto-negotiation on the specified port.
    517  * Parameters:
    518  *      unit - StrataSwitch unit #.
    519  *      port - StrataSwitch port #. 
    520  *      an   - Boolean, if true, auto-negotiation is enabled 
    521  *              (and/or restarted). If false, autonegotiation is disabled.
    522  * Returns:     
    523  *      SOC_E_XXX
    524  */
    525 int
    526 phy_xgxs6_an_set(int unit, soc_port_t port, int an)
    527 {
    528     int         rv; 
    529     uint16      mii_ctrl;
    530     uint16      xgxs_ctrl;
    531     uint16      mreg_val;
    532     phy_ctrl_t *pc;
    533 
    534     rv = SOC_E_NONE;
    535     pc = INT_PHY_SW_STATE(unit, port);
    536 
    537     /*
    538      * Configure signal auto-detection between SGMII and fiber.
    539      * This detection only works if auto-negotiation is enabled.
    540      */
    541     SOC_IF_ERROR_RETURN
    542         (READ_PHYXGXS6_SERDES_DIGITAL_1000X_CTRL1r(unit, pc, &mreg_val));
    543 
    544     mreg_val &= ~(1 << 4);  /* Clear auto-detect */
    545     if (an) {
    546         if (soc_property_port_get(unit, port, 
    547                                   spn_SERDES_AUTOMEDIUM, TRUE)) {
    548             mreg_val |= (1 << 4);   /* Set auto-detect */
    549         }
    550     }
    551     SOC_IF_ERROR_RETURN
    552         (WRITE_PHYXGXS6_SERDES_DIGITAL_1000X_CTRL1r(unit, pc, mreg_val));
    553 
    554     /* Stop sequencer */
    555     SOC_IF_ERROR_RETURN
    556         (READ_PHYXGXS6_BLK0_CTRLr(unit, pc, &xgxs_ctrl));
    557     SOC_IF_ERROR_RETURN
    558         (WRITE_PHYXGXS6_BLK0_CTRLr(unit, pc, xgxs_ctrl & ~0x2000));
    559 
    560     /* Autoneg enable bit in SerDes block is for both SerDes 
    561      * and XAUI core */
    562     mii_ctrl = (an) ? MII_CTRL_AE | MII_CTRL_RAN : 0;
    563     rv = MODIFY_PHYXGXS6_SERDES_MII_CTRLr(unit, pc, mii_ctrl, 
    564                                           MII_CTRL_AE | MII_CTRL_RAN);
    565 
    566     /* Restore sequencer */
    567     SOC_IF_ERROR_RETURN
    568         (WRITE_PHYXGXS6_BLK0_CTRLr(unit, pc, xgxs_ctrl));
    569 
    570     if (rv < 0) {
    571         return rv;
    572     }
    573 
    574     /* Wait for Tx PLL lock if sequencer was restarted */
    575     if (xgxs_ctrl & 0x2000) {
    576         rv = _phy_xgxs6_pll_lock_wait(unit, port);
    577     }
    578  
    579     /* Save autoneg state in software */
    580     pc->fiber.autoneg_enable = an;
    581 
    582     return rv;
    583 }
    584 
    585 /*
    586  * Function:    
    587  *      phy_xgxs6_an_get
    588  * Purpose:     
    589  *      Get the current auto-negotiation status (enabled/busy)
    590  * Parameters:
    591  *      unit - StrataSwitch unit #.
    592  *      port - StrataSwitch port #. 
    593  *      an   - (OUT) if true, auto-negotiation is enabled.
    594  *      an_done - (OUT) if true, auto-negotiation is complete. This
    595  *              value is undefined if an == false.
    596  * Returns:     
    597  *      SOC_E_XXX
    598  */
    599 
    600 int
    601 phy_xgxs6_an_get(int unit, soc_port_t port, int *an, int *an_done)
    602 {
    603     uint16      mii_ctrl;
    604     uint16      mii_stat;
    605     phy_ctrl_t *pc;
    606 
    607     pc = INT_PHY_SW_STATE(unit, port);
    608 
    609     SOC_IF_ERROR_RETURN
    610         (READ_PHYXGXS6_SERDES_MII_CTRLr(unit, pc, &mii_ctrl));
    611     SOC_IF_ERROR_RETURN
    612         (READ_PHYXGXS6_SERDES_MII_STATr(unit, pc, &mii_stat));
    613 
    614     *an = (mii_ctrl & MII_CTRL_AE) ? TRUE : FALSE;
    615 
    616     if (NULL != an_done) {
    617         *an_done = (mii_stat & MII_STAT_AN_DONE) ? TRUE : FALSE;
    618     }
    619 
    620     return SOC_E_NONE; 
    621 }
    622 
    623 /*
    624  * Function:
    625  *      phy_xgxs6_adv_local_set
    626  * Purpose:
    627  *      Set the current advertisement for auto-negotiation.
    628  * Parameters:
    629  *      unit - StrataSwitch unit #.
    630  *      port - StrataSwitch port #.
    631  *      mode - Port mode mask indicating supported options/speeds.
    632  * Returns:
    633  *      SOC_E_XXX
    634  * Notes:
    635  *      The advertisement is set only for the ACTIVE medium.
    636  *      No synchronization performed at this level.
    637  */
    638 
    639 STATIC int
    640 phy_xgxs6_adv_local_set(int unit, soc_port_t port, soc_port_mode_t mode)
    641 {
    642     uint16      an_adv;
    643     uint16      speed_10g;
    644     phy_ctrl_t *pc;
    645 
    646     pc = INT_PHY_SW_STATE(unit, port);
    647 
    648     /*
    649      * Set advertised duplex (only FD supported).
    650      */
    651     an_adv = (mode & SOC_PM_1000MB_FD) ? XGXS6_ANA_FD : 0;
    652 
    653     /*
    654      * Set advertised pause bits in link code word.
    655      */
    656     switch (mode & SOC_PM_PAUSE) {
    657     case SOC_PM_PAUSE_TX:
    658         an_adv |= XGXS6_ANA_PAUSE_ASYM;
    659         break;
    660     case SOC_PM_PAUSE_RX:
    661         an_adv |= XGXS6_ANA_PAUSE_SYM | XGXS6_ANA_PAUSE_ASYM;
    662         break;
    663     case SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX:
    664         an_adv |= XGXS6_ANA_PAUSE_SYM;
    665         break;
    666     }
    667 
    668     /* Update less than 1G capability */ 
    669     SOC_IF_ERROR_RETURN
    670         (WRITE_PHYXGXS6_SERDES_MII_ANAr(unit, pc, an_adv));
    671   
    672     /* Over 1G advertising */
    673     if (IS_HG_PORT(unit, port)) {
    674         /* For Draco and Hercules, use pre-CX4 signalling */
    675         speed_10g = (1 << 3);
    676         if (soc_property_port_get(unit, port, spn_10G_IS_CX4, TRUE)) {
    677             /* Also include 10G CX4 signalling by default */
    678             speed_10g |= (1 << 4);
    679         }
    680 
    681         /* Advertise 10G */
    682         an_adv  = (mode & SOC_PM_10GB) ? speed_10g : 0;
    683         an_adv |= (mode & SOC_PM_12GB) ? (1 << 5) : 0;
    684         an_adv |= (mode & SOC_PM_13GB) ? (1 << 7) : 0;
    685     } else {
    686         /* Advertise 10G CX4 */
    687         an_adv  = (mode & SOC_PM_10GB) ? (1 << 4) : 0; 
    688         an_adv |= (mode & SOC_PM_2500MB) ? (1 << 0) : 0;
    689     }
    690     SOC_IF_ERROR_RETURN
    691         (WRITE_PHYXGXS6_OVER1G_UP1r(unit, pc, an_adv));
    692 
    693     LOG_INFO(BSL_LS_SOC_PHY,
    694              (BSL_META_U(unit,
    695                          "phy_xgxs6_adv_local_set:unit=%d p=%d mode=0x%08x\n"),
    696               unit, port, mode));
    697 
    698     return SOC_E_NONE;
    699 }
    700 
    701 /*
    702  * Function:
    703  *      phy_xgxs6_adv_local_get
    704  * Purpose:
    705  *      Get the current advertisement for auto-negotiation.
    706  * Parameters:
    707  *      unit - StrataSwitch unit #.
    708  *      port - StrataSwitch port #.
    709  *      mode - (OUT) Port mode mask indicating supported options/speeds.
    710  * Returns:
    711  *      SOC_E_XXX
    712  * Notes:
    713  *      The advertisement is retrieved for the ACTIVE medium.
    714  *      No synchronization performed at this level.
    715  */
    716 
    717 STATIC int
    718 phy_xgxs6_adv_local_get(int unit, soc_port_t port, soc_port_mode_t *mode)
    719 {
    720     uint16      an_adv;
    721     phy_ctrl_t *pc;
    722 
    723     pc = INT_PHY_SW_STATE(unit, port);
    724 
    725     SOC_IF_ERROR_RETURN
    726         (READ_PHYXGXS6_OVER1G_UP1r(unit, pc, &an_adv));
    727 
    728     *mode = 0;
    729     if (IS_HG_PORT(unit, port)) {
    730         *mode  = (an_adv & ((1 << 3) | (1 << 4))) ? SOC_PM_10GB_FD : 0;
    731         *mode |= (an_adv & (1 << 5)) ? SOC_PM_12GB_FD : 0;
    732         *mode |= (an_adv & (1 << 7)) ? SOC_PM_13GB_FD : 0;
    733     } else {
    734         *mode  = (an_adv & (1 << 4)) ? SOC_PM_10GB_FD : 0;
    735         *mode |= (an_adv & (1 << 0)) ? SOC_PM_2500MB_FD : 0;
    736 
    737         SOC_IF_ERROR_RETURN
    738             (READ_PHYXGXS6_SERDES_MII_ANAr(unit, pc, &an_adv));
    739       
    740         *mode |= (an_adv & XGXS6_ANA_FD) ? SOC_PM_1000MB_FD : 0;
    741 
    742         switch (an_adv & (XGXS6_ANA_PAUSE_SYM | XGXS6_ANA_PAUSE_ASYM)) {
    743             case XGXS6_ANA_PAUSE_SYM:
    744                 *mode |= SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX;
    745                 break;
    746             case XGXS6_ANA_PAUSE_ASYM:
    747                 *mode |= SOC_PM_PAUSE_TX;
    748                 break;
    749             case XGXS6_ANA_PAUSE_SYM | XGXS6_ANA_PAUSE_ASYM:
    750                 *mode |= SOC_PM_PAUSE_RX;
    751                 break;
    752         }
    753 
    754     }
    755 
    756     LOG_INFO(BSL_LS_SOC_PHY,
    757              (BSL_META_U(unit,
    758                          "phy_xgxs6_adv_local_get:unit=%d p=%d mode=0x%08x\n"),
    759               unit, port, *mode));
    760 
    761     return SOC_E_NONE;
    762 }
    763 
    764 /*
    765  * Function:
    766  *      phy_xgxs6_adv_remote_get
    767  * Purpose:
    768  *      Get the current advertisement for auto-negotiation.
    769  * Parameters:
    770  *      unit - StrataSwitch unit #.
    771  *      port - StrataSwitch port #.
    772  *      mode - (OUT) Port mode mask indicating supported options/speeds.
    773  * Returns:
    774  *      SOC_E_XXX
    775  * Notes:
    776  *      The advertisement is retrieved for the ACTIVE medium.
    777  *      No synchronization performed at this level.
    778  */
    779 
    780 STATIC int
    781 phy_xgxs6_adv_remote_get(int unit, soc_port_t port, soc_port_mode_t *mode)
    782 {
    783     uint16      an_adv;
    784     phy_ctrl_t *pc;
    785 
    786     pc = INT_PHY_SW_STATE(unit, port);
    787 
    788     SOC_IF_ERROR_RETURN
    789         (READ_PHYXGXS6_OVER1G_LP_UP1r(unit, pc, &an_adv));
    790 
    791     *mode = 0;
    792     if (IS_HG_PORT(unit, port)) {
    793         *mode = (an_adv & ((1 << 3) | (1 << 4))) ? SOC_PM_10GB_FD : 0;
    794         *mode |= (an_adv & (1 << 5)) ? SOC_PM_12GB_FD : 0;
    795         *mode |= (an_adv & (1 << 7)) ? SOC_PM_13GB_FD : 0;
    796     } else {
    797         *mode  = (an_adv & (1 << 4)) ? SOC_PM_10GB_FD : 0;
    798         *mode |= (an_adv & (1 << 0)) ? SOC_PM_2500MB_FD : 0;
    799 
    800         SOC_IF_ERROR_RETURN
    801             (READ_PHYXGXS6_SERDES_MII_ANPr(unit, pc, &an_adv));
    802       
    803         *mode |= (an_adv & XGXS6_ANP_FD) ? SOC_PM_1000MB_FD : 0;
    804 
    805         switch (an_adv & (XGXS6_ANP_PAUSE_SYM | XGXS6_ANP_PAUSE_ASYM)) {
    806             case XGXS6_ANP_PAUSE_SYM:
    807                 *mode |= SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX;
    808                 break;
    809             case XGXS6_ANP_PAUSE_ASYM:
    810                 *mode |= SOC_PM_PAUSE_TX;
    811                 break;
    812             case XGXS6_ANP_PAUSE_SYM | XGXS6_ANP_PAUSE_ASYM:
    813                 *mode |= SOC_PM_PAUSE_RX;
    814                 break;
    815         }
    816     }
    817  
    818     LOG_INFO(BSL_LS_SOC_PHY,
    819              (BSL_META_U(unit,
    820                          "phy_xgxs6_adv_remote_get:unit=%d p=%d mode=0x%08x\n"),
    821               unit, port, *mode));
    822 
    823     return SOC_E_NONE;
    824 }
    825 
    826 
    827 /*
    828  * Function:
    829  *      phy_xgxs6_lb_set
    830  * Purpose:
    831  *      Put XGXS6/FusionCore in PHY loopback
    832  * Parameters:
    833  *      unit - StrataSwitch unit #.
    834  *      port - StrataSwitch port #. 
    835  *      enable - binary value for on/off (1/0)
    836  * Returns:     
    837  *      SOC_E_NONE
    838  */
    839 
    840 STATIC int
    841 phy_xgxs6_lb_set(int unit, soc_port_t port, int enable)
    842 {
    843     int         rv;
    844     phy_ctrl_t *pc;
    845     uint16      lb_bit;
    846 
    847     rv = SOC_E_NONE;
    848 
    849     pc = INT_PHY_SW_STATE(unit, port);
    850 
    851     if (IS_LMD_ENABLED_PORT(unit, port)) {
    852         SOC_IF_ERROR_RETURN
    853             (WRITE_PHYXGXS6_BLK1_LANE_CTRL2r(unit, pc, 
    854                                              (enable) ? 0xFF0F : 0xFF00)); 
    855         return SOC_E_NONE;
    856     }
    857 
    858     /*
    859      * control RX signal detect, so that a cable is not needed for loopback
    860      */
    861     SOC_IF_ERROR_RETURN
    862         (MODIFY_PHYXGXS6_RXALL_CTRLr(unit, pc, (enable) ? 0x0010 : 0, 0x0010));
    863 
    864     /*
    865      * control the actual loopback bit
    866      */
    867     lb_bit = XGXS6_IEEE_CTRL_LB_ENA;
    868     if (IS_XE_PORT(unit, port)) {
    869         lb_bit = 1;
    870     }
    871     SOC_IF_ERROR_RETURN
    872         (MODIFY_PHYXGXS6_XAUI_MII_CTRLr(unit, pc,
    873                                         (enable) ? lb_bit : 0, lb_bit)); 
    874 
    875     SOC_IF_ERROR_RETURN
    876         (MODIFY_PHYXGXS6_SERDES_MII_CTRLr(unit, pc,
    877                                          (enable) ? MII_CTRL_LE : 0,
    878                                          MII_CTRL_LE));
    879  
    880     return rv;
    881 }
    882 
    883 /*
    884  * Function:
    885  *      phy_xgxs6_lb_get
    886  * Purpose:
    887  *      Get XGXS6/FusionCore PHY loopback state
    888  * Parameters:
    889  *      unit - StrataSwitch unit #.
    890  *      port - StrataSwitch port #. 
    891  *      enable - address of location to store binary value for on/off (1/0)
    892  * Returns:     
    893  *      SOC_E_NONE
    894  */
    895 
    896 STATIC int
    897 phy_xgxs6_lb_get(int unit, soc_port_t port, int *enable)
    898 {
    899     uint16      reg_val; 
    900     uint16      lb_bit;
    901     phy_ctrl_t *pc;
    902  
    903     pc = INT_PHY_SW_STATE(unit, port);
    904 
    905     if (IS_LMD_ENABLED_PORT(unit, port)) {
    906         SOC_IF_ERROR_RETURN             /* Get Loopback status*/
    907             (READ_PHYXGXS6_BLK1_LANE_CTRL2r(unit, pc, &reg_val));
    908 
    909         *enable = ((reg_val & 0x000F) == 0x000f) ? TRUE : FALSE;
    910         return SOC_E_NONE;
    911     }
    912 
    913     lb_bit = XGXS6_IEEE_CTRL_LB_ENA;
    914     if (IS_XE_PORT(unit, port)) {
    915         lb_bit = 1;
    916     }
    917  
    918     SOC_IF_ERROR_RETURN
    919         (READ_PHYXGXS6_XAUI_MII_CTRLr(unit, pc, &reg_val));
    920 
    921     *enable = (reg_val & lb_bit) ? TRUE : FALSE;
    922 
    923     return SOC_E_NONE;
    924 }
    925 
    926 
    927 STATIC int
    928 phy_xgxs6_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode)
    929 {
    930     phy_ctrl_t *pc;
    931  
    932     pc = INT_PHY_SW_STATE(unit, port);
    933 
    934     *mode = (SOC_PM_1000MB_FD | SOC_PM_2500MB_FD | 
    935              SOC_PM_MII | SOC_PM_XGMII | SOC_PM_LB_PHY | SOC_PM_AN |
    936              SOC_PM_PAUSE | SOC_PM_PAUSE_ASYMM);
    937     switch(pc->speed_max) {
    938         case 13000:
    939             *mode |= SOC_PM_13GB_FD;
    940             /* fall through */
    941         case 12000:
    942             *mode |= SOC_PM_12GB_FD;
    943             /* fall through */
    944         default:
    945             *mode |= SOC_PM_10GB_FD;
    946     }
    947     
    948     return SOC_E_NONE;
    949 }
    950 
    951 STATIC int
    952 _phy_xgxs6_control_tx_driver_set(int unit, phy_ctrl_t *pc,
    953                                 soc_phy_control_t type, uint32 value)
    954 {
    955     uint16  data;             /* Temporary holder of reg value to be written */
    956     uint16  mask;             /* Bit mask of reg value to be updated */
    957 
    958     if (value > 15) {
    959         return SOC_E_PARAM;
    960     }
    961 
    962     data = mask = 0;
    963     switch(type) {
    964     case SOC_PHY_CONTROL_PREEMPHASIS:
    965          data = _shr_bit_rev8((uint8)value) << 8;
    966          mask = 0xF000;
    967          break;
    968     case SOC_PHY_CONTROL_DRIVER_CURRENT:
    969          data = _shr_bit_rev8((uint8)value) << 4;
    970          mask = 0x0F00;
    971          break;
    972     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
    973          data = _shr_bit_rev8((uint8)value);
    974          mask = 0x00F0;
    975          break;
    976     default:
    977          /* should never get here */
    978          return SOC_E_PARAM;
    979     }
    980 
    981     /* Update preemphasis/driver/pre-driver current */
    982     SOC_IF_ERROR_RETURN
    983         (MODIFY_PHYXGXS6_TXALL_DRIVERr(unit, pc, data, mask));
    984 
    985     return SOC_E_NONE;
    986 }
    987 
    988 STATIC int
    989 _phy_xgxs6_control_tx_driver_get(int unit, phy_ctrl_t *pc,
    990                                 soc_phy_control_t type, uint32 *value)
    991 {
    992     uint16  data16;           /* Temporary holder of 16 bit reg value */
    993     uint8   data8;            /* Temporary holder of 8 bit reg value */
    994 
    995     /* Read preemphasis/driver/pre-driver current */
    996     SOC_IF_ERROR_RETURN
    997         (READ_PHYXGXS6_TXALL_DRIVERr(unit, pc, &data16));
    998 
    999     switch(type) {
   1000     case SOC_PHY_CONTROL_PREEMPHASIS:
   1001          data8 = (uint8)((data16 & 0xF000) >> 8);
   1002          *value = _shr_bit_rev8(data8);
   1003          break;
   1004     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   1005          data8 = (uint8)((data16 & 0x0F00) >> 4);
   1006          *value = _shr_bit_rev8(data8);
   1007          break;
   1008     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   1009          data8 = (uint8)(data16 & 0x00F0);
   1010          *value = _shr_bit_rev8(data8);
   1011          break;
   1012     default:
   1013          /* should never get here */
   1014          return SOC_E_PARAM;
   1015     }
   1016 
   1017     return SOC_E_NONE;
   1018 }
   1019 
   1020 
   1021 /*
   1022  * Function:
   1023  *      phy_xgxs6_control_set
   1024  * Purpose:
   1025  *      Configure PHY device specific control fucntion. 
   1026  * Parameters:
   1027  *      unit  - StrataSwitch unit #.
   1028  *      port  - StrataSwitch port #. 
   1029  *      type  - Control to update 
   1030  *      value - New setting for the control 
   1031  * Returns:     
   1032  *      SOC_E_NONE
   1033  */
   1034 STATIC int
   1035 phy_xgxs6_control_set(int unit, soc_port_t port,
   1036                      soc_phy_control_t type, uint32 value)
   1037 {
   1038     int rv;
   1039     phy_ctrl_t *pc;
   1040     /* coverity[mixed_enums] */
   1041     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
   1042         return SOC_E_PARAM;
   1043     }
   1044    
   1045     pc = INT_PHY_SW_STATE(unit, port);
   1046     rv = SOC_E_UNAVAIL;
   1047     switch(type) {
   1048     case SOC_PHY_CONTROL_PREEMPHASIS:
   1049         /* fall through */
   1050     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   1051         /* fall through */
   1052     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   1053         rv = _phy_xgxs6_control_tx_driver_set(unit, pc, type, value);
   1054         break;
   1055     default:
   1056         rv = SOC_E_UNAVAIL;
   1057         break; 
   1058     }
   1059     return rv;
   1060 }
   1061 
   1062 /*
   1063  * Function:
   1064  *      phy_xgxs6_control_get
   1065  * Purpose:
   1066  *      Get current control settign of the PHY. 
   1067  * Parameters:
   1068  *      unit  - StrataSwitch unit #.
   1069  *      port  - StrataSwitch port #. 
   1070  *      type  - Control to update 
   1071  *      value - (OUT)Current setting for the control 
   1072  * Returns:     
   1073  *      SOC_E_NONE
   1074  */
   1075 STATIC int
   1076 phy_xgxs6_control_get(int unit, soc_port_t port,
   1077                      soc_phy_control_t type, uint32 *value)
   1078 {
   1079     int rv;
   1080     phy_ctrl_t *pc;
   1081 
   1082     if (NULL == value) {
   1083         return SOC_E_PARAM;
   1084     }
   1085      /* coverity[mixed_enums] */
   1086     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
   1087         return SOC_E_PARAM;
   1088     }
   1089    
   1090     pc = INT_PHY_SW_STATE(unit, port);
   1091     rv = SOC_E_UNAVAIL;
   1092     switch(type) {
   1093     case SOC_PHY_CONTROL_PREEMPHASIS:
   1094         /* fall through */
   1095     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   1096         /* fall through */
   1097     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   1098         rv = _phy_xgxs6_control_tx_driver_get(unit, pc, type, value);
   1099         break;
   1100     default:
   1101         rv = SOC_E_UNAVAIL;
   1102         break; 
   1103     }
   1104 
   1105     return rv;
   1106 }
   1107 
   1108 /*
   1109  * Function:
   1110  *      phy_xgxs6_reg_read
   1111  * Purpose:
   1112  *      Routine to read PHY register
   1113  * Parameters:
   1114  *      uint         - BCM unit number
   1115  *      pc           - PHY state
   1116  *      flags        - Flags which specify the register type
   1117  *      phy_reg_addr - Encoded register address
   1118  *      phy_data     - (OUT) Value read from PHY register
   1119  * Note:
   1120  *      This register read function is not thread safe. Higher level
   1121  * function that calls this function must obtain a per port lock
   1122  * to avoid overriding register page mapping between threads.
   1123  */
   1124 STATIC int
   1125 phy_xgxs6_reg_read(int unit, soc_port_t port, uint32 flags,
   1126                   uint32 phy_reg_addr, uint32 *phy_data)
   1127 {
   1128     uint32               reg_flags;
   1129     uint16               reg_bank;
   1130     uint8                reg_addr;
   1131     uint16               data;     /* Temporary holder for phy_data */
   1132     phy_ctrl_t           *pc;      /* PHY software state */
   1133 
   1134     COMPILER_REFERENCE(flags);
   1135 
   1136     pc   = INT_PHY_SW_STATE(unit, port);
   1137 
   1138     reg_flags = SOC_PHY_REG_FLAGS(phy_reg_addr);
   1139     reg_bank  = SOC_PHY_REG_BANK(phy_reg_addr);
   1140     reg_addr  = SOC_PHY_REG_ADDR(phy_reg_addr);
   1141 
   1142     SOC_IF_ERROR_RETURN
   1143         (phy_reg_xgxs6_read(unit, pc, reg_flags, reg_bank, reg_addr, &data));
   1144 
   1145    *phy_data = data;
   1146 
   1147     return SOC_E_NONE;
   1148 }
   1149 
   1150 /*
   1151  * Function:
   1152  *      phy_xgxs6_reg_write
   1153  * Purpose:
   1154  *      Routine to write PHY register
   1155  * Parameters:
   1156  *      uint         - BCM unit number
   1157  *      pc           - PHY state
   1158  *      flags        - Flags which specify the register type
   1159  *      phy_reg_addr - Encoded register address
   1160  *      phy_data     - Value write to PHY register
   1161  * Note:
   1162  *      This register read function is not thread safe. Higher level
   1163  * function that calls this function must obtain a per port lock
   1164  * to avoid overriding register page mapping between threads.
   1165  */
   1166 STATIC int
   1167 phy_xgxs6_reg_write(int unit, soc_port_t port, uint32 flags,
   1168                    uint32 phy_reg_addr, uint32 phy_data)
   1169 {
   1170     uint32               reg_flags;
   1171     uint16               reg_bank;
   1172     uint8                reg_addr;
   1173     uint16               data;     /* Temporary holder for phy_data */
   1174     phy_ctrl_t           *pc;      /* PHY software state */
   1175 
   1176     COMPILER_REFERENCE(flags);
   1177 
   1178 
   1179     pc   = INT_PHY_SW_STATE(unit, port);
   1180     data = (uint16) (phy_data & 0x0000FFFF);
   1181 
   1182     reg_flags = SOC_PHY_REG_FLAGS(phy_reg_addr);
   1183     reg_bank  = SOC_PHY_REG_BANK(phy_reg_addr);
   1184     reg_addr  = SOC_PHY_REG_ADDR(phy_reg_addr);
   1185 
   1186     return phy_reg_xgxs6_write(unit, pc, reg_flags, reg_bank, reg_addr, data);
   1187 }  
   1188 
   1189 /*
   1190  * Function:
   1191  *      phy_xgxs6_reg_modify
   1192  * Purpose:
   1193  *      Routine to write PHY register
   1194  * Parameters:
   1195  *      uint         - BCM unit number
   1196  *      pc           - PHY state
   1197  *      flags        - Flags which specify the register type
   1198  *      phy_reg_addr - Encoded register address
   1199  *      phy_mo_data  - New value for the bits specified in phy_mo_mask
   1200  *      phy_mo_mask  - Bit mask to modify
   1201  * Note:
   1202  *      This register read function is not thread safe. Higher level
   1203  * function that calls this function must obtain a per port lock
   1204  * to avoid overriding register page mapping between threads.
   1205  */
   1206 STATIC int
   1207 phy_xgxs6_reg_modify(int unit, soc_port_t port, uint32 flags,
   1208                     uint32 phy_reg_addr, uint32 phy_data,
   1209                     uint32 phy_data_mask)
   1210 {
   1211     uint32               reg_flags;
   1212     uint16               reg_bank;
   1213     uint8                reg_addr;
   1214     uint16               data;     /* Temporary holder for phy_data */
   1215     uint16               mask;     /* Temporary holder for phy_data_mask */
   1216     phy_ctrl_t           *pc;      /* PHY software state */
   1217 
   1218     COMPILER_REFERENCE(flags);
   1219 
   1220     pc   = INT_PHY_SW_STATE(unit, port);
   1221     data = (uint16) (phy_data & 0x0000FFFF);
   1222     mask = (uint16) (phy_data_mask & 0x0000FFFF);
   1223 
   1224     reg_flags = SOC_PHY_REG_FLAGS(phy_reg_addr);
   1225     reg_bank  = SOC_PHY_REG_BANK(phy_reg_addr);
   1226     reg_addr  = SOC_PHY_REG_ADDR(phy_reg_addr);
   1227 
   1228     return phy_reg_xgxs6_modify(unit, pc, reg_flags, 
   1229                              reg_bank, reg_addr, data, mask);
   1230 }
   1231 
   1232 STATIC int
   1233 _phy_xgxs6_stop(int unit, soc_port_t port)
   1234 {
   1235     int                 stop, copper;
   1236     phy_ctrl_t  *pc;
   1237 
   1238     pc = INT_PHY_SW_STATE(unit, port);
   1239 
   1240     copper = (pc->stop &
   1241               PHY_STOP_COPPER) != 0;
   1242 
   1243     stop = ((pc->stop &
   1244              (PHY_STOP_PHY_DIS |
   1245               PHY_STOP_DRAIN)) != 0 ||
   1246             (copper &&
   1247              (pc->stop &
   1248               (PHY_STOP_MAC_DIS |
   1249                PHY_STOP_DUPLEX_CHG |
   1250                PHY_STOP_SPEED_CHG)) != 0));
   1251 
   1252     LOG_INFO(BSL_LS_SOC_PHY,
   1253              (BSL_META_U(unit,
   1254                          "phy_xgxs6_stop: u=%d p=%d copper=%d stop=%d flg=0x%x\n"),
   1255               unit, port, copper, stop,
   1256               pc->stop));
   1257 
   1258 
   1259     return _phy_xgxs6_enable_set(unit,port,stop?FALSE:TRUE);
   1260 }
   1261 
   1262 
   1263 /*
   1264  * Function:
   1265  *      _phy_xgxs6_notify_stop
   1266  * Purpose:
   1267  *      Add a reason to put serdesxgxs6 PHY in reset.
   1268  * Parameters:
   1269  *      unit - StrataSwitch unit #.
   1270  *      port - StrataSwitch port #.
   1271  *      flags - Reason to stop
   1272  * Returns:
   1273  *      SOC_E_XXX
   1274  */
   1275 
   1276 STATIC int
   1277 _phy_xgxs6_notify_stop(int unit, soc_port_t port, uint32 flags)
   1278 {
   1279     INT_PHY_SW_STATE(unit, port)->stop |= flags;
   1280     return _phy_xgxs6_stop(unit, port);
   1281 }
   1282 
   1283 /*
   1284  * Function:
   1285  *      _phy_xgxs6_notify_resume
   1286  * Purpose:
   1287  *      Remove a reason to put serdesxgxs6 PHY in reset.
   1288  * Parameters:
   1289  *      unit - StrataSwitch unit #.
   1290  *      port - StrataSwitch port #.
   1291  *      flags - Reason to stop
   1292  * Returns:
   1293  *      SOC_E_XXX
   1294  */
   1295 
   1296 STATIC int
   1297 _phy_xgxs6_notify_resume(int unit, soc_port_t port, uint32 flags)
   1298 {
   1299     INT_PHY_SW_STATE(unit, port)->stop &= ~flags;
   1300     return _phy_xgxs6_stop(unit, port);
   1301 }
   1302 
   1303 /*
   1304  * Function:
   1305  *      _phy_xgxs6_notify_speed
   1306  * Purpose:
   1307  *      Program speed if (and only if) serdesxgxs6 is an intermediate PHY.
   1308  * Parameters:
   1309  *      unit - StrataSwitch unit #.  
   1310  *      port - StrataSwitch port #.
   1311  *      speed - Speed to program.
   1312  * Returns:
   1313  *      SOC_E_XXX
   1314  * Notes:
   1315  *      If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to
   1316  *      talk directly to an external fiber module.
   1317  *
   1318  *      If PHY_FLAGS_FIBER is clear, the PHY is being used in
   1319  *      pass-through mode to talk to an external SGMII PHY.
   1320  *
   1321  *      When used in pass-through mode, autoneg must be turned off and
   1322  *      the speed/duplex forced to match that of the external PHY.
   1323  */
   1324 
   1325 STATIC int
   1326 _phy_xgxs6_notify_speed(int unit, soc_port_t port, uint32 speed)
   1327 {
   1328     int          fiber;
   1329 
   1330     fiber = PHY_FIBER_MODE(unit, port);
   1331 
   1332     LOG_INFO(BSL_LS_SOC_PHY,
   1333              (BSL_META_U(unit,
   1334                          "_phy_xgxs6_notify_speed: "
   1335                          "u=%d p=%d speed=%d fiber=%d\n"),
   1336               unit, port, speed, fiber));
   1337 
   1338     if (SAL_BOOT_SIMULATION) {
   1339         return SOC_E_NONE;
   1340     }
   1341 
   1342     /* Update speed */
   1343     SOC_IF_ERROR_RETURN
   1344         (phy_xgxs6_speed_set(unit, port, speed));
   1345 
   1346     /* Autonegotiation must be turned off to talk to external PHY */
   1347     if (!PHY_SGMII_AUTONEG_MODE(unit, port) && PHY_EXTERNAL_MODE(unit, port)) {
   1348         SOC_IF_ERROR_RETURN
   1349             (phy_xgxs6_an_set(unit, port, FALSE));
   1350     }
   1351     LOG_INFO(BSL_LS_SOC_PHY,
   1352              (BSL_META_U(unit,
   1353                          "_phy_xgxs6_notify_speed: "
   1354                          "u=%d p=%d speed=%d fiber=%d rv=%d\n"),
   1355               unit, port, speed, fiber,SOC_E_NONE));
   1356 
   1357     return SOC_E_NONE;
   1358 }
   1359 
   1360 STATIC int
   1361 phy_xgxs6_notify(int unit, soc_port_t port,
   1362                        soc_phy_event_t event, uint32 value)
   1363 {
   1364     int             rv;
   1365 
   1366     if (event >= phyEventCount) {
   1367         return SOC_E_PARAM;
   1368     }
   1369 
   1370     rv = SOC_E_NONE;
   1371     switch(event) {
   1372     case phyEventInterface:
   1373         break;
   1374     case phyEventDuplex:
   1375         break;
   1376     case phyEventSpeed:
   1377         rv = (_phy_xgxs6_notify_speed(unit, port, value));
   1378         break;
   1379     case phyEventStop:
   1380         rv = (_phy_xgxs6_notify_stop(unit, port, value));
   1381         break;
   1382     case phyEventResume:
   1383         rv = (_phy_xgxs6_notify_resume(unit, port, value));
   1384         break;
   1385     case phyEventAutoneg:
   1386         rv = (phy_xgxs6_an_set(unit, port, value));
   1387         break;
   1388     default:
   1389         rv = SOC_E_UNAVAIL;
   1390     }
   1391 
   1392     return rv;
   1393 }
   1394 
   1395 
   1396 /*
   1397  * Variable:
   1398  *      phy_xgxs6_drv
   1399  * Purpose:
   1400  *      Phy Driver for 10G (XAUI x 4) Serdes PHY. 
   1401  */
   1402 
   1403 phy_driver_t phy_xgxs6_hg = {
   1404     "XGXS6 Unicore PHY Driver",
   1405     phy_xgxs6_init,           /* Init */
   1406     phy_null_reset,           /* Reset (dummy) */
   1407     phy_xgxs6_link_get,       /* Link get   */
   1408     phy_xgxs6_enable_set,     /* Enable set */
   1409     phy_null_enable_get,      /* Enable get */
   1410     phy_null_set,             /* Duplex set */
   1411     phy_null_one_get,         /* Duplex get */
   1412     phy_xgxs6_speed_set,      /* Speed set  */
   1413     phy_xgxs6_speed_get,      /* Speed get  */
   1414     phy_null_set,             /* Master set */
   1415     phy_null_zero_get,        /* Master get */
   1416     phy_xgxs6_an_set,         /* ANA set */
   1417     phy_xgxs6_an_get,         /* ANA get */
   1418     phy_xgxs6_adv_local_set,  /* Local Advert set */
   1419     phy_xgxs6_adv_local_get,  /* Local Advert get */
   1420     phy_xgxs6_adv_remote_get, /* Remote Advert get */
   1421     phy_xgxs6_lb_set,         /* PHY loopback set */
   1422     phy_xgxs6_lb_get,         /* PHY loopback set */
   1423     phy_null_interface_set,   /* IO Interface set */
   1424     phy_null_interface_get,   /* IO Interface get */
   1425     phy_xgxs6_ability_get,    /* PHY abilities mask */
   1426     NULL,                     /* phy_linkup_evnt */
   1427     NULL,                     /* phy_linkdn_evnt */
   1428     phy_null_mdix_set,
   1429     phy_null_mdix_get,
   1430     phy_null_mdix_status_get,
   1431     NULL,                     /* Medium config set */
   1432     NULL,                     /* Medium config get */
   1433     phy_null_medium_get,
   1434     NULL,                     /* phy_cable_diag  */
   1435     NULL,                     /* phy_link_change */
   1436     phy_xgxs6_control_set,
   1437     phy_xgxs6_control_get,
   1438     phy_xgxs6_reg_read,
   1439     phy_xgxs6_reg_write, 
   1440     phy_xgxs6_reg_modify,
   1441     phy_xgxs6_notify                      /* phy_notify */ 
   1442 };
   1443 
   1444 #endif /*  INCLUDE_PHY_XGXS6 */
   1445 
   1446 int _phy_xgxs6_not_empty;