Vladimir Serbinenko (phcoder@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2663
-gerrit
commit 180b27e9d45356a1fabfc8ab77a5b85be3434e60 Author: Vladimir Serbinenko phcoder@gmail.com Date: Tue Mar 12 15:53:44 2013 +0100
Put back into git most of my X201 work. As-is. Code quality leaves a lot to be desired but it works.
Change-Id: I81ae0ecadefa88c317170f49d8d4fddf39b75edd Signed-off-by: Vladimir 'phcoder' Serbinenko Signed-off-by: Vladimir Serbinenko phcoder@gmail.com
X201 and related work
Change-Id: I81ae0ecadefa88c317170f49d8d4fddf39b75edd Signed-off-by: Vladimir Serbinenko phcoder@gmail.com --- src/arch/x86/boot/smbios.c | 4 +- src/arch/x86/lib/romstage_console.c | 7 + src/console/Kconfig | 6 + src/console/Makefile.inc | 1 + src/console/console.c | 5 + src/console/spkmodem_console.c | 46 + src/console/usbdebug_console.c | 8 +- src/cpu/intel/microcode/microcode.c | 3 + src/cpu/intel/model_206ax/Kconfig | 5 +- src/cpu/intel/model_206ax/Makefile.inc | 6 + src/cpu/intel/model_206ax/acpi.c | 1 + src/cpu/intel/model_206ax/bootblock.c | 3 +- src/cpu/intel/model_206ax/cache_as_ram.inc | 6 +- src/cpu/intel/model_206ax/model_206ax_init.c | 26 +- src/cpu/x86/Kconfig | 2 +- src/cpu/x86/fpu_enable.inc | 5 + src/cpu/x86/lapic/apic_timer.c | 17 + src/cpu/x86/mtrr/mtrr.c | 32 +- src/device/device.c | 38 +- src/ec/acpi/Makefile.inc | 1 + src/ec/acpi/ec.c | 12 + src/ec/lenovo/h8/acpi/ec.asl | 178 +- src/ec/lenovo/h8/acpi/thermal.asl | 7 + src/ec/lenovo/h8/h8.c | 26 +- src/include/console/console.h | 3 + src/include/delay.h | 1 + src/include/usbdebug.h | 1 + src/lib/Makefile.inc | 3 + src/lib/ramtest.c | 22 +- src/lib/usbdebug.c | 26 +- src/mainboard/lenovo/Kconfig | 6 + src/mainboard/lenovo/x201/Kconfig | 58 + src/mainboard/lenovo/x201/Makefile.inc | 23 + src/mainboard/lenovo/x201/acpi/dock.asl | 77 + src/mainboard/lenovo/x201/acpi/ec.asl | 26 + src/mainboard/lenovo/x201/acpi/gpe.asl | 30 + src/mainboard/lenovo/x201/acpi/ich7_pci_irqs.asl | 46 + src/mainboard/lenovo/x201/acpi/mainboard.asl | 0 src/mainboard/lenovo/x201/acpi/platform.asl | 170 + .../lenovo/x201/acpi/sandybridge_pci_irqs.asl | 87 + src/mainboard/lenovo/x201/acpi/superio.asl | 0 src/mainboard/lenovo/x201/acpi/video.asl | 69 + src/mainboard/lenovo/x201/acpi_tables.c | 275 ++ src/mainboard/lenovo/x201/cmos.layout | 139 + src/mainboard/lenovo/x201/devicetree.cb | 148 + src/mainboard/lenovo/x201/dock.c | 270 ++ src/mainboard/lenovo/x201/dock.h | 28 + src/mainboard/lenovo/x201/dsdt.asl | 94 + src/mainboard/lenovo/x201/fadt.c | 159 + src/mainboard/lenovo/x201/irq_tables.c | 62 + src/mainboard/lenovo/x201/mainboard.c | 295 ++ src/mainboard/lenovo/x201/mptable.c | 61 + src/mainboard/lenovo/x201/romstage.c | 885 +++++ src/mainboard/lenovo/x201/smi.h | 27 + src/mainboard/lenovo/x201/smihandler.c | 208 + src/northbridge/intel/Makefile.inc | 1 + src/northbridge/intel/sandybridge/Kconfig | 4 +- src/northbridge/intel/sandybridge/Makefile.inc | 14 +- src/northbridge/intel/sandybridge/acpi.c | 8 +- .../intel/sandybridge/acpi/hostbridge.asl | 57 +- src/northbridge/intel/sandybridge/acpi/igd.asl | 14 + src/northbridge/intel/sandybridge/early_init.c | 22 +- src/northbridge/intel/sandybridge/gma.c | 12 +- src/northbridge/intel/sandybridge/northbridge.c | 204 +- src/northbridge/intel/sandybridge/raminit.c | 4151 ++++++++++++++++++-- src/northbridge/intel/sandybridge/raminit.h | 11 +- src/northbridge/intel/sandybridge/raminit_fake.c | 986 +++++ src/northbridge/intel/sandybridge/raminit_tables.c | 1238 ++++++ src/northbridge/intel/sandybridge/sandybridge.h | 425 +- src/southbridge/intel/bd82x6x/Makefile.inc | 4 +- src/southbridge/intel/bd82x6x/azalia.c | 2 +- src/southbridge/intel/bd82x6x/early_smbus.c | 15 + src/southbridge/intel/bd82x6x/lpc.c | 385 +- src/southbridge/intel/bd82x6x/me.c | 10 +- src/southbridge/intel/bd82x6x/me.h | 1 + src/southbridge/intel/bd82x6x/pch.h | 15 +- src/southbridge/intel/bd82x6x/sata.c | 47 +- src/southbridge/intel/bd82x6x/smbus.c | 4 +- src/southbridge/intel/bd82x6x/smbus.h | 144 + src/southbridge/intel/bd82x6x/smi.c | 6 +- src/southbridge/intel/bd82x6x/spi.c | 10 +- src/southbridge/intel/bd82x6x/thermal.c | 84 + src/southbridge/intel/bd82x6x/usb_debug.c | 9 +- src/southbridge/intel/bd82x6x/usb_ehci.c | 35 +- util/inteltool/cpu.c | 166 + util/inteltool/gpio.c | 6 + util/inteltool/memory.c | 101 +- util/inteltool/powermgt.c | 6 + util/inteltool/rootcmplx.c | 1 + 89 files changed, 11361 insertions(+), 581 deletions(-)
diff --git a/src/arch/x86/boot/smbios.c b/src/arch/x86/boot/smbios.c index 308336a..34aa175 100644 --- a/src/arch/x86/boot/smbios.c +++ b/src/arch/x86/boot/smbios.c @@ -133,9 +133,9 @@ static int smbios_write_type0(unsigned long *current, int handle) t->bios_release_date = smbios_add_string(t->eos, COREBOOT_DMI_DATE);
if (strlen(CONFIG_LOCALVERSION)) - t->bios_version = smbios_add_string(t->eos, CONFIG_LOCALVERSION); + t->bios_version = smbios_add_string(t->eos, "CBET4000 " CONFIG_LOCALVERSION); else - t->bios_version = smbios_add_string(t->eos, COREBOOT_VERSION); + t->bios_version = smbios_add_string(t->eos, "CBET4000 " COREBOOT_VERSION); #else #define SPACES \ " " diff --git a/src/arch/x86/lib/romstage_console.c b/src/arch/x86/lib/romstage_console.c index f43db05..49de160 100644 --- a/src/arch/x86/lib/romstage_console.c +++ b/src/arch/x86/lib/romstage_console.c @@ -28,6 +28,10 @@ #if CONFIG_CONSOLE_NE2K #include <console/ne2k.h> #endif +#if CONFIG_SPKMODEM +#include <console/spkmodem.h> +#endif +
void console_tx_byte(unsigned char byte) { @@ -52,6 +56,9 @@ void console_tx_byte(unsigned char byte) #if CONFIG_CONSOLE_CBMEM cbmemc_tx_byte(byte); #endif +#if CONFIG_SPKMODEM + spkmodem_tx_byte(byte); +#endif }
static void console_tx_flush(void) diff --git a/src/console/Kconfig b/src/console/Kconfig index 7fbed4a..01f9e3a 100644 --- a/src/console/Kconfig +++ b/src/console/Kconfig @@ -119,6 +119,12 @@ config TTYS0_LCS default 3 depends on CONSOLE_SERIAL8250 || CONSOLE_SERIAL8250MEM
+config SPKMODEM + bool "Spkmodem (console on speaker) console output" + default n + help + Send coreboot debug output through speaker + # Use "select HAVE_USBDEBUG" on southbridges which have Debug Port code. config HAVE_USBDEBUG def_bool n diff --git a/src/console/Makefile.inc b/src/console/Makefile.inc index 9499180..a57f457 100644 --- a/src/console/Makefile.inc +++ b/src/console/Makefile.inc @@ -20,6 +20,7 @@ bootblock-y += die.c
ramstage-$(CONFIG_CONSOLE_SERIAL8250) += uart8250_console.c ramstage-$(CONFIG_CONSOLE_SERIAL8250MEM) += uart8250mem_console.c +ramstage-$(CONFIG_SPKMODEM) += spkmodem_console.c ramstage-$(CONFIG_USBDEBUG) += usbdebug_console.c ramstage-$(CONFIG_CONSOLE_LOGBUF) += logbuf_console.c ramstage-$(CONFIG_CONSOLE_NE2K) += ne2k_console.c diff --git a/src/console/console.c b/src/console/console.c index 34a26ec..8da77c1 100644 --- a/src/console/console.c +++ b/src/console/console.c @@ -40,6 +40,7 @@ static inline int get_option(void *dest, const char *name) { return -1; } void console_init(void) { struct console_driver *driver; + if(get_option(&console_loglevel, "debug_level")) console_loglevel=CONFIG_DEFAULT_CONSOLE_LOGLEVEL;
@@ -119,6 +120,10 @@ void console_init(void) #if CONFIG_CONSOLE_CBMEM cbmemc_init(); #endif +#if CONFIG_SPKMODEM + spkmodem_init(); +#endif + static const char console_test[] = "\n\ncoreboot-" COREBOOT_VERSION diff --git a/src/console/spkmodem_console.c b/src/console/spkmodem_console.c new file mode 100644 index 0000000..814a1ac --- /dev/null +++ b/src/console/spkmodem_console.c @@ -0,0 +1,46 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Vladimir Serbinenko + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <console/console.h> +#include <console/spkmodem.h> + +static void spkmodem_tx_flush(void) +{ +} + +static unsigned char spkmodem_rx_byte(void) +{ + return 0; +} + +static int spkmodem_tst_byte(void) +{ + return 0; +} + + +static const struct console_driver spkmodem_console __console = { + .init = spkmodem_init, + .tx_byte = spkmodem_tx_byte, + .tx_flush = spkmodem_tx_flush, + .rx_byte = spkmodem_rx_byte, + .tst_byte = spkmodem_tst_byte, +}; + diff --git a/src/console/usbdebug_console.c b/src/console/usbdebug_console.c index 58a62b8..38719f2 100644 --- a/src/console/usbdebug_console.c +++ b/src/console/usbdebug_console.c @@ -50,12 +50,15 @@ unsigned get_ehci_debug(void)
static void dbgp_init(void) { + enable_usbdebug(CONFIG_USBDEBUG_DEFAULT_PORT); + usbdebug_init(CONFIG_EHCI_BAR, CONFIG_EHCI_DEBUG_OFFSET, &dbg_info); }
static void dbgp_tx_byte(unsigned char data) { - usbdebug_tx_byte(&dbg_info, data); + if (dbg_info.ehci_debug) + usbdebug_tx_byte(&dbg_info, data); }
static unsigned char dbgp_rx_byte(void) @@ -70,7 +73,8 @@ static unsigned char dbgp_rx_byte(void)
static void dbgp_tx_flush(void) { - usbdebug_tx_flush(&dbg_info); + if (dbg_info.ehci_debug) + usbdebug_tx_flush(&dbg_info); }
static int dbgp_tst_byte(void) diff --git a/src/cpu/intel/microcode/microcode.c b/src/cpu/intel/microcode/microcode.c index 713a6df..d4c4444 100644 --- a/src/cpu/intel/microcode/microcode.c +++ b/src/cpu/intel/microcode/microcode.c @@ -93,6 +93,9 @@ void intel_update_microcode(const void *microcode_updates) const char *c; msr_t msr;
+ if (!microcode_updates) + return; + /* CPUID sets MSR 0x8B iff a microcode update has been loaded. */ msr.lo = 0; msr.hi = 0; diff --git a/src/cpu/intel/model_206ax/Kconfig b/src/cpu/intel/model_206ax/Kconfig index 5b3f893..d82ec5b 100644 --- a/src/cpu/intel/model_206ax/Kconfig +++ b/src/cpu/intel/model_206ax/Kconfig @@ -10,8 +10,9 @@ config CPU_SPECIFIC_OPTIONS def_bool y select SMP select SSE2 - select UDELAY_LAPIC select SMM_TSEG + select UDELAY_LAPIC + select HAVE_INIT_TIMER select CPU_MICROCODE_IN_CBFS #select AP_IN_SIPI_WAIT select TSC_SYNC_MFENCE @@ -34,5 +35,5 @@ config ENABLE_VMX
config MICROCODE_INCLUDE_PATH string - default "src/cpu/intel/model_206ax" + default "3rdparty/mainboard/lenovo/x201" endif diff --git a/src/cpu/intel/model_206ax/Makefile.inc b/src/cpu/intel/model_206ax/Makefile.inc index a324b64..cdee323 100644 --- a/src/cpu/intel/model_206ax/Makefile.inc +++ b/src/cpu/intel/model_206ax/Makefile.inc @@ -1,5 +1,11 @@ ramstage-y += model_206ax_init.c subdirs-y += ../../x86/name +subdirs-y += ../../x86/cache +subdirs-y += ../../x86/mtrr +subdirs-y += ../../x86/lapic +subdirs-y += ../../intel/turbo +subdirs-y += ../../intel/microcode +subdirs-y += ../../x86/smm
ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c
diff --git a/src/cpu/intel/model_206ax/acpi.c b/src/cpu/intel/model_206ax/acpi.c index 80ed4ba..aa86f76 100644 --- a/src/cpu/intel/model_206ax/acpi.c +++ b/src/cpu/intel/model_206ax/acpi.c @@ -327,6 +327,7 @@ void generate_cpu_entries(void) int cores_per_package = get_cores_per_package(); int numcpus = totalcores/cores_per_package;
+ printk(BIOS_DEBUG, "Found %d CPU(s) with %d core(s) each.\n", numcpus, cores_per_package);
diff --git a/src/cpu/intel/model_206ax/bootblock.c b/src/cpu/intel/model_206ax/bootblock.c index 02958bb..b87367b 100644 --- a/src/cpu/intel/model_206ax/bootblock.c +++ b/src/cpu/intel/model_206ax/bootblock.c @@ -28,7 +28,8 @@ #include <cpu/intel/microcode/microcode.c> #include "model_206ax.h"
-#if CONFIG_SOUTHBRIDGE_INTEL_BD82X6X || CONFIG_SOUTHBRIDGE_INTEL_C216 +#if 1 +//CONFIG_SOUTHBRIDGE_INTEL_BD82X6X || CONFIG_SOUTHBRIDGE_INTEL_C216 /* Needed for RCBA access to set Soft Reset Data register */ #include <southbridge/intel/bd82x6x/pch.h> #else diff --git a/src/cpu/intel/model_206ax/cache_as_ram.inc b/src/cpu/intel/model_206ax/cache_as_ram.inc index 9a2db37..9c4b06f 100644 --- a/src/cpu/intel/model_206ax/cache_as_ram.inc +++ b/src/cpu/intel/model_206ax/cache_as_ram.inc @@ -167,7 +167,7 @@ clear_mtrrs:
/* Set up the stack pointer below MRC variable space. */ movl $(CACHE_AS_RAM_SIZE + CACHE_AS_RAM_BASE - \ - CONFIG_DCACHE_RAM_MRC_VAR_SIZE - 4), %eax + CONFIG_DCACHE_RAM_MRC_VAR_SIZE - 4 - 4096), %eax movl %eax, %esp
/* Restore the BIST result. */ @@ -335,16 +335,18 @@ __main: jmp .Lhlt
mtrr_table: + .word 0x02FF + /* Fixed MTRRs */ .word 0x250, 0x258, 0x259 .word 0x268, 0x269, 0x26A .word 0x26B, 0x26C, 0x26D .word 0x26E, 0x26F + /* Variable MTRRs */ .word 0x200, 0x201, 0x202, 0x203 .word 0x204, 0x205, 0x206, 0x207 .word 0x208, 0x209, 0x20A, 0x20B .word 0x20C, 0x20D, 0x20E, 0x20F - .word 0x210, 0x211, 0x212, 0x213 mtrr_table_end:
diff --git a/src/cpu/intel/model_206ax/model_206ax_init.c b/src/cpu/intel/model_206ax/model_206ax_init.c index d1f9277..da76fa0 100644 --- a/src/cpu/intel/model_206ax/model_206ax_init.c +++ b/src/cpu/intel/model_206ax/model_206ax_init.c @@ -243,6 +243,7 @@ int cpu_config_tdp_levels(void) */ void set_power_limits(u8 power_limit_1_time) { +#ifdef DISABLED msr_t msr = rdmsr(MSR_PLATFORM_INFO); msr_t limit; unsigned power_unit; @@ -301,13 +302,18 @@ void set_power_limits(u8 power_limit_1_time) limit.lo = msr.lo & 0xff; wrmsr(MSR_TURBO_ACTIVATION_RATIO, limit); } +#endif }
static void configure_c_states(void) { +#ifdef DISABLED msr_t msr;
+ /* 0x00000000:0x02000403 */ msr = rdmsr(MSR_PMG_CST_CONFIG_CONTROL); + printk(BIOS_ERR, "CST: %x %x\n", + msr.hi, msr.lo); msr.lo |= (1 << 28); // C1 Auto Undemotion Enable msr.lo |= (1 << 27); // C3 Auto Undemotion Enable msr.lo |= (1 << 26); // C1 Auto Demotion Enable @@ -361,6 +367,7 @@ static void configure_c_states(void) else msr.lo |= PP1_CURRENT_LIMIT_SNB; wrmsr(MSR_PP1_CURRENT_CONFIG, msr); +#endif }
static void configure_thermal_target(void) @@ -390,20 +397,23 @@ static void configure_misc(void) msr_t msr;
msr = rdmsr(IA32_MISC_ENABLE); + msr.lo |= (1 << 0); /* Fast String enable */ msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */ msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */ - wrmsr(IA32_MISC_ENABLE, msr); + wrmsr(IA32_MISC_ENABLE, msr);
/* Disable Thermal interrupts */ msr.lo = 0; msr.hi = 0; wrmsr(IA32_THERM_INTERRUPT, msr);
+#ifdef DISABLED /* Enable package critical interrupt only */ msr.lo = 1 << 4; msr.hi = 0; wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr); +#endif }
static void enable_lapic_tpr(void) @@ -417,6 +427,7 @@ static void enable_lapic_tpr(void)
static void configure_dca_cap(void) { +#ifdef DISABLED struct cpuid_result cpuid_regs; msr_t msr;
@@ -427,6 +438,7 @@ static void configure_dca_cap(void) msr.lo |= 1; wrmsr(IA32_PLATFORM_DCA_CAP, msr); } +#endif }
static void set_max_ratio(void) @@ -453,6 +465,7 @@ static void set_max_ratio(void)
static void set_energy_perf_bias(u8 policy) { +#ifdef DISABLED msr_t msr;
/* Energy Policy is bits 3:0 */ @@ -463,6 +476,7 @@ static void set_energy_perf_bias(u8 policy)
printk(BIOS_DEBUG, "model_x06ax: energy policy set to %u\n", policy); +#endif }
static void configure_mca(void) @@ -511,7 +525,7 @@ static void intel_cores_init(device_t cpu) /* Build the cpu device path */ cpu_path.type = DEVICE_PATH_APIC; cpu_path.apic.apic_id = - cpu->path.apic.apic_id + i; + cpu->path.apic.apic_id + (i & 1) + ((i & 2) << 1);
/* Update APIC ID if no hyperthreading */ if (threads_per_core == 1) @@ -542,6 +556,9 @@ static void model_206ax_init(device_t cpu) char processor_name[49]; struct cpuid_result cpuid_regs;
+ /* Start up extra cores */ + intel_cores_init(cpu); + /* Turn on caching if we haven't already */ x86_enable_cache();
@@ -553,7 +570,7 @@ static void model_206ax_init(device_t cpu) /* Print processor name */ fill_processor_name(processor_name); printk(BIOS_INFO, "CPU: %s.\n", processor_name); - + printk(BIOS_INFO, "CPU:lapic=%ld, boot_cpu=%d\n", lapicid (), boot_cpu ()); #if CONFIG_USBDEBUG // Is this caution really needed? if(!ehci_debug_addr) @@ -602,8 +619,6 @@ static void model_206ax_init(device_t cpu) /* Enable Turbo */ enable_turbo();
- /* Start up extra cores */ - intel_cores_init(cpu); }
static struct device_operations cpu_dev_ops = { @@ -611,6 +626,7 @@ static struct device_operations cpu_dev_ops = { };
static struct cpu_device_id cpu_table[] = { + { X86_VENDOR_INTEL, 0x20655 }, /* Intel Sandybridge */ { X86_VENDOR_INTEL, 0x206a0 }, /* Intel Sandybridge */ { X86_VENDOR_INTEL, 0x206a6 }, /* Intel Sandybridge D1 */ { X86_VENDOR_INTEL, 0x206a7 }, /* Intel Sandybridge D2/J1 */ diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig index ae3241e..4fb8894 100644 --- a/src/cpu/x86/Kconfig +++ b/src/cpu/x86/Kconfig @@ -45,7 +45,7 @@ config TSC_SYNC_MFENCE config XIP_ROM_SIZE hex default ROM_SIZE if ROMCC - default 0x10000 + default 0x20000
config CPU_ADDR_BITS int diff --git a/src/cpu/x86/fpu_enable.inc b/src/cpu/x86/fpu_enable.inc index f3eedcd..71374d4 100644 --- a/src/cpu/x86/fpu_enable.inc +++ b/src/cpu/x86/fpu_enable.inc @@ -33,7 +33,12 @@ __fpu_start: */ movl %cr0, %eax andl $~(1 << 2), %eax + orl $(1 << 1), %eax movl %eax, %cr0
+ movl %cr4, %eax + orl $(3 << 9), %eax + movl %eax, %cr4 + /* Restore BIST. */ movl %ebp, %eax diff --git a/src/cpu/x86/lapic/apic_timer.c b/src/cpu/x86/lapic/apic_timer.c index 53209fb..9f9d719 100644 --- a/src/cpu/x86/lapic/apic_timer.c +++ b/src/cpu/x86/lapic/apic_timer.c @@ -103,3 +103,20 @@ void udelay(u32 usecs) value = lapic_read(LAPIC_TMCCT); } while((start - value) < ticks); } + +void ns100delay(u32 ns100secs) +{ + u32 start, value, ticks; + + if (!timer_fsb || (lapic_read(LAPIC_LVTT) & + (LAPIC_LVT_TIMER_PERIODIC | LAPIC_LVT_MASKED)) != + (LAPIC_LVT_TIMER_PERIODIC | LAPIC_LVT_MASKED)) + init_timer(); + + /* Calculate the number of ticks to run, our FSB runs at timer_fsb Mhz */ + ticks = (ns100secs * timer_fsb) / 10; + start = lapic_read(LAPIC_TMCCT); + do { + value = lapic_read(LAPIC_TMCCT); + } while((start - value) < ticks); +} diff --git a/src/cpu/x86/mtrr/mtrr.c b/src/cpu/x86/mtrr/mtrr.c index a061b54..0cde99e 100644 --- a/src/cpu/x86/mtrr/mtrr.c +++ b/src/cpu/x86/mtrr/mtrr.c @@ -245,6 +245,8 @@ static unsigned int range_to_mtrr(unsigned int reg, { unsigned long hole_startk = 0, hole_sizek = 0;
+ printk (BIOS_ERR, "range_to_mtrr\n"); + if (!range_sizek) { /* If there's no MTRR hole, this function will bail out * here when called for the hole. @@ -261,28 +263,36 @@ static unsigned int range_to_mtrr(unsigned int reg, return reg; }
-#define MIN_ALIGN 0x10000 /* 64MB */ - - if (above4gb == 2 && type == MTRR_TYPE_WRBACK && - range_sizek > MIN_ALIGN && range_sizek % MIN_ALIGN) { - /* - * If this range is not divisible then instead - * make a larger range and carve out an uncached hole. - */ - hole_startk = range_startk + range_sizek; - hole_sizek = MIN_ALIGN - (range_sizek % MIN_ALIGN); - range_sizek += hole_sizek; + printk (BIOS_ERR, "was: %lx + %lx\n", range_startk, range_sizek); + + if (above4gb == 2 && type == MTRR_TYPE_WRBACK) { + int i; + for (i = 30; i > 0; i--) + if (((range_sizek >> (i - 1)) & 0xf) == 0xe) + { + hole_sizek += (1 << i); + range_sizek += (1 << i); + printk (BIOS_ERR, "i=%d\n", i); + } + hole_startk = range_startk + range_sizek - hole_sizek; }
+ printk (BIOS_ERR, "became: (%lx + %lx) - (%lx + %lx)\n", range_startk, range_sizek, hole_startk, hole_sizek); + while(range_sizek) { unsigned long max_align, align; unsigned long sizek; + + printk (BIOS_ERR, "i=%lx\n", range_sizek); + /* Compute the maximum size I can make a range */ max_align = fls(range_startk); align = fms(range_sizek); if (align > max_align) { align = max_align; } + if (align > 21) + align = 21; sizek = 1 << align;
/* if range is above 4GB, MTRR is needed diff --git a/src/device/device.c b/src/device/device.c index 07bbc7a..4dcf06f 100644 --- a/src/device/device.c +++ b/src/device/device.c @@ -528,6 +528,12 @@ static void allocate_resources(struct bus *bus, struct resource *bridge, resource->base, (resource->flags & IORESOURCE_IO) ? "io" : (resource->flags & IORESOURCE_PREFETCH) ? "prefmem" : "mem"); + if (resource->base == 0xe0000000 + && PCI_SLOT(dev->path.pci.devfn) == 0x2) + { + printk (BIOS_ERR, "moving to 0xd0000000\n"); + resource->base = 0xd0000000; + } }
/* @@ -585,19 +591,14 @@ static void allocate_resources(struct bus *bus, struct resource *bridge, } }
-#if CONFIG_PCI_64BIT_PREF_MEM -#define MEM_MASK (IORESOURCE_PREFETCH | IORESOURCE_MEM) -#else #define MEM_MASK (IORESOURCE_MEM) -#endif - #define IO_MASK (IORESOURCE_IO) #define PREF_TYPE (IORESOURCE_PREFETCH | IORESOURCE_MEM) #define MEM_TYPE (IORESOURCE_MEM) #define IO_TYPE (IORESOURCE_IO)
struct constraints { - struct resource pref, io, mem; + struct resource io, mem; };
static void constrain_resources(struct device *dev, struct constraints* limits) @@ -621,9 +622,7 @@ static void constrain_resources(struct device *dev, struct constraints* limits) }
/* PREFETCH, MEM, or I/O - skip any others. */ - if ((res->flags & MEM_MASK) == PREF_TYPE) - lim = &limits->pref; - else if ((res->flags & MEM_MASK) == MEM_TYPE) + if ((res->flags & MEM_MASK) == MEM_TYPE) lim = &limits->mem; else if ((res->flags & IO_MASK) == IO_TYPE) lim = &limits->io; @@ -668,11 +667,9 @@ static void avoid_fixed_resources(struct device *dev) printk(BIOS_SPEW, "%s: %s\n", __func__, dev_path(dev));
/* Initialize constraints to maximum size. */ - limits.pref.base = 0; - limits.pref.limit = 0xffffffffffffffffULL; limits.io.base = 0; limits.io.limit = 0xffffffffffffffffULL; - limits.mem.base = 0; + limits.mem.base = 0xe0000000; limits.mem.limit = 0xffffffffffffffffULL;
/* Constrain the limits to dev's initial resources. */ @@ -681,9 +678,6 @@ static void avoid_fixed_resources(struct device *dev) continue; printk(BIOS_SPEW, "%s:@%s %02lx limit %08llx\n", __func__, dev_path(dev), res->index, res->limit); - if ((res->flags & MEM_MASK) == PREF_TYPE && - (res->limit < limits.pref.limit)) - limits.pref.limit = res->limit; if ((res->flags & MEM_MASK) == MEM_TYPE && (res->limit < limits.mem.limit)) limits.mem.limit = res->limit; @@ -703,9 +697,7 @@ static void avoid_fixed_resources(struct device *dev) continue;
/* PREFETCH, MEM, or I/O - skip any others. */ - if ((res->flags & MEM_MASK) == PREF_TYPE) - lim = &limits.pref; - else if ((res->flags & MEM_MASK) == MEM_TYPE) + if ((res->flags & MEM_MASK) == MEM_TYPE) lim = &limits.mem; else if ((res->flags & IO_MASK) == IO_TYPE) lim = &limits.io; @@ -820,7 +812,9 @@ void assign_resources(struct bus *bus) dev_path(curdev)); continue; } + printk (BIOS_ERR, "alive "__FILE__ ":%d, %s, %p\n", __LINE__,dev_path(curdev), curdev->ops->set_resources); curdev->ops->set_resources(curdev); + printk (BIOS_ERR, "alive "__FILE__ ":%d\n", __LINE__); } printk(BIOS_SPEW, "%s assign_resources, bus %d link: %d\n", dev_path(bus->dev), bus->secondary, bus->link_num); @@ -1017,11 +1011,15 @@ void dev_configure(void) } }
+ printk (BIOS_ERR, "alive "__FILE__ ":%d\n", __LINE__); + /* For all domains. */ for (child = root->link_list->children; child; child=child->sibling) if (child->path.type == DEVICE_PATH_PCI_DOMAIN) avoid_fixed_resources(child);
+ printk (BIOS_ERR, "alive "__FILE__ ":%d\n", __LINE__); + /* * Now we need to adjust the resources. MEM resources need to start at * the highest address managable. @@ -1037,6 +1035,8 @@ void dev_configure(void) } }
+ printk (BIOS_ERR, "alive "__FILE__ ":%d\n", __LINE__); + /* Store the computed resource allocations into device registers ... */ printk(BIOS_INFO, "Setting resources...\n"); for (child = root->link_list->children; child; child = child->sibling) { @@ -1062,6 +1062,8 @@ void dev_configure(void) } } } + printk (BIOS_ERR, "alive "__FILE__ ":%d\n", __LINE__); + assign_resources(root->link_list); printk(BIOS_INFO, "Done setting resources.\n"); print_resource_tree(root, BIOS_SPEW, "After assigning values."); diff --git a/src/ec/acpi/Makefile.inc b/src/ec/acpi/Makefile.inc index 34c5136..27c26d9 100644 --- a/src/ec/acpi/Makefile.inc +++ b/src/ec/acpi/Makefile.inc @@ -1,2 +1,3 @@ ramstage-y += ec.c smm-$(CONFIG_HAVE_SMI_HANDLER) += ec.c +romstage-y += ec.c diff --git a/src/ec/acpi/ec.c b/src/ec/acpi/ec.c index ad297fb..a772f8e 100644 --- a/src/ec/acpi/ec.c +++ b/src/ec/acpi/ec.c @@ -25,9 +25,18 @@ #include <delay.h> #include "ec.h"
+#ifdef __PRE_RAM__ + +static const int ec_cmd_reg = EC_SC; +static const int ec_data_reg = EC_DATA; + +#else + static int ec_cmd_reg = EC_SC; static int ec_data_reg = EC_DATA;
+#endif + int send_ec_command(u8 command) { int timeout; @@ -132,6 +141,8 @@ void ec_clr_bit(u8 addr, u8 bit) ec_write(addr, ec_read(addr) & ~(1 << bit)); }
+#ifndef __PRE_RAM__ + void ec_set_ports(u16 cmd_reg, u16 data_reg) { ec_cmd_reg = cmd_reg; @@ -141,3 +152,4 @@ void ec_set_ports(u16 cmd_reg, u16 data_reg) struct chip_operations ec_acpi_ops = { CHIP_NAME("ACPI Embedded Controller") }; +#endif diff --git a/src/ec/lenovo/h8/acpi/ec.asl b/src/ec/lenovo/h8/acpi/ec.asl index 368afa8..8f7e76f 100644 --- a/src/ec/lenovo/h8/acpi/ec.asl +++ b/src/ec/lenovo/h8/acpi/ec.asl @@ -25,7 +25,7 @@ Device(EC) Name (_HID, EISAID("PNP0C09")) Name (_UID, 0)
- Name (_GPE, 28) + Name (_GPE, 0x11) Mutex (ECLK, 0)
OperationRegion(ERAM, EmbeddedControl, 0x00, 0x100) @@ -86,19 +86,25 @@ Device(EC) /* Sleep Button pressed */ Method(_Q13, 0, NotSerialized) { - Notify(_SB.PCI0.LPCB.EC.SLPB, 0x80) + Notify(^SLPB, 0x80) }
/* Brightness up GPE */ Method(_Q14, 0, NotSerialized) { - \DSPC.BRTU () + Notify (_SB.PCI0.GFX0.LCD0, 0x86) }
/* Brightness down GPE */ Method(_Q15, 0, NotSerialized) { - \DSPC.BRTD() + Notify (_SB.PCI0.GFX0.LCD0, 0x87) + } + + /* Next display GPE */ + Method(_Q16, 0, NotSerialized) + { + Notify (_SB.PCI0.GFX0, 0x82) }
/* AC status change: present */ @@ -116,14 +122,174 @@ Device(EC)
Method(_Q2A, 0, NotSerialized) { - Notify(_SB.PCI0.LPCB.EC.LID, 0x80) + Notify(^LID, 0x80) }
Method(_Q2B, 0, NotSerialized) { - Notify(_SB.PCI0.LPCB.EC.LID, 0x80) + Notify(^LID, 0x80) + } + + + /* IBM proprietary buttons. */ + + Method (_Q10, 0, NotSerialized) + { + ^HKEY.RHK (0x01) }
+ Method (_Q11, 0, NotSerialized) + { + ^HKEY.RHK (0x02) + } + + Method (_Q12, 0, NotSerialized) + { + ^HKEY.RHK (0x03) + } + + Method (_Q64, 0, NotSerialized) + { + ^HKEY.RHK (0x05) + } + + Method (_Q65, 0, NotSerialized) + { + ^HKEY.RHK (0x06) + } + + Method (_Q17, 0, NotSerialized) + { + ^HKEY.RHK (0x08) + } + + Method (_Q66, 0, NotSerialized) + { + ^HKEY.RHK (0x0A) + } + + Method (_Q1A, 0, NotSerialized) + { + ^HKEY.RHK (0x0B) + } + + Method (_Q1B, 0, NotSerialized) + { + ^HKEY.RHK (0x0C) + } + + Method (_Q62, 0, NotSerialized) + { + ^HKEY.RHK (0x0D) + } + + Method (_Q60, 0, NotSerialized) + { + ^HKEY.RHK (0x0E) + } + + Method (_Q61, 0, NotSerialized) + { + ^HKEY.RHK (0x0F) + } + + Method (_Q1F, 0, NotSerialized) + { + ^HKEY.RHK (0x12) + } + + Method (_Q67, 0, NotSerialized) + { + ^HKEY.RHK (0x13) + } + + Method (_Q63, 0, NotSerialized) + { + ^HKEY.RHK (0x14) + } + + Method (_Q19, 0, NotSerialized) + { + ^HKEY.RHK (0x18) + } + + Method (_Q1C, 0, NotSerialized) + { + ^HKEY.RHK (0x19) + } + + Method (_Q1D, 0, NotSerialized) + { + ^HKEY.RHK (0x1A) + } + + Device (HKEY) + { + Name (_HID, EisaId ("IBM0068")) + Name (BTN, 0) + /* MASK */ + Name (DHKN, 0x080C) + /* Effective Mask */ + Name (EMSK, 0) + Name (EN, 0) + Method (_STA, 0, NotSerialized) + { + Return (0x0F) + } + Method (MHKP, 0, NotSerialized) + { + Store (BTN, Local0) + If (LEqual (Local0, Zero)) { + Return (Zero) + } + Store (Zero, BTN) + Add (Local0, 0x1000, Local0) + Return (Local0) + } + /* Report event */ + Method (RHK, 1, NotSerialized) { + ShiftLeft (One, Subtract (Arg0, 1), Local0) + If (And (EMSK, Local0)) { + Store (Arg0, BTN) + Notify (HKEY, 0x80) + } + } + Method (MHKC, 1, NotSerialized) { + If (Arg0) { + Store (DHKN, EMSK) + } + Else + { + Store (Zero, EMSK) + } + Store (Arg0, EN) + } + Method (MHKM, 2, NotSerialized) { + If (LLessEqual (Arg0, 0x20)) { + ShiftLeft (One, Subtract (Arg0, 1), Local0) + If (Arg1) + { + Or (DHKN, Local0, DHKN) + } + Else + { + And (DHKN, Not (Local0), DHKN) + } + If (EN) + { + Store (DHKN, EMSK) + } + } + } + Method (MHKA, 0, NotSerialized) + { + Return (0x07FFFFFF) + } + Method (MHKV, 0, NotSerialized) + { + Return (0x0100) + } + }
#include "ac.asl" #include "battery.asl" diff --git a/src/ec/lenovo/h8/acpi/thermal.asl b/src/ec/lenovo/h8/acpi/thermal.asl index 35b6f14..735171b 100644 --- a/src/ec/lenovo/h8/acpi/thermal.asl +++ b/src/ec/lenovo/h8/acpi/thermal.asl @@ -1,5 +1,7 @@ Scope(_TZ) { + Name (MEBT, 0) + Method(C2K, 1, NotSerialized) { Multiply(Arg0, 10, Local0) @@ -20,6 +22,11 @@ Scope(_TZ) Return (C2K(127)) } Method(_TMP) { + /* Avoid tripping alarm if ME isn't booted at all yet */ + If (LAnd (LNot (MEBT), LEqual (_SB.PCI0.LPCB.EC.TMP0, 128))) { + Return (C2K(40)) + } + Store (1, MEBT) Return (C2K(_SB.PCI0.LPCB.EC.TMP0)) } } diff --git a/src/ec/lenovo/h8/h8.c b/src/ec/lenovo/h8/h8.c index ecd34b2..810e0a6 100644 --- a/src/ec/lenovo/h8/h8.c +++ b/src/ec/lenovo/h8/h8.c @@ -50,6 +50,14 @@ void h8_wlan_enable(int on) ec_clr_bit(0x3a, 5); }
+static void h8_3g_enable(int on) +{ + if (on) + ec_set_bit(0x3a, 6); + else + ec_clr_bit(0x3a, 6); +} + static void h8_log_ec_version(void) { unsigned char ecfw[9], c; @@ -142,6 +150,8 @@ static void h8_enable(device_t dev) ec_write(0x1e, conf->evente_enable); ec_write(0x1f, conf->eventf_enable);
+ ec_write(0x78, 0x3a); + ec_write(H8_FAN_CONTROL, H8_FAN_CONTROL_AUTO); h8_wlan_enable(conf->wlan_enable); h8_trackpoint_enable(conf->trackpoint_enable); @@ -150,16 +160,14 @@ static void h8_enable(device_t dev) if (!get_option(&val, "volume")) ec_write(H8_VOLUME_CONTROL, val);
+ h8_bluetooth_enable(1); + h8_3g_enable(1);
- if (!get_option(&val, "bluetooth")) - h8_bluetooth_enable(val); - - if (!get_option(&val, "first_battery")) { - tmp = ec_read(H8_CONFIG3); - tmp &= ~(1 << 4); - tmp |= (val & 1)<< 4; - ec_write(H8_CONFIG3, tmp); - } + val = 1; + tmp = ec_read(H8_CONFIG3); + tmp &= ~(1 << 4); + tmp |= (val & 1)<< 4; + ec_write(H8_CONFIG3, tmp); h8_set_audio_mute(0); }
diff --git a/src/include/console/console.h b/src/include/console/console.h index 496571b..628c116 100644 --- a/src/include/console/console.h +++ b/src/include/console/console.h @@ -36,6 +36,9 @@ #if CONFIG_CONSOLE_CBMEM #include <console/cbmem_console.h> #endif +#if CONFIG_SPKMODEM +#include <console/spkmodem.h> +#endif
#ifndef __PRE_RAM__ void console_tx_flush(void); diff --git a/src/include/delay.h b/src/include/delay.h index 0333879..c66803c 100644 --- a/src/include/delay.h +++ b/src/include/delay.h @@ -12,6 +12,7 @@ void init_timer(void); void udelay(unsigned usecs); void mdelay(unsigned msecs); void delay(unsigned secs); +void ns100delay(unsigned ns100secs);
#endif #endif /* DELAY_H */ diff --git a/src/include/usbdebug.h b/src/include/usbdebug.h index 8caf361..a99807d 100644 --- a/src/include/usbdebug.h +++ b/src/include/usbdebug.h @@ -46,5 +46,6 @@ int early_usbdebug_init(void); void usbdebug_tx_byte(struct ehci_debug_info *info, unsigned char data); void usbdebug_tx_flush(struct ehci_debug_info *info); int usbdebug_init(unsigned ehci_bar, unsigned offset, struct ehci_debug_info *info); +unsigned char usbdebug_rx_byte(struct ehci_debug_info *dbg_info); #endif #endif diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc index 8ff0a44..6aaf0fe 100644 --- a/src/lib/Makefile.inc +++ b/src/lib/Makefile.inc @@ -45,6 +45,8 @@ romstage-$(CONFIG_CONSOLE_SERIAL8250MEM) += uart8250mem.c romstage-$(CONFIG_CONSOLE_CBMEM) += cbmem_console.c romstage-$(CONFIG_CONSOLE_NE2K) += ne2k.c romstage-$(CONFIG_USBDEBUG) += usbdebug.c +romstage-$(CONFIG_SPKMODEM) += spkmodem.c + romstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c romstage-y += compute_ip_checksum.c romstage-y += memmove.c @@ -77,6 +79,7 @@ ramstage-$(CONFIG_CONSOLE_SERIAL8250) += uart8250.c ramstage-$(CONFIG_CONSOLE_SERIAL8250MEM) += uart8250mem.c ramstage-$(CONFIG_CONSOLE_CBMEM) += cbmem_console.c ramstage-$(CONFIG_USBDEBUG) += usbdebug.c +ramstage-$(CONFIG_SPKMODEM) += spkmodem.c ramstage-$(CONFIG_BOOTSPLASH) += jpeg.c ramstage-$(CONFIG_TRACE) += trace.c ramstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c diff --git a/src/lib/ramtest.c b/src/lib/ramtest.c index 3457210..c04cf07 100644 --- a/src/lib/ramtest.c +++ b/src/lib/ramtest.c @@ -1,6 +1,7 @@ #include <stdint.h> #include <lib.h> /* Prototypes */ #include <console/console.h> +#include <arch/io.h>
static void write_phys(unsigned long addr, u32 value) { @@ -176,6 +177,22 @@ static int ram_bitset_nodie(unsigned long start)
void ram_check(unsigned long start, unsigned long stop) { + unsigned long i; + int ok = 1; + printk(BIOS_ERR, "Testing DRAM %lx-%lx\n", start, stop); + for (i = start & ~3; i < stop; i+=4) + write32 (i, i); + for (i = start & ~3; i < stop; i+=4) + { + u32 v = read32 (i); + if (v != i) + { + ok = 0; + printk(BIOS_ERR, "Fail at %lx: %lx vs %lx\n", i, i, (unsigned long)v); + } + } + printk(BIOS_ERR, "Tested DRAM %lx-%lx: %s\n", start, stop, ok ? "OK" : "FAIL"); +#if 0 /* * This is much more of a "Is my DRAM properly configured?" * test than a "Is my DRAM faulty?" test. Not all bits @@ -189,12 +206,15 @@ void ram_check(unsigned long start, unsigned long stop) print_debug("\n"); #endif if (ram_bitset_nodie(start)) - die("DRAM ERROR"); + printk(BIOS_ERR, "DRAM ERROR"); + else + printk(BIOS_ERR, "DRAM OK"); #if !defined(__ROMCC__) printk(BIOS_DEBUG, "Done.\n"); #else print_debug("Done.\n"); #endif +#endif }
diff --git a/src/lib/usbdebug.c b/src/lib/usbdebug.c index 24d7967..ee90598 100644 --- a/src/lib/usbdebug.c +++ b/src/lib/usbdebug.c @@ -80,7 +80,7 @@ #define HUB_RESET_TIMEOUT 500
#define DBGP_MAX_PACKET 8 -#define DBGP_LOOPS 1000 +#define DBGP_LOOPS 10000
static int dbgp_wait_until_complete(struct ehci_dbg_port *ehci_debug) { @@ -133,6 +133,7 @@ retry: dbgp_breath();
/* If I get a NACK reissue the transmission */ + if (lpid == USB_PID_NAK) { if (--loop > 0) goto retry; @@ -604,6 +605,29 @@ void usbdebug_tx_flush(struct ehci_debug_info *dbg_info)
if (dbg_info->ehci_debug && dbg_info->bufidx > 0) { dbgp_bulk_write_x(dbg_info, dbg_info->buf, dbg_info->bufidx); + dbg_info->bufidx = 0; } } + +unsigned char usbdebug_rx_byte(struct ehci_debug_info *dbg_info) +{ + if (!dbg_info) { + /* "Find" dbg_info structure in Cache */ + dbg_info = (struct ehci_debug_info *) + (CONFIG_DCACHE_RAM_BASE + CONFIG_DCACHE_RAM_SIZE - sizeof(struct ehci_debug_info)); + } + + if (dbg_info->ehci_debug) { + unsigned char c = 0xff; + u32 pids; + usbdebug_tx_flush (dbg_info); + pids = read32((unsigned long)&((struct ehci_dbg_port *) dbg_info->ehci_debug)->pids); + while (dbgp_bulk_read_x (dbg_info, &c, 1) <= 0); + write32((unsigned long)&((struct ehci_dbg_port *) dbg_info->ehci_debug)->pids, pids); + usbdebug_tx_byte(dbg_info, c); + usbdebug_tx_flush (dbg_info); + return c; + } + return 0xff; +} diff --git a/src/mainboard/lenovo/Kconfig b/src/mainboard/lenovo/Kconfig index 8ee2778..7def45a 100644 --- a/src/mainboard/lenovo/Kconfig +++ b/src/mainboard/lenovo/Kconfig @@ -12,6 +12,11 @@ config BOARD_LENOVO_X60 ThinkPad X60s (Model 1702, 1703) ThinkPad X60 (Model 1709)
+config BOARD_LENOVO_X201 + bool "ThinkPad X201" + help + New port. + config BOARD_LENOVO_T60 bool "ThinkPad T60 / T60p" help @@ -23,6 +28,7 @@ config BOARD_LENOVO_T60 endchoice
source "src/mainboard/lenovo/x60/Kconfig" +source "src/mainboard/lenovo/x201/Kconfig" source "src/mainboard/lenovo/t60/Kconfig"
config MAINBOARD_VENDOR diff --git a/src/mainboard/lenovo/x201/Kconfig b/src/mainboard/lenovo/x201/Kconfig new file mode 100644 index 0000000..150e298 --- /dev/null +++ b/src/mainboard/lenovo/x201/Kconfig @@ -0,0 +1,58 @@ +if BOARD_LENOVO_X201 + +config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + select ARCH_X86 + select CPU_INTEL_MODEL_206AX + select NORTHBRIDGE_INTEL_SANDYBRIDGE + select SOUTHBRIDGE_INTEL_BD82X6X + select SOUTHBRIDGE_RICOH_RL5C476 + select SUPERIO_NSC_PC87382 + select SUPERIO_NSC_PC87392 + select EC_LENOVO_PMH7 + select EC_LENOVO_H8 + select DRIVERS_ICS_954309 + select HAVE_OPTION_TABLE + select HAVE_PIRQ_TABLE + select HAVE_MP_TABLE + select MMCONF_SUPPORT + select GFXUMA + select BOARD_ROMSIZE_KB_8192 + select CHANNEL_XOR_RANDOMIZATION + select HAVE_ACPI_TABLES + select HAVE_ACPI_RESUME + select UDELAY_TSC + +config MAINBOARD_DIR + string + default lenovo/x201 + +config MAINBOARD_PART_NUMBER + string + default "3626EN1" + +config MAINBOARD_VERSION + string + default "ThinkPad X201" + +config MAINBOARD_VENDOR + string + default "LENOVO" + +config MMCONF_BASE_ADDRESS + hex + default 0xe0000000 + +config IRQ_SLOT_COUNT + int + default 18 + +config MAX_CPUS + int + default 4 + +config CPU_ADDR_BITS + int + default 36 + +endif diff --git a/src/mainboard/lenovo/x201/Makefile.inc b/src/mainboard/lenovo/x201/Makefile.inc new file mode 100644 index 0000000..1ed3999 --- /dev/null +++ b/src/mainboard/lenovo/x201/Makefile.inc @@ -0,0 +1,23 @@ +## +## 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 +## + +smm-$(CONFIG_HAVE_SMI_HANDLER) += dock.c +romstage-y += dock.c +ramstage-y += dock.c + diff --git a/src/mainboard/lenovo/x201/acpi/dock.asl b/src/mainboard/lenovo/x201/acpi/dock.asl new file mode 100644 index 0000000..136f888 --- /dev/null +++ b/src/mainboard/lenovo/x201/acpi/dock.asl @@ -0,0 +1,77 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (c) 2011 Sven Schnelle svens@stackframe.org + * + * 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 "smi.h" + +Scope (_SB) +{ + OperationRegion (DLPC, SystemIO, 0x164c, 1) + Field(DLPC, ByteAcc, NoLock, Preserve) + { + , 3, + DSTA, 1, + } + + Device(DOCK) + { + Name(_HID, "ACPI0003") + Name(_UID, 0x00) + Name(_PCL, Package() { _SB } ) + + Method(_DCK, 1, NotSerialized) + { + if (Arg0) { + /* connect dock */ + TRAP(SMI_DOCK_CONNECT) + } else { + /* disconnect dock */ + TRAP(SMI_DOCK_DISCONNECT) + } + + Xor(Arg0, DSTA, Local0) + Return (Local0) + } + + Method(_STA, 0, NotSerialized) + { + Return (DSTA) + } + } +} + +Scope(_SB.PCI0.LPCB.EC) +{ + Method(_Q18, 0, NotSerialized) + { + Notify(_SB.DOCK, 3) + } + + Method(_Q50, 0, NotSerialized) + { + Notify(_SB.DOCK, 3) + } + + Method(_Q58, 0, NotSerialized) + { + Notify(_SB.DOCK, 0) + } + +} diff --git a/src/mainboard/lenovo/x201/acpi/ec.asl b/src/mainboard/lenovo/x201/acpi/ec.asl new file mode 100644 index 0000000..4b3e72c --- /dev/null +++ b/src/mainboard/lenovo/x201/acpi/ec.asl @@ -0,0 +1,26 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (c) 2011 Sven Schnelle svens@stackframe.org + * + * 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 <ec/lenovo/h8/acpi/ec.asl> + +Scope(_SB.PCI0.LPCB.EC) +{ +} diff --git a/src/mainboard/lenovo/x201/acpi/gpe.asl b/src/mainboard/lenovo/x201/acpi/gpe.asl new file mode 100644 index 0000000..b160b50 --- /dev/null +++ b/src/mainboard/lenovo/x201/acpi/gpe.asl @@ -0,0 +1,30 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (c) 2011 Sven Schnelle svens@stackframe.org + * + * 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 "smi.h" +Scope (_GPE) +{ + Method(_L18, 0, NotSerialized) + { + /* Read EC register to clear wake status */ + Store(_SB.PCI0.LPCB.EC.WAKE, Local0) + } +} diff --git a/src/mainboard/lenovo/x201/acpi/ich7_pci_irqs.asl b/src/mainboard/lenovo/x201/acpi/ich7_pci_irqs.asl new file mode 100644 index 0000000..548996c --- /dev/null +++ b/src/mainboard/lenovo/x201/acpi/ich7_pci_irqs.asl @@ -0,0 +1,46 @@ +/* + * 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 + */ + +/* This is board specific information: IRQ routing for the + * 0:1e.0 PCI bridge of the ICH7 + */ + +If (PICM) { + Return (Package() { + Package (0x04) { 0x0000FFFF, 0x00, 0x00, 0x10 }, + Package (0x04) { 0x0000FFFF, 0x01, 0x00, 0x11 }, + Package (0x04) { 0x0000FFFF, 0x02, 0x00, 0x12 }, + Package (0x04) { 0x0001FFFF, 0x00, 0x00, 0x10 }, + Package (0x04) { 0x0002FFFF, 0x00, 0x00, 0x15 }, + Package (0x04) { 0x0002FFFF, 0x01, 0x00, 0x16 }, + Package (0x04) { 0x0008FFFF, 0x00, 0x00, 0x14 } + }) + } Else { + Return (Package() { + Package (0x04) { 0x0000FFFF, 0x00, _SB.PCI0.LPCB.LNKA, 0x00 }, + Package (0x04) { 0x0000FFFF, 0x01, _SB.PCI0.LPCB.LNKB, 0x00 }, + Package (0x04) { 0x0000FFFF, 0x02, _SB.PCI0.LPCB.LNKC, 0x00 }, + Package (0x04) { 0x0001FFFF, 0x00, _SB.PCI0.LPCB.LNKA, 0x00 }, + Package (0x04) { 0x0002FFFF, 0x00, _SB.PCI0.LPCB.LNKF, 0x00 }, + Package (0x04) { 0x0002FFFF, 0x01, _SB.PCI0.LPCB.LNKG, 0x00 }, + Package (0x04) { 0x0008FFFF, 0x00, _SB.PCI0.LPCB.LNKE, 0x00 } + }) +} diff --git a/src/mainboard/lenovo/x201/acpi/mainboard.asl b/src/mainboard/lenovo/x201/acpi/mainboard.asl new file mode 100644 index 0000000..e69de29 diff --git a/src/mainboard/lenovo/x201/acpi/platform.asl b/src/mainboard/lenovo/x201/acpi/platform.asl new file mode 100644 index 0000000..2bf3a2b --- /dev/null +++ b/src/mainboard/lenovo/x201/acpi/platform.asl @@ -0,0 +1,170 @@ +/* + * 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 + */ + +/* These come from the dynamically created CPU SSDT */ +External(PDC0) +External(PDC1) + +/* 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) +{ + _SB.PCI0.LPCB.EC.MUTE(1) + _SB.PCI0.LPCB.EC.USBP(0) +} + +/* The _WAK method is called on system wakeup */ + +Method(_WAK,1) +{ + // CPU specific part + + // Notify PCI Express slots in case a card + // was inserted while a sleep state was active. + + // Are we going to S3? + If (LEqual(Arg0, 3)) { + // .. + } + + // Are we going to S4? + If (LEqual(Arg0, 4)) { + // .. + } + + // TODO: Windows XP SP2 P-State restore + + Return(Package(){0,0}) +} + +/* System Bus */ + +Scope(_SB) +{ + /* This method is placed on the top level, so we can make sure it's the + * first executed _INI method. + */ + Method(_INI, 0) + { + /* The DTS data in NVS is probably not up to date. + * Update temperature values and make sure AP thermal + * interrupts can happen + */ + + // TRAP(71) // TODO + + /* Determine the Operating System and save the value in OSYS. + * We have to do this in order to be able to work around + * certain windows bugs. + * + * OSYS value | Operating System + * -----------+------------------ + * 2000 | Windows 2000 + * 2001 | Windows XP(+SP1) + * 2002 | Windows XP SP2 + * 2006 | Windows Vista + * ???? | Windows 7 + */ + + /* Let's assume we're running at least Windows 2000 */ + Store (2000, OSYS) + + If (CondRefOf(_OSI, Local0)) { + /* Linux answers _OSI with "True" for a couple of + * Windows version queries. But unlike Windows it + * needs a Video repost, so let's determine whether + * we're running Linux. + */ +/* + If (_OSI("Linux")) { + Store (1, LINX) + }*/ + + If (_OSI("Windows 2001")) { + Store (2001, OSYS) + } + + If (_OSI("Windows 2001 SP1")) { + Store (2001, OSYS) + } + + If (_OSI("Windows 2001 SP2")) { + Store (2002, OSYS) + } + + If (_OSI("Windows 2006")) { + Store (2006, OSYS) + } + } + + /* And the OS workarounds start right after we know what we're + * running: Windows XP SP1 needs to have C-State coordination + * enabled in SMM. + */ + If (LAnd(LEqual(OSYS, 2001), MPEN)) { + // TRAP(61) // TODO + } + + /* SMM power state and C4-on-C3 settings need to be updated */ + // TRAP(43) // TODO + } +} + diff --git a/src/mainboard/lenovo/x201/acpi/sandybridge_pci_irqs.asl b/src/mainboard/lenovo/x201/acpi/sandybridge_pci_irqs.asl new file mode 100644 index 0000000..1fdef91 --- /dev/null +++ b/src/mainboard/lenovo/x201/acpi/sandybridge_pci_irqs.asl @@ -0,0 +1,87 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Sven Schnelle svens@stackframe.org + * + * 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 is board specific information: IRQ routing for the + * i945 + */ + + +// PCI Interrupt Routing +Method(_PRT) +{ + If (PICM) { + Return (Package() { + Package() { 0x0001ffff, 0, 0, 0x10 }, + Package() { 0x0002ffff, 0, 0, 0x10 }, // VGA + Package() { 0x0003ffff, 0, 0, 0x10 }, + Package() { 0x0016ffff, 0, 0, 0x10 }, // ME + Package() { 0x0016ffff, 1, 0, 0x11 }, // ME + Package() { 0x0016ffff, 2, 0, 0x12 }, // ME + Package() { 0x0016ffff, 3, 0, 0x13 }, // ME + Package() { 0x0019ffff, 0, 0, 0x14 }, // Ethernet + Package() { 0x001affff, 0, 0, 0x14 }, // USB + Package() { 0x001affff, 1, 0, 0x15 }, // USB + Package() { 0x001affff, 2, 0, 0x16 }, // USB + Package() { 0x001affff, 3, 0, 0x17 }, // USB + Package() { 0x001bffff, 1, 0, 0x11 }, // Audio + Package() { 0x001cffff, 0, 0, 0x14 }, // PCI bridge + Package() { 0x001cffff, 1, 0, 0x15 }, // PCI bridge + Package() { 0x001cffff, 2, 0, 0x16 }, // PCI bridge + Package() { 0x001cffff, 3, 0, 0x17 }, // PCI bridge + Package() { 0x001dffff, 0, 0, 0x10 }, // USB + Package() { 0x001dffff, 1, 0, 0x11 }, // USB + Package() { 0x001dffff, 2, 0, 0x12 }, // USB + Package() { 0x001dffff, 3, 0, 0x13 }, // USB + Package() { 0x001fffff, 0, 0, 0x17 }, // LPC + Package() { 0x001fffff, 1, 0, 0x10 }, // IDE + Package() { 0x001fffff, 2, 0, 0x11 }, // SATA + Package() { 0x001fffff, 3, 0, 0x13 } // SMBUS + }) + } Else { + Return (Package() { + Package() { 0x0001ffff, 0, _SB.PCI0.LPCB.LNKA, 0 }, + Package() { 0x0002ffff, 0, _SB.PCI0.LPCB.LNKA, 0 }, // VGA + Package() { 0x0003ffff, 0, _SB.PCI0.LPCB.LNKA, 0 }, + Package() { 0x0016ffff, 0, _SB.PCI0.LPCB.LNKA, 0 }, // ME + Package() { 0x0016ffff, 1, _SB.PCI0.LPCB.LNKB, 0 }, // ME + Package() { 0x0016ffff, 2, _SB.PCI0.LPCB.LNKC, 0 }, // ME + Package() { 0x0016ffff, 3, _SB.PCI0.LPCB.LNKD, 0 }, // ME + Package() { 0x0019ffff, 0, _SB.PCI0.LPCB.LNKE, 0 }, // Ethernet + Package() { 0x001affff, 0, _SB.PCI0.LPCB.LNKE, 0 }, // USB + Package() { 0x001affff, 1, _SB.PCI0.LPCB.LNKF, 0 }, // USB + Package() { 0x001affff, 2, _SB.PCI0.LPCB.LNKG, 0 }, // USB + Package() { 0x001affff, 3, _SB.PCI0.LPCB.LNKH, 0 }, // USB + Package() { 0x001bffff, 1, _SB.PCI0.LPCB.LNKB, 0 }, // Audio + Package() { 0x001cffff, 0, _SB.PCI0.LPCB.LNKE, 0 }, // PCI + Package() { 0x001cffff, 1, _SB.PCI0.LPCB.LNKF, 0 }, // PCI + Package() { 0x001cffff, 2, _SB.PCI0.LPCB.LNKG, 0 }, // PCI + Package() { 0x001cffff, 3, _SB.PCI0.LPCB.LNKH, 0 }, // PCI + Package() { 0x001dffff, 0, _SB.PCI0.LPCB.LNKA, 0 }, // USB + Package() { 0x001dffff, 1, _SB.PCI0.LPCB.LNKB, 0 }, // USB + Package() { 0x001dffff, 2, _SB.PCI0.LPCB.LNKC, 0 }, // USB + Package() { 0x001dffff, 3, _SB.PCI0.LPCB.LNKD, 0 }, // USB + Package() { 0x001fffff, 0, _SB.PCI0.LPCB.LNKH, 0 }, // LPC + Package() { 0x001fffff, 1, _SB.PCI0.LPCB.LNKA, 0 }, // IDE + Package() { 0x001fffff, 2, _SB.PCI0.LPCB.LNKB, 0 }, // SATA + Package() { 0x001fffff, 3, _SB.PCI0.LPCB.LNKD, 0 } // SMBus + }) + } +} diff --git a/src/mainboard/lenovo/x201/acpi/superio.asl b/src/mainboard/lenovo/x201/acpi/superio.asl new file mode 100644 index 0000000..e69de29 diff --git a/src/mainboard/lenovo/x201/acpi/video.asl b/src/mainboard/lenovo/x201/acpi/video.asl new file mode 100644 index 0000000..95b7008 --- /dev/null +++ b/src/mainboard/lenovo/x201/acpi/video.asl @@ -0,0 +1,69 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (c) 2011 Sven Schnelle svens@stackframe.org + * + * 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 "smi.h" + +Scope (_SB.PCI0.GFX0) +{ + Device (LCD0) + { + Name (_ADR, 0x0400) + + Name (BRIG, Package (0x12) + { + 0xb2, + 0xb2, + 0x3, + 0x7, + 0x9, + 0xd, + 0x11, + 0x16, + 0x1a, + 0x21, + 0x27, + 0x2e, + 0x37, + 0x3f, + 0x4e, + 0x61, + 0x81, + 0xb2, + }) + + + Method (_BCL, 0, NotSerialized) + { + Return (BRIG) + } + + Method (_BCM, 1, NotSerialized) + { + Store (ShiftLeft (Arg0, 3), ^^BCLV) + } + Method (_BQC, 0, NotSerialized) + { + Store (^^BCLV, Local0) + ShiftRight (Local0, 3, Local0) + Return (Local0) + } + } +} diff --git a/src/mainboard/lenovo/x201/acpi_tables.c b/src/mainboard/lenovo/x201/acpi_tables.c new file mode 100644 index 0000000..665d7be --- /dev/null +++ b/src/mainboard/lenovo/x201/acpi_tables.c @@ -0,0 +1,275 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <string.h> +#include <console/console.h> +#include <arch/io.h> +#include <arch/ioapic.h> +#include <arch/acpi.h> +#include <arch/acpigen.h> +#include <arch/smp/mpspec.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> + +extern const unsigned char AmlCode[]; +#if CONFIG_HAVE_ACPI_SLIC +unsigned long acpi_create_slic(unsigned long current); +#endif + +#include "southbridge/intel/i82801gx/nvs.h" +static void acpi_create_gnvs(global_nvs_t *gnvs) +{ + memset((void *)gnvs, 0, sizeof(*gnvs)); + gnvs->apic = 1; + gnvs->mpen = 1; /* Enable Multi Processing */ + + /* Enable both COM ports */ + gnvs->cmap = 0x01; + gnvs->cmbp = 0x01; + + /* IGD Displays */ + gnvs->ndid = 3; + gnvs->did[0] = 0x80000100; + gnvs->did[1] = 0x80000240; + gnvs->did[2] = 0x80000410; + gnvs->did[3] = 0x80000410; + gnvs->did[4] = 0x00000005; +} + +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, + 1, IO_APIC_ADDR, 0); + + /* INT_SRC_OVR */ + current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *) + current, 0, 0, 2, MP_IRQ_POLARITY_DEFAULT | MP_IRQ_TRIGGER_DEFAULT); + current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *) + current, 0, 9, 9, MP_IRQ_POLARITY_HIGH | MP_IRQ_TRIGGER_LEVEL); + + /* LAPIC_NMI */ + current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *) + current, 0, + MP_IRQ_POLARITY_HIGH | + MP_IRQ_TRIGGER_EDGE, 0x01); + current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *) + current, 1, MP_IRQ_POLARITY_HIGH | + MP_IRQ_TRIGGER_EDGE, 0x01); + current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *) + current, 2, MP_IRQ_POLARITY_HIGH | + MP_IRQ_TRIGGER_EDGE, 0x01); + current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *) + current, 3, MP_IRQ_POLARITY_HIGH | + MP_IRQ_TRIGGER_EDGE, 0x01); + 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; +} + +void smm_setup_structures(void *gnvs, void *tcg, void *smi1); + +#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; +#if CONFIG_HAVE_ACPI_SLIC + acpi_header_t *slic; +#endif + acpi_header_t *ssdt; + acpi_header_t *dsdt; + void *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); + + /* + * We explicitly add these tables later on: + */ + printk(BIOS_DEBUG, "ACPI: * HPET\n"); + + hpet = (acpi_hpet_t *) current; + current += sizeof(acpi_hpet_t); + ALIGN_CURRENT; + acpi_create_hpet(hpet); + acpi_add_table(rsdp, hpet); + + /* If we want to use HPET Timers Linux wants an MADT */ + printk(BIOS_DEBUG, "ACPI: * MADT\n"); + + madt = (acpi_madt_t *) current; + acpi_create_madt(madt); + current += madt->header.length; + ALIGN_CURRENT; + acpi_add_table(rsdp, madt); + + printk(BIOS_DEBUG, "ACPI: * MCFG\n"); + mcfg = (acpi_mcfg_t *) current; + acpi_create_mcfg(mcfg); + current += mcfg->header.length; + ALIGN_CURRENT; + acpi_add_table(rsdp, mcfg); + + printk(BIOS_DEBUG, "ACPI: * FACS\n"); + facs = (acpi_facs_t *) current; + current += sizeof(acpi_facs_t); + ALIGN_CURRENT; + acpi_create_facs(facs); + + dsdt = (acpi_header_t *) current; + memcpy(dsdt, &AmlCode, sizeof(acpi_header_t)); + current += dsdt->length; + memcpy(dsdt, &AmlCode, dsdt->length); + + /* Fix up global NVS region for SMI handler. The GNVS region lives + * in the (high) table area. The low memory map looks like this: + * + * 0x00000000 - 0x000003ff Real Mode IVT + * 0x00000020 - 0x0000019c Low MP Table (XXX conflict?) + * 0x00000400 - 0x000004ff BDA (somewhat unused) + * 0x00000500 - 0x0000052f Moved GDT + * 0x00000530 - 0x00000b64 coreboot table + * 0x0007c000 - 0x0007dfff OS boot sector (unused?) + * 0x0007e000 - 0x0007ffff free to use (so no good for acpi+smi) + * 0x00080000 - 0x0009fbff usable ram + * 0x0009fc00 - 0x0009ffff EBDA (unused?) + * 0x000a0000 - 0x000bffff VGA memory + * 0x000c0000 - 0x000cffff VGA option rom + * 0x000d0000 - 0x000dffff free for other option roms? + * 0x000e0000 - 0x000fffff SeaBIOS? (conflict with low tables:) + * 0x000f0000 - 0x000f03ff PIRQ table + * 0x000f0400 - 0x000f66?? ACPI tables + * 0x000f66?? - 0x000f???? DMI tables + */ + + ALIGN_CURRENT; + + /* Pack GNVS into the ACPI table area */ + 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 -> 0x%08x\n", i, (u32)current); + *(u32*)(((u32)dsdt) + i) = current; // 0x92 bytes + break; + } + } + + /* And fill it */ + acpi_create_gnvs((global_nvs_t *)current); + + /* Keep pointer around */ + gnvs = (void *)current; + + current += 0x100; + ALIGN_CURRENT; + + /* And tell SMI about it */ + smm_setup_structures(gnvs, NULL, NULL); + + /* 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: * DSDT @ %p Length %x\n", dsdt, + dsdt->length); + +#if CONFIG_HAVE_ACPI_SLIC + printk(BIOS_DEBUG, "ACPI: * SLIC\n"); + slic = (acpi_header_t *)current; + current += acpi_create_slic(current); + ALIGN_CURRENT; + acpi_add_table(rsdp, slic); +#endif + + printk(BIOS_DEBUG, "ACPI: * FADT\n"); + 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: * SSDT\n"); + ssdt = (acpi_header_t *)current; + acpi_create_ssdt_generator(ssdt, ACPI_TABLE_CREATOR); + current += ssdt->length; + acpi_add_table(rsdp, ssdt); + ALIGN_CURRENT; + + printk(BIOS_DEBUG, "current = %lx\n", current); + printk(BIOS_INFO, "ACPI: done.\n"); + + /* Enable Dummy DCC ON# for DVI */ + printk(BIOS_DEBUG, "Laptop handling...\n"); + outb(inb(0x60f) & ~(1 << 5), 0x60f); + + return current; +} diff --git a/src/mainboard/lenovo/x201/cmos.layout b/src/mainboard/lenovo/x201/cmos.layout new file mode 100644 index 0000000..6d2ac45 --- /dev/null +++ b/src/mainboard/lenovo/x201/cmos.layout @@ -0,0 +1,139 @@ +## +## 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 + +# Stumpy USB reset workaround disable +400 8 r 0 stumpy_usb_reset_disable + +# coreboot config options: southbridge +408 1 e 1 nmi +409 2 e 7 power_on_after_fail +#411 5 r 0 unused + +# coreboot config options: bootloader +#Used by ChromeOS: +416 128 r 0 vbnv +#544 440 r 0 unused + +# SandyBridge MRC Scrambler Seed values +896 32 r 0 mrc_scrambler_seed +928 32 r 0 mrc_scrambler_seed_s3 +960 16 r 0 mrc_scrambler_seed_chk + +# 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/lenovo/x201/devicetree.cb b/src/mainboard/lenovo/x201/devicetree.cb new file mode 100644 index 0000000..c4c67a9 --- /dev/null +++ b/src/mainboard/lenovo/x201/devicetree.cb @@ -0,0 +1,148 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2007-2009 coresystems GmbH +## Copyright (C) 2011 Sven Schnelle svens@stackframe.org +## +## 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 northbridge/intel/sandybridge + + + # Enable DisplayPort Hotplug with 6ms pulse + register "gpu_dp_d_hotplug" = "0x06" + + # Enable Panel as LVDS and configure power delays + register "gpu_panel_port_select" = "0" # LVDS + register "gpu_panel_power_cycle_delay" = "3" + register "gpu_panel_power_up_delay" = "250" + register "gpu_panel_power_down_delay" = "250" + register "gpu_panel_power_backlight_on_delay" = "2500" + register "gpu_panel_power_backlight_off_delay" = "2500" + register "gpu_cpu_backlight" = "0x58d" + register "gpu_pch_backlight" = "0x061a061a" + + chip ec/lenovo/pmh7 + device pnp ff.1 on # dummy + end + register "backlight_enable" = "0x01" + register "dock_event_enable" = "0x01" + end + + chip ec/lenovo/h8 + device pnp ff.2 on # dummy + io 0x60 = 0x62 + io 0x62 = 0x66 + io 0x64 = 0x1600 + io 0x66 = 0x1604 + end + + register "config0" = "0xa6" + register "config1" = "0x05" + register "config2" = "0xa0" + register "config3" = "0x01" + + register "beepmask0" = "0xfe" + register "beepmask1" = "0x96" + + register "event2_enable" = "0xff" + register "event3_enable" = "0xff" + register "event4_enable" = "0xf4" + register "event5_enable" = "0x3c" + register "event6_enable" = "0x80" + register "event7_enable" = "0x01" + register "eventc_enable" = "0x3c" + register "event8_enable" = "0x01" + register "event9_enable" = "0xff" + register "eventa_enable" = "0xff" + register "eventb_enable" = "0xff" + register "eventc_enable" = "0xff" + register "eventd_enable" = "0xff" + + register "wlan_enable" = "0x01" + register "trackpoint_enable" = "0x03" + end + + device lapic_cluster 0 on + chip cpu/intel/model_206ax + device lapic 0 on end + end + end + + device pci_domain 0 on + device pci 00.0 on # Host bridge + subsystemid 0x17aa 0x2193 + end + device pci 02.0 on # VGA controller + subsystemid 0x17aa 0x215a + end + chip southbridge/intel/bd82x6x + register "pirqa_routing" = "0x0b" + register "pirqb_routing" = "0x0b" + register "pirqc_routing" = "0x0b" + register "pirqd_routing" = "0x0b" + register "pirqe_routing" = "0x0b" + register "pirqf_routing" = "0x0b" + register "pirqg_routing" = "0x0b" + register "pirqh_routing" = "0x0b" + + # GPI routing + # 0 No effect (default) + # 1 SMI# (if corresponding ALT_GPI_SMI_EN bit is also set) + # 2 SCI (if corresponding GPIO_EN bit is also set) + register "gpi1_routing" = "2" + register "gpi13_routing" = "2" + + register "sata_ahci" = "0x1" + register "sata_port_map" = "0x33" + + register "gpe0_en" = "0x20022046" + register "alt_gp_smi_en" = "0x0000" + + device pci 16.2 on # IDE/SATA + subsystemid 0x17aa 0x2161 + end + + device pci 19.0 on # Ethernet + subsystemid 0x17aa 0x2153 + end + + device pci 1a.0 on # USB2 EHCI + subsystemid 0x17aa 0x2163 + end + +# register "c4onc3_enable" = "1" + device pci 1b.0 on # Audio Controller + subsystemid 0x17aa 0x215e + end + device pci 1d.0 on # USB2 EHCI + subsystemid 0x17aa 0x2163 + end + device pci 1f.0 on # PCI-LPC bridge + subsystemid 0x17aa 0x2166 + end + device pci 1f.2 on # IDE/SATA + subsystemid 0x17aa 0x2168 + end + device pci 1f.3 on # SMBUS + subsystemid 0x17aa 0x2167 + end + end + chip southbridge/ricoh/rl5c476 + end + end +end diff --git a/src/mainboard/lenovo/x201/dock.c b/src/mainboard/lenovo/x201/dock.c new file mode 100644 index 0000000..1b15a6c --- /dev/null +++ b/src/mainboard/lenovo/x201/dock.c @@ -0,0 +1,270 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Sven Schnelle svens@stackframe.org + * + * 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 <arch/io.h> +#include <delay.h> +#include <arch/io.h> +#include "dock.h" +#include "southbridge/intel/i82801gx/i82801gx.h" +#include "superio/nsc/pc87392/pc87392.h" + +static void dlpc_write_register(int reg, int value) +{ + outb(reg, 0x164e); + outb(value, 0x164f); +} + +static u8 dlpc_read_register(int reg) +{ + outb(reg, 0x164e); + return inb(0x164f); +} + +static void dock_write_register(int reg, int value) +{ + outb(reg, 0x2e); + outb(value, 0x2f); +} + +static u8 dock_read_register(int reg) +{ + outb(reg, 0x2e); + return inb(0x2f); +} + +static void dlpc_gpio_set_mode(int port, int mode) +{ + dlpc_write_register(0xf0, port); + dlpc_write_register(0xf1, mode); +} + +static void dock_gpio_set_mode(int port, int mode, int irq) +{ + dock_write_register(0xf0, port); + dock_write_register(0xf1, mode); + dock_write_register(0xf2, irq); +} + +static void dlpc_gpio_init(void) +{ + /* Select GPIO module */ + dlpc_write_register(0x07, 0x07); + /* GPIO Base Address 0x1680 */ + dlpc_write_register(0x60, 0x16); + dlpc_write_register(0x61, 0x80); + + /* Activate GPIO */ + dlpc_write_register(0x30, 0x01); + + dlpc_gpio_set_mode(0x00, 3); + dlpc_gpio_set_mode(0x01, 3); + dlpc_gpio_set_mode(0x02, 0); + dlpc_gpio_set_mode(0x03, 3); + dlpc_gpio_set_mode(0x04, 4); + dlpc_gpio_set_mode(0x20, 4); + dlpc_gpio_set_mode(0x21, 4); + dlpc_gpio_set_mode(0x23, 4); +} + +int dlpc_init(void) +{ + int timeout = 1000; + + /* Enable 14.318MHz CLK on CLKIN */ + dlpc_write_register(0x29, 0xa0); + while(!(dlpc_read_register(0x29) & 0x10) && timeout--) + udelay(1000); + + if (!timeout) + return 1; + + /* Select DLPC module */ + dlpc_write_register(0x07, 0x19); + /* DLPC Base Address 0x164c */ + dlpc_write_register(0x60, 0x16); + dlpc_write_register(0x61, 0x4c); + /* Activate DLPC */ + dlpc_write_register(0x30, 0x01); + + dlpc_gpio_init(); + + return 0; +} + +int dock_connect(void) +{ + int timeout = 1000; + + outb(0x07, 0x164c); + + timeout = 1000; + + while(!(inb(0x164c) & 8) && timeout--) + udelay(1000); + + if (!timeout) { + /* docking failed, disable DLPC switch */ + outb(0x00, 0x164c); + dlpc_write_register(0x30, 0x00); + return 1; + } + + /* Assert D_PLTRST# */ + outb(0xfe, 0x1680); + udelay(100000); + /* Deassert D_PLTRST# */ + outb(0xff, 0x1680); + + udelay(100000); + + /* startup 14.318MHz Clock */ + dock_write_register(0x29, 0x06); + /* wait until clock is settled */ + timeout = 1000; + while(!(dock_read_register(0x29) & 0x08) && timeout--) + udelay(1000); + + if (!timeout) + return 1; + + /* Pin 6: CLKRUN + * Pin 72: #DR1 + * Pin 19: #SMI + * Pin 73: #MTR + */ + dock_write_register(0x24, 0x37); + + /* PNF active HIGH */ + dock_write_register(0x25, 0xa0); + + /* disable FDC */ + dock_write_register(0x26, 0x01); + + /* Enable GPIO IRQ to #SMI */ + dock_write_register(0x28, 0x02); + + /* select GPIO */ + dock_write_register(0x07, 0x07); + + /* set base address */ + dock_write_register(0x60, 0x16); + dock_write_register(0x61, 0x20); + + /* init GPIO pins */ + dock_gpio_set_mode(0x00, PC87392_GPIO_PIN_DEBOUNCE | + PC87392_GPIO_PIN_PULLUP, 0x00); + + dock_gpio_set_mode(0x01, PC87392_GPIO_PIN_DEBOUNCE | + PC87392_GPIO_PIN_PULLUP, + PC87392_GPIO_PIN_TRIGGERS_SMI); + + dock_gpio_set_mode(0x02, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x03, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x04, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x05, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x06, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x07, PC87392_GPIO_PIN_PULLUP, 0x02); + + dock_gpio_set_mode(0x10, PC87392_GPIO_PIN_DEBOUNCE | + PC87392_GPIO_PIN_PULLUP, + PC87392_GPIO_PIN_TRIGGERS_SMI); + + dock_gpio_set_mode(0x11, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x12, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x13, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x14, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x15, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x16, PC87392_GPIO_PIN_PULLUP | + PC87392_GPIO_PIN_OE , 0x00); + + dock_gpio_set_mode(0x17, PC87392_GPIO_PIN_PULLUP, 0x00); + + dock_gpio_set_mode(0x20, PC87392_GPIO_PIN_TYPE_PUSH_PULL | + PC87392_GPIO_PIN_OE, 0x00); + + dock_gpio_set_mode(0x21, PC87392_GPIO_PIN_TYPE_PUSH_PULL | + PC87392_GPIO_PIN_OE, 0x00); + + dock_gpio_set_mode(0x22, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x23, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x24, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x25, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x26, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x27, PC87392_GPIO_PIN_PULLUP, 0x00); + + dock_gpio_set_mode(0x30, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x31, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x32, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x33, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x34, PC87392_GPIO_PIN_PULLUP, 0x00); + + dock_gpio_set_mode(0x35, PC87392_GPIO_PIN_PULLUP | + PC87392_GPIO_PIN_OE, 0x00); + + dock_gpio_set_mode(0x36, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x37, PC87392_GPIO_PIN_PULLUP, 0x00); + + /* enable GPIO */ + dock_write_register(0x30, 0x01); + + outb(0x00, 0x1628); + outb(0x00, 0x1623); + outb(0x82, 0x1622); + outb(0xff, 0x1624); + + /* Enable USB and Ultrabay power */ + outb(0x03, 0x1628); + + dock_write_register(0x07, 0x03); + dock_write_register(0x30, 0x01); + console_init(); + return 0; +} + +void dock_disconnect(void) +{ + printk(BIOS_DEBUG, "%s enter\n", __func__); + /* disconnect LPC bus */ + outb(0x00, 0x164c); + udelay(10000); + + /* Assert PLTRST and DLPCPD */ + outb(0xfc, 0x1680); + udelay(10000); + + /* disable Ultrabay and USB Power */ + outb(0x00, 0x1628); + udelay(10000); + + printk(BIOS_DEBUG, "%s finish\n", __func__); +} + +int dock_present(void) +{ + return !((inb(DEFAULT_GPIOBASE + 0x0c) >> 13) & 1); +} + +int dock_ultrabay_device_present(void) +{ + return inb(0x1621) & 0x02 ? 0 : 1; +} diff --git a/src/mainboard/lenovo/x201/dock.h b/src/mainboard/lenovo/x201/dock.h new file mode 100644 index 0000000..141ae48 --- /dev/null +++ b/src/mainboard/lenovo/x201/dock.h @@ -0,0 +1,28 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Sven Schnelle svens@stackframe.org + * + * 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 THINKPAD_X60_DOCK_H +#define THINKPAD_X60_DOCK_H + +extern int dock_connect(void); +extern void dock_disconnect(void); +extern int dock_present(void); +extern int dlpc_init(void); +extern int dock_ultrabay_device_present(void); +#endif diff --git a/src/mainboard/lenovo/x201/dsdt.asl b/src/mainboard/lenovo/x201/dsdt.asl new file mode 100644 index 0000000..de67721 --- /dev/null +++ b/src/mainboard/lenovo/x201/dsdt.asl @@ -0,0 +1,94 @@ +/* + * 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 + */ + +DefinitionBlock( + "dsdt.aml", + "DSDT", + 0x03, // DSDT revision: ACPI v3.0 + "COREv4", // OEM id + "COREBOOT", // OEM table id + 0x20090419 // OEM revision +) +{ + // Some generic macros + #include "acpi/platform.asl" + + // global NVS and variables + #include <southbridge/intel/bd82x6x/acpi/globalnvs.asl> + + // General Purpose Events + #include "acpi/gpe.asl" + + // mainboard specific devices + #include "acpi/mainboard.asl" + + #include <cpu/intel/model_206ax/acpi/cpu.asl> + + Scope (_SB) { + Device (PCI0) + { + #include <northbridge/intel/sandybridge/acpi/sandybridge.asl> + #include <southbridge/intel/bd82x6x/acpi/pch.asl> + } + Device (UNCR) + { + Name (_BBN, 0xFF) + Name (_ADR, 0x00) + Name (RID, 0x00) + Name (_HID, EisaId ("PNP0A03")) + Name (_CRS, ResourceTemplate () + { + WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, + 0x0000, // Granularity + 0x00FF, // Range Minimum + 0x00FF, // Range Maximum + 0x0000, // Translation Offset + 0x0001, // Length + ,, ) + }) + Device (SAD) + { + Name (_ADR, 0x01) + Name (RID, 0x00) + OperationRegion (SADC, PCI_Config, 0x00, 0x0100) + Field (SADC, DWordAcc, NoLock, Preserve) + { + Offset (0x40), + PAM0, 8, + PAM1, 8, + PAM2, 8, + PAM3, 8, + PAM4, 8, + PAM5, 8, + PAM6, 8 + } + } + } + } + + #include "acpi/video.asl" + + /* Chipset specific sleep states */ + #include <southbridge/intel/i82801gx/acpi/sleepstates.asl> + + // Dock support code + #include "acpi/dock.asl" +} diff --git a/src/mainboard/lenovo/x201/fadt.c b/src/mainboard/lenovo/x201/fadt.c new file mode 100644 index 0000000..8fbd0ac --- /dev/null +++ b/src/mainboard/lenovo/x201/fadt.c @@ -0,0 +1,159 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2008 coresystems GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <string.h> +#include <device/pci.h> +#include <arch/acpi.h> +#include <cpu/x86/smm.h> + +/* FIXME: This needs to go into a separate .h file + * to be included by the ich7 smi handler, ich7 smi init + * code and the mainboard fadt. + */ + +void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt) +{ + acpi_header_t *header = &(fadt->header); + u16 pmbase = pci_read_config16(dev_find_slot(0, PCI_DEVFN(0x1f,0)), 0x40) & 0xfffe; + + memset((void *) fadt, 0, sizeof(acpi_fadt_t)); + memcpy(header->signature, "FACP", 4); + header->length = sizeof(acpi_fadt_t); + header->revision = 3; + 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 = 0; + + fadt->firmware_ctrl = (unsigned long) facs; + fadt->dsdt = (unsigned long) dsdt; + fadt->model = 0x00; + fadt->preferred_pm_profile = PM_MOBILE; + fadt->sci_int = 0x9; + fadt->smi_cmd = APM_CNT; + fadt->acpi_enable = APM_CNT_ACPI_ENABLE; + fadt->acpi_disable = APM_CNT_ACPI_DISABLE; + fadt->s4bios_req = 0x0; + fadt->pstate_cnt = APM_CNT_PST_CONTROL; + + fadt->pm1a_evt_blk = pmbase; + fadt->pm1b_evt_blk = 0x0; + fadt->pm1a_cnt_blk = pmbase + 0x4; + fadt->pm1b_cnt_blk = 0x0; + fadt->pm2_cnt_blk = pmbase + 0x50; + fadt->pm_tmr_blk = pmbase + 0x8; + fadt->gpe0_blk = pmbase + 0x20; + fadt->gpe1_blk = 0; + + fadt->pm1_evt_len = 4; + fadt->pm1_cnt_len = 2; + fadt->pm2_cnt_len = 1; + fadt->pm_tmr_len = 4; + fadt->gpe0_blk_len = 0x10; + fadt->gpe1_blk_len = 0; + fadt->gpe1_base = 0; + fadt->cst_cnt = APM_CNT_CST_CONTROL; + fadt->p_lvl2_lat = 1; + fadt->p_lvl3_lat = 0x23; + fadt->flush_size = 0; + fadt->flush_stride = 0; + fadt->duty_offset = 1; + fadt->duty_width = 3; + fadt->day_alrm = 0xd; + fadt->mon_alrm = 0x00; + fadt->century = 0x32; + fadt->iapc_boot_arch = 0x00; + fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED | + ACPI_FADT_SLEEP_BUTTON | ACPI_FADT_S4_RTC_WAKE | + ACPI_FADT_DOCKING_SUPPORTED; + + fadt->reset_reg.space_id = 0; + fadt->reset_reg.bit_width = 0; + fadt->reset_reg.bit_offset = 0; + fadt->reset_reg.resv = 0; + fadt->reset_reg.addrl = 0x0; + fadt->reset_reg.addrh = 0x0; + + fadt->reset_value = 0; + fadt->x_firmware_ctl_l = (unsigned long)facs; + fadt->x_firmware_ctl_h = 0; + fadt->x_dsdt_l = (unsigned long)dsdt; + fadt->x_dsdt_h = 0; + + fadt->x_pm1a_evt_blk.space_id = 1; + fadt->x_pm1a_evt_blk.bit_width = 32; + fadt->x_pm1a_evt_blk.bit_offset = 0; + fadt->x_pm1a_evt_blk.resv = 0; + fadt->x_pm1a_evt_blk.addrl = pmbase; + fadt->x_pm1a_evt_blk.addrh = 0x0; + + fadt->x_pm1b_evt_blk.space_id = 0; + fadt->x_pm1b_evt_blk.bit_width = 0; + fadt->x_pm1b_evt_blk.bit_offset = 0; + fadt->x_pm1b_evt_blk.resv = 0; + fadt->x_pm1b_evt_blk.addrl = 0x0; + fadt->x_pm1b_evt_blk.addrh = 0x0; + + fadt->x_pm1a_cnt_blk.space_id = 1; + fadt->x_pm1a_cnt_blk.bit_width = 32; + fadt->x_pm1a_cnt_blk.bit_offset = 0; + fadt->x_pm1a_cnt_blk.resv = 0; + fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4; + fadt->x_pm1a_cnt_blk.addrh = 0x0; + + fadt->x_pm1b_cnt_blk.space_id = 0; + fadt->x_pm1b_cnt_blk.bit_width = 0; + fadt->x_pm1b_cnt_blk.bit_offset = 0; + fadt->x_pm1b_cnt_blk.resv = 0; + fadt->x_pm1b_cnt_blk.addrl = 0x0; + fadt->x_pm1b_cnt_blk.addrh = 0x0; + + fadt->x_pm2_cnt_blk.space_id = 1; + fadt->x_pm2_cnt_blk.bit_width = 8; + fadt->x_pm2_cnt_blk.bit_offset = 0; + fadt->x_pm2_cnt_blk.resv = 0; + fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50; + fadt->x_pm2_cnt_blk.addrh = 0x0; + + fadt->x_pm_tmr_blk.space_id = 1; + fadt->x_pm_tmr_blk.bit_width = 32; + fadt->x_pm_tmr_blk.bit_offset = 0; + fadt->x_pm_tmr_blk.resv = 0; + fadt->x_pm_tmr_blk.addrl = pmbase + 0x8; + fadt->x_pm_tmr_blk.addrh = 0x0; + + fadt->x_gpe0_blk.space_id = 1; + fadt->x_gpe0_blk.bit_width = 128; + fadt->x_gpe0_blk.bit_offset = 0; + fadt->x_gpe0_blk.resv = 0; + fadt->x_gpe0_blk.addrl = pmbase + 0x20; + fadt->x_gpe0_blk.addrh = 0x0; + + fadt->x_gpe1_blk.space_id = 0; + fadt->x_gpe1_blk.bit_width = 0; + fadt->x_gpe1_blk.bit_offset = 0; + fadt->x_gpe1_blk.resv = 0; + fadt->x_gpe1_blk.addrl = 0x0; + fadt->x_gpe1_blk.addrh = 0x0; + + header->checksum = + acpi_checksum((void *) fadt, header->length); +} diff --git a/src/mainboard/lenovo/x201/irq_tables.c b/src/mainboard/lenovo/x201/irq_tables.c new file mode 100644 index 0000000..f1ab06d --- /dev/null +++ b/src/mainboard/lenovo/x201/irq_tables.c @@ -0,0 +1,62 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (c) 2011 Sven Schnelle svens@stackframe.org + * + * 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/pirq_routing.h> + +static const struct irq_routing_table intel_irq_routing_table = { + PIRQ_SIGNATURE, /* u32 signature */ + PIRQ_VERSION, /* u16 version */ + 32 + 16 * 15, /* Max. number of devices on the bus */ + 0x00, /* Interrupt router bus */ + (0x1f << 3) | 0x0, /* Interrupt router dev */ + 0, /* IRQs devoted exclusively to PCI usage */ + 0x8086, /* Vendor */ + 0x122e, /* Device */ + 0, /* Miniport */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */ + 0xf5, /* Checksum (has to be set to some value that + * would give 0 after the sum of all bytes + * for this structure (including checksum). + */ + { + /* bus, dev | fn, {link, bitmap}, {link, bitmap}, {link, bitmap}, {link, bitmap}, slot, rfu */ + {0x00, (0x00 << 3) | 0x0, {{0x60, 0x1cf8}, {0x61, 0x1cf8}, {0x62, 0x1cf8}, {0x63, 0x1cf8}}, 0x0, 0x0}, /* Host 0:00.0 */ + {0x00, (0x02 << 3) | 0x0, {{0x60, 0x1cf8}, {0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, 0x0, 0x0}, /* VGA 0:02.0 */ + {0x00, (0x1b << 3) | 0x0, {{0x00, 0xdef8}, {0x61, 0x1cf8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, 0x0, 0x0}, /* HD Audio 0:1b.0 */ + {0x00, (0x1c << 3) | 0x0, {{0x68, 0x1cf8}, {0x69, 0x1cf8}, {0x6a, 0x1cf8}, {0x6b, 0x1cf8}}, 0x0, 0x0}, /* PCIe 0:1c.0 */ + {0x00, (0x1c << 3) | 0x1, {{0x68, 0x1cf8}, {0x69, 0x1cf8}, {0x6a, 0x1cf8}, {0x6b, 0x1cf8}}, 0x0, 0x0}, /* PCIe 0:1c.1 */ + {0x00, (0x1c << 3) | 0x2, {{0x68, 0x1cf8}, {0x69, 0x1cf8}, {0x6a, 0x1cf8}, {0x6b, 0x1cf8}}, 0x0, 0x0}, /* PCIe 0:1c.2 */ + {0x00, (0x1c << 3) | 0x3, {{0x68, 0x1cf8}, {0x69, 0x1cf8}, {0x6a, 0x1cf8}, {0x6b, 0x1cf8}}, 0x0, 0x0}, /* PCIe 0:1c.3 */ + {0x00, (0x1d << 3) | 0x0, {{0x60, 0x1cf8}, {0x61, 0x1cf8}, {0x62, 0x1cf8}, {0x63, 0x1cf8}}, 0x0, 0x0}, /* USB 0:1d.0 */ + {0x00, (0x1d << 3) | 0x1, {{0x60, 0x1cf8}, {0x61, 0x1cf8}, {0x62, 0x1cf8}, {0x63, 0x1cf8}}, 0x0, 0x0}, /* USB 0:1d.1 */ + {0x00, (0x1d << 3) | 0x2, {{0x60, 0x1cf8}, {0x61, 0x1cf8}, {0x62, 0x1cf8}, {0x63, 0x1cf8}}, 0x0, 0x0}, /* USB 0:1d.2 */ + {0x00, (0x1d << 3) | 0x3, {{0x60, 0x1cf8}, {0x61, 0x1cf8}, {0x62, 0x1cf8}, {0x63, 0x1cf8}}, 0x0, 0x0}, /* USB 0:1d.3 */ + {0x00, (0x1e << 3) | 0x0, {{0x60, 0x1cf8}, {0x61, 0x1cf8}, {0x62, 0x1cf8}, {0x63, 0x1cf8}}, 0x0, 0x0}, /* PCI 0:1e.0 */ + {0x00, (0x1f << 3) | 0x0, {{0x6b, 0x1cf8}, {0x60, 0x1cf8}, {0x60, 0x1cf8}, {0x00, 0xdef8}}, 0x0, 0x0}, /* LPC 0:1f.0 */ + {0x00, (0x1f << 3) | 0x1, {{0x6b, 0x1cf8}, {0x60, 0x1cf8}, {0x60, 0x1cf8}, {0x00, 0xdef8}}, 0x0, 0x0}, /* IDE 0:1f.1 */ + {0x00, (0x1f << 3) | 0x2, {{0x6b, 0x1cf8}, {0x60, 0x1cf8}, {0x60, 0x1cf8}, {0x00, 0xdef8}}, 0x0, 0x0}, /* SATA 0:1f.2 */ + } +}; + +unsigned long write_pirq_routing_table(unsigned long addr) +{ + return copy_pirq_routing_table(addr, &intel_irq_routing_table); +} diff --git a/src/mainboard/lenovo/x201/mainboard.c b/src/mainboard/lenovo/x201/mainboard.c new file mode 100644 index 0000000..dae8bdf --- /dev/null +++ b/src/mainboard/lenovo/x201/mainboard.c @@ -0,0 +1,295 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2011 Sven Schnelle svens@stackframe.org + * + * 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 <arch/io.h> +#include <delay.h> +#include <device/pci_def.h> +#include <device/pci_ops.h> +#include <device/pci_ids.h> +#include <arch/io.h> +#include <ec/lenovo/pmh7/pmh7.h> +#include <ec/acpi/ec.h> +#include <ec/lenovo/h8/h8.h> +#include <northbridge/intel/i945/i945.h> +#include <pc80/mc146818rtc.h> +#include "dock.h" +#include <arch/x86/include/arch/acpigen.h> +#if CONFIG_PCI_OPTION_ROM_RUN_YABEL || CONFIG_PCI_OPTION_ROM_RUN_REALMODE +#include <x86emu/regs.h> +#include <arch/interrupt.h> +#endif +#include <pc80/keyboard.h> +#include <cpu/x86/lapic.h> +#include <device/pci.h> +#include <smbios.h> + +static acpi_cstate_t cst_entries[] = { + { 1, 1, 1000, { 0x7f, 1, 2, { 0 }, 1, 0 } }, + { 2, 1, 500, { 0x01, 8, 0, { 0 }, DEFAULT_PMBASE + LV2, 0 } }, + { 2, 17, 250, { 0x01, 8, 0, { 0 }, DEFAULT_PMBASE + LV3, 0 } }, +}; + +int get_cst_entries(acpi_cstate_t **entries) +{ + *entries = cst_entries; + return ARRAY_SIZE(cst_entries); +} + +#if CONFIG_PCI_OPTION_ROM_RUN_YABEL || CONFIG_PCI_OPTION_ROM_RUN_REALMODE + +static int int15_handler(void) +{ + switch((X86_EAX & 0xffff)) { + /* Get boot display. */ + case 0x5f35: + X86_EAX = 0x5f; +#if 0 + /* DisplayPort */ + X86_ECX = 0x4; + /* VGA */ + X86_ECX = 0x1; +#endif + /* LCD */ + X86_ECX = 0x8; + + return 1; + case 0x5f40: + X86_EAX = 0x5f; + X86_ECX = 0x2; + return 1; + default: + printk(BIOS_WARNING, "Unknown INT15 function %04x!\n", + X86_EAX & 0xffff); + return 0; + } +} +#endif + +static void rcba_config(void) +{ +#if 0 +#if 0 + u32 reg32; + + /* + * GFX INTA -> PIRQA (MSI) + * D28IP_P1IP WLAN INTA -> PIRQB + * D28IP_P4IP ETH0 INTB -> PIRQC (MSI) + * D29IP_E1P EHCI1 INTA -> PIRQD + * D26IP_E2P EHCI2 INTA -> PIRQB + * D31IP_SIP SATA INTA -> PIRQA (MSI) + * D31IP_SMIP SMBUS INTC -> PIRQH + * D31IP_TTIP THRT INTB -> PIRQG + * D27IP_ZIP HDA INTA -> PIRQG (MSI) + * + * LIGHTSENSOR -> PIRQE (Edge Triggered) + * TRACKPAD -> PIRQF (Edge Triggered) + */ + /* Device interrupt pin register (board specific) */ + RCBA32(D31IP) = (INTD << D31IP_TTIP) | (INTC << D31IP_SIP2) | + (INTD << D31IP_UNKIP) | (INTA << D31IP_SMIP) | (INTB << D31IP_SIP); + RCBA32(D30IP) = (NOINT << D30IP_PIP); + RCBA32(D29IP) = 0x40043214;//(INTA << D29IP_E1P); + RCBA32(D28IP) = 0x00014321;//(INTA << D28IP_P1IP) | (INTC << D28IP_P3IP) | + // (INTB << D28IP_P4IP); + RCBA32(D27IP) = 0x00000002;//(INTA << D27IP_ZIP); + RCBA32(D26IP) = 0x30003214;//(INTA << D26IP_E2P); + RCBA32(D25IP) = (NOINT << D25IP_LIP); + RCBA32(D22IP) = (NOINT << D22IP_MEI1IP); +#endif + RCBA32 (0x30fc) = 0x00000000; + (void) RCBA32 (0x30fc); + RCBA32 (0x3100) = 0x04341200; + (void) RCBA32 (0x3100); + RCBA32 (0x3104) = 0x00000000; + (void) RCBA32 (0x3104); + RCBA32 (0x3108) = 0x40043214; + (void) RCBA32 (0x3108); + RCBA32 (0x310c) = 0x00014321; + (void) RCBA32 (0x310c); + RCBA32 (0x3110) = 0x00000002; + (void) RCBA32 (0x3110); + RCBA32 (0x3114) = 0x30003214; + (void) RCBA32 (0x3114); + RCBA32 (0x311c) = 0x00000002; + (void) RCBA32 (0x311c); + RCBA32 (0x3120) = 0x00000000; + (void) RCBA32 (0x3120); + RCBA32 (0x3124) = 0x00002321; + (void) RCBA32 (0x3124); + RCBA32 (0x313c) = 0x00000000; + (void) RCBA32 (0x313c); + RCBA32 (0x3140) = 0x00003107; + (void) RCBA32 (0x3140); + RCBA32 (0x3144) = 0x76543210; + (void) RCBA32 (0x3144); + RCBA32 (0x3148) = 0x00000010; + (void) RCBA32 (0x3148); + RCBA32 (0x314c) = 0x00007654; + (void) RCBA32 (0x314c); + RCBA32 (0x3150) = 0x00000004; + (void) RCBA32 (0x3150); + RCBA32 (0x3158) = 0x00000000; + (void) RCBA32 (0x3158); + RCBA32 (0x315c) = 0x00003210; + (void) RCBA32 (0x315c); + RCBA32 (0x31fc) = 0x03000000; + (void) RCBA32 (0x31fc); + +#if 0 + /* Device interrupt route registers */ + DIR_ROUTE(D31IR, PIRQA, PIRQG, PIRQH, PIRQB); + DIR_ROUTE(D29IR, PIRQD, PIRQE, PIRQG, PIRQH); + DIR_ROUTE(D28IR, PIRQB, PIRQC, PIRQD, PIRQE); + DIR_ROUTE(D27IR, PIRQG, PIRQH, PIRQA, PIRQB); + DIR_ROUTE(D26IR, PIRQB, PIRQC, PIRQD, PIRQA); + DIR_ROUTE(D25IR, PIRQA, PIRQB, PIRQC, PIRQD); + DIR_ROUTE(D22IR, PIRQA, PIRQB, PIRQC, PIRQD); + /* Enable IOAPIC (generic) */ + RCBA16(OIC) = 0x0100; + /* PCH BWG says to read back the IOAPIC enable register */ + (void) RCBA16(OIC); + /* Disable unused devices (board specific) */ + reg32 = RCBA32(FD); + reg32 |= PCH_DISABLE_ALWAYS; + RCBA32(FD) = reg32; +#endif + +#if 0 + RCBA32 (0x3418) = 0x16e61fe1; + (void) RCBA32 (0x3418); +#endif +#endif +} + +const char *smbios_mainboard_version(void) +{ + return "Lenovo X201"; +} + +static void mainboard_enable(device_t dev) +{ + device_t dev0; + u8 defaults_loaded = 0; + u16 pmbase; + + printk(BIOS_SPEW, "starting SPI configure\n"); + + /* Configure SPI. */ + RCBA32 (0x3800) = 0x07ff0500; + RCBA32 (0x3804) = 0x3f046008; + RCBA32 (0x3808) = 0x0058efc0; + RCBA32 (0x384c) = 0x92000000; + RCBA32 (0x3850) = 0x00000a0b; + RCBA32 (0x3858) = 0x07ff0500; + RCBA32 (0x385c) = 0x04ff0003; + RCBA32 (0x3860) = 0x00020001; + RCBA32 (0x3864) = 0x00000fff; + RCBA32 (0x3874) = 0x9fff07d0; + RCBA32 (0x3890) = 0xf8400000; + RCBA32 (0x3894) = 0x143b5006; + RCBA32 (0x3898) = 0x05200302; + RCBA32 (0x389c) = 0x0601209f; + RCBA32 (0x38b0) = 0x00000004; + RCBA32 (0x38b4) = 0x03040002; + RCBA32 (0x38c0) = 0x00000007; + RCBA32 (0x38c4) = 0x00802005; + RCBA32 (0x38c8) = 0x00002005; + RCBA32 (0x3804) = 0x3f04e008; + + printk(BIOS_SPEW, "SPI configured\n"); + + pmbase = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x1f, 0)), + PMBASE) & 0xff80; + + printk(BIOS_SPEW, " ... pmbase = 0x%04x\n", pmbase); + + outl(0, pmbase + SMI_EN); + + printk(BIOS_ERR, " smi_en = 0x%08x\n", inl(pmbase + SMI_EN)); + + enable_lapic(); + pci_write_config32(dev_find_slot(0, PCI_DEVFN(0x1f, 0)), GPIO_BASE, DEFAULT_GPIOBASE|1); + pci_write_config8(dev_find_slot(0, PCI_DEVFN(0x1f, 0)), GPIO_CNTL, 0x10); + + rcba_config(); + +#ifdef DISABLED + ec_clr_bit(0x03, 2); + + if (inb(0x164c) & 0x08) { + ec_set_bit(0x03, 2); + ec_write(0x0c, 0x88); + } +#endif + /* If we're resuming from suspend, blink suspend LED */ + dev0 = dev_find_slot(0, PCI_DEVFN(0,0)); + if (dev0 && pci_read_config32(dev0, SKPAD) == SKPAD_ACPI_S3_MAGIC) + ec_write(0x0c, 0xc7); + +#ifdef DISABLED + idedev = dev_find_slot(0, PCI_DEVFN(0x1f,1)); + if (idedev && idedev->chip_info && dock_ultrabay_device_present()) { + struct southbridge_intel_i82801gx_config *config = idedev->chip_info; + config->ide_enable_primary = 1; + /* enable Ultrabay power */ + outb(inb(0x1628) | 0x01, 0x1628); + ec_write(0x0c, 0x84); + } else { + /* disable Ultrabay power */ + outb(inb(0x1628) & ~0x01, 0x1628); + ec_write(0x0c, 0x04); + } +#endif + + if (get_option(&defaults_loaded, "cmos_defaults_loaded") < 0) { + printk(BIOS_INFO, "failed to get cmos_defaults_loaded"); + defaults_loaded = 0; + } + + if (!defaults_loaded) { + printk(BIOS_INFO, "Restoring CMOS defaults\n"); + set_option("tft_brightness", &(u8[]){ 0xff }); + set_option("volume", &(u8[]){ 0x03 }); + /* set baudrate to 115200 baud */ + set_option("baud_rate", &(u8[]){ 0x00 }); + /* set default debug_level (DEFAULT_CONSOLE_LOGLEVEL starts at 1) */ + set_option("debug_level", &(u8[]) { CONFIG_DEFAULT_CONSOLE_LOGLEVEL+1 }); + set_option("cmos_defaults_loaded", &(u8[]){ 0x01 }); + } +#if CONFIG_PCI_OPTION_ROM_RUN_YABEL || CONFIG_PCI_OPTION_ROM_RUN_REALMODE + /* Install custom int15 handler for VGA OPROM */ + mainboard_interrupt_handlers(0x15, &int15_handler); +#endif + + /* This sneaked in here, because X201 SuperIO chip isn't really + connected to anything and hence we don't init it. + */ + pc_keyboard_init(0); +} + +struct chip_operations mainboard_ops = { + .enable_dev = mainboard_enable, +}; + diff --git a/src/mainboard/lenovo/x201/mptable.c b/src/mainboard/lenovo/x201/mptable.c new file mode 100644 index 0000000..a83a3a2 --- /dev/null +++ b/src/mainboard/lenovo/x201/mptable.c @@ -0,0 +1,61 @@ +/* generated by MPTable, version 2.0.15*/ +/* as modified by RGM for coreboot */ +#include <console/console.h> +#include <arch/smp/mpspec.h> +#include <arch/ioapic.h> +#include <device/pci.h> +#include <string.h> +#include <stdint.h> + +#define INTA 0x00 +#define INTB 0x01 +#define INTC 0x02 +#define INTD 0x03 + +static void *smp_write_config_table(void *v) +{ + struct mp_config_table *mc; + int isa_bus; + + mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN); + + mptable_init(mc, LOCAL_APIC_ADDR); + + smp_write_processors(mc); + + mptable_write_buses(mc, NULL, &isa_bus); + /* I/O APICs: APIC ID Version State Address */ + smp_write_ioapic(mc, 0x2, 0x20, 0xfec00000); + + mptable_add_isa_interrupts(mc, isa_bus, 0x2, 0); + + /* I/O Ints: Type Polarity Trigger Bus ID IRQ APIC ID PIN#*/ + smp_write_intsrc(mc, mp_ExtINT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0x0, 0x2, 0x0); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0x1, 0x2, 0x1); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0x0, 0x2, 0x2); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0x3, 0x2, 0x3); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0x4, 0x2, 0x4); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0x5, 0x2, 0x5); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0x6, 0x2, 0x6); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0x7, 0x2, 0x7); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0x8, 0x2, 0x8); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0x9, 0x2, 0x9); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0xa, 0x2, 0xa); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0xb, 0x2, 0xb); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0xc, 0x2, 0xc); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0xd, 0x2, 0xd); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0xe, 0x2, 0xe); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0xf, 0x2, 0xf); + /* Local Ints: Type Polarity Trigger Bus ID IRQ APIC ID PIN# */ + smp_write_lintsrc(mc, mp_ExtINT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0x0, MP_APIC_ALL, 0x0); + smp_write_lintsrc(mc, mp_NMI, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x3, 0x0, MP_APIC_ALL, 0x1); + + return mptable_finalize(mc); +} + +unsigned long write_smp_table(unsigned long addr) +{ + void *v; + v = smp_write_floating_table(addr, 0); + return (unsigned long)smp_write_config_table(v); +} diff --git a/src/mainboard/lenovo/x201/romstage.c b/src/mainboard/lenovo/x201/romstage.c new file mode 100644 index 0000000..d551253 --- /dev/null +++ b/src/mainboard/lenovo/x201/romstage.c @@ -0,0 +1,885 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2011 Sven Schnelle svens@stackframe.org + * + * 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 + */ + +// __PRE_RAM__ means: use "unsigned" for device, not a struct. + +#include <stdint.h> +#include <string.h> +#include <arch/io.h> +#include <arch/romcc_io.h> +#include <device/pci_def.h> +#include <device/pnp_def.h> +#include <cpu/x86/lapic.h> +#include <lib.h> +#include <pc80/mc146818rtc.h> +#include <console/console.h> +#include <cpu/x86/bist.h> +#include <ec/acpi/ec.h> +#include <delay.h> +#include "dock.h" +#include "southbridge/intel/bd82x6x/pch.h" +#include "southbridge/intel/bd82x6x/gpio.h" +#include "northbridge/intel/sandybridge/sandybridge.h" + +#include "northbridge/intel/sandybridge/sandybridge.h" +#include "northbridge/intel/sandybridge/raminit.h" +#include "southbridge/intel/bd82x6x/pch.h" +#include "southbridge/intel/bd82x6x/gpio.h" +#include "southbridge/intel/bd82x6x/me.h" + +//#define SERIALICE 1 + +static void pch_enable_lpc(void) +{ + /* Parrot EC Decode Range Port60/64, Port62/66 */ + /* Enable EC, PS/2 Keyboard/Mouse */ + pci_write_config16(PCH_LPC_DEV, LPC_EN, KBC_LPC_EN | MC_LPC_EN); + + /* Map EC_IO decode to the LPC bus */ + pci_write_config32(PCH_LPC_DEV, LPC_GEN1_DEC, (0x15ec & ~3) | 0x00040001); + + /* Map EC registers 68/6C decode to the LPC bus */ + pci_write_config32(PCH_LPC_DEV, LPC_GEN2_DEC, (0x68 & ~3) | 0x00040001); +} + + +static void rcba_config(void) +{ + static const u32 rcba_dump3[] = { + 0x00000000, + 0x04341200, 0x00000000, 0x40043214, 0x00014321, + 0x00000002, 0x30003214, 0x00000001, 0x00000002, + 0x00000000, 0x00002321, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00003107, 0x76543210, 0x00000010, 0x00007654, + 0x00000004, 0x00000000, 0x00000000, 0x00003210, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x03000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x02060100, 0x0000000f, 0x01020000, 0x80000000, + 0x00000000, 0x04000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x000fffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x7f8fdfff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00003900, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00010000, 0x00000000, 0x00000000, 0x0001004b, + 0x06000008, 0x00010000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0000001c, 0x00000080, 0x00000000, 0x00000000, + 0x00000c61, 0x00000000, 0x16e61fe1, 0xbf4f001f, + 0x00000000, 0x00060010, 0x0000001d, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xdeaddeed, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x20000557, 0x2000055f, 0x2000074b, 0x2000074b, + 0x20000557, 0x2000014b, 0x2000074b, 0x2000074b, + 0x2000074b, 0x2000074b, 0x2000055f, 0x2000055f, + 0x20000557, 0x2000055f, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x000026a3, 0x00040002, 0x01000052, + 0x02000772, 0x16000f8f, 0x1800ff4f, 0x0001d630, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xfc000201, 0x3c000201, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0a001f00, 0x00000000, 0x00000000, 0x00000001, + 0x00010000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x089c0018, 0x00000000, 0x00000000, + 0x11111111, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x4e564d49, 0x00000000, 0x00000000, + }; + unsigned i; + for (i = 0; i < sizeof (rcba_dump3) / 4; i++) + { + RCBA32 (4 * i + 0x30fc) = rcba_dump3[i]; + (void) RCBA32 (4 * i + 0x30fc); + } + +#if 0 + RCBA32 (0x30fc) = 0x00000000; + (void) RCBA32 (0x30fc); + RCBA32 (0x3100) = 0x04341200; + (void) RCBA32 (0x3100); + RCBA32 (0x3104) = 0x00000000; + (void) RCBA32 (0x3104); + RCBA32 (0x3108) = 0x40043214; + (void) RCBA32 (0x3108); + RCBA32 (0x310c) = 0x00014321; + (void) RCBA32 (0x310c); + RCBA32 (0x3110) = 0x00000002; + (void) RCBA32 (0x3110); + RCBA32 (0x3114) = 0x30003214; + (void) RCBA32 (0x3114); + RCBA32 (0x311c) = 0x00000002; + (void) RCBA32 (0x311c); + RCBA32 (0x3120) = 0x00000000; + (void) RCBA32 (0x3120); + RCBA32 (0x3124) = 0x00002321; + (void) RCBA32 (0x3124); + RCBA32 (0x313c) = 0x00000000; + (void) RCBA32 (0x313c); + RCBA32 (0x3140) = 0x00003107; + (void) RCBA32 (0x3140); + RCBA32 (0x3144) = 0x76543210; + (void) RCBA32 (0x3144); + RCBA32 (0x3148) = 0x00000010; + (void) RCBA32 (0x3148); + RCBA32 (0x314c) = 0x00007654; + (void) RCBA32 (0x314c); + RCBA32 (0x3150) = 0x00000004; + (void) RCBA32 (0x3150); + RCBA32 (0x3158) = 0x00000000; + (void) RCBA32 (0x3158); + RCBA32 (0x315c) = 0x00003210; + (void) RCBA32 (0x315c); + RCBA32 (0x31fc) = 0x03000000; + (void) RCBA32 (0x31fc); +#endif +} + +#include <cbmem.h> + +#ifdef SERIALICE +static void +sio_putc (char c) +{ + usbdebug_tx_byte(0, c); + usbdebug_tx_flush (0); +} + +static char +sio_getc (void) +{ + return usbdebug_rx_byte(0); +} + +/* SIO helpers */ + +static void sio_putstring(const char *string) +{ + /* Very simple, no %d, %x etc. */ + while (*string) { + if (*string == '\n') + sio_putc('\r'); + sio_putc(*string); + string++; + } +} + +#define sio_put_nibble(nibble) \ + if (nibble > 9) \ + nibble += ('a' - 10); \ + else \ + nibble += '0'; \ + sio_putc(nibble) + +static void sio_put8(u8 data) +{ + u8 c; + + c = (data >> 4) & 0xf; + sio_put_nibble(c); + + c = data & 0xf; + sio_put_nibble(c); +} + +static void sio_put16(u16 data) +{ + int i; + for (i=12; i >= 0; i -= 4) { + u8 c = (data >> i) & 0xf; + sio_put_nibble(c); + } +} + +static void sio_put32(u32 data) +{ + int i; + for (i=28; i >= 0; i -= 4) { + u8 c = (data >> i) & 0xf; + sio_put_nibble(c); + } +} + +static void sio_put64(u64 data) +{ + int i; + for (i=60; i >= 0; i -= 4) { + u8 c = (data >> i) & 0xf; + sio_put_nibble(c); + } +} + +typedef struct _u128 +{ + u64 lo; + u64 hi; +} u128; + +static void sio_put128(u128 data) +{ + sio_put64 (data.hi); + sio_put64 (data.lo); +} + +static u8 sio_get_nibble(void) +{ + u8 ret = 0; + u8 nibble = sio_getc(); + + if (nibble >= '0' && nibble <= '9') { + ret = (nibble - '0'); + } else if (nibble >= 'a' && nibble <= 'f') { + ret = (nibble - 'a') + 0xa; + } else if (nibble >= 'A' && nibble <= 'F') { + ret = (nibble - 'A') + 0xa; + } else { + sio_putstring("ERROR: parsing number\n"); + } + return ret; +} + +static u8 sio_get8(void) +{ + u8 data; + data = sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + return data; +} + +static u16 sio_get16(void) +{ + u16 data; + + data = sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + + return data; +} + +static u32 sio_get32(void) +{ + u32 data; + + data = sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + + return data; +} + +static u64 sio_get64(void) +{ + u64 data = 0; + int i; + + for (i = 0; i < 64; i+=4) + { + data |= sio_get_nibble(); + data = data << 4; + } + + return data; +} + +static u128 sio_get128(void) +{ + u128 data; + data.hi = sio_get64 (); + data.lo = sio_get64 (); + + return data; +} + +static u64 +read64 (u32 addr) +{ + u64 ret; + u64 stor; + asm volatile ("movq %%xmm0, %0\n" + "movq (%2), %%xmm0\n" + "movq %%xmm0, %1\n" + "movq %0, %%xmm0":"+m"(stor),"=m"(ret):"r"(addr)); + + return ret; +} + +static void +write64 (u32 addr, u64 val) +{ + u64 stor; + asm volatile ("movq %%xmm0, %0\n" + "movq %%xmm0, %1\n" + "movq (%2), %%xmm0\n" + "movq %0, %%xmm0":"+m"(stor):"m"(val),"r"(addr)); +} + +static u128 +read128 (u32 addr) +{ + u128 ret; + u128 stor; + asm volatile ("movdqu %%xmm0, %0\n" + "movdqa (%2), %%xmm0\n" + "movdqu %%xmm0, %1\n" + "movdqu %0, %%xmm0":"+m"(stor),"=m"(ret):"r"(addr)); + + return ret; +} + +static void +write128 (u32 addr, u128 val) +{ + u128 stor; + asm volatile ("movdqu %%xmm0, %0\n" + "movdqu %%xmm0, %1\n" + "movdqa (%2), %%xmm0\n" + "movdqu %0, %%xmm0":"+m"(stor):"m"(val),"r"(addr)); +} + +/* Accessor functions */ + +static void serialice_read_memory(void) +{ + u8 width; + u32 addr; + + // Format: + // *rm00000000.w + addr = sio_get32(); + sio_getc(); // skip . + width = sio_getc(); + + sio_putc('\r'); sio_putc('\n'); + + switch (width) { + case 'b': sio_put8(read8(addr)); break; + case 'w': sio_put16(read16(addr)); break; + case 'l': sio_put32(read32(addr)); break; + case 'q': sio_put64(read64(addr)); break; + case 'p': sio_put128(read128(addr)); break; + } +} + +static void serialice_clflush(void) +{ + u32 addr; + + // Format: + // *fm00000000 + addr = sio_get32(); + + sio_putc('\r'); sio_putc('\n'); + + asm volatile ("clflush (%0)" : : "r" (addr)); +} + +static void serialice_write_memory(void) +{ + u8 width; + u32 addr; + u64 data; + u128 data128; + + // Format: + // *wm00000000.w=0000 + addr = sio_get32(); + sio_getc(); // skip . + width = sio_getc(); + sio_getc(); // skip = + + switch (width) { + case 'b': data = sio_get8(); write8(addr, (u8)data); break; + case 'w': data = sio_get16(); write16(addr, (u16)data); break; + case 'l': data = sio_get32(); write32(addr, (u32)data); break; + case 'q': data = sio_get64(); write64(addr, data); break; + case 'p': data128 = sio_get128(); write128(addr, data128); break; + } +} + +static void serialice_read_io(void) +{ + u8 width; + u16 port; + + // Format: + // *ri0000.w + port = sio_get16(); + sio_getc(); // skip . + width = sio_getc(); + + sio_putc('\r'); sio_putc('\n'); + + switch (width) { + case 'b': sio_put8(inb(port)); break; + case 'w': sio_put16(inw(port)); break; + case 'l': sio_put32(inl(port)); break; + } +} + +static void serialice_write_io(void) +{ + u8 width; + u16 port; + u32 data; + + // Format: + // *wi0000.w=0000 + port = sio_get16(); + sio_getc(); // skip . + width = sio_getc(); + sio_getc(); // skip = + + switch (width) { + case 'b': data = sio_get8(); outb((u8)data, port); break; + case 'w': data = sio_get16(); outw((u16)data, port); break; + case 'l': data = sio_get32(); outl((u32)data, port); break; + } +} + +static inline msr_t serialice_rdmsr(u32 index, u32 key) +{ + msr_t result; + __asm__ __volatile__ ( + "rdmsr" + : "=a" (result.lo), "=d" (result.hi) + : "c" (index), "D" (key) + ); + return result; +} + +static inline void serialice_wrmsr(u32 index, msr_t msr, u32 key) +{ + __asm__ __volatile__ ( + "wrmsr" + : /* No outputs */ + : "c" (index), "a" (msr.lo), "d" (msr.hi), "D" (key) + ); +} + + +static void serialice_read_msr(void) +{ + u32 addr, key; + msr_t msr; + + // Format: + // *rc00000000.9c5a203a + addr = sio_get32(); + sio_getc(); // skip . + key = sio_get32(); // key in %edi + + sio_putc('\r'); sio_putc('\n'); + + msr = serialice_rdmsr(addr, key); + sio_put32(msr.hi); + sio_putc('.'); + sio_put32(msr.lo); +} + +static void serialice_write_msr(void) +{ + u32 addr, key; + msr_t msr; + + // Format: + // *wc00000000.9c5a203a=00000000.00000000 + addr = sio_get32(); + sio_getc(); // skip . + key = sio_get32(); // read key in %edi + sio_getc(); // skip = + msr.hi = sio_get32(); + sio_getc(); // skip . + msr.lo = sio_get32(); + + serialice_wrmsr(addr, msr, key); +} + +/* CPUID functions */ + +static inline u32 cpuid_eax(u32 op, u32 op2) +{ + u32 eax; + + __asm__("cpuid" + : "=a" (eax) + : "a" (op), "c" (op2) + : "ebx", "edx" ); + return eax; +} + +static inline u32 cpuid_ebx(u32 op, u32 op2) +{ + u32 ebx; + + __asm__("cpuid" + : "=b" (ebx) + : "a" (op), "c" (op2) + : "edx"); + return ebx; +} + +static inline u32 cpuid_ecx(u32 op, u32 op2) +{ + u32 ecx; + + __asm__("cpuid" + : "=c" (ecx) + : "a" (op), "c" (op2) + : "ebx", "edx" ); + return ecx; +} + +static inline u32 cpuid_edx(u32 op, u32 op2) +{ + u32 edx; + + __asm__("cpuid" + : "=d" (edx) + : "a" (op), "c" (op2) + : "ebx"); + return edx; +} + +static void serialice_cpuinfo(void) +{ + u32 eax, ecx; + u32 reg32; + + // Format: + // --EAX--- --ECX--- + // *ci00000000.00000000 + eax = sio_get32(); + sio_getc(); // skip . + ecx = sio_get32(); + + sio_putc('\r'); sio_putc('\n'); + + /* This code looks quite crappy but this way we don't + * have to worry about running out of registers if we + * occupy eax, ebx, ecx, edx at the same time + */ + reg32 = cpuid_eax(eax, ecx); + sio_put32(reg32); + sio_putc('.'); + + reg32 = cpuid_ebx(eax, ecx); + sio_put32(reg32); + sio_putc('.'); + + reg32 = cpuid_ecx(eax, ecx); + sio_put32(reg32); + sio_putc('.'); + + reg32 = cpuid_edx(eax, ecx); + sio_put32(reg32); +} + +static void serialice_mainboard(void) +{ + sio_putc('\r'); sio_putc('\n'); + + /* must be defined in mainboard/<boardname>.c */ + sio_putstring("Lenovo X201"); +} + +static void serialice_version(void) +{ + sio_putstring("\nSerialICE vphcoder (" __DATE__ ")\n"); +} + + +static void serialice (void) +{ + serialice_version(); + + while(1) { + u16 c; + sio_putstring("\n> "); + + c = sio_getc(); + if (c != '*') + continue; + + c = sio_getc() << 8; + c |= sio_getc(); + + switch(c) { + case (('r' << 8)|'a'): + { + u32 addr, len; + sio_getc(); // skip . + addr = sio_get32(); + sio_getc(); // skip . + len = sio_get32 (); + ram_check (addr, len); + break; + } + case (('q' << 8)|'r'): + quick_ram_check(); + break; + case (('q' << 8)|'s'): + return; + case (('r' << 8)|'m'): // Read Memory *rm + serialice_read_memory(); + break; + case (('f' << 8)|'m'): // Flush Memory *fm + serialice_clflush(); + break; + case (('w' << 8)|'m'): // Write Memory *wm + serialice_write_memory(); + break; + case (('r' << 8)|'i'): // Read IO *ri + serialice_read_io(); + break; + case (('w' << 8)|'i'): // Write IO *wi + serialice_write_io(); + break; + case (('r' << 8)|'c'): // Read CPU MSR *rc + serialice_read_msr(); + break; + case (('w' << 8)|'c'): // Write CPU MSR *wc + serialice_write_msr(); + break; + case (('c' << 8)|'i'): // Read CPUID *ci + serialice_cpuinfo(); + break; + case (('m' << 8)|'b'): // Read mainboard type *mb + serialice_mainboard(); + break; + case (('v' << 8)|'i'): // Read version info *vi + serialice_version(); + break; + case (('s' << 8)|'i'): + raminit (0); + break; + default: + sio_putstring("ERROR\n"); + break; + } + } +} +#endif + +void main(unsigned long bist) +{ + u32 reg32; + int s3resume = 0; + + reg32 = inl(DEFAULT_PMBASE + 0x04); + + if (bist == 0) + enable_lapic(); + + /* Force PCIRST# */ + pci_write_config16(PCI_DEV(0, 0x1e, 0), BCTRL, SBR); + pci_write_config16(PCI_DEV(0, 0, 0), BCTRL, SBR); + udelay(200 * 1000); + pci_write_config16(PCI_DEV(0, 0x1e, 0), BCTRL, 0); + pci_write_config16(PCI_DEV(0, 0, 0), BCTRL, 0); + + /* Enable USB Power. */ + ec_set_bit(0x3b, 4); + + pch_enable_lpc(); + +#ifdef DISABLED + /* Enable GPIOs */ + pci_write_config32(PCH_LPC_DEV, GPIO_BASE, DEFAULT_GPIOBASE|1); + pci_write_config8(PCH_LPC_DEV, GPIO_CNTL, 0x10); + // setup_pch_gpios(&x201_gpio_map); +#endif + sandybridge_early_initialization(SANDYBRIDGE_MOBILE); + + /* This should probably go away. Until now it is required + * and mainboard specific + */ + rcba_config(); + + console_init(); + + printk(BIOS_DEBUG, "PM1_CNT: %08x\n", reg32); + +#ifdef SERIALICE + serialice (); +#endif + + /* Halt if there was a built in self test failure */ + report_bist_failure(bist); + + /* Read PM1_CNT */ + reg32 = inl(DEFAULT_PMBASE + 0x04); + printk(BIOS_DEBUG, "PM1_CNT: %08x\n", reg32); + if (((reg32 >> 10) & 7) == 5) { +#if CONFIG_HAVE_ACPI_RESUME + printk(BIOS_DEBUG, "Resume from S3 detected.\n"); + s3resume = 1; +#else + printk(BIOS_DEBUG, "Resume from S3 detected, but disabled.\n"); +#endif + } + +#ifndef SERIALICE + raminit(s3resume); +#endif + + intel_early_me_status(); + + if (s3resume) + { + /* Clear SLP_TYPE. This will break stage2 but + * we care for that when we get there. + */ + reg32 = inl(DEFAULT_PMBASE + 0x04); + outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04); + } + +#if CONFIG_HAVE_ACPI_RESUME + /* Start address of high memory tables */ + unsigned long high_ram_base = get_top_of_ram() - HIGH_MEMORY_SIZE; + + /* If there is no high memory area, we didn't boot before, so + * this is not a resume. In that case we just create the cbmem toc. + */ + if (s3resume && cbmem_reinit((u64)high_ram_base)) { + void *resume_backup_memory = cbmem_find(CBMEM_ID_RESUME); + int i, j; + + for (i = 1; i < 2048 + 1024; i++) + { + u32 s = 0; + for (j = 0; j < 0x100000; j += 4) + s += *(u32 *) ((i << 20) | j); + if (((u8 *)0x100000)[i] != s % 255) + { + printk (BIOS_ERR, "MiB %d corrupted %x vs %x\n", i, + ((u8 *)0x100000)[i], s % 255); + } + } + /* for (i = 0; i < 65536; i++) + if (read8 (i) != read8 (i + 0x100000)) + printk (BIOS_ERR, "Corruption at %x: %x vs %x\n", i, + read8 (i), read8 (i + 0x100000));*/ + + + /* copy 1MB - 64K to high tables ram_base to prevent memory corruption + * through stage 2. We could keep stuff like stack and heap in high tables + * memory completely, but that's a wonderful clean up task for another + * day. + */ + if (resume_backup_memory) + memcpy(resume_backup_memory, (void *)CONFIG_RAMBASE, HIGH_MEMORY_SAVE); + + /* Magic for S3 resume */ + pci_write_config32(PCI_DEV(0, 0x00, 0), SKPAD, 0xcafed00d); + } + else if (s3resume) { + printk(BIOS_ERR, "Failed S3 resume.\n"); + ram_check (0x100000, 0x200000); + + /* Failed S3 resume, reset to come up cleanly */ + outb(0xe, 0xcf9); + hlt(); + } else { + pci_write_config32(PCI_DEV(0, 0x00, 0), SKPAD, 0xcafebabe); + quick_ram_check(); + } +#endif +} diff --git a/src/mainboard/lenovo/x201/smi.h b/src/mainboard/lenovo/x201/smi.h new file mode 100644 index 0000000..c5f48a1 --- /dev/null +++ b/src/mainboard/lenovo/x201/smi.h @@ -0,0 +1,27 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Sven Schnelle svens@stackframe.org + * + * 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_LENOVO_X60_SMI_H +#define MAINBOARD_LENOVO_X60_SMI_H + +#define SMI_DOCK_CONNECT 0x01 +#define SMI_DOCK_DISCONNECT 0x02 +#define SMI_SAVE_CMOS 0x03 + +#endif diff --git a/src/mainboard/lenovo/x201/smihandler.c b/src/mainboard/lenovo/x201/smihandler.c new file mode 100644 index 0000000..c0d8440 --- /dev/null +++ b/src/mainboard/lenovo/x201/smihandler.c @@ -0,0 +1,208 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <arch/io.h> +#include <arch/romcc_io.h> +#include <console/console.h> +#include <cpu/x86/smm.h> +#include "southbridge/intel/i82801gx/nvs.h" +#include "southbridge/intel/i82801gx/i82801gx.h" +#include <ec/acpi/ec.h> +#include <pc80/mc146818rtc.h> +#include <ec/lenovo/h8/h8.h> +#include <delay.h> +#include "dock.h" +#include "smi.h" + +/* The southbridge SMI handler checks whether gnvs has a + * valid pointer before calling the trap handler + */ +extern global_nvs_t *gnvs; + +static void mainboard_smm_init(void) +{ + printk(BIOS_DEBUG, "initializing SMI\n"); + /* Enable 0x1600/0x1600 register pair */ + ec_set_bit(0x00, 0x05); +} + +static void mainboard_smi_save_cmos(void) +{ + u8 val; + u8 tmp70, tmp72; + + tmp70 = inb(0x70); + tmp72 = inb(0x72); + + val = pci_read_config8(PCI_DEV(0, 2, 1), 0xf4); + set_option("tft_brightness", &val); + val = ec_read(H8_VOLUME_CONTROL); + set_option("volume", &val); + + outb(tmp70, 0x70); + outb(tmp72, 0x72); +} + +int mainboard_io_trap_handler(int smif) +{ + static int smm_initialized; + + if (!smm_initialized) { + mainboard_smm_init(); + smm_initialized = 1; + } + + switch (smif) { + case SMI_DOCK_CONNECT: + ec_clr_bit(0x03, 2); + udelay(250000); + if (!dock_connect()) { + ec_set_bit(0x03, 2); + /* set dock LED to indicate status */ + ec_write(0x0c, 0x09); + ec_write(0x0c, 0x88); + } else { + /* blink dock LED to indicate failure */ + ec_write(0x0c, 0x08); + ec_write(0x0c, 0xc9); + } + break; + + case SMI_DOCK_DISCONNECT: + ec_clr_bit(0x03, 2); + dock_disconnect(); + break; + + case SMI_SAVE_CMOS: + mainboard_smi_save_cmos(); + break; + default: + return 0; + } + + /* On success, the IO Trap Handler returns 1 + * On failure, the IO Trap Handler returns a value != 1 */ + return 1; +} + +static void mainboard_smi_brightness_up(void) +{ + u8 value; + + if ((value = pci_read_config8(PCI_DEV(0, 2, 1), 0xf4)) < 0xf0) + pci_write_config8(PCI_DEV(0, 2, 1), 0xf4, (value + 0x10) | 0xf); +} + +static void mainboard_smi_brightness_down(void) +{ + u8 value; + + if ((value = pci_read_config8(PCI_DEV(0, 2, 1), 0xf4)) > 0x10) + pci_write_config8(PCI_DEV(0, 2, 1), 0xf4, (value - 0x10) & 0xf0); +} + +static void mainboard_smi_handle_ec_sci(void) +{ + u8 status = inb(EC_SC); + u8 event; + + if (!(status & EC_SCI_EVT)) + return; + + event = ec_query(); + printk(BIOS_DEBUG, "EC event %02x\n", event); + + switch(event) { + /* brightness up */ + case 0x14: + mainboard_smi_brightness_up(); + mainboard_smi_save_cmos(); + break; + /* brightness down */ + case 0x15: + mainboard_smi_brightness_down(); + mainboard_smi_save_cmos(); + break; + /* Fn-F9 key */ + case 0x18: + /* Power loss */ + case 0x27: + /* Undock Key */ + case 0x50: + mainboard_io_trap_handler(SMI_DOCK_DISCONNECT); + break; + /* Dock Event */ + case 0x37: + case 0x58: + mainboard_io_trap_handler(SMI_DOCK_CONNECT); + break; + default: + break; + } +} + +void mainboard_smi_gpi(u16 gpi) +{ + if (gpi & (1 << 12)) + mainboard_smi_handle_ec_sci(); +} + +int mainboard_smi_apmc(u8 data) +{ + u16 pmbase = pci_read_config16(PCI_DEV(0, 0x1f, 0), 0x40) & 0xfffc; + u8 tmp; + + printk(BIOS_DEBUG, "%s: pmbase %04X, data %02X\n", __func__, pmbase, data); + + if (!pmbase) + return 0; + + switch(data) { + case APM_CNT_ACPI_ENABLE: + /* use 0x1600/0x1604 to prevent races with userspace */ + ec_set_ports(0x1604, 0x1600); + /* route H8SCI to SCI */ + outw(inw(ALT_GP_SMI_EN) & ~0x1000, pmbase + ALT_GP_SMI_EN); + tmp = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xbb); + tmp &= ~0x03; + tmp |= 0x02; + pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xbb, tmp); + /* discard all events, and enable attention */ + ec_write(0x80, 0x01); + break; + case APM_CNT_ACPI_DISABLE: + /* we have to use port 0x62/0x66, as 0x1600/0x1604 doesn't + provide a EC query function */ + ec_set_ports(0x66, 0x62); + /* route H8SCI# to SMI */ + outw(inw(pmbase + ALT_GP_SMI_EN) | 0x1000, pmbase + ALT_GP_SMI_EN); + tmp = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xbb); + tmp &= ~0x03; + tmp |= 0x01; + pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xbb, tmp); + /* discard all events, and enable attention */ + ec_write(0x80, 0x01); + break; + default: + break; + } + return 0; +} diff --git a/src/northbridge/intel/Makefile.inc b/src/northbridge/intel/Makefile.inc index 5888c65..e46d1a1 100644 --- a/src/northbridge/intel/Makefile.inc +++ b/src/northbridge/intel/Makefile.inc @@ -9,6 +9,7 @@ subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I82810) += i82810 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I82830) += i82830 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I855) += i855 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I945) += i945 +subdirs-$(CONFIG_NORTHBRIDGE_INTEL_QM45) += qm45 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_GM45) += gm45 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_SCH) += sch subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I5000) += i5000 diff --git a/src/northbridge/intel/sandybridge/Kconfig b/src/northbridge/intel/sandybridge/Kconfig index 7ab8cc0..7659dc6 100644 --- a/src/northbridge/intel/sandybridge/Kconfig +++ b/src/northbridge/intel/sandybridge/Kconfig @@ -45,7 +45,7 @@ config MRC_CACHE_BASE config MRC_CACHE_LOCATION hex depends on !CHROMEOS - default 0x1ec000 + default 0x500000
config MRC_CACHE_SIZE hex @@ -66,7 +66,7 @@ if NORTHBRIDGE_INTEL_IVYBRIDGE
config VGA_BIOS_ID string - default "8086,0166" + default "8086,0046"
config EXTERNAL_MRC_BLOB bool diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index 95d66ce..cb9b6fc 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -24,23 +24,11 @@ ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c ramstage-y += mrccache.c
romstage-y += raminit.c -romstage-y += mrccache.c romstage-y += early_init.c -romstage-y += report_platform.c +romstage-y += mrccache.c romstage-y += ../../../arch/x86/lib/walkcbfs.S
smm-$(CONFIG_HAVE_SMI_HANDLER) += udelay.c smm-$(CONFIG_HAVE_SMI_HANDLER) += finalize.c
-# We don't ship that, but booting without it is bound to fail -cbfs-files-$(CONFIG_HAVE_MRC) += mrc.bin -mrc.bin-file := $(call strip_quotes,$(CONFIG_MRC_FILE)) -ifeq ($(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE),y) -mrc.bin-position := 0xfffa0000 -endif -ifeq ($(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE),y) -mrc.bin-position := 0xfffe0000 -endif -mrc.bin-type := 0xab - $(obj)/northbridge/intel/sandybridge/acpi.ramstage.o : $(obj)/build.h diff --git a/src/northbridge/intel/sandybridge/acpi.c b/src/northbridge/intel/sandybridge/acpi.c index 0a179ca..926c71c 100644 --- a/src/northbridge/intel/sandybridge/acpi.c +++ b/src/northbridge/intel/sandybridge/acpi.c @@ -38,13 +38,9 @@ unsigned long acpi_fill_mcfg(unsigned long current) u32 pciexbar_reg; int max_buses;
- dev = dev_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SB, 0); - if (!dev) - dev = dev_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_IB, 0); - if (!dev) - return current; + dev = dev_find_slot(0xff, PCI_DEVFN (0, 1));
- pciexbar_reg=pci_read_config32(dev, PCIEXBAR); + pciexbar_reg=read32 (0xeff01050);
// MMCFG not supported or not enabled. if (!(pciexbar_reg & (1 << 0))) diff --git a/src/northbridge/intel/sandybridge/acpi/hostbridge.asl b/src/northbridge/intel/sandybridge/acpi/hostbridge.asl index 93db98d..ded393b 100644 --- a/src/northbridge/intel/sandybridge/acpi/hostbridge.asl +++ b/src/northbridge/intel/sandybridge/acpi/hostbridge.asl @@ -54,51 +54,13 @@ Device (MCHC) , 11, // DMBR, 24, // DMIBAR
- Offset (0x70), // ME Base Address - MEBA, 64, - - // ... - - Offset (0x80), // PAM0 - , 4, - PM0H, 2, - , 2, - Offset (0x81), // PAM1 - PM1L, 2, - , 2, - PM1H, 2, - , 2, - Offset (0x82), // PAM2 - PM2L, 2, - , 2, - PM2H, 2, - , 2, - Offset (0x83), // PAM3 - PM3L, 2, - , 2, - PM3H, 2, - , 2, - Offset (0x84), // PAM4 - PM4L, 2, - , 2, - PM4H, 2, - , 2, - Offset (0x85), // PAM5 - PM5L, 2, - , 2, - PM5H, 2, - , 2, - Offset (0x86), // PAM6 - PM6L, 2, - , 2, - PM6H, 2, - , 2, - - Offset (0xa0), // Top of Used Memory - TOM, 64, - - Offset (0xbc), // Top of Low Used Memory - TLUD, 32, + + Offset (0xa0), + TOM, 16, + TUUD, 16, + + Offset (0xb0), // Top of Low Used Memory + TLUD, 16, }
Mutex (CTCM, 1) /* CTDP Switch Mutex (sync level 1) */ @@ -365,14 +327,17 @@ Method (_CRS, 0, Serialized) // Fix up PCI memory region // Start with Top of Lower Usable DRAM Store (^MCHC.TLUD, Local0) - Store (^MCHC.MEBA, Local1) + ShiftRight (Local0, 4, Local0) + Store (^MCHC.TUUD, Local1)
// Check if ME base is equal If (LEqual (Local0, Local1)) { // Use Top Of Memory instead Store (^MCHC.TOM, Local0) + ShiftRight (Local0, 6, Local0) }
+ ShiftLeft (Local0, 20, Local0) Store (Local0, PMIN) Add(Subtract(PMAX, PMIN), 1, PLEN)
diff --git a/src/northbridge/intel/sandybridge/acpi/igd.asl b/src/northbridge/intel/sandybridge/acpi/igd.asl index a6804ad..eaa55f2 100644 --- a/src/northbridge/intel/sandybridge/acpi/igd.asl +++ b/src/northbridge/intel/sandybridge/acpi/igd.asl @@ -23,6 +23,20 @@ Device (GFX0) { Name (_ADR, 0x00020000)
+ OperationRegion (GFXC, PCI_Config, 0x00, 0x0100) + Field (GFXC, DWordAcc, NoLock, Preserve) + { + Offset (0x10), + BAR0, 64 + } + + OperationRegion (GFRG, SystemMemory, And (BAR0, 0xfffffffffffffff0), 0x400000) + Field (GFRG, DWordAcc, NoLock, Preserve) + { + Offset (0x48254), + BCLV, 16 + } + /* Display Output Switching */ Method (_DOS, 1) { diff --git a/src/northbridge/intel/sandybridge/early_init.c b/src/northbridge/intel/sandybridge/early_init.c index c184fa2..a7af1b2 100644 --- a/src/northbridge/intel/sandybridge/early_init.c +++ b/src/northbridge/intel/sandybridge/early_init.c @@ -56,13 +56,13 @@ static void sandybridge_setup_bars(void) pci_write_config32(PCI_DEV(0, 0x00, 0), DMIBAR + 4, (0LL+DEFAULT_DMIBAR) >> 32);
/* Set C0000-FFFFF to access RAM on both reads and writes */ - pci_write_config8(PCI_DEV(0, 0x00, 0), PAM0, 0x30); - pci_write_config8(PCI_DEV(0, 0x00, 0), PAM1, 0x33); - pci_write_config8(PCI_DEV(0, 0x00, 0), PAM2, 0x33); - pci_write_config8(PCI_DEV(0, 0x00, 0), PAM3, 0x33); - pci_write_config8(PCI_DEV(0, 0x00, 0), PAM4, 0x33); - pci_write_config8(PCI_DEV(0, 0x00, 0), PAM5, 0x33); - pci_write_config8(PCI_DEV(0, 0x00, 0), PAM6, 0x33); + pci_write_config8(PCI_DEV(0xff, 0x00, 1), QPD0F1_PAM(0), 0x30); + pci_write_config8(PCI_DEV(0xff, 0x00, 1), QPD0F1_PAM(1), 0x33); + pci_write_config8(PCI_DEV(0xff, 0x00, 1), QPD0F1_PAM(2), 0x33); + pci_write_config8(PCI_DEV(0xff, 0x00, 1), QPD0F1_PAM(3), 0x33); + pci_write_config8(PCI_DEV(0xff, 0x00, 1), QPD0F1_PAM(4), 0x33); + pci_write_config8(PCI_DEV(0xff, 0x00, 1), QPD0F1_PAM(5), 0x33); + pci_write_config8(PCI_DEV(0xff, 0x00, 1), QPD0F1_PAM(6), 0x33);
#if CONFIG_ELOG_BOOT_COUNT /* Increment Boot Counter for non-S3 resume */ @@ -105,10 +105,12 @@ static void sandybridge_setup_graphics(void) return; }
+ return; + printk(BIOS_DEBUG, "Initializing Graphics...\n");
/* Setup IGD memory by setting GGC[7:3] = 1 for 32MB */ - reg16 = pci_read_config16(PCI_DEV(0,0,0), GGC); + reg16 = pci_read_config16(PCI_DEV(0,0,0), D0F0_GGC); reg16 &= ~0x00f8; reg16 |= 1 << 3; /* Program GTT memory by setting GGC[9:8] = 2MB */ @@ -116,7 +118,7 @@ static void sandybridge_setup_graphics(void) reg16 |= 2 << 8; /* Enable VGA decode */ reg16 &= ~0x0002; - pci_write_config16(PCI_DEV(0,0,0), GGC, reg16); + pci_write_config16(PCI_DEV(0,0,0), D0F0_GGC, reg16);
/* Enable 256MB aperture */ reg8 = pci_read_config8(PCI_DEV(0, 2, 0), MSAC); @@ -169,7 +171,7 @@ void sandybridge_early_initialization(int chipset_type) sandybridge_setup_bars();
/* Device Enable */ - pci_write_config32(PCI_DEV(0, 0, 0), DEVEN, DEVEN_HOST | DEVEN_IGD); + pci_write_config32(PCI_DEV(0, 0, 0), D0F0_DEVEN, 9);
sandybridge_setup_graphics(); } diff --git a/src/northbridge/intel/sandybridge/gma.c b/src/northbridge/intel/sandybridge/gma.c index 52707bd..98d4236 100644 --- a/src/northbridge/intel/sandybridge/gma.c +++ b/src/northbridge/intel/sandybridge/gma.c @@ -620,19 +620,29 @@ static void gma_func0_init(struct device *dev) { u32 reg32;
+ printk (BIOS_ERR, "GMA " __FILE__ ":%d\n", __LINE__); + /* IGD needs to be Bus Master */ reg32 = pci_read_config32(dev, PCI_COMMAND); reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; pci_write_config32(dev, PCI_COMMAND, reg32);
+ printk (BIOS_ERR, "GMA " __FILE__ ":%d\n", __LINE__); + /* Init graphics power management */ gma_pm_init_pre_vbios(dev);
+ printk (BIOS_ERR, "GMA " __FILE__ ":%d\n", __LINE__); + /* PCI Init, will run VBIOS */ pci_dev_init(dev);
+ printk (BIOS_ERR, "GMA " __FILE__ ":%d\n", __LINE__); + /* Post VBIOS init */ gma_pm_init_post_vbios(dev); + + printk (BIOS_ERR, "GMA " __FILE__ ":%d\n", __LINE__); }
static void gma_set_subsystem(device_t dev, unsigned vendor, unsigned device) @@ -661,7 +671,7 @@ static struct device_operations gma_func0_ops = { };
static const unsigned short gma_ids[] = { - 0x0102, 0x0106, 0x010a, 0x0112, 0x0116, 0x0122, 0x0126, 0x0156, 0x166, + 0x0046, 0x0102, 0x0106, 0x010a, 0x0112, 0x0116, 0x0122, 0x0126, 0x0156, 0x166, 0, }; static const struct pci_driver gma_gt1_desktop __pci_driver = { diff --git a/src/northbridge/intel/sandybridge/northbridge.c b/src/northbridge/intel/sandybridge/northbridge.c index 8652838..89c2af0 100644 --- a/src/northbridge/intel/sandybridge/northbridge.c +++ b/src/northbridge/intel/sandybridge/northbridge.c @@ -104,19 +104,6 @@ static void add_fixed_resources(struct device *dev, int index) struct resource *resource; u32 pcie_config_base, pcie_config_size;
- /* Using uma_resource() here would fail as base & size cannot - * be used as-is for a single MTRR. This would cause excessive - * use of MTRRs. - * - * Use of mmio_resource() instead does not create UC holes by using - * MTRRs, but making these regions uncacheable is taken care of by - * making sure they do not overlap with any ram_resource(). - * - * The resources can be changed to use separate mmio_resource() - * calls after MTRR code is able to merge them wisely. - */ - mmio_resource(dev, index++, uma_memory_base >> 10, uma_memory_size >> 10); - if (get_pcie_bar(&pcie_config_base, &pcie_config_size)) { printk(BIOS_DEBUG, "Adding PCIe config bar base=0x%08x " "size=0x%x\n", pcie_config_base, pcie_config_size); @@ -133,137 +120,72 @@ static void add_fixed_resources(struct device *dev, int index) mmio_resource(dev, index++, CONFIG_CHROMEOS_RAMOOPS_RAM_START >> 10, CONFIG_CHROMEOS_RAMOOPS_RAM_SIZE >> 10); #endif - - /* Required for SandyBridge sighting 3715511 */ - bad_ram_resource(dev, index++, 0x20000000 >> 10, 0x00200000 >> 10); - bad_ram_resource(dev, index++, 0x40000000 >> 10, 0x00200000 >> 10); + bad_ram_resource(dev, index++, 0x1fc000000ULL >> 10, + 0x004000000 >> 10); }
static void pci_domain_set_resources(device_t dev) { - uint64_t tom, me_base, touud; - uint32_t tseg_base, uma_size, tolud; - uint16_t ggc; - unsigned long long tomk; + uint32_t tseg_base; + uint64_t TOUUD; + uint16_t reg16;
- /* Total Memory 2GB example: - * - * 00000000 0000MB-1992MB 1992MB RAM (writeback) - * 7c800000 1992MB-2000MB 8MB TSEG (SMRR) - * 7d000000 2000MB-2002MB 2MB GFX GTT (uncached) - * 7d200000 2002MB-2034MB 32MB GFX UMA (uncached) - * 7f200000 2034MB TOLUD - * 7f800000 2040MB MEBASE - * 7f800000 2040MB-2048MB 8MB ME UMA (uncached) - * 80000000 2048MB TOM - * 100000000 4096MB-4102MB 6MB RAM (writeback) - * - * Total Memory 4GB example: - * - * 00000000 0000MB-2768MB 2768MB RAM (writeback) - * ad000000 2768MB-2776MB 8MB TSEG (SMRR) - * ad800000 2776MB-2778MB 2MB GFX GTT (uncached) - * ada00000 2778MB-2810MB 32MB GFX UMA (uncached) - * afa00000 2810MB TOLUD - * ff800000 4088MB MEBASE - * ff800000 4088MB-4096MB 8MB ME UMA (uncached) - * 100000000 4096MB TOM - * 100000000 4096MB-5374MB 1278MB RAM (writeback) - * 14fe00000 5368MB TOUUD - */ + tseg_base = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0, 0)), + TSEG); + TOUUD = pci_read_config16(dev_find_slot(0, PCI_DEVFN(0, 0)), + D0F0_TOUUD);
- /* Top of Upper Usable DRAM, including remap */ - touud = pci_read_config32(dev, TOUUD+4); - touud <<= 32; - touud |= pci_read_config32(dev, TOUUD); - - /* Top of Lower Usable DRAM */ - tolud = pci_read_config32(dev, TOLUD); - - /* Top of Memory - does not account for any UMA */ - tom = pci_read_config32(dev, 0xa4); - tom <<= 32; - tom |= pci_read_config32(dev, 0xa0); - - printk(BIOS_DEBUG, "TOUUD 0x%llx TOLUD 0x%08x TOM 0x%llx\n", - touud, tolud, tom); - - /* ME UMA needs excluding if total memory <4GB */ - me_base = pci_read_config32(dev, 0x74); - me_base <<= 32; - me_base |= pci_read_config32(dev, 0x70); - - printk(BIOS_DEBUG, "MEBASE 0x%llx\n", me_base); - - tomk = tolud >> 10; - if (me_base == tolud) { - /* ME is from MEBASE-TOM */ - uma_size = (tom - me_base) >> 10; - /* Increment TOLUD to account for ME as RAM */ - tolud += uma_size << 10; - /* UMA starts at old TOLUD */ - uma_memory_base = tomk * 1024ULL; - uma_memory_size = uma_size * 1024ULL; - printk(BIOS_DEBUG, "ME UMA base 0x%llx size %uM\n", - me_base, uma_size >> 10); - } - - /* Graphics memory comes next */ - ggc = pci_read_config16(dev, GGC); - if (!(ggc & 2)) { - printk(BIOS_DEBUG, "IGD decoded, subtracting "); - - /* Graphics memory */ - uma_size = ((ggc >> 3) & 0x1f) * 32 * 1024ULL; - printk(BIOS_DEBUG, "%uM UMA", uma_size >> 10); - tomk -= uma_size; - uma_memory_base = tomk * 1024ULL; - uma_memory_size += uma_size * 1024ULL; - - /* GTT Graphics Stolen Memory Size (GGMS) */ - uma_size = ((ggc >> 8) & 0x3) * 1024ULL; - tomk -= uma_size; - uma_memory_base = tomk * 1024ULL; - uma_memory_size += uma_size * 1024ULL; - printk(BIOS_DEBUG, " and %uM GTT\n", uma_size >> 10); - } + printk(BIOS_DEBUG, "ram_before_4g_top: 0x%x\n", tseg_base); + printk(BIOS_DEBUG, "TOUUD: 0x%x\n", (unsigned) TOUUD); + + /* Report the memory regions */ + ram_resource(dev, 3, 0, 640); + ram_resource(dev, 4, 768, ((tseg_base >> 10) - 768));
- /* Calculate TSEG size from its base which must be below GTT */ - tseg_base = pci_read_config32(dev, 0xb8); - uma_size = (uma_memory_base - tseg_base) >> 10; - tomk -= uma_size; - uma_memory_base = tomk * 1024ULL; - uma_memory_size += uma_size * 1024ULL; - printk(BIOS_DEBUG, "TSEG base 0x%08x size %uM\n", - tseg_base, uma_size >> 10);
- printk(BIOS_INFO, "Available memory below 4GB: %lluM\n", tomk >> 10);
- /* Report the memory regions */ - ram_resource(dev, 3, 0, legacy_hole_base_k); - ram_resource(dev, 4, legacy_hole_base_k + legacy_hole_size_k, - (tomk - (legacy_hole_base_k + legacy_hole_size_k))); - - /* - * If >= 4GB installed then memory from TOLUD to 4GB - * is remapped above TOM, TOUUD will account for both + /* Using uma_resource() here would fail as base & size cannot + * be used as-is for a single MTRR. This would cause excessive + * use of MTRRs. + * + * Use of mmio_resource() instead does not create UC holes by using + * MTRRs, but making these regions uncacheable is taken care of by + * making sure they do not overlap with any ram_resource(). + * + * The resources can be changed to use separate mmio_resource() + * calls after MTRR code is able to merge them wisely. */ - touud >>= 10; /* Convert to KB */ - if (touud > 4096 * 1024) { - ram_resource(dev, 5, 4096 * 1024, touud - (4096 * 1024)); - printk(BIOS_INFO, "Available memory above 4GB: %lluM\n", - (touud >> 10) - 4096); - } - - add_fixed_resources(dev, 6); - - assign_resources(dev->link_list); - -#if CONFIG_WRITE_HIGH_TABLES - /* Leave some space for ACPI, PIRQ and MP tables */ - high_tables_base = (tomk * 1024) - HIGH_MEMORY_SIZE; - high_tables_size = HIGH_MEMORY_SIZE; -#endif + mmio_resource(dev, 5, tseg_base >> 10, CONFIG_SMM_TSEG_SIZE >> 10); + + reg16 = pci_read_config16 (dev_find_slot(0, PCI_DEVFN(0, 0)), D0F0_GGC); + const int uma_sizes_gtt[16] = { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 }; + /* Igd memory */ + const int uma_sizes_igd[16] = + { + 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352, 256, 512 + }; + u32 igd_base, gtt_base; + int uma_size_igd, uma_size_gtt; + + uma_size_igd = uma_sizes_igd[(reg16 >> 4) & 0xF]; + uma_size_gtt = uma_sizes_gtt[(reg16 >> 8) & 0xF]; + + igd_base = pci_read_config32 (dev_find_slot(0, PCI_DEVFN(0, 0)), D0F0_IGD_BASE); + gtt_base = pci_read_config32 (dev_find_slot(0, PCI_DEVFN(0, 0)), D0F0_GTT_BASE); + mmio_resource(dev, 6, gtt_base >> 10, uma_size_gtt << 10); + mmio_resource(dev, 7, igd_base >> 10, uma_size_igd << 10); + + if (TOUUD > 4096 + 256) + ram_resource(dev, 8, (4096 << 10), + ((TOUUD - 4096) << 10)); + + add_fixed_resources(dev, 9); + + assign_resources(dev->link_list); + + /* Leave some space for ACPI, PIRQ and MP tables */ + high_tables_base = tseg_base - HIGH_MEMORY_SIZE; + high_tables_size = HIGH_MEMORY_SIZE; }
/* TODO We could determine how many PCIe busses we need in @@ -297,7 +219,7 @@ static void mc_read_resources(device_t dev) /* We use 0xcf as an unused index for our PCIe bar so that we find it again */ resource = new_resource(dev, 0xcf); resource->base = DEFAULT_PCIEXBAR; - resource->size = 64 * 1024 * 1024; /* 64MB hard coded PCIe config space */ + resource->size = 256 * 1024 * 1024; /* 64MB hard coded PCIe config space */ resource->flags = IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; @@ -413,7 +335,8 @@ static void northbridge_init(struct device *dev)
/* Configure turbo power limits 1ms after reset complete bit */ mdelay(1); - set_power_limits(28); +#ifdef DISABLED + set_power_limits(28);
/* * CPUs with configurable TDP also need power limits set @@ -424,7 +347,7 @@ static void northbridge_init(struct device *dev) MCHBAR32(0x59A0) = msr.lo; MCHBAR32(0x59A4) = msr.hi; } - +#endif /* Set here before graphics PM init */ MCHBAR32(0x5500) = 0x00100001; } @@ -463,6 +386,13 @@ static struct device_operations mc_ops = { .ops_pci = &intel_pci_ops, };
+ +static const struct pci_driver mc_driver_44 __pci_driver = { + .ops = &mc_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x0044, /* Sandy bridge */ +}; + static const struct pci_driver mc_driver_0100 __pci_driver = { .ops = &mc_ops, .vendor = PCI_VENDOR_ID_INTEL, diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index f25aaa1..a26539c 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -16,11 +16,16 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifndef REAL +#define REAL 1 +#endif
+#if REAL #include <console/console.h> #include <string.h> #include <arch/hlt.h> #include <arch/io.h> +#include <cpu/x86/msr.h> #include <arch/romcc_io.h> #include <cbmem.h> #include <arch/cbfs.h> @@ -28,292 +33,3998 @@ #include <ip_checksum.h> #include <pc80/mc146818rtc.h> #include <device/pci_def.h> +#include <arch/cpu.h> +#include <spd.h> #include "raminit.h" #include "pei_data.h" +#endif + +#if !REAL +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef u32 device_t; +#endif + #include "sandybridge.h"
-/* Management Engine is in the southbridge */ #include "southbridge/intel/bd82x6x/me.h" + +#if REAL +#include <delay.h> + +/* Management Engine is in the southbridge */ #if CONFIG_CHROMEOS #include <vendorcode/google/chromeos/chromeos.h> #else #define recovery_mode_enabled(x) 0 #endif +#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) + +#define NORTHBRIDGE 0, 0, 0 +#define SOUTHBRIDGE 0, 0x1f, 0 +#define HECIDEV 0, 0x16, 0 +#define HECIBAR 0x10 + +struct ram_training +{ + u16 lane_timings[4][2][2][2][9]; + u16 reg_178; + u16 reg_10b; +}; + +#if !REAL +#include "raminit_fake.c" #else -#define CMOS_OFFSET_MRC_SEED 152 -#define CMOS_OFFSET_MRC_SEED_S3 156 -#define CMOS_OFFSET_MRC_SEED_CHK 160 + +#include <lib.h> /* Prototypes */ + +static void +my_write_msr (u32 addr, u64 val) +{ + msr_t msr = { .lo = val, .hi = val >> 32 }; + + wrmsr (addr, msr); +} + +static inline void +write_acpi32 (u32 addr, u32 val) +{ + outl (val, DEFAULT_PMBASE | addr); +} + +#if 0 +static void +nvram_write (u8 addr, u8 val) +{ + cmos_write (val, addr); +} + +static inline u8 +nvram_read (u8 addr) +{ + return cmos_read (addr); +} #endif
-static void save_mrc_data(struct pei_data *pei_data) +static inline void +write_acpi16 (u32 addr, u16 val) +{ + outw (val, DEFAULT_PMBASE | addr); +} + +static inline u32 +read_acpi32 (u32 addr) { - u16 c1, c2, checksum; + return inl (DEFAULT_PMBASE | addr); +}
-#if CONFIG_EARLY_CBMEM_INIT - struct mrc_data_container *mrcdata; - int output_len = ALIGN(pei_data->mrc_output_len, 16); +static inline u16 +read_acpi16 (u32 addr) +{ + return inw (DEFAULT_PMBASE | addr); +}
- /* Save the MRC S3 restore data to cbmem */ - cbmem_initialize(); - mrcdata = cbmem_add - (CBMEM_ID_MRCDATA, - output_len + sizeof(struct mrc_data_container)); +static inline u16 +read_tco16 (u32 addr) +{ + return inw (DEFAULT_PMBASE | (0x60 + addr)); +}
- printk(BIOS_DEBUG, "Relocate MRC DATA from %p to %p (%u bytes)\n", - pei_data->mrc_output, mrcdata, output_len); +static inline u8 +read_tco8 (u32 addr) +{ + return inb (DEFAULT_PMBASE | (0x60 + addr)); +}
- 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); +static inline void +write_tco16 (u32 addr, u16 val) +{ + outw (val, DEFAULT_PMBASE | (0x60 + addr)); +}
- /* 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); +static inline void +write_tco8 (u32 addr, u8 val) +{ + outb (val, DEFAULT_PMBASE | (0x60 + addr)); +}
- mrcdata->mrc_checksum = compute_ip_checksum(mrcdata->mrc_data, - mrcdata->mrc_data_size); -#endif +static inline void +write_mchbar32 (u32 addr, u32 val) +{ + MCHBAR32(addr) = val; + // udelay (1000); +} + +static inline void +write_mchbar16 (u32 addr, u16 val) +{ + MCHBAR16(addr) = val; + //udelay (1000); +} + +static inline void +write_mchbar8 (u32 addr, u8 val) +{ + MCHBAR8(addr) = val; + //udelay (1000); +} + +static u32 mchgav (u32 addr, u32 val) +{ + //printk (BIOS_DEBUG, "MCH: [%x] => %x\n", addr, val); + return val; +} + +static u32 pcigav (u32 addr, u32 val) +{ + //printk (BIOS_DEBUG, "PCI: [%x] => %x\n", addr, val); + return val; +}
- /* 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); +static inline u32 +read_mchbar32 (u32 addr) +{ + return mchgav (addr, MCHBAR32(addr)); +}
- 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); +static inline u32 +read_mchbar32_bypass (u32 addr) +{ + return MCHBAR32(addr); +}
- /* 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); +static inline u16 +read_mchbar16 (u32 addr) +{ + return mchgav (addr, MCHBAR16(addr)); +}
- cmos_write(checksum & 0xff, CMOS_OFFSET_MRC_SEED_CHK); - cmos_write((checksum >> 8) & 0xff, CMOS_OFFSET_MRC_SEED_CHK+1); +static inline u8 +read_mchbar8 (u32 addr) +{ + return mchgav (addr, MCHBAR8(addr)); }
-static void prepare_mrc_cache(struct pei_data *pei_data) +static inline u8 +read_mchbar8_bypass (u32 addr) { - struct mrc_data_container *mrc_cache; - u16 c1, c2, checksum, seed_checksum; + return MCHBAR8(addr); +}
- // preset just in case there is an error - pei_data->mrc_input = NULL; - pei_data->mrc_input_len = 0; +static u32 +pci_read32 (int bus, int dev, int func, u32 addr) +{ + return pcigav (addr, pci_read_config32(PCI_DEV(bus, dev, func), addr)); +}
- /* 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); +static u8 +pci_read8 (int bus, int dev, int func, u32 addr) +{ + return pcigav (addr, pci_read_config8(PCI_DEV(bus, dev, func), addr)); +}
- 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); +static void +pci_write32 (int bus, int dev, int func, u32 addr, u32 val) +{ + return pci_write_config32(PCI_DEV(bus, dev, func), addr, val); +}
- /* 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); +static void +pci_write16 (int bus, int dev, int func, u32 addr, u16 val) +{ + return pci_write_config16(PCI_DEV(bus, dev, func), addr, val); +}
- seed_checksum = cmos_read(CMOS_OFFSET_MRC_SEED_CHK); - seed_checksum |= cmos_read(CMOS_OFFSET_MRC_SEED_CHK+1) << 8; +static void +pci_write8 (int bus, int dev, int func, u32 addr, u8 val) +{ + return pci_write_config8(PCI_DEV(bus, dev, func), addr, val); +}
- 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; - } +static u16 +pci_read16 (int bus, int dev, int func, u32 addr) +{ + return pcigav (addr, pci_read_config16(PCI_DEV(bus, dev, func), addr)); +}
- if ((mrc_cache = find_current_mrc_cache()) == NULL) { - /* error message printed in find_current_mrc_cache */ - return; - } +static void +pci_mm_write8 (int bus, int dev, int func, u32 addr, u8 val) +{ + write8 (DEFAULT_PCIEXBAR | (bus << 20) | (dev << 15) | (func << 12) | addr, val); +} +static void +pci_mm_write16 (int bus, int dev, int func, u32 addr, u16 val) +{ + write16 (DEFAULT_PCIEXBAR | (bus << 20) | (dev << 15) | (func << 12) | addr, val); +} + +static void +pci_mm_write32 (int bus, int dev, int func, u32 addr, u32 val) +{ + write32 (DEFAULT_PCIEXBAR | (bus << 20) | (dev << 15) | (func << 12) | addr, val); +} + +static u32 +pci_mm_read32 (int bus, int dev, int func, u32 addr) +{ + return pcigav (addr, read32 (DEFAULT_PCIEXBAR | (bus << 20) | (dev << 15) | (func << 12) | addr)); +} + +static u16 +pci_mm_read16 (int bus, int dev, int func, u32 addr) +{ + return pcigav (addr, read16 (DEFAULT_PCIEXBAR | (bus << 20) | (dev << 15) | (func << 12) | addr)); +} + +static u8 +pci_mm_read8 (int bus, int dev, int func, u32 addr) +{ + return pcigav (addr, read8 (DEFAULT_PCIEXBAR | (bus << 20) | (dev << 15) | (func << 12) | addr)); +} + +#if 0 +static void clflush(u32 addr) +{ + asm volatile ("clflush (%0)" : : "r" (addr)); +} + +typedef struct _u128 +{ + u64 lo; + u64 hi; +} u128; + +static void +read128 (u32 addr, u64 *out) +{ + u128 ret; + u128 stor; + asm volatile ("movdqu %%xmm0, %0\n" + "movdqa (%2), %%xmm0\n" + "movdqu %%xmm0, %1\n" + "movdqu %0, %%xmm0":"+m"(stor),"=m"(ret):"r"(addr)); + out[0] = ret.lo; + out[1] = ret.hi; +} +#endif + +#endif + +/* OK */ +static void +write_1d0 (u32 val, u16 addr, int bits, int flag) +{ + write_mchbar32 (0x1d0, 0); + while (read_mchbar32_bypass (0x1d0) & 0x800000); + write_mchbar32 (0x1d4, (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits)); + write_mchbar32 (0x1d0, 0x40000000 | addr); + while (read_mchbar32_bypass (0x1d0) & 0x800000); +} + +/* OK */ +static u16 +read_1d0 (u16 addr, int split) +{ + u32 val; + write_mchbar32 (0x1d0, 0); + while (read_mchbar32_bypass (0x1d0) & 0x800000); + write_mchbar32 (0x1d0, 0x80000000 | (((read_mchbar8_bypass (0x246) >> 2) & 3) + 0x361 - addr)); + while (read_mchbar32_bypass (0x1d0) & 0x800000); + val = read_mchbar32_bypass (0x1d8); + write_1d0 (0, 0x33d, 0, 0); + write_1d0 (0, 0x33d, 0, 0); + val &= ((1 << split) - 1); + // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val); + return val; +} + +static void +sfence (void) +{ +#if REAL + asm volatile ("sfence"); +#endif +} + + +static inline u16 +get_lane_offset (int slot, int rank, int lane) +{ + return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot - 0x452 * (lane == 8); +} + +static inline u16 +get_timing_register_addr (int lane, int tm, int slot, int rank) +{ + const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c }; + return get_lane_offset (slot, rank, lane) + offs[(tm + 3) % 4]; +}
- pei_data->mrc_input = mrc_cache->mrc_data; - pei_data->mrc_input_len = mrc_cache->mrc_data_size;
- 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); +static u32 gav_real (int line, u32 in) +{ + // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in); + return in; }
-static const char* ecc_decoder[] = { - "inactive", - "active on IO", - "disabled on IO", - "active" +#define gav(x) gav_real (__LINE__, (x)) + +struct raminfo +{ + u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */ + u16 some_base_frequency; + u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */ + u8 density[2][2]; /* [CHANNEL][SLOT] */ + u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */ + int rank_start[2][2][2]; + u8 cas_latency; + u8 board_lane_delay[9]; + u8 use_ecc; + u8 revision; + u8 max_supported_clock_speed_index; + u8 uma_enabled; + u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */ + u8 silicon_revision; + u8 populated_ranks_mask[2]; + u8 max_slots_used_in_channel; + u8 v4030[2]; + union { + struct + { + u16 v4044[2]; + u16 v4048[2]; + }; + u8 u4044[2][2][2]; + }; + unsigned total_memory_mb; + unsigned interleaved_part_mb; + unsigned non_interleaved_part_mb; + + u32 heci_bar; + u64 heci_uma_addr; + unsigned memory_reserved_for_heci_mb; + u32 v4086; + + struct ram_training training; + u32 last_500_command[2]; };
-/* - * Dump in the log memory controller configuration as read from the memory - * controller registers. - */ -static void report_memory_config(void) -{ - u32 addr_decoder_common, addr_decode_ch[2]; - int i; - - addr_decoder_common = MCHBAR32(0x5000); - addr_decode_ch[0] = MCHBAR32(0x5004); - addr_decode_ch[1] = MCHBAR32(0x5008); - - printk(BIOS_DEBUG, "memcfg DDR3 clock %d MHz\n", - (MCHBAR32(0x5e04) * 13333 * 2 + 50)/100); - printk(BIOS_DEBUG, "memcfg channel assignment: A: %d, B % d, C % d\n", - addr_decoder_common & 3, - (addr_decoder_common >> 2) & 3, - (addr_decoder_common >> 4) & 3); - - for (i = 0; i < ARRAY_SIZE(addr_decode_ch); i++) { - u32 ch_conf = addr_decode_ch[i]; - printk(BIOS_DEBUG, "memcfg channel[%d] config (%8.8x):\n", - i, ch_conf); - printk(BIOS_DEBUG, " ECC %s\n", - ecc_decoder[(ch_conf >> 24) & 3]); - printk(BIOS_DEBUG, " enhanced interleave mode %s\n", - ((ch_conf >> 22) & 1) ? "on" : "off"); - printk(BIOS_DEBUG, " rank interleave %s\n", - ((ch_conf >> 21) & 1) ? "on" : "off"); - printk(BIOS_DEBUG, " DIMMA %d MB width x%d %s rank%s\n", - ((ch_conf >> 0) & 0xff) * 256, - ((ch_conf >> 19) & 1) ? 16 : 8, - ((ch_conf >> 17) & 1) ? "dual" : "single", - ((ch_conf >> 16) & 1) ? "" : ", selected"); - printk(BIOS_DEBUG, " DIMMB %d MB width x%d %s rank%s\n", - ((ch_conf >> 8) & 0xff) * 256, - ((ch_conf >> 20) & 1) ? 16 : 8, - ((ch_conf >> 18) & 1) ? "dual" : "single", - ((ch_conf >> 16) & 1) ? ", selected" : ""); - } +static void +write_500 (struct raminfo *info, int channel, u32 val, u16 addr, int bits, int flag); + +/* OK */ +static u16 +read_500_bypass (struct raminfo *info, int channel, u16 addr, int split) +{ + u32 val; + info->last_500_command[channel] = 0x80000000; + write_mchbar32 (0x500 + (channel << 10), 0); + while (read_mchbar32_bypass (0x500 + (channel << 10)) & 0x800000); + write_mchbar32 (0x500 + (channel << 10), 0x80000000 | (((read_mchbar8_bypass (0x246 + (channel << 10)) >> 2) & 3) + 0xb88 - addr)); + while (read_mchbar32_bypass (0x500 + (channel << 10)) & 0x800000); + val = read_mchbar32_bypass (0x508 + (channel << 10)); + return val & ((1 << split) - 1); }
-static void post_system_agent_init(struct pei_data *pei_data) +static u16 +read_500 (struct raminfo *info, int channel, u16 addr, int split) { - /* If PCIe init is skipped, set the PEG clock gating */ - if (!pei_data->pcie_init) - MCHBAR32(0x7010) = MCHBAR32(0x7010) | 0x01; + u16 ret; + ret = read_500_bypass (info, channel, addr, split); + // printk (BIOS_ERR, "R500 [%d/%x] => %x\n", channel, addr, ret); + return ret; }
-/** - * 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) +/* OK */ +static void +write_500 (struct raminfo *info, int channel, u32 val, u16 addr, int bits, int flag) +{ + if (info->last_500_command[channel] == 0x80000000) + { + info->last_500_command[channel] = 0x40000000; + write_500 (info, channel, 0, 0xb61, 0, 0); + } + write_mchbar32 (0x500 + (channel << 10), 0); + while (read_mchbar32 (0x500 + (channel << 10)) & 0x800000); + write_mchbar32 (0x504 + (channel << 10), (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits)); + write_mchbar32 (0x500 + (channel << 10), 0x40000000 | addr); + while (read_mchbar32 (0x500 + (channel << 10)) & 0x800000); +} + +static int +rw_test (int rank) +{ + const u32 mask = 0xf00fc33c; + int ok = 0xff; + int i; + for (i = 0; i < 64; i++) + write32 ((rank << 28) | (i << 2), 0); + sfence (); + for (i = 0; i < 64; i++) + gav (read32 ((rank << 28) | (i << 2))); + sfence (); + for (i = 0; i < 32; i++) + { + u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0); + write32 ((rank << 28) | (i << 3), pat); + write32 ((rank << 28) | (i << 3) | 4, pat); + } + sfence (); + for (i = 0; i < 32; i++) + { + u8 pat = (((mask >> i) & 1) ? 0xff : 0); + int j; + u32 val; + gav (val = read32 ((rank << 28) | (i << 3))); + for (j = 0; j < 4; j++) + if (((val >> (j * 8)) & 0xff) != pat) + ok &= ~(1 << j); + gav (val = read32 ((rank << 28) | (i << 3) | 4)); + for (j = 0; j < 4; j++) + if (((val >> (j * 8)) & 0xff) != pat) + ok &= ~(16 << j); + } + sfence (); + for (i = 0; i < 64; i++) + write32 ((rank << 28) | (i << 2), 0); + sfence (); + for (i = 0; i < 64; i++) + gav (read32 ((rank << 28) | (i << 2))); + + return ok; +} + +static void +program_timings (struct raminfo *info, u16 base, int channel, int slot, int rank) +{ + int lane; + for (lane = 0; lane < 8; lane++) + { + write_500 (info, channel, base + info->training.lane_timings[2][channel][slot][rank][lane], + get_timing_register_addr (lane, 2, slot, rank), 9, 0); + write_500 (info, channel, base + info->training.lane_timings[3][channel][slot][rank][lane], + get_timing_register_addr (lane, 3, slot, rank), 9, 0); + } +} + +static void +write_26c (int channel, u16 si) +{ + write_mchbar32 (0x26c + (channel << 10), 0x03243f35); + write_mchbar32 (0x268 + (channel << 10), 0xcfc00000 | (si << 9)); + write_mchbar16 (0x2b9 + (channel << 10), si); +} + +static u32 +get_580 (int channel, u8 addr) +{ + u32 ret; + gav (read_1d0 (0x142, 3)); + write_mchbar8 (0x5ff, 0x0); /* OK */ + write_mchbar8 (0x5ff, 0x80); /* OK */ + write_mchbar32 (0x580 + (channel << 10), 0x8493c012 | addr); + write_mchbar8 (0x580 + (channel << 10), read_mchbar8 (0x580 + (channel << 10)) | 1); + while (!((ret = read_mchbar32 (0x580 + (channel << 10))) & 0x10000)); + write_mchbar8 (0x580 + (channel << 10), read_mchbar8 (0x580 + (channel << 10)) & ~1); + return ret; +} + +static void +seq8 (void) +{ + write_mchbar8 (0x243, 0x1); + write_mchbar8 (0x643, 0x1); +} + +const int cached_config = 0; + +#define NUM_CHANNELS 2 +#define NUM_SLOTS 2 +#define NUM_RANKS 2 +#define RANK_SHIFT 28 +#define CHANNEL_SHIFT 10 + +#include "raminit_tables.c" + +static void +seq9 (struct raminfo *info, int channel, int slot, int rank) +{ + int i, lane; + + for (i = 0; i < 2; i++) + for (lane = 0; lane < 8; lane++) + write_500 (info, channel, info->training.lane_timings[i + 1][channel][slot][rank][lane], + get_timing_register_addr (lane, i + 1, slot, rank), 9, 0); + + write_1d0 (1, 0x103, 6, 1); + for (lane = 0; lane < 8; lane++) + write_500 (info, channel, info->training.lane_timings[0][channel][slot][rank][lane], get_timing_register_addr (lane, 0, slot, rank), 9, 0); + + for (i = 0; i < 2; i++) + { + for (lane = 0; lane < 8; lane++) + write_500 (info, channel, info->training.lane_timings[i + 1][channel][slot][rank][lane], get_timing_register_addr (lane, i + 1, slot, rank), 9, 0); + gav (get_580 (channel, ((i + 1) << 2) | (rank << 5))); + } + + gav (read_1d0 (0x142, 3)); // = 0x10408118 + write_mchbar8 (0x5ff, 0x0); /* OK */ + write_mchbar8 (0x5ff, 0x80); /* OK */ + write_1d0 (0x2, 0x142, 3, 1); + for (lane = 0; lane < 8; lane++) + { + // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]); + info->training.lane_timings[2][channel][slot][rank][lane] = read_500 (info, channel, get_timing_register_addr (lane, 2, slot, rank), 9); + //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]); + info->training.lane_timings[3][channel][slot][rank][lane] = info->training.lane_timings[2][channel][slot][rank][lane] + 0x20; + } +} + +static int +count_ranks_in_channel (struct raminfo *info, int channel) +{ + int slot, rank; + int res = 0; + for (slot = 0; slot < NUM_SLOTS; slot++) + for (rank = 0; rank < NUM_SLOTS; rank++) + res += info->populated_ranks[channel][slot][rank]; + return res; +} + +static void +config_rank (struct raminfo *info, int s3resume, int channel, int slot, int rank) { - struct sys_info sysinfo; - unsigned long entry; + int add;
- report_platform_info(); + write_1d0 (0, 0x178, 7, 1); + seq9 (info, channel, slot, rank); + program_timings (info, 0x80, channel, slot, rank);
- /* Wait for ME to be ready */ - intel_early_me_init(); - intel_early_me_uma_size(); + if (channel == 0) + add = count_ranks_in_channel (info, 1); + else + add = 0; + if (!s3resume) + gav (rw_test (rank + add)); + program_timings (info, 0x00, channel, slot, rank); + if (!s3resume) + gav (rw_test (rank + add)); + if (!s3resume) + gav (rw_test (rank + add)); + write_1d0 (0, 0x142, 3, 1); + write_1d0 (0, 0x103, 6, 1); + + gav (get_580 (channel, 0xc | (rank << 5))); + gav (read_1d0 (0x142, 3)); + + write_mchbar8 (0x5ff, 0x0); /* OK */ + write_mchbar8 (0x5ff, 0x80); /* OK */ +}
- printk(BIOS_DEBUG, "Starting UEFI PEI System Agent\n"); +static void +set_4cf (struct raminfo *info, int channel, u8 val) +{ + gav (read_500 (info, channel, 0x4cf, 4)); // = 0xc2300cf9 + write_500 (info, channel, val, 0x4cf, 4, 1); + gav (read_500 (info, channel, 0x659, 4)); // = 0x80300839 + write_500 (info, channel, val, 0x659, 4, 1); + gav (read_500 (info, channel, 0x697, 4)); // = 0x80300839 + write_500 (info, channel, val, 0x697, 4, 1); +}
- memset(&sysinfo, 0, sizeof(sysinfo)); +static void +set_334 (int zero) +{ + int j, k, channel; + const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b }; + u32 vd8[2][16];
- sysinfo.boot_path = pei_data->boot_mode; + for (channel = 0; channel < NUM_CHANNELS; channel++) + { + for (j = 0; j < 4; j++) + { + u32 a = (j == 1) ? 0x29292929 : 0x31313131; + u32 lmask = (j == 3) ? 0xffff : 0xffffffff; + u16 c; + if ((j == 0 || j == 3) && zero) + c = 0; + else if (j == 3) + c = 0x5f; + else + c = 0x5f5f;
- /* - * Do not pass MRC data in for recovery mode boot, - * Always pass it in for S3 resume. - */ - if (!recovery_mode_enabled() || pei_data->boot_mode == 2) - prepare_mrc_cache(pei_data); + for (k = 0; k < 2; k++) + { + write_mchbar32 (0x138 + 8 * k, (channel << 26) | (j << 24)); + gav (vd8[1][(channel << 3) | (j << 1) | k] = read_mchbar32 (0x138 + 8 * k)); + gav (vd8[0][(channel << 3) | (j << 1) | k] = read_mchbar32 (0x13c + 8 * k)); + }
- /* 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(); + write_mchbar32 (0x334 + (channel << 10) + (j * 0x44), zero ? 0 : val3[j]); + write_mchbar32 (0x32c + (channel << 10) + (j * 0x44), zero ? 0 : (0x18191819 & lmask)); + write_mchbar16 (0x34a + (channel << 10) + (j * 0x44), c); + write_mchbar32 (0x33c + (channel << 10) + (j * 0x44), zero ? 0 : (a & lmask)); + write_mchbar32 (0x344 + (channel << 10) + (j * 0x44), zero ? 0 : (a & lmask)); } + }
- /* Pass console handler in pei_data */ - pei_data->tx_byte = console_tx_byte; - - /* Locate and call UEFI System Agent binary. */ - /* TODO make MRC blob (0xab?) defined in cbfs_core.h. */ - entry = (unsigned long)cbfs_get_file_content( - CBFS_DEFAULT_MEDIA, "mrc.bin", 0xab); - if (entry) { - int rv; - asm volatile ( - "call *%%ecx\n\t" - :"=a" (rv) : "c" (entry), "a" (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); - } - die("Nonzero MRC return value.\n"); - } - } else { - die("UEFI PEI System Agent not found.\n"); + write_mchbar32 (0x130, read_mchbar32 (0x130) | 1); /* OK */ + while (read_mchbar8 (0x130) & 1); /* OK */ +} + +static void +rmw_1d0 (u16 addr, u32 and, u32 or, int split, int flag) +{ + u32 v; + v = read_1d0 (addr, split); + write_1d0 ((v & and) | or, addr, split, flag); +} + +static int +find_highest_bit_set (u16 val) +{ + int i; + for (i = 15; i >= 0; i--) + if (val & (1 << i)) + return i; + return -1; +} + +static int +find_lowest_bit_set32 (u32 val) +{ + int i; + for (i = 0; i < 32; i++) + if (val & (1 << i)) + return i; + return -1; +} + +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +enum + { + DEVICE_TYPE = 2, + MODULE_TYPE = 3, + DENSITY = 4, + RANKS_AND_DQ = 7, + MEMORY_BUS_WIDTH = 8, + TIMEBASE_DIVIDEND = 10, + TIMEBASE_DIVISOR = 11, + CYCLETIME = 12, + + CAS_LATENCIES_LSB = 14, + CAS_LATENCIES_MSB = 15, + CAS_LATENCY_TIME = 16, + THERMAL_AND_REFRESH = 31, + REFERENCE_RAW_CARD_USED = 62, + RANK1_ADDRESS_MAPPING = 63 + }; + +static void +calculate_timings (struct raminfo *info) +{ + unsigned cycletime; + unsigned cas_latency_time; + unsigned supported_cas_latencies; + unsigned channel, slot; + unsigned clock_speed_index; + unsigned min_cas_latency; + unsigned cas_latency; + unsigned max_clock_index; + + /* Find common CAS latency */ + supported_cas_latencies = 0x3fe; + for (channel = 0; channel < NUM_CHANNELS; channel++) + for (slot = 0; slot < NUM_SLOTS; slot++) + if (info->populated_ranks[channel][slot][0]) + supported_cas_latencies &= 2 * (info->spd[channel][slot][CAS_LATENCIES_LSB] | (info->spd[channel][slot][CAS_LATENCIES_MSB] << 8)); + + max_clock_index = min (3, info->max_supported_clock_speed_index); + + cycletime = min_cycletime[max_clock_index]; + cas_latency_time = min_cas_latency_time[max_clock_index]; + + for (channel = 0; channel < NUM_CHANNELS; channel++) + for (slot = 0; slot < NUM_SLOTS; slot++) + if (info->populated_ranks[channel][slot][0]) + { + unsigned timebase; + timebase = 1000 * info->spd[channel][slot][TIMEBASE_DIVIDEND] / info->spd[channel][slot][TIMEBASE_DIVISOR]; + cycletime = max (cycletime, timebase * info->spd[channel][slot][CYCLETIME]); + cas_latency_time = max (cas_latency_time, timebase * info->spd[channel][slot][CAS_LATENCY_TIME]); } + for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) + { + if (cycletime == min_cycletime[clock_speed_index]) + break; + if (cycletime > min_cycletime[clock_speed_index]) + { + clock_speed_index--; + cycletime = min_cycletime[clock_speed_index]; + break; + } + } + min_cas_latency = (cas_latency_time + cycletime - 1) / cycletime; + cas_latency = 0; + while (supported_cas_latencies) + { + cas_latency = find_highest_bit_set(supported_cas_latencies) + 3; + if (cas_latency <= min_cas_latency) + break; + supported_cas_latencies &= ~(1 << find_highest_bit_set(supported_cas_latencies)); + }
-#if CONFIG_USBDEBUG - /* mrc.bin reconfigures USB, so reinit it to have debug */ - early_usbdebug_init(); -#endif + if (cas_latency != min_cas_latency && clock_speed_index) + clock_speed_index--; + + if (cas_latency * min_cycletime[clock_speed_index] > 20000) + die ("Couldn't configure DRAM"); + info->clock_speed_index = clock_speed_index; + info->cas_latency = cas_latency; +} + +#define s3oresume (s3resume && !REAL) + +static void +program_base_timings (struct raminfo *info) +{ + unsigned channel; + unsigned slot, rank, lane; + unsigned extended_silicon_revision; + int i; + + extended_silicon_revision = info->silicon_revision; + if (info->silicon_revision == 0) + for (channel = 0; channel < NUM_CHANNELS; channel++) + for (slot = 0; slot < NUM_SLOTS; slot++) + if ((info->spd[channel][slot][MODULE_TYPE] & 0xF) == 3) + extended_silicon_revision = 4;
- /* 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); + for (channel = 0; channel < NUM_CHANNELS; channel++) + { + for (slot = 0; slot < NUM_SLOTS; slot++) + for (rank = 0; rank < NUM_SLOTS; rank++) + { + int card_timing_2; + if (!info->populated_ranks[channel][slot][rank]) + continue;
- /* 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(); + for (lane = 0; lane < 9; lane++) + { + int tm_reg; + int card_timing;
- post_system_agent_init(pei_data); - report_memory_config(); + card_timing = 0; + if ((info->spd[channel][slot][MODULE_TYPE] & 0xF) == 3) + { + int reference_card; + reference_card = info->spd[channel][slot][REFERENCE_RAW_CARD_USED] & 0x1f; + if (reference_card == 3) + card_timing = u16_ffd1188[0][lane][info->clock_speed_index]; + if (reference_card == 5) + card_timing = u16_ffd1188[1][lane][info->clock_speed_index]; + }
- /* S3 resume: don't save scrambler seed or MRC data */ - if (pei_data->boot_mode != 2) - save_mrc_data(pei_data); + info->training.lane_timings[0][channel][slot][rank][lane] = u8_FFFD1218[info->clock_speed_index]; + info->training.lane_timings[1][channel][slot][rank][lane] = 256; + + for (tm_reg = 2; tm_reg < 4; tm_reg++) + info->training.lane_timings[tm_reg][channel][slot][rank][lane] = u8_FFFD1240[channel][extended_silicon_revision][lane][2 * slot + rank][info->clock_speed_index] + + info->v4048[channel] + + u8_FFFD0C78[channel][extended_silicon_revision][info->v4030[channel]][slot][rank][info->clock_speed_index] + + card_timing; + for (tm_reg = 0; tm_reg < 4; tm_reg++) + write_500 (info, channel, info->training.lane_timings[tm_reg][channel][slot][rank][lane], + get_timing_register_addr (lane, tm_reg, slot, rank), + 9, 0); + } + + card_timing_2 = 0; + if (!(extended_silicon_revision != 4 + || (info->populated_ranks_mask[channel] & 5) == 5)) + { + if ((info->spd[channel][slot][REFERENCE_RAW_CARD_USED] & 0x1F) == 3) + card_timing_2 = u16_FFFE0EB8[0][info->clock_speed_index]; + if ((info->spd[channel][slot][REFERENCE_RAW_CARD_USED] & 0x1F) == 5) + card_timing_2 = u16_FFFE0EB8[1][info->clock_speed_index]; + } + + for (i = 0; i < 3; i++) + write_500 (info, channel, (card_timing_2 + info->v4048[channel] + + u8_FFFD0EF8[channel][extended_silicon_revision][info->v4030[channel]][info->clock_speed_index]), + u16_fffd0c50[i][slot][rank], 8, 1); + write_500 (info, channel, (info->v4048[channel] + u8_FFFD0C78[channel][extended_silicon_revision][info->v4030[channel]][slot][rank][info->clock_speed_index]), + u16_fffd0c70[slot][rank], 7, 1); + } + if (!info->populated_ranks_mask[channel]) + continue; + for (i = 0; i < 3; i++) + write_500 (info, channel, (info->v4048[channel] + info->v4044[channel] + + u8_FFFD17E0[channel][extended_silicon_revision][info->v4030[channel]][info->clock_speed_index]), + u16_fffd0c68[i], 8, 1); + } }
-struct cbmem_entry *get_cbmem_toc(void) +/* The time of DDR transfer in ps. */ +static unsigned int +halfcycle_ps (struct raminfo *info) { - return (struct cbmem_entry *)(get_top_of_ram() - HIGH_MEMORY_SIZE); + return 3750 / (info->clock_speed_index + 3); }
-unsigned long get_top_of_ram(void) +/* The time of clock cycle in ps. */ +static unsigned int +cycle_ps (struct raminfo *info) { - /* Base of TSEG is top of usable DRAM */ - u32 tom = pci_read_config32(PCI_DEV(0,0,0), TSEG); - return (unsigned long) tom; + return 2 * halfcycle_ps (info); +} + +/* Frequency in 1.(1)=10/9 MHz units. */ +static unsigned +frequency_11 (struct raminfo *info) +{ + return (info->clock_speed_index + 3) * 120; +} + +/* Frequency in 0.1 MHz units. */ +static unsigned +frequency_01 (struct raminfo *info) +{ + return 100 * frequency_11 (info) / 9; +} + +static unsigned +ps_to_halfcycles (struct raminfo *info, unsigned int ps) +{ + return (frequency_11 (info) * 2) * ps / 900000; +} + +static unsigned +ns_to_cycles (struct raminfo *info, unsigned int ns) +{ + return (frequency_11 (info)) * ns / 900; +} + +static void +compute_derived_timings(struct raminfo *info) +{ + unsigned channel, slot, rank; + int extended_silicon_revision; + int some_delay_1_ps; + int some_delay_2_ps; + int some_delay_2_halfcycles_ceil; + int some_delay_2_halfcycles_floor; + int some_delay_3_ps; + int some_delay_3_halfcycles; + int some_delay_3_ps_rounded; + int some_delay_1_cycle_ceil; + int some_delay_1_cycle_floor; + + some_delay_3_halfcycles = 0; + some_delay_3_ps_rounded = 0; + extended_silicon_revision = info->silicon_revision; + if (!info->silicon_revision) + for (channel = 0; channel < NUM_CHANNELS; channel++) + for (slot = 0; slot < NUM_SLOTS; slot++) + if ((info->spd[channel][slot][MODULE_TYPE] & 0xF) == 3) + extended_silicon_revision = 4; + if (info->board_lane_delay[7] < 5) + info->board_lane_delay[7] = 5; + info->u4044[0][0][0] = 2; + if ( info->silicon_revision == 2 || info->silicon_revision == 3 ) + info->u4044[0][0][0] = 0; + if ( info->revision < 0x10u ) + info->u4044[0][0][0] = 0; + info->u4044[0][1][0] = 0; + info->u4044[1][1][1] = 0; + if (info->revision < 8) + info->u4044[0][0][0] = 0; + if (info->revision >= 8 && (info->silicon_revision == 0 + || info->silicon_revision == 1)) + { + some_delay_1_ps = 3929; + some_delay_2_ps = 735; + } + else + { + some_delay_1_ps = 3490; + some_delay_2_ps = 750; + } + some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps (info); + some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps (info); + if (some_delay_1_ps % cycle_ps (info)) + some_delay_1_cycle_ceil++; + else + some_delay_1_cycle_floor--; + info->u4044[0][1][1] = some_delay_1_cycle_floor; + if (info->u4044[0][0][0]) + some_delay_2_ps = halfcycle_ps (info) >> 6; + some_delay_2_ps += max (some_delay_1_ps - 30, 2 * halfcycle_ps (info) * (some_delay_1_cycle_ceil - 1) + 1000) + 375; + some_delay_3_ps = halfcycle_ps (info) - some_delay_2_ps % halfcycle_ps (info); + if (info->u4044[0][0][0]) + { + if (some_delay_3_ps < 150) + some_delay_3_halfcycles = 0; + else + some_delay_3_halfcycles = (some_delay_3_ps << 6) / halfcycle_ps (info); + some_delay_3_ps_rounded = halfcycle_ps (info) * some_delay_3_halfcycles >> 6; + } + some_delay_2_halfcycles_ceil = (some_delay_2_ps + halfcycle_ps (info) - 1) / halfcycle_ps (info) - 2 * (some_delay_1_cycle_ceil - 1); + if (info->u4044[0][0][0] && some_delay_3_ps < 150) + some_delay_2_halfcycles_ceil++; + some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil; + if (info->revision < 0x10) + some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil - 1; + if (!info->u4044[0][0][0]) + ++some_delay_2_halfcycles_floor; + info->u4044[1][0][0] = some_delay_2_halfcycles_ceil; + info->u4044[1][0][1] = some_delay_3_halfcycles; + info->u4044[1][1][0] = some_delay_3_ps_rounded; + info->u4044[0][0][1] = some_delay_2_halfcycles_floor; + if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0]) + || (info->populated_ranks[1][0][0] && info->populated_ranks[1][1][0])) + info->max_slots_used_in_channel = 2; + else + info->max_slots_used_in_channel = 1; + for (channel = 0; channel < 2; channel++) + write_mchbar32 (0x244 + (channel << 10), ((info->revision < 8) ? 1 : 0x200) + | ((2 - info->max_slots_used_in_channel) << 17) | (channel << 21) | (info->u4044[0][1][1] << 18) | 0x9510); + if (info->max_slots_used_in_channel == 1) + { + info->v4030[0] = (count_ranks_in_channel (info, 0) == 2); + info->v4030[1] = (count_ranks_in_channel (info, 1) == 2); + } + else + { + info->v4030[0] = ((count_ranks_in_channel (info, 0) == 1) || (count_ranks_in_channel (info, 0) == 2)) ? 2 : 3; /* 2 if 1 or 2 ranks */ + info->v4030[1] = ((count_ranks_in_channel (info, 1) == 1) || (count_ranks_in_channel (info, 1) == 2)) ? 2 : 3; + } + for (channel = 0; channel < NUM_CHANNELS; channel++) + { + int max_of_unk; + int min_of_unk_2; + + int i, count; + int sum; + + if (!info->populated_ranks_mask[channel]) + continue; + + max_of_unk = 0; + min_of_unk_2 = 32767; + + sum = 0; + count = 0; + for (i = 0; i < 3; i++) + { + int unk1; + if (info->revision < 8) + unk1 = u8_FFFD1891[0][channel][info->clock_speed_index][i]; + else if (!(info->revision >= 0x10 || info->u4044[0][0][0])) + unk1 = u8_FFFD1891[1][channel][info->clock_speed_index][i]; + else + unk1 = 0; + for (slot = 0; slot < NUM_SLOTS; slot++) + for (rank = 0; rank < NUM_RANKS; rank++) + { + int a = 0; + int b = 0; + + if (!info->populated_ranks[channel][slot][rank]) + continue; + if ( extended_silicon_revision == 4 && (info->populated_ranks_mask[channel] & 5) != 5 ) + { + if ( (info->spd[channel][slot][REFERENCE_RAW_CARD_USED] & 0x1F) == 3 ) + { + a = u16_ffd1178[0][info->clock_speed_index]; + b = u16_fe0eb8[0][info->clock_speed_index]; + } + else if ( (info->spd[channel][slot][REFERENCE_RAW_CARD_USED] & 0x1F) == 5 ) + { + a = u16_ffd1178[1][info->clock_speed_index]; + b = u16_fe0eb8[1][info->clock_speed_index]; + } + } + min_of_unk_2 = min (min_of_unk_2, a); + min_of_unk_2 = min (min_of_unk_2, b); + if (rank == 0) + { + sum += a; + count++; + } + { + int t; + t = b + u8_FFFD0EF8[channel][extended_silicon_revision][info->v4030[channel]][info->clock_speed_index]; + if (unk1 >= t) + max_of_unk = max (max_of_unk, unk1 - t); + } + } + { + int t = u8_FFFD17E0[channel][extended_silicon_revision][info->v4030[channel]][info->clock_speed_index] + min_of_unk_2; + if (unk1 >= t) + max_of_unk = max (max_of_unk, unk1 - t); + } + } + + info->u4044[0][channel][0] = sum / count; + info->u4044[1][channel][0] = max_of_unk; + } +} + +static void jedec_read(struct raminfo *info, + int channel, int slot, int rank, + int total_rank, u8 addr3, unsigned int value) +{ + /* Handle mirrored mapping. */ + if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1)) + addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) | ((addr3 >> 1) & 0x10); + write_mchbar8 (0x271, addr3 | (read_mchbar8 (0x271) & 0xC1)); + write_mchbar8 (0x671, addr3 | (read_mchbar8 (0x671) & 0xC1)); + + /* Handle mirrored mapping. */ + if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1)) + value = (value & ~0x1f8) | ((value >> 1) & 0xA8) | ((value & 0xA8) << 1); + + read32 ((value << 3) | (total_rank << 28)); + + write_mchbar8 (0x271, (read_mchbar8 (0x271) & 0xC3) | 2); + write_mchbar8 (0x671, (read_mchbar8 (0x671) & 0xC3) | 2); + + read32 (total_rank << 28); } + +enum + { + MR1_RZQ12 = 512, + MR1_RZQ2 = 64, + MR1_RZQ4 = 4, + MR1_ODS34OHM = 2 + }; + +enum + { + MR0_BT_INTERLEAVED = 8, + MR0_DLL_RESET_ON = 256 + }; + +enum + { + MR2_RTT_WR_DISABLED = 0, + MR2_RZQ2 = 1 << 10 + }; + +static void +jedec_init (struct raminfo *info) +{ + int write_recovery; + int channel, slot, rank; + int total_rank; + int dll_on; + int self_refresh_temperature; + int auto_self_refresh; + + auto_self_refresh = 1; + self_refresh_temperature = 1; + if (info->board_lane_delay[3] <= 10) + { + if (info->board_lane_delay[3] <= 8) + write_recovery = info->board_lane_delay[3] - 4; + else + write_recovery = 5; + } + else + { + write_recovery = 6; + } + for (channel = 0; channel < NUM_CHANNELS; channel++) + for (slot = 0; slot < NUM_CHANNELS; slot++) + for (rank = 0; rank < NUM_RANKS; rank++) + if (info->populated_ranks[channel][slot][rank]) + { + auto_self_refresh &= (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1; + self_refresh_temperature &= info->spd[channel][slot][THERMAL_AND_REFRESH] & 1; + } + if (auto_self_refresh == 1) + self_refresh_temperature = 0; + + dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3) + || (info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0]) + || (info->populated_ranks[1][0][0] && info->populated_ranks[1][1][0])); + + total_rank = 0; + + for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) + { + int rtt, rtt_wr = MR2_RTT_WR_DISABLED; + int rzq_reg58e; + + if (info->silicon_revision == 2 || info->silicon_revision == 3) + { + rzq_reg58e = 64; + rtt = MR1_RZQ2; + if (info->clock_speed_index != 0) + { + rzq_reg58e = 4; + if (info->populated_ranks_mask[channel] == 3) + rtt = MR1_RZQ4; + } + } + else + { + if ((info->populated_ranks_mask[channel] & 5) == 5) + { + rtt = MR1_RZQ12; + rzq_reg58e = 64; + rtt_wr = MR2_RZQ2; + } + else + { + rzq_reg58e = 4; + rtt = MR1_RZQ4; + } + } + + write_mchbar16 (0x588 + (channel << 10), 0x0); + write_mchbar16 (0x58a + (channel << 10), 0x4); + write_mchbar16 (0x58c + (channel << 10), rtt | MR1_ODS34OHM); + write_mchbar16 (0x58e + (channel << 10), rzq_reg58e | 0x82); + write_mchbar16 (0x590 + (channel << 10), 0x1282); + + for (slot = 0; slot < NUM_SLOTS; slot++) + for (rank = 0; rank < NUM_RANKS; rank++) + if (info->populated_ranks[channel][slot][rank]) + { + jedec_read (info, channel, slot, rank, + total_rank, 0x28, + rtt_wr | (info->clock_speed_index << 3) + | (auto_self_refresh << 6) | (self_refresh_temperature << 7)); + jedec_read (info, channel, slot, rank, total_rank, 0x38, 0); + jedec_read (info, channel, slot, rank, + total_rank, 0x18, rtt | MR1_ODS34OHM); + jedec_read (info, channel, slot, rank, + total_rank, 6, + (dll_on << 12) | (write_recovery << 9) + | ((info->cas_latency - 4) << 4) | MR0_BT_INTERLEAVED | MR0_DLL_RESET_ON); + total_rank++; + } + } +} + +static void pm_wait (u16 us) +{ + u32 base = read_acpi32 (8); + u32 ticks = (us * 358) / 100; + while (((read_acpi32 (8) - base) & 0xffffff) < ticks); +} + +static void program_modules_memory_map (struct raminfo *info, int pre_jedec) +{ + unsigned channel, slot, rank; + unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */ + unsigned int channel_0_non_interleaved; + + for (channel = 0; channel < NUM_CHANNELS; channel++) + for (slot = 0; slot < NUM_SLOTS; slot++) + for (rank = 0; rank < NUM_RANKS; rank++) + { + if (info->populated_ranks[channel][slot][rank]) + { + total_mb[channel] += pre_jedec ? 256 : (256 << info->density[channel][slot] >> info->is_x16_module[channel][slot]); + write_mchbar8 (0x208 + rank + 2 * slot + (channel << 10), + (pre_jedec ? (1 | ((1 + 1) << 1)) : (info->is_x16_module[channel][slot] | ((info->density[channel][slot] + 1) << 1))) | 0x80); + } + write_mchbar16 (0x200 + (channel << 10) + 4 * slot + 2 * rank, total_mb[channel] >> 6); + } + + info->total_memory_mb = total_mb[0] + total_mb[1]; + + info->interleaved_part_mb = pre_jedec ? 0 : 2 * min (total_mb[0], total_mb[1]); + info->non_interleaved_part_mb = total_mb[0] + total_mb[1] - info->interleaved_part_mb; + channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2; + write_mchbar32 (0x100, channel_0_non_interleaved | (info->non_interleaved_part_mb << 16)); + if (!pre_jedec) + write_mchbar16 (0x104, info->interleaved_part_mb); +} + +static void program_board_delay(struct raminfo *info) +{ + int cas_latency_shift; + int some_delay_ns; + int some_delay_3_half_cycles; + + unsigned channel, i; + int high_multiplier; + int lane_3_delay; + int cas_latency_derived; + + high_multiplier = 0; + some_delay_ns = 200; + some_delay_3_half_cycles = 4; + cas_latency_shift = info->silicon_revision == 0 || info->silicon_revision == 1 ? 1 : 0; + if (info->revision < 8) + { + some_delay_ns = 600; + cas_latency_shift = 0; + } + { + int speed_bit; + speed_bit = ((info->clock_speed_index > 1 || (info->silicon_revision != 2 && info->silicon_revision != 3))) ^ (info->revision >= 0x10); + write_500 (info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e, 3, 1); + write_500 (info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e, 3, 1); + if (info->revision >= 0x10 && info->clock_speed_index <= 1 && (info->silicon_revision == 2 || info->silicon_revision == 3)) + rmw_1d0 (0x116, 5, 2, 4, 1); + } + write_mchbar32 (0x120, (1 << (info->max_slots_used_in_channel + 28)) | 0x188e7f9f); + + write_mchbar8 (0x124, info->board_lane_delay[4] + ((frequency_01 (info) + 999) / 1000)); + write_mchbar16 (0x125, 0x1360); + write_mchbar8 (0x127, 0x40); + if ((info->some_base_frequency >> 4) < frequency_11 (info) / 2) + { + unsigned some_delay_2_half_cycles; + high_multiplier = 1; + some_delay_2_half_cycles = ps_to_halfcycles (info, + ((3 * 900000 / (info->some_base_frequency >> 4)) >> 1) + (halfcycle_ps (info) * lut4041[info->clock_speed_index] >> 6) + + 4 * halfcycle_ps (info) + + 2230); + some_delay_3_half_cycles = min ((some_delay_2_half_cycles + (frequency_11 (info) * 2) * (28 - some_delay_2_half_cycles) / + (frequency_11 (info) * 2 - 4 * (info->some_base_frequency >> 4))) >> 3, 7); + } + if (read_mchbar8 (0x2ca9) & 1) + some_delay_3_half_cycles = 3; + for (channel = 0; channel < NUM_CHANNELS; channel++) + { + write_mchbar32 (0x220 + (channel << 10), read_mchbar32 (0x220 + (channel << 10)) | 0x18001117); + write_mchbar32 (0x224 + (channel << 10), (info->max_slots_used_in_channel - 1) + | ((info->cas_latency + - 5 - info->clock_speed_index) << 21) + | ((info->max_slots_used_in_channel + info->cas_latency - cas_latency_shift - 4) << 16) + | ((info->cas_latency - cas_latency_shift - 4) << 26) + | ((info->cas_latency - info->clock_speed_index + info->max_slots_used_in_channel - 6) << 8)); + write_mchbar32 (0x228 + (channel << 10), info->max_slots_used_in_channel); + write_mchbar8 (0x239 + (channel << 10), 32); + write_mchbar32 (0x248 + (channel << 10), (high_multiplier << 24) | (some_delay_3_half_cycles << 25) | 0x840000); + write_mchbar32 (0x278 + (channel << 10), 0xc362042); + write_mchbar32 (0x27c + (channel << 10), 0x8b000062); + write_mchbar32 (0x24c + (channel << 10), ((!!info->clock_speed_index) << 17) | (((2 + info->clock_speed_index - (!!info->clock_speed_index))) << 12) | 0x10200); + + write_mchbar8 (0x267 + (channel << 10), 0x4); + write_mchbar16 (0x272 + (channel << 10), 0x155); + write_mchbar32 (0x2bc + (channel << 10), + (read_mchbar32 (0x2bc + (channel << 10)) & 0xFF000000) + | 0x707070); + + write_500 (info, channel, + ((!info->populated_ranks[channel][1][1]) + | (!info->populated_ranks[channel][1][0] << 1) + | (!info->populated_ranks[channel][0][1] << 2) + | (!info->populated_ranks[channel][0][0] << 3)), + 0x4c9, 4, 1); + } + + write_mchbar8 (0x2c4, ((1 + (info->clock_speed_index != 0)) << 6) | 0xC); + { + u8 freq_divisor = 2; + if ((info->some_base_frequency >> 4) == frequency_11 (info)) + freq_divisor = 3; + else if ( (info->some_base_frequency >> 3) < 3 * (frequency_11 (info) / 2) ) + freq_divisor = 1; + else + freq_divisor = 2; + write_mchbar32 (0x2c0, (freq_divisor << 11) | 0x6009c400); + } + + if ( info->board_lane_delay[3] <= 10 ) + { + if ( info->board_lane_delay[3] <= 8 ) + lane_3_delay = info->board_lane_delay[3]; + else + lane_3_delay = 10; + } + else + { + lane_3_delay = 12; + } + cas_latency_derived = info->cas_latency - info->clock_speed_index + 2; + if (info->clock_speed_index > 1) + cas_latency_derived++; + for (channel = 0; channel < NUM_CHANNELS; channel++) + { + write_mchbar32 (0x240 + (channel << 10), ((info->clock_speed_index == 0) * 0x11000) | 0x1002100 | ((2 + info->clock_speed_index) << 4) | (info->cas_latency - 3)); + write_500 (info, channel, (info->clock_speed_index << 1) | 1, 0x609, 6, 1); + write_500 (info, channel, info->clock_speed_index + 2 * info->cas_latency - 7, 0x601, 6, 1); + + write_mchbar32 (0x250 + (channel << 10), ((lane_3_delay + info->clock_speed_index + 9) << 6) + | (info->board_lane_delay[7] << 2) | (info->board_lane_delay[4] << 16) | (info->board_lane_delay[1] << 25) | (info->board_lane_delay[1] << 29) | 1); + write_mchbar32 (0x254 + (channel << 10), (info->board_lane_delay[1] >> 3) | ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) | 0x80 | + (info->board_lane_delay[6] << 1) | (info->board_lane_delay[2] << 28) | (cas_latency_derived << 16) | 0x4700000); + write_mchbar32 (0x258 + (channel << 10), ((info->board_lane_delay[5] + info->clock_speed_index + 9) << 12) | ((info->clock_speed_index - info->cas_latency + 12) << 8) + | (info->board_lane_delay[2] << 17) | (info->board_lane_delay[4] << 24) | 0x47); + write_mchbar32 (0x25c + (channel << 10), (info->board_lane_delay[1] << 1) | (info->board_lane_delay[0] << 8) | 0x1DA50000); + write_mchbar8 (0x264 + (channel << 10), 0xff); + write_mchbar8 (0x5f8 + (channel << 10), (cas_latency_shift << 3) | info->use_ecc); + } + + program_modules_memory_map (info, 1); + + write_mchbar16 (0x610, (min (ns_to_cycles (info, some_delay_ns) / 2, 127) << 9) + | (read_mchbar16(0x610) & 0x1C3) | 0x3C); + write_mchbar16 (0x612, read_mchbar16(0x612) | 0x100); + write_mchbar16 (0x214, read_mchbar16 (0x214) | 0x3E00); + for (i = 0; i < 8; i++) + { + pci_mm_write32 (QUICKPATH_BUS, 0, 1, 0x80 + 4 * i, (info->total_memory_mb - 64) | !i | 2); + pci_mm_write32 (QUICKPATH_BUS, 0, 1, 0xc0 + 4 * i, 0); + } +} + +#define ALIGN_DOWN(addr, align) \ + ((addr) & ~((typeof (addr)) align - 1)) +#define ALIGN_UP(addr, align) \ + ((addr + (typeof (addr)) align - 1) & ~((typeof (addr)) align - 1)) + +#define BETTER_MEMORY_MAP 0 + +static void program_total_memory_map(struct raminfo *info) +{ + unsigned int TOM, TOLUD, TOUUD; + unsigned int quickpath_reserved; + unsigned int REMAPbase; + unsigned int uma_base_igd; + unsigned int uma_base_gtt; + int memory_remap; + unsigned int memory_map[8]; + int i; + unsigned int current_limit; + unsigned int tseg_base; + int uma_size_igd = 0, uma_size_gtt = 0; + + memset (memory_map, 0, sizeof (memory_map)); + +#if REAL + if (info->uma_enabled) + { + u16 t = pci_mm_read16 (NORTHBRIDGE, D0F0_GGC); + gav (t); + const int uma_sizes_gtt[16] = { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 }; + /* Igd memory */ + const int uma_sizes_igd[16] = + { + 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352, 256, 512 + }; + + uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF]; + uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF]; + } +#endif + + TOM = info->total_memory_mb; + if (TOM == 4096) + TOM = 4032; + TOUUD = ALIGN_DOWN (TOM - info->memory_reserved_for_heci_mb, 64); + TOLUD = ALIGN_DOWN (min (3072 + + ALIGN_UP(uma_size_igd + uma_size_gtt, 64) + , TOUUD), 64); + memory_remap = 0; + if (TOUUD - TOLUD > 64) + { + memory_remap = 1; + REMAPbase = max (4096, TOUUD); + TOUUD = TOUUD - TOLUD + 4096; + } + if (TOUUD > 4096) + memory_map[2] = TOUUD | 1; + quickpath_reserved = 0; + + { + u32 t; + + gav (t = pci_mm_read32 (QUICKPATH_BUS, 0, 1, 0x68)); + if (t & 0x800) + quickpath_reserved = (1 << find_lowest_bit_set32 (t >> 20)); + } + if (memory_remap) + TOUUD -= quickpath_reserved; + +#if !REAL + if (info->uma_enabled) + { + u16 t = pci_mm_read16 (NORTHBRIDGE, D0F0_GGC); + gav (t); + const int uma_sizes_gtt[16] = { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 }; + /* Igd memory */ + const int uma_sizes_igd[16] = + { + 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352, 256, 512 + }; + + uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF]; + uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF]; + } +#endif + + uma_base_igd = TOLUD - uma_size_igd; + uma_base_gtt = uma_base_igd - uma_size_gtt; + tseg_base = ALIGN_DOWN (uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20); + if (!memory_remap) + tseg_base -= quickpath_reserved; + tseg_base = ALIGN_DOWN (tseg_base, 8); + + pci_mm_write16 (NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4); + pci_mm_write16 (NORTHBRIDGE, D0F0_TOM, TOM >> 6); + if (memory_remap) + { + pci_mm_write16 (NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6); + pci_mm_write16 (NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6); + } + pci_mm_write16 (NORTHBRIDGE, D0F0_TOUUD, TOUUD); + + if (info->uma_enabled) + { + pci_mm_write32 (NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20); + pci_mm_write32 (NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20); + } + pci_mm_write32 (NORTHBRIDGE, TSEG, tseg_base << 20); + + current_limit = 0; + memory_map[0] = ALIGN_DOWN (uma_base_gtt, 64) | 1; + memory_map[1] = 4096; + for (i = 0; i < ARRAY_SIZE (memory_map); i++) + { + current_limit = max (current_limit, memory_map[i] & ~1); + pci_mm_write32 (QUICKPATH_BUS, 0, 1, 4 * i + 0x80, (memory_map[i] & 1) | ALIGN_DOWN (current_limit - 1, 64) | 2); + pci_mm_write32 (QUICKPATH_BUS, 0, 1, 4 * i + 0xc0, 0); + } +} + +static void +collect_system_info (struct raminfo *info) +{ + u32 capid0[3]; + int i; + unsigned channel; + + /* Wait for some bit, maybe TXT clear. */ + while (!(read8(0xfed40000) & (1 << 7))) ; + + if (!info->heci_bar) + gav (info->heci_bar = pci_mm_read32 (HECIDEV, HECIBAR) & 0xFFFFFFF8); + if (!info->memory_reserved_for_heci_mb) + { + /* Wait for ME to be ready */ + intel_early_me_init (); + info->memory_reserved_for_heci_mb = intel_early_me_uma_size (); + } + + for (i = 0; i < 3; i++) + gav (capid0[i] = pci_mm_read32 (NORTHBRIDGE, D0F0_CAPID0 | (i << 2))); + gav (info->revision = pci_mm_read8 (NORTHBRIDGE, PCI_REVISION_ID)); + info->max_supported_clock_speed_index = (~capid0[1] & 7); + + if ((capid0[1] >> 11) & 1) + info->uma_enabled = 0; + else + gav (info->uma_enabled = pci_mm_read8 (NORTHBRIDGE, D0F0_DEVEN) & 8); + /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff*/ + info->silicon_revision = 0; + + if (capid0[2] & 2) + { + info->silicon_revision = 0; + info->max_supported_clock_speed_index = 2; + for (channel = 0; channel < NUM_CHANNELS; channel++) + if (info->populated_ranks[channel][0][0] && (info->spd[channel][0][MODULE_TYPE] & 0xf) == 3) + { + info->silicon_revision = 2; + info->max_supported_clock_speed_index = 1; + } + } + else + { + switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1) ) + { + case 1: + case 2: + info->silicon_revision = 3; + break; + case 3: + info->silicon_revision = 0; + break; + case 0: + info->silicon_revision = 2; + break; + } + switch (pci_mm_read16 (NORTHBRIDGE, PCI_DEVICE_ID)) + { + case 0x40: + info->silicon_revision = 0; + break; + case 0x48: + info->silicon_revision = 1; + break; + } + } +} + +static void +enable_hpet (void) +{ +#if REAL + u32 reg32; + + /* Move HPET to default address 0xfed00000 and enable it */ + reg32 = RCBA32(HPTC); + reg32 |= (1 << 7); // HPET Address Enable + reg32 &= ~(3 << 0); + RCBA32(HPTC) = reg32; +#else + write32 (DEFAULT_RCBA | HPTC, 0x80); +#endif +} + +static void +dump_timings (struct raminfo *info) +{ +#if REAL + int channel, slot, rank, lane, i; + printk (BIOS_DEBUG, "Timings:\n"); + for (channel = 0; channel < NUM_CHANNELS; channel++) + for (slot = 0; slot < NUM_SLOTS; slot++) + for (rank = 0; rank < NUM_RANKS; rank++) + { + if (!info->populated_ranks[channel][slot][rank]) + continue; + printk (BIOS_DEBUG, "channel %d, slot %d, rank %d\n", channel, slot, rank); + for (lane = 0; lane < 9; lane++) + { + printk (BIOS_DEBUG, "lane %d: ", lane); + for (i = 0; i < 4; i++) + { + printk (BIOS_DEBUG, "%x (%x) ", read_500_bypass (info, channel, + get_timing_register_addr (lane, i, slot, rank), 9), + info->training.lane_timings[i][channel][slot][rank][lane]); + } + printk (BIOS_DEBUG, "\n"); + } + } + printk (BIOS_DEBUG, "[178] = %x (%x)\n", read_1d0 (0x178, 7), info->training.reg_178); + printk (BIOS_DEBUG, "[10b] = %x (%x)\n", read_1d0 (0x10b, 6), info->training.reg_10b); +#endif +} + +static void +save_timings (struct raminfo *info) +{ +#if CONFIG_EARLY_CBMEM_INIT + struct ram_training train; + struct mrc_data_container *mrcdata; + int output_len = ALIGN(sizeof (train), 16); + int channel, slot, rank, lane, i; + + memset (&train, 0, sizeof (train)); + for (channel = 0; channel < NUM_CHANNELS; channel++) + for (slot = 0; slot < NUM_SLOTS; slot++) + for (rank = 0; rank < NUM_RANKS; rank++) + if (info->populated_ranks[channel][slot][rank]) + for (lane = 0; lane < 9; lane++) + for (i = 0; i < 4; i++) + train.lane_timings[i][channel][slot][rank][lane] = read_500 (info, channel, + get_timing_register_addr (lane, i, slot, rank), 9); + info->training.reg_178 = read_1d0 (0x178, 7); + info->training.reg_10b = read_1d0 (0x10b, 6); + + /* Save the MRC S3 restore data to cbmem */ + cbmem_initialize(); + mrcdata = cbmem_add + (CBMEM_ID_MRCDATA, + output_len + sizeof(struct mrc_data_container)); + + printk(BIOS_DEBUG, "Relocate MRC DATA from %p to %p (%u bytes)\n", + &train, mrcdata, output_len); + + mrcdata->mrc_signature = MRC_DATA_SIGNATURE; + mrcdata->mrc_data_size = output_len; + mrcdata->reserved = 0; + memcpy(mrcdata->mrc_data, &train, + sizeof (train)); + + /* Zero the unused space in aligned buffer. */ + if (output_len > sizeof (train)) + memset(mrcdata->mrc_data+sizeof (train), 0, + output_len - sizeof (train)); + + mrcdata->mrc_checksum = compute_ip_checksum(mrcdata->mrc_data, + mrcdata->mrc_data_size); +#endif +} + +#if REAL +static const struct ram_training * +get_cached_training (void) +{ + struct mrc_data_container *cont; + cont = find_current_mrc_cache(); + if (!cont) + return 0; + return (void *) cont->mrc_data; +} +#endif + +/* FIXME: add timeout. */ +static void +wait_heci_ready (void) +{ + while (!(read32 (DEFAULT_HECIBAR | 0xc) & 8)); // = 0x8000000c + write32 ((DEFAULT_HECIBAR | 0x4), (read32 (DEFAULT_HECIBAR | 0x4) & ~0x10) | 0xc); +} + +/* FIXME: add timeout. */ +static void +wait_heci_cb_avail (int len) +{ + union + { + struct mei_csr csr; + u32 raw; + } csr; + + while (!(read32 (DEFAULT_HECIBAR | 0xc) & 8)); + + do + csr.raw = read32 (DEFAULT_HECIBAR | 0x4); + while (len > csr.csr.buffer_depth - (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr)); +} + +static void +send_heci_packet (struct mei_header *head, u32 *payload) +{ + int len = (head->length + 3) / 4; + int i; + + wait_heci_cb_avail (len + 1); + + /* FIXME: handle leftovers correctly. */ + write32 (DEFAULT_HECIBAR | 0, *(u32 *)head); + for (i = 0; i < len - 1; i++) + write32 (DEFAULT_HECIBAR | 0, payload[i]); + + write32 (DEFAULT_HECIBAR | 0, payload[i] & ((1 << (8 * len)) - 1)); + write32 (DEFAULT_HECIBAR | 0x4, read32 (DEFAULT_HECIBAR | 0x4) | 0x4); +} + +static void +send_heci_message (u8 *msg, int len, u8 hostaddress, u8 clientaddress) +{ + struct mei_header head; + int maxlen; + + wait_heci_ready (); + maxlen = (read32 (DEFAULT_HECIBAR | 0x4) >> 24) * 4 - 4; + + while (len) + { + int cur = len; + if (cur > maxlen) + { + cur = maxlen; + head.is_complete = 0; + } + else + head.is_complete = 1; + head.length = cur; + head.reserved = 0; + head.client_address = clientaddress; + head.host_address = hostaddress; + send_heci_packet (&head, (u32 *) msg); + len -= cur; + msg += cur; + } +} + +/* FIXME: Add timeout. */ +static int +recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet, u32 *packet_size) +{ + union + { + struct mei_csr csr; + u32 raw; + } csr; + int i = 0; + + write32 (DEFAULT_HECIBAR | 0x4, read32 (DEFAULT_HECIBAR | 0x4) | 2); + do + { + csr.raw = read32 (DEFAULT_HECIBAR | 0xc); +#if !REAL + if (i++ > 347) + return -1; +#endif + } + while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr); + *(u32 *)head = read32 (DEFAULT_HECIBAR | 0x8); + if (!head->length) + { + write32 (DEFAULT_HECIBAR | 0x4, read32 (DEFAULT_HECIBAR | 0x4) | 2); + *packet_size = 0; + return 0; + } + if (head->length + 4 > 4 * csr.csr.buffer_depth || head->length > *packet_size) + { + *packet_size = 0; + return -1; + } + + do + csr.raw = read32 (DEFAULT_HECIBAR | 0xc); + while ((head->length + 3) >> 2 > csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr); + + for (i = 0; i < (head->length + 3) >> 2; i++) + packet[i++] = read32 (DEFAULT_HECIBAR | 0x8); + *packet_size = head->length; + if (!csr.csr.ready) + *packet_size = 0; + write32 (DEFAULT_HECIBAR | 0x4, read32 (DEFAULT_HECIBAR | 0x4) | 4); + return 0; +} + +/* FIXME: Add timeout. */ +static int +recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size) +{ + struct mei_header head; + int current_position; + + current_position = 0; + while (1) + { + u32 current_size; + current_size = *message_size - current_position; + if (recv_heci_packet(info, &head, message + (current_position >> 2), ¤t_size) == -1 ) + break; + if (!current_size) + break; + current_position += current_size; + if (head.is_complete) + { + *message_size = current_position; + return 0; + } + + if (current_position >= *message_size) + break; + } + *message_size = 0; + return -1; +} + +static void +send_heci_uma_message(struct raminfo *info) +{ + struct uma_reply + { + u8 group_id; + u8 command; + u8 reserved; + u8 result; + u8 field2; + u8 unk3[0x48 - 4 - 1]; + }__attribute__ ((packed)) reply; + struct uma_message + { + u8 group_id; + u8 cmd; + u8 reserved; + u8 result; + u32 c2; + u64 heci_uma_addr; + u32 memory_reserved_for_heci_mb; + u16 c3; + } __attribute__ ((packed)) msg = { + 0, MKHI_SET_UMA, 0, 0, + 0x82, + info->heci_uma_addr, + info->memory_reserved_for_heci_mb, + 0 + }; + u32 reply_size; + + send_heci_message ((u8 *) &msg, sizeof (msg), 0, 7); + + reply_size = sizeof (reply); + if (recv_heci_message (info, (u32 *) &reply, &reply_size) == -1) + return; + + if (reply.command == (MKHI_SET_UMA | (1 << 7))) + info->v4086 = reply.field2; + else + die ("HECI init failed\n"); +} + +static void +setup_heci_uma (struct raminfo *info) +{ + u32 reg44; + + /* trouble start */ + reg44 = pci_mm_read32 (HECIDEV, 0x44); // = 0x80010020 + info->memory_reserved_for_heci_mb = 0; + info->heci_uma_addr = 0; + if (!((reg44 & 0x10000) && !(pci_mm_read32 (HECIDEV, 0x40) & 0x20))) + return; + + info->heci_bar = pci_mm_read32 (HECIDEV, 0x10) & 0xFFFFFFF0; + info->memory_reserved_for_heci_mb = reg44 & 0x3f; + info->heci_uma_addr = ((u64)((((u64) pci_mm_read16 (NORTHBRIDGE, D0F0_TOM)) << 6) - info->memory_reserved_for_heci_mb)) << 20; + + pci_mm_read32 (NORTHBRIDGE, DMIBAR); + if (info->memory_reserved_for_heci_mb) + { + write32 (DEFAULT_DMIBAR | 0x14, read32 (DEFAULT_DMIBAR | 0x14) & ~0x80); + write32 (DEFAULT_RCBA | 0x14, read32 (DEFAULT_RCBA | 0x14) & ~0x80); + write32 (DEFAULT_DMIBAR | 0x20, read32 (DEFAULT_DMIBAR | 0x20) & ~0x80); + write32 (DEFAULT_RCBA | 0x20, read32 (DEFAULT_RCBA | 0x20) & ~0x80); + write32 (DEFAULT_DMIBAR | 0x2c, read32 (DEFAULT_DMIBAR | 0x2c) & ~0x80); + write32 (DEFAULT_RCBA | 0x30, read32 (DEFAULT_RCBA | 0x30) & ~0x80); + write32 (DEFAULT_DMIBAR | 0x38, read32 (DEFAULT_DMIBAR | 0x38) & ~0x80); + write32 (DEFAULT_RCBA | 0x40, read32 (DEFAULT_RCBA | 0x40) & ~0x80); + + write32 (DEFAULT_RCBA | 0x40, 0x87000080); // OK + write32 (DEFAULT_DMIBAR | 0x38, 0x87000080); // OK + while (read16 (DEFAULT_RCBA | 0x46) & 2 && read16 (DEFAULT_DMIBAR | 0x3e) & 2); + } + + write_mchbar32 (0x24, 0x10000 + info->memory_reserved_for_heci_mb); + printk (BIOS_ERR, __FILE__ ":%d\n", __LINE__); + + send_heci_uma_message(info); + + pci_mm_write32 (HECIDEV, 0x10, 0x0); + pci_mm_write8 (HECIDEV, 0x4, 0x0); + +} + +#if 1 +static int +have_match_ranks (struct raminfo *info, int channel, int ranks) +{ + int ranks_in_channel; + ranks_in_channel = info->populated_ranks[channel][0][0] + + info->populated_ranks[channel][0][1] + + info->populated_ranks[channel][1][0] + + info->populated_ranks[channel][1][1]; + + /* empty channel */ + if (ranks_in_channel == 0) + return 1; + + if (ranks_in_channel != ranks) + return 0; + /* single slot */ + if (info->populated_ranks[channel][0][0] != info->populated_ranks[channel][1][0]) + return 1; + if (info->populated_ranks[channel][0][1] != info->populated_ranks[channel][1][1]) + return 1; + if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1]) + return 0; + if (info->density[channel][0] != info->density[channel][1]) + return 0; + return 1; +} +#endif + +#define WTF1 1 + +#if REAL +void raminit (const int s3resume) +#else +void raminit (int s3resume) +#endif +{ + unsigned channel, slot, lane, rank; + int i; + + struct raminfo info; + +#ifdef LATER + const dimminfo_t *const dimms = sysinfo->dimms; + const timings_t *const timings = &sysinfo->selected_timings; + const int sff = sysinfo->gfx_type == GMCH_GS45; + + int ch; + u8 reg8; + int i; + + report_platform_info(); +#endif + + gav (0x55); + + outb (0x0, 0x62); + + u16 si; + +#if ! REAL + //Unrecognised: [ffff000:f917] 000b.0012 CPUID: eax: 0000000b; ecx: 00000000 => 00000001.00000002.00000100.00000000 + + //Unrecognised: [ffff000:f927] 000b.0013 CPUID: eax: 0000000b; ecx: 00000001 => 00000004.00000004.00000201.00000000 + + unsigned number_cores; +#if REAL + struct cpuid_result result; + unsigned threads_per_package, threads_per_core; + + /* Logical processors (threads) per core */ + result = cpuid_ext(0xb, 0); + threads_per_core = result.ebx & 0xffff; + + /* Logical processors (threads) per package */ + result = cpuid_ext(0xb, 1); + threads_per_package = result.ebx & 0xffff; + + if (threads_per_package == 0 || threads_per_core == 0 || threads_per_package % threads_per_core) + number_cores = 1; + else + number_cores = threads_per_package / threads_per_core; +#else + number_cores = 2; +#endif + + u8 al = nvram_read (0x4c); + if (number_cores <= 1) + si = 0; + else if (!(al & 1)) + si = 1; + else if (number_cores <= 2) + si = 0; + else if (!(al & 2)) + si = 2; + else + si = 0; + if (!(nvram_read (0x55) & 2)) + si |= 0x100; +#else + /* bit 0 = disable multicore, + bit 1 = disable quadcore, + bit 8 = disable hyperthreading. */ + si = 0; +#endif + + pci_write32 (0xff, 0x0, 0x0, 0x80, + (pci_read32 (0xff, 0x0, 0x0, 0x80) & 0xfffffefc) | 0x10000 | si); + outb (0x1, 0x62); + outb (0x4, 0x62); + pci_write32 (SOUTHBRIDGE, RCBA, DEFAULT_RCBA | 1); + gav (read32 (DEFAULT_RCBA | 0x3410)); + write32 (DEFAULT_RCBA | 0x3410, 0xc61); + gav (read32 (DEFAULT_RCBA | 0x3410)); + pci_write32 (SOUTHBRIDGE, 0x40, 0x400); + pci_write8 (SOUTHBRIDGE, 0x44, 0x80); + + u16 t4041 = read_tco16 (0x8); + gav (t4041); + write_tco16 (0x8, t4041); + pci_write32 (SOUTHBRIDGE, 0xd0, 0x0); + pci_write16 (SOUTHBRIDGE, 0x82, 0x3c01); + + u32 t4046 = pci_read32 (SOUTHBRIDGE, 0xdc); + gav (t4046); + pci_write32 (SOUTHBRIDGE, 0xdc, t4046); + pci_write32 (0xff, 0x0, 0x1, 0x50, DEFAULT_PCIEXBAR | 1); + pci_write32 (SOUTHBRIDGE, RCBA, DEFAULT_RCBA | 1); + gav (read32 (DEFAULT_RCBA | 0x3410)); + write32 (DEFAULT_RCBA | 0x3410, 0xc61); + + pci_write32 (SOUTHBRIDGE, 0x84, 0x7c1601); + pci_write32 (SOUTHBRIDGE, 0x8c, 0x1c1681); + outb (0x2, 0x62); +#if !REAL + + my_write_msr (0x79, 0xffec1410); + //Unrecognised: [ffff000:fc22] 00c0.00c1 Microcode Update: ERROR: Cannot fake write in a post-hook. + + //Unrecognised: [ffff000:fb6a] 00c8.00c9 CPUID: eax: 00000006; ecx: 0000008b => 00000005.00000002.00000001.00000000 +#endif + + rdmsr (0xce); + rdmsr (0x199); + my_write_msr (0x199, 0x15); + rdmsr (0x1a0); + my_write_msr (0x1a0, 0x00850089); + rdmsr (0xce); + rdmsr (0x199); + my_write_msr (0x199, 0x14); + rdmsr (0x1a0); + my_write_msr (0x1a0, 0x00850089); + rdmsr (0x1f1); + my_write_msr (0x1f1, 0x1); + outb (0x5, 0x62); + + /*Unrecognised: [ffff000:fc9f] 00ed.00ee LAPIC: [00000300] <= 000c4500 + + Unrecognised: [ffff000:fc9f] 00ed.00ef LAPIC: [00000300] => 000c0500 + */ + outb (0x3, 0x62); + + outb (0x0, 0x62); + outb (0x2, 0x62); + outb (0x2c, 0x62); + outb (0x12, 0x62); + outb (0x30, 0x62); + /*Unrecognised: addr ff7ff7da val ff7ff856*/ + + outb (0x13, 0x62); + outb (0x28, 0x62); + outb (0x29, 0x62); + outb (0x17, 0x62); + outb (0x27, 0x62); + outb (0x4a, 0x62); + /*Unrecognised: addr ff7ff7da val ff7ff856*/ + + gav (pci_mm_read16 (SOUTHBRIDGE, 0x40)); // = 0x1001 + + outb (0x11, 0x62); + outb (0x40, 0x62); + pci_write32 (NORTHBRIDGE, D0F0_MCHBAR_LO, DEFAULT_MCHBAR | 1); + pci_write32 (0, 0x1f, 0x3, SMB_BASE, SMBUS_IO_BASE); + pci_write32 (0, 0x1f, 0x3, HOSTC, 0x1); + gav (pci_read16 (0, 0x1f, 0x3, 0x4)); // = 0x1 + pci_write16 (0, 0x1f, 0x3, 0x4, 0x1); + pci_write32 (SOUTHBRIDGE, RCBA, DEFAULT_RCBA | 1); + pci_mm_write32 (NORTHBRIDGE, D0F0_MCHBAR_LO, DEFAULT_MCHBAR | 1); + pci_mm_write32 (NORTHBRIDGE, D0F0_DMIBAR_LO, DEFAULT_DMIBAR | 1); + gav (pci_mm_read8 (HECIDEV, PCI_VENDOR_ID)); // = 0x86 + pci_write32 (SOUTHBRIDGE, RCBA, DEFAULT_RCBA | 1); + gav (pci_read32 (SOUTHBRIDGE, 0x40)); // = 0x1001 + pci_write32 (SOUTHBRIDGE, 0x40, 0x1001); + gav (pci_read8 (SOUTHBRIDGE, 0x44)); // = 0x80 + pci_write8 (SOUTHBRIDGE, 0x44, 0x80); + gav (pci_read8 (SOUTHBRIDGE, 0xa6)); // = 0x2 + pci_write8 (SOUTHBRIDGE, 0xa6, 0x2); + gav (pci_read32 (SOUTHBRIDGE, GPIOBASE)); // = DEFAULT_GPIOBASE | 1 + pci_write32 (SOUTHBRIDGE, GPIOBASE, DEFAULT_GPIOBASE | 1); + gav (pci_read8 (SOUTHBRIDGE, 0x4c)); // = 0x10 + pci_write8 (SOUTHBRIDGE, 0x4c, 0x10); +#if !REAL + gav (pci_read8 (SOUTHBRIDGE, 0x8)); // = 0x6 + gav (pci_read8 (SOUTHBRIDGE, 0x8)); // = 0x6 + gav (read32 (DEFAULT_RCBA | 0x3598)); + gav (pci_read32 (0, 0x1d, 0x0, 0xfc)); // = 0x20191708 + pci_write32 (0, 0x1d, 0x0, 0xfc, 0x20191708); + gav (pci_read8 (SOUTHBRIDGE, 0x8)); // = 0x6 + gav (pci_read8 (SOUTHBRIDGE, 0x8)); // = 0x6 + gav (pci_read8 (0, 0x1d, 0x0, 0x88)); // = 0xa0 + pci_write8 (0, 0x1d, 0x0, 0x88, 0xa0); + gav (pci_read32 (0, 0x1a, 0x0, 0xfc)); // = 0x20191708 + pci_write32 (0, 0x1a, 0x0, 0xfc, 0x20191708); + gav (pci_read8 (SOUTHBRIDGE, 0x8)); // = 0x6 + gav (pci_read8 (SOUTHBRIDGE, 0x8)); // = 0x6 + gav (pci_read8 (0, 0x1a, 0x0, 0x88)); // = 0xa0 + pci_write8 (0, 0x1a, 0x0, 0x88, 0xa0); + write8 (DEFAULT_RCBA | 0x14, 0x11); + write16 (DEFAULT_RCBA | 0x50, 0x7654); +#endif + + enable_hpet (); + u32 t4143 = read32 (0xfed00010); + gav (t4143); + write32 (0xfed00010, t4143 | 1); + gav (read8 (DEFAULT_RCBA | 0x3428)); + write8 (DEFAULT_RCBA | 0x3428, 0x1d); + pci_mm_write32 (0, 0x1f, 0x6, 0x40, 0x40000000); + pci_mm_write32 (0, 0x1f, 0x6, 0x44, 0x0); + gav (pci_mm_read32 (0, 0x1f, 0x6, 0x40)); // = 0x40000004 + pci_mm_write32 (0, 0x1f, 0x6, 0x40, 0x40000005); + u16 t4; + t4 = read16 (0x4000001a); + gav (t4); + write16 (0x4000001a, (t4 & ~0xf) | 0x10f0); + gav (pci_mm_read32 (0, 0x1f, 0x6, 0x40)); // = 0x40000005 + pci_mm_write32 (0, 0x1f, 0x6, 0x40, 0x40000004); + pci_mm_write32 (0, 0x1f, 0x6, 0x40, 0x0); + gav (pci_read16 (SOUTHBRIDGE, 0x40)); // = 0x1001 + gav (pci_read16 (SOUTHBRIDGE, GPIOBASE)); // = DEFAULT_GPIOBASE | 1 + gav (read8 (DEFAULT_RCBA | 0x3414)); + gav (read_acpi16 (0x0)); +#if !REAL + u16 pm1cnt; + gav (pm1cnt = read_acpi16 (0x4)); + s3resume = ((pm1cnt >> 10) & 7) == 5; +#endif + if (s3resume) + { + pci_mm_read8 (SOUTHBRIDGE, 0xa2); // = 0xa0 + pci_mm_read8 (SOUTHBRIDGE, 0xa4); // = 0x9 + pci_mm_read8 (SOUTHBRIDGE, 0xa4); // = 0x9 + pci_mm_write8 (SOUTHBRIDGE, 0xa4, 0x9); + } + else + { + gav (pci_mm_read8 (SOUTHBRIDGE, 0xa4)); // = 0x5 + pci_mm_write8 (SOUTHBRIDGE, 0xa4, 0x5); + } + pci_mm_write8 (0, 0x3, 0x0, 0x4, 0x0); + write16 (DEFAULT_RCBA | 0x3124, 0x2321); + pci_mm_write8 (SOUTHBRIDGE, 0xdc, 0x0); + + pci_mm_write32 (SOUTHBRIDGE, RCBA, DEFAULT_RCBA | 1); + gav (pci_mm_read16 (SOUTHBRIDGE, 0x80)); // = 0x10 + pci_mm_write16 (SOUTHBRIDGE, 0x80, 0x10); + pci_mm_write16 (SOUTHBRIDGE, 0x82, 0x3f07); + if (s3resume) + { + read_mchbar32 (0x1e8); + write_mchbar32 (0x1e8, 0x6); + read_mchbar32 (0x1e8); + write_mchbar32 (0x1e8, 0x4); + } + + pci_mm_write16 (SOUTHBRIDGE, GPIOBASE, DEFAULT_GPIOBASE); + pci_mm_read8 (SOUTHBRIDGE, 0x4c); // = 0x10 + pci_mm_write8 (SOUTHBRIDGE, 0x4c, 0x10); + gav (inw (DEFAULT_GPIOBASE | 0x38)); // = 0x10 + + outl (0x1963a5ff, DEFAULT_GPIOBASE); + outl (0xffffffff, DEFAULT_GPIOBASE | 0xc); + outl (0x87bf6aff, DEFAULT_GPIOBASE | 0x4); + outl (0x0, DEFAULT_GPIOBASE | 0x18); + outl (0x120c6, DEFAULT_GPIOBASE | 0x2c); + outl (0x27706fe, DEFAULT_GPIOBASE | 0x30); + outl (0x29fffff, DEFAULT_GPIOBASE | 0x38); + outl (0x1b01f9f4, DEFAULT_GPIOBASE | 0x34); + outl (0x0, DEFAULT_GPIOBASE | 0x40); + outl (0x0, DEFAULT_GPIOBASE | 0x48); + outl (0xf00, DEFAULT_GPIOBASE | 0x44); + pci_mm_write16 (SOUTHBRIDGE, PMBASE, DEFAULT_PMBASE); + gav (pci_mm_read8 (SOUTHBRIDGE, ACPI_CNTL)); // = 0x80 + pci_mm_write8 (SOUTHBRIDGE, ACPI_CNTL, 0x80); + gav (pci_mm_read32 (SOUTHBRIDGE, 0xac)); // = 0x0 + pci_mm_write32 (SOUTHBRIDGE, 0xac, 0x0); + pci_mm_write32 (SOUTHBRIDGE, 0x84, 0xc0681); + + gav (read32 (DEFAULT_RCBA | 0x3400)); + write32 (DEFAULT_RCBA | 0x3400, 0x1c); + gav (read32 (DEFAULT_RCBA | 0x3410)); + write32 (DEFAULT_RCBA | 0x3410, 0xc61); + + gav (read_tco16 (0x8)); + write_tco16 (0x8, 0x800); + write_tco8 (0x6, gav (read_tco8 (0x6)) | 0x2); + gav (inb (0x61)); // = 0x2 + outb (0x3c, 0x61); + enable_hpet (); + pci_mm_read8 (SOUTHBRIDGE, 0xa4); // = 0x5 +#if !REAL + if (!s3resume) + { + nvram_write (0xa, nvram_read (0xa) | 0x70); + nvram_write (0xb, nvram_read (0xb) | 0x80); + nvram_write (0xa, nvram_read (0xa) & ~0x50); + nvram_write (0xb, nvram_read (0xb) & ~0x80); + } +#endif + gav (read32 (DEFAULT_RCBA | 0x3410)); + write32 (DEFAULT_RCBA | 0x3410, 0xc61); + gav (pci_read8 (SOUTHBRIDGE, 0x8)); // = 0x6 + gav (inl (DEFAULT_GPIOBASE)); // = 0x6 + outl (0x7963a5ff, DEFAULT_GPIOBASE); + gav (inl (DEFAULT_GPIOBASE | 0x4)); // = 0x7963a5ff + outl (0x87bf6aff, DEFAULT_GPIOBASE | 0x4); + outl (gav (inl (DEFAULT_GPIOBASE | 0xc)) | 0x40000000, DEFAULT_GPIOBASE | 0xc); + gav (inl (DEFAULT_GPIOBASE | 0x60)); // = 0xfffbfffb + outl (0x41000000, DEFAULT_GPIOBASE | 0x60); + pci_write32 (SOUTHBRIDGE, LPC_GEN3_DEC, 0x1c1681); + pci_write32 (SOUTHBRIDGE, LPC_GEN2_DEC, 0xc15e1); + pci_write32 (SOUTHBRIDGE, LPC_GEN1_DEC, 0x7c1601); + gav (inl (DEFAULT_GPIOBASE | 0xc)); // = 0x7c1601 + outb (0x15, 0x62); + outb (0x16, 0x62); + gav (pci_read32 (NORTHBRIDGE, D0F0_MCHBAR_LO)); // = DEFAULT_MCHBAR | 1 + u8 x2ca8; + + gav (x2ca8 = read_mchbar8 (0x2ca8)); + if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) + { + printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n"); + write_mchbar8 (0x2ca8, 0); + outb (0xe, 0xcf9); +#if REAL + while (1) + { + asm volatile ("hlt"); + } +#else + printf ("CP5\n"); + exit (0); +#endif + } + +#if !REAL + if (!s3resume) + { + u8 t; + gav (t = nvram_read (0x33)); + if (x2ca8 == 0) + { + nvram_write (0x33, t & ~0x40); + gav (read32 (DEFAULT_RCBA | 0x3598)); + write32 (DEFAULT_RCBA | 0x3598, 0x1); + pci_write16 (0, 0x1d, 0x0, 0x20, 0x2000); + gav (pci_read8 (0, 0x1d, 0x0, 0x4)); // = 0xff + pci_write8 (0, 0x1d, 0x0, 0x4, 0xff); + pci_write16 (0, 0x1d, 0x1, 0x20, 0x2020); + gav (pci_read8 (0, 0x1d, 0x1, 0x4)); // = 0xff + pci_write8 (0, 0x1d, 0x1, 0x4, 0xff); + pci_write16 (0, 0x1d, 0x2, 0x20, 0x2040); + gav (pci_read8 (0, 0x1d, 0x2, 0x4)); // = 0xff + pci_write8 (0, 0x1d, 0x2, 0x4, 0xff); + pci_write16 (0, 0x1d, 0x3, 0x20, 0x2060); + gav (pci_read8 (0, 0x1d, 0x3, 0x4)); // = 0xff + pci_write8 (0, 0x1d, 0x3, 0x4, 0xff); + pci_write16 (0, 0x1a, 0x0, 0x20, 0x2080); + gav (pci_read8 (0, 0x1a, 0x0, 0x4)); // = 0xff + pci_write8 (0, 0x1a, 0x0, 0x4, 0xff); + pci_write16 (0, 0x1a, 0x1, 0x20, 0x20a0); + gav (pci_read8 (0, 0x1a, 0x1, 0x4)); // = 0xff + pci_write8 (0, 0x1a, 0x1, 0x4, 0xff); + pci_write16 (0, 0x1a, 0x2, 0x20, 0x20e0); + gav (pci_read8 (0, 0x1a, 0x2, 0x4)); // = 0xff + pci_write8 (0, 0x1a, 0x2, 0x4, 0xff); + for (i = 0; i < 15; i++) + { + gav (inw (0x2010)); // = 0xff + gav (inw (0x2012)); // = 0xff + gav (inw (0x2030)); // = 0xff + gav (inw (0x2032)); // = 0xff + gav (inw (0x2050)); // = 0xff + gav (inw (0x2052)); // = 0xff + gav (inw (0x2070)); // = 0xff + gav (inw (0x2072)); // = 0xff + gav (inw (0x2090)); // = 0xff + gav (inw (0x2092)); // = 0xff + gav (inw (0x20b0)); // = 0xff + gav (inw (0x20b2)); // = 0xff + gav (inw (0x20f0)); // = 0xff + gav (inw (0x20f2)); // = 0xff + if (i != 14) + pm_wait (0x400); /* <10*/ + } + pci_write16 (0, 0x1d, 0x0, 0x20, 0x0); + gav (pci_read8 (0, 0x1d, 0x0, 0x4)); // = 0xff + pci_write8 (0, 0x1d, 0x0, 0x4, 0xfe); + pci_write16 (0, 0x1d, 0x1, 0x20, 0x0); + gav (pci_read8 (0, 0x1d, 0x1, 0x4)); // = 0xff + pci_write8 (0, 0x1d, 0x1, 0x4, 0xfe); + pci_write16 (0, 0x1d, 0x2, 0x20, 0x0); + gav (pci_read8 (0, 0x1d, 0x2, 0x4)); // = 0xff + pci_write8 (0, 0x1d, 0x2, 0x4, 0xfe); + pci_write16 (0, 0x1d, 0x3, 0x20, 0x0); + gav (pci_read8 (0, 0x1d, 0x3, 0x4)); // = 0xff + pci_write8 (0, 0x1d, 0x3, 0x4, 0xfe); + pci_write16 (0, 0x1a, 0x0, 0x20, 0x0); + gav (pci_read8 (0, 0x1a, 0x0, 0x4)); // = 0xff + pci_write8 (0, 0x1a, 0x0, 0x4, 0xfe); + pci_write16 (0, 0x1a, 0x1, 0x20, 0x0); + gav (pci_read8 (0, 0x1a, 0x1, 0x4)); // = 0xff + pci_write8 (0, 0x1a, 0x1, 0x4, 0xfe); + pci_write16 (0, 0x1a, 0x2, 0x20, 0x0); + gav (pci_read8 (0, 0x1a, 0x2, 0x4)); // = 0xff + pci_write8 (0, 0x1a, 0x2, 0x4, 0xfe); + write32 (DEFAULT_RCBA | 0x3598, 0x0); + } + } +#endif + + outb (0x55, 0x62); + +#if REAL + outb (0xb6, 0x43); + outb (0x00, 0x42); + outb (0x05, 0x42); +#endif + + outb (0x32, 0x62); + /*Unrecognised: addr ff7ff7da val ff7ff856*/ + + gav (pci_read32 (0, 0x1f, 0x3, 0x0)); // = 0x3b308086 +#if REAL + gav (pci_read32 (0, 0x1f, 0x3, 0x20)); // = 0x1101 +#endif + pci_write32 (0, 0x1f, 0x3, 0x20, 0x1100); + gav (pci_read8 (0, 0x1f, 0x3, 0x4)); // = 0x1 + pci_write8 (0, 0x1f, 0x3, 0x4, 0x1); + gav (pci_read8 (0, 0x1f, 0x3, 0x40)); // = 0x1 + pci_write8 (0, 0x1f, 0x3, 0x40, 0x9); + gav (pci_read8 (0, 0x1f, 0x3, 0x40)); // = 0x1 + pci_write8 (0, 0x1f, 0x3, 0x40, 0x1); +#if REAL + pci_read32 (0, 0x1f, 0x3, 0x20); // = 0x1101 +#endif + outb (0x4f, 0x62); + outb (0x50, 0x62); + /*Unrecognised: addr ff7ff7da val ff7ff856*/ + + gav (pci_read8 (NORTHBRIDGE, D0F0_CAPID0 + 8)); // = 0x88 + rdmsr (0x17);// !!! + /*Unrecognised: [0000:fffaf715] 1a183.1a184 Microcode Update: ERROR: Cannot fake write in a post-hook.*/ + + rdmsr (0x17);// !!! + /*Unrecognised: [0000:fffaf715] 1a25d.1a25e Microcode Update: ERROR: Cannot fake write in a post-hook.*/ + + outb (0x48, 0x62); + if (x2ca8 != 0) + { + outb (0x42, 0x15ec); + gav (inb (0x15ee)); // = 0x42 + } + +#if REAL + /* Enable SMBUS. */ + enable_smbus(); +#endif + + gav (pci_mm_read16 (SOUTHBRIDGE, GPIOBASE)); // = DEFAULT_GPIOBASE | 1 + u16 t3; + + if (x2ca8 == 0) + { + gav (t3 = inw (DEFAULT_GPIOBASE | 0x38)); + outw (t3 & ~0x400, DEFAULT_GPIOBASE | 0x38); + gav (smbus_read_byte (0x5c, 0x06)); + smbus_write_byte (0x5c, 0x06, 0x8f); + + for (i = 0; i < 5; i++) + pm_wait (0x3e8); + + gav (smbus_read_byte (0x5c, 0x07)); + smbus_write_byte (0x5c, 0x07, 0x8f); + + for (i = 0; i < 5; i++) + pm_wait (0x3e8); + gav (pci_mm_read16 (SOUTHBRIDGE, GPIOBASE)); // = DEFAULT_GPIOBASE | 1 + outw (t3 | 0x400, DEFAULT_GPIOBASE | 0x38); + outb (0x42, 0x15ec); + gav (inb (0x15ee)); // = 0x42 + gav (pci_mm_read16 (SOUTHBRIDGE, GPIOBASE)); // = DEFAULT_GPIOBASE | 1 + } + + gav (t3 = inw (DEFAULT_GPIOBASE | 0x38)); + outw (t3 & ~0x400, DEFAULT_GPIOBASE | 0x38); + + gav (smbus_read_byte (0x57, 0x55)); + gav (pci_mm_read16 (SOUTHBRIDGE, GPIOBASE)); // = DEFAULT_GPIOBASE | 1 + outw (t3 | 0x400, DEFAULT_GPIOBASE | 0x38); + + outb (0x42, 0x62); + gav (read_tco16 (0x6)); +#if !REAL + pci_mm_write32 (NORTHBRIDGE, PCI_SUBSYSTEM_VENDOR_ID, 0x219317aa); + pci_mm_write32 (0, 0x1, 0x0, 0x8c, 0x219417aa); + pci_mm_write32 (0xff, 0, 0, PCI_SUBSYSTEM_VENDOR_ID, 0x219617aa); + pci_mm_write32 (0xff, 0, 1, PCI_SUBSYSTEM_VENDOR_ID, 0x219617aa); + pci_mm_write32 (0xff, 2, 0, PCI_SUBSYSTEM_VENDOR_ID, 0x219617aa); + pci_mm_write32 (0xff, 2, 1, PCI_SUBSYSTEM_VENDOR_ID, 0x219617aa); +#endif + pci_mm_write32 (NORTHBRIDGE, D0F0_MCHBAR_LO, DEFAULT_MCHBAR | 1); + pci_mm_write32 (NORTHBRIDGE, D0F0_MCHBAR_HI, 0x0); + pci_mm_write32 (NORTHBRIDGE, D0F0_DMIBAR_LO, DEFAULT_DMIBAR | 1); + pci_mm_write32 (NORTHBRIDGE, D0F0_DMIBAR_HI, 0x0); + pci_mm_write32 (NORTHBRIDGE, D0F0_EPBAR_LO, DEFAULT_EPBAR | 1); + pci_mm_write32 (NORTHBRIDGE, D0F0_EPBAR_HI, 0x0); + pci_mm_read32 (NORTHBRIDGE, D0F0_MCHBAR_LO); // = DEFAULT_MCHBAR | 1 + pci_mm_read32 (NORTHBRIDGE, D0F0_MCHBAR_HI); // = 0x0 + gav (read8 (DEFAULT_DMIBAR | 0x254)); + write8 (DEFAULT_DMIBAR | 0x254, 0x1); + gav (pci_mm_read32 (SOUTHBRIDGE, 0xec)); // = 0x2b83806 + write16 (DEFAULT_DMIBAR | 0x1b8, 0x18f2); + pci_mm_write16 (NORTHBRIDGE, D0F0_DEVEN, pci_mm_read16 (NORTHBRIDGE, D0F0_DEVEN) & 0xfeff); + read_mchbar16 (0x48); + write_mchbar16 (0x48, 0x2); + rdmsr (0x17); + + pci_mm_read32 (NORTHBRIDGE, D0F0_DMIBAR_LO); // = DEFAULT_DMIBAR | 1 + if (pci_mm_read16 (0, 0x1, 0x0, 0x0) != 0xffff) + { + gav (pci_mm_read16 (0, 0x1, 0x0, 0xac)); + pci_mm_write32 (0, 0x1, 0x0, 0x200, pci_mm_read32 (0, 0x1, 0x0, 0x200) & ~0x100); + pci_mm_write8 (0, 0x1, 0x0, 0x1f8, (pci_mm_read8 (0, 0x1, 0x0, 0x1f8) & ~1) | 4); + u32 t4431 = read32 (DEFAULT_DMIBAR | 0xd68); + gav (t4431); + write32 (DEFAULT_DMIBAR | 0xd68, t4431 | 0x08000000); + pci_mm_write32 (0, 0x1, 0x0, 0x200, pci_mm_read32 (0, 0x1, 0x0, 0x200) & ~0x00200000); + gav (pci_mm_read8 (0, 0x1, 0x0, 0xd60)); // = 0x0 + gav (pci_mm_read8 (0, 0x1, 0x0, 0xd60)); // = 0x0 + pci_mm_write8 (0, 0x1, 0x0, 0xd60, 0x3); + gav (pci_mm_read16 (0, 0x1, 0x0, 0xda8)); // = 0xbf9 + gav (pci_mm_read16 (0, 0x1, 0x0, 0xda8)); // = 0xbf9 + pci_mm_write16 (0, 0x1, 0x0, 0xda8, 0xf9); + pci_mm_read16 (0, 0x1, 0x0, 0xda8); // = 0xf9 + pci_mm_read16 (0, 0x1, 0x0, 0xda8); // = 0xf9 + pci_mm_write16 (0, 0x1, 0x0, 0xda8, 0x79); + pci_mm_read8 (0, 0x1, 0x0, 0xd0); // = 0x2 + pci_mm_read8 (0, 0x1, 0x0, 0xd0); // = 0x2 + pci_mm_write8 (0, 0x1, 0x0, 0xd0, 0x1); + pci_mm_read16 (0, 0x1, 0x0, 0x224); // = 0xd + pci_mm_read32 (NORTHBRIDGE, D0F0_CAPID0); // = 0x10c0009 + pci_mm_read32 (NORTHBRIDGE, D0F0_CAPID0 + 4); // = 0x316126 + pci_mm_read16 (0, 0x1, 0x0, 0x224); // = 0xd + pci_mm_write16 (0, 0x1, 0x0, 0x224, 0x1d); + pci_mm_read16 (0, 0x6, 0x0, 0x0); // = 0xffff + pci_mm_read16 (0, 0x1, 0x0, 0x224); // = 0x1d + pci_mm_read16 (0, 0x6, 0x0, 0x0); // = 0xffff + pci_mm_write16 (0, 0x1, 0x0, 0xac, 0x4d01); + pci_mm_read16 (0, 0x1, 0x0, 0x224); // = 0x1d + pci_mm_read8 (0, 0x1, 0x0, 0xba); // = 0x0 + pci_mm_read16 (0, 0x1, 0x0, 0x0); // = 0x8086 + pci_mm_read32 (0, 0x1, 0x0, 0xc00); // = 0xffffffff + pci_mm_write32 (0, 0x1, 0x0, 0xc00, 0xffffc0fc); + pci_mm_read32 (0, 0x1, 0x0, 0xc04); // = 0x9600000f + pci_mm_write32 (0, 0x1, 0x0, 0xc04, 0x96000000); + pci_mm_read32 (0, 0x1, 0x0, 0xc04); // = 0x96000000 + pci_mm_write32 (0, 0x1, 0x0, 0xc04, 0x16000000); + pci_mm_write32 (0, 0x1, 0x0, 0xc08, 0x0); + } + else + pci_mm_read16 (0, 0x1, 0x0, 0x0); // = 0xffff + + pci_mm_read32 (NORTHBRIDGE, D0F0_DMIBAR_LO); // = DEFAULT_DMIBAR | 1 + pci_mm_read16 (0, 0x6, 0x0, 0x0); // = 0xffff + pci_mm_read16 (0, 0x6, 0x0, 0x0); // = 0xffff + pci_mm_write32 (HECIDEV, HECIBAR, DEFAULT_HECIBAR); + pci_mm_write32 (HECIDEV, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + + outl ((gav (inl (DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000, DEFAULT_GPIOBASE | 0x38); + gav (inb (DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e + +#if !REAL + pci_mm_write32 (0, 0x2, 0x0, PCI_SUBSYSTEM_VENDOR_ID, 0x215a17aa); +#endif + pci_mm_write8 (NORTHBRIDGE, D0F0_DEVEN, pci_mm_read8 (NORTHBRIDGE, D0F0_DEVEN) | 2); + pci_mm_write16 (0, 0x1, 0x0, 0x224, pci_mm_read16 (0, 0x1, 0x0, 0x224) | 1); + pci_mm_write16 (NORTHBRIDGE, D0F0_GGC, pci_mm_read16 (NORTHBRIDGE, D0F0_GGC) | 2); + pci_mm_read32 (NORTHBRIDGE, D0F0_MCHBAR_LO); // = DEFAULT_MCHBAR | 1 + pci_mm_read32 (NORTHBRIDGE, D0F0_MCHBAR_HI); // = 0x0 + pci_mm_read32 (NORTHBRIDGE, D0F0_DMIBAR_LO); // = DEFAULT_DMIBAR | 1 + pci_mm_read32 (NORTHBRIDGE, D0F0_DMIBAR_HI); // = 0x0 + + const struct { int dev, func; } bridges[] = { {0x1e, 0}, {0x1c, 0}, {0x1c, 1}, {0x1c, 2}, {0x1c, 3}, {0x1c, 4}, {0x1c, 5}, {0x1c, 6}, {0x1c, 7} }; + for (i = 0; i < sizeof (bridges) / sizeof (bridges[0]); i++) + { + u16 dev; + pci_mm_write32 (0, bridges[i].dev, bridges[i].func, 0x18, 0x20200); + for (dev = 0; dev < 0x20; dev++) + { + u16 vendor = pci_mm_read16 (2, dev, 0x0, 0x0); + if (vendor == 0xffff) + continue; + pci_mm_read16 (2, dev, 0x0, 0xa); + } + pci_mm_write32 (0, bridges[i].dev, bridges[i].func, 0x18, 0x0); + } + + pci_mm_read16 (0, 0x1, 0x0, 0x0); // = 0x8086 + pci_mm_read8 (NORTHBRIDGE, D0F0_CAPID0 + 6); // = 0x31 + pci_mm_read8 (0, 0x1, 0x0, 0xba); // = 0x0 + pci_mm_read16 (0, 0x6, 0x0, 0x0); // = 0xffff + pci_mm_read8 (NORTHBRIDGE, D0F0_CAPID0 + 6); // = 0x31 + pci_mm_read8 (0, 0x6, 0x0, 0xba); // = 0xff + pci_mm_read16 (0, 0x1, 0x0, 0x11a); // = 0x2 + pci_mm_read16 (0, 0x6, 0x0, 0x11a); // = 0xffff + pci_mm_read16 (0, 0x1, 0x0, 0x0); // = 0x8086 + pci_mm_read32 (0, 0x1, 0x0, 0x18); // = 0x0 + pci_mm_write32 (0, 0x1, 0x0, 0x18, 0x0); + pci_mm_read16 (0, 0x6, 0x0, 0x0); // = 0xffff + write_mchbar16 (0x1170, 0xa880); + write_mchbar8 (0x11c1, 0x1); + write_mchbar16 (0x1170, 0xb880); + read_mchbar8 (0x1210); + write_mchbar8 (0x1210, 0x84); + pci_mm_read8 (NORTHBRIDGE, D0F0_GGC); // = 0x52 + pci_mm_write8 (NORTHBRIDGE, D0F0_GGC, 0x2); + pci_mm_read8 (NORTHBRIDGE, D0F0_GGC); // = 0x2 + pci_mm_write8 (NORTHBRIDGE, D0F0_GGC, 0x52); + pci_mm_read16 (NORTHBRIDGE, D0F0_GGC); // = 0xb52 + + pci_mm_write16 (NORTHBRIDGE, D0F0_GGC, 0xb52); + u16 deven; + deven = pci_mm_read16 (NORTHBRIDGE, D0F0_DEVEN); // = 0x3 + + if (deven & 8) + { + write_mchbar8 (0x2c30, 0x20); + pci_mm_read8 (0, 0x0, 0x0, 0x8); // = 0x18 + write_mchbar16 (0x2c30, read_mchbar16 (0x2c30) | 0x200); + write_mchbar16 (0x2c32, 0x434); + read_mchbar32 (0x2c44); + write_mchbar32 (0x2c44, 0x1053687); + pci_mm_read8 (0, 0x2, 0x0, 0x62); // = 0x2 + pci_mm_write8 (0, 0x2, 0x0, 0x62, 0x2); + read8 (DEFAULT_RCBA | 0x2318); + write8 (DEFAULT_RCBA | 0x2318, 0x47); + read8 (DEFAULT_RCBA | 0x2320); + write8 (DEFAULT_RCBA | 0x2320, 0xfc); + } + + read_mchbar32 (0x30); + write_mchbar32 (0x30, 0x40); + pci_mm_read8 (SOUTHBRIDGE, 0x8); // = 0x6 + pci_mm_read16 (NORTHBRIDGE, D0F0_GGC); // = 0xb52 + pci_mm_write16 (NORTHBRIDGE, D0F0_GGC, 0xb50); + gav (read32 (DEFAULT_RCBA | 0x3428)); + write32 (DEFAULT_RCBA | 0x3428, 0x1d); +#if !REAL + for (i = 0x10; i < 0x28; ) + { + u32 s; + pci_mm_read32 (0, 0x2, 0x0, i); // = 0xffffffff + pci_mm_read32 (0, 0x2, 0x0, i); // = 0xffffffff + pci_mm_write32 (0, 0x2, 0x0, i, 0x0); + pci_mm_read32 (0, 0x2, 0x0, i); // = 0xffffffff + pci_mm_write32 (0, 0x2, 0x0, i, 0xffffffff); + s = pci_mm_read32 (0, 0x2, 0x0, i); + if (s != 0xffffffff && s != 0) + { + if (s & 1) + { + pci_mm_write32 (0, 0x2, 0x0, i, s & 0x7); + i += 4; + } + else + { + pci_mm_read32 (0, 0x2, 0x0, i); // = 0xffffffff + pci_mm_write32 (0, 0x2, 0x0, i, s & 0xf); + i += 8; + } + } + else + i += 4; + } +#endif + + outb ((gav (inb (DEFAULT_GPIOBASE | 0x3a)) & ~0x2) | 0x20, + DEFAULT_GPIOBASE | 0x3a); + outb (0x50, 0x15ec); + outb (inb (0x15ee) & 0x70, 0x15ee); +#if !REAL + pci_mm_read8 (0, 0x1d, 0x0, 0x80); // = 0x0 + pci_mm_write8 (0, 0x1d, 0x0, 0x80, 0x1); + pci_mm_read8 (0, 0x1a, 0x0, 0x80); // = 0x0 + pci_mm_write8 (0, 0x1a, 0x0, 0x80, 0x1); + pci_mm_write32 (HECIDEV, PCI_SUBSYSTEM_VENDOR_ID, 0x215f17aa); + pci_mm_write32 (0, 0x16, 0x2, PCI_SUBSYSTEM_VENDOR_ID, 0x216117aa); + pci_mm_write32 (0, 0x16, 0x3, PCI_SUBSYSTEM_VENDOR_ID, 0x216217aa); + pci_mm_write32 (0, 0x1a, 0x0, PCI_SUBSYSTEM_VENDOR_ID, 0x216317aa); + pci_mm_write32 (0, 0x1b, 0x0, PCI_SUBSYSTEM_VENDOR_ID, 0x215e17aa); + pci_mm_write32 (0, 0x1c, 0x0, 0x94, 0x216417aa); + pci_mm_write32 (0, 0x1c, 0x1, 0x94, 0x216417aa); + pci_mm_write32 (0, 0x1c, 0x2, 0x94, 0x216417aa); + pci_mm_write32 (0, 0x1c, 0x3, 0x94, 0x216417aa); + pci_mm_write32 (0, 0x1c, 0x4, 0x94, 0x216417aa); + pci_mm_write32 (0, 0x1d, 0x0, PCI_SUBSYSTEM_VENDOR_ID, 0x216317aa); + pci_mm_write32 (0, 0x1e, 0x0, 0x54, 0x216517aa); + pci_mm_write32 (SOUTHBRIDGE, PCI_SUBSYSTEM_VENDOR_ID, 0x216617aa); + pci_mm_write32 (0, 0x1f, 0x3, PCI_SUBSYSTEM_VENDOR_ID, 0x216717aa); + pci_mm_write32 (0, 0x1f, 0x5, PCI_SUBSYSTEM_VENDOR_ID, 0x216a17aa); + pci_mm_write32 (0, 0x1f, 0x6, PCI_SUBSYSTEM_VENDOR_ID, 0x219017aa); + pci_mm_read8 (0, 0x1d, 0x0, 0x80); // = 0x1 + pci_mm_write8 (0, 0x1d, 0x0, 0x80, 0x0); + pci_mm_read8 (0, 0x1a, 0x0, 0x80); // = 0x1 + pci_mm_write8 (0, 0x1a, 0x0, 0x80, 0x0); + pci_mm_write32 (13, 0x0, 0x0, PCI_SUBSYSTEM_VENDOR_ID, 0x213317aa); + pci_mm_write32 (13, 0x0, 0x1, PCI_SUBSYSTEM_VENDOR_ID, 0x213417aa); + pci_mm_write32 (13, 0x0, 0x3, PCI_SUBSYSTEM_VENDOR_ID, 0x213617aa); +#endif + + pci_mm_write32 (HECIDEV, HECIBAR, DEFAULT_HECIBAR); + pci_mm_write32 (HECIDEV, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + write_acpi16 (0x2, 0x0); + write_acpi32 (0x28, 0x0); + write_acpi32 (0x2c, 0x0); + if (!s3resume) + { + gav (read_acpi32 (0x4)); + gav (read_acpi32 (0x20)); + gav (read_acpi32 (0x34)); + write_acpi16 (0x0, 0x900); + write_acpi32 (0x20, 0xffff7ffe); + write_acpi32 (0x34, 0x56974); + pci_mm_read8 (SOUTHBRIDGE, 0xa4); // = 0x5 + pci_mm_write8 (SOUTHBRIDGE, 0xa4, 0x7); + } + gav (read32 (DEFAULT_RCBA | 0x3410)); + +#if !REAL + if (gav (read32 (DEFAULT_RCBA | 0x3804)) & 0x4000) + { + u32 v; + + write8 (DEFAULT_RCBA | 0x3894, 0x6); + write8 (DEFAULT_RCBA | 0x3895, 0x50); + write8 (DEFAULT_RCBA | 0x3896, 0x3b); + write8 (DEFAULT_RCBA | 0x3897, 0x14); + write8 (DEFAULT_RCBA | 0x3898, 0x2); + write8 (DEFAULT_RCBA | 0x3899, 0x3); + write8 (DEFAULT_RCBA | 0x389a, 0x20); + write8 (DEFAULT_RCBA | 0x389b, 0x5); + write8 (DEFAULT_RCBA | 0x389c, 0x9f); + write8 (DEFAULT_RCBA | 0x389d, 0x20); + write8 (DEFAULT_RCBA | 0x389e, 0x1); + write8 (DEFAULT_RCBA | 0x389f, 0x6); + write8 (DEFAULT_RCBA | 0x3890, 0xc); + gav (read8 (DEFAULT_RCBA | 0x3890)); + write32 (DEFAULT_RCBA | 0x3808, 0x0); + gav (read32 (DEFAULT_RCBA | 0x3808)); + write16 (DEFAULT_RCBA | 0x3891, 0x4242); + gav (read16 (DEFAULT_RCBA | 0x3891)); + gav (read8 (DEFAULT_RCBA | 0x3890)); + write8 (DEFAULT_RCBA | 0x3890, 0xc); + gav (read8 (DEFAULT_RCBA | 0x3890)); + if ((gav (read32 (DEFAULT_RCBA | 0x3810)) & 0x20) || WTF1) + v = 0x2005; + else + v = 0x2015; + write32 (DEFAULT_RCBA | 0x38c8, v); + write32 (DEFAULT_RCBA | 0x38c4, 0x800000 | v); + gav (read32 (DEFAULT_RCBA | 0x38b0)); + write32 (DEFAULT_RCBA | 0x38b0, 0x1000); + gav (read32 (DEFAULT_RCBA | 0x38b4)); + gav (read32 (DEFAULT_RCBA | 0x38b0)); + write32 (DEFAULT_RCBA | 0x38b0, 0x4); + gav (read32 (DEFAULT_RCBA | 0x38b4)); + write32 (DEFAULT_RCBA | 0x3874, 0x1fff07d0); + } +#endif + gav (inb (DEFAULT_GPIOBASE | 0xe)); // = 0x1fff07d0 + +#if REAL + /* Enable SMBUS. */ + enable_smbus(); +#endif + + { + u8 block[5]; + u16 fsbfreq = 62879; + smbus_block_read (0x69, 0, 5, block); + block[0] = fsbfreq; + block[1] = fsbfreq >> 8; + + smbus_block_write (0x69, 0, 5, block); + } + + outb (0x44, 0x62); + outb (0x3c, 0x62); +#if !REAL + nvram_read (0x71); +#endif + rdmsr (0xfe); + rdmsr (0x201); + rdmsr (0x203); + rdmsr (0x205); + rdmsr (0x207); + gav (read32 (DEFAULT_RCBA | 0x3410)); + write32 (DEFAULT_RCBA | 0x3410, 0xc61); + gav (read8 (0xfed40000)); + pci_mm_read32 (0xff, 0, 0, 0x88); + read_mchbar32 (0x28); + gav (read8 (0xfed30008)); + + memset (&info, 0x5a, sizeof (info)); + + info.last_500_command[0] = 0; + info.last_500_command[1] = 0; + + info.some_base_frequency = 0x10e0; + info.board_lane_delay[0] = 0x14; + info.board_lane_delay[1] = 0x07; + info.board_lane_delay[2] = 0x07; + info.board_lane_delay[3] = 0x08; + info.board_lane_delay[4] = 0x56; + info.board_lane_delay[5] = 0x04; + info.board_lane_delay[6] = 0x04; + info.board_lane_delay[7] = 0x05; + info.board_lane_delay[8] = 0x10; + + info.training.reg_178 = 0; + info.training.reg_10b = 0; + + info.heci_bar = 0; + info.memory_reserved_for_heci_mb = 0; + if (!s3resume || REAL) + { + pci_mm_read8 (SOUTHBRIDGE, 0xa2); // = 0x80 + + collect_system_info (&info); + +#if REAL + /* Enable SMBUS. */ + enable_smbus(); +#endif + + memset (&info.populated_ranks, 0, sizeof (info.populated_ranks)); + + gav (0x55); + + info.use_ecc = 1; + for (channel = 0; channel < NUM_CHANNELS; channel++) + for (slot = 0; slot < NUM_CHANNELS; slot++) + { + int v; + int try; + int addr; + const u8 useful_addresses[] = + { + DEVICE_TYPE, + MODULE_TYPE, + DENSITY, + RANKS_AND_DQ, + MEMORY_BUS_WIDTH, + TIMEBASE_DIVIDEND, + TIMEBASE_DIVISOR, + CYCLETIME, + CAS_LATENCIES_LSB, + CAS_LATENCIES_MSB, + CAS_LATENCY_TIME, + 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + THERMAL_AND_REFRESH, + 0x20, + REFERENCE_RAW_CARD_USED, + RANK1_ADDRESS_MAPPING, + 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, + 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95 + }; + if (slot) + continue; + for (try = 0; try < 5; try++) + { + v = smbus_read_byte (0x50 + channel, DEVICE_TYPE); + if (v >= 0) + break; + } + if (v < 0) + continue; + for (addr = 0; addr < sizeof (useful_addresses) / sizeof (useful_addresses[0]); addr++) + gav (info.spd[channel][0][useful_addresses[addr]] = smbus_read_byte (0x50 + channel, useful_addresses[addr])); + if (info.spd[channel][0][DEVICE_TYPE] != 11 ) + die ("Only DDR3 is supported"); + + v = info.spd[channel][0][RANKS_AND_DQ]; + info.populated_ranks[channel][0][0] = 1; + info.populated_ranks[channel][0][1] = ((v >> 3) & 7); + if (((v >> 3) & 7) > 1) + die ("At most 2 ranks are supported"); + if ((v & 7) == 0 || (v & 7) > 2) + die ("Only x8 and x16 modules are supported"); + if ((info.spd[channel][slot][MODULE_TYPE] & 0xF) != 2 + && (info.spd[channel][slot][MODULE_TYPE] & 0xF) != 3) + die ("Registered memory is not supported"); + info.is_x16_module[channel][0] = (v & 7) - 1; + info.density[channel][slot] = info.spd[channel][slot][DENSITY] & 0xF; + if (!(info.spd[channel][slot][MEMORY_BUS_WIDTH] & 0x18)) + info.use_ecc = 0; + } + + gav (0x55); + + for (channel = 0; channel < NUM_CHANNELS; channel++) + { + int v = 0; + for (slot = 0; slot < NUM_SLOTS; slot++) + for (rank = 0; rank < NUM_RANKS; rank++) + v |= info.populated_ranks[channel][slot][rank] << (2 * slot + rank); + info.populated_ranks_mask[channel] = v; + } + + gav (0x55); + + gav (pci_mm_read32 (NORTHBRIDGE, D0F0_CAPID0 + 4)); + } + else + { + memset (info.populated_ranks, 0, sizeof (info.populated_ranks)); +#if 0 + info.populated_ranks[0][0][0] = 1; + info.populated_ranks[0][0][1] = 1; + info.populated_ranks_mask[0] = 3; + info.populated_ranks_mask[1] = 0; + info.use_ecc = 0; + info.max_slots_used_in_channel = 1; + + info.spd[0][0][0x02] = 0x0b; + info.spd[0][0][0x03] = 0x03; + info.spd[0][0][0x04] = 0x03; + info.spd[0][0][0x07] = 0x09; + info.spd[0][0][0x08] = 0x03; + info.spd[0][0][0x0a] = 0x01; + info.spd[0][0][0x0b] = 0x08; + info.spd[0][0][0x0c] = 0x0c; + info.spd[0][0][0x0e] = 0x3e; + info.spd[0][0][0x0f] = 0x00; + info.spd[0][0][0x10] = 0x69; + info.spd[0][0][0x11] = 0x78; + info.spd[0][0][0x12] = 0x69; + info.spd[0][0][0x13] = 0x30; + info.spd[0][0][0x14] = 0x69; + info.spd[0][0][0x15] = 0x11; + info.spd[0][0][0x16] = 0x20; + info.spd[0][0][0x17] = 0x89; + info.spd[0][0][0x18] = 0x00; + info.spd[0][0][0x19] = 0x05; + info.spd[0][0][0x1a] = 0x3c; + info.spd[0][0][0x1b] = 0x3c; + info.spd[0][0][0x1c] = 0x00; + info.spd[0][0][0x1d] = 0xf0; + info.spd[0][0][0x1f] = 0x05; + info.spd[0][0][0x20] = 0x00; + info.spd[0][0][0x3e] = 0x05; + info.spd[0][0][0x3f] = 0x00; + info.spd[0][0][0x75] = 0x80; + info.spd[0][0][0x76] = 0xad; + info.spd[0][0][0x77] = 0x01; + info.spd[0][0][0x78] = 0x10; + info.spd[0][0][0x79] = 0x52; + info.spd[0][0][0x7a] = 0x26; + info.spd[0][0][0x7b] = 0x50; + info.spd[0][0][0x7c] = 0xf4; + info.spd[0][0][0x7d] = 0x7d; + info.spd[0][0][0x7e] = 0xb0; + info.spd[0][0][0x7f] = 0xcf; + info.spd[0][0][0x80] = 0x48; + info.spd[0][0][0x81] = 0x4d; + info.spd[0][0][0x82] = 0x54; + info.spd[0][0][0x83] = 0x33; + info.spd[0][0][0x84] = 0x35; + info.spd[0][0][0x85] = 0x31; + info.spd[0][0][0x86] = 0x53; + info.spd[0][0][0x87] = 0x36; + info.spd[0][0][0x88] = 0x42; + info.spd[0][0][0x89] = 0x46; + info.spd[0][0][0x8a] = 0x52; + info.spd[0][0][0x8b] = 0x38; + info.spd[0][0][0x8c] = 0x43; + info.spd[0][0][0x8d] = 0x2d; + info.spd[0][0][0x8e] = 0x48; + info.spd[0][0][0x8f] = 0x39; + info.spd[0][0][0x90] = 0x20; + info.spd[0][0][0x91] = 0x20; + info.spd[0][0][0x92] = 0x4e; + info.spd[0][0][0x93] = 0x30; + info.spd[0][0][0x94] = 0x80; + info.spd[0][0][0x95] = 0xad; +#else + info.populated_ranks[0][0][0] = 1; + info.populated_ranks[0][0][1] = 1; + info.populated_ranks[1][0][0] = 1; + info.populated_ranks[1][0][1] = 1; + info.populated_ranks_mask[0] = 3; + info.populated_ranks_mask[1] = 3; + info.use_ecc = 0; + info.max_slots_used_in_channel = 1; + + info.spd[0][0][0x02] = 0x0b; + info.spd[0][0][0x03] = 0x03; + info.spd[0][0][0x04] = 0x03; + info.spd[0][0][0x07] = 0x09; + info.spd[0][0][0x08] = 0x03; + info.spd[0][0][0x0a] = 0x01; + info.spd[0][0][0x0b] = 0x08; + info.spd[0][0][0x0c] = 0x0c; + info.spd[0][0][0x0e] = 0x3e; + info.spd[0][0][0x0f] = 0x00; + info.spd[0][0][0x10] = 0x69; + info.spd[0][0][0x11] = 0x78; + info.spd[0][0][0x12] = 0x69; + info.spd[0][0][0x13] = 0x30; + info.spd[0][0][0x14] = 0x69; + info.spd[0][0][0x15] = 0x11; + info.spd[0][0][0x16] = 0x20; + info.spd[0][0][0x17] = 0x89; + info.spd[0][0][0x18] = 0x00; + info.spd[0][0][0x19] = 0x05; + info.spd[0][0][0x1a] = 0x3c; + info.spd[0][0][0x1b] = 0x3c; + info.spd[0][0][0x1c] = 0x00; + info.spd[0][0][0x1d] = 0xf0; + info.spd[0][0][0x1f] = 0x05; + info.spd[0][0][0x20] = 0x00; + info.spd[0][0][0x3e] = 0x05; + info.spd[0][0][0x3f] = 0x00; + info.spd[0][0][0x75] = 0x80; + info.spd[0][0][0x76] = 0xad; + info.spd[0][0][0x77] = 0x01; + info.spd[0][0][0x78] = 0x10; + info.spd[0][0][0x79] = 0x52; + info.spd[0][0][0x7a] = 0x26; + info.spd[0][0][0x7b] = 0x50; + info.spd[0][0][0x7c] = 0xf4; + info.spd[0][0][0x7d] = 0x7d; + info.spd[0][0][0x7e] = 0xb0; + info.spd[0][0][0x7f] = 0xcf; + info.spd[0][0][0x80] = 0x48; + info.spd[0][0][0x81] = 0x4d; + info.spd[0][0][0x82] = 0x54; + info.spd[0][0][0x83] = 0x33; + info.spd[0][0][0x84] = 0x35; + info.spd[0][0][0x85] = 0x31; + info.spd[0][0][0x86] = 0x53; + info.spd[0][0][0x87] = 0x36; + info.spd[0][0][0x88] = 0x42; + info.spd[0][0][0x89] = 0x46; + info.spd[0][0][0x8a] = 0x52; + info.spd[0][0][0x8b] = 0x38; + info.spd[0][0][0x8c] = 0x43; + info.spd[0][0][0x8d] = 0x2d; + info.spd[0][0][0x8e] = 0x48; + info.spd[0][0][0x8f] = 0x39; + info.spd[0][0][0x90] = 0x20; + info.spd[0][0][0x91] = 0x20; + info.spd[0][0][0x92] = 0x4e; + info.spd[0][0][0x93] = 0x30; + info.spd[0][0][0x94] = 0x80; + info.spd[0][0][0x95] = 0xad; + + info.spd[1][0][0x02] = 0x0b; + info.spd[1][0][0x03] = 0x03; + info.spd[1][0][0x04] = 0x03; + info.spd[1][0][0x07] = 0x09; + info.spd[1][0][0x08] = 0x03; + info.spd[1][0][0x0a] = 0x01; + info.spd[1][0][0x0b] = 0x08; + info.spd[1][0][0x0c] = 0x0c; + info.spd[1][0][0x0e] = 0x3e; + info.spd[1][0][0x0f] = 0x00; + info.spd[1][0][0x10] = 0x69; + info.spd[1][0][0x11] = 0x78; + info.spd[1][0][0x12] = 0x69; + info.spd[1][0][0x13] = 0x30; + info.spd[1][0][0x14] = 0x69; + info.spd[1][0][0x15] = 0x11; + info.spd[1][0][0x16] = 0x20; + info.spd[1][0][0x17] = 0x89; + info.spd[1][0][0x18] = 0x00; + info.spd[1][0][0x19] = 0x05; + info.spd[1][0][0x1a] = 0x3c; + info.spd[1][0][0x1b] = 0x3c; + info.spd[1][0][0x1c] = 0x00; + info.spd[1][0][0x1d] = 0xf0; + info.spd[1][0][0x1f] = 0x05; + info.spd[1][0][0x20] = 0x00; + info.spd[1][0][0x3e] = 0x05; + info.spd[1][0][0x3f] = 0x00; + info.spd[1][0][0x75] = 0x80; + info.spd[1][0][0x76] = 0xad; + info.spd[1][0][0x77] = 0x01; + info.spd[1][0][0x78] = 0x10; + info.spd[1][0][0x79] = 0x52; + info.spd[1][0][0x7a] = 0x26; + info.spd[1][0][0x7b] = 0x50; + info.spd[1][0][0x7c] = 0xf4; + info.spd[1][0][0x7d] = 0x7d; + info.spd[1][0][0x7e] = 0xb0; + info.spd[1][0][0x7f] = 0xcf; + info.spd[1][0][0x80] = 0x48; + info.spd[1][0][0x81] = 0x4d; + info.spd[1][0][0x82] = 0x54; + info.spd[1][0][0x83] = 0x33; + info.spd[1][0][0x84] = 0x35; + info.spd[1][0][0x85] = 0x31; + info.spd[1][0][0x86] = 0x53; + info.spd[1][0][0x87] = 0x36; + info.spd[1][0][0x88] = 0x42; + info.spd[1][0][0x89] = 0x46; + info.spd[1][0][0x8a] = 0x52; + info.spd[1][0][0x8b] = 0x38; + info.spd[1][0][0x8c] = 0x43; + info.spd[1][0][0x8d] = 0x2d; + info.spd[1][0][0x8e] = 0x48; + info.spd[1][0][0x8f] = 0x39; + info.spd[1][0][0x90] = 0x20; + info.spd[1][0][0x91] = 0x20; + info.spd[1][0][0x92] = 0x4e; + info.spd[1][0][0x93] = 0x30; + info.spd[1][0][0x94] = 0x80; + info.spd[1][0][0x95] = 0xad; + +#endif + + info.is_x16_module[0][0] = (info.spd[0][0][RANKS_AND_DQ] & 7) - 1; + info.density[0][0] = info.spd[0][0][DENSITY] & 0xF; + + info.is_x16_module[1][0] = (info.spd[1][0][RANKS_AND_DQ] & 7) - 1; + info.density[1][0] = info.spd[1][0][DENSITY] & 0xF; + } + + write_mchbar8 (0x2ca8, read_mchbar8 (0x2ca8) & 0xfc); +#if REAL + write_mchbar8 (0x2ca8, 8); +#endif + rdmsr (0x207); // !!! + + collect_system_info (&info); + calculate_timings (&info); + +#if !REAL + pci_mm_write8 (NORTHBRIDGE, 0xdf, 0x82); +#endif + + if (!s3resume) + gav (pci_mm_read8 (SOUTHBRIDGE, 0xa2)); + + gav (read_mchbar8 (0x2ca8)); ///!!!! + + if (!s3resume && x2ca8 == 0) + pci_mm_write8 (SOUTHBRIDGE, 0xa2, pci_mm_read8 (SOUTHBRIDGE, 0xa2) | 0x80); + + compute_derived_timings (&info); + + if (x2ca8 == 0) + { + gav (read_mchbar8 (0x164)); + write_mchbar8 (0x164, 0x26); + write_mchbar16 (0x2c20, 0x10); + } + + write_mchbar32 (0x18b4, read_mchbar32 (0x18b4) | 0x210000); /* OK */ + write_mchbar32 (0x1890, read_mchbar32 (0x1890) | 0x2000000); /* OK */ + write_mchbar32 (0x18b4, read_mchbar32 (0x18b4) | 0x8000); + + gav (pci_mm_read32 (0xff, 2, 1, 0x50)); // !!!! + pci_mm_write8 (0xff, 2, 1, 0x54, 0x12); + + gav (read_mchbar16 (0x2c10)); // !!!! + write_mchbar16 (0x2c10, 0x412); + gav (read_mchbar16 (0x2c10)); // !!!! + write_mchbar16 (0x2c12, read_mchbar16 (0x2c12) | 0x100); /* OK */ + + gav (read_mchbar8 (0x2ca8)); // !!!! + write_mchbar32 (0x1804, (read_mchbar32 (0x1804) & 0xfffffffc) | 0x8400080); + + pci_mm_read32 (0xff, 2, 1, 0x6c); // !!!! + pci_mm_write32 (0xff, 2, 1, 0x6c, 0x40a0a0); + gav (read_mchbar32 (0x1c04)); // !!!! + gav (read_mchbar32 (0x1804)); // !!!! + + if (x2ca8 == 0) + { + write_mchbar8 (0x2ca8, read_mchbar8 (0x2ca8) | 1); + } + + write_mchbar32 (0x18d8, 0x120000); + write_mchbar32 (0x18dc, 0x30a484a); + pci_mm_write32 (0xff, 2, 1, 0xe0, 0x0); + pci_mm_write32 (0xff, 2, 1, 0xf4, 0x9444a); + write_mchbar32 (0x18d8, 0x40000); + write_mchbar32 (0x18dc, 0xb000000); + pci_mm_write32 (0xff, 2, 1, 0xe0, 0x60000); + pci_mm_write32 (0xff, 2, 1, 0xf4, 0x0); + write_mchbar32 (0x18d8, 0x180000); + write_mchbar32 (0x18dc, 0xc0000142); + pci_mm_write32 (0xff, 2, 1, 0xe0, 0x20000); + pci_mm_write32 (0xff, 2, 1, 0xf4, 0x142); + write_mchbar32 (0x18d8, 0x1e0000); + + gav (read_mchbar32 (0x18dc)); // !!!! + write_mchbar32 (0x18dc, 0x3); + gav (read_mchbar32 (0x18dc)); // !!!! + + if (x2ca8 == 0) + { + write_mchbar8 (0x2ca8, read_mchbar8 (0x2ca8) | 1); // guess + } + + write_mchbar32 (0x188c, 0x20bc09); + pci_mm_write32 (0xff, 2, 1, 0xd0, 0x40b0c09); + write_mchbar32 (0x1a10, 0x4200010e); + write_mchbar32 (0x18b8, read_mchbar32 (0x18b8) | 0x200); + gav (read_mchbar32 (0x1918)); // !!!! + write_mchbar32 (0x1918, 0x332); + + gav (read_mchbar32 (0x18b8)); // !!!! + write_mchbar32 (0x18b8, 0xe00); + gav (read_mchbar32 (0x182c)); // !!!! + write_mchbar32 (0x182c, 0x10202); + gav (pci_mm_read32 (0xff, 2, 1, 0x94)); // !!!! + pci_mm_write32 (0xff, 2, 1, 0x94, 0x10202); + write_mchbar32 (0x1a1c, read_mchbar32 (0x1a1c) & 0x8fffffff); + write_mchbar32 (0x1a70, read_mchbar32 (0x1a70) | 0x100000); + + write_mchbar32 (0x18b4, read_mchbar32 (0x18b4) & 0xffff7fff); + gav (read_mchbar32 (0x1a68)); // !!!! + write_mchbar32 (0x1a68, 0x343800); + gav (read_mchbar32 (0x1e68)); // !!!! + gav (read_mchbar32 (0x1a68)); // !!!! + + if (x2ca8 == 0) + { + write_mchbar8 (0x2ca8, read_mchbar8 (0x2ca8) | 1); // guess + } + + pci_mm_read32 (0xff, 2, 0, 0x048); // !!!! + pci_mm_write32 (0xff, 2, 0, 0x048, 0x140000); + pci_mm_read32 (0xff, 2, 0, 0x058); // !!!! + pci_mm_write32 (0xff, 2, 0, 0x058, 0x64555); + pci_mm_read32 (0xff, 2, 0, 0x058); // !!!! + pci_mm_read32 (0xff, 0, 0, 0xd0); // !!!! + pci_mm_write32 (0xff, 0, 0, 0xd0, 0x180); + gav (read_mchbar32 (0x1af0)); // !!!! + gav (read_mchbar32 (0x1af0)); // !!!! + write_mchbar32 (0x1af0, 0x1f020003); + gav (read_mchbar32 (0x1af0)); // !!!! + + if (((x2ca8 == 0))) + { + write_mchbar8 (0x2ca8, read_mchbar8 (0x2ca8) | 1); // guess + } + + gav (read_mchbar32 (0x1890)); // !!!! + write_mchbar32 (0x1890, 0x80102); + gav (read_mchbar32 (0x18b4)); // !!!! + write_mchbar32 (0x18b4, 0x216000); + write_mchbar32 (0x18a4, 0x22222222); + write_mchbar32 (0x18a8, 0x22222222); + write_mchbar32 (0x18ac, 0x22222); + + if (x2ca8 == 0) + { + int b144[2]; + if (!s3resume) + for (channel = 0; channel < 2; channel++) + { + gav (read_mchbar8 (0x2ca8)); + write_mchbar32 (0x140, (read_mchbar32 (0x140) & 0xf8ffffff) | 0x2000000); + write_mchbar32 (0x138, (read_mchbar32 (0x138) & 0xf8ffffff) | 0x2000000); + gav (b144[channel] = (read_mchbar8 (0x144) >> 4) & 1); + write_mchbar32 (0x274 + (channel << 10), 0x50005); + write_mchbar16 (0x265 + (channel << 10), 0xe00); + } + else + { + write_mchbar32 (0x274, 0x30005); + write_mchbar16 (0x265, 0xd00); + write_mchbar32 (0x674, info.populated_ranks[1][0][0] ? 0x40005 : 0x20004); + write_mchbar16 (0x665, info.populated_ranks[1][0][0] ? 0xd00 : 0xc00); + b144[0] = 0; + b144[1] = 1; + } + + write_mchbar8 (0x2ca9, read_mchbar8 (0x2ca9) & ~1); + write_mchbar32 (0x2d04, 0x1); + write_mchbar32 (0x2d00, 0x1010000); + write_mchbar32 (0x2d0c, 0x0); + write_mchbar32 (0x2d08, 0x1110000); + write_mchbar32 (0x2d14, 0x5); + write_mchbar32 (0x2d10, 0x401fdff); + write_mchbar32 (0x2d1c, 0x101); + write_mchbar32 (0x2d18, 0x811f9fc); + write_mchbar32 (0x2d24, 0x105); + write_mchbar32 (0x2d20, 0x410fcff); + write_mchbar32 (0x2d2c, 0x7); + write_mchbar32 (0x2d28, 0x911f1fb); + write_mchbar32 (0x2d34, 0x101); + write_mchbar32 (0x2d30, 0x811fdfa); + write_mchbar32 (0x2d3c, 0x105); + write_mchbar32 (0x2d38, 0x4200000); + write_mchbar32 (0x2d44, 0x107); + write_mchbar32 (0x2d40, 0x2200000); + write_mchbar32 (0x2d4c, 0x107); + write_mchbar32 (0x2d48, 0x2200000); + write_mchbar32 (0x2d54, 0x105); + write_mchbar32 (0x2d50, 0x4200000); + + write_mchbar32 (0x6d4, 0x100f8); + write_mchbar32 (0x6d8, 0x1100f8); + if (s3resume) + write_mchbar32 (0x6dc, info.populated_ranks[1][0][0] ? 0x33fefa : 0x33fffa); + else + write_mchbar32 (0x6dc, b144[0] ? 0x23faff : 0x22fdf9); +#if !REAL + printf ("CP13\n"); +#endif + + write_mchbar32 (0x6e0, 0x100fa); + write_mchbar32 (0x6e4, 0x0); + if (s3resume && info.populated_ranks[1][0][0]) + write_mchbar32 (0x6e8, 0x22fcf8); + else + write_mchbar32 (0x6e8, b144[1] ? 0x23faff : 0x22fdf9); + + write_mchbar32 (0x2d5c, 0x1010001); + write_mchbar32 (0x2d58, 0x1110000); + write_mchbar32 (0x2d64, 0x2020104); + write_mchbar32 (0x2d60, 0x211fffe); + write_mchbar32 (0x2d6c, 0x117); + write_mchbar32 (0x2d68, 0x430e7ee); + write_mchbar32 (0x2d74, 0x10100126); + write_mchbar32 (0x2d70, 0x1010f0ff); + write_mchbar32 (0x2d7c, 0x113); + write_mchbar32 (0x2d78, 0x810ebf1); + write_mchbar32 (0x2d84, 0xa0a010d); + write_mchbar32 (0x2d80, 0x510fbff); + write_mchbar32 (0x2d8c, 0xa0a010d); + write_mchbar32 (0x2d88, 0x510fbff); + write_mchbar32 (0x2da4, 0x8080016); + write_mchbar32 (0x2da0, 0x800fff2); + write_mchbar32 (0x2dac, 0x1b1b0025); + write_mchbar32 (0x2da8, 0x1b11e7ec); + write_mchbar32 (0x2db4, 0x808012e); + write_mchbar32 (0x2db0, 0x830e8fd); + write_mchbar32 (0x2dbc, 0xe000ef); + write_mchbar32 (0x2db8, 0x10d0077); + if (!(deven & 8)) + { + read_mchbar32 (0x2cb0); + write_mchbar32 (0x2cb0, 0x40); + } + + if (deven & 8) + { + write_mchbar32 (0xff8, 0x1800 | read_mchbar32 (0xff8)); + read_mchbar32 (0x2cb0); + write_mchbar32 (0x2cb0, 0x00); + pci_mm_read8 (0, 0x2, 0x0, 0x4c); + pci_mm_read8 (0, 0x2, 0x0, 0x4c); + pci_mm_read8 (0, 0x2, 0x0, 0x4e); + + read_mchbar8 (0x1150); + read_mchbar8 (0x1151); + read_mchbar8 (0x1022); + read_mchbar8 (0x16d0); + write_mchbar32 (0x1300, 0x60606060); + write_mchbar32 (0x1304, 0x60606060); + write_mchbar32 (0x1308, 0x78797a7b); + write_mchbar32 (0x130c, 0x7c7d7e7f); + write_mchbar32 (0x1310, 0x60606060); + write_mchbar32 (0x1314, 0x60606060); + write_mchbar32 (0x1318, 0x60606060); + write_mchbar32 (0x131c, 0x60606060); + write_mchbar32 (0x1320, 0x50515253); + write_mchbar32 (0x1324, 0x54555657); + write_mchbar32 (0x1328, 0x58595a5b); + write_mchbar32 (0x132c, 0x5c5d5e5f); + write_mchbar32 (0x1330, 0x40414243); + write_mchbar32 (0x1334, 0x44454647); + write_mchbar32 (0x1338, 0x48494a4b); + write_mchbar32 (0x133c, 0x4c4d4e4f); + write_mchbar32 (0x1340, 0x30313233); + write_mchbar32 (0x1344, 0x34353637); + write_mchbar32 (0x1348, 0x38393a3b); + write_mchbar32 (0x134c, 0x3c3d3e3f); + write_mchbar32 (0x1350, 0x20212223); + write_mchbar32 (0x1354, 0x24252627); + write_mchbar32 (0x1358, 0x28292a2b); + write_mchbar32 (0x135c, 0x2c2d2e2f); + write_mchbar32 (0x1360, 0x10111213); + write_mchbar32 (0x1364, 0x14151617); + write_mchbar32 (0x1368, 0x18191a1b); + write_mchbar32 (0x136c, 0x1c1d1e1f); + write_mchbar32 (0x1370, 0x10203); + write_mchbar32 (0x1374, 0x4050607); + write_mchbar32 (0x1378, 0x8090a0b); + write_mchbar32 (0x137c, 0xc0d0e0f); + write_mchbar8 (0x11cc, 0x4e); + write_mchbar32 (0x1110, 0x73970404); + write_mchbar32 (0x1114, 0x72960404); + write_mchbar32 (0x1118, 0x6f950404); + write_mchbar32 (0x111c, 0x6d940404); + write_mchbar32 (0x1120, 0x6a930404); + write_mchbar32 (0x1124, 0x68a41404); + write_mchbar32 (0x1128, 0x66a21404); + write_mchbar32 (0x112c, 0x63a01404); + write_mchbar32 (0x1130, 0x609e1404); + write_mchbar32 (0x1134, 0x5f9c1404); + write_mchbar32 (0x1138, 0x5c961404); + write_mchbar32 (0x113c, 0x58a02404); + write_mchbar32 (0x1140, 0x54942404); + write_mchbar32 (0x1190, 0x900080a); + write_mchbar16 (0x11c0, 0xc40b); + write_mchbar16 (0x11c2, 0x303); + write_mchbar16 (0x11c4, 0x301); + read_mchbar32 (0x1190); + write_mchbar32 (0x1190, 0x8900080a); + write_mchbar32 (0x11b8, 0x70c3000); + write_mchbar8 (0x11ec, 0xa); + write_mchbar16 (0x1100, 0x800); + read_mchbar32 (0x11bc); + write_mchbar32 (0x11bc, 0x1e84800); + write_mchbar16 (0x11ca, 0xfa); + write_mchbar32 (0x11e4, 0x4e20); + write_mchbar8 (0x11bc, 0xf); + write_mchbar16 (0x11da, 0x19); + write_mchbar16 (0x11ba, 0x470c); + write_mchbar32 (0x1680, 0xe6ffe4ff); + write_mchbar32 (0x1684, 0xdeffdaff); + write_mchbar32 (0x1688, 0xd4ffd0ff); + write_mchbar32 (0x168c, 0xccffc6ff); + write_mchbar32 (0x1690, 0xc0ffbeff); + write_mchbar32 (0x1694, 0xb8ffb0ff); + write_mchbar32 (0x1698, 0xa8ff0000); + write_mchbar32 (0x169c, 0xc00); + write_mchbar32 (0x1290, 0x5000000); + } + + write_mchbar32 (0x124c, 0x15040d00); + write_mchbar32 (0x1250, 0x7f0000); + write_mchbar32 (0x1254, 0x1e220004); + write_mchbar32 (0x1258, 0x4000004); + write_mchbar32 (0x1278, 0x0); + write_mchbar32 (0x125c, 0x0); + write_mchbar32 (0x1260, 0x0); + write_mchbar32 (0x1264, 0x0); + write_mchbar32 (0x1268, 0x0); + write_mchbar32 (0x126c, 0x0); + write_mchbar32 (0x1270, 0x0); + write_mchbar32 (0x1274, 0x0); + } + + if ((deven & 8) && x2ca8 == 0) + { + write_mchbar16 (0x1214, 0x320); + write_mchbar32 (0x1600, 0x40000000); + read_mchbar32 (0x11f4); + write_mchbar32 (0x11f4, 0x10000000); + read_mchbar16 (0x1230); + write_mchbar16 (0x1230, 0x8000); + write_mchbar32 (0x1400, 0x13040020); + write_mchbar32 (0x1404, 0xe090120); + write_mchbar32 (0x1408, 0x5120220); + write_mchbar32 (0x140c, 0x5120330); + write_mchbar32 (0x1410, 0xe090220); + write_mchbar32 (0x1414, 0x1010001); + write_mchbar32 (0x1418, 0x1110000); + write_mchbar32 (0x141c, 0x9020020); + write_mchbar32 (0x1420, 0xd090220); + write_mchbar32 (0x1424, 0x2090220); + write_mchbar32 (0x1428, 0x2090330); + write_mchbar32 (0x142c, 0xd090220); + write_mchbar32 (0x1430, 0x1010001); + write_mchbar32 (0x1434, 0x1110000); + write_mchbar32 (0x1438, 0x11040020); + write_mchbar32 (0x143c, 0x4030220); + write_mchbar32 (0x1440, 0x1060220); + write_mchbar32 (0x1444, 0x1060330); + write_mchbar32 (0x1448, 0x4030220); + write_mchbar32 (0x144c, 0x1010001); + write_mchbar32 (0x1450, 0x1110000); + write_mchbar32 (0x1454, 0x4010020); + write_mchbar32 (0x1458, 0xb090220); + write_mchbar32 (0x145c, 0x1090220); + write_mchbar32 (0x1460, 0x1090330); + write_mchbar32 (0x1464, 0xb090220); + write_mchbar32 (0x1468, 0x1010001); + write_mchbar32 (0x146c, 0x1110000); + write_mchbar32 (0x1470, 0xf040020); + write_mchbar32 (0x1474, 0xa090220); + write_mchbar32 (0x1478, 0x1120220); + write_mchbar32 (0x147c, 0x1120330); + write_mchbar32 (0x1480, 0xa090220); + write_mchbar32 (0x1484, 0x1010001); + write_mchbar32 (0x1488, 0x1110000); + write_mchbar32 (0x148c, 0x7020020); + write_mchbar32 (0x1490, 0x1010220); + write_mchbar32 (0x1494, 0x10210); + write_mchbar32 (0x1498, 0x10320); + write_mchbar32 (0x149c, 0x1010220); + write_mchbar32 (0x14a0, 0x1010001); + write_mchbar32 (0x14a4, 0x1110000); + write_mchbar32 (0x14a8, 0xd040020); + write_mchbar32 (0x14ac, 0x8090220); + write_mchbar32 (0x14b0, 0x1111310); + write_mchbar32 (0x14b4, 0x1111420); + write_mchbar32 (0x14b8, 0x8090220); + write_mchbar32 (0x14bc, 0x1010001); + write_mchbar32 (0x14c0, 0x1110000); + write_mchbar32 (0x14c4, 0x3010020); + write_mchbar32 (0x14c8, 0x7090220); + write_mchbar32 (0x14cc, 0x1081310); + write_mchbar32 (0x14d0, 0x1081420); + write_mchbar32 (0x14d4, 0x7090220); + write_mchbar32 (0x14d8, 0x1010001); + write_mchbar32 (0x14dc, 0x1110000); + write_mchbar32 (0x14e0, 0xb040020); + write_mchbar32 (0x14e4, 0x2030220); + write_mchbar32 (0x14e8, 0x1051310); + write_mchbar32 (0x14ec, 0x1051420); + write_mchbar32 (0x14f0, 0x2030220); + write_mchbar32 (0x14f4, 0x1010001); + write_mchbar32 (0x14f8, 0x1110000); + write_mchbar32 (0x14fc, 0x5020020); + write_mchbar32 (0x1500, 0x5090220); + write_mchbar32 (0x1504, 0x2071310); + write_mchbar32 (0x1508, 0x2071420); + write_mchbar32 (0x150c, 0x5090220); + write_mchbar32 (0x1510, 0x1010001); + write_mchbar32 (0x1514, 0x1110000); + write_mchbar32 (0x1518, 0x7040120); + write_mchbar32 (0x151c, 0x2090220); + write_mchbar32 (0x1520, 0x70b1210); + write_mchbar32 (0x1524, 0x70b1310); + write_mchbar32 (0x1528, 0x2090220); + write_mchbar32 (0x152c, 0x1010001); + write_mchbar32 (0x1530, 0x1110000); + write_mchbar32 (0x1534, 0x1010110); + write_mchbar32 (0x1538, 0x1081310); + write_mchbar32 (0x153c, 0x5041200); + write_mchbar32 (0x1540, 0x5041310); + write_mchbar32 (0x1544, 0x1081310); + write_mchbar32 (0x1548, 0x1010001); + write_mchbar32 (0x154c, 0x1110000); + write_mchbar32 (0x1550, 0x1040120); + write_mchbar32 (0x1554, 0x4051210); + write_mchbar32 (0x1558, 0xd051200); + write_mchbar32 (0x155c, 0xd051200); + write_mchbar32 (0x1560, 0x4051210); + write_mchbar32 (0x1564, 0x1010001); + write_mchbar32 (0x1568, 0x1110000); + write_mchbar16 (0x1222, 0x220a); + write_mchbar16 (0x123c, 0x1fc0); + write_mchbar16 (0x1220, 0x1388); + } + + read_mchbar32 (0x2c80); // !!!! + write_mchbar32 (0x2c80, 0x1053688); + read_mchbar32 (0x1c04); // !!!! + write_mchbar32 (0x1804, 0x406080); + + read_mchbar8 (0x2ca8); + + if (x2ca8 == 0) + { + write_mchbar8 (0x2ca8, read_mchbar8 (0x2ca8) & ~3); + write_mchbar8 (0x2ca8, read_mchbar8 (0x2ca8) + 4); + write_mchbar32 (0x1af0, read_mchbar32 (0x1af0) | 0x10); +#if REAL + while (1) + { + asm volatile ("hlt"); + } +#else + printf ("CP5\n"); + exit (0); +#endif + } + + write_mchbar8 (0x2ca8, read_mchbar8 (0x2ca8)); + read_mchbar32 (0x2c80); // !!!! + write_mchbar32 (0x2c80, 0x53688); + pci_mm_write32 (0xff, 0, 0, 0x60, 0x20220); + read_mchbar16 (0x2c20); // !!!! + read_mchbar16 (0x2c10); // !!!! + read_mchbar16 (0x2c00); // !!!! + write_mchbar16 (0x2c00, 0x8c0); + write_1d0 (0, 0x33d, 0, 0); + write_500 (&info, 0, 0, 0xb61, 0, 0); + write_500 (&info, 1, 0, 0xb61, 0, 0); + write_mchbar32 (0x1a30, 0x0); + write_mchbar32 (0x1a34, 0x0); + write_mchbar16 (0x614, 0xb5b | (info.populated_ranks[1][0][0] * 0x404) | (info.populated_ranks[0][0][0] * 0xa0)); + write_mchbar16 (0x616, 0x26a); + write_mchbar32 (0x134, 0x856000); + write_mchbar32 (0x160, 0x5ffffff); + read_mchbar32 (0x114); // !!!! + write_mchbar32 (0x114, 0xc2024440); + read_mchbar32 (0x118); // !!!! + write_mchbar32 (0x118, 0x4); + for (channel = 0; channel < NUM_CHANNELS; channel++) + write_mchbar32 (0x260 + (channel << 10), 0x30809ff | ((info.populated_ranks_mask[channel] & 3) << 20)); + for (channel = 0; channel < NUM_CHANNELS; channel++) + { + write_mchbar16 (0x31c + (channel << 10), 0x101); + write_mchbar16 (0x360 + (channel << 10), 0x909); + write_mchbar16 (0x3a4 + (channel << 10), 0x101); + write_mchbar16 (0x3e8 + (channel << 10), 0x101); + write_mchbar32 (0x320 + (channel << 10), 0x29002900); + write_mchbar32 (0x324 + (channel << 10), 0x0); + write_mchbar32 (0x368 + (channel << 10), 0x32003200); + write_mchbar16 (0x352 + (channel << 10), 0x505); + write_mchbar16 (0x354 + (channel << 10), 0x3c3c); + write_mchbar16 (0x356 + (channel << 10), 0x1040); + write_mchbar16 (0x39a + (channel << 10), 0x73e4); + write_mchbar16 (0x3de + (channel << 10), 0x77ed); + write_mchbar16 (0x422 + (channel << 10), 0x1040); + } + + write_1d0 (0x4, 0x151, 4, 1); + write_1d0 (0, 0x142, 3, 1); + rdmsr (0x1ac); // !!!! + write_500 (&info, 1, 1, 0x6b3, 4, 1); + write_500 (&info, 1, 1, 0x6cf, 4, 1); + + rmw_1d0 (0x21c, 0x38, 0, 6, 1); + + write_1d0 (((!info.populated_ranks[1][0][0]) << 1) | ((!info.populated_ranks[0][0][0]) << 0), 0x1d1, 3, 1); + for (channel = 0; channel < NUM_CHANNELS; channel++) + { + write_mchbar16 (0x38e + (channel << 10), 0x5f5f); + write_mchbar16 (0x3d2 + (channel << 10), 0x5f5f); + } + + set_334 (0); + + program_base_timings (&info); + + write_mchbar8 (0x5ff, read_mchbar8 (0x5ff) | 0x80); /* OK */ + + write_1d0 (0x2, 0x1d5, 2, 1); + write_1d0 (0x20, 0x166, 7, 1); + write_1d0 (0x0, 0xeb, 3, 1); + write_1d0 (0x0, 0xf3, 6, 1); + + for (channel = 0; channel < NUM_CHANNELS; channel++) + for (lane = 0; lane < 9; lane++) + { + u16 addr = 0x125 + get_lane_offset (0, 0, lane); + u8 a; + a = read_500 (&info, channel, addr, 6); // = 0x20040080 //!!!! + write_500 (&info, channel, a, addr, 6, 1); + } + + if (s3resume) + { + const struct ram_training *train; + + train = get_cached_training(); + if (train == NULL) + { + u32 reg32; + printk (BIOS_ERR, "Couldn't find training data. Rebooting\n"); + reg32 = inl(DEFAULT_PMBASE + 0x04); + outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04); + outb (0xe, 0xcf9); + +#if REAL + while (1) + { + asm volatile ("hlt"); + } +#else + printf ("CP5\n"); + exit (0); +#endif + } + int tm; + info.training = *train; + for (tm = 0; tm < 4; tm++) + for (channel = 0; channel < NUM_CHANNELS; channel++) + for (slot = 0; slot < NUM_SLOTS; slot++) + for (rank = 0; rank < NUM_RANKS; rank++) + for (lane = 0; lane < 9; lane++) + write_500 (&info, channel, info.training.lane_timings[tm][channel][slot][rank][lane], get_timing_register_addr (lane, tm, slot, rank), 9, 0); + write_1d0 (train->reg_178, 0x178, 7, 1); + write_1d0 (train->reg_10b, 0x10b, 6, 1); + } + + read_mchbar32 (0x1f4); // !!!! + write_mchbar32 (0x1f4, 0x20000); + write_mchbar32 (0x1f0, 0x1d000200); + read_mchbar8 (0x1f0); // !!!! + write_mchbar8 (0x1f0, 0x1); + read_mchbar8 (0x1f0); // !!!! + + program_board_delay(&info); + + write_mchbar8 (0x5ff, 0x0); /* OK */ + write_mchbar8 (0x5ff, 0x80); /* OK */ + write_mchbar8 (0x5f4, 0x1); /* OK */ + + write_mchbar32 (0x130, read_mchbar32 (0x130) & 0xfffffffd); // | 2 when ? + while (read_mchbar32 (0x130) & 1); + gav (read_1d0 (0x14b, 7)); // = 0x81023100 + write_1d0 (0x30, 0x14b, 7, 1); + read_1d0 (0xd6, 6); // = 0xfa008080 // !!!! + write_1d0 (7, 0xd6, 6, 1); + read_1d0 (0x328, 6); // = 0xfa018080 // !!!! + write_1d0 (7, 0x328, 6, 1); + + for (channel = 0; channel < NUM_CHANNELS; channel++) + set_4cf (&info, channel, info.populated_ranks[channel][0][0] ? 8 : 0); + + read_1d0 (0x116, 4); // = 0x4040432 // !!!! + write_1d0 (2, 0x116, 4, 1); + read_1d0 (0xae, 6); // = 0xe8088080 // !!!! + write_1d0 (0, 0xae, 6, 1); + read_1d0 (0x300, 4); // = 0x48088080 // !!!! + write_1d0 (0, 0x300, 6, 1); + read_mchbar16 (0x356); // !!!! + write_mchbar16 (0x356, 0x1040); + read_mchbar16 (0x756); // !!!! + write_mchbar16 (0x756, 0x1040); + write_mchbar32 (0x140, read_mchbar32 (0x140) & ~0x07000000); + write_mchbar32 (0x138, read_mchbar32 (0x138) & ~0x07000000); + write_mchbar32 (0x130, 0x31111301); + while (read_mchbar32 (0x130) & 1); + + { + u32 t; + u8 val_a1; + val_a1 = read_1d0 (0xa1, 6); // = 0x1cf4040 // !!!! + t = read_1d0 (0x2f3, 6); // = 0x10a4040 // !!!! + rmw_1d0 (0x320, 0x07, (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1); + rmw_1d0 (0x14b, 0x78, ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 & 4), 7, 1); + rmw_1d0 (0xce, 0x38, ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 & 4), 6, 1); + } + + for (channel = 0; channel < NUM_CHANNELS; channel++) + set_4cf (&info, channel, info.populated_ranks[channel][0][0] ? 9 : 1); + + rmw_1d0 (0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!! + read_mchbar32 (0x144); // !!!! + write_1d0 (2, 0xae, 6, 1); + write_1d0 (2, 0x300, 6, 1); + write_1d0 (2, 0x121, 3, 1); + read_1d0 (0xd6, 6); // = 0xfa00c0c7 // !!!! + write_1d0 (4, 0xd6, 6, 1); + read_1d0 (0x328, 6); // = 0xfa00c0c7 // !!!! + write_1d0 (4, 0x328, 6, 1); + + for (channel = 0; channel < NUM_CHANNELS; channel++) + set_4cf (&info, channel, info.populated_ranks[channel][0][0] ? 9 : 0); + + write_mchbar32 (0x130, 0x11111301 | (info.populated_ranks[1][0][0] << 30) | (info.populated_ranks[0][0][0] << 29)); + while (read_mchbar8 (0x130) & 1); // !!!! + read_1d0 (0xa1, 6); // = 0x1cf4054 // !!!! + read_1d0 (0x2f3, 6); // = 0x10a4054 // !!!! + read_1d0 (0x21c, 6); // = 0xafa00c0 // !!!! + write_1d0 (0, 0x21c, 6, 1); + read_1d0 (0x14b, 7); // = 0x810231b0 // !!!! + write_1d0 (0x35, 0x14b, 7, 1); + + for (channel = 0; channel < NUM_CHANNELS; channel++) + set_4cf (&info, channel, info.populated_ranks[channel][0][0] ? 0xb : 0x2); + + set_334 (1); + + write_mchbar8 (0x1e8, 0x4); /* OK */ + + for (channel = 0; channel < NUM_CHANNELS; channel++) + { + write_500 (&info, channel, 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2, 1); + write_500 (&info, channel, 0x3, 0x69b, 2, 1); + } + write_mchbar32 (0x2d0, (read_mchbar32 (0x2d0) & 0xff2c01ff) | 0x200000); /* OK */ + write_mchbar16 (0x6c0, 0x14a0); /* OK */ + write_mchbar32 (0x6d0, (read_mchbar32 (0x6d0) & 0xff0080ff) | 0x8000); /* OK */ + write_mchbar16 (0x232, 0x8); + write_mchbar32 (0x234, (read_mchbar32 (0x234) & 0xfffbfffb) | 0x40004); /* 0x40004 or 0 depending on ? */ + write_mchbar32 (0x34, (read_mchbar32 (0x34) & 0xfffffffd) | 5); /* OK */ + write_mchbar32 (0x128, 0x2150d05); + write_mchbar8 (0x12c, 0x1f); /* OK */ + write_mchbar8 (0x12d, 0x56); /* OK */ + write_mchbar8 (0x12e, 0x31); + write_mchbar8 (0x12f, 0x0); /* OK */ + write_mchbar8 (0x271, 0x2); /* OK */ + write_mchbar8 (0x671, 0x2); /* OK */ + write_mchbar8 (0x1e8, 0x4); /* OK */ + for (channel = 0; channel < NUM_CHANNELS; channel++) + write_mchbar32 (0x294 + (channel << 10), (info.populated_ranks_mask[channel] & 3) << 16); + write_mchbar32 (0x134, (read_mchbar32 (0x134) & 0xfc01ffff) | 0x10000); /* OK */ + write_mchbar32 (0x134, (read_mchbar32 (0x134) & 0xfc85ffff) | 0x850000); /* OK */ + for (channel = 0; channel < NUM_CHANNELS; channel++) + write_mchbar32 (0x260 + (channel << 10), (read_mchbar32 (0x260 + (channel << 10)) & ~0xf00000) | 0x8000000 |((info.populated_ranks_mask[channel] & 3) << 20)); + + if (!s3resume) + jedec_init (&info); + + int totalrank = 0; + for (channel = 0; channel < NUM_CHANNELS; channel++) + for (slot = 0; slot < NUM_SLOTS; slot++) + for (rank = 0; rank < NUM_RANKS; rank++) + if (info.populated_ranks[channel][slot][rank]) + { + jedec_read (&info, channel, slot, rank, totalrank, 0xa, 0x400); + totalrank++; + } + + write_mchbar8 (0x12c, 0x9f); + + read_mchbar8 (0x271); // 2 // !!!! + write_mchbar8 (0x271, 0xe); + read_mchbar8 (0x671); // !!!! + write_mchbar8 (0x671, 0xe); + + if (s3resume) + { + pci_mm_write16 (NORTHBRIDGE, 0xc8, 3); + write_26c (0, 0x820); + write_26c (1, 0x820); + write_mchbar32 (0x130, read_mchbar32 (0x130) | 2); + } + + for (channel = 0; channel < NUM_CHANNELS; channel++) + { + write_mchbar32 (0x294 + (channel << 10), (info.populated_ranks_mask[channel] & 3) << 16); + write_mchbar16 (0x298 + (channel << 10), (info.populated_ranks[channel][0][0]) | (info.populated_ranks[channel][0][1] << 5)); + write_mchbar32 (0x29c + (channel << 10), 0x77a); + } + read_mchbar32 (0x2c0); /// !!! + write_mchbar32 (0x2c0, 0x6009cc00); + + if (!s3resume) + { + { + u8 a, b; + a = read_mchbar8 (0x243); // !!!! + b = read_mchbar8 (0x643); // !!!! + write_mchbar8 (0x243, a | 2); + write_mchbar8 (0x643, b | 2); + } + + write_1d0 (7, 0x19b, 3, 1); + write_1d0 (7, 0x1c0, 3, 1); + write_1d0 (4, 0x1c6, 4, 1); + write_1d0 (4, 0x1cc, 4, 1); + read_1d0 (0x151, 4); // = 0x408c6d74 // !!!! + write_1d0 (4, 0x151, 4 ,1); + write_mchbar32 (0x584, 0xfffff); + write_mchbar32 (0x984, 0xfffff); + + for (channel = 0; channel < NUM_CHANNELS; channel++) + for (slot = 0; slot < NUM_SLOTS; slot++) + for (rank = 0; rank < NUM_RANKS; rank++) + if (info.populated_ranks[channel][slot][rank]) + config_rank (&info, s3resume, channel, slot, rank); + + seq8 (); + + pci_mm_write16 (NORTHBRIDGE, 0xc8, 3); + write_26c (0, 0x820); + write_26c (1, 0x820); + write_mchbar32 (0x130, read_mchbar32 (0x130) | 2); + } + + write_mchbar32 (0xfa4, read_mchbar32 (0xfa4) & ~0x01000002); + write_mchbar32 (0xfb0, 0x2000e019); + +#if !REAL + printf ("CP16\n"); +#endif + + /* FIXME: here there should be training. */ + + dump_timings (&info); + + program_modules_memory_map (&info, 0); + program_total_memory_map (&info); + + if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0) + write_mchbar8 (0x111, 0x20 | (0 << 2) | (1 << 6) | (0 << 7)); + else if (have_match_ranks (&info, 0, 4) && have_match_ranks (&info, 1, 4)) + write_mchbar8 (0x111, 0x20 | (3 << 2) | (0 << 6) | (1 << 7)); + else if (have_match_ranks (&info, 0, 2) && have_match_ranks (&info, 1, 2)) + write_mchbar8 (0x111, 0x20 | (3 << 2) | (0 << 6) | (0 << 7)); + else + write_mchbar8 (0x111, 0x20 | (3 << 2) | (1 << 6) | (0 << 7)); + + write_mchbar32 (0xfac, read_mchbar32 (0xfac) & ~0x80000000); // OK + write_mchbar32 (0xfb4, 0x4800); // OK + write_mchbar32 (0xfb8, (info.revision < 8) ? 0x20 : 0x0); // OK + write_mchbar32 (0xe94, 0x7ffff); // OK + write_mchbar32 (0xfc0, 0x80002040); // OK + write_mchbar32 (0xfc4, 0x701246); // OK + write_mchbar8 (0xfc8, read_mchbar8 (0xfc8) & ~0x70); // OK + write_mchbar32 (0xe5c, 0x1000000 | read_mchbar32 (0xe5c)); // OK + write_mchbar32 (0x1a70, (read_mchbar32 (0x1a70) | 0x00200000) & ~0x00100000); // OK + write_mchbar32 (0x50, 0x700b0); // OK + write_mchbar32 (0x3c, 0x10); // OK + write_mchbar8 (0x1aa8, (read_mchbar8 (0x1aa8) & ~0x35) | 0xa); // OK + write_mchbar8 (0xff4, read_mchbar8 (0xff4) | 0x2); // OK + write_mchbar32 (0xff8, (read_mchbar32 (0xff8) & ~0xe008) | 0x1020); // OK + +#if REAL + write_mchbar32 (0xd00, IOMMU_BASE2 | 1); + write_mchbar32 (0xd40, IOMMU_BASE1 | 1); + write_mchbar32 (0xdc0, IOMMU_BASE4 | 1); + + write32 (IOMMU_BASE1 | 0xffc, 0x80000000); + write32 (IOMMU_BASE2 | 0xffc, 0xc0000000); + write32 (IOMMU_BASE4 | 0xffc, 0x80000000); + +#else + { + u32 eax; + eax = read32 (0xffc + (read_mchbar32 (0xd00) & ~1)) | 0x08000000; // = 0xe911714b// OK + write32 (0xffc + (read_mchbar32 (0xd00) & ~1), eax);// OK + eax = read32 (0xffc + (read_mchbar32 (0xdc0) & ~1)) | 0x40000000; // = 0xe911714b// OK + write32 (0xffc + (read_mchbar32 (0xdc0) & ~1), eax);// OK + } +#endif + + { + u32 eax; + + eax = (info.some_base_frequency >> 4) / 9; + write_mchbar32 (0xfcc, (read_mchbar32 (0xfcc) & 0xfffc0000) | (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);// OK + write_mchbar32 (0x20, 0x33001); //OK + } + + for (channel = 0; channel < NUM_CHANNELS; channel++) + { + write_mchbar32 (0x220 + (channel << 10), + read_mchbar32 (0x220 + (channel << 10)) & ~0x7770); //OK + if (info.max_slots_used_in_channel == 1) + write_mchbar16 (0x237 + (channel << 10), (read_mchbar16 (0x237 + (channel << 10)) | 0x0201)); //OK + else + write_mchbar16 (0x237 + (channel << 10), (read_mchbar16 (0x237 + (channel << 10)) & ~0x0201)); //OK + + write_mchbar8 (0x241 + (channel << 10), read_mchbar8 (0x241 + (channel << 10)) | 1); // OK + + if (info.clock_speed_index <= 1 && (info.silicon_revision == 2 || info.silicon_revision == 3)) + write_mchbar32 (0x248 + (channel << 10), + (read_mchbar32 (0x248 + (channel << 10)) | 0x00102000)); // OK + else + write_mchbar32 (0x248 + (channel << 10), + (read_mchbar32 (0x248 + (channel << 10)) & ~0x00102000)); // OK + } + + write_mchbar32 (0x115, read_mchbar32 (0x115) | 0x1000000); // OK + + { + u8 al; + al = 0xd; + if (!(info.silicon_revision == 0 || info.silicon_revision == 1)) + al += 2; + al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4; + write_mchbar32 (0x210, (al << 16) | 0x20); // OK + } + + for (channel = 0; channel < NUM_CHANNELS; channel++) + { + write_mchbar32 (0x288 + (channel << 10), 0x70605040); // OK + write_mchbar32 (0x28c + (channel << 10), 0xfffec080); // OK + write_mchbar32 (0x290 + (channel << 10), 0x282091c | ((info.max_slots_used_in_channel - 1) << 0x16)); // OK + } + u32 reg1c; + pci_mm_read32 (NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK + reg1c = read32 (DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK + pci_mm_read32 (NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK + write32 (DEFAULT_EPBAR | 0x01c, reg1c); // OK + read_mchbar8 (0xe08); // = 0x0 + pci_mm_read32 (NORTHBRIDGE, 0xe4); // = 0x316126 + write_mchbar8 (0x1210, read_mchbar8 (0x1210) | 2); // OK + write_mchbar32 (0x1200, 0x8800440); // OK + write_mchbar32 (0x1204, 0x53ff0453); // OK + write_mchbar32 (0x1208, 0x19002043); // OK + write_mchbar16 (0x1214, 0x320); // OK + + /* trouble start. */ + if (info.revision == 0x10 || info.revision == 0x11) + { + write_mchbar16 (0x1214, 0x220); // OK + write_mchbar8 (0x1210, read_mchbar8 (0x1210) | 0x40); // OK + } + + write_mchbar8 (0x1214, read_mchbar8 (0x1214) | 0x4); // OK + write_mchbar8 (0x120c, 0x1); // OK + write_mchbar8 (0x1218, 0x3); // OK + write_mchbar8 (0x121a, 0x3); // OK + write_mchbar8 (0x121c, 0x3); // OK + write_mchbar16 (0xc14, 0x0); // OK + write_mchbar16 (0xc20, 0x0); // OK + write_mchbar32 (0x1c, 0x0); // OK + + /* revision dependent here. */ + + write_mchbar16 (0x1230, read_mchbar16 (0x1230) | 0x1f07); // OK + + if (info.uma_enabled) + write_mchbar32 (0x11f4, read_mchbar32 (0x11f4) | 0x10000000); // OK + + write_mchbar16 (0x1230, read_mchbar16 (0x1230) | 0x8000); // OK + write_mchbar8 (0x1214, read_mchbar8 (0x1214) | 1); // OK + + u8 bl, ebpb; + u16 reg_1020; + + reg_1020 = read_mchbar32 (0x1020); // = 0x6c733c // OK + write_mchbar8 (0x1070, 0x1); // OK + + write_mchbar32 (0x1000, 0x100); // OK + write_mchbar8 (0x1007, 0x0); // OK + + if (reg_1020 != 0) + { + write_mchbar16 (0x1018, 0x0); // OK + bl = reg_1020 >> 8; + ebpb = reg_1020 & 0xff; + } + else + { + ebpb = 0; + bl = 8; + } + + /* trouble start */ + rdmsr (0x1a2); + + write_mchbar32 (0x1014, 0xffffffff); // OK + + write_mchbar32 (0x1010, ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020)); // OK + + write_mchbar8 (0x101c, 0xb8); // OK + + write_mchbar8 (0x123e, (read_mchbar8 (0x123e) & 0xf) | 0x60); // OK + if (reg_1020 != 0) + { + write_mchbar32 (0x123c, (read_mchbar32 (0x123c) & ~0x00900000) | 0x600000); // OK + write_mchbar8 (0x101c, 0xb8); // OK + } + + setup_heci_uma (&info); + + if (info.uma_enabled) + { + u16 ax; + write_mchbar32 (0x11b0, read_mchbar32 (0x11b0) | 0x4000); // OK + write_mchbar32 (0x11b4, read_mchbar32 (0x11b4) | 0x4000); // OK + write_mchbar16 (0x1190, read_mchbar16 (0x1190) | 0x4000); // OK + + ax = read_mchbar16 (0x1190) & 0xf00; // = 0x480a // OK + write_mchbar16 (0x1170, ax | (read_mchbar16 (0x1170) & 0x107f) | 0x4080); // OK + write_mchbar16 (0x1170, read_mchbar16 (0x1170) | 0x1000); // OK +#if REAL + udelay (1000); +#endif + u16 ecx; + for (ecx = 0xffff; ecx && (read_mchbar16 (0x1170) & 0x1000); ecx--);// OK + write_mchbar16 (0x1190, read_mchbar16 (0x1190) & ~0x4000);// OK + } + + pci_mm_write8 (SOUTHBRIDGE, 0xa2, pci_mm_read8 (SOUTHBRIDGE, 0xa2) & ~0x80); + write_mchbar16 (0x2ca8, 0x0); + /* Trouble end */ + +#if REAL + udelay (1000); + write_mchbar16 (0x2ca8, 0x8); + dump_timings (&info); + if (!s3resume) + save_timings (&info); +#endif +} + +#if REAL +unsigned long get_top_of_ram(void) +{ + /* Base of TSEG is top of usable DRAM */ + u32 tom = pci_read_config32(PCI_DEV(0,0,0), TSEG); + return (unsigned long) tom; +} + +struct cbmem_entry *get_cbmem_toc(void) +{ + return (struct cbmem_entry *)(get_top_of_ram() - HIGH_MEMORY_SIZE); +} +#endif + +#if !REAL +int +main (void) +{ + raminit (0); + return 0; +} +#endif diff --git a/src/northbridge/intel/sandybridge/raminit.h b/src/northbridge/intel/sandybridge/raminit.h index 124f694..92f644e 100644 --- a/src/northbridge/intel/sandybridge/raminit.h +++ b/src/northbridge/intel/sandybridge/raminit.h @@ -20,16 +20,9 @@ #ifndef RAMINIT_H #define RAMINIT_H
-#include "pei_data.h" +#include "sandybridge.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 raminit(int s3resume); unsigned long get_top_of_ram(void); int fixup_sandybridge_errata(void);
diff --git a/src/northbridge/intel/sandybridge/raminit_fake.c b/src/northbridge/intel/sandybridge/raminit_fake.c new file mode 100644 index 0000000..09bf4bd --- /dev/null +++ b/src/northbridge/intel/sandybridge/raminit_fake.c @@ -0,0 +1,986 @@ +#include <parse.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) + +#define CONFIG_SMM_TSEG_SIZE (8 << 20) + +#define PCI_VENDOR_ID 0x00 /* 16 bits */ +#define PCI_COMMAND 0x04 /* 16 bits */ +#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ +#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ +#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ +#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */ +#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ +#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ +#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ +#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ +#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ +#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ +#define PCI_REVISION_ID 8 +#define PCI_DEVICE_ID 2 + +#define CONFIG_MMCONF_BASE_ADDRESS 0xe0000000 + + +#define PCI_SUBSYSTEM_VENDOR_ID 0x2c + +#if 0 +static u32 +cpu_model (void) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (op.type != CPU_MODEL) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return 0x20655; +} +#endif + +static void +write32 (u32 addr, u32 val) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (op.is_in || op.data_width != 32 || op.addr != addr || op.val != val || op.type != MEM) + { + printf ("Bad %d: %x, %x vs %x, %llx\n", __LINE__, addr, val, op.addr, op.val); + exit (1); + } +} + +static void +write16 (u32 addr, u16 val) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (op.is_in || op.data_width != 16 || op.addr != addr || op.val != val || op.type != MEM) + { + printf ("Bad %d: %x, %x vs %x, %llx\n", __LINE__, addr, val, op.addr, op.val); + exit (1); + } +} + +static void +write8 (u32 addr, u8 val) +{ + struct opcode op; + fetch_opcode (&op); + if (op.is_in || op.data_width != 8 || op.addr != addr || op.val != val || op.type != MEM) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } +} + + +static int +smbus_read_byte (u32 dev, u32 addr) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (!op.is_in || op.data_width != 8 || op.addr != addr || op.type != SMBUS || op.dev != dev) + { + printf ("Bad %d: %x, %d vs %x, %d\n", __LINE__, op.addr, SMBUS, addr, op.type); + exit (1); + } + return (signed short) op.val; +} + +static int +smbus_block_read (u32 dev, u32 addr, u32 len, u8 *block) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (!op.is_in || op.data_width != len || op.addr != addr || op.type != OPCODE_SMBUS_BLOCK || op.dev != dev) + { + printf ("Bad %d: %x, %d vs %x, %d\n", __LINE__, op.addr, OPCODE_SMBUS_BLOCK, addr, op.type); + exit (1); + } + memcpy (block, &op.val, len); + return 0; +} + +static int +smbus_block_write (u32 dev, u32 addr, u32 len, const u8 *block) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (op.is_in || op.data_width != len || op.addr != addr || op.type != OPCODE_SMBUS_BLOCK || op.dev != dev || memcmp (block, &op.val, len) != 0) + { + printf ("Bad %d: %x, %d vs %x, %d\n", __LINE__, op.addr, OPCODE_SMBUS_BLOCK, addr, op.type); + exit (1); + } + return 0; +} + +static void +smbus_write_byte (u32 dev, u32 addr, u8 val) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (op.is_in || op.data_width != 8 || op.addr != addr || op.type != SMBUS || op.dev != dev || op.val != val) + { + printf ("Bad %d: %x, %d vs %x, %d\n", __LINE__, addr, SMBUS, op.addr, op.type); + exit (1); + } +} + +static void +write_mchbar32 (u32 addr, u32 val) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (op.is_in || op.data_width != 32 || op.addr != addr || op.val != val || op.type != OPCODE_MCHBAR) + { + printf ("Bad [%x] = %x vs [%x] = %llx\n", addr, val, op.addr, op.val); + exit (1); + } +} + +static void +write_acpi32 (u32 addr, u32 val) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (op.is_in || op.data_width != 32 || op.addr != addr || op.val != val || op.type != ACPI) + { + printf ("Bad [%x] = %x vs [%x] = %llx\n", addr, val, op.addr, op.val); + exit (1); + } +} + +static void +write_mchbar16 (u32 addr, u16 val) +{ + struct opcode op; + fetch_opcode (&op); + if (op.is_in || op.data_width != 16 || op.addr != addr || op.val != val || op.type != OPCODE_MCHBAR) + { + printf ("Bad %d: %x, %x vs %x, %llx\n", __LINE__, addr, val, op.addr, op.val); + exit (1); + } +} + +static void +write_acpi16 (u32 addr, u16 val) +{ + struct opcode op; + fetch_opcode (&op); + if (op.is_in || op.data_width != 16 || op.addr != addr || op.val != val || op.type != ACPI) + { + printf ("Bad %d: %x, %x vs %x, %llx\n", __LINE__, addr, val, op.addr, op.val); + exit (1); + } +} + +static void +write_tco16 (u32 addr, u16 val) +{ + struct opcode op; + fetch_opcode (&op); + if (op.is_in || op.data_width != 16 || op.addr != addr || op.val != val || op.type != TCO) + { + printf ("Bad %d: %x, %x vs %x, %llx\n", __LINE__, addr, val, op.addr, op.val); + exit (1); + } +} + +static void +write_tco8 (u32 addr, u8 val) +{ + struct opcode op; + fetch_opcode (&op); + if (op.is_in || op.data_width != 8 || op.addr != addr || op.val != val || op.type != TCO) + { + printf ("Bad %d: %x, %x vs %x, %llx\n", __LINE__, addr, val, op.addr, op.val); + exit (1); + } +} + +static void +write_mchbar8 (u32 addr, u8 val) +{ + struct opcode op; + fetch_opcode (&op); + if (op.is_in || op.data_width != 8 || op.addr != addr || op.val != val || op.type != OPCODE_MCHBAR) + { + printf ("Bad %d: %x, %x vs %x, %llx\n", __LINE__, addr, val, op.addr, op.val); + exit (1); + } +} + +static u32 +read_mchbar32 (u32 addr) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (!op.is_in || op.data_width != 32 || op.addr != addr || op.type != OPCODE_MCHBAR) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static u32 +read_mchbar32_bypass (u32 addr) +{ + return read_mchbar32 (addr); +} + +static u32 +read_acpi32 (u32 addr) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (!op.is_in || op.data_width != 32 || op.addr != addr || op.type != ACPI) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static u16 +read_mchbar16 (u32 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (!op.is_in || op.data_width != 16 || op.addr != addr || op.type != OPCODE_MCHBAR) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static u16 +read_tco16 (u32 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (!op.is_in || op.data_width != 16 || op.addr != addr || op.type != TCO) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static u16 +read_acpi16 (u32 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (!op.is_in || op.data_width != 16 || op.addr != addr || op.type != ACPI) + { + printf ("Bad %d: %x, 16 vs %x, %d\n", __LINE__, addr, op.addr, op.data_width); + exit (1); + } + return op.val; +} + +static u8 +read_mchbar8 (u32 addr) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (!op.is_in || op.data_width != 8 || op.addr != addr || op.type != OPCODE_MCHBAR) + { + printf ("Bad %d: %x vs %x\n", __LINE__, addr, op.addr); + exit (1); + } + return op.val; +} + +static u8 +read_tco8 (u32 addr) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (!op.is_in || op.data_width != 8 || op.addr != addr || op.type != TCO) + { + printf ("Bad %d: %x vs %x\n", __LINE__, addr, op.addr); + exit (1); + } + return op.val; +} + +static u32 +read32 (u32 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (!op.is_in || op.data_width != 32 || op.addr != addr || op.type != MEM) + { + printf ("Bad %d: %x vs %x\n", __LINE__, addr, op.addr); + exit (1); + } + return op.val; +} + +static u64 +read64 (u32 addr) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (!op.is_in || op.data_width != 64 || op.addr != addr || op.type != MEM) + { + printf ("Bad %d: %x vs %x\n", __LINE__, addr, op.addr); + exit (1); + } + return op.val; +} + +static void +clflush (u32 addr) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + + if (op.addr != addr || op.type != CLFLUSH) + { + printf ("Bad %d: %x vs %x\n", __LINE__, addr, op.addr); + exit (1); + } +} + +static void +read128 (u32 addr, u64 *out) +{ + out[0] = read64 (addr); + out[1] = read64 (addr + 8); +} + +static u16 +read16 (u32 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (!op.is_in || op.data_width != 16 || op.addr != addr || op.type != MEM) + { + printf ("Bad %d: %x vs %x\n", __LINE__, addr, op.addr); + exit (1); + } + return op.val; +} + +static u8 +read8 (u32 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (!op.is_in || op.data_width != 8 || op.addr != addr || op.type != MEM) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static u8 +inb (u32 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (!op.is_in || op.data_width != 8 || op.addr != addr || op.type != PCIO) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static void +outb (u8 val, u32 addr) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (op.is_in || op.data_width != 8 || op.addr != addr || op.type != PCIO || op.val != val) + { + printf ("Bad %d: %x, %x, 8, %d, 0 vs %x, %llx, %d, %d, %d\n", __LINE__, addr, val, PCIO, op.addr, op.val, op.data_width, op.type, + op.is_in); + printf ("%x, %llx, %d\n", val, op.val, op.val != val); + exit (1); + } +} + +static void +outw (u16 val, u32 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (op.is_in || op.data_width != 16 || op.addr != addr || op.type != PCIO || op.val != val) + { + printf ("Bad %d: %x, %x vs %x, %llx\n", __LINE__, addr, val, op.addr, op.val); + exit (1); + } +} + +static void +outl (u32 val, u32 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (op.is_in || op.data_width != 32 || op.addr != addr || op.type != PCIO || op.val != val) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } +} + +static u32 +inl (u32 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (!op.is_in || op.data_width != 32 || op.addr != addr || op.type != PCIO) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static u16 +inw (u32 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (!op.is_in || op.data_width != 16 || op.addr != addr || op.type != PCIO) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static void +pci_mm_write8 (int bus, int dev, int func, u32 addr, u8 val) +{ + struct opcode op; + if (bus == 0xff) + { + write8 (DEFAULT_PCIEXBAR | (bus << 20) | (dev << 15) | (func << 12) | addr, val); + return; + } + + fetch_opcode (&op); + if (op.is_in || op.data_width != 8 || op.addr != addr || op.type != PCIMM || op.dev != dev || op.func != func || op.bus != bus || op.val != val) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } +} + +static void +pci_write8 (int bus, int dev, int func, u32 addr, u8 val) +{ + struct opcode op; + fetch_opcode (&op); + if (op.is_in || op.data_width != 8 || op.addr != addr || op.type != PCI || op.dev != dev || op.func != func || op.bus != bus || op.val != val) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } +} + +static void +pci_write16 (int bus, int dev, int func, u32 addr, u16 val) +{ + struct opcode op; + fetch_opcode (&op); + if (op.is_in || op.data_width != 16 || op.addr != addr || op.type != PCI || op.dev != dev || op.func != func || op.bus != bus || op.val != val) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } +} + +static void +pci_mm_write16 (int bus, int dev, int func, u32 addr, u16 val) +{ + struct opcode op; + fetch_opcode (&op); + if (op.is_in || op.data_width != 16 || op.addr != addr || op.type != PCIMM || op.dev != dev || op.func != func || op.bus != bus || op.val != val) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } +} + +static void +pci_mm_write32 (int bus, int dev, int func, u32 addr, u32 val) +{ + struct opcode op; + if (bus == 0xff) + { + write32 (DEFAULT_PCIEXBAR | (bus << 20) | (dev << 15) | (func << 12) | addr, val); + return; + } + + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + + if (op.is_in || op.data_width != 32 || op.addr != addr || op.type != PCIMM || op.dev != dev || op.func != func || op.bus != bus || op.val != val) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } +} + +static void +pci_write32 (int bus, int dev, int func, u32 addr, u32 val) +{ + struct opcode op; + fetch_opcode (&op); + if (op.is_in || op.data_width != 32 || op.addr != addr || op.type != PCI || op.dev != dev || op.func != func || op.bus != bus || op.val != val) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } +} + +static u8 +pci_read8 (int bus, int dev, int func, u32 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (!op.is_in || op.data_width != 8 || op.addr != addr || op.type != PCI || op.dev != dev || op.func != func || op.bus != bus) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static u8 +nvram_read (u8 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (!op.is_in || op.addr != addr || op.type != NVRAM) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static void +nvram_write (u8 addr, u8 val) +{ + struct opcode op; + fetch_opcode (&op); + if (op.is_in || op.addr != addr || op.type != NVRAM || op.val != val) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } +} + +static u8 +pci_mm_read8 (int bus, int dev, int func, u32 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (!op.is_in || op.data_width != 8 || op.addr != addr || op.type != PCIMM || op.dev != op.dev || op.func != op.func || op.bus != op.bus) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static u16 +pci_mm_read16 (int bus, int dev, int func, u32 addr) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (!op.is_in || op.data_width != 16 || op.addr != addr || op.type != PCIMM || op.dev != dev || op.func != func || op.bus != bus) + { + printf ("Bad %d: %x vs %x\n", __LINE__, addr, op.addr); + exit (1); + } + return op.val; +} + +static u16 +pci_read16 (int bus, int dev, int func, u32 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (!op.is_in || op.data_width != 16 || op.addr != addr || op.type != PCI || op.dev != op.dev || op.func != op.func || op.bus != op.bus) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static u32 +pci_mm_read32 (int bus, int dev, int func, u32 addr) +{ + struct opcode op; + + if (bus == 0xff) + return read32 (DEFAULT_PCIEXBAR | (bus << 20) | (dev << 15) | (func << 12) | addr); + + fetch_opcode (&op); + if (!op.is_in || op.data_width != 32 || op.addr != addr || op.type != PCIMM || op.dev != op.dev || op.func != op.func || op.bus != op.bus) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static u32 +pci_read32 (int bus, int dev, int func, u32 addr) +{ + struct opcode op; + if (!fetch_opcode (&op)) + { + printf ("EOF\n"); + exit (1); + } + if (!op.is_in || op.data_width != 32 || op.addr != addr || op.type != PCI || op.dev != op.dev || op.func != op.func || op.bus != op.bus) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static u64 +rdmsr (u32 addr) +{ + struct opcode op; + fetch_opcode (&op); + if (!op.is_in || op.addr != addr || op.type != MSR) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static u64 +my_write_msr (u32 addr, u64 val) +{ + struct opcode op; + fetch_opcode (&op); + if (op.is_in || op.addr != addr || op.type != MSR || op.val != val) + { + printf ("Bad %d\n", __LINE__); + exit (1); + } + return op.val; +} + +static void +die (const char *msg) +{ + printf ("%s\n", msg); + exit (1); +} + +static void +intel_early_me_init (void) +{ +} + +static unsigned +intel_early_me_uma_size (void) +{ + u32 t; + t = pci_mm_read32 (HECIDEV, 0x44); + if ( t & 0x10000 ) + return t & 0x3F; + return 0; +} + +static u8 +read_mchbar8_bypass (u32 addr) +{ + return read_mchbar8 (addr); +} + +#define printk(condition, fmt, args...) printf(fmt, ## args) + +static const struct ram_training * +get_cached_training (void) +{ + static const struct ram_training ret = + { +#if 0 + .lane_timings = + { + { + { + { + { 5, 5, 3, 4, 4, 3, 4, 4, 21 }, + { 5, 4, 2, 5, 4, 3, 4, 4, 21 } + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + { + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + }, + { + { + { + { 0x6e, 0x64, 0x7b, 0x56, 0xbd, 0xa0, 0xae, 0xad, 0x100 }, + { 0x6e, 0x67, 0x7a, 0x54, 0xbd, 0x9f, 0xac, 0xac, 0x100 } + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + { + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + }, + { + { + { + { 0x59, 0x55, 0x6d, 0x44, 0xa3, 0x76, 0x90, 0x81, 0x80 }, + { 0x58, 0x51, 0x6b, 0x41, 0xa1, 0x75, 0x8e, 0x7f, 0x80 }, + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + { + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + }, + { + { + { + { 0x78, 0x74, 0x8b, 0x64, 0xc1, 0x94, 0xaf, 0x9d, 0x80 }, + { 0x76, 0x6e, 0x88, 0x60, 0xbe, 0x93, 0xae, 0x9d, 0x80 }, + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + { + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + } + }, + .reg_178 = 0x42, + .reg_10b = 1, +#else + .lane_timings = + { + { + { + { + { 5, 5, 3, 5, 4, 4, 5, 3, 21 }, + { 6, 6, 3, 4, 4, 4, 4, 4, 21 } + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + { + { + { 3, 4, 5, 3, 2, 4, 3, 4, 21 }, + { 4, 3, 5, 4, 2, 5, 4, 4, 21 }, + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + }, + { + { + { + { 0x6f, 0x66, 0x82, 0x58, 0xc5, 0xa6, 0xb4, 0xb2, 0x100 }, + { 0x70, 0x68, 0x83, 0x59, 0xc5, 0xa5, 0xb4, 0xb2, 0x100 } + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + { + { + { 0x91, 0x88, 0x99, 0x76, 0xdc, 0xb8, 0xcf, 0xc5, 0x100 }, + { 0x94, 0x8d, 0x9c, 0x76, 0xde, 0xba, 0xce, 0xc6, 0x100 }, + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + }, + { + { + { + { 0x60, 0x5b, 0x74, 0x4a, 0xa9, 0x7d, 0x96, 0x86, 0x80 }, + { 0x5d, 0x59, 0x72, 0x49, 0xa8, 0x7a, 0x97, 0x86, 0x80 }, + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + { + { + { 0x5b, 0x53, 0x6c, 0x49, 0xa8, 0x79, 0x92, 0x84, 0x80 }, + { 0x5b, 0x51, 0x6d, 0x48, 0xa7, 0x7a, 0x92, 0x82, 0x80 }, + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + }, + { + { + { + { 0x7f, 0x7a, 0x92, 0x6a, 0xc7, 0x9c, 0xb7, 0xa5, 0x80 }, + { 0x7d, 0x77, 0x8f, 0x69, 0xc6, 0x98, 0xb7, 0xa5, 0x80 }, + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + { + { + { 0x79, 0x6f, 0x89, 0x65, 0xc4, 0x96, 0xaf, 0x9f, 0x80 }, + { 0x78, 0x6b, 0x89, 0x64, 0xc2, 0x98, 0xaf, 0x9d, 0x80 }, + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + } + }, + .reg_178 = 0, + .reg_10b = 1, +#endif + }; + return &ret; +} + +#define udelay(x) diff --git a/src/northbridge/intel/sandybridge/raminit_tables.c b/src/northbridge/intel/sandybridge/raminit_tables.c new file mode 100644 index 0000000..7c94a66 --- /dev/null +++ b/src/northbridge/intel/sandybridge/raminit_tables.c @@ -0,0 +1,1238 @@ +/* [CHANNEL][EXT_REVISON][LANE][2*SLOT+RANK][CLOCK_SPEED] */ +const u8 u8_FFFD1240[2][5][9][4][4] = { + { + { + { + { 0x3b, 0x53, 0x57, 0x5c }, + { 0x3b, 0x52, 0x57, 0x5c }, + { 0x3b, 0x4d, 0x51, 0x54 }, + { 0x3b, 0x4d, 0x51, 0x54 } + }, + { + { 0x46, 0x63, 0x6b, 0x74 }, + { 0x46, 0x62, 0x6b, 0x73 }, + { 0x46, 0x5d, 0x65, 0x6c }, + { 0x46, 0x5d, 0x65, 0x6c } + }, + { + { 0x51, 0x71, 0x7e, 0x8a }, + { 0x51, 0x71, 0x7d, 0x8a }, + { 0x51, 0x6c, 0x77, 0x82 }, + { 0x51, 0x6c, 0x77, 0x82 } + }, + { + { 0x5c, 0x7b, 0x8a, 0x99 }, + { 0x5c, 0x7b, 0x89, 0x98 }, + { 0x5c, 0x75, 0x83, 0x90 }, + { 0x5c, 0x75, 0x83, 0x90 } + }, + { + { 0x65, 0x81, 0x91, 0xa2 }, + { 0x65, 0x81, 0x91, 0xa1 }, + { 0x65, 0x7c, 0x8b, 0x9a }, + { 0x65, 0x7c, 0x8b, 0x9a } + }, + { + { 0x70, 0x8b, 0x9e, 0xb1 }, + { 0x70, 0x8b, 0x9d, 0xb0 }, + { 0x70, 0x86, 0x97, 0xa9 }, + { 0x70, 0x86, 0x97, 0xa9 } + }, + { + { 0x73, 0x8f, 0xa3, 0xb7 }, + { 0x73, 0x8f, 0xa3, 0xb6 }, + { 0x73, 0x8a, 0x9d, 0xaf }, + { 0x73, 0x8a, 0x9d, 0xaf }, + }, + { + { 0x78, 0x99, 0xaf, 0xc5 }, + { 0x78, 0x98, 0xae, 0xc4 }, + { 0x78, 0x93, 0xa8, 0xbd }, + { 0x78, 0x93, 0xa8, 0xbd }, + }, + { + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 } + }, + }, + { + { + { 0x3b, 0x53, 0x57, 0x5c }, + { 0x3b, 0x52, 0x57, 0x5c }, + { 0x3b, 0x4d, 0x51, 0x54 }, + { 0x3b, 0x4d, 0x51, 0x54 } + }, + { + { 0x46, 0x63, 0x6b, 0x74 }, + { 0x46, 0x62, 0x6b, 0x73 }, + { 0x46, 0x5d, 0x65, 0x6c }, + { 0x46, 0x5d, 0x65, 0x6c } + }, + { + { 0x51, 0x71, 0x7e, 0x8a }, + { 0x51, 0x71, 0x7d, 0x8a }, + { 0x51, 0x6c, 0x77, 0x82 }, + { 0x51, 0x6c, 0x77, 0x82 } + }, + { + { 0x5c, 0x7b, 0x8a, 0x99 }, + { 0x5c, 0x7b, 0x89, 0x98 }, + { 0x5c, 0x75, 0x83, 0x90 }, + { 0x5c, 0x75, 0x83, 0x90 } + }, + { + { 0x65, 0x81, 0x91, 0xa2 }, + { 0x65, 0x81, 0x91, 0xa1 }, + { 0x65, 0x7c, 0x8b, 0x9a }, + { 0x65, 0x7c, 0x8b, 0x9a } + }, + { + { 0x70, 0x8b, 0x9e, 0xb1 }, + { 0x70, 0x8b, 0x9d, 0xb0 }, + { 0x70, 0x86, 0x97, 0xa9 }, + { 0x70, 0x86, 0x97, 0xa9 } + }, + { + { 0x73, 0x8f, 0xa3, 0xb7 }, + { 0x73, 0x8f, 0xa3, 0xb6 }, + { 0x73, 0x8a, 0x9d, 0xaf }, + { 0x73, 0x8a, 0x9d, 0xaf } + }, + { + { 0x78, 0x99, 0xaf, 0xc5 }, + { 0x78, 0x98, 0xae, 0xc4 }, + { 0x78, 0x93, 0xa8, 0xbd }, + { 0x78, 0x93, 0xa8, 0xbd } + }, + { + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 } + }, + }, + { + { + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e } + }, + { + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e } + }, + { + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d } + }, + { + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d } + }, + { + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 } + }, + { + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 } + }, + { + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 } + }, + { + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 } + }, + { + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 } + }, + }, + { + { + { 0x55, 0x5b, 0x62, 0x61 }, + { 0x55, 0x5b, 0x62, 0x61 }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e } + }, + { + { 0x55, 0x5b, 0x62, 0x61 }, + { 0x55, 0x5b, 0x62, 0x61 }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e } + }, + { + { 0x5d, 0x67, 0x71, 0x73 }, + { 0x5d, 0x67, 0x71, 0x73 }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d } + }, + { + { 0x5d, 0x67, 0x71, 0x73 }, + { 0x5d, 0x67, 0x71, 0x73 }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d } + }, + { + { 0x6b, 0x7a, 0x88, 0x8f }, + { 0x6b, 0x7a, 0x88, 0x8f }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 } + }, + { + { 0x6b, 0x7a, 0x88, 0x8f }, + { 0x6b, 0x7a, 0x88, 0x8f }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 } + }, + { + { 0x75, 0x87, 0x98, 0xa2 }, + { 0x75, 0x87, 0x98, 0xa2 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 } + }, + { + { 0x75, 0x87, 0x98, 0xa2 }, + { 0x75, 0x87, 0x98, 0xa2 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 } + }, + { + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 } + }, + }, + { + { + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e } + }, + { + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e } + }, + { + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d } + }, + { + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d } + }, + { + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 } + }, + { + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 } + }, + { + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 } + }, + { + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 } + }, + { + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 } + }, + }, + }, + { + { + { + { 0x41, 0x59, 0x5f, 0x65 }, + { 0x41, 0x59, 0x5f, 0x65 }, + { 0x41, 0x53, 0x58, 0x5d }, + { 0x41, 0x53, 0x58, 0x5d } + }, + { + { 0x4b, 0x69, 0x73, 0x7d }, + { 0x4b, 0x69, 0x73, 0x7d }, + { 0x4b, 0x63, 0x6c, 0x75 }, + { 0x4b, 0x63, 0x6c, 0x75 }, + }, + { + { 0x54, 0x72, 0x7f, 0x8b }, + { 0x54, 0x72, 0x7f, 0x8b }, + { 0x54, 0x6c, 0x78, 0x83 }, + { 0x54, 0x6c, 0x78, 0x83 }, + }, + { + { 0x61, 0x81, 0x91, 0xa2 }, + { 0x61, 0x81, 0x91, 0xa2 }, + { 0x61, 0x7b, 0x8a, 0x99 }, + { 0x61, 0x7b, 0x8a, 0x99 }, + }, + { + { 0x6a, 0x87, 0x99, 0xab }, + { 0x6a, 0x87, 0x99, 0xab }, + { 0x6a, 0x82, 0x92, 0xa3 }, + { 0x6a, 0x82, 0x92, 0xa3 }, + }, + { + { 0x71, 0x8b, 0x9e, 0xb1 }, + { 0x71, 0x8b, 0x9e, 0xb1 }, + { 0x71, 0x86, 0x98, 0xa9 }, + { 0x71, 0x86, 0x98, 0xa9 }, + }, + { + { 0x75, 0x95, 0xab, 0xc0 }, + { 0x75, 0x95, 0xab, 0xc0 }, + { 0x75, 0x90, 0xa4, 0xb8 }, + { 0x75, 0x90, 0xa4, 0xb8 }, + }, + { + { 0x7d, 0x9f, 0xb6, 0xce }, + { 0x7d, 0x9f, 0xb6, 0xce }, + { 0x7d, 0x99, 0xb0, 0xc6 }, + { 0x7d, 0x99, 0xb0, 0xc6 }, + }, + { + { 0x61, 0x7e, 0x80, 0x9f }, + { 0x61, 0x7e, 0x95, 0x9f }, + { 0x61, 0x7e, 0x80, 0x9f }, + { 0x61, 0x7e, 0x80, 0x9f }, + }, + }, + { + { + { 0x41, 0x59, 0x5f, 0x65 }, + { 0x41, 0x59, 0x5f, 0x65 }, + { 0x41, 0x53, 0x58, 0x5d }, + { 0x41, 0x53, 0x58, 0x5d }, + }, + { + { 0x4b, 0x69, 0x73, 0x7d }, + { 0x4b, 0x69, 0x73, 0x7d }, + { 0x4b, 0x63, 0x6c, 0x75 }, + { 0x4b, 0x63, 0x6c, 0x75 }, + }, + { + { 0x54, 0x72, 0x7f, 0x8b }, + { 0x54, 0x72, 0x7f, 0x8b }, + { 0x54, 0x6c, 0x78, 0x83 }, + { 0x54, 0x6c, 0x78, 0x83 }, + }, + { + { 0x61, 0x81, 0x91, 0xa2 }, + { 0x61, 0x81, 0x91, 0xa2 }, + { 0x61, 0x7b, 0x8a, 0x99 }, + { 0x61, 0x7b, 0x8a, 0x99 }, + }, + { + { 0x6a, 0x87, 0x99, 0xab }, + { 0x6a, 0x87, 0x99, 0xab }, + { 0x6a, 0x82, 0x92, 0xa3 }, + { 0x6a, 0x82, 0x92, 0xa3 }, + }, + { + { 0x71, 0x8b, 0x9e, 0xb1 }, + { 0x71, 0x8b, 0x9e, 0xb1 }, + { 0x71, 0x86, 0x98, 0xa9 }, + { 0x71, 0x86, 0x98, 0xa9 }, + }, + { + { 0x75, 0x95, 0xab, 0xc0 }, + { 0x75, 0x95, 0xab, 0xc0 }, + { 0x75, 0x90, 0xa4, 0xb8 }, + { 0x75, 0x90, 0xa4, 0xb8 }, + }, + { + { 0x7d, 0x9f, 0xb6, 0xce }, + { 0x7d, 0x9f, 0xb6, 0xce }, + { 0x7d, 0x99, 0xb0, 0xc6 }, + { 0x7d, 0x99, 0xb0, 0xc6 }, + }, + { + { 0x61, 0x7e, 0x80, 0x9f }, + { 0x61, 0x7e, 0x80, 0x9f }, + { 0x61, 0x7e, 0x80, 0x9f }, + { 0x61, 0x7e, 0x80, 0x9f }, + }, + }, + { + { + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + }, + { + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + }, + { + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + }, + { + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + }, + { + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + }, + { + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + }, + { + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + }, + { + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + }, + { + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + }, + }, + { + { + { 0x56, 0x5d, 0x65, 0x64 }, + { 0x56, 0x5d, 0x65, 0x64 }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + }, + { + { 0x56, 0x5d, 0x65, 0x64 }, + { 0x56, 0x5d, 0x65, 0x64 }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + }, + { + { 0x5e, 0x68, 0x72, 0x74 }, + { 0x5e, 0x68, 0x72, 0x74 }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + }, + { + { 0x5e, 0x68, 0x72, 0x74 }, + { 0x5e, 0x68, 0x72, 0x74 }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + }, + { + { 0x68, 0x76, 0x83, 0x89 }, + { 0x68, 0x76, 0x83, 0x89 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + }, + { + { 0x68, 0x76, 0x83, 0x89 }, + { 0x68, 0x76, 0x83, 0x89 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + }, + { + { 0x70, 0x80, 0x90, 0x98 }, + { 0x70, 0x80, 0x90, 0x98 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + }, + { + { 0x70, 0x80, 0x90, 0x98 }, + { 0x70, 0x80, 0x90, 0x98 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + }, + { + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + }, + }, + { + { + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + }, + { + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + { 0x57, 0x5e, 0x66, 0x6e }, + }, + { + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + }, + { + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + { 0x5e, 0x69, 0x73, 0x7d }, + }, + { + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + }, + { + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + { 0x69, 0x77, 0x85, 0x92 }, + }, + { + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + }, + { + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + { 0x70, 0x80, 0x91, 0xa1 }, + }, + { + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + { 0x5c, 0x79, 0x87, 0x94 }, + } + } + } +}; + +const u16 u16_FFFE0EB8[2][4] = { + { 0x0000, 0x0000, 0x0000, 0x0000 }, + { 0x0000, 0x0000, 0x0000, 0x0000 } +}; + +/* [CARD][LANE][CLOCK_SPEED] */ +const u16 u16_ffd1188[2][9][4] = { + { + { 0xfff9, 0xfff7, 0xfff5, 0xfff2 }, + { 0xfff9, 0xfff7, 0xfff5, 0xfff2 }, + { 0xfffb, 0xfff9, 0xfff7, 0xfff6 }, + { 0xfffb, 0xfff9, 0xfff7, 0xfff6 }, + { 0xfffc, 0xfffb, 0xfffa, 0xfff8 }, + { 0xfffc, 0xfffb, 0xfffa, 0xfff8 }, + { 0xfffd, 0xfffc, 0xfffb, 0xfffa }, + { 0xfffd, 0xfffc, 0xfffb, 0xfffa }, + { 0x0000, 0x0000, 0x0000, 0x0000 } + }, + { + { 0x0001, 0x0001, 0x0001, 0x0002 }, + { 0xfffa, 0xfff8, 0xfff6, 0xfff4 }, + { 0x0001, 0x0002, 0x0002, 0x0003 }, + { 0xffe2, 0xffd8, 0xffce, 0xffc4 }, + { 0x0021, 0x002d, 0x0038, 0x0043 }, + { 0x0004, 0x0005, 0x0006, 0x0007 }, + { 0x000e, 0x0013, 0x0018, 0x001d }, + { 0x0009, 0x000c, 0x000f, 0x0012 }, + { 0x0000, 0x0000, 0x0000, 0x0000 } + } +}; + +/* [REVISION][CHANNEL][CLOCK_INDEX][?] */ +const u8 u8_FFFD1891[2][2][4][12] = { + { + { + { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x08, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 }, + }, + { + { 0x04, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x05, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x07, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x08, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 }, + } + }, + { + { + { 0x06, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x08, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x0a, 0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x0c, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 }, + }, + { + { 0x06, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x08, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x0a, 0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x0c, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74 } + } + } +}; + +const u8 u8_FFFD17E0[2][5][4][4] = { + { + { + { 0x00, 0x0c, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + { 0x23, 0x19, 0x0f, 0x05 }, + { 0x23, 0x19, 0x0f, 0x05 }, + }, + { + { 0x00, 0x0c, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + { 0x23, 0x19, 0x0f, 0x05 }, + { 0x23, 0x19, 0x0f, 0x05 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + { 0x44, 0x45, 0x47, 0x05 }, + { 0x44, 0x45, 0x47, 0x05 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + { 0x44, 0x45, 0x46, 0x44 }, + { 0x44, 0x45, 0x46, 0x44 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + { 0x2a, 0x24, 0x1e, 0x16 }, + { 0x2a, 0x24, 0x1e, 0x16 }, + }, + }, + { + { + { 0x00, 0x08, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + { 0x27, 0x1e, 0x16, 0x0d }, + { 0x27, 0x1e, 0x16, 0x0d }, + }, + { + { 0x00, 0x08, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + { 0x27, 0x1e, 0x16, 0x0d }, + { 0x27, 0x1e, 0x16, 0x0d }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + { 0x44, 0x45, 0x47, 0x05 }, + { 0x44, 0x45, 0x47, 0x05 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + { 0x43, 0x44, 0x45, 0x43 }, + { 0x43, 0x44, 0x45, 0x43 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + { 0x2a, 0x24, 0x1e, 0x16 }, + { 0x2a, 0x24, 0x1e, 0x16 }, + }, + }, +}; + +const u8 u8_FFFD0C78[2][5][4][2][2][4] = { + { + { + { + { + { 0x00, 0x00, 0x03, 0x04 }, + { 0x00, 0x00, 0x03, 0x04 }, + }, + { + { 0x00, 0x00, 0x03, 0x04 }, + { 0x00, 0x00, 0x03, 0x04 }, + }, + }, + { + { + { 0x00, 0x02, 0x0d, 0x0f }, + { 0x00, 0x02, 0x0d, 0x0f }, + }, + { + { 0x00, 0x02, 0x0d, 0x0f }, + { 0x00, 0x02, 0x0d, 0x0f }, + }, + }, + { + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + }, + { + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + }, + }, + { + { + { + { 0x00, 0x00, 0x03, 0x04 }, + { 0x00, 0x00, 0x03, 0x04 }, + }, + { + { 0x00, 0x00, 0x03, 0x04 }, + { 0x00, 0x00, 0x03, 0x04 }, + }, + }, + { + { + { 0x00, 0x02, 0x0d, 0x0f }, + { 0x00, 0x02, 0x0d, 0x0f }, + }, + { + { 0x00, 0x02, 0x0d, 0x0f }, + { 0x00, 0x02, 0x0d, 0x0f }, + }, + }, + { + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + }, + { + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + }, + }, + { + { + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + }, + { + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + }, + { + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + }, + { + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + }, + }, + { + { + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + }, + { + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + }, + { + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + }, + { + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + }, + }, + { + { + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + }, + { + { + { 0x04, 0x06, 0x08, 0x0a }, + { 0x04, 0x06, 0x08, 0x0a }, + }, + { + { 0x04, 0x06, 0x08, 0x0a }, + { 0x04, 0x06, 0x08, 0x0a }, + }, + }, + { + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + }, + { + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + }, + }, + }, + { + { + { + { + { 0x00, 0x00, 0x03, 0x04 }, + { 0x00, 0x00, 0x03, 0x04 }, + }, + { + { 0x00, 0x00, 0x03, 0x04 }, + { 0x00, 0x00, 0x03, 0x04 }, + }, + }, + { + { + { 0x00, 0x06, 0x0d, 0x0f }, + { 0x00, 0x06, 0x0d, 0x0f }, + }, + { + { 0x00, 0x06, 0x0d, 0x0f }, + { 0x00, 0x06, 0x0d, 0x0f }, + }, + }, + { + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + }, + { + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + }, + }, + { + { + { + { 0x00, 0x00, 0x03, 0x04 }, + { 0x00, 0x00, 0x03, 0x04 }, + }, + { + { 0x00, 0x00, 0x03, 0x04 }, + { 0x00, 0x00, 0x03, 0x04 }, + }, + }, + { + { + { 0x00, 0x06, 0x13, 0x17 }, + { 0x00, 0x06, 0x13, 0x17 }, + }, + { + { 0x00, 0x06, 0x13, 0x17 }, + { 0x00, 0x06, 0x13, 0x17 }, + }, + }, + { + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + }, + { + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + }, + }, + { + { + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + }, + { + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + }, + { + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + }, + { + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + { + { 0x04, 0x05, 0x07, 0x08 }, + { 0x04, 0x05, 0x07, 0x08 }, + }, + }, + }, + { + { + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + }, + { + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + }, + { + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + }, + { + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + { + { 0x06, 0x07, 0x09, 0x0b }, + { 0x06, 0x07, 0x09, 0x0b }, + }, + }, + }, + { + { + { + { 0x00, 0x00, 0x03, 0x04 }, + { 0x00, 0x00, 0x03, 0x04 }, + }, + { + { 0x00, 0x00, 0x03, 0x04 }, + { 0x00, 0x00, 0x03, 0x04 }, + }, + }, + { + { + { 0x04, 0x06, 0x08, 0x0a }, + { 0x00, 0x06, 0x0d, 0x0f }, + }, + { + { 0x00, 0x06, 0x0d, 0x0f }, + { 0x00, 0x06, 0x0d, 0x0f }, + }, + }, + { + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + }, + { + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + }, + }, + }, + }, +}; + +const u16 u16_fffd0c68[3] = { 0x04c3, 0x064d, 0x068b }; + +const u16 u16_fffd0c70[2][2] = { + { 0x06c0, 0x06c9 }, + { 0x06a4, 0x06ad } +}; + +const u16 u16_fffd0c50[3][2][2] = { + { + { 0x04b9, 0x04af }, + { 0x04a5, 0x049b } + }, + { + { 0x0625, 0x062f }, + { 0x0639, 0x0643 }, + }, + { + { 0x0663, 0x066d }, + { 0x0677, 0x0681 } + } +}; + +/* [CLOCK_INDEX] */ +const u16 min_cycletime[4] = { 0x09c4, 0x0753, 0x05dc, 0x0000 }; +/* [CLOCK_INDEX] */ +const u16 min_cas_latency_time[4] = { 0x30d4, 0x2bf2, 0x2904, 0x0000 }; + +/* [CHANNEL][EXT_SILICON_REVISION][?][CLOCK_INDEX] */ +/* On other mobos may also depend on slot and rank. */ +const u8 u8_FFFD0EF8[2][5][4][4] = { + { + { + { 0x00, 0x00, 0x03, 0x04, }, + { 0x00, 0x02, 0x0d, 0x0f, }, + { 0x00, 0x00, 0x00, 0x00, }, + { 0x00, 0x00, 0x00, 0x00, }, + }, + { + { 0x00, 0x00, 0x03, 0x04, }, + { 0x00, 0x02, 0x0d, 0x0f, }, + { 0x00, 0x00, 0x00, 0x00, }, + { 0x00, 0x00, 0x00, 0x00, }, + }, + { + { 0x09, 0x0c, 0x0f, 0x12, }, + { 0x09, 0x0c, 0x0f, 0x12, }, + { 0x09, 0x0c, 0x0f, 0x12, }, + { 0x09, 0x0c, 0x0f, 0x12, }, + }, + { + { 0x06, 0x08, 0x0a, 0x0c, }, + { 0x06, 0x08, 0x0a, 0x0c, }, + { 0x06, 0x08, 0x0a, 0x0c, }, + { 0x06, 0x08, 0x0a, 0x0c, }, + }, + { + { 0x00, 0x00, 0x00, 0x00, }, + { 0x07, 0x0a, 0x0d, 0x10, }, + { 0x04, 0x06, 0x08, 0x0a, }, + { 0x04, 0x06, 0x08, 0x0a, }, + }, + }, + { + { + { 0x00, 0x00, 0x03, 0x04, }, + { 0x00, 0x06, 0x0d, 0x0f, }, + { 0x00, 0x00, 0x00, 0x00, }, + { 0x00, 0x00, 0x00, 0x00, }, + }, + { + { 0x00, 0x00, 0x03, 0x04, }, + { 0x00, 0x06, 0x13, 0x17, }, + { 0x00, 0x00, 0x00, 0x00, }, + { 0x00, 0x00, 0x00, 0x00, }, + }, + { + { 0x09, 0x0c, 0x0f, 0x12, }, + { 0x09, 0x0c, 0x0f, 0x12, }, + { 0x09, 0x0c, 0x0f, 0x12, }, + { 0x09, 0x0c, 0x0f, 0x12, }, + }, + { + { 0x09, 0x0c, 0x10, 0x13, }, + { 0x09, 0x0c, 0x10, 0x13, }, + { 0x09, 0x0c, 0x10, 0x13, }, + { 0x09, 0x0c, 0x10, 0x13, }, + }, + { + { 0x00, 0x00, 0x00, 0x00, }, + { 0x07, 0x0a, 0x0d, 0x10, }, + { 0x04, 0x06, 0x08, 0x0a, }, + { 0x04, 0x06, 0x08, 0x0a, }, + }, + }, +}; + +/* [CLOCK_SPEED] */ +const u8 u8_FFFD1218[4] = { + 0x15, 0x15, 0x15, 0x12 +}; + +const u8 lut4041[] = { 1, 3, 4, 7 }; +const u8 lut4042[] = { 62, 60, 59, 56 }; +const u8 lut4043[] = { 5, 4, 3, 2 }; + +const u16 u16_ffd1178[2][4] = { + { 0xfffb, 0xfffa, 0xfff8, 0xfff7 }, + { 0xfffb, 0xfffa, 0xfff8, 0xfff7 }, +}; +const u16 u16_fe0eb8[2][4] = { + { 0x0000, 0x0000, 0x0000, 0x0000 }, + { 0x0000, 0x0000, 0x0000, 0x0000 } +}; diff --git a/src/northbridge/intel/sandybridge/sandybridge.h b/src/northbridge/intel/sandybridge/sandybridge.h index dd8681a..18a5f23 100644 --- a/src/northbridge/intel/sandybridge/sandybridge.h +++ b/src/northbridge/intel/sandybridge/sandybridge.h @@ -21,6 +21,406 @@ #ifndef __NORTHBRIDGE_INTEL_SANDYBRIDGE_SANDYBRIDGE_H__ #define __NORTHBRIDGE_INTEL_SANDYBRIDGE_SANDYBRIDGE_H__ 1
+#ifndef __ASSEMBLER__ + +#include <stdint.h> + +typedef enum { + FSB_CLOCK_1067MHz = 0, + FSB_CLOCK_800MHz = 1, + FSB_CLOCK_667MHz = 2, +} fsb_clock_t; + +typedef enum { /* Steppings below B1 were pre-production, + conversion stepping A1 is... ? + We'll support B1, B2, B3, and conversion stepping A1. */ + STEPPING_A0 = 0, + STEPPING_A1 = 1, + STEPPING_A2 = 2, + STEPPING_A3 = 3, + STEPPING_B0 = 4, + STEPPING_B1 = 5, + STEPPING_B2 = 6, + STEPPING_B3 = 7, + STEPPING_CONVERSION_A1 = 9, +} stepping_t; + +typedef enum { + GMCH_GM45 = 0, + GMCH_GM47, + GMCH_GM49, + GMCH_GE45, + GMCH_GL40, + GMCH_GL43, + GMCH_GS40, + GMCH_GS45, + GMCH_PM45, + GMCH_UNKNOWN +} gmch_gfx_t; + +typedef enum { + MEM_CLOCK_533MHz = 0, + MEM_CLOCK_400MHz = 1, + MEM_CLOCK_333MHz = 2, + MEM_CLOCK_1067MT = 0, + MEM_CLOCK_800MT = 1, + MEM_CLOCK_667MT = 2, +} mem_clock_t; + +typedef enum { + DDR1 = 1, + DDR2 = 2, + DDR3 = 3, +} ddr_t; + +typedef enum { + CHANNEL_MODE_SINGLE, + CHANNEL_MODE_DUAL_ASYNC, + CHANNEL_MODE_DUAL_INTERLEAVED, +} channel_mode_t; + +typedef enum { /* as in DDR3 spd */ + CHIP_WIDTH_x4 = 0, + CHIP_WIDTH_x8 = 1, + CHIP_WIDTH_x16 = 2, + CHIP_WIDTH_x32 = 3, +} chip_width_t; + +typedef enum { /* as in DDR3 spd */ + CHIP_CAP_256M = 0, + CHIP_CAP_512M = 1, + CHIP_CAP_1G = 2, + CHIP_CAP_2G = 3, + CHIP_CAP_4G = 4, + CHIP_CAP_8G = 5, + CHIP_CAP_16G = 6, +} chip_capacity_t; + +typedef struct { + unsigned int CAS; + fsb_clock_t fsb_clock; + mem_clock_t mem_clock; + channel_mode_t channel_mode; + unsigned int tRAS; + unsigned int tRP; + unsigned int tRCD; + unsigned int tRFC; + unsigned int tWR; + unsigned int tRD; + unsigned int tRRD; + unsigned int tFAW; + unsigned int tWL; +} timings_t; + +typedef struct { + unsigned int card_type; /* 0x0: unpopulated, + 0xa - 0xf: raw card type A - F */ + chip_width_t chip_width; + chip_capacity_t chip_capacity; + unsigned int page_size; /* of whole DIMM in Bytes (4096 or 8192) */ + unsigned int banks; + unsigned int ranks; + unsigned int rank_capacity_mb; /* per rank in Mega Bytes */ +} dimminfo_t; + +/* The setup is one DIMM per channel, so there's no need to find a + common timing setup between multiple chips (but chip and controller + still need to be coordinated */ +typedef struct { + stepping_t stepping; + int txt_enabled; + int cores; + gmch_gfx_t gfx_type; + int gs45_low_power_mode; /* low power mode of GMCH_GS45 */ + int max_ddr2_mhz; + int max_ddr3_mt; + fsb_clock_t max_fsb; + int max_fsb_mhz; + int max_render_mhz; + + int spd_type; + timings_t selected_timings; + dimminfo_t dimms[2]; +} sysinfo_t; + +#define TOTAL_CHANNELS 2 +#define CHANNEL_IS_POPULATED(dimms, idx) (dimms[idx].card_type != 0) +#define CHANNEL_IS_CARDF(dimms, idx) (dimms[idx].card_type == 0xf) +#define IF_CHANNEL_POPULATED(dimms, idx) if (dimms[idx].card_type != 0) +#define FOR_EACH_CHANNEL(idx) \ + for (idx = 0; idx < TOTAL_CHANNELS; ++idx) +#define FOR_EACH_POPULATED_CHANNEL(dimms, idx) \ + FOR_EACH_CHANNEL(idx) IF_CHANNEL_POPULATED(dimms, idx) + +#define RANKS_PER_CHANNEL 4 /* Only two may be populated */ +#define IF_RANK_POPULATED(dimms, ch, r) \ + if (dimms[ch].card_type && ((r) < dimms[ch].ranks)) +#define FOR_EACH_RANK_IN_CHANNEL(r) \ + for (r = 0; r < RANKS_PER_CHANNEL; ++r) +#define FOR_EACH_POPULATED_RANK_IN_CHANNEL(dimms, ch, r) \ + FOR_EACH_RANK_IN_CHANNEL(r) IF_RANK_POPULATED(dimms, ch, r) +#define FOR_EACH_RANK(ch, r) \ + FOR_EACH_CHANNEL(ch) FOR_EACH_RANK_IN_CHANNEL(r) +#define FOR_EACH_POPULATED_RANK(dimms, ch, r) \ + FOR_EACH_RANK(ch, r) IF_RANK_POPULATED(dimms, ch, r) + +#define DDR3_MAX_CAS 18 + + +enum { + VCO_2666 = 4, + VCO_3200 = 0, + VCO_4000 = 1, + VCO_5333 = 2, +}; + +#endif + +/* Offsets of read/write training results in CMOS. + They will be restored upon S3 resumes. */ +#define CMOS_READ_TRAINING 0x80 /* 16 bytes */ +#define CMOS_WRITE_TRAINING 0x90 /* 16 bytes + (could be reduced to 10 bytes) */ + + +#define DEFAULT_HECIBAR 0xfed17000 + + /* 4 KB per PCIe device */ +#define DEFAULT_PCIEXBAR CONFIG_MMCONF_BASE_ADDRESS + +#define IOMMU_BASE1 0xfed90000 +#define IOMMU_BASE2 0xfed91000 +#define IOMMU_BASE3 0xfed92000 +#define IOMMU_BASE4 0xfed93000 + +/* + * D0:F0 + */ +#define D0F0_EPBAR_LO 0x40 +#define D0F0_EPBAR_HI 0x44 +#define D0F0_MCHBAR_LO 0x48 +#define D0F0_MCHBAR_HI 0x4c +#define D0F0_GGC 0x52 +#define D0F0_DEVEN 0x54 +#define DEVEN_PEG60 (1 << 13) +#define DEVEN_IGD (1 << 4) +#define DEVEN_PEG10 (1 << 3) +#define DEVEN_PEG11 (1 << 2) +#define DEVEN_PEG12 (1 << 1) +#define DEVEN_HOST (1 << 0) +#define D0F0_PCIEXBAR_LO 0x60 +#define D0F0_PCIEXBAR_HI 0x64 +#define D0F0_DMIBAR_LO 0x68 +#define D0F0_DMIBAR_HI 0x6c +#define D0F0_PMBASE 0x78 +#define QPD0F1_PAM(x) (0x40+(x)) /* 0-6*/ +#define D0F0_REMAPBASE 0x98 +#define D0F0_REMAPLIMIT 0x9a +#define D0F0_SMRAM 0x9d +#define D0F0_ESMRAMC 0x9e +#define D0F0_TOM 0xa0 +#define D0F0_TOUUD 0xa2 +#define D0F0_IGD_BASE 0xa4 +#define D0F0_GTT_BASE 0xa8 +#define D0F0_TOLUD 0xb0 +#define D0F0_SKPD 0xdc /* Scratchpad Data */ +#define D0F0_CAPID0 0xe0 + +#define TSEG 0xac /* TSEG base */ + +/* + * D1:F0 PEG + */ +#define PEG_CAP 0xa2 +#define SLOTCAP 0xb4 +#define PEGLC 0xec +#define D1F0_VCCAP 0x104 +#define D1F0_VC0RCTL 0x114 + +/* + * Graphics frequencies + */ +#define GCFGC_PCIDEV PCI_DEV(0, 2, 0) +#define GCFGC_OFFSET 0xf0 +#define GCFGC_CR_SHIFT 0 +#define GCFGC_CR_MASK (0xf << GCFGC_CR_SHIFT) +#define GCFGC_CS_SHIFT 8 +#define GCFGC_CS_MASK (0xf << GCFGC_CS_SHIFT) +#define GCFGC_CD_SHIFT 12 +#define GCFGC_CD_MASK (0x1 << GCFGC_CD_SHIFT) +#define GCFGC_UPDATE_SHIFT 5 +#define GCFGC_UPDATE (0x1 << GCFGC_UPDATE_SHIFT) + +/* + * MCHBAR + */ + +#define MCHBAR8(x) *((volatile u8 *)(DEFAULT_MCHBAR + x)) +#define MCHBAR16(x) *((volatile u16 *)(DEFAULT_MCHBAR + x)) +#define MCHBAR32(x) *((volatile u32 *)(DEFAULT_MCHBAR + x)) + +#define PMSTS_MCHBAR 0x0f14 /* Self refresh channel status */ +#define PMSTS_WARM_RESET (1 << 1) +#define PMSTS_BOTH_SELFREFRESH (1 << 0) + +#define CLKCFG_MCHBAR 0x0c00 +#define CLKCFG_FSBCLK_SHIFT 0 +#define CLKCFG_FSBCLK_MASK (7 << CLKCFG_FSBCLK_SHIFT) +#define CLKCFG_MEMCLK_SHIFT 4 +#define CLKCFG_MEMCLK_MASK (7 << CLKCFG_MEMCLK_SHIFT) +#define CLKCFG_UPDATE (1 << 12) + +#define SSKPD_MCHBAR 0x0c1c +#define SSKPD_CLK_SHIFT 0 +#define SSKPD_CLK_MASK (7 << SSKPD_CLK_SHIFT) + +#define DCC_MCHBAR 0x200 +#define DCC_NO_CHANXOR (1 << 10) +#define DCC_INTERLEAVED (1 << 1) +#define DCC_CMD_SHIFT 16 +#define DCC_CMD_MASK (7 << DCC_CMD_SHIFT) +#define DCC_CMD_NOP (1 << DCC_CMD_SHIFT) + /* For mode register mr0: */ +#define DCC_SET_MREG (3 << DCC_CMD_SHIFT) + /* For extended mode registers mr1 to mr3: */ +#define DCC_SET_EREG (4 << DCC_CMD_SHIFT) +#define DCC_SET_EREG_SHIFT 21 +#define DCC_SET_EREG_MASK (DCC_CMD_MASK | (3 << DCC_SET_EREG_SHIFT)) +#define DCC_SET_EREGx(x) ((DCC_SET_EREG | \ + ((x - 1) << DCC_SET_EREG_SHIFT)) & \ + DCC_SET_EREG_MASK) + +/* Per channel DRAM Row Attribute registers (32-bit) */ +#define CxDRA_MCHBAR(x) (0x1208 + (x * 0x0100)) +#define CxDRA_PAGESIZE_SHIFT(r) (r * 4) /* Per rank r */ +#define CxDRA_PAGESIZE_MASKr(r) (0x7 << CxDRA_PAGESIZE_SHIFT(r)) +#define CxDRA_PAGESIZE_MASK 0x0000ffff +#define CxDRA_PAGESIZE(r, p) /* for log2(dimm page size in bytes) p */ \ + (((p - 10) << CxDRA_PAGESIZE_SHIFT(r)) & CxDRA_PAGESIZE_MASKr(r)) +#define CxDRA_BANKS_SHIFT(r) ((r * 3) + 16) +#define CxDRA_BANKS_MASKr(r) (0x3 << CxDRA_BANKS_SHIFT(r)) +#define CxDRA_BANKS_MASK 0x07ff0000 +#define CxDRA_BANKS(r, b) /* for number of banks b */ \ + ((b << (CxDRA_BANKS_SHIFT(r) - 3)) & CxDRA_BANKS_MASKr(r)) + +/* + * Per channel DRAM Row Boundary registers (32-bit) + * Every two ranks share one register and must be programmed at the same time. + * All registers (4 ranks per channel) have to be set. + */ +#define CxDRBy_MCHBAR(x, r) (0x1200 + (x * 0x0100) + ((r/2) * 4)) +#define CxDRBy_BOUND_SHIFT(r) ((r % 2) * 16) +#define CxDRBy_BOUND_MASK(r) (0x1fc << CxDRBy_BOUND_SHIFT(r)) +#define CxDRBy_BOUND_MB(r, b) /* for boundary in MB b */ \ + (((b >> 5) << CxDRBy_BOUND_SHIFT(r)) & CxDRBy_BOUND_MASK(r)) + +#define CxDRC0_MCHBAR(x) (0x1230 + (x * 0x0100)) +#define CxDRC0_RANKEN0 (1 << 24) /* Rank Enable */ +#define CxDRC0_RANKEN1 (1 << 25) +#define CxDRC0_RANKEN2 (1 << 26) +#define CxDRC0_RANKEN3 (1 << 27) +#define CxDRC0_RANKEN(r) (1 << (24 + r)) +#define CxDRC0_RANKEN_MASK (0xf << 24) +#define CxDRC0_RMS_SHIFT 8 /* Refresh Mode Select */ +#define CxDRC0_RMS_MASK (7 << CxDRC0_RMS_SHIFT) +#define CxDRC0_RMS_78US (2 << CxDRC0_RMS_SHIFT) +#define CxDRC0_RMS_39US (3 << CxDRC0_RMS_SHIFT) + +#define CxDRC1_MCHBAR(x) (0x1234 + (x * 0x0100)) +#define CxDRC1_SSDS_SHIFT 24 +#define CxDRC1_SSDS_MASK (0xff << CxDRC1_SSDS_SHIFT) +#define CxDRC1_DS (0x91 << CxDRC1_SSDS_SHIFT) +#define CxDRC1_SS (0xb1 << CxDRC1_SSDS_SHIFT) +#define CxDRC1_NOTPOP(r) (1 << (16 + r)) /* Write 1 for Not Populated */ +#define CxDRC1_NOTPOP_MASK (0xf << 16) +#define CxDRC1_MUSTWR (3 << 11) + +#define CxDRC2_MCHBAR(x) (0x1238 + (x * 0x0100)) +#define CxDRC2_NOTPOP(r) (1 << (24 + r)) /* Write 1 for Not Populated */ +#define CxDRC2_NOTPOP_MASK (0xf << 24) +#define CxDRC2_MUSTWR (1 << 12) +#define CxDRC2_CLK1067MT (1 << 0) + +/* DRAM Timing registers (32-bit each) */ +#define CxDRT0_MCHBAR(x) (0x1210 + (x * 0x0100)) +#define CxDRT0_BtB_WtP_SHIFT 26 +#define CxDRT0_BtB_WtP_MASK (0x1f << CxDRT0_BtB_WtP_SHIFT) +#define CxDRT0_BtB_WtR_SHIFT 20 +#define CxDRT0_BtB_WtR_MASK (0x1f << CxDRT0_BtB_WtR_SHIFT) +#define CxDRT1_MCHBAR(x) (0x1214 + (x * 0x0100)) +#define CxDRT2_MCHBAR(x) (0x1218 + (x * 0x0100)) +#define CxDRT3_MCHBAR(x) (0x121c + (x * 0x0100)) +#define CxDRT4_MCHBAR(x) (0x1220 + (x * 0x0100)) +#define CxDRT5_MCHBAR(x) (0x1224 + (x * 0x0100)) +#define CxDRT6_MCHBAR(x) (0x1228 + (x * 0x0100)) + +/* Clock disable registers (32-bit each) */ +#define CxDCLKDIS_MCHBAR(x) (0x120c + (x * 0x0100)) +#define CxDCLKDIS_MASK 3 +#define CxDCLKDIS_ENABLE 3 /* Always enable both clock pairs. */ + +/* On-Die-Termination registers (2x 32-bit per channel) */ +#define CxODT_HIGH(x) (0x124c + (x * 0x0100)) +#define CxODT_LOW(x) (0x1248 + (x * 0x0100)) + +/* Write Training registers. */ +#define CxWRTy_MCHBAR(ch, s) (0x1470 + (ch * 0x0100) + ((3 - s) * 4)) + +#define CxGTEW(x) (0x1270+(x*0x100)) +#define CxGTC(x) (0x1274+(x*0x100)) +#define CxDTPEW(x) (0x1278+(x*0x100)) +#define CxDTAEW(x) (0x1280+(x*0x100)) +#define CxDTC(x) (0x1288+(x*0x100)) + + +/* + * DMIBAR + */ + +#define DMIBAR8(x) *((volatile u8 *)(DEFAULT_DMIBAR + x)) +#define DMIBAR16(x) *((volatile u16 *)(DEFAULT_DMIBAR + x)) +#define DMIBAR32(x) *((volatile u32 *)(DEFAULT_DMIBAR + x)) + +#define DMIVC0RCTL 0x14 +#define DMIESD 0x44 + + +/* + * EPBAR + */ + +#define EPBAR8(x) *((volatile u8 *)(DEFAULT_EPBAR + x)) +#define EPBAR16(x) *((volatile u16 *)(DEFAULT_EPBAR + x)) +#define EPBAR32(x) *((volatile u32 *)(DEFAULT_EPBAR + x)) + + +#ifndef __ASSEMBLER__ +void gm45_early_init(void); +void gm45_early_reset(void); + +void enter_raminit_or_reset(void); +void get_gmch_info(sysinfo_t *); +void raminit_thermal(const sysinfo_t *); +void init_igd(const sysinfo_t *, int no_igd, int no_peg); +void init_pm(const sysinfo_t *); + +int raminit_read_vco_index(void); +u32 raminit_get_rank_addr(unsigned int channel, unsigned int rank); + +void raminit_rcomp_calibration(stepping_t stepping); +void raminit_reset_readwrite_pointers(void); +void raminit_receive_enable_calibration(const timings_t *, const dimminfo_t *); +void raminit_write_training(const mem_clock_t, const dimminfo_t *, int s3resume); +void raminit_read_training(const dimminfo_t *, int s3resume); + +void gm45_late_init(stepping_t); + +u32 decode_igd_memory_size(u32 gms); +u32 decode_igd_gtt_size(u32 gsm); + +void init_iommu(void); +#endif + /* Chipset types */ #define SANDYBRIDGE_MOBILE 0 #define SANDYBRIDGE_DESKTOP 1 @@ -53,6 +453,8 @@ #define DEFAULT_EPBAR 0xfed19000 /* 4 KB */ #define DEFAULT_RCBABASE 0xfed1c000
+#define QUICKPATH_BUS 0xff + #include <southbridge/intel/bd82x6x/pch.h>
/* Everything below this line is ignored in the DSDT */ @@ -66,24 +468,6 @@ #define DMIBAR 0x68 #define X60BAR 0x60
-#define GGC 0x50 /* GMCH Graphics Control */ - -#define DEVEN 0x54 /* Device Enable */ -#define DEVEN_PEG60 (1 << 13) -#define DEVEN_IGD (1 << 4) -#define DEVEN_PEG10 (1 << 3) -#define DEVEN_PEG11 (1 << 2) -#define DEVEN_PEG12 (1 << 1) -#define DEVEN_HOST (1 << 0) - -#define PAM0 0x80 -#define PAM1 0x81 -#define PAM2 0x82 -#define PAM3 0x83 -#define PAM4 0x84 -#define PAM5 0x85 -#define PAM6 0x86 - #define LAC 0x87 /* Legacy Access Control */ #define SMRAM 0x88 /* System Management RAM Control */ #define D_OPEN (1 << 6) @@ -92,11 +476,6 @@ #define G_SMRAME (1 << 3) #define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0))
-#define TOM 0xa0 -#define TOUUD 0xa8 /* Top of Upper Usable DRAM */ -#define TSEG 0xb8 /* TSEG base */ -#define TOLUD 0xbc /* Top of Low Used Memory */ - #define SKPAD 0xdc /* Scratchpad Data */
/* Device 0:1.0 PCI configuration space (PCI Express) */ diff --git a/src/southbridge/intel/bd82x6x/Makefile.inc b/src/southbridge/intel/bd82x6x/Makefile.inc index bc067ca..fd1474f 100644 --- a/src/southbridge/intel/bd82x6x/Makefile.inc +++ b/src/southbridge/intel/bd82x6x/Makefile.inc @@ -32,6 +32,7 @@ ramstage-y += usb_ehci.c ramstage-y += me.c ramstage-y += me_8.x.c ramstage-y += smbus.c +ramstage-y += thermal.c
ramstage-y += me_status.c ramstage-y += reset.c @@ -44,12 +45,11 @@ smm-$(CONFIG_SPI_FLASH_SMM) += spi.c ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c me.c me_8.x.c finalize.c
-romstage-y += early_usb.c early_smbus.c early_me.c me_status.c gpio.c +romstage-y += early_usb.c early_smbus.c early_me.c me_status.c romstage-$(CONFIG_USBDEBUG) += usb_debug.c ramstage-$(CONFIG_USBDEBUG) += usb_debug.c smm-$(CONFIG_USBDEBUG) += usb_debug.c romstage-y += reset.c -romstage-y += early_spi.c
bd82x6x_add_me: $(obj)/coreboot.pre $(IFDTOOL) printf " DD Adding Intel Firmware Descriptor\n" diff --git a/src/southbridge/intel/bd82x6x/azalia.c b/src/southbridge/intel/bd82x6x/azalia.c index a257daf..3a113ba 100644 --- a/src/southbridge/intel/bd82x6x/azalia.c +++ b/src/southbridge/intel/bd82x6x/azalia.c @@ -365,7 +365,7 @@ static struct device_operations azalia_ops = { .ops_pci = &azalia_pci_ops, };
-static const unsigned short pci_device_ids[] = { 0x1c20, 0x1e20, 0 }; +static const unsigned short pci_device_ids[] = { 0x1c20, 0x1e20, 0x3b56, 0 };
static const struct pci_driver pch_azalia __pci_driver = { .ops = &azalia_ops, diff --git a/src/southbridge/intel/bd82x6x/early_smbus.c b/src/southbridge/intel/bd82x6x/early_smbus.c index b13369a..ab20995 100644 --- a/src/southbridge/intel/bd82x6x/early_smbus.c +++ b/src/southbridge/intel/bd82x6x/early_smbus.c @@ -61,3 +61,18 @@ int smbus_read_byte(unsigned device, unsigned address) return do_smbus_read_byte(SMBUS_IO_BASE, device, address); }
+int smbus_write_byte(unsigned device, unsigned address, u8 data) +{ + return do_smbus_write_byte(SMBUS_IO_BASE, device, address, data); +} + +int smbus_block_read(unsigned device, unsigned cmd, u8 bytes, u8 *buf) +{ + return do_smbus_block_read(SMBUS_IO_BASE, device, cmd, bytes, buf); +} + +int smbus_block_write(unsigned device, unsigned cmd, u8 bytes, const u8 *buf) +{ + return do_smbus_block_write(SMBUS_IO_BASE, device, cmd, bytes, buf); +} + diff --git a/src/southbridge/intel/bd82x6x/lpc.c b/src/southbridge/intel/bd82x6x/lpc.c index 592f5de..3ae2c39 100644 --- a/src/southbridge/intel/bd82x6x/lpc.c +++ b/src/southbridge/intel/bd82x6x/lpc.c @@ -52,7 +52,7 @@ static void pch_enable_apic(struct device *dev) pci_write_config8(dev, ACPI_CNTL, 0x80);
*ioapic_index = 0; - *ioapic_data = (1 << 25); + *ioapic_data = (1 << 24);
/* affirm full set of redirection table entries ("write once") */ *ioapic_index = 1; @@ -63,7 +63,7 @@ static void pch_enable_apic(struct device *dev) *ioapic_index = 0; reg32 = *ioapic_data; printk(BIOS_DEBUG, "Southbridge APIC ID = %x\n", (reg32 >> 24) & 0x0f); - if (reg32 != (1 << 25)) + if (reg32 != (1 << 24)) die("APIC Error\n");
printk(BIOS_SPEW, "Dumping IOAPIC registers\n"); @@ -391,6 +391,354 @@ static void ppt_pm_init(struct device *dev) RCBA32_AND_OR(0x21b0, ~0UL, 0xf); }
+static void mobile5_pm_init(struct device *dev) +{ + printk(BIOS_DEBUG, "Mobile 5 PM init\n"); + pci_write_config8(dev, 0xa9, 0x47); + RCBA32 (0x1d44) = 0x00000000; + (void) RCBA32 (0x1d44); + RCBA32 (0x1d48) = 0x00030000; + (void) RCBA32 (0x1d48); + RCBA32 (0x1e80) = 0x000c0801; + (void) RCBA32 (0x1e80); + RCBA32 (0x1e84) = 0x000200f0; + (void) RCBA32 (0x1e84); + RCBA32 (0x2010) = 0x00188200; + (void) RCBA32 (0x2010); + RCBA32 (0x2014) = 0x14000016; + (void) RCBA32 (0x2014); + RCBA32 (0x2018) = 0xbc4abcb5; + (void) RCBA32 (0x2018); + RCBA32 (0x201c) = 0x00000000; + (void) RCBA32 (0x201c); + RCBA32 (0x2020) = 0xf0c9605b; + (void) RCBA32 (0x2020); + RCBA32 (0x2024) = 0x13683040; + (void) RCBA32 (0x2024); + RCBA32 (0x2028) = 0x04c8f16e; + (void) RCBA32 (0x2028); + RCBA32 (0x202c) = 0x09e90170; + (void) RCBA32 (0x202c); + RCBA32 (0x2100) = 0x00000000; + (void) RCBA32 (0x2100); + RCBA32 (0x2104) = 0x00000757; + (void) RCBA32 (0x2104); + RCBA32 (0x2108) = 0x00170001; + (void) RCBA32 (0x2108); + RCBA32 (0x211c) = 0x00000000; + (void) RCBA32 (0x211c); + RCBA32 (0x2120) = 0x00010000; + (void) RCBA32 (0x2120); + RCBA32 (0x21fc) = 0x00000000; + (void) RCBA32 (0x21fc); + RCBA32 (0x2200) = 0x20000044; + (void) RCBA32 (0x2200); + RCBA32 (0x2204) = 0x00000001; + (void) RCBA32 (0x2204); + RCBA32 (0x2208) = 0x00003457; + (void) RCBA32 (0x2208); + RCBA32 (0x2210) = 0x00000000; + (void) RCBA32 (0x2210); + RCBA32 (0x2214) = 0x00000001; + (void) RCBA32 (0x2214); + RCBA32 (0x2218) = 0xa0fff210; + (void) RCBA32 (0x2218); + RCBA32 (0x221c) = 0x0000df00; + (void) RCBA32 (0x221c); + RCBA32 (0x2220) = 0x00e30880; + (void) RCBA32 (0x2220); + RCBA32 (0x2224) = 0x00000070; + (void) RCBA32 (0x2224); + RCBA32 (0x2228) = 0x00004000; + (void) RCBA32 (0x2228); + RCBA32 (0x222c) = 0x00000000; + (void) RCBA32 (0x222c); + RCBA32 (0x2230) = 0x00e30880; + (void) RCBA32 (0x2230); + RCBA32 (0x2234) = 0x00000070; + (void) RCBA32 (0x2234); + RCBA32 (0x2238) = 0x00004000; + (void) RCBA32 (0x2238); + RCBA32 (0x223c) = 0x00000000; + (void) RCBA32 (0x223c); + RCBA32 (0x2240) = 0x00002301; + (void) RCBA32 (0x2240); + RCBA32 (0x2244) = 0x36000000; + (void) RCBA32 (0x2244); + RCBA32 (0x2248) = 0x00010107; + (void) RCBA32 (0x2248); + RCBA32 (0x224c) = 0x00160000; + (void) RCBA32 (0x224c); + RCBA32 (0x2250) = 0x00001b01; + (void) RCBA32 (0x2250); + RCBA32 (0x2254) = 0x36000000; + (void) RCBA32 (0x2254); + RCBA32 (0x2258) = 0x00010107; + (void) RCBA32 (0x2258); + RCBA32 (0x225c) = 0x00160000; + (void) RCBA32 (0x225c); + RCBA32 (0x2260) = 0x00000601; + (void) RCBA32 (0x2260); + RCBA32 (0x2264) = 0x16000000; + (void) RCBA32 (0x2264); + RCBA32 (0x2268) = 0x00010107; + (void) RCBA32 (0x2268); + RCBA32 (0x226c) = 0x00160000; + (void) RCBA32 (0x226c); + RCBA32 (0x2270) = 0x00001c01; + (void) RCBA32 (0x2270); + RCBA32 (0x2274) = 0x16000000; + (void) RCBA32 (0x2274); + RCBA32 (0x2278) = 0x00010107; + (void) RCBA32 (0x2278); + RCBA32 (0x227c) = 0x00160000; + (void) RCBA32 (0x227c); + RCBA32 (0x2300) = 0x00000000; + (void) RCBA32 (0x2300); + RCBA32 (0x2304) = 0x40000000; + (void) RCBA32 (0x2304); + RCBA32 (0x2308) = 0x4646827b; + (void) RCBA32 (0x2308); + RCBA32 (0x230c) = 0x6e803131; + (void) RCBA32 (0x230c); + RCBA32 (0x2310) = 0x32c77887; + (void) RCBA32 (0x2310); + RCBA32 (0x2314) = 0x00077733; + (void) RCBA32 (0x2314); + RCBA32 (0x2318) = 0x00007447; + (void) RCBA32 (0x2318); + RCBA32 (0x231c) = 0x00000040; + (void) RCBA32 (0x231c); + RCBA32 (0x2320) = 0xcccc0cfc; + (void) RCBA32 (0x2320); + RCBA32 (0x2324) = 0x0fbb0fff; + (void) RCBA32 (0x2324); + RCBA32 (0x30fc) = 0x00000000; + (void) RCBA32 (0x30fc); + RCBA32 (0x3100) = 0x04341200; + (void) RCBA32 (0x3100); + RCBA32 (0x3104) = 0x00000000; + (void) RCBA32 (0x3104); + RCBA32 (0x3108) = 0x40043214; + (void) RCBA32 (0x3108); + RCBA32 (0x310c) = 0x00014321; + (void) RCBA32 (0x310c); + RCBA32 (0x3110) = 0x00000002; + (void) RCBA32 (0x3110); + RCBA32 (0x3114) = 0x30003214; + (void) RCBA32 (0x3114); + RCBA32 (0x311c) = 0x00000002; + (void) RCBA32 (0x311c); + RCBA32 (0x3120) = 0x00000000; + (void) RCBA32 (0x3120); + RCBA32 (0x3124) = 0x00002321; + (void) RCBA32 (0x3124); + RCBA32 (0x313c) = 0x00000000; + (void) RCBA32 (0x313c); + RCBA32 (0x3140) = 0x00003107; + (void) RCBA32 (0x3140); + RCBA32 (0x3144) = 0x76543210; + (void) RCBA32 (0x3144); + RCBA32 (0x3148) = 0x00000010; + (void) RCBA32 (0x3148); + RCBA32 (0x314c) = 0x00007654; + (void) RCBA32 (0x314c); + RCBA32 (0x3150) = 0x00000004; + (void) RCBA32 (0x3150); + RCBA32 (0x3158) = 0x00000000; + (void) RCBA32 (0x3158); + RCBA32 (0x315c) = 0x00003210; + (void) RCBA32 (0x315c); + RCBA32 (0x31fc) = 0x03000000; + (void) RCBA32 (0x31fc); + RCBA32 (0x330c) = 0x00000000; + (void) RCBA32 (0x330c); + RCBA32 (0x3310) = 0x02060100; + (void) RCBA32 (0x3310); + RCBA32 (0x3314) = 0x0000000f; + (void) RCBA32 (0x3314); + RCBA32 (0x3318) = 0x01020000; + (void) RCBA32 (0x3318); + RCBA32 (0x331c) = 0x80000000; + (void) RCBA32 (0x331c); + RCBA32 (0x3324) = 0x04000000; + (void) RCBA32 (0x3324); + RCBA32 (0x3340) = 0x000fffff; + (void) RCBA32 (0x3340); + RCBA32 (0x3378) = 0x7f8fdfff; + (void) RCBA32 (0x3378); + RCBA32 (0x33a0) = 0x00003900; + (void) RCBA32 (0x33a0); + RCBA32 (0x33c0) = 0x00010000; + (void) RCBA32 (0x33c0); + RCBA32 (0x33cc) = 0x0001004b; + (void) RCBA32 (0x33cc); + RCBA32 (0x33d0) = 0x06000008; + (void) RCBA32 (0x33d0); + RCBA32 (0x33d4) = 0x00010000; + (void) RCBA32 (0x33d4); + RCBA32 (0x33fc) = 0x00000000; + (void) RCBA32 (0x33fc); + RCBA32 (0x3400) = 0x0000001c; + (void) RCBA32 (0x3400); + RCBA32 (0x3404) = 0x00000080; + (void) RCBA32 (0x3404); + RCBA32 (0x340c) = 0x00000000; + (void) RCBA32 (0x340c); + RCBA32 (0x3410) = 0x00000c61; + (void) RCBA32 (0x3410); + RCBA32 (0x3414) = 0x00000000; + (void) RCBA32 (0x3414); + RCBA32 (0x3418) = 0x16e61fe1; + (void) RCBA32 (0x3418); + RCBA32 (0x341c) = 0xbf4f001f; + (void) RCBA32 (0x341c); + RCBA32 (0x3420) = 0x00000000; + (void) RCBA32 (0x3420); + RCBA32 (0x3424) = 0x00060010; + (void) RCBA32 (0x3424); + RCBA32 (0x3428) = 0x0000001d; + (void) RCBA32 (0x3428); + RCBA32 (0x343c) = 0x00000000; + (void) RCBA32 (0x343c); + RCBA32 (0x3440) = 0xdeaddeed; + (void) RCBA32 (0x3440); + RCBA32 (0x34fc) = 0x00000000; + (void) RCBA32 (0x34fc); + RCBA32 (0x3500) = 0x20000557; + (void) RCBA32 (0x3500); + RCBA32 (0x3504) = 0x2000055f; + (void) RCBA32 (0x3504); + RCBA32 (0x3508) = 0x2000074b; + (void) RCBA32 (0x3508); + RCBA32 (0x350c) = 0x2000074b; + (void) RCBA32 (0x350c); + RCBA32 (0x3510) = 0x20000557; + (void) RCBA32 (0x3510); + RCBA32 (0x3514) = 0x2000014b; + (void) RCBA32 (0x3514); + RCBA32 (0x3518) = 0x2000074b; + (void) RCBA32 (0x3518); + RCBA32 (0x351c) = 0x2000074b; + (void) RCBA32 (0x351c); + RCBA32 (0x3520) = 0x2000074b; + (void) RCBA32 (0x3520); + RCBA32 (0x3524) = 0x2000074b; + (void) RCBA32 (0x3524); + RCBA32 (0x3528) = 0x2000055f; + (void) RCBA32 (0x3528); + RCBA32 (0x352c) = 0x2000055f; + (void) RCBA32 (0x352c); + RCBA32 (0x3530) = 0x20000557; + (void) RCBA32 (0x3530); + RCBA32 (0x3534) = 0x2000055f; + (void) RCBA32 (0x3534); + RCBA32 (0x355c) = 0x00000000; + (void) RCBA32 (0x355c); + RCBA32 (0x3560) = 0x00000001; + (void) RCBA32 (0x3560); + RCBA32 (0x3564) = 0x000026a3; + (void) RCBA32 (0x3564); + RCBA32 (0x3568) = 0x00040002; + (void) RCBA32 (0x3568); + RCBA32 (0x356c) = 0x01000052; + (void) RCBA32 (0x356c); + RCBA32 (0x3570) = 0x02000772; + (void) RCBA32 (0x3570); + RCBA32 (0x3574) = 0x16000f8f; + (void) RCBA32 (0x3574); + RCBA32 (0x3578) = 0x1800ff4f; + (void) RCBA32 (0x3578); + RCBA32 (0x357c) = 0x0001d630; + (void) RCBA32 (0x357c); + RCBA32 (0x359c) = 0x00000000; + (void) RCBA32 (0x359c); + RCBA32 (0x35a0) = 0xfc000201; + (void) RCBA32 (0x35a0); + RCBA32 (0x35a4) = 0x3c000201; + (void) RCBA32 (0x35a4); + RCBA32 (0x35fc) = 0x00000000; + (void) RCBA32 (0x35fc); + RCBA32 (0x3600) = 0x0a001f00; + (void) RCBA32 (0x3600); + RCBA32 (0x3608) = 0x00000000; + (void) RCBA32 (0x3608); + RCBA32 (0x360c) = 0x00000001; + (void) RCBA32 (0x360c); + RCBA32 (0x3610) = 0x00010000; + (void) RCBA32 (0x3610); + RCBA32 (0x36d0) = 0x00000000; + (void) RCBA32 (0x36d0); + RCBA32 (0x36d4) = 0x089c0018; + (void) RCBA32 (0x36d4); + RCBA32 (0x36dc) = 0x00000000; + (void) RCBA32 (0x36dc); + RCBA32 (0x36e0) = 0x11111111; + (void) RCBA32 (0x36e0); + RCBA32 (0x3720) = 0x00000000; + (void) RCBA32 (0x3720); + RCBA32 (0x3724) = 0x4e564d49; + (void) RCBA32 (0x3724); + RCBA32 (0x37fc) = 0x00000000; + (void) RCBA32 (0x37fc); + RCBA32 (0x3800) = 0x07ff0500; + (void) RCBA32 (0x3800); + RCBA32 (0x3804) = 0x3f04e008; + (void) RCBA32 (0x3804); + RCBA32 (0x3808) = 0x0058efc0; + (void) RCBA32 (0x3808); + RCBA32 (0x380c) = 0x00000000; + (void) RCBA32 (0x380c); + RCBA32 (0x384c) = 0x92000000; + (void) RCBA32 (0x384c); + RCBA32 (0x3850) = 0x00000a0b; + (void) RCBA32 (0x3850); + RCBA32 (0x3854) = 0x00000000; + (void) RCBA32 (0x3854); + RCBA32 (0x3858) = 0x07ff0500; + (void) RCBA32 (0x3858); + RCBA32 (0x385c) = 0x04ff0003; + (void) RCBA32 (0x385c); + RCBA32 (0x3860) = 0x00020001; + (void) RCBA32 (0x3860); + RCBA32 (0x3864) = 0x00000fff; + (void) RCBA32 (0x3864); + RCBA32 (0x3870) = 0x00000000; + (void) RCBA32 (0x3870); + RCBA32 (0x3874) = 0x9fff07d0; + (void) RCBA32 (0x3874); + RCBA32 (0x388c) = 0x00000000; + (void) RCBA32 (0x388c); + RCBA32 (0x3890) = 0xf8400000; + (void) RCBA32 (0x3890); + RCBA32 (0x3894) = 0x143b5006; + (void) RCBA32 (0x3894); + RCBA32 (0x3898) = 0x05200302; + (void) RCBA32 (0x3898); + RCBA32 (0x389c) = 0x0601209f; + (void) RCBA32 (0x389c); + RCBA32 (0x38ac) = 0x00000000; + (void) RCBA32 (0x38ac); + RCBA32 (0x38b0) = 0x00000004; + (void) RCBA32 (0x38b0); + RCBA32 (0x38b4) = 0x03040002; + (void) RCBA32 (0x38b4); + RCBA32 (0x38c0) = 0x00000007; + (void) RCBA32 (0x38c0); + RCBA32 (0x38c4) = 0x00802005; + (void) RCBA32 (0x38c4); + RCBA32 (0x38c8) = 0x00002005; + (void) RCBA32 (0x38c8); + RCBA32 (0x3dfc) = 0x00000000; + (void) RCBA32 (0x3dfc); + RCBA32 (0x3e7c) = 0xffffffff; + (void) RCBA32 (0x3e7c); + RCBA32 (0x3efc) = 0x00000000; + (void) RCBA32 (0x3efc); + RCBA32 (0x3f00) = 0x0000010b; + (void) RCBA32 (0x3f00); +} + static void enable_hpet(void) { u32 reg32; @@ -537,17 +885,6 @@ static void lpc_init(struct device *dev) /* Set the value for PCI command register. */ pci_write_config16(dev, PCI_COMMAND, 0x000f);
- /* IO APIC initialization. */ - pch_enable_apic(dev); - - pch_enable_serial_irqs(dev); - - /* Setup the PIRQ. */ - pch_pirq_init(dev); - - /* Setup power options. */ - pch_power_options(dev); - /* Initialize power management */ switch (pch_silicon_type()) { case PCH_TYPE_CPT: /* CougarPoint */ @@ -556,10 +893,24 @@ static void lpc_init(struct device *dev) case PCH_TYPE_PPT: /* PantherPoint */ ppt_pm_init(dev); break; + case PCH_TYPE_MOBILE5: + mobile5_pm_init (dev); + break; default: printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device); }
+ /* IO APIC initialization. */ + pch_enable_apic(dev); + + pch_enable_serial_irqs(dev); + + /* Setup the PIRQ. */ + pch_pirq_init(dev); + + /* Setup power options. */ + pch_power_options(dev); + /* Set the state of the GPIO lines. */ //gpio_init(dev);
@@ -607,6 +958,12 @@ static void pch_lpc_read_resources(device_t dev) IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0)); + res->base = 0x1000; + res->size = 0x0200; + res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | + IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + + res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0)); res->base = 0xff800000; res->size = 0x00800000; /* 8 MB for flash */ res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | @@ -700,7 +1057,7 @@ static const unsigned short pci_device_ids[] = { 0x1c46, 0x1c47, 0x1c49, 0x1c4a, 0x1c4b, 0x1c4c, 0x1c4d, 0x1c4e, 0x1c4f, 0x1c50, 0x1c52, 0x1c54, 0x1e55, 0x1c56, 0x1e57, 0x1c5c, - 0x1e5d, 0x1e5e, 0x1e5f, + 0x1e5d, 0x1e5e, 0x1e5f, 0x3b07, 0 };
static const struct pci_driver pch_lpc __pci_driver = { diff --git a/src/southbridge/intel/bd82x6x/me.c b/src/southbridge/intel/bd82x6x/me.c index b9aff37..1cc7709 100644 --- a/src/southbridge/intel/bd82x6x/me.c +++ b/src/southbridge/intel/bd82x6x/me.c @@ -380,7 +380,7 @@ static int mkhi_end_of_post(void) } #endif
-#if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG) && !defined(__SMM__) +#if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG) && !defined(__SMM__) && 0 /* Get ME firmware version */ static int mkhi_get_fw_version(void) { @@ -724,7 +724,7 @@ static void intel_me_init(device_t dev) if (intel_mei_setup(dev) < 0) break;
-#if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG) +#if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG) && 0 /* Print ME firmware version */ mkhi_get_fw_version(); /* Print ME firmware capabilities */ @@ -769,10 +769,14 @@ static struct device_operations device_ops = { .ops_pci = &pci_ops, };
+static const unsigned short pci_device_ids[] = { 0x1c3a, 0x3b64, + 0 }; + + static const struct pci_driver intel_me __pci_driver = { .ops = &device_ops, .vendor = PCI_VENDOR_ID_INTEL, - .device = 0x1c3a, + .devices = pci_device_ids };
#endif /* !__SMM__ */ diff --git a/src/southbridge/intel/bd82x6x/me.h b/src/southbridge/intel/bd82x6x/me.h index aaeb24d..6e2062d 100644 --- a/src/southbridge/intel/bd82x6x/me.h +++ b/src/southbridge/intel/bd82x6x/me.h @@ -194,6 +194,7 @@ struct mei_header { #define MKHI_MDES_ENABLE 0x09
#define MKHI_GET_FW_VERSION 0x02 +#define MKHI_SET_UMA 0x08 #define MKHI_END_OF_POST 0x0c #define MKHI_FEATURE_OVERRIDE 0x14
diff --git a/src/southbridge/intel/bd82x6x/pch.h b/src/southbridge/intel/bd82x6x/pch.h index 1211671..aa7cae5 100644 --- a/src/southbridge/intel/bd82x6x/pch.h +++ b/src/southbridge/intel/bd82x6x/pch.h @@ -22,8 +22,9 @@ #define SOUTHBRIDGE_INTEL_BD82X6X_PCH_H
/* PCH types */ -#define PCH_TYPE_CPT 0x1c /* CougarPoint */ -#define PCH_TYPE_PPT 0x1e /* IvyBridge */ +#define PCH_TYPE_CPT 0x1c /* CougarPoint */ +#define PCH_TYPE_PPT 0x1e /* IvyBridge */ +#define PCH_TYPE_MOBILE5 0x3b
/* PCH stepping values for LPC device */ #define PCH_STEP_A0 0 @@ -41,11 +42,11 @@ * again. But handling static BARs is a generic problem that should be * solved in the device allocator. */ -#define SMBUS_IO_BASE 0x0400 +#define SMBUS_IO_BASE 0x1100 #define SMBUS_SLAVE_ADDR 0x24 /* TODO Make sure these don't get changed by stage2 */ -#define DEFAULT_GPIOBASE 0x0480 -#define DEFAULT_PMBASE 0x0500 +#define DEFAULT_GPIOBASE 0x1180 +#define DEFAULT_PMBASE 0x1000
#define DEFAULT_RCBA 0xfed1c000
@@ -71,6 +72,9 @@ void pch_log_state(void); void enable_smbus(void); void enable_usb_bar(void); int smbus_read_byte(unsigned device, unsigned address); +int smbus_write_byte(unsigned device, unsigned address, u8 data); +int smbus_block_read(unsigned device, unsigned cmd, u8 bytes, u8 *buf); +int smbus_block_write(unsigned device, unsigned cmd, u8 bytes, const u8 *buf); int early_spi_read(u32 offset, u32 size, u8 *buffer); #endif #endif @@ -339,6 +343,7 @@ int early_spi_read(u32 offset, u32 size, u8 *buffer); #define D31IP 0x3100 /* 32bit */ #define D31IP_TTIP 24 /* Thermal Throttle Pin */ #define D31IP_SIP2 20 /* SATA Pin 2 */ +#define D31IP_UNKIP 16 #define D31IP_SMIP 12 /* SMBUS Pin */ #define D31IP_SIP 8 /* SATA Pin */ #define D30IP 0x3104 /* 32bit */ diff --git a/src/southbridge/intel/bd82x6x/sata.c b/src/southbridge/intel/bd82x6x/sata.c index fb29d73..3ca1b1a 100644 --- a/src/southbridge/intel/bd82x6x/sata.c +++ b/src/southbridge/intel/bd82x6x/sata.c @@ -23,6 +23,7 @@ #include <device/device.h> #include <device/pci.h> #include <device/pci_ids.h> +#include <delay.h> #include "pch.h"
typedef struct southbridge_intel_bd82x6x_config config_t; @@ -53,6 +54,8 @@ static void sata_init(struct device *dev) return; }
+ // printk(BIOS_ERR, "SATA: %s: %d\n", __FILE__, __LINE__); + /* SATA configuration */
/* Enable BARs */ @@ -96,46 +99,58 @@ static void sata_init(struct device *dev) ((config->sata_port_map ^ 0x3f) << 24) | 0x183); } else if(config->sata_ahci) { u32 abar; + int i;
printk(BIOS_DEBUG, "SATA: Controller in AHCI mode.\n");
/* Set Interrupt Line */ /* Interrupt Pin is set by D31IP.PIP */ - pci_write_config8(dev, INTR_LN, 0x0a); + pci_write_config8(dev, INTR_LN, 0x0b);
/* Set timings */ pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | - IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS | - IDE_PPE0 | IDE_IE0 | IDE_TIME0); + IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS); pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE | IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS);
/* Sync DMA */ - pci_write_config16(dev, IDE_SDMA_CNT, IDE_PSDE0); - pci_write_config16(dev, IDE_SDMA_TIM, 0x0001); + pci_write_config16(dev, IDE_SDMA_CNT, 0); + pci_write_config16(dev, IDE_SDMA_TIM, 0);
/* Set IDE I/O Configuration */ - reg32 = SIG_MODE_PRI_NORMAL | FAST_PCB1 | FAST_PCB0 | PCB1 | PCB0; + reg32 = SIG_MODE_PRI_NORMAL;// | FAST_PCB1 | FAST_PCB0 | PCB1 | PCB0; pci_write_config32(dev, IDE_CONFIG, reg32);
/* for AHCI, Port Enable is managed in memory mapped space */ reg16 = pci_read_config16(dev, 0x92); reg16 &= ~0x3f; /* 6 ports SKU + ORM */ - reg16 |= 0x8000 | config->sata_port_map; + reg16 |= 0x8100 | config->sata_port_map; pci_write_config16(dev, 0x92, reg16);
/* SATA Initialization register */ pci_write_config32(dev, 0x94, - ((config->sata_port_map ^ 0x3f) << 24) | 0x183); + ((config->sata_port_map ^ 0x3f) << 24) | 0x183 | 0x40000000); + pci_write_config32(dev, 0x98, 0x00590200);
/* Initialize AHCI memory-mapped space */ abar = pci_read_config32(dev, PCI_BASE_ADDRESS_5); printk(BIOS_DEBUG, "ABAR: %08X\n", abar); + /* CAP (HBA Capabilities) : enable power management */ reg32 = read32(abar + 0x00); reg32 |= 0x0c006000; // set PSC+SSC+SALP+SSS reg32 &= ~0x00020060; // clear SXS+EMS+PMS write32(abar + 0x00, reg32); + + /* AHCI enable. */ + for (i = 0; i < 5; i++) + { + write32(abar + 0x04, read32 (abar + 0x04) | 0x80000000); + mdelay (1); + if (read32 (abar + 0x04) & 0x80000000) + break; + } + /* PI (Ports implemented) */ write32(abar + 0x0c, config->sata_port_map); (void) read32(abar + 0x0c); /* Read back 1 */ @@ -143,6 +158,7 @@ static void sata_init(struct device *dev) /* CAP2 (HBA Capabilities Extended)*/ reg32 = read32(abar + 0x24); reg32 &= ~0x00000002; + write32(abar + 0x24, reg32); /* VSP (Vendor Specific Register */ reg32 = read32(abar + 0xa0); @@ -205,13 +221,14 @@ static void sata_init(struct device *dev) config->sata_port1_gen3_tx);
/* Additional Programming Requirements */ - sir_write(dev, 0x04, 0x00001600); - sir_write(dev, 0x28, 0xa0000033); + sir_write(dev, 0x04, 0x00000000); + sir_write(dev, 0x28, 0x0a000033); reg32 = sir_read(dev, 0x54); reg32 &= 0xff000000; - reg32 |= 0x5555aa; + reg32 |= 0x555555; + sir_write(dev, 0x54, reg32); - sir_write(dev, 0x64, 0xcccc8484); + sir_write(dev, 0x64, 0xcccccccc); reg32 = sir_read(dev, 0x68); reg32 &= 0xffff0000; reg32 |= 0xcccc; @@ -219,9 +236,10 @@ static void sata_init(struct device *dev) reg32 = sir_read(dev, 0x78); reg32 &= 0x0000ffff; reg32 |= 0x88880000; + sir_write(dev, 0x78, reg32); sir_write(dev, 0x84, 0x001c7000); - sir_write(dev, 0x88, 0x88338822); + sir_write(dev, 0x88, 0x88888888); sir_write(dev, 0xa0, 0x001c7000); // a4 sir_write(dev, 0xc4, 0x0c0c0c0c); @@ -250,6 +268,7 @@ static void sata_enable(device_t dev)
map |= (config->sata_port_map ^ 0x3f) << 8;
+ pci_write_config16(dev, 0x90, map); }
@@ -280,7 +299,7 @@ static struct device_operations sata_ops = {
static const unsigned short pci_device_ids[] = { 0x1c00, 0x1c01, 0x1c02, 0x1c03, 0x1e00, 0x1e01, 0x1e02, 0x1e03, - 0 }; + 0x3b2e, 0 };
static const struct pci_driver pch_sata __pci_driver = { .ops = &sata_ops, diff --git a/src/southbridge/intel/bd82x6x/smbus.c b/src/southbridge/intel/bd82x6x/smbus.c index 4930685..cb09c22 100644 --- a/src/southbridge/intel/bd82x6x/smbus.c +++ b/src/southbridge/intel/bd82x6x/smbus.c @@ -59,7 +59,7 @@ static int lsmbus_read_byte(device_t dev, u8 address) }
static struct smbus_bus_operations lops_smbus_bus = { - .read_byte = lsmbus_read_byte, + .read_byte = lsmbus_read_byte };
static void smbus_set_subsystem(device_t dev, unsigned vendor, unsigned device) @@ -100,7 +100,7 @@ static struct device_operations smbus_ops = { .ops_pci = &smbus_pci_ops, };
-static const unsigned short pci_device_ids[] = { 0x1c22, 0x1e22, 0 }; +static const unsigned short pci_device_ids[] = { 0x1c22, 0x1e22, 0x3b30, 0 };
static const struct pci_driver pch_smbus __pci_driver = { .ops = &smbus_ops, diff --git a/src/southbridge/intel/bd82x6x/smbus.h b/src/southbridge/intel/bd82x6x/smbus.h index f2f7f60..cb01539 100644 --- a/src/southbridge/intel/bd82x6x/smbus.h +++ b/src/southbridge/intel/bd82x6x/smbus.h @@ -98,3 +98,147 @@ static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned add return byte; }
+#ifdef __PRE_RAM__ + +static int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned address, unsigned data) +{ + unsigned char global_status_register; + + if (smbus_wait_until_ready(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + + /* Setup transaction */ + /* Disable interrupts */ + outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL); + /* Set the device I'm talking too */ + outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD); + /* Set the command/address... */ + outb(address & 0xff, smbus_base + SMBHSTCMD); + /* Set up for a byte data read */ + outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2), + (smbus_base + SMBHSTCTL)); + /* Clear any lingering errors, so the transaction will run */ + outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT); + + /* Clear the data byte... */ + outb(data, smbus_base + SMBHSTDAT0); + + /* Start the command */ + outb((inb(smbus_base + SMBHSTCTL) | 0x40), + smbus_base + SMBHSTCTL); + + /* Poll for transaction completion */ + if (smbus_wait_until_done(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; + + global_status_register = inb(smbus_base + SMBHSTSTAT); + + /* Ignore the "In Use" status... */ + global_status_register &= ~(3 << 5); + + /* Read results of transaction */ + if (global_status_register != (1 << 1)) + return SMBUS_ERROR; + + return 0; +} + +static int do_smbus_block_write(unsigned smbus_base, unsigned device, + unsigned cmd, unsigned bytes, const u8 *buf) +{ + u8 status; + + if (smbus_wait_until_ready(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + + /* Setup transaction */ + /* Disable interrupts */ + outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL); + /* Set the device I'm talking too */ + outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD); + /* Set the command/address... */ + outb(cmd & 0xff, smbus_base + SMBHSTCMD); + /* Set up for a block data write */ + outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2), + (smbus_base + SMBHSTCTL)); + /* Clear any lingering errors, so the transaction will run */ + outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT); + + /* set number of bytes to transfer */ + outb(bytes, smbus_base + SMBHSTDAT0); + + outb(*buf++, smbus_base + SMBBLKDAT); + bytes--; + + /* Start the command */ + outb((inb(smbus_base + SMBHSTCTL) | 0x40), + smbus_base + SMBHSTCTL); + + while(!(inb(smbus_base + SMBHSTSTAT) & 1)); + /* Poll for transaction completion */ + do { + status = inb(smbus_base + SMBHSTSTAT); + if (status & ((1 << 4) | /* FAILED */ + (1 << 3) | /* BUS ERR */ + (1 << 2))) /* DEV ERR */ + return SMBUS_ERROR; + + if (status & 0x80) { /* Byte done */ + outb(*buf++, smbus_base + SMBBLKDAT); + outb(status, smbus_base + SMBHSTSTAT); + } + } while(status & 0x01); + + return 0; +} + +static int do_smbus_block_read(unsigned smbus_base, unsigned device, + unsigned cmd, unsigned bytes, u8 *buf) +{ + u8 status; + int bytes_read = 0; + if (smbus_wait_until_ready(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + + /* Setup transaction */ + /* Disable interrupts */ + outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL); + /* Set the device I'm talking too */ + outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD); + /* Set the command/address... */ + outb(cmd & 0xff, smbus_base + SMBHSTCMD); + /* Set up for a block data read */ + outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2), + (smbus_base + SMBHSTCTL)); + /* Clear any lingering errors, so the transaction will run */ + outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT); + + /* Start the command */ + outb((inb(smbus_base + SMBHSTCTL) | 0x40), + smbus_base + SMBHSTCTL); + + while(!(inb(smbus_base + SMBHSTSTAT) & 1)); + /* Poll for transaction completion */ + do { + status = inb(smbus_base + SMBHSTSTAT); + if (status & ((1 << 4) | /* FAILED */ + (1 << 3) | /* BUS ERR */ + (1 << 2))) /* DEV ERR */ + return SMBUS_ERROR; + + if (status & 0x80) { /* Byte done */ + *buf = inb(smbus_base + SMBBLKDAT); + buf++; + bytes_read++; + outb(status, smbus_base + SMBHSTSTAT); + if (--bytes == 1) { + /* indicate that next byte is the last one */ + outb(inb(smbus_base + SMBHSTCTL) | 0x20, + smbus_base + SMBHSTCTL); + } + } + } while(status & 0x01); + + return bytes_read; +} +#endif diff --git a/src/southbridge/intel/bd82x6x/smi.c b/src/southbridge/intel/bd82x6x/smi.c index c89ae18..0ce1bc2 100644 --- a/src/southbridge/intel/bd82x6x/smi.c +++ b/src/southbridge/intel/bd82x6x/smi.c @@ -219,7 +219,6 @@ static void dump_tco_status(u32 tco_sts) }
- /** * @brief Set the EOS bit */ @@ -362,10 +361,13 @@ static void smm_install(void) smm_base); memcpy((void *)smm_base, &ied, sizeof(ied)); } + printk (BIOS_ERR, "alive "__FILE__":%d\n", __LINE__); wbinvd();
+ printk (BIOS_ERR, "alive "__FILE__":%d\n", __LINE__); /* close the SMM memory window and enable normal SMM */ pci_write_config8(dev, SMRAM, G_SMRAME | C_BASE_SEG); + printk (BIOS_ERR, "alive "__FILE__":%d\n", __LINE__); }
void smm_init(void) @@ -378,6 +380,8 @@ void smm_init(void) /* Put SMM code to 0xa0000 */ smm_install();
+ printk (BIOS_ERR, "alive "__FILE__":%d\n", __LINE__); + /* Put relocation code to 0x38000 and relocate SMBASE */ smm_relocate();
diff --git a/src/southbridge/intel/bd82x6x/spi.c b/src/southbridge/intel/bd82x6x/spi.c index 05649fc..4696dce 100644 --- a/src/southbridge/intel/bd82x6x/spi.c +++ b/src/southbridge/intel/bd82x6x/spi.c @@ -316,7 +316,8 @@ static inline int get_ich_version(uint16_t device_id) if ((device_id >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN && device_id <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX) || (device_id >= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN && - device_id <= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX)) + device_id <= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX) + || device_id == 0x3b07) return 9;
return 0; @@ -383,6 +384,13 @@ void spi_init(void) ich9_spi_regs *ich9_spi = (ich9_spi_regs *)(rcrb + ich9_spibar_offset); ichspi_lock = readw_(&ich9_spi->hsfs) & HSFS_FLOCKDN; + switch (0) + { + case ((char *) ich9_spi->opmenu - (char *)ich9_spi == 0x98): + break; + case 0: + break; + } cntlr.opmenu = ich9_spi->opmenu; cntlr.menubytes = sizeof(ich9_spi->opmenu); cntlr.optype = &ich9_spi->optype; diff --git a/src/southbridge/intel/bd82x6x/thermal.c b/src/southbridge/intel/bd82x6x/thermal.c new file mode 100644 index 0000000..c1040c5 --- /dev/null +++ b/src/southbridge/intel/bd82x6x/thermal.c @@ -0,0 +1,84 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include "pch.h" +#include <usbdebug.h> +#include <arch/io.h> + +static void thermal_init(struct device *dev) +{ + struct resource *res; + + printk(BIOS_DEBUG, "Thermal init start.\n"); + + res = find_resource(dev, 0x10); + if (!res) return; + + write32 (res->base + 4, 0x3a2b); + write8 (res->base + 0xe, 0x40); + write32 (res->base + 0x12, 0x1a40); + write16 (res->base + 0x16, 0x7746); + write16 (res->base + 0x1a, 0x10f0); + write16 (res->base + 0x56, 0xffff); + write16 (res->base + 0x64, 0xffff); + write16 (res->base + 0x66, 0xffff); + write16 (res->base + 0x68, 0xfa); + + write8 (res->base + 1, 0xb8); + + printk(BIOS_DEBUG, "Thermal init done.\n"); +} + + +static void set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +static struct pci_operations pci_ops = { + .set_subsystem = set_subsystem, +}; + +static struct device_operations thermal_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = thermal_init, + .scan_bus = 0, + .ops_pci = &pci_ops, +}; + +static const unsigned short pci_device_ids[] = { 0x3b32, 0 }; + +static const struct pci_driver pch_thermal __pci_driver = { + .ops = &thermal_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .devices = pci_device_ids, +}; diff --git a/src/southbridge/intel/bd82x6x/usb_debug.c b/src/southbridge/intel/bd82x6x/usb_debug.c index 4258a03..1c51761 100644 --- a/src/southbridge/intel/bd82x6x/usb_debug.c +++ b/src/southbridge/intel/bd82x6x/usb_debug.c @@ -24,6 +24,7 @@ #include <usbdebug.h> #include <device/pci_def.h> #include "pch.h" +#include <delay.h>
/* Required for successful build, but currently empty. */ void set_debug_port(unsigned int port) @@ -34,16 +35,18 @@ void set_debug_port(unsigned int port) void enable_usbdebug(unsigned int port) { u32 dbgctl; - device_t dev = PCI_DEV(0, 0x1d, 7); /* USB EHCI, D29:F7 */ + device_t dev = PCI_DEV(0, 0x1a, 0); /* USB EHCI, D29:F7 */ + device_t bdev = PCI_DEV(0, 0, 0); /* USB EHCI, D29:F7 */
/* Set the EHCI BAR address. */ pci_write_config32(dev, EHCI_BAR_INDEX, CONFIG_EHCI_BAR);
/* Enable access to the EHCI memory space registers. */ - pci_write_config8(dev, PCI_COMMAND, PCI_COMMAND_MEMORY); + pci_write_config16(dev, PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_SERR); + + pci_write_config16(bdev, PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
/* Force ownership of the Debug Port to the EHCI controller. */ - printk(BIOS_DEBUG, "Enabling OWNER_CNT\n"); dbgctl = read32(CONFIG_EHCI_BAR + CONFIG_EHCI_DEBUG_OFFSET); dbgctl |= (1 << 30); write32(CONFIG_EHCI_BAR + CONFIG_EHCI_DEBUG_OFFSET, dbgctl); diff --git a/src/southbridge/intel/bd82x6x/usb_ehci.c b/src/southbridge/intel/bd82x6x/usb_ehci.c index 76e8338..3ccaaff 100644 --- a/src/southbridge/intel/bd82x6x/usb_ehci.c +++ b/src/southbridge/intel/bd82x6x/usb_ehci.c @@ -36,6 +36,25 @@ static void usb_ehci_init(struct device *dev) RCBA32(0x35b0) = reg32;
printk(BIOS_DEBUG, "EHCI: Setting up controller.. "); + + pci_write_config32 (dev, 0x68, 0x00010001); + if (PCI_SLOT (dev->path.pci.devfn) == 0x1a) + pci_write_config32 (dev, 0x6c, 0x400a2005); + else + pci_write_config32 (dev, 0x6c, 0x40082005); + + pci_write_config32 (dev, 0x70, 0x3fdd0000); + pci_write_config32 (dev, 0x84, 0x130c8911); + pci_write_config32 (dev, 0x88, 0xa0); + if (PCI_SLOT (dev->path.pci.devfn) == 0x1a) + pci_write_config32 (dev, 0xec, 0x00629500); + else + pci_write_config32 (dev, 0xec, 0x00a10880); + pci_write_config32 (dev, 0xf4, 0x80808588); + pci_write_config32 (dev, 0xf4, 0x00808588); + pci_write_config32 (dev, 0xf4, 0x00808588); + pci_write_config32 (dev, 0xfc, 0x301b1728); + reg32 = pci_read_config32(dev, PCI_COMMAND); reg32 |= PCI_COMMAND_MASTER; //reg32 |= PCI_COMMAND_SERR; @@ -68,22 +87,28 @@ static void usb_ehci_set_subsystem(device_t dev, unsigned vendor, unsigned devic static void usb_ehci_set_resources(struct device *dev) { #if CONFIG_USBDEBUG - struct resource *res; - u32 base; - u32 usb_debug; + u32 usb_debug = 0;
+ if (PCI_SLOT(dev->path.pci.devfn) == 0x1a) + { usb_debug = get_ehci_debug(); set_ehci_debug(0); + } #endif pci_dev_set_resources(dev);
#if CONFIG_USBDEBUG + if (PCI_SLOT(dev->path.pci.devfn) == 0x1a) + { + struct resource *res; + u32 base; res = find_resource(dev, 0x10); - set_ehci_debug(usb_debug); if (!res) return; base = res->base; + set_ehci_debug(usb_debug); set_ehci_base(base); report_resource_stored(dev, res, ""); + } #endif }
@@ -103,7 +128,7 @@ static struct device_operations usb_ehci_ops = { };
static const unsigned short pci_device_ids[] = { 0x1c26, 0x1c2d, 0x1e26, 0x1e2d, - 0 }; + 0x3b34, 0x3b3c, 0 };
static const struct pci_driver pch_usb_ehci __pci_driver = { .ops = &usb_ehci_ops, diff --git a/util/inteltool/cpu.c b/util/inteltool/cpu.c index e73f096..bf5335c 100644 --- a/util/inteltool/cpu.c +++ b/util/inteltool/cpu.c @@ -888,6 +888,171 @@ int print_intel_core_msrs(void) { 0x0600, "IA32_DS_AREA" }, };
+ + static const msr_entry_t model20650_global_msrs[] = { + { 0x0000, "IA32_P5_MC_ADDR" }, + { 0x0001, "IA32_P5_MC_TYPE" }, + { 0x0006, "IA32_MONITOR_FILTER_LINE_SIZE" }, + { 0x0017, "IA32_PLATFORM_ID" }, + { 0x002a, "MSR_EBC_HARD_POWERON" }, + { 0x002b, "MSR_EBC_SOFT_POWRON" }, + { 0x002c, "MSR_EBC_FREQUENCY_ID" }, +// WRITE ONLY { 0x0079, "IA32_BIOS_UPDT_TRIG" }, + { 0x00e2, "IA32_MSR_PMG_CST_CONFIG" }, + { 0x019c, "IA32_THERM_STATUS" }, + { 0x019d, "MSR_THERM2_CTL" }, + { 0x01a0, "IA32_MISC_ENABLE" }, + { 0x01a1, "MSR_PLATFORM_BRV" }, + { 0x0200, "IA32_MTRR_PHYSBASE0" }, + { 0x0201, "IA32_MTRR_PHYSMASK0" }, + { 0x0202, "IA32_MTRR_PHYSBASE1" }, + { 0x0203, "IA32_MTRR_PHYSMASK1" }, + { 0x0204, "IA32_MTRR_PHYSBASE2" }, + { 0x0205, "IA32_MTRR_PHYSMASK2" }, + { 0x0206, "IA32_MTRR_PHYSBASE3" }, + { 0x0207, "IA32_MTRR_PHYSMASK3" }, + { 0x0208, "IA32_MTRR_PHYSBASE4" }, + { 0x0209, "IA32_MTRR_PHYSMASK4" }, + { 0x020a, "IA32_MTRR_PHYSBASE5" }, + { 0x020b, "IA32_MTRR_PHYSMASK5" }, + { 0x020c, "IA32_MTRR_PHYSBASE6" }, + { 0x020d, "IA32_MTRR_PHYSMASK6" }, + { 0x020e, "IA32_MTRR_PHYSBASE7" }, + { 0x020f, "IA32_MTRR_PHYSMASK7" }, + { 0x0250, "IA32_MTRR_FIX64K_00000" }, + { 0x0258, "IA32_MTRR_FIX16K_80000" }, + { 0x0259, "IA32_MTRR_FIX16K_A0000" }, + { 0x0268, "IA32_MTRR_FIX4K_C0000" }, + { 0x0269, "IA32_MTRR_FIX4K_C8000" }, + { 0x026a, "IA32_MTRR_FIX4K_D0000" }, + { 0x026b, "IA32_MTRR_FIX4K_D8000" }, + { 0x026c, "IA32_MTRR_FIX4K_E0000" }, + { 0x026d, "IA32_MTRR_FIX4K_E8000" }, + { 0x026e, "IA32_MTRR_FIX4K_F0000" }, + { 0x026f, "IA32_MTRR_FIX4K_F8000" }, + { 0x02ff, "IA32_MTRR_DEF_TYPE" }, + { 0x0300, "MSR_BPU_COUNTER0" }, + { 0x0301, "MSR_BPU_COUNTER1" }, + { 0x0302, "MSR_BPU_COUNTER2" }, + { 0x0303, "MSR_BPU_COUNTER3" }, + /* Skipped through 0x3ff for now*/ + + /* All MCX_ADDR AND MCX_MISC MSRs depend on a bit being + * set in MCX_STATUS */ + { 0x400, "IA32_MC0_CTL" }, + { 0x401, "IA32_MC0_STATUS" }, + { 0x402, "IA32_MC0_ADDR" }, + { 0x403, "IA32_MC0_MISC" }, + { 0x404, "IA32_MC1_CTL" }, + { 0x405, "IA32_MC1_STATUS" }, + { 0x406, "IA32_MC1_ADDR" }, + { 0x407, "IA32_MC1_MISC" }, + { 0x408, "IA32_MC2_CTL" }, + { 0x409, "IA32_MC2_STATUS" }, + { 0x40a, "IA32_MC2_ADDR" }, + { 0x40b, "IA32_MC2_MISC" }, + { 0x40c, "IA32_MC3_CTL" }, + { 0x40d, "IA32_MC3_STATUS" }, + { 0x40e, "IA32_MC3_ADDR" }, + { 0x40f, "IA32_MC3_MISC" }, + { 0x410, "IA32_MC4_CTL" }, + { 0x411, "IA32_MC4_STATUS" }, + { 0x412, "IA32_MC4_ADDR" }, + { 0x413, "IA32_MC4_MISC" }, + }; + + static const msr_entry_t model20650_per_core_msrs[] = { + { 0x0010, "IA32_TIME_STAMP_COUNTER" }, + { 0x001b, "IA32_APIC_BASE" }, + { 0x003a, "IA32_FEATURE_CONTROL" }, + { 0x008b, "IA32_BIOS_SIGN_ID" }, + { 0x009b, "IA32_SMM_MONITOR_CTL" }, + { 0x00e4, "IA32_PMG_IO_CAPTURE_BASE" }, + { 0x00fe, "IA32_MTRRCAP" }, + { 0x0174, "IA32_SYSENTER_CS" }, + { 0x0175, "IA32_SYSENTER_ESP" }, + { 0x0176, "IA32_SYSENTER_EIP" }, + { 0x0179, "IA32_MCG_CAP" }, + { 0x017a, "IA32_MCG_STATUS" }, + { 0x0180, "MSR_MCG_RAX" }, + { 0x0181, "MSR_MCG_RBX" }, + { 0x0182, "MSR_MCG_RCX" }, + { 0x0183, "MSR_MCG_RDX" }, + { 0x0184, "MSR_MCG_RSI" }, + { 0x0185, "MSR_MCG_RDI" }, + { 0x0186, "MSR_MCG_RBP" }, + { 0x0187, "MSR_MCG_RSP" }, + { 0x0188, "MSR_MCG_RFLAGS" }, + { 0x0189, "MSR_MCG_RIP" }, + { 0x018a, "MSR_MCG_MISC" }, + // 0x18b-f Reserved + { 0x0190, "MSR_MCG_R8" }, + { 0x0191, "MSR_MCG_R9" }, + { 0x0192, "MSR_MCG_R10" }, + { 0x0193, "MSR_MCG_R11" }, + { 0x0194, "MSR_MCG_R12" }, + { 0x0195, "MSR_MCG_R13" }, + { 0x0196, "MSR_MCG_R14" }, + { 0x0197, "MSR_MCG_R15" }, + { 0x0198, "IA32_PERF_STATUS" }, + { 0x0199, "IA32_PERF_CTL" }, + { 0x019a, "IA32_CLOCK_MODULATION" }, + { 0x019b, "IA32_THERM_INTERRUPT" }, + { 0x01a0, "IA32_MISC_ENABLE" }, // Bit 34 is Core Specific + { 0x01aa, "IA32_MISC_PWR_MGMT" }, + { 0x01d7, "MSR_LER_FROM_LIP" }, + { 0x01d8, "MSR_LER_TO_LIP" }, + { 0x01d9, "MSR_DEBUGCTLA" }, + { 0x01da, "MSR_LASTBRANCH_TOS" }, + { 0x01fc, "MSR_POWER_CTL" }, + { 0x0277, "IA32_PAT" }, + /** Virtualization + { 0x480, "IA32_VMX_BASIC" }, + through + { 0x48b, "IA32_VMX_PROCBASED_CTLS2" }, + Not implemented in my CPU + */ + { 0x0600, "IA32_DS_AREA" }, + /* 0x0680 - 0x06cf Branch Records Skipped */ + +{ 0x3a, "IA32_FEATURE_CONTROL" }, +{ 0x13c, "MSR_FEATURE_CONFIG" }, +{ 0x194, "MSR_FLEX_RATIO" }, +{ 0x1f8, "IA32_PLATFORM_DCA_CAP" }, +{ 0x1a0, "IA32_MISC_ENABLE" }, +{ 0x1a2, "MSR_TEMPERATURE_TARGET" }, +{ 0x199, "IA32_PERF_CTL" }, +{ 0x19b, "IA32_THERM_INTERRUPT" }, +{ 0x1b0, "IA32_ENERGY_PERFORMANCE_BIAS" }, +{ 0x1b2, "IA32_PACKAGE_THERM_INTERRUPT" }, +{ 0x2e7, "MSR_LT_LOCK_MEMORY" }, +{ 0x401, "IA32_MC0_STATUS" }, +{ 0x2e, "MSR_PIC_MSG_CONTROL" }, +{ 0xce, "MSR_PLATFORM_INFO" }, +{ 0xe2, "MSR_PMG_CST_CONFIG_CONTROL" }, +{ 0xe4, "MSR_PMG_IO_CAPTURE_BASE" }, +{ 0x1aa, "MSR_MISC_PWR_MGMT" }, +{ 0x1ad, "MSR_TURBO_RATIO_LIMIT" }, +{ 0x1fc, "MSR_POWER_CTL" }, +{ 0x60a, "MSR_PKGC3_IRTL" }, +{ 0x60b, "MSR_PKGC6_IRTL" }, +{ 0x60c, "MSR_PKGC7_IRTL" }, +{ 0x610, "MSR_PKG_POWER_LIMIT" }, +{ 0x601, "MSR_PP0_CURRENT_CONFIG" }, +{ 0x602, "MSR_PP1_CURRENT_CONFIG" }, +{ 0x606, "MSR_PKG_POWER_SKU_UNIT" }, +{ 0x614, "MSR_PKG_POWER_SKU" }, +{ 0x638, "MSR_PP0_POWER_LIMIT" }, +{ 0x640, "MSR_PP1_POWER_LIMIT" }, +{ 0x648, "MSR_CONFIG_TDP_NOMINAL" }, +{ 0x649, "MSR_CONFIG_TDP_LEVEL1" }, +{ 0x64a, "MSR_CONFIG_TDP_LEVEL2" }, +{ 0x64b, "MSR_CONFIG_TDP_CONTROL" }, +{ 0x64c, "MSR_TURBO_ACTIVATION_RATIO" }, + + + }; + typedef struct { unsigned int model; const msr_entry_t *global_msrs; @@ -904,6 +1069,7 @@ int print_intel_core_msrs(void) { 0x00f20, modelf2x_global_msrs, ARRAY_SIZE(modelf2x_global_msrs), modelf2x_per_core_msrs, ARRAY_SIZE(modelf2x_per_core_msrs) }, { 0x00f40, modelf4x_global_msrs, ARRAY_SIZE(modelf4x_global_msrs), modelf4x_per_core_msrs, ARRAY_SIZE(modelf4x_per_core_msrs) }, { 0x106c0, model6_atom_global_msrs, ARRAY_SIZE(model6_atom_global_msrs), model6_atom_per_core_msrs, ARRAY_SIZE(model6_atom_per_core_msrs) }, + { 0x20650, model20650_global_msrs, ARRAY_SIZE(model20650_global_msrs), model20650_per_core_msrs, ARRAY_SIZE(model20650_per_core_msrs) }, };
cpu_t *cpu = NULL; diff --git a/util/inteltool/gpio.c b/util/inteltool/gpio.c index 1d48a68..6da6bdd 100644 --- a/util/inteltool/gpio.c +++ b/util/inteltool/gpio.c @@ -294,6 +294,12 @@ int print_gpios(struct pci_dev *sb) size = ARRAY_SIZE(i631x_gpio_registers); break;
+ case 0x3b07: + gpiobase = pci_read_word(sb, 0x48) & 0xfffc; + gpio_registers = i631x_gpio_registers; + size = ARRAY_SIZE(i631x_gpio_registers); + break; + case PCI_DEVICE_ID_INTEL_82371XX: printf("This southbridge has GPIOs in the PM unit.\n"); return 1; diff --git a/util/inteltool/memory.c b/util/inteltool/memory.c index 72a2de4..0cf4e17 100644 --- a/util/inteltool/memory.c +++ b/util/inteltool/memory.c @@ -64,13 +64,108 @@ static const io_register_t sandybridge_mch_registers[] = { { 0x5D10, 8, "SSKPD" }, // Sticky Scratchpad Data };
+volatile uint8_t *mchbar; + +static void +write_mchbar32 (uint32_t addr, uint32_t val) +{ + * (volatile uint32_t *) (mchbar + addr) = val; +} + +static uint32_t +read_mchbar32 (uint32_t addr) +{ + return * (volatile uint32_t *) (mchbar + addr); +} + +static uint8_t +read_mchbar8 (uint32_t addr) +{ + return * (volatile uint8_t *) (mchbar + addr); +} + +static u16 +read_500 (int channel, u16 addr, int split) +{ + uint32_t val; + write_mchbar32 (0x500 + (channel << 10), 0); + while (read_mchbar32 (0x500 + (channel << 10)) & 0x800000); + write_mchbar32 (0x500 + (channel << 10), 0x80000000 | (((read_mchbar8 (0x246 + (channel << 10)) >> 2) & 3) + 0xb88 - addr)); + while (read_mchbar32 (0x500 + (channel << 10)) & 0x800000); + val = read_mchbar32 (0x508 + (channel << 10)); + return val & ((1 << split) - 1); +} + +static inline u16 +get_lane_offset (int slot, int rank, int lane) +{ + return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot - 0x452 * (lane == 8); +} + +static inline u16 +get_timing_register_addr (int lane, int tm, int slot, int rank) +{ + const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c }; + return get_lane_offset (slot, rank, lane) + offs[(tm + 3) % 4]; +} + +static void +write_1d0 (u32 val, u16 addr, int bits, int flag) +{ + write_mchbar32 (0x1d0, 0); + while (read_mchbar32 (0x1d0) & 0x800000); + write_mchbar32 (0x1d4, (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits)); + write_mchbar32 (0x1d0, 0x40000000 | addr); + while (read_mchbar32 (0x1d0) & 0x800000); +} + +static u16 +read_1d0 (u16 addr, int split) +{ + u32 val; + write_mchbar32 (0x1d0, 0); + while (read_mchbar32 (0x1d0) & 0x800000); + write_mchbar32 (0x1d0, 0x80000000 | (((read_mchbar8 (0x246) >> 2) & 3) + 0x361 - addr)); + while (read_mchbar32 (0x1d0) & 0x800000); + val = read_mchbar32 (0x1d8); + write_1d0 (0, 0x33d, 0, 0); + write_1d0 (0, 0x33d, 0, 0); + return val & ((1 << split) - 1); +} + + +static void +dump_timings (void) +{ + int channel, slot, rank, lane, i; + printf ("Timings:\n"); + for (channel = 0; channel < 2; channel++) + for (slot = 0; slot < 2; slot++) + for (rank = 0; rank < 2; rank++) + { + printf ("channel %d, slot %d, rank %d\n", channel, slot, rank); + for (lane = 0; lane < 9; lane++) + { + printf ("lane %d: ", lane); + for (i = 0; i < 4; i++) + { + printf ("%x ", read_500 (channel, + get_timing_register_addr (lane, i, slot, rank), 9)); + } + printf ("\n"); + } + } + printf ("[178] = %x\n", read_1d0 (0x178, 7)); + printf ("[10b] = %x\n", read_1d0 (0x10b, 6)); +} + + /* * (G)MCH MMIO Config Space */ int print_mchbar(struct pci_dev *nb, struct pci_access *pacc) { int i, size = (16 * 1024); - volatile uint8_t *mchbar; uint64_t mchbar_phys; const io_register_t *mch_registers = NULL; struct pci_dev *nb_device6; /* "overflow device" on i865 */ @@ -228,7 +323,9 @@ int print_mchbar(struct pci_dev *nb, struct pci_access *pacc) printf("0x%04x: 0x%08x\n", i, *(uint32_t *)(mchbar+i)); } } - + + printf ("clock_speed_index = %x\n", read_500 (0,0x609, 6) >> 1); + dump_timings (); unmap_physical((void *)mchbar, size); return 0; } diff --git a/util/inteltool/powermgt.c b/util/inteltool/powermgt.c index 71dfc49..9e3c2fb 100644 --- a/util/inteltool/powermgt.c +++ b/util/inteltool/powermgt.c @@ -677,6 +677,12 @@ int print_pmbase(struct pci_dev *sb, struct pci_access *pacc) size = ARRAY_SIZE(i63xx_pm_registers); break;
+ case 0x3b07: + pmbase = pci_read_word(sb, 0x40) & 0xfffc; + pm_registers = i63xx_pm_registers; + size = ARRAY_SIZE(i63xx_pm_registers); + break; + case 0x1234: // Dummy for non-existent functionality printf("This southbridge does not have PMBASE.\n"); return 1; diff --git a/util/inteltool/rootcmplx.c b/util/inteltool/rootcmplx.c index a478731..b307644 100644 --- a/util/inteltool/rootcmplx.c +++ b/util/inteltool/rootcmplx.c @@ -47,6 +47,7 @@ int print_rcba(struct pci_dev *sb) case PCI_DEVICE_ID_INTEL_ICH10R: case PCI_DEVICE_ID_INTEL_NM10: case PCI_DEVICE_ID_INTEL_I63XX: + case 0x3b07: rcba_phys = pci_read_long(sb, 0xf0) & 0xfffffffe; break; case PCI_DEVICE_ID_INTEL_ICH: