openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

phy8806x_tsc_functions.c (109485B)


      1 /***********************************************************************************
      2 ***********************************************************************************
      3 *  File Name     :  phy8806x_tsc_functions.c                                        *
      4 *  Created On    :  29/04/2013                                                    *
      5 *  Created By    :  Kiran Divakar                                                 *
      6 *  Description   :  APIs for Serdes IPs                                           *
      7 *                                                                                 *
      8 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      9 * 
     10 * Copyright 2007-2019 Broadcom Inc. All rights reserved.                                                           *
     11 *  No portions of this material may be reproduced in any form without             *
     12 *  the written permission of:                                                     *
     13 *      Broadcom Corporation                                                       *
     14 *      5300 California Avenue                                                     *
     15 *      Irvine, CA  92617                                                          *
     16 *                                                                                 *
     17 *  All information contained in this document is Broadcom Corporation             *
     18 *  company private proprietary, and trade secret.                                 *
     19  */
     20 
     21 /** @file phy8806x_tsc_functions.c
     22  * Implementation of API functions
     23  */
     24 
     25 #ifdef _MSC_VER
     26 /* Enclose all standard headers in a pragma to remove warings for MS compiler */
     27 #pragma warning( push, 0 )
     28 #endif
     29 
     30 #ifdef SERDES_API_FLOATING_POINT
     31 #include <math.h>
     32 #endif
     33 #ifdef _MSC_VER
     34 #pragma warning( pop )
     35 #endif
     36 
     37 #include <phymod/phymod_system.h>
     38 #include "phy8806x_tsc_functions.h"
     39 #include "phy8806x_tsc_field_access_c.h"
     40 #include "phy8806x_tsc_internal_c.h"
     41 #include "phy8806x_tsc_dv_functions_c.h"
     42 
     43 
     44 
     45     #include "phy8806x_tsc_pll_config_c.h"
     46 #ifndef UINT32_MAX
     47 #define UINT32_MAX (4294967295UL)
     48 #endif
     49 
     50 
     51 /************************************/
     52 /*  Display Eye Scan                */
     53 /************************************/
     54 
     55 /* This is best method for terminal ASCII display */
     56 err_code_t phy8806x_tsc_display_eye_scan (const phymod_access_t *pa){
     57 	uint32_t stripe[64];
     58 	uint16_t status = 0;
     59 	int8_t y;
     60 
     61 	EFUN(phy8806x_tsc_display_eye_scan_header (pa, 1));
     62 	/* start horizontal acquisition */
     63 	{   err_code_t err_code = phy8806x_tsc_meas_eye_scan_start (pa, EYE_SCAN_HORIZ);
     64 	    if (err_code)
     65 		    EFUN((phy8806x_tsc_meas_eye_scan_done (pa ), err_code)); }
     66 
     67 	/* display stripes */
     68 	for (y = 62; y >= -62; y = y - 2) {
     69 		{   err_code_t err_code = phy8806x_tsc_read_eye_scan_stripe (pa, &stripe[0], &status);
     70 		    if (err_code)
     71 			    EFUN((phy8806x_tsc_meas_eye_scan_done (pa ), err_code)); }
     72 		EFUN(phy8806x_tsc_display_eye_scan_stripe (pa, y, &stripe[0]));
     73 		EFUN_PRINTF(("\n"));
     74 	}
     75 	/* stop acquisition */
     76 	EFUN(phy8806x_tsc_meas_eye_scan_done (pa ));
     77 	EFUN(phy8806x_tsc_display_eye_scan_footer (pa, 1));
     78 
     79 	return ERR_CODE_NONE;
     80 }
     81 
     82 /* This function is for Falcon and is configured for passive mode */
     83 err_code_t phy8806x_tsc_meas_lowber_eye (const phymod_access_t *pa, const struct phy8806x_tsc_eyescan_options_st eyescan_options, uint32_t *buffer){
     84 	int8_t y, x;
     85 	int16_t i;
     86 	uint16_t status;
     87 	uint32_t errors = 0;
     88 	uint16_t timeout;
     89 	uint8_t stopped_state;
     90 
     91 	if (!buffer)
     92 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
     93 	i = 0;
     94 	ESTM(stopped_state = rdv_usr_sts_micro_stopped());
     95 
     96 	timeout = eyescan_options.timeout_in_milliseconds;
     97 	EFUN(wrcv_diag_max_time_control((uint8_t)timeout));
     98 
     99 	EFUN(wrv_usr_diag_mode(eyescan_options.mode));
    100 
    101 	EFUN_PRINTF(("Calculating\n"));
    102 	for (y = eyescan_options.vert_max; y >= eyescan_options.vert_min; y = y - eyescan_options.vstep) {
    103 		for (x = eyescan_options.horz_min; x <= eyescan_options.horz_max; x = x + eyescan_options.hstep) {
    104 			/* acquire sample */
    105 			EFUN(phy8806x_tsc_pmd_uc_cmd_with_data (pa, CMD_DIAG_EN, CMD_UC_DIAG_GET_EYE_SAMPLE, ((uint16_t)x) << 8 | (uint8_t)y, 200));
    106 			/* wait for sample complete */
    107 #if 0
    108 			do {
    109 				EFUN(phy8806x_tsc_delay_us(1000));
    110 				ESTM(status = rdv_usr_diag_status());
    111 				EFUN_PRINTF(("status=%04x\n", status));
    112 			} while ((status & 0x8000) == 0);
    113 #else
    114 			EFUN(phy8806x_tsc_poll_diag_done (pa, &status, (((uint32_t)timeout) << 7) * 10 + 20000));
    115 #endif
    116 			EFUN(phy8806x_tsc_prbs_err_count_ll (pa, &errors));
    117 			/* EFUN_PRINTF(("(%d,%d) = %u\n",x,y,errors & 0x7FFFFFF));    */
    118 
    119 			buffer[i] = errors & 0x7FFFFFFF;
    120 
    121 			i++;
    122 			EFUN_PRINTF(("."));
    123 		}
    124 		EFUN_PRINTF(("\n"));
    125 	}
    126 	EFUN_PRINTF(("\n"));
    127 	EFUN(phy8806x_tsc_meas_eye_scan_done (pa ));
    128 	EFUN(wrv_usr_sts_micro_stopped(stopped_state));
    129 	return ERR_CODE_NONE;
    130 }
    131 
    132 
    133 /* Display the LOW BER EyeScan */
    134 err_code_t phy8806x_tsc_display_lowber_eye (const phymod_access_t *pa, const struct phy8806x_tsc_eyescan_options_st eyescan_options, uint32_t *buffer){
    135 	int8_t x, y, i, z;
    136 	int16_t j; /* buffer pointer */
    137 	uint32_t val;
    138 	uint8_t overflow;
    139 	uint32_t limits[13]; /* allows upto 400 sec test time per point (1e-13 BER @ 10G) */
    140 
    141 	if (!buffer)
    142 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
    143 
    144 	/* Calculate initial total bitcount BER 1e-1 */
    145 	limits[0] = _mult_with_overflow_check (pa, eyescan_options.linerate_in_khz / 10, eyescan_options.timeout_in_milliseconds, &overflow);
    146 	if (overflow > 0) {
    147 		limits[0] = UINT32_MAX;
    148 		EFUN_PRINTF(("Very long timout_in_milliseconds results in saturation of Err counter can cause in accurate results\n"));
    149 	}
    150 
    151 	for (i = 1; i < 13; i++)   /* calculate thresholds */
    152 		limits[i] = limits[i - 1] / 10;
    153 
    154 	EFUN(phy8806x_tsc_display_eye_scan_header (pa, 1));
    155 	j = 0;
    156 	for (y = eyescan_options.vert_max; y >= eyescan_options.vert_min; y = y - eyescan_options.vstep) {
    157 		ESTM_PRINTF(("%6dmV : ", _ladder_setting_to_mV (pa, y, 0                 )));
    158 		for (z = -31; z < eyescan_options.horz_min; z++)
    159 			EFUN_PRINTF((" ")); /* add leading spaces if any */
    160 		for (x = eyescan_options.horz_min; x <= eyescan_options.horz_max; x = x + eyescan_options.hstep) {
    161 /*        val = float8_to_int32(buffer[j); */
    162 			val = buffer[j];
    163 
    164 			for (i = 0; i < 13; i++) {
    165 				if ((val != 0) & ((val >= limits[i]) | (limits[i] == 0))) {
    166 					for (z = 1; z <= eyescan_options.hstep; z++) {
    167 						if (z == 1) {
    168 							if (i <= 8)
    169 								EFUN_PRINTF(("%c", '1' + i));
    170 							else
    171 								EFUN_PRINTF(("%c", 'A' + i - 9));
    172 						} else
    173 							EFUN_PRINTF((" "));
    174 					}
    175 					break;
    176 				}
    177 			}
    178 			if (i == 13) {
    179 				for (z = 1; z <= eyescan_options.hstep; z++) {
    180 					if (z == 1) {
    181 						if ((x % 5) == 0 && (y % 5) == 0)
    182 							EFUN_PRINTF(("+"));
    183 						else if ((x % 5) != 0 && (y % 5) == 0)
    184 							EFUN_PRINTF(("-"));
    185 						else if ((x % 5) == 0 && (y % 5) != 0)
    186 							EFUN_PRINTF((":"));
    187 						else
    188 							EFUN_PRINTF((" "));
    189 					} else
    190 						EFUN_PRINTF((" "));
    191 				}
    192 			}
    193 			j++;
    194 		}
    195 		EFUN_PRINTF(("\n"));
    196 	}
    197 	EFUN(phy8806x_tsc_display_eye_scan_footer (pa, 1));
    198 	return ERR_CODE_NONE;
    199 }
    200 
    201 err_code_t phy8806x_tsc_meas_eye_scan_start (const phymod_access_t *pa, uint8_t direction){
    202 	uint8_t lock;
    203 
    204 	ESTM(lock = rd_pmd_rx_lock());
    205 	if (lock == 0) {
    206 		EFUN_PRINTF(("Error: No PMD_RX_LOCK on lane requesting 2D eye scan\n"));
    207 		return ERR_CODE_DIAG_SCAN_NOT_COMPLETE;
    208 	}
    209 	if (direction == EYE_SCAN_VERTICAL)
    210 		EFUN(phy8806x_tsc_pmd_uc_diag_cmd (pa, CMD_UC_DIAG_START_VSCAN_EYE, 200));
    211 	else
    212 		EFUN(phy8806x_tsc_pmd_uc_diag_cmd (pa, CMD_UC_DIAG_START_HSCAN_EYE, 200));
    213 	return ERR_CODE_NONE;
    214 }
    215 
    216 err_code_t phy8806x_tsc_read_eye_scan_stripe (const phymod_access_t *pa, uint32_t *buffer, uint16_t *status){
    217 	uint32_t val[2] = { 0, 0 };
    218 	uint16_t sts = 0;
    219 	int8_t i;
    220 
    221 	if (!buffer || !status)
    222 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
    223 	*status = 0;
    224 	for (i = 0; i < 32; i++) {
    225 		{   err_code_t err_code = phy8806x_tsc_poll_diag_eye_data (pa, &val[0], &sts, 200);
    226 		    *status |= sts & 0xF000;
    227 		    if (err_code)
    228 			    return err_code; }
    229 		buffer[i * 2]     = val[0];
    230 		buffer[(i * 2) + 1] = val[1];
    231 	}
    232 	*status |= sts & 0x00FF;
    233 	return ERR_CODE_NONE;
    234 }
    235 
    236 err_code_t phy8806x_tsc_display_eye_scan_stripe (const phymod_access_t *pa, int8_t y, uint32_t *buffer){
    237 
    238 	const uint32_t limits[7] = { 1835008, 183501, 18350, 1835, 184, 18, 2 };
    239 
    240 	int8_t x, i;
    241 	int16_t level;
    242 
    243 	/* ESTM(data_thresh = rd_rx_data_thresh_sel()); */
    244 	level = _ladder_setting_to_mV (pa, y, 0);
    245 
    246 	if (!buffer)
    247 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
    248 
    249 	EFUN_PRINTF(("%6dmV : ", level));
    250 
    251 	for (x = -31; x < 32; x++) {
    252 		for (i = 0; i < 7; i++)
    253 			if (buffer[x + 31] >= limits[i]) {
    254 				EFUN_PRINTF(("%c", '0' + i + 1));
    255 				break;
    256 			}
    257 		if (i == 7) {
    258 			if ((x % 5) == 0 && (y % 5) == 0) EFUN_PRINTF(("+")); else if ((x % 5) != 0 && (y % 5) == 0) EFUN_PRINTF(("-")); else if ((x % 5) == 0 && (y % 5) != 0) EFUN_PRINTF((":")); else EFUN_PRINTF((" "));
    259 		}
    260 	}
    261 	return ERR_CODE_NONE;
    262 }
    263 
    264 err_code_t phy8806x_tsc_display_eye_scan_header (const phymod_access_t *pa, int8_t i){
    265 	int8_t x;
    266 
    267 	EFUN_PRINTF(("\n"));
    268 	EFUN_PRINTF((" Each character N represents approximate error rate 1e-N at that location\n"));
    269 	for (x = 1; x <= i; x++)
    270 		EFUN_PRINTF(("  UI/64  : -30  -25  -20  -15  -10  -5    0    5    10   15   20   25   30"));
    271 	EFUN_PRINTF(("\n"));
    272 	for (x = 1; x <= i; x++)
    273 		EFUN_PRINTF(("         : -|----|----|----|----|----|----|----|----|----|----|----|----|-"));
    274 	EFUN_PRINTF(("\n"));
    275 	return ERR_CODE_NONE;
    276 }
    277 
    278 err_code_t phy8806x_tsc_display_eye_scan_footer (const phymod_access_t *pa, int8_t i){
    279 	int8_t x;
    280 
    281 	for (x = 1; x <= i; x++)
    282 		EFUN_PRINTF(("         : -|----|----|----|----|----|----|----|----|----|----|----|----|-"));
    283 	EFUN_PRINTF(("\n"));
    284 	for (x = 1; x <= i; x++)
    285 		EFUN_PRINTF(("  UI/64  : -30  -25  -20  -15  -10  -5    0    5    10   15   20   25   30"));
    286 	EFUN_PRINTF(("\n"));
    287 	return ERR_CODE_NONE;
    288 }
    289 
    290 
    291 /*eye_scan_status_t phy8806x_tsc_read_eye_scan_status (pa, void) */
    292 err_code_t phy8806x_tsc_read_eye_scan_status (const phymod_access_t *pa, uint16_t *status){
    293 
    294 	if (!status)
    295 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
    296 
    297 	ESTM(*status = rdv_usr_diag_status());
    298 
    299 	return ERR_CODE_NONE;
    300 }
    301 
    302 
    303 err_code_t phy8806x_tsc_meas_eye_scan_done (const phymod_access_t *pa){
    304 	EFUN(phy8806x_tsc_pmd_uc_diag_cmd (pa, CMD_UC_DIAG_DISABLE, 200));
    305 	return ERR_CODE_NONE;
    306 }
    307 
    308 
    309 err_code_t phy8806x_tsc_start_ber_scan_test (const phymod_access_t *pa, uint8_t ber_scan_mode, uint8_t timer_control, uint8_t max_error_control){
    310 	uint8_t lock, sts;
    311 
    312 	ESTM(lock = rd_pmd_rx_lock());
    313 	if (lock == 0) {
    314 		EFUN_PRINTF(("Error: No PMD_RX_LOCK on lane requesting BER scan\n"));
    315 		return ERR_CODE_DIAG_SCAN_NOT_COMPLETE;
    316 	}
    317 	ESTM(sts = rdv_usr_sts_micro_stopped());
    318 	if (sts > 1) {
    319 		EFUN_PRINTF(("Error: Lane is busy (%d) requesting BER scan\n", sts));
    320 		return ERR_CODE_DIAG_SCAN_NOT_COMPLETE;
    321 	}
    322 
    323 	EFUN(wrcv_diag_max_time_control(timer_control));
    324 	EFUN(wrcv_diag_max_err_control(max_error_control));
    325 	EFUN(phy8806x_tsc_pmd_uc_cmd (pa, CMD_CAPTURE_BER_START, ber_scan_mode, 500));
    326 	return ERR_CODE_NONE;
    327 }
    328 
    329 err_code_t phy8806x_tsc_read_ber_scan_data (const phymod_access_t *pa, uint32_t *errors, uint32_t *timer_values, uint8_t *cnt, uint32_t timeout){
    330 	uint8_t i, prbs_byte, prbs_multi, time_byte, time_multi;
    331 	uint16_t sts, dataword;
    332 
    333 	if (!errors || !timer_values || !cnt)
    334 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
    335 	/* init data arrays */
    336 	for (i = 0; i < DIAG_MAX_SAMPLES; i++) {
    337 		errors[i] = 0;
    338 		timer_values[i] = 0;
    339 	}
    340 	/* Check for completion read ln.diag_status byte?*/
    341 	ESTM(sts = rdv_usr_diag_status());
    342 	if ((sts & 0x8000) == 0)
    343 		return _error(ERR_CODE_DATA_NOTAVAIL);
    344 	*cnt = (sts & 0x00FF) / 3;
    345 	for (i = 0; i < *cnt; i++) {
    346 		/* Read 2 bytes of data */
    347 		EFUN(phy8806x_tsc_pmd_uc_cmd (pa,  CMD_READ_DIAG_DATA_WORD, 0, timeout));
    348 		ESTM(dataword = rd_uc_dsc_data());      /* LSB contains 2 -4bit nibbles */
    349 		time_byte = (uint8_t)(dataword >> 8);   /* MSB is time byte */
    350 		prbs_multi = (uint8_t)dataword & 0x0F;  /* split nibbles */
    351 		time_multi = (uint8_t)dataword >> 4;
    352 		/* Read 1 bytes of data */
    353 		EFUN(phy8806x_tsc_pmd_uc_cmd (pa,  CMD_READ_DIAG_DATA_BYTE, 0, timeout));
    354 		ESTM(prbs_byte = (uint8_t)rd_uc_dsc_data());
    355 		errors[i] = _float12_to_uint32 (pa, prbs_byte, prbs_multi); /* convert 12bits to uint32 */
    356 		timer_values[i] = (_float12_to_uint32 (pa, time_byte, time_multi) << 3);
    357 		/*  EFUN_PRINTF(("Err=%d (%02x<<%d); Time=%d (%02x<<%d)\n",errors[i],prbs_byte,prbs_multi,timer_values[i],time_byte,time_multi<<3)); */
    358 		/*if(timer_values[i] == 0 && errors[i] == 0) break;*/
    359 	}
    360 
    361 	return ERR_CODE_NONE;
    362 }
    363 
    364 
    365 /* This is good example function to do BER extrapolation */
    366 err_code_t phy8806x_tsc_eye_margin_proj (const phymod_access_t *pa, USR_DOUBLE rate, uint8_t ber_scan_mode, uint8_t timer_control, uint8_t max_error_control){
    367 	uint32_t errs[DIAG_MAX_SAMPLES];
    368 	uint32_t time[DIAG_MAX_SAMPLES];
    369 	uint8_t i, cnt;
    370 	uint16_t sts;
    371 	int16_t offset_start;
    372 	/* Below 'verbose' level is intended to be modified only within a debug */
    373 	/* session immediately after a breakpoint, and to retain its state only */
    374 	/* through function exit:  therefore it must be 'volatile' to prevent a */
    375 	/* compiler from eliding code conditioned on it, but NOT 'static'.      */
    376 	uint8_t volatile verbose = 0;
    377 
    378 
    379 	for (i = 0; i < DIAG_MAX_SAMPLES; i++) {
    380 		errs[i] = 0;
    381 		time[i] = 0;
    382 	}
    383 	/* start UC acquisition */
    384 	if (verbose > 2) EFUN_PRINTF(("start begin\n"));
    385 	EFUN(phy8806x_tsc_start_ber_scan_test (pa, ber_scan_mode, timer_control, max_error_control));
    386 	ESTM(offset_start = rd_uc_dsc_data());
    387 	if (verbose > 2) EFUN_PRINTF(("offset_start = %d:%dmV\n", offset_start, _ladder_setting_to_mV (pa, (int8_t)offset_start, 0)));
    388 	if (verbose > 2) EFUN_PRINTF(("start done\n"));
    389 
    390 	/* This wait is VERY LONG and should be replaced with interupt or something */
    391 	if (verbose > 5) {
    392 		do {
    393 			EFUN(phy8806x_tsc_delay_us(2000000));
    394 			ESTM(sts = rdv_usr_diag_status());
    395 			EFUN_PRINTF(("sts=%04x\n", sts));
    396 
    397 		} while ((sts & 0x8000) == 0);
    398 	} else {
    399 		EFUN_PRINTF(("Waiting for measurement time approx %d seconds", timer_control + (timer_control >> 1)));
    400 		EFUN(phy8806x_tsc_poll_diag_done (pa, &sts, timer_control * 2000));
    401 	}
    402 	if (verbose > 2) EFUN_PRINTF(("delay done\n"));
    403 
    404 	EFUN(phy8806x_tsc_read_ber_scan_data (pa,  &errs[0], &time[0], &cnt, 2000));
    405 
    406 	if (verbose > 2) EFUN_PRINTF(("read done cnt=%d\n", cnt));
    407 
    408 	EFUN(phy8806x_tsc_pmd_uc_cmd (pa, CMD_CAPTURE_BER_END, 0x00, 50));
    409 
    410 	if (verbose > 2) EFUN_PRINTF(("end function done\n"));
    411 	/* if(cnt == 1) {                                                     */
    412 	/*     EFUN_PRINTF(("Not enough points found to extrapolate BER\n")); */
    413 	/*     return(ERR_CODE_NONE);                                         */
    414 	/* }                                                                  */
    415 
    416 	EFUN(phy8806x_tsc_display_ber_scan_data (pa, rate, ber_scan_mode, &errs[0], &time[0], (uint8_t)_abs(offset_start)));
    417 
    418 	if (verbose > 2) EFUN_PRINTF(("display done\n"));
    419 
    420 	return ERR_CODE_NONE;
    421 }
    422 
    423 
    424 
    425 err_code_t phy8806x_tsc_display_ber_scan_data (const phymod_access_t *pa, USR_DOUBLE rate, uint8_t ber_scan_mode, uint32_t *total_errs, uint32_t *total_time, uint8_t max_offset){
    426 
    427 #ifdef SERDES_API_FLOATING_POINT
    428 	/* 'margins_mv[]' vector maps the p1 threshold code with actual mV
    429 	    Only relevant when mode=0
    430 	    This is not totally linear: for code 0~25 step=6mV; code 25~30 step=18mV; code 30~31 step=12
    431 	    'margins_mv[]' is valid only for Merlin. This vector would need to be modified accordingly for different Serdes
    432 	   USR_DOUBLE margins_mv[] = {0,6,12,18,24,30,36,42,48,54,60,66,72,78,84,
    433 	                       90,96,102,108,114,120,126,132,138,144,150,168,186,204,222,240,252};
    434 	   const USR_DOUBLE narrow_margins_mv[] = {0,3.6,7.2,10.8,14.4,18,21.6,25.5,28.8,32.4,36,39.6,43.2,46.8,50.4,
    435 	                                    54,57.6,61.2,64.8,68.4,72,75.6,79.2,82.8,86.4,90,100.8,111.6,122.4,133.2,144,151.2}; */
    436 	const unsigned int HI_CONFIDENCE_ERR_CNT = 100;         /* bit errors */
    437 	const unsigned int HI_CONFIDENCE_MIN_ERR_CNT = 20;      /* bit errors */
    438 	const unsigned int MAX_CLIPPED_ERR_CNT = 8355840;
    439 	const USR_DOUBLE ARTIFICIAL_BER = 0.5;                  /* used along ARTIFICIAL_MARGIN(_V/_H) when not enough points to extrapolate */
    440 	const int ARTIFICIAL_MARGIN_V = 500;                    /* Used along ARTIFICIAL_BER when not enough points to extrapolate. Unit: mV. Based on the concept of max Vpp of 1 Volt */
    441 	const int ARTIFICIAL_MARGIN_H = 1;                      /* Used along ARTIFICIAL_BER when not enough points to extrapolate. Unit: UI. Based on the concept of two consecutive scrambled bits (1 UI appart) being uncorrelated */
    442 	const int MIN_BER_TO_REPORT = -24;                      /* we clip the projected BER using this number */
    443 	const USR_DOUBLE MIN_BER_FOR_FIT = -8.0;                /*    all points with BER <= 10^MIN_BER_FOR_FIT will be used for line fit (i.e used for extrapolation) */
    444 	const int8_t verbose = 1;                               /* set verbosity to 1 for normal API operation */
    445 
    446 	/* BER confidence scale */
    447 	const USR_DOUBLE ber_conf_scale[104] = {
    448 		2.9957, 5.5717, 3.6123, 2.9224, 2.5604, 2.3337, 2.1765, 2.0604, 1.9704, 1.8983,
    449 		1.8391, 1.7893, 1.7468, 1.7100, 1.6778, 1.6494, 1.6239, 1.6011, 1.5804, 1.5616,
    450 		1.5444, 1.5286, 1.5140, 1.5005, 1.4879, 1.4762, 1.4652, 1.4550, 1.4453, 1.4362,
    451 		1.4276, 1.4194, 1.4117, 1.4044, 1.3974, 1.3908, 1.3844, 1.3784, 1.3726, 1.3670,
    452 		1.3617, 1.3566, 1.3517, 1.3470, 1.3425, 1.3381, 1.3339, 1.3298, 1.3259, 1.3221,
    453 		1.3184, 1.3148, 1.3114, 1.3080, 1.3048, 1.3016, 1.2986, 1.2956, 1.2927, 1.2899,
    454 		1.2872, 1.2845, 1.2820, 1.2794, 1.2770, 1.2746, 1.2722, 1.2700, 1.2677, 1.2656,
    455 		1.2634, 1.2614, 1.2593, 1.2573, 1.2554, 1.2535, 1.2516, 1.2498, 1.2481, 1.2463,
    456 		1.2446, 1.2429, 1.2413, 1.2397, 1.2381, 1.2365, 1.2350, 1.2335, 1.2320, 1.2306,
    457 		1.2292, 1.2278, 1.2264, 1.2251, 1.2238, 1.2225, 1.2212, 1.2199, 1.2187, 1.2175,
    458 		1.2163, /* starts in index: 100 for #errors: 100,200,300,400 */
    459 		1.1486, /* 200 */
    460 		1.1198, /* 300 */
    461 		1.1030
    462 	};              /*400 */
    463 
    464 
    465 	/* Define variables */
    466 	USR_DOUBLE lbers[DIAG_MAX_SAMPLES];             /* Internal linear scale sqrt(-log(ber)) */
    467 	USR_DOUBLE margins[DIAG_MAX_SAMPLES];           /* Eye margin @ each measurement */
    468 	USR_DOUBLE bers[DIAG_MAX_SAMPLES];              /* computed bit error rate */
    469 	uint32_t i;
    470 	int8_t offset[DIAG_MAX_SAMPLES];
    471 	int8_t mono_flags[DIAG_MAX_SAMPLES];
    472 
    473 	int8_t direction;
    474 	uint8_t heye;
    475 	int8_t delta_n;
    476 	USR_DOUBLE Exy = 0.0;
    477 	USR_DOUBLE Eyy = 0.0;
    478 	USR_DOUBLE Exx = 0.0;
    479 	USR_DOUBLE Ey  = 0.0;
    480 	USR_DOUBLE Ex  = 0.0;
    481 	USR_DOUBLE alpha = 0.0;
    482 	USR_DOUBLE gauss_noise = -1;
    483 	USR_DOUBLE beta = 0.0;
    484 	USR_DOUBLE sq_r = 0.0, alpha2 = 0.0;
    485 	USR_DOUBLE proj_ber = 0.0, proj_ber_aux = 0.0;
    486 	USR_DOUBLE proj_margin_12 = 0.0;
    487 	USR_DOUBLE proj_margin_15 = 0.0;
    488 	USR_DOUBLE proj_margin_18 = 0.0;
    489 	USR_DOUBLE sq_err1 = 0.0, sq_err2 = 0.0;
    490 	USR_DOUBLE ierr;
    491 	uint8_t start_n;
    492 	uint8_t stop_n;
    493 	uint8_t low_confidence;
    494 	uint8_t loop_index;
    495 	uint8_t n_mono = 0;
    496 	uint8_t eye_cnt = 1;
    497 	uint8_t hi_confidence_cnt = 0;
    498 	int8_t first_good_ber_idx = -1;
    499 	int8_t first_small_errcnt_idx = -1;
    500 	int8_t first_non_clipped_errcnt_idx = -1;
    501 	uint8_t range250;
    502 	uint8_t intrusive;
    503 	uint8_t ber_clipped = 0;
    504 	uint8_t last_point_discard;
    505 	uint8_t fit_count;
    506 	int artificial_margin;
    507 	int proj_case = 0; /* this variable will be used to signal what particular extrapolation case has happened at the end (after discarding invalid points of all sorts). To avoid potential issues: NEVER RE-USE VALUES... new cases should receive brand-new integer value */
    508 	USR_DOUBLE artificial_lber;
    509 	char message[256] = "NO MESSAGE";
    510 	char unit[5];
    511 
    512 	if (!total_errs || !total_time )
    513 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
    514 
    515 	/* Initialize BER array */
    516 	for (i = 0; i < DIAG_MAX_SAMPLES; i++) {
    517 		bers[i] = 0;
    518 		mono_flags[i] = 0;
    519 	}
    520 
    521 	/* Decode mode/direction/etc. */
    522 	heye = (ber_scan_mode & DIAG_BER_HORZ) >> 1;
    523 	direction = (ber_scan_mode & DIAG_BER_NEG) ? -1 : 1;
    524 	range250 = (ber_scan_mode & DIAG_BER_P1_NARROW) ? 0 : 1;
    525 	intrusive = (ber_scan_mode & DIAG_BER_INTR) ? 1 : 0;
    526 
    527 	/* Prepare artificial points in case they are needed */
    528 	if (heye == 1)
    529 		artificial_margin = direction * ARTIFICIAL_MARGIN_H;
    530 	else
    531 		artificial_margin = direction * ARTIFICIAL_MARGIN_V;
    532 	artificial_lber = (USR_DOUBLE)sqrt(-log10(ARTIFICIAL_BER));
    533 
    534 	/* Printing on-screen message */
    535 	if (heye == 1) {
    536 		if (verbose > 0) {
    537 			if (direction == -1) EFUN_PRINTF(("\n\n********** HORIZONTAL PROJECTION: LEFT SIDE ******************\n"));
    538 			if (direction == 1) EFUN_PRINTF(("\n\n********** HORIZONTAL PROJECTION: RIGHT SIDE *****************\n"));
    539 		}
    540 	} else {
    541 		if (verbose > 0) {
    542 			if (direction == -1) EFUN_PRINTF(("\n\n********** VERTICAL PROJECTION: BOTTOM ***********************\n"));
    543 			if (direction == 1) EFUN_PRINTF(("\n\n********** VERTICAL PROJECTION: TOP **************************\n"));
    544 		}
    545 	}
    546 
    547 	/* *******************************************
    548 	* Generate margins[]
    549 	* Generate ber[]
    550 	* Find first and last points for linear fit
    551  */
    552 	i = 0;
    553 	do {
    554 		if (heye == 1) {
    555 			ENULL_STRCPY(unit, "mUI");
    556 			offset[i] = (int8_t)(max_offset - i);
    557 #ifndef STANDALONE_EVENT
    558 			margins[i] = direction * offset[i] * 1000.0 / 64.0;
    559 #else
    560 			margins[i] = info_out->margins[i];
    561 #endif
    562 		} else {
    563 			ENULL_STRCPY(unit, "mV");
    564 			offset[i] = (int8_t)(max_offset - i);
    565 #ifndef STANDALONE_EVENT
    566 			if (intrusive)
    567 				margins[i] = direction * _ladder_setting_to_mV (pa, offset[i], 0);
    568 			else
    569 				margins[i] = direction * _ladder_setting_to_mV (pa, offset[i], range250);
    570 
    571 #else
    572 			margins[i] = info_out->margins[i];
    573 #endif
    574 		}
    575 		if (total_errs[i] == 0)
    576 			bers[i] = 1.0 / (((USR_DOUBLE)total_time[i]) * 0.00001 * rate);
    577 		else
    578 			bers[i] = (USR_DOUBLE)total_errs[i] / (((USR_DOUBLE)total_time[i]) * 0.00001 * rate);
    579 
    580 		/* Find the first data point with good BER (BER <= 10^MIN_BER_FOR_FIT)
    581 		   NOTE: no need for lower bound on BER, since correction factors will be applied for all total_errs>=0 */
    582 		if ((log10(bers[i]) <= MIN_BER_FOR_FIT) && (first_good_ber_idx == -1))
    583 			first_good_ber_idx = (int8_t)i;
    584 
    585 		/* Determine high-confidence iterations */
    586 		if (total_errs[i] >= HI_CONFIDENCE_ERR_CNT)
    587 			hi_confidence_cnt++;
    588 		else if ((total_errs[i] < HI_CONFIDENCE_MIN_ERR_CNT) && (first_small_errcnt_idx == -1))
    589 			/* find the first data point with small error count */
    590 			first_small_errcnt_idx = (int8_t)i;
    591 
    592 		/* Determine first NON-clipped error count
    593 		    NOTE: Originally this limit was created for post processing of micro-generated data; however, this could be used for PC-generated data as well */
    594 		if ((total_errs[i] < MAX_CLIPPED_ERR_CNT) && (first_non_clipped_errcnt_idx == -1) )
    595 			first_non_clipped_errcnt_idx = (int8_t)i;
    596 
    597 		i++;
    598 
    599 	} while (((total_errs[i] != 0) || (total_time[i] != 0)) && (i <= max_offset));
    600 
    601 	eye_cnt = (int8_t)i;
    602 
    603 
    604 	/* *******************************************
    605 	   Setting up stop_n variable.
    606 	   Check if:
    607 	    - There is only one point in measurement vector (i.e. eye_cnt = 1)
    608 	    - The very last point's measurement time was "too short"
    609  */
    610 
    611 	i = eye_cnt - 1;
    612 	if (i >= 1) {
    613 		if ((total_time[i] >= 0.5 * total_time[i - 1]) || (total_errs[i] >= HI_CONFIDENCE_MIN_ERR_CNT) ) {
    614 			stop_n = eye_cnt; /* last point will be included in linear fit */
    615 			last_point_discard = 0;
    616 		} else {
    617 			stop_n = eye_cnt - 1; /* discards the very last point */
    618 			last_point_discard = 1;
    619 		}
    620 	} else
    621 		stop_n = 1; /* there is ONLY one measurement */
    622 
    623 
    624 	/* *******************************************
    625 	   Print on screen (prints RAW BER data. i.e. conf factors)
    626  */
    627 	if (verbose > 0) {
    628 		i = 0;
    629 		do {
    630 			if (total_errs[i] == 0)
    631 				EFUN_PRINTF(("BER @ %4.0f %s < 1e%-6.2f (%u errors in %0.2f sec)\n", margins[i], unit, log10(bers[i]), total_errs[i], ((USR_DOUBLE)total_time[i]) * 0.00001));
    632 			else if (total_errs[i] >= MAX_CLIPPED_ERR_CNT)
    633 				EFUN_PRINTF(("BER @ %4.0f %s > 1e%-6.2f (%u errors in %0.2f sec)\n", margins[i], unit, log10(bers[i]), total_errs[i], ((USR_DOUBLE)total_time[i]) * 0.00001));
    634 			else
    635 				EFUN_PRINTF(("BER @ %4.0f %s = 1e%-6.2f (%u errors in %0.2f sec)\n", margins[i], unit, log10(bers[i]), total_errs[i], ((USR_DOUBLE)total_time[i]) * 0.00001));
    636 			i++;
    637 		} while (i < stop_n);
    638 	}
    639 
    640 	/* *******************************************
    641 	   Correcting *all* BER values using confidence factors in 'ber_conf_scale' vector
    642 	   This step is done for extrapolation purposes
    643  */
    644 	for (loop_index = 0; loop_index < eye_cnt; loop_index++) {
    645 		if (total_errs[loop_index] <= 100)
    646 			bers[loop_index] = ber_conf_scale[total_errs[loop_index]] * bers[loop_index];
    647 		else if (total_errs[loop_index] > 100 && total_errs[loop_index] < 200)
    648 			bers[loop_index] = ber_conf_scale[100] * bers[loop_index];
    649 		else if (total_errs[loop_index] >= 200 && total_errs[loop_index] < 300)
    650 			bers[loop_index] = ber_conf_scale[101] * bers[loop_index];
    651 		else if (total_errs[loop_index] >= 300 && total_errs[loop_index] < 400)
    652 			bers[loop_index] = ber_conf_scale[102] * bers[loop_index];
    653 		else if (total_errs[loop_index] >= 400)
    654 			bers[loop_index] = ber_conf_scale[103] * bers[loop_index];
    655 	}
    656 
    657 	/* *******************************************
    658 	   Computes the "linearised" ber vector
    659  */
    660 	for (loop_index = 0; loop_index < eye_cnt; loop_index++)
    661 		lbers[loop_index] = (USR_DOUBLE)sqrt(-log10(bers[loop_index]));
    662 
    663 	/* *******************************************
    664 	   Assign highest data point to use
    665  */
    666 	if (first_good_ber_idx == -1)
    667 		start_n = stop_n;
    668 	else
    669 		start_n = first_good_ber_idx;
    670 
    671 
    672 
    673 	/* ******************************************************
    674 	***********  EXTRAPOLATION (START) **********************
    675 	*********************************************************
    676 	   Different data set profiles can be received by this code.
    677 	   Each case is processed accordingly here (IF-ELSE IF cases)
    678  */
    679 
    680 	/* ====> Errors encountered all the way to sampling point */
    681 	if (start_n >= eye_cnt) {
    682 		proj_case = 1;
    683 		ENULL_STRCPY(message, "No low-BER point measured");
    684 
    685 		/* confidence factor of 0.96 is applied in this case to set a LOWER bound and report accordingly.
    686 		    This factor corresponds to approximately 3000 errors @95% confidence
    687 		    For reference: factors for 900, 2000, 3000, 5000, 20000 and 50000 errors are: 0.96, 0.96, 0.97, 0.99, 0.99, respectively */
    688 		proj_ber = 0.96 * log10(bers[eye_cnt - 1]);
    689 		proj_ber_aux = proj_ber;
    690 		EFUN_PRINTF(("BER *worse* than 1e%0.2f\n", proj_ber));
    691 		EFUN_PRINTF(("No margin @ 1e-12, 1e-15 & 1e-18\n\n\n"));
    692 		fit_count = 1;
    693 	}else  {
    694 
    695 		/* ====> Only ONE measured point. Typically when the eye is wide open.
    696 		    Artificial points will be used to make extrapolation possible */
    697 		if (stop_n == 1) {
    698 			proj_case = 2;
    699 			ENULL_STRCPY(message, "Not enough points (single measured point). Using artificial point");
    700 
    701 			low_confidence = 1;
    702 			delta_n = 1; /* 'delta_n' and 'fit_count' variables were kept for future use in case a new approach to handle low confidence case is adopted */
    703 			fit_count = 2;
    704 
    705 			/* Compute covariances and means... but only for two points: artificial and the single measured point */
    706 			Exy = ((margins[0] * lbers[0] + artificial_margin * artificial_lber) / 2.0);
    707 			Eyy = ((lbers[0] * lbers[0] + artificial_lber * artificial_lber) / 2.0);
    708 			Exx = ((margins[0] * margins[0] + artificial_margin * artificial_margin) / 2.0);
    709 			Ey  = ((lbers[0] + artificial_lber) / 2.0);
    710 			Ex  = ((margins[0] + artificial_margin) / 2.0);
    711 		}
    712 		/* ====> "NORMAL" case (when there are more than 1 measurements) */
    713 		else {
    714 
    715 			/* Detect and record nonmonotonic data points */
    716 			for (loop_index = 0; loop_index < stop_n; loop_index++) {
    717 				if ((loop_index > start_n) && (log10(bers[loop_index]) > log10(bers[loop_index - 1]))) {
    718 					mono_flags[loop_index] = 1;
    719 					if (first_good_ber_idx != -1)
    720 						n_mono++;
    721 				}
    722 			}
    723 
    724 			/* Finds number of MEASURED points available for extrapolation */
    725 			delta_n = (stop_n - start_n - n_mono);
    726 
    727 
    728 			/*    HIGH CONFIDENCE case */
    729 
    730 			if (delta_n >= 2) { /* there are at least 2 points to trace a line */
    731 				proj_case = 3;
    732 				ENULL_STRCPY(message, "Normal case");
    733 				low_confidence = 0;
    734 
    735 				/* Compute covariances and means */
    736 				fit_count = 0;
    737 				for (loop_index = start_n; loop_index < stop_n; loop_index++) {
    738 					if (mono_flags[loop_index] == 0) {
    739 						Exy += (margins[loop_index] * lbers[loop_index] / (USR_DOUBLE)delta_n);
    740 						Eyy += (lbers[loop_index] * lbers[loop_index] / (USR_DOUBLE)delta_n);
    741 						Exx += (margins[loop_index] * margins[loop_index] / (USR_DOUBLE)delta_n);
    742 						Ey  += (lbers[loop_index] / (USR_DOUBLE)delta_n);
    743 						Ex  += (margins[loop_index] / (USR_DOUBLE)delta_n);
    744 						fit_count++;
    745 					}
    746 				}
    747 			}
    748 			/*    LOW CONFIDENCE case */
    749 			else {  /*    NEW APPROACH (08/28/2014): consider very first point (error count < MAX_CLIPPED_ERR_CNT) and very last point for linear fit. This will give pessimistic/conservative extrapolation */
    750 				low_confidence = 1;
    751 				if ( (first_non_clipped_errcnt_idx >= 0) && (first_non_clipped_errcnt_idx < start_n)) {
    752 					proj_case = 4;
    753 					ENULL_STRCPY(message, "Not enough points. Using first measured point for conservative estimation");
    754 					fit_count = 2;
    755 					/* Compute covariances and means... but only for two points: first and last */
    756 					Exy = ((margins[stop_n - 1] * lbers[stop_n - 1] + margins[first_non_clipped_errcnt_idx] * lbers[first_non_clipped_errcnt_idx]) / 2.0);
    757 					Eyy = ((lbers[stop_n - 1] * lbers[stop_n - 1] + lbers[first_non_clipped_errcnt_idx] * lbers[first_non_clipped_errcnt_idx]) / 2.0);
    758 					Exx = ((margins[stop_n - 1] * margins[stop_n - 1] + margins[first_non_clipped_errcnt_idx] * margins[first_non_clipped_errcnt_idx]) / 2.0);
    759 					Ey  = ((lbers[stop_n - 1] + lbers[first_non_clipped_errcnt_idx]) / 2.0);
    760 					Ex  = ((margins[stop_n - 1] + margins[first_non_clipped_errcnt_idx]) / 2.0);
    761 				} else {
    762 					proj_case = 5;
    763 					ENULL_STRCPY(message, "Not enough points (cannot use non-clipped ErrorCount point). Using artificial point");
    764 					/* Compute covariances and means... but only for two points: artificial and the single measured point */
    765 					Exy = (artificial_margin * artificial_lber) / 2.0;
    766 					Eyy = (artificial_lber * artificial_lber) / 2.0;
    767 					Exx = (artificial_margin * artificial_margin) / 2.0;
    768 					Ey  = (artificial_lber) / 2.0;
    769 					Ex  = (artificial_margin) / 2.0;
    770 					fit_count = 1;
    771 					/* This FOR loop checks for monotonicity as well */
    772 					for (loop_index = start_n; loop_index < stop_n; loop_index++) {
    773 						if (mono_flags[loop_index] == 0) {
    774 							Exy += (margins[loop_index] * lbers[loop_index] / 2.0);
    775 							Eyy += (lbers[loop_index] * lbers[loop_index] / 2.0);
    776 							Exx += (margins[loop_index] * margins[loop_index] / 2.0);
    777 							Ey  += (lbers[loop_index] / 2.0);
    778 							Ex  += (margins[loop_index] / 2.0);
    779 							fit_count++;
    780 						}
    781 					}
    782 				}
    783 			}
    784 		}
    785 
    786 		/* Compute fit slope and offset: ber = alpha*margin + beta */
    787 		alpha = (Exy - Ey * Ex) / (Exx - Ex * Ex);
    788 		beta = Ey - Ex * alpha;
    789 		/* Compute alpha2: slope of regression: margin = alpha2*ber + beta2 */
    790 		alpha2 = (Exy - Ey * Ex) / (Eyy - Ey * Ey);
    791 		/* Compute correlation index sq_r */
    792 		sq_r = alpha * alpha2;
    793 
    794 		proj_ber = pow(10, (-beta * beta));
    795 		proj_margin_12 = direction * (sqrt(-log10(1e-12)) - beta) / alpha;
    796 		proj_margin_15 = direction * (sqrt(-log10(1e-15)) - beta) / alpha;
    797 		proj_margin_18 = direction * (sqrt(-log10(1e-18)) - beta) / alpha;
    798 
    799 		/* Estimate modeled gaussian noise.
    800 
    801 		    The following is based on the Q-function model and the following table:
    802 		        Q    |    log10(BER)
    803 		    =======================
    804 		      7.033    |    -12
    805 		      7.941    |    -15
    806 		      8.757    |    -18
    807 
    808 		   Based on the above, we solve for sigma:
    809 		    7.033*sigma = u - proj_margin_12 , and
    810 		    7.941*sigma = u - proj_margin_15
    811 		 */
    812 		gauss_noise = (proj_margin_12 - proj_margin_15) / 0.908;
    813 
    814 		sq_err1 = (Eyy + (beta * beta) + (Exx * alpha * alpha) -
    815 			   (2 * Ey * beta) - (2 * Exy * alpha) + (2 * Ex * beta * alpha));
    816 		sq_err2 = 0;
    817 		for (loop_index = start_n; loop_index < stop_n; loop_index++) {
    818 			ierr = (lbers[loop_index] - (alpha * margins[loop_index] + beta));
    819 			sq_err2 += (ierr * ierr / (USR_DOUBLE)delta_n);
    820 		}
    821 
    822 		proj_ber = log10(proj_ber);
    823 		proj_ber_aux = proj_ber;
    824 
    825 		if (proj_ber < MIN_BER_TO_REPORT) {
    826 			proj_ber = MIN_BER_TO_REPORT;
    827 			ber_clipped = 1;
    828 		}
    829 
    830 		/* Extrapolated results, low confidence */
    831 		if (low_confidence == 1) {
    832 
    833 			EFUN_PRINTF(("BER(extrapolated) < 1e%0.2f\n", proj_ber));
    834 			EFUN_PRINTF(("Margin @ 1e-12    > %0.2f %s\n", (proj_ber < -12) ? _abs(proj_margin_12) : 0, unit));
    835 			EFUN_PRINTF(("Margin @ 1e-15    > %0.2f %s\n", (proj_ber < -15) ? _abs(proj_margin_15) : 0, unit));
    836 			EFUN_PRINTF(("Margin @ 1e-18    > %0.2f %s\n", (proj_ber < -18) ? _abs(proj_margin_18) : 0, unit));
    837 
    838 			/* Extrapolated results, HIGH confidence */
    839 		} else {
    840 
    841 			if (ber_clipped == 1)
    842 				EFUN_PRINTF(("BER(extrapolated) < 1e%0.2f\n", proj_ber));
    843 			else
    844 				EFUN_PRINTF(("BER(extrapolated) = 1e%0.2f\n", proj_ber));
    845 			EFUN_PRINTF(("Margin @ 1e-12    = %0.2f %s\n", (proj_ber < -12) ? _abs(proj_margin_12) : 0, unit));
    846 			EFUN_PRINTF(("Margin @ 1e-15    = %0.2f %s\n", (proj_ber < -15) ? _abs(proj_margin_15) : 0, unit));
    847 			EFUN_PRINTF(("Margin @ 1e-18    = %0.2f %s\n", (proj_ber < -18) ? _abs(proj_margin_18) : 0, unit));
    848 		}
    849 
    850 		EFUN_PRINTF(("\n\n"));
    851 
    852 		/* Print non-monotonic outliers */
    853 		if (n_mono != 0) {
    854 			EFUN_PRINTF(("Detected non-monotonicity at { "));
    855 			for (loop_index = start_n; loop_index < stop_n; loop_index++)
    856 				if (mono_flags[loop_index] == 1)
    857 					EFUN_PRINTF(("%0.2f ", margins[loop_index]));
    858 			EFUN_PRINTF(("} %s\n\n\n", unit));
    859 		}
    860 
    861 	}
    862 	/* *******************************************
    863 	 ***********  EXTRAPOLATION (END) *************
    864  */
    865 
    866 
    867 
    868 	/* SUMMARY (for debugging purposes */
    869 	if (verbose > 2) EFUN_PRINTF(("\t=====> DEBUG INFO (start)\n\n"));
    870 	if (verbose > 2) {
    871 		EFUN_PRINTF((" loop   Margin      total_errors   time(sec)  logBER       lber"));
    872 		for (loop_index = 0; loop_index < stop_n + last_point_discard; loop_index++)
    873 			EFUN_PRINTF(("\n%5d %11.0f %14d %10.3f %8.2f %10.3f", loop_index, margins[loop_index], total_errs[loop_index], ((USR_DOUBLE)total_time[loop_index]) * 0.00001, log10(bers[loop_index]), lbers[loop_index]));
    874 		EFUN_PRINTF(("\n\n"));
    875 	}
    876 	if (verbose > 2) EFUN_PRINTF(("Max Offset = %d\n", max_offset));
    877 	if (verbose > 2) EFUN_PRINTF(("ber_clipped: %d, Projected BER (proj_ber_aux) = %.2f\n", ber_clipped, proj_ber_aux));
    878 	if (verbose > 2) EFUN_PRINTF(("first good ber idx at %d, ber = 1e%f\n", first_good_ber_idx, ((first_good_ber_idx >= 0) ? log10(bers[first_good_ber_idx]) : 0.0)));
    879 	if (verbose > 2) EFUN_PRINTF(("first small errcnt idx at %d, errors = %d\n", first_small_errcnt_idx, ((first_small_errcnt_idx >= 0) ? total_errs[first_small_errcnt_idx] : -1)));
    880 	if (verbose > 2) EFUN_PRINTF(("last point discarded?: %d, low_confidence: %d, first_non_clipped_errcnt_idx: %d, start_n: %d, stop_n: %d, eye_cnt: %d, n_mono: %d, first_good_ber_idx = %d, first_small_errcnt_idx = %d, fit_count: %d, delta_n: %d\n",
    881 				      last_point_discard, low_confidence, first_non_clipped_errcnt_idx, start_n, stop_n, eye_cnt, n_mono, first_good_ber_idx, first_small_errcnt_idx, fit_count, delta_n));
    882 	if (verbose > 2) EFUN_PRINTF(("Exy=%.2f, Eyy=%.4f, Exx=%.2f, Ey=%.4f, Ex=%.2f, alpha=%.4f, beta=%.4f, alpha2=%.3f, sq_r=%.3f, sq_err1=%g, sq_err2=%g, gauss_noise=%.3f\n", Exy, Eyy, Exx, Ey, Ex, alpha, beta, alpha2, sq_r, sq_err1, sq_err2, gauss_noise));
    883 	if (verbose > 2) EFUN_PRINTF(("%s\n", message));
    884 	if (verbose > 2) EFUN_PRINTF(("proj_case %d\n", proj_case));
    885 	if (verbose > 2) EFUN_PRINTF(("\n\t=====> DEBUG INFO (end)\n\n"));
    886 	EFUN_PRINTF(("\n\n\n"));
    887 
    888 
    889 
    890 #else
    891 	(void)rate;
    892 	(void)ber_scan_mode;
    893 	(void)max_offset;
    894 
    895 	EFUN_PRINTF(("This function needs SERDES_API_FLOATING_POINT define to operate \n"));
    896 
    897 	if (!total_errs || !total_time )
    898 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
    899 
    900 #endif
    901 	return ERR_CODE_NONE;
    902 
    903 }
    904 
    905 
    906 
    907 
    908 /*****************************/
    909 /*  Display Lane/Core State  */
    910 /*****************************/
    911 
    912 err_code_t phy8806x_tsc_display_lane_state_hdr (const phymod_access_t *pa){
    913 	EFUN_PRINTF(("LN "));
    914 	EFUN_PRINTF(("(CDRxN      , UC_CFG,TX_RX_RST,STP,PLL)  "));
    915 
    916 	EFUN_PRINTF(("SD LCK RXPPM "));
    917 	EFUN_PRINTF(("CLK90 CLKP1 "));
    918 	EFUN_PRINTF(("PF(M,L)  "));
    919 	EFUN_PRINTF(("VGA DCO "));
    920 	EFUN_PRINTF(("P1mV "));
    921 	EFUN_PRINTF(("M1mV "));
    922 	EFUN_PRINTF((" DFE(1,2,3,4,5,6)        "));
    923 	EFUN_PRINTF(("TXPPM "));
    924 	EFUN_PRINTF(("TXEQ(n1,m,p1,2,3) "));
    925 	EFUN_PRINTF(("TXAMP "));
    926 	EFUN_PRINTF(("  EYE(L,R,U,D)  "));
    927 	EFUN_PRINTF(("LINK_TIME"));
    928 	EFUN_PRINTF(("\n"));
    929 	return ERR_CODE_NONE;
    930 }
    931 
    932 err_code_t phy8806x_tsc_display_lane_state_legend (const phymod_access_t *pa){
    933 	EFUN_PRINTF(("\n"));
    934 	EFUN_PRINTF(("**********************************************************************************************\n"));
    935 	EFUN_PRINTF(("****                Legend of Entries in display_lane_state()                             ****\n"));
    936 	EFUN_PRINTF(("**********************************************************************************************\n"));
    937 	EFUN_PRINTF(("LN        : lane index within IP core\n"));
    938 	EFUN_PRINTF(("CDRxN     : CDR type x OSR ratio\n"));
    939 	EFUN_PRINTF(("UC_CFG    : micro lane configuration variable\n"));
    940 	EFUN_PRINTF(("TX_RX_RST : TX and RX Reset State {reset_active, reset_occured, reset_held}\n"));
    941 	EFUN_PRINTF(("STP       : uC Stopped State\n"));
    942 	EFUN_PRINTF(("PLL       : TX and RX PLL select\n"));
    943 	EFUN_PRINTF(("SD        : signal detect\n"));
    944 	EFUN_PRINTF(("LCK       : pmd_rx_lock\n"));
    945 	EFUN_PRINTF(("RXPPM     : Frequency offset of local reference clock with respect to RX data in ppm\n"));
    946 	EFUN_PRINTF(("CLK90     : Delay of zero crossing slicer, m1, wrt to data in PI codes\n"));
    947 	EFUN_PRINTF(("CLKP1     : Delay of diagnostic/lms slicer, p1, wrt to data in PI codes\n"));
    948 	EFUN_PRINTF(("PF(M,L)   : Peaking Filter Main (0..15) and Low Frequency (0..7) settings\n"));
    949 	EFUN_PRINTF(("VGA       : Variable Gain Amplifier settings (0..39)\n"));
    950 	EFUN_PRINTF(("DCO       : DC offset DAC control value\n"));
    951 	EFUN_PRINTF(("P1mV      : Vertical threshold voltage of p1 slicer\n"));
    952 	EFUN_PRINTF(("M1mV      : Vertical threshold voltage of m1 slicer\n"));
    953 	EFUN_PRINTF(("DFE taps  : ISI correction taps in units of 2.35mV\n"));
    954 	EFUN_PRINTF(("TXPPM            : Frequency offset of local reference clock with respect to TX data in ppm\n"));
    955 	EFUN_PRINTF(("TXEQ(n1,m,p1,p2,p3) : TX equalization FIR tap weights in units of 1Vpp/160 units\n"));
    956 	EFUN_PRINTF(("TXAMP : TX amplitude, Drivermode\n"));
    957 	EFUN_PRINTF(("EYE(L,R,U,D)     : Eye margin @ 1e-5 as seen by internal diagnostic slicer in mUI and mV\n"));
    958 	EFUN_PRINTF(("LINK_TIME        : Link time in milliseconds\n"));
    959 	EFUN_PRINTF(("**********************************************************************************************\n"));
    960 	return ERR_CODE_NONE;
    961 }
    962 
    963 err_code_t phy8806x_tsc_display_lane_state (const phymod_access_t *pa){
    964 	err_code_t err_code = _phy8806x_tsc_display_lane_state_no_newline (pa );
    965 
    966 	EFUN_PRINTF(("\n"));
    967 	return err_code;
    968 }
    969 
    970 err_code_t phy8806x_tsc_get_eye_margin_est (const phymod_access_t *pa, int *left_eye_mUI, int *right_eye_mUI, int *upper_eye_mV, int *lower_eye_mV){
    971 	uint8_t ladder_range = 0;
    972 
    973 
    974 	ESTM(*left_eye_mUI = _eye_to_mUI (pa, rdv_usr_sts_heye_left()));
    975 	ESTM(*right_eye_mUI = _eye_to_mUI (pa, rdv_usr_sts_heye_right()));
    976 	ESTM(*upper_eye_mV = _eye_to_mV (pa, rdv_usr_sts_veye_upper(), ladder_range));
    977 	ESTM(*lower_eye_mV = _eye_to_mV (pa, rdv_usr_sts_veye_lower(), ladder_range));
    978 	return ERR_CODE_NONE;
    979 }
    980 
    981 err_code_t phy8806x_tsc_display_core_state_hdr (const phymod_access_t *pa){
    982 
    983 	EFUN_PRINTF(("SerDes type = %s\n", "phy8806x_tsc"));
    984 
    985 	EFUN_PRINTF(("CORE RST  ST  PLL_PWDN  UC_ATV   COM_CLK   UCODE_VER  AFE_VER   LIVE_TEMP   AVG_TMON   RESCAL     VCO_RATE     ANA_VCO_RANGE      PLL_DIV         PLL_LOCK\n"));
    986 	return ERR_CODE_NONE;
    987 }
    988 
    989 err_code_t phy8806x_tsc_display_core_state_line (const phymod_access_t *pa){
    990 	err_code_t err_code = _phy8806x_tsc_display_core_state_no_newline (pa );
    991 
    992 	EFUN_PRINTF(("\n"));
    993 	return err_code;
    994 }
    995 
    996 err_code_t phy8806x_tsc_display_core_state_legend (const phymod_access_t *pa){
    997 	EFUN_PRINTF(("\n"));
    998 	EFUN_PRINTF(("**************************************************************************************************************\n"));
    999 	EFUN_PRINTF(("****                          Legend of Entries in display_core_state()                                   ****\n"));
   1000 	EFUN_PRINTF(("**************************************************************************************************************\n"));
   1001 	EFUN_PRINTF(("*  RST              : Core DP Reset State{reset_active, reset_occured, reset_held}                           *\n"));
   1002 	EFUN_PRINTF(("*  ST               : Core uC Status byte(hex)                                                               *\n"));
   1003 	EFUN_PRINTF(("*  PLL_PWDN         : PLL Powerdown Control Bit (active high)                                                *\n"));
   1004 	EFUN_PRINTF(("*  UC_ATV           : UC Active bit                                                                          *\n"));
   1005 	EFUN_PRINTF(("*  COM_CLK          : COM Clock frequency in MHz                                                             *\n"));
   1006 	EFUN_PRINTF(("*  UCODE_VER        : Microcode Version [majorversion_minorversion]                                          *\n"));
   1007 	EFUN_PRINTF(("*  AFE_VER          : AFE Hardware Vesrion                                                                   *\n"));
   1008 	EFUN_PRINTF(("*  LIVE_TEMP        : Live Die temperature in Celsius                                                        *\n"));
   1009 	EFUN_PRINTF(("*  AVG_TMON         : uC Temp_idx, Average temperature in Celsius                                            *\n"));
   1010 	EFUN_PRINTF(("*  RESCAL           : Analog Resistor Calibration value                                                      *\n"));
   1011 	EFUN_PRINTF(("*  VCO_RATE         : uC VCO Rate in GHz (approximate)                                                       *\n"));
   1012 	EFUN_PRINTF(("*  ANA_VCO_RANGE    : Analog VCO Range                                                                       *\n"));
   1013 	EFUN_PRINTF(("*  PLL_DIV          : (Register Value) Actual PLL Divider Value                                              *\n"));
   1014 	EFUN_PRINTF(("*  PLL_Lock         : PLL Lock                                                                               *\n"));
   1015 
   1016 	EFUN_PRINTF(("**************************************************************************************************************\n"));
   1017 	return ERR_CODE_NONE;
   1018 }
   1019 
   1020 /**********************************************/
   1021 /*  Display Lane/Core Config and Debug Status */
   1022 /**********************************************/
   1023 
   1024 err_code_t phy8806x_tsc_display_core_config (const phymod_access_t *pa){
   1025     uint16_t vco_mhz, vco1_mhz;
   1026 	EFUN_PRINTF(("\n\n***********************************\n"  ));
   1027 	EFUN_PRINTF((    "**** SERDES CORE CONFIGURATION ****\n"  ));
   1028 	EFUN_PRINTF((    "***********************************\n\n"));
   1029 	{
   1030 		struct   phy8806x_tsc_uc_core_config_st core_cfg;
   1031 		struct   phy8806x_tsc_uc_core_config_st pll1_cfg;
   1032 
   1033 		ENULL_MEMSET(&pll1_cfg, 0, sizeof(pll1_cfg));
   1034 		ENULL_MEMSET(&core_cfg, 0, sizeof(core_cfg));
   1035 		{
   1036 			uint8_t pll_orig;
   1037 			ESTM(pll_orig = phy8806x_tsc_get_pll(pa));
   1038 			EFUN(phy8806x_tsc_set_pll(pa, 0));
   1039 			EFUN(phy8806x_tsc_get_uc_core_config (pa, &core_cfg));
   1040 			EFUN(phy8806x_tsc_set_pll(pa, 1));
   1041 			EFUN(phy8806x_tsc_get_uc_core_config (pa, &pll1_cfg));
   1042 			EFUN(phy8806x_tsc_set_pll(pa, pll_orig));
   1043 		}
   1044 		{
   1045 			vco_mhz = (uint16_t)core_cfg.vco_rate_in_Mhz;
   1046 			vco1_mhz = (uint16_t)pll1_cfg.vco_rate_in_Mhz;
   1047 			EFUN_PRINTF((    "uC Config VCO Rate   = %d (~%d.%03dGHz), %d (~%d.%03dGHz)\n", core_cfg.field.vco_rate
   1048 					 , (vco_mhz / 1000)
   1049 					 , (vco_mhz % 1000)
   1050 					 , pll1_cfg.field.vco_rate
   1051 					 , (vco1_mhz / 1000)
   1052 					 , (vco1_mhz % 1000)               ));
   1053 			EFUN_PRINTF((    "Core Config from PCS = %d, %d\n\n", core_cfg.field.core_cfg_from_pcs
   1054 					 , pll1_cfg.field.core_cfg_from_pcs));
   1055 		}
   1056 	}
   1057 	ESTM_PRINTF((    "Tx Lane Addr 0       = %d\n", rdc_tx_lane_addr_0()));
   1058 	ESTM_PRINTF((    "Rx Lane Addr 0       = %d\n", rdc_rx_lane_addr_0()));
   1059 	ESTM_PRINTF((    "Tx Lane Addr 1       = %d\n", rdc_tx_lane_addr_1()));
   1060 	ESTM_PRINTF((    "Rx Lane Addr 1       = %d\n", rdc_rx_lane_addr_1()));
   1061 	ESTM_PRINTF((    "Tx Lane Addr 2       = %d\n", rdc_tx_lane_addr_2()));
   1062 	ESTM_PRINTF((    "Rx Lane Addr 2       = %d\n", rdc_rx_lane_addr_2()));
   1063 	ESTM_PRINTF((    "Tx Lane Addr 3       = %d\n", rdc_tx_lane_addr_3()));
   1064 	ESTM_PRINTF((    "Rx Lane Addr 3       = %d\n", rdc_rx_lane_addr_3()));
   1065 	return ERR_CODE_NONE;
   1066 }
   1067 
   1068 
   1069 err_code_t phy8806x_tsc_display_lane_config (const phymod_access_t *pa){
   1070 	struct phy8806x_tsc_uc_lane_config_st lane_cfg;
   1071 
   1072 	ENULL_MEMSET(&lane_cfg, 0, sizeof(lane_cfg));
   1073 
   1074 	EFUN_PRINTF(("\n\n*************************************\n"                                          ));
   1075 	ESTM_PRINTF((   "**** SERDES LANE %d CONFIGURATION ****\n", phy8806x_tsc_get_lane (pa )                     ));
   1076 	EFUN_PRINTF((    "*************************************\n\n"                                        ));
   1077 	EFUN(                                                         phy8806x_tsc_get_uc_lane_cfg (pa, &lane_cfg)      );
   1078 	EFUN_PRINTF((    "Auto-Neg Enabled            = %d\n", lane_cfg.field.an_enabled             ));
   1079 	EFUN_PRINTF((    "DFE on                      = %d\n", lane_cfg.field.dfe_on                 ));
   1080 	EFUN_PRINTF((    "DFE low power mode          = %d\n", lane_cfg.field.dfe_lp_mode            ));
   1081 	EFUN_PRINTF((    "Brdfe_on                    = %d\n", lane_cfg.field.force_brdfe_on         ));
   1082 	EFUN_PRINTF((    "Media Type                  = %d\n", lane_cfg.field.media_type             ));
   1083 	EFUN_PRINTF((    "Unreliable LOS              = %d\n", lane_cfg.field.unreliable_los         ));
   1084 	EFUN_PRINTF((    "Scrambling Disable          = %d\n", lane_cfg.field.scrambling_dis         ));
   1085 	EFUN_PRINTF((    "Lane Config from PCS        = %d\n\n", lane_cfg.field.lane_cfg_from_pcs      ));
   1086 	EFUN_PRINTF((    "CL72 Auto Polarity   Enable = %d\n", lane_cfg.field.cl72_auto_polarity_en  ));
   1087 	EFUN_PRINTF((    "CL72 Restart timeout Enable = %d\n", lane_cfg.field.cl72_restart_timeout_en));
   1088 	EFUN_PRINTF((    "Enable Short Channel OSx1   = %d\n", lane_cfg.field.en_short_chn_osx1      ));
   1089 	ESTM_PRINTF((    "CL93/72 Training Enable     = %d\n", rd_cl93n72_ieee_training_enable()     ));
   1090 
   1091 	ESTM_PRINTF((    "PLL Select                  = %d\n\n", rd_pll_select()                       ));
   1092 	ESTM_PRINTF((    "EEE Mode Enable             = %d\n", rd_eee_mode_en()                      ));
   1093 	ESTM_PRINTF((    "OSR Mode Force              = %d\n", rd_osr_mode_frc()                     ));
   1094 	ESTM_PRINTF((    "OSR Mode Force Val          = %d\n", rd_osr_mode_frc_val()                 ));
   1095 	ESTM_PRINTF((    "TX Polarity Invert          = %d\n", rd_tx_pmd_dp_invert()                 ));
   1096 	ESTM_PRINTF((    "RX Polarity Invert          = %d\n\n", rd_rx_pmd_dp_invert()                 ));
   1097 	ESTM_PRINTF((    "TXFIR Post2                 = %d\n", rd_txfir_post2()                      ));
   1098 	ESTM_PRINTF((    "TXFIR Post3                 = %d\n", rd_txfir_post3()                      ));
   1099 	ESTM_PRINTF((    "TXFIR Main                  = %d\n", rd_cl93n72_txfir_main()               ));
   1100 	ESTM_PRINTF((    "TXFIR Pre                   = %d\n", rd_cl93n72_txfir_pre()                ));
   1101 	ESTM_PRINTF((    "TXFIR Post                  = %d\n", rd_cl93n72_txfir_post()               ));
   1102 	return ERR_CODE_NONE;
   1103 }
   1104 
   1105 
   1106 err_code_t phy8806x_tsc_display_core_state (const phymod_access_t *pa){
   1107 	EFUN(phy8806x_tsc_display_core_state_hdr (pa ));
   1108 	EFUN(phy8806x_tsc_display_core_state_line (pa ));
   1109 	EFUN(phy8806x_tsc_display_core_state_legend (pa ));
   1110 	return ERR_CODE_NONE;
   1111 }
   1112 
   1113 
   1114 
   1115 err_code_t phy8806x_tsc_display_lane_debug_status (const phymod_access_t *pa){
   1116 	/* startup */
   1117 	struct phy8806x_tsc_usr_ctrl_disable_functions_st ds;
   1118 	struct phy8806x_tsc_usr_ctrl_disable_dfe_functions_st dsd;
   1119 	/* steady state */
   1120 	struct phy8806x_tsc_usr_ctrl_disable_functions_st dss;
   1121 	struct phy8806x_tsc_usr_ctrl_disable_dfe_functions_st dssd;
   1122 
   1123 	ENULL_MEMSET(&ds, 0, sizeof(ds  ));
   1124 	ENULL_MEMSET(&dsd, 0, sizeof(dsd ));
   1125 	ENULL_MEMSET(&dss, 0, sizeof(dss ));
   1126 	ENULL_MEMSET(&dssd, 0, sizeof(dssd));
   1127 
   1128 	EFUN_PRINTF(("\n\n************************************\n"                                                     ));
   1129 	ESTM_PRINTF((   "**** SERDES LANE %d DEBUG STATUS ****\n", phy8806x_tsc_get_lane (pa )                   ));
   1130 	EFUN_PRINTF((    "************************************\n\n"                                                   ));
   1131 	ESTM_PRINTF((    "Restart Count                                = %d\n", rdv_usr_sts_restart_counter()       ));
   1132 	ESTM_PRINTF((    "Reset Count                                  = %d\n", rdv_usr_sts_reset_counter()         ));
   1133 	ESTM_PRINTF((    "PMD Lock Count                               = %d\n\n", rdv_usr_sts_pmd_lock_counter()      ));
   1134 	EFUN(phy8806x_tsc_get_usr_ctrl_disable_startup (pa, &ds));
   1135 	EFUN_PRINTF((    "Disable Startup PF Adaptation                = %d\n", ds.field.pf_adaptation              ));
   1136 	EFUN_PRINTF((    "Disable Startup PF2 Adaptation               = %d\n", ds.field.pf2_adaptation             ));
   1137 	EFUN_PRINTF((    "Disable Startup DC Adaptation                = %d\n", ds.field.dc_adaptation              ));
   1138 	EFUN_PRINTF((    "Disable Startup VGA Adaptation               = %d\n", ds.field.vga_adaptation             ));
   1139 	EFUN_PRINTF((    "Disable Startup Slicer vOffset Tuning        = %d\n", ds.field.slicer_voffset_tuning      ));
   1140 	EFUN_PRINTF((    "Disable Startup Slicer hOffset Tuning        = %d\n", ds.field.slicer_hoffset_tuning      ));
   1141 	EFUN_PRINTF((    "Disable Startup Phase offset Adaptation      = %d\n", ds.field.phase_offset_adaptation    ));
   1142 	EFUN_PRINTF((    "Disable Startup Eye Adaptaion                = %d\n", ds.field.eye_adaptation             ));
   1143 	EFUN_PRINTF((    "Disable Startup All Adaptaion                = %d\n\n", ds.field.all_adaptation             ));
   1144 	EFUN(                                                            phy8806x_tsc_get_usr_ctrl_disable_startup_dfe (pa, &dsd) );
   1145 	EFUN_PRINTF((    "Disable Startup DFE Tap1 Adaptation          = %d\n", dsd.field.dfe_tap1_adaptation       ));
   1146 	EFUN_PRINTF((    "Disable Startup DFE FX Taps Adaptation       = %d\n", dsd.field.dfe_fx_taps_adaptation    ));
   1147 	EFUN_PRINTF((    "Disable Startup DFE FL Taps Adaptation       = %d\n", dsd.field.dfe_fl_taps_adaptation    ));
   1148 	EFUN_PRINTF((    "Disable Startup DFE Tap DCD                  = %d\n", dsd.field.dfe_dcd_adaptation        ));
   1149 	EFUN(                                                           phy8806x_tsc_get_usr_ctrl_disable_steady_state (pa, &dss) );
   1150 	EFUN_PRINTF((    "Disable Steady State PF Adaptation           = %d\n", dss.field.pf_adaptation             ));
   1151 	EFUN_PRINTF((    "Disable Steady State PF2 Adaptation          = %d\n", dss.field.pf2_adaptation            ));
   1152 	EFUN_PRINTF((    "Disable Steady State DC Adaptation           = %d\n", dss.field.dc_adaptation             ));
   1153 	EFUN_PRINTF((    "Disable Steady State VGA Adaptation          = %d\n", dss.field.vga_adaptation            ));
   1154 	EFUN_PRINTF((    "Disable Steady State Slicer vOffset Tuning   = %d\n", dss.field.slicer_voffset_tuning     ));
   1155 	EFUN_PRINTF((    "Disable Steady State Slicer hOffset Tuning   = %d\n", dss.field.slicer_hoffset_tuning     ));
   1156 	EFUN_PRINTF((    "Disable Steady State Phase offset Adaptation = %d\n", dss.field.phase_offset_adaptation   ));
   1157 	EFUN_PRINTF((    "Disable Steady State Eye Adaptaion           = %d\n", dss.field.eye_adaptation            ));
   1158 	EFUN_PRINTF((    "Disable Steady State All Adaptaion           = %d\n\n", dss.field.all_adaptation            ));
   1159 	EFUN(                                                      phy8806x_tsc_get_usr_ctrl_disable_steady_state_dfe (pa, &dssd) );
   1160 	EFUN_PRINTF((    "Disable Steady State DFE Tap1 Adaptation     = %d\n", dssd.field.dfe_tap1_adaptation      ));
   1161 	EFUN_PRINTF((    "Disable Steady State DFE FX Taps Adaptation  = %d\n", dssd.field.dfe_fx_taps_adaptation   ));
   1162 	EFUN_PRINTF((    "Disable Steady State DFE FL Taps Adaptation  = %d\n", dssd.field.dfe_fl_taps_adaptation   ));
   1163 	EFUN_PRINTF((    "Disable Steady State DFE Tap DCD             = %d\n", dssd.field.dfe_dcd_adaptation       ));
   1164 	ESTM_PRINTF((    "Retune after Reset                           = %d\n", rdv_usr_ctrl_retune_after_restart() ));
   1165 	ESTM_PRINTF((    "Clk90 offset Adjust                          = %d\n", rdv_usr_ctrl_clk90_offset_adjust()  ));
   1166 	ESTM_PRINTF((    "Clk90 offset Override                        = %d\n", rdv_usr_ctrl_clk90_offset_override()));
   1167 	ESTM_PRINTF((    "Lane Event Log Level                         = %d\n", rdv_usr_ctrl_lane_event_log_level() ));
   1168 
   1169 	return ERR_CODE_NONE;
   1170 }
   1171 
   1172 
   1173 
   1174 /*************************/
   1175 /*  Stop/Resume uC Lane  */
   1176 /*************************/
   1177 
   1178 err_code_t phy8806x_tsc_stop_uc_lane (const phymod_access_t *pa, uint8_t enable){
   1179 
   1180 	if (enable)
   1181 		return phy8806x_tsc_pmd_uc_control (pa, CMD_UC_CTRL_STOP_GRACEFULLY, 100);
   1182 	else
   1183 		return phy8806x_tsc_pmd_uc_control (pa, CMD_UC_CTRL_RESUME, 50);
   1184 }
   1185 
   1186 
   1187 err_code_t phy8806x_tsc_stop_uc_lane_status (const phymod_access_t *pa, uint8_t *uc_lane_stopped){
   1188 
   1189 	if (!uc_lane_stopped)
   1190 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   1191 
   1192 	ESTM(*uc_lane_stopped = rdv_usr_sts_micro_stopped());
   1193 
   1194 	return ERR_CODE_NONE;
   1195 }
   1196 
   1197 
   1198 /*******************************/
   1199 /*  Stop/Resume RX Adaptation  */
   1200 /*******************************/
   1201 
   1202 err_code_t phy8806x_tsc_stop_rx_adaptation (const phymod_access_t *pa, uint8_t enable){
   1203 
   1204 	if (enable)
   1205 		return phy8806x_tsc_pmd_uc_control (pa, CMD_UC_CTRL_STOP_GRACEFULLY, 100);
   1206 	else
   1207 		return phy8806x_tsc_pmd_uc_control (pa, CMD_UC_CTRL_RESUME, 50);
   1208 }
   1209 
   1210 err_code_t phy8806x_tsc_request_stop_rx_adaptation (const phymod_access_t *pa){
   1211 
   1212 	return phy8806x_tsc_pmd_uc_control_return_immediate (pa, CMD_UC_CTRL_STOP_GRACEFULLY);
   1213 }
   1214 
   1215 
   1216 /**********************/
   1217 /*  uCode CRC Verify  */
   1218 /**********************/
   1219 
   1220 err_code_t phy8806x_tsc_ucode_crc_verify (const phymod_access_t *pa, uint16_t ucode_len, uint16_t expected_crc_value){
   1221 	uint16_t calc_crc;
   1222 
   1223 	EFUN(phy8806x_tsc_pmd_uc_cmd_with_data (pa, CMD_CALC_CRC, 0, ucode_len, 200));
   1224 
   1225 	ESTM(calc_crc = rd_uc_dsc_data());
   1226 	if (calc_crc != expected_crc_value) {
   1227 		EFUN_PRINTF(("UC CRC did not match expected=%04x : calculated=%04x\n", expected_crc_value, calc_crc));
   1228 		return _error(ERR_CODE_UC_CRC_NOT_MATCH);
   1229 	}
   1230 
   1231 	return ERR_CODE_NONE;
   1232 }
   1233 
   1234 err_code_t phy8806x_tsc_start_ucode_crc_calc (const phymod_access_t *pa, uint16_t ucode_len){
   1235 
   1236 	EFUN(phy8806x_tsc_pmd_uc_cmd_with_data_return_immediate (pa, CMD_CALC_CRC, 0, ucode_len)); /* Invoke Calculate CRC command and return control immediately */
   1237 	return ERR_CODE_NONE;
   1238 }
   1239 
   1240 err_code_t phy8806x_tsc_check_ucode_crc (const phymod_access_t *pa, uint16_t expected_crc_value, uint32_t timeout_ms){
   1241 	uint16_t calc_crc;
   1242 	err_code_t err_code;
   1243 
   1244 	err_code = phy8806x_tsc_poll_uc_dsc_ready_for_cmd_equals_1 (pa, timeout_ms); /* Poll for uc_dsc_ready_for_cmd = 1 to indicate phy8806x_tsc ready for command */
   1245 	if (err_code) {
   1246 		EFUN_PRINTF(("ERROR : DSC ready for command timed out. Previous uC command not finished yet\n"));
   1247 		return err_code;
   1248 	}
   1249 	ESTM(calc_crc = rd_uc_dsc_data());
   1250 	if (calc_crc != expected_crc_value) {
   1251 		EFUN_PRINTF(("UC CRC did not match expected=%04x : calculated=%04x\n", expected_crc_value, calc_crc));
   1252 		return _error(ERR_CODE_UC_CRC_NOT_MATCH);
   1253 	}
   1254 
   1255 	return ERR_CODE_NONE;
   1256 }
   1257 
   1258 
   1259 /******************************************************/
   1260 /*  Commands through Serdes FW DSC Command Interface  */
   1261 /******************************************************/
   1262 
   1263 err_code_t phy8806x_tsc_pmd_uc_cmd_return_immediate (const phymod_access_t *pa, enum srds_pmd_uc_cmd_enum cmd, uint8_t supp_info){
   1264 	err_code_t err_code;
   1265 	uint16_t cmddata;
   1266 
   1267 	err_code = phy8806x_tsc_poll_uc_dsc_ready_for_cmd_equals_1 (pa, 1); /* Poll for uc_dsc_ready_for_cmd = 1 to indicate phy8806x_tsc ready for command */
   1268 	if (err_code) {
   1269 		EFUN_PRINTF(("ERROR : DSC ready for command timed out (before cmd) cmd = %d, supp_info = x%02x err=%d !\n", cmd, supp_info, err_code));
   1270 		return err_code;
   1271 	}
   1272 /*EFUN(wr_uc_dsc_supp_info(supp_info)); */                     /* Supplement info field */
   1273 /*EFUN(wr_uc_dsc_error_found(0x0)    ); */                     /* Clear error found field */
   1274 /*EFUN(wr_uc_dsc_gp_uc_req(cmd)      ); */                     /* Set command code */
   1275 /*EFUN(wr_uc_dsc_ready_for_cmd(0x0)  ); */                     /* Issue command, by clearing "ready for command" field */
   1276 	cmddata = (((uint16_t)supp_info) << 8) | (uint16_t)cmd;         /* Combine writes to single write instead of 4 RMW */
   1277 
   1278 	EFUN(phy8806x_tsc_pmd_wr_reg (pa, DSC_A_DSC_UC_CTRL, cmddata));       /* This address is same for Eagle, and all Merlin */
   1279 
   1280 	return ERR_CODE_NONE;
   1281 }
   1282 
   1283 err_code_t phy8806x_tsc_pmd_uc_cmd (const phymod_access_t *pa, enum srds_pmd_uc_cmd_enum cmd, uint8_t supp_info, uint32_t timeout_ms){
   1284 
   1285 	uint8_t uc_dsc_error_found;
   1286 
   1287 	EFUN(phy8806x_tsc_pmd_uc_cmd_return_immediate (pa, cmd, supp_info));          /* Invoke phy8806x_tsc_uc_cmd and return control immediately */
   1288 
   1289 	EFUN(phy8806x_tsc_poll_uc_dsc_ready_for_cmd_equals_1 (pa, timeout_ms));       /* Poll for uc_dsc_ready_for_cmd = 1 to indicate phy8806x_tsc ready for command */
   1290 	ESTM(uc_dsc_error_found = rd_uc_dsc_error_found());
   1291 	if (uc_dsc_error_found) {
   1292 		ESTM_PRINTF(("ERROR : DSC ready for command return error ( after cmd) cmd = %d, supp_info = x%02x !\n", cmd, rd_uc_dsc_supp_info()));
   1293 		return _error(ERR_CODE_UC_CMD_RETURN_ERROR);
   1294 	}
   1295 	return ERR_CODE_NONE;
   1296 }
   1297 
   1298 
   1299 err_code_t phy8806x_tsc_pmd_uc_cmd_with_data_return_immediate (const phymod_access_t *pa, enum srds_pmd_uc_cmd_enum cmd, uint8_t supp_info, uint16_t data){
   1300 	uint16_t cmddata;
   1301 	err_code_t err_code;
   1302 
   1303 	err_code = phy8806x_tsc_poll_uc_dsc_ready_for_cmd_equals_1 (pa, 1); /* Poll for uc_dsc_ready_for_cmd = 1 to indicate phy8806x_tsc ready for command */
   1304 	if (err_code) {
   1305 		EFUN_PRINTF(("ERROR : DSC ready for command timed out (before cmd) cmd = %d, supp_info = x%02x, data = x%04x err=%d !\n", cmd, supp_info, data, err_code));
   1306 		return err_code;
   1307 	}
   1308 
   1309 	EFUN(wr_uc_dsc_data(data));                            /* Write value written to uc_dsc_data field */
   1310 /*EFUN(wr_uc_dsc_supp_info(supp_info)); */                     /* Supplement info field */
   1311 /*EFUN(wr_uc_dsc_error_found(0x0));     */                     /* Clear error found field */
   1312 /*EFUN(wr_uc_dsc_gp_uc_req(cmd));       */                     /* Set command code */
   1313 /*EFUN(wr_uc_dsc_ready_for_cmd(0x0));   */                     /* Issue command, by clearing "ready for command" field */
   1314 	cmddata = (((uint16_t)supp_info) << 8) | (uint16_t)cmd;         /* Combine writes to single write instead of 4 RMW */
   1315 
   1316 	EFUN(phy8806x_tsc_pmd_wr_reg (pa, DSC_A_DSC_UC_CTRL, cmddata));       /* This address is same for Eagle, and all Merlin */
   1317 
   1318 	return ERR_CODE_NONE;
   1319 }
   1320 
   1321 
   1322 err_code_t phy8806x_tsc_pmd_uc_cmd_with_data (const phymod_access_t *pa, enum srds_pmd_uc_cmd_enum cmd, uint8_t supp_info, uint16_t data, uint32_t timeout_ms){
   1323 
   1324 	uint8_t uc_dsc_error_found;
   1325 
   1326 	EFUN(phy8806x_tsc_pmd_uc_cmd_with_data_return_immediate (pa, cmd, supp_info, data));  /* Invoke phy8806x_tsc_uc_cmd and return control immediately */
   1327 
   1328 	EFUN(phy8806x_tsc_poll_uc_dsc_ready_for_cmd_equals_1 (pa, timeout_ms));               /* Poll for uc_dsc_ready_for_cmd = 1 to indicate phy8806x_tsc ready for command */
   1329 	ESTM(uc_dsc_error_found = rd_uc_dsc_error_found());
   1330 	if (uc_dsc_error_found) {
   1331 		ESTM_PRINTF(("ERROR : DSC ready for command return error ( after cmd) cmd = %d, supp_info = x%02x !\n", cmd, rd_uc_dsc_supp_info()));
   1332 		return _error(ERR_CODE_UC_CMD_RETURN_ERROR);
   1333 	}
   1334 	return ERR_CODE_NONE;
   1335 }
   1336 
   1337 err_code_t phy8806x_tsc_pmd_uc_control_return_immediate (const phymod_access_t *pa, enum srds_pmd_uc_ctrl_cmd_enum control){
   1338 	return phy8806x_tsc_pmd_uc_cmd_return_immediate (pa, CMD_UC_CTRL, (uint8_t)control);
   1339 }
   1340 
   1341 err_code_t phy8806x_tsc_pmd_uc_control (const phymod_access_t *pa, enum srds_pmd_uc_ctrl_cmd_enum control, uint32_t timeout_ms){
   1342 	return phy8806x_tsc_pmd_uc_cmd (pa, CMD_UC_CTRL, (uint8_t)control, timeout_ms);
   1343 }
   1344 
   1345 err_code_t phy8806x_tsc_pmd_uc_diag_cmd (const phymod_access_t *pa, enum srds_pmd_uc_diag_cmd_enum control, uint32_t timeout_ms){
   1346 	return phy8806x_tsc_pmd_uc_cmd (pa, CMD_DIAG_EN, (uint8_t)control, timeout_ms);
   1347 }
   1348 
   1349 
   1350 /************************************************************/
   1351 /*      Serdes IP RAM access - Lane RAM Variables           */
   1352 /*----------------------------------------------------------*/
   1353 /*   - through Micro Register Interface for PMD IPs         */
   1354 /*   - through Serdes FW DSC Command Interface for Gallardo */
   1355 /************************************************************/
   1356 
   1357 /* Micro RAM Lane Byte Read */
   1358 uint8_t phy8806x_tsc_rdbl_uc_var (const phymod_access_t *pa, err_code_t *err_code_p, uint16_t addr){
   1359 	uint8_t rddata;
   1360 
   1361 	if (!err_code_p)
   1362 		return 0;
   1363 
   1364 	EPSTM(rddata = phy8806x_tsc_rdb_uc_ram (pa, err_code_p, (LANE_VAR_RAM_BASE + addr + (phy8806x_tsc_get_lane (pa ) * LANE_VAR_RAM_SIZE)))); /* Use Micro register interface for reading RAM */
   1365 
   1366 	return rddata;
   1367 }
   1368 
   1369 /* Micro RAM Lane Byte Signed Read */
   1370 int8_t phy8806x_tsc_rdbls_uc_var (const phymod_access_t *pa, err_code_t *err_code_p, uint16_t addr){
   1371 	return (int8_t)phy8806x_tsc_rdbl_uc_var (pa, err_code_p, addr);
   1372 }
   1373 
   1374 /* Micro RAM Lane Word Read */
   1375 uint16_t phy8806x_tsc_rdwl_uc_var (const phymod_access_t *pa, err_code_t *err_code_p, uint16_t addr){
   1376 	uint16_t rddata;
   1377 
   1378 	if (!err_code_p)
   1379 		return 0;
   1380 
   1381 	if (addr % 2 != 0) {                                                        /* Validate even address */
   1382 		*err_code_p = ERR_CODE_INVALID_RAM_ADDR;
   1383 		return 0;
   1384 	}
   1385 
   1386 	EPSTM(rddata = phy8806x_tsc_rdw_uc_ram (pa, err_code_p, (LANE_VAR_RAM_BASE + addr + (phy8806x_tsc_get_lane (pa ) * LANE_VAR_RAM_SIZE)))); /* Use Micro register interface for reading RAM */
   1387 
   1388 	return rddata;
   1389 }
   1390 
   1391 
   1392 /* Micro RAM Lane Word Signed Read */
   1393 int16_t phy8806x_tsc_rdwls_uc_var (const phymod_access_t *pa, err_code_t *err_code_p, uint16_t addr){
   1394 	return (int16_t)phy8806x_tsc_rdwl_uc_var (pa, err_code_p, addr);
   1395 }
   1396 
   1397 /* Micro RAM Lane Byte Write */
   1398 err_code_t phy8806x_tsc_wrbl_uc_var (const phymod_access_t *pa, uint16_t addr, uint8_t wr_val){
   1399 
   1400 
   1401 	if (addr < LANE_VAR_RAM_SIZE)
   1402 		return phy8806x_tsc_wrb_uc_ram (pa, (LANE_VAR_RAM_BASE + addr + (phy8806x_tsc_get_lane (pa ) * LANE_VAR_RAM_SIZE)), wr_val); /* Use Micro register interface for writing RAM */
   1403 	else
   1404 		return _error(ERR_CODE_INVALID_RAM_ADDR);
   1405 
   1406 }
   1407 
   1408 /* Micro RAM Lane Byte Signed Write */
   1409 err_code_t phy8806x_tsc_wrbls_uc_var (const phymod_access_t *pa, uint16_t addr, int8_t wr_val){
   1410 	return phy8806x_tsc_wrbl_uc_var (pa, addr, wr_val);
   1411 }
   1412 
   1413 /* Micro RAM Lane Word Write */
   1414 err_code_t phy8806x_tsc_wrwl_uc_var (const phymod_access_t *pa, uint16_t addr, uint16_t wr_val){
   1415 
   1416 
   1417 	if (addr % 2 != 0)                                                            /* Validate even address */
   1418 		return _error(ERR_CODE_INVALID_RAM_ADDR);
   1419 	if (addr < LANE_VAR_RAM_SIZE)
   1420 		return phy8806x_tsc_wrw_uc_ram (pa, (LANE_VAR_RAM_BASE + addr + (phy8806x_tsc_get_lane (pa ) * LANE_VAR_RAM_SIZE)), wr_val); /* Use Micro register interface for writing RAM */
   1421 	else
   1422 		return _error(ERR_CODE_INVALID_RAM_ADDR);
   1423 }
   1424 
   1425 /* Micro RAM Lane Word Signed Write */
   1426 err_code_t phy8806x_tsc_wrwls_uc_var (const phymod_access_t *pa, uint16_t addr, int16_t wr_val){
   1427 	return phy8806x_tsc_wrwl_uc_var (pa, addr, wr_val);
   1428 }
   1429 
   1430 
   1431 /************************************************************/
   1432 /*      Serdes IP RAM access - Core RAM Variables           */
   1433 /*----------------------------------------------------------*/
   1434 /*   - through Micro Register Interface for PMD IPs         */
   1435 /*   - through Serdes FW DSC Command Interface for Gallardo */
   1436 /************************************************************/
   1437 
   1438 /* Micro RAM Core Byte Read */
   1439 uint8_t phy8806x_tsc_rdbc_uc_var (const phymod_access_t *pa, err_code_t *err_code_p, uint8_t addr){
   1440 
   1441 	uint8_t rddata;
   1442 
   1443 	if (!err_code_p)
   1444 		return 0;
   1445 
   1446 	EPSTM(rddata = phy8806x_tsc_rdb_uc_ram (pa, err_code_p, (CORE_VAR_RAM_BASE + addr)));              /* Use Micro register interface for reading RAM */
   1447 	return rddata;
   1448 }
   1449 
   1450 /* Micro RAM Core Byte Signed Read */
   1451 int8_t phy8806x_tsc_rdbcs_uc_var (const phymod_access_t *pa, err_code_t *err_code_p, uint8_t addr){
   1452 	return (int8_t)phy8806x_tsc_rdbc_uc_var (pa, err_code_p, addr);
   1453 }
   1454 
   1455 /* Micro RAM Core Word Read */
   1456 uint16_t phy8806x_tsc_rdwc_uc_var (const phymod_access_t *pa, err_code_t *err_code_p, uint8_t addr){
   1457 
   1458 	uint16_t rddata;
   1459 
   1460 	if (!err_code_p)
   1461 		return 0;
   1462 	if (addr % 2 != 0) {                                                        /* Validate even address */
   1463 		*err_code_p = ERR_CODE_INVALID_RAM_ADDR;
   1464 		return 0;
   1465 	}
   1466 
   1467 	EPSTM(rddata = phy8806x_tsc_rdw_uc_ram (pa, err_code_p, (CORE_VAR_RAM_BASE + addr)));          /* Use Micro register interface for reading RAM */
   1468 	return rddata;
   1469 }
   1470 
   1471 /* Micro RAM Core Word Signed Read */
   1472 int16_t phy8806x_tsc_rdwcs_uc_var (const phymod_access_t *pa, err_code_t *err_code_p, uint8_t addr){
   1473 	return (int16_t)phy8806x_tsc_rdwc_uc_var (pa, err_code_p, addr);
   1474 }
   1475 
   1476 /* Micro RAM Core Byte Write  */
   1477 err_code_t phy8806x_tsc_wrbc_uc_var (const phymod_access_t *pa, uint8_t addr, uint8_t wr_val){
   1478 
   1479 
   1480 	if (addr < CORE_VAR_RAM_SIZE)
   1481 		return phy8806x_tsc_wrb_uc_ram (pa, (CORE_VAR_RAM_BASE + addr), wr_val);                    /* Use Micro register interface for writing RAM */
   1482 	else
   1483 		return _error(ERR_CODE_INVALID_RAM_ADDR);
   1484 }
   1485 
   1486 
   1487 /* Micro RAM Core Byte Signed Write */
   1488 err_code_t phy8806x_tsc_wrbcs_uc_var (const phymod_access_t *pa, uint8_t addr, int8_t wr_val){
   1489 	return phy8806x_tsc_wrbc_uc_var (pa, addr, wr_val);
   1490 }
   1491 
   1492 /* Micro RAM Core Word Write  */
   1493 err_code_t phy8806x_tsc_wrwc_uc_var (const phymod_access_t *pa, uint8_t addr, uint16_t wr_val){
   1494 	if (addr % 2 != 0)                                                            /* Validate even address */
   1495 		return _error(ERR_CODE_INVALID_RAM_ADDR);
   1496 	if (addr < CORE_VAR_RAM_SIZE)
   1497 		return phy8806x_tsc_wrw_uc_ram (pa, (CORE_VAR_RAM_BASE + addr), wr_val);                         /* Use Micro register interface for writing RAM */
   1498 	else
   1499 		return _error(ERR_CODE_INVALID_RAM_ADDR);
   1500 }
   1501 
   1502 /* Micro RAM Core Word Signed Write */
   1503 err_code_t phy8806x_tsc_wrwcs_uc_var (const phymod_access_t *pa, uint8_t addr, int16_t wr_val){
   1504 	return phy8806x_tsc_wrwc_uc_var (pa, addr, wr_val);
   1505 }
   1506 
   1507 
   1508 
   1509 /*******************************************************************/
   1510 /*  APIs to Write Core/Lane Config and User variables into uC RAM  */
   1511 /*******************************************************************/
   1512 
   1513 err_code_t phy8806x_tsc_set_uc_core_config (const phymod_access_t *pa, struct phy8806x_tsc_uc_core_config_st struct_val){
   1514 	{
   1515 #ifndef ATE_LOG
   1516 		uint8_t reset_state;
   1517 		ESTM(reset_state = rdc_core_dp_reset_state());
   1518 		if (reset_state < 7) {
   1519 			EFUN_PRINTF(("ERROR: phy8806x_tsc_set_uc_core_config (pa, ..) called without core_dp_s_rstb=0 Lane=%d reset_state=%d\n", phy8806x_tsc_get_lane (pa ), reset_state));
   1520 			return _error(ERR_CODE_CORE_DP_NOT_RESET);
   1521 		}
   1522 #endif
   1523 	}
   1524 	if (struct_val.vco_rate_in_Mhz > 0)
   1525 		struct_val.field.vco_rate = MHZ_TO_VCO_RATE(struct_val.vco_rate_in_Mhz);
   1526 	EFUN(_update_uc_core_config_word (pa, &struct_val));
   1527 	switch (phy8806x_tsc_get_pll(pa)) {
   1528 	case 0:
   1529 		EFUN(wrcv_config_word(struct_val.word));
   1530 		break;
   1531 	case 1:
   1532 		EFUN(wrcv_config_pll1_word(struct_val.word));
   1533 		break;
   1534 	default:
   1535 		EFUN(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
   1536 		break;
   1537 	}
   1538 	return ERR_CODE_NONE;
   1539 }
   1540 
   1541 err_code_t phy8806x_tsc_set_usr_ctrl_core_event_log_level (const phymod_access_t *pa, uint8_t core_event_log_level){
   1542 	return wrcv_usr_ctrl_core_event_log_level(core_event_log_level);
   1543 }
   1544 
   1545 err_code_t phy8806x_tsc_set_uc_lane_cfg (const phymod_access_t *pa, struct phy8806x_tsc_uc_lane_config_st struct_val){
   1546 #ifndef ATE_LOG
   1547 	uint8_t reset_state;
   1548 
   1549 	ESTM(reset_state = rd_lane_dp_reset_state());
   1550 	if (reset_state < 7) {
   1551 		EFUN_PRINTF(("ERROR: phy8806x_tsc_set_uc_lane_cfg (pa, ..) called without ln_dp_s_rstb=0 Lane=%d reset_state=%d\n", phy8806x_tsc_get_lane (pa ), reset_state));
   1552 		return _error(ERR_CODE_LANE_DP_NOT_RESET);
   1553 	}
   1554 #endif
   1555 	EFUN(_update_uc_lane_config_word (pa, &struct_val));
   1556 	return wrv_config_word(struct_val.word);
   1557 }
   1558 
   1559 err_code_t phy8806x_tsc_set_usr_ctrl_lane_event_log_level (const phymod_access_t *pa, uint8_t lane_event_log_level){
   1560 	return wrv_usr_ctrl_lane_event_log_level(lane_event_log_level);
   1561 }
   1562 
   1563 err_code_t phy8806x_tsc_set_usr_ctrl_disable_startup (const phymod_access_t *pa, struct phy8806x_tsc_usr_ctrl_disable_functions_st set_val){
   1564 	EFUN(_update_usr_ctrl_disable_functions_byte (pa, &set_val));
   1565 	return wrv_usr_ctrl_disable_startup_functions_word(set_val.word);
   1566 }
   1567 
   1568 err_code_t phy8806x_tsc_set_usr_ctrl_disable_startup_dfe (const phymod_access_t *pa, struct phy8806x_tsc_usr_ctrl_disable_dfe_functions_st set_val){
   1569 	EFUN(_update_usr_ctrl_disable_dfe_functions_byte (pa, &set_val));
   1570 	return wrv_usr_ctrl_disable_startup_dfe_functions_byte(set_val.byte);
   1571 }
   1572 
   1573 err_code_t phy8806x_tsc_set_usr_ctrl_disable_steady_state (const phymod_access_t *pa, struct phy8806x_tsc_usr_ctrl_disable_functions_st set_val){
   1574 	EFUN(_update_usr_ctrl_disable_functions_byte (pa, &set_val));
   1575 	return wrv_usr_ctrl_disable_steady_state_functions_word(set_val.word);
   1576 }
   1577 
   1578 err_code_t phy8806x_tsc_set_usr_ctrl_disable_steady_state_dfe (const phymod_access_t *pa, struct phy8806x_tsc_usr_ctrl_disable_dfe_functions_st set_val){
   1579 	EFUN(_update_usr_ctrl_disable_dfe_functions_byte (pa, &set_val));
   1580 	return wrv_usr_ctrl_disable_steady_state_dfe_functions_byte(set_val.byte);
   1581 }
   1582 
   1583 
   1584 
   1585 /******************************************************************/
   1586 /*  APIs to Read Core/Lane Config and User variables from uC RAM  */
   1587 /******************************************************************/
   1588 
   1589 err_code_t phy8806x_tsc_get_uc_core_config (const phymod_access_t *pa, struct phy8806x_tsc_uc_core_config_st *get_val){
   1590 	
   1591 	if (!get_val)
   1592 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   1593 	switch (phy8806x_tsc_get_pll(pa)) {
   1594 	case  0:
   1595 		ESTM(get_val->word = rdcv_config_word());
   1596 		break;
   1597 	case  1:
   1598 		ESTM(get_val->word = rdcv_config_pll1_word());
   1599 		break;
   1600 	default:
   1601 		EFUN(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
   1602 		break;
   1603 	}
   1604 	EFUN(_update_uc_core_config_st (pa, get_val));
   1605 	return ERR_CODE_NONE;
   1606 }
   1607 
   1608 err_code_t phy8806x_tsc_get_usr_ctrl_core_event_log_level (const phymod_access_t *pa, uint8_t *core_event_log_level){
   1609 
   1610 	if (!core_event_log_level)
   1611 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   1612 
   1613 	ESTM(*core_event_log_level = rdcv_usr_ctrl_core_event_log_level());
   1614 
   1615 	return ERR_CODE_NONE;
   1616 }
   1617 
   1618 err_code_t phy8806x_tsc_get_uc_lane_cfg (const phymod_access_t *pa, struct phy8806x_tsc_uc_lane_config_st *get_val){
   1619 
   1620 	if (!get_val)
   1621 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   1622 
   1623 	ESTM(get_val->word = rdv_config_word());
   1624 	EFUN(_update_uc_lane_config_st (pa, get_val));
   1625 	return ERR_CODE_NONE;
   1626 }
   1627 
   1628 err_code_t phy8806x_tsc_get_usr_ctrl_lane_event_log_level (const phymod_access_t *pa, uint8_t *lane_event_log_level){
   1629 
   1630 	if (!lane_event_log_level)
   1631 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   1632 
   1633 	ESTM(*lane_event_log_level = rdv_usr_ctrl_lane_event_log_level());
   1634 	return ERR_CODE_NONE;
   1635 }
   1636 
   1637 err_code_t phy8806x_tsc_get_usr_ctrl_disable_startup (const phymod_access_t *pa, struct phy8806x_tsc_usr_ctrl_disable_functions_st *get_val){
   1638 
   1639 	if (!get_val)
   1640 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   1641 
   1642 	ESTM(get_val->word = rdv_usr_ctrl_disable_startup_functions_word());
   1643 	EFUN(_update_usr_ctrl_disable_functions_st (pa, get_val));
   1644 	return ERR_CODE_NONE;
   1645 }
   1646 
   1647 err_code_t phy8806x_tsc_get_usr_ctrl_disable_startup_dfe (const phymod_access_t *pa, struct phy8806x_tsc_usr_ctrl_disable_dfe_functions_st *get_val){
   1648 
   1649 	if (!get_val)
   1650 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   1651 
   1652 	ESTM(get_val->byte = rdv_usr_ctrl_disable_startup_dfe_functions_byte());
   1653 	EFUN(_update_usr_ctrl_disable_dfe_functions_st (pa, get_val));
   1654 	return ERR_CODE_NONE;
   1655 }
   1656 
   1657 err_code_t phy8806x_tsc_get_usr_ctrl_disable_steady_state (const phymod_access_t *pa, struct phy8806x_tsc_usr_ctrl_disable_functions_st *get_val){
   1658 
   1659 	if (!get_val)
   1660 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   1661 
   1662 	ESTM(get_val->word = rdv_usr_ctrl_disable_steady_state_functions_word());
   1663 	EFUN(_update_usr_ctrl_disable_functions_st (pa, get_val));
   1664 	return ERR_CODE_NONE;
   1665 }
   1666 
   1667 err_code_t phy8806x_tsc_get_usr_ctrl_disable_steady_state_dfe (const phymod_access_t *pa, struct phy8806x_tsc_usr_ctrl_disable_dfe_functions_st *get_val){
   1668 
   1669 	if (!get_val)
   1670 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   1671 
   1672 	ESTM(get_val->byte = rdv_usr_ctrl_disable_steady_state_dfe_functions_byte());
   1673 	EFUN(_update_usr_ctrl_disable_dfe_functions_st (pa, get_val));
   1674 	return ERR_CODE_NONE;
   1675 }
   1676 
   1677 err_code_t phy8806x_tsc_get_clk90_offset_adjust (const phymod_access_t *pa, int8_t *adjust){
   1678 	if (!adjust)
   1679 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   1680 	ESTM(*adjust = (int8_t)rdv_usr_ctrl_clk90_offset_adjust());
   1681 	return ERR_CODE_NONE;
   1682 }
   1683 
   1684 err_code_t phy8806x_tsc_set_clk90_offset_adjust (const phymod_access_t *pa, int8_t adjust){
   1685 
   1686 	EFUN(_check_uc_lane_stopped (pa ));               /* make sure uC is stopped to a race conditions */
   1687 
   1688 	if ((adjust > 16) || (adjust < -16))
   1689 		return _error(ERR_CODE_INVALID_CLK90_ADJUST);
   1690 	ESTM(wrv_usr_ctrl_clk90_offset_adjust((uint8_t)(adjust)));
   1691 	return ERR_CODE_NONE;
   1692 }
   1693 
   1694 err_code_t phy8806x_tsc_get_clk90_offset_override (const phymod_access_t *pa, uint8_t *override){
   1695 	if (!override)
   1696 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   1697 	ESTM(*override = rdv_usr_ctrl_clk90_offset_override());
   1698 	return ERR_CODE_NONE;
   1699 }
   1700 
   1701 err_code_t phy8806x_tsc_set_clk90_offset_override (const phymod_access_t *pa, uint8_t enable, uint8_t override){
   1702 
   1703 	EFUN(_check_uc_lane_stopped (pa ));               /* make sure uC is stopped to a race conditions */
   1704 
   1705 	if ((override >= 52) || (override <= 24))
   1706 		return _error(ERR_CODE_INVALID_CLK90_OVERRIDE);
   1707 	ESTM(wrv_usr_ctrl_clk90_offset_override(((enable & 1) << 7) | override));
   1708 	return ERR_CODE_NONE;
   1709 }
   1710 
   1711 err_code_t phy8806x_tsc_get_clk90_offset (const phymod_access_t *pa, int8_t *offset){
   1712 
   1713 	if (!offset)
   1714 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   1715 
   1716 	ESTM(*offset = rdv_usr_sts_phase_hoffset());
   1717 
   1718 	return ERR_CODE_NONE;
   1719 }
   1720 
   1721 
   1722 /******************************************/
   1723 /*  Serdes Register field Poll functions  */
   1724 /******************************************/
   1725 
   1726 #ifndef CUSTOM_REG_POLLING
   1727 
   1728 /* poll for microcontroller to populate the dsc_data register */
   1729 err_code_t phy8806x_tsc_poll_diag_done (const phymod_access_t *pa, uint16_t *status, uint32_t timeout_ms){
   1730 	uint8_t loop;
   1731 
   1732 	if (!status)
   1733 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   1734 
   1735 	for (loop = 0; loop < 100; loop++) {
   1736 		ESTM(*status = rdv_usr_diag_status());
   1737 
   1738 		if ((*status & 0x8000) > 0)
   1739 			return ERR_CODE_NONE;
   1740 		if (loop > 10)
   1741 			EFUN(phy8806x_tsc_delay_us(10 * timeout_ms));
   1742 	}
   1743 	return _error(ERR_CODE_DIAG_TIMEOUT);
   1744 }
   1745 
   1746 /* poll for microcontroller to populate the dsc_data register */
   1747 err_code_t phy8806x_tsc_poll_diag_eye_data (const phymod_access_t *pa, uint32_t *data, uint16_t *status, uint32_t timeout_ms){
   1748 	uint8_t loop;
   1749 	uint16_t dscdata;
   1750 
   1751 	if (!data || !status)
   1752 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   1753 
   1754 	for (loop = 0; loop < 100; loop++) {
   1755 		ESTM(*status = rdv_usr_diag_status());
   1756 		if (((*status & 0x00FF) > 2) || ((*status & 0x8000) > 0)) {
   1757 			EFUN(phy8806x_tsc_pmd_uc_cmd (pa,  CMD_READ_DIAG_DATA_WORD, 0, 200));
   1758 			ESTM(dscdata = rd_uc_dsc_data());
   1759 			data[0] = _float8_to_int32 (pa, (float8_t)(dscdata >> 8));
   1760 			data[1] = _float8_to_int32 (pa, (float8_t)(dscdata & 0x00FF));
   1761 			return ERR_CODE_NONE;
   1762 		}
   1763 		if (loop > 10)
   1764 			EFUN(phy8806x_tsc_delay_us(10 * timeout_ms));
   1765 	}
   1766 	return _error(ERR_CODE_DIAG_TIMEOUT);
   1767 }
   1768 
   1769 /** Poll for field "uc_dsc_ready_for_cmd" = 1 [Return Val => Error_code (0 = Polling Pass)] */
   1770 err_code_t phy8806x_tsc_poll_uc_dsc_ready_for_cmd_equals_1 (const phymod_access_t *pa, uint32_t timeout_ms){
   1771 #ifndef ATE_LOG
   1772 	uint16_t loop;
   1773 
   1774 	/* read quickly for 4 tries */
   1775 	for (loop = 0; loop < 100; loop++) {
   1776 		uint16_t rddata;
   1777 		EFUN(phy8806x_tsc_pmd_rdt_reg (pa, DSC_A_DSC_UC_CTRL, &rddata));
   1778 		if (rddata & 0x0080) {          /* bit 7 is uc_dsc_ready_for_cmd */
   1779 			if (rddata & 0x0040) {  /* bit 6 is uc_dsc_error_found   */
   1780 				ESTM_PRINTF(("ERROR : DSC command returned error (after cmd) cmd = 0x%x, supp_info = 0x%02x !\n", rd_uc_dsc_gp_uc_req(), rd_uc_dsc_supp_info()));
   1781 				return _error(ERR_CODE_UC_CMD_RETURN_ERROR);
   1782 			}
   1783 			return ERR_CODE_NONE;
   1784 		}
   1785 		if (loop > 10)
   1786 			EFUN(phy8806x_tsc_delay_us(10 * timeout_ms));
   1787 	}
   1788 
   1789 #else
   1790 	{   uint16_t rddata;
   1791 	    EFUN_PRINTF(("// ATE_LOG phy8806x_tsc_poll_uc_dsc_ready_for_cmd_equals_1 begin\n"));
   1792 	    if (timeout_ms < 100)
   1793 		    EFUN(phy8806x_tsc_delay_us(1000 * timeout_ms));
   1794 	    else
   1795 		    EFUN(phy8806x_tsc_delay_ms(timeout_ms));
   1796 	    EFUN(phy8806x_tsc_pmd_rdt_reg (pa, DSC_A_DSC_UC_CTRL, &rddata));
   1797 	    if (rddata & 0x0080) {              /* bit 7 is uc_dsc_ready_for_cmd */
   1798 		    if (rddata & 0x0040) {      /* bit 6 is uc_dsc_error_found   */
   1799 			    ESTM_PRINTF(("ERROR : DSC command returned error (after cmd) cmd = 0x%x, supp_info = 0x%02x !\n", rd_uc_dsc_gp_uc_req(), rd_uc_dsc_supp_info()));
   1800 			    return _error(ERR_CODE_UC_CMD_RETURN_ERROR);
   1801 		    }
   1802 		    EFUN_PRINTF(("// ATE_LOG phy8806x_tsc_poll_uc_dsc_ready_for_cmd_equals_1 end\n"));
   1803 		    return ERR_CODE_NONE;
   1804 	    }
   1805 	    EFUN_PRINTF(("// ATE_LOG phy8806x_tsc_poll_uc_dsc_ready_for_cmd_equals_1 timeout\n")); }
   1806 #endif
   1807 	EFUN_PRINTF(("ERROR : DSC ready for command is not working, applying workaround and getting debug info !\n"));
   1808 	DISP(rd_uc_dsc_ready_for_cmd());
   1809 	DISP(rd_uc_dsc_supp_info());
   1810 	DISP(rd_uc_dsc_gp_uc_req());
   1811 	DISP(rd_uc_dsc_data());
   1812 	DISP(rd_dsc_state());
   1813 	ESTM_PRINTF(("Uc Core Status Byte = 0x%x\n", rdcv_status_byte()));
   1814 	/* artifically terminate the command to re-enable the command interface */
   1815 	EFUN(wr_uc_dsc_ready_for_cmd(0x1));
   1816 	return _error(ERR_CODE_POLLING_TIMEOUT);      /* Error Code for polling timeout */
   1817 }
   1818 
   1819 /* Poll for field "dsc_state" = DSC_STATE_UC_TUNE [Return Val => Error_code (0 = Polling Pass)] */
   1820 err_code_t phy8806x_tsc_poll_dsc_state_equals_uc_tune (const phymod_access_t *pa, uint32_t timeout_ms){
   1821 	uint16_t loop;
   1822 	uint16_t dsc_state;
   1823 
   1824 	/* poll 10 times to avoid longer delays later */
   1825 	for (loop = 0; loop < 100; loop++) {
   1826 		ESTM(dsc_state = rd_dsc_state());
   1827 		if (dsc_state == DSC_STATE_UC_TUNE)
   1828 			return ERR_CODE_NONE;
   1829 		if (loop > 10)
   1830 			EFUN(phy8806x_tsc_delay_us(10 * timeout_ms));
   1831 	}
   1832 	ESTM_PRINTF(("DSC_STATE = %d\n", rd_dsc_state()));
   1833 	return _error(ERR_CODE_POLLING_TIMEOUT);      /* Error Code for polling timeout */
   1834 }
   1835 
   1836 
   1837 /* Poll for field "st_afe_tx_fifo_resetb" = 1 [Return Val => Error_code (0 = Polling Pass)] */
   1838 err_code_t phy8806x_tsc_poll_st_afe_tx_fifo_resetb_equals_1 (const phymod_access_t *pa, uint32_t timeout_ms){
   1839 	uint16_t loop;
   1840 
   1841 	for (loop = 0; loop <= 100; loop++) {
   1842 		uint8_t st_afe_tx_fifo_resetb;
   1843 		ESTM(st_afe_tx_fifo_resetb = rd_st_afe_tx_fifo_resetb());
   1844 		if (st_afe_tx_fifo_resetb)
   1845 			return ERR_CODE_NONE;
   1846 		EFUN(phy8806x_tsc_delay_us(10 * timeout_ms));
   1847 	}
   1848 	return _error(ERR_CODE_POLLING_TIMEOUT);      /* Error Code for polling timeout */
   1849 }
   1850 
   1851 
   1852 /* Poll for field "micro_ra_initdone" = 1 [Return Val => Error_code (0 = Polling Pass)] */
   1853 err_code_t phy8806x_tsc_poll_micro_ra_initdone (const phymod_access_t *pa, uint32_t timeout_ms){
   1854 	uint16_t loop;
   1855 
   1856 	uint8_t result;
   1857 
   1858 	for (loop = 0; loop <= 100; loop++) {
   1859 		ESTM(result = rdc_micro_ra_initdone());
   1860 		if (result)
   1861 			return ERR_CODE_NONE;
   1862 		EFUN(phy8806x_tsc_delay_us(10 * timeout_ms));
   1863 	}
   1864 	return _error(ERR_CODE_POLLING_TIMEOUT);      /* Error Code for polling timeout */
   1865 }
   1866 #endif /* CUSTOM_REG_POLLING */
   1867 
   1868 
   1869 /* Configure ULL mode for TX */
   1870 err_code_t phy8806x_tsc_tx_ull_config (const phymod_access_t *pa, uint8_t enable){
   1871 	EFUN(phy8806x_tsc_tx_rptr_mode_timing (pa, enable)); /* Enable jitter filter enable */
   1872 	EFUN(_ull_tx_mode_setup (pa, enable));
   1873 	return ERR_CODE_NONE;
   1874 }
   1875 
   1876 /* Configure ULL mode for RX */
   1877 err_code_t phy8806x_tsc_rx_ull_config (const phymod_access_t *pa, uint8_t enable){
   1878 	EFUN(phy8806x_tsc_rx_rptr_mode_timing (pa, enable));
   1879 	EFUN(_ull_rx_mode_setup (pa, enable));
   1880 	return ERR_CODE_NONE;
   1881 }
   1882 
   1883 /* TX PI setup for Repeater Mode */
   1884 err_code_t phy8806x_tsc_tx_rptr_mode_timing (const phymod_access_t *pa, uint8_t enable){
   1885 	/* Enable TX PI and turn on 1st order loop in jitter filter */
   1886 	EFUN(wr_tx_pi_repeater_mode_en(0x1));
   1887 	EFUN(wr_tx_pi_en(enable));                                      /* TX_PI enable: 0 = diabled, 1 = enabled */
   1888 	EFUN(wr_tx_pi_jitter_filter_en(enable));                        /* Jitter filter enable to lock freq: 0 = diabled, 1 = enabled */
   1889 	EFUN(phy8806x_tsc_delay_us(25));                                 /* Wait for TX_PI to settle */
   1890 	return ERR_CODE_NONE;
   1891 }
   1892 
   1893 /* RX setup for Repeater Mode timing */
   1894 err_code_t phy8806x_tsc_rx_rptr_mode_timing (const phymod_access_t *pa, uint8_t enable){
   1895 	if (enable) {
   1896 		EFUN(wr_tx_pi_loop_timing_src_sel(1));
   1897 		EFUN(wr_ams_tx_ticksel(3));
   1898 	} else
   1899 		EFUN(wr_tx_pi_loop_timing_src_sel(0));
   1900 
   1901 	return ERR_CODE_NONE;
   1902 }
   1903 
   1904 /*
   1905 * COVERITY
   1906 *
   1907 * It is kept intentionally as a defensive default for future development.
   1908 */
   1909 /* coverity[param_set_but_not_used] */
   1910 err_code_t phy8806x_tsc_init_pram_for_uc_load (const phymod_access_t *pa, uint16_t ucode_len){
   1911 
   1912 	if (ucode_len > UCODE_MAX_SIZE)                   /* uCode size should be less than UCODE_MAX_SIZE  */
   1913 		return _error(ERR_CODE_INVALID_UCODE_LEN);
   1914 
   1915 	EFUN(wrc_micro_protect_fwcode(0x0));                    /* Remove Gate-off RAM chip select and other signals */
   1916 	EFUN(wrc_micro_master_clk_en(0x1));                     /* Enable clock to microcontroller subsystem */
   1917 	EFUN(wrc_micro_master_rstb(0x1));                       /* De-assert reset to microcontroller sybsystem */
   1918 	EFUN(wrc_micro_master_rstb(0x0));                       /* Assert reset to microcontroller sybsystem - Toggling reset*/
   1919 	EFUN(wrc_micro_master_rstb(0x1));                       /* De-assert reset to microcontroller sybsystem */
   1920 
   1921 	EFUN(wrc_micro_ra_init(0x1));                           /* Set initialization command to initialize code RAM */
   1922 	EFUN(phy8806x_tsc_poll_micro_ra_initdone (pa, 250));          /* Poll for micro_ra_initdone = 1 to indicate initialization done */
   1923 
   1924 	EFUN(wrc_micro_ra_init(0x0));                           /* Clear initialization command */
   1925 	/* ucode_len_padded = ((ucode_len + 3) & 0xFFFC); */    /* make sure it is on 32bit boundary */
   1926 	EFUN(wrc_micro_pramif_ahb_wraddr_msw(0x0000));
   1927 	EFUN(wrc_micro_pramif_ahb_wraddr_lsw(0x0000));
   1928 	EFUN(wrc_micro_pram_if_rstb(1));
   1929 	EFUN(wrc_micro_pramif_en(1));
   1930 	ucode_len = 0;                                      /* To avoid compile warnings */
   1931 
   1932 	/* Wait 8 pram clocks */
   1933 	/* write ucode into pram */
   1934 	/* Wait 8 pram clocks */
   1935 	/* call phy8806x_tsc_finish_pram_load */
   1936 	return ERR_CODE_NONE;
   1937 }
   1938 
   1939 err_code_t phy8806x_tsc_finish_pram_load (const phymod_access_t *pa){
   1940 	EFUN(wrc_micro_pramif_en(0));
   1941 	EFUN(wrc_micro_core_clk_en(1));
   1942 	/* EFUN(wrc_micro_core_rstb(1)); */
   1943 	return ERR_CODE_NONE;
   1944 }
   1945 
   1946 
   1947 /****************************************/
   1948 /*  Serdes Register/Variable Dump APIs  */
   1949 /****************************************/
   1950 
   1951 err_code_t phy8806x_tsc_reg_dump (const phymod_access_t *pa){
   1952 
   1953 	uint16_t addr, rddata;
   1954 
   1955 	EFUN_PRINTF(("\n****  SERDES REGISTER DUMP    ****"));
   1956 
   1957 	for (addr = 0x0; addr < 0x10; addr++) {
   1958 		if (!(addr % 16))
   1959 			EFUN_PRINTF(("\n%04x ", addr));
   1960 		EFUN(phy8806x_tsc_pmd_rdt_reg (pa, addr, &rddata));
   1961 		EFUN_PRINTF(("%04x ", rddata));
   1962 	}
   1963 
   1964 	for (addr = 0x90; addr < 0xA0; addr++) {
   1965 		if (!(addr % 16))
   1966 			EFUN_PRINTF(("\n%04x ", addr));
   1967 		EFUN(phy8806x_tsc_pmd_rdt_reg (pa, addr, &rddata));
   1968 		EFUN_PRINTF(("%04x ", rddata));
   1969 	}
   1970 
   1971 	for (addr = 0xD000; addr < 0xD180; addr++) {
   1972 		if (!(addr % 16))
   1973 			EFUN_PRINTF(("\n%04x ", addr));
   1974 		EFUN(phy8806x_tsc_pmd_rdt_reg (pa, addr, &rddata));
   1975 		EFUN_PRINTF(("%04x ", rddata));
   1976 	}
   1977 
   1978 	for (addr = 0xD180; addr < 0xD200; addr++) {
   1979 		if (!(addr % 16))
   1980 			EFUN_PRINTF(("\n%04x ", addr));
   1981 		EFUN(phy8806x_tsc_pmd_rdt_reg (pa, addr, &rddata));
   1982 		EFUN_PRINTF(("%04x ", rddata));
   1983 	}
   1984 
   1985 
   1986 	for (addr = 0xD200; addr < 0xD230; addr++) {
   1987 		if (!(addr % 16))
   1988 			EFUN_PRINTF(("\n%04x ", addr));
   1989 		EFUN(phy8806x_tsc_pmd_rdt_reg (pa, addr, &rddata));
   1990 		EFUN_PRINTF(("%04x ", rddata));
   1991 	}
   1992 
   1993 	for (addr = 0xFFD0; addr < 0xFFE0; addr++) {
   1994 		if (!(addr % 16))
   1995 			EFUN_PRINTF(("\n%04x ", addr));
   1996 		EFUN(phy8806x_tsc_pmd_rdt_reg (pa, addr, &rddata));
   1997 		EFUN_PRINTF(("%04x ", rddata));
   1998 	}
   1999 	return ERR_CODE_NONE;
   2000 }
   2001 
   2002 
   2003 err_code_t phy8806x_tsc_uc_core_var_dump (const phymod_access_t *pa){
   2004 	uint8_t addr;
   2005 
   2006 	EFUN_PRINTF(("\n**** SERDES UC CORE RAM VARIABLE DUMP ****"));
   2007 
   2008 	for (addr = 0x0; addr < CORE_VAR_RAM_SIZE; addr++) {
   2009 		if (!(addr % 26))
   2010 			EFUN_PRINTF(("\n%04x ", addr));
   2011 		ESTM_PRINTF(("%02x ", phy8806x_tsc_rdbc_uc_var (pa, __ERR, addr)));
   2012 	}
   2013 	return ERR_CODE_NONE;
   2014 }
   2015 
   2016 
   2017 err_code_t phy8806x_tsc_uc_lane_var_dump (const phymod_access_t *pa){
   2018 	uint8_t rx_lock, uc_stopped = 0;
   2019 	uint16_t addr;
   2020 
   2021 
   2022 	EFUN_PRINTF(("\n**** SERDES UC LANE %d RAM VARIABLE DUMP ****", phy8806x_tsc_get_lane (pa )));
   2023 
   2024 	ESTM(rx_lock = rd_pmd_rx_lock());
   2025 
   2026 	if (rx_lock == 1) {
   2027 		ESTM(uc_stopped = rdv_usr_sts_micro_stopped());
   2028 		if (!uc_stopped)
   2029 			EFUN(phy8806x_tsc_stop_rx_adaptation (pa, 1));
   2030 	} else
   2031 		EFUN(phy8806x_tsc_pmd_uc_control (pa, CMD_UC_CTRL_STOP_IMMEDIATE, 200));
   2032 
   2033 	for (addr = 0x0; addr < LANE_VAR_RAM_SIZE; addr++) {
   2034 		if (!(addr % 26))
   2035 			EFUN_PRINTF(("\n%04x ", addr));
   2036 		ESTM_PRINTF(("%02x ", phy8806x_tsc_rdbl_uc_var (pa, __ERR, addr)));
   2037 	}
   2038 
   2039 	if (rx_lock == 1) {
   2040 		if (!uc_stopped)
   2041 			EFUN(phy8806x_tsc_stop_rx_adaptation (pa, 0));
   2042 	} else
   2043 		EFUN(phy8806x_tsc_stop_rx_adaptation (pa, 0));
   2044 
   2045 	return ERR_CODE_NONE;
   2046 }
   2047 
   2048 /* Required Diagnostic Functions */
   2049 err_code_t phy8806x_tsc_display_diag_data (const phymod_access_t *pa, uint16_t diag_level){
   2050 	uint8_t rx_lock, micro_stop;
   2051 	uint32_t api_version;
   2052 
   2053 	EFUN_PRINTF(("\n**** SERDES DISPLAY DIAG DATA ****\n"));
   2054 	ESTM_PRINTF(("Rev ID Letter  = %02X\n", rdc_revid_rev_letter()));
   2055 	ESTM_PRINTF(("Rev ID Process = %02X\n", rdc_revid_process()));
   2056 	ESTM_PRINTF(("Rev ID Model   = %02X\n", rdc_revid_model()));
   2057 	ESTM_PRINTF(("Rev ID Model   = %02X\n", rdc_revid2()));
   2058 	ESTM_PRINTF(("Rev ID # Lanes = %d\n", rdc_revid_multiplicity()));
   2059 	ESTM_PRINTF(("Core = %d; LANE = %d\n", phy8806x_tsc_get_core(), phy8806x_tsc_get_lane (pa )));
   2060 	EFUN(phy8806x_tsc_version (pa, &api_version));
   2061 	EFUN_PRINTF(("SERDES API Version         = %06X\n", api_version));
   2062 	ESTM_PRINTF(("Common Ucode Version       = %04X", rdcv_common_ucode_version()));
   2063 	ESTM_PRINTF(("_%02X\n", rdcv_common_ucode_minor_version()));
   2064 	ESTM_PRINTF(("AFE Hardware Version       = 0x%X\n\n", rdcv_afe_hardware_version()));
   2065 
   2066 
   2067 	/* stop micro so all accesses are consistent */
   2068 	ESTM(rx_lock = rd_pmd_rx_lock());
   2069 	ESTM(micro_stop = rdv_usr_sts_micro_stopped());
   2070 	if (rx_lock == 1) {
   2071 		if (!micro_stop)
   2072 			EFUN(phy8806x_tsc_stop_rx_adaptation (pa, 1));
   2073 	} else
   2074 		EFUN(phy8806x_tsc_pmd_uc_control (pa, CMD_UC_CTRL_STOP_IMMEDIATE, 200));
   2075 
   2076 	if (diag_level & SRDS_DIAG_LANE) {
   2077 		struct phy8806x_tsc_detailed_lane_status_st lane_st;
   2078 		USR_MEMSET(&lane_st, 0, sizeof(lane_st));
   2079 		EFUN(phy8806x_tsc_log_full_pmd_state (pa, &lane_st));
   2080 		EFUN(phy8806x_tsc_disp_full_pmd_state (pa, &lane_st, 1));
   2081 	} else {
   2082 		EFUN(phy8806x_tsc_display_lane_state_hdr (pa ));
   2083 		EFUN(phy8806x_tsc_display_lane_state (pa ));
   2084 	}
   2085 	if (diag_level & SRDS_DIAG_CORE) {
   2086 		EFUN(phy8806x_tsc_display_core_state_hdr (pa ));
   2087 		EFUN(phy8806x_tsc_display_core_state_line (pa ));
   2088 	}
   2089 	if (diag_level & SRDS_DIAG_EVENT) {
   2090 		uint8_t trace_mem[1000]; 
   2091 		USR_MEMSET(trace_mem, 0, sizeof(trace_mem));
   2092 		EFUN(phy8806x_tsc_read_event_log (pa, trace_mem, EVENT_LOG_HEX));
   2093 	}
   2094 	if (diag_level & SRDS_DIAG_EYE)
   2095 		EFUN(phy8806x_tsc_display_eye_scan (pa ));
   2096 	if (diag_level & SRDS_DIAG_REG_CORE)
   2097 		EFUN(phy8806x_tsc_reg_dump (pa ));
   2098 	/* currently REG_CORE and REG_LANE dump same data. */
   2099 	/*if(diag_level & SRDS_DIAG_REG_LANE) {*/
   2100 	/*    EFUN(phy8806x_tsc_reg_dump (pa ));*/
   2101 	/*}*/
   2102 	if (diag_level & SRDS_DIAG_UC_CORE)
   2103 		EFUN(phy8806x_tsc_uc_core_var_dump (pa ));
   2104 	if (diag_level & SRDS_DIAG_UC_LANE)
   2105 		EFUN(phy8806x_tsc_uc_lane_var_dump (pa ));
   2106 	if (diag_level & SRDS_DIAG_LANE_DEBUG)
   2107 		EFUN(phy8806x_tsc_display_lane_debug_status (pa ));
   2108 	if (diag_level & SRDS_DIAG_BER_VERT) {
   2109 		/* display ber projections for all channels */
   2110 		uint8_t ber_mode = DIAG_BER_VERT | DIAG_BER_POS;
   2111 		uint8_t timer_control = 23;             /* 30 seconds */
   2112 		uint8_t err_threshold = 100 / 16;       /* 100 errors */
   2113 		EFUN(_phy8806x_tsc_display_ber_scan_data (pa, ber_mode, timer_control,  err_threshold));
   2114 		ber_mode = DIAG_BER_VERT | DIAG_BER_NEG;
   2115 		EFUN(_phy8806x_tsc_display_ber_scan_data (pa, ber_mode, timer_control,  err_threshold));
   2116 	}
   2117 	if (diag_level & SRDS_DIAG_BER_HORZ) {
   2118 		/* display ber projections for all channels */
   2119 		uint8_t ber_mode = DIAG_BER_HORZ | DIAG_BER_POS;
   2120 		uint8_t timer_control = 23;             /* 30 seconds */
   2121 		uint8_t err_threshold = 100 / 16;       /* 100 errors */
   2122 		EFUN(_phy8806x_tsc_display_ber_scan_data (pa, ber_mode, timer_control,  err_threshold));
   2123 		ber_mode = DIAG_BER_HORZ | DIAG_BER_NEG;
   2124 		EFUN(_phy8806x_tsc_display_ber_scan_data (pa, ber_mode, timer_control,  err_threshold));
   2125 	}
   2126 
   2127 	/* re enable micro */
   2128 	if (rx_lock == 1) {
   2129 		if (!micro_stop)
   2130 			EFUN(phy8806x_tsc_stop_rx_adaptation (pa, 0));
   2131 	} else
   2132 		EFUN(phy8806x_tsc_stop_rx_adaptation (pa, 0));
   2133 
   2134 	EFUN_PRINTF(("\n\n"));
   2135 	return ERR_CODE_NONE;
   2136 
   2137 }
   2138 
   2139 /* Required Diagnostic Functions */
   2140 err_code_t phy8806x_tsc_diag_access (const phymod_access_t *pa, enum srds_diag_access_enum type, uint16_t addr, uint16_t data, uint16_t param){
   2141 
   2142 	switch (type) {
   2143 	case SRDS_REG_READ:      {
   2144 		uint16_t tmp;
   2145 		if (data > 1) {
   2146 			uint16_t i;
   2147 			EFUN_PRINTF(("\n****  SERDES BLK REGISTER READ    ****"));
   2148 			for (i = 0; i < data; i++) {
   2149 				if (!(i % 16))
   2150 					ESTM_PRINTF(("\n%04x ", i + addr));
   2151 				EFUN(phy8806x_tsc_pmd_rdt_reg (pa, i + addr, &tmp));
   2152 				ESTM_PRINTF(("%04x ", tmp));
   2153 			}
   2154 			EFUN_PRINTF(("\n"));
   2155 		} else {
   2156 			EFUN(phy8806x_tsc_pmd_rdt_reg (pa, addr, &tmp));
   2157 			EFUN_PRINTF(("Register Read: x%04x = x%04x\n", addr, tmp));
   2158 		}
   2159 	} break;
   2160 	case SRDS_REG_RMW:       {
   2161 		uint16_t tmp, tmp2;
   2162 		EFUN(phy8806x_tsc_pmd_rdt_reg (pa, addr, &tmp));
   2163 		tmp2 = (tmp & ~param) | (param & data);
   2164 		EFUN(phy8806x_tsc_pmd_wr_reg (pa, addr, tmp2));
   2165 		EFUN_PRINTF(("Register RMW: x%04x = x%04x -> x%04x\n", addr, tmp, tmp2));
   2166 	} break;
   2167 	case SRDS_CORE_RAM_READ_BYTE: {
   2168 		if (data > 1) {
   2169 			uint8_t i;
   2170 			EFUN_PRINTF(("\n****  SERDES BLK CORE RAM READ BYTE   ****"));
   2171 			for (i = 0; i < (uint8_t)data; i++) {
   2172 				if (!(i % 26))
   2173 					ESTM_PRINTF(("\n%04x ", i + (uint8_t)addr));
   2174 				ESTM_PRINTF(("%02x ", phy8806x_tsc_rdbc_uc_var (pa, __ERR, i + (uint8_t)addr)));
   2175 			}
   2176 			EFUN_PRINTF(("\n"));
   2177 		} else
   2178 			ESTM_PRINTF(("Core RAM Read byte: x%04x = x%02x\n", (uint8_t)addr, phy8806x_tsc_rdbc_uc_var (pa, __ERR, (uint8_t)addr)));
   2179 	} break;
   2180 	case SRDS_LANE_RAM_READ_BYTE: {
   2181 		if (data > 1) {
   2182 			uint16_t i;
   2183 			EFUN_PRINTF(("\n****  SERDES BLK LANE RAM READ BYTE   ****"));
   2184 			for (i = 0; i < data; i++) {
   2185 				if (!(i % 26))
   2186 					ESTM_PRINTF(("\n%04x ", i + addr));
   2187 				ESTM_PRINTF(("%02x ", phy8806x_tsc_rdbl_uc_var (pa, __ERR, i + addr)));
   2188 			}
   2189 			EFUN_PRINTF(("\n"));
   2190 		} else
   2191 			ESTM_PRINTF(("Lane RAM Read byte: x%04x = x%02x\n", addr, phy8806x_tsc_rdbl_uc_var (pa, __ERR, addr)));
   2192 	} break;
   2193 	case SRDS_CORE_RAM_READ_WORD: {
   2194 		if (data > 1) {
   2195 			uint8_t i;
   2196 			EFUN_PRINTF(("\n****  SERDES BLK CORE RAM READ WORD   ****"));
   2197 			for (i = 0; i < (uint8_t)data; i += 2) {
   2198 				if (!(i % 16))
   2199 					ESTM_PRINTF(("\n%04x ", i + (uint8_t)addr));
   2200 				ESTM_PRINTF(("%04x ", phy8806x_tsc_rdwc_uc_var (pa, __ERR, i + (uint8_t)addr)));
   2201 			}
   2202 			EFUN_PRINTF(("\n"));
   2203 		} else
   2204 			ESTM_PRINTF(("Core RAM Read word: x%04x = x%04x\n", addr, phy8806x_tsc_rdwc_uc_var (pa, __ERR, (uint8_t)addr)));
   2205 	} break;
   2206 	case SRDS_LANE_RAM_READ_WORD: {
   2207 		if (data > 1) {
   2208 			uint16_t i;
   2209 			EFUN_PRINTF(("\n****  SERDES BLK LANE RAM READ WORD   ****"));
   2210 			for (i = 0; i < data; i += 2) {
   2211 				if (!(i % 16))
   2212 					ESTM_PRINTF(("\n%04x ", i = i + addr));
   2213 				ESTM_PRINTF(("%04x ", phy8806x_tsc_rdwl_uc_var (pa, __ERR, i + addr)));
   2214 			}
   2215 			EFUN_PRINTF(("\n"));
   2216 		} else
   2217 			ESTM_PRINTF(("Lane RAM Read word: x%04x = x%04x\n", addr, phy8806x_tsc_rdwl_uc_var (pa, __ERR, addr)));
   2218 	} break;
   2219 	case SRDS_CORE_RAM_RMW_BYTE:  {
   2220 		uint8_t tmp, tmp2;
   2221 		ESTM(tmp = phy8806x_tsc_rdbc_uc_var (pa, __ERR, (uint8_t)addr));
   2222 		tmp2 = (tmp & (uint8_t) ~param) | ((uint8_t)param & data);
   2223 		EFUN(phy8806x_tsc_wrbc_uc_var (pa, (uint8_t)addr, tmp2));
   2224 		EFUN_PRINTF(("Core RAM RMW byte: x%04x = x%02x -> x%02x\n", addr, tmp, tmp2));
   2225 	} break;
   2226 	case SRDS_LANE_RAM_RMW_BYTE:  {
   2227 		uint8_t tmp, tmp2;
   2228 		ESTM(tmp = phy8806x_tsc_rdbl_uc_var (pa, __ERR, addr));
   2229 		tmp2 = (tmp & (uint8_t) ~param) | ((uint8_t)param & data);
   2230 		EFUN(phy8806x_tsc_wrbl_uc_var (pa, addr, tmp2));
   2231 		EFUN_PRINTF(("Lane RAM RMW byte: x%04x = x%02x -> x%02x\n", addr, tmp, tmp2));
   2232 	} break;
   2233 	case SRDS_CORE_RAM_RMW_WORD:  {
   2234 		uint16_t tmp, tmp2;
   2235 		ESTM(tmp = phy8806x_tsc_rdwc_uc_var (pa, __ERR, (uint8_t)addr));
   2236 		tmp2 = (tmp & ~param) | (param & data);
   2237 		EFUN(phy8806x_tsc_wrwc_uc_var (pa, (uint8_t)addr, tmp2));
   2238 		EFUN_PRINTF(("Core RAM RMW word: x%04x = x%04x -> x%04x\n", addr, tmp, tmp2));
   2239 	} break;
   2240 	case SRDS_LANE_RAM_RMW_WORD:  {
   2241 		uint16_t tmp, tmp2;
   2242 		ESTM(tmp = phy8806x_tsc_rdwl_uc_var (pa, __ERR, addr));
   2243 		tmp2 = (tmp & ~param) | (param & data);
   2244 		EFUN(phy8806x_tsc_wrwl_uc_var (pa, addr, tmp2));
   2245 		EFUN_PRINTF(("Lane RAM RMW word: x%04x = x%04x -> x%04x\n", addr, tmp, tmp2));
   2246 	} break;
   2247 	case SRDS_GLOB_RAM_READ_BYTE: {
   2248 		if (data > 1) {
   2249 			uint16_t i;
   2250 			EFUN_PRINTF(("\n****  SERDES BLK GLOB RAM READ BYTE   ****"));
   2251 			for (i = 0; i < data; i++) {
   2252 				if (!(i % 16))
   2253 					ESTM_PRINTF(("\n%04x ", i + addr));
   2254 				ESTM_PRINTF(("%02x ", _phy8806x_tsc_rdb_uc_var (pa, __ERR, i + addr)));
   2255 			}
   2256 			EFUN_PRINTF(("\n"));
   2257 		} else
   2258 			ESTM_PRINTF(("Glob RAM Read byte: x%04x = x%02x\n", addr, _phy8806x_tsc_rdb_uc_var (pa, __ERR, addr)));
   2259 	} break;
   2260 	case SRDS_GLOB_RAM_RMW_BYTE:  {
   2261 		uint8_t tmp, tmp2;
   2262 		ESTM(tmp = _phy8806x_tsc_rdb_uc_var (pa, __ERR, addr));
   2263 		tmp2 = (tmp & (uint8_t) ~param) | ((uint8_t)param & data);
   2264 		EFUN(_phy8806x_tsc_wrb_uc_var (pa, addr, tmp2));
   2265 		EFUN_PRINTF(("Glob RAM RMW byte: x%04x = x%02x -> x%02x\n", addr, tmp, tmp2));
   2266 	} break;
   2267 	case SRDS_GLOB_RAM_READ_WORD: {
   2268 		if (data > 1) {
   2269 			uint16_t i;
   2270 			EFUN_PRINTF(("\n****  SERDES BLK GLOB RAM READ WORD   ****"));
   2271 			for (i = 0; i < data; i += 2) {
   2272 				if (!(i % 16))
   2273 					ESTM_PRINTF(("\n%04x ", i + addr));
   2274 				ESTM_PRINTF(("%04x ", _phy8806x_tsc_rdw_uc_var (pa, __ERR, i + addr)));
   2275 			}
   2276 			EFUN_PRINTF(("\n"));
   2277 		} else
   2278 			ESTM_PRINTF(("Glob RAM Read word: x%04x = x%04x\n", addr, _phy8806x_tsc_rdw_uc_var (pa, __ERR, addr)));
   2279 	} break;
   2280 	case SRDS_GLOB_RAM_RMW_WORD:  {
   2281 		uint16_t tmp, tmp2;
   2282 		ESTM(tmp = _phy8806x_tsc_rdw_uc_var (pa, __ERR, addr));
   2283 		tmp2 = (tmp & ~param) | (param & data);
   2284 		EFUN(_phy8806x_tsc_wrw_uc_var (pa, addr, tmp2));
   2285 		EFUN_PRINTF(("Glob RAM RMW word: x%04x = x%04x -> x%04x\n", addr, tmp, tmp2));
   2286 	} break;
   2287 	case SRDS_UC_CMD:        {
   2288 		uint16_t tmp;
   2289 		EFUN(phy8806x_tsc_pmd_uc_cmd_with_data (pa, (enum srds_pmd_uc_cmd_enum)addr, (uint8_t)param, data, 100));
   2290 		ESTM(tmp = rd_uc_dsc_data());
   2291 		EFUN_PRINTF(("uC Command: cmd=x%02x supp=x%02x data=x%04x returned=x%04x\n", addr, param, data, tmp));
   2292 	} break;
   2293 	case SRDS_BER_PROJ_DATA: {
   2294 		/* display ber projections for all channels */
   2295 		EFUN(_phy8806x_tsc_display_ber_scan_data (pa, (uint8_t)addr, (uint8_t)data,  (uint8_t)(param >> 4)));
   2296 	} break;
   2297 #ifdef TDT_CHARACTERIZATION
   2298 	case SRDS_TDT_CHAR:      {
   2299 		EFUN(phy8806x_tsc_tdt_char (pa, (enum srds_tdt_pattern_enum)addr, (uint8_t)data,  (uint8_t)param));
   2300 	} break;
   2301 #endif
   2302 	case SRDS_EN_BREAKPOINT: 
   2303 	case SRDS_GOTO_BREAKPOINT:
   2304 	case SRDS_RD_BREAKPOINT:
   2305 	case SRDS_DIS_BREAKPOINT:
   2306 	default: EFUN_PRINTF(("Invalid request type phy8806x_tsc_diag_access\n"));
   2307 	}
   2308 
   2309 	return ERR_CODE_NONE;
   2310 }
   2311 
   2312 /************************/
   2313 /*  Serdes API Version  */
   2314 /************************/
   2315 
   2316 err_code_t phy8806x_tsc_version (const phymod_access_t *pa, uint32_t *api_version){
   2317 
   2318 	if (!api_version)
   2319 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   2320 	*api_version = 0xA10210;
   2321 	return ERR_CODE_NONE;
   2322 }
   2323 
   2324 
   2325 /***************************************/
   2326 /*  API Function to Read Event Logger  */
   2327 /***************************************/
   2328 
   2329 err_code_t phy8806x_tsc_read_event_log (const phymod_access_t *pa, uint8_t *trace_mem, enum srds_event_log_display_mode_enum display_mode){
   2330 
   2331 	/* validate input arguments */
   2332 	if (trace_mem == NULL || (display_mode >= EVENT_LOG_MODE_MAX))
   2333 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   2334 
   2335 	/* stop writing event log */
   2336 	EFUN(phy8806x_tsc_event_log_stop (pa ));
   2337 
   2338 	EFUN(phy8806x_tsc_event_log_readmem (pa, trace_mem));
   2339 
   2340 	EFUN(phy8806x_tsc_event_log_display (pa, trace_mem, display_mode));
   2341 
   2342 	return ERR_CODE_NONE;
   2343 }
   2344 
   2345 err_code_t phy8806x_tsc_event_log_stop (const phymod_access_t *pa){
   2346 
   2347 
   2348 	EFUN_PRINTF(("\n\n********************************************\n"));
   2349 	EFUN_PRINTF((    "**** SERDES UC TRACE MEMORY DUMP ***********\n"));
   2350 	EFUN_PRINTF((    "********************************************\n"));
   2351 
   2352 	/* Start Read to stop uC logging and read the word at last event written by uC */
   2353 	EFUN(phy8806x_tsc_pmd_uc_cmd (pa, CMD_EVENT_LOG_READ, CMD_EVENT_LOG_READ_START, 10));
   2354 
   2355 	return ERR_CODE_NONE;
   2356 }
   2357 
   2358 err_code_t phy8806x_tsc_event_log_readmem (const phymod_access_t *pa, uint8_t *trace_mem){
   2359 	uint8_t uc_dsc_supp_info;
   2360 	uint16_t addr = 0, trace_mem_size = 0;
   2361 
   2362 	/* validate input arguments */
   2363 	if (trace_mem == NULL) return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   2364 
   2365 	ESTM_PRINTF(( "\n  DEBUG INFO: trace memory read index = 0x%04x\n", rdcv_trace_mem_rd_idx()));
   2366 
   2367 	trace_mem_size = 768;
   2368 	EFUN_PRINTF(("  DEBUG INFO: trace memory size = 0x%04x\n\n", trace_mem_size));
   2369 
   2370 	do {
   2371 		/* Read Next */
   2372 		EFUN(phy8806x_tsc_pmd_uc_cmd (pa, CMD_EVENT_LOG_READ, CMD_EVENT_LOG_READ_NEXT, 10));
   2373 
   2374 		if (addr >= trace_mem_size)
   2375 			return ERR_CODE_INVALID_EVENT_LOG_READ;
   2376 		else
   2377 			addr++;
   2378 
   2379 		ESTM(*(trace_mem++) = (uint8_t)rd_uc_dsc_data());
   2380 		ESTM(uc_dsc_supp_info = rd_uc_dsc_supp_info());
   2381 	} while (uc_dsc_supp_info != 1);
   2382 
   2383 	/* Read Done to resume logging  */
   2384 	EFUN(phy8806x_tsc_pmd_uc_cmd (pa, CMD_EVENT_LOG_READ, CMD_EVENT_LOG_READ_DONE, 10));
   2385 
   2386 	return ERR_CODE_NONE;
   2387 }
   2388 
   2389 err_code_t phy8806x_tsc_event_log_display (const phymod_access_t *pa, uint8_t *trace_mem, enum srds_event_log_display_mode_enum display_mode){
   2390 #define MAX_ENTRY_SIZE   (7)
   2391 #define NOR_ENTRY_SIZE   (4)
   2392 	uint16_t trace_mem_size = 0;
   2393 	uint8_t num_lanes = 0;
   2394 	uint8_t is_ref_time_found = 0, is_last_event_timewrap = 0;
   2395 	uint8_t post_cursor = 0, curr_cursor = 0, prev_cursor = 0;
   2396 	uint16_t addr = 0, rr = 0, prev_rr = 0;
   2397 	uint8_t cc = 0;
   2398 	uint16_t time = 0, ref_time = 0, num_time_wraparound = 0, this_num_time_wraparound = 0;
   2399 	USR_DOUBLE prev_time = 0, curr_time = 0;
   2400 	uint8_t word_per_row = 8;
   2401 	uint8_t prev_event = 0;
   2402 	uint8_t supp_info[MAX_ENTRY_SIZE - NOR_ENTRY_SIZE];
   2403 	char uc_lane_id_str[256];
   2404 	uint8_t char_0 = '0';
   2405 
   2406 	/* validate input arguments */
   2407 	if (trace_mem == NULL || (display_mode >= EVENT_LOG_MODE_MAX))
   2408 		return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   2409 
   2410 	trace_mem_size = 768;
   2411 	num_lanes = 4;
   2412 
   2413 	/* output */
   2414 	if (display_mode == EVENT_LOG_HEX || display_mode == EVENT_LOG_HEX_AND_DECODED) {
   2415 		/* print the 16-bit words in Hex format to screen, 8 words per row */
   2416 		for (rr = 0; rr < trace_mem_size; rr += (2 * word_per_row)) {
   2417 			for (cc = 0; cc < 2 * word_per_row; cc += 2)
   2418 				EFUN_PRINTF(("  0x%02x%02x", *(trace_mem + rr + cc), *(trace_mem + rr + cc + 1)));
   2419 			EFUN_PRINTF(("    %d\n", rr));
   2420 		}
   2421 	}
   2422 	if (display_mode == EVENT_LOG_DECODED || display_mode == EVENT_LOG_HEX_AND_DECODED) {
   2423 		/* decode for level 1 events */
   2424 
   2425 		/* print a text log of the events going backwards in time, showing time as T-10.340ms, where T is when the Start Read happened. */
   2426 		addr = 0;
   2427 		while (addr < trace_mem_size - 8) {                                                     /* last 8-byte reserved for trace memory wraparound */
   2428 
   2429 			if (*(trace_mem + addr) == 0x0) {                                               /* reach event log end */
   2430 				EFUN_PRINTF(("\n========== End of Event Log ==================\n"));
   2431 				break;
   2432 			}
   2433 
   2434 			if (*(trace_mem + addr) == 0xff) {                                           /* timestamp wraparound event handling */
   2435 
   2436 				this_num_time_wraparound = *(trace_mem + (++addr));
   2437 				this_num_time_wraparound = ((this_num_time_wraparound << 8) | *(trace_mem + (++addr)));
   2438 				num_time_wraparound += this_num_time_wraparound;
   2439 
   2440 				if (!is_last_event_timewrap) {                                         /* display the rest of previous event info */
   2441 					EFUN_PRINTF((","));
   2442 					EFUN(_display_event (pa, prev_event, (uint8_t)prev_rr, prev_cursor, curr_cursor, post_cursor, supp_info));
   2443 					is_last_event_timewrap = 1;
   2444 				}
   2445 
   2446 				EFUN_PRINTF(("\n  %5d timestamp wraparound(s). \n\n", this_num_time_wraparound));
   2447 				this_num_time_wraparound = 0;
   2448 
   2449 				addr++;
   2450 				continue;
   2451 			}else  {
   2452 				cc = (trace_mem[addr] & 0x1f);                                         /* lane id */
   2453 				if (cc >= num_lanes) {
   2454 					EFUN_PRINTF(("\n\n  Incorrect lane ID. Terminating event log display for current core... \n\n"));
   2455 					break;
   2456 				}
   2457 
   2458 				rr = (uint16_t)((trace_mem[addr] >> 5) & 0x7);                          /* determine event entry length */
   2459 
   2460 				time = *(trace_mem + (++addr));                                         /* timestamp */
   2461 				time = ((time << 8) | *(trace_mem + (++addr)));
   2462 				if (is_ref_time_found == 0) {                                           /* determine the reference time origin */
   2463 					is_ref_time_found = 1;
   2464 					ref_time = time;
   2465 				}else  {
   2466 #ifdef SERDES_API_FLOATING_POINT
   2467 					curr_time = (time - ref_time - (num_time_wraparound * 65536)) / 100.0;
   2468 #else
   2469 					curr_time = (time - ref_time - (num_time_wraparound * 65536)) / 100;
   2470 #endif
   2471 					if (!is_last_event_timewrap) {
   2472 #ifdef SERDES_API_FLOATING_POINT
   2473 						EFUN_PRINTF((" (+%.2f),", prev_time - curr_time));
   2474 #else
   2475 						EFUN_PRINTF((" (+%d),", prev_time - curr_time));
   2476 #endif
   2477 						EFUN(_display_event (pa, prev_event, (uint8_t)prev_rr, prev_cursor, curr_cursor, post_cursor, supp_info));
   2478 					}else
   2479 						is_last_event_timewrap = 0;
   2480 				}
   2481 
   2482 				if (cc < 10) {
   2483 					uc_lane_id_str[0] = char_0 + cc;
   2484 					uc_lane_id_str[1] = '\0';
   2485                 /* CID 2009523 Logically DeadCode :  ignore */
   2486 				} else if (cc < 100) {
   2487 					uc_lane_id_str[0] = char_0 + (cc / 10);
   2488 					uc_lane_id_str[1] = char_0 + (cc % 10);
   2489 					uc_lane_id_str[2] = '\0';
   2490 				} else {
   2491 					uc_lane_id_str[0] = char_0 + (cc / 100);
   2492 					uc_lane_id_str[1] = char_0 + ((cc % 100) - (cc % 10)) / 10;
   2493 					uc_lane_id_str[2] = char_0 + (cc % 10);
   2494 					uc_lane_id_str[3] = '\0';
   2495 				}
   2496 
   2497 				EFUN(phy8806x_tsc_uc_lane_idx_to_system_id(uc_lane_id_str, cc));
   2498 				EFUN_PRINTF(("  Lane %s: ", uc_lane_id_str));
   2499 #ifdef SERDES_API_FLOATING_POINT
   2500 				EFUN_PRINTF(("  t= %.2f ms", curr_time));
   2501 #else
   2502 				EFUN_PRINTF(("  t= %d ms", curr_time));
   2503 #endif
   2504 				prev_time = curr_time;
   2505 				prev_rr = rr;
   2506 
   2507 				prev_event = *(trace_mem + (++addr));
   2508 				switch (prev_event) {
   2509 				case EVENT_CODE_CL72_READY_FOR_COMMAND:
   2510 				case EVENT_CODE_EACH_WRITE_TO_CL72_TX_CHANGE_REQUEST:
   2511 				case EVENT_CODE_CL72_LOCAL_TX_CHANGED:
   2512 					if (rr != NOR_ENTRY_SIZE) {
   2513 						post_cursor = (*(trace_mem + (++addr)) & 0x30) >> 4;
   2514 						curr_cursor = (*(trace_mem + addr) & 0x0C) >> 2;
   2515 						prev_cursor = *(trace_mem + addr) & 0x03;
   2516 						addr--;                                 /* rewind to populate supplement info */
   2517 					}
   2518 					break;
   2519 				case EVENT_CODE_GENERAL_EVENT_0:
   2520 				case EVENT_CODE_GENERAL_EVENT_1:
   2521 				case EVENT_CODE_GENERAL_EVENT_2:
   2522 					post_cursor = *(trace_mem + (++addr));
   2523 					prev_cursor = *(trace_mem + (++addr));
   2524 					addr -= 2;                                     /* rewind to populate supplement info */
   2525 					break;
   2526 				case EVENT_CODE_ERROR_EVENT:
   2527 					post_cursor = *(trace_mem + (++addr));
   2528 					addr--;
   2529 					break;
   2530 				case EVENT_CODE_SM_STATUS_RESTART:
   2531 					post_cursor = *(trace_mem + (++addr));
   2532 					addr--;
   2533 					break;
   2534 				default:
   2535 					break;
   2536 				}
   2537 
   2538 				/* retrieve supplement info, if any */
   2539 				for (cc = 0; cc < rr - NOR_ENTRY_SIZE; cc++)
   2540 					supp_info[cc] = *(trace_mem + (++addr));
   2541 
   2542 				addr++;
   2543 			}
   2544 		}
   2545 	}
   2546 
   2547 	return ERR_CODE_NONE;
   2548 }
   2549 
   2550 
   2551 err_code_t phy8806x_tsc_display_state (const phymod_access_t *pa){
   2552 	EFUN(phy8806x_tsc_display_core_state (pa ));
   2553 	EFUN(phy8806x_tsc_display_lane_state_hdr (pa ));
   2554 	EFUN(phy8806x_tsc_display_lane_state (pa ));
   2555 	EFUN(phy8806x_tsc_display_lane_state_legend (pa ));
   2556 	return ERR_CODE_NONE;
   2557 }
   2558 
   2559 err_code_t phy8806x_tsc_display_config (const phymod_access_t *pa){
   2560 	EFUN(phy8806x_tsc_display_core_config (pa ));
   2561 	EFUN(phy8806x_tsc_display_lane_config (pa ));
   2562 	return ERR_CODE_NONE;
   2563 }
   2564 
   2565 
   2566 /**********************************************/
   2567 /*  Temperature forcing and reading           */
   2568 /**********************************************/
   2569 
   2570 err_code_t phy8806x_tsc_force_die_temperature (const phymod_access_t *pa, int16_t die_temp){
   2571 	/* Formula for PVTMON: T = 410.04-0.48705*reg10bit (from PVTMON Analog Module Specification v5.0 section 6.2) */
   2572 	int32_t die_temp_int;
   2573 
   2574 	if (die_temp > 130)
   2575 		die_temp = 130;
   2576 	if (die_temp < -45)
   2577 		die_temp = -45;
   2578 
   2579 	die_temp_int = (int32_t)die_temp;
   2580 	EFUN(wrcv_temp_frc_val((uint16_t)((431045 - ((die_temp_int << 10) + (die_temp_int << 4) + (die_temp_int << 3) + (die_temp_int << 1) + die_temp_int)) >> 9)));
   2581 
   2582 	return ERR_CODE_NONE;
   2583 }
   2584 
   2585 err_code_t phy8806x_tsc_read_die_temperature (const phymod_access_t *pa, int16_t *die_temp){
   2586 
   2587 	uint16_t die_temp_sensor_reading;
   2588 
   2589 	EFUN(phy8806x_tsc_pmd_uc_cmd (pa, CMD_UC_DBG, CMD_UC_DBG_DIE_TEMP, 100));
   2590 	ESTM(die_temp_sensor_reading = rd_uc_dsc_data());
   2591 	*die_temp = _bin_to_degC(die_temp_sensor_reading);
   2592 
   2593 	return ERR_CODE_NONE;
   2594 }
   2595 
   2596 
   2597 err_code_t phy8806x_tsc_read_die_temperature_double (const phymod_access_t *pa, USR_DOUBLE *die_temp){
   2598 #ifdef SERDES_API_FLOATING_POINT
   2599 	/* Formula for PVTMON: T = 410.04-0.48705*reg10bit (from PVTMON Analog Module Specification v5.0 section 6.2) */
   2600 	uint16_t die_temp_sensor_reading;
   2601 
   2602 	EFUN(phy8806x_tsc_pmd_uc_cmd (pa, CMD_UC_DBG, CMD_UC_DBG_DIE_TEMP, 100));
   2603 	ESTM(die_temp_sensor_reading = rd_uc_dsc_data());
   2604 
   2605 	*die_temp = 410.04 - 0.48705 * ((USR_DOUBLE)die_temp_sensor_reading);
   2606 
   2607 	return ERR_CODE_NONE;
   2608 #else
   2609 	EFUN_PRINTF((" Function 'phy8806x_tsc_read_die_temperature_double' needs SERDES_API_FLOATING_POINT defined to operate \n"));
   2610 	return _error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   2611 #endif
   2612 }
   2613 
   2614 
   2615 
   2616 
   2617 
   2618 err_code_t phy8806x_tsc_config_tx_fctts (const phymod_access_t *pa, uint16_t tx_pll_sel, uint16_t tx_osr_mode, uint16_t tx_fctts_update_page, uint16_t tx_fctts_status_page){
   2619 	EFUN(wr_tx_pll_select(tx_pll_sel));
   2620 
   2621 	EFUN(wr_tx_osr_mode_frc(1));
   2622 	EFUN(wr_tx_osr_mode_frc_val(tx_osr_mode));
   2623 
   2624 	EFUN(wr_cl93n72_tx_fctts_sn_en(1));
   2625 	EFUN(wr_cl93n72_prbs_mode_sel(0));
   2626 
   2627 	EFUN(wr_cl93n72_xmt_update_page(tx_fctts_update_page));
   2628 	EFUN(wr_cl93n72_ld_xmt_status_page(tx_fctts_status_page));
   2629 
   2630 	return ERR_CODE_NONE;
   2631 }
   2632 
   2633 err_code_t phy8806x_tsc_config_rx_fctts (const phymod_access_t *pa, uint16_t rx_pll_sel, uint16_t rx_osr_mode, uint16_t rx_fctts_sync_count_chkval, uint16_t rx_fctts_ext_marker_chk_en){
   2634 	EFUN(wr_rx_pll_select(rx_pll_sel));
   2635 
   2636 	EFUN(wr_rx_osr_mode_frc(1));
   2637 	EFUN(wr_rx_osr_mode_frc_val(rx_osr_mode));
   2638 
   2639 	
   2640 
   2641 	EFUN(wr_cl93n72_rx_fctts_sn_en(1));
   2642 	EFUN(wr_cl93n72_prbs_mode_sel(0));
   2643 	ESTM(rd_cl93n72_rx_fctts_status0());
   2644 
   2645 	EFUN(wr_cl93n72_rx_fctts_sync_count_chkval(rx_fctts_sync_count_chkval));
   2646 	EFUN(wr_cl93n72_rx_fctts_sync_count_clr(1));
   2647 	EFUN(wr_cl93n72_rx_fctts_ext_marker_check_en(rx_fctts_ext_marker_chk_en));
   2648 
   2649 	return ERR_CODE_NONE;
   2650 }
   2651 
   2652 err_code_t phy8806x_tsc_fctts_sn_to_trn (const phymod_access_t *pa, uint16_t xmt_update_page, uint16_t xmt_status_page, uint8_t tts_prbs_sel){
   2653 	/* configure update page and status page in TX TTS frames */
   2654 	EFUN(wr_cl93n72_ignore_xmt_reg_value(1));
   2655 	EFUN(wr_cl93n72_xmt_update_page(xmt_update_page));
   2656 	EFUN(wr_cl93n72_ld_xmt_status_page(xmt_status_page));
   2657 	EFUN(wr_cl93n72_ignore_xmt_reg_value(0));
   2658 
   2659 	/* specify traffic type after FC training */
   2660 	if (tts_prbs_sel == 0)
   2661 		EFUN(wr_cl93n72_send_fctts_after_training(1));
   2662 	else if (tts_prbs_sel == 1)
   2663 		EFUN(wr_prbs_gen_en(1));
   2664 	else {
   2665 		EFUN_PRINTF(("phy8806x_tsc_fctts_sn_to_trn: Invalid TTS PRBS traffic selection."));
   2666 		return ERR_CODE_INVALID_TTS_PRBS_TRAFFIC_SEL;
   2667 	}
   2668 
   2669 	EFUN(wr_cl93n72_timer_value_sel(1));
   2670 
   2671 	/* enable FC TTS training */
   2672 	EFUN(wr_cl93n72_ieee_training_enable(1));
   2673 	EFUN(wr_cl93n72_rx_training_en(1));
   2674 
   2675 	/* disable FC TTS speed negotiation */
   2676 	EFUN(wr_cl93n72_tx_fctts_sn_en(0));
   2677 	EFUN(wr_cl93n72_rx_fctts_sn_en(0));
   2678 
   2679 	/* request PMD f/w for a mode change */
   2680 	EFUN(wr_cl93n72_fctts_sn_to_trn_req(1));
   2681 
   2682 	/* wait for PMD f/w to complete mode change */
   2683 	EFUN(phy8806x_tsc_poll_fctts_sn_to_trn_req (pa, 1000));
   2684 
   2685 	return ERR_CODE_NONE;
   2686 }
   2687 
   2688 err_code_t phy8806x_tsc_poll_fctts_sn_to_trn_req (const phymod_access_t *pa, uint32_t timeout_ms){
   2689 	uint16_t loop;
   2690 	uint16_t fctts_sn_to_trn_req_set = 1;
   2691 
   2692 	/* poll 10 times to avoid longer delays later */
   2693 	for (loop = 0; loop < 100; loop++) {
   2694 		ESTM(fctts_sn_to_trn_req_set = rd_cl93n72_fctts_sn_to_trn_req());
   2695 		if (!fctts_sn_to_trn_req_set)
   2696 			return ERR_CODE_NONE;
   2697 		if (loop > 10)
   2698 			EFUN(phy8806x_tsc_delay_us(10 * timeout_ms));
   2699 	}
   2700 	ESTM_PRINTF(("cl93n72_fctts_sn_to_trn_req = %d\n", fctts_sn_to_trn_req_set));
   2701 	return _error(ERR_CODE_POLLING_TIMEOUT);      /* Error Code for polling timeout */
   2702 }
   2703