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

viper.c (159608B)


      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:        viper.c
      8  * Purpose:     Support Broadcom 28nm XGXS/SGMIIPLUS2 internal SerDes
      9  */
     10 
     11 /*
     12  *   This module implements an NTSW SDK Phy driver for the VIPER Serdes.
     13  *  
     14  *   LAYERING.
     15  *
     16  *   This driver is built on top of the PHYMOD library, which is a PHY
     17  *   driver library that can operate on a family of PHYs, including
     18  *   VIPER.  PHYMOD can be built in a standalone enviroment and be
     19  *   provided independently from the SDK.  PHYMOD APIs consist of
     20  *   "core" APIs and "phy" APIs.
     21  *
     22  *
     23  *   KEY IDEAS AND MAIN FUNCTIONS
     24  *
     25  *   Some key ideas in this architecture are:
     26  *
     27  *   o A PHMOD "phy" consists of one more more lanes, all residing in a single
     28  *     core.  An SDK "phy" is a logical port, which can consist of one or
     29  *     more lanes in a single core, OR, can consist of multiples lanes in
     30  *     more than one core.
     31  *   o PHYMOD code is "stateless" in the sense that all calls to PHYMOD
     32  *     APIs are fully parameterized and no per-phy state is held by a PHYMOD
     33  *     driver.
     34  *   o PHYMOD APIs do not map 1-1 with SDK .pd_control_set or .pd_control_get
     35  *     APIs (nor ".pd_xx" calls, nor to .phy_viper_per_lane_control_set and
     36  *     .phy_viper_per_lane_control_get APIs.
     37  *
     38  *   The purpose of this code, then, is to provide the necessary translations
     39  *   between the SDK interfaces and the PHYMOD interfaces.  This includes:
     40  * 
     41  *   o Looping over the cores in a logical PHY in order to operate on the
     42  *     supporting PHMOD PHYs
     43  *   o Determining the configuration data for the phy, based on programmed
     44  *     defaults and SOC properties.
     45  *   o Managing the allocation and freeing of phy data structures required for
     46  *     working storage.  Locating these structures on procedure invocation.
     47  *   o Mapping SDK API concepts to PHYMOD APIs.  In some cases, local state is
     48  *     required in this module in order to present the legacy API.
     49  *
     50  * 
     51  *   MAIN DATA STRUCTURES
     52  * 
     53  *   phy_ctrl_t
     54  *   The PHY control structure defines the SDK notion of a PHY
     55  *   (existing) structure owned by SDK phy driver modules.  In order
     56  *   to support PHYMOD PHYs, one addition was made to this structure
     57  *   (soc_phymod_ctrl_t phymod_ctrl;)
     58  *
     59  *   viper_config_t
     60  *   Driver specific data.  This structure is used by viper to hold
     61  *   logical port specific working storage.
     62  *
     63  *   soc_phymod_ctrl_t
     64  *   PHYMOD drivers.  Resides in phy_ctrl_t specifies how many cores
     65  *   are in this phy and contains an array of pointers to
     66  *   soc_phymod_phy_t structures, which define a PHYMOD PHY.
     67  *
     68  *   soc_phymod_phy_t
     69  *   This structure contains a pointer to phymod_phy_access_t and a
     70  *   pointer to the associated soc_phymod_core_t.  Instances if this
     71  *   structure are created during device probe/init and are maintained
     72  *   by the SOC.
     73  *
     74  *   soc_phymod_core_t
     75  *   This structure contains per-core information.  Multiple PHYMOD
     76  *   PHYS can point to a single core.
     77  *
     78  *   phymod_phy_access_t
     79  *   This structure contains information about how to read/write PHY
     80  *   registers.  A required parameter for PHYMOD PHY APIs
     81  * 
     82  *   phymod_core_access_t
     83  *   This structure contains information about how to read/write PHY
     84  *   registers.  A required parameter for PHYMOD core APIs.
     85  */
     86 
     87 #include <shared/bsl.h>
     88 
     89 #include <sal/types.h>
     90 #include <sal/types.h>
     91 #include <sal/core/spl.h>
     92 #include <shared/bsl.h>
     93 #include <soc/drv.h>
     94 #include <soc/debug.h>
     95 #include <soc/error.h>
     96 #include <soc/phyreg.h>
     97 #include <soc/port_ability.h>
     98 #include <soc/phy.h>
     99 #include <soc/phy/phyctrl.h>
    100 #include <soc/phy/drv.h>
    101 #include <soc/phy/phymod_ids.h>
    102 
    103 #include "phydefs.h"      /* Must include before other phy related includes */ 
    104 
    105 #include "phyconfig.h"     /* Must include before other phy related includes */
    106 #include "phyident.h"
    107 #include "phyreg.h"
    108 #include "phynull.h"
    109 #include "xgxs.h"
    110 #include "serdesid.h"
    111 
    112 #if defined(INCLUDE_XGXS_VIPER)
    113 
    114 #include <phymod/phymod.h>
    115 #include <phymod/phymod_debug.h>
    116 #include <phymod/phymod_diagnostics.h>
    117 #include <phymod/phymod_util.h>
    118 #include <phymod/chip/bcmi_viper_xgxs_sym.h>
    119 #include <phymod/chip/bcmi_sgmiip2x4_serdes_sym.h>
    120 #include <phymod/chip/viper.h>
    121 
    122 
    123 #include "../../../libs/phymod/chip/viper/tier1/viper_err_code.h"
    124 
    125 #define NUM_LANES             4    /* num of lanes per core */
    126 #define MAX_NUM_LANES         4    /* max num of lanes per port */
    127 #define VIPER_NO_CFG_VALUE     (-1)
    128 
    129 #define VIPERX          1
    130 
    131 typedef struct viper_speed_config_s {
    132     uint32  port_refclk_int;
    133     int     speed;
    134     int     port_num_lanes;
    135     int     scrambler_en;  
    136     uint32  line_interface;
    137     int     fiber_pref;
    138     int     pll_divider_req;
    139 } viper_speed_config_t;
    140 
    141 #define NUM_PATTERN_DATA_INTS    8
    142 typedef struct viper_pattern_s {
    143     uint32 pattern_data[NUM_PATTERN_DATA_INTS];
    144     uint32 pattern_length;
    145 } viper_pattern_t;
    146 
    147 #define VIPER_LANE_NAME_LEN   30
    148 
    149 typedef struct {
    150     uint16 serdes_id0;
    151     char   name[VIPER_LANE_NAME_LEN];
    152 } viper_dev_info_t;
    153 
    154 /* index to TX drive configuration table for each VCO setting.
    155  */
    156 typedef enum txdrv_inxs {
    157     TXDRV_XAUI_INX,     /* 10G XAUI mode  */
    158     TXDRV_SGMII_INX,    /* 1G SGMII mode  */
    159     TXDRV_AN_INX,       /* a common entry for autoneg mode */
    160     TXDRV_DFT_INX,      /* temp for any missing speed modes */
    161     TXDRV_LAST_INX      /* always last */
    162 } TXDRV_INXS_t;
    163 
    164 #define TXDRV_ENTRY_NUM     (TXDRV_LAST_INX)
    165 #define MAX_NUM_LANES        4
    166 
    167 /*
    168    Config - per logical port
    169 */
    170 typedef struct {
    171     phymod_polarity_t               phy_polarity_config;
    172     phymod_phy_reset_t              phy_reset_config;
    173     viper_pattern_t                 pattern;
    174     viper_speed_config_t            speed_config;
    175 
    176     int fiber_pref;                 /* spn_SERDES_FIBER_PREF */
    177     int cl37an;                     /* spn_PHY_AN_C37 */
    178     int auto_medium;
    179     viper_dev_info_t info;          /*serdes id info */
    180     phymod_tx_t tx_drive[TXDRV_ENTRY_NUM];
    181     phymod_tx_t ln_txparam[MAX_NUM_LANES] ;
    182 
    183 } viper_config_t;
    184 
    185 
    186 #define VIPER_IF_NULL   (1 << SOC_PORT_IF_NULL)
    187 #define VIPER_IF_SR     (1 << SOC_PORT_IF_SR)
    188 #define VIPER_IF_KR     (1 << SOC_PORT_IF_KR)
    189 #define VIPER_IF_KR4    (1 << SOC_PORT_IF_KR4)
    190 #define VIPER_IF_CR     (1 << SOC_PORT_IF_CR)
    191 #define VIPER_IF_CR4    (1 << SOC_PORT_IF_CR4)
    192 #define VIPER_IF_XAUI   (1 << SOC_PORT_IF_XAUI)
    193 
    194 #define VIPER_CL37_W_1G      3
    195 #define VIPER_CL37_WO_BAM    2
    196 #define VIPER_CL37_W_BAM     1
    197 #define VIPER_CL37_DISABLE   0
    198 
    199 STATIC int phy_viper_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability);
    200 STATIC int phy_viper_ability_advert_set(int unit, soc_port_t port,
    201                           soc_port_ability_t *ability);
    202 STATIC int _phy_viper_enable_set(int unit, soc_port_t port, int enable);
    203 
    204 /*
    205  * Function:
    206  *      _viper_reg_read
    207  * Doc:
    208  *      register read operations
    209  * Parameters:
    210  *      unit            - (IN)  unit number
    211  *      core_addr       - (IN)  core address
    212  *      reg_addr        - (IN)  address to read
    213  *      val             - (OUT) read value
    214  */
    215 STATIC int 
    216 _viper_reg_read(void* user_acc, uint32_t core_addr, uint32_t reg_addr, uint32_t *val)
    217 {
    218     uint16 data16;
    219     int rv;
    220     soc_phymod_core_t *core = (soc_phymod_core_t *)user_acc;
    221     
    222     rv = core->read(core->unit, core_addr, reg_addr, &data16);
    223     *val = data16;
    224     PHYMOD_VDBG(VIPER_DBG_REGACC,NULL,("%-22s: core_addr: 0x%08x reg_addr: 0x%08x, data: 0x%04x\n", __func__, core_addr, reg_addr, *val ));
    225     return rv;
    226 }
    227 
    228 /*
    229  * Function:
    230  *      _viper_reg_write
    231  * Doc:
    232 *      register write operations
    233  * Parameters:
    234  *      unit            - (IN)  unit number
    235  *      core_addr       - (IN)  core address
    236  *      reg_addr        - (IN)  address to write
    237  *      val             - (IN)  write value
    238  */
    239 STATIC int 
    240 _viper_reg_write(void* user_acc, uint32_t core_addr, uint32_t reg_addr, uint32_t val)
    241 {
    242     soc_phymod_core_t *core = (soc_phymod_core_t *)user_acc;
    243     uint16 data16 = (uint16)val;
    244     uint16 mask = (uint16)(val >> 16);
    245 
    246     if (mask) {
    247         if (core->wrmask) {
    248             return core->wrmask(core->unit, core_addr, reg_addr, data16, mask);
    249         }
    250         (void)core->read(core->unit, core_addr, reg_addr, &data16);
    251         data16 &= ~mask;
    252         data16 |= (val & mask);
    253     }
    254         PHYMOD_VDBG(VIPER_DBG_REGACC,NULL,("-22%s: core_addr: 0x%08x reg_addr: 0x%08x, data: 0x%04x\n", __func__, core_addr, reg_addr, val ));
    255 
    256     return core->write(core->unit, core_addr, reg_addr, data16);
    257 }
    258 
    259 
    260 
    261 #define IS_DUAL_LANE_PORT(_pc) ((_pc)->phy_mode == PHYCTRL_DUAL_LANE_PORT)
    262 #define IND_LANE_MODE(_pc) ((_pc)->phy_mode == PHYCTRL_ONE_LANE_PORT)  
    263 #define MAIN0_SERDESID_REV_LETTER_SHIFT  (14)
    264 #define MAIN0_SERDESID_REV_NUMBER_SHIFT  (11)
    265 
    266 #define MODEL_MASK            0x3f
    267 #define MODEL_XGXS_10G_028    0x8
    268 #define MODEL_SGMIIPLUS2_X4   0xf
    269 /*
    270  * Function:
    271  *      viper_show_serdes_info
    272  * Purpose:
    273  *      Show Serdes information.
    274  * Parameters:
    275  *      pc             - (IN)  phyctrl  oject
    276  *      pInfo          - (IN)  device info object
    277  *      rev_id         - (IN)  serdes revid
    278  * Returns:     
    279  *      SOC_E_NONE
    280  */
    281 STATIC int
    282 viper_show_serdes_info(phy_ctrl_t *pc, viper_dev_info_t *pInfo, phymod_core_info_t *core_info)
    283 {
    284     uint32_t serdes_id0, len;
    285 
    286     pInfo->serdes_id0 = core_info->serdes_id ;
    287 
    288     /* This is Viper device */
    289     serdes_id0 = pInfo->serdes_id0;
    290     if ((serdes_id0 & MODEL_MASK) == MODEL_XGXS_10G_028) {
    291         sal_strncpy(pInfo->name,"VIPERX-", sal_strlen("VIPERX-")); 
    292     } else if ((serdes_id0 & MODEL_MASK) == MODEL_SGMIIPLUS2_X4){
    293         sal_strncpy(pInfo->name,"VIPERG-", sal_strlen("VIPERG-"));
    294     }
    295     len = sal_strlen(pInfo->name);
    296     /* add rev letter */
    297     pInfo->name[len++] = 'A' + ((serdes_id0 >>
    298                           MAIN0_SERDESID_REV_LETTER_SHIFT) & 0x3);
    299     /* add rev number */
    300     pInfo->name[len++] = '0' + ((serdes_id0 >>
    301                           MAIN0_SERDESID_REV_NUMBER_SHIFT) & 0x7);
    302     pInfo->name[len++] = '/';
    303     pInfo->name[len++] = (pc->chip_num / 10) % 10 + '0';
    304     pInfo->name[len++] = pc->chip_num % 10 + '0';
    305     pInfo->name[len++] = '/';
    306 
    307     /* phy_mode: 0 single port mode, port uses all four lanes 
    308      *           1 dual port mode, port uses 2 lane
    309      *           2 quad port mode, port uses 1 lane
    310      */
    311     if (IS_DUAL_LANE_PORT(pc)) { /* dual-xgxs mode */
    312         if (pc->lane_num < 2) { /* the first dual-xgxs port */
    313             pInfo->name[len++] = '0';
    314             pInfo->name[len++] = '-';
    315             pInfo->name[len++] = '1';
    316         } else {
    317             pInfo->name[len++] = '2';
    318             pInfo->name[len++] = '-';
    319             pInfo->name[len++] = '3';
    320         }
    321     } else if (pc->phy_mode == PHYCTRL_ONE_LANE_PORT) {
    322         pInfo->name[len++] = pc->lane_num + '0';
    323     } else {
    324         pInfo->name[len++] = '4';
    325     }
    326     pInfo->name[len] = 0;  /* string terminator */
    327 
    328     if (len > VIPER_LANE_NAME_LEN) {
    329         LOG_ERROR(BSL_LS_SOC_COMMON,
    330                   (BSL_META("VIPER info string length %d exceeds max length 0x%x: u=%d p=%d\n"),
    331                    len,VIPER_LANE_NAME_LEN, pc->unit, pc->port));
    332         return SOC_E_MEMORY;
    333     }
    334     return SOC_E_NONE;
    335 }
    336 
    337 /*
    338  * Function:
    339  *      viper_speed_to_interface_config_get
    340  * Purpose:     
    341  *      Convert speed to interface_config struct
    342  * Parameters:
    343  *      unit                - BCM unit number.
    344  *      port                - Port number.
    345  *      speed               - speed to convert
    346  *      interface_config    - output interface config struct
    347  * Returns:     
    348  *      SOC_E_NONE
    349  */
    350 STATIC int 
    351 viper_speed_to_interface_config_get(const phymod_phy_access_t *phy, viper_speed_config_t* speed_config, phymod_phy_inf_config_t* interface_config, TXDRV_INXS_t* tx_index)
    352 {
    353     int fiber_pref;
    354     fiber_pref = speed_config->fiber_pref;
    355 
    356     SOC_IF_ERROR_RETURN(phymod_phy_inf_config_t_init(interface_config));
    357 
    358     interface_config->interface_modes = 0;
    359     interface_config->data_rate       = speed_config->speed;
    360     interface_config->pll_divider_req = speed_config->pll_divider_req ;
    361 
    362     *tx_index = TXDRV_DFT_INX;
    363 
    364     if (fiber_pref) {
    365         PHYMOD_INTF_MODES_FIBER_SET(interface_config);
    366     }    
    367     switch (speed_config->speed) {
    368         case 10:
    369             interface_config->interface_type = phymodInterfaceSGMII;
    370             *tx_index = TXDRV_DFT_INX;
    371             break;
    372         case 100:
    373         case 1000:
    374             if (speed_config->fiber_pref) { 
    375                 interface_config->interface_type = phymodInterface1000X;
    376                 *tx_index = TXDRV_DFT_INX;
    377             } else {
    378                 interface_config->interface_type = phymodInterfaceSGMII;
    379                 *tx_index = TXDRV_SGMII_INX;
    380             }
    381             break;
    382         case 2500:  
    383              interface_config->interface_type = phymodInterface1000X; 
    384              *tx_index = TXDRV_DFT_INX; 
    385              break;
    386         case 10000:
    387             interface_config->interface_type = phymodInterfaceXAUI;
    388             *tx_index = TXDRV_XAUI_INX;
    389             break;
    390        default:
    391             return SOC_E_PARAM;
    392     }
    393     return SOC_E_NONE;
    394 }
    395 
    396 
    397 /*
    398  * Function:
    399  *      viper_config_init
    400  * Purpose:     
    401  *      Determine phy configuration data for purposes of PHYMOD initialization.
    402  * 
    403  *      A side effect of this procedure is to save some per-logical port
    404  *      information in (viper_cfg_t *) &pc->driver_data;
    405  *
    406  * Parameters:
    407  *      unit                  - BCM unit number.
    408  *      port                  - Port number.
    409  *      logical_lane_offset   - starting logical lane number
    410  * Returns:     
    411  *      SOC_E_NONE
    412  */
    413 
    414 STATIC int
    415 viper_config_init(int unit, soc_port_t port, const phymod_phy_access_t* phy, 
    416                  int logical_lane_offset,
    417                  phymod_core_init_config_t *core_init_config, 
    418                  phymod_phy_init_config_t  *pm_phy_init_config)
    419 {
    420     phy_ctrl_t *pc;
    421     viper_speed_config_t *speed_config;
    422     viper_config_t *pCfg;
    423     phymod_tx_t *p_tx;
    424     int port_refclk_int;
    425     int port_num_lanes;
    426     int core_num;
    427     int phy_num_lanes;
    428     int lane_map_rx = 0, lane_map_tx = 0;
    429     int i;
    430     int fiber_pref = 0;
    431     uint32_t preemphasis;
    432     TXDRV_INXS_t tx_index = TXDRV_DFT_INX;
    433 
    434     pc = INT_PHY_SW_STATE(unit, port);
    435     if (pc == NULL) {
    436         return SOC_E_INTERNAL;
    437     }
    438     pCfg = (viper_config_t *) pc->driver_data;
    439 
    440     /* extract data from SOC_INFO */
    441     port_refclk_int = SOC_INFO(unit).port_refclk_int[port];
    442     port_refclk_int = 156;  
    443     port_refclk_int = soc_property_port_get(unit, port,spn_XGXS_LCPLL_XTAL_REFCLK, port_refclk_int);
    444     port_num_lanes = SOC_INFO(unit).port_num_lanes[port];
    445     
    446     /* figure out how many lanes are in this phy */
    447     core_num = (port / 4);
    448     phy_num_lanes = port_num_lanes - logical_lane_offset;
    449     if (phy_num_lanes > MAX_NUM_LANES) {
    450        phy_num_lanes = MAX_NUM_LANES;
    451     }
    452     
    453     /* 
    454         CORE configuration
    455     */
    456     phymod_core_init_config_t_init(core_init_config);
    457 
    458     core_init_config->lane_map.num_of_lanes = NUM_LANES;
    459     core_init_config->flags = PHYMOD_CORE_INIT_F_FIRMWARE_LOAD_VERIFY;
    460     lane_map_rx = soc_property_port_get(unit, port,
    461                                         spn_XGXS_RX_LANE_MAP, 0x3210);
    462 
    463     for (i=0; i<NUM_LANES; i++) {
    464          core_init_config->lane_map.lane_map_rx[i] = (lane_map_rx >> (i * 4 /* 4 bit per lane */)) & 0xf;
    465     }
    466 
    467     lane_map_tx = soc_property_port_get(unit, port,
    468                                         spn_XGXS_TX_LANE_MAP, 0x3210);
    469     for (i=0; i<NUM_LANES; i++) {
    470          core_init_config->lane_map.lane_map_tx[i] = (lane_map_tx >> (i * 4 /*4 bit per lane*/)) & 0xf;
    471     }
    472     /* next get the tx/rx polairty info */
    473     core_init_config->polarity_map.tx_polarity = soc_property_port_get(unit, port,
    474                             spn_PHY_XAUI_TX_POLARITY_FLIP, 0);
    475     core_init_config->polarity_map.rx_polarity = soc_property_port_get(unit, port,
    476                             spn_PHY_XAUI_RX_POLARITY_FLIP, 0);
    477     speed_config = &(pCfg->speed_config);
    478     speed_config->port_refclk_int  = port_refclk_int;
    479     speed_config->speed  = soc_property_port_get(unit, port, spn_PORT_INIT_SPEED, pc->speed_max);
    480     speed_config->port_num_lanes   = phy_num_lanes;
    481     speed_config->line_interface   = soc_property_port_get(unit, port, spn_SERDES_IF_TYPE, 0);
    482     speed_config->fiber_pref = soc_property_port_get(unit, port, spn_SERDES_FIBER_PREF, speed_config->fiber_pref);
    483     speed_config->pll_divider_req      = soc_property_port_get(unit, port, spn_XGXS_PHY_PLL_DIVIDER, 0);
    484 
    485     SOC_IF_ERROR_RETURN
    486         (viper_speed_to_interface_config_get(phy, speed_config, &(core_init_config->interface), &tx_index));
    487 
    488     /* 
    489         PHY configuration
    490     */
    491     for (i=0; i<MAX_NUM_LANES; i++) {
    492         pCfg->ln_txparam[i+logical_lane_offset].main  = -1 ;
    493         pCfg->ln_txparam[i+logical_lane_offset].post  = -1 ;
    494     }
    495 
    496     for (i = 0; i < TXDRV_ENTRY_NUM; i++) {
    497         p_tx = &pCfg->tx_drive[i];
    498         SOC_IF_ERROR_RETURN(phymod_tx_t_init(p_tx));
    499     }
    500     /* set the default tx parameters */
    501     p_tx = &pCfg->tx_drive[TXDRV_DFT_INX];
    502     p_tx->main = 0x32;
    503     p_tx->post = 0;
    504 
    505     p_tx = &pCfg->tx_drive[TXDRV_AN_INX];
    506     p_tx->main = 0x32;
    507     p_tx->post = 0x0;
    508 
    509     p_tx = &pCfg->tx_drive[TXDRV_XAUI_INX];
    510     p_tx->main = 0x32;
    511     p_tx->post = 0x0;
    512 
    513     phymod_phy_init_config_t_init(pm_phy_init_config);
    514     for (i = 0; i < 4; i++) {
    515         pm_phy_init_config->tx[i].main = pCfg->tx_drive[tx_index].main;
    516         pm_phy_init_config->tx[i].post = pCfg->tx_drive[tx_index].post;
    517     }
    518 
    519     pm_phy_init_config->polarity.rx_polarity
    520                                  = soc_property_port_get(unit, port,
    521                                    spn_PHY_XAUI_RX_POLARITY_FLIP, 
    522                                    pm_phy_init_config->polarity.rx_polarity);
    523     pm_phy_init_config->polarity.tx_polarity
    524                                  = soc_property_port_get(unit, port,
    525                                    spn_PHY_XAUI_TX_POLARITY_FLIP,
    526                                    pm_phy_init_config->polarity.tx_polarity);
    527     pm_phy_init_config->rx_los.rx_los_en
    528                                  = soc_property_port_get(unit, port,
    529                                    spn_SERDES_RX_LOS, 0);
    530     pm_phy_init_config->rx_los.rx_los_invert_en
    531                                  = soc_property_port_get(unit, port,
    532                                    spn_SERDES_RX_LOS_INVERT, 0);
    533 
    534     pm_phy_init_config->rx_swing = soc_property_port_get(unit, port, spn_SERDES_RX_LARGE_SWING, 0);
    535 
    536     for (i = 0; i < MAX_NUM_LANES; i++) {
    537         /*first get the preemphasis */
    538         preemphasis = 0;
    539         preemphasis = soc_property_port_suffix_num_get(unit, port,
    540                                     i + core_num * 4, spn_SERDES_PREEMPHASIS,
    541                                     "lane", preemphasis); 
    542         pm_phy_init_config->tx[i].main = (preemphasis & 0xff00) >> 8;
    543         pm_phy_init_config->tx[i].post = (preemphasis & 0xff0000) >> 16;
    544     }
    545 
    546 
    547     pm_phy_init_config->an_en = TRUE;
    548 
    549     /* By default enable cl37 */
    550     pCfg->cl37an = TRUE;
    551 
    552     pCfg->cl37an = soc_property_port_get(unit, port,
    553                                         spn_PHY_AN_C37, pCfg->cl37an); /* no L: C37, not CL37 */
    554 
    555     /* 
    556         phy_ctrl_t configuration (LOGICAL PORT BASED)
    557         Only do this once, for the first core of the logical port
    558     */
    559     if (core_num == 0) {
    560         /* phy_mode, PHYCTRL_MDIO_ADDR_SHARE, PHY_FLAGS_INDEPENDENT_LANE */
    561         if (port_num_lanes == 4) {
    562             pc->phy_mode = PHYCTRL_QUAD_LANE_PORT;
    563             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_INDEPENDENT_LANE);
    564         } else if (port_num_lanes == 2) {
    565             pc->phy_mode = PHYCTRL_DUAL_LANE_PORT;
    566             pc->flags |= PHYCTRL_MDIO_ADDR_SHARE;
    567             PHY_FLAGS_SET(unit, port, PHY_FLAGS_INDEPENDENT_LANE);
    568         } else if (port_num_lanes == 1) {
    569             pc->phy_mode = PHYCTRL_ONE_LANE_PORT;
    570             pc->flags |= PHYCTRL_MDIO_ADDR_SHARE;
    571             PHY_FLAGS_SET(unit, port, PHY_FLAGS_INDEPENDENT_LANE);
    572         }
    573         /* PHY_FLAGS_FIBER */
    574         PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER);
    575         if (!PHY_EXTERNAL_MODE(unit, port)) {
    576 
    577             fiber_pref = FALSE;
    578             if (PHY_FIBER_MODE(unit, port) ||
    579                 (!PHY_INDEPENDENT_LANE_MODE(unit, port)) ||
    580                 (pc->speed_max >= 10000)) {
    581                 fiber_pref = TRUE;
    582             }
    583             fiber_pref = soc_property_port_get(unit, port,
    584                                                spn_SERDES_FIBER_PREF, fiber_pref);
    585             if (fiber_pref) {
    586                 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER);
    587             }
    588         }
    589 
    590         
    591         PHY_FLAGS_SET(unit,port,PHY_FLAGS_SERVICE_INT_PHY_LINK_GET);
    592 
    593     }
    594 
    595     return SOC_E_NONE;
    596 }
    597 
    598 STATIC int
    599 _viper_device_print(soc_phymod_core_t *core)
    600 {
    601     phymod_core_access_t *pm_core;
    602     phymod_access_t *pm_acc;
    603     
    604     pm_core = &core->pm_core;
    605     pm_acc = &pm_core->access;
    606      
    607     if(core) {
    608         PHYMOD_VDBG(VIPER_DBG_MEM, pm_acc, ("ref_cnt=%0d core_p=%p\n", core->ref_cnt, (void *)core)) ;
    609     } else {
    610         PHYMOD_VDBG(VIPER_DBG_MEM, pm_acc, ("Error: no defined phymod core.\n"));
    611     }
    612     return SOC_E_NONE;
    613 }
    614 
    615 /*
    616  * Function:
    617  *      phy_viper_init
    618  *  
    619  *      An SDK "phy" is a logical port, which can consist of from 1-10 lanes,
    620  *          (A phy with more than 4 lanes requires more than one core).
    621  *      Per-logical port information is saved in (viper_config_t *) &pc->driver_data.
    622  *      An SDK phy is implemented as one or more PHYMOD "phy"s.
    623  *  
    624  *      A PHYMOD "phy" resides completely within a single core, which can be
    625  *      from 1 to 4 lanes.
    626  *      Per-phymod phy information is kept in (soc_phymod_ctrl_t) *pc->phymod_ctrl
    627  *      A phymod phy points to its core.  Up to 4 phymod phys can be on a single core
    628  *  
    629  * Purpose:     
    630  *      Initialize a viper phy
    631  * Parameters:
    632  *      unit - BCM unit number.
    633  *      port - Port number. 
    634  * Returns:     
    635  *      SOC_E_NONE
    636  */
    637 STATIC int
    638 phy_viper_init(int unit, soc_port_t port)
    639 {
    640     phy_ctrl_t *pc; 
    641     soc_phymod_ctrl_t *pmc;
    642     soc_phymod_phy_t *phy = NULL;
    643     soc_phymod_core_t *core;
    644     viper_config_t *pCfg;
    645     viper_speed_config_t *speed_config;
    646     viper_dev_info_t *pInfo;
    647     soc_phy_info_t *pi;
    648     phymod_phy_inf_config_t interface_config;
    649     phymod_core_status_t core_status;
    650     phymod_core_info_t core_info;
    651     int idx;
    652     int logical_lane_offset;
    653     soc_port_ability_t ability; 
    654     TXDRV_INXS_t tx_index = TXDRV_DFT_INX;
    655 
    656 
    657     pc = INT_PHY_SW_STATE(unit, port);
    658     if (pc == NULL) {
    659         return SOC_E_INTERNAL;
    660     }
    661     pc->driver_data = (void*)(pc+1);
    662     pmc = &pc->phymod_ctrl;
    663     pCfg = (viper_config_t *) pc->driver_data;
    664     pInfo = &pCfg->info; 
    665     
    666     sal_memset(pCfg, 0, sizeof(*pCfg));
    667     speed_config = &(pCfg->speed_config);
    668 
    669     sal_memset(&ability, 0, sizeof(ability));
    670 
    671     /* Loop through all phymod phys that support this SDK phy */
    672     logical_lane_offset = 0;
    673     for (idx = 0; idx < pmc->num_phys; idx++) {
    674         phy = pmc->phy[idx];
    675         core = phy->core;
    676         core->pm_core.access.lane_mask = phy->pm_phy.access.lane_mask;
    677         _viper_device_print(core) ;
    678         /* determine configuration data structure to default values, based on SOC properties */
    679         SOC_IF_ERROR_RETURN
    680             (viper_config_init(unit, port, &phy->pm_phy,
    681                               logical_lane_offset,
    682                               &core->init_config, &phy->init_config));
    683 
    684         core_status.pmd_active = 0;
    685         if (!SOC_WARM_BOOT(unit)) {
    686             SOC_IF_ERROR_RETURN
    687                 (phymod_core_init(&core->pm_core, &core->init_config, &core_status));
    688 
    689         }
    690 
    691         if (!SOC_WARM_BOOT(unit)) {
    692             SOC_IF_ERROR_RETURN
    693                 (phymod_phy_init(&phy->pm_phy, &phy->init_config));
    694         }
    695 
    696 
    697         /*read serdes id info */
    698         SOC_IF_ERROR_RETURN
    699             (phymod_core_info_get(&core->pm_core, &core_info)); 
    700 
    701 
    702         /* for multicore phys, need to ratchet up to the next batch of lanes */
    703         logical_lane_offset += core->init_config.lane_map.num_of_lanes; 
    704     }
    705 
    706     /* fill up the pInfo table for displaying the serdes driver info */
    707     SOC_IF_ERROR_RETURN
    708         (viper_show_serdes_info(pc, pInfo, &core_info));
    709 
    710     /* retrieve chip level information for serdes driver info */
    711     pi = &SOC_PHY_INFO(unit, port);
    712 
    713     if (!PHY_EXTERNAL_MODE(unit, port)) {
    714         pi->phy_name = pInfo->name;
    715     }
    716 
    717     if (SOC_WARM_BOOT(unit)) {
    718         return SOC_E_NONE;
    719     }
    720 
    721     speed_config->pll_divider_req = 40;
    722 
    723     /* set the port to its max or init_speed */
    724     SOC_IF_ERROR_RETURN
    725         (viper_speed_to_interface_config_get(&phy->pm_phy, speed_config, &interface_config, &tx_index));
    726 
    727     SOC_IF_ERROR_RETURN
    728             (phymod_phy_interface_config_set(&phy->pm_phy,
    729                                          0 /* flags */, &interface_config));
    730 
    731     /* setup the port's an cap */
    732     SOC_IF_ERROR_RETURN
    733         (phy_viper_ability_local_get(unit, port, &ability));
    734  
    735     SOC_IF_ERROR_RETURN
    736         (phy_viper_ability_advert_set(unit, port, &ability));
    737 
    738     LOG_INFO(BSL_LS_SOC_PHY,
    739              (BSL_META_U(pc->unit,
    740                          "phy_viper_init: u=%d p=%d\n"), unit, port));
    741 
    742     return SOC_E_NONE;
    743 }
    744 
    745 /*
    746  * Function:
    747  *      phy_viper_link_get
    748  * Purpose:
    749  *      Get layer2 connection status.
    750  * Parameters:
    751  *      unit - BCM unit number.
    752  *      port - Port number. 
    753  *      link - address of memory to store link up/down state.
    754  * Returns:     
    755  *      SOC_E_NONE
    756  */
    757 STATIC int
    758 phy_viper_link_get(int unit, soc_port_t port, int *link)
    759 {
    760     phy_ctrl_t                *pc;
    761     soc_phymod_ctrl_t         *pmc;
    762     phymod_phy_access_t       *pm_phy;
    763 
    764     *link = 0;
    765     /* locate phy control */
    766     pc = INT_PHY_SW_STATE(unit, port);
    767     if (pc == NULL) {
    768         return SOC_E_INTERNAL;
    769     }
    770 
    771     pmc = &pc->phymod_ctrl;
    772     pm_phy = &pmc->phy[pmc->main_phy]->pm_phy;
    773 
    774     SOC_IF_ERROR_RETURN
    775         (phymod_phy_link_status_get(pm_phy, (uint32_t *) link));
    776     return (SOC_E_NONE);
    777 }
    778 
    779 /*
    780  * Function:
    781  *      phy_viper_enable_set
    782  * Purpose:
    783  *      Enable/Disable phy 
    784  * Parameters:
    785  *      unit - BCM unit number.
    786  *      port - Port number. 
    787  *      enable - on/off state to set
    788  * Returns:     
    789  *      SOC_E_NONE
    790  */
    791 STATIC int
    792 phy_viper_enable_set(int unit, soc_port_t port, int enable)
    793 {
    794     return (_phy_viper_enable_set( unit,  port, enable));
    795 }
    796 
    797 /*
    798  * Function:
    799  *      phy_viper_enable_get
    800  * Purpose:
    801  *      Enable/Disable phy 
    802  * Parameters:
    803  *      unit - BCM unit number.
    804  *      port - Port number. 
    805  *      enable - on/off state to set
    806  * Returns:     
    807  *      SOC_E_NONE
    808  */
    809 STATIC int
    810 phy_viper_enable_get(int unit, soc_port_t port, int *enable)
    811 {
    812     phy_ctrl_t                *pc;
    813     soc_phymod_ctrl_t         *pmc;
    814     phymod_phy_access_t       *pm_phy;
    815     phymod_phy_power_t        phy_power;
    816 
    817     /* locate phy control */
    818     pc = INT_PHY_SW_STATE(unit, port);
    819     if (pc == NULL) {
    820         return SOC_E_INTERNAL;
    821     }
    822 
    823     pmc = &pc->phymod_ctrl;
    824     pm_phy = &pmc->phy[pmc->main_phy]->pm_phy;
    825 
    826     SOC_IF_ERROR_RETURN(phymod_phy_power_get(pm_phy, &phy_power));
    827     if (phy_power.tx & phy_power.rx) {
    828         *enable = 1;
    829     } else { 
    830         *enable = 0; 
    831     } 
    832 
    833     return (SOC_E_NONE);
    834 }
    835 
    836 /*
    837  * Function:
    838  *      phy_viper_speed_set
    839  * Purpose:
    840  *      Set PHY speed
    841  * Parameters:
    842  *      unit - BCM unit number.
    843  *      port - Port number. 
    844  *      speed - link speed in Mbps
    845  * Returns:     
    846  *      SOC_E_NONE
    847  */
    848 
    849 STATIC int
    850 phy_viper_speed_set(int unit, soc_port_t port, int speed)
    851 {
    852     phy_ctrl_t                *pc;
    853     viper_config_t            *pCfg;
    854     soc_phymod_ctrl_t         *pmc;
    855     soc_phymod_phy_t          *phy;
    856     int                       idx,ln;
    857     viper_speed_config_t      speed_config;
    858     phymod_phy_inf_config_t   interface_config;
    859     TXDRV_INXS_t tx_index = TXDRV_DFT_INX;
    860     phymod_tx_t phymod_tx;
    861     phymod_phy_access_t pm_phy_copy;
    862     int start_lane, num_lane ;
    863 
    864     /* locate phy control */
    865     pc = INT_PHY_SW_STATE(unit, port);
    866     if (pc == NULL) {
    867         return SOC_E_INTERNAL;
    868     }
    869     if (speed == 0) {
    870         return SOC_E_NONE; 
    871     }
    872 
    873     pmc = &pc->phymod_ctrl;
    874     pCfg = (viper_config_t *) pc->driver_data;
    875 
    876     /* take a copy of core and phy configuration values, and set the desired speed */
    877     sal_memcpy(&speed_config, &pCfg->speed_config, sizeof(speed_config));
    878     speed_config.speed = speed;
    879 
    880     SOC_IF_ERROR_RETURN(phymod_tx_t_init(&phymod_tx));
    881 
    882     /* determine the interface configuration */
    883     phy = pmc->phy[0];
    884     SOC_IF_ERROR_RETURN
    885         (viper_speed_to_interface_config_get(&phy->pm_phy, &speed_config, &interface_config, &tx_index));
    886 
    887     /* now loop through all cores */
    888     for (idx = 0; idx < pmc->num_phys; idx++) {
    889         phy = pmc->phy[idx];
    890         if (phy == NULL) {
    891             return SOC_E_INTERNAL;
    892         }
    893 
    894         sal_memcpy(&pm_phy_copy, &phy->pm_phy, sizeof(pm_phy_copy));
    895         PHYMOD_IF_ERR_RETURN
    896             (phymod_util_lane_config_get(&pm_phy_copy.access, &start_lane, &num_lane));
    897 
    898         for(ln=0; ln<num_lane; ln++) {
    899             pm_phy_copy.access.lane_mask = 1 << (start_lane +ln) ;
    900 
    901             phymod_tx.main  = pCfg->tx_drive[tx_index].main;
    902             phymod_tx.post  = pCfg->tx_drive[tx_index].post;
    903 
    904             if( pCfg->ln_txparam[4*idx+ln].main >=0) {
    905                 phymod_tx.main = pCfg->ln_txparam[4*idx+ln].main;
    906             }
    907             if( pCfg->ln_txparam[4*idx+ln].post >=0) {
    908                 phymod_tx.post = pCfg->ln_txparam[4*idx+ln].post;
    909             }
    910 
    911             SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx));
    912         }
    913 
    914         SOC_IF_ERROR_RETURN
    915             (phymod_phy_interface_config_set(&phy->pm_phy,
    916                                              0 /* flags */, &interface_config));
    917     }
    918 
    919     /* record success */
    920     pCfg->speed_config.speed = speed;
    921 
    922     return (SOC_E_NONE);
    923 }
    924 
    925 /*
    926  * Function:
    927  *      phy_viper_speed_get
    928  * Purpose:
    929  *      Get PHY speed
    930  * Parameters:
    931  *      unit - BCM unit number.
    932  *      port - Port number. 
    933  *      speed - current link speed in Mbps
    934  * Returns:     
    935  *      SOC_E_NONE
    936  */
    937 STATIC int
    938 phy_viper_speed_get(int unit, soc_port_t port, int *speed)
    939 {
    940     phy_ctrl_t                *pc;
    941     soc_phymod_ctrl_t         *pmc;
    942     soc_phymod_phy_t          *phy;
    943     phymod_phy_inf_config_t   interface_config;
    944     /*viper_config_t            *pCfg; */
    945     int                       flag = 0;
    946     phymod_ref_clk_t          ref_clock = phymodRefClk156Mhz;
    947 
    948     /* locate phy control */
    949     pc = INT_PHY_SW_STATE(unit, port);
    950     if (pc == NULL) {
    951         return SOC_E_INTERNAL;
    952     }
    953     /*pCfg = (viper_config_t *) pc->driver_data;*/
    954 
    955     pmc = &pc->phymod_ctrl;
    956 
    957     /* initialize the data structure */
    958     interface_config.data_rate = 0;
    959 
    960     /* now loop through all cores */
    961     phy = pmc->phy[pmc->main_phy];
    962     if (phy == NULL) {
    963         return SOC_E_INTERNAL;
    964     }
    965 
    966     SOC_IF_ERROR_RETURN
    967         (phymod_phy_interface_config_get(&phy->pm_phy,
    968                                          flag, ref_clock, &interface_config));
    969     *speed = interface_config.data_rate;
    970     return (SOC_E_NONE);
    971 }
    972 
    973 /*
    974  * Function:
    975  *      phy_viper_duplex_set
    976  * Purpose:
    977  *      Set PHY duplex mode
    978  * Parameters:
    979  *      unit - BCM unit number.
    980  *      port - Port number.
    981  *      duplex - current duplex mode
    982  * Returns:
    983  *      SOC_E_NONE
    984  */
    985 STATIC int
    986 phy_viper_duplex_set(int unit, soc_port_t port, int duplex)
    987 {
    988     phy_ctrl_t* pc;
    989     soc_phymod_ctrl_t *pmc;
    990     phymod_phy_access_t *pm_phy;
    991     int idx;
    992     phymod_duplex_mode_t duplex_mode;
    993 
    994     pc = INT_PHY_SW_STATE(unit, port);
    995     pmc = &pc->phymod_ctrl;
    996     switch (duplex) {
    997         case SOC_PORT_DUPLEX_HALF:
    998             duplex_mode = phymodDuplexHalf;
    999             break;
   1000         case SOC_PORT_DUPLEX_FULL:
   1001             duplex_mode = phymodDuplexFull;
   1002             break;
   1003         default:
   1004             duplex_mode = phymodDuplexFull;
   1005             break;
   1006     }
   1007 
   1008     for (idx = 0; idx < pmc->num_phys; idx++) {
   1009          pm_phy = &pmc->phy[idx]->pm_phy;
   1010          SOC_IF_ERROR_RETURN(phymod_phy_duplex_set(pm_phy, duplex_mode));
   1011     }
   1012 
   1013     return SOC_E_NONE;
   1014 }
   1015 
   1016 /*
   1017  * Function:
   1018  *      phy_viper_duplex_get
   1019  * Purpose:
   1020  *      Get PHY duplex mode
   1021  * Parameters:
   1022  *      unit - BCM unit number.
   1023  *      port - Port number.
   1024  *      duplex - current duplex mode
   1025  * Returns:
   1026  *      SOC_E_NONE
   1027  */
   1028 STATIC int
   1029 phy_viper_duplex_get(int unit, soc_port_t port, int *duplex)
   1030 {
   1031     phy_ctrl_t* pc;
   1032     soc_phymod_ctrl_t *pmc;
   1033     phymod_phy_access_t *pm_phy;
   1034     phymod_duplex_mode_t duplex_mode;
   1035 
   1036     pc = INT_PHY_SW_STATE(unit, port);
   1037     pmc = &pc->phymod_ctrl;
   1038 
   1039     /* Check first PHY only */
   1040     pm_phy = &pmc->phy[0]->pm_phy;
   1041     SOC_IF_ERROR_RETURN
   1042         (phymod_phy_duplex_get(pm_phy, &duplex_mode));
   1043     switch (duplex_mode) {
   1044         case phymodDuplexHalf:
   1045             *duplex = SOC_PORT_DUPLEX_HALF;
   1046             break;
   1047         case phymodDuplexFull:
   1048             *duplex = SOC_PORT_DUPLEX_FULL;
   1049             break;
   1050        default:
   1051             *duplex = SOC_PORT_DUPLEX_FULL;
   1052             break;
   1053     }
   1054 
   1055     return SOC_E_NONE;
   1056 }
   1057 
   1058 /*
   1059  * Function:    
   1060  *      phy_viper_an_set
   1061  * Purpose:     
   1062  *      Enable or disable auto-negotiation on the specified port.
   1063  * Parameters:
   1064  *      unit - BCM unit number.
   1065  *      port - Port number. 
   1066  *      an   - Boolean, if true, auto-negotiation is enabled 
   1067  *              (and/or restarted). If false, autonegotiation is disabled.
   1068  * Returns:     
   1069  *      SOC_E_XXX  _soc_triumph_tx
   1070  */
   1071 STATIC int
   1072 phy_viper_an_set(int unit, soc_port_t port, int enable)
   1073 {
   1074     phy_ctrl_t                *pc;
   1075     viper_config_t            *pCfg;
   1076     soc_phymod_ctrl_t         *pmc;
   1077     soc_phymod_phy_t          *phy;
   1078     phymod_autoneg_control_t  an;
   1079     soc_info_t *si;
   1080 
   1081     /* locate phy control */
   1082     pc = INT_PHY_SW_STATE(unit, port);
   1083     if (pc == NULL) {
   1084         return SOC_E_INTERNAL;
   1085     }
   1086 
   1087     phymod_autoneg_control_t_init(&an);
   1088     pmc = &pc->phymod_ctrl;
   1089     pCfg = (viper_config_t *) pc->driver_data;
   1090     si = &SOC_INFO(unit);
   1091 
   1092     /* for legacy purpose autodet is 1 by defalut */
   1093     pCfg->auto_medium = 1;
   1094     pCfg->auto_medium = soc_property_port_get(unit, port,
   1095                               spn_SERDES_AUTOMEDIUM, pCfg->auto_medium);
   1096 
   1097     /* only request autoneg on the first core */
   1098     phy = pmc->phy[pmc->main_phy];
   1099     if (phy == NULL) {
   1100         return SOC_E_INTERNAL;
   1101     }
   1102     an.enable = enable;
   1103     an.num_lane_adv = si->port_num_lanes[port];
   1104     an.an_mode = phymod_AN_MODE_NONE;
   1105     if (pCfg->cl37an) {
   1106         an.an_mode = phymod_AN_MODE_CL37;
   1107     } else {
   1108         if(pCfg->speed_config.fiber_pref) {
   1109             an.an_mode = phymod_AN_MODE_CL37;
   1110         } else {
   1111             an.an_mode = phymod_AN_MODE_SGMII;
   1112         }
   1113     }
   1114     if (pCfg->auto_medium) {
   1115         PHYMOD_AN_F_AUTO_MEDIUM_DETECT_SET(&an);
   1116     }
   1117     SOC_IF_ERROR_RETURN
   1118         (phymod_phy_autoneg_set(&phy->pm_phy, &an));
   1119 
   1120     return (SOC_E_NONE);
   1121 }
   1122 
   1123 /*
   1124  * Function:    
   1125  *      phy_viper_an_get
   1126  * Purpose:     
   1127  *      Get the current auto-negotiation status (enabled/busy)
   1128  * Parameters:
   1129  *      unit - BCM unit number.
   1130  *      port - Port number. 
   1131  *      an   - (OUT) if true, auto-negotiation is enabled.
   1132  *      an_done - (OUT) if true, auto-negotiation is complete. This
   1133  *              value is undefined if an == false.
   1134  * Returns:     
   1135  *      SOC_E_XXX
   1136  */
   1137 
   1138 STATIC int
   1139 phy_viper_an_get(int unit, soc_port_t port, int *an, int *an_done)
   1140 {
   1141     phy_ctrl_t* pc; 
   1142     soc_phymod_ctrl_t *pmc;
   1143     phymod_phy_access_t *pm_phy;
   1144     phymod_autoneg_control_t an_control;
   1145     int idx, an_complete;
   1146 
   1147     pc = INT_PHY_SW_STATE(unit, port);
   1148     pmc = &pc->phymod_ctrl;
   1149 
   1150     sal_memset(&an_control, 0x0, sizeof(an_control));
   1151 
   1152     idx = pmc->main_phy;
   1153     pm_phy = &pmc->phy[idx]->pm_phy;
   1154     SOC_IF_ERROR_RETURN
   1155         (phymod_phy_autoneg_get(pm_phy, &an_control, (uint32_t *) &an_complete)); 
   1156 
   1157     if (an_control.enable) {
   1158         *an = 1;
   1159         *an_done = an_complete;
   1160     } else {
   1161         *an = 0;
   1162         *an_done = 0;
   1163     }
   1164 
   1165     return (SOC_E_NONE);
   1166 }
   1167 
   1168 /*
   1169  * Function:
   1170  *      phy_viper_ability_advert_set
   1171  * Purpose:
   1172  *      Set the current advertisement for auto-negotiation.
   1173  * Parameters:
   1174  *      unit - BCM unit number.
   1175  *      port - Port number.
   1176  *      ability - Port mode mask indicating supported options/speeds.
   1177  * Returns:
   1178  *      SOC_E_XXX
   1179  * Notes:
   1180  *      The advertisement is set only for the ACTIVE medium.
   1181  *      No synchronization performed at this level.
   1182  */
   1183 
   1184 STATIC int
   1185 phy_viper_ability_advert_set(int unit, soc_port_t port,
   1186                           soc_port_ability_t *ability)
   1187 {
   1188     phy_ctrl_t                *pc;
   1189     viper_config_t            *pCfg;
   1190     soc_phymod_ctrl_t         *pmc;
   1191     soc_phymod_phy_t          *phy;
   1192     phymod_autoneg_ability_t  phymod_autoneg_ability; 
   1193 
   1194     /* locate phy control */
   1195     pc = INT_PHY_SW_STATE(unit, port);
   1196     if (pc == NULL) {
   1197         return SOC_E_INTERNAL;
   1198     }
   1199 
   1200     phymod_autoneg_ability_t_init(&phymod_autoneg_ability);
   1201 
   1202     pmc = &pc->phymod_ctrl;
   1203     pCfg = (viper_config_t *) pc->driver_data;
   1204 
   1205     /* only set abilities on the first core */
   1206     phy = pmc->phy[pmc->main_phy];
   1207     if (phy == NULL) {
   1208         return SOC_E_INTERNAL;
   1209     }
   1210 
   1211 
   1212     switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) {
   1213     case SOC_PA_PAUSE_TX:
   1214         PHYMOD_AN_CAP_ASYM_PAUSE_SET(&phymod_autoneg_ability);
   1215         break;
   1216     case SOC_PA_PAUSE_RX:
   1217         /* an_adv |= MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE; */
   1218         PHYMOD_AN_CAP_ASYM_PAUSE_SET(&phymod_autoneg_ability);
   1219         PHYMOD_AN_CAP_SYMM_PAUSE_SET(&phymod_autoneg_ability);
   1220         break;
   1221     case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX:
   1222         PHYMOD_AN_CAP_SYMM_PAUSE_SET(&phymod_autoneg_ability);
   1223         break;
   1224     }
   1225 
   1226     /* Set 1000MB CL37*/
   1227     if (pCfg->cl37an){
   1228         if(ability->speed_full_duplex & SOC_PA_SPEED_1000MB) {
   1229             PHYMOD_AN_CAP_CL37_SET(&phymod_autoneg_ability);
   1230         }
   1231     } else {
   1232         /* set the sgmii speed */
   1233         if(ability->speed_full_duplex & SOC_PA_SPEED_1000MB) {
   1234             PHYMOD_AN_CAP_SGMII_SET(&phymod_autoneg_ability);
   1235             phymod_autoneg_ability.sgmii_speed = phymod_CL37_SGMII_1000M;
   1236         } else if(ability->speed_full_duplex & SOC_PA_SPEED_100MB) {
   1237             PHYMOD_AN_CAP_SGMII_SET(&phymod_autoneg_ability);
   1238             phymod_autoneg_ability.sgmii_speed = phymod_CL37_SGMII_100M;
   1239         } else if(ability->speed_full_duplex & SOC_PA_SPEED_10MB) {
   1240             PHYMOD_AN_CAP_SGMII_SET(&phymod_autoneg_ability);
   1241             phymod_autoneg_ability.sgmii_speed = phymod_CL37_SGMII_10M;
   1242         } else {
   1243             PHYMOD_AN_CAP_SGMII_SET(&phymod_autoneg_ability);
   1244             phymod_autoneg_ability.sgmii_speed = phymod_CL37_SGMII_1000M;
   1245        }
   1246 
   1247     }
   1248 
   1249     SOC_IF_ERROR_RETURN
   1250         (phymod_phy_autoneg_ability_set(&phy->pm_phy, &phymod_autoneg_ability));
   1251 
   1252     return SOC_E_NONE;
   1253 }
   1254 
   1255 /*
   1256  * Function:
   1257  *      phy_viper_ability_advert_get
   1258  * Purpose:
   1259  *      Get the current advertisement for auto-negotiation.
   1260  * Parameters:
   1261  *      unit - BCM unit number.
   1262  *      port - Port number.
   1263  *      ability - (OUT) Port mode mask indicating supported options/speeds.
   1264  * Returns:
   1265  *      SOC_E_XXX
   1266  * Notes:
   1267  *      The advertisement is retrieved for the ACTIVE medium.
   1268  *      No synchronization performed at this level.
   1269  */
   1270 
   1271 STATIC int
   1272 phy_viper_ability_advert_get(int unit, soc_port_t port,
   1273                               soc_port_ability_t *ability)
   1274 {
   1275     phy_ctrl_t                *pc;
   1276     soc_phymod_ctrl_t         *pmc;
   1277     soc_phymod_phy_t          *phy;
   1278     int                       reg_ability;
   1279     _shr_port_mode_t          speed_full_duplex;
   1280     phymod_autoneg_ability_t  phymod_autoneg_ability; 
   1281     phymod_cl37_sgmii_speed_t cl37_sgmii_speed;
   1282 
   1283     /* locate phy control */
   1284     pc = INT_PHY_SW_STATE(unit, port);
   1285     if (pc == NULL) {
   1286         return SOC_E_INTERNAL;
   1287     }
   1288 
   1289     pmc = &pc->phymod_ctrl;
   1290 
   1291     /* only get abilities from the first core */
   1292     phy = pmc->phy[pmc->main_phy];
   1293     if (phy == NULL) {
   1294         return SOC_E_INTERNAL;
   1295     }
   1296 
   1297     phymod_autoneg_ability_t_init(&phymod_autoneg_ability);
   1298     SOC_IF_ERROR_RETURN
   1299         (phymod_phy_autoneg_ability_get(&phy->pm_phy, &phymod_autoneg_ability));
   1300     
   1301     cl37_sgmii_speed = phymod_autoneg_ability.sgmii_speed;
   1302     reg_ability = phymod_autoneg_ability.capabilities;
   1303     speed_full_duplex = 0;
   1304 
   1305     /* retrieve CL37 abilities */
   1306     if (reg_ability == PHYMOD_AN_CAP_CL37){
   1307         speed_full_duplex|= SOC_PA_SPEED_1000MB;
   1308     }
   1309 
   1310     /* retrieve sgmii speed */
   1311     if (cl37_sgmii_speed == phymod_CL37_SGMII_1000M){
   1312         speed_full_duplex|= SOC_PA_SPEED_1000MB;
   1313     } else if (cl37_sgmii_speed == phymod_CL37_SGMII_100M){
   1314         speed_full_duplex|= SOC_PA_SPEED_100MB;
   1315     } else if (cl37_sgmii_speed == phymod_CL37_SGMII_10M){
   1316         speed_full_duplex|= SOC_PA_SPEED_10MB;
   1317     } else {
   1318         speed_full_duplex|= 0;
   1319     }
   1320 
   1321     /* retrieve "pause" abilities */
   1322     ability->pause = 0;
   1323     if (reg_ability == PHYMOD_AN_CAP_ASYM_PAUSE) {
   1324         ability->pause = SOC_PA_PAUSE_TX;
   1325     } else if (reg_ability == (PHYMOD_AN_CAP_SYMM_PAUSE|PHYMOD_AN_CAP_ASYM_PAUSE)) {
   1326         ability->pause = SOC_PA_PAUSE_RX;
   1327     } else if (reg_ability == PHYMOD_AN_CAP_SYMM_PAUSE) {
   1328         ability->pause = (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX);
   1329     }
   1330 
   1331     ability->speed_full_duplex = speed_full_duplex;
   1332 
   1333     return SOC_E_NONE;
   1334 }
   1335 
   1336 /*
   1337  * Function:
   1338  *      phy_viper_ability_remote_get
   1339  * Purpose:
   1340  *      Get the current advertisement for auto-negotiation.
   1341  * Parameters:
   1342  *      unit - BCM unit number.
   1343  *      port - Port number.
   1344  *      ability - (OUT) Port mode mask indicating supported options/speeds.
   1345  * Returns:
   1346  *      SOC_E_XXX
   1347  * Notes:
   1348  *      The advertisement is retrieved for the ACTIVE medium.
   1349  *      No synchronization performed at this level.
   1350  */
   1351 
   1352 STATIC int
   1353 phy_viper_ability_remote_get(int unit, soc_port_t port,
   1354                                soc_port_ability_t *ability)
   1355 {
   1356     phy_ctrl_t                *pc;
   1357     soc_phymod_ctrl_t         *pmc;
   1358     soc_phymod_phy_t          *phy;
   1359     int                       reg37_ability;
   1360     int                       reg_ability;
   1361     _shr_port_mode_t          speed_full_duplex;
   1362     phymod_autoneg_ability_t  phymod_autoneg_ability; 
   1363 
   1364     /* locate phy control */
   1365     pc = INT_PHY_SW_STATE(unit, port);
   1366     if (pc == NULL) {
   1367         return SOC_E_INTERNAL;
   1368     }
   1369 
   1370     pmc = &pc->phymod_ctrl;
   1371 
   1372     /* only get abilities from the first core */
   1373     phy = pmc->phy[pmc->main_phy];
   1374     if (phy == NULL) {
   1375         return SOC_E_INTERNAL;
   1376     }
   1377 
   1378     phymod_autoneg_ability_t_init(&phymod_autoneg_ability);
   1379     SOC_IF_ERROR_RETURN
   1380         (phymod_phy_autoneg_remote_ability_get(&phy->pm_phy, &phymod_autoneg_ability));
   1381 
   1382     speed_full_duplex = 0;
   1383 
   1384     /* retrieve CL37 abilities */
   1385     reg37_ability = phymod_autoneg_ability.an_cap;
   1386     speed_full_duplex|= PHYMOD_AN_CAP_1G_KX_GET(reg37_ability)? SOC_PA_SPEED_1000MB : 0;
   1387     speed_full_duplex|= SOC_PA_SPEED_1000MB ;
   1388 
   1389     /* retrieve "pause" abilities */
   1390     reg_ability = phymod_autoneg_ability.capabilities;
   1391 
   1392     ability->pause = 0;
   1393     if (reg_ability == PHYMOD_AN_CAP_ASYM_PAUSE) {
   1394         ability->pause = SOC_PA_PAUSE_TX;
   1395     } else if (reg_ability == (PHYMOD_AN_CAP_SYMM_PAUSE|PHYMOD_AN_CAP_ASYM_PAUSE)) {
   1396         ability->pause = SOC_PA_PAUSE_RX;
   1397     } else if (reg_ability == PHYMOD_AN_CAP_SYMM_PAUSE) {
   1398         ability->pause = (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX);
   1399     }
   1400 
   1401     ability->speed_full_duplex = speed_full_duplex;
   1402 
   1403     return SOC_E_NONE;
   1404 }
   1405 
   1406 /*
   1407  * Function:
   1408  *      phy_viper_lb_set
   1409  * Purpose:
   1410  *      Enable/disable PHY loopback mode
   1411  * Parameters:
   1412  *      unit - BCM unit number.
   1413  *      port - Port number. 
   1414  *      enable - binary value for on/off (1/0)
   1415  * Returns:     
   1416  *      SOC_E_NONE
   1417  */
   1418 STATIC int
   1419 phy_viper_lb_set(int unit, soc_port_t port, int enable)
   1420 {
   1421     phy_ctrl_t* pc; 
   1422     soc_phymod_ctrl_t *pmc;
   1423     phymod_phy_access_t *pm_phy;
   1424     int idx;
   1425 
   1426     pc = INT_PHY_SW_STATE(unit, port);
   1427     pmc = &pc->phymod_ctrl;
   1428 
   1429     for (idx = 0; idx < pmc->num_phys; idx++) {
   1430         pm_phy = &pmc->phy[idx]->pm_phy;
   1431         SOC_IF_ERROR_RETURN
   1432             (phymod_phy_loopback_set(pm_phy, phymodLoopbackGlobal, enable)); 
   1433     }
   1434 
   1435     return (SOC_E_NONE);
   1436 }
   1437 
   1438 /*
   1439  * Function:
   1440  *      phy_viper_lb_get
   1441  * Purpose:
   1442  *      Get current PHY loopback mode
   1443  * Parameters:
   1444  *      unit - BCM unit number.
   1445  *      port - Port number. 
   1446  *      enable - address of location to store binary value for on/off (1/0)
   1447  * Returns:     
   1448  *      SOC_E_NONE
   1449  */
   1450 STATIC int
   1451 phy_viper_lb_get(int unit, soc_port_t port, int *enable)
   1452 {
   1453     phy_ctrl_t* pc; 
   1454     soc_phymod_ctrl_t *pmc;
   1455     phymod_phy_access_t *pm_phy;
   1456     uint32 lb_enable;
   1457 
   1458     pc = INT_PHY_SW_STATE(unit, port);
   1459     pmc = &pc->phymod_ctrl;
   1460 
   1461     *enable = 0;
   1462 
   1463     /* Check first PHY only */
   1464     pm_phy = &pmc->phy[0]->pm_phy;
   1465     SOC_IF_ERROR_RETURN
   1466         (phymod_phy_loopback_get(pm_phy, phymodLoopbackGlobal, &lb_enable));
   1467     if (lb_enable) {
   1468         *enable = 1;
   1469     }
   1470      
   1471     return (SOC_E_NONE);
   1472 }
   1473 
   1474 /*
   1475  * Function:
   1476  *      phy_viper_ability_local_get
   1477  * Purpose:
   1478  *      xx
   1479  * Parameters:
   1480  *      unit - BCM unit number.
   1481  *      port - Port number. 
   1482  *      ability - xx
   1483  * Returns:     
   1484  *      SOC_E_NONE
   1485  */
   1486 STATIC int
   1487 phy_viper_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   1488 {
   1489     phy_ctrl_t          *pc; 
   1490     viper_config_t             *pCfg;
   1491 
   1492     pc = INT_PHY_SW_STATE(unit, port);
   1493     pCfg = (viper_config_t *) pc->driver_data;
   1494 
   1495     if (NULL == ability) {
   1496         return SOC_E_PARAM;
   1497     }
   1498 
   1499     sal_memset(ability, 0, sizeof(*ability));
   1500 
   1501     ability->loopback  = SOC_PA_LB_PHY;
   1502     ability->medium    = SOC_PA_MEDIUM_FIBER;
   1503     ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   1504     ability->flags     = SOC_PA_AUTONEG;
   1505 
   1506     if (IND_LANE_MODE(pc)) { 
   1507         ability->speed_full_duplex  = SOC_PA_SPEED_1000MB;
   1508         if (pCfg->speed_config.fiber_pref) {
   1509             ability->speed_full_duplex  |= SOC_PA_SPEED_100MB;
   1510             if (pc->speed_max >= 2500) {
   1511                 ability->speed_full_duplex  |= SOC_PA_SPEED_2500MB;
   1512             }
   1513             ability->speed_half_duplex  = SOC_PA_SPEED_100MB;
   1514         } else {
   1515             ability->speed_full_duplex  |= SOC_PA_SPEED_10MB |
   1516                                            SOC_PA_SPEED_100MB;
   1517             ability->speed_half_duplex  = SOC_PA_SPEED_10MB |
   1518                                           SOC_PA_SPEED_100MB;
   1519         } 
   1520         ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   1521         ability->interface = SOC_PA_INTF_GMII | SOC_PA_INTF_SGMII;
   1522         ability->medium    = SOC_PA_MEDIUM_FIBER;
   1523         ability->eee       = SOC_PA_ABILITY_NONE;
   1524         ability->loopback  = SOC_PA_LB_PHY;
   1525         ability->flags     = SOC_PA_AUTONEG;
   1526     } else {
   1527         if (pCfg->speed_config.fiber_pref) {
   1528             ability->speed_half_duplex  = SOC_PA_SPEED_100MB;
   1529         } else {
   1530             ability->speed_half_duplex  = SOC_PA_SPEED_10MB |
   1531                                           SOC_PA_SPEED_100MB;
   1532         }
   1533         ability->speed_full_duplex = SOC_PA_SPEED_10GB;
   1534         ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   1535         ability->interface = SOC_PA_INTF_XGMII;
   1536         ability->medium    = SOC_PA_MEDIUM_FIBER;
   1537         ability->loopback  = SOC_PA_LB_PHY;
   1538         ability->eee       = SOC_PA_ABILITY_NONE;
   1539         ability->flags     = SOC_PA_ABILITY_NONE;
   1540     }
   1541 
   1542     LOG_INFO(BSL_LS_SOC_PHY,
   1543              (BSL_META_U(pc->unit,
   1544                          "phy_viper_ability_local_get:unit=%d p=%d sp=%08x\n"),
   1545               unit, port, ability->speed_full_duplex));
   1546     return (SOC_E_NONE);
   1547 }
   1548 
   1549 
   1550 STATIC int
   1551 phy_viper_interface_set(int unit, soc_port_t port, soc_port_if_t pif)
   1552 {
   1553     phy_ctrl_t      *pc;
   1554     viper_config_t *pCfg;
   1555 
   1556     pc = INT_PHY_SW_STATE(unit, port);
   1557     pCfg = (viper_config_t *) pc->driver_data;
   1558 
   1559     pCfg->speed_config.line_interface = (uint32) pif;
   1560 
   1561     if (pif == SOC_PORT_IF_GMII) {
   1562         pCfg->speed_config.fiber_pref = 1;
   1563     } else if (pif == SOC_PORT_IF_SGMII){
   1564         pCfg->speed_config.fiber_pref = 0;
   1565     }
   1566 
   1567     return SOC_E_NONE;
   1568 }
   1569 
   1570 STATIC int
   1571 phy_viper_interface_get(int unit, soc_port_t port, soc_port_if_t *pif)
   1572 {
   1573     phy_ctrl_t                  *pc;
   1574     soc_phymod_ctrl_t           *pmc;
   1575     soc_phymod_phy_t            *phy;
   1576     phymod_phy_inf_config_t     interface_config;
   1577     viper_config_t               *pCfg;
   1578     int                         flag = 0;
   1579     phymod_ref_clk_t            ref_clock = phymodRefClk156Mhz;
   1580 
   1581     /* locate phy control */
   1582     pc = INT_PHY_SW_STATE(unit, port);
   1583     if (pc == NULL) {
   1584         return SOC_E_INTERNAL;
   1585     }
   1586     pCfg = (viper_config_t *) pc->driver_data;
   1587 
   1588     pmc = &pc->phymod_ctrl;
   1589 
   1590     /* initialize the data structure */
   1591     sal_memset(&interface_config, 0x0, sizeof(phymod_phy_inf_config_t));
   1592 
   1593     /* now loop through all cores */
   1594     phy = pmc->phy[pmc->main_phy];
   1595     if (phy == NULL) {
   1596         return SOC_E_INTERNAL;
   1597     }
   1598 
   1599     /* note that the flags have an option to indicate whether it's ok to reprogram the PLL */
   1600     SOC_IF_ERROR_RETURN
   1601         (phymod_phy_interface_config_get(&phy->pm_phy,
   1602                                          flag, ref_clock, &interface_config));
   1603     switch (interface_config.interface_type) {
   1604     case phymodInterfaceXAUI:
   1605         *pif = _SHR_PORT_IF_XAUI;
   1606         break;
   1607     case phymodInterface1000X:
   1608         *pif = SOC_PORT_IF_GMII;
   1609         break;
   1610     case phymodInterfaceKX:
   1611         *pif = SOC_PORT_IF_KX;
   1612         break;
   1613     case phymodInterfaceSGMII:
   1614     {
   1615         if(interface_config.data_rate == 1000) {
   1616             if (PHY_EXTERNAL_MODE(unit, port) || !(pCfg->speed_config.fiber_pref)) {
   1617                 *pif = SOC_PORT_IF_SGMII;
   1618             } else {
   1619                 *pif = SOC_PORT_IF_GMII;
   1620             }
   1621         } else {
   1622             *pif = SOC_PORT_IF_SGMII;
   1623         }
   1624         break;
   1625     }
   1626     default:
   1627         *pif =  SOC_PORT_IF_SGMII;
   1628         break;
   1629     }
   1630 
   1631     return (SOC_E_NONE);
   1632 
   1633 }
   1634 
   1635 
   1636 /*
   1637  * Function:
   1638  *      viper_pcs_status_dump
   1639  * Purpose:
   1640  *      display all the serdes related parameters
   1641  * Parameters:
   1642  *      unit - BCM unit number.
   1643  *      port - Port number. 
   1644 
   1645  * Returns:     
   1646  *      SOC_E_NONE
   1647  */
   1648 STATIC int
   1649 viper_pcs_status_dump(int unit, soc_port_t port, void *arg)
   1650 {
   1651     phy_ctrl_t* pc; 
   1652     soc_phymod_ctrl_t *pmc;
   1653     phymod_phy_access_t *pm_phy;
   1654     int idx;
   1655 
   1656     pc = INT_PHY_SW_STATE(unit, port);
   1657     pmc = &pc->phymod_ctrl;
   1658 
   1659     for (idx = 0; idx < pmc->num_phys; idx++) {
   1660         pm_phy = &pmc->phy[idx]->pm_phy;
   1661         SOC_IF_ERROR_RETURN
   1662             (phymod_phy_pcs_info_dump(pm_phy, arg)); 
   1663     }
   1664     return (SOC_E_NONE);
   1665 }
   1666 
   1667 
   1668 /* 
   1669  * given a pc (phymod_ctrl_t) and logical lane number, 
   1670  *    find the correct soc_phymod_phy_t object and lane
   1671  */
   1672 STATIC int
   1673 _viper_find_soc_phy_lane(soc_phymod_ctrl_t *pmc, uint32_t lane, 
   1674                         soc_phymod_phy_t **p_phy, uint32 *lane_map)
   1675 {
   1676     phymod_phy_access_t *pm_phy;
   1677     int idx, lnx, ln_cnt, found;
   1678     uint32 lane_map_copy;
   1679 
   1680     /* Traverse lanes belonging to this port */
   1681     found = 0;
   1682     ln_cnt = 0;
   1683     for (idx = 0; idx < pmc->num_phys; idx++) {
   1684         pm_phy = &pmc->phy[idx]->pm_phy;
   1685         if (pm_phy == NULL) {
   1686             return SOC_E_INTERNAL;
   1687         }
   1688         lane_map_copy = pm_phy->access.lane_mask;
   1689         for (lnx = 0; lnx < 4; lnx++) {
   1690             if ((1 << lnx) & lane_map_copy) {
   1691                 if (ln_cnt == lane) {
   1692                     found = 1;
   1693                     break;
   1694                 }
   1695                 ln_cnt++;
   1696             }
   1697         }
   1698         if (found) {
   1699             *p_phy = pmc->phy[idx];
   1700             *lane_map = (1 << lnx);
   1701             break;
   1702         }
   1703     } 
   1704 
   1705     if (!found) {
   1706         /* No such lane */
   1707         return SOC_E_PARAM;
   1708     }
   1709     return (SOC_E_NONE);
   1710 }
   1711 
   1712 /* 
   1713  * viper_per_lane_preemphasis_set
   1714  */
   1715 STATIC int
   1716 viper_per_lane_preemphasis_set(soc_phymod_ctrl_t *pmc, int lane, uint32 value)
   1717 {
   1718     soc_phymod_phy_t    *p_phy;
   1719     uint32              lane_map;
   1720     phymod_phy_access_t pm_phy_copy, *pm_phy;
   1721     phymod_tx_t         phymod_tx;
   1722 
   1723     /* locate the desired phy and lane */
   1724     SOC_IF_ERROR_RETURN(_viper_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map));
   1725 
   1726     /* Make a copy of the phy access and overwrite the desired lane */
   1727     pm_phy = &p_phy->pm_phy;
   1728     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   1729     pm_phy_copy.access.lane_mask = lane_map;
   1730 
   1731     SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   1732     phymod_tx.main = (value >> 8) & 0xff;
   1733     phymod_tx.post = (value >> 16) & 0xff;
   1734     SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx));
   1735 
   1736     return(SOC_E_NONE);
   1737 }
   1738 
   1739 /* 
   1740  * viper_preemphasis_set
   1741  */
   1742 STATIC int
   1743 viper_preemphasis_set(soc_phymod_ctrl_t *pmc, uint32 value)
   1744 {
   1745     phymod_phy_access_t *pm_phy;
   1746     phymod_tx_t         phymod_tx;
   1747     int                 idx;
   1748 
   1749     /* loop through all cores */
   1750     for (idx = 0; idx < pmc->num_phys; idx++) {
   1751         pm_phy = &pmc->phy[idx]->pm_phy;
   1752 
   1753         if (pm_phy == NULL) {
   1754             return SOC_E_INTERNAL;
   1755         }
   1756 
   1757         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(pm_phy, &phymod_tx));
   1758         phymod_tx.main = (value >> 8) & 0xff;
   1759         phymod_tx.post = (value >> 16) & 0xff;
   1760         SOC_IF_ERROR_RETURN(phymod_phy_tx_set(pm_phy, &phymod_tx));
   1761 
   1762     }
   1763 
   1764     return(SOC_E_NONE);
   1765 }
   1766 
   1767 /* 
   1768  * viper_tx_fir_main_set
   1769  */
   1770 STATIC int
   1771 viper_tx_fir_main_set(soc_phymod_ctrl_t *pmc, uint32 value)
   1772 {
   1773     phymod_phy_access_t *pm_phy;
   1774     phymod_tx_t         phymod_tx;
   1775     int                 idx;
   1776 
   1777     /* loop through all cores */
   1778     for (idx = 0; idx < pmc->num_phys; idx++) {
   1779         pm_phy = &pmc->phy[idx]->pm_phy;
   1780 
   1781         if (pm_phy == NULL) {
   1782             return SOC_E_INTERNAL;
   1783         }
   1784 
   1785         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(pm_phy, &phymod_tx));
   1786         phymod_tx.main = value;
   1787         SOC_IF_ERROR_RETURN(phymod_phy_tx_set(pm_phy, &phymod_tx));
   1788     }
   1789 
   1790     return(SOC_E_NONE);
   1791 }
   1792 
   1793 /* 
   1794  * viper_tx_fir_post_set
   1795  */
   1796 STATIC int
   1797 viper_tx_fir_post_set(soc_phymod_ctrl_t *pmc, uint32 value)
   1798 {
   1799     phymod_phy_access_t *pm_phy;
   1800     phymod_tx_t         phymod_tx;
   1801     int                 idx;
   1802 
   1803     /* loop through all cores */
   1804     for (idx = 0; idx < pmc->num_phys; idx++) {
   1805         pm_phy = &pmc->phy[idx]->pm_phy;
   1806 
   1807         if (pm_phy == NULL) {
   1808             return SOC_E_INTERNAL;
   1809         }
   1810 
   1811         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(pm_phy, &phymod_tx));
   1812         phymod_tx.post = value;  
   1813         SOC_IF_ERROR_RETURN(phymod_phy_tx_set(pm_phy, &phymod_tx));
   1814     }
   1815 
   1816     return(SOC_E_NONE);
   1817 }
   1818 
   1819 #if 0
   1820 /* 
   1821  * viper_tx_fir_post2_set
   1822  */
   1823 STATIC int
   1824 viper_tx_fir_post2_set(soc_phymod_ctrl_t *pmc, uint32 value)
   1825 {
   1826     phymod_phy_access_t *pm_phy;
   1827     phymod_tx_t         phymod_tx;
   1828     int                 idx;
   1829 
   1830     /* loop through all cores */
   1831     for (idx = 0; idx < pmc->num_phys; idx++) {
   1832         pm_phy = &pmc->phy[idx]->pm_phy;
   1833 
   1834         if (pm_phy == NULL) {
   1835             return SOC_E_INTERNAL;
   1836         }
   1837 
   1838         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(pm_phy, &phymod_tx));
   1839         phymod_tx.post2 = value;
   1840         SOC_IF_ERROR_RETURN(phymod_phy_tx_set(pm_phy, &phymod_tx));
   1841     }
   1842 
   1843     return(SOC_E_NONE);
   1844 }
   1845 
   1846 /* 
   1847  * viper_tx_fir_post3_set
   1848  */
   1849 STATIC int
   1850 viper_tx_fir_post3_set(soc_phymod_ctrl_t *pmc, uint32 value)
   1851 {
   1852     phymod_phy_access_t *pm_phy;
   1853     phymod_tx_t         phymod_tx;
   1854     int                 idx;
   1855 
   1856     /* loop through all cores */
   1857     for (idx = 0; idx < pmc->num_phys; idx++) {
   1858         pm_phy = &pmc->phy[idx]->pm_phy;
   1859 
   1860         if (pm_phy == NULL) {
   1861             return SOC_E_INTERNAL;
   1862         }
   1863 
   1864         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(pm_phy, &phymod_tx));
   1865         phymod_tx.post3 = value;
   1866         SOC_IF_ERROR_RETURN(phymod_phy_tx_set(pm_phy, &phymod_tx));
   1867     }
   1868 
   1869     return(SOC_E_NONE);
   1870 }
   1871 #endif
   1872 
   1873 
   1874 /* 
   1875  * viper_per_lane_rx_dfe_tap_control_set
   1876  */
   1877 STATIC int
   1878 viper_per_lane_rx_dfe_tap_control_set(soc_phymod_ctrl_t *pmc, int lane, int tap, int enable, uint32 value)
   1879 {
   1880     soc_phymod_phy_t    *p_phy;
   1881     uint32              lane_map;
   1882     phymod_phy_access_t pm_phy_copy, *pm_phy;
   1883     phymod_rx_t          phymod_rx;
   1884 
   1885     /* locate the desired phy and lane */
   1886     SOC_IF_ERROR_RETURN(_viper_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map));
   1887 
   1888     /* Make a copy of the phy access and overwrite the desired lane */
   1889     pm_phy = &p_phy->pm_phy;
   1890     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   1891     pm_phy_copy.access.lane_mask = lane_map;
   1892 
   1893     if (tap < 0 || tap >= COUNTOF(phymod_rx.dfe)) {
   1894         /* this can only happen with a coding error */
   1895         return SOC_E_INTERNAL;
   1896     }
   1897 
   1898     SOC_IF_ERROR_RETURN(phymod_phy_rx_get(&pm_phy_copy, &phymod_rx));
   1899     phymod_rx.dfe[tap].enable = enable;
   1900     phymod_rx.dfe[tap].value = value;
   1901     SOC_IF_ERROR_RETURN(phymod_phy_rx_set(&pm_phy_copy, &phymod_rx));
   1902 
   1903     return(SOC_E_NONE);
   1904 }
   1905 
   1906 
   1907 /* 
   1908  * viper_tx_lane_squelch
   1909  */
   1910 STATIC int
   1911 viper_tx_lane_squelch(soc_phymod_ctrl_t *pmc, uint32 value)
   1912 {
   1913     phymod_phy_access_t *pm_phy;
   1914     phymod_phy_tx_lane_control_t  tx_control;
   1915     int                 idx;
   1916 
   1917     /* loop through all cores */
   1918     for (idx = 0; idx < pmc->num_phys; idx++) {
   1919         pm_phy = &pmc->phy[idx]->pm_phy;
   1920 
   1921         if (pm_phy == NULL) {
   1922             return SOC_E_INTERNAL;
   1923         }
   1924 
   1925         if (value == 1) {
   1926             tx_control = phymodTxSquelchOn;
   1927         } else {
   1928             tx_control = phymodTxSquelchOff;
   1929         }
   1930         SOC_IF_ERROR_RETURN
   1931             (phymod_phy_tx_lane_control_set(pm_phy, tx_control));
   1932     }
   1933     return(SOC_E_NONE);
   1934 }
   1935 
   1936 /* 
   1937  * viper_per_lane_rx_peak_filter_set
   1938  */
   1939 STATIC int
   1940 viper_per_lane_rx_peak_filter_set(soc_phymod_ctrl_t *pmc, int lane, int enable, uint32 value)
   1941 {
   1942     soc_phymod_phy_t    *p_phy;
   1943     uint32              lane_map;
   1944     phymod_phy_access_t pm_phy_copy, *pm_phy;
   1945     phymod_rx_t         phymod_rx;
   1946 
   1947     /* locate the desired phy and lane */
   1948     SOC_IF_ERROR_RETURN(_viper_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map));
   1949 
   1950     /* Make a copy of the phy access and overwrite the desired lane */
   1951     pm_phy = &p_phy->pm_phy;
   1952     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   1953     pm_phy_copy.access.lane_mask = lane_map;
   1954 
   1955     SOC_IF_ERROR_RETURN(phymod_phy_rx_get(&pm_phy_copy, &phymod_rx));
   1956     phymod_rx.peaking_filter.enable = TRUE;
   1957     phymod_rx.peaking_filter.value = value;
   1958     SOC_IF_ERROR_RETURN(phymod_phy_rx_set(pm_phy, &phymod_rx));
   1959 
   1960     return(SOC_E_NONE);
   1961 }
   1962 
   1963 /* 
   1964  * viper_rx_peak_filter_set
   1965  */
   1966 STATIC int 
   1967 viper_rx_peak_filter_set(soc_phymod_ctrl_t *pmc, uint32 value)
   1968 {
   1969     phymod_phy_access_t *pm_phy;
   1970     phymod_rx_t         phymod_rx;
   1971     int                 idx;
   1972 
   1973     /* loop through all cores */
   1974     for (idx = 0; idx < pmc->num_phys; idx++) {
   1975         pm_phy = &pmc->phy[idx]->pm_phy;
   1976 
   1977         if (pm_phy == NULL) {
   1978             return SOC_E_INTERNAL;
   1979         }
   1980 
   1981         SOC_IF_ERROR_RETURN(phymod_phy_rx_get(pm_phy, &phymod_rx));
   1982         phymod_rx.peaking_filter.enable = TRUE;
   1983         phymod_rx.peaking_filter.value = value;
   1984         SOC_IF_ERROR_RETURN(phymod_phy_rx_set(pm_phy, &phymod_rx));
   1985     }
   1986 
   1987     return(SOC_E_NONE);
   1988 }
   1989 
   1990 /* 
   1991  * viper_per_lane_rx_vga_set
   1992  */
   1993 STATIC int
   1994 viper_per_lane_rx_vga_set(soc_phymod_ctrl_t *pmc, int lane, int enable, uint32 value)
   1995 {
   1996     soc_phymod_phy_t    *p_phy;
   1997     uint32              lane_map;
   1998     phymod_phy_access_t pm_phy_copy, *pm_phy;
   1999     phymod_rx_t         phymod_rx;
   2000 
   2001     /* locate the desired phy and lane */
   2002     SOC_IF_ERROR_RETURN(_viper_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map));
   2003 
   2004     /* Make a copy of the phy access and overwrite the desired lane */
   2005     pm_phy = &p_phy->pm_phy;
   2006     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   2007     pm_phy_copy.access.lane_mask = lane_map;
   2008 
   2009     SOC_IF_ERROR_RETURN(phymod_phy_rx_get(&pm_phy_copy, &phymod_rx));
   2010     phymod_rx.vga.enable = TRUE;
   2011     phymod_rx.vga.value = value;
   2012     SOC_IF_ERROR_RETURN(phymod_phy_rx_set(pm_phy, &phymod_rx));
   2013 
   2014     return(SOC_E_NONE);
   2015 }
   2016 
   2017 
   2018 STATIC int
   2019 viper_rx_tap_release(soc_phymod_ctrl_t *pmc, int tap)
   2020 {
   2021     phymod_phy_access_t *pm_phy;
   2022     phymod_rx_t         phymod_rx;
   2023     int                 idx;
   2024 
   2025     /* bounds check "tap" */
   2026     if (tap < 0 || tap >= COUNTOF(phymod_rx.dfe)) {
   2027         return SOC_E_INTERNAL;
   2028     }
   2029 
   2030     /* loop through all cores */
   2031     for (idx = 0; idx < pmc->num_phys; idx++) {
   2032         pm_phy = &pmc->phy[idx]->pm_phy;
   2033 
   2034         if (pm_phy == NULL) {
   2035             return SOC_E_INTERNAL;
   2036         }
   2037         SOC_IF_ERROR_RETURN(phymod_phy_rx_get(pm_phy, &phymod_rx));
   2038         phymod_rx.dfe[tap].enable = FALSE;
   2039         SOC_IF_ERROR_RETURN(phymod_phy_rx_set(pm_phy, &phymod_rx));
   2040     }
   2041     return(SOC_E_NONE);
   2042 }
   2043 
   2044 /* 
   2045  * viper_rx_tap_set
   2046  */
   2047 STATIC int 
   2048 viper_rx_tap_set(soc_phymod_ctrl_t *pmc, int tap, uint32 value)
   2049 {
   2050     phymod_phy_access_t *pm_phy;
   2051     phymod_rx_t         phymod_rx;
   2052     int                 idx;
   2053 
   2054     /* bounds check "tap" */
   2055     if (tap < 0 || tap >= COUNTOF(phymod_rx.dfe)) {
   2056         return SOC_E_INTERNAL;
   2057     }
   2058 
   2059     /* loop through all cores */
   2060     for (idx = 0; idx < pmc->num_phys; idx++) {
   2061         pm_phy = &pmc->phy[idx]->pm_phy;
   2062 
   2063         if (pm_phy == NULL) {
   2064             return SOC_E_INTERNAL;
   2065         }
   2066         SOC_IF_ERROR_RETURN(phymod_phy_rx_get(pm_phy, &phymod_rx));
   2067         phymod_rx.dfe[tap].enable = TRUE;
   2068         phymod_rx.dfe[tap].value = value;
   2069         SOC_IF_ERROR_RETURN(phymod_phy_rx_set(pm_phy, &phymod_rx));
   2070     }
   2071 
   2072     return(SOC_E_NONE);
   2073 }
   2074 
   2075 /* 
   2076  * viper_pi_control_set
   2077  */
   2078 STATIC int 
   2079 viper_pi_control_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2080 {
   2081     phymod_phy_access_t  *pm_phy;
   2082     phymod_tx_override_t tx_override;
   2083     int                  idx;
   2084 
   2085     /* loop through all cores */
   2086     for (idx = 0; idx < pmc->num_phys; idx++) {
   2087         pm_phy = &pmc->phy[idx]->pm_phy;
   2088 
   2089         if (pm_phy == NULL) {
   2090             return SOC_E_INTERNAL;
   2091         }
   2092 
   2093         phymod_tx_override_t_init(&tx_override);
   2094         tx_override.phase_interpolator.enable = (value == 0) ? 0 : 1;
   2095         tx_override.phase_interpolator.value = value;
   2096         SOC_IF_ERROR_RETURN(phymod_phy_tx_override_set(pm_phy, &tx_override));
   2097     }
   2098 
   2099     return(SOC_E_NONE);
   2100 }
   2101 
   2102 /* 
   2103  * viper_tx_polarity_set
   2104  */
   2105 STATIC int 
   2106 viper_tx_polarity_set(soc_phymod_ctrl_t *pmc, phymod_polarity_t *cfg_polarity, uint32 value)
   2107 {
   2108     phymod_phy_access_t  *pm_phy;
   2109     phymod_polarity_t    polarity;
   2110     int                  idx;
   2111 
   2112     /* loop through all cores */
   2113     for (idx = 0; idx < pmc->num_phys; idx++) {
   2114         pm_phy = &pmc->phy[idx]->pm_phy;
   2115 
   2116         if (pm_phy == NULL) {
   2117             return SOC_E_INTERNAL;
   2118         }
   2119 
   2120         sal_memcpy(&polarity, cfg_polarity, sizeof(polarity));
   2121         polarity.tx_polarity = value;
   2122         SOC_IF_ERROR_RETURN(phymod_phy_polarity_set(pm_phy, &polarity));
   2123 
   2124         /* after successfully setting the parity, update the configured value */
   2125         cfg_polarity->tx_polarity = value;
   2126     }
   2127 
   2128     return(SOC_E_NONE);
   2129 }
   2130 
   2131 /* 
   2132  * viper_rx_polarity_set
   2133  */
   2134 
   2135 STATIC int 
   2136 viper_rx_polarity_set(soc_phymod_ctrl_t *pmc, phymod_polarity_t *cfg_polarity, uint32 value)
   2137 {
   2138     phymod_phy_access_t  *pm_phy;
   2139     phymod_polarity_t    polarity;
   2140     int                  idx;
   2141 
   2142     /* loop through all cores */
   2143     for (idx = 0; idx < pmc->num_phys; idx++) {
   2144         pm_phy = &pmc->phy[idx]->pm_phy;
   2145 
   2146         if (pm_phy == NULL) {
   2147             return SOC_E_INTERNAL;
   2148         }
   2149 
   2150         sal_memcpy(&polarity, cfg_polarity, sizeof(polarity));
   2151         polarity.rx_polarity = value;
   2152         SOC_IF_ERROR_RETURN(phymod_phy_polarity_set(pm_phy, &polarity));
   2153 
   2154         /* after successfully setting the parity, update the configured value */
   2155         cfg_polarity->rx_polarity = value;
   2156     }
   2157 
   2158     return(SOC_E_NONE);
   2159 }
   2160 
   2161 /* 
   2162  * viper_rx_reset
   2163  */
   2164 STATIC int
   2165 viper_rx_reset(soc_phymod_ctrl_t *pmc, phymod_phy_reset_t *cfg_reset, uint32 value)
   2166 {
   2167     phymod_phy_access_t *pm_phy;
   2168     phymod_phy_reset_t  reset;
   2169     int                 idx;
   2170 
   2171     /* loop through all cores */
   2172     for (idx = 0; idx < pmc->num_phys; idx++) {
   2173         pm_phy = &pmc->phy[idx]->pm_phy;
   2174 
   2175         if (pm_phy == NULL) {
   2176             return SOC_E_INTERNAL;
   2177         }
   2178 
   2179         sal_memcpy(&reset, cfg_reset, sizeof(reset));
   2180         reset.rx = (phymod_reset_direction_t) value;
   2181         SOC_IF_ERROR_RETURN(phymod_phy_reset_set(pm_phy, &reset));
   2182 
   2183         /* after successfully setting the parity, update the configured value */
   2184         cfg_reset->rx = (phymod_reset_direction_t) value;
   2185     }
   2186 
   2187     return(SOC_E_NONE);
   2188 }
   2189 
   2190 /* 
   2191  * viper_tx_reset
   2192  */
   2193 STATIC int
   2194 viper_tx_reset(soc_phymod_ctrl_t *pmc, phymod_phy_reset_t *cfg_reset, uint32 value)
   2195 {
   2196     phymod_phy_access_t *pm_phy;
   2197     phymod_phy_reset_t  reset;
   2198     int                 idx;
   2199 
   2200     /* loop through all cores */
   2201     for (idx = 0; idx < pmc->num_phys; idx++) {
   2202         pm_phy = &pmc->phy[idx]->pm_phy;
   2203 
   2204         if (pm_phy == NULL) {
   2205             return SOC_E_INTERNAL;
   2206         }
   2207 
   2208         sal_memcpy(&reset, cfg_reset, sizeof(reset));
   2209         reset.tx = (phymod_reset_direction_t) value;
   2210         SOC_IF_ERROR_RETURN(phymod_phy_reset_set(pm_phy, &reset));
   2211 
   2212         /* after successfully setting the parity, update the configured value */
   2213         cfg_reset->tx = (phymod_reset_direction_t) value;
   2214     }
   2215 
   2216     return(SOC_E_NONE);
   2217 }
   2218 
   2219 
   2220 STATIC int
   2221 viper_lane_map_set(soc_phymod_ctrl_t *pmc, uint32 value){
   2222     int idx;
   2223     phymod_lane_map_t lane_map;
   2224 
   2225     lane_map.num_of_lanes = NUM_LANES;
   2226     if(pmc->phy[0] == NULL){
   2227         return(SOC_E_INTERNAL);
   2228     }
   2229     for (idx=0; idx < NUM_LANES; idx++) {
   2230         lane_map.lane_map_rx[idx] = (value >> (idx * 4 /* 4 bit per lane */)) & 0xf;
   2231     }
   2232     for (idx=0; idx < NUM_LANES; idx++) {
   2233         lane_map.lane_map_tx[idx] = (value >> (16 + idx * 4 /* 4 bit per lane */)) & 0xf;
   2234     }
   2235     SOC_IF_ERROR_RETURN(phymod_core_lane_map_set(&pmc->phy[0]->core->pm_core, &lane_map));
   2236     return(SOC_E_NONE);
   2237 }
   2238 
   2239 
   2240 STATIC int
   2241 viper_lane_map_get(soc_phymod_ctrl_t *pmc, uint32 *value){
   2242     int idx;
   2243     phymod_lane_map_t lane_map;
   2244 
   2245     *value = 0;
   2246     if(pmc->phy[0] == NULL){
   2247         return(SOC_E_INTERNAL);
   2248     }
   2249     SOC_IF_ERROR_RETURN(phymod_core_lane_map_get(&pmc->phy[0]->core->pm_core, &lane_map));
   2250     if(lane_map.num_of_lanes != NUM_LANES){
   2251         return SOC_E_INTERNAL;
   2252     }
   2253     for (idx=0; idx < NUM_LANES; idx++) {
   2254         *value += (lane_map.lane_map_rx[idx] << (idx * 4));
   2255     }
   2256     for (idx=0; idx < NUM_LANES; idx++) {
   2257         *value += (lane_map.lane_map_tx[idx]<< (idx * 4 + 16 ));
   2258     }
   2259     
   2260     return(SOC_E_NONE);
   2261 }
   2262 
   2263 
   2264 
   2265 STATIC int
   2266 viper_pattern_len_set(soc_phymod_ctrl_t *pmc, uint32_t value)
   2267 {
   2268     phymod_phy_access_t    *pm_phy;
   2269     phymod_pattern_t       phymod_pattern;
   2270     int                    idx;
   2271 
   2272     /* loop through all cores */
   2273     for (idx = 0; idx < pmc->num_phys; idx++) {
   2274         pm_phy = &pmc->phy[idx]->pm_phy;
   2275 
   2276         if (pm_phy == NULL) {
   2277             return SOC_E_INTERNAL;
   2278         }
   2279 
   2280         phymod_pattern_t_init(&phymod_pattern);
   2281         SOC_IF_ERROR_RETURN
   2282             (phymod_phy_pattern_config_get(pm_phy, &phymod_pattern));
   2283         phymod_pattern.pattern_len = value;
   2284         SOC_IF_ERROR_RETURN(phymod_phy_pattern_config_set(pm_phy, &phymod_pattern));
   2285     }
   2286     return(SOC_E_NONE);
   2287 }
   2288 
   2289 STATIC int
   2290 viper_pattern_enable_set(soc_phymod_ctrl_t *pmc, uint32_t value)
   2291 {
   2292     phymod_phy_access_t    *pm_phy;
   2293     phymod_pattern_t       phymod_pattern;
   2294     int                    idx;
   2295 
   2296     /* loop through all cores */
   2297     for (idx = 0; idx < pmc->num_phys; idx++) {
   2298         pm_phy = &pmc->phy[idx]->pm_phy;
   2299 
   2300         if (pm_phy == NULL) {
   2301             return SOC_E_INTERNAL;
   2302         }
   2303 
   2304         phymod_pattern_t_init(&phymod_pattern);
   2305         SOC_IF_ERROR_RETURN
   2306             (phymod_phy_pattern_config_get(pm_phy, &phymod_pattern));
   2307         SOC_IF_ERROR_RETURN(phymod_phy_pattern_enable_set(pm_phy,  value, &phymod_pattern));
   2308     }
   2309     return(SOC_E_NONE);
   2310 }
   2311 
   2312 /* 
   2313  * viper_pattern_data_set 
   2314  *    Sets 32 bits of the 256 bit data pattern.
   2315  */
   2316 STATIC int
   2317 viper_pattern_data_set(int idx, viper_pattern_t *pattern, uint32 value)
   2318 {
   2319     if ((idx<0) || (idx >= COUNTOF(pattern->pattern_data))) {
   2320         return SOC_E_INTERNAL;
   2321     }
   2322 
   2323     /* update pattern data */
   2324     pattern->pattern_data[idx] = value;
   2325 
   2326     return(SOC_E_NONE);
   2327 }
   2328 
   2329 /* 
   2330  * viper_per_lane_prbs_poly_set
   2331  */
   2332 STATIC int
   2333 viper_per_lane_prbs_poly_set(soc_phymod_ctrl_t *pmc, int lane, uint32 value)
   2334 {
   2335    return(SOC_E_UNAVAIL);
   2336 }
   2337 
   2338 
   2339 STATIC
   2340 int
   2341 viper_sdk_poly_to_phymod_poly(uint32 sdk_poly, phymod_prbs_poly_t *phymod_poly){
   2342     switch(sdk_poly){
   2343     case SOC_PHY_PRBS_POLYNOMIAL_X7_X6_1:
   2344         *phymod_poly = phymodPrbsPoly7;
   2345         break;
   2346     case SOC_PHY_PRBS_POLYNOMIAL_X15_X14_1:
   2347         *phymod_poly = phymodPrbsPoly15;
   2348         break;
   2349     case SOC_PHY_PRBS_POLYNOMIAL_X23_X18_1:
   2350         *phymod_poly = phymodPrbsPoly23;
   2351         break;
   2352     case SOC_PHY_PRBS_POLYNOMIAL_X31_X28_1:
   2353         *phymod_poly = phymodPrbsPoly31;
   2354         break;
   2355     case SOC_PHY_PRBS_POLYNOMIAL_X9_X5_1:
   2356         *phymod_poly = phymodPrbsPoly9;
   2357         break;
   2358     case SOC_PHY_PRBS_POLYNOMIAL_X11_X9_1:
   2359         *phymod_poly = phymodPrbsPoly11;
   2360         break;
   2361     case SOC_PHY_PRBS_POLYNOMIAL_X58_X31_1:
   2362         *phymod_poly = phymodPrbsPoly58;
   2363         break;
   2364     default:
   2365         return SOC_E_INTERNAL;
   2366     }
   2367     return SOC_E_NONE;
   2368 }
   2369 
   2370 /* 
   2371  * viper_prbs_tx_poly_set
   2372  */
   2373 STATIC int
   2374 viper_prbs_tx_poly_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2375 {
   2376     phymod_phy_access_t  *pm_phy;
   2377     phymod_prbs_t        prbs;
   2378     uint32_t flags = 0;
   2379     int                    idx;
   2380     
   2381     for (idx = 0; idx < pmc->num_phys; idx++) {
   2382         if (pmc->phy[idx] == NULL) {
   2383             return SOC_E_INTERNAL;
   2384         }
   2385         pm_phy = &pmc->phy[idx]->pm_phy;
   2386         if (pm_phy == NULL) {
   2387             return SOC_E_INTERNAL;
   2388         }
   2389         PHYMOD_PRBS_DIRECTION_TX_SET(flags);
   2390         SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy,  flags, &prbs));
   2391         SOC_IF_ERROR_RETURN(viper_sdk_poly_to_phymod_poly(value, &prbs.poly));
   2392         SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_set(pm_phy, flags, &prbs));
   2393     }
   2394     return(SOC_E_NONE);
   2395 }
   2396 
   2397 /* 
   2398  * viper_prbs_rx_poly_set
   2399  */
   2400 STATIC int
   2401 viper_prbs_rx_poly_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2402 {
   2403     phymod_phy_access_t  *pm_phy;
   2404     phymod_prbs_t        prbs;
   2405     uint32_t flags = 0;
   2406     int                    idx;
   2407 
   2408     for (idx = 0; idx < pmc->num_phys; idx++) {
   2409         if (pmc->phy[idx] == NULL) {
   2410             return SOC_E_INTERNAL;
   2411         }
   2412         pm_phy = &pmc->phy[idx]->pm_phy;
   2413         if (pm_phy == NULL) {
   2414             return SOC_E_INTERNAL;
   2415         }
   2416         PHYMOD_PRBS_DIRECTION_RX_SET(flags);
   2417         SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy, flags, &prbs));
   2418         SOC_IF_ERROR_RETURN(viper_sdk_poly_to_phymod_poly(value, &prbs.poly));
   2419         SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_set(pm_phy, flags, &prbs));
   2420     }
   2421     return(SOC_E_NONE);
   2422 }
   2423 
   2424 
   2425 /* 
   2426  * viper_per_lane_prbs_tx_invert_data_set
   2427  */
   2428 STATIC int
   2429 viper_per_lane_prbs_tx_invert_data_set(soc_phymod_ctrl_t *pmc, int lane, uint32 value)
   2430 {
   2431    return(SOC_E_UNAVAIL);
   2432 }
   2433 
   2434 /* 
   2435  * viper_prbs_tx_invert_data_set
   2436  */
   2437 STATIC int
   2438 viper_prbs_tx_invert_data_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2439 {
   2440     phymod_phy_access_t  *pm_phy;
   2441     phymod_prbs_t        prbs;
   2442     uint32_t flags = 0;
   2443     int                    idx;
   2444     
   2445     for (idx = 0; idx < pmc->num_phys; idx++) {
   2446         if (pmc->phy[idx] == NULL) {
   2447             return SOC_E_INTERNAL;
   2448         }
   2449         pm_phy = &pmc->phy[idx]->pm_phy;
   2450         if (pm_phy == NULL) {
   2451             return SOC_E_INTERNAL;
   2452         }
   2453         PHYMOD_PRBS_DIRECTION_TX_SET(flags);
   2454         SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy, flags, &prbs));
   2455         prbs.invert = value;
   2456         SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_set(pm_phy, flags,  &prbs));
   2457     }
   2458     return(SOC_E_NONE);
   2459 }
   2460 
   2461 /* 
   2462  * viper_prbs_rx_invert_data_set
   2463  */
   2464 STATIC int
   2465 viper_prbs_rx_invert_data_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2466 {
   2467     phymod_phy_access_t  *pm_phy;
   2468     phymod_prbs_t        prbs;
   2469     uint32_t flags = 0;
   2470     int                    idx;
   2471 
   2472     for (idx = 0; idx < pmc->num_phys; idx++) {
   2473         if (pmc->phy[idx] == NULL) {
   2474             return SOC_E_INTERNAL;
   2475         }
   2476         pm_phy = &pmc->phy[idx]->pm_phy;
   2477         if (pm_phy == NULL) {
   2478             return SOC_E_INTERNAL;
   2479         }
   2480         PHYMOD_PRBS_DIRECTION_RX_SET(flags);
   2481         SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy, flags,  &prbs));
   2482         prbs.invert = value;
   2483         SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_set(pm_phy, flags, &prbs));
   2484     }
   2485     return(SOC_E_NONE);
   2486 }
   2487 
   2488 /* 
   2489  * viper_per_lane_prbs_tx_enable_set
   2490  */
   2491 STATIC int
   2492 viper_per_lane_prbs_tx_enable_set(soc_phymod_ctrl_t *pmc, int lane, uint32 value)
   2493 {
   2494    return(SOC_E_UNAVAIL);
   2495 }
   2496 /* 
   2497  * viper_prbs_tx_enable_set
   2498  */
   2499 STATIC int
   2500 viper_prbs_tx_enable_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2501 {
   2502     phymod_phy_access_t  *pm_phy;
   2503     uint32_t flags = 0;
   2504     int                    idx;
   2505 
   2506     for (idx = 0; idx < pmc->num_phys; idx++) {
   2507         if (pmc->phy[idx] == NULL) {
   2508             return SOC_E_INTERNAL;
   2509         }
   2510         pm_phy = &pmc->phy[idx]->pm_phy;
   2511         if (pm_phy == NULL) {
   2512             return SOC_E_INTERNAL;
   2513         }
   2514         PHYMOD_PRBS_DIRECTION_TX_SET(flags);
   2515         SOC_IF_ERROR_RETURN(phymod_phy_prbs_enable_set(pm_phy, flags, value));
   2516     }
   2517     return(SOC_E_NONE);
   2518 }
   2519 
   2520 /* 
   2521  * viper_prbs_rx_enable_set
   2522  */
   2523 STATIC int
   2524 viper_prbs_rx_enable_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2525 {
   2526     phymod_phy_access_t  *pm_phy;
   2527     uint32_t flags = 0;
   2528     int                    idx;
   2529 
   2530     for (idx = 0; idx < pmc->num_phys; idx++) {
   2531         if (pmc->phy[idx] == NULL) {
   2532             return SOC_E_INTERNAL;
   2533         }
   2534         pm_phy = &pmc->phy[idx]->pm_phy;
   2535         if (pm_phy == NULL) {
   2536             return SOC_E_INTERNAL;
   2537         }
   2538 
   2539         PHYMOD_PRBS_DIRECTION_RX_SET(flags);
   2540         SOC_IF_ERROR_RETURN(phymod_phy_prbs_enable_set(pm_phy, flags,  value));
   2541     }
   2542     return(SOC_E_NONE);
   2543 }
   2544 
   2545 /* 
   2546  * viper_loopback_internal_set
   2547  */
   2548 STATIC int 
   2549 viper_loopback_internal_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2550 {
   2551     phymod_phy_access_t  *pm_phy;
   2552     int                    idx;
   2553 
   2554     for (idx = 0; idx < pmc->num_phys; idx++) {
   2555         if (pmc->phy[idx] == NULL) {
   2556             return SOC_E_INTERNAL;
   2557         }
   2558         pm_phy = &pmc->phy[idx]->pm_phy;
   2559         if (pm_phy == NULL) {
   2560             return SOC_E_INTERNAL;
   2561         }
   2562     
   2563         SOC_IF_ERROR_RETURN
   2564             (phymod_phy_loopback_set(pm_phy, phymodLoopbackGlobal, value));
   2565     }
   2566     return(SOC_E_NONE);
   2567 }
   2568 
   2569 /* 
   2570  * viper_loopback_internal_pmd_set
   2571  */
   2572 STATIC int 
   2573 viper_loopback_internal_pmd_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2574 {
   2575     phymod_phy_access_t  *pm_phy;
   2576     int                    idx;
   2577 
   2578     for (idx = 0; idx < pmc->num_phys; idx++) {
   2579         if (pmc->phy[idx] == NULL) {
   2580             return SOC_E_INTERNAL;
   2581         }
   2582         pm_phy = &pmc->phy[idx]->pm_phy;
   2583         if (pm_phy == NULL) {
   2584             return SOC_E_INTERNAL;
   2585         }
   2586 
   2587         SOC_IF_ERROR_RETURN
   2588             (phymod_phy_loopback_set(pm_phy, phymodLoopbackGlobalPMD, value));
   2589     }
   2590     return(SOC_E_NONE);
   2591 }
   2592 
   2593 /* 
   2594  * viper_loopback_remote_set
   2595  */
   2596 STATIC int 
   2597 viper_loopback_remote_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2598 {
   2599     phymod_phy_access_t  *pm_phy;
   2600     int                    idx;
   2601 
   2602     for (idx = 0; idx < pmc->num_phys; idx++) {
   2603         if (pmc->phy[idx] == NULL) {
   2604             return SOC_E_INTERNAL;
   2605         }
   2606         pm_phy = &pmc->phy[idx]->pm_phy;
   2607         if (pm_phy == NULL) {
   2608             return SOC_E_INTERNAL;
   2609         }
   2610 
   2611         SOC_IF_ERROR_RETURN
   2612             (phymod_phy_loopback_set(pm_phy, phymodLoopbackRemotePMD, value));
   2613     }
   2614     return(SOC_E_NONE);
   2615 }
   2616 
   2617 /* 
   2618  * viper_loopback_remote_pcs_set
   2619  */
   2620 STATIC int 
   2621 viper_loopback_remote_pcs_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2622 {
   2623     phymod_phy_access_t  *pm_phy;
   2624     int                    idx;
   2625 
   2626     for (idx = 0; idx < pmc->num_phys; idx++) {
   2627         if (pmc->phy[idx] == NULL) {
   2628             return SOC_E_INTERNAL;
   2629         }
   2630         pm_phy = &pmc->phy[idx]->pm_phy;
   2631         if (pm_phy == NULL) {
   2632             return SOC_E_INTERNAL;
   2633         }
   2634 
   2635         SOC_IF_ERROR_RETURN
   2636             (phymod_phy_loopback_set(pm_phy, phymodLoopbackRemotePCS, value));
   2637     }
   2638     return(SOC_E_NONE);
   2639 }
   2640 
   2641 /* 
   2642  * viper_fec_enable_set
   2643  */
   2644 STATIC int 
   2645 viper_fec_enable_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2646 {
   2647     phymod_phy_access_t     *pm_phy;
   2648     int                     idx;
   2649 
   2650     /* loop through all cores */
   2651     for (idx = 0; idx < pmc->num_phys; idx++) {
   2652         pm_phy = &pmc->phy[idx]->pm_phy;
   2653 
   2654         if (pm_phy == NULL) {
   2655             return SOC_E_INTERNAL;
   2656         }
   2657         SOC_IF_ERROR_RETURN(phymod_phy_fec_enable_set(pm_phy, value));
   2658     }
   2659     return(SOC_E_NONE);
   2660 }
   2661 
   2662 /* 
   2663  * viper_8b10b_set
   2664  */
   2665 STATIC int
   2666 viper_8b10b_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2667 {
   2668    return(SOC_E_UNAVAIL);
   2669 }
   2670 
   2671 /* 
   2672  * viper_64b65b_set
   2673  */
   2674 STATIC int
   2675 viper_64b65b_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2676 {
   2677 
   2678    return(SOC_E_UNAVAIL);
   2679 }
   2680 
   2681 /* 
   2682  * viper_power_set
   2683  */
   2684 STATIC int
   2685 viper_power_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2686 {
   2687     phymod_phy_access_t     *pm_phy;
   2688     phymod_phy_power_t      power;
   2689     int                     idx;
   2690 
   2691     /* loop through all cores */
   2692     for (idx = 0; idx < pmc->num_phys; idx++) {
   2693         pm_phy = &pmc->phy[idx]->pm_phy;
   2694 
   2695         if (pm_phy == NULL) {
   2696             return SOC_E_INTERNAL;
   2697         }
   2698 
   2699         phymod_phy_power_t_init(&power);
   2700         if (value) {
   2701             power.tx = phymodPowerOn;
   2702             power.rx = phymodPowerOn;
   2703         } 
   2704         else {
   2705             power.tx = phymodPowerOff;
   2706             power.rx = phymodPowerOff;
   2707         }
   2708 
   2709         SOC_IF_ERROR_RETURN(phymod_phy_power_set(pm_phy, &power));
   2710     }
   2711 
   2712     return(SOC_E_NONE);
   2713 }
   2714 
   2715 /* 
   2716  * viper_per_lane_rx_low_freq_filter_set
   2717  */
   2718 STATIC int
   2719 viper_per_lane_rx_low_freq_filter_set(soc_phymod_ctrl_t *pmc, int lane, uint32 value)
   2720 {
   2721    return(SOC_E_UNAVAIL);
   2722 }
   2723 
   2724 /* 
   2725  * viper_rx_low_freq_filter_set
   2726  */
   2727 STATIC int
   2728 viper_rx_low_freq_filter_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2729 {
   2730     phymod_phy_access_t  *pm_phy;
   2731     phymod_rx_t          phymod_rx;
   2732     int                  idx;
   2733 
   2734     /* loop through all cores */
   2735     for (idx = 0; idx < pmc->num_phys; idx++) {
   2736         pm_phy = &pmc->phy[idx]->pm_phy;
   2737 
   2738         if (pm_phy == NULL) {
   2739             return SOC_E_INTERNAL;
   2740         }
   2741 
   2742         SOC_IF_ERROR_RETURN(phymod_phy_rx_get(pm_phy, &phymod_rx));
   2743 
   2744         phymod_rx.low_freq_peaking_filter.enable = TRUE;
   2745         phymod_rx.low_freq_peaking_filter.value = value;
   2746         SOC_IF_ERROR_RETURN(phymod_phy_rx_set(pm_phy, &phymod_rx));
   2747     }
   2748 
   2749     return(SOC_E_NONE);
   2750 }
   2751 
   2752 /* 
   2753  * viper_tx_ppm_adjust_set
   2754  */
   2755 STATIC int
   2756 viper_tx_ppm_adjust_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2757 {
   2758     phymod_phy_access_t  *pm_phy;
   2759     phymod_tx_override_t tx_override;
   2760     int                  idx;
   2761 
   2762     /* loop through all cores */
   2763     for (idx = 0; idx < pmc->num_phys; idx++) {
   2764         pm_phy = &pmc->phy[idx]->pm_phy;
   2765 
   2766         if (pm_phy == NULL) {
   2767             return SOC_E_INTERNAL;
   2768         }
   2769 
   2770         tx_override.phase_interpolator.enable = 1;
   2771         tx_override.phase_interpolator.value = value;
   2772         SOC_IF_ERROR_RETURN(phymod_phy_tx_override_set(pm_phy, &tx_override));
   2773     }
   2774     return(SOC_E_NONE);
   2775 }
   2776 
   2777 #if 0
   2778 /* 
   2779  * viper_vco_freq_set
   2780  */
   2781 STATIC int
   2782 viper__vco_freq_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2783 {
   2784     /*
   2785 The following 3 controls are used to override pre-defined speed in the phy.
   2786 What we discussed in SJ is that in case of rate which is not officially supported the driver will try to 
   2787 understand this parameters by itself.
   2788 Questions:
   2789 1. Do we want to support direct configuration of PLL\OS?
   2790 2. If yes - same API or new API
   2791 
   2792 phymod_phy_interface_config_set (?)
   2793     */
   2794 
   2795    return(SOC_E_UNAVAIL);
   2796 }
   2797 #endif
   2798 /* 
   2799  * viper_pll_divider_set
   2800  */
   2801 STATIC int
   2802 viper_pll_divider_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2803 {
   2804    return(SOC_E_UNAVAIL);
   2805 }
   2806 
   2807 /* 
   2808  * viper_oversample_mode_set
   2809  */
   2810 STATIC int
   2811 viper_oversample_mode_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2812 {
   2813    return(SOC_E_UNAVAIL);
   2814 }
   2815 
   2816 /* 
   2817  * viper_ref_clk_set
   2818  */
   2819 STATIC int
   2820 viper_ref_clk_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2821 {
   2822    return(SOC_E_UNAVAIL);
   2823 }
   2824 
   2825 /* 
   2826  * viper_rx_seq_toggle_set 
   2827  */
   2828 STATIC int
   2829 viper_rx_seq_toggle_set(soc_phymod_ctrl_t *pmc)
   2830 {
   2831     phymod_phy_access_t    *pm_phy;
   2832     int                    idx;
   2833 
   2834     /* loop through all cores */
   2835     for (idx = 0; idx < pmc->num_phys; idx++) {
   2836         if (pmc->phy[idx] == NULL) {
   2837             return(SOC_E_INTERNAL);
   2838         }
   2839 
   2840         pm_phy = &pmc->phy[idx]->pm_phy;
   2841         if (pm_phy == NULL) {
   2842             return(SOC_E_INTERNAL);
   2843         }
   2844         SOC_IF_ERROR_RETURN(phymod_phy_rx_restart(pm_phy));
   2845     }
   2846 
   2847     return(SOC_E_NONE);
   2848 }
   2849 
   2850 /* 
   2851  * viper_eee_set 
   2852  */
   2853 STATIC int
   2854 viper_eee_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2855 {
   2856     phymod_phy_access_t    *pm_phy;
   2857     int                    idx;
   2858 
   2859     /* loop through all cores */
   2860     for (idx = 0; idx < pmc->num_phys; idx++) {
   2861         if (pmc->phy[idx] == NULL) {
   2862             return(SOC_E_INTERNAL);
   2863         }
   2864 
   2865         pm_phy = &pmc->phy[idx]->pm_phy;
   2866         if (pm_phy == NULL) {
   2867             return(SOC_E_INTERNAL);
   2868         }
   2869         SOC_IF_ERROR_RETURN(phymod_phy_eee_set(pm_phy, value));
   2870     }
   2871 
   2872     return(SOC_E_NONE);
   2873 }
   2874 
   2875 STATIC int
   2876 viper_control_linkdown_transmit_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2877 {
   2878     phymod_phy_access_t    *pm_phy;
   2879     int                    idx;
   2880 
   2881     /* loop through all cores */
   2882     for (idx = 0; idx < pmc->num_phys; idx++) {
   2883         if (pmc->phy[idx] == NULL) {
   2884             return(SOC_E_INTERNAL);
   2885         }
   2886 
   2887         pm_phy = &pmc->phy[idx]->pm_phy;
   2888         if (pm_phy == NULL) {
   2889             return(SOC_E_INTERNAL);
   2890         }
   2891         SOC_IF_ERROR_RETURN(phymod_phy_linkdown_transmit_set(pm_phy, value));
   2892     }
   2893 
   2894     return(SOC_E_NONE);
   2895 }
   2896 
   2897 STATIC int
   2898 viper_control_linkdown_transmit_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   2899 {
   2900     phymod_phy_access_t  *pm_phy;
   2901 
   2902     /* just take the value from the first phy */
   2903     if (pmc->phy[0] == NULL) {
   2904         return SOC_E_INTERNAL;
   2905     }
   2906     pm_phy = &pmc->phy[0]->pm_phy;
   2907 
   2908     if (pm_phy == NULL) {
   2909          return SOC_E_INTERNAL;
   2910     }
   2911 
   2912     SOC_IF_ERROR_RETURN(phymod_phy_linkdown_transmit_get(pm_phy, value));
   2913 
   2914     return(SOC_E_NONE);
   2915 }
   2916 
   2917 /* 
   2918  * viper_driver_supply_set
   2919  */
   2920 STATIC int
   2921 viper_driver_supply_set(soc_phymod_ctrl_t *pmc, uint32 value)
   2922 {
   2923    return(SOC_E_UNAVAIL);
   2924 }
   2925 
   2926 #if 0
   2927 STATIC int
   2928 viper_user_speed_set(soc_phymod_ctrl_t *pmc, 
   2929                     phymod_pcs_userspeed_mode_t mode, 
   2930                     phymod_pcs_userspeed_param_t param, 
   2931                     uint32 value)
   2932 {
   2933     phymod_phy_access_t    *pm_phy;
   2934     soc_phymod_phy_t       *p_phy;
   2935     phymod_pcs_userspeed_config_t config ;
   2936     int                    idx;
   2937     uint32                 lane_map;
   2938     
   2939     SOC_IF_ERROR_RETURN(_viper_find_soc_phy_lane(pmc, 0, &p_phy, &lane_map));
   2940     config.mode          = mode ; 
   2941     config.param         = param ;
   2942     config.current_entry = (lane_map&0x1)? 0:((lane_map&0x2)? 1:((lane_map&0x4)? 2: ((lane_map&0x8)? 3:0)));
   2943     config.value         = value ;
   2944 
   2945     /* loop through all cores */
   2946     for (idx = 0; idx < pmc->num_phys; idx++) {
   2947         if (pmc->phy[idx] == NULL) {
   2948             return(SOC_E_INTERNAL);
   2949         }
   2950         
   2951         pm_phy = &pmc->phy[idx]->pm_phy;
   2952         if (pm_phy == NULL) {
   2953             return(SOC_E_INTERNAL);
   2954         }
   2955         SOC_IF_ERROR_RETURN(phymod_phy_pcs_userspeed_set(pm_phy, &config));
   2956     }
   2957     
   2958     return(SOC_E_NONE);
   2959 }
   2960 
   2961 
   2962 STATIC int
   2963 viper_user_speed_get(soc_phymod_ctrl_t *pmc, 
   2964                     phymod_pcs_userspeed_mode_t mode, 
   2965                     phymod_pcs_userspeed_param_t param, 
   2966                     uint32 *value)
   2967 {
   2968     phymod_phy_access_t    *pm_phy;
   2969     soc_phymod_phy_t       *p_phy;
   2970     phymod_pcs_userspeed_config_t config ;
   2971     int                    idx;
   2972     uint32                 lane_map;
   2973     
   2974     SOC_IF_ERROR_RETURN(_viper_find_soc_phy_lane(pmc, 0, &p_phy, &lane_map));
   2975     config.mode          = mode ; 
   2976     config.param         = param ;
   2977     config.current_entry = (lane_map&0x1)? 0:((lane_map&0x2)? 1:((lane_map&0x4)? 2: ((lane_map&0x8)? 3:0)));
   2978     config.value         = 0 ;
   2979 
   2980     *value = 0 ;
   2981 
   2982     /* loop through all cores */
   2983     for (idx = 0; idx < pmc->num_phys; idx++) {
   2984         if (pmc->phy[idx] == NULL) {
   2985             return(SOC_E_INTERNAL);
   2986         }
   2987         
   2988         pm_phy = &pmc->phy[idx]->pm_phy;
   2989         if (pm_phy == NULL) {
   2990             return(SOC_E_INTERNAL);
   2991         }
   2992         
   2993         SOC_IF_ERROR_RETURN(phymod_phy_pcs_userspeed_get(pm_phy, &config));
   2994         *value = config.value ;
   2995     }
   2996     
   2997     return(SOC_E_NONE);
   2998 }
   2999 #endif
   3000 /*
   3001  * Function:
   3002  *      phy_viper_control_set
   3003  * Purpose:
   3004  *      Configure PHY device specific control fucntion. 
   3005  * Parameters:
   3006  *      unit  - BCM unit number.
   3007  *      port  - Port number. 
   3008  *      type  - Control to update 
   3009  *      value - New setting for the control 
   3010  * Returns:     
   3011  *      SOC_E_NONE
   3012  */
   3013 STATIC int
   3014 phy_viper_control_set(int unit, soc_port_t port, soc_phy_control_t type, uint32 value)
   3015 {
   3016     int                 rv;
   3017     phy_ctrl_t          *pc;
   3018     soc_phymod_ctrl_t   *pmc;
   3019     viper_config_t       *pCfg;
   3020 
   3021     rv = SOC_E_UNAVAIL;
   3022 
   3023     /* coverity[mixed_enums] */
   3024     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
   3025         return (SOC_E_PARAM);
   3026     }
   3027 
   3028     /* locate phy control, phymod control, and the configuration data */
   3029     pc = INT_PHY_SW_STATE(unit, port);
   3030     if (pc == NULL) {
   3031         return SOC_E_INTERNAL;
   3032     }
   3033     pmc = &pc->phymod_ctrl;
   3034     pCfg = (viper_config_t *) pc->driver_data;
   3035 
   3036     switch(type) {
   3037 
   3038     case SOC_PHY_CONTROL_TX_FIR_PRE:
   3039         rv = SOC_E_UNAVAIL;
   3040         break;
   3041     case SOC_PHY_CONTROL_TX_FIR_MAIN:
   3042         rv = viper_tx_fir_main_set(pmc, value);
   3043         break;
   3044     case SOC_PHY_CONTROL_TX_FIR_POST:
   3045         rv = viper_tx_fir_post_set(pmc, value);
   3046         break;
   3047 #if 0
   3048     case SOC_PHY_CONTROL_TX_FIR_POST2:
   3049         rv = viper_tx_fir_post2_set(pmc, value);
   3050         break;
   3051     case SOC_PHY_CONTROL_TX_FIR_POST3:
   3052         rv = viper_tx_fir_post3_set(pmc, value);
   3053         break;
   3054 #endif
   3055     /* PREEMPHASIS */
   3056     case SOC_PHY_CONTROL_PREEMPHASIS_LANE0:
   3057         rv = viper_per_lane_preemphasis_set(pmc, 0, value);
   3058         break;
   3059     case SOC_PHY_CONTROL_PREEMPHASIS_LANE1:
   3060         rv = viper_per_lane_preemphasis_set(pmc, 1, value);
   3061         break;
   3062     case SOC_PHY_CONTROL_PREEMPHASIS_LANE2:
   3063         rv = viper_per_lane_preemphasis_set(pmc, 2, value);
   3064         break;
   3065     case SOC_PHY_CONTROL_PREEMPHASIS_LANE3:
   3066         rv = viper_per_lane_preemphasis_set(pmc, 3, value);
   3067         break;
   3068     case SOC_PHY_CONTROL_PREEMPHASIS:
   3069         rv = viper_preemphasis_set(pmc, value);
   3070         break;
   3071 
   3072     /* DRIVER CURRENT */
   3073     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0:
   3074         rv = SOC_E_UNAVAIL;
   3075         break;
   3076     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1:
   3077         rv = SOC_E_UNAVAIL;
   3078         break;
   3079     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2:
   3080         rv = SOC_E_UNAVAIL;
   3081         break;
   3082     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3:
   3083         rv = SOC_E_UNAVAIL;
   3084         break;
   3085     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   3086         rv = SOC_E_UNAVAIL;
   3087         break;
   3088 
   3089     /* PRE_DRIVER CURRENT  not supported anymore */
   3090     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0:
   3091         rv = SOC_E_UNAVAIL;
   3092         break;
   3093     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1:
   3094         rv = SOC_E_UNAVAIL;
   3095         break;
   3096     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2:
   3097         rv = SOC_E_UNAVAIL;
   3098         break;
   3099     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3:
   3100         rv = SOC_E_UNAVAIL;
   3101         break;
   3102     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   3103         rv = SOC_E_UNAVAIL;
   3104         break;
   3105 
   3106     /* POST2_DRIVER CURRENT not supported anymore */
   3107     case SOC_PHY_CONTROL_DRIVER_POST2_CURRENT:
   3108         rv = SOC_E_UNAVAIL;
   3109         break;
   3110     case SOC_PHY_CONTROL_DUMP:
   3111         /* "N/A: will be part of common phymod application" */
   3112         /*     was rv = tscmod_uc_status_dump(unit, port); */
   3113         break;
   3114 
   3115     /* TX LANE SQUELCH */
   3116     case SOC_PHY_CONTROL_TX_LANE_SQUELCH:
   3117         rv = viper_tx_lane_squelch(pmc, value);
   3118         break;
   3119 
   3120     /* RX PEAK FILTER */
   3121     case SOC_PHY_CONTROL_RX_PEAK_FILTER:
   3122         rv = viper_rx_peak_filter_set(pmc, value);
   3123         break;
   3124 
   3125     /* RX VGA */
   3126     case SOC_PHY_CONTROL_RX_VGA:
   3127         rv = SOC_E_UNAVAIL;
   3128         break;
   3129 
   3130     /* RX TAP */
   3131     case SOC_PHY_CONTROL_RX_TAP1:
   3132         rv = viper_rx_tap_set(pmc, 0, value);
   3133         break;
   3134     case SOC_PHY_CONTROL_RX_TAP2:
   3135         rv = viper_rx_tap_set(pmc, 1, value);
   3136         break;
   3137     case SOC_PHY_CONTROL_RX_TAP3:
   3138         rv = viper_rx_tap_set(pmc, 2, value);
   3139         break;
   3140     case SOC_PHY_CONTROL_RX_TAP4:
   3141         rv = viper_rx_tap_set(pmc, 3, value);
   3142         break;
   3143     case SOC_PHY_CONTROL_RX_TAP5:
   3144         rv = viper_rx_tap_set(pmc, 4, value);
   3145         break;
   3146     case SOC_PHY_CONTROL_RX_TAP1_RELEASE:       /* $$$ tbd $$$ */
   3147        rv = viper_rx_tap_release(pmc, 0);
   3148        break;
   3149     case SOC_PHY_CONTROL_RX_TAP2_RELEASE:       /* $$$ tbd $$$ */
   3150        rv = viper_rx_tap_release(pmc, 1);
   3151        break;
   3152     case SOC_PHY_CONTROL_RX_TAP3_RELEASE:       /* $$$ tbd $$$ */
   3153        rv = viper_rx_tap_release(pmc, 2);
   3154        break;
   3155     case SOC_PHY_CONTROL_RX_TAP4_RELEASE:       /* $$$ tbd $$$ */
   3156        rv = viper_rx_tap_release(pmc, 3);
   3157        break;
   3158     case SOC_PHY_CONTROL_RX_TAP5_RELEASE:       /* $$$ tbd $$$ */
   3159        rv = viper_rx_tap_release(pmc, 4);
   3160        break;
   3161     /* RX SLICER */
   3162     case SOC_PHY_CONTROL_RX_PLUS1_SLICER:
   3163         rv = SOC_E_UNAVAIL;
   3164         break;
   3165     case SOC_PHY_CONTROL_RX_MINUS1_SLICER:
   3166         rv = SOC_E_UNAVAIL;
   3167         break;
   3168     case SOC_PHY_CONTROL_RX_D_SLICER:
   3169         rv = SOC_E_UNAVAIL;
   3170         break;
   3171 
   3172     /* PHASE INTERPOLATOR */
   3173     case SOC_PHY_CONTROL_PHASE_INTERP:
   3174         rv = viper_pi_control_set(pmc, value);
   3175         break;
   3176 
   3177     /* POLARITY */
   3178     case SOC_PHY_CONTROL_RX_POLARITY:
   3179         rv = viper_rx_polarity_set(pmc, &pCfg->phy_polarity_config, value);;
   3180         break;
   3181     case SOC_PHY_CONTROL_TX_POLARITY:
   3182         rv = viper_tx_polarity_set(pmc, &pCfg->phy_polarity_config, value);
   3183         break;
   3184 
   3185     /* RESET */
   3186     case SOC_PHY_CONTROL_RX_RESET:
   3187         rv = viper_rx_reset(pmc, &pCfg->phy_reset_config, value);
   3188         break;
   3189     case SOC_PHY_CONTROL_TX_RESET:
   3190         rv = viper_tx_reset(pmc, &pCfg->phy_reset_config, value);
   3191         break;
   3192     /* LANE SWAP */
   3193     case SOC_PHY_CONTROL_LANE_SWAP:
   3194         rv = viper_lane_map_set(pmc, value);
   3195         break;
   3196     /* TX PATTERN */
   3197     case SOC_PHY_CONTROL_TX_PATTERN_20BIT:
   3198         rv = SOC_E_UNAVAIL;
   3199         break;
   3200     case SOC_PHY_CONTROL_TX_PATTERN_256BIT:
   3201         rv = SOC_E_UNAVAIL;
   3202         break;
   3203     case SOC_PHY_CONTROL_TX_PATTERN_LENGTH:
   3204         rv = viper_pattern_len_set(pmc, value);
   3205         break;
   3206     case SOC_PHY_CONTROL_TX_PATTERN_GEN_ENABLE:
   3207         rv = viper_pattern_enable_set(pmc, value);
   3208         break;
   3209     case SOC_PHY_CONTROL_TX_PATTERN_DATA0:
   3210         rv = viper_pattern_data_set(0, &pCfg->pattern, value);
   3211         break;
   3212     case SOC_PHY_CONTROL_TX_PATTERN_DATA1:
   3213         rv = viper_pattern_data_set(1, &pCfg->pattern, value);
   3214         break;
   3215     case SOC_PHY_CONTROL_TX_PATTERN_DATA2:
   3216         rv = viper_pattern_data_set(2, &pCfg->pattern, value);
   3217         break;
   3218     case SOC_PHY_CONTROL_TX_PATTERN_DATA3:
   3219         rv = viper_pattern_data_set(3, &pCfg->pattern, value);
   3220         break;
   3221     case SOC_PHY_CONTROL_TX_PATTERN_DATA4:
   3222         rv = viper_pattern_data_set(4, &pCfg->pattern, value);
   3223         break;
   3224     case SOC_PHY_CONTROL_TX_PATTERN_DATA5:
   3225         rv = viper_pattern_data_set(5, &pCfg->pattern, value);
   3226         break;
   3227     case SOC_PHY_CONTROL_TX_PATTERN_DATA6:
   3228         rv = viper_pattern_data_set(6, &pCfg->pattern, value);
   3229         break;
   3230     case SOC_PHY_CONTROL_TX_PATTERN_DATA7:
   3231         rv = viper_pattern_data_set(7, &pCfg->pattern, value);
   3232         break;
   3233 
   3234     /* decoupled PRBS */
   3235     case SOC_PHY_CONTROL_PRBS_DECOUPLED_TX_POLYNOMIAL:
   3236         rv = viper_prbs_tx_poly_set(pmc, value);
   3237         break;
   3238     case SOC_PHY_CONTROL_PRBS_DECOUPLED_TX_INVERT_DATA:
   3239         rv = viper_prbs_tx_invert_data_set(pmc, value);
   3240         break;
   3241     case SOC_PHY_CONTROL_PRBS_DECOUPLED_TX_ENABLE:
   3242         rv = viper_prbs_tx_enable_set(pmc, value);
   3243         break; 
   3244     case SOC_PHY_CONTROL_PRBS_DECOUPLED_RX_POLYNOMIAL:
   3245         rv = viper_prbs_rx_poly_set(pmc, value);
   3246         break;
   3247     case SOC_PHY_CONTROL_PRBS_DECOUPLED_RX_INVERT_DATA:
   3248         rv = viper_prbs_rx_invert_data_set(pmc, value);
   3249         break;
   3250     case SOC_PHY_CONTROL_PRBS_DECOUPLED_RX_ENABLE:
   3251         rv = viper_prbs_rx_enable_set(pmc, value);
   3252         break;
   3253     /* for legacy prbs usage mainly set both tx/rx the same */
   3254     case SOC_PHY_CONTROL_PRBS_POLYNOMIAL:
   3255         rv = viper_prbs_tx_poly_set(pmc, value);
   3256         rv = viper_prbs_rx_poly_set(pmc, value);
   3257         break;
   3258     case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA:
   3259         rv = viper_prbs_tx_invert_data_set(pmc, value);
   3260         break;
   3261     case SOC_PHY_CONTROL_PRBS_TX_ENABLE:
   3262         rv = viper_prbs_tx_enable_set(pmc, value);
   3263         rv = viper_prbs_rx_enable_set(pmc, value);
   3264         break;
   3265     case SOC_PHY_CONTROL_PRBS_RX_ENABLE:
   3266         rv = viper_prbs_tx_enable_set(pmc, value);
   3267         rv = viper_prbs_rx_enable_set(pmc, value);
   3268         break;
   3269 
   3270     /* LOOPBACK */
   3271     case SOC_PHY_CONTROL_LOOPBACK_INTERNAL:
   3272         rv = viper_loopback_internal_set(pmc, value);
   3273        break;
   3274     case SOC_PHY_CONTROL_LOOPBACK_PMD:
   3275         rv = viper_loopback_internal_pmd_set(pmc, value);
   3276        break;
   3277     case SOC_PHY_CONTROL_LOOPBACK_REMOTE:
   3278         rv = viper_loopback_remote_set(pmc, value);
   3279         break;
   3280     case SOC_PHY_CONTROL_LOOPBACK_REMOTE_PCS_BYPASS:
   3281         rv = viper_loopback_remote_pcs_set(pmc, value);
   3282         break;
   3283 
   3284     /* FEC */
   3285     case SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION:
   3286         rv = viper_fec_enable_set(pmc, value);
   3287         break;
   3288 
   3289     /* CUSTOM */
   3290     case SOC_PHY_CONTROL_CUSTOM1:
   3291        /* Obsolete ??
   3292        DEV_CFG_PTR(pc)->custom1 = value? TRUE: FALSE ;
   3293        rv = SOC_E_NONE; */
   3294        rv = SOC_E_UNAVAIL;
   3295        break;
   3296     /* 8B10B */
   3297     case SOC_PHY_CONTROL_8B10B:
   3298         rv = viper_8b10b_set(pmc, value);
   3299         break;
   3300 
   3301     /* 64B65B */
   3302     case SOC_PHY_CONTROL_64B66B:
   3303         rv = viper_64b65b_set(pmc, value);
   3304         break;
   3305 
   3306     /* POWER */
   3307     case SOC_PHY_CONTROL_POWER:
   3308        rv = viper_power_set(pmc, value);
   3309        break;
   3310 
   3311     /* RX_LOW_FREQ_PEAK_FILTER */
   3312     case SOC_PHY_CONTROL_RX_LOW_FREQ_PEAK_FILTER:
   3313        rv = viper_rx_low_freq_filter_set(pmc, value);
   3314        break;
   3315 
   3316     /* TX_PPM_ADJUST */
   3317     case SOC_PHY_CONTROL_TX_PPM_ADJUST:
   3318        rv = viper_tx_ppm_adjust_set(pmc, value);
   3319        break;
   3320 #if 0
   3321     /* VCO_FREQ */
   3322     case SOC_PHY_CONTROL_VCO_FREQ:
   3323        rv = viper_vco_freq_set(pmc, value);
   3324        break;
   3325 #endif
   3326     /* PLL_DIVIDER */
   3327     case SOC_PHY_CONTROL_PLL_DIVIDER:
   3328        rv = viper_pll_divider_set(pmc, value);
   3329        break;
   3330 
   3331     /* OVERSAMPLE_MODE */
   3332     case SOC_PHY_CONTROL_OVERSAMPLE_MODE:
   3333        rv = viper_oversample_mode_set(pmc, value);
   3334        break;
   3335 
   3336     /* REF_CLK */
   3337     case SOC_PHY_CONTROL_REF_CLK:
   3338        rv = viper_ref_clk_set(pmc, value);
   3339        break;
   3340 
   3341     /* RX_SEQ_TOGGLE */
   3342     case SOC_PHY_CONTROL_RX_SEQ_TOGGLE:
   3343        rv = viper_rx_seq_toggle_set(pmc);
   3344        break;
   3345 
   3346     /* DRIVER_SUPPLY */
   3347     case SOC_PHY_CONTROL_DRIVER_SUPPLY:
   3348        rv = viper_driver_supply_set(pmc, value);
   3349        break;
   3350     /* EEE */
   3351     case SOC_PHY_CONTROL_EEE:
   3352        rv = viper_eee_set(pmc, value);
   3353        break;
   3354 
   3355     /* EEE */
   3356 #ifdef TSC_EEE_SUPPORT
   3357     case SOC_PHY_CONTROL_EEE:
   3358     case SOC_PHY_CONTROL_EEE_AUTO:
   3359         rv = SOC_E_NONE;   /* not supported */
   3360         break;
   3361 #endif
   3362     case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT:
   3363        rv = viper_control_linkdown_transmit_set(pmc, value);
   3364        break;
   3365 #if 0
   3366        /* Added to support WA for HW bug; probably not required. */
   3367     case SOC_PHY_CONTROL_SOFTWARE_RX_LOS:
   3368         DEV_CFG_PTR(pc)->sw_rx_los.enable = (value == 0? 0: 1);
   3369         DEV_CFG_PTR(pc)->sw_rx_los.sys_link = 0; 
   3370         DEV_CFG_PTR(pc)->sw_rx_los.state = RXLOS_RESET;
   3371         DEV_CFG_PTR(pc)->sw_rx_los.link_status = 0;
   3372         /* THE FLAG IS SET IN INIT. FOR TSCMOD DRIVER
   3373            TO WORK IT'S LINK_GET MUST BE CALLED */
   3374         /* Manage the _SERVICE_INT_PHY_LINK_GET flag so that 
   3375            if external phy is present link_get for 
   3376            internal phy is still called to process 
   3377            software rx los feature 
   3378         if(value) {
   3379             PHY_FLAGS_SET(unit, port, PHY_FLAGS_SERVICE_INT_PHY_LINK_GET);
   3380         } else {
   3381             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_SERVICE_INT_PHY_LINK_GET);
   3382         }
   3383         */
   3384         rv = SOC_E_NONE;
   3385         break;
   3386     /* UNAVAIL */
   3387     case SOC_PHY_CONTROL_PARALLEL_DETECTION:
   3388     case SOC_PHY_CONTROL_BERT_PATTERN:
   3389     case SOC_PHY_CONTROL_BERT_RUN:
   3390     case SOC_PHY_CONTROL_BERT_PACKET_SIZE:
   3391     case SOC_PHY_CONTROL_BERT_IPG:
   3392     case SOC_PHY_CONTROL_RX_PEAK_FILTER_TEMP_COMP:
   3393     case SOC_PHY_CONTROL_CL73_FSM_AUTO_RECOVER:
   3394 #endif
   3395     default:
   3396         rv = SOC_E_UNAVAIL;
   3397         break; 
   3398     }
   3399     return rv;
   3400 }
   3401 
   3402 
   3403 /* 
   3404  * viper_tx_fir_pre_get
   3405  */
   3406 STATIC int
   3407 viper_tx_fir_pre_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   3408 {
   3409     phymod_phy_access_t *pm_phy;
   3410     phymod_tx_t         phymod_tx;
   3411     int                 idx;
   3412 
   3413     /* loop through all cores */
   3414     for (idx = 0; idx < pmc->num_phys; idx++) {
   3415         pm_phy = &pmc->phy[idx]->pm_phy;
   3416 
   3417         if (pm_phy == NULL) {
   3418             return SOC_E_INTERNAL;
   3419         }
   3420 
   3421         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(pm_phy, &phymod_tx));
   3422         *value = phymod_tx.pre;
   3423     }
   3424 
   3425     return(SOC_E_NONE);
   3426 }
   3427 
   3428 /* 
   3429  * viper_tx_fir_main_get
   3430  */
   3431 STATIC int
   3432 viper_tx_fir_main_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   3433 {
   3434     phymod_phy_access_t *pm_phy;
   3435     phymod_tx_t         phymod_tx;
   3436     int                 idx;
   3437 
   3438     /* loop through all cores */
   3439     for (idx = 0; idx < pmc->num_phys; idx++) {
   3440         pm_phy = &pmc->phy[idx]->pm_phy;
   3441 
   3442         if (pm_phy == NULL) {
   3443             return SOC_E_INTERNAL;
   3444         }
   3445 
   3446         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(pm_phy, &phymod_tx));
   3447         *value = phymod_tx.main;
   3448     }
   3449 
   3450     return(SOC_E_NONE);
   3451 }
   3452 
   3453 /* 
   3454  * viper_tx_fir_post_get
   3455  */
   3456 STATIC int
   3457 viper_tx_fir_post_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   3458 {
   3459     phymod_phy_access_t *pm_phy;
   3460     phymod_tx_t         phymod_tx;
   3461     int                 idx;
   3462 
   3463     /* loop through all cores */
   3464     for (idx = 0; idx < pmc->num_phys; idx++) {
   3465         pm_phy = &pmc->phy[idx]->pm_phy;
   3466 
   3467         if (pm_phy == NULL) {
   3468             return SOC_E_INTERNAL;
   3469         }
   3470 
   3471         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(pm_phy, &phymod_tx));
   3472         *value = phymod_tx.post;
   3473     }
   3474 
   3475     return(SOC_E_NONE);
   3476 }
   3477 
   3478 /* 
   3479  * viper_tx_fir_post2_get
   3480  */
   3481 STATIC int
   3482 viper_tx_fir_post2_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   3483 {
   3484     phymod_phy_access_t *pm_phy;
   3485     phymod_tx_t         phymod_tx;
   3486     int                 idx;
   3487 
   3488     /* loop through all cores */
   3489     for (idx = 0; idx < pmc->num_phys; idx++) {
   3490         pm_phy = &pmc->phy[idx]->pm_phy;
   3491 
   3492         if (pm_phy == NULL) {
   3493             return SOC_E_INTERNAL;
   3494         }
   3495 
   3496         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(pm_phy, &phymod_tx));
   3497         *value = phymod_tx.post2;
   3498     }
   3499 
   3500     return(SOC_E_NONE);
   3501 }
   3502 
   3503 /* 
   3504  * viper_tx_fir_post3_get
   3505  */
   3506 STATIC int
   3507 viper_tx_fir_post3_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   3508 {
   3509     phymod_phy_access_t *pm_phy;
   3510     phymod_tx_t         phymod_tx;
   3511     int                 idx;
   3512 
   3513     /* loop through all cores */
   3514     for (idx = 0; idx < pmc->num_phys; idx++) {
   3515         pm_phy = &pmc->phy[idx]->pm_phy;
   3516 
   3517         if (pm_phy == NULL) {
   3518             return SOC_E_INTERNAL;
   3519         }
   3520 
   3521         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(pm_phy, &phymod_tx));
   3522         *value = phymod_tx.post3;
   3523     }
   3524 
   3525     return(SOC_E_NONE);
   3526 }
   3527 
   3528 /* 
   3529  * viper_per_lane_preemphasis_get
   3530  */
   3531 STATIC int
   3532 viper_per_lane_preemphasis_get(soc_phymod_ctrl_t *pmc, int lane, uint32 *value)
   3533 {
   3534     soc_phymod_phy_t    *p_phy;
   3535     uint32              lane_map;
   3536     phymod_phy_access_t pm_phy_copy, *pm_phy;
   3537     phymod_tx_t         phymod_tx;
   3538 
   3539     /* locate the desired phy and lane */
   3540     SOC_IF_ERROR_RETURN(_viper_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map));
   3541 
   3542     /* Make a copy of the phy access and overwrite the desired lane */
   3543     pm_phy = &p_phy->pm_phy;
   3544     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   3545     pm_phy_copy.access.lane_mask = lane_map;
   3546 
   3547     SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   3548     *value = phymod_tx.pre  | (phymod_tx.main << 8) | (phymod_tx.post << 16);
   3549 
   3550     return(SOC_E_NONE);
   3551 }
   3552 
   3553 /* 
   3554  * viper_per_lane_driver_current_get
   3555  */
   3556 STATIC int
   3557 viper_per_lane_driver_current_get(soc_phymod_ctrl_t *pmc, int lane, uint32 *value)
   3558 {
   3559     soc_phymod_phy_t    *p_phy;
   3560     uint32              lane_map;
   3561     phymod_phy_access_t pm_phy_copy, *pm_phy;
   3562     phymod_tx_t         phymod_tx;
   3563 
   3564     /* locate the desired phy and lane */
   3565     SOC_IF_ERROR_RETURN(_viper_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map));
   3566 
   3567     /* Make a copy of the phy access and overwrite the desired lane */
   3568     pm_phy = &p_phy->pm_phy;
   3569     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   3570     pm_phy_copy.access.lane_mask = lane_map;
   3571 
   3572     SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   3573     *value = phymod_tx.amp;
   3574 
   3575     return(SOC_E_NONE);
   3576 }
   3577 
   3578 /* 
   3579  * viper_per_lane_prbs_poly_get
   3580  */
   3581 STATIC int
   3582 viper_per_lane_prbs_poly_get(soc_phymod_ctrl_t *pmc, int lane, uint32 *value)
   3583 {
   3584    return(SOC_E_UNAVAIL);
   3585 }
   3586 
   3587 /* 
   3588  * viper_per_lane_prbs_tx_invert_data_get
   3589  */
   3590 STATIC int
   3591 viper_per_lane_prbs_tx_invert_data_get(soc_phymod_ctrl_t *pmc, int lane, uint32 *value)
   3592 {
   3593    return(SOC_E_UNAVAIL);
   3594 }
   3595 
   3596 /* 
   3597  * viper_per_lane_prbs_tx_enable_get
   3598  */
   3599 STATIC int
   3600 viper_per_lane_prbs_tx_enable_get(soc_phymod_ctrl_t *pmc, int lane, uint32 *value)
   3601 {
   3602    return(SOC_E_UNAVAIL);
   3603 }
   3604 
   3605 /* 
   3606  * viper_per_lane_prbs_rx_enable_get
   3607  */
   3608 STATIC int
   3609 viper_per_lane_prbs_rx_enable_get(soc_phymod_ctrl_t *pmc, int lane, uint32 *value)
   3610 {
   3611    return(SOC_E_UNAVAIL);
   3612 }
   3613 
   3614 /* 
   3615  * viper_per_lane_prbs_rx_status_get
   3616  */
   3617 STATIC int
   3618 viper_per_lane_prbs_rx_status_get(soc_phymod_ctrl_t *pmc, int lane, uint32 *value)
   3619 {
   3620    /* $$$ Need to add diagnostic API */
   3621    return(SOC_E_UNAVAIL);
   3622 }
   3623 
   3624 /* 
   3625  * viper_per_lane_rx_peak_filter_get
   3626  */
   3627 STATIC int
   3628 viper_per_lane_rx_peak_filter_get(soc_phymod_ctrl_t *pmc, int lane, uint32 *value)
   3629 {
   3630     soc_phymod_phy_t    *p_phy;
   3631     uint32              lane_map;
   3632     phymod_phy_access_t pm_phy_copy, *pm_phy;
   3633     phymod_rx_t         phymod_rx;
   3634 
   3635     *value = 0;
   3636 
   3637     /* locate the desired phy and lane */
   3638     SOC_IF_ERROR_RETURN(_viper_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map));
   3639 
   3640     /* Make a copy of the phy access and overwrite the desired lane */
   3641     pm_phy = &p_phy->pm_phy;
   3642     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   3643     pm_phy_copy.access.lane_mask = lane_map;
   3644 
   3645     SOC_IF_ERROR_RETURN(phymod_phy_rx_get(&pm_phy_copy, &phymod_rx));
   3646     if (phymod_rx.peaking_filter.enable)
   3647         *value = phymod_rx.peaking_filter.value;
   3648 
   3649     return(SOC_E_NONE);
   3650 }
   3651 
   3652 /* 
   3653  * viper_per_lane_rx_vga_get
   3654  */
   3655 STATIC int
   3656 viper_per_lane_rx_vga_get(soc_phymod_ctrl_t *pmc, int lane, uint32 *value)
   3657 {
   3658     soc_phymod_phy_t    *p_phy;
   3659     uint32              lane_map;
   3660     phymod_phy_access_t pm_phy_copy, *pm_phy;
   3661     phymod_rx_t         phymod_rx;
   3662 
   3663     *value = 0;
   3664 
   3665     /* locate the desired phy and lane */
   3666     SOC_IF_ERROR_RETURN(_viper_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map));
   3667 
   3668     /* Make a copy of the phy access and overwrite the desired lane */
   3669     pm_phy = &p_phy->pm_phy;
   3670     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   3671     pm_phy_copy.access.lane_mask = lane_map;
   3672 
   3673     SOC_IF_ERROR_RETURN(phymod_phy_rx_get(&pm_phy_copy, &phymod_rx));
   3674     if (phymod_rx.vga.enable)
   3675         *value = phymod_rx.vga.value;
   3676 
   3677     return(SOC_E_NONE);
   3678 }
   3679 
   3680 /* 
   3681  * viper_per_lane_rx_dfe_tap_control_get
   3682  */
   3683 STATIC int
   3684 viper_per_lane_rx_dfe_tap_control_get(soc_phymod_ctrl_t *pmc, int lane, int tap, uint32 *value)
   3685 {
   3686     soc_phymod_phy_t    *p_phy;
   3687     uint32              lane_map;
   3688     phymod_phy_access_t pm_phy_copy, *pm_phy;
   3689     phymod_rx_t          phymod_rx;
   3690 
   3691     *value = 0;
   3692 
   3693     /* locate the desired phy and lane */
   3694     SOC_IF_ERROR_RETURN(_viper_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map));
   3695 
   3696     /* Make a copy of the phy access and overwrite the desired lane */
   3697     pm_phy = &p_phy->pm_phy;
   3698     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   3699     pm_phy_copy.access.lane_mask = lane_map;
   3700 
   3701     if (tap < 0 || tap >= COUNTOF(phymod_rx.dfe)) {
   3702         /* this can only happen with a coding error */
   3703         return SOC_E_INTERNAL;
   3704     }
   3705 
   3706     SOC_IF_ERROR_RETURN(phymod_phy_rx_get(&pm_phy_copy, &phymod_rx));
   3707     if (phymod_rx.dfe[tap].enable)
   3708        *value = phymod_rx.dfe[tap].value;
   3709 
   3710     return(SOC_E_NONE);
   3711 }
   3712 
   3713 
   3714 /* 
   3715  * viper_per_lane_rx_low_freq_filter_get
   3716  */
   3717 STATIC int
   3718 viper_per_lane_rx_low_freq_filter_get(soc_phymod_ctrl_t *pmc, int lane, uint32 *value)
   3719 {
   3720    return(SOC_E_UNAVAIL);
   3721 }
   3722 
   3723 /* 
   3724  * viper_rx_peak_filter_get
   3725  */
   3726 STATIC int 
   3727 viper_rx_peak_filter_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   3728 {
   3729     phymod_phy_access_t  *pm_phy;
   3730     phymod_rx_t          phymod_rx;
   3731 
   3732     /* just take the value from the first phy */
   3733     if (pmc->phy[0] == NULL) {
   3734         return SOC_E_INTERNAL;
   3735     }
   3736     pm_phy = &pmc->phy[0]->pm_phy;
   3737 
   3738     if (pm_phy == NULL) {
   3739         return SOC_E_INTERNAL;
   3740     }
   3741 
   3742     SOC_IF_ERROR_RETURN(phymod_phy_rx_get(pm_phy, &phymod_rx));
   3743     *value = phymod_rx.peaking_filter.value;
   3744 
   3745     return(SOC_E_NONE);
   3746 }
   3747 
   3748 
   3749 /* 
   3750  * viper_rx_tap_get
   3751  */
   3752 STATIC int 
   3753 viper_rx_tap_get(soc_phymod_ctrl_t *pmc, int tap, uint32 *value)
   3754 {
   3755     phymod_phy_access_t  *pm_phy;
   3756     phymod_rx_t          phymod_rx;
   3757 
   3758     if (tap < 0 || tap >= COUNTOF(phymod_rx.dfe)) {
   3759         /* this can only happen with a coding error */
   3760         return SOC_E_INTERNAL;
   3761     }
   3762     /* just take the value from the first phy */
   3763     if (pmc->phy[0] == NULL) {
   3764         return SOC_E_INTERNAL;
   3765     }
   3766     pm_phy = &pmc->phy[0]->pm_phy;
   3767 
   3768     if (pm_phy == NULL) {
   3769         return SOC_E_INTERNAL;
   3770     }
   3771 
   3772     SOC_IF_ERROR_RETURN(phymod_phy_rx_get(pm_phy, &phymod_rx));
   3773     *value = phymod_rx.dfe[tap].value;
   3774 
   3775     return(SOC_E_NONE);
   3776 }
   3777 
   3778 /* 
   3779  * viper_pi_control_get
   3780  */
   3781 STATIC int 
   3782 viper_pi_control_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   3783 {
   3784     phymod_phy_access_t  *pm_phy;
   3785     phymod_tx_override_t tx_override;
   3786 
   3787     /* just take the value from the first phy */
   3788     if (pmc->phy[0] == NULL) {
   3789         return SOC_E_INTERNAL;
   3790     }
   3791     pm_phy = &pmc->phy[0]->pm_phy;
   3792 
   3793     if (pm_phy == NULL) {
   3794         return SOC_E_INTERNAL;
   3795     }
   3796 
   3797     SOC_IF_ERROR_RETURN(phymod_phy_tx_override_get(pm_phy, &tx_override));
   3798     *value = tx_override.phase_interpolator.value;
   3799 
   3800     return(SOC_E_NONE);
   3801 }
   3802 
   3803 /* 
   3804  * viper_rx_signal_detect_get
   3805  */
   3806 STATIC int
   3807 viper_rx_signal_detect_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   3808 {
   3809    /* $$$ Need to add diagnostic API */
   3810    return(SOC_E_UNAVAIL);
   3811 }
   3812 
   3813 /* 
   3814  * viper_rx_seq_done_get
   3815  */
   3816 STATIC int
   3817 viper_rx_seq_done_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   3818 {
   3819     phymod_phy_access_t  *pm_phy;
   3820 
   3821     /* just take the value from the first phy */
   3822     if (pmc->phy[pmc->main_phy] == NULL) {
   3823         return SOC_E_INTERNAL;
   3824     }
   3825     pm_phy = &pmc->phy[pmc->main_phy]->pm_phy;
   3826 
   3827     if (pm_phy == NULL) {
   3828          return SOC_E_INTERNAL;
   3829     }
   3830 
   3831     SOC_IF_ERROR_RETURN(phymod_phy_rx_pmd_locked_get(pm_phy, value));
   3832 
   3833     return(SOC_E_NONE);
   3834 }
   3835 
   3836 /* 
   3837  * viper_eee_get
   3838  */
   3839 STATIC int
   3840 viper_eee_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   3841 {
   3842     phymod_phy_access_t  *pm_phy;
   3843 
   3844     /* just take the value from the first phy */
   3845     if (pmc->phy[0] == NULL) {
   3846         return SOC_E_INTERNAL;
   3847     }
   3848     pm_phy = &pmc->phy[0]->pm_phy;
   3849 
   3850     if (pm_phy == NULL) {
   3851          return SOC_E_INTERNAL;
   3852     }
   3853 
   3854     SOC_IF_ERROR_RETURN(phymod_phy_eee_get(pm_phy, value));
   3855 
   3856     return(SOC_E_NONE);
   3857 }
   3858 
   3859 
   3860 /* 
   3861  * viper_rx_ppm_get
   3862  */
   3863 STATIC int
   3864 viper_rx_ppm_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   3865 {
   3866     /* $$$ Need to add diagnostic API */
   3867     return(SOC_E_UNAVAIL);
   3868 }
   3869 
   3870 /* 
   3871  * viper_prbs_tx_poly_get
   3872  */
   3873 STATIC int
   3874 viper_prbs_tx_poly_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   3875 {
   3876     phymod_phy_access_t  *pm_phy;
   3877     phymod_prbs_t        prbs;
   3878     uint32_t flags = 0;
   3879 
   3880     /* just take the value from the first phy */
   3881     if (pmc->phy[0] == NULL) {
   3882         return SOC_E_INTERNAL;
   3883     }
   3884     pm_phy = &pmc->phy[0]->pm_phy;
   3885 
   3886     if (pm_phy == NULL) {
   3887         return SOC_E_INTERNAL;
   3888     }
   3889 
   3890     PHYMOD_PRBS_DIRECTION_TX_SET(flags);
   3891     SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy, flags, &prbs));
   3892 
   3893     *value = (int) prbs.poly;
   3894 
   3895     /* convert from PHYMOD enum to SDK enum */
   3896     switch(prbs.poly){
   3897     case phymodPrbsPoly7:
   3898         *value = SOC_PHY_PRBS_POLYNOMIAL_X7_X6_1;
   3899         break;
   3900     case phymodPrbsPoly9:
   3901         *value = SOC_PHY_PRBS_POLYNOMIAL_X9_X5_1;
   3902         break;
   3903     case phymodPrbsPoly15:
   3904         *value = SOC_PHY_PRBS_POLYNOMIAL_X15_X14_1;
   3905         break;
   3906     case phymodPrbsPoly23:
   3907         *value = SOC_PHY_PRBS_POLYNOMIAL_X23_X18_1;
   3908         break;
   3909     case phymodPrbsPoly31:
   3910         *value = SOC_PHY_PRBS_POLYNOMIAL_X31_X28_1;
   3911         break;
   3912     case phymodPrbsPoly11:
   3913         *value = SOC_PHY_PRBS_POLYNOMIAL_X11_X9_1;
   3914         break;
   3915     case phymodPrbsPoly58:
   3916         *value = SOC_PHY_PRBS_POLYNOMIAL_X58_X31_1; 
   3917         break;
   3918     default:
   3919         return SOC_E_INTERNAL;
   3920     }
   3921     return SOC_E_NONE;
   3922 }
   3923 /* 
   3924  * viper_prbs_rx_poly_get
   3925  */
   3926 STATIC int
   3927 viper_prbs_rx_poly_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   3928 {
   3929     phymod_phy_access_t  *pm_phy;
   3930     phymod_prbs_t        prbs;
   3931     uint32_t flags = 0;
   3932 
   3933     /* just take the value from the first phy */
   3934     if (pmc->phy[0] == NULL) {
   3935         return SOC_E_INTERNAL;
   3936     }
   3937     pm_phy = &pmc->phy[0]->pm_phy;
   3938 
   3939     if (pm_phy == NULL) {
   3940         return SOC_E_INTERNAL;
   3941     }
   3942 
   3943     PHYMOD_PRBS_DIRECTION_RX_SET(flags);
   3944     SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy, flags, &prbs));
   3945 
   3946     *value = (int) prbs.poly;
   3947 
   3948     /* convert from PHYMOD enum to SDK enum */
   3949     switch(prbs.poly){
   3950     case phymodPrbsPoly7:
   3951         *value = SOC_PHY_PRBS_POLYNOMIAL_X7_X6_1;
   3952         break;
   3953     case phymodPrbsPoly9:
   3954         *value = SOC_PHY_PRBS_POLYNOMIAL_X9_X5_1;
   3955         break;
   3956     case phymodPrbsPoly15:
   3957         *value = SOC_PHY_PRBS_POLYNOMIAL_X15_X14_1;
   3958         break;
   3959     case phymodPrbsPoly23:
   3960         *value = SOC_PHY_PRBS_POLYNOMIAL_X23_X18_1;
   3961         break;
   3962     case phymodPrbsPoly31:
   3963         *value = SOC_PHY_PRBS_POLYNOMIAL_X31_X28_1;
   3964         break;
   3965     case phymodPrbsPoly11:
   3966         *value = SOC_PHY_PRBS_POLYNOMIAL_X11_X9_1;
   3967         break;
   3968     case phymodPrbsPoly58:
   3969         *value = SOC_PHY_PRBS_POLYNOMIAL_X58_X31_1;
   3970         break;
   3971     default:
   3972         return SOC_E_INTERNAL;
   3973     }
   3974     return SOC_E_NONE;
   3975 }
   3976 
   3977 /* 
   3978  * viper_prbs_tx_invert_data_get
   3979  */
   3980 STATIC int
   3981 viper_prbs_tx_invert_data_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   3982 {
   3983     phymod_phy_access_t  *pm_phy;
   3984     phymod_prbs_t        prbs;
   3985     uint32_t flags = 0;
   3986 
   3987     /* just take the value from the first phy */
   3988     if (pmc->phy[0] == NULL) {
   3989         return SOC_E_INTERNAL;
   3990     }
   3991     pm_phy = &pmc->phy[0]->pm_phy;
   3992 
   3993     if (pm_phy == NULL) {
   3994         return SOC_E_INTERNAL;
   3995     }
   3996 
   3997     PHYMOD_PRBS_DIRECTION_TX_SET(flags);
   3998     SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy, flags, &prbs));
   3999     *value = prbs.invert;
   4000 
   4001     return(SOC_E_NONE);
   4002 }
   4003 
   4004 /* 
   4005  * viper_prbs_rx_invert_data_get
   4006  */
   4007 STATIC int
   4008 viper_prbs_rx_invert_data_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   4009 {
   4010     phymod_phy_access_t  *pm_phy;
   4011     phymod_prbs_t        prbs;
   4012     uint32_t flags = 0;
   4013 
   4014     /* just take the value from the first phy */
   4015     if (pmc->phy[0] == NULL) {
   4016         return SOC_E_INTERNAL;
   4017     }
   4018     pm_phy = &pmc->phy[0]->pm_phy;
   4019 
   4020     if (pm_phy == NULL) {
   4021         return SOC_E_INTERNAL;
   4022     }
   4023 
   4024     PHYMOD_PRBS_DIRECTION_RX_SET(flags);
   4025     SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy, flags, &prbs));
   4026     *value = prbs.invert;
   4027 
   4028     return(SOC_E_NONE);
   4029 }
   4030 
   4031 
   4032 /* 
   4033  * viper_prbs_tx_enable_get
   4034  */
   4035 STATIC int
   4036 viper_prbs_tx_enable_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   4037 {
   4038     phymod_phy_access_t  *pm_phy;
   4039     uint32_t flags = 0;
   4040 
   4041     /* just take the value from the first phy */
   4042     if (pmc->phy[0] == NULL) {
   4043         return SOC_E_INTERNAL;
   4044     }
   4045     pm_phy = &pmc->phy[0]->pm_phy;
   4046 
   4047     if (pm_phy == NULL) {
   4048         return SOC_E_INTERNAL;
   4049     }
   4050     PHYMOD_PRBS_DIRECTION_TX_SET(flags);
   4051     SOC_IF_ERROR_RETURN(phymod_phy_prbs_enable_get(pm_phy, flags, value));
   4052 
   4053     return(SOC_E_NONE);
   4054 }
   4055 
   4056 /* 
   4057  * viper_prbs_rx_enable_get
   4058  */
   4059 STATIC int
   4060 viper_prbs_rx_enable_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   4061 {
   4062     phymod_phy_access_t  *pm_phy;
   4063     uint32_t flags = 0;
   4064 
   4065     /* just take the value from the first phy */
   4066     if (pmc->phy[0] == NULL) {
   4067         return SOC_E_INTERNAL;
   4068     }
   4069     pm_phy = &pmc->phy[0]->pm_phy;
   4070 
   4071     if (pm_phy == NULL) {
   4072         return SOC_E_INTERNAL;
   4073     }
   4074 
   4075     PHYMOD_PRBS_DIRECTION_RX_SET(flags);
   4076     SOC_IF_ERROR_RETURN(phymod_phy_prbs_enable_get(pm_phy, flags, value));
   4077 
   4078     return(SOC_E_NONE);
   4079 }
   4080 
   4081 /* 
   4082  * viper_prbs_rx_status_get
   4083  */
   4084 STATIC int
   4085 viper_prbs_rx_status_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   4086 {
   4087     phymod_phy_access_t    *pm_phy;
   4088     phymod_prbs_status_t   prbs_tmp;
   4089     int idx, prbs_lock, lock_loss, error_count ;
   4090 
   4091     /* just take the value from the first phy */
   4092     if (pmc->phy[0] == NULL) {
   4093         return SOC_E_INTERNAL;
   4094     }
   4095 
   4096     prbs_lock   = 1 ; 
   4097     lock_loss   = 0 ;
   4098     error_count = 0 ;
   4099     for (idx = 0; idx < pmc->num_phys; idx++) {
   4100         pm_phy = &pmc->phy[idx]->pm_phy;
   4101 
   4102         if (pm_phy == NULL) {
   4103             return SOC_E_INTERNAL;
   4104         }
   4105         /* $$$ Need to add diagnostic API */
   4106         SOC_IF_ERROR_RETURN
   4107             (phymod_phy_prbs_status_get(pm_phy, 0, &prbs_tmp));
   4108 
   4109         if(prbs_tmp.prbs_lock==0) {
   4110             prbs_lock = 0 ;
   4111         } else {
   4112             if(prbs_tmp.prbs_lock_loss) {
   4113                 lock_loss = 1 ;
   4114             } else {
   4115                 error_count += prbs_tmp.error_count;
   4116             }
   4117         }
   4118     }
   4119     
   4120     if (prbs_lock == 0) {
   4121         *value = -1;
   4122     } else if ((lock_loss == 1) && (prbs_lock == 1)) {
   4123         *value = -2;
   4124     } else {
   4125         *value = error_count;
   4126     }
   4127     return(SOC_E_NONE);
   4128 }
   4129 
   4130 /* 
   4131  * viper_loopback_internal_pmd_get (this is the PMD global loopback)
   4132  */
   4133 STATIC int 
   4134 viper_loopback_internal_pmd_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   4135 {
   4136     phymod_phy_access_t    *pm_phy;
   4137     uint32_t               enable;
   4138 
   4139     /* just take the value from the first phy */
   4140     if (pmc->phy[0] == NULL) {
   4141         return SOC_E_INTERNAL;
   4142     }
   4143     pm_phy = &pmc->phy[0]->pm_phy;
   4144 
   4145     if (pm_phy == NULL) {
   4146         return SOC_E_INTERNAL;
   4147     }
   4148 
   4149     SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackGlobalPMD, &enable));
   4150     *value = enable;
   4151     return(SOC_E_NONE);
   4152 }
   4153 
   4154 
   4155 /* 
   4156  * viper_loopback_remote_get
   4157  */
   4158 STATIC int 
   4159 viper_loopback_remote_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   4160 {
   4161     phymod_phy_access_t    *pm_phy;
   4162     uint32_t               enable;
   4163 
   4164     /* just take the value from the first phy */
   4165     if (pmc->phy[0] == NULL) {
   4166         return SOC_E_INTERNAL;
   4167     }
   4168     pm_phy = &pmc->phy[0]->pm_phy;
   4169 
   4170     if (pm_phy == NULL) {
   4171         return SOC_E_INTERNAL;
   4172     }
   4173 
   4174     SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackRemotePMD, &enable));
   4175     *value = enable;
   4176     return(SOC_E_NONE);
   4177 }
   4178 
   4179 /* 
   4180  * viper_loopback_remote_pcs_get
   4181  */
   4182 STATIC int 
   4183 viper_loopback_remote_pcs_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   4184 {
   4185     phymod_phy_access_t    *pm_phy;
   4186     uint32_t               enable;
   4187 
   4188     /* just take the value from the first phy */
   4189     if (pmc->phy[0] == NULL) {
   4190         return SOC_E_INTERNAL;
   4191     }
   4192     pm_phy = &pmc->phy[0]->pm_phy;
   4193 
   4194     if (pm_phy == NULL) {
   4195         return SOC_E_INTERNAL;
   4196     }
   4197 
   4198     SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackRemotePCS, &enable));
   4199     *value = enable;
   4200     return(SOC_E_NONE);
   4201 }
   4202 
   4203 /* 
   4204  * viper_fec_get
   4205  */
   4206 STATIC int 
   4207 viper_fec_enable_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   4208 {
   4209     phymod_phy_access_t    *pm_phy;
   4210     uint32_t               enable;
   4211 
   4212     /* just take the value from the first phy */
   4213     if (pmc->phy[0] == NULL) {
   4214         return SOC_E_INTERNAL;
   4215     }
   4216     pm_phy = &pmc->phy[0]->pm_phy;
   4217 
   4218     if (pm_phy == NULL) {
   4219         return SOC_E_INTERNAL;
   4220     }
   4221 
   4222     SOC_IF_ERROR_RETURN(phymod_phy_fec_enable_get(pm_phy,  &enable));
   4223     *value = enable;
   4224 
   4225     return(SOC_E_NONE);
   4226 }
   4227 /* 
   4228  * viper_pattern_256bit_get 
   4229  *  
   4230  * CHECK SEMANTICS: assumption is that this procedure will retrieve the pattern 
   4231  * from Tier1 and return whether the tx pattern is enabled.  Note that this 
   4232  * is different from the 20 bit pattern retrieval semantics 
   4233  */
   4234 /* 
   4235  * viper_pattern_256bit_get 
   4236  *  
   4237  * CHECK SEMANTICS: assumption is that this procedure will retrieve the pattern 
   4238  * from Tier1 and return whether the tx pattern is enabled.  Note that this 
   4239  * is different from the 20 bit pattern retrieval semantics 
   4240  */
   4241 STATIC int
   4242 viper_pattern_get(soc_phymod_ctrl_t *pmc, viper_pattern_t* cfg_pattern)
   4243 {
   4244     phymod_phy_access_t    *pm_phy;
   4245     phymod_pattern_t       phymod_pattern;
   4246 
   4247     /* just take the value from the first phy */
   4248     if (pmc->phy[0] == NULL) {
   4249         return SOC_E_INTERNAL;
   4250     }
   4251     pm_phy = &pmc->phy[0]->pm_phy;
   4252 
   4253     if (pm_phy == NULL) {
   4254         return SOC_E_INTERNAL;
   4255     }
   4256 
   4257     SOC_IF_ERROR_RETURN(phymod_phy_pattern_config_get(pm_phy, &phymod_pattern));
   4258     sal_memcpy(cfg_pattern , phymod_pattern.pattern, sizeof(*cfg_pattern));
   4259     return(SOC_E_NONE);
   4260 }
   4261 
   4262 STATIC int
   4263 viper_pattern_len_get(soc_phymod_ctrl_t *pmc, uint32_t *value)
   4264 {
   4265     phymod_phy_access_t    *pm_phy;
   4266     phymod_pattern_t       phymod_pattern;
   4267 
   4268     /* just take the value from the first phy */
   4269     if (pmc->phy[0] == NULL) {
   4270         return SOC_E_INTERNAL;
   4271     }
   4272     pm_phy = &pmc->phy[0]->pm_phy;
   4273 
   4274     if (pm_phy == NULL) {
   4275         return SOC_E_INTERNAL;
   4276     }
   4277 
   4278     SOC_IF_ERROR_RETURN(phymod_phy_pattern_config_get(pm_phy, &phymod_pattern));
   4279     *value = phymod_pattern.pattern_len;
   4280     return(SOC_E_NONE);
   4281 }
   4282 
   4283 /* 
   4284  * viper_scrambler_get
   4285  */
   4286 STATIC int
   4287 viper_scrambler_get(soc_phymod_ctrl_t *pmc, soc_port_t port, uint32 *value)
   4288 {
   4289     phymod_phy_access_t     *pm_phy;
   4290     phymod_phy_inf_config_t config;
   4291     phymod_ref_clk_t        ref_clock = phymodRefClk156Mhz;
   4292 
   4293     /* just take the value from the first phy */
   4294     if (pmc->phy[0] == NULL) {
   4295         return SOC_E_INTERNAL;
   4296     }
   4297     pm_phy = &pmc->phy[0]->pm_phy;
   4298 
   4299     if (pm_phy == NULL) {
   4300         return SOC_E_INTERNAL;
   4301     }
   4302     
   4303     SOC_IF_ERROR_RETURN(phymod_phy_interface_config_get(pm_phy, 0 /* flags */, ref_clock, &config));
   4304     *value = PHYMOD_INTF_MODES_SCR_GET(&config);
   4305 
   4306     return(SOC_E_NONE);
   4307 }
   4308 
   4309 /*
   4310  * Function:
   4311  *      phy_viper_control_get
   4312  * Purpose:
   4313  *      Get current control settings of the PHY. 
   4314  * Parameters:
   4315  *      unit  - BCM unit number.
   4316  *      port  - Port number. 
   4317  *      type  - Control to update 
   4318  *      value - (OUT) Current setting for the control 
   4319  * Returns:     
   4320  *      SOC_E_NONE
   4321  */
   4322 STATIC int
   4323 phy_viper_control_get(int unit, soc_port_t port, soc_phy_control_t type, uint32 *value)
   4324 {
   4325     int                 rv;
   4326     phy_ctrl_t          *pc;
   4327     soc_phymod_ctrl_t   *pmc;
   4328     viper_config_t       *pCfg;
   4329 
   4330     /* coverity[mixed_enums] */
   4331     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
   4332         return (SOC_E_PARAM);
   4333     }
   4334 
   4335     /* locate phy control */
   4336     pc = INT_PHY_SW_STATE(unit, port);
   4337     if (pc == NULL) {
   4338         return SOC_E_INTERNAL;
   4339     }
   4340 
   4341     pmc = &pc->phymod_ctrl;
   4342     pCfg = (viper_config_t *) pc->driver_data;
   4343 
   4344     switch(type) {
   4345 
   4346     /* PREEMPHASIS */
   4347     case SOC_PHY_CONTROL_PREEMPHASIS_LANE0:
   4348         rv = viper_per_lane_preemphasis_get(pmc, 0, value);
   4349         break;
   4350     case SOC_PHY_CONTROL_PREEMPHASIS_LANE1:
   4351         rv = viper_per_lane_preemphasis_get(pmc, 1, value);
   4352         break;
   4353     case SOC_PHY_CONTROL_PREEMPHASIS_LANE2:
   4354         rv = viper_per_lane_preemphasis_get(pmc, 2, value);
   4355         break;
   4356     case SOC_PHY_CONTROL_PREEMPHASIS_LANE3:
   4357         rv = viper_per_lane_preemphasis_get(pmc, 3, value);
   4358         break;
   4359     case SOC_PHY_CONTROL_TX_FIR_PRE:
   4360         /* assume they are all the same as lane 0 */
   4361         rv = viper_tx_fir_pre_get(pmc, value);
   4362         break;
   4363     case SOC_PHY_CONTROL_TX_FIR_MAIN:
   4364         /* assume they are all the same as lane 0 */
   4365         rv = viper_tx_fir_main_get(pmc, value);
   4366         break;
   4367     case SOC_PHY_CONTROL_TX_FIR_POST:
   4368         /* assume they are all the same as lane 0 */
   4369         rv = viper_tx_fir_post_get(pmc, value);
   4370         break;
   4371     case SOC_PHY_CONTROL_TX_FIR_POST2:
   4372         /* assume they are all the same as lane 0 */
   4373         rv = viper_tx_fir_post2_get(pmc, value);
   4374         break;
   4375     case SOC_PHY_CONTROL_TX_FIR_POST3:
   4376         /* assume they are all the same as lane 0 */
   4377         rv = viper_tx_fir_post3_get(pmc, value);
   4378         break;
   4379 
   4380     /* DRIVER CURRENT */
   4381     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0:
   4382         rv = viper_per_lane_driver_current_get(pmc, 0, value);
   4383         break;
   4384     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1:
   4385         rv = viper_per_lane_driver_current_get(pmc, 1, value);
   4386         break;
   4387     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2:
   4388         rv = viper_per_lane_driver_current_get(pmc, 2, value);
   4389         break;
   4390     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3:
   4391         rv = viper_per_lane_driver_current_get(pmc, 3, value);
   4392         break;
   4393     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   4394         rv = viper_per_lane_driver_current_get(pmc, 0, value);
   4395         break;
   4396 
   4397     /* PRE-DRIVER CURRENT */
   4398     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0:
   4399         rv = SOC_E_UNAVAIL;
   4400         break;
   4401     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1:
   4402         rv = SOC_E_UNAVAIL;
   4403         break;
   4404     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2:
   4405         rv = SOC_E_UNAVAIL;
   4406         break;
   4407     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3:
   4408         rv = SOC_E_UNAVAIL;
   4409         break;
   4410     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   4411         rv = SOC_E_UNAVAIL;
   4412         break;
   4413 
   4414     /* POST2_DRIVER CURRENT */
   4415     case SOC_PHY_CONTROL_DRIVER_POST2_CURRENT:
   4416         rv = SOC_E_UNAVAIL;
   4417         break;
   4418 
   4419     /* RX PEAK FILTER */
   4420     case SOC_PHY_CONTROL_RX_PEAK_FILTER:
   4421         rv = viper_rx_peak_filter_get(pmc, value);
   4422         break;
   4423 
   4424     /* RX VGA */
   4425     case SOC_PHY_CONTROL_RX_VGA:
   4426         rv = SOC_E_UNAVAIL;
   4427         break;
   4428 
   4429     /* RX TAP */
   4430     case SOC_PHY_CONTROL_RX_TAP1:
   4431         rv = viper_rx_tap_get(pmc, 0, value);
   4432         break;
   4433     case SOC_PHY_CONTROL_RX_TAP2:
   4434         rv = viper_rx_tap_get(pmc, 1, value);
   4435         break;
   4436     case SOC_PHY_CONTROL_RX_TAP3:
   4437         rv = viper_rx_tap_get(pmc, 2, value);
   4438         break;
   4439     case SOC_PHY_CONTROL_RX_TAP4:
   4440         rv = viper_rx_tap_get(pmc, 3, value);
   4441         break;
   4442     case SOC_PHY_CONTROL_RX_TAP5:
   4443         rv = viper_rx_tap_get(pmc, 4, value);
   4444         break;
   4445 
   4446     /* RX SLICER */
   4447     case SOC_PHY_CONTROL_RX_PLUS1_SLICER:
   4448         rv = SOC_E_UNAVAIL;
   4449         break;
   4450     case SOC_PHY_CONTROL_RX_MINUS1_SLICER:
   4451         rv = SOC_E_UNAVAIL;
   4452         break;
   4453     case SOC_PHY_CONTROL_RX_D_SLICER:
   4454         rv = SOC_E_UNAVAIL;
   4455         break;
   4456 
   4457     /* PHASE INTERPOLATOR */
   4458     case SOC_PHY_CONTROL_PHASE_INTERP:
   4459         rv = viper_pi_control_get(pmc, value);
   4460         break;
   4461 
   4462     /* RX SIGNAL DETECT */
   4463     case SOC_PHY_CONTROL_RX_SIGNAL_DETECT:
   4464       rv = viper_rx_signal_detect_get(pmc, value);
   4465       break;
   4466     case SOC_PHY_CONTROL_RX_SEQ_DONE:
   4467       rv = viper_rx_seq_done_get(pmc, value);
   4468       break;
   4469     case SOC_PHY_CONTROL_RX_PPM:
   4470       rv = viper_rx_ppm_get(pmc, value);
   4471       break;
   4472     /* PRBS */
   4473     case SOC_PHY_CONTROL_PRBS_DECOUPLED_TX_POLYNOMIAL:
   4474       rv = viper_prbs_tx_poly_get(pmc, value);
   4475       break;
   4476     case SOC_PHY_CONTROL_PRBS_DECOUPLED_TX_INVERT_DATA:
   4477       rv = viper_prbs_tx_invert_data_get(pmc, value);
   4478       break;
   4479     case SOC_PHY_CONTROL_PRBS_DECOUPLED_TX_ENABLE:
   4480       rv = viper_prbs_tx_enable_get(pmc, value);
   4481       break;
   4482     case SOC_PHY_CONTROL_PRBS_DECOUPLED_RX_POLYNOMIAL:
   4483       rv = viper_prbs_rx_poly_get(pmc, value);
   4484       break;
   4485     case SOC_PHY_CONTROL_PRBS_DECOUPLED_RX_INVERT_DATA:
   4486       rv = viper_prbs_rx_invert_data_get(pmc, value);
   4487       break;
   4488     case SOC_PHY_CONTROL_PRBS_DECOUPLED_RX_ENABLE:
   4489       rv = viper_prbs_rx_enable_get(pmc, value);
   4490       break;
   4491     case SOC_PHY_CONTROL_PRBS_POLYNOMIAL:
   4492       rv = viper_prbs_tx_poly_get(pmc, value);
   4493       break;
   4494     case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA:
   4495       rv = viper_prbs_tx_invert_data_get(pmc, value);
   4496       break;
   4497     case SOC_PHY_CONTROL_PRBS_TX_ENABLE:
   4498       rv = viper_prbs_tx_enable_get(pmc, value);
   4499       break;
   4500     case SOC_PHY_CONTROL_PRBS_RX_ENABLE:
   4501       rv = viper_prbs_rx_enable_get(pmc, value);
   4502       break;
   4503     case SOC_PHY_CONTROL_PRBS_RX_STATUS:
   4504       rv = viper_prbs_rx_status_get(pmc, value);
   4505       break;
   4506 
   4507     /* LOOPBACK */
   4508     case SOC_PHY_CONTROL_LOOPBACK_REMOTE:
   4509        rv = viper_loopback_remote_get(pmc, value);
   4510        break;
   4511     case SOC_PHY_CONTROL_LOOPBACK_REMOTE_PCS_BYPASS:
   4512        rv = viper_loopback_remote_pcs_get(pmc, value);
   4513        break;
   4514     case SOC_PHY_CONTROL_LOOPBACK_PMD:
   4515        rv = viper_loopback_internal_pmd_get(pmc, value);
   4516        break;
   4517 
   4518     /* FEC */
   4519     case SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION:
   4520       rv = viper_fec_enable_get(pmc, value);
   4521       break;
   4522 
   4523     /* TX PATTERN */
   4524     case SOC_PHY_CONTROL_TX_PATTERN_256BIT:
   4525        rv = viper_pattern_get(pmc, &pCfg->pattern);
   4526       break;
   4527     case SOC_PHY_CONTROL_TX_PATTERN_LENGTH:
   4528        rv = viper_pattern_len_get(pmc, value);
   4529       break;
   4530     case SOC_PHY_CONTROL_TX_PATTERN_20BIT:
   4531        rv = viper_pattern_get(pmc, &pCfg->pattern);
   4532       break;
   4533 
   4534     /* SCRAMBLER */
   4535     case SOC_PHY_CONTROL_SCRAMBLER:
   4536        rv = viper_scrambler_get(pmc, port, value);
   4537        break;
   4538     case SOC_PHY_CONTROL_LANE_SWAP:
   4539         rv = viper_lane_map_get(pmc, value);
   4540         break;
   4541     /* EEE */
   4542     case SOC_PHY_CONTROL_EEE:
   4543         rv = viper_eee_get(pmc, value);
   4544         break;
   4545     case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT:
   4546        rv = viper_control_linkdown_transmit_get(pmc, value);
   4547        break;
   4548 
   4549     /* UNAVAIL */
   4550 
   4551 #if 0
   4552     /* BERT */
   4553     case SOC_PHY_CONTROL_BERT_TX_PACKETS:       /* fall through */
   4554     case SOC_PHY_CONTROL_BERT_RX_PACKETS:       /* fall through */
   4555     case SOC_PHY_CONTROL_BERT_RX_ERROR_BITS:    /* fall through */
   4556     case SOC_PHY_CONTROL_BERT_RX_ERROR_BYTES:   /* fall through */
   4557     case SOC_PHY_CONTROL_BERT_RX_ERROR_PACKETS: /* fall through */
   4558     case SOC_PHY_CONTROL_BERT_PATTERN:          /* fall through */
   4559     case SOC_PHY_CONTROL_BERT_PACKET_SIZE:      /* fall through */
   4560     case SOC_PHY_CONTROL_BERT_IPG:              /* fall through */
   4561         rv = SOC_E_NONE;
   4562         break;
   4563 
   4564     /* CUSTOM */
   4565     case SOC_PHY_CONTROL_CUSTOM1:
   4566       /* Obsolete ??
   4567       *value = DEV_CFG_PTR(pc)->custom1;
   4568       rv = SOC_E_NONE; */
   4569       break;
   4570 
   4571     /* SOFTWARE RX LOS */
   4572     case SOC_PHY_CONTROL_SOFTWARE_RX_LOS:
   4573        /* Was 
   4574        *value = DEV_CFG_PTR(pc)->sw_rx_los.enable ; */
   4575        rv = SOC_E_NONE ;
   4576        break ;
   4577 
   4578     /* UNAVAIL */
   4579     case SOC_PHY_CONTROL_PARALLEL_DETECTION:
   4580        rv = SOC_E_UNAVAIL;
   4581        break;
   4582 #endif
   4583     default:
   4584         rv = SOC_E_UNAVAIL;
   4585         break; 
   4586     }
   4587     return rv;
   4588 }     
   4589 
   4590 /*
   4591  * Function:
   4592  *      phy_viper_per_lane_control_set
   4593  * Purpose:
   4594  *      Configure PHY device specific control fucntion. 
   4595  * Parameters:
   4596  *      unit  - StrataSwitch unit #.
   4597  *      port  - StrataSwitch port #. 
   4598  *      lane  - lane number
   4599  *      type  - Control to update 
   4600  *      value - New setting for the control 
   4601  * Returns:     
   4602  *      SOC_E_NONE
   4603  */
   4604 STATIC int
   4605 phy_viper_per_lane_control_set(int unit, soc_port_t port, int lane, soc_phy_control_t type, uint32 value)
   4606 {
   4607     int                 rv;
   4608     phy_ctrl_t          *pc;
   4609     soc_phymod_ctrl_t   *pmc;
   4610 
   4611     /* locate phy control, phymod control, and the configuration data */
   4612     pc = INT_PHY_SW_STATE(unit, port);
   4613     if (pc == NULL) {
   4614         return SOC_E_INTERNAL;
   4615     }
   4616     pmc = &pc->phymod_ctrl;
   4617     /* coverity[mixed_enums] */
   4618     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
   4619         return SOC_E_PARAM;
   4620     }
   4621 
   4622     switch(type) {
   4623     case SOC_PHY_CONTROL_PREEMPHASIS:
   4624         rv = viper_per_lane_preemphasis_set(pmc, lane, value);
   4625         break; 
   4626     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   4627         rv = SOC_E_UNAVAIL;
   4628         break;
   4629     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   4630         rv = SOC_E_UNAVAIL;
   4631         break;
   4632     case SOC_PHY_CONTROL_DRIVER_POST2_CURRENT:
   4633         rv = SOC_E_UNAVAIL;
   4634         break;
   4635     case SOC_PHY_CONTROL_RX_TAP1:
   4636         rv = viper_per_lane_rx_dfe_tap_control_set (pmc, lane, 0 /* tap */, 1 /* enable */, value);
   4637         break;
   4638     case SOC_PHY_CONTROL_RX_TAP1_RELEASE:
   4639         rv = viper_per_lane_rx_dfe_tap_control_set (pmc, lane, 0 /* tap */, 0 /* release */, 0x8000);
   4640         break;
   4641     case SOC_PHY_CONTROL_RX_TAP2:
   4642         rv = viper_per_lane_rx_dfe_tap_control_set (pmc, lane, 1 /* tap */, 1 /* enable */, value);
   4643         break;
   4644     case SOC_PHY_CONTROL_RX_TAP2_RELEASE:
   4645         rv = viper_per_lane_rx_dfe_tap_control_set (pmc, lane, 1 /* tap */, 0 /* release */, 0x8000);
   4646         break;
   4647     case SOC_PHY_CONTROL_RX_TAP3:
   4648         rv = viper_per_lane_rx_dfe_tap_control_set (pmc, lane, 2 /* tap */, 1 /* enable */, value);
   4649         break;
   4650     case SOC_PHY_CONTROL_RX_TAP3_RELEASE:
   4651         rv = viper_per_lane_rx_dfe_tap_control_set (pmc, lane, 2 /* tap */, 0 /* release */, 0x8000);
   4652         break;
   4653     case SOC_PHY_CONTROL_RX_TAP4:
   4654         rv = viper_per_lane_rx_dfe_tap_control_set (pmc, lane, 3 /* tap */, 1 /* enable */, value);
   4655         break;
   4656     case SOC_PHY_CONTROL_RX_TAP4_RELEASE:
   4657         rv = viper_per_lane_rx_dfe_tap_control_set (pmc, lane, 3 /* tap */, 0 /* release */, 0x8000);
   4658         break;
   4659     case SOC_PHY_CONTROL_RX_TAP5:
   4660         rv = viper_per_lane_rx_dfe_tap_control_set (pmc, lane, 4 /* tap */, 1 /* enable */, value);
   4661         break;
   4662     case SOC_PHY_CONTROL_RX_TAP5_RELEASE:
   4663         rv = viper_per_lane_rx_dfe_tap_control_set (pmc, lane, 4 /* tap */, 0 /* release */, 0x8000);
   4664         break;
   4665 
   4666     case SOC_PHY_CONTROL_PRBS_POLYNOMIAL:
   4667         rv = viper_per_lane_prbs_poly_set(pmc, lane, value);
   4668         break;
   4669     case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA:
   4670         rv = viper_per_lane_prbs_tx_invert_data_set(pmc, lane, value);
   4671         break;
   4672     case SOC_PHY_CONTROL_PRBS_TX_ENABLE:
   4673         /* TX_ENABLE does both tx and rx */
   4674         rv = viper_per_lane_prbs_tx_enable_set(pmc, lane, value);
   4675         break; 
   4676     case SOC_PHY_CONTROL_PRBS_RX_ENABLE:
   4677         rv = SOC_E_NONE;
   4678         break;
   4679     case SOC_PHY_CONTROL_RX_PEAK_FILTER:
   4680         rv = viper_per_lane_rx_peak_filter_set(pmc, lane, 1 /* enable */, value);
   4681         break;
   4682     case SOC_PHY_CONTROL_RX_LOW_FREQ_PEAK_FILTER:
   4683         rv = viper_per_lane_rx_low_freq_filter_set(pmc, lane, value);
   4684         break;
   4685     case SOC_PHY_CONTROL_RX_VGA:
   4686         rv = viper_per_lane_rx_vga_set(pmc, lane, 1 /* enable */, value);
   4687         break;
   4688     case SOC_PHY_CONTROL_RX_VGA_RELEASE:
   4689         rv = viper_per_lane_rx_vga_set(pmc, lane, 0 /* release */, 0x8000);
   4690         break;
   4691     case SOC_PHY_CONTROL_RX_PLUS1_SLICER:
   4692         rv = SOC_E_UNAVAIL;
   4693         break; 
   4694     case SOC_PHY_CONTROL_RX_MINUS1_SLICER:
   4695         rv = SOC_E_UNAVAIL;
   4696         break; 
   4697     case SOC_PHY_CONTROL_RX_D_SLICER:
   4698         rv = SOC_E_UNAVAIL;
   4699         break;
   4700     default:
   4701         rv = SOC_E_UNAVAIL;
   4702         break; 
   4703     }
   4704 
   4705     return rv;
   4706 }
   4707 
   4708 /*
   4709  * Function:
   4710  *      phy_viper_per_lane_control_get
   4711  * Purpose:
   4712  *      Configure PHY device specific control fucntion. 
   4713  * Parameters:
   4714  *      unit  - StrataSwitch unit #.
   4715  *      port  - StrataSwitch port #. 
   4716  *      lane  - lane number
   4717  *      type  - Control to update 
   4718  *      value - New setting for the control 
   4719  * Returns:     
   4720  *      SOC_E_NONE
   4721  */
   4722 STATIC int
   4723 phy_viper_per_lane_control_get(int unit, soc_port_t port, int lane,
   4724                      soc_phy_control_t type, uint32 *value)
   4725 {
   4726     int                 rv;
   4727     phy_ctrl_t          *pc;
   4728     soc_phymod_ctrl_t   *pmc;
   4729 
   4730     /* locate phy control, phymod control, and the configuration data */
   4731     pc = INT_PHY_SW_STATE(unit, port);
   4732     if (pc == NULL) {
   4733         return SOC_E_INTERNAL;
   4734     }
   4735     pmc = &pc->phymod_ctrl;
   4736     /* coverity[mixed_enums] */
   4737     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
   4738         return SOC_E_PARAM;
   4739     }
   4740 
   4741     switch(type) {
   4742 
   4743     case SOC_PHY_CONTROL_PREEMPHASIS:
   4744         rv = viper_per_lane_preemphasis_get(pmc, lane, value);
   4745         break; 
   4746     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   4747         rv = SOC_E_UNAVAIL;
   4748         break;
   4749     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   4750         rv = SOC_E_UNAVAIL;
   4751         break;
   4752     case SOC_PHY_CONTROL_DRIVER_POST2_CURRENT:
   4753         rv = SOC_E_UNAVAIL;
   4754         break;
   4755     case SOC_PHY_CONTROL_PRBS_POLYNOMIAL:
   4756         rv = viper_per_lane_prbs_poly_get(pmc, lane, value);
   4757         break;
   4758     case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA:
   4759         rv = viper_per_lane_prbs_tx_invert_data_get(pmc, lane, value);
   4760         break;
   4761     case SOC_PHY_CONTROL_PRBS_TX_ENABLE:
   4762         rv = viper_per_lane_prbs_tx_enable_get(pmc, lane, value);
   4763         break;
   4764     case SOC_PHY_CONTROL_PRBS_RX_ENABLE:
   4765         rv = viper_per_lane_prbs_rx_enable_get(pmc, lane, value);
   4766         break;
   4767     case SOC_PHY_CONTROL_PRBS_RX_STATUS:
   4768         rv = viper_per_lane_prbs_rx_status_get(pmc, lane, value);
   4769         break;
   4770     case SOC_PHY_CONTROL_RX_PEAK_FILTER:
   4771         rv = viper_per_lane_rx_peak_filter_get(pmc, lane, value);
   4772         break;
   4773     case SOC_PHY_CONTROL_RX_VGA:
   4774         rv = viper_per_lane_rx_vga_get(pmc, lane, value);
   4775         break;
   4776     case SOC_PHY_CONTROL_RX_TAP1:
   4777         rv = viper_per_lane_rx_dfe_tap_control_get(pmc, lane, 0, value);
   4778         break;
   4779     case SOC_PHY_CONTROL_RX_TAP2:
   4780         rv = viper_per_lane_rx_dfe_tap_control_get(pmc, lane, 1, value);
   4781         break;
   4782     case SOC_PHY_CONTROL_RX_TAP3:
   4783         rv = viper_per_lane_rx_dfe_tap_control_get(pmc, lane, 2, value);
   4784         break;
   4785     case SOC_PHY_CONTROL_RX_TAP4:
   4786         rv = viper_per_lane_rx_dfe_tap_control_get(pmc, lane, 3, value);
   4787         break;
   4788     case SOC_PHY_CONTROL_RX_TAP5:
   4789         rv = viper_per_lane_rx_dfe_tap_control_get(pmc, lane, 4, value);
   4790         break;
   4791     case SOC_PHY_CONTROL_RX_LOW_FREQ_PEAK_FILTER:
   4792         rv = viper_per_lane_rx_low_freq_filter_get(pmc, lane, value);
   4793         break;
   4794     case SOC_PHY_CONTROL_RX_PLUS1_SLICER:
   4795         rv = SOC_E_UNAVAIL;
   4796         break; 
   4797     case SOC_PHY_CONTROL_RX_MINUS1_SLICER:
   4798         rv = SOC_E_UNAVAIL;
   4799         break; 
   4800     case SOC_PHY_CONTROL_RX_D_SLICER:
   4801         rv = SOC_E_UNAVAIL;
   4802         break; 
   4803     default:
   4804         rv = SOC_E_UNAVAIL;
   4805         break; 
   4806     }
   4807     return rv;
   4808 }
   4809 
   4810 /*
   4811  * Function:
   4812  *      phy_viper_reg_read
   4813  * Purpose:
   4814  *      Routine to read PHY register
   4815  * Parameters:
   4816  *      unit         - BCM unit number
   4817  *      port         - Port number
   4818  *      flags        - Flags which specify the register type
   4819  *      phy_reg_addr - Encoded register address
   4820  *      phy_data     - (OUT) Value read from PHY register
   4821  * Note:
   4822  *      This register read function is not thread safe. Higher level
   4823  * function that calls this function must obtain a per port lock
   4824  * to avoid overriding register page mapping between threads.
   4825  */
   4826 STATIC int
   4827 phy_viper_reg_read(int unit, soc_port_t port, uint32 flags,
   4828                   uint32 phy_reg_addr, uint32 *phy_reg_data)
   4829 {
   4830     phy_ctrl_t *pc;
   4831     soc_phymod_ctrl_t *pmc;
   4832     phymod_phy_access_t *pm_phy;
   4833     int idx;
   4834 
   4835     pc = INT_PHY_SW_STATE(unit, port);
   4836     if (pc == NULL) {
   4837         return SOC_E_INTERNAL;
   4838     }
   4839 
   4840     pmc = &pc->phymod_ctrl;
   4841     idx = pmc->main_phy ;
   4842     pm_phy = &pmc->phy[idx]->pm_phy;
   4843 
   4844     return phymod_phy_reg_read(pm_phy, phy_reg_addr, phy_reg_data);
   4845 }
   4846 
   4847 /*
   4848  * Function:
   4849  *      phy_viper_reg_write
   4850  * Purpose:
   4851  *      Routine to write PHY register
   4852  * Parameters:
   4853  *      uint         - BCM unit number
   4854  *      pc           - PHY state
   4855  *      flags        - Flags which specify the register type
   4856  *      phy_reg_addr - Encoded register address
   4857  *      phy_data     - Value write to PHY register
   4858  * Note:
   4859  *      This register read function is not thread safe. Higher level
   4860  * function that calls this function must obtain a per port lock
   4861  * to avoid overriding register page mapping between threads.
   4862  */
   4863 STATIC int
   4864 phy_viper_reg_write(int unit, soc_port_t port, uint32 flags,
   4865                    uint32 phy_reg_addr, uint32 phy_reg_data)
   4866 {
   4867     phy_ctrl_t *pc;
   4868     soc_phymod_ctrl_t *pmc;
   4869     phymod_phy_access_t *pm_phy;
   4870     int idx;
   4871 
   4872     pc = INT_PHY_SW_STATE(unit, port);
   4873     if (pc == NULL) {
   4874         return SOC_E_INTERNAL;
   4875     }
   4876 
   4877     pmc = &pc->phymod_ctrl;
   4878     for (idx = 0; idx < pmc->num_phys; idx++) {
   4879         pm_phy = &pmc->phy[idx]->pm_phy;
   4880         SOC_IF_ERROR_RETURN
   4881             (phymod_phy_reg_write(pm_phy, phy_reg_addr, phy_reg_data));
   4882     }
   4883     return SOC_E_NONE;
   4884 }
   4885 
   4886 /*
   4887  * Function:
   4888  *      phy_viper_reg_modify
   4889  * Purpose:
   4890  *      Routine to write PHY register
   4891  * Parameters:
   4892  *      uint         - BCM unit number
   4893  *      pc           - PHY state
   4894  *      flags        - Flags which specify the register type
   4895  *      phy_reg_addr - Encoded register address
   4896  *      phy_mo_data  - New value for the bits specified in phy_mo_mask
   4897  *      phy_mo_mask  - Bit mask to modify
   4898  * Note:
   4899  *      This function is not thread safe. Higher level
   4900  * function that calls this function must obtain a per port lock
   4901  * to avoid overriding register page mapping between threads.
   4902  */
   4903 STATIC int
   4904 phy_viper_reg_modify(int unit, soc_port_t port, uint32 flags,
   4905                     uint32 phy_reg_addr, uint32 phy_data,
   4906                     uint32 phy_data_mask)
   4907 {
   4908     phy_ctrl_t *pc;
   4909     soc_phymod_ctrl_t *pmc;
   4910     phymod_phy_access_t *pm_phy;
   4911     uint32 data32, tmp;
   4912     int idx;
   4913 
   4914     pc = INT_PHY_SW_STATE(unit, port);
   4915     if (pc == NULL) {
   4916         return SOC_E_INTERNAL;
   4917     }
   4918 
   4919     pmc = &pc->phymod_ctrl;
   4920     for (idx = 0; idx < pmc->num_phys; idx++) {
   4921         pm_phy = &pmc->phy[idx]->pm_phy;
   4922         SOC_IF_ERROR_RETURN
   4923             (phymod_phy_reg_read(pm_phy, phy_reg_addr, &data32));
   4924         tmp = data32;
   4925         data32 &= ~(phy_data_mask);
   4926         data32 |= (phy_data & phy_data_mask);
   4927         if (data32 != tmp) {
   4928             SOC_IF_ERROR_RETURN
   4929                 (phymod_phy_reg_write(pm_phy, phy_reg_addr, data32));
   4930         }
   4931     }
   4932     return SOC_E_NONE;
   4933 }
   4934 
   4935 STATIC void
   4936 phy_viper_cleanup(soc_phymod_ctrl_t *pmc)
   4937 {
   4938     int idx;
   4939     soc_phymod_phy_t *phy;
   4940     soc_phymod_core_t *core;
   4941 
   4942     for (idx = 0; idx < pmc->num_phys ; idx++) {
   4943         phy = pmc->phy[idx];
   4944         if (phy == NULL) {
   4945             LOG_WARN(BSL_LS_SOC_PHY,
   4946                      (BSL_META_U(pmc->unit,
   4947                                  "phy object is empty")));
   4948             continue;
   4949         }
   4950 
   4951         core = phy->core;
   4952         /* Destroy core object if not used anymore */
   4953         if (core && core->ref_cnt) {
   4954             if (--core->ref_cnt == 0) {
   4955                 PHYMOD_VDBG(VIPER_DBG_MEM, NULL,("clean_up core_p=%p\n", (void *)core)) ;
   4956                 soc_phymod_core_destroy(pmc->unit, core);
   4957             }
   4958         }
   4959 
   4960         /* Destroy phy object */
   4961         if (phy) {
   4962             PHYMOD_VDBG(VIPER_DBG_MEM, NULL,("clean_up phy=%p\n", (void *)phy)) ;
   4963             soc_phymod_phy_destroy(pmc->unit, phy);
   4964         }
   4965     }
   4966     pmc->num_phys = 0;
   4967 }
   4968 
   4969 STATIC void
   4970 phy_viper_core_init(phy_ctrl_t *pc, soc_phymod_core_t *core,
   4971                    phymod_bus_t *core_bus, uint32 core_addr)
   4972 {
   4973     phymod_core_access_t *pm_core;
   4974     phymod_access_t *pm_acc;
   4975 
   4976     core->unit = pc->unit;
   4977     core->port = pc->port;
   4978     core->read = pc->read;
   4979     core->write = pc->write;
   4980     core->wrmask = pc->wrmask;
   4981 
   4982     pm_core = &core->pm_core;
   4983     phymod_core_access_t_init(pm_core);
   4984     pm_acc = &pm_core->access;
   4985     phymod_access_t_init(pm_acc);
   4986     PHYMOD_ACC_USER_ACC(pm_acc) = core;
   4987     PHYMOD_ACC_BUS(pm_acc) = core_bus;
   4988     PHYMOD_ACC_ADDR(pm_acc) = core_addr;
   4989 #if 0
   4990     if (soc_property_port_get(pc->unit, pc->port, "viper_sim", 0) == 45) {
   4991         PHYMOD_ACC_F_CLAUSE45_SET(pm_acc);
   4992     }
   4993 #endif
   4994     return;
   4995 }
   4996 
   4997 
   4998 /*
   4999  * Function:
   5000  *      phy_viper_probe
   5001  * Purpose:
   5002  *      xx
   5003  * Parameters:
   5004  *      pc->phy_id   (IN)
   5005  *      pc->unit     (IN)
   5006  *      pc->port     (IN)
   5007  *      pc->size     (OUT) - memory required by phy port
   5008  *      pc->dev_name (OUT) - set to port device name
   5009  *  
   5010  * Note:
   5011  */
   5012 STATIC int
   5013 phy_viper_probe(int unit, phy_ctrl_t *pc)
   5014 {
   5015     int rv, idx;
   5016     uint32 lane_map[3], num_phys, core_id, phy_id, found;
   5017     phymod_bus_t core_bus;
   5018     phymod_dispatch_type_t phy_type;
   5019     phymod_core_access_t *pm_core;
   5020     phymod_phy_access_t *pm_phy;
   5021     phymod_access_t *pm_acc;
   5022     soc_phymod_ctrl_t *pmc;
   5023     soc_phymod_phy_t *phy;
   5024     soc_phymod_core_t *core;
   5025     soc_phymod_core_t core_probe;
   5026     soc_info_t *si;
   5027     phyident_core_info_t core_info[8];  
   5028     int array_max = 8;
   5029     int array_size = 0;
   5030     int port;
   5031     int phy_port;  /* physical port number */
   5032 
   5033     /* Initialize PHY bus */
   5034     SOC_IF_ERROR_RETURN(phymod_bus_t_init(&core_bus));
   5035     core_bus.bus_name = "viper_sim"; 
   5036     core_bus.read = _viper_reg_read; 
   5037     core_bus.write = _viper_reg_write;
   5038 
   5039     /* Configure PHY bus properties */
   5040     if (pc->wrmask) {
   5041         PHYMOD_BUS_CAP_WR_MODIFY_SET(&core_bus);
   5042         PHYMOD_BUS_CAP_LANE_CTRL_SET(&core_bus);
   5043     }
   5044 
   5045     port = pc->port;
   5046     pmc = &pc->phymod_ctrl;
   5047     si = &SOC_INFO(unit);
   5048     if (soc_feature(unit, soc_feature_logical_port_num)) {
   5049         phy_port = si->port_l2p_mapping[port];
   5050     } else {
   5051         phy_port = port;
   5052     }
   5053 
   5054     /* Install clean up function */
   5055     pmc->unit = pc->unit;
   5056     pmc->cleanup = phy_viper_cleanup;
   5057     if(SOC_IS_GREYHOUND2(unit) || soc_feature(unit, soc_feature_wh2)) {
   5058         pmc->symbols = &bcmi_sgmiip2x4_serdes_symbols;
   5059     }
   5060     else {
   5061         pmc->symbols = &bcmi_viper_xgxs_symbols;
   5062     }
   5063     pmc->main_phy= 0;
   5064 
   5065     if(SOC_IS_SABER2(unit)) { 
   5066         pc->lane_num = SOC_PORT_BINDEX(unit, phy_port);
   5067         pc->chip_num = SOC_BLOCK_NUMBER(unit, SOC_PORT_BLOCK(unit, phy_port));
   5068     }
   5069     else if (SOC_IS_GREYHOUND2(unit)){
   5070         /* every block has 2 SGMIIPlus2 cores, every core has 4 lanes */
   5071         pc->lane_num = SOC_PORT_BINDEX(unit, phy_port) % 4;
   5072         pc->chip_num = SOC_BLOCK_NUMBER(unit, SOC_PORT_BLOCK(unit, phy_port)) * 2 + SOC_PORT_BINDEX(unit, phy_port) / 4;
   5073     }
   5074     else if (soc_feature(unit, soc_feature_wh2)) {
   5075         /* viper ports belong to  gport3 and gport4 block of wolfhound2 */
   5076         pc->lane_num = SOC_PORT_BINDEX(unit, phy_port);
   5077         pc->chip_num = SOC_BLOCK_NUMBER(unit, SOC_PORT_BLOCK(unit, phy_port)) - 3;
   5078     }
   5079     /* request memory for the configuration structure */
   5080     pc->size = sizeof(viper_config_t);
   5081 
   5082     /* Bit N corresponds to lane N in lane_map */
   5083     lane_map[0] = 0xf;
   5084     lane_map[1] = 0 ;
   5085     lane_map[2] = 0 ;
   5086     num_phys = 1;
   5087     switch (si->port_num_lanes[port]) {
   5088     case 4:
   5089         pc->phy_mode = PHYCTRL_QUAD_LANE_PORT; 
   5090         break;
   5091     case 2:
   5092         lane_map[0] = 0x3;
   5093         pc->phy_mode = PHYCTRL_DUAL_LANE_PORT;
   5094         break;
   5095     case 1:
   5096     case 0:
   5097         lane_map[0] = 0x1;
   5098         pc->phy_mode = PHYCTRL_ONE_LANE_PORT;
   5099         break;
   5100     default:
   5101         return SOC_E_CONFIG;
   5102     }
   5103     lane_map[0] <<= pc->lane_num;
   5104 
   5105     /* we need to get the other core id if more than 1 core per port */
   5106     if (num_phys > 1) {
   5107         /* get the other core address */
   5108         SOC_IF_ERROR_RETURN
   5109             (soc_phy_addr_multi_get(unit, port, array_max, &array_size, &core_info[0]));
   5110     } else {
   5111         core_info[0].mdio_addr = pc->phy_id;
   5112     }
   5113 
   5114     phy_type = phymodDispatchTypeViper;
   5115 
   5116     /* Probe cores */
   5117     for (idx = 0; idx < num_phys ; idx++) {
   5118         phy_viper_core_init(pc, &core_probe, &core_bus,
   5119                            core_info[idx].mdio_addr);
   5120         /* Check that core is indeed an VIPER core */
   5121         pm_core = &core_probe.pm_core;
   5122         pm_core->type = phy_type;
   5123         rv = phymod_core_identify(pm_core, 0, &found);
   5124         if (SOC_FAILURE(rv)) {
   5125             return rv;
   5126         }
   5127         if (!found) {
   5128             return SOC_E_NOT_FOUND;
   5129         }
   5130     }
   5131 
   5132     rv = SOC_E_NONE;
   5133     for (idx = 0; idx < num_phys ; idx++) {
   5134         /* Set core and phy IDs based on PHY address */
   5135         core_id = pc->phy_id + idx;
   5136         phy_id = (lane_map[idx] << 16) | core_id;
   5137 
   5138         /* Create PHY object */
   5139         rv = soc_phymod_phy_create(unit, phy_id, &pmc->phy[idx]);
   5140         if (SOC_FAILURE(rv)) {
   5141             break;
   5142         }
   5143         pmc->num_phys++;
   5144 
   5145         /* Initialize phy object */
   5146         phy = pmc->phy[idx];
   5147         pm_phy = &phy->pm_phy;
   5148         phymod_phy_access_t_init(pm_phy);
   5149 
   5150         /* Find or create associated core object */
   5151         rv = soc_phymod_core_find_by_id(unit, core_id, &phy->core);
   5152         if (rv == SOC_E_NOT_FOUND) {
   5153             rv = soc_phymod_core_create(unit, core_id, &phy->core);
   5154         }
   5155         if (SOC_FAILURE(rv)) {
   5156             break;
   5157         }        
   5158     }
   5159     if (SOC_FAILURE(rv)) {
   5160         phy_viper_cleanup(pmc);
   5161         return rv;
   5162     }
   5163 
   5164     for (idx = 0; idx < pmc->num_phys ; idx++) {
   5165         phy = pmc->phy[idx];
   5166         core = phy->core;
   5167         pm_core = &core->pm_core;
   5168 
   5169         /* Initialize core object if newly created */
   5170         if (core->ref_cnt == 0) {
   5171             sal_memcpy(&core->pm_bus, &core_bus, sizeof(core->pm_bus));
   5172             phy_viper_core_init(pc, core, &core->pm_bus,
   5173                                core_info[idx].mdio_addr);
   5174             /* Set dispatch type */
   5175             pm_core->type = phy_type;
   5176         }
   5177         core->ref_cnt++;        
   5178 
   5179         /* Initialize phy access based on associated core */
   5180         pm_acc = &phy->pm_phy.access;
   5181         sal_memcpy(pm_acc, &pm_core->access, sizeof(*pm_acc));
   5182         phy->pm_phy.type = phy_type;
   5183         PHYMOD_ACC_LANE_MASK(pm_acc) = lane_map[idx];
   5184     }
   5185 
   5186     return SOC_E_NONE;
   5187 }
   5188 
   5189 
   5190 /***********************************************************************
   5191  *
   5192  * PASS-THROUGH NOTIFY ROUTINES
   5193  */
   5194 
   5195 /*
   5196  * Function:
   5197  *      _viper_notify_duplex
   5198  * Purpose:
   5199  *      Program duplex if (and only if) serdesphy is an intermediate PHY.
   5200  * Parameters:
   5201  *      unit - BCM unit number.
   5202  *      port - Port number.
   5203  *      duplex - Boolean, TRUE indicates full duplex, FALSE
   5204  *              indicates half.
   5205  * Returns:
   5206  *      SOC_E_XXX
   5207  * Notes:
   5208  *      If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to
   5209  *      talk directly to an external fiber module.
   5210  *
   5211  *      If PHY_FLAGS_FIBER is clear, the PHY is being used in
   5212  *      pass-through mode to talk to an external SGMII PHY.
   5213  *
   5214  *      When used in pass-through mode, autoneg must be turned off and
   5215  *      the speed/duplex forced to match that of the external PHY.
   5216  */
   5217 
   5218 STATIC int
   5219 _viper_notify_duplex(int unit, soc_port_t port, uint32 duplex)
   5220 {
   5221     SOC_IF_ERROR_RETURN
   5222         (phy_viper_duplex_set(unit, port, duplex));
   5223     return SOC_E_NONE;
   5224 }
   5225 
   5226 /*
   5227  * Function:
   5228  *      _viper_stop
   5229  * Purpose:
   5230  *      Put serdesviper SERDES in or out of reset depending on conditions
   5231  */
   5232 
   5233 STATIC int
   5234 _viper_stop(int unit, soc_port_t port)
   5235 {
   5236     phy_ctrl_t* pc; 
   5237     soc_phymod_ctrl_t *pmc;
   5238     phymod_phy_access_t *pm_phy;
   5239     phymod_phy_power_t phy_power;
   5240     int  stop, copper, speed;
   5241 
   5242     pc = INT_PHY_SW_STATE(unit, port);
   5243     pmc = &pc->phymod_ctrl;
   5244     pm_phy = &pmc->phy[pmc->main_phy]->pm_phy;
   5245 
   5246     if (pc->phy_mode != PHYCTRL_ONE_LANE_PORT) {
   5247         return SOC_E_NONE;
   5248     }
   5249 
   5250     /* 'Stop' only for speeds < 10G. */ 
   5251     SOC_IF_ERROR_RETURN
   5252         (phy_viper_speed_get(unit,port,&speed));
   5253     if(10000 <= speed) {
   5254         return SOC_E_NONE;
   5255     }
   5256     copper = (pc->stop &
   5257               PHY_STOP_COPPER) != 0;
   5258 
   5259     stop = ((pc->stop &
   5260              (PHY_STOP_PHY_DIS |
   5261               PHY_STOP_DRAIN)) != 0 ||
   5262             (copper &&
   5263              (pc->stop &
   5264               (PHY_STOP_MAC_DIS |
   5265                PHY_STOP_DUPLEX_CHG |
   5266                PHY_STOP_SPEED_CHG)) != 0));
   5267 
   5268     LOG_INFO(BSL_LS_SOC_PHY,
   5269              (BSL_META_U(pc->unit,
   5270                          "qsgmiie_stop: u=%d p=%d copper=%d stop=%d flg=0x%x\n"),
   5271               unit, port, copper, stop,
   5272               pc->stop));
   5273     if (stop) {
   5274         phy_power.tx = phymodPowerOff;
   5275         phy_power.rx = phymodPowerOff;
   5276     } else {
   5277         phy_power.tx = phymodPowerOn;
   5278         phy_power.rx = phymodPowerOn;
   5279     }
   5280     SOC_IF_ERROR_RETURN
   5281         (phymod_phy_power_set(pm_phy, &phy_power));
   5282     return SOC_E_NONE;
   5283 }
   5284 
   5285 /*
   5286  * Function:
   5287  *      _viper_notify_stop
   5288  * Purpose:
   5289  *      Add a reason to put serdesviper PHY in reset.
   5290  * Parameters:
   5291  *      unit - BCM unit number.
   5292  *      port - Port number.
   5293  *      flags - Reason to stop
   5294  * Returns:     
   5295  *      SOC_E_XXX
   5296  */
   5297 
   5298 STATIC int
   5299 _viper_notify_stop(int unit, soc_port_t port, uint32 flags)
   5300 {
   5301     INT_PHY_SW_STATE(unit, port)->stop |= flags;
   5302     return _viper_stop(unit, port);
   5303 }
   5304 
   5305 /*  
   5306  * Function:
   5307  *      _viper_notify_resume
   5308  * Purpose:
   5309  *      Remove a reason to put serdesviper PHY in reset.
   5310  * Parameters:
   5311  *      unit - BCM unit number.
   5312  *      port - Port number.
   5313  *      flags - Reason to stop
   5314  * Returns:     
   5315  *      SOC_E_XXX
   5316  */
   5317 
   5318 STATIC int
   5319 _viper_notify_resume(int unit, soc_port_t port, uint32 flags)
   5320 {   
   5321     INT_PHY_SW_STATE(unit, port)->stop &= ~flags;
   5322     return _viper_stop(unit, port);
   5323 }
   5324 
   5325 /*
   5326  * Function:
   5327  *      _viper_notify_speed
   5328  * Purpose:
   5329  *      Program duplex if (and only if) serdesviper is an intermediate PHY.
   5330  * Parameters:
   5331  *      unit - BCM unit number.
   5332  *      port - Port number.
   5333  *      speed - Speed to program.
   5334  * Returns:
   5335  *      SOC_E_XXX
   5336  * Notes:
   5337  *      If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to
   5338  *      talk directly to an external fiber module.
   5339  *
   5340  *      If PHY_FLAGS_FIBER is clear, the PHY is being used in
   5341  *      pass-through mode to talk to an external SGMII PHY.
   5342  *
   5343  *      When used in pass-through mode, autoneg must be turned off and
   5344  *      the speed/duplex forced to match that of the external PHY.
   5345  */
   5346 
   5347 STATIC int
   5348 _viper_notify_speed(int unit, soc_port_t port, uint32 speed)
   5349 {
   5350     phy_ctrl_t* pc; 
   5351     viper_config_t *pCfg;
   5352     int  fiber;
   5353 
   5354     pc = INT_PHY_SW_STATE(unit, port);
   5355     pCfg = (viper_config_t *) pc->driver_data;
   5356     fiber = pCfg->fiber_pref;
   5357 
   5358     LOG_INFO(BSL_LS_SOC_PHY,
   5359              (BSL_META_U(pc->unit,
   5360                          "_qsgmiie_notify_speed: "
   5361                          "u=%d p=%d speed=%d fiber=%d\n"),
   5362               unit, port, speed, fiber));
   5363 
   5364     if (SAL_BOOT_SIMULATION) {
   5365         return SOC_E_NONE;
   5366     }
   5367 
   5368     /* Put SERDES PHY in reset */
   5369     SOC_IF_ERROR_RETURN
   5370         (_viper_notify_stop(unit, port, PHY_STOP_SPEED_CHG));
   5371 
   5372     /* Update speed */
   5373     SOC_IF_ERROR_RETURN
   5374         (phy_viper_speed_set(unit, port, speed));
   5375 
   5376     /* Take SERDES PHY out of reset */
   5377     SOC_IF_ERROR_RETURN
   5378         (_viper_notify_resume(unit, port, PHY_STOP_SPEED_CHG));
   5379 
   5380     /* Autonegotiation must be turned off to talk to external PHY */
   5381     if (!PHY_SGMII_AUTONEG_MODE(unit, port) && PHY_EXTERNAL_MODE(unit, port)) {
   5382         SOC_IF_ERROR_RETURN
   5383             (phy_viper_an_set(unit, port, FALSE));
   5384     }
   5385     return SOC_E_NONE;
   5386 }
   5387 
   5388 /*
   5389  * Function:
   5390  *      viper_media_setup
   5391  * Purpose:     
   5392  *      Configure 
   5393  * Parameters:
   5394  *      unit - BCM unit number.
   5395  *      port - Port number.
   5396  *      fiber_mode - Configure for fiber mode
   5397  *      fiber_pref - Fiber preferrred (if fiber mode)
   5398  * Returns:     
   5399  *      SOC_E_XXX
   5400  */
   5401 STATIC int
   5402 _viper_notify_interface(int unit, soc_port_t port, uint32 intf)
   5403 {
   5404     return SOC_E_NONE;
   5405 }
   5406 
   5407 /*
   5408  * Function:
   5409  *      _viper_notify_mac_loopback
   5410  * Purpose:
   5411  *      Turn on rx clock compensation in mac loopback mode for
   5412  *      applicable XGXS devices
   5413  * Parameters:
   5414  *      unit - BCM unit number.
   5415  *      port - Port number.
   5416  *      enable - TRUE: In MAC loopback mode, FALSE: Not in MAC loopback mode 
   5417  * Returns:
   5418  *      SOC_E_XXX
   5419  */
   5420 STATIC int
   5421 _viper_notify_mac_loopback(int unit, soc_port_t port, uint32 enable)
   5422 {
   5423     return SOC_E_NONE;
   5424 }
   5425 
   5426 STATIC int
   5427 phy_viper_notify(int unit, soc_port_t port,
   5428                        soc_phy_event_t event, uint32 value)
   5429 {
   5430     int             rv;
   5431     rv = SOC_E_NONE ;
   5432     if (event >= phyEventCount) {
   5433         return SOC_E_PARAM;
   5434     }
   5435 
   5436     switch(event) {
   5437     case phyEventInterface:
   5438         rv = (_viper_notify_interface(unit, port, value));
   5439         break;
   5440     case phyEventDuplex:
   5441         rv = (_viper_notify_duplex(unit, port, value));
   5442         break;
   5443     case phyEventSpeed:
   5444         rv = (_viper_notify_speed(unit, port, value));
   5445         break;
   5446     case phyEventStop:
   5447         rv = (_viper_notify_stop(unit, port, value));
   5448         break;
   5449     case phyEventResume:
   5450         rv = (_viper_notify_resume(unit, port, value));
   5451         break;
   5452     case phyEventAutoneg:
   5453 #if 0
   5454         rv = (_viper_an_set(unit, port, value));
   5455 #endif
   5456         break;
   5457     case phyEventMacLoopback:
   5458         rv = (_viper_notify_mac_loopback(unit, port, value));
   5459         break;
   5460     case phyEventLpiBypass:
   5461         PHYMOD_LPI_BYPASS_SET(value);
   5462         rv = phy_viper_control_set(unit, port, SOC_PHY_CONTROL_EEE, value);
   5463         break;
   5464     default:
   5465         rv = SOC_E_UNAVAIL;
   5466         break;
   5467     }
   5468 
   5469     return rv;
   5470 }
   5471 
   5472 
   5473 /*
   5474  * Function:
   5475  *      phy_viper_master_set
   5476  * Purpose:
   5477  *      Configure master mode
   5478  * Parameters:
   5479  *      unit - StrataSwitch unit #.
   5480  *      port - StrataSwitch port #.
   5481  *      master - Master mode.
   5482  * Returns:
   5483  *      SOC_E_NONE/SOC_E_UNAVAIL
   5484  */
   5485 STATIC int
   5486 phy_viper_master_set(int unit, soc_port_t port, int master)
   5487 {
   5488     if (master != SOC_PORT_MS_SLAVE)
   5489         return SOC_E_UNAVAIL;
   5490 
   5491     return SOC_E_NONE;
   5492 }
   5493 
   5494 /*
   5495  * Function:
   5496  *      phy_viper_master_get
   5497  * Purpose:
   5498  *      this function is meant for 1000Base-T PHY. Added here to support
   5499  *      internal PHY regression test
   5500  * Parameters:
   5501  *      unit - StrataSwitch unit #.
   5502  *      port - StrataSwitch port #.
   5503  *      master - (OUT) SOC_PORT_MS_*
   5504  * Returns:
   5505  *      SOC_E_NONE
   5506  * Notes:
   5507  *      The master mode is retrieved for the ACTIVE medium.
   5508  */
   5509 STATIC int
   5510 phy_viper_master_get(int unit, soc_port_t port, int *master)
   5511 {
   5512     *master = SOC_PORT_MS_SLAVE;
   5513 
   5514     return SOC_E_NONE;
   5515 }
   5516 
   5517 /*
   5518  * Function:
   5519  *      phy_viper_diag_ctrl
   5520  * Purpose:
   5521  *      xx
   5522  * Parameters:
   5523  *      unit - BCM unit number.
   5524  *      port - Port number. 
   5525 
   5526  * Returns:     
   5527  *      SOC_E_NONE
   5528  */
   5529 
   5530 STATIC int
   5531 phy_viper_diag_ctrl(
   5532     int unit,        /* unit */
   5533     soc_port_t port, /* port */
   5534     uint32 inst,     /* the specific device block the control action directs to */
   5535     int op_type,     /* operation types: read,write or command sequence */
   5536     int op_cmd,      /* command code */
   5537     void *arg)       /* command argument based on op_type/op_cmd */
   5538 {
   5539     switch(op_cmd) {
   5540         case PHY_DIAG_CTRL_PCS:
   5541             LOG_INFO(BSL_LS_SOC_PHY,
   5542                      (BSL_META_U(unit,
   5543                                  "phy_temod_diag_ctrl: "
   5544                                  "u=%d p=%d PHY_DIAG_CTRL_PCS 0x%x\n"),
   5545                       unit, port, PHY_DIAG_CTRL_PCS));
   5546 			SOC_IF_ERROR_RETURN(viper_pcs_status_dump(unit, port, arg));
   5547             break;
   5548         default:
   5549             if (op_type == PHY_DIAG_CTRL_SET) {
   5550                 SOC_IF_ERROR_RETURN(phy_viper_control_set(unit,port,op_cmd,PTR_TO_INT(arg)));
   5551             } else if (op_type == PHY_DIAG_CTRL_GET) {
   5552                 SOC_IF_ERROR_RETURN(phy_viper_control_get(unit,port,op_cmd,(uint32 *)arg));
   5553             }
   5554             break ;
   5555         }
   5556     return (SOC_E_NONE);
   5557 }
   5558 
   5559 
   5560 #ifdef BROADCOM_DEBUG
   5561 void
   5562 viper_state_dump(int unit, soc_port_t port)
   5563 {
   5564     /* Show PHY configuration summary */
   5565     /* Lane status */
   5566     /* Show Counters */
   5567     /* Dump Registers */
   5568 }
   5569 #endif /* BROADCOM_DEBUG */
   5570 
   5571 /*
   5572  * Variable:
   5573  *      viper_drv
   5574  * Purpose:
   5575  *      Phy Driver for VIPER 
   5576  */
   5577 phy_driver_t phy_viper_drv = {
   5578     /* .drv_name                      = */ "VIPER PHYMOD PHY Driver",
   5579     /* .pd_init                       = */ phy_viper_init,
   5580     /* .pd_reset                      = */ phy_null_reset,
   5581     /* .pd_link_get                   = */ phy_viper_link_get,
   5582     /* .pd_enable_set                 = */ phy_viper_enable_set,
   5583     /* .pd_enable_get                 = */ phy_viper_enable_get,
   5584     /* .pd_duplex_set                 = */ phy_viper_duplex_set,
   5585     /* .pd_duplex_get                 = */ phy_viper_duplex_get,
   5586     /* .pd_speed_set                  = */ phy_viper_speed_set,
   5587     /* .pd_speed_get                  = */ phy_viper_speed_get,
   5588     /* .pd_master_set                 = */ phy_viper_master_set,
   5589     /* .pd_master_get                 = */ phy_viper_master_get,
   5590     /* .pd_an_set                     = */ phy_viper_an_set,
   5591     /* .pd_an_get                     = */ phy_viper_an_get,
   5592     /* .pd_adv_local_set              = */ NULL, /* Deprecated */
   5593     /* .pd_adv_local_get              = */ NULL, /* Deprecated */
   5594     /* .pd_adv_remote_get             = */ NULL, /* Deprecated */ 
   5595     /* .pd_lb_set                     = */ phy_viper_lb_set,
   5596     /* .pd_lb_get                     = */ phy_viper_lb_get,
   5597     /* .pd_interface_set              = */ phy_viper_interface_set,
   5598     /* .pd_interface_get              = */ phy_viper_interface_get,
   5599     /* .pd_ability                    = */ NULL, /* Deprecated */ 
   5600     /* .pd_linkup_evt                 = */ NULL,
   5601     /* .pd_linkdn_evt                 = */ NULL,
   5602     /* .pd_mdix_set                   = */ phy_null_mdix_set,
   5603     /* .pd_mdix_get                   = */ phy_null_mdix_get,
   5604     /* .pd_mdix_status_get            = */ phy_null_mdix_status_get,
   5605     /* .pd_medium_config_set          = */ NULL,
   5606     /* .pd_medium_config_get          = */ NULL,
   5607     /* .pd_medium_get                 = */ phy_null_medium_get,
   5608     /* .pd_cable_diag                 = */ NULL,
   5609     /* .pd_link_change                = */ NULL,
   5610     /* .pd_control_set                = */ phy_viper_control_set,
   5611     /* .pd_control_get                = */ phy_viper_control_get,
   5612     /* .pd_reg_read                   = */ phy_viper_reg_read,
   5613     /* .pd_reg_write                  = */ phy_viper_reg_write,
   5614     /* .pd_reg_modify                 = */ phy_viper_reg_modify,
   5615     /* .pd_notify                     = */ phy_viper_notify,
   5616     /* .pd_probe                      = */ phy_viper_probe,
   5617     /* .pd_ability_advert_set         = */ phy_viper_ability_advert_set, 
   5618     /* .pd_ability_advert_get         = */ phy_viper_ability_advert_get,
   5619     /* .pd_ability_remote_get         = */ phy_viper_ability_remote_get,
   5620     /* .pd_ability_local_get          = */ phy_viper_ability_local_get,
   5621     /* .pd_firmware_set               = */ NULL,
   5622     /* .pd_timesync_config_set        = */ NULL,
   5623     /* .pd_timesync_config_get        = */ NULL,
   5624     /* .pd_timesync_control_set       = */ NULL,
   5625     /* .pd_timesync_control_set       = */ NULL,
   5626     /* .pd_diag_ctrl                  = */ phy_viper_diag_ctrl,
   5627     /* .pd_lane_control_set           = */ phy_viper_per_lane_control_set,    
   5628     /* .pd_lane_control_get           = */ phy_viper_per_lane_control_get
   5629 };
   5630 
   5631 STATIC int
   5632 _phy_viper_enable_set(int unit, soc_port_t port, int enable)
   5633 {
   5634     phy_ctrl_t                *pc;
   5635     soc_phymod_ctrl_t         *pmc;
   5636     phymod_phy_access_t       *pm_phy;
   5637     phymod_phy_power_t        phy_power;   
   5638 
   5639     /* locate phy control */
   5640     pc = INT_PHY_SW_STATE(unit, port);
   5641     if (pc == NULL) {
   5642         return SOC_E_INTERNAL;
   5643     }
   5644 
   5645     pmc = &pc->phymod_ctrl;
   5646     pm_phy = &pmc->phy[pmc->main_phy]->pm_phy;
   5647 
   5648     if (enable) {
   5649         phy_power.tx = phymodPowerOn; 
   5650         phy_power.rx = phymodPowerOn; 
   5651     } else {
   5652         phy_power.tx = phymodPowerOff; 
   5653         phy_power.rx = phymodPowerOff; 
   5654     }
   5655 
   5656     SOC_IF_ERROR_RETURN(phymod_phy_power_set(pm_phy, &phy_power));
   5657     /*viper_phy_power_set(&pm_phy->access, &power); */ 
   5658 
   5659     return SOC_E_NONE;
   5660 }
   5661 
   5662 
   5663 
   5664 
   5665 
   5666 #else
   5667 int _viper_not_empty;
   5668 #endif /*  INCLUDE_XGXS_VIPER */
   5669