]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - drivers/ddr/altera/sequencer.c
ddr: altera: Clean up rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase() part 3
[people/ms/u-boot.git] / drivers / ddr / altera / sequencer.c
index 6fa07cf7cba69246b920eb8898f75bea19598a03..3d975f99fb76ce0ddf5e5bd082e7a2d837235f42 100644 (file)
@@ -1036,31 +1036,42 @@ static void rw_mgr_mem_handoff(void)
         */
 }
 
-/*
- * performs a guaranteed read on the patterns we are going to use during a
- * read test to ensure memory works
+/**
+ * rw_mgr_mem_calibrate_read_test_patterns() - Read back test patterns
+ * @rank_bgn:  Rank number
+ * @group:     Read/Write Group
+ * @all_ranks: Test all ranks
+ *
+ * Performs a guaranteed read on the patterns we are going to use during a
+ * read test to ensure memory works.
  */
-static uint32_t rw_mgr_mem_calibrate_read_test_patterns(uint32_t rank_bgn,
-       uint32_t group, uint32_t num_tries, uint32_t *bit_chk,
-       uint32_t all_ranks)
-{
-       uint32_t r, vg;
-       uint32_t correct_mask_vg;
-       uint32_t tmp_bit_chk;
-       uint32_t rank_end = all_ranks ? RW_MGR_MEM_NUMBER_OF_RANKS :
-               (rank_bgn + NUM_RANKS_PER_SHADOW_REG);
-       uint32_t addr;
-       uint32_t base_rw_mgr;
-
-       *bit_chk = param->read_correct_mask;
-       correct_mask_vg = param->read_correct_mask_vg;
+static int
+rw_mgr_mem_calibrate_read_test_patterns(const u32 rank_bgn, const u32 group,
+                                       const u32 all_ranks)
+{
+       const u32 addr = SDR_PHYGRP_RWMGRGRP_ADDRESS |
+                        RW_MGR_RUN_SINGLE_GROUP_OFFSET;
+       const u32 addr_offset =
+                        (group * RW_MGR_MEM_VIRTUAL_GROUPS_PER_READ_DQS) << 2;
+       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_READ_DQS /
+                               RW_MGR_MEM_VIRTUAL_GROUPS_PER_READ_DQS;
+       const u32 correct_mask_vg = param->read_correct_mask_vg;
+
+       u32 tmp_bit_chk, base_rw_mgr, bit_chk;
+       int vg, r;
+       int ret = 0;
+
+       bit_chk = param->read_correct_mask;
 
        for (r = rank_bgn; r < rank_end; r++) {
+               /* Request to skip the rank */
                if (param->skip_ranks[r])
-                       /* request to skip the rank */
                        continue;
 
-               /* set rank */
+               /* Set rank */
                set_rank_and_odt_mask(r, RW_MGR_ODT_MODE_READ_WRITE);
 
                /* Load up a constant bursts of read commands */
@@ -1073,56 +1084,55 @@ static uint32_t rw_mgr_mem_calibrate_read_test_patterns(uint32_t rank_bgn,
                        &sdr_rw_load_jump_mgr_regs->load_jump_add1);
 
                tmp_bit_chk = 0;
-               for (vg = RW_MGR_MEM_VIRTUAL_GROUPS_PER_READ_DQS-1; ; vg--) {
-                       /* reset the fifos to get pointers to known state */
-
+               for (vg = RW_MGR_MEM_VIRTUAL_GROUPS_PER_READ_DQS - 1;
+                    vg >= 0; vg--) {
+                       /* Reset the FIFOs to get pointers to known state. */
                        writel(0, &phy_mgr_cmd->fifo_reset);
                        writel(0, SDR_PHYGRP_RWMGRGRP_ADDRESS |
                                  RW_MGR_RESET_READ_DATAPATH_OFFSET);
-
-                       tmp_bit_chk = tmp_bit_chk << (RW_MGR_MEM_DQ_PER_READ_DQS
-                               / RW_MGR_MEM_VIRTUAL_GROUPS_PER_READ_DQS);
-
-                       addr = SDR_PHYGRP_RWMGRGRP_ADDRESS | RW_MGR_RUN_SINGLE_GROUP_OFFSET;
-                       writel(RW_MGR_GUARANTEED_READ, addr +
-                              ((group * RW_MGR_MEM_VIRTUAL_GROUPS_PER_READ_DQS +
-                               vg) << 2));
+                       writel(RW_MGR_GUARANTEED_READ,
+                              addr + addr_offset + (vg << 2));
 
                        base_rw_mgr = readl(SDR_PHYGRP_RWMGRGRP_ADDRESS);
-                       tmp_bit_chk = tmp_bit_chk | (correct_mask_vg & (~base_rw_mgr));
-
-                       if (vg == 0)
-                               break;
+                       tmp_bit_chk <<= shift_ratio;
+                       tmp_bit_chk |= correct_mask_vg & ~base_rw_mgr;
                }
-               *bit_chk &= tmp_bit_chk;
+
+               bit_chk &= tmp_bit_chk;
        }
 
-       addr = SDR_PHYGRP_RWMGRGRP_ADDRESS | RW_MGR_RUN_SINGLE_GROUP_OFFSET;
        writel(RW_MGR_CLEAR_DQS_ENABLE, addr + (group << 2));
 
        set_rank_and_odt_mask(0, RW_MGR_ODT_MODE_OFF);
-       debug_cond(DLEVEL == 1, "%s:%d test_load_patterns(%u,ALL) => (%u == %u) =>\
-                  %lu\n", __func__, __LINE__, group, *bit_chk, param->read_correct_mask,
-                  (long unsigned int)(*bit_chk == param->read_correct_mask));
-       return *bit_chk == param->read_correct_mask;
-}
 
-static uint32_t rw_mgr_mem_calibrate_read_test_patterns_all_ranks
-       (uint32_t group, uint32_t num_tries, uint32_t *bit_chk)
-{
-       return rw_mgr_mem_calibrate_read_test_patterns(0, group,
-               num_tries, bit_chk, 1);
+       if (bit_chk != param->read_correct_mask)
+               ret = -EIO;
+
+       debug_cond(DLEVEL == 1,
+                  "%s:%d test_load_patterns(%u,ALL) => (%u == %u) => %i\n",
+                  __func__, __LINE__, group, bit_chk,
+                  param->read_correct_mask, ret);
+
+       return ret;
 }
 
-/* load up the patterns we are going to use during a read test */
-static void rw_mgr_mem_calibrate_read_load_patterns(uint32_t rank_bgn,
-       uint32_t all_ranks)
+/**
+ * rw_mgr_mem_calibrate_read_load_patterns() - Load up the patterns for read test
+ * @rank_bgn:  Rank number
+ * @all_ranks: Test all ranks
+ *
+ * Load up the patterns we are going to use during a read test.
+ */
+static void rw_mgr_mem_calibrate_read_load_patterns(const u32 rank_bgn,
+                                                   const int all_ranks)
 {
-       uint32_t r;
-       uint32_t rank_end = all_ranks ? RW_MGR_MEM_NUMBER_OF_RANKS :
-               (rank_bgn + NUM_RANKS_PER_SHADOW_REG);
+       const u32 rank_end = all_ranks ?
+                       RW_MGR_MEM_NUMBER_OF_RANKS :
+                       (rank_bgn + NUM_RANKS_PER_SHADOW_REG);
+       u32 r;
 
        debug("%s:%d\n", __func__, __LINE__);
+
        for (r = rank_bgn; r < rank_end; r++) {
                if (param->skip_ranks[r])
                        /* request to skip the rank */
@@ -1276,269 +1286,292 @@ static uint32_t rw_mgr_mem_calibrate_read_test_all_ranks(uint32_t group,
                                              bit_chk, all_groups, 1);
 }
 
-static void rw_mgr_incr_vfifo(uint32_t grp, uint32_t *v)
+/**
+ * rw_mgr_incr_vfifo() - Increase VFIFO value
+ * @grp:       Read/Write group
+ *
+ * Increase VFIFO value.
+ */
+static void rw_mgr_incr_vfifo(const u32 grp)
 {
        writel(grp, &phy_mgr_cmd->inc_vfifo_hard_phy);
-       (*v)++;
 }
 
-static void rw_mgr_decr_vfifo(uint32_t grp, uint32_t *v)
+/**
+ * rw_mgr_decr_vfifo() - Decrease VFIFO value
+ * @grp:       Read/Write group
+ *
+ * Decrease VFIFO value.
+ */
+static void rw_mgr_decr_vfifo(const u32 grp)
 {
-       uint32_t i;
+       u32 i;
 
-       for (i = 0; i < VFIFO_SIZE-1; i++)
-               rw_mgr_incr_vfifo(grp, v);
+       for (i = 0; i < VFIFO_SIZE - 1; i++)
+               rw_mgr_incr_vfifo(grp);
 }
 
-static int find_vfifo_read(uint32_t grp, uint32_t *bit_chk)
+/**
+ * find_vfifo_failing_read() - Push VFIFO to get a failing read
+ * @grp:       Read/Write group
+ *
+ * Push VFIFO until a failing read happens.
+ */
+static int find_vfifo_failing_read(const u32 grp)
 {
-       uint32_t  v;
-       uint32_t fail_cnt = 0;
-       uint32_t test_status;
+       u32 v, ret, bit_chk, fail_cnt = 0;
 
-       for (v = 0; v < VFIFO_SIZE; ) {
-               debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: vfifo %u\n",
+       for (v = 0; v < VFIFO_SIZE; v++) {
+               debug_cond(DLEVEL == 2, "%s:%d: vfifo %u\n",
                           __func__, __LINE__, v);
-               test_status = rw_mgr_mem_calibrate_read_test_all_ranks
-                       (grp, 1, PASS_ONE_BIT, bit_chk, 0);
-               if (!test_status) {
+               ret = rw_mgr_mem_calibrate_read_test_all_ranks(grp, 1,
+                                               PASS_ONE_BIT, &bit_chk, 0);
+               if (!ret) {
                        fail_cnt++;
 
                        if (fail_cnt == 2)
-                               break;
+                               return v;
                }
 
-               /* fiddle with FIFO */
-               rw_mgr_incr_vfifo(grp, &v);
+               /* Fiddle with FIFO. */
+               rw_mgr_incr_vfifo(grp);
        }
 
-       if (v >= VFIFO_SIZE) {
-               /* no failing read found!! Something must have gone wrong */
-               debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: vfifo failed\n",
-                          __func__, __LINE__);
-               return 0;
-       } else {
-               return v;
-       }
+       /* No failing read found! Something must have gone wrong. */
+       debug_cond(DLEVEL == 2, "%s:%d: vfifo failed\n", __func__, __LINE__);
+       return 0;
 }
 
-static int find_working_phase(uint32_t *grp, uint32_t *bit_chk,
-                             uint32_t dtaps_per_ptap, uint32_t *work_bgn,
-                             uint32_t *v, uint32_t *d, uint32_t *p,
-                             uint32_t *i, uint32_t *max_working_cnt)
+/**
+ * sdr_find_phase() - Find DQS enable phase
+ * @working:   If 1, look for working phase, if 0, look for non-working phase
+ * @grp:       Read/Write group
+ * @work:      Working window position
+ * @i:         Iterator
+ * @p:         DQS Phase Iterator
+ *
+ * Find working or non-working DQS enable phase setting.
+ */
+static int sdr_find_phase(int working, const u32 grp, u32 *work,
+                         u32 *i, u32 *p)
 {
-       uint32_t found_begin = 0;
-       uint32_t tmp_delay = 0;
-       uint32_t test_status;
-
-       for (*d = 0; *d <= dtaps_per_ptap; (*d)++, tmp_delay +=
-               IO_DELAY_PER_DQS_EN_DCHAIN_TAP) {
-               *work_bgn = tmp_delay;
-               scc_mgr_set_dqs_en_delay_all_ranks(*grp, *d);
+       u32 ret, bit_chk;
+       const u32 end = VFIFO_SIZE + (working ? 0 : 1);
 
-               for (*i = 0; *i < VFIFO_SIZE; (*i)++) {
-                       for (*p = 0; *p <= IO_DQS_EN_PHASE_MAX; (*p)++, *work_bgn +=
-                               IO_DELAY_PER_OPA_TAP) {
-                               scc_mgr_set_dqs_en_phase_all_ranks(*grp, *p);
+       for (; *i < end; (*i)++) {
+               if (working)
+                       *p = 0;
 
-                               test_status =
-                               rw_mgr_mem_calibrate_read_test_all_ranks
-                               (*grp, 1, PASS_ONE_BIT, bit_chk, 0);
+               for (; *p <= IO_DQS_EN_PHASE_MAX; (*p)++) {
+                       scc_mgr_set_dqs_en_phase_all_ranks(grp, *p);
 
-                               if (test_status) {
-                                       *max_working_cnt = 1;
-                                       found_begin = 1;
-                                       break;
-                               }
-                       }
+                       ret = rw_mgr_mem_calibrate_read_test_all_ranks(grp, 1,
+                                               PASS_ONE_BIT, &bit_chk, 0);
+                       if (!working)
+                               ret = !ret;
 
-                       if (found_begin)
-                               break;
+                       if (ret)
+                               return 0;
 
-                       if (*p > IO_DQS_EN_PHASE_MAX)
-                               /* fiddle with FIFO */
-                               rw_mgr_incr_vfifo(*grp, v);
+                       *work += IO_DELAY_PER_OPA_TAP;
                }
 
-               if (found_begin)
-                       break;
+               if (*p > IO_DQS_EN_PHASE_MAX) {
+                       /* Fiddle with FIFO. */
+                       rw_mgr_incr_vfifo(grp);
+                       if (!working)
+                               *p = 0;
+               }
        }
 
-       if (*i >= VFIFO_SIZE) {
-               /* cannot find working solution */
-               debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: no vfifo/\
-                          ptap/dtap\n", __func__, __LINE__);
-               return 0;
-       } else {
-               return 1;
+       return -EINVAL;
+}
+
+/**
+ * sdr_working_phase() - Find working DQS enable phase
+ * @grp:       Read/Write group
+ * @work_bgn:  Working window start position
+ * @d:         dtaps output value
+ * @p:         DQS Phase Iterator
+ * @i:         Iterator
+ *
+ * Find working DQS enable phase setting.
+ */
+static int sdr_working_phase(const u32 grp, u32 *work_bgn, u32 *d,
+                            u32 *p, u32 *i)
+{
+       const u32 dtaps_per_ptap = IO_DELAY_PER_OPA_TAP /
+                                  IO_DELAY_PER_DQS_EN_DCHAIN_TAP;
+       int ret;
+
+       *work_bgn = 0;
+
+       for (*d = 0; *d <= dtaps_per_ptap; (*d)++) {
+               *i = 0;
+               scc_mgr_set_dqs_en_delay_all_ranks(grp, *d);
+               ret = sdr_find_phase(1, grp, work_bgn, i, p);
+               if (!ret)
+                       return 0;
+               *work_bgn += IO_DELAY_PER_DQS_EN_DCHAIN_TAP;
        }
+
+       /* Cannot find working solution */
+       debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: no vfifo/ptap/dtap\n",
+                  __func__, __LINE__);
+       return -EINVAL;
 }
 
-static void sdr_backup_phase(uint32_t *grp, uint32_t *bit_chk,
-                            uint32_t *work_bgn, uint32_t *v, uint32_t *d,
-                            uint32_t *p, uint32_t *max_working_cnt)
+/**
+ * sdr_backup_phase() - Find DQS enable backup phase
+ * @grp:       Read/Write group
+ * @work_bgn:  Working window start position
+ * @p:         DQS Phase Iterator
+ *
+ * Find DQS enable backup phase setting.
+ */
+static void sdr_backup_phase(const u32 grp, u32 *work_bgn, u32 *p)
 {
-       uint32_t found_begin = 0;
-       uint32_t tmp_delay;
+       u32 tmp_delay, bit_chk, d;
+       int ret;
 
        /* Special case code for backing up a phase */
        if (*p == 0) {
                *p = IO_DQS_EN_PHASE_MAX;
-               rw_mgr_decr_vfifo(*grp, v);
+               rw_mgr_decr_vfifo(grp);
        } else {
                (*p)--;
        }
        tmp_delay = *work_bgn - IO_DELAY_PER_OPA_TAP;
-       scc_mgr_set_dqs_en_phase_all_ranks(*grp, *p);
+       scc_mgr_set_dqs_en_phase_all_ranks(grp, *p);
 
-       for (*d = 0; *d <= IO_DQS_EN_DELAY_MAX && tmp_delay < *work_bgn;
-               (*d)++, tmp_delay += IO_DELAY_PER_DQS_EN_DCHAIN_TAP) {
-               scc_mgr_set_dqs_en_delay_all_ranks(*grp, *d);
+       for (d = 0; d <= IO_DQS_EN_DELAY_MAX && tmp_delay < *work_bgn; d++) {
+               scc_mgr_set_dqs_en_delay_all_ranks(grp, d);
 
-               if (rw_mgr_mem_calibrate_read_test_all_ranks(*grp, 1,
-                                                            PASS_ONE_BIT,
-                                                            bit_chk, 0)) {
-                       found_begin = 1;
+               ret = rw_mgr_mem_calibrate_read_test_all_ranks(grp, 1,
+                                       PASS_ONE_BIT, &bit_chk, 0);
+               if (ret) {
                        *work_bgn = tmp_delay;
                        break;
                }
-       }
 
-       /* We have found a working dtap before the ptap found above */
-       if (found_begin == 1)
-               (*max_working_cnt)++;
+               tmp_delay += IO_DELAY_PER_DQS_EN_DCHAIN_TAP;
+       }
 
-       /*
-        * Restore VFIFO to old state before we decremented it
-        * (if needed).
-        */
+       /* Restore VFIFO to old state before we decremented it (if needed). */
        (*p)++;
        if (*p > IO_DQS_EN_PHASE_MAX) {
                *p = 0;
-               rw_mgr_incr_vfifo(*grp, v);
+               rw_mgr_incr_vfifo(grp);
        }
 
-       scc_mgr_set_dqs_en_delay_all_ranks(*grp, 0);
+       scc_mgr_set_dqs_en_delay_all_ranks(grp, 0);
 }
 
-static int sdr_nonworking_phase(uint32_t *grp, uint32_t *bit_chk,
-                            uint32_t *work_bgn, uint32_t *v, uint32_t *d,
-                            uint32_t *p, uint32_t *i, uint32_t *max_working_cnt,
-                            uint32_t *work_end)
+/**
+ * sdr_nonworking_phase() - Find non-working DQS enable phase
+ * @grp:       Read/Write group
+ * @work_end:  Working window end position
+ * @p:         DQS Phase Iterator
+ * @i:         Iterator
+ *
+ * Find non-working DQS enable phase setting.
+ */
+static int sdr_nonworking_phase(const u32 grp, u32 *work_end, u32 *p, u32 *i)
 {
-       uint32_t found_end = 0;
+       int ret;
 
        (*p)++;
        *work_end += IO_DELAY_PER_OPA_TAP;
        if (*p > IO_DQS_EN_PHASE_MAX) {
-               /* fiddle with FIFO */
+               /* Fiddle with FIFO. */
                *p = 0;
-               rw_mgr_incr_vfifo(*grp, v);
+               rw_mgr_incr_vfifo(grp);
        }
 
-       for (; *i < VFIFO_SIZE + 1; (*i)++) {
-               for (; *p <= IO_DQS_EN_PHASE_MAX; (*p)++, *work_end
-                       += IO_DELAY_PER_OPA_TAP) {
-                       scc_mgr_set_dqs_en_phase_all_ranks(*grp, *p);
-
-                       if (!rw_mgr_mem_calibrate_read_test_all_ranks
-                               (*grp, 1, PASS_ONE_BIT, bit_chk, 0)) {
-                               found_end = 1;
-                               break;
-                       } else {
-                               (*max_working_cnt)++;
-                       }
-               }
-
-               if (found_end)
-                       break;
-
-               if (*p > IO_DQS_EN_PHASE_MAX) {
-                       /* fiddle with FIFO */
-                       rw_mgr_incr_vfifo(*grp, v);
-                       *p = 0;
-               }
+       ret = sdr_find_phase(0, grp, work_end, i, p);
+       if (ret) {
+               /* Cannot see edge of failing read. */
+               debug_cond(DLEVEL == 2, "%s:%d: end: failed\n",
+                          __func__, __LINE__);
        }
 
-       if (*i >= VFIFO_SIZE + 1) {
-               /* cannot see edge of failing read */
-               debug_cond(DLEVEL == 2, "%s:%d sdr_nonworking_phase: end:\
-                          failed\n", __func__, __LINE__);
-               return 0;
-       } else {
-               return 1;
-       }
+       return ret;
 }
 
-static int sdr_find_window_centre(uint32_t *grp, uint32_t *bit_chk,
-                                 uint32_t *work_bgn, uint32_t *v, uint32_t *d,
-                                 uint32_t *p, uint32_t *work_mid,
-                                 uint32_t *work_end)
+/**
+ * sdr_find_window_center() - Find center of the working DQS window.
+ * @grp:       Read/Write group
+ * @work_bgn:  First working settings
+ * @work_end:  Last working settings
+ *
+ * Find center of the working DQS enable window.
+ */
+static int sdr_find_window_center(const u32 grp, const u32 work_bgn,
+                                 const u32 work_end)
 {
-       int i;
+       u32 bit_chk, work_mid;
        int tmp_delay = 0;
+       int i, p, d;
 
-       *work_mid = (*work_bgn + *work_end) / 2;
+       work_mid = (work_bgn + work_end) / 2;
 
        debug_cond(DLEVEL == 2, "work_bgn=%d work_end=%d work_mid=%d\n",
-                  *work_bgn, *work_end, *work_mid);
+                  work_bgn, work_end, work_mid);
        /* Get the middle delay to be less than a VFIFO delay */
-       for (*p = 0; *p <= IO_DQS_EN_PHASE_MAX;
-               (*p)++, tmp_delay += IO_DELAY_PER_OPA_TAP)
-               ;
+       tmp_delay = (IO_DQS_EN_PHASE_MAX + 1) * IO_DELAY_PER_OPA_TAP;
+
        debug_cond(DLEVEL == 2, "vfifo ptap delay %d\n", tmp_delay);
-       while (*work_mid > tmp_delay)
-               *work_mid -= tmp_delay;
-       debug_cond(DLEVEL == 2, "new work_mid %d\n", *work_mid);
+       work_mid %= tmp_delay;
+       debug_cond(DLEVEL == 2, "new work_mid %d\n", work_mid);
 
-       tmp_delay = 0;
-       for (*p = 0; *p <= IO_DQS_EN_PHASE_MAX && tmp_delay < *work_mid;
-               (*p)++, tmp_delay += IO_DELAY_PER_OPA_TAP)
-               ;
-       tmp_delay -= IO_DELAY_PER_OPA_TAP;
-       debug_cond(DLEVEL == 2, "new p %d, tmp_delay=%d\n", (*p) - 1, tmp_delay);
-       for (*d = 0; *d <= IO_DQS_EN_DELAY_MAX && tmp_delay < *work_mid; (*d)++,
-               tmp_delay += IO_DELAY_PER_DQS_EN_DCHAIN_TAP)
-               ;
-       debug_cond(DLEVEL == 2, "new d %d, tmp_delay=%d\n", *d, tmp_delay);
+       tmp_delay = rounddown(work_mid, IO_DELAY_PER_OPA_TAP);
+       if (tmp_delay > IO_DQS_EN_PHASE_MAX * IO_DELAY_PER_OPA_TAP)
+               tmp_delay = IO_DQS_EN_PHASE_MAX * IO_DELAY_PER_OPA_TAP;
+       p = tmp_delay / IO_DELAY_PER_OPA_TAP;
+
+       debug_cond(DLEVEL == 2, "new p %d, tmp_delay=%d\n", p, tmp_delay);
+
+       d = DIV_ROUND_UP(work_mid - tmp_delay, IO_DELAY_PER_DQS_EN_DCHAIN_TAP);
+       if (d > IO_DQS_EN_DELAY_MAX)
+               d = IO_DQS_EN_DELAY_MAX;
+       tmp_delay += d * IO_DELAY_PER_DQS_EN_DCHAIN_TAP;
 
-       scc_mgr_set_dqs_en_phase_all_ranks(*grp, (*p) - 1);
-       scc_mgr_set_dqs_en_delay_all_ranks(*grp, *d);
+       debug_cond(DLEVEL == 2, "new d %d, tmp_delay=%d\n", d, tmp_delay);
+
+       scc_mgr_set_dqs_en_phase_all_ranks(grp, p);
+       scc_mgr_set_dqs_en_delay_all_ranks(grp, d);
 
        /*
         * push vfifo until we can successfully calibrate. We can do this
         * because the largest possible margin in 1 VFIFO cycle.
         */
        for (i = 0; i < VFIFO_SIZE; i++) {
-               debug_cond(DLEVEL == 2, "find_dqs_en_phase: center: vfifo=%u\n",
-                          *v);
-               if (rw_mgr_mem_calibrate_read_test_all_ranks(*grp, 1,
+               debug_cond(DLEVEL == 2, "find_dqs_en_phase: center\n");
+               if (rw_mgr_mem_calibrate_read_test_all_ranks(grp, 1,
                                                             PASS_ONE_BIT,
-                                                            bit_chk, 0)) {
-                       break;
+                                                            &bit_chk, 0)) {
+                       debug_cond(DLEVEL == 2,
+                                  "%s:%d center: found: ptap=%u dtap=%u\n",
+                                  __func__, __LINE__, p, d);
+                       return 0;
                }
 
-               /* fiddle with FIFO */
-               rw_mgr_incr_vfifo(*grp, v);
+               /* Fiddle with FIFO. */
+               rw_mgr_incr_vfifo(grp);
        }
 
-       if (i >= VFIFO_SIZE) {
-               debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: center: \
-                          failed\n", __func__, __LINE__);
-               return 0;
-       } else {
-               return 1;
-       }
+       debug_cond(DLEVEL == 2, "%s:%d center: failed.\n",
+                  __func__, __LINE__);
+       return -EINVAL;
 }
 
 /* find a good dqs enable to use */
-static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(uint32_t grp)
+static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(u32 grp)
 {
-       uint32_t v, d, p, i;
-       uint32_t max_working_cnt;
+       uint32_t d, p, i;
        uint32_t bit_chk;
        uint32_t dtaps_per_ptap;
-       uint32_t work_bgn, work_mid, work_end;
+       uint32_t work_bgn, work_end;
        uint32_t found_passing_read, found_failing_read, initial_failing_dtap;
 
        debug("%s:%d %u\n", __func__, __LINE__, grp);
@@ -1548,52 +1581,44 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(uint32_t grp)
        scc_mgr_set_dqs_en_delay_all_ranks(grp, 0);
        scc_mgr_set_dqs_en_phase_all_ranks(grp, 0);
 
-       /* ************************************************************** */
-       /* * Step 0 : Determine number of delay taps for each phase tap * */
-       dtaps_per_ptap = IO_DELAY_PER_OPA_TAP/IO_DELAY_PER_DQS_EN_DCHAIN_TAP;
-
-       /* ********************************************************* */
-       /* * Step 1 : First push vfifo until we get a failing read * */
-       v = find_vfifo_read(grp, &bit_chk);
+       /* Step 0: Determine number of delay taps for each phase tap. */
+       dtaps_per_ptap = IO_DELAY_PER_OPA_TAP / IO_DELAY_PER_DQS_EN_DCHAIN_TAP;
 
-       max_working_cnt = 0;
+       /* Step 1: First push vfifo until we get a failing read. */
+       find_vfifo_failing_read(grp);
 
-       /* ******************************************************** */
-       /* * step 2: find first working phase, increment in ptaps * */
+       /* Step 2: Find first working phase, increment in ptaps. */
        work_bgn = 0;
-       if (find_working_phase(&grp, &bit_chk, dtaps_per_ptap, &work_bgn, &v, &d,
-                               &p, &i, &max_working_cnt) == 0)
+       if (sdr_working_phase(grp, &work_bgn, &d, &p, &i))
                return 0;
 
        work_end = work_bgn;
 
        /*
-        * If d is 0 then the working window covers a phase tap and
-        * we can follow the old procedure otherwise, we've found the beginning,
+        * If d is 0 then the working window covers a phase tap and we can
+        * follow the old procedure. Otherwise, we've found the beginning
         * and we need to increment the dtaps until we find the end.
         */
        if (d == 0) {
-               /* ********************************************************* */
-               /* * step 3a: if we have room, back off by one and
-               increment in dtaps * */
-
-               sdr_backup_phase(&grp, &bit_chk, &work_bgn, &v, &d, &p,
-                                &max_working_cnt);
-
-               /* ********************************************************* */
-               /* * step 4a: go forward from working phase to non working
-               phase, increment in ptaps * */
-               if (sdr_nonworking_phase(&grp, &bit_chk, &work_bgn, &v, &d, &p,
-                                        &i, &max_working_cnt, &work_end) == 0)
+               /*
+                * Step 3a: If we have room, back off by one and
+                *          increment in dtaps.
+                */
+               sdr_backup_phase(grp, &work_bgn, &p);
+
+               /*
+                * Step 4a: go forward from working phase to non working
+                * phase, increment in ptaps.
+                */
+               if (sdr_nonworking_phase(grp, &work_end, &p, &i))
                        return 0;
 
-               /* ********************************************************* */
-               /* * step 5a:  back off one from last, increment in dtaps  * */
+               /* Step 5a: Back off one from last, increment in dtaps. */
 
                /* Special case code for backing up a phase */
                if (p == 0) {
                        p = IO_DQS_EN_PHASE_MAX;
-                       rw_mgr_decr_vfifo(grp, &v);
+                       rw_mgr_decr_vfifo(grp);
                } else {
                        p = p - 1;
                }
@@ -1601,104 +1626,83 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(uint32_t grp)
                work_end -= IO_DELAY_PER_OPA_TAP;
                scc_mgr_set_dqs_en_phase_all_ranks(grp, p);
 
-               /* * The actual increment of dtaps is done outside of
-               the if/else loop to share code */
                d = 0;
 
-               debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: v/p: \
-                          vfifo=%u ptap=%u\n", __func__, __LINE__,
-                          v, p);
-       } else {
-               /* ******************************************************* */
-               /* * step 3-5b:  Find the right edge of the window using
-               delay taps   * */
-               debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase:vfifo=%u \
-                          ptap=%u dtap=%u bgn=%u\n", __func__, __LINE__,
-                          v, p, d, work_bgn);
-
-               work_end = work_bgn;
+               debug_cond(DLEVEL == 2, "%s:%d p: ptap=%u\n",
+                          __func__, __LINE__, p);
+       }
 
-               /* * The actual increment of dtaps is done outside of the
-               if/else loop to share code */
+       /* The dtap increment to find the failing edge is done here. */
+       for (; d <= IO_DQS_EN_DELAY_MAX; d++) {
+               debug_cond(DLEVEL == 2, "%s:%d end-2: dtap=%u\n",
+                          __func__, __LINE__, d);
 
-               /* Only here to counterbalance a subtract later on which is
-               not needed if this branch of the algorithm is taken */
-               max_working_cnt++;
-       }
+               scc_mgr_set_dqs_en_delay_all_ranks(grp, d);
 
-       /* The dtap increment to find the failing edge is done here */
-       for (; d <= IO_DQS_EN_DELAY_MAX; d++, work_end +=
-               IO_DELAY_PER_DQS_EN_DCHAIN_TAP) {
-                       debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: \
-                                  end-2: dtap=%u\n", __func__, __LINE__, d);
-                       scc_mgr_set_dqs_en_delay_all_ranks(grp, d);
+               if (!rw_mgr_mem_calibrate_read_test_all_ranks(grp, 1,
+                                                             PASS_ONE_BIT,
+                                                             &bit_chk, 0)) {
+                       break;
+               }
 
-                       if (!rw_mgr_mem_calibrate_read_test_all_ranks(grp, 1,
-                                                                     PASS_ONE_BIT,
-                                                                     &bit_chk, 0)) {
-                               break;
-                       }
+               work_end += IO_DELAY_PER_DQS_EN_DCHAIN_TAP;
        }
 
        /* Go back to working dtap */
        if (d != 0)
                work_end -= IO_DELAY_PER_DQS_EN_DCHAIN_TAP;
 
-       debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: v/p/d: vfifo=%u \
-                  ptap=%u dtap=%u end=%u\n", __func__, __LINE__,
-                  v, p, d-1, work_end);
+       debug_cond(DLEVEL == 2,
+                  "%s:%d p/d: ptap=%u dtap=%u end=%u\n",
+                  __func__, __LINE__, p, d - 1, work_end);
 
        if (work_end < work_bgn) {
                /* nil range */
-               debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: end-2: \
-                          failed\n", __func__, __LINE__);
+               debug_cond(DLEVEL == 2, "%s:%d end-2: failed\n",
+                          __func__, __LINE__);
                return 0;
        }
 
-       debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: found range [%u,%u]\n",
+       debug_cond(DLEVEL == 2, "%s:%d found range [%u,%u]\n",
                   __func__, __LINE__, work_bgn, work_end);
 
-       /* *************************************************************** */
        /*
-        * * We need to calculate the number of dtaps that equal a ptap
-        * To do that we'll back up a ptap and re-find the edge of the
-        * window using dtaps
+        * We need to calculate the number of dtaps that equal a ptap.
+        * To do that we'll back up a ptap and re-find the edge of the
+        * window using dtaps
         */
-
-       debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: calculate dtaps_per_ptap \
-                  for tracking\n", __func__, __LINE__);
+       debug_cond(DLEVEL == 2, "%s:%d calculate dtaps_per_ptap for tracking\n",
+                  __func__, __LINE__);
 
        /* Special case code for backing up a phase */
        if (p == 0) {
                p = IO_DQS_EN_PHASE_MAX;
-               rw_mgr_decr_vfifo(grp, &v);
-               debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: backedup \
-                          cycle/phase: v=%u p=%u\n", __func__, __LINE__,
-                          v, p);
+               rw_mgr_decr_vfifo(grp);
+               debug_cond(DLEVEL == 2, "%s:%d backedup cycle/phase: p=%u\n",
+                          __func__, __LINE__, p);
        } else {
                p = p - 1;
-               debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: backedup \
-                          phase only: v=%u p=%u", __func__, __LINE__,
-                          v, p);
+               debug_cond(DLEVEL == 2, "%s:%d backedup phase only: p=%u",
+                          __func__, __LINE__, p);
        }
 
        scc_mgr_set_dqs_en_phase_all_ranks(grp, p);
 
        /*
         * Increase dtap until we first see a passing read (in case the
-        * window is smaller than a ptap),
-        * and then a failing read to mark the edge of the window again
+        * window is smaller than a ptap), and then a failing read to
+        * mark the edge of the window again.
         */
 
-       /* Find a passing read */
-       debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: find passing read\n",
+       /* Find a passing read. */
+       debug_cond(DLEVEL == 2, "%s:%d find passing read\n",
                   __func__, __LINE__);
        found_passing_read = 0;
        found_failing_read = 0;
        initial_failing_dtap = d;
        for (; d <= IO_DQS_EN_DELAY_MAX; d++) {
-               debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: testing \
-                          read d=%u\n", __func__, __LINE__, d);
+               debug_cond(DLEVEL == 2, "%s:%d testing read d=%u\n",
+                          __func__, __LINE__, d);
                scc_mgr_set_dqs_en_delay_all_ranks(grp, d);
 
                if (rw_mgr_mem_calibrate_read_test_all_ranks(grp, 1,
@@ -1710,12 +1714,12 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(uint32_t grp)
        }
 
        if (found_passing_read) {
-               /* Find a failing read */
-               debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: find failing \
-                          read\n", __func__, __LINE__);
+               /* Find a failing read. */
+               debug_cond(DLEVEL == 2, "%s:%d find failing read\n",
+                          __func__, __LINE__);
                for (d = d + 1; d <= IO_DQS_EN_DELAY_MAX; d++) {
-                       debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: \
-                                  testing read d=%u\n", __func__, __LINE__, d);
+                       debug_cond(DLEVEL == 2, "%s:%d testing read d=%u\n",
+                                  __func__, __LINE__, d);
                        scc_mgr_set_dqs_en_delay_all_ranks(grp, d);
 
                        if (!rw_mgr_mem_calibrate_read_test_all_ranks
@@ -1725,9 +1729,9 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(uint32_t grp)
                        }
                }
        } else {
-               debug_cond(DLEVEL == 1, "%s:%d find_dqs_en_phase: failed to \
-                          calculate dtaps", __func__, __LINE__);
-               debug_cond(DLEVEL == 1, "per ptap. Fall back on static value\n");
+               debug_cond(DLEVEL == 1,
+                          "%s:%d failed to calculate dtaps per ptap. Fall back on static value\n",
+                          __func__, __LINE__);
        }
 
        /*
@@ -1740,79 +1744,16 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(uint32_t grp)
                dtaps_per_ptap = d - initial_failing_dtap;
 
        writel(dtaps_per_ptap, &sdr_reg_file->dtaps_per_ptap);
-       debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: dtaps_per_ptap=%u \
-                  - %u = %u",  __func__, __LINE__, d,
-                  initial_failing_dtap, dtaps_per_ptap);
-
-       /* ******************************************** */
-       /* * step 6:  Find the centre of the window   * */
-       if (sdr_find_window_centre(&grp, &bit_chk, &work_bgn, &v, &d, &p,
-                                  &work_mid, &work_end) == 0)
+       debug_cond(DLEVEL == 2, "%s:%d dtaps_per_ptap=%u - %u = %u",
+                  __func__, __LINE__, d, initial_failing_dtap, dtaps_per_ptap);
+
+       /* Step 6: Find the centre of the window. */
+       if (sdr_find_window_centre(grp, work_bgn, work_end))
                return 0;
 
-       debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: center found: \
-                  vfifo=%u ptap=%u dtap=%u\n", __func__, __LINE__,
-                  v, p-1, d);
        return 1;
 }
 
-/*
- * Try rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase across different
- * dq_in_delay values
- */
-static uint32_t
-rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase_sweep_dq_in_delay
-(uint32_t write_group, uint32_t read_group, uint32_t test_bgn)
-{
-       uint32_t found;
-       uint32_t i;
-       uint32_t p;
-       uint32_t d;
-       uint32_t r;
-
-       const uint32_t delay_step = IO_IO_IN_DELAY_MAX /
-               (RW_MGR_MEM_DQ_PER_READ_DQS-1);
-               /* we start at zero, so have one less dq to devide among */
-
-       debug("%s:%d (%u,%u,%u)", __func__, __LINE__, write_group, read_group,
-             test_bgn);
-
-       /* try different dq_in_delays since the dq path is shorter than dqs */
-
-       for (r = 0; r < RW_MGR_MEM_NUMBER_OF_RANKS;
-            r += NUM_RANKS_PER_SHADOW_REG) {
-               for (i = 0, p = test_bgn, d = 0; i < RW_MGR_MEM_DQ_PER_READ_DQS; i++, p++, d += delay_step) {
-                       debug_cond(DLEVEL == 1, "%s:%d rw_mgr_mem_calibrate_\
-                                  vfifo_find_dqs_", __func__, __LINE__);
-                       debug_cond(DLEVEL == 1, "en_phase_sweep_dq_in_delay: g=%u/%u ",
-                              write_group, read_group);
-                       debug_cond(DLEVEL == 1, "r=%u, i=%u p=%u d=%u\n", r, i , p, d);
-                       scc_mgr_set_dq_in_delay(p, d);
-                       scc_mgr_load_dq(p);
-               }
-               writel(0, &sdr_scc_mgr->update);
-       }
-
-       found = rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(read_group);
-
-       debug_cond(DLEVEL == 1, "%s:%d rw_mgr_mem_calibrate_vfifo_find_dqs_\
-                  en_phase_sweep_dq", __func__, __LINE__);
-       debug_cond(DLEVEL == 1, "_in_delay: g=%u/%u found=%u; Reseting delay \
-                  chain to zero\n", write_group, read_group, found);
-
-       for (r = 0; r < RW_MGR_MEM_NUMBER_OF_RANKS;
-            r += NUM_RANKS_PER_SHADOW_REG) {
-               for (i = 0, p = test_bgn; i < RW_MGR_MEM_DQ_PER_READ_DQS;
-                       i++, p++) {
-                       scc_mgr_set_dq_in_delay(p, 0);
-                       scc_mgr_load_dq(p);
-               }
-               writel(0, &sdr_scc_mgr->update);
-       }
-
-       return found;
-}
-
 /* per-bit deskew DQ and center */
 static uint32_t rw_mgr_mem_calibrate_vfifo_center(uint32_t rank_bgn,
        uint32_t write_group, uint32_t read_group, uint32_t test_bgn,
@@ -2199,7 +2140,6 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_center(uint32_t rank_bgn,
 static int rw_mgr_mem_calibrate_guaranteed_write(const u32 rw_group,
                                                 const u32 phase)
 {
-       u32 bit_chk;
        int ret;
 
        /* Set a particular DQ/DQS phase. */
@@ -2222,16 +2162,12 @@ static int rw_mgr_mem_calibrate_guaranteed_write(const u32 rw_group,
         * Altera EMI_RM 2015.05.04 :: Figure 1-26
         * Back-to-Back reads of the patterns used for calibration.
         */
-       ret = rw_mgr_mem_calibrate_read_test_patterns_all_ranks(rw_group, 1,
-                                                               &bit_chk);
-       if (!ret) {     /* FIXME: 0 means failure in this old code :-( */
+       ret = rw_mgr_mem_calibrate_read_test_patterns(0, rw_group, 1);
+       if (ret)
                debug_cond(DLEVEL == 1,
                           "%s:%d Guaranteed read test failed: g=%u p=%u\n",
                           __func__, __LINE__, rw_group, phase);
-               return -EIO;
-       }
-
-       return 0;
+       return ret;
 }
 
 /**
@@ -2245,15 +2181,101 @@ static int rw_mgr_mem_calibrate_guaranteed_write(const u32 rw_group,
 static int rw_mgr_mem_calibrate_dqs_enable_calibration(const u32 rw_group,
                                                       const u32 test_bgn)
 {
-       int ret;
-
        /*
         * Altera EMI_RM 2015.05.04 :: Figure 1-27
         * DQS and DQS Eanble Signal Relationships.
         */
-       ret = rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase_sweep_dq_in_delay(
-                                               rw_group, rw_group, test_bgn);
-       if (!ret)       /* FIXME: 0 means failure in this old code :-( */
+
+       /* We start at zero, so have one less dq to devide among */
+       const u32 delay_step = IO_IO_IN_DELAY_MAX /
+                              (RW_MGR_MEM_DQ_PER_READ_DQS - 1);
+       int found;
+       u32 i, p, d, r;
+
+       debug("%s:%d (%u,%u)\n", __func__, __LINE__, rw_group, test_bgn);
+
+       /* Try different dq_in_delays since the DQ path is shorter than DQS. */
+       for (r = 0; r < RW_MGR_MEM_NUMBER_OF_RANKS;
+            r += NUM_RANKS_PER_SHADOW_REG) {
+               for (i = 0, p = test_bgn, d = 0;
+                    i < RW_MGR_MEM_DQ_PER_READ_DQS;
+                    i++, p++, d += delay_step) {
+                       debug_cond(DLEVEL == 1,
+                                  "%s:%d: g=%u r=%u i=%u p=%u d=%u\n",
+                                  __func__, __LINE__, rw_group, r, i, p, d);
+
+                       scc_mgr_set_dq_in_delay(p, d);
+                       scc_mgr_load_dq(p);
+               }
+
+               writel(0, &sdr_scc_mgr->update);
+       }
+
+       /*
+        * Try rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase across different
+        * dq_in_delay values
+        */
+       found = rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(rw_group);
+
+       debug_cond(DLEVEL == 1,
+                  "%s:%d: g=%u found=%u; Reseting delay chain to zero\n",
+                  __func__, __LINE__, rw_group, found);
+
+       for (r = 0; r < RW_MGR_MEM_NUMBER_OF_RANKS;
+            r += NUM_RANKS_PER_SHADOW_REG) {
+               scc_mgr_apply_group_dq_in_delay(test_bgn, 0);
+               writel(0, &sdr_scc_mgr->update);
+       }
+
+       if (!found)
+               return -EINVAL;
+
+       return 0;
+
+}
+
+/**
+ * rw_mgr_mem_calibrate_dq_dqs_centering() - Centering DQ/DQS
+ * @rw_group:          Read/Write Group
+ * @test_bgn:          Rank at which the test begins
+ * @use_read_test:     Perform a read test
+ * @update_fom:                Update FOM
+ *
+ * The centerin DQ/DQS stage attempts to align DQ and DQS signals on reads
+ * within a group.
+ */
+static int
+rw_mgr_mem_calibrate_dq_dqs_centering(const u32 rw_group, const u32 test_bgn,
+                                     const int use_read_test,
+                                     const int update_fom)
+
+{
+       int ret, grp_calibrated;
+       u32 rank_bgn, sr;
+
+       /*
+        * Altera EMI_RM 2015.05.04 :: Figure 1-28
+        * Read per-bit deskew can be done on a per shadow register basis.
+        */
+       grp_calibrated = 1;
+       for (rank_bgn = 0, sr = 0;
+            rank_bgn < RW_MGR_MEM_NUMBER_OF_RANKS;
+            rank_bgn += NUM_RANKS_PER_SHADOW_REG, sr++) {
+               /* Check if this set of ranks should be skipped entirely. */
+               if (param->skip_shadow_regs[sr])
+                       continue;
+
+               ret = rw_mgr_mem_calibrate_vfifo_center(rank_bgn, rw_group,
+                                                       rw_group, test_bgn,
+                                                       use_read_test,
+                                                       update_fom);
+               if (ret)
+                       continue;
+
+               grp_calibrated = 0;
+       }
+
+       if (!grp_calibrated)
                return -EIO;
 
        return 0;
@@ -2276,9 +2298,8 @@ static int rw_mgr_mem_calibrate_dqs_enable_calibration(const u32 rw_group,
  */
 static int rw_mgr_mem_calibrate_vfifo(const u32 rw_group, const u32 test_bgn)
 {
-       uint32_t p, d, rank_bgn, sr;
+       uint32_t p, d;
        uint32_t dtaps_per_ptap;
-       uint32_t grp_calibrated;
        uint32_t failed_substage;
 
        int ret;
@@ -2322,36 +2343,20 @@ static int rw_mgr_mem_calibrate_vfifo(const u32 rw_group, const u32 test_bgn)
                                continue;
                        }
 
+                       /* 3) Centering DQ/DQS */
                        /*
-                        * USER Read per-bit deskew can be done on a
-                        * per shadow register basis.
+                        * If doing read after write calibration, do not update
+                        * FOM now. Do it then.
                         */
-                       grp_calibrated = 1;
-                       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])
-                                       continue;
-                               /*
-                                * If doing read after write
-                                * calibration, do not update
-                                * FOM, now - do it then.
-                                */
-                               if (rw_mgr_mem_calibrate_vfifo_center(rank_bgn,
-                                                       rw_group, rw_group,
-                                                       test_bgn, 1, 0))
-                                       continue;
-
-                               grp_calibrated = 0;
+                       ret = rw_mgr_mem_calibrate_dq_dqs_centering(rw_group,
+                                                               test_bgn, 1, 0);
+                       if (ret) {
                                failed_substage = CAL_SUBSTAGE_VFIFO_CENTER;
+                               continue;
                        }
 
-                       if (grp_calibrated)
-                               goto cal_done_ok;
+                       /* All done. */
+                       goto cal_done_ok;
                }
        }