[coreboot-gerrit] New patch to review for coreboot: WIP: nb/intel/sandybridge: Implement dynamic PCI mmio size

Patrick Rudolph (siro@das-labor.org) gerrit at coreboot.org
Wed Jun 8 20:18:01 CEST 2016


Patrick Rudolph (siro at das-labor.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/15107

-gerrit

commit bdca6dfcf1994a77fcf84fd82c3ab74eea936aa1
Author: Patrick Rudolph <siro at das-labor.org>
Date:   Mon Jun 6 19:30:37 2016 +0200

    WIP: nb/intel/sandybridge: Implement dynamic PCI mmio size
    
    Verify that all PCI BARs fit into PCI mmio space.
    In case the space isn't sufficient or isn't used by PCI devices
    modify the mrc.cache to apply a different value on next boot.
    
    In case the PCI mmio space is to small initiate a reboot.
    
    Tested on Lenovo T520:
    The device reboots a single time to apply the new TOLUD and then
    successfully boots into GNU/Linux without the need to modify
    PCI mmio size by hand.
    
    Change-Id: Ibaafa46fd014c1a64775259cfd407c07e71350b4
    Signed-off-by: Patrick Rudolph <siro at das-labor.org>
---
 src/northbridge/intel/common/mrc_cache.c           |   2 +-
 src/northbridge/intel/common/mrc_cache.h           |   1 +
 src/northbridge/intel/sandybridge/Makefile.inc     |   1 +
 src/northbridge/intel/sandybridge/northbridge.c    |  20 +++-
 src/northbridge/intel/sandybridge/raminit.c        | 106 ++----------------
 .../intel/sandybridge/raminit_memorymap.c          |  68 ++++++++++++
 .../intel/sandybridge/raminit_memorymap.h          |  20 ++++
 .../intel/sandybridge/raminit_private.h            | 118 +++++++++++++++++++++
 8 files changed, 237 insertions(+), 99 deletions(-)

diff --git a/src/northbridge/intel/common/mrc_cache.c b/src/northbridge/intel/common/mrc_cache.c
index 4c3ee5d..a64d018 100644
--- a/src/northbridge/intel/common/mrc_cache.c
+++ b/src/northbridge/intel/common/mrc_cache.c
@@ -153,7 +153,7 @@ static struct mrc_data_container *find_next_mrc_cache
 	return mrc_cache;
 }
 
