Vladimir Serbinenko (phcoder@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4632
-gerrit
commit 45df1246fc5384cb95036cb6d1bb7d0c25325895 Author: Vladimir Serbinenko phcoder@gmail.com Date: Thu Jan 9 03:34:38 2014 +0100
X201: Make S3 work.
Change-Id: I319e57af52ff01083bfbffbcd883ac5f453320a1 Signed-off-by: Vladimir Serbinenko phcoder@gmail.com --- src/mainboard/lenovo/x201/romstage.c | 12 +- src/northbridge/intel/nehalem/early_init.c | 6 + src/northbridge/intel/nehalem/raminit.c | 177 ++++++++++++++--------------- 3 files changed, 93 insertions(+), 102 deletions(-)
diff --git a/src/mainboard/lenovo/x201/romstage.c b/src/mainboard/lenovo/x201/romstage.c index 8022d7b..fbf240e 100644 --- a/src/mainboard/lenovo/x201/romstage.c +++ b/src/mainboard/lenovo/x201/romstage.c @@ -239,25 +239,19 @@ void main(unsigned long bist) if (bist == 0) enable_lapic();
- /* Force PCIRST# */ - pci_write_config16(PCI_DEV(0, 0x1e, 0), BCTRL, SBR); - pci_write_config16(PCI_DEV(0, 0, 0), BCTRL, SBR); - udelay(200 * 1000); - pci_write_config16(PCI_DEV(0, 0x1e, 0), BCTRL, 0); - pci_write_config16(PCI_DEV(0, 0, 0), BCTRL, 0); + nehalem_early_initialization(NEHALEM_MOBILE); + + pch_enable_lpc();
/* Enable USB Power. We need to do it early for usbdebug to work. */ ec_set_bit(0x3b, 4);
- pch_enable_lpc(); - /* Enable GPIOs */ pci_write_config32(PCH_LPC_DEV, GPIO_BASE, DEFAULT_GPIOBASE | 1); pci_write_config8(PCH_LPC_DEV, GPIO_CNTL, 0x10);
setup_pch_gpios(&x201_gpio_map);
- nehalem_early_initialization(NEHALEM_MOBILE);
/* This should probably go away. Until now it is required * and mainboard specific diff --git a/src/northbridge/intel/nehalem/early_init.c b/src/northbridge/intel/nehalem/early_init.c index 81bac87..ee8c17a 100644 --- a/src/northbridge/intel/nehalem/early_init.c +++ b/src/northbridge/intel/nehalem/early_init.c @@ -166,4 +166,10 @@ void nehalem_early_initialization(int chipset_type) pci_write_config32(PCI_DEV(0, 0x16, 0), 0x10, DEFAULT_HECIBAR); pci_write_config32(PCI_DEV(0, 0x16, 0), PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + + /* Magic for S3 resume. Must be done early. */ + if (((inl(DEFAULT_PMBASE + PM1_CNT) >> 10) & 7) == SLP_TYP_S3) { + MCHBAR32 (0x1e8) = (MCHBAR32(0x1e8) & ~1) | 6; + MCHBAR32 (0x1e8) = (MCHBAR32(0x1e8) & ~3) | 4; + } } diff --git a/src/northbridge/intel/nehalem/raminit.c b/src/northbridge/intel/nehalem/raminit.c index 19af3bb..e210427 100644 --- a/src/northbridge/intel/nehalem/raminit.c +++ b/src/northbridge/intel/nehalem/raminit.c @@ -102,6 +102,10 @@ struct ram_training { u16 timing_offset[2][2][2][9]; u16 timing2_offset[2][2][2][9]; u16 timing2_bounds[2][2][2][9][2]; + u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */ + u8 reg2ca9_bit0; + u32 reg_6dc; + u32 reg_6e8; };
#if !REAL @@ -259,15 +263,14 @@ struct raminfo { struct ram_training training; u32 last_500_command[2];
- u8 reg2ca9_bit0; - u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */ - u32 delay46_ps[2]; - u32 delay54_ps[2]; u8 revision_flag_1; u8 some_delay_1_cycle_floor; u8 some_delay_2_halfcycles_ceil; u8 some_delay_3_ps_rounded;
+ u32 delay46_ps[2]; + u32 delay54_ps[2]; + const struct ram_training *cached_training; };
@@ -1680,6 +1683,9 @@ static void dump_timings(struct raminfo *info) #endif }
+/* Read timings and other registers that need to be restored verbatim and + put them to CBFS. + */ static void save_timings(struct raminfo *info) { #if CONFIG_EARLY_CBMEM_INIT @@ -1698,6 +1704,20 @@ static void save_timings(struct raminfo *info) train.reg_178 = read_1d0(0x178, 7); train.reg_10b = read_1d0(0x10b, 6);
+ for (channel = 0; channel < NUM_CHANNELS; channel++) { + u32 reg32; + reg32 = read_mchbar32 ((channel << 10) + 0x274); + train.reg274265[channel][0] = reg32 >> 16; + train.reg274265[channel][1] = reg32 & 0xffff; + train.reg274265[channel][2] = read_mchbar16 ((channel << 10) + 0x265) >> 8; + } + train.reg2ca9_bit0 = read_mchbar8(0x2ca9) & 1; + train.reg_6dc = read_mchbar32 (0x6dc); + train.reg_6e8 = read_mchbar32 (0x6e8); + + printk (BIOS_ERR, "[6dc] = %x\n", train.reg_6dc); + printk (BIOS_ERR, "[6e8] = %x\n", train.reg_6e8); + /* Save the MRC S3 restore data to cbmem */ cbmem_initialize(); mrcdata = cbmem_add @@ -1814,7 +1834,7 @@ recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 * packet, do { csr.raw = read32(DEFAULT_HECIBAR | 0xc); #if !REAL - if (i++ > 346) + if (i++ > 330) return -1; #endif } @@ -1990,8 +2010,6 @@ static int have_match_ranks(struct raminfo *info, int channel, int ranks) return 1; }
-#define WTF1 1 - static void read_4090(struct raminfo *info) { int i, channel, slot, rank, lane; @@ -3493,6 +3511,13 @@ set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2, 0, 1, &ratios2); compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4, 0, 1, &ratios1); + printk (BIOS_ERR, "[%x] <= %x\n", reg, + ratios1.freq4_to_max_remainder | (ratios2. + freq4_to_max_remainder + << 8) + | (ratios1.divisor_f4_to_fmax << 16) | (ratios2. + divisor_f4_to_fmax + << 20)); write_mchbar32(reg, ratios1.freq4_to_max_remainder | (ratios2. freq4_to_max_remainder @@ -3555,7 +3580,7 @@ set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2, } }
-static void set_2dxx_series(struct raminfo *info) +static void set_2dxx_series(struct raminfo *info, int s3resume) { set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005, 0, 1); @@ -3583,14 +3608,24 @@ static void set_2dxx_series(struct raminfo *info) set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency, frequency_11(info) / 2, 4000, 4000, 0, 0);
- set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0, - info->delay46_ps[0], 0, info->delay54_ps[0]); + if (s3resume) { + printk (BIOS_ERR, "[6dc] <= %x\n", info->cached_training->reg_6dc); + write_mchbar32(0x6dc, info->cached_training->reg_6dc); + } else + set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0, + info->delay46_ps[0], 0, + info->delay54_ps[0]); set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency, frequency_11(info), 2500, 0, 0, 0); set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency, frequency_11(info) / 2, 3500, 0, 0, 0); - set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0, - info->delay46_ps[1], 0, info->delay54_ps[1]); + if (s3resume) { + printk (BIOS_ERR, "[6e8] <= %x\n", info->cached_training->reg_6e8); + write_mchbar32(0x6e8, info->cached_training->reg_6e8); + } else + set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0, + info->delay46_ps[1], 0, + info->delay54_ps[1]); set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0); set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455, 470, 0); @@ -3641,7 +3676,7 @@ static void set_274265(struct raminfo *info) int channel;
delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info); - info->reg2ca9_bit0 = 0; + info->training.reg2ca9_bit0 = 0; for (channel = 0; channel < NUM_CHANNELS; channel++) { cycletime_ps = 900000 / lcm(2 * info->fsb_frequency, frequency_11(info)); @@ -3692,7 +3727,7 @@ static void set_274265(struct raminfo *info)
if (info->delay46_ps[channel] < 2500) { info->delay46_ps[channel] = 2500; - info->reg2ca9_bit0 = 1; + info->training.reg2ca9_bit0 = 1; } delay_b_ps = halfcycle_ps(info) + delay_c_ps; if (delay_b_ps <= delay_a_ps) @@ -3705,25 +3740,24 @@ static void set_274265(struct raminfo *info) 2 * halfcycle_ps(info) * delay_e_cycles; if (info->delay54_ps[channel] < 2500) info->delay54_ps[channel] = 2500; - info->reg274265[channel][0] = delay_e_cycles; + info->training.reg274265[channel][0] = delay_e_cycles; if (delay_d_ps + 7 * halfcycle_ps(info) <= 24 * halfcycle_ps(info)) - info->reg274265[channel][1] = 0; + info->training.reg274265[channel][1] = 0; else - info->reg274265[channel][1] = + info->training.reg274265[channel][1] = div_roundup(delay_d_ps + 7 * halfcycle_ps(info), 4 * halfcycle_ps(info)) - 6; write_mchbar32((channel << 10) + 0x274, - info->reg274265[channel][1] | (info-> - reg274265[channel] - [0] << 16)); - info->reg274265[channel][2] = + info->training.reg274265[channel][1] + | (info->training.reg274265[channel][0] << 16)); + info->training.reg274265[channel][2] = div_roundup(delay_c_ps + 3 * fsbcycle_ps(info), 4 * halfcycle_ps(info)) + 1; write_mchbar16((channel << 10) + 0x265, - info->reg274265[channel][2] << 8); + info->training.reg274265[channel][2] << 8); } - if (info->reg2ca9_bit0) + if (info->training.reg2ca9_bit0) write_mchbar8(0x2ca9, read_mchbar8(0x2ca9) | 1); else write_mchbar8(0x2ca9, read_mchbar8(0x2ca9) & ~1); @@ -3735,12 +3769,12 @@ static void restore_274265(struct raminfo *info)
for (channel = 0; channel < NUM_CHANNELS; channel++) { write_mchbar32((channel << 10) + 0x274, - (info->reg274265[channel][0] << 16) | info-> - reg274265[channel][1]); + (info->cached_training->reg274265[channel][0] << 16) + | info->cached_training->reg274265[channel][1]); write_mchbar16((channel << 10) + 0x265, - info->reg274265[channel][2] << 8); + info->cached_training->reg274265[channel][2] << 8); } - if (info->reg2ca9_bit0) + if (info->cached_training->reg2ca9_bit0) write_mchbar8(0x2ca9, read_mchbar8(0x2ca9) | 1); else write_mchbar8(0x2ca9, read_mchbar8(0x2ca9) & ~1); @@ -3763,6 +3797,7 @@ static void dmi_setup(void) } #endif
+#if REAL static void set_fsb_frequency (void) { @@ -3774,29 +3809,15 @@ set_fsb_frequency (void)
smbus_block_write(0x69, 0, 5, block); } +#endif
-#if REAL void raminit(const int s3resume) -#else -void raminit(int s3resume) -#endif { unsigned channel, slot, lane, rank; int i; struct raminfo info;
#if !REAL - pre_raminit1(); -#endif - - if (s3resume) { - read_mchbar32(0x1e8); - write_mchbar32(0x1e8, 0x6); - read_mchbar32(0x1e8); - write_mchbar32(0x1e8, 0x4); - } - -#if !REAL pre_raminit_2(); #endif u8 x2ca8; @@ -3822,7 +3843,7 @@ void raminit(int s3resume) #endif
#if !REAL - pre_raminit_4a(); + pre_raminit_4a(x2ca8); #endif
dmi_setup(); @@ -4160,50 +4181,29 @@ void raminit(int s3resume)
udelay(1000);
+ info.cached_training = get_cached_training(); + if (x2ca8 == 0) { - if (s3resume) { -#if REAL && 0 - info.reg2ca9_bit0 = 0; - info.reg274265[0][0] = 5; - info.reg274265[0][1] = 5; - info.reg274265[0][2] = 0xe; - info.reg274265[1][0] = 5; - info.reg274265[1][1] = 5; - info.reg274265[1][2] = 0xe; - info.delay46_ps[0] = 0xa86; - info.delay46_ps[1] = 0xa86; - info.delay54_ps[0] = 0xdc6; - info.delay54_ps[1] = 0xdc6; -#else - info.reg2ca9_bit0 = 0; - info.reg274265[0][0] = 3; - info.reg274265[0][1] = 5; - info.reg274265[0][2] = 0xd; - info.reg274265[1][0] = 4; - info.reg274265[1][1] = 5; - info.reg274265[1][2] = 0xd; - info.delay46_ps[0] = 0x110a; - info.delay46_ps[1] = 0xb58; - info.delay54_ps[0] = 0x144a; - info.delay54_ps[1] = 0xe98; -#endif + int j; + if (s3resume && info.cached_training) { restore_274265(&info); - } else + printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n", + info.cached_training->reg2ca9_bit0); + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n", + i, j, info.cached_training->reg274265[i][j]); + } else { set_274265(&info); - int j; - printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n", info.reg2ca9_bit0); - for (i = 0; i < 2; i++) - for (j = 0; j < 3; j++) - printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n", - i, j, info.reg274265[i][j]); - for (i = 0; i < 2; i++) - printk(BIOS_DEBUG, "delay46_ps[%d] = %x\n", i, - info.delay46_ps[i]); - for (i = 0; i < 2; i++) - printk(BIOS_DEBUG, "delay54_ps[%d] = %x\n", i, - info.delay54_ps[i]); - - set_2dxx_series(&info); + printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n", + info.training.reg2ca9_bit0); + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n", + i, j, info.training.reg274265[i][j]); + } + + set_2dxx_series(&info, s3resume);
if (!(deven & 8)) { read_mchbar32(0x2cb0); @@ -4519,8 +4519,6 @@ void raminit(int s3resume)
udelay(1000);
- info.cached_training = get_cached_training(); - if (s3resume) { if (info.cached_training == NULL) { u32 reg32; @@ -5010,10 +5008,3 @@ unsigned long get_top_of_ram(void) } #endif
-#if !REAL -int main(void) -{ - raminit(0); - return 0; -} -#endif