summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNico Huber <nico.h@gmx.de>2019-08-11 16:23:21 +0200
committerFelix Held <felix-coreboot@felixheld.de>2023-01-26 13:34:26 +0000
commitc9847884ffc9693cd8482ee77f1b03e66fa10026 (patch)
tree5716e71fa3aba6e4af17185d284d8112a790280f /src
parent0c314f9c7e1b3c39ad8b4c1f7cf0f72bdcaf8ff1 (diff)
nb/intel/gm45: Split DDR2 JEDEC init out
Split JEDEC init into common and DDR3 specific parts and add the DDR2 specific init code. This also replaces raw `mchbar_clrsetbits32` calls with a dedicated `jedec_command` function. TEST: DDR2 systems boot (with the rest of the patch train) - Tested on a Dell Latitude E6400 - Tested on a Compal JHL90 TEST: Ensure DDR3 systems still boot - Tested on a Thinkpad X200 Change-Id: I7a57549887c0323e5babbf18f691183412a99ba9 Signed-off-by: Nico Huber <nico.h@gmx.de> Reviewed-on: https://review.coreboot.org/c/coreboot/+/34827 Reviewed-by: Angel Pons <th3fanbus@gmail.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src')
-rw-r--r--src/northbridge/intel/gm45/gm45.h2
-rw-r--r--src/northbridge/intel/gm45/raminit.c115
2 files changed, 87 insertions, 30 deletions
diff --git a/src/northbridge/intel/gm45/gm45.h b/src/northbridge/intel/gm45/gm45.h
index c5c17a6a0d..c8ec6dc88d 100644
--- a/src/northbridge/intel/gm45/gm45.h
+++ b/src/northbridge/intel/gm45/gm45.h
@@ -243,6 +243,7 @@ enum {
#define DCC_CMD_SHIFT 16
#define DCC_CMD_MASK (7 << DCC_CMD_SHIFT)
#define DCC_CMD_NOP (1 << DCC_CMD_SHIFT)
+#define DCC_CMD_ABP (2 << DCC_CMD_SHIFT)
/* For mode register mr0: */
#define DCC_SET_MREG (3 << DCC_CMD_SHIFT)
/* For extended mode registers mr1 to mr3: */
@@ -252,6 +253,7 @@ enum {
#define DCC_SET_EREGx(x) ((DCC_SET_EREG | \
(((x) - 1) << DCC_SET_EREG_SHIFT)) & \
DCC_SET_EREG_MASK)
+#define DCC_CMD_CBR (6 << DCC_CMD_SHIFT)
/* Per channel DRAM Row Attribute registers (32-bit) */
#define CxDRA_MCHBAR(x) (0x1208 + ((x) * 0x0100))
diff --git a/src/northbridge/intel/gm45/raminit.c b/src/northbridge/intel/gm45/raminit.c
index 62785d3735..a57f201d4f 100644
--- a/src/northbridge/intel/gm45/raminit.c
+++ b/src/northbridge/intel/gm45/raminit.c
@@ -1697,28 +1697,19 @@ static void memory_io_init(const mem_clock_t ddr3clock,
ddr3_read_io_init(ddr3clock, dimms, sff);
}
-static void jedec_init(const timings_t *const timings,
- const dimminfo_t *const dimms)
+static void jedec_command(const uintptr_t rankaddr, const u32 cmd, const u32 val)
+{
+ mchbar_clrsetbits32(DCC_MCHBAR, DCC_SET_EREG_MASK, cmd);
+ read32p(rankaddr | val);
+}
+
+static void jedec_init_ddr3(const timings_t *const timings,
+ const dimminfo_t *const dimms)
{
if ((timings->tWR < 5) || (timings->tWR > 12))
die("tWR value unsupported in Jedec initialization.\n");
- /* Pre-jedec settings */
- mchbar_setbits32(0x40, 1 << 1);
- mchbar_setbits32(0x230, 3 << 1);
- mchbar_setbits32(0x238, 3 << 24);
- mchbar_setbits32(0x23c, 3 << 24);
-
- /* Normal write pointer operation */
- mchbar_setbits32(0x14f0, 1 << 9);
- mchbar_setbits32(0x15f0, 1 << 9);
-
- mchbar_clrsetbits32(DCC_MCHBAR, DCC_CMD_MASK, DCC_CMD_NOP);
- pci_and_config8(PCI_DEV(0, 0, 0), 0xf0, ~(1 << 2));
-
- pci_or_config8(PCI_DEV(0, 0, 0), 0xf0, 1 << 2);
- udelay(2);
/* 5 6 7 8 9 10 11 12 */
static const u8 wr_lut[] = { 1, 2, 3, 4, 5, 5, 6, 6 };
@@ -1736,18 +1727,82 @@ static void jedec_init(const timings_t *const timings,
/* We won't do this in dual-interleaved mode,
so don't care about the offset.
Mirrored ranks aren't taken into account here. */
- const u32 rankaddr = raminit_get_rank_addr(ch, r);
- printk(BIOS_DEBUG, "JEDEC init @0x%08x\n", rankaddr);
- mchbar_clrsetbits32(DCC_MCHBAR, DCC_SET_EREG_MASK, DCC_SET_EREGx(2));
- read32p(rankaddr | WL);
- mchbar_clrsetbits32(DCC_MCHBAR, DCC_SET_EREG_MASK, DCC_SET_EREGx(3));
- read32p(rankaddr);
- mchbar_clrsetbits32(DCC_MCHBAR, DCC_SET_EREG_MASK, DCC_SET_EREGx(1));
- read32p(rankaddr | ODT_120OHMS | ODS_34OHMS);
- mchbar_clrsetbits32(DCC_MCHBAR, DCC_CMD_MASK, DCC_SET_MREG);
- read32p(rankaddr | WR | DLL1 | CAS | INTERLEAVED);
- mchbar_clrsetbits32(DCC_MCHBAR, DCC_CMD_MASK, DCC_SET_MREG);
- read32p(rankaddr | WR | CAS | INTERLEAVED);
+ const uintptr_t rankaddr = raminit_get_rank_addr(ch, r);
+ printk(BIOS_DEBUG, "JEDEC init @0x%08x\n", (u32)rankaddr);
+
+ jedec_command(rankaddr, DCC_SET_EREGx(2), WL);
+ jedec_command(rankaddr, DCC_SET_EREGx(3), 0);
+ jedec_command(rankaddr, DCC_SET_EREGx(1), ODT_120OHMS | ODS_34OHMS);
+ jedec_command(rankaddr, DCC_SET_MREG, WR | DLL1 | CAS | INTERLEAVED);
+ jedec_command(rankaddr, DCC_SET_MREG, WR | CAS | INTERLEAVED);
+ }
+}
+
+static void jedec_init_ddr2(const timings_t *const timings,
+ const dimminfo_t *const dimms)
+{
+ /* All bit offsets are off by 3 (2^3 bytes bus width). */
+
+ /* Mode Register (MR) settings */
+ const int WR = ((timings->tWR - 1) & 7) << 12;
+ const int DLLreset = 1 << 11;
+ const int CAS = (timings->CAS & 7) << 7;
+ const int BTinterleaved = 1 << 6;
+ const int BL8 = 3 << 3;
+
+ /* Extended Mode Register 1 (EMR1) */
+ const int OCDdefault = 7 << 10;
+ const int ODT_150OHMS = 1 << 9 | 0 << 5;
+
+ int ch, r;
+ FOR_EACH_POPULATED_RANK(dimms, ch, r) {
+ /* We won't do this in dual-interleaved mode,
+ so don't care about the offset.
+ Mirrored ranks aren't taken into account here. */
+ const uintptr_t rankaddr = raminit_get_rank_addr(ch, r);
+ printk(BIOS_DEBUG, "JEDEC init @0x%08x\n", (u32)rankaddr);
+
+ jedec_command(rankaddr, DCC_CMD_ABP, 0);
+ jedec_command(rankaddr, DCC_SET_EREGx(2), 0);
+ jedec_command(rankaddr, DCC_SET_EREGx(3), 0);
+ jedec_command(rankaddr, DCC_SET_EREGx(1), ODT_150OHMS);
+ jedec_command(rankaddr, DCC_SET_MREG, WR | DLLreset | CAS | BTinterleaved | BL8);
+ jedec_command(rankaddr, DCC_CMD_ABP, 0);
+ jedec_command(rankaddr, DCC_CMD_CBR, 0);
+ udelay(1);
+ read32((void *)(rankaddr));
+
+ jedec_command(rankaddr, DCC_SET_MREG, WR | CAS | BTinterleaved | BL8);
+ jedec_command(rankaddr, DCC_SET_EREGx(1), OCDdefault | ODT_150OHMS);
+ jedec_command(rankaddr, DCC_SET_EREGx(1), ODT_150OHMS);
+ }
+}
+
+static void jedec_init(const int spd_type,
+ const timings_t *const timings,
+ const dimminfo_t *const dimms)
+{
+ /* Pre-jedec settings */
+ mchbar_setbits32(0x40, 1 << 1);
+ mchbar_setbits32(0x230, 3 << 1);
+ mchbar_setbits32(0x238, 3 << 24);
+ mchbar_setbits32(0x23c, 3 << 24);
+
+ /* Normal write pointer operation */
+ mchbar_setbits32(0x14f0, 1 << 9);
+ mchbar_setbits32(0x15f0, 1 << 9);
+
+ mchbar_clrsetbits32(DCC_MCHBAR, DCC_CMD_MASK, DCC_CMD_NOP);
+
+ pci_and_config8(PCI_DEV(0, 0, 0), 0xf0, ~(1 << 2));
+
+ pci_or_config8(PCI_DEV(0, 0, 0), 0xf0, 1 << 2);
+ udelay(2);
+
+ if (spd_type == DDR2) {
+ jedec_init_ddr2(timings, dimms);
+ } else if (spd_type == DDR3) {
+ jedec_init_ddr3(timings, dimms);
}
}
@@ -1920,7 +1975,7 @@ void raminit(sysinfo_t *const sysinfo, const int s3resume)
prejedec_memory_map(dimms, timings->channel_mode);
if (!s3resume)
/* Perform JEDEC initialization of DIMMS. */
- jedec_init(timings, dimms);
+ jedec_init(sysinfo->spd_type, timings, dimms);
/* Some programming steps after JEDEC initialization. */
post_jedec_sequence(sysinfo->cores);