Arthur Heymans has uploaded a new change for review. ( https://review.coreboot.org/19877 )
Change subject: nb/intel/x4x: DDR3 JEDEC init ......................................................................
nb/intel/x4x: DDR3 JEDEC init
Change-Id: I3b5eeb0aff6764292bbcbed7274274f615066c14 Signed-off-by: Arthur Heymans arthur@aheymans.xyz --- M src/northbridge/intel/x4x/raminit_ddr23.c M src/northbridge/intel/x4x/spd_ddr3_decode.c M src/northbridge/intel/x4x/x4x.h 3 files changed, 78 insertions(+), 9 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/77/19877/1
diff --git a/src/northbridge/intel/x4x/raminit_ddr23.c b/src/northbridge/intel/x4x/raminit_ddr23.c index 0d09c05..a289788 100644 --- a/src/northbridge/intel/x4x/raminit_ddr23.c +++ b/src/northbridge/intel/x4x/raminit_ddr23.c @@ -1269,14 +1269,31 @@ } }
-static void send_jedec_cmd(u8 r, u8 ch, u8 cmd, u16 val) +void send_jedec_cmd(const struct sysinfo *s, u8 r, u8 ch, u8 cmd, u32 val) { u32 addr = (ch << 29) | (r*0x08000000); volatile u32 rubbish; + u8 data8 = cmd; + u32 data32;
- MCHBAR8(0x271) = (MCHBAR8(0x271) & ~0x3e) | cmd; - MCHBAR8(0x671) = (MCHBAR8(0x671) & ~0x3e) | cmd; - rubbish = read32((void *)((val<<3) | addr)); + if (s->spd_type == DDR3 && (r & 1) && s->dimms[r].mirrorred) { + data8 &= ~(1 << 4); + data8 |= ((1 << 4) & (cmd >> 1)); + data8 &= ~(1 << 5); + data8 |= ((1 << 5) & (cmd << 1)); + } + + MCHBAR8(0x271) = (MCHBAR8(0x271) & ~0x3e) | data8; + MCHBAR8(0x671) = (MCHBAR8(0x671) & ~0x3e) | data8; + data32 = val; + if (s->spd_type == DDR3 && (r & 1) && s->dimms[r].mirrorred) { + data32 &= ~(0x1f8); + data32 |= (val & 0xb0) << 1; + data32 |= (val & 0x160) >> 1; + } + data32 <<= 3; + + rubbish = read32((void *)((data32 | addr))); udelay(10); MCHBAR8(0x271) = (MCHBAR8(0x271) & ~0x3e) | NORMALOP_CMD; MCHBAR8(0x671) = (MCHBAR8(0x671) & ~0x3e) | NORMALOP_CMD; @@ -1341,7 +1358,7 @@ default: break; } - send_jedec_cmd(r + ch*4, ch, jedec[i][0], v); + send_jedec_cmd(s, r + ch*4, ch, jedec[i][0], v); udelay(1); //printk(BIOS_DEBUG, "Jedec step %d\n", i); } @@ -1349,6 +1366,51 @@ printk(BIOS_DEBUG, "MRS done\n"); }
+static void jedec_ddr3(struct sysinfo *s) +{ + int ch, r, dimmconfig, cmd, ddr3_freq; + + u8 ddr3_emrs2_config[16][4] = { /* [config][Rank] */ + {0, 0, 0, 0}, /* NC_NC */ + {0, 0, 0, 0}, /* x8ss_NC */ + {0, 0, 0, 0}, /* x8ds_NC */ + {0, 0, 0, 0}, /* x16ss_NC */ + {0, 0, 0, 0}, /* NC_x8ss */ + {2, 0, 2, 0}, /* x8ss_x8ss */ + {2, 2, 2, 0}, /* x8ds_x8ss */ + {2, 0, 2, 0}, /* x16ss_x8ss */ + {0, 0, 0, 0}, /* NC_x8ss */ + {2, 0, 2, 2}, /* x8ss_x8ds */ + {2, 2, 2, 2}, /* x8ds_x8ds */ + {2, 0, 2, 2}, /* x16ss_x8ds */ + {0, 0, 0, 0}, /* NC_x16ss */ + {2, 0, 2, 0}, /* x8ss_x16ss */ + {2, 2, 2, 0}, /* x8ds_x16ss */ + {2, 0, 2, 0}, /* x16ss_x16ss */ + }; + + printk(BIOS_DEBUG, "MRS...\n"); + + ddr3_freq = s->selected_timings.mem_clk - MEM_CLOCK_800MHz; + FOR_EACH_POPULATED_RANK(s->dimms, ch, r) { + printk(BIOS_DEBUG, "CH%d: Found Rank %d\n", ch, r); + send_jedec_cmd(s, r + ch * 4, ch, NOP_CMD, 0); + udelay(200); + dimmconfig = s->dimm_config[ch]; + cmd = ddr3_freq << 3; /* actually twl - 5 which is same */ + cmd |= ddr3_emrs2_config[dimmconfig][r] << 9; + send_jedec_cmd(s, r + ch * 4, ch, EMRS2_CMD, cmd); + send_jedec_cmd(s, r + ch * 4, ch, EMRS3_CMD, 0); + cmd = ddr3_emrs1_config[dimmconfig][r] << 2; + cmd |= (1 << 1); + send_jedec_cmd(s, r + ch * 4, ch, EMRS1_CMD, cmd); + send_jedec_cmd(s, r + ch * 4, ch, MRS_CMD, (1 << 3) | (1 << 8) + | (1 << 12) | ((s->selected_timings.CAS - 4) << 4) + | ((s->selected_timings.tWR - 4) << 9)); + send_jedec_cmd(s, r + ch * 4, ch, ZQCAL_CMD, (1 << 10)); + } + printk(BIOS_DEBUG, "MRS done\n"); +} static u8 sampledqs(u16 mchloc, u32 addr, u8 hilow, u8 repeat) { u8 dqsmatch = 1; @@ -2163,9 +2225,12 @@ MCHBAR16(0x212) = (MCHBAR16(0x212) & ~0xf00) | 0xf00; printk(BIOS_DEBUG, "Done pre-jedec\n");
- // JEDEC reset - if (s->boot_path != BOOT_PATH_RESUME) - jedec_ddr2(s); + if (s->boot_path != BOOT_PATH_RESUME) { + if (s->spd_type == DDR2) + jedec_ddr2(s); + else + jedec_ddr3(s); + }
printk(BIOS_DEBUG, "Done jedec steps\n");
diff --git a/src/northbridge/intel/x4x/spd_ddr3_decode.c b/src/northbridge/intel/x4x/spd_ddr3_decode.c index fd69fd4..eab0548 100644 --- a/src/northbridge/intel/x4x/spd_ddr3_decode.c +++ b/src/northbridge/intel/x4x/spd_ddr3_decode.c @@ -152,6 +152,8 @@ s->dimms[dimm_idx].rows = decoded_dimm.row_bits; s->dimms[dimm_idx].cols = decoded_dimm.col_bits;
+ s->dimms[dimm_idx].mirrorred = decoded_dimm.flags.pins_mirrored; + saved_timings->min_tRAS = MAX(saved_timings->min_tRAS, decoded_dimm.tRAS); saved_timings->min_tRP = diff --git a/src/northbridge/intel/x4x/x4x.h b/src/northbridge/intel/x4x/x4x.h index 9ef07b3..c2eea38 100644 --- a/src/northbridge/intel/x4x/x4x.h +++ b/src/northbridge/intel/x4x/x4x.h @@ -276,6 +276,7 @@ unsigned int ranks; unsigned int rows; unsigned int cols; + u8 mirrorred; };
/* The setup is up to two DIMMs per channel */ @@ -355,6 +356,7 @@ struct abs_timings *saved_timings); int ddr3_save_dimminfo(u8 dimm_idx, u8 *raw_spd, struct abs_timings *saved_timings, struct sysinfo *s); +void send_jedec_cmd(const struct sysinfo *s, u8 r, u8 ch, u8 cmd, u32 val); void dqsset(u8 ch, u8 lane, const struct dll_setting *setting); void dqset(u8 ch, u8 lane, const struct dll_setting *setting);
@@ -364,7 +366,7 @@ extern const struct dll_setting ddr3_dll_setting_800[2][23]; extern const struct dll_setting ddr3_dll_setting_1066[2][23]; extern const struct dll_setting ddr3_dll_setting_1333[2][23]; - +extern const u8 ddr3_emrs1_config[16][4];
struct acpi_rsdp; #ifndef __SIMPLE_DEVICE__