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

phy8806x.c (290247B)


      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:        phy8806x.c
      8  * Purpose:     Support Broadcom BCP8806X external PHY.
      9  */
     10 
     11 /*
     12  *   This module implements an NTSW SDK Phy driver for the BCM8806X PHY.
     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  *   BCM8806X.  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_tsce_per_lane_control_set and
     36  *     .phy_tsce_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  *   tsce_config_t
     60  *   Driver specific data.  This structure is used by tsce 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 #ifdef BCM_CMICM_SUPPORT
    112 #include <soc/cmicm.h>
    113 #endif
    114 
    115 #if defined(INCLUDE_PHY_8806X)
    116 
    117 #include "phy8806x.h"
    118 #include "phy8806x_ctr.h"
    119 #include "phy8806x_syms.h"
    120 #include <phymod/phymod.h>
    121 #include <phymod/phymod_debug.h>
    122 #include <phymod/phymod_diagnostics.h>
    123 #include <appl/diag/diag.h>
    124 #include "phy8806x_funcs.h"
    125 
    126 #ifdef PORTMOD_SUPPORT
    127 #include <soc/portmod/portmod.h>
    128 #endif
    129 
    130 #if defined(INCLUDE_FCMAP)
    131 #include <soc/fcmapphy.h>
    132 #endif
    133 #include "../../../libs/phymod/chip/phy8806x/phy8806x_xmod_api.h"
    134 
    135 #define PMD_TEST_FIRMWARE
    136 #define PHY8806X_DEBUG              0
    137 
    138 #define NUM_LANES             4    /* num of lanes per core */
    139 #define MAX_NUM_LANES         4    /* max num of lanes per port */
    140 
    141 
    142 #define PHYMOD_INTF_CR4    (1 << SOC_PORT_IF_CR4)
    143 
    144 #define PHY8806X_40G_10G_INTF(_if)  ((_if) == SOC_PORT_IF_KR4 || (_if) == SOC_PORT_IF_XLAUI || \
    145                              (_if) == SOC_PORT_IF_CR4 || (_if) == SOC_PORT_IF_SR || \
    146                              (_if) == SOC_PORT_IF_KR || (_if) == SOC_PORT_IF_CR || \
    147                              (_if) == SOC_PORT_IF_XFI || (_if) == SOC_PORT_IF_SFI)
    148 
    149 #define PHY8806X_40G_10G_INTF_ALL   (PHY8806X_IF_KR4 | PHY8806X_IF_XLAUI | PHY8806X_IF_CR4 | PHY8806X_IF_SR | \
    150                         PHY8806X_IF_KR | PHY8806X_IF_CR | PHY8806X_IF_XFI | PHY8806X_IF_SFI)
    151 
    152 #define GEARBOX_LINE_LANE_CNT    4
    153 
    154 #define PHY8806X_LANE_NAME_LEN   30
    155 
    156 #define PHY8806X_MEASSURE_DOWNLOAD_TIME
    157 
    158 /* index to TX drive configuration table for each VCO setting.
    159  */
    160 typedef enum txdrv_inxs {
    161     TXDRV_XFI_INX = 0, /* 10G XFI */
    162     TXDRV_XLAUI_INX,   /* 40G XLAUI mode  */
    163     TXDRV_SFI_INX,     /* 10G SR fiber mode */
    164     TXDRV_SFIDAC_INX,  /* 10G SFI DAC mode */
    165     TXDRV_SR4_INX,     /* 40G SR4 */
    166     TXDRV_AN_INX,      /* a common entry for autoneg mode */
    167     TXDRV_DFT_INX,     /* temp for any missing speed modes */
    168     TXDRV_LAST_INX     /* always last */
    169 } TXDRV_INXS_t;
    170 
    171 /* Port mode */
    172 typedef enum {
    173     _BFCMAPPER_PORT_MODE_QUAD = 0,
    174     _BFCMAPPER_PORT_MODE_TRI_0122 = 1,
    175     _BFCMAPPER_PORT_MODE_TRI_0023 = 2,
    176     _BFCMAPPER_PORT_MODE_DUAL = 3,
    177     _BFCMAPPER_PORT_MODE_SINGLE = 4
    178 } _bfcmapper_port_mode_t;
    179 
    180 typedef enum {
    181     REPEATER_AN_PHASE_NONE = -1,
    182     REPEATER_AN_PHASE_0,
    183     REPEATER_AN_PHASE_1,
    184     REPEATER_AN_PHASE_2
    185 }  repeater_an_phase_t;
    186 
    187 #define REPEATER_AN_PHASE0_LOCKED   1
    188 #define REPEATER_AN_PHASE0_CL74     2
    189 #define REPEATER_AN_PHASE0_CL91     4
    190 #define REPEATER_AN_PHASE1_LOCKED   8
    191 #define REPEATER_AN_PHASE0_RETRY    10
    192 #define REPEATER_AN_PHASE1_RETRY    10
    193 
    194 #define REPEATER_FS_RESET_TRIAL     20
    195 
    196 #define TXDRV_ENTRY_NUM     (TXDRV_LAST_INX)
    197 
    198 #define PHY8806X_IF_NULL   (1 << SOC_PORT_IF_NULL)
    199 #define PHY8806X_IF_SR     (1 << SOC_PORT_IF_SR)
    200 #define PHY8806X_IF_SR2  (1 << SOC_PORT_IF_MII)
    201 #define PHY8806X_IF_SR4    (1 << SOC_PORT_IF_SR4)
    202 #define PHY8806X_IF_KR     (1 << SOC_PORT_IF_KR)
    203 #define PHY8806X_IF_KR2    (1 << SOC_PORT_IF_TBI)
    204 #define PHY8806X_IF_KR4    (1 << SOC_PORT_IF_KR4)
    205 #define PHY8806X_IF_CR     (1 << SOC_PORT_IF_CR)
    206 #define PHY8806X_IF_CR2    (1 << SOC_PORT_IF_RGMII)
    207 #define PHY8806X_IF_CR4    (1 << SOC_PORT_IF_CR4)
    208 #define PHY8806X_IF_XFI    (1 << SOC_PORT_IF_XFI)
    209 #define PHY8806X_IF_SFI    (1 << SOC_PORT_IF_SFI)
    210 #define PHY8806X_IF_XLAUI  (1 << SOC_PORT_IF_XLAUI)
    211 #define PHY8806X_IF_XGMII  (1 << SOC_PORT_IF_XGMII)
    212 #define PHY8806X_IF_ILKN   (1 << SOC_PORT_IF_ILKN)
    213 
    214 #define PHY8806X_40G_10G_INTF(_if)  ((_if) == SOC_PORT_IF_KR4 || (_if) == SOC_PORT_IF_XLAUI || \
    215                              (_if) == SOC_PORT_IF_CR4 || (_if) == SOC_PORT_IF_SR || \
    216                              (_if) == SOC_PORT_IF_KR || (_if) == SOC_PORT_IF_CR || \
    217                              (_if) == SOC_PORT_IF_XFI || (_if) == SOC_PORT_IF_SFI)
    218 
    219 #define PHY8806X_40G_10G_INTF_ALL   (PHY8806X_IF_KR4 | PHY8806X_IF_XLAUI | PHY8806X_IF_CR4 | PHY8806X_IF_SR | \
    220                         PHY8806X_IF_KR | PHY8806X_IF_CR | PHY8806X_IF_XFI | PHY8806X_IF_SFI)
    221 
    222 #define PHY8806X_CL73_HPAM_VS_SW        0x8
    223 #define PHY8806X_CL73_HPAM              0x6
    224 #define PHY8806X_CL73_CL37              0x5
    225 #define PHY8806X_MSA                    0x4
    226 #define PHY8806X_CL73_MSA               0x3
    227 #define PHY8806X_CL73_WO_BAM            0x2
    228 #define PHY8806X_CL73_W_BAM             0x1
    229 #define PHY8806X_CL73_DISABLE           0x0
    230 
    231 #define TO(_pc) (((phy8806x_config_t *)((_pc) + 1))->to)
    232 #define FIRMWARE(_pc) (((phy8806x_config_t *)((_pc) + 1))->firmware)
    233 #define FIRMWARE_LEN(_pc) (((phy8806x_config_t *)((_pc) + 1))->firmware_len)
    234 #define DL_DIVIDEND(_pc) (((phy8806x_config_t *)((_pc) + 1))->dl_dividend)
    235 #define DL_DIVISOR(_pc) (((phy8806x_config_t *)((_pc) + 1))->dl_divisor)
    236 #define ETH_CTR(_pc) (((phy8806x_config_t *)((_pc) + 1))->inbctr)
    237 #define PMD_SIZE(_pc) (((phy8806x_config_t *)((_pc) + 1))->pmd_size)
    238 #define PMD_CRC(_pc) (((phy8806x_config_t *)((_pc) + 1))->pmd_crc)
    239 #define TOP_DEV_REV_ID(_pc) (((phy8806x_config_t *)((_pc) + 1))->top_dev_rev_id)
    240 #define LED_TX(_pc) (((phy8806x_config_t *)((_pc) + 1))->led_tx)
    241 #define LED_RX(_pc) (((phy8806x_config_t *)((_pc) + 1))->led_rx)
    242 #define LED_SPEED(_pc) (((phy8806x_config_t *)((_pc) + 1))->led_speed)
    243 
    244 #define PORT_ADDRESS(_base_addr, _sys, _mig) ( ((_base_addr) & ((0x1 << 27) | 0xffff)) |  ((((_sys) << 3) + ((_mig) << 2)  + 1) << 19) )
    245 #define LOW16(_x)  ( (_x) & 0xffff )
    246 #define HIGH16(_x) ( ((_x) >> 16) & 0xffff )
    247 
    248 #define RETRY_COUNT 5
    249 
    250 #define WRITE_BLK_SIZE 4
    251 
    252 extern uint8 bcm_8806x_firmware[];
    253 
    254 extern int bcm_8806x_firmware_size;
    255 
    256 static char *dev_name_8806x = "BCM8806x";
    257 static sal_mutex_t xmod_mutex[SOC_MAX_NUM_DEVICES];
    258 
    259 #define XMOD_MUTEX_TIMEOUT 10000000 /* 10ms */
    260 
    261 #define PHY_IS_BCM8806X_A0(_pc) (PHY_IS_BCM8806X(_pc) \
    262                                    && ((TOP_DEV_REV_ID(_pc) & 0x00ff0000) == 0x00010000))
    263 #define PHY_IS_BCM8806X_B0(_pc) (PHY_IS_BCM8806X(_pc) \
    264                                    && ((TOP_DEV_REV_ID(_pc) & 0x00ff0000) == 0x00110000))
    265 #define PHY_IS_BCM88060(_pc) (PHY_IS_BCM8806X(_pc) \
    266                                    && ((TOP_DEV_REV_ID(_pc) & 0xff) == 0x60))
    267 #define PHY_IS_BCM88061(_pc) (PHY_IS_BCM8806X(_pc) \
    268                                    && ((TOP_DEV_REV_ID(_pc) & 0xff) == 0x61))
    269 #define PHY_IS_BCM88064(_pc) (PHY_IS_BCM8806X(_pc) \
    270                                    && ((TOP_DEV_REV_ID(_pc) & 0xff) == 0x64))
    271 #define PHY_IS_BCM88068(_pc) (PHY_IS_BCM8806X(_pc) \
    272                                    && ((TOP_DEV_REV_ID(_pc) & 0xff) == 0x68))
    273 
    274 #ifdef BE_HOST
    275 #define HOST2LE32(_x) (_shr_swap32((_x)))
    276 #define LE2HOST32(_x) (_shr_swap32((_x)))
    277 #else
    278 #define HOST2LE32(_x) (_x)
    279 #define LE2HOST32(_x) (_x)
    280 #endif
    281 
    282 STATIC int phy8806x_cl72_enable_set(soc_phymod_ctrl_t *pmc, uint32 value);
    283 STATIC int phy_8806x_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability);
    284 STATIC int phy_8806x_ability_advert_set(int unit, soc_port_t port,
    285                           soc_port_ability_t *ability);
    286 STATIC int _phy_8806x_write_to_arm(int unit, phy_ctrl_t *pc, uint32 addr, uint8 *data,int len);
    287 STATIC int _phy_8806x_xmod_command_ack(int unit, phy_ctrl_t *pc);
    288 STATIC int _phy_8806x_xmod_command_send(int unit, phy_ctrl_t *pc, int mode_opcode,  uint32 arg[], int arg_size);
    289 STATIC int _phy_8806x_xmod_result_recv(int unit, phy_ctrl_t *pc, uint32 result[], int result_size);
    290 STATIC int _phy_8806x_axi_write(int unit,phy_ctrl_t *pc, uint32 addr, uint32 data[], int size);
    291 STATIC int _phy_8806x_axi_read(int unit,phy_ctrl_t *pc, uint32 addr, uint32 data[], int size);
    292 STATIC int _pmd_enable(int unit, phy_ctrl_t *pc, int sys);
    293 STATIC int _pmd_disable(int unit, phy_ctrl_t *pc, int sys);
    294 STATIC int _pmd_start(int unit, phy_ctrl_t *pc, int sys);
    295 STATIC int _tsc_reg_read(int unit, phy_ctrl_t *pc, int mode, int tsc_port, int pmd, int pll, uint32 reg, uint16 *value);
    296 STATIC int _tsc_reg_write(int unit, phy_ctrl_t *pc, int mode, int tsc_port, int pmd, int pll, uint32 reg, uint16 value, uint16 mask);
    297 int tsc_reg_read_test_base(int unit, int port, int sys, int pmd, int pll, uint32 reg);
    298 int tsc_reg_write_test_base(int unit, int port, int sys, int pmd, int pll, uint32 reg, uint16 value, uint16 mask); 
    299 int phy_8806x_xmod_command(int unit, int port, int mode_opcode,  uint32 arg[], int arg_size, uint32 result[], int result_size);
    300 STATIC int phy_8806x_an_get(int unit, soc_port_t port, int *an, int *an_done);
    301 STATIC int phy8806x_forced_speed_line_side_set(soc_phymod_ctrl_t *pmc, uint32 value);
    302 STATIC int phy8806x_forced_speed_line_side_get(soc_phymod_ctrl_t *pmc, uint32 *value);
    303 STATIC int phy8806x_flow_control_mode_set(soc_phymod_ctrl_t *pmc, uint32 value, uint8 ingress);
    304 STATIC int phy8806x_flow_control_mode_get(soc_phymod_ctrl_t *pmc, uint8 ingress, uint32 *value);
    305 STATIC int phy8806x_psm_cos_bmp_set(soc_phymod_ctrl_t *pmc, uint32 value);
    306 STATIC int phy8806x_psm_cos_bmp_get(soc_phymod_ctrl_t *pmc, uint32* value);
    307 STATIC int phy8806x_pfc_use_ip_cos_set(soc_phymod_ctrl_t *pmc, uint32 value);
    308 STATIC int phy8806x_pfc_use_ip_cos_get(soc_phymod_ctrl_t *pmc, uint32* value);
    309 STATIC int _phy8806x_dump_buffer(int unit, int port, unsigned char *arg);
    310 STATIC int phy_8806x_an_set(int unit, soc_port_t port, int enable);
    311 STATIC int phy8806x_autoneg_line_side_set(soc_phymod_ctrl_t *pmc, uint32 enable);
    312 STATIC int phy8806x_autoneg_line_side_get(soc_phymod_ctrl_t *pmc, uint32 *enable);
    313 STATIC int phy_8806x_fw_stat_read(int unit, int port, int offset,  uint32_t result[], int result_size);
    314 extern int phy8806x_tsc_pmd_lock_status (const phymod_access_t *pa, uint8_t *pmd_rx_lock);
    315 
    316 /*
    317  * Function:
    318  *      _8806x_reg_read
    319  * Doc:
    320  *      register read operations
    321  * Parameters:
    322  *      unit            - (IN)  unit number
    323  *      core_addr       - (IN)  core address
    324  *      reg_addr        - (IN)  address to read
    325  *      val             - (OUT) read value
    326  */
    327 STATIC int 
    328 _8806x_reg_read(void* user_acc, uint32_t core_addr, uint32_t reg_addr, uint32_t *val)
    329 {
    330     uint16 data16;
    331     int rv = SOC_E_NONE;
    332     soc_phymod_core_t *core = (soc_phymod_core_t *)user_acc;
    333     phymod_core_access_t *pm_core = &core->pm_core;
    334     phymod_access_t *phyacc = &pm_core->access;
    335     int pll = PHYMOD_ACC_PLLIDX(phyacc);
    336     phy_ctrl_t *pc = EXT_PHY_SW_STATE(core->unit, core->port);
    337     int pmd = (reg_addr & 0x08000000) ? 1 : 0;
    338     int sys = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 1 : 0;
    339     int tsc_port, lane_mode;
    340 
    341     tsc_port = (sys << 3) + (pc->phy_id & 0x7) + 1;
    342     lane_mode = (reg_addr >> 16) & 7;
    343 
    344     rv = _tsc_reg_read(core->unit, pc, lane_mode, tsc_port, pmd, pll, (reg_addr & 0xffff), &data16);
    345 
    346     *val = data16;
    347 
    348     return rv;
    349 }
    350 
    351 /*
    352  * Function:
    353  *      _8806x_reg_write
    354  * Doc:
    355  *      register write operations
    356  * Parameters:
    357  *      unit            - (IN)  unit number
    358  *      core_addr       - (IN)  core address
    359  *      reg_addr        - (IN)  address to write
    360  *      val             - (IN)  write value
    361  */
    362 STATIC int 
    363 _8806x_reg_write(void* user_acc, uint32_t core_addr, uint32_t reg_addr, uint32_t val)
    364 {
    365     int rv = SOC_E_NONE;
    366     soc_phymod_core_t *core = (soc_phymod_core_t *)user_acc;
    367     phymod_core_access_t *pm_core = &core->pm_core;
    368     phymod_access_t *phyacc = &pm_core->access;
    369     int pll = PHYMOD_ACC_PLLIDX(phyacc);
    370     phy_ctrl_t *pc = EXT_PHY_SW_STATE(core->unit, core->port);
    371     int pmd = (reg_addr & 0x08000000) ? 1 : 0;
    372     int sys = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 1 : 0;
    373     int tsc_port, lane_mode;
    374     uint16 value = val & 0xffff;
    375     uint16 mask = (val & 0xffff0000) ? ((~val) >> 16) : (val >> 16);
    376 
    377     tsc_port = (sys << 3) + (pc->phy_id & 0x7) + 1;
    378     lane_mode = (reg_addr >> 16) & 7;
    379 
    380     rv = _tsc_reg_write(core->unit, pc, lane_mode, tsc_port, pmd, pll, (reg_addr & 0xffff), value, mask);
    381 
    382     return rv;
    383 }
    384 
    385 #define USE_PHY8806X_FW_STAT
    386 
    387 int
    388 _8806x_xmod_command(void *data)
    389 {
    390     xmod_buf_desc *bdp = (xmod_buf_desc *)data;
    391 
    392     soc_phymod_core_t *soc_core;
    393 
    394     if (bdp) {
    395         soc_core = PHYMOD_ACC_USER_ACC(bdp->pa);
    396 #ifdef USE_PHY8806X_FW_STAT
    397         if (bdp->mode_opcode == XMOD_CMD_MODE_ETH(XMOD_PHY_INTERFACE_CONFIG_GET)) {
    398             return(phy_8806x_fw_stat_read(soc_core->unit, soc_core->port,
    399                    FWSTAT_PHY_INTERFACE_CONFIG_GET_OFFSET, bdp->xmodrxbuff, bdp->xmodrxlen));
    400         } else if (bdp->mode_opcode == XMOD_CMD_MODE_ETH(XMOD_PHY_AUTONEG_GET)) {
    401             return(phy_8806x_fw_stat_read(soc_core->unit, soc_core->port,
    402                    FWSTAT_PHY_AUTONEG_GET_OFFSET, bdp->xmodrxbuff, bdp->xmodrxlen));
    403         } else 
    404 #endif
    405         if (bdp->mode_opcode == XMOD_CMD_MODE_ETH(XMOD_PHY_RX_PMD_LOCKED_GET)) {
    406             return (phy8806x_tsc_pmd_lock_status (bdp->pa, (uint8_t *)bdp->xmodrxbuff));
    407         } else {
    408             return (phy_8806x_xmod_command(soc_core->unit, soc_core->port, bdp->mode_opcode,
    409                     bdp->xmodtxbuff, bdp->xmodtxlen, bdp->xmodrxbuff, bdp->xmodrxlen));
    410         }
    411     }
    412 
    413     return SOC_E_UNAVAIL;
    414 }
    415 
    416 
    417 #define IS_DUAL_LANE_PORT(_pc) ((_pc)->phy_mode == PHYCTRL_DUAL_LANE_PORT)  
    418 #define IND_LANE_MODE(_pc) (((_pc)->phy_mode == PHYCTRL_DUAL_LANE_PORT) || ((_pc)->phy_mode == PHYCTRL_ONE_LANE_PORT))  
    419 
    420 uint8 * phy8806x_eth_ctr_get(phy_ctrl_t *pc)
    421 {
    422     return ((uint8 *) ETH_CTR(pc));
    423 }
    424 
    425 void phy8806x_led_tx_set(phy_ctrl_t *pc, uint8 val)
    426 {
    427     LED_TX(pc) = val;
    428     return;
    429 }
    430 
    431 void phy8806x_led_rx_set(phy_ctrl_t *pc, uint8 val)
    432 {
    433     LED_RX(pc) = val;
    434     return;
    435 }
    436 
    437 STATIC int
    438 phy8806x_port_config_init(phy8806x_speed_config_t* speed_config, phymod_port_config_t *port_config)
    439 {
    440     port_config->interface = speed_config->interface;
    441     port_config->sys_lane_count = speed_config->sys_lane_count;
    442     port_config->ln_lane_count = speed_config->ln_lane_count;
    443     port_config->an_mode= speed_config->an_mode;
    444     port_config->an_cl72 = speed_config->an_cl72;
    445     port_config->fs_cl72 = speed_config->fs_cl72;
    446     port_config->fs_cl72_sys = speed_config->fs_cl72_sys;
    447     port_config->an_fec = speed_config->an_fec;
    448     port_config->speed = speed_config->speed;
    449     port_config->port_is_higig = speed_config->port_is_higig;
    450     port_config->an_fec = speed_config->an_fec;
    451     port_config->port_mode = speed_config->port_mode;
    452     port_config->fiber_pref = speed_config->fiber_pref;
    453     port_config->fiber_pref_sys = speed_config->fiber_pref_sys;
    454     port_config->fs_fec = speed_config->fs_fec;
    455     port_config->fs_fec_sys = speed_config->fs_fec_sys;
    456     port_config->is_flex = speed_config->is_flex;
    457     port_config->quad_mode = speed_config->quad_mode;
    458 
    459     return SOC_E_NONE;
    460 }
    461 
    462 /*
    463  * Function:
    464  *      phy8806x_speed_to_interface_config_get
    465  * Purpose:     
    466  *      Convert speed to interface_config struct
    467  * Parameters:
    468  *      unit                - BCM unit number.
    469  *      port                - Port number.
    470  *      speed               - speed to convert
    471  *      interface_config    - output interface config struct
    472  * Returns:     
    473  *      SOC_E_NONE
    474  */
    475 STATIC int 
    476 phy8806x_speed_to_interface_config_get(phy8806x_speed_config_t* speed_config, phymod_phy_inf_config_t* interface_config, TXDRV_INXS_t* tx_index)
    477 {
    478     int port_is_higig;
    479     int port_num_lanes;
    480     int fiber_pref;
    481 
    482     port_num_lanes = speed_config->ln_lane_count;
    483     port_is_higig = speed_config->port_is_higig;
    484     fiber_pref = speed_config->fiber_pref;
    485 
    486     SOC_IF_ERROR_RETURN(phymod_phy_inf_config_t_init(interface_config));
    487 
    488     interface_config->interface_modes = 0;
    489     interface_config->data_rate       = speed_config->speed;
    490     interface_config->pll_divider_req = speed_config->pll_divider_req ;
    491     interface_config->device_aux_modes= NULL ;
    492 
    493     *tx_index = TXDRV_DFT_INX;
    494 
    495     if (port_is_higig) {
    496         PHYMOD_INTF_MODES_HIGIG_SET(interface_config);
    497     }
    498     switch (speed_config->speed) {
    499     case 1000:
    500         if (fiber_pref) {
    501             interface_config->interface_type = phymodInterface1000X;
    502             *tx_index = TXDRV_SFI_INX;
    503         } else {
    504             interface_config->interface_type = phymodInterfaceSGMII;
    505         }
    506         break;
    507     case 10000:
    508         if (speed_config->line_interface & PHY8806X_IF_SFI)
    509             interface_config->interface_type = phymodInterfaceSFI;
    510         else if (speed_config->line_interface & PHY8806X_IF_SR)
    511             interface_config->interface_type = phymodInterfaceSR;
    512         else if (speed_config->line_interface & PHY8806X_IF_CR)
    513             interface_config->interface_type = phymodInterfaceCR;
    514         else {
    515             if (speed_config->fs_cl72_sys)
    516                 interface_config->interface_type = phymodInterfaceCR;
    517             else
    518                 interface_config->interface_type = phymodInterfaceXFI;
    519         } 
    520         break;
    521     case 20000: 
    522         if (port_num_lanes == 1) {
    523             if (speed_config->fs_cl72_sys)
    524                 interface_config->interface_type = phymodInterfaceCR;
    525             else
    526                 interface_config->interface_type = phymodInterfaceXFI;
    527 
    528             *tx_index = TXDRV_XFI_INX;
    529         } else if(port_num_lanes == 2) {
    530             interface_config->interface_type = phymodInterfaceCR2;
    531         } 
    532         break ;
    533     case 25000:
    534         if (speed_config->fs_cl72_sys)
    535             interface_config->interface_type = phymodInterfaceCR;
    536         else
    537             interface_config->interface_type = phymodInterfaceXFI;
    538         *tx_index = TXDRV_XFI_INX;
    539         break ;
    540     case 40000:
    541         if(fiber_pref){
    542             PHYMOD_INTF_MODES_FIBER_SET(interface_config);
    543         }
    544         if (port_num_lanes == 4) {
    545             interface_config->interface_type = phymodInterfaceCR4;
    546             *tx_index = TXDRV_XLAUI_INX;
    547         } else {
    548             interface_config->interface_type = phymodInterfaceCR2;
    549             *tx_index = TXDRV_XLAUI_INX;
    550         }
    551         break;
    552     case 42000:
    553         if (port_num_lanes == 4) {
    554             interface_config->interface_type = phymodInterfaceCR4;
    555             *tx_index = TXDRV_XLAUI_INX;
    556         } else {
    557             interface_config->interface_type = phymodInterfaceCR2;
    558             *tx_index = TXDRV_XLAUI_INX;
    559         }
    560         break;
    561     case 50000:
    562         if(fiber_pref){
    563             PHYMOD_INTF_MODES_FIBER_SET(interface_config);
    564         }
    565         if (port_num_lanes == 4) {
    566             interface_config->interface_type = phymodInterfaceCR4;
    567             *tx_index = TXDRV_XLAUI_INX;
    568         } else {
    569             interface_config->interface_type = phymodInterfaceCR2;
    570             *tx_index = TXDRV_XLAUI_INX;
    571         }
    572         break;
    573     case 100000:
    574         interface_config->interface_type = phymodInterfaceCR4;
    575         *tx_index = TXDRV_XLAUI_INX;
    576         break;
    577     case 106000:
    578         interface_config->interface_type = phymodInterfaceCR4;
    579         *tx_index = TXDRV_XLAUI_INX;
    580         break;
    581     default:
    582         return SOC_E_PARAM;
    583     }
    584 
    585     switch (speed_config->port_refclk_int)
    586     {
    587     case 156:
    588         interface_config->ref_clock = phymodRefClk156Mhz;
    589         break;
    590     case 125:
    591         interface_config->ref_clock = phymodRefClk125Mhz;
    592         break;
    593     default:
    594         return SOC_E_PARAM;
    595     }
    596     return SOC_E_NONE;
    597 }
    598 
    599 STATIC int
    600 phy8806x_phymod_interfacetype_to_soc_type (phymod_interface_t interface_type, soc_port_if_t *pif)
    601 {
    602     switch (interface_type) {
    603     case phymodInterface1000X:
    604         *pif = SOC_PORT_IF_GMII;
    605         break;
    606     case phymodInterfaceSGMII:
    607         *pif = SOC_PORT_IF_SGMII;
    608         break;
    609     case phymodInterfaceXFI:
    610         *pif = SOC_PORT_IF_XFI;
    611         break;
    612     case phymodInterfaceSFI:
    613         *pif = SOC_PORT_IF_SFI;
    614         break;
    615     case phymodInterfaceXLAUI:
    616         *pif = SOC_PORT_IF_XLAUI;
    617         break;
    618     case phymodInterfaceKX:
    619         *pif = SOC_PORT_IF_KX;
    620         break;
    621     case phymodInterfaceRXAUI:
    622         *pif = SOC_PORT_IF_RXAUI;
    623         break;
    624     case phymodInterfaceXGMII:
    625         *pif = SOC_PORT_IF_XGMII;
    626         break;
    627     case phymodInterfaceKR2:
    628          *pif = SOC_PORT_IF_KR2;
    629         break;
    630     case phymodInterfaceCR2:
    631         *pif = SOC_PORT_IF_CR2;
    632         break;
    633     case phymodInterfaceSR2:
    634         *pif = SOC_PORT_IF_SR2;
    635         break;
    636     case phymodInterfaceSR4:
    637         *pif = SOC_PORT_IF_SR4;
    638         break;
    639     case phymodInterfaceCR4:
    640         *pif = SOC_PORT_IF_CR4;
    641         break;
    642     case phymodInterfaceKR4:
    643         *pif = SOC_PORT_IF_KR4;
    644         break;
    645     case phymodInterfaceCR:
    646         *pif = SOC_PORT_IF_CR;
    647         break;
    648     case phymodInterfaceKR:
    649         *pif = SOC_PORT_IF_KR;
    650         break;
    651     case phymodInterfaceSR:
    652         *pif = SOC_PORT_IF_SR;
    653         break;
    654     case phymodInterfaceCR10:
    655         *pif = SOC_PORT_IF_CAUI;
    656         break;
    657     case phymodInterfaceCAUI4:
    658         *pif = SOC_PORT_IF_CAUI;
    659         break;
    660     case phymodInterfaceBypass:
    661         *pif = SOC_PORT_IF_ILKN;
    662         break;
    663     default:
    664         *pif =  SOC_PORT_IF_XGMII;
    665         break;
    666     }
    667 
    668     return 0;
    669 }
    670 
    671 /* 
    672  * Given the BMP port number, the function returns
    673  *  the Quad mode (single, Tri0, Tri1, Dual, Single mode.
    674  */
    675 int get_quad_mode (int port)
    676 {
    677     int i = 0;
    678     int unit = 0;
    679     int port_idx = 0;
    680     int lane_cnt = 0;
    681     int quad_mode = 0;
    682 
    683     while ((i < 4) && (port_idx < 4)) {
    684         switch (port_idx) {
    685         case 0:
    686             lane_cnt = SOC_INFO(unit).port_num_lanes[port+port_idx];
    687             switch (lane_cnt) {
    688                 case 1:
    689                     quad_mode = _BFCMAPPER_PORT_MODE_QUAD;  /* QUAD */
    690                     break;
    691                 case 2:
    692                     quad_mode = _BFCMAPPER_PORT_MODE_DUAL;  /* DUAL */
    693                     break;
    694                 case 4:
    695                     quad_mode = _BFCMAPPER_PORT_MODE_SINGLE;  /* SINGLE */
    696                     return (quad_mode);
    697             }
    698             break;
    699         case 2:
    700             lane_cnt = SOC_INFO(unit).port_num_lanes[port+port_idx];
    701             switch (lane_cnt) {
    702                 case 1:
    703                     if (quad_mode == _BFCMAPPER_PORT_MODE_DUAL)
    704                         quad_mode = _BFCMAPPER_PORT_MODE_TRI_0023;  /* TRI0 */
    705                     break;
    706                 case 2:
    707                     if (quad_mode == _BFCMAPPER_PORT_MODE_QUAD)
    708                         quad_mode = _BFCMAPPER_PORT_MODE_TRI_0122;  /* TRI1 */
    709                     break;
    710 
    711             }
    712         }
    713 
    714         port_idx += lane_cnt;
    715         i++;
    716     }
    717 
    718     return quad_mode;
    719 }
    720 
    721 /* 
    722  * Given a port number, the function returns the BMP port numbrt.
    723  */
    724 int get_bmp_port (int port, phy_ctrl_t *pc)
    725 {
    726     int unit = 0;
    727     uint16 phy_addr=0;
    728 
    729     phy_addr = pc->phy_id;
    730 
    731     phy_addr -= phy_addr & 0x3;
    732     port= PHY_ADDR_TO_PORT(unit, phy_addr);
    733 
    734     return port;
    735 }
    736 
    737 int compute_quad_mode (int unit, int port)
    738 {
    739     phy_ctrl_t *pc;
    740     int bmp_port;
    741 
    742     pc = EXT_PHY_SW_STATE(unit, port); 
    743     bmp_port = get_bmp_port(port, pc);
    744     return get_quad_mode(bmp_port);
    745 }
    746 
    747 /*
    748  * Function:
    749  *      phy8806x_config_init
    750  * Purpose:     
    751  *      Determine phy configuration data for purposes of PHYMOD initialization.
    752  * 
    753  *      A side effect of this procedure is to save some per-logical port
    754  *      information in (phy8806x_cfg_t *) &pc->driver_data;
    755  *
    756  * Parameters:
    757  *      unit                  - BCM unit number.
    758  *      port                  - Port number.
    759  *      logical_lane_offset   - starting logical lane number
    760  * Returns:     
    761  *      SOC_E_NONE
    762  */
    763 STATIC int
    764 phy8806x_config_init(int unit, soc_port_t port, int logical_lane_offset,
    765                  phymod_core_init_config_t *core_init_config, 
    766                  phymod_phy_init_config_t  *pm_phy_init_config)
    767 {
    768     phy_ctrl_t *pc;
    769     phy8806x_speed_config_t *speed_config;
    770     phy8806x_config_t *pCfg;
    771     phymod_firmware_load_method_t fw_ld_method;
    772     int port_refclk_int;
    773     int port_num_lanes;
    774     int core_num;
    775     int phy_num_lanes;
    776     int port_is_higig;
    777     int phy_passthru; 
    778     int lane_map_rx, lane_map_tx, lane_map_tx_l=0;
    779     int i;
    780     int fiber_pref = 1;
    781     TXDRV_INXS_t tx_index = TXDRV_DFT_INX;
    782     uint32  temp32;
    783     soc_port_if_t soc_if;
    784     phy_ctrl_t *int_pc;
    785 
    786     pc = EXT_PHY_SW_STATE(unit, port);
    787     if (pc == NULL) {
    788         return SOC_E_INTERNAL;
    789     }
    790 
    791     int_pc = INT_PHY_SW_STATE(unit, port);
    792     if (int_pc == NULL) {
    793         return SOC_E_INTERNAL;
    794     }
    795 
    796     pCfg = (phy8806x_config_t *) pc->driver_data;
    797 
    798     /* extract data from SOC_INFO */
    799     /*port_refclk_int = SOC_INFO(unit).port_refclk_int[port];*/
    800     port_refclk_int = 156;  
    801     port_num_lanes = SOC_INFO(unit).port_num_lanes[port];
    802     port_is_higig = PBMP_MEMBER(PBMP_HG_ALL(unit), port);
    803 
    804     /* figure out how many lanes are in this phy */
    805     core_num = (logical_lane_offset / 4);
    806     phy_num_lanes = (port_num_lanes - logical_lane_offset);
    807     if (phy_num_lanes > MAX_NUM_LANES) {
    808        phy_num_lanes = MAX_NUM_LANES;
    809     }
    810     
    811     /* 
    812         CORE configuration
    813     */
    814     phymod_core_init_config_t_init(core_init_config);
    815     /* Set the core_mode to Ethernet. Need to add a config variable to get the right core Mode */
    816 #if defined(INCLUDE_FCMAP)
    817     if (pc->fcmap_enable) {
    818         /* Set Core Mode to FIBER_CHANNEL_MODE */
    819         core_init_config->core_mode = 1;
    820     } else
    821 #endif
    822     {
    823         /* Set Core Mode to ETHERNET_MODE */
    824         core_init_config->core_mode = 0;
    825     }
    826     fw_ld_method = phymodFirmwareLoadMethodNone;
    827 
    828     core_init_config->firmware_load_method  = soc_property_port_get(unit, port, 
    829                                               spn_LOAD_FIRMWARE, fw_ld_method);
    830     core_init_config->firmware_load_method &= 0xff; /* clear checksum bits */
    831     core_init_config->lane_map.num_of_lanes = port_num_lanes;
    832     
    833     /* Both internal data structure is logic lane base */
    834     lane_map_rx = soc_property_port_suffix_num_get(unit, port, core_num,
    835                                         spn_PHY_RX_LANE_MAP, "core", 0x3210);
    836     for (i=0; i<NUM_LANES; i++) {
    837         core_init_config->lane_map.lane_map_rx[i] = (lane_map_rx >> (i * 4 /* 4 bit per lane */)) & 0xf;
    838     }
    839  
    840     lane_map_tx = soc_property_port_suffix_num_get(unit, port, core_num,
    841                                         spn_PHY_TX_LANE_MAP, "core", 0x3210);
    842     for (i=0; i<NUM_LANES; i++) {
    843         lane_map_tx_l |= i << 4*((lane_map_tx >> (i*4)) & 0xf) ;
    844     }
    845     for (i=0; i<NUM_LANES; i++) {
    846         core_init_config->lane_map.lane_map_tx[i] = (lane_map_tx_l >> (i * 4 /*4 bit per lane*/)) & 0xf;
    847     }
    848 
    849     /* next get the tx/rx polairty info */
    850     core_init_config->polarity_map.rx_polarity = soc_property_port_get(unit, port, spn_PHY_RX_POLARITY_FLIP, 0);
    851     core_init_config->polarity_map.tx_polarity = soc_property_port_get(unit, port, spn_PHY_TX_POLARITY_FLIP, 0);
    852 
    853     speed_config = &(pCfg->speed_config);
    854     speed_config->port_refclk_int  = port_refclk_int;
    855     speed_config->speed  = soc_property_port_get(unit, port, spn_PORT_INIT_SPEED, pc->speed_max);
    856     speed_config->ln_lane_count    = phy_num_lanes;
    857     speed_config->port_is_higig    = port_is_higig;
    858     speed_config->line_interface   = soc_property_port_get(unit, port, spn_SERDES_IF_TYPE, SOC_PORT_IF_CR);
    859     speed_config->fiber_pref = soc_property_port_get(unit, port, spn_PHY_FIBER_PREF, 0);
    860     speed_config->fiber_pref_sys = soc_property_port_get(unit, port, spn_SERDES_FIBER_PREF, 0);
    861     speed_config->port_mode = soc_property_port_get(unit, port, spn_PHY_OPERATIONAL_MODE, 0);
    862     speed_config->an_fec = soc_property_port_get(unit, port, spn_PHY_EXT_AN_FEC, 0);
    863     speed_config->fs_cl72 = soc_property_port_get(unit, port, spn_PHY_INIT_CL72, 0);
    864     speed_config->fs_cl72_sys = soc_property_port_get(unit, port, spn_PORT_INIT_CL72, 0);
    865     speed_config->an_cl72 = soc_property_port_get(unit, port, spn_PHY_AN_C72, 1);
    866     speed_config->fs_fec = soc_property_port_get(unit, port, spn_PHY_FEC_ENABLE, 0);
    867     speed_config->fs_fec_sys = soc_property_port_get(unit, port, spn_SERDES_FEC_ENABLE, 0);
    868     speed_config->an_mode  = soc_property_port_get(unit, port, spn_PHY_AN_C73, 0);
    869     speed_config->repeater_an_phase  = REPEATER_AN_PHASE_NONE;
    870 
    871 #ifdef  BCM_TRIDENT2_SUPPORT
    872     if ((FLAGS(pc) & PHY8806X_FLEX) && SOC_IS_TRIDENT2(unit)) {
    873         if ((speed_config->ln_lane_count > 1) && ((speed_config->speed == 10000) || (speed_config->speed == 25000))) {
    874             speed_config->speed = speed_config->ln_lane_count * speed_config->speed;
    875             PHYCTRL_SPEED_SET(int_pc, int_pc->unit, int_pc->port, speed_config->speed);
    876         }
    877 
    878         if ((speed_config->ln_lane_count == 1) && ((speed_config->speed == 40000) || (speed_config->speed == 100000))) {
    879             if (speed_config->ln_lane_count == 1) {
    880                 switch (speed_config->speed) {
    881                 case 40000:
    882                 case 42000:
    883                 case 100000:
    884                 case 106000:
    885                     speed_config->speed = speed_config->speed/4;
    886                     break;
    887                 case 20000:
    888                 case 50000:
    889                     speed_config->speed = speed_config->speed/2;
    890                     break;
    891                 default:
    892                     break;
    893                 }
    894                 PHYCTRL_SPEED_SET(int_pc, int_pc->unit, int_pc->port, speed_config->speed);
    895             }
    896         }
    897     }
    898 #endif
    899 
    900     SOC_IF_ERROR_RETURN(soc_mac_probe(unit, port, &(speed_config->macd)));
    901 
    902     if (speed_config->port_mode == ETH_REPEATER) {
    903         PHY_FLAGS_SET(unit, port, PHY_FLAGS_REPEATER);
    904         if (FLAGS(pc) & PHY8806X_BMP0) {
    905             SOC_IF_ERROR_RETURN
    906                 (READ_TOP_FC_MODE_CONTROL_REG(unit, pc, &temp32));
    907                 temp32 |= 1 << 2;
    908             SOC_IF_ERROR_RETURN
    909                 (WRITE_TOP_FC_MODE_CONTROL_REG(unit, pc, temp32));
    910         }
    911 
    912         if (FLAGS(pc) & PHY8806X_BMP1) {
    913             SOC_IF_ERROR_RETURN
    914                 (READ_TOP_FC_MODE_CONTROL_REG(unit, pc, &temp32));
    915                 temp32 |= 1 << 3;
    916             SOC_IF_ERROR_RETURN
    917                 (WRITE_TOP_FC_MODE_CONTROL_REG(unit, pc, temp32));
    918         }
    919     }
    920 
    921 
    922     if (speed_config->port_mode == ETH_GEARBOX) {
    923         speed_config->sys_lane_count  = phy_num_lanes;
    924         speed_config->ln_lane_count   = GEARBOX_LINE_LANE_CNT;
    925     } else {
    926         speed_config->sys_lane_count  = speed_config->ln_lane_count;
    927     }
    928 
    929     SOC_IF_ERROR_RETURN
    930         (phy8806x_speed_to_interface_config_get(speed_config, &(core_init_config->interface), &tx_index));
    931 
    932     phy8806x_phymod_interfacetype_to_soc_type(core_init_config->interface.interface_type, &soc_if);
    933 
    934     /* coverity[mixed_enums]: ignore */
    935     speed_config->interface = soc_if;
    936     /* coverity[mixed_enums]: ignore */
    937     core_init_config->interface.interface_type = soc_if;
    938     /* 
    939         PHY configuration
    940     */
    941 
    942     phymod_phy_init_config_t_init(pm_phy_init_config);
    943 
    944     
    945     pm_phy_init_config->cl72_en = soc_property_port_get(unit, port, spn_PHY_AN_C72, TRUE);
    946     pm_phy_init_config->an_en = TRUE;
    947 
    948     /* check the higig port mode, then set the default cl73 mode */
    949     if (port_is_higig) {
    950         pCfg->cl73an = FALSE;
    951     } else {
    952         pCfg->cl73an = PHY8806X_CL73_W_BAM;
    953     }
    954 
    955     /* by default disable cl37 */
    956     pCfg->an_cl72 = TRUE;
    957     pCfg->forced_init_cl72 = FALSE;
    958     pCfg->an_fec = FALSE; 
    959 
    960     pCfg->cl73an  = soc_property_port_get(unit, port,
    961                                           spn_PHY_AN_C73, pCfg->cl73an); 
    962     pCfg->an_cl72 = soc_property_port_get(unit, port,
    963                                         spn_PHY_AN_C72, pCfg->an_cl72);
    964     pCfg->an_fec = soc_property_port_get(unit, port,
    965                                         spn_PHY_EXT_AN_FEC, pCfg->an_fec);
    966 
    967     pCfg->forced_init_cl72 = soc_property_port_get(unit, port,
    968                                         spn_PHY_INIT_CL72, pCfg->forced_init_cl72);
    969 
    970     
    971     /* 
    972         phy_ctrl_t configuration (LOGICAL PORT BASED)
    973         Only do this once, for the first core of the logical port
    974     */
    975     if (core_num == 0) {
    976         
    977 
    978         /* phy_mode, PHYCTRL_MDIO_ADDR_SHARE, PHY_FLAGS_INDEPENDENT_LANE */
    979         if (port_num_lanes == 4) {
    980             pc->phy_mode = PHYCTRL_QUAD_LANE_PORT;
    981             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_INDEPENDENT_LANE);
    982         } else if (port_num_lanes == 2) {
    983             pc->phy_mode = PHYCTRL_DUAL_LANE_PORT;
    984             pc->flags |= PHYCTRL_MDIO_ADDR_SHARE;
    985             PHY_FLAGS_SET(unit, port, PHY_FLAGS_INDEPENDENT_LANE);
    986         } else if (port_num_lanes == 1) {
    987             pc->phy_mode = PHYCTRL_ONE_LANE_PORT;
    988             pc->flags |= PHYCTRL_MDIO_ADDR_SHARE;
    989             PHY_FLAGS_SET(unit, port, PHY_FLAGS_INDEPENDENT_LANE);
    990         }
    991 
    992         /* PHY_FLAGS_PASSTHRU */
    993         phy_passthru = 0;
    994         if (PHY_EXTERNAL_MODE(unit, port)) {
    995             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_PASSTHRU);
    996             phy_passthru = soc_property_port_get(unit, port,
    997                                                  spn_PHY_PCS_REPEATER, 0);
    998             if (phy_passthru) {
    999                 PHY_FLAGS_SET(unit, port, PHY_FLAGS_PASSTHRU);
   1000             }
   1001         }
   1002 
   1003         /* PHY_FLAGS_FIBER */
   1004         PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER);
   1005         if (fiber_pref) {
   1006             PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER);
   1007         }
   1008     }
   1009 
   1010     return SOC_E_NONE;
   1011 }
   1012 
   1013 /*
   1014  * Function:
   1015  *      phy_8806x_init
   1016  *  
   1017  *      An SDK "phy" is a logical port, which can consist of from 1-10 lanes,
   1018  *          (A phy with more than 4 lanes requires more than one core).
   1019  *      Per-logical port information is saved in (phy8806x_cfg_t *) &pc->driver_data.
   1020  *      An SDK phy is implemented as one or more PHYMOD "phy"s.
   1021  *  
   1022  *      A PHYMOD "phy" resides completely within a single core, which can be
   1023  *      from 1 to 4 lanes.
   1024  *      Per-phymod phy information is kept in (soc_phymod_ctrl_t) *pc->phymod_ctrl
   1025  *      A phymod phy points to its core.  Up to 4 phymod phys can be on a single core
   1026  *  
   1027  * Purpose:     
   1028  *      Initialize a phy8806x phy
   1029  * Parameters:
   1030  *      unit - BCM unit number.
   1031  *      port - Port number. 
   1032  * Returns:     
   1033  *      SOC_E_NONE
   1034  */
   1035 STATIC int
   1036 phy_8806x_init(int unit, soc_port_t port)
   1037 {
   1038     phy_ctrl_t *pc; 
   1039     soc_phymod_ctrl_t *pmc = NULL;
   1040     soc_phymod_phy_t *phy = NULL;
   1041     soc_phymod_core_t *core = NULL;
   1042     phy8806x_config_t *pCfg = NULL;
   1043     phy8806x_speed_config_t *speed_config = NULL;
   1044 /*     soc_phy_info_t *pi = NULL; */
   1045     phymod_phy_inf_config_t interface_config;
   1046     phymod_core_status_t core_status;
   1047     phymod_core_info_t core_info;
   1048     int idx, rv = SOC_E_NONE;
   1049     int logical_lane_offset;
   1050     soc_port_ability_t ability;
   1051     TXDRV_INXS_t tx_index = TXDRV_DFT_INX;
   1052     phymod_port_config_t port_config;
   1053     uint32         temp32;
   1054     uint16         temp16;
   1055     uint8          *fw = NULL;
   1056     int            fw_len = 0;
   1057     int            bm, cm;
   1058     int            bmp_port = 0; 
   1059     int            fwdlm;
   1060     uint16         status_l = 0, status_s = 0;
   1061     soc_port_if_t  soc_if;
   1062     int            port_is_higig, port_was_higig;
   1063 
   1064     pc = EXT_PHY_SW_STATE(unit, port);
   1065     if (pc == NULL) {
   1066         return SOC_E_INTERNAL;
   1067     }
   1068     LOG_INFO(BSL_LS_SOC_PHY, (BSL_META_U(unit,
   1069         "u=%d p=%d PHYCTRL_INIT_STATE = %u speed_max = %d - %s\n"),
   1070          unit, pc->port, PHYCTRL_INIT_STATE(pc), pc->speed_max,
   1071          (FLAGS(pc) & PHY8806X_FLEX) ? "FLEX" : "REGULAR" ));
   1072 
   1073     if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS1) ||
   1074         (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) {
   1075 
   1076         pc->driver_data = (void*)(pc+1);
   1077         pmc = &pc->phymod_ctrl;
   1078         pCfg = (phy8806x_config_t *) pc->driver_data;
   1079     
   1080         port_is_higig = PBMP_MEMBER(PBMP_HG_ALL(unit), port);
   1081         /* Extract previous higig status before we clear the structure.
   1082            This is possible because the SDK reuses the previous phyctrl.
   1083          */
   1084         port_was_higig = pCfg->speed_config.port_is_higig;
   1085 
   1086         sal_memset(pCfg, 0, sizeof(*pCfg));
   1087         speed_config = &(pCfg->speed_config);
   1088 
   1089         sal_memset(&ability, 0, sizeof(ability));
   1090 
   1091         if (xmod_mutex[unit] == NULL) {
   1092             xmod_mutex[unit] = sal_mutex_create("xmod_mutex");
   1093         }
   1094         
   1095         if (xmod_mutex[unit] == NULL) {
   1096             return SOC_E_MEMORY;
   1097         }
   1098 
   1099         SOC_IF_ERROR_RETURN
   1100             (READ_TOP_DEV_REV_ID_REG(unit, pc, &TOP_DEV_REV_ID(pc)));
   1101 
   1102         LED_TX(pc) = 0;
   1103         LED_RX(pc) = 0;
   1104         LED_SPEED(pc) = 0;
   1105         FLAGS(pc) = 0;
   1106         PHY_FLAGS_SET(unit, port, PHY_FLAGS_C45);
   1107 
   1108         /* Use the following config variable for now until a new one is approved. */
   1109         if (soc_property_port_get(unit, port,spn_PHY_FORCE_FIRMWARE_LOAD, FALSE)) {
   1110             FLAGS(pc) |= PHY8806X_PM;
   1111         }
   1112 
   1113 #ifdef PORTMOD_SUPPORT
   1114         if (soc_feature(unit, soc_feature_portmod)) {
   1115             FLAGS(pc) |= PHY8806X_PORTMOD;
   1116         }
   1117 #endif
   1118 
   1119         if ((SOC_CONTROL(unit)->soc_flags & SOC_F_ALL_MODULES_INITED) && (!port_is_higig != !port_was_higig)) {
   1120             FLAGS(pc) |= PHY8806X_ENCAP_CHANGE;
   1121         }
   1122 
   1123         if (soc_phy_boot_master_get(unit, port, &bm, &cm) == SOC_E_NONE) {
   1124             if (bm) {
   1125                 if ((pc->phy_id & 0x4) == 0x0) {
   1126                     FLAGS(pc) |= PHY8806X_BMP0;
   1127                 } else {
   1128                     FLAGS(pc) |= PHY8806X_BMP1;
   1129                 }
   1130                 if (cm) {
   1131                     FLAGS(pc) |= PHY8806X_CHM;
   1132                 }
   1133             }
   1134         } else {
   1135             if ((pc->phy_id & 0x7) == 0x0) {
   1136                 FLAGS(pc) |= PHY8806X_BMP0;
   1137                 FLAGS(pc) |= PHY8806X_CHM;
   1138             } else if ((pc->phy_id & 0x7) == 0x4) {
   1139                 FLAGS(pc) |= PHY8806X_BMP1;
   1140             }
   1141         }
   1142 
   1143         if ((fwdlm = soc_property_port_get(unit, port,spn_MDIO_FIRMWARE_DOWNLOAD_MASTER, 0)) == -1) {
   1144             if (FLAGS(pc) & PHY8806X_CHM) {
   1145                 FLAGS(pc) |= PHY8806X_AC;
   1146             }
   1147         } else if (fwdlm == -2) {
   1148             if (FLAGS(pc) & PHY8806X_CHM) {
   1149                 FLAGS(pc) |= PHY8806X_FWDLM;
   1150             }
   1151         } else if (fwdlm == pc->port) {
   1152             FLAGS(pc) |= PHY8806X_FWDLM;
   1153         }
   1154 
   1155         if (!(SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit))) {
   1156 
   1157             temp32 = 0;
   1158 
   1159             /* Initialize the uart_ptr via AXI memory of the mHost (pc->phy_id & 0x3) before f/w starts to avoid a race condition. */
   1160             SOC_IF_ERROR_RETURN
   1161                 (_phy_8806x_axi_write(unit, pc, 0x27fff8 + (pc->phy_id & 0x3) * 0x100000, &temp32, 1));
   1162 
   1163             /* Initialize the print_ptr via AXI memory of the mHost (pc->phy_id & 0x3) before f/w starts to avoid a race condition. */
   1164             SOC_IF_ERROR_RETURN
   1165                 (_phy_8806x_axi_write(unit, pc, 0x27fffc + (pc->phy_id & 0x3) * 0x100000, &temp32, 1));
   1166 
   1167 
   1168             temp32 = soc_property_port_get(unit, port, spn_PHY_DIAG_BMP, 1);
   1169             if (temp32 & 0x4) {
   1170                 FLAGS(pc) |= PHY8806X_FW_RESTART;
   1171             }
   1172             temp32 = HOST2LE32(temp32 & 0xffff03);
   1173 
   1174             /* Initialize the mode via AXI memory of the mHost (pc->phy_id & 0x3) */
   1175             SOC_IF_ERROR_RETURN
   1176                 (_phy_8806x_axi_write(unit, pc, 0x27fff4 + (pc->phy_id & 0x3) * 0x100000, &temp32, 1));
   1177 
   1178         }
   1179 
   1180 #if defined(INCLUDE_FCMAP)
   1181         pc->fcmap_enable = soc_property_port_get(unit, port, spn_FCMAP_ENABLE, 0);
   1182 
   1183         if  (pc->fcmap_enable && !(PHY_IS_BCM88060(pc) || PHY_IS_BCM88061(pc))) {
   1184             LOG_ERROR(BSL_LS_SOC_PHY,
   1185                      (BSL_META_U(unit,
   1186                                  "u=%d p=%d FC not supported on the device !.\n"), unit, port));
   1187             pc->fcmap_enable = 0;
   1188         }
   1189 
   1190         pc->fcmap_dev_port = 0;
   1191         pc->fcmap_uc_dev_addr = SOC_FCMAPPHY_MDIO_ADDR(unit, pc->phy_id, 1);
   1192         pc->fcmap_dev_addr = SOC_FCMAPPHY_MDIO_ADDR(unit, pc->phy_id, 1);
   1193 
   1194         LOG_ERROR(BSL_LS_SOC_PHY,
   1195               (BSL_META_U(unit,
   1196                           "FCMAP ENABLE %d, port %d, dev_addr 0x%x\n"),
   1197                            pc->fcmap_enable, port, pc->fcmap_dev_addr ));
   1198 
   1199 #endif
   1200 
   1201         if (SOC_CONTROL(unit)->soc_flags & SOC_F_ALL_MODULES_INITED) {
   1202             SOC_IF_ERROR_RETURN
   1203                 (_phy_8806x_axi_read(unit, pc, 0x00100008, &temp32, 1));
   1204             temp32 = LE2HOST32(temp32);
   1205             if (temp32 == 0x2032544d) { /* 'MT2 ' converted to uint32 LE = ((' '<< 24) + ('2'<< 16) + ('T'<< 8) + ('M'<< 0)) */
   1206 
   1207 #if defined(INCLUDE_FCMAP)
   1208                 SOC_IF_ERROR_RETURN
   1209                     (READ_TOP_FC_MODE_CONTROL_REG(unit, pc, &temp32));
   1210 
   1211                 /* Mask out the other quad's bit. */
   1212                 temp32 = (pc->phy_id & 0x4) ? (temp32 & (1 << 1)) : (temp32 & (1 << 0)); 
   1213 
   1214                 if ((pc->fcmap_enable && (!temp32)) || ((!pc->fcmap_enable) && temp32)) {
   1215                     FLAGS(pc) |= PHY8806X_MODE_CHANGE;
   1216                 } else 
   1217 #endif
   1218                 {
   1219                     if (!(FLAGS(pc) & PHY8806X_ENCAP_CHANGE)) {
   1220                         FLAGS(pc) |= PHY8806X_FLEX;
   1221                     }
   1222                 }
   1223             } else {
   1224                 FLAGS(pc) &= ~PHY8806X_FW_RESTART;
   1225             }
   1226         }
   1227 
   1228         /* To skip restart */
   1229         if (FLAGS(pc) & PHY8806X_ENCAP_CHANGE) {
   1230              goto PASS5_BOOT;
   1231         }
   1232 
   1233         if ( ((FLAGS(pc) & (PHY8806X_FLEX | PHY8806X_ENCAP_CHANGE))) && 
   1234              (!(SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit))) ){
   1235             /* determine the number of lanes */
   1236             int num_lanes = SOC_INFO(unit).port_num_lanes[port];
   1237             int starting_lane_index = pc->phy_id & 0x7;
   1238             /* TOP_SOFT_RESET Register Bits 6-9 is for RTS0 and bits 10-13 is for RTS1.
   1239                One bit per lane. Create a RMW mask for this register from the phy id and
   1240                number of lanes, as per the following formula
   1241                ((2**num_lanes) - 1) << (starting_lane_index + 6) (ANDed with Oxf = 4 bits) 
   1242             */
   1243             uint32 single_mask = (((1U << num_lanes) - 1) & 0xf) << (starting_lane_index + 6);
   1244             /* TOP_RTS_MISC_CTRL Register Bits 0-7 is for RTS0 and bits 8-15 is for RTS1.
   1245                Two bits per lane. Create a RMW mask for this register from the phy id and
   1246                number of lanes, as per the following formula
   1247                ((2**(2*num_lanes)) - 1) << (2*starting_lane_index) (ANDed with 0xff = 8 bits)
   1248             */
   1249             uint32 dual_mask = (((1U << (num_lanes << 1)) - 1) & 0xff) << (starting_lane_index << 1); 
   1250 
   1251             /* LOG_CLI((BSL_META_U(unit,
   1252                         "u=%d p=%d single_mask = 0x%08x dual_mask = 0x%08x\n"),
   1253                         unit, pc->port, single_mask, dual_mask ));
   1254             */
   1255 
   1256             /* Place mHosts of the lane in reset */
   1257             SOC_IF_ERROR_RETURN
   1258                 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32));
   1259                 temp32 |= single_mask;
   1260             SOC_IF_ERROR_RETURN
   1261                 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   1262 
   1263             /* Halt the mHosts of the lane */
   1264             SOC_IF_ERROR_RETURN
   1265                 (READ_TOP_RTS_MISC_CTRL_REG(unit, pc, &temp32));
   1266                 temp32 &= ~dual_mask;
   1267             SOC_IF_ERROR_RETURN
   1268                 (WRITE_TOP_RTS_MISC_CTRL_REG(unit, pc, temp32));
   1269 
   1270             /* Bring mHosts of the lane out of reset */
   1271             SOC_IF_ERROR_RETURN
   1272                 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32));
   1273                 temp32 &= ~single_mask;
   1274             SOC_IF_ERROR_RETURN
   1275                 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   1276 
   1277 /*            if (FLAGS(pc) & PHY8806X_ENCAP_CHANGE) {
   1278                 goto PASS4_BOOT;
   1279             }
   1280 */
   1281             /* jump to 4-th pass */
   1282             PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS4);
   1283             return SOC_E_NONE;
   1284         }
   1285 
   1286 
   1287 #ifdef BCM_WARM_BOOT_SUPPORT
   1288         if (SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit)){
   1289             /* jump to 5-th pass */
   1290             PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS5);
   1291             return SOC_E_NONE;
   1292         }
   1293 #endif
   1294 
   1295         FIRMWARE(pc) = bcm_8806x_firmware;
   1296         FIRMWARE_LEN(pc) = bcm_8806x_firmware_size;
   1297         pc->flags |= PHYCTRL_MDIO_BCST;
   1298         pc->dev_name = dev_name_8806x;
   1299 
   1300         /* Now check whether a newer version of firmware is available for this model */
   1301         rv = soc_phy_fw_get(pc->dev_name, &fw, &fw_len);
   1302         if (SOC_SUCCESS(rv)) {
   1303             FIRMWARE(pc) = fw;
   1304             FIRMWARE_LEN(pc) = fw_len;
   1305         }
   1306 
   1307         if (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS1) {
   1308             /* initiate second pass of init if needed */
   1309             PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS2);
   1310             return SOC_E_NONE;
   1311         }
   1312 
   1313     }
   1314 
   1315     /* Firmware download happens between PASS1 and PASS2 */
   1316 
   1317 
   1318     if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS2) ||
   1319         (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) {
   1320 
   1321         /* The BMPs should be ready to accept commands at this point
   1322            and the others are in halt. */
   1323         /* Issue xmod_core_init(). (BMPs) */
   1324         if ( FLAGS(pc) & (PHY8806X_BMP0 | PHY8806X_BMP1) ) {
   1325             do {
   1326 
   1327                 rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) + 1, 1, 0, 0xd03d, &status_l);
   1328                 if (SOC_FAILURE(rv)) {
   1329                     break;
   1330                 }
   1331                 rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) + 9, 1, 0, 0xd03d, &status_s);
   1332                 if (SOC_FAILURE(rv)) {
   1333                     break;
   1334                 }
   1335                 if ((status_l== 0x80) &&  (status_s == 0x80)) {
   1336                     break;
   1337                 }
   1338             } while (!soc_timeout_check(&TO(pc)));
   1339 
   1340            if ( status_l != 0x80 ) {
   1341                 LOG_CLI((BSL_META_U(unit,
   1342                         "PHY8806X PMD (line) firmware failed to compute CRC: u=%d p=%d  status=%04x"
   1343                         " !.\n"), unit, pc->port, status_l));
   1344            } else {
   1345                rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) + 1, 1, 0, 0xd03e, &temp16);
   1346                if (SOC_FAILURE(rv) || (temp16 != PMD_CRC(pc))) {
   1347                    LOG_CLI((BSL_META_U(unit,
   1348                            "PHY8806X PMD (line) firmware CRC failure: u=%d p=%d  expected=0x%04x computed=0x%04x"
   1349                            " !.\n"), unit, pc->port, PMD_CRC(pc), temp16));
   1350                } else {
   1351                    LOG_CLI((BSL_META_U(unit,
   1352                            "PHY8806X PMD (line) firmware CRC Ok: u=%d p=%d computed=0x%04x"
   1353                            " !.\n"), unit, pc->port, temp16));
   1354                }
   1355            }
   1356 
   1357            if ( status_s != 0x80 ) {
   1358                 LOG_CLI((BSL_META_U(unit,
   1359                         "PHY8806X PMD (sys)  firmware failed to compute CRC: u=%d p=%d  status=%04x"
   1360                         " !.\n"), unit, pc->port, status_s));
   1361            } else {
   1362                rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) + 9, 1, 0, 0xd03e, &temp16);
   1363                if (SOC_FAILURE(rv) || (temp16 != PMD_CRC(pc))) {
   1364                    LOG_CLI((BSL_META_U(unit,
   1365                            "PHY8806X PMD (sys)  firmware CRC failure: u=%d p=%d  expected=0x%04x computed=0x%04x"
   1366                            " !.\n"), unit, pc->port, PMD_CRC(pc), temp16));
   1367                } else {
   1368                    LOG_CLI((BSL_META_U(unit,
   1369                            "PHY8806X PMD (sys)  firmware CRC Ok: u=%d p=%d computed=0x%04x"
   1370                            " !.\n"), unit, pc->port, temp16));
   1371                }
   1372            }
   1373         }
   1374 
   1375         if ( FLAGS(pc) & PHY8806X_PM ) {
   1376             return SOC_E_NONE;
   1377         }
   1378 
   1379         if (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS2) {
   1380             /* initiate third pass of init if needed */
   1381             PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS3);
   1382             return SOC_E_NONE;
   1383         }
   1384     }
   1385 
   1386     if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS3) ||
   1387         (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) {
   1388 
   1389         if ( FLAGS(pc) & (PHY8806X_BMP0 | PHY8806X_BMP1) ) {
   1390             /* Get results of xmod_core_init(). (BMPs) */
   1391 
   1392         }
   1393 
   1394         if (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS3) {
   1395             /* initiate fourth pass of init if needed */
   1396             PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS4);
   1397             return SOC_E_NONE;
   1398         }
   1399     }
   1400 
   1401     if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS4) ||
   1402         (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) {
   1403 
   1404         /* Enable FC Mode for Quad 0 */
   1405         if ((FLAGS(pc) & PHY8806X_BMP0)) {
   1406             SOC_IF_ERROR_RETURN
   1407                 (READ_TOP_FC_MODE_CONTROL_REG(unit, pc, &temp32));
   1408 #if defined(INCLUDE_FCMAP)
   1409             if (pc->fcmap_enable) {
   1410                 temp32 |= 1 << 0;
   1411             } else {
   1412                 temp32 &= ~(1 << 0);
   1413             }
   1414 #else
   1415             temp32 &= ~(1 << 0);
   1416 #endif
   1417             SOC_IF_ERROR_RETURN
   1418                 (WRITE_TOP_FC_MODE_CONTROL_REG(unit, pc, temp32));
   1419         }
   1420 
   1421         /* Enable FC Mode for Quad 1 */
   1422         if ((FLAGS(pc) & PHY8806X_BMP1)) {
   1423             SOC_IF_ERROR_RETURN
   1424                 (READ_TOP_FC_MODE_CONTROL_REG(unit, pc, &temp32));
   1425 #if defined(INCLUDE_FCMAP)
   1426             if (pc->fcmap_enable) {
   1427                 temp32 |= 1 << 1;
   1428             } else {
   1429                 temp32 &= ~(1 << 1);
   1430             }
   1431 #else
   1432             temp32 &= ~(1 << 1);
   1433 #endif
   1434             SOC_IF_ERROR_RETURN
   1435                 (WRITE_TOP_FC_MODE_CONTROL_REG(unit, pc, temp32));
   1436         }
   1437 /*
   1438 PASS4_BOOT:
   1439 */
   1440         /* Start all non BMPs */
   1441         if (( FLAGS(pc) & (PHY8806X_FLEX | PHY8806X_ENCAP_CHANGE)) ||
   1442             ( !( FLAGS(pc) & (PHY8806X_BMP0 | PHY8806X_BMP1)) )) {
   1443 
   1444             SOC_IF_ERROR_RETURN
   1445                 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32));
   1446                 temp32 |= 1 << ((pc->phy_id & 0x7) + 6);
   1447             SOC_IF_ERROR_RETURN
   1448                 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   1449 
   1450             SOC_IF_ERROR_RETURN
   1451                 (READ_TOP_RTS_MISC_CTRL_REG(unit, pc, &temp32));
   1452                 temp32 &= ~(0x3 << ((pc->phy_id & 0x7) << 1));
   1453                 temp32 |= (0x2 << ((pc->phy_id & 0x7) << 1));
   1454             SOC_IF_ERROR_RETURN
   1455                 (WRITE_TOP_RTS_MISC_CTRL_REG(unit, pc, temp32));
   1456 
   1457             SOC_IF_ERROR_RETURN
   1458                 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32));
   1459                 temp32 &= ~(1 << ((pc->phy_id & 0x7) + 6));
   1460             SOC_IF_ERROR_RETURN
   1461                 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   1462 
   1463          }
   1464 
   1465         if (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS4) {
   1466             /* initiate fourth pass of init if needed */
   1467             PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS5);
   1468             return SOC_E_NONE;
   1469         }
   1470     }
   1471 
   1472     if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS5) ||
   1473         (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) {
   1474 
   1475 /* don't restart */
   1476 PASS5_BOOT:
   1477         pc = EXT_PHY_SW_STATE(unit, port);
   1478         pc->driver_data = (void*)(pc+1);
   1479         pmc = &pc->phymod_ctrl;
   1480         pCfg = (phy8806x_config_t *) pc->driver_data;
   1481         speed_config = &(pCfg->speed_config);
   1482 
   1483         /* Loop through all phymod phys that support this SDK phy */
   1484         logical_lane_offset = 0;
   1485         for (idx = 0; idx < pmc->num_phys; idx++) {
   1486             phy = pmc->phy[idx];
   1487             core = phy->core;
   1488             /* determine configuration data structure to default values, based on SOC properties */
   1489             SOC_IF_ERROR_RETURN
   1490                 (phy8806x_config_init(unit, port,
   1491                               logical_lane_offset,
   1492                               &core->init_config, &phy->init_config));
   1493 
   1494             
   1495             if (!core->init) { 
   1496                core_status.pmd_active = 0;
   1497                core->init_config.trcvr_host_managed =  soc_property_port_get(unit, port, spn_FCMAP_TRANSCEIVER_HOST_MANAGED, 0);
   1498                SOC_IF_ERROR_RETURN
   1499                    (phymod_core_init(&core->pm_core, &core->init_config, &core_status));
   1500                core->init = TRUE;
   1501             }
   1502 
   1503             /*read serdes id info */
   1504             SOC_IF_ERROR_RETURN
   1505                 (phymod_core_info_get(&core->pm_core, &core_info)); 
   1506 
   1507 
   1508             /* for multicore phys, need to ratchet up to the next batch of lanes */
   1509             logical_lane_offset += core->init_config.lane_map.num_of_lanes;
   1510         }
   1511 
   1512         /* retrieve chip level information for serdes driver info */
   1513 /*         pi = &SOC_PHY_INFO(unit, port); */
   1514 
   1515 
   1516         /* set the port to its max or init_speed */
   1517         SOC_IF_ERROR_RETURN
   1518             (phy8806x_speed_to_interface_config_get(speed_config, &interface_config, &tx_index));
   1519 
   1520         phy8806x_phymod_interfacetype_to_soc_type(interface_config.interface_type, &soc_if);
   1521 
   1522         speed_config->interface = soc_if;
   1523 
   1524         phy8806x_port_config_init(speed_config, &port_config);
   1525 
   1526         if ( FLAGS(pc) & (PHY8806X_BMP0 | PHY8806X_BMP1) ) {
   1527             port_config.is_bootmaster = 1;
   1528         } else {
   1529             port_config.is_bootmaster = 0;
   1530         }
   1531 
   1532         /* Pass flex flag for both ETH and FC modes */
   1533         if (FLAGS(pc) & PHY8806X_FLEX) {
   1534             port_config.is_flex = 1;
   1535         }
   1536         
   1537         /* Port Init for ETH only */
   1538         if (core->init_config.core_mode == 0) {
   1539             bmp_port = get_bmp_port(port, pc);
   1540             port_config.quad_mode = get_quad_mode(bmp_port);       
   1541 
   1542             SOC_IF_ERROR_RETURN
   1543                 (phymod_port_init(&phy->pm_phy, &port_config));
   1544         }
   1545 
   1546 #if defined(INCLUDE_FCMAP)
   1547         if (pc->fcmap_enable) {
   1548             pc->fcmap_port_cfg = (void*)&port_config;
   1549             rv = soc_fcmapphy_init(unit, port, pc, 
   1550                         BFCMAP_CORE_BCM88060_A0, NULL);
   1551             
   1552             if (!SOC_SUCCESS(rv)) {
   1553                 LOG_ERROR(BSL_LS_SOC_PHY,
   1554                           (BSL_META_U(unit,
   1555                                       "soc_fcmapphy_init: FCMAP init for"
   1556                                       " u=%d p=%d FAILED\n "), unit, port));
   1557             } else {
   1558                 LOG_INFO(BSL_LS_SOC_PHY,
   1559                          (BSL_META_U(unit,
   1560                                      "soc_fcmapphy_init: FCMAP init for"
   1561                                      " u=%d p=%d SUCCESS\n"), unit, port));
   1562             }
   1563             return (rv);
   1564         }
   1565 #endif
   1566 
   1567         /*next check if cl72 needs to be enabled */
   1568         if (pCfg->forced_init_cl72) {
   1569             SOC_IF_ERROR_RETURN
   1570                 (phy8806x_cl72_enable_set(pmc, 1));
   1571         }
   1572 
   1573         /* setup the port's an cap */
   1574         SOC_IF_ERROR_RETURN
   1575             (phy_8806x_ability_local_get(unit, port, &ability));
   1576  
   1577         ability.medium = SOC_PA_MEDIUM_COPPER;
   1578         ability.channel =  SOC_PA_CHANNEL_LONG;
   1579         ability.fec = SOC_PA_FEC_NONE;
   1580 
   1581         SOC_IF_ERROR_RETURN
   1582             (phy_8806x_ability_advert_set(unit, port, &ability));
   1583 
   1584     }
   1585     LOG_INFO(BSL_LS_SOC_PHY,
   1586              (BSL_META_U(pc->unit,
   1587                          "phy_8806x_init: u=%d p=%d\n"), unit, port));
   1588 
   1589     pc->fiber.enable            = TRUE;
   1590     pc->fiber.force_duplex      = TRUE;
   1591     pc->fiber.preferred         = TRUE;
   1592 
   1593     return SOC_E_NONE;
   1594 }
   1595 
   1596 /*
   1597  * Function:
   1598  *      phy_8806x_link_get
   1599  * Purpose:
   1600  *      Get layer2 connection status.
   1601  * Parameters:
   1602  *      unit - BCM unit number.
   1603  *      port - Port number. 
   1604  *      link - address of memory to store link up/down state.
   1605  * Returns:     
   1606  *      SOC_E_NONE
   1607  */
   1608 STATIC int
   1609 phy_8806x_link_get(int unit, soc_port_t port, int *link)
   1610 {
   1611     phy_ctrl_t                *pc;
   1612     int                       rv = SOC_E_NONE;
   1613     uint16                    link_st;
   1614     int                       an = 0;
   1615     int                       an_done = 0;
   1616     phy8806x_config_t         *pCfg;
   1617     phy8806x_speed_config_t   *speed_config;
   1618     phy_ctrl_t                *int_pc = NULL;
   1619     phymod_phy_inf_config_t   interface_config;
   1620     phymod_ref_clk_t          ref_clock;
   1621     int                       speed, flag = 0;
   1622     soc_phymod_phy_t          *phy;
   1623     soc_phymod_ctrl_t         *pmc;
   1624     phymod_autoneg_control_t  an_control;
   1625     int                       an_complete;
   1626     phymod_phy_access_t       *pm_phy;
   1627     int                       local_fault = 0;
   1628     int                       remote_fault = 0;
   1629     static uint32_t           trials=0;    
   1630     int                       fec_val=0;
   1631 
   1632     *link = 0;
   1633     /* locate phy control */
   1634     pc = EXT_PHY_SW_STATE(unit, port);
   1635     if (pc == NULL) {
   1636         return SOC_E_INTERNAL;
   1637     }
   1638 
   1639     pmc = &pc->phymod_ctrl;
   1640     pCfg = (phy8806x_config_t *) pc->driver_data;
   1641     speed_config = &(pCfg->speed_config);
   1642 
   1643 #if defined(INCLUDE_FCMAP)
   1644     if (pc->fcmap_enable) {
   1645         rv = READ_FC_LINK_STATUS_REG(unit, pc, &link_st);
   1646         *link = (link_st & VS_MISC_STATUS_LL_STATUS_BIT_MASK) ? TRUE: FALSE;
   1647         return(rv); 
   1648     }
   1649 #endif
   1650 
   1651     int_pc = INT_PHY_SW_STATE(unit, port);
   1652     if (int_pc == NULL) {
   1653         return SOC_E_INTERNAL;
   1654     }
   1655 
   1656     SOC_IF_ERROR_RETURN(PHY_LINK_GET(int_pc->pd, unit, port, link));
   1657     if ((speed_config->repeater_an_phase == REPEATER_AN_PHASE_2) && (!*link)) {
   1658         speed_config->repeater_an_phase = REPEATER_AN_PHASE_NONE;
   1659         speed_config->repeater_an_resolved_speed = 0;
   1660         speed_config->repeater_an_retry_phase0 = 0;
   1661         phy_8806x_an_set(0, port, 0);
   1662         phy_8806x_an_set(0, port, 1);
   1663         return(SOC_E_NONE);
   1664     }
   1665 
   1666     if (speed_config->port_mode != ETH_REPEATER) {
   1667         SOC_IF_ERROR_RETURN
   1668         (phy_8806x_an_get(unit, port, &an, &an_done));
   1669 
   1670         if ( an ) {
   1671             if ( !an_done ) {
   1672                 #if 0
   1673                 LOG_CLI((BSL_META_U(unit,
   1674                     "phy_8806x_link_get: AN not done, return \n")));
   1675                 #endif
   1676                 *link = 0;
   1677                 return(SOC_E_NONE);
   1678             }
   1679         }    
   1680 
   1681         rv = READ_LINK_STATUS_REG(unit, pc, &link_st);
   1682         *link = (link_st & VS_MISC_STATUS_LL_STATUS_BIT_MASK) >> 3;
   1683     } else if (speed_config->port_mode == ETH_REPEATER) {
   1684         if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_NONE) {
   1685             /* We are in forced speed repeater mode. */
   1686 
   1687             local_fault = 0;
   1688             remote_fault = 0;
   1689             /* For now, only implemented for Tomohawk. Expand as needed */
   1690 #ifdef BCM_TOMAHAWK_SUPPORT
   1691             if (SOC_IS_TOMAHAWK(unit)) {
   1692                 /* Read the FAULT if any */
   1693                 if (speed_config->macd) {
   1694                     rv = MAC_CONTROL_GET(speed_config->macd, unit, port, SOC_MAC_CONTROL_FAULT_LOCAL_STATUS, &local_fault);
   1695                     rv = MAC_CONTROL_GET(speed_config->macd, unit, port, SOC_MAC_CONTROL_FAULT_REMOTE_STATUS, &remote_fault);
   1696                 }
   1697             }
   1698 #endif
   1699 
   1700 #ifdef PORTMOD_SUPPORT
   1701             if (FLAGS(pc) & PHY8806X_PORTMOD)  {
   1702                 portmod_port_local_fault_status_get(unit, port, &local_fault);
   1703                 portmod_port_remote_fault_status_get(unit, port, &remote_fault);
   1704             }
   1705 #endif
   1706             /* read the switch internal PHY link status (PCS link) */
   1707             SOC_IF_ERROR_RETURN(PHY_LINK_GET(int_pc->pd, unit, port, link));
   1708 
   1709 #ifdef PORTMOD_SUPPORT
   1710             if (FLAGS(pc) & PHY8806X_PORTMOD)
   1711                 portmod_port_link_get(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, link);
   1712 #endif
   1713         
   1714             pm_phy = &pmc->phy[0]->pm_phy;
   1715 
   1716             /* 
   1717              * JIRA SDK-118465
   1718              * Reset the MT2 sys and line side if any one of the below conditions are met :
   1719              * (a) If the switch internal PHY PCS link is DOWN.
   1720              * (b) If the switch internal PHY PCS link is UP but the MAC is seeing LOCAL or REMOTE fault.
   1721              */ 
   1722             if (!(*link) || 
   1723                 ((*link) && (local_fault || remote_fault) && (speed_config->speed != 1000))) {
   1724                 trials++;
   1725                 /* Wait for the link to stabilize during device init. */
   1726                 if (trials >= REPEATER_FS_RESET_TRIAL) {
   1727                     /* Send XMOD to reset the system and line side interface of MT2 port */  
   1728                     SOC_IF_ERROR_RETURN(phymod_reset_interface(pm_phy));
   1729                     trials = 0;
   1730                 }
   1731             }
   1732         } else {
   1733             /* Repeater AN mode is enabled. */
   1734             pm_phy = &pmc->phy[0]->pm_phy;
   1735             SOC_IF_ERROR_RETURN
   1736                 (phymod_phy_autoneg_get(pm_phy, &an_control, (uint32_t *) &an_complete));
   1737             if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_0) {
   1738                 if (an_control.flags & REPEATER_AN_PHASE0_LOCKED) {
   1739                     if (REPEATER_AN_PHASE0_CL74 & an_control.flags)
   1740                         fec_val = 1;
   1741                     else
   1742                         fec_val = 0;
   1743                     
   1744                     PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION, fec_val);
   1745 
   1746                     speed_config->repeater_an_phase = REPEATER_AN_PHASE_1;
   1747 
   1748                     pmc = &pc->phymod_ctrl;
   1749                     phy = pmc->phy[0];
   1750                     ref_clock = phymodRefClk156Mhz;
   1751                     /* note that the flags have an option to indicate whether it's ok to reprogram the PLL */
   1752                     SOC_IF_ERROR_RETURN(phymod_phy_interface_config_get(&phy->pm_phy,
   1753                                              flag, ref_clock, &interface_config));
   1754                     speed = interface_config.data_rate;
   1755                     speed_config->repeater_an_resolved_speed = interface_config.data_rate;
   1756 
   1757 #ifdef PORTMOD_SUPPORT
   1758                     if ((FLAGS(pc) & PHY8806X_PORTMOD) && (interface_config.data_rate != 100000))  {
   1759                         if (REPEATER_AN_PHASE0_CL74 & an_control.flags) {
   1760                             fec_val = 1;
   1761                             portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val);
   1762                         }
   1763                     }
   1764 #endif
   1765 
   1766                     if (interface_config.data_rate == 100000) {
   1767                         speed_config->speed = interface_config.data_rate;
   1768                         PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION, 0);
   1769                         PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION_CL91, 1);
   1770 #ifdef PORTMOD_SUPPORT
   1771                         if (FLAGS(pc) & PHY8806X_PORTMOD)  {
   1772                             fec_val = 1;
   1773                             portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val);
   1774                             PHYMOD_FEC_CL91_SET(fec_val);
   1775                             portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val);
   1776                         }
   1777 #endif
   1778                     } else {
   1779                         if (REPEATER_AN_PHASE0_CL91 & an_control.flags) {
   1780                             PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION_CL91, 1);
   1781 #ifdef PORTMOD_SUPPORT
   1782                         if (FLAGS(pc) & PHY8806X_PORTMOD)  {
   1783                             fec_val = 1;
   1784                             portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val);
   1785                             PHYMOD_FEC_CL91_SET(fec_val);
   1786                             portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val);
   1787                         }
   1788 #endif
   1789                         } else {
   1790                             /* CL91 is supported only for 100G */
   1791                             PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION_CL91, 0);
   1792 #ifdef PORTMOD_SUPPORT
   1793                         if (FLAGS(pc) & PHY8806X_PORTMOD)  {
   1794                             fec_val = 0;
   1795                             portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val);
   1796                             PHYMOD_FEC_CL91_SET(fec_val);
   1797                             portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val);
   1798                         }
   1799 #endif
   1800                         }
   1801                     }
   1802 
   1803                     PHY_SPEED_SET(int_pc->pd, unit, port, speed);
   1804 
   1805                     /* Set for the next phase */
   1806                     phy_8806x_an_set(0, port, 1);
   1807                     *link = 0;
   1808                     return(SOC_E_NONE);
   1809                 } else {
   1810                     *link = 0;
   1811                     if (speed_config->repeater_an_retry_phase0 >= REPEATER_AN_PHASE0_RETRY) {
   1812                         speed_config->repeater_an_phase = REPEATER_AN_PHASE_NONE;
   1813                         speed_config->repeater_an_resolved_speed = 0;
   1814                         phy_8806x_an_set(0, port, 0);
   1815                         phy_8806x_an_set(0, port, 1);
   1816                         speed_config->repeater_an_retry_phase0 = 0;
   1817                     }
   1818                     speed_config->repeater_an_retry_phase0++;
   1819                     return(SOC_E_NONE);
   1820                 }
   1821             } else if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_1) {
   1822                 pm_phy = &pmc->phy[0]->pm_phy;
   1823                 SOC_IF_ERROR_RETURN
   1824                     (phymod_phy_autoneg_get(pm_phy, &an_control, (uint32_t *) &an_complete));
   1825                 
   1826                 if (an_control.flags & REPEATER_AN_PHASE1_LOCKED) {               
   1827                     PHY_LINK_GET(int_pc->pd, unit, port, link);
   1828                     if (*link) {
   1829                         speed_config->repeater_an_phase = REPEATER_AN_PHASE_2;
   1830                     }
   1831                 } else {
   1832                     *link = 0;
   1833                     if (speed_config->repeater_an_retry_phase1 >= REPEATER_AN_PHASE1_RETRY) {
   1834                         speed_config->repeater_an_phase = REPEATER_AN_PHASE_NONE;
   1835                         speed_config->repeater_an_resolved_speed = 0;
   1836                         phy_8806x_an_set(0, port, 0);
   1837                         phy_8806x_an_set(0, port, 1);
   1838                         speed_config->repeater_an_retry_phase1 = 0;
   1839                     }
   1840                     speed_config->repeater_an_retry_phase1++;
   1841                 }
   1842                 return(SOC_E_NONE);
   1843             } else if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_2) {
   1844                 PHY_LINK_GET(int_pc->pd, unit, port, link);
   1845                 return(SOC_E_NONE);
   1846             }
   1847         }
   1848         return(SOC_E_NONE);
   1849     } 
   1850 
   1851     return (rv);
   1852 }
   1853 
   1854 /*
   1855  * Function:
   1856  *      phy_8806x_enable_set
   1857  * Purpose:
   1858  *      Enable/Disable phy 
   1859  * Parameters:
   1860  *      unit - BCM unit number.
   1861  *      port - Port number. 
   1862  *      enable - on/off state to set
   1863  * Returns:     
   1864  *      SOC_E_NONE
   1865  */
   1866 STATIC int
   1867 phy_8806x_enable_set(int unit, soc_port_t port, int enable)
   1868 {
   1869     phy_ctrl_t                *pc;
   1870     soc_phymod_ctrl_t         *pmc;
   1871     phymod_phy_access_t       *pm_phy;
   1872 
   1873     /* locate phy control */
   1874     pc = EXT_PHY_SW_STATE(unit, port);
   1875     if (pc == NULL) {
   1876         return SOC_E_INTERNAL;
   1877     }
   1878 
   1879 #if defined(INCLUDE_FCMAP)
   1880     if (pc->fcmap_enable) {
   1881         int p;
   1882         int rv = SOC_E_NONE;
   1883 
   1884         p = SOC_FCMAP_PORTID(unit, port);
   1885 
   1886         /* If not enable, bring FC link down */
   1887         if (!enable) {
   1888             LOG_ERROR(BSL_LS_SOC_PHY,
   1889                      (BSL_META_U(unit,
   1890                                  "Bringing FC link down u=%d p=%d enable=%d rv=%d\n"),
   1891                       unit, port, enable, rv));
   1892 
   1893             rv = bfcmap_port_shutdown(p);
   1894         } else {
   1895             LOG_ERROR(BSL_LS_SOC_PHY,
   1896                      (BSL_META_U(unit,
   1897                                  "Bringing FC link UP u=%d p=%d enable=%d rv=%d\n"),
   1898                       unit, port, enable, rv));
   1899 
   1900             rv = bfcmap_port_link_enable(p);
   1901         }
   1902 
   1903         if (rv != BFCMAP_E_NONE) {
   1904             LOG_ERROR(BSL_LS_SOC_PHY,
   1905                      (BSL_META_U(unit,
   1906                                  "Failed u=%d p=%d enable=%d rv=%d\n"),
   1907                       unit, port, enable, rv));
   1908             return SOC_E_FAIL;
   1909         }
   1910         LOG_INFO(BSL_LS_SOC_PHY,
   1911                  (BSL_META_U(unit,
   1912                              "Success u=%d p=%d enable=%d rv=%d\n"),
   1913                   unit, port, enable, rv));
   1914 
   1915         return SOC_E_NONE;
   1916     }
   1917 #endif
   1918 
   1919     if ( FLAGS(pc) & PHY8806X_PM ) {
   1920         return SOC_E_NONE;
   1921     }
   1922 
   1923     pmc = &pc->phymod_ctrl;
   1924     pm_phy = &pmc->phy[0]->pm_phy;
   1925     SOC_IF_ERROR_RETURN
   1926         (phymod_port_enable_set(pm_phy, (uint32_t)enable));
   1927 
   1928     return (SOC_E_NONE);
   1929 }
   1930 
   1931 /*
   1932  * Function:
   1933  *      phy_8806x_enable_get
   1934  * Purpose:
   1935  *      Enable/Disable phy 
   1936  * Parameters:
   1937  *      unit - BCM unit number.
   1938  *      port - Port number. 
   1939  *      enable - on/off state to set
   1940  * Returns:     
   1941  *      SOC_E_NONE
   1942  */
   1943 STATIC int
   1944 phy_8806x_enable_get(int unit, soc_port_t port, int *enable)
   1945 {
   1946     phy_ctrl_t                *pc;
   1947     soc_phymod_ctrl_t         *pmc;
   1948     phymod_phy_access_t       *pm_phy;
   1949 
   1950     /* locate phy control */
   1951     pc = EXT_PHY_SW_STATE(unit, port);
   1952     if (pc == NULL) {
   1953         return SOC_E_INTERNAL;
   1954     }
   1955 
   1956 #if defined(INCLUDE_FCMAP)
   1957     /* Skip for FC */
   1958     if (pc->fcmap_enable) {
   1959         *enable = 1;
   1960         return SOC_E_NONE;
   1961     }
   1962 #endif
   1963 
   1964     if ( FLAGS(pc) & PHY8806X_PM ) {
   1965         return SOC_E_NONE;
   1966     }
   1967 
   1968     pmc = &pc->phymod_ctrl;
   1969     pm_phy = &pmc->phy[0]->pm_phy;
   1970     SOC_IF_ERROR_RETURN
   1971         (phymod_port_enable_get(pm_phy, (uint32_t*)enable));
   1972 
   1973     *enable = 1;  
   1974     return (SOC_E_NONE);
   1975 }
   1976 
   1977 
   1978 /*
   1979  * Function:
   1980  *      phy_8806x_duplex_get
   1981  * Purpose:
   1982  *      Get PHY duplex mode
   1983  * Parameters:
   1984  *      unit - BCM unit number.
   1985  *      port - Port number. 
   1986  *      duplex - current duplex mode
   1987  * Returns:     
   1988  *      SOC_E_NONE
   1989  */
   1990 STATIC int
   1991 phy_8806x_duplex_get(int unit, soc_port_t port, int *duplex)
   1992 {
   1993     *duplex = TRUE;
   1994     return SOC_E_NONE;
   1995 }
   1996 
   1997 /*
   1998  * Function:
   1999  *      phy_8806x_speed_set
   2000  * Purpose:
   2001  *      Set PHY speed
   2002  * Parameters:
   2003  *      unit - BCM unit number.
   2004  *      port - Port number. 
   2005  *      speed - link speed in Mbps
   2006  * Returns:     
   2007  *      SOC_E_NONE
   2008  */
   2009 
   2010 STATIC int
   2011 phy_8806x_speed_set(int unit, soc_port_t port, int speed)
   2012 {
   2013     phy_ctrl_t                *pc;
   2014     phy8806x_config_t             *pCfg;
   2015     soc_phymod_ctrl_t         *pmc;
   2016     soc_phymod_phy_t          *phy;
   2017     phymod_phy_inf_config_t   interface_config;
   2018     int rv = SOC_E_NONE;
   2019     phy_ctrl_t                *int_pc;
   2020     phymod_ref_clk_t          ref_clock;
   2021 
   2022     /* locate phy control */
   2023     pc = EXT_PHY_SW_STATE(unit, port);
   2024     if (pc == NULL) {
   2025         return SOC_E_INTERNAL;
   2026     }
   2027 
   2028     if ((speed == 0) || ( FLAGS(pc) & PHY8806X_PM )) {
   2029         return SOC_E_NONE;
   2030     }
   2031 
   2032     int_pc = INT_PHY_SW_STATE(unit, port);
   2033     
   2034     if (NULL != int_pc) {
   2035         rv = PHY_SPEED_SET(int_pc->pd, unit, port, speed);
   2036     }
   2037 
   2038     pmc = &pc->phymod_ctrl;
   2039     pCfg = (phy8806x_config_t *) pc->driver_data;
   2040 
   2041     phy = pmc->phy[0];
   2042     if (phy == NULL) {
   2043         return SOC_E_INTERNAL;
   2044     }
   2045 
   2046     ref_clock = phymodRefClk156Mhz;
   2047     SOC_IF_ERROR_RETURN
   2048         (phymod_phy_interface_config_get(&phy->pm_phy,
   2049                                             0, ref_clock, &interface_config));
   2050     interface_config.data_rate = speed;
   2051 
   2052     /* note that the flags have an option to indicate whether it's ok to reprogram the PLL */
   2053     SOC_IF_ERROR_RETURN
   2054         (phymod_phy_interface_config_set(&phy->pm_phy,
   2055                                             0 /* flags */, &interface_config));
   2056 
   2057     /* record success */
   2058     pCfg->speed_config.speed = speed;
   2059 
   2060     pc->fiber.force_speed    = speed;;
   2061     return (rv);
   2062 }
   2063 
   2064 /*
   2065  * Function:
   2066  *      phy_8806x_speed_get
   2067  * Purpose:
   2068  *      Get PHY speed
   2069  * Parameters:
   2070  *      unit - BCM unit number.
   2071  *      port - Port number. 
   2072  *      speed - current link speed in Mbps
   2073  * Returns:     
   2074  *      SOC_E_NONE
   2075  */
   2076 STATIC int
   2077 phy_8806x_speed_get(int unit, soc_port_t port, int *speed)
   2078 {
   2079     phy_ctrl_t                *pc;
   2080     soc_phymod_ctrl_t         *pmc;
   2081     soc_phymod_phy_t          *phy;
   2082     phymod_phy_inf_config_t   interface_config;
   2083     int flag = 0;
   2084     phymod_ref_clk_t          ref_clock;
   2085     int                       an = 0;
   2086     int                       an_done = 0;
   2087     phy_ctrl_t                *int_pc = NULL;
   2088     phy8806x_speed_config_t *speed_config;
   2089     phy8806x_config_t *pCfg;
   2090 
   2091 #if 0
   2092 #if defined(INCLUDE_FCMAP)
   2093     uint32_t xmodtxbuff[XMOD_BUFFER_MAX_LEN/4];
   2094     uint32_t xmodrxbuff[XMOD_BUFFER_MAX_LEN/4];
   2095     uint8_t *buftxptr, *bufrxptr;
   2096     int xmodtxlen, xmodrxlen;
   2097     uint32_t x_cmd, x_response, cmd;
   2098     uint16_t fc_spd = 0;
   2099     int rv;
   2100 #endif
   2101 #endif
   2102 
   2103     /* locate phy control */
   2104     pc = EXT_PHY_SW_STATE(unit, port);
   2105     if (pc == NULL) {
   2106         return SOC_E_INTERNAL;
   2107     }
   2108 
   2109 
   2110 #if 0
   2111 #if defined(INCLUDE_FCMAP)
   2112     if (pc->fcmap_enable) {
   2113         cmd = 0x4;
   2114         x_cmd = HOST2LE32(cmd);
   2115 
   2116         /* write args to xmod buffer */
   2117         buftxptr = (uint8_t *)xmodtxbuff;
   2118         WRITE_XMOD_ARG_BUFF(buftxptr, &x_cmd, sizeof(x_cmd));
   2119         xmodtxlen = sizeof(x_cmd);
   2120         xmodtxlen = GET_XMOD_BUF_WORD_LEN(xmodtxlen);
   2121 
   2122         xmodrxlen = sizeof(x_response);
   2123         xmodrxlen = GET_XMOD_BUF_WORD_LEN(xmodrxlen);
   2124 
   2125         /* call xmod */
   2126         rv = phy_8806x_xmod_command(pc->unit, pc->port, XMOD_CMD_MODE_CORE(XMOD_DEV_DEBUG_CMD), xmodtxbuff, xmodtxlen, xmodrxbuff, xmodrxlen);
   2127 
   2128         /* retrieve the argument from the xmod rx buffer */
   2129         bufrxptr = (uint8_t *)xmodrxbuff;
   2130         READ_XMOD_ARG_BUFF(bufrxptr, &x_response, sizeof(x_response));
   2131         fc_spd = LE2HOST32(x_response);
   2132         /* Set speed to 10G */
   2133         *speed = 10000 ;
   2134 
   2135         return SOC_E_NONE;
   2136     }
   2137 #endif
   2138 #endif
   2139 
   2140     pCfg = (phy8806x_config_t *) pc->driver_data;
   2141     speed_config = &(pCfg->speed_config);
   2142     int_pc = INT_PHY_SW_STATE(unit, port);
   2143 
   2144     if (speed_config->port_mode == ETH_REPEATER) {
   2145         if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_NONE) {
   2146             /* If forced repeater AN mode */
   2147             SOC_IF_ERROR_RETURN(PHY_SPEED_GET(int_pc->pd, unit, port, speed));
   2148             return (SOC_E_NONE);
   2149         } else if (speed_config->repeater_an_phase == 0) {
   2150             *speed = 0;
   2151             LED_SPEED(pc) = 0;
   2152             return (SOC_E_NONE);
   2153         } else if (speed_config->repeater_an_phase == 1) {
   2154             pmc = &pc->phymod_ctrl;
   2155             phy = pmc->phy[0];
   2156             ref_clock = phymodRefClk156Mhz;
   2157             /* note that the flags have an option to indicate whether it's ok to reprogram the PLL */
   2158             SOC_IF_ERROR_RETURN
   2159                 (phymod_phy_interface_config_get(&phy->pm_phy,
   2160                                              flag, ref_clock, &interface_config));
   2161             *speed = interface_config.data_rate;
   2162             LED_SPEED(pc) = *speed;
   2163             return(SOC_E_NONE);
   2164         } else if (speed_config->repeater_an_phase >= 1) {
   2165             *speed = speed_config->repeater_an_resolved_speed;
   2166             LED_SPEED(pc) = *speed;
   2167             return(SOC_E_NONE);
   2168         }
   2169     }
   2170 
   2171     SOC_IF_ERROR_RETURN
   2172     (phy_8806x_an_get(unit, port, &an, &an_done));
   2173 
   2174     if ( an ) {
   2175         if ( !an_done ) {
   2176             #if 0
   2177             LOG_CLI((BSL_META_U(unit,
   2178                     "phy_8806x_speed_get: AN not done, return \n")));
   2179             #endif
   2180             *speed = 0;
   2181             LED_SPEED(pc) = 0;
   2182             return(SOC_E_NONE);
   2183         }
   2184     }
   2185 
   2186     pmc = &pc->phymod_ctrl;
   2187 
   2188     /* initialize the data structure */
   2189     interface_config.data_rate = 0;
   2190 
   2191     /* now loop through all cores */
   2192     phy = pmc->phy[0];
   2193     if (phy == NULL) {
   2194         return SOC_E_INTERNAL;
   2195     }
   2196 
   2197     pCfg = (phy8806x_config_t *) pc->driver_data;
   2198     speed_config = &(pCfg->speed_config);
   2199 
   2200     if (speed_config->port_mode == ETH_REPEATER) {
   2201         int_pc = INT_PHY_SW_STATE(unit, port);
   2202         SOC_IF_ERROR_RETURN(PHY_SPEED_GET(int_pc->pd, unit, port, speed));
   2203     } else {
   2204         ref_clock = phymodRefClk156Mhz;
   2205         /* note that the flags have an option to indicate whether it's ok to reprogram the PLL */
   2206         SOC_IF_ERROR_RETURN
   2207             (phymod_phy_interface_config_get(&phy->pm_phy,
   2208                                              flag, ref_clock, &interface_config));
   2209         *speed = interface_config.data_rate;
   2210     }
   2211     LED_SPEED(pc) = *speed;
   2212     return (SOC_E_NONE);
   2213 }
   2214 
   2215 #define AN_MAX_RETRY    10
   2216 
   2217 /*
   2218  * Function:    
   2219  *      phy_8806x_an_set
   2220  * Purpose:     
   2221  *      Enable or disable auto-negotiation on the specified port.
   2222  * Parameters:
   2223  *      unit - BCM unit number.
   2224  *      port - Port number. 
   2225  *      an   - Boolean, if true, auto-negotiation is enabled 
   2226  *              (and/or restarted). If false, autonegotiation is disabled.
   2227  * Returns:     
   2228  *      SOC_E_XXX  _soc_triumph_tx
   2229  */
   2230 STATIC int
   2231 phy_8806x_an_set(int unit, soc_port_t port, int enable)
   2232 {
   2233     phy_ctrl_t                *pc;
   2234     phy8806x_config_t         *pCfg;
   2235     soc_phymod_ctrl_t         *pmc;
   2236     soc_phymod_phy_t          *phy;
   2237     phymod_autoneg_control_t   an;
   2238     soc_info_t                *si;
   2239     phymod_phy_an_status_t     an_status;
   2240     phymod_an_try_enable_control_t an_ctrl;
   2241     phy8806x_speed_config_t* speed_config;
   2242     phy_ctrl_t                *int_pc;
   2243     uint32_t                   fec_val;
   2244 
   2245     /* locate phy control */
   2246     pc = EXT_PHY_SW_STATE(unit, port);
   2247     if (pc == NULL) {
   2248         return SOC_E_INTERNAL;
   2249     }
   2250 
   2251     int_pc = INT_PHY_SW_STATE(unit, port);
   2252 
   2253 #if defined(INCLUDE_FCMAP)
   2254     /* Skip for FC */
   2255     if (pc->fcmap_enable) {
   2256         return SOC_E_NONE;
   2257     }
   2258 #endif
   2259 
   2260     phymod_autoneg_control_t_init(&an);
   2261     pmc = &pc->phymod_ctrl;
   2262     pCfg = (phy8806x_config_t *) pc->driver_data;
   2263     speed_config = &(pCfg->speed_config);
   2264     si = &SOC_INFO(unit);
   2265 
   2266     /* only request autoneg on the first core */
   2267     phy = pmc->phy[0];
   2268     if (phy == NULL) {
   2269         return SOC_E_INTERNAL;
   2270     }
   2271     an_ctrl.enable = enable;
   2272     an_ctrl.num_lane_adv = si->port_num_lanes[port];
   2273     an_ctrl.an_mode = phymod_AN_MODE_NONE;
   2274     if(pCfg->cl73an) {
   2275         switch (pCfg->cl73an) {
   2276             case PHY8806X_CL73_W_BAM:  
   2277                 an_ctrl.an_mode = phymod_AN_MODE_CL73BAM;  
   2278                 break ;
   2279             case PHY8806X_CL73_WO_BAM:
   2280                 an_ctrl.an_mode = phymod_AN_MODE_CL73;  
   2281                 break ;
   2282             case PHY8806X_CL73_HPAM_VS_SW:    
   2283                 an_ctrl.an_mode = phymod_AN_MODE_HPAM;  
   2284                 break ;  /* against TD+ */
   2285             case PHY8806X_CL73_HPAM:
   2286                 an_ctrl.an_mode = phymod_AN_MODE_HPAM;  
   2287                 break ;  /* against TR3 */
   2288             case PHY8806X_CL73_CL37:    
   2289                 an_ctrl.an_mode = phymod_AN_MODE_CL73;  
   2290                 break ;
   2291             default:
   2292                 break;
   2293         }
   2294     }
   2295 
   2296     pc->fiber.autoneg_enable = enable;
   2297 
   2298     if (!enable) {
   2299         an.enable = 0; /* Disable AN */
   2300         an.num_lane_adv = si->port_num_lanes[port];
   2301         an.an_mode = an_ctrl.an_mode;
   2302         SOC_IF_ERROR_RETURN
   2303             (phymod_phy_autoneg_set(&phy->pm_phy, &an));
   2304         if (speed_config->repeater_an_phase > REPEATER_AN_PHASE_NONE) {
   2305             PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION, 0);
   2306             PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION_CL91, 0);
   2307         }
   2308         speed_config->repeater_an_phase  = REPEATER_AN_PHASE_NONE;
   2309         speed_config->repeater_an_resolved_speed  = 0;
   2310         speed_config->repeater_an_retry_phase0 = 0;
   2311         
   2312         if ((speed_config->port_mode == ETH_REPEATER) && (speed_config->speed == 100000)) {
   2313             fec_val = 0;
   2314             PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION_CL91, fec_val);
   2315 #ifdef PORTMOD_SUPPORT
   2316             if (FLAGS(pc) & PHY8806X_PORTMOD)  {
   2317                 portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val);
   2318                 PHYMOD_FEC_CL91_SET(fec_val);
   2319                 portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val);
   2320             }
   2321 #endif
   2322         }
   2323 
   2324     } else {
   2325         an_ctrl.speed = pc->speed_max;
   2326         if (speed_config->port_mode == ETH_REPEATER) {
   2327             if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_NONE) {
   2328                 speed_config->repeater_an_phase = REPEATER_AN_PHASE_0;
   2329                 /* Send SET_AN XMOD command to FW for enabling AutoNeg phase 0. */
   2330                 SOC_IF_ERROR_RETURN
   2331                     (phymod_phy_autoneg_try_enable(&phy->pm_phy, &an_ctrl, &an_status));
   2332                  return (SOC_E_NONE);
   2333             } else if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_1) {
   2334                 an_ctrl.speed = speed_config->repeater_an_resolved_speed;
   2335                 SOC_IF_ERROR_RETURN
   2336                     (phymod_phy_autoneg_try_enable(&phy->pm_phy, &an_ctrl, &an_status));
   2337                 return (SOC_E_NONE);
   2338             } else if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_2) {
   2339                 return (SOC_E_NONE);
   2340             }
   2341         }
   2342 
   2343         /* Send SET_AN XMOD command to FW for enabling AutoNeg. */
   2344         SOC_IF_ERROR_RETURN
   2345             (phymod_phy_autoneg_try_enable(&phy->pm_phy, &an_ctrl, &an_status));
   2346     }
   2347 
   2348     return (SOC_E_NONE);
   2349 }
   2350 
   2351 /*
   2352  * Function:    
   2353  *      phy_8806x_an_get
   2354  * Purpose:     
   2355  *      Get the current auto-negotiation status (enabled/busy)
   2356  * Parameters:
   2357  *      unit - BCM unit number.
   2358  *      port - Port number. 
   2359  *      an   - (OUT) if true, auto-negotiation is enabled.
   2360  *      an_done - (OUT) if true, auto-negotiation is complete. This
   2361  *              value is undefined if an == false.
   2362  * Returns:     
   2363  *      SOC_E_XXX
   2364  */
   2365 
   2366 STATIC int
   2367 phy_8806x_an_get(int unit, soc_port_t port, int *an, int *an_done)
   2368 {
   2369     phy_ctrl_t* pc; 
   2370     soc_phymod_ctrl_t *pmc;
   2371     phymod_phy_access_t *pm_phy;
   2372     phymod_autoneg_control_t an_control;
   2373     int idx, an_complete;
   2374     phy8806x_config_t         *pCfg;
   2375     phy8806x_speed_config_t   *speed_config;
   2376     phy_ctrl_t                *int_pc;
   2377     int                       link;
   2378 
   2379     pc = EXT_PHY_SW_STATE(unit, port);
   2380     pmc = &pc->phymod_ctrl;
   2381 
   2382     pCfg = (phy8806x_config_t *) pc->driver_data;
   2383     speed_config = &(pCfg->speed_config);
   2384 
   2385 #if defined(INCLUDE_FCMAP)
   2386     /* Skip for FC */
   2387     if (pc->fcmap_enable) {
   2388         return SOC_E_NONE;
   2389     }
   2390 #endif
   2391 
   2392     int_pc = INT_PHY_SW_STATE(unit, port);
   2393 
   2394     sal_memset(&an_control, 0x0, sizeof(an_control));
   2395     for (idx = 0; idx < pmc->num_phys; idx++) {
   2396         pm_phy = &pmc->phy[idx]->pm_phy;
   2397         SOC_IF_ERROR_RETURN
   2398             (phymod_phy_autoneg_get(pm_phy, &an_control, (uint32_t *) &an_complete));
   2399     }
   2400 
   2401     if (speed_config->port_mode != ETH_REPEATER) {
   2402         if (an_control.enable) {
   2403             *an = 1;
   2404             *an_done = an_complete;
   2405         } else {
   2406             *an = 0;
   2407             *an_done = 0;
   2408         }
   2409     } else if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_NONE) {
   2410         *an = 0;
   2411         *an_done = 0;
   2412     } else if (speed_config->repeater_an_phase >= REPEATER_AN_PHASE_0) {
   2413         *an = 1;
   2414         *an_done = 0;
   2415     } else if (speed_config->repeater_an_phase >= REPEATER_AN_PHASE_1) {
   2416         *an = 1;
   2417         PHY_LINK_GET(int_pc->pd, unit, port, &link);
   2418         if (link)
   2419             *an_done = 1;
   2420     } else if (speed_config->repeater_an_phase >= REPEATER_AN_PHASE_2) {
   2421         *an = 1;
   2422         *an_done = 1;
   2423     }
   2424 
   2425     return (SOC_E_NONE);
   2426 }
   2427 
   2428 /*
   2429  * Function:
   2430  *      phy_8806x_ability_advert_set
   2431  * Purpose:
   2432  *      Set the current advertisement for auto-negotiation.
   2433  * Parameters:
   2434  *      unit - BCM unit number.
   2435  *      port - Port number.
   2436  *      ability - Port mode mask indicating supported options/speeds.
   2437  * Returns:
   2438  *      SOC_E_XXX
   2439  * Notes:
   2440  *      The advertisement is set only for the ACTIVE medium.
   2441  *      No synchronization performed at this level.
   2442  */
   2443 
   2444 STATIC int
   2445 phy_8806x_ability_advert_set(int unit, soc_port_t port,
   2446                           soc_port_ability_t *ability)
   2447 {
   2448     phy_ctrl_t                *pc;
   2449     phy8806x_config_t         *pCfg;
   2450     soc_phymod_ctrl_t         *pmc;
   2451     soc_phymod_phy_t          *phy;
   2452     int                       port_num_lanes;
   2453     int                       line_interface;
   2454     uint32_t                  an_tech_ability;
   2455     uint32_t                  an_bam37_ability;
   2456     uint32_t                  an_bam73_ability;
   2457     _shr_port_mode_t          speed_full_duplex;
   2458     phymod_autoneg_ability_t  phymod_autoneg_ability; 
   2459     phy8806x_speed_config_t*  speed_config;
   2460 
   2461     /* locate phy control */
   2462     pc = EXT_PHY_SW_STATE(unit, port);
   2463     if (pc == NULL) {
   2464         return SOC_E_INTERNAL;
   2465     }
   2466 
   2467 #if defined(INCLUDE_FCMAP)
   2468     /* Skip for FC */
   2469     if (pc->fcmap_enable) {
   2470         return SOC_E_NONE;
   2471     }
   2472 #endif
   2473 
   2474     phymod_autoneg_ability_t_init(&phymod_autoneg_ability);
   2475 
   2476     pmc = &pc->phymod_ctrl;
   2477     pCfg = (phy8806x_config_t *) pc->driver_data;
   2478 
   2479     /* only set abilities on the first core */
   2480     phy = pmc->phy[0];
   2481     if (phy == NULL) {
   2482         return SOC_E_INTERNAL;
   2483     }
   2484 
   2485     pCfg = (phy8806x_config_t *) pc->driver_data;
   2486     port_num_lanes = pCfg->speed_config.ln_lane_count;
   2487     line_interface = pCfg->speed_config.line_interface;
   2488 
   2489     an_tech_ability  = 0;
   2490     an_bam37_ability = 0;
   2491     an_bam73_ability = 0;
   2492     speed_full_duplex = ability->speed_full_duplex;
   2493 
   2494     /* 
   2495          an_tech_ability
   2496     */
   2497     if (port_num_lanes == 4) {
   2498 		if (ability->medium) {
   2499             if (speed_full_duplex & SOC_PA_SPEED_100GB) {
   2500                 if (ability->medium & SOC_PA_MEDIUM_BACKPLANE) {
   2501                     PHYMOD_AN_CAP_100G_KR4_SET(an_tech_ability);
   2502                 } else if (ability->medium & SOC_PA_MEDIUM_COPPER) {
   2503                     PHYMOD_AN_CAP_100G_CR4_SET(an_tech_ability);
   2504                 } else {
   2505                     PHYMOD_AN_CAP_100G_KR4_SET(an_tech_ability);
   2506                 }
   2507             }
   2508             if (speed_full_duplex & SOC_PA_SPEED_40GB) {
   2509                 if (ability->medium & SOC_PA_MEDIUM_BACKPLANE) {
   2510                     PHYMOD_AN_CAP_40G_KR4_SET(an_tech_ability);
   2511                 } else if (ability->medium & SOC_PA_MEDIUM_COPPER) {
   2512                     PHYMOD_AN_CAP_40G_CR4_SET(an_tech_ability);
   2513                 } else {
   2514                     PHYMOD_AN_CAP_40G_KR4_SET(an_tech_ability);
   2515                 }
   2516             }
   2517 		} else {
   2518 			if (speed_full_duplex & SOC_PA_SPEED_100GB) {
   2519 				if (line_interface & (1 << SOC_PORT_IF_CR4)) {
   2520 					PHYMOD_AN_CAP_100G_CR4_SET(an_tech_ability);
   2521 				} else {
   2522 					PHYMOD_AN_CAP_100G_KR4_SET(an_tech_ability);
   2523 				}
   2524 			}
   2525 			if (speed_full_duplex & SOC_PA_SPEED_40GB) {
   2526 				if (line_interface & (1 << SOC_PORT_IF_CR4)) {
   2527 					PHYMOD_AN_CAP_40G_CR4_SET(an_tech_ability);
   2528 				} else {
   2529 					PHYMOD_AN_CAP_40G_KR4_SET(an_tech_ability);
   2530 				}
   2531 			}			
   2532 		}
   2533     } else if (port_num_lanes == 2) {
   2534         if (ability->medium) {
   2535             if (speed_full_duplex & SOC_PA_SPEED_20GB) {
   2536                 if (ability->medium & SOC_PA_MEDIUM_BACKPLANE) {
   2537                     PHYMOD_BAM_CL73_CAP_20G_KR2_SET(an_bam73_ability);
   2538                 } else if (ability->medium & SOC_PA_MEDIUM_COPPER) {
   2539                     PHYMOD_BAM_CL73_CAP_20G_CR2_SET(an_bam73_ability);
   2540                 } else {
   2541                     PHYMOD_BAM_CL73_CAP_20G_KR2_SET(an_bam73_ability);
   2542                 }
   2543             }
   2544             if (speed_full_duplex & SOC_PA_SPEED_40GB) {
   2545                 if (ability->medium & SOC_PA_MEDIUM_BACKPLANE) {
   2546                     PHYMOD_BAM_CL73_CAP_40G_KR2_SET(an_bam73_ability);
   2547                 } else if (ability->medium & SOC_PA_MEDIUM_COPPER) {
   2548                     PHYMOD_BAM_CL73_CAP_40G_CR2_SET(an_bam73_ability);
   2549                 } else {
   2550                     PHYMOD_BAM_CL73_CAP_40G_KR2_SET(an_bam73_ability);
   2551                 }
   2552             }
   2553             if (speed_full_duplex & SOC_PA_SPEED_50GB) {
   2554                 if (ability->medium & SOC_PA_MEDIUM_BACKPLANE) {
   2555                     PHYMOD_BAM_CL73_CAP_50G_KR2_SET(an_bam73_ability);
   2556                 } else if (ability->medium & SOC_PA_MEDIUM_COPPER) {
   2557                     PHYMOD_BAM_CL73_CAP_50G_CR2_SET(an_bam73_ability);
   2558                 } else {
   2559                     PHYMOD_BAM_CL73_CAP_50G_KR2_SET(an_bam73_ability);
   2560                 }
   2561             }			
   2562 		} else {
   2563 			if(speed_full_duplex & SOC_PA_SPEED_20GB) {
   2564 				/* need to fix CR2 bit shift issue */
   2565 				if (line_interface & PHY8806X_IF_CR2) {
   2566 					PHYMOD_BAM_CL73_CAP_20G_CR2_SET(an_bam73_ability);
   2567 				} else {
   2568 					PHYMOD_BAM_CL73_CAP_20G_KR2_SET(an_bam73_ability);
   2569 				}
   2570 			}
   2571 			if(speed_full_duplex & SOC_PA_SPEED_40GB) {
   2572 				/* need to fix CR2 bit shift issue */
   2573 				if (line_interface & PHY8806X_IF_CR2) {
   2574 					PHYMOD_BAM_CL73_CAP_40G_CR2_SET(an_bam73_ability);
   2575 				} else {
   2576 					PHYMOD_BAM_CL73_CAP_40G_KR2_SET(an_bam73_ability);
   2577 				}
   2578 			}
   2579 			if(speed_full_duplex & SOC_PA_SPEED_50GB) {
   2580 				/* need to fix CR2 bit shift issue */
   2581 				if (line_interface & PHY8806X_IF_CR2) {
   2582 					PHYMOD_BAM_CL73_CAP_50G_CR2_SET(an_bam73_ability);
   2583 				} else {
   2584 					PHYMOD_BAM_CL73_CAP_50G_KR2_SET(an_bam73_ability);
   2585 				}
   2586 			}
   2587 		}
   2588     } else {
   2589         if ((ability->medium || ability->channel)) {
   2590             if (speed_full_duplex & SOC_PA_SPEED_25GB) {
   2591                 if (ability->medium & SOC_PA_MEDIUM_BACKPLANE) {
   2592                     /* When in MSA AN mode : We do not want to populate the base page with IEEE mode. 
   2593                      * If we do, then IEEE takes the higher priority. Hence we add the following exception
   2594                      * block for each 25G case below: if(pCfg->cl73an!=PHY8806X_MSA)  */
   2595                     if (pCfg->cl73an != PHY8806X_MSA) {
   2596                        if (ability->channel & SOC_PA_CHANNEL_SHORT) {
   2597                             PHYMOD_AN_CAP_25G_KRS1_SET(an_tech_ability);
   2598                        } else {
   2599                             PHYMOD_AN_CAP_25G_KR1_SET(an_tech_ability);
   2600                        }
   2601                     }
   2602                     PHYMOD_BAM_CL73_CAP_25G_KR1_SET(an_bam73_ability);
   2603                 } else if (ability->medium & SOC_PA_MEDIUM_COPPER) {
   2604                     if (pCfg->cl73an != PHY8806X_MSA) {
   2605                         if (ability->channel & SOC_PA_CHANNEL_SHORT) {
   2606                             PHYMOD_AN_CAP_25G_CRS1_SET(an_tech_ability);
   2607                         } else {
   2608                             PHYMOD_AN_CAP_25G_CR1_SET(an_tech_ability);
   2609                         }
   2610                     }
   2611                     PHYMOD_BAM_CL73_CAP_25G_CR1_SET(an_bam73_ability);
   2612                 } else {
   2613                     if (pCfg->cl73an != PHY8806X_MSA) {
   2614                         if (ability->channel & SOC_PA_CHANNEL_SHORT) {
   2615                             PHYMOD_AN_CAP_25G_KRS1_SET(an_tech_ability);
   2616                         } else {
   2617                             PHYMOD_AN_CAP_25G_KR1_SET(an_tech_ability);
   2618                         }
   2619                     }
   2620                     PHYMOD_BAM_CL73_CAP_25G_KR1_SET(an_bam73_ability);
   2621                 }
   2622             }
   2623             if (speed_full_duplex & SOC_PA_SPEED_10GB) {
   2624                 PHYMOD_AN_CAP_10G_KR_SET(an_tech_ability);
   2625             }
   2626             if (speed_full_duplex & SOC_PA_SPEED_1000MB) {
   2627                 PHYMOD_AN_CAP_1G_KX_SET(an_tech_ability);
   2628             }	
   2629 		} else {
   2630 			if(speed_full_duplex & SOC_PA_SPEED_25GB) {
   2631 				if (line_interface & (1 << SOC_PORT_IF_CR)) {
   2632 					/* next check if just CL73 or Cl73BAM */
   2633 					PHYMOD_AN_CAP_25G_CR1_SET(an_tech_ability);
   2634 					PHYMOD_BAM_CL73_CAP_25G_CR1_SET(an_bam73_ability);
   2635 				} else {
   2636 					/* next check if just CL73 or Cl73BAM */
   2637 					PHYMOD_AN_CAP_25G_KR1_SET(an_tech_ability);
   2638 					PHYMOD_BAM_CL73_CAP_25G_KR1_SET(an_bam73_ability);
   2639 				}
   2640 			}
   2641 		}
   2642     }
   2643 
   2644    if (port_num_lanes == 4) {          /* 4 lanes */
   2645         if(speed_full_duplex & SOC_PA_SPEED_40GB)
   2646             PHYMOD_BAM_CL37_CAP_40G_SET(an_bam37_ability);
   2647     } else if (port_num_lanes == 2) {     /* 2 lanes */
   2648         if(speed_full_duplex & SOC_PA_SPEED_20GB){
   2649             PHYMOD_BAM_CL37_CAP_20G_X2_SET(an_bam37_ability);
   2650             PHYMOD_BAM_CL37_CAP_20G_X2_CX4_SET(an_bam37_ability);
   2651         }
   2652     } else {                              /* 1 lane */
   2653         if (speed_full_duplex & SOC_PA_SPEED_10GB) {
   2654             PHYMOD_AN_CAP_10G_KR_SET(an_tech_ability);
   2655            PHYMOD_AN_CAP_10G_KR_SET(an_tech_ability);
   2656         }
   2657         if (speed_full_duplex & SOC_PA_SPEED_1000MB) {
   2658             PHYMOD_AN_CAP_1G_KX_SET(an_tech_ability);
   2659         }
   2660     }
   2661     phymod_autoneg_ability.an_cap = an_tech_ability;
   2662     phymod_autoneg_ability.cl73bam_cap = an_bam73_ability; 
   2663     phymod_autoneg_ability.cl37bam_cap = an_bam37_ability; 
   2664 
   2665 
   2666     PHYMOD_AN_CAP_SYMM_PAUSE_CLR(&phymod_autoneg_ability);
   2667     PHYMOD_AN_CAP_ASYM_PAUSE_CLR(&phymod_autoneg_ability);
   2668 
   2669     switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) {
   2670     case SOC_PA_PAUSE_TX:
   2671         PHYMOD_AN_CAP_ASYM_PAUSE_SET(&phymod_autoneg_ability);
   2672         break;
   2673     case SOC_PA_PAUSE_RX:
   2674         /* an_adv |= MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE; */
   2675         PHYMOD_AN_CAP_ASYM_PAUSE_SET(&phymod_autoneg_ability);
   2676         PHYMOD_AN_CAP_SYMM_PAUSE_SET(&phymod_autoneg_ability);
   2677         break;
   2678     case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX:
   2679         PHYMOD_AN_CAP_SYMM_PAUSE_SET(&phymod_autoneg_ability);
   2680         break;
   2681     }
   2682 
   2683     /* also set the sgmii speed */
   2684     phymod_autoneg_ability.sgmii_speed = phymod_CL37_SGMII_1000M;
   2685 
   2686     /* next check if we need to set cl37 attribute */
   2687     if (pCfg->an_cl72) {
   2688         phymod_autoneg_ability.an_cl72 = 1;
   2689     }
   2690     if (pCfg->hg_mode) {
   2691         phymod_autoneg_ability.an_hg2 = 1;
   2692     }
   2693 
   2694     /*next need to check FEC ability */
   2695     if (ability->fec == SOC_PA_FEC_NONE) {
   2696         PHYMOD_AN_FEC_OFF_SET(phymod_autoneg_ability.an_fec);
   2697     } else {
   2698         if (ability->fec & SOC_PA_FEC_CL74)
   2699             PHYMOD_AN_FEC_CL74_SET(phymod_autoneg_ability.an_fec);
   2700         if (ability->fec & SOC_PA_FEC_CL91)
   2701             PHYMOD_AN_FEC_CL91_SET(phymod_autoneg_ability.an_fec);
   2702     }
   2703     
   2704     if (pCfg->an_fec == 1)
   2705         PHYMOD_AN_FEC_CL74_SET(phymod_autoneg_ability.an_fec);
   2706     else if (pCfg->an_fec == 2)
   2707         PHYMOD_AN_FEC_CL91_SET(phymod_autoneg_ability.an_fec);
   2708 
   2709     SOC_IF_ERROR_RETURN
   2710         (phymod_phy_autoneg_ability_set(&phy->pm_phy, &phymod_autoneg_ability));
   2711 
   2712     pc->fiber.advert_ability = *ability;
   2713 
   2714     speed_config = &(pCfg->speed_config);
   2715     if (speed_config->an_fec)
   2716         pc->fiber.advert_ability.fec = 1;
   2717     else
   2718         pc->fiber.advert_ability.fec = 0;
   2719 
   2720     return SOC_E_NONE;
   2721 }
   2722 
   2723 /*
   2724  * Function:
   2725  *      phy_8806x_ability_advert_get
   2726  * Purpose:
   2727  *      Get the current advertisement for auto-negotiation.
   2728  * Parameters:
   2729  *      unit - BCM unit number.
   2730  *      port - Port number.
   2731  *      ability - (OUT) Port mode mask indicating supported options/speeds.
   2732  * Returns:
   2733  *      SOC_E_XXX
   2734  * Notes:
   2735  *      The advertisement is retrieved for the ACTIVE medium.
   2736  *      No synchronization performed at this level.
   2737  */
   2738 
   2739 STATIC int
   2740 phy_8806x_ability_advert_get(int unit, soc_port_t port,
   2741                               soc_port_ability_t *ability)
   2742 {
   2743     phy_ctrl_t                *pc;
   2744     soc_phymod_ctrl_t         *pmc;
   2745     soc_phymod_phy_t          *phy;
   2746     int                       reg37_ability;
   2747     int                       reg73_ability;
   2748     int                       reg73bam_ability;
   2749     int                       reg_ability;
   2750     _shr_port_mode_t          speed_full_duplex;
   2751     phymod_autoneg_ability_t  phymod_autoneg_ability;
   2752 
   2753     /* locate phy control */
   2754     pc = EXT_PHY_SW_STATE(unit, port);
   2755     if (pc == NULL) {
   2756         return SOC_E_INTERNAL;
   2757     }
   2758 
   2759 #if defined(INCLUDE_FCMAP) 
   2760     if (pc->fcmap_enable) {
   2761         ability->pause |= SOC_PA_PAUSE_TX;
   2762         ability->pause |= SOC_PA_PAUSE_RX;
   2763         return SOC_E_NONE;
   2764     }
   2765 #endif
   2766 
   2767     pmc = &pc->phymod_ctrl;
   2768 
   2769     /* only get abilities from the first core */
   2770     phy = pmc->phy[0];
   2771     if (phy == NULL) {
   2772         return SOC_E_INTERNAL;
   2773     }
   2774 
   2775     phymod_autoneg_ability_t_init(&phymod_autoneg_ability);
   2776     SOC_IF_ERROR_RETURN
   2777         (phymod_phy_autoneg_ability_get(&phy->pm_phy, &phymod_autoneg_ability));
   2778 
   2779 
   2780     speed_full_duplex = 0;
   2781 
   2782     /* retrieve CL73 abilities */
   2783     reg73_ability = phymod_autoneg_ability.an_cap;
   2784    speed_full_duplex|= PHYMOD_AN_CAP_100G_CR4_GET(reg73_ability) ?SOC_PA_SPEED_100GB:0;
   2785     speed_full_duplex|= PHYMOD_AN_CAP_100G_KR4_GET(reg73_ability) ?SOC_PA_SPEED_100GB:0;
   2786     speed_full_duplex|= PHYMOD_AN_CAP_40G_CR4_GET(reg73_ability) ?SOC_PA_SPEED_40GB:0;
   2787     speed_full_duplex|= PHYMOD_AN_CAP_40G_KR4_GET(reg73_ability) ?SOC_PA_SPEED_40GB:0;
   2788     speed_full_duplex|= PHYMOD_AN_CAP_10G_KR_GET(reg73_ability)  ?SOC_PA_SPEED_10GB:0;
   2789     speed_full_duplex|= PHYMOD_AN_CAP_10G_KX4_GET(reg73_ability) ?SOC_PA_SPEED_10GB:0;
   2790     speed_full_duplex|= PHYMOD_AN_CAP_1G_KX_GET(reg73_ability)   ?SOC_PA_SPEED_1000MB:0;
   2791    speed_full_duplex|= PHYMOD_AN_CAP_25G_CR1_GET(reg73_ability) ?SOC_PA_SPEED_25GB:0;
   2792    speed_full_duplex|= PHYMOD_AN_CAP_25G_KR1_GET(reg73_ability) ?SOC_PA_SPEED_25GB:0;
   2793    
   2794     /* retrieve CL73bam abilities */
   2795     reg73bam_ability = phymod_autoneg_ability.cl73bam_cap;
   2796     speed_full_duplex|= PHYMOD_BAM_CL73_CAP_20G_CR2_GET(reg73bam_ability) ?SOC_PA_SPEED_20GB:0;
   2797     speed_full_duplex|= PHYMOD_BAM_CL73_CAP_20G_KR2_GET(reg73bam_ability) ?SOC_PA_SPEED_20GB:0;
   2798     speed_full_duplex|= PHYMOD_BAM_CL73_CAP_40G_CR2_GET(reg73bam_ability) ?SOC_PA_SPEED_40GB:0;
   2799     speed_full_duplex|= PHYMOD_BAM_CL73_CAP_40G_KR2_GET(reg73bam_ability) ?SOC_PA_SPEED_40GB:0;
   2800     speed_full_duplex|= PHYMOD_BAM_CL73_CAP_50G_CR2_GET(reg73bam_ability) ?SOC_PA_SPEED_50GB:0;
   2801     speed_full_duplex|= PHYMOD_BAM_CL73_CAP_50G_KR2_GET(reg73bam_ability) ?SOC_PA_SPEED_50GB:0;
   2802    speed_full_duplex|= PHYMOD_BAM_CL73_CAP_25G_CR1_GET(reg73bam_ability) ?SOC_PA_SPEED_25GB:0;
   2803    speed_full_duplex|= PHYMOD_BAM_CL73_CAP_25G_KR1_GET(reg73bam_ability) ?SOC_PA_SPEED_25GB:0;
   2804    
   2805     /* retrieve CL37 abilities */
   2806     reg37_ability = phymod_autoneg_ability.cl37bam_cap;
   2807     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_40G_GET(reg37_ability) ? SOC_PA_SPEED_40GB:0;
   2808     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_25P455G_GET(reg37_ability) ?    SOC_PA_SPEED_25GB:0;
   2809     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X2_CX4_GET(reg37_ability)? SOC_PA_SPEED_20GB:0;
   2810     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X2_GET(reg37_ability)?     SOC_PA_SPEED_20GB:0;
   2811     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X4_GET(reg37_ability)?     SOC_PA_SPEED_20GB:0;
   2812     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X4_CX4_GET(reg37_ability)? SOC_PA_SPEED_20GB:0;
   2813     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_10G_X2_CX4_GET(reg37_ability)? SOC_PA_SPEED_10GB:0;
   2814     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_10G_DXGXS_GET(reg37_ability)?  SOC_PA_SPEED_10GB:0;
   2815     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_10G_CX4_GET(reg37_ability)?    SOC_PA_SPEED_10GB:0;
   2816 
   2817     /* retrieve "pause" abilities */
   2818     reg_ability = phymod_autoneg_ability.capabilities;
   2819 
   2820     ability->pause = 0;
   2821     if (reg_ability == PHYMOD_AN_CAP_ASYM_PAUSE) {
   2822         ability->pause = SOC_PA_PAUSE_TX;
   2823     } else if (reg_ability == (PHYMOD_AN_CAP_SYMM_PAUSE|PHYMOD_AN_CAP_ASYM_PAUSE)) {
   2824         ability->pause = SOC_PA_PAUSE_RX;
   2825     } else if (reg_ability == PHYMOD_AN_CAP_SYMM_PAUSE) {
   2826         ability->pause = (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX);
   2827     }
   2828 
   2829     ability->speed_full_duplex = speed_full_duplex;
   2830     ability->encap = SOC_PA_ENCAP_IEEE | SOC_PA_ENCAP_HIGIG | SOC_PA_ENCAP_HIGIG2;
   2831     if (PHYMOD_AN_CAP_25G_KRS1_GET(reg73_ability) || PHYMOD_AN_CAP_25G_CRS1_GET(reg73_ability)) {
   2832         ability->channel = SOC_PA_CHANNEL_SHORT;
   2833     } else {
   2834         ability->channel = SOC_PA_CHANNEL_LONG;
   2835     }
   2836     if (PHYMOD_AN_CAP_100G_CR4_GET(reg73_ability) || PHYMOD_AN_CAP_40G_CR4_GET(reg73_ability)  ||
   2837         PHYMOD_AN_CAP_25G_CR1_GET(reg73_ability)  || PHYMOD_AN_CAP_25G_CRS1_GET(reg73_ability) ||
   2838         PHYMOD_BAM_CL73_CAP_20G_CR2_GET(reg73bam_ability)  || PHYMOD_BAM_CL73_CAP_40G_CR2_GET(reg73bam_ability) ||
   2839         PHYMOD_BAM_CL73_CAP_50G_CR2_GET(reg73bam_ability)  || PHYMOD_BAM_CL73_CAP_25G_CR1_GET(reg73bam_ability) ||
   2840         PHYMOD_BAM_CL73_CAP_50G_CR4_GET(reg73bam_ability)) {
   2841         ability->medium = SOC_PA_MEDIUM_COPPER;
   2842     } else {
   2843         ability->medium = SOC_PA_MEDIUM_BACKPLANE;
   2844     }
   2845 
   2846     ability->fec = 0;
   2847     if (PHYMOD_AN_FEC_OFF_GET(phymod_autoneg_ability.an_fec)) {
   2848         ability->fec = SOC_PA_FEC_NONE;
   2849     } else {
   2850         if (PHYMOD_AN_FEC_CL74_GET(phymod_autoneg_ability.an_fec)) {
   2851             ability->fec |= SOC_PA_FEC_CL74;
   2852         }
   2853         if (PHYMOD_AN_FEC_CL91_GET(phymod_autoneg_ability.an_fec)) {
   2854             ability->fec |= SOC_PA_FEC_CL91;
   2855         }
   2856     }
   2857 
   2858     return SOC_E_NONE;
   2859 }
   2860 
   2861 /*
   2862  * Function:
   2863  *      phy_8806x_ability_remote_get
   2864  * Purpose:
   2865  *      Get the current advertisement for auto-negotiation.
   2866  * Parameters:
   2867  *      unit - BCM unit number.
   2868  *      port - Port number.
   2869  *      ability - (OUT) Port mode mask indicating supported options/speeds.
   2870  * Returns:
   2871  *      SOC_E_XXX
   2872  * Notes:
   2873  *      The advertisement is retrieved for the ACTIVE medium.
   2874  *      No synchronization performed at this level.
   2875  */
   2876 
   2877 STATIC int
   2878 phy_8806x_ability_remote_get(int unit, soc_port_t port,
   2879                                soc_port_ability_t *ability)
   2880 {
   2881     phy_ctrl_t                *pc;
   2882     soc_phymod_ctrl_t         *pmc;
   2883     soc_phymod_phy_t          *phy;
   2884     int                       reg73_ability;
   2885     int                       reg73bam_ability;
   2886     int                       reg37_ability;
   2887     int                       reg_ability;
   2888     _shr_port_mode_t          speed_full_duplex;
   2889     phymod_autoneg_ability_t  phymod_autoneg_ability; 
   2890 
   2891     /* locate phy control */
   2892     pc = EXT_PHY_SW_STATE(unit, port);
   2893     if (pc == NULL) {
   2894         return SOC_E_INTERNAL;
   2895     }
   2896 
   2897 #if defined(INCLUDE_FCMAP)
   2898     if (pc->fcmap_enable) {
   2899         ability->pause |= SOC_PA_PAUSE_TX;
   2900         ability->pause |= SOC_PA_PAUSE_RX;
   2901         return SOC_E_NONE;
   2902     }
   2903 #endif
   2904 
   2905     pmc = &pc->phymod_ctrl;
   2906 
   2907     /* only get abilities from the first core */
   2908     phy = pmc->phy[0];
   2909     if (phy == NULL) {
   2910         return SOC_E_INTERNAL;
   2911     }
   2912 
   2913     phymod_autoneg_ability_t_init(&phymod_autoneg_ability);
   2914     SOC_IF_ERROR_RETURN
   2915         (phymod_phy_autoneg_remote_ability_get(&phy->pm_phy, &phymod_autoneg_ability));
   2916 
   2917     speed_full_duplex = 0;
   2918 
   2919     /* retrieve CL73 abilities */
   2920     reg73_ability = phymod_autoneg_ability.an_cap;
   2921     speed_full_duplex|= PHYMOD_AN_CAP_100G_CR4_GET(reg73_ability) ?SOC_PA_SPEED_100GB:0;
   2922     speed_full_duplex|= PHYMOD_AN_CAP_100G_KR4_GET(reg73_ability) ?SOC_PA_SPEED_100GB:0;
   2923     speed_full_duplex|= PHYMOD_AN_CAP_40G_CR4_GET(reg73_ability) ?SOC_PA_SPEED_40GB:0;
   2924     speed_full_duplex|= PHYMOD_AN_CAP_40G_KR4_GET(reg73_ability) ?SOC_PA_SPEED_40GB:0;
   2925     speed_full_duplex|= PHYMOD_AN_CAP_10G_KR_GET(reg73_ability)  ?SOC_PA_SPEED_10GB:0;
   2926     speed_full_duplex|= PHYMOD_AN_CAP_10G_KX4_GET(reg73_ability) ?SOC_PA_SPEED_10GB:0;
   2927     speed_full_duplex|= PHYMOD_AN_CAP_1G_KX_GET(reg73_ability)   ?SOC_PA_SPEED_1000MB:0;
   2928    speed_full_duplex|= PHYMOD_AN_CAP_25G_CR1_GET(reg73_ability) ?SOC_PA_SPEED_25GB:0;
   2929    speed_full_duplex|= PHYMOD_AN_CAP_25G_KR1_GET(reg73_ability) ?SOC_PA_SPEED_25GB:0;
   2930    
   2931     /* retrieve CL73bam abilities */
   2932     reg73bam_ability = phymod_autoneg_ability.cl73bam_cap;
   2933     speed_full_duplex|= PHYMOD_BAM_CL73_CAP_20G_CR2_GET(reg73bam_ability) ?SOC_PA_SPEED_20GB:0;
   2934     speed_full_duplex|= PHYMOD_BAM_CL73_CAP_20G_KR2_GET(reg73bam_ability) ?SOC_PA_SPEED_20GB:0;
   2935     speed_full_duplex|= PHYMOD_BAM_CL73_CAP_40G_CR2_GET(reg73bam_ability) ?SOC_PA_SPEED_40GB:0;
   2936     speed_full_duplex|= PHYMOD_BAM_CL73_CAP_40G_KR2_GET(reg73bam_ability) ?SOC_PA_SPEED_40GB:0;
   2937     speed_full_duplex|= PHYMOD_BAM_CL73_CAP_50G_CR2_GET(reg73bam_ability) ?SOC_PA_SPEED_50GB:0;
   2938     speed_full_duplex|= PHYMOD_BAM_CL73_CAP_50G_KR2_GET(reg73bam_ability) ?SOC_PA_SPEED_50GB:0;
   2939    speed_full_duplex|= PHYMOD_BAM_CL73_CAP_25G_CR1_GET(reg73bam_ability) ?SOC_PA_SPEED_25GB:0;
   2940    speed_full_duplex|= PHYMOD_BAM_CL73_CAP_25G_KR1_GET(reg73bam_ability) ?SOC_PA_SPEED_25GB:0;
   2941    speed_full_duplex|= PHYMOD_BAM_CL73_CAP_20G_CR1_GET(reg73bam_ability) ?SOC_PA_SPEED_20GB:0;
   2942    speed_full_duplex|= PHYMOD_BAM_CL73_CAP_20G_KR1_GET(reg73bam_ability) ?SOC_PA_SPEED_20GB:0;
   2943    
   2944     /* retrieve CL37 abilities */
   2945     reg37_ability = phymod_autoneg_ability.cl37bam_cap;
   2946     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_40G_GET(reg37_ability) ? SOC_PA_SPEED_40GB:0;
   2947     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_25P455G_GET(reg37_ability) ?    SOC_PA_SPEED_25GB:0;
   2948     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X2_CX4_GET(reg37_ability)? SOC_PA_SPEED_20GB:0;
   2949     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X2_GET(reg37_ability)?     SOC_PA_SPEED_20GB:0;
   2950     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X4_GET(reg37_ability)?     SOC_PA_SPEED_20GB:0;
   2951     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X4_CX4_GET(reg37_ability)? SOC_PA_SPEED_20GB:0;
   2952     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_10G_X2_CX4_GET(reg37_ability)? SOC_PA_SPEED_10GB:0;
   2953     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_10G_DXGXS_GET(reg37_ability)?  SOC_PA_SPEED_10GB:0;
   2954     speed_full_duplex|= PHYMOD_BAM_CL37_CAP_10G_CX4_GET(reg37_ability)?    SOC_PA_SPEED_10GB:0;
   2955 
   2956     if (PHYMOD_AN_CAP_25G_KRS1_GET(reg73_ability) || PHYMOD_AN_CAP_25G_CRS1_GET(reg73_ability)) {
   2957         ability->channel |= SOC_PA_CHANNEL_SHORT;
   2958     } else {
   2959         ability->channel |= SOC_PA_CHANNEL_LONG;
   2960     }
   2961     if (PHYMOD_AN_CAP_100G_CR4_GET(reg73_ability) || PHYMOD_AN_CAP_40G_CR4_GET(reg73_ability)  ||
   2962         PHYMOD_AN_CAP_25G_CR1_GET(reg73_ability)  || PHYMOD_AN_CAP_25G_CRS1_GET(reg73_ability) ||
   2963         PHYMOD_BAM_CL73_CAP_20G_CR2_GET(reg73bam_ability)  || PHYMOD_BAM_CL73_CAP_40G_CR2_GET(reg73bam_ability) ||
   2964         PHYMOD_BAM_CL73_CAP_50G_CR2_GET(reg73bam_ability)  || PHYMOD_BAM_CL73_CAP_25G_CR1_GET(reg73bam_ability) ||
   2965         PHYMOD_BAM_CL73_CAP_50G_CR4_GET(reg73bam_ability)) {
   2966         ability->medium = SOC_PA_MEDIUM_COPPER;
   2967     } else {
   2968         ability->medium = SOC_PA_MEDIUM_BACKPLANE;
   2969     }
   2970 	
   2971     /* retrieve "pause" abilities */
   2972     reg_ability = phymod_autoneg_ability.capabilities;
   2973 
   2974     ability->pause = 0;
   2975     if (reg_ability == PHYMOD_AN_CAP_ASYM_PAUSE) {
   2976         ability->pause = SOC_PA_PAUSE_TX;
   2977     } else if (reg_ability == (PHYMOD_AN_CAP_SYMM_PAUSE|PHYMOD_AN_CAP_ASYM_PAUSE)) {
   2978         ability->pause = SOC_PA_PAUSE_RX;
   2979     } else if (reg_ability == PHYMOD_AN_CAP_SYMM_PAUSE) {
   2980         ability->pause = (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX);
   2981     }
   2982 
   2983     ability->speed_full_duplex = speed_full_duplex;
   2984     ability->encap = SOC_PA_ENCAP_IEEE | SOC_PA_ENCAP_HIGIG | SOC_PA_ENCAP_HIGIG2;
   2985 
   2986     ability->fec = 0;
   2987     if (PHYMOD_AN_FEC_OFF_GET(phymod_autoneg_ability.an_fec)) {
   2988         ability->fec = SOC_PA_FEC_NONE;
   2989     } else {
   2990         if (PHYMOD_AN_FEC_CL74_GET(phymod_autoneg_ability.an_fec)) {
   2991             ability->fec |= SOC_PA_FEC_CL74;
   2992         }
   2993         if (PHYMOD_AN_FEC_CL91_GET(phymod_autoneg_ability.an_fec)) {
   2994             ability->fec |= SOC_PA_FEC_CL91;
   2995         }
   2996     }
   2997 
   2998     return SOC_E_NONE;
   2999 }
   3000 
   3001 /*
   3002  * Function:
   3003  *      phy_8806x_lb_set
   3004  * Purpose:
   3005  *      Enable/disable PHY loopback mode
   3006  * Parameters:
   3007  *      unit - BCM unit number.
   3008  *      port - Port number. 
   3009  *      enable - binary value for on/off (1/0)
   3010  * Returns:     
   3011  *      SOC_E_NONE
   3012  */
   3013 
   3014 STATIC int
   3015 phy_8806x_lb_set(int unit, soc_port_t port, int enable)
   3016 {
   3017     phy_ctrl_t* pc; 
   3018     soc_phymod_ctrl_t *pmc;
   3019     phymod_phy_access_t *pm_phy;
   3020     int idx=0;
   3021     phymod_loopback_mode_t lb_mode;
   3022 
   3023     pc = EXT_PHY_SW_STATE(unit, port);
   3024 
   3025     pmc = &pc->phymod_ctrl;
   3026 
   3027     pm_phy = &pmc->phy[idx]->pm_phy;
   3028 
   3029     if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) {
   3030         lb_mode = phymodLoopbackSysGlobal;
   3031         SOC_IF_ERROR_RETURN
   3032             (phymod_phy_loopback_set(pm_phy, lb_mode, enable));
   3033     } else {
   3034         lb_mode = phymodLoopbackGlobal;
   3035 #if defined(INCLUDE_FCMAP)
   3036         if (pc->fcmap_enable) {
   3037             lb_mode = phymodLoopbackGlobalPMD;
   3038         }
   3039 #endif
   3040         SOC_IF_ERROR_RETURN
   3041             (phymod_phy_loopback_set(pm_phy, lb_mode, enable));
   3042     }
   3043 
   3044     return (SOC_E_NONE);
   3045 }
   3046 
   3047 /*
   3048  * Function:
   3049  *      phy_8806x_lb_get
   3050  * Purpose:
   3051  *      Get current PHY loopback mode
   3052  * Parameters:
   3053  *      unit - BCM unit number.
   3054  *      port - Port number. 
   3055  *      enable - address of location to store binary value for on/off (1/0)
   3056  * Returns:     
   3057  *      SOC_E_NONE
   3058  */
   3059 STATIC int
   3060 phy_8806x_lb_get(int unit, soc_port_t port, int *enable)
   3061 {
   3062     phy_ctrl_t* pc; 
   3063     soc_phymod_ctrl_t *pmc;
   3064     phymod_phy_access_t *pm_phy;
   3065     uint32 lb_enable = 0;
   3066     int idx=0;
   3067 
   3068     pc = EXT_PHY_SW_STATE(unit, port);
   3069 #if defined(INCLUDE_FCMAP)
   3070     /* Skip for FC */
   3071     if (pc->fcmap_enable) {
   3072         return SOC_E_NONE;
   3073     }
   3074 #endif
   3075 
   3076     pmc = &pc->phymod_ctrl;
   3077 
   3078     *enable = 0;
   3079 
   3080     pm_phy = &pmc->phy[idx]->pm_phy;
   3081 
   3082     if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) {
   3083         SOC_IF_ERROR_RETURN
   3084             (phymod_phy_loopback_get(pm_phy, phymodLoopbackSysGlobal, &lb_enable));
   3085     } else {
   3086         SOC_IF_ERROR_RETURN
   3087             (phymod_phy_loopback_get(pm_phy, phymodLoopbackGlobal, &lb_enable));
   3088     }
   3089 
   3090     if (lb_enable) {
   3091         *enable = 1;
   3092     }
   3093      
   3094     return (SOC_E_NONE);
   3095 }
   3096 
   3097 /*
   3098  * Function:
   3099  *      phy_8806x_ability_local_get
   3100  * Purpose:
   3101  *      xx
   3102  * Parameters:
   3103  *      unit - BCM unit number.
   3104  *      port - Port number. 
   3105  *      ability - xx
   3106  * Returns:     
   3107  *      SOC_E_NONE
   3108  */
   3109 STATIC int
   3110 phy_8806x_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   3111 {
   3112     phy_ctrl_t          *pc; 
   3113     /* phy8806x_config_t   *pCfg; */
   3114 
   3115     pc = EXT_PHY_SW_STATE(unit, port);
   3116     /* pCfg = (phy8806x_config_t *) pc->driver_data; */
   3117 
   3118     if (NULL == ability) {
   3119         return SOC_E_PARAM;
   3120     }
   3121 
   3122     sal_memset(ability, 0, sizeof(*ability));
   3123 
   3124     ability->loopback  = SOC_PA_LB_PHY;
   3125     ability->medium    = SOC_PA_MEDIUM_FIBER | SOC_PA_MEDIUM_COPPER | SOC_PA_MEDIUM_BACKPLANE;
   3126     ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   3127     ability->fec       = SOC_PA_FEC_NONE |SOC_PA_FEC_CL74 | SOC_PA_FEC_CL91;
   3128     ability->flags     = SOC_PA_AUTONEG;
   3129 
   3130     if (IND_LANE_MODE(pc)) { 
   3131         ability->speed_full_duplex  = SOC_PA_SPEED_1000MB;
   3132         switch(pc->speed_max) {  /* must include all the supported speedss */
   3133             case 50000:
   3134                 ability->speed_full_duplex |= SOC_PA_SPEED_50GB;
   3135                 /* fall through */
   3136             case 40000:
   3137                 ability->speed_full_duplex |= SOC_PA_SPEED_40GB;
   3138                 /* fall through */                
   3139             case 25000:
   3140                 ability->speed_full_duplex |= SOC_PA_SPEED_25GB;
   3141                 /* fall through */
   3142             case 20000:
   3143                 ability->speed_full_duplex |= SOC_PA_SPEED_20GB;
   3144                 /* fall through */
   3145             case 10000:
   3146                 ability->speed_full_duplex |= SOC_PA_SPEED_10GB;
   3147                 /* fall through */
   3148             default:
   3149                 break;
   3150         }
   3151         ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   3152         ability->interface = SOC_PA_INTF_GMII | SOC_PA_INTF_SGMII;
   3153     } else {
   3154         ability->speed_half_duplex  = SOC_PA_ABILITY_NONE;
   3155         ability->speed_full_duplex  = SOC_PA_SPEED_1000MB;
   3156         switch(pc->speed_max) {
   3157             case 106000:
   3158                 ability->speed_full_duplex |= SOC_PA_SPEED_106GB;
   3159             /* Fall through */
   3160             case 100000:
   3161                 ability->speed_full_duplex |= SOC_PA_SPEED_100GB;
   3162             /* Fall through */
   3163             case 40000:
   3164                 ability->speed_full_duplex |= SOC_PA_SPEED_40GB;
   3165             /* Fall through */
   3166             default:
   3167                 ability->speed_full_duplex |= SOC_PA_SPEED_10GB;
   3168                 break; 
   3169         }
   3170         ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   3171         ability->interface = SOC_PA_INTF_XGMII;
   3172         ability->loopback  = SOC_PA_LB_PHY;
   3173         ability->flags     = SOC_PA_AUTONEG;
   3174     }
   3175 
   3176     return (SOC_E_NONE);
   3177 }
   3178 
   3179 /*
   3180  * Function:
   3181  *      phy_8806x_firmware_set
   3182  * Purpose:
   3183  *      xx
   3184  * Parameters:
   3185  *      unit - BCM unit number.
   3186  *      port - Port number. 
   3187 
   3188  * Returns:     
   3189  *      SOC_E_NONE
   3190  */
   3191 
   3192 
   3193 STATIC int
   3194 phy_8806x_firmware_set(int unit, int port, int offset, uint8 *data,int len)
   3195 {
   3196     phy_ctrl_t *pc;
   3197     int dividend, divisor, rv = SOC_E_FAIL;
   3198     uint32 temp32;
   3199     uint16 temp16;
   3200     uint16 status_l = 0, status_s = 0;
   3201 
   3202     pc = EXT_PHY_SW_STATE(unit, port);
   3203 
   3204     if (data) {
   3205         return SOC_E_FAIL;
   3206     }
   3207 
   3208     switch (offset) {
   3209         case PHYCTRL_UCODE_BCST_SETUP:
   3210             /* Turn on broadcast mode */
   3211 
   3212         if ( FLAGS(pc) & PHY8806X_BMP0 ) {
   3213             /* a.)  bring all mHosts out of reset */
   3214             SOC_IF_ERROR_RETURN
   3215                 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32));
   3216 
   3217                 temp32 &= ~0x40000015;
   3218                 /* temp32 |= (0xf << 6); */ /* RTS0 */
   3219                 temp32 |= ((0xf << 6) | (0xff << 14)); /* RTS0 + SRAM0 */
   3220 
   3221             SOC_IF_ERROR_RETURN
   3222                 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   3223 
   3224                 /* temp32 &= ~(0xf << 6); */
   3225                 temp32 &= ~((0xf << 6) | (0xff << 14));
   3226 
   3227                 temp32 |= 0x40000015;
   3228             SOC_IF_ERROR_RETURN
   3229                 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   3230             /* b.) make sure that PLLs are locked */
   3231 
   3232 
   3233 
   3234             /* c.) place all mHosts in reset */
   3235             SOC_IF_ERROR_RETURN
   3236                 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32));
   3237                 temp32 |= (0xf << 6);
   3238             SOC_IF_ERROR_RETURN
   3239                 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   3240 
   3241             /* d.) e.) combined together */
   3242             SOC_IF_ERROR_RETURN
   3243                 (READ_TOP_RTS_MISC_CTRL_REG(unit, pc, &temp32));
   3244                 temp32 &= ~0xff;
   3245                 if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) {
   3246                     temp32 |= (0x3 << ((pc->phy_id & 0x3) << 1));
   3247                 }
   3248             SOC_IF_ERROR_RETURN
   3249                 (WRITE_TOP_RTS_MISC_CTRL_REG(unit, pc, temp32));
   3250 
   3251             /* f.)  bring all mHosts out of reset */
   3252             SOC_IF_ERROR_RETURN
   3253                 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32));
   3254                 temp32 &= ~(0xf << 6);
   3255             SOC_IF_ERROR_RETURN
   3256                 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   3257 
   3258 
   3259             if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) {
   3260                 /* g.) */
   3261                 SOC_IF_ERROR_RETURN
   3262                     (MODIFY_PHY8806X_AXI_CONTROL_F0_REG(unit, pc, (1U << 9), (1U << 9)));
   3263 
   3264                 SOC_IF_ERROR_RETURN
   3265                     (WRITE_PHY8806X_AXI_ADDR_UPPER_F0_REG(unit, pc, 0x0026 + (pc->phy_id & 0x3) * 0x10));
   3266                 SOC_IF_ERROR_RETURN
   3267                     (WRITE_PHY8806X_AXI_ADDR_LOWER_F0_REG(unit, pc, 0x0000));
   3268             }
   3269 
   3270 #if defined(INCLUDE_FCMAP)
   3271             /* SDK-85976 : SW WAR for MONTREAL2-859 , only for A0*/
   3272             if (pc->fcmap_enable){
   3273                 if (PHY_IS_BCM8806X_A0(pc)) {
   3274                     SOC_IF_ERROR_RETURN
   3275                         (WRITE_LINE_FCPORT_EXT_TX_DISABLE_CTRL(unit, pc, 0));
   3276                 }
   3277             } else {
   3278                 SOC_IF_ERROR_RETURN
   3279                     (WRITE_LINE_FCPORT_EXT_TX_DISABLE_CTRL(unit, pc, 0xf));
   3280             }
   3281             if (pc->fcmap_enable) {
   3282                 SOC_IF_ERROR_RETURN
   3283                     (READ_TOP_SOFT_RESET_REG_2(unit, pc, &temp32));
   3284                 temp32 |= 0x115;
   3285                 SOC_IF_ERROR_RETURN
   3286                     (WRITE_TOP_SOFT_RESET_REG_2(unit, pc, temp32));
   3287             } else {
   3288                 SOC_IF_ERROR_RETURN
   3289                     (WRITE_TOP_SOFT_RESET_REG_2(unit, pc, 0x100));
   3290             }
   3291 #else
   3292             SOC_IF_ERROR_RETURN
   3293                 (WRITE_LINE_FCPORT_EXT_TX_DISABLE_CTRL(unit, pc, 0xf));
   3294             SOC_IF_ERROR_RETURN
   3295                 (WRITE_TOP_SOFT_RESET_REG_2(unit, pc, 0x100));
   3296 #endif
   3297 
   3298             SOC_IF_ERROR_RETURN
   3299                 (_pmd_enable(unit, pc, 0)); /* line */
   3300             SOC_IF_ERROR_RETURN
   3301                 (_pmd_enable(unit, pc, 1)); /* system */
   3302 
   3303         } else if ( FLAGS(pc) & PHY8806X_BMP1 ) {
   3304             /* a.) bring all mHosts out of reset */
   3305             SOC_IF_ERROR_RETURN
   3306                 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32));
   3307 
   3308                 temp32 &= ~0x8000002A;
   3309                 /* temp32 |= (0xf << 10); */ /* RTS1 */
   3310                 temp32 |= ((0xf << 10) | (0xff << 22)); /* RTS1 + SRAM1 */
   3311 
   3312             SOC_IF_ERROR_RETURN
   3313                 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   3314 
   3315                 /* temp32 &= ~(0xf << 10); */
   3316                 temp32 &= ~((0xf << 10) | (0xff << 22));
   3317                 temp32 |= 0x8000002A;
   3318 
   3319             SOC_IF_ERROR_RETURN
   3320                 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   3321             /* b.) make sure that PLLs are locked */
   3322 
   3323 
   3324 
   3325             /* c.) place all mHosts in reset */
   3326             SOC_IF_ERROR_RETURN
   3327                 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32));
   3328                 temp32 |= (0xf << 10);
   3329             SOC_IF_ERROR_RETURN
   3330                 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   3331 
   3332             /* d.) e.) combined together */
   3333             SOC_IF_ERROR_RETURN
   3334                 (READ_TOP_RTS_MISC_CTRL_REG(unit, pc, &temp32));
   3335                 temp32 &= ~0xff00;
   3336                 if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) {
   3337                     temp32 |= (0x3 << (((pc->phy_id & 0x3) << 1) + 8));
   3338                 }
   3339             SOC_IF_ERROR_RETURN
   3340                 (WRITE_TOP_RTS_MISC_CTRL_REG(unit, pc, temp32));
   3341 
   3342             /* f.) bring all mHosts out of reset */
   3343             SOC_IF_ERROR_RETURN
   3344                 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32));
   3345                 temp32 &= ~(0xf << 10);
   3346             SOC_IF_ERROR_RETURN
   3347                 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   3348 
   3349             if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) {
   3350                 /* g.) */
   3351                 SOC_IF_ERROR_RETURN
   3352                     (MODIFY_PHY8806X_AXI_CONTROL_F1_REG(unit, pc, (1U << 9), (1U << 9)));
   3353 
   3354                 SOC_IF_ERROR_RETURN
   3355                     (WRITE_PHY8806X_AXI_ADDR_UPPER_F1_REG(unit, pc, 0x0026 + (pc->phy_id & 0x3) * 0x10));
   3356                 SOC_IF_ERROR_RETURN
   3357                     (WRITE_PHY8806X_AXI_ADDR_LOWER_F1_REG(unit, pc, 0x0000));
   3358             }
   3359 #if defined(INCLUDE_FCMAP)
   3360             /* SDK-85976 : SW WAR for MONTREAL2-859 , only for A0*/
   3361             if (pc->fcmap_enable){
   3362                 if (PHY_IS_BCM8806X_A0(pc)) {
   3363                     SOC_IF_ERROR_RETURN
   3364                         (WRITE_LINE_FCPORT_EXT_TX_DISABLE_CTRL(unit, pc, 0));
   3365                 }
   3366             } else {
   3367                 SOC_IF_ERROR_RETURN
   3368                     (WRITE_LINE_FCPORT_EXT_TX_DISABLE_CTRL(unit, pc, 0xf));
   3369             }
   3370             if (pc->fcmap_enable) {
   3371                 SOC_IF_ERROR_RETURN
   3372                     (READ_TOP_SOFT_RESET_REG_2(unit, pc, &temp32));
   3373                 temp32 |= 0x115;
   3374                 SOC_IF_ERROR_RETURN
   3375                     (WRITE_TOP_SOFT_RESET_REG_2(unit, pc, temp32));
   3376             } else {
   3377                 SOC_IF_ERROR_RETURN
   3378                     (WRITE_TOP_SOFT_RESET_REG_2(unit, pc, 0x100));
   3379             }
   3380 #else
   3381             SOC_IF_ERROR_RETURN
   3382                 (WRITE_LINE_FCPORT_EXT_TX_DISABLE_CTRL(unit, pc, 0xf));
   3383             SOC_IF_ERROR_RETURN
   3384                 (WRITE_TOP_SOFT_RESET_REG_2(unit, pc, 0x100));
   3385 #endif
   3386 
   3387             SOC_IF_ERROR_RETURN
   3388                 (_pmd_enable(unit, pc, 0)); /* line */
   3389             SOC_IF_ERROR_RETURN
   3390                 (_pmd_enable(unit, pc, 1)); /* system */
   3391 
   3392         }
   3393             break;
   3394 
   3395         case PHYCTRL_UCODE_BCST_uC_SETUP:
   3396             break;
   3397         case PHYCTRL_UCODE_BCST_ENABLE:
   3398             if ( FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART) ) {
   3399                 break;
   3400             }
   3401             /* h.) */
   3402             if ( FLAGS(pc) & PHY8806X_FWDLM ) {
   3403                 SOC_IF_ERROR_RETURN
   3404                     (MODIFY_PHY8806X_MISC_CONTROL_REG(unit, pc, 0, (1U << 14)));
   3405             }
   3406 
   3407             if ( FLAGS(pc) & PHY8806X_CHM) {
   3408                 SOC_IF_ERROR_RETURN
   3409                     (MODIFY_PHY8806X_MISC_CONTROL_REG(unit, pc, (1U << 15), (1U << 15)));
   3410                 if ( FLAGS(pc) & PHY8806X_AC ) {
   3411                     if (DL_DIVIDEND(pc) && DL_DIVISOR(pc)) {
   3412                          rv = soc_cmic_rate_param_get(unit, &dividend, &divisor);
   3413                         if (SOC_SUCCESS(rv)) {
   3414                             rv = soc_cmic_rate_param_set(unit, DL_DIVIDEND(pc), DL_DIVISOR(pc));
   3415                         }
   3416                     }
   3417                     SOC_IF_ERROR_RETURN
   3418                         (_phy_8806x_write_to_arm(unit, pc, 0, FIRMWARE(pc), FIRMWARE_LEN(pc)));
   3419                     if (SOC_SUCCESS(rv)) {
   3420                         /* rv contains the return value of previous soc_cmic_rate_param_set() */
   3421                         SOC_IF_ERROR_RETURN
   3422                             (soc_cmic_rate_param_set(unit, dividend, divisor));
   3423                     }
   3424                 }
   3425             }
   3426 
   3427             break;
   3428 
   3429         case PHYCTRL_UCODE_BCST_LOAD:
   3430             if ( FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART) ) {
   3431                 break;
   3432             }
   3433             if (DL_DIVIDEND(pc) && DL_DIVISOR(pc)) {
   3434                  rv = soc_cmic_rate_param_get(unit, &dividend, &divisor);
   3435                 if (SOC_SUCCESS(rv)) {
   3436                     rv = soc_cmic_rate_param_set(unit, DL_DIVIDEND(pc), DL_DIVISOR(pc));
   3437                 }
   3438             }
   3439 
   3440             if ( FLAGS(pc) & PHY8806X_FWDLM ) {
   3441                SOC_IF_ERROR_RETURN
   3442                    (_phy_8806x_write_to_arm(unit, pc, 0, FIRMWARE(pc), FIRMWARE_LEN(pc)));
   3443             }
   3444             if (SOC_SUCCESS(rv)) {
   3445                 /* rv contains the return value of previous soc_cmic_rate_param_set() */
   3446                 SOC_IF_ERROR_RETURN
   3447                     (soc_cmic_rate_param_set(unit, dividend, divisor));
   3448             }
   3449             if ( FLAGS(pc) & (PHY8806X_BMP0 | PHY8806X_BMP1) ) {
   3450                 soc_timeout_init(&TO(pc), 35000000, 0);
   3451             }
   3452             break;
   3453 
   3454         case PHYCTRL_UCODE_BCST_END:
   3455             if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) {
   3456                 /* Turn off broadcast mode by reading the following reg. */
   3457                 if ( FLAGS(pc) & PHY8806X_CHM ) {
   3458                     SOC_IF_ERROR_RETURN
   3459                         (READ_PHY8806X_MISC_CONTROL_REG(unit, pc, &temp16));
   3460                 }
   3461 
   3462                 if ( FLAGS(pc) & PHY8806X_FWDLM ) {
   3463                     SOC_IF_ERROR_RETURN
   3464                         (MODIFY_PHY8806X_MISC_CONTROL_REG(unit, pc, (1U << 14), (1U << 14)));
   3465                 }
   3466             }
   3467 
   3468             if ( FLAGS(pc) & (PHY8806X_BMP0 | PHY8806X_BMP1) ) {
   3469                 SOC_IF_ERROR_RETURN
   3470                    (_pmd_disable(unit, pc, 0)); /* line */
   3471                 SOC_IF_ERROR_RETURN
   3472                    (_pmd_disable(unit, pc, 1)); /* system */
   3473 
   3474                 if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) {
   3475                     temp16 = 0;
   3476                     do {
   3477                         rv = READ_PHY8806X_FW_TO_SW_MESSAGE_REG(unit, pc, &temp16);
   3478                         if (temp16 | SOC_FAILURE(rv)) {
   3479                             break;
   3480                         }
   3481                     } while (!soc_timeout_check(&TO(pc)));
   3482 
   3483                         LOG_CLI((BSL_META_U(unit,
   3484                                 "PHY8806X_FW_TO_SW_MESSAGE_REG S : u=%d p=%d  status=%04x"
   3485                                 " !.\n"), unit, pc->port, temp16));
   3486                     if ((temp16 & 0x5000) != 0x5000) {
   3487                         LOG_CLI((BSL_META_U(unit,
   3488                                 "PHY8806X_FW_TO_SW_MESSAGE_REG failed: u=%d p=%d  status=%04x"
   3489                                 " !.\n"), unit, pc->port, temp16));
   3490                         /* return SOC_E_FAIL; */
   3491                     }
   3492                 }
   3493 
   3494                 temp32 = HOST2LE32(TOP_DEV_REV_ID(pc));
   3495 
   3496                 /*  Place the value in SRAM */
   3497                 SOC_IF_ERROR_RETURN
   3498                 (_phy_8806x_axi_write(unit, pc, 0x00100000 + 0x100 - 0x4, &temp32, 1));
   3499 
   3500                 /* Start PMDs */
   3501                 SOC_IF_ERROR_RETURN
   3502                     (_pmd_start(unit, pc, 0)); /* line */
   3503                 SOC_IF_ERROR_RETURN
   3504                     (_pmd_start(unit, pc, 1)); /* system */
   3505 
   3506                 /* Read the stored length and the CRC from SRAM */ 
   3507                 _phy_8806x_axi_read(unit, pc, 0x00100000, &temp32, 1);
   3508                 PMD_SIZE(pc) = LE2HOST32(temp32);
   3509                 _phy_8806x_axi_read(unit, pc, 0x00100004, &temp32, 1);
   3510                 PMD_CRC(pc) = LE2HOST32(temp32);
   3511 
   3512                 soc_timeout_init(&TO(pc), 5000000, 0); /* 5s timer */
   3513 
   3514                 do {
   3515 
   3516                     rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) + 1, 1, 0, 0xd03d, &status_l);
   3517                     if (SOC_FAILURE(rv)) {
   3518                         break;
   3519                     }
   3520                     rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) + 9, 1, 0, 0xd03d, &status_s);
   3521                     if (SOC_FAILURE(rv)) {
   3522                         break;
   3523                     }
   3524                     if ((status_l== 0x80) &&  (status_s == 0x80)) {
   3525                         break;
   3526                     }
   3527                 } while (!soc_timeout_check(&TO(pc)));
   3528 
   3529                if ( status_l != 0x80 ) {
   3530                     LOG_CLI((BSL_META_U(unit,
   3531                             "PHY8806X PMD (line) firmware not running: u=%d p=%d  status=%04x"
   3532                             " !.\n"), unit, pc->port, status_l));
   3533                } else {
   3534                     /* Issue command to compute CRC */
   3535                     _tsc_reg_write(unit, pc, 0, (pc->phy_id & 0x7) + 1, 1, 0, 0xd03e, PMD_SIZE(pc), 0);
   3536                     _tsc_reg_write(unit, pc, 0, (pc->phy_id & 0x7) + 1, 1, 0, 0xd03d, 0x14, 0);
   3537                }
   3538 
   3539                if ( status_s != 0x80 ) {
   3540                     LOG_CLI((BSL_META_U(unit,
   3541                             "PHY8806X PMD (sys)  firmware not running: u=%d p=%d  status=%04x"
   3542                             " !.\n"), unit, pc->port, status_s));
   3543                } else {
   3544                     /* Issue command to compute CRC */
   3545                     _tsc_reg_write(unit, pc, 0, (pc->phy_id & 0x7) + 9, 1, 0, 0xd03e, PMD_SIZE(pc), 0);
   3546                     _tsc_reg_write(unit, pc, 0, (pc->phy_id & 0x7) + 9, 1, 0, 0xd03d, 0x14, 0);
   3547                }
   3548 
   3549             }
   3550 
   3551             soc_timeout_init(&TO(pc), 5000000, 0); /* 5s timer */
   3552 
   3553             if ( FLAGS(pc) & PHY8806X_BMP0 ) {
   3554                 /* c.) place all mHosts in reset */
   3555                 SOC_IF_ERROR_RETURN
   3556                     (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32));
   3557                     temp32 |= (0xf << 6);
   3558                 SOC_IF_ERROR_RETURN
   3559                     (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   3560 
   3561                 /* d.) e.) combined together */
   3562                 SOC_IF_ERROR_RETURN
   3563                     (READ_TOP_RTS_MISC_CTRL_REG(unit, pc, &temp32));
   3564                     temp32 &= ~0xff;
   3565                     if (!( FLAGS(pc) & PHY8806X_PM )) {
   3566                         temp32 |= (0x2 << ((pc->phy_id & 0x3) << 1));
   3567                     }
   3568                 SOC_IF_ERROR_RETURN
   3569                     (WRITE_TOP_RTS_MISC_CTRL_REG(unit, pc, temp32));
   3570 
   3571                 /* f.) Release all mHosts from reset, Only BMP will run. Others halted.
   3572                        In PM all will be halted. */
   3573                 SOC_IF_ERROR_RETURN
   3574                     (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32));
   3575                     temp32 &= ~(0xf << 6);
   3576                 SOC_IF_ERROR_RETURN
   3577                     (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   3578 
   3579             } else if ( FLAGS(pc) & PHY8806X_BMP1 ) {
   3580                 /* c.) place all mHosts in reset */
   3581                 SOC_IF_ERROR_RETURN
   3582                     (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32));
   3583                     temp32 |= (0xf << 10);
   3584                 SOC_IF_ERROR_RETURN
   3585                     (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   3586 
   3587                 /* d.) e.) combined together */
   3588                 SOC_IF_ERROR_RETURN
   3589                     (READ_TOP_RTS_MISC_CTRL_REG(unit, pc, &temp32));
   3590                     temp32 &= ~0xff00;
   3591                     if (!( FLAGS(pc) & PHY8806X_PM )) {
   3592                         temp32 |= (0x2 << (((pc->phy_id & 0x3) << 1) + 8));
   3593                     }
   3594                 SOC_IF_ERROR_RETURN
   3595                     (WRITE_TOP_RTS_MISC_CTRL_REG(unit, pc, temp32));
   3596 
   3597                 /* f.) Release all mHosts from reset, Only BMP will run. Others halted.
   3598                        In PM all will be halted. */
   3599                 SOC_IF_ERROR_RETURN
   3600                     (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32));
   3601                     temp32 &= ~(0xf << 10);
   3602                 SOC_IF_ERROR_RETURN
   3603                     (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32));
   3604 
   3605             }
   3606 
   3607             break;
   3608 
   3609         default:
   3610             break;
   3611     }
   3612 
   3613 
   3614 
   3615     return SOC_E_NONE;
   3616 }
   3617 
   3618 STATIC int
   3619 _phy_8806x_validate_interface_type(phy8806x_speed_config_t  *speed_config, soc_port_if_t *pif)
   3620 {
   3621     int port_num_lanes;
   3622 
   3623     port_num_lanes = speed_config->ln_lane_count;
   3624 
   3625     switch (speed_config->speed) {
   3626     case 1000:
   3627         if (port_num_lanes == 1) {
   3628             switch (*pif) {
   3629             case SOC_PORT_IF_SGMII:
   3630             case SOC_PORT_IF_GMII:
   3631                 break;
   3632             default:
   3633                 *pif = SOC_PORT_IF_SGMII;
   3634             }
   3635         } else {
   3636             return SOC_E_PARAM;
   3637         }
   3638         break;
   3639     case 10000:
   3640     case 25000:
   3641     case 20000:
   3642         if (port_num_lanes == 1) {
   3643             switch (*pif) {
   3644                 case SOC_PORT_IF_CR:
   3645                 case SOC_PORT_IF_SR:
   3646                 case SOC_PORT_IF_KR:
   3647                 case SOC_PORT_IF_XFI:
   3648                 case SOC_PORT_IF_XAUI:
   3649                     break;
   3650                 case SOC_PORT_IF_LR:
   3651                     *pif = SOC_PORT_IF_SR;
   3652                     break;
   3653                 default:
   3654                     *pif = SOC_PORT_IF_CR;
   3655                     break;
   3656             }
   3657         } else if(port_num_lanes == 2) {
   3658             switch (*pif) {
   3659                 case SOC_PORT_IF_CR2:
   3660                 case SOC_PORT_IF_SR2:
   3661                 case SOC_PORT_IF_KR2:
   3662                     break;
   3663                 case SOC_PORT_IF_LR2:
   3664                     *pif = SOC_PORT_IF_SR2;
   3665                     break;
   3666                 default:
   3667                     *pif = SOC_PORT_IF_CR2;
   3668                     break;
   3669             }
   3670         } else {
   3671             return SOC_E_PARAM;
   3672         } 
   3673         break ;
   3674     case 40000:
   3675     case 42000:
   3676     case 50000:
   3677         if (port_num_lanes == 2) {
   3678             switch (*pif) {
   3679                 case SOC_PORT_IF_CR2:
   3680                 case SOC_PORT_IF_SR2:
   3681                 case SOC_PORT_IF_KR2:
   3682                     break;
   3683                 case SOC_PORT_IF_LR2:
   3684                     *pif = SOC_PORT_IF_SR2;
   3685                     break;
   3686                 default:
   3687                     *pif = SOC_PORT_IF_CR2;
   3688                     break;
   3689             }
   3690         } else if (port_num_lanes == 4) {
   3691             switch (*pif) {
   3692                 case SOC_PORT_IF_CR4:
   3693                 case SOC_PORT_IF_SR4:
   3694                 case SOC_PORT_IF_KR4:
   3695                 case SOC_PORT_IF_XLAUI:
   3696                     break;
   3697                 case SOC_PORT_IF_LR4:
   3698                     *pif = SOC_PORT_IF_SR4;
   3699                     break;
   3700                 default:
   3701                     *pif = SOC_PORT_IF_CR4;
   3702                     break;
   3703             }
   3704         } else {
   3705             return SOC_E_PARAM;
   3706         }
   3707         break;
   3708     case 100000:
   3709     case 106000:
   3710         if (port_num_lanes == 4) {
   3711             switch (*pif) {
   3712                 case SOC_PORT_IF_CR4:
   3713                 case SOC_PORT_IF_SR4:
   3714                 case SOC_PORT_IF_KR4:
   3715                 case SOC_PORT_IF_CAUI:
   3716                     break;
   3717                 case SOC_PORT_IF_LR4:
   3718                     *pif = SOC_PORT_IF_SR4;
   3719                     break;
   3720                 default:
   3721                     *pif = SOC_PORT_IF_CR4;
   3722                     break; 
   3723             } 
   3724         } else {
   3725             return SOC_E_PARAM;
   3726         }
   3727         break;
   3728     default:
   3729         return SOC_E_PARAM;
   3730     }
   3731 
   3732     return 0;
   3733 }
   3734 
   3735 
   3736 STATIC int
   3737 phy_8806x_interface_set(int unit, soc_port_t port, soc_port_if_t pif)
   3738 {
   3739     phy_ctrl_t                *pc;
   3740     soc_phymod_ctrl_t         *pmc;
   3741     soc_phymod_phy_t          *phy;
   3742     phymod_phy_inf_config_t   interface_config;
   3743     int flag = 0;
   3744     phymod_ref_clk_t            ref_clock;
   3745     phy8806x_speed_config_t     *speed_config;
   3746     phy8806x_config_t           *pCfg;
   3747     phymod_phy_access_t       pm_phy_copy;
   3748 
   3749     /* locate phy control */
   3750     pc = EXT_PHY_SW_STATE(unit, port);
   3751     if (pc == NULL) {
   3752         return SOC_E_INTERNAL;
   3753     }
   3754 
   3755     pmc = &pc->phymod_ctrl;
   3756 
   3757     /* initialize the data structure */
   3758     sal_memset(&interface_config, 0x0, sizeof(phymod_phy_inf_config_t));
   3759 
   3760     /* now loop through all cores */
   3761     phy = pmc->phy[0];
   3762     if (phy == NULL) {
   3763         return SOC_E_INTERNAL;
   3764     }
   3765 
   3766     ref_clock = phymodRefClk156Mhz;
   3767 
   3768     sal_memcpy(&pm_phy_copy, &phy->pm_phy, sizeof(pm_phy_copy));
   3769 
   3770     pm_phy_copy.port_loc = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) \
   3771         ? phymodPortLocSys :  ((pc->flags & PHYCTRL_LINE_SIDE_CTRL) \
   3772         ?  phymodPortLocLine : phymodPortLocDC);
   3773 
   3774     SOC_IF_ERROR_RETURN
   3775         (phymod_phy_interface_config_get(&pm_phy_copy,
   3776                                          flag, ref_clock, &interface_config));
   3777 
   3778     pCfg = (phy8806x_config_t *) pc->driver_data;
   3779     speed_config = &(pCfg->speed_config);
   3780 
   3781     if ((pif == SOC_PORT_IF_SFI) ||
   3782         (pif == SOC_PORT_IF_SR4) ||
   3783         (pif == SOC_PORT_IF_LR4) ||
   3784         (pif == SOC_PORT_IF_SR) ||
   3785         (pif == SOC_PORT_IF_SR2) ||
   3786         (pif == SOC_PORT_IF_LR) ||
   3787         (pif == SOC_PORT_IF_LR2) ||
   3788         (pif == SOC_PORT_IF_GMII)) {
   3789 #if defined(INCLUDE_FCMAP)
   3790         if (pc->fcmap_enable)
   3791             pCfg->speed_config.fiber_pref_sys = 1;
   3792 #endif
   3793         pCfg->speed_config.fiber_pref = 1;  
   3794     } else {
   3795 #if defined(INCLUDE_FCMAP)
   3796         if (pc->fcmap_enable)
   3797             pCfg->speed_config.fiber_pref_sys = 0;
   3798 #endif
   3799         pCfg->speed_config.fiber_pref = 0;
   3800     }
   3801 
   3802     SOC_IF_ERROR_RETURN(_phy_8806x_validate_interface_type(speed_config, &pif));
   3803 
   3804     /* coverity[mixed_enums]: ignore */
   3805     interface_config.interface_type = pif;
   3806     
   3807     if (!interface_config.data_rate)
   3808         interface_config.data_rate = pCfg->speed_config.speed;
   3809 
   3810     /* note that the flags have an option to indicate whether it's ok to reprogram the PLL */
   3811     SOC_IF_ERROR_RETURN
   3812         (phymod_phy_interface_config_set(&pm_phy_copy,
   3813                                          flag,  &interface_config));
   3814 
   3815     return (SOC_E_NONE);
   3816 }
   3817 
   3818 STATIC int
   3819 phy_8806x_interface_get(int unit, soc_port_t port, soc_port_if_t *pif)
   3820 {
   3821     phy_ctrl_t                *pc;
   3822     soc_phymod_ctrl_t         *pmc;
   3823     soc_phymod_phy_t          *phy;
   3824     phymod_phy_inf_config_t   interface_config;
   3825     int flag = 0;
   3826     phymod_ref_clk_t          ref_clock;
   3827     phymod_phy_access_t       pm_phy_copy;
   3828 
   3829     /* locate phy control */
   3830     pc = EXT_PHY_SW_STATE(unit, port);
   3831     if (pc == NULL) {
   3832         return SOC_E_INTERNAL;
   3833     }
   3834 
   3835     pmc = &pc->phymod_ctrl;
   3836 
   3837     /* initialize the data structure */
   3838     sal_memset(&interface_config, 0x0, sizeof(phymod_phy_inf_config_t));
   3839 
   3840     /* now loop through all cores */
   3841     phy = pmc->phy[0];
   3842     if (phy == NULL) {
   3843         return SOC_E_INTERNAL;
   3844     }
   3845 
   3846     ref_clock = phymodRefClk156Mhz;
   3847 
   3848     sal_memcpy(&pm_phy_copy, &phy->pm_phy, sizeof(pm_phy_copy));
   3849 
   3850     pm_phy_copy.port_loc = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) \
   3851         ? phymodPortLocSys :  ((pc->flags & PHYCTRL_LINE_SIDE_CTRL) \
   3852         ?  phymodPortLocLine : phymodPortLocDC);
   3853 
   3854     /* note that the flags have an option to indicate whether it's ok to reprogram the PLL */
   3855     SOC_IF_ERROR_RETURN
   3856         (phymod_phy_interface_config_get(&pm_phy_copy,
   3857                                          flag, ref_clock, &interface_config));
   3858 
   3859     /* coverity[mixed_enums]: ignore */
   3860     *pif = interface_config.interface_type;
   3861 
   3862     return (SOC_E_NONE);
   3863 
   3864 }
   3865 
   3866 
   3867 /*
   3868  * Function:
   3869  *      phy8806x_uc_status_dump
   3870  * Purpose:
   3871  *      display all the serdes related parameters
   3872  * Parameters:
   3873  *      unit - BCM unit number.
   3874  *      port - Port number. 
   3875 
   3876  * Returns:     
   3877  *      SOC_E_NONE
   3878  */
   3879 STATIC int
   3880 phy8806x_uc_status_dump(int unit, soc_port_t port, void *arg)
   3881 {
   3882     phy_ctrl_t* pc; 
   3883     soc_phymod_ctrl_t *pmc;
   3884     phymod_phy_access_t *pm_phy;
   3885     int idx;
   3886 
   3887     /* locate phy control, phymod control, and the configuration data */
   3888     pc = EXT_PHY_SW_STATE(unit, port);
   3889     if (pc == NULL) {
   3890         return SOC_E_INTERNAL;
   3891     }
   3892     pmc = &pc->phymod_ctrl;
   3893 
   3894     for (idx = 0; idx < pmc->num_phys; idx++) {
   3895         pm_phy = &pmc->phy[idx]->pm_phy;
   3896         SOC_IF_ERROR_RETURN
   3897             (phymod_phy_pmd_info_dump(pm_phy, arg)); 
   3898     }
   3899     return (SOC_E_NONE);
   3900 }
   3901 
   3902 /* 
   3903  * phy8806x_tx_lane_squelch
   3904  */
   3905 STATIC int
   3906 phy8806x_tx_lane_squelch(soc_phymod_ctrl_t *pmc, uint32 value)
   3907 {
   3908     phymod_phy_access_t *pm_phy;
   3909     phymod_phy_tx_lane_control_t  tx_control;
   3910     int                 idx;
   3911 
   3912     /* loop through all cores */
   3913     for (idx = 0; idx < pmc->num_phys; idx++) {
   3914         pm_phy = &pmc->phy[idx]->pm_phy;
   3915 
   3916         if (pm_phy == NULL) {
   3917             return SOC_E_INTERNAL;
   3918         }
   3919 
   3920         if (value == 1) {
   3921             tx_control = phymodTxSquelchOn;
   3922         } else {
   3923             tx_control = phymodTxSquelchOff;
   3924         }
   3925         SOC_IF_ERROR_RETURN
   3926             (phymod_phy_tx_lane_control_set(pm_phy, tx_control));
   3927     }
   3928     return(SOC_E_NONE);
   3929 }
   3930 
   3931 /* 
   3932  * phy8806x_tx_polarity_set
   3933  */
   3934 STATIC int 
   3935 phy8806x_tx_polarity_set(soc_phymod_ctrl_t *pmc, phymod_polarity_t *cfg_polarity, uint32 value)
   3936 {
   3937     phymod_phy_access_t  *pm_phy;
   3938     phymod_polarity_t    polarity;
   3939     int                  idx;
   3940 
   3941     /* loop through all cores */
   3942     for (idx = 0; idx < pmc->num_phys; idx++) {
   3943         pm_phy = &pmc->phy[idx]->pm_phy;
   3944 
   3945         if (pm_phy == NULL) {
   3946             return SOC_E_INTERNAL;
   3947         }
   3948 
   3949         sal_memcpy(&polarity, cfg_polarity, sizeof(polarity));
   3950         polarity.tx_polarity = value;
   3951         SOC_IF_ERROR_RETURN(phymod_phy_polarity_set(pm_phy, &polarity));
   3952 
   3953         /* after successfully setting the parity, update the configured value */
   3954         cfg_polarity->tx_polarity = value;
   3955     }
   3956 
   3957     return(SOC_E_NONE);
   3958 }
   3959 
   3960 /* 
   3961  * phy8806x_rx_polarity_set
   3962  */
   3963 
   3964 STATIC int 
   3965 phy8806x_rx_polarity_set(soc_phymod_ctrl_t *pmc, phymod_polarity_t *cfg_polarity, uint32 value)
   3966 {
   3967     phymod_phy_access_t  *pm_phy;
   3968     phymod_polarity_t    polarity;
   3969     int                  idx;
   3970 
   3971     /* loop through all cores */
   3972     for (idx = 0; idx < pmc->num_phys; idx++) {
   3973         pm_phy = &pmc->phy[idx]->pm_phy;
   3974 
   3975         if (pm_phy == NULL) {
   3976             return SOC_E_INTERNAL;
   3977         }
   3978 
   3979         sal_memcpy(&polarity, cfg_polarity, sizeof(polarity));
   3980         polarity.rx_polarity = value;
   3981         SOC_IF_ERROR_RETURN(phymod_phy_polarity_set(pm_phy, &polarity));
   3982 
   3983         /* after successfully setting the parity, update the configured value */
   3984         cfg_polarity->rx_polarity = value;
   3985     }
   3986 
   3987     return(SOC_E_NONE);
   3988 }
   3989 
   3990 /* 
   3991  * phy8806x_rx_reset
   3992  */
   3993 STATIC int
   3994 phy8806x_rx_reset(soc_phymod_ctrl_t *pmc, phymod_phy_reset_t *cfg_reset, uint32 value)
   3995 {
   3996     phymod_phy_access_t *pm_phy;
   3997     phymod_phy_reset_t  reset;
   3998     int                 idx;
   3999 
   4000     /* loop through all cores */
   4001     for (idx = 0; idx < pmc->num_phys; idx++) {
   4002         pm_phy = &pmc->phy[idx]->pm_phy;
   4003 
   4004         if (pm_phy == NULL) {
   4005             return SOC_E_INTERNAL;
   4006         }
   4007 
   4008         sal_memcpy(&reset, cfg_reset, sizeof(reset));
   4009         reset.rx = (phymod_reset_direction_t) value;
   4010         SOC_IF_ERROR_RETURN(phymod_phy_reset_set(pm_phy, &reset));
   4011 
   4012         /* after successfully setting the parity, update the configured value */
   4013         cfg_reset->rx = (phymod_reset_direction_t) value;
   4014     }
   4015 
   4016     return(SOC_E_NONE);
   4017 }
   4018 
   4019 /* 
   4020  * phy8806x_tx_reset
   4021  */
   4022 STATIC int
   4023 phy8806x_tx_reset(soc_phymod_ctrl_t *pmc, phymod_phy_reset_t *cfg_reset, uint32 value)
   4024 {
   4025     phymod_phy_access_t *pm_phy;
   4026     phymod_phy_reset_t  reset;
   4027     int                 idx;
   4028 
   4029     /* loop through all cores */
   4030     for (idx = 0; idx < pmc->num_phys; idx++) {
   4031         pm_phy = &pmc->phy[idx]->pm_phy;
   4032 
   4033         if (pm_phy == NULL) {
   4034             return SOC_E_INTERNAL;
   4035         }
   4036 
   4037         sal_memcpy(&reset, cfg_reset, sizeof(reset));
   4038         reset.tx = (phymod_reset_direction_t) value;
   4039         SOC_IF_ERROR_RETURN(phymod_phy_reset_set(pm_phy, &reset));
   4040 
   4041         /* after successfully setting the parity, update the configured value */
   4042         cfg_reset->tx = (phymod_reset_direction_t) value;
   4043     }
   4044 
   4045     return(SOC_E_NONE);
   4046 }
   4047 
   4048 /* 
   4049  * phy8806x_cl72_enable_set
   4050  */
   4051 STATIC int
   4052 phy8806x_cl72_enable_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4053 {
   4054     phymod_phy_access_t *pm_phy;
   4055     int                 idx;
   4056 
   4057     /* loop through all cores */
   4058     for (idx = 0; idx < pmc->num_phys; idx++) {
   4059         pm_phy = &pmc->phy[idx]->pm_phy;
   4060 
   4061         if (pm_phy == NULL) {
   4062             return SOC_E_INTERNAL;
   4063         }
   4064 
   4065         SOC_IF_ERROR_RETURN(phymod_phy_cl72_set(pm_phy, value));
   4066     }
   4067 
   4068     return(SOC_E_NONE);
   4069 }
   4070 
   4071 STATIC int
   4072 phy8806x_lane_map_set(soc_phymod_ctrl_t *pmc, uint32 value){
   4073     int idx;
   4074     phymod_lane_map_t lane_map;
   4075 
   4076     lane_map.num_of_lanes = NUM_LANES;
   4077     if(pmc->phy[0] == NULL){
   4078         return(SOC_E_INTERNAL);
   4079     }
   4080     for (idx=0; idx < NUM_LANES; idx++) {
   4081         lane_map.lane_map_rx[idx] = (value >> (idx * 4 /* 4 bit per lane */)) & 0xf;
   4082     }
   4083     for (idx=0; idx < NUM_LANES; idx++) {
   4084         lane_map.lane_map_tx[idx] = (value >> (16 + idx * 4 /* 4 bit per lane */)) & 0xf;
   4085     }
   4086     SOC_IF_ERROR_RETURN(phymod_core_lane_map_set(&pmc->phy[0]->core->pm_core, &lane_map));
   4087     return(SOC_E_NONE);
   4088 }
   4089 
   4090 /* 
   4091  * phy8806x_per_lane_prbs_poly_set
   4092  */
   4093 int
   4094 phy8806x_per_lane_prbs_poly_set(soc_phymod_ctrl_t *pmc, int lane, uint32 value)
   4095 {
   4096    return(SOC_E_UNAVAIL);
   4097 }
   4098 
   4099 STATIC int
   4100 phy8806x_sdk_poly_to_phymod_poly(uint32 sdk_poly, phymod_prbs_poly_t *phymod_poly){
   4101     switch(sdk_poly){
   4102     case SOC_PHY_PRBS_POLYNOMIAL_X7_X6_1:
   4103         *phymod_poly = phymodPrbsPoly7;
   4104         break;
   4105     case SOC_PHY_PRBS_POLYNOMIAL_X15_X14_1:
   4106         *phymod_poly = phymodPrbsPoly15;
   4107         break;
   4108     case SOC_PHY_PRBS_POLYNOMIAL_X23_X18_1:
   4109         *phymod_poly = phymodPrbsPoly23;
   4110         break;
   4111     case SOC_PHY_PRBS_POLYNOMIAL_X31_X28_1:
   4112         *phymod_poly = phymodPrbsPoly31;
   4113         break;
   4114     case SOC_PHY_PRBS_POLYNOMIAL_X9_X5_1:
   4115         *phymod_poly = phymodPrbsPoly9;
   4116         break;
   4117     case SOC_PHY_PRBS_POLYNOMIAL_X11_X9_1:
   4118         *phymod_poly = phymodPrbsPoly11;
   4119         break;
   4120     case SOC_PHY_PRBS_POLYNOMIAL_X58_X31_1:
   4121         *phymod_poly = phymodPrbsPoly58;
   4122         break;
   4123     default:
   4124         return SOC_E_INTERNAL;
   4125     }
   4126     return SOC_E_NONE;
   4127 }
   4128 
   4129 /* 
   4130  * phy8806x_prbs_tx_poly_set
   4131  */
   4132 int
   4133 phy8806x_prbs_tx_poly_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4134 {
   4135     phymod_phy_access_t  *pm_phy;
   4136     phymod_prbs_t        prbs;
   4137     uint32_t flags = 0;
   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     PHYMOD_PRBS_DIRECTION_TX_SET(flags);
   4149     SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy,  flags, &prbs));
   4150     SOC_IF_ERROR_RETURN(phy8806x_sdk_poly_to_phymod_poly(value, &prbs.poly));
   4151     SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_set(pm_phy, flags, &prbs));
   4152     return(SOC_E_NONE);
   4153 }
   4154 
   4155 /* 
   4156  * phy8806x_prbs_rx_poly_set
   4157  */
   4158 STATIC int
   4159 phy8806x_prbs_rx_poly_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4160 {
   4161     phymod_phy_access_t  *pm_phy;
   4162     phymod_prbs_t        prbs;
   4163     uint32_t flags = 0;
   4164 
   4165     /* just take the value from the first phy */
   4166     if (pmc->phy[0] == NULL) {
   4167         return SOC_E_INTERNAL;
   4168     }
   4169     pm_phy = &pmc->phy[0]->pm_phy;
   4170 
   4171     if (pm_phy == NULL) {
   4172         return SOC_E_INTERNAL;
   4173     }
   4174     PHYMOD_PRBS_DIRECTION_RX_SET(flags);
   4175     SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy, flags, &prbs));
   4176     SOC_IF_ERROR_RETURN(phy8806x_sdk_poly_to_phymod_poly(value, &prbs.poly));
   4177     SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_set(pm_phy, flags, &prbs));
   4178     return(SOC_E_NONE);
   4179 }
   4180 
   4181 
   4182 /* 
   4183  * phy8806x_per_lane_prbs_tx_invert_data_set
   4184  */
   4185 int
   4186 phy8806x_per_lane_prbs_tx_invert_data_set(soc_phymod_ctrl_t *pmc, int lane, uint32 value)
   4187 {
   4188    return(SOC_E_UNAVAIL);
   4189 }
   4190 
   4191 /* 
   4192  * phy8806x_prbs_tx_invert_data_set
   4193  */
   4194 STATIC int
   4195 phy8806x_prbs_tx_invert_data_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4196 {
   4197     phymod_phy_access_t  *pm_phy;
   4198     phymod_prbs_t        prbs;
   4199     uint32_t flags = 0;
   4200 
   4201     /* just take the value from the first phy */
   4202     if (pmc->phy[0] == NULL) {
   4203         return SOC_E_INTERNAL;
   4204     }
   4205     pm_phy = &pmc->phy[0]->pm_phy;
   4206 
   4207     if (pm_phy == NULL) {
   4208         return SOC_E_INTERNAL;
   4209     }
   4210 
   4211     PHYMOD_PRBS_DIRECTION_TX_SET(flags);
   4212     SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy, flags, &prbs));
   4213     prbs.invert = value;
   4214     SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_set(pm_phy, flags,  &prbs));
   4215     return(SOC_E_NONE);
   4216 }
   4217 
   4218 /* 
   4219  * phy8806x_prbs_rx_invert_data_set
   4220  */
   4221 int
   4222 phy8806x_prbs_rx_invert_data_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4223 {
   4224     phymod_phy_access_t  *pm_phy;
   4225     phymod_prbs_t        prbs;
   4226     uint32_t flags = 0;
   4227 
   4228     /* just take the value from the first phy */
   4229     if (pmc->phy[0] == NULL) {
   4230         return SOC_E_INTERNAL;
   4231     }
   4232     pm_phy = &pmc->phy[0]->pm_phy;
   4233 
   4234     if (pm_phy == NULL) {
   4235         return SOC_E_INTERNAL;
   4236     }
   4237 
   4238     PHYMOD_PRBS_DIRECTION_RX_SET(flags);
   4239     SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy, flags,  &prbs));
   4240     prbs.invert = value;
   4241     SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_set(pm_phy, flags, &prbs));
   4242     return(SOC_E_NONE);
   4243 }
   4244 
   4245 /* 
   4246  * phy8806x_per_lane_prbs_tx_enable_set
   4247  */
   4248 int
   4249 phy8806x_per_lane_prbs_tx_enable_set(soc_phymod_ctrl_t *pmc, int lane, uint32 value)
   4250 {
   4251    return(SOC_E_UNAVAIL);
   4252 }
   4253 /* 
   4254  * phy8806x_prbs_tx_enable_set
   4255  */
   4256 STATIC int
   4257 phy8806x_prbs_tx_enable_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4258 {
   4259     phymod_phy_access_t  *pm_phy;
   4260     uint32_t flags = 0;
   4261 
   4262     /* just take the value from the first phy */
   4263     if (pmc->phy[0] == NULL) {
   4264         return SOC_E_INTERNAL;
   4265     }
   4266     pm_phy = &pmc->phy[0]->pm_phy;
   4267 
   4268     if (pm_phy == NULL) {
   4269         return SOC_E_INTERNAL;
   4270     }
   4271     PHYMOD_PRBS_DIRECTION_TX_SET(flags);
   4272     SOC_IF_ERROR_RETURN(phymod_phy_prbs_enable_set(pm_phy, flags, value));
   4273     return(SOC_E_NONE);
   4274 }
   4275 
   4276 /* 
   4277  * phy8806x_prbs_rx_enable_set
   4278  */
   4279 STATIC int
   4280 phy8806x_prbs_rx_enable_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4281 {
   4282     phymod_phy_access_t  *pm_phy;
   4283     uint32_t flags = 0;
   4284 
   4285     /* just take the value from the first phy */
   4286     if (pmc->phy[0] == NULL) {
   4287         return SOC_E_INTERNAL;
   4288     }
   4289     pm_phy = &pmc->phy[0]->pm_phy;
   4290 
   4291     if (pm_phy == NULL) {
   4292         return SOC_E_INTERNAL;
   4293     }
   4294 
   4295     PHYMOD_PRBS_DIRECTION_RX_SET(flags);
   4296     SOC_IF_ERROR_RETURN(phymod_phy_prbs_enable_set(pm_phy, flags,  value));
   4297     return(SOC_E_NONE);
   4298 }
   4299 
   4300 /* 
   4301  * phy8806x_loopback_internal_set
   4302  */
   4303 STATIC int 
   4304 phy8806x_loopback_internal_set(soc_phymod_ctrl_t *pmc, int sys, uint32 value)
   4305 {
   4306     phymod_phy_access_t  *pm_phy;
   4307 #if defined(INCLUDE_FCMAP)
   4308     soc_phymod_core_t *core;
   4309     phy_ctrl_t        *pc;
   4310 #endif
   4311     phymod_loopback_mode_t lb_mode;
   4312 
   4313     /* just take the value from the first phy */
   4314     if (pmc->phy[0] == NULL) {
   4315         return SOC_E_INTERNAL;
   4316     }
   4317     pm_phy = &pmc->phy[0]->pm_phy;
   4318 
   4319     if (pm_phy == NULL) {
   4320         return SOC_E_INTERNAL;
   4321     }
   4322 
   4323     if (sys) {
   4324         SOC_IF_ERROR_RETURN
   4325             (phymod_phy_loopback_set(pm_phy, phymodLoopbackSysGlobal, value));
   4326     } else {
   4327         lb_mode = phymodLoopbackGlobal;
   4328 #if defined(INCLUDE_FCMAP)
   4329         core = pmc->phy[0]->core;
   4330         pc = EXT_PHY_SW_STATE(core->unit, core->port);
   4331         if (pc->fcmap_enable) {
   4332             lb_mode = phymodLoopbackGlobalPMD;
   4333         }
   4334 #endif
   4335         SOC_IF_ERROR_RETURN
   4336             (phymod_phy_loopback_set(pm_phy, lb_mode, value));
   4337 
   4338     }
   4339     return(SOC_E_NONE);
   4340 }
   4341 
   4342 /* 
   4343  * phy8806x_loopback_pmd_set
   4344  */
   4345 STATIC int 
   4346 phy8806x_loopback_pmd_set(soc_phymod_ctrl_t *pmc, int sys, uint32 value)
   4347 {
   4348     phymod_phy_access_t  *pm_phy;
   4349 
   4350     /* just take the value from the first phy */
   4351     if (pmc->phy[0] == NULL) {
   4352         return SOC_E_INTERNAL;
   4353     }
   4354     pm_phy = &pmc->phy[0]->pm_phy;
   4355 
   4356     if (pm_phy == NULL) {
   4357         return SOC_E_INTERNAL;
   4358     }
   4359 
   4360     if (sys) {
   4361         SOC_IF_ERROR_RETURN
   4362             (phymod_phy_loopback_set(pm_phy, phymodLoopbackSysGlobalPMD, value));
   4363     } else {
   4364         SOC_IF_ERROR_RETURN
   4365             (phymod_phy_loopback_set(pm_phy, phymodLoopbackGlobalPMD, value));
   4366     }
   4367 
   4368     return(SOC_E_NONE);
   4369 }
   4370 
   4371 /* 
   4372  * phy8806x_loopback_remote_set
   4373  */
   4374 STATIC int 
   4375 phy8806x_loopback_remote_set(soc_phymod_ctrl_t *pmc, int sys, uint32 value)
   4376 {
   4377     phymod_phy_access_t  *pm_phy;
   4378 
   4379     /* just take the value from the first phy */
   4380     if (pmc->phy[0] == NULL) {
   4381         return SOC_E_INTERNAL;
   4382     }
   4383     pm_phy = &pmc->phy[0]->pm_phy;
   4384 
   4385     if (pm_phy == NULL) {
   4386         return SOC_E_INTERNAL;
   4387     }
   4388 
   4389     if (sys) {
   4390         SOC_IF_ERROR_RETURN
   4391             (phymod_phy_loopback_set(pm_phy, phymodLoopbackSysRemotePMD, value));
   4392     } else {
   4393         SOC_IF_ERROR_RETURN
   4394             (phymod_phy_loopback_set(pm_phy, phymodLoopbackRemotePMD, value));
   4395     }
   4396     return(SOC_E_NONE);
   4397 }
   4398 
   4399 /* 
   4400  * phy8806x_loopback_pcs_set
   4401  */
   4402 /* STATIC */ int 
   4403 phy8806x_loopback_pcs_set(soc_phymod_ctrl_t *pmc, int sys, uint32 value)
   4404 {
   4405     phymod_phy_access_t  *pm_phy;
   4406 
   4407     /* just take the value from the first phy */
   4408     if (pmc->phy[0] == NULL) {
   4409         return SOC_E_INTERNAL;
   4410     }
   4411     pm_phy = &pmc->phy[0]->pm_phy;
   4412 
   4413     if (pm_phy == NULL) {
   4414         return SOC_E_INTERNAL;
   4415     }
   4416 
   4417     if (sys) {
   4418         SOC_IF_ERROR_RETURN
   4419             (phymod_phy_loopback_set(pm_phy, phymodLoopbackSysGlobalPCS, value));
   4420     } else {
   4421         SOC_IF_ERROR_RETURN
   4422             (phymod_phy_loopback_set(pm_phy, phymodLoopbackGlobalPCS, value));
   4423     }
   4424 
   4425     return(SOC_E_NONE);
   4426 }
   4427 
   4428 /* 
   4429  * phy8806x_loopback_remote_pcs_set
   4430  */
   4431 STATIC int 
   4432 phy8806x_loopback_remote_pcs_set(soc_phymod_ctrl_t *pmc, int sys, uint32 value)
   4433 {
   4434     phymod_phy_access_t  *pm_phy;
   4435 
   4436     /* just take the value from the first phy */
   4437     if (pmc->phy[0] == NULL) {
   4438         return SOC_E_INTERNAL;
   4439     }
   4440     pm_phy = &pmc->phy[0]->pm_phy;
   4441 
   4442     if (pm_phy == NULL) {
   4443         return SOC_E_INTERNAL;
   4444     }
   4445 
   4446     if (sys) {
   4447         SOC_IF_ERROR_RETURN
   4448             (phymod_phy_loopback_set(pm_phy, phymodLoopbackSysRemotePCS, value));
   4449     } else {
   4450         SOC_IF_ERROR_RETURN
   4451             (phymod_phy_loopback_set(pm_phy, phymodLoopbackRemotePCS, value));
   4452     }
   4453 
   4454     return(SOC_E_NONE);
   4455 }
   4456 
   4457 /* 
   4458  * phy8806x_fec_enable_set
   4459  */
   4460 STATIC int 
   4461 phy8806x_fec_enable_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4462 {
   4463     phymod_phy_access_t     *pm_phy;
   4464     int                     idx;
   4465 
   4466     /* loop through all cores */
   4467     for (idx = 0; idx < pmc->num_phys; idx++) {
   4468         pm_phy = &pmc->phy[idx]->pm_phy;
   4469 
   4470         if (pm_phy == NULL) {
   4471             return SOC_E_INTERNAL;
   4472         }
   4473         SOC_IF_ERROR_RETURN(phymod_phy_fec_enable_set(pm_phy, value));
   4474     }
   4475     return(SOC_E_NONE);
   4476 }
   4477 
   4478 /* 
   4479  * phy8806x_power_set
   4480  */
   4481 STATIC int
   4482 phy8806x_power_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4483 {
   4484     phymod_phy_access_t     *pm_phy;
   4485     phymod_phy_power_t      power;
   4486     int                     idx;
   4487 
   4488     /* loop through all cores */
   4489     for (idx = 0; idx < pmc->num_phys; idx++) {
   4490         pm_phy = &pmc->phy[idx]->pm_phy;
   4491 
   4492         if (pm_phy == NULL) {
   4493             return SOC_E_INTERNAL;
   4494         }
   4495 
   4496         phymod_phy_power_t_init(&power);
   4497         if (value) {
   4498             power.tx = phymodPowerOn;
   4499             power.rx = phymodPowerOn;
   4500         } 
   4501         else {
   4502             power.tx = phymodPowerOff;
   4503             power.rx = phymodPowerOff;
   4504         }
   4505 
   4506         SOC_IF_ERROR_RETURN(phymod_phy_power_set(pm_phy, &power));
   4507     }
   4508 
   4509     return(SOC_E_NONE);
   4510 }
   4511 
   4512 /* 
   4513  * given a pc (phymod_ctrl_t) and logical lane number, 
   4514  *    find the correct soc_phymod_phy_t object and lane
   4515  */
   4516 STATIC int
   4517 _phy8806x_find_soc_phy_lane(soc_phymod_ctrl_t *pmc, uint32_t lane, 
   4518                         soc_phymod_phy_t **p_phy, uint32 *lane_map)
   4519 {
   4520     phymod_phy_access_t *pm_phy;
   4521     int idx, lnx, ln_cnt, found;
   4522     uint32 lane_map_copy;
   4523 
   4524     /* Traverse lanes belonging to this port */
   4525     found = 0;
   4526     ln_cnt = 0;
   4527     for (idx = 0; idx < pmc->num_phys; idx++) {
   4528         pm_phy = &pmc->phy[idx]->pm_phy;
   4529         if (pm_phy == NULL) {
   4530             return SOC_E_INTERNAL;
   4531         }
   4532         lane_map_copy = pm_phy->access.lane_mask;
   4533         for (lnx = 0; lnx < 4; lnx++) {
   4534             if ((1 << lnx) & lane_map_copy) {
   4535                 if (ln_cnt == lane) {
   4536                     found = 1;
   4537                     break;
   4538                 }
   4539                 ln_cnt++;
   4540             }
   4541         }
   4542         if (found) {
   4543             *p_phy = pmc->phy[idx];
   4544             *lane_map = (1 << lnx);
   4545             break;
   4546         }
   4547     } 
   4548 
   4549     if (!found) {
   4550         /* No such lane */
   4551         return SOC_E_PARAM;
   4552     }
   4553     return (SOC_E_NONE);
   4554 }
   4555 
   4556 
   4557 /* 
   4558  * phy8806x_per_lane_preemphasis_set
   4559  */
   4560 STATIC int
   4561 phy8806x_per_lane_preemphasis_set(soc_phymod_ctrl_t *pmc, int lane, uint32 value)
   4562 {
   4563     soc_phymod_phy_t    *p_phy;
   4564     uint32              lane_map;
   4565     phymod_phy_access_t pm_phy_copy, *pm_phy;
   4566     phymod_tx_t         phymod_tx;
   4567     soc_phymod_core_t *soc_core;
   4568 
   4569     /* locate the desired phy and lane */
   4570     SOC_IF_ERROR_RETURN(_phy8806x_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map));
   4571 
   4572     /* Make a copy of the phy access and overwrite the desired lane */
   4573     pm_phy = &p_phy->pm_phy;
   4574     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   4575     pm_phy_copy.access.lane_mask = lane_map;
   4576 
   4577     soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   4578     pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   4579 
   4580     SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   4581     phymod_tx.pre = value & 0xff;
   4582     phymod_tx.main = (value >> 8) & 0xff;
   4583     phymod_tx.post = (value >> 16) & 0xff;
   4584     SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx));
   4585 
   4586     return(SOC_E_NONE);
   4587 }
   4588 
   4589 /* 
   4590  * phy8806x_preemphasis_set
   4591  */
   4592 STATIC int
   4593 phy8806x_preemphasis_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4594 {
   4595     phymod_phy_access_t *pm_phy, pm_phy_copy;
   4596     phymod_tx_t         phymod_tx;
   4597     int                 idx;
   4598     soc_phymod_core_t *soc_core;
   4599 
   4600     /* loop through all cores */
   4601     for (idx = 0; idx < pmc->num_phys; idx++) {
   4602         pm_phy = &pmc->phy[idx]->pm_phy;
   4603 
   4604         if (pm_phy == NULL) {
   4605             return SOC_E_INTERNAL;
   4606         }
   4607 
   4608         sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   4609         soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   4610         pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   4611 
   4612         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   4613         phymod_tx.pre = value & 0xff;
   4614         phymod_tx.main = (value >> 8) & 0xff;
   4615         phymod_tx.post = (value >> 16) & 0xff;
   4616         SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx));
   4617     }
   4618 
   4619     return(SOC_E_NONE);
   4620 }
   4621 
   4622 /* 
   4623  * phy8806x_tx_fir_pre_set
   4624  */
   4625 STATIC int
   4626 phy8806x_tx_fir_pre_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4627 {
   4628     phymod_phy_access_t *pm_phy, pm_phy_copy;
   4629     phymod_tx_t         phymod_tx;
   4630     int                 idx;
   4631     soc_phymod_core_t *soc_core;
   4632 
   4633     /* loop through all cores */
   4634     for (idx = 0; idx < pmc->num_phys; idx++) {
   4635         pm_phy = &pmc->phy[idx]->pm_phy;
   4636 
   4637         if (pm_phy == NULL) {
   4638             return SOC_E_INTERNAL;
   4639         }
   4640         sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   4641         soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   4642         pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   4643 
   4644 
   4645         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   4646         phymod_tx.pre = value;
   4647         SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx));
   4648     }
   4649 
   4650     return(SOC_E_NONE);
   4651 }
   4652 
   4653 /* 
   4654  * phy8806x_tx_fir_main_set
   4655  */
   4656 STATIC int
   4657 phy8806x_tx_fir_main_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4658 {
   4659     phymod_phy_access_t *pm_phy, pm_phy_copy;
   4660     phymod_tx_t         phymod_tx;
   4661     int                 idx;
   4662     soc_phymod_core_t *soc_core;
   4663 
   4664     /* loop through all cores */
   4665     for (idx = 0; idx < pmc->num_phys; idx++) {
   4666         pm_phy = &pmc->phy[idx]->pm_phy;
   4667 
   4668         if (pm_phy == NULL) {
   4669             return SOC_E_INTERNAL;
   4670         }
   4671         sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   4672         soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   4673         pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   4674 
   4675 
   4676         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   4677         phymod_tx.main = value;
   4678         SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx));
   4679     }
   4680 
   4681     return(SOC_E_NONE);
   4682 }
   4683 
   4684 /* 
   4685  * phy8806x_tx_fir_post_set
   4686  */
   4687 STATIC int
   4688 phy8806x_tx_fir_post_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4689 {
   4690     phymod_phy_access_t *pm_phy, pm_phy_copy;
   4691     phymod_tx_t         phymod_tx;
   4692     int                 idx;
   4693     soc_phymod_core_t *soc_core;
   4694 
   4695     /* loop through all cores */
   4696     for (idx = 0; idx < pmc->num_phys; idx++) {
   4697         pm_phy = &pmc->phy[idx]->pm_phy;
   4698 
   4699         if (pm_phy == NULL) {
   4700             return SOC_E_INTERNAL;
   4701         }
   4702         sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   4703         soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   4704         pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   4705 
   4706 
   4707         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   4708         phymod_tx.post = value;
   4709         SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx));
   4710     }
   4711 
   4712     return(SOC_E_NONE);
   4713 }
   4714 
   4715 /* 
   4716  * phy8806x_tx_fir_post2_set
   4717  */
   4718 STATIC int
   4719 phy8806x_tx_fir_post2_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4720 {
   4721     phymod_phy_access_t *pm_phy, pm_phy_copy;
   4722     phymod_tx_t         phymod_tx;
   4723     int                 idx;
   4724     soc_phymod_core_t *soc_core;
   4725 
   4726     /* loop through all cores */
   4727     for (idx = 0; idx < pmc->num_phys; idx++) {
   4728         pm_phy = &pmc->phy[idx]->pm_phy;
   4729 
   4730         if (pm_phy == NULL) {
   4731             return SOC_E_INTERNAL;
   4732         }
   4733         sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   4734         soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   4735         pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   4736 
   4737 
   4738         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   4739         phymod_tx.post2 = value;
   4740         SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx));
   4741     }
   4742 
   4743     return(SOC_E_NONE);
   4744 }
   4745 
   4746 /* 
   4747  * phy8806x_tx_fir_post3_set
   4748  */
   4749 STATIC int
   4750 phy8806x_tx_fir_post3_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4751 {
   4752     phymod_phy_access_t *pm_phy, pm_phy_copy;
   4753     phymod_tx_t         phymod_tx;
   4754     int                 idx;
   4755     soc_phymod_core_t *soc_core;
   4756 
   4757     /* loop through all cores */
   4758     for (idx = 0; idx < pmc->num_phys; idx++) {
   4759         pm_phy = &pmc->phy[idx]->pm_phy;
   4760 
   4761         if (pm_phy == NULL) {
   4762             return SOC_E_INTERNAL;
   4763         }
   4764         sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   4765         soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   4766         pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   4767 
   4768 
   4769         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   4770         phymod_tx.post3 = value;
   4771         SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx));
   4772     }
   4773 
   4774     return(SOC_E_NONE);
   4775 }
   4776 
   4777 /* 
   4778  * phy8806x_per_lane_driver_current_set
   4779  */
   4780 STATIC int
   4781 phy8806x_per_lane_driver_current_set(soc_phymod_ctrl_t *pmc, int lane, uint32 value)
   4782 {
   4783     soc_phymod_phy_t    *p_phy;
   4784     uint32              lane_map;
   4785     phymod_phy_access_t pm_phy_copy, *pm_phy;
   4786     phymod_tx_t         phymod_tx;
   4787     soc_phymod_core_t *soc_core;
   4788 
   4789     /* locate the desired phy and lane */
   4790     SOC_IF_ERROR_RETURN(_phy8806x_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map));
   4791 
   4792     /* Make a copy of the phy access and overwrite the desired lane */
   4793     pm_phy = &p_phy->pm_phy;
   4794     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   4795     pm_phy_copy.access.lane_mask = lane_map;
   4796     soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   4797     pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   4798 
   4799     SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   4800     phymod_tx.amp = value;
   4801     SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx));
   4802 
   4803     return(SOC_E_NONE);
   4804 }
   4805 
   4806 
   4807 /* 
   4808  * phy8806x_driver_current_set
   4809  */
   4810 STATIC int
   4811 phy8806x_driver_current_set(soc_phymod_ctrl_t *pmc, uint32 value)
   4812 {
   4813     phymod_phy_access_t *pm_phy, pm_phy_copy;
   4814     phymod_tx_t         phymod_tx;
   4815     int                 idx;
   4816     soc_phymod_core_t *soc_core;
   4817 
   4818     /* loop through all cores */
   4819     for (idx = 0; idx < pmc->num_phys; idx++) {
   4820         pm_phy = &pmc->phy[idx]->pm_phy;
   4821 
   4822         if (pm_phy == NULL) {
   4823             return SOC_E_INTERNAL;
   4824         }
   4825         sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   4826         soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   4827         pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   4828 
   4829 
   4830         SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   4831         phymod_tx.amp = value;
   4832         SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx));
   4833     }
   4834 
   4835     return(SOC_E_NONE);
   4836 }
   4837 
   4838 STATIC int
   4839 phy8806x_firmware_unreliable_los_set(soc_phymod_ctrl_t *pmc, uint32 enable)
   4840 {
   4841     phymod_phy_access_t    pm_phy_copy, *pm_phy;
   4842     phymod_firmware_lane_config_t fw_config;
   4843     int                    idx;
   4844     soc_phymod_core_t      *soc_core;
   4845 
   4846     /* loop through all cores */
   4847     for (idx = 0; idx < pmc->num_phys; idx++) {
   4848         if (pmc->phy[idx] == NULL) {
   4849             return(SOC_E_INTERNAL);
   4850         }
   4851 
   4852         pm_phy = &pmc->phy[idx]->pm_phy;
   4853         if (pm_phy == NULL) {
   4854             return(SOC_E_INTERNAL);
   4855         }
   4856 
   4857         sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   4858         soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   4859         pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   4860 
   4861         SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config));
   4862 
   4863         if (enable) {
   4864             fw_config.UnreliableLos = 1;
   4865         } else {
   4866             fw_config.UnreliableLos = 0;
   4867         }
   4868 
   4869         SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_set(&pm_phy_copy, fw_config));
   4870     }
   4871 
   4872     return(SOC_E_NONE);
   4873 }
   4874 
   4875 
   4876 STATIC int
   4877 phy8806x_firmware_dfe_enable_set(soc_phymod_ctrl_t *pmc, uint32 enable)
   4878 {
   4879     phymod_phy_access_t    pm_phy_copy, *pm_phy;
   4880     phymod_firmware_lane_config_t fw_config;
   4881     int                    idx;
   4882     soc_phymod_core_t      *soc_core;
   4883     
   4884     /* loop through all cores */
   4885     for (idx = 0; idx < pmc->num_phys; idx++) {
   4886         if (pmc->phy[idx] == NULL) {
   4887             return(SOC_E_INTERNAL);
   4888         }
   4889 
   4890         pm_phy = &pmc->phy[idx]->pm_phy;
   4891         if (pm_phy == NULL) {
   4892             return(SOC_E_INTERNAL);
   4893         }
   4894 
   4895         sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   4896         soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   4897         pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   4898 
   4899         SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config));
   4900 
   4901         if (enable) {
   4902             fw_config.DfeOn = 1;
   4903         } else {
   4904             fw_config.DfeOn = 0;
   4905         }
   4906 
   4907         SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_set(&pm_phy_copy, fw_config));
   4908     }
   4909 
   4910     return(SOC_E_NONE);
   4911 }
   4912 
   4913 /*
   4914  * tscf_firmware_mode_set
   4915  */
   4916 STATIC int
   4917 phy8806x_firmware_lp_dfe_enable_set(soc_phymod_ctrl_t *pmc, uint32 enable)
   4918 {
   4919     phymod_phy_access_t    pm_phy_copy, *pm_phy;
   4920     phymod_firmware_lane_config_t fw_config;
   4921     int                    idx;
   4922     soc_phymod_core_t      *soc_core;
   4923 
   4924     /* loop through all cores */
   4925     for (idx = 0; idx < pmc->num_phys; idx++) {
   4926         if (pmc->phy[idx] == NULL) {
   4927             return(SOC_E_INTERNAL);
   4928         }
   4929 
   4930         pm_phy = &pmc->phy[idx]->pm_phy;
   4931         if (pm_phy == NULL) {
   4932             return(SOC_E_INTERNAL);
   4933         }
   4934 
   4935         sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   4936         soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   4937         pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   4938 
   4939         SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config));
   4940 
   4941         if (enable) {
   4942             fw_config.DfeOn = 1;
   4943             fw_config.LpDfeOn = 1;
   4944         } else {
   4945             fw_config.LpDfeOn = 0;
   4946         }
   4947 
   4948         SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_set(&pm_phy_copy, fw_config));
   4949     }
   4950 
   4951     return(SOC_E_NONE);
   4952 }
   4953 
   4954 STATIC int
   4955 phy8806x_firmware_br_dfe_enable_set(soc_phymod_ctrl_t *pmc, uint32 enable)
   4956 {
   4957     phymod_phy_access_t    pm_phy_copy, *pm_phy;
   4958     phymod_firmware_lane_config_t fw_config;
   4959     int                    idx;
   4960     soc_phymod_core_t      *soc_core;
   4961 
   4962     /* loop through all cores */
   4963     for (idx = 0; idx < pmc->num_phys; idx++) {
   4964         if (pmc->phy[idx] == NULL) {
   4965             return(SOC_E_INTERNAL);
   4966         }
   4967 
   4968         pm_phy = &pmc->phy[idx]->pm_phy;
   4969         if (pm_phy == NULL) {
   4970             return(SOC_E_INTERNAL);
   4971         }
   4972 
   4973         sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   4974         soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   4975         pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   4976 
   4977         SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config));
   4978 
   4979         if (enable) {
   4980             fw_config.DfeOn = 1;
   4981             fw_config.ForceBrDfe = 1;
   4982         } else {
   4983             fw_config.ForceBrDfe = 0;
   4984         }
   4985 
   4986         SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_set(&pm_phy_copy, fw_config));
   4987     }
   4988 
   4989     return(SOC_E_NONE);
   4990 }
   4991 
   4992 /*
   4993  * Function:
   4994  *      phy_8806x_control_set
   4995  * Purpose:
   4996  *      Configure PHY device specific control fucntion. 
   4997  * Parameters:
   4998  *      unit  - BCM unit number.
   4999  *      port  - Port number. 
   5000  *      type  - Control to update 
   5001  *      value - New setting for the control 
   5002  * Returns:     
   5003  *      SOC_E_NONE
   5004  */
   5005 STATIC int
   5006 phy_8806x_control_set(int unit, soc_port_t port, soc_phy_control_t type, uint32 value)
   5007 {
   5008     int                 rv;
   5009     phy_ctrl_t          *pc;
   5010     soc_phymod_ctrl_t   *pmc;
   5011     phy8806x_config_t       *pCfg;
   5012 
   5013     rv = SOC_E_UNAVAIL;
   5014 
   5015     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
   5016         return (SOC_E_PARAM);
   5017     }
   5018 
   5019     /* locate phy control, phymod control, and the configuration data */
   5020     pc = EXT_PHY_SW_STATE(unit, port);
   5021     if (pc == NULL) {
   5022         return SOC_E_INTERNAL;
   5023     }
   5024 
   5025 #if defined(INCLUDE_FCMAP)
   5026     /* Skip these loopback set for FC */
   5027     if ((pc->fcmap_enable) && 
   5028          (type == SOC_PHY_CONTROL_LOOPBACK_REMOTE_PCS_BYPASS)) {
   5029         return SOC_E_NONE;
   5030     }
   5031 #endif
   5032 
   5033     pmc = &pc->phymod_ctrl;
   5034     pCfg = (phy8806x_config_t *) pc->driver_data;
   5035 
   5036     switch(type) {
   5037     case SOC_PHY_CONTROL_UNRELIABLE_LOS:
   5038         rv = phy8806x_firmware_unreliable_los_set(pmc, value);
   5039         break;
   5040     case SOC_PHY_CONTROL_FIRMWARE_DFE_ENABLE:
   5041         rv = phy8806x_firmware_dfe_enable_set(pmc, value);
   5042         break;
   5043     case SOC_PHY_CONTROL_FIRMWARE_LP_DFE_ENABLE:
   5044         rv = phy8806x_firmware_lp_dfe_enable_set(pmc, value);
   5045         break;
   5046     case SOC_PHY_CONTROL_FIRMWARE_BR_DFE_ENABLE:
   5047         rv = phy8806x_firmware_br_dfe_enable_set(pmc, value);
   5048         break;
   5049 
   5050     /* TX LANE SQUELCH */
   5051     case SOC_PHY_CONTROL_TX_LANE_SQUELCH:
   5052         rv = phy8806x_tx_lane_squelch(pmc, value);
   5053         break;
   5054 
   5055     /* POLARITY */
   5056     case SOC_PHY_CONTROL_RX_POLARITY:
   5057         rv = phy8806x_rx_polarity_set(pmc, &pCfg->phy_polarity_config, value);;
   5058         break;
   5059     case SOC_PHY_CONTROL_TX_POLARITY:
   5060         rv = phy8806x_tx_polarity_set(pmc, &pCfg->phy_polarity_config, value);
   5061         break;
   5062 
   5063     /* RESET */
   5064     case SOC_PHY_CONTROL_RX_RESET:
   5065         rv = phy8806x_rx_reset(pmc, &pCfg->phy_reset_config, value);
   5066         break;
   5067     case SOC_PHY_CONTROL_TX_RESET:
   5068         rv = phy8806x_tx_reset(pmc, &pCfg->phy_reset_config, value);
   5069         break;
   5070 
   5071     /* CL72 ENABLE */
   5072     case SOC_PHY_CONTROL_CL72:
   5073         if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) {
   5074             value = value | PORT_SYS_SIDE_CTRL;
   5075         }
   5076         rv = phy8806x_cl72_enable_set(pmc, value);
   5077         break;
   5078 
   5079     /* LANE SWAP */
   5080     case SOC_PHY_CONTROL_LANE_SWAP:
   5081         rv = phy8806x_lane_map_set(pmc, value);
   5082         break;
   5083 
   5084     /* for legacy prbs usage mainly set both tx/rx the same */
   5085     case SOC_PHY_CONTROL_PRBS_POLYNOMIAL:
   5086         rv = phy8806x_prbs_tx_poly_set(pmc, value);
   5087         rv = phy8806x_prbs_rx_poly_set(pmc, value);
   5088         break;
   5089     case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA:
   5090         rv = phy8806x_prbs_tx_invert_data_set(pmc, value);
   5091         break;
   5092     case SOC_PHY_CONTROL_PRBS_TX_ENABLE:
   5093         rv = phy8806x_prbs_tx_enable_set(pmc, value);
   5094         rv = phy8806x_prbs_rx_enable_set(pmc, value);
   5095         break;
   5096     case SOC_PHY_CONTROL_PRBS_RX_ENABLE:
   5097         rv = phy8806x_prbs_tx_enable_set(pmc, value);
   5098         rv = phy8806x_prbs_rx_enable_set(pmc, value);
   5099         break;
   5100 
   5101     /* LOOPBACK */
   5102     case SOC_PHY_CONTROL_LOOPBACK_INTERNAL:
   5103         rv = phy8806x_loopback_internal_set(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value);
   5104        break;
   5105     case SOC_PHY_CONTROL_LOOPBACK_PMD:
   5106         rv = phy8806x_loopback_pmd_set(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value);
   5107        break;
   5108     case SOC_PHY_CONTROL_LOOPBACK_REMOTE:
   5109         rv = phy8806x_loopback_remote_set(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value);
   5110         break;
   5111     case SOC_PHY_CONTROL_LOOPBACK_REMOTE_PCS_BYPASS:
   5112         rv = phy8806x_loopback_remote_pcs_set(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value);
   5113         break;
   5114 
   5115     /* FEC */
   5116     case SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION:
   5117         if (value)     /* 1 for CL74 */
   5118              value = 1;
   5119         if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) {
   5120             value = value | PORT_SYS_SIDE_CTRL;
   5121         }
   5122         rv = phy8806x_fec_enable_set(pmc, value);
   5123         break;
   5124 
   5125     case SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION_CL91:
   5126         if (value)     
   5127              value = 2; /* 1 for CL74, 2 for Cl91 */
   5128         if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) {
   5129             value = value | PORT_SYS_SIDE_CTRL;
   5130         }
   5131         rv = phy8806x_fec_enable_set(pmc, value);
   5132         break;
   5133 
   5134     /* POWER */
   5135     case SOC_PHY_CONTROL_POWER:
   5136        rv = phy8806x_power_set(pmc, value);
   5137        break;
   5138 
   5139     case SOC_PHY_CONTROL_FORCED_SPEED_LINE_SIDE:
   5140        if (pCfg->speed_config.port_mode == ETH_ETHERRAM)
   5141            rv = phy8806x_forced_speed_line_side_set(pmc, value);
   5142        else 
   5143            rv = SOC_E_UNAVAIL;
   5144        break; 
   5145     case SOC_PHY_CONTROL_AUTONEG_LINE_SIDE:
   5146        if (pCfg->speed_config.port_mode == ETH_ETHERRAM) 
   5147            rv = phy8806x_autoneg_line_side_set(pmc, value);
   5148        else
   5149            rv = SOC_E_UNAVAIL;
   5150        break;
   5151     case SOC_PHY_CONTROL_EGRESS_FLOW_CONTROL_MODE:
   5152         if (pCfg->speed_config.port_mode == ETH_ETHERRAM)
   5153             rv = phy8806x_flow_control_mode_set(pmc, value, 0);
   5154         else
   5155             rv = SOC_E_UNAVAIL;
   5156         break;
   5157     case SOC_PHY_CONTROL_INGRESS_FLOW_CONTROL_MODE:
   5158         if (pCfg->speed_config.port_mode == ETH_ETHERRAM)
   5159             rv = phy8806x_flow_control_mode_set(pmc, value, 1);
   5160         else
   5161             rv = SOC_E_UNAVAIL;
   5162         break;
   5163     case SOC_PHY_CONTROL_PSM_COS_BMP:
   5164         if (pCfg->speed_config.port_mode == ETH_ETHERRAM)
   5165             rv = phy8806x_psm_cos_bmp_set(pmc, value);
   5166         else
   5167             rv = SOC_E_UNAVAIL;
   5168         break;
   5169     case SOC_PHY_CONTROL_PFC_USE_IP_COS:
   5170         if (pCfg->speed_config.port_mode == ETH_ETHERRAM) {
   5171             rv = phy8806x_pfc_use_ip_cos_set(pmc, value); 
   5172         } else {
   5173             rv = SOC_E_UNAVAIL;
   5174         }
   5175         break;
   5176     case SOC_PHY_CONTROL_TX_FIR_PRE:
   5177         rv = phy8806x_tx_fir_pre_set(pmc, value);
   5178         break;
   5179     case SOC_PHY_CONTROL_TX_FIR_MAIN:
   5180         rv = phy8806x_tx_fir_main_set(pmc, value);
   5181         break;
   5182     case SOC_PHY_CONTROL_TX_FIR_POST:
   5183         rv = phy8806x_tx_fir_post_set(pmc, value);
   5184         break;
   5185     case SOC_PHY_CONTROL_TX_FIR_POST2:
   5186         rv = phy8806x_tx_fir_post2_set(pmc, value);
   5187         break;
   5188     case SOC_PHY_CONTROL_TX_FIR_POST3:
   5189         rv = phy8806x_tx_fir_post3_set(pmc, value);
   5190         break;
   5191     /* PREEMPHASIS */
   5192     case SOC_PHY_CONTROL_PREEMPHASIS_LANE0:
   5193         rv = phy8806x_per_lane_preemphasis_set(pmc, 0, value);
   5194         break;
   5195     case SOC_PHY_CONTROL_PREEMPHASIS_LANE1:
   5196         rv = phy8806x_per_lane_preemphasis_set(pmc, 1, value);
   5197         break;
   5198     case SOC_PHY_CONTROL_PREEMPHASIS_LANE2:
   5199         rv = phy8806x_per_lane_preemphasis_set(pmc, 2, value);
   5200         break;
   5201     case SOC_PHY_CONTROL_PREEMPHASIS_LANE3:
   5202         rv = phy8806x_per_lane_preemphasis_set(pmc, 3, value);
   5203         break;
   5204     case SOC_PHY_CONTROL_PREEMPHASIS:
   5205     {
   5206         /* we need to check if the value is 0xffffff, if yes, then clear
   5207         the user_set_tx bit */
   5208         if (value == 0xffffff) {
   5209             pCfg->user_set_tx = 0;
   5210         } else {     
   5211             rv = phy8806x_preemphasis_set(pmc, value);
   5212         }
   5213         break;
   5214     }
   5215     /* DRIVER CURRENT */
   5216     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0:
   5217         rv = phy8806x_per_lane_driver_current_set(pmc, 0, value);
   5218         break;
   5219     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1:
   5220         rv = phy8806x_per_lane_driver_current_set(pmc, 1, value);
   5221         break;
   5222     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2:
   5223         rv = phy8806x_per_lane_driver_current_set(pmc, 2, value);
   5224         break;
   5225     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3:
   5226         rv = phy8806x_per_lane_driver_current_set(pmc, 3, value);
   5227         break;
   5228     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   5229         rv = phy8806x_driver_current_set(pmc, value);
   5230         break;
   5231     case SOC_PHY_CONTROL_INTERFACE:
   5232         rv = phy_8806x_interface_set(unit, port, value);
   5233         break;
   5234     default:
   5235         rv = SOC_E_UNAVAIL;
   5236         break; 
   5237     }
   5238     return rv;
   5239 }
   5240 
   5241 STATIC int
   5242 phy8806x_pfc_use_ip_cos_set(soc_phymod_ctrl_t *pmc, uint32 value)
   5243 {
   5244     phymod_phy_access_t     *pm_phy;
   5245     int                     idx;
   5246 
   5247     /* loop through all cores */
   5248     for (idx = 0; idx < pmc->num_phys; idx++) {
   5249         pm_phy = &pmc->phy[idx]->pm_phy;
   5250 
   5251         if (pm_phy == NULL) {
   5252             return SOC_E_INTERNAL;
   5253         }
   5254         SOC_IF_ERROR_RETURN(phymod_phy_pfc_use_ip_cos_set(pm_phy, value));
   5255     }
   5256     return(SOC_E_NONE);
   5257 }
   5258 
   5259 STATIC int
   5260 phy8806x_pfc_use_ip_cos_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5261 {
   5262     phymod_phy_access_t     *pm_phy;
   5263     int                     idx;
   5264 
   5265     /* loop through all cores */
   5266     for (idx = 0; idx < pmc->num_phys; idx++) {
   5267         pm_phy = &pmc->phy[idx]->pm_phy;
   5268 
   5269         if (pm_phy == NULL) {
   5270             return SOC_E_INTERNAL;
   5271         }
   5272         SOC_IF_ERROR_RETURN(phymod_phy_pfc_use_ip_cos_get(pm_phy, value));
   5273     }
   5274 
   5275     return(SOC_E_NONE);
   5276 }
   5277 
   5278 STATIC int
   5279 phy8806x_psm_cos_bmp_set(soc_phymod_ctrl_t *pmc, uint32 value)
   5280 {
   5281     phymod_phy_access_t     *pm_phy;
   5282     int                     idx;
   5283 
   5284     /* loop through all cores */
   5285     for (idx = 0; idx < pmc->num_phys; idx++) {
   5286         pm_phy = &pmc->phy[idx]->pm_phy;
   5287 
   5288         if (pm_phy == NULL) {
   5289             return SOC_E_INTERNAL;
   5290         }
   5291         SOC_IF_ERROR_RETURN(phymod_phy_psm_cos_bmp_set(pm_phy, value));
   5292     }
   5293     return(SOC_E_NONE);
   5294 }
   5295 
   5296 STATIC int
   5297 phy8806x_psm_cos_bmp_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5298 {
   5299     phymod_phy_access_t     *pm_phy;
   5300     int                     idx;
   5301 
   5302     /* loop through all cores */
   5303     for (idx = 0; idx < pmc->num_phys; idx++) {
   5304         pm_phy = &pmc->phy[idx]->pm_phy;
   5305 
   5306         if (pm_phy == NULL) {
   5307             return SOC_E_INTERNAL;
   5308         }
   5309         SOC_IF_ERROR_RETURN(phymod_phy_psm_cos_bmp_get(pm_phy, value));
   5310     }
   5311 
   5312     return(SOC_E_NONE);
   5313 }
   5314 
   5315 STATIC int                               
   5316 phy8806x_flow_control_mode_set(soc_phymod_ctrl_t *pmc, uint32 value, uint8 ingress)
   5317 {
   5318     phymod_phy_access_t     *pm_phy;
   5319     int                     idx;
   5320                              
   5321     /* loop through all cores */
   5322     for (idx = 0; idx < pmc->num_phys; idx++) {
   5323         pm_phy = &pmc->phy[idx]->pm_phy;
   5324                              
   5325         if (pm_phy == NULL) {
   5326             return SOC_E_INTERNAL;
   5327         }
   5328         SOC_IF_ERROR_RETURN(phymod_phy_flow_control_mode_set(pm_phy, value, ingress));
   5329     }
   5330     return(SOC_E_NONE);
   5331 }
   5332 
   5333 STATIC int
   5334 phy8806x_flow_control_mode_get(soc_phymod_ctrl_t *pmc, uint8 ingress, uint32 *value)
   5335 {
   5336     phymod_phy_access_t     *pm_phy;
   5337     int                     idx;
   5338 
   5339     /* loop through all cores */
   5340     for (idx = 0; idx < pmc->num_phys; idx++) {
   5341         pm_phy = &pmc->phy[idx]->pm_phy;
   5342 
   5343         if (pm_phy == NULL) {
   5344             return SOC_E_INTERNAL;
   5345         }
   5346         SOC_IF_ERROR_RETURN(phymod_phy_flow_control_mode_get(pm_phy, ingress, value));
   5347     }
   5348 
   5349     return(SOC_E_NONE);
   5350 }
   5351 
   5352 STATIC int
   5353 phy8806x_forced_speed_line_side_set(soc_phymod_ctrl_t *pmc, uint32 value)
   5354 {
   5355     phymod_phy_access_t     *pm_phy;
   5356     int                     idx;
   5357 
   5358     /* loop through all cores */
   5359     for (idx = 0; idx < pmc->num_phys; idx++) {
   5360         pm_phy = &pmc->phy[idx]->pm_phy;
   5361 
   5362         if (pm_phy == NULL) {
   5363             return SOC_E_INTERNAL;
   5364         }
   5365         SOC_IF_ERROR_RETURN(phymod_phy_forced_speed_line_side_set(pm_phy, value));
   5366     }
   5367 
   5368     return(SOC_E_NONE);
   5369 }
   5370 
   5371 STATIC int
   5372 phy8806x_forced_speed_line_side_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5373 {
   5374     phymod_phy_access_t     *pm_phy;
   5375     int                     idx;
   5376 
   5377     /* loop through all cores */
   5378     for (idx = 0; idx < pmc->num_phys; idx++) {
   5379         pm_phy = &pmc->phy[idx]->pm_phy;
   5380 
   5381         if (pm_phy == NULL) {
   5382             return SOC_E_INTERNAL;
   5383         }
   5384         SOC_IF_ERROR_RETURN(phymod_phy_forced_speed_line_side_get(pm_phy, value));
   5385     }
   5386 
   5387     return(SOC_E_NONE);
   5388 }
   5389 
   5390 
   5391 STATIC int
   5392 phy8806x_autoneg_line_side_set(soc_phymod_ctrl_t *pmc, uint32 value)
   5393 {
   5394     phymod_phy_access_t     *pm_phy;
   5395     int                     idx;
   5396 
   5397     /* loop through all cores */
   5398     for (idx = 0; idx < pmc->num_phys; idx++) {
   5399         pm_phy = &pmc->phy[idx]->pm_phy;
   5400 
   5401         if (pm_phy == NULL) {
   5402             return SOC_E_INTERNAL;
   5403         }
   5404         SOC_IF_ERROR_RETURN(phymod_phy_autoneg_line_side_set(pm_phy, value));
   5405     }
   5406 
   5407 
   5408     return(SOC_E_NONE);
   5409 }
   5410 
   5411 STATIC int
   5412 phy8806x_autoneg_line_side_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5413 {
   5414     phymod_phy_access_t     *pm_phy;
   5415     int                     idx;
   5416 
   5417     /* loop through all cores */
   5418     for (idx = 0; idx < pmc->num_phys; idx++) {
   5419         pm_phy = &pmc->phy[idx]->pm_phy;
   5420 
   5421         if (pm_phy == NULL) {
   5422             return SOC_E_INTERNAL;
   5423         }
   5424         SOC_IF_ERROR_RETURN(phymod_phy_autoneg_line_side_get(pm_phy, value));
   5425     }
   5426 
   5427     return(SOC_E_NONE);
   5428 }
   5429 
   5430 /* 
   5431  * phy8806x_cl72_enable_get
   5432  */
   5433 STATIC int
   5434 phy8806x_cl72_enable_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5435 {
   5436     phymod_phy_access_t  *pm_phy;
   5437 
   5438     /* just take the value from the first phy */
   5439     if (pmc->phy[0] == NULL) {
   5440         return SOC_E_INTERNAL;
   5441     }
   5442     pm_phy = &pmc->phy[0]->pm_phy;
   5443 
   5444     if (pm_phy == NULL) {
   5445          return SOC_E_INTERNAL;
   5446     }
   5447 
   5448     SOC_IF_ERROR_RETURN(phymod_phy_cl72_get(pm_phy, value));
   5449 
   5450     return(SOC_E_NONE);
   5451 }
   5452 
   5453 /* 
   5454  * phy8806x_cl72_status_get
   5455  */
   5456 STATIC int
   5457 phy8806x_cl72_status_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5458 {
   5459     phymod_phy_access_t  *pm_phy;
   5460     phymod_cl72_status_t status;
   5461     phymod_phy_access_t pm_phy_copy;
   5462     soc_phymod_core_t *soc_core;
   5463 
   5464     /* just take the value from the first phy */
   5465     if (pmc->phy[0] == NULL) {
   5466         return SOC_E_INTERNAL;
   5467     }
   5468     pm_phy = &pmc->phy[0]->pm_phy;
   5469 
   5470     if (pm_phy == NULL) {
   5471         return SOC_E_INTERNAL;
   5472     }
   5473 
   5474     /* Make a copy of the phy access and overwrite the desired lane */
   5475     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   5476 
   5477     soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   5478     pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   5479 
   5480     SOC_IF_ERROR_RETURN(phymod_phy_cl72_status_get(&pm_phy_copy, &status));
   5481     *value = status.locked;
   5482 
   5483     return(SOC_E_NONE);
   5484 }
   5485 
   5486 /* 
   5487  * phy8806x_prbs_rx_status_get
   5488  */
   5489 STATIC int
   5490 phy8806x_prbs_rx_status_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5491 {
   5492     phymod_phy_access_t    *pm_phy;
   5493     phymod_prbs_status_t   prbs_tmp;
   5494 
   5495     /* just take the value from the first phy */
   5496     if (pmc->phy[0] == NULL) {
   5497         return SOC_E_INTERNAL;
   5498     }
   5499     pm_phy = &pmc->phy[0]->pm_phy;
   5500 
   5501     if (pm_phy == NULL) {
   5502         return SOC_E_INTERNAL;
   5503     }
   5504     /* $$$ Need to add diagnostic API */
   5505     SOC_IF_ERROR_RETURN
   5506         (phymod_phy_prbs_status_get(pm_phy, 0, &prbs_tmp));
   5507     if (prbs_tmp.prbs_lock == 0) {
   5508         *value = -1;
   5509     } else if ((prbs_tmp.prbs_lock_loss == 1) && (prbs_tmp.prbs_lock == 1)) {
   5510         *value = -2;
   5511     } else {
   5512         *value = prbs_tmp.error_count;
   5513     }     
   5514 
   5515     return(SOC_E_NONE);
   5516 }
   5517 
   5518 /* 
   5519  * phy8806x_loopback_internal_get
   5520  */
   5521 STATIC int 
   5522 phy8806x_loopback_internal_get(soc_phymod_ctrl_t *pmc, int sys, uint32 *value)
   5523 {
   5524     phymod_phy_access_t  *pm_phy;
   5525     uint32_t               enable;
   5526 
   5527     /* just take the value from the first phy */
   5528     if (pmc->phy[0] == NULL) {
   5529         return SOC_E_INTERNAL;
   5530     }
   5531     pm_phy = &pmc->phy[0]->pm_phy;
   5532 
   5533     if (pm_phy == NULL) {
   5534         return SOC_E_INTERNAL;
   5535     }
   5536 
   5537     if (sys) {
   5538         SOC_IF_ERROR_RETURN
   5539             (phymod_phy_loopback_get(pm_phy, phymodLoopbackSysGlobal, &enable));
   5540     } else {
   5541         SOC_IF_ERROR_RETURN
   5542             (phymod_phy_loopback_get(pm_phy, phymodLoopbackGlobal, &enable));
   5543 
   5544     }
   5545 
   5546     *value = enable;
   5547 
   5548     return(SOC_E_NONE);
   5549 }
   5550 
   5551 
   5552 /* 
   5553  * phy8806x_loopback_pmd_get (this is the PMD global loopback)
   5554  */
   5555 STATIC int 
   5556 phy8806x_loopback_pmd_get(soc_phymod_ctrl_t *pmc, int sys, uint32 *value)
   5557 {
   5558     phymod_phy_access_t    *pm_phy;
   5559     uint32_t               enable;
   5560 
   5561     /* just take the value from the first phy */
   5562     if (pmc->phy[0] == NULL) {
   5563         return SOC_E_INTERNAL;
   5564     }
   5565     pm_phy = &pmc->phy[0]->pm_phy;
   5566 
   5567     if (pm_phy == NULL) {
   5568         return SOC_E_INTERNAL;
   5569     }
   5570 
   5571     if (sys) {
   5572         SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackSysGlobalPMD, &enable));
   5573     } else {
   5574         SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackGlobalPMD, &enable));
   5575     }
   5576     *value = enable;
   5577     return(SOC_E_NONE);
   5578 }
   5579 
   5580 
   5581 /* 
   5582  * phy8806x_loopback_remote_get
   5583  */
   5584 STATIC int 
   5585 phy8806x_loopback_remote_get(soc_phymod_ctrl_t *pmc, int sys, uint32 *value)
   5586 {
   5587     phymod_phy_access_t    *pm_phy;
   5588     uint32_t               enable;
   5589 
   5590     /* just take the value from the first phy */
   5591     if (pmc->phy[0] == NULL) {
   5592         return SOC_E_INTERNAL;
   5593     }
   5594     pm_phy = &pmc->phy[0]->pm_phy;
   5595 
   5596     if (pm_phy == NULL) {
   5597         return SOC_E_INTERNAL;
   5598     }
   5599 
   5600     if (sys) {
   5601         SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackSysRemotePMD, &enable));
   5602     } else {
   5603         SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackRemotePMD, &enable));
   5604     }
   5605 
   5606     *value = enable;
   5607     return(SOC_E_NONE);
   5608 }
   5609 
   5610 /* 
   5611  * phy8806x_loopback_pcs_get
   5612  */
   5613 /* STATIC */ int 
   5614 phy8806x_loopback_pcs_get(soc_phymod_ctrl_t *pmc, int sys, uint32 *value)
   5615 {
   5616     phymod_phy_access_t    *pm_phy;
   5617     uint32_t               enable;
   5618 
   5619     /* just take the value from the first phy */
   5620     if (pmc->phy[0] == NULL) {
   5621         return SOC_E_INTERNAL;
   5622     }
   5623     pm_phy = &pmc->phy[0]->pm_phy;
   5624 
   5625     if (pm_phy == NULL) {
   5626         return SOC_E_INTERNAL;
   5627     }
   5628 
   5629     if (sys) {
   5630         SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackSysGlobalPCS, &enable));
   5631     } else {
   5632         SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackGlobalPCS, &enable));
   5633     }
   5634     *value = enable;
   5635     return(SOC_E_NONE);
   5636 }
   5637 
   5638 /* 
   5639  * phy8806x_loopback_remote_pcs_get
   5640  */
   5641 STATIC int 
   5642 phy8806x_loopback_remote_pcs_get(soc_phymod_ctrl_t *pmc, int sys, uint32 *value)
   5643 {
   5644     phymod_phy_access_t    *pm_phy;
   5645     uint32_t               enable;
   5646 
   5647     /* just take the value from the first phy */
   5648     if (pmc->phy[0] == NULL) {
   5649         return SOC_E_INTERNAL;
   5650     }
   5651     pm_phy = &pmc->phy[0]->pm_phy;
   5652 
   5653     if (pm_phy == NULL) {
   5654         return SOC_E_INTERNAL;
   5655     }
   5656 
   5657     if (sys) {
   5658         SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackSysRemotePCS, &enable));
   5659     } else {
   5660         SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackRemotePCS, &enable));
   5661     }
   5662     *value = enable;
   5663     return(SOC_E_NONE);
   5664 }
   5665 
   5666 /* 
   5667  * phy8806x_fec_get
   5668  */
   5669 STATIC int 
   5670 phy8806x_fec_enable_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5671 {
   5672     phymod_phy_access_t    *pm_phy;
   5673     uint32_t               enable;
   5674 
   5675     /* just take the value from the first phy */
   5676     if (pmc->phy[0] == NULL) {
   5677         return SOC_E_INTERNAL;
   5678     }
   5679     pm_phy = &pmc->phy[0]->pm_phy;
   5680 
   5681     if (pm_phy == NULL) {
   5682         return SOC_E_INTERNAL;
   5683     }
   5684 
   5685     SOC_IF_ERROR_RETURN(phymod_phy_fec_enable_get(pm_phy,  &enable));
   5686     *value = enable;
   5687 
   5688     return(SOC_E_NONE);
   5689 }
   5690 
   5691 
   5692 /* 
   5693  * phy8806x_tx_fir_pre_get
   5694  */
   5695 STATIC int
   5696 phy8806x_tx_fir_pre_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5697 {
   5698     phymod_phy_access_t *pm_phy, pm_phy_copy;
   5699     phymod_tx_t         phymod_tx;
   5700     soc_phymod_core_t *soc_core;
   5701 
   5702     pm_phy = &pmc->phy[0]->pm_phy;
   5703 
   5704     if (pm_phy == NULL) {
   5705         return SOC_E_INTERNAL;
   5706     }
   5707     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   5708     soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   5709     pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   5710 
   5711 
   5712     SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   5713     *value = phymod_tx.pre;
   5714 
   5715     return(SOC_E_NONE);
   5716 }
   5717 
   5718 /* 
   5719  * phy8806x_tx_fir_main_get
   5720  */
   5721 STATIC int
   5722 phy8806x_tx_fir_main_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5723 {
   5724     phymod_phy_access_t *pm_phy, pm_phy_copy;
   5725     phymod_tx_t         phymod_tx;
   5726     soc_phymod_core_t *soc_core;
   5727 
   5728     pm_phy = &pmc->phy[0]->pm_phy;
   5729 
   5730     if (pm_phy == NULL) {
   5731         return SOC_E_INTERNAL;
   5732     }
   5733     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   5734     soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   5735     pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   5736 
   5737 
   5738     SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   5739     *value = phymod_tx.main;
   5740 
   5741     return(SOC_E_NONE);
   5742 }
   5743 
   5744 /* 
   5745  * phy8806x_tx_fir_post_get
   5746  */
   5747 STATIC int
   5748 phy8806x_tx_fir_post_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5749 {
   5750     phymod_phy_access_t *pm_phy, pm_phy_copy;
   5751     phymod_tx_t         phymod_tx;
   5752     soc_phymod_core_t *soc_core;
   5753 
   5754     pm_phy = &pmc->phy[0]->pm_phy;
   5755 
   5756     if (pm_phy == NULL) {
   5757         return SOC_E_INTERNAL;
   5758     }
   5759     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   5760     soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   5761     pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   5762 
   5763 
   5764     SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   5765     *value = phymod_tx.post;
   5766 
   5767     return(SOC_E_NONE);
   5768 }
   5769 
   5770 /* 
   5771  * phy8806x_tx_fir_post2_get
   5772  */
   5773 STATIC int
   5774 phy8806x_tx_fir_post2_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5775 {
   5776     phymod_phy_access_t *pm_phy, pm_phy_copy;
   5777     phymod_tx_t         phymod_tx;
   5778     soc_phymod_core_t *soc_core;
   5779 
   5780     pm_phy = &pmc->phy[0]->pm_phy;
   5781 
   5782     if (pm_phy == NULL) {
   5783         return SOC_E_INTERNAL;
   5784     }
   5785     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   5786     soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   5787     pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   5788 
   5789 
   5790     SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   5791     *value = phymod_tx.post2;
   5792 
   5793     return(SOC_E_NONE);
   5794 }
   5795 
   5796 /* 
   5797  * phy8806x_tx_fir_post3_get
   5798  */
   5799 STATIC int
   5800 phy8806x_tx_fir_post3_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5801 {
   5802     phymod_phy_access_t *pm_phy, pm_phy_copy;
   5803     phymod_tx_t         phymod_tx;
   5804     soc_phymod_core_t *soc_core;
   5805 
   5806     pm_phy = &pmc->phy[0]->pm_phy;
   5807 
   5808     if (pm_phy == NULL) {
   5809         return SOC_E_INTERNAL;
   5810     }
   5811     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   5812     soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   5813     pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   5814 
   5815 
   5816     SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   5817     *value = phymod_tx.post3;
   5818 
   5819     return(SOC_E_NONE);
   5820 }
   5821 
   5822 
   5823 /* 
   5824  * phy8806x_per_lane_preemphasis_get
   5825  */
   5826 STATIC int
   5827 phy8806x_per_lane_preemphasis_get(soc_phymod_ctrl_t *pmc, int lane, uint32 *value)
   5828 {
   5829     soc_phymod_phy_t    *p_phy;
   5830     uint32              lane_map;
   5831     phymod_phy_access_t pm_phy_copy, *pm_phy;
   5832     phymod_tx_t         phymod_tx;
   5833     soc_phymod_core_t *soc_core;
   5834 
   5835     /* locate the desired phy and lane */
   5836     SOC_IF_ERROR_RETURN(_phy8806x_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map));
   5837 
   5838     /* Make a copy of the phy access and overwrite the desired lane */
   5839     pm_phy = &p_phy->pm_phy;
   5840     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   5841     soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   5842     pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   5843     pm_phy_copy.access.lane_mask = lane_map;
   5844 
   5845     SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   5846     *value = phymod_tx.pre  | (phymod_tx.main << 8) | (phymod_tx.post << 16);
   5847 
   5848     return(SOC_E_NONE);
   5849 }
   5850 
   5851 
   5852 /* 
   5853  * phy8806x_preemphasis_get
   5854  */
   5855 STATIC int
   5856 phy8806x_preemphasis_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5857 {
   5858     phymod_phy_access_t *pm_phy, pm_phy_copy;
   5859     phymod_tx_t         phymod_tx;
   5860     soc_phymod_core_t *soc_core;
   5861 
   5862     pm_phy = &pmc->phy[0]->pm_phy;
   5863 
   5864     if (pm_phy == NULL) {
   5865         return SOC_E_INTERNAL;
   5866     }
   5867     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   5868     soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   5869     pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   5870 
   5871 
   5872     SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   5873     *value = phymod_tx.pre  | (phymod_tx.main << 8) | (phymod_tx.post << 16);
   5874 
   5875     return(SOC_E_NONE);
   5876 }
   5877 
   5878 
   5879 /* 
   5880  * phy8806x_per_lane_driver_current_get
   5881  */
   5882 STATIC int
   5883 phy8806x_per_lane_driver_current_get(soc_phymod_ctrl_t *pmc, int lane, uint32 *value)
   5884 {
   5885     soc_phymod_phy_t    *p_phy;
   5886     uint32              lane_map;
   5887     phymod_phy_access_t pm_phy_copy, *pm_phy;
   5888     phymod_tx_t         phymod_tx;
   5889     soc_phymod_core_t *soc_core;
   5890 
   5891     /* locate the desired phy and lane */
   5892     SOC_IF_ERROR_RETURN(_phy8806x_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map));
   5893 
   5894     /* Make a copy of the phy access and overwrite the desired lane */
   5895     pm_phy = &p_phy->pm_phy;
   5896     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   5897     soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   5898     pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   5899     pm_phy_copy.access.lane_mask = lane_map;
   5900 
   5901     SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx));
   5902     *value = phymod_tx.amp;
   5903 
   5904     return(SOC_E_NONE);
   5905 }
   5906 
   5907 STATIC int
   5908 phy8806x_firmware_dfe_enable_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5909 {
   5910     phymod_phy_access_t    pm_phy_copy, *pm_phy;
   5911     phymod_firmware_lane_config_t fw_config;
   5912     soc_phymod_core_t *soc_core;
   5913 
   5914     /* just take the value from the first phy */
   5915     if (pmc->phy[0] == NULL) {
   5916         return SOC_E_INTERNAL;
   5917     }
   5918 
   5919     pm_phy = &pmc->phy[0]->pm_phy;
   5920     if (pm_phy == NULL) {
   5921         return SOC_E_INTERNAL;
   5922     }
   5923 
   5924     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   5925     soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   5926     pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   5927 
   5928     SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config));
   5929 
   5930     if (fw_config.DfeOn) {
   5931         *value = 1;
   5932     } else {
   5933         *value = 0;
   5934     }
   5935 
   5936     return(SOC_E_NONE);
   5937 }
   5938 
   5939 STATIC int
   5940 phy8806x_firmware_unreliable_los_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5941 {
   5942     phymod_phy_access_t    pm_phy_copy, *pm_phy;
   5943     phymod_firmware_lane_config_t fw_config;
   5944     soc_phymod_core_t *soc_core;
   5945 
   5946     /* just take the value from the first phy */
   5947     if (pmc->phy[0] == NULL) {
   5948         return SOC_E_INTERNAL;
   5949     }
   5950 
   5951     pm_phy = &pmc->phy[0]->pm_phy;
   5952     if (pm_phy == NULL) {
   5953         return SOC_E_INTERNAL;
   5954     }
   5955 
   5956     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   5957     soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   5958     pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   5959 
   5960     SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config));
   5961 
   5962     if (fw_config.UnreliableLos) {
   5963         *value = 1;
   5964     } else {
   5965         *value = 0;
   5966     }
   5967 
   5968     return(SOC_E_NONE);
   5969 }
   5970 
   5971 STATIC int
   5972 phy8806x_firmware_lp_dfe_enable_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   5973 {
   5974     phymod_phy_access_t    pm_phy_copy, *pm_phy;
   5975     phymod_firmware_lane_config_t fw_config;
   5976     soc_phymod_core_t *soc_core;
   5977 
   5978     /* just take the value from the first phy */
   5979     if (pmc->phy[0] == NULL) {
   5980         return SOC_E_INTERNAL;
   5981     }
   5982 
   5983     pm_phy = &pmc->phy[0]->pm_phy;
   5984     if (pm_phy == NULL) {
   5985         return SOC_E_INTERNAL;
   5986     }
   5987 
   5988     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   5989     soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   5990     pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   5991 
   5992     SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config));
   5993 
   5994     if (fw_config.LpDfeOn) {
   5995         *value = 1;
   5996     } else {
   5997         *value = 0;
   5998     }
   5999 
   6000     return(SOC_E_NONE);
   6001 }
   6002 
   6003 /*
   6004  * tscf_firmware_dfe_enable_get
   6005  */
   6006 STATIC int
   6007 phy8806x_firmware_br_dfe_enable_get(soc_phymod_ctrl_t *pmc, uint32 *value)
   6008 {
   6009     phymod_phy_access_t    pm_phy_copy, *pm_phy;
   6010     phymod_firmware_lane_config_t fw_config;
   6011     soc_phymod_core_t *soc_core;
   6012 
   6013     /* just take the value from the first phy */
   6014     if (pmc->phy[0] == NULL) {
   6015         return SOC_E_INTERNAL;
   6016     }
   6017 
   6018     pm_phy = &pmc->phy[0]->pm_phy;
   6019     if (pm_phy == NULL) {
   6020         return SOC_E_INTERNAL;
   6021     }
   6022 
   6023     sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy));
   6024     soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access);
   6025     pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine;
   6026 
   6027     SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config));
   6028 
   6029     if (fw_config.ForceBrDfe) {
   6030         *value = 1;
   6031     } else {
   6032         *value = 0;
   6033     }
   6034 
   6035     return(SOC_E_NONE);
   6036 }
   6037 
   6038 
   6039 /*
   6040  * Function:
   6041  *      phy_8806x_control_get
   6042  * Purpose:
   6043  *      Get current control settings of the PHY. 
   6044  * Parameters:
   6045  *      unit  - BCM unit number.
   6046  *      port  - Port number. 
   6047  *      type  - Control to update 
   6048  *      value - (OUT) Current setting for the control 
   6049  * Returns:     
   6050  *      SOC_E_NONE
   6051  */
   6052 STATIC int
   6053 phy_8806x_control_get(int unit, soc_port_t port, soc_phy_control_t type, uint32 *value)
   6054 {
   6055     int                 rv;
   6056     phy_ctrl_t          *pc;
   6057     soc_phymod_ctrl_t   *pmc;
   6058     /* phy8806x_config_t       *pCfg; */
   6059 
   6060     if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) {
   6061         return (SOC_E_PARAM);
   6062     }
   6063 
   6064     /* locate phy control */
   6065     pc = EXT_PHY_SW_STATE(unit, port);
   6066     if (pc == NULL) {
   6067         return SOC_E_INTERNAL;
   6068     }
   6069 
   6070 #if defined(INCLUDE_FCMAP)
   6071     /* Skip all loopback get for FC */
   6072     if ((pc->fcmap_enable) && 
   6073          (type == SOC_PHY_CONTROL_LOOPBACK_REMOTE_PCS_BYPASS)) {
   6074         return SOC_E_NONE;
   6075     }
   6076 #endif
   6077 
   6078     pmc = &pc->phymod_ctrl;
   6079     /* pCfg = (phy8806x_config_t *) pc->driver_data; */
   6080 
   6081     switch(type) {
   6082     case SOC_PHY_CONTROL_UNRELIABLE_LOS:
   6083        rv = phy8806x_firmware_unreliable_los_get(pmc, value);
   6084        break;
   6085     case SOC_PHY_CONTROL_FIRMWARE_DFE_ENABLE:
   6086        rv = phy8806x_firmware_dfe_enable_get(pmc, value);
   6087        break;
   6088     case SOC_PHY_CONTROL_FIRMWARE_LP_DFE_ENABLE:
   6089        rv = phy8806x_firmware_lp_dfe_enable_get(pmc, value);
   6090        break;
   6091     case SOC_PHY_CONTROL_FIRMWARE_BR_DFE_ENABLE:
   6092        rv = phy8806x_firmware_br_dfe_enable_get(pmc, value);
   6093        break; 
   6094    /* CL72 */
   6095     case SOC_PHY_CONTROL_CL72:
   6096       if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) {
   6097         *value = *value | PORT_SYS_SIDE_CTRL;
   6098       }
   6099       rv = phy8806x_cl72_enable_get(pmc, value);
   6100       break;
   6101     case SOC_PHY_CONTROL_CL72_STATUS:
   6102       rv = phy8806x_cl72_status_get(pmc, value);
   6103       break;
   6104 
   6105     case SOC_PHY_CONTROL_PRBS_RX_STATUS:
   6106       rv = phy8806x_prbs_rx_status_get(pmc, value);
   6107       break;
   6108 
   6109     /* LOOPBACK */
   6110     case SOC_PHY_CONTROL_LOOPBACK_INTERNAL:
   6111        rv = phy8806x_loopback_internal_get(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value);
   6112        break;
   6113     case SOC_PHY_CONTROL_LOOPBACK_REMOTE:
   6114        rv = phy8806x_loopback_remote_get(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value);
   6115        break;
   6116     case SOC_PHY_CONTROL_LOOPBACK_REMOTE_PCS_BYPASS:
   6117        rv = phy8806x_loopback_remote_pcs_get(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value);
   6118        break;
   6119     case SOC_PHY_CONTROL_LOOPBACK_PMD:
   6120        rv = phy8806x_loopback_pmd_get(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value);
   6121        break;
   6122 
   6123     /* FEC */
   6124     case SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION:
   6125         *value = 0;
   6126         if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) {
   6127             LOG_CLI((BSL_META_U(unit, "PHYCTRL_SYS_SIDE_CTRL \n")));
   6128             *value = *value | PORT_SYS_SIDE_CTRL;
   6129         }
   6130       rv = phy8806x_fec_enable_get(pmc, value);
   6131       if (*value != 1) /* Clear if the FEC is not CL74 (value 1) */
   6132             *value = 0;
   6133       break;
   6134 
   6135     case SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION_CL91:
   6136         *value = 0;
   6137         if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) {
   6138             LOG_CLI((BSL_META_U(unit, "PHYCTRL_SYS_SIDE_CTRL \n")));
   6139             *value = *value | PORT_SYS_SIDE_CTRL;
   6140         }
   6141       rv = phy8806x_fec_enable_get(pmc, value);
   6142 
   6143       if (*value == 2) /* Set only if the FEC is CL91 (value 2) */
   6144         *value = 1;    
   6145       else              
   6146         *value = 0;   /* Clear if the FEC is not set to CL91 (value 2) */
   6147           
   6148       break;
   6149 
   6150     case SOC_PHY_CONTROL_FORCED_SPEED_LINE_SIDE:
   6151        rv = phy8806x_forced_speed_line_side_get(pmc, value);
   6152        break; 
   6153     case SOC_PHY_CONTROL_AUTONEG_LINE_SIDE:
   6154        rv = phy8806x_autoneg_line_side_get(pmc, value);
   6155        break;
   6156     case SOC_PHY_CONTROL_EGRESS_FLOW_CONTROL_MODE:
   6157         rv = phy8806x_flow_control_mode_get(pmc, 0, value);
   6158         break; 
   6159     case SOC_PHY_CONTROL_INGRESS_FLOW_CONTROL_MODE:
   6160         rv = phy8806x_flow_control_mode_get(pmc, 1, value);
   6161         break;
   6162     case SOC_PHY_CONTROL_PSM_COS_BMP:
   6163         rv = phy8806x_psm_cos_bmp_get(pmc, value);
   6164         break;
   6165     case SOC_PHY_CONTROL_PFC_USE_IP_COS:
   6166         rv = phy8806x_pfc_use_ip_cos_get(pmc, value);
   6167         break;
   6168     /* PREEMPHASIS */
   6169     case SOC_PHY_CONTROL_PREEMPHASIS_LANE0:
   6170         rv = phy8806x_per_lane_preemphasis_get(pmc, 0, value);
   6171         break;
   6172     case SOC_PHY_CONTROL_PREEMPHASIS_LANE1:
   6173         rv = phy8806x_per_lane_preemphasis_get(pmc, 1, value);
   6174         break;
   6175     case SOC_PHY_CONTROL_PREEMPHASIS_LANE2:
   6176         rv = phy8806x_per_lane_preemphasis_get(pmc, 2, value);
   6177         break;
   6178     case SOC_PHY_CONTROL_PREEMPHASIS_LANE3:
   6179         rv = phy8806x_per_lane_preemphasis_get(pmc, 3, value);
   6180         break;
   6181     case SOC_PHY_CONTROL_PREEMPHASIS:
   6182         rv = phy8806x_preemphasis_get(pmc, value);
   6183             break;
   6184     case SOC_PHY_CONTROL_TX_FIR_PRE:
   6185         /* assume they are all the same as lane 0 */
   6186         rv = phy8806x_tx_fir_pre_get(pmc, value);
   6187         break;
   6188     case SOC_PHY_CONTROL_TX_FIR_MAIN:
   6189         /* assume they are all the same as lane 0 */
   6190         rv = phy8806x_tx_fir_main_get(pmc, value);
   6191         break;
   6192     case SOC_PHY_CONTROL_TX_FIR_POST:
   6193         /* assume they are all the same as lane 0 */
   6194         rv = phy8806x_tx_fir_post_get(pmc, value);
   6195         break;
   6196     case SOC_PHY_CONTROL_TX_FIR_POST2:
   6197         /* assume they are all the same as lane 0 */
   6198         rv = phy8806x_tx_fir_post2_get(pmc, value);
   6199         break;
   6200     case SOC_PHY_CONTROL_TX_FIR_POST3:
   6201         /* assume they are all the same as lane 0 */
   6202         rv = phy8806x_tx_fir_post3_get(pmc, value);
   6203         break;
   6204 
   6205     /* DRIVER CURRENT */
   6206     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0:
   6207         rv = phy8806x_per_lane_driver_current_get(pmc, 0, value);
   6208         break;
   6209     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1:
   6210         rv = phy8806x_per_lane_driver_current_get(pmc, 1, value);
   6211         break;
   6212     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2:
   6213         rv = phy8806x_per_lane_driver_current_get(pmc, 2, value);
   6214         break;
   6215     case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3:
   6216         rv = phy8806x_per_lane_driver_current_get(pmc, 3, value);
   6217         break;
   6218     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   6219         rv = phy8806x_per_lane_driver_current_get(pmc, 0, value);
   6220         break;
   6221     case SOC_PHY_CONTROL_SOFTWARE_RX_LOS:
   6222     case SOC_PHY_CONTROL_EEE:
   6223     case SOC_PHY_CONTROL_EEE_AUTO:
   6224         *value = FALSE;
   6225         rv = SOC_E_NONE;
   6226         break;
   6227     case SOC_PHY_CONTROL_INTERFACE:
   6228         rv = phy_8806x_interface_get(unit, port, (soc_port_if_t *)value);
   6229         break;
   6230    /* UNAVAIL */
   6231     default:
   6232         rv = SOC_E_UNAVAIL;
   6233         break; 
   6234     }
   6235     return rv;
   6236 }     
   6237 
   6238 /*
   6239  * Function:
   6240  *      phy_8806x_reg_read
   6241  * Purpose:
   6242  *      Routine to read PHY register
   6243  * Parameters:
   6244  *      unit         - BCM unit number
   6245  *      port         - Port number
   6246  *      flags        - Flags which specify the register type
   6247  *      phy_reg_addr - Encoded register address
   6248  *      phy_data     - (OUT) Value read from PHY register
   6249  * Note:
   6250  *      This register read function is not thread safe. Higher level
   6251  * function that calls this function must obtain a per port lock
   6252  * to avoid overriding register page mapping between threads.
   6253  */
   6254 STATIC int
   6255 phy_8806x_reg_read(int unit, soc_port_t port, uint32 flags,
   6256                   uint32 phy_reg_addr, uint32 *phy_reg_data)
   6257 {
   6258     phy_ctrl_t *pc;
   6259     soc_phymod_ctrl_t *pmc;
   6260     phymod_phy_access_t *pm_phy;
   6261     int idx=0;
   6262     uint32 data = 0;
   6263 
   6264     pc = EXT_PHY_SW_STATE(unit, port);
   6265     if (pc == NULL) {
   6266         return SOC_E_INTERNAL;
   6267     }
   6268 
   6269     pmc = &pc->phymod_ctrl;
   6270     pm_phy = &pmc->phy[idx]->pm_phy;
   6271     if (flags & SOC_PHY_I2C_DATA8) {
   6272         SOC_IF_ERROR_RETURN
   6273             (phymod_phy_i2c_read(pm_phy, 0, SOC_PHY_I2C_DEVAD(phy_reg_addr), SOC_PHY_I2C_REGAD(phy_reg_addr), 1, (uint8 *)&data));
   6274         data = LE2HOST32(data);
   6275         *phy_reg_data = data & 0xff;
   6276     } else if (flags & SOC_PHY_I2C_DATA16) {
   6277         SOC_IF_ERROR_RETURN
   6278             (phymod_phy_i2c_read(pm_phy, 0, SOC_PHY_I2C_DEVAD(phy_reg_addr), SOC_PHY_I2C_REGAD(phy_reg_addr), 2, (uint8 *)&data));
   6279         data = LE2HOST32(data);
   6280         *phy_reg_data = data & 0xffff;
   6281     } else if (flags & SOC_PHY_PVT_DATA) {
   6282         SOC_IF_ERROR_RETURN
   6283             (phymod_phy_private_read(pm_phy, phy_reg_addr, phy_reg_data));
   6284     } else {
   6285         SOC_IF_ERROR_RETURN
   6286             (phymod_phy_reg_read(pm_phy, phy_reg_addr, phy_reg_data));
   6287     }
   6288 
   6289     return SOC_E_NONE;
   6290 }
   6291 
   6292 /*
   6293  * Function:
   6294  *      phy_8806x_reg_write
   6295  * Purpose:
   6296  *      Routine to write PHY register
   6297  * Parameters:
   6298  *      uint         - BCM unit number
   6299  *      pc           - PHY state
   6300  *      flags        - Flags which specify the register type
   6301  *      phy_reg_addr - Encoded register address
   6302  *      phy_data     - Value write to PHY register
   6303  * Note:
   6304  *      This register read function is not thread safe. Higher level
   6305  * function that calls this function must obtain a per port lock
   6306  * to avoid overriding register page mapping between threads.
   6307  */
   6308 STATIC int
   6309 phy_8806x_reg_write(int unit, soc_port_t port, uint32 flags,
   6310                    uint32 phy_reg_addr, uint32 phy_reg_data)
   6311 {
   6312     phy_ctrl_t *pc;
   6313     soc_phymod_ctrl_t *pmc;
   6314     phymod_phy_access_t *pm_phy;
   6315     int idx;
   6316     uint32 data = 0;
   6317 
   6318     pc = EXT_PHY_SW_STATE(unit, port);
   6319     if (pc == NULL) {
   6320         return SOC_E_INTERNAL;
   6321     }
   6322 
   6323     pmc = &pc->phymod_ctrl;
   6324     for (idx = 0; idx < pmc->num_phys; idx++) {
   6325         pm_phy = &pmc->phy[idx]->pm_phy;
   6326         if (flags & SOC_PHY_I2C_DATA8) {
   6327             data = phy_reg_data & 0xFF;
   6328             SOC_IF_ERROR_RETURN
   6329                 (phymod_phy_i2c_write(pm_phy, 0, SOC_PHY_I2C_DEVAD(phy_reg_addr), SOC_PHY_I2C_REGAD(phy_reg_addr), 1, (uint8 *)&data));
   6330         } else if (flags & SOC_PHY_I2C_DATA16) {
   6331             data = phy_reg_data & 0xFFFF;
   6332             SOC_IF_ERROR_RETURN
   6333                 (phymod_phy_i2c_write(pm_phy, 0, SOC_PHY_I2C_DEVAD(phy_reg_addr), SOC_PHY_I2C_REGAD(phy_reg_addr), 2, (uint8 *)&data));
   6334         } else if (flags & SOC_PHY_PVT_DATA) {
   6335             SOC_IF_ERROR_RETURN
   6336                 (phymod_phy_private_write(pm_phy, phy_reg_addr, phy_reg_data));
   6337         } else {
   6338             SOC_IF_ERROR_RETURN
   6339                 (phymod_phy_reg_write(pm_phy, phy_reg_addr, phy_reg_data));
   6340         }
   6341     }
   6342     return SOC_E_NONE;
   6343 }
   6344 
   6345 /*
   6346  * Function:
   6347  *      phy_8806x_reg_modify
   6348  * Purpose:
   6349  *      Routine to write PHY register
   6350  * Parameters:
   6351  *      uint         - BCM unit number
   6352  *      pc           - PHY state
   6353  *      flags        - Flags which specify the register type
   6354  *      phy_reg_addr - Encoded register address
   6355  *      phy_mo_data  - New value for the bits specified in phy_mo_mask
   6356  *      phy_mo_mask  - Bit mask to modify
   6357  * Note:
   6358  *      This function is not thread safe. Higher level
   6359  * function that calls this function must obtain a per port lock
   6360  * to avoid overriding register page mapping between threads.
   6361  */
   6362 STATIC int
   6363 phy_8806x_reg_modify(int unit, soc_port_t port, uint32 flags,
   6364                     uint32 phy_reg_addr, uint32 phy_data,
   6365                     uint32 phy_data_mask)
   6366 {
   6367     phy_ctrl_t *pc;
   6368     soc_phymod_ctrl_t *pmc;
   6369     phymod_phy_access_t *pm_phy;
   6370     uint32 data32, tmp;
   6371     int idx;
   6372 
   6373     pc = EXT_PHY_SW_STATE(unit, port);
   6374     if (pc == NULL) {
   6375         return SOC_E_INTERNAL;
   6376     }
   6377 
   6378     pmc = &pc->phymod_ctrl;
   6379     for (idx = 0; idx < pmc->num_phys; idx++) {
   6380         pm_phy = &pmc->phy[idx]->pm_phy;
   6381         SOC_IF_ERROR_RETURN
   6382             (phymod_phy_reg_read(pm_phy, phy_reg_addr, &data32));
   6383         tmp = data32;
   6384         data32 &= ~(phy_data_mask);
   6385         data32 |= (phy_data & phy_data_mask);
   6386         if (data32 != tmp) {
   6387             SOC_IF_ERROR_RETURN
   6388                 (phymod_phy_reg_write(pm_phy, phy_reg_addr, data32));
   6389         }
   6390     }
   6391     return SOC_E_NONE;
   6392 }
   6393 
   6394 /*
   6395  * Function:
   6396  *      phy_8806x_multi_reg_read
   6397  * Purpose:
   6398  *      Routine to read PHY I2C data
   6399  * Parameters:
   6400  *      unit         - BCM unit number
   6401  *      port         - Port number
   6402  *      flags        - Flags which specify the register type
   6403  *      dev_addr     - device address
   6404  *      offset       - IC map offset
   6405  *      maxsize      - size of buffer provided to read
   6406  *      data         - (OUT) Value read from PHY register
   6407  *      actual_size  - (OUT) actual amount of data read
   6408  * Note:
   6409  *      This register read function is not thread safe. Higher level
   6410  * function that calls this function must obtain a per port lock
   6411  * to avoid overriding register page mapping between threads.
   6412  */
   6413 STATIC int
   6414 phy_8806x_multi_reg_read(int unit, soc_port_t port, uint32 flags,
   6415                uint32 dev_addr, uint32 offset, int max_size, uint8 *data, int *actual_size)
   6416 {
   6417     phy_ctrl_t *pc;
   6418     soc_phymod_ctrl_t *pmc;
   6419     phymod_phy_access_t *pm_phy;
   6420     int idx=0;
   6421 
   6422     pc = EXT_PHY_SW_STATE(unit, port);
   6423     if (pc == NULL) {
   6424         return SOC_E_INTERNAL;
   6425     }
   6426 
   6427     pmc = &pc->phymod_ctrl;
   6428     pm_phy = &pmc->phy[idx]->pm_phy;
   6429 
   6430     /* Endian unaware byte stream Returned */
   6431     *actual_size = 0;
   6432     SOC_IF_ERROR_RETURN
   6433         (phymod_phy_i2c_read(pm_phy, 0, dev_addr, offset, max_size, (uint8 *)data));
   6434     *actual_size = max_size;
   6435     return SOC_E_NONE;
   6436 }
   6437 
   6438 STATIC void
   6439 phy_8806x_cleanup(soc_phymod_ctrl_t *pmc)
   6440 {
   6441     int idx;
   6442     soc_phymod_phy_t *phy;
   6443     soc_phymod_core_t *core;
   6444 
   6445     for (idx = 0; idx < pmc->num_phys ; idx++) {
   6446         phy = pmc->phy[idx];
   6447         if (phy == NULL) {
   6448             LOG_WARN(BSL_LS_SOC_PHY,
   6449                      (BSL_META_U(pmc->unit,
   6450                                  "phy object is empty")));
   6451             continue;
   6452         }
   6453 
   6454         core = phy->core;
   6455 
   6456         /* Destroy core object if not used anymore */
   6457         if (core && core->ref_cnt) {
   6458             if (--core->ref_cnt == 0) {
   6459                 soc_phymod_core_destroy(pmc->unit, core);
   6460             }
   6461         }
   6462 
   6463         /* Destroy phy object */
   6464         if (phy) {
   6465             soc_phymod_phy_destroy(pmc->unit, phy);
   6466         }
   6467     }
   6468     pmc->num_phys = 0;
   6469 }
   6470 
   6471 STATIC void
   6472 phy_8806x_core_init(phy_ctrl_t *pc, soc_phymod_core_t *core,
   6473                    phymod_bus_t *core_bus, uint32 core_addr)
   6474 {
   6475     phymod_core_access_t *pm_core;
   6476     phymod_access_t *pm_acc;
   6477 
   6478     core->unit = pc->unit;
   6479     core->port = pc->port;
   6480     core->read = pc->read;
   6481     core->write = pc->write;
   6482     core->wrmask = pc->wrmask;
   6483 
   6484     pm_core = &core->pm_core;
   6485     phymod_core_access_t_init(pm_core);
   6486     pm_acc = &pm_core->access;
   6487     phymod_access_t_init(pm_acc);
   6488     PHYMOD_ACC_USER_ACC(pm_acc) = core;
   6489     PHYMOD_ACC_BUS(pm_acc) = core_bus;
   6490     PHYMOD_ACC_ADDR(pm_acc) = core_addr;
   6491     PHYMOD_ACC_EXT_ACC(pm_acc) = _8806x_xmod_command;
   6492 
   6493     if (soc_property_port_get(pc->unit, pc->port, "phy8806x_sim", 0) == 45) {
   6494         PHYMOD_ACC_F_CLAUSE45_SET(pm_acc);
   6495     }
   6496 
   6497     return;
   6498 }
   6499 
   6500 /*
   6501  * Function:
   6502  *      phy_8806x_probe
   6503  * Purpose:
   6504  *      xx
   6505  * Parameters:
   6506  *      pc->phy_id   (IN)
   6507  *      pc->unit     (IN)
   6508  *      pc->port     (IN)
   6509  *      pc->size     (OUT) - memory required by phy port
   6510  *      pc->dev_name (OUT) - set to port device name
   6511  *  
   6512  * Note:
   6513  */
   6514 STATIC int
   6515 phy_8806x_probe(int unit, phy_ctrl_t *pc)
   6516 {
   6517     int rv, idx;
   6518     uint32 lane_map, num_phys, core_id, phy_id /*, found */;
   6519     uint32 top_dev_rev_id;
   6520     phymod_bus_t core_bus;
   6521     phymod_dispatch_type_t phy_type;
   6522     phymod_core_access_t *pm_core;
   6523     phymod_phy_access_t *pm_phy;
   6524     phymod_access_t *pm_acc;
   6525     soc_phymod_ctrl_t *pmc;
   6526     soc_phymod_phy_t *phy;
   6527     soc_phymod_core_t *core;
   6528     soc_phymod_core_t core_probe;
   6529     soc_info_t *si;
   6530     phyident_core_info_t core_info[8];  
   6531     int array_max = 8;
   6532     int array_size = 0;
   6533     int port;
   6534     int phy_port;  /* physical port number */
   6535 
   6536     if (!(SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit))) {
   6537         /* Release the top level resets before the AXI reads. */
   6538         SOC_IF_ERROR_RETURN
   6539             (WRITE_TOP_SOFT_RESET_REG(unit, pc, 0xc000003f));
   6540     }
   6541 
   6542     SOC_IF_ERROR_RETURN
   6543         (READ_TOP_DEV_REV_ID_REG(unit, pc, &top_dev_rev_id));
   6544 
   6545     switch (top_dev_rev_id & 0xff) {
   6546         case 0x60:
   6547             pc->dev_name = "BCM88060";
   6548             break;
   6549 
   6550         case 0x61:
   6551             pc->dev_name = "BCM88061";
   6552             break;
   6553 
   6554         case 0x64:
   6555             pc->dev_name = "BCM88064";
   6556             break;
   6557 
   6558         case 0x68:
   6559             pc->dev_name = "BCM88068";
   6560             break;
   6561 
   6562         default:
   6563             break;
   6564     }
   6565 
   6566     /* Initialize PHY bus */
   6567     SOC_IF_ERROR_RETURN(phymod_bus_t_init(&core_bus));
   6568     core_bus.bus_name = "phy8806x"; 
   6569     core_bus.read = _8806x_reg_read; 
   6570     core_bus.write = _8806x_reg_write;
   6571 
   6572     /* Configure PHY bus properties */
   6573     PHYMOD_BUS_CAP_WR_MODIFY_SET(&core_bus);
   6574     PHYMOD_BUS_CAP_LANE_CTRL_SET(&core_bus);
   6575 
   6576     port = pc->port;
   6577     pmc = &pc->phymod_ctrl;
   6578     si = &SOC_INFO(unit);
   6579     if (soc_feature(unit, soc_feature_logical_port_num)) {
   6580         phy_port = si->port_l2p_mapping[port];
   6581     } else {
   6582         phy_port = port;
   6583     }
   6584 
   6585     /* Install clean up function */
   6586     pmc->unit = pc->unit;
   6587     pmc->cleanup = phy_8806x_cleanup;
   6588     #if 0
   6589     pmc->symbols = NULL; /*&bcmi_8806x_xgxs_symbols;*/
   6590     #endif
   6591 
   6592     
   6593     pc->lane_num = SOC_PORT_BINDEX(unit, phy_port);
   6594     pc->chip_num = SOC_BLOCK_NUMBER(unit, SOC_PORT_BLOCK(unit, phy_port));
   6595 
   6596     /* request memory for the configuration structure */
   6597     pc->size = sizeof(phy8806x_config_t);
   6598 
   6599     /* Bit N corresponds to lane N in lane_map */
   6600     lane_map = 0xf;
   6601     num_phys = 1;
   6602     switch (si->port_num_lanes[port]) {
   6603     case 4:
   6604         pc->phy_mode = PHYCTRL_QUAD_LANE_PORT; 
   6605         break;
   6606     case 2:
   6607         lane_map = 0x3;
   6608         pc->phy_mode = PHYCTRL_DUAL_LANE_PORT;
   6609         break;
   6610     case 1:
   6611     case 0:
   6612         lane_map = 0x1;
   6613         pc->phy_mode = PHYCTRL_ONE_LANE_PORT;
   6614         break;
   6615     default:
   6616         return SOC_E_CONFIG;
   6617     }
   6618     lane_map <<= pc->lane_num;
   6619 
   6620     /* we need to get the other core id if more than 1 core per port */
   6621     if (num_phys > 1) {
   6622         /* get the other core address */
   6623         SOC_IF_ERROR_RETURN
   6624             (soc_phy_addr_multi_get(unit, port, array_max, &array_size, &core_info[0]));
   6625     } else {
   6626         core_info[0].mdio_addr = pc->phy_id;
   6627     }
   6628 
   6629     phy_type = phymodDispatchTypePhy8806x;   /* Change to XMOD SRINATH */
   6630 
   6631     /* Probe cores */
   6632     for (idx = 0; idx < num_phys ; idx++) {
   6633         phy_8806x_core_init(pc, &core_probe, &core_bus,
   6634                            core_info[idx].mdio_addr);
   6635         pm_core = &core_probe.pm_core;
   6636         pm_core->type = phy_type;
   6637     }
   6638 
   6639     rv = SOC_E_NONE;
   6640     for (idx = 0; idx < num_phys ; idx++) {
   6641         /* Set core and phy IDs based on PHY address */
   6642         core_id = pc->phy_id + idx;
   6643         phy_id = (lane_map << 16) | core_id;
   6644 
   6645         /* Create PHY object */
   6646         rv = soc_phymod_phy_create(unit, phy_id, &pmc->phy[idx]);
   6647         if (SOC_FAILURE(rv)) {
   6648             break;
   6649         }
   6650         pmc->num_phys++;
   6651 
   6652         /* Initialize phy object */
   6653         phy = pmc->phy[idx];
   6654         pm_phy = &phy->pm_phy;
   6655         phymod_phy_access_t_init(pm_phy);
   6656 
   6657         /* Find or create associated core object */
   6658         rv = soc_phymod_core_find_by_id(unit, core_id, &phy->core);
   6659         if (rv == SOC_E_NOT_FOUND) {
   6660             rv = soc_phymod_core_create(unit, core_id, &phy->core);
   6661         }
   6662         if (SOC_FAILURE(rv)) {
   6663             break;
   6664         }        
   6665     }
   6666     if (SOC_FAILURE(rv)) {
   6667         phy_8806x_cleanup(pmc);
   6668         return rv;
   6669     }
   6670 
   6671     for (idx = 0; idx < pmc->num_phys ; idx++) {
   6672         phy = pmc->phy[idx];
   6673         core = phy->core;
   6674         pm_core = &core->pm_core;
   6675 
   6676         /* Initialize core object if newly created */
   6677         if (core->ref_cnt == 0) {
   6678             sal_memcpy(&core->pm_bus, &core_bus, sizeof(core->pm_bus));
   6679             phy_8806x_core_init(pc, core, &core->pm_bus,
   6680                                core_info[idx].mdio_addr);
   6681             /* Set dispatch type */
   6682             pm_core->type = phy_type;
   6683         }
   6684         core->ref_cnt++;        
   6685 
   6686         /* Initialize phy access based on associated core */
   6687         pm_acc = &phy->pm_phy.access;
   6688         sal_memcpy(pm_acc, &pm_core->access, sizeof(*pm_acc));
   6689         phy->pm_phy.type = phy_type;
   6690         PHYMOD_ACC_LANE_MASK(pm_acc) = lane_map;
   6691     }
   6692 
   6693     return SOC_E_NONE;
   6694 }
   6695 
   6696 
   6697 /***********************************************************************
   6698  *
   6699  * PASS-THROUGH NOTIFY ROUTINES
   6700  */
   6701 
   6702 /*
   6703  * Function:
   6704  *      _8806x_notify_duplex
   6705  * Purpose:
   6706  *      Program duplex if (and only if) serdesphy8806x is an intermediate PHY.
   6707  * Parameters:
   6708  *      unit - BCM unit number.
   6709  *      port - Port number.
   6710  *      duplex - Boolean, TRUE indicates full duplex, FALSE
   6711  *              indicates half.
   6712  * Returns:
   6713  *      SOC_E_XXX
   6714  * Notes:
   6715  *      If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to
   6716  *      talk directly to an external fiber module.
   6717  *
   6718  *      If PHY_FLAGS_FIBER is clear, the PHY is being used in
   6719  *      pass-through mode to talk to an external SGMII PHY.
   6720  *
   6721  *      When used in pass-through mode, autoneg must be turned off and
   6722  *      the speed/duplex forced to match that of the external PHY.
   6723  */
   6724 
   6725 
   6726 /*
   6727  * Function:
   6728  *      _8806x_stop
   6729  * Purpose:
   6730  *      Put serdesphy8806x SERDES in or out of reset depending on conditions
   6731  */
   6732 
   6733 STATIC int
   6734 _8806x_stop(int unit, soc_port_t port)
   6735 {
   6736     phy_ctrl_t* pc; 
   6737     soc_phymod_ctrl_t *pmc;
   6738     phymod_phy_access_t *pm_phy;
   6739     phymod_phy_power_t phy_power;
   6740     int  stop, copper, speed;
   6741 
   6742     pc = EXT_PHY_SW_STATE(unit, port);
   6743     pmc = &pc->phymod_ctrl;
   6744     pm_phy = &pmc->phy[0]->pm_phy;
   6745 
   6746     if (pc->phy_mode != PHYCTRL_ONE_LANE_PORT) {
   6747         return SOC_E_NONE;
   6748     }
   6749 
   6750     /* 'Stop' only for speeds < 10G. */ 
   6751     SOC_IF_ERROR_RETURN
   6752         (phy_8806x_speed_get(unit,port,&speed));
   6753     if(10000 <= speed) {
   6754         return SOC_E_NONE;
   6755     }
   6756     copper = (pc->stop &
   6757               PHY_STOP_COPPER) != 0;
   6758 
   6759     stop = ((pc->stop &
   6760              (PHY_STOP_PHY_DIS |
   6761               PHY_STOP_DRAIN)) != 0 ||
   6762             (copper &&
   6763              (pc->stop &
   6764               (PHY_STOP_MAC_DIS |
   6765                PHY_STOP_DUPLEX_CHG |
   6766                PHY_STOP_SPEED_CHG)) != 0));
   6767 
   6768     LOG_INFO(BSL_LS_SOC_PHY,
   6769              (BSL_META_U(pc->unit,
   6770                          "qsgmiie_stop: u=%d p=%d copper=%d stop=%d flg=0x%x\n"),
   6771               unit, port, copper, stop,
   6772               pc->stop));
   6773     if (stop) {
   6774         phy_power.tx = phymodPowerOff;
   6775         phy_power.rx = phymodPowerOff;
   6776     } else {
   6777         phy_power.tx = phymodPowerOn;
   6778         phy_power.rx = phymodPowerOn;
   6779     }
   6780     SOC_IF_ERROR_RETURN
   6781         (phymod_phy_power_set(pm_phy, &phy_power));
   6782     return SOC_E_NONE;
   6783 }
   6784 
   6785 /*
   6786  * Function:
   6787  *      _8806x_notify_stop
   6788  * Purpose:
   6789  *      Add a reason to put serdesphy8806x PHY in reset.
   6790  * Parameters:
   6791  *      unit - BCM unit number.
   6792  *      port - Port number.
   6793  *      flags - Reason to stop
   6794  * Returns:     
   6795  *      SOC_E_XXX
   6796  */
   6797 
   6798 int
   6799 _8806x_notify_stop(int unit, soc_port_t port, uint32 flags)
   6800 {
   6801     EXT_PHY_SW_STATE(unit, port)->stop |= flags;
   6802     return _8806x_stop(unit, port);
   6803 }
   6804 
   6805 /*  
   6806  * Function:
   6807  *      _8806x_notify_resume
   6808  * Purpose:
   6809  *      Remove a reason to put serdesphy8806x PHY in reset.
   6810  * Parameters:
   6811  *      unit - BCM unit number.
   6812  *      port - Port number.
   6813  *      flags - Reason to stop
   6814  * Returns:     
   6815  *      SOC_E_XXX
   6816  */
   6817 
   6818 int
   6819 _8806x_notify_resume(int unit, soc_port_t port, uint32 flags)
   6820 {   
   6821     EXT_PHY_SW_STATE(unit, port)->stop &= ~flags;
   6822     return _8806x_stop(unit, port);
   6823 }
   6824 
   6825 /*
   6826  * Function:
   6827  *      phy_8806x_diag_ctrl
   6828  * Purpose:
   6829  *      xx
   6830  * Parameters:
   6831  *      unit - BCM unit number.
   6832  *      port - Port number. 
   6833 
   6834  * Returns:     
   6835  *      SOC_E_NONE
   6836  */
   6837 
   6838 STATIC int
   6839 phy_8806x_diag_ctrl(
   6840     int unit,        /* unit */
   6841     soc_port_t port, /* port */
   6842     uint32 inst,     /* the specific device block the control action directs to */
   6843     int op_type,     /* operation types: read,write or command sequence */
   6844     int op_cmd,      /* command code */
   6845     void *arg)       /* command argument based on op_type/op_cmd */
   6846 {
   6847     int32 intf, prev_intf;
   6848     phy_ctrl_t          *pc;
   6849     int rv = SOC_E_NONE;
   6850 
   6851     /* locate phy control, phymod control, and the configuration data */
   6852     pc = EXT_PHY_SW_STATE(unit, port);
   6853     if (pc == NULL) {
   6854         return SOC_E_INTERNAL;
   6855     }
   6856 
   6857     /* Temporarily Set Interface type in PC flags, for the duration of this diag */
   6858 
   6859     intf = PHY_DIAG_INST_INTF(inst);
   6860     if (intf == PHY_DIAG_INTF_DFLT) {
   6861         intf = PHY_DIAG_INTF_LINE;
   6862     }
   6863 
   6864     prev_intf = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 1 : 0;
   6865 
   6866     if (intf == PHY_DIAG_INTF_SYS) {
   6867         pc->flags |= PHYCTRL_SYS_SIDE_CTRL;
   6868     } else {
   6869         pc->flags &= ~PHYCTRL_SYS_SIDE_CTRL;
   6870     }
   6871 
   6872     switch(op_cmd) {
   6873         case PHY_DIAG_CTRL_DSC:
   6874             LOG_INFO(BSL_LS_SOC_PHY,
   6875                      (BSL_META_U(unit,
   6876                                  "phy_mt2_diag_ctrl: "
   6877                                  "u=%d p=%d PHY_DIAG_CTRL_DSC 0x%x\n"),
   6878                                   unit, port, PHY_DIAG_CTRL_DSC));
   6879             rv = phy8806x_uc_status_dump(unit, port, arg);
   6880             break;
   6881         case PHY_DIAG_CTRL_STATE_GENERIC:
   6882             LOG_INFO(BSL_LS_SOC_PHY,
   6883                      (BSL_META_U(unit,
   6884                                  "phy_mt2_diag_ctrl: "
   6885                                  "u=%d p=%d PHY_DIAG_CTRL_STATE_GENERIC 0x%x\n"),
   6886                                   unit, port, PHY_DIAG_CTRL_STATE_GENERIC));
   6887             rv = _phy8806x_dump_buffer(unit, port, (unsigned char *)arg);
   6888             break;
   6889         default:
   6890             if (op_type == PHY_DIAG_CTRL_SET) {
   6891                 rv = phy_8806x_control_set(unit,port,op_cmd,PTR_TO_INT(arg));
   6892             } else if (op_type == PHY_DIAG_CTRL_GET) {
   6893                 rv = phy_8806x_control_get(unit,port,op_cmd,(uint32 *)arg);
   6894             }
   6895             break ;
   6896     }
   6897 
   6898     if (prev_intf) {
   6899         pc->flags |= PHYCTRL_SYS_SIDE_CTRL;
   6900     } else {
   6901         pc->flags &= ~PHYCTRL_SYS_SIDE_CTRL;
   6902     }
   6903 
   6904     SOC_IF_ERROR_RETURN(rv);
   6905     return (SOC_E_NONE);
   6906 }
   6907 
   6908 /*
   6909  * Function:
   6910  *      phy_8806x_linkup
   6911  * Purpose:
   6912  *      Link up handler
   6913  * Parameters:
   6914  *      unit  - StrataSwitch unit #.
   6915  *      port  - StrataSwitch port #.
   6916  * Returns:
   6917  *      SOC_E_NONE
   6918  */
   6919 STATIC int 
   6920 phy_8806x_linkup(int unit, soc_port_t port)
   6921 {
   6922     return SOC_E_NONE;
   6923 }
   6924 
   6925 /*
   6926  * Function:
   6927  *    phy_8806x_linkfault_get
   6928  * Purpose:
   6929  *    Get layer2 connection status.
   6930  * Parameters:
   6931  *    unit - StrataSwitch unit #.
   6932  *    port - StrataSwitch port #. 
   6933  *    fault - address of memory to store link fault state.
   6934  * Returns:    
   6935  *    SOC_E_NONE
   6936  */
   6937 
   6938 STATIC int
   6939 phy_8806x_linkfault_get(int unit, soc_port_t port, int *fault)
   6940 {
   6941     int        rv = SOC_E_NONE;
   6942     phy_ctrl_t *pc;
   6943 #if defined(INCLUDE_FCMAP)
   6944     uint16     fault_st;
   6945 #endif
   6946     uint16     reg_val;
   6947 
   6948     pc    = EXT_PHY_SW_STATE(unit, port);
   6949 
   6950     *fault = FALSE;      /* Default return */
   6951 
   6952 #if defined(INCLUDE_FCMAP)
   6953     if (pc->fcmap_enable) {
   6954         rv = READ_FC_LINK_FAULT_REG(unit, pc, &fault_st);
   6955         *fault = (fault_st & VS_MISC_STATUS_STATUS_BIT_MASK) ? TRUE: FALSE;
   6956         return(rv); 
   6957     }
   6958 #endif
   6959 
   6960     rv = READ_ETH_LOCAL_FAULT_REG(unit, pc, &reg_val);
   6961     if (reg_val & VS_MISC_STATUS_LIVE_STATUS_BIT_MASK) {
   6962         *fault |= SOC_PORT_FAULT_LOCAL;
   6963     }
   6964 
   6965     rv = READ_ETH_REMOTE_FAULT_REG(unit, pc, &reg_val);
   6966     if (reg_val & VS_MISC_STATUS_LIVE_STATUS_BIT_MASK) {
   6967         *fault |= SOC_PORT_FAULT_REMOTE;
   6968     }
   6969 
   6970     return (rv);
   6971 }
   6972 
   6973 /* Utility functions */
   6974 
   6975 STATIC int
   6976 _phy_8806x_write_to_arm(int unit, phy_ctrl_t *pc, uint32 addr, uint8 *data,int len)
   6977 {
   6978     int n_writes, i;
   6979 
   6980 #ifdef PHY8806X_MEASSURE_DOWNLOAD_TIME
   6981     sal_usecs_t t;
   6982     t = sal_time_usecs();
   6983 #endif
   6984 
   6985     n_writes = (len + WRITE_BLK_SIZE -1) / WRITE_BLK_SIZE;
   6986 
   6987     for ( i = 0; i < n_writes; i++ ) {
   6988 
   6989         /* address frames are ignored in the download mode */
   6990         SOC_IF_ERROR_RETURN
   6991             (PHY8806X_REG_WRITE(unit, pc, 
   6992                 SOC_PHY_CLAUSE45_ADDR(((1U << 3) | 0U), (((uint16)data[0])<<8)|data[1]),
   6993                 (((uint16)data[2])<<8)|data[3]) );
   6994 
   6995         data += WRITE_BLK_SIZE;
   6996 
   6997     }
   6998  
   6999 #ifdef PHY8806X_MEASSURE_DOWNLOAD_TIME
   7000     LOG_CLI((BSL_META_U(unit,
   7001                         "u=%d p=%d raw download took %u us\n"), unit, pc->port, SAL_USECS_SUB(sal_time_usecs(), t)));
   7002 #endif
   7003 
   7004     return (SOC_E_NONE);
   7005 }
   7006 
   7007 
   7008 int
   7009 phy_8806x_sbus_cmd(int unit,phy_ctrl_t *pc, uint32 reg, uint32 cmd, int ring,  uint32 arg[])
   7010 {
   7011     int    count, rv, write, size;
   7012     uint16 status, temp0, temp1;
   7013 
   7014     size = ((cmd >> 7) & 0x7f) >> 2;
   7015 
   7016     if ((size < 1) || (size > 4)) {
   7017         return (SOC_E_PARAM);
   7018     }
   7019 
   7020 
   7021     if (ring > 0x2) {
   7022         LOG_CLI((BSL_META_U(unit,
   7023                         "phy_8806x_sbus_reg_cmd: u=%d p=%d  : invalid ring !."
   7024                         " \n"), unit, pc->port));
   7025         return (SOC_E_PARAM);
   7026     }
   7027 
   7028     ring &= 0x3;
   7029 
   7030     /* LOG_CLI((BSL_META_U(unit,
   7031                         "phy_8806x_sbus_reg_cmd: u=%d p=%d  cmd_reg=%08x"
   7032                         " \n"), unit, pc->port, cmd)); */
   7033 
   7034     write = (((cmd >> 26) & 0x3f) + 1) & 0x2;
   7035 
   7036     SOC_IF_ERROR_RETURN
   7037         (WRITE_PHY8806X_SBUS_COMMAND_UPPER_REG(unit, pc, (cmd >> 16) & 0xffff));
   7038     SOC_IF_ERROR_RETURN
   7039         (WRITE_PHY8806X_SBUS_COMMAND_LOWER_REG(unit, pc, cmd & 0xffff));
   7040 
   7041     SOC_IF_ERROR_RETURN
   7042         (WRITE_PHY8806X_SBUS_ADDR_UPPER_REG(unit, pc, (reg >> 16) & 0xffff));
   7043     SOC_IF_ERROR_RETURN
   7044         (WRITE_PHY8806X_SBUS_ADDR_LOWER_REG(unit, pc, reg & 0xffff));
   7045 
   7046     if (write) {
   7047         if (size-- > 0) {
   7048             SOC_IF_ERROR_RETURN
   7049                 (WRITE_PHY8806X_SBUS_DATA_BYTES_1_0_REG(unit, pc, arg[0] & 0xffff));
   7050             SOC_IF_ERROR_RETURN
   7051                 (WRITE_PHY8806X_SBUS_DATA_BYTES_3_2_REG(unit, pc, (arg[0] >> 16) & 0xffff));
   7052         }
   7053 
   7054         if (size-- > 0) {
   7055             SOC_IF_ERROR_RETURN
   7056                 (WRITE_PHY8806X_SBUS_DATA_BYTES_5_4_REG(unit, pc, arg[1] & 0xffff));
   7057             SOC_IF_ERROR_RETURN
   7058                 (WRITE_PHY8806X_SBUS_DATA_BYTES_7_6_REG(unit, pc, (arg[1] >> 16) & 0xffff));
   7059         }
   7060 
   7061         if (size-- > 0) {
   7062             SOC_IF_ERROR_RETURN
   7063                 (WRITE_PHY8806X_SBUS_DATA_BYTES_9_8_REG(unit, pc, arg[2] & 0xffff));
   7064             SOC_IF_ERROR_RETURN
   7065                 (WRITE_PHY8806X_SBUS_DATA_BYTES_11_10_REG(unit, pc, (arg[2] >> 16) & 0xffff));
   7066         }
   7067 
   7068         if (size-- > 0) {
   7069             SOC_IF_ERROR_RETURN
   7070                 (WRITE_PHY8806X_SBUS_DATA_BYTES_13_12_REG(unit, pc, arg[3] & 0xffff));
   7071             SOC_IF_ERROR_RETURN
   7072                 (WRITE_PHY8806X_SBUS_DATA_BYTES_15_14_REG(unit, pc, (arg[3] >> 16) & 0xffff));
   7073         }
   7074     }
   7075 
   7076     SOC_IF_ERROR_RETURN
   7077         (WRITE_PHY8806X_SBUS_CONTROL_REG(unit, pc, (1U << 15) | (ring << 12))); /* TOP + go */
   7078 
   7079     count = 0;
   7080 
   7081     do {
   7082         rv = READ_PHY8806X_SBUS_STATUS_REG(unit, pc, &status);
   7083         if (((status & (SBUS_STATUS_ERR | SBUS_STATUS_NAK | SBUS_STATUS_DONE)) != 0) ||
   7084             SOC_FAILURE(rv)) {
   7085             break;
   7086         }
   7087     } while (count++ < SCHAN_MAX_POLLS);
   7088 
   7089     if (count >= SCHAN_MAX_POLLS) {
   7090         LOG_CLI((BSL_META_U(unit,
   7091                             "phy_8806x_sbus_reg_cmd failed: u=%d p=%d  status=%04x"
   7092                             "SCHAN_MAX_POLLS reached !.\n"), unit, pc->port, status));
   7093         return (SOC_E_FAIL);
   7094     }
   7095 
   7096     if ((status & (SBUS_STATUS_ERR | SBUS_STATUS_NAK)) != 0) {
   7097         LOG_CLI((BSL_META_U(unit,
   7098                             "phy_8806x_sbus_reg_cmd failed: u=%d p=%d "
   7099                             "cmd=0x%04x reg=0x%08x ring=%d d[0]=0x%08x d[1]=0x%08x d[2]=0x%08x d[3]=0x%08x status=%04x\n"), unit, pc->port, cmd, reg, ring, arg[0], arg[1], arg[2], arg[3], status));
   7100         return (SOC_E_FAIL);
   7101     }
   7102 
   7103     if (!write) {
   7104 
   7105         if (size-- > 0) {
   7106             SOC_IF_ERROR_RETURN
   7107                 (READ_PHY8806X_SBUS_DATA_BYTES_1_0_REG(unit, pc, &temp0));
   7108             SOC_IF_ERROR_RETURN
   7109                 (READ_PHY8806X_SBUS_DATA_BYTES_3_2_REG(unit, pc, &temp1));
   7110             arg[0] = (((uint32) temp1) << 16) | temp0;
   7111         }
   7112 
   7113         if (size-- > 0) {
   7114             SOC_IF_ERROR_RETURN
   7115                 (READ_PHY8806X_SBUS_DATA_BYTES_5_4_REG(unit, pc, &temp0));
   7116             SOC_IF_ERROR_RETURN
   7117                 (READ_PHY8806X_SBUS_DATA_BYTES_7_6_REG(unit, pc, &temp1));
   7118             arg[1] = (((uint32) temp1) << 16) | temp0;
   7119         }
   7120 
   7121         if (size-- > 0) {
   7122             SOC_IF_ERROR_RETURN
   7123                 (READ_PHY8806X_SBUS_DATA_BYTES_9_8_REG(unit, pc, &temp0));
   7124             SOC_IF_ERROR_RETURN
   7125                 (READ_PHY8806X_SBUS_DATA_BYTES_11_10_REG(unit, pc, &temp1));
   7126             arg[2] = (((uint32) temp1) << 16) | temp0;
   7127         }
   7128 
   7129         if (size-- > 0) {
   7130             SOC_IF_ERROR_RETURN
   7131                 (READ_PHY8806X_SBUS_DATA_BYTES_13_12_REG(unit, pc, &temp0));
   7132             SOC_IF_ERROR_RETURN
   7133                 (READ_PHY8806X_SBUS_DATA_BYTES_15_14_REG(unit, pc, &temp1));
   7134             arg[3] = (((uint32) temp1) << 16) | temp0;
   7135         }
   7136     }
   7137 
   7138     return (SOC_E_NONE);
   7139 }
   7140 
   7141 STATIC int _pmd_enable(int unit, phy_ctrl_t *pc, int sys)
   7142 {
   7143     uint32 data[4], reg_cmd, reg_cmd_1, mem_cmd  /* , reg_rcmd, reg_rcmd_1 */;
   7144     int ring, rv;
   7145     uint16 status = 0;
   7146  
   7147     ring = (pc->phy_id & 0x4) ? 1 : 0; /* mig too */
   7148 
   7149     reg_cmd   = (SBUS_WRITE_REGISTER_CMD_MSG << 26) |(((sys ? 0x6 : 0x2) & 0x7f) << 19) |(4 << 7);
   7150     reg_cmd_1 = (SBUS_WRITE_REGISTER_CMD_MSG << 26) |(((sys ? 0x7 : 0x3) & 0x7f) << 19) |(4 << 7);
   7151     mem_cmd   = (SBUS_WRITE_MEMORY_CMD_MSG   << 26) |(((sys ? 0x7 : 0x3) & 0x7f) << 19) |(16 << 7);
   7152 
   7153     /*
   7154     reg_rcmd   = (SBUS_READ_REGISTER_CMD_MSG << 26) |(((sys ? 0x6 : 0x2) & 0x7f) << 19) |(4 << 7);
   7155     reg_rcmd_1 = (SBUS_READ_REGISTER_CMD_MSG << 26) |(((sys ? 0x7 : 0x3) & 0x7f) << 19) |(4 << 7);
   7156      */
   7157 
   7158 #if defined(INCLUDE_FCMAP)
   7159     if (pc->fcmap_enable && !sys) {
   7160         /* FCPORT_PLL0_CTRL_CONFIGr = 0x3 */
   7161         data[0] = 0x3;
   7162         SOC_IF_ERROR_RETURN
   7163             (phy_8806x_sbus_cmd(unit, pc, 0x02000f00, reg_cmd_1, ring,  data));
   7164 
   7165         /*
   7166         SOC_IF_ERROR_RETURN
   7167             (phy_8806x_sbus_cmd(unit, pc, 0x02000f00, reg_rcmd_1, ring,  data));
   7168          */
   7169 
   7170         /* FCPORT_PLL1_CTRL_CONFIGr = 0x1 */
   7171         data[0] = 0x1;
   7172         SOC_IF_ERROR_RETURN
   7173             (phy_8806x_sbus_cmd(unit, pc, 0x02001000, reg_cmd_1, ring,  data));
   7174         /*
   7175         SOC_IF_ERROR_RETURN
   7176             (phy_8806x_sbus_cmd(unit, pc, 0x02001000, reg_rcmd_1, ring,  data));
   7177          */
   7178     }
   7179 #endif
   7180 
   7181     /* CLPORT_POWER_SAVE = 0 */
   7182     data[0] = 0;
   7183     SOC_IF_ERROR_RETURN
   7184         (phy_8806x_sbus_cmd(unit, pc, 0x02020D00, reg_cmd, ring,  data));
   7185 
   7186     /* CLPORT_XGXS0_CTRL_REG = 0x1C */
   7187     data[0] = 0x1C;
   7188     SOC_IF_ERROR_RETURN
   7189         (phy_8806x_sbus_cmd(unit, pc, 0x02021400, reg_cmd, ring,  data));
   7190 
   7191     /* CLPORT_XGXS0_CTRL_REG = 0x1E */
   7192     data[0] = 0x1e;
   7193     SOC_IF_ERROR_RETURN
   7194         (phy_8806x_sbus_cmd(unit, pc, 0x02021400, reg_cmd, ring,  data));
   7195 
   7196     /* CLPORT_XGXS0_CTRL_REG = 0x0E */
   7197     data[0] = 0x0e;
   7198     SOC_IF_ERROR_RETURN
   7199         (phy_8806x_sbus_cmd(unit, pc, 0x02021400, reg_cmd, ring,  data));
   7200 
   7201     sal_udelay(10000);
   7202     /* CLPORT_XGXS0_CTRL_REG = 0x06 */
   7203     data[0] = 0x06;
   7204     SOC_IF_ERROR_RETURN
   7205         (phy_8806x_sbus_cmd(unit, pc, 0x02021400, reg_cmd, ring,  data));
   7206 
   7207     sal_udelay(10000);
   7208     /* CLPORT_XGXS0_CTRL_REG = fc ? 0x7 : 0x5 */
   7209     data[0] = 0x5;
   7210 #if defined(INCLUDE_FCMAP)
   7211     if (pc->fcmap_enable) {
   7212         data[0] = 0x7;
   7213     }
   7214 #endif
   7215     SOC_IF_ERROR_RETURN
   7216         (phy_8806x_sbus_cmd(unit, pc, 0x02021400, reg_cmd, ring,  data));
   7217 
   7218     /* CLPORT_POWER_SAVE = 0 */
   7219 
   7220     /* FCPORT_TOP_CTRL_CONFIG = 0x10 */
   7221     data[0] = 0x10;
   7222     SOC_IF_ERROR_RETURN
   7223         (phy_8806x_sbus_cmd(unit, pc, 0x02000000, reg_cmd_1, ring,  data));
   7224 
   7225     /* PMD_X1_CONTROL.[1:0] = 0x3 */
   7226     data[0] = PORT_ADDRESS(0x00009010, sys, ring);
   7227     data[1] = 0x0003fffc;
   7228     data[2] = 0x1;
   7229     data[3] = 0;
   7230     SOC_IF_ERROR_RETURN
   7231         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7232 
   7233     /*  RESET_CONTROL_PMD.0 = 0x0 core_s_rstb = 0x0  */ 
   7234     data[0] = PORT_ADDRESS(0x0800d101, sys, ring);
   7235     data[1] = 0x0000fffe;
   7236     data[2] = 0x1;
   7237     data[3] = 0;
   7238     SOC_IF_ERROR_RETURN
   7239         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7240 
   7241 
   7242     /*  RESET_CONTROL_PMD.0 = 0x1 core_s_rstb = 0x1  */ 
   7243     data[0] = PORT_ADDRESS(0x0800d101, sys, ring);
   7244     data[1] = 0x0001fffe;
   7245     data[2] = 0x1;
   7246     data[3] = 0;
   7247     SOC_IF_ERROR_RETURN
   7248         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7249 
   7250 
   7251     /* PMD_X4_CONTROL.[1:0] = 0x3 */
   7252     data[0] = PORT_ADDRESS(0x0000c010, sys, ring);
   7253     data[1] = 0x0003fffc;
   7254     data[2] = 0x1;
   7255     data[3] = 0;
   7256     SOC_IF_ERROR_RETURN
   7257         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7258 
   7259 /* new additions */ 
   7260 
   7261     /* MICRO_A_COM_CLOCK_CONTROL0.1 = 0x0, micro_core_clk_en = 0 */ 
   7262     data[0] = PORT_ADDRESS(0x0800d200, sys, ring);
   7263     data[1] = 0x0000fffd;
   7264     data[2] = 0x1;
   7265     data[3] = 0;
   7266     SOC_IF_ERROR_RETURN
   7267         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7268 
   7269     /* MICRO_A_COM_CLOCK_CONTROL0.0 = 0x0, micro_master_clk_en = 0 */ 
   7270     data[0] = PORT_ADDRESS(0x0800d200, sys, ring);
   7271     data[1] = 0x0000fffe;
   7272     data[2] = 0x1;
   7273     data[3] = 0;
   7274     SOC_IF_ERROR_RETURN
   7275         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7276 
   7277 
   7278     /* MICRO_C_ram_control0.1 = 1, micro_protect_fwcode = 1 */
   7279     data[0] = PORT_ADDRESS(0x0800d225, sys, ring);
   7280     data[1] = 0x0002fffd;
   7281     data[2] = 0x1;
   7282     data[3] = 0;
   7283     SOC_IF_ERROR_RETURN
   7284         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7285 
   7286 
   7287     data[0] = PORT_ADDRESS(0x0800d200, sys, ring);
   7288     data[1] = 0x00000000;
   7289     data[2] = 0x1;
   7290     data[3] = 0;
   7291     SOC_IF_ERROR_RETURN
   7292         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7293 
   7294     data[0] = PORT_ADDRESS(0x0800d201, sys, ring);
   7295     data[1] = 0x00000000;
   7296     data[2] = 0x1;
   7297     data[3] = 0;
   7298     SOC_IF_ERROR_RETURN
   7299         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7300 
   7301     data[0] = PORT_ADDRESS(0x0800d202, sys, ring);
   7302     data[1] = 0x00000000;
   7303     data[2] = 0x1;
   7304     data[3] = 0;
   7305     SOC_IF_ERROR_RETURN
   7306         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7307 
   7308 
   7309     data[0] = PORT_ADDRESS(0x0800d203, sys, ring);
   7310     data[1] = 0x00000000;
   7311     data[2] = 0x1;
   7312     data[3] = 0;
   7313     SOC_IF_ERROR_RETURN
   7314         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7315 
   7316 
   7317     data[0] = PORT_ADDRESS(0x0800d204, sys, ring);
   7318     data[1] = 0x00000000;
   7319     data[2] = 0x1;
   7320     data[3] = 0;
   7321     SOC_IF_ERROR_RETURN
   7322         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7323 
   7324 
   7325     data[0] = PORT_ADDRESS(0x0800d205, sys, ring);
   7326     data[1] = 0x00000000;
   7327     data[2] = 0x1;
   7328     data[3] = 0;
   7329     SOC_IF_ERROR_RETURN
   7330         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7331 
   7332 
   7333     data[0] = PORT_ADDRESS(0x0800d206, sys, ring);
   7334     data[1] = 0x00000000;
   7335     data[2] = 0x1;
   7336     data[3] = 0;
   7337     SOC_IF_ERROR_RETURN
   7338         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7339 
   7340 
   7341     data[0] = PORT_ADDRESS(0x0800d207, sys, ring);
   7342     data[1] = 0x00000000;
   7343     data[2] = 0x1;
   7344     data[3] = 0;
   7345     SOC_IF_ERROR_RETURN
   7346         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7347 
   7348 
   7349     data[0] = PORT_ADDRESS(0x0800d208, sys, ring);
   7350     data[1] = 0x00000000;
   7351     data[2] = 0x1;
   7352     data[3] = 0;
   7353     SOC_IF_ERROR_RETURN
   7354         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7355 
   7356 
   7357     data[0] = PORT_ADDRESS(0x0800d209, sys, ring);
   7358     data[1] = 0x00000000;
   7359     data[2] = 0x1;
   7360     data[3] = 0;
   7361     SOC_IF_ERROR_RETURN
   7362         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7363 
   7364 
   7365     data[0] = PORT_ADDRESS(0x0800d20a, sys, ring);
   7366     data[1] = 0x00000000;
   7367     data[2] = 0x1;
   7368     data[3] = 0;
   7369     SOC_IF_ERROR_RETURN
   7370         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7371 
   7372 
   7373     data[0] = PORT_ADDRESS(0x0800d20b, sys, ring);
   7374     data[1] = 0x00000000;
   7375     data[2] = 0x1;
   7376     data[3] = 0;
   7377     SOC_IF_ERROR_RETURN
   7378         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7379 
   7380 
   7381     data[0] = PORT_ADDRESS(0x0800d20c, sys, ring);
   7382     data[1] = 0x00000000;
   7383     data[2] = 0x1;
   7384     data[3] = 0;
   7385     SOC_IF_ERROR_RETURN
   7386         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7387 
   7388 
   7389     data[0] = PORT_ADDRESS(0x0800d20d, sys, ring);
   7390     data[1] = 0x00000000;
   7391     data[2] = 0x1;
   7392     data[3] = 0;
   7393     SOC_IF_ERROR_RETURN
   7394         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7395 
   7396 
   7397     data[0] = PORT_ADDRESS(0x0800d20e, sys, ring);
   7398     data[1] = 0x00000000;
   7399     data[2] = 0x1;
   7400     data[3] = 0;
   7401     SOC_IF_ERROR_RETURN
   7402         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7403 
   7404 
   7405     data[0] = PORT_ADDRESS(0x0800d20f, sys, ring);
   7406     data[1] = 0x00000000;
   7407     data[2] = 0x1;
   7408     data[3] = 0;
   7409     SOC_IF_ERROR_RETURN
   7410         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7411 
   7412 
   7413     data[0] = PORT_ADDRESS(0x0800d210, sys, ring);
   7414     data[1] = 0x00000000;
   7415     data[2] = 0x1;
   7416     data[3] = 0;
   7417     SOC_IF_ERROR_RETURN
   7418         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7419 
   7420 
   7421     data[0] = PORT_ADDRESS(0x0800d211, sys, ring);
   7422     data[1] = 0x00000000;
   7423     data[2] = 0x1;
   7424     data[3] = 0;
   7425     SOC_IF_ERROR_RETURN
   7426         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7427 
   7428 
   7429     data[0] = PORT_ADDRESS(0x0800d212, sys, ring);
   7430     data[1] = 0x00000000;
   7431     data[2] = 0x1;
   7432     data[3] = 0;
   7433     SOC_IF_ERROR_RETURN
   7434         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7435 
   7436 
   7437     data[0] = PORT_ADDRESS(0x0800d213, sys, ring);
   7438     data[1] = 0x00000000;
   7439     data[2] = 0x1;
   7440     data[3] = 0;
   7441     SOC_IF_ERROR_RETURN
   7442         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7443 
   7444 
   7445     data[0] = PORT_ADDRESS(0x0800d214, sys, ring);
   7446     data[1] = 0x00000000;
   7447     data[2] = 0x1;
   7448     data[3] = 0;
   7449     SOC_IF_ERROR_RETURN
   7450         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7451 
   7452 
   7453     data[0] = PORT_ADDRESS(0x0800d215, sys, ring);
   7454     data[1] = 0x00000000;
   7455     data[2] = 0x1;
   7456     data[3] = 0;
   7457     SOC_IF_ERROR_RETURN
   7458         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7459 
   7460 
   7461     data[0] = PORT_ADDRESS(0x0800d216, sys, ring);
   7462     data[1] = 0x00070000;
   7463     data[2] = 0x1;
   7464     data[3] = 0;
   7465     SOC_IF_ERROR_RETURN
   7466         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7467 
   7468 
   7469     data[0] = PORT_ADDRESS(0x0800d217, sys, ring);
   7470     data[1] = 0x00000000;
   7471     data[2] = 0x1;
   7472     data[3] = 0;
   7473     SOC_IF_ERROR_RETURN
   7474         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7475 
   7476 
   7477     data[0] = PORT_ADDRESS(0x0800d218, sys, ring);
   7478     data[1] = 0x00000000;
   7479     data[2] = 0x1;
   7480     data[3] = 0;
   7481     SOC_IF_ERROR_RETURN
   7482         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7483 
   7484 
   7485     data[0] = PORT_ADDRESS(0x0800d219, sys, ring);
   7486     data[1] = 0x00000000;
   7487     data[2] = 0x1;
   7488     data[3] = 0;
   7489     SOC_IF_ERROR_RETURN
   7490         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7491 
   7492 
   7493     data[0] = PORT_ADDRESS(0x0800d21a, sys, ring);
   7494     data[1] = 0x00000000;
   7495     data[2] = 0x1;
   7496     data[3] = 0;
   7497     SOC_IF_ERROR_RETURN
   7498         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7499 
   7500 
   7501     data[0] = PORT_ADDRESS(0x0800d21b, sys, ring);
   7502     data[1] = 0x00000000;
   7503     data[2] = 0x1;
   7504     data[3] = 0;
   7505     SOC_IF_ERROR_RETURN
   7506         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7507 
   7508 
   7509     data[0] = PORT_ADDRESS(0x0800d220, sys, ring);
   7510     data[1] = 0x00000000;
   7511     data[2] = 0x1;
   7512     data[3] = 0;
   7513     SOC_IF_ERROR_RETURN
   7514         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7515 
   7516 
   7517     data[0] = PORT_ADDRESS(0x0800d221, sys, ring);
   7518     data[1] = 0x00000000;
   7519     data[2] = 0x1;
   7520     data[3] = 0;
   7521     SOC_IF_ERROR_RETURN
   7522         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7523 
   7524 
   7525     data[0] = PORT_ADDRESS(0x0800d224, sys, ring);
   7526     data[1] = 0x00000000;
   7527     data[2] = 0x1;
   7528     data[3] = 0;
   7529     SOC_IF_ERROR_RETURN
   7530         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7531 
   7532 
   7533     data[0] = PORT_ADDRESS(0x0800d226, sys, ring);
   7534     data[1] = 0x00000000;
   7535     data[2] = 0x1;
   7536     data[3] = 0;
   7537     SOC_IF_ERROR_RETURN
   7538         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7539 
   7540 
   7541     data[0] = PORT_ADDRESS(0x0800d225, sys, ring);
   7542     data[1] = 0x88030000;
   7543     data[2] = 0x1;
   7544     data[3] = 0;
   7545     SOC_IF_ERROR_RETURN
   7546         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7547 
   7548 
   7549     data[0] = PORT_ADDRESS(0x0800d228, sys, ring);
   7550     data[1] = 0x01010000;
   7551     data[2] = 0x1;
   7552     data[3] = 0;
   7553     SOC_IF_ERROR_RETURN
   7554         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7555 
   7556 
   7557     data[0] = PORT_ADDRESS(0x0800d229, sys, ring);
   7558     data[1] = 0x00000000;
   7559     data[2] = 0x1;
   7560     data[3] = 0;
   7561     SOC_IF_ERROR_RETURN
   7562         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7563 
   7564 
   7565 
   7566     /* MICRO_C_ram_control0.1 = 1, micro_protect_fwcode = 0 */
   7567     data[0] = PORT_ADDRESS(0x0800d225, sys, ring);
   7568     data[1] = 0x0000fffd;
   7569     data[2] = 0x1;
   7570     data[3] = 0;
   7571     SOC_IF_ERROR_RETURN
   7572         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7573 
   7574 /* end of new additions */ 
   7575 
   7576 #if 0
   7577     /* CKRST_CTRL_PMD_LANE_RESET_N_PWRDN_PIN_KILL_CONTROL.0 = 0x1 */ 
   7578     data[0] = PORT_ADDRESS(0x0800d0b3, sys, ring);
   7579     data[1] = 0x0001fffe;
   7580     data[2] = 0x1;
   7581     data[3] = 0;
   7582     SOC_IF_ERROR_RETURN
   7583         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7584 #endif
   7585 
   7586     /* MICRO_A_COM_CLOCK_CONTROL0.0 = 0x1 micro_master_clk_en = 0x1 */ 
   7587     data[0] = PORT_ADDRESS(0x0800d200, sys, ring);
   7588     data[1] = 0x0001fffe;
   7589     data[2] = 0x1;
   7590     data[3] = 0;
   7591     SOC_IF_ERROR_RETURN
   7592         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7593 
   7594     /* MICRO_A_COM_RESET_CONTROL0.0 = 0x0, MICRO_A_COM_RESET_CONTROL0.3 = 0x0, micro_pram_if_rstb=0 micro_master_rstb= 0x0  */
   7595     data[0] = PORT_ADDRESS(0x0800d201, sys, ring);
   7596     data[1] = 0x0000fff6;
   7597     data[2] = 0x1;
   7598     data[3] = 0;
   7599     SOC_IF_ERROR_RETURN
   7600         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7601 
   7602     /* MICRO_A_COM_RESET_CONTROL0.0 = 0x1, MICRO_A_COM_RESET_CONTROL0.3 = 0x1, micro_pram_if_rstb=1 micro_master_rstb= 0x1  */ 
   7603     data[0] = PORT_ADDRESS(0x0800d201, sys, ring);
   7604     data[1] = 0x0009fff6;
   7605     data[2] = 0x1;
   7606     data[3] = 0;
   7607     SOC_IF_ERROR_RETURN
   7608         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7609 
   7610     if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) {
   7611         /* MICRO_A_COM_AHB_CONTROL0.[9:8] = 0x1 */ 
   7612         data[0] = PORT_ADDRESS(0x0800d202, sys, ring);
   7613         data[1] = 0x0100fcff;
   7614         data[2] = 0x1;
   7615         data[3] = 0;
   7616         SOC_IF_ERROR_RETURN
   7617             (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7618 
   7619         /* tsc_reg_read_test_base(unit, pc->port, sys, 1, 0, 0xd203); */
   7620 
   7621         /* sal_udelay(250000); */
   7622 
   7623        soc_timeout_init(&TO(pc), 250000, 0); /* 250ms timer */
   7624 
   7625         do {
   7626 
   7627             rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) +  (sys ? 9 : 1), 1, 0, 0xd203, &status);
   7628             if (SOC_FAILURE(rv)) {
   7629                 break;
   7630             }
   7631                 if ((status & 0x1) == 0x1) {
   7632                     break;
   7633                 }
   7634         } while (!soc_timeout_check(&TO(pc)));
   7635 
   7636         if ((status & 0x1) != 0x1) {
   7637             LOG_CLI((BSL_META_U(unit,
   7638                     "PHY8806X PMD (%s) failed to clear code RAM: u=%d p=%d  status=%04x"
   7639                     " !.\n"), sys ? "sys" : "line", unit, pc->port, status));
   7640         }
   7641 
   7642         /* MICRO_A_COM_AHB_CONTROL0.[9:8] = 0x0 */ 
   7643         data[0] = PORT_ADDRESS(0x0800d202, sys, ring);
   7644         data[1] = 0x0000fcff;
   7645         data[2] = 0x1;
   7646         data[3] = 0;
   7647         SOC_IF_ERROR_RETURN
   7648             (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7649 
   7650         /* MICRO_A_COM_AHB_CONTROL0.[1:0] = 0x2, micro_ra_wrdatasize = 0x2 (32-bit) */ 
   7651         data[0] = PORT_ADDRESS(0x0800d202, sys, ring);
   7652         data[1] = 0x0002fffc;
   7653         data[2] = 0x1;
   7654         data[3] = 0;
   7655         SOC_IF_ERROR_RETURN
   7656             (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7657     }
   7658 
   7659     /* MICRO_A_COM_PRAMIF_CONTROL0.0 = 0x1 , micro_pramif_en = 1 */
   7660     data[0] = PORT_ADDRESS(0x0800d20c, sys, ring);
   7661     data[1] = 0x0001fffe;
   7662     data[2] = 0x1;
   7663     data[3] = 0;
   7664     SOC_IF_ERROR_RETURN
   7665         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7666 
   7667     if (FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART)) {
   7668         /* No need to set UCMEM_ACCESS_CONTROL=1 if no  f/w is downloaded */
   7669         return (SOC_E_NONE);
   7670     }
   7671 
   7672     /* FCPORT_TOP_CTRL_CONFIG = 0x11 */
   7673     data[0] = 0x11;
   7674     SOC_IF_ERROR_RETURN
   7675         (phy_8806x_sbus_cmd(unit, pc, 0x02000000, reg_cmd_1, ring,  data));
   7676 
   7677     return (SOC_E_NONE);
   7678 }
   7679 
   7680 STATIC int _pmd_disable(int unit, phy_ctrl_t *pc, int sys)
   7681 {
   7682     uint32 data[4], /* reg_cmd, */ reg_cmd_1, mem_cmd;
   7683     int ring, rv;
   7684     uint16 status = 0;
   7685  
   7686     ring = (pc->phy_id & 0x4) ? 1 : 0; /* mig too */
   7687 
   7688     /* reg_cmd   = (SBUS_WRITE_REGISTER_CMD_MSG << 26) |(((sys ? 0x6 : 0x2) & 0x7f) << 19) |(4 << 7); */
   7689     reg_cmd_1 = (SBUS_WRITE_REGISTER_CMD_MSG << 26) |(((sys ? 0x7 : 0x3) & 0x7f) << 19) |(4 << 7);
   7690     mem_cmd   = (SBUS_WRITE_MEMORY_CMD_MSG   << 26) |(((sys ? 0x7 : 0x3) & 0x7f) << 19) |(16 << 7);
   7691 
   7692     if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) {
   7693         /* FCPORT_TOP_CTRL_CONFIG = 0x10 */
   7694         data[0] = 0x10;
   7695         SOC_IF_ERROR_RETURN
   7696             (phy_8806x_sbus_cmd(unit, pc, 0x02000000, reg_cmd_1, ring,  data));
   7697     }
   7698 
   7699     /* MICRO_A_COM_AHB_CONTROL0.[9:8] = 0x2, clear data ram */ 
   7700     data[0] = PORT_ADDRESS(0x0800d202, sys, ring);
   7701     data[1] = 0x0200fcff;
   7702     data[2] = 0x1;
   7703     data[3] = 0;
   7704     SOC_IF_ERROR_RETURN
   7705         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7706 
   7707     /* tsc_reg_read_test_base(unit, pc->port, sys, 1, 0, 0xd203); */
   7708 
   7709     /* sal_udelay(250000); */
   7710 
   7711     soc_timeout_init(&TO(pc), 250000, 0); /* 250ms timer */
   7712 
   7713     do {
   7714            rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) +  (sys ? 9 : 1), 1, 0, 0xd203, &status);
   7715            if (SOC_FAILURE(rv)) {
   7716                break;
   7717            }
   7718            if ((status & 0x1) == 0x1) {
   7719                 break;
   7720            }
   7721     } while (!soc_timeout_check(&TO(pc)));
   7722 
   7723     if ((status & 0x1) != 0x1) {
   7724         LOG_CLI((BSL_META_U(unit,
   7725                 "PHY8806X PMD (%s) failed to clear data RAM: u=%d p=%d  status=%04x"
   7726                 " !.\n"), sys ? "sys" : "line", unit, pc->port, status));
   7727     }
   7728 
   7729     /* MICRO_A_COM_AHB_CONTROL0.[9:8] = 0x0 */ 
   7730     data[0] = PORT_ADDRESS(0x0800d202, sys, ring);
   7731     data[1] = 0x0000fcff;
   7732     data[2] = 0x1;
   7733     data[3] = 0;
   7734     SOC_IF_ERROR_RETURN
   7735         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7736 
   7737 
   7738     /* CKRST_CTRL_PMD_LANE_RESET_N_PWRDN_PIN_KILL_CONTROL.0 = 0x1 */ 
   7739     data[0] = PORT_ADDRESS(0x0800d0b3, sys, ring);
   7740     data[1] = 0x0001fffe;
   7741     data[2] = 0x1;
   7742     data[3] = 0;
   7743     SOC_IF_ERROR_RETURN
   7744         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7745 
   7746     return (SOC_E_NONE);
   7747 }
   7748 
   7749 STATIC int _pmd_start(int unit, phy_ctrl_t *pc, int sys)
   7750 {
   7751     uint32 data[4], mem_cmd;
   7752     int ring;
   7753 
   7754     ring = (pc->phy_id & 0x4) ? 1 : 0; /* mig too */
   7755 
   7756     mem_cmd = (SBUS_WRITE_MEMORY_CMD_MSG   << 26) |(((sys ? 0x7 : 0x3) & 0x7f) << 19) |(16 << 7);
   7757 
   7758     /* TOP_USER_CONTROL_0.15 = 0x0 */ 
   7759     data[0] = PORT_ADDRESS(0x0800d104, sys, ring);
   7760     data[1] = 0x00007fff;
   7761     data[2] = 0x1;
   7762     data[3] = 0;
   7763     SOC_IF_ERROR_RETURN
   7764         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7765 
   7766 
   7767     /* TOP_USER_CONTROL_0.15 = 0x1 */ 
   7768     data[0] = PORT_ADDRESS(0x0800d104, sys, ring);
   7769     data[1] = 0x80007fff;
   7770     data[2] = 0x1;
   7771     data[3] = 0;
   7772     SOC_IF_ERROR_RETURN
   7773         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7774 
   7775 
   7776     /* CKRST_CTRL_PMD_LANE_RESET_N_PWRDN_PIN_KILL_CONTROL.0 = 0x0 */ 
   7777     data[0] = PORT_ADDRESS(0x0800d0b3, sys, ring);
   7778     data[1] = 0x0000fffe;
   7779     data[2] = 0x1;
   7780     data[3] = 0;
   7781     SOC_IF_ERROR_RETURN
   7782         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7783 
   7784     /* MICRO_A_COM_CLOCK_CONTROL0.1 = 0x1 */ 
   7785     data[0] = PORT_ADDRESS(0x0800d200, sys, ring);
   7786     data[1] = 0x0002fffd;
   7787     data[2] = 0x1;
   7788     data[3] = 0;
   7789     SOC_IF_ERROR_RETURN
   7790         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7791 
   7792     /* MICRO_A_COM_RESET_CONTROL0.1 = 0x1 */ 
   7793     data[0] = PORT_ADDRESS(0x0800d201, sys, ring);
   7794     data[1] = 0x0002fffd;
   7795     data[2] = 0x1;
   7796     data[3] = 0;
   7797     SOC_IF_ERROR_RETURN
   7798         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   7799 
   7800     return (SOC_E_NONE);
   7801 }
   7802 
   7803 
   7804 /* _phy_8806x_toplvl_sbus_{read|write}() need to be optimized when the data only transactions are
   7805    implemented in the CMIC MDIO code.
   7806  */
   7807  
   7808 int
   7809 _phy_8806x_toplvl_sbus_write(int unit,phy_ctrl_t *pc, uint32 reg, uint32 arg[], int size)
   7810 {
   7811     uint32 cmd;
   7812 
   7813     if ((size < 1) || (size > 4)) {
   7814         return (SOC_E_PARAM);
   7815     }
   7816 
   7817    cmd = (SBUS_WRITE_REGISTER_CMD_MSG << 26) |
   7818          ((montreal2_BLKTYPE_TOP & 0x7f) << 19) |
   7819          ((4 * size) << 7);
   7820 
   7821     return (phy_8806x_sbus_cmd(unit, pc, reg, cmd, 2, arg));
   7822 
   7823 }
   7824 
   7825 int
   7826 _phy_8806x_fcport_sbus_write(int unit,phy_ctrl_t *pc, int sys, uint32 reg, uint32 arg[], int size)
   7827 {
   7828      uint32 cmd, blk, addr;
   7829      int ring;
   7830 
   7831      if ((size < 1) || (size > 4)) {
   7832          return (SOC_E_PARAM);
   7833      }
   7834 
   7835     blk = sys ? montreal2_BLKTYPE_SYS_FCPORT : montreal2_BLKTYPE_LINE_FCPORT;
   7836     addr = reg & 0x03ffffff;
   7837     addr |= ((blk & 0x3f) << 26);
   7838 
   7839     /* Ports 0-3 = MIG0, 4-7 = MIG1 */
   7840     ring = ((pc->phy_id % 8) < 4) ? 0 : 1;
   7841 
   7842    cmd = (SBUS_WRITE_REGISTER_CMD_MSG << 26) |
   7843          ((blk & 0x7f) << 19) |
   7844          ((4 * size) << 7);
   7845 
   7846     return (phy_8806x_sbus_cmd(unit, pc, addr, cmd, ring, arg));
   7847 
   7848 }
   7849 
   7850 int
   7851 _sbus_write_test(int unit,int port, uint32 reg, uint32 value)
   7852 {
   7853     phy_ctrl_t *pc;
   7854     uint32 temp32 = value;
   7855     int rv;
   7856 
   7857     pc = EXT_PHY_SW_STATE(unit, port);
   7858     rv = _phy_8806x_toplvl_sbus_write(unit, pc, reg, &temp32, 1);
   7859 
   7860     return rv;
   7861 }
   7862 
   7863 int
   7864 _phy_8806x_toplvl_sbus_read(int unit,phy_ctrl_t *pc, uint32 reg, uint32 arg[], int size)
   7865 {
   7866     uint32 cmd;
   7867 
   7868     if ((size < 1) || (size > 4)) {
   7869         return (SOC_E_PARAM);
   7870     }
   7871 
   7872     cmd = (SBUS_READ_REGISTER_CMD_MSG << 26) |
   7873           ((montreal2_BLKTYPE_TOP & 0x7f) << 19) |
   7874           ((4 * size) << 7);
   7875 
   7876     return (phy_8806x_sbus_cmd(unit, pc, reg, cmd, 2, arg));
   7877 }
   7878 
   7879 #if defined(INCLUDE_FCMAP)
   7880 int
   7881 _phy_8806x_fcport_sbus_read(int unit,phy_ctrl_t *pc, int sys, uint32 reg, uint32 arg[], int size)
   7882 {
   7883      uint32 cmd, blk, addr;
   7884      int ring;
   7885 
   7886      if ((size < 1) || (size > 4)) {
   7887          return (SOC_E_PARAM);
   7888      }
   7889 
   7890     blk = sys ? montreal2_BLKTYPE_SYS_FCPORT : montreal2_BLKTYPE_LINE_FCPORT;
   7891     addr = reg & 0x03ffffff;
   7892     addr |= ((blk & 0x3f) << 26);
   7893 
   7894     /* Ports 0-3 = MIG0, 4-7 = MIG1 */
   7895     ring = ((pc->phy_id % 8) < 4) ? 0 : 1;
   7896 
   7897     cmd = (SBUS_READ_REGISTER_CMD_MSG << 26) |
   7898           ((blk & 0x7f) << 19) |
   7899           ((4 * size) << 7);
   7900 
   7901      return (phy_8806x_sbus_cmd(unit, pc, addr, cmd, ring, arg));
   7902 }
   7903 #endif
   7904 
   7905 int
   7906 _sbus_read_test(int unit,int port, uint32 reg)
   7907 {
   7908     phy_ctrl_t *pc;
   7909     uint32 temp32;
   7910     int rv;
   7911 
   7912     pc = EXT_PHY_SW_STATE(unit, port);
   7913     rv = _phy_8806x_toplvl_sbus_read(unit, pc, reg, &temp32, 1);
   7914 
   7915     LOG_CLI((BSL_META_U(unit,
   7916                         "_sbus_read_test: u=%d p=%d "
   7917                         "value=0x%08x\n"), unit, pc->port, temp32));
   7918     return rv;
   7919 }
   7920 
   7921 int 
   7922 _phy_8806x_write_top_soft_reset_reg(int unit, phy_ctrl_t *pc, uint32 val)
   7923 {
   7924     uint32 temp = val;
   7925     int rv;
   7926     rv = _phy_8806x_toplvl_sbus_write(unit, pc, montreal2_TOP_SOFT_RESET_REGr, &temp, 1);
   7927     return (rv);
   7928 }
   7929 
   7930 int
   7931 _phy_8806x_write_top_rts_misc_ctrl_reg(int unit, phy_ctrl_t *pc, uint32 val)
   7932 {
   7933     uint32 temp = val;
   7934     int rv;
   7935     rv = _phy_8806x_toplvl_sbus_write(unit, pc, montreal2_TOP_RTS_MISC_CTRLr, &temp, 1);
   7936     return (rv);
   7937 }
   7938 
   7939 int 
   7940 _phy_8806x_write_top_soft_reset_reg_2(int unit, phy_ctrl_t *pc, uint32 val)
   7941 {
   7942     uint32 temp = val;
   7943     int rv;
   7944     rv = _phy_8806x_toplvl_sbus_write(unit, pc, montreal2_TOP_SOFT_RESET_REG_2r, &temp, 1);
   7945     return (rv);
   7946 }
   7947 
   7948 int 
   7949 _phy_8806x_write_top_fc_mode_control_reg(int unit, phy_ctrl_t *pc, uint32 val)
   7950 {
   7951     uint32 temp = val;
   7952     int rv;
   7953     rv = _phy_8806x_toplvl_sbus_write(unit, pc, montreal2_TOP_FC_MODE_CONTROLr, &temp, 1);
   7954     return (rv);
   7955 }
   7956 
   7957 int 
   7958 _phy_8806x_write_fcport_ext_tx_disable_ctrl(int unit, phy_ctrl_t *pc, int sys, uint32 val)
   7959 {
   7960     uint32 temp = val;
   7961     int rv;
   7962     rv = _phy_8806x_fcport_sbus_write(unit, pc, sys, montreal2_FCPORT_EXT_TX_DISABLE_CTRLr, &temp, 1);
   7963     return (rv);
   7964 }
   7965 
   7966 int
   7967 _fwdl_test(int unit,int port)
   7968 {
   7969     phy_ctrl_t *pc;
   7970 
   7971     pc = EXT_PHY_SW_STATE(unit, port);
   7972 
   7973     SOC_IF_ERROR_RETURN
   7974         (_phy_8806x_write_to_arm(unit, pc, 0, FIRMWARE(pc), FIRMWARE_LEN(pc)));
   7975 
   7976     return (SOC_E_NONE);
   7977 }
   7978 
   7979 
   7980 /* _phy_8806x_axi_{read|write}() need to be optimized when the data only transactions are
   7981    implemented in the CMIC MDIO code.
   7982  */
   7983  
   7984 STATIC int
   7985 _phy_8806x_axi_write(int unit,phy_ctrl_t *pc, uint32 addr, uint32 data[], int size)
   7986 {
   7987     int    count, rv, i;
   7988     uint16 control, status;
   7989     uint32 temp32;
   7990 
   7991     if ( addr & 0x3 ) {
   7992         LOG_CLI((BSL_META_U(unit,
   7993                             "_phy_8806x_axi_write failed: u=%d p=%d "
   7994                             "addr=%08x - unaligned !.\n"), unit, pc->port, addr));
   7995         return (SOC_E_FAIL);
   7996     }
   7997 
   7998     SOC_IF_ERROR_RETURN
   7999         (WRITE_PHY8806X_AXI_ADDR_UPPER_FX_REG(unit, pc, (addr >> 16) & 0xffff));
   8000     SOC_IF_ERROR_RETURN
   8001         (WRITE_PHY8806X_AXI_ADDR_LOWER_FX_REG(unit, pc, addr & 0xffff));
   8002 
   8003     i = 0;
   8004     while (size-- > 0) {
   8005         /* 
   8006            When the current destination address is 8 byte aligned write to  AXI_DATA_BYTES_1_2_FX_REG and 
   8007            AXI_DATA_BYTES_3_4_FX_REG else write to AXI_DATA_BYTES_5_6_FX_REG and AXI_DATA_BYTES_7_8_FX_REG.
   8008          */
   8009         /* The following preserves the byte order. */
   8010         temp32 = HOST2LE32(data[i]);
   8011 
   8012         if ( (addr + (i << 2)) & 0x7 ) {
   8013             SOC_IF_ERROR_RETURN
   8014                 (WRITE_PHY8806X_AXI_DATA_BYTES_5_4_FX_REG(unit, pc, temp32 & 0xffff));
   8015             SOC_IF_ERROR_RETURN
   8016                 (WRITE_PHY8806X_AXI_DATA_BYTES_7_6_FX_REG(unit, pc, (temp32 >> 16) & 0xffff));
   8017         } else {
   8018             SOC_IF_ERROR_RETURN
   8019                 (WRITE_PHY8806X_AXI_DATA_BYTES_1_0_FX_REG(unit, pc, temp32 & 0xffff));
   8020             SOC_IF_ERROR_RETURN
   8021                 (WRITE_PHY8806X_AXI_DATA_BYTES_3_2_FX_REG(unit, pc, (temp32 >> 16) & 0xffff));
   8022         }
   8023 
   8024         SOC_IF_ERROR_RETURN
   8025             (WRITE_PHY8806X_AXI_CONTROL_FX_REG(unit, pc, (1U << 13))); /* pre-go */
   8026 
   8027         SOC_IF_ERROR_RETURN
   8028             (WRITE_PHY8806X_AXI_CONTROL_FX_REG(unit, pc, (5U << 13))); /* go */
   8029 
   8030         count = 0;
   8031 
   8032         do {
   8033             rv = READ_PHY8806X_AXI_CONTROL_FX_REG(unit, pc, &control);
   8034             if (((control & (1U << 15) ) == 0) ||
   8035                 SOC_FAILURE(rv)) {
   8036                 break;
   8037             }
   8038         } while (count++ < AXI_MAX_POLLS);
   8039 
   8040         rv = READ_PHY8806X_AXI_STATUS_FX_REG(unit, pc, &status);
   8041 
   8042         if (count >= AXI_MAX_POLLS) {
   8043             LOG_CLI((BSL_META_U(unit,
   8044                                 "_phy_8806x_axi_write failed: u=%d p=%d addr=0x%08x control=0x%04x status=0x%04x"
   8045                                 "AXI_MAX_POLLS reached !.\n"), unit, pc->port, addr + (i << 2), control, status));
   8046             return (SOC_E_FAIL);
   8047         }
   8048 
   8049         if ((status & (1U << 9)) != 0) {
   8050             LOG_CLI((BSL_META_U(unit,
   8051                                 "_phy_8806x_axi_write failed: u=%d p=%d "
   8052                                 "addr=0x%08x status=0x%04x\n"), unit, pc->port, addr + (i << 2), status));
   8053             return (SOC_E_FAIL);
   8054         }
   8055         i++;
   8056     }
   8057 
   8058     return (SOC_E_NONE);
   8059 }
   8060 
   8061 int
   8062 _axi_write_test(int unit,int port, uint32 reg, uint32 value)
   8063 {
   8064     phy_ctrl_t *pc;
   8065     uint32 temp32 = value;
   8066     int rv;
   8067 
   8068     pc = EXT_PHY_SW_STATE(unit, port);
   8069     rv = _phy_8806x_axi_write(unit, pc, reg, &temp32, 1);
   8070 
   8071     return rv;
   8072 }
   8073 
   8074 int
   8075 _axi_write_test2(int unit,int port, uint32 reg, uint32 value)
   8076 {
   8077     phy_ctrl_t *pc;
   8078     uint32 temp32[2];
   8079     int rv;
   8080 
   8081     temp32[0] = value;
   8082     temp32[1] = value ^ 0xffffffff;
   8083 
   8084     pc = EXT_PHY_SW_STATE(unit, port);
   8085     rv = _phy_8806x_axi_write(unit, pc, reg, temp32, 2);
   8086 
   8087     LOG_CLI((BSL_META_U(unit,
   8088                         "_sbus_read_test 2: u=%d p=%d "
   8089                         "temp32[0]=0x%08x temp32[1]=0x%08x\n"), unit, pc->port, temp32[0], temp32[1]));
   8090     return rv;
   8091 }
   8092 
   8093 STATIC int
   8094 _phy_8806x_axi_read(int unit,phy_ctrl_t *pc, uint32 addr, uint32 data[], int size)
   8095 {
   8096     int    count, rv, i;
   8097     uint16 control, status;
   8098     uint16 temp0, temp1;
   8099     uint32 temp32;
   8100 
   8101     if ( addr & 0x3 ) {
   8102         LOG_CLI((BSL_META_U(unit,
   8103                             "_phy_8806x_axi_read failed: u=%d p=%d "
   8104                             "addr=%08x - unaligned !.\n"), unit, pc->port, addr));
   8105         return (SOC_E_FAIL);
   8106     }
   8107 
   8108     SOC_IF_ERROR_RETURN
   8109         (WRITE_PHY8806X_AXI_ADDR_UPPER_FX_REG(unit, pc, (addr >> 16) & 0xffff));
   8110     SOC_IF_ERROR_RETURN
   8111         (WRITE_PHY8806X_AXI_ADDR_LOWER_FX_REG(unit, pc, addr & 0xffff));
   8112 
   8113     i = 0;
   8114     while (size-- > 0) {
   8115         SOC_IF_ERROR_RETURN
   8116             (WRITE_PHY8806X_AXI_CONTROL_FX_REG(unit, pc, (3U << 13))); /* pre-go */
   8117 
   8118         SOC_IF_ERROR_RETURN
   8119             (WRITE_PHY8806X_AXI_CONTROL_FX_REG(unit, pc, (7U << 13))); /* go */
   8120 
   8121         count = 0;
   8122 
   8123         do {
   8124             rv = READ_PHY8806X_AXI_CONTROL_FX_REG(unit, pc, &control);
   8125             if (((control & (1U << 15)) == 0) ||
   8126                 SOC_FAILURE(rv)) {
   8127                 break;
   8128             }
   8129         } while (count++ < AXI_MAX_POLLS);
   8130 
   8131         rv = READ_PHY8806X_AXI_STATUS_FX_REG(unit, pc, &status);
   8132 
   8133         if (count >= AXI_MAX_POLLS) {
   8134             LOG_CLI((BSL_META_U(unit,
   8135                                 "_phy_8806x_axi_read failed: u=%d p=%d addr=0x%08x control=0x%04x status=0x%04x\n"
   8136                                 "AXI_MAX_POLLS reached !.\n"), unit, pc->port, addr + (i << 2), control, status));
   8137             return (SOC_E_FAIL);
   8138         }
   8139 
   8140         if ((status & (1U << 9)) != 0) {
   8141             LOG_CLI((BSL_META_U(unit,
   8142                                 "_phy_8806x_axi_read failed: u=%d p=%d "
   8143                                 "addr=0x%08x status=0x%04x\n"), unit, pc->port, addr + (i << 2), status));
   8144             return (SOC_E_FAIL);
   8145         }
   8146 
   8147         /* 
   8148            When the current source address is 8 byte aligned read from AXI_DATA_BYTES_1_2_FX_REG and 
   8149            AXI_DATA_BYTES_3_4_FX_REG else read from AXI_DATA_BYTES_5_6_FX_REG and AXI_DATA_BYTES_7_8_FX_REG.
   8150          */
   8151         if ( (addr + (i << 2)) & 0x7 ) {
   8152             SOC_IF_ERROR_RETURN
   8153                 (READ_PHY8806X_AXI_DATA_BYTES_5_4_FX_REG(unit, pc, &temp0));
   8154             SOC_IF_ERROR_RETURN
   8155                 (READ_PHY8806X_AXI_DATA_BYTES_7_6_FX_REG(unit, pc, &temp1));
   8156         } else {
   8157             SOC_IF_ERROR_RETURN
   8158                 (READ_PHY8806X_AXI_DATA_BYTES_1_0_FX_REG(unit, pc, &temp0));
   8159             SOC_IF_ERROR_RETURN
   8160                 (READ_PHY8806X_AXI_DATA_BYTES_3_2_FX_REG(unit, pc, &temp1));
   8161         }
   8162         temp32 = (((uint32) temp1) << 16) | temp0;
   8163 
   8164         /* The following preserves the byte order. */
   8165         data[i] = LE2HOST32(temp32);
   8166 
   8167         i++;
   8168     }
   8169 
   8170     return (SOC_E_NONE);
   8171 
   8172 }
   8173 
   8174 int
   8175 _axi_read_test(int unit,int port, uint32 reg)
   8176 {
   8177     phy_ctrl_t *pc;
   8178     uint32 temp32;
   8179     int rv;
   8180 
   8181     pc = EXT_PHY_SW_STATE(unit, port);
   8182     rv = _phy_8806x_axi_read(unit, pc, reg, &temp32, 1);
   8183 
   8184     LOG_CLI((BSL_META_U(unit,
   8185                         "_sbus_read_test: u=%d p=%d "
   8186                         "value=0x%08x\n"), unit, pc->port, temp32));
   8187     return rv;
   8188 }
   8189 
   8190 int
   8191 _axi_read_test2(int unit,int port, uint32 reg)
   8192 {
   8193     phy_ctrl_t *pc;
   8194     uint32 temp32[2];
   8195     int rv;
   8196 
   8197     pc = EXT_PHY_SW_STATE(unit, port);
   8198     rv = _phy_8806x_axi_read(unit, pc, reg, temp32, 2);
   8199 
   8200     LOG_CLI((BSL_META_U(unit,
   8201                         "_sbus_read_test: u=%d p=%d "
   8202                         "temp32[0]=0x%08x temp32[1]=0x%08x\n"), unit, pc->port, temp32[0], temp32[1]));
   8203     return rv;
   8204 }
   8205 
   8206 int
   8207 phy_is_8806x(phy_ctrl_t *pc)
   8208 {
   8209     return (PHY_IS_BCM8806X(pc) ? SOC_E_NONE : SOC_E_FAIL);
   8210 }
   8211 
   8212 int
   8213 phy_8806x_fw_stat_read(int unit, int port, int offset,  uint32 result[], int result_size)
   8214 {
   8215     phy_ctrl_t *pc;
   8216     int rv = SOC_E_NONE;
   8217 
   8218     pc = EXT_PHY_SW_STATE(unit, port);
   8219 
   8220     if (sal_mutex_take(xmod_mutex[unit], XMOD_MUTEX_TIMEOUT) < 0)
   8221     {
   8222         LOG_WARN(BSL_LS_SOC_PHY,
   8223                  (BSL_META_U(unit,
   8224                              "phy_8806x_fw_stat_read: Couldn't aquire lock. u=%d p=%d\n"), \
   8225                   unit, pc->port));
   8226         return SOC_E_FAIL;
   8227     }
   8228 
   8229     /* 0x{2,3,4,5}4 0200 : axi_buf = 0x240200 + (pc->phy_id & 0x3) * 0x100000 */
   8230     rv = _phy_8806x_axi_read(unit, pc, 0x240200 + ((pc->phy_id & 0x3) * 0x100000)+(offset*4), result, result_size);
   8231 
   8232     sal_mutex_give(xmod_mutex[unit]);
   8233     return rv;
   8234 }
   8235 
   8236 STATIC int
   8237 _phy_8806x_xmod_command_send(int unit, phy_ctrl_t *pc, int mode_opcode,  uint32 arg[], int arg_size)
   8238 {
   8239     uint16 status;
   8240     int rv, ack_count = 0;
   8241 
   8242     if ( FLAGS(pc) & PHY8806X_PM ) {
   8243         return SOC_E_NONE;
   8244     }
   8245 
   8246     if (arg_size > 256) {
   8247         LOG_WARN(BSL_LS_SOC_PHY,
   8248                  (BSL_META_U(unit,
   8249                              "PHY8806X command handler (invalid parameters): u=%d p=%d arg_size=%d\n"), \
   8250                   unit, pc->port, arg_size));
   8251         return SOC_E_PARAM;
   8252     }
   8253 
   8254     retry_after_ack:
   8255     soc_timeout_init(&TO(pc), 10000000, 0); /* 10000 ms timer */
   8256 
   8257     do {
   8258         rv = READ_PHY8806X_FW_TO_SW_MESSAGE_REG(unit, pc, &status);
   8259         if (!(status & (0x3 << 13)) || SOC_FAILURE(rv)) {
   8260             break;
   8261         }
   8262     } while (!soc_timeout_check(&TO(pc)));
   8263     if ((status & (0x3 << 13)) || SOC_FAILURE(rv)) {
   8264         LOG_WARN(BSL_LS_SOC_PHY,
   8265                  (BSL_META_U(unit,
   8266                              "PHY8806X command handler timeout (not ready): u=%d p=%d status=0x%04x\n"), \
   8267                   unit, pc->port, status));
   8268         _phy_8806x_xmod_command_ack(unit, pc);
   8269         if (ack_count++ < RETRY_COUNT ) {
   8270             goto retry_after_ack;
   8271         }
   8272         return SOC_E_TIMEOUT;
   8273     }
   8274 
   8275    /* 
   8276    -> 0x{2,3,4,5}4 0000 - 0x{2,3,4,5}4 00ff (256 bytes), axi_buf = 0x240000 + (pc->phy_id & 0x3) * 0x100000
   8277    <- 0x{2,3,4,5}4 0100 - 0x{2,3,4,5}4 01ff (256 bytes), axi_buf = 0x240100 + (pc->phy_id & 0x3) * 0x100000
   8278     */
   8279 
   8280     /* write arguments */
   8281     rv = _phy_8806x_axi_write(unit, pc, 0x240000 + (pc->phy_id & 0x3) * 0x100000, arg, arg_size);
   8282 
   8283     if (SOC_FAILURE(rv)) {
   8284         LOG_WARN(BSL_LS_SOC_PHY,
   8285                  (BSL_META_U(unit,
   8286                              "PHY8806X command handler (AXI write failure): u=%d p=%d\n"), \
   8287                   unit, pc->port));
   8288         return SOC_E_FAIL;
   8289     }
   8290 
   8291     /* issue command */
   8292     rv = WRITE_PHY8806X_SW_TO_FW_INTERRUPT_REG(unit, pc, (1U << 15) | (mode_opcode & 0x7fff));
   8293 
   8294     if (SOC_FAILURE(rv)) {
   8295         LOG_WARN(BSL_LS_SOC_PHY,
   8296                  (BSL_META_U(unit,
   8297                              "PHY8806X command handler (command failure): u=%d p=%d\n"), \
   8298                   unit, pc->port));
   8299         return SOC_E_FAIL;
   8300     }
   8301 
   8302     soc_timeout_init(&TO(pc), 10000000, 0); /* 10000 ms timer */
   8303 
   8304     return SOC_E_NONE;
   8305 }
   8306 
   8307 
   8308 STATIC int
   8309 _phy_8806x_xmod_result_recv(int unit, phy_ctrl_t *pc, uint32 result[], int result_size)
   8310 {
   8311     uint16 status;
   8312     int rv, rval;
   8313 
   8314     if ( FLAGS(pc) & PHY8806X_PM ) {
   8315         return SOC_E_NONE;
   8316     }
   8317 
   8318     if (result_size > 256) {
   8319         LOG_WARN(BSL_LS_SOC_PHY,
   8320                  (BSL_META_U(unit,
   8321                              "_phy_8806x_xmod_result_recv: invalid parameters: u=%d p=%d result_size=%d\n"), \
   8322                   unit, pc->port, result_size));
   8323         /* issue ack command */
   8324         _phy_8806x_xmod_command_ack(unit, pc);
   8325         return SOC_E_PARAM;
   8326     }
   8327 
   8328     do {
   8329         rv = READ_PHY8806X_FW_TO_SW_MESSAGE_REG(unit, pc, &status);
   8330         if ((status & (0x1 << 15)) | ((status & (0x3 << 13)) == (0x2 << 13)) || SOC_FAILURE(rv)) {
   8331             break;
   8332         }
   8333     } while (!soc_timeout_check(&TO(pc)));
   8334 
   8335     if (SOC_FAILURE(rv)) {
   8336         LOG_WARN(BSL_LS_SOC_PHY,
   8337                  (BSL_META_U(unit,
   8338                              "PHY8806X command handler (status read failure): u=%d p=%d\n"), \
   8339                   unit, pc->port));
   8340         /* issue ack command */
   8341         _phy_8806x_xmod_command_ack(unit, pc);
   8342         return SOC_E_FAIL;
   8343     }
   8344 
   8345     if (status & (0x1 << 15)) { /* error */
   8346         LOG_WARN(BSL_LS_SOC_PHY,
   8347                  (BSL_META_U(unit,
   8348                              "PHY8806X command handler failure: u=%d p=%d status=0x%04x\n"), \
   8349                   unit, pc->port, status));
   8350         /* issue ack command */
   8351         _phy_8806x_xmod_command_ack(unit, pc);
   8352         rval = -(status & BFCMAP_ERROR_CODE_MASK);
   8353 	/* could err Code map before */
   8354         return rval;
   8355     }
   8356 
   8357     if ((status & (0x3 << 13)) != (0x2 << 13)) { /* result not ready */
   8358         LOG_WARN(BSL_LS_SOC_PHY,
   8359                  (BSL_META_U(unit,
   8360                              "PHY8806X command handler timeout (no result): u=%d p=%d status=0x%04x\n"), \
   8361                   unit, pc->port, status));
   8362         /* issue ack command */
   8363         _phy_8806x_xmod_command_ack(unit, pc);
   8364         return SOC_E_TIMEOUT;
   8365     }
   8366 
   8367 
   8368    /* 
   8369    -> 0x{2,3,4,5}4 0000 - 0x{2,3,4,5}4 00ff (256 bytes), axi_buf = 0x240000 + (pc->phy_id & 0x3) * 0x100000
   8370    <- 0x{2,3,4,5}4 0100 - 0x{2,3,4,5}4 01ff (256 bytes), axi_buf = 0x240100 + (pc->phy_id & 0x3) * 0x100000
   8371     */
   8372 
   8373 
   8374     /* read results */
   8375     rv = _phy_8806x_axi_read(unit, pc, 0x240100 + (pc->phy_id & 0x3) * 0x100000, result, result_size);
   8376 
   8377     if (SOC_FAILURE(rv)) {
   8378         LOG_WARN(BSL_LS_SOC_PHY,
   8379                  (BSL_META_U(unit,
   8380                              "PHY8806X command handler (AXI read failure): u=%d p=%d\n"), \
   8381                   unit, pc->port));
   8382         /* issue ack command */
   8383         _phy_8806x_xmod_command_ack(unit, pc);
   8384 
   8385         return SOC_E_FAIL;
   8386     }
   8387 
   8388     /* issue ack command */
   8389     _phy_8806x_xmod_command_ack(unit, pc);
   8390 
   8391     return SOC_E_NONE;
   8392 
   8393 }
   8394 
   8395 int
   8396 phy_8806x_xmod_command(int unit, int port, int mode_opcode,  uint32 arg[], int arg_size, uint32 result[], int result_size)
   8397 {
   8398     phy_ctrl_t *pc;
   8399     int rv;
   8400 
   8401     pc = EXT_PHY_SW_STATE(unit, port);
   8402 
   8403     /* MT2 XMOD set opcodes have the LSB set */
   8404     if ((SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit)) && (mode_opcode & 0x1)) {
   8405         return SOC_E_NONE;
   8406     }
   8407 
   8408     if (sal_mutex_take(xmod_mutex[unit], XMOD_MUTEX_TIMEOUT) < 0)
   8409     {
   8410         LOG_WARN(BSL_LS_SOC_PHY,
   8411                  (BSL_META_U(unit,
   8412                              "phy_8806x_xmod_command: Couldn't aquire lock. u=%d p=%d mode:0x%x cmd:0x%x \n"), \
   8413                   unit, pc->port, (mode_opcode >> 8), (mode_opcode & 0xFF)));
   8414         return SOC_E_FAIL;
   8415     }
   8416 
   8417     rv = _phy_8806x_xmod_command_send(unit, pc, mode_opcode,  arg, arg_size);
   8418 
   8419     if (SOC_FAILURE(rv)) {
   8420         LOG_WARN(BSL_LS_SOC_PHY,
   8421                  (BSL_META_U(unit,
   8422                              "phy_8806x_xmod_command: send command failed. u=%d p=%d mode:0x%x cmd:0x%x \n"), \
   8423                   unit, pc->port, (mode_opcode >> 8), (mode_opcode & 0xFF)));
   8424         sal_mutex_give(xmod_mutex[unit]);
   8425         return SOC_E_FAIL;
   8426     }
   8427 
   8428     rv = _phy_8806x_xmod_result_recv(unit, pc, result, result_size);
   8429 
   8430     if (SOC_FAILURE(rv)) {
   8431         LOG_WARN(BSL_LS_SOC_PHY,
   8432                  (BSL_META_U(unit,
   8433                              "phy_8806x_xmod_command: receive result failed. u=%d p=%d mode:0x%x cmd:0x%x \n"), \
   8434                   unit, pc->port, (mode_opcode >> 8), (mode_opcode & 0xFF)));
   8435         sal_mutex_give(xmod_mutex[unit]);
   8436         return rv;
   8437     }
   8438 
   8439     sal_mutex_give(xmod_mutex[unit]);
   8440     return SOC_E_NONE;
   8441 }
   8442 
   8443 STATIC int
   8444 _phy_8806x_xmod_command_ack(int unit, phy_ctrl_t *pc)
   8445 {
   8446     int rv;
   8447 
   8448     if ( FLAGS(pc) & PHY8806X_PM ) {
   8449         return SOC_E_NONE;
   8450     }
   8451 
   8452     /* issue ack command */
   8453     rv = WRITE_PHY8806X_SW_TO_FW_INTERRUPT_REG(unit, pc, (1U << 15) | (0x17 & 0x7ff));
   8454 
   8455     if (SOC_FAILURE(rv)) {
   8456         LOG_WARN(BSL_LS_SOC_PHY,
   8457                  (BSL_META_U(unit,
   8458                              "PHY8806X command handler (ack failure): u=%d p=%d\n"), \
   8459                   unit, pc->port));
   8460         return SOC_E_FAIL;
   8461     }
   8462 
   8463     return SOC_E_NONE;
   8464 }
   8465 
   8466 
   8467 int xmod_test(int unit, int port) 
   8468 {
   8469     uint32 temp32[2];
   8470     int rv;
   8471 
   8472     temp32[0] = 0xaaaaaaaa;
   8473 
   8474     rv = phy_8806x_xmod_command(unit, port, 0x12, &temp32[0], 1, &temp32[1], 1);
   8475 
   8476     LOG_CLI((BSL_META_U(unit,
   8477                         "_phy_8806x_xmod_command: u=%d p=%d "
   8478                         "temp32[0]=0x%08x temp32[1]=0x%08x\n"), unit, port, temp32[0], temp32[1]));
   8479     return rv;
   8480 
   8481 
   8482 }
   8483 
   8484 STATIC int _tsc_reg_read(int unit, phy_ctrl_t *pc, int mode, int tsc_port, int pmd, int pll, uint32 reg, uint16 *value) 
   8485 {
   8486     uint32 data[4], mem_cmd;
   8487     int ring;
   8488 
   8489     ring = (pc->phy_id & 0x4) ? 1 : 0; /* mig too */
   8490 
   8491     /* No other SBUS  accesses between the write and the read. Ie. R5s need to be shutdown. */
   8492 
   8493     mem_cmd = (SBUS_WRITE_MEMORY_CMD_MSG   << 26) |((((tsc_port > 8) ? 0x7 : 0x3) & 0x7f) << 19) |(16 << 7);
   8494 
   8495     reg &= 0xffff;
   8496 
   8497     data[0] = ( (reg | (pmd ? (1U << 27) : 0) ) |  ( (tsc_port & 0x1f) << 19) ) | ((mode & 0x7) << 16) | (pll << 24);
   8498     data[1] = 0;
   8499     data[2] = 0;
   8500     data[3] = 0;
   8501     SOC_IF_ERROR_RETURN
   8502         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   8503 
   8504     mem_cmd = (SBUS_READ_MEMORY_CMD_MSG   << 26) |((((tsc_port > 8) ? 0x7 : 0x3) & 0x7f) << 19) |(16 << 7);
   8505 
   8506     SOC_IF_ERROR_RETURN
   8507         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   8508 
   8509     LOG_INFO(BSL_LS_SOC_PHY, (BSL_META_U(unit,
   8510                         "tsc_reg_read: u=%d p=%d tsc_port=%d"
   8511                         " data[0]=0x%08x data[1]=0x%08x data[2]=0x%08x data[3]=0x%08x\n"),
   8512         unit, pc->port, tsc_port, data[0], data[1], data[2], data[3]));
   8513 
   8514     *value = (data[1] & 0xffff);
   8515 
   8516     return SOC_E_NONE;
   8517 
   8518 }
   8519 
   8520 int tsc_reg_read_test_base(int unit, int port, int sys, int pmd, int pll, uint32 reg) 
   8521 {
   8522     phy_ctrl_t *pc;
   8523     uint16 value;
   8524     int tsc_port;
   8525 
   8526     pc = EXT_PHY_SW_STATE(unit, port);
   8527 
   8528     tsc_port = (sys << 3) + (((pc->phy_id & 0x4) ? 1 : 0) << 2)  + 1;
   8529 
   8530     SOC_IF_ERROR_RETURN
   8531         (_tsc_reg_read(unit, pc, 0, tsc_port, pmd, pll, reg, &value)); 
   8532 
   8533     LOG_CLI((BSL_META_U(unit,
   8534                         "tsc_reg_read_test_base: u=%d p=%d %s "
   8535                         "reg=0x%04x value=0x%04x\n"), unit, port, sys ? "S":"L", reg, value));
   8536 
   8537     return SOC_E_NONE;
   8538 }
   8539 
   8540 
   8541 STATIC int _tsc_reg_write(int unit, phy_ctrl_t *pc, int mode, int tsc_port, int pmd, int pll, uint32 reg, uint16 value, uint16 mask) 
   8542 {
   8543     uint32 data[4], mem_cmd;
   8544     int ring;
   8545 
   8546     ring = (pc->phy_id & 0x4) ? 1 : 0; /* mig too */
   8547 
   8548     mem_cmd = (SBUS_WRITE_MEMORY_CMD_MSG   << 26) |((((tsc_port > 8) ? 0x7 : 0x3) & 0x7f) << 19) |(16 << 7);
   8549 
   8550     reg &= 0xffff;
   8551 
   8552     data[0] = ( (reg | (pmd ? (1U << 27) : 0) ) |  ( (tsc_port & 0x1f) << 19) ) | ((mode & 0x7) << 16) | (pll << 24);
   8553     data[1] = ((value & 0xffff) << 16) | (mask & 0xffff);
   8554     data[2] = 1;
   8555     data[3] = 0;
   8556 
   8557     LOG_INFO(BSL_LS_SOC_PHY, (BSL_META_U(unit,
   8558                         "tsc_reg_write: u=%d p=%d tsc_port=%d"
   8559                         " data[0]=0x%08x data[1]=0x%08x data[2]=0x%08x data[3]=0x%08x\n"),
   8560         unit, pc->port, tsc_port, data[0], data[1], data[2], data[3]));
   8561 
   8562     SOC_IF_ERROR_RETURN
   8563         (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring,  data));
   8564 
   8565     return SOC_E_NONE;
   8566 
   8567 }
   8568 
   8569 int tsc_reg_write_test_base(int unit, int port, int sys, int pmd, int pll, uint32 reg, uint16 value, uint16 mask) 
   8570 {
   8571     phy_ctrl_t *pc;
   8572     int tsc_port;
   8573 
   8574     pc = EXT_PHY_SW_STATE(unit, port);
   8575 
   8576     tsc_port = (sys << 3) + (((pc->phy_id & 0x4) ? 1 : 0) << 2)  + 1;
   8577 
   8578     SOC_IF_ERROR_RETURN
   8579         (_tsc_reg_write(unit, pc, 0, tsc_port, pmd, pll, reg, value, mask)); 
   8580 
   8581     LOG_CLI((BSL_META_U(unit,
   8582                         "tsc_reg_write_test_base: u=%d p=%d %s "
   8583                         "reg=0x%04x value=0x%04x\n"), unit, port, sys ? "S":"L", reg, value));
   8584 
   8585     return SOC_E_NONE;
   8586 }
   8587 
   8588 STATIC int
   8589 phy8806x_medium_get(int unit, soc_port_t port, soc_port_medium_t *medium)
   8590 {
   8591     if (medium == NULL) {
   8592         return SOC_E_PARAM;
   8593     }
   8594 
   8595     *medium = SOC_PORT_MEDIUM_FIBER;
   8596 
   8597     return SOC_E_NONE;
   8598 }
   8599 
   8600 
   8601 STATIC int
   8602 phy8806x_medium_config_get(int unit, soc_port_t port,
   8603                            soc_port_medium_t medium,
   8604                            soc_phy_config_t *cfg)
   8605 {
   8606     int            rv;
   8607     phy_ctrl_t    *pc;
   8608 
   8609     pc = EXT_PHY_SW_STATE(unit, port);
   8610     rv = SOC_E_NONE;
   8611 
   8612     switch (medium) {
   8613     case SOC_PORT_MEDIUM_FIBER:
   8614         sal_memcpy(cfg, &pc->fiber, sizeof (*cfg));
   8615         break;
   8616     default:
   8617         rv = SOC_E_PARAM;
   8618         break;
   8619     }
   8620 
   8621     return rv;
   8622 }
   8623 
   8624  
   8625 STATIC int _phy8806x_dump_buffer(int unit, int port, unsigned char *arg)
   8626 {
   8627     uint32 uart_ptr = 0, print_ptr = 0, temp32, uart_ptr_r = 0, print_ptr_r = 0, mode = 0;
   8628     int cur_buf_size_r = 0, cur_buf_size = 0, avail_buf_size = 0, rv = SOC_E_NONE;
   8629     phy_ctrl_t *pc = NULL;
   8630     unsigned char *ch;
   8631 
   8632     pc = EXT_PHY_SW_STATE(unit, port);
   8633 
   8634     if (pc == NULL) {
   8635         return SOC_E_FAIL;
   8636     }
   8637     ch = arg - 4;
   8638 
   8639     avail_buf_size = (ch[0] | (ch[1] << 8) | (ch[2] << 16) | (ch[3] << 24)) - 8; /* 8 for rounding the AXI buffer */
   8640 
   8641     if (avail_buf_size < 0) {
   8642         LOG_WARN(BSL_LS_SOC_PHY,
   8643                  (BSL_META_U(unit,
   8644                              "Insufficient UART buffer u=%d p=%d\n"), \
   8645                   unit, pc->port));
   8646         return SOC_E_FAIL;
   8647     }
   8648 
   8649     if (sal_mutex_take(xmod_mutex[unit], XMOD_MUTEX_TIMEOUT) < 0)
   8650     {
   8651         LOG_WARN(BSL_LS_SOC_PHY,
   8652                  (BSL_META_U(unit,
   8653                              "phy_8806x_fw_stat_read: Couldn't aquire lock. u=%d p=%d\n"), \
   8654                   unit, pc->port));
   8655         return SOC_E_FAIL;
   8656     }
   8657 
   8658     if (SOC_SUCCESS(rv)) {
   8659         /* read the mode (uart_silent_mode) from the AXI memory of the mHost (pc->phy_id & 0x3) */
   8660         rv = _phy_8806x_axi_read(unit, pc, 0x27fff4 + (pc->phy_id & 0x3) * 0x100000, &temp32, 1);
   8661         mode = LE2HOST32(temp32) & 0x3;
   8662     }
   8663 
   8664     if (! mode ) {
   8665         /* Real uart is active in f/w. Let it fall through. */
   8666         rv = SOC_E_FAIL;
   8667     }
   8668 
   8669     
   8670     if (SOC_SUCCESS(rv)) {
   8671         /* read uart_ptr from the AXI memory of the mHost (pc->phy_id & 0x3) */
   8672         rv = _phy_8806x_axi_read(unit, pc, 0x27fff8 + (pc->phy_id & 0x3) * 0x100000, &temp32, 1);
   8673         uart_ptr = LE2HOST32(temp32);
   8674     }
   8675  
   8676     if (SOC_SUCCESS(rv)) {
   8677         /* read print_ptr from the AXI memory of the mHost (pc->phy_id & 0x3) */
   8678         rv = _phy_8806x_axi_read(unit, pc, 0x27fffc + (pc->phy_id & 0x3) * 0x100000, &temp32, 1);
   8679         print_ptr = LE2HOST32(temp32);
   8680     }
   8681 
   8682     /* printf("Port %d mode = %d uart ptr 0x%x print ptr 0x%x\n", port, mode, uart_ptr, print_ptr); */
   8683     cur_buf_size = print_ptr - uart_ptr;
   8684 
   8685     if ((cur_buf_size > 0) && (cur_buf_size > avail_buf_size)) {
   8686         print_ptr -= cur_buf_size - avail_buf_size;
   8687     }
   8688 
   8689     if ((cur_buf_size < 0) && ( (0x8000 - 0x10 + cur_buf_size) > avail_buf_size)) {
   8690         int temp;
   8691 
   8692         temp = print_ptr - (0x8000 - 0x10 + cur_buf_size - avail_buf_size);
   8693         if (temp < 0) {
   8694             temp += 0x8000 - 0x10;
   8695         }
   8696         print_ptr = temp;
   8697     }
   8698 
   8699     if (SOC_SUCCESS(rv)) {
   8700         uart_ptr_r = uart_ptr & ~0x3;                /* uart_ptr rounded to the previous 4 byte boundary */
   8701         print_ptr_r = (print_ptr + 3) & ~0x3;        /* print_ptr rounded to the next 4 byte boundary */
   8702         cur_buf_size_r = (print_ptr_r - uart_ptr_r); /* rounded cur_buf_size */
   8703     }
   8704 
   8705     if (cur_buf_size_r > 0) {
   8706 
   8707         if (SOC_SUCCESS(rv)) {
   8708             rv = _phy_8806x_axi_read(unit, pc, 0x278000 + uart_ptr_r + ((pc->phy_id & 0x3) << 20), (uint32 *)arg, cur_buf_size_r >> 2 ); /* << 20 = * 0x100000 */
   8709             arg[cur_buf_size_r] = 0;
   8710         }
   8711     } else if (cur_buf_size_r < 0) {
   8712 
   8713         if (SOC_SUCCESS(rv)) {
   8714             /* Read from uart_ptr to end */
   8715             rv = _phy_8806x_axi_read(unit, pc, 0x278000 + uart_ptr_r + ((pc->phy_id & 0x3) << 20), (uint32 *)arg, ((0x8000 - 0x10 - uart_ptr_r) >> 2));
   8716         }
   8717 
   8718         if (SOC_SUCCESS(rv)) {
   8719             /* Read from start to print_ptr */
   8720             rv = _phy_8806x_axi_read(unit, pc, 0x278000 + ((pc->phy_id & 0x3) << 20), (uint32 *)(arg + 0x8000 - 0x10 - uart_ptr_r), print_ptr_r >> 2);
   8721         }
   8722 
   8723         arg[0x8000 - 0x10 + cur_buf_size_r] = 0;
   8724     } else {
   8725         arg[0] = 0;
   8726     }
   8727     
   8728     if (SOC_SUCCESS(rv)) {
   8729         /* Write the print_prt value to the uart_prt localtion. */
   8730         temp32 = HOST2LE32(print_ptr);
   8731         rv = _phy_8806x_axi_write(unit, pc, 0x27fff8 + ((pc->phy_id & 0x3) << 20), &temp32, 1);
   8732     }
   8733 
   8734 #if 0
   8735 /* Read back values */
   8736     _phy_8806x_axi_read(unit, pc, 0x27fff8 +  ((pc->phy_id & 0x3) << 20), &temp32, 1);
   8737     uart_ptr = LE2HOST32(temp32);
   8738  
   8739     _phy_8806x_axi_read(unit, pc, 0x27fffc +  ((pc->phy_id & 0x3) << 20), &temp32, 1);
   8740     print_ptr = LE2HOST32(temp32);
   8741 
   8742     printf("After write Port %d uart ptr 0x%x print ptr 0x%x\n", port, uart_ptr, print_ptr);
   8743 #endif
   8744 
   8745     sal_mutex_give(xmod_mutex[unit]);
   8746 
   8747     if (SOC_FAILURE(rv)) {
   8748         arg[0] = 0;
   8749     }
   8750     return rv;
   8751 }
   8752 
   8753 int phy8806x_xmod_debug_cmd(int unit, int port)
   8754 {
   8755     phy_ctrl_t                *pc;
   8756     soc_phymod_phy_t          *phy;
   8757     soc_phymod_ctrl_t         *pmc;
   8758     int                        rv = SOC_E_NONE;
   8759 
   8760     /* locate phy control */
   8761     pc = EXT_PHY_SW_STATE(unit, port);
   8762     if (pc == NULL) {
   8763         return SOC_E_INTERNAL;
   8764     }
   8765 
   8766 #if defined(INCLUDE_FCMAP)
   8767     if (pc->fcmap_enable) {
   8768         return SOC_E_UNAVAIL;
   8769     }
   8770 #endif
   8771 
   8772     pmc = &pc->phymod_ctrl;
   8773     phy = pmc->phy[0]; 
   8774 
   8775     rv = phymod_debug_ether(&phy->pm_phy);
   8776 
   8777     return rv;
   8778 }
   8779 
   8780 STATIC uint32
   8781 _phy8806x_speed_led_encode(int speed)
   8782 {
   8783     if (speed == 0) {
   8784         return 0;
   8785     } else if (speed == 1000000) { /* 1G */
   8786         return 0x1;
   8787     } else if (speed == 10000000) { /* 10G */
   8788         return 0x2;
   8789     } else if (speed == 20000000) { /* 20G */
   8790         return 0x3;
   8791     } else if (speed == 25000000) { /* 25G */
   8792         return 0x4;
   8793     } else if (speed == 40000000) { /* 40G */
   8794         return 0x5;
   8795     } else if (speed == 50000000) { /* 50G */
   8796         return 0x6;
   8797     } else if (speed == 100000000) { /* 100G */
   8798         return 0x7;
   8799     } else if (speed == 4000000) { /* 4G - FC Only */
   8800         return 0x8;
   8801     } else if (speed == 8000000) { /* 8G - FC Only */
   8802         return 0x9;
   8803     } else if (speed == 16000000) { /* 16G - FC Only */
   8804         return 0xa;
   8805     } else if (speed == 32000000) { /* 32G - FC Only */
   8806         return 0xb;
   8807     } else {
   8808         return 0xf;
   8809     }
   8810 }
   8811 
   8812 int
   8813 phy_mt2_update_led_speed_activity(int unit, soc_port_t port)
   8814 {
   8815     uint32 speed, portdata = 0;
   8816 #ifdef BCM_TOMAHAWK_SUPPORT
   8817     int byte;
   8818     uint32 prev_data, led_dram_base;
   8819     int phy_port = 0;  /* physical port number */
   8820     soc_info_t *si = &SOC_INFO(unit);
   8821 #endif /* BCM_TOMAHAWK_SUPPORT */
   8822     phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port);
   8823 
   8824     if ((pc == NULL) || (!PHY_IS_BCM8806X(pc))){
   8825         return SOC_E_NONE;
   8826     }
   8827 
   8828     /* Update TX activity */
   8829     if (LED_TX(pc)) {
   8830         portdata |= 0x2;
   8831     }
   8832     /* Update RX activity */
   8833     if (LED_RX(pc)) {
   8834         portdata |= 0x4;
   8835     }
   8836     /*Update Speed */
   8837     speed = _phy8806x_speed_led_encode(LED_SPEED(pc));
   8838     portdata |= (speed << 3);
   8839 
   8840     /* For now, only implemented for Tomohawk. Expand as needed */
   8841 #ifdef BCM_TOMAHAWK_SUPPORT
   8842     if (SOC_IS_TOMAHAWK(unit)) {
   8843         phy_port = si->port_l2p_mapping[port];
   8844         led_dram_base = CMIC_LEDUP0_DATA_RAM_OFFSET;
   8845         /* Tomahawk: Port 1-32 and 97-128 are in ledproc0
   8846          *           Port 33-96 are in ledproc1
   8847          *           Port 129 & 131 are in ledproc2
   8848          */
   8849         if (phy_port > 32 && phy_port < 97) {
   8850             led_dram_base = CMIC_LEDUP1_DATA_RAM_OFFSET;
   8851             phy_port -=  32;
   8852         } else if (phy_port == 129 ) {
   8853             led_dram_base = CMIC_LEDUP2_DATA_RAM_OFFSET;
   8854             phy_port = 1;
   8855         } else if (phy_port == 131 ) {
   8856             led_dram_base = CMIC_LEDUP2_DATA_RAM_OFFSET;
   8857             phy_port = 2;
   8858         } else if (phy_port > 32) {
   8859             phy_port -= 64;
   8860         }
   8861         byte = LS_LED_DATA_OFFSET_A0 + phy_port - 1;
   8862 
   8863         prev_data = soc_pci_read(unit, led_dram_base + CMIC_LED_REG_SIZE * byte);
   8864         prev_data &= ~0x7e;
   8865         /* if link is down, mark activity as down
   8866            as activity is not being updated ..*/
   8867         if (prev_data & 0x01) {
   8868             portdata |= prev_data;
   8869         } else {
   8870             portdata = prev_data;
   8871         }
   8872         soc_pci_write(unit, led_dram_base + CMIC_LED_REG_SIZE * byte, portdata);
   8873 
   8874     }
   8875 #endif /* BCM_TOMAHAWK_SUPPORT */
   8876 
   8877     return SOC_E_NONE;
   8878 }
   8879 
   8880 
   8881 #if PHY8806X_DEBUG
   8882 int phy8806x_dev_debug_cmd(int unit, int port, int cmd, void *txbuf, int txlen, int *rsp, void *rxbuf, int rxlen)
   8883 {
   8884     uint32_t xmodtxbuff[XMOD_BUFFER_MAX_LEN/4];
   8885     uint32_t xmodrxbuff[XMOD_BUFFER_MAX_LEN/4];
   8886     uint8_t *buftxptr, *bufrxptr;
   8887     int xmodtxlen, xmodrxlen;
   8888     uint32_t x_cmd, x_response;
   8889     int rv, tx_cmd_len, rx_cmd_len;
   8890 
   8891     /* setting up xmod xmod_dev_debug_cmd:                             */
   8892     /* int xmod_dev_debug_cmd(IN uint32_t cmd, OUT uint32_t response); */
   8893 
   8894     tx_cmd_len = txlen + sizeof(x_cmd);
   8895     rx_cmd_len = rxlen + sizeof(x_response);
   8896 
   8897     /* check for tx lengths */
   8898     if (tx_cmd_len > XMOD_DEV_DEBUG_CMD_IN_LEN) {
   8899         LOG_ERROR(BSL_LS_SOC_PHY,
   8900                      (BSL_META_U(unit,
   8901                       "ERROR, TX length (%d) too long > %d\n"), tx_cmd_len, XMOD_DEV_DEBUG_CMD_IN_LEN));
   8902         return SOC_E_PARAM;
   8903     }
   8904     /* check for rx lengths */
   8905     if (rx_cmd_len > XMOD_DEV_DEBUG_CMD_OUT_LEN) {
   8906         LOG_ERROR(BSL_LS_SOC_PHY,
   8907                      (BSL_META_U(unit,
   8908                       "ERROR, RX length (%d) too long > %d\n"), rx_cmd_len, XMOD_DEV_DEBUG_CMD_OUT_LEN));
   8909         return SOC_E_PARAM;
   8910     }
   8911 
   8912     x_cmd = HOST2LE32(cmd);
   8913 
   8914     /* write args to xmod buffer */
   8915     buftxptr = (uint8_t *)xmodtxbuff;
   8916     WRITE_XMOD_ARG_BUFF(buftxptr, &x_cmd, sizeof(x_cmd));
   8917     xmodtxlen = sizeof(x_cmd);
   8918     if ((txbuf!=NULL) && txlen) {
   8919         WRITE_XMOD_ARG_BUFF(buftxptr, txbuf, txlen);
   8920         xmodtxlen += txlen;
   8921     }
   8922     xmodtxlen = GET_XMOD_BUF_WORD_LEN(xmodtxlen);
   8923 
   8924     /* get rx len */
   8925     xmodrxlen = sizeof(x_response);
   8926     if ((rxbuf!=NULL) && rxlen) {
   8927         xmodrxlen += rxlen;
   8928     }
   8929     xmodrxlen = GET_XMOD_BUF_WORD_LEN(xmodrxlen);
   8930 
   8931     /* call xmod */
   8932     rv = phy_8806x_xmod_command(unit, port, XMOD_CMD_MODE_CORE(XMOD_DEV_DEBUG_CMD), xmodtxbuff, xmodtxlen, xmodrxbuff, xmodrxlen);
   8933 
   8934     /* retrieve the argument from the xmod rx buffer */
   8935     bufrxptr = (uint8_t *)xmodrxbuff;
   8936     READ_XMOD_ARG_BUFF(bufrxptr, &x_response, sizeof(x_response));
   8937     if ((rxbuf!=NULL) && rxlen) {
   8938         READ_XMOD_ARG_BUFF(bufrxptr, rxbuf, rxlen);
   8939     }
   8940     *rsp = LE2HOST32(x_response);
   8941 
   8942     return rv;
   8943 }
   8944 #endif
   8945 
   8946 /*
   8947  * Variable:
   8948  *      phy8806x_drv
   8949  * Purpose:
   8950  *      Phy Driver for BCM8806X PHYs. 
   8951  */
   8952 phy_driver_t phy_8806xdrv = {
   8953     /* .drv_name                      = */ "BCM8806X PHYMOD PHY Driver",
   8954     /* .pd_init                       = */ phy_8806x_init,
   8955     /* .pd_reset                      = */ phy_null_reset,
   8956     /* .pd_link_get                   = */ phy_8806x_link_get,
   8957     /* .pd_enable_set                 = */ phy_8806x_enable_set,
   8958     /* .pd_enable_get                 = */ phy_8806x_enable_get,
   8959     /* .pd_duplex_set                 = */ phy_null_set,
   8960     /* .pd_duplex_get                 = */ phy_8806x_duplex_get,
   8961     /* .pd_speed_set                  = */ phy_8806x_speed_set,
   8962     /* .pd_speed_get                  = */ phy_8806x_speed_get,
   8963     /* .pd_master_set                 = */ phy_null_set,
   8964     /* .pd_master_get                 = */ phy_null_zero_get,
   8965     /* .pd_an_set                     = */ phy_8806x_an_set,
   8966     /* .pd_an_get                     = */ phy_8806x_an_get,
   8967     /* .pd_adv_local_set              = */ NULL, /* Deprecated */
   8968     /* .pd_adv_local_get              = */ NULL, /* Deprecated */
   8969     /* .pd_adv_remote_get             = */ NULL, /* Deprecated */ 
   8970     /* .pd_lb_set                     = */ phy_8806x_lb_set,
   8971     /* .pd_lb_get                     = */ phy_8806x_lb_get,
   8972     /* .pd_interface_set              = */ phy_8806x_interface_set,
   8973     /* .pd_interface_get              = */ phy_8806x_interface_get,
   8974     /* .pd_ability                    = */ NULL, /* Deprecated */ 
   8975     /* .pd_linkup_evt                 = */ phy_8806x_linkup,
   8976     /* .pd_linkdn_evt                 = */ NULL,
   8977     /* .pd_mdix_set                   = */ phy_null_mdix_set,
   8978     /* .pd_mdix_get                   = */ phy_null_mdix_get,
   8979     /* .pd_mdix_status_get            = */ phy_null_mdix_status_get,
   8980     /* .pd_medium_config_set          = */ NULL,
   8981     /* .pd_medium_config_get          = */ phy8806x_medium_config_get,
   8982     /* .pd_medium_get                 = */ phy8806x_medium_get,
   8983     /* .pd_cable_diag                 = */ NULL,
   8984     /* .pd_link_change                = */ NULL,
   8985     /* .pd_control_set                = */ phy_8806x_control_set,
   8986     /* .pd_control_get                = */ phy_8806x_control_get,
   8987     /* .pd_reg_read                   = */ phy_8806x_reg_read,
   8988     /* .pd_reg_write                  = */ phy_8806x_reg_write,
   8989     /* .pd_reg_modify                 = */ phy_8806x_reg_modify,
   8990     /* .pd_notify                     = */ NULL,
   8991     /* .pd_probe                      = */ phy_8806x_probe,
   8992     /* .pd_ability_advert_set         = */ phy_8806x_ability_advert_set, 
   8993     /* .pd_ability_advert_get         = */ phy_8806x_ability_advert_get,
   8994     /* .pd_ability_remote_get         = */ phy_8806x_ability_remote_get,
   8995     /* .pd_ability_local_get          = */ phy_8806x_ability_local_get,
   8996     /* .pd_firmware_set               = */ phy_8806x_firmware_set,
   8997     /* .pd_timesync_config_set        = */ NULL,
   8998     /* .pd_timesync_config_get        = */ NULL,
   8999     /* .pd_timesync_control_set       = */ NULL,
   9000     /* .pd_timesync_control_set       = */ NULL,
   9001     /* .pd_diag_ctrl                  = */ phy_8806x_diag_ctrl,
   9002     /* .pd_lane_control_set           = */ NULL,    
   9003     /* .pd_lane_control_get           = */ NULL,
   9004     /* .pd_lane_reg_read              = */ NULL,
   9005     /* .pd_lane_reg_write             = */ NULL,
   9006     /* .pd_oam_config_set             = */ NULL,
   9007     /* .pd_oam_config_get             = */ NULL,
   9008     /* .pd_oam_control_set            = */ NULL,
   9009     /* .pd_oam_control_get            = */ NULL,
   9010     /* .pd_timesync_enhanced_capture_get = */ NULL,
   9011     /* .pd_multi_get                  = */ phy_8806x_multi_reg_read,
   9012     /* .pd_precondition_before_probe  = */ NULL,
   9013     /* .pd_linkfault_get              = */ phy_8806x_linkfault_get
   9014 };
   9015 
   9016 #else
   9017 int _8806x_not_empty;
   9018 #endif /* INCLUDE_PHY_8806X */
   9019