Marc Jones (marc.jones@se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4015
-gerrit
commit c3ec822fcf9b8330f64c7c47e7ab964bc1d7ed50 Author: Marc Jones marc.jones@se-eng.com Date: Tue Oct 29 17:57:30 2013 -0600
Add Intel FSP northbridge support Sandybridge and Ivybridge
Add support for Sandybridge and Ivybridge using the Intel FSP. The FSP is different enough to warrant its own source files. This source handle the majority of FSP interaction.
"Intel® Firmware Support Package (Intel® FSP) provides key programming information for initializing Intel® silicon and can be easily integrated into a boot loader of the developer’s choice. It is easy to adopt, scalable to design, reduces time-to-market, and is economical to build." http://www.intel.com/content/www/us/en/intelligent-systems/intel-firmware-su...
Change-Id: Ib879c6b0fbf2eb1cbf929a87f592df29ac48bcc5 Signed-off-by: Marc Jones marc.jones@se-eng.com --- src/include/cbmem.h | 1 + src/northbridge/intel/Kconfig | 1 + src/northbridge/intel/Makefile.inc | 2 + src/northbridge/intel/fsp_sandybridge/Kconfig | 123 ++++++ src/northbridge/intel/fsp_sandybridge/Makefile.inc | 69 ++++ src/northbridge/intel/fsp_sandybridge/acpi.c | 202 ++++++++++ .../intel/fsp_sandybridge/acpi/hostbridge.asl | 361 +++++++++++++++++ src/northbridge/intel/fsp_sandybridge/acpi/igd.asl | 324 +++++++++++++++ .../intel/fsp_sandybridge/acpi/sandybridge.asl | 59 +++ src/northbridge/intel/fsp_sandybridge/chip.h | 42 ++ src/northbridge/intel/fsp_sandybridge/early_init.c | 88 +++++ src/northbridge/intel/fsp_sandybridge/finalize.c | 56 +++ src/northbridge/intel/fsp_sandybridge/fsp_util.c | 413 +++++++++++++++++++ src/northbridge/intel/fsp_sandybridge/fsp_util.h | 101 +++++ src/northbridge/intel/fsp_sandybridge/gma.c | 88 +++++ src/northbridge/intel/fsp_sandybridge/gma.h | 168 ++++++++ src/northbridge/intel/fsp_sandybridge/mrccache.c | 257 ++++++++++++ .../intel/fsp_sandybridge/northbridge.c | 437 +++++++++++++++++++++ .../intel/fsp_sandybridge/northbridge.h | 245 ++++++++++++ src/northbridge/intel/fsp_sandybridge/raminit.c | 84 ++++ src/northbridge/intel/fsp_sandybridge/raminit.h | 25 ++ .../intel/fsp_sandybridge/report_platform.c | 114 ++++++ src/northbridge/intel/fsp_sandybridge/udelay.c | 55 +++ 23 files changed, 3315 insertions(+)
diff --git a/src/include/cbmem.h b/src/include/cbmem.h index b3d3fff..0c32111 100644 --- a/src/include/cbmem.h +++ b/src/include/cbmem.h @@ -73,6 +73,7 @@ #define CBMEM_ID_EHCI_DEBUG 0xe4c1deb9 #define CBMEM_ID_NONE 0x00000000 #define CBMEM_ID_AGESA_RUNTIME 0x41474553 +#define CBMEM_ID_HOB_POINTER 0x484f4221
#ifndef __ASSEMBLER__ #include <stdint.h> diff --git a/src/northbridge/intel/Kconfig b/src/northbridge/intel/Kconfig index a20f7b0..c57f25d 100644 --- a/src/northbridge/intel/Kconfig +++ b/src/northbridge/intel/Kconfig @@ -14,3 +14,4 @@ source src/northbridge/intel/sch/Kconfig source src/northbridge/intel/i5000/Kconfig source src/northbridge/intel/sandybridge/Kconfig source src/northbridge/intel/haswell/Kconfig +source src/northbridge/intel/fsp_sandybridge/Kconfig diff --git a/src/northbridge/intel/Makefile.inc b/src/northbridge/intel/Makefile.inc index 62e427d..f460850 100644 --- a/src/northbridge/intel/Makefile.inc +++ b/src/northbridge/intel/Makefile.inc @@ -15,3 +15,5 @@ subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I5000) += i5000 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += sandybridge subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += sandybridge subdirs-$(CONFIG_NORTHBRIDGE_INTEL_HASWELL) += haswell +subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_SANDYBRIDGE) += fsp_sandybridge +subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_IVYBRIDGE) += fsp_sandybridge diff --git a/src/northbridge/intel/fsp_sandybridge/Kconfig b/src/northbridge/intel/fsp_sandybridge/Kconfig new file mode 100644 index 0000000..9308d04 --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/Kconfig @@ -0,0 +1,123 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2010 Google Inc. +## Copyright (C) 2013 Sage Electronic Engineering, LLC. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; version 2 of the License. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +config NORTHBRIDGE_INTEL_FSP_SANDYBRIDGE + bool + select CPU_INTEL_FSP_MODEL_206AX + +config NORTHBRIDGE_INTEL_FSP_IVYBRIDGE + bool + select CPU_INTEL_FSP_MODEL_306AX + +if NORTHBRIDGE_INTEL_FSP_IVYBRIDGE || NORTHBRIDGE_INTEL_FSP_SANDYBRIDGE + +config HAVE_FSP_BIN + bool "Use Intel Firmware Support Package" + help + Select this option to add an Intel FSP binary to + the resulting coreboot image. + + Note: Without this binary, coreboot builds relying on the FSP + will not boot + +config VGA_BIOS_ID + string + default "8086,0106" + help + This is the default PCI ID for the sandybridge/ivybridge graphics + devices. This string names the vbios rom in cbfs. The following + PCI IDs will be remapped to load this rom: + 0x80860102, 0x8086010a, 0x80860112, 0x80860116 + 0x80860122, 0x80860126, 0x80860166 + +config DCACHE_RAM_BASE + hex + default 0xff7f0000 + +config DCACHE_RAM_SIZE + hex + default 0x10000 + + +if HAVE_FSP_BIN + +config FSP_FILE + string "Intel FSP binary path and filename" + default "../intel/fsp/ivybridge_bd82x6x/FvFsp.bin" if CPU_INTEL_FSP_MODEL_306AX && SOUTHBRIDGE_INTEL_FSP_BD82X6X + default "../intel/fsp/ivybridge_i89xx/FvFsp.bin" if CPU_INTEL_FSP_MODEL_306AX && SOUTHBRIDGE_INTEL_FSP_I89XX + default "../intel/fsp/sandybridge_i89xx/FvFsp.bin" if CPU_INTEL_FSP_MODEL_206AX && SOUTHBRIDGE_INTEL_FSP_I89XX + help + The path and filename of the Intel FSP binary for this platform. + +config FSP_LOC + hex "Intel FSP Binary location in cbfs" + default 0xfff80000 + help + The location in cbfs that the FSP is located. This must match the + value that is set in the FSP binary. If the FSP needs to be moved, + rebase the FSP with the Intel's BCT (tool). + +config CBFS_SIZE + hex "Size of CBFS filesystem in ROM" + default 0x100000 + help + On Sandybridge and Ivybridge systems the firmware image may + have to store a lot more than just coreboot, including: + - a firmware descriptor + - Intel Management Engine firmware + This option specifies the maximum size of the CBFS portion in the + firmware image. + +config ENABLE_FAST_BOOT + bool "Enable Fast Boot" + default y if CPU_INTEL_FSP_MODEL_306AX && SOUTHBRIDGE_INTEL_FSP_BD82X6X + depends on !CACHE_ROM + help + Enabling this feature will cause MRC data to be cached in NV storage + which will speed up boot time on future reboots and/or power cycles. + + WARNING: This feature combined with the CACHE_ROM may result in undefined + behavior. + +config MRC_CACHE_SIZE + hex "MRC Data Cache Size" + default 0x10000 + depends on ENABLE_FAST_BOOT + help + This is the amount of space in NV storage that is reserved for MRC data + cache storage when using fast boot. + +config VIRTUAL_ROM_SIZE + hex "Virtual ROM Size" + default ROM_SIZE + depends on ENABLE_FAST_BOOT + help + This is used to calculate the offset of the MRC data cache in NV + Storage for "Fast Boot". If in doubt, leave this set to the default + which sets the virtual size equal to the ROM size. + + Example: Cougar Canyon 2 has 2 8 MB SPI ROMs. When the SPI ROMs are + loaded with a 4 MB coreboot image, the virtual ROM size is 8 MB. When + the SPI ROMs are loaded with an 8 MB coreboot image, the virtual ROM + size is 16 MB. + +endif # HAVE_FSP_BIN + +endif # NORTHBRIDGE_INTEL_FSP_IVYBRIDGE || NORTHBRIDGE_INTEL_FSP_SANDYBRIDGE diff --git a/src/northbridge/intel/fsp_sandybridge/Makefile.inc b/src/northbridge/intel/fsp_sandybridge/Makefile.inc new file mode 100644 index 0000000..1ab7cf4 --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/Makefile.inc @@ -0,0 +1,69 @@ +# +# This file is part of the coreboot project. +# +# Copyright (C) 2010 Google Inc. +# Copyright (C) 2013 Sage Electronic Engineering, LLC. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +ramstage-y += northbridge.c +ramstage-y += gma.c + +ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c +ramstage-$(CONFIG_HAVE_FSP_BIN) += fsp_util.c +ramstage-$(CONFIG_ENABLE_FAST_BOOT) += mrccache.c + +romstage-y += raminit.c +romstage-$(CONFIG_HAVE_FSP_BIN) += fsp_util.c +romstage-y += early_init.c +romstage-y += report_platform.c +romstage-y += ../../../arch/x86/lib/walkcbfs.S +romstage-$(CONFIG_ENABLE_FAST_BOOT) += mrccache.c + +smm-$(CONFIG_HAVE_SMI_HANDLER) += udelay.c +smm-$(CONFIG_HAVE_SMI_HANDLER) += finalize.c + +CC := $(CC) -I$(src)/mainboard/$(MAINBOARDDIR) + +ifeq ($(CONFIG_HAVE_FSP_BIN),y) +CC := $(CC) -I$(dir $(call strip_quotes,$(CONFIG_FSP_FILE)))include + +ramstage-y += $(top)/$(obj)/northbridge/intel/fsp_sandybridge/fsphob.c + +# Move the required FSP src files to the northbridge build directory +$(obj)/northbridge/intel/fsp_sandybridge/fsphob.c: $(dir $(call strip_quotes,$(CONFIG_FSP_FILE)))src/fsphob.c + cp $(dir $(call strip_quotes,$(CONFIG_FSP_FILE)))src/fsphob.c $(obj)/northbridge/intel/fsp_sandybridge/fsphob.c + +# We don't ship an FSP, but booting without it is bound to fail +cbfs-files-y += fsp.bin +fsp.bin-file := $(call strip_quotes,$(CONFIG_FSP_FILE)) +fsp.bin-position := $(CONFIG_FSP_LOC) +fsp.bin-type := 0xab +endif + +ifeq ($(CONFIG_ENABLE_FAST_BOOT),y) +$(obj)/mrc.cache: + dd if=/dev/zero count=1 \ + bs=$(shell printf "%d" $(CONFIG_MRC_CACHE_SIZE) ) | \ + tr '\000' '\377' > $@ + +cbfs-files-y += mrc.cache +mrc.cache-file := $(obj)/mrc.cache +mrc.cache-position := 0xfff50000 +mrc.cache-type := 0xac +endif + + +$(obj)/northbridge/intel/fsp_sandybridge/acpi.ramstage.o : $(obj)/build.h diff --git a/src/northbridge/intel/fsp_sandybridge/acpi.c b/src/northbridge/intel/fsp_sandybridge/acpi.c new file mode 100644 index 0000000..3c15615 --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/acpi.c @@ -0,0 +1,202 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2012 The Chromium OS Authors + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <types.h> +#include <string.h> +#include <console/console.h> +#include <arch/io.h> +#include <arch/acpi.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <build.h> +#include "northbridge.h" + +unsigned long acpi_fill_mcfg(unsigned long current) +{ + device_t dev; + u32 pciexbar = 0; + u32 pciexbar_reg; + int max_buses; + + dev = dev_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SB, 0); + if (!dev) + dev = dev_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_IB, 0); + if (!dev) + return current; + + pciexbar_reg=pci_read_config32(dev, PCIEXBAR); + + // MMCFG not supported or not enabled. + if (!(pciexbar_reg & (1 << 0))) + return current; + + switch ((pciexbar_reg >> 1) & 3) { + case 0: // 256MB + pciexbar = pciexbar_reg & ((1 << 31)|(1 << 30)|(1 << 29)|(1 << 28)); + max_buses = 256; + break; + case 1: // 128M + pciexbar = pciexbar_reg & ((1 << 31)|(1 << 30)|(1 << 29)|(1 << 28)|(1 << 27)); + max_buses = 128; + break; + case 2: // 64M + pciexbar = pciexbar_reg & ((1 << 31)|(1 << 30)|(1 << 29)|(1 << 28)|(1 << 27)|(1 << 26)); + max_buses = 64; + break; + default: // RSVD + return current; + } + + if (!pciexbar) + return current; + + current += acpi_create_mcfg_mmconfig((acpi_mcfg_mmconfig_t *) current, + pciexbar, 0x0, 0x0, max_buses - 1); + + return current; +} + +static void *get_intel_vbios(void) +{ + /* This should probably be looking at CBFS or we should always + * deploy the VBIOS on Intel systems, even if we don't run it + * in coreboot (e.g. SeaBIOS only scenarios). + */ + u8 *vbios = (u8 *)0xc0000; + + optionrom_header_t *oprom = (optionrom_header_t *)vbios; + optionrom_pcir_t *pcir = (optionrom_pcir_t *)(vbios + + oprom->pcir_offset); + + + printk(BIOS_DEBUG, "GET_VBIOS: %x %x %x %x %x\n", + oprom->signature, pcir->vendor, pcir->classcode[0], + pcir->classcode[1], pcir->classcode[2]); + + + if ((oprom->signature == OPROM_SIGNATURE) && + (pcir->vendor == PCI_VENDOR_ID_INTEL) && + (pcir->classcode[0] == 0x00) && + (pcir->classcode[1] == 0x00) && + (pcir->classcode[2] == 0x03)) + return (void *)vbios; + + return NULL; +} + +static int init_opregion_vbt(igd_opregion_t *opregion) +{ + void *vbios; + vbios = get_intel_vbios(); + if (!vbios) { + printk(BIOS_DEBUG, "VBIOS not found.\n"); + return 1; + } + + printk(BIOS_DEBUG, " ... VBIOS found at %p\n", vbios); + optionrom_header_t *oprom = (optionrom_header_t *)vbios; + optionrom_vbt_t *vbt = (optionrom_vbt_t *)(vbios + + oprom->vbt_offset); + + if (read32((unsigned long)vbt->hdr_signature) != VBT_SIGNATURE) { + printk(BIOS_DEBUG, "VBT not found!\n"); + return 1; + } + + memcpy(opregion->header.vbios_version, vbt->coreblock_biosbuild, 4); + memcpy(opregion->vbt.gvd1, vbt, vbt->hdr_vbt_size < 7168 ? + vbt->hdr_vbt_size : 7168); + + return 0; +} + + +/* Initialize IGD OpRegion, called from ACPI code */ +int init_igd_opregion(igd_opregion_t *opregion) +{ + device_t igd; + u16 reg16; + + memset((void *)opregion, 0, sizeof(igd_opregion_t)); + + // FIXME if IGD is disabled, we should exit here. + + memcpy(&opregion->header.signature, IGD_OPREGION_SIGNATURE, + sizeof(IGD_OPREGION_SIGNATURE)); + + /* 8kb */ + opregion->header.size = sizeof(igd_opregion_t) / 1024; + opregion->header.version = IGD_OPREGION_VERSION; + + // FIXME We just assume we're mobile for now + opregion->header.mailboxes = MAILBOXES_MOBILE; + + // TODO Initialize Mailbox 1 + + // TODO Initialize Mailbox 3 + opregion->mailbox3.bclp = IGD_BACKLIGHT_BRIGHTNESS; + opregion->mailbox3.pfit = IGD_FIELD_VALID | IGD_PFIT_STRETCH; + opregion->mailbox3.pcft = 0; // should be (IMON << 1) & 0x3e + opregion->mailbox3.cblv = IGD_FIELD_VALID | IGD_INITIAL_BRIGHTNESS; + opregion->mailbox3.bclm[0] = IGD_WORD_FIELD_VALID + 0x0000; + opregion->mailbox3.bclm[1] = IGD_WORD_FIELD_VALID + 0x0a19; + opregion->mailbox3.bclm[2] = IGD_WORD_FIELD_VALID + 0x1433; + opregion->mailbox3.bclm[3] = IGD_WORD_FIELD_VALID + 0x1e4c; + opregion->mailbox3.bclm[4] = IGD_WORD_FIELD_VALID + 0x2866; + opregion->mailbox3.bclm[5] = IGD_WORD_FIELD_VALID + 0x327f; + opregion->mailbox3.bclm[6] = IGD_WORD_FIELD_VALID + 0x3c99; + opregion->mailbox3.bclm[7] = IGD_WORD_FIELD_VALID + 0x46b2; + opregion->mailbox3.bclm[8] = IGD_WORD_FIELD_VALID + 0x50cc; + opregion->mailbox3.bclm[9] = IGD_WORD_FIELD_VALID + 0x5ae5; + opregion->mailbox3.bclm[10] = IGD_WORD_FIELD_VALID + 0x64ff; + + init_opregion_vbt(opregion); + + /* TODO This needs to happen in S3 resume, too. + * Maybe it should move to the finalize handler + */ + igd = dev_find_slot(0, PCI_DEVFN(0x2, 0)); + + pci_write_config32(igd, ASLS, (u32)opregion); + reg16 = pci_read_config16(igd, SWSCI); + reg16 &= ~(1 << 0); + reg16 |= (1 << 15); + pci_write_config16(igd, SWSCI, reg16); + + /* clear dmisci status */ + reg16 = inw(DEFAULT_PMBASE + TCO1_STS); + reg16 |= DMISCI_STS; // reference code does an &= + outw(DEFAULT_PMBASE + TCO1_STS, reg16); + + /* clear acpi tco status */ + outl(DEFAULT_PMBASE + GPE0_STS, TCOSCI_STS); + + /* enable acpi tco scis */ + reg16 = inw(DEFAULT_PMBASE + GPE0_EN); + reg16 |= TCOSCI_EN; + outw(DEFAULT_PMBASE + GPE0_EN, reg16); + + return 0; +} + + diff --git a/src/northbridge/intel/fsp_sandybridge/acpi/hostbridge.asl b/src/northbridge/intel/fsp_sandybridge/acpi/hostbridge.asl new file mode 100644 index 0000000..1a15d81 --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/acpi/hostbridge.asl @@ -0,0 +1,361 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + + +Name(_HID,EISAID("PNP0A08")) // PCIe +Name(_CID,EISAID("PNP0A03")) // PCI + +Name(_ADR, 0) +Name(_BBN, 0) + +Device (MCHC) +{ + Name(_ADR, 0x00000000) // 0:0.0 + + OperationRegion(MCHP, PCI_Config, 0x00, 0x100) + Field (MCHP, DWordAcc, NoLock, Preserve) + { + Offset (0x40), // EPBAR + EPEN, 1, // Enable + , 11, // + EPBR, 24, // EPBAR + + Offset (0x48), // MCHBAR + MHEN, 1, // Enable + , 13, // + MHBR, 22, // MCHBAR + + Offset (0x60), // PCIe BAR + PXEN, 1, // Enable + PXSZ, 2, // BAR size + , 23, // + PXBR, 10, // PCIe BAR + + Offset (0x68), // DMIBAR + DMEN, 1, // Enable + , 11, // + DMBR, 24, // DMIBAR + + Offset (0x70), // ME Base Address + MEBA, 64, + + // ... + + Offset (0x80), // PAM0 + , 4, + PM0H, 2, + , 2, + Offset (0x81), // PAM1 + PM1L, 2, + , 2, + PM1H, 2, + , 2, + Offset (0x82), // PAM2 + PM2L, 2, + , 2, + PM2H, 2, + , 2, + Offset (0x83), // PAM3 + PM3L, 2, + , 2, + PM3H, 2, + , 2, + Offset (0x84), // PAM4 + PM4L, 2, + , 2, + PM4H, 2, + , 2, + Offset (0x85), // PAM5 + PM5L, 2, + , 2, + PM5H, 2, + , 2, + Offset (0x86), // PAM6 + PM6L, 2, + , 2, + PM6H, 2, + , 2, + + Offset (0xa0), // Top of Used Memory + TOM, 64, + + Offset (0xbc), // Top of Low Used Memory + TLUD, 32, + } + + Mutex (CTCM, 1) /* CTDP Switch Mutex (sync level 1) */ + Name (CTCC, 0) /* CTDP Current Selection */ + Name (CTCN, 0) /* CTDP Nominal Select */ + Name (CTCD, 1) /* CTDP Down Select */ + Name (CTCU, 2) /* CTDP Up Select */ + + OperationRegion (MCHB, SystemMemory, DEFAULT_MCHBAR, 0x8000) + Field (MCHB, DWordAcc, Lock, Preserve) + { + Offset (0x5930), + CTDN, 15, /* CTDP Nominal PL1 */ + Offset (0x59a0), + PL1V, 15, /* Power Limit 1 Value */ + PL1E, 1, /* Power Limit 1 Enable */ + PL1C, 1, /* Power Limit 1 Clamp */ + PL1T, 7, /* Power Limit 1 Time */ + Offset (0x59a4), + PL2V, 15, /* Power Limit 2 Value */ + PL2E, 1, /* Power Limit 2 Enable */ + PL2C, 1, /* Power Limit 2 Clamp */ + PL2T, 7, /* Power Limit 2 Time */ + Offset (0x5f3c), + TARN, 8, /* CTDP Nominal Turbo Activation Ratio */ + Offset (0x5f40), + CTDD, 15, /* CTDP Down PL1 */ + , 1, + TARD, 8, /* CTDP Down Turbo Activation Ratio */ + Offset (0x5f48), + CTDU, 15, /* CTDP Up PL1 */ + , 1, + TARU, 8, /* CTDP Up Turbo Activation Ratio */ + Offset (0x5f50), + CTCS, 2, /* CTDP Select */ + Offset (0x5f54), + TARS, 8, /* Turbo Activation Ratio Select */ + } + + /* + * Search CPU0 _PSS looking for control=arg0 and then + * return previous P-state entry number for new _PPC + * + * Format of _PSS: + * Name (_PSS, Package () { + * Package (6) { freq, power, tlat, blat, control, status } + * } + */ + External (_PR.CPU0._PSS) + Method (PSSS, 1, NotSerialized) + { + Store (One, Local0) /* Start at P1 */ + Store (SizeOf (_PR.CPU0._PSS), Local1) + + While (LLess (Local0, Local1)) { + /* Store _PSS entry Control value to Local2 */ + ShiftRight (DeRefOf (Index (DeRefOf (Index + (_PR.CPU0._PSS, Local0)), 4)), 8, Local2) + If (LEqual (Local2, Arg0)) { + Return (Subtract (Local0, 1)) + } + Increment (Local0) + } + + Return (0) + } + + /* Set TDP Down */ + Method (STND, 0, Serialized) + { + If (Acquire (CTCM, 100)) { + Return (0) + } + If (LEqual (CTCD, CTCC)) { + Release (CTCM) + Return (0) + } + + Store ("Set TDP Down", Debug) + + /* Set CTC */ + Store (CTCD, CTCS) + + /* Set TAR */ + Store (TARD, TARS) + + /* Set PPC limit and notify OS */ + Store (PSSS (TARD), PPCM) + PPCN () + + /* Set PL2 to 1.25 * PL1 */ + Divide (Multiply (CTDD, 125), 100, Local0, PL2V) + + /* Set PL1 */ + Store (CTDD, PL1V) + + /* Store the new TDP Down setting */ + Store (CTCD, CTCC) + + Release (CTCM) + Return (1) + } + + /* Set TDP Nominal from Down */ + Method (STDN, 0, Serialized) + { + If (Acquire (CTCM, 100)) { + Return (0) + } + If (LEqual (CTCN, CTCC)) { + Release (CTCM) + Return (0) + } + + Store ("Set TDP Nominal", Debug) + + /* Set PL1 */ + Store (CTDN, PL1V) + + /* Set PL2 to 1.25 * PL1 */ + Divide (Multiply (CTDN, 125), 100, Local0, PL2V) + + /* Set PPC limit and notify OS */ + Store (PSSS (TARN), PPCM) + PPCN () + + /* Set TAR */ + Store (TARN, TARS) + + /* Set CTC */ + Store (CTCN, CTCS) + + /* Store the new TDP Nominal setting */ + Store (CTCN, CTCC) + + Release (CTCM) + Return (1) + } +} + +// Current Resource Settings + +Method (_CRS, 0, Serialized) +{ + Name (MCRS, ResourceTemplate() + { + // Bus Numbers + WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, + 0x0000, 0x0000, 0x00ff, 0x0000, 0x0100,,, PB00) + + // IO Region 0 + DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, 0x0000, 0x0cf7, 0x0000, 0x0cf8,,, PI00) + + // PCI Config Space + Io (Decode16, 0x0cf8, 0x0cf8, 0x0001, 0x0008) + + // IO Region 1 + DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, 0x0d00, 0xffff, 0x0000, 0xf300,,, PI01) + + // VGA memory (0xa0000-0xbffff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000a0000, 0x000bffff, 0x00000000, + 0x00020000,,, ASEG) + + // OPROM reserved (0xd0000-0xd3fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000d0000, 0x000d3fff, 0x00000000, + 0x00004000,,, OPR0) + + // OPROM reserved (0xd4000-0xd7fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000d4000, 0x000d7fff, 0x00000000, + 0x00004000,,, OPR1) + + // OPROM reserved (0xd8000-0xdbfff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000d8000, 0x000dbfff, 0x00000000, + 0x00004000,,, OPR2) + + // OPROM reserved (0xdc000-0xdffff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000dc000, 0x000dffff, 0x00000000, + 0x00004000,,, OPR3) + + // BIOS Extension (0xe0000-0xe3fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000e0000, 0x000e3fff, 0x00000000, + 0x00004000,,, ESG0) + + // BIOS Extension (0xe4000-0xe7fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000e4000, 0x000e7fff, 0x00000000, + 0x00004000,,, ESG1) + + // BIOS Extension (0xe8000-0xebfff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000e8000, 0x000ebfff, 0x00000000, + 0x00004000,,, ESG2) + + // BIOS Extension (0xec000-0xeffff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000ec000, 0x000effff, 0x00000000, + 0x00004000,,, ESG3) + + // System BIOS (0xf0000-0xfffff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000f0000, 0x000fffff, 0x00000000, + 0x00010000,,, FSEG) + + // PCI Memory Region (Top of memory-0xfebfffff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x00000000, 0xfebfffff, 0x00000000, + 0xfec00000,,, PM01) + + // TPM Area (0xfed40000-0xfed44fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0xfed40000, 0xfed44fff, 0x00000000, + 0x00005000,,, TPMR) + }) + + // Find PCI resource area in MCRS + CreateDwordField(MCRS, PM01._MIN, PMIN) + CreateDwordField(MCRS, PM01._MAX, PMAX) + CreateDwordField(MCRS, PM01._LEN, PLEN) + + // Fix up PCI memory region + // Start with Top of Lower Usable DRAM + Store (^MCHC.TLUD, Local0) + Store (^MCHC.MEBA, Local1) + + // Check if ME base is equal + If (LEqual (Local0, Local1)) { + // Use Top Of Memory instead + Store (^MCHC.TOM, Local0) + } + + Store (Local0, PMIN) + Add(Subtract(PMAX, PMIN), 1, PLEN) + + Return (MCRS) +} + +/* IRQ assignment is mainboard specific. Get it from mainboard ACPI code */ +#include "acpi/hostbridge_pci_irqs.asl" + + diff --git a/src/northbridge/intel/fsp_sandybridge/acpi/igd.asl b/src/northbridge/intel/fsp_sandybridge/acpi/igd.asl new file mode 100644 index 0000000..a6804ad --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/acpi/igd.asl @@ -0,0 +1,324 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +Device (GFX0) +{ + Name (_ADR, 0x00020000) + + /* Display Output Switching */ + Method (_DOS, 1) + { + /* Windows 2000 and Windows XP call _DOS to enable/disable + * Display Output Switching during init and while a switch + * is already active + */ + Store (And(Arg0, 7), DSEN) + } + + /* We try to support as many i945 systems as possible, + * so keep the number of DIDs flexible. + */ + Method (_DOD, 0) + { + If (LEqual(NDID, 1)) { + Name(DOD1, Package() { + 0xffffffff + }) + Store (Or(0x00010000, DID1), Index(DOD1, 0)) + Return(DOD1) + } + + If (LEqual(NDID, 2)) { + Name(DOD2, Package() { + 0xffffffff, + 0xffffffff + }) + Store (Or(0x00010000, DID2), Index(DOD2, 0)) + Store (Or(0x00010000, DID2), Index(DOD2, 1)) + Return(DOD2) + } + + If (LEqual(NDID, 3)) { + Name(DOD3, Package() { + 0xffffffff, + 0xffffffff, + 0xffffffff + }) + Store (Or(0x00010000, DID3), Index(DOD3, 0)) + Store (Or(0x00010000, DID3), Index(DOD3, 1)) + Store (Or(0x00010000, DID3), Index(DOD3, 2)) + Return(DOD3) + } + + If (LEqual(NDID, 4)) { + Name(DOD4, Package() { + 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff + }) + Store (Or(0x00010000, DID4), Index(DOD4, 0)) + Store (Or(0x00010000, DID4), Index(DOD4, 1)) + Store (Or(0x00010000, DID4), Index(DOD4, 2)) + Store (Or(0x00010000, DID4), Index(DOD4, 3)) + Return(DOD4) + } + + If (LGreater(NDID, 4)) { + Name(DOD5, Package() { + 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff + }) + Store (Or(0x00010000, DID5), Index(DOD5, 0)) + Store (Or(0x00010000, DID5), Index(DOD5, 1)) + Store (Or(0x00010000, DID5), Index(DOD5, 2)) + Store (Or(0x00010000, DID5), Index(DOD5, 3)) + Store (Or(0x00010000, DID5), Index(DOD5, 4)) + Return(DOD5) + } + + /* Some error happened, but we have to return something */ + Return (Package() {0x00000400}) + } + + Device(DD01) + { + /* Device Unique ID */ + Method(_ADR, 0, Serialized) + { + If(LEqual(DID1, 0)) { + Return (1) + } Else { + Return (And(0xffff, DID1)) + } + } + + /* Device Current Status */ + Method(_DCS, 0) + { + TRAP(1) + If (And(CSTE, 1)) { + Return (0x1f) + } + Return(0x1d) + } + + /* Query Device Graphics State */ + Method(_DGS, 0) + { + If (And(NSTE, 1)) { + Return(1) + } + Return(0) + } + + /* Device Set State */ + Method(_DSS, 1) + { + /* If Parameter Arg0 is (1 << 31) | (1 << 30), the + * display switch was completed + */ + If (LEqual(And(Arg0, 0xc0000000), 0xc0000000)) { + Store (NSTE, CSTE) + } + } + } + + Device(DD02) + { + /* Device Unique ID */ + Method(_ADR, 0, Serialized) + { + If(LEqual(DID2, 0)) { + Return (2) + } Else { + Return (And(0xffff, DID2)) + } + } + + /* Device Current Status */ + Method(_DCS, 0) + { + TRAP(1) + If (And(CSTE, 2)) { + Return (0x1f) + } + Return(0x1d) + } + + /* Query Device Graphics State */ + Method(_DGS, 0) + { + If (And(NSTE, 2)) { + Return(1) + } + Return(0) + } + + /* Device Set State */ + Method(_DSS, 1) + { + /* If Parameter Arg0 is (1 << 31) | (1 << 30), the + * display switch was completed + */ + If (LEqual(And(Arg0, 0xc0000000), 0xc0000000)) { + Store (NSTE, CSTE) + } + } + } + + + Device(DD03) + { + /* Device Unique ID */ + Method(_ADR, 0, Serialized) + { + If(LEqual(DID3, 0)) { + Return (3) + } Else { + Return (And(0xffff, DID3)) + } + } + + /* Device Current Status */ + Method(_DCS, 0) + { + TRAP(1) + If (And(CSTE, 4)) { + Return (0x1f) + } + Return(0x1d) + } + + /* Query Device Graphics State */ + Method(_DGS, 0) + { + If (And(NSTE, 4)) { + Return(1) + } + Return(0) + } + + /* Device Set State */ + Method(_DSS, 1) + { + /* If Parameter Arg0 is (1 << 31) | (1 << 30), the + * display switch was completed + */ + If (LEqual(And(Arg0, 0xc0000000), 0xc0000000)) { + Store (NSTE, CSTE) + } + } + } + + + Device(DD04) + { + /* Device Unique ID */ + Method(_ADR, 0, Serialized) + { + If(LEqual(DID4, 0)) { + Return (4) + } Else { + Return (And(0xffff, DID4)) + } + } + + /* Device Current Status */ + Method(_DCS, 0) + { + TRAP(1) + If (And(CSTE, 8)) { + Return (0x1f) + } + Return(0x1d) + } + + /* Query Device Graphics State */ + Method(_DGS, 0) + { + If (And(NSTE, 4)) { + Return(1) + } + Return(0) + } + + /* Device Set State */ + Method(_DSS, 1) + { + /* If Parameter Arg0 is (1 << 31) | (1 << 30), the + * display switch was completed + */ + If (LEqual(And(Arg0, 0xc0000000), 0xc0000000)) { + Store (NSTE, CSTE) + } + } + } + + + Device(DD05) + { + /* Device Unique ID */ + Method(_ADR, 0, Serialized) + { + If(LEqual(DID5, 0)) { + Return (5) + } Else { + Return (And(0xffff, DID5)) + } + } + + /* Device Current Status */ + Method(_DCS, 0) + { + TRAP(1) + If (And(CSTE, 16)) { + Return (0x1f) + } + Return(0x1d) + } + + /* Query Device Graphics State */ + Method(_DGS, 0) + { + If (And(NSTE, 4)) { + Return(1) + } + Return(0) + } + + /* Device Set State */ + Method(_DSS, 1) + { + /* If Parameter Arg0 is (1 << 31) | (1 << 30), the + * display switch was completed + */ + If (LEqual(And(Arg0, 0xc0000000), 0xc0000000)) { + Store (NSTE, CSTE) + } + } + } + +} + diff --git a/src/northbridge/intel/fsp_sandybridge/acpi/sandybridge.asl b/src/northbridge/intel/fsp_sandybridge/acpi/sandybridge.asl new file mode 100644 index 0000000..7d51135 --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/acpi/sandybridge.asl @@ -0,0 +1,59 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "../northbridge.h" +#include "hostbridge.asl" + +/* PCI Device Resource Consumption */ +Device (PDRC) +{ + Name (_HID, EISAID("PNP0C02")) + Name (_UID, 1) + + Name (PDRS, ResourceTemplate() { + Memory32Fixed(ReadWrite, 0xfed1c000, 0x00004000) // RCBA + Memory32Fixed(ReadWrite, DEFAULT_MCHBAR, 0x00004000) + Memory32Fixed(ReadWrite, DEFAULT_DMIBAR, 0x00001000) + Memory32Fixed(ReadWrite, DEFAULT_EPBAR, 0x00001000) + Memory32Fixed(ReadWrite, DEFAULT_PCIEXBAR, 0x04000000) + Memory32Fixed(ReadWrite, 0xfed20000, 0x00020000) // Misc ICH + Memory32Fixed(ReadWrite, 0xfed40000, 0x00005000) // Misc ICH + Memory32Fixed(ReadWrite, 0xfed45000, 0x0004b000) // Misc ICH + +#if CONFIG_CHROMEOS_RAMOOPS + Memory32Fixed(ReadWrite, CONFIG_CHROMEOS_RAMOOPS_RAM_START, + CONFIG_CHROMEOS_RAMOOPS_RAM_SIZE) +#endif + + /* Required for SandyBridge sighting 3715511 */ + Memory32Fixed(ReadWrite, 0x20000000, 0x00200000) + Memory32Fixed(ReadWrite, 0x40000000, 0x00200000) + }) + + // Current Resource Settings + Method (_CRS, 0, Serialized) + { + Return(PDRS) + } +} + +// Integrated graphics 0:2.0 +#include "igd.asl" diff --git a/src/northbridge/intel/fsp_sandybridge/chip.h b/src/northbridge/intel/fsp_sandybridge/chip.h new file mode 100644 index 0000000..7e6c1d8 --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/chip.h @@ -0,0 +1,42 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2008 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * Digital Port Hotplug Enable: + * 0x04 = Enabled, 2ms short pulse + * 0x05 = Enabled, 4.5ms short pulse + * 0x06 = Enabled, 6ms short pulse + * 0x07 = Enabled, 100ms short pulse + */ +struct northbridge_intel_fsp_sandybridge_config { + u8 gpu_dp_b_hotplug; /* Digital Port B Hotplug Config */ + u8 gpu_dp_c_hotplug; /* Digital Port C Hotplug Config */ + u8 gpu_dp_d_hotplug; /* Digital Port D Hotplug Config */ + + u8 gpu_panel_port_select; /* 0=LVDS 1=DP_B 2=DP_C 3=DP_D */ + u8 gpu_panel_power_cycle_delay; /* T4 time sequence */ + u16 gpu_panel_power_up_delay; /* T1+T2 time sequence */ + u16 gpu_panel_power_down_delay; /* T3 time sequence */ + u16 gpu_panel_power_backlight_on_delay; /* T5 time sequence */ + u16 gpu_panel_power_backlight_off_delay; /* Tx time sequence */ + + u32 gpu_cpu_backlight; /* CPU Backlight PWM value */ + u32 gpu_pch_backlight; /* PCH Backlight PWM value */ +}; + diff --git a/src/northbridge/intel/fsp_sandybridge/early_init.c b/src/northbridge/intel/fsp_sandybridge/early_init.c new file mode 100644 index 0000000..4b615e9 --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/early_init.c @@ -0,0 +1,88 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2010 coresystems GmbH + * Copyright (C) 2011 Google Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdint.h> +#include <stdlib.h> +#include <console/console.h> +#include <arch/io.h> +#include <device/pci_def.h> +#include <elog.h> +#include "northbridge.h" + +static void sandybridge_setup_bars(void) +{ + printk(BIOS_DEBUG, "Setting up static northbridge registers..."); + /* Set up all hardcoded northbridge BARs */ + pci_write_config32(PCI_DEV(0, 0x00, 0), EPBAR, DEFAULT_EPBAR | 1); + pci_write_config32(PCI_DEV(0, 0x00, 0), EPBAR + 4, (0LL+DEFAULT_EPBAR) >> 32); + pci_write_config32(PCI_DEV(0, 0x00, 0), MCHBAR, DEFAULT_MCHBAR | 1); + pci_write_config32(PCI_DEV(0, 0x00, 0), MCHBAR + 4, (0LL+DEFAULT_MCHBAR) >> 32); + pci_write_config32(PCI_DEV(0, 0x00, 0), PCIEXBAR, DEFAULT_PCIEXBAR | 5); /* 64MB - busses 0-63 */ + pci_write_config32(PCI_DEV(0, 0x00, 0), PCIEXBAR + 4, (0LL+DEFAULT_PCIEXBAR) >> 32); + pci_write_config32(PCI_DEV(0, 0x00, 0), DMIBAR, DEFAULT_DMIBAR | 1); + pci_write_config32(PCI_DEV(0, 0x00, 0), DMIBAR + 4, (0LL+DEFAULT_DMIBAR) >> 32); + + /* Set C0000-FFFFF to access RAM on both reads and writes */ + pci_write_config8(PCI_DEV(0, 0x00, 0), PAM0, 0x30); + pci_write_config8(PCI_DEV(0, 0x00, 0), PAM1, 0x33); + pci_write_config8(PCI_DEV(0, 0x00, 0), PAM2, 0x33); + pci_write_config8(PCI_DEV(0, 0x00, 0), PAM3, 0x33); + pci_write_config8(PCI_DEV(0, 0x00, 0), PAM4, 0x33); + pci_write_config8(PCI_DEV(0, 0x00, 0), PAM5, 0x33); + pci_write_config8(PCI_DEV(0, 0x00, 0), PAM6, 0x33); + +#if CONFIG_ELOG_BOOT_COUNT + /* Increment Boot Counter for non-S3 resume */ + if ((inw(DEFAULT_PMBASE + PM1_STS) & WAK_STS) && + ((inl(DEFAULT_PMBASE + PM1_CNT) >> 10) & 7) != SLP_TYP_S3) + boot_count_increment(); +#endif + + printk(BIOS_DEBUG, " done.\n"); + +#if CONFIG_ELOG_BOOT_COUNT + /* Increment Boot Counter except when resuming from S3 */ + if ((inw(DEFAULT_PMBASE + PM1_STS) & WAK_STS) && + ((inl(DEFAULT_PMBASE + PM1_CNT) >> 10) & 7) == SLP_TYP_S3) + return; + boot_count_increment(); +#endif +} + +void sandybridge_early_initialization(int chipset_type) +{ + u32 capid0_a; + u8 reg8; + + /* Device ID Override Enable should be done very early */ + capid0_a = pci_read_config32(PCI_DEV(0, 0, 0), 0xe4); + if (capid0_a & (1 << 10)) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 0), 0xf3); + reg8 &= ~7; /* Clear 2:0 */ + + if (chipset_type == SANDYBRIDGE_MOBILE) + reg8 |= 1; /* Set bit 0 */ + + pci_write_config8(PCI_DEV(0, 0, 0), 0xf3, reg8); + } + + /* Setup all BARs required for early PCIe and raminit */ + sandybridge_setup_bars(); +} diff --git a/src/northbridge/intel/fsp_sandybridge/finalize.c b/src/northbridge/intel/fsp_sandybridge/finalize.c new file mode 100644 index 0000000..f61f8b1 --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/finalize.c @@ -0,0 +1,56 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 The Chromium OS Authors. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <arch/io.h> +#include <stdlib.h> +#include "northbridge.h" + +#define PCI_DEV_SNB PCI_DEV(0, 0, 0) + +void intel_sandybridge_finalize_smm(void) +{ + pcie_or_config16(PCI_DEV_SNB, 0x50, 1 << 0); /* GGC */ + pcie_or_config32(PCI_DEV_SNB, 0x5c, 1 << 0); /* DPR */ + pcie_or_config32(PCI_DEV_SNB, 0x78, 1 << 10); /* ME */ + pcie_or_config32(PCI_DEV_SNB, 0x90, 1 << 0); /* REMAPBASE */ + pcie_or_config32(PCI_DEV_SNB, 0x98, 1 << 0); /* REMAPLIMIT */ + pcie_or_config32(PCI_DEV_SNB, 0xa0, 1 << 0); /* TOM */ + pcie_or_config32(PCI_DEV_SNB, 0xa8, 1 << 0); /* TOUUD */ + pcie_or_config32(PCI_DEV_SNB, 0xb0, 1 << 0); /* BDSM */ + pcie_or_config32(PCI_DEV_SNB, 0xb4, 1 << 0); /* BGSM */ + pcie_or_config32(PCI_DEV_SNB, 0xb8, 1 << 0); /* TSEGMB */ + pcie_or_config32(PCI_DEV_SNB, 0xbc, 1 << 0); /* TOLUD */ + + MCHBAR32_OR(0x5500, 1 << 0); /* PAVP */ + MCHBAR32_OR(0x5f00, 1 << 31); /* SA PM */ + MCHBAR32_OR(0x6020, 1 << 0); /* UMA GFX */ + MCHBAR32_OR(0x63fc, 1 << 0); /* VTDTRK */ + MCHBAR32_OR(0x6800, 1 << 31); + MCHBAR32_OR(0x7000, 1 << 31); + MCHBAR32_OR(0x77fc, 1 << 0); + + /* Memory Controller Lockdown */ + MCHBAR8(0x50fc) = 0x8f; + + /* Read+write the following */ + MCHBAR32(0x6030) = MCHBAR32(0x6030); + MCHBAR32(0x6034) = MCHBAR32(0x6034); + MCHBAR32(0x6008) = MCHBAR32(0x6008); +} diff --git a/src/northbridge/intel/fsp_sandybridge/fsp_util.c b/src/northbridge/intel/fsp_sandybridge/fsp_util.c new file mode 100644 index 0000000..a8738a4 --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/fsp_util.c @@ -0,0 +1,413 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Sage Electronic Engineering, LLC. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <types.h> +#include <string.h> +#include <cpu/x86/stack.h> +#include <console/console.h> +#include "fsp_util.h" + +#if CONFIG_ENABLE_FAST_BOOT +#include <device/device.h> +#include "northbridge.h" +#include <cbmem.h> +#include <ip_checksum.h> +#endif + +void find_fsp (void); + +#ifndef __PRE_RAM__ +/* Globals pointers for FSP structures */ +void *FspHobListPtr; +FSP_INFO_HEADER *fsp_header_ptr; + +void FspNotify (u32 Phase) +{ + FSP_NOTFY_PHASE NotifyPhaseProc; + NOTIFY_PHASE_PARAMS NotifyPhaseParams; + EFI_STATUS Status; + + if (fsp_header_ptr == NULL) { + find_fsp(); + if (fsp_header_ptr == NULL) { + post_code(0x4F); /* output something in case there is no serial */ + die("Can't find the FSP!\n"); + } + } + + /* call FSP PEI to Notify PostPciEnumeration */ + NotifyPhaseProc = (FSP_NOTFY_PHASE)(fsp_header_ptr->ImageBase + fsp_header_ptr->NotifyPhaseEntry); + NotifyPhaseParams.Phase = Phase; + Status = NotifyPhaseProc (&NotifyPhaseParams); + if (Status != 0) + printk(BIOS_ERR,"FSP API NotifyPhase failed for phase 0x%x with status: 0x%x\n", Phase, Status); +} +#endif + +#ifdef __PRE_RAM__ +/* + * + * Call the FSP to do memory init. The FSP doesn't return to this function. + * The FSP returns to the romstage_main_continue(). + * + */ +const PLATFORM_CONFIG DefaultPlatformConfig = { + TRUE, // Hyperthreading + FALSE, // Turbo Mode + FALSE, // Memory Down +#if CONFIG_ENABLE_FAST_BOOT + TRUE, // Fast Boot +#else + FALSE, // Fast Boot +#endif +}; + +void __attribute__ ((noreturn)) fsp_early_init (FSP_INFO_HEADER *fsp_ptr) +{ + FSP_FSP_INIT FspInitApi; + FSP_INIT_PARAMS FspInitParams; + FSP_INIT_RT_BUFFER FspRtBuffer; + MEM_CONFIG MemoryConfig; + memset((void*)&MemoryConfig, 0, sizeof(MEM_CONFIG)); + + memset((void*)&FspRtBuffer, 0, sizeof(FSP_INIT_RT_BUFFER)); + FspRtBuffer.Common.StackTop = (u32 *)ROMSTAGE_STACK; + FspRtBuffer.Platform.MemoryConfig = &MemoryConfig; + FspRtBuffer.PlatformConfiguration.PlatformConfig = &DefaultPlatformConfig; + FspInitParams.NvsBufferPtr = NULL; + +#if CONFIG_ENABLE_FAST_BOOT + /* find_current_mrc_cache */ + struct mrc_data_container *mrc_cache = NULL; + if (((mrc_cache = find_current_mrc_cache()) == NULL) || (mrc_cache->mrc_data_size == -1UL)) { + printk(BIOS_DEBUG, "FSP MRC cache not present.\n"); + FspInitParams.NvsBufferPtr = (void *) NULL; + } else { + printk(BIOS_DEBUG, "FSP MRC cache present at %x.\n", (u32)mrc_cache); + printk(BIOS_SPEW, "Saved MRC data:\n"); + hexdump32(BIOS_SPEW, (void *)mrc_cache->mrc_data, (mrc_cache->mrc_data_size / 4)); + FspInitParams.NvsBufferPtr = (void *) (EFI_HOB_GUID_TYPE *) mrc_cache->mrc_data; + } +#endif + + /* Not sure why passing BootMode is required - the only valid value is 0 */ + FspRtBuffer.Common.BootMode = 0; + FspInitParams.RtBufferPtr = (FSP_INIT_RT_BUFFER *)&FspRtBuffer; + FspInitParams.ContinuationFunc = (CONTINUATION_PROC)romstage_main_continue; + FspInitApi = (FSP_FSP_INIT)(fsp_ptr->ImageBase + fsp_ptr->FspInitEntry); + + /* call back to romstage.c here to allow structures to be changed */ + romstage_fsp_rt_buffer_callback(&FspRtBuffer); + + FspInitApi(&FspInitParams); + + /* Should never return. Control will continue from ContinuationFunc */ + die("Uh Oh! FspInitApi returned"); +} +#endif + +void __attribute__((optimize("O0"))) find_fsp () +{ + +#ifdef __PRE_RAM__ + volatile register u8 *fsp_ptr asm ("eax"); + + /* Entry point for CAR assembly routine */ + __asm__ __volatile__ ( + ".global find_fsp\n\t" + "find_fsp:\n\t" + ); +#else + u8 *fsp_ptr; +#endif + + /* The FSP is stored in CBFS */ + fsp_ptr = (u8 *) CONFIG_FSP_LOC; + + /* Check the FV signature, _FVH */ + if (((EFI_FIRMWARE_VOLUME_HEADER *)fsp_ptr)->Signature == 0x4856465F) { + /* Go to the end of the FV header and align the address. */ + fsp_ptr += ((EFI_FIRMWARE_VOLUME_HEADER *)fsp_ptr)->ExtHeaderOffset; + fsp_ptr += ((EFI_FIRMWARE_VOLUME_EXT_HEADER *)fsp_ptr)->ExtHeaderSize; + fsp_ptr = (u8 *)(((u32)fsp_ptr + 7) & 0xFFFFFFF8); + } else { + fsp_ptr = (u8*)ERROR_NO_FV_SIG; + } + + /* Check the FFS GUID */ + if (((u32)fsp_ptr > 0xff) && + (((u32 *)&(((EFI_FFS_FILE_HEADER *)fsp_ptr)->Name))[0] == 0x912740BE) && + (((u32 *)&(((EFI_FFS_FILE_HEADER *)fsp_ptr)->Name))[1] == 0x47342284) && + (((u32 *)&(((EFI_FFS_FILE_HEADER *)fsp_ptr)->Name))[2] == 0xB08471B9) && + (((u32 *)&(((EFI_FFS_FILE_HEADER *)fsp_ptr)->Name))[3] == 0x0C3F3527)) { + /* Add the FFS Header size to the base to find the Raw section Header */ + fsp_ptr += sizeof(EFI_FFS_FILE_HEADER); + } else { + fsp_ptr = (u8 *)ERROR_NO_FFS_GUID; + } + + if (((u32)fsp_ptr > 0xff) && + ((EFI_RAW_SECTION *)fsp_ptr)->Type == EFI_SECTION_RAW) { + /* Add the Raw Header size to the base to find the FSP INFO Header */ + fsp_ptr += sizeof(EFI_RAW_SECTION); + } else { + fsp_ptr = (u8 *)ERROR_NO_INFO_HEADER; + } + +#if 0 /* removed for debugging */ + /* Verify that the FSP is set to the base address we're expecting.*/ + if (((u32)fsp_ptr > 0xff) && + (*(u32*)(fsp_ptr + FSP_IMAGE_BASE_LOC) != CONFIG_FSP_LOC)) { + fsp_ptr = (u8 *)ERROR_IMAGEBASE_MISMATCH; + } + /* Verify the FSP Signature */ + if (((u32)fsp_ptr > 0xff) && + (*(u32*)(fsp_ptr + FSP_IMAGE_SIG_LOC) != FSP_SIG)){ + fsp_ptr = (u8 *)ERROR_INFO_HEAD_SIG_MISMATCH; + } + + /* Verify the FSP ID */ + if (((u32)fsp_ptr > 0xff) && + (*(u32 *)(fsp_ptr + FSP_IMAGE_ID_LOC) != CONFIG_FSP_IMAGE_ID_DWORD0)){ + fsp_ptr = (u8 *)ERROR_FSP_SIG_MISMATCH; + } + if (((u32)fsp_ptr > 0xff) && + (*(u32 *)(fsp_ptr + FSP_IMAGE_ID_LOC + 4) != CONFIG_FSP_IMAGE_ID_DWORD1)) { + fsp_ptr = (u8 *)ERROR_FSP_SIG_MISMATCH; + } +#endif /* removed for debugging */ + +#ifdef __PRE_RAM__ + __asm__ __volatile__ ("ret"); +#else + fsp_header_ptr = (FSP_INFO_HEADER *) fsp_ptr; + printk(BIOS_SPEW,"fsp_header_ptr: 0x%x\n", (u32)fsp_header_ptr); + return; +#endif +} + +void print_fsp_info(void) { + +#ifndef __PRE_RAM__ + if (fsp_header_ptr == NULL) + find_fsp(); + + printk(BIOS_INFO,"FSP Header Version: %d\n", fsp_header_ptr->HeaderRevision); + printk(BIOS_INFO,"FSP Revision: %d.%d\n", + (u8)((fsp_header_ptr->ImageRevision >> 8) & 0xff), + (u8)(fsp_header_ptr->ImageRevision & 0xff)); +#endif +} + +#ifndef __PRE_RAM__ /* Only parse HOB data in ramstage */ +static void print_hob_mem_attributes(void *Hobptr) { + EFI_HOB_MEMORY_ALLOCATION *HobMemoryPtr = (EFI_HOB_MEMORY_ALLOCATION *)Hobptr; + EFI_MEMORY_TYPE Hobmemtype = HobMemoryPtr->AllocDescriptor.MemoryType; + u64 Hobmemaddr = HobMemoryPtr->AllocDescriptor.MemoryBaseAddress; + u64 Hobmemlength = HobMemoryPtr->AllocDescriptor.MemoryLength; + const char * Hobmemtypenames[15]; + + Hobmemtypenames[0] = "EfiReservedMemoryType"; + Hobmemtypenames[1] = "EfiLoaderCode"; + Hobmemtypenames[2] = "EfiLoaderData"; + Hobmemtypenames[3] = "EfiBootServicesCode"; + Hobmemtypenames[4] = "EfiBootServicesData"; + Hobmemtypenames[5] = "EfiRuntimeServicesCode"; + Hobmemtypenames[6] = "EfiRuntimeServicesData"; + Hobmemtypenames[7] = "EfiConventionalMemory"; + Hobmemtypenames[8] = "EfiUnusableMemory"; + Hobmemtypenames[9] = "EfiACPIReclaimMemory"; + Hobmemtypenames[10] = "EfiACPIMemoryNVS"; + Hobmemtypenames[11] = "EfiMemoryMappedIO"; + Hobmemtypenames[12] = "EfiMemoryMappedIOPortSpace"; + Hobmemtypenames[13] = "EfiPalCode"; + Hobmemtypenames[14] = "EfiMaxMemoryType"; + + printk(BIOS_SPEW, " Memory type %s (0x%x)\n", + Hobmemtypenames[(u32)Hobmemtype], (u32) Hobmemtype); + printk(BIOS_SPEW, " at location 0x%0lx with length 0x%0lx\n", + (long unsigned int)Hobmemaddr, (long unsigned int)Hobmemlength); +} + +static void print_hob_resource_attributes(void *Hobptr) { + EFI_HOB_RESOURCE_DESCRIPTOR *HobResourcePtr = (EFI_HOB_RESOURCE_DESCRIPTOR *)Hobptr; + u32 Hobrestype = HobResourcePtr->ResourceType; + u32 Hobresattr = HobResourcePtr->ResourceAttribute; + u64 Hobresaddr = HobResourcePtr->PhysicalStart; + u64 Hobreslength = HobResourcePtr->ResourceLength; + const char *Hobrestypestr = NULL; + + // HOB Resource Types + switch (Hobrestype) { + case EFI_RESOURCE_SYSTEM_MEMORY: + Hobrestypestr = "EFI_RESOURCE_SYSTEM_MEMORY"; break; + case EFI_RESOURCE_MEMORY_MAPPED_IO: + Hobrestypestr = "EFI_RESOURCE_MEMORY_MAPPED_IO"; break; + case EFI_RESOURCE_IO: + Hobrestypestr = "EFI_RESOURCE_IO"; break; + case EFI_RESOURCE_FIRMWARE_DEVICE: + Hobrestypestr = "EFI_RESOURCE_FIRMWARE_DEVICE"; break; + case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT: + Hobrestypestr = "EFI_RESOURCE_MEMORY_MAPPED_IO_PORT"; break; + case EFI_RESOURCE_MEMORY_RESERVED: + Hobrestypestr = "EFI_RESOURCE_MEMORY_RESERVED"; break; + case EFI_RESOURCE_IO_RESERVED: + Hobrestypestr = "EFI_RESOURCE_IO_RESERVED"; break; + case EFI_RESOURCE_MAX_MEMORY_TYPE: + Hobrestypestr = "EFI_RESOURCE_MAX_MEMORY_TYPE"; break; + default: + Hobrestypestr = "EFI_RESOURCE_UNKNOWN"; break; + } + + printk(BIOS_SPEW, " Resource %s (0x%0x) has attributes 0x%0x\n", + Hobrestypestr, Hobrestype, Hobresattr); + printk(BIOS_SPEW, " at location 0x%0lx with length 0x%0lx\n", + (long unsigned int)Hobresaddr, (long unsigned int)Hobreslength); +} + +static const char * get_hob_type_string(void *Hobptr) { + EFI_HOB_GENERIC_HEADER *HobHeaderPtr = (EFI_HOB_GENERIC_HEADER *)Hobptr; + u16 Hobtype = HobHeaderPtr->HobType; + const char *Hobtypestring = NULL; + + switch (Hobtype) { + case EFI_HOB_TYPE_HANDOFF: + Hobtypestring = "EFI_HOB_TYPE_HANDOFF"; break; + case EFI_HOB_TYPE_MEMORY_ALLOCATION: + Hobtypestring = "EFI_HOB_TYPE_MEMORY_ALLOCATION"; break; + case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR: + Hobtypestring = "EFI_HOB_TYPE_RESOURCE_DESCRIPTOR"; break; + case EFI_HOB_TYPE_GUID_EXTENSION: + Hobtypestring = "EFI_HOB_TYPE_GUID_EXTENSION"; break; + case EFI_HOB_TYPE_MEMORY_POOL: + Hobtypestring = "EFI_HOB_TYPE_MEMORY_POOL"; break; + case EFI_HOB_TYPE_UNUSED: + Hobtypestring = "EFI_HOB_TYPE_UNUSED"; break; + case EFI_HOB_TYPE_END_OF_HOB_LIST: + Hobtypestring = "EFI_HOB_TYPE_END_OF_HOB_LIST"; break; + default: + Hobtypestring = "EFI_HOB_TYPE_UNRECOGNIZED"; break; + } + + return Hobtypestring; +} + +/* Print out a structure of all the HOBs + * that match a certain type: + * Print all types (0x0000) + * EFI_HOB_TYPE_HANDOFF (0x0001) + * EFI_HOB_TYPE_MEMORY_ALLOCATION (0x0002) + * EFI_HOB_TYPE_RESOURCE_DESCRIPTOR (0x0003) + * EFI_HOB_TYPE_GUID_EXTENSION (0x0004) + * EFI_HOB_TYPE_MEMORY_POOL (0x0007) + * EFI_HOB_TYPE_UNUSED (0xFFFE) + * EFI_HOB_TYPE_END_OF_HOB_LIST (0xFFFF) + */ +void print_hob_type_structure(u16 Hobtype, void *Hoblistptr) { + u32 *Currenthob; + u32 *Nexthob = 0; + u8 Lasthob = 0; + u32 Currenttype; + const char *Currenttypestr; + + Currenthob = Hoblistptr; + + /* Print out HOBs of our desired type until + * the end of the HOB list + */ + printk(BIOS_DEBUG, "\n=== FSP HOB Data Structure ===\n"); + printk(BIOS_DEBUG, "FSP Hoblistptr: 0x%0x\n", + (u32) Hoblistptr); + do { + EFI_HOB_GENERIC_HEADER *CurrentHeaderPtr = (EFI_HOB_GENERIC_HEADER *)Currenthob; + Currenttype = CurrentHeaderPtr->HobType; // Get the type of this HOB + Currenttypestr = get_hob_type_string(Currenthob); + + if (Currenttype == Hobtype || Hobtype == 0x0000) { + printk(BIOS_DEBUG, "HOB 0x%0x is an %s (type 0x%0x)\n", + (u32) Currenthob, Currenttypestr, Currenttype); + switch (Currenttype) { + case EFI_HOB_TYPE_MEMORY_ALLOCATION: + print_hob_mem_attributes(Currenthob); break; + case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR: + print_hob_resource_attributes(Currenthob); break; + } + } + + Lasthob = END_OF_HOB_LIST(Currenthob); // Check for end of HOB list + if (!Lasthob) { + Nexthob = GET_NEXT_HOB(Currenthob); // Get next HOB pointer + Currenthob = Nexthob; // Start on next HOB + } + } while (!Lasthob); + printk(BIOS_DEBUG, "=== End of FSP HOB Data Structure ===\n\n"); +} + +#if CONFIG_ENABLE_FAST_BOOT +/** + * Save the FSP memory HOB (mrc data) to the MRC area in CBMEM + */ +void save_mrc_data(void *hob_start) +{ + u32 *mrc_hob; + u32 *mrc_hob_data; + u32 mrc_hob_size; + struct mrc_data_container *mrc_data; + int output_len; + const EFI_GUID mrc_guid = FSP_NON_VOLATILE_STORAGE_HOB_GUID; + + mrc_hob = GetNextGuidHob(&mrc_guid, hob_start); + if (mrc_hob == NULL) die ("mrc_hob is NULL"); + + mrc_hob_data = GET_GUID_HOB_DATA (mrc_hob); + mrc_hob_size = (u32) GET_HOB_LENGTH(mrc_hob); + + printk(BIOS_DEBUG, "Memory Configure Data Hob at %p (size = 0x%x).\n", + (void *)mrc_hob_data, mrc_hob_size); + + output_len = ALIGN(mrc_hob_size, 16); + + /* Save the MRC S3/Fastboot/ADR restore data to cbmem */ + mrc_data = cbmem_add (CBMEM_ID_MRCDATA, + output_len + sizeof(struct mrc_data_container)); + + /* Just return if there was a problem with getting CBMEM */ + if (mrc_data == NULL) return; + + printk(BIOS_DEBUG, "Copy FSP MRC DATA to HOB (source addr %p, dest addr %p, %u bytes)\n", + (void *)mrc_hob_data, mrc_data, output_len); + + mrc_data->mrc_signature = MRC_DATA_SIGNATURE; + mrc_data->mrc_data_size = output_len; + mrc_data->reserved = 0; + memcpy(mrc_data->mrc_data, (const void *)mrc_hob_data, mrc_hob_size); + + /* Zero the unused space in aligned buffer. */ + if (output_len > mrc_hob_size) + memset((mrc_data->mrc_data + mrc_hob_size), 0, + output_len - mrc_hob_size); + + mrc_data->mrc_checksum = compute_ip_checksum(mrc_data->mrc_data, + mrc_data->mrc_data_size); + + printk(BIOS_SPEW, "MRC data in CBMEM(includes align and checksum):\n"); + hexdump32(BIOS_SPEW, (void *)mrc_data->mrc_data, (output_len / 4)); +} +#endif +#endif /*__PRE_RAM__*/ diff --git a/src/northbridge/intel/fsp_sandybridge/fsp_util.h b/src/northbridge/intel/fsp_sandybridge/fsp_util.h new file mode 100644 index 0000000..a237299 --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/fsp_util.h @@ -0,0 +1,101 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Sage Electronic Engineering, LLC. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef FSP_UTIL_H +#define FSP_UTIL_H + +#if IS_ENABLED(CONFIG_HAVE_FSP_BIN) + +#include <fsptypes.h> +#include <fspfv.h> +#include <fspffs.h> +#include <fspapi.h> +#include <fspplatform.h> +#include <fspinfoheader.h> +#include <fsphob.h> + +void fsp_early_init(FSP_INFO_HEADER *fsp_info); +void FspNotify(u32 Phase); +void romstage_main_continue(EFI_STATUS Status, VOID *HobListPtr); +void print_hob_type_structure(u16 Hobtype, void *Hoblistptr); +void romstage_fsp_rt_buffer_callback(FSP_INIT_RT_BUFFER *FspRtBuffer); +void print_fsp_info(void); + +#else /* (NOT) IS_ENABLED(CONFIG_HAVE_FSP_BIN) */ + +#define fsp_early_init(x) do {} while (0) +#define FspNotify(x) do {} while (0) +#define romstage_main_continue(x,y) do {} while (0) +#define print_hob_type_structure(x,y,z) do {} while (0) +#define romstage_fsp_rt_buffer_callback(x) do {} while (0) +#define print_fsp_info() do {} while (0) + +#endif /* IS_ENABLED(CONFIG_HAVE_FSP_BIN) */ + +#if CONFIG_ENABLE_FAST_BOOT +void save_mrc_data(void *hob_start); +#endif + + +/* Additional HOB types not included in the FSP: + * #define EFI_HOB_TYPE_HANDOFF 0x0001 + * #define EFI_HOB_TYPE_MEMORY_ALLOCATION 0x0002 + * #define EFI_HOB_TYPE_RESOURCE_DESCRIPTOR 0x0003 + * #define EFI_HOB_TYPE_GUID_EXTENSION 0x0004 + * #define EFI_HOB_TYPE_FV 0x0005 + * #define EFI_HOB_TYPE_CPU 0x0006 + * #define EFI_HOB_TYPE_MEMORY_POOL 0x0007 + * #define EFI_HOB_TYPE_CV 0x0008 + * #define EFI_HOB_TYPE_UNUSED 0xFFFE + * #define EFI_HOB_TYPE_END_OF_HOB_LIST 0xffff + */ +#define EFI_HOB_TYPE_HANDOFF 0x0001 +#define EFI_HOB_TYPE_MEMORY_POOL 0x0007 + +#if CONFIG_ENABLE_FAST_BOOT +#define FSP_INFO_HEADER_GUID \ + { \ + 0x912740BE, 0x2284, 0x4734, {0xB9, 0x71, 0x84, 0xB0, 0x27, 0x35, 0x3F, 0x0C} \ + } + +#define FSP_NON_VOLATILE_STORAGE_HOB_GUID \ + { \ + 0x721acf02, 0x4d77, 0x4c2a, { 0xb3, 0xdc, 0x27, 0xb, 0x7b, 0xa9, 0xe4, 0xb0 } \ + } +#endif + +/* The offset in bytes from the start of the info structure */ +#define FSP_IMAGE_SIG_LOC 0 +#define FSP_IMAGE_ID_LOC 16 +#define FSP_IMAGE_BASE_LOC 28 + +#define FSP_SIG 0x48505346 /* 'FSPH' */ + +#define ERROR_NO_FV_SIG 1 +#define ERROR_NO_FFS_GUID 2 +#define ERROR_NO_INFO_HEADER 3 +#define ERROR_IMAGEBASE_MISMATCH 4 +#define ERROR_INFO_HEAD_SIG_MISMATCH 5 +#define ERROR_FSP_SIG_MISMATCH 6 + +#ifndef __PRE_RAM__ +extern void *FspHobListPtr; +#endif + +#endif /* FSP_UTIL_H */ diff --git a/src/northbridge/intel/fsp_sandybridge/gma.c b/src/northbridge/intel/fsp_sandybridge/gma.c new file mode 100644 index 0000000..d578d56 --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/gma.c @@ -0,0 +1,88 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Chromium OS Authors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <arch/io.h> +#include <console/console.h> +#include <delay.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> + +#include "chip.h" +#include "northbridge.h" + + +/* some vga option roms are used for several chipsets but they only have one + * PCI ID in their header. If we encounter such an option rom, we need to do + * the mapping ourselfes + */ + +u32 map_oprom_vendev(u32 vendev) +{ + u32 new_vendev=vendev; + + switch (vendev) { + case 0x80860102: /* GT1 Desktop */ + case 0x8086010a: /* GT1 Server */ + case 0x80860112: /* GT2 Desktop */ + case 0x80860116: /* GT2 Mobile */ + case 0x80860122: /* GT2 Desktop >=1.3GHz */ + case 0x80860126: /* GT2 Mobile >=1.3GHz */ + case 0x80860166: /* IVB */ + new_vendev=0x80860106; /* GT1 Mobile */ + break; + } + + return new_vendev; +} + +static void gma_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +static struct pci_operations gma_pci_ops = { + .set_subsystem = gma_set_subsystem, +}; + +static struct device_operations gma_func0_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = pci_dev_init, + .scan_bus = 0, + .enable = 0, + .ops_pci = &gma_pci_ops, +}; + +static const unsigned short gma_ids[] = { + 0x0102, 0x0106, 0x010a, 0x0112, 0x0116, 0x0122, 0x0126, 0x166, + 0, +}; +static const struct pci_driver gma_gt1_desktop __pci_driver = { + .ops = &gma_func0_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .devices= gma_ids, +}; diff --git a/src/northbridge/intel/fsp_sandybridge/gma.h b/src/northbridge/intel/fsp_sandybridge/gma.h new file mode 100644 index 0000000..bd4c266 --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/gma.h @@ -0,0 +1,168 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Chromium OS Authors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* mailbox 0: header */ +typedef struct { + u8 signature[16]; + u32 size; + u32 version; + u8 sbios_version[32]; + u8 vbios_version[16]; + u8 driver_version[16]; + u32 mailboxes; + u8 reserved[164]; +} __attribute__((packed)) opregion_header_t; + +#define IGD_OPREGION_SIGNATURE "IntelGraphicsMem" +#define IGD_OPREGION_VERSION 2 + +#define IGD_MBOX1 (1 << 0) +#define IGD_MBOX2 (1 << 1) +#define IGD_MBOX3 (1 << 2) +#define IGD_MBOX4 (1 << 3) +#define IGD_MBOX5 (1 << 4) + +#define MAILBOXES_MOBILE (IGD_MBOX1 | IGD_MBOX2 | IGD_MBOX3 | \ + IGD_MBOX4 | IGD_MBOX5) +#define MAILBOXES_DESKTOP (IGD_MBOX2 | IGD_MBOX4) + +#define SBIOS_VERSION_SIZE 32 + +/* mailbox 1: public acpi methods */ +typedef struct { + u32 drdy; + u32 csts; + u32 cevt; + u8 reserved1[20]; + u32 didl[8]; + u32 cpdl[8]; + u32 cadl[8]; + u32 nadl[8]; + u32 aslp; + u32 tidx; + u32 chpd; + u32 clid; + u32 cdck; + u32 sxsw; + u32 evts; + u32 cnot; + u32 nrdy; + u8 reserved2[60]; +} __attribute__((packed)) opregion_mailbox1_t; + +/* mailbox 2: software sci interface */ +typedef struct { + u32 scic; + u32 parm; + u32 dslp; + u8 reserved[244]; +} __attribute__((packed)) opregion_mailbox2_t; + +/* mailbox 3: power conservation */ +typedef struct { + u32 ardy; + u32 aslc; + u32 tche; + u32 alsi; + u32 bclp; + u32 pfit; + u32 cblv; + u16 bclm[20]; + u32 cpfm; + u32 epfm; + u8 plut[74]; + u32 pfmb; + u32 ccdv; + u32 pcft; + u8 reserved[94]; +} __attribute__((packed)) opregion_mailbox3_t; + +#define IGD_BACKLIGHT_BRIGHTNESS 0xff +#define IGD_INITIAL_BRIGHTNESS 0x64 + +#define IGD_FIELD_VALID (1 << 31) +#define IGD_WORD_FIELD_VALID (1 << 15) +#define IGD_PFIT_STRETCH 6 + +/* mailbox 4: vbt */ +typedef struct { + u8 gvd1[7168]; +} __attribute__((packed)) opregion_vbt_t; + +/* IGD OpRegion */ +typedef struct { + opregion_header_t header; + opregion_mailbox1_t mailbox1; + opregion_mailbox2_t mailbox2; + opregion_mailbox3_t mailbox3; + opregion_vbt_t vbt; +} __attribute__((packed)) igd_opregion_t; + +/* Intel Video BIOS (Option ROM) */ +typedef struct { + u16 signature; + u8 size; + u8 reserved[21]; + u16 pcir_offset; + u16 vbt_offset; +} __attribute__((packed)) optionrom_header_t; + +#define OPROM_SIGNATURE 0xaa55 + +typedef struct { + u32 signature; + u16 vendor; + u16 device; + u16 reserved1; + u16 length; + u8 revision; + u8 classcode[3]; + u16 imagelength; + u16 coderevision; + u8 codetype; + u8 indicator; + u16 reserved2; +} __attribute__((packed)) optionrom_pcir_t; + +typedef struct { + u8 hdr_signature[20]; + u16 hdr_version; + u16 hdr_size; + u16 hdr_vbt_size; + u8 hdr_vbt_checksum; + u8 hdr_reserved; + u32 hdr_vbt_datablock; + u32 hdr_aim[4]; + u8 datahdr_signature[16]; + u16 datahdr_version; + u16 datahdr_size; + u16 datahdr_datablocksize; + u8 coreblock_id; + u16 coreblock_size; + u16 coreblock_biossize; + u8 coreblock_biostype; + u8 coreblock_releasestatus; + u8 coreblock_hwsupported; + u8 coreblock_integratedhw; + u8 coreblock_biosbuild[4]; + u8 coreblock_biossignon[155]; +} __attribute__((packed)) optionrom_vbt_t; + +#define VBT_SIGNATURE 0x54425624 + diff --git a/src/northbridge/intel/fsp_sandybridge/mrccache.c b/src/northbridge/intel/fsp_sandybridge/mrccache.c new file mode 100644 index 0000000..a793880 --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/mrccache.c @@ -0,0 +1,257 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Google Inc. + * Copyright (C) 2013 Sage Electronic Engineering, LLC. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdint.h> +#include <string.h> +#include <bootstate.h> +#include <console/console.h> +#include <cbfs.h> +#include <ip_checksum.h> +#include <device/device.h> +#include <cbmem.h> +#include "northbridge.h" +#include <spi-generic.h> +#include <spi_flash.h> +#include "fsp_util.h" + +/* convert a pointer to flash area into the offset inside the flash */ +static inline u32 to_flash_offset(void *p) { + return ((u32)p + CONFIG_VIRTUAL_ROM_SIZE); +} + +static struct mrc_data_container *next_mrc_block( + struct mrc_data_container *mrc_cache) +{ + /* MRC data blocks are aligned within the region */ + u32 mrc_size = sizeof(*mrc_cache) + mrc_cache->mrc_data_size; + if (mrc_size & (MRC_DATA_ALIGN - 1UL)) { + mrc_size &= ~(MRC_DATA_ALIGN - 1UL); + mrc_size += MRC_DATA_ALIGN; + } + + u8 *region_ptr = (u8*)mrc_cache; + region_ptr += mrc_size; + return (struct mrc_data_container *)region_ptr; +} + +static int is_mrc_cache(struct mrc_data_container *mrc_cache) +{ + return (!!mrc_cache) && (mrc_cache->mrc_signature == MRC_DATA_SIGNATURE); +} + +static u32 get_mrc_cache_region(struct mrc_data_container **mrc_region_ptr) +{ + u32 region_size; + region_size = CONFIG_MRC_CACHE_SIZE; + *mrc_region_ptr = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, + "mrc.cache", 0xac); + + return region_size; +} + +/* + * Find the largest index block in the MRC cache. Return NULL if none is + * found. + */ +static struct mrc_data_container *find_current_mrc_cache_local + (struct mrc_data_container *mrc_cache, u32 region_size) +{ + u32 region_end; + u32 entry_id = 0; + struct mrc_data_container *mrc_next = mrc_cache; + + region_end = (u32) mrc_cache + region_size; + + /* Search for the last filled entry in the region */ + while (is_mrc_cache(mrc_next)) { + entry_id++; + mrc_cache = mrc_next; + mrc_next = next_mrc_block(mrc_next); + if ((u32)mrc_next >= region_end) { + /* Stay in the MRC data region */ + break; + } + } + + if (entry_id == 0) { + printk(BIOS_ERR, "%s: No valid MRC cache found.\n", __func__); + return NULL; + } + + /* Verify checksum */ + if (mrc_cache->mrc_checksum != + compute_ip_checksum(mrc_cache->mrc_data, + mrc_cache->mrc_data_size)) { + printk(BIOS_ERR, "%s: MRC cache checksum mismatch\n", __func__); + return NULL; + } + + printk(BIOS_DEBUG, "%s: picked entry %u from cache block\n", __func__, + entry_id - 1); + + return mrc_cache; +} + +/* SPI code needs malloc/free. + * Also unknown if writing flash from XIP-flash code is a good idea + */ +#if !defined(__PRE_RAM__) +/* find the first empty block in the MRC cache area. + * If there's none, return NULL. + * + * @mrc_cache_base - base address of the MRC cache area + * @mrc_cache - current entry (for which we need to find next) + * @region_size - total size of the MRC cache area + */ +static struct mrc_data_container *find_next_mrc_cache + (struct mrc_data_container *mrc_cache_base, + struct mrc_data_container *mrc_cache, + u32 region_size) +{ + u32 region_end = (u32) mrc_cache_base + region_size; + u32 mrc_data_size = mrc_cache->mrc_data_size; + + mrc_cache = next_mrc_block(mrc_cache); + if (((u32)mrc_cache + mrc_data_size) >= region_end) { + /* Crossed the boundary */ + mrc_cache = NULL; + printk(BIOS_DEBUG, "%s: no available entries found\n", + __func__); + } else { + printk(BIOS_DEBUG, + "%s: picked next entry from cache block at %p\n", + __func__, mrc_cache); + } + + return mrc_cache; +} + +static void update_mrc_cache(void *unused) +{ + printk(BIOS_DEBUG, "Updating MRC cache data.\n"); + struct mrc_data_container *current = cbmem_find(CBMEM_ID_MRCDATA); + struct mrc_data_container *cache, *cache_base; + u32 cache_size; + + if (!current) { + printk(BIOS_ERR, "No MRC cache in cbmem. Can't update flash.\n"); + return; + } + if (current->mrc_data_size == -1) { + printk(BIOS_ERR, "MRC cache data in cbmem invalid.\n"); + return; + } + + cache_size = get_mrc_cache_region(&cache_base); + if (cache_base == NULL) { + printk(BIOS_ERR, "%s: could not find MRC cache area\n", + __func__); + return; + } + + /* + * we need to: + */ + // 0. compare MRC data to last mrc-cache block (exit if same) + cache = find_current_mrc_cache_local(cache_base, cache_size); + + if (cache && (cache->mrc_data_size == current->mrc_data_size) && + (memcmp(cache, current, cache->mrc_data_size) == 0)) { + printk(BIOS_DEBUG, + "MRC data in flash is up to date. No update.\n"); + return; + } + + // 1. use spi_flash_probe() to find the flash, then + spi_init(); + struct spi_flash *flash = spi_flash_probe(0, 0, 1000000, SPI_MODE_3); + if (!flash) { + printk(BIOS_DEBUG, "Could not find SPI device\n"); + return; + } + + // 2. look up the first unused block + if (cache) + cache = find_next_mrc_cache(cache_base, cache, cache_size); + + /* + * 3. if no such place exists, erase entire mrc-cache range & use + * block 0. First time around the erase is not needed, but this is a + * small overhead for simpler code. + */ + if (!cache) { + printk(BIOS_DEBUG, + "Need to erase the MRC cache region of %d bytes at %p\n", + cache_size, cache_base); + + flash->erase(flash, to_flash_offset(cache_base), cache_size); + + /* we will start at the beginning again */ + cache = cache_base; + } + // 4. write mrc data with flash->write() + printk(BIOS_DEBUG, "Write MRC cache update to flash at %p\n", + cache); + flash->write(flash, to_flash_offset(cache), + current->mrc_data_size + sizeof(*current), current); +} + +static void find_fsp_hob(void *unused) +{ + /* Set the global HOB list pointer */ + FspHobListPtr = (void*)*((u32*) cbmem_find(CBMEM_ID_HOB_POINTER)); + + if (!FspHobListPtr){ + printk(BIOS_ERR, "ERROR: Could not find FSP HOB pointer in CBFS!\n"); + } else { + /* 0x0000: Print all types */ + print_hob_type_structure(0x000, FspHobListPtr); + + #if CONFIG_ENABLE_FAST_BOOT + save_mrc_data(FspHobListPtr); + update_mrc_cache(NULL); + #endif + } +} + +BOOT_STATE_INIT_ENTRIES(fsp_hob_find) = { + BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY, + find_fsp_hob, NULL), +}; +#endif /* !defined(__PRE_RAM__) */ + +struct mrc_data_container *find_current_mrc_cache(void) +{ + struct mrc_data_container *cache_base; + u32 cache_size; + + cache_size = get_mrc_cache_region(&cache_base); + if (cache_base == NULL) { + printk(BIOS_ERR, "%s: could not find MRC cache area\n", + __func__); + return NULL; + } + + /* + * we need to: + */ + // 0. compare MRC data to last mrc-cache block (exit if same) + return find_current_mrc_cache_local(cache_base, cache_size); +} diff --git a/src/northbridge/intel/fsp_sandybridge/northbridge.c b/src/northbridge/intel/fsp_sandybridge/northbridge.c new file mode 100644 index 0000000..20595ee --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/northbridge.c @@ -0,0 +1,437 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved. + * Copyright (C) 2013 Sage Electronic Engineering, LLC. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <console/console.h> +#include <arch/acpi.h> +#include <arch/io.h> +#include <stdint.h> +#include <delay.h> +#include <cpu/intel/fsp_model_206ax/model_206ax.h> +#include <cpu/x86/msr.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/hypertransport.h> +#include <stdlib.h> +#include <string.h> +#include <cpu/cpu.h> +#include <cbmem.h> +#include "chip.h" +#include "northbridge.h" +#include "fsp_util.h" + +static int bridge_revision_id = -1; +static u8 finished_FSP_after_pci = 0; + +int bridge_silicon_revision(void) +{ + if (bridge_revision_id < 0) { + uint8_t stepping = cpuid_eax(1) & 0xf; + uint8_t bridge_id = pci_read_config16( + dev_find_slot(0, PCI_DEVFN(0, 0)), + PCI_DEVICE_ID) & 0xf0; + bridge_revision_id = bridge_id | stepping; + } + return bridge_revision_id; +} + +/* Reserve everything between A segment and 1MB: + * + * 0xa0000 - 0xbffff: legacy VGA + * 0xc0000 - 0xcffff: VGA OPROM (needed by kernel) + * 0xe0000 - 0xfffff: SeaBIOS, if used, otherwise DMI + */ +static const int legacy_hole_base_k = 0xa0000 / 1024; +static const int legacy_hole_size_k = 384; + +static int get_pcie_bar(u32 *base, u32 *len) +{ + device_t dev; + u32 pciexbar_reg; + + *base = 0; + *len = 0; + + dev = dev_find_slot(0, PCI_DEVFN(0, 0)); + if (!dev) + return 0; + + pciexbar_reg = pci_read_config32(dev, PCIEXBAR); + + if (!(pciexbar_reg & (1 << 0))) + return 0; + + switch ((pciexbar_reg >> 1) & 3) { + case 0: // 256MB + *base = pciexbar_reg & ((1 << 31)|(1 << 30)|(1 << 29)|(1 << 28)); + *len = 256 * 1024 * 1024; + return 1; + case 1: // 128M + *base = pciexbar_reg & ((1 << 31)|(1 << 30)|(1 << 29)|(1 << 28)|(1 << 27)); + *len = 128 * 1024 * 1024; + return 1; + case 2: // 64M + *base = pciexbar_reg & ((1 << 31)|(1 << 30)|(1 << 29)|(1 << 28)|(1 << 27)|(1 << 26)); + *len = 64 * 1024 * 1024; + return 1; + } + + return 0; +} + +static void add_fixed_resources(struct device *dev, int index) +{ + struct resource *resource; + u32 pcie_config_base, pcie_config_size; + + /* Using uma_resource() here would fail as base & size cannot + * be used as-is for a single MTRR. This would cause excessive + * use of MTRRs. + * + * Use of mmio_resource() instead does not create UC holes by using + * MTRRs, but making these regions uncacheable is taken care of by + * making sure they do not overlap with any ram_resource(). + * + * The resources can be changed to use separate mmio_resource() + * calls after MTRR code is able to merge them wisely. + */ + mmio_resource(dev, index++, uma_memory_base >> 10, uma_memory_size >> 10); + + if (get_pcie_bar(&pcie_config_base, &pcie_config_size)) { + printk(BIOS_DEBUG, "Adding PCIe config bar base=0x%08x " + "size=0x%x\n", pcie_config_base, pcie_config_size); + resource = new_resource(dev, index++); + resource->base = (resource_t) pcie_config_base; + resource->size = (resource_t) pcie_config_size; + resource->flags = IORESOURCE_MEM | IORESOURCE_RESERVE | + IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; + } + + mmio_resource(dev, index++, legacy_hole_base_k, legacy_hole_size_k); +} + +static void pci_domain_set_resources(device_t dev) +{ + uint64_t tom, me_base, touud; + uint32_t tseg_base, uma_size, tolud; + uint16_t ggc; + unsigned long long tomk; + + tomk = ggc = tseg_base = uma_size = tolud = tom = me_base = touud = 0; + + /* 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) & ~(1UL << 0); + + /* Top of Lower Usable DRAM */ + tolud = pci_read_config32(dev, TOLUD) & ~(1UL << 0); + + /* Top of Memory - does not account for any UMA */ + tom = pci_read_config32(dev, 0xa4); + tom <<= 32; + tom |= pci_read_config32(dev, 0xa0) & ~(1UL << 0); + + printk(BIOS_DEBUG, "TOUUD 0x%llx TOLUD 0x%08x TOM 0x%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); + + printk(BIOS_DEBUG, "MEBASE 0x%llx\n", me_base); + + 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; + printk(BIOS_DEBUG, "ME UMA base 0x%llx size %uM\n", + me_base, uma_size >> 10); + } + + /* Graphics memory comes next */ + ggc = pci_read_config16(dev, GGC); + if (!(ggc & 2)) { + printk(BIOS_DEBUG, "IGD decoded, subtracting "); + + /* Graphics memory */ + uma_size = ((ggc >> 3) & 0x1f) * 32 * 1024ULL; + printk(BIOS_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; + printk(BIOS_DEBUG, " and %uM GTT\n", uma_size >> 10); + } + + /* Calculate TSEG size from its base which must be below GTT */ + uma_memory_base = tomk * 1024ULL; + tseg_base = pci_read_config32(dev, 0xb8) & ~(1UL << 0); + uma_size = (uma_memory_base - tseg_base) >> 10; + tomk -= uma_size; + uma_memory_base = tomk * 1024ULL; + uma_memory_size += uma_size * 1024ULL; + printk(BIOS_DEBUG, "TSEG base 0x%08x size %uM\n", + tseg_base, uma_size >> 10); + + printk(BIOS_INFO, "Available memory below 4GB: %lluM\n", tomk >> 10); + + /* Report the memory regions */ + ram_resource(dev, 3, 0, legacy_hole_base_k); + ram_resource(dev, 4, legacy_hole_base_k + legacy_hole_size_k, + (tomk - (legacy_hole_base_k + legacy_hole_size_k))); + + /* + * If >= 4GB installed then memory from TOLUD to 4GB + * is remapped above TOM, TOUUD will account for both + */ + touud >>= 10; /* Convert to KB */ + if (touud > 4096 * 1024) { + ram_resource(dev, 5, 4096 * 1024, touud - (4096 * 1024)); + printk(BIOS_INFO, "Available memory above 4GB: %lluM\n", + (touud >> 10) - 4096); + } + + add_fixed_resources(dev, 6); + + assign_resources(dev->link_list); + + /* Leave some space for the HOB data above CBMem */ + set_top_of_ram((tomk - 2048) * 1024); +} + + /* TODO We could determine how many PCIe busses we need in + * the bar. For now that number is hardcoded to a max of 64. + * See e7525/northbridge.c for an example. + */ +static struct device_operations pci_domain_ops = { + .read_resources = pci_domain_read_resources, + .set_resources = pci_domain_set_resources, + .enable_resources = NULL, + .init = NULL, + .scan_bus = pci_domain_scan_bus, + .ops_pci_bus = pci_bus_default_ops, +}; + +static void mc_read_resources(device_t dev) +{ + struct resource *resource; + + pci_dev_read_resources(dev); + + /* So, this is one of the big mysteries in the coreboot resource + * allocator. This resource should make sure that the address space + * of the PCIe memory mapped config space bar. But it does not. + */ + + /* We use 0xcf as an unused index for our PCIe bar so that we find it again */ + resource = new_resource(dev, 0xcf); + resource->base = DEFAULT_PCIEXBAR; + resource->size = 64 * 1024 * 1024; /* 64MB hard coded PCIe config space */ + resource->flags = + IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED | + IORESOURCE_ASSIGNED; + printk(BIOS_DEBUG, "Adding PCIe enhanced config space BAR 0x%08lx-0x%08lx.\n", + (unsigned long)(resource->base), (unsigned long)(resource->base + resource->size)); +} + +static void mc_set_resources(device_t dev) +{ + struct resource *resource; + + /* Report the PCIe BAR */ + resource = find_resource(dev, 0xcf); + if (resource) { + report_resource_stored(dev, resource, "<mmconfig>"); + } + + /* And call the normal set_resources */ + pci_dev_set_resources(dev); +} + +static void intel_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +static void northbridge_init(struct device *dev) +{ + u8 bios_reset_cpl; + + /* + * Set bit 0 of BIOS_RESET_CPL to indicate to the CPU + * that BIOS has initialized memory and power management + */ + bios_reset_cpl = MCHBAR8(BIOS_RESET_CPL); + bios_reset_cpl |= 1; + MCHBAR8(BIOS_RESET_CPL) = bios_reset_cpl; + printk(BIOS_DEBUG, "Set BIOS_RESET_CPL\n"); +} + +static void northbridge_enable(device_t dev) +{ +#if CONFIG_HAVE_ACPI_RESUME + switch (pci_read_config32(dev, SKPAD)) { + case 0xcafebabe: + printk(BIOS_DEBUG, "Normal boot.\n"); + acpi_slp_type=0; + break; + case 0xcafed00d: + printk(BIOS_DEBUG, "S3 Resume.\n"); + acpi_slp_type=3; + break; + default: + printk(BIOS_DEBUG, "Unknown boot method, assuming normal.\n"); + acpi_slp_type=0; + break; + } +#endif +} + +static struct pci_operations intel_pci_ops = { + .set_subsystem = intel_set_subsystem, +}; + +static struct device_operations mc_ops = { + .read_resources = mc_read_resources, + .set_resources = mc_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = northbridge_init, + .enable = northbridge_enable, + .scan_bus = 0, + .ops_pci = &intel_pci_ops, +}; + +static const struct pci_driver mc_driver_0100 __pci_driver = { + .ops = &mc_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x0100, +}; + +static const struct pci_driver mc_driver __pci_driver = { + .ops = &mc_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x0104, /* Sandy bridge */ +}; + +static const struct pci_driver mc_driver_1 __pci_driver = { + .ops = &mc_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x0154, /* Ivy bridge */ +}; + +static void cpu_bus_init(device_t dev) +{ + initialize_cpus(dev->link_list); +} + + +static void cpu_bus_noop(device_t dev) +{ +} + +static struct device_operations cpu_bus_ops = { + .read_resources = cpu_bus_noop, + .set_resources = cpu_bus_noop, + .enable_resources = cpu_bus_noop, + .init = cpu_bus_init, + .scan_bus = 0, +}; + +static void enable_dev(device_t dev) +{ + /* Set the operations if it is a special bus type */ + if (dev->path.type == DEVICE_PATH_DOMAIN) { + dev->ops = &pci_domain_ops; + } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) { + dev->ops = &cpu_bus_ops; + } + + /* + * Notify FSP for PostPciEnumeration. + * This call needs to be done before resource allocation. + */ + if (!finished_FSP_after_pci) { + finished_FSP_after_pci = 1; + printk(BIOS_DEBUG, "FspNotify(EnumInitPhaseAfterPciEnumeration)\n"); + FspNotify(EnumInitPhaseAfterPciEnumeration); + printk(BIOS_DEBUG, + "Returned from FspNotify(EnumInitPhaseAfterPciEnumeration)\n\n"); + } +} + +static void finalize_chip(void *chip_info) +{ + /* Notify FSP for ReadyToBoot */ + printk(BIOS_DEBUG, "FspNotify(EnumInitPhaseReadyToBoot)\n"); + print_fsp_info(); + FspNotify(EnumInitPhaseReadyToBoot); + printk(BIOS_DEBUG, "Returned from FspNotify(EnumInitPhaseReadyToBoot)\n"); +} + +struct chip_operations northbridge_intel_fsp_sandybridge_ops = { + CHIP_NAME("Intel i7 (SandyBridge/IvyBridge) integrated Northbridge") + .enable_dev = enable_dev, + .final = finalize_chip, +}; diff --git a/src/northbridge/intel/fsp_sandybridge/northbridge.h b/src/northbridge/intel/fsp_sandybridge/northbridge.h new file mode 100644 index 0000000..3179832 --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/northbridge.h @@ -0,0 +1,245 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2008 coresystems GmbH + * Copyright (C) 2011 Google Inc. + * Copyright (C) 2013 Sage Electronic Engineering, LLC. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __NORTHBRIDGE_INTEL_SANDYBRIDGE_SANDYBRIDGE_H__ +#define __NORTHBRIDGE_INTEL_SANDYBRIDGE_SANDYBRIDGE_H__ 1 + +/* Chipset types */ +#define SANDYBRIDGE_MOBILE 0 +#define SANDYBRIDGE_DESKTOP 1 +#define SANDYBRIDGE_SERVER 2 + +/* Device ID for SandyBridge and IvyBridge */ +#define BASE_REV_SNB 0x00 +#define BASE_REV_IVB 0x50 +#define BASE_REV_MASK 0x50 + +/* SandyBridge CPU stepping */ +#define SNB_STEP_D0 (BASE_REV_SNB + 5) /* Also J0 */ +#define SNB_STEP_D1 (BASE_REV_SNB + 6) +#define SNB_STEP_D2 (BASE_REV_SNB + 7) /* Also J1/Q0 */ + +/* IvyBridge CPU stepping */ +#define IVB_STEP_A0 (BASE_REV_IVB + 0) +#define IVB_STEP_B0 (BASE_REV_IVB + 2) +#define IVB_STEP_C0 (BASE_REV_IVB + 4) +#define IVB_STEP_K0 (BASE_REV_IVB + 5) +#define IVB_STEP_D0 (BASE_REV_IVB + 6) + +/* Intel Enhanced Debug region must be 4MB */ +#define IED_SIZE 0x400000 + +/* Northbridge BARs */ +#define DEFAULT_PCIEXBAR CONFIG_MMCONF_BASE_ADDRESS /* 4 KB per PCIe device */ +#define DEFAULT_MCHBAR 0xfed10000 /* 16 KB */ +#define DEFAULT_DMIBAR 0xfed18000 /* 4 KB */ +#define DEFAULT_EPBAR 0xfed19000 /* 4 KB */ +#define DEFAULT_RCBABASE 0xfed1c000 + +#if CONFIG_SOUTHBRIDGE_INTEL_FSP_BD82X6X +#include <southbridge/intel/fsp_bd82x6x/pch.h> +#endif + +/* Everything below this line is ignored in the DSDT */ +#ifndef __ACPI__ + +/* Device 0:0.0 PCI configuration space (Host Bridge) */ + +#define EPBAR 0x40 +#define MCHBAR 0x48 +#define PCIEXBAR 0x60 +#define DMIBAR 0x68 +#define X60BAR 0x60 + +#define GGC 0x50 /* GMCH Graphics Control */ + +#define DEVEN 0x54 /* Device Enable */ +#define DEVEN_PEG60 (1 << 13) +#define DEVEN_IGD (1 << 4) +#define DEVEN_PEG10 (1 << 3) +#define DEVEN_PEG11 (1 << 2) +#define DEVEN_PEG12 (1 << 1) +#define DEVEN_HOST (1 << 0) + +#define PAM0 0x80 +#define PAM1 0x81 +#define PAM2 0x82 +#define PAM3 0x83 +#define PAM4 0x84 +#define PAM5 0x85 +#define PAM6 0x86 + +#define LAC 0x87 /* Legacy Access Control */ +#define SMRAM 0x88 /* System Management RAM Control */ +#define D_OPEN (1 << 6) +#define D_CLS (1 << 5) +#define D_LCK (1 << 4) +#define G_SMRAME (1 << 3) +#define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0)) + +#define TOM 0xa0 +#define TOUUD 0xa8 /* Top of Upper Usable DRAM */ +#define TSEG 0xb8 /* TSEG base */ +#define TOLUD 0xbc /* Top of Low Used Memory */ + +#define SKPAD 0xdc /* Scratchpad Data */ + +/* Device 0:1.0 PCI configuration space (PCI Express) */ + +#define BCTRL1 0x3e /* 16bit */ + + +/* Device 0:2.0 PCI configuration space (Graphics Device) */ + +#define MSAC 0x62 /* Multi Size Aperture Control */ +#define SWSCI 0xe8 /* SWSCI enable */ +#define ASLS 0xfc /* OpRegion Base */ + +/* + * MCHBAR + */ + +#define MCHBAR8(x) *((volatile u8 *)(DEFAULT_MCHBAR + x)) +#define MCHBAR16(x) *((volatile u16 *)(DEFAULT_MCHBAR + x)) +#define MCHBAR32(x) *((volatile u32 *)(DEFAULT_MCHBAR + x)) +#define MCHBAR32_OR(x, or) MCHBAR32(x) = (MCHBAR32(x) | (or)) + +#define SSKPD 0x5d14 /* 16bit (scratchpad) */ +#define BIOS_RESET_CPL 0x5da8 /* 8bit */ + +/* + * EPBAR - Egress Port Root Complex Register Block + */ + +#define EPBAR8(x) *((volatile u8 *)(DEFAULT_EPBAR + x)) +#define EPBAR16(x) *((volatile u16 *)(DEFAULT_EPBAR + x)) +#define EPBAR32(x) *((volatile u32 *)(DEFAULT_EPBAR + x)) + +#define EPPVCCAP1 0x004 /* 32bit */ +#define EPPVCCAP2 0x008 /* 32bit */ + +#define EPVC0RCAP 0x010 /* 32bit */ +#define EPVC0RCTL 0x014 /* 32bit */ +#define EPVC0RSTS 0x01a /* 16bit */ + +#define EPVC1RCAP 0x01c /* 32bit */ +#define EPVC1RCTL 0x020 /* 32bit */ +#define EPVC1RSTS 0x026 /* 16bit */ + +#define EPVC1MTS 0x028 /* 32bit */ +#define EPVC1IST 0x038 /* 64bit */ + +#define EPESD 0x044 /* 32bit */ + +#define EPLE1D 0x050 /* 32bit */ +#define EPLE1A 0x058 /* 64bit */ +#define EPLE2D 0x060 /* 32bit */ +#define EPLE2A 0x068 /* 64bit */ + +#define PORTARB 0x100 /* 256bit */ + +/* + * DMIBAR + */ + +#define DMIBAR8(x) *((volatile u8 *)(DEFAULT_DMIBAR + x)) +#define DMIBAR16(x) *((volatile u16 *)(DEFAULT_DMIBAR + x)) +#define DMIBAR32(x) *((volatile u32 *)(DEFAULT_DMIBAR + x)) + +#define DMIVCECH 0x000 /* 32bit */ +#define DMIPVCCAP1 0x004 /* 32bit */ +#define DMIPVCCAP2 0x008 /* 32bit */ + +#define DMIPVCCCTL 0x00c /* 16bit */ + +#define DMIVC0RCAP 0x010 /* 32bit */ +#define DMIVC0RCTL0 0x014 /* 32bit */ +#define DMIVC0RSTS 0x01a /* 16bit */ + +#define DMIVC1RCAP 0x01c /* 32bit */ +#define DMIVC1RCTL 0x020 /* 32bit */ +#define DMIVC1RSTS 0x026 /* 16bit */ + +#define DMILE1D 0x050 /* 32bit */ +#define DMILE1A 0x058 /* 64bit */ +#define DMILE2D 0x060 /* 32bit */ +#define DMILE2A 0x068 /* 64bit */ + +#define DMILCAP 0x084 /* 32bit */ +#define DMILCTL 0x088 /* 16bit */ +#define DMILSTS 0x08a /* 16bit */ + +#define DMICTL1 0x0f0 /* 32bit */ +#define DMICTL2 0x0fc /* 32bit */ + +#define DMICC 0x208 /* 32bit */ + +#define DMIDRCCFG 0xeb4 /* 32bit */ + +#ifndef __ASSEMBLER__ +static inline void barrier(void) { asm("" ::: "memory"); } + +struct ied_header { + char signature[10]; + u32 size; + u8 reserved[34]; +} __attribute__ ((packed)); + +#define PCI_DEVICE_ID_SB 0x0104 +#define PCI_DEVICE_ID_IB 0x0154 + +#ifdef __SMM__ +void intel_sandybridge_finalize_smm(void); +#else /* !__SMM__ */ +int bridge_silicon_revision(void); +void sandybridge_early_initialization(int chipset_type); +void sandybridge_late_initialization(void); + +/* debugging functions */ +void print_pci_devices(void); +void dump_pci_device(unsigned dev); +void dump_pci_devices(void); +void dump_spd_registers(void); +void dump_mem(unsigned start, unsigned end); +void report_platform_info(void); +#endif /* !__SMM__ */ + + +#define MRC_DATA_ALIGN 0x1000 +#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24)) + +struct mrc_data_container { + u32 mrc_signature; // "MRCD" + u32 mrc_data_size; // Actual total size of this structure + u32 mrc_checksum; // IP style checksum + u32 reserved; // For header alignment + u8 mrc_data[0]; // Variable size, platform/run time dependent. +} __attribute__ ((packed)); + +struct mrc_data_container *find_current_mrc_cache(void); +#if !defined(__PRE_RAM__) +#include "gma.h" +int init_igd_opregion(igd_opregion_t *igd_opregion); +#endif + +#endif +#endif +#endif diff --git a/src/northbridge/intel/fsp_sandybridge/raminit.c b/src/northbridge/intel/fsp_sandybridge/raminit.c new file mode 100644 index 0000000..19b48ca --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/raminit.c @@ -0,0 +1,84 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <console/console.h> +#include <string.h> +#include <arch/io.h> +#include <cbmem.h> +#include <device/pci_def.h> +#include "raminit.h" +#include "northbridge.h" + +static const char* ecc_decoder[] = { + "inactive", + "active on IO", + "disabled on IO", + "active" +}; + +/* + * Dump in the log memory controller configuration as read from the memory + * controller registers. + */ +void report_memory_config(void) +{ + u32 addr_decoder_common, addr_decode_ch[2]; + int i; + + addr_decoder_common = MCHBAR32(0x5000); + addr_decode_ch[0] = MCHBAR32(0x5004); + addr_decode_ch[1] = MCHBAR32(0x5008); + + printk(BIOS_DEBUG, "memcfg DDR3 clock %d MHz\n", + (MCHBAR32(0x5e04) * 13333 * 2 + 50)/100); + printk(BIOS_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]; + printk(BIOS_DEBUG, "memcfg channel[%d] config (%8.8x):\n", + i, ch_conf); + printk(BIOS_DEBUG, " ECC %s\n", + ecc_decoder[(ch_conf >> 24) & 3]); + printk(BIOS_DEBUG, " enhanced interleave mode %s\n", + ((ch_conf >> 22) & 1) ? "on" : "off"); + printk(BIOS_DEBUG, " rank interleave %s\n", + ((ch_conf >> 21) & 1) ? "on" : "off"); + printk(BIOS_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"); + printk(BIOS_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" : ""); + } +} + +unsigned long get_top_of_ram(void) +{ + /* Base of TSEG is top of usable DRAM */ + u32 tom = pci_read_config32(PCI_DEV(0,0,0), TSEG) & ~(1UL << 0); + tom -= 0x200000; /* 2MB for FSP HOB */ + return (unsigned long) tom; +} diff --git a/src/northbridge/intel/fsp_sandybridge/raminit.h b/src/northbridge/intel/fsp_sandybridge/raminit.h new file mode 100644 index 0000000..73e563f --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/raminit.h @@ -0,0 +1,25 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef RAMINIT_H +#define RAMINIT_H + +void report_memory_config(void); + +#endif /* RAMINIT_H */ diff --git a/src/northbridge/intel/fsp_sandybridge/report_platform.c b/src/northbridge/intel/fsp_sandybridge/report_platform.c new file mode 100644 index 0000000..22e4b4b --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/report_platform.c @@ -0,0 +1,114 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Google Inc. + * Copyright (C) 2013 Sage Electronic Engineering, LLC. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <console/console.h> +#include <arch/cpu.h> +#include <string.h> + +#if CONFIG_SOUTHBRIDGE_INTEL_FSP_BD82X6X +#include <southbridge/intel/fsp_bd82x6x/pch.h> +#endif + +#include <arch/io.h> +#include "northbridge.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++; + + cpuidr = cpuid(1); + printk(BIOS_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; + printk(BIOS_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) +{ + int i; + u16 dev_id = pci_read_config16(PCH_LPC_DEV, 2); + + + const char *pch_type = "Unknown"; + 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; + } + } + printk (BIOS_DEBUG, "PCH type: %s, device id: %x, rev id %x\n", + pch_type, dev_id, pci_read_config8(PCH_LPC_DEV, 8)); +} + +void report_platform_info(void) +{ + report_cpu_info(); + report_pch_info(); +} diff --git a/src/northbridge/intel/fsp_sandybridge/udelay.c b/src/northbridge/intel/fsp_sandybridge/udelay.c new file mode 100644 index 0000000..36febe7 --- /dev/null +++ b/src/northbridge/intel/fsp_sandybridge/udelay.c @@ -0,0 +1,55 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2008 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <delay.h> +#include <stdint.h> +#include <cpu/x86/tsc.h> +#include <cpu/x86/msr.h> + +/** + * Intel SandyBridge/IvyBridge CPUs always run the TSC at BCLK=100MHz + */ + +void udelay(u32 us) +{ + u32 dword; + tsc_t tsc, tsc1, tscd; + msr_t msr; + u32 fsb = 100, divisor; + u32 d; /* ticks per us */ + + msr = rdmsr(0xce); + divisor = (msr.lo >> 8) & 0xff; + + d = fsb * divisor; /* On Core/Core2 this is divided by 4 */ + multiply_to_tsc(&tscd, us, d); + + tsc1 = rdtsc(); + dword = tsc1.lo + tscd.lo; + if ((dword < tsc1.lo) || (dword < tscd.lo)) { + tsc1.hi++; + } + tsc1.lo = dword; + tsc1.hi += tscd.hi; + + do { + tsc = rdtsc(); + } while ((tsc.hi < tsc1.hi) + || ((tsc.hi == tsc1.hi) && (tsc.lo <= tsc1.lo))); +}