[U-Boot] [PATCH v2 0/11] Add support for caching Memory Reference Code data

Since the memory reference code is so slow on x86, add a feature to bypass this, storing the previous parameters in SPI flash. This saves around 500ms on each boot.
Also enable a SPI flash environment.
Changes in v2: - Use intel,ich-spi as the compatible string - Refactor IP checksum patches - Refactor IP checksum patches - Adjust the mc146818 driver instead of adding a new cmos.h header - Make changes to chromebook_link.dts since link.dts is gone - Use intel,ich-spi as the compatible string - Update for the new CMOS RAM access functions in the RTC - Add a comment about why both CMOS RAM and SPI flash are used for the cache
Simon Glass (11): x86: dts: Add compatible string for Intel ICH9 SPI controller x86: Move ipchecksum into common area and rename it x86: Allow adding of IP checksums x86: rtc: mc146818: Add helpers to read/write CMOS RAM x86: spi: Add device tree support Allow architecture-specific memory reservation x86: dts: Add SPI flash MRC details for chromebook_link x86: Implement a cache for Memory Reference Code parameters x86: config: Enable hook for saving MRC configuration x86: ivybridge: Drop the Kconfig MRC cache information x86: config: chromebook_link: Enable environment
arch/x86/cpu/Makefile | 1 + arch/x86/cpu/coreboot/Makefile | 1 - arch/x86/cpu/coreboot/ipchecksum.c | 55 ------ arch/x86/cpu/coreboot/tables.c | 8 +- arch/x86/cpu/ip_checksum.c | 55 ++++++ arch/x86/cpu/ivybridge/Kconfig | 28 --- arch/x86/cpu/ivybridge/Makefile | 1 + arch/x86/cpu/ivybridge/mrccache.c | 156 +++++++++++++++ arch/x86/cpu/ivybridge/sdram.c | 253 ++++++++++++++++++++++++ arch/x86/dts/chromebook_link.dts | 15 +- arch/x86/dts/link.dts | 229 +++++++++++++++++++++ arch/x86/include/asm/arch-coreboot/ipchecksum.h | 37 ---- arch/x86/include/asm/arch-ivybridge/mrccache.h | 51 +++++ arch/x86/include/asm/global_data.h | 3 + arch/x86/include/asm/ip_checksum.h | 16 ++ common/board_f.c | 7 + drivers/rtc/mc146818.c | 53 +++-- drivers/spi/ich.c | 7 + include/configs/chromebook_link.h | 8 + include/configs/x86-common.h | 1 + include/fdtdec.h | 1 + include/rtc.h | 32 +++ lib/fdtdec.c | 1 + 23 files changed, 879 insertions(+), 140 deletions(-) delete mode 100644 arch/x86/cpu/coreboot/ipchecksum.c create mode 100644 arch/x86/cpu/ip_checksum.c create mode 100644 arch/x86/cpu/ivybridge/mrccache.c create mode 100644 arch/x86/dts/link.dts delete mode 100644 arch/x86/include/asm/arch-coreboot/ipchecksum.h create mode 100644 arch/x86/include/asm/arch-ivybridge/mrccache.h create mode 100644 arch/x86/include/asm/ip_checksum.h

Add this to the enum so that we can use the various fdtdec functions. A later commit will move this driver to driver model.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Use intel,ich-spi as the compatible string
include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 2 files changed, 2 insertions(+)
diff --git a/include/fdtdec.h b/include/fdtdec.h index 4901c0d..de46562 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -172,6 +172,7 @@ enum fdt_compat_id { COMPAT_INTEL_MODEL_206AX, /* Intel Model 206AX CPU */ COMPAT_INTEL_GMA, /* Intel Graphics Media Accelerator */ COMPAT_AMS_AS3722, /* AMS AS3722 PMIC */ + COMPAT_INTEL_ICH_SPI, /* Intel ICH7/9 SPI controller */
COMPAT_COUNT, }; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 487122e..e989241 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -83,6 +83,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(INTEL_MODEL_206AX, "intel,model-206ax"), COMPAT(INTEL_GMA, "intel,gma"), COMPAT(AMS_AS3722, "ams,as3722"), + COMPAT(INTEL_ICH_SPI, "intel,ich-spi"), };
const char *fdtdec_get_compatible(enum fdt_compat_id id)

