diff mbox series

[U-Boot,085/126] x86: Update mrccache to support multiple caches

Message ID 20190925145750.200592-86-sjg@chromium.org
State Superseded
Delegated to: Bin Meng
Headers show
Series x86: Add initial support for apollolake | expand

Commit Message

Simon Glass Sept. 25, 2019, 2:57 p.m. UTC
With apollolake 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>
---

 arch/x86/cpu/broadwell/sdram.c     |  8 ++-
 arch/x86/cpu/ivybridge/sdram.c     |  8 ++-
 arch/x86/cpu/quark/dram.c          |  8 ++-
 arch/x86/include/asm/global_data.h | 21 +++++--
 arch/x86/include/asm/mrccache.h    | 11 +++-
 arch/x86/lib/fsp/fsp_common.c      |  2 +-
 arch/x86/lib/fsp1/fsp_dram.c       |  8 ++-
 arch/x86/lib/mrccache.c            | 93 ++++++++++++++++++++----------
 8 files changed, 109 insertions(+), 50 deletions(-)

Comments

Bin Meng Oct. 10, 2019, 7:39 a.m. UTC | #1
Hi Simon,

On Wed, Sep 25, 2019 at 10:59 PM Simon Glass <sjg@chromium.org> wrote:
>
> With apollolake 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>
> ---
>
>  arch/x86/cpu/broadwell/sdram.c     |  8 ++-
>  arch/x86/cpu/ivybridge/sdram.c     |  8 ++-
>  arch/x86/cpu/quark/dram.c          |  8 ++-
>  arch/x86/include/asm/global_data.h | 21 +++++--
>  arch/x86/include/asm/mrccache.h    | 11 +++-
>  arch/x86/lib/fsp/fsp_common.c      |  2 +-
>  arch/x86/lib/fsp1/fsp_dram.c       |  8 ++-
>  arch/x86/lib/mrccache.c            | 93 ++++++++++++++++++++----------
>  8 files changed, 109 insertions(+), 50 deletions(-)
>
> diff --git a/arch/x86/cpu/broadwell/sdram.c b/arch/x86/cpu/broadwell/sdram.c
> index b31d78c092a..107c04691b0 100644
> --- a/arch/x86/cpu/broadwell/sdram.c
> +++ b/arch/x86/cpu/broadwell/sdram.c
> @@ -82,7 +82,7 @@ static int prepare_mrc_cache(struct pei_data *pei_data)
>         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);
> @@ -168,12 +168,14 @@ int dram_init(void)
>               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 8a58d0383d5..8b03406666e 100644
> --- a/arch/x86/cpu/ivybridge/sdram.c
> +++ b/arch/x86/cpu/ivybridge/sdram.c
> @@ -115,7 +115,7 @@ static int prepare_mrc_cache(struct pei_data *pei_data)
>         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);
> @@ -537,12 +537,14 @@ int dram_init(void)
>
>         /* 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 51f9659ab15..3994355112b 100644
> --- a/arch/x86/cpu/quark/dram.c
> +++ b/arch/x86/cpu/quark/dram.c
> @@ -22,7 +22,7 @@ static __maybe_unused int prepare_mrc_cache(struct mrc_params *mrc_params)
>         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;
>
> @@ -152,9 +152,11 @@ int dram_init(void)
>  #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 c5faac5c901..2475b3427e1 100644
> --- a/arch/x86/include/asm/global_data.h
> +++ b/arch/x86/include/asm/global_data.h
> @@ -67,6 +67,21 @@ struct mtrr_request {
>         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);
> @@ -90,10 +105,8 @@ struct arch_global_data {
>         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 abf58182237..b81e2b2fb6a 100644
> --- a/arch/x86/include/asm/mrccache.h
> +++ b/arch/x86/include/asm/mrccache.h
> @@ -27,6 +27,13 @@ struct mrc_region {
>         u32     length;
>  };
>
> +/* Types of MRC data */
> +enum mrc_type_t {
> +       MRC_TYPE_NORMAL,
> +
> +       MRC_TYPE_COUNT,
> +};
> +
>  struct udevice;
>
>  /**
> @@ -84,6 +91,7 @@ int mrccache_reserve(void);
>   *   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 @@ int mrccache_reserve(void);
>   * 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 40ba866d77c..c1c30ce0eb6 100644
> --- a/arch/x86/lib/fsp/fsp_common.c
> +++ b/arch/x86/lib/fsp/fsp_common.c
> @@ -63,7 +63,7 @@ void *fsp_prepare_mrc_cache(void)
>         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 6a3349b42af..5ef89744b94 100644
> --- a/arch/x86/lib/fsp1/fsp_dram.c
> +++ b/arch/x86/lib/fsp1/fsp_dram.c
> @@ -15,9 +15,11 @@ int dram_init(void)
>         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 0208696c834..8de7dc48f44 100644
> --- a/arch/x86/lib/mrccache.c
> +++ b/arch/x86/lib/mrccache.c
> @@ -159,44 +159,51 @@ int mrccache_update(struct udevice *sf, struct mrc_region *entry,
>                                  cur);
>         if (ret) {
>                 debug("Failed to write to SPI flash\n");
> -               return ret;
> +               return log_msg_ret("Cannot update mrccache", ret);

This line change should be in patch [84/126] "x86: Tidy up error
handling in mrccache_save()"

>         }
>
>         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;
> +
> +       for (i = 0; i < MRC_TYPE_COUNT; i++) {
> +               struct mrc_output *mrc = &gd->arch.mrc[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);
> +               if (!mrc->len)
> +                       continue;
>
> -       gd->start_addr_sp &= ~0xf;
> +               /* 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;
> @@ -221,7 +228,8 @@ int mrccache_get_region(struct udevice **devp, struct mrc_region *entry)
>         }
>
>         /* Find the place where we put the MRC cache */
> -       mrc_node = dev_read_subnode(dev, "rw-mrc-cache");
> +       mrc_node = dev_read_subnode(dev, type == MRC_TYPE_NORMAL ?
> +                                   "rw-mrc-cache" : "rw-var-mrc-cache");

