[coreboot-gerrit] Change in coreboot[master]: nb/x4x/raminit: Decode ddr3 dimms
Arthur Heymans (Code Review)
gerrit at coreboot.org
Wed May 24 22:10:32 CEST 2017
Arthur Heymans has uploaded a new change for review. ( https://review.coreboot.org/19869 )
Change subject: nb/x4x/raminit: Decode ddr3 dimms
......................................................................
nb/x4x/raminit: Decode ddr3 dimms
The raw_spd array needs to be increased since the ddr3 variant of
spd_decode assumes an array of that size.
Change-Id: I8dba19ca1e6e6b0a03b56c8de9633f9c1a2eb7d7
Signed-off-by: Arthur Heymans <arthur at aheymans.xyz>
---
M src/northbridge/intel/x4x/Makefile.inc
M src/northbridge/intel/x4x/raminit.c
M src/northbridge/intel/x4x/raminit_ddr2.c
M src/northbridge/intel/x4x/spd_ddr2_decode.c
A src/northbridge/intel/x4x/spd_ddr3_decode.c
M src/northbridge/intel/x4x/x4x.h
6 files changed, 197 insertions(+), 8 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/69/19869/1
diff --git a/src/northbridge/intel/x4x/Makefile.inc b/src/northbridge/intel/x4x/Makefile.inc
index b433810..86ecf7b 100644
--- a/src/northbridge/intel/x4x/Makefile.inc
+++ b/src/northbridge/intel/x4x/Makefile.inc
@@ -21,6 +21,7 @@
romstage-y += raminit_ddr2.c
romstage-y += ram_calc.c
romstage-y += spd_ddr2_decode.c
+romstage-y += spd_ddr3_decode.c
ramstage-y += acpi.c
ramstage-y += ram_calc.c
diff --git a/src/northbridge/intel/x4x/raminit.c b/src/northbridge/intel/x4x/raminit.c
index 7e69b4c..b2bc280 100644
--- a/src/northbridge/intel/x4x/raminit.c
+++ b/src/northbridge/intel/x4x/raminit.c
@@ -116,7 +116,7 @@
unsigned int device;
u8 dram_type_mask = (1 << DDR2) | (1 << DDR3);
u8 dimm_mask = 0;
- u8 raw_spd[128];
+ u8 raw_spd[256];
int i;
struct abs_timings saved_timings = { };
saved_timings.cas_supported = (u32)-1;
@@ -151,7 +151,12 @@
continue;
}
} else { /* DDR3: not implemented so don't decode */
- die("DDR3 support is not implemented\n");
+ i2c_block_read(device, 0, 128, raw_spd);
+ if (ddr3_save_dimminfo(i, raw_spd, &saved_timings, s)) {
+ /* something in decoded SPD was unsupported */
+ s->dimms[i].card_type = RAW_CARD_UNPOPULATED;
+ continue;
+ }
}
dimm_mask = (1 << i);
}
@@ -159,6 +164,8 @@
die("No memory installed.\n");
if (s->spd_type == DDR2)
select_cas_dramfreq_ddr2(s, &saved_timings);
+ else
+ select_cas_dramfreq_ddr3(s, &saved_timings);
select_discrete_timings(s, &saved_timings);
}
diff --git a/src/northbridge/intel/x4x/raminit_ddr2.c b/src/northbridge/intel/x4x/raminit_ddr2.c
index 8984fad..e663564 100644
--- a/src/northbridge/intel/x4x/raminit_ddr2.c
+++ b/src/northbridge/intel/x4x/raminit_ddr2.c
@@ -1469,7 +1469,6 @@
};
u8 drbtab[10] = {0x04, 0x02, 0x08, 0x04, 0x08, 0x04, 0x10, 0x08, 0x20, 0x10};
- u8 tab_width;
// DRA
rankpop0 = 0;
@@ -1480,9 +1479,8 @@
i = ch << 1;
else
i = (ch << 1) + 1;
- tab_width = (s->dimms[i].width >> 3) - 1; /* 16->1, 8->0 */
dra = dratab[s->dimms[i].n_banks]
- [tab_width]
+ [s->dimms[i].width]
[s->dimms[i].cols-9]
[s->dimms[i].rows-12];
if (s->dimms[i].n_banks == 1)
diff --git a/src/northbridge/intel/x4x/spd_ddr2_decode.c b/src/northbridge/intel/x4x/spd_ddr2_decode.c
index 938aab7..f8f4403 100644
--- a/src/northbridge/intel/x4x/spd_ddr2_decode.c
+++ b/src/northbridge/intel/x4x/spd_ddr2_decode.c
@@ -82,12 +82,14 @@
* Used to be content of spd byte 62 which does not make
* that much sense.
*/
- s->dimms[dimm_idx].width = decoded_dimm.width;
- if (!(s->dimms[dimm_idx].width & (0x8 | 0x10))) {
+
+ if (!(decoded_dimm.width & (0x8 | 0x10))) {
printk(BIOS_ERR, "DIMM%d Unsupported width: x%d. Disabling dimm\n",
dimm_idx, s->dimms[dimm_idx].width);
return 1;
}
+
+ s->dimms[dimm_idx].width = (decoded_dimm.width >> 3) - 1;
/*
* This boils down to:
* "Except for the x16 configuration, all DDR2 devices have a
@@ -96,7 +98,7 @@
* page size."
* Micron, 'TN-47-16 Designing for High-Density DDR2 Memory'
*/
- s->dimms[dimm_idx].page_size = s->dimms[dimm_idx].width *
+ s->dimms[dimm_idx].page_size = decoded_dimm.width *
(1 << decoded_dimm.col_bits);
switch (decoded_dimm.banks) {
diff --git a/src/northbridge/intel/x4x/spd_ddr3_decode.c b/src/northbridge/intel/x4x/spd_ddr3_decode.c
new file mode 100644
index 0000000..fd69fd4
--- /dev/null
+++ b/src/northbridge/intel/x4x/spd_ddr3_decode.c
@@ -0,0 +1,175 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2015 Damien Zammit <damien at zamaudio.com>
+ * Copyright (C) 2017 Arthur Heymans <arthur at aheymans.xyz>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <arch/io.h>
+#include <console/console.h>
+#include <device/dram/ddr3.h>
+#include "x4x.h"
+
+static void normalize_tCLK(u32 *tCLK)
+{
+ if (*tCLK <= TCK_666MHZ)
+ *tCLK = TCK_666MHZ;
+ else if (*tCLK <= TCK_533MHZ)
+ *tCLK = TCK_533MHZ;
+ else if (*tCLK <= TCK_400MHZ)
+ *tCLK = TCK_400MHZ;
+ else
+ *tCLK = 0;
+}
+
+static void increase_tCLK(u32 *tCLK)
+{
+ ++*tCLK;
+ normalize_tCLK(tCLK);
+}
+
+void select_cas_dramfreq_ddr3(struct sysinfo *s,
+ struct abs_timings *saved_timings)
+{
+ /* various constraints must be fulfilled:
+ CAS * tCK < 20ns == 160MTB
+ tCK_max >= tCK >= tCK_min
+ CAS >= roundup(tAA_min/tCK)
+ CAS supported
+ AND BTW: Clock(MT) = 2000 / tCK(ns) - intel uses MTs but calls them MHz
+ */
+
+ u32 min_tCLK;
+ u8 try_CAS;
+ u16 capid = (pci_read_config16(PCI_DEV(0, 0, 0), 0xea) >> 4) & 0x3f;
+
+ switch (s->max_fsb) {
+ default:
+ case FSB_CLOCK_800MHz:
+ min_tCLK = TCK_400MHZ;
+ break;
+ case FSB_CLOCK_1066MHz:
+ min_tCLK = TCK_533MHZ;
+ break;
+ case FSB_CLOCK_1333MHz:
+ min_tCLK = TCK_666MHZ;
+ break;
+ }
+
+ switch (capid >> 3) {
+ default: /* Should not happen */
+ min_tCLK = TCK_400MHZ;
+ break;
+ case 1:
+ min_tCLK = MAX(min_tCLK, TCK_400MHZ);
+ break;
+ case 2:
+ min_tCLK = MAX(min_tCLK, TCK_533MHZ);
+ break;
+ case 3: /* Only on P45 */
+ min_tCLK = MAX(min_tCLK, TCK_666MHZ);
+ break;
+ }
+
+ min_tCLK = MAX(min_tCLK, saved_timings->min_tclk);
+ normalize_tCLK(&min_tCLK);
+ if (min_tCLK == 0) {
+ printk(BIOS_ERR, "DRAM frequency is under lowest supported "
+ "frequency (400 MHz). Increasing to 400 MHz as last resort");
+ min_tCLK = TCK_400MHZ;
+ }
+
+ while (1) {
+ if (min_tCLK == 0)
+ die("Couldn't find compatible clock / CAS settings.\n");
+ try_CAS = DIV_ROUND_UP(saved_timings->min_tAA, min_tCLK);
+ printk(BIOS_SPEW, "Trying CAS %u, tCK %u.\n", try_CAS, min_tCLK);
+ for (; try_CAS <= DDR3_MAX_CAS; ++try_CAS) {
+ if ((saved_timings->cas_supported << 4) & (1 << try_CAS))
+ break;
+ }
+ if ((try_CAS <= DDR3_MAX_CAS) && (try_CAS * min_tCLK < 20 * 256)) {
+ /* Found good CAS. */
+ printk(BIOS_SPEW, "Found compatible tCLK / CAS pair: %u / %u.\n",
+ min_tCLK, try_CAS);
+ break;
+ }
+ increase_tCLK(&min_tCLK);
+ }
+ s->selected_timings.tclk = min_tCLK;
+ s->selected_timings.CAS = try_CAS;
+
+ switch (s->selected_timings.tclk) {
+ case TCK_400MHZ:
+ s->selected_timings.mem_clk = MEM_CLOCK_800MHz; break;
+ case TCK_533MHZ:
+ s->selected_timings.mem_clk = MEM_CLOCK_1066MHz; break;
+ case TCK_666MHZ:
+ s->selected_timings.mem_clk = MEM_CLOCK_1333MHz; break;
+ }
+}
+
+int ddr3_save_dimminfo(u8 dimm_idx, u8 *raw_spd,
+ struct abs_timings *saved_timings, struct sysinfo *s)
+{
+ struct dimm_attr_st decoded_dimm;
+
+ if (spd_decode_ddr3(&decoded_dimm, raw_spd) != SPD_STATUS_OK)
+ return 1;
+
+ if (IS_ENABLED(CONFIG_DEBUG_RAM_SETUP))
+ dram_print_spd_ddr3(&decoded_dimm);
+
+ if (!(decoded_dimm.width & (0x8 | 0x10))) {
+ printk(BIOS_ERR, "DIMM%d Unsupported width: x%d. Disabling dimm\n",
+ dimm_idx, s->dimms[dimm_idx].width);
+ return 1;
+ }
+ s->dimms[dimm_idx].width = (decoded_dimm.width >> 3) - 1;
+ /*
+ * This boils down to:
+ * "Except for the x16 configuration, all DDR2 devices have a
+ * 1KB page size. For the x16 configuration, the page size is 2KB
+ * for all densities except the 256Mb device, which has a 1KB page size."
+ * Micron, 'TN-47-16 Designing for High-Density DDR2 Memory'
+ */
+ s->dimms[dimm_idx].page_size = s->dimms[dimm_idx].width *
+ (1 << decoded_dimm.col_bits);
+
+ s->dimms[dimm_idx].n_banks = 1; /* Always 8 banks on ddr3?? */
+
+ s->dimms[dimm_idx].ranks = decoded_dimm.ranks;
+ s->dimms[dimm_idx].rows = decoded_dimm.row_bits;
+ s->dimms[dimm_idx].cols = decoded_dimm.col_bits;
+
+ saved_timings->min_tRAS =
+ MAX(saved_timings->min_tRAS, decoded_dimm.tRAS);
+ saved_timings->min_tRP =
+ MAX(saved_timings->min_tRP, decoded_dimm.tRP);
+ saved_timings->min_tRCD =
+ MAX(saved_timings->min_tRCD, decoded_dimm.tRCD);
+ saved_timings->min_tWR =
+ MAX(saved_timings->min_tWR, decoded_dimm.tWR);
+ saved_timings->min_tRFC =
+ MAX(saved_timings->min_tRFC, decoded_dimm.tRFC);
+ saved_timings->min_tWTR =
+ MAX(saved_timings->min_tWTR, decoded_dimm.tWTR);
+ saved_timings->min_tRRD =
+ MAX(saved_timings->min_tRRD, decoded_dimm.tRRD);
+ saved_timings->min_tRTP =
+ MAX(saved_timings->min_tRTP, decoded_dimm.tRTP);
+ saved_timings->min_tAA =
+ MAX(saved_timings->min_tAA, decoded_dimm.tAA);
+ saved_timings->cas_supported &= decoded_dimm.cas_supported;
+ return 0;
+}
diff --git a/src/northbridge/intel/x4x/x4x.h b/src/northbridge/intel/x4x/x4x.h
index fc7fbfe..43e37ef 100644
--- a/src/northbridge/intel/x4x/x4x.h
+++ b/src/northbridge/intel/x4x/x4x.h
@@ -323,6 +323,7 @@
struct abs_timings {
u32 min_tclk;
+ u32 min_tAA;
u32 min_tRAS;
u32 min_tRP;
u32 min_tRCD;
@@ -349,6 +350,11 @@
struct abs_timings *saved_timings);
int ddr2_save_dimminfo(u8 dimm_idx, u8 *raw_spd,
struct abs_timings *saved_timings, struct sysinfo *s);
+void select_cas_dramfreq_ddr3(struct sysinfo *s,
+ struct abs_timings *saved_timings);
+int ddr3_save_dimminfo(u8 dimm_idx, u8 *raw_spd,
+ struct abs_timings *saved_timings, struct sysinfo *s);
+
struct acpi_rsdp;
#ifndef __SIMPLE_DEVICE__
--
To view, visit https://review.coreboot.org/19869
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8dba19ca1e6e6b0a03b56c8de9633f9c1a2eb7d7
Gerrit-PatchSet: 1
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Owner: Arthur Heymans <arthur at aheymans.xyz>
More information about the coreboot-gerrit
mailing list