Hi Simon, On Fri, Nov 7, 2014 at 4:20 AM, Simon Glass <s...@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 <s...@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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot