mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-04 18:41:03 +00:00
65dd74a674
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>
571 lines
16 KiB
C
571 lines
16 KiB
C
/*
|
|
* Copyright (c) 2011 The Chromium OS Authors.
|
|
* (C) Copyright 2010,2011
|
|
* Graeme Russ, <graeme.russ@gmail.com>
|
|
*
|
|
* Portions from Coreboot mainboard/google/link/romstage.c
|
|
* Copyright (C) 2007-2010 coresystems GmbH
|
|
* Copyright (C) 2011 Google Inc.
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0
|
|
*/
|
|
|
|
#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)
|
|
{
|
|
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;
|
|
}
|