The existing IP checksum function is only accessible to the 'coreboot' cpu. Move it into the common area and rename it slightly to remove the abbreviations.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Refactor IP checksum patches
arch/x86/cpu/Makefile | 1 + arch/x86/cpu/coreboot/Makefile | 1 - arch/x86/cpu/coreboot/ipchecksum.c | 55 ------------------------- arch/x86/cpu/coreboot/tables.c | 8 ++-- arch/x86/cpu/ip_checksum.c | 34 +++++++++++++++ arch/x86/include/asm/arch-coreboot/ipchecksum.h | 37 ----------------- arch/x86/include/asm/ip_checksum.h | 16 +++++++ 7 files changed, 55 insertions(+), 97 deletions(-) delete mode 100644 arch/x86/cpu/coreboot/ipchecksum.c create mode 100644 arch/x86/cpu/ip_checksum.c delete mode 100644 arch/x86/include/asm/arch-coreboot/ipchecksum.h create mode 100644 arch/x86/include/asm/ip_checksum.h
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 62e43c0..eee2289 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SYS_COREBOOT) += coreboot/ obj-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += ivybridge/ obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/ obj-$(CONFIG_INTEL_QUEENSBAY) += queensbay/ +obj-y += ip_checksum.o obj-y += lapic.o obj-y += mtrr.o obj-$(CONFIG_PCI) += pci.o 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/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..662af95 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 <asm/ip_checksum.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 (compute_ip_checksum((u16 *)header, sizeof(*header)) != 0) return -1;
- if (ipchksum((u16 *) (ptr + sizeof(*header)), - header->table_bytes) != header->table_checksum) + if (compute_ip_checksum((u16 *)(ptr + sizeof(*header)), + header->table_bytes) != header->table_checksum) return -1;
/* Now, walk the tables. */ diff --git a/arch/x86/cpu/ip_checksum.c b/arch/x86/cpu/ip_checksum.c new file mode 100644 index 0000000..1b529da --- /dev/null +++ b/arch/x86/cpu/ip_checksum.c @@ -0,0 +1,34 @@ +/* + * This file was originally taken from the FreeBSD project. + * + * Copyright (c) 2001 Charles Mott cm@linktel.net + * Copyright (c) 2008 coresystems GmbH + * All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <linux/types.h> +#include <linux/compiler.h> +#include <asm/ip_checksum.h> + +unsigned short compute_ip_checksum(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/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/ip_checksum.h b/arch/x86/include/asm/ip_checksum.h new file mode 100644 index 0000000..8d9626d --- /dev/null +++ b/arch/x86/include/asm/ip_checksum.h @@ -0,0 +1,16 @@ +/* + * From Coreboot ip_checksum.h + * + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _IP_CHECKSUM_H +#define _IP_CHECKSUM_H + +unsigned short compute_ip_checksum(const void *addr, unsigned long length); +unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, + unsigned long new); + +#endif /* IP_CHECKSUM_H */

Hi Simon,
On Fri, Jan 9, 2015 at 11:30 AM, Simon Glass sjg@chromium.org wrote:
The existing IP checksum function is only accessible to the 'coreboot' cpu. Move it into the common area and rename it slightly to remove the abbreviations.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Refactor IP checksum patches
arch/x86/cpu/Makefile | 1 + arch/x86/cpu/coreboot/Makefile | 1 - arch/x86/cpu/coreboot/ipchecksum.c | 55 ------------------------- arch/x86/cpu/coreboot/tables.c | 8 ++-- arch/x86/cpu/ip_checksum.c | 34 +++++++++++++++
What about the namings we discussed in the v1 patch thread? ip_xxx indicates ip protocol, but acutally they are not.
[snip]
Regards, Bin

