merlin16_prbs.c (16896B)
1 /************************************************************************************** 2 ************************************************************************************** 3 * File Name : merlin16_prbs.c * 4 * Created On : 04 Nov 2015 * 5 * Created By : Brent Roberts * 6 * Description : APIs for Serdes IPs * 7 * Revision : * 8 * * 9 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 10 * 11 * Copyright 2007-2019 Broadcom Inc. All rights reserved. * 12 * No portions of this material may be reproduced in any form without * 13 * the written permission of: * 14 * Broadcom Corporation * 15 * 5300 California Avenue * 16 * Irvine, CA 92617 * 17 * * 18 * All information contained in this document is Broadcom Corporation * 19 * company private proprietary, and trade secret. * 20 */ 21 22 /** @file merlin16_prbs.c 23 * Implementation of API PRBS functions 24 */ 25 #ifdef NON_SDK 26 #include <stdio.h> 27 #include <math.h> 28 #endif 29 30 #include "merlin16_prbs.h" 31 #include "merlin16_common.h" 32 #include "merlin16_dependencies.h" 33 #include "merlin16_functions.h" 34 #include "merlin16_internal.h" 35 #include "merlin16_internal_error.h" 36 #include "merlin16_select_defns.h" 37 #include "merlin16_access.h" 38 39 40 /******************************/ 41 /* TX Pattern Generator APIs */ 42 /******************************/ 43 44 /* Cofigure shared TX Pattern (Return Val = 0:PASS, 1-6:FAIL (reports 6 possible error scenarios if failed)) */ 45 err_code_t merlin16_config_shared_tx_pattern(srds_access_t *sa__, uint8_t patt_length, const char pattern[]) { 46 47 char patt_final[245] = ""; 48 char patt_mod[245] = "", bin[5] = ""; 49 uint8_t str_len, i, k, j = 0; 50 uint8_t offset_len, actual_patt_len = 0, hex = 0; 51 uint8_t zero_pad_len = 0; /* suppress warnings, changed by merlin16_INTERNAL_calc_patt_gen_mode_sel() */ 52 uint16_t patt_gen_wr_val = 0; 53 uint8_t mode_sel = 0; /* suppress warnings, changed by merlin16_INTERNAL_calc_patt_gen_mode_sel() */ 54 55 EFUN(merlin16_INTERNAL_calc_patt_gen_mode_sel(&mode_sel,&zero_pad_len,patt_length)); 56 57 /* Generating the appropriate write value to patt_gen_seq registers */ 58 str_len = (int8_t)USR_STRLEN(pattern); 59 60 if ((str_len > 2) && ((USR_STRNCMP(pattern, "0x", 2)) == 0)) { 61 /* Hexadecimal Pattern */ 62 for (i=2; i < str_len; i++) { 63 if (pattern[i] != '_') { 64 EFUN(merlin16_INTERNAL_compute_bin(pattern[i],bin)); 65 ENULL_STRNCAT(patt_mod, bin, 4); 66 actual_patt_len = actual_patt_len + 4; 67 if (actual_patt_len > 240) { 68 EFUN_PRINTF(("ERROR: Pattern bigger than max pattern length\n")); 69 return (_error(ERR_CODE_CFG_PATT_PATTERN_BIGGER_THAN_MAXLEN)); 70 } 71 } 72 } 73 74 offset_len = (actual_patt_len - patt_length); 75 if ((offset_len > 3) || (actual_patt_len < patt_length)) { 76 EFUN_PRINTF(("ERROR: Pattern length provided does not match the hexadecimal pattern provided\n")); 77 return (_error(ERR_CODE_CFG_PATT_LEN_MISMATCH)); 78 } 79 else if (offset_len) { 80 for (i=0; i < offset_len; i++) { 81 if (patt_mod[i] != '0') { 82 EFUN_PRINTF(("ERROR: Pattern length provided does not match the hexadecimal pattern provided\n")); 83 return (_error(ERR_CODE_CFG_PATT_LEN_MISMATCH)); 84 } 85 } 86 for (i=offset_len; i <= actual_patt_len; i++) { 87 patt_mod[i - offset_len] = patt_mod[i]; 88 } 89 } 90 } 91 else { 92 /* Binary Pattern */ 93 for (i=0; i < str_len; i++) { 94 if ((pattern[i] == '0') || (pattern[i] == '1')) { 95 bin[0] = pattern[i]; 96 bin[1] = '\0'; 97 ENULL_STRNCAT(patt_mod, bin, 1); 98 actual_patt_len++; 99 if (actual_patt_len > 240) { 100 EFUN_PRINTF(("ERROR: Pattern bigger than max pattern length\n")); 101 return (_error(ERR_CODE_CFG_PATT_PATTERN_BIGGER_THAN_MAXLEN)); 102 } 103 } 104 else if (pattern[i] != '_') { 105 EFUN_PRINTF(("ERROR: Invalid input Pattern\n")); 106 return (_error(ERR_CODE_CFG_PATT_INVALID_PATTERN)); 107 } 108 } 109 110 if (actual_patt_len != patt_length) { 111 EFUN_PRINTF(("ERROR: Pattern length provided does not match the binary pattern provided\n")); 112 return (_error(ERR_CODE_CFG_PATT_LEN_MISMATCH)); 113 } 114 } 115 116 /* Zero padding upper bits and concatinating patt_mod to form patt_final */ 117 for (i=0; i < zero_pad_len; i++) { 118 ENULL_STRNCAT(patt_final, "0", 1); 119 j++; 120 } 121 for (i=zero_pad_len; i + patt_length < 241; i = i + patt_length) { 122 ENULL_STRNCAT(patt_final, patt_mod, patt_length); 123 j++; 124 } 125 126 /* EFUN_PRINTF(("\nFinal Pattern = %s\n\n",patt_final)); */ 127 128 for (i=0; i < 15; i++) { 129 130 for (j=0; j < 4; j++) { 131 k = i*16 + j*4; 132 bin[0] = patt_final[k]; 133 bin[1] = patt_final[k+1]; 134 bin[2] = patt_final[k+2]; 135 bin[3] = patt_final[k+3]; 136 bin[4] = '\0'; 137 EFUN(merlin16_INTERNAL_compute_hex(bin, &hex)); 138 patt_gen_wr_val = ((patt_gen_wr_val << 4) | hex); 139 } 140 /* EFUN_PRINTF(("patt_gen_wr_val[%d] = 0x%x\n",(14-i),patt_gen_wr_val)); */ 141 142 /* Writing to apprpriate patt_gen_seq Registers */ 143 switch (i) { 144 case 0: EFUN(wrc_patt_gen_seq_14(patt_gen_wr_val)); 145 break; 146 case 1: EFUN(wrc_patt_gen_seq_13(patt_gen_wr_val)); 147 break; 148 case 2: EFUN(wrc_patt_gen_seq_12(patt_gen_wr_val)); 149 break; 150 case 3: EFUN(wrc_patt_gen_seq_11(patt_gen_wr_val)); 151 break; 152 case 4: EFUN(wrc_patt_gen_seq_10(patt_gen_wr_val)); 153 break; 154 case 5: EFUN(wrc_patt_gen_seq_9(patt_gen_wr_val)); 155 break; 156 case 6: EFUN(wrc_patt_gen_seq_8(patt_gen_wr_val)); 157 break; 158 case 7: EFUN(wrc_patt_gen_seq_7(patt_gen_wr_val)); 159 break; 160 case 8: EFUN(wrc_patt_gen_seq_6(patt_gen_wr_val)); 161 break; 162 case 9: EFUN(wrc_patt_gen_seq_5(patt_gen_wr_val)); 163 break; 164 case 10: EFUN(wrc_patt_gen_seq_4(patt_gen_wr_val)); 165 break; 166 case 11: EFUN(wrc_patt_gen_seq_3(patt_gen_wr_val)); 167 break; 168 case 12: EFUN(wrc_patt_gen_seq_2(patt_gen_wr_val)); 169 break; 170 case 13: EFUN(wrc_patt_gen_seq_1(patt_gen_wr_val)); 171 break; 172 case 14: EFUN(wrc_patt_gen_seq_0(patt_gen_wr_val)); 173 break; 174 default: EFUN_PRINTF(("ERROR: Invalid write to patt_gen_seq register\n")); 175 return (_error(ERR_CODE_CFG_PATT_INVALID_SEQ_WRITE)); 176 } 177 } 178 179 /* Pattern Generator Mode Select */ 180 /* EFUN(wr_patt_gen_mode_sel(mode_sel)); */ 181 /* EFUN_PRINTF(("Pattern gen Mode = %d\n",mode)); */ 182 183 /* Enable Fixed pattern Generation */ 184 /* EFUN(wr_patt_gen_en(0x1)); */ 185 return(ERR_CODE_NONE); 186 } 187 188 189 /* Enable/Disable Shared TX pattern generator */ 190 err_code_t merlin16_tx_shared_patt_gen_en(srds_access_t *sa__, uint8_t enable, uint8_t patt_length) { 191 uint8_t zero_pad_len = 0; /* suppress warnings, changed by merlin16_INTERNAL_calc_patt_gen_mode_sel() */ 192 uint8_t mode_sel = 0; /* suppress warnings, changed by merlin16_INTERNAL_calc_patt_gen_mode_sel() */ 193 194 EFUN(merlin16_INTERNAL_calc_patt_gen_mode_sel(&mode_sel,&zero_pad_len,patt_length)); 195 196 if (enable) { 197 if ((mode_sel < 1) || (mode_sel > 6)) { 198 return (_error(ERR_CODE_PATT_GEN_INVALID_MODE_SEL)); 199 } 200 mode_sel = (12 - mode_sel); 201 EFUN(wr_patt_gen_start_pos(mode_sel)); /* Start position for pattern */ 202 EFUN(wr_patt_gen_stop_pos(0x0)); /* Stop position for pattern */ 203 EFUN(wr_patt_gen_en(0x1)); /* Enable Fixed pattern Generation */ 204 } 205 else { 206 EFUN(wr_patt_gen_en(0x0)); /* Disable Fixed pattern Generation */ 207 } 208 return(ERR_CODE_NONE); 209 } 210 211 212 /**************************************/ 213 /* PRBS Generator/Checker Functions */ 214 /**************************************/ 215 216 /* Configure PRBS Generator */ 217 err_code_t merlin16_config_tx_prbs(srds_access_t *sa__, enum srds_prbs_polynomial_enum prbs_poly_mode, uint8_t prbs_inv) { 218 uint8_t poly_mode_lsb; 219 poly_mode_lsb = prbs_poly_mode & 0x7; 220 221 EFUN(wr_prbs_gen_mode_sel((uint8_t)poly_mode_lsb)); /* PRBS Generator mode sel */ 222 EFUN(wr_prbs_gen_inv(prbs_inv)); /* PRBS Invert Enable/Disable */ 223 /* To enable PRBS Generator */ 224 /* EFUN(wr_prbs_gen_en(0x1)); */ 225 return (ERR_CODE_NONE); 226 } 227 228 err_code_t merlin16_get_tx_prbs_config(srds_access_t *sa__, enum srds_prbs_polynomial_enum *prbs_poly_mode, uint8_t *prbs_inv) { 229 uint8_t val; 230 231 ESTM(val = rd_prbs_gen_mode_sel()); /* PRBS Generator mode sel */ 232 *prbs_poly_mode = (enum srds_prbs_polynomial_enum)val; 233 ESTM(val = rd_prbs_gen_inv()); /* PRBS Invert Enable/Disable */ 234 *prbs_inv = val; 235 236 return (ERR_CODE_NONE); 237 } 238 239 /* PRBS Generator Enable/Disable */ 240 err_code_t merlin16_tx_prbs_en(srds_access_t *sa__, uint8_t enable) { 241 242 if (enable) { 243 EFUN(wr_prbs_gen_en(0x1)); /* Enable PRBS Generator */ 244 } 245 else { 246 EFUN(wr_prbs_gen_en(0x0)); /* Disable PRBS Generator */ 247 } 248 return (ERR_CODE_NONE); 249 } 250 251 /* Get PRBS Generator Enable/Disable */ 252 err_code_t merlin16_get_tx_prbs_en(srds_access_t *sa__, uint8_t *enable) { 253 254 ESTM(*enable = rd_prbs_gen_en()); 255 256 return (ERR_CODE_NONE); 257 } 258 259 /* PRBS 1-bit error injection */ 260 err_code_t merlin16_tx_prbs_err_inject(srds_access_t *sa__, uint8_t enable) { 261 /* PRBS Error Insert. 262 0 to 1 transition on this signal will insert single bit error in the MSB bit of the data bus. 263 Reset value is 0x0. 264 */ 265 if(enable) 266 EFUN(wr_prbs_gen_err_ins(0x1)); 267 EFUN(wr_prbs_gen_err_ins(0)); 268 return (ERR_CODE_NONE); 269 } 270 271 /* Configure PRBS Checker */ 272 err_code_t merlin16_config_rx_prbs(srds_access_t *sa__, enum srds_prbs_polynomial_enum prbs_poly_mode, enum srds_prbs_checker_mode_enum prbs_checker_mode, uint8_t prbs_inv) { 273 uint8_t dig_lpbk = 0; 274 uint8_t poly_mode_lsb; 275 poly_mode_lsb = prbs_poly_mode & 0x7; 276 277 EFUN(wr_prbs_chk_mode_sel((uint8_t)poly_mode_lsb)); /* PRBS Checker Polynomial mode sel */ 278 EFUN(wr_prbs_chk_mode((uint8_t)prbs_checker_mode)); /* PRBS Checker mode sel (PRBS LOCK state machine select) */ 279 ESTM(dig_lpbk = rd_dig_lpbk_en()); 280 if(dig_lpbk == 0) { 281 /* Only enable auto mode in non-digital loop-back mode */ 282 EFUN(wr_prbs_chk_en_auto_mode(0x1)); /* PRBS Checker enable control - rx_dsc_lock & prbs_chk_en */ 283 } 284 EFUN(wr_prbs_chk_inv(prbs_inv)); /* PRBS Invert Enable/Disable */ 285 /* To enable PRBS Checker */ 286 /* EFUN(wr_prbs_chk_en(0x1)); */ 287 return (ERR_CODE_NONE); 288 } 289 290 /* get PRBS Checker */ 291 err_code_t merlin16_get_rx_prbs_config(srds_access_t *sa__, enum srds_prbs_polynomial_enum *prbs_poly_mode, enum srds_prbs_checker_mode_enum *prbs_checker_mode, uint8_t *prbs_inv) { 292 uint8_t val; 293 294 ESTM(val = rd_prbs_chk_mode_sel()); /* PRBS Checker Polynomial mode sel */ 295 *prbs_poly_mode = (enum srds_prbs_polynomial_enum)val; 296 297 ESTM(val = rd_prbs_chk_mode()); /* PRBS Checker mode sel (PRBS LOCK state machine select) */ 298 *prbs_checker_mode = (enum srds_prbs_checker_mode_enum)val; 299 ESTM(val = rd_prbs_chk_inv()); /* PRBS Invert Enable/Disable */ 300 *prbs_inv = val; 301 return (ERR_CODE_NONE); 302 } 303 304 /* PRBS Checker Enable/Disable */ 305 err_code_t merlin16_rx_prbs_en(srds_access_t *sa__, uint8_t enable) { 306 307 if (enable) { 308 EFUN(wr_prbs_chk_burst_err_cnt_en(0x1)); /* Must be enabled before prbs_chk_en */ 309 EFUN(wr_prbs_chk_en(0x1)); /* Enable PRBS Checker */ 310 } 311 else { 312 EFUN(wr_prbs_chk_en(0x0)); /* Disable PRBS Checker */ 313 EFUN(wr_prbs_chk_burst_err_cnt_en(0x0)); 314 } 315 return (ERR_CODE_NONE); 316 } 317 318 err_code_t merlin16_get_rx_prbs_en(srds_access_t *sa__, uint8_t *enable) { 319 320 ESTM(*enable = rd_prbs_chk_en()); 321 return (ERR_CODE_NONE); 322 } 323 324 325 /* PRBS Checker Lock State */ 326 err_code_t merlin16_prbs_chk_lock_state(srds_access_t *sa__, uint8_t *chk_lock) { 327 if(!chk_lock) { 328 return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT)); 329 } 330 331 ESTM(*chk_lock = rd_prbs_chk_lock()); /* PRBS Checker Lock Indication 1 = Locked, 0 = Out of Lock */ 332 return (ERR_CODE_NONE); 333 } 334 335 /* PRBS Error Count and Lock Lost (bit 31 in lock lost) */ 336 err_code_t merlin16_prbs_err_count_ll(srds_access_t *sa__, uint32_t *prbs_err_cnt) { 337 uint16_t rddata; 338 339 if(!prbs_err_cnt) { 340 return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT)); 341 } 342 ESTM(rddata = REG_RD_TLB_RX_PRBS_CHK_ERR_CNT_MSB_STATUS()); 343 *prbs_err_cnt = ((uint32_t) rddata)<<16; 344 ESTM(*prbs_err_cnt = (*prbs_err_cnt | rd_prbs_chk_err_cnt_lsb())); 345 return (ERR_CODE_NONE); 346 } 347 348 /* PRBS Error Count State */ 349 err_code_t merlin16_prbs_err_count_state(srds_access_t *sa__, uint32_t *prbs_err_cnt, uint8_t *lock_lost) { 350 uint8_t dig_lpbk_enable = 0; 351 uint8_t link_training_enable = 0; 352 if(!prbs_err_cnt || !lock_lost) { 353 return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT)); 354 } 355 EFUN(merlin16_prbs_err_count_ll(sa__, prbs_err_cnt)); 356 *lock_lost = (*prbs_err_cnt >> 31); 357 *prbs_err_cnt = (*prbs_err_cnt & 0x7FFFFFFF); 358 359 /* Check if Digital Loopback and LinkTrainig both are enabled */ 360 ESTM(dig_lpbk_enable = rd_dig_lpbk_en()); 361 362 ESTM(link_training_enable = rd_cl72_ieee_training_enable()); 363 if(dig_lpbk_enable && link_training_enable) { 364 EFUN_PRINTF(("WARNING: PRBS Check Lock - Digital Loopback and Link Training both are enabled\n")); 365 } 366 return (ERR_CODE_NONE); 367 } 368 369 370 /* toggle checker enable to start hardware timers and error counters */ 371 err_code_t merlin16_prbs_chk_en_toggle(srds_access_t *sa__) { 372 EFUN(wr_prbs_chk_en(0)); 373 EFUN(wr_prbs_chk_en(1)); 374 return ERR_CODE_NONE; 375 } 376 377 err_code_t merlin16_display_detailed_prbs_state_hdr(void) { 378 EFUN_PRINTF(("\nPRBS DETAILED DISPLAY :\n")); 379 380 /* Comment out display of PRBS burst error if BLACKHAWK */ 381 EFUN_PRINTF((" LN TX-Mode TX-PRBS-Inv TX-PMD-Inv RX-Mode RX-PRBS-Inv RX-PMD-Inv Lck LL PRBS-Err-Cnt Burst-Err")); 382 EFUN_PRINTF((" BER\n")); 383 return (ERR_CODE_NONE); 384 } 385 386 const char* merlin16_e2s_prbs_mode_enum[8] = { 387 " PRBS_7", 388 " PRBS_9", 389 "PRBS_11", 390 "PRBS_15", 391 "PRBS_23", 392 "PRBS_31", 393 "PRBS_58", 394 " ERR " 395 }; 396 397 err_code_t merlin16_display_detailed_prbs_state(srds_access_t *sa__) { 398 uint32_t err_cnt = 0; 399 uint8_t lock_lost = 0; 400 uint8_t enabled; 401 402 ESTM_PRINTF((" %d ",merlin16_get_lane(sa__))); 403 404 ESTM(enabled = rd_prbs_gen_en()); 405 if(enabled) { 406 enum srds_prbs_polynomial_enum prbs_poly_mode = PRBS_7; 407 uint8_t prbs_inv = 0; 408 char *prbs_string; 409 EFUN(merlin16_get_tx_prbs_config(sa__, &prbs_poly_mode, &prbs_inv)); 410 prbs_string = (char *)merlin16_e2s_prbs_mode_enum[prbs_poly_mode]; 411 ESTM_PRINTF(("%s",prbs_string)); 412 ESTM_PRINTF((" %1d ",prbs_inv)); 413 } else { 414 EFUN_PRINTF((" OFF ")); 415 ESTM_PRINTF((" - ")); 416 } 417 ESTM_PRINTF((" %1d ",rd_tx_pmd_dp_invert())); 418 419 ESTM(enabled = rd_prbs_chk_en()); 420 if(enabled) { 421 enum srds_prbs_polynomial_enum prbs_poly_mode = PRBS_7; 422 enum srds_prbs_checker_mode_enum prbs_checker_mode; 423 uint8_t prbs_inv = 0; 424 char *prbs_string; 425 EFUN(merlin16_get_rx_prbs_config(sa__, &prbs_poly_mode, &prbs_checker_mode, &prbs_inv)); 426 prbs_string = (char *)merlin16_e2s_prbs_mode_enum[prbs_poly_mode]; 427 ESTM_PRINTF((" %s",prbs_string)); 428 ESTM_PRINTF((" %1d ",prbs_inv)); 429 } else { 430 EFUN_PRINTF((" OFF ")); 431 ESTM_PRINTF((" - ")); 432 } 433 434 ESTM_PRINTF((" %1d ",rd_rx_pmd_dp_invert())); 435 ESTM_PRINTF((" %d ",rd_prbs_chk_lock())); 436 EFUN(merlin16_prbs_err_count_state(sa__,&err_cnt,&lock_lost)); 437 EFUN_PRINTF((" %d %010d ",lock_lost,err_cnt)); 438 ESTM_PRINTF((" %4d ",rd_prbs_chk_burst_err_cnt())); 439 EFUN(merlin16_INTERNAL_display_BER(sa__,100)); 440 EFUN_PRINTF(("\n")); 441 442 return (ERR_CODE_NONE); 443 } 444 445 446 447