summaryrefslogtreecommitdiff
path: root/arch/x86/lib/mrccache.c
diff options
context:
space:
mode:
authorBin Meng <bmeng.cn@gmail.com>2015-10-11 21:37:39 -0700
committerSimon Glass <sjg@chromium.org>2015-10-21 07:46:27 -0600
commited800961a019240208de4ee5662d6f02381a18aa (patch)
tree1fc7d5f5eb2d033a74598d85bea44e0086461c20 /arch/x86/lib/mrccache.c
parentbfa95c538b8b7d9384141f3c88021aa9d941ba54 (diff)
downloadu-boot-imx-ed800961a019240208de4ee5662d6f02381a18aa.zip
u-boot-imx-ed800961a019240208de4ee5662d6f02381a18aa.tar.gz
u-boot-imx-ed800961a019240208de4ee5662d6f02381a18aa.tar.bz2
x86: Add more common routines to manipulate mrc cache
This adds mrccache_reserve(), mrccache_get_region() and mrccache_save() APIs to the mrccache codes. They are ported from the ivybridge implementation, but with some changes. For example, in the mrccache_reserve(), ivybridge version only reserves the pure MRC data, which causes additional malloc() when saving the cache as the save API needs some meta data. Now we change it to save the whole MRC date plus the meta data to elinimate the need for the malloc() later. Signed-off-by: Bin Meng <bmeng.cn@gmail.com> Acked-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'arch/x86/lib/mrccache.c')
-rw-r--r--arch/x86/lib/mrccache.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c
index 1c4b5a8..0efae6d 100644
--- a/arch/x86/lib/mrccache.c
+++ b/arch/x86/lib/mrccache.c
@@ -2,11 +2,13 @@
* From coreboot src/southbridge/intel/bd82x6x/mrccache.c
*
* Copyright (C) 2014 Google Inc.
+ * Copyright (C) 2015 Bin Meng <bmeng.cn@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
+#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <net.h>
@@ -14,6 +16,8 @@
#include <spi_flash.h>
#include <asm/mrccache.h>
+DECLARE_GLOBAL_DATA_PTR;
+
static struct mrc_data_container *next_mrc_block(
struct mrc_data_container *cache)
{
@@ -155,3 +159,88 @@ int mrccache_update(struct udevice *sf, struct fmap_entry *entry,
return 0;
}
+
+int mrccache_reserve(void)
+{
+ struct mrc_data_container *cache;
+ u16 checksum;
+
+ if (!gd->arch.mrc_output_len)
+ return 0;
+
+ /* adjust stack pointer to store pure cache data plus the header */
+ gd->start_addr_sp -= (gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE);
+ cache = (struct mrc_data_container *)gd->start_addr_sp;
+
+ cache->signature = MRC_DATA_SIGNATURE;
+ cache->data_size = gd->arch.mrc_output_len;
+ checksum = compute_ip_checksum(gd->arch.mrc_output, 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);
+
+ /* gd->arch.mrc_output now points to the container */
+ gd->arch.mrc_output = (char *)cache;
+
+ gd->start_addr_sp &= ~0xf;
+
+ return 0;
+}
+
+int mrccache_get_region(struct udevice **devp, struct fmap_entry *entry)
+{
+ const void *blob = gd->fdt_blob;
+ int node, mrc_node;
+ int ret;
+
+ /* Find the flash chip within the SPI controller node */
+ node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
+ if (node < 0)
+ return -ENOENT;
+
+ /* Find the place where we put the MRC cache */
+ mrc_node = fdt_subnode_offset(blob, node, "rw-mrc-cache");
+ if (mrc_node < 0)
+ return -EPERM;
+
+ if (fdtdec_read_fmap_entry(blob, mrc_node, "rm-mrc-cache", entry))
+ return -EINVAL;
+
+ if (devp) {
+ ret = uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node,
+ devp);
+ debug("ret = %d\n", ret);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int mrccache_save(void)
+{
+ struct mrc_data_container *data;
+ struct fmap_entry entry;
+ struct udevice *sf;
+ int ret;
+
+ if (!gd->arch.mrc_output_len)
+ return 0;
+ debug("Saving %d bytes of MRC output data to SPI flash\n",
+ gd->arch.mrc_output_len);
+
+ ret = mrccache_get_region(&sf, &entry);
+ if (ret)
+ goto err_entry;
+ data = (struct mrc_data_container *)gd->arch.mrc_output;
+ ret = mrccache_update(sf, &entry, data);
+ if (!ret)
+ debug("Saved MRC data with checksum %04x\n", data->checksum);
+
+err_entry:
+ if (ret)
+ debug("%s: Failed: %d\n", __func__, ret);
+ return ret;
+}