]> git.karo-electronics.de Git - karo-tx-uboot.git/blobdiff - drivers/ddr/altera/sequencer.c
ddr: altera: Clean up of delay_for_n_mem_clocks() part 2
[karo-tx-uboot.git] / drivers / ddr / altera / sequencer.c
index 9cf2a1ad686d17480d4dc65268236c84a7d53bcd..25de209b5d15841f0772aa0f47ea02789a9b171c 100644 (file)
@@ -80,10 +80,6 @@ struct gbl_type *gbl;
 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)
 {
@@ -762,40 +758,41 @@ static void set_jump_as_return(void)
  * 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;
        }
 
        /*
@@ -815,7 +812,7 @@ static void delay_for_n_mem_clocks(const uint32_t clocks)
         * 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);
 
@@ -1022,20 +1019,234 @@ static void rw_mgr_mem_initialize(void)
                             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
@@ -2579,308 +2790,95 @@ cal_done_ok:
        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;
 }
 
 /**
@@ -2967,7 +2965,12 @@ static void search_window(const int search_dm,
 }
 
 /*
- * 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
@@ -3470,7 +3473,7 @@ static uint32_t mem_calibrate(void)
                                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;