nehalem: Restore frequency ratio registers on S3 resume

Previously registers 274/265 and 6dc/6e8 were recomputed
which lead to a slightly different values. On
S3 resume it needs to be a perfect match.

Change-Id: I14f42c7659dde5f327979831fcb1f84ea0c78dee
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-on: http://review.coreboot.org/4634
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <patrick@georgi-clan.de>
This commit is contained in:
Vladimir Serbinenko 2014-01-09 11:10:04 +01:00
parent f62669c966
commit f7a42de725
1 changed files with 79 additions and 67 deletions

View File

@ -102,6 +102,10 @@ struct ram_training {
u16 timing_offset[2][2][2][9]; u16 timing_offset[2][2][2][9];
u16 timing2_offset[2][2][2][9]; u16 timing2_offset[2][2][2][9];
u16 timing2_bounds[2][2][2][9][2]; 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 #if !REAL
@ -259,8 +263,6 @@ struct raminfo {
struct ram_training training; struct ram_training training;
u32 last_500_command[2]; u32 last_500_command[2];
u8 reg2ca9_bit0;
u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
u32 delay46_ps[2]; u32 delay46_ps[2];
u32 delay54_ps[2]; u32 delay54_ps[2];
u8 revision_flag_1; u8 revision_flag_1;
@ -1680,6 +1682,9 @@ static void dump_timings(struct raminfo *info)
#endif #endif
} }
/* Read timings and other registers that need to be restored verbatim and
put them to CBMEM.
*/
static void save_timings(struct raminfo *info) static void save_timings(struct raminfo *info)
{ {
#if CONFIG_EARLY_CBMEM_INIT #if CONFIG_EARLY_CBMEM_INIT
@ -1698,6 +1703,20 @@ static void save_timings(struct raminfo *info)
train.reg_178 = read_1d0(0x178, 7); train.reg_178 = read_1d0(0x178, 7);
train.reg_10b = read_1d0(0x10b, 6); 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_SPEW, "[6dc] = %x\n", train.reg_6dc);
printk (BIOS_SPEW, "[6e8] = %x\n", train.reg_6e8);
/* Save the MRC S3 restore data to cbmem */ /* Save the MRC S3 restore data to cbmem */
cbmem_recovery(0); cbmem_recovery(0);
mrcdata = cbmem_add mrcdata = cbmem_add
@ -3491,6 +3510,13 @@ set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
0, 1, &ratios2); 0, 1, &ratios2);
compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4, compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
0, 1, &ratios1); 0, 1, &ratios1);
printk (BIOS_SPEW, "[%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, write_mchbar32(reg,
ratios1.freq4_to_max_remainder | (ratios2. ratios1.freq4_to_max_remainder | (ratios2.
freq4_to_max_remainder freq4_to_max_remainder
@ -3553,7 +3579,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, set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
0, 1); 0, 1);
@ -3581,14 +3607,24 @@ static void set_2dxx_series(struct raminfo *info)
set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency, set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
frequency_11(info) / 2, 4000, 4000, 0, 0); frequency_11(info) / 2, 4000, 4000, 0, 0);
if (s3resume) {
printk (BIOS_SPEW, "[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, set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
info->delay46_ps[0], 0, info->delay54_ps[0]); info->delay46_ps[0], 0,
info->delay54_ps[0]);
set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency, set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
frequency_11(info), 2500, 0, 0, 0); frequency_11(info), 2500, 0, 0, 0);
set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency, set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
frequency_11(info) / 2, 3500, 0, 0, 0); frequency_11(info) / 2, 3500, 0, 0, 0);
if (s3resume) {
printk (BIOS_SPEW, "[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, set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
info->delay46_ps[1], 0, info->delay54_ps[1]); 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, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455, set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
470, 0); 470, 0);
@ -3639,7 +3675,7 @@ static void set_274265(struct raminfo *info)
int channel; int channel;
delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info); 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++) { for (channel = 0; channel < NUM_CHANNELS; channel++) {
cycletime_ps = cycletime_ps =
900000 / lcm(2 * info->fsb_frequency, frequency_11(info)); 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
@ -3690,7 +3726,7 @@ static void set_274265(struct raminfo *info)
if (info->delay46_ps[channel] < 2500) { if (info->delay46_ps[channel] < 2500) {
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; delay_b_ps = halfcycle_ps(info) + delay_c_ps;
if (delay_b_ps <= delay_a_ps) if (delay_b_ps <= delay_a_ps)
@ -3703,25 +3739,24 @@ static void set_274265(struct raminfo *info)
2 * halfcycle_ps(info) * delay_e_cycles; 2 * halfcycle_ps(info) * delay_e_cycles;
if (info->delay54_ps[channel] < 2500) if (info->delay54_ps[channel] < 2500)
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) <= if (delay_d_ps + 7 * halfcycle_ps(info) <=
24 * halfcycle_ps(info)) 24 * halfcycle_ps(info))
info->reg274265[channel][1] = 0; info->training.reg274265[channel][1] = 0;
else else
info->reg274265[channel][1] = info->training.reg274265[channel][1] =
div_roundup(delay_d_ps + 7 * halfcycle_ps(info), div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
4 * halfcycle_ps(info)) - 6; 4 * halfcycle_ps(info)) - 6;
write_mchbar32((channel << 10) + 0x274, write_mchbar32((channel << 10) + 0x274,
info->reg274265[channel][1] | (info-> info->training.reg274265[channel][1]
reg274265[channel] | (info->training.reg274265[channel][0] << 16));
[0] << 16)); info->training.reg274265[channel][2] =
info->reg274265[channel][2] =
div_roundup(delay_c_ps + 3 * fsbcycle_ps(info), div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
4 * halfcycle_ps(info)) + 1; 4 * halfcycle_ps(info)) + 1;
write_mchbar16((channel << 10) + 0x265, 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); write_mchbar8(0x2ca9, read_mchbar8(0x2ca9) | 1);
else else
write_mchbar8(0x2ca9, read_mchbar8(0x2ca9) & ~1); write_mchbar8(0x2ca9, read_mchbar8(0x2ca9) & ~1);
@ -3733,12 +3768,12 @@ static void restore_274265(struct raminfo *info)
for (channel = 0; channel < NUM_CHANNELS; channel++) { for (channel = 0; channel < NUM_CHANNELS; channel++) {
write_mchbar32((channel << 10) + 0x274, write_mchbar32((channel << 10) + 0x274,
(info->reg274265[channel][0] << 16) | info-> (info->cached_training->reg274265[channel][0] << 16)
reg274265[channel][1]); | info->cached_training->reg274265[channel][1]);
write_mchbar16((channel << 10) + 0x265, 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); write_mchbar8(0x2ca9, read_mchbar8(0x2ca9) | 1);
else else
write_mchbar8(0x2ca9, read_mchbar8(0x2ca9) & ~1); write_mchbar8(0x2ca9, read_mchbar8(0x2ca9) & ~1);
@ -4145,50 +4180,29 @@ void raminit(const int s3resume)
udelay(1000); udelay(1000);
info.cached_training = get_cached_training();
if (x2ca8 == 0) { 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
restore_274265(&info);
} else
set_274265(&info);
int j; int j;
printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n", info.reg2ca9_bit0); if (s3resume && info.cached_training) {
restore_274265(&info);
printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n",
info.cached_training->reg2ca9_bit0);
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
for (j = 0; j < 3; j++) for (j = 0; j < 3; j++)
printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n", printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n",
i, j, info.reg274265[i][j]); i, j, info.cached_training->reg274265[i][j]);
} else {
set_274265(&info);
printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n",
info.training.reg2ca9_bit0);
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
printk(BIOS_DEBUG, "delay46_ps[%d] = %x\n", i, for (j = 0; j < 3; j++)
info.delay46_ps[i]); printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n",
for (i = 0; i < 2; i++) i, j, info.training.reg274265[i][j]);
printk(BIOS_DEBUG, "delay54_ps[%d] = %x\n", i, }
info.delay54_ps[i]);
set_2dxx_series(&info); set_2dxx_series(&info, s3resume);
if (!(deven & 8)) { if (!(deven & 8)) {
read_mchbar32(0x2cb0); read_mchbar32(0x2cb0);
@ -4504,8 +4518,6 @@ void raminit(const int s3resume)
udelay(1000); udelay(1000);
info.cached_training = get_cached_training();
if (s3resume) { if (s3resume) {
if (info.cached_training == NULL) { if (info.cached_training == NULL) {
u32 reg32; u32 reg32;