in drivers/ddr/marvell/axp/ddr3_dqs.c [296:816]
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;
}