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>
This commit is contained in:
Nico Huber 2019-08-11 16:23:21 +02:00 committed by Felix Held
parent 0c314f9c7e
commit c9847884ff
2 changed files with 87 additions and 30 deletions

View File

@ -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))

View File

@ -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);