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