summaryrefslogtreecommitdiff
path: root/drivers/ddr/mvebu/ddr3_dqs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ddr/mvebu/ddr3_dqs.c')
-rw-r--r--drivers/ddr/mvebu/ddr3_dqs.c1374
1 files changed, 1374 insertions, 0 deletions
diff --git a/drivers/ddr/mvebu/ddr3_dqs.c b/drivers/ddr/mvebu/ddr3_dqs.c
new file mode 100644
index 0000000..71a986d
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_dqs.c
@@ -0,0 +1,1374 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_DQS_C(s, d, l) \
+ DEBUG_DQS_S(s); DEBUG_DQS_D(d, l); DEBUG_DQS_S("\n")
+#define DEBUG_DQS_FULL_C(s, d, l) \
+ DEBUG_DQS_FULL_S(s); DEBUG_DQS_FULL_D(d, l); DEBUG_DQS_FULL_S("\n")
+#define DEBUG_DQS_RESULTS_C(s, d, l) \
+ DEBUG_DQS_RESULTS_S(s); DEBUG_DQS_RESULTS_D(d, l); DEBUG_DQS_RESULTS_S("\n")
+#define DEBUG_PER_DQ_C(s, d, l) \
+ puts(s); printf("%x", d); puts("\n")
+
+#define DEBUG_DQS_RESULTS_S(s) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%s", s)
+#define DEBUG_DQS_RESULTS_D(d, l) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%x", d)
+
+#define DEBUG_PER_DQ_S(s) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_3, "%s", s)
+#define DEBUG_PER_DQ_D(d, l) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_3, "%x", d)
+#define DEBUG_PER_DQ_DD(d, l) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_3, "%d", d)
+
+#ifdef MV_DEBUG_DQS
+#define DEBUG_DQS_S(s) puts(s)
+#define DEBUG_DQS_D(d, l) printf("%x", d)
+#else
+#define DEBUG_DQS_S(s)
+#define DEBUG_DQS_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_DQS_FULL
+#define DEBUG_DQS_FULL_S(s) puts(s)
+#define DEBUG_DQS_FULL_D(d, l) printf("%x", d)
+#else
+#define DEBUG_DQS_FULL_S(s)
+#define DEBUG_DQS_FULL_D(d, l)
+#endif
+
+/* State machine for centralization - find low & high limit */
+enum {
+ PUP_ADLL_LIMITS_STATE_FAIL,
+ PUP_ADLL_LIMITS_STATE_PASS,
+ PUP_ADLL_LIMITS_STATE_FAIL_AFTER_PASS,
+};
+
+/* Hold centralization low results */
+static int centralization_low_limit[MAX_PUP_NUM] = { 0 };
+/* Hold centralization high results */
+static int centralization_high_limit[MAX_PUP_NUM] = { 0 };
+
+int ddr3_find_adll_limits(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc, int is_tx);
+int ddr3_check_window_limits(u32 pup, int high_limit, int low_limit, int is_tx,
+ int *size_valid);
+static int ddr3_center_calc(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx);
+int ddr3_special_pattern_i_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx, u32 special_pattern_pup);
+int ddr3_special_pattern_ii_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx, u32 special_pattern_pup);
+int ddr3_set_dqs_centralization_results(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx);
+
+#ifdef MV88F78X60
+extern u32 killer_pattern_32b[DQ_NUM][LEN_SPECIAL_PATTERN];
+extern u32 killer_pattern_64b[DQ_NUM][LEN_SPECIAL_PATTERN];
+extern int per_bit_data[MAX_PUP_NUM][DQ_NUM];
+#else
+extern u32 killer_pattern[DQ_NUM][LEN_16BIT_KILLER_PATTERN];
+extern u32 killer_pattern_32b[DQ_NUM][LEN_SPECIAL_PATTERN];
+#if defined(MV88F672X)
+extern int per_bit_data[MAX_PUP_NUM][DQ_NUM];
+#endif
+#endif
+extern u32 special_pattern[DQ_NUM][LEN_SPECIAL_PATTERN];
+
+static u32 *ddr3_dqs_choose_pattern(MV_DRAM_INFO *dram_info, u32 victim_dq)
+{
+ u32 *pattern_ptr;
+
+ /* Choose pattern */
+ switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+ case 16:
+ pattern_ptr = (u32 *)&killer_pattern[victim_dq];
+ break;
+#endif
+ case 32:
+ pattern_ptr = (u32 *)&killer_pattern_32b[victim_dq];
+ break;
+#if defined(MV88F78X60)
+ case 64:
+ pattern_ptr = (u32 *)&killer_pattern_64b[victim_dq];
+ break;
+#endif
+ default:
+#if defined(MV88F78X60)
+ pattern_ptr = (u32 *)&killer_pattern_32b[victim_dq];
+#else
+ pattern_ptr = (u32 *)&killer_pattern[victim_dq];
+#endif
+ break;
+ }
+
+ return pattern_ptr;
+}
+
+/*
+ * Name: ddr3_dqs_centralization_rx
+ * Desc: Execute the DQS centralization RX phase.
+ * Args: dram_info
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_dqs_centralization_rx(MV_DRAM_INFO *dram_info)
+{
+ u32 cs, ecc, reg;
+ int status;
+
+ DEBUG_DQS_S("DDR3 - DQS Centralization RX - Starting procedure\n");
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_DQS_S("DDR3 - DQS Centralization RX - SW Override Enabled\n");
+
+ reg = (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ /* Loop for each CS */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ DEBUG_DQS_FULL_C("DDR3 - DQS Centralization RX - CS - ",
+ (u32) cs, 1);
+
+ for (ecc = 0; ecc < (dram_info->ecc_ena + 1); ecc++) {
+
+ /* ECC Support - Switch ECC Mux on ecc=1 */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg |= (dram_info->ecc_ena *
+ ecc << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ if (ecc)
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - ECC Mux Enabled\n");
+ else
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - ECC Mux Disabled\n");
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - Find all limits\n");
+
+ status = ddr3_find_adll_limits(dram_info, cs,
+ ecc, 0);
+ if (MV_OK != status)
+ return status;
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - Start calculating center\n");
+
+ status = ddr3_center_calc(dram_info, cs, ecc,
+ 0);
+ if (MV_OK != status)
+ return status;
+ }
+ }
+ }
+
+ /* ECC Support - Disable ECC MUX */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+ (1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+ reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_dqs_centralization_tx
+ * Desc: Execute the DQS centralization TX phase.
+ * Args: dram_info
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_dqs_centralization_tx(MV_DRAM_INFO *dram_info)
+{
+ u32 cs, ecc, reg;
+ int status;
+
+ DEBUG_DQS_S("DDR3 - DQS Centralization TX - Starting procedure\n");
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_DQS_S("DDR3 - DQS Centralization TX - SW Override Enabled\n");
+
+ reg = (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ /* Loop for each CS */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ DEBUG_DQS_FULL_C("DDR3 - DQS Centralization TX - CS - ",
+ (u32) cs, 1);
+ for (ecc = 0; ecc < (dram_info->ecc_ena + 1); ecc++) {
+ /* ECC Support - Switch ECC Mux on ecc=1 */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg |= (dram_info->ecc_ena *
+ ecc << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ if (ecc)
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - ECC Mux Enabled\n");
+ else
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - ECC Mux Disabled\n");
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - Find all limits\n");
+
+ status = ddr3_find_adll_limits(dram_info, cs,
+ ecc, 1);
+ if (MV_OK != status)
+ return status;
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - Start calculating center\n");
+
+ status = ddr3_center_calc(dram_info, cs, ecc,
+ 1);
+ if (MV_OK != status)
+ return status;
+ }
+ }
+ }
+
+ /* ECC Support - Disable ECC MUX */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+ (1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+ reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_find_adll_limits
+ * Desc: Execute the Find ADLL limits phase.
+ * Args: dram_info
+ * cs
+ * ecc_ena
+ * is_tx Indicate whether Rx or Tx
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_find_adll_limits(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc, int is_tx)
+{
+ u32 victim_dq, pup, tmp;
+ u32 adll_addr;
+ u32 max_pup; /* maximal pup index */
+ u32 pup_mask = 0;
+ u32 unlock_pup; /* bit array of un locked pups */
+ u32 new_unlock_pup; /* bit array of compare failed pups */
+ u32 curr_adll;
+ u32 adll_start_val; /* adll start loop value - for rx or tx limit */
+ u32 high_limit; /* holds found High Limit */
+ u32 low_limit; /* holds found Low Limit */
+ int win_valid;
+ int update_win;
+ u32 sdram_offset;
+ u32 uj, cs_count, cs_tmp, ii;
+ u32 *pattern_ptr;
+ u32 dq;
+ u32 adll_end_val; /* adll end of loop val - for rx or tx limit */
+ u8 analog_pbs[DQ_NUM][MAX_PUP_NUM][DQ_NUM][2];
+ u8 analog_pbs_sum[MAX_PUP_NUM][DQ_NUM][2];
+ int pup_adll_limit_state[MAX_PUP_NUM]; /* hold state of each pup */
+
+ adll_addr = ((is_tx == 1) ? PUP_DQS_WR : PUP_DQS_RD);
+ adll_end_val = ((is_tx == 1) ? ADLL_MIN : ADLL_MAX);
+ adll_start_val = ((is_tx == 1) ? ADLL_MAX : ADLL_MIN);
+ max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Find Limits - Starting Find ADLL Limits\n");
+
+ /* init the array */
+ for (pup = 0; pup < max_pup; pup++) {
+ centralization_low_limit[pup] = ADLL_MIN;
+ centralization_high_limit[pup] = ADLL_MAX;
+ }
+
+ /* Killer Pattern */
+ cs_count = 0;
+ for (cs_tmp = 0; cs_tmp < cs; cs_tmp++) {
+ if (dram_info->cs_ena & (1 << cs_tmp))
+ cs_count++;
+ }
+ sdram_offset = cs_count * (SDRAM_CS_SIZE + 1);
+ sdram_offset += ((is_tx == 1) ?
+ SDRAM_DQS_TX_OFFS : SDRAM_DQS_RX_OFFS);
+
+ /* Prepare pup masks */
+ for (pup = 0; pup < max_pup; pup++)
+ pup_mask |= (1 << pup);
+
+ for (pup = 0; pup < max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ analog_pbs_sum[pup][dq][0] = adll_start_val;
+ analog_pbs_sum[pup][dq][1] = adll_end_val;
+ }
+ }
+
+ /* Loop - use different pattern for each victim_dq */
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - Victim DQ - ",
+ (u32)victim_dq, 1);
+ /*
+ * The pups 3 bit arrays represent state machine. with
+ * 3 stages for each pup.
+ * 1. fail and didn't get pass in earlier compares.
+ * 2. pass compare
+ * 3. fail after pass - end state.
+ * The window limits are the adll values where the adll
+ * was in the pass stage.
+ */
+
+ /* Set all states to Fail (1st state) */
+ for (pup = 0; pup < max_pup; pup++)
+ pup_adll_limit_state[pup] = PUP_ADLL_LIMITS_STATE_FAIL;
+
+ /* Set current valid pups */
+ unlock_pup = pup_mask;
+
+ /* Set ADLL to start value */
+ curr_adll = adll_start_val;
+
+#if defined(MV88F78X60)
+ for (pup = 0; pup < max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ analog_pbs[victim_dq][pup][dq][0] =
+ adll_start_val;
+ analog_pbs[victim_dq][pup][dq][1] =
+ adll_end_val;
+ per_bit_data[pup][dq] = 0;
+ }
+ }
+#endif
+
+ for (uj = 0; uj < ADLL_MAX; uj++) {
+ DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - Setting ADLL to ",
+ curr_adll, 2);
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ tmp = ((is_tx == 1) ? curr_adll +
+ dram_info->wl_val[cs]
+ [pup * (1 - ecc) + ecc * ECC_PUP]
+ [D] : curr_adll);
+ ddr3_write_pup_reg(adll_addr, cs, pup +
+ (ecc * ECC_PUP), 0, tmp);
+ }
+ }
+
+ /* Choose pattern */
+ pattern_ptr = ddr3_dqs_choose_pattern(dram_info,
+ victim_dq);
+
+ /* '1' - means pup failed, '0' - means pup pass */
+ new_unlock_pup = 0;
+
+ /* Read and compare results for Victim_DQ# */
+ for (ii = 0; ii < 3; ii++) {
+ u32 tmp = 0;
+ if (MV_OK != ddr3_sdram_dqs_compare(dram_info,
+ unlock_pup, &tmp,
+ pattern_ptr,
+ LEN_KILLER_PATTERN,
+ sdram_offset +
+ LEN_KILLER_PATTERN *
+ 4 * victim_dq,
+ is_tx, 0, NULL,
+ 0))
+ return MV_DDR3_TRAINING_ERR_DRAM_COMPARE;
+
+ new_unlock_pup |= tmp;
+ }
+
+ pup = 0;
+ DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - UnlockPup: ",
+ unlock_pup, 2);
+ DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - NewUnlockPup: ",
+ new_unlock_pup, 2);
+
+ /* Update pup state */
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 0) {
+ DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - Skipping pup ",
+ pup, 1);
+ continue;
+ }
+
+ /*
+ * Still didn't find the window limit of the pup
+ */
+ if (IS_PUP_ACTIVE(new_unlock_pup, pup) == 1) {
+ /* Current compare result == fail */
+ if (pup_adll_limit_state[pup] ==
+ PUP_ADLL_LIMITS_STATE_PASS) {
+ /*
+ * If now it failed but passed
+ * earlier
+ */
+ DEBUG_DQS_S("DDR3 - DQS Find Limits - PASS to FAIL: CS - ");
+ DEBUG_DQS_D(cs, 1);
+ DEBUG_DQS_S(", DQ - ");
+ DEBUG_DQS_D(victim_dq, 1);
+ DEBUG_DQS_S(", Pup - ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_S(", ADLL - ");
+ DEBUG_DQS_D(curr_adll, 2);
+ DEBUG_DQS_S("\n");
+
+#if defined(MV88F78X60)
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ if ((analog_pbs[victim_dq][pup][dq][0] != adll_start_val)
+ && (analog_pbs[victim_dq][pup]
+ [dq][1] == adll_end_val))
+ analog_pbs
+ [victim_dq]
+ [pup][dq]
+ [1] =
+ curr_adll;
+ }
+#endif
+ win_valid = 1;
+ update_win = 0;
+
+ /* Keep min / max limit value */
+ if (is_tx == 0) {
+ /* RX - found upper limit */
+ if (centralization_high_limit[pup] >
+ (curr_adll - 1)) {
+ high_limit =
+ curr_adll - 1;
+ low_limit =
+ centralization_low_limit[pup];
+ update_win = 1;
+ }
+ } else {
+ /* TX - found lower limit */
+ if (centralization_low_limit[pup] < (curr_adll + 1)) {
+ high_limit =
+ centralization_high_limit
+ [pup];
+ low_limit =
+ curr_adll + 1;
+ update_win =
+ 1;
+ }
+ }
+
+ if (update_win == 1) {
+ /*
+ * Before updating
+ * window limits we need
+ * to check that the
+ * limits are valid
+ */
+ if (MV_OK !=
+ ddr3_check_window_limits
+ (pup, high_limit,
+ low_limit, is_tx,
+ &win_valid))
+ return MV_DDR3_TRAINING_ERR_WIN_LIMITS;
+
+ if (win_valid == 1) {
+ /*
+ * Window limits
+ * should be
+ * updated
+ */
+ centralization_low_limit
+ [pup] =
+ low_limit;
+ centralization_high_limit
+ [pup] =
+ high_limit;
+ }
+ }
+
+ if (win_valid == 1) {
+ /* Found end of window - lock the pup */
+ pup_adll_limit_state[pup] =
+ PUP_ADLL_LIMITS_STATE_FAIL_AFTER_PASS;
+ unlock_pup &= ~(1 << pup);
+ } else {
+ /* Probably false pass - reset status */
+ pup_adll_limit_state[pup] =
+ PUP_ADLL_LIMITS_STATE_FAIL;
+
+#if defined(MV88F78X60)
+ /* Clear logging array of win size (per Dq) */
+ for (dq = 0;
+ dq < DQ_NUM;
+ dq++) {
+ analog_pbs
+ [victim_dq]
+ [pup][dq]
+ [0] =
+ adll_start_val;
+ analog_pbs
+ [victim_dq]
+ [pup][dq]
+ [1] =
+ adll_end_val;
+ per_bit_data
+ [pup][dq]
+ = 0;
+ }
+#endif
+ }
+ }
+ } else {
+ /* Current compare result == pass */
+ if (pup_adll_limit_state[pup] ==
+ PUP_ADLL_LIMITS_STATE_FAIL) {
+ /* If now it passed but failed earlier */
+ DEBUG_DQS_S("DDR3 - DQS Find Limits - FAIL to PASS: CS - ");
+ DEBUG_DQS_D(cs, 1);
+ DEBUG_DQS_S(", DQ - ");
+ DEBUG_DQS_D(victim_dq, 1);
+ DEBUG_DQS_S(", Pup - ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_S(", ADLL - ");
+ DEBUG_DQS_D(curr_adll, 2);
+ DEBUG_DQS_S("\n");
+
+#if defined(MV88F78X60)
+ for (dq = 0; dq < DQ_NUM;
+ dq++) {
+ if (analog_pbs[victim_dq][pup][dq][0] == adll_start_val)
+ analog_pbs
+ [victim_dq]
+ [pup][dq]
+ [0] =
+ curr_adll;
+ }
+#endif
+ /* Found start of window */
+ pup_adll_limit_state[pup] =
+ PUP_ADLL_LIMITS_STATE_PASS;
+
+ /* Keep min / max limit value */
+ if (is_tx == 0) {
+ /* RX - found low limit */
+ if (centralization_low_limit[pup] <= curr_adll)
+ centralization_low_limit
+ [pup] =
+ curr_adll;
+ } else {
+ /* TX - found high limit */
+ if (centralization_high_limit[pup] >= curr_adll)
+ centralization_high_limit
+ [pup] =
+ curr_adll;
+ }
+ }
+ }
+ }
+
+ if (unlock_pup == 0) {
+ /* Found limit to all pups */
+ DEBUG_DQS_FULL_S("DDR3 - DQS Find Limits - found PUP limit\n");
+ break;
+ }
+
+ /*
+ * Increment / decrement (Move to right / left
+ * one phase - ADLL) dqs RX / TX delay (for all un
+ * lock pups
+ */
+ if (is_tx == 0)
+ curr_adll++;
+ else
+ curr_adll--;
+ }
+
+ if (unlock_pup != 0) {
+ /*
+ * Found pups that didn't reach to the end of the
+ * state machine
+ */
+ DEBUG_DQS_C("DDR3 - DQS Find Limits - Pups that didn't reached end of the state machine: ",
+ unlock_pup, 1);
+
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ if (pup_adll_limit_state[pup] ==
+ PUP_ADLL_LIMITS_STATE_FAIL) {
+ /* ERROR - found fail for all window size */
+ DEBUG_DQS_S("DDR3 - DQS Find Limits - Got FAIL for the complete range on pup - ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_C(" victim DQ ",
+ victim_dq, 1);
+
+ /* For debug - set min limit to illegal limit */
+ centralization_low_limit[pup]
+ = ADLL_ERROR;
+ /*
+ * In case the pup is in mode
+ * PASS - the limit is the min
+ * / max adll, no need to
+ * update because of the results
+ * array default value
+ */
+ return MV_DDR3_TRAINING_ERR_PUP_RANGE;
+ }
+ }
+ }
+ }
+ }
+
+ DEBUG_DQS_S("DDR3 - DQS Find Limits - DQ values per victim results:\n");
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ for (pup = 0; pup < max_pup; pup++) {
+ DEBUG_DQS_S("Victim DQ-");
+ DEBUG_DQS_D(victim_dq, 1);
+ DEBUG_DQS_S(", PUP-");
+ DEBUG_DQS_D(pup, 1);
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ DEBUG_DQS_S(", DQ-");
+ DEBUG_DQS_D(dq, 1);
+ DEBUG_DQS_S(",S-");
+ DEBUG_DQS_D(analog_pbs[victim_dq][pup][dq]
+ [0], 2);
+ DEBUG_DQS_S(",E-");
+ DEBUG_DQS_D(analog_pbs[victim_dq][pup][dq]
+ [1], 2);
+
+ if (is_tx == 0) {
+ if (analog_pbs[victim_dq][pup][dq][0]
+ > analog_pbs_sum[pup][dq][0])
+ analog_pbs_sum[pup][dq][0] =
+ analog_pbs[victim_dq][pup]
+ [dq][0];
+ if (analog_pbs[victim_dq][pup][dq][1]
+ < analog_pbs_sum[pup][dq][1])
+ analog_pbs_sum[pup][dq][1] =
+ analog_pbs[victim_dq][pup]
+ [dq][1];
+ } else {
+ if (analog_pbs[victim_dq][pup][dq][0]
+ < analog_pbs_sum[pup][dq][0])
+ analog_pbs_sum[pup][dq][0] =
+ analog_pbs[victim_dq][pup]
+ [dq][0];
+ if (analog_pbs[victim_dq][pup][dq][1]
+ > analog_pbs_sum[pup][dq][1])
+ analog_pbs_sum[pup][dq][1] =
+ analog_pbs[victim_dq][pup]
+ [dq][1];
+ }
+ }
+ DEBUG_DQS_S("\n");
+ }
+ }
+
+ if (ddr3_get_log_level() >= MV_LOG_LEVEL_3) {
+ u32 dq;
+
+ DEBUG_PER_DQ_S("\n########## LOG LEVEL 3(Windows margins per-DQ) ##########\n");
+ if (is_tx) {
+ DEBUG_PER_DQ_C("DDR3 - TX CS: ", cs, 1);
+ } else {
+ DEBUG_PER_DQ_C("DDR3 - RX CS: ", cs, 1);
+ }
+
+ if (ecc == 0) {
+ DEBUG_PER_DQ_S("\n DATA RESULTS:\n");
+ } else {
+ DEBUG_PER_DQ_S("\n ECC RESULTS:\n");
+ }
+
+ /* Since all dq has the same value we take 0 as representive */
+ dq = 0;
+ for (pup = 0; pup < max_pup; pup++) {
+ if (ecc == 0) {
+ DEBUG_PER_DQ_S("\nBYTE:");
+ DEBUG_PER_DQ_D(pup, 1);
+ DEBUG_PER_DQ_S("\n");
+ } else {
+ DEBUG_PER_DQ_S("\nECC BYTE:\n");
+ }
+ DEBUG_PER_DQ_S(" DQ's LOW HIGH WIN-SIZE\n");
+ DEBUG_PER_DQ_S("============================================\n");
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ if (ecc == 0) {
+ DEBUG_PER_DQ_S("DQ[");
+ DEBUG_PER_DQ_DD((victim_dq +
+ DQ_NUM * pup), 2);
+ DEBUG_PER_DQ_S("]");
+ } else {
+ DEBUG_PER_DQ_S("CB[");
+ DEBUG_PER_DQ_DD(victim_dq, 2);
+ DEBUG_PER_DQ_S("]");
+ }
+ if (is_tx) {
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][1], 2); /* low value */
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][0], 2); /* high value */
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][0] - analog_pbs[victim_dq][pup][dq][1], 2); /* win-size */
+ } else {
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][0], 2); /* low value */
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D((analog_pbs[victim_dq][pup][dq][1] - 1), 2); /* high value */
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][1] - analog_pbs[victim_dq][pup][dq][0], 2); /* win-size */
+ }
+ DEBUG_PER_DQ_S("\n");
+ }
+ }
+ DEBUG_PER_DQ_S("\n");
+ }
+
+ if (is_tx) {
+ DEBUG_DQS_S("DDR3 - DQS TX - Find Limits - DQ values Summary:\n");
+ } else {
+ DEBUG_DQS_S("DDR3 - DQS RX - Find Limits - DQ values Summary:\n");
+ }
+
+ for (pup = 0; pup < max_pup; pup++) {
+ DEBUG_DQS_S("PUP-");
+ DEBUG_DQS_D(pup, 1);
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ DEBUG_DQS_S(", DQ-");
+ DEBUG_DQS_D(dq, 1);
+ DEBUG_DQS_S(",S-");
+ DEBUG_DQS_D(analog_pbs_sum[pup][dq][0], 2);
+ DEBUG_DQS_S(",E-");
+ DEBUG_DQS_D(analog_pbs_sum[pup][dq][1], 2);
+ }
+ DEBUG_DQS_S("\n");
+ }
+
+ if (is_tx) {
+ DEBUG_DQS_S("DDR3 - DQS TX - Find Limits - DQ values Summary:\n");
+ } else {
+ DEBUG_DQS_S("DDR3 - DQS RX - Find Limits - DQ values Summary:\n");
+ }
+
+ for (pup = 0; pup < max_pup; pup++) {
+ if (max_pup == 1) {
+ /* For ECC PUP */
+ DEBUG_DQS_S("DDR3 - DQS8");
+ } else {
+ DEBUG_DQS_S("DDR3 - DQS");
+ DEBUG_DQS_D(pup, 1);
+ }
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ DEBUG_DQS_S(", DQ-");
+ DEBUG_DQS_D(dq, 1);
+ DEBUG_DQS_S("::S-");
+ DEBUG_DQS_D(analog_pbs_sum[pup][dq][0], 2);
+ DEBUG_DQS_S(",E-");
+ DEBUG_DQS_D(analog_pbs_sum[pup][dq][1], 2);
+ }
+ DEBUG_DQS_S("\n");
+ }
+
+ DEBUG_DQS_S("DDR3 - DQS Find Limits - Ended\n");
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_check_window_limits
+ * Desc: Check window High & Low limits.
+ * Args: pup pup index
+ * high_limit window high limit
+ * low_limit window low limit
+ * is_tx Indicate whether Rx or Tx
+ * size_valid Indicate whether window size is valid
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_check_window_limits(u32 pup, int high_limit, int low_limit, int is_tx,
+ int *size_valid)
+{
+ DEBUG_DQS_FULL_S("DDR3 - DQS Check Win Limits - Starting\n");
+
+ if (low_limit > high_limit) {
+ DEBUG_DQS_S("DDR3 - DQS Check Win Limits - Pup ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_S(" Low Limit grater than High Limit\n");
+ *size_valid = 0;
+ return MV_OK;
+ }
+
+ /*
+ * Check that window size is valid, if not it was probably false pass
+ * before
+ */
+ if ((high_limit - low_limit) < MIN_WIN_SIZE) {
+ /*
+ * Since window size is too small probably there was false
+ * pass
+ */
+ *size_valid = 0;
+
+ DEBUG_DQS_S("DDR3 - DQS Check Win Limits - Pup ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_S(" Window size is smaller than MIN_WIN_SIZE\n");
+
+ } else if ((high_limit - low_limit) > ADLL_MAX) {
+ *size_valid = 0;
+
+ DEBUG_DQS_S("DDR3 - DQS Check Win Limits - Pup ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_S
+ (" Window size is bigger than max ADLL taps (31) Exiting.\n");
+
+ return MV_FAIL;
+
+ } else {
+ *size_valid = 1;
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Check Win Limits - Pup ");
+ DEBUG_DQS_FULL_D(pup, 1);
+ DEBUG_DQS_FULL_C(" window size is ", (high_limit - low_limit),
+ 2);
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_center_calc
+ * Desc: Execute the calculate the center of windows phase.
+ * Args: pDram Info
+ * is_tx Indicate whether Rx or Tx
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+static int ddr3_center_calc(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx)
+{
+ /* bit array of pups that need specail search */
+ u32 special_pattern_i_pup = 0;
+ u32 special_pattern_ii_pup = 0;
+ u32 pup;
+ u32 max_pup;
+
+ max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+ for (pup = 0; pup < max_pup; pup++) {
+ if (is_tx == 0) {
+ /* Check special pattern I */
+ /*
+ * Special pattern Low limit search - relevant only
+ * for Rx, win size < threshold and low limit = 0
+ */
+ if (((centralization_high_limit[pup] -
+ centralization_low_limit[pup]) < VALID_WIN_THRS)
+ && (centralization_low_limit[pup] == MIN_DELAY))
+ special_pattern_i_pup |= (1 << pup);
+
+ /* Check special pattern II */
+ /*
+ * Special pattern High limit search - relevant only
+ * for Rx, win size < threshold and high limit = 31
+ */
+ if (((centralization_high_limit[pup] -
+ centralization_low_limit[pup]) < VALID_WIN_THRS)
+ && (centralization_high_limit[pup] == MAX_DELAY))
+ special_pattern_ii_pup |= (1 << pup);
+ }
+ }
+
+ /* Run special pattern Low limit search - for relevant pup */
+ if (special_pattern_i_pup != 0) {
+ DEBUG_DQS_S("DDR3 - DQS Center Calc - Entering special pattern I for Low limit search\n");
+ if (MV_OK !=
+ ddr3_special_pattern_i_search(dram_info, cs, ecc, is_tx,
+ special_pattern_i_pup))
+ return MV_DDR3_TRAINING_ERR_DQS_LOW_LIMIT_SEARCH;
+ }
+
+ /* Run special pattern High limit search - for relevant pup */
+ if (special_pattern_ii_pup != 0) {
+ DEBUG_DQS_S("DDR3 - DQS Center Calc - Entering special pattern II for High limit search\n");
+ if (MV_OK !=
+ ddr3_special_pattern_ii_search(dram_info, cs, ecc, is_tx,
+ special_pattern_ii_pup))
+ return MV_DDR3_TRAINING_ERR_DQS_HIGH_LIMIT_SEARCH;
+ }
+
+ /* Set adll to center = (General_High_limit + General_Low_limit)/2 */
+ return ddr3_set_dqs_centralization_results(dram_info, cs, ecc, is_tx);
+}
+
+/*
+ * Name: ddr3_special_pattern_i_search
+ * Desc: Execute special pattern low limit search.
+ * Args:
+ * special_pattern_pup The pups that need the special search
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_special_pattern_i_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx, u32 special_pattern_pup)
+{
+ u32 victim_dq; /* loop index - victim DQ */
+ u32 adll_idx;
+ u32 pup;
+ u32 unlock_pup; /* bit array of the unlock pups */
+ u32 first_fail; /* bit array - of pups that get first fail */
+ u32 new_lockup_pup; /* bit array of compare failed pups */
+ u32 pass_pup; /* bit array of compare pass pup */
+ u32 sdram_offset;
+ u32 max_pup;
+ u32 comp_val;
+ u32 special_res[MAX_PUP_NUM]; /* hold tmp results */
+
+ DEBUG_DQS_S("DDR3 - DQS - Special Pattern I Search - Starting\n");
+
+ max_pup = ecc + (1 - ecc) * dram_info->num_of_std_pups;
+
+ /* Init the temporary results to max ADLL value */
+ for (pup = 0; pup < max_pup; pup++)
+ special_res[pup] = ADLL_MAX;
+
+ /* Run special pattern for all DQ - use the same pattern */
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ unlock_pup = special_pattern_pup;
+ first_fail = 0;
+
+ sdram_offset = cs * SDRAM_CS_SIZE + SDRAM_DQS_RX_OFFS +
+ LEN_KILLER_PATTERN * 4 * victim_dq;
+
+ for (pup = 0; pup < max_pup; pup++) {
+ /* Set adll value per PUP. adll = high limit per pup */
+ if (IS_PUP_ACTIVE(unlock_pup, pup)) {
+ /* only for pups that need special search */
+ ddr3_write_pup_reg(PUP_DQS_RD, cs,
+ pup + (ecc * ECC_PUP), 0,
+ centralization_high_limit
+ [pup]);
+ }
+ }
+
+ adll_idx = 0;
+ do {
+ /*
+ * Perform read and compare simultaneously for all
+ * un-locked MC use the special pattern mask
+ */
+ new_lockup_pup = 0;
+
+ if (MV_OK !=
+ ddr3_sdram_dqs_compare(dram_info, unlock_pup,
+ &new_lockup_pup,
+ special_pattern
+ [victim_dq],
+ LEN_SPECIAL_PATTERN,
+ sdram_offset, 0,
+ 0, NULL, 1))
+ return MV_FAIL;
+
+ DEBUG_DQS_S("DDR3 - DQS - Special I - ADLL value is: ");
+ DEBUG_DQS_D(adll_idx, 2);
+ DEBUG_DQS_S(", UnlockPup: ");
+ DEBUG_DQS_D(unlock_pup, 2);
+ DEBUG_DQS_S(", NewLockPup: ");
+ DEBUG_DQS_D(new_lockup_pup, 2);
+ DEBUG_DQS_S("\n");
+
+ if (unlock_pup != new_lockup_pup)
+ DEBUG_DQS_S("DDR3 - DQS - Special I - Some Pup passed!\n");
+
+ /* Search for pups with passed compare & already fail */
+ pass_pup = first_fail & ~new_lockup_pup & unlock_pup;
+ first_fail |= new_lockup_pup;
+ unlock_pup &= ~pass_pup;
+
+ /* Get pass pups */
+ if (pass_pup != 0) {
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(pass_pup, pup) ==
+ 1) {
+ /* If pup passed and has first fail = 1 */
+ /* keep min value of ADLL max value - current adll */
+ /* (centralization_high_limit[pup] + adll_idx) = current adll !!! */
+ comp_val =
+ (ADLL_MAX -
+ (centralization_high_limit
+ [pup] + adll_idx));
+
+ DEBUG_DQS_C
+ ("DDR3 - DQS - Special I - Pup - ",
+ pup, 1);
+ DEBUG_DQS_C
+ (" comp_val = ",
+ comp_val, 2);
+
+ if (comp_val <
+ special_res[pup]) {
+ special_res[pup] =
+ comp_val;
+ centralization_low_limit
+ [pup] =
+ (-1) *
+ comp_val;
+
+ DEBUG_DQS_C
+ ("DDR3 - DQS - Special I - Pup - ",
+ pup, 1);
+ DEBUG_DQS_C
+ (" Changed Low limit to ",
+ centralization_low_limit
+ [pup], 2);
+ }
+ }
+ }
+ }
+
+ /*
+ * Did all PUP found missing window?
+ * Check for each pup if adll (different for each pup)
+ * reach maximum if reach max value - lock the pup
+ * if not - increment (Move to right one phase - ADLL)
+ * dqs RX delay
+ */
+ adll_idx++;
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ /* Check only unlocked pups */
+ if ((centralization_high_limit[pup] +
+ adll_idx) >= ADLL_MAX) {
+ /* reach maximum - lock the pup */
+ DEBUG_DQS_C("DDR3 - DQS - Special I - reach maximum - lock pup ",
+ pup, 1);
+ unlock_pup &= ~(1 << pup);
+ } else {
+ /* Didn't reach maximum - increment ADLL */
+ ddr3_write_pup_reg(PUP_DQS_RD,
+ cs,
+ pup +
+ (ecc *
+ ECC_PUP), 0,
+ (centralization_high_limit
+ [pup] +
+ adll_idx));
+ }
+ }
+ }
+ } while (unlock_pup != 0);
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_special_pattern_ii_search
+ * Desc: Execute special pattern high limit search.
+ * Args:
+ * special_pattern_pup The pups that need the special search
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_special_pattern_ii_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx, u32 special_pattern_pup)
+{
+ u32 victim_dq; /* loop index - victim DQ */
+ u32 adll_idx;
+ u32 pup;
+ u32 unlock_pup; /* bit array of the unlock pups */
+ u32 first_fail; /* bit array - of pups that get first fail */
+ u32 new_lockup_pup; /* bit array of compare failed pups */
+ u32 pass_pup; /* bit array of compare pass pup */
+ u32 sdram_offset;
+ u32 max_pup;
+ u32 comp_val;
+ u32 special_res[MAX_PUP_NUM]; /* hold tmp results */
+
+ DEBUG_DQS_S("DDR3 - DQS - Special Pattern II Search - Starting\n");
+
+ max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+ /* init the tmporary results to max ADLL value */
+ for (pup = 0; pup < max_pup; pup++)
+ special_res[pup] = ADLL_MAX;
+
+ sdram_offset = cs * SDRAM_CS_SIZE + SDRAM_DQS_RX_OFFS;
+
+ /* run special pattern for all DQ - use the same pattern */
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ unlock_pup = special_pattern_pup;
+ first_fail = 0;
+
+ for (pup = 0; pup < max_pup; pup++) {
+ /* Set adll value per PUP. adll = 0 */
+ if (IS_PUP_ACTIVE(unlock_pup, pup)) {
+ /* Only for pups that need special search */
+ ddr3_write_pup_reg(PUP_DQS_RD, cs,
+ pup + (ecc * ECC_PUP), 0,
+ ADLL_MIN);
+ }
+ }
+
+ adll_idx = 0;
+ do {
+ /*
+ * Perform read and compare simultaneously for all
+ * un-locked MC use the special pattern mask
+ */
+ new_lockup_pup = 0;
+
+ if (MV_OK != ddr3_sdram_dqs_compare(
+ dram_info, unlock_pup, &new_lockup_pup,
+ special_pattern[victim_dq],
+ LEN_SPECIAL_PATTERN,
+ sdram_offset, 0, 0, NULL, 0))
+ return MV_FAIL;
+
+ DEBUG_DQS_S("DDR3 - DQS - Special II - ADLL value is ");
+ DEBUG_DQS_D(adll_idx, 2);
+ DEBUG_DQS_S("unlock_pup ");
+ DEBUG_DQS_D(unlock_pup, 1);
+ DEBUG_DQS_S("new_lockup_pup ");
+ DEBUG_DQS_D(new_lockup_pup, 1);
+ DEBUG_DQS_S("\n");
+
+ if (unlock_pup != new_lockup_pup) {
+ DEBUG_DQS_S("DDR3 - DQS - Special II - Some Pup passed!\n");
+ }
+
+ /* Search for pups with passed compare & already fail */
+ pass_pup = first_fail & ~new_lockup_pup & unlock_pup;
+ first_fail |= new_lockup_pup;
+ unlock_pup &= ~pass_pup;
+
+ /* Get pass pups */
+ if (pass_pup != 0) {
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(pass_pup, pup) ==
+ 1) {
+ /* If pup passed and has first fail = 1 */
+ /* keep min value of ADLL max value - current adll */
+ /* (adll_idx) = current adll !!! */
+ comp_val = adll_idx;
+
+ DEBUG_DQS_C("DDR3 - DQS - Special II - Pup - ",
+ pup, 1);
+ DEBUG_DQS_C(" comp_val = ",
+ comp_val, 1);
+
+ if (comp_val <
+ special_res[pup]) {
+ special_res[pup] =
+ comp_val;
+ centralization_high_limit
+ [pup] =
+ ADLL_MAX +
+ comp_val;
+
+ DEBUG_DQS_C
+ ("DDR3 - DQS - Special II - Pup - ",
+ pup, 1);
+ DEBUG_DQS_C
+ (" Changed High limit to ",
+ centralization_high_limit
+ [pup], 2);
+ }
+ }
+ }
+ }
+
+ /*
+ * Did all PUP found missing window?
+ * Check for each pup if adll (different for each pup)
+ * reach maximum if reach max value - lock the pup
+ * if not - increment (Move to right one phase - ADLL)
+ * dqs RX delay
+ */
+ adll_idx++;
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ /* Check only unlocked pups */
+ if ((adll_idx) >= ADLL_MAX) {
+ /* Reach maximum - lock the pup */
+ DEBUG_DQS_C("DDR3 - DQS - Special II - reach maximum - lock pup ",
+ pup, 1);
+ unlock_pup &= ~(1 << pup);
+ } else {
+ /* Didn't reach maximum - increment ADLL */
+ ddr3_write_pup_reg(PUP_DQS_RD,
+ cs,
+ pup +
+ (ecc *
+ ECC_PUP), 0,
+ (adll_idx));
+ }
+ }
+ }
+ } while (unlock_pup != 0);
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_set_dqs_centralization_results
+ * Desc: Set to HW the DQS centralization phase results.
+ * Args:
+ * is_tx Indicates whether to set Tx or RX results
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_set_dqs_centralization_results(MV_DRAM_INFO *dram_info, u32 cs,
+ u32 ecc, int is_tx)
+{
+ u32 pup, pup_num;
+ int addl_val;
+ u32 max_pup;
+
+ max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+ DEBUG_DQS_RESULTS_S("\n############ LOG LEVEL 2(Windows margins) ############\n");;
+
+ if (is_tx) {
+ DEBUG_DQS_RESULTS_C("DDR3 - DQS TX - Set Dqs Centralization Results - CS: ",
+ cs, 1);
+ } else {
+ DEBUG_DQS_RESULTS_C("DDR3 - DQS RX - Set Dqs Centralization Results - CS: ",
+ cs, 1);
+ }
+
+ /* Set adll to center = (General_High_limit + General_Low_limit)/2 */
+ DEBUG_DQS_RESULTS_S("\nDQS LOW HIGH WIN-SIZE Set\n");
+ DEBUG_DQS_RESULTS_S("==============================================\n");
+ for (pup = 0; pup < max_pup; pup++) {
+ addl_val = (centralization_high_limit[pup] +
+ centralization_low_limit[pup]) / 2;
+
+ pup_num = pup * (1 - ecc) + ecc * ECC_PUP;
+
+ DEBUG_DQS_RESULTS_D(pup_num, 1);
+ DEBUG_DQS_RESULTS_S(" 0x");
+ DEBUG_DQS_RESULTS_D(centralization_low_limit[pup], 2);
+ DEBUG_DQS_RESULTS_S(" 0x");
+ DEBUG_DQS_RESULTS_D(centralization_high_limit[pup], 2);
+ DEBUG_DQS_RESULTS_S(" 0x");
+ DEBUG_DQS_RESULTS_D(centralization_high_limit[pup] -
+ centralization_low_limit[pup], 2);
+ DEBUG_DQS_RESULTS_S(" 0x");
+ DEBUG_DQS_RESULTS_D(addl_val, 2);
+ DEBUG_DQS_RESULTS_S("\n");
+
+ if (addl_val < ADLL_MIN) {
+ addl_val = ADLL_MIN;
+ DEBUG_DQS_RESULTS_S("DDR3 - DQS - Setting ADLL value for Pup to MIN (since it was lower than 0)\n");
+ }
+
+ if (addl_val > ADLL_MAX) {
+ addl_val = ADLL_MAX;
+ DEBUG_DQS_RESULTS_S("DDR3 - DQS - Setting ADLL value for Pup to MAX (since it was higher than 31)\n");
+ }
+
+ if (is_tx) {
+ ddr3_write_pup_reg(PUP_DQS_WR, cs, pup_num, 0,
+ addl_val +
+ dram_info->wl_val[cs][pup_num][D]);
+ } else {
+ ddr3_write_pup_reg(PUP_DQS_RD, cs, pup_num, 0,
+ addl_val);
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Set training patterns
+ */
+int ddr3_load_dqs_patterns(MV_DRAM_INFO *dram_info)
+{
+ u32 cs, cs_count, cs_tmp, victim_dq;
+ u32 sdram_addr;
+ u32 *pattern_ptr;
+
+ /* Loop for each CS */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ cs_count = 0;
+ for (cs_tmp = 0; cs_tmp < cs; cs_tmp++) {
+ if (dram_info->cs_ena & (1 << cs_tmp))
+ cs_count++;
+ }
+
+ /* Init killer pattern */
+ sdram_addr = (cs_count * (SDRAM_CS_SIZE + 1) +
+ SDRAM_DQS_RX_OFFS);
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ pattern_ptr = ddr3_dqs_choose_pattern(dram_info,
+ victim_dq);
+ if (MV_OK != ddr3_sdram_dqs_compare(
+ dram_info, (u32)NULL, NULL,
+ pattern_ptr, LEN_KILLER_PATTERN,
+ sdram_addr + LEN_KILLER_PATTERN *
+ 4 * victim_dq, 1, 0, NULL,
+ 0))
+ return MV_DDR3_TRAINING_ERR_DQS_PATTERN;
+ }
+
+ /* Init special-killer pattern */
+ sdram_addr = (cs_count * (SDRAM_CS_SIZE + 1) +
+ SDRAM_DQS_RX_SPECIAL_OFFS);
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ if (MV_OK != ddr3_sdram_dqs_compare(
+ dram_info, (u32)NULL, NULL,
+ special_pattern[victim_dq],
+ LEN_KILLER_PATTERN, sdram_addr +
+ LEN_KILLER_PATTERN * 4 * victim_dq,
+ 1, 0, NULL, 0))
+ return MV_DDR3_TRAINING_ERR_DQS_PATTERN;
+ }
+ }
+ }
+
+ return MV_OK;
+}