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

tscbh.c (156291B)


      1 /*
      2  *
      3  * 
      4  *
      5  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      6  * 
      7  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      8  */
      9 
     10 #include <phymod/phymod.h>
     11 #include <phymod/phymod_system.h>
     12 #include <phymod/phymod_util.h>
     13 #include <phymod/phymod_dispatch.h>
     14 #include <phymod/chip/bcmi_tscbh_xgxs_defs.h>
     15 #include <phymod/chip/tscbh.h>
     16 #include "tscbh/tier1/tbhmod.h"
     17 #include "tscbh/tier1/tbhmod_sc_lkup_table.h"
     18 #include "tscbh/tier1/tbhmod_1588_lkup_table.h"
     19 #include "tscbh/tier1/tbhPCSRegEnums.h"
     20 #include "blackhawk/tier1/blackhawk_cfg_seq.h"
     21 #include "blackhawk/tier1/blackhawk_tsc_enum.h"
     22 #include "blackhawk/tier1/blackhawk_tsc_common.h"
     23 #include "blackhawk/tier1/blackhawk_tsc_interface.h"
     24 #include "blackhawk/tier1/blackhawk_tsc_dependencies.h"
     25 #include "blackhawk/tier1/blackhawk_tsc_internal.h"
     26 #include "blackhawk/tier1/public/blackhawk_api_uc_vars_rdwr_defns_public.h"
     27 #include "blackhawk/tier1/blackhawk_tsc_access.h"
     28 
     29 
     30 extern unsigned char blackhawk_ucode_rev0[];
     31 extern unsigned int blackhawk_ucode_len_rev0;
     32 extern unsigned short blackhawk_ucode_crc_rev0;
     33 extern unsigned short blackhawk_ucode_stack_size_rev0;
     34 
     35 extern unsigned char blackhawk_ucode_rev1[];
     36 extern unsigned int blackhawk_ucode_len_rev1;
     37 extern unsigned short blackhawk_ucode_crc_rev1;
     38 extern unsigned short blackhawk_ucode_stack_size_rev1;
     39 
     40 extern uint32_t spd_id_entry_26[TSCBH_SPEED_ID_TABLE_SIZE][TSCBH_SPEED_ID_ENTRY_SIZE];
     41 extern uint32_t spd_id_entry_25[TSCBH_SPEED_ID_TABLE_SIZE][TSCBH_SPEED_ID_ENTRY_SIZE];
     42 extern uint32_t spd_id_entry_20[TSCBH_SPEED_ID_TABLE_SIZE][TSCBH_SPEED_ID_ENTRY_SIZE];
     43 extern uint32_t am_table_entry[TSCBH_AM_TABLE_SIZE][TSCBH_AM_ENTRY_SIZE];
     44 extern uint32_t um_table_entry[TSCBH_UM_TABLE_SIZE][TSCBH_UM_ENTRY_SIZE];
     45 extern uint32_t speed_priority_mapping_table[TSCBH_SPEED_PRIORITY_MAPPING_TABLE_SIZE][TSCBH_SPEED_PRIORITY_MAPPING_ENTRY_SIZE];
     46 
     47 extern const ts_table_entry ts_table_rx_sop[TBHMOD_SPEED_MODE_COUNT];
     48 extern const ts_table_entry ts_table_tx_sop[TBHMOD_SPEED_MODE_COUNT];
     49 
     50 #define TSCBH_SERDES_ID           0x25 /* 0x9008 Main0_serdesID - Serdes ID Register */
     51 
     52 int tscbh_core_identify(const phymod_core_access_t* core, uint32_t core_id, uint32_t* is_identified)
     53 {
     54     PHYID2r_t id2;
     55     PHYID3r_t id3;
     56     MAIN0_SERDESIDr_t serdesid;
     57     int ioerr = 0;
     58 
     59     *is_identified = 0;
     60     ioerr += READ_PHYID2r(&core->access, &id2);
     61     ioerr += READ_PHYID3r(&core->access, &id3);
     62 
     63     if (PHYID2r_REGID1f_GET(id2) == TSCBH_ID0 &&
     64        (PHYID3r_REGID2f_GET(id3) == TSCBH_ID1)) {
     65         /* PHY IDs match - now check PCS model */
     66         ioerr += READ_MAIN0_SERDESIDr(&core->access, &serdesid);
     67         if ( (MAIN0_SERDESIDr_MODEL_NUMBERf_GET(serdesid)) == TSCBH_SERDES_ID)  {
     68             *is_identified = 1;
     69         }
     70     }
     71     return ioerr ? PHYMOD_E_IO : PHYMOD_E_NONE;
     72 }
     73 
     74 
     75 int tscbh_core_info_get(const phymod_core_access_t* core, phymod_core_info_t* info)
     76 {
     77     int rv = 0;
     78     MAIN0_SERDESIDr_t serdes_id;
     79     char core_name[15] = "Tscbh16";
     80     PHYID2r_t id2;
     81     PHYID3r_t id3;
     82     const phymod_access_t *pm_acc = &core->access;
     83 
     84     rv = READ_MAIN0_SERDESIDr(&core->access, &serdes_id);
     85 
     86     info->serdes_id = MAIN0_SERDESIDr_GET(serdes_id);
     87     PHYMOD_IF_ERR_RETURN
     88         (phymod_core_name_get(core, MAIN0_SERDESIDr_GET(serdes_id), core_name, info));
     89     info->serdes_id = MAIN0_SERDESIDr_GET(serdes_id);
     90     info->core_version = phymodCoreVersionTscbh16;
     91 
     92     PHYMOD_IF_ERR_RETURN(READ_PHYID2r(pm_acc, &id2));
     93     PHYMOD_IF_ERR_RETURN(READ_PHYID3r(pm_acc, &id3));
     94 
     95     info->phy_id0 = (uint16_t) id2.v[0];
     96     info->phy_id1 = (uint16_t) id3.v[0];
     97 
     98     return rv;
     99 }
    100 
    101 
    102 int tscbh_core_lane_map_get(const phymod_core_access_t* core, phymod_lane_map_t* lane_map)
    103 {
    104     return PHYMOD_E_NONE;
    105 }
    106 
    107 
    108 int tscbh_core_reset_set(const phymod_core_access_t* core, phymod_reset_mode_t reset_mode, phymod_reset_direction_t direction)
    109 {
    110     return PHYMOD_E_NONE;
    111 
    112 }
    113 
    114 int tscbh_core_reset_get(const phymod_core_access_t* core, phymod_reset_mode_t reset_mode, phymod_reset_direction_t* direction)
    115 {
    116     return PHYMOD_E_NONE;
    117 
    118 }
    119 
    120 int tscbh_phy_tx_lane_control_set(const phymod_phy_access_t* phy, phymod_phy_tx_lane_control_t tx_control)
    121 {
    122     phymod_firmware_lane_config_t fw_lane_config;
    123     phymod_phy_access_t phy_copy;
    124 
    125     PHYMOD_IF_ERR_RETURN (tscbh_phy_firmware_lane_config_get(phy, &fw_lane_config));
    126     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
    127 
    128     switch (tx_control) {
    129         case phymodTxTrafficDisable:
    130             PHYMOD_IF_ERR_RETURN(tbhmod_tx_lane_control(&phy_copy.access, 0, TBHMOD_TX_LANE_TRAFFIC_DISABLE));
    131             break;
    132         case phymodTxTrafficEnable:
    133             /* whenever the second inpout which is enable is set, then the thrid parameter is do not care */
    134             PHYMOD_IF_ERR_RETURN(tbhmod_tx_lane_control(&phy_copy.access, 1, TBHMOD_TX_LANE_ILLEGAL));
    135             break;
    136         case phymodTxReset:
    137             PHYMOD_IF_ERR_RETURN(tbhmod_tx_lane_control(&phy_copy.access, 0, TBHMOD_TX_LANE_RESET));
    138             break;
    139         case phymodTxElectricalIdleEnable:
    140             if (fw_lane_config.LaneConfigFromPCS == 0) {
    141                 PHYMOD_IF_ERR_RETURN(blackhawk_electrical_idle_set(&phy_copy.access, 1));
    142             } else {
    143                 return PHYMOD_E_PARAM;
    144             }
    145             break;
    146         case phymodTxElectricalIdleDisable:
    147             PHYMOD_IF_ERR_RETURN(blackhawk_electrical_idle_set(&phy_copy.access, 0));
    148             break;
    149         case phymodTxSquelchOn:
    150             PHYMOD_IF_ERR_RETURN(blackhawk_tsc_tx_disable(&phy_copy.access, 1));
    151             break;
    152         case phymodTxSquelchOff:
    153             PHYMOD_IF_ERR_RETURN(blackhawk_tsc_tx_disable(&phy_copy.access, 0));
    154             break;
    155         default:
    156             return PHYMOD_E_PARAM;
    157     }
    158     return PHYMOD_E_NONE;
    159 
    160 }
    161 
    162 
    163 int tscbh_phy_tx_lane_control_get(const phymod_phy_access_t* phy, phymod_phy_tx_lane_control_t *tx_control)
    164 {
    165     uint8_t tx_disable;
    166     int reset, tx_lane;
    167     uint32_t lb_enable;
    168     phymod_phy_access_t pm_phy_copy;
    169     int start_lane, num_lane;
    170 
    171     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
    172     /* next program the tx fir taps and driver current based on the input */
    173     PHYMOD_IF_ERR_RETURN
    174         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
    175 
    176     pm_phy_copy.access.lane_mask = 0x1 << start_lane;
    177 
    178     PHYMOD_IF_ERR_RETURN(blackhawk_tsc_tx_disable_get(&pm_phy_copy.access, &tx_disable));
    179 
    180     /* next check if PMD loopback is on */
    181     if (tx_disable) {
    182         PHYMOD_IF_ERR_RETURN(blackhawk_tsc_dig_lpbk_get(&pm_phy_copy.access, &lb_enable));
    183         if (lb_enable) tx_disable = 0;
    184     }
    185 
    186     if(tx_disable) {
    187         *tx_control = phymodTxSquelchOn;
    188     } else {
    189         PHYMOD_IF_ERR_RETURN(tbhmod_tx_lane_control_get(&pm_phy_copy.access, &reset, &tx_lane));
    190         if (!reset) {
    191             *tx_control = phymodTxReset;
    192         } else if (!tx_lane) {
    193             *tx_control = phymodTxTrafficDisable;
    194         } else {
    195             *tx_control = phymodTxTrafficEnable;
    196         }
    197     }
    198     return PHYMOD_E_NONE;
    199 }
    200 
    201 /*Rx control*/
    202 int tscbh_phy_rx_lane_control_set(const phymod_phy_access_t* phy, phymod_phy_rx_lane_control_t rx_control)
    203 {
    204     phymod_phy_access_t pm_phy_copy;
    205 
    206     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
    207 
    208     switch (rx_control) {
    209         case phymodRxReset:
    210             PHYMOD_IF_ERR_RETURN(tbhmod_rx_lane_control(&pm_phy_copy.access, 0));
    211             break;
    212         case phymodRxSquelchOn:
    213             PHYMOD_IF_ERR_RETURN(blackhawk_pmd_force_signal_detect(&pm_phy_copy.access, 1, 0));
    214             break;
    215         case phymodRxSquelchOff:
    216             PHYMOD_IF_ERR_RETURN(blackhawk_pmd_force_signal_detect(&pm_phy_copy.access, 0, 0));
    217             break;
    218         default:
    219             return PHYMOD_E_PARAM;
    220     }
    221 
    222     return PHYMOD_E_NONE;
    223 }
    224 
    225 int tscbh_phy_rx_lane_control_get(const phymod_phy_access_t* phy, phymod_phy_rx_lane_control_t* rx_control)
    226 {
    227     int reset, rx_squelch_enable;
    228     uint32_t lb_enable;
    229     uint8_t force_en, force_val;
    230     phymod_phy_access_t pm_phy_copy;
    231 
    232     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
    233 
    234     /* first get the force enabled bit and forced value */
    235     PHYMOD_IF_ERR_RETURN(blackhawk_pmd_force_signal_detect_get(&pm_phy_copy.access, &force_en, &force_val));
    236 
    237     if (force_en & (!force_val)) {
    238         rx_squelch_enable = 1;
    239     } else {
    240         rx_squelch_enable = 0;
    241     }
    242 
    243     /* next check if PMD loopback is on */
    244     if (rx_squelch_enable) {
    245         PHYMOD_IF_ERR_RETURN(blackhawk_tsc_dig_lpbk_get(&pm_phy_copy.access, &lb_enable));
    246         if (lb_enable) rx_squelch_enable = 0;
    247     }
    248     if(rx_squelch_enable) {
    249         *rx_control = phymodRxSquelchOn;
    250     } else {
    251         PHYMOD_IF_ERR_RETURN(tbhmod_rx_lane_control_get(&pm_phy_copy.access, &reset));
    252         if (reset == 0) {
    253             *rx_control = phymodRxReset;
    254         } else {
    255             *rx_control = phymodRxSquelchOff;
    256         }
    257     }
    258     return PHYMOD_E_NONE;
    259 
    260 }
    261 
    262 /* load tscbh fw. the fw_loader parameter is valid just for external fw load*/
    263 STATIC
    264 int _tscbh_core_firmware_load(const phymod_core_access_t* core, const phymod_core_init_config_t* init_config)
    265 {
    266     phymod_core_access_t  core_copy;
    267     phymod_phy_access_t phy_access;
    268     unsigned int blackhawk_ucode_len;
    269     unsigned char *blackhawk_ucode;
    270     uint32_t rev_num = 0;
    271 
    272     PHYMOD_MEMCPY(&core_copy, core, sizeof(core_copy));
    273     TSCBH_CORE_TO_PHY_ACCESS(&phy_access, core);
    274 
    275     phy_access.access.lane_mask = 0x1;
    276     PHYMOD_IF_ERR_RETURN
    277         (tbhmod_revid_get(&phy_access.access, &rev_num));
    278     if (rev_num == TBHMOD_REV_NUM_0) {
    279         blackhawk_ucode = blackhawk_ucode_rev0;
    280         blackhawk_ucode_len = blackhawk_ucode_len_rev0;
    281     } else {
    282         blackhawk_ucode = blackhawk_ucode_rev1;
    283         blackhawk_ucode_len = blackhawk_ucode_len_rev1;
    284     }
    285 
    286     switch(init_config->firmware_load_method){
    287     case phymodFirmwareLoadMethodInternal:
    288         PHYMOD_IF_ERR_RETURN(blackhawk_tsc_ucode_mdio_load(&core_copy.access, blackhawk_ucode, blackhawk_ucode_len));
    289         break;
    290     case phymodFirmwareLoadMethodExternal:
    291         PHYMOD_NULL_CHECK(init_config->firmware_loader);
    292         PHYMOD_IF_ERR_RETURN(blackhawk_tsc_ucode_init(&core_copy.access));
    293         PHYMOD_IF_ERR_RETURN
    294             (blackhawk_pram_firmware_enable(&core_copy.access, 1, 0));
    295         PHYMOD_IF_ERR_RETURN(init_config->firmware_loader(core, blackhawk_ucode_len, blackhawk_ucode));
    296         PHYMOD_IF_ERR_RETURN
    297             (blackhawk_pram_firmware_enable(&core_copy.access, 0, 0));
    298         break;
    299     case phymodFirmwareLoadMethodNone:
    300         break;
    301     default:
    302         PHYMOD_RETURN_WITH_ERR(PHYMOD_E_CONFIG, (_PHYMOD_MSG("illegal fw load method %u"), init_config->firmware_load_method));
    303     }
    304 
    305     return PHYMOD_E_NONE;
    306 
    307 }
    308 
    309 int tscbh_phy_firmware_lane_config_get(const phymod_phy_access_t* phy, phymod_firmware_lane_config_t* fw_config)
    310 {
    311     struct blackhawk_tsc_uc_lane_config_st lane_config;
    312     phymod_phy_access_t pm_phy_copy;
    313 
    314     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
    315 
    316     PHYMOD_MEMSET(&lane_config, 0x0, sizeof(lane_config));
    317     PHYMOD_MEMSET(fw_config, 0, sizeof(*fw_config));
    318 
    319     PHYMOD_IF_ERR_RETURN
    320         (blackhawk_tsc_get_uc_lane_cfg(&pm_phy_copy.access, &lane_config));
    321 
    322     fw_config->LaneConfigFromPCS     = lane_config.field.lane_cfg_from_pcs;
    323     fw_config->AnEnabled             = lane_config.field.an_enabled;
    324     fw_config->DfeOn                 = lane_config.field.dfe_on;
    325     fw_config->LpDfeOn               = lane_config.field.dfe_lp_mode;
    326     fw_config->ForceBrDfe            = lane_config.field.force_brdfe_on;
    327     fw_config->MediaType             = lane_config.field.media_type;
    328     fw_config->UnreliableLos         = lane_config.field.unreliable_los;
    329     fw_config->Cl72AutoPolEn         = lane_config.field.cl72_auto_polarity_en;
    330     fw_config->ScramblingDisable     = lane_config.field.scrambling_dis;
    331     fw_config->Cl72RestTO            = lane_config.field.cl72_restart_timeout_en;
    332     fw_config->ForceExtenedReach     = lane_config.field.force_es;
    333     fw_config->ForceNormalReach      = lane_config.field.force_ns;
    334     fw_config->LpPrecoderEnabled     = lane_config.field.lp_has_prec_en;
    335     fw_config->ForcePAM4Mode         = lane_config.field.force_pam4_mode;
    336     fw_config->ForceNRZMode          = lane_config.field.force_nrz_mode;
    337 
    338     return PHYMOD_E_NONE;
    339 }
    340 
    341 int tscbh_phy_tx_set(const phymod_phy_access_t* phy, const phymod_tx_t* tx)
    342 {
    343     phymod_phy_access_t phy_copy;
    344     int start_lane, num_lane, i;
    345     enum blackhawk_tsc_txfir_tap_enable_enum enable_taps = NRZ_6TAP;
    346     uint32_t lane_reset, pcs_lane_enable;
    347 
    348     PHYMOD_IF_ERR_RETURN
    349         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
    350     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
    351 
    352     /*next check if PCS lane is in reset */
    353     PHYMOD_IF_ERR_RETURN
    354         (tbhmod_enable_get(&phy_copy.access, &pcs_lane_enable));
    355 
    356     /*first check if lane is in reset */
    357     PHYMOD_IF_ERR_RETURN
    358         (blackhawk_lane_soft_reset_get(&phy_copy.access, &lane_reset));
    359 
    360     /* disable pcs lane if pcs lane not in rset */
    361     if (pcs_lane_enable) {
    362         phy_copy.access.lane_mask = 1 << start_lane;
    363         PHYMOD_IF_ERR_RETURN
    364             (tbhmod_disable_set(&phy_copy.access));
    365     }
    366     if (!lane_reset) {
    367         PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
    368         PHYMOD_IF_ERR_RETURN
    369             (blackhawk_lane_soft_reset(&phy_copy.access, 1));
    370     }
    371 
    372     for (i = 0; i < num_lane; i++) {
    373         if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
    374             continue;
    375         }
    376         phy_copy.access.lane_mask = 1 << (start_lane + i);
    377         /*next check 3 tap mode or 6 tap mode */
    378         if (tx->tap_mode == phymodTxTapMode3Tap) {
    379             if (tx->sig_method == phymodSignallingMethodNRZ) {
    380                 enable_taps= NRZ_LP_3TAP;
    381             } else {
    382                 enable_taps= PAM4_LP_3TAP;
    383             }
    384             PHYMOD_IF_ERR_RETURN
    385                 (blackhawk_tsc_apply_txfir_cfg(&phy_copy.access,
    386                                                  enable_taps,
    387                                                  0,
    388                                                  tx->pre,
    389                                                  tx->main,
    390                                                  tx->post,
    391                                                  0,
    392                                                  0));
    393         } else {
    394             if (tx->sig_method == phymodSignallingMethodNRZ) {
    395                 enable_taps= NRZ_6TAP;
    396             } else {
    397                 enable_taps= PAM4_6TAP;
    398             }
    399             PHYMOD_IF_ERR_RETURN
    400                 (blackhawk_tsc_apply_txfir_cfg(&phy_copy.access,
    401                                                  enable_taps,
    402                                                  tx->pre2,
    403                                                  tx->pre,
    404                                                  tx->main,
    405                                                  tx->post,
    406                                                  tx->post2,
    407                                                  tx->post3));
    408         }
    409     }
    410 
    411     if (!lane_reset) {
    412         PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
    413         PHYMOD_IF_ERR_RETURN
    414             (blackhawk_lane_soft_reset(&phy_copy.access, 0));
    415     }
    416 
    417     /* re-enable pcs lane if pcs lane not in rset */
    418     if (pcs_lane_enable) {
    419         phy_copy.access.lane_mask = 1 << start_lane;
    420         PHYMOD_IF_ERR_RETURN
    421             (tbhmod_enable_set(&phy_copy.access));
    422     }
    423     return PHYMOD_E_NONE;
    424 }
    425 
    426 int tscbh_phy_media_type_tx_get(const phymod_phy_access_t* phy, phymod_media_typed_t media, phymod_tx_t* tx)
    427 {
    428 
    429     return PHYMOD_E_NONE;
    430 
    431 }
    432 
    433 
    434 /*
    435  * set lane swapping for core
    436  */
    437 
    438 int tscbh_core_lane_map_set(const phymod_core_access_t* core, const phymod_lane_map_t* lane_map)
    439 {
    440     phymod_core_access_t  core_copy;
    441     uint32_t lane, pcs_tx_swap = 0, pcs_rx_swap = 0;
    442     uint8_t pmd_tx_addr[8], pmd_rx_addr[8];
    443 
    444     if (lane_map->num_of_lanes != TSCBH_NOF_LANES_IN_CORE){
    445         return PHYMOD_E_CONFIG;
    446     }
    447 
    448     PHYMOD_MEMCPY(&core_copy, core, sizeof(core_copy));
    449     core_copy.access.lane_mask = 0x1;
    450 
    451     for (lane = 0; lane < TSCBH_NOF_LANES_IN_CORE; lane++){
    452         if ((lane_map->lane_map_tx[lane] >= TSCBH_NOF_LANES_IN_CORE)||
    453              (lane_map->lane_map_rx[lane] >= TSCBH_NOF_LANES_IN_CORE)){
    454             return PHYMOD_E_CONFIG;
    455         }
    456         /*encode each lane as four bits*/
    457         
    458         pcs_tx_swap += lane_map->lane_map_tx[lane]<<(lane*4);
    459         pcs_rx_swap += lane_map->lane_map_rx[lane]<<(lane*4);
    460     }
    461     /* PMD lane addr is based on PCS logical to physical mapping*/
    462     for (lane = 0; lane < TSCBH_NOF_LANES_IN_CORE; lane++){
    463         pmd_tx_addr[((pcs_tx_swap >> (lane*4)) & 0xf)] = lane;
    464         pmd_rx_addr[((pcs_rx_swap >> (lane*4)) & 0xf)] = lane;
    465     }
    466 
    467     PHYMOD_IF_ERR_RETURN
    468         (tbhmod_pcs_tx_lane_swap(&core_copy.access, pcs_tx_swap));
    469     PHYMOD_IF_ERR_RETURN
    470         (tbhmod_pcs_rx_lane_swap(&core_copy.access, pcs_rx_swap));
    471     PHYMOD_IF_ERR_RETURN
    472         (blackhawk_tsc_map_lanes(&core_copy.access, TSCBH_NOF_LANES_IN_CORE, pmd_tx_addr, pmd_rx_addr));
    473 
    474     return PHYMOD_E_NONE;
    475 }
    476 
    477 #if 0
    478 STATIC
    479 int _tscbh_speed_config_get(uint32_t speed, uint32_t *pll_multiplier, uint32_t *is_pam4, uint32_t *osr_mode)
    480 {
    481     return PHYMOD_E_NONE;
    482 }
    483 #endif
    484 
    485 int _tscbh_phy_firmware_lane_config_set(const phymod_phy_access_t* phy, phymod_firmware_lane_config_t fw_config)
    486 {
    487     uint32_t is_warm_boot;
    488     struct blackhawk_tsc_uc_lane_config_st serdes_firmware_config;
    489     phymod_phy_access_t phy_copy;
    490     int start_lane, num_lane, i;
    491     uint32_t rst_status;
    492 
    493     PHYMOD_MEMSET(&serdes_firmware_config, 0x0, sizeof(serdes_firmware_config));
    494     PHYMOD_IF_ERR_RETURN
    495         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
    496     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
    497 
    498     for (i = 0; i < num_lane; i++) {
    499         if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
    500             continue;
    501         }
    502         phy_copy.access.lane_mask = 1 << (start_lane + i);
    503         serdes_firmware_config.field.lane_cfg_from_pcs      = fw_config.LaneConfigFromPCS;
    504         serdes_firmware_config.field.an_enabled             = fw_config.AnEnabled;
    505         serdes_firmware_config.field.dfe_on                 = fw_config.DfeOn;
    506         serdes_firmware_config.field.force_brdfe_on         = fw_config.ForceBrDfe;
    507         /* serdes_firmware_config.field.cl72_emulation_en = fw_config.Cl72Enable; */
    508         serdes_firmware_config.field.scrambling_dis         = fw_config.ScramblingDisable;
    509         serdes_firmware_config.field.unreliable_los         = fw_config.UnreliableLos;
    510         serdes_firmware_config.field.media_type             = fw_config.MediaType;
    511         serdes_firmware_config.field.dfe_lp_mode            = fw_config.LpDfeOn;
    512         serdes_firmware_config.field.cl72_auto_polarity_en  = fw_config.Cl72AutoPolEn;
    513         serdes_firmware_config.field.cl72_restart_timeout_en = fw_config.Cl72RestTO;
    514         serdes_firmware_config.field.force_es               = fw_config.ForceExtenedReach;
    515         serdes_firmware_config.field.force_ns               = fw_config.ForceNormalReach;
    516         serdes_firmware_config.field.force_nrz_mode         = fw_config.ForceNRZMode;
    517         serdes_firmware_config.field.force_pam4_mode        = fw_config.ForcePAM4Mode;
    518         serdes_firmware_config.field.lp_has_prec_en         = fw_config.LpPrecoderEnabled;
    519 
    520         PHYMOD_IF_ERR_RETURN(PHYMOD_IS_WRITE_DISABLED(&phy->access, &is_warm_boot));
    521 
    522         if (!is_warm_boot) {
    523             PHYMOD_IF_ERR_RETURN(blackhawk_lane_soft_reset_get(&phy_copy.access, &rst_status));
    524             if (!rst_status) PHYMOD_IF_ERR_RETURN (blackhawk_lane_soft_reset(&phy_copy.access, 1));
    525             PHYMOD_IF_ERR_RETURN(blackhawk_tsc_set_uc_lane_cfg(&phy_copy.access, serdes_firmware_config));
    526             if (!rst_status) PHYMOD_IF_ERR_RETURN (blackhawk_lane_soft_reset(&phy_copy.access, 0));
    527         }
    528     }
    529 
    530     return PHYMOD_E_NONE;
    531 }
    532 
    533 int tscbh_phy_firmware_lane_config_set(const phymod_phy_access_t* phy, phymod_firmware_lane_config_t fw_config)
    534 {
    535     phymod_phy_access_t phy_copy;
    536     uint32_t lane_reset, pcs_lane_enable;
    537     int start_lane, num_lane;
    538 
    539     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
    540     PHYMOD_IF_ERR_RETURN
    541         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
    542 
    543     /*first check if lane is in reset */
    544     PHYMOD_IF_ERR_RETURN
    545         (blackhawk_lane_soft_reset_get(&phy_copy.access, &lane_reset));
    546 
    547     /*next check if PCS lane is in reset */
    548     PHYMOD_IF_ERR_RETURN
    549         (tbhmod_enable_get(&phy_copy.access, &pcs_lane_enable));
    550 
    551     /* disable pcs lane if pcs lane not in rset */
    552     if (pcs_lane_enable) {
    553         phy_copy.access.lane_mask = 1 << start_lane;
    554         PHYMOD_IF_ERR_RETURN
    555             (tbhmod_disable_set(&phy_copy.access));
    556     }
    557 
    558     /* if lane is not in reset, then reset the lane first */
    559     if (!lane_reset) {
    560         PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
    561         PHYMOD_IF_ERR_RETURN
    562             (blackhawk_lane_soft_reset(&phy_copy.access, 1));
    563     }
    564 
    565     PHYMOD_IF_ERR_RETURN
    566          (_tscbh_phy_firmware_lane_config_set(phy, fw_config));
    567 
    568     if (!lane_reset) {
    569         PHYMOD_IF_ERR_RETURN
    570             (blackhawk_lane_soft_reset(&phy_copy.access, 0));
    571     }
    572 
    573     /* re-enable pcs lane if pcs lane not in rset */
    574     if (pcs_lane_enable) {
    575         phy_copy.access.lane_mask = 1 << start_lane;
    576         PHYMOD_IF_ERR_RETURN
    577             (tbhmod_enable_set(&phy_copy.access));
    578     }
    579 
    580     return PHYMOD_E_NONE;
    581 }
    582 
    583 
    584 /* reset rx sequencer
    585  * flags - unused parameter
    586  */
    587 int tscbh_phy_rx_restart(const phymod_phy_access_t* phy)
    588 {
    589 
    590     return PHYMOD_E_NONE;
    591 }
    592 
    593 
    594 int tscbh_phy_polarity_set(const phymod_phy_access_t* phy, const phymod_polarity_t* polarity)
    595 {
    596     phymod_phy_access_t phy_copy;
    597     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
    598 
    599     PHYMOD_IF_ERR_RETURN
    600         (blackhawk_tx_rx_polarity_set(&phy_copy.access, polarity->tx_polarity, polarity->rx_polarity));
    601 
    602     return PHYMOD_E_NONE;
    603 }
    604 
    605 
    606 int tscbh_phy_polarity_get(const phymod_phy_access_t* phy, phymod_polarity_t* polarity)
    607 {
    608     int start_lane, num_lane, i;
    609     phymod_polarity_t temp_pol;
    610     phymod_phy_access_t phy_copy;
    611     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
    612 
    613     /* figure out the lane num and start_lane based on the input */
    614     PHYMOD_IF_ERR_RETURN
    615         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
    616 
    617     polarity->tx_polarity = 0;
    618     polarity->rx_polarity = 0;
    619     for (i = 0; i < num_lane; i++) {
    620         if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
    621             continue;
    622         }
    623         phy_copy.access.lane_mask = 0x1 << (i + start_lane);
    624         temp_pol.tx_polarity = 0;
    625         temp_pol.rx_polarity = 0;
    626         PHYMOD_IF_ERR_RETURN
    627             (blackhawk_tx_rx_polarity_get(&phy_copy.access, &temp_pol.tx_polarity, &temp_pol.rx_polarity));
    628         polarity->tx_polarity |= ((temp_pol.tx_polarity & 0x1) << i);
    629         polarity->rx_polarity |= ((temp_pol.rx_polarity & 0x1) << i);
    630     }
    631 
    632     return PHYMOD_E_NONE;
    633 }
    634 
    635 int tscbh_phy_tx_get(const phymod_phy_access_t* phy, phymod_tx_t* tx)
    636 {
    637     uint8_t pmd_tx_tap_mode;
    638     uint16_t tx_tap_nrz_mode = 0;
    639     int16_t val;
    640     phymod_phy_access_t phy_copy;
    641     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
    642 
    643     /* read current tx tap mode */
    644     PHYMOD_IF_ERR_RETURN
    645         (blackhawk_tsc_tx_tap_mode_get(&phy_copy.access, &pmd_tx_tap_mode));
    646 
    647     /*read current tx NRZ mode control info */
    648     PHYMOD_IF_ERR_RETURN
    649         (blackhawk_tsc_tx_nrz_mode_get(&phy_copy.access, &tx_tap_nrz_mode));
    650 
    651     if (pmd_tx_tap_mode == 0) {
    652         /* 3 tap mode */
    653         tx->tap_mode = phymodTxTapMode3Tap;
    654     } else {
    655         tx->tap_mode = phymodTxTapMode6Tap;
    656     }
    657 
    658     if (tx_tap_nrz_mode) {
    659         tx->sig_method = phymodSignallingMethodNRZ;
    660     } else {
    661         tx->sig_method = phymodSignallingMethodPAM4;
    662     }
    663 
    664     /*next check 3 tap mode or 6 tap mode */
    665     if (tx->tap_mode == phymodTxTapMode3Tap) {
    666         PHYMOD_IF_ERR_RETURN
    667             (blackhawk_tsc_read_tx_afe(&phy_copy.access, TX_AFE_TAP0, &val));
    668             tx->pre = val;
    669         PHYMOD_IF_ERR_RETURN
    670             (blackhawk_tsc_read_tx_afe(&phy_copy.access, TX_AFE_TAP1, &val));
    671             tx->main = val;
    672         PHYMOD_IF_ERR_RETURN
    673             (blackhawk_tsc_read_tx_afe(&phy_copy.access, TX_AFE_TAP2, &val));
    674             tx->post = val;
    675             tx->pre2 = 0;
    676             tx->post2 = 0;
    677             tx->post3 = 0;
    678     } else {
    679         PHYMOD_IF_ERR_RETURN
    680             (blackhawk_tsc_read_tx_afe(&phy_copy.access, TX_AFE_TAP0, &val));
    681             tx->pre2 = val;
    682         PHYMOD_IF_ERR_RETURN
    683             (blackhawk_tsc_read_tx_afe(&phy_copy.access, TX_AFE_TAP1, &val));
    684             tx->pre = val;
    685         PHYMOD_IF_ERR_RETURN
    686             (blackhawk_tsc_read_tx_afe(&phy_copy.access, TX_AFE_TAP2, &val));
    687             tx->main = val;
    688         PHYMOD_IF_ERR_RETURN
    689             (blackhawk_tsc_read_tx_afe(&phy_copy.access, TX_AFE_TAP3, &val));
    690             tx->post = val;
    691         PHYMOD_IF_ERR_RETURN
    692             (blackhawk_tsc_read_tx_afe(&phy_copy.access, TX_AFE_TAP4, &val));
    693             tx->post2 = val;
    694         PHYMOD_IF_ERR_RETURN
    695             (blackhawk_tsc_read_tx_afe(&phy_copy.access, TX_AFE_TAP5, &val));
    696             tx->post3 = val;
    697     }
    698 
    699     return PHYMOD_E_NONE;
    700 }
    701 
    702 
    703 
    704 int tscbh_phy_tx_override_set(const phymod_phy_access_t* phy, const phymod_tx_override_t* tx_override)
    705 {
    706     phymod_phy_access_t phy_copy;
    707     int start_lane, num_lane, i;
    708 
    709     PHYMOD_IF_ERR_RETURN
    710         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
    711     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
    712 
    713     PHYMOD_IF_ERR_RETURN
    714         (blackhawk_lane_soft_reset(&phy_copy.access, 1));
    715 
    716     for (i = 0; i < num_lane; i++) {
    717         if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
    718             continue;
    719         }
    720         phy_copy.access.lane_mask = 1 << (start_lane + i);
    721         PHYMOD_IF_ERR_RETURN
    722              (blackhawk_tsc_tx_pi_freq_override(&phy_copy.access,
    723                                                  tx_override->phase_interpolator.enable,
    724                                                  tx_override->phase_interpolator.value));
    725     }
    726 
    727     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
    728     PHYMOD_IF_ERR_RETURN
    729         (blackhawk_lane_soft_reset(&phy_copy.access, 0));
    730 
    731     return PHYMOD_E_NONE;
    732 }
    733 
    734 int tscbh_phy_tx_override_get(const phymod_phy_access_t* phy, phymod_tx_override_t* tx_override)
    735 {
    736     phymod_phy_access_t phy_copy;
    737     int16_t temp_value;
    738     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
    739 
    740     PHYMOD_IF_ERR_RETURN
    741         (blackhawk_tx_pi_control_get(&phy_copy.access, &temp_value));
    742 
    743     tx_override->phase_interpolator.value = (int32_t) temp_value;
    744     return PHYMOD_E_NONE;
    745 }
    746 
    747 int tscbh_phy_reset_set(const phymod_phy_access_t* phy, const phymod_phy_reset_t* reset)
    748 {
    749 
    750     return PHYMOD_E_UNAVAIL;
    751 }
    752 
    753 
    754 int tscbh_phy_reset_get(const phymod_phy_access_t* phy, phymod_phy_reset_t* reset)
    755 {
    756 
    757     return PHYMOD_E_UNAVAIL;
    758 
    759 }
    760 
    761 
    762 int tscbh_phy_power_set(const phymod_phy_access_t* phy, const phymod_phy_power_t* power)
    763 {
    764     return PHYMOD_E_UNAVAIL;
    765 }
    766 
    767 int tscbh_phy_power_get(const phymod_phy_access_t* phy, phymod_phy_power_t* power)
    768 {
    769     return PHYMOD_E_UNAVAIL;
    770 }
    771 
    772 /* This function based on num_lane, data_rate and fec_type
    773  * assign force speed SW speed_id.
    774  */
    775 STATIC
    776 int _tscbh_phy_speed_id_set(int num_lane,
    777                             uint32_t data_rate,
    778                             phymod_fec_type_t fec_type,
    779                             tbhmod_spd_intfc_type_t* spd_intf)
    780 {
    781     if (num_lane == 1) {
    782         switch (data_rate) {
    783             case 10000:
    784                 if (fec_type == phymod_fec_None) {
    785                     *spd_intf = TBHMOD_SPD_10000_XFI;
    786                 } else if (fec_type == phymod_fec_CL74) {
    787                     *spd_intf = TBHMOD_SPD_10G_FEC_BASE_R_KR1_CR1;
    788                 } else {
    789                     return PHYMOD_E_UNAVAIL;
    790                 }
    791                 break;
    792             case 12000:
    793                 *spd_intf = TBHMOD_SPD_12P5G_BRCM_KR1;
    794                 break;
    795             case 20000:
    796                 if (fec_type == phymod_fec_None) {
    797                     *spd_intf = TBHMOD_SPD_20000_XFI;
    798                 } else if (fec_type == phymod_fec_CL74) {
    799                     *spd_intf = TBHMOD_SPD_20G_FEC_BASE_R_KR1_CR1;
    800                 } else {
    801                     return PHYMOD_E_UNAVAIL;
    802                 }
    803                 break;
    804             case 25000:
    805                 if (fec_type == phymod_fec_None) {
    806                     *spd_intf = TBHMOD_SPD_25000_XFI;
    807                 } else if (fec_type == phymod_fec_CL74) {
    808                     *spd_intf = TBHMOD_SPD_25G_FEC_BASE_R_KR1_CR1;
    809                 } else if (fec_type == phymod_fec_CL91) {
    810                     *spd_intf = TBHMOD_SPD_25G_FEC_RS_FEC_KR1_CR1;
    811                 } else {
    812                     return PHYMOD_E_UNAVAIL;
    813                 }
    814                 break;
    815             case 50000:
    816                 if (fec_type == phymod_fec_CL91) {
    817                     *spd_intf = TBHMOD_SPD_50G_BRCM_FEC_528_CR1_KR1;
    818                 } else if (fec_type == phymod_fec_RS544) {
    819                     *spd_intf = TBHMOD_SPD_50G_IEEE_KR1_CR1;
    820                 } else if (fec_type == phymod_fec_RS272) {
    821                     *spd_intf = TBHMOD_SPD_50G_BRCM_FEC_272_KR1_CR1;
    822                 } else {
    823                     return PHYMOD_E_UNAVAIL;
    824                 }
    825                 break;
    826             default:
    827                 return PHYMOD_E_UNAVAIL;
    828         }
    829     } else if (num_lane == 2) {
    830         switch (data_rate) {
    831             case 40000:
    832                 if (fec_type == phymod_fec_None) {
    833                     *spd_intf = TBHMOD_SPD_40G_MLD_X2;
    834                 } else {
    835                     return PHYMOD_E_UNAVAIL;
    836                 }
    837                 break;
    838             case 50000:
    839                 if (fec_type == phymod_fec_None) {
    840                     *spd_intf = TBHMOD_SPD_50G_MLD_X2;
    841                 } else if (fec_type == phymod_fec_CL91) {
    842                     *spd_intf = TBHMOD_SPD_50G_MLD_FEC_528_X2;
    843                 } else if (fec_type == phymod_fec_RS544) {
    844                     *spd_intf = TBHMOD_SPD_50G_BRCM_FEC_544_CR2_KR2;
    845                 } else {
    846                     return PHYMOD_E_UNAVAIL;
    847                 }
    848                 break;
    849             case 100000:
    850                 if (fec_type == phymod_fec_None) {
    851                     *spd_intf = TBHMOD_SPD_100G_BRCM_NOFEC_KR2_CR2;
    852                 } else if (fec_type == phymod_fec_CL91) {
    853                     *spd_intf = TBHMOD_SPD_100G_BRCM_FEC_528_KR2_CR2;
    854                 } else if (fec_type == phymod_fec_RS544) {
    855                     *spd_intf = TBHMOD_SPD_100G_IEEE_KR2_CR2;
    856                 } else if (fec_type == phymod_fec_RS272) {
    857                     *spd_intf = TBHMOD_SPD_100G_BRCM_FEC_272_KR2_CR2;
    858                 } else {
    859                     return PHYMOD_E_UNAVAIL;
    860                 }
    861                 break;
    862             default:
    863                 return PHYMOD_E_UNAVAIL;
    864         }
    865     } else if (num_lane == 4) {
    866         switch (data_rate) {
    867             case 40000:
    868                 if (fec_type == phymod_fec_None) {
    869                     *spd_intf = TBHMOD_SPD_40G_MLD_X4;
    870                 } else if (fec_type == phymod_fec_CL74) {
    871                     *spd_intf = TBHMOD_SPD_40G_FEC_BASE_R_KR4_CR4;
    872                 } else {
    873                     return PHYMOD_E_UNAVAIL;
    874                 }
    875                 break;
    876             case 100000:
    877                 if (fec_type == phymod_fec_None) {
    878                     *spd_intf = TBHMOD_SPD_100G_MLD_NO_FEC_X4;
    879                 } else if (fec_type == phymod_fec_CL91) {
    880                     *spd_intf = TBHMOD_SPD_100G_MLD_X4;
    881                 } else if (fec_type == phymod_fec_RS544) {
    882                     *spd_intf = TBHMOD_SPD_100G_BRCM_FEC_544_1XN_KR4_CR4;
    883                 } else {
    884                     return PHYMOD_E_UNAVAIL;
    885                 }
    886                 break;
    887             case 200000:
    888                 if (fec_type == phymod_fec_None) {
    889                     *spd_intf = TBHMOD_SPD_200G_BRCM_NO_FEC_KR4_CR4;
    890                 } else if (fec_type == phymod_fec_RS544) {
    891                     *spd_intf = TBHMOD_SPD_200G_BRCM_FEC_544_1XN_KR4_CR4;
    892                 } else if (fec_type == phymod_fec_RS544_2XN) {
    893                     *spd_intf = TBHMOD_SPD_200G_IEEE_FEC_544_2XN_KR4_CR4;
    894                 } else if (fec_type == phymod_fec_RS272) {
    895                     *spd_intf = TBHMOD_SPD_200G_BRCM_FEC_272_1XN_KR4_CR4;
    896                 } else {
    897                     return PHYMOD_E_UNAVAIL;
    898                 }
    899                 break;
    900             default:
    901                 return PHYMOD_E_UNAVAIL;
    902         }
    903     } else if (num_lane == 8) {
    904         if (data_rate == 400000 && fec_type == phymod_fec_RS544_2XN) {
    905             *spd_intf = TBHMOD_SPD_400G_BRCM_FEC_544_2XN_X8;
    906         } else {
    907             return PHYMOD_E_UNAVAIL;
    908         }
    909     } else {
    910         return PHYMOD_E_UNAVAIL;
    911     }
    912 
    913     return PHYMOD_E_NONE;
    914 }
    915 
    916 int tscbh_phy_speed_config_set(const phymod_phy_access_t* phy,
    917                                    const phymod_phy_speed_config_t* speed_config,
    918                                    const phymod_phy_pll_state_t* old_pll_state,
    919                                    phymod_phy_pll_state_t* new_pll_state)
    920 {
    921     uint32_t ovco_is_pwrdn, tvco_is_pwrdn = 0;
    922     phymod_phy_access_t pm_phy_copy;
    923     uint32_t lane_mask_backup;
    924     uint32_t  tvco_pll_index, ovco_pll_index, tvco_pll_div = 0, ovco_pll_div = 0, request_pll_div = 0, pll_index = 0;
    925     uint32_t loss_in_db;
    926     int i, start_lane, num_lane, mapped_speed_id, ilkn_set;
    927     phymod_firmware_lane_config_t firmware_lane_config;
    928     phymod_firmware_core_config_t firmware_core_config;
    929     tbhmod_spd_intfc_type_t spd_intf = 0;
    930     tbhmod_refclk_t ref_clk;
    931     uint32_t is_pam4, osr_mode;
    932 
    933     firmware_lane_config = speed_config->pmd_lane_config;
    934     /*first make sure that tvco pll index is valid */
    935     if (phy->access.tvco_pll_index > 1) {
    936         PHYMOD_DEBUG_ERROR(("Unsupported tvco index\n"));
    937         return PHYMOD_E_UNAVAIL;
    938     }
    939 
    940     tvco_pll_index = phy->access.tvco_pll_index;
    941     ovco_pll_index = tvco_pll_index ? 0 : 1;
    942 
    943     PHYMOD_MEMSET(&firmware_core_config, 0x0, sizeof(firmware_core_config));
    944 
    945     /* Copy the PLL state */
    946     *new_pll_state = *old_pll_state;
    947 
    948     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
    949     PHYMOD_IF_ERR_RETURN
    950         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
    951     lane_mask_backup = phy->access.lane_mask;
    952 
    953     /* Hold the pcs lane reset */
    954     pm_phy_copy.access.lane_mask = 1 << start_lane;
    955     PHYMOD_IF_ERR_RETURN
    956         (tbhmod_disable_set(&pm_phy_copy.access));
    957 
    958     /* write this port forced speed id entry */
    959     PHYMOD_IF_ERR_RETURN
    960       (tbhmod_set_sc_speed(&pm_phy_copy.access, TSCBH_FORCED_SPEED_ID_OFFSET + start_lane, 0));
    961 
    962     /*Hold the per lane PMD soft reset bit*/
    963     pm_phy_copy.access.lane_mask = lane_mask_backup;
    964     PHYMOD_IF_ERR_RETURN
    965         (blackhawk_lane_soft_reset(&pm_phy_copy.access, 1));
    966 
    967     /* first check if current lane are in ILKN mode */
    968     PHYMOD_IF_ERR_RETURN
    969         (tbhmod_pcs_ilkn_chk(&pm_phy_copy.access, &ilkn_set));
    970 
    971     /* if previous config is ILKN and reqeust config is ethernet
    972     need to clear some ILKN config */
    973     if (ilkn_set && !PHYMOD_DEVICE_OP_MODE_PCS_BYPASS_GET(phy->device_op_mode)) {
    974     /* Remove pmd_tx_disable_pin_dis it may be asserted because of ILKn */
    975         for (i = 0; i < num_lane; i++) {
    976             if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
    977                 continue;
    978             }
    979             pm_phy_copy.access.lane_mask = 1 << (start_lane + i);
    980             PHYMOD_IF_ERR_RETURN
    981                 (blackhawk_pmd_tx_disable_pin_dis_set(&pm_phy_copy.access, 0));
    982         }
    983         pm_phy_copy.access.lane_mask = lane_mask_backup;
    984         /*disable PCS ilkn mode */
    985         PHYMOD_IF_ERR_RETURN
    986             (tbhmod_pcs_ilkn_enable(&pm_phy_copy.access, 0));
    987       /* previous config is ethernet and request is ILKN mode */
    988     } else if (!ilkn_set && PHYMOD_DEVICE_OP_MODE_PCS_BYPASS_GET(phy->device_op_mode)) {
    989         for (i = 0; i < num_lane; i++) {
    990             if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
    991                 continue;
    992             }
    993             pm_phy_copy.access.lane_mask = 1 << (start_lane + i);
    994             PHYMOD_IF_ERR_RETURN
    995                 (blackhawk_pmd_tx_disable_pin_dis_set(&pm_phy_copy.access, 1));
    996         }
    997         /*enable PCS ilkn mode */
    998         for (i = 0; i < num_lane; i++) {
    999             if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   1000                 continue;
   1001             }
   1002             pm_phy_copy.access.lane_mask = 1 << (start_lane + i);
   1003             PHYMOD_IF_ERR_RETURN
   1004                 (tbhmod_pcs_ilkn_enable(&pm_phy_copy.access, 1));
   1005        }
   1006     }
   1007 
   1008     /*only update the port mode for ethernet port */
   1009     if (!PHYMOD_DEVICE_OP_MODE_PCS_BYPASS_GET(phy->device_op_mode)) {
   1010         PHYMOD_IF_ERR_RETURN
   1011             (tbhmod_update_port_mode(&pm_phy_copy.access));
   1012     }
   1013 
   1014     /*for ethernet speed mode config set */
   1015     if (!PHYMOD_DEVICE_OP_MODE_PCS_BYPASS_GET(phy->device_op_mode)) {
   1016         PHYMOD_IF_ERR_RETURN(_tscbh_phy_speed_id_set(num_lane, speed_config->data_rate,
   1017                                                      speed_config->fec_type, &spd_intf));
   1018 
   1019         PHYMOD_IF_ERR_RETURN
   1020             (tbhmod_get_mapped_speed(spd_intf, &mapped_speed_id));
   1021 
   1022         /* set the rs fec CW properly */
   1023         if ((speed_config->fec_type == phymod_fec_RS544) ||
   1024             (speed_config->fec_type == phymod_fec_RS544_2XN)) {
   1025             if (start_lane < 4) {
   1026                 pm_phy_copy.access.lane_mask = 1 << 0;
   1027             } else {
   1028                 pm_phy_copy.access.lane_mask = 1 << 4;
   1029             }
   1030             PHYMOD_IF_ERR_RETURN
   1031                 (tbhmod_rsfec_cw_type(&pm_phy_copy.access, 0, 0));
   1032         } else if ((speed_config->fec_type == phymod_fec_RS272) ||
   1033                    (speed_config->fec_type == phymod_fec_RS272_2XN)) {
   1034             if (start_lane < 4) {
   1035                 pm_phy_copy.access.lane_mask = 1 << 0;
   1036             } else {
   1037                 pm_phy_copy.access.lane_mask = 1 << 4;
   1038             }
   1039             PHYMOD_IF_ERR_RETURN
   1040                 (tbhmod_rsfec_cw_type(&pm_phy_copy.access, 1, 0));
   1041         }
   1042     }
   1043 
   1044     /* Check if ovco is power down */
   1045     pm_phy_copy.access.pll_idx = ovco_pll_index;
   1046     PHYMOD_IF_ERR_RETURN
   1047         (blackhawk_tsc_pll_pwrdn_get(&pm_phy_copy.access, &ovco_is_pwrdn));
   1048 
   1049     /* if ovco is NOT pwoer down, then get the ovco div*/
   1050     if (!ovco_is_pwrdn) {
   1051         PHYMOD_IF_ERR_RETURN
   1052             (blackhawk_tsc_INTERNAL_read_pll_div(&pm_phy_copy.access, &ovco_pll_div));
   1053     }
   1054 
   1055     /* next check if pcs bypass mode, yes, then need to check tvco is power down */
   1056     if (PHYMOD_DEVICE_OP_MODE_PCS_BYPASS_GET(phy->device_op_mode)) {
   1057         pm_phy_copy.access.pll_idx = tvco_pll_index;
   1058         PHYMOD_IF_ERR_RETURN
   1059             (blackhawk_tsc_pll_pwrdn_get(&pm_phy_copy.access, &tvco_is_pwrdn));
   1060     }
   1061 
   1062     if (!tvco_is_pwrdn) {
   1063         /* Get TVCO because it's not allowed to change during speed set */
   1064         pm_phy_copy.access.pll_idx = tvco_pll_index;
   1065         PHYMOD_IF_ERR_RETURN
   1066             (blackhawk_tsc_INTERNAL_read_pll_div(&pm_phy_copy.access, &tvco_pll_div));
   1067     }
   1068 
   1069     /* based on the current TVCO PLL div, decide which copy of speed id entry to load */
   1070     /* and this step only applies to (non)ilkn port*/
   1071     if (!PHYMOD_DEVICE_OP_MODE_PCS_BYPASS_GET(phy->device_op_mode)) {
   1072         /* first set the lane mask to be 0x1 */
   1073         pm_phy_copy.access.lane_mask = 1 << 0;
   1074         if ((tvco_pll_div == TBHMOD_PLL_MODE_DIV_170) || (tvco_pll_div == TBHMOD_PLL_MODE_DIV_85))  {
   1075             /* then load 26G TVCO speed id entry */
   1076             PHYMOD_IF_ERR_RETURN
   1077                 (phymod_mem_write(&pm_phy_copy.access, phymodMemSpeedIdTable, TSCBH_FORCED_SPEED_ID_OFFSET + start_lane, &spd_id_entry_26[mapped_speed_id][0]));
   1078         } else if ((tvco_pll_div == TBHMOD_PLL_MODE_DIV_165) || (tvco_pll_div == TBHMOD_PLL_MODE_DIV_82P5)) {
   1079             /* then load 25G TVCO speed id entry */
   1080             PHYMOD_IF_ERR_RETURN
   1081                 (phymod_mem_write(&pm_phy_copy.access, phymodMemSpeedIdTable, TSCBH_FORCED_SPEED_ID_OFFSET + start_lane, &spd_id_entry_25[mapped_speed_id][0]));
   1082         } else {
   1083             /* then load 20G TVCO speed id entry */
   1084             PHYMOD_IF_ERR_RETURN
   1085                 (phymod_mem_write(&pm_phy_copy.access, phymodMemSpeedIdTable, TSCBH_FORCED_SPEED_ID_OFFSET + start_lane, &spd_id_entry_20[mapped_speed_id][0]));
   1086         }
   1087     }
   1088 
   1089     /* Check the request speed VCO */
   1090     pm_phy_copy.access.lane_mask = 1 << start_lane;
   1091     PHYMOD_IF_ERR_RETURN
   1092         (tbhmod_refclk_get(&pm_phy_copy.access, &ref_clk));
   1093 
   1094     /* Get requested PLL */
   1095     /*for ethernet speed mode config set */
   1096     if (!PHYMOD_DEVICE_OP_MODE_PCS_BYPASS_GET(phy->device_op_mode)) {
   1097         PHYMOD_IF_ERR_RETURN
   1098             (tbhmod_plldiv_lkup_get(&pm_phy_copy.access, mapped_speed_id, ref_clk, &request_pll_div));
   1099     } else {
   1100         /*first check the ref clock */
   1101         int ref_clk_is_156p25 = 0;
   1102         if (ref_clk == TBHMOD_REF_CLK_156P25MHZ) {
   1103             ref_clk_is_156p25 = 1;
   1104         }
   1105         PHYMOD_IF_ERR_RETURN
   1106         (blackhawk_speed_config_get(speed_config->data_rate, ref_clk_is_156p25, &request_pll_div, &is_pam4, &osr_mode));
   1107     }
   1108 
   1109     if ((ovco_pll_div == request_pll_div) || (tvco_pll_div == request_pll_div)) {
   1110         /* First check if pll0 is active and the new speed can be
   1111            supported with existing VCO */
   1112         pll_index = (ovco_pll_div == request_pll_div)? ovco_pll_index : tvco_pll_index;
   1113     } else {
   1114         /*this speed request can not be configured */
   1115         PHYMOD_DEBUG_ERROR(("ERROR :: this speed can not be configured \n"));
   1116         return PHYMOD_E_CONFIG;
   1117     }
   1118 
   1119     /* choose the right pll index for the port */
   1120     for (i = 0; i < num_lane; i++) {
   1121         pm_phy_copy.access.lane_mask = 1 << (start_lane + i);
   1122         if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   1123             continue;
   1124         }
   1125         PHYMOD_IF_ERR_RETURN
   1126             (blackhawk_lane_pll_selection_set(&pm_phy_copy.access, pll_index));
   1127     }
   1128 
   1129     pm_phy_copy.access.lane_mask = lane_mask_backup;
   1130     /* Program OS mode */
   1131     if (!PHYMOD_DEVICE_OP_MODE_PCS_BYPASS_GET(phy->device_op_mode)) {
   1132         PHYMOD_IF_ERR_RETURN
   1133             (tbhmod_pmd_osmode_set(&pm_phy_copy.access, mapped_speed_id, ref_clk));
   1134     } else {
   1135         for (i = 0; i < num_lane; i++) {
   1136             pm_phy_copy.access.lane_mask = 1 << (start_lane + i);
   1137             if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   1138                 continue;
   1139             }
   1140             PHYMOD_IF_ERR_RETURN
   1141                 (blackhawk_osr_mode_set(&pm_phy_copy.access, osr_mode));
   1142         }
   1143     }
   1144 
   1145     /*next need to set certain firmware lane config to be zero*/
   1146     firmware_lane_config.LaneConfigFromPCS = 0;
   1147     firmware_lane_config.AnEnabled = 0;
   1148 
   1149    for (i = 0; i < num_lane; i++) {
   1150         pm_phy_copy.access.lane_mask = 0x1 << (start_lane + i);
   1151         if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   1152             continue;
   1153         }
   1154         PHYMOD_IF_ERR_RETURN
   1155              (_tscbh_phy_firmware_lane_config_set(&pm_phy_copy, firmware_lane_config));
   1156     }
   1157 
   1158     /* if the PAM4 mode, need to program the channel loss. In NRZ mode it is zeroed. */
   1159     loss_in_db = firmware_lane_config.ForcePAM4Mode? speed_config->PAM4_channel_loss : 0;
   1160     for (i = 0; i < num_lane; i++) {
   1161         pm_phy_copy.access.lane_mask = 0x1 << (start_lane + i);
   1162         if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   1163             continue;
   1164         }
   1165         PHYMOD_IF_ERR_RETURN
   1166             (blackhawk_channel_loss_set(&pm_phy_copy.access, loss_in_db));
   1167     }
   1168 
   1169     /* next need to enable/disable link training based on the input */
   1170     PHYMOD_IF_ERR_RETURN
   1171         (tscbh_phy_cl72_set(phy, speed_config->linkTraining));
   1172 
   1173     /*release the lne soft reset bit*/
   1174     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
   1175     PHYMOD_IF_ERR_RETURN
   1176         (blackhawk_lane_soft_reset(&pm_phy_copy.access, 0));
   1177 
   1178     /* Release the pcs lane reset */
   1179     pm_phy_copy.access.lane_mask = 1 << start_lane;
   1180     PHYMOD_IF_ERR_RETURN
   1181         (tbhmod_enable_set(&pm_phy_copy.access));
   1182 
   1183     /* first clear the current lane _mask from both */
   1184     new_pll_state->pll1_lanes_bitmap &= ~(phy->access.lane_mask);
   1185     new_pll_state->pll0_lanes_bitmap &= ~(phy->access.lane_mask);
   1186 
   1187     /* need to update the pll_state */
   1188     if (pll_index) {
   1189         new_pll_state->pll1_lanes_bitmap |= phy->access.lane_mask;
   1190     } else {
   1191         new_pll_state->pll0_lanes_bitmap |= phy->access.lane_mask;
   1192     }
   1193 
   1194     return PHYMOD_E_NONE;
   1195 }
   1196 
   1197 STATIC
   1198 int _tscbh_speed_table_entry_to_speed_config_get(const phymod_phy_access_t* phy,
   1199                                         spd_id_tbl_entry_t* speed_config_entry,
   1200                                         phymod_phy_speed_config_t* speed_config)
   1201 {
   1202     uint32_t pll_div, refclk_in_hz, data_rate_lane;
   1203     uint32_t pll_index;
   1204     int osr_mode;
   1205     tbhmod_refclk_t ref_clk;
   1206     uint32_t vco_rate;
   1207     phymod_phy_access_t phy_copy;
   1208     phymod_firmware_lane_config_t firmware_lane_config;
   1209     int num_lane;
   1210 
   1211     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   1212 
   1213     switch (speed_config_entry->num_lanes) {
   1214         case 0: num_lane = 1;
   1215             break;
   1216         case 1: num_lane = 2;
   1217             break;
   1218         case 2: num_lane = 4;
   1219             break;
   1220         case 3: num_lane = 8;
   1221             break;
   1222         case 4: num_lane = 3;
   1223             break;
   1224         case 5: num_lane = 6;
   1225             break;
   1226         case 6: num_lane = 7;
   1227             break;
   1228         default:
   1229             PHYMOD_DEBUG_ERROR(("Unsupported number of lane \n"));
   1230             return PHYMOD_E_UNAVAIL;
   1231     }
   1232 
   1233     /*first figure out which pll the current port is using */
   1234     PHYMOD_IF_ERR_RETURN
   1235         (blackhawk_lane_pll_selection_get(&phy_copy.access, &pll_index));
   1236 
   1237     phy_copy.access.pll_idx = pll_index;
   1238 
   1239     PHYMOD_IF_ERR_RETURN
   1240         (tscbh_phy_firmware_lane_config_get(phy, &firmware_lane_config));
   1241 
   1242     /* get the PLL div from HW */
   1243     PHYMOD_IF_ERR_RETURN
   1244         (blackhawk_tsc_INTERNAL_read_pll_div(&phy_copy.access, &pll_div));
   1245 
   1246     PHYMOD_IF_ERR_RETURN
   1247         (tbhmod_refclk_get(&phy_copy.access, &ref_clk));
   1248 
   1249     if (ref_clk == TBHMOD_REF_CLK_312P5MHZ) {
   1250         refclk_in_hz = 312500000;
   1251     } else {
   1252         refclk_in_hz = 156250000;
   1253     }
   1254     PHYMOD_IF_ERR_RETURN
   1255         (blackhawk_tsc_get_vco_from_refclk_div(&phy_copy.access, refclk_in_hz, pll_div, &vco_rate, 0));
   1256 
   1257     PHYMOD_IF_ERR_RETURN
   1258         (blackhawk_osr_mode_get(&phy_copy.access, &osr_mode));
   1259 
   1260     /*
   1261      * data_rate_lane = vco_rate / 66 * 64.
   1262      * For 25G VCO case, round down the data_rate_lane to 24000 by convention.
   1263      */
   1264     if (vco_rate == 20625000) {
   1265         data_rate_lane = 20000;
   1266     } else if (vco_rate == 25000000) {
   1267         data_rate_lane = 24000;
   1268     } else {
   1269         data_rate_lane = 25000;
   1270     }
   1271 
   1272     /* next check if PAM4 mode enabled */
   1273     if (firmware_lane_config.ForcePAM4Mode) {
   1274         data_rate_lane = data_rate_lane  << 1;
   1275     } else {
   1276         /* to get the over sample value */
   1277         data_rate_lane = data_rate_lane >> osr_mode;
   1278     }
   1279 
   1280     speed_config->data_rate = data_rate_lane * num_lane;
   1281 
   1282     PHYMOD_IF_ERR_RETURN
   1283         (tbhmod_fec_arch_decode_get(speed_config_entry->fec_arch, &(speed_config->fec_type)));
   1284 
   1285     return PHYMOD_E_NONE;
   1286 }
   1287 
   1288 
   1289 STATIC
   1290 int _tscbh_speed_id_to_speed_config_get(const phymod_phy_access_t* phy,
   1291                                         int speed_id,
   1292                                         int num_lane,
   1293                                         phymod_phy_speed_config_t* speed_config)
   1294 {
   1295     uint32_t pll_div, refclk_in_hz, data_rate_lane;
   1296     uint32_t pll_index;
   1297     int osr_mode;
   1298     tbhmod_refclk_t ref_clk;
   1299     uint32_t vco_rate;
   1300     phymod_phy_access_t phy_copy;
   1301     phymod_firmware_lane_config_t firmware_lane_config;
   1302     spd_id_tbl_entry_t speed_config_entry;
   1303     uint32_t packed_entry[5];
   1304 
   1305     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   1306 
   1307     /*first figure out which pll the current port is using */
   1308     PHYMOD_IF_ERR_RETURN
   1309         (blackhawk_lane_pll_selection_get(&phy_copy.access, &pll_index));
   1310 
   1311     phy_copy.access.pll_idx = pll_index;
   1312 
   1313     PHYMOD_IF_ERR_RETURN
   1314         (tscbh_phy_firmware_lane_config_get(phy, &firmware_lane_config));
   1315 
   1316     /* get the PLL div from HW */
   1317     PHYMOD_IF_ERR_RETURN
   1318         (blackhawk_tsc_INTERNAL_read_pll_div(&phy_copy.access, &pll_div));
   1319 
   1320     PHYMOD_IF_ERR_RETURN
   1321         (tbhmod_refclk_get(&phy_copy.access, &ref_clk));
   1322 
   1323     if (ref_clk == TBHMOD_REF_CLK_312P5MHZ) {
   1324         refclk_in_hz = 312500000;
   1325     } else {
   1326         refclk_in_hz = 156250000;
   1327     }
   1328     PHYMOD_IF_ERR_RETURN
   1329         (blackhawk_tsc_get_vco_from_refclk_div(&phy_copy.access, refclk_in_hz, pll_div, &vco_rate, 0));
   1330 
   1331     PHYMOD_IF_ERR_RETURN
   1332         (blackhawk_osr_mode_get(&phy_copy.access, &osr_mode));
   1333     /*
   1334      * data_rate_lane = vco_rate / 66 * 64.
   1335      * For 25G VCO case, round down the data_rate_lane to 24000 by convention.
   1336      */
   1337     if (vco_rate == 20625000) {
   1338         data_rate_lane = 20000;
   1339     } else if (vco_rate == 25000000) {
   1340         data_rate_lane = 24000;
   1341     } else {
   1342         data_rate_lane = 25000;
   1343     }
   1344 
   1345     /* next check if PAM4 mode enabled */
   1346     if (firmware_lane_config.ForcePAM4Mode) {
   1347         data_rate_lane = data_rate_lane  << 1;
   1348     } else {
   1349         /* to get the over sample value */
   1350         data_rate_lane = data_rate_lane >> osr_mode;
   1351     }
   1352 
   1353     speed_config->data_rate = data_rate_lane * num_lane;
   1354 
   1355     PHYMOD_IF_ERR_RETURN
   1356         (phymod_mem_read(&phy_copy.access, phymodMemSpeedIdTable, speed_id, packed_entry));
   1357 
   1358     spd_ctrl_unpack_spd_id_tbl_entry(packed_entry, &speed_config_entry);
   1359 
   1360     PHYMOD_IF_ERR_RETURN
   1361         (tbhmod_fec_arch_decode_get(speed_config_entry.fec_arch, &(speed_config->fec_type)));
   1362 
   1363     return PHYMOD_E_NONE;
   1364 }
   1365 
   1366 int tscbh_phy_speed_config_get(const phymod_phy_access_t* phy, phymod_phy_speed_config_t* speed_config)
   1367 {
   1368     uint32_t cl72_enable;
   1369     phymod_phy_access_t phy_copy;
   1370     phymod_firmware_lane_config_t firmware_lane_config;
   1371     int start_lane, num_lane, speed_id;
   1372     uint32_t packed_entry[20];
   1373     spd_id_tbl_entry_t speed_config_entry;
   1374     int an_en, an_done, osr_mode;
   1375     uint32_t pll_div, vco_freq_khz, pll_index, lane_mask_backup;
   1376     tbhmod_refclk_t ref_clk;
   1377 
   1378     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   1379     lane_mask_backup = phy->access.lane_mask;                                       
   1380 
   1381     PHYMOD_IF_ERR_RETURN
   1382         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   1383 
   1384     PHYMOD_IF_ERR_RETURN
   1385         (tscbh_phy_firmware_lane_config_get(phy, &firmware_lane_config));
   1386 
   1387     speed_config->pmd_lane_config.AnEnabled          = firmware_lane_config.AnEnabled;
   1388     speed_config->pmd_lane_config.Cl72AutoPolEn      = firmware_lane_config.Cl72AutoPolEn;
   1389     speed_config->pmd_lane_config.Cl72RestTO         = firmware_lane_config.Cl72RestTO;
   1390     speed_config->pmd_lane_config.DfeOn              = firmware_lane_config.DfeOn;
   1391     speed_config->pmd_lane_config.ForceBrDfe         = firmware_lane_config.ForceBrDfe;
   1392     speed_config->pmd_lane_config.ForceExtenedReach  = firmware_lane_config.ForceExtenedReach;
   1393     speed_config->pmd_lane_config.ForceNormalReach   = firmware_lane_config.ForceNormalReach;
   1394     speed_config->pmd_lane_config.ForceNRZMode       = firmware_lane_config.ForceNRZMode;
   1395     speed_config->pmd_lane_config.ForcePAM4Mode      = firmware_lane_config.ForcePAM4Mode;
   1396     speed_config->pmd_lane_config.LaneConfigFromPCS  = firmware_lane_config.LaneConfigFromPCS;
   1397     speed_config->pmd_lane_config.LpDfeOn            = firmware_lane_config.LpDfeOn;
   1398     speed_config->pmd_lane_config.LpPrecoderEnabled  = firmware_lane_config.LpPrecoderEnabled;
   1399     speed_config->pmd_lane_config.MediaType          = firmware_lane_config.MediaType;
   1400     speed_config->pmd_lane_config.ScramblingDisable  = firmware_lane_config.ScramblingDisable;
   1401     speed_config->pmd_lane_config.UnreliableLos      = firmware_lane_config.UnreliableLos;
   1402 
   1403     /* for ethernet port */
   1404     if (!PHYMOD_DEVICE_OP_MODE_PCS_BYPASS_GET(phy->device_op_mode)) {
   1405         /* first read speed id from resolved status */
   1406         PHYMOD_IF_ERR_RETURN
   1407             (tbhmod_speed_id_get(&phy_copy.access, &speed_id));
   1408 
   1409         /* next check check if AN enabled */
   1410         PHYMOD_IF_ERR_RETURN
   1411            (tbhmod_autoneg_status_get(&phy_copy.access, &an_en, &an_done));
   1412 
   1413         /* first read the speed entry and then decode the speed and FEC type */
   1414         phy_copy.access.lane_mask = 1 << 0;
   1415         PHYMOD_IF_ERR_RETURN
   1416             (phymod_mem_read(&phy_copy.access, phymodMemSpeedIdTable, speed_id, packed_entry));
   1417 
   1418         /*decode speed entry */
   1419         spd_ctrl_unpack_spd_id_tbl_entry(packed_entry, &speed_config_entry);
   1420 
   1421 
   1422         PHYMOD_IF_ERR_RETURN
   1423             (_tscbh_speed_table_entry_to_speed_config_get(phy, &speed_config_entry, speed_config));
   1424 
   1425         /* if autoneg enabled, needs to update the FEC_ARCH based on the An resolved status */
   1426         if (an_en && an_done) {
   1427             uint8_t fec_arch;
   1428             phy_copy.access.lane_mask = 0x1 << start_lane;
   1429             PHYMOD_IF_ERR_RETURN
   1430                 (tbhmod_autoneg_fec_status_get(&phy_copy.access, &fec_arch));
   1431             PHYMOD_IF_ERR_RETURN
   1432                 (tbhmod_fec_arch_decode_get(fec_arch, &(speed_config->fec_type)));
   1433         }
   1434     } else {
   1435         /*first figure out which pll the current port is using */
   1436         PHYMOD_IF_ERR_RETURN
   1437             (blackhawk_lane_pll_selection_get(&phy_copy.access, &pll_index));
   1438 
   1439         phy_copy.access.pll_idx = pll_index;
   1440          /* get the PLL div from HW */
   1441         PHYMOD_IF_ERR_RETURN
   1442             (blackhawk_tsc_INTERNAL_read_pll_div(&phy_copy.access, &pll_div));
   1443 
   1444         phy_copy.access.lane_mask = 0x1;
   1445         /* next read what's the ref clock */
   1446         PHYMOD_IF_ERR_RETURN
   1447            (tbhmod_refclk_get(&phy_copy.access, &ref_clk));
   1448 
   1449         if (ref_clk == TBHMOD_REF_CLK_156P25MHZ) {
   1450             PHYMOD_IF_ERR_RETURN
   1451                 (blackhawk_tsc_get_vco_from_refclk_div(&phy_copy.access, REF_CLOCK_156P25, pll_div, &vco_freq_khz, 0));
   1452         } else {
   1453             PHYMOD_IF_ERR_RETURN
   1454                 (blackhawk_tsc_get_vco_from_refclk_div(&phy_copy.access, REF_CLOCK_312P5, pll_div, &vco_freq_khz, 0));
   1455         }  
   1456 
   1457         phy_copy.access.lane_mask = lane_mask_backup;
   1458 
   1459         PHYMOD_IF_ERR_RETURN
   1460             (blackhawk_osr_mode_get(&phy_copy.access, &osr_mode));
   1461         /* next check if PAM4 mode enabled */
   1462         if (firmware_lane_config.ForcePAM4Mode) {
   1463             speed_config->data_rate = (vco_freq_khz  << 1) / 1000;
   1464         } else {
   1465             /* to get the over sample value */
   1466             if (osr_mode == 0) {
   1467                 speed_config->data_rate = (vco_freq_khz) / 1000;
   1468             } else if(osr_mode == 1) {
   1469                 speed_config->data_rate = (vco_freq_khz  >> 1) / 1000;
   1470             } else if (osr_mode == 2) {
   1471                 speed_config->data_rate = (vco_freq_khz  >> 2) / 1000;
   1472             }
   1473         }
   1474     }
   1475 
   1476     /* next get the cl72 enable status */
   1477     phy_copy.access.lane_mask = 0x1 << start_lane;
   1478     PHYMOD_IF_ERR_RETURN
   1479         (blackhawk_clause72_control_get(&phy_copy.access, &cl72_enable));
   1480     speed_config->linkTraining = cl72_enable;
   1481 
   1482     return PHYMOD_E_NONE;
   1483 }
   1484 
   1485 
   1486 int tscbh_phy_cl72_set(const phymod_phy_access_t* phy, uint32_t cl72_en)
   1487 {
   1488     struct blackhawk_tsc_uc_lane_config_st serdes_firmware_config;
   1489     phymod_firmware_lane_config_t firmware_lane_config;
   1490     int start_lane, num_lane, i;
   1491     uint32_t lane_reset, pcs_lane_enable;
   1492     phymod_phy_access_t pm_phy_copy;
   1493 
   1494     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
   1495     PHYMOD_IF_ERR_RETURN(blackhawk_tsc_get_uc_lane_cfg(&pm_phy_copy.access, &serdes_firmware_config));
   1496 
   1497     if ((serdes_firmware_config.field.dfe_on == 0) && cl72_en) {
   1498       PHYMOD_DEBUG_ERROR(("ERROR :: DFE is off : Can not start CL72/CL93 with no DFE\n"));
   1499       return PHYMOD_E_CONFIG;
   1500     }
   1501 
   1502     PHYMOD_IF_ERR_RETURN
   1503         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   1504 
   1505     /*first check if lane is in reset */
   1506     PHYMOD_IF_ERR_RETURN
   1507         (blackhawk_lane_soft_reset_get(&pm_phy_copy.access, &lane_reset));
   1508 
   1509     /*next check if PCS lane is in reset */
   1510     PHYMOD_IF_ERR_RETURN
   1511         (tbhmod_enable_get(&pm_phy_copy.access, &pcs_lane_enable));
   1512 
   1513     /* disable pcs lane if pcs lane not in rset */
   1514     if (pcs_lane_enable) {
   1515         pm_phy_copy.access.lane_mask = 1 << start_lane;
   1516         PHYMOD_IF_ERR_RETURN
   1517             (tbhmod_disable_set(&pm_phy_copy.access));
   1518     }
   1519 
   1520     /* if lane is not in reset, then reset the lane first */
   1521     if (!lane_reset) {
   1522         PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
   1523         PHYMOD_IF_ERR_RETURN
   1524             (blackhawk_lane_soft_reset(&pm_phy_copy.access, 1));
   1525     }
   1526 
   1527     /* next need to clear both force ER and NR config on the firmware lane config side
   1528     if link training enable is set */
   1529     if (cl72_en) {
   1530         PHYMOD_IF_ERR_RETURN
   1531             (tscbh_phy_firmware_lane_config_get(phy, &firmware_lane_config));
   1532 
   1533         firmware_lane_config.ForceNormalReach = 0;
   1534         firmware_lane_config.ForceExtenedReach = 0;
   1535 
   1536          PHYMOD_IF_ERR_RETURN
   1537             (_tscbh_phy_firmware_lane_config_set(phy, firmware_lane_config));
   1538     }
   1539     for (i = 0; i < num_lane; i++) {
   1540         pm_phy_copy.access.lane_mask = 1 << (start_lane + i);
   1541         if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   1542             continue;
   1543         }
   1544         PHYMOD_IF_ERR_RETURN
   1545             (blackhawk_clause72_control(&pm_phy_copy.access, cl72_en));
   1546     }
   1547 
   1548     /* release the ln dp reset */
   1549     if (!lane_reset) {
   1550         PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
   1551         PHYMOD_IF_ERR_RETURN
   1552             (blackhawk_lane_soft_reset(&pm_phy_copy.access, 0));
   1553     }
   1554 
   1555     /* re-enable pcs lane if pcs lane not in rset */
   1556     if (pcs_lane_enable) {
   1557         pm_phy_copy.access.lane_mask = 1 << start_lane;
   1558         PHYMOD_IF_ERR_RETURN
   1559             (tbhmod_enable_set(&pm_phy_copy.access));
   1560     }
   1561 
   1562     return PHYMOD_E_NONE;
   1563 }
   1564 
   1565 int tscbh_phy_cl72_get(const phymod_phy_access_t* phy, uint32_t* cl72_en)
   1566 {
   1567     phymod_phy_access_t pm_phy_copy;
   1568 
   1569     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
   1570 
   1571     PHYMOD_IF_ERR_RETURN
   1572         (blackhawk_clause72_control_get(&pm_phy_copy.access, cl72_en));
   1573 
   1574     return PHYMOD_E_NONE;
   1575 }
   1576 
   1577 
   1578 int tscbh_phy_cl72_status_get(const phymod_phy_access_t* phy, phymod_cl72_status_t* status)
   1579 {
   1580     int i;
   1581     uint32_t tmp_status;
   1582     int start_lane, num_lane;
   1583     phymod_phy_access_t phy_copy;
   1584     int an_en, an_done, speed_id;
   1585     spd_id_tbl_entry_t speed_config_entry;
   1586     uint32_t packed_entry[5];
   1587 
   1588     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   1589     status->locked = 1;
   1590 
   1591     /* next figure out the lane num and start_lane based on the input */
   1592     PHYMOD_IF_ERR_RETURN
   1593         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   1594     /* check check if AN enabled */
   1595     PHYMOD_IF_ERR_RETURN
   1596        (tbhmod_autoneg_status_get(&phy_copy.access, &an_en, &an_done));
   1597 
   1598     if (an_en && an_done) {
   1599         PHYMOD_IF_ERR_RETURN
   1600             (tbhmod_speed_id_get(&phy_copy.access, &speed_id));
   1601         PHYMOD_IF_ERR_RETURN
   1602             (phymod_mem_read(&phy_copy.access, phymodMemSpeedIdTable, speed_id, packed_entry));
   1603         spd_ctrl_unpack_spd_id_tbl_entry(packed_entry, &speed_config_entry);
   1604         /* Update num_lane and lane_mask for AN port */
   1605         num_lane = 1 << speed_config_entry.num_lanes;
   1606         /* Update lane_mask */
   1607         phy_copy.access.lane_mask = 0x0;
   1608         for (i = 0; i < num_lane; i++) {
   1609             phy_copy.access.lane_mask |= 0x1 << (i + start_lane);
   1610         }
   1611     }
   1612 
   1613     for (i = 0; i < num_lane; i++) {
   1614         if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   1615             continue;
   1616         }
   1617         phy_copy.access.lane_mask = 0x1 << (i + start_lane);
   1618         tmp_status = 1;
   1619         PHYMOD_IF_ERR_RETURN(blackhawk_pmd_cl72_receiver_status(&phy_copy.access, &tmp_status));
   1620         if (tmp_status == 0) {
   1621             status->locked = 0;
   1622             return PHYMOD_E_NONE;
   1623         }
   1624     }
   1625 
   1626     return PHYMOD_E_NONE;
   1627 }
   1628 
   1629 int tscbh_phy_loopback_set(const phymod_phy_access_t* phy, phymod_loopback_mode_t loopback, uint32_t enable)
   1630 {
   1631     int i;
   1632     int start_lane, num_lane;
   1633     phymod_phy_access_t phy_copy;
   1634 
   1635     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   1636 
   1637     /* next figure out the lane num and start_lane based on the input */
   1638     PHYMOD_IF_ERR_RETURN
   1639         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   1640 
   1641     switch (loopback) {
   1642     case phymodLoopbackGlobal :
   1643     case phymodLoopbackGlobalPMD :
   1644         if (enable) {
   1645             phy_copy.access.lane_mask = 1 << start_lane;
   1646             PHYMOD_IF_ERR_RETURN
   1647                 (tbhmod_disable_set(&phy_copy.access));
   1648             /*first squelch rx */
   1649             for (i = 0; i < num_lane; i++) {
   1650                 if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   1651                     continue;
   1652                 }
   1653                 PHYMOD_IF_ERR_RETURN(blackhawk_pmd_force_signal_detect(&phy_copy.access,  (int) enable, (int) 0));
   1654             }
   1655             phy_copy.access.lane_mask = 1 << start_lane;
   1656             PHYMOD_IF_ERR_RETURN
   1657                 (tbhmod_enable_set(&phy_copy.access));
   1658         }
   1659         for (i = 0; i < num_lane; i++) {
   1660             if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   1661                 continue;
   1662             }
   1663             phy_copy.access.lane_mask = 0x1 << (i + start_lane);
   1664             PHYMOD_IF_ERR_RETURN(blackhawk_tsc_tx_disable(&phy_copy.access, enable));
   1665             PHYMOD_IF_ERR_RETURN(blackhawk_tsc_dig_lpbk(&phy_copy.access, (uint8_t) enable));
   1666         }
   1667         if (!enable) {
   1668             for (i = 0; i < num_lane; i++) {
   1669                 if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   1670                     continue;
   1671                 }
   1672                 PHYMOD_IF_ERR_RETURN(blackhawk_pmd_force_signal_detect(&phy_copy.access,  (int) enable, (int) 0));
   1673             }
   1674         }
   1675         break;
   1676     case phymodLoopbackRemotePMD :
   1677         for (i = 0; i < num_lane; i++) {
   1678             if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   1679                 continue;
   1680             }
   1681             phy_copy.access.lane_mask = 0x1 << (i + start_lane);
   1682             PHYMOD_IF_ERR_RETURN(blackhawk_tsc_rmt_lpbk(&phy_copy.access, (uint8_t)enable));
   1683         }
   1684         break;
   1685     case phymodLoopbackRemotePCS :
   1686     default :
   1687         PHYMOD_RETURN_WITH_ERR(PHYMOD_E_UNAVAIL,
   1688                                (_PHYMOD_MSG("This mode is not supported\n")));
   1689         break;
   1690     }
   1691     return PHYMOD_E_NONE;
   1692 }
   1693 
   1694 int tscbh_phy_loopback_get(const phymod_phy_access_t* phy, phymod_loopback_mode_t loopback, uint32_t* enable)
   1695 {
   1696     int start_lane, num_lane;
   1697     phymod_phy_access_t phy_copy;
   1698 
   1699     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   1700 
   1701     /*next figure out the lane num and start_lane based on the input*/
   1702     PHYMOD_IF_ERR_RETURN
   1703         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   1704 
   1705     switch (loopback) {
   1706     case phymodLoopbackGlobal :
   1707     case phymodLoopbackGlobalPMD :
   1708         PHYMOD_IF_ERR_RETURN(blackhawk_tsc_dig_lpbk_get(&phy_copy.access, enable));
   1709         break;
   1710     case phymodLoopbackRemotePMD :
   1711         PHYMOD_IF_ERR_RETURN(blackhawk_tsc_rmt_lpbk_get(&phy_copy.access, enable));
   1712         break;
   1713     case phymodLoopbackRemotePCS :
   1714     default :
   1715         return PHYMOD_E_UNAVAIL;
   1716     }
   1717     return PHYMOD_E_NONE;
   1718 }
   1719 
   1720 /* Core initialization
   1721  * (PASS1)
   1722  * 1.  De-assert PMD core and PMD lane reset
   1723  * 2.  Set heartbeat for comclk
   1724  * 3.  Configure PMD lane mapping and PCS lane swap
   1725  * 4.  Micro code load and verify
   1726  * 5.  Start CRC Calculation (opt)
   1727  * (PASS2)
   1728  * 6.  De-assert micro reset
   1729  * 7.  Wait for uc_active = 1
   1730  * 8.  Initialize software information table for the micro
   1731  * 9.  Config PMD polarity
   1732  * 10. AFE/PLL configuration
   1733  * 11. Set core_from_pcs_config
   1734  * 12. Program AN default timer
   1735  * 13. Load sd_id_table, am_table and um_table into TSC memory
   1736  * 14. Release core DP soft reset
   1737  */
   1738 STATIC
   1739 int _tscbh_core_init_pass1(const phymod_core_access_t* core, const phymod_core_init_config_t* init_config, const phymod_core_status_t* core_status)
   1740 {
   1741     int rv, lane;
   1742     phymod_phy_access_t phy_access;
   1743     phymod_core_access_t  core_copy;
   1744     uint32_t uc_enable = 0, rev_num;
   1745     phymod_polarity_t tmp_pol;
   1746     ucode_info_t ucode;
   1747     unsigned int blackhawk_ucode_len;
   1748     unsigned char *blackhawk_ucode;
   1749 
   1750     TSCBH_CORE_TO_PHY_ACCESS(&phy_access, core);
   1751     PHYMOD_MEMCPY(&core_copy, core, sizeof(core_copy));
   1752     core_copy.access.lane_mask = 0x1;
   1753 
   1754     PHYMOD_MEMSET(&tmp_pol, 0x0, sizeof(tmp_pol));
   1755 
   1756     /* 1. De-assert PMD core power and core data path reset */
   1757     PHYMOD_IF_ERR_RETURN
   1758         (tbhmod_pmd_reset_seq(&core_copy.access, core_status->pmd_active));
   1759 
   1760     core_copy.access.pll_idx = 1;
   1761     PHYMOD_IF_ERR_RETURN
   1762         (blackhawk_tsc_core_dp_reset(&core_copy.access, 1));
   1763     core_copy.access.pll_idx = 0;
   1764     PHYMOD_IF_ERR_RETURN
   1765         (blackhawk_tsc_core_dp_reset(&core_copy.access, 1));
   1766 
   1767     /* De-assert PMD lane reset */
   1768     
   1769     for (lane = 0; lane < TSCBH_NOF_LANES_IN_CORE; lane++) {
   1770         phy_access.access.lane_mask = 1 << lane;
   1771         PHYMOD_IF_ERR_RETURN
   1772           (tbhmod_pmd_x4_reset(&phy_access.access));
   1773     }
   1774 
   1775     PHYMOD_IF_ERR_RETURN
   1776         (blackhawk_uc_active_get(&phy_access.access, &uc_enable));
   1777     if (uc_enable) return PHYMOD_E_NONE;
   1778 
   1779     /* 2. Set the heart beat, default is 156.25M */
   1780     if (init_config->interface.ref_clock != phymodRefClk156Mhz) {
   1781         PHYMOD_IF_ERR_RETURN
   1782             (blackhawk_refclk_set(&core_copy.access, init_config->interface.ref_clock));
   1783         PHYMOD_IF_ERR_RETURN
   1784             (tbhmod_refclk_set(&phy_access.access, TBHMOD_REF_CLK_312P5MHZ));
   1785     }
   1786 
   1787     /* 3. Configure PMD lane mapping and PCS lane swap */
   1788     PHYMOD_IF_ERR_RETURN
   1789         (tscbh_core_lane_map_set(&core_copy, &init_config->lane_map));
   1790 
   1791     /* 4. set the micro stack size */
   1792     phy_access.access.lane_mask = 0x1;
   1793     PHYMOD_IF_ERR_RETURN
   1794         (tbhmod_revid_get(&phy_access.access, &rev_num));
   1795     if (rev_num == TBHMOD_REV_NUM_0) {
   1796         ucode.stack_size = blackhawk_ucode_stack_size_rev0;
   1797         ucode.ucode_size = blackhawk_ucode_len_rev0;
   1798         blackhawk_ucode_len = blackhawk_ucode_len_rev0;
   1799         blackhawk_ucode = blackhawk_ucode_rev0;
   1800     } else {
   1801         ucode.stack_size = blackhawk_ucode_stack_size_rev1;
   1802         ucode.ucode_size = blackhawk_ucode_len_rev1;
   1803         blackhawk_ucode_len = blackhawk_ucode_len_rev1;
   1804         blackhawk_ucode = blackhawk_ucode_rev1;
   1805     }
   1806 
   1807     PHYMOD_IF_ERR_RETURN
   1808     (blackhawk_tsc_uc_reset_with_info(&core_copy.access , 1, ucode));
   1809 
   1810     /* 5. Micro code load and verify */
   1811     rv = _tscbh_core_firmware_load(&core_copy, init_config);
   1812     if (rv != PHYMOD_E_NONE) {
   1813         PHYMOD_DEBUG_ERROR(("devad 0x%"PRIx32" lane 0x%"PRIx32": UC firmware-load failed\n", core->access.addr, core->access.lane_mask));
   1814         PHYMOD_IF_ERR_RETURN(rv);
   1815     }
   1816 
   1817      /* need to check if the ucode load is correct or not */
   1818     if (init_config->firmware_load_method != phymodFirmwareLoadMethodNone) {
   1819         /* Read-back uCode from Program RAM and verify against ucode_image.
   1820          * The comparison is 4-byte at a time, which is time-consuming.
   1821          * Thus, this code is only needed for debug purpose.
   1822          */
   1823         if (PHYMOD_CORE_INIT_F_FIRMWARE_LOAD_VERIFY_GET(init_config)) {
   1824             rv = blackhawk_tsc_ucode_load_verify(&core_copy.access, (uint8_t *) blackhawk_ucode, blackhawk_ucode_len);
   1825             if (rv != PHYMOD_E_NONE) {
   1826                 PHYMOD_DEBUG_ERROR(("devad 0x%x lane 0x%x: UC load-verify failed\n", core->access.addr, core->access.lane_mask));
   1827                 PHYMOD_IF_ERR_RETURN(rv);
   1828             }
   1829         }
   1830     }
   1831 
   1832     return PHYMOD_E_NONE;
   1833 }
   1834 
   1835 
   1836 STATIC
   1837 int _tscbh_core_init_pass2(const phymod_core_access_t* core, const phymod_core_init_config_t* init_config, const phymod_core_status_t* core_status)
   1838 {
   1839     phymod_phy_access_t phy_access, phy_access_copy;
   1840     phymod_core_access_t  core_copy;
   1841     enum blackhawk_tsc_pll_refclk_enum refclk;
   1842     phymod_polarity_t tmp_pol;
   1843     int lane, pll_index;
   1844     uint32_t speed_id_load_size, am_table_load_size, um_table_load_size;
   1845     uint32_t tvco_rate, i, tvco_pll_index, rev_num;
   1846 
   1847     TSCBH_CORE_TO_PHY_ACCESS(&phy_access, core);
   1848     phy_access_copy = phy_access;
   1849     PHYMOD_MEMCPY(&core_copy, core, sizeof(core_copy));
   1850     core_copy.access.lane_mask = 0x1;
   1851     phy_access_copy = phy_access;
   1852     phy_access_copy.access = core->access;
   1853     phy_access_copy.access.lane_mask = 0x1;
   1854     phy_access_copy.type = core->type;
   1855     tvco_pll_index = core->access.tvco_pll_index;
   1856 
   1857     if (init_config->interface.ref_clock == phymodRefClk156Mhz) {
   1858         refclk = BLACKHAWK_TSC_PLL_REFCLK_156P25MHZ;
   1859         /* first check tvco index */
   1860         if (tvco_pll_index == 1) {
   1861             PHYMOD_IF_ERR_RETURN(
   1862                  tbhmod_pll_to_vco_get(TBHMOD_REF_CLK_156P25MHZ, init_config->pll1_div_init_value, &tvco_rate));
   1863         } else if (tvco_pll_index == 0) {
   1864             PHYMOD_IF_ERR_RETURN(
   1865                  tbhmod_pll_to_vco_get(TBHMOD_REF_CLK_156P25MHZ, init_config->pll0_div_init_value, &tvco_rate));
   1866         } else {
   1867             PHYMOD_DEBUG_ERROR(("Unsupported tvco index\n"));
   1868             return PHYMOD_E_UNAVAIL;
   1869         }
   1870     } else if (init_config->interface.ref_clock == phymodRefClk312Mhz) {
   1871         refclk = BLACKHAWK_TSC_PLL_REFCLK_312P5MHZ;
   1872         /* first check tvco index */
   1873         if (tvco_pll_index == 1) {
   1874             PHYMOD_IF_ERR_RETURN(
   1875                  tbhmod_pll_to_vco_get(TBHMOD_REF_CLK_312P5MHZ, init_config->pll1_div_init_value, &tvco_rate));
   1876         } else if (tvco_pll_index == 0) {
   1877             PHYMOD_IF_ERR_RETURN(
   1878                  tbhmod_pll_to_vco_get(TBHMOD_REF_CLK_312P5MHZ, init_config->pll0_div_init_value, &tvco_rate));
   1879         } else {
   1880             PHYMOD_DEBUG_ERROR(("Unsupported tvco index\n"));
   1881             return PHYMOD_E_UNAVAIL;
   1882         }
   1883     } else {
   1884         PHYMOD_DEBUG_ERROR(("Unsupported reference clock.\n"));
   1885         return PHYMOD_E_UNAVAIL;
   1886     }
   1887 
   1888     /*next need to load speed id table and AM table */
   1889     speed_id_load_size = TSCBH_SPEED_ID_TABLE_SIZE > TSCBH_HW_SPEED_ID_TABLE_SIZE ? TSCBH_HW_SPEED_ID_TABLE_SIZE : TSCBH_SPEED_ID_TABLE_SIZE;
   1890     am_table_load_size = TSCBH_AM_TABLE_SIZE > TSCBH_HW_AM_TABLE_SIZE ? TSCBH_HW_AM_TABLE_SIZE : TSCBH_AM_TABLE_SIZE;
   1891     um_table_load_size = TSCBH_UM_TABLE_SIZE > TSCBH_HW_UM_TABLE_SIZE ? TSCBH_HW_UM_TABLE_SIZE : TSCBH_UM_TABLE_SIZE;
   1892 
   1893     if (tvco_rate == TBHMOD_VCO_26G) {
   1894         for (i = 0; i < speed_id_load_size; i++) {
   1895             PHYMOD_IF_ERR_RETURN
   1896                 (phymod_mem_write(&core_copy.access, phymodMemSpeedIdTable, i, &spd_id_entry_26[i][0]));
   1897         }
   1898     } else if (tvco_rate == TBHMOD_VCO_25G) {
   1899         for (i = 0; i < speed_id_load_size; i++) {
   1900             PHYMOD_IF_ERR_RETURN
   1901                 (phymod_mem_write(&core_copy.access, phymodMemSpeedIdTable, i, &spd_id_entry_25[i][0]));
   1902         }
   1903     } else if (tvco_rate == TBHMOD_VCO_20G) {
   1904         for (i = 0; i < speed_id_load_size; i++) {
   1905             PHYMOD_IF_ERR_RETURN
   1906                 (phymod_mem_write(&core_copy.access, phymodMemSpeedIdTable, i, &spd_id_entry_20[i][0]));
   1907         }
   1908     }
   1909 
   1910     for (i = 0; i < am_table_load_size; i++) {
   1911         PHYMOD_IF_ERR_RETURN
   1912             (phymod_mem_write(&core_copy.access, phymodMemAMTable, i,  &am_table_entry[i][0]));
   1913     }
   1914 
   1915     for (i = 0; i < um_table_load_size; i++) {
   1916         PHYMOD_IF_ERR_RETURN
   1917             (phymod_mem_write(&core_copy.access, phymodMemUMTable, i,  &um_table_entry[i][0]));
   1918     }
   1919 
   1920     /*need to update speed_priority_mapping_table with correct speed id */
   1921     PHYMOD_IF_ERR_RETURN
   1922         (phymod_mem_write(&core_copy.access, phymodMemSpeedPriorityMapTable, 0,  &speed_priority_mapping_table[0][0]));
   1923 
   1924     if (init_config->firmware_load_method != phymodFirmwareLoadMethodNone) {
   1925         ucode_info_t ucode;
   1926         PHYMOD_IF_ERR_RETURN
   1927             (tbhmod_revid_get(&phy_access.access, &rev_num));
   1928         if (rev_num == TBHMOD_REV_NUM_0) {
   1929             ucode.stack_size = blackhawk_ucode_stack_size_rev0;
   1930             ucode.ucode_size = blackhawk_ucode_len_rev0;
   1931             ucode.crc_value  = blackhawk_ucode_crc_rev0;
   1932         } else {
   1933             ucode.stack_size = blackhawk_ucode_stack_size_rev1;
   1934             ucode.ucode_size = blackhawk_ucode_len_rev1;
   1935             ucode.crc_value  = blackhawk_ucode_crc_rev1;
   1936         }
   1937 
   1938         /* per PLP, uc will set this bit, so SW does not need to do this anymore */
   1939         /* PHYMOD_IF_ERR_RETURN
   1940             (blackhawk_uc_active_set(&core_copy.access ,1)); */
   1941 
   1942         /* 6. Release uc reset */
   1943         PHYMOD_IF_ERR_RETURN
   1944         (blackhawk_tsc_uc_reset_with_info(&core_copy.access , 0, ucode));
   1945 
   1946         /* 7. Wait for uc_active = 1 */
   1947         PHYMOD_IF_ERR_RETURN
   1948             (blackhawk_tsc_wait_uc_active(&phy_access.access));
   1949 
   1950         for (lane = 0; lane < TSCBH_NOF_LANES_IN_CORE; lane++) {
   1951             phy_access_copy.access.lane_mask = 1 << lane;
   1952             PHYMOD_IF_ERR_RETURN
   1953                 (blackhawk_pmd_ln_h_rstb_pkill_override(&phy_access_copy.access, 0x1));
   1954         }
   1955 
   1956         /* 8. Initialize software information table for the macro */
   1957         PHYMOD_IF_ERR_RETURN
   1958             (blackhawk_tsc_init_blackhawk_tsc_info(&core_copy.access));
   1959 
   1960         /* check the FW crc checksum error */
   1961         if (!PHYMOD_CORE_INIT_F_BYPASS_CRC_CHECK_GET(init_config)) {
   1962             PHYMOD_IF_ERR_RETURN
   1963                 (blackhawk_tsc_check_ucode_crc(&core_copy.access, ucode.crc_value, 200));
   1964         }
   1965 
   1966         /* release pmd lane hard reset */
   1967         for (lane = 0; lane < TSCBH_NOF_LANES_IN_CORE; lane++) {
   1968             phy_access_copy.access.lane_mask = 1 << lane;
   1969             PHYMOD_IF_ERR_RETURN
   1970                 (blackhawk_pmd_ln_h_rstb_pkill_override(&phy_access_copy.access, 0x0));
   1971         }
   1972     } else {
   1973         PHYMOD_IF_ERR_RETURN
   1974             (blackhawk_tsc_firmware_load_none_init_blackhawk_tsc_info(&core_copy.access));
   1975     }
   1976 
   1977     /* 9. RX/TX polarity configuration */
   1978     
   1979     for (lane = 0; lane < TSCBH_NOF_LANES_IN_CORE; lane++) {
   1980         phy_access_copy.access.lane_mask = 1 << lane;
   1981         tmp_pol.tx_polarity = (init_config->polarity_map.tx_polarity) >> lane & 0x1;
   1982         tmp_pol.rx_polarity = (init_config->polarity_map.rx_polarity) >> lane & 0x1;
   1983         PHYMOD_IF_ERR_RETURN
   1984             (tscbh_phy_polarity_set(&phy_access_copy, &tmp_pol));
   1985         /* clear the tmp vairiable */
   1986         PHYMOD_MEMSET(&tmp_pol, 0x0, sizeof(tmp_pol));
   1987     }
   1988 
   1989     /* 10. AFE/PLL configuration */
   1990     for (pll_index = 0; pll_index < 2; pll_index++) {
   1991         core_copy.access.pll_idx = pll_index;
   1992         PHYMOD_IF_ERR_RETURN
   1993             (blackhawk_afe_pll_reg_set(&core_copy.access, &init_config->afe_pll));
   1994     }
   1995 
   1996     /* PLL_DIV config for both PLL0 and PLL1 */
   1997     
   1998     if (init_config->pll0_div_init_value != phymod_TSCBH_PLL_DIVNONE) {
   1999         core_copy.access.pll_idx = 0;
   2000         PHYMOD_IF_ERR_RETURN
   2001             (blackhawk_tsc_configure_pll_refclk_div(&core_copy.access,
   2002                                                       refclk,
   2003                                                       init_config->pll0_div_init_value));
   2004     }
   2005 
   2006     if (init_config->pll1_div_init_value != phymod_TSCBH_PLL_DIVNONE) {
   2007         core_copy.access.pll_idx = 1;
   2008         PHYMOD_IF_ERR_RETURN
   2009             (blackhawk_tsc_configure_pll_refclk_div(&core_copy.access,
   2010                                                       refclk,
   2011                                                       init_config->pll1_div_init_value));
   2012     }
   2013 
   2014     /* 12. Program AN default timer  for both MMP0 and MMP1*/
   2015     core_copy.access.lane_mask = 0x1;
   2016     core_copy.access.pll_idx = 0;
   2017     PHYMOD_IF_ERR_RETURN
   2018         (tbhmod_set_an_timers(&core_copy.access, init_config->interface.ref_clock, NULL));
   2019 
   2020     core_copy.access.lane_mask = 0x10;
   2021     core_copy.access.pll_idx = 0;
   2022     PHYMOD_IF_ERR_RETURN
   2023         (tbhmod_set_an_timers(&core_copy.access, init_config->interface.ref_clock, NULL));
   2024 
   2025     /* 13. Load spd_id_table, am_table and um_table into TSC memory */
   2026     
   2027     /* 14. Release core DP soft reset for both PLLs */
   2028     core_copy.access.lane_mask = 0x1;
   2029     core_copy.access.pll_idx = 0;
   2030     /* next need to config PMD micro clock source, chip defualt is PLL0 and SW driver will overwrite the
   2031     default to use PLL1 */
   2032     PHYMOD_IF_ERR_RETURN
   2033         (blackhawk_micro_clk_source_select(&core_copy.access, 1));
   2034     PHYMOD_IF_ERR_RETURN
   2035         (blackhawk_tsc_core_dp_reset(&core_copy.access, 0));
   2036     core_copy.access.pll_idx = 1;
   2037     PHYMOD_IF_ERR_RETURN
   2038         (blackhawk_tsc_core_dp_reset(&core_copy.access, 0));
   2039 
   2040    return PHYMOD_E_NONE;
   2041 
   2042 }
   2043 
   2044 int tscbh_core_init(const phymod_core_access_t* core, const phymod_core_init_config_t* init_config, const phymod_core_status_t* core_status)
   2045 {
   2046     if ( (!PHYMOD_CORE_INIT_F_EXECUTE_PASS1_GET(init_config) &&
   2047           !PHYMOD_CORE_INIT_F_EXECUTE_PASS2_GET(init_config)) ||
   2048         PHYMOD_CORE_INIT_F_EXECUTE_PASS1_GET(init_config)) {
   2049         PHYMOD_IF_ERR_RETURN
   2050             (_tscbh_core_init_pass1(core, init_config, core_status));
   2051 
   2052         if (PHYMOD_CORE_INIT_F_EXECUTE_PASS1_GET(init_config)) {
   2053             return PHYMOD_E_NONE;
   2054         }
   2055     }
   2056 
   2057     if ( (!PHYMOD_CORE_INIT_F_EXECUTE_PASS1_GET(init_config) &&
   2058           !PHYMOD_CORE_INIT_F_EXECUTE_PASS2_GET(init_config)) ||
   2059         PHYMOD_CORE_INIT_F_EXECUTE_PASS2_GET(init_config)) {
   2060         PHYMOD_IF_ERR_RETURN
   2061             (_tscbh_core_init_pass2(core, init_config, core_status));
   2062     }
   2063 
   2064     return PHYMOD_E_NONE;
   2065 }
   2066 
   2067 int tscbh_phy_init(const phymod_phy_access_t* phy, const phymod_phy_init_config_t* init_config)
   2068 {
   2069     /*int pll_restart = 0;*/
   2070     const phymod_access_t *pm_acc = &phy->access;
   2071     phymod_phy_access_t pm_phy_copy;
   2072     int start_lane, num_lane, i;
   2073     phymod_firmware_lane_config_t firmware_lane_config;
   2074     uint32_t rev_num, pll_power_down = 0;
   2075     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
   2076     PHYMOD_MEMSET(&firmware_lane_config, 0x0, sizeof(firmware_lane_config));
   2077 
   2078     PHYMOD_IF_ERR_RETURN
   2079         (phymod_util_lane_config_get(pm_acc, &start_lane, &num_lane));
   2080     /* per lane based reset release */
   2081     PHYMOD_IF_ERR_RETURN
   2082         (tbhmod_pmd_x4_reset(&pm_phy_copy.access));
   2083 
   2084     /* Put PMD lane into soft reset */
   2085     PHYMOD_IF_ERR_RETURN
   2086         (blackhawk_lane_soft_reset(&pm_phy_copy.access, 1));
   2087 
   2088     /* next get version number */
   2089     pm_phy_copy.access.lane_mask = 0x1;
   2090     PHYMOD_IF_ERR_RETURN
   2091         (tbhmod_revid_get(&pm_phy_copy.access, &rev_num));
   2092 
   2093     
   2094     /* clearing all the lane config */
   2095     PHYMOD_MEMSET(&firmware_lane_config, 0x0, sizeof(firmware_lane_config));
   2096 
   2097     for (i = 0; i < num_lane; i++) {
   2098         if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   2099             continue;
   2100         }
   2101         pm_phy_copy.access.lane_mask = 0x1 << (i + start_lane);
   2102         /* set tx parameters */
   2103         PHYMOD_IF_ERR_RETURN
   2104             (tscbh_phy_tx_set(&pm_phy_copy, &init_config->tx[i]));
   2105     }
   2106 
   2107     
   2108     for (i = 0; i < num_lane; i++) {
   2109         if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   2110             continue;
   2111         }
   2112         pm_phy_copy.access.lane_mask = 0x1 << (i + start_lane);
   2113         PHYMOD_IF_ERR_RETURN
   2114              (_tscbh_phy_firmware_lane_config_set(&pm_phy_copy, firmware_lane_config));
   2115         /* FROM PMD team:
   2116          * The best initial analog calibration is achieved using the information
   2117          * from the PMD RX PRBS checker. Using the FW register value of 3 enables
   2118          * a continuous version that does not rely on PRBS traffic anymore.
   2119          * the value of 3 o will apply to A0 part only, and for B0 the value will be 0
   2120         */
   2121         if (rev_num == TBHMOD_REV_NUM_0) {
   2122             PHYMOD_IF_ERR_RETURN
   2123                  (blackhawk_tsc_lane_cfg_fwapi_data1_set(&pm_phy_copy.access, 3));
   2124         } else {
   2125             PHYMOD_IF_ERR_RETURN
   2126                  (blackhawk_tsc_lane_cfg_fwapi_data1_set(&pm_phy_copy.access, 0));
   2127         }
   2128     }
   2129 
   2130 #if 0 
   2131     /* next check if pcs-bypass mode  */
   2132     if (PHYMOD_DEVICE_OP_MODE_PCS_BYPASS_GET(phy->device_op_mode)) {
   2133         pm_phy_copy.access.lane_mask = lane_bkup;
   2134         PHYMOD_IF_ERR_RETURN
   2135             (blackhawk_pmd_tx_disable_pin_dis_set(&pm_phy_copy.access, 1));
   2136         PHYMOD_IF_ERR_RETURN
   2137           (tbhmod_init_pcs_ilkn(&phy->access));
   2138     }
   2139     
   2140     PHYMOD_IF_ERR_RETURN
   2141         (tbhmod_update_port_mode(pm_acc, &pll_restart));
   2142 #endif
   2143     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
   2144     PHYMOD_IF_ERR_RETURN
   2145         (tbhmod_rx_lane_control(&pm_phy_copy.access, 1));
   2146     PHYMOD_IF_ERR_RETURN
   2147         (tbhmod_tx_lane_control(&pm_phy_copy.access, 1, 0));         /* TX_LANE_CONTROL */
   2148 
   2149     /* make sure that power up PLL is locked */
   2150     pm_phy_copy.access.pll_idx = 0;
   2151     pm_phy_copy.access.lane_mask = 1 << 0;
   2152     PHYMOD_IF_ERR_RETURN
   2153         (blackhawk_tsc_pll_pwrdn_get(&pm_phy_copy.access, &pll_power_down));
   2154 
   2155     /* need to check pll0 lock if not power up */
   2156     /* put the check here is to save on boot up time */
   2157     if (!pll_power_down) {
   2158         uint32_t cnt = 0, pll_lock = 0;
   2159         cnt = 0;
   2160         while (cnt < 500) {
   2161             PHYMOD_IF_ERR_RETURN(blackhawk_tsc_pll_lock_get(&pm_phy_copy.access, &pll_lock));
   2162             cnt = cnt + 1;
   2163             if (pll_lock) {
   2164                 break;
   2165             } else {
   2166                 if(cnt == 500) {
   2167                     PHYMOD_DEBUG_ERROR(("WARNING :: core 0x%x PLL0 is not locked within 5 milli second \n", pm_phy_copy.access.addr));
   2168                     break;
   2169                 }
   2170             }
   2171             PHYMOD_USLEEP(10);
   2172         }
   2173     }
   2174 
   2175     pm_phy_copy.access.pll_idx = 1;
   2176     pm_phy_copy.access.lane_mask = 1 << 0;
   2177     PHYMOD_IF_ERR_RETURN
   2178         (blackhawk_tsc_pll_pwrdn_get(&pm_phy_copy.access, &pll_power_down));
   2179 
   2180     /* need to check pll1 lock if not power up */
   2181     if (!pll_power_down) {
   2182         uint32_t cnt = 0, pll_lock = 0;
   2183         cnt = 0;
   2184         while (cnt < 500) {
   2185             PHYMOD_IF_ERR_RETURN(blackhawk_tsc_pll_lock_get(&pm_phy_copy.access, &pll_lock));
   2186             cnt = cnt + 1;
   2187             if (pll_lock) {
   2188                 break;
   2189             } else {
   2190                 if(cnt == 500) {
   2191                     PHYMOD_DEBUG_ERROR(("WARNING :: core 0x%x PLL1 is not locked within 5 milli second \n", pm_phy_copy.access.addr));
   2192                     break;
   2193                 }
   2194             }
   2195             PHYMOD_USLEEP(10);
   2196         }
   2197     }
   2198 
   2199     return PHYMOD_E_NONE;
   2200 }
   2201 
   2202 
   2203 /* this function gives the PMD_RX_LOCK_STATUS */
   2204 int tscbh_phy_link_status_get(const phymod_phy_access_t* phy, uint32_t* link_status)
   2205 {
   2206     phymod_phy_access_t pm_phy_copy;
   2207     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
   2208 
   2209     PHYMOD_IF_ERR_RETURN(tbhmod_get_pcs_latched_link_status(&pm_phy_copy.access, link_status));
   2210     return PHYMOD_E_NONE;
   2211 }
   2212 
   2213 
   2214 int tscbh_phy_rx_pmd_locked_get(const phymod_phy_access_t* phy, uint32_t* pmd_lock)
   2215 {
   2216     int start_lane, num_lane, i;
   2217     phymod_phy_access_t pm_phy_copy;
   2218     uint8_t tmp_lock;
   2219 
   2220     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
   2221     *pmd_lock = 1;
   2222 
   2223     PHYMOD_IF_ERR_RETURN
   2224         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   2225 
   2226     for (i = 0; i < num_lane; i++) {
   2227         pm_phy_copy.access.lane_mask = 1 << (start_lane + i);
   2228         if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   2229             continue;
   2230         }
   2231         PHYMOD_IF_ERR_RETURN
   2232             (blackhawk_tsc_pmd_lock_status(&pm_phy_copy.access, &tmp_lock));
   2233         *pmd_lock &= (uint32_t) tmp_lock;
   2234     }
   2235     return PHYMOD_E_NONE;
   2236 
   2237 }
   2238 
   2239 /* this function gives the PMD_RX_LOCK_STATUS */
   2240 int tscbh_phy_rx_signal_detect_get(const phymod_phy_access_t* phy, uint32_t* signal_detect)
   2241 {
   2242     int start_lane, num_lane, i;
   2243     phymod_phy_access_t pm_phy_copy;
   2244     uint32_t tmp_detect;
   2245 
   2246     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
   2247     *signal_detect = 1;
   2248 
   2249     PHYMOD_IF_ERR_RETURN
   2250         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   2251 
   2252     for (i = 0; i < num_lane; i++) {
   2253         pm_phy_copy.access.lane_mask = 1 << (start_lane + i);
   2254         if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   2255             continue;
   2256         }
   2257         PHYMOD_IF_ERR_RETURN
   2258             (blackhawk_tsc_signal_detect(&pm_phy_copy.access, &tmp_detect));
   2259         *signal_detect &= tmp_detect;
   2260     }
   2261     return PHYMOD_E_NONE;
   2262 
   2263 }
   2264 
   2265 int tscbh_phy_reg_read(const phymod_phy_access_t* phy, uint32_t reg_addr, uint32_t* val)
   2266 {
   2267     PHYMOD_IF_ERR_RETURN(phymod_tscbh_iblk_read(&phy->access, reg_addr, val));
   2268     return PHYMOD_E_NONE;
   2269 }
   2270 
   2271 
   2272 int tscbh_phy_reg_write(const phymod_phy_access_t* phy, uint32_t reg_addr, uint32_t val)
   2273 {
   2274     PHYMOD_IF_ERR_RETURN(phymod_tscbh_iblk_write(&phy->access, reg_addr, val));
   2275     return PHYMOD_E_NONE;
   2276 }
   2277 
   2278 /* get default tx taps*/
   2279 int tscbh_phy_tx_taps_default_get(const phymod_phy_access_t* phy, phymod_phy_signalling_method_t mode, phymod_tx_t* tx)
   2280 {
   2281     /*always default to 6-taps mode */
   2282     tx->tap_mode = phymodTxTapMode6Tap;
   2283     tx->sig_method = mode;
   2284     if (mode == phymodSignallingMethodNRZ) {
   2285         tx->pre2 = 0;
   2286         tx->pre = 0;
   2287         tx->main = 127;
   2288         tx->post = 0;
   2289         tx->post2 = 0;
   2290         tx->post3 = 0;
   2291     } else {
   2292         tx->pre2 = 0;
   2293         tx->pre = -24;
   2294         tx->main = 132;
   2295         tx->post = -12;
   2296         tx->post2 = 0;
   2297         tx->post3 = 0;
   2298     }
   2299 
   2300     return PHYMOD_E_NONE;
   2301 }
   2302 
   2303 /* get default tx taps*/
   2304 int tscbh_phy_lane_config_default_get(const phymod_phy_access_t* phy, phymod_phy_signalling_method_t mode, phymod_firmware_lane_config_t* lane_config)
   2305 {
   2306     /* default always assume backplane as the medium type and with dfe on */
   2307     if (mode == phymodSignallingMethodNRZ) {
   2308         lane_config->ForceNRZMode = 1;
   2309         lane_config->ForcePAM4Mode = 0;
   2310         lane_config->ForceNormalReach  = 0;
   2311     } else {
   2312         lane_config->ForceNRZMode = 0;
   2313         lane_config->ForcePAM4Mode = 1;
   2314         lane_config->ForceNormalReach  = 1;
   2315     }
   2316     lane_config->LaneConfigFromPCS = 0;
   2317     lane_config->AnEnabled = 0;
   2318     lane_config->DfeOn = 1;
   2319     lane_config->LpDfeOn = 0;
   2320     lane_config->ForceBrDfe = 0;
   2321     lane_config->MediaType = 0;
   2322     lane_config->ScramblingDisable = 0;
   2323     lane_config->Cl72AutoPolEn = 0;
   2324     lane_config->Cl72RestTO    = 0;
   2325     lane_config->ForceExtenedReach = 0;
   2326     lane_config->LpPrecoderEnabled = 0;
   2327     lane_config->UnreliableLos = 0;
   2328 
   2329     return PHYMOD_E_NONE;
   2330 }
   2331 
   2332 int tscbh_phy_pll_multiplier_get(const phymod_phy_access_t* phy, uint32_t* core_vco_pll_multiplier)
   2333 {
   2334     phymod_phy_access_t pm_phy_copy;
   2335     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
   2336 
   2337     PHYMOD_IF_ERR_RETURN(blackhawk_tsc_INTERNAL_read_pll_div(&pm_phy_copy.access,  core_vco_pll_multiplier));
   2338     return PHYMOD_E_NONE;
   2339 }
   2340 
   2341 int tscbh_phy_firmware_load_info_get(const phymod_phy_access_t* phy, phymod_firmware_load_info_t* info)
   2342 {
   2343     uint32_t rev_num;
   2344     phymod_phy_access_t phy_copy;
   2345 
   2346     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   2347     phy_copy.access.lane_mask = 0x1;
   2348 
   2349     PHYMOD_IF_ERR_RETURN
   2350         (tbhmod_revid_get(&(phy_copy.access), &rev_num));
   2351     if (rev_num == TBHMOD_REV_NUM_0) {
   2352         info->ucode_ptr = &blackhawk_ucode_rev0[0];
   2353         info->ucode_len = blackhawk_ucode_len_rev0;
   2354     } else {
   2355         info->ucode_ptr = &blackhawk_ucode_rev1[0];
   2356         info->ucode_len = blackhawk_ucode_len_rev1;
   2357     }
   2358     return PHYMOD_E_NONE;
   2359 }
   2360 
   2361 int _tscbh_phy_autoneg_ability_to_vco_get(const phymod_autoneg_advert_abilities_t* an_advert_abilities,
   2362                                           uint16_t* request_vco)
   2363 {
   2364     phymod_autoneg_advert_ability_t* an_ability;
   2365     int i;
   2366 
   2367     an_ability = an_advert_abilities->autoneg_abilities;
   2368     /* We do not validate each abilities here since they are supposed to be validated in portmod. */
   2369     for (i = 0; i < an_advert_abilities->num_abilities; i++) {
   2370         switch (an_ability[i].speed) {
   2371             case 10000:
   2372                 /* CL73-10G-1lane */
   2373                 *request_vco |= TBHMOD_VCO_20G;
   2374                 break;
   2375             case 20000:
   2376                 /* CL73BAM-20G-2lanes */
   2377                 *request_vco |= TBHMOD_VCO_20G;
   2378                 break;
   2379             case 25000:
   2380                 /* CL73-1lane; CL73BAM-1lane; MSA-1lane */
   2381                 *request_vco |= TBHMOD_VCO_25G;
   2382                 break;
   2383             case 40000:
   2384                 /* CL73-40G-4lanes */
   2385                 /* CL73BAM-40G-2lanes */
   2386                 *request_vco |= TBHMOD_VCO_20G;
   2387                 break;
   2388             case 50000:
   2389                 if (an_ability[i].fec == phymod_fec_RS544) {
   2390                     /* CL73-50G-1lane */
   2391                     /* CL73BAM-50G-2lanes-RS544 */
   2392                     *request_vco |= TBHMOD_VCO_26G;
   2393                 } else {
   2394                     /* CL73BAM-50G-1lane*/
   2395                     /* CL73BAM-50G-2lanes-Nofec/CL74/RS528 */
   2396                     /* MSA-50G-2lanes */
   2397                     *request_vco |= TBHMOD_VCO_25G;
   2398                 }
   2399                 break;
   2400             case 100000:
   2401                 if (an_ability[i].fec == phymod_fec_RS544) {
   2402                     /* CL73-100G-2lanes */
   2403                     /* CL73BAM-100G-4lanes-RS544 */
   2404                     *request_vco |= TBHMOD_VCO_26G;
   2405                 } else {
   2406                     /* CL73-100G-4lanes */
   2407                     /* CL73BAM-100G-2lanes-RS528 */
   2408                     /* CL73BAM-100G-2lanes-Nofec */
   2409                     /* CL73BAM-100G-4lanes-Nofec */
   2410                     *request_vco |= TBHMOD_VCO_25G;
   2411                 }
   2412                 break;
   2413             case 200000:
   2414                 if ((an_ability[i].fec == phymod_fec_RS544)
   2415                     || (an_ability[i].fec == phymod_fec_RS544_2XN)) {
   2416                     /* CL73-200G-4lanes-RS544_2XN */
   2417                     /* CL73BAM-200G-4lanes-RS544_1XN */
   2418                     *request_vco |= TBHMOD_VCO_26G;
   2419                 } else {
   2420                     /* CL73BAM-200G-4lanes-Nofec */
   2421                     *request_vco |= TBHMOD_VCO_25G;
   2422                 }
   2423                 break;
   2424             default:
   2425                 break;
   2426         }
   2427 
   2428     }
   2429 
   2430     return PHYMOD_E_NONE;
   2431 }
   2432 
   2433 int tscbh_phy_autoneg_advert_ability_set(const phymod_phy_access_t* phy,
   2434                                          const phymod_autoneg_advert_abilities_t* an_advert_abilities,
   2435                                          const phymod_phy_pll_state_t* old_pll_adv_state,
   2436                                          phymod_phy_pll_state_t* new_pll_adv_state)
   2437 {
   2438     uint16_t request_vco = 0;
   2439     int start_lane, num_lane, i = 0, requested_pll_num;
   2440     phymod_phy_access_t phy_copy;
   2441     tbhmod_refclk_t ref_clk;
   2442     uint32_t request_pll_div[3], ovco_is_pwrdn = 0;
   2443     uint32_t  ovco_pll_div = 0, tvco_pll_div = 0, pll_index = 0;
   2444     uint8_t ovco_pll_index;
   2445     uint32_t cnt, pll_lock = 0;
   2446 
   2447     PHYMOD_IF_ERR_RETURN
   2448         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   2449 
   2450     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   2451     phy_copy.access.lane_mask = 0x1 << start_lane;
   2452 
   2453     ovco_pll_index = phy->access.tvco_pll_index ? 0 : 1;
   2454 
   2455     /* Program local advert abilitiy registers */
   2456     PHYMOD_IF_ERR_RETURN
   2457         (tbhmod_autoneg_ability_set(&phy_copy.access, an_advert_abilities));
   2458 
   2459     PHYMOD_IF_ERR_RETURN
   2460         (_tscbh_phy_autoneg_ability_to_vco_get(an_advert_abilities, &request_vco));
   2461 
   2462     PHYMOD_IF_ERR_RETURN
   2463         (tbhmod_refclk_get(&phy_copy.access, &ref_clk));
   2464     /* Check the request speed VCO */
   2465     if (request_vco & TBHMOD_VCO_20G) {
   2466         PHYMOD_IF_ERR_RETURN
   2467             (tbhmod_vco_to_pll_lkup(TBHMOD_VCO_20G, ref_clk, &request_pll_div[i]));
   2468         i++;
   2469     }
   2470     if (request_vco & TBHMOD_VCO_25G) {
   2471         PHYMOD_IF_ERR_RETURN
   2472             (tbhmod_vco_to_pll_lkup(TBHMOD_VCO_25G, ref_clk, &request_pll_div[i]));
   2473         i++;
   2474     }
   2475     if (request_vco & TBHMOD_VCO_26G) {
   2476         PHYMOD_IF_ERR_RETURN
   2477             (tbhmod_vco_to_pll_lkup(TBHMOD_VCO_26G, ref_clk, &request_pll_div[i]));
   2478         i++;
   2479     }
   2480     if (i > 2) {
   2481         /* More than 2 vcos are needed */
   2482         return PHYMOD_E_PARAM;
   2483     }
   2484     requested_pll_num = i - 1;
   2485 
   2486     /* Get OVCO info */
   2487     phy_copy.access.pll_idx = ovco_pll_index;
   2488     PHYMOD_IF_ERR_RETURN
   2489         (blackhawk_tsc_pll_pwrdn_get(&phy_copy.access, &ovco_is_pwrdn));
   2490     if (!ovco_is_pwrdn) {
   2491         PHYMOD_IF_ERR_RETURN
   2492             (blackhawk_tsc_INTERNAL_read_pll_div(&phy_copy.access, &ovco_pll_div));
   2493     }
   2494 
   2495     /* Get TVCO info */
   2496     phy_copy.access.pll_idx = phy->access.tvco_pll_index;
   2497     PHYMOD_IF_ERR_RETURN
   2498         (blackhawk_tsc_INTERNAL_read_pll_div(&phy_copy.access, &tvco_pll_div));
   2499 
   2500     /* Copy existing PLL lane bitmap */
   2501     *new_pll_adv_state = *old_pll_adv_state;
   2502 
   2503     /* Clear current lane_map from both PLL lane bitmap */
   2504     new_pll_adv_state->pll1_lanes_bitmap &= ~(phy->access.lane_mask);
   2505     new_pll_adv_state->pll0_lanes_bitmap &= ~(phy->access.lane_mask);
   2506 
   2507     for (i = requested_pll_num; i >= 0; i--) {
   2508         if (request_pll_div[i] == ovco_pll_div) {
   2509             /* if ovco is using PLL 0 */
   2510             if (!ovco_pll_index) {
   2511                 new_pll_adv_state->pll0_lanes_bitmap |= phy->access.lane_mask;
   2512             } else {
   2513                 new_pll_adv_state->pll1_lanes_bitmap |= phy->access.lane_mask;
   2514             }
   2515         } else if (request_pll_div[i] == tvco_pll_div) {
   2516             /* if ovco is using PLL 0 */
   2517             if (!ovco_pll_index) {
   2518                 new_pll_adv_state->pll1_lanes_bitmap |= phy->access.lane_mask;
   2519             } else {
   2520                 new_pll_adv_state->pll0_lanes_bitmap |= phy->access.lane_mask;
   2521             }
   2522         } else {
   2523             /* Need VCO change */
   2524             pll_index = ovco_pll_index;
   2525             phy_copy.access.pll_idx = pll_index;
   2526 
   2527             if (ovco_is_pwrdn) {
   2528                 /* Power up PLL0 */
   2529                 PHYMOD_IF_ERR_RETURN
   2530                     (blackhawk_tsc_core_pwrdn(&phy_copy.access, PWR_ON));
   2531             }
   2532             /*toggle core dp reset */
   2533             phy_copy.access.lane_mask = 0x1;
   2534             PHYMOD_IF_ERR_RETURN
   2535                 (blackhawk_tsc_core_dp_reset(&phy_copy.access, 1));
   2536 
   2537             /*config the PLL to the requested VCO */
   2538             if (ref_clk == TBHMOD_REF_CLK_312P5MHZ) {
   2539                 PHYMOD_IF_ERR_RETURN
   2540                     (blackhawk_tsc_configure_pll_refclk_div(&phy_copy.access,
   2541                                                             BLACKHAWK_TSC_PLL_REFCLK_312P5MHZ,
   2542                                                             request_pll_div[i]));
   2543             } else {
   2544                 PHYMOD_IF_ERR_RETURN
   2545                     (blackhawk_tsc_configure_pll_refclk_div(&phy_copy.access,
   2546                                                             BLACKHAWK_TSC_PLL_REFCLK_156P25MHZ,
   2547                                                             request_pll_div[i]));
   2548             }
   2549             /* release core soft reset */
   2550             PHYMOD_IF_ERR_RETURN
   2551                 (blackhawk_tsc_core_dp_reset(&phy_copy.access, 0));
   2552             ovco_pll_div = request_pll_div[i];
   2553             new_pll_adv_state->pll0_lanes_bitmap |= phy->access.lane_mask;
   2554 
   2555             /* need to wait for the PLL lock */
   2556             cnt = 0;
   2557             while (cnt < 500) {
   2558                 PHYMOD_IF_ERR_RETURN(blackhawk_tsc_pll_lock_get(&phy_copy.access, &pll_lock));
   2559                 cnt = cnt + 1;
   2560                 if(pll_lock) {
   2561                     break;
   2562                 } else {
   2563                     if(cnt == 500) {
   2564                         PHYMOD_DEBUG_ERROR(("WARNING :: core 0x%x PLL Index %d is not locked within 5 milli second \n", phy_copy.access.addr, pll_index));
   2565                         break;
   2566                     }
   2567                 }
   2568                 PHYMOD_USLEEP(10);
   2569             }
   2570 
   2571         }
   2572     }
   2573 
   2574     return PHYMOD_E_NONE;
   2575 }
   2576 
   2577 int tscbh_phy_autoneg_advert_ability_get(const phymod_phy_access_t* phy,
   2578                                          phymod_autoneg_advert_abilities_t* an_advert_abilities)
   2579 {
   2580     phymod_phy_access_t phy_copy;
   2581     int start_lane, num_lane, i;
   2582     phymod_firmware_lane_config_t firmware_lane_config;
   2583 
   2584     PHYMOD_IF_ERR_RETURN
   2585         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   2586     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   2587     phy_copy.access.lane_mask = 0x1 << start_lane;
   2588 
   2589     PHYMOD_IF_ERR_RETURN
   2590         (tbhmod_autoneg_ability_get(&phy_copy.access, an_advert_abilities));
   2591 
   2592     /* Get Medium type from fw_lane_config */
   2593     PHYMOD_IF_ERR_RETURN
   2594         (tscbh_phy_firmware_lane_config_get(phy, &firmware_lane_config));
   2595 
   2596     for (i = 0; i < an_advert_abilities->num_abilities; i++) {
   2597         an_advert_abilities->autoneg_abilities[i].medium = firmware_lane_config.MediaType;
   2598     }
   2599 
   2600     return PHYMOD_E_NONE;
   2601 }
   2602 
   2603 int tscbh_phy_autoneg_remote_advert_ability_get(const phymod_phy_access_t* phy,
   2604                                                 phymod_autoneg_advert_abilities_t* an_advert_abilities)
   2605 {
   2606     phymod_phy_access_t phy_copy;
   2607     int start_lane, num_lane, i, is_copper = 0;
   2608 
   2609     PHYMOD_IF_ERR_RETURN
   2610         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   2611     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   2612     phy_copy.access.lane_mask = 0x1 << start_lane;
   2613 
   2614     PHYMOD_IF_ERR_RETURN
   2615         (tbhmod_autoneg_remote_ability_get(&phy_copy.access, an_advert_abilities));
   2616 
   2617     for (i = 0; i < an_advert_abilities->num_abilities; i++) {
   2618         if (an_advert_abilities->autoneg_abilities[i].medium == phymodFirmwareMediaTypeCopperCable) {
   2619             is_copper = 1;
   2620             break;
   2621         }
   2622     }
   2623 
   2624     for (i = 0; i < an_advert_abilities->num_abilities; i++) {
   2625         if (is_copper) {
   2626             an_advert_abilities->autoneg_abilities[i].medium = phymodFirmwareMediaTypeCopperCable;
   2627         } else {
   2628             an_advert_abilities->autoneg_abilities[i].medium = phymodFirmwareMediaTypePcbTraceBackPlane;
   2629         }
   2630     }
   2631 
   2632     return PHYMOD_E_NONE;
   2633 }
   2634 
   2635 int tscbh_phy_autoneg_set(const phymod_phy_access_t* phy, const phymod_autoneg_control_t* an)
   2636 {
   2637     int num_lane_adv_encoded, mapped_speed_id;
   2638     int start_lane, num_lane;
   2639     int i, do_lane_config_set;
   2640     uint32_t pll_1_div, vco_rate, refclk_in_hz;
   2641     phymod_firmware_lane_config_t firmware_lane_config;
   2642     tbhmod_an_control_t an_control;
   2643     phymod_phy_access_t phy_copy;
   2644     tbhmod_refclk_t ref_clk;
   2645     tbhmod_spd_intfc_type_t spd_intf = 0;
   2646 
   2647     PHYMOD_MEMSET(&firmware_lane_config, 0x0, sizeof(firmware_lane_config));
   2648 
   2649     PHYMOD_MEMSET(&an_control, 0x0, sizeof(an_control));
   2650     PHYMOD_IF_ERR_RETURN
   2651         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   2652 
   2653     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   2654     phy_copy.access.lane_mask = 0x1 << start_lane;
   2655 
   2656     if (an->enable) {
   2657         PHYMOD_IF_ERR_RETURN(tbhmod_disable_set(&phy_copy.access));
   2658         /* adjust FEC arch for RS544 */
   2659         if (PHYMOD_AN_F_FEC_RS272_CLR_GET(an)) {
   2660             PHYMOD_IF_ERR_RETURN(tbhmod_rsfec_cw_type(&phy_copy.access, 0, 0));
   2661         }
   2662 
   2663         /*next choose TVCO as the PLL selelction for all the lanes*/
   2664         for (i = 0; i < num_lane; i++) {
   2665             phy_copy.access.lane_mask = 1 << (start_lane + i);
   2666             PHYMOD_IF_ERR_RETURN
   2667                 (blackhawk_lane_pll_selection_set(&phy_copy.access, phy->access.tvco_pll_index));
   2668         }
   2669     }
   2670 
   2671     switch (an->num_lane_adv) {
   2672         case 1:
   2673             num_lane_adv_encoded = 0;
   2674             break;
   2675         case 2:
   2676             num_lane_adv_encoded = 1;
   2677             break;
   2678         case 4:
   2679             num_lane_adv_encoded = 2;
   2680             break;
   2681         case 8:
   2682             num_lane_adv_encoded = 3;
   2683             break;
   2684         default:
   2685             return PHYMOD_E_PARAM;
   2686     }
   2687 
   2688     an_control.num_lane_adv = num_lane_adv_encoded;
   2689     an_control.enable       = an->enable;
   2690     switch (an->an_mode) {
   2691         case phymod_AN_MODE_CL73:
   2692             an_control.an_type = TBHMOD_AN_MODE_CL73;
   2693             break;
   2694         case phymod_AN_MODE_CL73BAM:
   2695             an_control.an_type = TBHMOD_AN_MODE_CL73_BAM;
   2696             break;
   2697         case phymod_AN_MODE_CL73_MSA:
   2698             an_control.an_type = TBHMOD_AN_MODE_CL73_MSA;
   2699             break;
   2700         default:
   2701             return PHYMOD_E_PARAM;
   2702             break;
   2703     }
   2704 
   2705     /* SW WAR for 400G AN */
   2706     /* if AN is enabled, first needs to disable timer */
   2707     if (num_lane == 8) {
   2708         if (an->enable) {
   2709             PHYMOD_IF_ERR_RETURN
   2710                 (tbhmod_400g_autoneg_timer_disable(&phy_copy.access, 1));
   2711         } else {
   2712             PHYMOD_IF_ERR_RETURN
   2713                 (tbhmod_400g_autoneg_timer_disable(&phy_copy.access, 0));
   2714         }
   2715     }
   2716 
   2717     if (an->enable) {
   2718         /* Set AN port mode */
   2719         PHYMOD_IF_ERR_RETURN
   2720             (tbhmod_set_an_port_mode(&phy_copy.access, start_lane));
   2721 
   2722         /* Get TVCO rate (PLL1 for now) */
   2723         PHYMOD_IF_ERR_RETURN
   2724             (tbhmod_refclk_get(&phy_copy.access, &ref_clk));
   2725 
   2726         if (ref_clk == TBHMOD_REF_CLK_312P5MHZ) {
   2727             refclk_in_hz = 312500000;
   2728         } else {
   2729             refclk_in_hz = 156250000;
   2730         }
   2731 
   2732         /* next read current TVCO pll divider*/
   2733         phy_copy.access.pll_idx = phy->access.tvco_pll_index;
   2734         PHYMOD_IF_ERR_RETURN
   2735             (blackhawk_tsc_INTERNAL_read_pll_div(&phy_copy.access, &pll_1_div));
   2736 
   2737         PHYMOD_IF_ERR_RETURN
   2738             (blackhawk_tsc_get_vco_from_refclk_div(&phy_copy.access, refclk_in_hz, pll_1_div, &vco_rate, 0));
   2739 
   2740         if (vco_rate == 20625000) {
   2741             /* load 20G VCO spd_id */
   2742             spd_intf = TBHMOD_SPD_CL73_20G;
   2743         } else if (vco_rate == 25781250) {
   2744             /* load 25G VCO spd_id */
   2745             spd_intf = TBHMOD_SPD_CL73_25G;
   2746         } else if (vco_rate == 26562500) {
   2747             /* load 26G VCO spd_id */
   2748             spd_intf = TBHMOD_SPD_CL73_26G;
   2749         } else {
   2750             return PHYMOD_E_PARAM;
   2751         }
   2752 
   2753         PHYMOD_IF_ERR_RETURN
   2754             (tbhmod_get_mapped_speed(spd_intf, &mapped_speed_id));
   2755 
   2756         phy_copy.access.lane_mask = 0x1 << start_lane;
   2757 
   2758         /* Load 1G speed ID */
   2759         PHYMOD_IF_ERR_RETURN
   2760             (tbhmod_set_sc_speed(&phy_copy.access, mapped_speed_id, 0));
   2761     }
   2762 
   2763     do_lane_config_set = 0;
   2764     if (an->enable) {
   2765         /* make sure the firmware config is set to an enabled */
   2766         PHYMOD_IF_ERR_RETURN
   2767             (tscbh_phy_firmware_lane_config_get(&phy_copy, &firmware_lane_config));
   2768         /* make sure the firmware config is set to an enabled */
   2769         if (firmware_lane_config.AnEnabled != 1) {
   2770           firmware_lane_config.AnEnabled = 1;
   2771           do_lane_config_set = 1;
   2772         }
   2773         if (firmware_lane_config.LaneConfigFromPCS != 1) {
   2774           firmware_lane_config.LaneConfigFromPCS = 1;
   2775           do_lane_config_set = 1;
   2776         }
   2777         firmware_lane_config.Cl72RestTO = 0;
   2778         firmware_lane_config.ForceNormalReach = 0;
   2779         firmware_lane_config.ForceExtenedReach = 0;
   2780         firmware_lane_config.ForceNRZMode= 0;
   2781         firmware_lane_config.ForcePAM4Mode = 0;
   2782     }
   2783 
   2784     if (do_lane_config_set) {
   2785         for (i = 0; i < num_lane; i++) {
   2786             if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   2787                 continue;
   2788             }
   2789             phy_copy.access.lane_mask = 0x1 << (i + start_lane);
   2790             PHYMOD_IF_ERR_RETURN
   2791                 (blackhawk_lane_soft_reset(&phy_copy.access, 1));
   2792         }
   2793         PHYMOD_USLEEP(1000);
   2794         for (i = 0; i < num_lane; i++) {
   2795             if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   2796                 continue;
   2797             }
   2798             phy_copy.access.lane_mask = 0x1 << (i + start_lane);
   2799             PHYMOD_IF_ERR_RETURN
   2800                 (_tscbh_phy_firmware_lane_config_set(&phy_copy, firmware_lane_config));
   2801         }
   2802         for (i = 0; i < num_lane; i++) {
   2803             if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   2804                 continue;
   2805             }
   2806             phy_copy.access.lane_mask = 0x1 << (i + start_lane);
   2807             PHYMOD_IF_ERR_RETURN
   2808                 (blackhawk_lane_soft_reset(&phy_copy.access, 0));
   2809         }
   2810     }
   2811 
   2812     phy_copy.access.lane_mask = 0x1 << start_lane;
   2813 
   2814     PHYMOD_IF_ERR_RETURN
   2815         (tbhmod_autoneg_control(&phy_copy.access, &an_control));
   2816 /* for now comment out, need to revisit */
   2817 #if 0
   2818     if (!an->enable) {
   2819         tbhmod_enable_set(&phy_copy.access);
   2820     }
   2821 #endif
   2822 
   2823     return PHYMOD_E_NONE;
   2824 }
   2825 
   2826 int tscbh_phy_autoneg_get(const phymod_phy_access_t* phy, phymod_autoneg_control_t* an, uint32_t* an_done)
   2827 {
   2828     tbhmod_an_control_t an_control;
   2829     phymod_phy_access_t phy_copy;
   2830     int start_lane, num_lane;
   2831     int an_complete = 0;
   2832 
   2833     PHYMOD_IF_ERR_RETURN
   2834         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   2835 
   2836     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   2837     phy_copy.access.lane_mask = 0x1 << start_lane;
   2838 
   2839     PHYMOD_MEMSET(&an_control, 0x0,  sizeof(tbhmod_an_control_t));
   2840     PHYMOD_IF_ERR_RETURN
   2841         (tbhmod_autoneg_control_get(&phy_copy.access, &an_control, &an_complete));
   2842 
   2843     if (an_control.enable) {
   2844         an->enable = 1;
   2845         *an_done = an_complete;
   2846     } else {
   2847         an->enable = 0;
   2848     }
   2849 
   2850     switch (an_control.num_lane_adv) {
   2851         case 0:
   2852             an->num_lane_adv = 1;
   2853             break;
   2854         case 1:
   2855             an->num_lane_adv = 2;
   2856             break;
   2857         case 2:
   2858             an->num_lane_adv = 4;
   2859             break;
   2860         case 3:
   2861             an->num_lane_adv = 8;
   2862             break;
   2863         default:
   2864             an->num_lane_adv = 0;
   2865             break;
   2866     }
   2867 
   2868     switch (an_control.an_type) {
   2869         case TBHMOD_AN_MODE_CL73:
   2870             an->an_mode = phymod_AN_MODE_CL73;
   2871             break;
   2872         case TBHMOD_AN_MODE_CL73_BAM:
   2873             an->an_mode = phymod_AN_MODE_CL73BAM;
   2874             break;
   2875         case TBHMOD_AN_MODE_MSA:
   2876             an->an_mode = phymod_AN_MODE_MSA;
   2877             break;
   2878         case TBHMOD_AN_MODE_CL73_MSA:
   2879             an->an_mode = phymod_AN_MODE_CL73_MSA;
   2880             break;
   2881         default:
   2882             an->an_mode = phymod_AN_MODE_NONE;
   2883             break;
   2884     }
   2885 
   2886     return PHYMOD_E_NONE;
   2887 }
   2888 
   2889 int tscbh_phy_autoneg_status_get(const phymod_phy_access_t* phy, phymod_autoneg_status_t* status)
   2890 {
   2891     int an_en, an_done;
   2892     phymod_phy_speed_config_t speed_config;
   2893     phymod_phy_access_t phy_copy;
   2894     int start_lane, num_lane, speed_id;
   2895     uint32_t packed_entry[5];
   2896     spd_id_tbl_entry_t speed_config_entry;
   2897 
   2898     PHYMOD_IF_ERR_RETURN
   2899         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   2900 
   2901     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   2902     phy_copy.access.lane_mask = 0x1 << start_lane;
   2903 
   2904     PHYMOD_IF_ERR_RETURN
   2905        (tbhmod_autoneg_status_get(&phy_copy.access, &an_en, &an_done));
   2906 
   2907     PHYMOD_IF_ERR_RETURN
   2908        (tscbh_phy_speed_config_get(phy, &speed_config));
   2909 
   2910     if (an_en && an_done) {
   2911         uint32_t an_resolved_mode;
   2912         /* if an resolves and link up */
   2913         PHYMOD_IF_ERR_RETURN
   2914             (tbhmod_speed_id_get(&phy_copy.access, &speed_id));
   2915         /*read the speed id entry and get the num_lane info */
   2916         phy_copy.access.lane_mask = 1 << start_lane;
   2917         PHYMOD_IF_ERR_RETURN
   2918             (phymod_mem_read(&phy_copy.access, phymodMemSpeedIdTable, speed_id, packed_entry));
   2919         spd_ctrl_unpack_spd_id_tbl_entry(packed_entry, &speed_config_entry);
   2920         num_lane = 1 << speed_config_entry.num_lanes;
   2921         /* read the AN final resolved port mode */
   2922         PHYMOD_IF_ERR_RETURN
   2923             (tbhmod_resolved_port_mode_get(&phy_copy.access, &an_resolved_mode));
   2924         status->resolved_port_mode = an_resolved_mode;
   2925     }
   2926 
   2927     status->enabled   = an_en;
   2928     status->locked    = an_done;
   2929     status->data_rate = speed_config.data_rate;
   2930     status->resolved_num_lane = num_lane;
   2931 
   2932     return PHYMOD_E_NONE;
   2933 }
   2934 
   2935 int tscbh_phy_pll_reconfig(const phymod_phy_access_t* phy,
   2936                             uint8_t pll_index,
   2937                             uint32_t pll_div)
   2938 {
   2939     phymod_phy_access_t pm_phy_copy;
   2940     tbhmod_refclk_t ref_clk;
   2941     /*phymod_tscbh_pll_multiplier_t pll_0, pll_1; */
   2942     uint32_t tvco_rate = 0, speed_id_load_size, i, pll_is_pwrdn;
   2943     uint8_t tvco_pll_index, tvco_reconfig = 0;
   2944     enum blackhawk_tsc_pll_refclk_enum refclk;
   2945     uint32_t cnt = 0, pll_lock = 0;
   2946 
   2947     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
   2948     tvco_pll_index = phy->access.tvco_pll_index;
   2949 
   2950     if (pll_index > 1) {
   2951         PHYMOD_DEBUG_ERROR(("Unsupported PLL index\n"));
   2952         return PHYMOD_E_UNAVAIL;
   2953     }
   2954 
   2955     tvco_reconfig = (tvco_pll_index == pll_index) ? 1 : 0;
   2956 
   2957     pm_phy_copy.access.lane_mask = 1 << 0;
   2958     /* first needs to read the ref clock from main reg*/
   2959     PHYMOD_IF_ERR_RETURN
   2960         (tbhmod_refclk_get(&pm_phy_copy.access, &ref_clk));
   2961 
   2962     if (ref_clk == TBHMOD_REF_CLK_156P25MHZ) {
   2963         refclk = BLACKHAWK_TSC_PLL_REFCLK_156P25MHZ;
   2964     } else if (ref_clk == TBHMOD_REF_CLK_312P5MHZ) {
   2965         refclk = BLACKHAWK_TSC_PLL_REFCLK_312P5MHZ;
   2966     } else {
   2967         PHYMOD_DEBUG_ERROR(("Unsupported reference clock.\n"));
   2968         return PHYMOD_E_UNAVAIL;
   2969     }
   2970 
   2971     if (tvco_reconfig) {
   2972         PHYMOD_IF_ERR_RETURN
   2973             (tbhmod_pll_to_vco_get(ref_clk, pll_div, &tvco_rate));
   2974     }
   2975 
   2976     /* next disable pcs datapath only if TVCO re-config*/
   2977     if (tvco_reconfig) {
   2978         PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
   2979         PHYMOD_IF_ERR_RETURN
   2980             (tbhmod_disable_set(&pm_phy_copy.access));
   2981     }
   2982 
   2983     /*only need to load speed id table for tvco re-config */
   2984     /*then reload the speed id table based on the new tvco */
   2985     if (tvco_reconfig) {
   2986         speed_id_load_size = TSCBH_SPEED_ID_TABLE_SIZE > TSCBH_HW_SPEED_ID_TABLE_SIZE ? TSCBH_HW_SPEED_ID_TABLE_SIZE : TSCBH_SPEED_ID_TABLE_SIZE;
   2987         if (tvco_rate == TBHMOD_VCO_26G) {
   2988             for (i = 0; i < speed_id_load_size; i++) {
   2989                 PHYMOD_IF_ERR_RETURN
   2990                     (phymod_mem_write(&pm_phy_copy.access, phymodMemSpeedIdTable, i, &spd_id_entry_26[i][0]));
   2991             }
   2992         } else if (tvco_rate == TBHMOD_VCO_25G) {
   2993             for (i = 0; i < speed_id_load_size; i++) {
   2994                 PHYMOD_IF_ERR_RETURN
   2995                     (phymod_mem_write(&pm_phy_copy.access, phymodMemSpeedIdTable, i, &spd_id_entry_25[i][0]));
   2996             }
   2997         } else if (tvco_rate == TBHMOD_VCO_20G) {
   2998             for (i = 0; i < speed_id_load_size; i++) {
   2999                 PHYMOD_IF_ERR_RETURN
   3000                     (phymod_mem_write(&pm_phy_copy.access, phymodMemSpeedIdTable, i, &spd_id_entry_20[i][0]));
   3001             }
   3002         }
   3003     }
   3004 
   3005     /*next check if the PLL is power down or not */
   3006     pm_phy_copy.access.pll_idx = pll_index;
   3007     pm_phy_copy.access.lane_mask = 1 << 0;
   3008     PHYMOD_IF_ERR_RETURN
   3009         (blackhawk_tsc_pll_pwrdn_get(&pm_phy_copy.access, &pll_is_pwrdn));
   3010 
   3011     /* if PLL is power down, need to power up first */
   3012     if (pll_is_pwrdn) {
   3013         /* Power up ovco if it's power down */
   3014         PHYMOD_IF_ERR_RETURN
   3015             (blackhawk_tsc_core_pwrdn(&pm_phy_copy.access, PWR_ON));
   3016     }
   3017 
   3018     PHYMOD_IF_ERR_RETURN
   3019         (blackhawk_tsc_core_dp_reset(&pm_phy_copy.access, 1));
   3020 
   3021     /*next re-config pll divider */
   3022     PHYMOD_IF_ERR_RETURN
   3023         (blackhawk_tsc_configure_pll_refclk_div(&pm_phy_copy.access,
   3024                                                   refclk,
   3025                                                   pll_div));
   3026 
   3027     PHYMOD_IF_ERR_RETURN
   3028         (blackhawk_tsc_core_dp_reset(&pm_phy_copy.access, 0));
   3029 
   3030     /* need to wait for the PLL lock */
   3031     cnt = 0;
   3032     while (cnt < 500) {
   3033         PHYMOD_IF_ERR_RETURN(blackhawk_tsc_pll_lock_get(&pm_phy_copy.access, &pll_lock));
   3034         cnt = cnt + 1;
   3035         if(pll_lock) {
   3036             break;
   3037         } else {
   3038             if(cnt == 500) {
   3039                 PHYMOD_DEBUG_ERROR(("WARNING :: core 0x%x PLL Index %d is not locked within 5 milli second \n", pm_phy_copy.access.addr, pll_index));
   3040                 break;
   3041             }
   3042         }
   3043         PHYMOD_USLEEP(10);
   3044     }
   3045 
   3046     return PHYMOD_E_NONE;
   3047 }
   3048 
   3049 int tscbh_phy_tx_pam4_precoder_enable_set(const phymod_phy_access_t* phy, int enable)
   3050 {
   3051     phymod_phy_access_t phy_copy;
   3052     int start_lane, num_lane, i;
   3053     uint32_t lane_reset, pcs_lane_enable;
   3054 
   3055     PHYMOD_IF_ERR_RETURN
   3056         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   3057     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   3058 
   3059     /*first check if lane is in reset */
   3060     PHYMOD_IF_ERR_RETURN
   3061         (blackhawk_lane_soft_reset_get(&phy_copy.access, &lane_reset));
   3062 
   3063     /*next check if PCS lane is in reset */
   3064     PHYMOD_IF_ERR_RETURN
   3065         (tbhmod_enable_get(&phy_copy.access, &pcs_lane_enable));
   3066 
   3067     /* disable pcs lane if pcs lane not in rset */
   3068     if (pcs_lane_enable) {
   3069         phy_copy.access.lane_mask = 1 << start_lane;
   3070         PHYMOD_IF_ERR_RETURN
   3071             (tbhmod_disable_set(&phy_copy.access));
   3072     }
   3073 
   3074     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   3075     /* if lane is not in reset, then reset the lane first */
   3076     if (!lane_reset) {
   3077         PHYMOD_IF_ERR_RETURN
   3078             (blackhawk_lane_soft_reset(&phy_copy.access, 1));
   3079     }
   3080 
   3081     for (i = 0; i < num_lane; i++) {
   3082         if (!PHYMOD_LANEPBMP_MEMBER(phy->access.lane_mask, start_lane + i)) {
   3083             continue;
   3084         }
   3085         phy_copy.access.lane_mask = 1 << (start_lane + i);
   3086         PHYMOD_IF_ERR_RETURN
   3087             (blackhawk_tsc_tx_pam4_precoder_enable_set(&phy_copy.access, enable));
   3088     }
   3089 
   3090     /* release the ln dp reset */
   3091     if (!lane_reset) {
   3092         PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   3093         PHYMOD_IF_ERR_RETURN
   3094             (blackhawk_lane_soft_reset(&phy_copy.access, 0));
   3095     }
   3096 
   3097     /* re-enable pcs lane if pcs lane not in rset */
   3098     if (pcs_lane_enable) {
   3099         phy_copy.access.lane_mask = 1 << start_lane;
   3100         PHYMOD_IF_ERR_RETURN
   3101             (tbhmod_enable_set(&phy_copy.access));
   3102     }
   3103 
   3104     return PHYMOD_E_NONE;
   3105 }
   3106 
   3107 int tscbh_phy_tx_pam4_precoder_enable_get(const phymod_phy_access_t* phy, int *enable)
   3108 {
   3109     phymod_phy_access_t pm_phy_copy;
   3110 
   3111     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
   3112     PHYMOD_IF_ERR_RETURN
   3113         (blackhawk_tsc_tx_pam4_precoder_enable_get(&pm_phy_copy.access, enable));
   3114     return PHYMOD_E_NONE;
   3115 }
   3116 
   3117 /*Set/Get timesync enable*/
   3118 int tscbh_timesync_enable_set(const phymod_phy_access_t* phy, uint32_t flags, uint32_t enable)
   3119 {
   3120     phymod_phy_access_t phy_copy;
   3121     int start_lane, num_lane, is_sfd = 0;
   3122     uint32_t pcs_lane_enable;
   3123     uint32_t fclk_div_mode = 0;
   3124 
   3125     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   3126     PHYMOD_IF_ERR_RETURN
   3127         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   3128 
   3129     phy_copy.access.lane_mask = 0x1 << start_lane;
   3130 
   3131     /* RX timestamping control */
   3132     if (PHYMOD_TIMESYNC_ENABLE_F_RX_GET(flags)) {
   3133         PHYMOD_IF_ERR_RETURN
   3134             (tbhmod_pcs_rx_ts_en(&phy_copy.access, enable, is_sfd));
   3135     }
   3136 
   3137     /* Core related control:
   3138      *     1. Enable fclk on PMD, with default div_mode.
   3139      */
   3140     if (PHYMOD_TIMESYNC_ENABLE_F_CORE_GET(flags)) {
   3141         phy_copy.access.pll_idx = phy_copy.access.tvco_pll_index;
   3142         PHYMOD_IF_ERR_RETURN
   3143             (blackhawk_tsc_clk4sync_enable_set(&phy_copy.access, enable, fclk_div_mode));
   3144     }
   3145 
   3146     /* One-Step Timestamp Pipeline */
   3147     if (PHYMOD_TIMESYNC_ENABLE_F_ONE_STEP_PIPELINE_GET(flags)){
   3148         /* check if PCS lane is in reset */
   3149         PHYMOD_IF_ERR_RETURN
   3150             (tbhmod_enable_get(&phy_copy.access, &pcs_lane_enable));
   3151 
   3152         /* disable pcs lane if pcs lane not in rset */
   3153         if (pcs_lane_enable) {
   3154             PHYMOD_IF_ERR_RETURN
   3155                 (tbhmod_disable_set(&phy_copy.access));
   3156         }
   3157 
   3158         PHYMOD_IF_ERR_RETURN
   3159             (tbhmod_osts_pipeline(&phy_copy.access, enable));
   3160 
   3161         /* re-enable pcs lane if pcs lane not in rset */
   3162         if (pcs_lane_enable) {
   3163             PHYMOD_IF_ERR_RETURN
   3164                 (tbhmod_enable_set(&phy_copy.access));
   3165         }
   3166     }
   3167 
   3168     return PHYMOD_E_NONE;
   3169 }
   3170 
   3171 /* Only one flag can be served each time.
   3172  */
   3173 int tscbh_timesync_enable_get(const phymod_phy_access_t* phy, uint32_t flags, uint32_t* enable)
   3174 {
   3175     phymod_phy_access_t phy_copy;
   3176     uint32_t fclk_div_mode;
   3177 
   3178     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   3179 
   3180     if (PHYMOD_TIMESYNC_ENABLE_F_RX_GET(flags)) {
   3181         PHYMOD_IF_ERR_RETURN
   3182             (tbhmod_pcs_rx_ts_en_get(&phy_copy.access, enable));
   3183     }
   3184 
   3185     if (PHYMOD_TIMESYNC_ENABLE_F_ONE_STEP_PIPELINE_GET(flags)){
   3186         PHYMOD_IF_ERR_RETURN
   3187             (tbhmod_osts_pipeline_get(&phy_copy.access, enable));
   3188     }
   3189 
   3190     if (PHYMOD_TIMESYNC_ENABLE_F_CORE_GET(flags)) {
   3191         phy_copy.access.pll_idx = phy_copy.access.tvco_pll_index;
   3192         PHYMOD_IF_ERR_RETURN
   3193             (blackhawk_tsc_clk4sync_enable_get(&phy_copy.access, enable, &fclk_div_mode));
   3194     }
   3195 
   3196     return PHYMOD_E_NONE;
   3197 }
   3198 
   3199 /*Set timesync adjust*/
   3200 int tscbh_timesync_adjust_set(const phymod_phy_access_t* phy, uint32_t ts_am_norm_mode)
   3201 {
   3202     int start_lane, num_lane, i, is_pam4, is_valid = 0;
   3203     uint8_t fec_arch;
   3204     int speed_id, mapped_speed_id;
   3205     int an_en, an_done;
   3206     phymod_phy_access_t phy_copy;
   3207     spd_id_tbl_entry_t speed_config_entry;
   3208     uint32_t packed_entry[5];
   3209     phymod_phy_speed_config_t speed_config;
   3210     phymod_firmware_lane_config_t firmware_lane_config;
   3211     tbhmod_spd_intfc_type_t spd_intf = 0;
   3212     phymod_mem_type_t tx_mem,rx_mem;
   3213     int ts_table_index;
   3214     int osr_mode;
   3215     ts_table_entry *ts_tx_entry = NULL, *ts_rx_entry = NULL;
   3216     ts_table_entry ts_update_table;
   3217     uint32_t psll_entry[TBHMOD_TS_TABLE_SIZE * TBHMOD_TS_PSLL_BASED_ENTRY_SIZE];
   3218     uint32_t psll_entry_size;
   3219     uint32_t pll_div, pll_index;
   3220     tbhmod_refclk_t ref_clk;
   3221     uint32_t tvco, current_vco;
   3222     int mem_offset;
   3223 
   3224     if (ts_am_norm_mode == 0x2) {
   3225         PHYMOD_DEBUG_ERROR(("TSCBH does not supported Latestlane Mode.\n"));
   3226         return PHYMOD_E_UNAVAIL;
   3227     }
   3228 
   3229     /* Here starts the sequence to enable Timestamping based on the current speed config */
   3230     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   3231     PHYMOD_IF_ERR_RETURN
   3232         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   3233     PHYMOD_IF_ERR_RETURN
   3234        (tbhmod_autoneg_status_get(&phy_copy.access, &an_en, &an_done));
   3235     PHYMOD_IF_ERR_RETURN
   3236        (tscbh_phy_firmware_lane_config_get(phy, &firmware_lane_config));
   3237 
   3238     is_pam4 = firmware_lane_config.ForcePAM4Mode;
   3239     psll_entry_size = TBHMOD_TS_TABLE_SIZE * TBHMOD_TS_PSLL_BASED_ENTRY_SIZE;
   3240     if (start_lane < 4) {
   3241         /* MPP0 */
   3242         mem_offset = start_lane * TBHMOD_TS_TABLE_SIZE;
   3243     } else {
   3244         /* MPP1 */
   3245         mem_offset = (start_lane - 4) * TBHMOD_TS_TABLE_SIZE;
   3246     }
   3247 
   3248     /* 1. Find default 1588 Table */
   3249 
   3250     /* 1.1 Get current speed id */
   3251     PHYMOD_IF_ERR_RETURN
   3252         (tbhmod_speed_id_get(&phy_copy.access, &speed_id));
   3253 
   3254     PHYMOD_IF_ERR_RETURN
   3255         (phymod_mem_read(&phy_copy.access, phymodMemSpeedIdTable, speed_id, packed_entry));
   3256     spd_ctrl_unpack_spd_id_tbl_entry(packed_entry, &speed_config_entry);
   3257     /* 1.2 Update num_lane and lane_mask for AN port */
   3258     if (an_en && an_done) {
   3259         num_lane = 1 << speed_config_entry.num_lanes;
   3260         /* Update lane_mask */
   3261         phy_copy.access.lane_mask = 0x0;
   3262         for (i = 0; i < num_lane; i++) {
   3263             phy_copy.access.lane_mask |= 0x1 << (i + start_lane);
   3264         }
   3265     }
   3266     /* 1.3 Get FEC type */
   3267     PHYMOD_IF_ERR_RETURN
   3268         (_tscbh_speed_id_to_speed_config_get(phy, speed_id, num_lane, &speed_config));
   3269 
   3270     if (an_en && an_done) {
   3271         PHYMOD_IF_ERR_RETURN
   3272             (tbhmod_autoneg_fec_status_get(&phy_copy.access, &fec_arch));
   3273         PHYMOD_IF_ERR_RETURN
   3274             (tbhmod_fec_arch_decode_get(fec_arch, &(speed_config.fec_type)));
   3275     }
   3276 
   3277     /* 10G-CL74 does not support 1588 */
   3278     if ((speed_config.data_rate == 10000) && (speed_config.fec_type == phymod_fec_CL74)) {
   3279         PHYMOD_DEBUG_ERROR(("1588 is not supported in current speed config.\n"));
   3280         return PHYMOD_E_UNAVAIL;
   3281     }
   3282 
   3283     /* 1.4 Get mapped speed id */
   3284     if (speed_id <= 0x25) {
   3285         /* AN speed IDs */
   3286         mapped_speed_id = speed_id;
   3287     } else {
   3288         /* Customized speed ID, need extra mapping. */
   3289         /* Only applys to FS */
   3290         PHYMOD_IF_ERR_RETURN(_tscbh_phy_speed_id_set(num_lane, speed_config.data_rate,
   3291                                                      speed_config.fec_type, &spd_intf));
   3292         PHYMOD_IF_ERR_RETURN
   3293             (tbhmod_get_mapped_speed(spd_intf, &mapped_speed_id));
   3294     }
   3295 
   3296     /* 1.5 Get the table index of the 1588 table */
   3297     PHYMOD_IF_ERR_RETURN
   3298        (tbhmod_1588_table_index_get(mapped_speed_id, speed_config.fec_type, &ts_table_index));
   3299 
   3300     if (ts_table_index == -1) {
   3301         PHYMOD_DEBUG_ERROR(("1588 is not supported in current speed config.\n"));
   3302         return PHYMOD_E_UNAVAIL;
   3303     }
   3304 
   3305     /* 1.6 Find the 1588 table */
   3306     ts_tx_entry = (ts_table_entry*) &(ts_table_tx_sop[ts_table_index]);
   3307     ts_rx_entry = (ts_table_entry*) &(ts_table_rx_sop[ts_table_index]);
   3308 
   3309     if (num_lane == 8) {
   3310         tx_mem = phymodMemTxLkup1588400G;
   3311         rx_mem = phymodMemRxLkup1588400G;
   3312     } else if (start_lane < 4) {
   3313         tx_mem = phymodMemTxLkup1588Mpp0;
   3314         rx_mem = phymodMemRxLkup1588Mpp0;
   3315     } else {
   3316         tx_mem = phymodMemTxLkup1588Mpp1;
   3317         rx_mem = phymodMemRxLkup1588Mpp1;
   3318     }
   3319     /* Get OS mode */
   3320     PHYMOD_IF_ERR_RETURN
   3321         (blackhawk_osr_mode_get(&phy_copy.access, &osr_mode));
   3322 
   3323     PHYMOD_IF_ERR_RETURN
   3324         (tbhmod_refclk_get(&phy_copy.access, &ref_clk));
   3325 
   3326     /* Get current used VCO */
   3327      PHYMOD_IF_ERR_RETURN
   3328         (blackhawk_lane_pll_selection_get(&phy_copy.access, &pll_index));
   3329     phy_copy.access.pll_idx = pll_index;
   3330     PHYMOD_IF_ERR_RETURN
   3331         (blackhawk_tsc_INTERNAL_read_pll_div(&phy_copy.access, &pll_div));
   3332     PHYMOD_IF_ERR_RETURN
   3333         (tbhmod_pll_to_vco_get(ref_clk, pll_div, &current_vco));
   3334     /* Get TVCO */
   3335     phy_copy.access.pll_idx = phy_copy.access.tvco_pll_index;
   3336     PHYMOD_IF_ERR_RETURN
   3337         (blackhawk_tsc_INTERNAL_read_pll_div(&phy_copy.access, &pll_div));
   3338     PHYMOD_IF_ERR_RETURN
   3339         (tbhmod_pll_to_vco_get(ref_clk, pll_div, &tvco));
   3340 
   3341     /* 2. Program UI */
   3342     
   3343     PHYMOD_IF_ERR_RETURN
   3344         (tbhmod_pcs_set_1588_ui(&phy_copy.access, current_vco, tvco, osr_mode, 0, is_pam4));
   3345 
   3346     /* 3. Program PMD lantency */
   3347     PHYMOD_IF_ERR_RETURN
   3348         (tbhmod_1588_pmd_latency(&phy_copy.access, current_vco, osr_mode, is_pam4));
   3349 
   3350     /* 4. Enable rx deskew
   3351      *    Need low to high transition to trigger HW recording the current status.
   3352     */
   3353     if (ts_am_norm_mode == 0x1) {
   3354         PHYMOD_IF_ERR_RETURN
   3355             (tbhmod_pcs_rx_deskew_en(&phy_copy.access, 0));
   3356         PHYMOD_USLEEP(10);
   3357         PHYMOD_IF_ERR_RETURN
   3358             (tbhmod_pcs_rx_deskew_en(&phy_copy.access, 1));
   3359     }
   3360 
   3361     /* 5. Load 1588 TX table */
   3362     /* Different MPPs have different memory space.
   3363      * Different logical ports have different memory offset.
   3364      */
   3365     for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3366         PHYMOD_IF_ERR_RETURN
   3367             (phymod_mem_write(&phy_copy.access, tx_mem, (i + mem_offset), &(*ts_tx_entry)[i][0]));
   3368     }
   3369 
   3370     /* 6. Load 1588 RX table */
   3371     if (ts_am_norm_mode == 0x1) {
   3372         /* RX tbl need to update deskew before writing to mem */
   3373         /* 6.1 Check for deskew valid */
   3374         for (i = 0; i < 1000; i++) {
   3375             PHYMOD_USLEEP(10);
   3376             PHYMOD_IF_ERR_RETURN
   3377                 (tbhmod_pcs_ts_deskew_valid(&phy_copy.access, speed_config_entry.bit_mux_mode, &is_valid));
   3378             if (is_valid) {
   3379                 break;
   3380             }
   3381         }
   3382         if (!is_valid) {
   3383             return PHYMOD_E_TIMEOUT;
   3384         }
   3385 
   3386         /* 6.2 Update deskew to 1588 table */
   3387         /* 6.2.1 Translate RX table to psuedo logical lane(PSLL) based array */
   3388         for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3389             PHYMOD_IF_ERR_RETURN
   3390                 (tbhmod_tbl_entry_to_psll_entry_map(&(*ts_rx_entry)[i][0], &psll_entry[i * TBHMOD_TS_PSLL_BASED_ENTRY_SIZE]));
   3391         }
   3392 
   3393         /* 6.2.2 Calculate deskew and update time value for each PSLL */
   3394         PHYMOD_IF_ERR_RETURN
   3395             (tbhmod_pcs_mod_rx_1588_tbl_val(&phy_copy.access, speed_config_entry.bit_mux_mode,
   3396                                             current_vco, osr_mode, is_pam4, psll_entry_size, psll_entry));
   3397 
   3398         /* 6.2.3 Translate PSLL based array back to 1588 entry format */
   3399         for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3400             PHYMOD_IF_ERR_RETURN
   3401                 (tbhmod_psll_entry_to_tbl_entry_map(&psll_entry[i * TBHMOD_TS_PSLL_BASED_ENTRY_SIZE], &ts_update_table[i][0]));
   3402         }
   3403 
   3404         /* 6.3 Write the updated RX table to memroy */
   3405         for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3406             PHYMOD_IF_ERR_RETURN
   3407                 (phymod_mem_write(&phy_copy.access, rx_mem, (i + mem_offset), &ts_update_table[i][0]));
   3408         }
   3409     } else {
   3410         /* If deskew update is not required, load default tables */
   3411         for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3412             PHYMOD_IF_ERR_RETURN
   3413                 (phymod_mem_write(&phy_copy.access, rx_mem, (i + mem_offset), &(*ts_rx_entry)[i][0]));
   3414         }
   3415     }
   3416 
   3417     /* 7. Enable SFD/SOP timestamping on tx and rx */
   3418     /* In Gen1, only applys to 10G, 20G and 25G. */
   3419     PHYMOD_IF_ERR_RETURN
   3420         (tbhmod_pcs_set_1588_xgmii(&phy_copy.access, 0, current_vco, osr_mode));
   3421 
   3422     return PHYMOD_E_NONE;
   3423 }
   3424 
   3425 
   3426 int _tscbh_flexport_sw_workaround(const phymod_phy_access_t* phy)
   3427 {
   3428     phymod_phy_access_t phy_copy;
   3429     int start_lane, num_lane, mapped_speed_id;
   3430     uint32_t pll_div, pll_index;
   3431     uint32_t packed_entry[5];
   3432     tbhmod_spd_intfc_type_t spd_intf = 0;
   3433 
   3434     PHYMOD_IF_ERR_RETURN
   3435         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   3436     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   3437     /* enable PMD lane override */
   3438     phy_copy.access.lane_mask = 1 << start_lane;
   3439 
   3440     /* Hold the pcs lane reset */
   3441     PHYMOD_IF_ERR_RETURN
   3442         (tbhmod_disable_set(&phy_copy.access));
   3443 
   3444     /* get PLL index */
   3445     PHYMOD_IF_ERR_RETURN
   3446         (blackhawk_lane_pll_selection_get(&phy_copy.access, &pll_index));
   3447 
   3448     /* get the PLL div */
   3449     phy_copy.access.lane_mask = 0x1;
   3450     phy_copy.access.pll_idx = pll_index;
   3451     PHYMOD_IF_ERR_RETURN
   3452         (blackhawk_tsc_INTERNAL_read_pll_div(&phy_copy.access, &pll_div));
   3453 
   3454     /* for 26G VCO, use speed id 5
   3455        for 25G vco, use speed id 2
   3456        for 20G vco, use speed id 0 */
   3457     if ((pll_div == TBHMOD_PLL_MODE_DIV_170) || (pll_div == TBHMOD_PLL_MODE_DIV_85))  {
   3458         spd_intf = TBHMOD_SPD_50G_IEEE_KR1_CR1;
   3459     } else if ((pll_div == TBHMOD_PLL_MODE_DIV_165) || (pll_div == TBHMOD_PLL_MODE_DIV_82P5)) {
   3460         spd_intf = TBHMOD_SPD_25000_XFI;
   3461     } else {
   3462         spd_intf = TBHMOD_SPD_10000_XFI;
   3463     }
   3464 
   3465     PHYMOD_IF_ERR_RETURN
   3466         (tbhmod_get_mapped_speed(spd_intf, &mapped_speed_id));
   3467 
   3468     /*next read the speed id entry and then copy to the right forced speed */
   3469     phy_copy.access.lane_mask = 1 << 0;
   3470     PHYMOD_IF_ERR_RETURN
   3471         (phymod_mem_read(&phy_copy.access, phymodMemSpeedIdTable, mapped_speed_id, packed_entry));
   3472     PHYMOD_IF_ERR_RETURN
   3473         (phymod_mem_write(&phy_copy.access, phymodMemSpeedIdTable, TSCBH_FORCED_SPEED_ID_OFFSET + start_lane, packed_entry));
   3474 
   3475     /* next update the port_mode */
   3476     phy_copy.access.lane_mask = 1 << start_lane;
   3477     PHYMOD_IF_ERR_RETURN
   3478         (tbhmod_update_port_mode(&phy_copy.access));
   3479 
   3480     /* add rx lock override */
   3481     PHYMOD_IF_ERR_RETURN
   3482         (tbhmod_pmd_rx_lock_override_enable(&phy_copy.access, 1));
   3483     /* clear state machine state */
   3484     PHYMOD_IF_ERR_RETURN
   3485         (tbhmod_read_sc_fsm_status(&phy_copy.access));
   3486     PHYMOD_IF_ERR_RETURN
   3487         (tbhmod_read_sc_done(&phy_copy.access));
   3488     PHYMOD_IF_ERR_RETURN
   3489         (tbhmod_enable_set(&phy_copy.access));
   3490     PHYMOD_IF_ERR_RETURN
   3491         (tbhmod_polling_for_sc_done(&phy_copy.access));
   3492     /* disable pcs again */
   3493     PHYMOD_IF_ERR_RETURN
   3494         (tbhmod_disable_set(&phy_copy.access));
   3495     PHYMOD_USLEEP(10000);
   3496     /* disable rx lock override */
   3497     PHYMOD_IF_ERR_RETURN
   3498         (tbhmod_pmd_rx_lock_override_enable(&phy_copy.access, 0));
   3499 
   3500     return PHYMOD_E_NONE;
   3501 }
   3502 
   3503 int tscbh_phy_pcs_enable_set(const phymod_phy_access_t* phy, uint32_t enable)
   3504 {
   3505     phymod_phy_access_t phy_copy;
   3506     int start_lane, num_lane;
   3507 
   3508     PHYMOD_IF_ERR_RETURN
   3509         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   3510     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   3511 
   3512     if (enable == 1) {
   3513         phy_copy.access.lane_mask = 1 << start_lane;
   3514         PHYMOD_IF_ERR_RETURN
   3515             (tbhmod_enable_set(&phy_copy.access));
   3516     } else if (enable == 0) {
   3517         PHYMOD_IF_ERR_RETURN
   3518             (tbhmod_disable_set(&phy_copy.access));
   3519     } else {
   3520         /* this is the SW WAR for the 16nm flexport HW issue */
   3521         PHYMOD_IF_ERR_RETURN
   3522             (_tscbh_flexport_sw_workaround(phy));
   3523     }
   3524 
   3525     return PHYMOD_E_NONE;
   3526 }
   3527 
   3528 int tscbh_phy_synce_clk_ctrl_set(const phymod_phy_access_t* phy,
   3529                                  phymod_synce_clk_ctrl_t cfg)
   3530 {
   3531     phymod_phy_access_t phy_copy;
   3532     uint32_t current_pll_index, pll_div, sdm_val;
   3533     int osr_mode;
   3534 
   3535     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   3536 
   3537     PHYMOD_IF_ERR_RETURN
   3538          (tbhmod_synce_mode_set(&phy_copy.access, cfg.stg0_mode, cfg.stg1_mode));
   3539 
   3540     /* next check if SDM mode, if yes, needs to figure out the SDM value based on the current */
   3541     if ((cfg.stg0_mode == 0x2) && (cfg.stg1_mode == 0x0)) {
   3542         /* vco the port is using */
   3543         /* first get the PLL index */
   3544         PHYMOD_IF_ERR_RETURN
   3545             (blackhawk_lane_pll_selection_get(&phy_copy.access, &current_pll_index));
   3546 
   3547         /* next get the OSR the port is current using */
   3548         PHYMOD_IF_ERR_RETURN
   3549             (blackhawk_osr_mode_get(&phy_copy.access, &osr_mode));
   3550 
   3551         /* next get the VCO the port is current using */
   3552         phy_copy.access.pll_idx = current_pll_index;
   3553         phy_copy.access.lane_mask = 0x1;
   3554         PHYMOD_IF_ERR_RETURN
   3555             (blackhawk_tsc_INTERNAL_read_pll_div(&phy_copy.access, &pll_div));
   3556 
   3557         /* next based on the VCO value and osr mode, set the SDM value properly */
   3558         /* first check 26G VCO */
   3559         if ((pll_div == TBHMOD_PLL_MODE_DIV_170) || (pll_div == TBHMOD_PLL_MODE_DIV_85))  {
   3560             sdm_val = TSCBH_SYNCE_SDM_DIVISOR_26G_VCO;
   3561         } else if ((pll_div == TBHMOD_PLL_MODE_DIV_165) || (pll_div == TBHMOD_PLL_MODE_DIV_82P5)) {
   3562             sdm_val = TSCBH_SYNCE_SDM_DIVISOR_25GP78125_VCO;
   3563         } else if ((pll_div == TBHMOD_PLL_MODE_DIV_132) || (pll_div == TBHMOD_PLL_MODE_DIV_66)) {
   3564             sdm_val = TSCBH_SYNCE_SDM_DIVISOR_20G_VCO;
   3565         } else if ((pll_div == TBHMOD_PLL_MODE_DIV_160) || (pll_div == TBHMOD_PLL_MODE_DIV_80)) {
   3566             sdm_val = TSCBH_SYNCE_SDM_DIVISOR_25G_VCO;
   3567         } else {
   3568             PHYMOD_DEBUG_ERROR(("Unsupported VCOs\n"));
   3569             return PHYMOD_E_UNAVAIL;
   3570         }
   3571 
   3572         /* need to adjust the SDM value based on OSR mode */
   3573         if (osr_mode == 1) {
   3574             sdm_val >>= 1;
   3575         }
   3576 
   3577         /* next configure the SDM value */
   3578         PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   3579         PHYMOD_IF_ERR_RETURN
   3580             (tbhmod_synce_clk_ctrl_set(&phy_copy.access, sdm_val));
   3581     }
   3582 
   3583     return PHYMOD_E_NONE;
   3584 }
   3585 
   3586 int tscbh_phy_synce_clk_ctrl_get(const phymod_phy_access_t* phy,
   3587                                  phymod_synce_clk_ctrl_t *cfg)
   3588 {
   3589     phymod_phy_access_t phy_copy;
   3590 
   3591     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   3592 
   3593     PHYMOD_IF_ERR_RETURN
   3594         (tbhmod_synce_mode_get(&phy_copy.access, &(cfg->stg0_mode), &(cfg->stg1_mode)));
   3595 
   3596     PHYMOD_IF_ERR_RETURN
   3597         (tbhmod_synce_clk_ctrl_get(&phy_copy.access, &(cfg->sdm_val)));
   3598 
   3599     return PHYMOD_E_NONE;
   3600 }
   3601 
   3602 int tscbh_phy_rx_ppm_get(const phymod_phy_access_t* phy, int16_t* rx_ppm)
   3603 {
   3604     int start_lane, num_lane;
   3605     phymod_phy_access_t pm_phy_copy;
   3606 
   3607     PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy));
   3608 
   3609     PHYMOD_IF_ERR_RETURN
   3610         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   3611 
   3612     pm_phy_copy.access.lane_mask = 1 << start_lane;
   3613     PHYMOD_IF_ERR_RETURN
   3614         (blackhawk_tsc_rx_ppm(&pm_phy_copy.access, rx_ppm));
   3615     return PHYMOD_E_NONE;
   3616 }
   3617 
   3618 /* This function will handle PCS ECC interrupts.
   3619  * 1. Clear interrupt status.
   3620  * 2. Re-load the config table if error is in UM, AM table.
   3621  * 3. Re-load the 1588 tables and SPEED_ID table for 1b error.
   3622  * 4. Return is_handled = 0 if 2b-error happens and Phymod can not recover.
   3623  */
   3624 int tscbh_intr_handler(const phymod_phy_access_t* phy,
   3625                        phymod_interrupt_type_t type,
   3626                        uint32_t* is_handled)
   3627 {
   3628     phymod_phy_access_t phy_copy;
   3629     tbhmod_intr_status_t intr_status;
   3630     uint32_t am_table_load_size, um_table_load_size;
   3631     uint32_t speed_id_table[TSCBH_HW_SPEED_ID_TABLE_SIZE][TSCBH_SPEED_ID_ENTRY_SIZE];
   3632     int i, j, mem_offset;
   3633     ts_table_entry ts_table;
   3634 
   3635     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   3636     intr_status.type = type;
   3637 
   3638     /* Get and clear interrupt status */
   3639     PHYMOD_IF_ERR_RETURN
   3640         (tbhmod_intr_status_get(&phy_copy.access, &intr_status));
   3641 
   3642     phy_copy.access.lane_mask = 0x1;
   3643 
   3644     if (intr_status.is_2b_err) {
   3645         *is_handled = 0;
   3646     } else {
   3647         *is_handled = 1;
   3648     }
   3649 
   3650     switch (type) {
   3651         case phymodIntrEccAMTable:
   3652             *is_handled = 1;
   3653             /* Reload AM table */
   3654             am_table_load_size = TSCBH_AM_TABLE_SIZE > TSCBH_HW_AM_TABLE_SIZE ? TSCBH_HW_AM_TABLE_SIZE : TSCBH_AM_TABLE_SIZE;
   3655             for (i = 0; i < am_table_load_size; i++) {
   3656                 PHYMOD_IF_ERR_RETURN
   3657                     (phymod_mem_write(&phy_copy.access, phymodMemAMTable, i,  &am_table_entry[i][0]));
   3658             }
   3659             break;
   3660         case phymodIntrEccSpeedTable:
   3661             if (intr_status.is_1b_err) {
   3662                 for (i = 0; i < TSCBH_HW_SPEED_ID_TABLE_SIZE; i++) {
   3663                     PHYMOD_IF_ERR_RETURN
   3664                         (phymod_mem_read(&phy_copy.access, phymodMemSpeedIdTable, i, &speed_id_table[i][0]));
   3665                 }
   3666                 for (i = 0; i < TSCBH_HW_SPEED_ID_TABLE_SIZE; i++) {
   3667                     PHYMOD_IF_ERR_RETURN
   3668                         (phymod_mem_write(&phy_copy.access, phymodMemSpeedIdTable, i, &speed_id_table[i][0]));
   3669                 }
   3670             }
   3671             break;
   3672         case phymodIntrEccUMTable:
   3673             *is_handled = 1;
   3674             /* Reload UM table */
   3675             um_table_load_size = TSCBH_UM_TABLE_SIZE > TSCBH_HW_UM_TABLE_SIZE ? TSCBH_HW_UM_TABLE_SIZE : TSCBH_UM_TABLE_SIZE;
   3676             for (i = 0; i < um_table_load_size; i++) {
   3677                 PHYMOD_IF_ERR_RETURN
   3678                     (phymod_mem_write(&phy_copy.access, phymodMemUMTable, i,  &um_table_entry[i][0]));
   3679             }
   3680             break;
   3681         case phymodIntrEccRx1588400g:
   3682             if (intr_status.is_1b_err) {
   3683                 for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3684                     PHYMOD_IF_ERR_RETURN
   3685                         (phymod_mem_read(&phy_copy.access, phymodMemRxLkup1588400G, i, &ts_table[i][0]));
   3686                 }
   3687                 for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3688                     PHYMOD_IF_ERR_RETURN
   3689                         (phymod_mem_write(&phy_copy.access, phymodMemRxLkup1588400G, i, &ts_table[i][0]));
   3690                 }
   3691             }
   3692             break;
   3693         case phymodIntrEccRx1588Mpp1:
   3694              if (intr_status.is_1b_err) {
   3695                 for (j = 0; j < TBHMOD_TS_MPP_MEM_TABLE_CNT; j++) {
   3696                     mem_offset = j * TBHMOD_TS_TABLE_SIZE;
   3697                     for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3698                         PHYMOD_IF_ERR_RETURN
   3699                             (phymod_mem_read(&phy_copy.access, phymodMemRxLkup1588Mpp1,
   3700                                              i + mem_offset, &ts_table[i][0]));
   3701                     }
   3702                     for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3703                         PHYMOD_IF_ERR_RETURN
   3704                             (phymod_mem_write(&phy_copy.access, phymodMemRxLkup1588Mpp1,
   3705                                               i + mem_offset, &ts_table[i][0]));
   3706                     }
   3707                 }
   3708             }
   3709             break;
   3710         case phymodIntrEccRx1588Mpp0:
   3711             if (intr_status.is_1b_err) {
   3712                 for (j = 0; j < TBHMOD_TS_MPP_MEM_TABLE_CNT; j++) {
   3713                     mem_offset = j * TBHMOD_TS_TABLE_SIZE;
   3714                     for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3715                         PHYMOD_IF_ERR_RETURN
   3716                             (phymod_mem_read(&phy_copy.access, phymodMemRxLkup1588Mpp0,
   3717                                              i + mem_offset, &ts_table[i][0]));
   3718                     }
   3719                     for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3720                         PHYMOD_IF_ERR_RETURN
   3721                             (phymod_mem_write(&phy_copy.access, phymodMemRxLkup1588Mpp0,
   3722                                               i + mem_offset, &ts_table[i][0]));
   3723                     }
   3724                 }
   3725             }
   3726             break;
   3727         case phymodIntrEccTx1588400g:
   3728             if (intr_status.is_1b_err) {
   3729                 for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3730                     PHYMOD_IF_ERR_RETURN
   3731                         (phymod_mem_read(&phy_copy.access, phymodMemTxLkup1588400G, i, &ts_table[i][0]));
   3732                 }
   3733                 for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3734                     PHYMOD_IF_ERR_RETURN
   3735                         (phymod_mem_write(&phy_copy.access, phymodMemTxLkup1588400G, i, &ts_table[i][0]));
   3736                 }
   3737             }
   3738             break;
   3739         case phymodIntrEccTx1588Mpp1:
   3740             if (intr_status.is_1b_err) {
   3741                 for (j = 0; j < TBHMOD_TS_MPP_MEM_TABLE_CNT; j++) {
   3742                     mem_offset = j * TBHMOD_TS_TABLE_SIZE;
   3743                     for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3744                         PHYMOD_IF_ERR_RETURN
   3745                             (phymod_mem_read(&phy_copy.access, phymodMemTxLkup1588Mpp1,
   3746                                              i + mem_offset, &ts_table[i][0]));
   3747                     }
   3748                     for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3749                         PHYMOD_IF_ERR_RETURN
   3750                             (phymod_mem_write(&phy_copy.access, phymodMemTxLkup1588Mpp1,
   3751                                               i + mem_offset, &ts_table[i][0]));
   3752                     }
   3753                 }
   3754             }
   3755             break;
   3756         case phymodIntrEccTx1588Mpp0:
   3757             if (intr_status.is_1b_err) {
   3758                 for (j = 0; j < TBHMOD_TS_MPP_MEM_TABLE_CNT; j++) {
   3759                     mem_offset = j * TBHMOD_TS_TABLE_SIZE;
   3760                     for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3761                         PHYMOD_IF_ERR_RETURN
   3762                             (phymod_mem_read(&phy_copy.access, phymodMemTxLkup1588Mpp0,
   3763                                              i + mem_offset, &ts_table[i][0]));
   3764                     }
   3765                     for (i = 0; i < TBHMOD_TS_TABLE_SIZE; i++) {
   3766                         PHYMOD_IF_ERR_RETURN
   3767                             (phymod_mem_write(&phy_copy.access, phymodMemTxLkup1588Mpp0,
   3768                                               i + mem_offset, &ts_table[i][0]));
   3769                     }
   3770                 }
   3771             }
   3772             break;
   3773         default:
   3774             break;
   3775     }
   3776 
   3777     return PHYMOD_E_NONE;
   3778 }
   3779 
   3780 int tscbh_timesync_tx_info_get(const phymod_phy_access_t* phy, phymod_ts_fifo_status_t* ts_tx_info)
   3781 {
   3782     phymod_phy_access_t phy_copy;
   3783     tbhmod_ts_tx_info_t local_ts_tx_info;
   3784 
   3785     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   3786     PHYMOD_MEMSET(&local_ts_tx_info, 0, sizeof(tbhmod_ts_tx_info_t));
   3787 
   3788     PHYMOD_IF_ERR_RETURN(tbhmod_1588_tx_info_get(&phy_copy.access, &local_ts_tx_info));
   3789 
   3790     ts_tx_info->ts_in_fifo_lo = ((uint32_t)(local_ts_tx_info.ts_val_mid << 16)) | ((uint32_t)local_ts_tx_info.ts_val_lo);
   3791     ts_tx_info->ts_in_fifo_hi = (uint32_t)local_ts_tx_info.ts_val_hi;
   3792     ts_tx_info->ts_seq_id = (uint32_t)local_ts_tx_info.ts_seq_id;
   3793     ts_tx_info->ts_sub_nanosec = (uint32_t)local_ts_tx_info.ts_sub_nanosec;
   3794 
   3795     return PHYMOD_E_NONE;
   3796 }
   3797 
   3798 int tscbh_phy_pcs_lane_swap_adjust(const phymod_phy_access_t* phy, uint32_t active_lane_map, uint32_t original_tx_lane_map, uint32_t original_rx_lane_map)
   3799 {
   3800     phymod_phy_access_t phy_copy;
   3801     int start_lane, num_lane, i, disable_lane[2]= {0,0}, disable_lane_num = 0;
   3802     int tx_physical_lane, tx_logical_lane, rx_physical_lane, rx_logical_lane;
   3803     uint32_t new_tx_lane_map, new_rx_lane_map, swap_mask, tmp_tx_lane_map, tmp_rx_lane_map;
   3804 
   3805     PHYMOD_IF_ERR_RETURN
   3806         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   3807     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   3808 
   3809     /* next based on active_lane_map, figure out the disable lane num  and index*/
   3810     for (i = 0; i < num_lane; i++)
   3811     {
   3812         if(active_lane_map & (1 << i))
   3813         {
   3814             continue;
   3815         } else {
   3816             disable_lane[disable_lane_num] = i + start_lane;
   3817             disable_lane_num++;
   3818         }
   3819     }
   3820 
   3821     /* next check if disable_lane_num 0 */
   3822     if (disable_lane_num == 0) {
   3823         new_tx_lane_map = original_tx_lane_map;
   3824         new_rx_lane_map = original_rx_lane_map;
   3825 
   3826         /* next check if 4 lane or 8 lane port */
   3827         if (num_lane == 8) {
   3828             PHYMOD_IF_ERR_RETURN
   3829                 (tbhmod_pcs_tx_lane_swap(&phy_copy.access, new_tx_lane_map));
   3830             PHYMOD_IF_ERR_RETURN
   3831                 (tbhmod_pcs_rx_lane_swap(&phy_copy.access, new_rx_lane_map));
   3832         } else { /* 4 lane port */
   3833             for (i = 0; i < num_lane; i++) {
   3834                 tx_logical_lane = i + start_lane;
   3835                 rx_logical_lane = i + start_lane;
   3836                 tx_physical_lane = (original_tx_lane_map & (0xf << (tx_logical_lane * 4)) ) >> (tx_logical_lane * 4);
   3837                 rx_physical_lane = (original_rx_lane_map & (0xf << (rx_logical_lane * 4)) ) >> (rx_logical_lane * 4);
   3838                 tx_physical_lane &= 0xf;
   3839                 rx_physical_lane &= 0xf;
   3840                 PHYMOD_IF_ERR_RETURN
   3841                     (tbhmod_pcs_single_tx_lane_swap_set(&phy_copy.access, tx_physical_lane, tx_logical_lane));
   3842                 PHYMOD_IF_ERR_RETURN
   3843                     (tbhmod_pcs_single_rx_lane_swap_set(&phy_copy.access, rx_physical_lane, rx_logical_lane));
   3844             }
   3845         }
   3846     } else  {
   3847         if (num_lane == 4) {
   3848             /* first check if disable lane is the last, if yes, then need to adjust */
   3849             if ((disable_lane[0] == 3) || (disable_lane[0] == 7)) {
   3850                 return PHYMOD_E_NONE;
   3851             } else if (disable_lane[0] < 4) {
   3852                 /* mpp0 */
   3853                 tx_logical_lane = disable_lane[0];
   3854                 rx_logical_lane = disable_lane[0];
   3855                 tx_physical_lane = (original_tx_lane_map & (0xf << (3 * 4)) & 0xffff) >> (3 * 4);
   3856                 rx_physical_lane = (original_rx_lane_map & (0xf << (3 * 4)) & 0xffff) >> (3 * 4);
   3857                 tx_physical_lane &= 0xf;
   3858                 rx_physical_lane &= 0xf;
   3859                 PHYMOD_IF_ERR_RETURN
   3860                     (tbhmod_pcs_single_tx_lane_swap_set(&phy_copy.access, tx_physical_lane, tx_logical_lane));
   3861                 PHYMOD_IF_ERR_RETURN
   3862                     (tbhmod_pcs_single_rx_lane_swap_set(&phy_copy.access, rx_physical_lane, rx_logical_lane));
   3863                 /* mpp0 */
   3864                 tx_logical_lane = 3;
   3865                 rx_logical_lane = 3;
   3866                 tx_physical_lane = (original_tx_lane_map & (0xf << (disable_lane[0] * 4)) & 0xffff) >> (disable_lane[0] * 4);
   3867                 rx_physical_lane = (original_rx_lane_map & (0xf << (disable_lane[0] * 4)) & 0xffff) >> (disable_lane[0] * 4);
   3868                 tx_physical_lane &= 0xf;
   3869                 rx_physical_lane &= 0xf;
   3870                 PHYMOD_IF_ERR_RETURN
   3871                     (tbhmod_pcs_single_tx_lane_swap_set(&phy_copy.access, tx_physical_lane, tx_logical_lane));
   3872                 PHYMOD_IF_ERR_RETURN
   3873                     (tbhmod_pcs_single_rx_lane_swap_set(&phy_copy.access, rx_physical_lane, rx_logical_lane));
   3874             } else {
   3875                 /* mpp1 */
   3876                 tx_logical_lane = disable_lane[0];
   3877                 rx_logical_lane = disable_lane[0];
   3878                 tx_physical_lane = (original_tx_lane_map & (0xf << (7 * 4)) & 0xffff0000) >> (7 * 4);
   3879                 rx_physical_lane = (original_rx_lane_map & (0xf << (7 * 4)) & 0xffff0000) >> (7 * 4);
   3880                 tx_physical_lane &= 0xf;
   3881                 rx_physical_lane &= 0xf;
   3882                 PHYMOD_IF_ERR_RETURN
   3883                     (tbhmod_pcs_single_tx_lane_swap_set(&phy_copy.access, tx_physical_lane, tx_logical_lane));
   3884                 PHYMOD_IF_ERR_RETURN
   3885                     (tbhmod_pcs_single_rx_lane_swap_set(&phy_copy.access, rx_physical_lane, rx_logical_lane));
   3886                 /* mpp1 */
   3887                 tx_logical_lane = 7;
   3888                 rx_logical_lane = 7;
   3889                 tx_physical_lane = (original_tx_lane_map & (0xf << (disable_lane[0] * 4)) & 0xffff0000) >> (disable_lane[0] * 4);
   3890                 rx_physical_lane = (original_rx_lane_map & (0xf << (disable_lane[0] * 4)) & 0xffff0000) >> (disable_lane[0] * 4);
   3891                 tx_physical_lane &= 0xf;
   3892                 rx_physical_lane &= 0xf;
   3893                 PHYMOD_IF_ERR_RETURN
   3894                     (tbhmod_pcs_single_tx_lane_swap_set(&phy_copy.access, tx_physical_lane, tx_logical_lane));
   3895                 PHYMOD_IF_ERR_RETURN
   3896                     (tbhmod_pcs_single_rx_lane_swap_set(&phy_copy.access, rx_physical_lane, rx_logical_lane));
   3897             }
   3898         } else if (num_lane == 8) {
   3899             /* first check if disable lane is the last, if yes, then no need to adjust */
   3900             if (disable_lane_num == 1) {
   3901                 /* no need to do pcs adjust */
   3902                 if (disable_lane[0] == 7) {
   3903                     return PHYMOD_E_NONE;
   3904                 } else {
   3905                     new_tx_lane_map = (original_tx_lane_map & (0xf << (7 * 4)) & 0xffffffff) >> (4 * (7 - disable_lane[0]));
   3906                     new_tx_lane_map |= (original_tx_lane_map & (0xf << (disable_lane[0] * 4)) & 0xffffffff) << (4 * (7 - disable_lane[0]));
   3907                     new_rx_lane_map = (original_rx_lane_map & (0xf << (7 * 4)) & 0xffffffff) >> (4 * (7 - disable_lane[0]));
   3908                     new_rx_lane_map |= (original_rx_lane_map & (0xf << (disable_lane[0] * 4)) & 0xffffffff) << (4 * (7 - disable_lane[0]));
   3909                     swap_mask = ~(0xf << (4 * 7) | 0xf << (4 * disable_lane[0]));
   3910                     new_tx_lane_map |=  (original_tx_lane_map & swap_mask);
   3911                     new_rx_lane_map |=  (original_rx_lane_map & swap_mask);
   3912                 }
   3913             } else { /*2 lane disabled */
   3914                 if ((disable_lane[0] == 6)  && (disable_lane[1] == 7)) {
   3915                     /* no need to do pcs adjust */
   3916                     return PHYMOD_E_NONE;
   3917                 } else if (disable_lane[1] != 6) {
   3918                     new_tx_lane_map = (original_tx_lane_map & (0xf << (6 * 4)) & 0xffffffff) >> (4 * (6 - disable_lane[0]));
   3919                     new_tx_lane_map |= (original_tx_lane_map & (0xf << (disable_lane[0] * 4)) & 0xffffffff) << (4 * (6 - disable_lane[0]));
   3920                     tmp_tx_lane_map = (original_tx_lane_map & (0xf << (7 * 4)) & 0xffffffff) >> (4 * (7 - disable_lane[1]));
   3921                     tmp_tx_lane_map |= (original_tx_lane_map & (0xf << (disable_lane[1] * 4)) & 0xffffffff) <<  (4 * (7 - disable_lane[1]));
   3922                     new_tx_lane_map |= tmp_tx_lane_map;
   3923                     new_rx_lane_map = (original_rx_lane_map & (0xf << (6 * 4)) & 0xffffffff) >> (4 * (6 - disable_lane[0]));
   3924                     new_rx_lane_map |= (original_rx_lane_map & (0xf << (disable_lane[0] * 4)) & 0xffffffff) << (4 * (6 - disable_lane[0]));
   3925                     tmp_rx_lane_map = (original_rx_lane_map & (0xf << (7 * 4)) & 0xffffffff) >> (4 * (7 - disable_lane[1]));
   3926                     tmp_rx_lane_map |= (original_rx_lane_map & (0xf << (disable_lane[1] * 4)) & 0xffffffff) << (4 * (7 - disable_lane[1]));
   3927                     new_rx_lane_map |= tmp_rx_lane_map;
   3928                     swap_mask = ~(0xff << (4 * 6) | 0xf << (4 * disable_lane[0]) | 0xf << (4 * disable_lane[1]));
   3929                     new_tx_lane_map |=  (original_tx_lane_map & swap_mask);
   3930                     new_rx_lane_map |=  (original_rx_lane_map & swap_mask);
   3931                 } else {
   3932                     tmp_tx_lane_map = (original_tx_lane_map & (0xf << (7 * 4)) & 0xffffffff) >> (4 * (7 - disable_lane[0]));
   3933                     tmp_tx_lane_map |= (original_tx_lane_map & (0xf << (disable_lane[0] * 4)) & 0xffffffff) <<  (4 * (7 - disable_lane[0]));
   3934                     new_tx_lane_map = tmp_tx_lane_map;
   3935                     tmp_rx_lane_map = (original_rx_lane_map & (0xf << (7 * 4)) & 0xffffffff) >> (4 * (7 - disable_lane[0]));
   3936                     tmp_rx_lane_map |= (original_rx_lane_map & (0xf << (disable_lane[0] * 4)) & 0xffffffff) << (4 * (7 - disable_lane[0]));
   3937                     new_rx_lane_map = tmp_rx_lane_map;
   3938                     swap_mask = ~(0xf << (4 * 7) | 0xf << (4 * disable_lane[0]));
   3939                     new_tx_lane_map |=  (original_tx_lane_map & swap_mask);
   3940                     new_rx_lane_map |=  (original_rx_lane_map & swap_mask);
   3941                 }
   3942             }
   3943 
   3944             PHYMOD_IF_ERR_RETURN
   3945                 (tbhmod_pcs_tx_lane_swap(&phy_copy.access, new_tx_lane_map));
   3946             PHYMOD_IF_ERR_RETURN
   3947                 (tbhmod_pcs_rx_lane_swap(&phy_copy.access, new_rx_lane_map));
   3948         }
   3949     }
   3950     return PHYMOD_E_NONE;
   3951 }
   3952 
   3953 int tscbh_phy_load_speed_id_entry(const phymod_phy_access_t* phy, uint32_t speed, uint32_t num_lane, phymod_fec_type_t fec_type)
   3954 {
   3955     phymod_phy_access_t phy_copy;
   3956     int start_lane, local_num_lane, mapped_speed_id;
   3957     tbhmod_spd_intfc_type_t spd_intf;
   3958     uint32_t tvco_pll_div;
   3959 
   3960     PHYMOD_IF_ERR_RETURN
   3961         (phymod_util_lane_config_get(&phy->access, &start_lane, &local_num_lane));
   3962     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   3963 
   3964     /* first check the speed */
   3965     switch (speed) {
   3966     case 150000:
   3967         spd_intf = TBHMOD_SPD_150G_FEC_544_2XN_N3;
   3968         break;
   3969     case 350000:
   3970         spd_intf = TBHMOD_SPD_350G_FEC_544_2XN_N7;
   3971         break;
   3972     case 300000:
   3973         spd_intf = TBHMOD_SPD_300G_FEC_544_2XN_N6;
   3974         break;
   3975     case 400000:
   3976         spd_intf = TBHMOD_SPD_400G_BRCM_FEC_544_2XN_X8;
   3977         break;
   3978     case 200000:
   3979         if (fec_type == phymod_fec_RS544_2XN) {
   3980             spd_intf = TBHMOD_SPD_200G_IEEE_FEC_544_2XN_KR4_CR4;
   3981         } else if (fec_type == phymod_fec_RS544) {
   3982             spd_intf = TBHMOD_SPD_200G_BRCM_FEC_544_1XN_KR4_CR4;
   3983         } else if (fec_type == phymod_fec_RS272) {
   3984             spd_intf = TBHMOD_SPD_200G_BRCM_FEC_272_1XN_KR4_CR4;
   3985         } else {
   3986             PHYMOD_DEBUG_ERROR(("Unsupported 200G fec type\n"));
   3987             return PHYMOD_E_UNAVAIL;
   3988         }
   3989         break;
   3990     default:
   3991         PHYMOD_DEBUG_ERROR(("Unsupported speed for speed id load function \n"));
   3992         return PHYMOD_E_UNAVAIL;
   3993     }
   3994 
   3995     PHYMOD_IF_ERR_RETURN
   3996         (tbhmod_get_mapped_speed(spd_intf, &mapped_speed_id));
   3997 
   3998     /* Get TVCO because it's not allowed to change during speed set */
   3999     phy_copy.access.pll_idx = phy->access.tvco_pll_index;
   4000 
   4001     PHYMOD_IF_ERR_RETURN
   4002         (blackhawk_tsc_INTERNAL_read_pll_div(&phy_copy.access, &tvco_pll_div));
   4003 
   4004     /* based on the current TVCO PLL div, decide which copy of speed id entry to load */
   4005     /* first set the lane mask to be 0x1 */
   4006     phy_copy.access.lane_mask = 1 << 0;
   4007     if ((tvco_pll_div == TBHMOD_PLL_MODE_DIV_170) || (tvco_pll_div == TBHMOD_PLL_MODE_DIV_85))  {
   4008         /* then load 26G TVCO speed id entry */
   4009         PHYMOD_IF_ERR_RETURN
   4010             (phymod_mem_write(&phy_copy.access, phymodMemSpeedIdTable, TSCBH_FORCED_SPEED_ID_OFFSET + start_lane, &spd_id_entry_26[mapped_speed_id][0]));
   4011     } else if ((tvco_pll_div == TBHMOD_PLL_MODE_DIV_165) || (tvco_pll_div == TBHMOD_PLL_MODE_DIV_82P5)) {
   4012         /* then load 25G TVCO speed id entry */
   4013         PHYMOD_IF_ERR_RETURN
   4014             (phymod_mem_write(&phy_copy.access, phymodMemSpeedIdTable, TSCBH_FORCED_SPEED_ID_OFFSET + start_lane, &spd_id_entry_25[mapped_speed_id][0]));
   4015     } else {
   4016         /* then load 20G TVCO speed id entry */
   4017         PHYMOD_IF_ERR_RETURN
   4018             (phymod_mem_write(&phy_copy.access, phymodMemSpeedIdTable, TSCBH_FORCED_SPEED_ID_OFFSET + start_lane, &spd_id_entry_20[mapped_speed_id][0]));
   4019     }
   4020 
   4021     return PHYMOD_E_NONE;
   4022 }
   4023 
   4024 int tscbh_phy_pmd_override_enable_set(const phymod_phy_access_t* phy,
   4025                                    phymod_override_type_t pmd_override_type,
   4026                                    uint32_t override_enable,
   4027                                    uint32_t override_val)
   4028 {
   4029     phymod_phy_access_t phy_copy;
   4030     int start_lane, num_lane;
   4031 
   4032     PHYMOD_IF_ERR_RETURN
   4033         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   4034     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   4035 
   4036     PHYMOD_IF_ERR_RETURN
   4037         (tbhmod_pmd_override_enable_set(&phy_copy.access, pmd_override_type, override_enable, override_val));
   4038 
   4039     return PHYMOD_E_NONE;
   4040 }
   4041 
   4042 int tscbh_phy_pll_powerdown_get(const phymod_phy_access_t* phy, uint32_t pll_index, uint32_t* powerdown)
   4043 {
   4044     phymod_phy_access_t phy_copy;
   4045 
   4046     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   4047 
   4048     phy_copy.access.pll_idx = pll_index;
   4049     phy_copy.access.lane_mask = 1 << 0;
   4050     PHYMOD_IF_ERR_RETURN
   4051         (blackhawk_tsc_pll_pwrdn_get(&phy_copy.access, powerdown));
   4052 
   4053     return PHYMOD_E_NONE;
   4054 }
   4055 
   4056 int tscbh_phy_fec_bypass_indication_set(const phymod_phy_access_t* phy,
   4057                                         uint32_t enable)
   4058 {
   4059     int start_lane, num_lane;
   4060     phymod_phy_access_t phy_copy;
   4061     uint32_t lane_reset, pcs_lane_enable;
   4062 
   4063     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   4064 
   4065     PHYMOD_IF_ERR_RETURN
   4066         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   4067 
   4068     /*first check if lane is in reset */
   4069     PHYMOD_IF_ERR_RETURN
   4070         (blackhawk_lane_soft_reset_get(&phy_copy.access, &lane_reset));
   4071 
   4072     /*next check if PCS lane is in reset */
   4073     PHYMOD_IF_ERR_RETURN
   4074         (tbhmod_enable_get(&phy_copy.access, &pcs_lane_enable));
   4075 
   4076     /* disable pcs lane if pcs lane not in rset */
   4077     if (pcs_lane_enable) {
   4078         phy_copy.access.lane_mask = 1 << start_lane;
   4079         PHYMOD_IF_ERR_RETURN
   4080             (tbhmod_disable_set(&phy_copy.access));
   4081     }
   4082 
   4083     /* if lane is not in reset, then reset the lane first */
   4084     if (!lane_reset) {
   4085         PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   4086         PHYMOD_IF_ERR_RETURN
   4087             (blackhawk_lane_soft_reset(&phy_copy.access, 1));
   4088     }
   4089 
   4090     phy_copy.access.lane_mask = 1 << start_lane;
   4091     PHYMOD_IF_ERR_RETURN(
   4092       tbhmod_fec_bypass_indication_set(&phy_copy.access, enable));
   4093 
   4094     /* release the lane soft reset bit */
   4095     if (!lane_reset) {
   4096         PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   4097         PHYMOD_IF_ERR_RETURN
   4098             (blackhawk_lane_soft_reset(&phy_copy.access, 0));
   4099     }
   4100 
   4101     /* re-enable pcs lane if pcs lane not in rset */
   4102     if (pcs_lane_enable) {
   4103         phy_copy.access.lane_mask = 1 << start_lane;
   4104         PHYMOD_IF_ERR_RETURN
   4105             (tbhmod_enable_set(&phy_copy.access));
   4106     }
   4107 
   4108     return PHYMOD_E_NONE;
   4109 }
   4110 
   4111 int tscbh_phy_fec_bypass_indication_get(const phymod_phy_access_t* phy,
   4112                                         uint32_t *enable)
   4113 {
   4114     int start_lane, num_lane;
   4115     phymod_phy_access_t phy_copy;
   4116 
   4117     PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy));
   4118 
   4119     PHYMOD_IF_ERR_RETURN
   4120         (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane));
   4121 
   4122     phy_copy.access.lane_mask = 1 << start_lane;
   4123 
   4124     PHYMOD_IF_ERR_RETURN(
   4125       tbhmod_fec_bypass_indication_get(&phy_copy.access, enable));
   4126 
   4127     return PHYMOD_E_NONE;
   4128 }
   4129