aboutsummaryrefslogtreecommitdiff
path: root/src/northbridge/intel/haswell
diff options
context:
space:
mode:
Diffstat (limited to 'src/northbridge/intel/haswell')
-rw-r--r--src/northbridge/intel/haswell/hostbridge_regs.h4
-rw-r--r--src/northbridge/intel/haswell/raminit.c48
2 files changed, 52 insertions, 0 deletions
diff --git a/src/northbridge/intel/haswell/hostbridge_regs.h b/src/northbridge/intel/haswell/hostbridge_regs.h
index f5fa54aef7..70e15b74e2 100644
--- a/src/northbridge/intel/haswell/hostbridge_regs.h
+++ b/src/northbridge/intel/haswell/hostbridge_regs.h
@@ -60,7 +60,11 @@
#define SKPAD 0xdc /* Scratchpad Data */
#define CAPID0_A 0xe4
+#define CAPID_ECCDIS (1 << 25)
#define VTD_DISABLE (1 << 23)
+#define CAPID_DDPCD (1 << 14)
+#define CAPID_PDCD (1 << 12)
+#define CAPID_DDRSZ(x) (((x) >> 19) & 0x3)
#define CAPID0_B 0xe8
diff --git a/src/northbridge/intel/haswell/raminit.c b/src/northbridge/intel/haswell/raminit.c
index 5d67954125..0b5969249a 100644
--- a/src/northbridge/intel/haswell/raminit.c
+++ b/src/northbridge/intel/haswell/raminit.c
@@ -10,6 +10,7 @@
#include <memory_info.h>
#include <mrc_cache.h>
#include <device/pci_def.h>
+#include <device/pci_ops.h>
#include <device/dram/ddr3.h>
#include <smbios.h>
#include <spd.h>
@@ -170,6 +171,45 @@ void sdram_initialize(struct pei_data *pei_data)
report_memory_config();
}
+static bool nb_supports_ecc(const uint32_t capid0_a)
+{
+ return !(capid0_a & CAPID_ECCDIS);
+}
+
+static uint16_t nb_slots_per_channel(const uint32_t capid0_a)
+{
+ return !(capid0_a & CAPID_DDPCD) + 1;
+}
+
+static uint16_t nb_number_of_channels(const uint32_t capid0_a)
+{
+ return !(capid0_a & CAPID_PDCD) + 1;
+}
+
+static uint32_t nb_max_chan_capacity_mib(const uint32_t capid0_a)
+{
+ uint32_t ddrsz;
+
+ /* Values from documentation, which assume two DIMMs per channel */
+ switch (CAPID_DDRSZ(capid0_a)) {
+ case 1:
+ ddrsz = 8192;
+ break;
+ case 2:
+ ddrsz = 2048;
+ break;
+ case 3:
+ ddrsz = 512;
+ break;
+ default:
+ ddrsz = 16384;
+ break;
+ }
+
+ /* Account for the maximum number of DIMMs per channel */
+ return (ddrsz / 2) * nb_slots_per_channel(capid0_a);
+}
+
void setup_sdram_meminfo(struct pei_data *pei_data)
{
u32 addr_decode_ch[2];
@@ -221,4 +261,12 @@ void setup_sdram_meminfo(struct pei_data *pei_data)
}
}
mem_info->dimm_cnt = dimm_cnt;
+
+ const uint32_t capid0_a = pci_read_config32(HOST_BRIDGE, CAPID0_A);
+
+ const uint16_t channels = nb_number_of_channels(capid0_a);
+
+ mem_info->ecc_capable = nb_supports_ecc(capid0_a);
+ mem_info->max_capacity_mib = channels * nb_max_chan_capacity_mib(capid0_a);
+ mem_info->number_of_devices = channels * nb_slots_per_channel(capid0_a);
}