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

merlin16_config.c (43318B)


      1 /***********************************************************************************
      2  ***********************************************************************************
      3  *  File Name     :  merlin16_config.c                                           *
      4  *  Created On    :  03 Nov 2015                                                   *
      5  *  Created By    :  Brent Roberts                                                 *
      6  *  Description   :  APIs for Serdes IPs                                           *
      7  *  Revision      :    *
      8  *                                                                                 *
      9  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
     10  * 
     11  * Copyright 2007-2019 Broadcom Inc. All rights reserved.                                                           *
     12  *  No portions of this material may be reproduced in any form without             *
     13  *  the written permission of:                                                     *
     14  *      Broadcom Corporation                                                       *
     15  *      5300 California Avenue                                                     *
     16  *      Irvine, CA  92617                                                          *
     17  *                                                                                 *
     18  *  All information contained in this document is Broadcom Corporation             *
     19  *  company private proprietary, and trade secret.                                 *
     20  */
     21 
     22 /** @file merlin16_config.c
     23  * Implementation of API config functions
     24  */
     25 
     26 #include <phymod/phymod.h>
     27 #include <phymod/phymod_system.h>
     28 #include "merlin16_config.h"
     29 #include "merlin16_access.h"
     30 #include "merlin16_common.h"
     31 #include "merlin16_functions.h"
     32 #include "merlin16_internal.h"
     33 #include "merlin16_internal_error.h"
     34 #include "merlin16_select_defns.h"
     35 #include "merlin16_enum.h"
     36 #include "merlin16_dependencies.h"
     37 
     38 /* If SERDES_EVAL is defined, then is_ate_log_enabled() is queried to *\
     39 \* know whether to log ATE.  merlin16_access.h provides that function.  */
     40 
     41 
     42 
     43 /*******************************/
     44 /*  Stop/Resume RX Adaptation  */
     45 /*******************************/
     46 
     47 err_code_t merlin16_stop_rx_adaptation(srds_access_t *sa__, uint8_t enable) {
     48 
     49   if (enable) {
     50       err_code_t err_code;
     51       err_code = merlin16_pmd_uc_control(sa__, CMD_UC_CTRL_STOP_GRACEFULLY,GRACEFUL_STOP_TIME);
     52       if(err_code) {
     53           uint8_t temp=0;
     54           USR_PRINTF(("Warning Graceful stop request returned error %d; Requesting a forceful stop\n",err_code));
     55           temp = merlin16_INTERNAL_stop_micro(sa__,0,&err_code);
     56           /* return value from merlin16_INTERNAL_stop_micro - immediate stop is not required */
     57           /* void casting to avoid compiler warning. */
     58           (void)temp;
     59       }
     60       return(err_code);
     61   }
     62   else {
     63     return(merlin16_pmd_uc_control(sa__, CMD_UC_CTRL_RESUME,50));
     64   }
     65 }
     66 
     67 err_code_t merlin16_request_stop_rx_adaptation(srds_access_t *sa__) {
     68 
     69   return(merlin16_pmd_uc_control_return_immediate(sa__, CMD_UC_CTRL_STOP_GRACEFULLY));
     70 }
     71 
     72 /**********************/
     73 /*  uCode CRC Verify  */
     74 /**********************/
     75 
     76 err_code_t merlin16_ucode_crc_verify(srds_access_t *sa__, uint16_t ucode_len,uint16_t expected_crc_value) {
     77     uint16_t calc_crc;
     78     EFUN(merlin16_pmd_uc_cmd_with_data(sa__, CMD_CALC_CRC,0,ucode_len,200));
     79 
     80     ESTM(calc_crc = rd_uc_dsc_data());
     81     if(calc_crc != expected_crc_value) {
     82         EFUN_PRINTF(("Microcode CRC did not match expected=%04x : calculated=%04x\n",expected_crc_value, calc_crc));
     83         return(_error(ERR_CODE_UC_CRC_NOT_MATCH));
     84     }
     85     return(ERR_CODE_NONE);
     86 }
     87 
     88 err_code_t merlin16_start_ucode_crc_calc(srds_access_t *sa__, uint16_t ucode_len) {
     89     EFUN(merlin16_pmd_uc_cmd_with_data_return_immediate(sa__, CMD_CALC_CRC, 0, ucode_len)); /* Invoke Calculate CRC command and return control immediately */
     90     return(ERR_CODE_NONE);
     91 }
     92 
     93 err_code_t merlin16_check_ucode_crc(srds_access_t *sa__, uint16_t expected_crc_value, uint32_t timeout_ms) {
     94     uint16_t calc_crc;
     95     err_code_t err_code;
     96 
     97     err_code = merlin16_INTERNAL_poll_uc_dsc_ready_for_cmd_equals_1(sa__, timeout_ms, CMD_CALC_CRC); /* Poll for uc_dsc_ready_for_cmd = 1 to indicate merlin16 ready for command */
     98     if (err_code) {
     99       EFUN_PRINTF(("ERROR : DSC ready for command timed out. Previous uC command not finished yet\n"));
    100       return (err_code);
    101     }
    102     ESTM(calc_crc = rd_uc_dsc_data());
    103     if(calc_crc != expected_crc_value) {
    104         EFUN_PRINTF(("UC CRC did not match expected=%04x : calculated=%04x\n",expected_crc_value, calc_crc));
    105         return(_error(ERR_CODE_UC_CRC_NOT_MATCH));
    106     }
    107 
    108     return(ERR_CODE_NONE);
    109 }
    110 
    111 
    112 /**************************************************************/
    113 /*  APIs to Write Lane Config and User variables into uC RAM  */
    114 /**************************************************************/
    115 
    116 err_code_t merlin16_set_uc_lane_cfg(srds_access_t *sa__, struct merlin16_uc_lane_config_st struct_val) {
    117   uint8_t reset_state;
    118   ESTM(reset_state = rd_rx_lane_dp_reset_state());
    119   if(reset_state < 7) {
    120       EFUN_PRINTF(("ERROR: merlin16_set_uc_lane_cfg(..) called without ln_dp_s_rstb=0\n"));
    121       return (_error(ERR_CODE_LANE_DP_NOT_RESET));
    122   }
    123   EFUN(merlin16_INTERNAL_update_uc_lane_config_word(&struct_val));
    124   return(wrv_config_word(struct_val.word));
    125 }
    126 
    127 /******************************************************************/
    128 /*  APIs to Read Core/Lane Config and User variables from uC RAM  */
    129 /******************************************************************/
    130 
    131 err_code_t merlin16_get_uc_core_config(srds_access_t *sa__, struct merlin16_uc_core_config_st *get_val)
    132 {
    133     
    134     if(!get_val) {
    135         return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
    136     }
    137         ESTM(get_val->word = rdcv_config_word());
    138     EFUN(merlin16_INTERNAL_update_uc_core_config_st(get_val));
    139     return ERR_CODE_NONE;
    140 }
    141 
    142 err_code_t merlin16_get_uc_lane_cfg(srds_access_t *sa__, struct merlin16_uc_lane_config_st *get_val) {
    143 
    144   if(!get_val) {
    145      return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    146   }
    147   ESTM(get_val->word = rdv_config_word());
    148   EFUN(merlin16_INTERNAL_update_uc_lane_config_st(get_val));
    149   return (ERR_CODE_NONE);
    150 }
    151 
    152 /*--------------------------------------------*/
    153 /*  APIs to Enable or Disable datapath reset  */
    154 /*--------------------------------------------*/
    155 
    156 err_code_t merlin16_tx_dp_reset(srds_access_t *sa__, uint8_t enable) {
    157     if (enable) {
    158         EFUN(wr_tx_ln_dp_s_rstb(0x0));
    159     } else {
    160         EFUN(wr_tx_ln_dp_s_rstb(0x1));
    161         EFUN(wr_tx_uc_ack_lane_dp_reset(0x1));
    162         EFUN(wr_tx_uc_ack_lane_cfg_done(0x1));
    163     }
    164     return ERR_CODE_NONE;
    165 }
    166 
    167 err_code_t merlin16_rx_dp_reset(srds_access_t *sa__, uint8_t enable) {
    168     if (enable) {
    169         EFUN(wr_rx_ln_dp_s_rstb(0x0));
    170     } else {
    171         EFUN(wr_rx_ln_dp_s_rstb(0x1));
    172     }
    173     return ERR_CODE_NONE;
    174 }
    175 
    176 err_code_t merlin16_core_dp_reset(srds_access_t *sa__, uint8_t enable){
    177     if (enable) {
    178         EFUN(wrc_core_dp_s_rstb(0x0));
    179     } else {
    180         EFUN(wrc_core_dp_s_rstb(0x1));
    181     }
    182     return ERR_CODE_NONE;
    183 }
    184 
    185 /********************************/
    186 /*  Loading ucode through PRAM  */
    187 /********************************/
    188 err_code_t merlin16_ucode_pram_load(srds_access_t *sa__, char const * ucode_image, uint32_t ucode_len) {
    189     uint16_t ucode_len_remainder = ((ucode_len + 3) & 0xFFFFFFFC) - ucode_len;
    190 
    191     if(!ucode_image) {
    192         return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    193     }
    194 
    195     if (ucode_len > UCODE_MAX_SIZE) {                       /* uCode size should be less than UCODE_MAX_SIZE  */
    196         return (_error(ERR_CODE_INVALID_UCODE_LEN));
    197     }
    198 
    199     EFUN(wrc_micro_master_clk_en(0x1));                     /* Enable clock to microcontroller subsystem */
    200     EFUN(wrc_micro_master_rstb(0x1));                       /* De-assert reset to microcontroller sybsystem */
    201     EFUN(wrc_micro_master_rstb(0x0));                       /* Assert reset to microcontroller sybsystem - Toggling reset*/
    202     EFUN(wrc_micro_master_rstb(0x1));                       /* De-assert reset to microcontroller sybsystem */
    203 
    204     EFUN(wrc_micro_ra_init(0x1));                           /* Set initialization command to initialize code RAM */
    205     EFUN(merlin16_INTERNAL_poll_micro_ra_initdone(sa__, 250));/* Poll for micro_ra_initdone = 1 to indicate initialization done */
    206 
    207     EFUN(wrc_micro_ra_init(0x2));                         /* Write command for data RAM initialization */
    208     EFUN(merlin16_INTERNAL_poll_micro_ra_initdone(sa__, 250)); /* Poll status of data RAM initialization */
    209 
    210     EFUN(wrc_micro_ra_init(0x0));                           /* Clear initialization command */
    211 
    212 
    213     EFUN(wrc_micro_pramif_ahb_wraddr_msw(0x0000));
    214     EFUN(wrc_micro_pramif_ahb_wraddr_lsw(0x0000));
    215     EFUN(wrc_micro_pram_if_rstb(1));
    216     EFUN(wrc_micro_pramif_en(1));
    217 
    218     /* Wait 8 pram clocks */
    219     EFUN(USR_DELAY_US(1));
    220     
    221     /* write ucode into pram */
    222     while (ucode_len > 0) {
    223         EFUN(merlin16_pmd_wr_pram(sa__, *ucode_image));
    224         --ucode_len;
    225         ++ucode_image;
    226     }
    227     
    228     /* Pad to 32 bits */
    229     while (ucode_len_remainder > 0) {
    230         EFUN(merlin16_pmd_wr_pram(sa__, 0));
    231         --ucode_len_remainder;
    232     }
    233     
    234     /* Wait 8 pram clocks */
    235     EFUN(USR_DELAY_US(1));
    236 
    237 
    238     EFUN(wrc_micro_pramif_en(0));
    239     EFUN(wrc_micro_core_clk_en(1));
    240    /* EFUN(wrc_micro_core_rstb(1)); */
    241     return(ERR_CODE_NONE);
    242 }
    243 
    244 /************************************/
    245 /*  Accessing core_config_from_pcs  */
    246 /************************************/
    247 
    248 err_code_t merlin16_set_core_config_from_pcs(srds_access_t *sa__, uint8_t core_cfg_from_pcs) {
    249     struct merlin16_uc_core_config_st core_config;
    250     EFUN(merlin16_get_uc_core_config(sa__, &core_config));
    251     core_config.field.core_cfg_from_pcs = core_cfg_from_pcs;
    252     EFUN(merlin16_INTERNAL_set_uc_core_config(sa__, core_config));
    253     return (ERR_CODE_NONE);
    254 }
    255  
    256 #if defined(MERLIN_SHORTFIN) || defined(FALCON_SHORTFIN)
    257 err_code_t merlin16_set_an_los_workaround(srds_access_t *sa__, uint8_t an_los_workaround) {
    258     struct merlin16_uc_core_config_st core_config;
    259     EFUN(merlin16_get_uc_core_config(sa__, &core_config));
    260     core_config.field.an_los_workaround = an_los_workaround;
    261     EFUN(merlin16_INTERNAL_set_uc_core_config(sa__, core_config));
    262     return (ERR_CODE_NONE);
    263 }
    264 #endif
    265 
    266 /******************/
    267 /*  Lane Mapping  */
    268 /******************/
    269 
    270 err_code_t merlin16_map_lanes(srds_access_t *sa__, uint8_t num_lanes, uint8_t const *tx_lane_map, uint8_t const *rx_lane_map) {
    271     uint8_t rd_val = 0;
    272 
    273     /* Verify that the core data path is held in reset. */
    274     ESTM(rd_val = rdc_core_dp_s_rstb());
    275     if (rd_val != 0) {
    276         EFUN_PRINTF(("ERROR: core data path reset is not de-asserted\n"));
    277         return (ERR_CODE_UC_NOT_RESET);
    278     }
    279 
    280     /* Verify that all micros are held in reset. */
    281 
    282     ESTM(rd_val = rdc_micro_core_rstb());
    283     if (rd_val != 0) {
    284         return (ERR_CODE_UC_NOT_RESET);
    285     }
    286 
    287     /* Verify that the num_lanes parameter is correct. */
    288     ESTM(rd_val = rdc_revid_multiplicity());
    289     if (rd_val != num_lanes) {
    290         return (ERR_CODE_BAD_LANE_COUNT);
    291     }
    292 
    293     /* Verify that tx_lane_map and rx_lane_map are valid. */
    294     {
    295         uint8_t index1, index2;
    296         /*uint8_t lp_message_printed = 0;*/
    297         for (index1=0; index1<num_lanes; ++index1) {
    298 
    299             /* Verify that a lane map is not to an invalid lane. */
    300             if ((tx_lane_map[index1] >= num_lanes)
    301                 || (rx_lane_map[index1] >= num_lanes)){
    302                 return (ERR_CODE_BAD_LANE);
    303             }
    304 #if 0
    305             /* Warn if an RX lane mapping is not the same as TX. */
    306             if ((tx_lane_map[index1] != rx_lane_map[index1])
    307                 && !lp_message_printed) {
    308                 ESTM_PRINTF(("Warning:  In core %d, TX lane %d is mapped to %d, while RX lane %d is mapped to %d.\n          Digital and remote loopback will not operate as expected.\n          Further warnings are suppressed.\n", merlin16_get_core(sa__), index1, tx_lane_map[index1], index1, rx_lane_map[index1]));
    309                 lp_message_printed = 1;
    310             }
    311 #endif
    312 
    313             /* Verify that a lane map is not used twice. */
    314             for (index2=index1+1; index2<num_lanes; ++index2) {
    315                 if ((tx_lane_map[index1] == tx_lane_map[index2])
    316                     || (rx_lane_map[index1] == rx_lane_map[index2])) {
    317                     return (ERR_CODE_BAD_LANE);
    318                 }
    319             }
    320         }
    321     }
    322 
    323     /* Write the map bitfields.
    324      * Support up to 8 lanes.
    325      */
    326     EFUN(wrc_tx_lane_addr_0(*(tx_lane_map++))); EFUN(wrc_rx_lane_addr_0(*(rx_lane_map++)));
    327 #if defined(wrc_tx_lane_addr_1)
    328     if (num_lanes > 1) { EFUN(wrc_tx_lane_addr_1(*(tx_lane_map++))); EFUN(wrc_rx_lane_addr_1(*(rx_lane_map++))); }
    329 #if defined(wrc_tx_lane_addr_2)
    330     if (num_lanes > 2) { EFUN(wrc_tx_lane_addr_2(*(tx_lane_map++))); EFUN(wrc_rx_lane_addr_2(*(rx_lane_map++))); }
    331 #if defined(wrc_tx_lane_addr_3)
    332     if (num_lanes > 3) { EFUN(wrc_tx_lane_addr_3(*(tx_lane_map++))); EFUN(wrc_rx_lane_addr_3(*(rx_lane_map++))); }
    333 #if defined(wrc_tx_lane_addr_4)
    334     if (num_lanes > 4) { EFUN(wrc_tx_lane_addr_4(*(tx_lane_map++))); EFUN(wrc_rx_lane_addr_4(*(rx_lane_map++))); }
    335 #if defined(wrc_tx_lane_addr_5)
    336     if (num_lanes > 5) { EFUN(wrc_tx_lane_addr_5(*(tx_lane_map++))); EFUN(wrc_rx_lane_addr_5(*(rx_lane_map++))); }
    337 #if defined(wrc_tx_lane_addr_6)
    338     if (num_lanes > 6) { EFUN(wrc_tx_lane_addr_6(*(tx_lane_map++))); EFUN(wrc_rx_lane_addr_6(*(rx_lane_map++))); }
    339 #if defined(wrc_tx_lane_addr_7)
    340     if (num_lanes > 7) { EFUN(wrc_tx_lane_addr_7(*(tx_lane_map++))); EFUN(wrc_rx_lane_addr_7(*(rx_lane_map++))); }
    341 #endif
    342 #endif
    343 #endif
    344 #endif
    345 #endif
    346 #endif
    347 #endif
    348     return (ERR_CODE_NONE);
    349 }
    350 
    351 /************************/
    352 /*  Serdes API Version  */
    353 /************************/
    354 
    355 err_code_t merlin16_version(uint32_t *api_version) {
    356 
    357     if(!api_version) {
    358         return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    359     }
    360     *api_version = 0xA10710;
    361     return (ERR_CODE_NONE);
    362 }
    363 
    364 /*****************/
    365 /*  PMD_RX_LOCK  */
    366 /*****************/
    367 
    368 err_code_t merlin16_pmd_lock_status(srds_access_t *sa__, uint8_t *pmd_rx_lock) {
    369     if(!pmd_rx_lock) {
    370         return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    371     }
    372     ESTM(*pmd_rx_lock = rd_pmd_rx_lock());
    373     return (ERR_CODE_NONE);
    374 }
    375 
    376 /**********************************/
    377 /*  Serdes TX disable/RX Restart  */
    378 /**********************************/
    379 
    380 err_code_t merlin16_tx_disable(srds_access_t *sa__, uint8_t enable) {
    381 
    382   if (enable) {
    383     EFUN(wr_sdk_tx_disable(0x1));
    384   }
    385   else {
    386     EFUN(wr_sdk_tx_disable(0x0));
    387   }
    388   return(ERR_CODE_NONE);
    389 }
    390 
    391 err_code_t merlin16_rx_restart(srds_access_t *sa__, uint8_t enable) {
    392 
    393   EFUN(wr_rx_restart_pmd_hold(enable));
    394   return(ERR_CODE_NONE);
    395 }
    396 /******************************************************/
    397 /*  Single function to set/get all RX AFE parameters  */
    398 /******************************************************/
    399 
    400 err_code_t merlin16_write_rx_afe(srds_access_t *sa__, enum srds_rx_afe_settings_enum param, int8_t val) {
    401   /* Assumes the micro is not actively tuning */
    402 
    403     switch(param) {
    404     case RX_AFE_PF:
    405         return(merlin16_INTERNAL_set_rx_pf_main(sa__, val));
    406 
    407     case RX_AFE_PF2:
    408         return(merlin16_INTERNAL_set_rx_pf2(sa__, val));
    409 
    410     case RX_AFE_VGA:
    411       return(merlin16_INTERNAL_set_rx_vga(sa__, val));
    412 
    413     case RX_AFE_DFE1:
    414         return(merlin16_INTERNAL_set_rx_dfe1(sa__, val));
    415 
    416     case RX_AFE_DFE2:
    417         return(merlin16_INTERNAL_set_rx_dfe2(sa__, val));
    418 
    419     case RX_AFE_DFE3:
    420         return(merlin16_INTERNAL_set_rx_dfe3(sa__, val));
    421 
    422     case RX_AFE_DFE4:
    423         return(merlin16_INTERNAL_set_rx_dfe4(sa__, val));
    424 
    425     case RX_AFE_DFE5:
    426         return(merlin16_INTERNAL_set_rx_dfe5(sa__, val));
    427 
    428     default:
    429         return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    430     }
    431 }
    432 
    433 err_code_t merlin16_read_rx_afe(srds_access_t *sa__, enum srds_rx_afe_settings_enum param, int8_t *val) {
    434   /* Assumes the micro is not actively tuning */
    435     if(!val) {
    436         return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    437     }
    438 
    439     switch(param) {
    440     case RX_AFE_PF:
    441         EFUN(merlin16_INTERNAL_get_rx_pf_main(sa__, val));
    442         break;
    443     case RX_AFE_PF2:
    444         EFUN(merlin16_INTERNAL_get_rx_pf2(sa__, val));
    445         break;
    446     case RX_AFE_VGA:
    447         EFUN(merlin16_INTERNAL_get_rx_vga(sa__, val));
    448       break;
    449 
    450     case RX_AFE_DFE1:
    451         EFUN(merlin16_INTERNAL_get_rx_dfe1(sa__, val));
    452         break;
    453     case RX_AFE_DFE2:
    454         EFUN(merlin16_INTERNAL_get_rx_dfe2(sa__, val));
    455         break;
    456     case RX_AFE_DFE3:
    457         EFUN(merlin16_INTERNAL_get_rx_dfe3(sa__, val));
    458         break;
    459     case RX_AFE_DFE4:
    460         EFUN(merlin16_INTERNAL_get_rx_dfe4(sa__, val));
    461         break;
    462     case RX_AFE_DFE5:
    463         EFUN(merlin16_INTERNAL_get_rx_dfe5(sa__, val));
    464         break;
    465     default:
    466         return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    467     }
    468 
    469     return(ERR_CODE_NONE);
    470 }
    471 
    472 
    473 /**********************************************/
    474 /*  Loopback and Ultra-Low Latency Functions  */
    475 /**********************************************/
    476 
    477 /* Locks TX_PI to Loop timing */
    478 err_code_t merlin16_loop_timing(srds_access_t *sa__, uint8_t enable) {
    479 
    480     if (enable) {
    481         EFUN(wr_tx_pi_repeater_mode_en(0x0));
    482         EFUN(wr_tx_pi_en(0x1));                  /* TX_PI enable: 0 = diabled, 1 = enabled */
    483         EFUN(wr_tx_pi_jitter_filter_en(0x1));    /* Jitter filter enable to lock freq: 0 = diabled, 1 = enabled */
    484         EFUN(USR_DELAY_US(25));               /* Wait for tclk to lock to CDR */
    485     } 
    486     else {
    487         EFUN(wr_tx_pi_jitter_filter_en(0x0));    /* Jitter filter enable to lock freq: 0 = diabled, 1 = enabled */
    488         EFUN(wr_tx_pi_en(0x0));                  /* TX_PI enable: 0 = diabled, 1 = enabled */
    489         EFUN(wr_tx_pi_repeater_mode_en(0x1));
    490     }
    491     return (ERR_CODE_NONE);
    492 }
    493 
    494 /* Setup Remote Loopback mode  */
    495 err_code_t merlin16_rmt_lpbk(srds_access_t *sa__, uint8_t enable) {
    496     if (enable) {
    497         EFUN(merlin16_loop_timing(sa__, enable));
    498         EFUN(wr_tx_pi_ext_ctrl_en(0x1));  /* PD path enable: 0 = diabled, 1 = enabled */
    499         EFUN(wr_rmt_lpbk_en(0x1));        /* Remote Loopback Enable: 0 = diabled, 1 = enable  */
    500         EFUN(USR_DELAY_US(50));        /* Wait for rclk and tclk phase lock before expecing good data from rmt loopback */
    501     } else {                              /* Might require longer wait time for smaller values of tx_pi_ext_phase_bwsel_integ */
    502         EFUN(wr_rmt_lpbk_en(0x0));        /* Remote Loopback Enable: 0 = diabled, 1 = enable  */
    503         EFUN(wr_tx_pi_ext_ctrl_en(0x0));  /* PD path enable: 0 = diabled, 1 = enabled */
    504         EFUN(merlin16_loop_timing(sa__, enable));
    505     }
    506     return (ERR_CODE_NONE);
    507 }
    508 
    509 /* Repeater Only APIs (Not applicable to PMD) */
    510 
    511 
    512 
    513 /* TX PI setup for Repeater Mode */
    514 err_code_t merlin16_tx_rptr_mode_timing(srds_access_t *sa__, uint8_t enable) {
    515     /* Enable TX PI and turn on 1st order loop in jitter filter */
    516     EFUN(wr_tx_pi_repeater_mode_en(0x1));
    517     EFUN(wr_tx_pi_en(enable));                            /* TX_PI enable: 0 = diabled, 1 = enabled */
    518     EFUN(wr_tx_pi_jitter_filter_en(enable));              /* Jitter filter enable to lock freq: 0 = diabled, 1 = enabled */
    519     EFUN(USR_DELAY_US(25));                               /* Wait for TX_PI to settle */
    520     return (ERR_CODE_NONE);
    521 }
    522 
    523 /* RX setup for Repeater Mode timing */
    524 err_code_t merlin16_rx_rptr_mode_timing(srds_access_t *sa__, uint8_t enable) {
    525     (void)enable;
    526 
    527     return (ERR_CODE_NONE);
    528 }
    529 
    530 /* Switch to remote loopback from NL mode in repeater */
    531 err_code_t merlin16_rmt_lpbk_from_nl(srds_access_t *sa__) {
    532     EFUN(merlin16_rmt_lpbk(sa__, 0)); /* Reset TX_PI */
    533     EFUN(merlin16_rmt_lpbk(sa__, 1)); /* Enable RMT LPBK */
    534     return (ERR_CODE_NONE);
    535 }
    536 
    537 
    538 /* Switch back from remote loopback to NL mode in repeater */
    539 err_code_t merlin16_nl_from_rmt_lpbk(srds_access_t *sa__, enum srds_rptr_mode_enum mode) {
    540     switch(mode) {
    541     case DATA_IN_SIDE:
    542         EFUN(merlin16_rx_rptr_mode_timing(sa__, 1)); /* Enable RX PI transfer */
    543         break;
    544     case RMT_LPBK_SIDE:
    545         EFUN(merlin16_rmt_lpbk(sa__, 0));            /* Reset TX_PI */
    546         EFUN(merlin16_tx_rptr_mode_timing(sa__, 1)); /* Enable jitter filter enable */
    547         EFUN(wr_ams_tx_ll_selpath_tx(0x0));        /* Select TX PCS data from PCS interface */
    548         break;
    549     default : return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    550     }
    551     return (ERR_CODE_NONE);
    552 }
    553 
    554 /********************************/
    555 /*  TX_PI Fixed Frequency Mode  */
    556 /********************************/
    557 /* TX_PI Frequency Override (Fixed Frequency Mode) */
    558 err_code_t merlin16_tx_pi_freq_override(srds_access_t *sa__, uint8_t enable, int16_t freq_override_val) {
    559     if (enable) {
    560         EFUN(wr_tx_pi_en(0x1));                              /* TX_PI enable :            0 = disabled, 1 = enabled */
    561         EFUN(wr_tx_pi_freq_override_en(0x1));                /* Fixed freq mode enable:   0 = disabled, 1 = enabled */
    562         EFUN(wr_tx_pi_freq_override_val(freq_override_val)); /* Fixed Freq Override Value (+/-8192) */
    563     }
    564     else {
    565         EFUN(wr_tx_pi_freq_override_val(0));                 /* Fixed Freq Override Value to 0 */
    566         EFUN(wr_tx_pi_freq_override_en(0x0));                /* Fixed freq mode enable:   0 = disabled, 1 = enabled */
    567         EFUN(wr_tx_pi_en(0x0));                              /* TX_PI enable :            0 = disabled, 1 = enabled */
    568     }
    569   return (ERR_CODE_NONE);
    570 }
    571 
    572 /*********************************/
    573 /*  uc_active and uc_reset APIs  */
    574 /*********************************/
    575 
    576 /* Enable or Disable the uC reset */
    577 err_code_t merlin16_uc_reset(srds_access_t *sa__, uint8_t enable) {
    578   ucode_info_t ucode_info = {0};
    579   return merlin16_uc_reset_with_info(sa__, enable, ucode_info);
    580 }
    581 
    582 err_code_t merlin16_uc_reset_with_info(srds_access_t *sa__, uint8_t enable, ucode_info_t ucode_info) {
    583   if (enable) {
    584     /* Assert micro reset and reset all micro registers (all non-status registers written to default value) */
    585     EFUN(wrc_micro_core_clk_en(0x0));                     /* Disable clock to M0 core */
    586 
    587     EFUN(wrc_micro_master_clk_en(0x0));                   /* Disable clock to microcontroller subsystem */
    588     EFUN(merlin16_pmd_wr_reg(sa__, 0xD200, 0x0000));
    589     EFUN(merlin16_pmd_wr_reg(sa__, 0xD201, 0x0000));
    590     EFUN(merlin16_pmd_wr_reg(sa__, 0xD202, 0x0000));
    591     EFUN(merlin16_pmd_wr_reg(sa__, 0xD204, 0x0000));
    592     EFUN(merlin16_pmd_wr_reg(sa__, 0xD205, 0x0000));
    593     EFUN(merlin16_pmd_wr_reg(sa__, 0xD206, 0x0000));
    594     EFUN(merlin16_pmd_wr_reg(sa__, 0xD207, 0x0000));
    595     EFUN(merlin16_pmd_wr_reg(sa__, 0xD208, 0x0000));
    596     EFUN(merlin16_pmd_wr_reg(sa__, 0xD209, 0x0000));
    597     EFUN(merlin16_pmd_wr_reg(sa__, 0xD20A, 0x0000));
    598     EFUN(merlin16_pmd_wr_reg(sa__, 0xD20B, 0x0000));
    599     EFUN(merlin16_pmd_wr_reg(sa__, 0xD20C, 0x0000));
    600     EFUN(merlin16_pmd_wr_reg(sa__, 0xD20D, 0x0000));
    601     EFUN(merlin16_pmd_wr_reg(sa__, 0xD20E, 0x0000));
    602     EFUN(merlin16_pmd_wr_reg(sa__, 0xD211, 0x0000));
    603     EFUN(merlin16_pmd_wr_reg(sa__, 0xD212, 0x0000));
    604     EFUN(merlin16_pmd_wr_reg(sa__, 0xD213, 0x0000));
    605     EFUN(merlin16_pmd_wr_reg(sa__, 0xD214, 0x0000));
    606     EFUN(merlin16_pmd_wr_reg(sa__, 0xD215, 0x0000));
    607     EFUN(merlin16_pmd_wr_reg(sa__, 0xD216, 0x0007));
    608     EFUN(merlin16_pmd_wr_reg(sa__, 0xD217, 0x0000));
    609     EFUN(merlin16_pmd_wr_reg(sa__, 0xD218, 0x0000));
    610     EFUN(merlin16_pmd_wr_reg(sa__, 0xD219, 0x0000));
    611     EFUN(merlin16_pmd_wr_reg(sa__, 0xD21A, 0x0000));
    612     EFUN(merlin16_pmd_wr_reg(sa__, 0xD21B, 0x0000));
    613     EFUN(merlin16_pmd_wr_reg(sa__, 0xD220, 0x0000));
    614     EFUN(merlin16_pmd_wr_reg(sa__, 0xD221, 0x0000));
    615     EFUN(merlin16_pmd_wr_reg(sa__, 0xD224, 0x0000));
    616 
    617     EFUN(merlin16_pmd_wr_reg(sa__, 0xD225, 0x8301));
    618 
    619     EFUN(merlin16_pmd_wr_reg(sa__, 0xD226, 0x0000));
    620     EFUN(merlin16_pmd_wr_reg(sa__, 0xD228, 0x0101));
    621     EFUN(merlin16_pmd_wr_reg(sa__, 0xD229, 0x0000));
    622     EFUN(merlin16_pmd_wr_reg(sa__, 0xD22A, 0x0000));  
    623   }
    624   else {
    625     /* De-assert micro reset - Start executing code */
    626     EFUN(wrc_micro_master_clk_en (0x1));             /* Enable clock to microcontroller subsystem */
    627     EFUN(wrc_micro_master_rstb   (0x1));             /* De-assert reset to microcontroller sybsystem */
    628 
    629     EFUN(wrc_micro_core_clk_en   (0x1));            /* Enable clock to M0 core */
    630     EFUN(wrc_micro_core_rstb     (0x1));
    631   }
    632  return (ERR_CODE_NONE);
    633 }
    634 
    635 /* Wait for uC to become active */
    636 err_code_t merlin16_wait_uc_active(srds_access_t *sa__) {
    637     uint16_t loop;
    638     for (loop = 0; loop < 10000; loop++) {
    639         uint16_t rddata;
    640         ESTM(rddata = rdc_uc_active());
    641         if (rddata) {
    642             return (ERR_CODE_NONE);
    643         }
    644         if (loop>10) {
    645             EFUN(USR_DELAY_US(1));
    646         }
    647     }
    648     return (_error(ERR_CODE_MICRO_INIT_NOT_DONE));
    649 }
    650 
    651 static err_code_t merlin16_init_merlin16_info_fill(srds_access_t *sa__, merlin16_info_t * const merlin16_info_ptr) {
    652 
    653     uint32_t info_table[INFO_TABLE_END / sizeof(uint32_t)];
    654     uint32_t info_table_signature;
    655     uint8_t  info_table_version;
    656     err_code_t err_code = ERR_CODE_NONE;
    657 
    658     if (merlin16_info_ptr == 0) {
    659         EFUN_PRINTF(("ERROR:  Info table pointer is null.\n"));
    660         return (_error(ERR_CODE_INFO_TABLE_ERROR));
    661     }
    662 
    663     /* runtime optimization: If table was already filled - no point in filling it again */
    664     if (merlin16_info_ptr->valid) {
    665         return (ERR_CODE_NONE);
    666     }
    667 
    668     if (merlin16_info_ptr->signature == SRDS_INFO_SIGNATURE) {
    669         /*Already initalized and so check for microcode version and exit with proper status*/
    670         err_code = merlin16_INTERNAL_match_ucode_from_info(sa__);
    671 
    672         if (err_code == ERR_CODE_NONE) {
    673             /* ucode version match */
    674             return (ERR_CODE_NONE);
    675         } else {
    676             /* ucode version mismatch */
    677             return (_error(ERR_CODE_MICRO_INIT_NOT_DONE));
    678         }
    679     }
    680     /*Never initialized so far, continue with initialization */
    681 
    682     err_code = merlin16_rdblk_uc_prog_ram(sa__, (uint8_t *)info_table, INFO_TABLE_RAM_BASE, INFO_TABLE_END);
    683     /* Release lock before returning from the call to avoid deadlock */
    684     if (ERR_CODE_NONE != err_code) {
    685        return (_error(err_code));
    686     }
    687 
    688     info_table_signature = info_table[INFO_TABLE_OFFS_SIGNATURE / sizeof(uint32_t)];
    689     info_table_version = (uint8_t)(info_table_signature >> 24);
    690     if (((info_table_signature & 0x00FFFFFF) != 0x666E49)
    691         || (!(   ((info_table_version >= 0x32) && (info_table_version <= 0x39))
    692               || ((info_table_version >= 0x41) && (info_table_version <= 0x5A))))) {
    693         return (_error(ERR_CODE_INFO_TABLE_ERROR));
    694     }
    695     
    696     merlin16_info_ptr->lane_count = info_table[INFO_TABLE_OFFS_OTHER_SIZE / sizeof(uint32_t)] & 0xFF;
    697     merlin16_info_ptr->trace_memory_descending_writes = ((info_table[INFO_TABLE_OFFS_OTHER_SIZE / sizeof(uint32_t)] & 0x1000000) != 0);
    698 
    699     merlin16_info_ptr->core_var_ram_size = (info_table[INFO_TABLE_OFFS_OTHER_SIZE / sizeof(uint32_t)] >> 8) & 0xFF;
    700 
    701     merlin16_info_ptr->lane_var_ram_size = (info_table[INFO_TABLE_OFFS_TRACE_LANE_MEM_SIZE / sizeof(uint32_t)] >> 16) & 0xFFFF;
    702 
    703     merlin16_info_ptr->diag_mem_ram_size = (info_table[INFO_TABLE_OFFS_TRACE_LANE_MEM_SIZE / sizeof(uint32_t)] & 0xFFFF) / merlin16_info_ptr->lane_count;
    704     merlin16_info_ptr->trace_mem_ram_size = (info_table[INFO_TABLE_OFFS_TRACE_LANE_MEM_SIZE / sizeof(uint32_t)] & 0xFFFF);
    705     
    706     merlin16_info_ptr->diag_mem_ram_base = info_table[INFO_TABLE_OFFS_TRACE_MEM_PTR / sizeof(uint32_t)];
    707     merlin16_info_ptr->trace_mem_ram_base = merlin16_info_ptr->diag_mem_ram_base;
    708     
    709     merlin16_info_ptr->core_var_ram_base = info_table[INFO_TABLE_OFFS_CORE_MEM_PTR / sizeof(uint32_t)];
    710     
    711     merlin16_info_ptr->micro_var_ram_base = info_table[INFO_TABLE_OFFS_MICRO_MEM_PTR / sizeof(uint32_t)];
    712     merlin16_info_ptr->micro_var_ram_size = (info_table[INFO_TABLE_OFFS_OTHER_SIZE_2 / sizeof(uint32_t)] >> 4) & 0xFF;
    713 
    714     merlin16_info_ptr->lane_var_ram_base = info_table[INFO_TABLE_OFFS_LANE_MEM_PTR / sizeof(uint32_t)];
    715 
    716     
    717 
    718     if (info_table_version < 0x34) {
    719         merlin16_info_ptr->micro_count = 1;
    720     } else {
    721         merlin16_info_ptr->micro_count = info_table[INFO_TABLE_OFFS_OTHER_SIZE_2 / sizeof(uint32_t)] & 0xF;
    722     }
    723 
    724     if (info_table_version < 0x36) {
    725         merlin16_info_ptr->grp_ram_size = 0;
    726     } else {
    727         merlin16_info_ptr->grp_ram_size = info_table[INFO_TABLE_OFFS_GROUP_RAM_SIZE / sizeof(uint32_t)] & 0xFFFF;
    728     }
    729     merlin16_info_ptr->ucode_version = info_table[INFO_TABLE_OFFS_UC_VERSION /sizeof(uint32_t)];
    730     merlin16_info_ptr->signature = SRDS_INFO_SIGNATURE;
    731     merlin16_info_ptr->valid = 1;
    732 
    733     return (ERR_CODE_NONE);
    734 }
    735 
    736 err_code_t merlin16_init_merlin16_info (srds_access_t *sa__) {
    737     int level, rv;
    738     merlin16_info_t * const merlin16_info_ptr = merlin16_INTERNAL_get_merlin16_info_ptr();
    739 
    740     level = PHYMOD_SPLHI(); /* to protect critical code when filling the global falcon16_tsc_inf table */
    741     rv = merlin16_init_merlin16_info_fill(sa__, merlin16_info_ptr);
    742     PHYMOD_SPL(level);    /* end of critical code */
    743     EFUN(rv); /* error checking is after completing the critical code, to avoid stuck with the high priority task */
    744 
    745     return (ERR_CODE_NONE);
    746 
    747 }
    748 /*-----------------*/
    749 /*  Configure PLL  */
    750 /*-----------------*/
    751 
    752 err_code_t merlin16_configure_pll_refclk_div(srds_access_t *sa__,
    753                                            enum merlin16_pll_refclk_enum refclk,
    754                                            enum merlin16_pll_div_enum div) {
    755     return merlin16_INTERNAL_configure_pll(sa__, refclk, div, 0, MERLIN16_PLL_OPTION_NONE);
    756 }
    757 
    758 err_code_t merlin16_configure_pll_refclk_vco(srds_access_t *sa__,
    759                                            enum merlin16_pll_refclk_enum refclk,
    760                                            uint32_t vco_freq_khz) {
    761     return merlin16_INTERNAL_configure_pll(sa__, refclk, MERLIN16_PLL_DIV_UNKNOWN, vco_freq_khz, MERLIN16_PLL_OPTION_NONE);
    762 }
    763 
    764 err_code_t merlin16_configure_pll_div_vco(srds_access_t *sa__,
    765                                         enum merlin16_pll_div_enum div,
    766                                         uint32_t vco_freq_khz) {
    767     return merlin16_INTERNAL_configure_pll(sa__, MERLIN16_PLL_REFCLK_UNKNOWN, div, vco_freq_khz, MERLIN16_PLL_OPTION_NONE);
    768 }
    769 
    770 /* following routines divide refclk input by 2 to prevent fracn mode */
    771 err_code_t merlin16_configure_pll_refclk_div_div2refclk(srds_access_t *sa__,
    772                                            enum merlin16_pll_refclk_enum refclk,
    773                                            enum merlin16_pll_div_enum div) {
    774    return merlin16_INTERNAL_configure_pll(sa__, refclk, div, 0, MERLIN16_PLL_OPTION_REFCLK_DIV2_EN);
    775 }
    776 
    777 err_code_t merlin16_configure_pll_refclk_vco_div2refclk(srds_access_t *sa__,
    778                                            enum merlin16_pll_refclk_enum refclk,
    779                                            uint32_t vco_freq_khz) {
    780     return merlin16_INTERNAL_configure_pll(sa__, refclk, MERLIN16_PLL_DIV_UNKNOWN, vco_freq_khz, MERLIN16_PLL_OPTION_REFCLK_DIV2_EN);
    781 }
    782 
    783 err_code_t merlin16_configure_pll_div_vco_div2refclk(srds_access_t *sa__,
    784                                         enum merlin16_pll_div_enum div,
    785                                         uint32_t vco_freq_khz) {
    786     return merlin16_INTERNAL_configure_pll(sa__, MERLIN16_PLL_REFCLK_UNKNOWN, div, vco_freq_khz, MERLIN16_PLL_OPTION_REFCLK_DIV2_EN);
    787 }
    788 /* following routines divide refclk input by 2 to prevent fracn mode */
    789 err_code_t merlin16_configure_pll_refclk_div_div4refclk(srds_access_t *sa__,
    790                                            enum merlin16_pll_refclk_enum refclk,
    791                                            enum merlin16_pll_div_enum div) {
    792    return merlin16_INTERNAL_configure_pll(sa__, refclk, div, 0, MERLIN16_PLL_OPTION_REFCLK_DIV4_EN);
    793 }
    794 
    795 err_code_t merlin16_configure_pll_refclk_vco_div4refclk(srds_access_t *sa__,
    796                                            enum merlin16_pll_refclk_enum refclk,
    797                                            uint32_t vco_freq_khz) {
    798     return merlin16_INTERNAL_configure_pll(sa__, refclk, MERLIN16_PLL_DIV_UNKNOWN, vco_freq_khz, MERLIN16_PLL_OPTION_REFCLK_DIV4_EN);
    799 }
    800 
    801 err_code_t merlin16_configure_pll_div_vco_div4refclk(srds_access_t *sa__,
    802                                         enum merlin16_pll_div_enum div,
    803                                         uint32_t vco_freq_khz) {
    804     return merlin16_INTERNAL_configure_pll(sa__, MERLIN16_PLL_REFCLK_UNKNOWN, div, vco_freq_khz, MERLIN16_PLL_OPTION_REFCLK_DIV4_EN);
    805 }
    806 
    807 
    808 err_code_t merlin16_get_vco_from_refclk_div(uint32_t refclk_freq_hz, enum merlin16_pll_div_enum div, uint32_t *vco_freq_khz, enum merlin16_pll_option_enum pll_option) {
    809     EFUN(merlin16_INTERNAL_get_vco_from_refclk_div(refclk_freq_hz, div, vco_freq_khz, pll_option));
    810     return (ERR_CODE_NONE);
    811 }
    812 
    813 
    814 /***********************************************/
    815 /*  Microcode Load into Program RAM Functions  */
    816 /***********************************************/
    817 
    818 /* uCode Load through Register (MDIO) Interface [Return Val = Error_Code (0 = PASS)] */
    819 err_code_t merlin16_ucode_mdio_load(srds_access_t *sa__, uint8_t *ucode_image, uint32_t ucode_len) {
    820     uint32_t   ucode_len_padded, count = 0;
    821     uint16_t   wrdata_lsw;
    822     uint8_t    wrdata_lsb;
    823 
    824     if(!ucode_image) {
    825         return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    826     }
    827 
    828     if (ucode_len > UCODE_MAX_SIZE) {                     /* uCode size should be less than UCODE_MAX_SIZE  */
    829         return (_error(ERR_CODE_INVALID_UCODE_LEN));
    830     }
    831 
    832     EFUN(wrc_micro_master_clk_en(0x1));                   /* Enable clock to microcontroller subsystem */
    833     EFUN(wrc_micro_master_rstb(0x1));                     /* De-assert reset to microcontroller sybsystem */
    834     EFUN(wrc_micro_master_rstb(0x0));                     /* Assert reset to microcontroller sybsystem - Toggling reset*/
    835     EFUN(wrc_micro_master_rstb(0x1));                     /* De-assert reset to microcontroller sybsystem */
    836 
    837     EFUN(wrc_micro_ra_init(0x1));                         /* Set initialization command to initialize code RAM */
    838     EFUN(merlin16_INTERNAL_poll_micro_ra_initdone(sa__, 250)); /* Poll for micro_ra_initdone = 1 to indicate initialization done */
    839 
    840     EFUN(wrc_micro_ra_init(0x2));                         /* Write command for data RAM initialization */
    841     EFUN(merlin16_INTERNAL_poll_micro_ra_initdone(sa__, 250)); /* Poll status of data RAM initialization */
    842 
    843     EFUN(wrc_micro_ra_init(0x0));                         /* Clear initialization command */
    844 
    845     ucode_len_padded = ((ucode_len + 3) & 0xFFFFFFFC);    /* Aligning ucode size to 4-byte boundary */
    846 
    847     /* Code to Load microcode */
    848     EFUN(wrc_micro_autoinc_wraddr_en(0x1));               /* To auto increment RAM write address */
    849     EFUN(wrc_micro_ra_wrdatasize(0x1));                   /* Select 16bit transfers */
    850     EFUN(wrc_micro_ra_wraddr_msw(0x0));                   /* Upper 16bits of start address of Program RAM where the ucode is to be loaded */
    851     EFUN(wrc_micro_ra_wraddr_lsw(0x0));                   /* Lower 16bits of start address of Program RAM where the ucode is to be loaded */
    852 
    853     do {                                                  /* ucode_image loaded 16bits at a time */
    854         wrdata_lsb = (count < ucode_len) ? ucode_image[count] : 0x0; /* wrdata_lsb read from ucode_image; zero padded to 4byte boundary */
    855         count++;
    856         wrdata_lsw = (count < ucode_len) ? ucode_image[count] : 0x0; /* wrdata_msb read from ucode_image; zero padded to 4byte boundary */
    857         count++;
    858         wrdata_lsw = ((wrdata_lsw << 8) | wrdata_lsb);               /* 16bit wrdata_lsw formed from 8bit msb and lsb values read from ucode_image */
    859         EFUN(wrc_micro_ra_wrdata_lsw(wrdata_lsw));                   /* Program RAM lower 16bits write data */
    860     }   while (count < ucode_len_padded);                 /* Loop repeated till entire image loaded (upto the 4byte boundary) */
    861 
    862     EFUN(wrc_micro_ra_wrdatasize(0x2));                   /* Select 32bit transfers as default */
    863     EFUN(wrc_micro_core_clk_en(0x1));                     /* Enable clock to M0 core */
    864     /* EFUN(wrc_micro_core_rstb(0x1)); */                 /* De-assert reset to micro to start executing microcode */
    865     return (ERR_CODE_NONE);                               /* NO Errors while loading microcode (uCode Load PASS) */
    866   }
    867 
    868 
    869 /* Read-back uCode from Program RAM and verify against ucode_image [Return Val = Error_Code (0 = PASS)]  */
    870 err_code_t merlin16_ucode_load_verify(srds_access_t *sa__, uint8_t *ucode_image, uint32_t ucode_len) {
    871 
    872     uint32_t ucode_len_padded, count = 0;
    873     uint16_t rddata_lsw;
    874     uint16_t data_lsw;
    875     uint8_t  rddata_lsb;
    876 
    877     if(!ucode_image) {
    878         return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    879     }
    880 
    881     ucode_len_padded = ((ucode_len + 3) & 0xFFFFFFFC);    /* Aligning ucode size to 4-byte boundary */
    882 
    883     if (ucode_len_padded > UCODE_MAX_SIZE) {              /* uCode size should be less than UCODE_MAX_SIZE */
    884         return (_error(ERR_CODE_INVALID_UCODE_LEN));
    885     }
    886 
    887     EFUN(wrc_micro_autoinc_rdaddr_en(0x1));               /* To auto increment RAM read address */
    888     EFUN(wrc_micro_ra_rddatasize(0x1));                   /* Select 16bit transfers */
    889     EFUN(wrc_micro_ra_rdaddr_msw(0x0));                   /* Upper 16bits of start address of Program RAM from where to read ucode */
    890     EFUN(wrc_micro_ra_rdaddr_lsw(0x0));                   /* Lower 16bits of start address of Program RAM from where to read ucode */
    891 
    892     do {                                                  /* ucode_image read 16bits at a time */
    893         rddata_lsb = (count < ucode_len) ? ucode_image[count] : 0x0; /* rddata_lsb read from ucode_image; zero padded to 4byte boundary */
    894         count++;
    895         rddata_lsw = (count < ucode_len) ? ucode_image[count] : 0x0; /* rddata_msb read from ucode_image; zero padded to 4byte boundary */
    896         count++;
    897         rddata_lsw = ((rddata_lsw << 8) | rddata_lsb);               /* 16bit rddata_lsw formed from 8bit msb and lsb values read from ucode_image */
    898                                                                      /* Compare Program RAM ucode to ucode_image (Read to micro_ra_rddata_lsw reg auto-increments the ram_address) */
    899         ESTM(data_lsw = rdc_micro_ra_rddata_lsw());
    900         if (data_lsw != rddata_lsw) {
    901             EFUN_PRINTF(("Ucode_Load_Verify_FAIL: Addr = 0x%x: Read_data = 0x%x :  Expected_data = 0x%x \n",(count-2),data_lsw,rddata_lsw));
    902             return (_error(ERR_CODE_UCODE_VERIFY_FAIL));             /* Verify uCode FAIL */
    903         }
    904 
    905     } while (count < ucode_len_padded);                   /* Loop repeated till entire image loaded (upto the 4byte boundary) */
    906 
    907     EFUN(wrc_micro_ra_rddatasize(0x2));                   /* Select 32bit transfers ad default */
    908     return (ERR_CODE_NONE);                               /* Verify uCode PASS */
    909 }
    910 
    911 /******************************************************************/
    912 /*  APIs to Align TX clocks                                       */
    913 /******************************************************************/
    914 err_code_t merlin16_tx_clock_align(srds_access_t *sa__, int num_lanes, int enable) {
    915     int current_lane, lane;
    916     
    917     ESTM(current_lane = merlin16_get_lane(sa__));
    918 
    919     for(lane = 0;lane<num_lanes;++lane) {
    920         EFUN(merlin16_set_lane(sa__,lane));
    921         if(enable) {
    922             if(lane == current_lane) {              /* Current Lane should be the master lane */
    923                 EFUN(wr_ams_tx_sel_txmaster(1));    /* Select one lane as txmaster. For all other lanes, this should be 0. */
    924                 EFUN(wr_ams_tx_pd_phasedet(0));     /* 1 - TCA PD powerdown, 0 - enable PD  (enable only for the slave lanes) */
    925             } else {
    926            /* Initial TX lane clock phase alignment. Program following registers only for slave lanes, master lane registers should not be programmed (can be kept in default values). */
    927                 EFUN(wr_tx_pi_pd_bypass_vco(1));        /* for quick phase lock time */
    928                 EFUN(wr_tx_pi_pd_bypass_flt(1));      /*  for quick phase lock time */
    929                 EFUN(wr_tx_pi_ext_pd_sel(0));         /*  selects PD path based on tx_pi_repeater_mode_en */
    930                 EFUN(wr_tx_pi_repeater_mode_en(1));   /*  selects external PD from afe as input to tx_pi */
    931                 EFUN(wr_tx_pi_en(1));                 /*  Enable TX_PI    */
    932                 EFUN(wr_tx_pi_jitter_filter_en(0));   /*  turn off frequency lock for tx_pi as all te tclk clocks are derived from VCO and same frequency */
    933                 EFUN(wr_tx_pi_ext_ctrl_en(1));        /*  turn on PD path to TX_PI to lock the clocks */
    934                 EFUN(USR_DELAY_US(25));                   /*  wait for the slave lane clocks to lock to the master lane clock */
    935                 EFUN(wr_tx_pi_ext_phase_bwsel_integ(3)); /*  0 to 7: higher value means faster lock time */
    936                 EFUN(wr_tx_pi_pd_bypass_vco(0));         /*  disable filter bypass for more accurate lock */
    937                 EFUN(wr_tx_pi_pd_bypass_flt(0));         /*  disable filter bypass for more accurate lock */
    938                 EFUN(USR_DELAY_US(60));                   /*  wait for the slave lane clocks to lock to the master lane clock withing 1/16th of UI. */
    939                 /* that all TX lane clocks are correct frequency and aligned together within 1/16th of UI. */
    940             }
    941         
    942         } else {
    943             if(lane == current_lane) {              /* Current Lane should be the master lane */
    944                 EFUN(wr_ams_tx_sel_txmaster(0));    /* Select one lane as txmaster. For all other lanes, this should be 0. */
    945                 EFUN(wr_ams_tx_pd_phasedet(1));     /* 1 - TCA PD powerdown, 0 - enable PD  (enable only for the slave lanes) */
    946             } else {
    947            /* Initial TX lane clock phase alignment. Program following registers only for slave lanes, master lane registers should not be programmed (can be kept in default values). */
    948                 EFUN(wr_tx_pi_pd_bypass_vco(0));         /* for quick phase lock time */
    949                 EFUN(wr_tx_pi_pd_bypass_flt(0));      /*  for quick phase lock time */
    950                 EFUN(wr_tx_pi_ext_pd_sel(0));         /*  selects PD path based on tx_pi_repeater_mode_en */
    951                 EFUN(wr_tx_pi_repeater_mode_en(1));   /*  selects external PD from afe as input to tx_pi */
    952                 EFUN(wr_tx_pi_en(0));                 /*  Enable TX_PI    */
    953                 EFUN(wr_tx_pi_jitter_filter_en(0));   /*  turn off frequency lock for tx_pi as all te tclk clocks are derived from VCO and same frequency */
    954                 EFUN(wr_tx_pi_ext_ctrl_en(0));        /*  turn on PD path to TX_PI to lock the clocks */
    955                 EFUN(wr_tx_pi_ext_phase_bwsel_integ(0)); /*  0 to 7: higher value means faster lock time */
    956                 EFUN(wr_tx_pi_pd_bypass_vco(0));         /*  disable filter bypass for more accurate lock */
    957                 /* that all TX lane clocks are correct frequency and aligned together within 1/16th of UI. */
    958             }
    959 
    960         }
    961     }
    962     EFUN(merlin16_set_lane(sa__,current_lane)); /* return lane to previous state */
    963     return(ERR_CODE_NONE);
    964  }
    965 
    966 
    967