summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/cpu/coreboot/Makefile1
-rw-r--r--arch/x86/cpu/coreboot/coreboot.c5
-rw-r--r--arch/x86/cpu/coreboot/ipchecksum.c55
-rw-r--r--arch/x86/cpu/coreboot/tables.c8
-rw-r--r--arch/x86/cpu/cpu.c7
-rw-r--r--arch/x86/cpu/ivybridge/Kconfig28
-rw-r--r--arch/x86/cpu/ivybridge/Makefile1
-rw-r--r--arch/x86/cpu/ivybridge/mrccache.c156
-rw-r--r--arch/x86/cpu/ivybridge/sdram.c253
-rw-r--r--arch/x86/cpu/mtrr.c14
-rw-r--r--arch/x86/cpu/start16.S20
-rw-r--r--arch/x86/dts/chromebook_link.dts15
-rw-r--r--arch/x86/include/asm/arch-coreboot/ipchecksum.h37
-rw-r--r--arch/x86/include/asm/arch-ivybridge/mrccache.h51
-rw-r--r--arch/x86/include/asm/global_data.h16
-rw-r--r--arch/x86/include/asm/mtrr.h5
-rw-r--r--arch/x86/include/asm/u-boot-x86.h2
-rw-r--r--arch/x86/lib/init_helpers.c4
-rw-r--r--arch/x86/lib/interrupts.c2
19 files changed, 535 insertions, 145 deletions
diff --git a/arch/x86/cpu/coreboot/Makefile b/arch/x86/cpu/coreboot/Makefile
index 35e6cdd..b6e870a 100644
--- a/arch/x86/cpu/coreboot/Makefile
+++ b/arch/x86/cpu/coreboot/Makefile
@@ -16,7 +16,6 @@
obj-y += car.o
obj-y += coreboot.o
obj-y += tables.o
-obj-y += ipchecksum.o
obj-y += sdram.o
obj-y += timestamp.o
obj-$(CONFIG_PCI) += pci.o
diff --git a/arch/x86/cpu/coreboot/coreboot.c b/arch/x86/cpu/coreboot/coreboot.c
index 6d06d5a..4cdd0d4 100644
--- a/arch/x86/cpu/coreboot/coreboot.c
+++ b/arch/x86/cpu/coreboot/coreboot.c
@@ -99,3 +99,8 @@ void panic_puts(const char *str)
while (*str)
NS16550_putc(port, *str++);
}
+
+int misc_init_r(void)
+{
+ return 0;
+}
diff --git a/arch/x86/cpu/coreboot/ipchecksum.c b/arch/x86/cpu/coreboot/ipchecksum.c
deleted file mode 100644
index 3340872..0000000
--- a/arch/x86/cpu/coreboot/ipchecksum.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * This file is part of the libpayload project.
- *
- * It has originally been taken from the FreeBSD project.
- *
- * Copyright (c) 2001 Charles Mott <cm@linktel.net>
- * Copyright (c) 2008 coresystems GmbH
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <linux/types.h>
-#include <linux/compiler.h>
-#include <asm/arch/ipchecksum.h>
-
-unsigned short ipchksum(const void *vptr, unsigned long nbytes)
-{
- int sum, oddbyte;
- const unsigned short *ptr = vptr;
-
- sum = 0;
- while (nbytes > 1) {
- sum += *ptr++;
- nbytes -= 2;
- }
- if (nbytes == 1) {
- oddbyte = 0;
- ((u8 *)&oddbyte)[0] = *(u8 *) ptr;
- ((u8 *)&oddbyte)[1] = 0;
- sum += oddbyte;
- }
- sum = (sum >> 16) + (sum & 0xffff);
- sum += (sum >> 16);
- return ~sum;
-}
diff --git a/arch/x86/cpu/coreboot/tables.c b/arch/x86/cpu/coreboot/tables.c
index 92b7528..2b12b19 100644
--- a/arch/x86/cpu/coreboot/tables.c
+++ b/arch/x86/cpu/coreboot/tables.c
@@ -8,7 +8,7 @@
*/
#include <common.h>
-#include <asm/arch/ipchecksum.h>
+#include <net.h>
#include <asm/arch/sysinfo.h>
#include <asm/arch/tables.h>
@@ -131,11 +131,11 @@ static int cb_parse_header(void *addr, int len, struct sysinfo_t *info)
return 0;
/* Make sure the checksums match. */
- if (ipchksum((u16 *) header, sizeof(*header)) != 0)
+ if (!ip_checksum_ok(header, sizeof(*header)))
return -1;
- if (ipchksum((u16 *) (ptr + sizeof(*header)),
- header->table_bytes) != header->table_checksum)
+ if (compute_ip_checksum(ptr + sizeof(*header), header->table_bytes) !=
+ header->table_checksum)
return -1;
/* Now, walk the tables. */
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c
index 30e5069..ed7905c 100644
--- a/arch/x86/cpu/cpu.c
+++ b/arch/x86/cpu/cpu.c
@@ -223,6 +223,11 @@ static bool has_cpuid(void)
return flag_is_changeable_p(X86_EFLAGS_ID);
}
+static bool has_mtrr(void)
+{
+ return cpuid_edx(0x00000001) & (1 << 12) ? true : false;
+}
+
static int build_vendor_name(char *vendor_name)
{
struct cpuid_result result;
@@ -318,6 +323,8 @@ int x86_cpu_init_f(void)
gd->arch.x86_model = c.x86_model;
gd->arch.x86_mask = c.x86_mask;
gd->arch.x86_device = cpu.device;
+
+ gd->arch.has_mtrr = has_mtrr();
}
return 0;
diff --git a/arch/x86/cpu/ivybridge/Kconfig b/arch/x86/cpu/ivybridge/Kconfig
index afca957..e4595be 100644
--- a/arch/x86/cpu/ivybridge/Kconfig
+++ b/arch/x86/cpu/ivybridge/Kconfig
@@ -26,20 +26,6 @@ config CACHE_MRC_SIZE_KB
int
default 256
-config MRC_CACHE_BASE
- hex
- default 0xff800000
-
-config MRC_CACHE_LOCATION
- hex
- depends on !CHROMEOS
- default 0x1ec000
-
-config MRC_CACHE_SIZE
- hex
- depends on !CHROMEOS
- default 0x10000
-
config DCACHE_RAM_BASE
hex
default 0xff7f0000
@@ -64,20 +50,6 @@ config CACHE_MRC_SIZE_KB
int
default 512
-config MRC_CACHE_BASE
- hex
- default 0xff800000
-
-config MRC_CACHE_LOCATION
- hex
- depends on !CHROMEOS
- default 0x370000
-
-config MRC_CACHE_SIZE
- hex
- depends on !CHROMEOS
- default 0x10000
-
config DCACHE_RAM_BASE
hex
default 0xff7e0000
diff --git a/arch/x86/cpu/ivybridge/Makefile b/arch/x86/cpu/ivybridge/Makefile
index 0c7efae..3576b83 100644
--- a/arch/x86/cpu/ivybridge/Makefile
+++ b/arch/x86/cpu/ivybridge/Makefile
@@ -14,6 +14,7 @@ obj-y += lpc.o
obj-y += me_status.o
obj-y += model_206ax.o
obj-y += microcode_intel.o
+obj-y += mrccache.o
obj-y += northbridge.o
obj-y += pch.o
obj-y += pci.o
diff --git a/arch/x86/cpu/ivybridge/mrccache.c b/arch/x86/cpu/ivybridge/mrccache.c
new file mode 100644
index 0000000..0f1a64b
--- /dev/null
+++ b/arch/x86/cpu/ivybridge/mrccache.c
@@ -0,0 +1,156 @@
+/*
+ * From Coreboot src/southbridge/intel/bd82x6x/mrccache.c
+ *
+ * Copyright (C) 2014 Google Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <net.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <asm/arch/mrccache.h>
+#include <asm/arch/sandybridge.h>
+
+static struct mrc_data_container *next_mrc_block(
+ struct mrc_data_container *mrc_cache)
+{
+ /* MRC data blocks are aligned within the region */
+ u32 mrc_size = sizeof(*mrc_cache) + mrc_cache->data_size;
+ if (mrc_size & (MRC_DATA_ALIGN - 1UL)) {
+ mrc_size &= ~(MRC_DATA_ALIGN - 1UL);
+ mrc_size += MRC_DATA_ALIGN;
+ }
+
+ u8 *region_ptr = (u8 *)mrc_cache;
+ region_ptr += mrc_size;
+ return (struct mrc_data_container *)region_ptr;
+}
+
+static int is_mrc_cache(struct mrc_data_container *cache)
+{
+ return cache && (cache->signature == MRC_DATA_SIGNATURE);
+}
+
+/*
+ * Find the largest index block in the MRC cache. Return NULL if none is
+ * found.
+ */
+struct mrc_data_container *mrccache_find_current(struct fmap_entry *entry)
+{
+ struct mrc_data_container *cache, *next;
+ ulong base_addr, end_addr;
+ uint id;
+
+ base_addr = (1ULL << 32) - CONFIG_ROM_SIZE + entry->offset;
+ end_addr = base_addr + entry->length;
+ cache = NULL;
+
+ /* Search for the last filled entry in the region */
+ for (id = 0, next = (struct mrc_data_container *)base_addr;
+ is_mrc_cache(next);
+ id++) {
+ cache = next;
+ next = next_mrc_block(next);
+ if ((ulong)next >= end_addr)
+ break;
+ }
+
+ if (id-- == 0) {
+ debug("%s: No valid MRC cache found.\n", __func__);
+ return NULL;
+ }
+
+ /* Verify checksum */
+ if (cache->checksum != compute_ip_checksum(cache->data,
+ cache->data_size)) {
+ printf("%s: MRC cache checksum mismatch\n", __func__);
+ return NULL;
+ }
+
+ debug("%s: picked entry %u from cache block\n", __func__, id);
+
+ return cache;
+}
+
+/**
+ * find_next_mrc_cache() - get next cache entry
+ *
+ * @entry: MRC cache flash area
+ * @cache: Entry to start from
+ *
+ * @return next cache entry if found, NULL if we got to the end
+ */
+static struct mrc_data_container *find_next_mrc_cache(struct fmap_entry *entry,
+ struct mrc_data_container *cache)
+{
+ ulong base_addr, end_addr;
+
+ base_addr = (1ULL << 32) - CONFIG_ROM_SIZE + entry->offset;
+ end_addr = base_addr + entry->length;
+
+ cache = next_mrc_block(cache);
+ if ((ulong)cache >= end_addr) {
+ /* Crossed the boundary */
+ cache = NULL;
+ debug("%s: no available entries found\n", __func__);
+ } else {
+ debug("%s: picked next entry from cache block at %p\n",
+ __func__, cache);
+ }
+
+ return cache;
+}
+
+int mrccache_update(struct spi_flash *sf, struct fmap_entry *entry,
+ struct mrc_data_container *cur)
+{
+ struct mrc_data_container *cache;
+ ulong offset;
+ ulong base_addr;
+ int ret;
+
+ /* Find the last used block */
+ base_addr = (1ULL << 32) - CONFIG_ROM_SIZE + entry->offset;
+ debug("Updating MRC cache data\n");
+ cache = mrccache_find_current(entry);
+ if (cache && (cache->data_size == cur->data_size) &&
+ (!memcmp(cache, cur, cache->data_size + sizeof(*cur)))) {
+ debug("MRC data in flash is up to date. No update\n");
+ return -EEXIST;
+ }
+
+ /* Move to the next block, which will be the first unused block */
+ if (cache)
+ cache = find_next_mrc_cache(entry, cache);
+
+ /*
+ * If we have got to the end, erase the entire mrc-cache area and start
+ * again at block 0.
+ */
+ if (!cache) {
+ debug("Erasing the MRC cache region of %x bytes at %x\n",
+ entry->length, entry->offset);
+
+ ret = spi_flash_erase(sf, entry->offset, entry->length);
+ if (ret) {
+ debug("Failed to erase flash region\n");
+ return ret;
+ }
+ cache = (struct mrc_data_container *)base_addr;
+ }
+
+ /* Write the data out */
+ offset = (ulong)cache - base_addr + entry->offset;
+ debug("Write MRC cache update to flash at %lx\n", offset);
+ ret = spi_flash_write(sf, offset, cur->data_size + sizeof(*cur), cur);
+ if (ret) {
+ debug("Failed to write to SPI flash\n");
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/arch/x86/cpu/ivybridge/sdram.c b/arch/x86/cpu/ivybridge/sdram.c
index 9504735..4963448 100644
--- a/arch/x86/cpu/ivybridge/sdram.c
+++ b/arch/x86/cpu/ivybridge/sdram.c
@@ -14,12 +14,17 @@
#include <errno.h>
#include <fdtdec.h>
#include <malloc.h>
+#include <net.h>
+#include <rtc.h>
+#include <spi.h>
+#include <spi_flash.h>
#include <asm/processor.h>
#include <asm/gpio.h>
#include <asm/global_data.h>
#include <asm/mtrr.h>
#include <asm/pci.h>
#include <asm/arch/me.h>
+#include <asm/arch/mrccache.h>
#include <asm/arch/pei_data.h>
#include <asm/arch/pch.h>
#include <asm/post.h>
@@ -27,6 +32,10 @@
DECLARE_GLOBAL_DATA_PTR;
+#define CMOS_OFFSET_MRC_SEED 152
+#define CMOS_OFFSET_MRC_SEED_S3 156
+#define CMOS_OFFSET_MRC_SEED_CHK 160
+
/*
* This function looks for the highest region of memory lower than 4GB which
* has enough space for U-Boot where U-Boot is aligned on a page boundary.
@@ -80,6 +89,202 @@ void dram_init_banksize(void)
}
}
+static int get_mrc_entry(struct spi_flash **sfp, struct fmap_entry *entry)
+{
+ const void *blob = gd->fdt_blob;
+ int node, spi_node, mrc_node;
+ int upto;
+
+ /* Find the flash chip within the SPI controller node */
+ upto = 0;
+ spi_node = fdtdec_next_alias(blob, "spi", COMPAT_INTEL_ICH_SPI, &upto);
+ if (spi_node < 0)
+ return -ENOENT;
+ node = fdt_first_subnode(blob, spi_node);
+ if (node < 0)
+ return -ECHILD;
+
+ /* 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 (sfp) {
+ *sfp = spi_flash_probe_fdt(blob, node, spi_node);
+ if (!*sfp)
+ return -EBADF;
+ }
+
+ return 0;
+}
+
+static int read_seed_from_cmos(struct pei_data *pei_data)
+{
+ u16 c1, c2, checksum, seed_checksum;
+
+ /*
+ * Read scrambler seeds from CMOS RAM. We don't want to store them in
+ * SPI flash since they change on every boot and that would wear down
+ * the flash too much. So we store these in CMOS and the large MRC
+ * data in SPI flash.
+ */
+ pei_data->scrambler_seed = rtc_read32(CMOS_OFFSET_MRC_SEED);
+ debug("Read scrambler seed 0x%08x from CMOS 0x%02x\n",
+ pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED);
+
+ pei_data->scrambler_seed_s3 = rtc_read32(CMOS_OFFSET_MRC_SEED_S3);
+ debug("Read S3 scrambler seed 0x%08x from CMOS 0x%02x\n",
+ pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3);
+
+ /* Compute seed checksum and compare */
+ c1 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed,
+ sizeof(u32));
+ c2 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed_s3,
+ sizeof(u32));
+ checksum = add_ip_checksums(sizeof(u32), c1, c2);
+
+ seed_checksum = rtc_read8(CMOS_OFFSET_MRC_SEED_CHK);
+ seed_checksum |= rtc_read8(CMOS_OFFSET_MRC_SEED_CHK + 1) << 8;
+
+ if (checksum != seed_checksum) {
+ debug("%s: invalid seed checksum\n", __func__);
+ pei_data->scrambler_seed = 0;
+ pei_data->scrambler_seed_s3 = 0;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int prepare_mrc_cache(struct pei_data *pei_data)
+{
+ struct mrc_data_container *mrc_cache;
+ struct fmap_entry entry;
+ int ret;
+
+ ret = read_seed_from_cmos(pei_data);
+ if (ret)
+ return ret;
+ ret = get_mrc_entry(NULL, &entry);
+ if (ret)
+ return ret;
+ mrc_cache = mrccache_find_current(&entry);
+ if (!mrc_cache)
+ return -ENOENT;
+
+ /*
+ * TODO(sjg@chromium.org): Skip this for now as it causes boot
+ * problems
+ */
+ if (0) {
+ pei_data->mrc_input = mrc_cache->data;
+ pei_data->mrc_input_len = mrc_cache->data_size;
+ }
+ debug("%s: at %p, size %x checksum %04x\n", __func__,
+ pei_data->mrc_input, pei_data->mrc_input_len,
+ mrc_cache->checksum);
+
+ return 0;
+}
+
+static int build_mrc_data(struct mrc_data_container **datap)
+{
+ struct mrc_data_container *data;
+ int orig_len;
+ int output_len;
+
+ orig_len = gd->arch.mrc_output_len;
+ output_len = ALIGN(orig_len, 16);
+ data = malloc(output_len + sizeof(*data));
+ if (!data)
+ return -ENOMEM;
+ data->signature = MRC_DATA_SIGNATURE;
+ data->data_size = output_len;
+ data->reserved = 0;
+ memcpy(data->data, gd->arch.mrc_output, orig_len);
+
+ /* Zero the unused space in aligned buffer. */
+ if (output_len > orig_len)
+ memset(data->data + orig_len, 0, output_len - orig_len);
+
+ data->checksum = compute_ip_checksum(data->data, output_len);
+ *datap = data;
+
+ return 0;
+}
+
+static int write_seeds_to_cmos(struct pei_data *pei_data)
+{
+ u16 c1, c2, checksum;
+
+ /* Save the MRC seed values to CMOS */
+ rtc_write32(CMOS_OFFSET_MRC_SEED, pei_data->scrambler_seed);
+ debug("Save scrambler seed 0x%08x to CMOS 0x%02x\n",
+ pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED);
+
+ rtc_write32(CMOS_OFFSET_MRC_SEED_S3, pei_data->scrambler_seed_s3);
+ debug("Save s3 scrambler seed 0x%08x to CMOS 0x%02x\n",
+ pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3);
+
+ /* Save a simple checksum of the seed values */
+ c1 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed,
+ sizeof(u32));
+ c2 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed_s3,
+ sizeof(u32));
+ checksum = add_ip_checksums(sizeof(u32), c1, c2);
+
+ rtc_write8(CMOS_OFFSET_MRC_SEED_CHK, checksum & 0xff);
+ rtc_write8(CMOS_OFFSET_MRC_SEED_CHK + 1, (checksum >> 8) & 0xff);
+
+ return 0;
+}
+
+static int sdram_save_mrc_data(void)
+{
+ struct mrc_data_container *data;
+ struct fmap_entry entry;
+ struct spi_flash *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 = get_mrc_entry(&sf, &entry);
+ if (ret)
+ goto err_entry;
+ ret = build_mrc_data(&data);
+ if (ret)
+ goto err_data;
+ ret = mrccache_update(sf, &entry, data);
+ if (!ret)
+ debug("Saved MRC data with checksum %04x\n", data->checksum);
+
+ free(data);
+err_data:
+ spi_flash_free(sf);
+err_entry:
+ if (ret)
+ debug("%s: Failed: %d\n", __func__, ret);
+ return ret;
+}
+
+/* Use this hook to save our SDRAM parameters */
+int misc_init_r(void)
+{
+ int ret;
+
+ ret = sdram_save_mrc_data();
+ if (ret)
+ printf("Unable to save MRC data: %d\n", ret);
+
+ return 0;
+}
+
static const char *const ecc_decoder[] = {
"inactive",
"active on IO",
@@ -142,6 +347,11 @@ static asmlinkage void console_tx_byte(unsigned char byte)
#endif
}
+static int recovery_mode_enabled(void)
+{
+ return false;
+}
+
/**
* Find the PEI executable in the ROM and execute it.
*
@@ -166,6 +376,17 @@ int sdram_initialise(struct pei_data *pei_data)
debug("Starting UEFI PEI System Agent\n");
+ /*
+ * Do not pass MRC data in for recovery mode boot,
+ * Always pass it in for S3 resume.
+ */
+ if (!recovery_mode_enabled() ||
+ pei_data->boot_mode == PEI_BOOT_RESUME) {
+ ret = prepare_mrc_cache(pei_data);
+ if (ret)
+ debug("prepare_mrc_cache failed: %d\n", ret);
+ }
+
/* If MRC data is not found we cannot continue S3 resume. */
if (pei_data->boot_mode == PEI_BOOT_RESUME && !pei_data->mrc_input) {
debug("Giving up in sdram_initialize: No MRC data\n");
@@ -216,6 +437,8 @@ int sdram_initialise(struct pei_data *pei_data)
debug("System Agent Version %d.%d.%d Build %d\n",
version >> 24 , (version >> 16) & 0xff,
(version >> 8) & 0xff, version & 0xff);
+ debug("MCR output data length %#x at %p\n", pei_data->mrc_output_len,
+ pei_data->mrc_output);
/*
* Send ME init done for SandyBridge here. This is done inside the
@@ -231,6 +454,36 @@ int sdram_initialise(struct pei_data *pei_data)
post_system_agent_init(pei_data);
report_memory_config();
+ /* S3 resume: don't save scrambler seed or MRC data */
+ if (pei_data->boot_mode != PEI_BOOT_RESUME) {
+ /*
+ * This will be copied to SDRAM in reserve_arch(), then written
+ * to SPI flash in sdram_save_mrc_data()
+ */
+ gd->arch.mrc_output = (char *)pei_data->mrc_output;
+ gd->arch.mrc_output_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);
+ }
+
+ return 0;
+}
+
+int reserve_arch(void)
+{
+ u16 checksum;
+
+ checksum = compute_ip_checksum(gd->arch.mrc_output,
+ gd->arch.mrc_output_len);
+ debug("Saving %d bytes for MRC output data, checksum %04x\n",
+ gd->arch.mrc_output_len, checksum);
+ gd->start_addr_sp -= gd->arch.mrc_output_len;
+ memcpy((void *)gd->start_addr_sp, gd->arch.mrc_output,
+ gd->arch.mrc_output_len);
+ gd->arch.mrc_output = (char *)gd->start_addr_sp;
+ gd->start_addr_sp &= ~0xf;
+
return 0;
}
diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c
index d5a825d..5d36b3e 100644
--- a/arch/x86/cpu/mtrr.c
+++ b/arch/x86/cpu/mtrr.c
@@ -17,9 +17,14 @@
#include <asm/msr.h>
#include <asm/mtrr.h>
+DECLARE_GLOBAL_DATA_PTR;
+
/* Prepare to adjust MTRRs */
void mtrr_open(struct mtrr_state *state)
{
+ if (!gd->arch.has_mtrr)
+ return;
+
state->enable_cache = dcache_status();
if (state->enable_cache)
@@ -31,6 +36,9 @@ void mtrr_open(struct mtrr_state *state)
/* Clean up after adjusting MTRRs, and enable them */
void mtrr_close(struct mtrr_state *state)
{
+ if (!gd->arch.has_mtrr)
+ return;
+
wrmsrl(MTRR_DEF_TYPE_MSR, state->deftype | MTRR_DEF_TYPE_EN);
if (state->enable_cache)
enable_caches();
@@ -43,6 +51,9 @@ int mtrr_commit(bool do_caches)
uint64_t mask;
int i;
+ if (!gd->arch.has_mtrr)
+ return -ENOSYS;
+
mtrr_open(&state);
for (i = 0; i < gd->arch.mtrr_req_count; i++, req++) {
mask = ~(req->size - 1);
@@ -64,6 +75,9 @@ int mtrr_add_request(int type, uint64_t start, uint64_t size)
struct mtrr_request *req;
uint64_t mask;
+ if (!gd->arch.has_mtrr)
+ return -ENOSYS;
+
if (gd->arch.mtrr_req_count == MAX_MTRR_REQUESTS)
return -ENOSPC;
req = &gd->arch.mtrr_req[gd->arch.mtrr_req_count++];
diff --git a/arch/x86/cpu/start16.S b/arch/x86/cpu/start16.S
index 9550502..826e2b4 100644
--- a/arch/x86/cpu/start16.S
+++ b/arch/x86/cpu/start16.S
@@ -1,5 +1,5 @@
/*
- * U-boot - x86 Startup Code
+ * U-Boot - x86 Startup Code
*
* (C) Copyright 2008-2011
* Graeme Russ, <graeme.russ@gmail.com>
@@ -28,7 +28,7 @@ start16:
movl $GD_FLG_COLD_BOOT, %ebx
xorl %eax, %eax
- movl %eax, %cr3 /* Invalidate TLB */
+ movl %eax, %cr3 /* Invalidate TLB */
/* Turn off cache (this might require a 486-class CPU) */
movl %cr0, %eax
@@ -49,7 +49,7 @@ o32 cs lgdt gdt_ptr
jmp ff
ff:
- /* Finally restore BIST and jump to the 32bit initialization code */
+ /* Finally restore BIST and jump to the 32-bit initialization code */
movw $code32start, %ax
movw %ax, %bp
movl %ecx, %eax
@@ -64,17 +64,17 @@ idt_ptr:
.word 0 /* limit */
.long 0 /* base */
-/*
- * The following Global Descriptor Table is just enough to get us into
- * 'Flat Protected Mode' - It will be discarded as soon as the final
- * GDT is setup in a safe location in RAM
- */
+ /*
+ * The following Global Descriptor Table is just enough to get us into
+ * 'Flat Protected Mode' - It will be discarded as soon as the final
+ * GDT is setup in a safe location in RAM
+ */
gdt_ptr:
.word 0x1f /* limit (31 bytes = 4 GDT entries - 1) */
.long BOOT_SEG + gdt /* base */
-/* Some CPUs are picky about GDT alignment... */
-.align 16
+ /* Some CPUs are picky about GDT alignment... */
+ .align 16
gdt:
/*
* The GDT table ...
diff --git a/arch/x86/dts/chromebook_link.dts b/arch/x86/dts/chromebook_link.dts
index 9490b16..45ada61 100644
--- a/arch/x86/dts/chromebook_link.dts
+++ b/arch/x86/dts/chromebook_link.dts
@@ -7,6 +7,10 @@
model = "Google Link";
compatible = "google,link", "intel,celeron-ivybridge";
+ aliases {
+ spi0 = "/spi";
+ };
+
config {
silent_console = <0>;
};
@@ -150,11 +154,20 @@
spi {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "intel,ich9";
+ compatible = "intel,ich-spi";
spi-flash@0 {
+ #size-cells = <1>;
+ #address-cells = <1>;
reg = <0>;
compatible = "winbond,w25q64", "spi-flash";
memory-map = <0xff800000 0x00800000>;
+ rw-mrc-cache {
+ label = "rw-mrc-cache";
+ /* Alignment: 4k (for updating) */
+ reg = <0x003e0000 0x00010000>;
+ type = "wiped";
+ wipe-value = [ff];
+ };
};
};
diff --git a/arch/x86/include/asm/arch-coreboot/ipchecksum.h b/arch/x86/include/asm/arch-coreboot/ipchecksum.h
deleted file mode 100644
index 1d73b4d..0000000
--- a/arch/x86/include/asm/arch-coreboot/ipchecksum.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * This file is part of the libpayload project.
- *
- * It has originally been taken from the FreeBSD project.
- *
- * Copyright (c) 2001 Charles Mott <cm@linktel.net>
- * Copyright (c) 2008 coresystems GmbH
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _COREBOOT_IPCHECKSUM_H
-#define _COREBOOT_IPCHECKSUM_H
-
-unsigned short ipchksum(const void *vptr, unsigned long nbytes);
-
-#endif
diff --git a/arch/x86/include/asm/arch-ivybridge/mrccache.h b/arch/x86/include/asm/arch-ivybridge/mrccache.h
new file mode 100644
index 0000000..968b2ef
--- /dev/null
+++ b/arch/x86/include/asm/arch-ivybridge/mrccache.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _ASM_ARCH_MRCCACHE_H
+#define _ASM_ARCH_MRCCACHE_H
+
+#define MRC_DATA_ALIGN 0x1000
+#define MRC_DATA_SIGNATURE (('M' << 0) | ('R' << 8) | ('C' << 16) | \
+ ('D'<<24))
+
+__packed struct mrc_data_container {
+ u32 signature; /* "MRCD" */
+ u32 data_size; /* Size of the 'data' field */
+ u32 checksum; /* IP style checksum */
+ u32 reserved; /* For header alignment */
+ u8 data[0]; /* Variable size, platform/run time dependent */
+};
+
+struct fmap_entry;
+struct spi_flash;
+
+/**
+ * mrccache_find_current() - find the latest MRC cache record
+ *
+ * This searches the MRC cache region looking for the latest record to use
+ * for setting up SDRAM
+ *
+ * @entry: Information about the position and size of the MRC cache
+ * @return pointer to latest record, or NULL if none
+ */
+struct mrc_data_container *mrccache_find_current(struct fmap_entry *entry);
+
+/**
+ * mrccache_update() - update the MRC cache with a new record
+ *
+ * This writes a new record to the end of the MRC cache. If the new record is
+ * the same as the latest record then the write is skipped
+ *
+ * @sf: SPI flash to write to
+ * @entry: Position and size of MRC cache in SPI flash
+ * @cur: Record to write
+ * @return 0 if updated, -EEXIST if the record is the same as the latest
+ * record, other error if SPI write failed
+ */
+int mrccache_update(struct spi_flash *sf, struct fmap_entry *entry,
+ struct mrc_data_container *cur);
+
+#endif
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h
index 24e3052..5ee06eb 100644
--- a/arch/x86/include/asm/global_data.h
+++ b/arch/x86/include/asm/global_data.h
@@ -44,11 +44,11 @@ struct mtrr_request {
/* Architecture-specific global data */
struct arch_global_data {
- struct global_data *gd_addr; /* Location of Global Data */
- uint8_t x86; /* CPU family */
- uint8_t x86_vendor; /* CPU vendor */
- uint8_t x86_model;
- uint8_t x86_mask;
+ struct global_data *gd_addr; /* Location of Global Data */
+ uint8_t x86; /* CPU family */
+ uint8_t x86_vendor; /* CPU vendor */
+ uint8_t x86_model;
+ uint8_t x86_mask;
uint32_t x86_device;
uint64_t tsc_base; /* Initial value returned by rdtsc() */
uint32_t tsc_base_kclocks; /* Initial tsc as a kclocks value */
@@ -60,10 +60,14 @@ struct arch_global_data {
const struct pch_gpio_map *gpio_map; /* board GPIO map */
struct memory_info meminfo; /* Memory information */
#ifdef CONFIG_HAVE_FSP
- void *hob_list; /* FSP HOB list */
+ void *hob_list; /* FSP HOB list */
#endif
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;
};
#endif
diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h
index 3c11740..fda4eae 100644
--- a/arch/x86/include/asm/mtrr.h
+++ b/arch/x86/include/asm/mtrr.h
@@ -65,7 +65,6 @@ void mtrr_open(struct mtrr_state *state);
*
* @state: Structure from mtrr_open()
*/
-/* */
void mtrr_close(struct mtrr_state *state);
/**
@@ -76,6 +75,8 @@ void mtrr_close(struct mtrr_state *state);
* @type: Requested type (MTRR_TYPE_)
* @start: Start address
* @size: Size
+ *
+ * @return: 0 on success, non-zero on failure
*/
int mtrr_add_request(int type, uint64_t start, uint64_t size);
@@ -86,6 +87,8 @@ int mtrr_add_request(int type, uint64_t start, uint64_t size);
* It must be called with caches disabled.
*
* @do_caches: true if caches are currently on
+ *
+ * @return: 0 on success, non-zero on failure
*/
int mtrr_commit(bool do_caches);
diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h
index 36145cb..b98afa8 100644
--- a/arch/x86/include/asm/u-boot-x86.h
+++ b/arch/x86/include/asm/u-boot-x86.h
@@ -70,4 +70,6 @@ uint64_t timer_get_tsc(void);
void quick_ram_check(void);
+#define PCI_VGA_RAM_IMAGE_START 0xc0000
+
#endif /* _U_BOOT_I386_H_ */
diff --git a/arch/x86/lib/init_helpers.c b/arch/x86/lib/init_helpers.c
index fc211d9..5097ca2 100644
--- a/arch/x86/lib/init_helpers.c
+++ b/arch/x86/lib/init_helpers.c
@@ -7,6 +7,7 @@
#include <common.h>
#include <fdtdec.h>
#include <spi.h>
+#include <asm/errno.h>
#include <asm/mtrr.h>
#include <asm/sections.h>
@@ -71,7 +72,8 @@ int init_cache_f_r(void)
int ret;
ret = mtrr_commit(false);
- if (ret)
+ /* If MTRR MSR is not implemented by the processor, just ignore it */
+ if (ret && ret != -ENOSYS)
return ret;
#endif
/* Initialise the CPU cache(s) */
diff --git a/arch/x86/lib/interrupts.c b/arch/x86/lib/interrupts.c
index 6bb22d2..146ad11 100644
--- a/arch/x86/lib/interrupts.c
+++ b/arch/x86/lib/interrupts.c
@@ -130,7 +130,7 @@ int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
printf("Interrupt-Information:\n");
printf("Nr Routine Arg Count\n");
- for (irq = 0; irq <= CONFIG_SYS_NUM_IRQS; irq++) {
+ for (irq = 0; irq < CONFIG_SYS_NUM_IRQS; irq++) {
if (irq_handlers[irq].handler != NULL) {
printf("%02d %08lx %08lx %d\n",
irq,