diff options
author | Arthur Heymans <arthur@aheymans.xyz> | 2018-09-11 22:26:13 +0200 |
---|---|---|
committer | Felix Held <felix-coreboot@felixheld.de> | 2018-10-15 12:50:50 +0000 |
commit | 8ddd7d1e5eee9e3e604624622d9b91f9b99306ff (patch) | |
tree | 8d7757bb8aab83658ea6e7b2069b15eb8ef8f203 | |
parent | 672d5ad20b8c9aab677e754dc2996f1e5a30cb77 (diff) | |
download | coreboot-8ddd7d1e5eee9e3e604624622d9b91f9b99306ff.tar.xz |
nb/intel/x4x: Program read training results to all ranks
While during the read training itself only the settings for rank 0 are used for
all ranks, the controller does use the separate settings for each rank later on.
It is unknown which register is responsible for this.
The signals are probably not generated separately and therefore need to have the
same settings for all ranks. Therefore program the results for all ranks instead
of for all populated ranks.
TESTED: Fixes DG43GT not booting with only the second DIMM slot of a channel
populated.
Change-Id: I7965a068ef4779847e62e966154764370c91302a
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/28577
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
-rw-r--r-- | src/northbridge/intel/x4x/dq_dqs.c | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/src/northbridge/intel/x4x/dq_dqs.c b/src/northbridge/intel/x4x/dq_dqs.c index 64131d89b8..fbdb4f9f17 100644 --- a/src/northbridge/intel/x4x/dq_dqs.c +++ b/src/northbridge/intel/x4x/dq_dqs.c @@ -447,8 +447,12 @@ static int rt_find_dqs_limit(struct sysinfo *s, u8 channel, * - use the mean between the saved succeeding and failing value * - note0: bytelanes cannot be trained independently, so the delays need to be * adjusted and tested for all of them at the same time - * - note1: this memory controller appears to have per rank registers for these - * DQS rx delays, but only the one rank 0 seems to be used for all of them + * - note1: At this stage all ranks effectively use the rank0's rt_dqs settings, + * but later on their respective settings are used (TODO where is the + * 'switch' register??). So programming the results for all ranks at the end + * of the training. Programming on all ranks instead of all populated ranks, + * seems to be required, most likely because the signals can't really be generated + * separately. */ int do_read_training(struct sysinfo *s) { @@ -519,7 +523,9 @@ int do_read_training(struct sysinfo *s) printk(BIOS_ERR, "Huh? read training overflowed!!\n"); } - FOR_EACH_POPULATED_RANK_IN_CHANNEL(s->dimms, channel, rank) + /* Later on separate settings for each rank are used so program + all of them */ + FOR_EACH_RANK_IN_CHANNEL(rank) rt_set_dqs(channel, lane, rank, &s->rt_dqs[channel][lane]); printk(BIOS_DEBUG, "\tlane%d: %d.%d\n", |