mail.coreboot.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

coreboot-gerrit

Thread Start a new thread
Download
Threads by month
  • ----- 2025 -----
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2021 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2020 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2019 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2018 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2017 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2016 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2015 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2014 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2013 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
coreboot-gerrit@coreboot.org

May 2014

  • 1 participants
  • 1066 discussions
Patch set updated for coreboot: 88ae8dc fsp_baytrail: Add the FSP version of Intel's Bay Trail-I chip
by Martin Roth May 28, 2014

May 28, 2014
Martin Roth (gaumless(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5791 -gerrit commit 88ae8dc55fd0598a66ffba661a7db971a4e2f529 Author: Martin Roth <gaumless(a)gmail.com> Date: Mon May 12 21:55:00 2014 -0600 fsp_baytrail: Add the FSP version of Intel's Bay Trail-I chip While similar to the Bay Trail-M/D code based on the MRC, there are many differences as well: - Obviously, uses the FSP instead of the MRC binaries. - FSP does additional hardware setup, so coreboot doesn't need to. - Different microcode & microcode loading method - Uses the cache_as_ram.inc from the FSP Driver - Various other changes in support of the FSP Additional changes that don't have to to with the FSP vs MRC: - Updated IRQ Routing - Different FADT implementation. This was validated with FSP: BAYTRAIL_FSP_GOLD_002_10-JANUARY-2014.fd SHA256: d29eefbb33454bd5314bfaa38fb055d592a757de7b348ed7096cd8c2d65908a5 MD5: 9360cd915f0d3e4116bbc782233d7b91 Change-Id: Iadadf8cd6cf444ba840e0f76d3aed7825cd7aee4 Signed-off-by: Martin Roth <gaumless(a)gmail.com> Signed-off-by: Martin Roth <martin.roth(a)se-eng.com> --- src/soc/intel/Kconfig | 1 + src/soc/intel/Makefile.inc | 1 + src/soc/intel/fsp_baytrail/Kconfig | 162 +++++ src/soc/intel/fsp_baytrail/Makefile.inc | 90 +++ src/soc/intel/fsp_baytrail/acpi.c | 574 +++++++++++++++++ src/soc/intel/fsp_baytrail/acpi/cpu.asl | 77 +++ src/soc/intel/fsp_baytrail/acpi/device_nvs.asl | 87 +++ src/soc/intel/fsp_baytrail/acpi/globalnvs.asl | 103 +++ src/soc/intel/fsp_baytrail/acpi/gpio.asl | 110 ++++ src/soc/intel/fsp_baytrail/acpi/irq_helper.h | 55 ++ src/soc/intel/fsp_baytrail/acpi/irqlinks.asl | 493 ++++++++++++++ src/soc/intel/fsp_baytrail/acpi/irqroute.asl | 43 ++ src/soc/intel/fsp_baytrail/acpi/lpc.asl | 167 +++++ src/soc/intel/fsp_baytrail/acpi/lpe.asl | 119 ++++ src/soc/intel/fsp_baytrail/acpi/lpss.asl | 712 +++++++++++++++++++++ src/soc/intel/fsp_baytrail/acpi/platform.asl | 73 +++ src/soc/intel/fsp_baytrail/acpi/scc.asl | 187 ++++++ src/soc/intel/fsp_baytrail/acpi/sleepstates.asl | 26 + src/soc/intel/fsp_baytrail/acpi/southcluster.asl | 284 ++++++++ src/soc/intel/fsp_baytrail/acpi/usb.asl | 54 ++ src/soc/intel/fsp_baytrail/acpi/xhci.asl | 36 ++ src/soc/intel/fsp_baytrail/baytrail/acpi.h | 34 + src/soc/intel/fsp_baytrail/baytrail/baytrail.h | 74 +++ src/soc/intel/fsp_baytrail/baytrail/device_nvs.h | 67 ++ src/soc/intel/fsp_baytrail/baytrail/ehci.h | 44 ++ src/soc/intel/fsp_baytrail/baytrail/gfx.h | 48 ++ src/soc/intel/fsp_baytrail/baytrail/gpio.h | 387 +++++++++++ src/soc/intel/fsp_baytrail/baytrail/iomap.h | 90 +++ src/soc/intel/fsp_baytrail/baytrail/iosf.h | 195 ++++++ src/soc/intel/fsp_baytrail/baytrail/irq.h | 165 +++++ src/soc/intel/fsp_baytrail/baytrail/lpc.h | 112 ++++ src/soc/intel/fsp_baytrail/baytrail/msr.h | 41 ++ src/soc/intel/fsp_baytrail/baytrail/nvm.h | 34 + src/soc/intel/fsp_baytrail/baytrail/nvs.h | 73 +++ src/soc/intel/fsp_baytrail/baytrail/pattrs.h | 65 ++ src/soc/intel/fsp_baytrail/baytrail/pci_devs.h | 241 +++++++ src/soc/intel/fsp_baytrail/baytrail/pcie.h | 102 +++ src/soc/intel/fsp_baytrail/baytrail/pmc.h | 307 +++++++++ src/soc/intel/fsp_baytrail/baytrail/ramstage.h | 35 + src/soc/intel/fsp_baytrail/baytrail/reset.h | 36 ++ src/soc/intel/fsp_baytrail/baytrail/romstage.h | 52 ++ src/soc/intel/fsp_baytrail/baytrail/smm.h | 48 ++ src/soc/intel/fsp_baytrail/baytrail/spi.h | 68 ++ src/soc/intel/fsp_baytrail/baytrail/xhci.h | 56 ++ src/soc/intel/fsp_baytrail/bootblock/bootblock.c | 112 ++++ src/soc/intel/fsp_baytrail/chip.c | 116 ++++ src/soc/intel/fsp_baytrail/chip.h | 183 ++++++ src/soc/intel/fsp_baytrail/cpu.c | 278 ++++++++ src/soc/intel/fsp_baytrail/ehci.c | 180 ++++++ src/soc/intel/fsp_baytrail/fsp/Kconfig | 31 + src/soc/intel/fsp_baytrail/fsp/Makefile.inc | 22 + src/soc/intel/fsp_baytrail/fsp/chipset_fsp_util.c | 335 ++++++++++ src/soc/intel/fsp_baytrail/fsp/chipset_fsp_util.h | 49 ++ src/soc/intel/fsp_baytrail/gpio.c | 239 +++++++ src/soc/intel/fsp_baytrail/iosf.c | 111 ++++ src/soc/intel/fsp_baytrail/memmap.c | 28 + src/soc/intel/fsp_baytrail/microcode/Makefile.inc | 25 + .../intel/fsp_baytrail/microcode/microcode_blob.c | 25 + src/soc/intel/fsp_baytrail/northcluster.c | 222 +++++++ src/soc/intel/fsp_baytrail/nvm.c | 88 +++ src/soc/intel/fsp_baytrail/placeholders.c | 15 + src/soc/intel/fsp_baytrail/pmutil.c | 364 +++++++++++ src/soc/intel/fsp_baytrail/raminit.c | 48 ++ src/soc/intel/fsp_baytrail/ramstage.c | 138 ++++ src/soc/intel/fsp_baytrail/reset.c | 47 ++ src/soc/intel/fsp_baytrail/romstage/Makefile.inc | 26 + src/soc/intel/fsp_baytrail/romstage/pmc.c | 41 ++ .../intel/fsp_baytrail/romstage/report_platform.c | 88 +++ src/soc/intel/fsp_baytrail/romstage/romstage.c | 232 +++++++ src/soc/intel/fsp_baytrail/romstage/uart.c | 38 ++ src/soc/intel/fsp_baytrail/smihandler.c | 406 ++++++++++++ src/soc/intel/fsp_baytrail/smm.c | 132 ++++ src/soc/intel/fsp_baytrail/southcluster.c | 661 +++++++++++++++++++ src/soc/intel/fsp_baytrail/spi.c | 652 +++++++++++++++++++ src/soc/intel/fsp_baytrail/tsc_freq.c | 84 +++ 75 files changed, 10844 insertions(+) diff --git a/src/soc/intel/Kconfig b/src/soc/intel/Kconfig index 07099b3..3ddbf28 100644 --- a/src/soc/intel/Kconfig +++ b/src/soc/intel/Kconfig @@ -1 +1,2 @@ source src/soc/intel/baytrail/Kconfig +source src/soc/intel/fsp_baytrail/Kconfig diff --git a/src/soc/intel/Makefile.inc b/src/soc/intel/Makefile.inc index ad79817..b2f3cde 100644 --- a/src/soc/intel/Makefile.inc +++ b/src/soc/intel/Makefile.inc @@ -1 +1,2 @@ subdirs-$(CONFIG_SOC_INTEL_BAYTRAIL) += baytrail +subdirs-$(CONFIG_SOC_INTEL_FSP_BAYTRAIL) += fsp_baytrail diff --git a/src/soc/intel/fsp_baytrail/Kconfig b/src/soc/intel/fsp_baytrail/Kconfig new file mode 100644 index 0000000..220edf7 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/Kconfig @@ -0,0 +1,162 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2011 The ChromiumOS Authors. All rights reserved. +## Copyright (C) 2013-2014 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 SOC_INTEL_FSP_BAYTRAIL + bool + help + Bay Trail I part support using the Intel FSP. + +if SOC_INTEL_FSP_BAYTRAIL + +config CPU_SPECIFIC_OPTIONS + def_bool y + select ARCH_BOOTBLOCK_X86_32 + select ARCH_ROMSTAGE_X86_32 + select ARCH_RAMSTAGE_X86_32 + select DYNAMIC_CBMEM + select HAVE_HARD_RESET + select MMCONF_SUPPORT + select MMCONF_SUPPORT_DEFAULT + select RELOCATABLE_MODULES + select PARALLEL_MP + select REG_SCRIPT + select SMP + select SPI_FLASH + select SSE2 + select TSC_CONSTANT_RATE + select TSC_SYNC_MFENCE + select UDELAY_TSC + select SUPPORT_CPU_UCODE_IN_CBFS if INCLUDE_MICROCODE_IN_BUILD + select CPU_MICROCODE_ADDED_DURING_BUILD if INCLUDE_MICROCODE_IN_BUILD + select ROMSTAGE_RTC_INIT + +config BOOTBLOCK_CPU_INIT + string + default "soc/intel/fsp_baytrail/bootblock/bootblock.c" + +config MMCONF_BASE_ADDRESS + hex + default 0x80000000 + help + This is set by the FSP + +config MAX_CPUS + int + default 4 + +config CPU_ADDR_BITS + int + default 36 + +config SMM_TSEG_SIZE + hex + default 0x100000 + help + This is set by the FSP + +config SMM_RESERVED_SIZE + hex + default 0x100000 + +config VGA_BIOS_ID + string + default "8086,0f31" + help + This is the default PCI ID for the Bay Trail graphics + devices. This string names the vbios rom in cbfs. + +config INCLUDE_MICROCODE_IN_BUILD + bool "Build in microcode patch" + default n + help + Enable if the microcode patch is available. For the + BayTrail - I processors, the filename should start with + "M01". Using a microcode patch for the incorrect BayTrail + SKU will lead to unpredictable results. + +config MICROCODE_INCLUDE_PATH + string "Microcode Include path" + default "../intel/cpu/baytrail/microcode" + depends on SUPPORT_CPU_UCODE_IN_CBFS + +config CPU_MICROCODE_CBFS_LOC + hex + default 0xfff10040 + +config CPU_MICROCODE_CBFS_LEN + hex + default 0xcc00 + help + This should be updated when the microcode patch changes. + +config CBFS_SIZE + hex + default 0x200000 + help + On Bay Trail systems the firmware image has to store a lot more + than just coreboot, including: + - a firmware descriptor + - Intel Trusted Execution Engine firmware + This option specifies the maximum size of the CBFS portion in the + firmware image. + +config INCLUDE_ME + bool "Include the TXE" + default n + help + Build the TXE and descriptor.bin into the ROM image. If you want to use a + descriptor.bin and TXE file from the previous ROM image, you may not want + to build it in here. + +config ME_PATH + string + depends on INCLUDE_ME + help + The path of the TXE and Descriptor files. + +config LOCK_MANAGEMENT_ENGINE + bool "Lock TXE section" + default n + depends on INCLUDE_ME + help + The Intel Trusted Execution Engine supports preventing write accesses + from the host to the Management Engine section in the firmware + descriptor. If the ME section is locked, it can only be overwritten + with an external SPI flash programmer. You will want this if you + want to increase security of your ROM image once you are sure + that the ME firmware is no longer going to change. + + If unsure, say N. + +config ENABLE_BUILTIN_COM1 + bool "Enable built-in legacy Serial Port" + help + The Baytrail SOC has one legacy serial port. Choose this option to + configure the pads and enable it. This serial port can be used for + the debug console. + +config VGA_BIOS_FILE + string + default "../intel/cpu/baytrail/vbios/Baytrail_I_36_2_2/Vga.dat" if VGA_BIOS + +## Baytrail Specific FSP Kconfig +source src/soc/intel/fsp_baytrail/fsp/Kconfig + +endif #SOC_INTEL_FSP_BAYTRAIL diff --git a/src/soc/intel/fsp_baytrail/Makefile.inc b/src/soc/intel/fsp_baytrail/Makefile.inc new file mode 100644 index 0000000..e0f1e1d --- /dev/null +++ b/src/soc/intel/fsp_baytrail/Makefile.inc @@ -0,0 +1,90 @@ +# +# This file is part of the coreboot project. +# +# Copyright (C) 2010 Google Inc. +# Copyright (C) 2013-2014 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 +# +subdirs-y += microcode +subdirs-y += romstage +subdirs-y += ../../../cpu/x86/lapic +subdirs-y += ../../../cpu/x86/mtrr +subdirs-$(CONFIG_HAVE_SMI_HANDLER) += ../../../cpu/x86/smm +subdirs-y += ../../../cpu/x86/tsc +subdirs-y += ../../../cpu/x86/cache +subdirs-y += ../../../cpu/intel/turbo +subdirs-y += ../../../lib/fsp +subdirs-y += fsp + +ramstage-y += memmap.c +romstage-y += memmap.c +ramstage-y += tsc_freq.c +romstage-y += tsc_freq.c +smm-$(CONFIG_HAVE_SMI_HANDLER) += tsc_freq.c +ramstage-$(CONFIG_CACHE_MRC_SETTINGS) += nvm.c +ramstage-y += spi.c +smm-$(CONFIG_HAVE_SMI_HANDLER) += spi.c +ramstage-y += chip.c +ramstage-y += iosf.c +romstage-y += iosf.c +ramstage-y += northcluster.c +ramstage-y += ramstage.c +ramstage-y += gpio.c +ramstage-y += pmutil.c +romstage-y += raminit.c +ramstage-y += raminit.c +ramstage-y += southcluster.c +romstage-y += reset.c +ramstage-y += reset.c +ramstage-y += cpu.c +ramstage-y += acpi.c +smm-$(CONFIG_HAVE_SMI_HANDLER) += pmutil.c +smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c +ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smm.c + +ramstage-y += placeholders.c + +CPPFLAGS_common += -I$(src)/soc/intel/fsp_baytrail/ +CPPFLAGS_common += -I$(src)/soc/intel/fsp_baytrail/fsp + +# Run an intermediate step when producing coreboot.rom +# that adds additional components to the final firmware +# image outside of CBFS +ifeq ($(CONFIG_INCLUDE_ME),y) +ifneq ($(CONFIG_ME_PATH),) +INTERMEDIATE:=baytrail_add_txe + +baytrail_add_txe: $(obj)/coreboot.pre $(IFDTOOL) + printf " DD Adding Intel Firmware Descriptor\n" + dd if=$(call strip_quotes,$(CONFIG_ME_PATH))/descriptor.bin \ + of=$(obj)/coreboot.pre conv=notrunc >/dev/null 2>&1 + printf " IFDTOOL txe.bin -> coreboot.pre\n" + $(objutil)/ifdtool/ifdtool \ + -i ME:$(call strip_quotes,$(CONFIG_ME_PATH))/txe.bin \ + $(obj)/coreboot.pre + mv $(obj)/coreboot.pre.new $(obj)/coreboot.pre +ifeq ($(CONFIG_LOCK_MANAGEMENT_ENGINE),y) + printf " IFDTOOL Locking Management Engine\n" + $(objutil)/ifdtool/ifdtool -l $(obj)/coreboot.pre + mv $(obj)/coreboot.pre.new $(obj)/coreboot.pre +else + printf " IFDTOOL Unlocking Management Engine\n" + $(objutil)/ifdtool/ifdtool -u $(obj)/coreboot.pre + mv $(obj)/coreboot.pre.new $(obj)/coreboot.pre +endif + +endif +endif + diff --git a/src/soc/intel/fsp_baytrail/acpi.c b/src/soc/intel/fsp_baytrail/acpi.c new file mode 100644 index 0000000..dece178 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi.c @@ -0,0 +1,574 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009 coresystems GmbH + * Copyright (C) 2011 The Chromium OS Authors. All rights reserved. + * Copyright (C) 2013-2014 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 <console/console.h> +#include <arch/acpi.h> +#include <arch/acpigen.h> +#include <arch/cpu.h> +#include <cpu/x86/msr.h> +#include <cpu/intel/speedstep.h> +#include <cpu/intel/turbo.h> +#include <arch/smp/mpspec.h> +#include <device/device.h> +#include <device/pci.h> +#include <baytrail/baytrail.h> +#include <device/pci_ids.h> +#include <baytrail/pci_devs.h> +#include <baytrail/acpi.h> +#include <string.h> +#include <baytrail/iomap.h> +#include <baytrail/lpc.h> +#include <baytrail/pci_devs.h> +#include <baytrail/pmc.h> +#include <baytrail/irq.h> +#include <baytrail/iosf.h> +#include <arch/io.h> +#include <baytrail/msr.h> +#include <baytrail/pattrs.h> +#include <baytrail/pmc.h> +#include <cbmem.h> + +#include "chip.h" + +#define MWAIT_RES(state, sub_state) \ + { \ + .addrl = (((state) << 4) | (sub_state)), \ + .space_id = ACPI_ADDRESS_SPACE_FIXED, \ + .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL, \ + .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT, \ + .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD, \ + } + +/* C-state map without S0ix */ +static acpi_cstate_t cstate_map[] = { + { + /* C1 */ + .ctype = 1, /* ACPI C1 */ + .latency = 1, + .power = 1000, + .resource = MWAIT_RES(0, 0), + }, + { + /* C6NS with no L2 shrink */ + /* NOTE: this substate is above CPUID limit */ + .ctype = 2, /* ACPI C2 */ + .latency = 500, + .power = 10, + .resource = MWAIT_RES(5, 1), + }, + { + /* C6FS with full L2 shrink */ + .ctype = 3, /* ACPI C3 */ + .latency = 1500, /* 1.5ms worst case */ + .power = 10, + .resource = MWAIT_RES(5, 2), + } +}; + +void acpi_init_gnvs(global_nvs_t *gnvs) +{ + /* CPU core count */ + gnvs->pcnt = dev_count_cpu(); + + /* Top of Low Memory (start of resource allocation) */ + gnvs->tolm = nc_read_top_of_low_memory(); + +#if IS_ENABLED(CONFIG_CONSOLE_CBMEM) + /* Update the mem console pointer. */ + gnvs->cbmc = (u32)cbmem_find(CBMEM_ID_CONSOLE); +#endif +} + +static int acpi_sci_irq(void) +{ + const unsigned long actl = ILB_BASE_ADDRESS + ACTL; + int scis; + static int sci_irq; + + if (sci_irq) + return sci_irq; + + /* Determine how SCI is routed. */ + scis = read32(actl) & SCIS_MASK; + switch (scis) { + case SCIS_IRQ9: + case SCIS_IRQ10: + case SCIS_IRQ11: + sci_irq = scis - SCIS_IRQ9 + 9; + break; + case SCIS_IRQ20: + case SCIS_IRQ21: + case SCIS_IRQ22: + case SCIS_IRQ23: + sci_irq = scis - SCIS_IRQ20 + 20; + break; + default: + printk(BIOS_DEBUG, "Invalid SCI route! Defaulting to IRQ9.\n"); + sci_irq = 9; + break; + } + + printk(BIOS_DEBUG, "SCI is IRQ%d\n", sci_irq); + return sci_irq; +} + +void acpi_create_intel_hpet(acpi_hpet_t * hpet) +{ + acpi_header_t *header = &(hpet->header); + acpi_addr_t *addr = &(hpet->addr); + + memset((void *) hpet, 0, sizeof(acpi_hpet_t)); + + /* fill out header fields */ + memcpy(header->signature, "HPET", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(acpi_hpet_t); + header->revision = 1; + + /* fill out HPET address */ + addr->space_id = 0; /* Memory */ + addr->bit_width = 64; + addr->bit_offset = 0; + addr->addrl = (unsigned long long)HPET_BASE_ADDRESS & 0xffffffff; + addr->addrh = (unsigned long long)HPET_BASE_ADDRESS >> 32; + + hpet->id = 0x8086a201; /* Intel */ + hpet->number = 0x00; + hpet->min_tick = 0x0080; + + header->checksum = + acpi_checksum((void *) hpet, sizeof(acpi_hpet_t)); +} + +unsigned long acpi_fill_mcfg(unsigned long current) +{ + current += acpi_create_mcfg_mmconfig((acpi_mcfg_mmconfig_t *)current, + MCFG_BASE_ADDRESS, 0, 0, 255); + return current; +} + +/** + * Fill in the fadt with generic values that can be overridden later. + */ + +typedef struct soc_intel_fsp_baytrail_config config_t; + +void acpi_fill_in_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt) +{ + acpi_header_t *header = &(fadt->header); + struct device *lpcdev = dev_find_slot(FADT_SOC_LPC_DEV); + u16 pmbase = pci_read_config16(lpcdev, ABASE) & 0xfff0; + config_t *config = lpcdev->chip_info; + + memset((void *) fadt, 0, sizeof(acpi_fadt_t)); + + /* + * Reference section 5.2.9 Fixed ACPI Description Table (FADT) + * in the ACPI 3.0b specification. + */ + + /* FADT Header Structure */ + memcpy(header->signature, "FACP", 4); + header->length = sizeof(acpi_fadt_t); + header->revision = ACPI_FADT_REV_ACPI_3_0; + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + header->asl_compiler_revision = 1; + + /* ACPI Pointers */ + fadt->firmware_ctrl = (unsigned long) facs; + fadt->dsdt = (unsigned long) dsdt; + + fadt->model = 0; /* reserved, should be 0 ACPI 3.0 */ + fadt->preferred_pm_profile = config->fadt_pm_profile; /* unknown is default */ + + /* System Management */ + fadt->sci_int = acpi_sci_irq(); +#if IS_ENABLED(CONFIG_BAYTRAIL_SMM) + fadt->smi_cmd = APM_CNT; + fadt->acpi_enable = APM_CNT_ACPI_ENABLE; + fadt->acpi_disable = APM_CNT_ACPI_DISABLE; +#else + fadt->smi_cmd = 0x00; /* disable SMM */ + fadt->acpi_enable = 0x00; /* unused if SMI_CMD = 0 */ + fadt->acpi_disable = 0x00; /* unused if SMI_CMD = 0 */ + + /* Enable ACPI */ + outl(inl(pmbase + 4) | 0x01, pmbase + 4); +#endif + + /* Power Control */ + fadt->s4bios_req = 0x00; + fadt->pstate_cnt = 0x00; + + /* Control Registers - Base Address */ + fadt->pm1a_evt_blk = pmbase + PM1_STS; + fadt->pm1b_evt_blk = 0x00; /* Not Used */ + fadt->pm1a_cnt_blk = pmbase + PM1_CNT; + fadt->pm1b_cnt_blk = 0x00; /* Not Used */ + fadt->pm2_cnt_blk = pmbase + PM2A_CNT_BLK; + fadt->pm_tmr_blk = pmbase + PM1_TMR; + fadt->gpe0_blk = pmbase + GPE0_STS; + fadt->gpe1_blk = 0x00; /* Not Used */ + + /* Control Registers - Length */ + fadt->pm1_evt_len = 4; /* 32 bits */ + fadt->pm1_cnt_len = 2; /* 32 bit register, 16 bits used */ + fadt->pm2_cnt_len = 1; /* 8 bits */ + fadt->pm_tmr_len = 4; /* 32 bits */ + fadt->gpe0_blk_len = 8; /* 64 bits */ + fadt->gpe1_blk_len = 0; + fadt->gpe1_base = 0; + fadt->cst_cnt = 0; + fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED; + fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED; + fadt->flush_size = 0; /* set to 0 if WBINVD is 1 in flags */ + fadt->flush_stride = 0; /* set to 0 if WBINVD is 1 in flags */ + fadt->duty_offset = 1; + fadt->duty_width = 0; + + /* RTC Registers */ + fadt->day_alrm = 0x0D; + fadt->mon_alrm = 0x00; + fadt->century = 0x00; + fadt->iapc_boot_arch = config->fadt_boot_arch; /* legacy free default */ + + fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED | + ACPI_FADT_C2_MP_SUPPORTED | ACPI_FADT_SLEEP_BUTTON | + ACPI_FADT_RESET_REGISTER | ACPI_FADT_SLEEP_TYPE | + ACPI_FADT_S4_RTC_WAKE | ACPI_FADT_PLATFORM_CLOCK; + + /* Reset Register */ + fadt->reset_reg.space_id = ACPI_ADDRESS_SPACE_IO; + fadt->reset_reg.bit_width = 8; + fadt->reset_reg.bit_offset = 0; + fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS; + fadt->reset_reg.addrl = 0xCF9; + fadt->reset_reg.addrh = 0x00; + fadt->reset_value = 6; + + /* Reserved Bits */ + fadt->res3 = 0x00; /* reserved, MUST be 0 ACPI 3.0 */ + fadt->res4 = 0x00; /* reserved, MUST be 0 ACPI 3.0 */ + fadt->res5 = 0x00; /* reserved, MUST be 0 ACPI 3.0 */ + + /* Extended ACPI Pointers */ + fadt->x_firmware_ctl_l = (unsigned long)facs; + fadt->x_firmware_ctl_h = 0x00; + fadt->x_dsdt_l = (unsigned long)dsdt; + fadt->x_dsdt_h = 0x00; + + /* PM1 Status & PM1 Enable */ + fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO; + fadt->x_pm1a_evt_blk.bit_width = 32; + fadt->x_pm1a_evt_blk.bit_offset = 0; + fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS; + fadt->x_pm1a_evt_blk.addrl = fadt->pm1a_evt_blk; + fadt->x_pm1a_evt_blk.addrh = 0x00; + + fadt->x_pm1b_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO; + fadt->x_pm1b_evt_blk.bit_width = 0; + fadt->x_pm1b_evt_blk.bit_offset = 0; + fadt->x_pm1b_evt_blk.access_size = 0; + fadt->x_pm1b_evt_blk.addrl = fadt->pm1b_evt_blk; + fadt->x_pm1b_evt_blk.addrh = 0x00; + + /* PM1 Control Registers */ + fadt->x_pm1a_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO; + fadt->x_pm1a_cnt_blk.bit_width = 16; + fadt->x_pm1a_cnt_blk.bit_offset = 0; + fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS; + fadt->x_pm1a_cnt_blk.addrl = fadt->pm1a_cnt_blk; + fadt->x_pm1a_cnt_blk.addrh = 0x00; + + fadt->x_pm1b_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO; + fadt->x_pm1b_cnt_blk.bit_width = 0; + fadt->x_pm1b_cnt_blk.bit_offset = 0; + fadt->x_pm1b_cnt_blk.access_size = 0; + fadt->x_pm1b_cnt_blk.addrl = fadt->pm1b_cnt_blk; + fadt->x_pm1b_cnt_blk.addrh = 0x00; + + /* PM2 Control Registers */ + fadt->x_pm2_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO; + fadt->x_pm2_cnt_blk.bit_width = 8; + fadt->x_pm2_cnt_blk.bit_offset = 0; + fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS; + fadt->x_pm2_cnt_blk.addrl = fadt->pm2_cnt_blk; + fadt->x_pm2_cnt_blk.addrh = 0x00; + + /* PM1 Timer Register */ + fadt->x_pm_tmr_blk.space_id = ACPI_ADDRESS_SPACE_IO; + fadt->x_pm_tmr_blk.bit_width = 32; + fadt->x_pm_tmr_blk.bit_offset = 0; + fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS; + fadt->x_pm_tmr_blk.addrl = fadt->pm_tmr_blk; + fadt->x_pm_tmr_blk.addrh = 0x00; + + /* General-Purpose Event Registers */ + fadt->x_gpe0_blk.space_id = ACPI_ADDRESS_SPACE_IO; + fadt->x_gpe0_blk.bit_width = 64; /* EventStatus + EventEnable */ + fadt->x_gpe0_blk.bit_offset = 0; + fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS; + fadt->x_gpe0_blk.addrl = fadt->gpe0_blk; + fadt->x_gpe0_blk.addrh = 0x00; + + fadt->x_gpe1_blk.space_id = ACPI_ADDRESS_SPACE_IO; + fadt->x_gpe1_blk.bit_width = 0; + fadt->x_gpe1_blk.bit_offset = 0; + fadt->x_gpe1_blk.access_size = 0; + fadt->x_gpe1_blk.addrl = fadt->gpe1_blk; + fadt->x_gpe1_blk.addrh = 0x00; + + header->checksum = + acpi_checksum((void *) fadt, sizeof(acpi_fadt_t)); +} +static acpi_tstate_t baytrail_tss_table[] = { + { 100, 1000, 0, 0x00, 0 }, + { 88, 875, 0, 0x1e, 0 }, + { 75, 750, 0, 0x1c, 0 }, + { 63, 625, 0, 0x1a, 0 }, + { 50, 500, 0, 0x18, 0 }, + { 38, 375, 0, 0x16, 0 }, + { 25, 250, 0, 0x14, 0 }, + { 13, 125, 0, 0x12, 0 }, +}; + +static int generate_T_state_entries(int core, int cores_per_package) +{ + int len; + + /* Indicate SW_ALL coordination for T-states */ + len = acpigen_write_TSD_package(core, cores_per_package, SW_ALL); + + /* Indicate FFixedHW so OS will use MSR */ + len += acpigen_write_empty_PTC(); + + /* Set NVS controlled T-state limit */ + len += acpigen_write_TPC("\\TLVL"); + + /* Write TSS table for MSR access */ + len += acpigen_write_TSS_package( + ARRAY_SIZE(baytrail_tss_table), baytrail_tss_table); + + return len; +} + +static int calculate_power(int tdp, int p1_ratio, int ratio) +{ + u32 m; + u32 power; + + /* + * M = ((1.1 - ((p1_ratio - ratio) * 0.00625)) / 1.1) ^ 2 + * + * Power = (ratio / p1_ratio) * m * tdp + */ + + m = (110000 - ((p1_ratio - ratio) * 625)) / 11; + m = (m * m) / 1000; + + power = ((ratio * 100000 / p1_ratio) / 100); + power *= (m / 100) * (tdp / 1000); + power /= 1000; + + return (int)power; +} + +static int generate_P_state_entries(int core, int cores_per_package) +{ + int len, len_pss; + int ratio_min, ratio_max, ratio_turbo, ratio_step, ratio_range_2; + int coord_type, power_max, power_unit, num_entries; + int ratio, power, clock, clock_max; + int vid, vid_turbo, vid_min, vid_max, vid_range_2; + u32 control_status; + const struct pattrs *pattrs = pattrs_get(); + msr_t msr; + + /* Inputs from CPU attributes */ + ratio_max = pattrs->iacore_ratios[IACORE_MAX]; + ratio_min = pattrs->iacore_ratios[IACORE_LFM]; + vid_max = pattrs->iacore_vids[IACORE_MAX]; + vid_min = pattrs->iacore_vids[IACORE_LFM]; + + /* Hardware coordination of P-states */ + coord_type = HW_ALL; + + /* Max Non-Turbo Frequency */ + clock_max = (ratio_max * pattrs->bclk_khz) / 1000; + + /* Calculate CPU TDP in mW */ + msr = rdmsr(MSR_PKG_POWER_SKU_UNIT); + power_unit = 1 << (msr.lo & 0xf); + msr = rdmsr(MSR_PKG_POWER_LIMIT); + power_max = ((msr.lo & 0x7fff) / power_unit) * 1000; + + /* Write _PCT indicating use of FFixedHW */ + len = acpigen_write_empty_PCT(); + + /* Write _PPC with NVS specified limit on supported P-state */ + len += acpigen_write_PPC_NVS(); + + /* Write PSD indicating configured coordination type */ + len += acpigen_write_PSD_package(core, 1, coord_type); + + /* Add P-state entries in _PSS table */ + len += acpigen_write_name("_PSS"); + + /* Determine ratio points */ + ratio_step = 1; + num_entries = (ratio_max - ratio_min) / ratio_step; + while (num_entries > 15) { /* ACPI max is 15 ratios */ + ratio_step <<= 1; + num_entries >>= 1; + } + + /* P[T] is Turbo state if enabled */ + if (get_turbo_state() == TURBO_ENABLED) { + /* _PSS package count including Turbo */ + len_pss = acpigen_write_package(num_entries + 2); + + ratio_turbo = pattrs->iacore_ratios[IACORE_TURBO]; + vid_turbo = pattrs->iacore_vids[IACORE_TURBO]; + control_status = (ratio_turbo << 8) | vid_turbo; + + /* Add entry for Turbo ratio */ + len_pss += acpigen_write_PSS_package( + clock_max + 1, /*MHz*/ + power_max, /*mW*/ + 10, /*lat1*/ + 10, /*lat2*/ + control_status, /*control*/ + control_status); /*status*/ + } else { + /* _PSS package count without Turbo */ + len_pss = acpigen_write_package(num_entries + 1); + ratio_turbo = ratio_max; + vid_turbo = vid_max; + } + + /* First regular entry is max non-turbo ratio */ + control_status = (ratio_max << 8) | vid_max; + len_pss += acpigen_write_PSS_package( + clock_max, /*MHz*/ + power_max, /*mW*/ + 10, /*lat1*/ + 10, /*lat2*/ + control_status, /*control */ + control_status); /*status*/ + + /* Set up ratio and vid ranges for VID calculation */ + ratio_range_2 = (ratio_turbo - ratio_min) * 2; + vid_range_2 = (vid_turbo - vid_min) * 2; + + /* Generate the remaining entries */ + for (ratio = ratio_min + ((num_entries - 1) * ratio_step); + ratio >= ratio_min; ratio -= ratio_step) { + + /* Calculate VID for this ratio */ + vid = ((ratio - ratio_min) * vid_range_2) / + ratio_range_2 + vid_min; + /* Round up if remainder */ + if (((ratio - ratio_min) * vid_range_2) % ratio_range_2) + vid++; + + /* Calculate power at this ratio */ + power = calculate_power(power_max, ratio_max, ratio); + clock = (ratio * pattrs->bclk_khz) / 1000; + control_status = (ratio << 8) | (vid & 0xff); + + len_pss += acpigen_write_PSS_package( + clock, /*MHz*/ + power, /*mW*/ + 10, /*lat1*/ + 10, /*lat2*/ + control_status, /*control*/ + control_status); /*status*/ + } + + /* Fix package length */ + len_pss--; + acpigen_patch_len(len_pss); + + return len + len_pss; +} + +void generate_cpu_entries(void) +{ + int len_pr, core; + int pcontrol_blk = get_pmbase(), plen = 6; + const struct pattrs *pattrs = pattrs_get(); + + for (core=0; core<pattrs->num_cpus; core++) { + if (core > 0) { + pcontrol_blk = 0; + plen = 0; + } + + /* Generate processor \_PR.CPUx */ + len_pr = acpigen_write_processor( + core, pcontrol_blk, plen); + + /* Generate P-state tables */ + len_pr += generate_P_state_entries( + core, pattrs->num_cpus); + + /* Generate C-state tables */ + len_pr += acpigen_write_CST_package( + cstate_map, ARRAY_SIZE(cstate_map)); + + /* Generate T-state tables */ + len_pr += generate_T_state_entries( + core, pattrs->num_cpus); + + len_pr--; + acpigen_patch_len(len_pr); + } +} + +unsigned long acpi_madt_irq_overrides(unsigned long current) +{ + int sci_irq = acpi_sci_irq(); + acpi_madt_irqoverride_t *irqovr; + uint16_t sci_flags = MP_IRQ_TRIGGER_LEVEL; + + /* INT_SRC_OVR */ + irqovr = (void *)current; + current += acpi_create_madt_irqoverride(irqovr, 0, 0, 2, 0); + + if (sci_irq >= 20) + sci_flags |= MP_IRQ_POLARITY_LOW; + else + sci_flags |= MP_IRQ_POLARITY_HIGH; + + irqovr = (void *)current; + current += acpi_create_madt_irqoverride(irqovr, 0, sci_irq, sci_irq, + sci_flags); + + return current; +} diff --git a/src/soc/intel/fsp_baytrail/acpi/cpu.asl b/src/soc/intel/fsp_baytrail/acpi/cpu.asl new file mode 100644 index 0000000..16f62ba --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/cpu.asl @@ -0,0 +1,77 @@ +/* + * 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 + */ + +/* These devices are created at runtime */ +External (\_PR.CPU0, DeviceObj) +External (\_PR.CPU1, DeviceObj) +External (\_PR.CPU2, DeviceObj) +External (\_PR.CPU3, DeviceObj) + +/* Notify OS to re-read CPU tables, assuming ^2 CPU count */ +Method (PNOT) +{ + If (LGreaterEqual (\PCNT, 2)) { + Notify (\_PR.CPU0, 0x81) // _CST + Notify (\_PR.CPU1, 0x81) // _CST + } + If (LGreaterEqual (\PCNT, 4)) { + Notify (\_PR.CPU2, 0x81) // _CST + Notify (\_PR.CPU3, 0x81) // _CST + } +} + +/* Notify OS to re-read CPU _PPC limit, assuming ^2 CPU count */ +Method (PPCN) +{ + If (LGreaterEqual (\PCNT, 2)) { + Notify (\_PR.CPU0, 0x80) // _PPC + Notify (\_PR.CPU1, 0x80) // _PPC + } + If (LGreaterEqual (\PCNT, 4)) { + Notify (\_PR.CPU2, 0x80) // _PPC + Notify (\_PR.CPU3, 0x80) // _PPC + } +} + +/* Notify OS to re-read Throttle Limit tables, assuming ^2 CPU count */ +Method (TNOT) +{ + If (LGreaterEqual (\PCNT, 2)) { + Notify (\_PR.CPU0, 0x82) // _TPC + Notify (\_PR.CPU1, 0x82) // _TPC + } + If (LGreaterEqual (\PCNT, 4)) { + Notify (\_PR.CPU2, 0x82) // _TPC + Notify (\_PR.CPU3, 0x82) // _TPC + } +} + +/* Return a package containing enabled processor entries */ +Method (PPKG) +{ + If (LGreaterEqual (\PCNT, 4)) { + Return (Package() {\_PR.CPU0, \_PR.CPU1, \_PR.CPU2, \_PR.CPU3}) + } ElseIf (LGreaterEqual (\PCNT, 2)) { + Return (Package() {\_PR.CPU0, \_PR.CPU1}) + } Else { + Return (Package() {\_PR.CPU0}) + } +} diff --git a/src/soc/intel/fsp_baytrail/acpi/device_nvs.asl b/src/soc/intel/fsp_baytrail/acpi/device_nvs.asl new file mode 100644 index 0000000..fce7b53 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/device_nvs.asl @@ -0,0 +1,87 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 + */ + +/* Device Enabled in ACPI Mode */ + +S0EN, 8, // SDMA Enable +S1EN, 8, // I2C1 Enable +S2EN, 8, // I2C2 Enable +S3EN, 8, // I2C3 Enable +S4EN, 8, // I2C4 Enable +S5EN, 8, // I2C5 Enable +S6EN, 8, // I2C6 Enable +S7EN, 8, // I2C7 Enable +S8EN, 8, // SDMA2 Enable +S9EN, 8, // SPI Enable +SAEN, 8, // PWM1 Enable +SBEN, 8, // PWM2 Enable +SCEN, 8, // UART2 Enable +SDEN, 8, // UART2 Enable +C0EN, 8, // MMC Enable +C1EN, 8, // SDIO Enable +C2EN, 8, // SD Card Enable +LPEN, 8, // LPE Enable + +/* BAR 0 */ + +S0B0, 32, // SDMA BAR0 +S1B0, 32, // I2C1 BAR0 +S2B0, 32, // I2C2 BAR0 +S3B0, 32, // I2C3 BAR0 +S4B0, 32, // I2C4 BAR0 +S5B0, 32, // I2C5 BAR0 +S6B0, 32, // I2C6 BAR0 +S7B0, 32, // I2C7 BAR0 +S8B0, 32, // SDMA2 BAR0 +S9B0, 32, // SPI BAR0 +SAB0, 32, // PWM1 BAR0 +SBB0, 32, // PWM2 BAR0 +SCB0, 32, // UART1 BAR0 +SDB0, 32, // UART2 BAR0 +C0B0, 32, // MMC BAR0 +C1B0, 32, // SDIO BAR0 +C2B0, 32, // SD Card BAR0 +LPB0, 32, // LPE BAR0 + +/* BAR 1 */ + +S0B1, 32, // SDMA BAR1 +S1B1, 32, // I2C1 BAR1 +S2B1, 32, // I2C2 BAR1 +S3B1, 32, // I2C3 BAR1 +S4B1, 32, // I2C4 BAR1 +S5B1, 32, // I2C5 BAR1 +S6B1, 32, // I2C6 BAR1 +S7B1, 32, // I2C7 BAR1 +S8B1, 32, // SDMA2 BAR1 +S9B1, 32, // SPI BAR1 +SAB1, 32, // PWM1 BAR1 +SBB1, 32, // PWM2 BAR1 +SCB1, 32, // UART1 BAR1 +SDB1, 32, // UART2 BAR1 +C0B1, 32, // MMC BAR1 +C1B1, 32, // SDIO BAR1 +C2B1, 32, // SD Card BAR1 +LPB1, 32, // LPE BAR1 + +/* Extra */ + +LPFW, 32, // LPE BAR2 Firmware diff --git a/src/soc/intel/fsp_baytrail/acpi/globalnvs.asl b/src/soc/intel/fsp_baytrail/acpi/globalnvs.asl new file mode 100644 index 0000000..696390d --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/globalnvs.asl @@ -0,0 +1,103 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 + */ + +/* Global Variables */ + +Name(\PICM, 0) // IOAPIC/8259 + +/* Global ACPI memory region. This region is used for passing information + * between coreboot (aka "the system bios"), ACPI, and the SMI handler. + * Since we don't know where this will end up in memory at ACPI compile time, + * we have to fix it up in coreboot's ACPI creation phase. + */ + + +OperationRegion (GNVS, SystemMemory, 0xC0DEBABE, 0x2000) +Field (GNVS, ByteAcc, NoLock, Preserve) +{ + /* Miscellaneous */ + Offset (0x00), + OSYS, 16, // 0x00 - Operating System + SMIF, 8, // 0x02 - SMI function + PRM0, 8, // 0x03 - SMI function parameter + PRM1, 8, // 0x04 - SMI function parameter + SCIF, 8, // 0x05 - SCI function + PRM2, 8, // 0x06 - SCI function parameter + PRM3, 8, // 0x07 - SCI function parameter + LCKF, 8, // 0x08 - Global Lock function for EC + PRM4, 8, // 0x09 - Lock function parameter + PRM5, 8, // 0x0a - Lock function parameter + P80D, 32, // 0x0b - Debug port (IO 0x80) value + LIDS, 8, // 0x0f - LID state (open = 1) + PWRS, 8, // 0x10 - Power State (AC = 1) + PCNT, 8, // 0x11 - Processor count + TPMP, 8, // 0x12 - TPM Present and Enabled + TLVL, 8, // 0x13 - Throttle Level + PPCM, 8, // 0x14 - Maximum P-state usable by OS + + /* Device Config */ + Offset (0x20), + S5U0, 8, // 0x20 - Enable USB0 in S5 + S5U1, 8, // 0x21 - Enable USB1 in S5 + S3U0, 8, // 0x22 - Enable USB0 in S3 + S3U1, 8, // 0x23 - Enable USB1 in S3 + TACT, 8, // 0x24 - Thermal Active trip point + TPSV, 8, // 0x25 - Thermal Passive trip point + TCRT, 8, // 0x26 - Thermal Critical trip point + DPTE, 8, // 0x27 - Enable DPTF + + /* Base addresses */ + Offset (0x30), + CMEM, 32, // 0x30 - CBMEM TOC + TOLM, 32, // 0x34 - Top of Low Memory + CBMC, 32, // 0x38 - coreboot mem console pointer + + Offset (0x1000), + #include <soc/intel/fsp_baytrail/acpi/device_nvs.asl> +} + +/* Set flag to enable USB charging in S3 */ +Method (S3UE) +{ + Store (One, \S3U0) + Store (One, \S3U1) +} + +/* Set flag to disable USB charging in S3 */ +Method (S3UD) +{ + Store (Zero, \S3U0) + Store (Zero, \S3U1) +} + +/* Set flag to enable USB charging in S5 */ +Method (S5UE) +{ + Store (One, \S5U0) + Store (One, \S5U1) +} + +/* Set flag to disable USB charging in S5 */ +Method (S5UD) +{ + Store (Zero, \S5U0) + Store (Zero, \S5U1) +} diff --git a/src/soc/intel/fsp_baytrail/acpi/gpio.asl b/src/soc/intel/fsp_baytrail/acpi/gpio.asl new file mode 100644 index 0000000..f2618a8 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/gpio.asl @@ -0,0 +1,110 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 <soc/intel/fsp_baytrail/baytrail/iomap.h> +#include <soc/intel/fsp_baytrail/baytrail/irq.h> + +/* SouthCluster GPIO */ +Device (GPSC) +{ + Name (_HID, "INT33FC") + Name (_CID, "INT33FC") + Name (_UID, 1) + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, RMEM) + Interrupt (ResourceConsumer, Level, ActiveLow, Shared,,,) + { + GPIO_SC_IRQ + } + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^RMEM._BAS, RBAS) + Add (IO_BASE_ADDRESS, IO_BASE_OFFSET_GPSCORE, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + Return (0xF) + } +} + +/* NorthCluster GPIO */ +Device (GPNC) +{ + Name (_HID, "INT33FC") + Name (_CID, "INT33FC") + Name (_UID, 2) + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, RMEM) + Interrupt (ResourceConsumer, Level, ActiveLow, Shared,,,) + { + GPIO_NC_IRQ + } + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^RMEM._BAS, RBAS) + Add (IO_BASE_ADDRESS, IO_BASE_OFFSET_GPNCORE, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + Return (0xF) + } +} + +/* SUS GPIO */ +Device (GPSS) +{ + Name (_HID, "INT33FC") + Name (_CID, "INT33FC") + Name (_UID, 3) + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, RMEM) + Interrupt (ResourceConsumer, Level, ActiveLow, Shared,,,) + { + GPIO_SUS_IRQ + } + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^RMEM._BAS, RBAS) + Add (IO_BASE_ADDRESS, IO_BASE_OFFSET_GPSSUS, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + Return (0xF) + } +} diff --git a/src/soc/intel/fsp_baytrail/acpi/irq_helper.h b/src/soc/intel/fsp_baytrail/acpi/irq_helper.h new file mode 100644 index 0000000..e3a23d8 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/irq_helper.h @@ -0,0 +1,55 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2014 Sage Electronics 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 + */ + +/* + * This file will use arch/x86/acpi/irqroute.asl and mainboard/irqroute.h + * to generate the ACPI IRQ routing for the mainboard being compiled. + * This method uses #defines in irqroute.h along with the macros contained + * in this file to generate an IRQ routing for each PCI device in the system. + */ +#undef PCI_DEV_PIRQ_ROUTES +#undef ACPI_DEV_IRQ +#undef PCI_DEV_PIRQ_ROUTE +#undef PIRQ_PIC_ROUTES +#undef PIRQ_PIC + +#if defined(PIC_MODE) + +#define ACPI_DEV_IRQ(dev_, pin_, pin_name_) \ + Package() { ## dev_ ## ffff, pin_, \_SB.PCI0.LPCB.LNK ## pin_name_, 0 } + +#else /* defined(PIC_MODE) */ + +#define ACPI_DEV_IRQ(dev_, pin_, pin_name_) \ + Package() { ## dev_ ## ffff, pin_, 0, PIRQ ## pin_name_ ## _APIC_IRQ } + +#endif + +#define PCI_DEV_PIRQ_ROUTE(dev_, a_, b_, c_, d_) \ + ACPI_DEV_IRQ(dev_, 0, a_), \ + ACPI_DEV_IRQ(dev_, 1, b_), \ + ACPI_DEV_IRQ(dev_, 2, c_), \ + ACPI_DEV_IRQ(dev_, 3, d_) + +/* Empty PIRQ_PIC definition. */ +#define PIRQ_PIC(pirq_, pic_irq_) + +/* Include the mainboard irq route definition */ +#include "irqroute.h" diff --git a/src/soc/intel/fsp_baytrail/acpi/irqlinks.asl b/src/soc/intel/fsp_baytrail/acpi/irqlinks.asl new file mode 100644 index 0000000..5fcee45 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/irqlinks.asl @@ -0,0 +1,493 @@ +/* + * 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 (LNKA) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 1) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTA) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 1, 3, 4, 5, 6, 7, 10, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLA, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLA, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTA + ShiftLeft(1, And(PRTA, 0x0f), IRQ0) + + Return (RTLA) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTA) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTA, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} + +Device (LNKB) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 2) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTB) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 1, 3, 4, 5, 6, 7, 11, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLB, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLB, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTB + ShiftLeft(1, And(PRTB, 0x0f), IRQ0) + + Return (RTLB) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTB) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTB, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} + +Device (LNKC) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 3) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTC) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 1, 3, 4, 5, 6, 7, 10, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLC, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLC, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTC + ShiftLeft(1, And(PRTC, 0x0f), IRQ0) + + Return (RTLC) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTC) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTC, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} + +Device (LNKD) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 4) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTD) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 1, 3, 4, 5, 6, 7, 11, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLD, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLD, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTD + ShiftLeft(1, And(PRTD, 0x0f), IRQ0) + + Return (RTLD) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTD) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTD, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} + +Device (LNKE) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 5) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTE) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 1, 3, 4, 5, 6, 7, 10, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLE, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLE, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTE + ShiftLeft(1, And(PRTE, 0x0f), IRQ0) + + Return (RTLE) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTE) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTE, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} + +Device (LNKF) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 6) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTF) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 1, 3, 4, 5, 6, 7, 11, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLF, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLF, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTF + ShiftLeft(1, And(PRTF, 0x0f), IRQ0) + + Return (RTLF) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTF) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTF, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} + +Device (LNKG) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 7) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTG) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 1, 3, 4, 5, 6, 7, 10, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLG, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLG, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTG + ShiftLeft(1, And(PRTG, 0x0f), IRQ0) + + Return (RTLG) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTG) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTG, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} + +Device (LNKH) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 8) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTH) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 1, 3, 4, 5, 6, 7, 11, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLH, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLH, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTH + ShiftLeft(1, And(PRTH, 0x0f), IRQ0) + + Return (RTLH) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTH) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTH, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} + diff --git a/src/soc/intel/fsp_baytrail/acpi/irqroute.asl b/src/soc/intel/fsp_baytrail/acpi/irqroute.asl new file mode 100644 index 0000000..940f853 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/irqroute.asl @@ -0,0 +1,43 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2013 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 + */ + +// PCI Interrupt Routing +Method(_PRT) +{ + /* + * PICM comes from _PIC, which returns the following: + * 0 – PIC mode + * 1 – APIC mode + * 2 – SAPIC mode + */ + If (PICM) { + Return (Package() { + #undef PIC_MODE + #include "irq_helper.h" + PCI_DEV_PIRQ_ROUTES + }) + } Else { + Return (Package() { + #define PIC_MODE + #include "irq_helper.h" + PCI_DEV_PIRQ_ROUTES + }) + } +} diff --git a/src/soc/intel/fsp_baytrail/acpi/lpc.asl b/src/soc/intel/fsp_baytrail/acpi/lpc.asl new file mode 100644 index 0000000..408d2b4 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/lpc.asl @@ -0,0 +1,167 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2013 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 + */ + +// Intel LPC Bus Device - 0:1f.0 + +Device (LPCB) +{ + Name(_ADR, 0x001f0000) + + #include "irqlinks.asl" + + #include "acpi/ec.asl" + + Device (DMAC) // DMA Controller + { + Name(_HID, EISAID("PNP0200")) + Name(_CRS, ResourceTemplate() + { + IO (Decode16, 0x00, 0x00, 0x01, 0x20) + IO (Decode16, 0x81, 0x81, 0x01, 0x11) + IO (Decode16, 0x93, 0x93, 0x01, 0x0d) + IO (Decode16, 0xc0, 0xc0, 0x01, 0x20) + DMA (Compatibility, NotBusMaster, Transfer8_16) { 4 } + }) + } + + Device (FWH) // Firmware Hub + { + Name (_HID, EISAID("INT0800")) + Name (_CRS, ResourceTemplate() + { + Memory32Fixed(ReadOnly, 0xff000000, 0x01000000) + }) + } + + Device (HPET) + { + Name (_HID, EISAID("PNP0103")) + Name (_CID, 0x010CD041) + + Method (_STA, 0) // Device Status + { + Return (0xf) // Enable and show device + } + + Name(_CRS, ResourceTemplate() + { + Memory32Fixed(ReadOnly, 0xfed00000, 0x400) + }) + } + + Device(PIC) // 8259 Interrupt Controller + { + Name(_HID,EISAID("PNP0000")) + Name(_CRS, ResourceTemplate() + { + IO (Decode16, 0x20, 0x20, 0x01, 0x02) + IO (Decode16, 0x24, 0x24, 0x01, 0x02) + IO (Decode16, 0x28, 0x28, 0x01, 0x02) + IO (Decode16, 0x2c, 0x2c, 0x01, 0x02) + IO (Decode16, 0x30, 0x30, 0x01, 0x02) + IO (Decode16, 0x34, 0x34, 0x01, 0x02) + IO (Decode16, 0x38, 0x38, 0x01, 0x02) + IO (Decode16, 0x3c, 0x3c, 0x01, 0x02) + IO (Decode16, 0xa0, 0xa0, 0x01, 0x02) + IO (Decode16, 0xa4, 0xa4, 0x01, 0x02) + IO (Decode16, 0xa8, 0xa8, 0x01, 0x02) + IO (Decode16, 0xac, 0xac, 0x01, 0x02) + IO (Decode16, 0xb0, 0xb0, 0x01, 0x02) + IO (Decode16, 0xb4, 0xb4, 0x01, 0x02) + IO (Decode16, 0xb8, 0xb8, 0x01, 0x02) + IO (Decode16, 0xbc, 0xbc, 0x01, 0x02) + IO (Decode16, 0x4d0, 0x4d0, 0x01, 0x02) + IRQNoFlags () { 2 } + }) + } + + Device(LDRC) // LPC device: Resource consumption + { + Name (_HID, EISAID("PNP0C02")) + Name (_UID, 2) + + Name (RBUF, ResourceTemplate() + { + IO (Decode16, 0x61, 0x61, 0x1, 0x01) // NMI Status + IO (Decode16, 0x63, 0x63, 0x1, 0x01) // CPU Reserved + IO (Decode16, 0x65, 0x65, 0x1, 0x01) // CPU Reserved + IO (Decode16, 0x67, 0x67, 0x1, 0x01) // CPU Reserved + IO (Decode16, 0x80, 0x80, 0x1, 0x01) // Port 80 Post + IO (Decode16, 0x92, 0x92, 0x1, 0x01) // CPU Reserved + IO (Decode16, 0xb2, 0xb2, 0x1, 0x02) // SWSMI + }) + + Method (_CRS, 0, NotSerialized) + { + Return (RBUF) + } + } + + Device (RTC) // Real Time Clock + { + Name (_HID, EISAID("PNP0B00")) + Name (_CRS, ResourceTemplate() + { + IO (Decode16, 0x70, 0x70, 1, 8) +// Disable as Windows doesn't like it, and systems don't seem to use it. +// IRQNoFlags() { 8 } + }) + } + + Device (TIMR) // Intel 8254 timer + { + Name(_HID, EISAID("PNP0100")) + Name(_CRS, ResourceTemplate() + { + IO (Decode16, 0x40, 0x40, 0x01, 0x04) + IO (Decode16, 0x50, 0x50, 0x10, 0x04) + IRQNoFlags() {0} + }) + } + + // Include mainboard's superio.asl file. + #include "acpi/superio.asl" + +#ifdef ENABLE_TPM + Device (TPM) // Trusted Platform Module + { + Name(_HID, EISAID("IFX0102")) + Name(_CID, 0x310cd041) + Name(_UID, 1) + + Method(_STA, 0) + { + If (TPMP) { + Return (0xf) + } + Return (0x0) + } + + Name(_CRS, ResourceTemplate() { + IO (Decode16, 0x2e, 0x2e, 0x01, 0x02) + IO (Decode16, 0x6f0, 0x6f0, 0x01, 0x10) + Memory32Fixed (ReadWrite, 0xfed40000, 0x5000) + IRQ (Edge, Activehigh, Exclusive) { 6 } + }) + } +#endif +} diff --git a/src/soc/intel/fsp_baytrail/acpi/lpe.asl b/src/soc/intel/fsp_baytrail/acpi/lpe.asl new file mode 100644 index 0000000..71a2746 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/lpe.asl @@ -0,0 +1,119 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 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 + */ + +Device (LPEA) +{ + Name (_HID, "80860F28") + Name (_CID, "80860F28") + Name (_UID, 1) + Name (_DDN, "Low Power Audio Controller") + Name (_PR0, Package () { PLPE }) + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x00200000, BAR0) + Memory32Fixed (ReadWrite, 0, 0x00001000, BAR1) + Memory32Fixed (ReadWrite, 0, 0x00100000, BAR2) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPE_DMA0_IRQ + } + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPE_DMA1_IRQ + } + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPE_SSP0_IRQ + } + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPE_SSP1_IRQ + } + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPE_SSP2_IRQ + } + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPE_IPC2HOST_IRQ + } + }) + + Method (_CRS) + { + /* Update BAR0 from NVS */ + CreateDwordField (^RBUF, ^BAR0._BAS, BAS0) + Store (\LPB0, BAS0) + + /* Update BAR1 from NVS */ + CreateDwordField (^RBUF, ^BAR1._BAS, BAS1) + Store (\LPB1, BAS1) + + /* Update LPE FW from NVS */ + CreateDwordField (^RBUF, ^BAR2._BAS, BAS2) + Store (\LPFW, BAS2) + + /* Append any Mainboard defined GPIOs */ + If (CondRefOf (^GBUF, Local0)) { + ConcatenateResTemplate (^RBUF, Local0, Local1) + Return (Local1) + } + + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\LPEN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } + + OperationRegion (KEYS, SystemMemory, LPB1, 0x100) + Field (KEYS, DWordAcc, NoLock, WriteAsZeros) + { + Offset (0x84), + PSAT, 32, + } + + PowerResource (PLPE, 0, 0) + { + Method (_STA) + { + Return (1) + } + + Method (_OFF) + { + Or (PSAT, 0x00000003, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + + Method (_ON) + { + And (PSAT, 0xfffffffc, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + } +} diff --git a/src/soc/intel/fsp_baytrail/acpi/lpss.asl b/src/soc/intel/fsp_baytrail/acpi/lpss.asl new file mode 100644 index 0000000..0f8f746 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/lpss.asl @@ -0,0 +1,712 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 + */ + +Device (SDM1) +{ + Name (_HID, "INTL9C60") + Name (_UID, 1) + Name (_DDN, "DMA Controller #1") + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPSS_DMA1_IRQ + } + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\S0B0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\S0EN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } +} + +Device (SDM2) +{ + Name (_HID, "INTL9C60") + Name (_UID, 2) + Name (_DDN, "DMA Controller #2") + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPSS_DMA2_IRQ + } + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\S8B0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\S8EN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } +} + +Device (I2C1) +{ + Name (_HID, "80860F41") + Name (_UID, 1) + Name (_DDN, "I2C Controller #1") + + /* Standard Mode: HCNT, LCNT, SDA Hold Time */ + Name (SSCN, Package () { 0x200, 0x200, 0x6 }) + + /* Fast Mode: HCNT, LCNT, SDA Hold Time */ + Name (FMCN, Package () { 0x55, 0x99, 0x6 }) + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPSS_I2C1_IRQ + } + FixedDMA (0x10, 0x0, Width32Bit, ) + FixedDMA (0x11, 0x1, Width32Bit, ) + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\S1B0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\S1EN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } + + OperationRegion (KEYS, SystemMemory, S1B1, 0x100) + Field (KEYS, DWordAcc, NoLock, WriteAsZeros) + { + Offset (0x84), + PSAT, 32, + } + + Method (_PS3) + { + Or (PSAT, 0x00000003, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + + Method (_PS0) + { + And (PSAT, 0xfffffffc, PSAT) + Or (PSAT, 0x00000000, PSAT) + } +} + +Device (I2C2) +{ + Name (_HID, "80860F41") + Name (_UID, 2) + Name (_DDN, "I2C Controller #2") + + /* Standard Mode: HCNT, LCNT, SDA Hold Time */ + Name (SSCN, Package () { 0x200, 0x200, 0x6 }) + + /* Fast Mode: HCNT, LCNT, SDA Hold Time */ + Name (FMCN, Package () { 0x55, 0x99, 0x6 }) + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPSS_I2C2_IRQ + } + FixedDMA (0x10, 0x0, Width32Bit, ) + FixedDMA (0x11, 0x1, Width32Bit, ) + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\S2B0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\S2EN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } + + OperationRegion (KEYS, SystemMemory, S2B1, 0x100) + Field (KEYS, DWordAcc, NoLock, WriteAsZeros) + { + Offset (0x84), + PSAT, 32, + } + + Method (_PS3) + { + Or (PSAT, 0x00000003, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + + Method (_PS0) + { + And (PSAT, 0xfffffffc, PSAT) + Or (PSAT, 0x00000000, PSAT) + } +} + +Device (I2C3) +{ + Name (_HID, "80860F41") + Name (_UID, 3) + Name (_DDN, "I2C Controller #3") + + /* Standard Mode: HCNT, LCNT, SDA Hold Time */ + Name (SSCN, Package () { 0x200, 0x200, 0x6 }) + + /* Fast Mode: HCNT, LCNT, SDA Hold Time */ + Name (FMCN, Package () { 0x55, 0x99, 0x6 }) + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPSS_I2C3_IRQ + } + FixedDMA (0x10, 0x0, Width32Bit, ) + FixedDMA (0x11, 0x1, Width32Bit, ) + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\S3B0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\S3EN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } + + OperationRegion (KEYS, SystemMemory, S3B1, 0x100) + Field (KEYS, DWordAcc, NoLock, WriteAsZeros) + { + Offset (0x84), + PSAT, 32, + } + + Method (_PS3) + { + Or (PSAT, 0x00000003, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + + Method (_PS0) + { + And (PSAT, 0xfffffffc, PSAT) + Or (PSAT, 0x00000000, PSAT) + } +} + +Device (I2C4) +{ + Name (_HID, "80860F41") + Name (_UID, 4) + Name (_DDN, "I2C Controller #4") + + /* Standard Mode: HCNT, LCNT, SDA Hold Time */ + Name (SSCN, Package () { 0x200, 0x200, 0x6 }) + + /* Fast Mode: HCNT, LCNT, SDA Hold Time */ + Name (FMCN, Package () { 0x55, 0x99, 0x6 }) + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPSS_I2C4_IRQ + } + FixedDMA (0x10, 0x0, Width32Bit, ) + FixedDMA (0x11, 0x1, Width32Bit, ) + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\S4B0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\S4EN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } + + OperationRegion (KEYS, SystemMemory, S4B1, 0x100) + Field (KEYS, DWordAcc, NoLock, WriteAsZeros) + { + Offset (0x84), + PSAT, 32, + } + + Method (_PS3) + { + Or (PSAT, 0x00000003, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + + Method (_PS0) + { + And (PSAT, 0xfffffffc, PSAT) + Or (PSAT, 0x00000000, PSAT) + } +} + +Device (I2C5) +{ + Name (_HID, "80860F41") + Name (_UID, 5) + Name (_DDN, "I2C Controller #5") + + /* Standard Mode: HCNT, LCNT, SDA Hold Time */ + Name (SSCN, Package () { 0x200, 0x200, 0x6 }) + + /* Fast Mode: HCNT, LCNT, SDA Hold Time */ + Name (FMCN, Package () { 0x55, 0x99, 0x6 }) + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPSS_I2C5_IRQ + } + FixedDMA (0x10, 0x0, Width32Bit, ) + FixedDMA (0x11, 0x1, Width32Bit, ) + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\S5B0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\S5EN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } + + OperationRegion (KEYS, SystemMemory, S5B1, 0x100) + Field (KEYS, DWordAcc, NoLock, WriteAsZeros) + { + Offset (0x84), + PSAT, 32, + } + + Method (_PS3) + { + Or (PSAT, 0x00000003, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + + Method (_PS0) + { + And (PSAT, 0xfffffffc, PSAT) + Or (PSAT, 0x00000000, PSAT) + } +} + +Device (I2C6) +{ + Name (_HID, "80860F41") + Name (_UID, 6) + Name (_DDN, "I2C Controller #6") + + /* Standard Mode: HCNT, LCNT, SDA Hold Time */ + Name (SSCN, Package () { 0x200, 0x200, 0x6 }) + + /* Fast Mode: HCNT, LCNT, SDA Hold Time */ + Name (FMCN, Package () { 0x55, 0x99, 0x6 }) + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPSS_I2C6_IRQ + } + FixedDMA (0x10, 0x0, Width32Bit, ) + FixedDMA (0x11, 0x1, Width32Bit, ) + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\S6B0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\S6EN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } + + OperationRegion (KEYS, SystemMemory, S6B1, 0x100) + Field (KEYS, DWordAcc, NoLock, WriteAsZeros) + { + Offset (0x84), + PSAT, 32, + } + + Method (_PS3) + { + Or (PSAT, 0x00000003, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + + Method (_PS0) + { + And (PSAT, 0xfffffffc, PSAT) + Or (PSAT, 0x00000000, PSAT) + } +} + +Device (I2C7) +{ + Name (_HID, "80860F41") + Name (_UID, 7) + Name (_DDN, "I2C Controller #7") + + /* Standard Mode: HCNT, LCNT, SDA Hold Time */ + Name (SSCN, Package () { 0x200, 0x200, 0x6 }) + + /* Fast Mode: HCNT, LCNT, SDA Hold Time */ + Name (FMCN, Package () { 0x55, 0x99, 0x6 }) + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPSS_I2C7_IRQ + } + FixedDMA (0x10, 0x0, Width32Bit, ) + FixedDMA (0x11, 0x1, Width32Bit, ) + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\S7B0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\S7EN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } + + OperationRegion (KEYS, SystemMemory, S7B1, 0x100) + Field (KEYS, DWordAcc, NoLock, WriteAsZeros) + { + Offset (0x84), + PSAT, 32, + } + + Method (_PS3) + { + Or (PSAT, 0x00000003, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + + Method (_PS0) + { + And (PSAT, 0xfffffffc, PSAT) + Or (PSAT, 0x00000000, PSAT) + } +} + +Device (SPI1) +{ + Name (_HID, "80860F0E") + Name (_UID, 1) + Name (_DDN, "SPI Controller #2") + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPSS_SPI_IRQ + } + FixedDMA (0x0, 0x0, Width32Bit, ) + FixedDMA (0x1, 0x1, Width32Bit, ) + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\S9B0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\S9EN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } + + OperationRegion (KEYS, SystemMemory, S9B1, 0x100) + Field (KEYS, DWordAcc, NoLock, WriteAsZeros) + { + Offset (0x84), + PSAT, 32, + } + + Method (_PS3) + { + Or (PSAT, 0x00000003, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + + Method (_PS0) + { + And (PSAT, 0xfffffffc, PSAT) + Or (PSAT, 0x00000000, PSAT) + } +} + +Device (PWM1) +{ + Name (_HID, "80860F09") + Name (_UID, 1) + Name (_DDN, "PWM Controller #1") + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\SAB0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\SAEN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } +} + +Device (PWM2) +{ + Name (_HID, "80860F09") + Name (_UID, 2) + Name (_DDN, "PWM Controller #2") + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\SBB0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\SBEN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } +} + +Device (UAR1) +{ + Name (_HID, "80860F0A") + Name (_UID, 1) + Name (_DDN, "HS-UART Controller #1") + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPSS_HSUART1_IRQ + } + FixedDMA (0x2, 0x2, Width32Bit, ) + FixedDMA (0x3, 0x3, Width32Bit, ) + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\SCB0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\SCEN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } + + OperationRegion (KEYS, SystemMemory, SCB1, 0x100) + Field (KEYS, DWordAcc, NoLock, WriteAsZeros) + { + Offset (0x84), + PSAT, 32, + } + + Method (_PS3) + { + Or (PSAT, 0x00000003, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + + Method (_PS0) + { + And (PSAT, 0xfffffffc, PSAT) + Or (PSAT, 0x00000000, PSAT) + } +} + +Device (UAR2) +{ + Name (_HID, "80860F0A") + Name (_UID, 2) + Name (_DDN, "HS-UART Controller #2") + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + LPSS_HSUART2_IRQ + } + FixedDMA (0x4, 0x4, Width32Bit, ) + FixedDMA (0x5, 0x5, Width32Bit, ) + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\SDB0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\SDEN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } + + OperationRegion (KEYS, SystemMemory, SDB1, 0x100) + Field (KEYS, DWordAcc, NoLock, WriteAsZeros) + { + Offset (0x84), + PSAT, 32, + } + + Method (_PS3) + { + Or (PSAT, 0x00000003, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + + Method (_PS0) + { + And (PSAT, 0xfffffffc, PSAT) + Or (PSAT, 0x00000000, PSAT) + } +} diff --git a/src/soc/intel/fsp_baytrail/acpi/platform.asl b/src/soc/intel/fsp_baytrail/acpi/platform.asl new file mode 100644 index 0000000..e069392 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/platform.asl @@ -0,0 +1,73 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2012 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 + */ + +/* The APM port can be used for generating software SMIs */ + +OperationRegion (APMP, SystemIO, 0xb2, 2) +Field (APMP, ByteAcc, NoLock, Preserve) +{ + APMC, 8, // APM command + APMS, 8 // APM status +} + +/* Port 80 POST */ + +OperationRegion (POST, SystemIO, 0x80, 1) +Field (POST, ByteAcc, Lock, Preserve) +{ + DBG0, 8 +} + +/* SMI I/O Trap */ +Method(TRAP, 1, Serialized) +{ + Store (Arg0, SMIF) // SMI Function + Store (0, TRP0) // Generate trap + Return (SMIF) // Return value of SMI handler +} + +/* The _PIC method is called by the OS to choose between interrupt + * routing via the i8259 interrupt controller or the APIC. + * + * _PIC is called with a parameter of 0 for i8259 configuration and + * with a parameter of 1 for Local Apic/IOAPIC configuration. + */ + +Method(_PIC, 1) +{ + // Remember the OS' IRQ routing choice. + Store(Arg0, PICM) +} + +/* The _PTS method (Prepare To Sleep) is called before the OS is + * entering a sleep state. The sleep state number is passed in Arg0 + */ + +Method(_PTS,1) +{ +} + +/* The _WAK method is called on system wakeup */ + +Method(_WAK,1) +{ + Return(Package(){0,0}) +} + diff --git a/src/soc/intel/fsp_baytrail/acpi/scc.asl b/src/soc/intel/fsp_baytrail/acpi/scc.asl new file mode 100644 index 0000000..7181fb1 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/scc.asl @@ -0,0 +1,187 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 + */ + +Device (EMMC) +{ + Name (_HID, "80860F14") + Name (_CID, "PNP0D40") + Name (_UID, 1) + Name (_DDN, "eMMC Controller 4.5") + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + SCC_EMMC_IRQ + } + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\C0B0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\C0EN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } + + OperationRegion (KEYS, SystemMemory, C0B1, 0x100) + Field (KEYS, DWordAcc, NoLock, WriteAsZeros) + { + Offset (0x84), + PSAT, 32, + } + + Method (_PS3) + { + Or (PSAT, 0x00000003, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + + Method (_PS0) + { + And (PSAT, 0xfffffffc, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + + Device (EM45) + { + /* Slot 0, Function 8 */ + Name (_ADR, 0x8) + + Method (_RMV, 0, NotSerialized) + { + Return (0) + } + } +} + +Device (SDIO) +{ + Name (_HID, "INT33BB") + Name (_CID, "PNP0D40") + Name (_UID, 2) + Name (_DDN, "SDIO Controller") + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + SCC_SDIO_IRQ + } + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\C1B0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\C1EN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } + + OperationRegion (KEYS, SystemMemory, C1B1, 0x100) + Field (KEYS, DWordAcc, NoLock, WriteAsZeros) + { + Offset (0x84), + PSAT, 32, + } + + Method (_PS3) + { + Or (PSAT, 0x00000003, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + + Method (_PS0) + { + And (PSAT, 0xfffffffc, PSAT) + Or (PSAT, 0x00000000, PSAT) + } +} + +Device (SDCD) +{ + Name (_HID, "80860F16") + Name (_CID, "PNP0D40") + Name (_UID, 3) + Name (_DDN, "SD Card Controller") + + Name (RBUF, ResourceTemplate() + { + Memory32Fixed (ReadWrite, 0, 0x1000, BAR0) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive,,,) + { + SCC_SD_IRQ + } + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^BAR0._BAS, RBAS) + Store (\C2B0, RBAS) + Return (^RBUF) + } + + Method (_STA) + { + If (LEqual (\C2EN, 1)) { + Return (0xF) + } Else { + Return (0x0) + } + } + + OperationRegion (KEYS, SystemMemory, C2B1, 0x100) + Field (KEYS, DWordAcc, NoLock, WriteAsZeros) + { + Offset (0x84), + PSAT, 32, + } + + Method (_PS3) + { + Or (PSAT, 0x00000003, PSAT) + Or (PSAT, 0x00000000, PSAT) + } + + Method (_PS0) + { + And (PSAT, 0xfffffffc, PSAT) + Or (PSAT, 0x00000000, PSAT) + } +} diff --git a/src/soc/intel/fsp_baytrail/acpi/sleepstates.asl b/src/soc/intel/fsp_baytrail/acpi/sleepstates.asl new file mode 100644 index 0000000..b21656c --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/sleepstates.asl @@ -0,0 +1,26 @@ +/* + * 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(\_S0, Package(){0x0,0x0,0x0,0x0}) +// Name(\_S1, Package(){0x1,0x1,0x0,0x0}) +Name(\_S4, Package(){0x6,0x6,0x0,0x0}) +Name(\_S5, Package(){0x7,0x7,0x0,0x0}) + diff --git a/src/soc/intel/fsp_baytrail/acpi/southcluster.asl b/src/soc/intel/fsp_baytrail/acpi/southcluster.asl new file mode 100644 index 0000000..7136e14 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/southcluster.asl @@ -0,0 +1,284 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 <soc/intel/fsp_baytrail/baytrail/iomap.h> +#include <soc/intel/fsp_baytrail/baytrail/irq.h> +#include "../baytrail/baytrail.h" + +Scope(\) +{ + // IO-Trap at 0x800. This is the ACPI->SMI communication interface. + + OperationRegion(IO_T, SystemIO, 0x800, 0x10) + Field(IO_T, ByteAcc, NoLock, Preserve) + { + Offset(0x8), + TRP0, 8 // IO-Trap at 0x808 + } + + // Intel Legacy Block + OperationRegion(ILBS, SystemMemory, ILB_BASE_ADDRESS, ILB_BASE_SIZE) + Field (ILBS, AnyAcc, NoLock, Preserve) + { + Offset (0x8), + PRTA, 8, + PRTB, 8, + PRTC, 8, + PRTD, 8, + PRTE, 8, + PRTF, 8, + PRTG, 8, + PRTH, 8, + } +} + +Name(_HID,EISAID("PNP0A08")) // PCIe +Name(_CID,EISAID("PNP0A03")) // PCI + +Name(_ADR, 0) +Name(_BBN, 0) + +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 (0xc0000-0xc3fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000c0000, 0x000c3fff, 0x00000000, + 0x00004000,,, OPR0) + + // OPROM reserved (0xc4000-0xc7fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000c4000, 0x000c7fff, 0x00000000, + 0x00004000,,, OPR1) + + // OPROM reserved (0xc8000-0xcbfff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000c8000, 0x000cbfff, 0x00000000, + 0x00004000,,, OPR2) + + // OPROM reserved (0xcc000-0xcffff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000cc000, 0x000cffff, 0x00000000, + 0x00004000,,, OPR3) + + // OPROM reserved (0xd0000-0xd3fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000d0000, 0x000d3fff, 0x00000000, + 0x00004000,,, OPR4) + + // OPROM reserved (0xd4000-0xd7fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000d4000, 0x000d7fff, 0x00000000, + 0x00004000,,, OPR5) + + // OPROM reserved (0xd8000-0xdbfff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000d8000, 0x000dbfff, 0x00000000, + 0x00004000,,, OPR6) + + // OPROM reserved (0xdc000-0xdffff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000dc000, 0x000dffff, 0x00000000, + 0x00004000,,, OPR7) + + // 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-0xfeafffff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0xfea00000, 0xfeafffff, 0x00000000, + 0x00100000,,, PMEM) + + // TPM Area (0xfed40000-0xfed44fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0xfed40000, 0xfed44fff, 0x00000000, + 0x00005000,,, TPMR) + }) + + // Update PCI resource area + CreateDwordField(MCRS, PMEM._MIN, PMIN) + CreateDwordField(MCRS, PMEM._MAX, PMAX) + CreateDwordField(MCRS, PMEM._LEN, PLEN) + + // TOLM is BMBOUND accessible from IOSF so is saved in NVS + Store (\TOLM, PMIN) + Add (Subtract (PMAX, PMIN), 1, PLEN) + + Return (MCRS) +} + +/* Device Resource Consumption */ +Device (PDRC) +{ + Name (_HID, EISAID("PNP0C02")) + Name (_UID, 1) + + Name (PDRS, ResourceTemplate() { + Memory32Fixed(ReadWrite, ABORT_BASE_ADDRESS, ABORT_BASE_SIZE) + Memory32Fixed(ReadWrite, MCFG_BASE_ADDRESS, MCFG_BASE_SIZE) + Memory32Fixed(ReadWrite, PMC_BASE_ADDRESS, PMC_BASE_SIZE) + Memory32Fixed(ReadWrite, ILB_BASE_ADDRESS, ILB_BASE_SIZE) + Memory32Fixed(ReadWrite, SPI_BASE_ADDRESS, SPI_BASE_SIZE) + Memory32Fixed(ReadWrite, MPHY_BASE_ADDRESS, MPHY_BASE_SIZE) + Memory32Fixed(ReadWrite, PUNIT_BASE_ADDRESS, PUNIT_BASE_SIZE) + Memory32Fixed(ReadWrite, RCBA_BASE_ADDRESS, RCBA_BASE_SIZE) + }) + + // Current Resource Settings + Method (_CRS, 0, Serialized) + { + Return(PDRS) + } +} + +Method (_OSC, 4) +{ + /* Check for proper GUID */ + If (LEqual (Arg0, ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766"))) + { + /* Let OS control everything */ + Return (Arg3) + } + Else + { + /* Unrecognized UUID */ + CreateDWordField (Arg3, 0, CDW1) + Or (CDW1, 4, CDW1) + Return (Arg3) + } +} + +/* IOSF MBI Interface for kernel access */ +Device (IOSF) +{ + Name (_HID, "INT33BD") + Name (_CID, "INT33BD") + Name (_UID, 1) + + Name (RBUF, ResourceTemplate () + { + /* MCR / MDR / MCRX */ + Memory32Fixed (ReadWrite, 0, 12, RBAR) + }) + + Method (_CRS) + { + CreateDwordField (^RBUF, ^RBAR._BAS, RBAS) + Store (Add (MCFG_BASE_ADDRESS, 0xD0), RBAS) + Return (^RBUF) + } +} + +// LPC Bridge 0:1f.0 +#include "lpc.asl" + +#if INCLUDE_EHCI +// USB EHCI 0:1d.0 +#include "usb.asl" +#endif + +#if INCLUDE_XHCI +// USB XHCI 0:14.0 +#include "xhci.asl" +#endif + +// IRQ routing for each PCI device +#include "irqroute.asl" + +Scope (\_SB) +{ + // GPIO Devices + #include "gpio.asl" + +#if INCLUDE_LPSS + // LPSS Devices + #include "lpss.asl" +#endif + +#if INCLUDE_SCC + // SCC Devices + #include "scc.asl" +#endif + +#if INCLUDE_LPE + // LPE Device + #include "lpe.asl" +#endif +} diff --git a/src/soc/intel/fsp_baytrail/acpi/usb.asl b/src/soc/intel/fsp_baytrail/acpi/usb.asl new file mode 100644 index 0000000..ebc32ae --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/usb.asl @@ -0,0 +1,54 @@ +/* + * 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 + */ + +/* Intel Baytrail USB support */ + +// EHCI Controller 0:1d.0 + +Device (EHC1) +{ + Name(_ADR, 0x001d0000) + + Name (_PRW, Package(){ 13, 4 }) // Power Resources for Wake + + // Leave USB ports on for to allow Wake from USB + + Method(_S3D,0) // Highest D State in S3 State + { + Return (2) + } + + Method(_S4D,0) // Highest D State in S4 State + { + Return (2) + } + + Device (HUB7) + { + Name (_ADR, 0x00000000) + + Device (PRT1) { Name (_ADR, 1) } // USB Port 0 + Device (PRT2) { Name (_ADR, 2) } // USB Port 1 + Device (PRT3) { Name (_ADR, 3) } // USB Port 2 + Device (PRT4) { Name (_ADR, 4) } // USB Port 3 + } +} + diff --git a/src/soc/intel/fsp_baytrail/acpi/xhci.asl b/src/soc/intel/fsp_baytrail/acpi/xhci.asl new file mode 100644 index 0000000..4d5367a --- /dev/null +++ b/src/soc/intel/fsp_baytrail/acpi/xhci.asl @@ -0,0 +1,36 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 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 + */ + +Device (XHCI) +{ + Name (_ADR, 0x00140000) + Name (_PRW, Package () { 0x0d, 3 }) + Name (_S3D, 3) /* Highest D state in S3 state */ + + Device (RHUB) + { + Name (_ADR, 0x00000000) + Device (PRT1) { Name (_ADR, 1) } + Device (PRT2) { Name (_ADR, 2) } + Device (PRT3) { Name (_ADR, 3) } + Device (PRT4) { Name (_ADR, 4) } + } +} diff --git a/src/soc/intel/fsp_baytrail/baytrail/acpi.h b/src/soc/intel/fsp_baytrail/baytrail/acpi.h new file mode 100644 index 0000000..d796873 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/acpi.h @@ -0,0 +1,34 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 _BAYTRAIL_ACPI_H_ +#define _BAYTRAIL_ACPI_H_ + +#include <arch/acpi.h> +#include <baytrail/nvs.h> + +void acpi_create_intel_hpet(acpi_hpet_t * hpet); +void acpi_create_serialio_ssdt(acpi_header_t *ssdt); +void acpi_fill_in_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt); +unsigned long acpi_madt_irq_overrides(unsigned long current); +void acpi_init_gnvs(global_nvs_t *gnvs); + +#endif /* _BAYTRAIL_ACPI_H_ */ + diff --git a/src/soc/intel/fsp_baytrail/baytrail/baytrail.h b/src/soc/intel/fsp_baytrail/baytrail/baytrail.h new file mode 100644 index 0000000..d3a2377 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/baytrail.h @@ -0,0 +1,74 @@ +/* + * 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 __SOC_INTEL_FSP_BAYTRAIL_BAYTRAIL_H__ +#define __SOC_INTEL_FSP_BAYTRAIL_BAYTRAIL_H__ + +#define DEFAULT_ECBASE CONFIG_MMCONF_BASE_ADDRESS +#define CPU_MICROCODE_CBFS_LEN 0x26000 + +/* Southbridge internal device IO BARs (Set to match FSP settings) */ +#define SMBUS_IO_BASE 0xefa0 +#define SMBUS_SLAVE_ADDR 0x24 +#define DEFAULT_GPIOBASE 0x0500 +#define DEFAULT_ABASE 0x0400 + +/* Southbridge internal device MEM BARs (Set to match FSP settings) */ +#define DEFAULT_IBASE 0xfed08000 +#define DEFAULT_PBASE 0xfed03000 +#define DEFAULT_RCBA 0xfed1c000 + +/* Everything below this line is ignored in the DSDT */ +#ifndef __ACPI__ + +/* Device 0:0.0 PCI configuration space (Host Bridge) */ + +/* SOC types */ +#define SOC_TYPE_BAYTRAIL 0x0F1C + +#ifndef __ASSEMBLER__ +static inline void barrier(void) { asm("" ::: "memory"); } + +#define SKPAD 0xFC + +int bridge_silicon_revision(void); +void rangeley_early_initialization(void); + +#ifndef __PRE_RAM__ +/* soc.c */ +int soc_silicon_revision(void); +int soc_silicon_type(void); +int soc_silicon_supported(int type, int rev); +void soc_enable(device_t dev); + +/* 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 /* __PRE_RAM__ */ +#endif /* __ASSEMBLER__ */ + +#endif /* __ACPI__ */ +#endif diff --git a/src/soc/intel/fsp_baytrail/baytrail/device_nvs.h b/src/soc/intel/fsp_baytrail/baytrail/device_nvs.h new file mode 100644 index 0000000..a06ca70 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/device_nvs.h @@ -0,0 +1,67 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 _BAYTRAIL_DEVICE_NVS_H_ +#define _BAYTRAIL_DEVICE_NVS_H_ + +#include <stdint.h> + +/* Offset in Global NVS where this structure lives */ +#define DEVICE_NVS_OFFSET 0x1000 + +#define LPSS_NVS_SIO_DMA1 0 +#define LPSS_NVS_I2C1 1 +#define LPSS_NVS_I2C2 2 +#define LPSS_NVS_I2C3 3 +#define LPSS_NVS_I2C4 4 +#define LPSS_NVS_I2C5 5 +#define LPSS_NVS_I2C6 6 +#define LPSS_NVS_I2C7 7 +#define LPSS_NVS_SIO_DMA2 8 +#define LPSS_NVS_SPI 9 +#define LPSS_NVS_PWM1 10 +#define LPSS_NVS_PWM2 11 +#define LPSS_NVS_HSUART1 12 +#define LPSS_NVS_HSUART2 13 + +#define SCC_NVS_MMC 0 +#define SCC_NVS_SDIO 1 +#define SCC_NVS_SD 2 + +typedef struct { + /* Device Enabled in ACPI Mode */ + u8 lpss_en[14]; + u8 scc_en[3]; + u8 lpe_en; + + /* BAR 0 */ + u32 lpss_bar0[14]; + u32 scc_bar0[3]; + u32 lpe_bar0; + + /* BAR 1 */ + u32 lpss_bar1[14]; + u32 scc_bar1[3]; + u32 lpe_bar1; + + /* Extra */ + u32 lpe_fw; /* LPE Firmware */ +} __attribute__((packed)) device_nvs_t; + +#endif diff --git a/src/soc/intel/fsp_baytrail/baytrail/ehci.h b/src/soc/intel/fsp_baytrail/baytrail/ehci.h new file mode 100644 index 0000000..a1edd6d --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/ehci.h @@ -0,0 +1,44 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 BAYTRAIL_EHCI_H +#define BAYTRAIL_EHCI_H + +/* EHCI PCI Registers */ +#define EHCI_CMD_STS 0x04 +# define INTRDIS (1 << 10) +#define EHCI_SBRN_FLA_PWC 0x60 +# define PORTWKIMP (1 << 16) +# define PORTWKCAPMASK (0x3ff << 17) +#define EHCI_USB2PDO 0x64 + +/* EHCI Memory Registers */ +#define USB2CMD 0x20 +# define USB2CMD_ASE (1 << 5) +# define USB2CMD_PSE (1 << 4) +# define USB2CMD_HCRESET (1 << 1) +# define USB2CMD_RS (1 << 0) +#define USB2STS 0x24 +# define USB2STS_HCHALT (1 << 12) + +/* RCBA EHCI Registers */ +#define RCBA_FUNC_DIS 0x220 +# define RCBA_EHCI_DIS (1 << 0) + +#endif /* BAYTRAIL_EHCI_H */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/gfx.h b/src/soc/intel/fsp_baytrail/baytrail/gfx.h new file mode 100644 index 0000000..655615d --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/gfx.h @@ -0,0 +1,48 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 _BAYTRAIL_GFX_H_ +#define _BAYTRAIL_GFX_H_ + +/* + * PCI config registers. + */ + +#define GGC 0x50 +# define GGC_VGA_DISABLE (1 << 1) +# define GGC_GTT_SIZE_MASK (3 << 8) +# define GGC_GTT_SIZE_0MB (0 << 8) +# define GGC_GTT_SIZE_1MB (1 << 8) +# define GGC_GTT_SIZE_2MB (2 << 8) +# define GGC_GSM_SIZE_MASK (0x1f << 3) +# define GGC_GSM_SIZE_0MB (0 << 3) +# define GGC_GSM_SIZE_32MB (1 << 3) +# define GGC_GSM_SIZE_64MB (2 << 3) +# define GGC_GSM_SIZE_128MB (4 << 3) + +#define GSM_BASE 0x5c +#define GTT_BASE 0x70 + +#define MSAC 0x62 +#define APERTURE_SIZE_MASK (3 << 1) +#define APERTURE_SIZE_128MB (0 << 1) +#define APERTURE_SIZE_256MB (1 << 1) +#define APERTURE_SIZE_512MB (3 << 1) + +#endif /* _BAYTRAIL_GFX_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/gpio.h b/src/soc/intel/fsp_baytrail/baytrail/gpio.h new file mode 100644 index 0000000..4c9e8a8 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/gpio.h @@ -0,0 +1,387 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 _BAYTRAIL_GPIO_H_ +#define _BAYTRAIL_GPIO_H_ + +#include <stdint.h> +#include <arch/io.h> +#include <baytrail/iomap.h> + +/* #define GPIO_DEBUG */ + +/* Pad base, ex. PAD_CONF0[n]= PAD_BASE+16*n */ +#define GPSCORE_PAD_BASE (IO_BASE_ADDRESS + IO_BASE_OFFSET_GPSCORE) +#define GPNCORE_PAD_BASE (IO_BASE_ADDRESS + IO_BASE_OFFSET_GPNCORE) +#define GPSSUS_PAD_BASE (IO_BASE_ADDRESS + IO_BASE_OFFSET_GPSSUS) + +/* DIRQ registers start at pad base + 0x980 */ +#define PAD_BASE_DIRQ_OFFSET 0x980 + +/* Pad register offset */ +#define PAD_CONF0_REG 0x0 +#define PAD_CONF1_REG 0x4 +#define PAD_VAL_REG 0x8 + +/* Legacy IO register base */ +#define GPSCORE_LEGACY_BASE (GPIO_BASE_ADDRESS + 0x00) +#define GPSSUS_LEGACY_BASE (GPIO_BASE_ADDRESS + 0x80) +/* Some banks have no legacy GPIO interface */ +#define GP_LEGACY_BASE_NONE 0xFFFF + +#define LEGACY_USE_SEL_REG 0x00 +#define LEGACY_IO_SEL_REG 0x04 +#define LEGACY_GP_LVL_REG 0x08 +#define LEGACY_TPE_REG 0x0C +#define LEGACY_TNE_REG 0x10 +#define LEGACY_TS_REG 0x14 +#define LEGACY_WAKE_EN_REG 0x18 + +/* Number of GPIOs in each bank */ +#define GPNCORE_COUNT 27 +#define GPSCORE_COUNT 102 +#define GPSSUS_COUNT 44 + +/* GPIO legacy IO register settings */ +#define GPIO_USE_MMIO 0 +#define GPIO_USE_LEGACY 1 + +#define GPIO_DIR_OUTPUT 0 +#define GPIO_DIR_INPUT 1 + +#define GPIO_LEVEL_LOW 0 +#define GPIO_LEVEL_HIGH 1 + +#define GPIO_PEDGE_DISABLE 0 +#define GPIO_PEDGE_ENABLE 1 + +#define GPIO_NEDGE_DISABLE 0 +#define GPIO_NEDGE_ENABLE 1 + +/* config0[29] - Disable second mask */ +#define PAD_MASK2_DISABLE (1 << 29) + +/* config0[27] - Direct Irq En */ +#define PAD_IRQ_EN (1 << 27) + +/* config0[26] - gd_tne */ +#define PAD_TNE_IRQ (1 << 26) + +/* config0[25] - gd_tpe */ +#define PAD_TPE_IRQ (1 << 25) + +/* config0[24] - Gd Level */ +#define PAD_LEVEL_IRQ (1 << 24) +#define PAD_EDGE_IRQ (0 << 24) + +/* config0[17] - Slow clkgate / glitch filter */ +#define PAD_SLOWGF_ENABLE (1 << 17) + +/* config0[16] - Fast clkgate / glitch filter */ +#define PAD_FASTGF_ENABLE (1 << 16) + +/* config0[15] - Hysteresis enable (inverted) */ +#define PAD_HYST_DISABLE (1 << 15) +#define PAD_HYST_ENABLE (0 << 15) + +/* config0[14:13] - Hysteresis control */ +#define PAD_HYST_CTRL_DEFAULT (2 << 13) + +/* config0[11] - Bypass Flop */ +#define PAD_FLOP_BYPASS (1 << 11) +#define PAD_FLOP_ENABLE (0 << 11) + +/* config0[10:9] - Pull str */ +#define PAD_PU_2K (0 << 9) +#define PAD_PU_10K (1 << 9) +#define PAD_PU_20K (2 << 9) +#define PAD_PU_40K (3 << 9) + +/* config0[8:7] - Pull assign */ +#define PAD_PULL_DISABLE (0 << 7) +#define PAD_PULL_UP (1 << 7) +#define PAD_PULL_DOWN (2 << 7) + +/* config0[2:0] - Func. pin mux */ +#define PAD_FUNC0 0x0 +#define PAD_FUNC1 0x1 +#define PAD_FUNC2 0x2 +#define PAD_FUNC3 0x3 +#define PAD_FUNC4 0x4 +#define PAD_FUNC5 0x5 +#define PAD_FUNC6 0x6 + +/* pad config0 power-on values - We will not often want to change these */ +#define PAD_CONFIG0_DEFAULT (PAD_MASK2_DISABLE | PAD_SLOWGF_ENABLE | \ + PAD_FASTGF_ENABLE | PAD_HYST_DISABLE | \ + PAD_HYST_CTRL_DEFAULT | PAD_FLOP_BYPASS) + +/* pad config1 reg power-on values - Shouldn't need to change this */ +#define PAD_CONFIG1_DEFAULT 0x8000 + +/* pad_val[2] - Iinenb - active low */ +#define PAD_VAL_INPUT_DISABLE (1 << 2) +#define PAD_VAL_INPUT_ENABLE (0 << 2) + +/* pad_val[1] - Ioutenb - active low */ +#define PAD_VAL_OUTPUT_DISABLE (1 << 1) +#define PAD_VAL_OUTPUT_ENABLE (0 << 1) + +/* Input / Output state should usually be mutually exclusive */ +#define PAD_VAL_INPUT (PAD_VAL_INPUT_ENABLE | PAD_VAL_OUTPUT_DISABLE) +#define PAD_VAL_OUTPUT (PAD_VAL_OUTPUT_ENABLE | PAD_VAL_INPUT_DISABLE) + +/* pad_val[0] - Value */ +#define PAD_VAL_HIGH (1 << 0) +#define PAD_VAL_LOW (0 << 0) + +/* pad_val reg power-on default varies by pad, and apparently can cause issues + * if not set correctly, even if the pin isn't configured as GPIO. */ +#define PAD_VAL_DEFAULT PAD_VAL_INPUT + +/* Configure GPIOs as MMIO by default */ +#define GPIO_INPUT_PU_10K \ + { .pad_conf0 = PAD_PU_10K | PAD_PULL_UP | PAD_CONFIG0_DEFAULT, \ + .pad_conf1 = PAD_CONFIG1_DEFAULT, \ + .pad_val = PAD_VAL_INPUT, \ + .use_sel = GPIO_USE_MMIO, \ + .is_gpio = 1 } + +#define GPIO_INPUT_PD_10K \ + { .pad_conf0 = PAD_PU_10K | PAD_PULL_DOWN | PAD_CONFIG0_DEFAULT, \ + .pad_conf1 = PAD_CONFIG1_DEFAULT, \ + .pad_val = PAD_VAL_INPUT, \ + .use_sel = GPIO_USE_MMIO, \ + .is_gpio = 1 } + +#define GPIO_INPUT_NOPU \ + { .pad_conf0 = PAD_PU_10K | PAD_PULL_DISABLE | PAD_CONFIG0_DEFAULT, \ + .pad_conf1 = PAD_CONFIG1_DEFAULT, \ + .pad_val = PAD_VAL_INPUT, \ + .use_sel = GPIO_USE_MMIO, \ + .is_gpio = 1 } + +#define GPIO_INPUT_LEGACY_NOPU \ + { .pad_conf0 = PAD_PU_10K | PAD_PULL_DISABLE | PAD_CONFIG0_DEFAULT, \ + .pad_conf1 = PAD_CONFIG1_DEFAULT, \ + .pad_val = PAD_VAL_INPUT, \ + .use_sel = GPIO_USE_LEGACY, \ + .io_sel = GPIO_DIR_INPUT, \ + .is_gpio = 1 } + +/* Direct / dedicated IRQ input - pass signal directly to apic */ +#define GPIO_DIRQ \ + { .pad_conf0 = PAD_PU_10K | PAD_PULL_DISABLE | PAD_CONFIG0_DEFAULT \ + | PAD_FUNC0 | PAD_IRQ_EN | PAD_TPE_IRQ | PAD_LEVEL_IRQ, \ + .pad_conf1 = PAD_CONFIG1_DEFAULT, \ + .pad_val = PAD_VAL_INPUT, } + + +#define GPIO_OUT_LOW \ + { .pad_conf0 = PAD_PULL_DISABLE | PAD_CONFIG0_DEFAULT \ + .pad_conf1 = PAD_CONFIG1_DEFAULT, \ + .pad_val = PAD_VAL_OUTPUT | PAD_VAL_LOW, \ + .use_sel = GPIO_USE_LEGACY, \ + .io_sel = GPIO_DIR_OUTPUT, \ + .gp_lvl = GPIO_LEVEL_LOW, \ + .is_gpio = 1 } + +#define GPIO_OUT_HIGH \ + { .pad_conf0 = PAD_PULL_DISABLE | PAD_CONFIG0_DEFAULT, \ + .pad_conf1 = PAD_CONFIG1_DEFAULT, \ + .pad_val = PAD_VAL_OUTPUT | PAD_VAL_HIGH, \ + .use_sel = GPIO_USE_LEGACY, \ + .io_sel = GPIO_DIR_OUTPUT, \ + .gp_lvl = GPIO_LEVEL_HIGH, \ + .is_gpio = 1 } + +/* Define no-pull / PU / PD configs for each functional config option */ +#define GPIO_FUNC(_func, _pudir, _str) \ + { .use_sel = GPIO_USE_MMIO, \ + .pad_conf0 = PAD_FUNC##_func | PAD_##_pudir | PAD_PU_##_str | \ + PAD_CONFIG0_DEFAULT, \ + .pad_conf1 = PAD_CONFIG1_DEFAULT, \ + .pad_val = PAD_VAL_DEFAULT } + +/* Default functional configs -- no PU */ +#define GPIO_FUNC0 GPIO_FUNC(0, PULL_DISABLE, 10K) +#define GPIO_FUNC1 GPIO_FUNC(1, PULL_DISABLE, 10K) +#define GPIO_FUNC2 GPIO_FUNC(2, PULL_DISABLE, 10K) +#define GPIO_FUNC3 GPIO_FUNC(3, PULL_DISABLE, 10K) +#define GPIO_FUNC4 GPIO_FUNC(4, PULL_DISABLE, 10K) +#define GPIO_FUNC5 GPIO_FUNC(5, PULL_DISABLE, 10K) +#define GPIO_FUNC6 GPIO_FUNC(6, PULL_DISABLE, 10K) + +/* ACPI GPIO routing. Assume everything is externally pulled and negative edge + * triggered. SCI implies WAKE, but WAKE doesn't imply SCI. */ +#define GPIO_ACPI_SCI \ + { .pad_conf0 = PAD_PULL_DISABLE | PAD_CONFIG0_DEFAULT | PAD_FUNC0, \ + .pad_conf1 = PAD_CONFIG1_DEFAULT, \ + .pad_val = PAD_VAL_INPUT, \ + .use_sel = GPIO_USE_LEGACY, \ + .io_sel = GPIO_DIR_INPUT, \ + .tne = 1, \ + .sci = 1, \ + .wake_en = 1, } +#define GPIO_ACPI_WAKE \ + { .pad_conf0 = PAD_PULL_DISABLE | PAD_CONFIG0_DEFAULT | PAD_FUNC0, \ + .pad_conf1 = PAD_CONFIG1_DEFAULT, \ + .pad_val = PAD_VAL_INPUT, \ + .use_sel = GPIO_USE_LEGACY, \ + .io_sel = GPIO_DIR_INPUT, \ + .tne = 1, \ + .wake_en = 1, } +#define GPIO_ACPI_SMI \ + { .pad_conf0 = PAD_PULL_DISABLE | PAD_CONFIG0_DEFAULT | PAD_FUNC0, \ + .pad_conf1 = PAD_CONFIG1_DEFAULT, \ + .pad_val = PAD_VAL_INPUT, \ + .use_sel = GPIO_USE_LEGACY, \ + .io_sel = GPIO_DIR_INPUT, \ + .tne = 1, \ + .smi = 1} + +/* End marker */ +#define GPIO_LIST_END 0xffffffff + +#define GPIO_END \ + { .pad_conf0 = GPIO_LIST_END } + +/* Common default GPIO settings */ +#define GPIO_INPUT GPIO_INPUT_NOPU +#define GPIO_INPUT_LEGACY GPIO_INPUT_LEGACY_NOPU +#define GPIO_INPUT_PU GPIO_INPUT_PU_10K +#define GPIO_INPUT_PD GPIO_INPUT_PD_10K +#define GPIO_NC GPIO_INPUT_PU_10K +#define GPIO_DEFAULT GPIO_FUNC0 + +/* 16 DirectIRQs per supported bank */ +#define GPIO_MAX_DIRQS 16 + +/* Most pins are GPIO function 0. Some banks have a range of pins with GPIO + * function 1. Indicate first / last GPIOs with function 1. */ +#define GPIO_NONE 255 +/* All NCORE GPIOs are function 0 */ +#define GPNCORE_GPIO_F1_RANGE_START GPIO_NONE +#define GPNCORE_GPIO_F1_RANGE_END GPIO_NONE +/* SCORE GPIO [92:93] are function 1 */ +#define GPSCORE_GPIO_F1_RANGE_START 92 +#define GPSCORE_GPIO_F1_RANGE_END 93 +/* SSUS GPIO [11:21] are function 1 */ +#define GPSSUS_GPIO_F1_RANGE_START 11 +#define GPSSUS_GPIO_F1_RANGE_END 21 + +struct soc_gpio_map { + u32 pad_conf0; + u32 pad_conf1; + u32 pad_val; + u32 use_sel : 1; + u32 io_sel : 1; + u32 gp_lvl : 1; + u32 tpe : 1; + u32 tne : 1; + u32 wake_en : 1; + u32 smi : 1; + u32 is_gpio : 1; + u32 sci : 1; +} __attribute__ ((packed)); + +struct soc_gpio_config { + const struct soc_gpio_map *ncore; + const struct soc_gpio_map *score; + const struct soc_gpio_map *ssus; + const u8 (*core_dirq)[GPIO_MAX_DIRQS]; + const u8 (*sus_dirq)[GPIO_MAX_DIRQS]; +}; + +/* Description of GPIO 'bank' ex. {ncore, score. ssus} */ +struct gpio_bank { + const int gpio_count; + const u8* gpio_to_pad; + const int legacy_base; + const unsigned long pad_base; + const u8 has_wake_en :1; + const u8 gpio_f1_range_start; + const u8 gpio_f1_range_end; +}; + +void setup_soc_gpios(struct soc_gpio_config *config); +/* This function is weak and can be overridden by a mainboard function. */ +struct soc_gpio_config* mainboard_get_gpios(void); + +/* Functions / defines for changing GPIOs in romstage */ +/* SCORE Pad definitions. */ +#define UART_RXD_PAD 82 +#define UART_TXD_PAD 83 +#define PCU_SMB_CLK_PAD 88 +#define PCU_SMB_DATA_PAD 90 + +static inline unsigned int score_pconf0(int pad_num) +{ + return GPSCORE_PAD_BASE + pad_num * 16; +} + +static inline unsigned int ssus_pconf0(int pad_num) +{ + return GPSSUS_PAD_BASE + pad_num * 16; +} + +static inline void score_select_func(int pad, int func) +{ + uint32_t reg; + uint32_t pconf0_addr = score_pconf0(pad); + + reg = read32(pconf0_addr); + reg &= ~0x7; + reg |= func & 0x7; + write32(pconf0_addr, reg); +} + +static inline void ssus_select_func(int pad, int func) +{ + uint32_t reg; + uint32_t pconf0_addr = ssus_pconf0(pad); + + reg = read32(pconf0_addr); + reg &= ~0x7; + reg |= func & 0x7; + write32(pconf0_addr, reg); +} + +/* These functions require that the input pad be configured as an input GPIO */ +static inline int score_get_gpio(int pad) +{ + uint32_t val_addr = score_pconf0(pad) + PAD_VAL_REG; + + return read32(val_addr) & PAD_VAL_HIGH; +} + +static inline int ssus_get_gpio(int pad) +{ + uint32_t val_addr = ssus_pconf0(pad) + PAD_VAL_REG; + + return read32(val_addr) & PAD_VAL_HIGH; +} + +static inline void ssus_disable_internal_pull(int pad) +{ + const uint32_t pull_mask = ~(0xf << 7); + write32(ssus_pconf0(pad), read32(ssus_pconf0(pad)) & pull_mask); +} + +#endif /* _BAYTRAIL_GPIO_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/iomap.h b/src/soc/intel/fsp_baytrail/baytrail/iomap.h new file mode 100644 index 0000000..867484b --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/iomap.h @@ -0,0 +1,90 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 _BAYTRAIL_IOMAP_H_ +#define _BAYTRAIL_IOMAP_H_ + + +/* + * Memory Mapped IO bases. + */ + +/* PCI Configuration Space */ +#define MCFG_BASE_ADDRESS CONFIG_MMCONF_BASE_ADDRESS +#define MCFG_BASE_SIZE 0x10000000 + +/* Transactions in this range will abort */ +#define ABORT_BASE_ADDRESS 0xfeb00000 +#define ABORT_BASE_SIZE 0x00100000 + +/* Power Management Controller */ +#define PMC_BASE_ADDRESS 0xfed03000 +#define PMC_BASE_SIZE 0x400 + +/* IO Memory */ +#define IO_BASE_ADDRESS 0xfed0c000 +#define IO_BASE_OFFSET_GPSCORE 0x0000 +#define IO_BASE_OFFSET_GPNCORE 0x1000 +#define IO_BASE_OFFSET_GPSSUS 0x2000 +#define IO_BASE_SIZE 0x4000 + +/* Intel Legacy Block */ +#define ILB_BASE_ADDRESS 0xfed08000 +#define ILB_BASE_SIZE 0x400 + +/* SPI Bus */ +#define SPI_BASE_ADDRESS 0xfed01000 +#define SPI_BASE_SIZE 0x400 + +/* MODPHY */ +#define MPHY_BASE_ADDRESS 0xfef00000 +#define MPHY_BASE_SIZE 0x100000 + +/* Power Management Unit */ +#define PUNIT_BASE_ADDRESS 0xfed05000 +#define PUNIT_BASE_SIZE 0x800 + +/* Root Complex Base Address */ +#define RCBA_BASE_ADDRESS 0xfed1c000 +#define RCBA_BASE_SIZE 0x400 + +/* High Performance Event Timer */ +#define HPET_BASE_ADDRESS 0xfed00000 +#define HPET_BASE_SIZE 0x400 + +/* Temporary Base Address */ +#define TEMP_BASE_ADDRESS 0xfd000000 + +/* + * IO Port bases. + */ +#define ACPI_BASE_ADDRESS 0x0400 +#define ACPI_BASE_SIZE 0x80 + +#define GPIO_BASE_ADDRESS 0x0500 +#define GPIO_BASE_SIZE 0x100 + +#define SMBUS_BASE_ADDRESS 0xefa0 + +#ifndef __ACPI__ +/* Read Top of Low Memory (BMBOUND) */ +uint32_t nc_read_top_of_low_memory(void); +#endif + +#endif /* _BAYTRAIL_IOMAP_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/iosf.h b/src/soc/intel/fsp_baytrail/baytrail/iosf.h new file mode 100644 index 0000000..8fd1e24 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/iosf.h @@ -0,0 +1,195 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 wacbmem_entryanty 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 _BAYTRAIL_IOSF_H_ +#define _BAYTRAIL_IOSF_H_ + +#include <stdint.h> +#include <baytrail/pci_devs.h> + +/* + * The Bay Trail SoC has a message network called IOSF Sideband. The access + * routines are through 3 registers in PCI config space of 00:00.0: + * MCR - control register + * MDR - data register + * MCRX - control register extension + * The extension register is only used for addresses that don't fit into the + * 8 bit register address. + */ + +#ifndef PCI_DEV +#define PCI_DEV(SEGBUS, DEV, FN) ( \ + (((SEGBUS) & 0xFFF) << 20) | \ + (((DEV) & 0x1F) << 15) | \ + (((FN) & 0x07) << 12)) +#endif +#define IOSF_PCI_DEV PCI_DEV(0,SOC_DEV,SOC_FUNC) + +#define MCR_REG 0xd0 +#define IOSF_OPCODE(x) ((x) << 24) +#define IOSF_PORT(x) ((0xff & (x)) << 16) +#define IOSF_REG(x) ((0xff & (x)) << 8) +#define IOSF_REG_UPPER(x) (((~0xff) & (x))) +#define IOSF_BYTE_EN_0 0x10 +#define IOSF_BYTE_EN_1 0x20 +#define IOSF_BYTE_EN_2 0x40 +#define IOSF_BYTE_EN_3 0x80 +#define IOSF_BYTE_EN \ + (IOSF_BYTE_EN_0 | IOSF_BYTE_EN_1 | IOSF_BYTE_EN_2 | IOSF_BYTE_EN_3) +#define MDR_REG 0xd4 +#define MCRX_REG 0xd8 + +uint32_t iosf_bunit_read(int reg); +void iosf_bunit_write(int reg, uint32_t val); +uint32_t iosf_dunit_read(int reg); +void iosf_dunit_write(int reg, uint32_t val); +/* Some registers are per channel while the gloals live in dunit 0 */ +uint32_t iosf_dunit_ch0_read(int reg); +uint32_t iosf_dunit_ch1_read(int reg); +uint32_t iosf_punit_read(int reg); +uint32_t iosf_lpss_read(int reg); +void iosf_lpss_write(int reg, uint32_t val); + +/* IOSF ports. */ +#define IOSF_PORT_AUNIT 0x00 /* IO Arbiter unit */ +#define IOSF_PORT_SYSMEMC 0x01 /* System Memory Controller */ +#define IOSF_PORT_BUNIT 0x03 /* System Memroy Arbiter/Bunit */ +#define IOSF_PORT_DUNIT_CH1 0x07 /* DUNIT Channel 1 */ +#define IOSF_PORT_USBPHY 0x43 /* USB PHY */ +#define IOSF_PORT_USHPHY 0x61 /* USB XHCI PHY */ +#define IOSF_PORT_LPSS 0xa0 /* LPSS - Low Power Subsystem */ + +/* Read and write opcodes differ per port. */ +#define IOSF_OP_READ_SYSMEMC 0x10 +#define IOSF_OP_WRITE_SYSMEMC (IOSF_OP_READ_SYSMEMC | 1) +#define IOSF_OP_READ_BUNIT 0x10 +#define IOSF_OP_WRITE_BUNIT (IOSF_OP_READ_BUNIT | 1) +#define IOSF_OP_READ_LPSS 0x06 +#define IOSF_OP_WRITE_LPSS (IOSF_OP_READ_LPSS | 1) + +/* + * BUNIT Registers. + */ + +#define BNOCACHE 0x23 +/* BMBOUND has a 128MiB granularity. Highest address is 0xf8000000. */ +#define BUNIT_BMBOUND 0x25 +/* BMBOUND_HI describes the available ram above 4GiB. It has a + * 256MiB granularity. Physical address bits 35:28 are compared with 31:24 + * bits in the BMBOUND_HI register. Also note that since BMBOUND has 128MiB + * granularity care needs to be taken with the e820 map to account for a hole + * in the ram. */ +#define BUNIT_BMBOUND_HI 0x26 +#define BUNIT_MMCONF_REG 0x27 +/* The SMMRR registers define the SMM region in MiB granularity. */ +#define BUNIT_SMRRL 0x2e +#define BUNIT_SMRRH 0x2f +# define BUNIT_SMRR_ENABLE (1 << 31) + +/* + * DUNIT Registers. + */ + +#define DRP 0x00 +# define DRP_DIMM0_RANK0_EN (0x01 << 0) +# define DRP_DIMM0_RANK1_EN (0x01 << 1) +# define DRP_DIMM1_RANK0_EN (0x01 << 2) +# define DRP_DIMM1_RANK1_EN (0x01 << 3) +# define DRP_RANK_MASK (DRP_DIMM0_RANK0_EN | DRP_DIMM0_RANK1_EN | \ + DRP_DIMM1_RANK0_EN | DRP_DIMM1_RANK1_EN) +#define DTR0 0x01 +# define DTR0_SPEED_MASK 0x03 +# define DTR0_SPEED_800 0x00 +# define DTR0_SPEED_1066 0x01 +# define DTR0_SPEED_1333 0x02 +# define DTR0_SPEED_1600 0x03 + + +/* + * LPSS Registers + */ +#define LPSS_SIO_DMA1_CTL 0x280 +#define LPSS_I2C1_CTL 0x288 +#define LPSS_I2C2_CTL 0x290 +#define LPSS_I2C3_CTL 0x298 +#define LPSS_I2C4_CTL 0x2a0 +#define LPSS_I2C5_CTL 0x2a8 +#define LPSS_I2C6_CTL 0x2b0 +#define LPSS_I2C7_CTL 0x2b8 +#define LPSS_SIO_DMA2_CTL 0x240 +#define LPSS_PWM1_CTL 0x248 +#define LPSS_PWM2_CTL 0x250 +#define LPSS_HSUART1_CTL 0x258 +#define LPSS_HSUART2_CTL 0x260 +#define LPSS_SPI_CTL 0x268 +# define LPSS_CTL_ACPI_INT_EN (1 << 21) +# define LPSS_CTL_PCI_CFG_DIS (1 << 20) +# define LPSS_CTL_SNOOP (1 << 18) +# define LPSS_CTL_NOSNOOP (1 << 19) +# define LPSS_CTL_PM_CAP_PRSNT (1 << 1) + +/* + * SCC Registers + */ +#define SCC_SD_CTL 0x504 +#define SCC_SDIO_CTL 0x508 +#define SCC_MMC_CTL 0x50c +# define SCC_CTL_PCI_CFG_DIS (1 << 0) +# define SCC_CTL_ACPI_INT_EN (1 << 1) + +/* + * CCU Registers + */ + +#define PLT_CLK_CTRL_0 0x3c +#define PLT_CLK_CTRL_1 0x40 +#define PLT_CLK_CTRL_2 0x44 +#define PLT_CLK_CTRL_3 0x48 +#define PLT_CLK_CTRL_4 0x4c +#define PLT_CLK_CTRL_5 0x50 +# define PLT_CLK_CTRL_19P2MHZ_FREQ (0 << 1) +# define PLT_CLK_CTRL_25MHZ_FREQ (1 << 1) +# define PLT_CLK_CTRL_SELECT_FREQ (1 << 0) + +/* + * USBPHY Registers + */ +#define USBPHY_COMPBG 0x7f04 +#define USBPHY_PER_PORT_LANE0 0x4100 +#define USBPHY_PER_PORT_RCOMP_HS_PULLUP0 0x4122 +#define USBPHY_PER_PORT_LANE1 0x4200 +#define USBPHY_PER_PORT_RCOMP_HS_PULLUP1 0x4222 +#define USBPHY_PER_PORT_LANE2 0x4300 +#define USBPHY_PER_PORT_RCOMP_HS_PULLUP2 0x4322 +#define USBPHY_PER_PORT_LANE3 0x4400 +#define USBPHY_PER_PORT_RCOMP_HS_PULLUP3 0x4422 + +/* + * USHPHY Registers + */ +#define USHPHY_CDN_PLL_CONTROL 0x03c0 +#define USHPHY_CDN_VCO_START_CAL_POINT 0x0054 +#define USHPHY_CCDRLF 0x8040 +#define USHPHY_PEAKING_AMP_CONFIG_DIAG 0x80a8 +#define USHPHY_OFFSET_COR_CONFIG_DIAG 0x80b0 +#define USHPHY_VGA_GAIN_CONFIG_DIAG 0x8080 +#define USHPHY_REE_DAC_CONTROL 0x80b8 +#define USHPHY_CDN_U1_POWER_STATE_DEF 0x0000 + +#endif /* _BAYTRAIL_IOSF_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/irq.h b/src/soc/intel/fsp_baytrail/baytrail/irq.h new file mode 100644 index 0000000..98ca116 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/irq.h @@ -0,0 +1,165 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 _BAYTRAIL_IRQ_H_ +#define _BAYTRAIL_IRQ_H_ + +#define PIRQA_APIC_IRQ 16 +#define PIRQB_APIC_IRQ 17 +#define PIRQC_APIC_IRQ 18 +#define PIRQD_APIC_IRQ 19 +#define PIRQE_APIC_IRQ 20 +#define PIRQF_APIC_IRQ 21 +#define PIRQG_APIC_IRQ 22 +#define PIRQH_APIC_IRQ 23 +/* The below IRQs are for when devices are in ACPI mode. Active low. */ +#define LPE_DMA0_IRQ 24 +#define LPE_DMA1_IRQ 25 +#define LPE_SSP0_IRQ 26 +#define LPE_SSP1_IRQ 27 +#define LPE_SSP2_IRQ 28 +#define LPE_IPC2HOST_IRQ 29 +#define LPSS_I2C1_IRQ 32 +#define LPSS_I2C2_IRQ 33 +#define LPSS_I2C3_IRQ 34 +#define LPSS_I2C4_IRQ 35 +#define LPSS_I2C5_IRQ 36 +#define LPSS_I2C6_IRQ 37 +#define LPSS_I2C7_IRQ 38 +#define LPSS_HSUART1_IRQ 39 +#define LPSS_HSUART2_IRQ 40 +#define LPSS_SPI_IRQ 41 +#define LPSS_DMA1_IRQ 42 +#define LPSS_DMA2_IRQ 43 +#define SCC_EMMC_IRQ 44 +#define SCC_SDIO_IRQ 46 +#define SCC_SD_IRQ 47 +#define GPIO_NC_IRQ 48 +#define GPIO_SC_IRQ 49 +#define GPIO_SUS_IRQ 50 +/* GPIO direct / dedicated IRQs. */ +#define GPIO_S0_DED_IRQ_0 51 +#define GPIO_S0_DED_IRQ_1 52 +#define GPIO_S0_DED_IRQ_2 53 +#define GPIO_S0_DED_IRQ_3 54 +#define GPIO_S0_DED_IRQ_4 55 +#define GPIO_S0_DED_IRQ_5 56 +#define GPIO_S0_DED_IRQ_6 57 +#define GPIO_S0_DED_IRQ_7 58 +#define GPIO_S0_DED_IRQ_8 59 +#define GPIO_S0_DED_IRQ_9 60 +#define GPIO_S0_DED_IRQ_10 61 +#define GPIO_S0_DED_IRQ_11 62 +#define GPIO_S0_DED_IRQ_12 63 +#define GPIO_S0_DED_IRQ_13 64 +#define GPIO_S0_DED_IRQ_14 65 +#define GPIO_S0_DED_IRQ_15 66 +#define GPIO_S5_DED_IRQ_0 67 +#define GPIO_S5_DED_IRQ_1 68 +#define GPIO_S5_DED_IRQ_2 69 +#define GPIO_S5_DED_IRQ_3 70 +#define GPIO_S5_DED_IRQ_4 71 +#define GPIO_S5_DED_IRQ_5 72 +#define GPIO_S5_DED_IRQ_6 73 +#define GPIO_S5_DED_IRQ_7 74 +#define GPIO_S5_DED_IRQ_8 75 +#define GPIO_S5_DED_IRQ_9 76 +#define GPIO_S5_DED_IRQ_10 77 +#define GPIO_S5_DED_IRQ_11 78 +#define GPIO_S5_DED_IRQ_12 79 +#define GPIO_S5_DED_IRQ_13 80 +#define GPIO_S5_DED_IRQ_14 81 +#define GPIO_S5_DED_IRQ_15 82 +/* DIRQs - Two levels of expansion to evaluate to numeric constants for ASL. */ +#define _GPIO_S0_DED_IRQ(slot) GPIO_S0_DED_IRQ_##slot +#define _GPIO_S5_DED_IRQ(slot) GPIO_S5_DED_IRQ_##slot +#define GPIO_S0_DED_IRQ(slot) _GPIO_S0_DED_IRQ(slot) +#define GPIO_S5_DED_IRQ(slot) _GPIO_S5_DED_IRQ(slot) + +/* PIC IRQ settings. */ +#define PIRQ_PIC_IRQ3 0x3 +#define PIRQ_PIC_IRQ4 0x4 +#define PIRQ_PIC_IRQ5 0x5 +#define PIRQ_PIC_IRQ6 0x6 +#define PIRQ_PIC_IRQ7 0x7 +#define PIRQ_PIC_IRQ9 0x9 +#define PIRQ_PIC_IRQ10 0xa +#define PIRQ_PIC_IRQ11 0xb +#define PIRQ_PIC_IRQ12 0xc +#define PIRQ_PIC_IRQ14 0xe +#define PIRQ_PIC_IRQ15 0xf +#define PIRQ_PIC_IRQDISABLE 0x80 +#define PIRQ_PIC_UNKNOWN_UNUSED 0xff + +/* Overloaded term, but these values determine the per device route. */ +#define PIRQA 0 +#define PIRQB 1 +#define PIRQC 2 +#define PIRQD 3 +#define PIRQE 4 +#define PIRQF 5 +#define PIRQG 6 +#define PIRQH 7 + +/* These registers live behind the ILB_BASE_ADDRESS */ +#define ACTL 0x00 +# define SCIS_MASK 0x07 +# define SCIS_IRQ9 0x00 +# define SCIS_IRQ10 0x01 +# define SCIS_IRQ11 0x02 +# define SCIS_IRQ20 0x04 +# define SCIS_IRQ21 0x05 +# define SCIS_IRQ22 0x06 +# define SCIS_IRQ23 0x07 + +/* In each mainboard directory there should exist a header file irqroute.h that + * defines the PCI_DEV_PIRQ_ROUTES and PIRQ_PIC_ROUTES macros which + * consist of PCI_DEV_PIRQ_ROUTE and PIRQ_PIC entries. */ + +#if !defined(__ASSEMBLER__) && !defined(__ACPI__) +#include <stdint.h> + +#define NUM_OF_PCI_DEVS 32 +#define NUM_PIRQS 8 + +struct baytrail_irq_route { + /* Per device configuration. */ + uint16_t pcidev[NUM_OF_PCI_DEVS]; + /* Route path for each internal PIRQx in PIC mode. */ + uint8_t pic[NUM_PIRQS]; +}; + +extern const struct baytrail_irq_route global_baytrail_irq_route; + +#define DEFINE_IRQ_ROUTES \ + const struct baytrail_irq_route global_baytrail_irq_route = { \ + .pcidev = { PCI_DEV_PIRQ_ROUTES, }, \ + .pic = { PIRQ_PIC_ROUTES, }, \ + } + +#define PCI_DEV_PIRQ_ROUTE(dev_, a_, b_, c_, d_) \ + [dev_] = ((PIRQ ## d_) << 12) | ((PIRQ ## c_) << 8) | \ + ((PIRQ ## b_) << 4) | ((PIRQ ## a_) << 0) + +#define PIRQ_PIC(pirq_, pic_irq_) \ + [PIRQ ## pirq_] = PIRQ_PIC_IRQ ## pic_irq_ + +#endif /* !defined(__ASSEMBLER__) && !defined(__ACPI__) */ + +#endif /* _BAYTRAIL_IRQ_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/lpc.h b/src/soc/intel/fsp_baytrail/baytrail/lpc.h new file mode 100644 index 0000000..9dd0439 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/lpc.h @@ -0,0 +1,112 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2013-2014 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 _BAYTRAIL_LPC_H_ +#define _BAYTRAIL_LPC_H_ + +#define FADT_SOC_LPC_DEV 0, PCI_DEVFN(0x1f,0) + +/* PCI config registers in LPC bridge. */ +#define REVID 0x08 +#define ABASE 0x40 /* IO BAR */ +#define PBASE 0x44 /* MEM BAR */ +#define GBASE 0x48 /* IO BAR */ +#define IOBASE 0x4c /* MEM BAR */ +#define IBASE 0x50 /* MEM BAR */ +#define SBASE 0x54 /* MEM BAR */ +#define MPBASE 0x58 /* MEM BAR */ +#define PUBASE 0x5c +#define SET_BAR_ENABLE 0x02 +#define UART_CONT 0x80 +#define RCBA 0xf0 +#define RCBA_ENABLE 0x01 + +#define ILB_ACTL 0 +#define ILB_MC 0x4 +#define ILB_PIRQA_ROUT 0x8 +#define ILB_PIRQB_ROUT 0x9 +#define ILB_PIRQC_ROUT 0xA +#define ILB_PIRQD_ROUT 0xB +#define ILB_PIRQE_ROUT 0xC +#define ILB_PIRQF_ROUT 0xD +#define ILB_PIRQG_ROUT 0xE +#define ILB_PIRQH_ROUT 0xF +#define ILB_SERIRQ_CNTL 0x10 +#define SCNT_CONTINUOUS_MODE (1 << 7) +#define SCNT_QUIET_MODE 0 +#define ILB_IR00 0x20 +#define ILB_IR01 0x22 +#define ILB_IR02 0x24 +#define ILB_IR03 0x26 +#define ILB_IR04 0x28 +#define ILB_IR05 0x2A +#define ILB_IR06 0x2C +#define ILB_IR07 0x2E +#define ILB_IR08 0x30 +#define ILB_IR09 0x32 +#define ILB_IR10 0x34 +#define ILB_IR11 0x36 +#define ILB_IR12 0x38 +#define ILB_IR13 0x3A +#define ILB_IR14 0x3C +#define ILB_IR15 0x3E +#define ILB_IR16 0x40 +#define ILB_IR17 0x42 +#define ILB_IR18 0x44 +#define ILB_IR19 0x46 +#define ILB_IR20 0x48 +#define ILB_IR21 0x4A +#define ILB_IR22 0x4C +#define ILB_IR23 0x4E +#define ILB_IR24 0x50 +#define ILB_IR25 0x52 +#define ILB_IR26 0x54 +#define ILB_IR27 0x56 +#define ILB_IR28 0x58 +#define ILB_IR29 0x5A +#define ILB_IR30 0x5C +#define ILB_IR31 0x5E +#define ILB_OIC 0x60 +#define SIRQEN (1 << 12) +#define AEN (1 << 8) + +#define RID_A_STEPPING_START 1 +#define RID_B_STEPPING_START 5 +#define RID_C_STEPPING_START 0xe +enum baytrail_stepping { + STEP_A0, + STEP_A1, + STEP_B0, + STEP_B1, + STEP_B2, + STEP_B3, + STEP_C0, +}; + +/* Registers behind the RCBA_BASE_ADDRESS bar. */ +#define GCS 0x00 +# define BILD (1 << 0) + +/* Default IO range claimed by the LPC devices. The upper bound is exclusive. */ +#define LPC_DEFAULT_IO_RANGE_LOWER 0 +#define LPC_DEFAULT_IO_RANGE_UPPER 0x1000 +#define IO_APIC_RANGE_SIZE 0x1000 + +#endif /* _BAYTRAIL_LPC_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/msr.h b/src/soc/intel/fsp_baytrail/baytrail/msr.h new file mode 100644 index 0000000..882346c --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/msr.h @@ -0,0 +1,41 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 wacbmem_entryanty 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 _BAYTRAIL_MSR_H_ +#define _BAYTRAIL_MSR_H_ + +#define MSR_IA32_PLATFORM_ID 0x17 +#define MSR_BSEL_CR_OVERCLOCK_CONTROL 0xcd +#define MSR_PLATFORM_INFO 0xce +#define MSR_PMG_CST_CONFIG_CONTROL 0xe2 +#define MSR_POWER_MISC 0x120 +#define MSR_IA32_PERF_CTL 0x199 +#define MSR_IA32_MISC_ENABLES 0x1a0 +#define MSR_POWER_CTL 0x1fc +#define MSR_PKG_POWER_SKU_UNIT 0x606 +#define MSR_PKG_POWER_LIMIT 0x610 +#define MSR_IACORE_RATIOS 0x66a +#define MSR_IACORE_TURBO_RATIOS 0x66c +#define MSR_IACORE_VIDS 0x66b +#define MSR_IACORE_TURBO_VIDS 0x66d + +/* Read BCLK from MSR */ +unsigned bus_freq_khz(void); + +#endif /* _BAYTRAIL_MSR_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/nvm.h b/src/soc/intel/fsp_baytrail/baytrail/nvm.h new file mode 100644 index 0000000..d0cbf7b --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/nvm.h @@ -0,0 +1,34 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 _NVM_H_ +#define _NVM_H_ + +#include <stddef.h> + +/* Determine if area is erased. returns 1 if erased. 0 otherwise. */ +int nvm_is_erased(const void *start, size_t size); + +/* Erase region according to start and size. Returns < 0 on error else 0. */ +int nvm_erase(void *start, size_t size); + +/* Write data to NVM. Returns 0 on success < 0 on error. */ +int nvm_write(void *start, const void *data, size_t size); + +#endif /* _NVM_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/nvs.h b/src/soc/intel/fsp_baytrail/baytrail/nvs.h new file mode 100644 index 0000000..1e12310 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/nvs.h @@ -0,0 +1,73 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 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 + */ + +#ifndef _BAYTRAIL_NVS_H_ +#define _BAYTRAIL_NVS_H_ + +#include <baytrail/device_nvs.h> + +typedef struct { + /* Miscellaneous */ + u16 osys; /* 0x00 - Operating System */ + u8 smif; /* 0x02 - SMI function call ("TRAP") */ + u8 prm0; /* 0x03 - SMI function call parameter */ + u8 prm1; /* 0x04 - SMI function call parameter */ + u8 scif; /* 0x05 - SCI function call (via _L00) */ + u8 prm2; /* 0x06 - SCI function call parameter */ + u8 prm3; /* 0x07 - SCI function call parameter */ + u8 lckf; /* 0x08 - Global Lock function for EC */ + u8 prm4; /* 0x09 - Lock function parameter */ + u8 prm5; /* 0x0a - Lock function parameter */ + u32 p80d; /* 0x0b - Debug port (IO 0x80) value */ + u8 lids; /* 0x0f - LID state (open = 1) */ + u8 pwrs; /* 0x10 - Power state (AC = 1) */ + u8 pcnt; /* 0x11 - Processor Count */ + u8 tpmp; /* 0x12 - TPM Present and Enabled */ + u8 tlvl; /* 0x13 - Throttle Level */ + u8 ppcm; /* 0x14 - Maximum P-state usable by OS */ + u8 rsvd1[11]; + + /* Device Config */ + u8 s5u0; /* 0x20 - Enable USB0 in S5 */ + u8 s5u1; /* 0x21 - Enable USB1 in S5 */ + u8 s3u0; /* 0x22 - Enable USB0 in S3 */ + u8 s3u1; /* 0x23 - Enable USB1 in S3 */ + u8 tact; /* 0x24 - Thermal Active trip point */ + u8 tpsv; /* 0x25 - Thermal Passive trip point */ + u8 tcrt; /* 0x26 - Thermal Critical trip point */ + u8 dpte; /* 0x27 - Enable DPTF */ + u8 rsvd2[8]; + + /* Base Addresses */ + u32 cmem; /* 0x30 - CBMEM TOC */ + u32 tolm; /* 0x34 - Top of Low Memory */ + u32 cbmc; /* 0x38 - coreboot memconsole */ + u8 rsvd3[196]; + + /* Baytrail LPSS (0x1000) */ + device_nvs_t dev; +} __attribute__((packed)) global_nvs_t; + +#ifdef __SMM__ +/* Used in SMM to find the ACPI GNVS address */ +global_nvs_t *smm_get_gnvs(void); +#endif + +#endif /* _BAYTRAIL_NVS_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/pattrs.h b/src/soc/intel/fsp_baytrail/baytrail/pattrs.h new file mode 100644 index 0000000..d4eb721 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/pattrs.h @@ -0,0 +1,65 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 _PATTRS_H_ +#define _PATTRS_H_ + +#include <stdint.h> +#include <cpu/x86/msr.h> + +enum { + IACORE_MIN, + IACORE_LFM, + IACORE_MAX, + IACORE_TURBO, + IACORE_END +}; + +/* The pattrs structure is a common place to stash pertinent information + * about the processor or platform. Instead of going to the source (msrs, cpuid) + * every time an attribute is needed use the pattrs structure. + */ +struct pattrs { + msr_t platform_id; + msr_t platform_info; + int iacore_ratios[IACORE_END]; + int iacore_vids[IACORE_END]; + uint32_t cpuid; + int revid; + int stepping; + const void *microcode_patch; + int address_bits; + int num_cpus; + unsigned bclk_khz; +}; + +/* This is just to hide the abstraction w/o relying on how the underlying + * storage is allocated. */ +#define PATTRS_GLOB_NAME __global_pattrs +#define DEFINE_PATTRS struct pattrs PATTRS_GLOB_NAME +extern DEFINE_PATTRS; + +static inline const struct pattrs *pattrs_get(void) +{ + return &PATTRS_GLOB_NAME; +} + + +#endif /* _PATTRS_H_ */ + diff --git a/src/soc/intel/fsp_baytrail/baytrail/pci_devs.h b/src/soc/intel/fsp_baytrail/baytrail/pci_devs.h new file mode 100644 index 0000000..dc41d13 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/pci_devs.h @@ -0,0 +1,241 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 _BAYTRAIL_PCI_DEVS_H_ +#define _BAYTRAIL_PCI_DEVS_H_ + +#define BUS0 0 + +/* All these devices live on bus 0 with the associated device and function */ +#define DEV_FUNC(x,y) ((x<<3) | y) + + +/* SoC transaction router */ +#define SOC_DEV 0x0 +#define SOC_FUNC 0 +# define SOC_DEVID 0x0f00 +# define SOC_DEV_FUNC DEV_FUNC(SOC_DEV,SOC_FUNC) + + +/* Graphics and Display */ +#define GFX_DEV 0x2 +#define GFX_FUNC 0 +# define GFX_DEVID 0x0f31 +# define GFX_DEV_FUNC DEV_FUNC(GFX_DEV,GFX_FUNC) + +/* MIPI */ +#define MIPI_DEV 0x3 +#define MIPI_FUNC 0 +# define MIPI_DEVID 0x0f38 +# define MIPI_DEV_FUNC DEV_FUNC(MIPI_DEV,MIPI_FUNC) + + +/* SDIO Port */ +#define EMMC_DEV 0x10 +#define EMMC_FUNC 0 +# define EMMC_DEVID 0x0f14 +# define EMMC_DEV_FUNC DEV_FUNC(EMMC_DEV,EMMC_FUNC) + +/* SDIO Port */ +#define SDIO_DEV 0x11 +#define SDIO_FUNC 0 +# define SDIO_DEVID 0x0f15 +# define SDIO_DEV_FUNC DEV_FUNC(SDIO_DEV,SDIO_FUNC) + +/* SD Port */ +#define SD_DEV 0x12 +#define SD_FUNC 0 +# define SD_DEVID 0x0f16 +# define SD_DEV_FUNC DEV_FUNC(SD_DEV,SD_FUNC) + +/* SATA */ +#define SATA_DEV 0x13 +#define SATA_FUNC 0 +# define IDE1_DEVID 0x0f20 +# define IDE2_DEVID 0x0f21 +# define AHCI1_DEVID 0x0f22 +# define AHCI2_DEVID 0x0f23 +# define SATA_MA 0x84 +# define SATA_MAP 0x90 +# define SATA_PSC 0x92 +# define SATA_SP 0xD0 +# define SATA_BIST1 0xE4 +# define SATA_BIST2 0xE8 +# define SATA_DEV_FUNC DEV_FUNC(SATA_DEV,SATA_FUNC) + +#define SATA_MA_BDFO PCI_DEV(BUS0, SATA_DEV, SATA_FUNC), SATA_MA +#define SATA_SP_BDFO PCI_DEV(BUS0, SATA_DEV, SATA_FUNC), SATA_SP +#define SATA_BIST1_BDFO PCI_DEV(BUS0, SATA_DEV, SATA_FUNC), SATA_BIST1 +#define SATA_BIST2_BDFO PCI_DEV(BUS0, SATA_DEV, SATA_FUNC), SATA_BIST2 + +/* xHCI */ +#define XHCI_DEV 0x14 +#define XHCI_FUNC 0 +# define XHCI_DEVID 0x0f35 +# define XHCI_FUS_REG 0xE0 +# define XHCI_FUNC_DISABLE (1 << 0) +# define XHCI_USB2PR_REG 0xD0 +# define XHCI_DEV_FUNC DEV_FUNC(XHCI_DEV,XHCI_FUNC) + +/* LPE Audio */ +#define LPE_DEV 0x15 +#define LPE_FUNC 0 +# define LPE_DEVID 0x0f28 +# define LPE_DEV_FUNC DEV_FUNC(LPE_DEV,LPE_FUNC) + +/* OTG */ +#define OTG_DEV 0x16 +#define OTG_FUNC 0 +# define OTG_DEVID 0x0f37 +# define OTG_DEV_FUNC DEV_FUNC(LPE_DEV,LPE_FUNC) + +/* MMC Port */ +#define MMC45_DEV 0x17 +#define MMC45_FUNC 0 +# define MMC45_DEVID 0x0f50 +# define MMC45_DEV_FUNC DEV_FUNC(MMC45_DEV,MMC45_FUNC) + +/* Serial IO 1 */ +#define SIO1_DEV 0x18 +# define SIO_DMA1_DEV SIO1_DEV +# define SIO_DMA1_FUNC 0 +# define SIO_DMA1_DEVID 0x0f40 +# define I2C1_DEV SIO1_DEV +# define I2C1_FUNC 1 +# define I2C1_DEVID 0x0f41 +# define I2C2_DEV SIO1_DEV +# define I2C2_FUNC 2 +# define I2C2_DEVID 0x0f42 +# define I2C3_DEV SIO1_DEV +# define I2C3_FUNC 3 +# define I2C3_DEVID 0x0f43 +# define I2C4_DEV SIO1_DEV +# define I2C4_FUNC 4 +# define I2C4_DEVID 0x0f44 +# define I2C5_DEV SIO1_DEV +# define I2C5_FUNC 5 +# define I2C5_DEVID 0x0f45 +# define I2C6_DEV SIO1_DEV +# define I2C6_FUNC 6 +# define I2C6_DEVID 0x0f46 +# define I2C7_DEV SIO1_DEV +# define I2C7_FUNC 7 +# define I2C7_DEVID 0x0f47 +# define SIO_DMA1_DEV_FUNC DEV_FUNC(SIO_DMA1_DEV,SIO_DMA1_FUNC) +# define I2C1_DEV_FUNC DEV_FUNC(I2C1_DEV,I2C1_FUNC) +# define I2C2_DEV_FUNC DEV_FUNC(I2C2_DEV,I2C2_FUNC) +# define I2C3_DEV_FUNC DEV_FUNC(I2C3_DEV,I2C3_FUNC) +# define I2C4_DEV_FUNC DEV_FUNC(I2C4_DEV,I2C4_FUNC) +# define I2C5_DEV_FUNC DEV_FUNC(I2C5_DEV,I2C5_FUNC) +# define I2C6_DEV_FUNC DEV_FUNC(I2C6_DEV,I2C6_FUNC) +# define I2C7_DEV_FUNC DEV_FUNC(I2C7_DEV,I2C7_FUNC) + +/* Trusted Execution Engine */ +#define TXE_DEV 0x1a +#define TXE_FUNC 0 +# define TXE_DEVID 0x0f18 +# define TXE_DEV_FUNC DEV_FUNC(TXE_DEV,TXE_FUNC) + +/* HD Audio */ +#define HDA_DEV 0x1b +#define HDA_FUNC 0 +# define HDA_DEVID 0x0f04 +# define HDA_DEV_FUNC DEV_FUNC(HDA_DEV,HDA_FUNC) +# define HDA_AZUBAR 0x14 +# define HDA_MMLA 0x64 +# define HDA_MMUA 0x68 +#define HDA_AZUBAR_BDFO PCI_DEV(BUS0, HDA_DEV, HDA_FUNC), HDA_AZUBAR +#define HDA_MMLA_BDFO PCI_DEV(BUS0, HDA_DEV, HDA_FUNC), HDA_MMLA +#define HDA_MMUA_BDFO PCI_DEV(BUS0, HDA_DEV, HDA_FUNC), HDA_MMUA + +/* PCIe Ports */ +#define PCIE_DEV 0x1c +# define PCIE_PORT1_DEV PCIE_DEV +# define PCIE_PORT1_FUNC 0 +# define PCIE_PORT1_DEVID 0x0f48 +# define PCIE_PORT2_DEV PCIE_DEV +# define PCIE_PORT2_FUNC 1 +# define PCIE_PORT2_DEVID 0x0f4a +# define PCIE_PORT3_DEV PCIE_DEV +# define PCIE_PORT3_FUNC 2 +# define PCIE_PORT3_DEVID 0x0f4c +# define PCIE_PORT4_DEV PCIE_DEV +# define PCIE_PORT4_FUNC 3 +# define PCIE_PORT4_DEVID 0x0f4e +# define PCIE_PORT1_DEV_FUNC DEV_FUNC(PCIE_DEV,PCIE_PORT1_FUNC) +# define PCIE_PORT2_DEV_FUNC DEV_FUNC(PCIE_DEV,PCIE_PORT2_FUNC) +# define PCIE_PORT3_DEV_FUNC DEV_FUNC(PCIE_DEV,PCIE_PORT3_FUNC) +# define PCIE_PORT4_DEV_FUNC DEV_FUNC(PCIE_DEV,PCIE_PORT4_FUNC) + +/* EHCI */ +#define EHCI_DEV 0x1d +#define EHCI_FUNC 0 +# define EHCI_DEVID 0x0f34 +# define EHCI_DEV_FUNC DEV_FUNC(EHCI_DEV,EHCI_FUNC) + +/* Serial IO 2 */ +#define SIO2_DEV 0x1e +# define SIO_DMA2_DEV SIO2_DEV +# define SIO_DMA2_FUNC 0 +# define SIO_DMA2_DEVID 0x0f06 +# define PWM1_DEV SIO2_DEV +# define PWM1_FUNC 1 +# define PWM1_DEVID 0x0f08 +# define PWM2_DEV SIO2_DEV +# define PWM2_FUNC 2 +# define PWM2_DEVID 0x0f09 +# define HSUART1_DEV SIO2_DEV +# define HSUART1_FUNC 3 +# define HSUART1_DEVID 0x0f0a +# define HSUART2_DEV SIO2_DEV +# define HSUART2_FUNC 4 +# define HSUART2_DEVID 0x0f0c +# define SPI_DEV SIO2_DEV +# define SPI_FUNC 5 +# define SPI_DEVID 0xf0e +# define SIO_DMA2_DEV_FUNC DEV_FUNC(SIO_DMA2_DEV,SIO_DMA2_FUNC) +# define PWM1_DEV_FUNC DEV_FUNC(PWM1_DEV,PWM1_FUNC) +# define PWM2_DEV_FUNC DEV_FUNC(PWM2_DEV,PWM2_FUNC) +# define HSUART1_DEV_FUNC DEV_FUNC(HSUART1_DEV,HSUART1_FUNC) +# define HSUART2_DEV_FUNC DEV_FUNC(HSUART2_DEV,HSUART2_FUNC) +# define SPI_DEV_FUNC DEV_FUNC(SPI_DEV,SPI_FUNC) + + +/* Platform Controller Unit */ +#define PCU_DEV 0x1f +# define LPC_DEV PCU_DEV +# define LPC_FUNC 0 +# define LPC_DEVID 0x0f1c +# define SMBUS_DEV PCU_DEV +# define SMBUS_FUNC 3 +# define SMBUS_DEVID 0x0f12 +# define LPC_DEV_FUNC DEV_FUNC(LPC_DEV,LPC_FUNC) +# define LPC_BDF PCI_DEV(0, LPC_DEV, LPC_FUNC) +# define SMBUS_DEV_FUNC DEV_FUNC(SMBUS_DEV,SMBUS_FUNC) + +#define INITIAL_TIMESTAMP_LOCATION HDA_MMUA_BDFO +#define BEFORE_CAR_TIMESTAMP_LOCATION SATA_BIST1_BDFO +#define ASM_BEFORE_CAR_TSC_LOC 0x80 << 24 | SATA_DEV_FUNC << 8 | SATA_BIST1 +#define AFTER_CAR_TIMESTAMP_LOCATION SATA_BIST2_BDFO +#define ASM_AFTER_CAR_TSC_LOC 0x80 << 24 | SATA_DEV_FUNC << 8 | SATA_BIST2 +#define START_ROMSTAGE_TIMESTAMP_LOCATION HDA_MMLA_BDFO +#define BEFORE_RAMINIT_TIMESTAMP_LOCATION SATA_MA_BDFO + +#endif /* _BAYTRAIL_PCI_DEVS_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/pcie.h b/src/soc/intel/fsp_baytrail/baytrail/pcie.h new file mode 100644 index 0000000..98effea --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/pcie.h @@ -0,0 +1,102 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 wacbmem_entryanty 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 _BAYTRAIL_PCIE_H_ +#define _BAYTRAIL_PCIE_H_ + +/* PCIe root port config space registers. */ +#define XCAP 0x40 +# define SI (1 << 24) +#define DCAP 0x44 +# define MPS_MASK 0x7 +#define DCTL_DSTS 0x48 +# define URE (1 << 3) +# define FEE (1 << 2) +# define NFE (1 << 1) +# define CEE (1 << 0) +#define LCAP 0x4c +# define L1EXIT_SHIFT 15 +# define L1EXIT_MASK (0x7 << L1EXIT_SHIFT) +#define LCTL 0x50 +# define CCC (1 << 6) +# define RL (1 << 5) +# define LD (1 << 4) +#define LSTS 0x52 +#define SLCAP 0x54 +# define SLN_SHIFT 19 +# define SLS_SHIFT 15 +# define SLV_SHIFT 7 +# define HPC (1 << 6) +# define HPS (1 << 5) +#define SLCTL_SLSTS 0x58 +# define PDS (1 << 22) +#define DCAP2 0x64 +# define OBFFS (0x3 << 18) +# define LTRMS (1 << 11) +#define DSTS2 0x68 +# define OBFFEN (3 << 13) +# define LTRME (1 << 10) +# define CTD (1 << 4) +#define CHCFG 0xd0 +# define UPSD (1 << 24) +# define UNRS (1 << 15) +# define UPRS (1 << 14) +#define MPC2 0xd4 +# define IPF (1 << 11) +# define LSTP (1 << 6) +# define EOIFD (1 << 1) +#define MPC 0xd8 +# define CCEL_SHIFT 15 +# define CCEL_MASK (0x7 << CCEL_SHIFT) +#define RPPGEN 0xe0 +# define RPSCGEN (1 << 15) +# define LCLKREQEN (1 << 13) +# define BBCLKREQEN (1 << 12) +# define SRDLCGEN (1 << 11) +# define SRDBCGEN (1 << 10) +# define RPDLCGEN (1 << 9) +# define RPDBCGEN (1 << 8) +#define PWRCTL 0xe8 +# define RPL1SQPOL (1 << 1) +# define RPDTSQPOL (1 << 0) +#define PHYCTL2_IOSFBCTL 0xf4 +# define PLL_OFF_EN (1 << 8) +# define TDFT (3 << 14) +# define TXCFGCHWAIT (3 << 12) +# define SIID (3 << 26) +#define STRPFUSECFG 0xfc +# define LANECFG_SHIFT 14 +# define LANECFG_MASK (0x3 << LANECFG_SHIFT) +#define AERCH 0x100 +#define NFTS 0x314 +#define L0SC 0x318 +#define CFG2 0x320 +# define CSREN (1 << 22) +# define LATGC_SHIFT 6 +# define LATGC_MASK (0x7 << LATGC_SHIFT) +#define PCIEDBG 0x324 +# define SPCE (1 << 5) +#define PCIESTS1 0x328 +#define PCIEALC 0x338 +#define RTP 0x33c +#define PHYCTL4 0x408 +# define SQDIS (1 << 27) + + +#endif /* _BAYTRAIL_PCIE_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/pmc.h b/src/soc/intel/fsp_baytrail/baytrail/pmc.h new file mode 100644 index 0000000..ee15dd9 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/pmc.h @@ -0,0 +1,307 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2013-2014 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 _BAYTRAIL_PMC_H_ +#define _BAYTRAIL_PMC_H_ + + +#define IOCOM1 0x3f8 + +/* Memory mapped IO registers behind PMC_BASE_ADDRESS */ +#define PRSTS 0x00 +# define PMC_WDT_STS (1 << 15) +# define SEC_GBLRST_STS (1 << 7) +# define SEC_WDT_STS (1 << 6) +# define WOL_OVR_WK_STS (1 << 5) +# define PMC_WAKE_STS (1 << 4) +#define PMC_CFG 0x08 +# define SPS (1 << 5) +# define NO_REBOOT (1 << 4) +# define SX_ENT_TO_EN (1 << 3) +# define TIMING_T581_SHIFT (0) +# define TIMING_T581_MASK (3 << TIMING_T581_SHIFT) +# define TIMING_T581_10uS (0 << TIMING_T581_SHIFT) +# define TIMING_T581_100uS (1 << TIMING_T581_SHIFT) +# define TIMING_T581_1mS (2 << TIMING_T581_SHIFT) +# define TIMING_T581_10mS (3 << TIMING_T581_SHIFT) +#define VLV_PM_STS 0x0c +# define PMC_MSG_FULL_STS (1 << 24) +# define PMC_MSG_4_FULL_STS (1 << 23) +# define PMC_MSG_3_FULL_STS (1 << 22) +# define PMC_MSG_2_FULL_STS (1 << 21) +# define PMC_MSG_1_FULL_STS (1 << 20) +# define CODE_REQ (1 << 8) +# define HPR_ENT_TO (1 << 2) +# define SX_ENT_TO (1 << 1) +#define GEN_PMCON1 0x20 +# define UART_EN (1 << 24) +# define DISB (1 << 23) +# define MEM_SR (1 << 21) +# define SRS (1 << 20) +# define CTS (1 << 19) +# define MS4V (1 << 18) +# define PWR_FLR (1 << 16) +# define PME_B0_S5_DIS (1 << 15) +# define SUS_PWR_FLR (1 << 14) +# define WOL_EN_OVRD (1 << 13) +# define DIS_SLP_X_STRCH_SUS_UP (1 << 12) +# define GEN_RST_STS (1 << 9) +# define RPS (1 << 2) +# define AFTERG3_EN (1 << 0) +#define GEN_PMCON2 0x24 +# define SLPSX_STR_POL_LOCK (1 << 18) +# define BIOS_PCI_EXP_EN (1 << 10) +# define PWRBTN_LVL (1 << 9) +# define SMI_LOCK (1 << 4) +#define ETR 0x48 +# define CF9LOCK (1 << 31) +# define LTR_DEF (1 << 22) +# define IGNORE_HPET (1 << 21) +# define CF9GR (1 << 20) +# define CWORWRE (1 << 18) +#define FUNC_DIS 0x34 +# define SIO_DMA2_DIS (1 << 0) +# define PWM1_DIS (1 << 1) +# define PWM2_DIS (1 << 2) +# define HSUART1_DIS (1 << 3) +# define HSUART2_DIS (1 << 4) +# define SPI_DIS (1 << 5) +# define MMC45_DIS (1 << 8) +# define EMMC_DIS (1 << 8) +# define SDIO_DIS (1 << 9) +# define SD_DIS (1 << 10) +# define MIPI_DIS (1 << 11) +# define HDA_DIS (1 << 12) +# define LPE_DIS (1 << 13) +# define OTG_DIS (1 << 14) +# define XHCI_DIS (1 << 15) +# define SATA_DIS (1 << 17) +# define EHCI_DIS (1 << 18) +# define TXE_DIS (1 << 19) +# define PCIE_PORT1_DIS (1 << 20) +# define PCIE_PORT2_DIS (1 << 21) +# define PCIE_PORT3_DIS (1 << 22) +# define PCIE_PORT4_DIS (1 << 23) +# define SIO_DMA1_DIS (1 << 24) +# define I2C1_DIS (1 << 25) +# define I2C2_DIS (1 << 26) +# define I2C3_DIS (1 << 27) +# define I2C4_DIS (1 << 28) +# define I2C5_DIS (1 << 29) +# define I2C6_DIS (1 << 30) +# define I2C7_DIS (1 << 31) +#define FUNC_DIS2 0x38 +# define USH_SS_PHY_DIS (1 << 2) +# define OTG_SS_PHY_DIS (1 << 1) +# define SMBUS_DIS (1 << 0) +#define GPIO_ROUT 0x58 +# define ROUTE_MASK 3 +# define ROUTE_NONE 0 +# define ROUTE_SMI 1 +# define ROUTE_SCI 2 +#define PLT_CLK_CTL_0 0x60 +#define PLT_CLK_CTL_1 0x64 +#define PLT_CLK_CTL_2 0x68 +#define PLT_CLK_CTL_3 0x6c +#define PLT_CLK_CTL_4 0x70 +#define PLT_CLK_CTL_5 0x74 +# define CLK_FREQ_25MHZ (0x0 << 2) +# define CLK_FREQ_19P2MHZ (0x1 << 2) +# define CLK_CTL_D3_LPE (0x0 << 0) +# define CLK_CTL_ON (0x1 << 0) +# define CLK_CTL_OFF (0x2 << 0) +#define PME_STS 0xc0 +#define GPE_LEVEL_EDGE 0xc4 +# define GPE_EDGE 0 +# define GPE_LEVEL 1 +#define GPE_POLARITY 0xc8 +# define GPE_ACTIVE_HIGH 1 +# define GPE_ACTIVE_LOW 0 +#define LOCK 0xcc + +/* IO Mapped registers behind ACPI_BASE_ADDRESS */ +#define PM1_STS 0x00 +#define WAK_STS (1 << 15) +#define PCIEXPWAK_STS (1 << 14) +#define USB_STS (1 << 13) +#define PRBTNOR_STS (1 << 11) +#define RTC_STS (1 << 10) +#define PWRBTN_STS (1 << 8) +#define GBL_STS (1 << 5) +#define TMROF_STS (1 << 0) +#define PM1_EN 0x02 +#define PCIEXPWAK_DIS (1 << 14) +#define USB_WAKE_EN (1 << 13) +#define RTC_EN (1 << 10) +#define PWRBTN_EN (1 << 8) +#define GBL_EN (1 << 5) +#define TMROF_EN (1 << 0) +#define PM1_CNT 0x04 +#define SLP_EN (1 << 13) +#define SLP_TYP_SHIFT 10 +#define SLP_TYP (7 << SLP_TYP_SHIFT) +#define SLP_TYP_S0 0 +#define SLP_TYP_S1 1 +#define SLP_TYP_S3 5 +#define SLP_TYP_S4 6 +#define SLP_TYP_S5 7 +#define GBL_RLS (1 << 2) +#define BM_RLD (1 << 1) +#define SCI_EN (1 << 0) +#define PM1_TMR 0x08 +#define GPE0_STS 0x20 +#define CORE_GPIO_STS7 (1 << 31) +#define CORE_GPIO_STS6 (1 << 30) +#define CORE_GPIO_STS5 (1 << 29) +#define CORE_GPIO_STS4 (1 << 28) +#define CORE_GPIO_STS3 (1 << 27) +#define CORE_GPIO_STS2 (1 << 26) +#define CORE_GPIO_STS1 (1 << 25) +#define CORE_GPIO_STS0 (1 << 24) +#define SUS_GPIO_STS7 (1 << 23) +#define SUS_GPIO_STS6 (1 << 22) +#define SUS_GPIO_STS5 (1 << 21) +#define SUS_GPIO_STS4 (1 << 20) +#define SUS_GPIO_STS3 (1 << 19) +#define SUS_GPIO_STS2 (1 << 18) +#define SUS_GPIO_STS1 (1 << 17) +#define SUS_GPIO_STS0 (1 << 16) +#define PME_B0_STS_BIT 13 +#define PME_B0_STS (1 << PME_B0_STS_BIT) +#define BATLOW_STS (1 << 10) +#define PCI_EXP_STS (1 << 9) +#define PCIE_WAKE3_STS (1 << 8) +#define PCIE_WAKE2_STS (1 << 7) +#define PCIE_WAKE1_STS (1 << 6) +#define GUNIT_SCI_STS (1 << 5) +#define PUNIT_SCI_STS (1 << 4) +#define PCIE_WAKE0_STS (1 << 3) +#define SWGPE_STS (1 << 2) +#define HOT_PLUG_STS (1 << 1) +#define GPE0_EN 0x28 +#define CORE_GPIO_EN7 (1 << 31) +#define CORE_GPIO_EN6 (1 << 30) +#define CORE_GPIO_EN5 (1 << 29) +#define CORE_GPIO_EN4 (1 << 28) +#define CORE_GPIO_EN3 (1 << 27) +#define CORE_GPIO_EN2 (1 << 26) +#define CORE_GPIO_EN1 (1 << 25) +#define CORE_GPIO_EN0 (1 << 24) +#define SUS_GPIO_EN7_BIT 23 +#define SUS_GPIO_EN7 (1 << SUS_GPIO_EN7_BIT) +#define SUS_GPIO_EN6_BIT 22 +#define SUS_GPIO_EN6 (1 << SUS_GPIO_EN6_BIT) +#define SUS_GPIO_EN5_BIT 21 +#define SUS_GPIO_EN5 (1 << SUS_GPIO_EN5_BIT) +#define SUS_GPIO_EN4_BIT 20 +#define SUS_GPIO_EN4 (1 << SUS_GPIO_EN4_BIT) +#define SUS_GPIO_EN3_BIT 19 +#define SUS_GPIO_EN3 (1 << SUS_GPIO_EN3_BIT) +#define SUS_GPIO_EN2_BIT 18 +#define SUS_GPIO_EN2 (1 << SUS_GPIO_EN2_BIT) +#define SUS_GPIO_EN1_BIT 17 +#define SUS_GPIO_EN1 (1 << SUS_GPIO_EN1_BIT) +#define SUS_GPIO_EN0_BIT 16 +#define SUS_GPIO_EN0 (1 << SUS_GPIO_EN0_BIT) +#define PME_B0_EN (1 << 13) +#define BATLOW_EN (1 << 10) +#define PCI_EXP_EN (1 << 9) +#define PCIE_WAKE3_EN (1 << 8) +#define PCIE_WAKE2_EN (1 << 7) +#define PCIE_WAKE1_EN (1 << 6) +#define PCIE_WAKE0_EN (1 << 3) +#define SWGPE_EN (1 << 2) +#define HOT_PLUG_EN (1 << 1) +#define _ACPI_ENABLE_WAKE_SUS_GPIO(x) SUS_GPIO_EN##x##_BIT +#define ACPI_ENABLE_WAKE_SUS_GPIO(x) _ACPI_ENABLE_WAKE_SUS_GPIO(x) +#define SMI_EN 0x30 +#define INTEL_USB2_EN (1 << 18) // Intel-Specific USB2 SMI logic +#define USB_EN (1 << 17) // Legacy USB2 SMI logic +#define PERIODIC_EN (1 << 14) // SMI on PERIODIC_STS in SMI_STS +#define TCO_EN (1 << 13) // Enable TCO Logic (BIOSWE et al) +#define BIOS_RLS (1 << 7) // asserts SCI on bit set +#define SWSMI_TMR_EN (1 << 6) // start software smi timer on bit set +#define APMC_EN (1 << 5) // Writes to APM_CNT cause SMI# +#define SLP_SMI_EN (1 << 4) // Write to SLP_EN in PM1_CNT asserts SMI# +#define BIOS_EN (1 << 2) // Assert SMI# on setting GBL_RLS bit +#define EOS (1 << 1) // End of SMI (deassert SMI#) +#define GBL_SMI_EN (1 << 0) // SMI# generation at all? +#define SMI_STS 0x34 +#define ALT_GPIO_SMI 0x38 +#define UPRWC 0x3c +# define UPRWC_WR_EN (1 << 1) // USB Per-Port Registers Write Enable +#define GPE_CTRL 0x40 +#define PM2A_CNT_BLK 0x50 +#define TCO_RLD 0x60 +#define TCO_STS 0x64 +# define SECOND_TO_STS (1 << 17) +# define TCO_TIMEOUT (1 << 3) +#define TCO1_CNT 0x68 +# define TCO_LOCK (1 << 12) +# define TCO_TMR_HALT (1 << 11) +#define TCO_TMR 0x70 + +/* I/O ports */ +#define RST_CNT 0xcf9 +# define FULL_RST (1 << 3) +# define RST_CPU (1 << 2) +# define SYS_RST (1 << 1) + +#if !defined(__ASSEMBLER__) && !defined(__ACPI__) + +/* Track power state from reset to log events. */ +struct chipset_power_state { + uint16_t pm1_sts; + uint16_t pm1_en; + uint32_t pm1_cnt; + uint32_t gpe0_sts; + uint32_t gpe0_en; + uint32_t tco_sts; + uint32_t prsts; + uint32_t gen_pmcon1; + uint32_t gen_pmcon2; +} __attribute__((packed)); + +/* Power Management Utility Functions. */ +uint16_t get_pmbase(void); +uint32_t clear_smi_status(void); +uint16_t clear_pm1_status(void); +uint32_t clear_tco_status(void); +uint32_t clear_gpe_status(void); +uint32_t clear_alt_status(void); +void clear_pmc_status(void); +void enable_smi(uint32_t mask); +void disable_smi(uint32_t mask); +void enable_pm1(uint16_t events); +void enable_pm1_control(uint32_t mask); +void disable_pm1_control(uint32_t mask); +void enable_gpe(uint32_t mask); +void disable_gpe(uint32_t mask); +void disable_all_gpe(void); + +#if IS_ENABLED(CONFIG_ELOG) +void southcluster_log_state(void); +#else +static inline void southcluster_log_state(void) {} +#endif + +#endif /* !defined(__ASSEMBLER__) && !defined(__ACPI__) */ + +#endif /* _BAYTRAIL_PMC_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/ramstage.h b/src/soc/intel/fsp_baytrail/baytrail/ramstage.h new file mode 100644 index 0000000..095f09c --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/ramstage.h @@ -0,0 +1,35 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 _BAYTRAIL_RAMSTAGE_H_ +#define _BAYTRAIL_RAMSTAGE_H_ + +#include <device/device.h> + +/* The baytrail_init_pre_device() function is called prior to device + * initialization, but it's after console and cbmem has been reinitialized. */ +void baytrail_init_pre_device(void); +void baytrail_init_cpus(device_t dev); +void set_max_freq(void); +void southcluster_enable_dev(device_t dev); +void scc_enable_acpi_mode(device_t dev, int iosf_reg, int nvs_index); + +extern struct pci_operations soc_pci_ops; + +#endif /* _BAYTRAIL_RAMSTAGE_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/reset.h b/src/soc/intel/fsp_baytrail/baytrail/reset.h new file mode 100644 index 0000000..dbf0fd2 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/reset.h @@ -0,0 +1,36 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 _BAYTRAIL_RESET_H_ +#define _BAYTRAIL_RESET_H_ +#include <reset.h> + +/* Bay Trail has the following types of resets: + * - Soft reset (INIT# to cpu) - write 0x1 to I/O 0x92 + * - Soft reset (INIT# to cpu)- write 0x4 to I/0 0xcf9 + * - Cold reset (S0->S5->S0) - write 0xe to I/0 0xcf9 + * - Warm reset (PMC_PLTRST# assertion) - write 0x6 to I/O 0xcf9 + * - Global reset (S0->S5->S0 with TXE reset) - write 0x6 or 0xe to 0xcf9 but + * with ETR[20] set. + */ + +void cold_reset(void); +void warm_reset(void); + +#endif /* _BAYTRAIL_RESET_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/romstage.h b/src/soc/intel/fsp_baytrail/baytrail/romstage.h new file mode 100644 index 0000000..8feab8a --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/romstage.h @@ -0,0 +1,52 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2014 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 _BAYTRAIL_ROMSTAGE_H_ +#define _BAYTRAIL_ROMSTAGE_H_ + +#if !defined(__PRE_RAM__) +#error "Don't include romstage.h from a ramstage compilation unit!" +#endif + +void report_platform_info(void); + +#include <stdint.h> +#include <arch/cpu.h> + +#include <fsptypes.h> + +void romstage_main_continue(EFI_STATUS status, void *hob_list_ptr); + +#define NUM_ROMSTAGE_TS 4 + +void tco_disable(void); +void punit_init(void); +void set_max_freq(void); +void early_mainboard_romstage_entry(void); +void late_mainboard_romstage_entry(void); +void get_func_disables(uint32_t *mask, uint32_t *mask2); + +#if IS_ENABLED(CONFIG_ENABLE_BUILTIN_COM1) +void byt_config_com1_and_enable(void); +#else +static inline void byt_config_com1_and_enable(void) { } +#endif + +#endif /* _BAYTRAIL_ROMSTAGE_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/smm.h b/src/soc/intel/fsp_baytrail/baytrail/smm.h new file mode 100644 index 0000000..0208c9f --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/smm.h @@ -0,0 +1,48 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2014 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 _BAYTRAIL_SMM_H_ +#define _BAYTRAIL_SMM_H_ + +/* There is a bug in the order of Kconfig includes in that arch/x86/Kconfig + * is included after chipset code. This causes the chipset's Kconfig to be + * clobbered by the arch/x86/Kconfig if they have the same name. */ +static inline int smm_region_size(void) +{ +#ifndef CONFIG_SMM_TSEG_SIZE +#error CONFIG_SMM_TSEG_SIZE must be set. +#endif + + /* Make it 8MiB by default. */ + if (CONFIG_SMM_TSEG_SIZE == 0) + return (8 << 20); + return CONFIG_SMM_TSEG_SIZE; +} + +void *smm_region_start(void); + +#if !defined(__PRE_RAM__) && !defined(__SMM___) +#include <stdint.h> +void southcluster_smm_clear_state(void); +void southcluster_smm_enable_smi(void); +void southcluster_smm_save_gpio_route(uint32_t route); +#endif + +#endif /* _BAYTRAIL_SMM_H_ */ diff --git a/src/soc/intel/fsp_baytrail/baytrail/spi.h b/src/soc/intel/fsp_baytrail/baytrail/spi.h new file mode 100644 index 0000000..ee1648a --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/spi.h @@ -0,0 +1,68 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 _BAYTRAIL_SPI_H_ +#define _BAYTRAIL_SPI_H_ + +#include <stdint.h> + +/* These registers live behind SPI_BASE_ADDRESS. */ +#define HSFSTS 0x04 +# define FLOCKDN (0x1 << 15) +#define PREOP 0x94 +#define OPTYPE 0x96 +#define OPMENU0 0x98 +#define OPMENU1 0x9c +#define LVSCC 0xc4 +# define VCL (0x1 << 23) +# define EO(x) (((x) & 0xff) << 8) +# define WG_1_BYTE (0x0 << 2) +# define WG_64_BYTE (0x1 << 2) +# define BES_256_BYTE (0x0 << 0) +# define BES_4_KB (0x1 << 0) +# define BES_8_KB (0x2 << 0) +# define BES_64_KB (0x3 << 0) +#define UVSCC 0xc8 +#define SCS 0xf8 +# define SMIWPEN (0x1 << 7) +#define BCR 0xfc +# define EISS (0x1 << 5) +# define SRC_MASK (0x3 << 2) +# define SRC_CACHE_NO_PREFETCH (0x0 << 2) +# define SRC_NO_CACHE_NO_PREFETCH (0x1 << 2) +# define SRC_CACHE_PREFETCH (0x2 << 2) +# define BCR_LE (0x1 << 1) +# define BCR_WPD (0x1 << 0) + +/* + * SPI lockdown configuration. + */ +struct spi_config { + uint16_t preop; + uint16_t optype; + uint32_t opmenu[2]; + uint32_t lvscc; + uint32_t uvscc; +}; + +/* Return 0 on success < 0 on failure. */ +int mainboard_get_spi_config(struct spi_config *cfg); + +#endif /* _BAYTRAIL_SPI_H_ */ + diff --git a/src/soc/intel/fsp_baytrail/baytrail/xhci.h b/src/soc/intel/fsp_baytrail/baytrail/xhci.h new file mode 100644 index 0000000..b317361 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/baytrail/xhci.h @@ -0,0 +1,56 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 BAYTRAIL_XHCI_H +#define BAYTRAIL_XHCI_H + +/* XHCI PCI Registers */ +#define XHCI_PWR_CTL_STS 0x74 +#define XHCI_USB2PR 0xd0 +#define XHCI_USB2PRM 0xd4 +#define XHCI_USB3PR 0xd8 +#define XHCI_USB3PRM 0xdc +#define XHCI_USB2PDO 0xe4 +#define XHCI_USB3PDO 0xe8 + +/* XHCI Memory Registers */ +#define XHCI_USB3_PORTSC(port) (0x4e0 + (port * 0x10)) +# define XHCI_USB3_PORTSC_CHST (0x7f << 17) +# define XHCI_USB3_PORTSC_WCE (1 << 25) /* Wake on Connect */ +# define XHCI_USB3_PORTSC_WDE (1 << 26) /* Wake on Disconnect */ +# define XHCI_USB3_PORTSC_WOE (1 << 27) /* Wake on Overcurrent */ +# define XHCI_USB3_PORTSC_WRC (1 << 19) /* Warm Reset Complete */ +# define XHCI_USB3_PORTSC_LWS (1 << 16) /* Link Write Strobe */ +# define XHCI_USB3_PORTSC_PED (1 << 1) /* Port Enabled/Disabled */ +# define XHCI_USB3_PORTSC_WPR (1 << 31) /* Warm Port Reset */ +# define XHCI_USB3_PORTSC_PLS (0xf << 5) /* Port Link State */ +# define XHCI_PLSR_DISABLED (4 << 5) /* Port is disabled */ +# define XHCI_PLSR_RXDETECT (5 << 5) /* Port is disconnected */ +# define XHCI_PLSR_POLLING (7 << 5) /* Port is polling */ +# define XHCI_PLSW_ENABLE (5 << 5) /* Enable port */ + +/* The Fuse register is incorrect for Baytrail-M so use hardcoded values */ +#define BYTM_USB2_PORT_COUNT 4 +#define BYTM_USB2_PORT_MAP 0xf +#define BYTM_USB3_PORT_COUNT 1 +#define BYTM_USB3_PORT_MAP 0x1 + +#define XHCI_RESET_TIMEOUT 100000 /* 100ms */ + +#endif /* BAYTRAIL_XHCI_H */ diff --git a/src/soc/intel/fsp_baytrail/bootblock/bootblock.c b/src/soc/intel/fsp_baytrail/bootblock/bootblock.c new file mode 100644 index 0000000..1623f04 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/bootblock/bootblock.c @@ -0,0 +1,112 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google, Inc. + * Copyright (C) 2013-2014 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 <arch/io.h> +#include <cpu/x86/cache.h> +#include <cpu/x86/msr.h> +#include <cpu/x86/mtrr.h> +#include <baytrail/iosf.h> +#include <baytrail/pci_devs.h> +#include <baytrail/spi.h> +#include <baytrail/iomap.h> +#include <baytrail/lpc.h> +#include <reset.h> + +/* + * check for a warm reset and do a hard reset instead. + */ +static void check_for_warm_reset(void) +{ + + /* + * Check if INIT# is asserted by port 0xCF9 and whether RCBA has been set. + * If either is true, then this is a warm reset so execute a Hard Reset + */ + if ( (inb(0xcf9) == 0x04) || + (pci_io_read_config32(LPC_BDF, RCBA) & RCBA_ENABLE) ) { + outb(0x00, 0xcf9); + outb(0x06, 0xcf9); + } +} + +static void set_var_mtrr(int reg, uint32_t base, uint32_t size, int type) +{ + msr_t basem, maskm; + basem.lo = base | type; + basem.hi = 0; + wrmsr(MTRRphysBase_MSR(reg), basem); + maskm.lo = ~(size - 1) | MTRRphysMaskValid; + maskm.hi = (1 << (CONFIG_CPU_ADDR_BITS - 32)) - 1; + wrmsr(MTRRphysMask_MSR(reg), maskm); +} + +/* + * Enable Prefetching and Caching. + */ +static void enable_spi_prefetch(void) +{ + uint32_t bcr = SPI_BASE_ADDRESS + BCR; + /* Enable caching and prefetching in the SPI controller. */ + write32(bcr, (read32(bcr) & ~SRC_MASK) | SRC_CACHE_PREFETCH); +} + +static void enable_rom_caching(void) +{ + msr_t msr; + + disable_cache(); + set_var_mtrr(1, 0xffffffff - CACHE_ROM_SIZE + 1, + CACHE_ROM_SIZE, MTRR_TYPE_WRPROT); + enable_cache(); + + /* Enable Variable MTRRs */ + msr.hi = 0x00000000; + msr.lo = 0x00000800; + wrmsr(MTRRdefType_MSR, msr); +} + +static void setup_mmconfig(void) +{ + uint32_t reg; + + /* Set up the MMCONF range. The register lives in the BUNIT. The + * IO variant of the config access needs to be used initially to + * properly configure as the IOSF access registers live in PCI + * config space. */ + reg = 0; + /* Clear the extended register. */ + pci_io_write_config32(IOSF_PCI_DEV, MCRX_REG, reg); + reg = CONFIG_MMCONF_BASE_ADDRESS | 1; + pci_io_write_config32(IOSF_PCI_DEV, MDR_REG, reg); + reg = IOSF_OPCODE(IOSF_OP_WRITE_BUNIT) | IOSF_PORT(IOSF_PORT_BUNIT) | + IOSF_REG(BUNIT_MMCONF_REG) | IOSF_BYTE_EN; + pci_io_write_config32(IOSF_PCI_DEV, MCR_REG, reg); +} + +static void bootblock_cpu_init(void) +{ + + check_for_warm_reset(); + + /* Allow memory-mapped PCI config access. */ + setup_mmconfig(); + enable_rom_caching(); + enable_spi_prefetch(); +} diff --git a/src/soc/intel/fsp_baytrail/chip.c b/src/soc/intel/fsp_baytrail/chip.c new file mode 100644 index 0000000..839e8dc --- /dev/null +++ b/src/soc/intel/fsp_baytrail/chip.c @@ -0,0 +1,116 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 <device/device.h> +#include <device/pci.h> +#include <baytrail/pci_devs.h> +#include <baytrail/ramstage.h> +#include <drivers/intel/fsp/fsp_util.h> +#include "chip.h" + +static void pci_domain_set_resources(device_t dev) +{ + assign_resources(dev->link_list); +} + +static void finalize_dev (device_t dev) +{ + /* + * Notify FSP for PostPciEnumeration. + * Northbridge APIC init should be early and late enough... + */ + printk(BIOS_DEBUG, "FspNotify(EnumInitPhaseAfterPciEnumeration)\n"); + FspNotify(EnumInitPhaseAfterPciEnumeration); +} + +static struct device_operations pci_domain_ops = { + .read_resources = pci_domain_read_resources, + .set_resources = pci_domain_set_resources, + .enable_resources = NULL, + .init = NULL, + .final = &finalize_dev, + .scan_bus = pci_domain_scan_bus, + .ops_pci_bus = pci_bus_default_ops, +}; + +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 = baytrail_init_cpus, + .scan_bus = NULL, +}; + +static void enable_dev(device_t dev) +{ + printk(BIOS_DEBUG, "enable_dev(%s, %d)\n", + dev_name(dev), dev->path.type); + + /* 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; + } else if (dev->path.type == DEVICE_PATH_PCI) { + /* Handle south cluster enablement. */ + if (PCI_SLOT(dev->path.pci.devfn) > GFX_DEV && + (dev->ops == NULL || dev->ops->enable == NULL)) { + southcluster_enable_dev(dev); + } + } +} + +static void finalize_chip(void *chip_info) +{ + /* Notify FSP for ReadyToBoot */ + printk(BIOS_DEBUG, "FspNotify(EnumInitPhaseReadyToBoot)\n"); + FspNotify(EnumInitPhaseReadyToBoot); + +} + +/* Called at BS_DEV_INIT_CHIPS time -- very early. Just after BS_PRE_DEVICE. */ +static void soc_init(void *chip_info) +{ + baytrail_init_pre_device(); +} + +struct chip_operations soc_intel_fsp_baytrail_ops = { + CHIP_NAME("Intel BayTrail SoC") + .enable_dev = enable_dev, + .init = soc_init, + .final = &finalize_chip, +}; + +static void pci_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)); + } +} + +struct pci_operations soc_pci_ops = { + .set_subsystem = &pci_set_subsystem, +}; diff --git a/src/soc/intel/fsp_baytrail/chip.h b/src/soc/intel/fsp_baytrail/chip.h new file mode 100644 index 0000000..7e86862 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/chip.h @@ -0,0 +1,183 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2013-2014 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_BAYTRAIL_CHIP_H_ +#define _FSP_BAYTRAIL_CHIP_H_ + +#include <arch/acpi.h> + +/* The devicetree parser expects chip.h to reside directly in the path + * specified by the devicetree. */ + +struct soc_intel_fsp_baytrail_config { + +/* ***** UPD Configuration ***** */ + + /* Spd addresses */ + uint8_t MrcInitSPDAddr1; + uint8_t MrcInitSPDAddr2; + #define SPD_ADDR_DEFAULT 0x00 + #define SPD_ADDR_DISABLED 0xFF + + /* SataMode + * NOTE: These are offset by 1 to set 0 as "use default". This is so that + * if the register value is not set in the devicetree.cb file, the default + * value gets used. This is fixed up in the chipset_fsp_util.c code. + * + * 0x0 "IDE" + * 0x1 "AHCI" + */ + uint8_t SataMode; + #define SATA_MODE_DEFAULT 0x00 + #define SATA_MODE_IDE 0x01 + #define SATA_MODE_AHCI 0x02 + + /* + * MrcInitTsegSize + * 0x01, "1 MB" + * 0x02, "2 MB" + * 0x04, "4 MB" + * 0x08, "8 MB" + */ + uint16_t MrcInitTsegSize; + #define TSEG_SIZE_DEFAULT 0 + #define TSEG_SIZE_1_MB 1 + #define TSEG_SIZE_2_MB 2 + #define TSEG_SIZE_4_MB 4 + #define TSEG_SIZE_8_MB 8 + + /* + * MrcInitMmioSize + * 0x400, "1.0 GB"s + * 0x600, "1.5 GB" + * 0x800, "2.0 GB" + */ + uint16_t MrcInitMmioSize; + #define MMIO_SIZE_DEFAULT 0x00 + #define MMIO_SIZE_1_0_GB 0x400 + #define MMIO_SIZE_1_5_GB 0x600 + #define MMIO_SIZE_2_0_GB 0x800 + + /* + * eMMCBootMode + * NOTE: These are offset by 1 to set 0 as "use default". This is so that + * if the register value is not set in the devicetree.cb file, the default + * value gets used. This is fixed up in the chipset_fsp_util.c code + * + * 0x0 "Disabled" + * 0x1 "Auto" + * 0x2 "eMMC 4.1" + * 0x3 "eMMC 4.5" + */ + uint8_t eMMCBootMode; + #define EMMC_USE_DEFAULT 0 + #define EMMC_DISABLED 1 + #define EMMC_AUTO 2 + #define EMMC_4_1 3 + #define EMMC_4_5 4 + #define EMMC_FOLLOWS_DEVICETREE 5 + + /* + * IgdDvmt50PreAlloc + * 0x01, "32 MB" + * 0x02, "64 MB" + * 0x03, "96 MB" + * 0x04, "128 MB" + * 0x05, "160 MB" + * 0x06, "192 MB" + * 0x07, "224 MB" + * 0x08, "256 MB" + * 0x09, "288 MB" + * 0x0A, "320 MB" + * 0x0B, "352 MB" + * 0x0C, "384 MB" + * 0x0D, "416 MB" + * 0x0E, "448 MB" + * 0x0F, "480 MB" + * 0x10, "512 MB" + */ + uint8_t IgdDvmt50PreAlloc; + #define IGD_MEMSIZE_DEFAULT 0x00 + #define IGD_MEMSIZE_32MB 0x01 + #define IGD_MEMSIZE_64MB 0x02 + #define IGD_MEMSIZE_96MB 0x03 + #define IGD_MEMSIZE_128MB 0x04 + #define IGD_MEMSIZE_160MB 0x05 + #define IGD_MEMSIZE_192MB 0x06 + #define IGD_MEMSIZE_224MB 0x07 + #define IGD_MEMSIZE_256MB 0x08 + #define IGD_MEMSIZE_288MB 0x09 + #define IGD_MEMSIZE_320MB 0x0A + #define IGD_MEMSIZE_352MB 0x0B + #define IGD_MEMSIZE_384MB 0x0C + #define IGD_MEMSIZE_416MB 0x0D + #define IGD_MEMSIZE_448MB 0x0E + #define IGD_MEMSIZE_480MB 0x0F + #define IGD_MEMSIZE_512MB 0x10 + #define IGD_MEMSIZE_MULTIPLIER 32 + + /* + * Selection 0x1 , "128 MB" + * Selection 0x2 , "256 MB" + * Selection 0x3 , "512 MB" + */ + uint8_t ApertureSize; + #define APERTURE_SIZE_DEFAULT 0 + #define APERTURE_SIZE_128MB 1 + #define APERTURE_SIZE_256MB 2 + #define APERTURE_SIZE_512MB 3 + #define APERTURE_SIZE_BASE 64 + + /* + * Selection 0x1 , "1 MB" + * Selection 0x2 , "2 MB" + */ + uint8_t GttSize; + #define GTT_SIZE_DEFAULT 0 + #define GTT_SIZE_1MB 1 + #define GTT_SIZE_2MB 2 + + /* + * Enable PCI Mode for LPSS SIO devices. + * If disabled, LPSS SIO devices will run in ACPI mode. + */ + uint8_t LpssSioEnablePciMode; + #define LPSS_PCI_MODE_DEFAULT 0x00 + #define LPSS_PCI_MODE_DISABLE 0x01 + #define LPSS_PCI_MODE_ENABLE 0x02 + + /* modifiers for various enables */ + uint8_t AzaliaAutoEnable; + #define AZALIA_FOLLOWS_DEVICETREE 0 + #define AZALIA_FSP_AUTO_ENABLE 1 + + uint8_t LpeAcpiModeEnable; + #define LPE_ACPI_MODE_DISABLED 1 + #define LPE_ACPI_MODE_ENABLED 2 + +/* ***** ACPI configuration ***** */ + /* Options for these are in src/arch/x86/include/arch/acpi.h */ + uint8_t fadt_pm_profile; + uint16_t fadt_boot_arch; + +}; + +extern struct chip_operations soc_intel_fsp_baytrail_ops; +#endif /* _FSP_BAYTRAIL_CHIP_H_ */ diff --git a/src/soc/intel/fsp_baytrail/cpu.c b/src/soc/intel/fsp_baytrail/cpu.c new file mode 100644 index 0000000..f260880 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/cpu.c @@ -0,0 +1,278 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2014 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 <stdlib.h> +#include <console/console.h> +#include <cpu/cpu.h> +#include <cpu/intel/microcode.h> +#include <cpu/intel/turbo.h> +#include <cpu/x86/cache.h> +#include <cpu/x86/lapic.h> +#include <cpu/x86/mp.h> +#include <cpu/x86/msr.h> +#include <cpu/x86/mtrr.h> +#include <cpu/x86/smm.h> +#include <reg_script.h> + +#include <baytrail/msr.h> +#include <baytrail/pattrs.h> +#include <baytrail/ramstage.h> +#if IS_ENABLED(CONFIG_HAVE_SMI_HANDLER) +#include <baytrail/smm.h> + +static void smm_relocate(void *unused); +static void enable_smis(void *unused); + +static struct mp_flight_record mp_steps[] = { + MP_FR_BLOCK_APS(smm_relocate, NULL, smm_relocate, NULL), + MP_FR_BLOCK_APS(mp_initialize_cpu, NULL, mp_initialize_cpu, NULL), + /* Wait for APs to finish initialization before proceeding. */ + MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL), +}; +#else /* CONFIG_HAVE_SMI_HANDLER */ +static struct mp_flight_record mp_steps[] = { + MP_FR_BLOCK_APS(mp_initialize_cpu, NULL, mp_initialize_cpu, NULL), +}; +#endif + +/* The APIC id space on Bay Trail is sparse. Each id is separated by 2. */ +static int adjust_apic_id(int index, int apic_id) +{ + return 2 * index; +} + +/* Core level MSRs */ +const struct reg_script core_msr_script[] = { + /* Dynamic L2 shrink enable and threshold */ + REG_MSR_RMW(MSR_PMG_CST_CONFIG_CONTROL, ~0x3f000f, 0xe0008), + /* Disable C1E */ + REG_MSR_RMW(MSR_POWER_CTL, ~0x2, 0), + REG_MSR_OR(MSR_POWER_MISC, 0x44), + REG_SCRIPT_END +}; + +void baytrail_init_cpus(device_t dev) +{ + struct bus *cpu_bus = dev->link_list; + const struct pattrs *pattrs = pattrs_get(); + struct mp_params mp_params; + + x86_mtrr_check(); + + /* Enable the local cpu apics */ + setup_lapic(); + + mp_params.num_cpus = pattrs->num_cpus, + mp_params.parallel_microcode_load = 0, + mp_params.adjust_apic_id = adjust_apic_id; + mp_params.flight_plan = &mp_steps[0]; + mp_params.num_records = ARRAY_SIZE(mp_steps); + mp_params.microcode_pointer = 0; + + if (mp_init(cpu_bus, &mp_params)) { + printk(BIOS_ERR, "MP initialization failure.\n"); + } +} + +static void baytrail_core_init(device_t cpu) +{ + printk(BIOS_DEBUG, "Init BayTrail core.\n"); + + /* On bay trail the turbo disable bit is actually scoped at building + * block level -- not package. For non-bsp cores that are within a + * building block enable turbo. The cores within the BSP's building + * block will just see it already enabled and move on. */ + if (lapicid()) + enable_turbo(); + + /* Set core MSRs */ + reg_script_run(core_msr_script); + + /* Set this core to max frequency ratio */ + set_max_freq(); +} + +static struct device_operations cpu_dev_ops = { + .init = baytrail_core_init, +}; + +static struct cpu_device_id cpu_table[] = { + { X86_VENDOR_INTEL, 0x30671 }, + { X86_VENDOR_INTEL, 0x30672 }, + { X86_VENDOR_INTEL, 0x30673 }, + { X86_VENDOR_INTEL, 0x30678 }, + { 0, 0 }, +}; + +static const struct cpu_driver driver __cpu_driver = { + .ops = &cpu_dev_ops, + .id_table = cpu_table, +}; + +#if IS_ENABLED(CONFIG_HAVE_SMI_HANDLER) +/* + * SMM loading and initialization. + */ + +struct smm_relocation_attrs { + uint32_t smbase; + uint32_t smrr_base; + uint32_t smrr_mask; +}; + +static struct smm_relocation_attrs relo_attrs; + +static void adjust_apic_id_map(struct smm_loader_params *smm_params) +{ + int i; + struct smm_runtime *runtime = smm_params->runtime; + + for (i = 0; i < CONFIG_MAX_CPUS; i++) + runtime->apic_id_to_cpu[i] = mp_get_apic_id(i); +} + +static void asmlinkage +cpu_smm_do_relocation(void *arg, int cpu, const struct smm_runtime *runtime) +{ +#ifndef CONFIG_MAX_CPUS +#error CONFIG_MAX_CPUS must be set. +#endif + msr_t smrr; + em64t100_smm_state_save_area_t *smm_state; + + if (cpu >= CONFIG_MAX_CPUS) { + printk(BIOS_CRIT, + "Invalid CPU number assigned in SMM stub: %d\n", cpu); + return; + } + + /* Set up SMRR. */ + smrr.lo = relo_attrs.smrr_base; + smrr.hi = 0; + wrmsr(SMRRphysBase_MSR, smrr); + smrr.lo = relo_attrs.smrr_mask; + smrr.hi = 0; + wrmsr(SMRRphysMask_MSR, smrr); + + /* The relocated handler runs with all CPUs concurrently. Therefore + * stagger the entry points adjusting SMBASE downwards by save state + * size * CPU num. */ + smm_state = (void *)(SMM_EM64T100_SAVE_STATE_OFFSET + runtime->smbase); + smm_state->smbase = relo_attrs.smbase - cpu * runtime->save_state_size; + printk(BIOS_DEBUG, "New SMBASE 0x%08x\n", smm_state->smbase); +} + +static int install_relocation_handler(int num_cpus) +{ + const int save_state_size = sizeof(em64t100_smm_state_save_area_t); + + struct smm_loader_params smm_params = { + .per_cpu_stack_size = save_state_size, + .num_concurrent_stacks = num_cpus, + .per_cpu_save_state_size = save_state_size, + .num_concurrent_save_states = 1, + .handler = (smm_handler_t)&cpu_smm_do_relocation, + }; + + if (smm_setup_relocation_handler(&smm_params)) + return -1; + + adjust_apic_id_map(&smm_params); + + return 0; +} + +static int install_permanent_handler(int num_cpus) +{ +#ifndef CONFIG_SMM_RESERVED_SIZE +#error CONFIG_SMM_RESERVED_SIZE must be set. +#endif + /* There are num_cpus concurrent stacks and num_cpus concurrent save + * state areas. Lastly, set the stack size to the save state size. */ + int save_state_size = sizeof(em64t100_smm_state_save_area_t); + struct smm_loader_params smm_params = { + .per_cpu_stack_size = save_state_size, + .num_concurrent_stacks = num_cpus, + .per_cpu_save_state_size = save_state_size, + .num_concurrent_save_states = num_cpus, + }; + const int tseg_size = smm_region_size() - CONFIG_SMM_RESERVED_SIZE; + + printk(BIOS_DEBUG, "Installing SMM handler to 0x%08x\n", + relo_attrs.smbase); + + if (smm_load_module((void *)relo_attrs.smbase, tseg_size, &smm_params)) + return -1; + + adjust_apic_id_map(&smm_params); + + return 0; +} + +static int smm_load_handlers(void) +{ + /* All range registers are aligned to 4KiB */ + const uint32_t rmask = ~((1 << 12) - 1); + const struct pattrs *pattrs = pattrs_get(); + + /* Initialize global tracking state. */ + relo_attrs.smbase = (uint32_t)smm_region_start(); + relo_attrs.smrr_base = relo_attrs.smbase | MTRR_TYPE_WRBACK; + relo_attrs.smrr_mask = ~(smm_region_size() - 1) & rmask; + relo_attrs.smrr_mask |= MTRRphysMaskValid; + + /* Install handlers. */ + if (install_relocation_handler(pattrs->num_cpus) < 0) { + printk(BIOS_ERR, "Unable to install SMM relocation handler.\n"); + return -1; + } + + if (install_permanent_handler(pattrs->num_cpus) < 0) { + printk(BIOS_ERR, "Unable to install SMM permanent handler.\n"); + return -1; + } + + /* Ensure the SMM handlers hit DRAM before performing first SMI. */ + wbinvd(); + + return 0; +} + +static void smm_relocate(void *unused) +{ + + /* Load relocation and permanent handler. */ + if (boot_cpu()) { + if (smm_load_handlers() < 0) { + printk(BIOS_ERR, "Error loading SMM handlers.\n"); + return; + } + southcluster_smm_clear_state(); + } + + /* Relocate SMM space. */ + smm_initiate_relocation(); +} + +static void enable_smis(void *unused) +{ + southcluster_smm_enable_smi(); +} +#endif diff --git a/src/soc/intel/fsp_baytrail/ehci.c b/src/soc/intel/fsp_baytrail/ehci.c new file mode 100644 index 0000000..b9a3f9e --- /dev/null +++ b/src/soc/intel/fsp_baytrail/ehci.c @@ -0,0 +1,180 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2013 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 <arch/acpi.h> +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <stdint.h> +#include <reg_script.h> + +#include <baytrail/iomap.h> +#include <baytrail/iosf.h> +#include <baytrail/pci_devs.h> +#include <baytrail/pmc.h> +#include <baytrail/ramstage.h> +#include <baytrail/ehci.h> + +#include "chip.h" + +static const struct reg_script ehci_init_script[] = { + /* Enable S0 PLL shutdown + * D29:F0:7A[12,10,7,6,4,3,2,1]=11111111b */ + REG_PCI_OR16(0x7a, 0x14de), + /* Enable SB local clock gating + * D29:F0:7C[14,3,2]=111b (14 set in clock gating step) */ + REG_PCI_OR32(0x7c, 0x0000000c), + REG_PCI_OR32(0x8c, 0x00000001), + /* Enable dynamic clock gating 0x4001=0xCE */ + REG_IOSF_RMW(IOSF_PORT_USBPHY, 0x4001, 0xFFFFFF00, 0xCE), + /* Magic RCBA register set sequence */ + /* RCBA + 0x200=0x1 */ + REG_MMIO_WRITE32(RCBA_BASE_ADDRESS + 0x200, 0x00000001), + /* RCBA + 0x204=0x2 */ + REG_MMIO_WRITE32(RCBA_BASE_ADDRESS + 0x204, 0x00000002), + /* RCBA + 0x208=0x0 */ + REG_MMIO_WRITE32(RCBA_BASE_ADDRESS + 0x208, 0x00000000), + /* RCBA + 0x240[4,3,2,1,0]=00000b */ + REG_MMIO_RMW32(RCBA_BASE_ADDRESS + 0x240, ~0x0000001f, 0), + /* RCBA + 0x318[9,8,6,5,4,3,2,1,0]=000000111b */ + REG_MMIO_RMW32(RCBA_BASE_ADDRESS + 0x318, ~0x00000378, 0x00000007), + /* RCBA + 0x31c[3,2,1,0]=0011b */ + REG_MMIO_RMW32(RCBA_BASE_ADDRESS + 0x31c, ~0x0000000c, 0x00000003), + REG_SCRIPT_END +}; + +static const struct reg_script ehci_clock_gating_script[] = { + /* Enable SB local clock gating */ + REG_PCI_OR32(0x7c, 0x00004000), + /* RCBA + 0x284=0xbe (step B0+) */ + REG_MMIO_WRITE32(RCBA_BASE_ADDRESS + 0x284, 0x000000be), + REG_SCRIPT_END +}; + +static const struct reg_script ehci_disable_script[] = { + /* Clear Run/Stop Bit */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, USB2CMD, ~USB2CMD_RS, 0), + /* Wait for HC Halted */ + REG_RES_POLL32(PCI_BASE_ADDRESS_0, USB2STS, + USB2STS_HCHALT, USB2STS_HCHALT, 10000), + /* Disable Interrupts */ + REG_PCI_OR32(EHCI_CMD_STS, INTRDIS), + /* Disable Asynchronous and Periodic Scheduler */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, USB2CMD, + ~(USB2CMD_ASE | USB2CMD_PSE), 0), + /* Disable port wake */ + REG_PCI_RMW32(EHCI_SBRN_FLA_PWC, ~(PORTWKIMP | PORTWKCAPMASK), 0), + /* Set Function Disable bit in RCBA */ + REG_MMIO_OR32(RCBA_BASE_ADDRESS + RCBA_FUNC_DIS, RCBA_EHCI_DIS), + REG_SCRIPT_END +}; + +static const struct reg_script ehci_hc_reset[] = { + REG_RES_OR16(PCI_BASE_ADDRESS_0, USB2CMD, USB2CMD_HCRESET), + REG_SCRIPT_END +}; + +static void usb2_phy_init(device_t dev) +{ + struct soc_intel_fsp_baytrail_config *config = dev->chip_info; + struct reg_script usb2_phy_script[] = { + /* USB3PHYInit() */ + REG_IOSF_WRITE(IOSF_PORT_USBPHY, USBPHY_COMPBG, 0x4700), + /* Per port phy settings, set in devicetree.cb */ + REG_IOSF_WRITE(IOSF_PORT_USBPHY, USBPHY_PER_PORT_LANE0, + config->usb2_per_port_lane0), + REG_IOSF_WRITE(IOSF_PORT_USBPHY, + USBPHY_PER_PORT_RCOMP_HS_PULLUP0, + config->usb2_per_port_rcomp_hs_pullup0), + REG_IOSF_WRITE(IOSF_PORT_USBPHY, USBPHY_PER_PORT_LANE1, + config->usb2_per_port_lane1), + REG_IOSF_WRITE(IOSF_PORT_USBPHY, + USBPHY_PER_PORT_RCOMP_HS_PULLUP1, + config->usb2_per_port_rcomp_hs_pullup1), + REG_IOSF_WRITE(IOSF_PORT_USBPHY, USBPHY_PER_PORT_LANE2, + config->usb2_per_port_lane2), + REG_IOSF_WRITE(IOSF_PORT_USBPHY, + USBPHY_PER_PORT_RCOMP_HS_PULLUP2, + config->usb2_per_port_rcomp_hs_pullup2), + REG_IOSF_WRITE(IOSF_PORT_USBPHY, USBPHY_PER_PORT_LANE3, + config->usb2_per_port_lane3), + REG_IOSF_WRITE(IOSF_PORT_USBPHY, + USBPHY_PER_PORT_RCOMP_HS_PULLUP3, + config->usb2_per_port_rcomp_hs_pullup3), + REG_SCRIPT_END + }; + + if (config->usb2_per_port_lane0) + reg_script_run(usb2_phy_script); +} + +static void ehci_init(device_t dev) +{ + struct soc_intel_fsp_baytrail_config *config = dev->chip_info; + struct reg_script ehci_hc_init[] = { + /* Controller init */ + REG_SCRIPT_NEXT(ehci_init_script), + /* Enable clock gating */ + REG_SCRIPT_NEXT(ehci_clock_gating_script), + /* + * Disable ports if requested + */ + /* Open per-port disable control override */ + REG_IO_RMW16(ACPI_BASE_ADDRESS + UPRWC, ~0, UPRWC_WR_EN), + REG_PCI_WRITE8(EHCI_USB2PDO, config->usb2_port_disable_mask), + /* Close per-port disable control override */ + REG_IO_RMW16(ACPI_BASE_ADDRESS + UPRWC, ~UPRWC_WR_EN, 0), + REG_SCRIPT_END + }; + + /* Don't reset controller in S3 resume path */ + if (acpi_slp_type != 3) + reg_script_run_on_dev(dev, ehci_hc_reset); + + /* Disable controller if ports are routed to XHCI */ + if (config->usb_route_to_xhci) { + /* Disable controller */ + reg_script_run_on_dev(dev, ehci_disable_script); + + /* Hide device with southcluster function */ + dev->enabled = 0; + southcluster_enable_dev(dev); + } else { + /* Initialize EHCI controller */ + reg_script_run_on_dev(dev, ehci_hc_init); + } + + /* Setup USB2 PHY based on board config */ + usb2_phy_init(dev); +} + +static struct device_operations ehci_device_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = ehci_init, + .ops_pci = &soc_pci_ops, +}; + +static const struct pci_driver baytrail_ehci __pci_driver = { + .ops = &ehci_device_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = EHCI_DEVID +}; diff --git a/src/soc/intel/fsp_baytrail/fsp/Kconfig b/src/soc/intel/fsp_baytrail/fsp/Kconfig new file mode 100644 index 0000000..5df6374 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/fsp/Kconfig @@ -0,0 +1,31 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2014 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 BAYTRAIL_FSP_SPECIFIC_OPTIONS + def_bool y + select PLATFORM_USES_FSP + select USE_GENERIC_FSP_CAR_INC + select FSP_USES_UPD + +config FSP_FILE + string + default "../intel/fsp/baytrail/FvFsp.bin" + help + The path and filename of the Intel FSP binary for this platform. + diff --git a/src/soc/intel/fsp_baytrail/fsp/Makefile.inc b/src/soc/intel/fsp_baytrail/fsp/Makefile.inc new file mode 100644 index 0000000..ebdc80a --- /dev/null +++ b/src/soc/intel/fsp_baytrail/fsp/Makefile.inc @@ -0,0 +1,22 @@ +# +# This file is part of the coreboot project. +# +# Copyright (C) 2014 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 += chipset_fsp_util.c +romstage-y += chipset_fsp_util.c + diff --git a/src/soc/intel/fsp_baytrail/fsp/chipset_fsp_util.c b/src/soc/intel/fsp_baytrail/fsp/chipset_fsp_util.c new file mode 100644 index 0000000..87fe5ae --- /dev/null +++ b/src/soc/intel/fsp_baytrail/fsp/chipset_fsp_util.c @@ -0,0 +1,335 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013-2014 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 <bootstate.h> +#include <cbmem.h> +#include <device/device.h> +#include <device/pci_def.h> +#include <baytrail/pci_devs.h> +#include <drivers/intel/fsp/fsp_util.h> +#include "../chip.h" +#include <baytrail/reset.h> + +#ifdef __PRE_RAM__ +#include <baytrail/romstage.h> +#endif + +#ifdef __PRE_RAM__ + +/* Copy the default UPD region and settings to a buffer for modification */ +static void GetUpdDefaultFromFsp (FSP_INFO_HEADER *FspInfo, UPD_DATA_REGION *UpdData) +{ + VPD_DATA_REGION *VpdDataRgnPtr; + UPD_DATA_REGION *UpdDataRgnPtr; + VpdDataRgnPtr = (VPD_DATA_REGION *)(UINT32)(FspInfo->CfgRegionOffset + FspInfo->ImageBase); + UpdDataRgnPtr = (UPD_DATA_REGION *)(UINT32)(VpdDataRgnPtr->PcdUpdRegionOffset + FspInfo->ImageBase); + memcpy((void*)UpdData, (void*)UpdDataRgnPtr, sizeof(UPD_DATA_REGION)); +} + +/* default to just enabling HDMI audio */ +const PCH_AZALIA_CONFIG mAzaliaConfig = { + .Pme = 1, + .DS = 1, + .DA = 0, + .HdmiCodec = 1, + .AzaliaVCi = 1, + .Rsvdbits = 0, + .AzaliaVerbTableNum = 0, + .AzaliaVerbTable = NULL, + .ResetWaitTimer = 300 +}; + +typedef struct soc_intel_fsp_baytrail_config config_t; + +/** + * Update the UPD data based on values from devicetree.cb + * + * @param UpdData Pointer to the UPD Data structure + */ +static void ConfigureDefaultUpdData(UPD_DATA_REGION *UpdData) +{ + ROMSTAGE_CONST struct device *dev; + ROMSTAGE_CONST config_t *config; + printk(BIOS_DEBUG, "Configure Default UPD Data\n"); + + dev = dev_find_slot(0, SOC_DEV_FUNC); + config = dev->chip_info; + + /* Set up default verb tables - Just HDMI audio */ + UpdData->AzaliaConfigPtr = (UINT32)&mAzaliaConfig; + + /* Set SPD addresses */ + if (config->MrcInitSPDAddr1 == SPD_ADDR_DISABLED) + UpdData->PcdMrcInitSPDAddr1 = 0x00; + else if (config->MrcInitSPDAddr1 != SPD_ADDR_DEFAULT) + UpdData->PcdMrcInitSPDAddr1 = config->MrcInitSPDAddr1; + printk(BIOS_DEBUG, "SPD Addr1:\t\t0x%02x\n", UpdData->PcdMrcInitSPDAddr1); + + if (config->MrcInitSPDAddr2 == SPD_ADDR_DISABLED) + UpdData->PcdMrcInitSPDAddr2 = 0x00; + else if (config->MrcInitSPDAddr2 != SPD_ADDR_DEFAULT) + UpdData->PcdMrcInitSPDAddr2 = config->MrcInitSPDAddr2; + printk(BIOS_DEBUG, "SPD Addr2:\t\t0x%02x\n", UpdData->PcdMrcInitSPDAddr2); + + if (config->SataMode != SATA_MODE_DEFAULT) + UpdData->PcdSataMode = config->SataMode - SATA_MODE_IDE; + + if ((config->eMMCBootMode != EMMC_USE_DEFAULT) || + (config->eMMCBootMode != EMMC_FOLLOWS_DEVICETREE)) + UpdData->PcdeMMCBootMode = config->eMMCBootMode; + + if (config->LpssSioEnablePciMode != LPSS_PCI_MODE_DEFAULT) + UpdData->PcdLpssSioEnablePciMode = config->LpssSioEnablePciMode - + LPSS_PCI_MODE_DISABLE; + + if (config->MrcInitTsegSize != TSEG_SIZE_DEFAULT) + UpdData->PcdMrcInitTsegSize = config->MrcInitTsegSize; + printk(BIOS_DEBUG, "Tseg Size:\t\t%d MB\n", UpdData->PcdMrcInitTsegSize); + + if (config->MrcInitMmioSize != MMIO_SIZE_DEFAULT) + UpdData->PcdMrcInitMmioSize = config->MrcInitMmioSize; + printk(BIOS_DEBUG, "MMIO Size:\t\t%d MB\n", UpdData->PcdMrcInitMmioSize); + + if (config->IgdDvmt50PreAlloc != IGD_MEMSIZE_DEFAULT) + UpdData->PcdIgdDvmt50PreAlloc = config->IgdDvmt50PreAlloc; + printk(BIOS_DEBUG, "IGD Memory Size:\t%d MB\n", + UpdData->PcdIgdDvmt50PreAlloc * IGD_MEMSIZE_MULTIPLIER); + + if (config->ApertureSize != APERTURE_SIZE_DEFAULT) + UpdData->PcdApertureSize = config->ApertureSize; + printk(BIOS_DEBUG, "Aperture Size:\t\t%d MB\n", + APERTURE_SIZE_BASE << UpdData->PcdApertureSize); + + if (config->GttSize != GTT_SIZE_DEFAULT) + UpdData->PcdGttSize = config->GttSize; + printk(BIOS_DEBUG, "GTT Size:\t\t%d MB\n", UpdData->PcdGttSize); + + /* Advance dev to PCI device 0.0 */ + for (dev = &dev_root; dev; dev = dev_find_next_pci_device(dev)){ + if (dev->path.type != DEVICE_PATH_PCI) + continue; + if (dev->path.pci.devfn == PCI_DEVFN(0x0,0)) + break; + } + + /* + * Loop through all the SOC devices in the devicetree + * enabling and disabling them as requested. + */ + for (; dev; dev = dev->sibling) { + + if (dev->path.type != DEVICE_PATH_PCI) + continue; + + switch (dev->path.pci.devfn) { + case MIPI_DEV_FUNC: /* Camera / Image Signal Processing */ + UpdData->ISPEnable = dev->enabled; + printk(BIOS_DEBUG, "MIPI/ISP:\t\t%s\n", + UpdData->PcdEnableSdio?"Enabled":"Disabled"); + break; + case EMMC_DEV_FUNC: /* EMMC 4.1*/ + if ((dev->enabled) && + (config->eMMCBootMode == EMMC_FOLLOWS_DEVICETREE)) + UpdData->PcdeMMCBootMode = EMMC_4_1 - EMMC_DISABLED; + break; + case SDIO_DEV_FUNC: + UpdData->PcdEnableSdio = dev->enabled; + printk(BIOS_DEBUG, "Sdio:\t\t\t%s\n", + UpdData->PcdEnableSdio?"Enabled":"Disabled"); + break; + case SD_DEV_FUNC: + UpdData->PcdEnableSdcard = dev->enabled; + printk(BIOS_DEBUG, "Sdcard:\t\t\t%s\n", + UpdData->PcdEnableSdcard?"Enabled":"Disabled"); + break; + case SATA_DEV_FUNC: + UpdData->PcdEnableSata = dev->enabled; + printk(BIOS_DEBUG, "Sata:\t\t\t%s\n", + UpdData->PcdEnableSata?"Enabled":"Disabled"); + if (UpdData->PcdEnableSata) + printk(BIOS_DEBUG, "SATA Mode:\t\t%s\n", + UpdData->PcdSataMode?"AHCI":"IDE"); + break; + case XHCI_DEV_FUNC: + UpdData->PcdEnableXhci = dev->enabled; + break; + case LPE_DEV_FUNC: + if (dev->enabled && config->LpeAcpiModeEnable == + LPE_ACPI_MODE_ENABLED) + UpdData->PcdEnableLpe = LPE_ACPI_MODE_ENABLED; + else + UpdData->PcdEnableLpe = dev->enabled; + printk(BIOS_DEBUG, "Lpe:\t\t\t%s\n", + UpdData->PcdEnableLpe?"Enabled":"Disabled"); + printk(BIOS_DEBUG, "Lpe mode:\t\t%s\n", + UpdData->PcdEnableLpe == LPE_ACPI_MODE_ENABLED? + "ACPI":"PCI"); + break; + case MMC45_DEV_FUNC: /* MMC 4.5*/ + if ((dev->enabled) && + (config->eMMCBootMode == EMMC_FOLLOWS_DEVICETREE)) + UpdData->PcdeMMCBootMode = EMMC_4_5 - EMMC_DISABLED; + break; + case SIO_DMA1_DEV_FUNC: + UpdData->PcdEnableDma0 = dev->enabled; + printk(BIOS_DEBUG, "SIO Dma 0:\t\t%s\n", + UpdData->PcdEnableDma0?"Enabled":"Disabled"); + break; + case I2C1_DEV_FUNC: + UpdData->PcdEnableI2C0 = dev->enabled; + printk(BIOS_DEBUG, "SIO I2C0:\t\t%s\n", + UpdData->PcdEnableI2C0?"Enabled":"Disabled"); + break; + case I2C2_DEV_FUNC: + UpdData->PcdEnableI2C1 = dev->enabled; + printk(BIOS_DEBUG, "SIO I2C1:\t\t%s\n", + UpdData->PcdEnableI2C1?"Enabled":"Disabled"); + break; + case I2C3_DEV_FUNC: + UpdData->PcdEnableI2C2 = dev->enabled; + printk(BIOS_DEBUG, "SIO I2C2:\t\t%s\n", + UpdData->PcdEnableI2C2?"Enabled":"Disabled"); + break; + case I2C4_DEV_FUNC: + UpdData->PcdEnableI2C3 = dev->enabled; + printk(BIOS_DEBUG, "SIO I2C3:\t\t%s\n", + UpdData->PcdEnableI2C3?"Enabled":"Disabled"); + break; + case I2C5_DEV_FUNC: + UpdData->PcdEnableI2C4 = dev->enabled; + printk(BIOS_DEBUG, "SIO I2C4:\t\t%s\n", + UpdData->PcdEnableI2C4?"Enabled":"Disabled"); + break; + case I2C6_DEV_FUNC: + UpdData->PcdEnableI2C5 = dev->enabled; + printk(BIOS_DEBUG, "SIO I2C5:\t\t%s\n", + UpdData->PcdEnableI2C5?"Enabled":"Disabled"); + break; + case I2C7_DEV_FUNC: + UpdData->PcdEnableI2C6 = dev->enabled; + printk(BIOS_DEBUG, "SIO I2C6:\t\t%s\n", + UpdData->PcdEnableI2C6?"Enabled":"Disabled"); + break; + case TXE_DEV_FUNC: /* TXE */ + break; + case HDA_DEV_FUNC: + if (config->AzaliaAutoEnable) { + UpdData->PcdEnableAzalia = 2; + printk(BIOS_DEBUG, "Azalia:\t\t\tAuto\n"); + } else { + UpdData->PcdEnableAzalia = dev->enabled; + printk(BIOS_DEBUG, "Azalia:\t\t\t%s\n", + UpdData->PcdEnableAzalia?"Enabled":"Disabled"); + } + break; + case PCIE_PORT1_DEV_FUNC: + case PCIE_PORT2_DEV_FUNC: + case PCIE_PORT3_DEV_FUNC: + case PCIE_PORT4_DEV_FUNC: + break; + case EHCI_DEV_FUNC: + UpdData->PcdEnableXhci = !(dev->enabled); + break; + case SIO_DMA2_DEV_FUNC: + UpdData->PcdEnableDma1 = dev->enabled; + printk(BIOS_DEBUG, "SIO Dma1:\t\t%s\n", + UpdData->PcdEnableDma1?"Enabled":"Disabled"); + break; + case PWM1_DEV_FUNC: + UpdData->PcdEnablePwm0 = dev->enabled; + printk(BIOS_DEBUG, "Pwm0\t\t\t%s\n", + UpdData->PcdEnablePwm0?"Enabled":"Disabled"); + break; + case PWM2_DEV_FUNC: + UpdData->PcdEnablePwm1 = dev->enabled; + printk(BIOS_DEBUG, "Pwm1:\t\t\t%s\n", + UpdData->PcdEnablePwm1?"Enabled":"Disabled"); + break; + case HSUART1_DEV_FUNC: + UpdData->PcdEnableHsuart0 = dev->enabled; + printk(BIOS_DEBUG, "Hsuart0:\t\t%s\n", + UpdData->PcdEnableHsuart0?"Enabled":"Disabled"); + break; + case HSUART2_DEV_FUNC: + UpdData->PcdEnableHsuart1 = dev->enabled; + printk(BIOS_DEBUG, "Hsuart1:\t\t%s\n", + UpdData->PcdEnableHsuart1?"Enabled":"Disabled"); + break; + case SPI_DEV_FUNC: + UpdData->PcdEnableSpi = dev->enabled; + printk(BIOS_DEBUG, "Spi:\t\t\t%s\n", + UpdData->PcdEnableSpi?"Enabled":"Disabled"); + break; + case LPC_DEV_FUNC: /* LPC */ + break; + case SMBUS_DEV_FUNC: + break; + } + } + + if(UpdData->PcdeMMCBootMode == EMMC_AUTO - EMMC_DISABLED) { + printk(BIOS_DEBUG, "eMMC Mode:\t\tAuto"); + } else { + printk(BIOS_DEBUG, "eMMC 4.1:\t\t%s\n", + UpdData->PcdeMMCBootMode == EMMC_4_1 - EMMC_DISABLED? + "Enabled":"Disabled"); + printk(BIOS_DEBUG, "eMMC 4.5:\t\t%s\n", + UpdData->PcdeMMCBootMode == EMMC_4_5 - EMMC_DISABLED? + "Enabled":"Disabled"); + } + printk(BIOS_DEBUG, "Xhci:\t\t\t%s\n", + UpdData->PcdEnableXhci?"Enabled":"Disabled"); + +} + +/* Set up the Baytrail specific structures for the call into the FSP */ +void chipset_fsp_early_init(FSP_INIT_PARAMS *pFspInitParams, + FSP_INFO_HEADER *fsp_ptr) +{ + FSP_INIT_RT_BUFFER *pFspRtBuffer = pFspInitParams->RtBufferPtr; + + /* Initialize the UPD Data */ + GetUpdDefaultFromFsp (fsp_ptr, pFspRtBuffer->Common.UpdDataRgnPtr); + ConfigureDefaultUpdData(pFspRtBuffer->Common.UpdDataRgnPtr); + pFspInitParams->NvsBufferPtr = NULL; + pFspRtBuffer->Common.BootMode = BOOT_WITH_FULL_CONFIGURATION; + +#if IS_ENABLED(CONFIG_ENABLE_FAST_BOOT) + /* Find the fastboot cache that was saved in the ROM */ + pFspInitParams->NvsBufferPtr = find_and_set_fastboot_cache(); +#endif + + return; +} + +/* The FSP returns here after the fsp_early_init call */ +void ChipsetFspReturnPoint(EFI_STATUS Status, + VOID *HobListPtr) +{ + if (Status == 0xFFFFFFFF) { + warm_reset(); + } + romstage_main_continue(Status, HobListPtr); +} + +#endif /* __PRE_RAM__ */ diff --git a/src/soc/intel/fsp_baytrail/fsp/chipset_fsp_util.h b/src/soc/intel/fsp_baytrail/fsp/chipset_fsp_util.h new file mode 100644 index 0000000..1b60398 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/fsp/chipset_fsp_util.h @@ -0,0 +1,49 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013-2014 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 CHIPSET_FSP_UTIL_H +#define CHIPSET_FSP_UTIL_H + +#include <fsp.h> +#include <fsptypes.h> +#include <fspfv.h> +#include <fspffs.h> +#include <fspapi.h> +#include <fspplatform.h> +#include <fspinfoheader.h> +#include <fsphob.h> +#include <fspvpd.h> +#include <azalia.h> + +#define FSP_RESERVE_MEMORY_SIZE 0x200000 + +#define FSP_INFO_HEADER_GUID \ + { \ + 0x912740BE, 0x2284, 0x4734, {0xB9, 0x71, 0x84, 0xB0, 0x27, 0x35, 0x3F, 0x0C} \ + } + +/* + * The FSP Image ID is different for each platform's FSP and + * can be used to verify that the right FSP binary is loaded. + * For the Bay Trail FSP, the Image Id is "VLYVIEW0". + */ +#define FSP_IMAGE_ID_DWORD0 0x56594C56 /* 'VLYV' */ +#define FSP_IMAGE_ID_DWORD1 0x30574549 /* 'IEW0' */ + +#endif /* CHIPSET_FSP_UTIL_H */ diff --git a/src/soc/intel/fsp_baytrail/gpio.c b/src/soc/intel/fsp_baytrail/gpio.c new file mode 100644 index 0000000..69e9ac6 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/gpio.c @@ -0,0 +1,239 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 <device/pci.h> +#include <console/console.h> +#include <baytrail/gpio.h> +#include <baytrail/pmc.h> + +/* GPIO-to-Pad LUTs */ +static const u8 gpncore_gpio_to_pad[GPNCORE_COUNT] = + { 19, 18, 17, 20, 21, 22, 24, 25, /* [ 0: 7] */ + 23, 16, 14, 15, 12, 26, 27, 1, /* [ 8:15] */ + 4, 8, 11, 0, 3, 6, 10, 13, /* [16:23] */ + 2, 5, 9 }; /* [24:26] */ + +static const u8 gpscore_gpio_to_pad[GPSCORE_COUNT] = + { 85, 89, 93, 96, 99, 102, 98, 101, /* [ 0: 7] */ + 34, 37, 36, 38, 39, 35, 40, 84, /* [ 8: 15] */ + 62, 61, 64, 59, 54, 56, 60, 55, /* [16: 23] */ + 63, 57, 51, 50, 53, 47, 52, 49, /* [24: 31] */ + 48, 43, 46, 41, 45, 42, 58, 44, /* [32: 39] */ + 95, 105, 70, 68, 67, 66, 69, 71, /* [40: 47] */ + 65, 72, 86, 90, 88, 92, 103, 77, /* [48: 55] */ + 79, 83, 78, 81, 80, 82, 13, 12, /* [56: 63] */ + 15, 14, 17, 18, 19, 16, 2, 1, /* [64: 71] */ + 0, 4, 6, 7, 9, 8, 33, 32, /* [72: 79] */ + 31, 30, 29, 27, 25, 28, 26, 23, /* [80: 87] */ + 21, 20, 24, 22, 5, 3, 10, 11, /* [88: 95] */ + 106, 87, 91, 104, 97, 100 }; /* [96:101] */ + +static const u8 gpssus_gpio_to_pad[GPSSUS_COUNT] = + { 29, 33, 30, 31, 32, 34, 36, 35, /* [ 0: 7] */ + 38, 37, 18, 7, 11, 20, 17, 1, /* [ 8:15] */ + 8, 10, 19, 12, 0, 2, 23, 39, /* [16:23] */ + 28, 27, 22, 21, 24, 25, 26, 51, /* [24:31] */ + 56, 54, 49, 55, 48, 57, 50, 58, /* [32:39] */ + 52, 53, 59, 40 }; /* [40:43] */ + +/* GPIO bank descriptions */ +static const struct gpio_bank gpncore_bank = { + .gpio_count = GPNCORE_COUNT, + .gpio_to_pad = gpncore_gpio_to_pad, + .legacy_base = GP_LEGACY_BASE_NONE, + .pad_base = GPNCORE_PAD_BASE, + .has_wake_en = 0, + .gpio_f1_range_start = GPNCORE_GPIO_F1_RANGE_START, + .gpio_f1_range_end = GPNCORE_GPIO_F1_RANGE_END, +}; + +static const struct gpio_bank gpscore_bank = { + .gpio_count = GPSCORE_COUNT, + .gpio_to_pad = gpscore_gpio_to_pad, + .legacy_base = GPSCORE_LEGACY_BASE, + .pad_base = GPSCORE_PAD_BASE, + .has_wake_en = 0, + .gpio_f1_range_start = GPSCORE_GPIO_F1_RANGE_START, + .gpio_f1_range_end = GPSCORE_GPIO_F1_RANGE_END, +}; + +static const struct gpio_bank gpssus_bank = { + .gpio_count = GPSSUS_COUNT, + .gpio_to_pad = gpssus_gpio_to_pad, + .legacy_base = GPSSUS_LEGACY_BASE, + .pad_base = GPSSUS_PAD_BASE, + .has_wake_en = 1, + .gpio_f1_range_start = GPSSUS_GPIO_F1_RANGE_START, + .gpio_f1_range_end = GPSSUS_GPIO_F1_RANGE_END, +}; + +static void setup_gpios(const struct soc_gpio_map *gpios, + const struct gpio_bank *bank) +{ + const struct soc_gpio_map *config; + int gpio = 0; + u32 reg, pad_conf0; + u8 set, bit; + + u32 use_sel[4] = {0}; + u32 io_sel[4] = {0}; + u32 gp_lvl[4] = {0}; + u32 tpe[4] = {0}; + u32 tne[4] = {0}; + u32 wake_en[4] = {0}; + + if (!gpios) + return; + + for (config = gpios; config->pad_conf0 != GPIO_LIST_END; + config++, gpio++) { + if (gpio > bank->gpio_count) + break; + + set = gpio >> 5; + bit = gpio % 32; + + if (bank->legacy_base != GP_LEGACY_BASE_NONE) { + /* Legacy IO configuration */ + use_sel[set] |= config->use_sel << bit; + io_sel[set] |= config->io_sel << bit; + gp_lvl[set] |= config->gp_lvl << bit; + tpe[set] |= config->tpe << bit; + tne[set] |= config->tne << bit; + + /* Some banks do not have wake_en ability */ + if (bank->has_wake_en) + wake_en[set] |= config->wake_en << bit; + } + + /* Pad configuration registers */ + reg = bank->pad_base + 16 * bank->gpio_to_pad[gpio]; + + /* Add correct func to GPIO pad config */ + pad_conf0 = config->pad_conf0; + if (config->is_gpio) + { + if (gpio >= bank->gpio_f1_range_start && + gpio <= bank->gpio_f1_range_end) + pad_conf0 |= PAD_FUNC1; + else + pad_conf0 |= PAD_FUNC0; + } + +#ifdef GPIO_DEBUG + printk(BIOS_DEBUG, "Write Pad: Base(%x) - %x %x %x\n", + reg, pad_conf0, config->pad_conf1, config->pad_val); +#endif + + write32(reg + PAD_CONF0_REG, pad_conf0); + write32(reg + PAD_CONF1_REG, config->pad_conf1); + write32(reg + PAD_VAL_REG, config->pad_val); + } + + if (bank->legacy_base != GP_LEGACY_BASE_NONE) + for (set = 0; set <= (bank->gpio_count - 1) / 32; ++set) { + reg = bank->legacy_base + 0x20 * set; + +#ifdef GPIO_DEBUG + printk(BIOS_DEBUG, + "Write GPIO: Reg(%x) - %x %x %x %x %x\n", + reg, use_sel[set], io_sel[set], gp_lvl[set], + tpe[set], tne[set]); +#endif + + outl(use_sel[set], reg + LEGACY_USE_SEL_REG); + outl(io_sel[set], reg + LEGACY_IO_SEL_REG); + outl(gp_lvl[set], reg + LEGACY_GP_LVL_REG); + outl(tpe[set], reg + LEGACY_TPE_REG); + outl(tne[set], reg + LEGACY_TNE_REG); + + /* TS registers are WOC */ + outl(0, reg + LEGACY_TS_REG); + + if (bank->has_wake_en) + outl(wake_en[set], reg + LEGACY_WAKE_EN_REG); + } +} + +static void setup_gpio_route(const struct soc_gpio_map *sus, + const struct soc_gpio_map *core) +{ + uint32_t route_reg = 0; + int i; + + for (i = 0; i < 8; i++) { + /* SMI takes precedence and wake_en implies SCI. */ + if (sus[i].smi) { + route_reg |= ROUTE_SMI << (2 * i); + } else if (sus[i].sci) { + route_reg |= ROUTE_SCI << (2 * i); + } + + if (core[i].smi) { + route_reg |= ROUTE_SMI << (2 * (i + 8)); + } else if (core[i].sci) { + route_reg |= ROUTE_SCI << (2 * (i + 8)); + } + } + +#if IS_ENABLED(CONFIG_HAVE_SMI_HANDLER) + southcluster_smm_save_gpio_route(route_reg); +#endif +} + +static void setup_dirqs(const u8 dirq[GPIO_MAX_DIRQS], + const struct gpio_bank *bank) +{ + u32 reg = bank->pad_base + PAD_BASE_DIRQ_OFFSET; + u32 val; + int i; + + /* Write all four DIRQ registers */ + for (i=0; i<4; ++i) { + val = dirq[i * 4 + 3] << 24 | dirq[i * 4 + 2] << 16 | + dirq[i * 4 + 1] << 8 | dirq[i * 4]; + write32(reg + i * 4, val); +#ifdef GPIO_DEBUG + printk(BIOS_DEBUG, "Write DIRQ reg(%x) - %x\n", + reg + i * 4, val); +#endif + } +} + +void setup_soc_gpios(struct soc_gpio_config *config) +{ + if (config) { + setup_gpios(config->ncore, &gpncore_bank); + setup_gpios(config->score, &gpscore_bank); + setup_gpios(config->ssus, &gpssus_bank); + setup_gpio_route(config->ssus, config->score); + + if (config->core_dirq) + setup_dirqs(*config->core_dirq, &gpscore_bank); + if (config->sus_dirq) + setup_dirqs(*config->sus_dirq, &gpssus_bank); + } + +} + +struct soc_gpio_config* __attribute__((weak)) mainboard_get_gpios(void) +{ + printk(BIOS_DEBUG, "Default/empty GPIO config\n"); + return NULL; +} diff --git a/src/soc/intel/fsp_baytrail/iosf.c b/src/soc/intel/fsp_baytrail/iosf.c new file mode 100644 index 0000000..f892b20 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/iosf.c @@ -0,0 +1,111 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google, Inc. + * Copyright (C) 2014 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 wacbmem_entryanty 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 <baytrail/iosf.h> + +#if !defined(__PRE_RAM__) +#ifndef CONFIG_MMCONF_BASE_ADDRESS +#error CONFIG_MMCONF_BASE_ADDRESS must be set. +#endif +#define IOSF_PCI_BASE (CONFIG_MMCONF_BASE_ADDRESS + (IOSF_PCI_DEV << 12)) + +static inline void write_iosf_reg(int reg, uint32_t value) +{ + write32(IOSF_PCI_BASE + reg, value); +} +static inline uint32_t read_iosf_reg(int reg) +{ + return read32(IOSF_PCI_BASE + reg); +} +#else +static inline void write_iosf_reg(int reg, uint32_t value) +{ + pci_write_config32(IOSF_PCI_DEV, reg, value); +} +static inline uint32_t read_iosf_reg(int reg) +{ + return pci_read_config32(IOSF_PCI_DEV, reg); +} +#endif + +/* Common sequences for all the port accesses. */ +static uint32_t iosf_read_port(uint32_t cr, int reg) +{ + cr |= IOSF_REG(reg) | IOSF_BYTE_EN; + write_iosf_reg(MCRX_REG, IOSF_REG_UPPER(reg)); + write_iosf_reg(MCR_REG, cr); + return read_iosf_reg(MDR_REG); +} + +static void iosf_write_port(uint32_t cr, int reg, uint32_t val) +{ + cr |= IOSF_REG(reg) | IOSF_BYTE_EN; + write_iosf_reg(MDR_REG, val); + write_iosf_reg(MCRX_REG, IOSF_REG_UPPER(reg)); + write_iosf_reg(MCR_REG, cr); +} + +#define IOSF_READ(port) \ + IOSF_OPCODE(IOSF_OP_READ_##port) | IOSF_PORT(IOSF_PORT_##port) +#define IOSF_WRITE(port) \ + IOSF_OPCODE(IOSF_OP_WRITE_##port) | IOSF_PORT(IOSF_PORT_##port) + +uint32_t iosf_bunit_read(int reg) +{ + return iosf_read_port(IOSF_READ(BUNIT), reg); +} + +void iosf_bunit_write(int reg, uint32_t val) +{ + iosf_write_port(IOSF_WRITE(BUNIT), reg, val); +} + +uint32_t iosf_dunit_read(int reg) +{ + return iosf_read_port(IOSF_READ(SYSMEMC), reg); +} + +uint32_t iosf_dunit_ch0_read(int reg) +{ + return iosf_dunit_read(reg); +} + +uint32_t iosf_dunit_ch1_read(int reg) +{ + uint32_t cr = IOSF_OPCODE(IOSF_OP_READ_SYSMEMC) | + IOSF_PORT(IOSF_PORT_DUNIT_CH1); + return iosf_read_port(cr, reg); +} + +void iosf_dunit_write(int reg, uint32_t val) +{ + iosf_write_port(IOSF_WRITE(SYSMEMC), reg, val); +} + +uint32_t iosf_lpss_read(int reg) +{ + return iosf_read_port(IOSF_READ(LPSS), reg); +} + +void iosf_lpss_write(int reg, uint32_t val) +{ + return iosf_write_port(IOSF_WRITE(LPSS), reg, val); +} diff --git a/src/soc/intel/fsp_baytrail/memmap.c b/src/soc/intel/fsp_baytrail/memmap.c new file mode 100644 index 0000000..83858b8 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/memmap.c @@ -0,0 +1,28 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 wacbmem_entryanty 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 <cbmem.h> +#include <baytrail/iosf.h> +#include <baytrail/smm.h> + +void *smm_region_start(void) +{ + return (void *)(iosf_bunit_read(BUNIT_SMRRL) << 20); +} diff --git a/src/soc/intel/fsp_baytrail/microcode/Makefile.inc b/src/soc/intel/fsp_baytrail/microcode/Makefile.inc new file mode 100644 index 0000000..012c712 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/microcode/Makefile.inc @@ -0,0 +1,25 @@ +# +# This file is part of the coreboot project. +# +# Copyright (C) 2014 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 +# +cpu_microcode-$(CONFIG_CPU_MICROCODE_CBFS_GENERATE) += microcode_blob.c + +ifneq ($(CONFIG_MICROCODE_INCLUDE_PATH),) +ifneq ($(wildcard $(shell realpath -q -L "$(top)/$(CONFIG_MICROCODE_INCLUDE_PATH)")),) +CPPFLAGS_common += -I$(CONFIG_MICROCODE_INCLUDE_PATH) +endif +endif diff --git a/src/soc/intel/fsp_baytrail/microcode/microcode_blob.c b/src/soc/intel/fsp_baytrail/microcode/microcode_blob.c new file mode 100644 index 0000000..9df84dd --- /dev/null +++ b/src/soc/intel/fsp_baytrail/microcode/microcode_blob.c @@ -0,0 +1,25 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013-2014 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 + */ + +unsigned microcode[] = { + +/* Size is 0xCC00 - update in Kconfig when the patch gets updated. */ +#include "M013067331E.h" // M0130673: Baytrail I B2 / B3 + +}; diff --git a/src/soc/intel/fsp_baytrail/northcluster.c b/src/soc/intel/fsp_baytrail/northcluster.c new file mode 100644 index 0000000..19be0f6 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/northcluster.c @@ -0,0 +1,222 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2013-2014 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 <cpu/x86/smm.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <cpu/x86/lapic.h> +#include <baytrail/iomap.h> +#include <baytrail/iosf.h> +#include <baytrail/pci_devs.h> +#include <baytrail/ramstage.h> +#include <device/pci.h> +#include <cbmem.h> +#include <baytrail/baytrail.h> +#include <drivers/intel/fsp/fsp_util.h> + + +static const int legacy_hole_base_k = 0xa0000 / 1024; +static const int legacy_hole_size_k = 384; + +/* Host Memory Map: + * + * +--------------------------+ BMBOUND_HI + * | Usable DRAM | + * +--------------------------+ 4GiB + * | PCI Address Space | + * +--------------------------+ BMBOUND + * | TPM | + * +--------------------------+ IMR2 + * | TXE | + * +--------------------------+ IMR1 + * | iGD | + * +--------------------------+ + * | GTT | + * +--------------------------+ SMMRRH, IRM0 + * | TSEG | + * +--------------------------+ SMMRRL + * | FSP | + * +--------------------------+ SMMRRL - 2MB + * | Usable DRAM | + * +--------------------------+ FFFFF + * | ROM Area | + * +--------------------------+ A0000 + * | Usable DRAM | + * +--------------------------+ 0 + * + * Note that there are really only a few regions that need to enumerated w.r.t. + * coreboot's resource model: + * + * +--------------------------+ BMBOUND_HI + * | Cacheable/Usable | + * +--------------------------+ 4GiB + * + * +--------------------------+ BMBOUND + * | Uncacheable/Reserved | + * +--------------------------+ SMMRRH + * | Cacheable/Reserved | + * +--------------------------+ SMMRRL - 2MB + * | Cacheable/Usable | + * +--------------------------+ 0 + */ + +/* + * Get the top of low memory for use by ACPI + */ +uint32_t nc_read_top_of_low_memory(void) +{ + uint32_t fsp_mem_base = 0; + GetLowMemorySize(&fsp_mem_base); + + return fsp_mem_base; +} + +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 = iosf_bunit_read(BUNIT_MMCONF_REG); + + if (!(pciexbar_reg & (1 << 0))) + return 0; + + *base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) | + (1 << 28)); + *len = 256 * 1024 * 1024; /* 256MB ECAM range */ + return 1; + +} + +static int add_fixed_resources(struct device *dev, int index) +{ + struct resource *resource; + u32 pcie_config_base, pcie_config_size; + + + 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; + } + + resource = new_resource(dev, index++); /* Local APIC */ + resource->base = LAPIC_DEFAULT_BASE; + resource->size = 0x00001000; + resource->flags = IORESOURCE_MEM | IORESOURCE_RESERVE | + IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; + + mmio_resource(dev, index++, legacy_hole_base_k, legacy_hole_size_k); + + return index; +} + +static void mc_add_dram_resources(device_t dev) +{ + u32 bmbound, bsmmrrl; + int index = 0; + uint64_t highmem_size = 0; + uint32_t fsp_mem_base = 0; + + GetHighMemorySize(&highmem_size); + GetLowMemorySize(&fsp_mem_base); + + + bmbound = iosf_bunit_read(BUNIT_BMBOUND); + bsmmrrl = iosf_bunit_read(BUNIT_SMRRL) << 20; + + if (bsmmrrl){ + printk(BIOS_DEBUG, "UMA, GTT & SMM memory location: 0x%x\n" + "UMA, GTT & SMM memory size: %dM\n", + bsmmrrl, (bmbound - bsmmrrl) >> 20); + + printk(BIOS_DEBUG, "FSP memory location: 0x%x\nFSP memory size: %dM\n", + fsp_mem_base, (bsmmrrl - fsp_mem_base) >> 20); + + if ((bsmmrrl - fsp_mem_base ) != FSP_RESERVE_MEMORY_SIZE) + printk(BIOS_WARNING, "Warning: Fsp memory size does not match " + "expected memory size (%x).\n", FSP_RESERVE_MEMORY_SIZE); + } + + printk(BIOS_INFO, "Available memory below 4GB: 0x%08x (%dM)\n", + fsp_mem_base, fsp_mem_base >> 20); + + /* Report the memory regions. */ + ram_resource(dev, index++, 0, legacy_hole_base_k); + ram_resource(dev, index++, legacy_hole_base_k + legacy_hole_size_k, + ((fsp_mem_base >> 10) - (legacy_hole_base_k + legacy_hole_size_k))); + + /* Mark SMM & FSP regions reserved */ + mmio_resource(dev, index++, fsp_mem_base >> 10, + (bmbound - fsp_mem_base) >> 10); + + if (highmem_size) { + ram_resource(dev, index++, 0x100000000 >> 10, highmem_size >> 10 ); + } + printk(BIOS_INFO, "Available memory above 4GB: %lluM\n", + highmem_size >> 20); + + index = add_fixed_resources(dev, index); +} + +static void nc_read_resources(device_t dev) +{ + /* Call the normal read_resources */ + pci_dev_read_resources(dev); + + + /* Calculate and add DRAM resources. */ + mc_add_dram_resources(dev); +} + +static void nc_enable(device_t dev) +{ + print_fsp_info(); +} + +static struct device_operations nc_ops = { + .read_resources = nc_read_resources, + .set_resources = NULL, + .enable_resources = NULL, + .init = NULL, + .enable = &nc_enable, + .scan_bus = NULL, + .ops_pci = &soc_pci_ops, +}; + +static const struct pci_driver nc_driver __pci_driver = { + .ops = &nc_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = SOC_DEVID, +}; + diff --git a/src/soc/intel/fsp_baytrail/nvm.c b/src/soc/intel/fsp_baytrail/nvm.c new file mode 100644 index 0000000..dab87ae --- /dev/null +++ b/src/soc/intel/fsp_baytrail/nvm.c @@ -0,0 +1,88 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2014 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 <stddef.h> +#include <console/console.h> +#include <string.h> +#include <spi-generic.h> +#include <spi_flash.h> +#include <baytrail/nvm.h> + +/* This module assumes the flash is memory mapped just below 4GiB in the + * address space for reading. Also this module assumes an area it erased + * when all bytes read as all 0xff's. */ + +static struct spi_flash *flash; + +static int nvm_init(void) +{ + if (flash != NULL) + return 0; + + spi_init(); + flash = spi_flash_probe(0, 0, 1000000, SPI_MODE_3); + if (!flash) { + printk(BIOS_DEBUG, "Could not find SPI device\n"); + return -1; + } + + return 0; +} + +/* Convert memory mapped pointer to flash offset. */ +static inline uint32_t to_flash_offset(void *p) +{ +#ifndef CONFIG_ROM_SIZE +#error CONFIG_ROM_SIZE must be set. +#endif + return CONFIG_ROM_SIZE + (uintptr_t)p; +} + +int nvm_is_erased(const void *start, size_t size) +{ + const uint8_t *cur = start; + const uint8_t erased_value = 0xff; + + while (size > 0) { + if (*cur != erased_value) + return 0; + cur++; + size--; + } + return 1; +} + +int nvm_erase(void *start, size_t size) +{ + if (nvm_init() < 0) + return -1; + flash->erase(flash, to_flash_offset(start), size); + return 0; +} + +/* Write data to NVM. Returns 0 on success < 0 on error. */ +int nvm_write(void *start, const void *data, size_t size) +{ + if (nvm_init() < 0) + return -1; + flash->write(flash, to_flash_offset(start), size, data); + return 0; +} diff --git a/src/soc/intel/fsp_baytrail/placeholders.c b/src/soc/intel/fsp_baytrail/placeholders.c new file mode 100644 index 0000000..c9a9da4 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/placeholders.c @@ -0,0 +1,15 @@ + +#include <arch/acpi.h> +#include <cpu/cpu.h> +#include <device/pci_rom.h> +#include <baytrail/acpi.h> + + +void acpi_create_serialio_ssdt(acpi_header_t *ssdt) {} + +#if IS_ENABLED(CONFIG_HAVE_SMI_HANDLER) +void smm_init(void) {} +#endif + +/* Rmodules don't like weak symbols. */ +u32 map_oprom_vendev(u32 vendev) { return vendev; } diff --git a/src/soc/intel/fsp_baytrail/pmutil.c b/src/soc/intel/fsp_baytrail/pmutil.c new file mode 100644 index 0000000..aee3726 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/pmutil.c @@ -0,0 +1,364 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 <arch/io.h> +#include <console/console.h> + +#include <baytrail/iomap.h> +#include <baytrail/lpc.h> +#include <baytrail/pci_devs.h> +#include <baytrail/pmc.h> + +#if defined(__SMM__) + +static const device_t pcu_dev = PCI_DEV(0, PCU_DEV, 0); + +static inline device_t get_pcu_dev(void) +{ + return pcu_dev; +} + +#else /* !__SMM__ */ +#include <device/device.h> +#include <device/pci.h> + +static device_t pcu_dev; +static device_t get_pcu_dev(void) +{ + if (pcu_dev == NULL) + pcu_dev = dev_find_slot(0, PCI_DEVFN(PCU_DEV, 0)); + return pcu_dev; +} +#endif + +uint16_t get_pmbase(void) +{ + return pci_read_config16(get_pcu_dev(), ABASE) & 0xfff8; +} + +static void print_num_status_bits(int num_bits, uint32_t status, + const char *bit_names[]) +{ + int i; + + if (!status) + return; + + for (i = num_bits - 1; i >= 0; i--) { + if (status & (1 << i)) { + if (bit_names[i]) + printk(BIOS_DEBUG, "%s ", bit_names[i]); + else + printk(BIOS_DEBUG, "BIT%d ", i); + } + } +} + +static void print_status_bits(uint32_t status, const char *bit_names[]) +{ + print_num_status_bits(32, status, bit_names); +} + +static uint32_t print_smi_status(uint32_t smi_sts) +{ + static const char *smi_sts_bits[] = { + [2] = "BIOS", + [4] = "SLP_SMI", + [5] = "APM", + [6] = "SWSMI_TMR", + [8] = "PM1", + [9] = "GPE0", + [12] = "DEVMON", + [13] = "TCO", + [14] = "PERIODIC", + [15] = "ILB", + [16] = "SMBUS_SMI", + [17] = "LEGACY_USB2", + [18] = "INTEL_USB2", + [20] = "PCI_EXP_SMI", + [26] = "SPI", + [28] = "PUNIT", + [29] = "GUNIT", + }; + + if (!smi_sts) + return 0; + + printk(BIOS_DEBUG, "SMI_STS: "); + print_status_bits(smi_sts, smi_sts_bits); + printk(BIOS_DEBUG, "\n"); + + return smi_sts; +} + +static uint32_t reset_smi_status(void) +{ + uint16_t pmbase = get_pmbase(); + uint32_t smi_sts = inl(pmbase + SMI_STS); + outl(smi_sts, pmbase + SMI_STS); + return smi_sts; +} + +uint32_t clear_smi_status(void) +{ + return print_smi_status(reset_smi_status()); +} + +void enable_smi(uint32_t mask) +{ + uint16_t pmbase = get_pmbase(); + uint32_t smi_en = inl(pmbase + SMI_EN); + smi_en |= mask; + outl(smi_en, pmbase + SMI_EN); +} + +void disable_smi(uint32_t mask) +{ + uint16_t pmbase = get_pmbase(); + uint32_t smi_en = inl(pmbase + SMI_EN); + smi_en &= ~mask; + outl(smi_en, pmbase + SMI_EN); +} + +void enable_pm1_control(uint32_t mask) +{ + uint16_t pmbase = get_pmbase(); + uint32_t pm1_cnt = inl(pmbase + PM1_CNT); + pm1_cnt |= mask; + outl(pm1_cnt, pmbase + PM1_CNT); +} + +void disable_pm1_control(uint32_t mask) +{ + uint16_t pmbase = get_pmbase(); + uint32_t pm1_cnt = inl(pmbase + PM1_CNT); + pm1_cnt &= ~mask; + outl(pm1_cnt, pmbase + PM1_CNT); +} + +static uint16_t reset_pm1_status(void) +{ + uint16_t pmbase = get_pmbase(); + uint16_t pm1_sts = inw(pmbase + PM1_STS); + outw(pm1_sts, pmbase + PM1_STS); + return pm1_sts; +} + +static uint16_t print_pm1_status(uint16_t pm1_sts) +{ + static const char *pm1_sts_bits[] = { + [0] = "TMROF", + [5] = "GBL", + [8] = "PWRBTN", + [10] = "RTC", + [11] = "PRBTNOR", + [13] = "USB", + [14] = "PCIEXPWAK", + [15] = "WAK", + }; + + if (!pm1_sts) + return 0; + + printk(BIOS_SPEW, "PM1_STS: "); + print_status_bits(pm1_sts, pm1_sts_bits); + printk(BIOS_SPEW, "\n"); + + return pm1_sts; +} + +uint16_t clear_pm1_status(void) +{ + return print_pm1_status(reset_pm1_status()); +} + +void enable_pm1(uint16_t events) +{ + outw(events, get_pmbase() + PM1_EN); +} + +static uint32_t print_tco_status(uint32_t tco_sts) +{ + static const char *tco_sts_bits[] = { + [3] = "TIMEOUT", + [17] = "SECOND_TO", + }; + + if (!tco_sts) + return 0; + + printk(BIOS_DEBUG, "TCO_STS: "); + print_status_bits(tco_sts, tco_sts_bits); + printk(BIOS_DEBUG, "\n"); + + return tco_sts; +} + +static uint32_t reset_tco_status(void) +{ + uint16_t pmbase = get_pmbase(); + uint32_t tco_sts = inl(pmbase + TCO_STS); + uint32_t tco_en = inl(pmbase + TCO1_CNT); + + outl(tco_sts, pmbase + TCO_STS); + return tco_sts & tco_en; +} + +uint32_t clear_tco_status(void) +{ + return print_tco_status(reset_tco_status()); +} + +void enable_gpe(uint32_t mask) +{ + uint16_t pmbase = get_pmbase(); + uint32_t gpe0_en = inl(pmbase + GPE0_EN); + gpe0_en |= mask; + outl(gpe0_en, pmbase + GPE0_EN); +} + +void disable_gpe(uint32_t mask) +{ + uint16_t pmbase = get_pmbase(); + uint32_t gpe0_en = inl(pmbase + GPE0_EN); + gpe0_en &= ~mask; + outl(gpe0_en, pmbase + GPE0_EN); +} + +void disable_all_gpe(void) +{ + disable_gpe(~0); +} + + +static uint32_t reset_gpe_status(void) +{ + uint16_t pmbase = get_pmbase(); + uint32_t gpe_sts = inl(pmbase + GPE0_STS); + outl(gpe_sts, pmbase + GPE0_STS); + return gpe_sts; +} + +static uint32_t print_gpe_sts(uint32_t gpe_sts) +{ + static const char *gpe_sts_bits[] = { + [1] = "HOTPLUG", + [2] = "SWGPE", + [3] = "PCIE_WAKE0", + [4] = "PUNIT", + [5] = "GUNIT", + [6] = "PCIE_WAKE1", + [7] = "PCIE_WAKE2", + [8] = "PCIE_WAKE3", + [9] = "PCI_EXP", + [10] = "BATLOW", + [13] = "PME_B0", + [16] = "SUS_GPIO_0", + [17] = "SUS_GPIO_1", + [18] = "SUS_GPIO_2", + [19] = "SUS_GPIO_3", + [20] = "SUS_GPIO_4", + [21] = "SUS_GPIO_5", + [22] = "SUS_GPIO_6", + [23] = "SUS_GPIO_7", + [24] = "CORE_GPIO_0", + [25] = "CORE_GPIO_1", + [26] = "CORE_GPIO_2", + [27] = "CORE_GPIO_3", + [28] = "CORE_GPIO_4", + [29] = "CORE_GPIO_5", + [30] = "CORE_GPIO_6", + [31] = "CORE_GPIO_7", + }; + + if (!gpe_sts) + return gpe_sts; + + printk(BIOS_DEBUG, "GPE0a_STS: "); + print_status_bits(gpe_sts, gpe_sts_bits); + printk(BIOS_DEBUG, "\n"); + + return gpe_sts; +} + +uint32_t clear_gpe_status(void) +{ + return print_gpe_sts(reset_gpe_status()); +} + +static uint32_t reset_alt_status(void) +{ + uint16_t pmbase = get_pmbase(); + uint32_t alt_gpio_smi = inl(pmbase + ALT_GPIO_SMI); + outl(alt_gpio_smi, pmbase + ALT_GPIO_SMI); + return alt_gpio_smi; +} + +static uint32_t print_alt_sts(uint32_t alt_gpio_smi) +{ + uint32_t alt_gpio_sts; + static const char *alt_gpio_smi_sts_bits[] = { + [0] = "SUS_GPIO_0", + [1] = "SUS_GPIO_1", + [2] = "SUS_GPIO_2", + [3] = "SUS_GPIO_3", + [4] = "SUS_GPIO_4", + [5] = "SUS_GPIO_5", + [6] = "SUS_GPIO_6", + [7] = "SUS_GPIO_7", + [8] = "CORE_GPIO_0", + [9] = "CORE_GPIO_1", + [10] = "CORE_GPIO_2", + [11] = "CORE_GPIO_3", + [12] = "CORE_GPIO_4", + [13] = "CORE_GPIO_5", + [14] = "CORE_GPIO_6", + [15] = "CORE_GPIO_7", + }; + + /* Status bits are in the upper 16 bits. */ + alt_gpio_sts = alt_gpio_smi >> 16; + if (!alt_gpio_sts) + return alt_gpio_smi; + + printk(BIOS_DEBUG, "ALT_GPIO_SMI: "); + print_num_status_bits(16, alt_gpio_sts, alt_gpio_smi_sts_bits); + printk(BIOS_DEBUG, "\n"); + + return alt_gpio_smi; +} + +uint32_t clear_alt_status(void) +{ + return print_alt_sts(reset_alt_status()); +} + +void clear_pmc_status(void) +{ + uint32_t prsts; + uint32_t gen_pmcon1; + + prsts = read32(PMC_BASE_ADDRESS + PRSTS); + gen_pmcon1 = read32(PMC_BASE_ADDRESS + GEN_PMCON1); + + /* Clear the status bits. The RPS field is cleared on a 0 write. */ + write32(PMC_BASE_ADDRESS + GEN_PMCON1, gen_pmcon1 & ~RPS); + write32(PMC_BASE_ADDRESS + PRSTS, prsts); +} diff --git a/src/soc/intel/fsp_baytrail/raminit.c b/src/soc/intel/fsp_baytrail/raminit.c new file mode 100644 index 0000000..9170f48 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/raminit.c @@ -0,0 +1,48 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Google Inc. + * Copyright (C) 2014 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/io.h> +#include <cbmem.h> +#include <device/device.h> +#include <baytrail/baytrail.h> +#include <baytrail/iosf.h> +#include <cpu/x86/msr.h> +#include <drivers/intel/fsp/fsp_util.h> + +unsigned long get_top_of_ram(void) +{ + /* + * Calculate the top of usable (low) DRAM. + * The FSP's reserved memory sits just below the SMM region, + * allowing calculation of the top of usable memory. + * + * The entire memory map is shown in northcluster.c + */ + u32 tom = iosf_bunit_read(BUNIT_BMBOUND); + u32 bsmmrrl = iosf_bunit_read(BUNIT_SMRRL) << 20; + if (bsmmrrl) { + tom = bsmmrrl; + } + tom -= FSP_RESERVE_MEMORY_SIZE; + + return (unsigned long) tom; +} + diff --git a/src/soc/intel/fsp_baytrail/ramstage.c b/src/soc/intel/fsp_baytrail/ramstage.c new file mode 100644 index 0000000..e231701 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/ramstage.c @@ -0,0 +1,138 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 <arch/cpu.h> +#include <console/console.h> +#include <cpu/intel/microcode.h> +#include <cpu/x86/cr.h> +#include <cpu/x86/msr.h> +#include <device/device.h> +#include <device/pci_def.h> +#include <device/pci_ops.h> +#include <stdlib.h> + +#include <baytrail/gpio.h> +#include <baytrail/lpc.h> +#include <baytrail/msr.h> +#include <baytrail/pattrs.h> +#include <baytrail/pci_devs.h> +#include <baytrail/ramstage.h> + +/* Global PATTRS */ +DEFINE_PATTRS; + +#define SHOW_PATTRS 1 + +static void detect_num_cpus(struct pattrs *attrs) +{ + int ecx = 0; + + while (1) { + struct cpuid_result leaf_b; + + leaf_b = cpuid_ext(0xb, ecx); + + /* Bay Trail doesn't have hyperthreading so just determine the + * number of cores by from level type (ecx[15:8] == * 2). */ + if ((leaf_b.ecx & 0xff00) == 0x0200) { + attrs->num_cpus = leaf_b.ebx & 0xffff; + break; + } + ecx++; + } +} + +static inline void fill_in_msr(msr_t *msr, int idx) +{ + *msr = rdmsr(idx); + if (SHOW_PATTRS) { + printk(BIOS_DEBUG, "msr(%x) = %08x%08x\n", + idx, msr->hi, msr->lo); + } +} + +static const char *stepping_str[] = { + "A0", "A1", "B0", "B1", "B2", "B3" +}; + +static void fill_in_pattrs(void) +{ + device_t dev; + msr_t msr; + struct pattrs *attrs = (struct pattrs *)pattrs_get(); + + attrs->cpuid = cpuid_eax(1); + dev = dev_find_slot(0, PCI_DEVFN(LPC_DEV, LPC_FUNC)); + attrs->revid = pci_read_config8(dev, REVID); + /* The revision to stepping IDs have two values per metal stepping. */ + if (attrs->revid >= RID_B_STEPPING_START) { + attrs->stepping = (attrs->revid - RID_B_STEPPING_START) / 2; + attrs->stepping += STEP_B0; + } else { + attrs->stepping = (attrs->revid - RID_A_STEPPING_START) / 2; + attrs->stepping += STEP_A0; + } + + attrs->address_bits = cpuid_eax(0x80000008) & 0xff; + detect_num_cpus(attrs); + + if (SHOW_PATTRS) { + printk(BIOS_DEBUG, + "CPUID: %08x\nCores: %d\nRevision ID: %02x\nStepping: %s\n", + attrs->cpuid, attrs->num_cpus, attrs->revid, + (attrs->stepping >= ARRAY_SIZE(stepping_str)) ? "??" : + stepping_str[attrs->stepping]); + } + + fill_in_msr(&attrs->platform_id, MSR_IA32_PLATFORM_ID); + fill_in_msr(&attrs->platform_info, MSR_PLATFORM_INFO); + + /* Set IA core speed ratio and voltages */ + msr = rdmsr(MSR_IACORE_RATIOS); + attrs->iacore_ratios[IACORE_MIN] = msr.lo & 0x7f; + attrs->iacore_ratios[IACORE_LFM] = (msr.lo >> 8) & 0x7f; + attrs->iacore_ratios[IACORE_MAX] = (msr.lo >> 16) & 0x7f; + msr = rdmsr(MSR_IACORE_TURBO_RATIOS); + attrs->iacore_ratios[IACORE_TURBO] = (msr.lo & 0xff); /* 1 core max */ + + msr = rdmsr(MSR_IACORE_VIDS); + attrs->iacore_vids[IACORE_MIN] = msr.lo & 0x7f; + attrs->iacore_vids[IACORE_LFM] = (msr.lo >> 8) & 0x7f; + attrs->iacore_vids[IACORE_MAX] = (msr.lo >> 16) & 0x7f; + msr = rdmsr(MSR_IACORE_TURBO_VIDS); + attrs->iacore_vids[IACORE_TURBO] = (msr.lo & 0xff); /* 1 core max */ + + /* Set bus clock speed */ + attrs->bclk_khz = bus_freq_khz(); +} + + +void baytrail_init_pre_device(void) +{ + struct soc_gpio_config *config; + + fill_in_pattrs(); + + /* Allow for SSE instructions to be executed. */ + write_cr4(read_cr4() | CR4_OSFXSR | CR4_OSXMMEXCPT); + + /* Get GPIO initial states from mainboard */ + config = mainboard_get_gpios(); + setup_soc_gpios(config); +} diff --git a/src/soc/intel/fsp_baytrail/reset.c b/src/soc/intel/fsp_baytrail/reset.c new file mode 100644 index 0000000..a421ec9 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/reset.c @@ -0,0 +1,47 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 <arch/io.h> +#include <baytrail/pmc.h> +#include <baytrail/reset.h> + +void cold_reset(void) +{ + /* S0->S5->S0 trip. */ + outb(RST_CPU | SYS_RST | FULL_RST, RST_CNT); +} + +void warm_reset(void) +{ + /* PMC_PLTRST# asserted. */ + outb(RST_CPU | SYS_RST, RST_CNT); +} + +void soft_reset(void) +{ + /* Sends INIT# to CPU */ + outb(RST_CPU, RST_CNT); +} + +void hard_reset(void) +{ + /* Don't power cycle on hard_reset(). It's not really clear what the + * semantics should be for the meaning of hard_reset(). */ + warm_reset(); +} diff --git a/src/soc/intel/fsp_baytrail/romstage/Makefile.inc b/src/soc/intel/fsp_baytrail/romstage/Makefile.inc new file mode 100644 index 0000000..ff7762e --- /dev/null +++ b/src/soc/intel/fsp_baytrail/romstage/Makefile.inc @@ -0,0 +1,26 @@ +# +# This file is part of the coreboot project. +# +# Copyright (C) 2013 Google Inc. +# Copyright (C) 2014 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 +# + +romstage-y += romstage.c +romstage-y += pmc.c +romstage-y += report_platform.c +romstage-$(CONFIG_ENABLE_BUILTIN_COM1) += uart.c + +$(obj)/soc/intel/fsp_baytrail/romstage/romstage.romstage.o : $(obj)/build.h \ No newline at end of file diff --git a/src/soc/intel/fsp_baytrail/romstage/pmc.c b/src/soc/intel/fsp_baytrail/romstage/pmc.c new file mode 100644 index 0000000..678f951 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/romstage/pmc.c @@ -0,0 +1,41 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 <stddef.h> +#include <arch/io.h> +#include <console/console.h> +#include <device/device.h> +#include <device/pci_def.h> +#include <baytrail/iomap.h> +#include <baytrail/iosf.h> +#include <baytrail/lpc.h> +#include <baytrail/pci_devs.h> +#include <baytrail/pmc.h> +#include <baytrail/romstage.h> +#include "../chip.h" + +void tco_disable(void) +{ + uint32_t reg; + + reg = inl(ACPI_BASE_ADDRESS + TCO1_CNT); + reg |= TCO_TMR_HALT; + outl(reg, ACPI_BASE_ADDRESS + TCO1_CNT); +} + diff --git a/src/soc/intel/fsp_baytrail/romstage/report_platform.c b/src/soc/intel/fsp_baytrail/romstage/report_platform.c new file mode 100644 index 0000000..37e40ba --- /dev/null +++ b/src/soc/intel/fsp_baytrail/romstage/report_platform.c @@ -0,0 +1,88 @@ +/* + * 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/io.h> +#include <baytrail/iosf.h> +#include <baytrail/romstage.h> +#include <cpu/x86/msr.h> +#include <baytrail/msr.h> +#include <cpu/x86/name.h> + +static void print_dram_info(void) +{ + const int mrc_ver_reg = 0xf0; + const uint32_t soc_dev = PCI_DEV(0, SOC_DEV, SOC_FUNC); + uint32_t reg; + int num_channels; + int speed; + uint32_t ch0; + uint32_t ch1; + + reg = pci_read_config32(soc_dev, mrc_ver_reg); + + printk(BIOS_INFO, "MRC v%d.%02d\n", (reg >> 8) & 0xff, reg & 0xff); + + /* Number of channels enabled and DDR3 type. Determine number of + * channels by the keying of the rank enable bits [3:0]. * */ + ch0 = iosf_dunit_ch0_read(DRP); + ch1 = iosf_dunit_ch1_read(DRP); + num_channels = 0; + if (ch0 & DRP_RANK_MASK) + num_channels++; + if (ch1 & DRP_RANK_MASK) + num_channels++; + + printk(BIOS_INFO, "%d channels of %sDDR3 @ ", num_channels, + (reg & (1 << 22)) ? "LP" : ""); + + /* DRAM frequency -- all channels run at same frequency. */ + reg = iosf_dunit_read(DTR0); + switch (reg & 0x3) { + case 0: + speed = 800; break; + case 1: + speed = 1066; break; + case 2: + speed = 1333; break; + case 3: + speed = 1600; break; + } + printk(BIOS_INFO, "%dMHz\n", speed); +} + +#define VARIANT_ID_BYTE 18 +#define VARIANT_ID_MASK 7 +void report_platform_info(void) +{ + const char *baytrail_variants[4] = { + "Bay Trail-I (ISG/embedded)", + "Bay Trail-T (Tablet)", + "Bay Trail-D (Desktop)", + "Bay Trail-M (Mobile)", + }; + msr_t platform_id = rdmsr(MSR_IA32_PLATFORM_ID); + uint8_t variant = (platform_id.hi >> VARIANT_ID_BYTE) & VARIANT_ID_MASK; + + printk(BIOS_INFO, "Baytrail Chip Variant: %s\n", variant < 4 ? + baytrail_variants[variant] : "Unknown"); + print_dram_info(); + +} diff --git a/src/soc/intel/fsp_baytrail/romstage/romstage.c b/src/soc/intel/fsp_baytrail/romstage/romstage.c new file mode 100644 index 0000000..a63156f --- /dev/null +++ b/src/soc/intel/fsp_baytrail/romstage/romstage.c @@ -0,0 +1,232 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2013-2014 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 <stddef.h> +#include <arch/cpu.h> +#include <lib.h> +#include <arch/io.h> +#include <arch/cbfs.h> +#include <arch/stages.h> +#include <console/console.h> +#include <cbmem.h> +#include <cpu/x86/mtrr.h> +#include <romstage_handoff.h> +#include <timestamp.h> +#include <baytrail/gpio.h> +#include <baytrail/iomap.h> +#include <baytrail/lpc.h> +#include <baytrail/pci_devs.h> +#include <baytrail/romstage.h> +#include <baytrail/acpi.h> +#include <baytrail/baytrail.h> +#include <drivers/intel/fsp/fsp_util.h> +#include <baytrail/pmc.h> +#include <baytrail/spi.h> +#include <build.h> +#include <pc80/mc146818rtc.h> +#include <device/pci_def.h> +#include <console/cbmem_console.h> + +static void program_base_addresses(void) +{ + uint32_t reg; + + /* Memory Mapped IO registers. */ + reg = PMC_BASE_ADDRESS | SET_BAR_ENABLE; + pci_write_config32(LPC_BDF, PBASE, reg); + reg = IO_BASE_ADDRESS | SET_BAR_ENABLE; + pci_write_config32(LPC_BDF, IOBASE, reg); + reg = ILB_BASE_ADDRESS | SET_BAR_ENABLE; + pci_write_config32(LPC_BDF, IBASE, reg); + reg = SPI_BASE_ADDRESS | SET_BAR_ENABLE; + pci_write_config32(LPC_BDF, SBASE, reg); + reg = MPHY_BASE_ADDRESS | SET_BAR_ENABLE; + pci_write_config32(LPC_BDF, MPBASE, reg); + reg = PUNIT_BASE_ADDRESS | SET_BAR_ENABLE; + pci_write_config32(LPC_BDF, PUBASE, reg); + reg = RCBA_BASE_ADDRESS | RCBA_ENABLE; + pci_write_config32(LPC_BDF, RCBA, reg); + + /* IO Port Registers. */ + reg = ACPI_BASE_ADDRESS | SET_BAR_ENABLE; + pci_write_config32(LPC_BDF, ABASE, reg); + reg = GPIO_BASE_ADDRESS | SET_BAR_ENABLE; + pci_write_config32(LPC_BDF, GBASE, reg); +} + +static void spi_init(void) +{ + const uint32_t scs = SPI_BASE_ADDRESS + SCS; + const uint32_t bcr = SPI_BASE_ADDRESS + BCR; + uint32_t reg; + + /* Disable generating SMI when setting WPD bit. */ + write32(scs, read32(scs) & ~SMIWPEN); + /* + * Enable caching and prefetching in the SPI controller. Disable + * the SMM-only BIOS write and set WPD bit. + */ + reg = (read32(bcr) & ~SRC_MASK) | SRC_CACHE_PREFETCH | BCR_WPD; + reg &= ~EISS; + write32(bcr, reg); +} + +static void baytrail_rtc_init(void) +{ + uint32_t pbase = pci_read_config32(LPC_BDF, PBASE) & 0xfffffff0; + uint32_t gen_pmcon1 = read32(pbase + GEN_PMCON1); + int rtc_failed = !!(gen_pmcon1 & RPS); + + if (rtc_failed) { + printk(BIOS_DEBUG, + "RTC Failure detected. Resetting Date to %x/%x/%x%x\n", + COREBOOT_BUILD_MONTH_BCD, + COREBOOT_BUILD_DAY_BCD, + 0x20, + COREBOOT_BUILD_YEAR_BCD); + + write32(DEFAULT_PBASE + GEN_PMCON1, gen_pmcon1 & ~RPS); + } + + rtc_init(rtc_failed); +} + +/* Entry from cache-as-ram.inc. */ +void * asmlinkage main(FSP_INFO_HEADER *fsp_info_header) +{ + const unsigned long func_dis = PMC_BASE_ADDRESS + FUNC_DIS; + const unsigned long func_dis2 = PMC_BASE_ADDRESS + FUNC_DIS2; + uint32_t fd_mask = 0; + uint32_t fd2_mask = 0; + + post_code(0x40); + + program_base_addresses(); + + post_code(0x41); + tco_disable(); + + post_code(0x42); + byt_config_com1_and_enable(); + + post_code(0x43); + console_init(); + + spi_init(); + baytrail_rtc_init(); + + /* Call into mainboard. */ + early_mainboard_romstage_entry(); + + set_max_freq(); + + post_code(0x44); + + /* Program any required function disables */ + get_func_disables(&fd_mask, &fd2_mask); + + if (fd_mask != 0) { + write32(func_dis, read32(func_dis) | fd_mask); + /* Ensure posted write hits. */ + read32(func_dis); + } + + if (fd2_mask != 0) { + write32(func_dis2, read32(func_dis2) | fd2_mask); + /* Ensure posted write hits. */ + read32(func_dis2); + } + + post_code(0x47); + + /* + * Call early init to initialize memory and chipset. This function returns + * to the romstage_main_continue function with a pointer to the HOB + * structure. + */ + post_code(0x48); + printk(BIOS_DEBUG, "Starting the Intel FSP (early_init)\n"); + fsp_early_init(fsp_info_header); + die("Uh Oh! fsp_early_init should not return here.\n"); +} + +/******************************************************************************* + * The FSP early_init function returns to this function. + * Memory is setup and the stack is set by the FSP. + */ +void romstage_main_continue(EFI_STATUS status, void *hob_list_ptr) { + int cbmem_was_initted; + void *cbmem_hob_ptr; + +#if IS_ENABLED(CONFIG_COLLECT_TIMESTAMPS) + tsc_t after_initram_time = rdtsc(); + tsc_t base_time; + base_time.hi = 0; + base_time.lo = 0; +#endif + + post_code(0x4a); + printk(BIOS_DEBUG, "%s status: %x hob_list_ptr: %x\n", + __func__, (u32) status, (u32) hob_list_ptr); + +#if IS_ENABLED(CONFIG_USBDEBUG_IN_ROMSTAGE) + /* FSP reconfigures USB, so reinit it to have debug */ + usbdebug_init(); +#endif /* IS_ENABLED(CONFIG_USBDEBUG_IN_ROMSTAGE) */ + + printk(BIOS_DEBUG, "FSP Status: 0x%0x\n", (u32)status); + + report_platform_info(); + +#if IS_ENABLED(CONFIG_COLLECT_TIMESTAMPS) + after_initram_time = rdtsc(); +#endif + post_code(0x4b); + + late_mainboard_romstage_entry(); + post_code(0x4c); + + quick_ram_check(); + post_code(0x4d); + + cbmem_was_initted = !cbmem_recovery(0); + + /* Save the HOB pointer in CBMEM to be used in ramstage*/ + cbmem_hob_ptr = cbmem_add (CBMEM_ID_HOB_POINTER, sizeof(*hob_list_ptr)); + *(u32*)cbmem_hob_ptr = (u32)hob_list_ptr; + post_code(0x4e); + +#if IS_ENABLED(CONFIG_COLLECT_TIMESTAMPS) + timestamp_init(base_time); + timestamp_reinit(); + timestamp_add(TS_AFTER_INITRAM, after_initram_time); + timestamp_add_now(TS_END_ROMSTAGE); +#endif + +#if IS_ENABLED(CONFIG_CONSOLE_CBMEM) + printk(BIOS_DEBUG, "cbmemc_reinit\n"); + cbmemc_reinit(); +#endif + post_code(0x4f); + + /* Load the ramstage. */ + copy_and_run(); + while (1); +} diff --git a/src/soc/intel/fsp_baytrail/romstage/uart.c b/src/soc/intel/fsp_baytrail/romstage/uart.c new file mode 100644 index 0000000..971067f --- /dev/null +++ b/src/soc/intel/fsp_baytrail/romstage/uart.c @@ -0,0 +1,38 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 <arch/io.h> +#include <baytrail/gpio.h> +#include <baytrail/iomap.h> +#include <baytrail/lpc.h> +#include <baytrail/pci_devs.h> +#include <baytrail/romstage.h> + +void byt_config_com1_and_enable(void) +{ + uint32_t reg; + + /* Enable the legacy UART hardware. */ + reg = 1; + pci_write_config32(PCI_DEV(0, LPC_DEV, 0), UART_CONT, reg); + + /* Set up the pads to select the UART function */ + score_select_func(UART_RXD_PAD, 1); + score_select_func(UART_TXD_PAD, 1); +} diff --git a/src/soc/intel/fsp_baytrail/smihandler.c b/src/soc/intel/fsp_baytrail/smihandler.c new file mode 100644 index 0000000..2225964 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/smihandler.c @@ -0,0 +1,406 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 <arch/hlt.h> +#include <arch/io.h> +#include <console/console.h> +#include <cpu/x86/cache.h> +#include <cpu/x86/smm.h> +#include <device/pci_def.h> +#include <elog.h> + +#include <baytrail/pci_devs.h> +#include <baytrail/pmc.h> +#include <baytrail/nvs.h> + +/* GNVS needs to be set by coreboot initiating a software SMI. */ +static global_nvs_t *gnvs; +static int smm_initialized; + +int southbridge_io_trap_handler(int smif) +{ + switch (smif) { + case 0x32: + printk(BIOS_DEBUG, "OS Init\n"); + /* gnvs->smif: + * On success, the IO Trap Handler returns 0 + * On failure, the IO Trap Handler returns a value != 0 + */ + gnvs->smif = 0; + return 1; /* IO trap handled */ + } + + /* Not handled */ + return 0; +} + +void southbridge_smi_set_eos(void) +{ + enable_smi(EOS); +} + +global_nvs_t *smm_get_gnvs(void) +{ + return gnvs; +} + +static void busmaster_disable_on_bus(int bus) +{ + int slot, func; + unsigned int val; + unsigned char hdr; + + for (slot = 0; slot < 0x20; slot++) { + for (func = 0; func < 8; func++) { + u32 reg32; + device_t dev = PCI_DEV(bus, slot, func); + + val = pci_read_config32(dev, PCI_VENDOR_ID); + + if (val == 0xffffffff || val == 0x00000000 || + val == 0x0000ffff || val == 0xffff0000) + continue; + + /* Disable Bus Mastering for this one device */ + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 &= ~PCI_COMMAND_MASTER; + pci_write_config32(dev, PCI_COMMAND, reg32); + + /* If this is a bridge, then follow it. */ + hdr = pci_read_config8(dev, PCI_HEADER_TYPE); + hdr &= 0x7f; + if (hdr == PCI_HEADER_TYPE_BRIDGE || + hdr == PCI_HEADER_TYPE_CARDBUS) { + unsigned int buses; + buses = pci_read_config32(dev, PCI_PRIMARY_BUS); + busmaster_disable_on_bus((buses >> 8) & 0xff); + } + } + } +} + +static void southbridge_smi_sleep(void) +{ + uint32_t reg32; + uint8_t slp_typ; + uint16_t pmbase = get_pmbase(); + + /* First, disable further SMIs */ + disable_smi(SLP_SMI_EN); + + /* Figure out SLP_TYP */ + reg32 = inl(pmbase + PM1_CNT); + printk(BIOS_SPEW, "SMI#: SLP = 0x%08x\n", reg32); + slp_typ = (reg32 >> 10) & 7; + + /* Do any mainboard sleep handling */ + mainboard_smi_sleep(slp_typ-2); + +#if IS_ENABLED(CONFIG_ELOG_GSMI) + /* Log S3, S4, and S5 entry */ + if (slp_typ >= 5) + elog_add_event_byte(ELOG_TYPE_ACPI_ENTER, slp_typ-2); +#endif + + /* Next, do the deed. + */ + + switch (slp_typ) { + case SLP_TYP_S0: + printk(BIOS_DEBUG, "SMI#: Entering S0 (On)\n"); + break; + case SLP_TYP_S1: + printk(BIOS_DEBUG, "SMI#: Entering S1 (Assert STPCLK#)\n"); + break; + case SLP_TYP_S3: + printk(BIOS_DEBUG, "SMI#: Entering S3 (Suspend-To-RAM)\n"); + + /* Invalidate the cache before going to S3 */ + wbinvd(); + break; + case SLP_TYP_S4: + printk(BIOS_DEBUG, "SMI#: Entering S4 (Suspend-To-Disk)\n"); + break; + case SLP_TYP_S5: + printk(BIOS_DEBUG, "SMI#: Entering S5 (Soft Power off)\n"); + + /* Disable all GPE */ + disable_all_gpe(); + + /* also iterates over all bridges on bus 0 */ + busmaster_disable_on_bus(0); + break; + default: + printk(BIOS_DEBUG, "SMI#: ERROR: SLP_TYP reserved\n"); + break; + } + + /* Write back to the SLP register to cause the originally intended + * event again. We need to set BIT13 (SLP_EN) though to make the + * sleep happen. + */ + enable_pm1_control(SLP_EN); + + /* Make sure to stop executing code here for S3/S4/S5 */ + if (slp_typ > 1) + hlt(); + + /* In most sleep states, the code flow of this function ends at + * the line above. However, if we entered sleep state S1 and wake + * up again, we will continue to execute code in this function. + */ + reg32 = inl(pmbase + PM1_CNT); + if (reg32 & SCI_EN) { + /* The OS is not an ACPI OS, so we set the state to S0 */ + disable_pm1_control(SLP_EN | SLP_TYP); + } +} + +/* + * Look for Synchronous IO SMI and use save state from that + * core in case we are not running on the same core that + * initiated the IO transaction. + */ +static em64t100_smm_state_save_area_t *smi_apmc_find_state_save(uint8_t cmd) +{ +#ifndef CONFIG_MAX_CPUS +#error CONFIG_MAX_CPUS must be set. +#endif + em64t100_smm_state_save_area_t *state; + int node; + + /* Check all nodes looking for the one that issued the IO */ + for (node = 0; node < CONFIG_MAX_CPUS; node++) { + state = smm_get_save_state(node); + + /* Check for Synchronous IO (bit0==1) */ + if (!(state->io_misc_info & (1 << 0))) + continue; + + /* Make sure it was a write (bit4==0) */ + if (state->io_misc_info & (1 << 4)) + continue; + + /* Check for APMC IO port */ + if (((state->io_misc_info >> 16) & 0xff) != APM_CNT) + continue; + + /* Check AX against the requested command */ + if ((state->rax & 0xff) != cmd) + continue; + + return state; + } + + return NULL; +} + +#if IS_ENABLED(CONFIG_ELOG_GSMI) +static void southbridge_smi_gsmi(void) +{ + u32 *ret, *param; + uint8_t sub_command; + em64t100_smm_state_save_area_t *io_smi = + smi_apmc_find_state_save(ELOG_GSMI_APM_CNT); + + if (!io_smi) + return; + + /* Command and return value in EAX */ + ret = (u32*)&io_smi->rax; + sub_command = (uint8_t)(*ret >> 8); + + /* Parameter buffer in EBX */ + param = (u32*)&io_smi->rbx; + + /* drivers/elog/gsmi.c */ + *ret = gsmi_exec(sub_command, param); +} +#endif +static void southbridge_smi_apmc(void) +{ + uint8_t reg8; + em64t100_smm_state_save_area_t *state; + + /* Emulate B2 register as the FADT / Linux expects it */ + + reg8 = inb(APM_CNT); + switch (reg8) { + case APM_CNT_CST_CONTROL: + /* Calling this function seems to cause + * some kind of race condition in Linux + * and causes a kernel oops + */ + printk(BIOS_DEBUG, "C-state control\n"); + break; + case APM_CNT_PST_CONTROL: + /* Calling this function seems to cause + * some kind of race condition in Linux + * and causes a kernel oops + */ + printk(BIOS_DEBUG, "P-state control\n"); + break; + case APM_CNT_ACPI_DISABLE: + disable_pm1_control(SCI_EN); + printk(BIOS_DEBUG, "SMI#: ACPI disabled.\n"); + break; + case APM_CNT_ACPI_ENABLE: + enable_pm1_control(SCI_EN); + printk(BIOS_DEBUG, "SMI#: ACPI enabled.\n"); + break; + case APM_CNT_GNVS_UPDATE: + if (smm_initialized) { + printk(BIOS_DEBUG, + "SMI#: SMM structures already initialized!\n"); + return; + } + state = smi_apmc_find_state_save(reg8); + if (state) { + /* EBX in the state save contains the GNVS pointer */ + gnvs = (global_nvs_t *)((uint32_t)state->rbx); + smm_initialized = 1; + printk(BIOS_DEBUG, "SMI#: Setting GNVS to %p\n", gnvs); + } + break; +#if IS_ENABLED(CONFIG_ELOG_GSMI) + case ELOG_GSMI_APM_CNT: + southbridge_smi_gsmi(); + break; +#endif + } + + mainboard_smi_apmc(reg8); +} + +static void southbridge_smi_pm1(void) +{ + uint16_t pm1_sts = clear_pm1_status(); + + /* While OSPM is not active, poweroff immediately + * on a power button event. + */ + if (pm1_sts & PWRBTN_STS) { + // power button pressed +#if IS_ENABLED(CONFIG_ELOG_GSMI) + elog_add_event(ELOG_TYPE_POWER_BUTTON); +#endif + disable_pm1_control(-1UL); + enable_pm1_control(SLP_EN | (SLP_TYP_S5 << SLP_TYP_SHIFT)); + } +} + +static void southbridge_smi_gpe0(void) +{ + clear_gpe_status(); +} + +static void southbridge_smi_tco(void) +{ + uint32_t tco_sts = clear_tco_status(); + + /* Any TCO event? */ + if (!tco_sts) + return; + + if (tco_sts & TCO_TIMEOUT) { /* TIMEOUT */ + /* Handle TCO timeout */ + printk(BIOS_DEBUG, "TCO Timeout.\n"); + } +} + +static void southbridge_smi_periodic(void) +{ + uint32_t reg32; + + reg32 = inl(get_pmbase() + SMI_EN); + + /* Are periodic SMIs enabled? */ + if ((reg32 & PERIODIC_EN) == 0) + return; + + printk(BIOS_DEBUG, "Periodic SMI.\n"); +} + +typedef void (*smi_handler_t)(void); + +static const smi_handler_t southbridge_smi[32] = { + NULL, // [0] reserved + NULL, // [1] reserved + NULL, // [2] BIOS_STS + NULL, // [3] LEGACY_USB_STS + southbridge_smi_sleep, // [4] SLP_SMI_STS + southbridge_smi_apmc, // [5] APM_STS + NULL, // [6] SWSMI_TMR_STS + NULL, // [7] reserved + southbridge_smi_pm1, // [8] PM1_STS + southbridge_smi_gpe0, // [9] GPE0_STS + NULL, // [10] reserved + NULL, // [11] reserved + NULL, // [12] reserved + southbridge_smi_tco, // [13] TCO_STS + southbridge_smi_periodic, // [14] PERIODIC_STS + NULL, // [15] SERIRQ_SMI_STS + NULL, // [16] SMBUS_SMI_STS + NULL, // [17] LEGACY_USB2_STS + NULL, // [18] INTEL_USB2_STS + NULL, // [19] reserved + NULL, // [20] PCI_EXP_SMI_STS + NULL, // [21] reserved + NULL, // [22] reserved + NULL, // [23] reserved + NULL, // [24] reserved + NULL, // [25] reserved + NULL, // [26] SPI_STS + NULL, // [27] reserved + NULL, // [28] PUNIT + NULL, // [29] GUNIT + NULL, // [30] reserved + NULL // [31] reserved +}; + +void southbridge_smi_handler(void) +{ + int i; + uint32_t smi_sts; + + /* We need to clear the SMI status registers, or we won't see what's + * happening in the following calls. + */ + smi_sts = clear_smi_status(); + + /* Call SMI sub handler for each of the status bits */ + for (i = 0; i < ARRAY_SIZE(southbridge_smi); i++) { + if (!(smi_sts & (1 << i))) + continue; + + if (southbridge_smi[i] != NULL) { + southbridge_smi[i](); + } else { + printk(BIOS_DEBUG, + "SMI_STS[%d] occured, but no " + "handler available.\n", i); + } + } + + /* The GPIO SMI events do not have a status bit in SMI_STS. Therefore, + * these events need to be cleared and checked unconditionally. */ + mainboard_smi_gpi(clear_alt_status()); +} diff --git a/src/soc/intel/fsp_baytrail/smm.c b/src/soc/intel/fsp_baytrail/smm.c new file mode 100644 index 0000000..d4b3d58 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/smm.c @@ -0,0 +1,132 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 <device/device.h> +#include <device/pci.h> +#include <console/console.h> +#include <arch/io.h> +#include <cpu/cpu.h> +#include <cpu/x86/smm.h> +#include <string.h> + +#include <baytrail/iomap.h> +#include <baytrail/pmc.h> +#include <baytrail/smm.h> + +/* Save the gpio route register. The settings are committed from + * southcluster_smm_enable_smi(). */ +static uint32_t gpio_route; + +void southcluster_smm_save_gpio_route(uint32_t route) +{ + gpio_route = route; +} + +void southcluster_smm_clear_state(void) +{ + uint32_t smi_en; + + /* Log events from chipset before clearing */ + southcluster_log_state(); + + printk(BIOS_DEBUG, "Initializing Southbridge SMI..."); + printk(BIOS_SPEW, " pmbase = 0x%04x\n", get_pmbase()); + + smi_en = inl(get_pmbase() + SMI_EN); + if (smi_en & APMC_EN) { + printk(BIOS_INFO, "SMI# handler already enabled?\n"); + return; + } + + /* Dump and clear status registers */ + clear_smi_status(); + clear_pm1_status(); + clear_tco_status(); + clear_gpe_status(); + clear_alt_status(); + clear_pmc_status(); +} + +static void southcluster_smm_route_gpios(void) +{ + const unsigned long gpio_rout = PMC_BASE_ADDRESS + GPIO_ROUT; + const unsigned short alt_gpio_smi = ACPI_BASE_ADDRESS + ALT_GPIO_SMI; + uint32_t alt_gpio_reg = 0; + uint32_t route_reg = gpio_route; + int i; + + printk(BIOS_DEBUG, "GPIO_ROUT = %08x\n", route_reg); + + /* Start the routing for the specific gpios. */ + write32(gpio_rout, route_reg); + + /* Enable SMIs for the gpios that are set to trigger the SMI. */ + for (i = 0; i < 16; i++) { + if ((route_reg & ROUTE_MASK) == ROUTE_SMI) { + alt_gpio_reg |= (1 << i); + } + route_reg >>= 2; + } + printk(BIOS_DEBUG, "ALT_GPIO_SMI = %08x\n", alt_gpio_reg); + + outl(alt_gpio_reg, alt_gpio_smi); +} + +void southcluster_smm_enable_smi(void) +{ + + printk(BIOS_DEBUG, "Enabling SMIs.\n"); + /* Configure events Disable pcie wake. */ + enable_pm1(PWRBTN_EN | GBL_EN | PCIEXPWAK_DIS); + disable_gpe(PME_B0_EN); + + /* Set up the GPIO route. */ + southcluster_smm_route_gpios(); + + /* Enable SMI generation: + * - on APMC writes (io 0xb2) + * - on writes to SLP_EN (sleep states) + * - on writes to GBL_RLS (bios commands) + * No SMIs: + * - on TCO events + * - on microcontroller writes (io 0x62/0x66) + */ + enable_smi(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | EOS); +} + +void smm_setup_structures(void *gnvs, void *tcg, void *smi1) +{ + /* + * Issue SMI to set the gnvs pointer in SMM. + * tcg and smi1 are unused. + * + * EAX = APM_CNT_GNVS_UPDATE + * EBX = gnvs pointer + * EDX = APM_CNT + */ + asm volatile ( + "outb %%al, %%dx\n\t" + : /* ignore result */ + : "a" (APM_CNT_GNVS_UPDATE), + "b" ((uint32_t)gnvs), + "d" (APM_CNT) + ); +} diff --git a/src/soc/intel/fsp_baytrail/southcluster.c b/src/soc/intel/fsp_baytrail/southcluster.c new file mode 100644 index 0000000..ed92c60 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/southcluster.c @@ -0,0 +1,661 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2013-2014 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 <arch/io.h> +#include <arch/ioapic.h> +#include <cbmem.h> +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_def.h> +#include <pc80/mc146818rtc.h> +#include <pc80/i8254.h> +#include <pc80/i8259.h> +#include <pc80/isa-dma.h> +#include <romstage_handoff.h> + +#include <baytrail/baytrail.h> +#include <baytrail/iomap.h> +#include <baytrail/irq.h> +#include <baytrail/lpc.h> +#include <baytrail/nvs.h> +#include <baytrail/pci_devs.h> +#include <baytrail/pmc.h> +#include <baytrail/ramstage.h> +#include "chip.h" + +#define ENABLE_ACPI_MODE_IN_COREBOOT 0 +#define TEST_SMM_FLASH_LOCKDOWN 0 + +typedef struct soc_intel_fsp_baytrail_config config_t; + +static inline void +add_mmio_resource(device_t dev, int i, unsigned long addr, unsigned long size) +{ + mmio_resource(dev, i, addr >> 10, size >> 10); +} + +static void sc_add_mmio_resources(device_t dev) +{ +#ifndef CONFIG_VIRTUAL_ROM_SIZE +#error CONFIG_VIRTUAL_ROM_SIZE must be set. +#endif + add_mmio_resource(dev, 0xfeb, ABORT_BASE_ADDRESS, ABORT_BASE_SIZE); + add_mmio_resource(dev, PBASE, PMC_BASE_ADDRESS, PMC_BASE_SIZE); + add_mmio_resource(dev, IOBASE, IO_BASE_ADDRESS, IO_BASE_SIZE); + add_mmio_resource(dev, IBASE, ILB_BASE_ADDRESS, ILB_BASE_SIZE); + add_mmio_resource(dev, SBASE, SPI_BASE_ADDRESS, SPI_BASE_SIZE); + add_mmio_resource(dev, MPBASE, MPHY_BASE_ADDRESS, MPHY_BASE_SIZE); + add_mmio_resource(dev, PUBASE, PUNIT_BASE_ADDRESS, PUNIT_BASE_SIZE); + add_mmio_resource(dev, RCBA, RCBA_BASE_ADDRESS, RCBA_BASE_SIZE); + add_mmio_resource(dev, 0xfff, 0xffffffff - CONFIG_VIRTUAL_ROM_SIZE + 1, + CONFIG_VIRTUAL_ROM_SIZE); /* BIOS ROM */ + add_mmio_resource(dev, 0xfec, IO_APIC_ADDR, 0x00001000); /* IOAPIC */ +} + +/* Default IO range claimed by the LPC device. The upper bound is exclusive. */ +#define LPC_DEFAULT_IO_RANGE_LOWER 0 +#define LPC_DEFAULT_IO_RANGE_UPPER 0x1000 + +static void sc_enable_ioapic(struct device *dev) +{ + int i; + u32 reg32; + volatile u32 *ioapic_index = (volatile u32 *)(IO_APIC_ADDR); + volatile u32 *ioapic_data = (volatile u32 *)(IO_APIC_ADDR + 0x10); + u32 ilb_base = pci_read_config32(dev, IBASE) & ~0x0f; + + /* + * Enable ACPI I/O and power management. + * Set SCI IRQ to IRQ9 + */ + write32(ilb_base + ILB_OIC, 0x100); /* AEN */ + reg32 = read32(ilb_base + ILB_OIC); /* Read back per BWG */ + write32(ilb_base + ILB_ACTL, 0); /* ACTL bit 2:0 SCIS IRQ9 */ + + *ioapic_index = 0; + *ioapic_data = (1 << 25); + + /* affirm full set of redirection table entries ("write once") */ + *ioapic_index = 1; + reg32 = *ioapic_data; + *ioapic_index = 1; + *ioapic_data = reg32; + + *ioapic_index = 0; + reg32 = *ioapic_data; + printk(BIOS_DEBUG, "Southbridge APIC ID = %x\n", (reg32 >> 24) & 0x0f); + if (reg32 != (1 << 25)) + die("APIC Error\n"); + + printk(BIOS_SPEW, "Dumping IOAPIC registers\n"); + for (i=0; i<3; i++) { + *ioapic_index = i; + printk(BIOS_SPEW, " reg 0x%04x:", i); + reg32 = *ioapic_data; + printk(BIOS_SPEW, " 0x%08x\n", reg32); + } + + *ioapic_index = 3; /* Select Boot Configuration register. */ + *ioapic_data = 1; /* Use Processor System Bus to deliver interrupts. */ +} + +static void sc_enable_serial_irqs(struct device *dev) +{ +#ifdef SETUPSERIQ /* NOT defined. Remove when the TODO is done. */ + /* + * TODO: SERIRQ seems to have a number of problems on baytrail. + * With it enabled, we get some spurious interrupts (ps2) + * in seabios. It also caused IOCHK# NMIs. Remove it + * until we understand how it needs to be configured. + */ + u8 reg8; + u32 ibase = pci_read_config32(dev, IBASE) & ~0xF; + + /* + * Disable the IOCHK# NMI. Let the NMI handler enable it if it needs. + */ + reg8 = inb(0x61); + reg8 &= 0x0f; /* Higher Nibble must be 0 */ + reg8 |= (1 << 3); /* IOCHK# NMI Disable for now */ + outb(reg8, 0x61); + + write32(ibase + ILB_OIC, read32(ibase + ILB_OIC) | SIRQEN); + write8(ibase + ILB_SERIRQ_CNTL, SCNT_CONTINUOUS_MODE); + +#if !IS_ENABLED(CONFIG_SERIRQ_CONTINUOUS_MODE) + /* + * SoC requires that the System BIOS first set the SERIRQ logic to + * continuous mode operation for at least one frame before switching + * it into quiet mode operation. + */ + outb(0x00, 0xED); /* I/O Delay to get the 1 frame */ + write8(ibase + ILB_SERIRQ_CNTL, SCNT_QUIET_MODE); +#endif +#endif /* DON'T SET UP IRQS */ +} + +/* + * Write PCI config space IRQ assignments. PCI devices have the INT_LINE + * (0x3C) and INT_PIN (0x3D) registers which report interrupt routing + * information to operating systems and drivers. The INT_PIN register is + * generally read only and reports which interrupt pin A - D it uses. The + * INT_LINE register is configurable and reports which IRQ (generally the + * PIC IRQs 1 - 15) it will use. This needs to take interrupt pin swizzling + * on devices that are downstream on a PCI bridge into account. + * + * This function will loop through all enabled PCI devices and program the + * INT_LINE register with the correct PIC IRQ number for the INT_PIN that it + * uses. It then configures each interrupt in the pic to be level triggered. + */ +static void write_pci_config_irqs(void) +{ + device_t irq_dev; + device_t targ_dev; + uint8_t int_line = 0; + uint8_t original_int_pin = 0; + uint8_t new_int_pin = 0; + uint16_t current_bdf = 0; + uint16_t parent_bdf = 0; + uint8_t pirq = 0; + uint8_t device_num = 0; + const struct baytrail_irq_route *ir = &global_baytrail_irq_route; + + if (ir == NULL) { + printk(BIOS_WARNING, "Warning: Can't write PCI IRQ assignments because" + " 'global_baytrail_irq_route' structure does not exist\n"); + return; + } + + /* + * Loop through all enabled devices and program their + * INT_LINE, INT_PIN registers from values taken from + * the Interrupt Route registers in the ILB + */ + printk(BIOS_DEBUG, "PCI_CFG IRQ: Write PCI config space IRQ assignments\n"); + for(irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) { + + if ((irq_dev->path.type != DEVICE_PATH_PCI) || + (!irq_dev->enabled)) + continue; + + current_bdf = irq_dev->path.pci.devfn | + irq_dev->bus->secondary << 8; + + /* + * Step 1: Get the INT_PIN and device structure to look for + * in the pirq_data table defined in the mainboard directory. + */ + targ_dev = NULL; + new_int_pin = get_irq_pins(irq_dev, &targ_dev); + if (targ_dev == NULL || new_int_pin < 1) + continue; + + /* Get the original INT_PIN for record keeping */ + original_int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN); + + parent_bdf = targ_dev->path.pci.devfn + | targ_dev->bus->secondary << 8; + device_num = PCI_SLOT(parent_bdf); + + if (ir->pcidev[device_num] == 0) { + printk(BIOS_WARNING, + "Warning: PCI Device %d does not have an IRQ entry, skipping it\n", + device_num); + continue; + } + + /* Find the PIRQ that is attached to the INT_PIN this device uses */ + pirq = (ir->pcidev[device_num] >> ((new_int_pin - 1) * 4)) & 0xF; + + /* Get the INT_LINE this device/function will use */ + int_line = ir->pic[pirq]; + + if (int_line != PIRQ_PIC_IRQDISABLE) { + /* Set this IRQ to level triggered since it is used by a PCI device */ + i8259_configure_irq_trigger(int_line, IRQ_LEVEL_TRIGGERED); + /* Set the Interrupt Line register in PCI config space */ + pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line); + } else { + /* Set the Interrupt line register as "unknown or unused" */ + pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, + PIRQ_PIC_UNKNOWN_UNUSED); + } + + printk(BIOS_SPEW, "\tINT_PIN\t\t: %d (%s)\n", + original_int_pin, pin_to_str(original_int_pin)); + if (parent_bdf != current_bdf) + printk(BIOS_SPEW, "\tSwizzled to\t: %d (%s)\n", + new_int_pin, pin_to_str(new_int_pin)); + printk(BIOS_SPEW, "\tPIRQ\t\t: %c\n" + "\tINT_LINE\t: 0x%X (IRQ %d)\n", + 'A' + pirq, int_line, int_line); + } + printk(BIOS_DEBUG, "PCI_CFG IRQ: Finished writing PCI config space IRQ assignments\n"); +} + +static void sc_pirq_init(device_t dev) +{ + int i, j; + int pirq; + const unsigned long pr_base = ILB_BASE_ADDRESS + 0x08; + const unsigned long ir_base = ILB_BASE_ADDRESS + 0x20; + const unsigned long actl = ILB_BASE_ADDRESS + ACTL; + const struct baytrail_irq_route *ir = &global_baytrail_irq_route; + + /* Set up the PIRQ PIC routing based on static config. */ + printk(BIOS_SPEW, "Start writing IRQ assignments\n" + "PIRQ\tA \tB \tC \tD \tE \tF \tG \tH\n" + "IRQ "); + for (i = 0; i < NUM_PIRQS; i++) { + write8(pr_base + i*sizeof(ir->pic[i]), ir->pic[i]); + printk(BIOS_SPEW, "\t%d", ir->pic[i]); + } + printk(BIOS_SPEW, "\n\n"); + + /* Set up the per device PIRQ routing based on static config. */ + printk(BIOS_SPEW, "\t\t\tPIRQ[A-H] routed to each INT_PIN[A-D]\n" + "Dev\tINTA (IRQ)\tINTB (IRQ)\tINTC (IRQ)\tINTD (IRQ)\n"); + for (i = 0; i < NUM_OF_PCI_DEVS; i++) { + write16(ir_base + i*sizeof(ir->pcidev[i]), ir->pcidev[i]); + + /* If the entry is more than just 0, print it out */ + if(ir->pcidev[i]) { + printk(BIOS_SPEW, " %d: ", i); + for (j = 0; j < 4; j++) { + pirq = (ir->pcidev[i] >> (j * 4)) & 0xF; + printk(BIOS_SPEW, "\t%-4c (%d)", 'A' + pirq, ir->pic[pirq]); + } + printk(BIOS_SPEW, "\n"); + } + } + + /* Route SCI to IRQ9 */ + write32(actl, (read32(actl) & ~SCIS_MASK) | SCIS_IRQ9); + printk(BIOS_SPEW, "Finished writing IRQ assignments\n"); + + /* Write IRQ assignments to PCI config space */ + write_pci_config_irqs(); +} + +static inline int io_range_in_default(int base, int size) +{ + /* Does it start above the range? */ + if (base >= LPC_DEFAULT_IO_RANGE_UPPER) + return 0; + + /* Is it entirely contained? */ + if (base >= LPC_DEFAULT_IO_RANGE_LOWER && + (base + size) < LPC_DEFAULT_IO_RANGE_UPPER) + return 1; + + /* This will return not in range for partial overlaps. */ + return 0; +} + +/* + * Note: this function assumes there is no overlap with the default LPC device's + * claimed range: LPC_DEFAULT_IO_RANGE_LOWER -> LPC_DEFAULT_IO_RANGE_UPPER. + */ +static void sc_add_io_resource(device_t dev, int base, int size, int index) +{ + struct resource *res; + + if (io_range_in_default(base, size)) + return; + + res = new_resource(dev, index); + res->base = base; + res->size = size; + res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | + IORESOURCE_FIXED; +} + +static void sc_add_io_resources(device_t dev) +{ + struct resource *res; + u8 io_index = 0; + + /* + * Add the default claimed IO range for the LPC device + * and mark it as subtractive decode. + */ + res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0)); + res->base = LPC_DEFAULT_IO_RANGE_LOWER; + res->size = LPC_DEFAULT_IO_RANGE_UPPER - LPC_DEFAULT_IO_RANGE_LOWER; + res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | + IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + + /* GPIO */ + sc_add_io_resource(dev, GPIO_BASE_ADDRESS, GPIO_BASE_SIZE, GBASE); + + /* ACPI */ + sc_add_io_resource(dev, ACPI_BASE_ADDRESS, ACPI_BASE_SIZE, ABASE); +} + +static void sc_read_resources(device_t dev) +{ + /* Get the normal PCI resources of this device. */ + pci_dev_read_resources(dev); + + /* Add non-standard MMIO resources. */ + sc_add_mmio_resources(dev); + + /* Add IO resources. */ + sc_add_io_resources(dev); +} + +static void enable_hpet(void) +{ +} + +static void sc_init(struct device *dev) +{ + u32 ibase; + + printk(BIOS_DEBUG, "soc: southcluster_init\n"); + + ibase = pci_read_config32(dev, IBASE) & ~0xF; + + write8(ibase + ILB_MC, 0); + + /* Set the value for PCI command register. */ + pci_write_config16(dev, PCI_COMMAND, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL); + + /* IO APIC initialization. */ + sc_enable_ioapic(dev); + + sc_enable_serial_irqs(dev); + + /* Setup the PIRQ. */ + sc_pirq_init(dev); + + /* Initialize the High Precision Event Timers, if present. */ + enable_hpet(); + + /* Initialize ISA DMA. */ + isa_dma_init(); + + setup_i8259(); + + setup_i8254(); +} + +/* + * Common code for the south cluster devices. + */ + +/* Set bit in function disable register to hide this device. */ +static void sc_disable_devfn(device_t dev) +{ + const unsigned long func_dis = PMC_BASE_ADDRESS + FUNC_DIS; + const unsigned long func_dis2 = PMC_BASE_ADDRESS + FUNC_DIS2; + uint32_t fd_mask = 0; + uint32_t fd2_mask = 0; + +#define SET_DIS_MASK(name_) \ + case PCI_DEVFN(name_ ## _DEV, name_ ## _FUNC): \ + fd_mask |= name_ ## _DIS +#define SET_DIS_MASK2(name_) \ + case PCI_DEVFN(name_ ## _DEV, name_ ## _FUNC): \ + fd2_mask |= name_ ## _DIS + + switch (dev->path.pci.devfn) { + SET_DIS_MASK(MIPI); + break; + SET_DIS_MASK(EMMC); + break; + SET_DIS_MASK(SDIO); + break; + SET_DIS_MASK(SD); + break; + SET_DIS_MASK(SATA); + break; + SET_DIS_MASK(XHCI); + /* Disable super speed PHY when XHCI is not available. */ + fd2_mask |= USH_SS_PHY_DIS; + break; + SET_DIS_MASK(LPE); + break; + SET_DIS_MASK(MMC45); + break; + SET_DIS_MASK(SIO_DMA1); + break; + SET_DIS_MASK(I2C1); + break; + SET_DIS_MASK(I2C2); + break; + SET_DIS_MASK(I2C3); + break; + SET_DIS_MASK(I2C4); + break; + SET_DIS_MASK(I2C5); + break; + SET_DIS_MASK(I2C6); + break; + SET_DIS_MASK(I2C7); + break; + SET_DIS_MASK(TXE); + break; + SET_DIS_MASK(HDA); + break; + SET_DIS_MASK(PCIE_PORT1); + break; + SET_DIS_MASK(PCIE_PORT2); + break; + SET_DIS_MASK(PCIE_PORT3); + break; + SET_DIS_MASK(PCIE_PORT4); + break; + SET_DIS_MASK(EHCI); + break; + SET_DIS_MASK(SIO_DMA2); + break; + SET_DIS_MASK(PWM1); + break; + SET_DIS_MASK(PWM2); + break; + SET_DIS_MASK(HSUART1); + break; + SET_DIS_MASK(HSUART2); + break; + SET_DIS_MASK(SPI); + break; + SET_DIS_MASK2(SMBUS); + break; + SET_DIS_MASK(OTG); + /* Disable OTG PHY when OTG is not available. */ + fd2_mask |= OTG_SS_PHY_DIS; + break; + } + + if (fd_mask != 0) { + write32(func_dis, read32(func_dis) | fd_mask); + /* Ensure posted write hits. */ + read32(func_dis); + } + + if (fd2_mask != 0) { + write32(func_dis2, read32(func_dis2) | fd2_mask); + /* Ensure posted write hits. */ + read32(func_dis2); + } +} + +static inline void set_d3hot_bits(device_t dev, int offset) +{ + uint32_t reg8; + printk(BIOS_DEBUG, "Power management CAP offset 0x%x.\n", offset); + reg8 = pci_read_config8(dev, offset + 4); + reg8 |= 0x3; + pci_write_config8(dev, offset + 4, reg8); +} + +/* Parts of the audio subsystem are powered by the HDA device. Therefore, one + * cannot put HDA into D3Hot. Instead perform this workaround to make some of + * the audio paths work for LPE audio. */ +static void hda_work_around(device_t dev) +{ + unsigned long gctl = TEMP_BASE_ADDRESS + 0x8; + + /* Need to set magic register 0x43 to 0xd7 in config space. */ + pci_write_config8(dev, 0x43, 0xd7); + + /* Need to set bit 0 of GCTL to take the device out of reset. However, + * that requires setting up the 64-bit BAR. */ + pci_write_config32(dev, PCI_BASE_ADDRESS_0, TEMP_BASE_ADDRESS); + pci_write_config32(dev, PCI_BASE_ADDRESS_1, 0); + pci_write_config8(dev, PCI_COMMAND, PCI_COMMAND_MEMORY); + write32(gctl, read32(gctl) | 0x1); + pci_write_config8(dev, PCI_COMMAND, 0); + pci_write_config32(dev, PCI_BASE_ADDRESS_0, 0); +} + +static int place_device_in_d3hot(device_t dev) +{ + unsigned offset; + + /* Parts of the HDA block are used for LPE audio as well. + * Therefore assume the HDA will never be put into D3Hot. */ + if (dev->path.pci.devfn == PCI_DEVFN(HDA_DEV, HDA_FUNC)) { + hda_work_around(dev); + return 0; + } + + offset = pci_find_capability(dev, PCI_CAP_ID_PM); + + if (offset != 0) { + set_d3hot_bits(dev, offset); + return 0; + } + + /* For some reason some of the devices don't have the capability + * pointer set correctly. Work around this by hard coding the offset. */ +#define DEV_CASE(name_) \ + case PCI_DEVFN(name_ ## _DEV, name_ ## _FUNC) + + switch (dev->path.pci.devfn) { + DEV_CASE(MIPI): + DEV_CASE(SDIO): + DEV_CASE(EMMC): + DEV_CASE(SD): + DEV_CASE(MMC45): + DEV_CASE(LPE): + DEV_CASE(SIO_DMA1): + DEV_CASE(I2C1): + DEV_CASE(I2C2): + DEV_CASE(I2C3): + DEV_CASE(I2C4): + DEV_CASE(I2C5): + DEV_CASE(I2C6): + DEV_CASE(I2C7): + DEV_CASE(SIO_DMA2): + DEV_CASE(PWM1): + DEV_CASE(PWM2): + DEV_CASE(HSUART1): + DEV_CASE(HSUART2): + DEV_CASE(SPI): + DEV_CASE(OTG): + offset = 0x80; + break; + DEV_CASE(SATA): + DEV_CASE(XHCI): + DEV_CASE(EHCI): + offset = 0x70; + break; + DEV_CASE(HDA): + DEV_CASE(SMBUS): + offset = 0x50; + break; + DEV_CASE(TXE): + /* TXE cannot be placed in D3Hot. */ + return 0; + break; + DEV_CASE(PCIE_PORT1): + DEV_CASE(PCIE_PORT2): + DEV_CASE(PCIE_PORT3): + DEV_CASE(PCIE_PORT4): + offset = 0xa0; + break; + } + + if (offset != 0) { + set_d3hot_bits(dev, offset); + return 0; + } + + return -1; +} + +/* Common PCI device function disable. */ +void southcluster_enable_dev(device_t dev) +{ + uint32_t reg32; + + if (!dev->enabled) { + int slot = PCI_SLOT(dev->path.pci.devfn); + int func = PCI_FUNC(dev->path.pci.devfn); + printk(BIOS_DEBUG, "%s: Disabling device: %02x.%01x\n", + dev_path(dev), slot, func); + + /* Ensure memory, io, and bus master are all disabled */ + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 &= ~(PCI_COMMAND_MASTER | + PCI_COMMAND_MEMORY | PCI_COMMAND_IO); + pci_write_config32(dev, PCI_COMMAND, reg32); + + /* Place device in D3Hot */ + if (place_device_in_d3hot(dev) < 0) { + printk(BIOS_WARNING, + "Could not place %02x.%01x into D3Hot. " + "Keeping device visible.\n", slot, func); + return; + } + /* Disable this device if possible */ + sc_disable_devfn(dev); + } else { + /* Enable SERR */ + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 |= PCI_COMMAND_SERR; + pci_write_config32(dev, PCI_COMMAND, reg32); + } +} + +static struct device_operations device_ops = { + .read_resources = sc_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = NULL, + .init = sc_init, + .enable = southcluster_enable_dev, + .scan_bus = scan_static_bus, + .ops_pci = &soc_pci_ops, +}; + +static const struct pci_driver southcluster __pci_driver = { + .ops = &device_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = LPC_DEVID, +}; diff --git a/src/soc/intel/fsp_baytrail/spi.c b/src/soc/intel/fsp_baytrail/spi.c new file mode 100644 index 0000000..ddec2e0 --- /dev/null +++ b/src/soc/intel/fsp_baytrail/spi.c @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * Copyright (C) 2013-2014 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* This file is derived from the flashrom project. */ +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <delay.h> +#include <arch/io.h> +#include <console/console.h> +#include <device/pci_ids.h> +#include <spi_flash.h> + +#include <baytrail/lpc.h> +#include <baytrail/pci_devs.h> + +#ifdef __SMM__ +#define pci_read_config_byte(dev, reg, targ)\ + *(targ) = pci_read_config8(dev, reg) +#define pci_read_config_word(dev, reg, targ)\ + *(targ) = pci_read_config16(dev, reg) +#define pci_read_config_dword(dev, reg, targ)\ + *(targ) = pci_read_config32(dev, reg) +#define pci_write_config_byte(dev, reg, val)\ + pci_write_config8(dev, reg, val) +#define pci_write_config_word(dev, reg, val)\ + pci_write_config16(dev, reg, val) +#define pci_write_config_dword(dev, reg, val)\ + pci_write_config32(dev, reg, val) +#else /* !__SMM__ */ +#include <device/device.h> +#include <device/pci.h> +#define pci_read_config_byte(dev, reg, targ)\ + *(targ) = pci_read_config8(dev, reg) +#define pci_read_config_word(dev, reg, targ)\ + *(targ) = pci_read_config16(dev, reg) +#define pci_read_config_dword(dev, reg, targ)\ + *(targ) = pci_read_config32(dev, reg) +#define pci_write_config_byte(dev, reg, val)\ + pci_write_config8(dev, reg, val) +#define pci_write_config_word(dev, reg, val)\ + pci_write_config16(dev, reg, val) +#define pci_write_config_dword(dev, reg, val)\ + pci_write_config32(dev, reg, val) +#endif /* !__SMM__ */ + +typedef struct spi_slave ich_spi_slave; + +static int ichspi_lock = 0; + +typedef struct ich9_spi_regs { + uint32_t bfpr; + uint16_t hsfs; + uint16_t hsfc; + uint32_t faddr; + uint32_t _reserved0; + uint32_t fdata[16]; + uint32_t frap; + uint32_t freg[5]; + uint32_t _reserved1[3]; + uint32_t pr[5]; + uint32_t _reserved2[2]; + uint8_t ssfs; + uint8_t ssfc[3]; + uint16_t preop; + uint16_t optype; + uint8_t opmenu[8]; + uint32_t bbar; + uint8_t _reserved3[12]; + uint32_t fdoc; + uint32_t fdod; + uint8_t _reserved4[8]; + uint32_t afc; + uint32_t lvscc; + uint32_t uvscc; + uint8_t _reserved5[4]; + uint32_t fpb; + uint8_t _reserved6[28]; + uint32_t srdl; + uint32_t srdc; + uint32_t srd; +} __attribute__((packed)) ich9_spi_regs; + +typedef struct ich_spi_controller { + int locked; + + uint8_t *opmenu; + int menubytes; + uint16_t *preop; + uint16_t *optype; + uint32_t *addr; + uint8_t *data; + unsigned databytes; + uint8_t *status; + uint16_t *control; + uint32_t *bbar; +} ich_spi_controller; + +static ich_spi_controller cntlr; + +enum { + SPIS_SCIP = 0x0001, + SPIS_GRANT = 0x0002, + SPIS_CDS = 0x0004, + SPIS_FCERR = 0x0008, + SSFS_AEL = 0x0010, + SPIS_LOCK = 0x8000, + SPIS_RESERVED_MASK = 0x7ff0, + SSFS_RESERVED_MASK = 0x7fe2 +}; + +enum { + SPIC_SCGO = 0x000002, + SPIC_ACS = 0x000004, + SPIC_SPOP = 0x000008, + SPIC_DBC = 0x003f00, + SPIC_DS = 0x004000, + SPIC_SME = 0x008000, + SSFC_SCF_MASK = 0x070000, + SSFC_RESERVED = 0xf80000 +}; + +enum { + HSFS_FDONE = 0x0001, + HSFS_FCERR = 0x0002, + HSFS_AEL = 0x0004, + HSFS_BERASE_MASK = 0x0018, + HSFS_BERASE_SHIFT = 3, + HSFS_SCIP = 0x0020, + HSFS_FDOPSS = 0x2000, + HSFS_FDV = 0x4000, + HSFS_FLOCKDN = 0x8000 +}; + +enum { + HSFC_FGO = 0x0001, + HSFC_FCYCLE_MASK = 0x0006, + HSFC_FCYCLE_SHIFT = 1, + HSFC_FDBC_MASK = 0x3f00, + HSFC_FDBC_SHIFT = 8, + HSFC_FSMIE = 0x8000 +}; + +enum { + SPI_OPCODE_TYPE_READ_NO_ADDRESS = 0, + SPI_OPCODE_TYPE_WRITE_NO_ADDRESS = 1, + SPI_OPCODE_TYPE_READ_WITH_ADDRESS = 2, + SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS = 3 +}; + +#if IS_ENABLED(CONFIG_DEBUG_SPI_FLASH) + +static u8 readb_(const void *addr) +{ + u8 v = read8((unsigned long)addr); + printk(BIOS_DEBUG, "read %2.2x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static u16 readw_(const void *addr) +{ + u16 v = read16((unsigned long)addr); + printk(BIOS_DEBUG, "read %4.4x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static u32 readl_(const void *addr) +{ + u32 v = read32((unsigned long)addr); + printk(BIOS_DEBUG, "read %8.8x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static void writeb_(u8 b, const void *addr) +{ + write8((unsigned long)addr, b); + printk(BIOS_DEBUG, "wrote %2.2x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +static void writew_(u16 b, const void *addr) +{ + write16((unsigned long)addr, b); + printk(BIOS_DEBUG, "wrote %4.4x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +static void writel_(u32 b, const void *addr) +{ + write32((unsigned long)addr, b); + printk(BIOS_DEBUG, "wrote %8.8x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +#else /* CONFIG_DEBUG_SPI_FLASH ^^^ enabled vvv NOT enabled */ + +#define readb_(a) read8((uint32_t)a) +#define readw_(a) read16((uint32_t)a) +#define readl_(a) read32((uint32_t)a) +#define writeb_(val, addr) write8((uint32_t)addr, val) +#define writew_(val, addr) write16((uint32_t)addr, val) +#define writel_(val, addr) write32((uint32_t)addr, val) + +#endif /* CONFIG_DEBUG_SPI_FLASH ^^^ NOT enabled */ + +static void write_reg(const void *value, void *dest, uint32_t size) +{ + const uint8_t *bvalue = value; + uint8_t *bdest = dest; + + while (size >= 4) { + writel_(*(const uint32_t *)bvalue, bdest); + bdest += 4; bvalue += 4; size -= 4; + } + while (size) { + writeb_(*bvalue, bdest); + bdest++; bvalue++; size--; + } +} + +static void read_reg(const void *src, void *value, uint32_t size) +{ + const uint8_t *bsrc = src; + uint8_t *bvalue = value; + + while (size >= 4) { + *(uint32_t *)bvalue = readl_(bsrc); + bsrc += 4; bvalue += 4; size -= 4; + } + while (size) { + *bvalue = readb_(bsrc); + bsrc++; bvalue++; size--; + } +} + +static void ich_set_bbar(uint32_t minaddr) +{ + const uint32_t bbar_mask = 0x00ffff00; + uint32_t ichspi_bbar; + + minaddr &= bbar_mask; + ichspi_bbar = readl_(cntlr.bbar) & ~bbar_mask; + ichspi_bbar |= minaddr; + writel_(ichspi_bbar, cntlr.bbar); +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + printk(BIOS_DEBUG, "spi_cs_is_valid used but not implemented\n"); + return 0; +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + ich_spi_slave *slave = malloc(sizeof(*slave)); + + if (!slave) { + printk(BIOS_DEBUG, "ICH SPI: Bad allocation\n"); + return NULL; + } + + memset(slave, 0, sizeof(*slave)); + + slave->bus = bus; + slave->cs = cs; + return slave; +} + +static ich9_spi_regs *spi_regs(void) +{ + device_t dev; + uint32_t sbase; + +#ifdef __SMM__ + dev = PCI_DEV(0, LPC_DEV, LPC_FUNC); +#else + dev = dev_find_slot(0, PCI_DEVFN(LPC_DEV, LPC_FUNC)); +#endif + pci_read_config_dword(dev, SBASE, &sbase); + sbase &= ~0x1ff; + + return (void *)sbase; +} + +void spi_init(void) +{ + ich9_spi_regs *ich9_spi = spi_regs(); + + ichspi_lock = readw_(&ich9_spi->hsfs) & HSFS_FLOCKDN; + cntlr.opmenu = ich9_spi->opmenu; + cntlr.menubytes = sizeof(ich9_spi->opmenu); + cntlr.optype = &ich9_spi->optype; + cntlr.addr = &ich9_spi->faddr; + cntlr.data = (uint8_t *)ich9_spi->fdata; + cntlr.databytes = sizeof(ich9_spi->fdata); + cntlr.status = &ich9_spi->ssfs; + cntlr.control = (uint16_t *)ich9_spi->ssfc; + cntlr.bbar = &ich9_spi->bbar; + cntlr.preop = &ich9_spi->preop; + ich_set_bbar(0); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +void spi_cs_activate(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +typedef struct spi_transaction { + const uint8_t *out; + uint32_t bytesout; + uint8_t *in; + uint32_t bytesin; + uint8_t type; + uint8_t opcode; + uint32_t offset; +} spi_transaction; + +static inline void spi_use_out(spi_transaction *trans, unsigned bytes) +{ + trans->out += bytes; + trans->bytesout -= bytes; +} + +static inline void spi_use_in(spi_transaction *trans, unsigned bytes) +{ + trans->in += bytes; + trans->bytesin -= bytes; +} + +static void spi_setup_type(spi_transaction *trans) +{ + trans->type = 0xFF; + + /* Try to guess spi type from read/write sizes. */ + if (trans->bytesin == 0) { + if (trans->bytesout > 4) + /* + * If bytesin = 0 and bytesout > 4, we presume this is + * a write data operation, which is accompanied by an + * address. + */ + trans->type = SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS; + else + trans->type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS; + return; + } + + if (trans->bytesout == 1) { /* and bytesin is > 0 */ + trans->type = SPI_OPCODE_TYPE_READ_NO_ADDRESS; + return; + } + + if (trans->bytesout == 4) { /* and bytesin is > 0 */ + trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS; + } + + /* Fast read command is called with 5 bytes instead of 4 */ + if (trans->out[0] == SPI_OPCODE_FAST_READ && trans->bytesout == 5) { + trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS; + --trans->bytesout; + } +} + +static int spi_setup_opcode(spi_transaction *trans) +{ + uint16_t optypes; + uint8_t opmenu[cntlr.menubytes]; + + trans->opcode = trans->out[0]; + spi_use_out(trans, 1); + if (!ichspi_lock) { + /* The lock is off, so just use index 0. */ + writeb_(trans->opcode, cntlr.opmenu); + optypes = readw_(cntlr.optype); + optypes = (optypes & 0xfffc) | (trans->type & 0x3); + writew_(optypes, cntlr.optype); + return 0; + } else { + /* The lock is on. See if what we need is on the menu. */ + uint8_t optype; + uint16_t opcode_index; + + /* Write Enable is handled as atomic prefix */ + if (trans->opcode == SPI_OPCODE_WREN) + return 0; + + read_reg(cntlr.opmenu, opmenu, sizeof(opmenu)); + for (opcode_index = 0; opcode_index < cntlr.menubytes; + opcode_index++) { + if (opmenu[opcode_index] == trans->opcode) + break; + } + + if (opcode_index == cntlr.menubytes) { + printk(BIOS_DEBUG, "ICH SPI: Opcode %x not found\n", + trans->opcode); + return -1; + } + + optypes = readw_(cntlr.optype); + optype = (optypes >> (opcode_index * 2)) & 0x3; + if (trans->type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS && + optype == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS && + trans->bytesout >= 3) { + /* We guessed wrong earlier. Fix it up. */ + trans->type = optype; + } + if (optype != trans->type) { + printk(BIOS_DEBUG, "ICH SPI: Transaction doesn't fit type %d\n", + optype); + return -1; + } + return opcode_index; + } +} + +static int spi_setup_offset(spi_transaction *trans) +{ + /* Separate the SPI address and data. */ + switch (trans->type) { + case SPI_OPCODE_TYPE_READ_NO_ADDRESS: + case SPI_OPCODE_TYPE_WRITE_NO_ADDRESS: + return 0; + case SPI_OPCODE_TYPE_READ_WITH_ADDRESS: + case SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS: + trans->offset = ((uint32_t)trans->out[0] << 16) | + ((uint32_t)trans->out[1] << 8) | + ((uint32_t)trans->out[2] << 0); + spi_use_out(trans, 3); + return 1; + default: + printk(BIOS_DEBUG, "Unrecognized SPI transaction type %#x\n", trans->type); + return -1; + } +} + +/* + * Wait for up to 60ms til status register bit(s) turn 1 (in case wait_til_set + * below is True) or 0. In case the wait was for the bit(s) to set - write + * those bits back, which would cause resetting them. + * + * Return the last read status value on success or -1 on failure. + */ +static int ich_status_poll(u16 bitmask, int wait_til_set) +{ + int timeout = 40000; /* This will result in 400 ms */ + u16 status = 0; + + while (timeout--) { + status = readw_(cntlr.status); + if (wait_til_set ^ ((status & bitmask) == 0)) { + if (wait_til_set) + writew_((status & bitmask), cntlr.status); + return status; + } + udelay(10); + } + + printk(BIOS_DEBUG, "ICH SPI: SCIP timeout, read %x, expected %x\n", + status, bitmask); + return -1; +} + +int spi_xfer(struct spi_slave *slave, const void *dout, + unsigned int bitsout, void *din, unsigned int bitsin) +{ + uint16_t control; + int16_t opcode_index; + int with_address; + int status; + + spi_transaction trans = { + dout, bitsout / 8, + din, bitsin / 8, + 0xff, 0xff, 0 + }; + + /* There has to always at least be an opcode. */ + if (!bitsout || !dout) { + printk(BIOS_DEBUG, "ICH SPI: No opcode for transfer\n"); + return -1; + } + /* Make sure if we read something we have a place to put it. */ + if (bitsin != 0 && !din) { + printk(BIOS_DEBUG, "ICH SPI: Read but no target buffer\n"); + return -1; + } + /* Right now we don't support writing partial bytes. */ + if (bitsout % 8 || bitsin % 8) { + printk(BIOS_DEBUG, "ICH SPI: Accessing partial bytes not supported\n"); + return -1; + } + + if (ich_status_poll(SPIS_SCIP, 0) == -1) + return -1; + + writew_(SPIS_CDS | SPIS_FCERR, cntlr.status); + + spi_setup_type(&trans); + if ((opcode_index = spi_setup_opcode(&trans)) < 0) + return -1; + if ((with_address = spi_setup_offset(&trans)) < 0) + return -1; + + if (!ichspi_lock && trans.opcode == SPI_OPCODE_WREN) { + /* + * Treat Write Enable as Atomic Pre-Op if possible + * in order to prevent the Management Engine from + * issuing a transaction between WREN and DATA. + */ + writew_(trans.opcode, cntlr.preop); + return 0; + } + + /* Preset control fields */ + control = SPIC_SCGO | ((opcode_index & 0x07) << 4); + + /* Issue atomic preop cycle if needed */ + if (readw_(cntlr.preop)) + control |= SPIC_ACS; + + if (!trans.bytesout && !trans.bytesin) { + /* SPI addresses are 24 bit only */ + if (with_address) + writel_(trans.offset & 0x00FFFFFF, cntlr.addr); + + /* + * This is a 'no data' command (like Write Enable), its + * bitesout size was 1, decremented to zero while executing + * spi_setup_opcode() above. Tell the chip to send the + * command. + */ + writew_(control, cntlr.control); + + /* wait for the result */ + status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1); + if (status == -1) + return -1; + + if (status & SPIS_FCERR) { + printk(BIOS_DEBUG, "ICH SPI: Command transaction error\n"); + return -1; + } + + goto spi_xfer_exit; + } + + /* + * Check if this is a write command attempting to transfer more bytes + * than the controller can handle. Iterations for writes are not + * supported here because each SPI write command needs to be preceded + * and followed by other SPI commands, and this sequence is controlled + * by the SPI chip driver. + */ + if (trans.bytesout > cntlr.databytes) { + printk(BIOS_DEBUG, "ICH SPI: Too much to write. Does your SPI chip driver use" + " CONTROLLER_PAGE_LIMIT?\n"); + return -1; + } + + /* + * Read or write up to databytes bytes at a time until everything has + * been sent. + */ + while (trans.bytesout || trans.bytesin) { + uint32_t data_length; + + /* SPI addresses are 24 bit only */ + writel_(trans.offset & 0x00FFFFFF, cntlr.addr); + + if (trans.bytesout) + data_length = min(trans.bytesout, cntlr.databytes); + else + data_length = min(trans.bytesin, cntlr.databytes); + + /* Program data into FDATA0 to N */ + if (trans.bytesout) { + write_reg(trans.out, cntlr.data, data_length); + spi_use_out(&trans, data_length); + if (with_address) + trans.offset += data_length; + } + + /* Add proper control fields' values */ + control &= ~((cntlr.databytes - 1) << 8); + control |= SPIC_DS; + control |= (data_length - 1) << 8; + + /* write it */ + writew_(control, cntlr.control); + + /* Wait for Cycle Done Status or Flash Cycle Error. */ + status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1); + if (status == -1) + return -1; + + if (status & SPIS_FCERR) { + printk(BIOS_DEBUG, "ICH SPI: Data transaction error\n"); + return -1; + } + + if (trans.bytesin) { + read_reg(cntlr.data, trans.in, data_length); + spi_use_in(&trans, data_length); + if (with_address) + trans.offset += data_length; + } + } + +spi_xfer_exit: + /* Clear atomic preop now that xfer is done */ + writew_(0, cntlr.preop); + + return 0; +} diff --git a/src/soc/intel/fsp_baytrail/tsc_freq.c b/src/soc/intel/fsp_baytrail/tsc_freq.c new file mode 100644 index 0000000..b74e41e --- /dev/null +++ b/src/soc/intel/fsp_baytrail/tsc_freq.c @@ -0,0 +1,84 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 <cpu/x86/msr.h> +#include <cpu/x86/tsc.h> +#include <baytrail/msr.h> +#if !defined(__PRE_RAM__) +#include <baytrail/ramstage.h> +#else +#include <baytrail/romstage.h> +#endif + +unsigned bus_freq_khz(void) +{ + msr_t clk_info = rdmsr(MSR_BSEL_CR_OVERCLOCK_CONTROL); + switch (clk_info.lo & 0x3) { + case 0: + return 83333; + case 1: + return 100000; + case 2: + return 133333; + case 3: + return 116666; + default: + return 0; + } +} + +unsigned long tsc_freq_mhz(void) +{ + msr_t platform_info; + unsigned bclk_khz = bus_freq_khz(); + + if (!bclk_khz) + return 0; + + platform_info = rdmsr(MSR_PLATFORM_INFO); + return (bclk_khz * ((platform_info.lo >> 8) & 0xff)) / 1000; +} + +#if !defined(__SMM__) + +void set_max_freq(void) +{ + msr_t perf_ctl; + msr_t msr; + + /* Enable speed step. */ + msr = rdmsr(MSR_IA32_MISC_ENABLES); + msr.lo |= (1 << 16); + wrmsr(MSR_IA32_MISC_ENABLES, msr); + + /* Set guaranteed ratio [21:16] from IACORE_RATIOS to bits [15:8] of + * the PERF_CTL. */ + msr = rdmsr(MSR_IACORE_RATIOS); + perf_ctl.lo = (msr.lo & 0x3f0000) >> 8; + /* Set guaranteed vid [21:16] from IACORE_VIDS to bits [7:0] of + * the PERF_CTL. */ + msr = rdmsr(MSR_IACORE_VIDS); + perf_ctl.lo |= (msr.lo & 0x7f0000) >> 16; + perf_ctl.hi = 0; + + wrmsr(MSR_IA32_PERF_CTL, perf_ctl); +} + +#endif /* __SMM__ */
1 0
0 0
Patch set updated for coreboot: 363e7d9 add rtc_init() to romstage
by Martin Roth May 28, 2014

May 28, 2014
Martin Roth (gaumless(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5735 -gerrit commit 363e7d93a3a509e221ee2bf6df6376a69964e81e Author: Martin Roth <gaumless(a)gmail.com> Date: Mon May 12 21:52:54 2014 -0600 add rtc_init() to romstage The FSP clears the bit that tells us whether or not the RTC has lost power when it sets up memory. Because of this, we need to initialize the RTC in romstage instead of ramstage. Change-Id: I158e4339fc539d32cfb2428042df6156d312a5f4 Signed-off-by: Martin Roth <gaumless(a)gmail.com> Signed-off-by: Martin Roth <martin.roth(a)se-eng.com> --- src/drivers/pc80/Kconfig | 6 ++++++ src/drivers/pc80/Makefile.inc | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/drivers/pc80/Kconfig b/src/drivers/pc80/Kconfig index 3572bc2..f53183b 100644 --- a/src/drivers/pc80/Kconfig +++ b/src/drivers/pc80/Kconfig @@ -22,3 +22,9 @@ config TPM Enable this option to enable TPM support in coreboot. If unsure, say N. + +config ROMSTAGE_RTC_INIT + bool + default n + help + Enable this option to use rtc_init() in romstage diff --git a/src/drivers/pc80/Makefile.inc b/src/drivers/pc80/Makefile.inc index 4d0a280..7451b33 100644 --- a/src/drivers/pc80/Makefile.inc +++ b/src/drivers/pc80/Makefile.inc @@ -1,4 +1,8 @@ +ifeq ($(CONFIG_ROMSTAGE_RTC_INIT),y) +romstage-y += mc146818rtc.c +else ramstage-y += mc146818rtc.c +endif ramstage-y += isa-dma.c ramstage-y += i8254.c ramstage-y += i8259.c
1 0
0 0
Patch set updated for coreboot: 0c8b097 intel/bayleybay: Add Intel's Bayley Bay mainboard
by Martin Roth May 28, 2014

May 28, 2014
Martin Roth (gaumless(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5792 -gerrit commit 0c8b097c8aa8a6096526990d8ba90d7f45b4eb27 Author: Martin Roth <gaumless(a)gmail.com> Date: Mon May 12 21:56:27 2014 -0600 intel/bayleybay: Add Intel's Bayley Bay mainboard Bay Trail-I Platform – Bayley Bay-I Customer Reference Board The Bayley Bay CRB-I is a dual-channel DDR3L SO-DIMM non-ECC platform. It is designed to support the Bay Trail-I SoC. This implementation uses the Intel FSP (Vist the Intel FSP website for details on FSP architecture and support). This code does not currently support S3. All other features and IO ports are functional. Booted on Ubuntu 14.04, Mint 16, Fedora 20 with SeaBIOS payload. Memtest86, FWTS, and other tests pass. Notes: - Generates a 2MB binary to be flashed to the upper 2MB of the ROM, to preserve the existing Intel Flash Descriptor & TXE binary. - Tested with B0 & B3 Baytrail I parts Board support page will be updated on acceptance. Change-Id: I80c836c7590f2dc25ec854e7a0bb939024cea600 Signed-off-by: Martin Roth <gaumless(a)gmail.com> Signed-off-by: Martin Roth <martin.roth(a)se-eng.com> --- src/mainboard/intel/Kconfig | 3 + src/mainboard/intel/bayleybay/Kconfig | 99 +++++++++ src/mainboard/intel/bayleybay/Makefile.inc | 21 ++ src/mainboard/intel/bayleybay/acpi/ec.asl | 0 src/mainboard/intel/bayleybay/acpi/mainboard.asl | 25 +++ src/mainboard/intel/bayleybay/acpi/superio.asl | 0 src/mainboard/intel/bayleybay/acpi/video.asl | 0 src/mainboard/intel/bayleybay/acpi_tables.c | 257 +++++++++++++++++++++++ src/mainboard/intel/bayleybay/board_info.txt | 4 + src/mainboard/intel/bayleybay/cmos.layout | 134 ++++++++++++ src/mainboard/intel/bayleybay/devicetree.cb | 78 +++++++ src/mainboard/intel/bayleybay/dsdt.asl | 57 +++++ src/mainboard/intel/bayleybay/fadt.c | 35 +++ src/mainboard/intel/bayleybay/gpio.c | 230 ++++++++++++++++++++ src/mainboard/intel/bayleybay/irqroute.c | 22 ++ src/mainboard/intel/bayleybay/irqroute.h | 72 +++++++ src/mainboard/intel/bayleybay/mainboard.c | 48 +++++ src/mainboard/intel/bayleybay/onboard.h | 25 +++ src/mainboard/intel/bayleybay/romstage.c | 173 +++++++++++++++ src/mainboard/intel/bayleybay/thermal.h | 33 +++ 20 files changed, 1316 insertions(+) diff --git a/src/mainboard/intel/Kconfig b/src/mainboard/intel/Kconfig index 75142e3..365297c 100644 --- a/src/mainboard/intel/Kconfig +++ b/src/mainboard/intel/Kconfig @@ -3,6 +3,8 @@ if VENDOR_INTEL choice prompt "Mainboard model" +config BOARD_INTEL_BAYLEYBAY + bool "Bayley Bay CRB" config BOARD_INTEL_COUGAR_CANYON2 bool "Cougar Canyon 2 CRB" config BOARD_INTEL_D810E2CB @@ -28,6 +30,7 @@ config BOARD_INTEL_WTM2 endchoice +source "src/mainboard/intel/bayleybay/Kconfig" source "src/mainboard/intel/cougar_canyon2/Kconfig" source "src/mainboard/intel/d810e2cb/Kconfig" source "src/mainboard/intel/d945gclf/Kconfig" diff --git a/src/mainboard/intel/bayleybay/Kconfig b/src/mainboard/intel/bayleybay/Kconfig new file mode 100644 index 0000000..46f368d --- /dev/null +++ b/src/mainboard/intel/bayleybay/Kconfig @@ -0,0 +1,99 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2013-2014 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 +## + +if BOARD_INTEL_BAYLEYBAY + +config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + select SOC_INTEL_FSP_BAYTRAIL + select BOARD_ROMSIZE_KB_2048 + select HAVE_ACPI_TABLES + select HAVE_OPTION_TABLE + select EARLY_CBMEM_INIT + select OVERRIDE_MRC_CACHE_LOC + select POST_IO + +config MAINBOARD_DIR + string + default "intel/bayleybay" + +config INCLUDE_ME + bool + default n + +config LOCK_MANAGEMENT_ENGINE + bool + default n + +config MAINBOARD_PART_NUMBER + string + default "Bayley Bay CRB" + +config MMCONF_BASE_ADDRESS + hex + default 0xe0000000 + +config IRQ_SLOT_COUNT + int + default 18 + +config MAX_CPUS + int + default 16 + +config CACHE_ROM_SIZE_OVERRIDE + hex + default 0x800000 + +config FSP_LOC + hex + default 0xfffc0000 + +config FSP_FILE + string + default "../intel/fsp/baytrail/BAYTRAIL_FSP.fd" + +config MRC_CACHE_LOC_OVERRIDE + hex + default 0xfff80000 + depends on ENABLE_FAST_BOOT + +config CBFS_SIZE + hex + default 0x00200000 + +config DRIVERS_PS2_KEYBOARD + bool + default n + +config CONSOLE_POST + bool + default y + +config ENABLE_FSP_FAST_BOOT + bool + depends on HAVE_FSP_BIN + default y + +config VIRTUAL_ROM_SIZE + hex + depends on ENABLE_FSP_FAST_BOOT + default 0x800000 + +endif # BOARD_INTEL_BAYLEYBAY diff --git a/src/mainboard/intel/bayleybay/Makefile.inc b/src/mainboard/intel/bayleybay/Makefile.inc new file mode 100644 index 0000000..2f7a8c5 --- /dev/null +++ b/src/mainboard/intel/bayleybay/Makefile.inc @@ -0,0 +1,21 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2013 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 +## + +ramstage-y += gpio.c +ramstage-y += irqroute.c diff --git a/src/mainboard/intel/bayleybay/acpi/ec.asl b/src/mainboard/intel/bayleybay/acpi/ec.asl new file mode 100644 index 0000000..e69de29 diff --git a/src/mainboard/intel/bayleybay/acpi/mainboard.asl b/src/mainboard/intel/bayleybay/acpi/mainboard.asl new file mode 100644 index 0000000..c1884c5 --- /dev/null +++ b/src/mainboard/intel/bayleybay/acpi/mainboard.asl @@ -0,0 +1,25 @@ +/* + * 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 + */ + +Device (PWRB) +{ + Name(_HID, EisaId("PNP0C0C")) +} diff --git a/src/mainboard/intel/bayleybay/acpi/superio.asl b/src/mainboard/intel/bayleybay/acpi/superio.asl new file mode 100644 index 0000000..e69de29 diff --git a/src/mainboard/intel/bayleybay/acpi/video.asl b/src/mainboard/intel/bayleybay/acpi/video.asl new file mode 100644 index 0000000..e69de29 diff --git a/src/mainboard/intel/bayleybay/acpi_tables.c b/src/mainboard/intel/bayleybay/acpi_tables.c new file mode 100644 index 0000000..8a9d857 --- /dev/null +++ b/src/mainboard/intel/bayleybay/acpi_tables.c @@ -0,0 +1,257 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Google Inc. + * Copyright (C) 2013-2014 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 <cbmem.h> +#include <console/console.h> +#include <arch/acpi.h> +#include <arch/ioapic.h> +#include <arch/acpigen.h> +#include <arch/smp/mpspec.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <cpu/cpu.h> +#include <cpu/x86/msr.h> +#include <baytrail/acpi.h> +#include <baytrail/nvs.h> +#include <baytrail/iomap.h> + + +extern const unsigned char AmlCode[]; + +static void acpi_create_gnvs(global_nvs_t *gnvs) +{ + acpi_init_gnvs(gnvs); + + /* Enable USB ports in S3 */ + gnvs->s3u0 = 1; + gnvs->s3u1 = 1; + + /* Disable USB ports in S5 */ + gnvs->s5u0 = 0; + gnvs->s5u1 = 0; + + /* TPM Present */ + gnvs->tpmp = 0; + + /* Enable DPTF */ + gnvs->dpte = 0; + + /* CBMEM TOC */ + gnvs->cmem = 0; +} + +unsigned long acpi_fill_madt(unsigned long current) +{ + /* Local APICs */ + current = acpi_create_madt_lapics(current); + + /* IOAPIC */ + current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *) current, + 2, IO_APIC_ADDR, 0); + + current = acpi_madt_irq_overrides(current); + + return current; +} + +unsigned long acpi_fill_ssdt_generator(unsigned long current, + const char *oem_table_id) +{ + generate_cpu_entries(); + return (unsigned long) (acpigen_get_current()); +} + +unsigned long acpi_fill_slit(unsigned long current) +{ + // Not implemented + return current; +} + +unsigned long acpi_fill_srat(unsigned long current) +{ + /* No NUMA, no SRAT */ + return current; +} + +#define ALIGN_CURRENT current = (ALIGN(current, 16)) +unsigned long write_acpi_tables(unsigned long start) +{ + unsigned long current; + int i; + acpi_rsdp_t *rsdp; + acpi_rsdt_t *rsdt; + acpi_xsdt_t *xsdt; + acpi_hpet_t *hpet; + acpi_madt_t *madt; + acpi_mcfg_t *mcfg; + acpi_fadt_t *fadt; + acpi_facs_t *facs; + acpi_header_t *ssdt; + acpi_header_t *ssdt2; + acpi_header_t *dsdt; + global_nvs_t *gnvs; + + current = start; + + /* Align ACPI tables to 16byte */ + ALIGN_CURRENT; + + printk(BIOS_INFO, "ACPI: Writing ACPI tables at %lx.\n", start); + + /* We need at least an RSDP and an RSDT Table */ + rsdp = (acpi_rsdp_t *) current; + current += sizeof(acpi_rsdp_t); + ALIGN_CURRENT; + rsdt = (acpi_rsdt_t *) current; + current += sizeof(acpi_rsdt_t); + ALIGN_CURRENT; + xsdt = (acpi_xsdt_t *) current; + current += sizeof(acpi_xsdt_t); + ALIGN_CURRENT; + + /* clear all table memory */ + memset((void *) start, 0, current - start); + + acpi_write_rsdp(rsdp, rsdt, xsdt); + acpi_write_rsdt(rsdt); + acpi_write_xsdt(xsdt); + + facs = (acpi_facs_t *) current; + current += sizeof(acpi_facs_t); + ALIGN_CURRENT; + acpi_create_facs(facs); + printk(BIOS_DEBUG, "ACPI: * FACS @ %p Length %x", facs, + facs->length); + + dsdt = (acpi_header_t *) current; + memcpy(dsdt, &AmlCode, sizeof(acpi_header_t)); + current += dsdt->length; + ALIGN_CURRENT; + memcpy(dsdt, &AmlCode, dsdt->length); + printk(BIOS_DEBUG, "ACPI: * DSDT @ %p Length %x", dsdt, + dsdt->length); + + fadt = (acpi_fadt_t *) current; + current += sizeof(acpi_fadt_t); + ALIGN_CURRENT; + acpi_create_fadt(fadt, facs, dsdt); + acpi_add_table(rsdp, fadt); + printk(BIOS_DEBUG, "ACPI: * FADT @ %p Length %x", fadt, + fadt->header.length); + + /* + * We explicitly add these tables later on: + */ + hpet = (acpi_hpet_t *) current; + current += sizeof(acpi_hpet_t); + ALIGN_CURRENT; + acpi_create_intel_hpet(hpet); + acpi_add_table(rsdp, hpet); + printk(BIOS_DEBUG, "ACPI: * HPET @ %p Length %x\n", hpet, + hpet->header.length); + + /* If we want to use HPET Timers Linux wants an MADT */ + madt = (acpi_madt_t *) current; + acpi_create_madt(madt); + current += madt->header.length; + ALIGN_CURRENT; + acpi_add_table(rsdp, madt); + printk(BIOS_DEBUG, "ACPI: * MADT @ %p Length %x\n",madt, + madt->header.length); + + mcfg = (acpi_mcfg_t *) current; + acpi_create_mcfg(mcfg); + current += mcfg->header.length; + ALIGN_CURRENT; + acpi_add_table(rsdp, mcfg); + printk(BIOS_DEBUG, "ACPI: * MCFG @ %p Length %x\n",mcfg, + mcfg->header.length); + + /* Update GNVS pointer into CBMEM */ + gnvs = cbmem_find(CBMEM_ID_ACPI_GNVS); + if (!gnvs) { + printk(BIOS_DEBUG, "ACPI: Could not find CBMEM GNVS\n"); + gnvs = (global_nvs_t *)current; + } + + for (i=0; i < dsdt->length; i++) { + if (*(u32*)(((u32)dsdt) + i) == 0xC0DEBABE) { + printk(BIOS_DEBUG, "ACPI: Patching up global NVS in " + "DSDT at offset 0x%04x -> %p\n", i, gnvs); + *(u32*)(((u32)dsdt) + i) = (unsigned long)gnvs; + acpi_save_gnvs((unsigned long)gnvs); + break; + } + } + + /* And fill it */ + acpi_create_gnvs(gnvs); + + /* And tell SMI about it */ +#if CONFIG_HAVE_SMI_HANDLER + smm_setup_structures(gnvs, NULL, NULL); +#endif + + current += sizeof(global_nvs_t); + ALIGN_CURRENT; + + /* We patched up the DSDT, so we need to recalculate the checksum */ + dsdt->checksum = 0; + dsdt->checksum = acpi_checksum((void *)dsdt, dsdt->length); + + printk(BIOS_DEBUG, "ACPI Updated DSDT @ %p Length %x\n", dsdt, + dsdt->length); + + ssdt = (acpi_header_t *)current; + memset(ssdt, 0, sizeof(acpi_header_t)); + acpi_create_ssdt_generator(ssdt, ACPI_TABLE_CREATOR); + if (ssdt->length) { + current += ssdt->length; + acpi_add_table(rsdp, ssdt); + printk(BIOS_DEBUG, "ACPI: * SSDT @ %p Length %x\n",ssdt, + ssdt->length); + ALIGN_CURRENT; + } else { + ssdt = NULL; + printk(BIOS_DEBUG, "ACPI: * SSDT not generated.\n"); + } + + ssdt2 = (acpi_header_t *)current; + memset(ssdt2, 0, sizeof(acpi_header_t)); + acpi_create_serialio_ssdt(ssdt2); + if (ssdt2->length) { + current += ssdt2->length; + acpi_add_table(rsdp, ssdt2); + printk(BIOS_DEBUG, "ACPI: * SSDT2 @ %p Length %x\n",ssdt2, + ssdt2->length); + ALIGN_CURRENT; + } else { + ssdt2 = NULL; + printk(BIOS_DEBUG, "ACPI: * SSDT2 not generated.\n"); + } + + printk(BIOS_DEBUG, "current = %lx\n", current); + + printk(BIOS_INFO, "ACPI: done.\n"); + return current; +} diff --git a/src/mainboard/intel/bayleybay/board_info.txt b/src/mainboard/intel/bayleybay/board_info.txt new file mode 100644 index 0000000..501a6a4 --- /dev/null +++ b/src/mainboard/intel/bayleybay/board_info.txt @@ -0,0 +1,4 @@ +Board name: Bayley Bay +Category: eval +ROM protocol: SPI +ROM socketed: n diff --git a/src/mainboard/intel/bayleybay/cmos.layout b/src/mainboard/intel/bayleybay/cmos.layout new file mode 100644 index 0000000..0b86c51 --- /dev/null +++ b/src/mainboard/intel/bayleybay/cmos.layout @@ -0,0 +1,134 @@ +## +## 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 +## + +# ----------------------------------------------------------------- +entries + +#start-bit length config config-ID name +#0 8 r 0 seconds +#8 8 r 0 alarm_seconds +#16 8 r 0 minutes +#24 8 r 0 alarm_minutes +#32 8 r 0 hours +#40 8 r 0 alarm_hours +#48 8 r 0 day_of_week +#56 8 r 0 day_of_month +#64 8 r 0 month +#72 8 r 0 year +# ----------------------------------------------------------------- +# Status Register A +#80 4 r 0 rate_select +#84 3 r 0 REF_Clock +#87 1 r 0 UIP +# ----------------------------------------------------------------- +# Status Register B +#88 1 r 0 auto_switch_DST +#89 1 r 0 24_hour_mode +#90 1 r 0 binary_values_enable +#91 1 r 0 square-wave_out_enable +#92 1 r 0 update_finished_enable +#93 1 r 0 alarm_interrupt_enable +#94 1 r 0 periodic_interrupt_enable +#95 1 r 0 disable_clock_updates +# ----------------------------------------------------------------- +# Status Register C +#96 4 r 0 status_c_rsvd +#100 1 r 0 uf_flag +#101 1 r 0 af_flag +#102 1 r 0 pf_flag +#103 1 r 0 irqf_flag +# ----------------------------------------------------------------- +# Status Register D +#104 7 r 0 status_d_rsvd +#111 1 r 0 valid_cmos_ram +# ----------------------------------------------------------------- +# Diagnostic Status Register +#112 8 r 0 diag_rsvd1 + +# ----------------------------------------------------------------- +0 120 r 0 reserved_memory +#120 264 r 0 unused + +# ----------------------------------------------------------------- +# RTC_BOOT_BYTE (coreboot hardcoded) +384 1 e 4 boot_option +385 1 e 4 last_boot +388 4 r 0 reboot_bits +#390 2 r 0 unused? + +# ----------------------------------------------------------------- +# coreboot config options: console +392 3 e 5 baud_rate +395 4 e 6 debug_level +#399 1 r 0 unused + +# coreboot config options: cpu +400 1 e 2 hyper_threading +#401 7 r 0 unused + +# coreboot config options: southbridge +408 1 e 1 nmi +409 2 e 7 power_on_after_fail +#411 5 r 0 unused + +# MRC Scrambler Seed values +896 32 r 0 mrc_scrambler_seed +928 32 r 0 mrc_scrambler_seed_s3 + +# coreboot config options: check sums +984 16 h 0 check_sum +#1000 24 r 0 amd_reserved + +# ----------------------------------------------------------------- + +enumerations + +#ID value text +1 0 Disable +1 1 Enable +2 0 Enable +2 1 Disable +4 0 Fallback +4 1 Normal +5 0 115200 +5 1 57600 +5 2 38400 +5 3 19200 +5 4 9600 +5 5 4800 +5 6 2400 +5 7 1200 +6 1 Emergency +6 2 Alert +6 3 Critical +6 4 Error +6 5 Warning +6 6 Notice +6 7 Info +6 8 Debug +6 9 Spew +7 0 Disable +7 1 Enable +7 2 Keep +# ----------------------------------------------------------------- +checksums + +checksum 392 415 984 + + diff --git a/src/mainboard/intel/bayleybay/devicetree.cb b/src/mainboard/intel/bayleybay/devicetree.cb new file mode 100644 index 0000000..c1e701e --- /dev/null +++ b/src/mainboard/intel/bayleybay/devicetree.cb @@ -0,0 +1,78 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2013-2014 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 +## + +chip soc/intel/fsp_baytrail + + #### ACPI Register Settings #### + register "fadt_pm_profile" = "PM_MOBILE" + register "fadt_boot_arch" = "ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042" + + #### FSP register settings #### + register "SataMode" = "SATA_MODE_AHCI" + register "MrcInitSPDAddr1" = "SPD_ADDR_DEFAULT" + register "MrcInitSPDAddr2" = "SPD_ADDR_DEFAULT" + register "MrcInitTsegSize" = "TSEG_SIZE_DEFAULT" + register "MrcInitMmioSize" = "MMIO_SIZE_DEFAULT" + register "eMMCBootMode" = "EMMC_FOLLOWS_DEVICETREE" + register "IgdDvmt50PreAlloc" = "IGD_MEMSIZE_DEFAULT" + register "ApertureSize" = "APERTURE_SIZE_DEFAULT" + register "GttSize" = "GTT_SIZE_DEFAULT" + register "LpssSioEnablePciMode" = "LPSS_PCI_MODE_DEFAULT" + register "AzaliaAutoEnable" = "AZALIA_FOLLOWS_DEVICETREE" + register "LpeAcpiModeEnable" = "LPE_ACPI_MODE_DISABLED" + + device cpu_cluster 0 on + device lapic 0 on end + end + + device domain 0 on + device pci 00.0 on end # 8086 0F00 - SoC router + device pci 02.0 on end # 8086 0F31 - GFX + + device pci 11.0 on end # 8086 0F15 - SDIO Port + device pci 12.0 on end # 8086 0F16 - SD Port + device pci 13.0 on end # 8086 0F23 - SATA AHCI (0F20, 0F21, 0F22, 0F23) + device pci 14.0 off end # 8086 0F35 - USB XHCI - Only 1 USB controller at a time + device pci 15.0 on end # 8086 0F28 - LP Engine Audio + device pci 17.0 on end # 8086 0F50 - MMC Port + device pci 18.0 on end # 8086 0F40 - SIO - DMA + device pci 18.1 on end # 8086 0F41 - I2C Port 1 + device pci 18.2 on end # 8086 0F42 - I2C Port 2 + device pci 18.3 on end # 8086 0F43 - I2C Port 3 + device pci 18.4 on end # 8086 0F44 - I2C Port 4 + device pci 18.5 on end # 8086 0F45 - I2C Port 5 + device pci 18.6 on end # 8086 0F46 - I2C Port 6 + device pci 18.7 on end # 8086 0F47 - I2C Port 7 + device pci 1a.0 on end # 8086 0F18 - Trusted Execution Engine + device pci 1b.0 on end # 8086 0F04 - HD Audio + device pci 1c.0 on end # 8086 0F48 - PCIe Root Port 1 (x4 slot) + device pci 1c.1 on end # 8086 0F4A - PCIe Root Port 2 (half mini pcie slot) + device pci 1c.2 on end # 8086 0F4C - PCIe Root Port 3 (front x1 slot) + device pci 1c.3 on end # 8086 0F4E - PCIe Root Port 4 (rear x1 slot) + device pci 1d.0 on end # 8086 0F34 - USB EHCI - Only 1 USB controller at a time + device pci 1e.0 on end # 8086 0F06 - SIO - DMA + device pci 1e.1 on end # 8086 0F08 - PWM 1 + device pci 1e.2 on end # 8086 0F09 - PWM 2 + device pci 1e.3 on end # 8086 0F0A - HSUART 1 + device pci 1e.4 on end # 8086 0F0C - HSUART 2 + device pci 1e.5 on end # 8086 0F0E - SPI + device pci 1f.0 on end # 8086 0F1C - LPC bridge + device pci 1f.3 on end # 8086 0F12 - SMBus 0 + end +end diff --git a/src/mainboard/intel/bayleybay/dsdt.asl b/src/mainboard/intel/bayleybay/dsdt.asl new file mode 100644 index 0000000..cb2a4da --- /dev/null +++ b/src/mainboard/intel/bayleybay/dsdt.asl @@ -0,0 +1,57 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2011 Google Inc. + * Copyright (C) 2014 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 + */ + +#define INCLUDE_LPE 1 +#define INCLUDE_SCC 1 +#define INCLUDE_EHCI 1 +#define INCLUDE_XHCI 1 +#define INCLUDE_LPSS 1 + + +DefinitionBlock( + "dsdt.aml", + "DSDT", + 0x02, // DSDT revision: ACPI v2.0 + "COREv4", // OEM id + "COREBOOT", // OEM table id + 0x20110725 // OEM revision +) +{ + // Some generic macros + #include <soc/intel/fsp_baytrail/acpi/platform.asl> + + // global NVS and variables + #include <soc/intel/fsp_baytrail/acpi/globalnvs.asl> + + #include <soc/intel/fsp_baytrail/acpi/cpu.asl> + + Scope (\_SB) { + Device (PCI0) + { + #include <soc/intel/fsp_baytrail/acpi/southcluster.asl> + } + } + + /* Chipset specific sleep states */ + #include <soc/intel/fsp_baytrail/acpi/sleepstates.asl> + + #include "acpi/mainboard.asl" +} diff --git a/src/mainboard/intel/bayleybay/fadt.c b/src/mainboard/intel/bayleybay/fadt.c new file mode 100644 index 0000000..29d0c1d --- /dev/null +++ b/src/mainboard/intel/bayleybay/fadt.c @@ -0,0 +1,35 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * 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 <arch/acpi.h> +#include <baytrail/acpi.h> + +void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt) +{ + acpi_header_t *header = &(fadt->header); + + acpi_fill_in_fadt(fadt,facs,dsdt); + + /* Platform specific customizations go here */ + + header->checksum = 0; + header->checksum = + acpi_checksum((void *) fadt, sizeof(acpi_fadt_t)); +} diff --git a/src/mainboard/intel/bayleybay/gpio.c b/src/mainboard/intel/bayleybay/gpio.c new file mode 100644 index 0000000..ddb7052 --- /dev/null +++ b/src/mainboard/intel/bayleybay/gpio.c @@ -0,0 +1,230 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2014 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 <stdlib.h> +#include <baytrail/gpio.h> +#include "irqroute.h" + +/* NCORE GPIOs */ +static const struct soc_gpio_map gpncore_gpio_map[] = { + GPIO_FUNC2, /* GPIO 0 */ + GPIO_FUNC2, /* GPIO 1 */ + GPIO_FUNC2, /* GPIO 2 */ + GPIO_FUNC2, /* GPIO 3 */ + GPIO_FUNC2, /* GPIO 4 */ + GPIO_FUNC2, /* GPIO 5 */ + GPIO_FUNC2, /* GPIO 6 */ + GPIO_FUNC2, /* GPIO 7 */ + GPIO_FUNC2, /* GPIO 8 */ + GPIO_FUNC2, /* GPIO 9 */ + GPIO_FUNC2, /* GPIO 10 */ + GPIO_FUNC2, /* GPIO 11 */ + GPIO_FUNC2, /* GPIO 12 */ + GPIO_FUNC2, /* GPIO 13 */ + GPIO_FUNC2, /* GPIO 14 */ + GPIO_FUNC2, /* GPIO 15 */ + GPIO_FUNC2, /* GPIO 16 */ + GPIO_FUNC2, /* GPIO 17 */ + GPIO_FUNC2, /* GPIO 18 */ + GPIO_FUNC2, /* GPIO 19 */ + GPIO_FUNC2, /* GPIO 20 */ + GPIO_FUNC2, /* GPIO 21 */ + GPIO_FUNC2, /* GPIO 22 */ + GPIO_FUNC2, /* GPIO 23 */ + GPIO_FUNC2, /* GPIO 24 */ + GPIO_FUNC2, /* GPIO 25 */ + GPIO_FUNC2, /* GPIO 26 */ + GPIO_END +}; + +/* SCORE GPIOs (GPIO_S0_SC_XX)*/ +static const struct soc_gpio_map gpscore_gpio_map[] = { + GPIO_FUNC1, /* GPIO_S0_SC[000] SATA_GP[0] - - - */ + GPIO_FUNC2, /* GPIO_S0_SC[001] SATA_GP[1] SATA_DEVSLP[0] - - */ + GPIO_FUNC1, /* GPIO_S0_SC[002] SATA_LED# - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[003] PCIE_CLKREQ[0]# - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[004] PCIE_CLKREQ[1]# - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[005] PCIE_CLKREQ[2]# - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[006] PCIE_CLKREQ[3]# - - - */ + GPIO_NC, /* GPIO_S0_SC[007] RESERVED SD3_WP - - */ + GPIO_FUNC2, /* GPIO_S0_SC[008] I2S0_CLK HDA_RST# - - */ + GPIO_FUNC2, /* GPIO_S0_SC[009] I2S0_FRM HDA_SYNC - - */ + GPIO_FUNC2, /* GPIO_S0_SC[010] I2S0_DATAOUT HDA_CLK - - */ + GPIO_FUNC2, /* GPIO_S0_SC[011] I2S0_DATAIN HDA_SDO - - */ + GPIO_FUNC2, /* GPIO_S0_SC[012] I2S1_CLK HDA_SDI[0] - - */ + GPIO_NC, /* GPIO_S0_SC[013] I2S1_FRM HDA_SDI[1] - - */ + GPIO_DEFAULT, /* GPIO_S0_SC[014] I2S1_DATAOUT RESERVED - - */ + GPIO_DEFAULT, /* GPIO_S0_SC[015] I2S1_DATAIN RESERVED - - */ + GPIO_NC, /* GPIO_S0_SC[016] MMC1_CLK - MMC1_45_CLK - */ + GPIO_NC, /* GPIO_S0_SC[017] MMC1_D[0] - MMC1_45_D[0] - */ + GPIO_NC, /* GPIO_S0_SC[018] MMC1_D[1] - MMC1_45_D[1] - */ + GPIO_NC, /* GPIO_S0_SC[019] MMC1_D[2] - MMC1_45_D[2] - */ + GPIO_NC, /* GPIO_S0_SC[020] MMC1_D[3] - MMC1_45_D[3] - */ + GPIO_NC, /* GPIO_S0_SC[021] MMC1_D[4] - MMC1_45_D[4] - */ + GPIO_NC, /* GPIO_S0_SC[022] MMC1_D[5] - MMC1_45_D[5] - */ + GPIO_NC, /* GPIO_S0_SC[023] MMC1_D[6] - MMC1_45_D[6] - */ + GPIO_NC, /* GPIO_S0_SC[024] MMC1_D[7] - MMC1_45_D[7] - */ + GPIO_NC, /* GPIO_S0_SC[025] MMC1_CMD - MMC1_45_CMD - */ + GPIO_NC, /* GPIO_S0_SC[026] MMC1_RST# SATA_DEVSLP[0] MMC1_45_RST# - */ + GPIO_FUNC1, /* GPIO_S0_SC[027] SD2_CLK - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[028] SD2_D[0] - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[029] SD2_D[1] - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[030] SD2_D[2] - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[031] SD2_D[3]_CD# - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[032] SD2_CMD - - - */ + GPIO_NC, /* GPIO_S0_SC[033] SD3_CLK - - - */ + GPIO_NC, /* GPIO_S0_SC[034] SD3_D[0] - - - */ + GPIO_NC, /* GPIO_S0_SC[035] SD3_D[1] - - - */ + GPIO_NC, /* GPIO_S0_SC[036] SD3_D[2] - - - */ + GPIO_NC, /* GPIO_S0_SC[037] SD3_D[3] - - - */ + GPIO_NC, /* GPIO_S0_SC[038] SD3_CD# - - - */ + GPIO_NC, /* GPIO_S0_SC[039] SD3_CMD - - - */ + GPIO_NC, /* GPIO_S0_SC[040] SD3_1P8EN - - - */ + GPIO_NC, /* GPIO_S0_SC[041] SD3_PWREN# - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[042] ILB_LPC_AD[0] - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[043] ILB_LPC_AD[1] - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[044] ILB_LPC_AD[2] - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[045] ILB_LPC_AD[3] - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[046] ILB_LPC_FRAME# - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[047] ILB_LPC_CLK[0] - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[048] ILB_LPC_CLK[1] - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[049] ILB_LPC_CLKRUN# - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[050] ILB_LPC_SERIRQ - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[051] PCU_SMB_DATA - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[052] PCU_SMB_CLK - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[053] PCU_SMB_ALERT# - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[054] ILB_8254_SPKR RESERVED - - */ + GPIO_DEFAULT, /* GPIO_S0_SC[055] RESERVED - - - */ + GPIO_DEFAULT, /* GPIO_S0_SC[056] RESERVED - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[057] PCU_UART_TXD - - - */ + GPIO_DEFAULT, /* GPIO_S0_SC[058] RESERVED - - - */ + GPIO_DEFAULT, /* GPIO_S0_SC[059] RESERVED - - - */ + GPIO_DEFAULT, /* GPIO_S0_SC[060] RESERVED - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[061] PCU_UART_RXD - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[062] LPE_I2S2_CLK SATA_DEVSLP[1] RESERVED - */ + GPIO_FUNC1, /* GPIO_S0_SC[063] LPE_I2S2_FRM RESERVED - - */ + GPIO_FUNC1, /* GPIO_S0_SC[064] LPE_I2S2_DATAIN - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[065] LPE_I2S2_DATAOUT - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[066] SIO_SPI_CS# - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[067] SIO_SPI_MISO - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[068] SIO_SPI_MOSI - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[069] SIO_SPI_CLK - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[070] SIO_UART1_RXD RESERVED - - */ + GPIO_FUNC1, /* GPIO_S0_SC[071] SIO_UART1_TXD RESERVED - - */ + GPIO_FUNC1, /* GPIO_S0_SC[072] SIO_UART1_RTS# - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[073] SIO_UART1_CTS# - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[074] SIO_UART2_RXD - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[075] SIO_UART2_TXD - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[076] SIO_UART2_RTS# - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[077] SIO_UART2_CTS# - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[078] SIO_I2C0_DATA - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[079] SIO_I2C0_CLK - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[080] SIO_I2C1_DATA - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[081] SIO_I2C1_CLK RESERVED - - */ + GPIO_FUNC1, /* GPIO_S0_SC[082] SIO_I2C2_DATA - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[083] SIO_I2C2_CLK - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[084] SIO_I2C3_DATA - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[085] SIO_I2C3_CLK - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[086] SIO_I2C4_DATA - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[087] SIO_I2C4_CLK - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[088] SIO_I2C5_DATA - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[089] SIO_I2C5_CLK - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[090] SIO_I2C6_DATA ILB_NMI - - */ + GPIO_FUNC1, /* GPIO_S0_SC[091] SIO_I2C6_CLK SD3_WP - - */ + GPIO_FUNC1, /* RESERVED GPIO_S0_SC[092] - - - */ + GPIO_FUNC1, /* RESERVED GPIO_S0_SC[093] - - - */ + GPIO_DEFAULT, /* GPIO_S0_SC[094] SIO_PWM[0] - - - */ + GPIO_DEFAULT, /* GPIO_S0_SC[095] SIO_PWM[1] - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[096] PMC_PLT_CLK[0] - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[097] PMC_PLT_CLK[1] - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[098] PMC_PLT_CLK[2] - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[099] PMC_PLT_CLK[3] - - - */ + GPIO_FUNC1, /* GPIO_S0_SC[100] PMC_PLT_CLK[4] - - - */ + GPIO_DEFAULT, /* GPIO_S0_SC[101] PMC_PLT_CLK[5] - - - */ + GPIO_END +}; + +/* SSUS GPIOs (GPIO_S5) */ +static const struct soc_gpio_map gpssus_gpio_map[] = { + GPIO_DEFAULT, /* GPIO_S5[00] RESERVED - - - */ + GPIO_DEFAULT, /* GPIO_S5[01] RESERVED RESERVED RESERVED PMC_WAKE_PCIE[1]# */ + GPIO_DEFAULT, /* GPIO_S5[02] RESERVED RESERVED RESERVED PMC_WAKE_PCIE[2]# */ + GPIO_DEFAULT, /* GPIO_S5[03] RESERVED RESERVED RESERVED PMC_WAKE_PCIE[3]# */ + GPIO_DEFAULT, /* GPIO_S5[04] RESERVED RESERVED RESERVED RESERVED */ + GPIO_DEFAULT, /* GPIO_S5[05] PMC_SUSCLK[1] RESERVED RESERVED RESERVED */ + GPIO_DEFAULT, /* GPIO_S5[06] PMC_SUSCLK[2] RESERVED RESERVED RESERVED */ + GPIO_DEFAULT, /* GPIO_S5[07] PMC_SUSCLK[3] RESERVED RESERVED RESERVED */ + GPIO_NC, /* GPIO_S5[08] RESERVED RESERVED RESERVED RESERVED */ + GPIO_NC, /* GPIO_S5[09] RESERVED RESERVED RESERVED RESERVED */ + GPIO_NC, /* GPIO_S5[10] RESERVED RESERVED RESERVED - */ + GPIO_DEFAULT, /* PMC_SUSPWRDNACK GPIO_S5[11] - - - */ + GPIO_FUNC0, /* PMC_SUSCLK[0] GPIO_S5[12] - - - */ + GPIO_FUNC1, /* RESERVED GPIO_S5[13] - - - */ + GPIO_FUNC1, /* RESERVED GPIO_S5[14] USB_ULPI_RST# - - */ + GPIO_FUNC0, /* PMC_WAKE_PCIE[0]# GPIO_S5[15] - - - */ + GPIO_FUNC0, /* PMC_PWRBTN# GPIO_S5[16] - - - */ + GPIO_DEFAULT, /* RESERVED GPIO_S5[17] - - - */ + GPIO_FUNC1, /* PMC_SUS_STAT# GPIO_S5[18] - - - */ + GPIO_FUNC0, /* USB_OC[0]# GPIO_S5[19] - - - */ + GPIO_FUNC0, /* USB_OC[1]# GPIO_S5[20] - - - */ + GPIO_FUNC0, /* PCU_SPI_CS[1]# GPIO_S5[21] - - - */ + GPIO_DEFAULT, /* GPIO_S5[22] RESERVED RESERVED RESERVED RESERVED */ + GPIO_DEFAULT, /* GPIO_S5[23] RESERVED RESERVED RESERVED RESERVED */ + GPIO_DEFAULT, /* GPIO_S5[24] RESERVED RESERVED RESERVED RESERVED */ + GPIO_DEFAULT, /* GPIO_S5[25] RESERVED RESERVED RESERVED RESERVED */ + GPIO_DEFAULT, /* GPIO_S5[26] RESERVED RESERVED RESERVED RESERVED */ + GPIO_DEFAULT, /* GPIO_S5[27] RESERVED RESERVED RESERVED RESERVED */ + GPIO_DEFAULT, /* GPIO_S5[28] RESERVED RESERVED RESERVED RESERVED */ + GPIO_DEFAULT, /* GPIO_S5[29] RESERVED RESERVED RESERVED RESERVED */ + GPIO_DEFAULT, /* GPIO_S5[30] RESERVED RESERVED RESERVED RESERVED */ + GPIO_DEFAULT, /* GPIO_S5[31] USB_ULPI_CLK RESERVED RESERVED - */ + GPIO_DEFAULT, /* GPIO_S5[32] USB_ULPI_DATA[0] RESERVED RESERVED - */ + GPIO_DEFAULT, /* GPIO_S5[33] USB_ULPI_DATA[1] RESERVED RESERVED - */ + GPIO_DEFAULT, /* GPIO_S5[34] USB_ULPI_DATA[2] RESERVED RESERVED - */ + GPIO_DEFAULT, /* GPIO_S5[35] USB_ULPI_DATA[3] RESERVED RESERVED - */ + GPIO_DEFAULT, /* GPIO_S5[36] USB_ULPI_DATA[4] RESERVED RESERVED - */ + GPIO_DEFAULT, /* GPIO_S5[37] USB_ULPI_DATA[5] RESERVED RESERVED - */ + GPIO_NC, /* GPIO_S5[38] USB_ULPI_DATA[6] RESERVED RESERVED - */ + GPIO_NC, /* GPIO_S5[39] USB_ULPI_DATA[7] RESERVED RESERVED - */ + GPIO_NC, /* GPIO_S5[40] USB_ULPI_DIR RESERVED RESERVED - */ + GPIO_NC, /* GPIO_S5[41] USB_ULPI_NXT RESERVED RESERVED - */ + GPIO_DEFAULT, /* GPIO_S5[42] USB_ULPI_STP RESERVED RESERVED - */ + GPIO_DEFAULT, /* GPIO_S5[43] USB_ULPI_REFCLK RESERVED RESERVED - */ + GPIO_END +}; + +static const u8 core_dedicated_irq[GPIO_MAX_DIRQS] = { +}; + +static const u8 sus_dedicated_irq[GPIO_MAX_DIRQS] = { +}; + +static struct soc_gpio_config gpio_config = { + .ncore = gpncore_gpio_map, + .score = gpscore_gpio_map, + .ssus = gpssus_gpio_map, + .core_dirq = &core_dedicated_irq, + .sus_dirq = &sus_dedicated_irq, +}; + +struct soc_gpio_config* mainboard_get_gpios(void) +{ + return &gpio_config; +} diff --git a/src/mainboard/intel/bayleybay/irqroute.c b/src/mainboard/intel/bayleybay/irqroute.c new file mode 100644 index 0000000..552be8f --- /dev/null +++ b/src/mainboard/intel/bayleybay/irqroute.c @@ -0,0 +1,22 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 "irqroute.h" + +DEFINE_IRQ_ROUTES; diff --git a/src/mainboard/intel/bayleybay/irqroute.h b/src/mainboard/intel/bayleybay/irqroute.h new file mode 100644 index 0000000..4a29b20 --- /dev/null +++ b/src/mainboard/intel/bayleybay/irqroute.h @@ -0,0 +1,72 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 <soc/intel/fsp_baytrail/baytrail/irq.h> +#include <soc/intel/fsp_baytrail/baytrail/pci_devs.h> + +/* + *IR02h GFX INT(A) - PIRQ A + *IR10h EMMC INT(ABCD) - PIRQ DEFG + *IR11h SDIO INT(A) - PIRQ B + *IR12h SD INT(A) - PIRQ C + *IR13h SATA INT(A) - PIRQ D + *IR14h XHCI INT(A) - PIRQ E + *IR15h LP Audio INT(A) - PIRQ F + *IR17h MMC INT(A) - PIRQ F + *IR18h SIO INT(ABCD) - PIRQ BADC + *IR1Ah TXE INT(A) - PIRQ F + *IR1Bh HD Audio INT(A) - PIRQ G + *IR1Ch PCIe INT(ABCD) - PIRQ EFGH + *IR1Dh EHCI INT(A) - PIRQ D + *IR1Eh SIO INT(ABCD) - PIRQ BDEF + *IR1Fh LPC INT(ABCD) - PIRQ HGBC + */ +#define PCI_DEV_PIRQ_ROUTES \ + PCI_DEV_PIRQ_ROUTE(GFX_DEV, A, A, A, A), \ + PCI_DEV_PIRQ_ROUTE(EMMC_DEV, D, E, F, G), \ + PCI_DEV_PIRQ_ROUTE(SDIO_DEV, B, A, A, A), \ + PCI_DEV_PIRQ_ROUTE(SD_DEV, C, A, A, A), \ + PCI_DEV_PIRQ_ROUTE(SATA_DEV, D, A, A, A), \ + PCI_DEV_PIRQ_ROUTE(XHCI_DEV, E, A, A, A), \ + PCI_DEV_PIRQ_ROUTE(LPE_DEV, F, A, A, A), \ + PCI_DEV_PIRQ_ROUTE(MMC45_DEV, F, A, A, A), \ + PCI_DEV_PIRQ_ROUTE(SIO1_DEV, B, A, D, C), \ + PCI_DEV_PIRQ_ROUTE(TXE_DEV, F, A, A, A), \ + PCI_DEV_PIRQ_ROUTE(HDA_DEV, G, A, A, A), \ + PCI_DEV_PIRQ_ROUTE(PCIE_DEV, E, F, G, H), \ + PCI_DEV_PIRQ_ROUTE(EHCI_DEV, D, A, A, A), \ + PCI_DEV_PIRQ_ROUTE(SIO2_DEV, B, D, E, F), \ + PCI_DEV_PIRQ_ROUTE(PCU_DEV, H, G, B, C) + +/* + * Route each PIRQ[A-H] to a PIC IRQ[0-15] + * Reserved: 0, 1, 2, 8, 13 + * PS2 keyboard: 12 + * ACPI/SCI: 9 + * Floppy: 6 + */ +#define PIRQ_PIC_ROUTES \ + PIRQ_PIC(A, 4), \ + PIRQ_PIC(B, 5), \ + PIRQ_PIC(C, 7), \ + PIRQ_PIC(D, 10), \ + PIRQ_PIC(E, 11), \ + PIRQ_PIC(F, 12), \ + PIRQ_PIC(G, 14), \ + PIRQ_PIC(H, 15) diff --git a/src/mainboard/intel/bayleybay/mainboard.c b/src/mainboard/intel/bayleybay/mainboard.c new file mode 100644 index 0000000..feae6ef --- /dev/null +++ b/src/mainboard/intel/bayleybay/mainboard.c @@ -0,0 +1,48 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2011 The ChromiumOS 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 <types.h> +#include <string.h> +#include <device/device.h> +#include <device/device.h> +#include <device/pci_def.h> +#include <device/pci_ops.h> +#include <console/console.h> +#if CONFIG_VGA_ROM_RUN +#include <x86emu/x86emu.h> +#endif +#include <pc80/mc146818rtc.h> +#include <arch/acpi.h> +#include <arch/io.h> +#include <arch/interrupt.h> +#include <boot/coreboot_tables.h> + +/* + * mainboard_enable is executed as first thing after enumerate_buses(). + * This is the earliest point to add customization. + */ +static void mainboard_enable(device_t dev) +{ + +} + +struct chip_operations mainboard_ops = { + .enable_dev = mainboard_enable, +}; diff --git a/src/mainboard/intel/bayleybay/onboard.h b/src/mainboard/intel/bayleybay/onboard.h new file mode 100644 index 0000000..1ac3ac0 --- /dev/null +++ b/src/mainboard/intel/bayleybay/onboard.h @@ -0,0 +1,25 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 The ChromiumOS 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 + */ + +#ifndef MAINBOARD_ONBOARD_H +#define MAINBOARD_ONBOARD_H + +#include <arch/smp/mpspec.h> + +#endif diff --git a/src/mainboard/intel/bayleybay/romstage.c b/src/mainboard/intel/bayleybay/romstage.c new file mode 100644 index 0000000..a801894 --- /dev/null +++ b/src/mainboard/intel/bayleybay/romstage.c @@ -0,0 +1,173 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 <stddef.h> +#include <arch/cpu.h> +#include <lib.h> +#include <arch/io.h> +#include <arch/cbfs.h> +#include <arch/stages.h> +#include <console/console.h> +#include <cbmem.h> +#include <cpu/x86/mtrr.h> +#include <romstage_handoff.h> +#include <timestamp.h> +#include <baytrail/gpio.h> +#include <baytrail/iomap.h> +#include <baytrail/lpc.h> +#include <baytrail/pci_devs.h> +#include <baytrail/romstage.h> +#include <baytrail/acpi.h> +#include <baytrail/baytrail.h> +#include <drivers/intel/fsp/fsp_util.h> + +/** + * /brief mainboard call for setup that needs to be done before fsp init + * + */ +void early_mainboard_romstage_entry() +{ + +} + +/** + * Get function disables - most of these will be done automatically + * @param fd_mask + * @param fd2_mask + */ +void get_func_disables(uint32_t *fd_mask, uint32_t *fd2_mask) +{ + +} + +/** + * /brief mainboard call for setup that needs to be done after fsp init + * + */ +void late_mainboard_romstage_entry() +{ + +} + +const uint32_t mAzaliaVerbTableData13[] = { +/* + *ALC262 Verb Table - 10EC0262 + */ + /* Pin Complex (NID 0x11 ) */ + 0x01171CF0, + 0x01171D11, + 0x01171E11, + 0x01171F41, + /* Pin Complex (NID 0x12 ) */ + 0x01271CF0, + 0x01271D11, + 0x01271E11, + 0x01271F41, + /* Pin Complex (NID 0x14 ) */ + 0x01471C10, + 0x01471D40, + 0x01471E01, + 0x01471F01, + /* Pin Complex (NID 0x15 ) */ + 0x01571CF0, + 0x01571D11, + 0x01571E11, + 0x01571F41, + /* Pin Complex (NID 0x16 ) */ + 0x01671CF0, + 0x01671D11, + 0x01671E11, + 0x01671F41, + /* Pin Complex (NID 0x18 ) */ + 0x01871C20, + 0x01871D98, + 0x01871EA1, + 0x01871F01, + /* Pin Complex (NID 0x19 ) */ + 0x01971C21, + 0x01971D98, + 0x01971EA1, + 0x01971F02, + /* Pin Complex (NID 0x1A ) */ + 0x01A71C2F, + 0x01A71D30, + 0x01A71E81, + 0x01A71F01, + /* Pin Complex (NID 0x1B ) */ + 0x01B71C1F, + 0x01B71D40, + 0x01B71E21, + 0x01B71F02, + /* Pin Complex (NID 0x1C ) */ + 0x01C71CF0, + 0x01C71D11, + 0x01C71E11, + 0x01C71F41, + /* Pin Complex (NID 0x1D ) */ + 0x01D71C01, + 0x01D71DC6, + 0x01D71E14, + 0x01D71F40, + /* Pin Complex (NID 0x1E ) */ + 0x01E71CF0, + 0x01E71D11, + 0x01E71E11, + 0x01E71F41, + /* Pin Complex (NID 0x1F ) */ + 0x01F71CF0, + 0x01F71D11, + 0x01F71E11, + 0x01F71F41 }; + +const PCH_AZALIA_VERB_TABLE mAzaliaVerbTable[] = { { +/* + * VerbTable: (RealTek ALC262) + * Revision ID = 0xFF, support all steps + * Codec Verb Table For AZALIA + * Codec Address: CAd value (0/1/2) + * Codec Vendor: 0x10EC0262 + */ + { + 0x10EC0262, /* Vendor ID/Device IDA */ + 0x0000, /* SubSystem ID */ + 0xFF, /* Revision IDA */ + 0x01, /* Front panel support (1=yes, 2=no) */ + 0x000B, /* Number of Rear Jacks = 11 */ + 0x0002 /* Number of Front Jacks = 2 */ + }, + (uint32_t *)mAzaliaVerbTableData13 } }; + +const PCH_AZALIA_CONFIG mainboard_AzaliaConfig = { + .Pme = 1, + .DS = 1, + .DA = 0, + .HdmiCodec = 1, + .AzaliaVCi = 1, + .Rsvdbits = 0, + .AzaliaVerbTableNum = 1, + .AzaliaVerbTable = (PCH_AZALIA_VERB_TABLE *)mAzaliaVerbTable, + .ResetWaitTimer = 300 }; + +/** /brief customize fsp parameters here if needed + */ +void romstage_fsp_rt_buffer_callback(FSP_INIT_RT_BUFFER *FspRtBuffer) +{ + +} diff --git a/src/mainboard/intel/bayleybay/thermal.h b/src/mainboard/intel/bayleybay/thermal.h new file mode 100644 index 0000000..78dfcbe --- /dev/null +++ b/src/mainboard/intel/bayleybay/thermal.h @@ -0,0 +1,33 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 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 + */ + +#ifndef MAINBOARD_THERMAL_H +#define MAINBOARD_THERMAL_H + + +/* Temperature which OS will shutdown at */ +#define CRITICAL_TEMPERATURE 100 + +/* Temperature which OS will throttle CPU */ +#define PASSIVE_TEMPERATURE 90 + +/* Tj_max value for calculating PECI CPU temperature */ +#define MAX_TEMPERATURE 100 + +#endif /* MAINBOARD_THERMAL_H */
1 0
0 0
Patch set updated for coreboot: 2f79a1f drivers/intel/fsp: update enable_mrc_cache with fast boot
by Martin Roth May 28, 2014

May 28, 2014
Martin Roth (gaumless(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5794 -gerrit commit 2f79a1fe3fe092664cc57f5b9d36837bfe2d8536 Author: Martin Roth <gaumless(a)gmail.com> Date: Mon May 19 15:30:00 2014 -0600 drivers/intel/fsp: update enable_mrc_cache with fast boot When going from a configuration with fast boot disabled to one with it enabled, ENABLE_MRC_CACHE was not being enabled properly. This forces it on with ENABLE_FSP_FAST_BOOT. Change-Id: If7b6374e0c0a1d5403a50a1b0a958cea6f96cc88 Signed-off-by: Martin Roth <gaumless(a)gmail.com> --- src/drivers/intel/fsp/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/drivers/intel/fsp/Kconfig b/src/drivers/intel/fsp/Kconfig index 3e16266..ed38811 100644 --- a/src/drivers/intel/fsp/Kconfig +++ b/src/drivers/intel/fsp/Kconfig @@ -54,6 +54,7 @@ config FSP_LOC config ENABLE_FSP_FAST_BOOT bool "Enable Fast Boot" + select ENABLE_MRC_CACHE if ENABLE_FSP_FAST_BOOT default n help Enabling this feature will force the MRC data to be cached in NV @@ -62,7 +63,7 @@ config ENABLE_FSP_FAST_BOOT config ENABLE_MRC_CACHE bool - default ENABLE_FSP_FAST_BOOT + default n help Enabling this feature will cause MRC data to be cached in NV storage. This can either be used for fast boot, or just because the FSP wants
1 0
0 0
Patch set updated for coreboot: 278c784 sandy/ivybridge: Native raminit.
by Vladimir Serbinenko May 27, 2014

May 27, 2014
Vladimir Serbinenko (phcoder(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5786 -gerrit commit 278c7843430b53e39b2a22630562db2f7a8f81cb Author: Vladimir Serbinenko <phcoder(a)gmail.com> Date: Sun May 18 11:05:56 2014 +0200 sandy/ivybridge: Native raminit. Based on damo22 work and my X230 tracing. Works for my X230 in a variety of RAM configs. Also-By: Damien Zammit <damien(a)zamaudio.com> Change-Id: I1aa024c55a8416fc53b25e7123037df0e55a2769 Signed-off-by: Vladimir Serbinenko <phcoder(a)gmail.com> --- src/device/dram/ddr3.c | 8 +- src/include/device/dram/ddr3.h | 11 +- src/mainboard/lenovo/x230/romstage.c | 72 +- src/northbridge/intel/sandybridge/Makefile.inc | 2 + src/northbridge/intel/sandybridge/pchinit.c | 549 ++++ src/northbridge/intel/sandybridge/raminit.c | 3699 ++++++++++++++++++++++-- src/northbridge/intel/sandybridge/raminit.h | 16 +- 7 files changed, 4107 insertions(+), 250 deletions(-) diff --git a/src/device/dram/ddr3.c b/src/device/dram/ddr3.c index 9b4f490..69782ab 100644 --- a/src/device/dram/ddr3.c +++ b/src/device/dram/ddr3.c @@ -110,7 +110,7 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) { int ret; u16 crc, spd_crc; - u8 ftb_divisor, ftb_dividend, capacity_shift, bus_width, sdram_width; + u8 ftb_divisor, ftb_dividend, capacity_shift, bus_width; u8 reg8; u32 mtb; /* medium time base */ unsigned int val, param; @@ -209,8 +209,8 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) printram(" Invalid SDRAM width\n"); ret = SPD_STATUS_INVALID_FIELD; } - sdram_width = (4 << val); - printram(" SDRAM width : %u\n", sdram_width); + dimm->width = (4 << val); + printram(" SDRAM width : %u\n", dimm->width); /* Memory bus width */ reg8 = spd[8]; @@ -236,7 +236,7 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) * capacity_shift * The rest is the JEDEC formula */ dimm->size_mb = ((1 << (capacity_shift + (25 - 20))) * bus_width - * dimm->ranks) / sdram_width; + * dimm->ranks) / dimm->width; /* Fine Timebase (FTB) Dividend/Divisor */ /* Dividend */ diff --git a/src/include/device/dram/ddr3.h b/src/include/device/dram/ddr3.h index b19c51c..fcaf10b 100644 --- a/src/include/device/dram/ddr3.h +++ b/src/include/device/dram/ddr3.h @@ -37,6 +37,7 @@ * @{ */ #define TCK_1066MHZ 240 +#define TCK_933MHZ 275 #define TCK_800MHZ 320 #define TCK_666MHZ 384 #define TCK_533MHZ 480 @@ -54,11 +55,11 @@ * disabled. * @{ */ -#if defined(CONFIG_DEBUG_RAM_SETUP) && (CONFIG_DEBUG_RAM_SETUP) +//#if defined(CONFIG_DEBUG_RAM_SETUP) && (CONFIG_DEBUG_RAM_SETUP) #define printram(x, ...) printk(BIOS_DEBUG, x, ##__VA_ARGS__) -#else -#define printram(x, ...) -#endif +//#else +//#define printram(x, ...) +//#endif /** @} */ /* @@ -137,6 +138,8 @@ typedef struct dimm_attr_st { u16 cas_supported; /* Flags extracted from SPD */ dimm_flags_t flags; + /* SDRAM width */ + u8 width; /* Number of ranks */ u8 ranks; /* Number or row address bits */ diff --git a/src/mainboard/lenovo/x230/romstage.c b/src/mainboard/lenovo/x230/romstage.c index 6e4e685..dba19b1 100644 --- a/src/mainboard/lenovo/x230/romstage.c +++ b/src/mainboard/lenovo/x230/romstage.c @@ -114,60 +114,13 @@ void main(unsigned long bist) int cbmem_was_initted; u32 pm1_cnt; u16 pm1_sts; + spd_raw_data spd[4]; if (MCHBAR16(SSKPD) == 0xCAFE) { outb(0x6, 0xcf9); hlt (); } - struct pei_data pei_data = { - .pei_version = PEI_VERSION, - .mchbar = DEFAULT_MCHBAR, - .dmibar = DEFAULT_DMIBAR, - .epbar = DEFAULT_EPBAR, - .pciexbar = CONFIG_MMCONF_BASE_ADDRESS, - .smbusbar = SMBUS_IO_BASE, - .wdbbar = 0x4000000, - .wdbsize = 0x1000, - .hpet_address = CONFIG_HPET_ADDRESS, - .rcba = DEFAULT_RCBABASE, - .pmbase = DEFAULT_PMBASE, - .gpiobase = DEFAULT_GPIOBASE, - .thermalbase = 0xfed08000, - .system_type = 0, // 0 Mobile, 1 Desktop/Server - .tseg_size = CONFIG_SMM_TSEG_SIZE, - .spd_addresses = { 0xA0, 0x00,0xA2,0x00 }, - .ts_addresses = { 0x00, 0x00, 0x00, 0x00 }, - .ec_present = 1, - .gbe_enable = 1, - .ddr3lv_support = 0, - // 0 = leave channel enabled - // 1 = disable dimm 0 on channel - // 2 = disable dimm 1 on channel - // 3 = disable dimm 0+1 on channel - .dimm_channel0_disabled = 2, - .dimm_channel1_disabled = 2, - .max_ddr3_freq = 1600, - .usb_port_config = { - /* enabled usb oc pin length */ - { 1, 0, 0x0080 }, /* P0 (left, fan side), OC 0 */ - { 1, 1, 0x0080 }, /* P1 (left touchpad side), OC 1 */ - { 1, 3, 0x0080 }, /* P2: dock, OC 3 */ - { 1, 0, 0x0040 }, /* P3: wwan, no OC */ - { 1, 0, 0x0080 }, /* P4: Wacom tablet on X230t, otherwise empty */ - { 1, 0, 0x0080 }, /* P5: Expresscard, no OC */ - { 0, 0, 0x0000 }, /* P6: Empty */ - { 1, 0, 0x0080 }, /* P7: dock, no OC */ - { 0, 0, 0x0000 }, /* P8: Empty */ - { 1, 5, 0x0080 }, /* P9: Right (EHCI debug), OC 5 */ - { 1, 0, 0x0040 }, /* P10: fingerprint reader, no OC */ - { 1, 0, 0x0040 }, /* P11: bluetooth, no OC. */ - { 1, 0, 0x0040 }, /* P12: wlan, no OC */ - { 1, 0, 0x0080 }, /* P13: webcam, no OC */ - }, - .ddr_refresh_rate_config = 2, /* Force double refresh rate */ - }; - timestamp_init(get_initial_timestamp()); timestamp_add_now(TS_START_ROMSTAGE); @@ -224,24 +177,13 @@ void main(unsigned long bist) post_code(0x39); post_code(0x3a); - pei_data.boot_mode = boot_mode; timestamp_add_now(TS_BEFORE_INITRAM); - /* MRC.bin has a bug and sometimes halts (instead of reboot?). - */ - if (boot_mode != 2) - { - RCBA32(GCS) = RCBA32(GCS) & ~(1 << 5); /* reset */ - outw((0 << 11), DEFAULT_PMBASE | 0x60 | 0x08); /* let timer go */ - } - - sdram_initialize(&pei_data); + memset (spd, 0, sizeof (spd)); + read_spd (&spd[0], 0x50); + read_spd (&spd[2], 0x51); - if (boot_mode != 2) - { - RCBA32(GCS) = RCBA32(GCS) | (1 << 5); /* No reset */ - outw((1 << 11), DEFAULT_PMBASE | 0x60 | 0x08); /* halt timer */ - } + init_dram_ddr3 (spd, 1); timestamp_add_now(TS_AFTER_INITRAM); post_code(0x3c); @@ -254,8 +196,8 @@ void main(unsigned long bist) MCHBAR16(SSKPD) = 0xCAFE; cbmem_was_initted = !cbmem_recovery(boot_mode==2); - if (boot_mode!=2) - save_mrc_data(&pei_data); +// if (boot_mode!=2) +// save_mrc_data(&pei_data); #if CONFIG_HAVE_ACPI_RESUME /* If there is no high memory area, we didn't boot before, so diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index 6655e2a..707a8d0 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -27,6 +27,8 @@ ramstage-y += mrccache.c romstage-y += ram_calc.c romstage-y += raminit.c +romstage-y += pchinit.c +romstage-y += ../../../device/dram/ddr3.c romstage-y += mrccache.c romstage-y += early_init.c romstage-y += report_platform.c diff --git a/src/northbridge/intel/sandybridge/pchinit.c b/src/northbridge/intel/sandybridge/pchinit.c new file mode 100644 index 0000000..72fd156 --- /dev/null +++ b/src/northbridge/intel/sandybridge/pchinit.c @@ -0,0 +1,549 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Vladimir Serbinenko <phcoder(a)gmail.com> + * + * 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/hlt.h> +#include <arch/io.h> +#include <cbmem.h> +#include <arch/cbfs.h> +#include <cbfs.h> +#include <ip_checksum.h> +#include <pc80/mc146818rtc.h> +#include <device/pci_def.h> +#include "raminit.h" +#include "pei_data.h" +#include "sandybridge.h" +#include <delay.h> + +/* Management Engine is in the southbridge */ +#include "southbridge/intel/bd82x6x/me.h" +#include "southbridge/intel/bd82x6x/pch.h" +#include <cpu/x86/msr.h> +#include <cpu/cpu.h> +#include "cpu/intel/model_2065x/model_2065x.h" + +#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0) + +static void +wait_2338 (void) +{ + while (read8 (DEFAULT_RCBABASE | 0x2338) & 1); +} + +static u32 +read_2338 (u32 edx) +{ + u32 ret; + + write32 (DEFAULT_RCBABASE | 0x2330, edx); + write16 (DEFAULT_RCBABASE | 0x2338, (read16 (DEFAULT_RCBABASE | 0x2338) + & 0x1ff) | 0x600); + wait_2338 (); + ret = read32 (DEFAULT_RCBABASE | 0x2334); + wait_2338 (); + read8 (DEFAULT_RCBABASE | 0x2338); + return ret; +} + +static void +write_2338 (u32 edx, u32 val) +{ + read_2338 (edx); + write16 (DEFAULT_RCBABASE | 0x2338, (read16 (DEFAULT_RCBABASE | 0x2338) + & 0x1ff) | 0x600); + wait_2338 (); + + write32 (DEFAULT_RCBABASE | 0x2334, val); + wait_2338 (); + write16 (DEFAULT_RCBABASE | 0x2338, + (read16 (DEFAULT_RCBABASE | 0x2338) & 0x1ff) | 0x600); + read8 (DEFAULT_RCBABASE | 0x2338); +} + +#define USB_ACC_CONTROL 0x80 + +static void +init_usb (void) +{ + u32 base; + read32 (DEFAULT_RCBABASE | 0x3418); // !!! = 0x06000000 + pcie_read_config16 (SOUTHBRIDGE, 0x40); // !!! = 0x0501 + read32 (DEFAULT_RCBABASE | 0x3598); // !!! = 0x00000000 + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0x10); // !!! = 0x00000000 + pcie_read_config16 (PCI_DEV (0, 0x1d, 0), 0x04); // !!! = 0x0000 + base = 0xe8000000; + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0x10, base); + pcie_read_config16 (PCI_DEV (0, 0x1d, 0), 0x04); // !!! = 0x0000 + pcie_write_config16 (PCI_DEV (0, 0x1d, 0), 0x04, 0x0006); + + pcie_write_config16 (PCI_DEV (0, 0x1d, 0), USB_ACC_CONTROL, + pcie_read_config16 (PCI_DEV (0, 0x1d, 0), + USB_ACC_CONTROL) | 1); + read32 (base + 4); // !!! = 0x00204008 + write32 (base + 4, 0x00200008); + read32 (base + 4); // !!! = 0x00200008 + write32 (base + 4, 0x00200003); + pcie_write_config16 (PCI_DEV (0, 0x1d, 0), USB_ACC_CONTROL, + pcie_read_config16 (PCI_DEV (0, 0x1d, 0), + USB_ACC_CONTROL) & ~1); + read32 (0xe8000024); // !!! = 0x00001000 + write16 (0xe8000020, read16 (0xe8000020) | 2); + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0x84); // !!! = 0x83088e01 + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0x84, 0x930c8811); + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0x88); // !!! = 0x04000030 + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0x88, 0x24000d30); + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0xf4); // !!! = 0x00408588 + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0xf4, 0x80408588); + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0xf4); // !!! = 0x80408588 + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0xf4, 0x80808588); + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0xf4); // !!! = 0x80808588 + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0xf4, 0x00808588); + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0xfc); // !!! = 0x20591708 + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0xfc, 0x205b1708); + write32 (DEFAULT_RCBABASE | 0x3560, + read32 (DEFAULT_RCBABASE | 0x3560) | 0x20c8000); + pcie_read_config16 (PCI_DEV (0, 0x1d, 0), 0x04); // !!! = 0x0006 + pcie_write_config16 (PCI_DEV (0, 0x1d, 0), 0x04, 0x0000); + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0x10, 0x00000000); + base = 0xfef00000; + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0x10); // !!! = 0xfef00000 + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0x10); // !!! = 0xfef00000 + pcie_read_config16 (PCI_DEV (0, 0x1a, 0), 0x04); // !!! = 0x0002 + pcie_read_config16 (PCI_DEV (0, 0x1a, 0), 0x04); // !!! = 0x0002 + pcie_write_config16 (PCI_DEV (0, 0x1a, 0), 0x04, 0x0006); + pcie_write_config16 (PCI_DEV (0, 0x1a, 0), 0x80, + pcie_read_config16 (PCI_DEV (0, 0x1a, 0), 0x80) | 1); + read32 (base + 4); // !!! = 0x00203006 + write32 (base + 4, 0x00200006); + read32 (base + 4); // !!! = 0x00200006 + write32 (base + 4, 0x00200003); + pcie_write_config16 (PCI_DEV (0, 0x1a, 0), USB_ACC_CONTROL, + pcie_read_config16 (PCI_DEV (0, 0x1a, 0), + USB_ACC_CONTROL) & ~1); + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0x84); // !!! = 0x83088e01 + pcie_write_config32 (PCI_DEV (0, 0x1a, 0), 0x84, 0x930c8811); + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0x88); // !!! = 0x04000030 + pcie_write_config32 (PCI_DEV (0, 0x1a, 0), 0x88, 0x24000d30); + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0xf4); // !!! = 0x00408588 + pcie_write_config32 (PCI_DEV (0, 0x1a, 0), 0xf4, 0x80408588); + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0xf4); // !!! = 0x80408588 + pcie_write_config32 (PCI_DEV (0, 0x1a, 0), 0xf4, 0x80808588); + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0xf4); // !!! = 0x80808588 + pcie_write_config32 (PCI_DEV (0, 0x1a, 0), 0xf4, 0x00808588); + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0xfc); // !!! = 0x20591708 + pcie_write_config32 (PCI_DEV (0, 0x1a, 0), 0xfc, 0x205b1708); + write32 (DEFAULT_RCBABASE | 0x3560, + read32 (DEFAULT_RCBABASE | 0x3560) | 0x20c8000); + pcie_write_config16 (PCI_DEV (0, 0x1a, 0), 0x04, 0x0002); + + pcie_read_config16 (SOUTHBRIDGE, 0x02); // !!! = 0x1e55 + outw (inw (DEFAULT_PMBASE | 0x003c) | 2, DEFAULT_PMBASE | 0x003c); + u16 reg_359c = 0x150; + int i; + for (i = 0; i < 14; i++) + if (reg_359c & (1 << i)) + write16 (DEFAULT_RCBABASE | 0x359c, + read16 (DEFAULT_RCBABASE | 0x359c) | (1 << i)); + else + write16 (DEFAULT_RCBABASE | 0x359c, + read16 (DEFAULT_RCBABASE | 0x359c) & ~(1 << i)); + pcie_read_config8 (SOUTHBRIDGE, 0x08); // !!! = 0x04 + pcie_read_config16 (SOUTHBRIDGE, 0x02); // !!! = 0x1e55 + pcie_read_config32 (PCI_DEV (0, 0x14, 0), 0xe4); // !!! = 0x00000000 + pcie_write_config32 (PCI_DEV (0, 0x14, 0), 0xe4, 0x00000000); + outw (0x0000, DEFAULT_PMBASE | 0x003c); + write32 (DEFAULT_RCBABASE | 0x3418, 0x16001fe0); + read32 (DEFAULT_RCBABASE | 0x3418); // !!! = 0x16001fe0 +} + +static void +init_thermal (void) +{ + /* OK { */ + pcie_write_config32 (PCI_DEV (0, 0x1f, 6), 0x40, 0xfed08000); + pcie_write_config32 (PCI_DEV (0, 0x1f, 6), 0x44, 0x00000000); + pcie_read_config32 (PCI_DEV (0, 0x1f, 6), 0x40); // !!! = 0xfed08004 + pcie_write_config32 (PCI_DEV (0, 0x1f, 6), 0x40, 0xfed08005); + write16 (0xfed08004, 0x3a2b); + write8 (0xfed0800c, 0xff); + write8 (0xfed0800d, 0x00); + write8 (0xfed0800e, 0x40); + write8 (0xfed08082, 0x00); + write8 (0xfed08001, 0xba); + msr_t msr; + msr = rdmsr (MSR_TEMPERATURE_TARGET); // !!! = 0x0000000000691200 + write16 (0xfed08012, ((msr.lo >> 16) & 0xff) << 6); + write16 (0xfed08016, 0x808c); + + + write32 (DEFAULT_RCBABASE | 0x38b0, + (read32 (DEFAULT_RCBABASE | 0x38b0) & 0xffff8003) | 0x403c); + + write16 (0xfed08014, 0xde87); + /* } OK */ + if (read32 (DEFAULT_RCBABASE | 0x38b4) & 0x4000) // !!! = 0x0000437e + write16 (0xfed0801a, 0x0000); + else + { + /* ? */ + } + pcie_read_config32 (PCI_DEV (0, 0x1f, 6), 0x40); // !!! = 0xfed08005 + pcie_write_config32 (PCI_DEV (0, 0x1f, 6), 0x40, 0xfed08004); + pcie_write_config32 (PCI_DEV (0, 0x1f, 6), 0x40, 0x00000000); +} + +void +pch_init (void) +{ + int i; + + /* Undocumented. */ + pcie_write_config8 (SOUTHBRIDGE, 0xa6, + pcie_read_config8 (SOUTHBRIDGE, 0xa6) | 2); + + write32 (DEFAULT_RCBABASE | 0x2088, 0x00109000); + read32 (DEFAULT_RCBABASE | 0x20ac); // !!! = 0x00000000 + write32 (DEFAULT_RCBABASE | 0x20ac, 0x40000000); + write32 (DEFAULT_RCBABASE | 0x100c, 0x01110000); + write8 (DEFAULT_RCBABASE | 0x2340, 0x1b); + read32 (DEFAULT_RCBABASE | 0x2314); // !!! = 0x0a080000 + write32 (DEFAULT_RCBABASE | 0x2314, 0x0a280000); + read32 (DEFAULT_RCBABASE | 0x2310); // !!! = 0xc809605b + write32 (DEFAULT_RCBABASE | 0x2310, 0xa809605b); + write32 (DEFAULT_RCBABASE | 0x2324, 0x00854c74); + read8 (DEFAULT_RCBABASE | 0x0400); // !!! = 0x00 + read32 (DEFAULT_RCBABASE | 0x2310); // !!! = 0xa809605b + write32 (DEFAULT_RCBABASE | 0x2310, 0xa809605b); + read32 (DEFAULT_RCBABASE | 0x2310); // !!! = 0xa809605b + write32 (DEFAULT_RCBABASE | 0x2310, 0xa809605b); + + write_2338 (0xea007f62, 0x00590133); + write_2338 (0xec007f62, 0x00590133); + write_2338 (0xec007f64, 0x59555588); + write_2338 (0xea0040b9, 0x0001051c); + write_2338 (0xeb0040a1, 0x800084ff); + write_2338 (0xec0040a1, 0x800084ff); + write_2338 (0xea004001, 0x00008400); + write_2338 (0xeb004002, 0x40201758); + write_2338 (0xec004002, 0x40201758); + write_2338 (0xea004002, 0x00601758); + write_2338 (0xea0040a1, 0x810084ff); + write_2338 (0xeb0040b1, 0x0001c598); + write_2338 (0xec0040b1, 0x0001c598); + write_2338 (0xeb0040b6, 0x0001c598); + write_2338 (0xea0000a9, 0x80ff969f); + write_2338 (0xea0001a9, 0x80ff969f); + write_2338 (0xeb0040b2, 0x0001c396); + write_2338 (0xeb0040b3, 0x0001c396); + write_2338 (0xec0040b2, 0x0001c396); + write_2338 (0xea0001a9, 0x80ff94ff); + write_2338 (0xea000151, 0x0088037f); + write_2338 (0xea0000a9, 0x80ff94ff); + write_2338 (0xea000051, 0x0088037f); + + write_2338 (0xea007f05, 0x00010642); + write_2338 (0xea0040b7, 0x0001c91c); + write_2338 (0xea0040b8, 0x0001c91c); + write_2338 (0xeb0040a1, 0x820084ff); + write_2338 (0xec0040a1, 0x820084ff); + write_2338 (0xea007f0a, 0xc2480000); + + write_2338 (0xec00404d, 0x1ff177f); + write_2338 (0xec000084, 0x5a600000); + write_2338 (0xec000184, 0x5a600000); + write_2338 (0xec000284, 0x5a600000); + write_2338 (0xec000384, 0x5a600000); + write_2338 (0xec000094, 0x000f0501); + write_2338 (0xec000194, 0x000f0501); + write_2338 (0xec000294, 0x000f0501); + write_2338 (0xec000394, 0x000f0501); + write_2338 (0xec000096, 0x00000001); + write_2338 (0xec000196, 0x00000001); + write_2338 (0xec000296, 0x00000001); + write_2338 (0xec000396, 0x00000001); + write_2338 (0xec000001, 0x00008c08); + write_2338 (0xec000101, 0x00008c08); + write_2338 (0xec000201, 0x00008c08); + write_2338 (0xec000301, 0x00008c08); + write_2338 (0xec0040b5, 0x0001c518); + write_2338 (0xec000087, 0x06077597); + write_2338 (0xec000187, 0x06077597); + write_2338 (0xec000287, 0x06077597); + write_2338 (0xec000387, 0x06077597); + write_2338 (0xea000050, 0x00bb0157); + write_2338 (0xea000150, 0x00bb0157); + write_2338 (0xec007f60, 0x77777d77); + write_2338 (0xea00008d, 0x01320000); + write_2338 (0xea00018d, 0x01320000); + + read16 (DEFAULT_RCBABASE | 0x0400); // !!! = 0x0b00 + read32 (DEFAULT_RCBABASE | 0x0400); // !!! = 0x00000b00 + + write_2338 (0xec0007b2, 0x04514b5e); + write_2338 (0xec00078c, 0x40000200); + write_2338 (0xec000780, 0x02000020); + + read8 (DEFAULT_RCBABASE | 0x3414); // !!! = 0x00 + + read32 (DEFAULT_RCBABASE | 0x3598); // !!! = 0x00000001 + read32 (DEFAULT_RCBABASE | 0x3598); // !!! = 0x00000001 + write32 (DEFAULT_RCBABASE | 0x3598, 0x00000000); + read32 (DEFAULT_RCBABASE | 0x3598); // !!! = 0x00000000 + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0x88); // !!! = 0x04000030 + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0x88, 0x04000030); + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0x88); // !!! = 0x04000030 + pcie_write_config32 (PCI_DEV (0, 0x1a, 0), 0x88, 0x04000030); + + read32 (DEFAULT_RCBABASE | 0x3410); // !!! = 0x00000c20 + write32 (DEFAULT_RCBABASE | 0x3410, 0x00000c20); + read32 (DEFAULT_RCBABASE | 0x3410); // !!! = 0x00000c20 + /* Disable SATA2. */ + write32 (DEFAULT_RCBABASE | 0x3418, + read32 (DEFAULT_RCBABASE | 0x3418) | 0x02000000); + read32 (DEFAULT_RCBABASE | 0x3418); // !!! = 0x06000000 + + /* Configure thermal */ + init_thermal (); + + read8 (DEFAULT_RCBABASE | 0x31fe); // !!! = 0x00 + read16 (DEFAULT_RCBABASE | 0x31fe); // !!! = 0x0000 + write16 (DEFAULT_RCBABASE | 0x31fe, 0x0100); + read16 (DEFAULT_RCBABASE | 0x31fe); // !!! = 0x0100 + read8 (DEFAULT_RCBABASE | 0x31fe); // !!! = 0x00 + write8 (0xfec00000, 0x00); + read32 (0xfec00010); // !!! = 0x00000000 + init_usb (); + + write32 (DEFAULT_DMIBAR | 0x0914, + read32 (DEFAULT_DMIBAR | 0x0914) | 0x80000000); + write32 (DEFAULT_DMIBAR | 0x0934, + read32 (DEFAULT_DMIBAR | 0x0934) | 0x80000000); + for (i = 0; i < 4; i++) + { + write32 (DEFAULT_DMIBAR | 0x0a00 | (i << 4), + read32 (DEFAULT_DMIBAR | 0x0a00 | (i << 4)) & 0xf3ffffff); + write32 (DEFAULT_DMIBAR | 0x0a04 | (i << 4), + read32 (DEFAULT_DMIBAR | 0x0a04 | (i << 4)) | 0x800); + } + write32 (DEFAULT_DMIBAR | 0x0c30, (read32 (DEFAULT_DMIBAR | 0x0c30) + & 0xfffffff) | 0x40000000); + for (i = 0; i < 2; i++) + { + write32 (DEFAULT_DMIBAR | 0x0904 | (i << 5), + read32 (DEFAULT_DMIBAR | 0x0904 | (i << 5)) & 0xfe3fffff); + write32 (DEFAULT_DMIBAR | 0x090c | (i << 5), + read32 (DEFAULT_DMIBAR | 0x090c | (i << 5)) & 0xfff1ffff); + } + write32 (DEFAULT_DMIBAR | 0x090c, + read32 (DEFAULT_DMIBAR | 0x090c) & 0xfe1fffff); + write32 (DEFAULT_DMIBAR | 0x092c, + read32 (DEFAULT_DMIBAR | 0x092c) & 0xfe1fffff); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x7a1842ec); + read32 (DEFAULT_DMIBAR | 0x090c); // !!! = 0x00000208 + write32 (DEFAULT_DMIBAR | 0x090c, 0x00000128); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x7a1842ec); + read32 (DEFAULT_DMIBAR | 0x092c); // !!! = 0x00000208 + write32 (DEFAULT_DMIBAR | 0x092c, 0x00000128); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0c04); // !!! = 0x2e680008 + write32 (DEFAULT_DMIBAR | 0x0c04, 0x2e680008); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x3a1842ec); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x3a1842ec); + read32 (DEFAULT_DMIBAR | 0x0910); // !!! = 0x00006300 + write32 (DEFAULT_DMIBAR | 0x0910, 0x00004300); + read32 (DEFAULT_DMIBAR | 0x0930); // !!! = 0x00006300 + write32 (DEFAULT_DMIBAR | 0x0930, 0x00004300); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0c00); // !!! = 0x29700c08 + write32 (DEFAULT_DMIBAR | 0x0c00, 0x29700c08); + read32 (DEFAULT_DMIBAR | 0x0a04); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a04, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0a14); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a14, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0a24); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a24, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0a34); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a34, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0900); // !!! = 0x50000000 + write32 (DEFAULT_DMIBAR | 0x0900, 0x50000000); + read32 (DEFAULT_DMIBAR | 0x0920); // !!! = 0x50000000 + write32 (DEFAULT_DMIBAR | 0x0920, 0x50000000); + read32 (DEFAULT_DMIBAR | 0x0908); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0908, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0928); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0928, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x3a1842ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x3a1846ec); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x3a1842ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x3a1846ec); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0908); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0908, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0928); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0928, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0c00); // !!! = 0x29700c08 + write32 (DEFAULT_DMIBAR | 0x0c00, 0x29700c08); + read32 (DEFAULT_DMIBAR | 0x0c0c); // !!! = 0x16063400 + write32 (DEFAULT_DMIBAR | 0x0c0c, 0x00063400); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x46339008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x46339008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46339008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x45339008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46339008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x45339008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x45339008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x453b9008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x45339008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x453b9008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x453b9008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x45bb9008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x453b9008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x45bb9008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x45bb9008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x45fb9008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x45bb9008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x45fb9008); + read32 (DEFAULT_DMIBAR | 0x0914); // !!! = 0x9021a080 + write32 (DEFAULT_DMIBAR | 0x0914, 0x9021a280); + read32 (DEFAULT_DMIBAR | 0x0934); // !!! = 0x9021a080 + write32 (DEFAULT_DMIBAR | 0x0934, 0x9021a280); + read32 (DEFAULT_DMIBAR | 0x0914); // !!! = 0x9021a280 + write32 (DEFAULT_DMIBAR | 0x0914, 0x9821a280); + read32 (DEFAULT_DMIBAR | 0x0934); // !!! = 0x9021a280 + write32 (DEFAULT_DMIBAR | 0x0934, 0x9821a280); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0258); // !!! = 0x40000600 + write32 (DEFAULT_DMIBAR | 0x0258, 0x60000600); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x3a1846ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x2a1846ec); + read32 (DEFAULT_DMIBAR | 0x0914); // !!! = 0x9821a280 + write32 (DEFAULT_DMIBAR | 0x0914, 0x98200280); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x3a1846ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x2a1846ec); + read32 (DEFAULT_DMIBAR | 0x0934); // !!! = 0x9821a280 + write32 (DEFAULT_DMIBAR | 0x0934, 0x98200280); + read32 (DEFAULT_DMIBAR | 0x022c); // !!! = 0x00c26460 + write32 (DEFAULT_DMIBAR | 0x022c, 0x00c2403c); + read8 (DEFAULT_RCBABASE | 0x21a4); // !!! = 0x42 + + read32 (DEFAULT_RCBABASE | 0x21a4); // !!! = 0x00012c42 + read32 (DEFAULT_RCBABASE | 0x2340); // !!! = 0x0013001b + write32 (DEFAULT_RCBABASE | 0x2340, 0x003a001b); + read8 (DEFAULT_RCBABASE | 0x21b0); // !!! = 0x01 + write8 (DEFAULT_RCBABASE | 0x21b0, 0x02); + read32 (DEFAULT_DMIBAR | 0x0084); // !!! = 0x0041ac41 + write32 (DEFAULT_DMIBAR | 0x0084, 0x0041ac42); + read8 (DEFAULT_DMIBAR | 0x0088); // !!! = 0x00 + write8 (DEFAULT_DMIBAR | 0x0088, 0x20); + read16 (DEFAULT_DMIBAR | 0x008a); // !!! = 0x0041 + read8 (DEFAULT_DMIBAR | 0x0088); // !!! = 0x00 + write8 (DEFAULT_DMIBAR | 0x0088, 0x20); + read16 (DEFAULT_DMIBAR | 0x008a); // !!! = 0x0042 + read16 (DEFAULT_DMIBAR | 0x008a); // !!! = 0x0042 + + pcie_read_config16 (PCI_DEV (0, 0x1e, 0), 0x00); // !!! = 0x8086 + pcie_write_config32 (PCI_DEV (0, 0x1e, 0), 0x18, 0x00ff0200); + pcie_read_config8 (PCI_DEV (0, 0x1e, 0), 0x19); // !!! = 0x02 + + pcie_write_config8 (PCI_DEV (0, 0x1e, 0), 0x1a, 0x02); + pcie_write_config32 (PCI_DEV (0, 0x1e, 0), 0x18, 0x00000000); + + read32 (DEFAULT_DMIBAR | 0x0014); // !!! = 0x8000007f + write32 (DEFAULT_DMIBAR | 0x0014, 0x80000019); + read32 (DEFAULT_DMIBAR | 0x0020); // !!! = 0x01000000 + write32 (DEFAULT_DMIBAR | 0x0020, 0x81000022); + read32 (DEFAULT_DMIBAR | 0x002c); // !!! = 0x02000000 + write32 (DEFAULT_DMIBAR | 0x002c, 0x82000044); + read32 (DEFAULT_DMIBAR | 0x0038); // !!! = 0x07000080 + write32 (DEFAULT_DMIBAR | 0x0038, 0x87000080); + read8 (DEFAULT_DMIBAR | 0x0004); // !!! = 0x00 + write8 (DEFAULT_DMIBAR | 0x0004, 0x01); + pcie_read_config32 (SOUTHBRIDGE, 0xf0); // !!! = 0xfed1c001 + read32 (DEFAULT_RCBABASE | 0x0050); // !!! = 0x01200654 + write32 (DEFAULT_RCBABASE | 0x0050, 0x01200654); + read32 (DEFAULT_RCBABASE | 0x0050); // !!! = 0x01200654 + write32 (DEFAULT_RCBABASE | 0x0050, 0x012a0654); + read32 (DEFAULT_RCBABASE | 0x0050); // !!! = 0x012a0654 + read8 (DEFAULT_RCBABASE | 0x1114); // !!! = 0x00 + write8 (DEFAULT_RCBABASE | 0x1114, 0x05); + read32 (DEFAULT_RCBABASE | 0x2014); // !!! = 0x80000011 + write32 (DEFAULT_RCBABASE | 0x2014, 0x80000019); + read32 (DEFAULT_RCBABASE | 0x2020); // !!! = 0x00000000 + write32 (DEFAULT_RCBABASE | 0x2020, 0x81000022); + read32 (DEFAULT_RCBABASE | 0x2020); // !!! = 0x81000022 + read32 (DEFAULT_RCBABASE | 0x2030); // !!! = 0x00000000 + write32 (DEFAULT_RCBABASE | 0x2030, 0x82000044); + read32 (DEFAULT_RCBABASE | 0x2030); // !!! = 0x82000044 + read32 (DEFAULT_RCBABASE | 0x2040); // !!! = 0x00000000 + write32 (DEFAULT_RCBABASE | 0x2040, 0x87000080); + read32 (DEFAULT_RCBABASE | 0x0050); // !!! = 0x012a0654 + write32 (DEFAULT_RCBABASE | 0x0050, 0x812a0654); + read32 (DEFAULT_RCBABASE | 0x0050); // !!! = 0x812a0654 + read16 (DEFAULT_RCBABASE | 0x201a); // !!! = 0x0000 + read16 (DEFAULT_RCBABASE | 0x2026); // !!! = 0x0000 + read16 (DEFAULT_RCBABASE | 0x2036); // !!! = 0x0000 + read16 (DEFAULT_RCBABASE | 0x2046); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x001a); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x0026); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x0032); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x003e); // !!! = 0x0000 +} diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index 61e1545..1feaf45 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -1,7 +1,8 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2011 Google Inc. + * Copyright (C) 2014 Damien Zammit <damien(a)zamaudio.com> + * Copyright (C) 2014 Vladimir Serbinenko <phcoder(a)gmail.com> * * 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 @@ -31,128 +32,151 @@ #include "raminit.h" #include "pei_data.h" #include "sandybridge.h" +#include <delay.h> /* Management Engine is in the southbridge */ #include "southbridge/intel/bd82x6x/me.h" +#include "southbridge/intel/bd82x6x/pch.h" +#include "southbridge/intel/bd82x6x/smbus.h" +#include <cpu/x86/msr.h> +#include <cpu/cpu.h> +#include "cpu/intel/model_2065x/model_2065x.h" + #if CONFIG_CHROMEOS #include <vendorcode/google/chromeos/chromeos.h> #else #define recovery_mode_enabled(x) 0 #endif -/* - * MRC scrambler seed offsets should be reserved in - * mainboard cmos.layout and not covered by checksum. - */ -#if CONFIG_USE_OPTION_TABLE -#include "option_table.h" -#define CMOS_OFFSET_MRC_SEED (CMOS_VSTART_mrc_scrambler_seed >> 3) -#define CMOS_OFFSET_MRC_SEED_S3 (CMOS_VSTART_mrc_scrambler_seed_s3 >> 3) -#define CMOS_OFFSET_MRC_SEED_CHK (CMOS_VSTART_mrc_scrambler_seed_chk >> 3) -#else -#define CMOS_OFFSET_MRC_SEED 152 -#define CMOS_OFFSET_MRC_SEED_S3 156 -#define CMOS_OFFSET_MRC_SEED_CHK 160 -#endif +/* FIXME: no ECC support. */ +/* FIXME: no support for 3-channel chipsets. */ +/* FIXME: no S3. */ +/* FIXME: no timing caching. */ -void save_mrc_data(struct pei_data *pei_data) -{ - u16 c1, c2, checksum; +#define SANDYIVY_MAX_DIMM_SLOTS 4 -#if CONFIG_EARLY_CBMEM_INIT - struct mrc_data_container *mrcdata; - int output_len = ALIGN(pei_data->mrc_output_len, 16); +#define BASEFREQ 133 +#define tDLLK 512 - /* Save the MRC S3 restore data to cbmem */ - mrcdata = cbmem_add - (CBMEM_ID_MRCDATA, - output_len + sizeof(struct mrc_data_container)); +#define IS_SANDY_CPU(x) ((x & 0xffff0) == 0x206a0) +#define IS_SANDY_CPU_C(x) ((x & 0xf) == 4) +#define IS_SANDY_CPU_D0(x) ((x & 0xf) == 5) +#define IS_SANDY_CPU_D1(x) ((x & 0xf) == 6) +#define IS_SANDY_CPU_D2(x) ((x & 0xf) == 7) - printk(BIOS_DEBUG, "Relocate MRC DATA from %p to %p (%u bytes)\n", - pei_data->mrc_output, mrcdata, output_len); +#define IS_IVY_CPU(x) ((x & 0xffff0) == 0x306a0) +#define IS_IVY_CPU_C(x) ((x & 0xf) == 4) +#define IS_IVY_CPU_K(x) ((x & 0xf) == 5) +#define IS_IVY_CPU_D(x) ((x & 0xf) == 6) +#define IS_IVY_CPU_E(x) ((x & 0xf) >= 8) - mrcdata->mrc_signature = MRC_DATA_SIGNATURE; - mrcdata->mrc_data_size = output_len; - mrcdata->reserved = 0; - memcpy(mrcdata->mrc_data, pei_data->mrc_output, - pei_data->mrc_output_len); +#define NUM_CHANNELS 2 +#define NUM_SLOTRANKS 4 - /* Zero the unused space in aligned buffer. */ - if (output_len > pei_data->mrc_output_len) - memset(mrcdata->mrc_data+pei_data->mrc_output_len, 0, - output_len - pei_data->mrc_output_len); +typedef struct odtmap_st { + u16 rttwr; + u16 rttnom; +} odtmap; - mrcdata->mrc_checksum = compute_ip_checksum(mrcdata->mrc_data, - mrcdata->mrc_data_size); -#endif +typedef struct dimm_info_st +{ + dimm_attr dimm[SANDYIVY_MAX_DIMM_SLOTS]; +} dimm_info; - /* Save the MRC seed values to CMOS */ - cmos_write32(CMOS_OFFSET_MRC_SEED, pei_data->scrambler_seed); - printk(BIOS_DEBUG, "Save scrambler seed 0x%08x to CMOS 0x%02x\n", - pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED); +struct ram_rank_timings +{ + /* Register 4024. One byte per slotrank. */ + u8 val_4024; + /* Register 4028. One nibble per slotrank. */ + u8 val_4028; - cmos_write32(CMOS_OFFSET_MRC_SEED_S3, pei_data->scrambler_seed_s3); - printk(BIOS_DEBUG, "Save s3 scrambler seed 0x%08x to CMOS 0x%02x\n", - pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3); + int val_320c; - /* Save a simple checksum of the seed values */ - c1 = compute_ip_checksum((u8*)&pei_data->scrambler_seed, - sizeof(u32)); - c2 = compute_ip_checksum((u8*)&pei_data->scrambler_seed_s3, - sizeof(u32)); - checksum = add_ip_checksums(sizeof(u32), c1, c2); + struct ram_lane_timings + { + /* lane register offset 0x10. */ + u16 timA; /* bits 0 - 5, bits 16 - 18 */ + u8 rising; /* bits 8 - 14 */ + u8 falling; /* bits 20 - 26. */ - cmos_write(checksum & 0xff, CMOS_OFFSET_MRC_SEED_CHK); - cmos_write((checksum >> 8) & 0xff, CMOS_OFFSET_MRC_SEED_CHK+1); -} + /* lane register offset 0x20. */ + int timC; /* bit 0 - 5, 19. */ + u16 timB; /* bits 8 - 13, 15 - 17. */ + } lanes[8]; +}; -static void prepare_mrc_cache(struct pei_data *pei_data) -{ - struct mrc_data_container *mrc_cache; - u16 c1, c2, checksum, seed_checksum; +typedef struct ramctr_timing_st { + int mobile; - // preset just in case there is an error - pei_data->mrc_input = NULL; - pei_data->mrc_input_len = 0; + enum spd_memory_type dram_type; + u16 cas_supported; + /* tLatencies are in units of ns, scaled by x256 */ + u32 tCK; + u32 tAA; + u32 tWR; + u32 tRCD; + u32 tRRD; + u32 tRP; + u32 tRAS; + u32 tRC; + u32 tRFC; + u32 tWTR; + u32 tRTP; + u32 tFAW; + /* Latencies in terms of clock cycles + * They are saved separately as they are needed for DRAM MRS commands*/ + u8 CAS; /* CAS read latency */ + u8 CWL; /* CAS write latency */ + /* Number of dimms currently connected */ + u8 n_dimms; - /* Read scrambler seeds from CMOS */ - pei_data->scrambler_seed = cmos_read32(CMOS_OFFSET_MRC_SEED); - printk(BIOS_DEBUG, "Read scrambler seed 0x%08x from CMOS 0x%02x\n", - pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED); + u32 tREFI; + u32 tMOD; + u32 tXSOffset; + u32 tWLO; + u32 tCKE; + u32 tXPDLL; + u32 tXP; + u32 tAONPD; - pei_data->scrambler_seed_s3 = cmos_read32(CMOS_OFFSET_MRC_SEED_S3); - printk(BIOS_DEBUG, "Read S3 scrambler seed 0x%08x from CMOS 0x%02x\n", - pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3); + u32 delay1; + u32 delay2; - /* Compute seed checksum and compare */ - c1 = compute_ip_checksum((u8*)&pei_data->scrambler_seed, - sizeof(u32)); - c2 = compute_ip_checksum((u8*)&pei_data->scrambler_seed_s3, - sizeof(u32)); - checksum = add_ip_checksums(sizeof(u32), c1, c2); + u8 eccsupport; + u8 dualchannel; + u8 thermalrefresh; - seed_checksum = cmos_read(CMOS_OFFSET_MRC_SEED_CHK); - seed_checksum |= cmos_read(CMOS_OFFSET_MRC_SEED_CHK+1) << 8; + u8 rankmap[2][2]; //channels, dimms - if (checksum != seed_checksum) { - printk(BIOS_ERR, "%s: invalid seed checksum\n", __func__); - pei_data->scrambler_seed = 0; - pei_data->scrambler_seed_s3 = 0; - return; - } + int reg_c14_offset; - if ((mrc_cache = find_current_mrc_cache()) == NULL) { - /* error message printed in find_current_mrc_cache */ - return; - } + int edge_offset[3]; + int timC_offset[3]; - pei_data->mrc_input = mrc_cache->mrc_data; - pei_data->mrc_input_len = mrc_cache->mrc_data_size; + int rank_mirror[NUM_CHANNELS][NUM_SLOTRANKS]; - printk(BIOS_DEBUG, "%s: at %p, size %x checksum %04x\n", - __func__, pei_data->mrc_input, - pei_data->mrc_input_len, mrc_cache->mrc_checksum); -} + struct ram_rank_timings timings[NUM_CHANNELS][NUM_SLOTRANKS]; +} ramctr_timing; + +#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0) +#define NORTHBRIDGE PCI_DEV(0, 0x0, 0) +#define GFX_DEV PCI_DEV(0, 0x2, 0) +#define HECIDEV PCI_DEV(0, 0x16, 0) +#define NUM_SLOTS 2 +#define NUM_LANES 8 +#define FOR_ALL_LANES for (lane = 0; lane < NUM_LANES; lane++) +#define FOR_ALL_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++) +#define FOR_ALL_POPULATED_RANKS for (slotrank = 0; slotrank < NUM_SLOTRANKS; slotrank++) if ((ctrl->rankmap[channel][0] | ctrl->rankmap[channel][1]) & (1 << slotrank)) +#define FOR_ALL_POPULATED_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++) if (ctrl->rankmap[channel][0] | ctrl->rankmap[channel][1]) +#define max(a,b) ((a) > (b) ? (a) : (b)) +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define MAX_EDGE_TIMING 71 +#define MAX_TIMC 127 +#define MAX_TIMB 511 +#define MAX_TIMA 127 + +static void +program_timings (ramctr_timing *ctrl, int channel); static const char* ecc_decoder[] = { "inactive", @@ -161,6 +185,28 @@ static const char* ecc_decoder[] = { "active" }; +static void +wait_txt_clear (void) +{ + struct cpuid_result cp; + + cp = cpuid_ext (0x1, 0x0); + /* Check if TXT is supported? */ + if (!(cp.ecx & 0x40)) + return; + /* Some TXT public bit. */ + if (!(read32 (0xfed30010) & 1)) + return; + /* Wait for TXT clear. */ + while (!(read8 (0xfed40000) & (1 << 7))); +} + +static void +sfence (void) +{ + asm volatile ("sfence"); +} + /* * Dump in the log memory controller configuration as read from the memory * controller registers. @@ -204,97 +250,3418 @@ static void report_memory_config(void) } } -static void post_system_agent_init(struct pei_data *pei_data) +static void post_system_agent_init(void) { /* If PCIe init is skipped, set the PEG clock gating */ - if (!pei_data->pcie_init) - MCHBAR32(0x7010) = MCHBAR32(0x7010) | 0x01; + MCHBAR32(0x7010) = MCHBAR32(0x7010) | 0x01; } -/** - * Find PEI executable in coreboot filesystem and execute it. - * - * @param pei_data: configuration data for UEFI PEI reference code - */ -void sdram_initialize(struct pei_data *pei_data) +void read_spd(spd_raw_data *spd, u8 addr) { - struct sys_info sysinfo; - int (*entry) (struct pei_data *pei_data) __attribute__ ((regparm(1))); + int j; + for (j = 0; j < 256; j++) + (*spd)[j] = do_smbus_read_byte(SMBUS_IO_BASE, addr, j); +} - report_platform_info(); +static void dram_find_spds_ddr3(spd_raw_data *spd, dimm_info * dimm, + ramctr_timing * ctrl) +{ + int i = 0; + int dimms = 0; + static const u8 ch[4] = { 0, 0, 1, 1 }; + static const u8 dm[4] = { 0, 1, 0, 1 }; + for (i = 0; i < 4; i++) { + ctrl->rankmap[ch[i]][dm[i]] = 0; + spd_decode_ddr3(&dimm->dimm[i], spd[i]); + if (dimm->dimm[i].dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3) { + // set dimm invalid + dimm->dimm[i].ranks = 0; + dimm->dimm[i].size_mb = 0; + continue; + } - /* Wait for ME to be ready */ - intel_early_me_init(); - intel_early_me_uma_size(); + dram_print_spd_ddr3(&dimm->dimm[i]); + dimms++; + ctrl->rank_mirror[ch[i]][dm[i] * 2] = 0; + ctrl->rank_mirror[ch[i]][dm[i] * 2 + 1] = spd[i][0x3f] & 1; - printk(BIOS_DEBUG, "Starting UEFI PEI System Agent\n"); + /* FIXME: should merge data from all dimms. */ + ctrl->thermalrefresh = spd[i][31]; + ctrl->rankmap[ch[i]][dm[i]] = (1 << dimm->dimm[i].ranks) - 1; + printk(BIOS_DEBUG, "i=%d rankmap[%d][%d] = %d\n", i, + ch[i], dm[i], + ctrl->rankmap[ch[i]][dm[i]]); + } + if (!dimms) + die("No DIMMs were found"); +} + +static void dram_find_common_params(const dimm_info * dimms, ramctr_timing * ctrl) +{ + size_t i, valid_dimms; + ctrl->cas_supported = 0xff; + valid_dimms = 0; + for (i = 0; i < 4; i++) { + const dimm_attr *dimm = &dimms->dimm[i]; + if (dimm->dram_type == SPD_MEMORY_TYPE_UNDEFINED) + continue; + valid_dimms++; + + if (valid_dimms == 1) { + /* First DIMM defines the type of DIMM */ + ctrl->dram_type = dimm->dram_type; + } else { + /* Check if we have mismatched DIMMs */ + if (ctrl->dram_type != dimm->dram_type) + die("Mismatched DIMM Types"); + } + /* Find all possible CAS combinations */ + ctrl->cas_supported &= dimm->cas_supported; + + /* Find the smallest common latencies supported by all DIMMs */ + ctrl->tCK = MAX(ctrl->tCK, dimm->tCK); + ctrl->tAA = MAX(ctrl->tAA, dimm->tAA); + ctrl->tWR = MAX(ctrl->tWR, dimm->tWR); + ctrl->tRCD = MAX(ctrl->tRCD, dimm->tRCD); + ctrl->tRRD = MAX(ctrl->tRRD, dimm->tRRD); + ctrl->tRP = MAX(ctrl->tRP, dimm->tRP); + ctrl->tRAS = MAX(ctrl->tRAS, dimm->tRAS); + ctrl->tRC = MAX(ctrl->tRC, dimm->tRC); + ctrl->tRFC = MAX(ctrl->tRFC, dimm->tRFC); + ctrl->tWTR = MAX(ctrl->tWTR, dimm->tWTR); + ctrl->tRTP = MAX(ctrl->tRTP, dimm->tRTP); + ctrl->tFAW = MAX(ctrl->tFAW, dimm->tFAW); + } - memset(&sysinfo, 0, sizeof(sysinfo)); + ctrl->n_dimms = valid_dimms; + if (!ctrl->cas_supported) + die("Unsupported DIMM combination. " + "DIMMS do not support common CAS latency"); + if (!valid_dimms) + die("No valid DIMMs found"); - sysinfo.boot_path = pei_data->boot_mode; + ctrl->dualchannel = + (pcie_read_config32(PCI_DEV(0, 0, 0), 0xE4) & 0x4000) >> 14; + if (ctrl->dualchannel) { + printk(BIOS_DEBUG, "Dual channel supported\n"); + } else { + printk(BIOS_DEBUG, "Dual channel not supported\n"); + } +} - /* - * Do not pass MRC data in for recovery mode boot, - * Always pass it in for S3 resume. +static u8 get_CWL(u8 CAS) +{ + /* Get CWL based on CAS using the following rule: + * _________________________________________ + * CAS: | 4T | 5T | 6T | 7T | 8T | 9T | 10T | 11T | + * CWL: | 5T | 5T | 5T | 6T | 6T | 7T | 7T | 8T | */ - if (!recovery_mode_enabled() || pei_data->boot_mode == 2) - prepare_mrc_cache(pei_data); - - /* If MRC data is not found we cannot continue S3 resume. */ - if (pei_data->boot_mode == 2 && !pei_data->mrc_input) { - printk(BIOS_DEBUG, "Giving up in sdram_initialize: No MRC data\n"); - outb(0x6, 0xcf9); - hlt(); - } - - /* Pass console handler in pei_data */ - pei_data->tx_byte = do_putchar; - - /* Locate and call UEFI System Agent binary. */ - /* TODO make MRC blob (0xab?) defined in cbfs_core.h. */ - entry = cbfs_get_file_content( - CBFS_DEFAULT_MEDIA, "mrc.bin", 0xab, NULL); - if (entry) { - int rv; - rv = entry (pei_data); - if (rv) { - switch (rv) { - case -1: - printk(BIOS_ERR, "PEI version mismatch.\n"); - break; - case -2: - printk(BIOS_ERR, "Invalid memory frequency.\n"); - break; - default: - printk(BIOS_ERR, "MRC returned %x.\n", rv); + static const u8 cas_cwl_map[] = { 5, 5, 5, 6, 6, 7, 7, 8 }; + if (CAS > 11) + return 8; + return cas_cwl_map[CAS - 4]; +} + +static u32 get_REFI(u32 tCK) +{ + /* Get REFI based on MCU frequency using the following rule: + * _________________________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * REFI: | 3120 | 4160 | 5200 | 6240 | 7280 | 8320 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u32 frq_refi_map[] = + { 3120, 4160, 5200, 6240, 7280, 8320 }; + if (FRQ > 8) + return 8320; + return frq_refi_map[FRQ - 3]; +} + +static u8 get_XSOffset(u32 tCK) +{ + /* Get XSOffset based on MCU frequency using the following rule: + * _________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * XSOffset : | 4 | 6 | 7 | 8 | 10 | 11 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u8 frq_xs_map[] = { 4, 6, 7, 8, 10, 11 }; + if (FRQ > 8) + return 11; + return frq_xs_map[FRQ - 3]; +} + +static u8 get_MOD(u32 tCK) +{ + /* Get MOD based on MCU frequency using the following rule: + * _____________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * MOD : | 12 | 12 | 12 | 12 | 15 | 16 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u8 frq_mod_map[] = { 12, 12, 12, 12, 15, 16 }; + if (FRQ > 8) + return 16; + return frq_mod_map[FRQ - 3]; +} + +static u8 get_WLO(u32 tCK) +{ + /* Get WLO based on MCU frequency using the following rule: + * _______________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * WLO : | 4 | 5 | 6 | 6 | 8 | 8 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u8 frq_wlo_map[] = { 4, 5, 6, 6, 8, 8 }; + if (FRQ > 8) + return 8; + return frq_wlo_map[FRQ - 3]; +} + +static u8 get_CKE(u32 tCK) +{ + /* Get CKE based on MCU frequency using the following rule: + * _______________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * CKE : | 3 | 3 | 4 | 4 | 5 | 6 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u8 frq_cke_map[] = { 3, 3, 4, 4, 5, 6 }; + if (FRQ > 8) + return 6; + return frq_cke_map[FRQ - 3]; +} + +static u8 get_XPDLL(u32 tCK) +{ + /* Get XPDLL based on MCU frequency using the following rule: + * _____________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * XPDLL : | 10 | 13 | 16 | 20 | 23 | 26 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u8 frq_xpdll_map[] = { 10, 13, 16, 20, 23, 26 }; + if (FRQ > 8) + return 26; + return frq_xpdll_map[FRQ - 3]; +} + +static u8 get_XP(u32 tCK) +{ + /* Get XP based on MCU frequency using the following rule: + * _______________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * XP : | 3 | 4 | 4 | 5 | 6 | 7 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u8 frq_xp_map[] = { 3, 4, 4, 5, 6, 7 }; + if (FRQ > 8) + return 7; + return frq_xp_map[FRQ - 3]; +} + +static u8 get_AONPD(u32 tCK) +{ + /* Get AONPD based on MCU frequency using the following rule: + * ________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * AONPD : | 4 | 5 | 6 | 8 | 8 | 10 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u8 frq_aonpd_map[] = { 4, 5, 6, 8, 8, 10 }; + if (FRQ > 8) + return 10; + return frq_aonpd_map[FRQ - 3]; +} + +static u32 get_COMP2(u32 tCK) +{ + /* Get COMP2 based on MCU frequency using the following rule: + * ___________________________________________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * COMP : | D6BEDCC | CE7C34C | CA57A4C | C6369CC | C42514C | C21410C | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u32 frq_comp2_map[] = { 0xD6BEDCC, 0xCE7C34C, 0xCA57A4C, + 0xC6369CC, 0xC42514C, 0xC21410C + }; + if (FRQ > 8) + return 0xD6BEDCC; + return frq_comp2_map[FRQ - 3]; +} + +static void dram_timing(ramctr_timing * ctrl) +{ + u8 val; + u32 val32; + + /* Maximum supported DDR3 frequency is 1066MHz (DDR3 2133) so make sure + * we cap it if we have faster DIMMs. + * Then, align it to the closest JEDEC standard frequency */ + if (ctrl->tCK <= TCK_1066MHZ) { + ctrl->tCK = TCK_1066MHZ; + ctrl->delay1 = 16; + ctrl->delay2 = 8; + ctrl->edge_offset[0] = 16; + ctrl->edge_offset[1] = 7; + ctrl->edge_offset[2] = 7; + ctrl->timC_offset[0] = 18; + ctrl->timC_offset[1] = 7; + ctrl->timC_offset[2] = 7; + ctrl->reg_c14_offset = 16; + } else if (ctrl->tCK <= TCK_933MHZ) { + ctrl->tCK = TCK_933MHZ; + ctrl->delay1 = 15; + ctrl->delay2 = 8; + ctrl->edge_offset[0] = 14; + ctrl->edge_offset[1] = 6; + ctrl->edge_offset[2] = 6; + ctrl->timC_offset[0] = 15; + ctrl->timC_offset[1] = 6; + ctrl->timC_offset[2] = 6; + ctrl->reg_c14_offset = 14; + } else if (ctrl->tCK <= TCK_800MHZ) { + ctrl->tCK = TCK_800MHZ; + ctrl->delay1 = 12; + ctrl->delay2 = 6; + ctrl->edge_offset[0] = 13; + ctrl->edge_offset[1] = 5; + ctrl->edge_offset[2] = 5; + ctrl->timC_offset[0] = 14; + ctrl->timC_offset[1] = 5; + ctrl->timC_offset[2] = 5; + ctrl->reg_c14_offset = 12; + } else if (ctrl->tCK <= TCK_666MHZ) { + ctrl->tCK = TCK_666MHZ; + ctrl->delay1 = 12; + ctrl->delay2 = 6; + ctrl->edge_offset[0] = 10; + ctrl->edge_offset[1] = 4; + ctrl->edge_offset[2] = 4; + ctrl->timC_offset[0] = 11; + ctrl->timC_offset[1] = 4; + ctrl->timC_offset[2] = 4; + ctrl->reg_c14_offset = 10; + } else { + ctrl->tCK = TCK_533MHZ; + ctrl->delay1 = 12; + ctrl->delay2 = 5; + ctrl->edge_offset[0] = 8; + ctrl->edge_offset[1] = 3; + ctrl->edge_offset[2] = 3; + ctrl->timC_offset[0] = 9; + ctrl->timC_offset[1] = 3; + ctrl->timC_offset[2] = 3; + ctrl->reg_c14_offset = 8; + } + + val32 = (1000 << 8) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected DRAM frequency: %u MHz\n", val32); + + /* Find CAS and CWL latencies */ + val = (ctrl->tAA + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Minimum CAS latency : %uT\n", val); + /* Find lowest supported CAS latency that satisfies the minimum value */ + while (!((ctrl->cas_supported >> (val - 4)) & 1) + && (ctrl->cas_supported >> (val - 4))) { + val++; + } + /* Is CAS supported */ + if (!(ctrl->cas_supported & (1 << (val - 4)))) + printk(BIOS_DEBUG, "CAS not supported\n"); + printk(BIOS_DEBUG, "Selected CAS latency : %uT\n", val); + ctrl->CAS = val; + ctrl->CWL = get_CWL(ctrl->CAS); + printk(BIOS_DEBUG, "Selected CWL latency : %uT\n", ctrl->CWL); + + /* Find tRCD */ + ctrl->tRCD = (ctrl->tRCD + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRCD : %uT\n", ctrl->tRCD); + + ctrl->tRP = (ctrl->tRP + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRP : %uT\n", ctrl->tRP); + + /* Find tRAS */ + ctrl->tRAS = (ctrl->tRAS + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRAS : %uT\n", ctrl->tRAS); + + /* Find tWR */ + ctrl->tWR = (ctrl->tWR + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tWR : %uT\n", ctrl->tWR); + + /* Find tFAW */ + ctrl->tFAW = (ctrl->tFAW + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tFAW : %uT\n", ctrl->tFAW); + + /* Find tRRD */ + ctrl->tRRD = (ctrl->tRRD + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRRD : %uT\n", ctrl->tRRD); + + /* Find tRTP */ + ctrl->tRTP = (ctrl->tRTP + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRTP : %uT\n", ctrl->tRTP); + + /* Find tWTR */ + ctrl->tWTR = (ctrl->tWTR + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tWTR : %uT\n", ctrl->tWTR); + + /* Refresh-to-Active or Refresh-to-Refresh (tRFC) */ + ctrl->tRFC = (ctrl->tRFC + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRFC : %uT\n", ctrl->tRFC); + + ctrl->tRC = (ctrl->tRC + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Required tRC : %uT\n", ctrl->tRC); + + ctrl->tREFI = get_REFI(ctrl->tCK); + ctrl->tMOD = get_MOD(ctrl->tCK); + ctrl->tXSOffset = get_XSOffset(ctrl->tCK); + ctrl->tWLO = get_WLO(ctrl->tCK); + ctrl->tCKE = get_CKE(ctrl->tCK); + ctrl->tXPDLL = get_XPDLL(ctrl->tCK); + ctrl->tXP = get_XP(ctrl->tCK); + ctrl->tAONPD = get_AONPD(ctrl->tCK); +} + +static void dram_freq(ramctr_timing * ctrl) +{ + u8 val1, val2; + u32 reg1 = 0; + + /* Step 1 - Set target PCU frequency */ + + if (ctrl->tCK <= TCK_1066MHZ) { + val1 = 0x08; + ctrl->tCK = TCK_1066MHZ; + } else if (ctrl->tCK <= TCK_933MHZ) { + val1 = 0x07; + ctrl->tCK = TCK_933MHZ; + } else if (ctrl->tCK <= TCK_800MHZ) { + val1 = 0x06; + ctrl->tCK = TCK_800MHZ; + } else if (ctrl->tCK <= TCK_666MHZ) { + val1 = 0x05; + ctrl->tCK = TCK_666MHZ; + } else { + val1 = 0x04; + ctrl->tCK = TCK_533MHZ; + } + + /* Step 2 - Select frequency in the MCU */ + reg1 = val1; + reg1 |= 0x80000000; // set running bit + MCHBAR32(0x5e00) = reg1; + while (reg1 >> 0x1f) { + printk(BIOS_DEBUG, " PLL busy..."); + reg1 = MCHBAR32(0x5e00); + } + printk(BIOS_DEBUG, "done\n"); + + /* Step 3 - Verify lock frequency */ + reg1 = MCHBAR32(0x5e04); + val2 = (u8) reg1; + if (val2 > val1) { + printk(BIOS_DEBUG, "Lock frequency is lower, recalculating\n"); + switch (val2) { + case 8: + ctrl->tCK = TCK_1066MHZ; + break; + case 7: + ctrl->tCK = TCK_933MHZ; + break; + case 6: + ctrl->tCK = TCK_800MHZ; + break; + case 5: + ctrl->tCK = TCK_666MHZ; + break; + case 4: + ctrl->tCK = TCK_533MHZ; + break; + default: + printk(BIOS_DEBUG, "ERROR: PLL is off or unknown\n"); + break; + } + dram_timing(ctrl); // recalculate timings + } + printk(BIOS_DEBUG, "MCU frequency is set at : %d MHz\n", (1000 << 8) / ctrl->tCK); +} + +static void dram_xover(ramctr_timing * ctrl) +{ + size_t ch; + u32 reg, addr; + u8 rmap; + for (ch = 0; ch < 2; ch++) { + // enable xover clk + reg = 0; + rmap = (ctrl->rankmap[ch][0] | (ctrl->rankmap[ch][1] << 2)); + reg = (reg & ~0xf000000) | (rmap << 24); + addr = (ch == 0) ? 0xc14 : 0xd14; + printk (BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + + // enable xover ctl + reg = 0; + if ((ctrl->rankmap[ch][0] & 0x1) || (ctrl->rankmap[ch][1] & 0x1)) { + reg = (reg & ~0x20000) | (1 << 0x11); + } + if ((ctrl->rankmap[ch][0] & 0x2) || (ctrl->rankmap[ch][1] & 0x2)) { + reg = (reg & ~0x4000000) | (1 << 0x1a); + } + // enable xover cmd + reg = (reg & ~0x4000) | (1 << 14); + addr = (ch == 0) ? 0x320c : 0x330c; + printk (BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + } +} + +static void dram_timing_regs(ramctr_timing * ctrl) +{ + size_t ch; + u32 reg, addr, val32, cpu, stretch; + u8 val; + struct cpuid_result cpures; + + for (ch = 0; ch < 2; ch++) { + // DBP + reg = 0; + val = ctrl->tRCD; + reg = (reg & ~0xf) | val; + val = ctrl->tRP; + reg = (reg & ~0xf0) | (val << 0x4); + val = ctrl->CAS; + reg = (reg & ~0xf00) | (val << 0x8); + val = ctrl->CWL; + reg = (reg & ~0xf000) | (val << 0xc); + val = ctrl->tRAS; + reg = (reg & ~0xff0000) | (val << 0x10); + addr = (ch == 0 ? 0x4000 : 0x4400); + printk (BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + + // RAP + reg = 0; + val = ctrl->tRRD; + reg = (reg & ~0xf) | val; + val = ctrl->tRTP; + reg = (reg & ~0xf0) | (val << 0x4); + val = ctrl->tCKE; + reg = (reg & ~0xf00) | (val << 0x8); + val = ctrl->tWTR; + reg = (reg & ~0xf000) | (val << 0xc); + val = ctrl->tFAW; + reg = (reg & ~0xff0000) | (val << 0x10); + val = ctrl->tWR; + reg = (reg & ~0x1f000000) | (val << 0x18); + reg = (reg & ~0xc0000000) | (3 << 30); + addr = (ch == 0 ? 0x4004 : 0x4404); + printk (BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + + // OTHP + addr = (ch == 0 ? 0x400c : 0x440c); + reg = MCHBAR32(addr); + val = ctrl->tXPDLL; + reg = (reg & ~0x1f) | val; + val = ctrl->tXP; + reg = (reg & ~0xe0) | (val << 0x5); + val = ctrl->tAONPD; + reg = (reg & ~0xf00) | (val << 0x8); + printk (BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + + MCHBAR32(ch == 0 ? 0x4014 : 0x4414) = 0; + + MCHBAR32(addr) |= 0x00020000; + + + // ODT stretch + reg = 0; + + cpures = cpuid(0); + cpu = cpures.eax; + if (IS_IVY_CPU(cpu) + || (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_D2(cpu))) { + stretch = 2; + addr = (ch == 0 ? 0x400c : 0x440c); + printk (BIOS_DEBUG, "[%x] = %x\n", addr, reg); + reg = MCHBAR32(addr); + + if ((ctrl->rankmap[ch][0] == 0) || + ctrl->rankmap[ch][1] == 0) { + + // Rank 0 - operate on rank 2 + reg = (reg & ~0xc0000) | (stretch << 0x12); + + // Rank 2 - operate on rank 0 + reg = (reg & ~0x30000) | (stretch << 0x10); + + addr = (ch == 0 ? 0x400c : 0x440c); + printk (BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + } + + } else if (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_C(cpu)) { + stretch = 3; + addr = (ch == 0 ? 0x401c : 0x441c); + reg = MCHBAR32(addr); + + if ((ctrl->rankmap[ch][0] == 0) || + ctrl->rankmap[ch][1] == 0) { + + // Rank 0 - operate on rank 2 + reg = (reg & ~0x3000) | (stretch << 0xc); + + // Rank 2 - operate on rank 0 + reg = (reg & ~0xc00) | (stretch << 0xa); + + addr = (ch == 0 ? 0x401c : 0x441c); + printk (BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; } - die("Nonzero MRC return value.\n"); + } else { + stretch = 0; + } + + // REFI + reg = 0; + val32 = ctrl->tREFI; + reg = (reg & ~0xffff) | val32; + val32 = ctrl->tRFC; + reg = (reg & ~0x1ff0000) | (val32 << 0x10); + val32 = (u32) (ctrl->tREFI * 9) / 1024; + reg = (reg & ~0xfe000000) | (val32 << 0x19); + addr = (ch == 0 ? 0x4298 : 0x4698); + printk (BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + + addr = (ch == 0 ? 0x4294 : 0x4694); + MCHBAR32(addr) |= 0xff; + + // SRFTP + reg = 0; + val32 = tDLLK; + reg = (reg & ~0xfff) | val32; + val32 = ctrl->tXSOffset; + reg = (reg & ~0xf000) | (val32 << 0xc); + val32 = tDLLK - ctrl->tXSOffset; + reg = (reg & ~0x3ff0000) | (val32 << 0x10); + val32 = ctrl->tMOD - 8; + reg = (reg & ~0xf0000000) | (val32 << 0x1c); + addr = (ch == 0 ? 0x42a4 : 0x46a4); + printk (BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + } +} + +static void dram_dimm_mapping(dimm_info * info, ramctr_timing * ctrl) +{ + size_t ch; + int t; + u32 reg, addr, val32; + for (ch = 0; ch < 2; ch++) { + dimm_attr *dimmA = 0; + dimm_attr *dimmB = 0; + reg = 0; + val32 = 0; + addr = 0; + if (info->dimm[2 * ch].size_mb >= + info->dimm[2 * ch + 1].size_mb) { + // dimm 0 is bigger, set it to dimmA + dimmA = &info->dimm[2 * ch]; + dimmB = &info->dimm[2 * ch + 1]; + reg = (reg & ~0x10000) | (0 << 0x10); + } else { + // dimm 1 is bigger, set it to dimmA + dimmA = &info->dimm[2 * ch + 1]; + dimmB = &info->dimm[2 * ch]; + reg = (reg & ~0x10000) | (1 << 0x10); + // swap dimm info + t = ctrl->rank_mirror[ch][1]; + ctrl->rank_mirror[ch][1] = ctrl->rank_mirror[ch][3]; + ctrl->rank_mirror[ch][3] = t; + } + // dimmA + if (dimmA && (dimmA->ranks > 0)) { + val32 = dimmA->size_mb / 256; + reg = (reg & ~0xff) | val32; + val32 = dimmA->ranks - 1; + reg = (reg & ~0x20000) | (val32 << 0x11); + val32 = (dimmA->width / 8) - 1; + reg = (reg & ~0x80000) | (val32 << 0x13); + } + // dimmB + if (dimmB && (dimmB->ranks > 0)) { + val32 = dimmB->size_mb / 256; + reg = (reg & ~0xff00) | (val32 << 0x8); + val32 = dimmB->ranks - 1; + reg = (reg & ~0x40000) | (val32 << 0x12); + val32 = (dimmB->width / 8) - 1; + reg = (reg & ~0x100000) | (val32 << 0x14); } + reg = (reg & ~0x200000) | (1 << 21); // rank interleave + reg = (reg & ~0x400000) | (1 << 22); // enhanced interleave + + // Set MAD-DIMM register + addr = 0x5004 + ch * 4; + if ((dimmA && (dimmA->ranks > 0)) || + (dimmB && (dimmB->ranks > 0))) { + MCHBAR32(addr) = reg; + } + } +} + +static void dram_zones(dimm_info * info, ramctr_timing * ctrl, int training) +{ + u32 reg, ch0size, ch1size; + u8 val; + reg = 0; + val = 0; + if (training) { + ch0size = info->dimm[0].size_mb + info->dimm[1].size_mb ? 256 : 0; + ch1size = info->dimm[2].size_mb + info->dimm[3].size_mb ? 256 : 0; } else { - die("UEFI PEI System Agent not found.\n"); + ch0size = info->dimm[0].size_mb + info->dimm[1].size_mb; + ch1size = info->dimm[2].size_mb + info->dimm[3].size_mb; } -#if CONFIG_USBDEBUG_IN_ROMSTAGE - /* mrc.bin reconfigures USB, so reinit it to have debug */ - usbdebug_init(); -#endif + if (ch0size >= ch1size) { + reg = MCHBAR32(0x5000); + reg = (reg & ~0xf) | 4; + MCHBAR32(0x5000) = reg; - /* For reference print the System Agent version - * after executing the UEFI PEI stage. - */ - u32 version = MCHBAR32(0x5034); - printk(BIOS_DEBUG, "System Agent Version %d.%d.%d Build %d\n", - version >> 24 , (version >> 16) & 0xff, - (version >> 8) & 0xff, version & 0xff); - - /* Send ME init done for SandyBridge here. This is done - * inside the SystemAgent binary on IvyBridge. */ - if (BASE_REV_SNB == - (pci_read_config16(PCI_CPU_DEVICE, PCI_DEVICE_ID) & BASE_REV_MASK)) - intel_early_me_init_done(ME_INIT_STATUS_SUCCESS); - else - intel_early_me_status(); + reg = MCHBAR32(0x5014); + val = ch1size / 256; + reg = (reg & ~0xff000000) | val << 24; + reg = (reg & ~0xff0000) | (2 * val) << 16; + MCHBAR32(0x5014) = reg; + } else { + reg = MCHBAR32(0x5000); + reg = (reg & ~0xf) | 1; + MCHBAR32(0x5000) = reg; + + reg = MCHBAR32(0x5014); + val = ch0size / 256; + reg = (reg & ~0xff000000) | val << 24; + reg = (reg & ~0xff0000) | (2 * val) << 16; + MCHBAR32(0x5014) = reg; + } + + reg = MCHBAR32(0x5000); + reg = (reg & ~0x18) | (1 << 4); + MCHBAR32(0x5000) = reg; +} + +/* FIXME: this function bugs. */ +static void dram_memorymap(dimm_info * info, int me_uma_size) +{ + u32 reg, val, reclaim; + u32 tom, gfxstolen, gttsize; + size_t tsegsize, mmiosize, toludbase, touudbase, gfxstolenbase, gttbase, + tsegbase, mestolenbase; + size_t tsegbasedelta, remapbase, remaplimit; + uint16_t ggc; + + mmiosize = 0x400; + + ggc = pci_read_config16(NORTHBRIDGE, GGC); + if (!(ggc & 2)) { + gfxstolen = ((ggc >> 3) & 0x1f) * 32; + gttsize = ((ggc >> 8) & 0x3); + } else { + gfxstolen = 0; + gttsize = 0; + } + + tsegsize = CONFIG_SMM_TSEG_SIZE >> 20; + + tom = info->dimm[0].size_mb + info->dimm[1].size_mb + + info->dimm[2].size_mb + info->dimm[3].size_mb; + + mestolenbase = tom - me_uma_size; + + toludbase = MIN(4096 - mmiosize, tom - me_uma_size); + gfxstolenbase = toludbase - gfxstolen; + gttbase = gfxstolenbase - gttsize; + + tsegbase = gttbase - tsegsize; + + // Round tsegbase down to nearest address aligned to tsegsize + tsegbasedelta = tsegbase & (tsegsize - 1); + tsegbase &= ~(tsegsize - 1); + + gttbase -= tsegbasedelta; + gfxstolenbase -= tsegbasedelta; + toludbase -= tsegbasedelta; + + // Test if it is possible to reclaim a hole in the ram addressing + if (tom - me_uma_size > toludbase) { + // Reclaim is possible + reclaim = 1; + remapbase = MAX(4096, tom - me_uma_size); + remaplimit = remapbase + + MIN(4096, tom - me_uma_size) - toludbase - 1; + touudbase = remaplimit + 1; + } else { + // Reclaim not possible + reclaim = 0; + touudbase = tom - me_uma_size; + } + + // Update memory map in pci-e configuration space + + // TOM (top of memory) + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xa0); + val = tom & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk (BIOS_DEBUG, "PCI:[%x] = %x\n", 0xa0, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xa0, reg); + + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xa4); + val = tom & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk (BIOS_DEBUG, "PCI:[%x] = %x\n", 0xa4, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xa4, reg); + + // TOLUD (top of low used dram) + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xbc); + val = toludbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk (BIOS_DEBUG, "PCI:[%x] = %x\n", 0xbc, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xbc, reg); + + // TOUUD LSB (top of upper usable dram) + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xa8); + val = touudbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk (BIOS_DEBUG, "PCI:[%x] = %x\n", 0xa8, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xa8, reg); + + // TOUUD MSB + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xac); + val = touudbase & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk (BIOS_DEBUG, "PCI:[%x] = %x\n", 0xac, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xac, reg); + + if (reclaim) { + // REMAP BASE + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x94); + val = remapbase & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk (BIOS_DEBUG, "PCI:[%x] = %x\n", 0x94, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x94, reg); + + // REMAP LIMIT + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x98); + val = remaplimit & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk (BIOS_DEBUG, "PCI:[%x] = %x\n", 0x98, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x98, reg); + + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x9c); + val = remaplimit & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk (BIOS_DEBUG, "PCI:[%x] = %x\n", 0x9c, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x9c, reg); + } + // TSEG + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xb8); + val = tsegbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk (BIOS_DEBUG, "PCI:[%x] = %x\n", 0xb8, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xb8, reg); + + // GFX stolen memory + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xb0); + val = gfxstolenbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk (BIOS_DEBUG, "PCI:[%x] = %x\n", 0xb0, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xb0, reg); + + // GTT stolen memory + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xb4); + val = gttbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk (BIOS_DEBUG, "PCI:[%x] = %x\n", 0xb4, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xb4, reg); + + if (me_uma_size) { + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x7c); + val = (0x80000 - me_uma_size) & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk (BIOS_DEBUG, "PCI:[%x] = %x\n", 0x7c, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x7c, reg); + + // ME base + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x70); + val = mestolenbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk (BIOS_DEBUG, "PCI:[%x] = %x\n", 0x70, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x70, reg); + + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x74); + val = mestolenbase & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk (BIOS_DEBUG, "PCI:[%x] = %x\n", 0x74, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x74, reg); + + // ME mask + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x78); + val = (0x80000 - me_uma_size) & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + reg = (reg & ~0x400) | (1 << 10); // set lockbit on ME mem + + reg = (reg & ~0x800) | (1 << 11); // set ME memory enable + printk (BIOS_DEBUG, "PCI:[%x] = %x\n", 0x78, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x78, reg); + } +} + +static void dram_ioregs(ramctr_timing * ctrl) +{ + u32 reg, ch0rank, ch1rank, comp2; + + int channel; + + ch0rank = ctrl->rankmap[0][0] | (ctrl->rankmap[0][1] << 2); + ch1rank = ctrl->rankmap[1][0] | (ctrl->rankmap[1][1] << 2); + + // IO clock + MCHBAR32(0xc00) = ch0rank; + MCHBAR32(0xd00) = ch1rank; + + // IO command + MCHBAR32(0x3200) = ch0rank; + MCHBAR32(0x3300) = ch1rank; + + // IO control + FOR_ALL_POPULATED_CHANNELS { + program_timings (ctrl, channel); + } + + // Rcomp + printk(BIOS_DEBUG, "RCOMP..."); + reg = 0; + while (reg == 0) { + reg = MCHBAR32(0x5084) & 0x10000; + } + printk(BIOS_DEBUG, "done\n"); + + // Set comp2 + comp2 = get_COMP2(ctrl->tCK); + MCHBAR32(0x3714) = comp2; + printk(BIOS_DEBUG, "COMP2 done\n"); + + // Set comp1 + FOR_ALL_POPULATED_CHANNELS { + reg = MCHBAR32(0x1810 + channel * 0x100); //ch0 + reg = (reg & ~0xe00) | (1 << 0x9); //odt + reg = (reg & ~0xe00000) | (1 << 0x15); //clk drive up + reg = (reg & ~0x38000000) | (1 << 0x1b); //ctl drive up + MCHBAR32(0x1810 + channel * 0x100) = reg; + } + printk(BIOS_DEBUG, "COMP1 done\n"); + + printk(BIOS_DEBUG, "FORCE RCOMP and wait 20us..."); + reg = MCHBAR32(0x5f08); + reg = (reg & ~0x100) | (1 << 0x8); + MCHBAR32(0x5f08) = reg; + udelay(20); + printk(BIOS_DEBUG, "done\n"); +} + +static void dram_jedecreset(ramctr_timing * ctrl) +{ + u32 reg, addr, rmap, rank; + u8 ch, chw; + + while ( !(MCHBAR32(0x5084) & 0x10000) ); + do { + reg = MCHBAR32(0x428c); + } while ((reg & 0x14) == 0); + + // Set state of memory controller + reg = 0x112; + addr = 0x5030; + MCHBAR32(addr) = reg; + MCHBAR32(0x4ea0) = 0; + reg = (reg & ~0x2) | (1 << 0x1); //ddr reset + MCHBAR32(addr) = reg; + + // Assert dimm reset signal + reg = MCHBAR32(addr); + reg &= ~0x2; + MCHBAR32(addr) = reg; + + // Wait 200us + udelay(200); + + // Deassert dimm reset signal + reg = MCHBAR32(addr); + reg = (reg & ~0x2) | (1 << 0x1); + MCHBAR32(addr) = reg; + + // Wait 500us + udelay(500); + + // Enable DCLK + reg = MCHBAR32(addr); + reg = (reg & ~0x4) | (1 << 0x2); + MCHBAR32(addr) = reg; + + // XXX Wait 20ns + udelay(1); + + for (ch = 0; ch < 2; ch++) { + // Set valid rank CKE + reg = 0; + rmap = ctrl->rankmap[ch][0] | (ctrl->rankmap[ch][1] << 2); + reg = (reg & ~0xf) | rmap; + addr = (ch == 0) ? 0x42a0 : 0x46a0; + MCHBAR32(addr) = reg; + + // Wait 10ns for ranks to settle + //udelay(0.01); + + reg = (reg & ~0xf0) | (rmap << 0x4); + MCHBAR32(addr) = reg; + + // Write reset using a NOP + reg = 0; + chw = (ctrl->rankmap[0][0] | ctrl->rankmap[0][1]) ? 0 : 1; + rank = (ctrl->rankmap[chw][0]) ? 0 : 2; + addr = (chw == 0) ? 0x428c : 0x468c; + do { + reg = MCHBAR32(addr); + } while ((reg & 0x14) == 0); + + reg = 0; + reg = (reg & ~0xff) | 1; + reg = (reg & ~0x400000) | (1 << 0x16); + addr = (chw == 0) ? 0x4284 : 0x4684; + MCHBAR32(addr) = reg; + } +} + +static odtmap get_ODT(ramctr_timing * ctrl, u8 rank) +{ + /* Get ODT based on rankmap: */ + u8 dimms_per_ch, table; + u8 ch0dimmA, ch0dimmB, ch1dimmA, ch1dimmB; + static const odtmap odt_map[4][6] = { + {{60, 60}, {60, 60}, {120, 30}, {120, 30}, {120, 30}, + {120, 30}}, + {{0, 0}, {60, 60}, {0, 0}, {0, 0}, {120, 30}, {120, 30}}, + {{60, 60}, {60, 60}, {120, 30}, {120, 30}, {120, 30}, + {120, 30}}, + {{0, 0}, {60, 60}, {0, 0}, {120, 30}, {0, 0}, {120, 30}} + }; + ch0dimmA = (ctrl->rankmap[0][0] != 0) ? 1 : 0; + ch0dimmB = (ctrl->rankmap[0][1] != 0) ? 1 : 0; + ch1dimmA = (ctrl->rankmap[1][0] != 0) ? 1 : 0; + ch1dimmB = (ctrl->rankmap[1][1] != 0) ? 1 : 0; + + dimms_per_ch = (ch0dimmA + ch0dimmB > ch1dimmA + ch1dimmB) ? + ch0dimmA + ch0dimmB : ch1dimmA + ch1dimmB; + table = 0; + + if (dimms_per_ch == 1) { + if ((ctrl->rankmap[0][0] + | ctrl->rankmap[0][1] + | ctrl->rankmap[1][0] + | ctrl->rankmap[1][1]) != 3) { + table = 0; + } else { + table = 1; + } + } else if (dimms_per_ch == 2) { + if ((ctrl->rankmap[0][0] | ctrl->rankmap[0][1]) != 3) { + if ((ctrl->rankmap[1][0] | ctrl->rankmap[1][1]) != 3) { + table = 2; + } else { + table = 3; + } + } else { + if ((ctrl->rankmap[1][0] | ctrl->rankmap[1][1]) != 3) { + table = 4; + } else { + table = 5; + } + } + } else { + printk(BIOS_DEBUG, + "Huh, no dimms? m00 = %d m01 = %d m10 = %d m11 = %d dpc = %d\n", + ctrl->rankmap[0][0], ctrl->rankmap[0][1], + ctrl->rankmap[1][0], ctrl->rankmap[1][1], dimms_per_ch); + die(""); + } + + return odt_map[rank][table]; +} + +static void +write_mrreg (ramctr_timing * ctrl, int channel, int slotrank, int reg, u32 val) +{ + u32 r32; + do { + r32 = MCHBAR32(0x428c + 0x400 * channel); + } while ((r32 & 0x50) == 0); + + printk (BIOS_SPEW, "MRd: %x <= %x\n", reg, val); + + if (ctrl->rank_mirror[channel][slotrank]) { + reg = ((reg >> 1) & 1) | ((reg << 1) & 2); + val = (val & ~0x1f8) | ((val >> 1) & 0xa8) | ((val & 0xa8) << 1); + } + + printk (BIOS_SPEW, "MRd: %x <= %x\n", reg, val); + + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f000); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | (reg << 20) | val | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f000); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x41001); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24) | (reg << 20) | val | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x0f000); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x1001 | (ctrl->delay1 << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24) | (reg << 20) | val | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x80001); +} + +static u32 make_mr0(ramctr_timing *ctrl, u8 rank) +{ + u16 mr0reg, mch_cas, mch_wr; + static const u8 mch_wr_t[12] = { 1, 2, 3, 4, 0, 5, 0, 6, 0, 7, 0, 0 }; + mr0reg = 0x100; + + // Convert CAS to MCH register friendly + if (ctrl->CAS < 12) { + mch_cas = (u16) ((ctrl->CAS - 4) << 1); + } else { + mch_cas = (u16) (ctrl->CAS - 12); + mch_cas = ((mch_cas << 1) | 0x1); + } + + // Convert tWR to MCH register friendly + mch_wr = mch_wr_t[ctrl->tWR - 5]; + + mr0reg = (mr0reg & ~0x4) | (mch_cas & 0x1); + mr0reg = (mr0reg & ~0x70) | ((mch_cas & 0xe) << 3); + mr0reg = (mr0reg & ~0xe00) | (mch_wr << 9); + // Fast (desktop) 0x1 or slow (mobile) 0x0 + mr0reg = (mr0reg & ~0x1000) | (!ctrl->mobile << 12); + return mr0reg; +} + +static void dram_mr0(ramctr_timing * ctrl, u8 rank) +{ + int channel; + + FOR_ALL_POPULATED_CHANNELS + write_mrreg (ctrl, channel, rank, 0, make_mr0 (ctrl, rank)); +} + +static u32 encode_odt(u32 odt) +{ + switch (odt) { + case 30: + return (1 << 9) | (1 << 2); // RZQ/8, RZQ/4 + case 60: + return (1 << 2); // RZQ/4 + case 120: + return (1 << 6); // RZQ/2 + default: + case 0: + return 0; + } +} + +static u32 make_mr1(ramctr_timing * ctrl, u8 rank) +{ + odtmap odt; + u32 mr1reg; + + odt = get_ODT(ctrl, rank); + mr1reg = 0x2; + + mr1reg |= encode_odt (odt.rttnom); + + return mr1reg; +} + +static void dram_mr1(ramctr_timing * ctrl, u8 rank) +{ + u16 mr1reg; + u8 ch; + + mr1reg = make_mr1(ctrl, rank); + + for (ch = 0; ch < 2; ch++) { + write_mrreg (ctrl, ch, rank, 1, mr1reg); + } +} + +static void dram_mr2(ramctr_timing * ctrl, u8 rank) +{ + u16 pasr, cwl, asr, str, mr2reg; + u8 ch; + odtmap odt; + + pasr = 0; + cwl = ctrl->CWL - 5; + asr = + (ctrl->thermalrefresh & 0x1) & ((ctrl->thermalrefresh & 0x4) >> 2); + /* FIXME: compute STR. */ + str = 1; + odt = get_ODT(ctrl, rank); + + mr2reg = 0; + mr2reg = (mr2reg & ~0x7) | pasr; + mr2reg = (mr2reg & ~0x38) | (cwl << 0x3); + mr2reg = (mr2reg & ~0x40) | (asr << 0x6); + mr2reg = (mr2reg & ~0x80) | (str << 0x7); + mr2reg |= (odt.rttwr / 60) << 9; + + for (ch = 0; ch < 2; ch++) { + write_mrreg (ctrl, ch, rank, 2, mr2reg); + } +} + +static void dram_mr3(ramctr_timing * ctrl, u8 rank) +{ + u16 mr3reg; + u8 ch; + + mr3reg = 0; + + for (ch = 0; ch < 2; ch++) { + write_mrreg (ctrl, ch, rank, 3, mr3reg); + } +} + +static void +wait_428c (int channel) +{ + while (1) + { + if (read32 (DEFAULT_MCHBAR | 0x428c | (channel << 10)) & 0x50) + return; + } +} + +static void dram_mrscommands(ramctr_timing * ctrl) +{ + u8 rank, ch; + u32 reg, addr; + + for (rank = 0; rank < 4; rank++) { + // MR2 + printk(BIOS_SPEW, "MR2 rank %d...", rank); + dram_mr2(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + + // MR3 + printk(BIOS_SPEW, "MR3 rank %d...", rank); + dram_mr3(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + + // MR1 + printk(BIOS_SPEW, "MR1 rank %d...", rank); + dram_mr1(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + + // MR0 + printk(BIOS_SPEW, "MR0 rank %d...", rank); + dram_mr0(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + } + + write32 (DEFAULT_MCHBAR + 0x4e20, 0x7); + write32 (DEFAULT_MCHBAR + 0x4e30, 0xf1001); + write32 (DEFAULT_MCHBAR + 0x4e00, 0x60002); + write32 (DEFAULT_MCHBAR + 0x4e10, 0); + write32 (DEFAULT_MCHBAR + 0x4e24, 0x1f003); + write32 (DEFAULT_MCHBAR + 0x4e34, 0x1901001); + write32 (DEFAULT_MCHBAR + 0x4e04, 0x60400); + write32 (DEFAULT_MCHBAR + 0x4e14, 0x288); + write32 (DEFAULT_MCHBAR + 0x4e84, 0x40004); + + // Drain + for (ch = 0; ch < 2; ch++) { + // Wait for ref drained + addr = (ch == 0) ? 0x428c : 0x468c; + do { + reg = MCHBAR32(addr); + } while ((reg & 0x50) == 0); + } + + // Refresh enable + reg = MCHBAR32(0x5030); + reg = (reg & ~0x8) | (1 << 0x3); + MCHBAR32(0x5030) = reg; + + for (ch = 0; ch < 2; ch++) { + if ((ctrl->rankmap[ch][0] | ctrl->rankmap[ch][1]) != 0) { + addr = (ch == 0) ? 0x4020 : 0x4420; + reg = MCHBAR32(addr); + reg &= ~0x200000; + MCHBAR32(addr) = reg; + + wait_428c (ch); + + rank = (ctrl->rankmap[ch][0] != 0) ? 0 : 2; + + // Drain + addr = (ch == 0) ? 0x428c : 0x468c; + do { + reg = MCHBAR32(addr); + } while ((reg & 0x50) == 0); + + write32 (DEFAULT_MCHBAR + 0x4220 + ch * 0x400, 0x0f003); + write32 (0x4230 + 0x400 * ch + DEFAULT_MCHBAR, 0x659001); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * ch, + (rank << 24) | (6 << 16)); + write32 (DEFAULT_MCHBAR + 0x4210 + ch * 0x400, 0x3e0); + + // Drain + addr = (ch == 0) ? 0x428c : 0x468c; + do { + reg = MCHBAR32(addr); + } while ((reg & 0x50) == 0); + } + } +} + +const u32 lane_registers[] = {0x0000, 0x0200, 0x0400, 0x0600, + 0x1000, 0x1200, 0x1400, 0x1600, + 0x0800 }; + +static int +clamp (int val, int low, int up) +{ + if (val < low) + return low; + if (val > up) + return up; + return val; +} + +static void +program_timings (ramctr_timing *ctrl, int channel) +{ + u32 reg32, reg_4024, reg_c14, reg_c18, reg_4028; + int lane; + int slotrank, slot; + int full_shift = 0; + u16 slot320c[NUM_SLOTS]; + + FOR_ALL_POPULATED_RANKS + if (full_shift < -ctrl->timings[channel][slotrank].val_320c) + full_shift = -ctrl->timings[channel][slotrank].val_320c; + + for (slot = 0; slot < NUM_SLOTS; slot++) + switch (ctrl->rankmap[channel][slot]) + { + case 0: + default: + slot320c[slot] = 0x7f; + break; + case 1: + slot320c[slot] = ctrl->timings[channel][2 * slot + 0].val_320c + full_shift; + break; + case 2: + slot320c[slot] = ctrl->timings[channel][2 * slot + 1].val_320c + full_shift; + break; + case 3: + slot320c[slot] = (ctrl->timings[channel][2 * slot].val_320c + + ctrl->timings[channel][2 * slot + 1].val_320c) / 2 + full_shift; + break; + } + + reg32 = (1 << 17) | (1 << 14); + reg32 |= ((slot320c[0] & 0x3f) << 6) | ((slot320c[0] & 0x40) << 9); + reg32 |= (slot320c[1] & 0x7f) << 18; + reg32 |= (full_shift & 0x3f) | ((full_shift & 0x40) << 6); + + MCHBAR32(0x320c + 0x100 * channel) = reg32; + + reg_c14 = (ctrl->rankmap[channel][0] | (ctrl->rankmap[channel][1] << 2)) << 24; + reg_c18 = 0; + + FOR_ALL_POPULATED_RANKS + { + int shift = ctrl->timings[channel][slotrank].val_320c + full_shift; + int offset_val_c14; + if (shift < 0) + shift = 0; + offset_val_c14 = ctrl->reg_c14_offset + shift; + reg_c14 |= (offset_val_c14 & 0x3f) << (6 * slotrank); + reg_c18 |= ((offset_val_c14 >> 6) & 1) << slotrank; + } + + MCHBAR32 (0xc14 + channel * 0x100) = reg_c14; + MCHBAR32 (0xc18 + channel * 0x100) = reg_c18; + + reg_4028 = MCHBAR32 (0x4028 + channel * 0x400); + reg_4028 &= 0xffff0000; + + reg_4024 = 0; + + FOR_ALL_POPULATED_RANKS + { + int post_timA_min_high = 7, post_timA_max_high = 0; + int pre_timA_min_high = 7, pre_timA_max_high = 0; + int shift_402x = 0; + int shift = ctrl->timings[channel][slotrank].val_320c + full_shift; + + if (shift < 0) + shift = 0; + + FOR_ALL_LANES + { + if (post_timA_min_high > ((ctrl->timings[channel][slotrank].lanes[lane].timA + shift) >> 6)) + post_timA_min_high = ((ctrl->timings[channel][slotrank].lanes[lane].timA + shift) >> 6); + if (pre_timA_min_high > (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6)) + pre_timA_min_high = (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6); + if (post_timA_max_high < ((ctrl->timings[channel][slotrank].lanes[lane].timA + shift) >> 6)) + post_timA_max_high = ((ctrl->timings[channel][slotrank].lanes[lane].timA + shift) >> 6); + if (pre_timA_max_high < (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6)) + pre_timA_max_high = (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6); + } + + if (pre_timA_max_high - pre_timA_min_high < post_timA_max_high - post_timA_min_high) + shift_402x = +1; + else if (pre_timA_max_high - pre_timA_min_high > post_timA_max_high - post_timA_min_high) + shift_402x = -1; + + reg_4028 |= (ctrl->timings[channel][slotrank].val_4028 + shift_402x - post_timA_min_high) << (4 * slotrank); + reg_4024 |= (ctrl->timings[channel][slotrank].val_4024 + shift_402x) << (8 * slotrank); + + FOR_ALL_LANES + { + MCHBAR32 (lane_registers[lane] + 0x10 + 0x100 * channel + 4 * slotrank) + = (((ctrl->timings[channel][slotrank].lanes[lane].timA + shift) & 0x3f) + | ((ctrl->timings[channel][slotrank].lanes[lane].rising + shift) << 8) + | (((ctrl->timings[channel][slotrank].lanes[lane].timA + shift + - (post_timA_min_high << 6)) & 0x1c0) << 10) + | (ctrl->timings[channel][slotrank].lanes[lane].falling << 20)); + + MCHBAR32 (lane_registers[lane] + 0x20 + 0x100 * channel + 4 * slotrank) + = ((clamp(ctrl->timings[channel][slotrank].lanes[lane].timC + shift, 0, 127) & 0x3f) + | (((ctrl->timings[channel][slotrank].lanes[lane].timB + shift) & 0x3f) << 8) + | (((ctrl->timings[channel][slotrank].lanes[lane].timB + shift) & 0x1c0) << 9) + | ((clamp(ctrl->timings[channel][slotrank].lanes[lane].timC + shift, 0, 127) & 0x40) << 13)); + } + } + MCHBAR32 (0x4024 + channel * 0x400) = reg_4024; + MCHBAR32 (0x4028 + channel * 0x400) = reg_4028; +} + +static void +test_timA (ramctr_timing *ctrl, int channel, int slotrank) +{ + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, (0xc01 | (ctrl->delay1 << 16))); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x360004); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x4040c01); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x100f | ((ctrl->CAS + 36) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, (0xc01 | (ctrl->delay1 << 16))); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel, (slotrank << 24) | 0x360000); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c (channel); +} + +static int +does_lane_work(ramctr_timing *ctrl, int channel, int slotrank, int lane) +{ + u32 timA = ctrl->timings[channel][slotrank].lanes[lane].timA; + return ((read32 (DEFAULT_MCHBAR + lane_registers[lane] + + channel * 0x100 + 4 + ((timA / 32) & 1) * 4) + >> (timA % 32)) & 1); +} + +struct run +{ + int middle; + int end; + int start; + int all; +}; + +static struct run +get_longest_zero_run (int *seq, int sz) +{ + int i, ls; + int bl = 0, bs = 0; + struct run ret; + + ls = 0; + for (i = 0; i < 2 * sz; i++) + if (seq[i % sz]) + { + if (i - ls > bl) + { + bl = i - ls; + bs = ls; + } + ls = i + 1; + } + if (bl == 0) + { + ret.middle = sz / 2; + ret.start = 0; + ret.end = sz; + ret.all = 1; + return ret; + } + + ret.start = bs % sz; + ret.end = (bs + bl - 1) % sz; + ret.middle = (bs + (bl - 1) / 2) % sz; + ret.all = 0; + + return ret; +} + +static void +discover_timA_coarse (ramctr_timing *ctrl, int channel, int slotrank, int *upperA) +{ + int timA; + int statistics[NUM_LANES][128]; + int lane; + + for (timA = 0; timA < 128; timA++) { + FOR_ALL_LANES + ctrl->timings[channel][slotrank].lanes[lane].timA = timA; + program_timings (ctrl, channel); + + test_timA(ctrl, channel, slotrank); + + FOR_ALL_LANES { + statistics[lane][timA] = !does_lane_work (ctrl, channel, slotrank, lane); + printk(BIOS_SPEW, "Astat: %d, %d, %d, %x, %x\n", channel, slotrank, lane, timA, + statistics[lane][timA]); + } + } + FOR_ALL_LANES + { + struct run rn = get_longest_zero_run (statistics[lane], 128); + ctrl->timings[channel][slotrank].lanes[lane].timA = rn.middle; + upperA[lane] = rn.end; + if (upperA[lane] < rn.middle) + upperA[lane] += 128; + printk(BIOS_SPEW, "Aval: %d, %d, %d, %x\n", channel, slotrank, lane, ctrl->timings[channel][slotrank].lanes[lane].timA); + printk(BIOS_SPEW, "Aend: %d, %d, %d, %x\n", channel, slotrank, lane, upperA[lane]); + } +} + +static void +discover_timA_fine (ramctr_timing *ctrl, int channel, int slotrank, int *upperA) +{ + int timA_delta; + int statistics[NUM_LANES][51]; + int lane, i; + + memset (statistics, 0, sizeof (statistics)); + + for (timA_delta = -25; timA_delta <= 25; timA_delta++) { + FOR_ALL_LANES + ctrl->timings[channel][slotrank].lanes[lane].timA = upperA[lane] + timA_delta + 0x40; + program_timings (ctrl, channel); + + for (i = 0; i < 100; i++) + { + test_timA(ctrl, channel, slotrank); + FOR_ALL_LANES { + statistics[lane][timA_delta + 25] += does_lane_work (ctrl, channel, slotrank, lane); + } + } + FOR_ALL_LANES { + printk(BIOS_SPEW, "A+stat: %d, %d, %d, %d (%x), %x\n", channel, slotrank, lane, timA_delta, + upperA[lane] + timA_delta + 0x40, + statistics[lane][timA_delta + 25]); + } + } + FOR_ALL_LANES + { + int last_zero, first_all; + + for (last_zero = -25; last_zero <= 25; last_zero++) + if (statistics[lane][last_zero + 25]) + break; + last_zero--; + for (first_all = -25; first_all <= 25; first_all++) + if (statistics[lane][first_all + 25] == 100) + break; + + printk (BIOS_SPEW, "lane %d: %d, %d\n", lane, last_zero, first_all); + + ctrl->timings[channel][slotrank].lanes[lane].timA = (last_zero + first_all) / 2 + upperA[lane]; + printk(BIOS_SPEW, "Aval: %d, %d, %d, %x\n", channel, slotrank, lane, ctrl->timings[channel][slotrank].lanes[lane].timA); + } +} + +static void +discover_402x (ramctr_timing *ctrl, int channel, int slotrank, int *upperA) +{ + int works[NUM_LANES]; + int lane; + while (1) + { + int all_works = 1, some_works = 0; + program_timings (ctrl, channel); + test_timA(ctrl, channel, slotrank); + FOR_ALL_LANES + { + works[lane] = !does_lane_work(ctrl, channel, slotrank, lane); + if (works[lane]) + some_works = 1; + else + all_works = 0; + } + if (all_works) + return; + if (!some_works) { + if (ctrl->timings[channel][slotrank].val_4024 < 2) + die ("402x discovery failed"); + ctrl->timings[channel][slotrank].val_4024 -= 2; + printk (BIOS_SPEW, "4024 -= 2;\n"); + continue; + } + ctrl->timings[channel][slotrank].val_4028 += 2; + printk (BIOS_SPEW, "4028 += 2;\n"); + if (ctrl->timings[channel][slotrank].val_4028 >= 0x10) + die ("402x discovery failed"); + FOR_ALL_LANES + if (works[lane]) { + ctrl->timings[channel][slotrank].lanes[lane].timA += 128; + upperA[lane] += 128; + printk (BIOS_SPEW, "increment %d, %d, %d\n", channel, slotrank, lane); + } + } +} + +struct timA_minmax +{ + int timA_min_high, timA_max_high; +}; + +static void +pre_timA_change (ramctr_timing *ctrl, int channel, int slotrank, struct timA_minmax *mnmx) +{ + int lane; + mnmx->timA_min_high = 7; + mnmx->timA_max_high = 0; + + FOR_ALL_LANES { + if (mnmx->timA_min_high > (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6)) + mnmx->timA_min_high = (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6); + if (mnmx->timA_max_high < (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6)) + mnmx->timA_max_high = (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6); + } +} + +static void +post_timA_change (ramctr_timing *ctrl, int channel, int slotrank, struct timA_minmax *mnmx) +{ + struct timA_minmax post; + int shift_402x = 0; + + /* Get changed maxima. */ + pre_timA_change (ctrl, channel, slotrank, &post); + + if (mnmx->timA_max_high - mnmx->timA_min_high < post.timA_max_high - post.timA_min_high) + shift_402x = +1; + else if (mnmx->timA_max_high - mnmx->timA_min_high > post.timA_max_high - post.timA_min_high) + shift_402x = -1; + else + shift_402x = 0; + + ctrl->timings[channel][slotrank].val_4028 += shift_402x; + ctrl->timings[channel][slotrank].val_4024 += shift_402x; + printk (BIOS_SPEW, "4024 += %d;\n", shift_402x); + printk (BIOS_SPEW, "4028 += %d;\n", shift_402x); +} + +static void +read_training (ramctr_timing *ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + { + u32 r32; + int all_high, some_high; + int upperA[NUM_LANES]; + struct timA_minmax mnmx; + + wait_428c (channel); + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x4230 + channel * 0x400, + 0xc01 | (ctrl->tRP << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + channel * 0x400, + (slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 1); + + write32 (DEFAULT_MCHBAR + 0x3400, (slotrank << 2) | 0x8001); + + ctrl->timings[channel][slotrank].val_4028 = 4; + ctrl->timings[channel][slotrank].val_4024 = 55; + program_timings (ctrl, channel); + + discover_timA_coarse (ctrl, channel, slotrank, upperA); + + all_high = 1; + some_high = 0; + FOR_ALL_LANES + if (ctrl->timings[channel][slotrank].lanes[lane].timA >= 0x40) + some_high = 1; + else + all_high = 0; + if (all_high) { + ctrl->timings[channel][slotrank].val_4028--; + printk (BIOS_SPEW, "4028--;\n"); + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].timA -= 0x40; + upperA[lane] -= 0x40; + } + } else if (some_high) { + ctrl->timings[channel][slotrank].val_4024++; + ctrl->timings[channel][slotrank].val_4028++; + printk (BIOS_SPEW, "4024++;\n"); + printk (BIOS_SPEW, "4028++;\n"); + } + + program_timings (ctrl, channel); + + pre_timA_change (ctrl, channel, slotrank, &mnmx); + + discover_402x (ctrl, channel, slotrank, upperA); + + post_timA_change (ctrl, channel, slotrank, &mnmx); + pre_timA_change (ctrl, channel, slotrank, &mnmx); + + discover_timA_fine (ctrl, channel, slotrank,upperA); + + post_timA_change (ctrl, channel, slotrank, &mnmx); + pre_timA_change (ctrl, channel, slotrank, &mnmx); + + FOR_ALL_LANES + ctrl->timings[channel][slotrank].lanes[lane].timA -= mnmx.timA_min_high * 0x40; + ctrl->timings[channel][slotrank].val_4028 -= mnmx.timA_min_high; + printk (BIOS_SPEW, "4028 -= %d;\n", mnmx.timA_min_high); + + post_timA_change (ctrl, channel, slotrank, &mnmx); + + printk (BIOS_SPEW, "4/8: %d, %d, %x, %x\n", channel, slotrank, + ctrl->timings[channel][slotrank].val_4024, + ctrl->timings[channel][slotrank].val_4028); + + FOR_ALL_LANES + printk (BIOS_SPEW, "%d, %d, %d, %x\n", channel, slotrank, lane, + ctrl->timings[channel][slotrank].lanes[lane].timA); + + write32 (DEFAULT_MCHBAR + 0x3400, 0); + + r32 = read32 (DEFAULT_MCHBAR + 0x5030); + write32 (DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay (1); + + write32 (DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay (1); + } + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + write32 (0x4080 + 4 * lane + 0x400 * channel + DEFAULT_MCHBAR, 0); +} + +static void +test_timC (ramctr_timing *ctrl, int channel, int slotrank) +{ + int lane; + + FOR_ALL_LANES + { + write32 (DEFAULT_MCHBAR + 0x4340 + channel * 0x400 + + 4 * lane, 0); + read32 (DEFAULT_MCHBAR + 0x4140 + channel * 0x400 + + 4 * lane); + } + + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f006); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, (max ((ctrl->tFAW >> 2) + 1, ctrl->tRRD) << 10) + | 4 | (ctrl->tRCD << 16)); + + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | (6 << 16)); + + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x244); + + write32 (DEFAULT_MCHBAR + 0x4224 + channel * 0x400, 0x1f207); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x8041001); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24) | 8); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f201); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x80411f4); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0x242); + + write32 (DEFAULT_MCHBAR + 0x422c + channel * 0x400, 0x1f207); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, 0x8000c01 + | ((ctrl->CWL + ctrl->tWTR + 5) << 16)); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel, (slotrank << 24) | 8); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 0xc0001); + + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0xc01 | (ctrl->tRP << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x240); + + write32 (DEFAULT_MCHBAR + 0x4224 + channel * 0x400, 0x1f006); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + (max (ctrl->tRRD, (ctrl->tFAW >> 2) + 1) << 10) + | 8 | (ctrl->CAS << 16)); + + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24) | 0x60000); + + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0x244); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x40011f4 | (max (ctrl->tRTP, 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0x242); + + write32 (DEFAULT_MCHBAR + 0x422c + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, 0xc01 | (ctrl->tRP << 16)); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0x240); + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 0xc0001); + wait_428c (channel); +} + +static void +discover_timC (ramctr_timing *ctrl, int channel, int slotrank) +{ + int timC; + int statistics[NUM_LANES][MAX_TIMC + 1]; + int lane; + + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0xc01 | (ctrl->tRP << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x240); + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 1); + + for (timC = 0; timC <= MAX_TIMC; timC++) { + FOR_ALL_LANES + ctrl->timings[channel][slotrank].lanes[lane].timC = timC; + program_timings (ctrl, channel); + + test_timC (ctrl, channel, slotrank); + + FOR_ALL_LANES + { + statistics[lane][timC] = read32 (DEFAULT_MCHBAR + 0x4340 + 4 * lane + + channel * 0x400); + printk(BIOS_SPEW, "Cstat: %d, %d, %d, %x, %x\n", channel, slotrank, lane, timC, + statistics[lane][timC]); + } + } + FOR_ALL_LANES + { + struct run rn = get_longest_zero_run (statistics[lane], MAX_TIMC + 1); + ctrl->timings[channel][slotrank].lanes[lane].timC = rn.middle; + if (rn.all) + die ("timC discovery failed"); + printk(BIOS_SPEW, "Cval: %d, %d, %d, %x\n", channel, slotrank, lane, ctrl->timings[channel][slotrank].lanes[lane].timC); + } +} + +static int +get_precedening_channels (ramctr_timing *ctrl, int target_channel) +{ + int channel, ret = 0; + FOR_ALL_POPULATED_CHANNELS + if (channel < target_channel) + ret++; + return ret; +} + +static void +fill_pattern0 (ramctr_timing *ctrl, int channel, u32 a, u32 b) +{ + unsigned j; + unsigned channel_offset = get_precedening_channels (ctrl, channel) * 0x40; + printk (BIOS_SPEW, "channel_offset=%x\n", channel_offset); + for (j = 0 ; j < 16; j++) + write32 (0x04000000 + channel_offset + 4 * j, j & 2 ? b : a); + sfence (); +} +static int num_of_channels (const ramctr_timing *ctrl) +{ + int ret = 0; + int channel; + FOR_ALL_POPULATED_CHANNELS + ret++; + return ret; +} + +static void fill_pattern1 (ramctr_timing *ctrl, int channel) +{ + unsigned j; + unsigned channel_offset = get_precedening_channels (ctrl, channel) * 0x40; + unsigned channel_step = 0x40 * num_of_channels (ctrl); + for (j = 0 ; j < 16; j++) + write32 (0x04000000 + channel_offset + j * 4, 0xffffffff); + for (j = 0 ; j < 16; j++) + write32 (0x04000000 + channel_offset + channel_step + j * 4, 0); + sfence (); +} + +static void +precharge (ramctr_timing *ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_POPULATED_CHANNELS + { + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].falling = 16; + ctrl->timings[channel][slotrank].lanes[lane].rising = 16; + } + + program_timings (ctrl, channel); + + FOR_ALL_POPULATED_RANKS + { + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32 (0x4230 + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + channel * 0x400, (slotrank << 24) | 0x360004); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32 (0x4234 + 0x400 * channel + DEFAULT_MCHBAR, 0x4041003); + write32 (DEFAULT_MCHBAR + 0x4204 + channel * 0x400, (slotrank << 24) | 0); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32 (0x4238 + 0x400 * channel + DEFAULT_MCHBAR, 0x1001 | ((ctrl->CAS + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + channel * 0x400, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32 (0x423c + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + write32 (DEFAULT_MCHBAR + 0x420c + channel * 0x400, (slotrank << 24) | 0x360000); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c (channel); + } + + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].falling = 48; + ctrl->timings[channel][slotrank].lanes[lane].rising = 48; + } + + program_timings (ctrl, channel); + + FOR_ALL_POPULATED_RANKS + { + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32 (0x4230 + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + channel * 0x400, (slotrank << 24) | 0x360004); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32 (0x4234 + 0x400 * channel + DEFAULT_MCHBAR, 0x4041003); + write32 (DEFAULT_MCHBAR + 0x4204 + channel * 0x400, (slotrank << 24) | 0); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32 (0x4238 + 0x400 * channel + DEFAULT_MCHBAR, 0x1001 | ((ctrl->CAS + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + channel * 0x400, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32 (0x423c + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + + write32 (DEFAULT_MCHBAR + 0x420c + channel * 0x400, (slotrank << 24) | 0x360000); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + wait_428c (channel); + } + } +} + +static void +test_timB (ramctr_timing *ctrl, int channel, int slotrank) +{ + write_mrreg (ctrl, channel, slotrank, 1, 0x80 | make_mr1 (ctrl, slotrank)); + + wait_428c (channel); + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f207); + write32 (0x4230 + 0x400 * channel + DEFAULT_MCHBAR, 0x8000c01 + | ((ctrl->CWL + ctrl->delay2) << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, 8 | (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f107); + write32 (0x4234 + 0x400 * channel + DEFAULT_MCHBAR, 0x4000c01 | ((ctrl->CAS + 38) << 16)); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24) | 4); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x400 * channel + 0x4284, 0x40001); + wait_428c (channel); + + write_mrreg (ctrl, channel, slotrank, 1, 0x1080 | make_mr1 (ctrl, slotrank)); +} + +static void +discover_timB (ramctr_timing *ctrl, int channel, int slotrank) +{ + int timB; + int statistics[NUM_LANES][128]; + int lane; + + write32 (DEFAULT_MCHBAR + 0x3400, 0x108052 | (slotrank << 2)); + + for (timB = 0; timB < 128; timB++) { + FOR_ALL_LANES + ctrl->timings[channel][slotrank].lanes[lane].timB = timB; + program_timings (ctrl, channel); + + test_timB (ctrl, channel, slotrank); + + FOR_ALL_LANES { + statistics[lane][timB] = !((read32 (DEFAULT_MCHBAR + lane_registers[lane] + + channel * 0x100 + 4 + ((timB / 32) & 1) * 4) + >> (timB % 32)) & 1); + printk(BIOS_SPEW, "Bstat: %d, %d, %d, %x, %x\n", channel, slotrank, lane, timB, + statistics[lane][timB]); + } + } + FOR_ALL_LANES + { + struct run rn = get_longest_zero_run (statistics[lane], 128); + ctrl->timings[channel][slotrank].lanes[lane].timB = rn.end; + if (rn.all) + die ("timB discovery failed"); + printk(BIOS_SPEW, "Bval: %d, %d, %d, %x\n", channel, slotrank, lane, ctrl->timings[channel][slotrank].lanes[lane].timB); + } +} + +static int +get_timB_high_adjust (u64 val) +{ + int i; + if (val >= 0xfffffffffff00000LL) + return -1; + if (val >= 0xfffffff000000000LL) + return -2; + if (val >= 0xfff0000000000000LL) + return -3; + + for (i = 0; i < 8; i++) + if (val >> (8 * (7 - i) + 4)) + return i; + return 8; +} + +static void +adjust_high_timB (ramctr_timing *ctrl) +{ + int channel, slotrank, lane; + write32 (DEFAULT_MCHBAR + 0x3400, 0x200); + FOR_ALL_POPULATED_CHANNELS { + fill_pattern1 (ctrl, channel); + write32 (DEFAULT_MCHBAR | 0x4288 | (channel << 10), 1); + } + FOR_ALL_POPULATED_CHANNELS + FOR_ALL_POPULATED_RANKS { + + write32 (DEFAULT_MCHBAR + 0x4288 + channel * 0x400, 0x10001); + + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f006); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0xc01 | (ctrl->tRCD << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + channel * 0x400, 0x1f207); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x8040c01); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24) | 0x8); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f201); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x8041003); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0x3e2); + + write32 (DEFAULT_MCHBAR + 0x422c + channel * 0x400, 0x1f207); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16)); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel, (slotrank << 24) | 0x8); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 0xc0001); + + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0xc01 | ((ctrl->tRP) << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x240); + + write32 (DEFAULT_MCHBAR + 0x4224 + channel * 0x400, 0x1f006); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0xc01 | ((ctrl->tRCD) << 16)); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x3f105); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x4000c01 | ((ctrl->tRP + + ctrl->timings[channel][slotrank].val_4024 + + ctrl->timings[channel][slotrank].val_4028) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24) | 0x60008); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 0x80001); + wait_428c (channel); + FOR_ALL_LANES { + u64 res = read32 (DEFAULT_MCHBAR + lane_registers[lane] + 0x100 * channel + 4); + res |= ((u64)read32 (DEFAULT_MCHBAR + lane_registers[lane] + 0x100 * channel + 8)) << 32; + ctrl->timings[channel][slotrank].lanes[lane].timB += get_timB_high_adjust (res) * 64; + printk(BIOS_SPEW, "Bval+: %d, %d, %d, %x\n", channel, slotrank, lane, ctrl->timings[channel][slotrank].lanes[lane].timB); + } + } + write32 (DEFAULT_MCHBAR + 0x3400, 0); +} + +static void +write_training (ramctr_timing *ctrl) +{ + int channel, slotrank, lane; + u32 r32; + + FOR_ALL_POPULATED_CHANNELS + write32 (DEFAULT_MCHBAR + 0x4008 + 0x400 * channel, + read32 (DEFAULT_MCHBAR + 0x4008 + 0x400 * channel) | 0x8000000); + + FOR_ALL_POPULATED_CHANNELS { + wait_428c (channel); + + /* choose an existing rank. */ + slotrank = !ctrl->rankmap[channel][0] ? 2 : 0; + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x0f003); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60000); + + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c (channel); + write32 (DEFAULT_MCHBAR + 0x4020 + channel * 0x400, + read32 (DEFAULT_MCHBAR + 0x4020 + channel * 0x400) | 0x200000); + } + write32 (DEFAULT_MCHBAR + 0x5030, + read32 (DEFAULT_MCHBAR + 0x5030) & ~8); + FOR_ALL_POPULATED_CHANNELS { + wait_428c (channel); + + /* choose an existing rank. */ + slotrank = !ctrl->rankmap[channel][0] ? 2 : 0; + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x0f003); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60000); + + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c (channel); + } + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + write_mrreg (ctrl, channel, slotrank, 1, make_mr1(ctrl, slotrank) | 0x1080); + + write32 (DEFAULT_MCHBAR + 0x3400, 0x108052); + + r32 = read32 (DEFAULT_MCHBAR + 0x5030); + write32 (DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay (1); + + write32 (DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay (1); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + discover_timB(ctrl, channel, slotrank); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + write_mrreg (ctrl, channel, slotrank, 1, make_mr1(ctrl, slotrank)); + + write32 (DEFAULT_MCHBAR + 0x3400, 0); + + FOR_ALL_POPULATED_CHANNELS + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x5030, read32 (DEFAULT_MCHBAR + 0x5030) | 8); + + FOR_ALL_POPULATED_CHANNELS + { + write32 (DEFAULT_MCHBAR + 0x4020 + channel * 0x400, + ~0x00200000 & read32 (DEFAULT_MCHBAR + 0x4020 + channel * 0x400)); + read32 (DEFAULT_MCHBAR + 0x428c + channel * 0x400); + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x0f003); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x659001); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, 0x60000); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 1); + wait_428c (channel); + } + + r32 = read32 (DEFAULT_MCHBAR + 0x5030); + write32 (DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay (1); + + write32 (DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay (1); + + printk (BIOS_SPEW, "CPE\n"); + precharge (ctrl); + printk (BIOS_SPEW, "CPF\n"); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + read32 (0x4080 + 4 * lane + 0x400 * channel + DEFAULT_MCHBAR); + write32 (0x4080 + 4 * lane + 0x400 * channel + DEFAULT_MCHBAR, 0); + } + + FOR_ALL_POPULATED_CHANNELS + { + fill_pattern0 (ctrl, channel, 0xaaaaaaaa, 0x55555555); + write32 (DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + } + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + discover_timC(ctrl, channel, slotrank); + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); + + adjust_high_timB(ctrl); + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + read32 (0x4080 + 4 * lane + 0x400 * channel + DEFAULT_MCHBAR); + write32 (0x4080 + 4 * lane + 0x400 * channel + DEFAULT_MCHBAR, 0); + } +} + +static int +test_320c (ramctr_timing *ctrl, int channel, int slotrank) +{ + struct ram_rank_timings saved_rt = ctrl->timings[channel][slotrank]; + int timC_delta; + int lanes_ok = 0; + int ctr = 0; + int lane; + + for (timC_delta = -5; timC_delta <= 5; timC_delta++) { + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].timC = saved_rt.lanes[lane].timC + timC_delta; + } + program_timings (ctrl, channel); + FOR_ALL_LANES + write32 (DEFAULT_MCHBAR + 4 * lane + 0x4f40, 0); + + write32 (DEFAULT_MCHBAR + 0x4288 + channel * 0x400, 0x1f); + + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f006); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, ((max (ctrl->tRRD, (ctrl->tFAW >> 2) + 1)) << 10) + | 8 | (ctrl->tRCD << 16)); + + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | ctr | 0x60000); + + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x244); + + write32 (DEFAULT_MCHBAR + 0x4224 + channel * 0x400, 0x1f201); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x8001020 | ((ctrl->CWL + ctrl->tWTR + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4244 + channel * 0x400, 0x389abcd); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0x20e42); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x4001020 | (max (ctrl->tRTP, 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4248 + channel * 0x400, 0x389abcd); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0x20e42); + + write32 (DEFAULT_MCHBAR + 0x422c + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, 0xf1001); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel, (slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0x240); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + wait_428c (channel); + FOR_ALL_LANES + { + u32 r32 = read32 (DEFAULT_MCHBAR + 0x4340 + 4 * lane + channel * 0x400); + + if (r32 == 0) + lanes_ok |= 1 << lane; + } + ctr++; + if (lanes_ok == ((1 << NUM_LANES) - 1)) + break; + } + + ctrl->timings[channel][slotrank] = saved_rt; + return lanes_ok != ((1 << NUM_LANES) - 1); +} + +const u32 pattern[][16] = { + { 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff }, + { 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000 }, + { 0xe62d6424, 0x9277e09e, 0x8f43dc3f, 0x76eae589, + 0x0010fdc6, 0xdc55e01c, 0x5effb0ab, 0x6cba5d29, + 0xa43d1e64, 0xab5c2e0f, 0x7796ed16, 0x96023bf4, + 0xa74c831d, 0x90f138c0, 0x17830a8a, 0x5ac17c47 }, + { 0x359ebbeb, 0x2b9b4512, 0xef584d98, 0x106bf7cb, + 0x363525ad, 0xb3a4dfdc, 0xa6b9fcd8, 0xd21689ec, + 0x84a3695b, 0xbd9c2e27, 0xdb3d0f44, 0x988158f1, + 0xcca91d3f, 0xb62a6d12, 0xe905e4cf, 0x7f1fa626 }, + { 0xe58efeae, 0xcd006081, 0xa9119403, 0xbcfbd35f, + 0x213b3bf7, 0x7bfcb773, 0xc85143f9, 0x0bdbff50, + 0xa3053c90, 0x51d66cb7, 0x296f4387, 0xb715f99e, + 0xfaddc989, 0xbb1de8a7, 0x39206b4d, 0x80174a57 }, + { 0xa1622ac1, 0xb4f4a5f0, 0x16dc2bc3, 0x50fb0954, + 0x2e261721, 0x52b82c3c, 0x821902b8, 0x0d4b6c38, + 0x1f618631, 0x047956f3, 0xd4337f5a, 0x591f8002, + 0x27f28db2, 0xfae37369, 0xb3f27580, 0x3cdb6397 }, + { 0x3dee23be, 0x19f36408, 0x227f4a6a, 0x024603c5, + 0xd5e062db, 0x6d8d4c5c, 0x7ff693b0, 0x76641be9, + 0x9e74f41c, 0xe7bc7f33, 0x2636f2e9, 0x70279750, + 0xce2355aa, 0x32d230ef, 0x22f9b468, 0xadd4e7a2 }, + { 0x936c0fed, 0xba0612d5, 0xa97c1ea7, 0x10e29d67, + 0x1c4c5dc8, 0x83645621, 0xcd8b521c, 0xb8301817, + 0xac7d6571, 0xcc41d200, 0x4ebdefdd, 0xd2917bde, + 0x60f75acc, 0x7791534b, 0x26ea2a83, 0x6b74513a }, + { 0xd1957b85, 0xc6f8f9ca, 0xf04fb4be, 0xfeb786fb, + 0xa1dea3aa, 0x67fe7db6, 0x25d49c87, 0xe3d54870, + 0x93dc1f86, 0x7d0c1a18, 0x9272e128, 0x68e1b876, + 0xce284c9e, 0x8fa18792, 0x5785a340, 0xb6fcf198 }, + { 0xff7d8e4a, 0x0c21ee43, 0xe820b388, 0xb4443c0e, + 0xa1e6e498, 0x5c426110, 0x1b434ef3, 0xbef05b91, + 0xa6907968, 0x53662ac3, 0x6defac32, 0x2c11c29c, + 0x6175cced, 0xb17dd3ad, 0x6e6a1076, 0x1372b1fa }, + { 0x4408ed06, 0x49460ffd, 0xb49d26cb, 0x6a3662a5, + 0x5e857047, 0xa387cd4a, 0x04edc81e, 0xfd94d8d4, + 0x2fe48d91, 0x9d2356bc, 0x96131878, 0xaca3fce4, + 0xbb312c6c, 0x5023b090, 0x3614be70, 0xa14dfabb }, + { 0xd4cc1e83, 0x757a1930, 0xc3d16a61, 0x9e0d6681, + 0x8a081fa9, 0xbd11c888, 0x1672f010, 0xa083f71c, + 0x1ec02eef, 0xc4586ca8, 0x6d322b35, 0x56054679, + 0x1552a0ff, 0x5cb7707e, 0xdfb55d4a, 0xcc76cc07 }, + { 0x507cf71f, 0x2166421a, 0x54be4af0, 0xfd42158c, + 0x417b1f7f, 0x9466860b, 0x3a0075bf, 0x2055575c, + 0xcedfe7ab, 0xbe85aa5f, 0x39d0c2e3, 0x851c19df, + 0x39a35a3f, 0x3fb10d7d, 0x20b14899, 0x703b7f08 }, + { 0x8a7d9dd1, 0x33235565, 0xbd3d2e57, 0xa48c2726, + 0x0d5e2e13, 0xae421ff9, 0x8784a224, 0xf66c1510, + 0x057627aa, 0x8fb0cb41, 0x4289975a, 0xb181adfa, + 0x59f2059a, 0xe86feb05, 0x84222fc1, 0x319b3ce9 }, + { 0xe1e243b8, 0x3b0bcc1a, 0x70396f00, 0x5caff44d, + 0xe96961b3, 0xad73f692, 0x8b841a2d, 0xf5838839, + 0xec9c9d04, 0xcc2b5562, 0xf8ca2549, 0xa9c52ff8, + 0x3b2fde68, 0x3d4dc7f0, 0xa57387d0, 0x051199ad }, + { 0x5f0ce4fc, 0xd830fbb7, 0x90abeb8f, 0x96d9cdbb, + 0x58f80a80, 0x0baaca36, 0x81a23623, 0x77127614, + 0xaa8382cd, 0x0922fbca, 0xd84d37e1, 0x721297df, + 0x160f3b3a, 0x10a1ecdc, 0x151c92f4, 0xc1fdcdab }, + { 0x261c45cc, 0xfeddd2da, 0xfc3cb1c1, 0x6639641f, + 0x2c011892, 0x7108bee2, 0x8545e0b9, 0x7dd36dab, + 0x07d91950, 0x1520adcb, 0xf84aa939, 0x07d9bb2d, + 0xdf1ed826, 0xaee3c814, 0x1dca1e81, 0xc8e9f486 }, + { 0x933d306a, 0xaab7103d, 0xa8be37be, 0x49612f3a, + 0xb0cf28e5, 0xf9648902, 0x106d7c11, 0xf32e1813, + 0x21af36ef, 0xe695e4c4, 0x7ee1831d, 0x2aeda467, + 0x99d0c655, 0x3f0691ab, 0xcd68f7c1, 0xb469a20e }, + { 0x8557aef0, 0x3eb0e373, 0x0853ac31, 0xe5bded62, + 0x3eddb0dd, 0x6bbf1caf, 0x2119c3d9, 0xe1732350, + 0x55456c75, 0xf6119375, 0x498dd1ad, 0x13f80916, + 0xb97f9f5e, 0x921d9f4c, 0xabdee367, 0x1d6bb8bf }, + { 0xd165a3be, 0xd8b41598, 0xa20e1809, 0xefd5c8ce, + 0x18935c80, 0xdf1911f9, 0xc9e449eb, 0xb887a4d7, + 0x4a324f6f, 0x533e8031, 0x1c21c074, 0xa95f1ea5, + 0x765b320a, 0x839d7dfb, 0xc7d3aa93, 0xe534ae3d }, + { 0xbe8592c8, 0x068457e6, 0x89b94fa3, 0xd522ad02, + 0x7e7db0b7, 0x2c5b896f, 0x9f8ecb37, 0x05b983ff, + 0x3fe9b25f, 0x34a6215b, 0x0592ba34, 0xd564f85a, + 0x156c426d, 0x25ad5460, 0xe7b5e8b7, 0xa73285c6 }, + { 0x5ad8d838, 0x27b42d36, 0xcc806ad1, 0x157a058a, + 0x7297735a, 0xffd6df8d, 0xff96f7a2, 0x155b27ea, + 0x84708101, 0x979fd78b, 0x49797d0c, 0x0dc93e3c, + 0x20287332, 0xed759f88, 0xe5068529, 0xb83aa781 }, + { 0xc38b302c, 0x57b54075, 0xac810692, 0xb0d493e7, + 0x4adda486, 0x0665ce2e, 0xb2a9c003, 0xafacc4ce, + 0x4d5e906d, 0xb3d52fab, 0xe6962c6b, 0x850f4dd1, + 0x5021656c, 0x5df6c06b, 0x9255125b, 0x2363c478 }, + { 0x188b715c, 0xe8b884b0, 0x5e6d0b9a, 0x1f0051e1, + 0xd2d35d4c, 0xbfeaecbe, 0xc84bb0ad, 0x67a232d6, + 0x99001587, 0xbf4313e1, 0x74f64061, 0x2c1fc562, + 0xb6fe8ca6, 0x5226a239, 0xf5198574, 0x61b51dca }, + { 0x51dcecd3, 0xbadbe596, 0xebe3e84a, 0x772bfdfc, + 0x03656ac5, 0xa7c36e91, 0x6cd32cf0, 0xc3f699dd, + 0x7d5aba01, 0x51e38e82, 0x23103a98, 0x20298b9d, + 0x19436510, 0x63ad7e6c, 0x8bc2b33f, 0x27079917 }, + { 0x8bd5be78, 0xf2403bfa, 0x780ebdb6, 0x94c53b64, + 0x6241c2e2, 0x5bfb081e, 0x6799e88f, 0xc997b7d1, + 0x466ac8b1, 0xbf5909da, 0x497ea39f, 0x402ffb48, + 0xd7470c2d, 0x8510aba9, 0x6c52a1c9, 0x812ca967 }, + { 0x031f7ab4, 0xd32fe890, 0x36ae6de5, 0x083dcde4, + 0x99a7f12f, 0xe44864a7, 0x02b75fff, 0xf25dda35, + 0x7679ff4f, 0xed421e01, 0xd9c2cfa1, 0xd36b4e82, + 0x5315d908, 0xc7ebcb2a, 0xb6f3e4c1, 0xf5bfbae9 }, + { 0x3f4a2a96, 0x64d8bd5a, 0x19acd70d, 0xf62fcdd9, + 0x5de99cdf, 0x32f3b7cb, 0x2c020578, 0x4e9bafb8, + 0x74919a08, 0xaba33e91, 0xa6bd2254, 0x2435a9b9, + 0x47e2a1b4, 0xe837a28e, 0xe113f1b0, 0x7654bd79 }, + { 0x05537a6c, 0x77be1a5c, 0x4c7492c9, 0x9086bfb0, + 0x257adc18, 0xf4787fc1, 0xe3fb6d53, 0x9525e589, + 0x445a65bc, 0x833f7d08, 0x69cf1f7e, 0x9a6372e1, + 0xceedb52e, 0x31032997, 0xd1c36828, 0x132772d6 }, + { 0x0a166972, 0x89beaf3b, 0x8d780fbc, 0x8aea5392, + 0x58347a41, 0x1e381ec2, 0xcc6280c8, 0xee0863e1, + 0x976e2dd2, 0x8c6ee6e2, 0xa0ca57cd, 0x95114a7d, + 0x3c096704, 0xa941769d, 0x2de20c05, 0x0bf8f812 }, + { 0x22779d6c, 0x94e12e8f, 0x5ce40299, 0xea1b55b0, + 0x9ebec05d, 0xe076cd2b, 0x8fef5648, 0x6a284c65, + 0xa790b705, 0xf0b19997, 0x0d8ca8af, 0x17440419, + 0xef4f702f, 0x33cbcbb1, 0x83d60f26, 0x48988397 }, + { 0x0fed7f53, 0xb5acbb67, 0xc031c73f, 0x5364d9ef, + 0xa6dbd12d, 0x82174a6c, 0xccf8e7ab, 0xc473c036, + 0xcff493d8, 0xad9afc3b, 0x316a24e8, 0x1842bea4, + 0x4cc0c82e, 0x28ccd91e, 0xd7311b5d, 0x50a89860 }, +}; + +static void fill_pattern5 (ramctr_timing *ctrl, int channel) +{ + unsigned i, j; + unsigned channel_offset = get_precedening_channels (ctrl, channel) * 0x40; + unsigned channel_step = 0x40 * num_of_channels (ctrl); + for (i = 0; i < sizeof (pattern) / sizeof (pattern[0]); i++) + { + for (j = 0 ; j < 16; j++) + write32 (0x04000000 + channel_offset + i * channel_step + j * 4, pattern[i][j]); + } + sfence (); +} + + +static void +reprogram_320c (ramctr_timing *ctrl) +{ + int channel, slotrank; + u32 r32; + + FOR_ALL_POPULATED_CHANNELS { + wait_428c (channel); + + /* choose an existing rank. */ + slotrank = !ctrl->rankmap[channel][0] ? 2 : 0; + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x0f003); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60000); + + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c (channel); + write32 (DEFAULT_MCHBAR + 0x4020 + channel * 0x400, + read32 (DEFAULT_MCHBAR + 0x4020 + channel * 0x400) | 0x200000); + } + write32 (DEFAULT_MCHBAR + 0x5030, + read32 (DEFAULT_MCHBAR + 0x5030) & ~8); + FOR_ALL_POPULATED_CHANNELS { + wait_428c (channel); + + /* choose an existing rank. */ + slotrank = !ctrl->rankmap[channel][0] ? 2 : 0; + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x0f003); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60000); + + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c (channel); + } + + /* jedec reset */ + dram_jedecreset(ctrl); + /* mrs commands. */ + dram_mrscommands(ctrl); + + r32 = read32 (DEFAULT_MCHBAR + 0x5030); + write32 (DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay (1); + + write32 (DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay (1); +} + +static void +command_training (ramctr_timing *ctrl) +{ + int channel; + int slotrank; + u32 reg_4004_b30; + int delta = 0; + int c320c; + int stat[NUM_SLOTRANKS][256]; + + /* FIXME: vendor BIOS discovers this by trying 0 and 2. Apparently 2 should work for + all systems but 0 is slightly more efficient for the systems that can tolerate it. + */ + reg_4004_b30 = 2; + + FOR_ALL_POPULATED_CHANNELS + /* FIXME: avoid unnecessarry readback. */ + MCHBAR32 (0x4004 + 0x400 * channel) = + (MCHBAR32 (0x4004 + 0x400 * channel) & ~(3 << 30)) + | (reg_4004_b30 << 30); + + if (reg_4004_b30 == 2) + delta = 2; + else if (reg_4004_b30 == 0) + delta = 4; + + FOR_ALL_CHANNELS + { + FOR_ALL_POPULATED_RANKS + ctrl->timings[channel][slotrank].val_4024 -= delta; + } + + FOR_ALL_POPULATED_CHANNELS + { + fill_pattern5 (ctrl, channel); + write32 (DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + } + + FOR_ALL_POPULATED_CHANNELS + { + for (c320c = -127; c320c <= 127; c320c++) + { + FOR_ALL_POPULATED_RANKS + ctrl->timings[channel][slotrank].val_320c = c320c; + program_timings (ctrl, channel); + reprogram_320c (ctrl); + FOR_ALL_POPULATED_RANKS + { + stat[slotrank][c320c + 127] = test_320c (ctrl, channel, slotrank); + printk (BIOS_SPEW, "3stat: %d, %d, %d: %d\n", channel, slotrank, c320c, + stat[slotrank][c320c + 127]); + } + } + FOR_ALL_POPULATED_RANKS + { + struct run rn = get_longest_zero_run (stat[slotrank], 255); + ctrl->timings[channel][slotrank].val_320c = rn.middle - 127; + printk (BIOS_SPEW, "3val: %d, %d: %d\n", channel, slotrank, + ctrl->timings[channel][slotrank].val_320c); + if (rn.all) + die ("c320c discovery failed"); + } + } + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); + + reprogram_320c(ctrl); +} + +static void +discover_edges_real (ramctr_timing *ctrl, int channel, int slotrank, int *edges) +{ + int edge; + int statistics[NUM_LANES][MAX_EDGE_TIMING + 1]; + int lane; + + for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) { + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].rising = edge; + ctrl->timings[channel][slotrank].lanes[lane].falling = edge; + } + printk (BIOS_SPEW, "edge %02x\n", edge); + program_timings (ctrl, channel); + + FOR_ALL_LANES + { + write32 (DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + 4 * lane, 0); + read32 (DEFAULT_MCHBAR + 0x400 * channel + 4 * lane + 0x4140); + } + + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, (0xc01 | (ctrl->delay1 << 16))); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x360004); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x40411f4); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x1001 | ((ctrl->CAS + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, (0xc01 | (ctrl->delay1 << 16))); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel, (slotrank << 24) | 0x360000); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c (channel); + + FOR_ALL_LANES + { + statistics[lane][edge] = read32 (DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + lane * 4); + printk (BIOS_SPEW, "estat %d, %d, %d, %d %02x\n", channel, slotrank, lane, edge, statistics[lane][edge]); + } + } + FOR_ALL_LANES + { + struct run rn = get_longest_zero_run (statistics[lane], MAX_EDGE_TIMING + 1); + edges[lane] = rn.middle; + if (rn.all) + die ("edge discovery failed"); + printk (BIOS_SPEW, "eval %d, %d, %d, %02x\n", channel, slotrank, lane, edges[lane]); + } +} + +static void +discover_edges (ramctr_timing *ctrl) +{ + int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int channel, slotrank, lane; + u32 r32; + + write32 (DEFAULT_MCHBAR + 0x3400, 0); + + r32 = read32 (DEFAULT_MCHBAR + 0x5030); + write32 (DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay (1); + + write32 (DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay (1); + + FOR_ALL_POPULATED_CHANNELS + { + FOR_ALL_LANES + write32 (DEFAULT_MCHBAR + 4 * lane + 0x400 * channel + 0x4080, 0); + } + + FOR_ALL_POPULATED_CHANNELS + { + fill_pattern0 (ctrl, channel, 0, 0); + write32 (DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + FOR_ALL_LANES + read32 (DEFAULT_MCHBAR + 0x400 * channel + lane * 4 + 0x4140); + + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].falling = 16; + ctrl->timings[channel][slotrank].lanes[lane].rising = 16; + } + + program_timings (ctrl, channel); + + FOR_ALL_POPULATED_RANKS + { + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32 (0x4230 + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + channel * 0x400, (slotrank << 24) | 0x360004); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32 (0x4234 + 0x400 * channel + DEFAULT_MCHBAR, 0x4041003); + write32 (DEFAULT_MCHBAR + 0x4204 + channel * 0x400, (slotrank << 24) | 0); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32 (0x4238 + 0x400 * channel + DEFAULT_MCHBAR, 0x1001 | ((ctrl->CAS + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + channel * 0x400, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32 (0x423c + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + write32 (DEFAULT_MCHBAR + 0x420c + channel * 0x400, (slotrank << 24) | 0x360000); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c (channel); + } + + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].falling = 48; + ctrl->timings[channel][slotrank].lanes[lane].rising = 48; + } + + program_timings (ctrl, channel); + + FOR_ALL_POPULATED_RANKS + { + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32 (0x4230 + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + channel * 0x400, (slotrank << 24) | 0x360004); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32 (0x4234 + 0x400 * channel + DEFAULT_MCHBAR, 0x4041003); + write32 (DEFAULT_MCHBAR + 0x4204 + channel * 0x400, (slotrank << 24) | 0); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32 (0x4238 + 0x400 * channel + DEFAULT_MCHBAR, 0x1001 | ((ctrl->CAS + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + channel * 0x400, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32 (0x423c + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + + write32 (DEFAULT_MCHBAR + 0x420c + channel * 0x400, (slotrank << 24) | 0x360000); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + wait_428c (channel); + } + + FOR_ALL_LANES + { + write32 (DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + lane * 4, + ~read32 (DEFAULT_MCHBAR + 0x4040 + 0x400 * channel + lane * 4) & 0xff); + } + + fill_pattern0 (ctrl, channel, 0, 0xffffffff); + write32 (DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + } + + /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */ + write32 (DEFAULT_MCHBAR + 0x4eb0, 0x300); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + { + discover_edges_real (ctrl, channel, slotrank, falling_edges[channel][slotrank]); + } + + write32 (DEFAULT_MCHBAR + 0x4eb0, 0x200); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + { + discover_edges_real (ctrl, channel, slotrank, rising_edges[channel][slotrank]); + } + + write32 (DEFAULT_MCHBAR + 0x4eb0, 0); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].falling = falling_edges[channel][slotrank][lane]; + ctrl->timings[channel][slotrank].lanes[lane].rising = rising_edges[channel][slotrank][lane]; + } + + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + write32 (0x4080 + 4 * lane + 0x400 * channel + DEFAULT_MCHBAR, 0); + } +} + +static void +discover_edges_write_real (ramctr_timing *ctrl, int channel, int slotrank, int *edges) +{ + int edge; + u32 raw_statistics[MAX_EDGE_TIMING + 1]; + int statistics[MAX_EDGE_TIMING + 1]; + const int reg3000b24[] = {0, 0xc, 0x2c}; + int lane, i; + int lower[NUM_LANES]; + int upper[NUM_LANES]; + + FOR_ALL_LANES + { + lower[lane] = 0; + upper[lane] = MAX_EDGE_TIMING; + } + + for (i = 0; i < 3; i++) { + /* FIXME: trace shows that vendor BIOS also tests with other patterns. + I'm not sure whether it's really needed. + */ + write32 (DEFAULT_MCHBAR + 0x3000 + 0x100 * channel, + reg3000b24[i] << 24); + printk (BIOS_SPEW, "patterned\n"); + printk (BIOS_SPEW, "[%x] = 0x%08x\n(%d, %d)\n",0x3000 + 0x100 * channel, + reg3000b24[i] << 24, channel, slotrank); + for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) { + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].rising = edge; + ctrl->timings[channel][slotrank].lanes[lane].falling = edge; + } + program_timings (ctrl, channel); + + FOR_ALL_LANES + { + write32 (DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + 4 * lane, 0); + read32 (DEFAULT_MCHBAR + 0x400 * channel + 4 * lane + 0x4140); + } + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f006); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x4 | (ctrl->tRCD << 16) + | (max (ctrl->tRRD, + (ctrl->tFAW >> 2) + 1) << 10)); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x240); + + write32 (DEFAULT_MCHBAR + 0x4224 + channel * 0x400, 0x1f201); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x8005020 | ((ctrl->tWTR + ctrl->CWL + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0x242); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x4005020 | (max (ctrl->tRTP, 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0x242); + + write32 (DEFAULT_MCHBAR + 0x422c + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, 0xc01 | (ctrl->tRP << 16)); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel, (slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 0xc0001); + wait_428c (channel); + FOR_ALL_LANES + { + read32 (DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + lane * 4); + } + + raw_statistics[edge] = MCHBAR32 (0x436c + channel * 0x400); + } + FOR_ALL_LANES + { + struct run rn; + for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) + statistics[edge] = !!(raw_statistics[edge] & (1 << lane)); + rn = get_longest_zero_run (statistics, MAX_EDGE_TIMING + 1); + printk (BIOS_SPEW, "edges: %d, %d, %d: 0x%x-0x%x-0x%x, 0x%x-0x%x\n", channel, slotrank, i, + rn.start, rn.middle, rn.end, + rn.start + ctrl->edge_offset[i], + rn.end - ctrl->edge_offset[i]); + lower[lane] = max (rn.start + ctrl->edge_offset[i], lower[lane]); + upper[lane] = min (rn.end - ctrl->edge_offset[i], upper[lane]); + edges[lane] = (lower[lane] + upper[lane]) / 2; + + } + } + + write32 (DEFAULT_MCHBAR + 0x3000, 0); + printk (BIOS_SPEW, "CPA\n"); +} + +static void +discover_edges_write (ramctr_timing *ctrl) +{ + int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int channel, slotrank, lane; + + FOR_ALL_POPULATED_CHANNELS + { + fill_pattern5 (ctrl, channel); + write32 (DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + } + + /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */ + write32 (DEFAULT_MCHBAR + 0x4eb0, 0x300); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + { + discover_edges_write_real (ctrl, channel, slotrank, falling_edges[channel][slotrank]); + } + + write32 (DEFAULT_MCHBAR + 0x4eb0, 0x200); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + { + discover_edges_write_real (ctrl, channel, slotrank, rising_edges[channel][slotrank]); + } + + write32 (DEFAULT_MCHBAR + 0x4eb0, 0); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].falling = falling_edges[channel][slotrank][lane]; + ctrl->timings[channel][slotrank].lanes[lane].rising = rising_edges[channel][slotrank][lane]; + } + + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + write32 (0x4080 + 4 * lane + 0x400 * channel + DEFAULT_MCHBAR, 0); + } +} + +static void +discover_timC_write (ramctr_timing *ctrl) +{ + const u8 rege3c_b24[3] = { 0, 0xf, 0x2f }; + int i; + + int lower[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int upper[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int channel, slotrank, lane; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES + { + lower[channel][slotrank][lane] = 0; + upper[channel][slotrank][lane] = MAX_TIMC; + } + + write32 (DEFAULT_MCHBAR + 0x4ea8, 1); + + for (i = 0; i < 3; i++) + FOR_ALL_POPULATED_CHANNELS + { + write32 ((channel << 8) + DEFAULT_MCHBAR + 0xe3c, + (rege3c_b24[i] << 24) | (read32 ((channel << 8) + DEFAULT_MCHBAR + 0xe3c) & ~0x3f000000)); + udelay (2); + FOR_ALL_POPULATED_RANKS + { + int timC; + u32 raw_statistics[MAX_TIMC + 1]; + int statistics[MAX_TIMC + 1]; + + /* FIXME: trace shows that vendor BIOS also tests with other patterns. + I'm not sure whether it's really needed. + */ + fill_pattern5 (ctrl, channel); + for (timC = 0; timC < MAX_TIMC + 1; timC++) + { + FOR_ALL_LANES + ctrl->timings[channel][slotrank].lanes[lane].timC = timC; + program_timings (ctrl, channel); + wait_428c (channel); + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f006); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, (max ((ctrl->tFAW >> 2) + 1, + ctrl->tRRD) << 10) | (ctrl->tRCD << 16) | 4); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x244); + + write32 (DEFAULT_MCHBAR + 0x4224 + channel * 0x400, 0x1f201); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x80011e0 | ((ctrl->tWTR + ctrl->CWL + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0x242); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x40011e0 | (max (ctrl->tRTP, 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0x242); + + write32 (DEFAULT_MCHBAR + 0x422c + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, 0x1001 | (ctrl->tRP << 16)); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel,(slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + wait_428c (channel); + raw_statistics[timC] = MCHBAR32 (0x436c + channel * 0x400); + printk (BIOS_SPEW, "Cstat %02x %02x\n", timC, raw_statistics[timC]); + } + FOR_ALL_LANES + { + struct run rn; + for (timC = 0; timC <= MAX_TIMC; timC++) + statistics[timC] = !!(raw_statistics[timC] & (1 << lane)); + rn = get_longest_zero_run (statistics, MAX_TIMC + 1); + if (rn.all) + die ("timC write discovery failed"); + printk (BIOS_SPEW, "timC: %d, %d, %d: 0x%x-0x%x-0x%x, 0x%x-0x%x\n", channel, slotrank, i, + rn.start, rn.middle, rn.end, + rn.start + ctrl->timC_offset[i], + rn.end - ctrl->timC_offset[i]); + lower[channel][slotrank][lane] = max (rn.start + ctrl->timC_offset[i], + lower[channel][slotrank][lane]); + upper[channel][slotrank][lane] = min (rn.end - ctrl->timC_offset[i], + upper[channel][slotrank][lane]); + + } + } + } + + write32 ((channel << 8) + DEFAULT_MCHBAR + 0xe3c, + 0 | (read32 ((channel << 8) + DEFAULT_MCHBAR + 0xe3c) & ~0x3f000000)); + udelay (2); + + write32 (DEFAULT_MCHBAR + 0x4ea8, 0); + + printk (BIOS_SPEW, "CPB\n"); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + printk (BIOS_SPEW, "timC [%d, %d, %d] = 0x%x\n", channel, slotrank, lane, + (lower[channel][slotrank][lane] + upper[channel][slotrank][lane]) / 2); + ctrl->timings[channel][slotrank].lanes[lane].timC = + (lower[channel][slotrank][lane] + upper[channel][slotrank][lane]) / 2; + } + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); +} + +static void +normalize_training (ramctr_timing *ctrl) +{ + int channel, slotrank, lane; + int mat = 0; + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + { + int delta; + FOR_ALL_LANES + mat = max (ctrl->timings[channel][slotrank].lanes[lane].timA, mat); + delta = (mat >> 6) - ctrl->timings[channel][slotrank].val_4028; + ctrl->timings[channel][slotrank].val_4024 += delta; + ctrl->timings[channel][slotrank].val_4028 += delta; + } + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); +} + + +static void +write_controller_mr(ramctr_timing *ctrl) +{ + int channel, slotrank; + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + { + write32 (DEFAULT_MCHBAR | 0x0004 | (channel << 8) | lane_registers[slotrank], make_mr0 (ctrl, slotrank)); + write32 (DEFAULT_MCHBAR | 0x0008 | (channel << 8) | lane_registers[slotrank], make_mr1 (ctrl, slotrank)); + } +} + +static void +channel_test(ramctr_timing *ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_POPULATED_CHANNELS + if (read32 (DEFAULT_MCHBAR | 0x42a0 | (channel << 10)) & 0xa000) + die ("Mini channel test failed (1)\n"); + FOR_ALL_POPULATED_CHANNELS + { + fill_pattern0 (ctrl, channel, 0x12345678, 0x98765432); + + write32 (DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + } + + for (slotrank = 0; slotrank < 4; slotrank++) + FOR_ALL_CHANNELS + if ((ctrl->rankmap[channel][0] | ctrl->rankmap[channel][1]) & (1 << slotrank)) + { + FOR_ALL_LANES + { + write32 (DEFAULT_MCHBAR | (0x4f40 + 4 * lane), 0); + write32 (DEFAULT_MCHBAR | (0x4d40 + 4 * lane), 0); + } + wait_428c (channel); + write32 (DEFAULT_MCHBAR | 0x4220 | (channel << 10), 0x0001f006); + write32 (DEFAULT_MCHBAR | 0x4230 | (channel << 10), 0x0028a004); + write32 (DEFAULT_MCHBAR | 0x4200 | (channel << 10), + 0x00060000 | (slotrank << 24)); + write32 (DEFAULT_MCHBAR | 0x4210 | (channel << 10), 0x00000244); + write32 (DEFAULT_MCHBAR | 0x4224 | (channel << 10), 0x0001f201); + write32 (DEFAULT_MCHBAR | 0x4234 | (channel << 10), 0x08281064); + write32 (DEFAULT_MCHBAR | 0x4204 | (channel << 10), + 0x00000000 | (slotrank << 24)); + write32 (DEFAULT_MCHBAR | 0x4214 | (channel << 10), 0x00000242); + write32 (DEFAULT_MCHBAR | 0x4228 | (channel << 10), 0x0001f105); + write32 (DEFAULT_MCHBAR | 0x4238 | (channel << 10), 0x04281064); + write32 (DEFAULT_MCHBAR | 0x4208 | (channel << 10), + 0x00000000 | (slotrank << 24)); + write32 (DEFAULT_MCHBAR | 0x4218 | (channel << 10), 0x00000242); + write32 (DEFAULT_MCHBAR | 0x422c | (channel << 10), 0x0001f002); + write32 (DEFAULT_MCHBAR | 0x423c | (channel << 10), 0x00280c01); + write32 (DEFAULT_MCHBAR | 0x420c | (channel << 10), + 0x00060400 | (slotrank << 24)); + write32 (DEFAULT_MCHBAR | 0x421c | (channel << 10), 0x00000240); + write32 (DEFAULT_MCHBAR | 0x4284 | (channel << 10), 0x000c0001); + wait_428c (channel); + FOR_ALL_LANES + if (read32 (DEFAULT_MCHBAR | 0x4340 | (channel << 10))) + die ("Mini channel test failed (2)\n"); + } +} + +static void +set_scrambling_seed (ramctr_timing *ctrl) +{ + int channel; + + /* FIXME: we hardcode seeds. Do we need to use some PRNG for them? + I don't think so. */ + static u32 seeds[2][3] = { + { 0x00009a36, 0xbafcfdcf, 0x46d1ab68}, + { 0x00028bfa, 0x53fe4b49, 0x19ed5483} + }; + FOR_ALL_POPULATED_CHANNELS + { + MCHBAR32(0x4020 + channel * 0x400) &= ~0x10000000; + write32 (DEFAULT_MCHBAR | 0x4034, seeds[channel][0]); + write32 (DEFAULT_MCHBAR | 0x403c, seeds[channel][1]); + write32 (DEFAULT_MCHBAR | 0x4038, seeds[channel][2]); + } +} + +static void +set_4f8c (void) +{ + struct cpuid_result cpures; + u32 cpu; + + cpures = cpuid(0); + cpu = (cpures.eax); + if (IS_SANDY_CPU(cpu) && (IS_SANDY_CPU_D0(cpu) || IS_SANDY_CPU_D1(cpu))) { + MCHBAR32(0x4f8c) = 0x141D1519; + } else { + MCHBAR32(0x4f8c) = 0x551D1519; + } +} + +static void +prepare_training (ramctr_timing *ctrl) +{ + int channel; + + FOR_ALL_POPULATED_CHANNELS { + // Always drive command bus + MCHBAR32(0x4004 + 0x400 * channel) |= 0x20000000; + } + + udelay (1); + + FOR_ALL_POPULATED_CHANNELS + wait_428c (channel); +} + +static void +hardcode1 (ramctr_timing *ctrl) +{ + int channel; + FOR_ALL_POPULATED_CHANNELS { + read32 (DEFAULT_MCHBAR | 0x400c | (channel << 10)); // !!! = 0x000258b4 + write32 (DEFAULT_MCHBAR | 0x400c | (channel << 10), 0x000058b4); // FIXME: hardcoded + write32 (DEFAULT_MCHBAR | 0x4008 | (channel << 10), 0x0a042220); // FIXME: hardcoded + } +} + +static void +set_42a0 (ramctr_timing *ctrl) +{ + int channel; + FOR_ALL_POPULATED_CHANNELS { + write32 (DEFAULT_MCHBAR | (0x42a0 + 0x400 * channel), 0x00001000 | ctrl->rankmap[channel][0] | (ctrl->rankmap[channel][1] << 2)); + MCHBAR32(0x4004 + 0x400 * channel) &= ~0x20000000; // OK + } +} + +void init_dram_ddr3(spd_raw_data *spds, int mobile) +{ + int me_uma_size; + + /* FIXME: hardcoded. */ + write32 (DEFAULT_MCHBAR | 0x5f00, 0x0000270f); + + report_platform_info(); + + /* Wait for ME to be ready */ + intel_early_me_init(); + me_uma_size = intel_early_me_uma_size(); + + printk(BIOS_DEBUG, "Starting native Platform init\n"); + + pch_init (); + + u32 reg_5d10; + + wait_txt_clear (); + + wrmsr (0x000002e6, (msr_t) { .lo = 0, .hi = 0 }); + + reg_5d10 = read32 (DEFAULT_MCHBAR | 0x5d10); // !!! = 0x00000000 + if ((pcie_read_config16 (SOUTHBRIDGE, 0xa2) & 0xa0) == 0x20 /* 0x0004 */ + && reg_5d10) { + /* Need reset. */ + outb (0x6, 0xcf9); + + while (1); + } + + ramctr_timing ctrl; + + dimm_info info; + + ctrl.mobile = mobile; + + /* Get DDR3 SPD data */ + dram_find_spds_ddr3(spds, &info, &ctrl); + + /* Find fastest common supported parameters */ + dram_find_common_params(&info, &ctrl); + + /* Calculate timings */ + dram_timing(&ctrl); + + /* Set MCU frequency */ + dram_freq(&ctrl); + + /* Set version register */ + MCHBAR32(0x5034) = 0xC04EB002; + + /* Enable crossover */ + dram_xover(&ctrl); + + /* Set timing and refresh registers */ + dram_timing_regs(&ctrl); + + /* Power mode preset */ + MCHBAR32(0x4e80) = 0x5500; + + /* Set scheduler parameters */ + MCHBAR32(0x4c20) = 0x10100005; + + /* Set cpu specific register */ + set_4f8c (); + + /* Clear IO reset bit */ + MCHBAR32(0x5030) &= ~0x20; + + /* FIXME: Fix dimm map - Set MAD-DIMM registers */ + dram_dimm_mapping(&info, &ctrl); + printk(BIOS_DEBUG, "Done dimm mapping\n"); + + /* Zone config */ + dram_zones(&info, &ctrl, 1); + + /* Set memory map */ + dram_memorymap(&info, me_uma_size); + printk(BIOS_DEBUG, "Done memory map\n"); + + /* Set IO registers */ + dram_ioregs(&ctrl); + printk(BIOS_DEBUG, "Done io registers\n"); + + udelay (1); + + /* Do jedec ddr3 reset sequence */ + dram_jedecreset(&ctrl); + printk(BIOS_DEBUG, "Done jedec reset\n"); + + /* MRS commands */ + dram_mrscommands(&ctrl); + printk(BIOS_DEBUG, "Done MRS commands\n"); + dram_mrscommands(&ctrl); + + /* Prepare for memory training */ + prepare_training(&ctrl); + + read_training (&ctrl); + write_training (&ctrl); + + printk (BIOS_SPEW, "CP5a\n"); + + discover_edges (&ctrl); + + printk (BIOS_SPEW, "CP5b\n"); + + command_training(&ctrl); + + printk (BIOS_SPEW, "CP5c\n"); + + discover_edges_write(&ctrl); + + discover_timC_write(&ctrl); + + normalize_training (&ctrl); + + hardcode1 (&ctrl); + + write_controller_mr(&ctrl); + + channel_test(&ctrl); + + write32 (DEFAULT_MCHBAR | 0x5024, 0x00a030ce);// FIXME: hardcoded + + set_scrambling_seed(&ctrl); + + set_42a0 (&ctrl); + + write32 (DEFAULT_MCHBAR | 0x4cd4, 0x00000046); // FIXME: hardcoded + + write32 (DEFAULT_MCHBAR | 0x400c, (read32 (DEFAULT_MCHBAR | 0x400c) & 0xFFFFCFFF) | 0x1000); // OK + write32 (DEFAULT_MCHBAR | 0x440c, (read32 (DEFAULT_MCHBAR | 0x440c) & 0xFFFFCFFF) | 0x1000); // OK + write32 (DEFAULT_MCHBAR | 0x4cb0, 0x00000740); // FIXME: hardcoded + write32 (DEFAULT_MCHBAR | 0x4380, 0x00000aaa); // OK + write32 (DEFAULT_MCHBAR | 0x4780, 0x00000aaa); // OK + write32 (DEFAULT_MCHBAR | 0x4f88, 0x5f7003ff); // OK + write32 (DEFAULT_MCHBAR | 0x5064, 0x00073193); // FIXME: hardcoded + write32 (DEFAULT_MCHBAR | 0x4384, 0x009b6ea1);// FIXME: hardcoded + write32 (DEFAULT_MCHBAR | 0x4784, 0x009b6ea1);// FIXME: hardcoded + write32 (DEFAULT_MCHBAR | 0x5880, 0xca9171e5);// FIXME: hardcoded + read32 (DEFAULT_MCHBAR | 0x5888); // !!! = 0x00e4d5d0 + write32 (DEFAULT_MCHBAR | 0x5888, 0x00e4d5d0);// FIXME: hardcoded + read32 (DEFAULT_MCHBAR | 0x58a8); // !!! = 0x00000000 + write32 (DEFAULT_MCHBAR | 0x58a8, 0x00000000);// FIXME: hardcoded + read32 (DEFAULT_MCHBAR | 0x4294); // !!! = 0x000098ff + write32 (DEFAULT_MCHBAR | 0x4294, 0x000198ff);// FIXME: hardcoded + read32 (DEFAULT_MCHBAR | 0x4694); // !!! = 0x000098ff + write32 (DEFAULT_MCHBAR | 0x4694, 0x000198ff);// FIXME: hardcoded + + MCHBAR32 (0x5030) |= 1; // OK + MCHBAR32 (0x5030) |= 0x80; // OK + MCHBAR32 (0x5f18) = 0xfa; // OK + read32 (DEFAULT_MCHBAR | 0x5d10); // !!! = 0x00000000 + write32 (DEFAULT_MCHBAR | 0x5d10, 0x2010040c); // FIXME: hardcoded + + /* Zone config */ + dram_zones(&info, &ctrl, 0); + +#if CONFIG_USBDEBUG_IN_ROMSTAGE + /* mrc.bin reconfigures USB, so reinit it to have debug */ + usbdebug_init(); +#endif + + /* FIXME: uncomment this once dram_memorymap is fixed. */ +// intel_early_me_init_done(ME_INIT_STATUS_SUCCESS); - post_system_agent_init(pei_data); + post_system_agent_init(); report_memory_config(); } diff --git a/src/northbridge/intel/sandybridge/raminit.h b/src/northbridge/intel/sandybridge/raminit.h index c3b1c2a..7e0b10e 100644 --- a/src/northbridge/intel/sandybridge/raminit.h +++ b/src/northbridge/intel/sandybridge/raminit.h @@ -20,17 +20,11 @@ #ifndef RAMINIT_H #define RAMINIT_H -#include "pei_data.h" +#include <device/dram/ddr3.h> -struct sys_info { - u8 boot_path; -#define BOOT_PATH_NORMAL 0 -#define BOOT_PATH_RESET 1 -#define BOOT_PATH_RESUME 2 -} __attribute__ ((packed)); - -void sdram_initialize(struct pei_data *pei_data); -void save_mrc_data(struct pei_data *pei_data); -int fixup_sandybridge_errata(void); +/* The order is ch0dimmA, ch0dimmB, ch1dimmA, ch1dimmB. */ +void init_dram_ddr3(spd_raw_data *spds, int mobile); +void pch_init(void); +void read_spd(spd_raw_data *spd, u8 addr); #endif /* RAMINIT_H */
1 0
0 0
New patch to review for coreboot: d758a87 CIMx: Use the new PCI IRQ functions
by Mike Loptien May 27, 2014

May 27, 2014
Mike Loptien (mike.loptien(a)se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5879 -gerrit commit d758a87831a22728b3129ba64dda72598186ef72 Author: Mike Loptien <mike.loptien(a)se-eng.com> Date: Fri Feb 7 11:20:33 2014 -0700 CIMx: Use the new PCI IRQ functions The PCI IRQ functions in pci_device.c should be used to find the IRQ routing information for the PCI devices. These are generic functions that search for the PCI interrupt information and returns all of the information needed to correctly program the PCI Configuration space registers with the correct IRQ values. Change-Id: I9f44514bbba149f72cfea5aa57f2d10633dd45bf Signed-off-by: Mike Loptien <mike.loptien(a)se-eng.com> Reviewed-on: http://gerrit/3293 Reviewed-by: Marc Jones <marc.jones(a)se-eng.com> Tested-by: Automated Builds <automated.builds(a)se-eng.com> --- src/southbridge/amd/cimx/cimx_util.c | 106 +++++++++++++++++++++++------------ 1 file changed, 69 insertions(+), 37 deletions(-) diff --git a/src/southbridge/amd/cimx/cimx_util.c b/src/southbridge/amd/cimx/cimx_util.c index bf8fbfd..8fb7d43 100644 --- a/src/southbridge/amd/cimx/cimx_util.c +++ b/src/southbridge/amd/cimx/cimx_util.c @@ -46,6 +46,7 @@ const char * intr_types[] = { #endif const struct pirq_struct * pirq_data_ptr = NULL; +u32 pirq_data_size = 0; const u8 * intr_data_ptr = NULL; const u8 * picr_data_ptr = NULL; @@ -114,11 +115,15 @@ void write_pci_int_table (void) */ void write_pci_cfg_irqs(void) { - device_t dev; + device_t dev = NULL; /* Our current device to route IRQs to */ + device_t target_dev = NULL; /* The bridge that a device may be connected to */ int int_pin = 0; /* Value of the INT_PIN register 0x3D */ + int target_pin = 0; /* Pin we will search our tables for */ int int_line = 0; /* IRQ number read from PCI_INTR table and programmed to INT_LINE reg 0x3C */ - int c00_idx = 0; /* Index into PCI_INTR table, 0xC00/0xC01 */ + int pci_intr_idx = 0; /* Index into PCI_INTR table, 0xC00/0xC01 */ + int bus = 0; /* A PCI Device Bus number */ int devfn = 0; /* A PCI Device and Function number */ + int bridged_device = 0; /* This device is on a PCI bridge */ int i = 0; if (pirq_data_ptr == NULL) { @@ -129,65 +134,92 @@ void write_pci_cfg_irqs(void) /* Populate the PCI cfg space header with the IRQ assignment */ printk(BIOS_DEBUG, "PCI_CFG IRQ: Write PCI config space IRQ assignments\n"); + for (dev = all_devices; dev; dev = dev->next) { - devfn = dev->path.pci.devfn; + /* + * Step 1: Get the INT_PIN and device structure to look for in the + * PCI_INTR table pirq_data + */ + target_dev = NULL; + target_pin = get_irq_pins(dev, &target_dev); + if (target_dev == NULL) + continue; - if (!(dev->enabled)) - continue; /* Skip disabled devices */ + if (target_pin < 1) + continue; - /* Get the INT_PIN that this dev uses */ + /* Get the original INT_PIN for record keeping */ int_pin = pci_read_config8(dev, PCI_INTERRUPT_PIN); if (int_pin < 1 || int_pin > 4) - continue; /* Device has INT_PIN = 0 so we do not need to set up an IRQ for it */ + continue; /* Device has invalid INT_PIN so we do not need to set up an IRQ for it */ - printk(BIOS_SPEW, "PCI_CFG IRQ: Found dev %01x:%02xh.%02xh\n", - dev->bus->secondary, PCI_SLOT(devfn), PCI_FUNC(devfn)); + bus = target_dev->bus->secondary; + devfn = target_dev->path.pci.devfn; - /* Find the index into the PCI_INTR table for this device */ - i = 0; - c00_idx = 0xFF; /* Will check to make sure it changed */ - while ((pirq_data_ptr[i].devfn != 0xFF) || (pirq_data_ptr[i].PIN[0] != 0xFF)) { - if (pirq_data_ptr[i].devfn != devfn) { - i++; + /* + * Step 2: Use the INT_PIN and DevFn number to find the PCI_INTR + * register (0xC00) index for this device + */ + pci_intr_idx = 0xBAD; /* Will check to make sure it changed */ + for (i = 0; i <= pirq_data_size - 1; i++) { + if (pirq_data_ptr[i].devfn != devfn) continue; - } - c00_idx = pirq_data_ptr[i].PIN[int_pin - 1]; /* PIN_A is index 0 in pirq_data array but 1 in PCI cfg reg */ - break; /* Found our device, stop looping */ + + /* PIN_A is index 0 in pirq_data array but 1 in PCI cfg reg */ + pci_intr_idx = pirq_data_ptr[i].PIN[target_pin - 1]; + printk(BIOS_SPEW, "\tFound this device in pirq_data table entry %d\n", i); + break; } - /* Make sure we got a valid index */ - if (c00_idx == 0xFF) { + /* + * Step 3: Make sure we got a valid index and use it to get + * the IRQ number from the PCI_INTR register table + */ + if (pci_intr_idx == 0xBAD) { /* Not on a bridge or in pirq_data table, skip it */ printk(BIOS_SPEW, "PCI Devfn (0x%x) not found in pirq_data table\n", devfn); continue; - } else if (c00_idx == 0x1F) { + } else if (pci_intr_idx == 0x1F) { /* Index found is not defined */ printk(BIOS_SPEW, "Got index 0x1F (Not Connected), perhaps this device was defined wrong?\n"); continue; + } else if (pci_intr_idx > FCH_INT_TABLE_SIZE) { /* Index out of bounds */ + printk(BIOS_ERR, "%s: got 0xC00/0xC01 table index 0x%x, max is 0x%x\n", + __func__, pci_intr_idx, FCH_INT_TABLE_SIZE); + continue; } - /* Program the INT_LINE register (0x3C) in PCI config space */ - int_line = read_pci_int_idx(c00_idx, 0); /* Get the IRQ associated with this INT_PIN */ - if (int_line == IRQ_DIS) { + /* Find the value to program into the INT_LINE register from the PCI_INTR registers */ + int_line = read_pci_int_idx(pci_intr_idx, 0); + if (int_line == PIRQ_NC) { /* The IRQ found is not disabled */ printk(BIOS_SPEW, "Got IRQ 0x1F (disabled), perhaps this device was defined wrong?\n"); continue; - } else if ((1 << int_line) & IRQ_RES) { + } else if ((1 << int_line) & IRQ_RES) { /* Found an IRQ that is reserved */ printk(BIOS_WARNING, "WARNING: PCI IRQ %d is reserved, check the mainboard_picr_data table\n" - "Skipping write of PCI config space\n", int_line); + "Skip writing it to PCI config space to prevent instability\n", int_line); continue; } - pci_write_config8(dev, PCI_INTERRUPT_LINE, int_line); /* Set INT_LINE reg with value from PCI_INTR table */ - /* Set this IRQ to level triggered since it is used by PCI devices */ + /* + * Step 4: Program the INT_LINE register in this device's + * PCI config space with the IRQ number we found in step 3 + * and make it Level Triggered + */ + pci_write_config8(dev, PCI_INTERRUPT_LINE, int_line); + + /* Set this IRQ to level triggered since it is used by a PCI device */ i8259_configure_irq_trigger(int_line, IRQ_LEVEL_TRIGGERED); - printk(BIOS_SPEW, "\tINT_PIN\t\t: %d (%s)\n", int_pin, - (int_pin == 1) ? "PIN A": - (int_pin == 2) ? "PIN B": - (int_pin == 3) ? "PIN C": - (int_pin == 4) ? "PIN D" : "Unknown INT_PIN!"); - printk(BIOS_SPEW, "\tINT_LINE\t: 0x%x (IRQ %d)\n" - "\tPCI_INTR idx\t: 0x%02x (%s)\n", - int_line, int_line, c00_idx, intr_types[c00_idx]); - } + /* + * Step 5: Print out debug info and move on to next device + */ + printk(BIOS_SPEW, "\tOrig INT_PIN\t: %d (%s)\n", + int_pin, pin_to_str(int_pin)); + if (bridged_device) + printk(BIOS_SPEW, "\tSwizzled to\t: %d (%s)\n", + target_pin, pin_to_str(target_pin)); + printk(BIOS_SPEW, "\tPCI_INTR idx\t: 0x%02x (%s)\n" + "\tINT_LINE\t: 0x%X (IRQ %d)\n", + pci_intr_idx, intr_types[pci_intr_idx], int_line, int_line); + } /* for (dev = all_devices) */ printk(BIOS_DEBUG, "PCI_CFG IRQ: Finished writing PCI config space IRQ assignments\n"); } #endif /* __PRE_RAM__ */
1 0
0 0
New patch to review for coreboot: 3325bdf CIMx: Set up the PCI IRQ routing
by Mike Loptien May 27, 2014

May 27, 2014
Mike Loptien (mike.loptien(a)se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5877 -gerrit commit 3325bdf5e64a3f95da2961a074999736a31edb2a Author: Mike Loptien <mike.loptien(a)se-eng.com> Date: Mon Jan 20 17:57:39 2014 -0700 CIMx: Set up the PCI IRQ routing The PCI_INTR table is an Index/Data pair of I/O ports 0xC00 and 0xC01. This table is responsible for physically routing IRQs to the PIC and IOAPIC. The settings given in this table are chipset and mainboard dependent, so the table values will reside in the mainboard.c file. This allows for a system to uniquely set its IRQ routing. The function to write the PCI_INTR table resides in cimx_util.c because the indices into the table have the same definitions for all SBx00 FCH chipsets. The next piece is a function that will read the PCI_INTR table and program the INT_LINE and INT_PIN registers in PCI config space appropriately. This function will read a devices' INT_PIN register, which is always hardcoded to a value if it uses hardware interrupts. It then uses this value, along with the device and function numbers to determine an index into the PCI_INTR table. It will read the table and program the corresponding value into the PCI config space register 0x3C, INT_LINE. Finally, it will set this IRQ number to LEVEL_TRIGGERED on the PIC because it is a PCI device interrupt and the must be level triggered. For example, the SB800 USB EHCI device 0:18.2 has an INT_PIN value hardcoded to 2. This corresponds to PIN B. On the Persimmon mainboard, I want the USB device to use IRQ 11. I will program the PCI_INTR table at index 0x31 (this USB device index) to 11. This function will then read the INT_PIN register, read the PCI_INTR table, and then program the INT_LINE register with the value it read. It will then set the IRQ on the PIC to LEVEL_TRIGGERED by writing a 1 to I/O port 0x4D1 at bit position 4. Also, the SB700 has slightly different register definitions than the newer SB800 and SB900 so it needs its own set of #defines for the pci_intr registers. Change-Id: I6de858289a17fa1e1abacf6328ea5099be74b1d6 Signed-off-by: Mike Loptien <mike.loptien(a)se-eng.com> Reviewed-on: http://gerrit/3027 Reviewed-by: Marc Jones <marc.jones(a)se-eng.com> Tested-by: Automated Builds <automated.builds(a)se-eng.com> --- src/include/pc80/i8259.h | 67 +++++++++- src/mainboard/amd/persimmon/mainboard.c | 93 +++++++++++++- src/mainboard/amd/persimmon/mptable.c | 149 +++++++++++----------- src/northbridge/amd/agesa/family14/pci_devs.h | 55 ++++++++ src/southbridge/amd/cimx/cimx_util.c | 173 ++++++++++++++++++++++++++ src/southbridge/amd/cimx/cimx_util.h | 111 ++++++++++++++++- src/southbridge/amd/cimx/sb800/late.c | 68 ++++++---- src/southbridge/amd/cimx/sb800/pci_devs.h | 106 ++++++++++++++++ 8 files changed, 720 insertions(+), 102 deletions(-) diff --git a/src/include/pc80/i8259.h b/src/include/pc80/i8259.h index 7e99e4b..5a32b29 100644 --- a/src/include/pc80/i8259.h +++ b/src/include/pc80/i8259.h @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2007-2009 coresystems GmbH + * 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 @@ -20,10 +21,74 @@ #ifndef PC80_I8259_H #define PC80_I8259_H -void setup_i8259(void); +/* + * IRQ numbers and common usage + * If an IRQ does not say it is 'Reserved' + * then it can be used by a device. + */ +/* PIC IRQs */ +#define IRQ_DIS 0x1F /* IRQ is disabled */ +#define IRQ_0 0x00 /* Reserved - Timer IRQ */ +#define IRQ_1 0x01 /* Keyboard controller */ +#define IRQ_2 0x02 /* Reserved - Cascade to Slave PIC */ +#define IRQ_3 0x03 /* Serial Port 2 & 4 */ +#define IRQ_4 0x04 /* Serial Port 1 & 3 */ +#define IRQ_5 0x05 /* Parallel Port 2 & 3 or Sound Card */ +#define IRQ_6 0x06 /* Floppy Disk Controller */ +#define IRQ_7 0x07 /* Parallel Port 1 */ +#define IRQ_8 0x08 /* Reserved - RTC */ +#define IRQ_9 0x09 /* Reserved - ACPI System Control Interrupt */ +#define IRQ_10 0x0A /* Free or SCSI or NIC */ +#define IRQ_11 0x0B /* Free or SCSI or NIC */ +#define IRQ_12 0x0C /* PS/2 Mouse */ +#define IRQ_13 0x0D /* Reserved - CPU Floating Point Unit */ +#define IRQ_14 0x0E /* Primary ATA */ +#define IRQ_15 0x0F /* Secondary ATA */ +#define IRQ_RES ((1 << IRQ_0) | (1 << IRQ_1) | (1 << IRQ_2) \ + | (1 << IRQ_8) | (1 << IRQ_9) | (1 << IRQ_13)) + +#define MASTER_PIC_ICW1 0x20 +#define SLAVE_PIC_ICW1 0xa0 +#define ICW_SELECT (1 << 4) +#define OCW_SELECT (0 << 4) +#define ADI (1 << 2) +#define SNGL (1 << 1) +#define IC4 (1 << 0) + +#define MASTER_PIC_ICW2 0x21 +#define SLAVE_PIC_ICW2 0xa1 +#define INT_VECTOR_MASTER 0x20 +#define IRQ0 0x00 +#define IRQ1 0x01 +#define INT_VECTOR_SLAVE 0x28 +#define IRQ8 0x00 +#define IRQ9 0x01 + +#define MASTER_PIC_ICW3 0x21 +#define CASCADED_PIC (1 << 2) + +#define MASTER_PIC_ICW4 0x21 +#define SLAVE_PIC_ICW4 0xa1 +#define MICROPROCESSOR_MODE (1 << 0) + +#define SLAVE_PIC_ICW3 0xa1 +#define SLAVE_ID 0x02 + +#define MASTER_PIC_OCW1 0x21 +#define SLAVE_PIC_OCW1 0xa1 +#define IRQ2 (1 << 2) +#define ALL_IRQS 0xff + +#define ELCR1 0x4d0 +#define ELCR2 0x4d1 #define IRQ_LEVEL_TRIGGERED 1 #define IRQ_EDGE_TRIGGERED 0 + +u16 pic_read_irq_mask(void); +void pic_write_irq_mask(u16 mask); +void pic_irq_enable(u8 int_num, u8 mask); +void setup_i8259(void); void i8259_configure_irq_trigger(int int_num, int is_level_triggered); #endif /* PC80_I8259_H */ diff --git a/src/mainboard/amd/persimmon/mainboard.c b/src/mainboard/amd/persimmon/mainboard.c index b17bc6a..566eb84 100644 --- a/src/mainboard/amd/persimmon/mainboard.c +++ b/src/mainboard/amd/persimmon/mainboard.c @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2011 Advanced Micro Devices, 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 @@ -23,16 +24,101 @@ #include <arch/io.h> #include <cpu/x86/msr.h> #include <device/pci_def.h> -#include <southbridge/amd/sb800/sb800.h> +#include <southbridge/amd/cimx/cimx_util.h> #include <arch/acpi.h> #include "BiosCallOuts.h" #include <cpu/amd/agesa/s3_resume.h> #include <cpu/amd/mtrr.h> #include "SBPLATFORM.h" +#include <southbridge/amd/cimx/sb800/pci_devs.h> +#include <northbridge/amd/agesa/family14/pci_devs.h> void set_pcie_reset(void); void set_pcie_dereset(void); +/*********************************************************** + * These arrays set up the FCH PCI_INTR registers 0xC00/0xC01. + * This table is responsible for physically routing the PIC and + * IOAPIC IRQs to the different PCI devices on the system. It + * is read and written via registers 0xC00/0xC01 as an + * Index/Data pair. These values are chipset and mainboard + * dependent and should be updated accordingly. + * + * These values are used by the PCI configuration space, + * MP Tables. TODO: Make ACPI use these values too. + * + * The Persimmon PCI INTA/B/C/D pins are connected to + * FCH pins INTE/F/G/H on the schematic so these need + * to be routed as well. + */ +u8 mainboard_picr_data[FCH_INT_TABLE_SIZE] = { + [0x00] = 0x0A,0x0B,0x0A,0x0B,0x0A,0x0B,0x0A,0x0B, /* INTA# - INTH# */ + [0x08] = 0x00,0xF0,0x00,0x00,0x1F,0x1F,0x1F,0x1F, /* Misc-nil,0,1,2, INT from Serial irq */ + [0x10] = 0x1F,0x1F,0x1F,0x0A,0x1F,0x1F,0x1F, /* SCI, SMBUS0, ASF, HDA, FC, GEC, PerMon */ + [0x20] = 0x1F,0x1F,0x1F,0x1F,0x1F,0x1F, /* IMC INT0 - 5 */ + [0x30] = 0x0A,0x0B,0x0A,0x0B,0x1F,0x1F,0x0A, /* USB Devs 18/19/20/22 INTA-C */ + [0x40] = 0x0B,0x0B, /* IDE, SATA */ + [0x50] = 0x0A,0x0B,0x0A,0x0B /* GPPInt0 - 3 */ +}; + +u8 mainboard_intr_data[FCH_INT_TABLE_SIZE] = { + [0x00] = 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, /* INTA# - INTH# */ + [0x08] = 0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F,0x1F, /* Misc-nil,0,1,2, INT from Serial irq */ + [0x10] = 0x09,0x1F,0x1F,0x10,0x1F,0x12,0x1F, /* SCI, SMBUS0, ASF, HDA, FC, GEC, PerMon */ + [0x20] = 0x1F,0x1F,0x1F,0x1F,0x1F,0x1F, /* IMC INT0 - 5 */ + [0x30] = 0x12,0x11,0x12,0x11,0x12,0x11,0x12, /* USB Devs 18/19/22/20 INTA-C */ + [0x40] = 0x11,0x13, /* IDE, SATA */ + [0x50] = 0x10,0x11,0x12,0x13 /* GPPInt0 - 3 */ +}; + +/* + * This table defines the index into the picr/intr_data + * tables for each device. Any enabled device and slot + * that uses hardware interrupts should have an entry + * in this table to define its index into the FCH + * PCI_INTR register 0xC00/0xC01. This index will define + * the interrupt that it should use. Putting PIRQ_A into + * the PIN A index for a device will tell that device to + * use PIC IRQ 11 if it uses PIN A for its hardware INT. + */ +/* + * Persimmon has PCI/PCIe slot INT_PINA/B/C/D connected to + * PIRQE/F/G/H so PIN A on off-chip devices should get + * mapped to PIRQE, etc. + */ +static const struct pirq_struct mainboard_pirq_data[] = { + /* {PCI dev, fn PCI INT {PIN A, PIN B, PIN C, PIN D}}, */ + {GFX_DEVFN, {PIRQ_A, PIRQ_B, PIRQ_NC, PIRQ_NC}}, /* VGA: 01.0 */ + {NB_PCIE_PORT1_DEVFN, {PIRQ_E, PIRQ_F, PIRQ_G, PIRQ_H}}, /* NIC: 04.0 */ + {NB_PCIE_PORT3_DEVFN, {PIRQ_E, PIRQ_F, PIRQ_G, PIRQ_H}}, /* PCIe bdg:06.0 */ + {SATA_DEVFN, {PIRQ_SATA, PIRQ_NC, PIRQ_NC, PIRQ_NC}}, /* SATA: 11.0 */ + {OHCI1_DEVFN, {PIRQ_OHCI1, PIRQ_NC, PIRQ_NC, PIRQ_NC}}, /* OHCI1: 18.0 */ + {EHCI1_DEVFN, {PIRQ_NC, PIRQ_EHCI1, PIRQ_NC, PIRQ_NC}}, /* EHCI1: 18.2 */ + {OHCI2_DEVFN, {PIRQ_OHCI2, PIRQ_NC, PIRQ_NC, PIRQ_NC}}, /* OHCI2: 19.0 */ + {EHCI2_DEVFN, {PIRQ_NC, PIRQ_EHCI2, PIRQ_NC, PIRQ_NC}}, /* EHCI2: 19.2 */ + {SMBUS_DEVFN, {PIRQ_SMBUS, PIRQ_NC, PIRQ_NC, PIRQ_NC}}, /* SMBUS: 20.0 */ + {IDE_DEVFN, {PIRQ_NC, PIRQ_IDE, PIRQ_NC, PIRQ_NC}}, /* IDE: 20.1 */ + {HDA_DEVFN, {PIRQ_HDA, PIRQ_NC, PIRQ_NC, PIRQ_NC}}, /* HDA: 20.2 */ + {SB_PCI_PORT_DEVFN, {PIRQ_E, PIRQ_F, PIRQ_G, PIRQ_H}}, /* PCI bdg: 20.4 */ + {OHCI4_DEVFN, {PIRQ_NC, PIRQ_NC, PIRQ_OHCI4, PIRQ_NC}}, /* OHCI4: 20.5 */ + {OHCI3_DEVFN, {PIRQ_OHCI3, PIRQ_NC, PIRQ_NC, PIRQ_NC}}, /* OHCI3: 22.0 */ + {EHCI3_DEVFN, {PIRQ_NC, PIRQ_EHCI3, PIRQ_NC, PIRQ_NC}}, /* EHCI3: 22.2 */ + {0xFF, {0xFF, 0xFF, 0xFF, 0xFF}}, /* End of the array */ +}; + +/* PIRQ Setup */ + +extern const struct pirq_struct * pirq_data_ptr; +extern u8 * intr_data_ptr; +extern u8 * picr_data_ptr; + +static void pirq_setup(void) +{ + pirq_data_ptr = mainboard_pirq_data; + intr_data_ptr = mainboard_intr_data; + picr_data_ptr = mainboard_picr_data; +} + /** * TODO * SB CIMx callback @@ -59,7 +145,7 @@ static void mainboard_enable(device_t dev) /* * The mainboard is the first place that we get control in ramstage. Check - * for S3 resume and call the approriate AGESA/CIMx resume functions. + * for S3 resume and call the appropriate AGESA/CIMx resume functions. */ #if CONFIG_HAVE_ACPI_RESUME acpi_slp_type = acpi_get_sleep_type(); @@ -82,6 +168,9 @@ static void mainboard_enable(device_t dev) */ pm_iowrite(0x29, 0x80); pm_iowrite(0x28, 0x61); + + /* Initialize the PIRQ data structures for consumption */ + pirq_setup(); } struct chip_operations mainboard_ops = { diff --git a/src/mainboard/amd/persimmon/mptable.c b/src/mainboard/amd/persimmon/mptable.c index 6b8aaa6..aacf50a 100644 --- a/src/mainboard/amd/persimmon/mptable.c +++ b/src/mainboard/amd/persimmon/mptable.c @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2011 Advanced Micro Devices, 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 @@ -26,124 +27,122 @@ #include <stdint.h> #include <cpu/amd/amdfam14.h> #include <SBPLATFORM.h> +#include <southbridge/amd/cimx/cimx_util.h> +#include <drivers/generic/ioapic/chip.h> +#define IO_APIC_ID (CONFIG_MAX_CPUS + 1) extern u8 bus_sb800[6]; - extern u32 apicid_sb800; +extern u8 * intr_data_ptr; extern u32 bus_type[256]; extern u32 sbdn_sb800; -u8 intr_data[] = { - [0x00] = 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, /* INTA# - INTH# */ - [0x08] = 0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F,0x1F, /* Misc-nil,0,1,2, INT from Serial irq */ - [0x10] = 0x09,0x1F,0x1F,0x10,0x1F,0x12,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x12,0x11,0x12,0x11,0x12,0x11,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x11,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x10,0x11,0x12,0x13 -}; - static void *smp_write_config_table(void *v) { struct mp_config_table *mc; int bus_isa; - + u32 dword; + /* Intialize the MP_Table */ mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN); mptable_init(mc, LOCAL_APIC_ADDR); - memcpy(mc->mpc_oem, "AMD ", 8); + /* + * Type 0: Processor Entries: + * LAPIC ID, LAPIC Version, CPU Flags:EN/BP, + * CPU Signature (Stepping, Model, Family), + * Feature Flags + */ smp_write_processors(mc); + /* Get Bus Configuration */ get_bus_conf(); + /* + * Type 1: Bus Entries: + * Bus ID, Bus Type + */ mptable_write_buses(mc, NULL, &bus_isa); - /* I/O APICs: APIC ID Version State Address */ - - u32 dword; - u8 byte; - - ReadPMIO(SB_PMIOA_REG34, AccWidthUint32, &dword); - dword &= 0xFFFFFFF0; + /* + * Type 2: I/O APICs: + * APIC ID, Version, APIC Flags:EN, Address + */ + dword = 0; + dword = pm_ioread(0x34) & 0xF0; + dword |= (pm_ioread(0x35) & 0xFF) << 8; + dword |= (pm_ioread(0x36) & 0xFF) << 16; + dword |= (pm_ioread(0x37) & 0xFF) << 24; + /* Set IO APIC ID onto IO_APIC_ID */ + write32 (dword, 0x00); + write32 (dword + 0x10, IO_APIC_ID << 24); + apicid_sb800 = IO_APIC_ID; smp_write_ioapic(mc, apicid_sb800, 0x21, dword); - for (byte = 0x0; byte < sizeof(intr_data); byte ++) { - outb(byte | 0x80, 0xC00); - outb(intr_data[byte], 0xC01); - } - - /* I/O Ints: Type Polarity Trigger Bus ID IRQ APIC ID PIN# */ -#define IO_LOCAL_INT(type, intr, apicid, pin) \ - smp_write_lintsrc(mc, (type), MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, bus_isa, (intr), (apicid), (pin)); - + /* + * Type 3: I/O Interrupt Table Entries: + * Int Type, Int Polarity, Int Level, Source Bus ID, + * Source Bus IRQ, Dest APIC ID, Dest PIN# + */ mptable_add_isa_interrupts(mc, bus_isa, apicid_sb800, 0); /* PCI interrupts are level triggered, and are * associated with a specific bus/device/function tuple. */ -#if !CONFIG_GENERATE_ACPI_TABLES #define PCI_INT(bus, dev, fn, pin) \ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(fn)), apicid_sb800, (pin)) -#else -#define PCI_INT(bus, dev, fn, pin) -#endif - /* APU Internal Graphic Device*/ - PCI_INT(0x0, 0x01, 0x0, intr_data[0x02]); - PCI_INT(0x0, 0x01, 0x1, intr_data[0x03]); + /* APU Internal Graphic Device */ + PCI_INT(0x0, 0x01, 0x0, intr_data_ptr[PIRQ_C]); + PCI_INT(0x0, 0x01, 0x1, intr_data_ptr[PIRQ_D]); + + /* SMBUS / ACPI */ + PCI_INT(0x0, 0x14, 0x0, intr_data_ptr[PIRQ_SMBUS]); - //PCI_INT(0x0, 0x14, 0x1, 0x11); /* IDE. */ - PCI_INT(0x0, 0x14, 0x0, 0x10); - /* Southbridge HD Audio: */ - PCI_INT(0x0, 0x14, 0x2, 0x12); + /* Southbridge HD Audio */ + PCI_INT(0x0, 0x14, 0x2, intr_data_ptr[PIRQ_HDA]); - PCI_INT(0x0, 0x12, 0x0, intr_data[0x30]); /* USB */ - PCI_INT(0x0, 0x12, 0x1, intr_data[0x31]); - PCI_INT(0x0, 0x13, 0x0, intr_data[0x32]); - PCI_INT(0x0, 0x13, 0x1, intr_data[0x33]); - PCI_INT(0x0, 0x16, 0x0, intr_data[0x34]); - PCI_INT(0x0, 0x16, 0x1, intr_data[0x35]); + /* LPC */ + PCI_INT(0x0, 0x14, 0x3, intr_data_ptr[PIRQ_C]); - /* sata */ - PCI_INT(0x0, 0x11, 0x0, intr_data[0x41]); + /* USB */ + PCI_INT(0x0, 0x12, 0x0, intr_data_ptr[PIRQ_OHCI1]); + PCI_INT(0x0, 0x12, 0x2, intr_data_ptr[PIRQ_EHCI1]); + PCI_INT(0x0, 0x13, 0x0, intr_data_ptr[PIRQ_OHCI2]); + PCI_INT(0x0, 0x13, 0x2, intr_data_ptr[PIRQ_EHCI2]); + PCI_INT(0x0, 0x14, 0x5, intr_data_ptr[PIRQ_OHCI4]); - /* on board NIC & Slot PCIE. */ + /* IDE */ + PCI_INT(0x0, 0x14, 0x1, intr_data_ptr[PIRQ_IDE]); + + /* SATA */ + PCI_INT(0x0, 0x11, 0x0, intr_data_ptr[PIRQ_SATA]); + + /* on board NIC & Slot PCIE */ + PCI_INT(0x1, 0x0, 0x0, intr_data_ptr[PIRQ_E]); /* Use INTE */ + PCI_INT(0x2, 0x0, 0x0, intr_data_ptr[PIRQ_E]); /* Use INTE */ /* PCI slots */ - /* PCI_SLOT 0. */ - PCI_INT(bus_sb800[1], 0x5, 0x0, 0x14); - PCI_INT(bus_sb800[1], 0x5, 0x1, 0x15); - PCI_INT(bus_sb800[1], 0x5, 0x2, 0x16); - PCI_INT(bus_sb800[1], 0x5, 0x3, 0x17); - - /* PCI_SLOT 1. */ - PCI_INT(bus_sb800[1], 0x6, 0x0, 0x15); - PCI_INT(bus_sb800[1], 0x6, 0x1, 0x16); - PCI_INT(bus_sb800[1], 0x6, 0x2, 0x17); - PCI_INT(bus_sb800[1], 0x6, 0x3, 0x14); - - /* PCI_SLOT 2. */ - PCI_INT(bus_sb800[1], 0x7, 0x0, 0x16); - PCI_INT(bus_sb800[1], 0x7, 0x1, 0x17); - PCI_INT(bus_sb800[1], 0x7, 0x2, 0x14); - PCI_INT(bus_sb800[1], 0x7, 0x3, 0x15); - - PCI_INT(bus_sb800[2], 0x0, 0x0, 0x12); - PCI_INT(bus_sb800[2], 0x0, 0x1, 0x13); - PCI_INT(bus_sb800[2], 0x0, 0x2, 0x14); + /* PCI_SLOT 0 */ + PCI_INT(bus_sb800[1], 0x5, 0x0, intr_data_ptr[PIRQ_E]); /* INTA -> INTE */ + PCI_INT(bus_sb800[1], 0x5, 0x1, intr_data_ptr[PIRQ_F]); /* INTB -> INTF */ + PCI_INT(bus_sb800[1], 0x5, 0x2, intr_data_ptr[PIRQ_G]); /* INTC -> INTG */ + PCI_INT(bus_sb800[1], 0x5, 0x3, intr_data_ptr[PIRQ_H]); /* INTD -> INTH */ /* PCIe PortA */ - PCI_INT(0x0, 0x15, 0x0, 0x10); + PCI_INT(0x0, 0x15, 0x0, intr_data_ptr[PIRQ_E]); /* INTA -> INTE */ /* PCIe PortB */ - PCI_INT(0x0, 0x15, 0x1, 0x11); + PCI_INT(0x0, 0x15, 0x1, intr_data_ptr[PIRQ_F]); /* INTB -> INTF */ /* PCIe PortC */ - PCI_INT(0x0, 0x15, 0x2, 0x12); + PCI_INT(0x0, 0x15, 0x2, intr_data_ptr[PIRQ_G]); /* INTC -> INTG */ /* PCIe PortD */ - PCI_INT(0x0, 0x15, 0x3, 0x13); + PCI_INT(0x0, 0x15, 0x3, intr_data_ptr[PIRQ_H]); /* INTD -> INTH */ /*Local Ints: Type Polarity Trigger Bus ID IRQ APIC ID PIN# */ +#define IO_LOCAL_INT(type, intr, apicid, pin) \ + smp_write_lintsrc(mc, (type), MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, bus_isa, (intr), (apicid), (pin)); + IO_LOCAL_INT(mp_ExtINT, 0x0, MP_APIC_ALL, 0x0); IO_LOCAL_INT(mp_NMI, 0x0, MP_APIC_ALL, 0x1); /* There is no extension information... */ @@ -155,6 +154,6 @@ static void *smp_write_config_table(void *v) unsigned long write_smp_table(unsigned long addr) { void *v; - v = smp_write_floating_table(addr, 0); + v = smp_write_floating_table(addr, 0); /* ADDR, Enable Virtual Wire */ return (unsigned long)smp_write_config_table(v); } diff --git a/src/northbridge/amd/agesa/family14/pci_devs.h b/src/northbridge/amd/agesa/family14/pci_devs.h new file mode 100644 index 0000000..c257d3d --- /dev/null +++ b/src/northbridge/amd/agesa/family14/pci_devs.h @@ -0,0 +1,55 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2014 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 _AMD_FAM14_PCI_DEVS_H_ +#define _AMD_FAM14_PCI_DEVS_H_ + +#define BUS0 0 + +/* Graphics and Display */ +#define GFX_DEV 0x1 +#define GFX_FUNC 0 +# define GFX_DEVFN PCI_DEVFN(GFX_DEV,GFX_FUNC) + +/* PCI Ports */ +#define PCI_PORT_DEV 0x14 +#define PCI_PORT_FUNC 4 +# define PCI_PORT_DEVID 0x4384 +# define PCI_PORT_DEVFN PCI_DEVFN(PCI_PORT_DEV,PCI_PORT_FUNC) + +/* PCIe Ports */ +#define NB_PCIE_PORT1_DEV 0x4 +#define NB_PCIE_PORT2_DEV 0x5 +#define NB_PCIE_PORT3_DEV 0x6 +#define NB_PCIE_PORT4_DEV 0x7 +#define NB_PCIE_PORT5_DEV 0x8 +#define NB_PCIE_FUNC 0 +# define NB_PCIE_PORT1_DEVID 0x1512 +# define NB_PCIE_PORT2_DEVID 0x1513 +# define NB_PCIE_PORT3_DEVID 0x1514 +# define NB_PCIE_PORT4_DEVID 0x1515 +# define NB_PCIE_PORT5_DEVID 0x1516 +# define NB_PCIE_PORT1_DEVFN PCI_DEVFN(NB_PCIE_PORT1_DEV,NB_PCIE_FUNC) +# define NB_PCIE_PORT2_DEVFN PCI_DEVFN(NB_PCIE_PORT2_DEV,NB_PCIE_FUNC) +# define NB_PCIE_PORT3_DEVFN PCI_DEVFN(NB_PCIE_PORT3_DEV,NB_PCIE_FUNC) +# define NB_PCIE_PORT4_DEVFN PCI_DEVFN(NB_PCIE_PORT4_DEV,NB_PCIE_FUNC) +# define NB_PCIE_PORT5_DEVFN PCI_DEVFN(NB_PCIE_PORT5_DEV,NB_PCIE_FUNC) + +#endif /* _AMD_FAM14_PCI_DEVS_H_ */ diff --git a/src/southbridge/amd/cimx/cimx_util.c b/src/southbridge/amd/cimx/cimx_util.c index a3c6ad7..bf8fbfd 100644 --- a/src/southbridge/amd/cimx/cimx_util.c +++ b/src/southbridge/amd/cimx/cimx_util.c @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2010 Advanced Micro Devices, Inc. + * Copyright (C) 2014 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 @@ -16,8 +17,180 @@ * 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 <device/pci.h> #include <arch/io.h> +#include <string.h> #include "cimx_util.h" +#include <pc80/i8259.h> + +#ifndef __PRE_RAM__ +#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_CIMX_SB800) || \ + IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_CIMX_SB900) +const char * intr_types[] = { + [0x00] = "INTA#\t", "INTB#\t", "INTC#\t", "INTD#\t", "INTE#\t", "INTF#\t", "INTG#\t", "INTH#\t", + [0x08] = "Misc\t", "Misc0\t", "Misc1\t", "Misc2\t", "Ser IRQ INTA", "Ser IRQ INTB", "Ser IRQ INTC", "Ser IRQ INTD", + [0x10] = "SCI\t", "SMBUS0\t", "ASF\t", "HDA\t", "FC\t\t", "GEC\t", "PerMon\t", + [0x20] = "IMC INT0\t", "IMC INT1\t", "IMC INT2\t", "IMC INT3\t", "IMC INT4\t", "IMC INT5\t", + [0x30] = "Dev18.0 INTA", "Dev18.2 INTB", "Dev19.0 INTA", "Dev19.2 INTB", "Dev22.0 INTA", "Dev22.2 INTB", "Dev20.5 INTC", + [0x40] = "IDE\t", "SATA\t", + [0x50] = "GPPInt0\t", "GPPInt1\t", "GPPInt2\t", "GPPInt3\t" +}; +#elif IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_CIMX_SB700) +const char * intr_types[] = { + [0x00] = "INTA#\t", "INTB#\t", "INTC#\t", "INTD#\t", + [0x04] = "ACPI\t", "SMBUS\t", "RSVD\t", "RSVD\t", "RSVD\t", + [0x09] = "INTE#\t", "INTF#\t", "INTG#\t", "INTH#\t", +}; +#endif + +const struct pirq_struct * pirq_data_ptr = NULL; +const u8 * intr_data_ptr = NULL; +const u8 * picr_data_ptr = NULL; + +/* + * Read the FCH PCI_INTR registers 0xC00/0xC01 at a + * given index and a given PIC (0) or IOAPIC (1) mode + */ +u8 read_pci_int_idx(u8 index, int mode) +{ + outb((mode << 7) | index, PCI_INTR_INDEX); + return inb(PCI_INTR_DATA); +} + +/* + * Write a value to the FCH PCI_INTR registers 0xC00/0xC01 + * at a given index and PIC (0) or IOAPIC (1) mode + */ +void write_pci_int_idx(u8 index, int mode, u8 data) +{ + outb((mode << 7) | index, PCI_INTR_INDEX); + outb(data, PCI_INTR_DATA); +} + +/* + * Write the FCH PCI_INTR registers 0xC00/0xC01 with values + * given in global variables intr_data and picr_data. + * These variables are defined in mainboard.c + */ +void write_pci_int_table (void) +{ + u8 byte; + + if(picr_data_ptr == NULL || intr_data_ptr == NULL){ + printk(BIOS_ERR, "Warning: Can't write PCI_INTR 0xC00/0xC01 registers because\n" + "'mainboard_picr_data' or 'mainboard_intr_data' tables are NULL\n"); + return; + } + + /* PIC IRQ routine */ + printk(BIOS_DEBUG, "PCI_INTR tables: Writing registers C00/C01 for PIC mode PCI IRQ routing:\n" + "\tPCI_INTR_INDEX\t\tPCI_INTR_DATA\n"); + for (byte = 0; byte < FCH_INT_TABLE_SIZE; byte++) { + if (intr_types[byte]) { + write_pci_int_idx(byte, 0, (u8) picr_data_ptr[byte]); + printk(BIOS_DEBUG, "\t0x%02X %s\t: 0x%02X\n", + byte, intr_types[byte], read_pci_int_idx(byte, 0)); + } + } + + /* APIC IRQ routine */ + printk(BIOS_DEBUG, "PCI_INTR tables: Writing registers C00/C01 for APIC mode PCI IRQ routing:\n" + "\tPCI_INTR_INDEX\t\tPCI_INTR_DATA\n"); + for (byte = 0; byte < FCH_INT_TABLE_SIZE; byte++) { + if (intr_types[byte]) { + write_pci_int_idx(byte, 1, (u8) intr_data_ptr[byte]); + printk(BIOS_DEBUG, "\t0x%02X %s\t: 0x%02X\n", + byte, intr_types[byte], read_pci_int_idx(byte, 1)); + } + } +} + +/* + * Function to write the PCI config space Interrupt + * registers based on the values given in PCI_INTR + * table at I/O port 0xC00/0xC01 + */ +void write_pci_cfg_irqs(void) +{ + device_t dev; + int int_pin = 0; /* Value of the INT_PIN register 0x3D */ + int int_line = 0; /* IRQ number read from PCI_INTR table and programmed to INT_LINE reg 0x3C */ + int c00_idx = 0; /* Index into PCI_INTR table, 0xC00/0xC01 */ + int devfn = 0; /* A PCI Device and Function number */ + int i = 0; + + if (pirq_data_ptr == NULL) { + printk(BIOS_WARNING, "Warning: Can't write PCI IRQ assignments because" + " 'mainboard_pirq_data' structure does not exist\n"); + return; + } + + /* Populate the PCI cfg space header with the IRQ assignment */ + printk(BIOS_DEBUG, "PCI_CFG IRQ: Write PCI config space IRQ assignments\n"); + for (dev = all_devices; dev; dev = dev->next) { + devfn = dev->path.pci.devfn; + + if (!(dev->enabled)) + continue; /* Skip disabled devices */ + + /* Get the INT_PIN that this dev uses */ + int_pin = pci_read_config8(dev, PCI_INTERRUPT_PIN); + if (int_pin < 1 || int_pin > 4) + continue; /* Device has INT_PIN = 0 so we do not need to set up an IRQ for it */ + + printk(BIOS_SPEW, "PCI_CFG IRQ: Found dev %01x:%02xh.%02xh\n", + dev->bus->secondary, PCI_SLOT(devfn), PCI_FUNC(devfn)); + + /* Find the index into the PCI_INTR table for this device */ + i = 0; + c00_idx = 0xFF; /* Will check to make sure it changed */ + while ((pirq_data_ptr[i].devfn != 0xFF) || (pirq_data_ptr[i].PIN[0] != 0xFF)) { + if (pirq_data_ptr[i].devfn != devfn) { + i++; + continue; + } + c00_idx = pirq_data_ptr[i].PIN[int_pin - 1]; /* PIN_A is index 0 in pirq_data array but 1 in PCI cfg reg */ + break; /* Found our device, stop looping */ + } + + /* Make sure we got a valid index */ + if (c00_idx == 0xFF) { + printk(BIOS_SPEW, "PCI Devfn (0x%x) not found in pirq_data table\n", devfn); + continue; + } else if (c00_idx == 0x1F) { + printk(BIOS_SPEW, "Got index 0x1F (Not Connected), perhaps this device was defined wrong?\n"); + continue; + } + + /* Program the INT_LINE register (0x3C) in PCI config space */ + int_line = read_pci_int_idx(c00_idx, 0); /* Get the IRQ associated with this INT_PIN */ + if (int_line == IRQ_DIS) { + printk(BIOS_SPEW, "Got IRQ 0x1F (disabled), perhaps this device was defined wrong?\n"); + continue; + } else if ((1 << int_line) & IRQ_RES) { + printk(BIOS_WARNING, "WARNING: PCI IRQ %d is reserved, check the mainboard_picr_data table\n" + "Skipping write of PCI config space\n", int_line); + continue; + } + pci_write_config8(dev, PCI_INTERRUPT_LINE, int_line); /* Set INT_LINE reg with value from PCI_INTR table */ + + /* Set this IRQ to level triggered since it is used by PCI devices */ + i8259_configure_irq_trigger(int_line, IRQ_LEVEL_TRIGGERED); + + printk(BIOS_SPEW, "\tINT_PIN\t\t: %d (%s)\n", int_pin, + (int_pin == 1) ? "PIN A": + (int_pin == 2) ? "PIN B": + (int_pin == 3) ? "PIN C": + (int_pin == 4) ? "PIN D" : "Unknown INT_PIN!"); + printk(BIOS_SPEW, "\tINT_LINE\t: 0x%x (IRQ %d)\n" + "\tPCI_INTR idx\t: 0x%02x (%s)\n", + int_line, int_line, c00_idx, intr_types[c00_idx]); + } + printk(BIOS_DEBUG, "PCI_CFG IRQ: Finished writing PCI config space IRQ assignments\n"); +} +#endif /* __PRE_RAM__ */ static void pmio_write_index(u16 port_base, u8 reg, u8 value) { diff --git a/src/southbridge/amd/cimx/cimx_util.h b/src/southbridge/amd/cimx/cimx_util.h index 1e806ba..0f53497 100644 --- a/src/southbridge/amd/cimx/cimx_util.h +++ b/src/southbridge/amd/cimx/cimx_util.h @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2010 Advanced Micro Devices, Inc. + * Copyright (C) 2014 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 @@ -22,15 +23,123 @@ #include <stdint.h> -/* Power management index/data registers */ +/* + * PIRQ and device routing - these define the index + * into the FCH PCI_INTR 0xC00/0xC01 interrupt + * routing table + */ +#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_CIMX_SB800) || \ + IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_CIMX_SB900) +#define FCH_INT_TABLE_SIZE 0x54 +#define PIRQ_NC 0x1F /* Not Used */ +#define PIRQ_A 0x00 /* INT A */ +#define PIRQ_B 0x01 /* INT B */ +#define PIRQ_C 0x02 /* INT C */ +#define PIRQ_D 0x03 /* INT D */ +#define PIRQ_E 0x04 /* INT E */ +#define PIRQ_F 0x05 /* INT F */ +#define PIRQ_G 0x06 /* INT G */ +#define PIRQ_H 0x07 /* INT H */ +#define PIRQ_MISC 0x08 /* Miscellaneous IRQ Settings - See FCH Spec */ +#define PIRQ_MISC0 0x09 /* Miscellaneous0 IRQ Settings */ +#define PIRQ_MISC1 0x0A /* Miscellaneous1 IRQ Settings */ +#define PIRQ_MISC2 0x0B /* Miscellaneous2 IRQ Settings */ +#define PIRQ_SIRQA 0x0C /* Serial IRQ INTA */ +#define PIRQ_SIRQB 0x0D /* Serial IRQ INTA */ +#define PIRQ_SIRQC 0x0E /* Serial IRQ INTA */ +#define PIRQ_SIRQD 0x0F /* Serial IRQ INTA */ +#define PIRQ_SCI 0x10 /* SCI IRQ */ +#define PIRQ_SMBUS 0x11 /* SMBUS 14h.0 */ +#define PIRQ_ASF 0x12 /* ASF */ +#define PIRQ_HDA 0x13 /* HDA 14h.2 */ +#define PIRQ_FC 0x14 /* FC */ +#define PIRQ_GEC 0x15 /* GEC */ +#define PIRQ_PMON 0x16 /* Performance Monitor */ +#define PIRQ_IMC0 0x20 /* IMC INT0 */ +#define PIRQ_IMC1 0x21 /* IMC INT1 */ +#define PIRQ_IMC2 0x22 /* IMC INT2 */ +#define PIRQ_IMC3 0x23 /* IMC INT3 */ +#define PIRQ_IMC4 0x24 /* IMC INT4 */ +#define PIRQ_IMC5 0x25 /* IMC INT5 */ +#define PIRQ_OHCI1 0x30 /* USB OHCI 12h.0 */ +#define PIRQ_EHCI1 0x31 /* USB EHCI 12h.2 */ +#define PIRQ_OHCI2 0x32 /* USB OHCI 13h.0 */ +#define PIRQ_EHCI2 0x33 /* USB EHCI 13h.2 */ +#define PIRQ_OHCI3 0x34 /* USB OHCI 16h.0 */ +#define PIRQ_EHCI3 0x35 /* USB EHCI 16h.2 */ +#define PIRQ_OHCI4 0x36 /* USB OHCI 14h.5 */ +#define PIRQ_IDE 0x40 /* IDE 14h.1 */ +#define PIRQ_SATA 0x41 /* SATA 11h.0 */ +#define PIRQ_GPP0 0x50 /* GPP INT 0 */ +#define PIRQ_GPP1 0x51 /* GPP INT 1 */ +#define PIRQ_GPP2 0x52 /* GPP INT 2 */ +#define PIRQ_GPP3 0x53 /* GPP INT 3 */ +#elif IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_CIMX_SB700) +#define FCH_INT_TABLE_SIZE 0xD +#define PIRQ_NC 0x1F /* Not Used */ +#define PIRQ_A 0x00 /* INT A */ +#define PIRQ_B 0x01 /* INT B */ +#define PIRQ_C 0x02 /* INT C */ +#define PIRQ_D 0x03 /* INT D */ +#define PIRQ_ACPI 0x04 /* ACPI */ +#define PIRQ_SMBUS 0x05 /* SMBUS */ +/* Index 6, 7, 8 are all reserved */ +#define PIRQ_E 0x09 /* INT E */ +#define PIRQ_F 0x0A /* INT F */ +#define PIRQ_G 0x0B /* INT G */ +#define PIRQ_H 0x0C /* INT H */ +#endif + +/* + * IRQ numbers and common usage + * If an IRQ does not say it is 'Reserved' + * then it can be used by a device. + */ +/* PIC IRQs */ +#define IRQ_DIS 0x1F /* IRQ is disabled */ +#define IRQ_0 0x00 /* Reserved - Timer IRQ */ +#define IRQ_1 0x01 /* Keyboard controller */ +#define IRQ_2 0x02 /* Reserved - Cascade to Slave PIC */ +#define IRQ_3 0x03 /* Serial Port 2 & 4 */ +#define IRQ_4 0x04 /* Serial Port 1 & 3 */ +#define IRQ_5 0x05 /* Parallel Port 2 & 3 or Sound Card */ +#define IRQ_6 0x06 /* Floppy Disk Controller */ +#define IRQ_7 0x07 /* Parallel Port 1 */ +#define IRQ_8 0x08 /* Reserved - RTC */ +#define IRQ_9 0x09 /* Reserved - ACPI System Control Interrupt */ +#define IRQ_10 0x0A /* Free or SCSI or NIC */ +#define IRQ_11 0x0B /* Free or SCSI or NIC */ +#define IRQ_12 0x0C /* PS/2 Mouse */ +#define IRQ_13 0x0D /* Reserved - CPU Floating Point Unit */ +#define IRQ_14 0x0E /* Primary ATA */ +#define IRQ_15 0x0F /* Secondary ATA */ + +/* FCH index/data registers */ #define PM_INDEX 0xcd6 #define PM_DATA 0xcd7 +#define BIOSRAM_INDEX 0xcd4 +#define BIOSRAM_DATA 0xcd5 #define PM2_INDEX 0xcd0 #define PM2_DATA 0xcd1 +#define PCI_INTR_INDEX 0xc00 +#define PCI_INTR_DATA 0xc01 void pm_iowrite(u8 reg, u8 value); u8 pm_ioread(u8 reg); void pm2_iowrite(u8 reg, u8 value); u8 pm2_ioread(u8 reg); +#ifndef __PRE_RAM__ + +struct pirq_struct { +u8 devfn; +u8 PIN[4]; /* PINA/B/C/D are index 0/1/2/3 */ +}; + +u8 read_pci_int_idx(u8 index, int mode); +void write_pci_int_idx(u8 index, int mode, u8 data); +void write_pci_cfg_irqs(void); +void write_pci_int_table (void); +#endif /* __PRE_RAM */ + #endif /* CIMX_UTIL_H */ diff --git a/src/southbridge/amd/cimx/sb800/late.c b/src/southbridge/amd/cimx/sb800/late.c index 40b422b..ecc53af 100644 --- a/src/southbridge/amd/cimx/sb800/late.c +++ b/src/southbridge/amd/cimx/sb800/late.c @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2011 Advanced Micro Devices, 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 @@ -36,6 +37,7 @@ #include "sb_cimx.h" /* AMD CIMX wrapper entries */ #include "smbus.h" #include "fan.h" +#include <southbridge/amd/cimx/cimx_util.h> /*implement in mainboard.c*/ void set_pcie_reset(void); @@ -339,10 +341,10 @@ static void sb800_enable(device_t dev) struct southbridge_amd_cimx_sb800_config *sb_chip = (struct southbridge_amd_cimx_sb800_config *)(dev->chip_info); - printk(BIOS_DEBUG, "sb800_enable() "); - + printk(BIOS_DEBUG, "%s: Enabling ", __func__); switch (dev->path.pci.devfn) { - case (0x11 << 3) | 0: /* 0:11.0 SATA */ + case (0x11 << 3) | 0: /* 0:11h.0 SATA */ + printk(BIOS_DEBUG, "SATA: 0:11h.0\n"); /* the first sb800 device */ switch (GPP_CFGMODE) { /* config the GPP PCIe ports */ case GPP_CFGMODE_X2200: @@ -372,8 +374,16 @@ static void sb800_enable(device_t dev) } break; - case (0x14 << 3) | 0: /* 0:14:0 SMBUS */ - printk(BIOS_INFO, "sm_init().\n"); + case (0x14 << 3) | 0: /* 0:14h:0 SMBUS */ + printk(BIOS_DEBUG, "SMBUS: 0:14h.0\n"); + + /* Write PCI_INTR table */ + write_pci_int_table(); + + /* Now that all the devices are set up, write their IRQs */ + write_pci_cfg_irqs(); + + printk(BIOS_INFO, "sm_init()\n"); clear_ioapic(IO_APIC_ADDR); #if CONFIG_CPU_AMD_AGESA /* Assign the ioapic ID the next available number after the processor core local APIC IDs */ @@ -392,23 +402,25 @@ static void sb800_enable(device_t dev) #endif break; - case (0x14 << 3) | 1: /* 0:14:1 IDE */ + case (0x14 << 3) | 1: /* 0:14h:1 IDE */ + printk(BIOS_DEBUG, "IDE: 0:14h.1\n"); break; - case (0x14 << 3) | 2: /* 0:14:2 HDA */ + case (0x14 << 3) | 2: /* 0:14h:2 HDA */ + printk(BIOS_DEBUG, "HDA: 0:14h.2\n"); if (dev->enabled) { if (AZALIA_DISABLE == sb_config->AzaliaController) { sb_config->AzaliaController = AZALIA_AUTO; } - printk(BIOS_DEBUG, "hda enabled\n"); + printk(BIOS_DEBUG, "\thda enabled\n"); } else { sb_config->AzaliaController = AZALIA_DISABLE; - printk(BIOS_DEBUG, "hda disabled\n"); + printk(BIOS_DEBUG, "\thda disabled\n"); } break; - - case (0x14 << 3) | 3: /* 0:14:3 LPC */ + case (0x14 << 3) | 3: /* 0:14h:3 LPC */ + printk(BIOS_DEBUG, "LPC: 0:14h.3\n"); /* Initialize the fans */ #if CONFIG_SB800_IMC_FAN_CONTROL init_sb800_IMC_fans(dev); @@ -417,20 +429,23 @@ static void sb800_enable(device_t dev) #endif break; - case (0x14 << 3) | 4: /* 0:14:4 PCI */ + case (0x14 << 3) | 4: /* 0:14h:4 PCI */ + printk(BIOS_DEBUG, "PCI Bridge: 0:14h.4\n"); break; - case (0x14 << 3) | 6: /* 0:14:6 GEC */ + case (0x14 << 3) | 6: /* 0:14h:6 GEC */ + printk(BIOS_DEBUG, "GEC: 0:14h.6\n"); if (dev->enabled) { sb_config->GecConfig = 0; - printk(BIOS_DEBUG, "gec enabled\n"); + printk(BIOS_DEBUG, "\tgec enabled\n"); } else { sb_config->GecConfig = 1; - printk(BIOS_DEBUG, "gec disabled\n"); + printk(BIOS_DEBUG, "\tgec disabled\n"); } break; - case (0x15 << 3) | 0: /* 0:15:0 PCIe PortA */ + case (0x15 << 3) | 0: /* 0:15h:0 PCIe PortA */ + printk(BIOS_DEBUG, "PCIe PortA: 0:15h.0\n"); { device_t device; for (device = dev; device; device = device->next) { @@ -449,25 +464,32 @@ static void sb800_enable(device_t dev) } break; - case (0x12 << 3) | 0: /* 0:12:0 OHCI-USB1 */ + case (0x12 << 3) | 0: /* 0:12h:0 OHCI-USB1 */ + printk(BIOS_DEBUG, "USB OHCI1: 0:12h.0\n"); sb_config->USBMODE.UsbMode.Ohci1 = dev->enabled; break; - case (0x12 << 3) | 2: /* 0:12:2 EHCI-USB1 */ + case (0x12 << 3) | 2: /* 0:12h:2 EHCI-USB1 */ + printk(BIOS_DEBUG, "USB EHCI1: 0:12h.2\n"); sb_config->USBMODE.UsbMode.Ehci1 = dev->enabled; break; - case (0x13 << 3) | 0: /* 0:13:0 OHCI-USB2 */ + case (0x13 << 3) | 0: /* 0:13h:0 OHCI-USB2 */ + printk(BIOS_DEBUG, "USB OHCI2: 0:13h.0\n"); sb_config->USBMODE.UsbMode.Ohci2 = dev->enabled; break; - case (0x13 << 3) | 2: /* 0:13:2 EHCI-USB2 */ + case (0x13 << 3) | 2: /* 0:13h:2 EHCI-USB2 */ + printk(BIOS_DEBUG, "USB EHCI2: 0:13.2\n"); sb_config->USBMODE.UsbMode.Ehci2 = dev->enabled; break; - case (0x14 << 3) | 5: /* 0:14:5 OHCI-USB4 */ + case (0x14 << 3) | 5: /* 0:14h:5 OHCI-USB4 */ + printk(BIOS_DEBUG, "USB OHCI4: 0:14h.5\n"); sb_config->USBMODE.UsbMode.Ohci4 = dev->enabled; break; - case (0x16 << 3) | 0: /* 0:16:0 OHCI-USB3 */ + case (0x16 << 3) | 0: /* 0:16h:0 OHCI-USB3 */ + printk(BIOS_DEBUG, "USB OHCI3: 0:16h.0\n"); sb_config->USBMODE.UsbMode.Ohci3 = dev->enabled; break; - case (0x16 << 3) | 2: /* 0:16:2 EHCI-USB3 */ + case (0x16 << 3) | 2: /* 0:16h:2 EHCI-USB3 */ + printk(BIOS_DEBUG, "USB EHCI3: 0:16h.2\n"); sb_config->USBMODE.UsbMode.Ehci3 = dev->enabled; /* call the CIMX entry at the last sb800 device, diff --git a/src/southbridge/amd/cimx/sb800/pci_devs.h b/src/southbridge/amd/cimx/sb800/pci_devs.h new file mode 100644 index 0000000..b0d7521 --- /dev/null +++ b/src/southbridge/amd/cimx/sb800/pci_devs.h @@ -0,0 +1,106 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2014 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 _CIMX_SB00_PCI_DEVS_H_ +#define _CIMX_SB00_PCI_DEVS_H_ + +#define BUS0 0 + +/* SATA */ +#define SATA_DEV 0x11 +#define SATA_FUNC 0 +# define SATA_IDE_DEVID 0x4390 +# define AHCI_DEVID 0x4391 +# define RAID_DEVID 0x4392 +# define RAID5_DEVID 0x4393 +# define SATA_DEVFN PCI_DEVFN(SATA_DEV,SATA_FUNC) + +/* OHCI */ +#define OHCI1_DEV 0x12 +#define OHCI1_FUNC 0 +#define OHCI2_DEV 0x13 +#define OHCI2_FUNC 0 +#define OHCI3_DEV 0x16 +#define OHCI3_FUNC 0 +#define OHCI4_DEV 0x14 +#define OHCI4_FUNC 5 +# define OHCI_DEVID 0x4397 +# define OHCI1_DEVFN PCI_DEVFN(OHCI1_DEV,OHCI1_FUNC) +# define OHCI2_DEVFN PCI_DEVFN(OHCI2_DEV,OHCI2_FUNC) +# define OHCI3_DEVFN PCI_DEVFN(OHCI3_DEV,OHCI3_FUNC) +# define OHCI4_DEVFN PCI_DEVFN(OHCI4_DEV,OHCI4_FUNC) + +/* EHCI */ +#define EHCI1_DEV 0x12 +#define EHCI1_FUNC 2 +#define EHCI2_DEV 0x13 +#define EHCI2_FUNC 2 +#define EHCI3_DEV 0x16 +#define EHCI3_FUNC 2 +# define EHCI_DEVID 0x4396 +# define EHCI1_DEVFN PCI_DEVFN(EHCI1_DEV,EHCI1_FUNC) +# define EHCI2_DEVFN PCI_DEVFN(EHCI2_DEV,EHCI2_FUNC) +# define EHCI3_DEVFN PCI_DEVFN(EHCI3_DEV,EHCI3_FUNC) + +/* IDE */ +#define IDE_DEV 0x14 +#define IDE_FUNC 1 +# define IDE_DEVID 0x439C +# define IDE_DEVFN PCI_DEVFN(IDE_DEV,IDE_FUNC) + +/* HD Audio */ +#define HDA_DEV 0x14 +#define HDA_FUNC 2 +# define HDA_DEVID 0x4383 +# define HDA_DEVFN PCI_DEVFN(HDA_DEV,HDA_FUNC) + +/* PCI Ports */ +#define SB_PCI_PORT_DEV 0x14 +#define SB_PCI_PORT_FUNC 4 +# define SB_PCI_PORT_DEVID 0x4384 +# define SB_PCI_PORT_DEVFN PCI_DEVFN(SB_PCI_PORT_DEV,SB_PCI_PORT_FUNC) + +/* PCIe Ports */ +#define SB_PCIE_DEV 0x15 +#define SB_PCIE_PORT1_FUNC 0 +#define SB_PCIE_PORT2_FUNC 1 +#define SB_PCIE_PORT3_FUNC 2 +#define SB_PCIE_PORT4_FUNC 3 +# define SB_PCIE_PORT1_DEVID 0x43A0 +# define SB_PCIE_PORT2_DEVID 0x43A1 +# define SB_PCIE_PORT3_DEVID 0x43A2 +# define SB_PCIE_PORT4_DEVID 0x43A3 +# define SB_PCIE_PORT1_DEVFN PCI_DEVFN(SB_PCIE_DEV,SB_PCIE_PORT1_FUNC) +# define SB_PCIE_PORT2_DEVFN PCI_DEVFN(SB_PCIE_DEV,SB_PCIE_PORT2_FUNC) +# define SB_PCIE_PORT3_DEVFN PCI_DEVFN(SB_PCIE_DEV,SB_PCIE_PORT3_FUNC) +# define SB_PCIE_PORT4_DEVFN PCI_DEVFN(SB_PCIE_DEV,SB_PCIE_PORT4_FUNC) + +/* Fusion Controller Hub */ +#define PCU_DEV 0x14 +#define LPC_DEV PCU_DEV +#define LPC_FUNC 3 +#define SMBUS_DEV 0x14 +#define SMBUS_FUNC 0 +# define LPC_DEVID 0x439D +# define SMBUS_DEVID 0x4385 +# define LPC_DEVFN PCI_DEVFN(LPC_DEV,LPC_FUNC) +# define SMBUS_DEVFN PCI_DEVFN(SMBUS_DEV,SMBUS_FUNC) + +#endif /* _CIMX_SB800_PCI_DEVS_H_ */
1 0
0 0
New patch to review for coreboot: cce42ec Persimmon: Make MPTable setup use IOAPIC defines
by Mike Loptien May 27, 2014

May 27, 2014
Mike Loptien (mike.loptien(a)se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5878 -gerrit commit cce42eccc2b5d0074e4313e728a2ad8ca4ba9bc8 Author: Mike Loptien <mike.loptien(a)se-eng.com> Date: Tue Jan 7 11:23:42 2014 -0700 Persimmon: Make MPTable setup use IOAPIC defines The IOAPIC is setup before we start writing the system tables. This means that we can just read the IOAPIC registers to get its configuration instead of hardcoding values that may be wrong. Bug 3022 Change-Id: I96ec046a2208eddf4b5e442214ff43d2a349ca4d Signed-off-by: Mike Loptien <mike.loptien(a)se-eng.com> Reviewed-on: http://gerrit/2947 Reviewed-by: Marc Jones <marc.jones(a)se-eng.com> Tested-by: Automated Builds <automated.builds(a)se-eng.com> --- src/mainboard/amd/persimmon/mptable.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/mainboard/amd/persimmon/mptable.c b/src/mainboard/amd/persimmon/mptable.c index aacf50a..a65b8e6 100644 --- a/src/mainboard/amd/persimmon/mptable.c +++ b/src/mainboard/amd/persimmon/mptable.c @@ -29,8 +29,8 @@ #include <SBPLATFORM.h> #include <southbridge/amd/cimx/cimx_util.h> #include <drivers/generic/ioapic/chip.h> +#include <arch/ioapic.h> -#define IO_APIC_ID (CONFIG_MAX_CPUS + 1) extern u8 bus_sb800[6]; extern u32 apicid_sb800; extern u8 * intr_data_ptr; @@ -42,7 +42,8 @@ static void *smp_write_config_table(void *v) { struct mp_config_table *mc; int bus_isa; - u32 dword; + u32 apicver_sb800; + /* Intialize the MP_Table */ mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN); @@ -69,16 +70,10 @@ static void *smp_write_config_table(void *v) * Type 2: I/O APICs: * APIC ID, Version, APIC Flags:EN, Address */ - dword = 0; - dword = pm_ioread(0x34) & 0xF0; - dword |= (pm_ioread(0x35) & 0xFF) << 8; - dword |= (pm_ioread(0x36) & 0xFF) << 16; - dword |= (pm_ioread(0x37) & 0xFF) << 24; - /* Set IO APIC ID onto IO_APIC_ID */ - write32 (dword, 0x00); - write32 (dword + 0x10, IO_APIC_ID << 24); - apicid_sb800 = IO_APIC_ID; - smp_write_ioapic(mc, apicid_sb800, 0x21, dword); + apicid_sb800 = (io_apic_read(IO_APIC_ADDR, 0x00) >> 24); /* Get IOAPIC ID */ + apicver_sb800 = (io_apic_read(IO_APIC_ADDR, 0x01) & 0xFF); /* Get IOAPIC version */ + + smp_write_ioapic(mc, apicid_sb800, apicver_sb800, IO_APIC_ADDR); /* * Type 3: I/O Interrupt Table Entries:
1 0
0 0
Patch merged into coreboot/master: 470c37c util/cbfstool: Use `%zu` instead of `%ld` for size_t arguments
by gerritï¼ coreboot.org May 27, 2014

May 27, 2014
the following patch was just integrated into master: commit 470c37c372b6b6a6961a3b287f609f55c15f6d4c Author: Paul Menzel <paulepanter(a)users.sourceforge.net> Date: Sun Mar 16 00:15:57 2014 +0100 util/cbfstool: Use `%zu` instead of `%ld` for size_t arguments cbfstool fails to built under 32-bit platforms since commit aa2f739a cbfs: fix issues with word size and endianness. due to the use of '%ld' format specifier on size_t, which on these platforms is only 32-bit. No error is seen though, when cbfstool is built, when building a coreboot image, where it is put in `build/cbfstool`. Use the length modifier `z` for size_t arguments, and cast to size_t where appropriate. Change-Id: Id84a20fbf237376a31f7e4816bd139463800c977 Signed-off-by: Paul Menzel <paulepanter(a)users.sourceforge.net> Reviewed-on: http://review.coreboot.org/5388 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin <adurbin(a)gmail.com> See http://review.coreboot.org/5388 for details. -gerrit
1 0
0 0
Patch set updated for coreboot: 7183f4f sandy/ivybridge: Native raminit.
by Vladimir Serbinenko May 27, 2014

May 27, 2014
Vladimir Serbinenko (phcoder(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5786 -gerrit commit 7183f4fbe27474cccd45ec8a06106109e2f443ea Author: Vladimir Serbinenko <phcoder(a)gmail.com> Date: Sun May 18 11:05:56 2014 +0200 sandy/ivybridge: Native raminit. Based on damo22 work and my X230 tracing. Works for my X230 in a variety of RAM configs. Also-By: Damien Zammit <damien(a)zamaudio.com> Change-Id: I1aa024c55a8416fc53b25e7123037df0e55a2769 Signed-off-by: Vladimir Serbinenko <phcoder(a)gmail.com> --- src/device/dram/ddr3.c | 8 +- src/include/device/dram/ddr3.h | 11 +- src/mainboard/lenovo/x230/romstage.c | 72 +- src/northbridge/intel/sandybridge/Makefile.inc | 2 + src/northbridge/intel/sandybridge/pchinit.c | 638 ++++ src/northbridge/intel/sandybridge/raminit.c | 3696 ++++++++++++++++++++++-- src/northbridge/intel/sandybridge/raminit.h | 16 +- 7 files changed, 4193 insertions(+), 250 deletions(-) diff --git a/src/device/dram/ddr3.c b/src/device/dram/ddr3.c index 9b4f490..69782ab 100644 --- a/src/device/dram/ddr3.c +++ b/src/device/dram/ddr3.c @@ -110,7 +110,7 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) { int ret; u16 crc, spd_crc; - u8 ftb_divisor, ftb_dividend, capacity_shift, bus_width, sdram_width; + u8 ftb_divisor, ftb_dividend, capacity_shift, bus_width; u8 reg8; u32 mtb; /* medium time base */ unsigned int val, param; @@ -209,8 +209,8 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) printram(" Invalid SDRAM width\n"); ret = SPD_STATUS_INVALID_FIELD; } - sdram_width = (4 << val); - printram(" SDRAM width : %u\n", sdram_width); + dimm->width = (4 << val); + printram(" SDRAM width : %u\n", dimm->width); /* Memory bus width */ reg8 = spd[8]; @@ -236,7 +236,7 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) * capacity_shift * The rest is the JEDEC formula */ dimm->size_mb = ((1 << (capacity_shift + (25 - 20))) * bus_width - * dimm->ranks) / sdram_width; + * dimm->ranks) / dimm->width; /* Fine Timebase (FTB) Dividend/Divisor */ /* Dividend */ diff --git a/src/include/device/dram/ddr3.h b/src/include/device/dram/ddr3.h index b19c51c..fcaf10b 100644 --- a/src/include/device/dram/ddr3.h +++ b/src/include/device/dram/ddr3.h @@ -37,6 +37,7 @@ * @{ */ #define TCK_1066MHZ 240 +#define TCK_933MHZ 275 #define TCK_800MHZ 320 #define TCK_666MHZ 384 #define TCK_533MHZ 480 @@ -54,11 +55,11 @@ * disabled. * @{ */ -#if defined(CONFIG_DEBUG_RAM_SETUP) && (CONFIG_DEBUG_RAM_SETUP) +//#if defined(CONFIG_DEBUG_RAM_SETUP) && (CONFIG_DEBUG_RAM_SETUP) #define printram(x, ...) printk(BIOS_DEBUG, x, ##__VA_ARGS__) -#else -#define printram(x, ...) -#endif +//#else +//#define printram(x, ...) +//#endif /** @} */ /* @@ -137,6 +138,8 @@ typedef struct dimm_attr_st { u16 cas_supported; /* Flags extracted from SPD */ dimm_flags_t flags; + /* SDRAM width */ + u8 width; /* Number of ranks */ u8 ranks; /* Number or row address bits */ diff --git a/src/mainboard/lenovo/x230/romstage.c b/src/mainboard/lenovo/x230/romstage.c index 6e4e685..dba19b1 100644 --- a/src/mainboard/lenovo/x230/romstage.c +++ b/src/mainboard/lenovo/x230/romstage.c @@ -114,60 +114,13 @@ void main(unsigned long bist) int cbmem_was_initted; u32 pm1_cnt; u16 pm1_sts; + spd_raw_data spd[4]; if (MCHBAR16(SSKPD) == 0xCAFE) { outb(0x6, 0xcf9); hlt (); } - struct pei_data pei_data = { - .pei_version = PEI_VERSION, - .mchbar = DEFAULT_MCHBAR, - .dmibar = DEFAULT_DMIBAR, - .epbar = DEFAULT_EPBAR, - .pciexbar = CONFIG_MMCONF_BASE_ADDRESS, - .smbusbar = SMBUS_IO_BASE, - .wdbbar = 0x4000000, - .wdbsize = 0x1000, - .hpet_address = CONFIG_HPET_ADDRESS, - .rcba = DEFAULT_RCBABASE, - .pmbase = DEFAULT_PMBASE, - .gpiobase = DEFAULT_GPIOBASE, - .thermalbase = 0xfed08000, - .system_type = 0, // 0 Mobile, 1 Desktop/Server - .tseg_size = CONFIG_SMM_TSEG_SIZE, - .spd_addresses = { 0xA0, 0x00,0xA2,0x00 }, - .ts_addresses = { 0x00, 0x00, 0x00, 0x00 }, - .ec_present = 1, - .gbe_enable = 1, - .ddr3lv_support = 0, - // 0 = leave channel enabled - // 1 = disable dimm 0 on channel - // 2 = disable dimm 1 on channel - // 3 = disable dimm 0+1 on channel - .dimm_channel0_disabled = 2, - .dimm_channel1_disabled = 2, - .max_ddr3_freq = 1600, - .usb_port_config = { - /* enabled usb oc pin length */ - { 1, 0, 0x0080 }, /* P0 (left, fan side), OC 0 */ - { 1, 1, 0x0080 }, /* P1 (left touchpad side), OC 1 */ - { 1, 3, 0x0080 }, /* P2: dock, OC 3 */ - { 1, 0, 0x0040 }, /* P3: wwan, no OC */ - { 1, 0, 0x0080 }, /* P4: Wacom tablet on X230t, otherwise empty */ - { 1, 0, 0x0080 }, /* P5: Expresscard, no OC */ - { 0, 0, 0x0000 }, /* P6: Empty */ - { 1, 0, 0x0080 }, /* P7: dock, no OC */ - { 0, 0, 0x0000 }, /* P8: Empty */ - { 1, 5, 0x0080 }, /* P9: Right (EHCI debug), OC 5 */ - { 1, 0, 0x0040 }, /* P10: fingerprint reader, no OC */ - { 1, 0, 0x0040 }, /* P11: bluetooth, no OC. */ - { 1, 0, 0x0040 }, /* P12: wlan, no OC */ - { 1, 0, 0x0080 }, /* P13: webcam, no OC */ - }, - .ddr_refresh_rate_config = 2, /* Force double refresh rate */ - }; - timestamp_init(get_initial_timestamp()); timestamp_add_now(TS_START_ROMSTAGE); @@ -224,24 +177,13 @@ void main(unsigned long bist) post_code(0x39); post_code(0x3a); - pei_data.boot_mode = boot_mode; timestamp_add_now(TS_BEFORE_INITRAM); - /* MRC.bin has a bug and sometimes halts (instead of reboot?). - */ - if (boot_mode != 2) - { - RCBA32(GCS) = RCBA32(GCS) & ~(1 << 5); /* reset */ - outw((0 << 11), DEFAULT_PMBASE | 0x60 | 0x08); /* let timer go */ - } - - sdram_initialize(&pei_data); + memset (spd, 0, sizeof (spd)); + read_spd (&spd[0], 0x50); + read_spd (&spd[2], 0x51); - if (boot_mode != 2) - { - RCBA32(GCS) = RCBA32(GCS) | (1 << 5); /* No reset */ - outw((1 << 11), DEFAULT_PMBASE | 0x60 | 0x08); /* halt timer */ - } + init_dram_ddr3 (spd, 1); timestamp_add_now(TS_AFTER_INITRAM); post_code(0x3c); @@ -254,8 +196,8 @@ void main(unsigned long bist) MCHBAR16(SSKPD) = 0xCAFE; cbmem_was_initted = !cbmem_recovery(boot_mode==2); - if (boot_mode!=2) - save_mrc_data(&pei_data); +// if (boot_mode!=2) +// save_mrc_data(&pei_data); #if CONFIG_HAVE_ACPI_RESUME /* If there is no high memory area, we didn't boot before, so diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index 6655e2a..707a8d0 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -27,6 +27,8 @@ ramstage-y += mrccache.c romstage-y += ram_calc.c romstage-y += raminit.c +romstage-y += pchinit.c +romstage-y += ../../../device/dram/ddr3.c romstage-y += mrccache.c romstage-y += early_init.c romstage-y += report_platform.c diff --git a/src/northbridge/intel/sandybridge/pchinit.c b/src/northbridge/intel/sandybridge/pchinit.c new file mode 100644 index 0000000..e03cfa8 --- /dev/null +++ b/src/northbridge/intel/sandybridge/pchinit.c @@ -0,0 +1,638 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Vladimir Serbinenko <phcoder(a)gmail.com> + * + * 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/hlt.h> +#include <arch/io.h> +#include <cbmem.h> +#include <arch/cbfs.h> +#include <cbfs.h> +#include <ip_checksum.h> +#include <pc80/mc146818rtc.h> +#include <device/pci_def.h> +#include "raminit.h" +#include "pei_data.h" +#include "sandybridge.h" +#include <delay.h> + +/* Management Engine is in the southbridge */ +#include "southbridge/intel/bd82x6x/me.h" +#include "southbridge/intel/bd82x6x/pch.h" +#include <cpu/x86/msr.h> +#include <cpu/cpu.h> +#include "cpu/intel/model_2065x/model_2065x.h" + +#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0) +#define NORTHBRIDGE PCI_DEV(0, 0x0, 0) +#define GFX_DEV PCI_DEV(0, 0x2, 0) + +static int +wait_2338 (void) +{ + int timeout; + + timeout = 1000; + while (1) + { + if (!(read8 (DEFAULT_RCBABASE | 0x2338) & 1)) + return 0; + if (!timeout--) + return -1; + } +} + +static int +read_2338 (u32 edx, u32 * result) +{ + int ret; + + write32 (DEFAULT_RCBABASE | 0x2330, edx); + write16 (DEFAULT_RCBABASE | 0x2338, (read16 (DEFAULT_RCBABASE | 0x2338) + & 0x1ff) | 0x600); + ret = wait_2338 (); + if (ret < 0) + return ret; + *result = read32 (DEFAULT_RCBABASE | 0x2334); // !!! = 0x00590133 + ret = wait_2338 (); + if (ret < 0) + return ret; + if (read8 (DEFAULT_RCBABASE | 0x2338) & 6) + return -2; + return 0; +} + +static int +and_or_2338 (u32 edx, u32 and, u32 or) +{ + u32 t1; + int ret; + ret = read_2338 (edx, &t1); + if (ret < 0) + return ret; + write16 (DEFAULT_RCBABASE | 0x2338, (read16 (DEFAULT_RCBABASE | 0x2338) + & 0x1ff) | 0x600); + t1 &= and; + t1 |= or; + ret = wait_2338 (); + if (ret < 0) + return ret; + + write32 (DEFAULT_RCBABASE | 0x2334, t1); + ret = wait_2338 (); + if (ret < 0) + return ret; + write16 (DEFAULT_RCBABASE | 0x2338, + (read16 (DEFAULT_RCBABASE | 0x2338) & 0x1ff) | 0x600); + if (read8 (DEFAULT_RCBABASE | 0x2338) & 6) + return -2; + return 0; +} + +#define USB_ACC_CONTROL 0x80 + +static void +init_usb (void) +{ + u32 base; + pcie_read_config32 (SOUTHBRIDGE, 0xf0); // !!! = 0xfed1c001 + read32 (DEFAULT_RCBABASE | 0x3418); // !!! = 0x06000000 + pcie_read_config16 (SOUTHBRIDGE, 0x40); // !!! = 0x0501 + read32 (DEFAULT_RCBABASE | 0x3598); // !!! = 0x00000000 + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0x10); // !!! = 0x00000000 + pcie_read_config16 (PCI_DEV (0, 0x1d, 0), 0x04); // !!! = 0x0000 + base = 0xe8000000; + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0x10, base); + pcie_read_config16 (PCI_DEV (0, 0x1d, 0), 0x04); // !!! = 0x0000 + pcie_write_config16 (PCI_DEV (0, 0x1d, 0), 0x04, 0x0006); + + pcie_write_config16 (PCI_DEV (0, 0x1d, 0), USB_ACC_CONTROL, + pcie_read_config16 (PCI_DEV (0, 0x1d, 0), + USB_ACC_CONTROL) | 1); + read32 (base + 4); // !!! = 0x00204008 + write32 (base + 4, 0x00200008); + read32 (base + 4); // !!! = 0x00200008 + write32 (base + 4, 0x00200003); + pcie_write_config16 (PCI_DEV (0, 0x1d, 0), USB_ACC_CONTROL, + pcie_read_config16 (PCI_DEV (0, 0x1d, 0), + USB_ACC_CONTROL) & ~1); + read32 (0xe8000024); // !!! = 0x00001000 + write16 (0xe8000020, read16 (0xe8000020) | 2); + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0x84); // !!! = 0x83088e01 + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0x84, 0x930c8811); + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0x88); // !!! = 0x04000030 + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0x88, 0x24000d30); + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0xf4); // !!! = 0x00408588 + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0xf4, 0x80408588); + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0xf4); // !!! = 0x80408588 + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0xf4, 0x80808588); + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0xf4); // !!! = 0x80808588 + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0xf4, 0x00808588); + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0xfc); // !!! = 0x20591708 + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0xfc, 0x205b1708); + write32 (DEFAULT_RCBABASE | 0x3560, + read32 (DEFAULT_RCBABASE | 0x3560) | 0x20c8000); + pcie_read_config16 (PCI_DEV (0, 0x1d, 0), 0x04); // !!! = 0x0006 + pcie_write_config16 (PCI_DEV (0, 0x1d, 0), 0x04, 0x0000); + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0x10, 0x00000000); + base = 0xfef00000; + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0x10); // !!! = 0xfef00000 + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0x10); // !!! = 0xfef00000 + pcie_read_config16 (PCI_DEV (0, 0x1a, 0), 0x04); // !!! = 0x0002 + pcie_read_config16 (PCI_DEV (0, 0x1a, 0), 0x04); // !!! = 0x0002 + pcie_write_config16 (PCI_DEV (0, 0x1a, 0), 0x04, 0x0006); + pcie_write_config16 (PCI_DEV (0, 0x1a, 0), 0x80, + pcie_read_config16 (PCI_DEV (0, 0x1a, 0), 0x80) | 1); + read32 (base + 4); // !!! = 0x00203006 + write32 (base + 4, 0x00200006); + read32 (base + 4); // !!! = 0x00200006 + write32 (base + 4, 0x00200003); + pcie_write_config16 (PCI_DEV (0, 0x1a, 0), USB_ACC_CONTROL, + pcie_read_config16 (PCI_DEV (0, 0x1a, 0), + USB_ACC_CONTROL) & ~1); + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0x84); // !!! = 0x83088e01 + pcie_write_config32 (PCI_DEV (0, 0x1a, 0), 0x84, 0x930c8811); + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0x88); // !!! = 0x04000030 + pcie_write_config32 (PCI_DEV (0, 0x1a, 0), 0x88, 0x24000d30); + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0xf4); // !!! = 0x00408588 + pcie_write_config32 (PCI_DEV (0, 0x1a, 0), 0xf4, 0x80408588); + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0xf4); // !!! = 0x80408588 + pcie_write_config32 (PCI_DEV (0, 0x1a, 0), 0xf4, 0x80808588); + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0xf4); // !!! = 0x80808588 + pcie_write_config32 (PCI_DEV (0, 0x1a, 0), 0xf4, 0x00808588); + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0xfc); // !!! = 0x20591708 + pcie_write_config32 (PCI_DEV (0, 0x1a, 0), 0xfc, 0x205b1708); + write32 (DEFAULT_RCBABASE | 0x3560, + read32 (DEFAULT_RCBABASE | 0x3560) | 0x20c8000); + pcie_write_config16 (PCI_DEV (0, 0x1a, 0), 0x04, 0x0002); + + pcie_read_config16 (SOUTHBRIDGE, 0x02); // !!! = 0x1e55 + outw (inw (DEFAULT_PMBASE | 0x003c) | 2, DEFAULT_PMBASE | 0x003c); + u16 reg_359c = 0x150; + int i; + for (i = 0; i < 14; i++) + if (reg_359c & (1 << i)) + write16 (DEFAULT_RCBABASE | 0x359c, + read16 (DEFAULT_RCBABASE | 0x359c) | (1 << i)); + else + write16 (DEFAULT_RCBABASE | 0x359c, + read16 (DEFAULT_RCBABASE | 0x359c) & ~(1 << i)); + pcie_read_config8 (SOUTHBRIDGE, 0x08); // !!! = 0x04 + pcie_read_config16 (SOUTHBRIDGE, 0x02); // !!! = 0x1e55 + pcie_read_config32 (PCI_DEV (0, 0x14, 0), 0xe4); // !!! = 0x00000000 + pcie_write_config32 (PCI_DEV (0, 0x14, 0), 0xe4, 0x00000000); + outw (0x0000, DEFAULT_PMBASE | 0x003c); + write32 (DEFAULT_RCBABASE | 0x3418, 0x16001fe0); + read32 (DEFAULT_RCBABASE | 0x3418); // !!! = 0x16001fe0 +} + +static void +init_thermal (void) +{ + /* OK { */ + pcie_write_config32 (PCI_DEV (0, 0x1f, 6), 0x40, 0xfed08000); + pcie_write_config32 (PCI_DEV (0, 0x1f, 6), 0x44, 0x00000000); + pcie_read_config32 (PCI_DEV (0, 0x1f, 6), 0x40); // !!! = 0xfed08004 + pcie_write_config32 (PCI_DEV (0, 0x1f, 6), 0x40, 0xfed08005); + write16 (0xfed08004, 0x3a2b); + write8 (0xfed0800c, 0xff); + write8 (0xfed0800d, 0x00); + write8 (0xfed0800e, 0x40); + write8 (0xfed08082, 0x00); + write8 (0xfed08001, 0xba); + msr_t msr; + msr = rdmsr (MSR_TEMPERATURE_TARGET); // !!! = 0x0000000000691200 + write16 (0xfed08012, ((msr.lo >> 16) & 0xff) << 6); + write16 (0xfed08016, 0x808c); + + + write32 (DEFAULT_RCBABASE | 0x38b0, + (read32 (DEFAULT_RCBABASE | 0x38b0) & 0xffff8003) | 0x403c); + + write16 (0xfed08014, 0xde87); + /* } OK */ + if (read32 (DEFAULT_RCBABASE | 0x38b4) & 0x4000) // !!! = 0x0000437e + write16 (0xfed0801a, 0x0000); + else + { + /* ? */ + } + pcie_read_config32 (PCI_DEV (0, 0x1f, 6), 0x40); // !!! = 0xfed08005 + pcie_write_config32 (PCI_DEV (0, 0x1f, 6), 0x40, 0xfed08004); + pcie_write_config32 (PCI_DEV (0, 0x1f, 6), 0x40, 0x00000000); +} + +void +pch_init (void) +{ + int i; + + pcie_read_config16 (SOUTHBRIDGE, PCI_DEVICE_ID); // !!! = 0x1e55 + pcie_read_config32 (SOUTHBRIDGE, RCBA); // !!! = 0xfed1c001 + pcie_write_config32 (SOUTHBRIDGE, RCBA, DEFAULT_RCBA | 1); + pcie_read_config32 (SOUTHBRIDGE, PMBASE); // !!! = 0x00000501 + pcie_write_config32 (SOUTHBRIDGE, PMBASE, DEFAULT_PMBASE | 1); + pcie_write_config8 (SOUTHBRIDGE, ACPI_CNTL, + pcie_read_config8 (SOUTHBRIDGE, ACPI_CNTL) | ACPI_EN); + + /* Undocumented. */ + pcie_write_config8 (SOUTHBRIDGE, 0xa6, + pcie_read_config8 (SOUTHBRIDGE, 0xa6) | 2); + + pcie_read_config32 (SOUTHBRIDGE, GPIO_BASE); // !!! = 0x00000481 + pcie_write_config32 (SOUTHBRIDGE, GPIO_BASE, DEFAULT_GPIOBASE | 1); + pcie_read_config8 (SOUTHBRIDGE, GPIO_CNTL); // !!! = 0x10 + pcie_write_config8 (SOUTHBRIDGE, GPIO_CNTL, 0x10); + pcie_read_config16 (SOUTHBRIDGE, PCI_DEVICE_ID); // !!! = 0x1e55 + + write32 (DEFAULT_RCBABASE | 0x2088, 0x00109000); + read32 (DEFAULT_RCBABASE | 0x20ac); // !!! = 0x00000000 + write32 (DEFAULT_RCBABASE | 0x20ac, 0x40000000); + write32 (DEFAULT_RCBABASE | 0x100c, 0x01110000); + write8 (DEFAULT_RCBABASE | 0x2340, 0x1b); + read32 (DEFAULT_RCBABASE | 0x2314); // !!! = 0x0a080000 + write32 (DEFAULT_RCBABASE | 0x2314, 0x0a280000); + read32 (DEFAULT_RCBABASE | 0x2310); // !!! = 0xc809605b + write32 (DEFAULT_RCBABASE | 0x2310, 0xa809605b); + write32 (DEFAULT_RCBABASE | 0x2324, 0x00854c74); + read8 (DEFAULT_RCBABASE | 0x0400); // !!! = 0x00 + read32 (DEFAULT_RCBABASE | 0x2310); // !!! = 0xa809605b + write32 (DEFAULT_RCBABASE | 0x2310, 0xa809605b); + read32 (DEFAULT_RCBABASE | 0x2310); // !!! = 0xa809605b + write32 (DEFAULT_RCBABASE | 0x2310, 0xa809605b); + + and_or_2338 (0xea007f62, 0, 0x00590133); + and_or_2338 (0xec007f62, 0, 0x00590133); + and_or_2338 (0xec007f64, 0, 0x59555588); + and_or_2338 (0xea0040b9, 0, 0x0001051c); + and_or_2338 (0xeb0040a1, 0, 0x800084ff); + and_or_2338 (0xec0040a1, 0, 0x800084ff); + and_or_2338 (0xea004001, 0, 0x00008400); + and_or_2338 (0xeb004002, 0, 0x40201758); + and_or_2338 (0xec004002, 0, 0x40201758); + and_or_2338 (0xea004002, 0, 0x00601758); + and_or_2338 (0xea0040a1, 0, 0x810084ff); + and_or_2338 (0xeb0040b1, 0, 0x0001c598); + and_or_2338 (0xec0040b1, 0, 0x0001c598); + and_or_2338 (0xeb0040b6, 0, 0x0001c598); + and_or_2338 (0xea0000a9, 0, 0x80ff969f); + and_or_2338 (0xea0001a9, 0, 0x80ff969f); + and_or_2338 (0xeb0040b2, 0, 0x0001c396); + and_or_2338 (0xeb0040b3, 0, 0x0001c396); + and_or_2338 (0xec0040b2, 0, 0x0001c396); + and_or_2338 (0xea0001a9, 0, 0x80ff94ff); + and_or_2338 (0xea000151, 0, 0x0088037f); + and_or_2338 (0xea0000a9, 0, 0x80ff94ff); + and_or_2338 (0xea000051, 0, 0x0088037f); + + u32 reg32; + read_2338 (0xea007f05, &reg32); + + and_or_2338 (0xea007f05, 0, 0x00010642); + and_or_2338 (0xea0040b7, 0, 0x0001c91c); + and_or_2338 (0xea0040b8, 0, 0x0001c91c); + and_or_2338 (0xeb0040a1, 0, 0x820084ff); + and_or_2338 (0xec0040a1, 0, 0x820084ff); + and_or_2338 (0xea007f0a, 0, 0xc2480000); + + + pcie_read_config8 (SOUTHBRIDGE, 0x08); // !!! = 0x04 + pcie_read_config16 (SOUTHBRIDGE, 0x02); // !!! = 0x1e55 + + and_or_2338 (0xec00404d, 0, 0x1ff177f); + and_or_2338 (0xec000084, 0, 0x5a600000); + and_or_2338 (0xec000184, 0, 0x5a600000); + and_or_2338 (0xec000284, 0, 0x5a600000); + and_or_2338 (0xec000384, 0, 0x5a600000); + and_or_2338 (0xec000094, 0, 0x000f0501); + and_or_2338 (0xec000194, 0, 0x000f0501); + and_or_2338 (0xec000294, 0, 0x000f0501); + and_or_2338 (0xec000394, 0, 0x000f0501); + and_or_2338 (0xec000096, 0, 0x00000001); + and_or_2338 (0xec000196, 0, 0x00000001); + and_or_2338 (0xec000296, 0, 0x00000001); + and_or_2338 (0xec000396, 0, 0x00000001); + and_or_2338 (0xec000001, 0, 0x00008c08); + and_or_2338 (0xec000101, 0, 0x00008c08); + and_or_2338 (0xec000201, 0, 0x00008c08); + and_or_2338 (0xec000301, 0, 0x00008c08); + and_or_2338 (0xec0040b5, 0, 0x0001c518); + and_or_2338 (0xec000087, 0, 0x06077597); + and_or_2338 (0xec000187, 0, 0x06077597); + and_or_2338 (0xec000287, 0, 0x06077597); + and_or_2338 (0xec000387, 0, 0x06077597); + and_or_2338 (0xea000050, 0, 0x00bb0157); + and_or_2338 (0xea000150, 0, 0x00bb0157); + and_or_2338 (0xec007f60, 0, 0x77777d77); + and_or_2338 (0xea00008d, 0, 0x01320000); + and_or_2338 (0xea00018d, 0, 0x01320000); + + read16 (DEFAULT_RCBABASE | 0x0400); // !!! = 0x0b00 + read32 (DEFAULT_RCBABASE | 0x0400); // !!! = 0x00000b00 + + and_or_2338 (0xec0007b2, 0, 0x04514b5e); + and_or_2338 (0xec00078c, 0, 0x40000200); + and_or_2338 (0xec000780, 0, 0x02000020); + + read8 (DEFAULT_RCBABASE | 0x3414); // !!! = 0x00 + pcie_read_config16 (SOUTHBRIDGE, 0x02); // !!! = 0x1e55 + + read32 (DEFAULT_RCBABASE | 0x3598); // !!! = 0x00000001 + read32 (DEFAULT_RCBABASE | 0x3598); // !!! = 0x00000001 + write32 (DEFAULT_RCBABASE | 0x3598, 0x00000000); + read32 (DEFAULT_RCBABASE | 0x3598); // !!! = 0x00000000 + pcie_read_config32 (PCI_DEV (0, 0x1d, 0), 0x88); // !!! = 0x04000030 + pcie_write_config32 (PCI_DEV (0, 0x1d, 0), 0x88, 0x04000030); + pcie_read_config32 (PCI_DEV (0, 0x1a, 0), 0x88); // !!! = 0x04000030 + pcie_write_config32 (PCI_DEV (0, 0x1a, 0), 0x88, 0x04000030); + + read32 (DEFAULT_RCBABASE | 0x3410); // !!! = 0x00000c20 + write32 (DEFAULT_RCBABASE | 0x3410, 0x00000c20); + read32 (DEFAULT_RCBABASE | 0x3410); // !!! = 0x00000c20 + /* Disable SATA2. */ + write32 (DEFAULT_RCBABASE | 0x3418, + read32 (DEFAULT_RCBABASE | 0x3418) | 0x02000000); + read32 (DEFAULT_RCBABASE | 0x3418); // !!! = 0x06000000 + + /* Configure thermal */ + init_thermal (); + + read8 (DEFAULT_RCBABASE | 0x31fe); // !!! = 0x00 + read16 (DEFAULT_RCBABASE | 0x31fe); // !!! = 0x0000 + write16 (DEFAULT_RCBABASE | 0x31fe, 0x0100); + read16 (DEFAULT_RCBABASE | 0x31fe); // !!! = 0x0100 + read8 (DEFAULT_RCBABASE | 0x31fe); // !!! = 0x00 + write8 (0xfec00000, 0x00); + read32 (0xfec00010); // !!! = 0x00000000 + pcie_write_config32 (PCI_DEV (0, 0x1f, 3), 0x20, 0x00000400); + pcie_read_config8 (PCI_DEV (0, 0x1f, 3), 0x04); // !!! = 0x01 + pcie_write_config8 (PCI_DEV (0, 0x1f, 3), 0x04, 0x01); + pcie_read_config8 (PCI_DEV (0, 0x1f, 3), 0x40); // !!! = 0x01 + pcie_write_config8 (PCI_DEV (0, 0x1f, 3), 0x40, 0x09); + pcie_read_config8 (PCI_DEV (0, 0x1f, 3), 0x40); // !!! = 0x01 + pcie_write_config8 (PCI_DEV (0, 0x1f, 3), 0x40, 0x01); + outb (0xff, 0x0400); + init_usb (); + pcie_read_config16 (NORTHBRIDGE, 0xe4); // !!! = 0x619b + pcie_read_config16 (NORTHBRIDGE, 0x02); // !!! = 0x0154 + cpuid_ext (0x1, 0x0); // !!! = 0x00000000000306a9 + pcie_write_config32 (NORTHBRIDGE, 0x48, 0xfed10001); + pcie_write_config32 (NORTHBRIDGE, 0x4c, 0x00000000); + pcie_write_config32 (NORTHBRIDGE, 0x68, 0xfed18001); + pcie_write_config32 (NORTHBRIDGE, 0x6c, 0x00000000); + pcie_write_config32 (NORTHBRIDGE, 0x40, 0xfed19001); + pcie_write_config32 (NORTHBRIDGE, 0x44, 0x00000000); + read32 (DEFAULT_MCHBAR | 0x5f00); // !!! = 0x0000270f + write32 (DEFAULT_MCHBAR | 0x5f00, 0x0000270f); + cpuid_ext (0x1, 0x0); // !!! = 0x00000000000306a9 + pcie_read_config16 (NORTHBRIDGE, 0x02); // !!! = 0x0154 + pcie_read_config32 (NORTHBRIDGE, 0x68); // !!! = 0xfed18001 + pcie_read_config32 (NORTHBRIDGE, 0x6c); // !!! = 0x00000000 + write32 (DEFAULT_DMIBAR | 0x0914, + read32 (DEFAULT_DMIBAR | 0x0914) | 0x80000000); + write32 (DEFAULT_DMIBAR | 0x0934, + read32 (DEFAULT_DMIBAR | 0x0934) | 0x80000000); + for (i = 0; i < 4; i++) + { + write32 (DEFAULT_DMIBAR | 0x0a00 | (i << 4), + read32 (DEFAULT_DMIBAR | 0x0a00 | (i << 4)) & 0xf3ffffff); + write32 (DEFAULT_DMIBAR | 0x0a04 | (i << 4), + read32 (DEFAULT_DMIBAR | 0x0a04 | (i << 4)) | 0x800); + } + write32 (DEFAULT_DMIBAR | 0x0c30, (read32 (DEFAULT_DMIBAR | 0x0c30) + & 0xfffffff) | 0x40000000); + for (i = 0; i < 2; i++) + { + write32 (DEFAULT_DMIBAR | 0x0904 | (i << 5), + read32 (DEFAULT_DMIBAR | 0x0904 | (i << 5)) & 0xfe3fffff); + write32 (DEFAULT_DMIBAR | 0x090c | (i << 5), + read32 (DEFAULT_DMIBAR | 0x090c | (i << 5)) & 0xfff1ffff); + } + write32 (DEFAULT_DMIBAR | 0x090c, + read32 (DEFAULT_DMIBAR | 0x090c) & 0xfe1fffff); + write32 (DEFAULT_DMIBAR | 0x092c, + read32 (DEFAULT_DMIBAR | 0x092c) & 0xfe1fffff); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x7a1842ec); + read32 (DEFAULT_DMIBAR | 0x090c); // !!! = 0x00000208 + write32 (DEFAULT_DMIBAR | 0x090c, 0x00000128); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x7a1842ec); + read32 (DEFAULT_DMIBAR | 0x092c); // !!! = 0x00000208 + write32 (DEFAULT_DMIBAR | 0x092c, 0x00000128); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0c04); // !!! = 0x2e680008 + write32 (DEFAULT_DMIBAR | 0x0c04, 0x2e680008); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x3a1842ec); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x3a1842ec); + read32 (DEFAULT_DMIBAR | 0x0910); // !!! = 0x00006300 + write32 (DEFAULT_DMIBAR | 0x0910, 0x00004300); + read32 (DEFAULT_DMIBAR | 0x0930); // !!! = 0x00006300 + write32 (DEFAULT_DMIBAR | 0x0930, 0x00004300); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0c00); // !!! = 0x29700c08 + write32 (DEFAULT_DMIBAR | 0x0c00, 0x29700c08); + read32 (DEFAULT_DMIBAR | 0x0a04); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a04, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0a14); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a14, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0a24); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a24, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0a34); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a34, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0900); // !!! = 0x50000000 + write32 (DEFAULT_DMIBAR | 0x0900, 0x50000000); + read32 (DEFAULT_DMIBAR | 0x0920); // !!! = 0x50000000 + write32 (DEFAULT_DMIBAR | 0x0920, 0x50000000); + read32 (DEFAULT_DMIBAR | 0x0908); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0908, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0928); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0928, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x3a1842ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x3a1846ec); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x3a1842ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x3a1846ec); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0908); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0908, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0928); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0928, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0c00); // !!! = 0x29700c08 + write32 (DEFAULT_DMIBAR | 0x0c00, 0x29700c08); + read32 (DEFAULT_DMIBAR | 0x0c0c); // !!! = 0x16063400 + write32 (DEFAULT_DMIBAR | 0x0c0c, 0x00063400); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x46339008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x46339008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46339008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x45339008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46339008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x45339008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x45339008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x453b9008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x45339008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x453b9008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x453b9008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x45bb9008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x453b9008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x45bb9008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x45bb9008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x45fb9008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x45bb9008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x45fb9008); + read32 (DEFAULT_DMIBAR | 0x0914); // !!! = 0x9021a080 + write32 (DEFAULT_DMIBAR | 0x0914, 0x9021a280); + read32 (DEFAULT_DMIBAR | 0x0934); // !!! = 0x9021a080 + write32 (DEFAULT_DMIBAR | 0x0934, 0x9021a280); + read32 (DEFAULT_DMIBAR | 0x0914); // !!! = 0x9021a280 + write32 (DEFAULT_DMIBAR | 0x0914, 0x9821a280); + read32 (DEFAULT_DMIBAR | 0x0934); // !!! = 0x9021a280 + write32 (DEFAULT_DMIBAR | 0x0934, 0x9821a280); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0258); // !!! = 0x40000600 + write32 (DEFAULT_DMIBAR | 0x0258, 0x60000600); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x3a1846ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x2a1846ec); + read32 (DEFAULT_DMIBAR | 0x0914); // !!! = 0x9821a280 + write32 (DEFAULT_DMIBAR | 0x0914, 0x98200280); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x3a1846ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x2a1846ec); + read32 (DEFAULT_DMIBAR | 0x0934); // !!! = 0x9821a280 + write32 (DEFAULT_DMIBAR | 0x0934, 0x98200280); + read32 (DEFAULT_DMIBAR | 0x022c); // !!! = 0x00c26460 + write32 (DEFAULT_DMIBAR | 0x022c, 0x00c2403c); + read8 (DEFAULT_RCBABASE | 0x21a4); // !!! = 0x42 + pcie_read_config32 (NORTHBRIDGE, 0xe4); // !!! = 0xe200619b + pcie_read_config32 (SOUTHBRIDGE, 0xf0); // !!! = 0xfed1c001 + read32 (DEFAULT_RCBABASE | 0x21a4); // !!! = 0x00012c42 + read32 (DEFAULT_RCBABASE | 0x2340); // !!! = 0x0013001b + write32 (DEFAULT_RCBABASE | 0x2340, 0x003a001b); + read8 (DEFAULT_RCBABASE | 0x21b0); // !!! = 0x01 + write8 (DEFAULT_RCBABASE | 0x21b0, 0x02); + read32 (DEFAULT_DMIBAR | 0x0084); // !!! = 0x0041ac41 + write32 (DEFAULT_DMIBAR | 0x0084, 0x0041ac42); + read8 (DEFAULT_DMIBAR | 0x0088); // !!! = 0x00 + write8 (DEFAULT_DMIBAR | 0x0088, 0x20); + read16 (DEFAULT_DMIBAR | 0x008a); // !!! = 0x0041 + read8 (DEFAULT_DMIBAR | 0x0088); // !!! = 0x00 + write8 (DEFAULT_DMIBAR | 0x0088, 0x20); + read16 (DEFAULT_DMIBAR | 0x008a); // !!! = 0x0042 + read16 (DEFAULT_DMIBAR | 0x008a); // !!! = 0x0042 + pcie_read_config16 (NORTHBRIDGE, 0x50); // !!! = 0x0208 + pcie_write_config16 (NORTHBRIDGE, 0x50, 0x020a); + pcie_read_config16 (PCI_DEV (0, 0x1e, 0), 0x00); // !!! = 0x8086 + pcie_write_config32 (PCI_DEV (0, 0x1e, 0), 0x18, 0x00ff0200); + pcie_read_config8 (PCI_DEV (0, 0x1e, 0), 0x19); // !!! = 0x02 + pcie_write_config16 (PCI_DEV (2, 0x0, 0), 0x00, 0x0000); + + pcie_write_config8 (PCI_DEV (0, 0x1e, 0), 0x1a, 0x02); + pcie_write_config32 (PCI_DEV (0, 0x1e, 0), 0x18, 0x00000000); + + pcie_read_config16 (NORTHBRIDGE, 0x54); // !!! = 0x0011 + pcie_read_config16 (NORTHBRIDGE, 0x50); // !!! = 0x020a + pcie_write_config16 (NORTHBRIDGE, 0x50, 0x0202); + pcie_read_config8 (NORTHBRIDGE, 0x50); // !!! = 0x02 + pcie_write_config8 (NORTHBRIDGE, 0x50, 0x0a); + pcie_read_config16 (NORTHBRIDGE, 0x50); // !!! = 0x020a + pcie_write_config16 (NORTHBRIDGE, 0x50, 0x020a); + pcie_read_config8 (GFX_DEV, 0x62); // !!! = 0x02 + pcie_write_config8 (GFX_DEV, 0x62, 0x02); + pcie_read_config16 (NORTHBRIDGE, 0x50); // !!! = 0x020a + pcie_write_config16 (NORTHBRIDGE, 0x50, 0x0208); + pcie_read_config32 (NORTHBRIDGE, 0x68); // !!! = 0xfed18001 + pcie_read_config32 (NORTHBRIDGE, 0x6c); // !!! = 0x00000000 + read32 (DEFAULT_DMIBAR | 0x0014); // !!! = 0x8000007f + write32 (DEFAULT_DMIBAR | 0x0014, 0x80000019); + read32 (DEFAULT_DMIBAR | 0x0020); // !!! = 0x01000000 + write32 (DEFAULT_DMIBAR | 0x0020, 0x81000022); + read32 (DEFAULT_DMIBAR | 0x002c); // !!! = 0x02000000 + write32 (DEFAULT_DMIBAR | 0x002c, 0x82000044); + read32 (DEFAULT_DMIBAR | 0x0038); // !!! = 0x07000080 + write32 (DEFAULT_DMIBAR | 0x0038, 0x87000080); + read8 (DEFAULT_DMIBAR | 0x0004); // !!! = 0x00 + write8 (DEFAULT_DMIBAR | 0x0004, 0x01); + pcie_read_config32 (SOUTHBRIDGE, 0xf0); // !!! = 0xfed1c001 + read32 (DEFAULT_RCBABASE | 0x0050); // !!! = 0x01200654 + write32 (DEFAULT_RCBABASE | 0x0050, 0x01200654); + read32 (DEFAULT_RCBABASE | 0x0050); // !!! = 0x01200654 + write32 (DEFAULT_RCBABASE | 0x0050, 0x012a0654); + read32 (DEFAULT_RCBABASE | 0x0050); // !!! = 0x012a0654 + read8 (DEFAULT_RCBABASE | 0x1114); // !!! = 0x00 + write8 (DEFAULT_RCBABASE | 0x1114, 0x05); + read32 (DEFAULT_RCBABASE | 0x2014); // !!! = 0x80000011 + write32 (DEFAULT_RCBABASE | 0x2014, 0x80000019); + read32 (DEFAULT_RCBABASE | 0x2020); // !!! = 0x00000000 + write32 (DEFAULT_RCBABASE | 0x2020, 0x81000022); + read32 (DEFAULT_RCBABASE | 0x2020); // !!! = 0x81000022 + read32 (DEFAULT_RCBABASE | 0x2030); // !!! = 0x00000000 + write32 (DEFAULT_RCBABASE | 0x2030, 0x82000044); + read32 (DEFAULT_RCBABASE | 0x2030); // !!! = 0x82000044 + read32 (DEFAULT_RCBABASE | 0x2040); // !!! = 0x00000000 + write32 (DEFAULT_RCBABASE | 0x2040, 0x87000080); + read32 (DEFAULT_RCBABASE | 0x0050); // !!! = 0x012a0654 + write32 (DEFAULT_RCBABASE | 0x0050, 0x812a0654); + read32 (DEFAULT_RCBABASE | 0x0050); // !!! = 0x812a0654 + read16 (DEFAULT_RCBABASE | 0x201a); // !!! = 0x0000 + read16 (DEFAULT_RCBABASE | 0x2026); // !!! = 0x0000 + read16 (DEFAULT_RCBABASE | 0x2036); // !!! = 0x0000 + read16 (DEFAULT_RCBABASE | 0x2046); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x001a); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x0026); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x0032); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x003e); // !!! = 0x0000 +} diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index 61e1545..7f2beda 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -1,7 +1,8 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2011 Google Inc. + * Copyright (C) 2014 Damien Zammit <damien(a)zamaudio.com> + * Copyright (C) 2014 Vladimir Serbinenko <phcoder(a)gmail.com> * * 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 @@ -31,128 +32,151 @@ #include "raminit.h" #include "pei_data.h" #include "sandybridge.h" +#include <delay.h> /* Management Engine is in the southbridge */ #include "southbridge/intel/bd82x6x/me.h" +#include "southbridge/intel/bd82x6x/pch.h" +#include "southbridge/intel/bd82x6x/smbus.h" +#include <cpu/x86/msr.h> +#include <cpu/cpu.h> +#include "cpu/intel/model_2065x/model_2065x.h" + #if CONFIG_CHROMEOS #include <vendorcode/google/chromeos/chromeos.h> #else #define recovery_mode_enabled(x) 0 #endif -/* - * MRC scrambler seed offsets should be reserved in - * mainboard cmos.layout and not covered by checksum. - */ -#if CONFIG_USE_OPTION_TABLE -#include "option_table.h" -#define CMOS_OFFSET_MRC_SEED (CMOS_VSTART_mrc_scrambler_seed >> 3) -#define CMOS_OFFSET_MRC_SEED_S3 (CMOS_VSTART_mrc_scrambler_seed_s3 >> 3) -#define CMOS_OFFSET_MRC_SEED_CHK (CMOS_VSTART_mrc_scrambler_seed_chk >> 3) -#else -#define CMOS_OFFSET_MRC_SEED 152 -#define CMOS_OFFSET_MRC_SEED_S3 156 -#define CMOS_OFFSET_MRC_SEED_CHK 160 -#endif +/* FIXME: no ECC support. */ +/* FIXME: no support for 3-channel chipsets. */ +/* FIXME: no S3. */ +/* FIXME: no timing caching. */ -void save_mrc_data(struct pei_data *pei_data) -{ - u16 c1, c2, checksum; +#define SANDYIVY_MAX_DIMM_SLOTS 4 -#if CONFIG_EARLY_CBMEM_INIT - struct mrc_data_container *mrcdata; - int output_len = ALIGN(pei_data->mrc_output_len, 16); +#define BASEFREQ 133 +#define tDLLK 512 - /* Save the MRC S3 restore data to cbmem */ - mrcdata = cbmem_add - (CBMEM_ID_MRCDATA, - output_len + sizeof(struct mrc_data_container)); +#define IS_SANDY_CPU(x) ((x & 0xffff0) == 0x206a0) +#define IS_SANDY_CPU_C(x) ((x & 0xf) == 4) +#define IS_SANDY_CPU_D0(x) ((x & 0xf) == 5) +#define IS_SANDY_CPU_D1(x) ((x & 0xf) == 6) +#define IS_SANDY_CPU_D2(x) ((x & 0xf) == 7) - printk(BIOS_DEBUG, "Relocate MRC DATA from %p to %p (%u bytes)\n", - pei_data->mrc_output, mrcdata, output_len); +#define IS_IVY_CPU(x) ((x & 0xffff0) == 0x306a0) +#define IS_IVY_CPU_C(x) ((x & 0xf) == 4) +#define IS_IVY_CPU_K(x) ((x & 0xf) == 5) +#define IS_IVY_CPU_D(x) ((x & 0xf) == 6) +#define IS_IVY_CPU_E(x) ((x & 0xf) >= 8) - mrcdata->mrc_signature = MRC_DATA_SIGNATURE; - mrcdata->mrc_data_size = output_len; - mrcdata->reserved = 0; - memcpy(mrcdata->mrc_data, pei_data->mrc_output, - pei_data->mrc_output_len); +#define NUM_CHANNELS 2 +#define NUM_SLOTRANKS 4 - /* Zero the unused space in aligned buffer. */ - if (output_len > pei_data->mrc_output_len) - memset(mrcdata->mrc_data+pei_data->mrc_output_len, 0, - output_len - pei_data->mrc_output_len); +typedef struct odtmap_st { + u16 rttwr; + u16 rttnom; +} odtmap; - mrcdata->mrc_checksum = compute_ip_checksum(mrcdata->mrc_data, - mrcdata->mrc_data_size); -#endif +typedef struct dimm_info_st +{ + dimm_attr dimm[SANDYIVY_MAX_DIMM_SLOTS]; +} dimm_info; - /* Save the MRC seed values to CMOS */ - cmos_write32(CMOS_OFFSET_MRC_SEED, pei_data->scrambler_seed); - printk(BIOS_DEBUG, "Save scrambler seed 0x%08x to CMOS 0x%02x\n", - pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED); +struct ram_rank_timings +{ + /* Register 4024. One byte per slotrank. */ + u8 val_4024; + /* Register 4028. One nibble per slotrank. */ + u8 val_4028; - cmos_write32(CMOS_OFFSET_MRC_SEED_S3, pei_data->scrambler_seed_s3); - printk(BIOS_DEBUG, "Save s3 scrambler seed 0x%08x to CMOS 0x%02x\n", - pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3); + int val_320c; - /* Save a simple checksum of the seed values */ - c1 = compute_ip_checksum((u8*)&pei_data->scrambler_seed, - sizeof(u32)); - c2 = compute_ip_checksum((u8*)&pei_data->scrambler_seed_s3, - sizeof(u32)); - checksum = add_ip_checksums(sizeof(u32), c1, c2); + struct ram_lane_timings + { + /* lane register offset 0x10. */ + u16 timA; /* bits 0 - 5, bits 16 - 18 */ + u8 rising; /* bits 8 - 14 */ + u8 falling; /* bits 20 - 26. */ - cmos_write(checksum & 0xff, CMOS_OFFSET_MRC_SEED_CHK); - cmos_write((checksum >> 8) & 0xff, CMOS_OFFSET_MRC_SEED_CHK+1); -} + /* lane register offset 0x20. */ + int timC; /* bit 0 - 5, 19. */ + u16 timB; /* bits 8 - 13, 15 - 17. */ + } lanes[8]; +}; -static void prepare_mrc_cache(struct pei_data *pei_data) -{ - struct mrc_data_container *mrc_cache; - u16 c1, c2, checksum, seed_checksum; +typedef struct ramctr_timing_st { + int mobile; - // preset just in case there is an error - pei_data->mrc_input = NULL; - pei_data->mrc_input_len = 0; + enum spd_memory_type dram_type; + u16 cas_supported; + /* tLatencies are in units of ns, scaled by x256 */ + u32 tCK; + u32 tAA; + u32 tWR; + u32 tRCD; + u32 tRRD; + u32 tRP; + u32 tRAS; + u32 tRC; + u32 tRFC; + u32 tWTR; + u32 tRTP; + u32 tFAW; + /* Latencies in terms of clock cycles + * They are saved separately as they are needed for DRAM MRS commands*/ + u8 CAS; /* CAS read latency */ + u8 CWL; /* CAS write latency */ + /* Number of dimms currently connected */ + u8 n_dimms; - /* Read scrambler seeds from CMOS */ - pei_data->scrambler_seed = cmos_read32(CMOS_OFFSET_MRC_SEED); - printk(BIOS_DEBUG, "Read scrambler seed 0x%08x from CMOS 0x%02x\n", - pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED); + u32 tREFI; + u32 tMOD; + u32 tXSOffset; + u32 tWLO; + u32 tCKE; + u32 tXPDLL; + u32 tXP; + u32 tAONPD; - pei_data->scrambler_seed_s3 = cmos_read32(CMOS_OFFSET_MRC_SEED_S3); - printk(BIOS_DEBUG, "Read S3 scrambler seed 0x%08x from CMOS 0x%02x\n", - pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3); + u32 delay1; + u32 delay2; - /* Compute seed checksum and compare */ - c1 = compute_ip_checksum((u8*)&pei_data->scrambler_seed, - sizeof(u32)); - c2 = compute_ip_checksum((u8*)&pei_data->scrambler_seed_s3, - sizeof(u32)); - checksum = add_ip_checksums(sizeof(u32), c1, c2); + u8 eccsupport; + u8 dualchannel; + u8 thermalrefresh; - seed_checksum = cmos_read(CMOS_OFFSET_MRC_SEED_CHK); - seed_checksum |= cmos_read(CMOS_OFFSET_MRC_SEED_CHK+1) << 8; + u8 rankmap[2][2]; //channels, dimms - if (checksum != seed_checksum) { - printk(BIOS_ERR, "%s: invalid seed checksum\n", __func__); - pei_data->scrambler_seed = 0; - pei_data->scrambler_seed_s3 = 0; - return; - } + int reg_c14_offset; - if ((mrc_cache = find_current_mrc_cache()) == NULL) { - /* error message printed in find_current_mrc_cache */ - return; - } + int edge_offset[3]; + int timC_offset[3]; - pei_data->mrc_input = mrc_cache->mrc_data; - pei_data->mrc_input_len = mrc_cache->mrc_data_size; + int rank_mirror[NUM_CHANNELS][NUM_SLOTRANKS]; - printk(BIOS_DEBUG, "%s: at %p, size %x checksum %04x\n", - __func__, pei_data->mrc_input, - pei_data->mrc_input_len, mrc_cache->mrc_checksum); -} + struct ram_rank_timings timings[NUM_CHANNELS][NUM_SLOTRANKS]; +} ramctr_timing; + +#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0) +#define NORTHBRIDGE PCI_DEV(0, 0x0, 0) +#define GFX_DEV PCI_DEV(0, 0x2, 0) +#define HECIDEV PCI_DEV(0, 0x16, 0) +#define NUM_SLOTS 2 +#define NUM_LANES 8 +#define FOR_ALL_LANES for (lane = 0; lane < NUM_LANES; lane++) +#define FOR_ALL_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++) +#define FOR_ALL_POPULATED_RANKS for (slotrank = 0; slotrank < NUM_SLOTRANKS; slotrank++) if ((ctrl->rankmap[channel][0] | ctrl->rankmap[channel][1]) & (1 << slotrank)) +#define FOR_ALL_POPULATED_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++) if (ctrl->rankmap[channel][0] | ctrl->rankmap[channel][1]) +#define max(a,b) ((a) > (b) ? (a) : (b)) +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define MAX_EDGE_TIMING 71 +#define MAX_TIMC 127 +#define MAX_TIMB 511 +#define MAX_TIMA 127 + +static void +program_timings (ramctr_timing *ctrl, int channel); static const char* ecc_decoder[] = { "inactive", @@ -161,6 +185,28 @@ static const char* ecc_decoder[] = { "active" }; +static void +wait_txt_clear (void) +{ + struct cpuid_result cp; + + cp = cpuid_ext (0x1, 0x0); + /* Check if TXT is supported? */ + if (!(cp.ecx & 0x40)) + return; + /* Some TXT public bit. */ + if (!(read32 (0xfed30010) & 1)) + return; + /* Wait for TXT clear. */ + while (!(read8 (0xfed40000) & (1 << 7))); +} + +static void +sfence (void) +{ + asm volatile ("sfence"); +} + /* * Dump in the log memory controller configuration as read from the memory * controller registers. @@ -204,97 +250,3415 @@ static void report_memory_config(void) } } -static void post_system_agent_init(struct pei_data *pei_data) +static void post_system_agent_init(void) { /* If PCIe init is skipped, set the PEG clock gating */ - if (!pei_data->pcie_init) - MCHBAR32(0x7010) = MCHBAR32(0x7010) | 0x01; + MCHBAR32(0x7010) = MCHBAR32(0x7010) | 0x01; } -/** - * Find PEI executable in coreboot filesystem and execute it. - * - * @param pei_data: configuration data for UEFI PEI reference code - */ -void sdram_initialize(struct pei_data *pei_data) +void read_spd(spd_raw_data *spd, u8 addr) { - struct sys_info sysinfo; - int (*entry) (struct pei_data *pei_data) __attribute__ ((regparm(1))); + int j; + for (j = 0; j < 256; j++) + (*spd)[j] = do_smbus_read_byte(SMBUS_IO_BASE, addr, j); +} - report_platform_info(); +static void dram_find_spds_ddr3(spd_raw_data *spd, dimm_info * dimm, + ramctr_timing * ctrl) +{ + int i = 0; + int dimms = 0; + static const u8 ch[4] = { 0, 0, 1, 1 }; + static const u8 dm[4] = { 0, 1, 0, 1 }; + for (i = 0; i < 4; i++) { + ctrl->rankmap[ch[i]][dm[i]] = 0; + spd_decode_ddr3(&dimm->dimm[i], spd[i]); + if (dimm->dimm[i].dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3) { + // set dimm invalid + dimm->dimm[i].ranks = 0; + dimm->dimm[i].size_mb = 0; + continue; + } - /* Wait for ME to be ready */ - intel_early_me_init(); - intel_early_me_uma_size(); + dram_print_spd_ddr3(&dimm->dimm[i]); + dimms++; + ctrl->rank_mirror[ch[i]][dm[i] * 2] = 0; + ctrl->rank_mirror[ch[i]][dm[i] * 2 + 1] = spd[i][0x3f] & 1; - printk(BIOS_DEBUG, "Starting UEFI PEI System Agent\n"); + /* FIXME: should merge data from all dimms. */ + ctrl->thermalrefresh = spd[i][31]; + ctrl->rankmap[ch[i]][dm[i]] = (1 << dimm->dimm[i].ranks) - 1; + printram("i=%d rankmap[%d][%d] = %d\n", i, + ch[i], dm[i], + ctrl->rankmap[ch[i]][dm[i]]); + } + if (!dimms) + die("No DIMMs were found"); +} + +static void dram_find_common_params(const dimm_info * dimms, ramctr_timing * ctrl) +{ + size_t i, valid_dimms; + ctrl->cas_supported = 0xff; + valid_dimms = 0; + for (i = 0; i < 4; i++) { + const dimm_attr *dimm = &dimms->dimm[i]; + if (dimm->dram_type == SPD_MEMORY_TYPE_UNDEFINED) + continue; + valid_dimms++; + + if (valid_dimms == 1) { + /* First DIMM defines the type of DIMM */ + ctrl->dram_type = dimm->dram_type; + } else { + /* Check if we have mismatched DIMMs */ + if (ctrl->dram_type != dimm->dram_type) + die("Mismatched DIMM Types"); + } + /* Find all possible CAS combinations */ + ctrl->cas_supported &= dimm->cas_supported; + + /* Find the smallest common latencies supported by all DIMMs */ + ctrl->tCK = MAX(ctrl->tCK, dimm->tCK); + ctrl->tAA = MAX(ctrl->tAA, dimm->tAA); + ctrl->tWR = MAX(ctrl->tWR, dimm->tWR); + ctrl->tRCD = MAX(ctrl->tRCD, dimm->tRCD); + ctrl->tRRD = MAX(ctrl->tRRD, dimm->tRRD); + ctrl->tRP = MAX(ctrl->tRP, dimm->tRP); + ctrl->tRAS = MAX(ctrl->tRAS, dimm->tRAS); + ctrl->tRC = MAX(ctrl->tRC, dimm->tRC); + ctrl->tRFC = MAX(ctrl->tRFC, dimm->tRFC); + ctrl->tWTR = MAX(ctrl->tWTR, dimm->tWTR); + ctrl->tRTP = MAX(ctrl->tRTP, dimm->tRTP); + ctrl->tFAW = MAX(ctrl->tFAW, dimm->tFAW); + } - memset(&sysinfo, 0, sizeof(sysinfo)); + ctrl->n_dimms = valid_dimms; + if (!ctrl->cas_supported) + die("Unsupported DIMM combination. " + "DIMMS do not support common CAS latency"); + if (!valid_dimms) + die("No valid DIMMs found"); - sysinfo.boot_path = pei_data->boot_mode; + ctrl->dualchannel = + (pcie_read_config32(PCI_DEV(0, 0, 0), 0xE4) & 0x4000) >> 14; + if (ctrl->dualchannel) { + printram("Dual channel supported\n"); + } else { + printram("Dual channel not supported\n"); + } +} - /* - * Do not pass MRC data in for recovery mode boot, - * Always pass it in for S3 resume. +static u8 get_CWL(u8 CAS) +{ + /* Get CWL based on CAS using the following rule: + * _________________________________________ + * CAS: | 4T | 5T | 6T | 7T | 8T | 9T | 10T | 11T | + * CWL: | 5T | 5T | 5T | 6T | 6T | 7T | 7T | 8T | */ - if (!recovery_mode_enabled() || pei_data->boot_mode == 2) - prepare_mrc_cache(pei_data); - - /* If MRC data is not found we cannot continue S3 resume. */ - if (pei_data->boot_mode == 2 && !pei_data->mrc_input) { - printk(BIOS_DEBUG, "Giving up in sdram_initialize: No MRC data\n"); - outb(0x6, 0xcf9); - hlt(); - } - - /* Pass console handler in pei_data */ - pei_data->tx_byte = do_putchar; - - /* Locate and call UEFI System Agent binary. */ - /* TODO make MRC blob (0xab?) defined in cbfs_core.h. */ - entry = cbfs_get_file_content( - CBFS_DEFAULT_MEDIA, "mrc.bin", 0xab, NULL); - if (entry) { - int rv; - rv = entry (pei_data); - if (rv) { - switch (rv) { - case -1: - printk(BIOS_ERR, "PEI version mismatch.\n"); - break; - case -2: - printk(BIOS_ERR, "Invalid memory frequency.\n"); - break; - default: - printk(BIOS_ERR, "MRC returned %x.\n", rv); + static const u8 cas_cwl_map[] = { 5, 5, 5, 6, 6, 7, 7, 8 }; + if (CAS > 11) + return 8; + return cas_cwl_map[CAS - 4]; +} + +static u32 get_REFI(u32 tCK) +{ + /* Get REFI based on MCU frequency using the following rule: + * _________________________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * REFI: | 3120 | 4160 | 5200 | 6240 | 7280 | 8320 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u32 frq_refi_map[] = + { 3120, 4160, 5200, 6240, 7280, 8320 }; + if (FRQ > 8) + return 8320; + return frq_refi_map[FRQ - 3]; +} + +static u8 get_XSOffset(u32 tCK) +{ + /* Get XSOffset based on MCU frequency using the following rule: + * _________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * XSOffset : | 4 | 6 | 7 | 8 | 10 | 11 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u8 frq_xs_map[] = { 4, 6, 7, 8, 10, 11 }; + if (FRQ > 8) + return 11; + return frq_xs_map[FRQ - 3]; +} + +static u8 get_MOD(u32 tCK) +{ + /* Get MOD based on MCU frequency using the following rule: + * _____________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * MOD : | 12 | 12 | 12 | 12 | 15 | 16 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u8 frq_mod_map[] = { 12, 12, 12, 12, 15, 16 }; + if (FRQ > 8) + return 16; + return frq_mod_map[FRQ - 3]; +} + +static u8 get_WLO(u32 tCK) +{ + /* Get WLO based on MCU frequency using the following rule: + * _______________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * WLO : | 4 | 5 | 6 | 6 | 8 | 8 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u8 frq_wlo_map[] = { 4, 5, 6, 6, 8, 8 }; + if (FRQ > 8) + return 8; + return frq_wlo_map[FRQ - 3]; +} + +static u8 get_CKE(u32 tCK) +{ + /* Get CKE based on MCU frequency using the following rule: + * _______________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * CKE : | 3 | 3 | 4 | 4 | 5 | 6 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u8 frq_cke_map[] = { 3, 3, 4, 4, 5, 6 }; + if (FRQ > 8) + return 6; + return frq_cke_map[FRQ - 3]; +} + +static u8 get_XPDLL(u32 tCK) +{ + /* Get XPDLL based on MCU frequency using the following rule: + * _____________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * XPDLL : | 10 | 13 | 16 | 20 | 23 | 26 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u8 frq_xpdll_map[] = { 10, 13, 16, 20, 23, 26 }; + if (FRQ > 8) + return 26; + return frq_xpdll_map[FRQ - 3]; +} + +static u8 get_XP(u32 tCK) +{ + /* Get XP based on MCU frequency using the following rule: + * _______________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * XP : | 3 | 4 | 4 | 5 | 6 | 7 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u8 frq_xp_map[] = { 3, 4, 4, 5, 6, 7 }; + if (FRQ > 8) + return 7; + return frq_xp_map[FRQ - 3]; +} + +static u8 get_AONPD(u32 tCK) +{ + /* Get AONPD based on MCU frequency using the following rule: + * ________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * AONPD : | 4 | 5 | 6 | 8 | 8 | 10 | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u8 frq_aonpd_map[] = { 4, 5, 6, 8, 8, 10 }; + if (FRQ > 8) + return 10; + return frq_aonpd_map[FRQ - 3]; +} + +static u32 get_COMP2(u32 tCK) +{ + /* Get COMP2 based on MCU frequency using the following rule: + * ___________________________________________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * COMP : | D6BEDCC | CE7C34C | CA57A4C | C6369CC | C42514C | C21410C | + */ + u32 FRQ = (u32) 256000 / (tCK * BASEFREQ); + static const u32 frq_comp2_map[] = { 0xD6BEDCC, 0xCE7C34C, 0xCA57A4C, + 0xC6369CC, 0xC42514C, 0xC21410C + }; + if (FRQ > 8) + return 0xD6BEDCC; + return frq_comp2_map[FRQ - 3]; +} + +static void dram_timing(ramctr_timing * ctrl) +{ + u8 val; + u32 val32; + + /* Maximum supported DDR3 frequency is 1066MHz (DDR3 2133) so make sure + * we cap it if we have faster DIMMs. + * Then, align it to the closest JEDEC standard frequency */ + if (ctrl->tCK <= TCK_1066MHZ) { + ctrl->tCK = TCK_1066MHZ; + ctrl->delay1 = 16; + ctrl->delay2 = 8; + ctrl->edge_offset[0] = 16; + ctrl->edge_offset[1] = 7; + ctrl->edge_offset[2] = 7; + ctrl->timC_offset[0] = 18; + ctrl->timC_offset[1] = 7; + ctrl->timC_offset[2] = 7; + ctrl->reg_c14_offset = 16; + } else if (ctrl->tCK <= TCK_933MHZ) { + ctrl->tCK = TCK_933MHZ; + ctrl->delay1 = 15; + ctrl->delay2 = 8; + ctrl->edge_offset[0] = 14; + ctrl->edge_offset[1] = 6; + ctrl->edge_offset[2] = 6; + ctrl->timC_offset[0] = 15; + ctrl->timC_offset[1] = 6; + ctrl->timC_offset[2] = 6; + ctrl->reg_c14_offset = 14; + } else if (ctrl->tCK <= TCK_800MHZ) { + ctrl->tCK = TCK_800MHZ; + ctrl->delay1 = 12; + ctrl->delay2 = 6; + ctrl->edge_offset[0] = 13; + ctrl->edge_offset[1] = 5; + ctrl->edge_offset[2] = 5; + ctrl->timC_offset[0] = 14; + ctrl->timC_offset[1] = 5; + ctrl->timC_offset[2] = 5; + ctrl->reg_c14_offset = 12; + } else if (ctrl->tCK <= TCK_666MHZ) { + ctrl->tCK = TCK_666MHZ; + ctrl->delay1 = 12; + ctrl->delay2 = 6; + ctrl->edge_offset[0] = 10; + ctrl->edge_offset[1] = 4; + ctrl->edge_offset[2] = 4; + ctrl->timC_offset[0] = 11; + ctrl->timC_offset[1] = 4; + ctrl->timC_offset[2] = 4; + ctrl->reg_c14_offset = 10; + } else { + ctrl->tCK = TCK_533MHZ; + ctrl->delay1 = 12; + ctrl->delay2 = 5; + ctrl->edge_offset[0] = 8; + ctrl->edge_offset[1] = 3; + ctrl->edge_offset[2] = 3; + ctrl->timC_offset[0] = 9; + ctrl->timC_offset[1] = 3; + ctrl->timC_offset[2] = 3; + ctrl->reg_c14_offset = 8; + } + + val32 = (1000 << 8) / ctrl->tCK; + printram("Selected DRAM frequency: %u MHz\n", val32); + + /* Find CAS and CWL latencies */ + val = (ctrl->tAA + ctrl->tCK - 1) / ctrl->tCK; + printram("Minimum CAS latency : %uT\n", val); + /* Find lowest supported CAS latency that satisfies the minimum value */ + while (!((ctrl->cas_supported >> (val - 4)) & 1) + && (ctrl->cas_supported >> (val - 4))) { + val++; + } + /* Is CAS supported */ + if (!(ctrl->cas_supported & (1 << (val - 4)))) + printram("CAS not supported\n"); + printram("Selected CAS latency : %uT\n", val); + ctrl->CAS = val; + ctrl->CWL = get_CWL(ctrl->CAS); + printram("Selected CWL latency : %uT\n", ctrl->CWL); + + /* Find tRCD */ + ctrl->tRCD = (ctrl->tRCD + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tRCD : %uT\n", ctrl->tRCD); + + ctrl->tRP = (ctrl->tRP + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tRP : %uT\n", ctrl->tRP); + + /* Find tRAS */ + ctrl->tRAS = (ctrl->tRAS + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tRAS : %uT\n", ctrl->tRAS); + + /* Find tWR */ + ctrl->tWR = (ctrl->tWR + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tWR : %uT\n", ctrl->tWR); + + /* Find tFAW */ + ctrl->tFAW = (ctrl->tFAW + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tFAW : %uT\n", ctrl->tFAW); + + /* Find tRRD */ + ctrl->tRRD = (ctrl->tRRD + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tRRD : %uT\n", ctrl->tRRD); + + /* Find tRTP */ + ctrl->tRTP = (ctrl->tRTP + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tRTP : %uT\n", ctrl->tRTP); + + /* Find tWTR */ + ctrl->tWTR = (ctrl->tWTR + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tWTR : %uT\n", ctrl->tWTR); + + /* Refresh-to-Active or Refresh-to-Refresh (tRFC) */ + ctrl->tRFC = (ctrl->tRFC + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tRFC : %uT\n", ctrl->tRFC); + + ctrl->tRC = (ctrl->tRC + ctrl->tCK - 1) / ctrl->tCK; + printram("Required tRC : %uT\n", ctrl->tRC); + + ctrl->tREFI = get_REFI(ctrl->tCK); + ctrl->tMOD = get_MOD(ctrl->tCK); + ctrl->tXSOffset = get_XSOffset(ctrl->tCK); + ctrl->tWLO = get_WLO(ctrl->tCK); + ctrl->tCKE = get_CKE(ctrl->tCK); + ctrl->tXPDLL = get_XPDLL(ctrl->tCK); + ctrl->tXP = get_XP(ctrl->tCK); + ctrl->tAONPD = get_AONPD(ctrl->tCK); +} + +static void dram_freq(ramctr_timing * ctrl) +{ + u8 val1, val2; + u32 reg1 = 0; + + /* Step 1 - Set target PCU frequency */ + + if (ctrl->tCK <= TCK_1066MHZ) { + val1 = 0x08; + ctrl->tCK = TCK_1066MHZ; + } else if (ctrl->tCK <= TCK_933MHZ) { + val1 = 0x07; + ctrl->tCK = TCK_933MHZ; + } else if (ctrl->tCK <= TCK_800MHZ) { + val1 = 0x06; + ctrl->tCK = TCK_800MHZ; + } else if (ctrl->tCK <= TCK_666MHZ) { + val1 = 0x05; + ctrl->tCK = TCK_666MHZ; + } else { + val1 = 0x04; + ctrl->tCK = TCK_533MHZ; + } + + /* Step 2 - Select frequency in the MCU */ + reg1 = val1; + reg1 |= 0x80000000; // set running bit + MCHBAR32(0x5e00) = reg1; + while (reg1 >> 0x1f) { + printram(" PLL busy..."); + reg1 = MCHBAR32(0x5e00); + } + printram("done\n"); + + /* Step 3 - Verify lock frequency */ + reg1 = MCHBAR32(0x5e04); + val2 = (u8) reg1; + if (val2 > val1) { + printram("Lock frequency is lower, recalculating\n"); + switch (val2) { + case 8: + ctrl->tCK = TCK_1066MHZ; + break; + case 7: + ctrl->tCK = TCK_933MHZ; + break; + case 6: + ctrl->tCK = TCK_800MHZ; + break; + case 5: + ctrl->tCK = TCK_666MHZ; + break; + case 4: + ctrl->tCK = TCK_533MHZ; + break; + default: + printram("ERROR: PLL is off or unknown\n"); + break; + } + dram_timing(ctrl); // recalculate timings + } + printram("MCU frequency is set at : %d MHz\n", (1000 << 8) / ctrl->tCK); +} + +static void dram_xover(ramctr_timing * ctrl) +{ + size_t ch; + u32 reg, addr; + u8 rmap; + for (ch = 0; ch < 2; ch++) { + // enable xover clk + reg = 0; + rmap = (ctrl->rankmap[ch][0] | (ctrl->rankmap[ch][1] << 2)); + reg = (reg & ~0xf000000) | (rmap << 24); + addr = (ch == 0) ? 0xc14 : 0xd14; + printram ("[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + + // enable xover ctl + reg = 0; + if ((ctrl->rankmap[ch][0] & 0x1) || (ctrl->rankmap[ch][1] & 0x1)) { + reg = (reg & ~0x20000) | (1 << 0x11); + } + if ((ctrl->rankmap[ch][0] & 0x2) || (ctrl->rankmap[ch][1] & 0x2)) { + reg = (reg & ~0x4000000) | (1 << 0x1a); + } + // enable xover cmd + reg = (reg & ~0x4000) | (1 << 14); + addr = (ch == 0) ? 0x320c : 0x330c; + printram ("[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + } +} + +static void dram_timing_regs(ramctr_timing * ctrl) +{ + size_t ch; + u32 reg, addr, val32, cpu, stretch; + u8 val; + struct cpuid_result cpures; + + for (ch = 0; ch < 2; ch++) { + // DBP + reg = 0; + val = ctrl->tRCD; + reg = (reg & ~0xf) | val; + val = ctrl->tRP; + reg = (reg & ~0xf0) | (val << 0x4); + val = ctrl->CAS; + reg = (reg & ~0xf00) | (val << 0x8); + val = ctrl->CWL; + reg = (reg & ~0xf000) | (val << 0xc); + val = ctrl->tRAS; + reg = (reg & ~0xff0000) | (val << 0x10); + addr = (ch == 0 ? 0x4000 : 0x4400); + printram ("[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + + // RAP + reg = 0; + val = ctrl->tRRD; + reg = (reg & ~0xf) | val; + val = ctrl->tRTP; + reg = (reg & ~0xf0) | (val << 0x4); + val = ctrl->tCKE; + reg = (reg & ~0xf00) | (val << 0x8); + val = ctrl->tWTR; + reg = (reg & ~0xf000) | (val << 0xc); + val = ctrl->tFAW; + reg = (reg & ~0xff0000) | (val << 0x10); + val = ctrl->tWR; + reg = (reg & ~0x1f000000) | (val << 0x18); + reg = (reg & ~0xc0000000) | (3 << 30); + addr = (ch == 0 ? 0x4004 : 0x4404); + printram ("[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + + // OTHP + addr = (ch == 0 ? 0x400c : 0x440c); + reg = MCHBAR32(addr); + val = ctrl->tXPDLL; + reg = (reg & ~0x1f) | val; + val = ctrl->tXP; + reg = (reg & ~0xe0) | (val << 0x5); + val = ctrl->tAONPD; + reg = (reg & ~0xf00) | (val << 0x8); + printram ("[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + + MCHBAR32(ch == 0 ? 0x4014 : 0x4414) = 0; + + MCHBAR32(addr) |= 0x00020000; + + + // ODT stretch + reg = 0; + + cpures = cpuid(0); + cpu = cpures.eax; + if (IS_IVY_CPU(cpu) + || (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_D2(cpu))) { + stretch = 2; + addr = (ch == 0 ? 0x400c : 0x440c); + printram ("[%x] = %x\n", addr, reg); + reg = MCHBAR32(addr); + + if ((ctrl->rankmap[ch][0] == 0) || + ctrl->rankmap[ch][1] == 0) { + + // Rank 0 - operate on rank 2 + reg = (reg & ~0xc0000) | (stretch << 0x12); + + // Rank 2 - operate on rank 0 + reg = (reg & ~0x30000) | (stretch << 0x10); + + addr = (ch == 0 ? 0x400c : 0x440c); + printram ("[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + } + + } else if (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_C(cpu)) { + stretch = 3; + addr = (ch == 0 ? 0x401c : 0x441c); + reg = MCHBAR32(addr); + + if ((ctrl->rankmap[ch][0] == 0) || + ctrl->rankmap[ch][1] == 0) { + + // Rank 0 - operate on rank 2 + reg = (reg & ~0x3000) | (stretch << 0xc); + + // Rank 2 - operate on rank 0 + reg = (reg & ~0xc00) | (stretch << 0xa); + + addr = (ch == 0 ? 0x401c : 0x441c); + printram ("[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; } - die("Nonzero MRC return value.\n"); + } else { + stretch = 0; + } + + // REFI + reg = 0; + val32 = ctrl->tREFI; + reg = (reg & ~0xffff) | val32; + val32 = ctrl->tRFC; + reg = (reg & ~0x1ff0000) | (val32 << 0x10); + val32 = (u32) (ctrl->tREFI * 9) / 1024; + reg = (reg & ~0xfe000000) | (val32 << 0x19); + addr = (ch == 0 ? 0x4298 : 0x4698); + printram ("[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + + addr = (ch == 0 ? 0x4294 : 0x4694); + MCHBAR32(addr) |= 0xff; + + // SRFTP + reg = 0; + val32 = tDLLK; + reg = (reg & ~0xfff) | val32; + val32 = ctrl->tXSOffset; + reg = (reg & ~0xf000) | (val32 << 0xc); + val32 = tDLLK - ctrl->tXSOffset; + reg = (reg & ~0x3ff0000) | (val32 << 0x10); + val32 = ctrl->tMOD - 8; + reg = (reg & ~0xf0000000) | (val32 << 0x1c); + addr = (ch == 0 ? 0x42a4 : 0x46a4); + printram ("[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + } +} + +static void dram_dimm_mapping(dimm_info * info, ramctr_timing * ctrl) +{ + size_t ch; + int t; + u32 reg, addr, val32; + for (ch = 0; ch < 2; ch++) { + dimm_attr *dimmA = 0; + dimm_attr *dimmB = 0; + reg = 0; + val32 = 0; + addr = 0; + if (info->dimm[2 * ch].size_mb >= + info->dimm[2 * ch + 1].size_mb) { + // dimm 0 is bigger, set it to dimmA + dimmA = &info->dimm[2 * ch]; + dimmB = &info->dimm[2 * ch + 1]; + reg = (reg & ~0x10000) | (0 << 0x10); + } else { + // dimm 1 is bigger, set it to dimmA + dimmA = &info->dimm[2 * ch + 1]; + dimmB = &info->dimm[2 * ch]; + reg = (reg & ~0x10000) | (1 << 0x10); + // swap dimm info + t = ctrl->rank_mirror[ch][1]; + ctrl->rank_mirror[ch][1] = ctrl->rank_mirror[ch][3]; + ctrl->rank_mirror[ch][3] = t; + } + // dimmA + if (dimmA && (dimmA->ranks > 0)) { + val32 = dimmA->size_mb / 256; + reg = (reg & ~0xff) | val32; + val32 = dimmA->ranks - 1; + reg = (reg & ~0x20000) | (val32 << 0x11); + val32 = (dimmA->width / 8) - 1; + reg = (reg & ~0x80000) | (val32 << 0x13); + } + // dimmB + if (dimmB && (dimmB->ranks > 0)) { + val32 = dimmB->size_mb / 256; + reg = (reg & ~0xff00) | (val32 << 0x8); + val32 = dimmB->ranks - 1; + reg = (reg & ~0x40000) | (val32 << 0x12); + val32 = (dimmB->width / 8) - 1; + reg = (reg & ~0x100000) | (val32 << 0x14); } + reg = (reg & ~0x200000) | (1 << 0x15); // rank interleave + reg = (reg & ~0x400000) | (1 << 0x16); // enhanced interleave + + // Set MAD-DIMM register + addr = 0x5004 + ch * 4; + if ((dimmA && (dimmA->ranks > 0)) || + (dimmB && (dimmB->ranks > 0))) { + MCHBAR32(addr) = reg; + } + } +} + +static void dram_zones(dimm_info * info, ramctr_timing * ctrl, int training) +{ + u32 reg, ch0size, ch1size; + u8 val; + reg = 0; + val = 0; + if (training) { + ch0size = info->dimm[0].size_mb + info->dimm[1].size_mb ? 256 : 0; + ch1size = info->dimm[2].size_mb + info->dimm[3].size_mb ? 256 : 0; } else { - die("UEFI PEI System Agent not found.\n"); + ch0size = info->dimm[0].size_mb + info->dimm[1].size_mb; + ch1size = info->dimm[2].size_mb + info->dimm[3].size_mb; } -#if CONFIG_USBDEBUG_IN_ROMSTAGE - /* mrc.bin reconfigures USB, so reinit it to have debug */ - usbdebug_init(); -#endif + if (ch0size >= ch1size) { + reg = MCHBAR32(0x5000); + reg = (reg & ~0xf) | 4; + MCHBAR32(0x5000) = reg; - /* For reference print the System Agent version - * after executing the UEFI PEI stage. - */ - u32 version = MCHBAR32(0x5034); - printk(BIOS_DEBUG, "System Agent Version %d.%d.%d Build %d\n", - version >> 24 , (version >> 16) & 0xff, - (version >> 8) & 0xff, version & 0xff); - - /* Send ME init done for SandyBridge here. This is done - * inside the SystemAgent binary on IvyBridge. */ - if (BASE_REV_SNB == - (pci_read_config16(PCI_CPU_DEVICE, PCI_DEVICE_ID) & BASE_REV_MASK)) - intel_early_me_init_done(ME_INIT_STATUS_SUCCESS); - else - intel_early_me_status(); + reg = MCHBAR32(0x5014); + val = ch1size / 256; + reg = (reg & ~0xff000000) | val << 24; + reg = (reg & ~0xff0000) | (2 * val) << 16; + MCHBAR32(0x5014) = reg; + } else { + reg = MCHBAR32(0x5000); + reg = (reg & ~0xf) | 1; + MCHBAR32(0x5000) = reg; + + reg = MCHBAR32(0x5014); + val = ch0size / 256; + reg = (reg & ~0xff000000) | val << 24; + reg = (reg & ~0xff0000) | (2 * val) << 16; + MCHBAR32(0x5014) = reg; + } + + reg = MCHBAR32(0x5000); + reg = (reg & ~0x18) | (1 << 4); + MCHBAR32(0x5000) = reg; +} + +/* FIXME: this function bugs. */ +static void dram_memorymap(dimm_info * info, int me_uma_size) +{ + u32 reg, val, reclaim; + u32 tom, gfxstolen, gttsize; + size_t tsegsize, mmiosize, toludbase, touudbase, gfxstolenbase, gttbase, + tsegbase, mestolenbase; + size_t tsegbasedelta, remapbase, remaplimit; + + // FIXME: Make these configurable + gfxstolen = 128; + gttsize = 1; + mmiosize = 0x400; + // + + tsegsize = CONFIG_SMM_TSEG_SIZE >> 20; + + tom = info->dimm[0].size_mb + info->dimm[1].size_mb + + info->dimm[2].size_mb + info->dimm[3].size_mb; + + mestolenbase = tom - me_uma_size; + + toludbase = MIN(4096 - mmiosize, tom - me_uma_size); + gfxstolenbase = toludbase - gfxstolen; + gttbase = gfxstolenbase - gttsize; + + tsegbase = gttbase - tsegsize; + + // Round tsegbase down to nearest address aligned to tsegsize + tsegbasedelta = tsegbase & (tsegsize - 1); + tsegbase &= ~(tsegsize - 1); + + gttbase -= tsegbasedelta; + gfxstolenbase -= tsegbasedelta; + toludbase -= tsegbasedelta; + + // Test if it is possible to reclaim a hole in the ram addressing + if (tom - me_uma_size > toludbase) { + // Reclaim is possible + reclaim = 1; + remapbase = MAX(4096, tom - me_uma_size); + remaplimit = remapbase + + MIN(4096, tom - me_uma_size) - toludbase - 1; + touudbase = remaplimit + 1; + } else { + // Reclaim not possible + reclaim = 0; + touudbase = tom - me_uma_size; + } + + // Update memory map in pci-e configuration space + + // TOM (top of memory) + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xa0); + val = tom & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printram ("PCI:[%x] = %x\n", 0xa0, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xa0, reg); + + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xa4); + val = tom & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printram ("PCI:[%x] = %x\n", 0xa4, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xa4, reg); + + // TOLUD (top of low used dram) + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xbc); + val = toludbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printram ("PCI:[%x] = %x\n", 0xbc, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xbc, reg); + + // TOUUD MSB (top of upper usable dram) + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xa8); + val = touudbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printram ("PCI:[%x] = %x\n", 0xa8, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xa8, reg); + + // TOUUD LSB + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xac); + val = touudbase & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printram ("PCI:[%x] = %x\n", 0xac, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xac, reg); + + if (reclaim) { + // REMAP BASE + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x94); + val = remapbase & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printram ("PCI:[%x] = %x\n", 0x94, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x94, reg); + + // REMAP LIMIT + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x98); + val = remaplimit & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printram ("PCI:[%x] = %x\n", 0x98, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x98, reg); + + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x9c); + val = remaplimit & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printram ("PCI:[%x] = %x\n", 0x9c, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x9c, reg); + } + // TSEG + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xb8); + val = tsegbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printram ("PCI:[%x] = %x\n", 0xb8, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xb8, reg); + + // GFX stolen memory + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xb0); + val = gfxstolenbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printram ("PCI:[%x] = %x\n", 0xb0, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xb0, reg); + + // GTT stolen memory + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xb4); + val = gttbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printram ("PCI:[%x] = %x\n", 0xb4, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xb4, reg); + + if (me_uma_size) { + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x7c); + val = (0x80000 - me_uma_size) & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printram ("PCI:[%x] = %x\n", 0x7c, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x7c, reg); + + // ME base + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x70); + val = mestolenbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printram ("PCI:[%x] = %x\n", 0x70, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x70, reg); + + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x74); + val = mestolenbase & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printram ("PCI:[%x] = %x\n", 0x74, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x74, reg); + + // ME mask + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x78); + val = (0x80000 - me_uma_size) & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + reg = (reg & ~0x400) | (1 << 10); // set lockbit on ME mem + + reg = (reg & ~0x800) | (1 << 11); // set ME memory enable + printram ("PCI:[%x] = %x\n", 0x78, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x78, reg); + } +} + +static void dram_ioregs(ramctr_timing * ctrl) +{ + u32 reg, ch0rank, ch1rank, comp2; + + int channel; + + ch0rank = ctrl->rankmap[0][0] | (ctrl->rankmap[0][1] << 2); + ch1rank = ctrl->rankmap[1][0] | (ctrl->rankmap[1][1] << 2); + + // IO clock + MCHBAR32(0xc00) = ch0rank; + MCHBAR32(0xd00) = ch1rank; + + // IO command + MCHBAR32(0x3200) = ch0rank; + MCHBAR32(0x3300) = ch1rank; + + // IO control + FOR_ALL_POPULATED_CHANNELS { + program_timings (ctrl, channel); + } + + // Rcomp + printram("RCOMP..."); + reg = 0; + while (reg == 0) { + reg = MCHBAR32(0x5084) & 0x10000; + } + printram("done\n"); + + // Set comp2 + comp2 = get_COMP2(ctrl->tCK); + MCHBAR32(0x3714) = comp2; + printram("COMP2 done\n"); + + // Set comp1 + FOR_ALL_POPULATED_CHANNELS { + reg = MCHBAR32(0x1810 + channel * 0x100); //ch0 + reg = (reg & ~0xe00) | (1 << 0x9); //odt + reg = (reg & ~0xe00000) | (1 << 0x15); //clk drive up + reg = (reg & ~0x38000000) | (1 << 0x1b); //ctl drive up + MCHBAR32(0x1810 + channel * 0x100) = reg; + } + printram("COMP1 done\n"); + + printram("FORCE RCOMP and wait 20us..."); + reg = MCHBAR32(0x5f08); + reg = (reg & ~0x100) | (1 << 0x8); + MCHBAR32(0x5f08) = reg; + udelay(20); + printram("done\n"); +} + +static void dram_jedecreset(ramctr_timing * ctrl) +{ + u32 reg, addr, rmap, rank; + u8 ch, chw; + + while ( !(MCHBAR32(0x5084) & 0x10000) ); + do { + reg = MCHBAR32(0x428c); + } while ((reg & 0x14) == 0); + + // Set state of memory controller + reg = 0x112; + addr = 0x5030; + MCHBAR32(addr) = reg; + MCHBAR32(0x4ea0) = 0; + reg = (reg & ~0x2) | (1 << 0x1); //ddr reset + MCHBAR32(addr) = reg; + + // Assert dimm reset signal + reg = MCHBAR32(addr); + reg &= ~0x2; + MCHBAR32(addr) = reg; + + // Wait 200us + udelay(200); + + // Deassert dimm reset signal + reg = MCHBAR32(addr); + reg = (reg & ~0x2) | (1 << 0x1); + MCHBAR32(addr) = reg; + + // Wait 500us + udelay(500); + + // Enable DCLK + reg = MCHBAR32(addr); + reg = (reg & ~0x4) | (1 << 0x2); + MCHBAR32(addr) = reg; + + // XXX Wait 20ns + udelay(1); + + for (ch = 0; ch < 2; ch++) { + // Set valid rank CKE + reg = 0; + rmap = ctrl->rankmap[ch][0] | (ctrl->rankmap[ch][1] << 2); + reg = (reg & ~0xf) | rmap; + addr = (ch == 0) ? 0x42a0 : 0x46a0; + MCHBAR32(addr) = reg; + + // Wait 10ns for ranks to settle + //udelay(0.01); + + reg = (reg & ~0xf0) | (rmap << 0x4); + MCHBAR32(addr) = reg; + + // Write reset using a NOP + reg = 0; + chw = (ctrl->rankmap[0][0] | ctrl->rankmap[0][1]) ? 0 : 1; + rank = (ctrl->rankmap[chw][0]) ? 0 : 2; + addr = (chw == 0) ? 0x428c : 0x468c; + do { + reg = MCHBAR32(addr); + } while ((reg & 0x14) == 0); + + reg = 0; + reg = (reg & ~0xff) | 1; + reg = (reg & ~0x400000) | (1 << 0x16); + addr = (chw == 0) ? 0x4284 : 0x4684; + MCHBAR32(addr) = reg; + } +} + +static odtmap get_ODT(ramctr_timing * ctrl, u8 rank) +{ + /* Get ODT based on rankmap: */ + u8 dimms_per_ch, table; + u8 ch0dimmA, ch0dimmB, ch1dimmA, ch1dimmB; + static const odtmap odt_map[4][6] = { + {{60, 60}, {60, 60}, {120, 30}, {120, 30}, {120, 30}, + {120, 30}}, + {{0, 0}, {60, 60}, {0, 0}, {0, 0}, {120, 30}, {120, 30}}, + {{60, 60}, {60, 60}, {120, 30}, {120, 30}, {120, 30}, + {120, 30}}, + {{0, 0}, {60, 60}, {0, 0}, {120, 30}, {0, 0}, {120, 30}} + }; + ch0dimmA = (ctrl->rankmap[0][0] != 0) ? 1 : 0; + ch0dimmB = (ctrl->rankmap[0][1] != 0) ? 1 : 0; + ch1dimmA = (ctrl->rankmap[1][0] != 0) ? 1 : 0; + ch1dimmB = (ctrl->rankmap[1][1] != 0) ? 1 : 0; + + dimms_per_ch = (ch0dimmA + ch0dimmB > ch1dimmA + ch1dimmB) ? + ch0dimmA + ch0dimmB : ch1dimmA + ch1dimmB; + table = 0; + + if (dimms_per_ch == 1) { + if ((ctrl->rankmap[0][0] + | ctrl->rankmap[0][1] + | ctrl->rankmap[1][0] + | ctrl->rankmap[1][1]) != 3) { + table = 0; + } else { + table = 1; + } + } else if (dimms_per_ch == 2) { + if ((ctrl->rankmap[0][0] | ctrl->rankmap[0][1]) != 3) { + if ((ctrl->rankmap[1][0] | ctrl->rankmap[1][1]) != 3) { + table = 2; + } else { + table = 3; + } + } else { + if ((ctrl->rankmap[1][0] | ctrl->rankmap[1][1]) != 3) { + table = 4; + } else { + table = 5; + } + } + } else { + printram + ("Huh, no dimms? m00 = %d m01 = %d m10 = %d m11 = %d dpc = %d\n", + ctrl->rankmap[0][0], ctrl->rankmap[0][1], + ctrl->rankmap[1][0], ctrl->rankmap[1][1], dimms_per_ch); + die(""); + } + + return odt_map[rank][table]; +} + +static void +write_mrreg (ramctr_timing * ctrl, int channel, int slotrank, int reg, u32 val) +{ + u32 r32; + do { + r32 = MCHBAR32(0x428c + 0x400 * channel); + } while ((r32 & 0x50) == 0); + + printk (BIOS_ERR, "MRd: %x <= %x\n", reg, val); + + if (ctrl->rank_mirror[channel][slotrank]) { + reg = ((reg >> 1) & 1) | ((reg << 1) & 2); + val = (val & ~0x1f8) | ((val >> 1) & 0xa8) | ((val & 0xa8) << 1); + } + + printk (BIOS_ERR, "MRd: %x <= %x\n", reg, val); + + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f000); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | (reg << 20) | val | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f000); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x41001); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24) | (reg << 20) | val | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x0f000); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x1001 | (ctrl->delay1 << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24) | (reg << 20) | val | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x80001); +} + +static u32 make_mr0(ramctr_timing *ctrl, u8 rank) +{ + u16 mr0reg, mch_cas, mch_wr; + static const u8 mch_wr_t[12] = { 1, 2, 3, 4, 0, 5, 0, 6, 0, 7, 0, 0 }; + mr0reg = 0x100; + + // Convert CAS to MCH register friendly + if (ctrl->CAS < 12) { + mch_cas = (u16) ((ctrl->CAS - 4) << 1); + } else { + mch_cas = (u16) (ctrl->CAS - 12); + mch_cas = ((mch_cas << 1) | 0x1); + } + + // Convert tWR to MCH register friendly + mch_wr = mch_wr_t[ctrl->tWR - 5]; + + mr0reg = (mr0reg & ~0x4) | (mch_cas & 0x1); + mr0reg = (mr0reg & ~0x70) | ((mch_cas & 0xe) << 3); + mr0reg = (mr0reg & ~0xe00) | (mch_wr << 9); + // Fast (desktop) 0x1 or slow (mobile) 0x0 + mr0reg = (mr0reg & ~0x1000) | (!ctrl->mobile << 12); + return mr0reg; +} + +static void dram_mr0(ramctr_timing * ctrl, u8 rank) +{ + int channel; + + FOR_ALL_POPULATED_CHANNELS + write_mrreg (ctrl, channel, rank, 0, make_mr0 (ctrl, rank)); +} + +static u32 encode_odt(u32 odt) +{ + switch (odt) { + case 30: + return (1 << 9) | (1 << 2); // RZQ/8, RZQ/4 + case 60: + return (1 << 2); // RZQ/4 + case 120: + return (1 << 6); // RZQ/2 + default: + case 0: + return 0; + } +} + +static u32 make_mr1(ramctr_timing * ctrl, u8 rank) +{ + odtmap odt; + u32 mr1reg; + + odt = get_ODT(ctrl, rank); + mr1reg = 0x2; + + mr1reg |= encode_odt (odt.rttnom); + + return mr1reg; +} + +static void dram_mr1(ramctr_timing * ctrl, u8 rank) +{ + u16 mr1reg; + u8 ch; + + mr1reg = make_mr1(ctrl, rank); + + for (ch = 0; ch < 2; ch++) { + write_mrreg (ctrl, ch, rank, 1, mr1reg); + } +} + +static void dram_mr2(ramctr_timing * ctrl, u8 rank) +{ + u16 pasr, cwl, asr, str, mr2reg; + u8 ch; + odtmap odt; + + pasr = 0; + cwl = ctrl->CWL - 5; + asr = + (ctrl->thermalrefresh & 0x1) & ((ctrl->thermalrefresh & 0x4) >> 2); + /* FIXME: compute STR. */ + str = 1; + odt = get_ODT(ctrl, rank); + + mr2reg = 0; + mr2reg = (mr2reg & ~0x7) | pasr; + mr2reg = (mr2reg & ~0x38) | (cwl << 0x3); + mr2reg = (mr2reg & ~0x40) | (asr << 0x6); + mr2reg = (mr2reg & ~0x80) | (str << 0x7); + mr2reg |= (odt.rttwr / 60) << 9; + + for (ch = 0; ch < 2; ch++) { + write_mrreg (ctrl, ch, rank, 2, mr2reg); + } +} + +static void dram_mr3(ramctr_timing * ctrl, u8 rank) +{ + u16 mr3reg; + u8 ch; + + mr3reg = 0; + + for (ch = 0; ch < 2; ch++) { + write_mrreg (ctrl, ch, rank, 3, mr3reg); + } +} + +static void dram_mrscommands(ramctr_timing * ctrl) +{ + u8 rank, ch; + u32 reg, addr; + + for (rank = 0; rank < 4; rank++) { + // MR2 + printram("MR2 rank %d...", rank); + dram_mr2(ctrl, rank); + printram("done\n"); + + // MR3 + printram("MR3 rank %d...", rank); + dram_mr3(ctrl, rank); + printram("done\n"); + + // MR1 + printram("MR1 rank %d...", rank); + dram_mr1(ctrl, rank); + printram("done\n"); + + // MR0 + printram("MR0 rank %d...", rank); + dram_mr0(ctrl, rank); + printram("done\n"); + } + + write32 (DEFAULT_MCHBAR + 0x4e20, 0x7); + write32 (DEFAULT_MCHBAR + 0x4e30, 0xf1001); + write32 (DEFAULT_MCHBAR + 0x4e00, 0x60002); + write32 (DEFAULT_MCHBAR + 0x4e10, 0); + write32 (DEFAULT_MCHBAR + 0x4e24, 0x1f003); + write32 (DEFAULT_MCHBAR + 0x4e34, 0x1901001); + write32 (DEFAULT_MCHBAR + 0x4e04, 0x60400); + write32 (DEFAULT_MCHBAR + 0x4e14, 0x288); + write32 (DEFAULT_MCHBAR + 0x4e84, 0x40004); + + // Drain + for (ch = 0; ch < 2; ch++) { + // Wait for ref drained + addr = (ch == 0) ? 0x428c : 0x468c; + do { + reg = MCHBAR32(addr); + } while ((reg & 0x50) == 0); + } + + // Refresh enable + reg = MCHBAR32(0x5030); + reg = (reg & ~0x8) | (1 << 0x3); + MCHBAR32(0x5030) = reg; + + for (ch = 0; ch < 2; ch++) { + if ((ctrl->rankmap[ch][0] | ctrl->rankmap[ch][1]) != 0) { + addr = (ch == 0) ? 0x4020 : 0x4420; + reg = MCHBAR32(addr); + reg &= ~0x200000; + MCHBAR32(addr) = reg; + + addr = (ch == 0) ? 0x428c : 0x468c; + reg = MCHBAR32(addr); + + if ((reg & 0x10) == 0x10) { + printram("ERROR: Refresh enable failed\n"); + } else { + printram("Refresh enable worked\n"); + } + + rank = (ctrl->rankmap[ch][0] != 0) ? 0 : 2; + + // Drain + addr = (ch == 0) ? 0x428c : 0x468c; + do { + reg = MCHBAR32(addr); + } while ((reg & 0x50) == 0); + + write32 (DEFAULT_MCHBAR + 0x4220 + ch * 0x400, 0x0f003); + write32 (0x4230 + 0x400 * ch + DEFAULT_MCHBAR, 0x659001); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * ch, + (rank << 24) | (6 << 16)); + write32 (DEFAULT_MCHBAR + 0x4210 + ch * 0x400, 0x3e0); + + // Drain + addr = (ch == 0) ? 0x428c : 0x468c; + do { + reg = MCHBAR32(addr); + } while ((reg & 0x50) == 0); + } + } +} + +static void +wait_428c (int channel) +{ + while (1) + { + if (read32 (DEFAULT_MCHBAR | 0x428c | (channel << 10)) & 0x50) + return; + } +} + +const u32 lane_registers[] = {0x0000, 0x0200, 0x0400, 0x0600, + 0x1000, 0x1200, 0x1400, 0x1600, + 0x0800 }; + +static int +clamp (int val, int low, int up) +{ + if (val < low) + return low; + if (val > up) + return up; + return val; +} + +static void +program_timings (ramctr_timing *ctrl, int channel) +{ + u32 reg32, reg_4024, reg_c14, reg_c18, reg_4028; + int lane; + int slotrank, slot; + int full_shift = 0; + u16 slot320c[NUM_SLOTS]; + + FOR_ALL_POPULATED_RANKS + if (full_shift < -ctrl->timings[channel][slotrank].val_320c) + full_shift = -ctrl->timings[channel][slotrank].val_320c; + + for (slot = 0; slot < NUM_SLOTS; slot++) + switch (ctrl->rankmap[channel][slot]) + { + case 0: + default: + slot320c[slot] = 0x7f; + break; + case 1: + slot320c[slot] = ctrl->timings[channel][2 * slot + 0].val_320c + full_shift; + break; + case 2: + slot320c[slot] = ctrl->timings[channel][2 * slot + 1].val_320c + full_shift; + break; + case 3: + slot320c[slot] = (ctrl->timings[channel][2 * slot].val_320c + + ctrl->timings[channel][2 * slot + 1].val_320c) / 2 + full_shift; + break; + } + + reg32 = (1 << 17) | (1 << 14); + reg32 |= ((slot320c[0] & 0x3f) << 6) | ((slot320c[0] & 0x40) << 9); + reg32 |= (slot320c[1] & 0x7f) << 18; + reg32 |= (full_shift & 0x3f) | ((full_shift & 0x40) << 6); + + MCHBAR32(0x320c + 0x100 * channel) = reg32; + + reg_c14 = (ctrl->rankmap[channel][0] | (ctrl->rankmap[channel][1] << 2)) << 24; + reg_c18 = 0; + + FOR_ALL_POPULATED_RANKS + { + int shift = ctrl->timings[channel][slotrank].val_320c + full_shift; + int offset_val_c14; + if (shift < 0) + shift = 0; + offset_val_c14 = ctrl->reg_c14_offset + shift; + reg_c14 |= (offset_val_c14 & 0x3f) << (6 * slotrank); + reg_c18 |= ((offset_val_c14 >> 6) & 1) << slotrank; + } + + MCHBAR32 (0xc14 + channel * 0x100) = reg_c14; + MCHBAR32 (0xc18 + channel * 0x100) = reg_c18; + + reg_4028 = MCHBAR32 (0x4028 + channel * 0x400); + reg_4028 &= 0xffff0000; + + reg_4024 = 0; + + FOR_ALL_POPULATED_RANKS + { + int post_timA_min_high = 7, post_timA_max_high = 0; + int pre_timA_min_high = 7, pre_timA_max_high = 0; + int shift_402x = 0; + int shift = ctrl->timings[channel][slotrank].val_320c + full_shift; + + if (shift < 0) + shift = 0; + + FOR_ALL_LANES + { + if (post_timA_min_high > ((ctrl->timings[channel][slotrank].lanes[lane].timA + shift) >> 6)) + post_timA_min_high = ((ctrl->timings[channel][slotrank].lanes[lane].timA + shift) >> 6); + if (pre_timA_min_high > (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6)) + pre_timA_min_high = (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6); + if (post_timA_max_high < ((ctrl->timings[channel][slotrank].lanes[lane].timA + shift) >> 6)) + post_timA_max_high = ((ctrl->timings[channel][slotrank].lanes[lane].timA + shift) >> 6); + if (pre_timA_max_high < (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6)) + pre_timA_max_high = (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6); + } + + if (pre_timA_max_high - pre_timA_min_high < post_timA_max_high - post_timA_min_high) + shift_402x = +1; + else if (pre_timA_max_high - pre_timA_min_high > post_timA_max_high - post_timA_min_high) + shift_402x = -1; + + reg_4028 |= (ctrl->timings[channel][slotrank].val_4028 + shift_402x - post_timA_min_high) << (4 * slotrank); + reg_4024 |= (ctrl->timings[channel][slotrank].val_4024 + shift_402x) << (8 * slotrank); + + FOR_ALL_LANES + { + MCHBAR32 (lane_registers[lane] + 0x10 + 0x100 * channel + 4 * slotrank) + = (((ctrl->timings[channel][slotrank].lanes[lane].timA + shift) & 0x3f) + | ((ctrl->timings[channel][slotrank].lanes[lane].rising + shift) << 8) + | (((ctrl->timings[channel][slotrank].lanes[lane].timA + shift + - (post_timA_min_high << 6)) & 0x1c0) << 10) + | (ctrl->timings[channel][slotrank].lanes[lane].falling << 20)); + + MCHBAR32 (lane_registers[lane] + 0x20 + 0x100 * channel + 4 * slotrank) + = ((clamp(ctrl->timings[channel][slotrank].lanes[lane].timC + shift, 0, 127) & 0x3f) + | (((ctrl->timings[channel][slotrank].lanes[lane].timB + shift) & 0x3f) << 8) + | (((ctrl->timings[channel][slotrank].lanes[lane].timB + shift) & 0x1c0) << 9) + | ((clamp(ctrl->timings[channel][slotrank].lanes[lane].timC + shift, 0, 127) & 0x40) << 13)); + } + } + MCHBAR32 (0x4024 + channel * 0x400) = reg_4024; + MCHBAR32 (0x4028 + channel * 0x400) = reg_4028; +} + +static void +test_timA (ramctr_timing *ctrl, int channel, int slotrank) +{ + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, (0xc01 | (ctrl->delay1 << 16))); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x360004); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x4040c01); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x100f | ((ctrl->CAS + 36) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, (0xc01 | (ctrl->delay1 << 16))); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel, (slotrank << 24) | 0x360000); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c (channel); +} + +static int +does_lane_work(ramctr_timing *ctrl, int channel, int slotrank, int lane) +{ + u32 timA = ctrl->timings[channel][slotrank].lanes[lane].timA; + return ((read32 (DEFAULT_MCHBAR + lane_registers[lane] + + channel * 0x100 + 4 + ((timA / 32) & 1) * 4) + >> (timA % 32)) & 1); +} + +struct run +{ + int middle; + int end; + int start; + int all; +}; + +static struct run +get_longest_zero_run (int *seq, int sz) +{ + int i, ls; + int bl = 0, bs = 0; + struct run ret; + + ls = 0; + for (i = 0; i < 2 * sz; i++) + if (seq[i % sz]) + { + if (i - ls > bl) + { + bl = i - ls; + bs = ls; + } + ls = i + 1; + } + if (bl == 0) + { + ret.middle = sz / 2; + ret.start = 0; + ret.end = sz; + ret.all = 1; + return ret; + } + + ret.start = bs % sz; + ret.end = (bs + bl - 1) % sz; + ret.middle = (bs + (bl - 1) / 2) % sz; + ret.all = 0; + + return ret; +} + +static void +discover_timA_coarse (ramctr_timing *ctrl, int channel, int slotrank, int *upperA) +{ + int timA; + int statistics[NUM_LANES][128]; + int lane; + + for (timA = 0; timA < 128; timA++) { + FOR_ALL_LANES + ctrl->timings[channel][slotrank].lanes[lane].timA = timA; + program_timings (ctrl, channel); + + test_timA(ctrl, channel, slotrank); + + FOR_ALL_LANES { + statistics[lane][timA] = !does_lane_work (ctrl, channel, slotrank, lane); + printk(BIOS_ERR, "Astat: %d, %d, %d, %x, %x\n", channel, slotrank, lane, timA, + statistics[lane][timA]); + } + } + FOR_ALL_LANES + { + struct run rn = get_longest_zero_run (statistics[lane], 128); + ctrl->timings[channel][slotrank].lanes[lane].timA = rn.middle; + upperA[lane] = rn.end; + if (upperA[lane] < rn.middle) + upperA[lane] += 128; + printk(BIOS_ERR, "Aval: %d, %d, %d, %x\n", channel, slotrank, lane, ctrl->timings[channel][slotrank].lanes[lane].timA); + printk(BIOS_ERR, "Aend: %d, %d, %d, %x\n", channel, slotrank, lane, upperA[lane]); + } +} + +static void +discover_timA_fine (ramctr_timing *ctrl, int channel, int slotrank, int *upperA) +{ + int timA_delta; + int statistics[NUM_LANES][51]; + int lane, i; + + memset (statistics, 0, sizeof (statistics)); + + for (timA_delta = -25; timA_delta <= 25; timA_delta++) { + FOR_ALL_LANES + ctrl->timings[channel][slotrank].lanes[lane].timA = upperA[lane] + timA_delta + 0x40; + program_timings (ctrl, channel); + + for (i = 0; i < 100; i++) + { + test_timA(ctrl, channel, slotrank); + FOR_ALL_LANES { + statistics[lane][timA_delta + 25] += does_lane_work (ctrl, channel, slotrank, lane); + } + } + FOR_ALL_LANES { + printk(BIOS_ERR, "A+stat: %d, %d, %d, %d (%x), %x\n", channel, slotrank, lane, timA_delta, + upperA[lane] + timA_delta + 0x40, + statistics[lane][timA_delta + 25]); + } + } + FOR_ALL_LANES + { + int last_zero, first_all; + + for (last_zero = -25; last_zero <= 25; last_zero++) + if (statistics[lane][last_zero + 25]) + break; + last_zero--; + for (first_all = -25; first_all <= 25; first_all++) + if (statistics[lane][first_all + 25] == 100) + break; + + printk (BIOS_ERR, "lane %d: %d, %d\n", lane, last_zero, first_all); + + ctrl->timings[channel][slotrank].lanes[lane].timA = (last_zero + first_all) / 2 + upperA[lane]; + printk(BIOS_ERR, "Aval: %d, %d, %d, %x\n", channel, slotrank, lane, ctrl->timings[channel][slotrank].lanes[lane].timA); + } +} + +static void +discover_402x (ramctr_timing *ctrl, int channel, int slotrank, int *upperA) +{ + int works[NUM_LANES]; + int lane; + while (1) + { + int all_works = 1, some_works = 0; + program_timings (ctrl, channel); + test_timA(ctrl, channel, slotrank); + FOR_ALL_LANES + { + works[lane] = !does_lane_work(ctrl, channel, slotrank, lane); + if (works[lane]) + some_works = 1; + else + all_works = 0; + } + if (all_works) + return; + if (!some_works) { + if (ctrl->timings[channel][slotrank].val_4024 < 2) + die ("402x discovery failed"); + ctrl->timings[channel][slotrank].val_4024 -= 2; + printk (BIOS_ERR, "4024 -= 2;\n"); + continue; + } + ctrl->timings[channel][slotrank].val_4028 += 2; + printk (BIOS_ERR, "4028 += 2;\n"); + if (ctrl->timings[channel][slotrank].val_4028 >= 0x10) + die ("402x discovery failed"); + FOR_ALL_LANES + if (works[lane]) { + ctrl->timings[channel][slotrank].lanes[lane].timA += 128; + upperA[lane] += 128; + printk (BIOS_ERR, "increment %d, %d, %d\n", channel, slotrank, lane); + } + } +} + +struct timA_minmax +{ + int timA_min_high, timA_max_high; +}; + +static void +pre_timA_change (ramctr_timing *ctrl, int channel, int slotrank, struct timA_minmax *mnmx) +{ + int lane; + mnmx->timA_min_high = 7; + mnmx->timA_max_high = 0; + + FOR_ALL_LANES { + if (mnmx->timA_min_high > (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6)) + mnmx->timA_min_high = (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6); + if (mnmx->timA_max_high < (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6)) + mnmx->timA_max_high = (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6); + } +} + +static void +post_timA_change (ramctr_timing *ctrl, int channel, int slotrank, struct timA_minmax *mnmx) +{ + struct timA_minmax post; + int shift_402x = 0; + + /* Get changed maxima. */ + pre_timA_change (ctrl, channel, slotrank, &post); + + if (mnmx->timA_max_high - mnmx->timA_min_high < post.timA_max_high - post.timA_min_high) + shift_402x = +1; + else if (mnmx->timA_max_high - mnmx->timA_min_high > post.timA_max_high - post.timA_min_high) + shift_402x = -1; + else + shift_402x = 0; + + ctrl->timings[channel][slotrank].val_4028 += shift_402x; + ctrl->timings[channel][slotrank].val_4024 += shift_402x; + printk (BIOS_ERR, "4024 += %d;\n", shift_402x); + printk (BIOS_ERR, "4028 += %d;\n", shift_402x); +} + +static void +read_training (ramctr_timing *ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + { + u32 r32; + int all_high, some_high; + int upperA[NUM_LANES]; + struct timA_minmax mnmx; + + wait_428c (channel); + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x4230 + channel * 0x400, + 0xc01 | (ctrl->tRP << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + channel * 0x400, + (slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 1); + + write32 (DEFAULT_MCHBAR + 0x3400, (slotrank << 2) | 0x8001); + + ctrl->timings[channel][slotrank].val_4028 = 4; + ctrl->timings[channel][slotrank].val_4024 = 55; + program_timings (ctrl, channel); + + discover_timA_coarse (ctrl, channel, slotrank, upperA); + + all_high = 1; + some_high = 0; + FOR_ALL_LANES + if (ctrl->timings[channel][slotrank].lanes[lane].timA >= 0x40) + some_high = 1; + else + all_high = 0; + if (all_high) { + ctrl->timings[channel][slotrank].val_4028--; + printk (BIOS_ERR, "4028--;\n"); + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].timA -= 0x40; + upperA[lane] -= 0x40; + } + } else if (some_high) { + ctrl->timings[channel][slotrank].val_4024++; + ctrl->timings[channel][slotrank].val_4028++; + printk (BIOS_ERR, "4024++;\n"); + printk (BIOS_ERR, "4028++;\n"); + } + + program_timings (ctrl, channel); + + pre_timA_change (ctrl, channel, slotrank, &mnmx); + + discover_402x (ctrl, channel, slotrank, upperA); + + post_timA_change (ctrl, channel, slotrank, &mnmx); + pre_timA_change (ctrl, channel, slotrank, &mnmx); + + discover_timA_fine (ctrl, channel, slotrank,upperA); + + post_timA_change (ctrl, channel, slotrank, &mnmx); + pre_timA_change (ctrl, channel, slotrank, &mnmx); + + FOR_ALL_LANES + ctrl->timings[channel][slotrank].lanes[lane].timA -= mnmx.timA_min_high * 0x40; + ctrl->timings[channel][slotrank].val_4028 -= mnmx.timA_min_high; + printk (BIOS_ERR, "4028 -= %d;\n", mnmx.timA_min_high); + + post_timA_change (ctrl, channel, slotrank, &mnmx); + + printk (BIOS_ERR, "4/8: %d, %d, %x, %x\n", channel, slotrank, + ctrl->timings[channel][slotrank].val_4024, + ctrl->timings[channel][slotrank].val_4028); + + FOR_ALL_LANES + printk (BIOS_ERR, "%d, %d, %d, %x\n", channel, slotrank, lane, + ctrl->timings[channel][slotrank].lanes[lane].timA); + + write32 (DEFAULT_MCHBAR + 0x3400, 0); + + r32 = read32 (DEFAULT_MCHBAR + 0x5030); + write32 (DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay (1); + + write32 (DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay (1); + } + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + write32 (0x4080 + 4 * lane + 0x400 * channel + DEFAULT_MCHBAR, 0); +} + +static void +test_timC (ramctr_timing *ctrl, int channel, int slotrank) +{ + int lane; + + FOR_ALL_LANES + { + write32 (DEFAULT_MCHBAR + 0x4340 + channel * 0x400 + + 4 * lane, 0); + read32 (DEFAULT_MCHBAR + 0x4140 + channel * 0x400 + + 4 * lane); + } + + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f006); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, (max ((ctrl->tFAW >> 2) + 1, ctrl->tRRD) << 10) + | 4 | (ctrl->tRCD << 16)); + + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | (6 << 16)); + + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x244); + + write32 (DEFAULT_MCHBAR + 0x4224 + channel * 0x400, 0x1f207); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x8041001); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24) | 8); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f201); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x80411f4); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0x242); + + write32 (DEFAULT_MCHBAR + 0x422c + channel * 0x400, 0x1f207); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, 0x8000c01 + | ((ctrl->CWL + ctrl->tWTR + 5) << 16)); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel, (slotrank << 24) | 8); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 0xc0001); + + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0xc01 | (ctrl->tRP << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x240); + + write32 (DEFAULT_MCHBAR + 0x4224 + channel * 0x400, 0x1f006); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + (max (ctrl->tRRD, (ctrl->tFAW >> 2) + 1) << 10) + | 8 | (ctrl->CAS << 16)); + + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24) | 0x60000); + + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0x244); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x40011f4 | (max (ctrl->tRTP, 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0x242); + + write32 (DEFAULT_MCHBAR + 0x422c + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, 0xc01 | (ctrl->tRP << 16)); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0x240); + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 0xc0001); + wait_428c (channel); +} + +static void +discover_timC (ramctr_timing *ctrl, int channel, int slotrank) +{ + int timC; + int statistics[NUM_LANES][MAX_TIMC + 1]; + int lane; + + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0xc01 | (ctrl->tRP << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x240); + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 1); + + for (timC = 0; timC <= MAX_TIMC; timC++) { + FOR_ALL_LANES + ctrl->timings[channel][slotrank].lanes[lane].timC = timC; + program_timings (ctrl, channel); + + test_timC (ctrl, channel, slotrank); + + FOR_ALL_LANES + { + statistics[lane][timC] = read32 (DEFAULT_MCHBAR + 0x4340 + 4 * lane + + channel * 0x400); + printk(BIOS_ERR, "Cstat: %d, %d, %d, %x, %x\n", channel, slotrank, lane, timC, + statistics[lane][timC]); + } + } + FOR_ALL_LANES + { + struct run rn = get_longest_zero_run (statistics[lane], MAX_TIMC + 1); + ctrl->timings[channel][slotrank].lanes[lane].timC = rn.middle; + if (rn.all) + die ("timC discovery failed"); + printk(BIOS_ERR, "Cval: %d, %d, %d, %x\n", channel, slotrank, lane, ctrl->timings[channel][slotrank].lanes[lane].timC); + } +} + +static int +get_precedening_channels (ramctr_timing *ctrl, int target_channel) +{ + int channel, ret = 0; + FOR_ALL_POPULATED_CHANNELS + if (channel < target_channel) + ret++; + return ret; +} + +static void +fill_pattern0 (ramctr_timing *ctrl, int channel, u32 a, u32 b) +{ + unsigned j; + unsigned channel_offset = get_precedening_channels (ctrl, channel) * 0x40; + printk (BIOS_ERR, "channel_offset=%x\n", channel_offset); + for (j = 0 ; j < 16; j++) + write32 (0x04000000 + channel_offset + 4 * j, j & 2 ? b : a); + sfence (); +} +static int num_of_channels (const ramctr_timing *ctrl) +{ + int ret = 0; + int channel; + FOR_ALL_POPULATED_CHANNELS + ret++; + return ret; +} + +static void fill_pattern1 (ramctr_timing *ctrl, int channel) +{ + unsigned j; + unsigned channel_offset = get_precedening_channels (ctrl, channel) * 0x40; + unsigned channel_step = 0x40 * num_of_channels (ctrl); + for (j = 0 ; j < 16; j++) + write32 (0x04000000 + channel_offset + j * 4, 0xffffffff); + for (j = 0 ; j < 16; j++) + write32 (0x04000000 + channel_offset + channel_step + j * 4, 0); + sfence (); +} + +static void +precharge (ramctr_timing *ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_POPULATED_CHANNELS + { + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].falling = 16; + ctrl->timings[channel][slotrank].lanes[lane].rising = 16; + } + + program_timings (ctrl, channel); + + FOR_ALL_POPULATED_RANKS + { + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32 (0x4230 + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + channel * 0x400, (slotrank << 24) | 0x360004); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32 (0x4234 + 0x400 * channel + DEFAULT_MCHBAR, 0x4041003); + write32 (DEFAULT_MCHBAR + 0x4204 + channel * 0x400, (slotrank << 24) | 0); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32 (0x4238 + 0x400 * channel + DEFAULT_MCHBAR, 0x1001 | ((ctrl->CAS + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + channel * 0x400, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32 (0x423c + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + write32 (DEFAULT_MCHBAR + 0x420c + channel * 0x400, (slotrank << 24) | 0x360000); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c (channel); + } + + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].falling = 48; + ctrl->timings[channel][slotrank].lanes[lane].rising = 48; + } + + program_timings (ctrl, channel); + + FOR_ALL_POPULATED_RANKS + { + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32 (0x4230 + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + channel * 0x400, (slotrank << 24) | 0x360004); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32 (0x4234 + 0x400 * channel + DEFAULT_MCHBAR, 0x4041003); + write32 (DEFAULT_MCHBAR + 0x4204 + channel * 0x400, (slotrank << 24) | 0); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32 (0x4238 + 0x400 * channel + DEFAULT_MCHBAR, 0x1001 | ((ctrl->CAS + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + channel * 0x400, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32 (0x423c + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + + write32 (DEFAULT_MCHBAR + 0x420c + channel * 0x400, (slotrank << 24) | 0x360000); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + wait_428c (channel); + } + } +} + +static void +test_timB (ramctr_timing *ctrl, int channel, int slotrank) +{ + write_mrreg (ctrl, channel, slotrank, 1, 0x80 | make_mr1 (ctrl, slotrank)); + + wait_428c (channel); + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f207); + write32 (0x4230 + 0x400 * channel + DEFAULT_MCHBAR, 0x8000c01 + | ((ctrl->CWL + ctrl->delay2) << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, 8 | (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f107); + write32 (0x4234 + 0x400 * channel + DEFAULT_MCHBAR, 0x4000c01 | ((ctrl->CAS + 38) << 16)); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24) | 4); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x400 * channel + 0x4284, 0x40001); + wait_428c (channel); + + write_mrreg (ctrl, channel, slotrank, 1, 0x1080 | make_mr1 (ctrl, slotrank)); +} + +static void +discover_timB (ramctr_timing *ctrl, int channel, int slotrank) +{ + int timB; + int statistics[NUM_LANES][128]; + int lane; + + write32 (DEFAULT_MCHBAR + 0x3400, 0x108052 | (slotrank << 2)); + + for (timB = 0; timB < 128; timB++) { + FOR_ALL_LANES + ctrl->timings[channel][slotrank].lanes[lane].timB = timB; + program_timings (ctrl, channel); + + test_timB (ctrl, channel, slotrank); + + FOR_ALL_LANES { + statistics[lane][timB] = !((read32 (DEFAULT_MCHBAR + lane_registers[lane] + + channel * 0x100 + 4 + ((timB / 32) & 1) * 4) + >> (timB % 32)) & 1); + printk(BIOS_ERR, "Bstat: %d, %d, %d, %x, %x\n", channel, slotrank, lane, timB, + statistics[lane][timB]); + } + } + FOR_ALL_LANES + { + struct run rn = get_longest_zero_run (statistics[lane], 128); + ctrl->timings[channel][slotrank].lanes[lane].timB = rn.end; + if (rn.all) + die ("timB discovery failed"); + printk(BIOS_ERR, "Bval: %d, %d, %d, %x\n", channel, slotrank, lane, ctrl->timings[channel][slotrank].lanes[lane].timB); + } +} + +static int +get_timB_high_adjust (u64 val) +{ + int i; + if (val >= 0xfffffffffff00000LL) + return -1; + if (val >= 0xfffffff000000000LL) + return -2; + if (val >= 0xfff0000000000000LL) + return -3; + + for (i = 0; i < 8; i++) + if (val >> (8 * (7 - i) + 4)) + return i; + return 8; +} + +static void +adjust_high_timB (ramctr_timing *ctrl) +{ + int channel, slotrank, lane; + write32 (DEFAULT_MCHBAR + 0x3400, 0x200); + FOR_ALL_POPULATED_CHANNELS { + fill_pattern1 (ctrl, channel); + write32 (DEFAULT_MCHBAR | 0x4288 | (channel << 10), 1); + } + FOR_ALL_POPULATED_CHANNELS + FOR_ALL_POPULATED_RANKS { + + write32 (DEFAULT_MCHBAR + 0x4288 + channel * 0x400, 0x10001); + + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f006); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0xc01 | (ctrl->tRCD << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + channel * 0x400, 0x1f207); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x8040c01); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24) | 0x8); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f201); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x8041003); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0x3e2); + + write32 (DEFAULT_MCHBAR + 0x422c + channel * 0x400, 0x1f207); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16)); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel, (slotrank << 24) | 0x8); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 0xc0001); + + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0xc01 | ((ctrl->tRP) << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x240); + + write32 (DEFAULT_MCHBAR + 0x4224 + channel * 0x400, 0x1f006); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0xc01 | ((ctrl->tRCD) << 16)); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x3f105); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x4000c01 | ((ctrl->tRP + + ctrl->timings[channel][slotrank].val_4024 + + ctrl->timings[channel][slotrank].val_4028) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24) | 0x60008); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 0x80001); + wait_428c (channel); + FOR_ALL_LANES { + u64 res = read32 (DEFAULT_MCHBAR + lane_registers[lane] + 0x100 * channel + 4); + res |= ((u64)read32 (DEFAULT_MCHBAR + lane_registers[lane] + 0x100 * channel + 8)) << 32; + ctrl->timings[channel][slotrank].lanes[lane].timB += get_timB_high_adjust (res) * 64; + printk(BIOS_ERR, "Bval+: %d, %d, %d, %x\n", channel, slotrank, lane, ctrl->timings[channel][slotrank].lanes[lane].timB); + } + } + write32 (DEFAULT_MCHBAR + 0x3400, 0); +} + +static void +write_training (ramctr_timing *ctrl) +{ + int channel, slotrank, lane; + u32 r32; + + FOR_ALL_POPULATED_CHANNELS + write32 (DEFAULT_MCHBAR + 0x4008 + 0x400 * channel, + read32 (DEFAULT_MCHBAR + 0x4008 + 0x400 * channel) | 0x8000000); + + FOR_ALL_POPULATED_CHANNELS { + wait_428c (channel); + + /* choose an existing rank. */ + slotrank = !ctrl->rankmap[channel][0] ? 2 : 0; + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x0f003); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60000); + + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c (channel); + write32 (DEFAULT_MCHBAR + 0x4020 + channel * 0x400, + read32 (DEFAULT_MCHBAR + 0x4020 + channel * 0x400) | 0x200000); + } + write32 (DEFAULT_MCHBAR + 0x5030, + read32 (DEFAULT_MCHBAR + 0x5030) & ~8); + FOR_ALL_POPULATED_CHANNELS { + wait_428c (channel); + + /* choose an existing rank. */ + slotrank = !ctrl->rankmap[channel][0] ? 2 : 0; + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x0f003); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60000); + + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c (channel); + } + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + write_mrreg (ctrl, channel, slotrank, 1, make_mr1(ctrl, slotrank) | 0x1080); + + write32 (DEFAULT_MCHBAR + 0x3400, 0x108052); + + r32 = read32 (DEFAULT_MCHBAR + 0x5030); + write32 (DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay (1); + + write32 (DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay (1); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + discover_timB(ctrl, channel, slotrank); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + write_mrreg (ctrl, channel, slotrank, 1, make_mr1(ctrl, slotrank)); + + write32 (DEFAULT_MCHBAR + 0x3400, 0); + + FOR_ALL_POPULATED_CHANNELS + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x5030, read32 (DEFAULT_MCHBAR + 0x5030) | 8); + + FOR_ALL_POPULATED_CHANNELS + { + write32 (DEFAULT_MCHBAR + 0x4020 + channel * 0x400, + ~0x00200000 & read32 (DEFAULT_MCHBAR + 0x4020 + channel * 0x400)); + read32 (DEFAULT_MCHBAR + 0x428c + channel * 0x400); + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x0f003); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x659001); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, 0x60000); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 1); + wait_428c (channel); + } + + r32 = read32 (DEFAULT_MCHBAR + 0x5030); + write32 (DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay (1); + + write32 (DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay (1); + + printk (BIOS_ERR, "CPE\n"); + precharge (ctrl); + printk (BIOS_ERR, "CPF\n"); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + read32 (0x4080 + 4 * lane + 0x400 * channel + DEFAULT_MCHBAR); + write32 (0x4080 + 4 * lane + 0x400 * channel + DEFAULT_MCHBAR, 0); + } + + FOR_ALL_POPULATED_CHANNELS + { + fill_pattern0 (ctrl, channel, 0xaaaaaaaa, 0x55555555); + write32 (DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + } + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + discover_timC(ctrl, channel, slotrank); + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); + + adjust_high_timB(ctrl); + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + read32 (0x4080 + 4 * lane + 0x400 * channel + DEFAULT_MCHBAR); + write32 (0x4080 + 4 * lane + 0x400 * channel + DEFAULT_MCHBAR, 0); + } +} + +static int +test_320c (ramctr_timing *ctrl, int channel, int slotrank) +{ + struct ram_rank_timings saved_rt = ctrl->timings[channel][slotrank]; + int timC_delta; + int lanes_ok = 0; + int ctr = 0; + int lane; + + for (timC_delta = -5; timC_delta <= 5; timC_delta++) { + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].timC = saved_rt.lanes[lane].timC + timC_delta; + } + program_timings (ctrl, channel); + FOR_ALL_LANES + write32 (DEFAULT_MCHBAR + 4 * lane + 0x4f40, 0); + + write32 (DEFAULT_MCHBAR + 0x4288 + channel * 0x400, 0x1f); + + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f006); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, ((max (ctrl->tRRD, (ctrl->tFAW >> 2) + 1)) << 10) + | 8 | (ctrl->tRCD << 16)); + + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | ctr | 0x60000); + + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x244); + + write32 (DEFAULT_MCHBAR + 0x4224 + channel * 0x400, 0x1f201); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x8001020 | ((ctrl->CWL + ctrl->tWTR + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4244 + channel * 0x400, 0x389abcd); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0x20e42); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x4001020 | (max (ctrl->tRTP, 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4248 + channel * 0x400, 0x389abcd); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0x20e42); + + write32 (DEFAULT_MCHBAR + 0x422c + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, 0xf1001); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel, (slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0x240); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + wait_428c (channel); + FOR_ALL_LANES + { + u32 r32 = read32 (DEFAULT_MCHBAR + 0x4340 + 4 * lane + channel * 0x400); + + if (r32 == 0) + lanes_ok |= 1 << lane; + } + ctr++; + if (lanes_ok == ((1 << NUM_LANES) - 1)) + break; + } + + ctrl->timings[channel][slotrank] = saved_rt; + return lanes_ok != ((1 << NUM_LANES) - 1); +} + +const u32 pattern[][16] = { + { 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff }, + { 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000 }, + { 0xe62d6424, 0x9277e09e, 0x8f43dc3f, 0x76eae589, + 0x0010fdc6, 0xdc55e01c, 0x5effb0ab, 0x6cba5d29, + 0xa43d1e64, 0xab5c2e0f, 0x7796ed16, 0x96023bf4, + 0xa74c831d, 0x90f138c0, 0x17830a8a, 0x5ac17c47 }, + { 0x359ebbeb, 0x2b9b4512, 0xef584d98, 0x106bf7cb, + 0x363525ad, 0xb3a4dfdc, 0xa6b9fcd8, 0xd21689ec, + 0x84a3695b, 0xbd9c2e27, 0xdb3d0f44, 0x988158f1, + 0xcca91d3f, 0xb62a6d12, 0xe905e4cf, 0x7f1fa626 }, + { 0xe58efeae, 0xcd006081, 0xa9119403, 0xbcfbd35f, + 0x213b3bf7, 0x7bfcb773, 0xc85143f9, 0x0bdbff50, + 0xa3053c90, 0x51d66cb7, 0x296f4387, 0xb715f99e, + 0xfaddc989, 0xbb1de8a7, 0x39206b4d, 0x80174a57 }, + { 0xa1622ac1, 0xb4f4a5f0, 0x16dc2bc3, 0x50fb0954, + 0x2e261721, 0x52b82c3c, 0x821902b8, 0x0d4b6c38, + 0x1f618631, 0x047956f3, 0xd4337f5a, 0x591f8002, + 0x27f28db2, 0xfae37369, 0xb3f27580, 0x3cdb6397 }, + { 0x3dee23be, 0x19f36408, 0x227f4a6a, 0x024603c5, + 0xd5e062db, 0x6d8d4c5c, 0x7ff693b0, 0x76641be9, + 0x9e74f41c, 0xe7bc7f33, 0x2636f2e9, 0x70279750, + 0xce2355aa, 0x32d230ef, 0x22f9b468, 0xadd4e7a2 }, + { 0x936c0fed, 0xba0612d5, 0xa97c1ea7, 0x10e29d67, + 0x1c4c5dc8, 0x83645621, 0xcd8b521c, 0xb8301817, + 0xac7d6571, 0xcc41d200, 0x4ebdefdd, 0xd2917bde, + 0x60f75acc, 0x7791534b, 0x26ea2a83, 0x6b74513a }, + { 0xd1957b85, 0xc6f8f9ca, 0xf04fb4be, 0xfeb786fb, + 0xa1dea3aa, 0x67fe7db6, 0x25d49c87, 0xe3d54870, + 0x93dc1f86, 0x7d0c1a18, 0x9272e128, 0x68e1b876, + 0xce284c9e, 0x8fa18792, 0x5785a340, 0xb6fcf198 }, + { 0xff7d8e4a, 0x0c21ee43, 0xe820b388, 0xb4443c0e, + 0xa1e6e498, 0x5c426110, 0x1b434ef3, 0xbef05b91, + 0xa6907968, 0x53662ac3, 0x6defac32, 0x2c11c29c, + 0x6175cced, 0xb17dd3ad, 0x6e6a1076, 0x1372b1fa }, + { 0x4408ed06, 0x49460ffd, 0xb49d26cb, 0x6a3662a5, + 0x5e857047, 0xa387cd4a, 0x04edc81e, 0xfd94d8d4, + 0x2fe48d91, 0x9d2356bc, 0x96131878, 0xaca3fce4, + 0xbb312c6c, 0x5023b090, 0x3614be70, 0xa14dfabb }, + { 0xd4cc1e83, 0x757a1930, 0xc3d16a61, 0x9e0d6681, + 0x8a081fa9, 0xbd11c888, 0x1672f010, 0xa083f71c, + 0x1ec02eef, 0xc4586ca8, 0x6d322b35, 0x56054679, + 0x1552a0ff, 0x5cb7707e, 0xdfb55d4a, 0xcc76cc07 }, + { 0x507cf71f, 0x2166421a, 0x54be4af0, 0xfd42158c, + 0x417b1f7f, 0x9466860b, 0x3a0075bf, 0x2055575c, + 0xcedfe7ab, 0xbe85aa5f, 0x39d0c2e3, 0x851c19df, + 0x39a35a3f, 0x3fb10d7d, 0x20b14899, 0x703b7f08 }, + { 0x8a7d9dd1, 0x33235565, 0xbd3d2e57, 0xa48c2726, + 0x0d5e2e13, 0xae421ff9, 0x8784a224, 0xf66c1510, + 0x057627aa, 0x8fb0cb41, 0x4289975a, 0xb181adfa, + 0x59f2059a, 0xe86feb05, 0x84222fc1, 0x319b3ce9 }, + { 0xe1e243b8, 0x3b0bcc1a, 0x70396f00, 0x5caff44d, + 0xe96961b3, 0xad73f692, 0x8b841a2d, 0xf5838839, + 0xec9c9d04, 0xcc2b5562, 0xf8ca2549, 0xa9c52ff8, + 0x3b2fde68, 0x3d4dc7f0, 0xa57387d0, 0x051199ad }, + { 0x5f0ce4fc, 0xd830fbb7, 0x90abeb8f, 0x96d9cdbb, + 0x58f80a80, 0x0baaca36, 0x81a23623, 0x77127614, + 0xaa8382cd, 0x0922fbca, 0xd84d37e1, 0x721297df, + 0x160f3b3a, 0x10a1ecdc, 0x151c92f4, 0xc1fdcdab }, + { 0x261c45cc, 0xfeddd2da, 0xfc3cb1c1, 0x6639641f, + 0x2c011892, 0x7108bee2, 0x8545e0b9, 0x7dd36dab, + 0x07d91950, 0x1520adcb, 0xf84aa939, 0x07d9bb2d, + 0xdf1ed826, 0xaee3c814, 0x1dca1e81, 0xc8e9f486 }, + { 0x933d306a, 0xaab7103d, 0xa8be37be, 0x49612f3a, + 0xb0cf28e5, 0xf9648902, 0x106d7c11, 0xf32e1813, + 0x21af36ef, 0xe695e4c4, 0x7ee1831d, 0x2aeda467, + 0x99d0c655, 0x3f0691ab, 0xcd68f7c1, 0xb469a20e }, + { 0x8557aef0, 0x3eb0e373, 0x0853ac31, 0xe5bded62, + 0x3eddb0dd, 0x6bbf1caf, 0x2119c3d9, 0xe1732350, + 0x55456c75, 0xf6119375, 0x498dd1ad, 0x13f80916, + 0xb97f9f5e, 0x921d9f4c, 0xabdee367, 0x1d6bb8bf }, + { 0xd165a3be, 0xd8b41598, 0xa20e1809, 0xefd5c8ce, + 0x18935c80, 0xdf1911f9, 0xc9e449eb, 0xb887a4d7, + 0x4a324f6f, 0x533e8031, 0x1c21c074, 0xa95f1ea5, + 0x765b320a, 0x839d7dfb, 0xc7d3aa93, 0xe534ae3d }, + { 0xbe8592c8, 0x068457e6, 0x89b94fa3, 0xd522ad02, + 0x7e7db0b7, 0x2c5b896f, 0x9f8ecb37, 0x05b983ff, + 0x3fe9b25f, 0x34a6215b, 0x0592ba34, 0xd564f85a, + 0x156c426d, 0x25ad5460, 0xe7b5e8b7, 0xa73285c6 }, + { 0x5ad8d838, 0x27b42d36, 0xcc806ad1, 0x157a058a, + 0x7297735a, 0xffd6df8d, 0xff96f7a2, 0x155b27ea, + 0x84708101, 0x979fd78b, 0x49797d0c, 0x0dc93e3c, + 0x20287332, 0xed759f88, 0xe5068529, 0xb83aa781 }, + { 0xc38b302c, 0x57b54075, 0xac810692, 0xb0d493e7, + 0x4adda486, 0x0665ce2e, 0xb2a9c003, 0xafacc4ce, + 0x4d5e906d, 0xb3d52fab, 0xe6962c6b, 0x850f4dd1, + 0x5021656c, 0x5df6c06b, 0x9255125b, 0x2363c478 }, + { 0x188b715c, 0xe8b884b0, 0x5e6d0b9a, 0x1f0051e1, + 0xd2d35d4c, 0xbfeaecbe, 0xc84bb0ad, 0x67a232d6, + 0x99001587, 0xbf4313e1, 0x74f64061, 0x2c1fc562, + 0xb6fe8ca6, 0x5226a239, 0xf5198574, 0x61b51dca }, + { 0x51dcecd3, 0xbadbe596, 0xebe3e84a, 0x772bfdfc, + 0x03656ac5, 0xa7c36e91, 0x6cd32cf0, 0xc3f699dd, + 0x7d5aba01, 0x51e38e82, 0x23103a98, 0x20298b9d, + 0x19436510, 0x63ad7e6c, 0x8bc2b33f, 0x27079917 }, + { 0x8bd5be78, 0xf2403bfa, 0x780ebdb6, 0x94c53b64, + 0x6241c2e2, 0x5bfb081e, 0x6799e88f, 0xc997b7d1, + 0x466ac8b1, 0xbf5909da, 0x497ea39f, 0x402ffb48, + 0xd7470c2d, 0x8510aba9, 0x6c52a1c9, 0x812ca967 }, + { 0x031f7ab4, 0xd32fe890, 0x36ae6de5, 0x083dcde4, + 0x99a7f12f, 0xe44864a7, 0x02b75fff, 0xf25dda35, + 0x7679ff4f, 0xed421e01, 0xd9c2cfa1, 0xd36b4e82, + 0x5315d908, 0xc7ebcb2a, 0xb6f3e4c1, 0xf5bfbae9 }, + { 0x3f4a2a96, 0x64d8bd5a, 0x19acd70d, 0xf62fcdd9, + 0x5de99cdf, 0x32f3b7cb, 0x2c020578, 0x4e9bafb8, + 0x74919a08, 0xaba33e91, 0xa6bd2254, 0x2435a9b9, + 0x47e2a1b4, 0xe837a28e, 0xe113f1b0, 0x7654bd79 }, + { 0x05537a6c, 0x77be1a5c, 0x4c7492c9, 0x9086bfb0, + 0x257adc18, 0xf4787fc1, 0xe3fb6d53, 0x9525e589, + 0x445a65bc, 0x833f7d08, 0x69cf1f7e, 0x9a6372e1, + 0xceedb52e, 0x31032997, 0xd1c36828, 0x132772d6 }, + { 0x0a166972, 0x89beaf3b, 0x8d780fbc, 0x8aea5392, + 0x58347a41, 0x1e381ec2, 0xcc6280c8, 0xee0863e1, + 0x976e2dd2, 0x8c6ee6e2, 0xa0ca57cd, 0x95114a7d, + 0x3c096704, 0xa941769d, 0x2de20c05, 0x0bf8f812 }, + { 0x22779d6c, 0x94e12e8f, 0x5ce40299, 0xea1b55b0, + 0x9ebec05d, 0xe076cd2b, 0x8fef5648, 0x6a284c65, + 0xa790b705, 0xf0b19997, 0x0d8ca8af, 0x17440419, + 0xef4f702f, 0x33cbcbb1, 0x83d60f26, 0x48988397 }, + { 0x0fed7f53, 0xb5acbb67, 0xc031c73f, 0x5364d9ef, + 0xa6dbd12d, 0x82174a6c, 0xccf8e7ab, 0xc473c036, + 0xcff493d8, 0xad9afc3b, 0x316a24e8, 0x1842bea4, + 0x4cc0c82e, 0x28ccd91e, 0xd7311b5d, 0x50a89860 }, +}; + +static void fill_pattern5 (ramctr_timing *ctrl, int channel) +{ + unsigned i, j; + unsigned channel_offset = get_precedening_channels (ctrl, channel) * 0x40; + unsigned channel_step = 0x40 * num_of_channels (ctrl); + for (i = 0; i < sizeof (pattern) / sizeof (pattern[0]); i++) + { + for (j = 0 ; j < 16; j++) + write32 (0x04000000 + channel_offset + i * channel_step + j * 4, pattern[i][j]); + } + sfence (); +} + + +static void +reprogram_320c (ramctr_timing *ctrl) +{ + int channel, slotrank; + u32 r32; + + FOR_ALL_POPULATED_CHANNELS { + wait_428c (channel); + + /* choose an existing rank. */ + slotrank = !ctrl->rankmap[channel][0] ? 2 : 0; + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x0f003); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60000); + + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c (channel); + write32 (DEFAULT_MCHBAR + 0x4020 + channel * 0x400, + read32 (DEFAULT_MCHBAR + 0x4020 + channel * 0x400) | 0x200000); + } + write32 (DEFAULT_MCHBAR + 0x5030, + read32 (DEFAULT_MCHBAR + 0x5030) & ~8); + FOR_ALL_POPULATED_CHANNELS { + wait_428c (channel); + + /* choose an existing rank. */ + slotrank = !ctrl->rankmap[channel][0] ? 2 : 0; + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x0f003); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60000); + + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x3e0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c (channel); + } + + /* jedec reset */ + dram_jedecreset(ctrl); + /* mrs commands. */ + dram_mrscommands(ctrl); + + r32 = read32 (DEFAULT_MCHBAR + 0x5030); + write32 (DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay (1); + + write32 (DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay (1); +} + +static void +command_training (ramctr_timing *ctrl) +{ + int channel; + int slotrank; + u32 reg_4004_b30; + int delta = 0; + int c320c; + int stat[NUM_SLOTRANKS][256]; + + /* FIXME: vendor BIOS discovers this by trying 0 and 2. Apparently 2 should work for + all systems but 0 is slightly more efficient for the systems that can tolerate it. + */ + reg_4004_b30 = 2; + + FOR_ALL_POPULATED_CHANNELS + /* FIXME: avoid unnecessarry readback. */ + MCHBAR32 (0x4004 + 0x400 * channel) = + (MCHBAR32 (0x4004 + 0x400 * channel) & ~(3 << 30)) + | (reg_4004_b30 << 30); + + if (reg_4004_b30 == 2) + delta = 2; + else if (reg_4004_b30 == 0) + delta = 4; + + FOR_ALL_CHANNELS + { + FOR_ALL_POPULATED_RANKS + ctrl->timings[channel][slotrank].val_4024 -= delta; + } + + FOR_ALL_POPULATED_CHANNELS + { + fill_pattern5 (ctrl, channel); + write32 (DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + } + + FOR_ALL_POPULATED_CHANNELS + { + for (c320c = -127; c320c <= 127; c320c++) + { + FOR_ALL_POPULATED_RANKS + ctrl->timings[channel][slotrank].val_320c = c320c; + program_timings (ctrl, channel); + reprogram_320c (ctrl); + FOR_ALL_POPULATED_RANKS + { + stat[slotrank][c320c + 127] = test_320c (ctrl, channel, slotrank); + printk (BIOS_ERR, "3stat: %d, %d, %d: %d\n", channel, slotrank, c320c, + stat[slotrank][c320c + 127]); + } + } + FOR_ALL_POPULATED_RANKS + { + struct run rn = get_longest_zero_run (stat[slotrank], 255); + ctrl->timings[channel][slotrank].val_320c = rn.middle - 127; + printk (BIOS_ERR, "3val: %d, %d: %d\n", channel, slotrank, + ctrl->timings[channel][slotrank].val_320c); + if (rn.all) + die ("c320c discovery failed"); + } + } + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); + + reprogram_320c(ctrl); +} + +static void +discover_edges_real (ramctr_timing *ctrl, int channel, int slotrank, int *edges) +{ + int edge; + int statistics[NUM_LANES][MAX_EDGE_TIMING + 1]; + int lane; + + for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) { + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].rising = edge; + ctrl->timings[channel][slotrank].lanes[lane].falling = edge; + } + printk (BIOS_ERR, "edge %02x\n", edge); + program_timings (ctrl, channel); + + FOR_ALL_LANES + { + write32 (DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + 4 * lane, 0); + read32 (DEFAULT_MCHBAR + 0x400 * channel + 4 * lane + 0x4140); + } + + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, (0xc01 | (ctrl->delay1 << 16))); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x360004); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x40411f4); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x1001 | ((ctrl->CAS + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, (0xc01 | (ctrl->delay1 << 16))); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel, (slotrank << 24) | 0x360000); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c (channel); + + FOR_ALL_LANES + { + statistics[lane][edge] = read32 (DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + lane * 4); + printk (BIOS_ERR, "estat %d, %d, %d, %d %02x\n", channel, slotrank, lane, edge, statistics[lane][edge]); + } + } + FOR_ALL_LANES + { + struct run rn = get_longest_zero_run (statistics[lane], MAX_EDGE_TIMING + 1); + edges[lane] = rn.middle; + if (rn.all) + die ("edge discovery failed"); + printk (BIOS_ERR, "eval %d, %d, %d, %02x\n", channel, slotrank, lane, edges[lane]); + } +} + +static void +discover_edges (ramctr_timing *ctrl) +{ + int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int channel, slotrank, lane; + u32 r32; + + write32 (DEFAULT_MCHBAR + 0x3400, 0); + + r32 = read32 (DEFAULT_MCHBAR + 0x5030); + write32 (DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay (1); + + write32 (DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay (1); + + FOR_ALL_POPULATED_CHANNELS + { + FOR_ALL_LANES + write32 (DEFAULT_MCHBAR + 4 * lane + 0x400 * channel + 0x4080, 0); + } + + FOR_ALL_POPULATED_CHANNELS + { + fill_pattern0 (ctrl, channel, 0, 0); + write32 (DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + FOR_ALL_LANES + read32 (DEFAULT_MCHBAR + 0x400 * channel + lane * 4 + 0x4140); + + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].falling = 16; + ctrl->timings[channel][slotrank].lanes[lane].rising = 16; + } + + program_timings (ctrl, channel); + + FOR_ALL_POPULATED_RANKS + { + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32 (0x4230 + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + channel * 0x400, (slotrank << 24) | 0x360004); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32 (0x4234 + 0x400 * channel + DEFAULT_MCHBAR, 0x4041003); + write32 (DEFAULT_MCHBAR + 0x4204 + channel * 0x400, (slotrank << 24) | 0); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32 (0x4238 + 0x400 * channel + DEFAULT_MCHBAR, 0x1001 | ((ctrl->CAS + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + channel * 0x400, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32 (0x423c + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + write32 (DEFAULT_MCHBAR + 0x420c + channel * 0x400, (slotrank << 24) | 0x360000); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c (channel); + } + + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].falling = 48; + ctrl->timings[channel][slotrank].lanes[lane].rising = 48; + } + + program_timings (ctrl, channel); + + FOR_ALL_POPULATED_RANKS + { + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32 (0x4230 + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + write32 (DEFAULT_MCHBAR + 0x4200 + channel * 0x400, (slotrank << 24) | 0x360004); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32 (0x4234 + 0x400 * channel + DEFAULT_MCHBAR, 0x4041003); + write32 (DEFAULT_MCHBAR + 0x4204 + channel * 0x400, (slotrank << 24) | 0); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32 (0x4238 + 0x400 * channel + DEFAULT_MCHBAR, 0x1001 | ((ctrl->CAS + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + channel * 0x400, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32 (0x423c + 0x400 * channel + DEFAULT_MCHBAR, 0xc01 | (ctrl->delay1 << 16)); + + write32 (DEFAULT_MCHBAR + 0x420c + channel * 0x400, (slotrank << 24) | 0x360000); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + wait_428c (channel); + } + + FOR_ALL_LANES + { + write32 (DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + lane * 4, + ~read32 (DEFAULT_MCHBAR + 0x4040 + 0x400 * channel + lane * 4) & 0xff); + } + + fill_pattern0 (ctrl, channel, 0, 0xffffffff); + write32 (DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + } + + /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */ + write32 (DEFAULT_MCHBAR + 0x4eb0, 0x300); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + { + discover_edges_real (ctrl, channel, slotrank, falling_edges[channel][slotrank]); + } + + write32 (DEFAULT_MCHBAR + 0x4eb0, 0x200); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + { + discover_edges_real (ctrl, channel, slotrank, rising_edges[channel][slotrank]); + } + + write32 (DEFAULT_MCHBAR + 0x4eb0, 0); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].falling = falling_edges[channel][slotrank][lane]; + ctrl->timings[channel][slotrank].lanes[lane].rising = rising_edges[channel][slotrank][lane]; + } + + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + write32 (0x4080 + 4 * lane + 0x400 * channel + DEFAULT_MCHBAR, 0); + } +} + +static void +discover_edges_write_real (ramctr_timing *ctrl, int channel, int slotrank, int *edges) +{ + int edge; + u32 raw_statistics[MAX_EDGE_TIMING + 1]; + int statistics[MAX_EDGE_TIMING + 1]; + const int reg3000b24[] = {0, 0xc, 0x2c}; + int lane, i; + int lower[NUM_LANES]; + int upper[NUM_LANES]; + + FOR_ALL_LANES + { + lower[lane] = 0; + upper[lane] = MAX_EDGE_TIMING; + } + + for (i = 0; i < 3; i++) { + /* FIXME: trace shows that vendor BIOS also tests with other patterns. + I'm not sure whether it's really needed. + */ + write32 (DEFAULT_MCHBAR + 0x3000 + 0x100 * channel, + reg3000b24[i] << 24); + printk (BIOS_ERR, "patterned\n"); + printk (BIOS_ERR, "[%x] = 0x%08x\n(%d, %d)\n",0x3000 + 0x100 * channel, + reg3000b24[i] << 24, channel, slotrank); + for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) { + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].rising = edge; + ctrl->timings[channel][slotrank].lanes[lane].falling = edge; + } + program_timings (ctrl, channel); + + FOR_ALL_LANES + { + write32 (DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + 4 * lane, 0); + read32 (DEFAULT_MCHBAR + 0x400 * channel + 4 * lane + 0x4140); + } + wait_428c (channel); + + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f006); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x4 | (ctrl->tRCD << 16) + | (max (ctrl->tRRD, + (ctrl->tFAW >> 2) + 1) << 10)); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x240); + + write32 (DEFAULT_MCHBAR + 0x4224 + channel * 0x400, 0x1f201); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x8005020 | ((ctrl->tWTR + ctrl->CWL + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0x242); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x4005020 | (max (ctrl->tRTP, 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0x242); + + write32 (DEFAULT_MCHBAR + 0x422c + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, 0xc01 | (ctrl->tRP << 16)); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel, (slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4284 + channel * 0x400, 0xc0001); + wait_428c (channel); + FOR_ALL_LANES + { + read32 (DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + lane * 4); + } + + raw_statistics[edge] = MCHBAR32 (0x436c + channel * 0x400); + } + FOR_ALL_LANES + { + struct run rn; + for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) + statistics[edge] = !!(raw_statistics[edge] & (1 << lane)); + rn = get_longest_zero_run (statistics, MAX_EDGE_TIMING + 1); + printk (BIOS_ERR, "edges: %d, %d, %d: 0x%x-0x%x-0x%x, 0x%x-0x%x\n", channel, slotrank, i, + rn.start, rn.middle, rn.end, + rn.start + ctrl->edge_offset[i], + rn.end - ctrl->edge_offset[i]); + lower[lane] = max (rn.start + ctrl->edge_offset[i], lower[lane]); + upper[lane] = min (rn.end - ctrl->edge_offset[i], upper[lane]); + edges[lane] = (lower[lane] + upper[lane]) / 2; + + } + } + + write32 (DEFAULT_MCHBAR + 0x3000, 0); + printk (BIOS_ERR, "CPA\n"); +} + +static void +discover_edges_write (ramctr_timing *ctrl) +{ + int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int channel, slotrank, lane; + + FOR_ALL_POPULATED_CHANNELS + { + fill_pattern5 (ctrl, channel); + write32 (DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + } + + /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */ + write32 (DEFAULT_MCHBAR + 0x4eb0, 0x300); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + { + discover_edges_write_real (ctrl, channel, slotrank, falling_edges[channel][slotrank]); + } + + write32 (DEFAULT_MCHBAR + 0x4eb0, 0x200); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + { + discover_edges_write_real (ctrl, channel, slotrank, rising_edges[channel][slotrank]); + } + + write32 (DEFAULT_MCHBAR + 0x4eb0, 0); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + ctrl->timings[channel][slotrank].lanes[lane].falling = falling_edges[channel][slotrank][lane]; + ctrl->timings[channel][slotrank].lanes[lane].rising = rising_edges[channel][slotrank][lane]; + } + + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + write32 (0x4080 + 4 * lane + 0x400 * channel + DEFAULT_MCHBAR, 0); + } +} + +static void +discover_timC_write (ramctr_timing *ctrl) +{ + const u8 rege3c_b24[3] = { 0, 0xf, 0x2f }; + int i; + + int lower[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int upper[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int channel, slotrank, lane; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES + { + lower[channel][slotrank][lane] = 0; + upper[channel][slotrank][lane] = MAX_TIMC; + } + + write32 (DEFAULT_MCHBAR + 0x4ea8, 1); + + for (i = 0; i < 3; i++) + FOR_ALL_POPULATED_CHANNELS + { + write32 ((channel << 8) + DEFAULT_MCHBAR + 0xe3c, + (rege3c_b24[i] << 24) | (read32 ((channel << 8) + DEFAULT_MCHBAR + 0xe3c) & ~0x3f000000)); + udelay (2); + FOR_ALL_POPULATED_RANKS + { + int timC; + u32 raw_statistics[MAX_TIMC + 1]; + int statistics[MAX_TIMC + 1]; + + /* FIXME: trace shows that vendor BIOS also tests with other patterns. + I'm not sure whether it's really needed. + */ + fill_pattern5 (ctrl, channel); + for (timC = 0; timC < MAX_TIMC + 1; timC++) + { + FOR_ALL_LANES + ctrl->timings[channel][slotrank].lanes[lane].timC = timC; + program_timings (ctrl, channel); + wait_428c (channel); + write32 (DEFAULT_MCHBAR + 0x4220 + channel * 0x400, 0x1f006); + write32 (DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, (max ((ctrl->tFAW >> 2) + 1, + ctrl->tRRD) << 10) | (ctrl->tRCD << 16) | 4); + write32 (DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, (slotrank << 24) | 0x60000); + write32 (DEFAULT_MCHBAR + 0x4210 + channel * 0x400, 0x244); + + write32 (DEFAULT_MCHBAR + 0x4224 + channel * 0x400, 0x1f201); + write32 (DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x80011e0 | ((ctrl->tWTR + ctrl->CWL + 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4214 + channel * 0x400, 0x242); + + write32 (DEFAULT_MCHBAR + 0x4228 + channel * 0x400, 0x1f105); + write32 (DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x40011e0 | (max (ctrl->tRTP, 8) << 16)); + write32 (DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32 (DEFAULT_MCHBAR + 0x4218 + channel * 0x400, 0x242); + + write32 (DEFAULT_MCHBAR + 0x422c + channel * 0x400, 0x1f002); + write32 (DEFAULT_MCHBAR + 0x423c + 0x400 * channel, 0x1001 | (ctrl->tRP << 16)); + write32 (DEFAULT_MCHBAR + 0x420c + 0x400 * channel,(slotrank << 24) | 0x60400); + write32 (DEFAULT_MCHBAR + 0x421c + channel * 0x400, 0); + + write32 (DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + wait_428c (channel); + raw_statistics[timC] = MCHBAR32 (0x436c + channel * 0x400); + printk (BIOS_ERR, "Cstat %02x %02x\n", timC, raw_statistics[timC]); + } + FOR_ALL_LANES + { + struct run rn; + for (timC = 0; timC <= MAX_TIMC; timC++) + statistics[timC] = !!(raw_statistics[timC] & (1 << lane)); + rn = get_longest_zero_run (statistics, MAX_TIMC + 1); + if (rn.all) + die ("timC write discovery failed"); + printk (BIOS_ERR, "timC: %d, %d, %d: 0x%x-0x%x-0x%x, 0x%x-0x%x\n", channel, slotrank, i, + rn.start, rn.middle, rn.end, + rn.start + ctrl->timC_offset[i], + rn.end - ctrl->timC_offset[i]); + lower[channel][slotrank][lane] = max (rn.start + ctrl->timC_offset[i], + lower[channel][slotrank][lane]); + upper[channel][slotrank][lane] = min (rn.end - ctrl->timC_offset[i], + upper[channel][slotrank][lane]); + + } + } + } + + write32 ((channel << 8) + DEFAULT_MCHBAR + 0xe3c, + 0 | (read32 ((channel << 8) + DEFAULT_MCHBAR + 0xe3c) & ~0x3f000000)); + udelay (2); + + write32 (DEFAULT_MCHBAR + 0x4ea8, 0); + + printk (BIOS_ERR, "CPB\n"); + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + FOR_ALL_LANES + { + printk (BIOS_ERR, "timC [%d, %d, %d] = 0x%x\n", channel, slotrank, lane, + (lower[channel][slotrank][lane] + upper[channel][slotrank][lane]) / 2); + ctrl->timings[channel][slotrank].lanes[lane].timC = + (lower[channel][slotrank][lane] + upper[channel][slotrank][lane]) / 2; + } + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); +} + +static void +normalize_training (ramctr_timing *ctrl) +{ + int channel, slotrank, lane; + int mat = 0; + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + { + int delta; + FOR_ALL_LANES + mat = max (ctrl->timings[channel][slotrank].lanes[lane].timA, mat); + delta = (mat >> 6) - ctrl->timings[channel][slotrank].val_4028; + ctrl->timings[channel][slotrank].val_4024 += delta; + ctrl->timings[channel][slotrank].val_4028 += delta; + } + + FOR_ALL_POPULATED_CHANNELS + program_timings (ctrl, channel); +} + + +static void +write_controller_mr(ramctr_timing *ctrl) +{ + int channel, slotrank; + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + { + write32 (DEFAULT_MCHBAR | 0x0004 | (channel << 8) | lane_registers[slotrank], make_mr0 (ctrl, slotrank)); + write32 (DEFAULT_MCHBAR | 0x0008 | (channel << 8) | lane_registers[slotrank], make_mr1 (ctrl, slotrank)); + } +} + +static void +channel_test(ramctr_timing *ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_POPULATED_CHANNELS + if (read32 (DEFAULT_MCHBAR | 0x42a0 | (channel << 10)) & 0xa000) + die ("Mini channel test failed (1)\n"); + FOR_ALL_POPULATED_CHANNELS + { + fill_pattern0 (ctrl, channel, 0x12345678, 0x98765432); + + write32 (DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + } + + for (slotrank = 0; slotrank < 4; slotrank++) + FOR_ALL_CHANNELS + if ((ctrl->rankmap[channel][0] | ctrl->rankmap[channel][1]) & (1 << slotrank)) + { + FOR_ALL_LANES + { + write32 (DEFAULT_MCHBAR | (0x4f40 + 4 * lane), 0); + write32 (DEFAULT_MCHBAR | (0x4d40 + 4 * lane), 0); + } + wait_428c (channel); + write32 (DEFAULT_MCHBAR | 0x4220 | (channel << 10), 0x0001f006); + write32 (DEFAULT_MCHBAR | 0x4230 | (channel << 10), 0x0028a004); + write32 (DEFAULT_MCHBAR | 0x4200 | (channel << 10), + 0x00060000 | (slotrank << 24)); + write32 (DEFAULT_MCHBAR | 0x4210 | (channel << 10), 0x00000244); + write32 (DEFAULT_MCHBAR | 0x4224 | (channel << 10), 0x0001f201); + write32 (DEFAULT_MCHBAR | 0x4234 | (channel << 10), 0x08281064); + write32 (DEFAULT_MCHBAR | 0x4204 | (channel << 10), + 0x00000000 | (slotrank << 24)); + write32 (DEFAULT_MCHBAR | 0x4214 | (channel << 10), 0x00000242); + write32 (DEFAULT_MCHBAR | 0x4228 | (channel << 10), 0x0001f105); + write32 (DEFAULT_MCHBAR | 0x4238 | (channel << 10), 0x04281064); + write32 (DEFAULT_MCHBAR | 0x4208 | (channel << 10), + 0x00000000 | (slotrank << 24)); + write32 (DEFAULT_MCHBAR | 0x4218 | (channel << 10), 0x00000242); + write32 (DEFAULT_MCHBAR | 0x422c | (channel << 10), 0x0001f002); + write32 (DEFAULT_MCHBAR | 0x423c | (channel << 10), 0x00280c01); + write32 (DEFAULT_MCHBAR | 0x420c | (channel << 10), + 0x00060400 | (slotrank << 24)); + write32 (DEFAULT_MCHBAR | 0x421c | (channel << 10), 0x00000240); + write32 (DEFAULT_MCHBAR | 0x4284 | (channel << 10), 0x000c0001); + wait_428c (channel); + FOR_ALL_LANES + if (read32 (DEFAULT_MCHBAR | 0x4340 | (channel << 10))) + die ("Mini channel test failed (2)\n"); + } +} + +static void +set_scrambling_seed (ramctr_timing *ctrl) +{ + int channel; + + /* FIXME: we hardcode seeds. Do we need to use some PRNG for them? + I don't think so. */ + static u32 seeds[2][3] = { + { 0x00009a36, 0xbafcfdcf, 0x46d1ab68}, + { 0x00028bfa, 0x53fe4b49, 0x19ed5483} + }; + FOR_ALL_POPULATED_CHANNELS + { + MCHBAR32(0x4020 + channel * 0x400) &= ~0x10000000; + write32 (DEFAULT_MCHBAR | 0x4034, seeds[channel][0]); + write32 (DEFAULT_MCHBAR | 0x403c, seeds[channel][1]); + write32 (DEFAULT_MCHBAR | 0x4038, seeds[channel][2]); + } +} + +static void +set_4f8c (void) +{ + struct cpuid_result cpures; + u32 cpu; + + cpures = cpuid(0); + cpu = (cpures.eax); + if (IS_SANDY_CPU(cpu) && (IS_SANDY_CPU_D0(cpu) || IS_SANDY_CPU_D1(cpu))) { + MCHBAR32(0x4f8c) = 0x141D1519; + } else { + MCHBAR32(0x4f8c) = 0x551D1519; + } +} + +static void +prepare_training (ramctr_timing *ctrl) +{ + int channel; + + FOR_ALL_POPULATED_CHANNELS { + // Always drive command bus + MCHBAR32(0x4004 + 0x400 * channel) |= 0x20000000; + } + + udelay (1); + + FOR_ALL_POPULATED_CHANNELS + wait_428c (channel); +} + +static void +hardcode1 (ramctr_timing *ctrl) +{ + int channel; + FOR_ALL_POPULATED_CHANNELS { + read32 (DEFAULT_MCHBAR | 0x400c | (channel << 10)); // !!! = 0x000258b4 + write32 (DEFAULT_MCHBAR | 0x400c | (channel << 10), 0x000058b4); // FIXME: hardcoded + write32 (DEFAULT_MCHBAR | 0x4008 | (channel << 10), 0x0a042220); // FIXME: hardcoded + } +} + +static void +set_42a0 (ramctr_timing *ctrl) +{ + int channel; + FOR_ALL_POPULATED_CHANNELS { + write32 (DEFAULT_MCHBAR | (0x42a0 + 0x400 * channel), 0x00001000 | ctrl->rankmap[channel][0] | (ctrl->rankmap[channel][1] << 2)); + MCHBAR32(0x4004 + 0x400 * channel) &= ~0x20000000; // OK + } +} + +void init_dram_ddr3(spd_raw_data *spds, int mobile) +{ + int me_uma_size; + report_platform_info(); + + /* Wait for ME to be ready */ + intel_early_me_init(); + me_uma_size = intel_early_me_uma_size(); + + printk(BIOS_DEBUG, "Starting native Platform init\n"); + + pch_init (); + + u32 reg_5d10; + + wait_txt_clear (); + + wrmsr (0x000002e6, (msr_t) { .lo = 0, .hi = 0 }); + + reg_5d10 = read32 (DEFAULT_MCHBAR | 0x5d10); // !!! = 0x00000000 + if ((pcie_read_config16 (SOUTHBRIDGE, 0xa2) & 0xa0) == 0x20 /* 0x0004 */ + && reg_5d10) { + /* Need reset. */ + outb (0x6, 0xcf9); + + while (1); + } + + ramctr_timing ctrl; + + dimm_info info; + + ctrl.mobile = mobile; + + /* Get DDR3 SPD data */ + dram_find_spds_ddr3(spds, &info, &ctrl); + + /* Find fastest common supported parameters */ + dram_find_common_params(&info, &ctrl); + + /* Calculate timings */ + dram_timing(&ctrl); + + /* Set MCU frequency */ + dram_freq(&ctrl); + + /* Set version register */ + MCHBAR32(0x5034) = 0xC04EB002; + + /* Enable crossover */ + dram_xover(&ctrl); + + /* Set timing and refresh registers */ + dram_timing_regs(&ctrl); + + /* Power mode preset */ + MCHBAR32(0x4e80) = 0x5500; + + /* Set scheduler parameters */ + MCHBAR32(0x4c20) = 0x10100005; + + /* Set cpu specific register */ + set_4f8c (); + + /* Clear IO reset bit */ + MCHBAR32(0x5030) &= ~0x20; + + /* FIXME: Fix dimm map - Set MAD-DIMM registers */ + dram_dimm_mapping(&info, &ctrl); + printram("Done dimm mapping\n"); + + /* Zone config */ + dram_zones(&info, &ctrl, 1); + + /* Set memory map */ + dram_memorymap(&info, me_uma_size); + printram("Done memory map\n"); + + /* Set IO registers */ + dram_ioregs(&ctrl); + printram("Done io registers\n"); + + udelay (1); + + /* Do jedec ddr3 reset sequence */ + dram_jedecreset(&ctrl); + printram("Done jedec reset\n"); + + /* MRS commands */ + dram_mrscommands(&ctrl); + printram("Done MRS commands\n"); + dram_mrscommands(&ctrl); + + /* Prepare for memory training */ + prepare_training(&ctrl); + + read_training (&ctrl); + write_training (&ctrl); + + printk (BIOS_ERR, "CP5a\n"); + + discover_edges (&ctrl); + + printk (BIOS_ERR, "CP5b\n"); + + command_training(&ctrl); + + printk (BIOS_ERR, "CP5c\n"); + + discover_edges_write(&ctrl); + + discover_timC_write(&ctrl); + + normalize_training (&ctrl); + + hardcode1 (&ctrl); + + write_controller_mr(&ctrl); + + channel_test(&ctrl); + + write32 (DEFAULT_MCHBAR | 0x5024, 0x00a030ce);// FIXME: hardcoded + + set_scrambling_seed(&ctrl); + + set_42a0 (&ctrl); + + write32 (DEFAULT_MCHBAR | 0x4cd4, 0x00000046); // FIXME: hardcoded + + write32 (DEFAULT_MCHBAR | 0x400c, (read32 (DEFAULT_MCHBAR | 0x400c) & 0xFFFFCFFF) | 0x1000); // OK + write32 (DEFAULT_MCHBAR | 0x440c, (read32 (DEFAULT_MCHBAR | 0x440c) & 0xFFFFCFFF) | 0x1000); // OK + write32 (DEFAULT_MCHBAR | 0x4cb0, 0x00000740); // FIXME: hardcoded + write32 (DEFAULT_MCHBAR | 0x4380, 0x00000aaa); // OK + write32 (DEFAULT_MCHBAR | 0x4780, 0x00000aaa); // OK + write32 (DEFAULT_MCHBAR | 0x4f88, 0x5f7003ff); // OK + write32 (DEFAULT_MCHBAR | 0x5064, 0x00073193); // FIXME: hardcoded + write32 (DEFAULT_MCHBAR | 0x4384, 0x009b6ea1);// FIXME: hardcoded + write32 (DEFAULT_MCHBAR | 0x4784, 0x009b6ea1);// FIXME: hardcoded + write32 (DEFAULT_MCHBAR | 0x5880, 0xca9171e5);// FIXME: hardcoded + read32 (DEFAULT_MCHBAR | 0x5888); // !!! = 0x00e4d5d0 + write32 (DEFAULT_MCHBAR | 0x5888, 0x00e4d5d0);// FIXME: hardcoded + read32 (DEFAULT_MCHBAR | 0x58a8); // !!! = 0x00000000 + write32 (DEFAULT_MCHBAR | 0x58a8, 0x00000000);// FIXME: hardcoded + read32 (DEFAULT_MCHBAR | 0x4294); // !!! = 0x000098ff + write32 (DEFAULT_MCHBAR | 0x4294, 0x000198ff);// FIXME: hardcoded + read32 (DEFAULT_MCHBAR | 0x4694); // !!! = 0x000098ff + write32 (DEFAULT_MCHBAR | 0x4694, 0x000198ff);// FIXME: hardcoded + + MCHBAR32 (0x5030) |= 1; // OK + MCHBAR32 (0x5030) |= 0x80; // OK + MCHBAR32 (0x5f18) = 0xfa; // OK + read32 (DEFAULT_MCHBAR | 0x5d10); // !!! = 0x00000000 + write32 (DEFAULT_MCHBAR | 0x5d10, 0x2010040c); // FIXME: hardcoded + + /* Zone config */ + dram_zones(&info, &ctrl, 0); + +#if CONFIG_USBDEBUG_IN_ROMSTAGE + /* mrc.bin reconfigures USB, so reinit it to have debug */ + usbdebug_init(); +#endif + + /* FIXME: uncomment this once dram_memorymap is fixed. */ +// intel_early_me_init_done(ME_INIT_STATUS_SUCCESS); - post_system_agent_init(pei_data); + post_system_agent_init(); report_memory_config(); } diff --git a/src/northbridge/intel/sandybridge/raminit.h b/src/northbridge/intel/sandybridge/raminit.h index c3b1c2a..7e0b10e 100644 --- a/src/northbridge/intel/sandybridge/raminit.h +++ b/src/northbridge/intel/sandybridge/raminit.h @@ -20,17 +20,11 @@ #ifndef RAMINIT_H #define RAMINIT_H -#include "pei_data.h" +#include <device/dram/ddr3.h> -struct sys_info { - u8 boot_path; -#define BOOT_PATH_NORMAL 0 -#define BOOT_PATH_RESET 1 -#define BOOT_PATH_RESUME 2 -} __attribute__ ((packed)); - -void sdram_initialize(struct pei_data *pei_data); -void save_mrc_data(struct pei_data *pei_data); -int fixup_sandybridge_errata(void); +/* The order is ch0dimmA, ch0dimmB, ch1dimmA, ch1dimmB. */ +void init_dram_ddr3(spd_raw_data *spds, int mobile); +void pch_init(void); +void read_spd(spd_raw_data *spd, u8 addr); #endif /* RAMINIT_H */
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • ...
  • 107
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.