]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
x86: ivybridge: Implement SDRAM init
authorSimon Glass <sjg@chromium.org>
Thu, 13 Nov 2014 05:42:28 +0000 (22:42 -0700)
committerSimon Glass <sjg@chromium.org>
Fri, 21 Nov 2014 06:34:15 +0000 (07:34 +0100)
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@chromium.org>
23 files changed:
arch/x86/Kconfig
arch/x86/cpu/ivybridge/Kconfig
arch/x86/cpu/ivybridge/Makefile
arch/x86/cpu/ivybridge/early_me.c [new file with mode: 0644]
arch/x86/cpu/ivybridge/me_status.c [new file with mode: 0644]
arch/x86/cpu/ivybridge/report_platform.c [new file with mode: 0644]
arch/x86/cpu/ivybridge/sdram.c
arch/x86/cpu/start.S
arch/x86/dts/link.dts
arch/x86/include/asm/arch-ivybridge/me.h [new file with mode: 0644]
arch/x86/include/asm/arch-ivybridge/pch.h
arch/x86/include/asm/arch-ivybridge/pei_data.h [new file with mode: 0644]
arch/x86/include/asm/arch-ivybridge/sandybridge.h
arch/x86/include/asm/config.h
arch/x86/include/asm/global_data.h
arch/x86/include/asm/post.h
arch/x86/include/asm/u-boot-x86.h
arch/x86/lib/Makefile
arch/x86/lib/ramtest.c [new file with mode: 0644]
include/configs/chromebook_link.h
include/configs/x86-common.h
include/fdtdec.h
lib/fdtdec.c

index f27d731bfd86ef55ff9c2c73f5e64c46b2fa0efa..43c22ff7a5ccc3e689fcdf8dd2693e38d22f81d1 100644 (file)
@@ -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
@@ -63,6 +74,15 @@ config HAVE_INTEL_ME
          SPI flash format. You will need to supply the me.bin file in
          your board directory.
 
+config X86_RAMTEST
+       bool "Perform a simple RAM test after SDRAM initialisation"
+       help
+         If there is something wrong with SDRAM then the platform will
+         often crash within U-Boot or the kernel. This option enables a
+         very simple RAM test that quickly checks whether the SDRAM seems
+         to work correctly. It is not exhaustive but can save time by
+         detecting obvious failures.
+
 source "arch/x86/cpu/ivybridge/Kconfig"
 
 source "board/chromebook-x86/coreboot/Kconfig"
index 177247edc659da91e767b2568d96a6109ff10351..afca9579da29065bab64312c429b6a073039311f 100644 (file)
@@ -129,6 +129,7 @@ config CPU_SPECIFIC_OPTIONS
        select CPU_MICROCODE_IN_CBFS
        select TSC_SYNC_MFENCE
        select HAVE_INTEL_ME
+       select X86_RAMTEST
 
 config SMM_TSEG_SIZE
        hex
index e5c0751e6596c8199e813222b548d8dbb0e74016..721b37e628c02dbee8296be1dbca0ed847dcb322 100644 (file)
@@ -7,7 +7,10 @@
 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 += microcode_intel.o
 obj-y += pci.o
+obj-y += report_platform.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 (file)
index 0000000..b24dea1
--- /dev/null
@@ -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(PCH_DEV, PCI_CPU_MEBASE_L);
+       mebase_h = pci_read_config32(PCH_DEV, 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 (file)
index 0000000..15cf69f
--- /dev/null
@@ -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 (file)
index 0000000..69e31b3
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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/cpu.h>
+#include <asm/pci.h>
+#include <asm/arch/pch.h>
+
+static void report_cpu_info(void)
+{
+       char cpu_string[CPU_MAX_NAME_LEN], *cpu_name;
+       const char *mode[] = {"NOT ", ""};
+       struct cpuid_result cpuidr;
+       int vt, txt, aes;
+       u32 index;
+
+       index = 0x80000000;
+       cpuidr = cpuid(index);
+       if (cpuidr.eax < 0x80000004) {
+               strcpy(cpu_string, "Platform info not available");
+               cpu_name = cpu_string;
+       } else {
+               cpu_name = cpu_get_name(cpu_string);
+       }
+
+       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();
+}
index 5f9ae5ecdbcd4c62176450d3f4687171ec78ba00..df2b9901fc0cc8a64944b544699e55b7d4c8bf0f 100644 (file)
  */
 
 #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 the PEI executable in the ROM 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(PCH_DEV, 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;
 }
index 1b738f9916708c41ef176aaf79e2fa87f51e2aa0..b0d0ac0610b158be02ac05327214e7219d2f0323 100644 (file)
@@ -78,20 +78,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
index 74b21985f581767c26efd8b84ee072e496b88339..932991604f7c9503af72210faefddebbabf941b9 100644 (file)
        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];
+               };
+               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 (file)
index 0000000..3a0809d
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * 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_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
index ae338e3d92aa0bf3985e03130d30a86f82cff456..c6efdb85659ab66c70d0301c09bf3326ca7decf1 100644 (file)
 /* 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
 #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 */
 #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 (file)
index 0000000..5026c8b
--- /dev/null
@@ -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
index a1072f21e8765b214a5dd51be6960583d1acc833..114ee19e2412e8fe47a9e94e5032527865aeca40 100644 (file)
 #define SSKPD          0x5d14  /* 16bit (scratchpad) */
 #define BIOS_RESET_CPL 0x5da8  /* 8bit */
 
+void report_platform_info(void);
+
 void sandybridge_early_init(int chipset_type);
 
 #endif
index ff15828a713de5d1258aada2dc5aa599734ca900..c97d988f3be87c42fb8588a94f0824ba61fec7fb 100644 (file)
@@ -10,5 +10,6 @@
 #define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_LMB
 #define CONFIG_SYS_BOOT_RAMDISK_HIGH
+#define asmlinkage __attribute__((regparm(0)))
 
 #endif
index 4ea46d79eb2225185bab3e7e58c84e4f4811ed87..48bbd1ae43e52c80f0971e860345aaf23711f8c1 100644 (file)
@@ -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 */
@@ -34,6 +46,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
index 61dcda190a4d170eab9555358acb3eb437009c8f..ce68839decaa2cd198e4589021eec2cf8eb9afec 100644 (file)
 #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__
index 0399417e4094685bb05731945e019b0531021361..98217dd615ff3ea9661c7cb0ce78c4f68bef9a36 100644 (file)
@@ -70,4 +70,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_ */
index 25b672a0c13d831f0ddf1df0f4c17717dab8c863..e146e646cdba11a58ed50fb3d5764586d9f1a52e 100644 (file)
@@ -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-$(CONFIG_X86_RAMTEST) += ramtest.o
 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 (file)
index 0000000..c21be03
--- /dev/null
@@ -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();
+}
index 3063bd9a0f678ea067427725e4f7d0a1e0147981..8caeca64307c233bcb509bd12d3a78859140b28a 100644 (file)
 #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
 
 #define CONFIG_COREBOOT_SERIAL
 
index 825e9f78426e14eb0ad61a3344c974cd58019aa8..f16ae3291323887671945745dd7cf954c9073ee1 100644 (file)
 #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
index 3bd60b7f12286548c09f816cd910c2ece97607c8..abfd678424b5521d7cf941f1542b4dacef163cbd 100644 (file)
@@ -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,
 };
index 9a68f9ca154d69ee884e79e09f04d5ce8fb8d6e8..aafc4f931505227b71a01bbbcc8ef8850f8beac4 100644 (file)
@@ -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)