nb/intel/sandybridge: Use bitfields to program MCMAIN timings
Tested on Asus P8H61-M PRO, still boots. Change-Id: I9a996de5d596cdb541c8b327f119425243724007 Signed-off-by: Angel Pons <th3fanbus@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/47512 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
This commit is contained in:
parent
593f4ca10b
commit
7a61274943
|
@ -135,63 +135,67 @@ static void dram_odt_stretch(ramctr_timing *ctrl, int channel)
|
||||||
printk(RAM_DEBUG, "OTHP Workaround [%x] = %x\n", addr, MCHBAR32(addr));
|
printk(RAM_DEBUG, "OTHP Workaround [%x] = %x\n", addr, MCHBAR32(addr));
|
||||||
} else {
|
} else {
|
||||||
addr = TC_OTHP_ch(channel);
|
addr = TC_OTHP_ch(channel);
|
||||||
MCHBAR32_AND_OR(addr, ~(0xf << 16), (stretch << 16) | (stretch << 18));
|
union tc_othp_reg tc_othp = {
|
||||||
|
.raw = MCHBAR32(addr),
|
||||||
|
};
|
||||||
|
tc_othp.odt_delay_d0 = stretch;
|
||||||
|
tc_othp.odt_delay_d1 = stretch;
|
||||||
|
MCHBAR32(addr) = tc_othp.raw;
|
||||||
printk(RAM_DEBUG, "OTHP [%x] = %x\n", addr, MCHBAR32(addr));
|
printk(RAM_DEBUG, "OTHP [%x] = %x\n", addr, MCHBAR32(addr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dram_timing_regs(ramctr_timing *ctrl)
|
void dram_timing_regs(ramctr_timing *ctrl)
|
||||||
{
|
{
|
||||||
u32 reg, val32;
|
|
||||||
int channel;
|
int channel;
|
||||||
|
|
||||||
FOR_ALL_CHANNELS {
|
FOR_ALL_CHANNELS {
|
||||||
/* BIN parameters */
|
/* BIN parameters */
|
||||||
reg = 0;
|
const union tc_dbp_reg tc_dbp = {
|
||||||
reg |= (ctrl->tRCD << 0);
|
.tRCD = ctrl->tRCD,
|
||||||
reg |= (ctrl->tRP << 4);
|
.tRP = ctrl->tRP,
|
||||||
reg |= (ctrl->CAS << 8);
|
.tAA = ctrl->CAS,
|
||||||
reg |= (ctrl->CWL << 12);
|
.tCWL = ctrl->CWL,
|
||||||
reg |= (ctrl->tRAS << 16);
|
.tRAS = ctrl->tRAS,
|
||||||
printram("DBP [%x] = %x\n", TC_DBP_ch(channel), reg);
|
};
|
||||||
MCHBAR32(TC_DBP_ch(channel)) = reg;
|
printram("DBP [%x] = %x\n", TC_DBP_ch(channel), tc_dbp.raw);
|
||||||
|
MCHBAR32(TC_DBP_ch(channel)) = tc_dbp.raw;
|
||||||
|
|
||||||
/* Regular access parameters */
|
/* Regular access parameters */
|
||||||
reg = 0;
|
const union tc_rap_reg tc_rap = {
|
||||||
reg |= (ctrl->tRRD << 0);
|
.tRRD = ctrl->tRRD,
|
||||||
reg |= (ctrl->tRTP << 4);
|
.tRTP = ctrl->tRTP,
|
||||||
reg |= (ctrl->tCKE << 8);
|
.tCKE = ctrl->tCKE,
|
||||||
reg |= (ctrl->tWTR << 12);
|
.tWTR = ctrl->tWTR,
|
||||||
reg |= (ctrl->tFAW << 16);
|
.tFAW = ctrl->tFAW,
|
||||||
reg |= (ctrl->tWR << 24);
|
.tWR = ctrl->tWR,
|
||||||
reg |= (3 << 30);
|
.tCMD = 3,
|
||||||
printram("RAP [%x] = %x\n", TC_RAP_ch(channel), reg);
|
};
|
||||||
MCHBAR32(TC_RAP_ch(channel)) = reg;
|
printram("RAP [%x] = %x\n", TC_RAP_ch(channel), tc_rap.raw);
|
||||||
|
MCHBAR32(TC_RAP_ch(channel)) = tc_rap.raw;
|
||||||
|
|
||||||
/* Other parameters */
|
/* Other parameters */
|
||||||
reg = 0;
|
const union tc_othp_reg tc_othp = {
|
||||||
reg |= (ctrl->tXPDLL << 0);
|
.tXPDLL = ctrl->tXPDLL,
|
||||||
reg |= (ctrl->tXP << 5);
|
.tXP = ctrl->tXP,
|
||||||
reg |= (ctrl->tAONPD << 8);
|
.tAONPD = ctrl->tAONPD,
|
||||||
reg |= 0xa0000;
|
.tCPDED = 2,
|
||||||
printram("OTHP [%x] = %x\n", TC_OTHP_ch(channel), reg);
|
.tPRPDEN = 2,
|
||||||
MCHBAR32(TC_OTHP_ch(channel)) = reg;
|
};
|
||||||
|
printram("OTHP [%x] = %x\n", TC_OTHP_ch(channel), tc_othp.raw);
|
||||||
|
MCHBAR32(TC_OTHP_ch(channel)) = tc_othp.raw;
|
||||||
|
|
||||||
/* Debug parameters - only applies to Ivy Bridge */
|
/* Debug parameters - only applies to Ivy Bridge */
|
||||||
if (IS_IVY_CPU(ctrl->cpu)) {
|
if (IS_IVY_CPU(ctrl->cpu)) {
|
||||||
reg = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If tXP and tXPDLL are very high, we need to increase them by one.
|
* If tXP and tXPDLL are very high, we need to increase them by one.
|
||||||
* This can only happen on Ivy Bridge, and when overclocking the RAM.
|
* This can only happen on Ivy Bridge, and when overclocking the RAM.
|
||||||
*/
|
*/
|
||||||
if (ctrl->tXP >= 8)
|
const union tc_dtp_reg tc_dtp = {
|
||||||
reg |= (1 << 12);
|
.overclock_tXP = ctrl->tXP >= 8,
|
||||||
|
.overclock_tXPDLL = ctrl->tXPDLL >= 32,
|
||||||
if (ctrl->tXPDLL >= 32)
|
};
|
||||||
reg |= (1 << 13);
|
MCHBAR32(TC_DTP_ch(channel)) = tc_dtp.raw;
|
||||||
|
|
||||||
MCHBAR32(TC_DTP_ch(channel)) = reg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dram_odt_stretch(ctrl, channel);
|
dram_odt_stretch(ctrl, channel);
|
||||||
|
@ -201,28 +205,31 @@ void dram_timing_regs(ramctr_timing *ctrl)
|
||||||
* The tREFIx9 field should be programmed to minimum of 8.9 * tREFI (to allow
|
* The tREFIx9 field should be programmed to minimum of 8.9 * tREFI (to allow
|
||||||
* for possible delays from ZQ or isoc) and tRASmax (70us) divided by 1024.
|
* for possible delays from ZQ or isoc) and tRASmax (70us) divided by 1024.
|
||||||
*/
|
*/
|
||||||
val32 = MIN((ctrl->tREFI * 89) / 10, (70000 << 8) / ctrl->tCK);
|
const u32 val32 = MIN((ctrl->tREFI * 89) / 10, (70000 << 8) / ctrl->tCK);
|
||||||
|
|
||||||
reg = ((ctrl->tREFI & 0xffff) << 0) |
|
const union tc_rftp_reg tc_rftp = {
|
||||||
((ctrl->tRFC & 0x01ff) << 16) | (((val32 / 1024) & 0x7f) << 25);
|
.tREFI = ctrl->tREFI,
|
||||||
|
.tRFC = ctrl->tRFC,
|
||||||
|
.tREFIx9 = val32 / 1024,
|
||||||
|
};
|
||||||
|
printram("REFI [%x] = %x\n", TC_RFTP_ch(channel), tc_rftp.raw);
|
||||||
|
MCHBAR32(TC_RFTP_ch(channel)) = tc_rftp.raw;
|
||||||
|
|
||||||
printram("REFI [%x] = %x\n", TC_RFTP_ch(channel), reg);
|
union tc_rfp_reg tc_rfp = {
|
||||||
MCHBAR32(TC_RFTP_ch(channel)) = reg;
|
.raw = MCHBAR32(TC_RFP_ch(channel)),
|
||||||
|
};
|
||||||
MCHBAR32_OR(TC_RFP_ch(channel), 0xff);
|
tc_rfp.oref_ri = 0xff;
|
||||||
|
MCHBAR32(TC_RFP_ch(channel)) = tc_rfp.raw;
|
||||||
|
|
||||||
/* Self-refresh timing parameters */
|
/* Self-refresh timing parameters */
|
||||||
reg = 0;
|
const union tc_srftp_reg tc_srftp = {
|
||||||
val32 = tDLLK;
|
.tXSDLL = tDLLK,
|
||||||
reg = (reg & ~0x00000fff) | (val32 << 0);
|
.tXS_offset = ctrl->tXSOffset,
|
||||||
val32 = ctrl->tXSOffset;
|
.tZQOPER = tDLLK - ctrl->tXSOffset,
|
||||||
reg = (reg & ~0x0000f000) | (val32 << 12);
|
.tMOD = ctrl->tMOD - 8,
|
||||||
val32 = tDLLK - ctrl->tXSOffset;
|
};
|
||||||
reg = (reg & ~0x03ff0000) | (val32 << 16);
|
printram("SRFTP [%x] = %x\n", TC_SRFTP_ch(channel), tc_srftp.raw);
|
||||||
val32 = ctrl->tMOD - 8;
|
MCHBAR32(TC_SRFTP_ch(channel)) = tc_srftp.raw;
|
||||||
reg = (reg & ~0xf0000000) | (val32 << 28);
|
|
||||||
printram("SRFTP [%x] = %x\n", TC_SRFTP_ch(channel), reg);
|
|
||||||
MCHBAR32(TC_SRFTP_ch(channel)) = reg;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2215,14 +2222,16 @@ static int try_cmd_stretch(ramctr_timing *ctrl, int channel, int cmd_stretch)
|
||||||
|
|
||||||
ctrl->cmd_stretch[channel] = cmd_stretch;
|
ctrl->cmd_stretch[channel] = cmd_stretch;
|
||||||
|
|
||||||
MCHBAR32(TC_RAP_ch(channel)) =
|
const union tc_rap_reg tc_rap = {
|
||||||
(ctrl->tRRD << 0)
|
.tRRD = ctrl->tRRD,
|
||||||
| (ctrl->tRTP << 4)
|
.tRTP = ctrl->tRTP,
|
||||||
| (ctrl->tCKE << 8)
|
.tCKE = ctrl->tCKE,
|
||||||
| (ctrl->tWTR << 12)
|
.tWTR = ctrl->tWTR,
|
||||||
| (ctrl->tFAW << 16)
|
.tFAW = ctrl->tFAW,
|
||||||
| (ctrl->tWR << 24)
|
.tWR = ctrl->tWR,
|
||||||
| (ctrl->cmd_stretch[channel] << 30);
|
.tCMD = ctrl->cmd_stretch[channel],
|
||||||
|
};
|
||||||
|
MCHBAR32(TC_RAP_ch(channel)) = tc_rap.raw;
|
||||||
|
|
||||||
if (ctrl->cmd_stretch[channel] == 2)
|
if (ctrl->cmd_stretch[channel] == 2)
|
||||||
delta = 2;
|
delta = 2;
|
||||||
|
@ -2980,7 +2989,6 @@ void set_read_write_timings(ramctr_timing *ctrl)
|
||||||
int channel, slotrank;
|
int channel, slotrank;
|
||||||
|
|
||||||
FOR_ALL_POPULATED_CHANNELS {
|
FOR_ALL_POPULATED_CHANNELS {
|
||||||
u32 b20, b4_8_12;
|
|
||||||
int min_pi = 10000;
|
int min_pi = 10000;
|
||||||
int max_pi = -10000;
|
int max_pi = -10000;
|
||||||
|
|
||||||
|
@ -2989,14 +2997,23 @@ void set_read_write_timings(ramctr_timing *ctrl)
|
||||||
min_pi = MIN(ctrl->timings[channel][slotrank].pi_coding, min_pi);
|
min_pi = MIN(ctrl->timings[channel][slotrank].pi_coding, min_pi);
|
||||||
}
|
}
|
||||||
|
|
||||||
b20 = (max_pi - min_pi > 51) ? 0 : ctrl->ref_card_offset[channel];
|
const u32 tWRDRDD = (max_pi - min_pi > 51) ? 0 : ctrl->ref_card_offset[channel];
|
||||||
|
|
||||||
b4_8_12 = (ctrl->pi_coding_threshold < max_pi - min_pi) ? 0x3330 : 0x2220;
|
const u32 val = (ctrl->pi_coding_threshold < max_pi - min_pi) ? 3 : 2;
|
||||||
|
|
||||||
dram_odt_stretch(ctrl, channel);
|
dram_odt_stretch(ctrl, channel);
|
||||||
|
|
||||||
MCHBAR32(TC_RWP_ch(channel)) = (1 << 27) | (2 << 24) | (b20 << 20) |
|
const union tc_rwp_reg tc_rwp = {
|
||||||
((ctrl->ref_card_offset[channel] + 2) << 16) | b4_8_12;
|
.tRRDR = 0,
|
||||||
|
.tRRDD = val,
|
||||||
|
.tWWDR = val,
|
||||||
|
.tWWDD = val,
|
||||||
|
.tRWDRDD = ctrl->ref_card_offset[channel] + 2,
|
||||||
|
.tWRDRDD = tWRDRDD,
|
||||||
|
.tRWSR = 2,
|
||||||
|
.dec_wrd = 1,
|
||||||
|
};
|
||||||
|
MCHBAR32(TC_RWP_ch(channel)) = tc_rwp.raw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3028,8 +3045,13 @@ void final_registers(ramctr_timing *ctrl)
|
||||||
/* FIXME: This register only exists on Ivy Bridge */
|
/* FIXME: This register only exists on Ivy Bridge */
|
||||||
MCHBAR32(WMM_READ_CONFIG) = 0x46;
|
MCHBAR32(WMM_READ_CONFIG) = 0x46;
|
||||||
|
|
||||||
FOR_ALL_CHANNELS
|
FOR_ALL_CHANNELS {
|
||||||
MCHBAR32_AND_OR(TC_OTHP_ch(channel), ~(3 << 12), 1 << 12);
|
union tc_othp_reg tc_othp = {
|
||||||
|
.raw = MCHBAR32(TC_OTHP_ch(channel)),
|
||||||
|
};
|
||||||
|
tc_othp.tCPDED = 1;
|
||||||
|
MCHBAR32(TC_OTHP_ch(channel)) = tc_othp.raw;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_mobile)
|
if (is_mobile)
|
||||||
/* APD - DLL Off, 64 DCLKs until idle, decision per rank */
|
/* APD - DLL Off, 64 DCLKs until idle, decision per rank */
|
||||||
|
@ -3067,8 +3089,13 @@ void final_registers(ramctr_timing *ctrl)
|
||||||
MCHBAR32_AND_OR(MEM_TRML_THRESHOLDS_CONFIG, ~0x00ffffff, 0x00e4d5d0);
|
MCHBAR32_AND_OR(MEM_TRML_THRESHOLDS_CONFIG, ~0x00ffffff, 0x00e4d5d0);
|
||||||
MCHBAR32_AND(MEM_TRML_INTERRUPT, ~0x1f);
|
MCHBAR32_AND(MEM_TRML_INTERRUPT, ~0x1f);
|
||||||
|
|
||||||
FOR_ALL_CHANNELS
|
FOR_ALL_CHANNELS {
|
||||||
MCHBAR32_AND_OR(TC_RFP_ch(channel), ~(3 << 16), 1 << 16);
|
union tc_rfp_reg tc_rfp = {
|
||||||
|
.raw = MCHBAR32(TC_RFP_ch(channel)),
|
||||||
|
};
|
||||||
|
tc_rfp.refresh_2x_control = 1;
|
||||||
|
MCHBAR32(TC_RFP_ch(channel)) = tc_rfp.raw;
|
||||||
|
}
|
||||||
|
|
||||||
MCHBAR32_OR(MC_INIT_STATE_G, 1 << 0);
|
MCHBAR32_OR(MC_INIT_STATE_G, 1 << 0);
|
||||||
MCHBAR32_OR(MC_INIT_STATE_G, 1 << 7);
|
MCHBAR32_OR(MC_INIT_STATE_G, 1 << 7);
|
||||||
|
@ -3107,14 +3134,16 @@ void restore_timings(ramctr_timing *ctrl)
|
||||||
int channel, lane;
|
int channel, lane;
|
||||||
|
|
||||||
FOR_ALL_POPULATED_CHANNELS {
|
FOR_ALL_POPULATED_CHANNELS {
|
||||||
MCHBAR32(TC_RAP_ch(channel)) =
|
const union tc_rap_reg tc_rap = {
|
||||||
(ctrl->tRRD << 0)
|
.tRRD = ctrl->tRRD,
|
||||||
| (ctrl->tRTP << 4)
|
.tRTP = ctrl->tRTP,
|
||||||
| (ctrl->tCKE << 8)
|
.tCKE = ctrl->tCKE,
|
||||||
| (ctrl->tWTR << 12)
|
.tWTR = ctrl->tWTR,
|
||||||
| (ctrl->tFAW << 16)
|
.tFAW = ctrl->tFAW,
|
||||||
| (ctrl->tWR << 24)
|
.tWR = ctrl->tWR,
|
||||||
| (ctrl->cmd_stretch[channel] << 30);
|
.tCMD = ctrl->cmd_stretch[channel],
|
||||||
|
};
|
||||||
|
MCHBAR32(TC_RAP_ch(channel)) = tc_rap.raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
udelay(1);
|
udelay(1);
|
||||||
|
|
|
@ -98,6 +98,108 @@ struct iosav_ssq {
|
||||||
} addr_update;
|
} addr_update;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union tc_dbp_reg {
|
||||||
|
struct {
|
||||||
|
u32 tRCD : 4; /* [ 3.. 0] */
|
||||||
|
u32 tRP : 4; /* [ 7.. 4] */
|
||||||
|
u32 tAA : 4; /* [11.. 8] */
|
||||||
|
u32 tCWL : 4; /* [15..12] */
|
||||||
|
u32 tRAS : 8; /* [23..16] */
|
||||||
|
u32 : 8;
|
||||||
|
};
|
||||||
|
u32 raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
union tc_rap_reg {
|
||||||
|
struct {
|
||||||
|
u32 tRRD : 4; /* [ 3.. 0] */
|
||||||
|
u32 tRTP : 4; /* [ 7.. 4] */
|
||||||
|
u32 tCKE : 4; /* [11.. 8] */
|
||||||
|
u32 tWTR : 4; /* [15..12] */
|
||||||
|
u32 tFAW : 8; /* [23..16] */
|
||||||
|
u32 tWR : 5; /* [28..24] */
|
||||||
|
u32 dis_3st : 1; /* [29..29] */
|
||||||
|
u32 tCMD : 2; /* [31..30] */
|
||||||
|
};
|
||||||
|
u32 raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
union tc_rwp_reg {
|
||||||
|
struct {
|
||||||
|
u32 tRRDR : 3; /* [ 2.. 0] */
|
||||||
|
u32 : 1;
|
||||||
|
u32 tRRDD : 3; /* [ 6.. 4] */
|
||||||
|
u32 : 1;
|
||||||
|
u32 tWWDR : 3; /* [10.. 8] */
|
||||||
|
u32 : 1;
|
||||||
|
u32 tWWDD : 3; /* [14..12] */
|
||||||
|
u32 : 1;
|
||||||
|
u32 tRWDRDD : 3; /* [18..16] */
|
||||||
|
u32 : 1;
|
||||||
|
u32 tWRDRDD : 3; /* [22..20] */
|
||||||
|
u32 : 1;
|
||||||
|
u32 tRWSR : 3; /* [26..24] */
|
||||||
|
u32 dec_wrd : 1; /* [27..27] */
|
||||||
|
u32 : 4;
|
||||||
|
};
|
||||||
|
u32 raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
union tc_othp_reg {
|
||||||
|
struct {
|
||||||
|
u32 tXPDLL : 5; /* [ 4.. 0] */
|
||||||
|
u32 tXP : 3; /* [ 7.. 5] */
|
||||||
|
u32 tAONPD : 4; /* [11.. 8] */
|
||||||
|
u32 tCPDED : 2; /* [13..12] */
|
||||||
|
u32 tPRPDEN : 2; /* [15..14] */
|
||||||
|
u32 odt_delay_d0 : 2; /* [17..16] */
|
||||||
|
u32 odt_delay_d1 : 2; /* [19..18] */
|
||||||
|
u32 : 12;
|
||||||
|
};
|
||||||
|
u32 raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
union tc_dtp_reg {
|
||||||
|
struct {
|
||||||
|
u32 : 12;
|
||||||
|
u32 overclock_tXP : 1; /* [12..12] */
|
||||||
|
u32 overclock_tXPDLL : 1; /* [13..13] */
|
||||||
|
u32 : 18;
|
||||||
|
};
|
||||||
|
u32 raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
union tc_rfp_reg {
|
||||||
|
struct {
|
||||||
|
u32 oref_ri : 8; /* [ 7.. 0] */
|
||||||
|
u32 refresh_high_wm : 4; /* [11.. 8] */
|
||||||
|
u32 refresh_panic_wm : 4; /* [15..12] */
|
||||||
|
u32 refresh_2x_control : 2; /* [17..16] */
|
||||||
|
u32 : 14;
|
||||||
|
};
|
||||||
|
u32 raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
union tc_rftp_reg {
|
||||||
|
struct {
|
||||||
|
u32 tREFI : 16; /* [15.. 0] */
|
||||||
|
u32 tRFC : 9; /* [24..16] */
|
||||||
|
u32 tREFIx9 : 7; /* [31..25] */
|
||||||
|
};
|
||||||
|
u32 raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
union tc_srftp_reg {
|
||||||
|
struct {
|
||||||
|
u32 tXSDLL : 12; /* [11.. 0] */
|
||||||
|
u32 tXS_offset : 4; /* [15..12] */
|
||||||
|
u32 tZQOPER : 10; /* [25..16] */
|
||||||
|
u32 : 2;
|
||||||
|
u32 tMOD : 4; /* [31..28] */
|
||||||
|
};
|
||||||
|
u32 raw;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct ramctr_timing_st ramctr_timing;
|
typedef struct ramctr_timing_st ramctr_timing;
|
||||||
|
|
||||||
void iosav_write_sequence(const int ch, const struct iosav_ssq *seq, const unsigned int length);
|
void iosav_write_sequence(const int ch, const struct iosav_ssq *seq, const unsigned int length);
|
||||||
|
|
Loading…
Reference in New Issue