-static void update_mrc_cache(void *unused)
+void update_mrc_cache(void *unused)
 {
 	printk(BIOS_DEBUG, "Updating MRC cache data.\n");
 	struct mrc_data_container *current = cbmem_find(CBMEM_ID_MRCDATA);
diff --git a/src/northbridge/intel/common/mrc_cache.h b/src/northbridge/intel/common/mrc_cache.h
index 1fb6667..decb84c 100644
--- a/src/northbridge/intel/common/mrc_cache.h
+++ b/src/northbridge/intel/common/mrc_cache.h
@@ -14,5 +14,6 @@ struct mrc_data_container {
 
 struct mrc_data_container *find_current_mrc_cache(void);
 struct mrc_data_container *store_current_mrc_cache(void *data, unsigned length);
+void update_mrc_cache(void *unused);
 
 #endif /* NORTHBRIDGE_INTEL_COMMON_MRC_CACHE_H */
diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc
index b1bc2ac..035e55b 100644
--- a/src/northbridge/intel/sandybridge/Makefile.inc
+++ b/src/northbridge/intel/sandybridge/Makefile.inc
@@ -22,6 +22,7 @@ ramstage-$(CONFIG_SANDYBRIDGE_IVYBRIDGE_LVDS) += gma_sandybridge_lvds.c
 ramstage-$(CONFIG_SANDYBRIDGE_IVYBRIDGE_LVDS) += gma_ivybridge_lvds.c
 
 ramstage-y += acpi.c
+ramstage-y += raminit_memorymap.c
 
 romstage-y += ram_calc.c
 ifeq ($(CONFIG_USE_NATIVE_RAMINIT),y)
diff --git a/src/northbridge/intel/sandybridge/northbridge.c b/src/northbridge/intel/sandybridge/northbridge.c
index 53d93a2..1829782 100644
--- a/src/northbridge/intel/sandybridge/northbridge.c
+++ b/src/northbridge/intel/sandybridge/northbridge.c
@@ -33,6 +33,7 @@
 #include "chip.h"
 #include "sandybridge.h"
 #include <cpu/intel/smm/gen1/smi.h>
+#include "raminit_memorymap.h"
 
 static int bridge_revision_id = -1;
 
@@ -141,7 +142,7 @@ static void add_fixed_resources(struct device *dev, int index)
 static void pci_domain_set_resources(device_t dev)
 {
 	uint64_t tom, me_base, touud;
-	uint32_t tseg_base, uma_size, tolud;
+	uint32_t tseg_base, tseg_size, uma_size, tolud, tolud_used;
 	uint16_t ggc;
 	unsigned long long tomk;
 
@@ -187,6 +188,23 @@ static void pci_domain_set_resources(device_t dev)
 	printk(BIOS_DEBUG, "TOUUD 0x%llx TOLUD 0x%08x TOM 0x%llx\n",
 	       touud, tolud, tom);
 
+	/* Top of Lower Usable DRAM */
+	tolud = pci_read_config32(dev, TOLUD);
+
+	/* Make sure all dynamic resources fit into PCI mmio space */
+	tolud_used = dev_verify_resources(tolud);
+	if (tolud_used) {
+		printk(BIOS_DEBUG, "TOLUD required 0x%08x\n", tolud_used);
+
+		northbridge_get_tseg_base_and_size(&tseg_base, &tseg_size);
+
+		if (tolud_used < tolud)
+			dram_ddr3_set_tolud(tolud_used, 1);
+		/* FIXME: tseg alignment */
+		else if ((tolud_used - tseg_size) > tolud)
+			dram_ddr3_set_tolud(tolud_used, 0);
+	}
+
 	/* ME UMA needs excluding if total memory <4GB */
 	me_base = pci_read_config32(dev, 0x74);
 	me_base <<= 32;
diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c
index 6bb77b2..efd6c2d 100644
--- a/src/northbridge/intel/sandybridge/raminit.c
+++ b/src/northbridge/intel/sandybridge/raminit.c
@@ -31,6 +31,7 @@
 #include <memory_info.h>
 #include <smbios.h>
 #include "raminit_native.h"
+#include "raminit_private.h"
 #include "sandybridge.h"
 #include <delay.h>
 #include <lib.h>
@@ -94,101 +95,6 @@
 #define IS_IVY_CPU_D(x) ((x & 0xf) == 6)
 #define IS_IVY_CPU_E(x) ((x & 0xf) >= 8)
 
-#define NUM_CHANNELS 2
-#define NUM_SLOTRANKS 4
-#define NUM_SLOTS 2
-#define NUM_LANES 8
-
-/* FIXME: Vendor BIOS uses 64 but our algorithms are less
-   performant and even 1 seems to be enough in practice.  */
-#define NUM_PATTERNS 4
-
-typedef struct odtmap_st {
-	u16 rttwr;
-	u16 rttnom;
-} odtmap;
-
-typedef struct dimm_info_st {
-	dimm_attr dimm[NUM_CHANNELS][NUM_SLOTS];
-} dimm_info;
-
-struct ram_rank_timings {
-	/* Register 4024. One byte per slotrank.  */
-	u8 val_4024;
-	/* Register 4028. One nibble per slotrank.  */
-	u8 val_4028;
-
-	int val_320c;
-
-	struct ram_lane_timings {
-		/* lane register offset 0x10.  */
-		u16 timA;	/* bits 0 - 5, bits 16 - 18 */
-		u8 rising;	/* bits 8 - 14 */
-		u8 falling;	/* bits 20 - 26.  */
-
-		/* lane register offset 0x20.  */
-		int timC;	/* bit 0 - 5, 19.  */
-		u16 timB;	/* bits 8 - 13, 15 - 17.  */
-	} lanes[NUM_LANES];
-};
-
-struct ramctr_timing_st;
-
-typedef struct ramctr_timing_st {
-	u16 spd_crc[NUM_CHANNELS][NUM_SLOTS];
-	int mobile;
-
-	u16 cas_supported;
-	/* tLatencies are in units of ns, scaled by x256 */
-	u32 tCK;
-	u32 tAA;
-	u32 tWR;
-	u32 tRCD;
-	u32 tRRD;
-	u32 tRP;
-	u32 tRAS;
-	u32 tRFC;
-	u32 tWTR;
-	u32 tRTP;
-	u32 tFAW;
-	/* Latencies in terms of clock cycles
-	 * They are saved separately as they are needed for DRAM MRS commands*/
-	u8 CAS;			/* CAS read latency */
-	u8 CWL;			/* CAS write latency */
-
-	u32 tREFI;
-	u32 tMOD;
-	u32 tXSOffset;
-	u32 tWLO;
-	u32 tCKE;
-	u32 tXPDLL;
-	u32 tXP;
-	u32 tAONPD;
-
-	u16 reg_5064b0; /* bits 0-11. */
-
-	u8 rankmap[NUM_CHANNELS];
-	int ref_card_offset[NUM_CHANNELS];
-	u32 mad_dimm[NUM_CHANNELS];
-	int channel_size_mb[NUM_CHANNELS];
-	u32 cmd_stretch[NUM_CHANNELS];
-
-	int reg_c14_offset;
-	int reg_320c_range_threshold;
-
-	int edge_offset[3];
-	int timC_offset[3];
-
-	int extended_temperature_range;
-	int auto_self_refresh;
-
-	int rank_mirror[NUM_CHANNELS][NUM_SLOTRANKS];
-
-	struct ram_rank_timings timings[NUM_CHANNELS][NUM_SLOTRANKS];
-
-	dimm_info info;
-} ramctr_timing;
-
 #define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
 #define NORTHBRIDGE PCI_DEV(0, 0x0, 0)
 #define FOR_ALL_LANES for (lane = 0; lane < NUM_LANES; lane++)
@@ -1103,8 +1009,14 @@ static void dram_memorymap(ramctr_timing * ctrl, int me_uma_size)
 
 	mestolenbase = tom - me_uma_size;
 
-	toludbase = MIN(4096 - mmiosize + gfxstolen + gttsize + tsegsize,
-			tom - me_uma_size);
+	if (ctrl->pci_tolud_base) {
+		printk(BIOS_DEBUG, "Using mrc.cache TOLUD 0x%08x\n", ctrl->pci_tolud_base << 20);
+
+		toludbase = MIN(ctrl->pci_tolud_base, tom - me_uma_size);
+	}
+	else
+		toludbase = MIN(4096 - mmiosize + gfxstolen + gttsize + tsegsize,
+				tom - me_uma_size);
 	gfxstolenbase = toludbase - gfxstolen;
 	gttbase = gfxstolenbase - gttsize;
 
diff --git a/src/northbridge/intel/sandybridge/raminit_memorymap.c b/src/northbridge/intel/sandybridge/raminit_memorymap.c
new file mode 100644
index 0000000..7c0bf67
--- /dev/null
+++ b/src/northbridge/intel/sandybridge/raminit_memorymap.c
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2016 Patrick Rudolph <siro at das-labor.org>
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 <halt.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <northbridge/intel/common/mrc_cache.h>
+#include <cbmem.h>
+#include <console/console.h>
+#include "raminit_private.h"
+#include "raminit_memorymap.h"
+
+/* Store TOLUD base in mrc cache to allow dynamic PCI size changes.
+ * The caller might request a reboot to apply changes immediately.
+ */
+void dram_ddr3_set_tolud(u32 base, u8 reboot_now)
+{
+	struct mrc_data_container *mrc_cache;
+	ramctr_timing *ctrl_cached;
+
+	if (!IS_ENABLED(CONFIG_USE_NATIVE_RAMINIT))
+		return;
+
+	/* try to find timings in MRC cache */
+	mrc_cache = cbmem_find(CBMEM_ID_MRCDATA);
+	if (!mrc_cache || (mrc_cache->mrc_data_size < sizeof(ramctr_timing))) {
+		printk(BIOS_ERR, "mrc.cache not found in CBMEM\n");
+		return;
+	}
+
+	ctrl_cached = (ramctr_timing *)mrc_cache->mrc_data;
+
+	/* pci_tolud_base is in MiB */
+	ctrl_cached->pci_tolud_base = base >> 20;
+
+	printk(BIOS_INFO, "Writing new TOLUD 0x%08x to mrc.cache\n", base);
+
+	/* update CRC */
+	if (!store_current_mrc_cache(ctrl_cached, sizeof(ramctr_timing))) {
+		printk(BIOS_ERR, "failed to store mrc.cache\n");
+		return;
+	}
+
+	if (reboot_now) {
+		printk(BIOS_INFO, "Reboot now to apply new TOLUD !\n");
+
+		/* write mrc cache to flash */
+		update_mrc_cache(NULL);
+
+		/* Reset to come up cleanly */
+		outb(0x6, 0xcf9);
+		halt();
+	}
+}
+
diff --git a/src/northbridge/intel/sandybridge/raminit_memorymap.h b/src/northbridge/intel/sandybridge/raminit_memorymap.h
new file mode 100644
index 0000000..babbc45
--- /dev/null
+++ b/src/northbridge/intel/sandybridge/raminit_memorymap.h
@@ -0,0 +1,20 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2016 Patrick Rudolph <siro at das-labor.org>
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.
+ */
+
+#ifndef SANDYBRIDGE_RAMINIT_MEMORYMAP_H
+#define SANDYBRIDGE_RAMINIT_MEMORYMAP_H
+void dram_ddr3_set_tolud(u32 base, u8 reboot_now);
+
+#endif
diff --git a/src/northbridge/intel/sandybridge/raminit_private.h b/src/northbridge/intel/sandybridge/raminit_private.h
new file mode 100644
index 0000000..5168e48
--- /dev/null
+++ b/src/northbridge/intel/sandybridge/raminit_private.h
@@ -0,0 +1,118 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2016 Patrick Rudolph <siro at das-labor.org>
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.
+ */
+
+#ifndef SANDYBRIDGE_RAMINIT_PRIVATE_H
+#define SANDYBRIDGE_RAMINIT_PRIVATE_H
+
+#include <device/dram/ddr3.h>
+
+#define NUM_CHANNELS 2
+#define NUM_SLOTRANKS 4
+#define NUM_SLOTS 2
+#define NUM_LANES 8
+
+/* FIXME: Vendor BIOS uses 64 but our algorithms are less
+   performant and even 1 seems to be enough in practice.  */
+#define NUM_PATTERNS 4
+
+typedef struct odtmap_st {
+	u16 rttwr;
+	u16 rttnom;
+} odtmap;
+
+typedef struct dimm_info_st {
+	dimm_attr dimm[NUM_CHANNELS][NUM_SLOTS];
+} dimm_info;
+
+struct ram_rank_timings {
+	/* Register 4024. One byte per slotrank.  */
+	u8 val_4024;
+	/* Register 4028. One nibble per slotrank.  */
+	u8 val_4028;
+
+	int val_320c;
+
+	struct ram_lane_timings {
+		/* lane register offset 0x10.  */
+		u16 timA;	/* bits 0 - 5, bits 16 - 18 */
+		u8 rising;	/* bits 8 - 14 */
+		u8 falling;	/* bits 20 - 26.  */
+
+		/* lane register offset 0x20.  */
+		int timC;	/* bit 0 - 5, 19.  */
+		u16 timB;	/* bits 8 - 13, 15 - 17.  */
+	} lanes[NUM_LANES];
+};
+
+struct ramctr_timing_st;
+
+typedef struct ramctr_timing_st {
+	u16 spd_crc[NUM_CHANNELS][NUM_SLOTS];
+	int mobile;
+
+	u16 cas_supported;
+	/* tLatencies are in units of ns, scaled by x256 */
+	u32 tCK;
+	u32 tAA;
+	u32 tWR;
+	u32 tRCD;
+	u32 tRRD;
+	u32 tRP;
+	u32 tRAS;
+	u32 tRFC;
+	u32 tWTR;
+	u32 tRTP;
+	u32 tFAW;
+	/* Latencies in terms of clock cycles
+	 * They are saved separately as they are needed for DRAM MRS commands*/
+	u8 CAS;			/* CAS read latency */
+	u8 CWL;			/* CAS write latency */
+
+	u32 tREFI;
+	u32 tMOD;
+	u32 tXSOffset;
+	u32 tWLO;
+	u32 tCKE;
+	u32 tXPDLL;
+	u32 tXP;
+	u32 tAONPD;
+
+	u16 reg_5064b0; /* bits 0-11. */
+
+	u8 rankmap[NUM_CHANNELS];
+	int ref_card_offset[NUM_CHANNELS];
+	u32 mad_dimm[NUM_CHANNELS];
+	int channel_size_mb[NUM_CHANNELS];
+	u32 cmd_stretch[NUM_CHANNELS];
+
+	int reg_c14_offset;
+	int reg_320c_range_threshold;
+
+	int edge_offset[3];
+	int timC_offset[3];
+
+	int extended_temperature_range;
+	int auto_self_refresh;
+
+	int rank_mirror[NUM_CHANNELS][NUM_SLOTRANKS];
+
+	struct ram_rank_timings timings[NUM_CHANNELS][NUM_SLOTRANKS];
+
+	dimm_info info;
+
+	u32 pci_tolud_base;
+} ramctr_timing;
+
+#endif /* SANDYBRIDGE_RAMINIT_PRIVATE_H */



More information about the coreboot-gerrit mailing list