[U-Boot] [PATCH 39/39] x86: ivybridge: Implement SDRAM init
Bin Meng
bmeng.cn at gmail.com
Mon Nov 10 05:44:04 CET 2014
Hi Simon,
On Fri, Nov 7, 2014 at 4:20 AM, Simon Glass <sjg at chromium.org> wrote:
> Implement SDRAM init using the Memory Reference Code (mrc.bin) provided in
> the board directory and the SDRAM SPD information in the device tree. This
> also needs the Intel Management Engine (me.bin) to work. Binary blobs
> everywhere: so far we have MRC, ME and microcode.
>
> SDRAM init works by setting up various parameters and calling the MRC. This
> in turn does some sort of magic to work out how much memory there is and
> the timing parameters to use. It also sets up the DRAM controllers. When
> the MRC returns, we use the information it provides to map out the
> available memory in U-Boot.
>
> U-Boot normally moves itself to the top of RAM. On x86 the RAM is not
> generally contiguous, and anyway some RAM may be above 4GB which doesn't
> work in 32-bit mode. So we relocate to the top of the largest block of
> RAM we can find below 4GB. Memory above 4GB is accessible with special
> functions (see physmem).
>
> It would be possible to build U-Boot in 64-bit mode but this wouldn't
> necessarily provide any more memory, since the largest block is often below
> 4GB. Anyway U-Boot doesn't need huge amounts of memory - even a very large
> ramdisk seldom exceeds 100-200MB. U-Boot has support for booting 64-bit
> kernels directly so this does not pose a limitation in that area. Also there
> are probably parts of U-Boot that will not work correctly in 64-bit mode.
> The MRC is one.
>
> There is some work remaining in this area. Since memory init is very slow
> (over 500ms) it is possible to save the parameters in SPI flash to speed it
> up next time. Suspend/resume support is not fully implemented, or at least
> it is not efficient.
>
> With this patch, link boots to a prompt.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
>
> Makefile | 5 +
> arch/x86/Kconfig | 11 +
> arch/x86/cpu/ivybridge/Makefile | 3 +
> arch/x86/cpu/ivybridge/early_me.c | 191 ++++++++
> arch/x86/cpu/ivybridge/me_status.c | 195 ++++++++
> arch/x86/cpu/ivybridge/report_platform.c | 98 ++++
> arch/x86/cpu/ivybridge/sdram.c | 553 +++++++++++++++++++++-
> arch/x86/cpu/start.S | 10 +-
> arch/x86/dts/link.dts | 111 +++++
> arch/x86/include/asm/arch-ivybridge/me.h | 357 ++++++++++++++
> arch/x86/include/asm/arch-ivybridge/pch.h | 113 +++++
> arch/x86/include/asm/arch-ivybridge/pei_data.h | 121 +++++
> arch/x86/include/asm/arch-ivybridge/sandybridge.h | 2 +
> arch/x86/include/asm/config.h | 1 +
> arch/x86/include/asm/global_data.h | 13 +
> arch/x86/include/asm/post.h | 5 +
> arch/x86/include/asm/u-boot-x86.h | 2 +
> arch/x86/lib/Makefile | 1 +
> arch/x86/lib/ramtest.c | 79 ++++
> include/configs/chromebook_link.h | 5 +
> include/configs/x86-common.h | 2 +-
> include/fdtdec.h | 1 +
> lib/fdtdec.c | 1 +
> 23 files changed, 1874 insertions(+), 6 deletions(-)
> create mode 100644 arch/x86/cpu/ivybridge/early_me.c
> create mode 100644 arch/x86/cpu/ivybridge/me_status.c
> create mode 100644 arch/x86/cpu/ivybridge/report_platform.c
> create mode 100644 arch/x86/include/asm/arch-ivybridge/me.h
> create mode 100644 arch/x86/include/asm/arch-ivybridge/pei_data.h
> create mode 100644 arch/x86/lib/ramtest.c
>
> diff --git a/Makefile b/Makefile
> index 86d0510..4f0260f 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -956,9 +956,14 @@ u-boot.rom: u-boot-x86-16bit.bin u-boot-dtb.bin \
> $(srctree)/board/$(BOARDDIR)/descriptor.bin
> $(objtree)/tools/ifdtool -c -r $(CONFIG_ROM_SIZE) \
> -D $(srctree)/board/$(BOARDDIR)/descriptor.bin u-boot.tmp
> + $(objtree)/tools/ifdtool \
> + -i ME:$(srctree)/board/$(BOARDDIR)/me.bin u-boot.tmp
> $(objtree)/tools/ifdtool -w \
> $(CONFIG_SYS_TEXT_BASE):$(objtree)/u-boot-dtb.bin u-boot.tmp
> $(objtree)/tools/ifdtool -w \
> + $(CONFIG_X86_MRC_START):$(srctree)/board/$(BOARDDIR)/mrc.bin \
> + u-boot.tmp
> + $(objtree)/tools/ifdtool -w \
> $(CONFIG_SYS_X86_START16):$(objtree)/u-boot-x86-16bit.bin \
> u-boot.tmp
> mv u-boot.tmp $@
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 73fe8b2..e992610 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -50,6 +50,17 @@ config CPU_ADDR_BITS
> int
> default 36
>
> +config HPET_ADDRESS
> + hex
> + default 0xfed00000 if !HPET_ADDRESS_OVERRIDE
> +
> +config SMM_TSEG
> + bool
> + default n
> +
> +config SMM_TSEG_SIZE
> + hex
> +
> config ROM_SIZE
> hex
> default 0x800000
> diff --git a/arch/x86/cpu/ivybridge/Makefile b/arch/x86/cpu/ivybridge/Makefile
> index 4bfb03a..6669a6f 100644
> --- a/arch/x86/cpu/ivybridge/Makefile
> +++ b/arch/x86/cpu/ivybridge/Makefile
> @@ -7,6 +7,9 @@
> obj-y += car.o
> obj-y += cpu.o
> obj-y += early_init.o
> +obj-y += early_me.o
> obj-y += lpc.o
> +obj-y += me_status.o
> +obj-y += report_platform.o
> obj-y += microcode_intel.o
> obj-y += sdram.o
> diff --git a/arch/x86/cpu/ivybridge/early_me.c b/arch/x86/cpu/ivybridge/early_me.c
> new file mode 100644
> index 0000000..5528a9a
> --- /dev/null
> +++ b/arch/x86/cpu/ivybridge/early_me.c
> @@ -0,0 +1,191 @@
> +/*
> + * From Coreboot src/southbridge/intel/bd82x6x/early_me.c
> + *
> + * Copyright (C) 2011 The Chromium OS Authors. All rights reserved.
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> +
> +#include <common.h>
> +#include <errno.h>
> +#include <asm/pci.h>
> +#include <asm/processor.h>
> +#include <asm/arch/me.h>
> +#include <asm/arch/pch.h>
> +#include <asm/io.h>
> +
> +static const char *const me_ack_values[] = {
> + [ME_HFS_ACK_NO_DID] = "No DID Ack received",
> + [ME_HFS_ACK_RESET] = "Non-power cycle reset",
> + [ME_HFS_ACK_PWR_CYCLE] = "Power cycle reset",
> + [ME_HFS_ACK_S3] = "Go to S3",
> + [ME_HFS_ACK_S4] = "Go to S4",
> + [ME_HFS_ACK_S5] = "Go to S5",
> + [ME_HFS_ACK_GBL_RESET] = "Global Reset",
> + [ME_HFS_ACK_CONTINUE] = "Continue to boot"
> +};
> +
> +static inline void pci_read_dword_ptr(void *ptr, int offset)
> +{
> + u32 dword;
> +
> + dword = pci_read_config32(PCH_ME_DEV, offset);
> + memcpy(ptr, &dword, sizeof(dword));
> +}
> +
> +static inline void pci_write_dword_ptr(void *ptr, int offset)
> +{
> + u32 dword = 0;
> + memcpy(&dword, ptr, sizeof(dword));
> + pci_write_config32(PCH_ME_DEV, offset, dword);
> +}
> +
> +void intel_early_me_status(void)
> +{
> + struct me_hfs hfs;
> + struct me_gmes gmes;
> +
> + pci_read_dword_ptr(&hfs, PCI_ME_HFS);
> + pci_read_dword_ptr(&gmes, PCI_ME_GMES);
> +
> + intel_me_status(&hfs, &gmes);
> +}
> +
> +int intel_early_me_init(void)
> +{
> + int count;
> + struct me_uma uma;
> + struct me_hfs hfs;
> +
> + debug("Intel ME early init\n");
> +
> + /* Wait for ME UMA SIZE VALID bit to be set */
> + for (count = ME_RETRY; count > 0; --count) {
> + pci_read_dword_ptr(&uma, PCI_ME_UMA);
> + if (uma.valid)
> + break;
> + udelay(ME_DELAY);
> + }
> + if (!count) {
> + printf("ERROR: ME is not ready!\n");
> + return -EBUSY;
> + }
> +
> + /* Check for valid firmware */
> + pci_read_dword_ptr(&hfs, PCI_ME_HFS);
> + if (hfs.fpt_bad) {
> + printf("WARNING: ME has bad firmware\n");
> + return -EBADF;
> + }
> +
> + debug("Intel ME firmware is ready\n");
> +
> + return 0;
> +}
> +
> +int intel_early_me_uma_size(void)
> +{
> + struct me_uma uma;
> +
> + pci_read_dword_ptr(&uma, PCI_ME_UMA);
> + if (uma.valid) {
> + debug("ME: Requested %uMB UMA\n", uma.size);
> + return uma.size;
> + }
> +
> + debug("ME: Invalid UMA size\n");
> + return -EINVAL;
> +}
> +
> +static inline void set_global_reset(int enable)
> +{
> + u32 etr3;
> +
> + etr3 = pci_read_config32(PCH_LPC_DEV, ETR3);
> +
> + /* Clear CF9 Without Resume Well Reset Enable */
> + etr3 &= ~ETR3_CWORWRE;
> +
> + /* CF9GR indicates a Global Reset */
> + if (enable)
> + etr3 |= ETR3_CF9GR;
> + else
> + etr3 &= ~ETR3_CF9GR;
> +
> + pci_write_config32(PCH_LPC_DEV, ETR3, etr3);
> +}
> +
> +int intel_early_me_init_done(u8 status)
> +{
> + u8 reset;
> + int count;
> + u32 mebase_l, mebase_h;
> + struct me_hfs hfs;
> + struct me_did did = {
> + .init_done = ME_INIT_DONE,
> + .status = status
> + };
> +
> + /* MEBASE from MESEG_BASE[35:20] */
> + mebase_l = pci_read_config32(PCI_CPU_DEVICE, PCI_CPU_MEBASE_L);
> + mebase_h = pci_read_config32(PCI_CPU_DEVICE, PCI_CPU_MEBASE_H);
> + mebase_h &= 0xf;
> + did.uma_base = (mebase_l >> 20) | (mebase_h << 12);
> +
> + /* Send message to ME */
> + debug("ME: Sending Init Done with status: %d, UMA base: 0x%04x\n",
> + status, did.uma_base);
> +
> + pci_write_dword_ptr(&did, PCI_ME_H_GS);
> +
> + /* Must wait for ME acknowledgement */
> + for (count = ME_RETRY; count > 0; --count) {
> + pci_read_dword_ptr(&hfs, PCI_ME_HFS);
> + if (hfs.bios_msg_ack)
> + break;
> + udelay(ME_DELAY);
> + }
> + if (!count) {
> + printf("ERROR: ME failed to respond\n");
> + return -1;
> + }
> +
> + /* Return the requested BIOS action */
> + debug("ME: Requested BIOS Action: %s\n", me_ack_values[hfs.ack_data]);
> +
> + /* Check status after acknowledgement */
> + intel_early_me_status();
> +
> + reset = 0;
> + switch (hfs.ack_data) {
> + case ME_HFS_ACK_CONTINUE:
> + /* Continue to boot */
> + return 0;
> + case ME_HFS_ACK_RESET:
> + /* Non-power cycle reset */
> + set_global_reset(0);
> + reset = 0x06;
> + break;
> + case ME_HFS_ACK_PWR_CYCLE:
> + /* Power cycle reset */
> + set_global_reset(0);
> + reset = 0x0e;
> + break;
> + case ME_HFS_ACK_GBL_RESET:
> + /* Global reset */
> + set_global_reset(1);
> + reset = 0x0e;
> + break;
> + case ME_HFS_ACK_S3:
> + case ME_HFS_ACK_S4:
> + case ME_HFS_ACK_S5:
> + break;
> + }
> +
> + /* Perform the requested reset */
> + if (reset) {
> + outb(reset, 0xcf9);
> + cpu_hlt();
> + }
> + return -1;
> +}
> diff --git a/arch/x86/cpu/ivybridge/me_status.c b/arch/x86/cpu/ivybridge/me_status.c
> new file mode 100644
> index 0000000..15cf69f
> --- /dev/null
> +++ b/arch/x86/cpu/ivybridge/me_status.c
> @@ -0,0 +1,195 @@
> +/*
> + * From Coreboot src/southbridge/intel/bd82x6x/me_status.c
> + *
> + * Copyright (C) 2011 The Chromium OS Authors. All rights reserved.
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> +
> +#include <common.h>
> +#include <asm/arch/me.h>
> +
> +/* HFS1[3:0] Current Working State Values */
> +static const char *const me_cws_values[] = {
> + [ME_HFS_CWS_RESET] = "Reset",
> + [ME_HFS_CWS_INIT] = "Initializing",
> + [ME_HFS_CWS_REC] = "Recovery",
> + [ME_HFS_CWS_NORMAL] = "Normal",
> + [ME_HFS_CWS_WAIT] = "Platform Disable Wait",
> + [ME_HFS_CWS_TRANS] = "OP State Transition",
> + [ME_HFS_CWS_INVALID] = "Invalid CPU Plugged In"
> +};
> +
> +/* HFS1[8:6] Current Operation State Values */
> +static const char *const me_opstate_values[] = {
> + [ME_HFS_STATE_PREBOOT] = "Preboot",
> + [ME_HFS_STATE_M0_UMA] = "M0 with UMA",
> + [ME_HFS_STATE_M3] = "M3 without UMA",
> + [ME_HFS_STATE_M0] = "M0 without UMA",
> + [ME_HFS_STATE_BRINGUP] = "Bring up",
> + [ME_HFS_STATE_ERROR] = "M0 without UMA but with error"
> +};
> +
> +/* HFS[19:16] Current Operation Mode Values */
> +static const char *const me_opmode_values[] = {
> + [ME_HFS_MODE_NORMAL] = "Normal",
> + [ME_HFS_MODE_DEBUG] = "Debug",
> + [ME_HFS_MODE_DIS] = "Soft Temporary Disable",
> + [ME_HFS_MODE_OVER_JMPR] = "Security Override via Jumper",
> + [ME_HFS_MODE_OVER_MEI] = "Security Override via MEI Message"
> +};
> +
> +/* HFS[15:12] Error Code Values */
> +static const char *const me_error_values[] = {
> + [ME_HFS_ERROR_NONE] = "No Error",
> + [ME_HFS_ERROR_UNCAT] = "Uncategorized Failure",
> + [ME_HFS_ERROR_IMAGE] = "Image Failure",
> + [ME_HFS_ERROR_DEBUG] = "Debug Failure"
> +};
> +
> +/* GMES[31:28] ME Progress Code */
> +static const char *const me_progress_values[] = {
> + [ME_GMES_PHASE_ROM] = "ROM Phase",
> + [ME_GMES_PHASE_BUP] = "BUP Phase",
> + [ME_GMES_PHASE_UKERNEL] = "uKernel Phase",
> + [ME_GMES_PHASE_POLICY] = "Policy Module",
> + [ME_GMES_PHASE_MODULE] = "Module Loading",
> + [ME_GMES_PHASE_UNKNOWN] = "Unknown",
> + [ME_GMES_PHASE_HOST] = "Host Communication"
> +};
> +
> +/* GMES[27:24] Power Management Event */
> +static const char *const me_pmevent_values[] = {
> + [0x00] = "Clean Moff->Mx wake",
> + [0x01] = "Moff->Mx wake after an error",
> + [0x02] = "Clean global reset",
> + [0x03] = "Global reset after an error",
> + [0x04] = "Clean Intel ME reset",
> + [0x05] = "Intel ME reset due to exception",
> + [0x06] = "Pseudo-global reset",
> + [0x07] = "S0/M0->Sx/M3",
> + [0x08] = "Sx/M3->S0/M0",
> + [0x09] = "Non-power cycle reset",
> + [0x0a] = "Power cycle reset through M3",
> + [0x0b] = "Power cycle reset through Moff",
> + [0x0c] = "Sx/Mx->Sx/Moff"
> +};
> +
> +/* Progress Code 0 states */
> +static const char *const me_progress_rom_values[] = {
> + [0x00] = "BEGIN",
> + [0x06] = "DISABLE"
> +};
> +
> +/* Progress Code 1 states */
> +static const char *const me_progress_bup_values[] = {
> + [0x00] = "Initialization starts",
> + [0x01] = "Disable the host wake event",
> + [0x04] = "Flow determination start process",
> + [0x08] = "Error reading/matching the VSCC table in the descriptor",
> + [0x0a] = "Check to see if straps say ME DISABLED",
> + [0x0b] = "Timeout waiting for PWROK",
> + [0x0d] = "Possibly handle BUP manufacturing override strap",
> + [0x11] = "Bringup in M3",
> + [0x12] = "Bringup in M0",
> + [0x13] = "Flow detection error",
> + [0x15] = "M3 clock switching error",
> + [0x18] = "M3 kernel load",
> + [0x1c] = "T34 missing - cannot program ICC",
> + [0x1f] = "Waiting for DID BIOS message",
> + [0x20] = "Waiting for DID BIOS message failure",
> + [0x21] = "DID reported an error",
> + [0x22] = "Enabling UMA",
> + [0x23] = "Enabling UMA error",
> + [0x24] = "Sending DID Ack to BIOS",
> + [0x25] = "Sending DID Ack to BIOS error",
> + [0x26] = "Switching clocks in M0",
> + [0x27] = "Switching clocks in M0 error",
> + [0x28] = "ME in temp disable",
> + [0x32] = "M0 kernel load",
> +};
> +
> +/* Progress Code 3 states */
> +static const char *const me_progress_policy_values[] = {
> + [0x00] = "Entery into Policy Module",
> + [0x03] = "Received S3 entry",
> + [0x04] = "Received S4 entry",
> + [0x05] = "Received S5 entry",
> + [0x06] = "Received UPD entry",
> + [0x07] = "Received PCR entry",
> + [0x08] = "Received NPCR entry",
> + [0x09] = "Received host wake",
> + [0x0a] = "Received AC<>DC switch",
> + [0x0b] = "Received DRAM Init Done",
> + [0x0c] = "VSCC Data not found for flash device",
> + [0x0d] = "VSCC Table is not valid",
> + [0x0e] = "Flash Partition Boundary is outside address space",
> + [0x0f] = "ME cannot access the chipset descriptor region",
> + [0x10] = "Required VSCC values for flash parts do not match",
> +};
> +
> +void intel_me_status(struct me_hfs *hfs, struct me_gmes *gmes)
> +{
> + /* Check Current States */
> + debug("ME: FW Partition Table : %s\n",
> + hfs->fpt_bad ? "BAD" : "OK");
> + debug("ME: Bringup Loader Failure : %s\n",
> + hfs->ft_bup_ld_flr ? "YES" : "NO");
> + debug("ME: Firmware Init Complete : %s\n",
> + hfs->fw_init_complete ? "YES" : "NO");
> + debug("ME: Manufacturing Mode : %s\n",
> + hfs->mfg_mode ? "YES" : "NO");
> + debug("ME: Boot Options Present : %s\n",
> + hfs->boot_options_present ? "YES" : "NO");
> + debug("ME: Update In Progress : %s\n",
> + hfs->update_in_progress ? "YES" : "NO");
> + debug("ME: Current Working State : %s\n",
> + me_cws_values[hfs->working_state]);
> + debug("ME: Current Operation State : %s\n",
> + me_opstate_values[hfs->operation_state]);
> + debug("ME: Current Operation Mode : %s\n",
> + me_opmode_values[hfs->operation_mode]);
> + debug("ME: Error Code : %s\n",
> + me_error_values[hfs->error_code]);
> + debug("ME: Progress Phase : %s\n",
> + me_progress_values[gmes->progress_code]);
> + debug("ME: Power Management Event : %s\n",
> + me_pmevent_values[gmes->current_pmevent]);
> +
> + debug("ME: Progress Phase State : ");
> + switch (gmes->progress_code) {
> + case ME_GMES_PHASE_ROM: /* ROM Phase */
> + debug("%s", me_progress_rom_values[gmes->current_state]);
> + break;
> +
> + case ME_GMES_PHASE_BUP: /* Bringup Phase */
> + if (gmes->current_state < ARRAY_SIZE(me_progress_bup_values) &&
> + me_progress_bup_values[gmes->current_state])
> + debug("%s",
> + me_progress_bup_values[gmes->current_state]);
> + else
> + debug("0x%02x", gmes->current_state);
> + break;
> +
> + case ME_GMES_PHASE_POLICY: /* Policy Module Phase */
> + if (gmes->current_state <
> + ARRAY_SIZE(me_progress_policy_values) &&
> + me_progress_policy_values[gmes->current_state])
> + debug("%s",
> + me_progress_policy_values[gmes->current_state]);
> + else
> + debug("0x%02x", gmes->current_state);
> + break;
> +
> + case ME_GMES_PHASE_HOST: /* Host Communication Phase */
> + if (!gmes->current_state)
> + debug("Host communication established");
> + else
> + debug("0x%02x", gmes->current_state);
> + break;
> +
> + default:
> + debug("Unknown 0x%02x", gmes->current_state);
> + }
> + debug("\n");
> +}
> diff --git a/arch/x86/cpu/ivybridge/report_platform.c b/arch/x86/cpu/ivybridge/report_platform.c
> new file mode 100644
> index 0000000..b236ecb
> --- /dev/null
> +++ b/arch/x86/cpu/ivybridge/report_platform.c
> @@ -0,0 +1,98 @@
> +/*
> + * From Coreboot src/northbridge/intel/sandybridge/report_platform.c
> + *
> + * Copyright (C) 2012 Google Inc.
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> +
> +#include <common.h>
> +#include <asm/processor.h>
> +#include <asm/pci.h>
> +#include <asm/arch/pch.h>
> +
> +static void report_cpu_info(void)
> +{
> + struct cpuid_result cpuidr;
> + u32 i, index;
> + char cpu_string[50], *cpu_name = cpu_string; /* 48 bytes are reported */
> + int vt, txt, aes;
> + const char *mode[] = {"NOT ", ""};
> +
> + index = 0x80000000;
> + cpuidr = cpuid(index);
> + if (cpuidr.eax < 0x80000004) {
> + strcpy(cpu_string, "Platform info not available");
> + } else {
> + u32 *p = (u32 *)cpu_string;
> + for (i = 2; i <= 4 ; i++) {
> + cpuidr = cpuid(index + i);
> + *p++ = cpuidr.eax;
> + *p++ = cpuidr.ebx;
> + *p++ = cpuidr.ecx;
> + *p++ = cpuidr.edx;
> + }
> + }
> + /* Skip leading spaces in CPU name string */
> + while (cpu_name[0] == ' ')
> + cpu_name++;
The above codes can be just replaced by a call to fill_processor_name()
> + cpuidr = cpuid(1);
> + debug("CPU id(%x): %s\n", cpuidr.eax, cpu_name);
> + aes = (cpuidr.ecx & (1 << 25)) ? 1 : 0;
> + txt = (cpuidr.ecx & (1 << 6)) ? 1 : 0;
> + vt = (cpuidr.ecx & (1 << 5)) ? 1 : 0;
> + debug("AES %ssupported, TXT %ssupported, VT %ssupported\n",
> + mode[aes], mode[txt], mode[vt]);
> +}
> +
> +/* The PCI id name match comes from Intel document 472178 */
> +static struct {
> + u16 dev_id;
> + const char *dev_name;
> +} pch_table[] = {
> + {0x1E41, "Desktop Sample"},
> + {0x1E42, "Mobile Sample"},
> + {0x1E43, "SFF Sample"},
> + {0x1E44, "Z77"},
> + {0x1E45, "H71"},
> + {0x1E46, "Z75"},
> + {0x1E47, "Q77"},
> + {0x1E48, "Q75"},
> + {0x1E49, "B75"},
> + {0x1E4A, "H77"},
> + {0x1E53, "C216"},
> + {0x1E55, "QM77"},
> + {0x1E56, "QS77"},
> + {0x1E58, "UM77"},
> + {0x1E57, "HM77"},
> + {0x1E59, "HM76"},
> + {0x1E5D, "HM75"},
> + {0x1E5E, "HM70"},
> + {0x1E5F, "NM70"},
> +};
> +
> +static void report_pch_info(void)
> +{
> + const char *pch_type = "Unknown";
> + int i;
> + u16 dev_id;
> + uint8_t rev_id;
> +
> + dev_id = pci_read_config16(PCH_LPC_DEV, 2);
> + for (i = 0; i < ARRAY_SIZE(pch_table); i++) {
> + if (pch_table[i].dev_id == dev_id) {
> + pch_type = pch_table[i].dev_name;
> + break;
> + }
> + }
> + rev_id = pci_read_config8(PCH_LPC_DEV, 8);
> + debug("PCH type: %s, device id: %x, rev id %x\n", pch_type, dev_id,
> + rev_id);
> +}
> +
> +void report_platform_info(void)
> +{
> + report_cpu_info();
> + report_pch_info();
> +}
> diff --git a/arch/x86/cpu/ivybridge/sdram.c b/arch/x86/cpu/ivybridge/sdram.c
> index 5f9ae5e..ed89f60 100644
> --- a/arch/x86/cpu/ivybridge/sdram.c
> +++ b/arch/x86/cpu/ivybridge/sdram.c
> @@ -11,10 +11,561 @@
> */
>
> #include <common.h>
> +#include <errno.h>
> +#include <fdtdec.h>
> +#include <malloc.h>
> +#include <asm/processor.h>
> +#include <asm/gpio.h>
> +#include <asm/global_data.h>
> +#include <asm/pci.h>
> +#include <asm/arch/me.h>
> +#include <asm/arch/pei_data.h>
> +#include <asm/arch/pch.h>
> +#include <asm/post.h>
> +#include <asm/arch/sandybridge.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +/*
> + * 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.
> + * It overrides the default implementation found elsewhere which simply
> + * picks the end of ram, wherever that may be. The location of the stack,
> + * the relocation address, and how far U-Boot is moved by relocation are
> + * set in the global data structure.
> + */
> +ulong board_get_usable_ram_top(ulong total_size)
> +{
> + struct memory_info *info = &gd->arch.meminfo;
> + uintptr_t dest_addr = 0;
> + struct memory_area *largest = NULL;
> + int i;
> +
> + /* Find largest area of memory below 4GB */
> +
> + for (i = 0; i < info->num_areas; i++) {
> + struct memory_area *area = &info->area[i];
> +
> + if (area->start >= 1ULL << 32)
> + continue;
> + if (!largest || area->size > largest->size)
> + largest = area;
> + }
> +
> + /* If no suitable area was found, return an error. */
> + assert(largest);
> + if (!largest || largest->size < (2 << 20))
> + panic("No available memory found for relocation");
> +
> + dest_addr = largest->start + largest->size;
> +
> + return (ulong)dest_addr;
> +}
> +
> +void dram_init_banksize(void)
> +{
> + struct memory_info *info = &gd->arch.meminfo;
> + int num_banks;
> + int i;
> +
> + for (i = 0, num_banks = 0; i < info->num_areas; i++) {
> + struct memory_area *area = &info->area[i];
> +
> + if (area->start >= 1ULL << 32)
> + continue;
> + gd->bd->bi_dram[num_banks].start = area->start;
> + gd->bd->bi_dram[num_banks].size = area->size;
> + num_banks++;
> + }
> +}
> +
> +static const char *const ecc_decoder[] = {
> + "inactive",
> + "active on IO",
> + "disabled on IO",
> + "active"
> +};
> +
> +/*
> + * Dump in the log memory controller configuration as read from the memory
> + * controller registers.
> + */
> +static void report_memory_config(void)
> +{
> + u32 addr_decoder_common, addr_decode_ch[2];
> + int i;
> +
> + addr_decoder_common = readl(MCHBAR_REG(0x5000));
> + addr_decode_ch[0] = readl(MCHBAR_REG(0x5004));
> + addr_decode_ch[1] = readl(MCHBAR_REG(0x5008));
> +
> + debug("memcfg DDR3 clock %d MHz\n",
> + (readl(MCHBAR_REG(0x5e04)) * 13333 * 2 + 50) / 100);
> + debug("memcfg channel assignment: A: %d, B % d, C % d\n",
> + addr_decoder_common & 3,
> + (addr_decoder_common >> 2) & 3,
> + (addr_decoder_common >> 4) & 3);
> +
> + for (i = 0; i < ARRAY_SIZE(addr_decode_ch); i++) {
> + u32 ch_conf = addr_decode_ch[i];
> + debug("memcfg channel[%d] config (%8.8x):\n", i, ch_conf);
> + debug(" ECC %s\n", ecc_decoder[(ch_conf >> 24) & 3]);
> + debug(" enhanced interleave mode %s\n",
> + ((ch_conf >> 22) & 1) ? "on" : "off");
> + debug(" rank interleave %s\n",
> + ((ch_conf >> 21) & 1) ? "on" : "off");
> + debug(" DIMMA %d MB width x%d %s rank%s\n",
> + ((ch_conf >> 0) & 0xff) * 256,
> + ((ch_conf >> 19) & 1) ? 16 : 8,
> + ((ch_conf >> 17) & 1) ? "dual" : "single",
> + ((ch_conf >> 16) & 1) ? "" : ", selected");
> + debug(" DIMMB %d MB width x%d %s rank%s\n",
> + ((ch_conf >> 8) & 0xff) * 256,
> + ((ch_conf >> 20) & 1) ? 16 : 8,
> + ((ch_conf >> 18) & 1) ? "dual" : "single",
> + ((ch_conf >> 16) & 1) ? ", selected" : "");
> + }
> +}
> +
> +static void post_system_agent_init(struct pei_data *pei_data)
> +{
> + /* If PCIe init is skipped, set the PEG clock gating */
> + if (!pei_data->pcie_init)
> + setbits_le32(MCHBAR_REG(0x7010), 1);
> +}
> +
> +static asmlinkage void console_tx_byte(unsigned char byte)
> +{
> +#ifdef DEBUG
> + putc(byte);
> +#endif
> +}
> +
> +/**
> + * Find PEI executable in coreboot filesystem and execute it.
> + *
> + * @param pei_data: configuration data for UEFI PEI reference code
> + */
> +int sdram_initialise(struct pei_data *pei_data)
> +{
> + unsigned version;
> + const char *data;
> + uint16_t done;
> + int ret;
> +
> + report_platform_info();
> +
> + /* Wait for ME to be ready */
> + ret = intel_early_me_init();
> + if (ret)
> + return ret;
> + ret = intel_early_me_uma_size();
> + if (ret < 0)
> + return ret;
> +
> + debug("Starting UEFI PEI System Agent\n");
> +
> + /* 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");
> + outb(0x6, PORT_RESET);
> + cpu_hlt();
> + }
> +
> + /* Pass console handler in pei_data */
> + pei_data->tx_byte = console_tx_byte;
> +
> + debug("PEI data at %p, size %x:\n", pei_data, sizeof(*pei_data));
> +
> + data = (char *)CONFIG_X86_MRC_START;
> + if (data) {
> + int rv;
> + int (*func)(struct pei_data *);
> +
> + debug("Calling MRC at %p\n", data);
> + post_code(POST_PRE_MRC);
> + func = (int (*)(struct pei_data *))data;
> + rv = func(pei_data);
> + post_code(POST_MRC);
> + if (rv) {
> + switch (rv) {
> + case -1:
> + printf("PEI version mismatch.\n");
> + break;
> + case -2:
> + printf("Invalid memory frequency.\n");
> + break;
> + default:
> + printf("MRC returned %x.\n", rv);
> + }
> + printf("Nonzero MRC return value.\n");
> + return -EFAULT;
> + }
> + } else {
> + printf("UEFI PEI System Agent not found.\n");
> + return -ENOSYS;
> + }
> +
> +#if CONFIG_USBDEBUG
> + /* mrc.bin reconfigures USB, so reinit it to have debug */
> + early_usbdebug_init();
> +#endif
> +
> + version = readl(MCHBAR_REG(0x5034));
> + debug("System Agent Version %d.%d.%d Build %d\n",
> + version >> 24 , (version >> 16) & 0xff,
> + (version >> 8) & 0xff, version & 0xff);
> +
> + /*
> + * Send ME init done for SandyBridge here. This is done inside the
> + * SystemAgent binary on IvyBridge
> + */
> + done = pci_read_config32(PCI_CPU_DEVICE, PCI_DEVICE_ID);
> + done &= BASE_REV_MASK;
> + if (BASE_REV_SNB == done)
> + intel_early_me_init_done(ME_INIT_STATUS_SUCCESS);
> + else
> + intel_early_me_status();
> +
> + post_system_agent_init(pei_data);
> + report_memory_config();
> +
> + return 0;
> +}
> +
> +static int copy_spd(struct pei_data *peid)
> +{
> + const int gpio_vector[] = {41, 42, 43, 10, -1};
> + int spd_index;
> + const void *blob = gd->fdt_blob;
> + int node, spd_node;
> + int ret, i;
> +
> + for (i = 0; ; i++) {
> + if (gpio_vector[i] == -1)
> + break;
> + ret = gpio_requestf(gpio_vector[i], "spd_id%d", i);
> + if (ret) {
> + debug("%s: Could not request gpio %d\n", __func__,
> + gpio_vector[i]);
> + return ret;
> + }
> + }
> + spd_index = gpio_get_values_as_int(gpio_vector);
> + debug("spd index %d\n", spd_index);
> + node = fdtdec_next_compatible(blob, 0, COMPAT_MEMORY_SPD);
> + if (node < 0) {
> + printf("SPD data not found.\n");
> + return -ENOENT;
> + }
> +
> + for (spd_node = fdt_first_subnode(blob, node);
> + spd_node > 0;
> + spd_node = fdt_next_subnode(blob, spd_node)) {
> + const char *data;
> + int len;
> +
> + if (fdtdec_get_int(blob, spd_node, "reg", -1) != spd_index)
> + continue;
> + data = fdt_getprop(blob, spd_node, "data", &len);
> + if (len < sizeof(peid->spd_data[0])) {
> + printf("Missing SPD data\n");
> + return -EINVAL;
> + }
> +
> + debug("Using SDRAM SPD data for '%s'\n",
> + fdt_get_name(blob, spd_node, NULL));
> + memcpy(peid->spd_data[0], data, sizeof(peid->spd_data[0]));
> + break;
> + }
> +
> + if (spd_node < 0) {
> + printf("No SPD data found for index %d\n", spd_index);
> + return -ENOENT;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * add_memory_area() - Add a new usable memory area to our list
> + *
> + * Note: @start and @end must not span the first 4GB boundary
> + *
> + * @info: Place to store memory info
> + * @start: Start of this memory area
> + * @end: End of this memory area + 1
> + */
> +static int add_memory_area(struct memory_info *info,
> + uint64_t start, uint64_t end)
> +{
> + struct memory_area *ptr;
> +
> + if (info->num_areas == CONFIG_NR_DRAM_BANKS)
> + return -ENOSPC;
> +
> + ptr = &info->area[info->num_areas];
> + ptr->start = start;
> + ptr->size = end - start;
> + info->total_memory += ptr->size;
> + if (ptr->start < (1ULL << 32))
> + info->total_32bit_memory += ptr->size;
> + debug("%d: memory %llx size %llx, total now %llx / %llx\n",
> + info->num_areas, ptr->start, ptr->size,
> + info->total_32bit_memory, info->total_memory);
> + info->num_areas++;
> +
> + return 0;
> +}
> +
> +/**
> + * sdram_find() - Find available memory
> + *
> + * This is a bit complicated since on x86 there are system memory holes all
> + * over the place. We create a list of available memory blocks
> + */
> +static int sdram_find(pci_dev_t dev)
> +{
> + struct memory_info *info = &gd->arch.meminfo;
> + uint32_t tseg_base, uma_size, tolud;
> + uint64_t tom, me_base, touud;
> + uint64_t uma_memory_base = 0;
> + uint64_t uma_memory_size;
> + unsigned long long tomk;
> + uint16_t ggc;
> +
> + /* Total Memory 2GB example:
> + *
> + * 00000000 0000MB-1992MB 1992MB RAM (writeback)
> + * 7c800000 1992MB-2000MB 8MB TSEG (SMRR)
> + * 7d000000 2000MB-2002MB 2MB GFX GTT (uncached)
> + * 7d200000 2002MB-2034MB 32MB GFX UMA (uncached)
> + * 7f200000 2034MB TOLUD
> + * 7f800000 2040MB MEBASE
> + * 7f800000 2040MB-2048MB 8MB ME UMA (uncached)
> + * 80000000 2048MB TOM
> + * 100000000 4096MB-4102MB 6MB RAM (writeback)
> + *
> + * Total Memory 4GB example:
> + *
> + * 00000000 0000MB-2768MB 2768MB RAM (writeback)
> + * ad000000 2768MB-2776MB 8MB TSEG (SMRR)
> + * ad800000 2776MB-2778MB 2MB GFX GTT (uncached)
> + * ada00000 2778MB-2810MB 32MB GFX UMA (uncached)
> + * afa00000 2810MB TOLUD
> + * ff800000 4088MB MEBASE
> + * ff800000 4088MB-4096MB 8MB ME UMA (uncached)
> + * 100000000 4096MB TOM
> + * 100000000 4096MB-5374MB 1278MB RAM (writeback)
> + * 14fe00000 5368MB TOUUD
> + */
> +
> + /* Top of Upper Usable DRAM, including remap */
> + touud = pci_read_config32(dev, TOUUD+4);
> + touud <<= 32;
> + touud |= pci_read_config32(dev, TOUUD);
> +
> + /* Top of Lower Usable DRAM */
> + tolud = pci_read_config32(dev, TOLUD);
> +
> + /* Top of Memory - does not account for any UMA */
> + tom = pci_read_config32(dev, 0xa4);
> + tom <<= 32;
> + tom |= pci_read_config32(dev, 0xa0);
> +
> + debug("TOUUD %llx TOLUD %08x TOM %llx\n", touud, tolud, tom);
> +
> + /* ME UMA needs excluding if total memory <4GB */
> + me_base = pci_read_config32(dev, 0x74);
> + me_base <<= 32;
> + me_base |= pci_read_config32(dev, 0x70);
> +
> + debug("MEBASE %llx\n", me_base);
> +
> + /* TODO: Get rid of all this shifting by 10 bits */
> + tomk = tolud >> 10;
> + if (me_base == tolud) {
> + /* ME is from MEBASE-TOM */
> + uma_size = (tom - me_base) >> 10;
> + /* Increment TOLUD to account for ME as RAM */
> + tolud += uma_size << 10;
> + /* UMA starts at old TOLUD */
> + uma_memory_base = tomk * 1024ULL;
> + uma_memory_size = uma_size * 1024ULL;
> + debug("ME UMA base %llx size %uM\n", me_base, uma_size >> 10);
> + }
> +
> + /* Graphics memory comes next */
> + ggc = pci_read_config16(dev, GGC);
> + if (!(ggc & 2)) {
> + debug("IGD decoded, subtracting ");
> +
> + /* Graphics memory */
> + uma_size = ((ggc >> 3) & 0x1f) * 32 * 1024ULL;
> + debug("%uM UMA", uma_size >> 10);
> + tomk -= uma_size;
> + uma_memory_base = tomk * 1024ULL;
> + uma_memory_size += uma_size * 1024ULL;
> +
> + /* GTT Graphics Stolen Memory Size (GGMS) */
> + uma_size = ((ggc >> 8) & 0x3) * 1024ULL;
> + tomk -= uma_size;
> + uma_memory_base = tomk * 1024ULL;
> + uma_memory_size += uma_size * 1024ULL;
> + debug(" and %uM GTT\n", uma_size >> 10);
> + }
> +
> + /* Calculate TSEG size from its base which must be below GTT */
> + tseg_base = pci_read_config32(dev, 0xb8);
> + uma_size = (uma_memory_base - tseg_base) >> 10;
> + tomk -= uma_size;
> + uma_memory_base = tomk * 1024ULL;
> + uma_memory_size += uma_size * 1024ULL;
> + debug("TSEG base 0x%08x size %uM\n", tseg_base, uma_size >> 10);
> +
> + debug("Available memory below 4GB: %lluM\n", tomk >> 10);
> +
> + /* Report the memory regions */
> + add_memory_area(info, 1 << 20, 2 << 28);
> + add_memory_area(info, (2 << 28) + (2 << 20), 4 << 28);
> + add_memory_area(info, (4 << 28) + (2 << 20), tseg_base);
> + add_memory_area(info, 1ULL << 32, touud);
> + /*
> + * If >= 4GB installed then memory from TOLUD to 4GB
> + * is remapped above TOM, TOUUD will account for both
> + */
> + if (touud > (1ULL << 32ULL)) {
> + debug("Available memory above 4GB: %lluM\n",
> + (touud >> 20) - 4096);
> + }
> +
> + return 0;
> +}
> +
> +static void rcba_config(void)
> +{
> + /*
> + * GFX INTA -> PIRQA (MSI)
> + * D28IP_P3IP WLAN INTA -> PIRQB
> + * D29IP_E1P EHCI1 INTA -> PIRQD
> + * D26IP_E2P EHCI2 INTA -> PIRQF
> + * D31IP_SIP SATA INTA -> PIRQF (MSI)
> + * D31IP_SMIP SMBUS INTB -> PIRQH
> + * D31IP_TTIP THRT INTC -> PIRQA
> + * D27IP_ZIP HDA INTA -> PIRQA (MSI)
> + *
> + * TRACKPAD -> PIRQE (Edge Triggered)
> + * TOUCHSCREEN -> PIRQG (Edge Triggered)
> + */
> +
> + /* Device interrupt pin register (board specific) */
> + writel((INTC << D31IP_TTIP) | (NOINT << D31IP_SIP2) |
> + (INTB << D31IP_SMIP) | (INTA << D31IP_SIP), RCB_REG(D31IP));
> + writel(NOINT << D30IP_PIP, RCB_REG(D30IP));
> + writel(INTA << D29IP_E1P, RCB_REG(D29IP));
> + writel(INTA << D28IP_P3IP, RCB_REG(D28IP));
> + writel(INTA << D27IP_ZIP, RCB_REG(D27IP));
> + writel(INTA << D26IP_E2P, RCB_REG(D26IP));
> + writel(NOINT << D25IP_LIP, RCB_REG(D25IP));
> + writel(NOINT << D22IP_MEI1IP, RCB_REG(D22IP));
> +
> + /* Device interrupt route registers */
> + writel(DIR_ROUTE(PIRQB, PIRQH, PIRQA, PIRQC), RCB_REG(D31IR));
> + writel(DIR_ROUTE(PIRQD, PIRQE, PIRQF, PIRQG), RCB_REG(D29IR));
> + writel(DIR_ROUTE(PIRQB, PIRQC, PIRQD, PIRQE), RCB_REG(D28IR));
> + writel(DIR_ROUTE(PIRQA, PIRQH, PIRQA, PIRQB), RCB_REG(D27IR));
> + writel(DIR_ROUTE(PIRQF, PIRQE, PIRQG, PIRQH), RCB_REG(D26IR));
> + writel(DIR_ROUTE(PIRQA, PIRQB, PIRQC, PIRQD), RCB_REG(D25IR));
> + writel(DIR_ROUTE(PIRQA, PIRQB, PIRQC, PIRQD), RCB_REG(D22IR));
> +
> + /* Enable IOAPIC (generic) */
> + writew(0x0100, RCB_REG(OIC));
> + /* PCH BWG says to read back the IOAPIC enable register */
> + (void)readw(RCB_REG(OIC));
> +
> + /* Disable unused devices (board specific) */
> + setbits_le32(RCB_REG(FD), PCH_DISABLE_ALWAYS);
> +}
>
> int dram_init(void)
> {
> - /* TODO: Set up DRAM */
> + struct pei_data pei_data __aligned(8) = {
> + .pei_version = PEI_VERSION,
> + .mchbar = DEFAULT_MCHBAR,
> + .dmibar = DEFAULT_DMIBAR,
> + .epbar = DEFAULT_EPBAR,
> + .pciexbar = CONFIG_MMCONF_BASE_ADDRESS,
> + .smbusbar = SMBUS_IO_BASE,
> + .wdbbar = 0x4000000,
> + .wdbsize = 0x1000,
> + .hpet_address = CONFIG_HPET_ADDRESS,
> + .rcba = DEFAULT_RCBABASE,
> + .pmbase = DEFAULT_PMBASE,
> + .gpiobase = DEFAULT_GPIOBASE,
> + .thermalbase = 0xfed08000,
> + .system_type = 0, /* 0 Mobile, 1 Desktop/Server */
> + .tseg_size = CONFIG_SMM_TSEG_SIZE,
> + .ts_addresses = { 0x00, 0x00, 0x00, 0x00 },
> + .ec_present = 1,
> + .ddr3lv_support = 1,
> + /*
> + * 0 = leave channel enabled
> + * 1 = disable dimm 0 on channel
> + * 2 = disable dimm 1 on channel
> + * 3 = disable dimm 0+1 on channel
> + */
> + .dimm_channel0_disabled = 2,
> + .dimm_channel1_disabled = 2,
> + .max_ddr3_freq = 1600,
> + .usb_port_config = {
> + /*
> + * Empty and onboard Ports 0-7, set to un-used pin
> + * OC3
> + */
> + { 0, 3, 0x0000 }, /* P0= Empty */
> + { 1, 0, 0x0040 }, /* P1= Left USB 1 (OC0) */
> + { 1, 1, 0x0040 }, /* P2= Left USB 2 (OC1) */
> + { 1, 3, 0x0040 }, /* P3= SDCARD (no OC) */
> + { 0, 3, 0x0000 }, /* P4= Empty */
> + { 1, 3, 0x0040 }, /* P5= WWAN (no OC) */
> + { 0, 3, 0x0000 }, /* P6= Empty */
> + { 0, 3, 0x0000 }, /* P7= Empty */
> + /*
> + * Empty and onboard Ports 8-13, set to un-used pin
> + * OC4
> + */
> + { 1, 4, 0x0040 }, /* P8= Camera (no OC) */
> + { 1, 4, 0x0040 }, /* P9= Bluetooth (no OC) */
> + { 0, 4, 0x0000 }, /* P10= Empty */
> + { 0, 4, 0x0000 }, /* P11= Empty */
> + { 0, 4, 0x0000 }, /* P12= Empty */
> + { 0, 4, 0x0000 }, /* P13= Empty */
> + },
> + };
> + pci_dev_t dev = PCI_BDF(0, 0, 0);
> + int ret;
> +
> + debug("Boot mode %d\n", gd->arch.pei_boot_mode);
> + debug("mcr_input %p\n", pei_data.mrc_input);
> + pei_data.boot_mode = gd->arch.pei_boot_mode;
> + ret = copy_spd(&pei_data);
> + if (!ret)
> + ret = sdram_initialise(&pei_data);
> + if (ret)
> + return ret;
> +
> + rcba_config();
> + quick_ram_check();
> +
> + writew(0xCAFE, MCHBAR_REG(SSKPD));
> +
> + post_code(POST_DRAM);
> +
> + ret = sdram_find(dev);
> + if (ret)
> + return ret;
> +
> + gd->ram_size = gd->arch.meminfo.total_32bit_memory;
>
> return 0;
> }
> diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S
> index f62ffeb..4e973f1 100644
> --- a/arch/x86/cpu/start.S
> +++ b/arch/x86/cpu/start.S
> @@ -94,20 +94,22 @@ car_init_ret:
> * We now have CONFIG_SYS_CAR_SIZE bytes of Cache-As-RAM (or SRAM,
> * or fully initialised SDRAM - we really don't care which)
> * starting at CONFIG_SYS_CAR_ADDR to be used as a temporary stack
> - * and early malloc area.
> + * and early malloc area. The MRC requires some space at the top.
> *
> * Stack grows down from top of CAR. We have:
> *
> * top-> CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE
> + * MRC area
> * global_data
> * x86 global descriptor table
> * early malloc area
> * stack
> * bottom-> CONFIG_SYS_CAR_ADDR
> */
> -
> - /* Stack grows down from top of CAR */
> - movl $(CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE), %esp
> + movl $(CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE - 4), %esp
> +#ifdef CONFIG_DCACHE_RAM_MRC_VAR_SIZE
> + subl CONFIG_DCACHE_RAM_MRC_VAR_SIZE, %esp
> +#endif
>
> /* Reserve space on stack for global data */
> subl $GENERATED_GBL_DATA_SIZE, %esp
> diff --git a/arch/x86/dts/link.dts b/arch/x86/dts/link.dts
> index 84fb0a9..f152da5 100644
> --- a/arch/x86/dts/link.dts
> +++ b/arch/x86/dts/link.dts
> @@ -41,6 +41,117 @@
> chosen { };
> memory { device_type = "memory"; reg = <0 0>; };
>
> + 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];
> + };
Is this the limitation of the MRC that it cannot read SPD from the
DIMM? Or is it because the RAM chip is soldered on board?
> + 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>;
> diff --git a/arch/x86/include/asm/arch-ivybridge/me.h b/arch/x86/include/asm/arch-ivybridge/me.h
> new file mode 100644
> index 0000000..e0e41c8
> --- /dev/null
> +++ b/arch/x86/include/asm/arch-ivybridge/me.h
> @@ -0,0 +1,357 @@
> +/*
> + * From Coreboot src/southbridge/intel/bd82x6x/me.h
> + *
> + * Copyright (C) 2011 The Chromium OS Authors. All rights reserved.
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> +
> +#ifndef _ASM_INTEL_ME_H
> +#define _ASM_INTEL_ME_H
> +
> +#include <linux/compiler.h>
> +#include <linux/types.h>
> +
> +#define ME_RETRY 100000 /* 1 second */
> +#define ME_DELAY 10 /* 10 us */
> +
> +/*
> + * Management Engine PCI registers
> + */
> +
> +#define PCI_CPU_DEVICE PCI_BDF(0, 0, 0)
> +#define PCI_CPU_MEBASE_L 0x70 /* Set by MRC */
> +#define PCI_CPU_MEBASE_H 0x74 /* Set by MRC */
> +
> +#define PCI_ME_HFS 0x40
> +#define ME_HFS_CWS_RESET 0
> +#define ME_HFS_CWS_INIT 1
> +#define ME_HFS_CWS_REC 2
> +#define ME_HFS_CWS_NORMAL 5
> +#define ME_HFS_CWS_WAIT 6
> +#define ME_HFS_CWS_TRANS 7
> +#define ME_HFS_CWS_INVALID 8
> +#define ME_HFS_STATE_PREBOOT 0
> +#define ME_HFS_STATE_M0_UMA 1
> +#define ME_HFS_STATE_M3 4
> +#define ME_HFS_STATE_M0 5
> +#define ME_HFS_STATE_BRINGUP 6
> +#define ME_HFS_STATE_ERROR 7
> +#define ME_HFS_ERROR_NONE 0
> +#define ME_HFS_ERROR_UNCAT 1
> +#define ME_HFS_ERROR_IMAGE 3
> +#define ME_HFS_ERROR_DEBUG 4
> +#define ME_HFS_MODE_NORMAL 0
> +#define ME_HFS_MODE_DEBUG 2
> +#define ME_HFS_MODE_DIS 3
> +#define ME_HFS_MODE_OVER_JMPR 4
> +#define ME_HFS_MODE_OVER_MEI 5
> +#define ME_HFS_BIOS_DRAM_ACK 1
> +#define ME_HFS_ACK_NO_DID 0
> +#define ME_HFS_ACK_RESET 1
> +#define ME_HFS_ACK_PWR_CYCLE 2
> +#define ME_HFS_ACK_S3 3
> +#define ME_HFS_ACK_S4 4
> +#define ME_HFS_ACK_S5 5
> +#define ME_HFS_ACK_GBL_RESET 6
> +#define ME_HFS_ACK_CONTINUE 7
> +
> +struct me_hfs {
> + u32 working_state:4;
> + u32 mfg_mode:1;
> + u32 fpt_bad:1;
> + u32 operation_state:3;
> + u32 fw_init_complete:1;
> + u32 ft_bup_ld_flr:1;
> + u32 update_in_progress:1;
> + u32 error_code:4;
> + u32 operation_mode:4;
> + u32 reserved:4;
> + u32 boot_options_present:1;
> + u32 ack_data:3;
> + u32 bios_msg_ack:4;
> +} __packed;
> +
> +#define PCI_ME_UMA 0x44
> +
> +struct me_uma {
> + u32 size:6;
> + u32 reserved_1:10;
> + u32 valid:1;
> + u32 reserved_0:14;
> + u32 set_to_one:1;
> +} __packed;
> +
> +#define PCI_ME_H_GS 0x4c
> +#define ME_INIT_DONE 1
> +#define ME_INIT_STATUS_SUCCESS 0
> +#define ME_INIT_STATUS_NOMEM 1
> +#define ME_INIT_STATUS_ERROR 2
> +
> +struct me_did {
> + u32 uma_base:16;
> + u32 reserved:8;
> + u32 status:4;
> + u32 init_done:4;
> +} __packed;
> +
> +#define PCI_ME_GMES 0x48
> +#define ME_GMES_PHASE_ROM 0
> +#define ME_GMES_PHASE_BUP 1
> +#define ME_GMES_PHASE_UKERNEL 2
> +#define ME_GMES_PHASE_POLICY 3
> +#define ME_GMES_PHASE_MODULE 4
> +#define ME_GMES_PHASE_UNKNOWN 5
> +#define ME_GMES_PHASE_HOST 6
> +
> +struct me_gmes {
> + u32 bist_in_prog:1;
> + u32 icc_prog_sts:2;
> + u32 invoke_mebx:1;
> + u32 cpu_replaced_sts:1;
> + u32 mbp_rdy:1;
> + u32 mfs_failure:1;
> + u32 warm_rst_req_for_df:1;
> + u32 cpu_replaced_valid:1;
> + u32 reserved_1:2;
> + u32 fw_upd_ipu:1;
> + u32 reserved_2:4;
> + u32 current_state:8;
> + u32 current_pmevent:4;
> + u32 progress_code:4;
> +} __packed;
> +
> +#define PCI_ME_HERES 0xbc
> +#define PCI_ME_EXT_SHA1 0x00
> +#define PCI_ME_EXT_SHA256 0x02
> +#define PCI_ME_HER(x) (0xc0+(4*(x)))
> +
> +struct me_heres {
> + u32 extend_reg_algorithm:4;
> + u32 reserved:26;
> + u32 extend_feature_present:1;
> + u32 extend_reg_valid:1;
> +} __packed;
> +
> +/*
> + * Management Engine MEI registers
> + */
> +
> +#define MEI_H_CB_WW 0x00
> +#define MEI_H_CSR 0x04
> +#define MEI_ME_CB_RW 0x08
> +#define MEI_ME_CSR_HA 0x0c
> +
> +struct mei_csr {
> + u32 interrupt_enable:1;
> + u32 interrupt_status:1;
> + u32 interrupt_generate:1;
> + u32 ready:1;
> + u32 reset:1;
> + u32 reserved:3;
> + u32 buffer_read_ptr:8;
> + u32 buffer_write_ptr:8;
> + u32 buffer_depth:8;
> +} __packed;
> +
> +#define MEI_ADDRESS_CORE 0x01
> +#define MEI_ADDRESS_AMT 0x02
> +#define MEI_ADDRESS_RESERVED 0x03
> +#define MEI_ADDRESS_WDT 0x04
> +#define MEI_ADDRESS_MKHI 0x07
> +#define MEI_ADDRESS_ICC 0x08
> +#define MEI_ADDRESS_THERMAL 0x09
> +
> +#define MEI_HOST_ADDRESS 0
> +
> +struct mei_header {
> + u32 client_address:8;
> + u32 host_address:8;
> + u32 length:9;
> + u32 reserved:6;
> + u32 is_complete:1;
> +} __packed;
> +
> +#define MKHI_GROUP_ID_CBM 0x00
> +#define MKHI_GROUP_ID_FWCAPS 0x03
> +#define MKHI_GROUP_ID_MDES 0x08
> +#define MKHI_GROUP_ID_GEN 0xff
> +
> +#define MKHI_GLOBAL_RESET 0x0b
> +
> +#define MKHI_FWCAPS_GET_RULE 0x02
> +
> +#define MKHI_MDES_ENABLE 0x09
> +
> +#define MKHI_GET_FW_VERSION 0x02
> +#define MKHI_END_OF_POST 0x0c
> +#define MKHI_FEATURE_OVERRIDE 0x14
> +
> +struct mkhi_header {
> + u32 group_id:8;
> + u32 command:7;
> + u32 is_response:1;
> + u32 reserved:8;
> + u32 result:8;
> +} __packed;
> +
> +struct me_fw_version {
> + u16 code_minor;
> + u16 code_major;
> + u16 code_build_number;
> + u16 code_hot_fix;
> + u16 recovery_minor;
> + u16 recovery_major;
> + u16 recovery_build_number;
> + u16 recovery_hot_fix;
> +} __packed;
> +
> +
> +#define HECI_EOP_STATUS_SUCCESS 0x0
> +#define HECI_EOP_PERFORM_GLOBAL_RESET 0x1
> +
> +#define CBM_RR_GLOBAL_RESET 0x01
> +
> +#define GLOBAL_RESET_BIOS_MRC 0x01
> +#define GLOBAL_RESET_BIOS_POST 0x02
> +#define GLOBAL_RESET_MEBX 0x03
> +
> +struct me_global_reset {
> + u8 request_origin;
> + u8 reset_type;
> +} __packed;
> +
> +enum me_bios_path {
> + ME_NORMAL_BIOS_PATH,
> + ME_S3WAKE_BIOS_PATH,
> + ME_ERROR_BIOS_PATH,
> + ME_RECOVERY_BIOS_PATH,
> + ME_DISABLE_BIOS_PATH,
> + ME_FIRMWARE_UPDATE_BIOS_PATH,
> +};
> +
> +struct __packed mbp_fw_version_name {
> + u32 major_version:16;
> + u32 minor_version:16;
> + u32 hotfix_version:16;
> + u32 build_version:16;
> +};
> +
> +struct __packed mbp_icc_profile {
> + u8 num_icc_profiles;
> + u8 icc_profile_soft_strap;
> + u8 icc_profile_index;
> + u8 reserved;
> + u32 register_lock_mask[3];
> +};
> +
> +struct __packed mefwcaps_sku {
> + u32 full_net:1;
> + u32 std_net:1;
> + u32 manageability:1;
> + u32 small_business:1;
> + u32 l3manageability:1;
> + u32 intel_at:1;
> + u32 intel_cls:1;
> + u32 reserved:3;
> + u32 intel_mpc:1;
> + u32 icc_over_clocking:1;
> + u32 pavp:1;
> + u32 reserved_1:4;
> + u32 ipv6:1;
> + u32 kvm:1;
> + u32 och:1;
> + u32 vlan:1;
> + u32 tls:1;
> + u32 reserved_4:1;
> + u32 wlan:1;
> + u32 reserved_5:8;
> +};
> +
> +struct __packed tdt_state_flag {
> + u16 lock_state:1;
> + u16 authenticate_module:1;
> + u16 s3authentication:1;
> + u16 flash_wear_out:1;
> + u16 flash_variable_security:1;
> + u16 wwan3gpresent:1;
> + u16 wwan3goob:1;
> + u16 reserved:9;
> +};
> +
> +struct __packed tdt_state_info {
> + u8 state;
> + u8 last_theft_trigger;
> + struct tdt_state_flag flags;
> +};
> +
> +struct __packed platform_type_rule_data {
> + u32 platform_target_usage_type:4;
> + u32 platform_target_market_type:2;
> + u32 super_sku:1;
> + u32 reserved:1;
> + u32 intel_me_fw_image_type:4;
> + u32 platform_brand:4;
> + u32 reserved_1:16;
> +};
> +
> +struct __packed mbp_fw_caps {
> + struct mefwcaps_sku fw_capabilities;
> + u8 available;
> +};
> +
> +struct __packed mbp_rom_bist_data {
> + u16 device_id;
> + u16 fuse_test_flags;
> + u32 umchid[4];
> +};
> +
> +struct __packed mbp_platform_key {
> + u32 key[8];
> +};
> +
> +struct __packed mbp_plat_type {
> + struct platform_type_rule_data rule_data;
> + u8 available;
> +};
> +
> +struct __packed me_bios_payload {
> + struct mbp_fw_version_name fw_version_name;
> + struct mbp_fw_caps fw_caps_sku;
> + struct mbp_rom_bist_data rom_bist_data;
> + struct mbp_platform_key platform_key;
> + struct mbp_plat_type fw_plat_type;
> + struct mbp_icc_profile icc_profile;
> + struct tdt_state_info at_state;
> + u32 mfsintegrity;
> +};
> +
> +struct __packed mbp_header {
> + u32 mbp_size:8;
> + u32 num_entries:8;
> + u32 rsvd:16;
> +};
> +
> +struct __packed mbp_item_header {
> + u32 app_id:8;
> + u32 item_id:8;
> + u32 length:8;
> + u32 rsvd:8;
> +};
> +
> +struct __packed me_fwcaps {
> + u32 id;
> + u8 length;
> + struct mefwcaps_sku caps_sku;
> + u8 reserved[3];
> +};
> +
> +/* Defined in me_status.c for both romstage and ramstage */
> +void intel_me_status(struct me_hfs *hfs, struct me_gmes *gmes);
> +
> +void intel_early_me_status(void);
> +int intel_early_me_init(void);
> +int intel_early_me_uma_size(void);
> +int intel_early_me_init_done(u8 status);
> +
> +#endif
> diff --git a/arch/x86/include/asm/arch-ivybridge/pch.h b/arch/x86/include/asm/arch-ivybridge/pch.h
> index ae338e3..c6efdb8 100644
> --- a/arch/x86/include/asm/arch-ivybridge/pch.h
> +++ b/arch/x86/include/asm/arch-ivybridge/pch.h
> @@ -31,6 +31,13 @@
> /* PCI Configuration Space (D31:F0): LPC */
> #define PCH_LPC_DEV PCI_BDF(0, 0x1f, 0)
>
> +#define GEN_PMCON_1 0xa0
> +#define GEN_PMCON_2 0xa2
> +#define GEN_PMCON_3 0xa4
> +#define ETR3 0xac
> +#define ETR3_CWORWRE (1 << 18)
> +#define ETR3_CF9GR (1 << 20)
> +
> #define PMBASE 0x40
> #define ACPI_CNTL 0x44
> #define BIOS_CNTL 0xDC
> @@ -126,12 +133,97 @@
> #define RPC 0x0400 /* 32bit */
> #define RPFN 0x0404 /* 32bit */
>
> +#define TRSR 0x1e00 /* 8bit */
> +#define TRCR 0x1e10 /* 64bit */
> +#define TWDR 0x1e18 /* 64bit */
> +
> +#define IOTR0 0x1e80 /* 64bit */
> +#define IOTR1 0x1e88 /* 64bit */
> +#define IOTR2 0x1e90 /* 64bit */
> +#define IOTR3 0x1e98 /* 64bit */
> +
> +#define TCTL 0x3000 /* 8bit */
> +
> +#define NOINT 0
> +#define INTA 1
> +#define INTB 2
> +#define INTC 3
> +#define INTD 4
> +
> +#define DIR_IDR 12 /* Interrupt D Pin Offset */
> +#define DIR_ICR 8 /* Interrupt C Pin Offset */
> +#define DIR_IBR 4 /* Interrupt B Pin Offset */
> +#define DIR_IAR 0 /* Interrupt A Pin Offset */
> +
> +#define PIRQA 0
> +#define PIRQB 1
> +#define PIRQC 2
> +#define PIRQD 3
> +#define PIRQE 4
> +#define PIRQF 5
> +#define PIRQG 6
> +#define PIRQH 7
> +
> +/* IO Buffer Programming */
> +#define IOBPIRI 0x2330
> +#define IOBPD 0x2334
> +#define IOBPS 0x2338
> +#define IOBPS_RW_BX ((1 << 9)|(1 << 10))
> +#define IOBPS_WRITE_AX ((1 << 9)|(1 << 10))
> +#define IOBPS_READ_AX ((1 << 8)|(1 << 9)|(1 << 10))
> +
> +#define D31IP 0x3100 /* 32bit */
> +#define D31IP_TTIP 24 /* Thermal Throttle Pin */
> +#define D31IP_SIP2 20 /* SATA Pin 2 */
> +#define D31IP_SMIP 12 /* SMBUS Pin */
> +#define D31IP_SIP 8 /* SATA Pin */
> +#define D30IP 0x3104 /* 32bit */
> +#define D30IP_PIP 0 /* PCI Bridge Pin */
> +#define D29IP 0x3108 /* 32bit */
> +#define D29IP_E1P 0 /* EHCI #1 Pin */
> +#define D28IP 0x310c /* 32bit */
> +#define D28IP_P8IP 28 /* PCI Express Port 8 */
> +#define D28IP_P7IP 24 /* PCI Express Port 7 */
> +#define D28IP_P6IP 20 /* PCI Express Port 6 */
> +#define D28IP_P5IP 16 /* PCI Express Port 5 */
> +#define D28IP_P4IP 12 /* PCI Express Port 4 */
> +#define D28IP_P3IP 8 /* PCI Express Port 3 */
> +#define D28IP_P2IP 4 /* PCI Express Port 2 */
> +#define D28IP_P1IP 0 /* PCI Express Port 1 */
> +#define D27IP 0x3110 /* 32bit */
> +#define D27IP_ZIP 0 /* HD Audio Pin */
> +#define D26IP 0x3114 /* 32bit */
> +#define D26IP_E2P 0 /* EHCI #2 Pin */
> +#define D25IP 0x3118 /* 32bit */
> +#define D25IP_LIP 0 /* GbE LAN Pin */
> +#define D22IP 0x3124 /* 32bit */
> +#define D22IP_KTIP 12 /* KT Pin */
> +#define D22IP_IDERIP 8 /* IDE-R Pin */
> +#define D22IP_MEI2IP 4 /* MEI #2 Pin */
> +#define D22IP_MEI1IP 0 /* MEI #1 Pin */
> +#define D20IP 0x3128 /* 32bit */
> +#define D20IP_XHCIIP 0
> +#define D31IR 0x3140 /* 16bit */
> +#define D30IR 0x3142 /* 16bit */
> +#define D29IR 0x3144 /* 16bit */
> +#define D28IR 0x3146 /* 16bit */
> +#define D27IR 0x3148 /* 16bit */
> +#define D26IR 0x314c /* 16bit */
> +#define D25IR 0x3150 /* 16bit */
> +#define D22IR 0x315c /* 16bit */
> +#define D20IR 0x3160 /* 16bit */
> +#define OIC 0x31fe /* 16bit */
> +
> #define SPI_FREQ_SWSEQ 0x3893
> #define SPI_DESC_COMP0 0x38b0
> #define SPI_FREQ_WR_ERA 0x38b4
> #define SOFT_RESET_CTRL 0x38f4
> #define SOFT_RESET_DATA 0x38f8
>
> +#define DIR_ROUTE(a, b, c, d) \
> + (((d) << DIR_IDR) | ((c) << DIR_ICR) | \
> + ((b) << DIR_IBR) | ((a) << DIR_IAR))
> +
> #define RC 0x3400 /* 32bit */
> #define HPTC 0x3404 /* 32bit */
> #define GCS 0x3410 /* 32bit */
> @@ -142,6 +234,27 @@
> #define FD2 0x3428 /* 32bit */
> #define CG 0x341c /* 32bit */
>
> +/* Function Disable 1 RCBA 0x3418 */
> +#define PCH_DISABLE_ALWAYS ((1 << 0)|(1 << 26))
> +#define PCH_DISABLE_P2P (1 << 1)
> +#define PCH_DISABLE_SATA1 (1 << 2)
> +#define PCH_DISABLE_SMBUS (1 << 3)
> +#define PCH_DISABLE_HD_AUDIO (1 << 4)
> +#define PCH_DISABLE_EHCI2 (1 << 13)
> +#define PCH_DISABLE_LPC (1 << 14)
> +#define PCH_DISABLE_EHCI1 (1 << 15)
> +#define PCH_DISABLE_PCIE(x) (1 << (16 + x))
> +#define PCH_DISABLE_THERMAL (1 << 24)
> +#define PCH_DISABLE_SATA2 (1 << 25)
> +#define PCH_DISABLE_XHCI (1 << 27)
> +
> +/* Function Disable 2 RCBA 0x3428 */
> +#define PCH_DISABLE_KT (1 << 4)
> +#define PCH_DISABLE_IDER (1 << 3)
> +#define PCH_DISABLE_MEI2 (1 << 2)
> +#define PCH_DISABLE_MEI1 (1 << 1)
> +#define PCH_ENABLE_DBDF (1 << 0)
> +
> /* ICH7 GPIOBASE */
> #define GPIO_USE_SEL 0x00
> #define GP_IO_SEL 0x04
> diff --git a/arch/x86/include/asm/arch-ivybridge/pei_data.h b/arch/x86/include/asm/arch-ivybridge/pei_data.h
> new file mode 100644
> index 0000000..5026c8b
> --- /dev/null
> +++ b/arch/x86/include/asm/arch-ivybridge/pei_data.h
> @@ -0,0 +1,121 @@
> +/*
> + * Copyright (c) 2011, Google Inc.
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> +
> +#ifndef ASM_ARCH_PEI_DATA_H
> +#define ASM_ARCH_PEI_DATA_H
> +
> +struct pch_usb3_controller_settings {
> + /* 0: Disable, 1: Enable, 2: Auto, 3: Smart Auto */
> + uint16_t mode;
> + /* 4 bit mask, 1: switchable, 0: not switchable */
> + uint16_t hs_port_switch_mask;
> + /* 0: No xHCI preOS driver, 1: xHCI preOS driver */
> + uint16_t preboot_support;
> + /* 0: Disable, 1: Enable */
> + uint16_t xhci_streams;
> +};
> +
> +typedef asmlinkage void (*tx_byte_func)(unsigned char byte);
> +
> +#define PEI_VERSION 6
> +
> +struct __packed pei_data {
> + uint32_t pei_version;
> + uint32_t mchbar;
> + uint32_t dmibar;
> + uint32_t epbar;
> + uint32_t pciexbar;
> + uint16_t smbusbar;
> + uint32_t wdbbar;
> + uint32_t wdbsize;
> + uint32_t hpet_address;
> + uint32_t rcba;
> + uint32_t pmbase;
> + uint32_t gpiobase;
> + uint32_t thermalbase;
> + uint32_t system_type; /* 0 Mobile, 1 Desktop/Server */
> + uint32_t tseg_size;
> + uint8_t spd_addresses[4];
> + uint8_t ts_addresses[4];
> + int boot_mode;
> + int ec_present;
> + int gbe_enable;
> + /*
> + * 0 = leave channel enabled
> + * 1 = disable dimm 0 on channel
> + * 2 = disable dimm 1 on channel
> + * 3 = disable dimm 0+1 on channel
> + */
> + int dimm_channel0_disabled;
> + int dimm_channel1_disabled;
> + /* Seed values saved in CMOS */
> + uint32_t scrambler_seed;
> + uint32_t scrambler_seed_s3;
> + /* Data read from flash and passed into MRC */
> + unsigned char *mrc_input;
> + unsigned int mrc_input_len;
> + /* Data from MRC that should be saved to flash */
> + unsigned char *mrc_output;
> + unsigned int mrc_output_len;
> + /*
> + * Max frequency DDR3 could be ran at. Could be one of four values:
> + * 800, 1067, 1333, 1600
> + */
> + uint32_t max_ddr3_freq;
> + /*
> + * USB Port Configuration:
> + * [0] = enable
> + * [1] = overcurrent pin
> + * [2] = length
> + *
> + * Ports 0-7 can be mapped to OC0-OC3
> + * Ports 8-13 can be mapped to OC4-OC7
> + *
> + * Port Length
> + * MOBILE:
> + * < 0x050 = Setting 1 (back panel, 1-5in, lowest tx amplitude)
> + * < 0x140 = Setting 2 (back panel, 5-14in, highest tx amplitude)
> + * DESKTOP:
> + * < 0x080 = Setting 1 (front/back panel, <8in, lowest tx amplitude)
> + * < 0x130 = Setting 2 (back panel, 8-13in, higher tx amplitude)
> + * < 0x150 = Setting 3 (back panel, 13-15in, higest tx amplitude)
> + */
> + uint16_t usb_port_config[16][3];
> + /* See the usb3 struct above for details */
> + struct pch_usb3_controller_settings usb3;
> + /*
> + * SPD data array for onboard RAM. Specify address 0xf0,
> + * 0xf1, 0xf2, 0xf3 to index one of the 4 slots in
> + * spd_address for a given "DIMM".
> + */
> + uint8_t spd_data[4][256];
> + tx_byte_func tx_byte;
> + int ddr3lv_support;
> + /*
> + * pcie_init needs to be set to 1 to have the system agent initialise
> + * PCIe. Note: This should only be required if your system has Gen3
> + * devices and it will increase your boot time by at least 100ms.
> + */
> + int pcie_init;
> + /*
> + * N mode functionality. Leave this setting at 0.
> + * 0 Auto
> + * 1 1N
> + * 2 2N
> + */
> + int nmode;
> + /*
> + * DDR refresh rate config. JEDEC Standard No.21-C Annex K allows
> + * for DIMM SPD data to specify whether double-rate is required for
> + * extended operating temperature range.
> + * 0 Enable double rate based upon temperature thresholds
> + * 1 Normal rate
> + * 2 Always enable double rate
> + */
> + int ddr_refresh_rate_config;
> +};
> +
> +#endif
> diff --git a/arch/x86/include/asm/arch-ivybridge/sandybridge.h b/arch/x86/include/asm/arch-ivybridge/sandybridge.h
> index a1072f2..114ee19 100644
> --- a/arch/x86/include/asm/arch-ivybridge/sandybridge.h
> +++ b/arch/x86/include/asm/arch-ivybridge/sandybridge.h
> @@ -102,6 +102,8 @@
> #define SSKPD 0x5d14 /* 16bit (scratchpad) */
> #define BIOS_RESET_CPL 0x5da8 /* 8bit */
>
> +void report_platform_info(void);
> +
> void sandybridge_early_init(int chipset_type);
>
> #endif
> diff --git a/arch/x86/include/asm/config.h b/arch/x86/include/asm/config.h
> index ff15828..c97d988 100644
> --- a/arch/x86/include/asm/config.h
> +++ b/arch/x86/include/asm/config.h
> @@ -10,5 +10,6 @@
> #define CONFIG_SYS_GENERIC_BOARD
> #define CONFIG_LMB
> #define CONFIG_SYS_BOOT_RAMDISK_HIGH
> +#define asmlinkage __attribute__((regparm(0)))
>
> #endif
> diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h
> index 351581b..80bc3e8 100644
> --- a/arch/x86/include/asm/global_data.h
> +++ b/arch/x86/include/asm/global_data.h
> @@ -17,6 +17,18 @@ enum pei_boot_mode_t {
>
> };
>
> +struct memory_area {
> + uint64_t start;
> + uint64_t size;
> +};
> +
> +struct memory_info {
> + int num_areas;
> + uint64_t total_memory;
> + uint64_t total_32bit_memory;
> + struct memory_area area[CONFIG_NR_DRAM_BANKS];
> +};
> +
> /* Architecture-specific global data */
> struct arch_global_data {
> struct global_data *gd_addr; /* Location of Global Data */
> @@ -28,6 +40,7 @@ struct arch_global_data {
> struct pci_controller *hose; /* PCI hose for early use */
> enum pei_boot_mode_t pei_boot_mode;
> const struct pch_gpio_map *gpio_map; /* board GPIO map */
> + struct memory_info meminfo; /* Memory information */
> };
>
> #endif
> diff --git a/arch/x86/include/asm/post.h b/arch/x86/include/asm/post.h
> index 61dcda1..ce68839 100644
> --- a/arch/x86/include/asm/post.h
> +++ b/arch/x86/include/asm/post.h
> @@ -27,6 +27,11 @@
> #define POST_CPU_INIT 0x2b
> #define POST_EARLY_INIT 0x2c
> #define POST_CPU_INFO 0x2d
> +#define POST_PRE_MRC 0x2e
> +#define POST_MRC 0x2f
> +#define POST_DRAM 0x2f
> +
> +#define POST_RAM_FAILURE 0xea
>
> /* Output a post code using al - value must be 0 to 0xff */
> #ifdef __ASSEMBLY__
> diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h
> index 6404cd3..f20e5b5 100644
> --- a/arch/x86/include/asm/u-boot-x86.h
> +++ b/arch/x86/include/asm/u-boot-x86.h
> @@ -72,4 +72,6 @@ static inline __attribute__((no_instrument_function)) uint64_t rdtsc(void)
> void timer_set_tsc_base(uint64_t new_base);
> uint64_t timer_get_tsc(void);
>
> +void quick_ram_check(void);
> +
> #endif /* _U_BOOT_I386_H_ */
> diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
> index 25b672a..d0c7f30 100644
> --- a/arch/x86/lib/Makefile
> +++ b/arch/x86/lib/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_SYS_PCAT_TIMER) += pcat_timer.o
> obj-$(CONFIG_PCI) += pci_type1.o
> obj-y += relocate.o
> obj-y += physmem.o
> +obj-y += ramtest.o
Can we make the ramtest wrapped by CONFIG_X86_RAMTEST?
> obj-y += string.o
> obj-$(CONFIG_SYS_X86_TSC_TIMER) += tsc_timer.o
> obj-$(CONFIG_VIDEO_VGA) += video.o
> diff --git a/arch/x86/lib/ramtest.c b/arch/x86/lib/ramtest.c
> new file mode 100644
> index 0000000..c21be03
> --- /dev/null
> +++ b/arch/x86/lib/ramtest.c
> @@ -0,0 +1,79 @@
> +/*
> + * Copyright (c) 2014 Google, Inc
> + *
> + * From Coreboot src/lib/ramtest.c
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> +
> +#include <common.h>
> +#include <asm/io.h>
> +#include <asm/post.h>
> +
> +static void write_phys(unsigned long addr, u32 value)
> +{
> +#if CONFIG_SSE2
> + asm volatile(
> + "movnti %1, (%0)"
> + : /* outputs */
> + : "r" (addr), "r" (value) /* inputs */
> + : /* clobbers */
> + );
> +#else
> + writel(value, addr);
> +#endif
> +}
> +
> +static u32 read_phys(unsigned long addr)
> +{
> + return readl(addr);
> +}
> +
> +static void phys_memory_barrier(void)
> +{
> +#if CONFIG_SSE2
> + /* Needed for movnti */
> + asm volatile(
> + "sfence"
> + :
> + :
> + : "memory"
> + );
> +#else
> + asm volatile(""
> + :
> + :
> + : "memory");
> +#endif
> +}
> +
> +void quick_ram_check(void)
> +{
> + int fail = 0;
> + u32 backup;
> +
> + backup = read_phys(CONFIG_RAMBASE);
> + write_phys(CONFIG_RAMBASE, 0x55555555);
> + phys_memory_barrier();
> + if (read_phys(CONFIG_RAMBASE) != 0x55555555)
> + fail = 1;
> + write_phys(CONFIG_RAMBASE, 0xaaaaaaaa);
> + phys_memory_barrier();
> + if (read_phys(CONFIG_RAMBASE) != 0xaaaaaaaa)
> + fail = 1;
> + write_phys(CONFIG_RAMBASE, 0x00000000);
> + phys_memory_barrier();
> + if (read_phys(CONFIG_RAMBASE) != 0x00000000)
> + fail = 1;
> + write_phys(CONFIG_RAMBASE, 0xffffffff);
> + phys_memory_barrier();
> + if (read_phys(CONFIG_RAMBASE) != 0xffffffff)
> + fail = 1;
> +
> + write_phys(CONFIG_RAMBASE, backup);
> + if (fail) {
> + post_code(POST_RAM_FAILURE);
> + panic("RAM INIT FAILURE!\n");
> + }
> + phys_memory_barrier();
> +}
> diff --git a/include/configs/chromebook_link.h b/include/configs/chromebook_link.h
> index 637bdb9..64b7490 100644
> --- a/include/configs/chromebook_link.h
> +++ b/include/configs/chromebook_link.h
> @@ -18,13 +18,18 @@
> #define CONFIG_SYS_CAR_ADDR 0xff7e0000
> #define CONFIG_SYS_CAR_SIZE (128 * 1024)
> #define CONFIG_SYS_MONITOR_LEN (1 << 20)
> +#define CONFIG_DCACHE_RAM_MRC_VAR_SIZE 0x4000
> #define CONFIG_SYS_X86_START16 0xfffff800
> #define CONFIG_BOARD_EARLY_INIT_F
> #define CONFIG_BOARD_EARLY_INIT_R
> +#define CONFIG_DISPLAY_CPUINFO
>
> #define CONFIG_X86_RESET_VECTOR
> #define CONFIG_NR_DRAM_BANKS 8
>
> +#define CONFIG_X86_MRC_START 0xfffa0000
> +#define CONFIG_CACHE_MRC_SIZE_KB 512
> +
> /*
> * These common x86 features are not yet supported, but are added in
> * follow-on patches in this series. Add undefs here to avoid every patch
> diff --git a/include/configs/x86-common.h b/include/configs/x86-common.h
> index 33ff04f..6d3bcc9 100644
> --- a/include/configs/x86-common.h
> +++ b/include/configs/x86-common.h
> @@ -208,7 +208,7 @@
> #define CONFIG_SYS_STACK_SIZE (32 * 1024)
> #define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE
> #define CONFIG_SYS_MALLOC_LEN 0x200000
> -#define CONFIG_SYS_MALLOC_F_LEN (1 << 10)
> +#define CONFIG_SYS_MALLOC_F_LEN (2 << 10)
>
> /* allow to overwrite serial and ethaddr */
> #define CONFIG_ENV_OVERWRITE
> diff --git a/include/fdtdec.h b/include/fdtdec.h
> index 3bd60b7..abfd678 100644
> --- a/include/fdtdec.h
> +++ b/include/fdtdec.h
> @@ -119,6 +119,7 @@ enum fdt_compat_id {
> COMPAT_PARADE_PS8625, /* Parade PS8622 EDP->LVDS bridge */
> COMPAT_INTEL_LPC, /* Intel Low Pin Count I/F */
> COMPAT_INTEL_MICROCODE, /* Intel microcode update */
> + COMPAT_MEMORY_SPD, /* Memory SPD information */
>
> COMPAT_COUNT,
> };
> diff --git a/lib/fdtdec.c b/lib/fdtdec.c
> index 9a68f9c..aafc4f9 100644
> --- a/lib/fdtdec.c
> +++ b/lib/fdtdec.c
> @@ -74,6 +74,7 @@ static const char * const compat_names[COMPAT_COUNT] = {
> COMPAT(PARADE_PS8625, "parade,ps8625"),
> COMPAT(COMPAT_INTEL_LPC, "intel,lpc"),
> COMPAT(INTEL_MICROCODE, "intel,microcode"),
> + COMPAT(MEMORY_SPD, "memory-spd"),
> };
>
> const char *fdtdec_get_compatible(enum fdt_compat_id id)
> --
Regards,
Bin
More information about the U-Boot
mailing list