diff options
Diffstat (limited to 'src/northbridge')
-rw-r--r-- | src/northbridge/intel/x4x/raminit_ddr2.c | 168 | ||||
-rw-r--r-- | src/northbridge/intel/x4x/x4x.h | 7 |
2 files changed, 135 insertions, 40 deletions
diff --git a/src/northbridge/intel/x4x/raminit_ddr2.c b/src/northbridge/intel/x4x/raminit_ddr2.c index d38f69e794..490c329997 100644 --- a/src/northbridge/intel/x4x/raminit_ddr2.c +++ b/src/northbridge/intel/x4x/raminit_ddr2.c @@ -20,6 +20,11 @@ #include <console/console.h> #include <commonlib/helpers.h> #include <delay.h> +#include <pc80/mc146818rtc.h> +/* This northbridge can also occur with ICH10 */ +#if IS_ENABLED(CONFIG_SOUTHBRIDGE_INTEL_I82801GX) +#include <southbridge/intel/i82801gx/i82801gx.h> +#endif #include "iomap.h" #include "x4x.h" @@ -257,26 +262,25 @@ static void clkcross_ddr2(struct sysinfo *s) static void checkreset_ddr2(struct sysinfo *s) { u8 pmcon2; - u8 reset = 0; pmcon2 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa2); - if (!(pmcon2 & 0x80)) { - pmcon2 |= 0x80; + + if (pmcon2 & 0x80) { + pmcon2 &= ~0x80; pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, pmcon2); - reset = 1; /* do magic 0xf0 thing. */ u8 reg8 = pci_read_config8(PCI_DEV(0, 0, 0), 0xf0); pci_write_config8(PCI_DEV(0, 0, 0), 0xf0, reg8 & ~(1 << 2)); reg8 = pci_read_config8(PCI_DEV(0, 0, 0), 0xf0); pci_write_config8(PCI_DEV(0, 0, 0), 0xf0, reg8 | (1 << 2)); - } - if (reset) { + printk(BIOS_DEBUG, "Reset...\n"); - outb(0xe, 0xcf9); + outb(0x6, 0xcf9); asm ("hlt"); } - pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, pmcon2 | 0x80); + pmcon2 |= 0x80; + pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, pmcon2); } static void setioclk_ddr2(struct sysinfo *s) @@ -1490,6 +1494,78 @@ static void rcven_ddr2(struct sysinfo *s) printk(BIOS_DEBUG, "End rcven\n"); } +static void sdram_save_receive_enable(void) +{ + int i = 0; + u16 reg16; + u8 values[18]; + u8 lane, ch; + + FOR_EACH_CHANNEL(ch) { + lane = 0; + while (lane < 8) { + values[i] = (MCHBAR8(0x400*ch + 0x560 + lane++ * 4) & 0xf); + values[i++] |= (MCHBAR8(0x400*ch + 0x560 + lane++ * 4) & 0xf) << 4; + } + values[i++] = (MCHBAR32(0x400*ch + 0x248) >> 16) & 0xf; + reg16 = MCHBAR16(0x400*ch + 0x5fa); + values[i++] = reg16 & 0xff; + values[i++] = (reg16 >> 8) & 0xff; + reg16 = MCHBAR16(0x400*ch + 0x58c); + values[i++] = reg16 & 0xff; + values[i++] = (reg16 >> 8) & 0xff; + } + + for (i = 0; i < ARRAY_SIZE(values); i++) + cmos_write(values[i], 128 + i); +} + +static void sdram_recover_receive_enable(void) +{ + u8 i; + u32 reg32; + u16 reg16; + u8 values[18]; + u8 ch, lane; + + for (i = 0; i < ARRAY_SIZE(values); i++) + values[i] = cmos_read(128 + i); + + i = 0; + FOR_EACH_CHANNEL(ch) { + lane = 0; + while (lane < 8) { + MCHBAR8(0x400*ch + 0x560 + lane++ * 4) = 0x70 | + (values[i] & 0xf); + MCHBAR8(0x400*ch + 0x560 + lane++ * 4) = 0x70 | + ((values[i++] >> 4) & 0xf); + } + reg32 = (MCHBAR32(0x400*ch + 0x248) & ~0xf0000) + | ((values[i++] & 0xf) << 16); + MCHBAR32(0x400*ch + 0x248) = reg32; + reg16 = values[i++]; + reg16 |= values[i++] << 8; + MCHBAR16(0x400*ch + 0x5fa) = reg16; + reg16 = values[i++]; + reg16 |= values[i++] << 8; + MCHBAR16(0x400*ch + 0x58c) = reg16; + } +} + +static void sdram_program_receive_enable(struct sysinfo *s) +{ + /* enable upper CMOS */ + RCBA32(0x3400) = (1 << 2); + + /* Program Receive Enable Timings */ + if (s->boot_path == BOOT_PATH_WARM_RESET) { + sdram_recover_receive_enable(); + } else { + rcven_ddr2(s); + sdram_save_receive_enable(); + } +} + static void dradrb_ddr2(struct sysinfo *s) { u8 map, i, ch, r, rankpop0, rankpop1; @@ -1863,23 +1939,25 @@ void raminit_ddr2(struct sysinfo *s) // Reset if required checkreset_ddr2(s); - // Clear self refresh - MCHBAR32(0xf14) = MCHBAR32(0xf14) | 0x3; + if (s->boot_path != BOOT_PATH_WARM_RESET) { + // Clear self refresh + MCHBAR32(PMSTS_MCHBAR) = MCHBAR32(PMSTS_MCHBAR) + | PMSTS_BOTH_SELFREFRESH; - // Clear host clk gate reg - MCHBAR32(0x1c) = MCHBAR32(0x1c) | 0xffffffff; + // Clear host clk gate reg + MCHBAR32(0x1c) = MCHBAR32(0x1c) | 0xffffffff; - // Select DDR2 - MCHBAR8(0x1a8) = MCHBAR8(0x1a8) & ~0x4; + // Select DDR2 + MCHBAR8(0x1a8) = MCHBAR8(0x1a8) & ~0x4; - // Set freq - MCHBAR32(0xc00) = (MCHBAR32(0xc00) & ~0x70) | - (s->selected_timings.mem_clk << 4) | (1 << 10); + // Set freq + MCHBAR32(0xc00) = (MCHBAR32(0xc00) & ~0x70) | + (s->selected_timings.mem_clk << 4) | (1 << 10); - // Overwrite freq if chipset rejects it - s->selected_timings.mem_clk = (MCHBAR8(0xc00) & 0x70) >> 4; - if (s->selected_timings.mem_clk > (s->max_fsb + 3)) { - die("Error: DDR is faster than FSB, halt\n"); + // Overwrite freq if chipset rejects it + s->selected_timings.mem_clk = (MCHBAR8(0xc00) & 0x70) >> 4; + if (s->selected_timings.mem_clk > (s->max_fsb + 3)) + die("Error: DDR is faster than FSB, halt\n"); } udelay(250000); @@ -1889,8 +1967,10 @@ void raminit_ddr2(struct sysinfo *s) printk(BIOS_DEBUG, "Done clk crossing\n"); // DDR2 IO - setioclk_ddr2(s); - printk(BIOS_DEBUG, "Done I/O clk\n"); + if (s->boot_path != BOOT_PATH_WARM_RESET) { + setioclk_ddr2(s); + printk(BIOS_DEBUG, "Done I/O clk\n"); + } // Grant to launch launch_ddr2(s); @@ -1904,16 +1984,21 @@ void raminit_ddr2(struct sysinfo *s) dll_ddr2(s); // RCOMP - rcomp_ddr2(s); - printk(BIOS_DEBUG, "RCOMP\n"); + if (s->boot_path != BOOT_PATH_WARM_RESET) { + rcomp_ddr2(s); + printk(BIOS_DEBUG, "RCOMP\n"); + } // ODT odt_ddr2(s); printk(BIOS_DEBUG, "Done ODT\n"); // RCOMP update - while ((MCHBAR8(0x130) & 1) != 0 ); - printk(BIOS_DEBUG, "Done RCOMP update\n"); + if (s->boot_path != BOOT_PATH_WARM_RESET) { + while ((MCHBAR8(0x130) & 1) != 0) + ; + printk(BIOS_DEBUG, "Done RCOMP update\n"); + } // Set defaults MCHBAR32(0x260) = (MCHBAR32(0x260) & ~1) | 0xf00000; @@ -1993,7 +2078,7 @@ void raminit_ddr2(struct sysinfo *s) } // Receive enable - rcven_ddr2(s); + sdram_program_receive_enable(s); printk(BIOS_DEBUG, "Done rcven\n"); // Finish rcven @@ -2008,16 +2093,23 @@ void raminit_ddr2(struct sysinfo *s) MCHBAR8(0x5dc) = MCHBAR8(0x5dc) | 0x80; // Dummy writes / reads - volatile u32 data; - FOR_EACH_POPULATED_RANK(s->dimms, ch, r) { - for (bank = 0; bank < 4; bank++) { - reg32 = (ch << 29) | (r*0x8000000) | (bank << 12); - write32((u32 *)reg32, 0xffffffff); - data = read32((u32 *)reg32); - printk(BIOS_DEBUG, "Wrote ones, Read: [0x%08x]=0x%08x\n", reg32, data); - write32((u32 *)reg32, 0x00000000); - data = read32((u32 *)reg32); - printk(BIOS_DEBUG, "Wrote zeros, Read: [0x%08x]=0x%08x\n", reg32, data); + if (s->boot_path == BOOT_PATH_NORMAL) { + volatile u32 data; + FOR_EACH_POPULATED_RANK(s->dimms, ch, r) { + for (bank = 0; bank < 4; bank++) { + reg32 = (ch << 29) | (r*0x8000000) | + (bank << 12); + write32((u32 *)reg32, 0xffffffff); + data = read32((u32 *)reg32); + printk(BIOS_DEBUG, "Wrote ones,"); + printk(BIOS_DEBUG, " Read: [0x%08x]=0x%08x\n", + reg32, data); + write32((u32 *)reg32, 0x00000000); + data = read32((u32 *)reg32); + printk(BIOS_DEBUG, "Wrote zeros,"); + printk(BIOS_DEBUG, " Read: [0x%08x]=0x%08x\n", + reg32, data); + } } } printk(BIOS_DEBUG, "Done dummy reads\n"); diff --git a/src/northbridge/intel/x4x/x4x.h b/src/northbridge/intel/x4x/x4x.h index 7ca634f5cd..66d765ab83 100644 --- a/src/northbridge/intel/x4x/x4x.h +++ b/src/northbridge/intel/x4x/x4x.h @@ -87,8 +87,8 @@ #define MCHBAR32(x) *((volatile u32 *)(DEFAULT_MCHBAR + x)) #define PMSTS_MCHBAR 0x0f14 /* Self refresh channel status */ -#define PMSTS_WARM_RESET (1 << 1) -#define PMSTS_BOTH_SELFREFRESH (1 << 0) +#define PMSTS_WARM_RESET (1 << 8) +#define PMSTS_BOTH_SELFREFRESH (3 << 0) #define CLKCFG_MCHBAR 0x0c00 #define CLKCFG_FSBCLK_SHIFT 0 @@ -290,6 +290,9 @@ struct sysinfo { struct dimminfo dimms[4]; u8 spd_map[4]; }; +#define BOOT_PATH_NORMAL 0 +#define BOOT_PATH_WARM_RESET 1 +#define BOOT_PATH_RESUME 2 enum ddr2_signals { CLKSET0 = 0, |