[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