Hi Bin,
On 10 January 2015 at 08:47, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Jan 9, 2015 at 11:30 AM, Simon Glass sjg@chromium.org wrote:
The existing IP checksum function is only accessible to the 'coreboot' cpu. Move it into the common area and rename it slightly to remove the abbreviations.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Refactor IP checksum patches
arch/x86/cpu/Makefile | 1 + arch/x86/cpu/coreboot/Makefile | 1 - arch/x86/cpu/coreboot/ipchecksum.c | 55 ------------------------- arch/x86/cpu/coreboot/tables.c | 8 ++-- arch/x86/cpu/ip_checksum.c | 34 +++++++++++++++
What about the namings we discussed in the v1 patch thread? ip_xxx indicates ip protocol, but acutally they are not.
Is it not? This is not actually CMOS-specific - e.g. it is used by Coreboot to send data through to U-Boot in the tables it provides.
I thought it was an IP checksum...
Regards, Simon

Hi Simon,
On Sun, Jan 11, 2015 at 1:20 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 10 January 2015 at 08:47, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Jan 9, 2015 at 11:30 AM, Simon Glass sjg@chromium.org wrote:
The existing IP checksum function is only accessible to the 'coreboot' cpu. Move it into the common area and rename it slightly to remove the abbreviations.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Refactor IP checksum patches
arch/x86/cpu/Makefile | 1 + arch/x86/cpu/coreboot/Makefile | 1 - arch/x86/cpu/coreboot/ipchecksum.c | 55 ------------------------- arch/x86/cpu/coreboot/tables.c | 8 ++-- arch/x86/cpu/ip_checksum.c | 34 +++++++++++++++
What about the namings we discussed in the v1 patch thread? ip_xxx indicates ip protocol, but acutally they are not.
Is it not? This is not actually CMOS-specific - e.g. it is used by Coreboot to send data through to U-Boot in the tables it provides.
I thought it was an IP checksum...
OK, so you mean coreboot is using the same IP checksum algorithm to generate checksums for coreboot tables to be passed to U-Boot. If that is the case, I think we should put the these files to u-boot/net or u-boot/lib. Are there existing codes that we can reuse?
Regards, Bin

Hi Bin,
On 10 January 2015 at 19:44, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sun, Jan 11, 2015 at 1:20 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 10 January 2015 at 08:47, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Jan 9, 2015 at 11:30 AM, Simon Glass sjg@chromium.org wrote:
The existing IP checksum function is only accessible to the 'coreboot' cpu. Move it into the common area and rename it slightly to remove the abbreviations.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Refactor IP checksum patches
arch/x86/cpu/Makefile | 1 + arch/x86/cpu/coreboot/Makefile | 1 - arch/x86/cpu/coreboot/ipchecksum.c | 55 ------------------------- arch/x86/cpu/coreboot/tables.c | 8 ++-- arch/x86/cpu/ip_checksum.c | 34 +++++++++++++++
What about the namings we discussed in the v1 patch thread? ip_xxx indicates ip protocol, but acutally they are not.
Is it not? This is not actually CMOS-specific - e.g. it is used by Coreboot to send data through to U-Boot in the tables it provides.
I thought it was an IP checksum...
OK, so you mean coreboot is using the same IP checksum algorithm to generate checksums for coreboot tables to be passed to U-Boot. If that is the case, I think we should put the these files to u-boot/net or u-boot/lib. Are there existing codes that we can reuse?
NetCkSum() is similar but does not need to worry about an odd length. So I doubt I can use that.
Regards, Simon

