int do_qlm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { int num_qlm; int qlm; int c_arg; /* Make sure we got the correct number of arguments */ if (((argc - 2) % 3) != 0) { printf("Invalid number of arguments %d\n", argc); usage(argv); return -1; } num_qlm = cvmx_qlm_get_num(); qlm = simple_strtoul(argv[1], NULL, 0); if ((qlm < 0) || (qlm >= num_qlm)) { printf("Invalid qlm number\n"); return -1; } if (argc >= 5) { int lane; uint64_t value; int field_count; int num_fields = (argc - 2) / 3; c_arg = 2; for (field_count = 0; field_count < num_fields; field_count++) { char name[30]; if (!strcmp(argv[c_arg], "all")) lane = -1; else { lane = (int)simple_strtol(argv[c_arg], NULL, 0); if (lane >= cvmx_qlm_get_lanes(qlm)) { printf("Invalid lane passed\n"); return -1; } } strcpy(name, argv[c_arg + 1]); value = convert_number(argv[c_arg + 2]); cvmx_qlm_jtag_set(qlm, lane, name, value); /* Assert serdes_tx_byp to force the new settings to override the QLM default. */ if (strncmp(name, "biasdrv_", 8) == 0 || strncmp(name, "tcoeff_", 7) == 0) cvmx_qlm_jtag_set(qlm, lane, "serdes_tx_byp", 1); c_arg += 3; if (lane == -1) break; } } else cvmx_qlm_display_registers(qlm); return 0; }
/** * Initialize the QLM layer */ void cvmx_qlm_init(void) { int qlm; int qlm_jtag_length; char *qlm_jtag_name = "cvmx_qlm_jtag"; int qlm_jtag_size = CVMX_QLM_JTAG_UINT32 * 8 * 4; static uint64_t qlm_base = 0; const cvmx_bootmem_named_block_desc_t *desc; #ifndef CVMX_BUILD_FOR_LINUX_HOST /* Skip actual JTAG accesses on simulator */ if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) return; #endif qlm_jtag_length = cvmx_qlm_jtag_get_length(); if (4 * qlm_jtag_length > (int)sizeof(__cvmx_qlm_jtag_xor_ref[0]) * 8) { cvmx_dprintf("ERROR: cvmx_qlm_init: JTAG chain larger than XOR ref size\n"); return; } /* No need to initialize the initial JTAG state if cvmx_qlm_jtag named block is already created. */ if ((desc = cvmx_bootmem_find_named_block(qlm_jtag_name)) != NULL) { #ifdef CVMX_BUILD_FOR_LINUX_HOST char buffer[qlm_jtag_size]; octeon_remote_read_mem(buffer, desc->base_addr, qlm_jtag_size); memcpy(__cvmx_qlm_jtag_xor_ref, buffer, qlm_jtag_size); #else __cvmx_qlm_jtag_xor_ref = cvmx_phys_to_ptr(desc->base_addr); #endif /* Initialize the internal JTAG */ cvmx_helper_qlm_jtag_init(); return; } /* Create named block to store the initial JTAG state. */ qlm_base = cvmx_bootmem_phy_named_block_alloc(qlm_jtag_size, 0, 0, 128, qlm_jtag_name, CVMX_BOOTMEM_FLAG_END_ALLOC); if (qlm_base == -1ull) { cvmx_dprintf("ERROR: cvmx_qlm_init: Error in creating %s named block\n", qlm_jtag_name); return; } #ifndef CVMX_BUILD_FOR_LINUX_HOST __cvmx_qlm_jtag_xor_ref = cvmx_phys_to_ptr(qlm_base); #endif memset(__cvmx_qlm_jtag_xor_ref, 0, qlm_jtag_size); /* Initialize the internal JTAG */ cvmx_helper_qlm_jtag_init(); /* Read the XOR defaults for the JTAG chain */ for (qlm=0; qlm<cvmx_qlm_get_num(); qlm++) { int i; /* Capture the reset defaults */ cvmx_helper_qlm_jtag_capture(qlm); /* Save the reset defaults. This will shift out too much data, but the extra zeros don't hurt anything */ for (i=0; i<CVMX_QLM_JTAG_UINT32; i++) __cvmx_qlm_jtag_xor_ref[qlm][i] = cvmx_helper_qlm_jtag_shift(qlm, 32, 0); } #ifdef CVMX_BUILD_FOR_LINUX_HOST /* Update the initial state for oct-remote utils. */ { char buffer[qlm_jtag_size]; memcpy(buffer, &__cvmx_qlm_jtag_xor_ref, qlm_jtag_size); octeon_remote_write_mem(qlm_base, buffer, qlm_jtag_size); } #endif /* Apply speed tweak as a workaround for errata G-16094. */ __cvmx_qlm_speed_tweak(); __cvmx_qlm_pcie_idle_dac_tweak(); }
/** * Errata G-16094: QLM Gen2 Equalizer Default Setting Change. * CN68XX pass 1.x and CN66XX pass 1.x QLM tweak. This function tweaks the * JTAG setting for a QLMs to run better at 5 and 6.25Ghz. */ void __cvmx_qlm_speed_tweak(void) { cvmx_mio_qlmx_cfg_t qlm_cfg; int num_qlms = cvmx_qlm_get_num(); int qlm; /* Workaround for Errata (G-16467) */ if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS2_X)) { for (qlm = 0; qlm < num_qlms; qlm++) { int ir50dac; /* This workaround only applies to QLMs running at 6.25Ghz */ if (cvmx_qlm_get_gbaud_mhz(qlm) == 6250) { #ifdef CVMX_QLM_DUMP_STATE cvmx_dprintf("%s:%d: QLM%d: Applying workaround for Errata G-16467\n", __func__, __LINE__, qlm); cvmx_qlm_display_registers(qlm); cvmx_dprintf("\n"); #endif cvmx_qlm_jtag_set(qlm, -1, "cfg_cdr_trunc", 0); /* Hold the QLM in reset */ cvmx_qlm_jtag_set(qlm, -1, "cfg_rst_n_set", 0); cvmx_qlm_jtag_set(qlm, -1, "cfg_rst_n_clr", 1); /* Forcfe TX to be idle */ cvmx_qlm_jtag_set(qlm, -1, "cfg_tx_idle_clr", 0); cvmx_qlm_jtag_set(qlm, -1, "cfg_tx_idle_set", 1); if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS2_0)) { ir50dac = cvmx_qlm_jtag_get(qlm, 0, "ir50dac"); while (++ir50dac <= 31) cvmx_qlm_jtag_set(qlm, -1, "ir50dac", ir50dac); } cvmx_qlm_jtag_set(qlm, -1, "div4_byp", 0); cvmx_qlm_jtag_set(qlm, -1, "clkf_byp", 16); cvmx_qlm_jtag_set(qlm, -1, "serdes_pll_byp", 1); cvmx_qlm_jtag_set(qlm, -1, "spdsel_byp", 1); #ifdef CVMX_QLM_DUMP_STATE cvmx_dprintf("%s:%d: QLM%d: Done applying workaround for Errata G-16467\n", __func__, __LINE__, qlm); cvmx_qlm_display_registers(qlm); cvmx_dprintf("\n\n"); #endif /* The QLM will be taken out of reset later when ILK/XAUI are initialized. */ } } #ifndef CVMX_BUILD_FOR_LINUX_HOST /* These QLM tuning parameters are specific to EBB6800 eval boards using Cavium QLM cables. These should be removed or tunned based on customer boards. */ if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBB6800) { for (qlm = 0; qlm < num_qlms; qlm++) { #ifdef CVMX_QLM_DUMP_STATE cvmx_dprintf("Setting tunning parameters for QLM%d\n", qlm); #endif cvmx_qlm_jtag_set(qlm, -1, "biasdrv_hs_ls_byp", 12); cvmx_qlm_jtag_set(qlm, -1, "biasdrv_hf_byp", 12); cvmx_qlm_jtag_set(qlm, -1, "biasdrv_lf_ls_byp", 12); cvmx_qlm_jtag_set(qlm, -1, "biasdrv_lf_byp", 12); cvmx_qlm_jtag_set(qlm, -1, "tcoeff_hf_byp", 15); cvmx_qlm_jtag_set(qlm, -1, "tcoeff_hf_ls_byp", 15); cvmx_qlm_jtag_set(qlm, -1, "tcoeff_lf_ls_byp", 15); cvmx_qlm_jtag_set(qlm, -1, "tcoeff_lf_byp", 15); cvmx_qlm_jtag_set(qlm, -1, "rx_cap_gen2", 0); cvmx_qlm_jtag_set(qlm, -1, "rx_eq_gen2", 11); cvmx_qlm_jtag_set(qlm, -1, "serdes_tx_byp", 1); } } else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_NIC68_4) { for (qlm = 0; qlm < num_qlms; qlm++) { #ifdef CVMX_QLM_DUMP_STATE cvmx_dprintf("Setting tunning parameters for QLM%d\n", qlm); #endif cvmx_qlm_jtag_set(qlm, -1, "biasdrv_hs_ls_byp", 30); cvmx_qlm_jtag_set(qlm, -1, "biasdrv_hf_byp", 30); cvmx_qlm_jtag_set(qlm, -1, "biasdrv_lf_ls_byp", 30); cvmx_qlm_jtag_set(qlm, -1, "biasdrv_lf_byp", 30); cvmx_qlm_jtag_set(qlm, -1, "tcoeff_hf_byp", 0); cvmx_qlm_jtag_set(qlm, -1, "tcoeff_hf_ls_byp", 0); cvmx_qlm_jtag_set(qlm, -1, "tcoeff_lf_ls_byp", 0); cvmx_qlm_jtag_set(qlm, -1, "tcoeff_lf_byp", 0); cvmx_qlm_jtag_set(qlm, -1, "rx_cap_gen2", 1); cvmx_qlm_jtag_set(qlm, -1, "rx_eq_gen2", 8); cvmx_qlm_jtag_set(qlm, -1, "serdes_tx_byp", 1); } } #endif } /* G-16094 QLM Gen2 Equalizer Default Setting Change */ else if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_X) || OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_X)) { /* Loop through the QLMs */ for (qlm = 0; qlm < num_qlms; qlm++) { /* Read the QLM speed */ qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm)); /* If the QLM is at 6.25Ghz or 5Ghz then program JTAG */ if ((qlm_cfg.s.qlm_spd == 5) || (qlm_cfg.s.qlm_spd == 12) || (qlm_cfg.s.qlm_spd == 0) || (qlm_cfg.s.qlm_spd == 6) || (qlm_cfg.s.qlm_spd == 11)) { cvmx_qlm_jtag_set(qlm, -1, "rx_cap_gen2", 0x1); cvmx_qlm_jtag_set(qlm, -1, "rx_eq_gen2", 0x8); } } } }