x86: Update mrccache to support multiple caches
With Apollo Lake we need to support a normal cache, which almost never
changes and a much smaller 'variable' cache which changes every time.
Update the code to add a cache type, use an array for the caches and use a
for loop to iterate over the caches.
Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
diff --git a/arch/x86/cpu/broadwell/sdram.c b/arch/x86/cpu/broadwell/sdram.c
index dfd8afc..15bfc58 100644
--- a/arch/x86/cpu/broadwell/sdram.c
+++ b/arch/x86/cpu/broadwell/sdram.c
@@ -83,7 +83,7 @@
struct mrc_region entry;
int ret;
- ret = mrccache_get_region(NULL, &entry);
+ ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry);
if (ret)
return ret;
mrc_cache = mrccache_find_current(&entry);
@@ -169,12 +169,14 @@
pei_data->data_to_save);
/* S3 resume: don't save scrambler seed or MRC data */
if (pei_data->boot_mode != SLEEP_STATE_S3) {
+ struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
+
/*
* This will be copied to SDRAM in reserve_arch(), then written
* to SPI flash in mrccache_save()
*/
- gd->arch.mrc_output = (char *)pei_data->data_to_save;
- gd->arch.mrc_output_len = pei_data->data_to_save_size;
+ mrc->buf = (char *)pei_data->data_to_save;
+ mrc->len = pei_data->data_to_save_size;
}
gd->arch.pei_meminfo = pei_data->meminfo;
diff --git a/arch/x86/cpu/ivybridge/sdram.c b/arch/x86/cpu/ivybridge/sdram.c
index 51ca4ad..cf34f94 100644
--- a/arch/x86/cpu/ivybridge/sdram.c
+++ b/arch/x86/cpu/ivybridge/sdram.c
@@ -116,7 +116,7 @@
ret = read_seed_from_cmos(pei_data);
if (ret)
return ret;
- ret = mrccache_get_region(NULL, &entry);
+ ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry);
if (ret)
return ret;
mrc_cache = mrccache_find_current(&entry);
@@ -538,12 +538,14 @@
/* S3 resume: don't save scrambler seed or MRC data */
if (pei_data->boot_mode != PEI_BOOT_RESUME) {
+ struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
+
/*
* This will be copied to SDRAM in reserve_arch(), then written
* to SPI flash in mrccache_save()
*/
- gd->arch.mrc_output = (char *)pei_data->mrc_output;
- gd->arch.mrc_output_len = pei_data->mrc_output_len;
+ mrc->buf = (char *)pei_data->mrc_output;
+ mrc->len = pei_data->mrc_output_len;
ret = write_seeds_to_cmos(pei_data);
if (ret)
debug("Failed to write seeds to CMOS: %d\n", ret);
diff --git a/arch/x86/cpu/quark/dram.c b/arch/x86/cpu/quark/dram.c
index 995e119..2bf90dc 100644
--- a/arch/x86/cpu/quark/dram.c
+++ b/arch/x86/cpu/quark/dram.c
@@ -24,7 +24,7 @@
struct mrc_region entry;
int ret;
- ret = mrccache_get_region(NULL, &entry);
+ ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry);
if (ret)
return ret;
@@ -154,9 +154,11 @@
#ifdef CONFIG_ENABLE_MRC_CACHE
cache = malloc(sizeof(struct mrc_timings));
if (cache) {
+ struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
+
memcpy(cache, &mrc_params.timings, sizeof(struct mrc_timings));
- gd->arch.mrc_output = cache;
- gd->arch.mrc_output_len = sizeof(struct mrc_timings);
+ mrc->buf = cache;
+ mrc->len = sizeof(struct mrc_timings);
}
#endif
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h
index 3212b00..190b604 100644
--- a/arch/x86/include/asm/global_data.h
+++ b/arch/x86/include/asm/global_data.h
@@ -67,6 +67,21 @@
uint64_t size;
};
+/**
+ * struct mrc_output - holds the MRC data
+ *
+ * @buf: MRC training data to save for the next boot. This is set to point to
+ * the raw data after SDRAM init is complete. Then mrccache_setup()
+ * turns it into a proper cache record with a checksum
+ * @len: Length of @buf
+ * @cache: Resulting cache record
+ */
+struct mrc_output {
+ char *buf;
+ uint len;
+ struct mrc_data_container *cache;
+};
+
/* Architecture-specific global data */
struct arch_global_data {
u64 gdt[X86_GDT_NUM_ENTRIES] __aligned(16);
@@ -91,10 +106,8 @@
struct mtrr_request mtrr_req[MAX_MTRR_REQUESTS];
int mtrr_req_count;
int has_mtrr;
- /* MRC training data to save for the next boot */
- char *mrc_output;
- unsigned int mrc_output_len;
- struct mrc_data_container *mrc_cache;
+ /* MRC training data */
+ struct mrc_output mrc[MRC_TYPE_COUNT];
ulong table; /* Table pointer from previous loader */
int turbo_state; /* Current turbo state */
struct irq_routing_table *pirq_routing_table;
diff --git a/arch/x86/include/asm/mrccache.h b/arch/x86/include/asm/mrccache.h
index abf5818..b81e2b2 100644
--- a/arch/x86/include/asm/mrccache.h
+++ b/arch/x86/include/asm/mrccache.h
@@ -27,6 +27,13 @@
u32 length;
};
+/* Types of MRC data */
+enum mrc_type_t {
+ MRC_TYPE_NORMAL,
+
+ MRC_TYPE_COUNT,
+};
+
struct udevice;
/**
@@ -84,6 +91,7 @@
* triggers PCI bus enumeration during which insufficient memory issue
* might be exposed and it causes subsequent SPI flash probe fails).
*
+ * @type: Type of MRC data to use
* @devp: Returns pointer to the SPI flash device
* @entry: Position and size of MRC cache in SPI flash
* @return 0 if success, -ENOENT if SPI flash node does not exist in the
@@ -91,7 +99,8 @@
* tree, -EINVAL if MRC region properties format is incorrect, other error
* if SPI flash probe failed.
*/
-int mrccache_get_region(struct udevice **devp, struct mrc_region *entry);
+int mrccache_get_region(enum mrc_type_t type, struct udevice **devp,
+ struct mrc_region *entry);
/**
* mrccache_save() - save MRC data to the SPI flash
diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c
index a5efe35..4c5358e 100644
--- a/arch/x86/lib/fsp/fsp_common.c
+++ b/arch/x86/lib/fsp/fsp_common.c
@@ -64,7 +64,7 @@
struct mrc_region entry;
int ret;
- ret = mrccache_get_region(NULL, &entry);
+ ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry);
if (ret)
return NULL;
diff --git a/arch/x86/lib/fsp1/fsp_dram.c b/arch/x86/lib/fsp1/fsp_dram.c
index 6a3349b..5ef8974 100644
--- a/arch/x86/lib/fsp1/fsp_dram.c
+++ b/arch/x86/lib/fsp1/fsp_dram.c
@@ -15,9 +15,11 @@
if (ret)
return ret;
- if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE))
- gd->arch.mrc_output = fsp_get_nvs_data(gd->arch.hob_list,
- &gd->arch.mrc_output_len);
+ if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) {
+ struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
+
+ mrc->buf = fsp_get_nvs_data(gd->arch.hob_list, &mrc->len);
+ }
return 0;
}
diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c
index 712bacd..1278737 100644
--- a/arch/x86/lib/mrccache.c
+++ b/arch/x86/lib/mrccache.c
@@ -174,38 +174,45 @@
return 0;
}
-static void mrccache_setup(void *data)
+static void mrccache_setup(struct mrc_output *mrc, void *data)
{
struct mrc_data_container *cache = data;
u16 checksum;
cache->signature = MRC_DATA_SIGNATURE;
- cache->data_size = gd->arch.mrc_output_len;
- checksum = compute_ip_checksum(gd->arch.mrc_output, cache->data_size);
+ cache->data_size = mrc->len;
+ checksum = compute_ip_checksum(mrc->buf, cache->data_size);
debug("Saving %d bytes for MRC output data, checksum %04x\n",
cache->data_size, checksum);
cache->checksum = checksum;
cache->reserved = 0;
- memcpy(cache->data, gd->arch.mrc_output, cache->data_size);
+ memcpy(cache->data, mrc->buf, cache->data_size);
- gd->arch.mrc_cache = cache;
+ mrc->cache = cache;
}
int mrccache_reserve(void)
{
- if (!gd->arch.mrc_output_len)
- return 0;
+ int i;
- /* adjust stack pointer to store pure cache data plus the header */
- gd->start_addr_sp -= (gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE);
- mrccache_setup((void *)gd->start_addr_sp);
+ for (i = 0; i < MRC_TYPE_COUNT; i++) {
+ struct mrc_output *mrc = &gd->arch.mrc[i];
- gd->start_addr_sp &= ~0xf;
+ if (!mrc->len)
+ continue;
+
+ /* adjust stack pointer to store pure cache data plus header */
+ gd->start_addr_sp -= (mrc->len + MRC_DATA_HEADER_SIZE);
+ mrccache_setup(mrc, (void *)gd->start_addr_sp);
+
+ gd->start_addr_sp &= ~0xf;
+ }
return 0;
}
-int mrccache_get_region(struct udevice **devp, struct mrc_region *entry)
+int mrccache_get_region(enum mrc_type_t type, struct udevice **devp,
+ struct mrc_region *entry)
{
struct udevice *dev;
ofnode mrc_node;
@@ -246,31 +253,33 @@
if (devp)
*devp = dev;
- debug("MRC cache in '%s', offset %x, len %x, base %x\n",
- dev->name, entry->offset, entry->length, entry->base);
+ debug("MRC cache type %d in '%s', offset %x, len %x, base %x\n",
+ type, dev->name, entry->offset, entry->length, entry->base);
return 0;
}
-int mrccache_save(void)
+static int mrccache_save_type(enum mrc_type_t type)
{
struct mrc_data_container *cache;
+ struct mrc_output *mrc;
struct mrc_region entry;
struct udevice *sf;
int ret;
- if (!gd->arch.mrc_output_len)
+ mrc = &gd->arch.mrc[type];
+ if (!mrc->len)
return 0;
- debug("Saving %#x bytes of MRC output data to SPI flash\n",
- gd->arch.mrc_output_len);
-
- ret = mrccache_get_region(&sf, &entry);
+ log_debug("Saving %#x bytes of MRC output data type %d to SPI flash\n",
+ mrc->len, type);
+ ret = mrccache_get_region(type, &sf, &entry);
if (ret)
return log_msg_ret("Cannot get region", ret);
ret = device_probe(sf);
if (ret)
return log_msg_ret("Cannot probe device", ret);
- cache = gd->arch.mrc_cache;
+ cache = mrc->cache;
+
ret = mrccache_update(sf, &entry, cache);
if (!ret)
debug("Saved MRC data with checksum %04x\n", cache->checksum);
@@ -280,17 +289,36 @@
return 0;
}
+int mrccache_save(void)
+{
+ int i;
+
+ for (i = 0; i < MRC_TYPE_COUNT; i++) {
+ int ret;
+
+ ret = mrccache_save_type(i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
int mrccache_spl_save(void)
{
- void *data;
- int size;
+ int i;
- size = gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE;
- data = malloc(size);
- if (!data)
- return log_msg_ret("Allocate MRC cache block", -ENOMEM);
- mrccache_setup(data);
- gd->arch.mrc_output = data;
+ for (i = 0; i < MRC_TYPE_COUNT; i++) {
+ struct mrc_output *mrc = &gd->arch.mrc[i];
+ void *data;
+ int size;
+
+ size = mrc->len + MRC_DATA_HEADER_SIZE;
+ data = malloc(size);
+ if (!data)
+ return log_msg_ret("Allocate MRC cache block", -ENOMEM);
+ mrccache_setup(mrc, data);
+ }
return mrccache_save();
}