Hi Simon,
On Sun, Jan 11, 2015 at 11:33 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 10 January 2015 at 19:44, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sun, Jan 11, 2015 at 1:20 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 10 January 2015 at 08:47, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Jan 9, 2015 at 11:30 AM, Simon Glass sjg@chromium.org wrote:
The existing IP checksum function is only accessible to the 'coreboot' cpu. Move it into the common area and rename it slightly to remove the abbreviations.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Refactor IP checksum patches
arch/x86/cpu/Makefile | 1 + arch/x86/cpu/coreboot/Makefile | 1 - arch/x86/cpu/coreboot/ipchecksum.c | 55 ------------------------- arch/x86/cpu/coreboot/tables.c | 8 ++-- arch/x86/cpu/ip_checksum.c | 34 +++++++++++++++
What about the namings we discussed in the v1 patch thread? ip_xxx indicates ip protocol, but acutally they are not.
Is it not? This is not actually CMOS-specific - e.g. it is used by Coreboot to send data through to U-Boot in the tables it provides.
I thought it was an IP checksum...
OK, so you mean coreboot is using the same IP checksum algorithm to generate checksums for coreboot tables to be passed to U-Boot. If that is the case, I think we should put the these files to u-boot/net or u-boot/lib. Are there existing codes that we can reuse?
NetCkSum() is similar but does not need to worry about an odd length. So I doubt I can use that.
But would you consider moving it to some another place more suitable than arch/x86/cpu/? I feel that it is IP related stuff and it may make people confused when seeing it in arch/x86 directory. If we move it to u-boot/net, maybe you can replace NetCkSum() with the one we have here since it can deal with odd length.
Regards, Bin

Hi Bin,
On 10 January 2015 at 20:04, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sun, Jan 11, 2015 at 11:33 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 10 January 2015 at 19:44, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sun, Jan 11, 2015 at 1:20 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 10 January 2015 at 08:47, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Jan 9, 2015 at 11:30 AM, Simon Glass sjg@chromium.org wrote:
The existing IP checksum function is only accessible to the 'coreboot' cpu. Move it into the common area and rename it slightly to remove the abbreviations.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Refactor IP checksum patches
arch/x86/cpu/Makefile | 1 + arch/x86/cpu/coreboot/Makefile | 1 - arch/x86/cpu/coreboot/ipchecksum.c | 55 ------------------------- arch/x86/cpu/coreboot/tables.c | 8 ++-- arch/x86/cpu/ip_checksum.c | 34 +++++++++++++++
What about the namings we discussed in the v1 patch thread? ip_xxx indicates ip protocol, but acutally they are not.
Is it not? This is not actually CMOS-specific - e.g. it is used by Coreboot to send data through to U-Boot in the tables it provides.
I thought it was an IP checksum...
OK, so you mean coreboot is using the same IP checksum algorithm to generate checksums for coreboot tables to be passed to U-Boot. If that is the case, I think we should put the these files to u-boot/net or u-boot/lib. Are there existing codes that we can reuse?
NetCkSum() is similar but does not need to worry about an odd length. So I doubt I can use that.
But would you consider moving it to some another place more suitable than arch/x86/cpu/? I feel that it is IP related stuff and it may make people confused when seeing it in arch/x86 directory. If we move it to u-boot/net, maybe you can replace NetCkSum() with the one we have here since it can deal with odd length.
I suspect it might be confusing in any case. But I think we can move this file to net/ - at least I don't see any big problems. I wonder whether people might complain about changing the existing NetChkSum() function, but we will see.
Regards, Simon

Add a function to add IP checksums.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Refactor IP checksum patches
arch/x86/cpu/ip_checksum.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
diff --git a/arch/x86/cpu/ip_checksum.c b/arch/x86/cpu/ip_checksum.c index 1b529da..ddfc0d7 100644 --- a/arch/x86/cpu/ip_checksum.c +++ b/arch/x86/cpu/ip_checksum.c @@ -32,3 +32,24 @@ unsigned short compute_ip_checksum(const void *vptr, unsigned long nbytes) sum += (sum >> 16); return ~sum; } + +unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, + unsigned long new) +{ + unsigned long checksum; + + sum = ~sum & 0xffff; + new = ~new & 0xffff; + if (offset & 1) { + /* + * byte-swap the sum if it came from an odd offset; since the + * computation is endian independant this works. + */ + new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00); + } + checksum = sum + new; + if (checksum > 0xffff) + checksum -= 0xffff; + + return (~checksum) & 0xffff; +}

