nb/intel/x4x: Add DDR3 JEDEC init
Add DDR3 JEDEC init (Power up and Initialization by setting emrs regs) This also modifies the send_jedec_cmd function as DDR3 dimms can have ranks mirrored which needs to be accounted for. The ddr3_emrs1_config array is placed externally since it is also needed for write leveling. Change-Id: I510b8669aaa48ba99fb4dcf1ece716aef26741bb Signed-off-by: Arthur Heymans <arthur@aheymans.xyz> Reviewed-on: https://review.coreboot.org/22994 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
This commit is contained in:
parent
9129f1aae9
commit
f1287266ab
|
@ -408,6 +408,9 @@ static int ddr3_save_dimminfo(u8 dimm_idx, u8 *raw_spd,
|
|||
|
||||
s->dimms[dimm_idx].spd_crc = spd_ddr3_calc_unique_crc(raw_spd,
|
||||
raw_spd[0]);
|
||||
|
||||
s->dimms[dimm_idx].mirrored = decoded_dimm.flags.pins_mirrored;
|
||||
|
||||
return CB_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -1347,14 +1347,45 @@ u32 test_address(int channel, int rank)
|
|||
return channel * 512 * MiB + rank * 128 * MiB;
|
||||
}
|
||||
|
||||
static void dojedec_ddr2(u8 r, u8 ch, u8 cmd, u16 val)
|
||||
|
||||
/* DDR3 Rank1 Address mirror
|
||||
* swap the following pins:
|
||||
* A3<->A4, A5<->A6, A7<->A8, BA0<->BA1 */
|
||||
static u32 mirror_shift_bit(const u32 data, u8 bit)
|
||||
{
|
||||
u32 temp0 = data, temp1 = data;
|
||||
temp0 &= 1 << bit;
|
||||
temp0 <<= 1;
|
||||
temp1 &= 1 << (bit + 1);
|
||||
temp1 >>= 1;
|
||||
return (data & ~(3 << bit)) | temp0 | temp1;
|
||||
}
|
||||
|
||||
static void send_jedec_cmd(const struct sysinfo *s, u8 r,
|
||||
u8 ch, u8 cmd, u32 val)
|
||||
{
|
||||
u32 addr = test_address(ch, r);
|
||||
volatile u32 rubbish;
|
||||
u8 data8 = cmd;
|
||||
u32 data32;
|
||||
|
||||
MCHBAR8(0x271) = (MCHBAR8(0x271) & ~0x3e) | cmd;
|
||||
MCHBAR8(0x671) = (MCHBAR8(0x671) & ~0x3e) | cmd;
|
||||
rubbish = read32((void *)((val<<3) | addr));
|
||||
if (s->spd_type == DDR3 && (r & 1)
|
||||
&& s->dimms[ch * 2 + (r >> 1)].mirrored) {
|
||||
data8 = (u8)mirror_shift_bit(data8, 4);
|
||||
}
|
||||
|
||||
MCHBAR8(0x271) = (MCHBAR8(0x271) & ~0x3e) | data8;
|
||||
MCHBAR8(0x671) = (MCHBAR8(0x671) & ~0x3e) | data8;
|
||||
data32 = val;
|
||||
if (s->spd_type == DDR3 && (r & 1)
|
||||
&& s->dimms[ch * 2 + (r >> 1)].mirrored) {
|
||||
data32 = mirror_shift_bit(data32, 3);
|
||||
data32 = mirror_shift_bit(data32, 5);
|
||||
data32 = mirror_shift_bit(data32, 7);
|
||||
}
|
||||
data32 <<= 3;
|
||||
|
||||
rubbish = read32((void *)((data32 | addr)));
|
||||
udelay(10);
|
||||
MCHBAR8(0x271) = (MCHBAR8(0x271) & ~0x3e) | NORMALOP_CMD;
|
||||
MCHBAR8(0x671) = (MCHBAR8(0x671) & ~0x3e) | NORMALOP_CMD;
|
||||
|
@ -1419,7 +1450,7 @@ static void jedec_ddr2(struct sysinfo *s)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
dojedec_ddr2(r, ch, jedec[i][0], v);
|
||||
send_jedec_cmd(s, r, ch, jedec[i][0], v);
|
||||
udelay(1);
|
||||
printk(RAM_SPEW, "Jedec step %d\n", i);
|
||||
}
|
||||
|
@ -1427,6 +1458,55 @@ static void jedec_ddr2(struct sysinfo *s)
|
|||
printk(BIOS_DEBUG, "MRS done\n");
|
||||
}
|
||||
|
||||
static void jedec_ddr3(struct sysinfo *s)
|
||||
{
|
||||
int ch, r, dimmconfig, cmd, ddr3_freq;
|
||||
|
||||
u8 ddr3_emrs2_rtt_wr_config[16][4] = { /* [config][Rank] */
|
||||
{0, 0, 0, 0}, /* NC_NC */
|
||||
{0, 0, 0, 0}, /* x8ss_NC */
|
||||
{0, 0, 0, 0}, /* x8ds_NC */
|
||||
{0, 0, 0, 0}, /* x16ss_NC */
|
||||
{0, 0, 0, 0}, /* NC_x8ss */
|
||||
{2, 0, 2, 0}, /* x8ss_x8ss */
|
||||
{2, 2, 2, 0}, /* x8ds_x8ss */
|
||||
{2, 0, 2, 0}, /* x16ss_x8ss */
|
||||
{0, 0, 0, 0}, /* NC_x8ss */
|
||||
{2, 0, 2, 2}, /* x8ss_x8ds */
|
||||
{2, 2, 2, 2}, /* x8ds_x8ds */
|
||||
{2, 0, 2, 2}, /* x16ss_x8ds */
|
||||
{0, 0, 0, 0}, /* NC_x16ss */
|
||||
{2, 0, 2, 0}, /* x8ss_x16ss */
|
||||
{2, 2, 2, 0}, /* x8ds_x16ss */
|
||||
{2, 0, 2, 0}, /* x16ss_x16ss */
|
||||
};
|
||||
|
||||
printk(BIOS_DEBUG, "MRS...\n");
|
||||
|
||||
ddr3_freq = s->selected_timings.mem_clk - MEM_CLOCK_800MHz;
|
||||
FOR_EACH_POPULATED_RANK(s->dimms, ch, r) {
|
||||
printk(BIOS_DEBUG, "CH%d: Found Rank %d\n", ch, r);
|
||||
send_jedec_cmd(s, r, ch, NOP_CMD, 0);
|
||||
udelay(200);
|
||||
dimmconfig = s->dimm_config[ch];
|
||||
cmd = ddr3_freq << 3; /* actually twl - 5 which is same */
|
||||
cmd |= ddr3_emrs2_rtt_wr_config[dimmconfig][r] << 9;
|
||||
send_jedec_cmd(s, r, ch, EMRS2_CMD, cmd);
|
||||
send_jedec_cmd(s, r, ch, EMRS3_CMD, 0);
|
||||
cmd = ddr3_emrs1_rtt_nom_config[dimmconfig][r] << 2;
|
||||
/* Hardcode output drive strength to 34 Ohm / RZQ/7 (why??) */
|
||||
cmd |= (1 << 1);
|
||||
send_jedec_cmd(s, r, ch, EMRS1_CMD, cmd);
|
||||
/* Burst type interleaved, burst length 8, Reset DLL,
|
||||
* Precharge PD: DLL on */
|
||||
send_jedec_cmd(s, r, ch, MRS_CMD, (1 << 3) | (1 << 8)
|
||||
| (1 << 12) | ((s->selected_timings.CAS - 4) << 4)
|
||||
| ((s->selected_timings.tWR - 4) << 9));
|
||||
send_jedec_cmd(s, r, ch, ZQCAL_CMD, (1 << 10));
|
||||
}
|
||||
printk(BIOS_DEBUG, "MRS done\n");
|
||||
}
|
||||
|
||||
static void sdram_recover_receive_enable(const struct sysinfo *s)
|
||||
{
|
||||
u32 reg32;
|
||||
|
@ -1949,8 +2029,12 @@ void do_raminit(struct sysinfo *s, int fast_boot)
|
|||
printk(BIOS_DEBUG, "Done pre-jedec\n");
|
||||
|
||||
// JEDEC reset
|
||||
if (s->boot_path != BOOT_PATH_RESUME)
|
||||
jedec_ddr2(s);
|
||||
if (s->boot_path != BOOT_PATH_RESUME) {
|
||||
if (s->spd_type == DDR2)
|
||||
jedec_ddr2(s);
|
||||
else /* DDR3 */
|
||||
jedec_ddr3(s);
|
||||
}
|
||||
|
||||
printk(BIOS_DEBUG, "Done jedec steps\n");
|
||||
|
||||
|
|
|
@ -269,3 +269,22 @@ const struct dll_setting default_ddr3_1333_dq[2][TOTAL_BYTELANES] = {
|
|||
{13, 6, 1, 0, 1, 0},
|
||||
{0, 3, 1, 1, 0, 1}, }
|
||||
};
|
||||
|
||||
const u8 ddr3_emrs1_rtt_nom_config[16][4] = { /* [Config][Rank] */
|
||||
{0x00, 0x00, 0x00, 0x00}, /* NC_NC */
|
||||
{0x11, 0x00, 0x00, 0x00}, /* 8S_NC */
|
||||
{0x11, 0x11, 0x00, 0x00}, /* 8D_NC */
|
||||
{0x11, 0x00, 0x00, 0x00}, /* 16S_NC */
|
||||
{0x00, 0x00, 0x11, 0x00}, /* NC_8S */
|
||||
{0x81, 0x00, 0x81, 0x00}, /* 8S_8S */
|
||||
{0x81, 0x81, 0x81, 0x00}, /* 8D_8S */
|
||||
{0x81, 0x00, 0x81, 0x00}, /* 16S_8S */
|
||||
{0x00, 0x00, 0x11, 0x11}, /* NC_8D */
|
||||
{0x81, 0x00, 0x81, 0x81}, /* 8S_8D */
|
||||
{0x81, 0x81, 0x81, 0x81}, /* 8D_8D */
|
||||
{0x81, 0x00, 0x81, 0x81}, /* 16S_8D */
|
||||
{0x00, 0x00, 0x11, 0x00}, /* NC_16S */
|
||||
{0x81, 0x00, 0x81, 0x00}, /* 8S_16S */
|
||||
{0x81, 0x81, 0x81, 0x00}, /* 8D_16S */
|
||||
{0x81, 0x00, 0x81, 0x00}, /* 16S_16S */
|
||||
};
|
||||
|
|
|
@ -309,6 +309,7 @@ struct dimminfo {
|
|||
unsigned int rows;
|
||||
unsigned int cols;
|
||||
u16 spd_crc;
|
||||
u8 mirrored;
|
||||
};
|
||||
|
||||
struct rcven_timings {
|
||||
|
@ -388,6 +389,7 @@ extern const struct dll_setting default_ddr2_800_dq[TOTAL_BYTELANES];
|
|||
extern const struct dll_setting default_ddr3_800_dq[2][TOTAL_BYTELANES];
|
||||
extern const struct dll_setting default_ddr3_1067_dq[2][TOTAL_BYTELANES];
|
||||
extern const struct dll_setting default_ddr3_1333_dq[2][TOTAL_BYTELANES];
|
||||
extern const u8 ddr3_emrs1_rtt_nom_config[16][4];
|
||||
|
||||
struct acpi_rsdp;
|
||||
#ifndef __SIMPLE_DEVICE__
|
||||
|
|
Loading…
Reference in New Issue