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

xgxs16g.c (105290B)


      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:        xgxs16g.c
      8  * Purpose:     Support Broadcom 1000/2500/10000/12000/13000/16000 SerDes(XGXS-16G)
      9  *              Support BCM 40nm Xenia core XGXS_13G_040_FC 
     10  */
     11 
     12 #include <sal/types.h>
     13 #include <shared/bsl.h>
     14 #include <sal/types.h>
     15 #include <sal/core/spl.h>
     16 
     17 #include <soc/drv.h>
     18 #include <soc/debug.h>
     19 #include <soc/error.h>
     20 #include <soc/phyreg.h>
     21 #include <soc/port_ability.h>
     22 
     23 #include <soc/phy.h>
     24 #include <soc/phy/phyctrl.h>
     25 #include <soc/phy/drv.h>
     26 
     27 #include "phydefs.h"      /* Must include before other phy related includes */ 
     28 
     29 #if defined(INCLUDE_XGXS_16G)
     30 #include "phyconfig.h"     /* Must include before other phy related includes */
     31 #include "phyident.h"
     32 #include "phyreg.h"
     33 #include "phynull.h"
     34 #include "xgxs.h"
     35 #include "serdesid.h"
     36 #include "xgxs16g.h"
     37 
     38 #define TX_DRIVER_DFT_LN_CTRL  0x4
     39 #define PHY_XGXS16G_LANEPRBS_LANE_SHIFT   4
     40 
     41 /* Notify event forward declaration */
     42 STATIC int phy_xgxs16g_interface_get(int unit, soc_port_t port,
     43                                        soc_port_if_t *pif);
     44 STATIC int phy_xgxs16g_master_get(int unit, soc_port_t port, int *master);
     45 STATIC int _phy_xgxs16g_notify_duplex(int unit, soc_port_t port, uint32 duplex);
     46 STATIC int _phy_xgxs16g_notify_speed(int unit, soc_port_t port, uint32 speed);
     47 STATIC int _phy_xgxs16g_notify_stop(int unit, soc_port_t port, uint32 flags);
     48 STATIC int _phy_xgxs16g_notify_resume(int unit, soc_port_t port, uint32 flags);
     49 STATIC int _phy_xgxs16g_notify_interface(int unit, soc_port_t port, uint32 intf);
     50 STATIC int _phy_xgxs16g_notify_mac_loopback(int unit, soc_port_t port, uint32 enable);
     51 #define XGXS16G_PLL_WAIT  250000
     52 STATIC int phy_xgxs16g_an_set(int unit, soc_port_t port, int an);
     53 STATIC int phy_xgxs16g_an_get(int unit, soc_port_t port,
     54                               int *an, int *an_done);
     55 STATIC int phy_xgxs16g_speed_get(int unit, soc_port_t port, int *speed);
     56 STATIC int phy_xgxs16g_ability_advert_set(int unit, soc_port_t port, 
     57                                          soc_port_ability_t *ability);
     58 STATIC int phy_xgxs16g_ability_advert_get(int unit, soc_port_t port,
     59                                          soc_port_ability_t *ability);
     60 STATIC int phy_xgxs16g_ability_local_get(int unit, soc_port_t port,
     61                                    soc_port_ability_t *ability); 
     62 STATIC int phy_xgxs16g_speed_set(int unit, soc_port_t port, int speed);
     63 STATIC int _phy_xgxs16g_control_vco_disturbed_set(int unit, soc_port_t port);
     64 STATIC int _phy_xgxs16g_control_vco_disturbed_get(int unit, soc_port_t port,
     65                                                   uint32 *value);
     66 
     67 STATIC int
     68 _phy_xgxs16g_pll_lock_wait(int unit, soc_port_t port)
     69 {
     70     uint16           data16;
     71     phy_ctrl_t      *pc;
     72     soc_timeout_t    to;
     73     int              rv;
     74 
     75     pc = INT_PHY_SW_STATE(unit, port);
     76     _phy_xgxs16g_control_vco_disturbed_set(unit, port);
     77     soc_timeout_init(&to, XGXS16G_PLL_WAIT, 0);
     78     do {
     79         rv = READ_XGXS16G_XGXSBLK0_XGXSSTATUSr(unit, pc, &data16);
     80         if ((data16 & XGXSBLK0_XGXSSTATUS_TXPLL_LOCK_MASK) ||
     81             SOC_FAILURE(rv)) {
     82             break;
     83         }
     84     } while (!soc_timeout_check(&to));
     85     if ((data16 & XGXSBLK0_XGXSSTATUS_TXPLL_LOCK_MASK) == 0) {
     86         LOG_WARN(BSL_LS_SOC_PHY,
     87                  (BSL_META_U(unit,
     88                              "XGXS_16G : TXPLL did not lock: u=%d p=%d\n"),
     89                   unit, port));
     90         return (SOC_E_TIMEOUT);
     91     }
     92     return (SOC_E_NONE);
     93 }
     94 
     95 STATIC int
     96 _phy_xgxs16g_pin_out_set(int unit, soc_port_t port)
     97 {
     98     uint16      data16;
     99     uint16      mask16;
    100     phy_ctrl_t *pc;
    101     uint32      phy_xaui_tx_polarity_flip;
    102     uint32      phy_xaui_rx_polarity_flip=0;
    103 
    104     pc = INT_PHY_SW_STATE(unit, port);
    105 
    106     /* 
    107      * Transform CX4 pin out on the board to HG pinout
    108      */
    109     if (soc_property_port_get(unit, port, spn_CX4_TO_HIGIG, FALSE)) {
    110         if (FEATURE_NEW_LANESWAP(pc)) {
    111             SOC_IF_ERROR_RETURN     /* Enable TX Lane swap */
    112                 (WRITE_XGXS16G_XGXSBLK8_TXLNSWAP1r(unit, pc, 0x80e4));
    113         } else {
    114             /* Swap TX lanes */
    115             data16 = XGXSBLK2_TXLNSWAP_TX_LNSWAP_EN_MASK; 
    116             mask16 = XGXSBLK2_TXLNSWAP_TX_LNSWAP_EN_MASK;
    117             SOC_IF_ERROR_RETURN
    118                 (MODIFY_XGXS16G_XGXSBLK2_TXLNSWAPr(unit, pc, data16, mask16));
    119         }
    120 
    121         /* Flip TX polarity */
    122         data16 = TX0_TX_ACONTROL0_TXPOL_FLIP_MASK;
    123         mask16 = TX0_TX_ACONTROL0_TXPOL_FLIP_MASK;
    124         SOC_IF_ERROR_RETURN
    125             (MODIFY_XGXS16G_TX_ALL_TX_ACONTROL0r(unit, pc, data16, mask16));
    126     } else {
    127         /* If CX4 to HG conversion is enabled, do not allow individual lane
    128          * swapping.
    129          */
    130         int i;
    131         uint16 lane_map;
    132         uint16 lane, hw_map, chk_map;
    133 
    134         /* Update RX lane map */
    135         lane_map = soc_property_port_get(unit, port,
    136                                         spn_XGXS_RX_LANE_MAP, 0x0123) & 0xffff;
    137         if (lane_map != 0x0123) {
    138             hw_map  = 0;
    139             chk_map = 0;
    140             for (i = 0; i < 4; i++) {
    141                 lane     = (lane_map >> (i * 4)) & 0xf;
    142                 hw_map  |= lane << (i * 2);
    143                 chk_map |= 1 << lane;
    144             }
    145             if (chk_map == 0xf) {
    146                 if (FEATURE_NEW_LANESWAP(pc)) {
    147                     /* swap the hw_map */
    148                     for (hw_map=0, i = 3; i >= 0; i--) {
    149                         lane  = (lane_map >> (i * 4)) & 0xf;
    150                         hw_map  |= lane << ((3 - i) * 2);
    151                     }
    152                     SOC_IF_ERROR_RETURN     /* Enable RX Lane swap */
    153                        (MODIFY_XGXS16G_XGXSBLK8_RXLNSWAP1r(unit, pc, 
    154                            hw_map,
    155                            XGXSBLK2_RXLNSWAP_RX_LNSWAP_EN_MASK |
    156                            XGXSBLK8_RXLNSWAP1_RX0_LNSWAP_SEL_MASK |
    157                            XGXSBLK8_RXLNSWAP1_RX1_LNSWAP_SEL_MASK |
    158                            XGXSBLK8_RXLNSWAP1_RX2_LNSWAP_SEL_MASK |
    159                            XGXSBLK8_RXLNSWAP1_RX3_LNSWAP_SEL_MASK));
    160 
    161                 } else {
    162                     hw_map |= XGXSBLK2_RXLNSWAP_RX_LNSWAP_EN_MASK |
    163                               XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE_EN_MASK;
    164                     mask16  = XGXSBLK2_RXLNSWAP_RX_LNSWAP_EN_MASK |
    165                               XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE_EN_MASK |
    166                               XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE0_MASK |
    167                               XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE1_MASK |
    168                               XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE2_MASK |
    169                               XGXSBLK2_RXLNSWAP_RX_LNSWAP_FORCE3_MASK;
    170                     SOC_IF_ERROR_RETURN
    171                         (MODIFY_XGXS16G_XGXSBLK2_RXLNSWAPr(unit, pc, 
    172                                                        hw_map, mask16));
    173                 }
    174             } else {
    175                 LOG_WARN(BSL_LS_SOC_PHY,
    176                          (BSL_META_U(unit,
    177                                      "unit %d port %s: Invalid RX lane map 0x%04x.\n"),
    178                           unit, SOC_PORT_NAME(unit, port), lane_map));
    179             }
    180         }
    181 
    182         /* Update TX lane map */
    183         lane_map = soc_property_port_get(unit, port,
    184                                         spn_XGXS_TX_LANE_MAP, 0x0123) & 0xffff;
    185 
    186         if (lane_map != 0x0123) {
    187             hw_map  = 0;
    188             chk_map = 0;
    189             for (i = 0; i < 4; i++) {
    190               lane     = (lane_map >> (i * 4)) & 0xf;
    191                 hw_map  |= lane << (i * 2);
    192                 chk_map |= 1 << lane;
    193             }
    194             if (chk_map == 0xf) {
    195                 if (FEATURE_NEW_LANESWAP(pc)) {
    196                     /* swap the hw_map */
    197                     for (hw_map=0, i = 3; i >= 0; i--) {
    198                         lane  = (lane_map >> (i * 4)) & 0xf;
    199                         hw_map  |= lane << ((3 - i) * 2);
    200                     }
    201                     SOC_IF_ERROR_RETURN     /* Enable TX Lane swap */
    202                        (MODIFY_XGXS16G_XGXSBLK8_TXLNSWAP1r(unit, pc, 
    203                             hw_map,
    204                             XGXSBLK8_TXLNSWAP1_TX3_LNSWAP_SEL_MASK |
    205                             XGXSBLK8_TXLNSWAP1_TX2_LNSWAP_SEL_MASK |
    206                             XGXSBLK8_TXLNSWAP1_TX1_LNSWAP_SEL_MASK |
    207                             XGXSBLK8_TXLNSWAP1_TX0_LNSWAP_SEL_MASK));
    208                 } else {
    209                     hw_map |= XGXSBLK2_TXLNSWAP_TX_LNSWAP_EN_MASK;
    210                     mask16  = XGXSBLK2_TXLNSWAP_TX_LNSWAP_EN_MASK |
    211                               XGXSBLK2_TXLNSWAP_TX_LNSWAP_FORCE0_MASK |
    212                               XGXSBLK2_TXLNSWAP_TX_LNSWAP_FORCE1_MASK |
    213                               XGXSBLK2_TXLNSWAP_TX_LNSWAP_FORCE2_MASK |
    214                               XGXSBLK2_TXLNSWAP_TX_LNSWAP_FORCE3_MASK;
    215                     SOC_IF_ERROR_RETURN
    216                         (MODIFY_XGXS16G_XGXSBLK2_TXLNSWAPr(unit, pc,
    217                                                        hw_map, mask16));
    218                 }
    219             } else {
    220                 LOG_WARN(BSL_LS_SOC_PHY,
    221                          (BSL_META_U(unit,
    222                                      "unit %d port %s: Invalid TX lane map 0x%04x.\n"),
    223                           unit, SOC_PORT_NAME(unit, port), lane_map));
    224             }
    225         }
    226         phy_xaui_tx_polarity_flip = soc_property_port_get(unit, port,
    227                                               spn_PHY_XAUI_TX_POLARITY_FLIP, 0);
    228         if (phy_xaui_tx_polarity_flip) {
    229             /* Flip TX polarity */
    230             data16 = TX0_TX_ACONTROL0_TXPOL_FLIP_MASK;
    231             mask16 = TX0_TX_ACONTROL0_TXPOL_FLIP_MASK;
    232             LOG_WARN(BSL_LS_SOC_PHY,
    233                      (BSL_META_U(unit,
    234                                  "unit %d port %s: TX Polarity swap 0x%04x.\n"),
    235                       unit, SOC_PORT_NAME(unit, port), data16));
    236             if (phy_xaui_tx_polarity_flip == 1) {
    237                 SOC_IF_ERROR_RETURN
    238                 (MODIFY_XGXS16G_TX_ALL_TX_ACONTROL0r(unit, pc, data16, mask16));
    239             }
    240             if ((phy_xaui_tx_polarity_flip & 0x000F) == 0x000F) {
    241                 SOC_IF_ERROR_RETURN
    242                   (MODIFY_XGXS16G_TX0_TX_ACONTROL0r(unit, pc, data16, mask16));
    243             }
    244             if ((phy_xaui_tx_polarity_flip & 0x00F0) == 0x00F0) {
    245                 SOC_IF_ERROR_RETURN
    246                   (MODIFY_XGXS16G_TX1_TX_ACONTROL0r(unit, pc, data16, mask16));
    247             }
    248             if ((phy_xaui_tx_polarity_flip & 0x0F00) == 0x0F00) {
    249                 SOC_IF_ERROR_RETURN
    250                   (MODIFY_XGXS16G_TX2_TX_ACONTROL0r(unit, pc, data16, mask16));
    251             }
    252             if ((phy_xaui_tx_polarity_flip & 0xF000) == 0xF000) {
    253                 SOC_IF_ERROR_RETURN
    254                   (MODIFY_XGXS16G_TX3_TX_ACONTROL0r(unit, pc, data16, mask16));
    255             }
    256         }
    257         phy_xaui_rx_polarity_flip = soc_property_port_get(unit, port,
    258                                               spn_PHY_XAUI_RX_POLARITY_FLIP, 0);
    259         if (phy_xaui_rx_polarity_flip) {
    260             /* Flip RX polarity */
    261             data16 = 0x06; /* RX_POLARITY_FORCE_R | RX_POLARIRT_R */
    262             mask16 = 0x06;
    263             LOG_WARN(BSL_LS_SOC_PHY,
    264                      (BSL_META_U(unit,
    265                                  "unit %d port %s: RX Polarity swap 0x%04x.\n"),
    266                       unit, SOC_PORT_NAME(unit, port), data16));
    267             if (phy_xaui_rx_polarity_flip == 1) {
    268                 SOC_IF_ERROR_RETURN
    269                 (MODIFY_XGXS16G_RX_CONTROL_PCIEr(unit, pc, data16, mask16));
    270             }
    271             if ((phy_xaui_rx_polarity_flip & 0x000F) == 0x000F) {
    272                 SOC_IF_ERROR_RETURN
    273                   (MODIFY_XGXS16G_RX0_ANA_RX_CONTROL_PCIEr(unit, pc, data16, mask16));
    274             }
    275             if ((phy_xaui_rx_polarity_flip & 0x00F0) == 0x00F0) {
    276                 SOC_IF_ERROR_RETURN
    277                   (MODIFY_XGXS16G_RX1_ANA_RX_CONTROL_PCIEr(unit, pc, data16, mask16));
    278             }
    279             if ((phy_xaui_rx_polarity_flip & 0x0F00) == 0x0F00) {
    280                 SOC_IF_ERROR_RETURN
    281                   (MODIFY_XGXS16G_RX2_ANA_RX_CONTROL_PCIEr(unit, pc, data16, mask16));
    282             }
    283             if ((phy_xaui_rx_polarity_flip & 0xF000) == 0xF000) {
    284                 SOC_IF_ERROR_RETURN
    285                   (MODIFY_XGXS16G_RX3_ANA_RX_CONTROL_PCIEr(unit, pc, data16, mask16));
    286             }
    287         }
    288     }
    289     return (SOC_E_NONE);
    290 }
    291 
    292 /*
    293  * Function:
    294  *      phy_xgxs16g_init
    295  * Purpose:     
    296  *      Initialize xgxs6 phys
    297  * Parameters:
    298  *      unit - StrataSwitch unit #.
    299  *      port - StrataSwitch port #. 
    300  * Returns:     
    301  *      SOC_E_NONE
    302  */
    303 
    304 STATIC int
    305 phy_xgxs16g_init(int unit, soc_port_t port)
    306 {
    307     uint16              data16;
    308     uint16              mask16;
    309     int                 preemph, idriver, pdriver;
    310     soc_port_ability_t  ability;
    311     phy_ctrl_t         *pc;
    312     int                 serdes_fiber_pref_def;
    313     XGXS16G_DEV_DESC *pDesc;
    314     soc_phy_info_t *pi;
    315     int len;
    316     int serdes_id0;
    317 
    318     pc = INT_PHY_SW_STATE(unit, port);
    319     pDesc = (XGXS16G_DEV_DESC *)(pc + 1);
    320 
    321     SOC_IF_ERROR_RETURN
    322         (READ_XGXS16G_SERDESID_SERDESID2r(unit, pc, &pDesc->serdes_id0));
    323     serdes_id0 = pDesc->serdes_id0;
    324     SOC_IF_ERROR_RETURN
    325         (READ_XGXS16G_SERDESID_SERDESID2r(unit, pc, &pDesc->serdes_id2));
    326 
    327     /* compose device name/instance/lane information for display 
    328      * XGXS_16G device uses existing method
    329      */
    330     if (XGXS16G_13G_ID(pc)) {
    331         /*
    332          * COVERITY
    333          *
    334          * Checked that buffer overflow will not happen for destination string.
    335          */
    336         /* coverity[secure-coding] */
    337 
    338         sal_strcpy(pDesc->name,"XGXS13G-");
    339         len = sal_strlen(pDesc->name);
    340         /* add rev letter */
    341         pDesc->name[len++] = 'A' + ((serdes_id0 >>
    342                           SERDESID_SERDESID0_REV_LETTER_SHIFT) & 0x3);
    343         /* add rev number */
    344         pDesc->name[len++] = '0' + ((serdes_id0 >>
    345                           SERDESID_SERDESID0_REV_NUMBER_SHIFT) & 0x7);
    346         pDesc->name[len++] = '/';
    347         pDesc->name[len++] = (pc->chip_num/10)%10 + '0';
    348         pDesc->name[len++] = pc->chip_num%10 + '0';
    349         pDesc->name[len++] = '/';
    350         pDesc->name[len++] = '4';
    351         pDesc->name[len] = 0;  /* string terminator */
    352 
    353         if (len > XGXS16G_LANE_NAME_LEN) {
    354             LOG_ERROR(BSL_LS_SOC_PHY,
    355                       (BSL_META_U(unit,
    356                                   "XGXS13G info string length %d exceeds max length 0x%x: u=%d p=%d\n"),
    357                        len,XGXS16G_LANE_NAME_LEN,unit, port));
    358             return SOC_E_MEMORY;
    359         }
    360 
    361         pi = &SOC_PHY_INFO(unit, port);
    362         if (!PHY_EXTERNAL_MODE(unit, port)) {
    363             pi->phy_name = pDesc->name;
    364         }
    365 
    366     }
    367     
    368     /* Reset the core */
    369 
    370     /* Stop PLL Sequencer and configure the core into correct mode */
    371     data16 = (XGXSBLK0_XGXSCONTROL_MODE_10G_ComboCoreMode <<
    372                 XGXSBLK0_XGXSCONTROL_MODE_10G_SHIFT) |
    373              XGXSBLK0_XGXSCONTROL_HSTL_MASK |
    374              XGXSBLK0_XGXSCONTROL_CDET_EN_MASK |
    375              XGXSBLK0_XGXSCONTROL_EDEN_MASK |
    376              XGXSBLK0_XGXSCONTROL_AFRST_EN_MASK |
    377              XGXSBLK0_XGXSCONTROL_TXCKO_DIV_MASK;
    378     SOC_IF_ERROR_RETURN
    379         (WRITE_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, data16)); 
    380 
    381     /* disable in-band MDIO. PHY-443 */
    382     SOC_IF_ERROR_RETURN
    383         (XGXS16G_REG_MODIFY(unit, pc, 0x00, 0x8111, 1 << 3, 1 << 3));
    384 
    385     if (soc_property_port_get(unit, port,
    386                           spn_PHY_AN_C73, FALSE)) {
    387          PHY_FLAGS_SET(unit, port, PHY_FLAGS_C73);
    388     }
    389 
    390     /* disable CL73 BAM */
    391     SOC_IF_ERROR_RETURN
    392         (MODIFY_XGXS16G_AN_CL73_REG(unit,pc,0x8372,
    393                0,
    394                CL73_USERB0_CL73_BAMCTRL1_CL73_BAMEN_MASK));
    395 
    396     if (!PHY_CLAUSE73_MODE(unit, port)) {
    397         /* disable CL73 AN device*/
    398         SOC_IF_ERROR_RETURN
    399             (WRITE_XGXS16G_AN_CL73_REG(unit,pc,MII_CTRL_REG,0));
    400     }
    401 
    402     /* Disable IEEE block select auto-detect. 
    403      * The driver will select desired block as necessary.
    404      * By default, the driver keeps the mapping for XAUI block in
    405      * IEEE address space.
    406      */
    407     SOC_IF_ERROR_RETURN
    408         (MODIFY_XGXS16G_XGXSBLK0_MISCCONTROL1r(unit, pc, 
    409                            XGXSBLK0_MISCCONTROL1_IEEE_BLKSEL_VAL_MASK,
    410                            XGXSBLK0_MISCCONTROL1_IEEE_BLKSEL_AUTODET_MASK |
    411                            XGXSBLK0_MISCCONTROL1_IEEE_BLKSEL_VAL_MASK));
    412 
    413     /*
    414      * Configure signal auto-detection between SGMII and fiber.
    415      */
    416     data16 = SERDESDIGITAL_CONTROL1000X1_CRC_CHECKER_DISABLE_MASK;
    417     mask16 = SERDESDIGITAL_CONTROL1000X1_AUTODET_EN_MASK |
    418              SERDESDIGITAL_CONTROL1000X1_CRC_CHECKER_DISABLE_MASK |
    419              SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK;
    420     if (soc_property_port_get(unit, port, spn_SERDES_AUTOMEDIUM, TRUE)) {
    421         data16 |= SERDESDIGITAL_CONTROL1000X1_AUTODET_EN_MASK;
    422     }
    423     serdes_fiber_pref_def = TRUE;
    424     if (PHY_EXTERNAL_MODE(unit, port) && IS_GE_PORT(unit, port)) {
    425         serdes_fiber_pref_def = FALSE;
    426     }
    427     if (soc_property_port_get(unit, port, spn_SERDES_FIBER_PREF,
    428                                 serdes_fiber_pref_def)) {
    429         data16 |= SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK;
    430     }
    431     if (soc_property_port_get(unit, port, 
    432                               spn_SERDES_SGMII_MASTER, FALSE)) {
    433         data16 |= SERDESDIGITAL_CONTROL1000X1_SGMII_MASTER_MODE_MASK;
    434         mask16 |= SERDESDIGITAL_CONTROL1000X1_SGMII_MASTER_MODE_MASK;
    435     }
    436     SOC_IF_ERROR_RETURN
    437         (MODIFY_XGXS16G_SERDESDIGITAL_CONTROL1000X1r(unit, pc, data16, mask16));
    438     
    439     /* Disable SerDes parallel detect */
    440     SOC_IF_ERROR_RETURN
    441         (WRITE_XGXS16G_SERDESDIGITAL_CONTROL1000X2r(unit, pc, 0));
    442 
    443     /* Initialize combo SerDes to reasonable default settings */
    444     SOC_IF_ERROR_RETURN
    445         (WRITE_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, 
    446                                MII_CTRL_AE  | MII_CTRL_FD | MII_CTRL_SS_1000));
    447 
    448     /* Disable 10G parallel detect */
    449     SOC_IF_ERROR_RETURN
    450         (WRITE_XGXS16G_AN73_PDET_PARDET10GCONTROLr(unit, pc, 0));
    451 
    452     /* Enable BAM mode */
    453     SOC_IF_ERROR_RETURN
    454         (WRITE_XGXS16G_BAM_NEXTPAGE_MP5_NEXTPAGECTRLr(unit, pc, 1));
    455 
    456     /* Initialize XAUI to reasonable default settings */
    457 	if (XGXS16G_13G_ID(pc)) {
    458 		/* 40nm */
    459 		preemph = soc_property_port_get(unit, port, spn_XGXS_PREEMPHASIS, 0);
    460 		idriver = soc_property_port_get(unit, port, spn_XGXS_DRIVER_CURRENT, 4);
    461 		data16  = ((preemph & 0xf) << TX_ALL_040_TX_DRIVER_PREEMPHASIS_POST_SHIFT) |
    462 				  ((idriver & 0x7) << TX_ALL_040_TX_DRIVER_IDRIVER_SHIFT);
    463 		mask16  = TX_ALL_040_TX_DRIVER_PREEMPHASIS_POST_MASK |
    464 				  TX_ALL_040_TX_DRIVER_IDRIVER_MASK;
    465 		SOC_IF_ERROR_RETURN
    466 			(MODIFY_XGXS13G_040_TX_ALL_ACONTROL1r(unit, pc, data16, mask16));		
    467 	} else {
    468 		preemph = soc_property_port_get(unit, port, spn_XGXS_PREEMPHASIS, 0);
    469 		idriver = soc_property_port_get(unit, port, spn_XGXS_DRIVER_CURRENT, 9);
    470 		pdriver = soc_property_port_get(unit, port, spn_XGXS_PRE_DRIVER_CURRENT, 9);
    471 		data16  = ((preemph & 0xf) << TX_ALL_TX_DRIVER_PREEMPHASIS_SHIFT) |
    472 				  ((idriver & 0xf) << TX_ALL_TX_DRIVER_IDRIVER_SHIFT) |
    473 				  ((pdriver & 0xf) << TX_ALL_TX_DRIVER_IPREDRIVER_SHIFT);
    474 		mask16  = TX_ALL_TX_DRIVER_PREEMPHASIS_MASK |
    475 				  TX_ALL_TX_DRIVER_IDRIVER_MASK |
    476 				  TX_ALL_TX_DRIVER_IPREDRIVER_MASK;
    477 		SOC_IF_ERROR_RETURN
    478 			(MODIFY_XGXS16G_TX_ALL_TX_DRIVERr(unit, pc, data16, mask16));
    479 	}
    480 
    481     /* Advertise all property by default */
    482     SOC_IF_ERROR_RETURN
    483         (phy_xgxs16g_ability_local_get(unit, port, &ability));
    484 
    485     SOC_IF_ERROR_RETURN
    486         (phy_xgxs16g_ability_advert_set(unit, port, &ability));
    487 
    488     /* Adjust parallel detect link timer to 60ms */
    489     SOC_IF_ERROR_RETURN
    490         (WRITE_XGXS16G_AN73_PDET_PARDET10GLINKr(unit, pc, 0x16E2));
    491 
    492     /* Enable 10G parallel detect by default */
    493     data16 = 0;
    494     mask16 = AN73_PDET_PARDET10GCONTROL_PARDET10G_EN_MASK;
    495     if (soc_property_port_get(unit, port, spn_XGXS_PDETECT_10G, 1)) {
    496         data16 = AN73_PDET_PARDET10GCONTROL_PARDET10G_EN_MASK;
    497     }
    498     SOC_IF_ERROR_RETURN
    499         (MODIFY_XGXS16G_AN73_PDET_PARDET10GCONTROLr(unit, pc, data16, mask16));
    500  
    501     /* Allow config settings to adjust pin out for XAUI lane */
    502     SOC_IF_ERROR_RETURN
    503         (_phy_xgxs16g_pin_out_set(unit, port));
    504 
    505     /* set elasticity fifo size to 13.5k to support 12k jumbo pkt size*/
    506     SOC_IF_ERROR_RETURN
    507         (MODIFY_XGXS16G_SERDESDIGITAL_CONTROL1000X3r(unit,pc,
    508                    (1 << 2),
    509                    SERDESDIGITAL_CONTROL1000X3_FIFO_ELASICITY_TX_RX_MASK));
    510 
    511     /* enable autoneg or force a speed depending on the port type */
    512 
    513     if (PHY_EXTERNAL_MODE(unit, port) &&
    514         (IS_XE_PORT(unit, port) || IS_HG_PORT(unit, port))) {
    515         int force_speed;
    516 
    517         force_speed = SERDESDIGITAL_MISC1_FORCE_SPEED_SEL_MASK;
    518         if (soc_property_port_get(unit, port, spn_10G_IS_CX4, TRUE)) {
    519             force_speed |= 4; /* 10G CX4 */
    520         } else {
    521             force_speed |= 3; /* 10G HiG */
    522         }
    523 
    524         /* disable autoneg */
    525         SOC_IF_ERROR_RETURN
    526             (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc,
    527                                              0,
    528                                              MII_CTRL_AE));
    529         if (PHY_CLAUSE73_MODE(unit, port)) {
    530             SOC_IF_ERROR_RETURN
    531                 (MODIFY_XGXS16G_AN_CL73_REG(unit, pc,MII_CTRL_REG,
    532                                               0,
    533                                               MII_CTRL_AE));
    534         }
    535 
    536         /* force speed  to 10G */
    537         SOC_IF_ERROR_RETURN
    538             (MODIFY_XGXS16G_SERDESDIGITAL_MISC1r(unit, pc, force_speed,
    539                                 SERDESDIGITAL_MISC1_FORCE_SPEED_SEL_MASK |
    540                                 SERDESDIGITAL_MISC1_FORCE_SPEED_MASK));
    541     } else { /* autoneg */
    542         SOC_IF_ERROR_RETURN
    543             (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc,
    544                                              MII_CTRL_AE | MII_CTRL_RAN,
    545                                              MII_CTRL_AE | MII_CTRL_RAN));
    546         if (PHY_CLAUSE73_MODE(unit, port)) {
    547             SOC_IF_ERROR_RETURN
    548                 (MODIFY_XGXS16G_AN_CL73_REG(unit, pc,MII_CTRL_REG,
    549                                               MII_CTRL_AE | MII_CTRL_RAN,
    550                                               MII_CTRL_AE | MII_CTRL_RAN));
    551         }
    552     }
    553 
    554     if (XGXS16G_13G_ID(pc)) {
    555         /* Enabble LPI passthru' for native mode EEE */
    556         SOC_IF_ERROR_RETURN
    557              (MODIFY_XGXS16G_REMOTEPHY_MISC5r(unit, pc, 0xc000, 0xc000));
    558         SOC_IF_ERROR_RETURN
    559              (MODIFY_XGXS16G_XGXSBLK7_EEECONTROLr(unit, pc, 0x0007, 0x0007));
    560     }
    561 
    562     /* Start PLL Sequencer and wait for PLL to lock */
    563     SOC_IF_ERROR_RETURN
    564         (MODIFY_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc,
    565                                  XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK,
    566                                  XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
    567     (void) _phy_xgxs16g_pll_lock_wait(unit, port);
    568    
    569     /* PRBS Polynomial for all lanes: 0x8019=0x0000 */
    570     SOC_IF_ERROR_RETURN
    571         (WRITE_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, 0)); 
    572 
    573     return (SOC_E_NONE);
    574 }
    575 
    576 /*
    577  * Function:
    578  *      phy_xgxs16g_link_get
    579  * Purpose:
    580  *      Get layer2 connection status.
    581  * Parameters:
    582  *      unit - StrataSwitch unit #.
    583  *      port - StrataSwitch port #. 
    584  *      link - address of memory to store link up/down state.
    585  * Returns:     
    586  *      SOC_E_NONE
    587  */
    588 
    589 STATIC int
    590 phy_xgxs16g_link_get(int unit, soc_port_t port, int *link)
    591 {
    592     phy_ctrl_t *pc;
    593     uint16  xgxs_stat1;
    594     uint16  xgxs_stat3;
    595     int     autoneg;
    596     int     an_done;
    597 
    598     if (PHY_DISABLED_MODE(unit, port)) {
    599         *link = FALSE;
    600         return SOC_E_NONE;
    601     }
    602 
    603     pc = INT_PHY_SW_STATE(unit, port);
    604 
    605     SOC_IF_ERROR_RETURN
    606         (READ_XGXS16G_GP_STATUS_XGXSSTATUS3r(unit, pc, &xgxs_stat3));
    607 
    608     *link =  (xgxs_stat3 & GP_STATUS_XGXSSTATUS3_LINK_LATCHDOWN_MASK) ? 1 : 0;
    609 
    610     /*
    611      * Following logic is to ensure that there is no false link up status
    612      * in an mode. Link status is set as UP only if an_done is complete.
    613      */
    614     SOC_IF_ERROR_RETURN
    615         (phy_xgxs16g_an_get(unit, port, &autoneg, NULL));
    616 
    617     if (autoneg) {
    618         /* If autoneg is enabled, check for autoneg done. */
    619         SOC_IF_ERROR_RETURN
    620             (READ_XGXS16G_GP_STATUS_XGXSSTATUS1r(unit, pc, &xgxs_stat1));
    621 
    622         an_done = ((xgxs_stat1 & GP_STATUS_XGXSSTATUS1_AUTONEG_COMPLETE_MASK) 
    623                   != 0);
    624         if (!an_done) {
    625             uint16 an_status;
    626 
    627             /* check Clause73 autoneg */
    628             if (PHY_CLAUSE73_MODE(unit, port)) {
    629                 SOC_IF_ERROR_RETURN
    630                     (READ_XGXS16G_GP_STATUS_TOPANSTATUS1r(unit, pc, &an_status));
    631 
    632                 if (an_status & 
    633                     GP_STATUS_TOPANSTATUS1_CL73_AUTONEG_COMPLETE_MASK) {
    634                     an_done = TRUE; 
    635                 }
    636             }
    637         }
    638 
    639         *link = (*link) && (an_done);
    640     }
    641 
    642     return (SOC_E_NONE);
    643 }
    644 
    645 /*
    646  * Function:
    647  *      phy_xgxs16g_enable_set
    648  * Purpose:
    649  *      Enable/Disable phy 
    650  * Parameters:
    651  *      unit - StrataSwitch unit #.
    652  *      port - StrataSwitch port #. 
    653  *      enable - on/off state to set
    654  * Returns:     
    655  *      SOC_E_NONE
    656  */
    657 
    658 STATIC int
    659 phy_xgxs16g_enable_set(int unit, soc_port_t port, int enable)
    660 {
    661     uint16      pmd_tx_disable;
    662     phy_ctrl_t *pc;
    663    
    664     pc = INT_PHY_SW_STATE(unit, port);
    665 
    666     if (enable) {
    667         PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE);
    668         pmd_tx_disable = 0;
    669     } else {
    670         pmd_tx_disable = XGXSBLK0_MISCCONTROL1_GLOBAL_PMD_TX_DISABLE_MASK;
    671         PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE);
    672     }
    673 
    674     /* disable the Tx */
    675     SOC_IF_ERROR_RETURN
    676         (MODIFY_XGXS16G_XGXSBLK0_MISCCONTROL1r(unit, pc, pmd_tx_disable,
    677                XGXSBLK0_MISCCONTROL1_GLOBAL_PMD_TX_DISABLE_MASK));
    678 
    679     /* disable the Rx */
    680     SOC_IF_ERROR_RETURN
    681         (MODIFY_XGXS16G_RX_ALL_RX_CONTROLr(unit, pc, 
    682                enable? 0:DSC_2_0_DSC_CTRL0_RXSEQSTART_MASK,
    683                DSC_2_0_DSC_CTRL0_RXSEQSTART_MASK));
    684 
    685     return (SOC_E_NONE);
    686 }
    687 
    688 /*
    689  * Function:
    690  *      phy_xgxs16g_speed_set
    691  * Purpose:
    692  *      Set PHY speed
    693  * Parameters:
    694  *      unit - StrataSwitch unit #.
    695  *      port - StrataSwitch port #. 
    696  *      speed - link speed in Mbps
    697  * Returns:     
    698  *      SOC_E_NONE
    699  */
    700 
    701 STATIC int
    702 phy_xgxs16g_speed_set(int unit, soc_port_t port, int speed)
    703 {
    704     phy_ctrl_t *pc;
    705     uint16      force_speed;
    706     uint16      data16;
    707     uint16       speed_mii;
    708     uint16      sgmii_status;
    709 
    710     speed_mii = 0;
    711 
    712     /* Check for valid speed and convert valid speed to HW values */
    713     force_speed = SERDESDIGITAL_MISC1_FORCE_SPEED_SEL_MASK;
    714     switch (speed) {
    715     case 10:
    716         speed_mii = MII_CTRL_SS_10;
    717         break;
    718     case 100:
    719         speed_mii = MII_CTRL_SS_100;
    720         break;
    721     case 1000:
    722         speed_mii = MII_CTRL_SS_1000;
    723         force_speed = 0;
    724         break;
    725     case 2500:   
    726         speed_mii = MII_CTRL_SS_MSB | MII_CTRL_SS_LSB;
    727         force_speed |= 0; 
    728         break;
    729     case 5000:   
    730         force_speed |= 1; 
    731         break;
    732     case 6000:   
    733         force_speed |= 2; 
    734         break;
    735     case 0:      /* set to reasonable speed */
    736         /* fall through */
    737     case 10000:
    738         if (soc_property_port_get(unit, port, spn_10G_IS_CX4, TRUE)) {
    739             force_speed |= 4; /* 10G CX4 */
    740         } else {
    741             force_speed |= 3; /* 10G HiG */
    742         }
    743         break;
    744     case 12000:  
    745         force_speed |= 5;
    746         break;
    747     case 12500:
    748         force_speed |= 6;
    749         break;
    750     case 13000:
    751         force_speed |= 7;
    752         break;
    753     case 15000:
    754         force_speed |= 8;
    755         break;
    756     case 16000:
    757         force_speed |= 9;
    758         break;
    759     default:
    760         return (SOC_E_PARAM);
    761     }
    762    
    763     pc = INT_PHY_SW_STATE(unit, port);
    764 
    765     /* Disable autoneg */
    766     SOC_IF_ERROR_RETURN
    767         (phy_xgxs16g_an_set(unit, port, 0));
    768 
    769     /* Puts PLL in reset state and forces all datapath into reset state */
    770     SOC_IF_ERROR_RETURN
    771         (MODIFY_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, 0,
    772                                   XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
    773 
    774     if (FEATURE_SPEED_100FX(pc)) {
    775         /* disable 100FX and 100FX auto-detect */
    776         SOC_IF_ERROR_RETURN
    777             (MODIFY_XGXS16G_FX100_CONTROL1r(unit,pc,
    778                               0,
    779                               FX100_CONTROL1_AUTODET_EN_MASK |
    780                               FX100_CONTROL1_ENABLE_MASK));
    781 
    782         /* disable 100FX idle detect */
    783         SOC_IF_ERROR_RETURN
    784             (MODIFY_XGXS16G_FX100_CONTROL3r(unit,pc,
    785                               FX100_CONTROL3_CORRELATOR_DISABLE_MASK,
    786                               FX100_CONTROL3_CORRELATOR_DISABLE_MASK));
    787     }
    788 
    789     /* Set force speed */
    790     SOC_IF_ERROR_RETURN
    791         (MODIFY_XGXS16G_SERDESDIGITAL_MISC1r(unit, pc, force_speed,
    792                                 SERDESDIGITAL_MISC1_FORCE_SPEED_SEL_MASK |
    793                                 SERDESDIGITAL_MISC1_FORCE_SPEED_MASK));
    794                                     
    795     /* Set forced speed in IEEE control register. */
    796             
    797     if (speed <= 2500) {
    798         if (FEATURE_SPEED_100FX(pc)) {
    799             SOC_IF_ERROR_RETURN
    800                 (READ_XGXS16G_SERDESDIGITAL_STATUS1000X1r(unit, pc, &sgmii_status));
    801 
    802             sgmii_status &= SERDESDIGITAL_STATUS1000X1_SGMII_MODE_MASK;
    803             if (!sgmii_status && (speed == 100)) {
    804 
    805                 /* fiber mode 100fx, enable */
    806                 SOC_IF_ERROR_RETURN
    807                     (MODIFY_XGXS16G_FX100_CONTROL1r(unit,pc,
    808                                   FX100_CONTROL1_FAR_END_FAULT_EN_MASK |
    809                                   FX100_CONTROL1_ENABLE_MASK,
    810                                   FX100_CONTROL1_FAR_END_FAULT_EN_MASK |
    811                                   FX100_CONTROL1_ENABLE_MASK));
    812 
    813                 /* enable 100fx extended packet size */
    814                 SOC_IF_ERROR_RETURN
    815                     (MODIFY_XGXS16G_FX100_CONTROL2r(unit,pc,
    816                                 FX100_CONTROL2_EXTEND_PKT_SIZE_MASK,
    817                                 FX100_CONTROL2_EXTEND_PKT_SIZE_MASK));
    818             } else {
    819                 SOC_IF_ERROR_RETURN
    820                     (READ_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, &data16));
    821                 data16 &= ~(MII_CTRL_SS_LSB | MII_CTRL_SS_MSB);
    822                 data16 |= speed_mii;
    823                 SOC_IF_ERROR_RETURN
    824                     (WRITE_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, data16));
    825             }
    826 
    827         } else {
    828             SOC_IF_ERROR_RETURN
    829                 (READ_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, &data16));
    830             data16 &= ~(MII_CTRL_SS_LSB | MII_CTRL_SS_MSB);
    831             data16 |= speed_mii;
    832             SOC_IF_ERROR_RETURN
    833                 (WRITE_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, data16));
    834         }
    835     }
    836 
    837     /* Bring PLL out of reset */
    838     SOC_IF_ERROR_RETURN
    839         (MODIFY_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, 
    840                                   XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK,
    841                                   XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
    842     (void) _phy_xgxs16g_pll_lock_wait(unit, port);
    843 
    844     return (SOC_E_NONE);
    845 }
    846 
    847 /*
    848  * Function:
    849  *      phy_xgxs16g_speed_get
    850  * Purpose:
    851  *      Get PHY speed
    852  * Parameters:
    853  *      unit - StrataSwitch unit #.
    854  *      port - StrataSwitch port #. 
    855  *      speed - current link speed in Mbps
    856  * Returns:     
    857  *      SOC_E_NONE
    858  */
    859 STATIC int
    860 phy_xgxs16g_speed_get(int unit, soc_port_t port, int *speed)
    861 {
    862     phy_ctrl_t *pc;
    863     uint16      hw_speed;
    864     int         autoneg;
    865 
    866     static int  actual_speed[] = {10,      /*  0  */
    867                                   100,     /*  1  */
    868                                   1000,    /*  2  */
    869                                   2500,    /*  3  */
    870                                   5000,    /*  4  */
    871                                   6000,    /*  5  */
    872                                   10000,   /*  6  */
    873                                   10000,   /*  7  */
    874                                   12000,   /*  8  */
    875                                   12500,   /*  9  */
    876                                   13000,   /*  A  */
    877                                   15000,   /*  B  */
    878                                   16000,   /*  C  */
    879                                   1000,    /*  D  KX */
    880                                   10000};  /*  E  KX4*/
    881     static int  forced_speed[] = {2500,    /*  0  */
    882                                   5000,    /*  1  */
    883                                   6000,    /*  2  */
    884                                   10000,   /*  3  */
    885                                   10000,   /*  4  */
    886                                   12000,   /*  5  */
    887                                   12500,   /*  6  */
    888                                   13000,   /*  7  */
    889                                   15000,   /*  8  */
    890                                   16000};  /*  9  */ 
    891 
    892     SOC_IF_ERROR_RETURN
    893         (phy_xgxs16g_an_get(unit, port, &autoneg, NULL));
    894 
    895     /* Set reasonable default speed */
    896     *speed = 10000; 
    897     pc = INT_PHY_SW_STATE(unit, port);
    898     if (autoneg) {
    899         /* Get actual speed */
    900         SOC_IF_ERROR_RETURN
    901             (READ_XGXS16G_GP_STATUS_TOPANSTATUS1r(unit, pc, &hw_speed));
    902         hw_speed = (hw_speed & GP_STATUS_TOPANSTATUS1_ACTUAL_SPEED_MASK) >>
    903                    GP_STATUS_TOPANSTATUS1_ACTUAL_SPEED_SHIFT;
    904         if (hw_speed < COUNTOF(actual_speed)) {
    905             *speed = actual_speed[hw_speed];
    906         } else {
    907             return (SOC_E_INTERNAL);
    908         }
    909     } else {
    910         /* Get forced speed */
    911         SOC_IF_ERROR_RETURN 
    912             (READ_XGXS16G_SERDESDIGITAL_MISC1r(unit, pc, &hw_speed));
    913         if (hw_speed & SERDESDIGITAL_MISC1_FORCE_SPEED_SEL_MASK) {
    914             hw_speed = (hw_speed & SERDESDIGITAL_MISC1_FORCE_SPEED_MASK) >>
    915                        SERDESDIGITAL_MISC1_FORCE_SPEED_SHIFT;
    916             if (hw_speed < COUNTOF(forced_speed)){
    917                 *speed = forced_speed[hw_speed];
    918             } else {
    919                 return (SOC_E_INTERNAL);
    920             }
    921         } else {
    922             uint16       speed_mii;
    923             SOC_IF_ERROR_RETURN
    924                 (READ_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, &speed_mii));
    925             speed_mii &= (MII_CTRL_SS_LSB | MII_CTRL_SS_MSB);
    926             switch (speed_mii) {
    927             case MII_CTRL_SS_10:
    928                 *speed = 10;
    929                 break;
    930             case MII_CTRL_SS_100:
    931                 *speed = 100;
    932                 break;
    933             case MII_CTRL_SS_1000:
    934                 *speed = 1000;
    935                 break;
    936             case (MII_CTRL_SS_MSB | MII_CTRL_SS_LSB):   
    937                 *speed = 2500;
    938                 break;
    939             default:
    940                 *speed = pc->speed_max;
    941                 break;
    942             }
    943         }
    944     }
    945 
    946     LOG_INFO(BSL_LS_SOC_PHY,
    947              (BSL_META_U(unit,
    948                          "phy_xgxs16g_speed_get: u=%d p=%d GP_STATUS_TOPANSTATUS1 %04x speed= %d\n"),
    949               unit, port, hw_speed,*speed));
    950 
    951     return (SOC_E_NONE);
    952 }
    953 /*
    954  * Function:
    955  *      phy_xgxs16g_master_get
    956  * Purpose:
    957  *      this function is meant for 1000Base-T PHY. Added here to support
    958  *      internal PHY regression test
    959  * Parameters:
    960  *      unit - StrataSwitch unit #.
    961  *      port - StrataSwitch port #.
    962  *      master - (OUT) SOC_PORT_MS_*
    963  * Returns:
    964  *      SOC_E_NONE
    965  * Notes:
    966  *      The master mode is retrieved for the ACTIVE medium.
    967  */
    968 
    969 STATIC int
    970 phy_xgxs16g_master_get(int unit, soc_port_t port, int *master)
    971 {
    972     *master = SOC_PORT_MS_NONE;
    973     return SOC_E_NONE;
    974 }
    975 /*
    976  * Function:
    977  *      phy_xgxs16g_interface_get
    978  * Purpose:
    979  *      this function is meant for 1000Base-T PHY. Added here to support
    980  *      internal PHY regression test
    981  * Parameters:
    982  *      unit - StrataSwitch unit #.
    983  *      port - StrataSwitch port #.
    984  *      master - (OUT) SOC_PORT_IF_*
    985  * Returns:
    986  *      SOC_E_NONE
    987  * Notes:
    988  *      Interface mode is retrieved for the ACTIVE medium.
    989  */
    990 
    991 STATIC int
    992 phy_xgxs16g_interface_get(int unit, soc_port_t port, soc_port_if_t *pif)
    993 {  
    994    int serdes_fiber_pref = 0; 
    995    int speed = 0;
    996    SOC_IF_ERROR_RETURN(phy_xgxs16g_speed_get(unit, port, &speed));
    997    switch(speed)
    998    {
    999    case 10:
   1000    case 100:
   1001         *pif = SOC_PORT_IF_MII;
   1002         break;
   1003    case 1000:
   1004         serdes_fiber_pref = soc_property_port_get(unit, port, spn_SERDES_FIBER_PREF,
   1005                                 0); 
   1006             if(serdes_fiber_pref == TRUE) {
   1007                 *pif = SOC_PORT_IF_GMII;
   1008             } else {
   1009                 *pif = SOC_PORT_IF_SGMII;
   1010             }
   1011         break;
   1012    case 2500:
   1013         *pif = SOC_PORT_IF_GMII;
   1014         break;
   1015    case 10000:
   1016    case 13000:
   1017    default:
   1018         *pif = SOC_PORT_IF_XGMII;
   1019         break;
   1020    }
   1021    return SOC_E_NONE;
   1022 }
   1023 
   1024 
   1025 /*
   1026  * Function:    
   1027  *      phy_xgxs16g_an_set
   1028  * Purpose:     
   1029  *      Enable or disabled auto-negotiation on the specified port.
   1030  * Parameters:
   1031  *      unit - StrataSwitch unit #.
   1032  *      port - StrataSwitch port #. 
   1033  *      an   - Boolean, if true, auto-negotiation is enabled 
   1034  *              (and/or restarted). If false, autonegotiation is disabled.
   1035  * Returns:     
   1036  *      SOC_E_XXX
   1037  */
   1038 STATIC int
   1039 phy_xgxs16g_an_set(int unit, soc_port_t port, int an)
   1040 {
   1041     uint16      data16;
   1042     uint16      mask16;
   1043     int         cur_autoneg;
   1044     phy_ctrl_t *pc;
   1045 
   1046     pc = INT_PHY_SW_STATE(unit, port);
   1047 
   1048     SOC_IF_ERROR_RETURN
   1049         (phy_xgxs16g_an_get(unit, port, &cur_autoneg, NULL));
   1050 
   1051     /* If request to disable autoneg and autoneg is already disabled,
   1052      * do nothing.
   1053      */ 
   1054     if ((!cur_autoneg) && (!an)) {
   1055         return (SOC_E_NONE);
   1056     }
   1057 
   1058     SOC_IF_ERROR_RETURN
   1059         (WRITE_XGXS16G_BAM_NEXTPAGE_MP5_NEXTPAGECTRLr(unit, pc, an ? 1 : 0));
   1060 
   1061     /* If request to enable autoneg and autoneg is already enabled,
   1062      * restart autoneg.
   1063      */
   1064     if (cur_autoneg && an) {
   1065         SOC_IF_ERROR_RETURN
   1066             (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc,
   1067                                              MII_CTRL_AE | MII_CTRL_RAN,
   1068                                              MII_CTRL_AE | MII_CTRL_RAN));
   1069         if (PHY_CLAUSE73_MODE(unit, port)) {
   1070             SOC_IF_ERROR_RETURN
   1071                 (MODIFY_XGXS16G_AN_CL73_REG(unit, pc,MII_CTRL_REG,
   1072                                               MII_CTRL_AE,
   1073                                               MII_CTRL_AE));
   1074         }
   1075     }
   1076 
   1077     /* Do the following sequence if changing autoneg setting. */
   1078     /* Stop PLL Sequencer */
   1079     SOC_IF_ERROR_RETURN
   1080         (MODIFY_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, 0,
   1081                                  XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
   1082 
   1083     /* Disable/Enable 10G parallel detect */
   1084     data16 = 0;
   1085     mask16 = AN73_PDET_PARDET10GCONTROL_PARDET10G_EN_MASK;
   1086     if (soc_property_port_get(unit, port, spn_XGXS_PDETECT_10G, 1) && an) {
   1087         data16 = AN73_PDET_PARDET10GCONTROL_PARDET10G_EN_MASK;
   1088     }
   1089     SOC_IF_ERROR_RETURN
   1090         (MODIFY_XGXS16G_AN73_PDET_PARDET10GCONTROLr(unit, pc, data16, mask16));
   1091     
   1092     /* Disable/Enable 1000X parallel detect */
   1093     data16 = SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK;
   1094     mask16 = SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK;
   1095     SOC_IF_ERROR_RETURN
   1096         (MODIFY_XGXS16G_SERDESDIGITAL_CONTROL1000X2r(unit, pc, data16, mask16));
   1097 
   1098     /* Clause 73 backplane support */
   1099     if (PHY_CLAUSE73_MODE(unit, port)) {
   1100         
   1101     }
   1102 
   1103     /* Enable autoneg and restart autoneg */
   1104     data16 = (an) ? MII_CTRL_AE | MII_CTRL_RAN : 0;
   1105     mask16 = MII_CTRL_AE | MII_CTRL_RAN;
   1106     SOC_IF_ERROR_RETURN
   1107         (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, data16, mask16));
   1108 
   1109     if (PHY_CLAUSE73_MODE(unit, port)) {
   1110         SOC_IF_ERROR_RETURN
   1111             (MODIFY_XGXS16G_AN_CL73_REG(unit, pc, MII_CTRL_REG,
   1112                                           data16,
   1113                                           mask16));
   1114     }
   1115 
   1116     /* Start PLL Sequencer and wait for PLL to lock */
   1117     SOC_IF_ERROR_RETURN
   1118         (MODIFY_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc,
   1119                                  XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK,
   1120                                  XGXSBLK0_XGXSCONTROL_START_SEQUENCER_MASK));
   1121     (void) _phy_xgxs16g_pll_lock_wait(unit, port);
   1122 
   1123     return (SOC_E_NONE);
   1124 }
   1125 
   1126 /*
   1127  * Function:    
   1128  *      phy_xgxs16g_an_get
   1129  * Purpose:     
   1130  *      Get the current auto-negotiation status (enabled/busy)
   1131  * Parameters:
   1132  *      unit - StrataSwitch unit #.
   1133  *      port - StrataSwitch port #. 
   1134  *      an   - (OUT) if true, auto-negotiation is enabled.
   1135  *      an_done - (OUT) if true, auto-negotiation is complete. This
   1136  *              value is undefined if an == false.
   1137  * Returns:     
   1138  *      SOC_E_XXX
   1139  */
   1140 
   1141 STATIC int
   1142 phy_xgxs16g_an_get(int unit, soc_port_t port, int *an, int *an_done)
   1143 {
   1144     uint16      mii_ctrl;
   1145     uint16      an_status;
   1146     phy_ctrl_t *pc;
   1147 
   1148     pc = INT_PHY_SW_STATE(unit, port);
   1149 
   1150     SOC_IF_ERROR_RETURN
   1151         (READ_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, &mii_ctrl));
   1152     *an = ((mii_ctrl & MII_CTRL_AE) != 0);
   1153 
   1154     if (NULL != an_done) {
   1155         SOC_IF_ERROR_RETURN
   1156             (READ_XGXS16G_GP_STATUS_TOPANSTATUS1r(unit, pc, &an_status));
   1157         *an_done = ((an_status & 
   1158                      GP_STATUS_TOPANSTATUS1_CL37_AUTONEG_COMPLETE_MASK) != 0);
   1159 
   1160         if (PHY_CLAUSE73_MODE(unit, port)) {
   1161             *an_done |= ((an_status &
   1162                          GP_STATUS_TOPANSTATUS1_CL73_AUTONEG_COMPLETE_MASK) != 
   1163                         0);
   1164         }
   1165     }
   1166 
   1167     return (SOC_E_NONE);
   1168 }
   1169 
   1170 STATIC int
   1171 _phy_xgxs16g_c73_adv_local_set(int unit, soc_port_t port,
   1172                             soc_port_ability_t *ability)
   1173 {
   1174     uint16            an_adv;
   1175     uint16            pause;
   1176     phy_ctrl_t       *pc;
   1177 
   1178     pc = INT_PHY_SW_STATE(unit, port);
   1179 
   1180     an_adv = (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) ?
   1181                CL73_AN_ADV_TECH_1G_KX : 0;
   1182     an_adv |= (ability->speed_full_duplex & SOC_PA_SPEED_10GB) ?
   1183               CL73_AN_ADV_TECH_10G_KX4 : 0;
   1184 
   1185     SOC_IF_ERROR_RETURN
   1186         (MODIFY_XGXS16G_AN_CL73_REG(unit, pc, CL73_AN_ADVERT1_REG, an_adv,
   1187                                      CL73_AN_ADV_TECH_SPEEDS_MASK));
   1188 
   1189     switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) {
   1190     case SOC_PA_PAUSE_TX:
   1191         pause = CL73_AN_ADV_ASYM_PAUSE;
   1192         break;
   1193     case SOC_PA_PAUSE_RX:
   1194         pause = CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE;
   1195         break;
   1196     case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX:
   1197         pause = CL73_AN_ADV_PAUSE;
   1198         break;
   1199     default:
   1200         pause = 0;
   1201         break;
   1202     }
   1203 
   1204     SOC_IF_ERROR_RETURN
   1205         (MODIFY_XGXS16G_AN_CL73_REG(unit, pc, CL73_AN_ADVERT0_REG, pause,
   1206                                      (CL73_AN_ADV_PAUSE |
   1207                                       CL73_AN_ADV_ASYM_PAUSE)));
   1208 
   1209     LOG_INFO(BSL_LS_SOC_PHY,
   1210              (BSL_META_U(unit,
   1211                          "_phy_xgxs16g_c73_adv_local_set: u=%d p=%d pause=%08x speeds=%04x,adv=0x%x\n"),
   1212               unit, port, pause, an_adv,ability->speed_full_duplex));
   1213     return SOC_E_NONE;
   1214 }
   1215 
   1216 STATIC int
   1217 _phy_xgxs16g_c73_adv_local_get(int unit, soc_port_t port,
   1218                             soc_port_ability_t *ability)
   1219 {
   1220     uint16            an_adv;
   1221     soc_port_mode_t   speeds,pause;
   1222     phy_ctrl_t       *pc;
   1223 
   1224     pc = INT_PHY_SW_STATE(unit, port);
   1225 
   1226     SOC_IF_ERROR_RETURN
   1227         (READ_XGXS16G_AN_CL73_REG(unit, pc, CL73_AN_ADVERT1_REG, &an_adv));
   1228 
   1229     speeds = (an_adv & CL73_AN_ADV_TECH_1G_KX) ? SOC_PA_SPEED_1000MB : 0;
   1230     speeds |= (an_adv & CL73_AN_ADV_TECH_10G_KX4) ? SOC_PA_SPEED_10GB : 0;
   1231     ability->speed_full_duplex |= speeds;
   1232 
   1233     SOC_IF_ERROR_RETURN
   1234         (READ_XGXS16G_AN_CL73_REG(unit, pc, CL73_AN_ADVERT0_REG, &an_adv));
   1235 
   1236     switch (an_adv & (CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE)) {
   1237         case CL73_AN_ADV_PAUSE:
   1238             pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   1239             break;
   1240         case CL73_AN_ADV_ASYM_PAUSE:
   1241             pause = SOC_PA_PAUSE_TX;
   1242             break;
   1243         case CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE:
   1244             pause = SOC_PA_PAUSE_RX;
   1245             break;
   1246         default:
   1247             pause = 0;
   1248             break;
   1249     }
   1250     ability->pause = pause;
   1251 
   1252     LOG_INFO(BSL_LS_SOC_PHY,
   1253              (BSL_META_U(unit,
   1254                          "_phy_xgxs16g_c73_adv_local_get: u=%d p=%d pause=%08x speeds=%04x\n"),
   1255               unit, port, pause, speeds));
   1256     return SOC_E_NONE;
   1257 }
   1258 
   1259 STATIC int
   1260 _phy_xgxs16g_c73_adv_remote_get(int unit, soc_port_t port,
   1261                              soc_port_ability_t *ability)
   1262 {
   1263     uint16            an_adv;
   1264     soc_port_mode_t   mode;
   1265     phy_ctrl_t       *pc;
   1266      pc = INT_PHY_SW_STATE(unit, port);
   1267      SOC_IF_ERROR_RETURN
   1268         (READ_XGXS16G_AN_CL73_REG(unit, pc,CL73_AN_LP_ABILITY1_REG, &an_adv));
   1269 
   1270     mode = (an_adv & CL73_AN_ADV_TECH_1G_KX) ? SOC_PA_SPEED_1000MB : 0;
   1271     mode |= (an_adv & CL73_AN_ADV_TECH_10G_KX4) ? SOC_PA_SPEED_10GB : 0;
   1272     ability->speed_full_duplex |= mode;
   1273 
   1274     SOC_IF_ERROR_RETURN
   1275         (READ_XGXS16G_AN_CL73_REG(unit, pc, CL73_AN_LP_ABILITY0_REG,&an_adv));
   1276 
   1277     mode = 0;
   1278     switch (an_adv & (CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE)) {
   1279         case CL73_AN_ADV_PAUSE:
   1280             mode = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   1281             break;
   1282         case CL73_AN_ADV_ASYM_PAUSE:
   1283             mode = SOC_PA_PAUSE_TX;
   1284             break;
   1285         case CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE:
   1286             mode = SOC_PA_PAUSE_RX;
   1287             break;
   1288     }
   1289     ability->pause = mode;
   1290 
   1291     return SOC_E_NONE;
   1292 }
   1293 
   1294 /*
   1295  * Function:
   1296  *      phy_xgxs16g_ability_advert_set
   1297  * Purpose:
   1298  *      Set the current advertisement for auto-negotiation.
   1299  * Parameters:
   1300  *      unit - StrataSwitch unit #.
   1301  *      port - StrataSwitch port #.
   1302  *      mode - Port mode mask indicating supported options/speeds.
   1303  * Returns:
   1304  *      SOC_E_XXX
   1305  * Notes:
   1306  *      The advertisement is set only for the ACTIVE medium.
   1307  *      No synchronization performed at this level.
   1308  */
   1309 
   1310 STATIC int
   1311 phy_xgxs16g_ability_advert_set(int unit, soc_port_t port,
   1312                           soc_port_ability_t *ability)
   1313 {
   1314     uint16           adv_over1g;
   1315     uint16           an_adv;
   1316     soc_port_mode_t  mode;
   1317     phy_ctrl_t      *pc;
   1318 
   1319     if (NULL == ability) {
   1320         return (SOC_E_PARAM);
   1321     }
   1322 
   1323     pc = INT_PHY_SW_STATE(unit, port);
   1324 
   1325     /* Support only full duplex */
   1326     an_adv = (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) ? MII_ANP_C37_FD : 0;
   1327     switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) {
   1328     case SOC_PA_PAUSE_TX:
   1329         an_adv |= MII_ANP_C37_ASYM_PAUSE;
   1330         break;
   1331     case SOC_PA_PAUSE_RX:
   1332         an_adv |= MII_ANP_C37_ASYM_PAUSE | MII_ANP_C37_PAUSE;
   1333         break;
   1334     case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX:
   1335         an_adv |= MII_ANP_C37_PAUSE;
   1336         break;
   1337     }
   1338     SOC_IF_ERROR_RETURN
   1339         (WRITE_XGXS16G_COMBO_IEEE0_AUTONEGADVr(unit, pc, an_adv));
   1340 
   1341     mode = ability->speed_full_duplex;
   1342     adv_over1g = 0;
   1343     adv_over1g |= (mode & SOC_PA_SPEED_2500MB) ? OVER1G_UP1_DATARATE_2P5GX1_MASK : 0;
   1344     if (mode & SOC_PA_SPEED_10GB) {
   1345         if (soc_property_port_get(unit, port, spn_10G_IS_CX4, TRUE)) {
   1346             adv_over1g |= OVER1G_UP1_DATARATE_10GCX4_MASK;
   1347         } else {
   1348             adv_over1g |= OVER1G_UP1_DATARATE_10GX4_MASK;
   1349         }
   1350     }
   1351     adv_over1g |= (mode & SOC_PA_SPEED_12GB) ? OVER1G_UP1_DATARATE_12GX4_MASK : 0;
   1352     adv_over1g |= (mode & SOC_PA_SPEED_13GB) ? OVER1G_UP1_DATARATE_13GX4_MASK : 0;
   1353     adv_over1g |= (mode & SOC_PA_SPEED_16GB) ? OVER1G_UP1_DATARATE_16GX4_MASK : 0;
   1354     SOC_IF_ERROR_RETURN
   1355         (WRITE_XGXS16G_OVER1G_UP1r(unit, pc, adv_over1g));
   1356 
   1357     if (PHY_CLAUSE73_MODE(unit, port)) {
   1358         SOC_IF_ERROR_RETURN
   1359             (_phy_xgxs16g_c73_adv_local_set(unit, port, ability));
   1360     }
   1361 
   1362     LOG_INFO(BSL_LS_SOC_PHY,
   1363              (BSL_META_U(unit,
   1364                          "phy_xgxs16g_ability_advert_set:u=%d p=%d pause=%08x OVER1G_UP1 %04x\n"),
   1365               unit, port, ability->pause, an_adv));
   1366     
   1367     return (SOC_E_NONE);
   1368 }
   1369 
   1370 /*
   1371  * Function:
   1372  *      phy_xgxs16g_ability_advert_get
   1373  * Purpose:
   1374  *      Get the current advertisement for auto-negotiation.
   1375  * Parameters:
   1376  *      unit - StrataSwitch unit #.
   1377  *      port - StrataSwitch port #.
   1378  *      mode - (OUT) Port mode mask indicating supported options/speeds.
   1379  * Returns:
   1380  *      SOC_E_XXX
   1381  * Notes:
   1382  *      The advertisement is retrieved for the ACTIVE medium.
   1383  *      No synchronization performed at this level.
   1384  */
   1385 
   1386 STATIC int
   1387 phy_xgxs16g_ability_advert_get(int unit, soc_port_t port,
   1388                               soc_port_ability_t *ability)
   1389 {
   1390     uint16           adv_over1g;
   1391     uint16           an_adv;
   1392     soc_port_mode_t  mode;
   1393     phy_ctrl_t      *pc;
   1394 
   1395     if (NULL == ability) {
   1396         return (SOC_E_PARAM);
   1397     }
   1398 
   1399     pc = INT_PHY_SW_STATE(unit, port);
   1400 
   1401     sal_memset(ability, 0, sizeof(*ability));
   1402     mode = 0;
   1403     SOC_IF_ERROR_RETURN
   1404         (READ_XGXS16G_COMBO_IEEE0_AUTONEGADVr(unit, pc, &an_adv));
   1405 
   1406     switch (an_adv & (MII_ANP_C37_ASYM_PAUSE | MII_ANP_C37_PAUSE)) {
   1407     case MII_ANP_C37_ASYM_PAUSE:
   1408         mode |= SOC_PA_PAUSE_TX;
   1409         break;
   1410     case (MII_ANP_C37_ASYM_PAUSE | MII_ANP_C37_PAUSE):
   1411         mode |= SOC_PA_PAUSE_RX;
   1412         break;
   1413     case MII_ANP_C37_PAUSE:
   1414         mode |= SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   1415         break;
   1416     }
   1417     ability->pause = mode;
   1418 
   1419     mode = 0;
   1420     mode |= (an_adv & MII_ANP_C37_FD) ? SOC_PA_SPEED_1000MB : 0;
   1421     SOC_IF_ERROR_RETURN
   1422         (READ_XGXS16G_OVER1G_UP1r(unit, pc, &adv_over1g));
   1423     mode |= (adv_over1g & OVER1G_UP1_DATARATE_2P5GX1_MASK) ? 
   1424               SOC_PA_SPEED_2500MB : 0;
   1425     mode |= (adv_over1g & OVER1G_UP1_DATARATE_10GCX4_MASK) ?
   1426               SOC_PA_SPEED_10GB : 0;
   1427     mode |= (adv_over1g & OVER1G_UP1_DATARATE_10GX4_MASK) ?
   1428               SOC_PA_SPEED_10GB : 0;
   1429     mode |= (adv_over1g & OVER1G_UP1_DATARATE_12GX4_MASK) ?
   1430               SOC_PA_SPEED_12GB : 0;
   1431     mode |= (adv_over1g & OVER1G_UP1_DATARATE_13GX4_MASK) ?
   1432               SOC_PA_SPEED_13GB : 0;
   1433     mode |= (adv_over1g & OVER1G_UP1_DATARATE_16GX4_MASK) ?
   1434               SOC_PA_SPEED_16GB : 0;
   1435 
   1436     ability->speed_full_duplex = mode;
   1437 
   1438     /* check for clause73 */
   1439     if (PHY_CLAUSE73_MODE(unit, port)) {
   1440         SOC_IF_ERROR_RETURN
   1441             (_phy_xgxs16g_c73_adv_local_get(unit, port, ability));
   1442     }
   1443 
   1444     LOG_INFO(BSL_LS_SOC_PHY,
   1445              (BSL_META_U(unit,
   1446                          "phy_xgxs16g_ability_advert_get:unit=%d p=%d pause=%08x sp=%08x\n"),
   1447               unit, port, ability->pause, ability->speed_full_duplex));
   1448 
   1449     return (SOC_E_NONE);
   1450 }
   1451 
   1452 /*
   1453  * Function:
   1454  *      phy_xgxs16g_ability_remote_get
   1455  * Purpose:
   1456  *      Get the current advertisement for auto-negotiation.
   1457  * Parameters:
   1458  *      unit - StrataSwitch unit #.
   1459  *      port - StrataSwitch port #.
   1460  *      mode - (OUT) Port mode mask indicating supported options/speeds.
   1461  * Returns:
   1462  *      SOC_E_XXX
   1463  * Notes:
   1464  *      The advertisement is retrieved for the ACTIVE medium.
   1465  *      No synchronization performed at this level.
   1466  */
   1467 
   1468 STATIC int
   1469 phy_xgxs16g_ability_remote_get(int unit, soc_port_t port,
   1470                                soc_port_ability_t *ability)
   1471 {
   1472     uint16            an_status;
   1473     uint16            an_done;
   1474     uint16            link_stat_gp;
   1475     uint16            an_adv;
   1476     soc_port_mode_t   mode;
   1477     phy_ctrl_t       *pc;
   1478 
   1479     if (NULL == ability) {
   1480         return (SOC_E_PARAM);
   1481     }
   1482  
   1483     pc = INT_PHY_SW_STATE(unit, port);
   1484 
   1485     SOC_IF_ERROR_RETURN
   1486             (READ_XGXS16G_GP_STATUS_TOPANSTATUS1r(unit, pc, &an_status));
   1487 
   1488     an_done = an_status & (GP_STATUS_TOPANSTATUS1_CL37_AUTONEG_COMPLETE_MASK |
   1489                            GP_STATUS_TOPANSTATUS1_CL73_AUTONEG_COMPLETE_MASK);
   1490     link_stat_gp = an_status & GP_STATUS_TOPANSTATUS1_LINK_STATUS_MASK;
   1491     LOG_INFO(BSL_LS_SOC_PHY,
   1492              (BSL_META_U(unit,
   1493                          "u=%d p=%d an_status=%04x link_stat_gp=%04x\n"),
   1494               unit, port, an_status, link_stat_gp));
   1495 
   1496     sal_memset(ability, 0, sizeof(*ability));
   1497 
   1498     mode = 0;
   1499     if (link_stat_gp && an_done) {
   1500         /* Decode remote advertisement only when link is up and autoneg is
   1501          * completed.
   1502          */
   1503 
   1504         if (an_status & GP_STATUS_TOPANSTATUS1_CL37_AUTONEG_COMPLETE_MASK) {
   1505             SOC_IF_ERROR_RETURN
   1506                 (READ_XGXS16G_GP_STATUS_LP_UP1r(unit, pc, &an_adv));
   1507             mode |= (an_adv & OVER1G_LP_UP1_DATARATE_16GX4_MASK) ?
   1508                      SOC_PA_SPEED_16GB : 0;
   1509             mode |= (an_adv & OVER1G_LP_UP1_DATARATE_13GX4_MASK) ?
   1510                      SOC_PA_SPEED_13GB : 0;
   1511             mode |= (an_adv & OVER1G_LP_UP1_DATARATE_12GX4_MASK) ?
   1512                      SOC_PA_SPEED_12GB : 0;
   1513             mode |= (an_adv & OVER1G_LP_UP1_DATARATE_10GCX4_MASK) ?
   1514                      SOC_PA_SPEED_10GB : 0;
   1515             mode |= (an_adv & OVER1G_LP_UP1_DATARATE_10GX4_MASK) ?
   1516                      SOC_PA_SPEED_10GB : 0;
   1517             mode |= (an_adv & OVER1G_LP_UP1_DATARATE_2P5GX1_MASK) ?
   1518                      SOC_PA_SPEED_2500MB : 0;
   1519 
   1520             LOG_INFO(BSL_LS_SOC_PHY,
   1521                      (BSL_META_U(unit,
   1522                                  "u=%d p=%d over1G an_adv=%04x\n"),
   1523                       unit, port, an_adv));
   1524             SOC_IF_ERROR_RETURN
   1525                 (READ_XGXS16G_COMBO_IEEE0_AUTONEGLPABILr(unit, pc, &an_adv));
   1526             LOG_INFO(BSL_LS_SOC_PHY,
   1527                      (BSL_META_U(unit,
   1528                                  "u=%d p=%d combo an_adv=%04x\n"),
   1529                       unit, port, an_adv));
   1530 
   1531             mode |= (an_adv & MII_ANP_C37_FD) ? SOC_PA_SPEED_1000MB : 0;
   1532             ability->speed_full_duplex = mode;
   1533 
   1534             mode = 0; 
   1535             switch (an_adv & (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) {
   1536                 case MII_ANP_C37_PAUSE:
   1537                     mode |= SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   1538                     break;
   1539                 case MII_ANP_C37_ASYM_PAUSE:
   1540                     mode |= SOC_PA_PAUSE_TX;
   1541                     break;
   1542                 case MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE:
   1543                     mode |= SOC_PA_PAUSE_RX;
   1544                     break;
   1545             }
   1546             ability->pause = mode;
   1547         }
   1548         if (an_status & GP_STATUS_TOPANSTATUS1_CL73_AUTONEG_COMPLETE_MASK) {
   1549             if (PHY_CLAUSE73_MODE(unit, port)) {
   1550                 SOC_IF_ERROR_RETURN
   1551                     (_phy_xgxs16g_c73_adv_remote_get(unit, port, ability));
   1552             }
   1553         }
   1554     } else {
   1555         /* Simply return local abilities */
   1556         phy_xgxs16g_ability_advert_get(unit, port, ability);
   1557     }
   1558     LOG_INFO(BSL_LS_SOC_PHY,
   1559              (BSL_META_U(unit,
   1560                          "phy_xgxs16g_ability_remote_get:unit=%d p=%d pause=%08x sp=%08x\n"),
   1561               unit, port, ability->pause, ability->speed_full_duplex));
   1562 
   1563     return (SOC_E_NONE);
   1564 }
   1565 
   1566 
   1567 /*
   1568  * Function:
   1569  *      phy_xgxs16g_lb_set
   1570  * Purpose:
   1571  *      Put XGXS6/FusionCore in PHY loopback
   1572  * Parameters:
   1573  *      unit - StrataSwitch unit #.
   1574  *      port - StrataSwitch port #. 
   1575  *      enable - binary value for on/off (1/0)
   1576  * Returns:     
   1577  *      SOC_E_NONE
   1578  */
   1579 
   1580 STATIC int
   1581 phy_xgxs16g_lb_set(int unit, soc_port_t port, int enable)
   1582 {
   1583     uint16      misc_ctrl;
   1584     uint16      lb_bit;
   1585     uint16      lb_mask;
   1586     phy_ctrl_t *pc;
   1587 
   1588     pc = INT_PHY_SW_STATE(unit, port);
   1589     
   1590     /* Configure Loopback in XAUI */
   1591     SOC_IF_ERROR_RETURN
   1592         (READ_XGXS16G_XGXSBLK0_MISCCONTROL1r(unit, pc, &misc_ctrl));
   1593     if (misc_ctrl & XGXSBLK0_MISCCONTROL1_PCS_DEV_EN_OVERRIDE_MASK) {
   1594           /* PCS */
   1595           lb_bit  = (enable) ? IEEE0BLK_IEEECONTROL0_GLOOPBACK_MASK : 0;
   1596           lb_mask = IEEE0BLK_IEEECONTROL0_GLOOPBACK_MASK;
   1597     } else if (misc_ctrl & XGXSBLK0_MISCCONTROL1_PMD_DEV_EN_OVERRIDE_MASK) {
   1598           /* PMA/PMD */
   1599           lb_bit  = (enable) ? 1 : 0;
   1600           lb_mask = 1;
   1601     } else {
   1602           /* PHY XS, DTE XS */
   1603           lb_bit  = (enable) ? IEEE0BLK_IEEECONTROL0_GLOOPBACK_MASK : 0;
   1604           lb_mask = IEEE0BLK_IEEECONTROL0_GLOOPBACK_MASK;
   1605     }
   1606     SOC_IF_ERROR_RETURN
   1607         (MODIFY_XGXS16G_IEEE0BLK_IEEECONTROL0r(unit, pc, lb_bit, lb_mask));
   1608 
   1609     /* Configure Loopback in SerDes */
   1610     SOC_IF_ERROR_RETURN
   1611         (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, 
   1612                                              (enable) ? MII_CTRL_LE : 0,
   1613                                              MII_CTRL_LE));
   1614 
   1615     return (SOC_E_NONE);
   1616 }
   1617 
   1618 /*
   1619  * Function:
   1620  *      phy_xgxs16g_lb_get
   1621  * Purpose:
   1622  *      Get XGXS6/FusionCore PHY loopback state
   1623  * Parameters:
   1624  *      unit - StrataSwitch unit #.
   1625  *      port - StrataSwitch port #. 
   1626  *      enable - address of location to store binary value for on/off (1/0)
   1627  * Returns:     
   1628  *      SOC_E_NONE
   1629  */
   1630 
   1631 STATIC int
   1632 phy_xgxs16g_lb_get(int unit, soc_port_t port, int *enable)
   1633 {
   1634     uint16      mii_ctrl;
   1635     phy_ctrl_t *pc;
   1636 
   1637     pc = INT_PHY_SW_STATE(unit, port);
   1638 
   1639     SOC_IF_ERROR_RETURN
   1640         (READ_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, &mii_ctrl));
   1641     *enable = ((mii_ctrl & MII_CTRL_LE) == MII_CTRL_LE);
   1642 
   1643     return (SOC_E_NONE);
   1644 }
   1645 
   1646 
   1647 STATIC int
   1648 phy_xgxs16g_ability_local_get(int unit, soc_port_t port,
   1649                               soc_port_ability_t *ability)
   1650 {
   1651     phy_ctrl_t *pc;
   1652 
   1653     if (NULL == ability) {
   1654         return (SOC_E_PARAM);
   1655     }
   1656 
   1657     pc = INT_PHY_SW_STATE(unit, port);
   1658 
   1659     ability->speed_half_duplex  = SOC_PA_ABILITY_NONE;
   1660     ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   1661     ability->interface = SOC_PA_INTF_XGMII;
   1662     ability->medium    = SOC_PA_MEDIUM_COPPER;
   1663     ability->loopback  = SOC_PA_LB_PHY;
   1664     ability->flags     = SOC_PA_AUTONEG;
   1665 
   1666     ability->speed_full_duplex  = SOC_PA_SPEED_1000MB | SOC_PA_SPEED_2500MB;
   1667     if (FEATURE_SPEED_100FX(pc)) {
   1668         ability->speed_full_duplex  |= SOC_PA_SPEED_100MB;
   1669     }
   1670 
   1671     /*
   1672      * If not in fiber mode or in copper mode, advertise 10/100 Mbps
   1673      * capability. Other wise assume 1000X mode of operation for
   1674      * below 10Gbps speed operation.
   1675      */
   1676     if (!PHY_FIBER_MODE(unit, port) || PHY_COPPER_MODE(unit, port)) {
   1677         if (IS_XE_PORT(unit, port)) {
   1678             ability->speed_half_duplex  |= SOC_PA_SPEED_10MB |
   1679                                           SOC_PA_SPEED_100MB;
   1680             ability->speed_full_duplex  |= SOC_PA_SPEED_10MB |
   1681                                           SOC_PA_SPEED_100MB;
   1682         } else if (IS_GE_PORT(unit, port)) {
   1683             ability->speed_half_duplex  |= SOC_PA_SPEED_10MB |
   1684                                           SOC_PA_SPEED_100MB;
   1685             ability->speed_full_duplex  |= SOC_PA_SPEED_10MB |
   1686                                           SOC_PA_SPEED_100MB;
   1687             ability->speed_full_duplex &= ~SOC_PA_SPEED_2500MB;
   1688         }
   1689     }
   1690     switch(pc->speed_max) {
   1691         case 16000:
   1692             ability->speed_full_duplex |= SOC_PA_SPEED_16GB; 
   1693             /* fall through */
   1694         case 13000:
   1695             ability->speed_full_duplex |= SOC_PA_SPEED_13GB;
   1696             /* fall through */
   1697         case 12000:
   1698             ability->speed_full_duplex |= SOC_PA_SPEED_12GB;
   1699             /* fall through */
   1700         default:
   1701             ability->speed_full_duplex |= SOC_PA_SPEED_10GB;
   1702             break; 
   1703     }
   1704 
   1705     return (SOC_E_NONE);
   1706 }
   1707 
   1708 
   1709 STATIC int
   1710 _phy_xgxs16g_tx_driver_field_get(phy_ctrl_t *pc, soc_phy_control_t type,
   1711 								int *ln_ctrl, uint16 *mask, int *shfter)
   1712 {
   1713     int lane_ctrl;
   1714     int is_40nm;
   1715 	
   1716     is_40nm = XGXS16G_13G_ID(pc);
   1717     lane_ctrl = TX_DRIVER_DFT_LN_CTRL;
   1718     *mask = 0;
   1719     *shfter = 0;
   1720     /* _LANEn(n=0-3) control type only applies to combo mode or dxgxs in
   1721      * independent channel mode
   1722      */
   1723 
   1724     switch(type) {
   1725     case SOC_PHY_CONTROL_PREEMPHASIS_LANE0:
   1726     /* fall through */
   1727     case SOC_PHY_CONTROL_PREEMPHASIS_LANE1:
   1728     /* fall through */
   1729     case SOC_PHY_CONTROL_PREEMPHASIS_LANE2:
   1730     /* fall through */
   1731     case SOC_PHY_CONTROL_PREEMPHASIS_LANE3:
   1732     /* fall through */
   1733     case SOC_PHY_CONTROL_PREEMPHASIS:
   1734          *shfter = is_40nm ? TX_ALL_040_TX_DRIVER_PREEMPHASIS_POST_SHIFT :
   1735 						TX_ALL_TX_DRIVER_PREEMPHASIS_SHIFT;
   1736          *mask = is_40nm ? TX_ALL_040_TX_DRIVER_PREEMPHASIS_POST_MASK : 
   1737 						TX_ALL_TX_DRIVER_PREEMPHASIS_MASK;
   1738          if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE0) {
   1739              lane_ctrl = 0;
   1740          } else if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE1) {
   1741              lane_ctrl = 1;
   1742          } else if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE2) {
   1743              lane_ctrl = 2;
   1744          } else if (type == SOC_PHY_CONTROL_PREEMPHASIS_LANE3) {
   1745              lane_ctrl = 3;
   1746          }
   1747          break;
   1748 
   1749     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0:
   1750     /* fall through */
   1751     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1:
   1752     /* fall through */
   1753     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2:
   1754     /* fall through */
   1755     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3:
   1756     /* fall through */
   1757     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   1758          *shfter = is_40nm ? TX_ALL_040_TX_DRIVER_IDRIVER_SHIFT : 
   1759 		 TX_ALL_TX_DRIVER_IDRIVER_SHIFT;
   1760          *mask = is_40nm ? TX_ALL_040_TX_DRIVER_IDRIVER_MASK : 
   1761 		 TX_ALL_TX_DRIVER_IDRIVER_MASK;
   1762          if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0) {
   1763              lane_ctrl = 0;
   1764          } else if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1) {
   1765              lane_ctrl = 1;
   1766          } else if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2) {
   1767              lane_ctrl = 2;
   1768          } else if (type == SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3) {
   1769              lane_ctrl = 3;
   1770          }
   1771          break;
   1772 
   1773     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0:
   1774     /* fall through */
   1775     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1:
   1776     /* fall through */
   1777     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2:
   1778     /* fall through */
   1779     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3:
   1780     /* fall through */
   1781     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   1782         if(is_40nm) {
   1783             /* 40nm analog does not support pre driver configuration */
   1784             *shfter = 0;
   1785             *mask = 0;
   1786         } else {		 
   1787             *shfter = TX_ALL_TX_DRIVER_IPREDRIVER_SHIFT;
   1788             *mask = TX_ALL_TX_DRIVER_IPREDRIVER_MASK;
   1789         }
   1790          if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0) {
   1791              lane_ctrl = 0;
   1792          } else if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1) {
   1793              lane_ctrl = 1;
   1794          } else if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2) {
   1795              lane_ctrl = 2;
   1796         
   1797            /* coverity[mixed_enums:FALSE] */
   1798          } else if (type == SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3) {
   1799              lane_ctrl = 3;
   1800          }
   1801          break;
   1802     default:
   1803          /* should never get here */
   1804          return SOC_E_PARAM;
   1805     }
   1806     *ln_ctrl = lane_ctrl;
   1807     return SOC_E_NONE;
   1808 }
   1809 
   1810 STATIC int
   1811 _phy_xgxs16g_control_tx_driver_set(int unit, phy_ctrl_t *pc,
   1812                                 soc_phy_control_t type, uint32 value)
   1813 {
   1814     uint16  data;             /* Temporary holder of reg value to be written */
   1815     uint16  mask;             /* Bit mask of reg value to be updated */
   1816     int     lane_ctrl;
   1817     int     shifter;
   1818 	int 	is_40nm;
   1819 
   1820     if (value > 15) {
   1821         return SOC_E_PARAM;
   1822     }
   1823 
   1824     SOC_IF_ERROR_RETURN
   1825         (_phy_xgxs16g_tx_driver_field_get(pc, type,&lane_ctrl,&mask,&shifter));
   1826 
   1827 	is_40nm = XGXS16G_13G_ID(pc);
   1828     data = value << shifter;
   1829 	
   1830 	switch (lane_ctrl) {
   1831 		case 0: 
   1832 			SOC_IF_ERROR_RETURN
   1833 				(is_40nm ?
   1834 					MODIFY_XGXS13G_040_TX0_ACONTROL1r(unit, pc, data, mask) :
   1835 					MODIFY_XGXS16G_TX0_TX_DRIVERr(unit, pc, data, mask));
   1836 			break;
   1837 		case 1: 
   1838 			SOC_IF_ERROR_RETURN
   1839 				(is_40nm ?
   1840 					MODIFY_XGXS13G_040_TX1_ACONTROL1r(unit, pc, data, mask) :
   1841 					MODIFY_XGXS16G_TX1_TX_DRIVERr(unit, pc, data, mask));
   1842 			break;
   1843 		case 2: 
   1844 			SOC_IF_ERROR_RETURN
   1845 				(is_40nm ?
   1846 					MODIFY_XGXS13G_040_TX2_ACONTROL1r(unit, pc, data, mask) :
   1847 					MODIFY_XGXS16G_TX2_TX_DRIVERr(unit, pc, data, mask));
   1848 			break;
   1849 		case 3: 
   1850 			SOC_IF_ERROR_RETURN
   1851 				(is_40nm ?
   1852 					MODIFY_XGXS13G_040_TX3_ACONTROL1r(unit, pc, data, mask) :
   1853 					MODIFY_XGXS16G_TX3_TX_DRIVERr(unit, pc, data, mask));
   1854 			break;
   1855 		case TX_DRIVER_DFT_LN_CTRL: 
   1856 			SOC_IF_ERROR_RETURN
   1857 				(is_40nm ?
   1858 					MODIFY_XGXS13G_040_TX_ALL_ACONTROL1r(unit, pc, data, mask) :
   1859 					MODIFY_XGXS16G_TX_ALL_TX_DRIVERr(unit, pc, data, mask));
   1860 			break;
   1861 		default:
   1862 			break;
   1863 	}	
   1864 #if 0
   1865     int     lane_num;
   1866     if (lane_ctrl != TX_DRIVER_DFT_LN_CTRL) {
   1867         lane_num = lane_ctrl;
   1868         if (lane_num == 0) {
   1869             SOC_IF_ERROR_RETURN
   1870                 (MODIFY_XGXS16G_TX0_TX_DRIVERr(unit, pc, data, mask));
   1871         } else if (lane_num == 1) {
   1872             SOC_IF_ERROR_RETURN
   1873                 (MODIFY_XGXS16G_TX1_TX_DRIVERr(unit, pc, data, mask));
   1874         } else if (lane_num == 2) {
   1875             SOC_IF_ERROR_RETURN
   1876                 (MODIFY_XGXS16G_TX2_TX_DRIVERr(unit, pc, data, mask));
   1877         } else if (lane_num == 3) {
   1878             SOC_IF_ERROR_RETURN
   1879                 (MODIFY_XGXS16G_TX3_TX_DRIVERr(unit, pc, data, mask));
   1880         }
   1881     } else {
   1882         /* Update preemphasis/driver/pre-driver current */
   1883         SOC_IF_ERROR_RETURN
   1884             (MODIFY_XGXS16G_TX0_TX_DRIVERr(unit, pc, data, mask));
   1885         SOC_IF_ERROR_RETURN
   1886             (MODIFY_XGXS16G_TX1_TX_DRIVERr(unit, pc, data, mask));
   1887         SOC_IF_ERROR_RETURN
   1888             (MODIFY_XGXS16G_TX2_TX_DRIVERr(unit, pc, data, mask));
   1889         SOC_IF_ERROR_RETURN
   1890             (MODIFY_XGXS16G_TX3_TX_DRIVERr(unit, pc, data, mask));
   1891     }
   1892 #endif
   1893     return SOC_E_NONE;
   1894 }
   1895 
   1896 
   1897 STATIC int
   1898 _phy_xgxs16g_control_linkdown_transmit_set(int unit, soc_port_t port, 
   1899                                            uint32 value)
   1900 {
   1901     uint16      data;
   1902     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   1903 
   1904     if (value) {
   1905         data = (SERDESDIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_BITS <<
   1906                 SERDESDIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_SHIFT) |
   1907                (SERDESDIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_BITS <<
   1908                 SERDESDIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_SHIFT) |
   1909                (SERDESDIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_BITS <<
   1910                 SERDESDIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_SHIFT);
   1911         SOC_IF_ERROR_RETURN
   1912             (WRITE_XGXS16G_SERDESDIGITAL_CONTROL1000X2r(unit, pc, data));
   1913     } else {
   1914         data = (SERDESDIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_BITS <<
   1915                 SERDESDIGITAL_CONTROL1000X2_DISABLE_FALSE_LINK_SHIFT) |
   1916                (SERDESDIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_BITS <<
   1917                 SERDESDIGITAL_CONTROL1000X2_FILTER_FORCE_LINK_SHIFT) |
   1918                (SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_BITS <<
   1919                 SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_SHIFT);
   1920         SOC_IF_ERROR_RETURN
   1921             (WRITE_XGXS16G_SERDESDIGITAL_CONTROL1000X2r(unit, pc, data));
   1922     }
   1923     return SOC_E_NONE;
   1924 }
   1925 
   1926 STATIC int
   1927 _phy_xgxs16g_control_linkdown_transmit_get(int unit, soc_port_t port, 
   1928                                            uint32 *value)
   1929 {
   1930     uint16      data;
   1931     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   1932 
   1933     SOC_IF_ERROR_RETURN
   1934             (READ_XGXS16G_SERDESDIGITAL_CONTROL1000X2r(unit, pc, &data));
   1935 
   1936     *value = (data & 
   1937               (SERDESDIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_BITS <<
   1938                SERDESDIGITAL_CONTROL1000X2_FORCE_XMIT_DATA_ON_TXSIDE_SHIFT))
   1939              ? 1 : 0;
   1940 
   1941     return SOC_E_NONE;
   1942 }
   1943 
   1944 
   1945 
   1946 STATIC int
   1947 _phy_xgxs16g_control_prbs_polynomial_set(int unit, soc_port_t port, uint32 value)
   1948 {
   1949     uint16      data;
   1950     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   1951 
   1952     value &= 7;
   1953     data = 0x8888 | value 
   1954         |(value << PHY_XGXS16G_LANEPRBS_LANE_SHIFT)
   1955         |(value << (PHY_XGXS16G_LANEPRBS_LANE_SHIFT*2))
   1956         |(value << (PHY_XGXS16G_LANEPRBS_LANE_SHIFT*3));
   1957     
   1958       
   1959     /* 
   1960      * write back updated configuration 
   1961      */
   1962     SOC_IF_ERROR_RETURN
   1963           (WRITE_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, data));
   1964 
   1965     return SOC_E_NONE;
   1966 }
   1967 
   1968 STATIC int
   1969 _phy_xgxs16g_control_prbs_polynomial_get(int unit, soc_port_t port, uint32 *value)
   1970 {
   1971     uint16      data;
   1972     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);;
   1973 
   1974     SOC_IF_ERROR_RETURN
   1975         (READ_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, &data));
   1976 
   1977     /* Extract prbs polynomial setting from register */
   1978     data = ((data >> (XGXSBLK1_LANEPRBS_PRBS_ORDER1_SHIFT * pc->lane_num)) &
   1979             XGXSBLK1_LANEPRBS_PRBS_ORDER0_MASK);
   1980     *value = (uint32) data;
   1981 
   1982     return SOC_E_NONE;
   1983 }
   1984 
   1985 
   1986 STATIC int
   1987 _phy_xgxs16g_control_prbs_tx_invert_data_set(int unit, soc_port_t port, uint32 value)
   1988 {
   1989     uint16      data = 0;
   1990     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);		
   1991     uint32      lane_mask = 1 << (PHY_XGXS16G_LANEPRBS_LANE_SHIFT * pc->lane_num);
   1992 
   1993     SOC_IF_ERROR_RETURN
   1994         (READ_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, &data));
   1995     
   1996     /* prbs_inv is bit 2 per lane */
   1997     if (value) {
   1998         data |= lane_mask << XGXSBLK1_LANEPRBS_PRBS_INV0_SHIFT;
   1999     } else {
   2000         data &= ~(lane_mask << XGXSBLK1_LANEPRBS_PRBS_INV0_SHIFT);
   2001     }
   2002 
   2003     /* write back updated configuration */
   2004     if (value > 0x8000) {
   2005         SOC_IF_ERROR_RETURN
   2006 	    (WRITE_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, value));
   2007     } else {
   2008         SOC_IF_ERROR_RETURN
   2009 	    (WRITE_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, data));
   2010     } 
   2011 
   2012     return SOC_E_NONE;
   2013 
   2014 }
   2015 
   2016 STATIC int
   2017 _phy_xgxs16g_control_prbs_tx_invert_data_get(int unit, soc_port_t port, uint32 *value)
   2018 {
   2019     uint16      data;
   2020     uint16      inv_shifter = 0;
   2021     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   2022 
   2023     SOC_IF_ERROR_RETURN
   2024         (READ_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, &data));
   2025     
   2026    
   2027     inv_shifter = (XGXSBLK1_LANEPRBS_PRBS_ORDER1_SHIFT * pc->lane_num) + 
   2028                  XGXSBLK1_LANEPRBS_PRBS_INV0_SHIFT;
   2029     data &= (1 << inv_shifter);
   2030  
   2031     *value = (data) ?  1 : 0;
   2032     
   2033     return SOC_E_NONE;
   2034 }
   2035 
   2036 
   2037 STATIC int
   2038 _phy_xgxs16g_control_xgxs_prbs_tx_enable_set(int unit, soc_port_t port, 
   2039                                           uint32 value)
   2040 {
   2041     uint16      data = 0;
   2042     uint16      pll_mode = 0;
   2043     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   2044 
   2045     if (value) {
   2046 
   2047         /* First set XAUI mode: 0x8000 = 0x203f */
   2048         SOC_IF_ERROR_RETURN
   2049             (WRITE_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x203f));
   2050         
   2051         sal_usleep(1000);
   2052         
   2053         /* Set double wide div/1: 0x8016=0xffff */
   2054         SOC_IF_ERROR_RETURN
   2055             (WRITE_XGXS16G_XGXSBLK1_LANECTRL1r(unit, pc, 0xffff));
   2056         
   2057         /* clear multiPRT mode: 0x800d=0x0003 */
   2058         /*SOC_IF_ERROR_RETURN
   2059             (WRITE_XGXS16G_XGXSBLK0_MMDSELECTr(unit, pc, 0x4003));
   2060 	*/
   2061 
   2062         /* Set in individual lane mode, Disable PLL Sequencer: 0x8000=0x063f */
   2063         SOC_IF_ERROR_RETURN
   2064             (WRITE_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x063f));
   2065         
   2066         /* Force VCO based on current operating frequency */
   2067         SOC_IF_ERROR_RETURN 
   2068             (READ_XGXS16G_PLL_PLLSTATUSr(unit, pc, &pll_mode)); 
   2069         pll_mode &= 
   2070             (PLL_PLLSTATUS_PLL_MODE_AFE_MASK | PLL_PLLSTATUS_RESERVED0_MASK); 
   2071         SOC_IF_ERROR_RETURN 
   2072             (READ_XGXS16G_SERDESDIGITAL_MISC1r(unit, pc, &data)); 
   2073         data &= ~SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_MASK; 
   2074         data |= SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SEL_MASK | 
   2075             (pll_mode << SERDESDIGITAL_MISC1_FORCE_PLL_MODE_AFE_SHIFT); 
   2076         SOC_IF_ERROR_RETURN 
   2077             (WRITE_XGXS16G_SERDESDIGITAL_MISC1r(unit, pc, data)); 
   2078 
   2079         /* Disable asymmetric mode for 40nm UC_B0 */
   2080         if(XGXS16G_13G_REV_B0(pc)){
   2081         SOC_IF_ERROR_RETURN
   2082             (MODIFY_XGXS16G_XGXSBLK8_TXLNSWAP1r(unit, pc, 0,
   2083                      XGXSBLK8_TXLNSWAP1_ASYMM_EN_MASK));        
   2084         }
   2085         /* Turn AN off: 0x0=0x0 */
   2086         SOC_IF_ERROR_RETURN
   2087             (WRITE_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, 0));
   2088         
   2089         /* Turn CL36 PCS off: 0x8015=0x0 */
   2090         SOC_IF_ERROR_RETURN
   2091             (WRITE_XGXS16G_XGXSBLK1_LANECTRL0r(unit, pc, 0));
   2092         
   2093         /* Put port in loopback if requested */
   2094         data = ((value & 0x8000) == 0x8000) ? 
   2095                XGXSBLK1_LANECTRL2_GLOOP1G_MASK : 0;
   2096         /* CDED & EDEN off: 0x8017 */
   2097         SOC_IF_ERROR_RETURN
   2098             (WRITE_XGXS16G_XGXSBLK1_LANECTRL2r(unit, pc, data));
   2099  
   2100         /* PRBS Polynomial for all lanes: 0x8019=0x8888 */
   2101         SOC_IF_ERROR_RETURN
   2102            (READ_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, &data));
   2103         data |= 0x8888;
   2104         SOC_IF_ERROR_RETURN
   2105             (WRITE_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, data));
   2106         
   2107  
   2108         /* Enable PRBS read: 0x80f1=0x1c47 */ 
   2109         SOC_IF_ERROR_RETURN
   2110             (WRITE_XGXS16G_RX_ALL_RX_CONTROLr(unit, pc, 0x1c47));
   2111         
   2112         /* Enable PLL Sequencer: 0x8000=0x263f */
   2113         SOC_IF_ERROR_RETURN
   2114             (WRITE_XGXS16G_XGXSBLK0_XGXSCONTROLr(unit, pc, 0x263f));
   2115         
   2116         /* Delay a while */
   2117         sal_usleep(250000);
   2118     } else {
   2119         /* Restore port */
   2120         return phy_xgxs16g_init(unit, port);
   2121     }
   2122     return SOC_E_NONE;
   2123 }
   2124 
   2125 STATIC int
   2126 _phy_xgxs16g_control_prbs_tx_enable_set(int unit, soc_port_t port, uint32 value)
   2127 {
   2128 
   2129     SOC_IF_ERROR_RETURN(
   2130 			_phy_xgxs16g_control_xgxs_prbs_tx_enable_set(unit, port, value));
   2131     return SOC_E_NONE;
   2132 }
   2133 
   2134 
   2135 STATIC int
   2136 _phy_xgxs16g_control_prbs_tx_rx_enable_get(int unit, soc_port_t port, 
   2137                                         uint32 *value)
   2138 {
   2139     uint16      data;
   2140     uint16       inv_shifter = 0;
   2141     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   2142 
   2143     /*
   2144      * Hypercore PRBS - note that in the Hypercore there is only 1 enable 
   2145      * for both TX/RX 
   2146      */
   2147     SOC_IF_ERROR_RETURN
   2148         (READ_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, &data));
   2149 
   2150     inv_shifter = (XGXSBLK1_LANEPRBS_PRBS_ORDER1_SHIFT * pc->lane_num) +
   2151                 XGXSBLK1_LANEPRBS_PRBS_EN0_SHIFT;
   2152     data &= (1 << inv_shifter);
   2153  
   2154     *value = (data) ?  1 : 0;
   2155   
   2156     return SOC_E_NONE;
   2157 }
   2158 
   2159 STATIC int
   2160 _phy_xgxs16g_control_prbs_tx_enable_get(int unit, soc_port_t port, uint32 *value)
   2161 {
   2162     return _phy_xgxs16g_control_prbs_tx_rx_enable_get(unit, port, value);
   2163 }
   2164 
   2165 STATIC int
   2166 _phy_xgxs16g_control_prbs_rx_enable_set(int unit, soc_port_t port, uint32 value)
   2167 {
   2168     uint16      data;
   2169     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   2170     uint32      lane_mask = 1 << (PHY_XGXS16G_LANEPRBS_LANE_SHIFT * pc->lane_num);
   2171 
   2172     SOC_IF_ERROR_RETURN
   2173         (READ_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, &data));
   2174 
   2175     if (value) {
   2176         data |= lane_mask <<  XGXSBLK1_LANEPRBS_PRBS_EN0_SHIFT;
   2177     }  else {
   2178         data &= ~(lane_mask << XGXSBLK1_LANEPRBS_PRBS_EN0_SHIFT);
   2179     }
   2180     
   2181     /* write back updated configuration */
   2182     SOC_IF_ERROR_RETURN
   2183         (WRITE_XGXS16G_XGXSBLK1_LANEPRBSr(unit, pc, data));
   2184     
   2185     /* Set up status collection */
   2186     /* uPrbsRxControlReg = 0x80b1;
   2187      * uPrbsRxControlReg += uLaneAddr * 0x10;
   2188      */
   2189     SOC_IF_ERROR_RETURN
   2190         (XGXS16G_REG_READ(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), &data));
   2191     
   2192     data &= ~RX0_RX_CONTROL_STATUS_SEL_MASK;
   2193     if (value) {
   2194         data |= RX0_RX_CONTROL_STATUS_SEL_prbsStatus;
   2195     } else {
   2196         data &= ~RX0_RX_CONTROL_STATUS_SEL_prbsStatus;
   2197     }
   2198     
   2199     SOC_IF_ERROR_RETURN
   2200         (XGXS16G_REG_WRITE(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), data));
   2201 
   2202     return SOC_E_NONE;
   2203 }
   2204 
   2205 STATIC int
   2206 _phy_xgxs16g_control_prbs_rx_enable_get(int unit, soc_port_t port, uint32 *value)
   2207 {
   2208     return _phy_xgxs16g_control_prbs_tx_rx_enable_get(unit, port, value);
   2209 }
   2210 
   2211 /*
   2212  * Returns value 
   2213  *      ==  0: PRBS receive is in sync
   2214  *      == -1: PRBS receive never got into sync
   2215  *      ==  n: number of errors
   2216  */
   2217 STATIC int
   2218 _phy_xgxs16g_control_xgxs_prbs_rx_status_get(int unit, soc_port_t port, 
   2219                                           uint32 *value)
   2220 {
   2221     int         lane;
   2222     uint16      data;
   2223     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);;
   2224 
   2225     
   2226     /* Get status for all 4 lanes and check for sync
   2227      * 0x80b0, 0x80c0, 0x80d0, 0x80e0 
   2228      */
   2229     *value = 0;
   2230     for (lane = 0; lane < 4; lane++) {
   2231         SOC_IF_ERROR_RETURN
   2232             (XGXS16G_REG_READ(unit, pc, 0x0, 0x80b0 + (0x10 * lane), &data));
   2233         if (data == (RX0_RX_STATUS_PRBS_STATUS_PRBS_LOCK_BITS  <<
   2234                      RX0_RX_STATUS_PRBS_STATUS_PRBS_LOCK_SHIFT)) {
   2235             /* PRBS is in sync */
   2236             continue;
   2237         } else if (data == 0) {
   2238             /* PRBS not in sync */
   2239             *value = -1;            
   2240 	    break;
   2241         } else {
   2242             /* Get errors */
   2243             *value += data & RX0_RX_STATUS_PRBS_STATUS_PTBS_ERRORS_MASK;
   2244         }
   2245     }
   2246     return SOC_E_NONE;
   2247 }
   2248 
   2249 
   2250 STATIC int
   2251 _phy_xgxs16g_control_prbs_rx_status_get(int unit, soc_port_t port, uint32 *value)
   2252 {
   2253     int         rv;
   2254     uint16      rx_sts, saved_rx_sts;
   2255     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   2256 
   2257     /* Set up prbs rx status collection */
   2258     SOC_IF_ERROR_RETURN
   2259         (XGXS16G_REG_READ(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), &rx_sts));
   2260     saved_rx_sts = rx_sts;
   2261     rx_sts = (rx_sts & ~RX0_RX_CONTROL_STATUS_SEL_MASK) |
   2262              RX0_RX_CONTROL_STATUS_SEL_prbsStatus;
   2263     SOC_IF_ERROR_RETURN
   2264         (XGXS16G_REG_WRITE(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), rx_sts));
   2265 
   2266     rv = _phy_xgxs16g_control_xgxs_prbs_rx_status_get(unit, port, value);
   2267 
   2268 
   2269     /* Restore rx status */
   2270     SOC_IF_ERROR_RETURN
   2271         (XGXS16G_REG_WRITE(unit,pc,0x0,0x80B1 + (0x10 * pc->lane_num), saved_rx_sts));
   2272 
   2273     return rv;
   2274 }
   2275 
   2276 
   2277 
   2278 /*
   2279  * Function:
   2280  *      phy_xgxs16g_control_set
   2281  * Purpose:
   2282  *      Configure PHY device specific control fucntion. 
   2283  * Parameters:
   2284  *      unit  - StrataSwitch unit #.
   2285  *      port  - StrataSwitch port #. 
   2286  *      type  - Control to update 
   2287  *      value - New setting for the control 
   2288  * Returns:     
   2289  *      SOC_E_NONE
   2290  */
   2291 STATIC int
   2292 phy_xgxs16g_control_set(int unit, soc_port_t port,
   2293                      soc_phy_control_t type, uint32 value)
   2294 {
   2295     int rv;
   2296     phy_ctrl_t *pc;
   2297     /* coverity[mixed_enums] */
   2298     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
   2299         return SOC_E_PARAM;
   2300     }
   2301 
   2302    
   2303     pc = INT_PHY_SW_STATE(unit, port);
   2304     rv = SOC_E_UNAVAIL;
   2305     switch(type) {
   2306     case SOC_PHY_CONTROL_PREEMPHASIS_LANE0:
   2307         /* fall through */
   2308     case SOC_PHY_CONTROL_PREEMPHASIS_LANE1:
   2309         /* fall through */
   2310     case SOC_PHY_CONTROL_PREEMPHASIS_LANE2:
   2311         /* fall through */
   2312     case SOC_PHY_CONTROL_PREEMPHASIS_LANE3:
   2313         /* fall through */
   2314     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0:
   2315         /* fall through */
   2316     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1:
   2317         /* fall through */
   2318     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2:
   2319         /* fall through */
   2320     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3:
   2321         /* fall through */
   2322     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0:
   2323         /* fall through */
   2324     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1:
   2325         /* fall through */
   2326     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2:
   2327         /* fall through */
   2328     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3:
   2329         /* fall through */
   2330     case SOC_PHY_CONTROL_PREEMPHASIS:
   2331         /* fall through */
   2332     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   2333         /* fall through */
   2334     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   2335         rv = _phy_xgxs16g_control_tx_driver_set(unit, pc, type, value);
   2336         break;
   2337     case SOC_PHY_CONTROL_EQUALIZER_BOOST:
   2338         rv = MODIFY_XGXS16G_RX_ALL_RX_ANALOGBIAS0r(unit, pc, value,
   2339                                   RX_ALL_RX_EQ_BOOST_EQUALIZER_CONTROL_MASK);
   2340         break;
   2341     case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT:
   2342         rv = _phy_xgxs16g_control_linkdown_transmit_set(unit, port, value);
   2343         break;
   2344     case SOC_PHY_CONTROL_PRBS_POLYNOMIAL:
   2345         rv = _phy_xgxs16g_control_prbs_polynomial_set(unit, port, value);
   2346         break;
   2347     case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA:
   2348         rv = _phy_xgxs16g_control_prbs_tx_invert_data_set(unit, port, value);
   2349         break;
   2350     case SOC_PHY_CONTROL_PRBS_TX_ENABLE:
   2351         rv = _phy_xgxs16g_control_prbs_tx_enable_set(unit, port, value);
   2352         break;
   2353     case SOC_PHY_CONTROL_PRBS_RX_ENABLE:
   2354         rv = _phy_xgxs16g_control_prbs_rx_enable_set(unit, port, value);
   2355         break;
   2356 
   2357     case SOC_PHY_CONTROL_PARALLEL_DETECTION:
   2358         /* enable 1000X parallel detect */
   2359         SOC_IF_ERROR_RETURN
   2360             (MODIFY_XGXS16G_SERDESDIGITAL_CONTROL1000X2r(unit, pc,
   2361             value? SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK:0,              SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK));
   2362         rv = SOC_E_NONE;
   2363         break;
   2364 
   2365     default:
   2366         rv = (SOC_E_UNAVAIL);
   2367         break;
   2368     }
   2369     return rv;
   2370 }
   2371 
   2372 STATIC int
   2373 _phy_xgxs16g_control_tx_driver_get(int unit, phy_ctrl_t *pc,
   2374                                 soc_phy_control_t type, uint32 *value)
   2375 {
   2376     uint16  data16;           /* Temporary holder of 16 bit reg value */
   2377     uint16  mask;
   2378     int     shifter;
   2379     int 	lane_ctrl;
   2380 	int 	is_40nm;
   2381 
   2382     SOC_IF_ERROR_RETURN
   2383         (_phy_xgxs16g_tx_driver_field_get(pc, type,&lane_ctrl,&mask,&shifter));
   2384 		
   2385 	is_40nm = XGXS16G_13G_ID(pc);
   2386 
   2387     /* Read preemphasis/driver/pre-driver current */
   2388 	switch (lane_ctrl) {
   2389 		case 0:
   2390 			SOC_IF_ERROR_RETURN
   2391 				(is_40nm ?
   2392 					READ_XGXS13G_040_TX0_ACONTROL1r(unit, pc, &data16) :
   2393 					READ_XGXS16G_TX0_TX_DRIVERr(unit, pc, &data16));
   2394 			break;
   2395 		case 1:
   2396 			SOC_IF_ERROR_RETURN
   2397 				(is_40nm ?
   2398 					READ_XGXS13G_040_TX1_ACONTROL1r(unit, pc, &data16) :
   2399 					READ_XGXS16G_TX1_TX_DRIVERr(unit, pc, &data16));
   2400 			break;
   2401 		case 2:
   2402 			SOC_IF_ERROR_RETURN
   2403 				(is_40nm ?
   2404 					READ_XGXS13G_040_TX2_ACONTROL1r(unit, pc, &data16) :
   2405 					READ_XGXS16G_TX2_TX_DRIVERr(unit, pc, &data16));
   2406 			break;
   2407 		case 3:
   2408 			SOC_IF_ERROR_RETURN
   2409 				(is_40nm ?
   2410 					READ_XGXS13G_040_TX3_ACONTROL1r(unit, pc, &data16) :
   2411 					READ_XGXS16G_TX3_TX_DRIVERr(unit, pc, &data16));
   2412 			break;
   2413 		case TX_DRIVER_DFT_LN_CTRL:
   2414 			SOC_IF_ERROR_RETURN
   2415 				(is_40nm ?
   2416 					READ_XGXS13G_040_TX_ALL_ACONTROL1r(unit, pc, &data16) :
   2417 					READ_XGXS16G_TX_ALL_TX_DRIVERr(unit, pc, &data16));
   2418 			break;
   2419 		default:
   2420 			return SOC_E_NONE;
   2421 	}	
   2422 
   2423     *value = (data16 & mask) >> shifter;
   2424 
   2425     return (SOC_E_NONE);
   2426 }
   2427 
   2428 /* Make use of the SERDESDIGITAL_PATGENCTRL.PKT_SIZE[0] as a scratch pad for VCO status */
   2429 STATIC int
   2430 _phy_xgxs16g_control_vco_disturbed_get(int unit, soc_port_t port, uint32 *value)
   2431 {
   2432     uint16 data;
   2433     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   2434     if(!pc) {
   2435         return SOC_E_NONE;
   2436     }
   2437     SOC_IF_ERROR_RETURN(READ_XGXS16G_SERDESDIGITAL_PATGENCTRLr(unit, pc, &data));
   2438     SOC_IF_ERROR_RETURN(MODIFY_XGXS16G_SERDESDIGITAL_PATGENCTRLr(unit, pc, 0,  SERDESDIGITAL_PATGENCTRL_PKT_SIZE_MASK));
   2439 
   2440     *value = (data & SERDESDIGITAL_PATGENCTRL_PKT_SIZE_MASK) ? 1 : 0;
   2441 
   2442     return SOC_E_NONE;
   2443 }
   2444 
   2445 STATIC int
   2446 _phy_xgxs16g_control_vco_disturbed_set(int unit, soc_port_t port)
   2447 {
   2448     uint16 data, mask;
   2449     phy_ctrl_t *pc = INT_PHY_SW_STATE(unit, port);
   2450     if(!pc) {
   2451         return SOC_E_NONE;
   2452     }
   2453     data = 1 << SERDESDIGITAL_PATGENCTRL_PKT_SIZE_SHIFT;
   2454     mask = SERDESDIGITAL_PATGENCTRL_PKT_SIZE_MASK;
   2455 
   2456     SOC_IF_ERROR_RETURN(MODIFY_XGXS16G_SERDESDIGITAL_PATGENCTRLr(unit, pc, data, mask));
   2457 
   2458     return SOC_E_NONE;
   2459 }
   2460 
   2461 /*
   2462  * Function:
   2463  *      phy_xgxs16g_control_get
   2464  * Purpose:
   2465  *      Get current control settign of the PHY. 
   2466  * Parameters:
   2467  *      unit  - StrataSwitch unit #.
   2468  *      port  - StrataSwitch port #. 
   2469  *      type  - Control to update 
   2470  *      value - (OUT)Current setting for the control 
   2471  * Returns:     
   2472  *      SOC_E_NONE
   2473  */
   2474 STATIC int
   2475 phy_xgxs16g_control_get(int unit, soc_port_t port,
   2476                      soc_phy_control_t type, uint32 *value)
   2477 {
   2478     int rv;
   2479     phy_ctrl_t *pc;
   2480     uint16 data16;
   2481     /* coverity[mixed_enums] */
   2482     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
   2483         return (SOC_E_PARAM);
   2484     }
   2485 
   2486     pc = INT_PHY_SW_STATE(unit, port);
   2487     rv = SOC_E_UNAVAIL;
   2488     switch(type) {
   2489     case SOC_PHY_CONTROL_PREEMPHASIS_LANE0:
   2490         /* fall through */
   2491     case SOC_PHY_CONTROL_PREEMPHASIS_LANE1:
   2492         /* fall through */
   2493     case SOC_PHY_CONTROL_PREEMPHASIS_LANE2:
   2494         /* fall through */
   2495     case SOC_PHY_CONTROL_PREEMPHASIS_LANE3:
   2496         /* fall through */
   2497     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0:
   2498         /* fall through */
   2499     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1:
   2500         /* fall through */
   2501     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2:
   2502         /* fall through */
   2503     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3:
   2504         /* fall through */
   2505     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0:
   2506         /* fall through */
   2507     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1:
   2508         /* fall through */
   2509     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2:
   2510         /* fall through */
   2511     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3:
   2512         /* fall through */
   2513     case SOC_PHY_CONTROL_PREEMPHASIS:
   2514         /* fall through */
   2515     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   2516         /* fall through */
   2517     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   2518         rv = _phy_xgxs16g_control_tx_driver_get(unit, pc, type, value);
   2519         break;
   2520     case SOC_PHY_CONTROL_PRBS_POLYNOMIAL:
   2521         rv = _phy_xgxs16g_control_prbs_polynomial_get(unit, port, value);
   2522         break;
   2523     case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA:
   2524         rv = _phy_xgxs16g_control_prbs_tx_invert_data_get(unit, port, value);
   2525         break;
   2526     case SOC_PHY_CONTROL_PRBS_TX_ENABLE:
   2527         rv = _phy_xgxs16g_control_prbs_tx_enable_get(unit, port, value);
   2528         break;
   2529     case SOC_PHY_CONTROL_PRBS_RX_ENABLE:
   2530         rv = _phy_xgxs16g_control_prbs_rx_enable_get(unit, port, value);
   2531         break;
   2532     case SOC_PHY_CONTROL_PRBS_RX_STATUS:
   2533         rv = _phy_xgxs16g_control_prbs_rx_status_get(unit, port, value);
   2534         break;
   2535 
   2536     case SOC_PHY_CONTROL_EQUALIZER_BOOST:
   2537         SOC_IF_ERROR_RETURN
   2538             (READ_XGXS16G_RX_ALL_RX_ANALOGBIAS0r(unit, pc, &data16));
   2539         *value = data16 & RX_ALL_RX_EQ_BOOST_EQUALIZER_CONTROL_MASK;
   2540         rv = SOC_E_NONE;
   2541         break;
   2542    case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT:
   2543         rv = _phy_xgxs16g_control_linkdown_transmit_get(unit, port, value);
   2544         break;
   2545     case SOC_PHY_CONTROL_PARALLEL_DETECTION:
   2546         SOC_IF_ERROR_RETURN
   2547             (READ_XGXS16G_SERDESDIGITAL_CONTROL1000X2r(unit, pc,&data16));
   2548         *value =
   2549            data16 & SERDESDIGITAL_CONTROL1000X2_ENABLE_PARALLEL_DETECTION_MASK?
   2550              TRUE: FALSE;
   2551         rv = SOC_E_NONE;
   2552         break;
   2553     case SOC_PHY_CONTROL_VCO_DISTURBED:
   2554          rv = _phy_xgxs16g_control_vco_disturbed_get(unit, port, value);
   2555          break;
   2556     default:
   2557         rv = (SOC_E_UNAVAIL);
   2558         break;
   2559     }
   2560     return rv;
   2561 }
   2562 
   2563 /*
   2564  * Function:
   2565  *      phy_xgxs16g_reg_read
   2566  * Purpose:
   2567  *      Routine to read PHY register
   2568  * Parameters:
   2569  *      uint         - BCM unit number
   2570  *      pc           - PHY state
   2571  *      flags        - Flags which specify the register type
   2572  *      phy_reg_addr - Encoded register address
   2573  *      phy_data     - (OUT) Value read from PHY register
   2574  * Note:
   2575  *      This register read function is not thread safe. Higher level
   2576  * function that calls this function must obtain a per port lock
   2577  * to avoid overriding register page mapping between threads.
   2578  */
   2579 STATIC int
   2580 phy_xgxs16g_reg_read(int unit, soc_port_t port, uint32 flags,
   2581                   uint32 phy_reg_addr, uint32 *phy_data)
   2582 {
   2583     uint16               data;     /* Temporary holder for phy_data */
   2584     phy_ctrl_t          *pc;      /* PHY software state */
   2585 
   2586     pc = INT_PHY_SW_STATE(unit, port);
   2587 
   2588     SOC_IF_ERROR_RETURN
   2589         (phy_reg_aer_read(unit, pc, phy_reg_addr, &data));
   2590 
   2591    *phy_data = data;
   2592 
   2593     return (SOC_E_NONE);
   2594 }
   2595 
   2596 /*
   2597  * Function:
   2598  *      phy_xgxs16g_reg_write
   2599  * Purpose:
   2600  *      Routine to write PHY register
   2601  * Parameters:
   2602  *      uint         - BCM unit number
   2603  *      pc           - PHY state
   2604  *      flags        - Flags which specify the register type
   2605  *      phy_reg_addr - Encoded register address
   2606  *      phy_data     - Value write to PHY register
   2607  * Note:
   2608  *      This register read function is not thread safe. Higher level
   2609  * function that calls this function must obtain a per port lock
   2610  * to avoid overriding register page mapping between threads.
   2611  */
   2612 STATIC int
   2613 phy_xgxs16g_reg_write(int unit, soc_port_t port, uint32 flags,
   2614                    uint32 phy_reg_addr, uint32 phy_data)
   2615 {
   2616     uint16               data;     /* Temporary holder for phy_data */
   2617     phy_ctrl_t          *pc;      /* PHY software state */
   2618 
   2619     pc = INT_PHY_SW_STATE(unit, port);
   2620 
   2621     data      = (uint16) (phy_data & 0x0000FFFF);
   2622 
   2623     SOC_IF_ERROR_RETURN
   2624         (phy_reg_aer_write(unit, pc, phy_reg_addr, data));
   2625 
   2626     return (SOC_E_NONE);
   2627 }  
   2628 
   2629 /*
   2630  * Function:
   2631  *      phy_xgxs16g_reg_modify
   2632  * Purpose:
   2633  *      Routine to write PHY register
   2634  * Parameters:
   2635  *      uint         - BCM unit number
   2636  *      pc           - PHY state
   2637  *      flags        - Flags which specify the register type
   2638  *      phy_reg_addr - Encoded register address
   2639  *      phy_mo_data  - New value for the bits specified in phy_mo_mask
   2640  *      phy_mo_mask  - Bit mask to modify
   2641  * Note:
   2642  *      This register read function is not thread safe. Higher level
   2643  * function that calls this function must obtain a per port lock
   2644  * to avoid overriding register page mapping between threads.
   2645  */
   2646 STATIC int
   2647 phy_xgxs16g_reg_modify(int unit, soc_port_t port, uint32 flags,
   2648                     uint32 phy_reg_addr, uint32 phy_data,
   2649                     uint32 phy_data_mask)
   2650 {
   2651     uint16               data;     /* Temporary holder for phy_data */
   2652     uint16               mask;
   2653     phy_ctrl_t    *pc;      /* PHY software state */
   2654 
   2655     pc = INT_PHY_SW_STATE(unit, port);
   2656 
   2657     data      = (uint16) (phy_data & 0x0000FFFF);
   2658     mask      = (uint16) (phy_data_mask & 0x0000FFFF);
   2659 
   2660     SOC_IF_ERROR_RETURN
   2661         (phy_reg_aer_modify(unit, pc, phy_reg_addr, data, mask));
   2662 
   2663     return (SOC_E_NONE);
   2664 }
   2665 
   2666 STATIC int
   2667 phy_xgxs16g_probe(int unit, phy_ctrl_t *pc)
   2668 {
   2669     uint16      serdes_id0;
   2670     uint16      serdes_id2;
   2671     soc_info_t *si;
   2672     int phy_port;  /* physical port number */
   2673 
   2674     si = &SOC_INFO(unit);
   2675     if (soc_feature(unit, soc_feature_logical_port_num)) {
   2676         phy_port = si->port_l2p_mapping[pc->port];
   2677     } else {
   2678         phy_port = pc->port;
   2679     }
   2680 
   2681     SOC_IF_ERROR_RETURN
   2682         (READ_XGXS16G_SERDESID_SERDESID0r(unit, pc, &serdes_id0));
   2683     SOC_IF_ERROR_RETURN
   2684         (READ_XGXS16G_SERDESID_SERDESID2r(unit, pc, &serdes_id2));
   2685 
   2686     if ((serdes_id0 & SERDESID_SERDESID0_MODEL_NUMBER_MASK) !=
   2687         SERDES_ID0_MODEL_NUMBER_XGXS_16G) {
   2688         return SOC_E_NOT_FOUND;
   2689     }
   2690 
   2691     if (serdes_id2 & SERDESID_SERDESID2_DR_16G_4L_MASK) {
   2692         /* XGXS16G */
   2693         pc->size = sizeof(XGXS16G_DEV_DESC);
   2694         return SOC_E_NONE;
   2695     }
   2696 
   2697     if (serdes_id2 & SERDESID_SERDESID2_DR_13G_4L_MASK) {
   2698         /* XGXS13G new 40nm serdes */
   2699         pc->lane_num = SOC_PORT_BINDEX(unit, phy_port);
   2700         pc->chip_num = SOC_BLOCK_NUMBER(unit, SOC_PORT_BLOCK(unit, phy_port));
   2701         if (pc->lane_num) {
   2702             LOG_WARN(BSL_LS_SOC_PHY,
   2703                      (BSL_META_U(unit,
   2704                                  "_phy_xgxs16g_probe u=%d p=%d: wrong lane# 0x%x, set to 0\n"),
   2705                       unit, pc->port, pc->lane_num));
   2706             pc->lane_num = 0;
   2707         }
   2708     
   2709         pc->dev_name = "XGXS13G";
   2710         
   2711         pc->size = sizeof(XGXS16G_DEV_DESC);
   2712         return SOC_E_NONE;
   2713     }
   2714     return SOC_E_NOT_FOUND;
   2715 }
   2716 
   2717 STATIC int
   2718 phy_xgxs16g_notify(int unit, soc_port_t port,
   2719                        soc_phy_event_t event, uint32 value)
   2720 {
   2721     int             rv;
   2722 
   2723     if (event >= phyEventCount) {
   2724         return SOC_E_PARAM;
   2725     }
   2726 
   2727     rv = SOC_E_NONE;
   2728     switch(event) {
   2729     case phyEventInterface:
   2730         rv = (_phy_xgxs16g_notify_interface(unit, port, value));
   2731         break;
   2732     case phyEventDuplex:
   2733         rv = (_phy_xgxs16g_notify_duplex(unit, port, value));
   2734         break;
   2735     case phyEventSpeed:
   2736         rv = (_phy_xgxs16g_notify_speed(unit, port, value));
   2737         break;
   2738     case phyEventStop:
   2739         rv = (_phy_xgxs16g_notify_stop(unit, port, value));
   2740         break;
   2741     case phyEventResume:
   2742         rv = (_phy_xgxs16g_notify_resume(unit, port, value));
   2743         break;
   2744     case phyEventAutoneg:
   2745         rv = (phy_xgxs16g_an_set(unit, port, value));
   2746         break;
   2747     case phyEventMacLoopback:
   2748         rv = (_phy_xgxs16g_notify_mac_loopback(unit, port, value));
   2749         break;
   2750     default:
   2751         rv = SOC_E_UNAVAIL;
   2752         break;
   2753     }
   2754 
   2755     return rv;
   2756 }
   2757 
   2758 STATIC int
   2759 phy_xgxs16g_duplex_get(int unit, soc_port_t port, int *duplex)
   2760 {
   2761     uint16       reg0_16;
   2762     uint16       mii_ctrl;
   2763     phy_ctrl_t  *pc;
   2764 
   2765     pc = INT_PHY_SW_STATE(unit, port);
   2766 
   2767     *duplex = TRUE;
   2768 
   2769     SOC_IF_ERROR_RETURN
   2770         (READ_XGXS16G_GP_STATUS_STATUS1000X1r(unit, pc, &reg0_16));
   2771 
   2772     if (reg0_16 & GP_STATUS_STATUS1000X1_SGMII_MODE_MASK) {
   2773 
   2774     /* retrieve the duplex setting in SGMII mode */
   2775         SOC_IF_ERROR_RETURN
   2776             (READ_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, &mii_ctrl));
   2777 
   2778         if (mii_ctrl & MII_CTRL_AE) {
   2779             SOC_IF_ERROR_RETURN
   2780                 (READ_XGXS16G_COMBO_IEEE0_AUTONEGLPABILr(unit,pc,&reg0_16));
   2781 
   2782             /* make sure link partner is also in SGMII mode
   2783              * otherwise fall through to use the FD bit in MII_CTRL reg
   2784              */
   2785             if (reg0_16 & MII_ANP_SGMII_MODE) {
   2786                 if (reg0_16 & MII_ANP_SGMII_FD) {
   2787                     *duplex = TRUE;
   2788                 } else {
   2789                     *duplex = FALSE;
   2790                 }
   2791                 return SOC_E_NONE;
   2792             }
   2793         }
   2794         *duplex = (mii_ctrl & MII_CTRL_FD) ? TRUE : FALSE;
   2795     }
   2796     return SOC_E_NONE;
   2797 }
   2798 
   2799 /*
   2800  * Variable:
   2801  *      phy_xgxs16g_drv
   2802  * Purpose:
   2803  *      Phy Driver for 10G (XAUI x 4) Serdes PHY. 
   2804  */
   2805 
   2806 phy_driver_t phy_xgxs16g_hg = {
   2807     /* .drv_name                      = */ "XGXS16G Unicore PHY Driver",
   2808     /* .pd_init                       = */ phy_xgxs16g_init,
   2809     /* .pd_reset                      = */ phy_null_reset,
   2810     /* .pd_link_get                   = */ phy_xgxs16g_link_get,
   2811     /* .pd_enable_set                 = */ phy_xgxs16g_enable_set,
   2812     /* .pd_enable_get                 = */ phy_null_enable_get,
   2813     /* .pd_duplex_set                 = */ phy_null_set,
   2814     /* .pd_duplex_get                 = */ phy_xgxs16g_duplex_get,
   2815     /* .pd_speed_set                  = */ phy_xgxs16g_speed_set,
   2816     /* .pd_speed_get                  = */ phy_xgxs16g_speed_get,
   2817     /* .pd_master_set                 = */ phy_null_set,
   2818     /* .pd_master_get                 = */ phy_xgxs16g_master_get,
   2819     /* .pd_an_set                     = */ phy_xgxs16g_an_set,
   2820     /* .pd_an_get                     = */ phy_xgxs16g_an_get,
   2821     /* .pd_adv_local_set              = */ NULL, /* Deprecated */
   2822     /* .pd_adv_local_get              = */ NULL, /* Deprecated */
   2823     /* .pd_adv_remote_get             = */ NULL, /* Deprecated */ 
   2824     /* .pd_lb_set                     = */ phy_xgxs16g_lb_set,
   2825     /* .pd_lb_get                     = */ phy_xgxs16g_lb_get,
   2826     /* .pd_interface_set              = */ phy_null_interface_set,
   2827     /* .pd_interface_get              = */ phy_xgxs16g_interface_get,
   2828     /* .pd_ability                    = */ NULL, /* Deprecated */ 
   2829     /* .pd_linkup_evt                 = */ NULL,
   2830     /* .pd_linkdn_evt                 = */ NULL,
   2831     /* .pd_mdix_set                   = */ phy_null_mdix_set,
   2832     /* .pd_mdix_get                   = */ phy_null_mdix_get,
   2833     /* .pd_mdix_status_get            = */ phy_null_mdix_status_get,
   2834     /* .pd_medium_config_set          = */ NULL,
   2835     /* .pd_medium_config_get          = */ NULL,
   2836     /* .pd_medium_get                 = */ phy_null_medium_get,
   2837     /* .pd_cable_diag                 = */ NULL,
   2838     /* .pd_link_change                = */ NULL,
   2839     /* .pd_control_set                = */ phy_xgxs16g_control_set,
   2840     /* .pd_control_get                = */ phy_xgxs16g_control_get,
   2841     /* .pd_reg_read                   = */ phy_xgxs16g_reg_read,
   2842     /* .pd_reg_write                  = */ phy_xgxs16g_reg_write,
   2843     /* .pd_reg_modify                 = */ phy_xgxs16g_reg_modify,
   2844     /* .pd_notify                     = */ phy_xgxs16g_notify,
   2845     /* .pd_probe                      = */ phy_xgxs16g_probe,
   2846     /* .pd_ability_advert_set         = */ phy_xgxs16g_ability_advert_set, 
   2847     /* .pd_ability_advert_get         = */ phy_xgxs16g_ability_advert_get,
   2848     /* .pd_ability_remote_get         = */ phy_xgxs16g_ability_remote_get,
   2849     /* .pd_ability_local_get          = */ phy_xgxs16g_ability_local_get
   2850 };
   2851 
   2852 
   2853 /***********************************************************************
   2854  *
   2855  * PASS-THROUGH NOTIFY ROUTINES
   2856  */
   2857 
   2858 /*
   2859  * Function:
   2860  *      _phy_xgxs16g_notify_duplex
   2861  * Purpose:
   2862  *      Program duplex if (and only if) serdesxgxs16g is an intermediate PHY.
   2863  * Parameters:
   2864  *      unit - StrataSwitch unit #.
   2865  *      port - StrataSwitch port #.
   2866  *      duplex - Boolean, TRUE indicates full duplex, FALSE
   2867  *              indicates half.
   2868  * Returns:
   2869  *      SOC_E_XXX
   2870  * Notes:
   2871  *      If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to
   2872  *      talk directly to an external fiber module.
   2873  *
   2874  *      If PHY_FLAGS_FIBER is clear, the PHY is being used in
   2875  *      pass-through mode to talk to an external SGMII PHY.
   2876  *
   2877  *      When used in pass-through mode, autoneg must be turned off and
   2878  *      the speed/duplex forced to match that of the external PHY.
   2879  */
   2880 
   2881 STATIC int
   2882 _phy_xgxs16g_notify_duplex(int unit, soc_port_t port, uint32 duplex)
   2883 {
   2884     int                 fiber;
   2885     uint16              mii_ctrl;
   2886     phy_ctrl_t  *pc;
   2887 
   2888     fiber = PHY_FIBER_MODE(unit, port);
   2889     pc    = INT_PHY_SW_STATE(unit, port);
   2890     LOG_INFO(BSL_LS_SOC_PHY,
   2891              (BSL_META_U(unit,
   2892                          "_phy_xgxs16g_notify_duplex: "
   2893                          "u=%d p=%d duplex=%d fiber=%d\n"),
   2894               unit, port, duplex, fiber));
   2895 
   2896     if (SAL_BOOT_SIMULATION) {
   2897         return SOC_E_NONE;
   2898     }
   2899 
   2900     if (fiber) {
   2901         SOC_IF_ERROR_RETURN
   2902             (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc,
   2903                                           MII_CTRL_FD, MII_CTRL_FD));
   2904         return SOC_E_NONE;
   2905     }
   2906 
   2907     /* Put SERDES PHY in reset */
   2908 
   2909     SOC_IF_ERROR_RETURN
   2910         (_phy_xgxs16g_notify_stop(unit, port, PHY_STOP_DUPLEX_CHG));
   2911 
   2912     /* Update duplexity */
   2913     mii_ctrl = (duplex) ? MII_CTRL_FD : 0;
   2914     SOC_IF_ERROR_RETURN
   2915         (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, mii_ctrl, MII_CTRL_FD));
   2916 
   2917     /* Take SERDES PHY out of reset */
   2918     SOC_IF_ERROR_RETURN
   2919         (_phy_xgxs16g_notify_resume(unit, port, PHY_STOP_DUPLEX_CHG));
   2920 
   2921     /* Autonegotiation must be turned off to talk to external PHY if
   2922      * SGMII autoneg is not enabled.
   2923      */
   2924     if (!PHY_SGMII_AUTONEG_MODE(unit, port)) {
   2925         SOC_IF_ERROR_RETURN
   2926             (phy_xgxs16g_an_set(unit, port, FALSE));
   2927     }
   2928     return SOC_E_NONE;
   2929 }
   2930 
   2931 /*
   2932  * Function:
   2933  *      _phy_xgxs16g_notify_speed
   2934  * Purpose:
   2935  *      Program duplex if (and only if) serdesxgxs16g is an intermediate PHY.
   2936  * Parameters:
   2937  *      unit - StrataSwitch unit #.
   2938  *      port - StrataSwitch port #.
   2939  *      speed - Speed to program.
   2940  * Returns:
   2941  *      SOC_E_XXX
   2942  * Notes:
   2943  *      If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to
   2944  *      talk directly to an external fiber module.
   2945  *
   2946  *      If PHY_FLAGS_FIBER is clear, the PHY is being used in
   2947  *      pass-through mode to talk to an external SGMII PHY.
   2948  *
   2949  *      When used in pass-through mode, autoneg must be turned off and
   2950  *      the speed/duplex forced to match that of the external PHY.
   2951  */
   2952 
   2953 STATIC int
   2954 _phy_xgxs16g_notify_speed(int unit, soc_port_t port, uint32 speed)
   2955 {
   2956     int          fiber;
   2957     uint16       fiber_status;
   2958     phy_ctrl_t  *pc;
   2959 
   2960     pc    = INT_PHY_SW_STATE(unit, port);
   2961     fiber = PHY_FIBER_MODE(unit, port);
   2962 
   2963     LOG_INFO(BSL_LS_SOC_PHY,
   2964              (BSL_META_U(unit,
   2965                          "_phy_xgxs16g_notify_speed: "
   2966                          "u=%d p=%d speed=%d fiber=%d\n"),
   2967               unit, port, speed, fiber));
   2968 
   2969     if (SAL_BOOT_SIMULATION) {
   2970         return SOC_E_NONE;
   2971     }
   2972 
   2973     SOC_IF_ERROR_RETURN
   2974         (READ_XGXS16G_SERDESDIGITAL_STATUS1000X1r(unit, pc, &fiber_status));
   2975 
   2976     /* Put SERDES PHY in reset */
   2977     SOC_IF_ERROR_RETURN
   2978         (_phy_xgxs16g_notify_stop(unit, port, PHY_STOP_SPEED_CHG));
   2979 
   2980     /* Update speed */
   2981     SOC_IF_ERROR_RETURN
   2982         (phy_xgxs16g_speed_set(unit, port, speed));
   2983 
   2984     /* Take SERDES PHY out of reset */
   2985     SOC_IF_ERROR_RETURN
   2986         (_phy_xgxs16g_notify_resume(unit, port, PHY_STOP_SPEED_CHG));
   2987 
   2988     /* Autonegotiation must be turned off to talk to external PHY */
   2989     if (!PHY_SGMII_AUTONEG_MODE(unit, port) && PHY_EXTERNAL_MODE(unit, port)) {
   2990         SOC_IF_ERROR_RETURN
   2991             (phy_xgxs16g_an_set(unit, port, FALSE));
   2992     }
   2993     LOG_INFO(BSL_LS_SOC_PHY,
   2994              (BSL_META_U(unit,
   2995                          "_phy_xgxs16g_notify_speed: "
   2996                          "u=%d p=%d speed=%d fiber=%d rv=%d\n"),
   2997               unit, port, speed, fiber,SOC_E_NONE));
   2998 
   2999     return SOC_E_NONE;
   3000 }
   3001 
   3002 /*
   3003  * Function:
   3004  *      _phy_xgxs16g_stop
   3005  * Purpose:
   3006  *      Put serdesxgxs16g SERDES in or out of reset depending on conditions
   3007  */
   3008 
   3009 STATIC int
   3010 _phy_xgxs16g_stop(int unit, soc_port_t port)
   3011 {
   3012     uint16              mii_ctrl;
   3013     int                 stop, copper;
   3014     phy_ctrl_t  *pc;
   3015 
   3016     pc = INT_PHY_SW_STATE(unit, port);
   3017 
   3018     copper = (pc->stop &
   3019               PHY_STOP_COPPER) != 0;
   3020 
   3021     stop = ((pc->stop &
   3022              (PHY_STOP_PHY_DIS |
   3023               PHY_STOP_DRAIN)) != 0 ||
   3024             (copper &&
   3025              (pc->stop &
   3026               (PHY_STOP_MAC_DIS |
   3027                PHY_STOP_DUPLEX_CHG |
   3028                PHY_STOP_SPEED_CHG)) != 0));
   3029 
   3030     LOG_INFO(BSL_LS_SOC_PHY,
   3031              (BSL_META_U(unit,
   3032                          "phy_xgxs16g_stop: u=%d p=%d copper=%d stop=%d flg=0x%x\n"),
   3033               unit, port, copper, stop,
   3034               pc->stop));
   3035 
   3036     mii_ctrl = (stop) ? MII_CTRL_PD : 0;
   3037     SOC_IF_ERROR_RETURN
   3038         (MODIFY_XGXS16G_COMBO_IEEE0_MIICNTLr(unit, pc, mii_ctrl, MII_CTRL_PD));
   3039 
   3040     return SOC_E_NONE;
   3041 }
   3042 
   3043 /*
   3044  * Function:
   3045  *      _phy_xgxs16g_notify_stop
   3046  * Purpose:
   3047  *      Add a reason to put serdesxgxs16g PHY in reset.
   3048  * Parameters:
   3049  *      unit - StrataSwitch unit #.
   3050  *      port - StrataSwitch port #.
   3051  *      flags - Reason to stop
   3052  * Returns:     
   3053  *      SOC_E_XXX
   3054  */
   3055 
   3056 STATIC int
   3057 _phy_xgxs16g_notify_stop(int unit, soc_port_t port, uint32 flags)
   3058 {
   3059     INT_PHY_SW_STATE(unit, port)->stop |= flags;
   3060 
   3061     return SOC_E_NONE;
   3062 /*    return _phy_xgxs16g_stop(unit, port); */
   3063 }
   3064 
   3065 /*  
   3066  * Function:
   3067  *      _phy_xgxs16g_notify_resume
   3068  * Purpose:
   3069  *      Remove a reason to put serdesxgxs16g PHY in reset.
   3070  * Parameters:
   3071  *      unit - StrataSwitch unit #.
   3072  *      port - StrataSwitch port #.
   3073  *      flags - Reason to stop
   3074  * Returns:     
   3075  *      SOC_E_XXX
   3076  */
   3077 
   3078 STATIC int
   3079 _phy_xgxs16g_notify_resume(int unit, soc_port_t port, uint32 flags)
   3080 {   
   3081     INT_PHY_SW_STATE(unit, port)->stop &= ~flags;
   3082     
   3083     return _phy_xgxs16g_stop(unit, port);
   3084 }
   3085 
   3086 /*
   3087  * Function:
   3088  *      phy_xgxs16g_media_setup
   3089  * Purpose:     
   3090  *      Configure 
   3091  * Parameters:
   3092  *      unit - StrataSwitch unit #.
   3093  *      port - StrataSwitch port #.
   3094  *      fiber_mode - Configure for fiber mode
   3095  *      fiber_pref - Fiber preferrred (if fiber mode)
   3096  * Returns:     
   3097  *      SOC_E_XXX
   3098  */
   3099 STATIC int
   3100 _phy_xgxs16g_notify_interface(int unit, soc_port_t port, uint32 intf)
   3101 {
   3102     phy_ctrl_t  *pc;
   3103     uint16       data16;
   3104     
   3105     LOG_INFO(BSL_LS_SOC_PHY,
   3106              (BSL_META_U(unit,
   3107                          "_phy_xgxs16g_notify_interface: u=%d p=%d IF=0x%x\n"),
   3108               unit, port, intf));
   3109 
   3110 
   3111     pc = INT_PHY_SW_STATE(unit, port);
   3112 
   3113     data16 = 0;
   3114     if (intf != SOC_PORT_IF_SGMII) {
   3115         data16 = SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK;
   3116     }
   3117  
   3118     SOC_IF_ERROR_RETURN
   3119         (MODIFY_XGXS16G_SERDESDIGITAL_CONTROL1000X1r(unit, pc, data16,
   3120                            SERDESDIGITAL_CONTROL1000X1_FIBER_MODE_1000X_MASK));
   3121  
   3122     return SOC_E_NONE;
   3123 }
   3124 
   3125 /*
   3126  * Function:
   3127  *      _phy_xgxs16g_notify_mac_loopback
   3128  * Purpose:
   3129  *      turn on rx clock compensation in mac loopback mode for
   3130  *      applicable XGXS devices
   3131  * Parameters:
   3132  *      unit - StrataSwitch unit #.
   3133  *      port - StrataSwitch port #.
   3134  *      enable - TRUE mac loopback mode, FALSE not in mac loopback mode 
   3135  * Returns:
   3136  *      SOC_E_XXX
   3137  */
   3138 STATIC int
   3139 _phy_xgxs16g_notify_mac_loopback(int unit, soc_port_t port, uint32 enable)
   3140 {
   3141     phy_ctrl_t  *pc;
   3142     
   3143     LOG_INFO(BSL_LS_SOC_PHY,
   3144              (BSL_META_U(unit,
   3145                          "_phy_xgxs16g_notify_mac_loopback: u=%d p=%d enable=0x%x\n"),
   3146               unit, port, enable));
   3147 
   3148     pc = INT_PHY_SW_STATE(unit, port);
   3149 
   3150     /* XMAC loopback mode needs to enable clock comp */
   3151     if (XGXS16G_13G_ID(pc)) {
   3152         SOC_IF_ERROR_RETURN
   3153             (MODIFY_XGXS16G_XGXSBLK2_UNICOREMODE10Gr(unit, pc,
   3154                  enable? 0x80: 0x91,
   3155                  XGXSBLK2_UNICOREMODE10G_UNICOREMODE10GHIG_MASK |
   3156                  XGXSBLK2_UNICOREMODE10G_UNICOREMODE10GCX4_MASK));
   3157     }
   3158     return SOC_E_NONE;
   3159 }
   3160 
   3161 #ifdef BROADCOM_DEBUG
   3162 void
   3163 phy_xgxs16g_state_dump(int unit, soc_port_t port)
   3164 {
   3165 
   3166     /* Show PHY configuration summary */
   3167     /* lane status */
   3168     
   3169 
   3170     /* Show Counters */
   3171     /* Digital.CrcErr_RxPkt_A */
   3172     /* ieee0Blk_A.MIIStat_A */
   3173 
   3174     /* Dump Registers */
   3175 }
   3176 #endif /* BROADCOM_DEBUG */
   3177 
   3178 #else
   3179 int _phy_xgxs16g_not_empty;
   3180 #endif /*  INCLUDE_XGXS_16G */
   3181