On x86 we use CMOS RAM to read and write some settings. Add basic support for this, including access to registers 128-255.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Adjust the mc146818 driver instead of adding a new cmos.h header
drivers/rtc/mc146818.c | 53 +++++++++++++++++++++++++++++++++++++------------- include/rtc.h | 32 ++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 14 deletions(-)
diff --git a/drivers/rtc/mc146818.c b/drivers/rtc/mc146818.c index 39e6041..b506b16 100644 --- a/drivers/rtc/mc146818.c +++ b/drivers/rtc/mc146818.c @@ -27,9 +27,6 @@ /* Set this to 1 to clear the CMOS RAM */ #define CLEAR_CMOS 0
-static uchar rtc_read (uchar reg); -static void rtc_write (uchar reg, uchar val); - #define RTC_PORT_MC146818 CONFIG_SYS_ISA_IO_BASE_ADDRESS + 0x70 #define RTC_SECONDS 0x00 #define RTC_SECONDS_ALARM 0x01 @@ -133,32 +130,60 @@ void rtc_reset (void)
/* ------------------------------------------------------------------------- */
-#ifdef CONFIG_SYS_RTC_REG_BASE_ADDR /* * use direct memory access */ -static uchar rtc_read (uchar reg) +int rtc_read(int reg) { +#ifdef CONFIG_SYS_RTC_REG_BASE_ADDR return in8(CONFIG_SYS_RTC_REG_BASE_ADDR + reg); +#else + int ofs = 0; + + if (reg >= 128) { + ofs = 2; + reg -= 128; + } + out8(RTC_PORT_MC146818 + ofs, reg); + + return in8(RTC_PORT_MC146818 + ofs + 1); +#endif }
-static void rtc_write (uchar reg, uchar val) +void rtc_write(int reg, uchar val) { +#ifdef CONFIG_SYS_RTC_REG_BASE_ADDR out8(CONFIG_SYS_RTC_REG_BASE_ADDR + reg, val); -} #else -static uchar rtc_read (uchar reg) + int ofs = 0; + + if (reg >= 128) { + ofs = 2; + reg -= 128; + } + out8(RTC_PORT_MC146818 + ofs, reg); + out8(RTC_PORT_MC146818 + ofs + 1, val); +#endif +} + +u32 rtc_read32(int reg) { - out8(RTC_PORT_MC146818,reg); - return in8(RTC_PORT_MC146818 + 1); + u32 value = 0; + int i; + + for (i = 0; i < sizeof(value); i++) + value |= rtc_read(reg + i) << (i << 3); + + return value; }
-static void rtc_write (uchar reg, uchar val) +void rtc_write32(int reg, u32 value) { - out8(RTC_PORT_MC146818,reg); - out8(RTC_PORT_MC146818+1, val); + int i; + + for (i = 0; i < sizeof(value); i++) + rtc_write(reg + i, (value >> (i << 3)) & 0xff); } -#endif
void rtc_init(void) { diff --git a/include/rtc.h b/include/rtc.h index d11aa8b..b6df1f4 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -51,6 +51,38 @@ unsigned long mktime (unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int);
/** + * rtc_read() - Read an 8-bit register + * + * @reg: Register to read + * @return value read + */ +int rtc_read(int reg); + +/** + * rtc_write() - Write an 8-bit register + * + * @reg: Register to write + * @value: Value to write + */ +void rtc_write(int reg, uchar val); + +/** + * rtc_read32() - Read a 32-bit value from the RTC + * + * @reg: Offset to start reading from + * @return value read + */ +u32 rtc_read32(int reg); + +/** + * rtc_write32() - Write a 32-bit value to the RTC + * + * @reg: Register to start writing to + * @value: Value to write + */ +void rtc_write32(int reg, u32 value); + +/** * rtc_init() - Set up the real time clock ready for use */ void rtc_init(void);

As a temporary measure before the ICH driver moves over to driver model, add device tree support to the driver.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
drivers/spi/ich.c | 7 +++++++ include/configs/x86-common.h | 1 + 2 files changed, 8 insertions(+)
diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index 0379444..fdff158 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -153,6 +153,13 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, return &ich->slave; }
+struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node, + int spi_node) +{ + /* We only support a single SPI at present */ + return spi_setup_slave(0, 0, 20000000, 0); +} + void spi_free_slave(struct spi_slave *slave) { struct ich_spi_slave *ich = to_ich_spi(slave); diff --git a/include/configs/x86-common.h b/include/configs/x86-common.h index 4f0a3c5..ecedfc3 100644 --- a/include/configs/x86-common.h +++ b/include/configs/x86-common.h @@ -211,6 +211,7 @@ #define CONFIG_CMD_SF_TEST #define CONFIG_CMD_SPI #define CONFIG_SPI +#define CONFIG_OF_SPI_FLASH
/*----------------------------------------------------------------------- * Environment configuration

All memory to be reserved for use after relocation by adding a new call to perform this reservation.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
common/board_f.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/common/board_f.c b/common/board_f.c index 3a4b32c..215108b 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -807,6 +807,12 @@ static int initf_dm(void) return 0; }
+/* Architecture-specific memory reservation */ +__weak int reserve_arch(void) +{ + return 0; +} + static init_fnc_t init_sequence_f[] = { #ifdef CONFIG_SANDBOX setup_ram_buf, @@ -970,6 +976,7 @@ static init_fnc_t init_sequence_f[] = { setup_machine, reserve_global_data, reserve_fdt, + reserve_arch, reserve_stacks, setup_dram_config, show_dram_config,

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 sjg@chromium.org ---
Changes in v2: - Make changes to chromebook_link.dts since link.dts is gone - Use intel,ich-spi as the compatible string
arch/x86/dts/chromebook_link.dts | 15 ++- arch/x86/dts/link.dts | 229 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 arch/x86/dts/link.dts
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/dts/link.dts b/arch/x86/dts/link.dts new file mode 100644 index 0000000..52d8b60 --- /dev/null +++ b/arch/x86/dts/link.dts @@ -0,0 +1,229 @@ +/dts-v1/; + +/include/ "skeleton.dtsi" +/include/ "serial.dtsi" + +/ { + model = "Google Link"; + compatible = "google,link", "intel,celeron-ivybridge"; + + aliases { + spi0 = "/spi"; + }; + + config { + silent_console = <0>; + }; + + gpioa { + compatible = "intel,ich6-gpio"; + u-boot,dm-pre-reloc; + reg = <0 0x10>; + bank-name = "A"; + }; + + gpiob { + compatible = "intel,ich6-gpio"; + u-boot,dm-pre-reloc; + reg = <0x30 0x10>; + bank-name = "B"; + }; + + gpioc { + compatible = "intel,ich6-gpio"; + u-boot,dm-pre-reloc; + reg = <0x40 0x10>; + bank-name = "C"; + }; + + chosen { + stdout-path = "/serial"; + }; + + spd { + compatible = "memory-spd"; + #address-cells = <1>; + #size-cells = <0>; + elpida_4Gb_1600_x16 { + reg = <0>; + data = [92 10 0b 03 04 19 02 02 + 03 52 01 08 0a 00 fe 00 + 69 78 69 3c 69 11 18 81 + 20 08 3c 3c 01 40 83 81 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 0f 11 42 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 02 fe 00 + 11 52 00 00 00 07 7f 37 + 45 42 4a 32 30 55 47 36 + 45 42 55 30 2d 47 4e 2d + 46 20 30 20 02 fe 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00]; + }; + samsung_4Gb_1600_1.35v_x16 { + reg = <1>; + data = [92 11 0b 03 04 19 02 02 + 03 11 01 08 0a 00 fe 00 + 69 78 69 3c 69 11 18 81 + f0 0a 3c 3c 01 40 83 01 + 00 80 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 0f 11 02 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 80 ce 01 + 00 00 00 00 00 00 6a 04 + 4d 34 37 31 42 35 36 37 + 34 42 48 30 2d 59 4b 30 + 20 20 00 00 80 ce 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00]; + }; + micron_4Gb_1600_1.35v_x16 { + reg = <2>; + data = [92 11 0b 03 04 19 02 02 + 03 11 01 08 0a 00 fe 00 + 69 78 69 3c 69 11 18 81 + 20 08 3c 3c 01 40 83 05 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 0f 01 02 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 80 2c 00 + 00 00 00 00 00 00 ad 75 + 34 4b 54 46 32 35 36 36 + 34 48 5a 2d 31 47 36 45 + 31 20 45 31 80 2c 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff]; + }; + }; + + spi { + #address-cells = <1>; + #size-cells = <0>; + compatible = "intel,ich9-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]; + }; + }; + }; + + pci { + sata { + compatible = "intel,pantherpoint-ahci"; + intel,sata-mode = "ahci"; + intel,sata-port-map = <1>; + intel,sata-port0-gen3-tx = <0x00880a7f>; + }; + + gma { + compatible = "intel,gma"; + intel,dp_hotplug = <0 0 0x06>; + intel,panel-port-select = <1>; + intel,panel-power-cycle-delay = <6>; + intel,panel-power-up-delay = <2000>; + intel,panel-power-down-delay = <500>; + intel,panel-power-backlight-on-delay = <2000>; + intel,panel-power-backlight-off-delay = <2000>; + intel,cpu-backlight = <0x00000200>; + intel,pch-backlight = <0x04000000>; + }; + + lpc { + compatible = "intel,lpc"; + #address-cells = <1>; + #size-cells = <1>; + gen-dec = <0x800 0xfc 0x900 0xfc>; + intel,gen-dec = <0x800 0xfc 0x900 0xfc>; + intel,pirq-routing = <0x8b 0x8a 0x8b 0x8b + 0x80 0x80 0x80 0x80>; + intel,gpi-routing = <0 0 0 0 0 0 0 2 + 1 0 0 0 0 0 0 0>; + /* Enable EC SMI source */ + intel,alt-gp-smi-enable = <0x0100>; + + cros-ec@200 { + compatible = "google,cros-ec"; + reg = <0x204 1 0x200 1 0x880 0x80>; + + /* Describes the flash memory within the EC */ + #address-cells = <1>; + #size-cells = <1>; + flash@8000000 { + reg = <0x08000000 0x20000>; + erase-value = <0xff>; + }; + }; + }; + }; + + microcode { + update@0 { +#include "microcode/m12306a9_0000001b.dtsi" + }; + }; + +};

Hi Simon,
On Fri, Jan 9, 2015 at 11:30 AM, Simon Glass sjg@chromium.org wrote:
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 sjg@chromium.org
Changes in v2:
- Make changes to chromebook_link.dts since link.dts is gone
- Use intel,ich-spi as the compatible string
arch/x86/dts/chromebook_link.dts | 15 ++- arch/x86/dts/link.dts | 229 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 arch/x86/dts/link.dts
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/dts/link.dts b/arch/x86/dts/link.dts new file mode 100644
Looks that you created link.dts again? Guess you may not rebase to u-boot-x86/next branch correctly?
[snip]
Regards, Bin

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 sjg@chromium.org ---
Changes in v2: - Update for the new CMOS RAM access functions in the RTC - Add a comment about why both CMOS RAM and SPI flash are used for the cache
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
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..182c995 --- /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 <spi.h> +#include <spi_flash.h> +#include <asm/ip_checksum.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..c1da20a 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 <rtc.h> +#include <spi.h> +#include <spi_flash.h> +#include <asm/ip_checksum.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_read(CMOS_OFFSET_MRC_SEED_CHK); + seed_checksum |= rtc_read(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_write(CMOS_OFFSET_MRC_SEED_CHK, checksum & 0xff); + rtc_write(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 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..7d76f4a 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -64,6 +64,9 @@ struct arch_global_data { #endif struct mtrr_request mtrr_req[MAX_MTRR_REQUESTS]; int mtrr_req_count; + /* MRC training data to save for the next boot */ + char *mrc_output; + unsigned int mrc_output_len; };
#endif

Add a hook to ensure that this information is saved.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
include/configs/chromebook_link.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/configs/chromebook_link.h b/include/configs/chromebook_link.h index 7e6d239..6e8b9ef 100644 --- a/include/configs/chromebook_link.h +++ b/include/configs/chromebook_link.h @@ -20,6 +20,7 @@
#define CONFIG_DCACHE_RAM_MRC_VAR_SIZE 0x4000 #define CONFIG_BOARD_EARLY_INIT_F +#define CONFIG_MISC_INIT_R
#define CONFIG_NR_DRAM_BANKS 8 #define CONFIG_X86_MRC_ADDR 0xfffa0000

This is now stored in the device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
arch/x86/cpu/ivybridge/Kconfig | 28 ---------------------------- 1 file changed, 28 deletions(-)
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

Enable an environment area.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
include/configs/chromebook_link.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/include/configs/chromebook_link.h b/include/configs/chromebook_link.h index 6e8b9ef..7b460e8 100644 --- a/include/configs/chromebook_link.h +++ b/include/configs/chromebook_link.h @@ -64,6 +64,13 @@ #define CONFIG_CMD_CROS_EC #define CONFIG_ARCH_EARLY_INIT_R
+#undef CONFIG_ENV_IS_NOWHERE +#undef CONFIG_ENV_SIZE +#define CONFIG_ENV_SIZE 0x1000 +#define CONFIG_ENV_SECT_SIZE 0x1000 +#define CONFIG_ENV_IS_IN_SPI_FLASH +#define CONFIG_ENV_OFFSET 0x003f8000 + #define CONFIG_STD_DEVICES_SETTINGS "stdin=usbkbd,vga,serial\0" \ "stdout=vga,serial\0" \ "stderr=vga,serial\0"

On Fri, Jan 9, 2015 at 11:30 AM, Simon Glass sjg@chromium.org wrote:
Enable an environment area.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
include/configs/chromebook_link.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/include/configs/chromebook_link.h b/include/configs/chromebook_link.h index 6e8b9ef..7b460e8 100644 --- a/include/configs/chromebook_link.h +++ b/include/configs/chromebook_link.h @@ -64,6 +64,13 @@ #define CONFIG_CMD_CROS_EC #define CONFIG_ARCH_EARLY_INIT_R
+#undef CONFIG_ENV_IS_NOWHERE +#undef CONFIG_ENV_SIZE +#define CONFIG_ENV_SIZE 0x1000 +#define CONFIG_ENV_SECT_SIZE 0x1000 +#define CONFIG_ENV_IS_IN_SPI_FLASH +#define CONFIG_ENV_OFFSET 0x003f8000
#define CONFIG_STD_DEVICES_SETTINGS "stdin=usbkbd,vga,serial\0" \ "stdout=vga,serial\0" \ "stderr=vga,serial\0" --
Reviewed-by: Bin Meng bmeng.cn@gmail.com
participants (2)
-
Bin Meng
-
Simon Glass