From c9847884ffc9693cd8482ee77f1b03e66fa10026 Mon Sep 17 00:00:00 2001 From: Nico Huber Date: Sun, 11 Aug 2019 16:23:21 +0200 Subject: 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 Reviewed-on: https://review.coreboot.org/c/coreboot/+/34827 Reviewed-by: Angel Pons Tested-by: build bot (Jenkins) --- src/northbridge/intel/gm45/gm45.h | 2 + src/northbridge/intel/gm45/raminit.c | 115 ++++++++++++++++++++++++++--------- 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); -- cgit v1.2.3