merlin16_pcieg3_prbs.c (16408B)
1 /************************************************************************************** 2 ************************************************************************************** 3 * File Name : merlin16_pcieg3_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_pcieg3_prbs.c 23 * Implementation of API PRBS functions 24 */ 25 #ifdef __KERNEL__ 26 #include <linux/types.h> 27 #else 28 #ifndef EXCLUDE_STD_HEADERS 29 #include <stdio.h> 30 #include <math.h> 31 #endif 32 #endif 33 34 #include "merlin16_pcieg3_prbs.h" 35 #include "merlin16_pcieg3_common.h" 36 #include "merlin16_pcieg3_dependencies.h" 37 #include "merlin16_pcieg3_functions.h" 38 #include "merlin16_pcieg3_internal.h" 39 #include "merlin16_pcieg3_internal_error.h" 40 #include "merlin16_pcieg3_select_defns.h" 41 #include "merlin16_pcieg3_usr_includes.h" 42 43 /******************************/ 44 /* TX Pattern Generator APIs */ 45 /******************************/ 46 47 /* Cofigure shared TX Pattern (Return Val = 0:PASS, 1-6:FAIL (reports 6 possible error scenarios if failed)) */ 48 err_code_t merlin16_pcieg3_config_shared_tx_pattern(srds_access_t *sa__, uint8_t patt_length, const char pattern[]) { 49 50 char patt_final[245] = ""; 51 char patt_mod[245] = "", bin[5] = ""; 52 uint8_t str_len, i, k, j = 0; 53 uint8_t offset_len, actual_patt_len = 0, hex = 0; 54 uint8_t zero_pad_len = 0; /* suppress warnings, changed by merlin16_pcieg3_INTERNAL_calc_patt_gen_mode_sel() */ 55 uint16_t patt_gen_wr_val = 0; 56 uint8_t mode_sel = 0; /* suppress warnings, changed by merlin16_pcieg3_INTERNAL_calc_patt_gen_mode_sel() */ 57 58 EFUN(merlin16_pcieg3_INTERNAL_calc_patt_gen_mode_sel(&mode_sel,&zero_pad_len,patt_length)); 59 60 /* Generating the appropriate write value to patt_gen_seq registers */ 61 str_len = (int8_t)USR_STRLEN(pattern); 62 63 if ((str_len > 2) && ((USR_STRNCMP(pattern, "0x", 2)) == 0)) { 64 /* Hexadecimal Pattern */ 65 for (i=2; i < str_len; i++) { 66 if (pattern[i] != '_') { 67 EFUN(merlin16_pcieg3_INTERNAL_compute_bin(pattern[i],bin)); 68 ENULL_STRNCAT(patt_mod, bin, 4); 69 actual_patt_len = actual_patt_len + 4; 70 if (actual_patt_len > 240) { 71 EFUN_PRINTF(("ERROR: Pattern bigger than max pattern length\n")); 72 return (_error(ERR_CODE_CFG_PATT_PATTERN_BIGGER_THAN_MAXLEN)); 73 } 74 } 75 } 76 77 offset_len = (actual_patt_len - patt_length); 78 if ((offset_len > 3) || (actual_patt_len < patt_length)) { 79 EFUN_PRINTF(("ERROR: Pattern length provided does not match the hexadecimal pattern provided\n")); 80 return (_error(ERR_CODE_CFG_PATT_LEN_MISMATCH)); 81 } 82 else if (offset_len) { 83 for (i=0; i < offset_len; i++) { 84 if (patt_mod[i] != '0') { 85 EFUN_PRINTF(("ERROR: Pattern length provided does not match the hexadecimal pattern provided\n")); 86 return (_error(ERR_CODE_CFG_PATT_LEN_MISMATCH)); 87 } 88 } 89 for (i=offset_len; i <= actual_patt_len; i++) { 90 patt_mod[i - offset_len] = patt_mod[i]; 91 } 92 } 93 } 94 else { 95 /* Binary Pattern */ 96 for (i=0; i < str_len; i++) { 97 if ((pattern[i] == '0') || (pattern[i] == '1')) { 98 bin[0] = pattern[i]; 99 bin[1] = '\0'; 100 ENULL_STRNCAT(patt_mod, bin, 1); 101 actual_patt_len++; 102 if (actual_patt_len > 240) { 103 EFUN_PRINTF(("ERROR: Pattern bigger than max pattern length\n")); 104 return (_error(ERR_CODE_CFG_PATT_PATTERN_BIGGER_THAN_MAXLEN)); 105 } 106 } 107 else if (pattern[i] != '_') { 108 EFUN_PRINTF(("ERROR: Invalid input Pattern\n")); 109 return (_error(ERR_CODE_CFG_PATT_INVALID_PATTERN)); 110 } 111 } 112 113 if (actual_patt_len != patt_length) { 114 EFUN_PRINTF(("ERROR: Pattern length provided does not match the binary pattern provided\n")); 115 return (_error(ERR_CODE_CFG_PATT_LEN_MISMATCH)); 116 } 117 } 118 119 /* Zero padding upper bits and concatinating patt_mod to form patt_final */ 120 for (i=0; i < zero_pad_len; i++) { 121 ENULL_STRNCAT(patt_final, "0", 1); 122 j++; 123 } 124 for (i=zero_pad_len; i + patt_length < 241; i = i + patt_length) { 125 ENULL_STRNCAT(patt_final, patt_mod, patt_length); 126 j++; 127 } 128 129 /* EFUN_PRINTF(("\nFinal Pattern = %s\n\n",patt_final)); */ 130 131 for (i=0; i < 15; i++) { 132 133 for (j=0; j < 4; j++) { 134 k = i*16 + j*4; 135 bin[0] = patt_final[k]; 136 bin[1] = patt_final[k+1]; 137 bin[2] = patt_final[k+2]; 138 bin[3] = patt_final[k+3]; 139 bin[4] = '\0'; 140 EFUN(merlin16_pcieg3_INTERNAL_compute_hex(bin, &hex)); 141 patt_gen_wr_val = ((patt_gen_wr_val << 4) | hex); 142 } 143 /* EFUN_PRINTF(("patt_gen_wr_val[%d] = 0x%x\n",(14-i),patt_gen_wr_val)); */ 144 145 /* Writing to apprpriate patt_gen_seq Registers */ 146 switch (i) { 147 case 0: EFUN(wrc_patt_gen_seq_14(patt_gen_wr_val)); 148 break; 149 case 1: EFUN(wrc_patt_gen_seq_13(patt_gen_wr_val)); 150 break; 151 case 2: EFUN(wrc_patt_gen_seq_12(patt_gen_wr_val)); 152 break; 153 case 3: EFUN(wrc_patt_gen_seq_11(patt_gen_wr_val)); 154 break; 155 case 4: EFUN(wrc_patt_gen_seq_10(patt_gen_wr_val)); 156 break; 157 case 5: EFUN(wrc_patt_gen_seq_9(patt_gen_wr_val)); 158 break; 159 case 6: EFUN(wrc_patt_gen_seq_8(patt_gen_wr_val)); 160 break; 161 case 7: EFUN(wrc_patt_gen_seq_7(patt_gen_wr_val)); 162 break; 163 case 8: EFUN(wrc_patt_gen_seq_6(patt_gen_wr_val)); 164 break; 165 case 9: EFUN(wrc_patt_gen_seq_5(patt_gen_wr_val)); 166 break; 167 case 10: EFUN(wrc_patt_gen_seq_4(patt_gen_wr_val)); 168 break; 169 case 11: EFUN(wrc_patt_gen_seq_3(patt_gen_wr_val)); 170 break; 171 case 12: EFUN(wrc_patt_gen_seq_2(patt_gen_wr_val)); 172 break; 173 case 13: EFUN(wrc_patt_gen_seq_1(patt_gen_wr_val)); 174 break; 175 case 14: EFUN(wrc_patt_gen_seq_0(patt_gen_wr_val)); 176 break; 177 default: EFUN_PRINTF(("ERROR: Invalid write to patt_gen_seq register\n")); 178 return (_error(ERR_CODE_CFG_PATT_INVALID_SEQ_WRITE)); 179 } 180 } 181 182 /* Pattern Generator Mode Select */ 183 /* EFUN(wr_patt_gen_mode_sel(mode_sel)); */ 184 /* EFUN_PRINTF(("Pattern gen Mode = %d\n",mode)); */ 185 186 /* Enable Fixed pattern Generation */ 187 /* EFUN(wr_patt_gen_en(0x1)); */ 188 return(ERR_CODE_NONE); 189 } 190 191 192 /* Enable/Disable Shared TX pattern generator */ 193 err_code_t merlin16_pcieg3_tx_shared_patt_gen_en(srds_access_t *sa__, uint8_t enable, uint8_t patt_length) { 194 uint8_t zero_pad_len = 0; /* suppress warnings, changed by merlin16_pcieg3_INTERNAL_calc_patt_gen_mode_sel() */ 195 uint8_t mode_sel = 0; /* suppress warnings, changed by merlin16_pcieg3_INTERNAL_calc_patt_gen_mode_sel() */ 196 197 EFUN(merlin16_pcieg3_INTERNAL_calc_patt_gen_mode_sel(&mode_sel,&zero_pad_len,patt_length)); 198 199 if (enable) { 200 if ((mode_sel < 1) || (mode_sel > 6)) { 201 return (_error(ERR_CODE_PATT_GEN_INVALID_MODE_SEL)); 202 } 203 mode_sel = (12 - mode_sel); 204 EFUN(wr_patt_gen_start_pos(mode_sel)); /* Start position for pattern */ 205 EFUN(wr_patt_gen_stop_pos(0x0)); /* Stop position for pattern */ 206 EFUN(wr_patt_gen_en(0x1)); /* Enable Fixed pattern Generation */ 207 } 208 else { 209 EFUN(wr_patt_gen_en(0x0)); /* Disable Fixed pattern Generation */ 210 } 211 return(ERR_CODE_NONE); 212 } 213 214 215 /**************************************/ 216 /* PRBS Generator/Checker Functions */ 217 /**************************************/ 218 219 /* Configure PRBS Generator */ 220 err_code_t merlin16_pcieg3_config_tx_prbs(srds_access_t *sa__, enum srds_prbs_polynomial_enum prbs_poly_mode, uint8_t prbs_inv) { 221 uint8_t poly_mode_lsb; 222 poly_mode_lsb = prbs_poly_mode & 0x7; 223 224 EFUN(wr_prbs_gen_mode_sel((uint8_t)poly_mode_lsb)); /* PRBS Generator mode sel */ 225 EFUN(wr_prbs_gen_inv(prbs_inv)); /* PRBS Invert Enable/Disable */ 226 /* To enable PRBS Generator */ 227 /* EFUN(wr_prbs_gen_en(0x1)); */ 228 return (ERR_CODE_NONE); 229 } 230 231 err_code_t merlin16_pcieg3_get_tx_prbs_config(srds_access_t *sa__, enum srds_prbs_polynomial_enum *prbs_poly_mode, uint8_t *prbs_inv) { 232 uint8_t val; 233 234 ESTM(val = rd_prbs_gen_mode_sel()); /* PRBS Generator mode sel */ 235 *prbs_poly_mode = (enum srds_prbs_polynomial_enum)val; 236 ESTM(val = rd_prbs_gen_inv()); /* PRBS Invert Enable/Disable */ 237 *prbs_inv = val; 238 239 return (ERR_CODE_NONE); 240 } 241 242 /* PRBS Generator Enable/Disable */ 243 err_code_t merlin16_pcieg3_tx_prbs_en(srds_access_t *sa__, uint8_t enable) { 244 245 if (enable) { 246 EFUN(wr_prbs_gen_en(0x1)); /* Enable PRBS Generator */ 247 } 248 else { 249 EFUN(wr_prbs_gen_en(0x0)); /* Disable PRBS Generator */ 250 } 251 return (ERR_CODE_NONE); 252 } 253 254 /* Get PRBS Generator Enable/Disable */ 255 err_code_t merlin16_pcieg3_get_tx_prbs_en(srds_access_t *sa__, uint8_t *enable) { 256 257 ESTM(*enable = rd_prbs_gen_en()); 258 259 return (ERR_CODE_NONE); 260 } 261 262 /* PRBS 1-bit error injection */ 263 err_code_t merlin16_pcieg3_tx_prbs_err_inject(srds_access_t *sa__, uint8_t enable) { 264 /* PRBS Error Insert. 265 0 to 1 transition on this signal will insert single bit error in the MSB bit of the data bus. 266 Reset value is 0x0. 267 */ 268 if(enable) 269 EFUN(wr_prbs_gen_err_ins(0x1)); 270 EFUN(wr_prbs_gen_err_ins(0)); 271 return (ERR_CODE_NONE); 272 } 273 274 /* Configure PRBS Checker */ 275 err_code_t merlin16_pcieg3_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) { 276 277 uint8_t poly_mode_lsb; 278 poly_mode_lsb = prbs_poly_mode & 0x7; 279 280 EFUN(wr_prbs_chk_mode_sel((uint8_t)poly_mode_lsb)); /* PRBS Checker Polynomial mode sel */ 281 EFUN(wr_prbs_chk_mode((uint8_t)prbs_checker_mode)); /* PRBS Checker mode sel (PRBS LOCK state machine select) */ 282 EFUN(wr_prbs_chk_en_auto_mode(0x1)); /* PRBS Checker enable control - rx_dsc_lock & prbs_chk_en */ 283 EFUN(wr_prbs_chk_inv(prbs_inv)); /* PRBS Invert Enable/Disable */ 284 /* To enable PRBS Checker */ 285 /* EFUN(wr_prbs_chk_en(0x1)); */ 286 return (ERR_CODE_NONE); 287 } 288 289 /* get PRBS Checker */ 290 err_code_t merlin16_pcieg3_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) { 291 uint8_t val; 292 293 ESTM(val = rd_prbs_chk_mode_sel()); /* PRBS Checker Polynomial mode sel */ 294 *prbs_poly_mode = (enum srds_prbs_polynomial_enum)val; 295 296 ESTM(val = rd_prbs_chk_mode()); /* PRBS Checker mode sel (PRBS LOCK state machine select) */ 297 *prbs_checker_mode = (enum srds_prbs_checker_mode_enum)val; 298 ESTM(val = rd_prbs_chk_inv()); /* PRBS Invert Enable/Disable */ 299 *prbs_inv = val; 300 return (ERR_CODE_NONE); 301 } 302 303 /* PRBS Checker Enable/Disable */ 304 err_code_t merlin16_pcieg3_rx_prbs_en(srds_access_t *sa__, uint8_t enable) { 305 306 if (enable) { 307 EFUN(wr_prbs_chk_burst_err_cnt_en(0x1)); /* Must be enabled before prbs_chk_en */ 308 EFUN(wr_prbs_chk_en(0x1)); /* Enable PRBS Checker */ 309 } 310 else { 311 EFUN(wr_prbs_chk_en(0x0)); /* Disable PRBS Checker */ 312 EFUN(wr_prbs_chk_burst_err_cnt_en(0x0)); 313 } 314 return (ERR_CODE_NONE); 315 } 316 317 err_code_t merlin16_pcieg3_get_rx_prbs_en(srds_access_t *sa__, uint8_t *enable) { 318 319 ESTM(*enable = rd_prbs_chk_en()); 320 return (ERR_CODE_NONE); 321 } 322 323 324 /* PRBS Checker Lock State */ 325 err_code_t merlin16_pcieg3_prbs_chk_lock_state(srds_access_t *sa__, uint8_t *chk_lock) { 326 if(!chk_lock) { 327 return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT)); 328 } 329 330 ESTM(*chk_lock = rd_prbs_chk_lock()); /* PRBS Checker Lock Indication 1 = Locked, 0 = Out of Lock */ 331 return (ERR_CODE_NONE); 332 } 333 334 /* PRBS Error Count and Lock Lost (bit 31 in lock lost) */ 335 err_code_t merlin16_pcieg3_prbs_err_count_ll(srds_access_t *sa__, uint32_t *prbs_err_cnt) { 336 uint16_t rddata; 337 338 if(!prbs_err_cnt) { 339 return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT)); 340 } 341 ESTM(rddata = REG_RD_TLB_RX_PRBS_CHK_ERR_CNT_MSB_STATUS()); 342 *prbs_err_cnt = ((uint32_t) rddata)<<16; 343 ESTM(*prbs_err_cnt = (*prbs_err_cnt | rd_prbs_chk_err_cnt_lsb())); 344 return (ERR_CODE_NONE); 345 } 346 347 /* PRBS Error Count State */ 348 err_code_t merlin16_pcieg3_prbs_err_count_state(srds_access_t *sa__, uint32_t *prbs_err_cnt, uint8_t *lock_lost) { 349 if(!prbs_err_cnt || !lock_lost) { 350 return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT)); 351 } 352 EFUN(merlin16_pcieg3_prbs_err_count_ll(sa__, prbs_err_cnt)); 353 *lock_lost = (*prbs_err_cnt >> 31); 354 *prbs_err_cnt = (*prbs_err_cnt & 0x7FFFFFFF); 355 return (ERR_CODE_NONE); 356 } 357 358 err_code_t merlin16_pcieg3_display_detailed_prbs_state_hdr(void) { 359 EFUN_PRINTF(("\nPRBS DETAILED DISPLAY :\n")); 360 361 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")); 362 EFUN_PRINTF((" BER\n")); 363 return (ERR_CODE_NONE); 364 } 365 366 const char* merlin16_pcieg3_e2s_prbs_mode_enum[8] = { 367 " PRBS_7", 368 " PRBS_9", 369 "PRBS_11", 370 "PRBS_15", 371 "PRBS_23", 372 "PRBS_31", 373 "PRBS_58", 374 " ERR " 375 }; 376 377 err_code_t merlin16_pcieg3_display_detailed_prbs_state(srds_access_t *sa__) { 378 uint32_t err_cnt = 0; 379 uint8_t lock_lost = 0; 380 uint8_t enabled; 381 382 ESTM_PRINTF((" %d ",merlin16_pcieg3_get_lane(sa__))); 383 384 ESTM(enabled = rd_prbs_gen_en()); 385 if(enabled) { 386 enum srds_prbs_polynomial_enum prbs_poly_mode = PRBS_7; 387 uint8_t prbs_inv = 0; 388 char *prbs_string; 389 EFUN(merlin16_pcieg3_get_tx_prbs_config(sa__, &prbs_poly_mode, &prbs_inv)); 390 prbs_string = (char *)merlin16_pcieg3_e2s_prbs_mode_enum[prbs_poly_mode]; 391 ESTM_PRINTF(("%s",prbs_string)); 392 ESTM_PRINTF((" %1d ",prbs_inv)); 393 } else { 394 EFUN_PRINTF((" OFF ")); 395 ESTM_PRINTF((" - ")); 396 } 397 ESTM_PRINTF((" %1d ",rd_tx_pmd_dp_invert())); 398 399 ESTM(enabled = rd_prbs_chk_en()); 400 if(enabled) { 401 enum srds_prbs_polynomial_enum prbs_poly_mode = PRBS_7; 402 enum srds_prbs_checker_mode_enum prbs_checker_mode; 403 uint8_t prbs_inv = 0; 404 char *prbs_string; 405 EFUN(merlin16_pcieg3_get_rx_prbs_config(sa__, &prbs_poly_mode, &prbs_checker_mode, &prbs_inv)); 406 prbs_string = (char *)merlin16_pcieg3_e2s_prbs_mode_enum[prbs_poly_mode]; 407 ESTM_PRINTF((" %s",prbs_string)); 408 ESTM_PRINTF((" %1d ",prbs_inv)); 409 } else { 410 EFUN_PRINTF((" OFF ")); 411 ESTM_PRINTF((" - ")); 412 } 413 414 ESTM_PRINTF((" %1d ",rd_rx_pmd_dp_invert())); 415 ESTM_PRINTF((" %d ",rd_prbs_chk_lock())); 416 EFUN(merlin16_pcieg3_prbs_err_count_state(sa__,&err_cnt,&lock_lost)); 417 EFUN_PRINTF((" %d %010d ",lock_lost,err_cnt)); 418 ESTM_PRINTF((" %4d ",rd_prbs_chk_burst_err_cnt())); 419 EFUN(merlin16_pcieg3_INTERNAL_display_BER(sa__,100)); 420 EFUN_PRINTF(("\n")); 421 422 return (ERR_CODE_NONE); 423 } 424 425