summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorArthur Heymans <arthur@aheymans.xyz>2018-09-11 22:26:13 +0200
committerFelix Held <felix-coreboot@felixheld.de>2018-10-15 12:50:50 +0000
commit8ddd7d1e5eee9e3e604624622d9b91f9b99306ff (patch)
tree8d7757bb8aab83658ea6e7b2069b15eb8ef8f203 /src
parent672d5ad20b8c9aab677e754dc2996f1e5a30cb77 (diff)
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>
Diffstat (limited to 'src')
-rw-r--r--src/northbridge/intel/x4x/dq_dqs.c12
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",