Angel Pons has uploaded this change for review.

View Change

[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();
}

To view, visit change 34865. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I4de1d7fc70877c11c37549cf1d723cbdcc6b1910
Gerrit-Change-Number: 34865
Gerrit-PatchSet: 1
Gerrit-Owner: Angel Pons <th3fanbus@gmail.com>
Gerrit-MessageType: newchange