merlin16_diag.c (83618B)
1 /*********************************************************************************** 2 *********************************************************************************** 3 * File Name : merlin16_diag.c * 4 * Created On : 03 Nov 2015 * 5 * Created By : Brent Roberts * 6 * Description : Diagnostic APIs for Serdes IPs * 7 * Revision : * 8 * * 9 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 10 * 11 * Copyright 2007-2019 Broadcom Inc. All rights reserved. * 12 * No portions of this material may be reproduced in any form without * 13 * the written permission of: * 14 * Broadcom Corporation * 15 * 5300 California Avenue * 16 * Irvine, CA 92617 * 17 * * 18 * All information contained in this document is Broadcom Corporation * 19 * company private proprietary, and trade secret. * 20 */ 21 22 /** @file merlin16_diag.c 23 * Implementation of API functions 24 */ 25 26 #ifdef NON_SDK 27 #include <stdio.h> 28 #endif 29 30 #ifdef _MSC_VER 31 /* Enclose all standard headers in a pragma to remove warings for MS compiler */ 32 #pragma warning( push, 0 ) 33 #endif 34 35 #ifdef SERDES_API_FLOATING_POINT 36 #include <math.h> 37 #endif 38 #ifdef _MSC_VER 39 #pragma warning( pop ) 40 #endif 41 42 #include <phymod/phymod.h> 43 #include <phymod/phymod_system.h> 44 #include "merlin16_diag.h" 45 #include "merlin16_access.h" 46 #include "merlin16_config.h" 47 #include "merlin16_debug_functions.h" 48 #include "merlin16_functions.h" 49 #include "merlin16_internal.h" 50 #include "merlin16_internal_error.h" 51 #include "merlin16_prbs.h" 52 #include "merlin16_select_defns.h" 53 54 55 /************************************/ 56 /* Display Eye Scan */ 57 /************************************/ 58 59 60 /* This is best method for terminal ASCII display */ 61 err_code_t merlin16_display_eye_scan(srds_access_t *sa__) { 62 uint32_t stripe[64] = {0}; 63 uint16_t status = 0; 64 int8_t y,y_max,y_step; 65 66 y_max = EYE_SCAN_NRZ_VERTICAL_IDX_MAX; 67 y_step = EYE_SCAN_NRZ_VERTICAL_STEP; 68 69 EFUN(merlin16_display_eye_scan_header(1)); 70 71 /* start horizontal acquisition */ 72 { err_code_t err_code = merlin16_meas_eye_scan_start(sa__, EYE_SCAN_HORIZ); 73 if (err_code) { 74 EFUN((merlin16_meas_eye_scan_done(sa__), err_code)); 75 } 76 } 77 78 for (y = y_max;y>=-y_max;y=y-y_step) 79 { 80 { err_code_t err_code = merlin16_read_eye_scan_stripe(sa__, &stripe[0], &status); 81 if (err_code) { 82 EFUN((merlin16_meas_eye_scan_done(sa__), err_code)); 83 } 84 } 85 EFUN(merlin16_display_eye_scan_stripe(sa__, y,&stripe[0])); 86 EFUN_PRINTF(("\n")); 87 } 88 /* stop acquisition */ 89 EFUN(merlin16_meas_eye_scan_done(sa__)); 90 EFUN(merlin16_display_eye_scan_footer(1)); 91 92 return(ERR_CODE_NONE); 93 } 94 95 err_code_t merlin16_meas_eye_scan_start(srds_access_t *sa__, uint8_t direction) { 96 uint8_t lock; 97 98 ESTM(lock = rd_pmd_rx_lock()); 99 if(lock == 0) { 100 EFUN_PRINTF(("Error: No PMD_RX_LOCK on lane requesting 2D eye scan\n")); 101 return(ERR_CODE_DIAG_SCAN_NOT_COMPLETE); 102 } 103 if(direction == EYE_SCAN_VERTICAL) { 104 EFUN(merlin16_pmd_uc_diag_cmd(sa__, CMD_UC_DIAG_START_VSCAN_EYE,GRACEFUL_STOP_TIME)); 105 } else if(direction == EYE_SCAN_HORIZ) { 106 EFUN(merlin16_pmd_uc_diag_cmd(sa__, CMD_UC_DIAG_START_HSCAN_EYE,GRACEFUL_STOP_TIME)); 107 } else if(direction == EYE_SCAN_SLICE) { 108 EFUN(merlin16_pmd_uc_diag_cmd(sa__, CMD_UC_DIAG_START_EYE_SLICE,GRACEFUL_STOP_TIME)); 109 } 110 return(ERR_CODE_NONE); 111 } 112 113 err_code_t merlin16_INTERNAL_poll_diag_data(srds_access_t *sa__, const merlin16_info_t *merlin16_info_ptr, uint16_t *status, uint8_t *diag_rd_ptr, uint8_t byte_count, uint32_t timeout_ms) { 114 const uint32_t lane_diag_size = merlin16_info_ptr->diag_mem_ram_size; 115 uint16_t loop; 116 117 *diag_rd_ptr = 0; 118 119 if(!status) { 120 return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT)); 121 } 122 123 /** If the byte_count is too high, then there might be problems not updating 124 * the read pointer fast enough. 125 */ 126 if (byte_count > (lane_diag_size / 2)) { 127 ESTM_PRINTF(("\nERROR : merlin16_INTERNAL_poll_diag_data() has excessive byte count of %d.\n", byte_count)); 128 return (_error(ERR_CODE_DIAG_TIMEOUT)); 129 } 130 131 ESTM(*diag_rd_ptr = rdv_usr_diag_rd_ptr()); 132 133 /* Wait until byte_count bytes are available to be read in the diagnostic memory. */ 134 loop = 0; 135 while (1) { 136 uint8_t diag_wr_ptr, full_count; 137 138 ESTM(diag_wr_ptr = rdv_usr_diag_wr_ptr()); 139 if (diag_wr_ptr >= *diag_rd_ptr) { 140 full_count = diag_wr_ptr - *diag_rd_ptr; 141 } else { 142 full_count = (uint16_t)diag_wr_ptr + lane_diag_size - *diag_rd_ptr; 143 } 144 if (full_count >= byte_count) { 145 break; 146 } 147 148 ++loop; 149 if (loop > 10) { 150 EFUN(USR_DELAY_US(10*timeout_ms)); 151 } 152 if (loop > 1000) { 153 return(_error(ERR_CODE_DIAG_TIMEOUT)); 154 } 155 } 156 ESTM(*status = rdv_usr_diag_status() & 0xFF); 157 return(ERR_CODE_NONE); 158 } 159 160 typedef struct { 161 uint32_t *buffer_ptr; 162 } merlin16_read_eye_scan_stripe_callback_arg_t; 163 164 static err_code_t merlin16_read_eye_scan_stripe_callback(void *arg, uint8_t byte_count, uint16_t data) { 165 merlin16_read_eye_scan_stripe_callback_arg_t * const cast_arg = (merlin16_read_eye_scan_stripe_callback_arg_t *)arg; 166 *(cast_arg->buffer_ptr++) = merlin16_INTERNAL_float8_to_int32((float8_t)(data & 0xFF)); 167 if (byte_count > 1) { 168 *(cast_arg->buffer_ptr++) = merlin16_INTERNAL_float8_to_int32((float8_t)(data >> 8)); 169 } 170 return (ERR_CODE_NONE); 171 } 172 173 err_code_t merlin16_read_eye_scan_stripe(srds_access_t *sa__, uint32_t *buffer, uint16_t *status) { 174 merlin16_info_t const * const merlin16_info_ptr = merlin16_INTERNAL_get_merlin16_info_ptr(); 175 const uint8_t lane = merlin16_get_lane(sa__); 176 const uint8_t stripe_size = 64; 177 178 merlin16_read_eye_scan_stripe_callback_arg_t arg; 179 uint32_t lane_diag_base; 180 uint8_t diag_rd_ptr; 181 182 if(!buffer || !status) { 183 return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT)); 184 } 185 186 EFUN(merlin16_INTERNAL_verify_merlin16_info(merlin16_info_ptr, sa__)); 187 188 lane_diag_base = merlin16_info_ptr->diag_mem_ram_base + ((lane%merlin16_info_ptr->lane_count) * merlin16_info_ptr->diag_mem_ram_size) + 189 merlin16_info_ptr->grp_ram_size*merlin16_INTERNAL_grp_idx_from_lane(merlin16_get_physical_lane(sa__)); 190 191 EFUN(merlin16_INTERNAL_poll_diag_data(sa__, merlin16_info_ptr, status, &diag_rd_ptr, stripe_size, 400)); 192 193 arg.buffer_ptr = buffer; 194 EFUN(merlin16_INTERNAL_rdblk_uc_generic_ram(sa__, 195 lane_diag_base, 196 merlin16_info_ptr->diag_mem_ram_size, 197 diag_rd_ptr, 198 stripe_size, 199 &arg, 200 merlin16_read_eye_scan_stripe_callback)); 201 202 diag_rd_ptr = ((uint32_t)diag_rd_ptr + stripe_size) % merlin16_info_ptr->diag_mem_ram_size; 203 EFUN(wrv_usr_diag_rd_ptr(diag_rd_ptr)); 204 ESTM(*status = rdv_usr_diag_status() & 0xFF); 205 return(ERR_CODE_NONE); 206 } 207 208 err_code_t merlin16_display_eye_scan_stripe(srds_access_t *sa__, int8_t y,uint32_t *buffer) { 209 210 const uint32_t limits[7] = {917504, 91750, 9175, 917, 91, 9, 1}; 211 212 int8_t x,i; 213 int8_t data_thresh; 214 int16_t level; 215 216 217 ESTM(data_thresh = rd_p1_thresh_sel()); 218 level = merlin16_INTERNAL_ladder_setting_to_mV(sa__, y,data_thresh); 219 220 if(!buffer) { 221 return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT)); 222 } 223 224 EFUN_PRINTF(("%6dmV : ", level)); 225 226 for (x=-31;x<32;x++) { 227 for (i=0;i<7;i++) { 228 if (buffer[x+31]>=limits[i]) { 229 EFUN_PRINTF(("%c", '0'+i+1)); 230 break; 231 } 232 } 233 if (i==7) { 234 if ((x%5)==0 && (y%5)==0) {EFUN_PRINTF(("+"));} 235 else if ((x%5)!=0 && (y%5)==0) {EFUN_PRINTF(("-"));} 236 else if ((x%5)==0 && (y%5)!=0) {EFUN_PRINTF((":"));} 237 else {EFUN_PRINTF((" "));} 238 } 239 } 240 return(ERR_CODE_NONE); 241 } 242 243 err_code_t merlin16_display_eye_scan_header(int8_t i) { 244 int8_t x; 245 EFUN_PRINTF(("\n")); 246 EFUN_PRINTF((" Each character N represents approximate error rate 1e-N at that location\n")); 247 for(x=1;x<=i;x++) { 248 EFUN_PRINTF((" UI/64 : -30 -25 -20 -15 -10 -5 0 5 10 15 20 25 30")); 249 } 250 EFUN_PRINTF(("\n")); 251 for(x=1;x<=i;x++) { 252 EFUN_PRINTF((" : -|----|----|----|----|----|----|----|----|----|----|----|----|-")); 253 } 254 EFUN_PRINTF(("\n")); 255 return(ERR_CODE_NONE); 256 } 257 258 err_code_t merlin16_display_eye_scan_footer(int8_t i) { 259 int8_t x; 260 for(x=1;x<=i;x++) { 261 EFUN_PRINTF((" : -|----|----|----|----|----|----|----|----|----|----|----|----|-")); 262 } 263 EFUN_PRINTF(("\n")); 264 for(x=1;x<=i;x++) { 265 EFUN_PRINTF((" UI/64 : -30 -25 -20 -15 -10 -5 0 5 10 15 20 25 30")); 266 } 267 EFUN_PRINTF(("\n")); 268 return(ERR_CODE_NONE); 269 } 270 271 272 err_code_t merlin16_read_eye_scan_status(srds_access_t *sa__, uint16_t *status) { 273 274 if(!status) { 275 return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT)); 276 } 277 278 ESTM(*status=rdv_usr_diag_status()); 279 280 return(ERR_CODE_NONE); 281 } 282 283 284 err_code_t merlin16_meas_eye_scan_done(srds_access_t *sa__) { 285 EFUN(merlin16_pmd_uc_diag_cmd(sa__, CMD_UC_DIAG_DISABLE,GRACEFUL_STOP_TIME)); 286 return(ERR_CODE_NONE); 287 } 288 289 290 err_code_t merlin16_start_ber_scan_test(srds_access_t *sa__, uint8_t ber_scan_mode, uint8_t timer_control, uint8_t max_error_control) { 291 uint8_t lock,sts; 292 ESTM(lock = rd_pmd_rx_lock()); 293 if(lock == 0) { 294 EFUN_PRINTF(("Error: No PMD_RX_LOCK on lane requesting BER scan\n")); 295 return(ERR_CODE_DIAG_SCAN_NOT_COMPLETE); 296 } 297 ESTM(sts =rdv_usr_sts_micro_stopped()); 298 if(sts > 1) { 299 EFUN_PRINTF(("Error: Lane is busy (%d) requesting BER scan\n",sts)); 300 return(ERR_CODE_DIAG_SCAN_NOT_COMPLETE); 301 } 302 303 EFUN(wrcv_diag_max_time_control(timer_control)); 304 EFUN(wrcv_diag_max_err_control(max_error_control)); 305 EFUN(merlin16_pmd_uc_cmd(sa__, CMD_CAPTURE_BER_START, ber_scan_mode,GRACEFUL_STOP_TIME)); 306 return(ERR_CODE_NONE); 307 } 308 309 err_code_t merlin16_read_ber_scan_data(srds_access_t *sa__, uint32_t *errors, uint32_t *timer_values, uint8_t *cnt, uint32_t timeout) { 310 uint8_t i,prbs_byte,prbs_multi,time_byte,time_multi; 311 uint16_t sts,dataword; 312 313 314 if(!errors || !timer_values || !cnt) { 315 return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT)); 316 } 317 /* init data arrays */ 318 for(i=0;i< DIAG_MAX_SAMPLES;i++) { 319 errors[i]=0; 320 timer_values[i]=0; 321 } 322 /* Check for completion read ln.diag_status byte?*/ 323 ESTM(sts = rdv_usr_diag_status()); 324 if((sts & 0x8000) == 0) { 325 return(_error(ERR_CODE_DATA_NOTAVAIL)); 326 } 327 *cnt = (sts & 0x00FF)/3; 328 for(i=0;i < *cnt;i++) { 329 /* Read 2 bytes of data */ 330 EFUN(merlin16_pmd_uc_cmd(sa__, CMD_READ_DIAG_DATA_WORD, 0, timeout)); 331 ESTM(dataword = rd_uc_dsc_data()); /* LSB contains 2 -4bit nibbles */ 332 time_byte = (uint8_t)(dataword>>8); /* MSB is time byte */ 333 prbs_multi = (uint8_t)dataword & 0x0F; /* split nibbles */ 334 time_multi = (uint8_t)dataword>>4; 335 /* Read 1 bytes of data */ 336 EFUN(merlin16_pmd_uc_cmd(sa__, CMD_READ_DIAG_DATA_BYTE, 0, timeout)); 337 ESTM(prbs_byte = (uint8_t)rd_uc_dsc_data()); 338 errors[i] = merlin16_INTERNAL_float12_to_uint32(prbs_byte,prbs_multi); /* convert 12bits to uint32 */ 339 timer_values[i] = (merlin16_INTERNAL_float12_to_uint32(time_byte,time_multi)<<3); 340 /* 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)); */ 341 /*if(timer_values[i] == 0 && errors[i] == 0) break;*/ 342 } 343 344 return(ERR_CODE_NONE); 345 } 346 347 348 /* This is good example function to do BER extrapolation */ 349 err_code_t merlin16_eye_margin_proj(srds_access_t *sa__, USR_DOUBLE rate, uint8_t ber_scan_mode, uint8_t timer_control, uint8_t max_error_control) { 350 uint32_t errs[DIAG_MAX_SAMPLES]; 351 uint32_t time[DIAG_MAX_SAMPLES]; 352 uint8_t i,cnt=0; 353 uint16_t sts; 354 int16_t offset_start; 355 /* Below 'DIAG_VERBOSE' level is intended to be modified only within a debug */ 356 /* session immediately after a breakpoint, and to retain its state only */ 357 /* through function exit: therefore it must be 'volatile' to prevent a */ 358 /* compiler from eliding code conditioned on it, but NOT 'static'. */ 359 360 361 for(i=0;i<DIAG_MAX_SAMPLES;i++) { 362 errs[i]=0; 363 time[i]=0; 364 } 365 /* start UC acquisition */ 366 if(DIAG_VERBOSE > 2) EFUN_PRINTF(("start begin\n")); 367 EFUN(merlin16_start_ber_scan_test(sa__, ber_scan_mode, timer_control, max_error_control)); 368 ESTM(offset_start = rd_uc_dsc_data()); 369 if(DIAG_VERBOSE > 2) EFUN_PRINTF(("offset_start = %d:%dmV\n",offset_start,merlin16_INTERNAL_ladder_setting_to_mV(sa__, (int8_t)offset_start,0))); 370 if(DIAG_VERBOSE > 2) EFUN_PRINTF(("start done\n")); 371 372 /* This wait is VERY LONG and should be replaced with interupt or something */ 373 if(DIAG_VERBOSE > 5) { 374 do { 375 EFUN(USR_DELAY_US(2000000)); 376 ESTM(sts = rdv_usr_diag_status()); 377 EFUN_PRINTF(("sts=%04x\n",sts)); 378 379 } while ((sts & 0x8000) == 0); 380 } else { 381 EFUN_PRINTF(("Waiting for measurement time approx %d seconds",timer_control+(timer_control>>1))); 382 EFUN(merlin16_INTERNAL_poll_diag_done(sa__, &sts,timer_control*2000)); 383 } 384 if(DIAG_VERBOSE > 2) EFUN_PRINTF(("delay done\n")); 385 386 EFUN(merlin16_read_ber_scan_data(sa__, &errs[0], &time[0], &cnt, 2000)); 387 388 if(DIAG_VERBOSE > 2) EFUN_PRINTF(("read done cnt=%d\n",cnt)); 389 390 EFUN(merlin16_pmd_uc_cmd(sa__, CMD_CAPTURE_BER_END,0x00,200)); 391 392 if(DIAG_VERBOSE > 2) EFUN_PRINTF(("end function done\n")); 393 /* if(cnt == 1) { */ 394 /* EFUN_PRINTF(("Not enough points found to extrapolate BER\n")); */ 395 /* return(ERR_CODE_NONE); */ 396 /* } */ 397 398 EFUN(merlin16_display_ber_scan_data(sa__, rate, ber_scan_mode, &errs[0], &time[0],(uint8_t)SRDS_ABS(offset_start))); 399 400 if(DIAG_VERBOSE > 2) EFUN_PRINTF(("display done\n")); 401 402 return(ERR_CODE_NONE); 403 } 404 405 406 407 err_code_t merlin16_display_ber_scan_data (srds_access_t *sa__, USR_DOUBLE rate, uint8_t ber_scan_mode, uint32_t *total_errs, uint32_t *total_time, uint8_t max_offset) { 408 409 #ifdef SERDES_API_FLOATING_POINT 410 /* 'margins_mv[]' vector maps the p1 threshold code with actual mV 411 Only relevant when mode=0 412 This is not totally linear: for code 0~25 step=6mV; code 25~30 step=18mV; code 30~31 step=12 413 'margins_mv[]' is valid only for Merlin. This vector would need to be modified accordingly for different Serdes 414 USR_DOUBLE margins_mv[] = {0,6,12,18,24,30,36,42,48,54,60,66,72,78,84, 415 90,96,102,108,114,120,126,132,138,144,150,168,186,204,222,240,252}; 416 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, 417 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}; */ 418 #if !defined(STANDALONE_EVENT) 419 420 421 const USR_DOUBLE intrusive_margins_mv[] = {2,6,10,14,18,22,26,30,32,36,40,44,48,52,56,60}; 422 #endif 423 424 const unsigned int HI_CONFIDENCE_ERR_CNT = 100; /* bit errors */ 425 const unsigned int HI_CONFIDENCE_MIN_ERR_CNT = 20; /* bit errors */ 426 const unsigned int MAX_CLIPPED_ERR_CNT = 8355840; 427 const USR_DOUBLE ARTIFICIAL_BER = 0.5; /* used along ARTIFICIAL_MARGIN(_V/_H) when not enough points to extrapolate */ 428 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 */ 429 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 */ 430 const int MIN_BER_TO_REPORT = -24; /* we clip the projected BER using this number */ 431 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) */ 432 433 /* BER confidence scale */ 434 const USR_DOUBLE ber_conf_scale[104] = { 435 2.9957,5.5717,3.6123,2.9224,2.5604,2.3337,2.1765,2.0604,1.9704,1.8983, 436 1.8391,1.7893,1.7468,1.7100,1.6778,1.6494,1.6239,1.6011,1.5804,1.5616, 437 1.5444,1.5286,1.5140,1.5005,1.4879,1.4762,1.4652,1.4550,1.4453,1.4362, 438 1.4276,1.4194,1.4117,1.4044,1.3974,1.3908,1.3844,1.3784,1.3726,1.3670, 439 1.3617,1.3566,1.3517,1.3470,1.3425,1.3381,1.3339,1.3298,1.3259,1.3221, 440 1.3184,1.3148,1.3114,1.3080,1.3048,1.3016,1.2986,1.2956,1.2927,1.2899, 441 1.2872,1.2845,1.2820,1.2794,1.2770,1.2746,1.2722,1.2700,1.2677,1.2656, 442 1.2634,1.2614,1.2593,1.2573,1.2554,1.2535,1.2516,1.2498,1.2481,1.2463, 443 1.2446,1.2429,1.2413,1.2397,1.2381,1.2365,1.2350,1.2335,1.2320,1.2306, 444 1.2292,1.2278,1.2264,1.2251,1.2238,1.2225,1.2212,1.2199,1.2187,1.2175, 445 1.2163, /* starts in index: 100 for #errors: 100,200,300,400 */ 446 1.1486, /* 200 */ 447 1.1198, /* 300 */ 448 1.1030}; /*400 */ 449 450 451 /* Define variables */ 452 USR_DOUBLE lbers[DIAG_MAX_SAMPLES] = {0}; /* Internal linear scale sqrt(-log(ber)) */ 453 USR_DOUBLE margins[DIAG_MAX_SAMPLES] = {0}; /* Eye margin @ each measurement */ 454 USR_DOUBLE bers[DIAG_MAX_SAMPLES] = {0}; /* computed bit error rate */ 455 uint32_t i; 456 int8_t offset[DIAG_MAX_SAMPLES]; 457 int8_t mono_flags[DIAG_MAX_SAMPLES]; 458 459 int8_t direction; 460 uint8_t heye; 461 int8_t delta_n=1; 462 USR_DOUBLE Exy = 0.0; 463 USR_DOUBLE Eyy = 0.0; 464 USR_DOUBLE Exx = 0.0; 465 USR_DOUBLE Ey = 0.0; 466 USR_DOUBLE Ex = 0.0; 467 USR_DOUBLE alpha = 0.0; 468 USR_DOUBLE gauss_noise = -1; 469 USR_DOUBLE beta = 0.0; 470 USR_DOUBLE sq_r = 0.0, alpha2 = 0.0; 471 USR_DOUBLE proj_ber = 0.0, proj_ber_aux = 0.0; 472 USR_DOUBLE proj_margin_12 = 0.0; 473 USR_DOUBLE proj_margin_15 = 0.0; 474 USR_DOUBLE proj_margin_18 = 0.0; 475 USR_DOUBLE sq_err1 = 0.0, sq_err2 = 0.0; 476 USR_DOUBLE ierr; 477 uint8_t start_n; 478 uint8_t stop_n; 479 uint8_t low_confidence=1; 480 uint8_t loop_index; 481 uint8_t n_mono = 0; 482 uint8_t eye_cnt; 483 uint8_t hi_confidence_cnt = 0; 484 int8_t first_good_ber_idx = -1; 485 int8_t first_small_errcnt_idx = -1; 486 int8_t first_non_clipped_errcnt_idx = -1; 487 uint8_t range250; 488 uint8_t intrusive; 489 uint8_t ber_clipped = 0; 490 uint8_t last_point_discard; 491 uint8_t fit_count; 492 int artificial_margin; 493 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 */ 494 USR_DOUBLE artificial_lber; 495 char message[256] = "NO MESSAGE"; 496 char unit[5]; 497 498 if(!total_errs || !total_time ) { 499 return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT)); 500 } 501 502 /* Initialize BER array */ 503 for (i = 0; i < DIAG_MAX_SAMPLES; i++) { 504 bers[i] = 0; 505 mono_flags[i] = 0; 506 } 507 508 /* Decode mode/direction/etc. */ 509 heye = (ber_scan_mode & DIAG_BER_HORZ)>>1; 510 direction = (ber_scan_mode & DIAG_BER_NEG) ? -1 : 1 ; 511 range250 = (ber_scan_mode & DIAG_BER_P1_NARROW) ? 0 : 1; 512 intrusive = (ber_scan_mode & DIAG_BER_INTR) ? 1 : 0; 513 514 /* Prepare artificial points in case they are needed */ 515 if (heye == 1) { 516 artificial_margin = direction*ARTIFICIAL_MARGIN_H; 517 } else { 518 artificial_margin = direction*ARTIFICIAL_MARGIN_V; 519 } 520 artificial_lber = (USR_DOUBLE)sqrt(-log10(ARTIFICIAL_BER)); 521 522 /* Printing on-screen message */ 523 if (heye == 1) { 524 if (direction==-1) EFUN_PRINTF(("\n\n********** HORIZONTAL PROJECTION: LEFT SIDE ******************\n")); 525 if (direction== 1) EFUN_PRINTF(("\n\n********** HORIZONTAL PROJECTION: RIGHT SIDE *****************\n")); 526 } else { 527 if (direction==-1) EFUN_PRINTF(("\n\n********** VERTICAL PROJECTION: BOTTOM ***********************\n")); 528 if (direction== 1) EFUN_PRINTF(("\n\n********** VERTICAL PROJECTION: TOP **************************\n")); 529 } 530 531 /* ******************************************* 532 * Generate margins[] 533 * Generate ber[] 534 * Find first and last points for linear fit 535 */ 536 i=0; 537 do { 538 if(heye == 1) { 539 ENULL_STRCPY(unit,"mUI"); 540 offset[i] = (int8_t)(max_offset-i); 541 #ifndef STANDALONE_EVENT 542 margins[i] = direction*offset[i]*1000.0/64.0; 543 #else 544 margins[i] = info_out->margins[i]; 545 #endif 546 } else { 547 ENULL_STRCPY(unit,"mV"); 548 offset[i] = (int8_t)(max_offset-i); 549 #ifndef STANDALONE_EVENT 550 if(intrusive) { 551 margins[i] = direction*intrusive_margins_mv[offset[i]]; 552 } else { 553 margins[i] = direction*merlin16_INTERNAL_ladder_setting_to_mV(sa__, offset[i], range250); 554 } 555 #else 556 margins[i] = info_out->margins[i]; 557 #endif 558 } 559 if (total_errs[i] == 0) { 560 bers[i] = 1.0/(((USR_DOUBLE)total_time[i])*0.00001*rate); 561 } else { 562 bers[i] = (USR_DOUBLE)total_errs[i]/(((USR_DOUBLE)total_time[i])*0.00001*rate); 563 } 564 565 /* Find the first data point with good BER (BER <= 10^MIN_BER_FOR_FIT) 566 NOTE: no need for lower bound on BER, since correction factors will be applied for all total_errs>=0 */ 567 if ((log10(bers[i]) <= MIN_BER_FOR_FIT) && (first_good_ber_idx == -1)) { 568 first_good_ber_idx = (int8_t)i; 569 } 570 571 /* Determine high-confidence iterations */ 572 if (total_errs[i] >= HI_CONFIDENCE_ERR_CNT) { 573 hi_confidence_cnt++; 574 } else if ((total_errs[i] < HI_CONFIDENCE_MIN_ERR_CNT) && (first_small_errcnt_idx == -1)) { 575 /* find the first data point with small error count */ 576 first_small_errcnt_idx = (int8_t)i; 577 } 578 579 /* Determine first NON-clipped error count 580 NOTE: Originally this limit was created for post processing of micro-generated data; however, this could be used for PC-generated data as well */ 581 if ((total_errs[i] < MAX_CLIPPED_ERR_CNT) && (first_non_clipped_errcnt_idx == -1) ) { 582 first_non_clipped_errcnt_idx = (int8_t)i; 583 } 584 585 i++; 586 587 } while(((total_errs[i] != 0) || (total_time[i] != 0)) && (i<=max_offset)); 588 589 eye_cnt = (int8_t) i; 590 591 592 /* ******************************************* 593 Setting up stop_n variable. 594 Check if: 595 - There is only one point in measurement vector (i.e. eye_cnt = 1) 596 - The very last point's measurement time was "too short" 597 */ 598 599 i = eye_cnt - 1; 600 if (i>=1) { 601 if ((total_time[i] >= 0.5*total_time[i-1]) || (total_errs[i] >= HI_CONFIDENCE_MIN_ERR_CNT) ){ 602 stop_n = eye_cnt; /* last point will be included in linear fit */ 603 last_point_discard = 0; 604 } else { 605 stop_n = eye_cnt - 1; /* discards the very last point */ 606 last_point_discard = 1; 607 } 608 } else { 609 stop_n = 1; /* there is ONLY one measurement */ 610 last_point_discard = 0; 611 } 612 613 614 /* ******************************************* 615 Print on screen (prints RAW BER data. i.e. conf factors) 616 */ 617 i = 0; 618 do { 619 if (total_errs[i] == 0) { 620 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)); 621 } else if (total_errs[i] >= MAX_CLIPPED_ERR_CNT) { 622 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)); 623 } else { 624 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)); 625 } 626 i++; 627 } while (i<stop_n); 628 629 /* ******************************************* 630 Correcting *all* BER values using confidence factors in 'ber_conf_scale' vector 631 This step is done for extrapolation purposes 632 */ 633 for (loop_index=0; loop_index < eye_cnt; loop_index++) { 634 if (total_errs[loop_index] <= 100) { 635 bers[loop_index] = ber_conf_scale[total_errs[loop_index]] * bers[loop_index]; 636 } else if (total_errs[loop_index] > 100 && total_errs[loop_index] < 200) { 637 bers[loop_index] = ber_conf_scale[100] * bers[loop_index]; 638 } else if (total_errs[loop_index] >= 200 && total_errs[loop_index] < 300) { 639 bers[loop_index] = ber_conf_scale[101] * bers[loop_index]; 640 } else if (total_errs[loop_index] >= 300 && total_errs[loop_index] < 400) { 641 bers[loop_index] = ber_conf_scale[102] * bers[loop_index]; 642 } else if (total_errs[loop_index] >= 400) { 643 bers[loop_index] = ber_conf_scale[103] * bers[loop_index]; 644 } 645 } 646 647 /* ******************************************* 648 Computes the "linearised" ber vector 649 */ 650 for (loop_index=0; loop_index<eye_cnt; loop_index++) { 651 lbers[loop_index] = (USR_DOUBLE)sqrt(-log10(bers[loop_index])); 652 } 653 654 /* ******************************************* 655 Assign highest data point to use 656 */ 657 if (first_good_ber_idx == -1) { 658 start_n = stop_n; 659 } else { 660 start_n = first_good_ber_idx; 661 } 662 663 664 665 /* ****************************************************** 666 *********** EXTRAPOLATION (START) ********************** 667 ********************************************************* 668 Different data set profiles can be received by this code. 669 Each case is processed accordingly here (IF-ELSE IF cases) 670 */ 671 672 /* ====> Errors encountered all the way to sampling point */ 673 if (start_n >= eye_cnt) { 674 proj_case = 1; 675 ENULL_STRCPY(message,"No low-BER point measured"); 676 677 /* confidence factor of 0.96 is applied in this case to set a LOWER bound and report accordingly. 678 This factor corresponds to approximately 3000 errors @95% confidence 679 For reference: factors for 900, 2000, 3000, 5000, 20000 and 50000 errors are: 0.96, 0.96, 0.97, 0.99, 0.99, respectively */ 680 proj_ber = 0.96*log10(bers[eye_cnt-1]); 681 proj_ber_aux = proj_ber; 682 EFUN_PRINTF(("BER *worse* than 1e%0.2f\n", proj_ber)); 683 EFUN_PRINTF(("No margin @ 1e-12, 1e-15 & 1e-18\n\n\n")); 684 fit_count = 1; 685 } 686 687 else { 688 689 /* ====> Only ONE measured point. Typically when the eye is wide open. 690 Artificial points will be used to make extrapolation possible */ 691 if (stop_n==1) { 692 proj_case = 2; 693 ENULL_STRCPY(message,"Not enough points (single measured point). Using artificial point"); 694 695 low_confidence = 1; 696 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 */ 697 fit_count = 2; 698 699 /* Compute covariances and means... but only for two points: artificial and the single measured point */ 700 Exy = ((margins[0]*lbers[0] + artificial_margin*artificial_lber)/2.0); 701 Eyy = ((lbers[0]*lbers[0] + artificial_lber*artificial_lber)/2.0); 702 Exx = ((margins[0]*margins[0] + artificial_margin*artificial_margin)/2.0); 703 Ey = ((lbers[0] + artificial_lber)/2.0); 704 Ex = ((margins[0] + artificial_margin)/2.0); 705 } 706 707 /* ====> "NORMAL" case (when there are more than 1 measurements) */ 708 else { 709 710 /* Detect and record nonmonotonic data points */ 711 for (loop_index=0; loop_index < stop_n; loop_index++) { 712 if ((loop_index > start_n) && (log10(bers[loop_index]) > log10(bers[loop_index-1]))) { 713 mono_flags[loop_index] = 1; 714 if (first_good_ber_idx != -1) { 715 n_mono++; 716 } 717 } 718 } 719 720 /* Finds number of MEASURED points available for extrapolation */ 721 delta_n = (stop_n-start_n-n_mono); 722 723 724 /* HIGH CONFIDENCE case */ 725 726 if (delta_n >= 2) { /* there are at least 2 points to trace a line */ 727 proj_case = 3; 728 ENULL_STRCPY(message,"Normal case"); 729 low_confidence = 0; 730 731 /* Compute covariances and means */ 732 fit_count = 0; 733 for (loop_index=start_n; loop_index < stop_n; loop_index++) { 734 if (mono_flags[loop_index] == 0) { 735 Exy += (margins[loop_index]*lbers[loop_index]/(USR_DOUBLE)delta_n); 736 Eyy += (lbers[loop_index]*lbers[loop_index]/(USR_DOUBLE)delta_n); 737 Exx += (margins[loop_index]*margins[loop_index]/(USR_DOUBLE)delta_n); 738 Ey += (lbers[loop_index]/(USR_DOUBLE)delta_n); 739 Ex += (margins[loop_index]/(USR_DOUBLE)delta_n); 740 fit_count++; 741 } 742 } 743 } 744 745 /* LOW CONFIDENCE case */ 746 747 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 */ 748 low_confidence = 1; 749 if ( (first_non_clipped_errcnt_idx>=0) && (first_non_clipped_errcnt_idx < start_n)) { 750 proj_case = 4; 751 ENULL_STRCPY(message,"Not enough points. Using first measured point for conservative estimation"); 752 fit_count = 2; 753 /* Compute covariances and means... but only for two points: first and last */ 754 Exy = ((margins[stop_n-1]*lbers[stop_n-1] + margins[first_non_clipped_errcnt_idx]*lbers[first_non_clipped_errcnt_idx])/2.0); 755 Eyy = ((lbers[stop_n-1]*lbers[stop_n-1] + lbers[first_non_clipped_errcnt_idx]*lbers[first_non_clipped_errcnt_idx])/2.0); 756 Exx = ((margins[stop_n-1]*margins[stop_n-1] + margins[first_non_clipped_errcnt_idx]*margins[first_non_clipped_errcnt_idx])/2.0); 757 Ey = ((lbers[stop_n-1] + lbers[first_non_clipped_errcnt_idx])/2.0); 758 Ex = ((margins[stop_n-1] + margins[first_non_clipped_errcnt_idx])/2.0); 759 } else { 760 proj_case = 5; 761 ENULL_STRCPY(message,"Not enough points (cannot use non-clipped ErrorCount point). Using artificial point"); 762 /* Compute covariances and means... but only for two points: artificial and the single measured point */ 763 Exy = (artificial_margin*artificial_lber)/2.0; 764 Eyy = (artificial_lber*artificial_lber)/2.0; 765 Exx = (artificial_margin*artificial_margin)/2.0; 766 Ey = (artificial_lber)/2.0; 767 Ex = (artificial_margin)/2.0; 768 fit_count = 1; 769 /* This FOR loop checks for monotonicity as well */ 770 for (loop_index=start_n; loop_index < stop_n; loop_index++) { 771 if (mono_flags[loop_index] == 0) { 772 Exy += (margins[loop_index]*lbers[loop_index]/2.0); 773 Eyy += (lbers[loop_index]*lbers[loop_index]/2.0); 774 Exx += (margins[loop_index]*margins[loop_index]/2.0); 775 Ey += (lbers[loop_index]/2.0); 776 Ex += (margins[loop_index]/2.0); 777 fit_count++; 778 } 779 } 780 } 781 } 782 } 783 784 /* Compute fit slope and offset: ber = alpha*margin + beta */ 785 alpha = (Exy - Ey*Ex) / (Exx - Ex*Ex); 786 beta = Ey - Ex*alpha; 787 /* Compute alpha2: slope of regression: margin = alpha2*ber + beta2 */ 788 alpha2 = (Exy - Ey*Ex) / (Eyy - Ey*Ey); 789 /* Compute correlation index sq_r */ 790 sq_r = alpha*alpha2; 791 792 proj_ber = pow(10,(-beta*beta)); 793 proj_margin_12 = direction*(sqrt(-log10(1e-12))-beta)/alpha; 794 proj_margin_15 = direction*(sqrt(-log10(1e-15))-beta)/alpha; 795 proj_margin_18 = direction*(sqrt(-log10(1e-18))-beta)/alpha; 796 797 /* Estimate modeled gaussian noise. 798 799 The following is based on the Q-function model and the following table: 800 Q | log10(BER) 801 ======================= 802 7.033 | -12 803 7.941 | -15 804 8.757 | -18 805 806 Based on the above, we solve for sigma: 807 7.033*sigma = u - proj_margin_12 , and 808 7.941*sigma = u - proj_margin_15 809 */ 810 gauss_noise = (proj_margin_12 - proj_margin_15)/0.908; 811 812 sq_err1 = (Eyy + (beta*beta) + (Exx*alpha*alpha) - 813 (2*Ey*beta) - (2*Exy*alpha) + (2*Ex*beta*alpha)); 814 sq_err2 = 0; 815 for (loop_index=start_n; loop_index<stop_n; loop_index++) { 816 ierr = (lbers[loop_index] - (alpha*margins[loop_index] + beta)); 817 sq_err2 += (ierr*ierr/(USR_DOUBLE)delta_n); 818 } 819 820 proj_ber = log10(proj_ber); 821 proj_ber_aux = proj_ber; 822 823 if (proj_ber < MIN_BER_TO_REPORT) { 824 proj_ber = MIN_BER_TO_REPORT; 825 ber_clipped = 1; 826 } 827 828 /* Extrapolated results, low confidence */ 829 if (low_confidence == 1) { 830 831 EFUN_PRINTF(("BER(extrapolated) < 1e%0.2f\n", proj_ber)); 832 EFUN_PRINTF(("Margin @ 1e-12 > %0.2f %s\n", (proj_ber < -12)? SRDS_ABS(proj_margin_12) : 0, unit)); 833 EFUN_PRINTF(("Margin @ 1e-15 > %0.2f %s\n", (proj_ber < -15)? SRDS_ABS(proj_margin_15) : 0, unit)); 834 EFUN_PRINTF(("Margin @ 1e-18 > %0.2f %s\n", (proj_ber < -18)? SRDS_ABS(proj_margin_18) : 0, unit)); 835 836 /* Extrapolated results, HIGH confidence */ 837 } else { 838 839 if (ber_clipped == 1) { 840 EFUN_PRINTF(("BER(extrapolated) < 1e%0.2f\n", proj_ber)); 841 } else { 842 EFUN_PRINTF(("BER(extrapolated) = 1e%0.2f\n", proj_ber)); 843 } 844 EFUN_PRINTF(("Margin @ 1e-12 = %0.2f %s\n", (proj_ber < -12)? SRDS_ABS(proj_margin_12) : 0, unit)); 845 EFUN_PRINTF(("Margin @ 1e-15 = %0.2f %s\n", (proj_ber < -15)? SRDS_ABS(proj_margin_15) : 0, unit)); 846 EFUN_PRINTF(("Margin @ 1e-18 = %0.2f %s\n", (proj_ber < -18)? SRDS_ABS(proj_margin_18) : 0, unit)); 847 } 848 849 EFUN_PRINTF(("\n\n")); 850 851 /* Print non-monotonic outliers */ 852 if (n_mono != 0) { 853 EFUN_PRINTF(("Detected non-monotonicity at { ")); 854 for (loop_index = start_n; loop_index < stop_n; loop_index++) { 855 if (mono_flags[loop_index] == 1) { 856 EFUN_PRINTF(("%0.2f ", margins[loop_index])); 857 } 858 } 859 EFUN_PRINTF(("} %s\n\n\n",unit)); 860 } 861 862 } 863 /* ******************************************* 864 *********** EXTRAPOLATION (END) ************* 865 */ 866 867 868 869 /* SUMMARY (for debugging purposes */ 870 if (DIAG_VERBOSE > 2) EFUN_PRINTF(("\t=====> DEBUG INFO (start)\n\n")); 871 if (DIAG_VERBOSE > 2) { 872 EFUN_PRINTF((" loop Margin total_errors time(sec) logBER lber")); 873 for (loop_index=0; loop_index < stop_n+last_point_discard; loop_index++) { 874 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])); 875 } 876 EFUN_PRINTF(("\n\n")); 877 } 878 if (DIAG_VERBOSE > 2) EFUN_PRINTF(("Max Offset = %d\n",max_offset)); 879 if (DIAG_VERBOSE > 2) EFUN_PRINTF(("ber_clipped: %d, Projected BER (proj_ber_aux) = %.2f\n", ber_clipped, proj_ber_aux)); 880 if (DIAG_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))); 881 { 882 char aux_str[20]; 883 USR_SPRINTF(aux_str, "%d", total_errs[first_small_errcnt_idx]); 884 if (DIAG_VERBOSE > 2) EFUN_PRINTF(("first small errcnt idx at %d, errors = %s\n", first_small_errcnt_idx, ((first_small_errcnt_idx>=0) ? aux_str : "-1"))); 885 } 886 if (DIAG_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", 887 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)); 888 if (DIAG_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)); 889 if (DIAG_VERBOSE > 2) EFUN_PRINTF(("%s\n", message)); 890 if (DIAG_VERBOSE > 2) EFUN_PRINTF(("proj_case %d\n",proj_case)); 891 if (DIAG_VERBOSE > 2) EFUN_PRINTF(("\n\t=====> DEBUG INFO (end)\n\n")); 892 EFUN_PRINTF(("\n\n\n")); 893 894 895 #else 896 (void)rate; 897 (void)ber_scan_mode; 898 (void)max_offset; 899 900 EFUN_PRINTF(("This function needs SERDES_API_FLOATING_POINT define to operate \n")); 901 902 if(!total_errs || !total_time ) { 903 return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT)); 904 } 905 #endif 906 return(ERR_CODE_NONE); 907 } 908 909 /*****************************/ 910 /* Display Lane/Core State */ 911 /*****************************/ 912 913 err_code_t merlin16_display_lane_state_hdr(void) { 914 EFUN_PRINTF(("LN (CDRxN , UC_CFG,UC_STS,TX_RX_RST,STP) ")); 915 EFUN_PRINTF(("SD LCK RXPPM ")); 916 EFUN_PRINTF(("CLK90 CLKP1 ")); 917 EFUN_PRINTF(("PF(M,L) ")); 918 EFUN_PRINTF(("VGA ")); 919 EFUN_PRINTF(("DCO P1mV ")); 920 EFUN_PRINTF((" DFE(1,2,3,4,5,dcd1,dcd2) SLICER(ze,zo,pe,po,me,mo) ")); 921 EFUN_PRINTF(("TXPPM TXEQ(n1,m,p1,p2) EYE(L,R,U,D) ")); 922 EFUN_PRINTF(("SOC(p,n) ")); 923 EFUN_PRINTF(("LINK_TIME BER")); 924 EFUN_PRINTF(("\n")); 925 return (ERR_CODE_NONE); 926 } 927 928 err_code_t merlin16_display_lane_state_legend(void) { 929 EFUN_PRINTF(("\n")); 930 EFUN_PRINTF(("**********************************************************************************************\n")); 931 EFUN_PRINTF(("**** Legend of Entries in display_lane_state() ****\n")); 932 EFUN_PRINTF(("**********************************************************************************************\n")); 933 EFUN_PRINTF(("LN : Lane index within IP core\n")); 934 EFUN_PRINTF(("CDRxN : CDR type x OSR ratio [xT-OS3p3; x7-OS7p5; x9-OSx8p25; xA-OSx10]\n")); 935 EFUN_PRINTF(("UC_CFG : Micro lane configuration variable\n")); 936 EFUN_PRINTF(("UC_STS : Micro lane status variable\n")); 937 #if defined(SERDES_TX_RS_SEPARATE) 938 EFUN_PRINTF(("TX_RX_RST : TX and RX Reset State{reset_active, reset_occured, reset_held}\n")); 939 #else 940 EFUN_PRINTF(("RST : Reset State{reset_active, reset_occured, reset_held}\n")); 941 #endif 942 EFUN_PRINTF(("STP : uC Stopped State\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 #if defined(RX_VGA_CTRL_VAL_MIN) 950 EFUN_PRINTF(("VGA : Variable Gain Amplifier settings (%d..%d)\n", RX_VGA_CTRL_VAL_MIN, RX_VGA_CTRL_VAL_MAX)); 951 #else 952 EFUN_PRINTF(("VGA : Variable Gain Amplifier settings (0..%d)\n", RX_VGA_CTRL_VAL_MAX)); 953 #endif 954 EFUN_PRINTF(("DCO : DC offset DAC control value\n")); 955 EFUN_PRINTF(("P1mV : Vertical threshold voltage of p1 slicer\n")); 956 EFUN_PRINTF(("DFE taps : ISI correction taps in units of 2.35mV (for 1 & 2 even values are displayed, dcd = even-odd)\n")); 957 EFUN_PRINTF(("SLICER(ze,zo,pe,po,me,mo) : Slicer calibration control codes\n")); 958 EFUN_PRINTF(("TXPPM : Frequency offset of local reference clock with respect to TX data in ppm\n")); 959 EFUN_PRINTF(("TXEQ(n1,m,p1,p2) : TX equalization FIR tap weights in units of 1Vpp/60 units\n")); 960 EFUN_PRINTF(("SOC(p,n) : Signal Detect Offset Calibration\n")); 961 EFUN_PRINTF(("EYE(L,R,U,D) : Eye margin @ 1e-5 as seen by internal diagnostic slicer in mUI and mV\n")); 962 EFUN_PRINTF(("LINK_TIME : Link time in milliseconds\n")); 963 EFUN_PRINTF(("BER : Bit Error Rate calculated based on 100ms test time; displayed only if prbs_chk_en=1.\n")); 964 EFUN_PRINTF(("**********************************************************************************************\n")); 965 return (ERR_CODE_NONE); 966 } 967 968 err_code_t merlin16_display_lane_state(srds_access_t *sa__) { 969 err_code_t err_code = merlin16_INTERNAL_display_lane_state_no_newline(sa__); 970 EFUN_PRINTF(("\n")); 971 return (err_code); 972 } 973 974 err_code_t merlin16_display_core_state_hdr(void) { 975 char core_type[20] = "merlin16"; 976 COMPILER_REFERENCE(core_type); 977 EFUN_PRINTF(("SerDes type = %s\n",core_type)); 978 979 EFUN_PRINTF(("CORE RST_ST PLL_PWDN UC_ATV COM_CLK UCODE_VER API_VER AFE_VER LIVE_TEMP AVG_TMON RESCAL VCO_RATE ANA_VCO_RANGE PLL_DIV PLL_LOCK")); 980 EFUN_PRINTF(("\n")); 981 return (ERR_CODE_NONE); 982 } 983 984 err_code_t merlin16_display_core_state_line(srds_access_t *sa__) { 985 err_code_t err_code = merlin16_INTERNAL_display_core_state_no_newline(sa__); 986 EFUN_PRINTF(("\n")); 987 return (err_code); 988 } 989 990 err_code_t merlin16_display_core_state_legend(void) { 991 EFUN_PRINTF(("\n")); 992 EFUN_PRINTF(("**************************************************************************************************************\n")); 993 EFUN_PRINTF(("**** Legend of Entries in display_core_state() ****\n")); 994 EFUN_PRINTF(("**************************************************************************************************************\n")); 995 EFUN_PRINTF(("* RST_ST : Core DP Reset State{reset_active, reset_occured, reset_held}, Core uC Status byte(hex) *\n")); 996 EFUN_PRINTF(("* PLL_PWDN : PLL Powerdown Control Bit (active high) *\n")); 997 EFUN_PRINTF(("* UC_ATV : UC Active bit *\n")); 998 EFUN_PRINTF(("* COM_CLK : COM Clock frequency in MHz *\n")); 999 EFUN_PRINTF(("* UCODE_VER : Microcode Version [majorversion_minorversion] *\n")); 1000 EFUN_PRINTF(("* API_VER : API Version *\n")); 1001 EFUN_PRINTF(("* AFE_VER : AFE Hardware Vesrion *\n")); 1002 EFUN_PRINTF(("* LIVE_TEMP : Live Die temperature in Celsius *\n")); 1003 EFUN_PRINTF(("* AVG_TMON : uC Temp_idx, Average temperature in Celsius *\n")); 1004 EFUN_PRINTF(("* RESCAL : Analog Resistor Calibration value *\n")); 1005 EFUN_PRINTF(("* VCO_RATE : uC VCO Rate in GHz (approximate) *\n")); 1006 EFUN_PRINTF(("* ANA_VCO_RANGE : Analog VCO Range *\n")); 1007 EFUN_PRINTF(("* PLL_Lock : PLL Lock *\n")); 1008 1009 EFUN_PRINTF(("**************************************************************************************************************\n")); 1010 return (ERR_CODE_NONE); 1011 } 1012 1013 /**********************************************/ 1014 /* Display Lane/Core Config and Debug Status */ 1015 /**********************************************/ 1016 err_code_t merlin16_display_core_config(srds_access_t *sa__) { 1017 EFUN_PRINTF(("\n\n***********************************\n" )); 1018 EFUN_PRINTF(( "**** SERDES CORE CONFIGURATION ****\n" )); 1019 EFUN_PRINTF(( "***********************************\n\n")); 1020 { 1021 struct merlin16_uc_core_config_st core_cfg; 1022 ENULL_MEMSET(&core_cfg, 0, sizeof(core_cfg)); 1023 EFUN(merlin16_get_uc_core_config(sa__, &core_cfg)); 1024 { 1025 uint16_t vco_mhz = (uint16_t)core_cfg.vco_rate_in_Mhz; 1026 COMPILER_REFERENCE(vco_mhz); 1027 EFUN_PRINTF(( "uC Config VCO Rate = %d (~%d.%03dGHz)\n" , core_cfg.field.vco_rate 1028 , (vco_mhz / 1000) 1029 , (vco_mhz % 1000) )); 1030 EFUN_PRINTF(( "Core Config from PCS = %d\n\n" , core_cfg.field.core_cfg_from_pcs)); 1031 } 1032 } 1033 ESTM_PRINTF(( "Tx Lane Addr 0 = %d\n" , rdc_tx_lane_addr_0())); 1034 ESTM_PRINTF(( "Rx Lane Addr 0 = %d\n" , rdc_rx_lane_addr_0())); 1035 ESTM_PRINTF(( "Tx Lane Addr 1 = %d\n" , rdc_tx_lane_addr_1())); 1036 ESTM_PRINTF(( "Rx Lane Addr 1 = %d\n" , rdc_rx_lane_addr_1())); 1037 ESTM_PRINTF(( "Tx Lane Addr 2 = %d\n" , rdc_tx_lane_addr_2())); 1038 ESTM_PRINTF(( "Rx Lane Addr 2 = %d\n" , rdc_rx_lane_addr_2())); 1039 ESTM_PRINTF(( "Tx Lane Addr 3 = %d\n" , rdc_tx_lane_addr_3())); 1040 ESTM_PRINTF(( "Rx Lane Addr 3 = %d\n" , rdc_rx_lane_addr_3())); 1041 #ifdef rdc_tx_lane_addr_4 1042 ESTM_PRINTF(( "Tx Lane Addr 4 = %d\n" , rdc_tx_lane_addr_4())); 1043 ESTM_PRINTF(( "Rx Lane Addr 4 = %d\n" , rdc_rx_lane_addr_4())); 1044 #endif 1045 #ifdef rdc_tx_lane_addr_5 1046 ESTM_PRINTF(( "Tx Lane Addr 5 = %d\n" , rdc_tx_lane_addr_5())); 1047 ESTM_PRINTF(( "Rx Lane Addr 5 = %d\n" , rdc_rx_lane_addr_5())); 1048 #endif 1049 #ifdef rdc_tx_lane_addr_6 1050 ESTM_PRINTF(( "Tx Lane Addr 6 = %d\n" , rdc_tx_lane_addr_6())); 1051 ESTM_PRINTF(( "Rx Lane Addr 6 = %d\n" , rdc_rx_lane_addr_6())); 1052 #endif 1053 #ifdef rdc_tx_lane_addr_7 1054 ESTM_PRINTF(( "Tx Lane Addr 7 = %d\n" , rdc_tx_lane_addr_7())); 1055 ESTM_PRINTF(( "Rx Lane Addr 7 = %d\n" , rdc_rx_lane_addr_7())); 1056 #endif 1057 return(ERR_CODE_NONE); 1058 } 1059 1060 1061 err_code_t merlin16_display_lane_config(srds_access_t *sa__) { 1062 struct merlin16_uc_lane_config_st lane_cfg; 1063 1064 ENULL_MEMSET(&lane_cfg, 0, sizeof(lane_cfg)); 1065 1066 EFUN_PRINTF(("\n\n*************************************\n" )); 1067 ESTM_PRINTF(( "**** SERDES LANE %d CONFIGURATION ****\n" , merlin16_get_lane(sa__) )); 1068 EFUN_PRINTF(( "*************************************\n\n" )); 1069 EFUN( merlin16_get_uc_lane_cfg(sa__, &lane_cfg)); 1070 EFUN_PRINTF(( "Lane Config from PCS = %d\n\n" , lane_cfg.field.lane_cfg_from_pcs )); 1071 EFUN_PRINTF(( "Auto-Neg Enabled = %d\n" , lane_cfg.field.an_enabled )); 1072 EFUN_PRINTF(( "DFE on = %d\n" , lane_cfg.field.dfe_on )); 1073 EFUN_PRINTF(( "Brdfe_on = %d\n" , lane_cfg.field.force_brdfe_on )); 1074 EFUN_PRINTF(( "Media Type = %d\n" , lane_cfg.field.media_type )); 1075 EFUN_PRINTF(( "Unreliable LOS = %d\n" , lane_cfg.field.unreliable_los )); 1076 EFUN_PRINTF(( "Scrambling Disable = %d\n" , lane_cfg.field.scrambling_dis )); 1077 ESTM_PRINTF(( "CL72 Training Enable = %d\n" , rd_cl72_ieee_training_enable() )); 1078 EFUN_PRINTF(( "CL72 Auto Polarity Enable = %d\n" , lane_cfg.field.cl72_auto_polarity_en )); 1079 EFUN_PRINTF(( "CL72 Restart timeout Enable = %d\n" , lane_cfg.field.cl72_restart_timeout_en)); 1080 1081 ESTM_PRINTF(( "TX OSR Mode Force = %d\n" , rd_tx_osr_mode_frc() )); 1082 ESTM_PRINTF(( "TX OSR Mode Force Val = %d\n" , rd_tx_osr_mode_frc_val() )); 1083 ESTM_PRINTF(( "RX OSR Mode Force = %d\n" , rd_rx_osr_mode_frc() )); 1084 ESTM_PRINTF(( "RX OSR Mode Force Val = %d\n" , rd_rx_osr_mode_frc_val() )); 1085 ESTM_PRINTF(( "TX Polarity Invert = %d\n" , rd_tx_pmd_dp_invert() )); 1086 ESTM_PRINTF(( "RX Polarity Invert = %d\n\n" , rd_rx_pmd_dp_invert() )); 1087 ESTM_PRINTF(( "TXFIR Post2 = %d\n" , rd_txfir_post2() )); 1088 ESTM_PRINTF(( "TXFIR Main Override = %d\n" , rd_cl72_txfir_main() )); 1089 ESTM_PRINTF(( "TXFIR Pre Override = %d\n" , rd_cl72_txfir_pre() )); 1090 ESTM_PRINTF(( "TXFIR Post Override = %d\n" , rd_cl72_txfir_post() )); 1091 return(ERR_CODE_NONE); 1092 } 1093 1094 1095 err_code_t merlin16_display_core_state(srds_access_t *sa__) { 1096 EFUN(merlin16_display_core_state_hdr()); 1097 EFUN(merlin16_display_core_state_line(sa__)); 1098 EFUN(merlin16_display_core_state_legend()); 1099 return ERR_CODE_NONE; 1100 } 1101 1102 1103 err_code_t merlin16_display_lane_debug_status(srds_access_t *sa__) { 1104 /* startup */ 1105 struct merlin16_usr_ctrl_disable_functions_st ds; 1106 struct merlin16_usr_ctrl_disable_dfe_functions_st dsd; 1107 /* steady state */ 1108 struct merlin16_usr_ctrl_disable_functions_st dss; 1109 struct merlin16_usr_ctrl_disable_dfe_functions_st dssd; 1110 1111 ENULL_MEMSET(&ds , 0, sizeof(ds )); 1112 ENULL_MEMSET(&dsd , 0, sizeof(dsd )); 1113 ENULL_MEMSET(&dss , 0, sizeof(dss )); 1114 ENULL_MEMSET(&dssd, 0, sizeof(dssd)); 1115 1116 EFUN_PRINTF(("\n\n************************************\n" )); 1117 ESTM_PRINTF(( "**** SERDES LANE %d DEBUG STATUS ****\n" , merlin16_get_lane(sa__) )); 1118 EFUN_PRINTF(( "************************************\n\n" )); 1119 ESTM_PRINTF(( "Restart Count = %d\n" , rdv_usr_sts_restart_counter() )); 1120 ESTM_PRINTF(( "Reset Count = %d\n" , rdv_usr_sts_reset_counter() )); 1121 ESTM_PRINTF(( "PMD Lock Count = %d\n\n", rdv_usr_sts_pmd_lock_counter() )); 1122 EFUN(merlin16_get_usr_ctrl_disable_startup(sa__, &ds)); 1123 EFUN_PRINTF(( "Disable Startup PF Adaptation = %d\n" , ds.field.pf_adaptation )); 1124 EFUN_PRINTF(( "Disable Startup DC Adaptation = %d\n" , ds.field.dc_adaptation )); 1125 EFUN_PRINTF(( "Disable Startup Slicer Offset Tuning = %d\n" , ds.field.slicer_offset_tuning )); 1126 EFUN_PRINTF(( "Disable Startup Clk90 offset Adaptation = %d\n" , ds.field.clk90_offset_adaptation )); 1127 EFUN_PRINTF(( "Disable Startup P1 level Tuning = %d\n" , ds.field.p1_level_tuning )); 1128 EFUN_PRINTF(( "Disable Startup Eye Adaptation = %d\n" , ds.field.eye_adaptation )); 1129 EFUN_PRINTF(( "Disable Startup All Adaptation = %d\n\n", ds.field.all_adaptation )); 1130 EFUN( merlin16_get_usr_ctrl_disable_startup_dfe(sa__, &dsd)); 1131 EFUN_PRINTF(( "Disable Startup DFE Tap1 Adaptation = %d\n" , dsd.field.dfe_tap1_adaptation )); 1132 EFUN_PRINTF(( "Disable Startup DFE Tap2 Adaptation = %d\n" , dsd.field.dfe_tap2_adaptation )); 1133 EFUN_PRINTF(( "Disable Startup DFE Tap3 Adaptation = %d\n" , dsd.field.dfe_tap3_adaptation )); 1134 EFUN_PRINTF(( "Disable Startup DFE Tap4 Adaptation = %d\n" , dsd.field.dfe_tap4_adaptation )); 1135 EFUN_PRINTF(( "Disable Startup DFE Tap5 Adaptation = %d\n" , dsd.field.dfe_tap5_adaptation )); 1136 EFUN_PRINTF(( "Disable Startup DFE Tap1 DCD = %d\n" , dsd.field.dfe_tap1_dcd )); 1137 EFUN_PRINTF(( "Disable Startup DFE Tap2 DCD = %d\n\n", dsd.field.dfe_tap2_dcd )); 1138 EFUN( merlin16_get_usr_ctrl_disable_steady_state(sa__, &dss)); 1139 EFUN_PRINTF(( "Disable Steady State PF Adaptation = %d\n" , dss.field.pf_adaptation )); 1140 EFUN_PRINTF(( "Disable Steady State DC Adaptation = %d\n" , dss.field.dc_adaptation )); 1141 EFUN_PRINTF(( "Disable Steady State Slicer Offset Tuning = %d\n" , dss.field.slicer_offset_tuning )); 1142 EFUN_PRINTF(( "Disable Steady State Clk90 offset Adaptation = %d\n" , dss.field.clk90_offset_adaptation )); 1143 EFUN_PRINTF(( "Disable Steady State P1 level Tuning = %d\n" , dss.field.p1_level_tuning )); 1144 EFUN_PRINTF(( "Disable Steady State Eye Adaptation = %d\n" , dss.field.eye_adaptation )); 1145 EFUN_PRINTF(( "Disable Steady State All Adaptation = %d\n\n", dss.field.all_adaptation )); 1146 EFUN( merlin16_get_usr_ctrl_disable_steady_state_dfe(sa__, &dssd)); 1147 EFUN_PRINTF(( "Disable Steady State DFE Tap1 Adaptation = %d\n" , dssd.field.dfe_tap1_adaptation )); 1148 EFUN_PRINTF(( "Disable Steady State DFE Tap2 Adaptation = %d\n" , dssd.field.dfe_tap2_adaptation )); 1149 EFUN_PRINTF(( "Disable Steady State DFE Tap3 Adaptation = %d\n" , dssd.field.dfe_tap3_adaptation )); 1150 EFUN_PRINTF(( "Disable Steady State DFE Tap4 Adaptation = %d\n" , dssd.field.dfe_tap4_adaptation )); 1151 EFUN_PRINTF(( "Disable Steady State DFE Tap5 Adaptation = %d\n" , dssd.field.dfe_tap5_adaptation )); 1152 EFUN_PRINTF(( "Disable Steady State DFE Tap1 DCD = %d\n" , dssd.field.dfe_tap1_dcd )); 1153 EFUN_PRINTF(( "Disable Steady State DFE Tap2 DCD = %d\n\n", dssd.field.dfe_tap2_dcd )); 1154 ESTM_PRINTF(( "Clk90 offset Adjust = %d\n" , rdv_usr_ctrl_clk90_offset_adjust() )); 1155 ESTM_PRINTF(( "Clk90 offset Override = %d\n" , rdv_usr_ctrl_clk90_offset_override())); 1156 ESTM_PRINTF(( "Lane Event Log Level = %d\n" , rdv_usr_ctrl_lane_event_log_level() )); 1157 1158 return(ERR_CODE_NONE); 1159 } 1160 1161 static err_code_t _display_ber_scan_data(srds_access_t *sa__, uint8_t ber_scan_mode, uint8_t timer_control, uint8_t max_error_control) { 1162 uint8_t i,prbs_byte,prbs_multi,time_byte,time_multi; 1163 uint16_t sts,dataword; 1164 int16_t offset_start; 1165 uint8_t cnt; 1166 uint32_t errors,timer_values; 1167 int rate,direction; 1168 uint8_t range250; 1169 merlin16_osr_mode_st osr_mode; 1170 struct merlin16_uc_core_config_st core_config; 1171 1172 ENULL_MEMSET(&core_config,0,sizeof(core_config)); 1173 ENULL_MEMSET(&osr_mode,0,sizeof(osr_mode)); 1174 1175 EFUN(merlin16_get_uc_core_config(sa__, &core_config)); 1176 EFUN(merlin16_INTERNAL_get_osr_mode(sa__, &osr_mode)); 1177 1178 #ifdef wr_ams_rx_rxclk_div2p5 1179 if((osr_mode.rx > MERLIN16_OSX4) && (osr_mode.rx != MERLIN16_OSX2P5)) { 1180 #else 1181 if(osr_mode.rx > MERLIN16_OSX4) { 1182 #endif 1183 EFUN_PRINTF(("ERROR DIAG display_ber_data: osr mode too high\n")); 1184 return(ERR_CODE_BAD_PTR_OR_INVALID_INPUT); 1185 } 1186 rate = core_config.vco_rate_in_Mhz/(1<<osr_mode.rx); 1187 direction = (ber_scan_mode & DIAG_BER_NEG) ? -1 : 1 ; 1188 range250 = (ber_scan_mode & DIAG_BER_P1_NARROW) ? 0 : 1; 1189 1190 EFUN_PRINTF(("\n**** SERDES BER DATA ****\n")); 1191 EFUN_PRINTF(("BER MODE = %x %d %d\n",ber_scan_mode,timer_control,max_error_control)); 1192 EFUN_PRINTF(("DATA RATE = %d Mhz\n",rate)); 1193 /* start UC acquisition */ 1194 if(DIAG_VERBOSE > 2) EFUN_PRINTF(("start begin\n")); 1195 EFUN(merlin16_start_ber_scan_test(sa__, ber_scan_mode, timer_control, max_error_control)); 1196 ESTM(offset_start = rd_uc_dsc_data()); 1197 if(ber_scan_mode & DIAG_BER_HORZ) { 1198 EFUN_PRINTF(("STARTING OFFSET = %d : %d mUI\n",offset_start,(offset_start*1000)>>6)); 1199 } else { 1200 EFUN_PRINTF(("STARTING OFFSET = %d : %d mV\n",offset_start,merlin16_INTERNAL_ladder_setting_to_mV(sa__, (int8_t)offset_start, range250))); 1201 } 1202 if(DIAG_VERBOSE > 2) EFUN_PRINTF(("start done\n")); 1203 1204 1205 /* This wait is VERY LONG and should be replaced with interupt or something */ 1206 if(DIAG_VERBOSE > 5) { 1207 do { 1208 EFUN(USR_DELAY_US(2000000)); 1209 ESTM(sts = rdv_usr_diag_status()); 1210 EFUN_PRINTF(("sts=%04x\n",sts)); 1211 1212 } while ((sts & 0x8000) == 0); 1213 } else { 1214 EFUN_PRINTF(("Waiting for measurement time approx %d seconds",timer_control+(timer_control>>1))); 1215 EFUN(merlin16_INTERNAL_poll_diag_done(sa__, &sts,timer_control*2000)); 1216 } 1217 if(DIAG_VERBOSE > 2) EFUN_PRINTF(("delay done\n")); 1218 1219 /* Check for completion read ln.diag_status byte?*/ 1220 ESTM(sts = rdv_usr_diag_status()); 1221 if((sts & 0x8000) == 0) { 1222 return(_error(ERR_CODE_DATA_NOTAVAIL)); 1223 } 1224 cnt = (sts & 0x00FF)/3; 1225 for(i=0;i < cnt;i++) { 1226 /* Read 2 bytes of data */ 1227 EFUN(merlin16_pmd_uc_cmd(sa__, CMD_READ_DIAG_DATA_WORD, 0, 200)); 1228 ESTM(dataword = rd_uc_dsc_data()); /* LSB contains 2 -4bit nibbles */ 1229 time_byte = (uint8_t)(dataword>>8); /* MSB is time byte */ 1230 prbs_multi = (uint8_t)dataword & 0x0F; /* split nibbles */ 1231 time_multi = (uint8_t)dataword>>4; 1232 /* Read 1 bytes of data */ 1233 EFUN(merlin16_pmd_uc_cmd(sa__, CMD_READ_DIAG_DATA_BYTE, 0, 200)); 1234 ESTM(prbs_byte = (uint8_t)rd_uc_dsc_data()); 1235 errors = merlin16_INTERNAL_float12_to_uint32(prbs_byte,prbs_multi); /* convert 12bits to uint32 */ 1236 timer_values = (merlin16_INTERNAL_float12_to_uint32(time_byte,time_multi)<<3); 1237 if(DIAG_VERBOSE < 5) { 1238 if (!(i % 4)) { 1239 EFUN_PRINTF(("\n")); 1240 } 1241 if(ber_scan_mode & DIAG_BER_HORZ) { 1242 EFUN_PRINTF(("%d %d %d ",direction*(((SRDS_ABS(offset_start)-i)*1000)>>6),errors,timer_values)); 1243 } else { 1244 EFUN_PRINTF(("%d %d %d ",direction*merlin16_INTERNAL_ladder_setting_to_mV(sa__, (int8_t)SRDS_ABS(offset_start)-i, range250),errors,timer_values)); 1245 } 1246 1247 } else { 1248 EFUN_PRINTF(("BER Errors=%d (%02x<<%d): Time=%d (%02x<<%d)\n",errors,prbs_byte,prbs_multi,timer_values,time_byte,time_multi<<3)); 1249 } 1250 /*if(timer_values == 0 && errors == 0) break;*/ 1251 } 1252 EFUN_PRINTF(("\n")); 1253 EFUN(merlin16_pmd_uc_cmd(sa__, CMD_CAPTURE_BER_END,0x00,2000)); 1254 1255 return(ERR_CODE_NONE); 1256 } 1257 1258 /*******************************************/ 1259 /* Diagnostic Functions Required for SDK */ 1260 /*******************************************/ 1261 1262 /* Required Diagnostic Functions */ 1263 err_code_t merlin16_display_diag_data(srds_access_t *sa__, uint16_t diag_level) { 1264 uint8_t rx_lock, micro_stop; 1265 uint32_t api_version; 1266 1267 EFUN_PRINTF(("\n**** SERDES DISPLAY DIAG DATA ****\n")); 1268 ESTM_PRINTF(("Rev ID Letter = %02X\n", rdc_revid_rev_letter())); 1269 ESTM_PRINTF(("Rev ID Process = %02X\n", rdc_revid_process())); 1270 ESTM_PRINTF(("Rev ID Model = %02X\n", rdc_revid_model())); 1271 ESTM_PRINTF(("Rev ID Model = %02X\n", rdc_revid2())); 1272 ESTM_PRINTF(("Rev ID # Lanes = %d\n" ,rdc_revid_multiplicity())); 1273 ESTM_PRINTF(("Core = %d; LANE = %d\n",merlin16_get_core(sa__),merlin16_get_lane(sa__))); 1274 EFUN(merlin16_version(&api_version)); 1275 EFUN_PRINTF(("SERDES API Version = %06X\n",api_version)); 1276 ESTM_PRINTF(("Common Ucode Version = %04X", rdcv_common_ucode_version())); 1277 ESTM_PRINTF(("_%02X\n", rdcv_common_ucode_minor_version())); 1278 ESTM_PRINTF(("AFE Hardware Version = 0x%X\n\n", rdcv_afe_hardware_version())); 1279 1280 /* stop micro so all accesses are consistent */ 1281 ESTM(rx_lock = rd_pmd_rx_lock()); 1282 { 1283 err_code_t err_code=ERR_CODE_NONE; 1284 micro_stop = merlin16_INTERNAL_stop_micro(sa__,rx_lock,&err_code); 1285 if(err_code) USR_PRINTF(("Unable to stop microcontroller, following data is suspect\n")); 1286 } 1287 1288 EFUN(merlin16_display_lane_state_hdr()); 1289 EFUN(merlin16_display_lane_state(sa__)); 1290 1291 1292 if(diag_level & SRDS_DIAG_CORE) { 1293 EFUN(merlin16_display_core_state_hdr()); 1294 EFUN(merlin16_display_core_state_line(sa__)); 1295 } 1296 if(diag_level & SRDS_DIAG_EVENT_SAFE) { 1297 merlin16_INTERNAL_event_log_dump_state_t state; 1298 uint8_t micro_num = 0; 1299 { 1300 state.index = 0; 1301 state.line_start_index = 0; 1302 EFUN(merlin16_INTERNAL_read_event_log_with_callback(sa__, micro_num, 1, &state, merlin16_INTERNAL_event_log_dump_callback)); 1303 EFUN(merlin16_INTERNAL_event_log_dump_callback(&state, 0, 0)); 1304 } 1305 } 1306 if(diag_level & SRDS_DIAG_EVENT) { 1307 EFUN(merlin16_read_event_log(sa__)); 1308 } 1309 if(diag_level & SRDS_DIAG_EYE) { 1310 EFUN(merlin16_display_eye_scan(sa__)); 1311 } 1312 /* currently REG_CORE and REG_LANE dump same data. */ 1313 if((diag_level & SRDS_DIAG_REG_CORE) 1314 || (diag_level & SRDS_DIAG_REG_LANE)) { 1315 EFUN(merlin16_reg_dump(sa__)); 1316 } 1317 if(diag_level & SRDS_DIAG_UC_CORE) { 1318 EFUN(merlin16_uc_core_var_dump(sa__)); 1319 } 1320 if(diag_level & SRDS_DIAG_UC_LANE) { 1321 EFUN(merlin16_uc_lane_var_dump(sa__)); 1322 } 1323 if(diag_level & SRDS_DIAG_LANE_DEBUG) { 1324 EFUN(merlin16_display_lane_debug_status(sa__)); 1325 } 1326 if(diag_level & SRDS_DIAG_BER_VERT) { 1327 /* display ber projections for all channels */ 1328 uint8_t ber_mode = DIAG_BER_VERT | DIAG_BER_POS; 1329 uint8_t timer_control = 23; /* 30 seconds */ 1330 uint8_t err_threshold = 100 / 16; /* 100 errors */ 1331 EFUN(_display_ber_scan_data(sa__, ber_mode, timer_control, err_threshold)); 1332 ber_mode = DIAG_BER_VERT | DIAG_BER_NEG; 1333 EFUN(_display_ber_scan_data(sa__, ber_mode, timer_control, err_threshold)); 1334 } 1335 if(diag_level & SRDS_DIAG_BER_HORZ) { 1336 /* display ber projections for all channels */ 1337 uint8_t ber_mode = DIAG_BER_HORZ | DIAG_BER_POS; 1338 uint8_t timer_control = 23; /* 30 seconds */ 1339 uint8_t err_threshold = 100 / 16; /* 100 errors */ 1340 EFUN(_display_ber_scan_data(sa__, ber_mode, timer_control, err_threshold)); 1341 ber_mode = DIAG_BER_HORZ | DIAG_BER_NEG; 1342 EFUN(_display_ber_scan_data(sa__, ber_mode, timer_control, err_threshold)); 1343 } 1344 1345 /* re enable micro */ 1346 if (!micro_stop) { 1347 EFUN(merlin16_stop_rx_adaptation(sa__, 0)); 1348 } 1349 1350 EFUN_PRINTF(("\n\n")); 1351 return (ERR_CODE_NONE); 1352 1353 } 1354 1355 typedef struct { 1356 uint16_t addr; 1357 uint8_t line_byte_counter; 1358 } merlin16_diag_access_callback_state_t; 1359 1360 static err_code_t merlin16_diag_access_read_byte_callback(void *arg, uint8_t byte_count, uint16_t data) { 1361 merlin16_diag_access_callback_state_t * const state_ptr = (merlin16_diag_access_callback_state_t *)arg; 1362 while (byte_count > 0) { 1363 if (state_ptr->line_byte_counter == 0) { 1364 USR_PRINTF(("\n%04x ", state_ptr->addr)); 1365 } 1366 USR_PRINTF(("%02x ", data & 0xFF)); 1367 ++state_ptr->addr; 1368 state_ptr->line_byte_counter = (state_ptr->line_byte_counter+1) % 16; 1369 data >>= 8; 1370 --byte_count; 1371 } 1372 return (ERR_CODE_NONE); 1373 } 1374 1375 static err_code_t merlin16_diag_access_read_word_callback(void *arg, uint8_t byte_count, uint16_t data) { 1376 merlin16_diag_access_callback_state_t * const state_ptr = (merlin16_diag_access_callback_state_t *)arg; 1377 if (state_ptr->line_byte_counter == 0) { 1378 USR_PRINTF(("\n%04x ", state_ptr->addr)); 1379 } 1380 USR_PRINTF(("%04x ", data)); 1381 state_ptr->addr += 2; 1382 state_ptr->line_byte_counter = (state_ptr->line_byte_counter+2) % 16; 1383 return (ERR_CODE_NONE); 1384 } 1385 1386 /* Required Diagnostic Functions */ 1387 err_code_t merlin16_diag_access(srds_access_t *sa__, enum srds_diag_access_enum type, uint16_t addr, uint16_t data, uint16_t param) { 1388 merlin16_info_t * const merlin16_info_ptr = merlin16_INTERNAL_get_merlin16_info_ptr(); 1389 merlin16_diag_access_callback_state_t state; 1390 1391 EFUN(merlin16_INTERNAL_verify_merlin16_info(merlin16_info_ptr, sa__)); 1392 state.addr = addr; 1393 state.line_byte_counter = 0; 1394 1395 1396 switch(type) { 1397 case SRDS_REG_READ: { 1398 uint16_t tmp = 0; 1399 if(data > 1) { 1400 uint16_t i; 1401 EFUN_PRINTF(("\n**** SERDES BLK REGISTER READ ****")); 1402 for (i = 0; i < data; i++) { 1403 if (!(i % 16)) { 1404 ESTM_PRINTF(("\n%04x ",i+addr)); 1405 } 1406 EFUN(merlin16_pmd_rdt_reg(sa__, i+addr,&tmp)); 1407 ESTM_PRINTF(("%04x ", tmp)); 1408 } 1409 EFUN_PRINTF(("\n")); 1410 } else { 1411 EFUN(merlin16_pmd_rdt_reg(sa__, addr,&tmp)); 1412 EFUN_PRINTF(("Register Read: x%04x = x%04x\n",addr,tmp)); 1413 } 1414 } break; 1415 case SRDS_REG_RMW: { 1416 uint16_t tmp = 0, tmp2; 1417 EFUN(merlin16_pmd_rdt_reg(sa__, addr,&tmp)); 1418 tmp2 = (tmp & ~param) | (param & data); 1419 EFUN(merlin16_pmd_wr_reg(sa__, addr,tmp2)); 1420 EFUN_PRINTF(("Register RMW: x%04x = x%04x -> x%04x\n",addr,tmp,tmp2)); 1421 } break; 1422 case SRDS_CORE_RAM_READ_BYTE: { 1423 if(data > 1) { 1424 EFUN_PRINTF(("\n**** SERDES BLK CORE RAM READ BYTE ****")); 1425 EFUN(merlin16_INTERNAL_rdblk_uc_generic_ram(sa__, 1426 addr + merlin16_info_ptr->core_var_ram_base, 1427 data, 1428 0, 1429 data, 1430 &state, 1431 merlin16_diag_access_read_byte_callback)); 1432 EFUN_PRINTF(("\n")); 1433 } else { 1434 ESTM_PRINTF(("Core RAM Read byte: x%04x = x%02x\n",(uint8_t)addr,merlin16_rdbc_uc_var(sa__, __ERR, (uint8_t)addr))); 1435 } 1436 } break; 1437 case SRDS_LANE_RAM_READ_BYTE: { 1438 if(data > 1) { 1439 EFUN_PRINTF(("\n**** SERDES BLK LANE RAM READ BYTE ****")); 1440 EFUN(merlin16_INTERNAL_rdblk_uc_generic_ram(sa__, (addr + merlin16_info_ptr->lane_var_ram_base + (merlin16_get_physical_lane(sa__) * merlin16_info_ptr->lane_var_ram_size)), 1441 data, 1442 0, 1443 data, 1444 &state, 1445 merlin16_diag_access_read_byte_callback)); 1446 EFUN_PRINTF(("\n")); 1447 } else { 1448 ESTM_PRINTF(("Lane RAM Read byte: x%04x = x%02x\n",addr,merlin16_rdbl_uc_var(sa__, __ERR,addr))); 1449 } 1450 } break; 1451 case SRDS_CORE_RAM_READ_WORD: { 1452 if(data > 1) { 1453 EFUN_PRINTF(("\n**** SERDES BLK CORE RAM READ WORD ****")); 1454 EFUN(merlin16_INTERNAL_rdblk_uc_generic_ram(sa__, 1455 addr + merlin16_info_ptr->core_var_ram_base, 1456 ((data+1)>>1)<<1, /* Round up to nearest word count */ 1457 0, 1458 ((data+1)>>1)<<1, /* Round up to nearest word count */ 1459 &state, 1460 merlin16_diag_access_read_word_callback)); 1461 EFUN_PRINTF(("\n")); 1462 } else { 1463 ESTM_PRINTF(("Core RAM Read word: x%04x = x%04x\n",addr,merlin16_rdwc_uc_var(sa__, __ERR, (uint8_t)addr))); 1464 } 1465 } break; 1466 case SRDS_LANE_RAM_READ_WORD: { 1467 if(data > 1) { 1468 EFUN_PRINTF(("\n**** SERDES BLK LANE RAM READ WORD ****")); 1469 EFUN(merlin16_INTERNAL_rdblk_uc_generic_ram(sa__, (addr + merlin16_info_ptr->lane_var_ram_base + (merlin16_get_physical_lane(sa__) * merlin16_info_ptr->lane_var_ram_size)), 1470 ((data+1)>>1)<<1, /* Round up to nearest word count */ 1471 0, 1472 ((data+1)>>1)<<1, /* Round up to nearest word count */ 1473 &state, 1474 merlin16_diag_access_read_word_callback)); 1475 EFUN_PRINTF(("\n")); 1476 } else { 1477 ESTM_PRINTF(("Lane RAM Read word: x%04x = x%04x\n",addr,merlin16_rdwl_uc_var(sa__, __ERR, addr))); 1478 } 1479 } break; 1480 case SRDS_CORE_RAM_RMW_BYTE: { 1481 uint8_t tmp, tmp2; 1482 ESTM(tmp = merlin16_rdbc_uc_var(sa__, __ERR, (uint8_t)addr)); 1483 tmp2 = (tmp & (uint8_t)~param) | ((uint8_t)param & data); 1484 EFUN(merlin16_wrbc_uc_var(sa__, (uint8_t)addr,tmp2)); 1485 EFUN_PRINTF(("Core RAM RMW byte: x%04x = x%02x -> x%02x\n",addr,tmp,tmp2)); 1486 } break; 1487 case SRDS_LANE_RAM_RMW_BYTE: { 1488 uint8_t tmp, tmp2; 1489 ESTM(tmp = merlin16_rdbl_uc_var(sa__, __ERR,addr)); 1490 tmp2 = (tmp & (uint8_t)~param) | ((uint8_t)param & data); 1491 EFUN(merlin16_wrbl_uc_var(sa__, addr,tmp2)); 1492 EFUN_PRINTF(("Lane RAM RMW byte: x%04x = x%02x -> x%02x\n",addr,tmp,tmp2)); 1493 } break; 1494 case SRDS_CORE_RAM_RMW_WORD: { 1495 uint16_t tmp, tmp2; 1496 ESTM(tmp = merlin16_rdwc_uc_var(sa__, __ERR, (uint8_t)addr)); 1497 tmp2 = (tmp & ~param) | (param & data); 1498 EFUN(merlin16_wrwc_uc_var(sa__, (uint8_t)addr,tmp2)); 1499 EFUN_PRINTF(("Core RAM RMW word: x%04x = x%04x -> x%04x\n",addr,tmp,tmp2)); 1500 } break; 1501 case SRDS_LANE_RAM_RMW_WORD: { 1502 uint16_t tmp, tmp2; 1503 ESTM(tmp = merlin16_rdwl_uc_var(sa__, __ERR,addr)); 1504 tmp2 = (tmp & ~param) | (param & data); 1505 EFUN(merlin16_wrwl_uc_var(sa__, addr,tmp2)); 1506 EFUN_PRINTF(("Lane RAM RMW word: x%04x = x%04x -> x%04x\n",addr,tmp,tmp2)); 1507 } break; 1508 case SRDS_GLOB_RAM_READ_BYTE: { 1509 if(data > 1) { 1510 EFUN_PRINTF(("\n**** SERDES BLK GLOB RAM READ BYTE ****")); 1511 EFUN(merlin16_INTERNAL_rdblk_uc_generic_ram(sa__, 1512 0x20000000 | (uint32_t)addr, 1513 data, 1514 0, 1515 data, 1516 &state, 1517 merlin16_diag_access_read_byte_callback)); 1518 EFUN_PRINTF(("\n")); 1519 } else { 1520 ESTM_PRINTF(("Glob RAM Read byte: x%04x = x%02x\n",addr,merlin16_INTERNAL_rdb_uc_var(sa__, __ERR,addr))); 1521 } 1522 } break; 1523 case SRDS_GLOB_RAM_RMW_BYTE: { 1524 uint8_t tmp, tmp2; 1525 ESTM(tmp = merlin16_INTERNAL_rdb_uc_var(sa__, __ERR,addr)); 1526 tmp2 = (tmp & (uint8_t)~param) | ((uint8_t)param & data); 1527 EFUN(merlin16_INTERNAL_wrb_uc_var(sa__, addr,tmp2)); 1528 EFUN_PRINTF(("Glob RAM RMW byte: x%04x = x%02x -> x%02x\n",addr,tmp,tmp2)); 1529 } break; 1530 case SRDS_GLOB_RAM_READ_WORD: { 1531 if(data > 1) { 1532 EFUN_PRINTF(("\n**** SERDES BLK GLOB RAM READ WORD ****")); 1533 EFUN(merlin16_INTERNAL_rdblk_uc_generic_ram(sa__, 1534 0x20000000 | (uint32_t)addr, 1535 ((data+1)>>1)<<1, /* Round up to nearest word count */ 1536 0, 1537 ((data+1)>>1)<<1, /* Round up to nearest word count */ 1538 &state, 1539 merlin16_diag_access_read_word_callback)); 1540 EFUN_PRINTF(("\n")); 1541 } else { 1542 ESTM_PRINTF(("Glob RAM Read word: x%04x = x%04x\n",addr,merlin16_INTERNAL_rdw_uc_var(sa__, __ERR,addr))); 1543 } 1544 } break; 1545 case SRDS_GLOB_RAM_RMW_WORD: { 1546 uint16_t tmp, tmp2; 1547 ESTM(tmp = merlin16_INTERNAL_rdw_uc_var(sa__, __ERR,addr)); 1548 tmp2 = (tmp & ~param) | (param & data); 1549 EFUN(merlin16_INTERNAL_wrw_uc_var(sa__, addr,tmp2)); 1550 EFUN_PRINTF(("Glob RAM RMW word: x%04x = x%04x -> x%04x\n",addr,tmp,tmp2)); 1551 } break; 1552 case SRDS_UC_CMD: { 1553 uint16_t tmp; 1554 EFUN(merlin16_pmd_uc_cmd_with_data(sa__, (enum srds_pmd_uc_cmd_enum)addr, (uint8_t)param, data, GRACEFUL_STOP_TIME)); 1555 ESTM(tmp = rd_uc_dsc_data()); 1556 EFUN_PRINTF(("uC Command: cmd=x%02x supp=x%02x data=x%04x returned=x%04x\n",addr,param,data,tmp)); 1557 } break; 1558 case SRDS_PROG_RAM_READ_BYTE: { 1559 if(data > 1) { 1560 EFUN_PRINTF(("\n**** SERDES BLK PROG RAM READ BYTE ****")); 1561 EFUN(merlin16_INTERNAL_rdblk_uc_generic_ram(sa__, 1562 addr, 1563 data, 1564 0, 1565 data, 1566 &state, 1567 merlin16_diag_access_read_byte_callback)); 1568 EFUN_PRINTF(("\n")); 1569 } else { 1570 ESTM_PRINTF(("Prog RAM Read byte: x%04x = x%02x\n",addr,merlin16_INTERNAL_rdb_uc_var(sa__, __ERR,addr))); 1571 } 1572 } break; 1573 case SRDS_PROG_RAM_READ_WORD: { 1574 if(data > 1) { 1575 EFUN_PRINTF(("\n**** SERDES BLK PROG RAM READ WORD ****")); 1576 EFUN(merlin16_INTERNAL_rdblk_uc_generic_ram(sa__, 1577 addr, 1578 ((data+1)>>1)<<1, /* Round up to nearest word count */ 1579 0, 1580 ((data+1)>>1)<<1, /* Round up to nearest word count */ 1581 &state, 1582 merlin16_diag_access_read_word_callback)); 1583 EFUN_PRINTF(("\n")); 1584 } else { 1585 ESTM_PRINTF(("Prog RAM Read word: x%04x = x%04x\n",addr,merlin16_INTERNAL_rdw_uc_var(sa__, __ERR,addr))); 1586 } 1587 } break; 1588 case SRDS_BER_PROJ_DATA: { 1589 /* display ber projections for all channels */ 1590 EFUN(_display_ber_scan_data(sa__, (uint8_t)addr, (uint8_t)data, (uint8_t)(param>>4))); 1591 } break; 1592 case SRDS_EN_BREAKPOINT: 1593 case SRDS_GOTO_BREAKPOINT: 1594 case SRDS_RD_BREAKPOINT: 1595 case SRDS_DIS_BREAKPOINT: 1596 default: EFUN_PRINTF(("Invalid request type merlin16_diag_access\n")); 1597 } 1598 1599 return(ERR_CODE_NONE); 1600 } 1601 1602 err_code_t merlin16_display_state (srds_access_t *sa__) { 1603 EFUN(merlin16_display_core_state(sa__)); 1604 EFUN(merlin16_display_lane_state_hdr()); 1605 EFUN(merlin16_display_lane_state(sa__)); 1606 EFUN(merlin16_display_lane_state_legend()); 1607 return(ERR_CODE_NONE); 1608 } 1609 1610 err_code_t merlin16_display_config (srds_access_t *sa__) { 1611 EFUN(merlin16_display_core_config(sa__)); 1612 EFUN(merlin16_display_lane_config(sa__)); 1613 return(ERR_CODE_NONE); 1614 } 1615 1616 /*************************/ 1617 /* Temperature forcing */ 1618 /*************************/ 1619 1620 err_code_t merlin16_force_die_temperature (srds_access_t *sa__, int16_t die_temp) { 1621 /* disable force */ 1622 if(die_temp == -255) { 1623 EFUN(wrc_micro_pvt_tempdata_frc(0)); 1624 return(ERR_CODE_NONE); 1625 } 1626 1627 /* enable force */ 1628 if (die_temp>130) 1629 die_temp = 130; 1630 if (die_temp<-45) 1631 die_temp = -45; 1632 1633 EFUN(wrc_micro_pvt_tempdata_frcval(_degC_to_bin(die_temp))); 1634 EFUN(wrc_micro_pvt_tempdata_frc(1)); 1635 1636 return(ERR_CODE_NONE); 1637 } 1638 1639 /**********************/ 1640 /* CL72/CL93 Status */ 1641 /**********************/ 1642 1643 1644 err_code_t merlin16_display_cl72_status(srds_access_t *sa__) { 1645 EFUN_PRINTF(("\n\n************************\n" )); 1646 ESTM_PRINTF(( "** LANE %d CL72 Status **\n" , merlin16_get_lane(sa__) )); 1647 EFUN_PRINTF(( "************************\n" )); 1648 ESTM_PRINTF(( "cl72_signal_detect = %d (1 = CL72 training FSM in SEND_DATA state; 0 = CL72 in training state)\n" , rd_cl72_training_fsm_signal_detect())); 1649 ESTM_PRINTF(( "cl72_ieee_training_failure = %d (1 = Training failure detected; 0 = Training failure not detected)\n", rd_cl72_ieee_training_failure() )); 1650 ESTM_PRINTF(( "cl72_ieee_training_status = %d (1 = Start-up protocol in progress; 0 = Start-up protocol complete)\n" , rd_cl72_ieee_training_status() )); 1651 ESTM_PRINTF(( "cl72_ieee_receiver_status = %d (1 = Receiver trained and ready to receive; 0 = Receiver training)\n\n" , rd_cl72_ieee_receiver_status() )); 1652 return(ERR_CODE_NONE); 1653 } 1654 1655 1656 1657