diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/cpu/coreboot/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/cpu/coreboot/coreboot.c | 5 | ||||
-rw-r--r-- | arch/x86/cpu/coreboot/ipchecksum.c | 55 | ||||
-rw-r--r-- | arch/x86/cpu/coreboot/tables.c | 8 | ||||
-rw-r--r-- | arch/x86/cpu/cpu.c | 7 | ||||
-rw-r--r-- | arch/x86/cpu/ivybridge/Kconfig | 28 | ||||
-rw-r--r-- | arch/x86/cpu/ivybridge/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/cpu/ivybridge/mrccache.c | 156 | ||||
-rw-r--r-- | arch/x86/cpu/ivybridge/sdram.c | 253 | ||||
-rw-r--r-- | arch/x86/cpu/mtrr.c | 14 | ||||
-rw-r--r-- | arch/x86/cpu/start16.S | 20 | ||||
-rw-r--r-- | arch/x86/dts/chromebook_link.dts | 15 | ||||
-rw-r--r-- | arch/x86/include/asm/arch-coreboot/ipchecksum.h | 37 | ||||
-rw-r--r-- | arch/x86/include/asm/arch-ivybridge/mrccache.h | 51 | ||||
-rw-r--r-- | arch/x86/include/asm/global_data.h | 16 | ||||
-rw-r--r-- | arch/x86/include/asm/mtrr.h | 5 | ||||
-rw-r--r-- | arch/x86/include/asm/u-boot-x86.h | 2 | ||||
-rw-r--r-- | arch/x86/lib/init_helpers.c | 4 | ||||
-rw-r--r-- | arch/x86/lib/interrupts.c | 2 |
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, |