Angel Pons has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/34865 )
Change subject: [TESTONLY, DONOTMERGE] nb/gm45/rcven: Fill to the brim with spam ......................................................................
[TESTONLY, DONOTMERGE] nb/gm45/rcven: Fill to the brim with spam
Change-Id: I4de1d7fc70877c11c37549cf1d723cbdcc6b1910 Signed-off-by: Angel Pons th3fanbus@gmail.com --- M src/northbridge/intel/gm45/raminit_receive_enable_calibration.c 1 file changed, 162 insertions(+), 27 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/65/34865/1
diff --git a/src/northbridge/intel/gm45/raminit_receive_enable_calibration.c b/src/northbridge/intel/gm45/raminit_receive_enable_calibration.c index 7c7f56d..0385160 100644 --- a/src/northbridge/intel/gm45/raminit_receive_enable_calibration.c +++ b/src/northbridge/intel/gm45/raminit_receive_enable_calibration.c @@ -42,6 +42,7 @@ #define CxDRT3_C_SHIFT 7 #define CxDRT3_C_MASK (0xf << CxDRT3_C_SHIFT) #define CxDRT3_C(c) ((c << CxDRT3_C_SHIFT) & CxDRT3_C_MASK) + /* group to byte-lane mapping: (cardF X group X 2 per group) */ static const char bytelane_map[2][4][2] = { /* A,B,C */{ { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 } }, @@ -51,93 +52,156 @@ #define PH_BOUND 4 #define PH_STEP 2 #define PM_BOUND 3 -#define C_BOUND 16 +#define C_BOUND 16 typedef struct { - int c; - int pre; - int ph; - int t; + int c; // Coarse + int pre; // NOT! Preamble, per bytelane additional delay to Coarse + int ph; // Phase + int t; // TAP const int t_bound; - int p; + int p; // PI const int p_bound; } rec_timing_t; + +#define RCVEN_SPEW BIOS_DEBUG + +static void print_timings(int channel, int group, rec_timing_t timings[][4]) +{ + printk(RCVEN_SPEW, "ch %d, group %d: ", channel, group); + print_timing(&timings[channel][group]); +} + +static void print_timing(rec_timing_t *const timing) +{ + printk(RCVEN_SPEW, "\t%d.%d.%d.%d.%d\n", + timing->c, + timing->pre, + timing->ph, + timing->t, + timing->p + ); +} + static void normalize_rec_timing(rec_timing_t *const timing) { + unsigned int tmp = 0; + + printk(RCVEN_SPEW, "NORMALIZE START\n"); + while (timing->p >= timing->p_bound) { + tmp++; timing->t++; timing->p -= timing->p_bound; } + printk(RCVEN_SPEW, "\tafter %u t++: ", tmp); + print_timing(timing); + tmp = 0; + while (timing->p < 0) { + tmp++; timing->t--; timing->p += timing->p_bound; } + printk(RCVEN_SPEW, "\tafter %u t--: ", tmp); + print_timing(timing); + tmp = 0; + while (timing->t >= timing->t_bound) { + tmp++; timing->ph += PH_STEP; timing->t -= timing->t_bound; } + printk(RCVEN_SPEW, "\tafter %u ph++: " tmp); + print_timing(timing); + tmp = 0; + while (timing->t < 0) { + tmp++; timing->ph -= PH_STEP; timing->t += timing->t_bound; } + printk(RCVEN_SPEW, "\tafter %u ph--: ", tmp); + print_timing(timing); + tmp = 0; + while (timing->ph >= PH_BOUND) { + tmp++; timing->c++; timing->ph -= PH_BOUND; } + printk(RCVEN_SPEW, "\tafter %u c++: ", tmp); + print_timing(timing); + tmp = 0; + while (timing->ph < 0) { + tmp++; timing->c--; timing->ph += PH_BOUND; } - if (timing->c < 0 || timing->c >= C_BOUND) - die("Timing under-/overflow during " - "receive-enable calibration.\n"); + printk(RCVEN_SPEW, "\tafter %u c--: ", tmp); + print_timing(timing); + + if (timing->c < 0) + die("Timing under during receive-enable calibration.\n"); + + else if (timing->c >= C_BOUND) + die("Timing overflow during receive-enable calibration.\n"); + + printk(RCVEN_SPEW, "NORMALIZE END\n"); }
static void rec_full_backstep(rec_timing_t *const timing) { + printk(RCVEN_SPEW, "full backstep, "); timing->c--; } static void rec_half_backstep(rec_timing_t *const timing) { + printk(RCVEN_SPEW, "half backstep, "); timing->ph -= PH_STEP; } static void rec_quarter_step(rec_timing_t *const timing) { + printk(RCVEN_SPEW, "quarter step, "); timing->t += (timing->t_bound) >> 1; timing->p += (timing->t_bound & 1) * (timing->p_bound >> 1); } static void rec_quarter_backstep(rec_timing_t *const timing) { + printk(RCVEN_SPEW, "quarter backstep, "); timing->t -= (timing->t_bound) >> 1; timing->p -= (timing->t_bound & 1) * (timing->p_bound >> 1); } static void rec_smallest_step(rec_timing_t *const timing) { + printk(RCVEN_SPEW, "pi step, "); timing->p++; }
-static void program_timing(int channel, int group, - rec_timing_t timings[][4]) +static void program_timing(int channel, int group, rec_timing_t timings[][4]) { rec_timing_t *const timing = &timings[channel][group];
+ printk(RCVEN_SPEW, "%s: will normalize: ", __func__); + print_timing(timing); normalize_rec_timing(timing);
/* C value is per channel. */ unsigned int mchbar = CxDRT3_MCHBAR(channel); - MCHBAR32(mchbar) = (MCHBAR32(mchbar) & ~CxDRT3_C_MASK) | - CxDRT3_C(timing->c); + MCHBAR32(mchbar) = (MCHBAR32(mchbar) & ~CxDRT3_C_MASK) | CxDRT3_C(timing->c);
/* All other per group. */ mchbar = CxRECy_MCHBAR(channel, group); u32 reg = MCHBAR32(mchbar); reg &= ~CxRECy_TIMING_MASK; - reg |= CxRECy_T(timing->t) | CxRECy_P(timing->p) | - CxRECy_PH(timing->ph) | CxRECy_PM(timing->pre); + reg |= CxRECy_T(timing->t) | CxRECy_P(timing->p) | CxRECy_PH(timing->ph); + reg |= CxRECy_PM(timing->pre); MCHBAR32(mchbar) = reg; }
static int read_dqs_level(const int channel, const int lane) { + unsigned int mchbar = 0x14f0 + (channel * 0x0100); MCHBAR32(mchbar) &= ~(1 << 9); MCHBAR32(mchbar) |= (1 << 9); @@ -146,58 +210,97 @@ read32((u32 *)raminit_get_rank_addr(channel, 0));
mchbar = 0x14b0 + (channel * 0x0100) + ((7 - lane) * 4); - return MCHBAR32(mchbar) & (1 << 30); + + int level = MCHBAR32(mchbar) & (1 << 30); + + printk(RCVEN_SPEW, "DQS for channel %d lane %d: %s\n", + channel, lane, (level ? "HIGH" : "LOW"); + + return level; }
static void find_dqs_low(const int channel, const int group, rec_timing_t timings[][4], const char lane_map[][2]) { + printk(RCVEN_SPEW, "BEGIN %s\n" __func__); + + printk(RCVEN_SPEW, "Look for DQS low, using quarter steps.\n"); /* Look for DQS low, using quarter steps. */ while (read_dqs_level(channel, lane_map[group][0]) || read_dqs_level(channel, lane_map[group][1])) { + rec_quarter_step(&timings[channel][group]); + + printk(RCVEN_SPEW, "%s: program timings\n" __func__); program_timing(channel, group, timings); } + printk(RCVEN_SPEW, "FINISH %s\n" __func__); } static void find_dqs_high(const int channel, const int group, rec_timing_t timings[][4], const char lane_map[][2]) { + printk(RCVEN_SPEW, "BEGIN %s\n" __func__); /* Look for _any_ DQS high, using quarter steps. */ while (!read_dqs_level(channel, lane_map[group][0]) && !read_dqs_level(channel, lane_map[group][1])) { + rec_quarter_step(&timings[channel][group]); + + printk(RCVEN_SPEW, "%s: program timings\n" __func__); program_timing(channel, group, timings); } + printk(RCVEN_SPEW, "FINISH %s\n" __func__); } static void find_dqs_edge_lowhigh(const int channel, const int group, - rec_timing_t timings[][4], - const char lane_map[][2]) + rec_timing_t timings[][4], const char lane_map[][2]) { + printk(RCVEN_SPEW, "BEGIN %s\n" __func__); + + printk(RCVEN_SPEW, "Advance beyond previous high to low transition.\n"); /* Advance beyond previous high to low transition. */ timings[channel][group].t += 2; + + printk(RCVEN_SPEW, "%s: program timings\n" __func__); program_timing(channel, group, timings);
+ printk(RCVEN_SPEW, "Coarsely look for DQS high.\n"); /* Coarsely look for DQS high. */ find_dqs_high(channel, group, timings, lane_map);
+ printk(RCVEN_SPEW, "Go back.\n"); /* Go back and perform finer search. */ rec_quarter_backstep(&timings[channel][group]); + + printk(RCVEN_SPEW, "%s: program timings\n" __func__); program_timing(channel, group, timings); + + printk(RCVEN_SPEW, "Perform finer DQS high search.\n"); while (!read_dqs_level(channel, lane_map[group][0]) || !read_dqs_level(channel, lane_map[group][1])) { + rec_smallest_step(&timings[channel][group]); + + printk(RCVEN_SPEW, "%s: program timings\n" __func__); program_timing(channel, group, timings); } + printk(RCVEN_SPEW, "FINISH %s\n" __func__); } static void find_preamble(const int channel, const int group, rec_timing_t timings[][4], const char lane_map[][2]) { + printk(RCVEN_SPEW, "BEGIN %s\n" __func__); + + printk(RCVEN_SPEW, "Look for DQS low, backstepping.\n"); /* Look for DQS low, backstepping. */ while (read_dqs_level(channel, lane_map[group][0]) || read_dqs_level(channel, lane_map[group][1])) { + rec_full_backstep(&timings[channel][group]); + + printk(RCVEN_SPEW, "%s: program timings\n" __func__); program_timing(channel, group, timings); } + printk(RCVEN_SPEW, "FINISH %s\n" __func__); }
static void receive_enable_calibration(const timings_t *const timings, @@ -213,11 +316,13 @@ dimms[0].card_type == 0xf, dimms[1].card_type == 0xf, }; + printk(RCVEN_SPEW, "cardF: ch0 = %d, ch1 = %d.\n", cardF[0], cardF[1]);
- const unsigned int t_bound = - (timings->mem_clock == MEM_CLOCK_1067MT) ? 9 : 12; - const unsigned int p_bound = - (timings->mem_clock == MEM_CLOCK_1067MT) ? 8 : 1; + const unsigned int t_bound = (timings->mem_clock == MEM_CLOCK_1067MT) ? 9 : 12; + const unsigned int p_bound = (timings->mem_clock == MEM_CLOCK_1067MT) ? 8 : 1; + + printk(RCVEN_SPEW, "TAP bound = %u\n", t_bound); + printk(RCVEN_SPEW, "PI bound = %u\n", p_bound);
rec_timing_t rec_timings[2][4] = { { @@ -233,35 +338,61 @@ } };
+ printk(RCVEN_SPEW, "BEGIN MAIN LOOP\n"); + int ch, group; FOR_EACH_POPULATED_CHANNEL(dimms, ch) { const char (*const map)[2] = over_bytelane_map[cardF[ch]]; + printk(RCVEN_SPEW, "Begin channel %d\n", ch); + for (group = 0; group < 4; ++group) { + printk(RCVEN_SPEW, "RUNNING ON: channel %d, group %d\n", ch, group); + + printk(RCVEN_SPEW, "%s: program timings\n" __func__); program_timing(ch, group, rec_timings); + find_dqs_low(ch, group, rec_timings, map); + find_dqs_edge_lowhigh(ch, group, rec_timings, map);
rec_quarter_step(&rec_timings[ch][group]); + + printk(RCVEN_SPEW, "%s: program timings\n" __func__); program_timing(ch, group, rec_timings); + find_preamble(ch, group, rec_timings, map); + find_dqs_edge_lowhigh(ch, group, rec_timings, map); + rec_half_backstep(&rec_timings[ch][group]); + + printk(RCVEN_SPEW, "Normalize in %s: " __func__); + print_timings(channel, group, rec_timings) + normalize_rec_timing(&rec_timings[ch][group]); + if (cardF[ch]) { rec_timings[ch][group].t++; + printk(RCVEN_SPEW, "%s: program timings\n" __func__); program_timing(ch, group, rec_timings); } + printk(RCVEN_SPEW, "DONE FOR: channel %d, group %d\n", ch, group); } int c_min = C_BOUND; for (group = 0; group < 4; ++group) { if (rec_timings[ch][group].c < c_min) c_min = rec_timings[ch][group].c; } + + printk(RCVEN_SPEW, "Min coarse for channel %d: %d\n", ch, c_min); + for (group = 0; group < 4; ++group) { - rec_timings[ch][group].pre = - rec_timings[ch][group].c - c_min; - rec_timings[ch][group].c = c_min; + rec_timings[ch][group].pre = rec_timings[ch][group].c - c_min; + rec_timings[ch][group].c = c_min; + + printk(RCVEN_SPEW, "%s: program final timings\n" __func__); program_timing(ch, group, rec_timings); + printk(RAM_DEBUG, "Final timings for "); printk(BIOS_DEBUG, "group %d, ch %d: %d.%d.%d.%d.%d\n", group, ch, @@ -271,18 +402,20 @@ rec_timings[ch][group].t, rec_timings[ch][group].p); } + printk(RCVEN_SPEW, "End channel %d\n", ch); } + printk(RCVEN_SPEW, "END MAIN LOOP\n"); }
void raminit_receive_enable_calibration(const timings_t *const timings, const dimminfo_t *const dimms) { + printk(RCVEN_SPEW, "BEGIN rcven\n"); int ch;
/* Setup group to byte-lane mapping. */ FOR_EACH_POPULATED_CHANNEL(dimms, ch) { - const char (*const map)[2] = - bytelane_map[dimms[ch].card_type == 0xf]; + const char (*const map)[2] = bytelane_map[dimms[ch].card_type == 0xf]; unsigned int group; for (group = 0; group < 4; ++group) { const unsigned int mchbar = CxRECy_MCHBAR(ch, group); @@ -299,9 +432,11 @@ MCHBAR32(0x14f0) = (MCHBAR32(0x14f0) & ~(3 << 9)) | (1 << 9); MCHBAR32(0x15f0) = (MCHBAR32(0x15f0) & ~(3 << 9)) | (1 << 9);
+ printk(RCVEN_SPEW, "Start calibration\n"); receive_enable_calibration(timings, dimms);
MCHBAR32(0x12a4) &= ~(1 << 31); MCHBAR32(0x13a4) &= ~(1 << 31); + printk(RCVEN_SPEW, "FINISH rcven\n"); raminit_reset_readwrite_pointers(); }