struct param_type *param;
uint32_t curr_shadow_reg;
-static uint32_t rw_mgr_mem_calibrate_write_test(uint32_t rank_bgn,
- uint32_t write_group, uint32_t use_dm,
- uint32_t all_correct, uint32_t *bit_chk, uint32_t all_ranks);
-
static void set_failing_group_stage(uint32_t group, uint32_t stage,
uint32_t substage)
{
* should always use constants as argument to ensure all computations are
* performed at compile time
*/
-static void delay_for_n_mem_clocks(const uint32_t clocks)
+static void delay_for_n_mem_clocks(const u32 clocks)
{
- uint32_t afi_clocks;
- uint8_t inner = 0;
- uint8_t outer = 0;
- uint16_t c_loop = 0;
+ u32 afi_clocks;
+ u16 c_loop = 0;
+ u8 inner = 0;
+ u8 outer = 0;
debug("%s:%d: clocks=%u ... start\n", __func__, __LINE__, clocks);
-
- afi_clocks = (clocks + AFI_RATE_RATIO-1) / AFI_RATE_RATIO;
- /* scale (rounding up) to get afi clocks */
+ /* Scale (rounding up) to get afi clocks. */
+ afi_clocks = DIV_ROUND_UP(clocks, AFI_RATE_RATIO);
+ if (afi_clocks) /* Temporary underflow protection */
+ afi_clocks--;
/*
- * Note, we don't bother accounting for being off a little bit
- * because of a few extra instructions in outer loops
- * Note, the loops have a test at the end, and do the test before
- * the decrement, and so always perform the loop
+ * Note, we don't bother accounting for being off a little
+ * bit because of a few extra instructions in outer loops.
+ * Note, the loops have a test at the end, and do the test
+ * before the decrement, and so always perform the loop
* 1 time more than the counter value
*/
if (afi_clocks == 0) {
;
- } else if (afi_clocks <= 0x100) {
- inner = afi_clocks-1;
+ } else if (afi_clocks < 0x100) {
+ inner = afi_clocks;
outer = 0;
c_loop = 0;
- } else if (afi_clocks <= 0x10000) {
+ } else if (afi_clocks < 0x10000) {
inner = 0xff;
- outer = (afi_clocks-1) >> 8;
+ outer = afi_clocks >> 8;
c_loop = 0;
- } else {
+ } else { /* >= 0x10000 */
inner = 0xff;
outer = 0xff;
- c_loop = (afi_clocks-1) >> 16;
+ c_loop = afi_clocks >> 16;
}
/*
* and sequencer rom and keeps the delays more accurate and reduces
* overhead
*/
- if (afi_clocks <= 0x100) {
+ if (afi_clocks < 0x100) {
writel(SKIP_DELAY_LOOP_VALUE_OR_ZERO(inner),
&sdr_rw_load_mgr_regs->load_cntr1);
0);
}
-/*
- * At the end of calibration we have to program the user settings in, and
- * USER hand off the memory to the user.
+/**
+ * rw_mgr_mem_handoff() - Hand off the memory to user
+ *
+ * At the end of calibration we have to program the user settings in
+ * and hand off the memory to the user.
*/
static void rw_mgr_mem_handoff(void)
{
rw_mgr_mem_load_user(RW_MGR_MRS0_USER_MIRR, RW_MGR_MRS0_USER, 1);
/*
- * USER need to wait tMOD (12CK or 15ns) time before issuing
- * other commands, but we will have plenty of NIOS cycles before
- * actual handoff so its okay.
+ * Need to wait tMOD (12CK or 15ns) time before issuing other
+ * commands, but we will have plenty of NIOS cycles before actual
+ * handoff so its okay.
*/
}
+/**
+ * rw_mgr_mem_calibrate_write_test_issue() - Issue write test command
+ * @group: Write Group
+ * @use_dm: Use DM
+ *
+ * Issue write test command. Two variants are provided, one that just tests
+ * a write pattern and another that tests datamask functionality.
+ */
+static void rw_mgr_mem_calibrate_write_test_issue(u32 group,
+ u32 test_dm)
+{
+ const u32 quick_write_mode =
+ (STATIC_CALIB_STEPS & CALIB_SKIP_WRITES) &&
+ ENABLE_SUPER_QUICK_CALIBRATION;
+ u32 mcc_instruction;
+ u32 rw_wl_nop_cycles;
+
+ /*
+ * Set counter and jump addresses for the right
+ * number of NOP cycles.
+ * The number of supported NOP cycles can range from -1 to infinity
+ * Three different cases are handled:
+ *
+ * 1. For a number of NOP cycles greater than 0, the RW Mgr looping
+ * mechanism will be used to insert the right number of NOPs
+ *
+ * 2. For a number of NOP cycles equals to 0, the micro-instruction
+ * issuing the write command will jump straight to the
+ * micro-instruction that turns on DQS (for DDRx), or outputs write
+ * data (for RLD), skipping
+ * the NOP micro-instruction all together
+ *
+ * 3. A number of NOP cycles equal to -1 indicates that DQS must be
+ * turned on in the same micro-instruction that issues the write
+ * command. Then we need
+ * to directly jump to the micro-instruction that sends out the data
+ *
+ * NOTE: Implementing this mechanism uses 2 RW Mgr jump-counters
+ * (2 and 3). One jump-counter (0) is used to perform multiple
+ * write-read operations.
+ * one counter left to issue this command in "multiple-group" mode
+ */
+
+ rw_wl_nop_cycles = gbl->rw_wl_nop_cycles;
+
+ if (rw_wl_nop_cycles == -1) {
+ /*
+ * CNTR 2 - We want to execute the special write operation that
+ * turns on DQS right away and then skip directly to the
+ * instruction that sends out the data. We set the counter to a
+ * large number so that the jump is always taken.
+ */
+ writel(0xFF, &sdr_rw_load_mgr_regs->load_cntr2);
+
+ /* CNTR 3 - Not used */
+ if (test_dm) {
+ mcc_instruction = RW_MGR_LFSR_WR_RD_DM_BANK_0_WL_1;
+ writel(RW_MGR_LFSR_WR_RD_DM_BANK_0_DATA,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add2);
+ writel(RW_MGR_LFSR_WR_RD_DM_BANK_0_NOP,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add3);
+ } else {
+ mcc_instruction = RW_MGR_LFSR_WR_RD_BANK_0_WL_1;
+ writel(RW_MGR_LFSR_WR_RD_BANK_0_DATA,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add2);
+ writel(RW_MGR_LFSR_WR_RD_BANK_0_NOP,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add3);
+ }
+ } else if (rw_wl_nop_cycles == 0) {
+ /*
+ * CNTR 2 - We want to skip the NOP operation and go straight
+ * to the DQS enable instruction. We set the counter to a large
+ * number so that the jump is always taken.
+ */
+ writel(0xFF, &sdr_rw_load_mgr_regs->load_cntr2);
+
+ /* CNTR 3 - Not used */
+ if (test_dm) {
+ mcc_instruction = RW_MGR_LFSR_WR_RD_DM_BANK_0;
+ writel(RW_MGR_LFSR_WR_RD_DM_BANK_0_DQS,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add2);
+ } else {
+ mcc_instruction = RW_MGR_LFSR_WR_RD_BANK_0;
+ writel(RW_MGR_LFSR_WR_RD_BANK_0_DQS,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add2);
+ }
+ } else {
+ /*
+ * CNTR 2 - In this case we want to execute the next instruction
+ * and NOT take the jump. So we set the counter to 0. The jump
+ * address doesn't count.
+ */
+ writel(0x0, &sdr_rw_load_mgr_regs->load_cntr2);
+ writel(0x0, &sdr_rw_load_jump_mgr_regs->load_jump_add2);
+
+ /*
+ * CNTR 3 - Set the nop counter to the number of cycles we
+ * need to loop for, minus 1.
+ */
+ writel(rw_wl_nop_cycles - 1, &sdr_rw_load_mgr_regs->load_cntr3);
+ if (test_dm) {
+ mcc_instruction = RW_MGR_LFSR_WR_RD_DM_BANK_0;
+ writel(RW_MGR_LFSR_WR_RD_DM_BANK_0_NOP,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add3);
+ } else {
+ mcc_instruction = RW_MGR_LFSR_WR_RD_BANK_0;
+ writel(RW_MGR_LFSR_WR_RD_BANK_0_NOP,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add3);
+ }
+ }
+
+ writel(0, SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RESET_READ_DATAPATH_OFFSET);
+
+ if (quick_write_mode)
+ writel(0x08, &sdr_rw_load_mgr_regs->load_cntr0);
+ else
+ writel(0x40, &sdr_rw_load_mgr_regs->load_cntr0);
+
+ writel(mcc_instruction, &sdr_rw_load_jump_mgr_regs->load_jump_add0);
+
+ /*
+ * CNTR 1 - This is used to ensure enough time elapses
+ * for read data to come back.
+ */
+ writel(0x30, &sdr_rw_load_mgr_regs->load_cntr1);
+
+ if (test_dm) {
+ writel(RW_MGR_LFSR_WR_RD_DM_BANK_0_WAIT,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add1);
+ } else {
+ writel(RW_MGR_LFSR_WR_RD_BANK_0_WAIT,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add1);
+ }
+
+ writel(mcc_instruction, (SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RUN_SINGLE_GROUP_OFFSET) +
+ (group << 2));
+}
+
+/**
+ * rw_mgr_mem_calibrate_write_test() - Test writes, check for single/multiple pass
+ * @rank_bgn: Rank number
+ * @write_group: Write Group
+ * @use_dm: Use DM
+ * @all_correct: All bits must be correct in the mask
+ * @bit_chk: Resulting bit mask after the test
+ * @all_ranks: Test all ranks
+ *
+ * Test writes, can check for a single bit pass or multiple bit pass.
+ */
+static int
+rw_mgr_mem_calibrate_write_test(const u32 rank_bgn, const u32 write_group,
+ const u32 use_dm, const u32 all_correct,
+ u32 *bit_chk, const u32 all_ranks)
+{
+ const u32 rank_end = all_ranks ?
+ RW_MGR_MEM_NUMBER_OF_RANKS :
+ (rank_bgn + NUM_RANKS_PER_SHADOW_REG);
+ const u32 shift_ratio = RW_MGR_MEM_DQ_PER_WRITE_DQS /
+ RW_MGR_MEM_VIRTUAL_GROUPS_PER_WRITE_DQS;
+ const u32 correct_mask_vg = param->write_correct_mask_vg;
+
+ u32 tmp_bit_chk, base_rw_mgr;
+ int vg, r;
+
+ *bit_chk = param->write_correct_mask;
+
+ for (r = rank_bgn; r < rank_end; r++) {
+ /* Request to skip the rank */
+ if (param->skip_ranks[r])
+ continue;
+
+ /* Set rank */
+ set_rank_and_odt_mask(r, RW_MGR_ODT_MODE_READ_WRITE);
+
+ tmp_bit_chk = 0;
+ for (vg = RW_MGR_MEM_VIRTUAL_GROUPS_PER_WRITE_DQS - 1;
+ vg >= 0; vg--) {
+ /* Reset the FIFOs to get pointers to known state. */
+ writel(0, &phy_mgr_cmd->fifo_reset);
+
+ rw_mgr_mem_calibrate_write_test_issue(
+ write_group *
+ RW_MGR_MEM_VIRTUAL_GROUPS_PER_WRITE_DQS + vg,
+ use_dm);
+
+ base_rw_mgr = readl(SDR_PHYGRP_RWMGRGRP_ADDRESS);
+ tmp_bit_chk <<= shift_ratio;
+ tmp_bit_chk |= (correct_mask_vg & ~(base_rw_mgr));
+ }
+
+ *bit_chk &= tmp_bit_chk;
+ }
+
+ set_rank_and_odt_mask(0, RW_MGR_ODT_MODE_OFF);
+ if (all_correct) {
+ debug_cond(DLEVEL == 2,
+ "write_test(%u,%u,ALL) : %u == %u => %i\n",
+ write_group, use_dm, *bit_chk,
+ param->write_correct_mask,
+ *bit_chk == param->write_correct_mask);
+ return *bit_chk == param->write_correct_mask;
+ } else {
+ set_rank_and_odt_mask(0, RW_MGR_ODT_MODE_OFF);
+ debug_cond(DLEVEL == 2,
+ "write_test(%u,%u,ONE) : %u != %i => %i\n",
+ write_group, use_dm, *bit_chk, 0, *bit_chk != 0);
+ return *bit_chk != 0x00;
+ }
+}
+
/**
* rw_mgr_mem_calibrate_read_test_patterns() - Read back test patterns
* @rank_bgn: Rank number
return 1;
}
-/* VFIFO Calibration -- Read Deskew Calibration after write deskew */
-static uint32_t rw_mgr_mem_calibrate_vfifo_end(uint32_t read_group,
- uint32_t test_bgn)
+/**
+ * rw_mgr_mem_calibrate_vfifo_end() - DQ/DQS Centering.
+ * @rw_group: Read/Write Group
+ * @test_bgn: Rank at which the test begins
+ *
+ * Stage 3: DQ/DQS Centering.
+ *
+ * This function implements UniPHY calibration Stage 3, as explained in
+ * detail in Altera EMI_RM 2015.05.04 , "UniPHY Calibration Stages".
+ */
+static int rw_mgr_mem_calibrate_vfifo_end(const u32 rw_group,
+ const u32 test_bgn)
{
- uint32_t rank_bgn, sr;
- uint32_t grp_calibrated;
- uint32_t write_group;
-
- debug("%s:%d %u %u", __func__, __LINE__, read_group, test_bgn);
+ int ret;
- /* update info for sims */
+ debug("%s:%d %u %u", __func__, __LINE__, rw_group, test_bgn);
+ /* Update info for sims. */
+ reg_file_set_group(rw_group);
reg_file_set_stage(CAL_STAGE_VFIFO_AFTER_WRITES);
reg_file_set_sub_stage(CAL_SUBSTAGE_VFIFO_CENTER);
- write_group = read_group;
-
- /* update info for sims */
- reg_file_set_group(read_group);
-
- grp_calibrated = 1;
- /* Read per-bit deskew can be done on a per shadow register basis */
- for (rank_bgn = 0, sr = 0; rank_bgn < RW_MGR_MEM_NUMBER_OF_RANKS;
- rank_bgn += NUM_RANKS_PER_SHADOW_REG, ++sr) {
- /* Determine if this set of ranks should be skipped entirely */
- if (!param->skip_shadow_regs[sr]) {
- /* This is the last calibration round, update FOM here */
- if (rw_mgr_mem_calibrate_vfifo_center(rank_bgn,
- read_group,
- test_bgn, 0,
- 1)) {
- grp_calibrated = 0;
- }
- }
- }
-
-
- if (grp_calibrated == 0) {
- set_failing_group_stage(write_group,
+ ret = rw_mgr_mem_calibrate_dq_dqs_centering(rw_group, test_bgn, 0, 1);
+ if (ret)
+ set_failing_group_stage(rw_group,
CAL_STAGE_VFIFO_AFTER_WRITES,
CAL_SUBSTAGE_VFIFO_CENTER);
- return 0;
- }
-
- return 1;
+ return ret;
}
-/* Calibrate LFIFO to find smallest read latency */
+/**
+ * rw_mgr_mem_calibrate_lfifo() - Minimize latency
+ *
+ * Stage 4: Minimize latency.
+ *
+ * This function implements UniPHY calibration Stage 4, as explained in
+ * detail in Altera EMI_RM 2015.05.04 , "UniPHY Calibration Stages".
+ * Calibrate LFIFO to find smallest read latency.
+ */
static uint32_t rw_mgr_mem_calibrate_lfifo(void)
{
- uint32_t found_one;
+ int found_one = 0;
debug("%s:%d\n", __func__, __LINE__);
- /* update info for sims */
+ /* Update info for sims. */
reg_file_set_stage(CAL_STAGE_LFIFO);
reg_file_set_sub_stage(CAL_SUBSTAGE_READ_LATENCY);
/* Load up the patterns used by read calibration for all ranks */
rw_mgr_mem_calibrate_read_load_patterns(0, 1);
- found_one = 0;
do {
writel(gbl->curr_read_lat, &phy_mgr_cfg->phy_rlat);
debug_cond(DLEVEL == 2, "%s:%d lfifo: read_lat=%u",
__func__, __LINE__, gbl->curr_read_lat);
- if (!rw_mgr_mem_calibrate_read_test_all_ranks(0,
- NUM_READ_TESTS,
- PASS_ALL_BITS,
- 1)) {
+ if (!rw_mgr_mem_calibrate_read_test_all_ranks(0, NUM_READ_TESTS,
+ PASS_ALL_BITS, 1))
break;
- }
found_one = 1;
- /* reduce read latency and see if things are working */
- /* correctly */
+ /*
+ * Reduce read latency and see if things are
+ * working correctly.
+ */
gbl->curr_read_lat--;
} while (gbl->curr_read_lat > 0);
- /* reset the fifos to get pointers to known state */
-
+ /* Reset the fifos to get pointers to known state. */
writel(0, &phy_mgr_cmd->fifo_reset);
if (found_one) {
- /* add a fudge factor to the read latency that was determined */
+ /* Add a fudge factor to the read latency that was determined */
gbl->curr_read_lat += 2;
writel(gbl->curr_read_lat, &phy_mgr_cfg->phy_rlat);
- debug_cond(DLEVEL == 2, "%s:%d lfifo: success: using \
- read_lat=%u\n", __func__, __LINE__,
- gbl->curr_read_lat);
- return 1;
+ debug_cond(DLEVEL == 2,
+ "%s:%d lfifo: success: using read_lat=%u\n",
+ __func__, __LINE__, gbl->curr_read_lat);
} else {
set_failing_group_stage(0xff, CAL_STAGE_LFIFO,
CAL_SUBSTAGE_READ_LATENCY);
- debug_cond(DLEVEL == 2, "%s:%d lfifo: failed at initial \
- read_lat=%u\n", __func__, __LINE__,
- gbl->curr_read_lat);
- return 0;
- }
-}
-
-/*
- * issue write test command.
- * two variants are provided. one that just tests a write pattern and
- * another that tests datamask functionality.
- */
-static void rw_mgr_mem_calibrate_write_test_issue(uint32_t group,
- uint32_t test_dm)
-{
- uint32_t mcc_instruction;
- uint32_t quick_write_mode = (((STATIC_CALIB_STEPS) & CALIB_SKIP_WRITES) &&
- ENABLE_SUPER_QUICK_CALIBRATION);
- uint32_t rw_wl_nop_cycles;
- uint32_t addr;
-
- /*
- * Set counter and jump addresses for the right
- * number of NOP cycles.
- * The number of supported NOP cycles can range from -1 to infinity
- * Three different cases are handled:
- *
- * 1. For a number of NOP cycles greater than 0, the RW Mgr looping
- * mechanism will be used to insert the right number of NOPs
- *
- * 2. For a number of NOP cycles equals to 0, the micro-instruction
- * issuing the write command will jump straight to the
- * micro-instruction that turns on DQS (for DDRx), or outputs write
- * data (for RLD), skipping
- * the NOP micro-instruction all together
- *
- * 3. A number of NOP cycles equal to -1 indicates that DQS must be
- * turned on in the same micro-instruction that issues the write
- * command. Then we need
- * to directly jump to the micro-instruction that sends out the data
- *
- * NOTE: Implementing this mechanism uses 2 RW Mgr jump-counters
- * (2 and 3). One jump-counter (0) is used to perform multiple
- * write-read operations.
- * one counter left to issue this command in "multiple-group" mode
- */
-
- rw_wl_nop_cycles = gbl->rw_wl_nop_cycles;
-
- if (rw_wl_nop_cycles == -1) {
- /*
- * CNTR 2 - We want to execute the special write operation that
- * turns on DQS right away and then skip directly to the
- * instruction that sends out the data. We set the counter to a
- * large number so that the jump is always taken.
- */
- writel(0xFF, &sdr_rw_load_mgr_regs->load_cntr2);
-
- /* CNTR 3 - Not used */
- if (test_dm) {
- mcc_instruction = RW_MGR_LFSR_WR_RD_DM_BANK_0_WL_1;
- writel(RW_MGR_LFSR_WR_RD_DM_BANK_0_DATA,
- &sdr_rw_load_jump_mgr_regs->load_jump_add2);
- writel(RW_MGR_LFSR_WR_RD_DM_BANK_0_NOP,
- &sdr_rw_load_jump_mgr_regs->load_jump_add3);
- } else {
- mcc_instruction = RW_MGR_LFSR_WR_RD_BANK_0_WL_1;
- writel(RW_MGR_LFSR_WR_RD_BANK_0_DATA,
- &sdr_rw_load_jump_mgr_regs->load_jump_add2);
- writel(RW_MGR_LFSR_WR_RD_BANK_0_NOP,
- &sdr_rw_load_jump_mgr_regs->load_jump_add3);
- }
- } else if (rw_wl_nop_cycles == 0) {
- /*
- * CNTR 2 - We want to skip the NOP operation and go straight
- * to the DQS enable instruction. We set the counter to a large
- * number so that the jump is always taken.
- */
- writel(0xFF, &sdr_rw_load_mgr_regs->load_cntr2);
-
- /* CNTR 3 - Not used */
- if (test_dm) {
- mcc_instruction = RW_MGR_LFSR_WR_RD_DM_BANK_0;
- writel(RW_MGR_LFSR_WR_RD_DM_BANK_0_DQS,
- &sdr_rw_load_jump_mgr_regs->load_jump_add2);
- } else {
- mcc_instruction = RW_MGR_LFSR_WR_RD_BANK_0;
- writel(RW_MGR_LFSR_WR_RD_BANK_0_DQS,
- &sdr_rw_load_jump_mgr_regs->load_jump_add2);
- }
- } else {
- /*
- * CNTR 2 - In this case we want to execute the next instruction
- * and NOT take the jump. So we set the counter to 0. The jump
- * address doesn't count.
- */
- writel(0x0, &sdr_rw_load_mgr_regs->load_cntr2);
- writel(0x0, &sdr_rw_load_jump_mgr_regs->load_jump_add2);
-
- /*
- * CNTR 3 - Set the nop counter to the number of cycles we
- * need to loop for, minus 1.
- */
- writel(rw_wl_nop_cycles - 1, &sdr_rw_load_mgr_regs->load_cntr3);
- if (test_dm) {
- mcc_instruction = RW_MGR_LFSR_WR_RD_DM_BANK_0;
- writel(RW_MGR_LFSR_WR_RD_DM_BANK_0_NOP,
- &sdr_rw_load_jump_mgr_regs->load_jump_add3);
- } else {
- mcc_instruction = RW_MGR_LFSR_WR_RD_BANK_0;
- writel(RW_MGR_LFSR_WR_RD_BANK_0_NOP,
- &sdr_rw_load_jump_mgr_regs->load_jump_add3);
- }
- }
-
- writel(0, SDR_PHYGRP_RWMGRGRP_ADDRESS |
- RW_MGR_RESET_READ_DATAPATH_OFFSET);
-
- if (quick_write_mode)
- writel(0x08, &sdr_rw_load_mgr_regs->load_cntr0);
- else
- writel(0x40, &sdr_rw_load_mgr_regs->load_cntr0);
-
- writel(mcc_instruction, &sdr_rw_load_jump_mgr_regs->load_jump_add0);
-
- /*
- * CNTR 1 - This is used to ensure enough time elapses
- * for read data to come back.
- */
- writel(0x30, &sdr_rw_load_mgr_regs->load_cntr1);
-
- if (test_dm) {
- writel(RW_MGR_LFSR_WR_RD_DM_BANK_0_WAIT,
- &sdr_rw_load_jump_mgr_regs->load_jump_add1);
- } else {
- writel(RW_MGR_LFSR_WR_RD_BANK_0_WAIT,
- &sdr_rw_load_jump_mgr_regs->load_jump_add1);
- }
-
- addr = SDR_PHYGRP_RWMGRGRP_ADDRESS | RW_MGR_RUN_SINGLE_GROUP_OFFSET;
- writel(mcc_instruction, addr + (group << 2));
-}
-
-/* Test writes, can check for a single bit pass or multiple bit pass */
-static uint32_t rw_mgr_mem_calibrate_write_test(uint32_t rank_bgn,
- uint32_t write_group, uint32_t use_dm, uint32_t all_correct,
- uint32_t *bit_chk, uint32_t all_ranks)
-{
- uint32_t r;
- uint32_t correct_mask_vg;
- uint32_t tmp_bit_chk;
- uint32_t vg;
- uint32_t rank_end = all_ranks ? RW_MGR_MEM_NUMBER_OF_RANKS :
- (rank_bgn + NUM_RANKS_PER_SHADOW_REG);
- uint32_t addr_rw_mgr;
- uint32_t base_rw_mgr;
-
- *bit_chk = param->write_correct_mask;
- correct_mask_vg = param->write_correct_mask_vg;
-
- for (r = rank_bgn; r < rank_end; r++) {
- if (param->skip_ranks[r]) {
- /* request to skip the rank */
- continue;
- }
-
- /* set rank */
- set_rank_and_odt_mask(r, RW_MGR_ODT_MODE_READ_WRITE);
-
- tmp_bit_chk = 0;
- addr_rw_mgr = SDR_PHYGRP_RWMGRGRP_ADDRESS;
- for (vg = RW_MGR_MEM_VIRTUAL_GROUPS_PER_WRITE_DQS-1; ; vg--) {
- /* reset the fifos to get pointers to known state */
- writel(0, &phy_mgr_cmd->fifo_reset);
-
- tmp_bit_chk = tmp_bit_chk <<
- (RW_MGR_MEM_DQ_PER_WRITE_DQS /
- RW_MGR_MEM_VIRTUAL_GROUPS_PER_WRITE_DQS);
- rw_mgr_mem_calibrate_write_test_issue(write_group *
- RW_MGR_MEM_VIRTUAL_GROUPS_PER_WRITE_DQS+vg,
- use_dm);
-
- base_rw_mgr = readl(addr_rw_mgr);
- tmp_bit_chk = tmp_bit_chk | (correct_mask_vg & ~(base_rw_mgr));
- if (vg == 0)
- break;
- }
- *bit_chk &= tmp_bit_chk;
+ debug_cond(DLEVEL == 2,
+ "%s:%d lfifo: failed at initial read_lat=%u\n",
+ __func__, __LINE__, gbl->curr_read_lat);
}
- if (all_correct) {
- set_rank_and_odt_mask(0, RW_MGR_ODT_MODE_OFF);
- debug_cond(DLEVEL == 2, "write_test(%u,%u,ALL) : %u == \
- %u => %lu", write_group, use_dm,
- *bit_chk, param->write_correct_mask,
- (long unsigned int)(*bit_chk ==
- param->write_correct_mask));
- return *bit_chk == param->write_correct_mask;
- } else {
- set_rank_and_odt_mask(0, RW_MGR_ODT_MODE_OFF);
- debug_cond(DLEVEL == 2, "write_test(%u,%u,ONE) : %u != ",
- write_group, use_dm, *bit_chk);
- debug_cond(DLEVEL == 2, "%lu" " => %lu", (long unsigned int)0,
- (long unsigned int)(*bit_chk != 0));
- return *bit_chk != 0x00;
- }
+ return found_one;
}
/**
}
/*
- * center all windows. do per-bit-deskew to possibly increase size of
+ * rw_mgr_mem_calibrate_writes_center() - Center all windows
+ * @rank_bgn: Rank number
+ * @write_group: Write group
+ * @test_bgn: Rank at which the test begins
+ *
+ * Center all windows. Do per-bit-deskew to possibly increase size of
* certain windows.
*/
static int
if (STATIC_CALIB_STEPS & CALIB_SKIP_WRITES)
continue;
- if (rw_mgr_mem_calibrate_vfifo_end(read_group,
+ if (!rw_mgr_mem_calibrate_vfifo_end(read_group,
read_test_bgn))
continue;