From 19c3dad0ad9fb5e8c20b6c98431601250c029540 Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Sat, 26 Nov 2016 11:37:45 +0100 Subject: nb/intel/sandybridge/raminit: Fix odt stretch Move odt stretch into own function. Apply workaround on SandyBridge C-stepping CPU only. Apply odt stretch on all other CPU types. Don't depend on empty DIMM detection, as in case one slot is empty ref_card_offset is zero. Change-Id: I4320f14e0522ec997b1f9f3b12ba2c2070ee8e9e Signed-off-by: Patrick Rudolph Reviewed-on: https://review.coreboot.org/17616 Tested-by: build bot (Jenkins) Reviewed-by: Arthur Heymans --- src/northbridge/intel/sandybridge/raminit_common.c | 89 +++++++++------------- 1 file changed, 35 insertions(+), 54 deletions(-) (limited to 'src/northbridge/intel') diff --git a/src/northbridge/intel/sandybridge/raminit_common.c b/src/northbridge/intel/sandybridge/raminit_common.c index c05624cd42..e9d38c95b3 100644 --- a/src/northbridge/intel/sandybridge/raminit_common.c +++ b/src/northbridge/intel/sandybridge/raminit_common.c @@ -189,10 +189,39 @@ void dram_xover(ramctr_timing * ctrl) } } -void dram_timing_regs(ramctr_timing * ctrl) +static void dram_odt_stretch(ramctr_timing *ctrl, int channel) { - u32 reg, addr, val32, cpu, stretch; struct cpuid_result cpures; + u32 reg, addr, cpu, stretch; + + stretch = ctrl->ref_card_offset[channel]; + /* ODT stretch: Delay ODT signal by stretch value. + * Useful for multi DIMM setups on the same channel. */ + cpures = cpuid(1); + cpu = cpures.eax; + if (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_C(cpu)) { + if (stretch == 2) + stretch = 3; + addr = 0x400 * channel + 0x401c; + reg = MCHBAR32(addr) & 0xffffc3ff; + reg |= (stretch << 12); + reg |= (stretch << 10); + MCHBAR32(addr) = reg; + printram("OTHP Workaround [%x] = %x\n", addr, reg); + } else { + // OTHP + addr = 0x400 * channel + 0x400c; + reg = MCHBAR32(addr) & 0xfff0ffff; + reg |= (stretch << 16); + reg |= (stretch << 18); + MCHBAR32(addr) = reg; + printram("OTHP [%x] = %x\n", addr, reg); + } +} + +void dram_timing_regs(ramctr_timing *ctrl) +{ + u32 reg, addr, val32; int channel; FOR_ALL_CHANNELS { @@ -232,52 +261,7 @@ void dram_timing_regs(ramctr_timing * ctrl) MCHBAR32(addr) |= 0x00020000; - // ODT stretch - reg = 0; - - cpures = cpuid(1); - cpu = cpures.eax; - if (IS_IVY_CPU(cpu) - || (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_D2(cpu))) { - stretch = 2; - addr = 0x400 * channel + 0x400c; - printram("ODT stretch [%x] = %x\n", - 0x400 * channel + 0x400c, reg); - reg = MCHBAR32(addr); - - if (((ctrl->rankmap[channel] & 3) == 0) - || (ctrl->rankmap[channel] & 0xc) == 0) { - - // Rank 0 - operate on rank 2 - reg = (reg & ~0xc0000) | (stretch << 18); - - // Rank 2 - operate on rank 0 - reg = (reg & ~0x30000) | (stretch << 16); - - printram("ODT stretch [%x] = %x\n", addr, reg); - MCHBAR32(addr) = reg; - } - - } else if (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_C(cpu)) { - stretch = 3; - addr = 0x400 * channel + 0x401c; - reg = MCHBAR32(addr); - - if (((ctrl->rankmap[channel] & 3) == 0) - || (ctrl->rankmap[channel] & 0xc) == 0) { - - // Rank 0 - operate on rank 2 - reg = (reg & ~0x3000) | (stretch << 12); - - // Rank 2 - operate on rank 0 - reg = (reg & ~0xc00) | (stretch << 10); - - printram("ODT stretch [%x] = %x\n", addr, reg); - MCHBAR32(addr) = reg; - } - } else { - stretch = 0; - } + dram_odt_stretch(ctrl, channel); // REFI reg = 0; @@ -3155,7 +3139,7 @@ void prepare_training(ramctr_timing * ctrl) void set_4008c(ramctr_timing * ctrl) { int channel, slotrank; - u32 reg; + FOR_ALL_POPULATED_CHANNELS { u32 b20, b4_8_12; int min_320c = 10000; @@ -3176,11 +3160,8 @@ void set_4008c(ramctr_timing * ctrl) else b4_8_12 = 0x2220; - reg = read32(DEFAULT_MCHBAR + 0x400c + (channel << 10)); - write32(DEFAULT_MCHBAR + 0x400c + (channel << 10), - (reg & 0xFFF0FFFF) - | (ctrl->ref_card_offset[channel] << 16) - | (ctrl->ref_card_offset[channel] << 18)); + dram_odt_stretch(ctrl, channel); + write32(DEFAULT_MCHBAR + 0x4008 + (channel << 10), 0x0a000000 | (b20 << 20) -- cgit v1.2.3