diff options
-rw-r--r-- | arch/x86/include/asm/mrccache.h | 51 | ||||
-rw-r--r-- | arch/x86/lib/mrccache.c | 89 |
2 files changed, 140 insertions, 0 deletions
diff --git a/arch/x86/include/asm/mrccache.h b/arch/x86/include/asm/mrccache.h index 2fd908287d..bcf7117f09 100644 --- a/arch/x86/include/asm/mrccache.h +++ b/arch/x86/include/asm/mrccache.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Google, Inc + * Copyright (C) 2015 Bin Meng <bmeng.cn@gmail.com> * * SPDX-License-Identifier: GPL-2.0+ */ @@ -11,6 +12,8 @@ #define MRC_DATA_SIGNATURE (('M' << 0) | ('R' << 8) | \ ('C' << 16) | ('D'<<24)) +#define MRC_DATA_HEADER_SIZE 32 + struct __packed mrc_data_container { u32 signature; /* "MRCD" */ u32 data_size; /* Size of the 'data' field */ @@ -48,4 +51,52 @@ struct mrc_data_container *mrccache_find_current(struct fmap_entry *entry); int mrccache_update(struct udevice *sf, struct fmap_entry *entry, struct mrc_data_container *cur); +/** + * mrccache_reserve() - reserve MRC data on the stack + * + * This copies MRC data pointed by gd->arch.mrc_output to a new place on the + * stack with length gd->arch.mrc_output_len, and updates gd->arch.mrc_output + * to point to the new place once the migration is done. + * + * This routine should be called by reserve_arch() before U-Boot is relocated + * when MRC cache is enabled. + * + * @return 0 always + */ +int mrccache_reserve(void); + +/** + * mrccache_get_region() - get MRC region on the SPI flash + * + * This gets MRC region whose offset and size are described in the device tree + * as a subnode to the SPI flash. If a non-NULL device pointer is supplied, + * this also probes the SPI flash device and returns its device pointer for + * the caller to use later. + * + * Be careful when calling this routine with a non-NULL device pointer: + * - driver model initialization must be complete + * - calling in the pre-relocation phase may bring some side effects during + * the SPI flash device probe (eg: for SPI controllers on a PCI bus, it + * triggers PCI bus enumeration during which insufficient memory issue + * might be exposed and it causes subsequent SPI flash probe fails). + * + * @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 + * device tree, -EPERM if MRC region subnode does not exist in the device + * tree, -EINVAL if MRC region properties format is incorrect, other error + * if SPI flash probe failed. + */ +int mrccache_get_region(struct udevice **devp, struct fmap_entry *entry); + +/** + * mrccache_save() - save MRC data to the SPI flash + * + * This saves MRC data stored previously by gd->arch.mrc_output to a proper + * place within the MRC region on the SPI flash. + * + * @return 0 if saved to SPI flash successfully, other error if failed + */ +int mrccache_save(void); + #endif /* _ASM_MRCCACHE_H */ diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index 1c4b5a8d51..0efae6dbdf 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; +} |