From bdc88d4eb31e2bc84afb427c216c79e87a4233ef Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 29 Dec 2014 19:32:24 -0700 Subject: x86: Support ROMs on other archs We shouldn't assume that the VGA ROM can always be loaded at c0000. This is only true on x86 machines. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/include/asm/u-boot-x86.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/x86') diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index 36145cb0a8..b98afa801d 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_ */ -- cgit From 07570e709765e93f2b1e9506cfd8fa24455636b5 Mon Sep 17 00:00:00 2001 From: Sebastien Ronsse Date: Mon, 12 Jan 2015 17:17:25 +0000 Subject: x86: Fix out of bounds irq handlers access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using coreboot-x86_defconfig, the following error occurred prior to this modification: CC arch/x86/lib/interrupts arch/x86/lib/interrupts.c: In function ‘do_irqinfo’: arch/x86/lib/interrupts.c:134:24: error: iteration 16u invokes undefined behavior [-Werror=aggressive-loop-optimizations] if (irq_handlers[irq].handler != NULL) { ^ arch/x86/lib/interrupts.c:133:2: note: containing loop for (irq = 0; irq <= CONFIG_SYS_NUM_IRQS; irq++) { ^ cc1: all warnings being treated as errors scripts/Makefile.build:275: recipe for target 'arch/x86/lib/interrupts.o' failed make[1]: *** [arch/x86/lib/interrupts.o] Error 1 Makefile:1093: recipe for target 'arch/x86/lib' failed make: *** [arch/x86/lib] Error 2 Change-Id: I3572a822081b72ab760f1eb99442e1161d3d167e Signed-off-by: Sebastien Ronsse Acked-by: Simon Glass --- arch/x86/lib/interrupts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86') diff --git a/arch/x86/lib/interrupts.c b/arch/x86/lib/interrupts.c index 6bb22d25e8..146ad11fb5 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, -- cgit From 566d1754d3a84819d9e2829421898d115ef2c116 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 22 Jan 2015 11:29:39 +0800 Subject: x86: Add missing DECLARE_GLOBAL_DATA_PTR for mtrr.c arch/x86/cpu/mtrr.c has access to the U-Boot global data thus DECLARE_GLOBAL_DATA_PTR is needed. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/mtrr.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/x86') diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c index d5a825d181..ac8765f3cf 100644 --- a/arch/x86/cpu/mtrr.c +++ b/arch/x86/cpu/mtrr.c @@ -17,6 +17,8 @@ #include #include +DECLARE_GLOBAL_DATA_PTR; + /* Prepare to adjust MTRRs */ void mtrr_open(struct mtrr_state *state) { -- cgit From 49491669065c1c718d8dc0b0ebc151b3d010c17b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 22 Jan 2015 11:29:40 +0800 Subject: x86: Save mtrr support flag in global data CPUID (EAX 01H) returns MTRR support flag in EDX bit 12. Probe this flag in x86_cpu_init_f() and save it in global data. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/cpu.c | 7 +++++++ arch/x86/include/asm/global_data.h | 13 +++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'arch/x86') diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 30e5069698..ed7905c1d7 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/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 24e305239b..243ed5c461 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,11 @@ 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; }; #endif -- cgit From 3b621ccabdccb34891bb58865a9654a09c2b7279 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 22 Jan 2015 11:29:41 +0800 Subject: x86: Test mtrr support flag before accessing mtrr msr On some x86 processors (like Intel Quark) the MTRR registers are not supported. This is reflected by the CPUID (EAX 01H) result EDX[12]. Accessing the MTRR registers on such processors will cause #GP so we must test the support flag before accessing MTRR MSRs. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/mtrr.c | 12 ++++++++++++ arch/x86/include/asm/mtrr.h | 5 ++++- arch/x86/lib/init_helpers.c | 4 +++- 3 files changed, 19 insertions(+), 2 deletions(-) (limited to 'arch/x86') diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c index ac8765f3cf..5d36b3e020 100644 --- a/arch/x86/cpu/mtrr.c +++ b/arch/x86/cpu/mtrr.c @@ -22,6 +22,9 @@ 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) @@ -33,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(); @@ -45,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); @@ -66,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/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index 3c1174043c..fda4eae10d 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/lib/init_helpers.c b/arch/x86/lib/init_helpers.c index fc211d9d5c..5097ca274a 100644 --- a/arch/x86/lib/init_helpers.c +++ b/arch/x86/lib/init_helpers.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -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) */ -- cgit From fea1c47f5481871f9aad70a02dc8c66b91332774 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 20 Jan 2015 11:25:44 +0800 Subject: x86: Fix various code format issues in start16.S Various minor code format issues are fixed in start16.S: - U-boot -> U-Boot - 32bit -> 32-bit - Use TAB instead of SPACE to indent - Move the indention location of the GDT comment block Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/start16.S | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'arch/x86') diff --git a/arch/x86/cpu/start16.S b/arch/x86/cpu/start16.S index 9550502e9a..826e2b4361 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, @@ -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 ... -- cgit From b18c68d8918095672b295aef7bfbfc466b82c710 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 19 Jan 2015 22:16:09 -0700 Subject: x86: Use ipchecksum from net/ The existing IP checksum function is only accessible to the 'coreboot' cpu. Drop it in favour of the new code in the network subsystem. Signed-off-by: Simon Glass --- arch/x86/cpu/coreboot/Makefile | 1 - arch/x86/cpu/coreboot/ipchecksum.c | 55 ------------------------- arch/x86/cpu/coreboot/tables.c | 8 ++-- arch/x86/include/asm/arch-coreboot/ipchecksum.h | 37 ----------------- 4 files changed, 4 insertions(+), 97 deletions(-) delete mode 100644 arch/x86/cpu/coreboot/ipchecksum.c delete mode 100644 arch/x86/include/asm/arch-coreboot/ipchecksum.h (limited to 'arch/x86') diff --git a/arch/x86/cpu/coreboot/Makefile b/arch/x86/cpu/coreboot/Makefile index 35e6cdd741..b6e870a7cb 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/ipchecksum.c b/arch/x86/cpu/coreboot/ipchecksum.c deleted file mode 100644 index 3340872a87..0000000000 --- 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 - * 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 -#include -#include - -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 92b75286b1..2b12b19ba2 100644 --- a/arch/x86/cpu/coreboot/tables.c +++ b/arch/x86/cpu/coreboot/tables.c @@ -8,7 +8,7 @@ */ #include -#include +#include #include #include @@ -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/include/asm/arch-coreboot/ipchecksum.h b/arch/x86/include/asm/arch-coreboot/ipchecksum.h deleted file mode 100644 index 1d73b4d912..0000000000 --- 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 - * 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 -- cgit From a9aff2f46a7f7d29a662531dbc181773f16a606d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 19 Jan 2015 22:16:13 -0700 Subject: x86: dts: Add SPI flash MRC details for chromebook_link Correct the SPI flash compatible string, add an alias and specify the position of the MRC cache, used to store SDRAM training settings for the Memory Reference Code. Signed-off-by: Simon Glass --- arch/x86/dts/chromebook_link.dts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'arch/x86') diff --git a/arch/x86/dts/chromebook_link.dts b/arch/x86/dts/chromebook_link.dts index 9490b169fb..45ada610b3 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]; + }; }; }; -- cgit From 191c008a2155f99fc6476539878640b4032a457b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 19 Jan 2015 22:16:14 -0700 Subject: x86: Implement a cache for Memory Reference Code parameters The memory reference code takes a very long time to 'train' its SDRAM interface, around half a second. To avoid this delay on every boot we can store the parameters from the last training sessions to speed up the next. Add an implementation of this, storing the training data in CMOS RAM and SPI flash. Signed-off-by: Simon Glass --- arch/x86/cpu/ivybridge/Makefile | 1 + arch/x86/cpu/ivybridge/mrccache.c | 156 +++++++++++++++ arch/x86/cpu/ivybridge/sdram.c | 253 +++++++++++++++++++++++++ arch/x86/include/asm/arch-ivybridge/mrccache.h | 51 +++++ arch/x86/include/asm/global_data.h | 3 + 5 files changed, 464 insertions(+) create mode 100644 arch/x86/cpu/ivybridge/mrccache.c create mode 100644 arch/x86/include/asm/arch-ivybridge/mrccache.h (limited to 'arch/x86') diff --git a/arch/x86/cpu/ivybridge/Makefile b/arch/x86/cpu/ivybridge/Makefile index 0c7efaec7c..3576b83266 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 0000000000..0f1a64b268 --- /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 +#include +#include +#include +#include +#include +#include +#include + +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 95047359ff..49634485f3 100644 --- a/arch/x86/cpu/ivybridge/sdram.c +++ b/arch/x86/cpu/ivybridge/sdram.c @@ -14,12 +14,17 @@ #include #include #include +#include +#include +#include +#include #include #include #include #include #include #include +#include #include #include #include @@ -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/include/asm/arch-ivybridge/mrccache.h b/arch/x86/include/asm/arch-ivybridge/mrccache.h new file mode 100644 index 0000000000..968b2eff9e --- /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 243ed5c461..5ee06eb70d 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -65,6 +65,9 @@ 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; }; #endif -- cgit From 069f5481ba19b819ef11ba23181a264fc566b180 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 19 Jan 2015 22:16:15 -0700 Subject: x86: config: Enable hook for saving MRC configuration Add a hook to ensure that this information is saved. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/coreboot/coreboot.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch/x86') diff --git a/arch/x86/cpu/coreboot/coreboot.c b/arch/x86/cpu/coreboot/coreboot.c index 6d06d5af19..4cdd0d4035 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; +} -- cgit From 380ab5cc27051781864dea1f895181026954ab58 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 19 Jan 2015 22:16:16 -0700 Subject: x86: ivybridge: Drop the Kconfig MRC cache information This is now stored in the device tree. Signed-off-by: Simon Glass --- arch/x86/cpu/ivybridge/Kconfig | 28 ---------------------------- 1 file changed, 28 deletions(-) (limited to 'arch/x86') diff --git a/arch/x86/cpu/ivybridge/Kconfig b/arch/x86/cpu/ivybridge/Kconfig index afca9579da..e4595be3ae 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 -- cgit