This change should either be put in next patch [86/126] "x86: Add
mrccache support for a 'variable' cache", or squash the [86/126] patch
into this patch.

>         if (!ofnode_valid(mrc_node))
>                 return log_msg_ret("Cannot find node", -EPERM);
>
> @@ -233,31 +241,33 @@ int mrccache_get_region(struct udevice **devp, struct mrc_region *entry)
>
>         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);
> @@ -267,17 +277,36 @@ int mrccache_save(void)
>         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;
> -
> -       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;
> +       int i;
> +
> +       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();
>  }
> --

Regards,
Bin
diff mbox series

Patch

diff --git a/arch/x86/cpu/broadwell/sdram.c b/arch/x86/cpu/broadwell/sdram.c
index b31d78c092a..107c04691b0 100644
--- a/arch/x86/cpu/broadwell/sdram.c
+++ b/arch/x86/cpu/broadwell/sdram.c
@@ -82,7 +82,7 @@  static int prepare_mrc_cache(struct pei_data *pei_data)
 	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);
@@ -168,12 +168,14 @@  int dram_init(void)
 	      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 8a58d0383d5..8b03406666e 100644
--- a/arch/x86/cpu/ivybridge/sdram.c
+++ b/arch/x86/cpu/ivybridge/sdram.c
@@ -115,7 +115,7 @@  static int prepare_mrc_cache(struct pei_data *pei_data)
 	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);
@@ -537,12 +537,14 @@  int dram_init(void)
 
 	/* 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 51f9659ab15..3994355112b 100644
--- a/arch/x86/cpu/quark/dram.c
+++ b/arch/x86/cpu/quark/dram.c
@@ -22,7 +22,7 @@  static __maybe_unused int prepare_mrc_cache(struct mrc_params *mrc_params)
 	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;
 
@@ -152,9 +152,11 @@  int dram_init(void)
 #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 c5faac5c901..2475b3427e1 100644
--- a/arch/x86/include/asm/global_data.h
+++ b/arch/x86/include/asm/global_data.h
@@ -67,6 +67,21 @@  struct mtrr_request {
 	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);
@@ -90,10 +105,8 @@  struct arch_global_data {
 	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 abf58182237..b81e2b2fb6a 100644
--- a/arch/x86/include/asm/mrccache.h
+++ b/arch/x86/include/asm/mrccache.h
@@ -27,6 +27,13 @@  struct mrc_region {
 	u32	length;
 };
 
+/* Types of MRC data */
+enum mrc_type_t {
+	MRC_TYPE_NORMAL,
+
+	MRC_TYPE_COUNT,
+};
+
 struct udevice;
 
 /**
@@ -84,6 +91,7 @@  int mrccache_reserve(void);
  *   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 @@  int mrccache_reserve(void);
  * 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 40ba866d77c..c1c30ce0eb6 100644
--- a/arch/x86/lib/fsp/fsp_common.c
+++ b/arch/x86/lib/fsp/fsp_common.c
@@ -63,7 +63,7 @@  void *fsp_prepare_mrc_cache(void)
 	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 6a3349b42af..5ef89744b94 100644
--- a/arch/x86/lib/fsp1/fsp_dram.c
+++ b/arch/x86/lib/fsp1/fsp_dram.c
@@ -15,9 +15,11 @@  int dram_init(void)
 	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 0208696c834..8de7dc48f44 100644
--- a/arch/x86/lib/mrccache.c
+++ b/arch/x86/lib/mrccache.c
@@ -159,44 +159,51 @@  int mrccache_update(struct udevice *sf, struct mrc_region *entry,
 				 cur);
 	if (ret) {
 		debug("Failed to write to SPI flash\n");
-		return ret;
+		return log_msg_ret("Cannot update mrccache", ret);
 	}
 
 	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;
+
+	for (i = 0; i < MRC_TYPE_COUNT; i++) {
+		struct mrc_output *mrc = &gd->arch.mrc[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);
+		if (!mrc->len)
+			continue;
 
-	gd->start_addr_sp &= ~0xf;
+		/* 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;
@@ -221,7 +228,8 @@  int mrccache_get_region(struct udevice **devp, struct mrc_region *entry)
 	}
 
 	/* Find the place where we put the MRC cache */
-	mrc_node = dev_read_subnode(dev, "rw-mrc-cache");
+	mrc_node = dev_read_subnode(dev, type == MRC_TYPE_NORMAL ?
+				    "rw-mrc-cache" : "rw-var-mrc-cache");
 	if (!ofnode_valid(mrc_node))
 		return log_msg_ret("Cannot find node", -EPERM);
 
@@ -233,31 +241,33 @@  int mrccache_get_region(struct udevice **devp, struct mrc_region *entry)
 
 	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);
@@ -267,17 +277,36 @@  int mrccache_save(void)
 	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;
-
-	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;
+	int i;
+
+	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();
 }