diff options
author | Stefan Reinauer <stepan@coresystems.de> | 2009-04-17 08:37:18 +0000 |
---|---|---|
committer | Stefan Reinauer <stepan@openbios.org> | 2009-04-17 08:37:18 +0000 |
commit | aeba92ab5b0afd1464d6b1a275b5f5b00b351b32 (patch) | |
tree | 225fbff67fc05e70507ac6ef7b3af32f00bac6f8 /src | |
parent | 56c51bd120a935e64cfd96d8ad71c9d1f7aab323 (diff) | |
download | coreboot-aeba92ab5b0afd1464d6b1a275b5f5b00b351b32.tar.xz |
Add VIA CX700 support, plus VIA vt8454c reference board support.
Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
Acked-by: Ronald G. Minnich <rminnich@gmail.com>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4126 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src')
39 files changed, 6154 insertions, 6 deletions
diff --git a/src/cpu/via/car/cache_as_ram_post.c b/src/cpu/via/car/cache_as_ram_post.c new file mode 100644 index 0000000000..99e0dd89ec --- /dev/null +++ b/src/cpu/via/car/cache_as_ram_post.c @@ -0,0 +1,106 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 VIA Technologies, Inc. + * (Written by Jason Zhao <jasonzhao@viatech.com.cn> for VIA) + * + * 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 + */ + + __asm__ volatile ( + /* + FIXME : backup stack in CACHE_AS_RAM into mmx and sse and after we get STACK up, we restore that. + It is only needed if we want to go back + */ + + /* We don't need cache as ram for now on */ + /* disable cache */ + "movl %cr0, %eax\n\t" + "orl $(0x1<<30),%eax\n\t" + "movl %eax, %cr0\n\t" + + + /* Set the default memory type and disable fixed and enable variable MTRRs */ + "movl $0x2ff, %ecx\n\t" + //"movl $MTRRdefType_MSR, %ecx\n\t" + "xorl %edx, %edx\n\t" + /* Enable Variable and Disable Fixed MTRRs */ + "movl $0x00000800, %eax\n\t" + "wrmsr\n\t" + + /* enable caching for first 1M using variable mtrr */ + "movl $0x200, %ecx\n\t" + "xorl %edx, %edx\n\t" + "movl $(0 | 6), %eax\n\t" + //"movl $(0 | MTRR_TYPE_WRBACK), %eax\n\t" + "wrmsr\n\t" + +/*Jasonzhao@viatech.com.cn, I enable cache for 0-7ffff, 80000-9ffff, e0000-fffff; +if 1M cacheable,then when S3 resume, there is stange color on screen for 2 sec. +suppose problem of a0000-dfffff and cache . +and in x86_setup_fixed_mtrrs()(mtrr.c), 0-256M is set cacheable.*/ + + "movl $0x201, %ecx\n\t" + "movl $0x0000000f, %edx\n\t" /* AMD 40 bit 0xff*/ + "movl $((~(( 0 + 0x80000) - 1)) | 0x800), %eax\n\t" + "wrmsr\n\t" + + "movl $0x202, %ecx\n\t" + "xorl %edx, %edx\n\t" + "movl $(0x80000 | 6), %eax\n\t" + "orl $(0 | 6), %eax\n\t" + "wrmsr\n\t" + + "movl $0x203, %ecx\n\t" + "movl $0x0000000f, %edx\n\t" /* AMD 40 bit 0xff*/ + "movl $((~(( 0 + 0x20000) - 1)) | 0x800), %eax\n\t" + "wrmsr\n\t" + + "movl $0x204, %ecx\n\t" + "xorl %edx, %edx\n\t" + "movl $(0xc0000 | 6), %eax\n\t" + "orl $(0 | 6), %eax\n\t" + "wrmsr\n\t" + + "movl $0x205, %ecx\n\t" + "movl $0x0000000f, %edx\n\t" /* AMD 40 bit 0xff*/ + "movl $((~(( 0 + 0x40000) - 1)) | 0x800), %eax\n\t" + "wrmsr\n\t" + + /*jasonzhao@viatech.com.cn add this 2008-11-27, cache XIP_ROM_BASE-SIZE to speedup the coreboot code*/ + "movl $0x206, %ecx\n\t" + "xorl %edx, %edx\n\t" + "movl $XIP_ROM_BASE,%eax\n\t" + "orl $(0 | 6), %eax\n\t" + "wrmsr\n\t" + + "movl $0x207, %ecx\n\t" + "xorl %edx, %edx\n\t" + "movl $XIP_ROM_SIZE,%eax\n\t" + "decl %eax\n\t" + "notl %eax\n\t" + "orl $(0 | 0x800), %eax\n\t" + "wrmsr\n\t" + + /* enable cache */ + "movl %cr0, %eax\n\t" + "andl $0x9fffffff,%eax\n\t" + "movl %eax, %cr0\n\t" + "invd\n\t" + + /* + FIXME: I hope we don't need to change esp and ebp value here, so we can restore value from mmx sse back + But the problem is the range is some io related, So don't go back + */ + ); diff --git a/src/cpu/via/model_c7/Config.lb b/src/cpu/via/model_c7/Config.lb index d956832162..a95697dd4d 100644 --- a/src/cpu/via/model_c7/Config.lb +++ b/src/cpu/via/model_c7/Config.lb @@ -5,8 +5,8 @@ # # 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. +# 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 diff --git a/src/cpu/via/model_c7/model_c7_init.c b/src/cpu/via/model_c7/model_c7_init.c index c32c9b5220..d9d59d1c58 100644 --- a/src/cpu/via/model_c7/model_c7_init.c +++ b/src/cpu/via/model_c7/model_c7_init.c @@ -1,12 +1,12 @@ /* * This file is part of the coreboot project. * - * (C) 2007-2008 coresystems GmbH + * (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; either version 2 of - * the License, or (at your option) any later version. + * 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 @@ -195,6 +195,11 @@ static void model_c7_init(device_t dev) /* Gear up */ set_c7_speed(c.x86_model); + /* Enable APIC */ + msr = rdmsr(0x1107); + msr.lo |= 1<<24; + wrmsr(0x1107, msr); + /* Turn on cache */ x86_enable_cache(); diff --git a/src/cpu/x86/car/copy_and_run.c b/src/cpu/x86/car/copy_and_run.c index bd2662e0c0..7a070ee648 100644 --- a/src/cpu/x86/car/copy_and_run.c +++ b/src/cpu/x86/car/copy_and_run.c @@ -56,6 +56,11 @@ static void copy_and_run(unsigned cpu_reset) #else print_spew("coreboot_ram.bin length = "); print_spew_hex32(olen); print_spew("\r\n"); #endif +#ifdef CONFIG_DEACTIVATE_CAR + print_debug("Deactivating CAR"); +#include CONFIG_DEACTIVATE_CAR_FILE + print_debug(" - Done.\r\n"); +#endif print_debug("Jumping to coreboot.\r\n"); if(cpu_reset == 1 ) { diff --git a/src/include/pc80/i8259.h b/src/include/pc80/i8259.h index 10a3fc8071..48e8df58d9 100644 --- a/src/include/pc80/i8259.h +++ b/src/include/pc80/i8259.h @@ -1 +1,25 @@ +/* + * 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 + */ + +#ifndef PC80_I8259_H +#define PC80_I8259_H + void setup_i8259(void); + +#endif /* PC80_I8259_H */ diff --git a/src/include/spd_ddr2.h b/src/include/spd_ddr2.h index a1deb36c96..09851f9715 100644 --- a/src/include/spd_ddr2.h +++ b/src/include/spd_ddr2.h @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2007 Advanced Micro Devices, Inc. + * 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 @@ -29,6 +30,7 @@ #define SPD_DIMM_TYPE_uDIMM (1<<3) #define SPD_DIMM_TYPE_mRDIMM (1<<4) #define SPD_DIMM_TYPE_mUDIMM (1<<5) + #define SPD_MOD_ATTRIB 21 #define SPD_MOD_ATTRIB_DIFCK 0x20 #define SPD_MOD_ATTRIB_REGADC 0x11 /* x */ @@ -39,6 +41,15 @@ #define SPD_DIMM_CONF_TYPE_ECC 0x02 #define SPD_DIMM_CONF_TYPE_ADDR_PARITY 0x04 /* ? */ +#define SPD_CAS_LAT_MIN_X_1 23 +#define SPD_CAS_LAT_MAX_X_1 24 +#define SPD_CAS_LAT_MIN_X_2 25 +#define SPD_CAS_LAT_MAX_X_2 26 + +#define SPD_BURST_LENGTHS 16 + #define SPD_BURST_LENGTHS_4 (1<<2) + #define SPD_BURST_LENGTHS_8 (1<<3) + #define SPD_ROW_NUM 3 /* Number of Row addresses */ #define SPD_COL_NUM 4 /* Number of Column addresses */ #define SPD_BANK_NUM 17 /* SDRAM Device attributes - Number of Banks on @@ -82,6 +93,7 @@ #define SPD_TWTR 37 /* x */ #define SPD_TRTP 38 /* x */ +#define SPD_EX_TRC_TRFC 40 #define SPD_TRC 41 /* add byte 0x40 bit [3:1] , so final val41+ table[((val40>>1) & 0x7)] ... table[]={0, 0.25, 0.33, 0.5, 0.75, 0, 0}*/ #define SPD_TRFC 42 /* add byte 0x40 bit [6:4] , so final val42+ table[((val40>>4) & 0x7)] + (val40 & 1)*256*/ diff --git a/src/mainboard/via/vt8454c/Config.lb b/src/mainboard/via/vt8454c/Config.lb new file mode 100644 index 0000000000..5cda9d228e --- /dev/null +++ b/src/mainboard/via/vt8454c/Config.lb @@ -0,0 +1,198 @@ +## +## 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 +## + +## +## Compute the location and size of where this firmware image +## (coreboot plus bootloader) will live in the boot rom chip. +## +if USE_FALLBACK_IMAGE + default ROM_SECTION_SIZE = FALLBACK_SIZE + default ROM_SECTION_OFFSET = ( ROM_SIZE - FALLBACK_SIZE ) +else + default ROM_SECTION_SIZE = ( ROM_SIZE - FALLBACK_SIZE ) + default ROM_SECTION_OFFSET = 0 +end + +## +## Compute the start location and size size of +## The coreboot bootloader. +## +default PAYLOAD_SIZE = ( ROM_SECTION_SIZE - ROM_IMAGE_SIZE ) +default CONFIG_ROM_PAYLOAD_START = (0xffffffff - ROM_SIZE + ROM_SECTION_OFFSET + 1) + +## +## Compute where this copy of coreboot will start in the boot rom +## +default _ROMBASE = ( CONFIG_ROM_PAYLOAD_START + PAYLOAD_SIZE ) + +## +## Compute a range of ROM that can cached to speed up coreboot, +## execution speed. +## +## XIP_ROM_SIZE must be a power of 2. +## XIP_ROM_BASE must be a multiple of XIP_ROM_SIZE +## +default XIP_ROM_SIZE=65536 +default XIP_ROM_BASE = ( _ROMBASE + ROM_IMAGE_SIZE - XIP_ROM_SIZE ) + +## +## Set all of the defaults for an x86 architecture +## + +arch i386 end + +## +## Build the objects we have code for in this directory. +## + +driver mainboard.o + +if HAVE_MP_TABLE + object mptable.o +end + +if HAVE_PIRQ_TABLE + object irq_tables.o +end + +if HAVE_ACPI_TABLES + object fadt.o + object acpi_tables.o + makerule dsdt.c + depends "$(MAINBOARD)/dsdt.dsl" + action "iasl -p dsdt -tc $(MAINBOARD)/dsdt.dsl" + action "mv dsdt.hex dsdt.c" + end + object ./dsdt.o +end + +## +## Romcc output +## +makerule ./auto.inc + depends "$(MAINBOARD)/auto.c option_table.h" + action "$(CC) $(DISTRO_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(DEBUG_CFLAGS) -I$(TOP)/src -I. -nostdinc -nostdlib -fno-builtin -Wall -Os -c -S $(MAINBOARD)/auto.c -o $@" + action "perl -e 's/\.rodata/.rom.data/g' -pi $@" + action "perl -e 's/\.text/.section .rom.text/g' -pi $@" +end + +## +## Build our 16 bit and 32 bit coreboot entry code +## +mainboardinit cpu/x86/16bit/entry16.inc +mainboardinit cpu/x86/32bit/entry32.inc +ldscript /cpu/x86/16bit/entry16.lds +ldscript /cpu/x86/32bit/entry32.lds + +## +## Build our reset vector (This is where coreboot is entered) +## +if USE_FALLBACK_IMAGE + mainboardinit cpu/x86/16bit/reset16.inc + ldscript /cpu/x86/16bit/reset16.lds +else + mainboardinit cpu/x86/32bit/reset32.inc + ldscript /cpu/x86/32bit/reset32.lds +end + +mainboardinit cpu/via/car/cache_as_ram.inc + +## +## Include an id string (For safe flashing) +## +mainboardinit arch/i386/lib/id.inc +ldscript /arch/i386/lib/id.lds + +### +### O.k. We aren't just an intermediary anymore! +### + +## +## Setup RAM +## +mainboardinit cpu/x86/fpu/enable_fpu.inc +mainboardinit ./auto.inc + +## +## Include the secondary Configuration files +## +dir /pc80 +config chip.h + +chip northbridge/via/cx700 + device apic_cluster 0 on + chip cpu/via/model_c7 + device apic 0 on end + end + end + device pci_domain 0 on + device pci 0.0 on end # AGP Bridge + device pci 0.1 on end # Error Reporting + device pci 0.2 on end # Host Bus Control + device pci 0.3 on end # Memory Controller + device pci 0.4 on end # Power Management + device pci 0.7 on end # V-Link Controller + device pci 1.0 on # PCI Bridge + chip drivers/pci/onboard + device pci 0.0 on end + #register "rom_address" = "0xfffc0000" #256k image + register "rom_address" = "0xfff80000" #512k image + #register "rom_address" = "0xfff00000" #1024k image + end # Onboard Video + end # PCI Bridge + device pci f.0 on end # IDE/SATA + #device pci f.1 on end # IDE + device pci 10.0 on end # USB 1.1 + device pci 10.1 on end # USB 1.1 + device pci 10.2 on end # USB 1.1 + device pci 10.4 on end # USB 2.0 + device pci 11.0 on # Southbridge LPC + chip superio/via/vt1211 + device pnp 2e.0 on # Floppy + io 0x60 = 0x3f0 + irq 0x70 = 6 + drq 0x74 = 2 + end + device pnp 2e.1 on # Parallel Port + io 0x60 = 0x378 + irq 0x70 = 7 + drq 0x74 = 3 + end + device pnp 2e.2 on # COM1 + io 0x60 = 0x3f8 + irq 0x70 = 4 + end + device pnp 2e.3 on # COM2 + io 0x60 = 0x2f8 + irq 0x70 = 3 + end + device pnp 2e.b on # HWM + io 0x60 = 0xec00 + end + end # superio + end # pci 11.0 + # 1-4 non existant + #device pci 11.5 on end # AC97 Audio + #device pci 11.6 off end # AC97 Modem + #device pci 12.0 on end # Ethernet + end # pci domain 0 +end # cx700 + diff --git a/src/mainboard/via/vt8454c/Options.lb b/src/mainboard/via/vt8454c/Options.lb new file mode 100644 index 0000000000..4a319725f1 --- /dev/null +++ b/src/mainboard/via/vt8454c/Options.lb @@ -0,0 +1,246 @@ +## +## 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 +## + +uses HAVE_MP_TABLE +uses HAVE_PIRQ_TABLE +uses IRQ_SLOT_COUNT +uses HAVE_ACPI_TABLES +uses HAVE_OPTION_TABLE +uses USE_OPTION_TABLE + +uses USE_FALLBACK_IMAGE +uses HAVE_FALLBACK_BOOT +uses HAVE_HARD_RESET +uses MAINBOARD +uses MAINBOARD_VENDOR +uses MAINBOARD_PART_NUMBER +uses COREBOOT_EXTRA_VERSION +uses ARCH +uses FALLBACK_SIZE +uses STACK_SIZE +uses HEAP_SIZE +uses ROM_SIZE +uses ROM_SECTION_SIZE +uses ROM_IMAGE_SIZE +uses ROM_SECTION_SIZE +uses ROM_SECTION_OFFSET + +uses CONFIG_COMPRESS +uses CONFIG_ROM_PAYLOAD +uses CONFIG_ROM_PAYLOAD_START +uses CONFIG_COMPRESSED_PAYLOAD_NRV2B +uses CONFIG_COMPRESSED_PAYLOAD_LZMA +uses PAYLOAD_SIZE + +uses _ROMBASE +uses _RAMBASE +uses XIP_ROM_SIZE +uses XIP_ROM_BASE +uses CONFIG_CBFS + +# compiler specifics +uses CROSS_COMPILE +uses CC +uses HOSTCC +uses OBJCOPY + +# Console specifics +uses DEFAULT_CONSOLE_LOGLEVEL +uses MAXIMUM_CONSOLE_LOGLEVEL +uses CONFIG_CONSOLE_SERIAL8250 +uses TTYS0_BAUD +uses TTYS0_BASE +uses TTYS0_LCS + +uses CONFIG_UDELAY_TSC +uses CONFIG_TSC_X86RDTSC_CALIBRATE_WITH_TIMER2 +uses CONFIG_PCI_ROM_RUN +uses CONFIG_CONSOLE_VGA +uses CONFIG_MAX_PCI_BUSES +uses CONFIG_SMP +uses CONFIG_IOAPIC + +uses CONFIG_GDB_STUB + +uses USE_DCACHE_RAM +uses DCACHE_RAM_BASE +uses DCACHE_RAM_SIZE +uses CONFIG_USE_PRINTK_IN_CAR + +## ROM_SIZE is the size of boot ROM that this board will use. +default ROM_SIZE = 256*1024 + +default USE_DCACHE_RAM=1 +default DCACHE_RAM_BASE=0xffef0000 +#default DCACHE_RAM_BASE=0xffbf0000 +#default DCACHE_RAM_BASE=0xfec00000 +default DCACHE_RAM_SIZE=0x8000 +default CONFIG_USE_PRINTK_IN_CAR=1 + +### +### Leave this to 0; VGA is handled by seperate code. +### +default CONFIG_PCI_ROM_RUN=0 +default CONFIG_CONSOLE_VGA=0 + +## +## Build code for the fallback boot +## +default HAVE_FALLBACK_BOOT=1 + +## +## Use TSC for udelay. +## +default CONFIG_UDELAY_TSC=1 +default CONFIG_TSC_X86RDTSC_CALIBRATE_WITH_TIMER2=1 + +## +## Build code to reset the motherboard from linuxBIOS +## +default HAVE_HARD_RESET=1 + +## +## Build code to export a programmable irq routing table +## +default HAVE_PIRQ_TABLE=1 +default IRQ_SLOT_COUNT=15 + +## +## Build code to export an x86 MP table +## Useful for specifying IRQ routing values +## +default HAVE_MP_TABLE=1 + +## +## Build code to load acpi tables +## +default HAVE_ACPI_TABLES=1 + +## +## Build code to export a CMOS option table +## +default HAVE_OPTION_TABLE=1 + + +## +## Build code to setup a generic IOAPIC +## +default CONFIG_SMP=1 +default CONFIG_IOAPIC=1 + +### +### LinuxBIOS layout values +### + +## ROM_IMAGE_SIZE is the amount of space to allow linuxBIOS to occupy. +default ROM_IMAGE_SIZE = 65536 +default FALLBACK_SIZE = 131072 + +## +## Use a small 8K stack +## +default STACK_SIZE=0x2000 + +## +## Use a small 16K heap +## +default HEAP_SIZE=0x4000 + +## +## Only use the option table in a normal image +## +#default USE_OPTION_TABLE = !USE_FALLBACK_IMAGE +default USE_OPTION_TABLE = 0 + +default _RAMBASE = 0x00004000 + +default CONFIG_ROM_PAYLOAD = 1 + +## +## The default compiler +## +default CROSS_COMPILE="" +default CC="$(CROSS_COMPILE)gcc -m32" +default HOSTCC="gcc" + +## +## Set this to the max PCI bus number you +## would ever use for PCI config IO. +## Setting this number very high will make +## pci_locate_device take a long time when +## it can't find a device. +## +default CONFIG_MAX_PCI_BUSES = 0x80 + +## +## Disable the gdb stub by default +## +default CONFIG_GDB_STUB=0 + +## +## The Serial Console +## + +# To Enable the Serial Console +default CONFIG_CONSOLE_SERIAL8250=1 + +## Select the serial console baud rate +default TTYS0_BAUD=115200 +#default TTYS0_BAUD=57600 +#default TTYS0_BAUD=38400 +#default TTYS0_BAUD=19200 +#default TTYS0_BAUD=9600 +#default TTYS0_BAUD=4800 +#default TTYS0_BAUD=2400 +#default TTYS0_BAUD=1200 + +# Select the serial console base port +default TTYS0_BASE=0x3f8 + +# Select the serial protocol +# This defaults to 8 data bits, 1 stop bit, and no parity +default TTYS0_LCS=0x3 + +## +## Select the coreboot loglevel +## +## EMERG 1 system is unusable +## ALERT 2 action must be taken immediately +## CRIT 3 critical conditions +## ERR 4 error conditions +## WARNING 5 warning conditions +## NOTICE 6 normal but significant condition +## INFO 7 informational +## DEBUG 8 debug-level messages +## SPEW 9 Way too many details + +## Request this level of debugging output +default DEFAULT_CONSOLE_LOGLEVEL=5 +## At a maximum only compile in this level of debugging +default MAXIMUM_CONSOLE_LOGLEVEL=5 + +# +# CBFS +# +default CONFIG_CBFS=0 + +end + diff --git a/src/mainboard/via/vt8454c/acpi_tables.c b/src/mainboard/via/vt8454c/acpi_tables.c new file mode 100644 index 0000000000..edf8d7e207 --- /dev/null +++ b/src/mainboard/via/vt8454c/acpi_tables.c @@ -0,0 +1,205 @@ +/* + * 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/acpi.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include "dmi.h" + +extern unsigned char AmlCode[]; + +unsigned long acpi_fill_mcfg(unsigned long current) +{ + device_t dev; + u64 mmcfg; + + dev = dev_find_device(0x1106, 0x324b, 0); // 0:0x13.0 + if (!dev) + return current; + + // MMCFG not supported or not enabled. + if ((pci_read_config8(dev, 0x40) & 0xC0) != 0xC0) + return current; + + mmcfg = ((u64) pci_read_config8(dev, 0x41)) << 28; + if (!mmcfg) + return current; + + current += acpi_create_mcfg_mmconfig((acpi_mcfg_mmconfig_t *) current, mmcfg, 0x0, 0x0, 0xff); + + return current; +} + + +void acpi_create_via_hpet(acpi_hpet_t * hpet) +{ +#define HPET_ADDR 0xfe800000ULL + acpi_header_t *header = &(hpet->header); + acpi_addr_t *addr = &(hpet->addr); + + memset((void *) hpet, 0, sizeof(acpi_hpet_t)); + + /* fill out header fields */ + memcpy(header->signature, HPET_NAME, 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, "COREBOOT", 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(acpi_hpet_t); + header->revision = 1; + + /* fill out HPET address */ + // XXX factory bios just puts an address here -- who's right? + addr->space_id = 0; /* Memory */ + addr->bit_width = 64; + addr->bit_offset = 0; + addr->addrl = HPET_ADDR & 0xffffffff; + addr->addrh = HPET_ADDR >> 32; + + hpet->id = 0x11068201; /* VIA */ + hpet->number = 0x00; + hpet->min_tick = 0x0090; + + header->checksum = + acpi_checksum((void *) hpet, sizeof(acpi_hpet_t)); +} + + + +#define IO_APIC_ADDR 0xfec00000UL + +unsigned long acpi_fill_madt(unsigned long current) +{ + /* Local Apic */ + current += acpi_create_madt_lapic((acpi_madt_lapic_t *) current, 0, 0); + + /* IOAPIC */ + current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *) current, 2, IO_APIC_ADDR, 0); + + /* INT_SRC_OVR */ + current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *) current, 0, 0, 2, 0); + current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *) current, 0, 9, 9, 0x000f); // low/level + + /* LAPIC_NMI */ + current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *) current, 0, 0x0005, 1); // high/edge + + return 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; +} + +unsigned long write_acpi_tables(unsigned long start) +{ + unsigned long current; + acpi_rsdp_t *rsdp; + acpi_rsdt_t *rsdt; + acpi_hpet_t *hpet; + acpi_madt_t *madt; + acpi_mcfg_t *mcfg; + acpi_fadt_t *fadt; + acpi_facs_t *facs; + acpi_header_t *dsdt; + + /* Align ACPI tables to 16byte */ + start = (start + 0x0f) & -0x10; + current = start; + + printk_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); + rsdt = (acpi_rsdt_t *) current; + current += sizeof(acpi_rsdt_t); + + /* clear all table memory */ + memset((void *) start, 0, current - start); + + acpi_write_rsdp(rsdp, rsdt); + acpi_write_rsdt(rsdt); + + /* + * We explicitly add these tables later on: + */ + + printk_debug("ACPI: * HPET\n"); + + hpet = (acpi_hpet_t *) current; + current += sizeof(acpi_hpet_t); + acpi_create_via_hpet(hpet); + acpi_add_table(rsdt, hpet); + + /* If we want to use HPET Timers Linux wants an MADT */ + printk_debug("ACPI: * MADT\n"); + + madt = (acpi_madt_t *) current; + acpi_create_madt(madt); + current += madt->header.length; + acpi_add_table(rsdt, madt); + + printk_debug("ACPI: * MCFG\n"); + mcfg = (acpi_mcfg_t *) current; + acpi_create_mcfg(mcfg); + current += mcfg->header.length; + acpi_add_table(rsdt, mcfg); + + printk_debug("ACPI: * FACS\n"); + facs = (acpi_facs_t *) current; + current += sizeof(acpi_facs_t); + acpi_create_facs(facs); + + dsdt = (acpi_header_t *) current; + current += ((acpi_header_t *) AmlCode)->length; + memcpy((void *) dsdt, (void *) AmlCode, + ((acpi_header_t *) AmlCode)->length); +#if DONT_TRUST_IASL + dsdt->checksum = 0; // don't trust intel iasl compiler to get this right + dsdt->checksum = acpi_checksum(dsdt, dsdt->length); +#endif + printk_debug("ACPI: * DSDT @ %08x Length %x\n", dsdt, + dsdt->length); + printk_debug("ACPI: * FADT\n"); + + fadt = (acpi_fadt_t *) current; + current += sizeof(acpi_fadt_t); + + acpi_create_fadt(fadt, facs, dsdt); + acpi_add_table(rsdt, fadt); + + printk_debug("ACPI: * DMI (Linux workaround)\n"); + memcpy((void *)0xfff80, dmi_table, DMI_TABLE_SIZE); + + printk_info("ACPI: done.\n"); + return current; +} diff --git a/src/mainboard/via/vt8454c/auto.c b/src/mainboard/via/vt8454c/auto.c new file mode 100644 index 0000000000..1812fca139 --- /dev/null +++ b/src/mainboard/via/vt8454c/auto.c @@ -0,0 +1,127 @@ +/* + * 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 + */ + +#define ASSEMBLY 1 + +#include <stdint.h> +#include <device/pci_def.h> +#include <device/pci_ids.h> +#include <arch/io.h> +#include <device/pnp_def.h> +#include <arch/romcc_io.h> +#include <arch/hlt.h> +#include "pc80/serial.c" +#include "arch/i386/lib/console.c" +#include "ram/ramtest.c" +#include "northbridge/via/cx700/raminit.h" +#include "cpu/x86/mtrr/earlymtrr.c" +#include "cpu/x86/bist.h" + +#define CONFIG_DEACTIVATE_CAR 1 +#define CONFIG_DEACTIVATE_CAR_FILE "cpu/via/car/cache_as_ram_post.c" +#include "cpu/x86/car/copy_and_run.c" +#include "pc80/udelay_io.c" +#include "lib/delay.c" +#include "cpu/x86/lapic/boot_cpu.c" +#include "northbridge/via/cx700/cx700_early_smbus.c" +#include "debug.c" + +#include "northbridge/via/cx700/cx700_early_serial.c" +#include "northbridge/via/cx700/raminit.c" + +static void enable_mainboard_devices(void) +{ + device_t dev; + + dev = pci_locate_device(PCI_ID(0x1106, 0x8324), 0); + if (dev == PCI_DEV_INVALID) { + die("LPC bridge not found!!!\n"); + } + // Disable GP3 + pci_write_config8(dev, 0x98, 0x00); + + // Disable mc97 + pci_write_config8(dev, 0x50, 0x80); + + // Disable internal KBC Configuration + pci_write_config8(dev, 0x51, 0x2d); + pci_write_config8(dev, 0x58, 0x42); + pci_write_config8(dev, 0x59, 0x80); + pci_write_config8(dev, 0x5b, 0x01); + + // Enable P2P Bridge Header for External PCI BUS. + dev = pci_locate_device(PCI_ID(0x1106, 0x324e), 0); + if (dev == PCI_DEV_INVALID) { + die("P2P bridge not found!!!\n"); + } + pci_write_config8(dev, 0x4f, 0x41); + + // Switch SATA to non-RAID mode + dev = pci_locate_device(PCI_ID(0x1106, 0x0581), 0); + if (dev != PCI_DEV_INVALID) { + pci_write_config16(dev, 0xBA, 0x5324); + } +} + +static void enable_shadow_ram(const struct mem_controller *ctrl) +{ + u8 shadowreg; + + pci_write_config8(PCI_DEV(0, 0, 3), 0x80, 0x2a); + + /* 0xf0000-0xfffff - ACPI tables */ + shadowreg = pci_read_config8(PCI_DEV(0, 0, 3), 0x83); + shadowreg |= 0x30; + pci_write_config8(PCI_DEV(0, 0, 3), 0x83, shadowreg); +} + +static void main(unsigned long bist) +{ + /* Set statically so it should work with cx700 as well */ + static const struct mem_controller cx700[] = { + { + .channel0 = {0x50, 0x51}, + }, + }; + + enable_smbus(); + + enable_cx700_serial(); + uart_init(); + console_init(); + + /* Halt if there was a built in self test failure */ + report_bist_failure(bist); + + enable_mainboard_devices(); + + /* Allows access to all northbridge devices */ + pci_write_config8(PCI_DEV(0, 0, 0), 0x4f, 0x01); + + sdram_set_registers(cx700); + enable_shadow_ram(cx700); + sdram_enable(cx700); + copy_and_run(0); +} + +void amd64_main(unsigned long bist) { + main(bist); +} diff --git a/src/mainboard/via/vt8454c/chip.h b/src/mainboard/via/vt8454c/chip.h new file mode 100644 index 0000000000..ac8c5eb62d --- /dev/null +++ b/src/mainboard/via/vt8454c/chip.h @@ -0,0 +1,26 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +extern struct chip_operations mainboard_ops; + +struct mainboard_config { + int nothing; +}; diff --git a/src/mainboard/via/vt8454c/cmos.layout b/src/mainboard/via/vt8454c/cmos.layout new file mode 100644 index 0000000000..e80bb94d9d --- /dev/null +++ b/src/mainboard/via/vt8454c/cmos.layout @@ -0,0 +1,67 @@ +## 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 +## + +entries + +#start-bit length config config-ID name +0 384 r 0 reserved_memory +384 1 e 4 boot_option +385 1 e 4 last_boot +386 1 e 1 ECC_memory +388 4 r 0 reboot_bits +392 3 e 5 baud_rate +400 1 e 1 power_on_after_fail +412 4 e 6 debug_level +1008 16 h 0 check_sum + +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 6 Notice +6 7 Info +6 8 Debug +6 9 Spew +7 0 Network +7 1 HDD +7 2 Floppy +7 8 Fallback_Network +7 9 Fallback_HDD +7 10 Fallback_Floppy +#7 3 ROM + +checksums + +checksum 392 1007 1008 + + diff --git a/src/mainboard/via/vt8454c/debug.c b/src/mainboard/via/vt8454c/debug.c new file mode 100644 index 0000000000..54d8cf34e5 --- /dev/null +++ b/src/mainboard/via/vt8454c/debug.c @@ -0,0 +1,108 @@ +/* + * This file is part of the coreboot project. + * + * (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 + */ + +static void print_debug_pci_dev(unsigned dev) +{ + print_debug("PCI: "); + print_debug_hex8((dev >> 16) & 0xff); + print_debug_char(':'); + print_debug_hex8((dev >> 11) & 0x1f); + print_debug_char('.'); + print_debug_hex8((dev >> 8) & 7); +} + +static void print_pci_devices(void) +{ + device_t dev; + for (dev = PCI_DEV(0, 0, 0); + dev <= PCI_DEV(0, 0x1f, 0x7); dev += PCI_DEV(0, 0, 1)) { + u32 id; + id = pci_read_config32(dev, PCI_VENDOR_ID); + if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) + || (((id >> 16) & 0xffff) == 0xffff) + || (((id >> 16) & 0xffff) == 0x0000)) { + continue; + } + print_debug_pci_dev(dev); + print_debug("\r\n"); + } +} + +static void dump_pci_device(unsigned dev) +{ + int i; + print_debug_pci_dev(dev); + print_debug("\r\n"); + + for (i = 0; i <= 255; i++) { + unsigned char val; + if ((i & 0x0f) == 0) { + print_debug_hex8(i); + print_debug_char(':'); + } + val = pci_read_config8(dev, i); + print_debug_char(' '); + print_debug_hex8(val); + if ((i & 0x0f) == 0x0f) { + print_debug("\r\n"); + } + } +} + +static void dump_pci_devices(void) +{ + device_t dev; + for (dev = PCI_DEV(0, 0, 0); + dev <= PCI_DEV(0, 0x1f, 0x7); dev += PCI_DEV(0, 0, 1)) { + u32 id; + id = pci_read_config32(dev, PCI_VENDOR_ID); + if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) + || (((id >> 16) & 0xffff) == 0xffff) + || (((id >> 16) & 0xffff) == 0x0000)) { + continue; + } + dump_pci_device(dev); + } +} + + +static void dump_io_resources(unsigned port) +{ + + int i; + udelay(2000); + print_debug_hex16(port); + print_debug(":\r\n"); + for (i = 0; i < 256; i++) { + u8 val; + if ((i & 0x0f) == 0) { + print_debug_hex8(i); + print_debug_char(':'); + } + val = inb(port); + print_debug_char(' '); + print_debug_hex8(val); + if ((i & 0x0f) == 0x0f) { + print_debug("\r\n"); + } + port++; + } +} diff --git a/src/mainboard/via/vt8454c/dmi.h b/src/mainboard/via/vt8454c/dmi.h new file mode 100644 index 0000000000..17563f24c8 --- /dev/null +++ b/src/mainboard/via/vt8454c/dmi.h @@ -0,0 +1,31 @@ +/* + * 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 + */ + +#define DMI_TABLE_SIZE 0x55 + +static u8 dmi_table[DMI_TABLE_SIZE] = { + 0x5f, 0x53, 0x4d, 0x5f, 0x2d, 0x1f, 0x02, 0x03, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x44, 0x4d, 0x49, 0x5f, 0xeb, 0xa8, 0x03, 0xa0, 0xff, 0x0f, 0x00, 0x01, 0x00, 0x23, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x01, 0x02, 0x00, 0xe0, 0x03, 0x07, 0x90, 0xde, 0xcb, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x37, 0x01, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, + 0x47, 0x6d, 0x62, 0x48, 0x00, 0x32, 0x2e, 0x30, 0x00, 0x30, 0x33, 0x2f, 0x31, 0x33, 0x2f, 0x32, + 0x30, 0x30, 0x38, 0x00, 0x00 +}; diff --git a/src/mainboard/via/vt8454c/dsdt.dsl b/src/mainboard/via/vt8454c/dsdt.dsl new file mode 100644 index 0000000000..150fbcf5f9 --- /dev/null +++ b/src/mainboard/via/vt8454c/dsdt.dsl @@ -0,0 +1,341 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2004 Nick Barker <Nick.Barker9@btinternet.com> + * 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", 1, "CX700 ", "COREBOOT", 0x00000001) +{ + /* + * Define the main processor + */ + Scope (\_PR) + { + Processor (\_PR.CPU0, 0x00, 0x00000410, 0x06) {} + } + + /* For now only define 2 power states: + * - S0 which is fully on + * - S5 which is soft off + * any others would involve declaring the wake up methods + */ + Name (\_S0, Package () {0x00, 0x00, 0x00, 0x00 }) + Name (\_S5, Package () {0x02, 0x02, 0x00, 0x00 }) + + Scope (\) { + Name (PICF , 0) // Global flag indicating whether to use PIC or APIC mode + Method ( _PIC,1) // The OS is calling this + { + Store( Arg0 , PICF) + } + } // end of \ scope + + /* Root of the bus hierarchy */ + Scope (\_SB) + { + /* Define how interrupt Link A is plumbed in */ + Device (LNKA) + { + Name (_HID, EisaId ("PNP0C0F")) + Name (_UID, 0x01) + + /* Status - always return ready */ + Method (_STA, 0, NotSerialized) + { + Return (0x0B) + } + + /* Current Resources - return irq set up in BIOS */ + Method (_CRS, 0, NotSerialized) + { + Name (CRSP, ResourceTemplate () { + IRQ (Level, ActiveLow, Shared) {11} + }) + Name (CRSA, ResourceTemplate () { + Interrupt (ResourceConsumer, Level, ActiveLow, Shared) {16} + }) + + If (LNot (PICF)) { + Return (CRSP) + } Else { + Return (CRSA) + } + } + /* Possible Resources - return the range of irqs + * we are using for PCI - only here to keep Linux ACPI + * happy + */ + Method (_PRS, 0, NotSerialized) + { + Name (PRSP, ResourceTemplate () { + IRQ (Level, ActiveLow, Shared) {3,4,6,7,10,11,12} + }) + Name (PRSA, ResourceTemplate () { + Interrupt (ResourceConsumer, Level, ActiveLow, Shared) {16,17,18,19,20,21,22,23} + }) + + If (LNot (PICF)) { + Return (PRSP) + } Else { + Return (PRSA) + } + + } + /* Set Resources - dummy function to keep Linux ACPI happy + * Linux is more than happy not to tinker with irq + * assignments as long as the CRS and STA functions + * return good values + */ + Method (_SRS, 1, NotSerialized ) {} + /* Disable - dummy function to keep Linux ACPI happy */ + Method (_DIS, 0, NotSerialized ) {} + + } // End of LNKA + + /* Define how interrupt Link B is plumbed in */ + Device (LNKB) + { + Name (_HID, EisaId ("PNP0C0F")) + Name (_UID, 0x02) + + /* Status - always return ready */ + Method (_STA, 0, NotSerialized) + { + Return (0x0B) + } + + /* Current Resources - return irq set up in BIOS */ + Method (_CRS, 0, NotSerialized) + { + Name (CRSP, ResourceTemplate () { + IRQ (Level, ActiveLow, Shared) {11} + }) + Name (CRSA, ResourceTemplate () { + Interrupt (ResourceConsumer, Level, ActiveLow, Shared) {17} + }) + + If (LNot (PICF)) { + Return (CRSP) + } Else { + Return (CRSA) + } + } + /* Possible Resources - return the range of irqs + * we are using for PCI - only here to keep Linux ACPI + * happy + */ + Method (_PRS, 0, NotSerialized) + { + Name (PRSP, ResourceTemplate () { + IRQ (Level, ActiveLow, Shared) {3,4,6,7,10,11,12} + }) + Name (PRSA, ResourceTemplate () { + Interrupt (ResourceConsumer, Level, ActiveLow, Shared) {16,17,18,19,20,21,22,23} + }) + + If (LNot (PICF)) { + Return (PRSP) + } Else { + Return (PRSA) + } + + } + + /* Set Resources - dummy function to keep Linux ACPI happy + * Linux is more than happy not to tinker with irq + * assignments as long as the CRS and STA functions + * return good values + */ + Method (_SRS, 1, NotSerialized ) {} + /* Disable - dummy function to keep Linux ACPI happy */ + Method (_DIS, 0, NotSerialized ) {} + + } // End of LNKB + + /* Define how interrupt Link C is plumbed in */ + Device (LNKC) + { + Name (_HID, EisaId ("PNP0C0F")) + Name (_UID, 0x03) + + /* Status - always return ready */ + Method (_STA, 0, NotSerialized) + { + Return (0x0B) + } + + /* Current Resources - return irq set up in BIOS */ + Method (_CRS, 0, NotSerialized) + { + Name (CRSP, ResourceTemplate () { + IRQ (Level, ActiveLow, Shared) {10} + }) + Name (CRSA, ResourceTemplate () { + Interrupt (ResourceConsumer, Level, ActiveLow, Shared) {18} + }) + + If (LNot (PICF)) { + Return (CRSP) + } Else { + Return (CRSA) + } + } + /* Possible Resources - return the range of irqs + * we are using for PCI - only here to keep Linux ACPI + * happy + */ + Method (_PRS, 0, NotSerialized) + { + Name (PRSP, ResourceTemplate () { + IRQ (Level, ActiveLow, Shared) {3,4,6,7,10,11,12} + }) + Name (PRSA, ResourceTemplate () { + Interrupt (ResourceConsumer, Level, ActiveLow, Shared) {16,17,18,19,20,21,22,23} + }) + + If (LNot (PICF)) { + Return (PRSP) + } Else { + Return (PRSA) + } + + } + + /* Set Resources - dummy function to keep Linux ACPI happy + * Linux is more than happy not to tinker with irq + * assignments as long as the CRS and STA functions + * return good values + */ + Method (_SRS, 1, NotSerialized ) {} + /* Disable - dummy function to keep Linux ACPI happy */ + Method (_DIS, 0, NotSerialized ) {} + + } // End of LNKC + + /* Define how interrupt Link D is plumbed in */ + Device (LNKD) + { + Name (_HID, EisaId ("PNP0C0F")) + Name (_UID, 0x04) + + /* Status - always return ready */ + Method (_STA, 0, NotSerialized) + { + Return (0x0B) + } + + /* Current Resources - return irq set up in BIOS */ + Method (_CRS, 0, NotSerialized) + { + Name (CRSP, ResourceTemplate () { + IRQ (Level, ActiveLow, Shared) {10} + }) + Name (CRSA, ResourceTemplate () { + Interrupt (ResourceConsumer, Level, ActiveLow, Shared) {19} + }) + + If (LNot (PICF)) { + Return (CRSP) + } Else { + Return (CRSA) + } + } + /* Possible Resources - return the range of irqs + * we are using for PCI - only here to keep Linux ACPI + * happy + */ + Method (_PRS, 0, NotSerialized) + { + Name (PRSP, ResourceTemplate () { + IRQ (Level, ActiveLow, Shared) {3,4,6,7,10,11,12} + }) + Name (PRSA, ResourceTemplate () { + Interrupt (ResourceConsumer, Level, ActiveLow, Shared) {16,17,18,19,20,21,22,23} + }) + + If (LNot (PICF)) { + Return (PRSP) + } Else { + Return (PRSA) + } + + } + + /* Set Resources - dummy function to keep Linux ACPI happy + * Linux is more than happy not to tinker with irq + * assignments as long as the CRS and STA functions + * return good values + */ + Method (_SRS, 1, NotSerialized ) {} + /* Disable - dummy function to keep Linux ACPI happy */ + Method (_DIS, 0, NotSerialized ) {} + + } // End of LNKD + + /* PCI Root Bridge */ + Device (PCI0) + { + Name (_HID, EisaId ("PNP0A08")) + Name (_CID, EisaId ("PNP0A03")) + Name (_ADR, 0x00) + Name (_UID, 0x00) + Name (_BBN, 0x00) + + // Mainboard specific IRQ routing + Include ("irq.dsl") + + /* PCI Routing Table */ + Method (_PRT, 0, NotSerialized) + { + If (LNot (PICF)) + { + Return (PICM) + } + Else + { + Return (APIC) + } + } + + Device (P2PB) /* PCI to PCI bridge */ + { + Name (_ADR, 0x00130001) + + Include ("irq-p2p-bridge.dsl") + Method (_PRT, 0, NotSerialized) + { + If (LNot (PICF)) + { + Return (PICM) + } + Else + { + Return (APIC) + } + } + /* Status - always return ready */ + Method (_STA, 0, NotSerialized) + { + Return (0x0F) + } + } + } // End of PCI0 + } // End of _SB +} // End of Definition Block + diff --git a/src/mainboard/via/vt8454c/fadt.c b/src/mainboard/via/vt8454c/fadt.c new file mode 100644 index 0000000000..3954974075 --- /dev/null +++ b/src/mainboard/via/vt8454c/fadt.c @@ -0,0 +1,156 @@ +/* + * 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 <arch/acpi.h> + +void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt) +{ + acpi_header_t *header = &(fadt->header); + + memset((void *) fadt, 0, sizeof(acpi_fadt_t)); + memcpy(header->signature, "FACP", 4); + header->length = 244; + header->revision = 1; + memcpy(header->oem_id, "CX700 ", 6); + memcpy(header->oem_table_id, "COREBOOT", 8); + memcpy(header->asl_compiler_id, "CORE", 4); + header->asl_compiler_revision = 0; + + fadt->firmware_ctrl = (unsigned long) facs; + fadt->dsdt = (unsigned long) dsdt; + fadt->preferred_pm_profile = 0; + fadt->sci_int = 0x9; + fadt->smi_cmd = 0x0; + fadt->acpi_enable = 0xA1; + fadt->acpi_disable = 0xA0; + fadt->s4bios_req = 0x0; + fadt->pstate_cnt = 0x0; + + fadt->pm1a_evt_blk = 0x400; + fadt->pm1b_evt_blk = 0x0; + fadt->pm1a_cnt_blk = 0x404; + fadt->pm1b_cnt_blk = 0x0; + fadt->pm2_cnt_blk = 0x22; + fadt->pm_tmr_blk = 0x408; + fadt->gpe0_blk = 0x420; + fadt->gpe1_blk = 0x450; + + fadt->pm1_evt_len = 4; + fadt->pm1_cnt_len = 2; + fadt->pm2_cnt_len = 1; + fadt->pm_tmr_len = 4; + fadt->gpe0_blk_len = 4; + fadt->gpe1_blk_len = 4; + fadt->gpe1_base = 0x10; + fadt->cst_cnt = 0; + fadt->p_lvl2_lat = 101; + fadt->p_lvl3_lat = 1001; + fadt->flush_size = 0; + fadt->flush_stride = 0; + fadt->duty_offset = 0; + fadt->duty_width = 1; + fadt->day_alrm = 0x7d; + fadt->mon_alrm = 0x7e; + fadt->century = 0x32; + fadt->iapc_boot_arch = 0x0; + fadt->flags = 0x44a5; + + 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 = 4; + fadt->x_pm1a_evt_blk.bit_offset = 0; + fadt->x_pm1a_evt_blk.resv = 0; + fadt->x_pm1a_evt_blk.addrl = 0x400; + fadt->x_pm1a_evt_blk.addrh = 0x0; + + + fadt->x_pm1b_evt_blk.space_id = 1; + fadt->x_pm1b_evt_blk.bit_width = 4; + 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 = 2; + fadt->x_pm1a_cnt_blk.bit_offset = 0; + fadt->x_pm1a_cnt_blk.resv = 0; + fadt->x_pm1a_cnt_blk.addrl = 0x404; + fadt->x_pm1a_cnt_blk.addrh = 0x0; + + + fadt->x_pm1b_cnt_blk.space_id = 1; + fadt->x_pm1b_cnt_blk.bit_width = 2; + 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 = 0; + fadt->x_pm2_cnt_blk.bit_offset = 0; + fadt->x_pm2_cnt_blk.resv = 0; + fadt->x_pm2_cnt_blk.addrl = 0x0; + fadt->x_pm2_cnt_blk.addrh = 0x0; + + + fadt->x_pm_tmr_blk.space_id = 1; + fadt->x_pm_tmr_blk.bit_width = 4; + fadt->x_pm_tmr_blk.bit_offset = 0; + fadt->x_pm_tmr_blk.resv = 0; + fadt->x_pm_tmr_blk.addrl = 0x408; + fadt->x_pm_tmr_blk.addrh = 0x0; + + + fadt->x_gpe0_blk.space_id = 1; + fadt->x_gpe0_blk.bit_width = 0; + fadt->x_gpe0_blk.bit_offset = 0; + fadt->x_gpe0_blk.resv = 0; + fadt->x_gpe0_blk.addrl = 0x420; + fadt->x_gpe0_blk.addrh = 0x0; + + + fadt->x_gpe1_blk.space_id = 1; + 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, sizeof(acpi_fadt_t)); + +} diff --git a/src/mainboard/via/vt8454c/irq-p2p-bridge.dsl b/src/mainboard/via/vt8454c/irq-p2p-bridge.dsl new file mode 100644 index 0000000000..4a294bcbaa --- /dev/null +++ b/src/mainboard/via/vt8454c/irq-p2p-bridge.dsl @@ -0,0 +1,88 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +Name (PICM, Package () { + // _ADR PIN SRC IDX + + Package () { 0x0003FFFF, 0x00, LNKA, 0x00 }, + Package () { 0x0003FFFF, 0x01, LNKB, 0x00 }, + Package () { 0x0003FFFF, 0x02, LNKC, 0x00 }, + Package () { 0x0003FFFF, 0x03, LNKD, 0x00 }, + + Package () { 0x0004FFFF, 0x00, LNKB, 0x00 }, + Package () { 0x0004FFFF, 0x01, LNKC, 0x00 }, + Package () { 0x0004FFFF, 0x02, LNKD, 0x00 }, + Package () { 0x0004FFFF, 0x03, LNKA, 0x00 }, + + Package () { 0x0005FFFF, 0x00, LNKC, 0x00 }, + Package () { 0x0005FFFF, 0x01, LNKD, 0x00 }, + Package () { 0x0005FFFF, 0x02, LNKA, 0x00 }, + Package () { 0x0005FFFF, 0x03, LNKB, 0x00 }, + + Package () { 0x0006FFFF, 0x00, LNKD, 0x00 }, + Package () { 0x0006FFFF, 0x01, LNKA, 0x00 }, + Package () { 0x0006FFFF, 0x02, LNKB, 0x00 }, + Package () { 0x0006FFFF, 0x03, LNKC, 0x00 }, + + Package () { 0x0007FFFF, 0x00, LNKA, 0x00 }, + Package () { 0x0007FFFF, 0x01, LNKB, 0x00 }, + Package () { 0x0007FFFF, 0x02, LNKC, 0x00 }, + Package () { 0x0007FFFF, 0x03, LNKD, 0x00 }, + + Package () { 0x0008FFFF, 0x00, LNKB, 0x00 }, + Package () { 0x0008FFFF, 0x01, LNKC, 0x00 }, + Package () { 0x0008FFFF, 0x02, LNKD, 0x00 }, + Package () { 0x0008FFFF, 0x03, LNKA, 0x00 }, +}) + +Name (APIC, Package () { + Package () { 0x0003FFFF, 0x00, 0x00, 0x10 }, + Package () { 0x0003FFFF, 0x01, 0x00, 0x11 }, + Package () { 0x0003FFFF, 0x02, 0x00, 0x12 }, + Package () { 0x0003FFFF, 0x03, 0x00, 0x13 }, + + Package () { 0x0004FFFF, 0x00, 0x00, 0x11 }, + Package () { 0x0004FFFF, 0x01, 0x00, 0x12 }, + Package () { 0x0004FFFF, 0x02, 0x00, 0x13 }, + Package () { 0x0004FFFF, 0x03, 0x00, 0x10 }, + + Package () { 0x0005FFFF, 0x00, 0x00, 0x12 }, + Package () { 0x0005FFFF, 0x01, 0x00, 0x13 }, + Package () { 0x0005FFFF, 0x02, 0x00, 0x10 }, + Package () { 0x0005FFFF, 0x03, 0x00, 0x11 }, + + Package () { 0x0006FFFF, 0x00, 0x00, 0x13 }, + Package () { 0x0006FFFF, 0x01, 0x00, 0x10 }, + Package () { 0x0006FFFF, 0x02, 0x00, 0x11 }, + Package () { 0x0006FFFF, 0x03, 0x00, 0x12 }, + + Package () { 0x0007FFFF, 0x00, 0x00, 0x10 }, + Package () { 0x0007FFFF, 0x01, 0x00, 0x11 }, + Package () { 0x0007FFFF, 0x02, 0x00, 0x12 }, + Package () { 0x0007FFFF, 0x03, 0x00, 0x13 }, + + Package () { 0x0008FFFF, 0x00, 0x00, 0x11 }, + Package () { 0x0008FFFF, 0x01, 0x00, 0x12 }, + Package () { 0x0008FFFF, 0x02, 0x00, 0x13 }, + Package () { 0x0008FFFF, 0x03, 0x00, 0x10 }, +}) + + diff --git a/src/mainboard/via/vt8454c/irq.dsl b/src/mainboard/via/vt8454c/irq.dsl new file mode 100644 index 0000000000..63e64e61c0 --- /dev/null +++ b/src/mainboard/via/vt8454c/irq.dsl @@ -0,0 +1,143 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +Name (PICM, Package () { + // _ADR PIN SRC IDX + + Package () { 0x0001FFFF, 0x00, LNKA, 0x00 }, + Package () { 0x0001FFFF, 0x01, LNKB, 0x00 }, + Package () { 0x0001FFFF, 0x02, LNKC, 0x00 }, + Package () { 0x0001FFFF, 0x03, LNKD, 0x00 }, + + Package () { 0x0008FFFF, 0x00, LNKB, 0x00 }, + Package () { 0x0008FFFF, 0x01, LNKC, 0x00 }, + Package () { 0x0008FFFF, 0x02, LNKD, 0x00 }, + Package () { 0x0008FFFF, 0x03, LNKA, 0x00 }, + + Package () { 0x0009FFFF, 0x00, LNKC, 0x00 }, + Package () { 0x0009FFFF, 0x01, LNKD, 0x00 }, + Package () { 0x0009FFFF, 0x02, LNKA, 0x00 }, + Package () { 0x0009FFFF, 0x03, LNKB, 0x00 }, + + Package () { 0x000AFFFF, 0x00, LNKD, 0x00 }, + Package () { 0x000AFFFF, 0x01, LNKA, 0x00 }, + Package () { 0x000AFFFF, 0x02, LNKB, 0x00 }, + Package () { 0x000AFFFF, 0x03, LNKC, 0x00 }, + + Package () { 0x000BFFFF, 0x00, LNKD, 0x00 }, + Package () { 0x000BFFFF, 0x01, LNKA, 0x00 }, + Package () { 0x000BFFFF, 0x02, LNKB, 0x00 }, + Package () { 0x000BFFFF, 0x03, LNKC, 0x00 }, + + Package () { 0x000CFFFF, 0x00, LNKA, 0x00 }, + Package () { 0x000CFFFF, 0x01, LNKB, 0x00 }, + Package () { 0x000CFFFF, 0x02, LNKC, 0x00 }, + Package () { 0x000CFFFF, 0x03, LNKD, 0x00 }, + + Package () { 0x000DFFFF, 0x00, LNKA, 0x00 }, + Package () { 0x000DFFFF, 0x01, LNKB, 0x00 }, + Package () { 0x000DFFFF, 0x02, LNKC, 0x00 }, + Package () { 0x000DFFFF, 0x03, LNKD, 0x00 }, + + Package () { 0x000FFFFF, 0x00, LNKA, 0x00 }, + Package () { 0x000FFFFF, 0x01, LNKB, 0x00 }, + Package () { 0x000FFFFF, 0x02, LNKC, 0x00 }, + Package () { 0x000FFFFF, 0x03, LNKD, 0x00 }, + + /* USB controller */ + Package () { 0x0010FFFF, 0x00, LNKA, 0x00 }, + Package () { 0x0010FFFF, 0x01, LNKB, 0x00 }, + Package () { 0x0010FFFF, 0x02, LNKC, 0x00 }, + Package () { 0x0010FFFF, 0x03, LNKD, 0x00 }, + + Package () { 0x0011FFFF, 0x00, LNKA, 0x00 }, + Package () { 0x0011FFFF, 0x01, LNKB, 0x00 }, + Package () { 0x0011FFFF, 0x02, LNKC, 0x00 }, + Package () { 0x0011FFFF, 0x03, LNKD, 0x00 }, + + Package () { 0x0012FFFF, 0x00, LNKA, 0x00 }, + Package () { 0x0012FFFF, 0x01, LNKB, 0x00 }, + Package () { 0x0012FFFF, 0x02, LNKC, 0x00 }, + Package () { 0x0012FFFF, 0x03, LNKD, 0x00 } +}) + +Name (APIC, Package () { + Package () { 0x0001FFFF, 0x00, 0x00, 0x10 }, + Package () { 0x0001FFFF, 0x01, 0x00, 0x11 }, + Package () { 0x0001FFFF, 0x02, 0x00, 0x12 }, + Package () { 0x0001FFFF, 0x03, 0x00, 0x13 }, + + Package () { 0x0008FFFF, 0x00, 0x00, 0x11 }, + Package () { 0x0008FFFF, 0x01, 0x00, 0x12 }, + Package () { 0x0008FFFF, 0x02, 0x00, 0x13 }, + Package () { 0x0008FFFF, 0x03, 0x00, 0x10 }, + + Package () { 0x0009FFFF, 0x00, 0x00, 0x12 }, + Package () { 0x0009FFFF, 0x01, 0x00, 0x13 }, + Package () { 0x0009FFFF, 0x02, 0x00, 0x10 }, + Package () { 0x0009FFFF, 0x03, 0x00, 0x11 }, + + Package () { 0x000AFFFF, 0x00, 0x00, 0x13 }, + Package () { 0x000AFFFF, 0x01, 0x00, 0x10 }, + Package () { 0x000AFFFF, 0x02, 0x00, 0x11 }, + Package () { 0x000AFFFF, 0x03, 0x00, 0x12 }, + + Package () { 0x000BFFFF, 0x00, 0x00, 0x13 }, + Package () { 0x000BFFFF, 0x01, 0x00, 0x10 }, + Package () { 0x000BFFFF, 0x02, 0x00, 0x11 }, + Package () { 0x000BFFFF, 0x03, 0x00, 0x12 }, + + Package () { 0x000CFFFF, 0x00, 0x00, 0x10 }, + Package () { 0x000CFFFF, 0x01, 0x00, 0x11 }, + Package () { 0x000CFFFF, 0x02, 0x00, 0x12 }, + Package () { 0x000CFFFF, 0x03, 0x00, 0x13 }, + + Package () { 0x000DFFFF, 0x00, 0x00, 0x10 }, + Package () { 0x000DFFFF, 0x01, 0x00, 0x11 }, + Package () { 0x000DFFFF, 0x02, 0x00, 0x12 }, + Package () { 0x000DFFFF, 0x03, 0x00, 0x13 }, + + Package () { 0x000FFFFF, 0x00, LNKA, 0x00 }, + Package () { 0x000FFFFF, 0x01, LNKA, 0x00 }, + Package () { 0x000FFFFF, 0x02, LNKA, 0x00 }, + Package () { 0x000FFFFF, 0x03, LNKA, 0x00 }, + + /* USB controller. Hardwired in internal + APIC mode, see PM pg. 137, + "miscellaneous controls", footnote to + "IDE interrupt select" */ + Package () { 0x0010FFFF, 0x00, 0x00, 0x14 }, + Package () { 0x0010FFFF, 0x01, 0x00, 0x16 }, + Package () { 0x0010FFFF, 0x02, 0x00, 0x15 }, + Package () { 0x0010FFFF, 0x03, 0x00, 0x17 }, + + Package () { 0x0011FFFF, 0x00, LNKA, 0x00 }, + Package () { 0x0011FFFF, 0x01, LNKB, 0x00 }, + Package () { 0x0011FFFF, 0x02, LNKC, 0x00 }, + Package () { 0x0011FFFF, 0x03, LNKD, 0x00 }, + + Package () { 0x0012FFFF, 0x00, LNKD, 0x00 }, + Package () { 0x0012FFFF, 0x01, LNKD, 0x00 }, + Package () { 0x0012FFFF, 0x02, LNKD, 0x00 }, + Package () { 0x0012FFFF, 0x03, LNKD, 0x00 }, +}) + + diff --git a/src/mainboard/via/vt8454c/irq_tables.c b/src/mainboard/via/vt8454c/irq_tables.c new file mode 100644 index 0000000000..40d1ebb691 --- /dev/null +++ b/src/mainboard/via/vt8454c/irq_tables.c @@ -0,0 +1,61 @@ +/* + * 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 <arch/pirq_routing.h> + +const struct irq_routing_table intel_irq_routing_table = { + PIRQ_SIGNATURE, /* u32 signature */ + PIRQ_VERSION, /* u16 version */ + 32 + 16 * IRQ_SLOT_COUNT, /* There can be total 15 devices on the bus */ + 0x00, /* Where the interrupt router lies (bus) */ + (0x11 << 3) | 0x0, /* Where the interrupt router lies (dev) */ + 0xc20, /* IRQs devoted exclusively to PCI usage */ + 0x1106, /* Vendor */ + 0x596, /* Device */ + 0, /* Crap (miniport) */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* u8 rfu[11] */ + 0x84, /* u8 checksum. This 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, (0x08 << 3) | 0x0, {{0x01, 0xdeb8}, {0x02, 0xdeb8}, {0x03, 0xdeb8}, {0x05, 0x0deb8}}, 0x1, 0x0}, + {0x00, (0x09 << 3) | 0x0, {{0x02, 0xdeb8}, {0x03, 0xdeb8}, {0x05, 0xdeb8}, {0x01, 0x0deb8}}, 0x2, 0x0}, + {0x00, (0x0a << 3) | 0x0, {{0x03, 0xdeb8}, {0x05, 0xdeb8}, {0x01, 0xdeb8}, {0x02, 0x0deb8}}, 0x3, 0x0}, + {0x02, (0x03 << 3) | 0x0, {{0x01, 0xdeb8}, {0x02, 0xdeb8}, {0x03, 0xdeb8}, {0x05, 0x0deb8}}, 0x4, 0x0}, + {0x02, (0x04 << 3) | 0x0, {{0x02, 0xdeb8}, {0x03, 0xdeb8}, {0x05, 0xdeb8}, {0x01, 0x0deb8}}, 0x5, 0x0}, + {0x02, (0x05 << 3) | 0x0, {{0x03, 0xdeb8}, {0x05, 0xdeb8}, {0x01, 0xdeb8}, {0x02, 0x0deb8}}, 0x6, 0x0}, + {0x02, (0x06 << 3) | 0x0, {{0x05, 0xdeb8}, {0x01, 0xdeb8}, {0x02, 0xdeb8}, {0x03, 0x0deb8}}, 0x7, 0x0}, + {0x02, (0x07 << 3) | 0x0, {{0x01, 0xdeb8}, {0x02, 0xdeb8}, {0x03, 0xdeb8}, {0x05, 0x0deb8}}, 0x8, 0x0}, + {0x02, (0x08 << 3) | 0x0, {{0x03, 0xdeb8}, {0x05, 0xdeb8}, {0x01, 0xdeb8}, {0x02, 0x0deb8}}, 0x9, 0x0}, + {0x00, (0x01 << 3) | 0x0, {{0x02, 0xdeb8}, {0x02, 0xdeb8}, {0x02, 0xdeb8}, {0x02, 0x0deb8}}, 0x0, 0x0}, + {0x80, (0x01 << 3) | 0x0, {{0x02, 0xdeb8}, {0x02, 0xdeb8}, {0x02, 0xdeb8}, {0x02, 0x0deb8}}, 0x0, 0x0}, + {0x00, (0x11 << 3) | 0x0, {{0x00, 0xdeb8}, {0x00, 0xdeb8}, {0x03, 0xdeb8}, {0x05, 0x0deb8}}, 0x0, 0x0}, + {0x00, (0x0f << 3) | 0x0, {{0x01, 0xdeb8}, {0x02, 0xdeb8}, {0x03, 0xdeb8}, {0x05, 0x0deb8}}, 0x0, 0x0}, + {0x00, (0x01 << 3) | 0x0, {{0x01, 0xdeb8}, {0x02, 0xdeb8}, {0x03, 0xdeb8}, {0x05, 0x0deb8}}, 0x0, 0x0}, + {0x00, (0x10 << 3) | 0x0, {{0x01, 0xdeb8}, {0x02, 0xdeb8}, {0x03, 0xdeb8}, {0x05, 0x0deb8}}, 0x0, 0x0} + } +}; + +inline unsigned long write_pirq_routing_table(unsigned long addr) +{ + return copy_pirq_routing_table(addr); +} diff --git a/src/mainboard/via/vt8454c/mainboard.c b/src/mainboard/via/vt8454c/mainboard.c new file mode 100644 index 0000000000..e931ccdafb --- /dev/null +++ b/src/mainboard/via/vt8454c/mainboard.c @@ -0,0 +1,28 @@ +/* + * 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 <device/device.h> +#include "chip.h" + +struct chip_operations mainboard_ops = { + CHIP_NAME("VIA VT8454c Mainboard") +}; + diff --git a/src/mainboard/via/vt8454c/mptable.c b/src/mainboard/via/vt8454c/mptable.c new file mode 100644 index 0000000000..e060d67ddd --- /dev/null +++ b/src/mainboard/via/vt8454c/mptable.c @@ -0,0 +1,104 @@ +/* + * 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 <device/device.h> +#include <device/pci.h> +#include <arch/smp/mpspec.h> +#include <cpu/x86/lapic.h> +#include <console/console.h> +#include <string.h> +#include <stdint.h> + +void *smp_write_config_table(void *v) +{ + static const char sig[4] = MPC_SIGNATURE; + static const char oem[8] = "COREBOOT"; + static const char productid[12] = "VIA VT8454C "; + struct mp_config_table *mc; + + mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN); + memset(mc, 0, sizeof(*mc)); + + memcpy(mc->mpc_signature, sig, sizeof(sig)); + mc->mpc_length = sizeof(*mc); /* initially just the header */ + mc->mpc_spec = 0x04; + mc->mpc_checksum = 0; /* not yet computed */ + memcpy(mc->mpc_oem, oem, sizeof(oem)); + memcpy(mc->mpc_productid, productid, sizeof(productid)); + mc->mpc_oemptr = 0; + mc->mpc_oemsize = 0; + mc->mpc_entry_count = 0; /* No entries yet... */ + mc->mpc_lapic = LAPIC_ADDR; + mc->mpe_length = 0; + mc->mpe_checksum = 0; + mc->reserved = 0; + + smp_write_processors(mc); + + /*Bus: Bus ID Type */ + smp_write_bus(mc, 0, "PCI "); + smp_write_bus(mc, 1, "PCI "); + smp_write_bus(mc, 2, "PCI "); + smp_write_bus(mc, 128, "PCI "); + smp_write_bus(mc, 129, "ISA "); + + /* I/O APICs: APIC ID Version State Address */ + smp_write_ioapic(mc, 2, 17, 0xfec00000); + + /* I/O Ints: Type Polarity Trigger Bus ID IRQ APIC ID PIN# */ + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW, 0x0, 0x40, 0x2, 0x14); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW, 0x0, 0x41, 0x2, 0x16); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW, 0x0, 0x42, 0x2, 0x15); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW, 0x0, 0x43, 0x2, 0x17); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW, 0x80, 0x4, 0x2, 0x11); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW, 0x1, 0x0, 0x2, 0x11); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW, 0x2, 0x10, 0x2, 0x11); + smp_write_intsrc(mc, mp_ExtINT, MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT, 0x81, 0x0, 0x2, 0x0); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT, 0x81, 0x1, 0x2, 0x1); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT, 0x81, 0x0, 0x2, 0x2); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT, 0x81, 0x3, 0x2, 0x3); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT, 0x81, 0x4, 0x2, 0x4); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT, 0x81, 0x6, 0x2, 0x6); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT, 0x81, 0x7, 0x2, 0x7); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, 0x81, 0x8, 0x2, 0x8); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT, 0x81, 0x9, 0x2, 0x9); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT, 0x81, 0xc, 0x2, 0xc); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT, 0x81, 0xd, 0x2, 0xd); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT, 0x81, 0xe, 0x2, 0xe); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT, 0x81, 0xf, 0x2, 0xf); + + /*Local Ints: Type Polarity Trigger Bus ID IRQ APIC ID PIN# */ + smp_write_intsrc(mc, mp_ExtINT, MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT, 0x0, 0x0, MP_APIC_ALL, 0x0); + smp_write_intsrc(mc, mp_NMI, MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT, 0x0, 0x0, MP_APIC_ALL, 0x1); + + /* Compute the checksums */ + mc->mpe_checksum = smp_compute_checksum(smp_next_mpc_entry(mc), mc->mpe_length); + mc->mpc_checksum = smp_compute_checksum(mc, mc->mpc_length); + printk_debug("Wrote the mp table end at: %p - %p\n", mc, smp_next_mpe_entry(mc)); + return smp_next_mpe_entry(mc); +} + +unsigned long write_smp_table(unsigned long addr) +{ + void *v; + v = smp_write_floating_table(addr); + return (unsigned long)smp_write_config_table(v); +} diff --git a/src/mainboard/via/vt8454c/reset.c b/src/mainboard/via/vt8454c/reset.c new file mode 100644 index 0000000000..e1d879fa5a --- /dev/null +++ b/src/mainboard/via/vt8454c/reset.c @@ -0,0 +1,28 @@ +/* + * 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 "arch/romcc_io.h" + +void hard_reset(void) +{ + set_bios_reset(); + outb(0x06, 0x0cf9); +} diff --git a/src/northbridge/via/cx700/Config.lb b/src/northbridge/via/cx700/Config.lb new file mode 100644 index 0000000000..f4e558033e --- /dev/null +++ b/src/northbridge/via/cx700/Config.lb @@ -0,0 +1,28 @@ +## 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 + +config chip.h + +object cx700_reset.o +object northbridge.o +object vgabios.o + +driver cx700_agp.o +driver cx700_lpc.o +driver cx700_sata.o +driver cx700_vga.o + diff --git a/src/northbridge/via/cx700/chip.h b/src/northbridge/via/cx700/chip.h new file mode 100644 index 0000000000..7b7aca8e89 --- /dev/null +++ b/src/northbridge/via/cx700/chip.h @@ -0,0 +1,23 @@ +/* + * 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 + */ + +struct northbridge_via_cx700_config { +}; + +extern struct chip_operations northbridge_via_cx700_ops; diff --git a/src/northbridge/via/cx700/cx700_agp.c b/src/northbridge/via/cx700/cx700_agp.c new file mode 100644 index 0000000000..0166ee135a --- /dev/null +++ b/src/northbridge/via/cx700/cx700_agp.c @@ -0,0 +1,91 @@ +/* + * 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 <console/console.h> +#include <arch/io.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> + +/* This is the AGP 3.0 "bridge" @ Bus 0 Device 1 Func 0 */ + +static void agp_bridge_init(device_t dev) +{ + + device_t north_dev; + u8 reg8; + north_dev = dev_find_device(PCI_VENDOR_ID_VIA, 0x3324, 0); + + pci_write_config8(north_dev, 0xa0, 0x1); // Enable CPU Direct Access Frame Buffer + + pci_write_config8(north_dev, 0xa2, 0x4a); + + reg8 = pci_read_config8(north_dev, 0xc0); + reg8 |= 0x1; + pci_write_config8(north_dev, 0xc0, reg8); + + /* + * Since Internal Graphic already set to AGP3.0 compatible in its Capability Pointer + * We must set RAGP8X=1 B0D0F0 Rx84[3]=1 from backdoor register B0D0F0 RxB5[1:0]=11b + */ + north_dev = dev_find_device(PCI_VENDOR_ID_VIA, 0x0324, 0); + reg8 = pci_read_config8(north_dev, 0xb5); + reg8 |= 0x3; + pci_write_config8(north_dev, 0xb5, reg8); + pci_write_config8(north_dev, 0x94, 0x20); + pci_write_config8(north_dev, 0x13, 0xd0); + + pci_write_config16(dev, 0x4, 0x0007); + + pci_write_config8(dev, 0x19, 0x01); + pci_write_config8(dev, 0x1a, 0x01); + pci_write_config8(dev, 0x1c, 0xe0); + pci_write_config8(dev, 0x1d, 0xe0); + pci_write_config16(dev, 0x1e, 0xa220); + + pci_write_config16(dev, 0x20, 0xdd00); + pci_write_config16(dev, 0x22, 0xdef0); + pci_write_config16(dev, 0x24, 0xa000); + pci_write_config16(dev, 0x26, 0xbff0); + + pci_write_config8(dev, 0x3e, 0x0c); + pci_write_config8(dev, 0x40, 0x8b); + pci_write_config8(dev, 0x41, 0x43); + pci_write_config8(dev, 0x42, 0x62); + pci_write_config8(dev, 0x43, 0x44); + pci_write_config8(dev, 0x44, 0x34); +} + +static void cx700_noop(device_t dev) +{ +} + +static struct device_operations agp_bridge_operations = { + .read_resources = cx700_noop, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .init = agp_bridge_init, + .scan_bus = pci_scan_bridge, +}; + +static const struct pci_driver agp_bridge_driver __pci_driver = { + .ops = &agp_bridge_operations, + .vendor = PCI_VENDOR_ID_VIA, + .device = 0xb198, +}; diff --git a/src/northbridge/via/cx700/cx700_early_serial.c b/src/northbridge/via/cx700/cx700_early_serial.c new file mode 100644 index 0000000000..a0d7301e20 --- /dev/null +++ b/src/northbridge/via/cx700/cx700_early_serial.c @@ -0,0 +1,102 @@ +/* + * 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 + */ + +/* + * Enable the serial devices on the VIA CX700 + */ + +#include <arch/romcc_io.h> + +static void cx700_writepnpaddr(u8 val) +{ + outb(val, 0x2e); + outb(val, 0xeb); +} + +static void cx700_writepnpdata(u8 val) +{ + outb(val, 0x2f); + outb(val, 0xeb); +} + +static void cx700_writesiobyte(u16 reg, u8 val) +{ + outb(val, reg); +} + +static void cx700_writesioword(u16 reg, u16 val) +{ + outw(val, reg); +} + +static void enable_cx700_serial(void) +{ + outb(6, 0x80); + + // WTH? + outb(0x03, 0x22); + + // Set UART1 I/O Base Address + pci_write_config8(PCI_DEV(0, 17, 0), 0xb4, 0x7e); + + // UART1 Enable + pci_write_config8(PCI_DEV(0, 17, 0), 0xb0, 0x10); + + // turn on pnp + cx700_writepnpaddr(0x87); + cx700_writepnpaddr(0x87); + // now go ahead and set up com1. + // set address + cx700_writepnpaddr(0x7); + cx700_writepnpdata(0x2); + // enable serial out + cx700_writepnpaddr(0x30); + cx700_writepnpdata(0x1); + // serial port 1 base address (FEh) + cx700_writepnpaddr(0x60); + cx700_writepnpdata(0xfe); + // serial port 1 IRQ (04h) + cx700_writepnpaddr(0x70); + cx700_writepnpdata(0x4); + // serial port 1 control + cx700_writepnpaddr(0xf0); + cx700_writepnpdata(0x2); + // turn of pnp + cx700_writepnpaddr(0xaa); + + // XXX This part should be fully taken care of by + // src/pc80/serial.c:uart_init + + // set up reg to set baud rate. + cx700_writesiobyte(0x3fb, 0x80); + // Set 115 kb + cx700_writesioword(0x3f8, 1); + // Set 9.6 kb + // cx700_writesioword(0x3f8, 12) + // now set no parity, one stop, 8 bits + cx700_writesiobyte(0x3fb, 3); + // now turn on RTS, DRT + cx700_writesiobyte(0x3fc, 3); + // Enable interrupts + cx700_writesiobyte(0x3f9, 0xf); + // should be done. Dump a char for fun. + cx700_writesiobyte(0x3f8, 48); + + outb(7, 0x80); +} diff --git a/src/northbridge/via/cx700/cx700_early_smbus.c b/src/northbridge/via/cx700/cx700_early_smbus.c new file mode 100644 index 0000000000..218ae0a7a1 --- /dev/null +++ b/src/northbridge/via/cx700/cx700_early_smbus.c @@ -0,0 +1,268 @@ +/* + * 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 + */ + +// other bioses use this, too: +#define SMBUS_IO_BASE 0x0500 + +#define SMBHSTSTAT SMBUS_IO_BASE + 0x0 +#define SMBSLVSTAT SMBUS_IO_BASE + 0x1 +#define SMBHSTCTL SMBUS_IO_BASE + 0x2 +#define SMBHSTCMD SMBUS_IO_BASE + 0x3 +#define SMBXMITADD SMBUS_IO_BASE + 0x4 +#define SMBHSTDAT0 SMBUS_IO_BASE + 0x5 +#define SMBHSTDAT1 SMBUS_IO_BASE + 0x6 + +#define SMBBLKDAT SMBUS_IO_BASE + 0x7 +#define SMBSLVCTL SMBUS_IO_BASE + 0x8 +#define SMBTRNSADD SMBUS_IO_BASE + 0x9 +#define SMBSLVDATA SMBUS_IO_BASE + 0xa +#define SMLINK_PIN_CTL SMBUS_IO_BASE + 0xe +#define SMBUS_PIN_CTL SMBUS_IO_BASE + 0xf + +/* Define register settings */ +#define HOST_RESET 0xff +#define DIMM_BASE 0xa0 // 1010000 is base for DIMM in SMBus +#define READ_CMD 0x01 // 1 in the 0 bit of SMBHSTADD states to READ + +#define SMBUS_TIMEOUT (100*1000*10) + +#define I2C_TRANS_CMD 0x40 +#define CLOCK_SLAVE_ADDRESS 0x69 + +#define SMBUS_DELAY() outb(0x80, 0x80) + +/* Debugging macros. */ + +// #define DEBUG_SMBUS 1 + +#ifdef DEBUG_SMBUS +#define PRINT_DEBUG(x) print_debug(x) +#define PRINT_DEBUG_HEX16(x) print_debug_hex16(x) +#else +#define PRINT_DEBUG(x) +#define PRINT_DEBUG_HEX16(x) +#endif + +/* Internal functions */ +static void smbus_print_error(unsigned char host_status_register, int loops) +{ + /* Check if there actually was an error */ + if (host_status_register == 0x00 || host_status_register == 0x40 || + host_status_register == 0x42) + return; + print_err("SMBus Error: "); + print_err_hex8(host_status_register); + + print_err("\r\n"); + if (loops >= SMBUS_TIMEOUT) { + print_err("SMBus Timout\r\n"); + } + if (host_status_register & (1 << 4)) { + print_err("Interrup/SMI# was Failed Bus Transaction\r\n"); + } + if (host_status_register & (1 << 3)) { + print_err("Bus Error\r\n"); + } + if (host_status_register & (1 << 2)) { + print_err("Device Error\r\n"); + } + if (host_status_register & (1 << 1)) { + /* This isn't a real error... */ + print_debug("Interrupt/SMI# was Successful Completion\r\n"); + } + if (host_status_register & (1 << 0)) { + print_err("Host Busy\r\n"); + } +} + +static void smbus_wait_until_ready(void) +{ + int loops; + + loops = 0; + + /* Yes, this is a mess, but it's the easiest way to do it */ + while (((inb(SMBHSTSTAT) & 1) == 1) && (loops <= SMBUS_TIMEOUT)) { + SMBUS_DELAY(); + ++loops; + } +#ifdef DEBUG_SMBUS + /* Some systems seem to have a flakey SMBus. No need to spew a lot of + * errors on those, once we know that SMBus access is principally + * working. + */ + smbus_print_error(inb(SMBHSTSTAT), loops); +#endif +} + +static void smbus_reset(void) +{ + outb(HOST_RESET, SMBHSTSTAT); +} + +/* Public functions */ +static void set_ics_data(unsigned char dev, int data, char len) +{ + //int i; + smbus_reset(); + /* clear host data port */ + outb(0x00, SMBHSTDAT0); + SMBUS_DELAY(); + smbus_wait_until_ready(); + + /* read to reset block transfer counter */ + inb(SMBHSTCTL); + + /* fill blocktransfer array */ + if (dev = 0xd2) { + //char d2_data[] = {0x0d,0x00,0x3f,0xcd,0x7f,0xbf,0x1a,0x2a,0x01,0x0f,0x0b,0x00,0x8d,0x9b}; + outb(0x0d, SMBBLKDAT); + outb(0x00, SMBBLKDAT); + outb(0x3f, SMBBLKDAT); + outb(0xcd, SMBBLKDAT); + outb(0x7f, SMBBLKDAT); + outb(0xbf, SMBBLKDAT); + outb(0x1a, SMBBLKDAT); + outb(0x2a, SMBBLKDAT); + outb(0x01, SMBBLKDAT); + outb(0x0f, SMBBLKDAT); + outb(0x0b, SMBBLKDAT); + outb(0x80, SMBBLKDAT); + outb(0x8d, SMBBLKDAT); + outb(0x9b, SMBBLKDAT); + } else { + //char d4_data[] = {0x08,0xff,0x3f,0x00,0x00,0xff,0xff,0xff,0xff}; + outb(0x08, SMBBLKDAT); + outb(0xff, SMBBLKDAT); + outb(0x3f, SMBBLKDAT); + outb(0x00, SMBBLKDAT); + outb(0x00, SMBBLKDAT); + outb(0xff, SMBBLKDAT); + outb(0xff, SMBBLKDAT); + outb(0xff, SMBBLKDAT); + outb(0xff, SMBBLKDAT); + } + + //for (i=0; i < len; i++) + // outb(data[i],SMBBLKDAT); + + outb(dev, SMBXMITADD); + outb(0, SMBHSTCMD); + outb(len, SMBHSTDAT0); + outb(0x74, SMBHSTCTL); + + SMBUS_DELAY(); + + smbus_wait_until_ready(); + + smbus_reset(); + +} + +static unsigned int get_spd_data(const struct mem_controller *ctrl, unsigned int dimm, + unsigned int offset) +{ + unsigned int val, addr; + + smbus_reset(); + + /* clear host data port */ + outb(0x00, SMBHSTDAT0); + SMBUS_DELAY(); + smbus_wait_until_ready(); + + /* Fetch the SMBus address of the SPD ROM from + * the ctrl struct in auto.c in case they are at + * non-standard positions. + * SMBus Address shifted by 1 + */ + addr = (ctrl->channel0[dimm]) << 1; + + outb(addr | 0x1, SMBXMITADD); + outb(offset, SMBHSTCMD); + outb(0x48, SMBHSTCTL); + + SMBUS_DELAY(); + + smbus_wait_until_ready(); + + val = inb(SMBHSTDAT0); + smbus_reset(); + return val; +} + +static void enable_smbus(void) +{ + device_t dev; + + /* The CX700 ISA Bridge (0x1106, 0x8324) is hardcoded to this location, + * no need to probe. + */ + dev = PCI_DEV(0, 17, 0); + + /* SMBus Clock Select: Divider fof 14.318MHz */ + pci_write_config8(dev, 0x94, 0x20); + + /* SMBus I/O Base, enable SMBus */ + pci_write_config16(dev, 0xd0, SMBUS_IO_BASE | 1); + + /* SMBus Clock from 128K Source, Enable SMBus Host Controller */ + pci_write_config8(dev, 0xd2, 0x05); + + /* Enable I/O decoding */ + pci_write_config16(dev, 0x04, 0x0003); + + /* Setup clock chips */ + set_ics_data(0xd2, 0, 14); + set_ics_data(0xd4, 0, 9); +} + +/* Debugging Function */ +#ifdef DEBUG_SMBUS +static void dump_spd_data(const struct mem_controller *ctrl) +{ + int dimm, offset, regs; + unsigned int val; + + for (dimm = 0; dimm < DIMM_SOCKETS; dimm++) { + print_debug("SPD Data for DIMM "); + print_debug_hex8(dimm); + print_debug("\r\n"); + + val = get_spd_data(ctrl, dimm, 0); + if (val == 0xff) { + regs = 256; + } else if (val == 0x80) { + regs = 128; + } else { + print_debug("No DIMM present\r\n"); + regs = 0; + } + for (offset = 0; offset < regs; offset++) { + print_debug(" Offset "); + print_debug_hex8(offset); + print_debug(" = 0x"); + print_debug_hex8(get_spd_data(ctrl, dimm, offset)); + print_debug("\r\n"); + } + } +} +#else +#define dump_spd_data(ctrl) +#endif diff --git a/src/northbridge/via/cx700/cx700_lpc.c b/src/northbridge/via/cx700/cx700_lpc.c new file mode 100644 index 0000000000..65275baa81 --- /dev/null +++ b/src/northbridge/via/cx700/cx700_lpc.c @@ -0,0 +1,397 @@ +/* + * 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 <arch/io.h> +#include <console/console.h> + +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ops.h> +#include <device/pci_ids.h> + +#include <pc80/mc146818rtc.h> +#include <pc80/i8259.h> +#include <pc80/keyboard.h> +#include <pc80/isa-dma.h> + +#include <cpu/x86/lapic.h> +#include <stdlib.h> + +#define ACPI_IO_BASE 0x400 +#define HPET_ADDR 0xfe800000UL +#define IOAPIC_ADDR 0xfec00000ULL + +#ifdef CONFIG_IOAPIC +struct ioapicreg { + unsigned int reg; + unsigned int value_low, value_high; +}; + +static struct ioapicreg ioapicregvalues[] = { +#define ALL (0xff << 24) +#define NONE (0) +#define DISABLED (1 << 16) +#define ENABLED (0 << 16) +#define TRIGGER_EDGE (0 << 15) +#define TRIGGER_LEVEL (1 << 15) +#define POLARITY_HIGH (0 << 13) +#define POLARITY_LOW (1 << 13) +#define PHYSICAL_DEST (0 << 11) +#define LOGICAL_DEST (1 << 11) +#define ExtINT (7 << 8) +#define NMI (4 << 8) +#define SMI (2 << 8) +#define INT (1 << 8) + /* IO-APIC virtual wire mode configuration */ + /* mask, trigger, polarity, destination, delivery, vector */ + { 0, ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT, NONE}, + { 1, DISABLED, NONE}, + { 2, DISABLED, NONE}, + { 3, DISABLED, NONE}, + { 4, DISABLED, NONE}, + { 5, DISABLED, NONE}, + { 6, DISABLED, NONE}, + { 7, DISABLED, NONE}, + { 8, DISABLED, NONE}, + { 9, DISABLED, NONE}, + {10, DISABLED, NONE}, + {11, DISABLED, NONE}, + {12, DISABLED, NONE}, + {13, DISABLED, NONE}, + {14, DISABLED, NONE}, + {15, DISABLED, NONE}, + {16, DISABLED, NONE}, + {17, DISABLED, NONE}, + {18, DISABLED, NONE}, + {19, DISABLED, NONE}, + {20, DISABLED, NONE}, + {21, DISABLED, NONE}, + {22, DISABLED, NONE}, + {23, DISABLED, NONE}, +}; + +static void setup_ioapic(void) +{ + int i; + unsigned long value_low, value_high, val; + unsigned long ioapic_base = IOAPIC_ADDR; + volatile unsigned long *l; + struct ioapicreg *a = ioapicregvalues; + unsigned long bsp_lapicid = lapicid(); + + l = (unsigned long *)ioapic_base; + + /* Set APIC ADDR */ + l[0] = 0; + val = l[4]; + l[4] = (val & 0xF0FFFF) | (2 << 24); // 2 == ID as programmed elsewhere. should be a define? XXX + + /* Set APIC to FSB message bus. */ + l[0] = 0x3; + val = l[4]; + l[4] = (val & 0xFFFFFE) | 1; + + ioapicregvalues[0].value_high = bsp_lapicid << (56 - 32); + + printk_debug("IOAPIC: Bootstrap Processor Local APIC ID = %02x\n", bsp_lapicid); + + for (i = 0; i < ARRAY_SIZE(ioapicregvalues); i++, a++) { + l[0] = (a->reg * 2) + 0x10; + l[4] = a->value_low; + value_low = l[4]; + l[0] = (a->reg * 2) + 0x11; + l[4] = a->value_high; + value_high = l[4]; + if ((i == 0) && (value_low == 0xffffffff)) { + printk_warning("IOAPIC is not responding.\n"); + return; + } + printk_debug("IOAPIC: IRQ reg 0x%08x value 0x%08x 0x%08x\n", + a->reg, a->value_low, a->value_high); + } +} +#endif + +static const unsigned char pci_irqs[4] = { 11, 11, 10, 10 }; + +static const unsigned char usb_pins[4] = { 'A', 'B', 'C', 'D' }; +static const unsigned char vga_pins[4] = { 'A', 'B', 'C', 'D' }; +static const unsigned char slot_pins[4] = { 'B', 'C', 'D', 'A' }; +static const unsigned char ac97_pins[4] = { 'B', 'C', 'D', 'A' }; + +static unsigned char *pin_to_irq(const unsigned char *pin) +{ + static unsigned char irqs[4]; + int i; + for (i = 0; i < 4; i++) + irqs[i] = pci_irqs[pin[i] - 'A']; + + return irqs; +} + +static void pci_routing_fixup(struct device *dev) +{ + printk_debug("%s: device is %p\n", __FUNCTION__, dev); + + /* set up PCI IRQ routing */ + pci_write_config8(dev, 0x55, pci_irqs[0] << 4); + pci_write_config8(dev, 0x56, pci_irqs[1] | (pci_irqs[2] << 4)); + pci_write_config8(dev, 0x57, pci_irqs[3] << 4); + + /* Assigning IRQs */ + printk_debug("Setting up USB interrupts.\n"); + pci_assign_irqs(0, 0x10, pin_to_irq(usb_pins)); + + printk_debug("Setting up VGA interrupts.\n"); + pci_assign_irqs(1, 0x00, pin_to_irq(vga_pins)); + + printk_debug("Setting up PCI slot interrupts.\n"); + pci_assign_irqs(2, 0x04, pin_to_irq(slot_pins)); + // more? + + printk_debug("Setting up AC97 interrupts.\n"); + pci_assign_irqs(0x80, 0x1, pin_to_irq(ac97_pins)); +} + +/* + * Set up the power management capabilities directly into ACPI mode. This + * avoids having to handle any System Management Interrupts (SMI's) which I + * can't figure out how to do !!!! + */ + +void setup_pm(device_t dev) +{ + /* Debounce LID and PWRBTN# Inputs for 16ms. */ + pci_write_config8(dev, 0x80, 0x20); + + /* Set ACPI base address to IO ACPI_IO_BASE */ + pci_write_config16(dev, 0x88, ACPI_IO_BASE | 1); + + /* set ACPI irq to 9 */ + pci_write_config8(dev, 0x82, 0x49); + + /* Primary interupt channel, define wake events 0=IRQ0 15=IRQ15 1=en. */ + pci_write_config16(dev, 0x84, 0x609a); + + /* SMI output level to low, 7.5us throttle clock */ + pci_write_config8(dev, 0x8d, 0x18); + + /* GP Timer Control 1s */ + pci_write_config8(dev, 0x93, 0x88); + + /* Power Well */ + pci_write_config8(dev, 0x94, 0x20); // 0x20?? + + /* 7 = stp to sust delay 1msec + * 6 = SUSST# Deasserted Before PWRGD for STD + */ + pci_write_config8(dev, 0x95, 0xc0); // 0xc1?? + + /* Disable GP2 & GP3 Timer */ + pci_write_config8(dev, 0x98, 0); + + /* GP2 Timer Counter */ + pci_write_config8(dev, 0x99, 0xfb); + /* GP3 Timer Counter */ + //pci_write_config8(dev, 0x9a, 0x20); + + /* Multi Function Select 1 */ + pci_write_config8(dev, 0xe4, 0x00); + + /* Multi Function Select 2 */ + pci_write_config8(dev, 0xe5, 0x41); //?? + + /* Enable ACPI access (and setup like award) */ + pci_write_config8(dev, 0x81, 0x84); + + /* Clear status events. */ + outw(0xffff, ACPI_IO_BASE + 0x00); + outw(0xffff, ACPI_IO_BASE + 0x20); + outw(0xffff, ACPI_IO_BASE + 0x28); + outl(0xffffffff, ACPI_IO_BASE + 0x30); + + /* Disable SCI on GPIO. */ + outw(0x0, ACPI_IO_BASE + 0x22); + + /* Disable SMI on GPIO. */ + outw(0x0, ACPI_IO_BASE + 0x24); + + /* Disable all global enable SMIs. */ + outw(0x0, ACPI_IO_BASE + 0x2a); + + /* All SMI off, both IDE buses ON, PSON rising edge. */ + outw(0x0, ACPI_IO_BASE + 0x2c); + + /* Primary activity SMI disable. */ + outl(0x0, ACPI_IO_BASE + 0x34); + + /* GP timer reload on none. */ + outl(0x0, ACPI_IO_BASE + 0x38); + + /* Disable extended IO traps. */ + outb(0x0, ACPI_IO_BASE + 0x42); + + /* SCI is generated for RTC/pwrBtn/slpBtn. */ + outw(0x0001, ACPI_IO_BASE + 0x04); + + /* Allow SLP# signal to assert LDTSTOP_L. + * Will work for C3 and for FID/VID change. + */ + outb(0x1, ACPI_IO_BASE + 0x11); +} + +static void cx700_set_lpc_registers(struct device *dev) +{ + unsigned char enables; + + printk_debug("VIA CX700 LPC bridge init\n"); + + // enable the internal I/O decode + enables = pci_read_config8(dev, 0x6C); + enables |= 0x80; + pci_write_config8(dev, 0x6C, enables); + + // Map 4MB of FLASH into the address space +// pci_write_config8(dev, 0x41, 0x7f); + + // Set bit 6 of 0x40, because Award does it (IO recovery time) + // IMPORTANT FIX - EISA 0x4d0 decoding must be on so that PCI + // interrupts can be properly marked as level triggered. + enables = pci_read_config8(dev, 0x40); + enables |= 0x44; + pci_write_config8(dev, 0x40, enables); + + /* DMA Line buffer control */ + enables = pci_read_config8(dev, 0x42); + enables |= 0xf0; + pci_write_config8(dev, 0x42, enables); + + /* I/O recovery time */ + pci_write_config8(dev, 0x4c, 0x44); + + /* ROM memory cycles go to LPC. */ + pci_write_config8(dev, 0x59, 0x80); + + /* Enable SM dynamic clock gating */ + pci_write_config8(dev, 0x5b, 0x01); + + /* Set Read Pass Write Control Enable */ + pci_write_config8(dev, 0x48, 0x0c); + + /* Set SM Misc Control: Enable Internal APIC . */ + enables = pci_read_config8(dev, 0x58); + enables |= 1 << 6; + pci_write_config8(dev, 0x58, enables); + enables = pci_read_config8(dev, 0x4d); + enables |= 1 << 3; + pci_write_config8(dev, 0x4d, enables); + + /* Set bit 3 of 0x4f to match award (use INIT# as cpu reset) */ + enables = pci_read_config8(dev, 0x4f); + enables |= 0x08; + pci_write_config8(dev, 0x4f, enables); + + /* enable KBC configuration */ + pci_write_config8(dev, 0x51, 0x1f); + + /* enable serial irq */ + pci_write_config8(dev, 0x52, 0x9); + + /* dma */ + pci_write_config8(dev, 0x53, 0x00); + + // Power management setup + setup_pm(dev); + + /* set up isa bus -- i/o recovery time, rom write enable, extend-ale */ + pci_write_config8(dev, 0x40, 0x54); + + /* Enable HPET timer */ + pci_write_config32(dev, 0x68, (1 << 31) | (HPET_ADDR >> 8)); + +} + +void cx700_read_resources(device_t dev) +{ + struct resource *resource; + + /* Make sure we call our childrens set/enable functions - these + * are not called unless this device has a resource to set. + */ + + pci_dev_read_resources(dev); + + resource = new_resource(dev, 1); + resource->flags |= + IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_IO | IORESOURCE_STORED; + resource->size = 2; + resource->base = 0x2e; +} + +void cx700_set_resources(device_t dev) +{ + struct resource *resource; + resource = find_resource(dev, 1); + resource->flags |= IORESOURCE_STORED; + pci_dev_set_resources(dev); +} + +void cx700_enable_resources(device_t dev) +{ + /* Enable SuperIO decoding */ + pci_dev_enable_resources(dev); + enable_childrens_resources(dev); +} + +static void cx700_lpc_init(struct device *dev) +{ + cx700_set_lpc_registers(dev); + +#ifdef CONFIG_IOAPIC + setup_ioapic(); +#endif + + /* Initialize interrupts */ + pci_routing_fixup(dev); + /* make sure interupt controller is configured before keyboard init */ + setup_i8259(); + + /* Start the Real Time Clock */ + rtc_init(0); + + /* Initialize isa dma */ + isa_dma_init(); + + /* Initialize keyboard controller */ + init_pc_keyboard(0x60, 0x64, 0); +} + +static struct device_operations cx700_lpc_ops = { + .read_resources = cx700_read_resources, + .set_resources = cx700_set_resources, + .enable_resources = cx700_enable_resources, + .init = &cx700_lpc_init, + .scan_bus = scan_static_bus, +}; + +static const struct pci_driver lpc_driver __pci_driver = { + .ops = &cx700_lpc_ops, + .vendor = PCI_VENDOR_ID_VIA, + .device = 0x8324, +}; diff --git a/src/northbridge/via/cx700/cx700_registers.h b/src/northbridge/via/cx700/cx700_registers.h new file mode 100644 index 0000000000..996c00f015 --- /dev/null +++ b/src/northbridge/via/cx700/cx700_registers.h @@ -0,0 +1,272 @@ +/* + * 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 + */ + +/* CX700 has 48 bytes of scratch registers in D0F4 starting at Reg. 0xd0 */ +#define SCRATCH_REG_BASE 0xd0 +#define SCRATCH_RANK_0 0xd0 +#define SCRATCH_RANK_1 0xd1 +#define SCRATCH_RANK_2 0xd2 +#define SCRATCH_RANK_3 0xd3 +#define SCRATCH_DIMM_NUM 0xd4 +#define SCRATCH_RANK_NUM 0xd5 +#define SCRATCH_RANK_MAP 0xd6 +#define SCRATCH_DRAM_FREQ 0xd7 +#define SCRATCH_DRAM_NB_ODT 0xd8 +#define SCRATCH_RANK0_SIZE_REG 0xe0 /* RxE0~RxE3 */ +#define SCRATCH_RANK0_MA_REG 0xe4 /* RxE4~RxE7 */ +#define SCRATCH_CHA_DQSI_LOW_REG 0xe8 +#define SCRATCH_CHA_DQSI_HIGH_REG 0xe9 +#define SCRATCH_ChA_DQSI_REG 0xea +#define SCRATCH_DRAM_256M_BIT 0xee +#define SCRATCH_FLAGS 0xef + +static const u8 Reg_Val[] = { +/* REG, VALUE */ + 0x70, 0x33, + 0x71, 0x11, + 0x72, 0x33, + 0x73, 0x11, + 0x74, 0x20, + 0x75, 0x2e, + 0x76, 0x64, + 0x77, 0x00, + 0x78, 0x44, + 0x79, 0xaa, + 0x7a, 0x33, + 0x7b, 0xaa, + 0x7c, 0x00, + 0x7e, 0x33, + 0x7f, 0x33, + 0x80, 0x44, + 0x81, 0x44, + 0x82, 0x44, + 0x83, 0x02, + 0x50, 0x88, + 0x51, 0x7b, + 0x52, 0x6f, + 0x53, 0x88, + 0x54, 0x0e, + 0x55, 0x00, + 0x56, 0x00, + 0x59, 0x00, + 0x5d, 0x72, + 0x5e, 0x88, + 0x5f, 0xc7, + 0x68, 0x01, +}; + +/* Host registers initial value */ +static const u8 Host_Reg_Val[] = { +/* REG, VALUE */ + 0x60, 0xff, + 0x61, 0xff, + 0x62, 0x0f, + 0x63, 0xff, + 0x64, 0xff, + 0x65, 0x0f, + 0x66, 0xff, + 0x67, 0x30, +}; + +static const u8 Mem_Reg_Init[] = { +/* REG, AND, OR */ + 0x50, 0x11, 0x66, + 0x51, 0x11, 0x66, + 0x52, 0x00, 0x11, + 0x53, 0x00, 0x0f, + 0x54, 0x00, 0x00, + 0x55, 0x00, 0x00, + 0x56, 0x00, 0x00, + 0x57, 0x00, 0x00, + 0x60, 0x00, 0x00, + 0x62, 0xf7, 0x08, + 0x65, 0x00, 0xd9, + 0x66, 0x00, 0x80, + 0x67, 0x00, 0x50, /* OR 0x00 ?? */ + 0x69, 0xf0, 0x00, + 0x6a, 0x00, 0x00, + 0x6d, 0xcf, 0xc0, + 0x6e, 0xff, 0x80, + 0x75, 0x0f, 0x40, + 0x77, 0x00, 0x00, + 0x80, 0x00, 0x00, + 0x81, 0x00, 0x00, + 0x82, 0x00, 0x00, + 0x83, 0x00, 0x00, + 0x84, 0x00, 0x00, + 0x85, 0x00, 0x00, + 0x86, 0xff, 0x2c, /* OR 0x28 if we don't want enable top 1M SM memory */ + 0x40, 0x00, 0x00, + 0x7c, 0x00, 0x00, + 0x7e, 0x00, 0x00, + 0xa4, 0xfe, 0x00, + 0xb0, 0x7f, 0x80, + 0xb1, 0x00, 0xaa, + 0xb4, 0xfd, 0x02, + 0xb8, 0xfe, 0x00, +}; + +static const u8 Dram_Driving_ODT_CTRL[] = { +/* REG, VALUE */ + 0xd6, 0xa8, + 0xd4, 0x80, + 0xd0, 0x88, + 0xd3, 0x01, + 0xd8, 0x00, + 0xda, 0x80, +}; + +#define Rank0_ODT 0x00 +#define Rank1_ODT 0x01 +#define Rank2_ODT 0x02 +#define Rank3_ODT 0x03 +#define NA_ODT 0x00 +#define NB_ODT_75ohm 0x00 +#define NB_ODT_150ohm 0x01 +#define DDR2_ODT_75ohm 0x20 +#define DDR2_ODT_150ohm 0x40 + +static const u8 ODT_TBL[] = { +/* RankMap, ODT Control Bits, DRAM & NB ODT setting */ + 0x01, ((NA_ODT << 6) | (NA_ODT << 4) | (NA_ODT << 2) | Rank0_ODT), (DDR2_ODT_150ohm | NB_ODT_75ohm), + 0x03, ((NA_ODT << 6) | (NA_ODT << 4) | (Rank0_ODT << 2) | Rank1_ODT), (DDR2_ODT_150ohm | NB_ODT_75ohm), + 0x04, ((NA_ODT << 6) | (Rank2_ODT << 4) | (NA_ODT << 2) | NA_ODT), (DDR2_ODT_150ohm | NB_ODT_75ohm), + 0x05, ((NA_ODT << 6) | (Rank0_ODT << 4) | (NA_ODT << 2) | Rank2_ODT), (DDR2_ODT_75ohm | NB_ODT_150ohm), + 0x07, ((NA_ODT << 6) | (Rank0_ODT << 4) | (Rank2_ODT << 2) | Rank2_ODT), (DDR2_ODT_75ohm | NB_ODT_150ohm), + 0x0c, ((Rank2_ODT << 6) | (Rank3_ODT << 4) | (NA_ODT << 2) | NA_ODT), (DDR2_ODT_150ohm | NB_ODT_75ohm), + 0x0d, ((Rank0_ODT << 6) | (Rank0_ODT << 4) | (NA_ODT << 2) | Rank2_ODT), (DDR2_ODT_75ohm | NB_ODT_150ohm), + 0x0f, ((Rank0_ODT << 6) | (Rank0_ODT << 4) | (Rank2_ODT << 2) | Rank2_ODT), (DDR2_ODT_75ohm | NB_ODT_150ohm), +}; + +static const u8 DQS_DQ_TBL[] = { +/* RxE0: DRAM Timing DQS */ +/* RxE2: DRAM Timing DQ */ +/* RxE0, RxE2 */ + 0xee, 0xba, + 0xee, 0xba, + 0xcc, 0xba, + 0xcc, 0xba, +}; + +static const u8 Duty_Control_DDR2[] = { +/* RxEC, RxED, RxEE, RXEF */ + /* DDRII533 1~2 rank, DDRII400 */ + 0x84, 0x10, 0x00, 0x10, + /* DDRII533 3~4 rank */ + 0x44, 0x10, 0x00, 0x10, +}; + +static const u8 ChA_Clk_Phase_DDR2_Table[] = { +/* Rx91, Rx92, Rx93 */ + /* DDRII533 1 rank */ + 0x04, 0x05, 0x06, + /* DDRII533 2~4 rank */ + 0x04, 0x05, 0x05, + /* DDRII400 */ + 0x02, 0x04, 0x04, +}; + +static const u8 DQ_DQS_Table[] = { +/* REG, VALUE */ +/* DRAM DQ/DQS Output Delay Control */ + 0xdc, 0x65, + 0xdd, 0x01, + 0xde, 0xc0, +/* DRAM DQ/DQS input Capture Control */ + 0x78, 0x83, + 0x79, 0x83, + 0x7a, 0x00, +}; + +static const u8 DQSOChA_DDR2_Driving_Table[] = { +/* Rx70, Rx71 */ + /* DDRII533 1~2 rank */ + 0x00, 0x01, + /* DDRII533 3~4 rank */ + 0x03, 0x00, + /* DDRII400 1~2 rank */ + 0x00, 0x04, + /* DDRII400 3~4 rank */ + 0x00, 0x01, +}; + +/************************************************************************/ +/* Chipset Performance UP and other setting after DRAM Sizing Registers */ +/************************************************************************/ +static const u8 Dram_Table[] = { +/* REG, AND, OR */ + 0x60, 0xff, 0x03, + 0x66, 0xcf, 0x80, + 0x68, 0x00, 0x00, + 0x69, 0xfd, 0x03, + 0x6e, 0xff, 0x01, + 0x95, 0xff, 0x40, +}; + +static const u8 Host_Table[] = { +/* REG, AND, OR */ + 0x51, 0x81, 0x7a, + 0x55, 0xff, 0x06, + 0x5e, 0x00, 0x88, + 0x5d, 0xff, 0xb2, +}; + +static const u8 Init_Rank_Reg_Table[] = { + /* Rank Ending Address Registers */ + 0x40, 0x41, 0x42, 0x43, + /* Rank Beginning Address Registers */ + 0x48, 0x49, 0x4a, 0x4b, + /* Physical-to-Virtual Rank Mapping Registers */ + 0x54, 0x55, +}; + +static const u16 DDR2_MRS_table[] = { +/* CL: 2, 3, 4, 5 */ + 0x150, 0x1d0, 0x250, 0x2d0, /* BL=4 ;Use 1X-bandwidth MA table to init DRAM */ + 0x158, 0x1d8, 0x258, 0x2d8, /* BL=8 ;Use 1X-bandwidth MA table to init DRAM */ +}; + +#define MRS_DDR2_TWR2 ((0 << 15) | (0 << 20) | (1 << 12)) +#define MRS_DDR2_TWR3 ((0 << 15) | (1 << 20) | (0 << 12)) +#define MRS_DDR2_TWR4 ((0 << 15) | (1 << 20) | (1 << 12)) +#define MRS_DDR2_TWR5 ((1 << 15) | (0 << 20) | (0 << 12)) +static const u32 DDR2_Twr_table[] = { + MRS_DDR2_TWR2, + MRS_DDR2_TWR3, + MRS_DDR2_TWR4, + MRS_DDR2_TWR5, +}; + +static const u8 DQSI_Rate_Table[] = { + 8, /* DDRII 200 */ + 8, /* DDRII 266 */ + 8, /* DDRII 333 */ + 7, /* DDRII 400 */ + 8, /* DDRII 533 */ + 8, /* DDRII 666 */ +}; + +static const u8 REFC_Table[] = { + 0x65, 0x32, /* DDRII 100 */ + 0x86, 0x43, /* DDRII 266 */ + 0xa8, 0x54, /* DDRII 333 */ + 0xca, 0x65, /* DDRII 400 */ + 0xca, 0x86, /* DDRII 533 */ + 0xca, 0xa8, /* DDRII 666 */ +}; diff --git a/src/northbridge/via/cx700/cx700_reset.c b/src/northbridge/via/cx700/cx700_reset.c new file mode 100644 index 0000000000..80e09d7fab --- /dev/null +++ b/src/northbridge/via/cx700/cx700_reset.c @@ -0,0 +1,25 @@ +/* + * 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 <arch/io.h> + +void hard_reset(void) +{ + outb((1 << 2) | (1 << 1), 0xcf9); +} diff --git a/src/northbridge/via/cx700/cx700_sata.c b/src/northbridge/via/cx700/cx700_sata.c new file mode 100644 index 0000000000..893126606e --- /dev/null +++ b/src/northbridge/via/cx700/cx700_sata.c @@ -0,0 +1,160 @@ +/* + * 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 <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> + +/* IDE specific bits */ +#define IDE_MODE_REG 0x09 +#define IDE0_NATIVE_MODE (1 << 0) +#define IDE1_NATIVE_MODE (1 << 2) + +/* These are default addresses */ +#define IDE0_DATA_ADDR 0x1f0 +#define IDE0_CONTROL_ADDR 0x3f4 +#define IDE1_DATA_ADDR 0x170 +#define IDE1_CONTROL_ADDR 0x370 + +#define BUS_MASTER_ADDR 0xfc00 + +#define CHANNEL_ENABLE_REG 0x40 +#define ENABLE_IDE0 (1 << 0) +#define ENABLE_IDE1 (1 << 1) + +/* TODO: better user configuration */ +#define DISABLE_SATA 0 + +static void sata_init(struct device *dev) +{ + u8 reg8; + + printk_debug("Configuring VIA SATA & EIDE Controller\n"); + + /* Class IDE Disk, instead of RAID controller */ + reg8 = pci_read_config8(dev, 0x45); + reg8 &= 0x7f; /* Sub Class Write Protect off */ + pci_write_config8(dev, 0x45, reg8); + pci_write_config8(dev, 0x0a, 0x01); + reg8 |= 0x80; /* Sub Class Write Protect on */ + pci_write_config8(dev, 0x45, reg8); + +#if defined(DISABLE_SATA) && (DISABLE_SATA == 1) + printk_info("Disabling SATA (Primary Channel)\n"); + /* Disable SATA channels */ + pci_write_config8(dev, 0x40, 0x00); +#else + pci_write_config8(dev, 0x40, 0x43); +#endif + + reg8 = pci_read_config8(dev, 0x6a); + reg8 |= 0x8; /* Mode Select set to Manual Mode */ + reg8 &= ~7; + reg8 |= 0x2; /* Manual setting to 50 ohm */ + + pci_write_config8(dev, 0x6a, reg8); + + reg8 = pci_read_config8(dev, 0x6b); + reg8 &= ~7; + reg8 |= 0x01; /* Autocomp of Termination */ + pci_write_config8(dev, 0x6b, reg8); + + /* Enable EIDE (secondary channel) even if SATA disabled */ + reg8 = pci_read_config8(dev, 0xc0); + reg8 |= 0x1; + pci_write_config8(dev, 0xc0, reg8); + + // Enable bus mastering, memory space acces, io space access + pci_write_config16(dev, 0x04, 0x0007); + + /* Set SATA base ports. */ + pci_write_config32(dev, 0x10, 0x01f1); + pci_write_config32(dev, 0x14, 0x03f5); + /* Set EIDE base ports. */ + pci_write_config32(dev, 0x18, 0x0171); + pci_write_config32(dev, 0x1c, 0x0375); + + /* SATA/EIDE Bus Master mode base address */ + pci_write_config32(dev, 0x20, BUS_MASTER_ADDR | 1); + + /* Enable read/write prefetch buffers */ + reg8 = pci_read_config8(dev, 0xc1); + reg8 |= 0x30; + pci_write_config8(dev, 0xc1, reg8); + + /* Set FIFO thresholds like */ + pci_write_config8(dev, 0xc3, 0x1); /* FIFO flushed when 1/2 full */ + + /* EIDE Sector Size */ + pci_write_config16(dev, 0xe8, 0x200); + + /* Some Miscellaneous Control */ + pci_write_config8(dev, 0x44, 0x7); + pci_write_config8(dev, 0x45, 0xaf); + pci_write_config8(dev, 0x46, 0x8); + + /* EIDE Configuration */ + reg8 = pci_read_config8(dev, 0xc4); + reg8 |= 0x10; + pci_write_config8(dev, 0xc4, reg8); + + pci_write_config8(dev, 0xc5, 0xc); + + /* Interrupt Line */ + reg8 = pci_read_config8(dev, 0x45); + reg8 &= ~(1 << 4); /* Interrupt Line Write Protect off */ + pci_write_config8(dev, 0x45, reg8); + + pci_write_config8(dev, 0x3c, 0x0e); /* Interrupt */ + + /* Set the drive timing control */ + pci_write_config16(dev, 0x48, 0x5d5d); + + /* Enable only compatibility mode. */ + reg8 = pci_read_config8(dev, 0x42); + reg8 &= ~0xa0; + pci_write_config8(dev, 0x42, reg8); + reg8 = pci_read_config8(dev, 0x42); + printk_debug("Reg 0x42 read back as 0x%x\n", reg8); + + /* Support Staggered Spin-Up */ + reg8 = pci_read_config8(dev, 0xb9); + if ((reg8 & 0x8) == 0) { + printk_debug("start OOB sequence on both drives\n"); + reg8 |= 0x30; + pci_write_config8(dev, 0xb9, reg8); + } +} + +static struct device_operations sata_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = sata_init, + .enable = 0, + .ops_pci = 0, +}; + +/* When the SATA controller is in IDE mode, the Device ID is 0x5324 */ +static const struct pci_driver northbridge_driver __pci_driver = { + .ops = &sata_ops, + .vendor = PCI_VENDOR_ID_VIA, + .device = 0x5324, +}; diff --git a/src/northbridge/via/cx700/cx700_usb.c b/src/northbridge/via/cx700/cx700_usb.c new file mode 100644 index 0000000000..b2dc482df3 --- /dev/null +++ b/src/northbridge/via/cx700/cx700_usb.c @@ -0,0 +1,56 @@ +/* + * 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 <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> + +static void usb_init(struct device *dev) +{ + u32 reg32; + u8 reg8; + + /* USB Specification says the device must be Bus Master */ + printk_debug("UHCI: Setting up controller.. "); + + reg32 = pci_read_config32(dev, PCI_COMMAND); + pci_write_config32(dev, PCI_COMMAND, reg32 | PCI_COMMAND_MASTER); + + reg8 = pci_read_config8(dev, 0xca); + reg8 |= (1 << 0); + pci_write_config8(dev, 0xca, reg8); + + printk_debug("done.\n"); +} + +static struct device_operations usb_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = usb_init, + .enable = 0, + .ops_pci = 0, +}; + +static const struct pci_driver via_usb_driver __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VENDOR_ID_VIA, + .device = 0x3038, +}; diff --git a/src/northbridge/via/cx700/cx700_vga.c b/src/northbridge/via/cx700/cx700_vga.c new file mode 100644 index 0000000000..96bb769e20 --- /dev/null +++ b/src/northbridge/via/cx700/cx700_vga.c @@ -0,0 +1,119 @@ +/* + * 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 <console/console.h> +#include <arch/io.h> +#include <stdint.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <stdlib.h> +#include <string.h> +#include <bitops.h> +#include <cpu/cpu.h> +#include <cpu/x86/mtrr.h> +#include <cpu/x86/msr.h> +#include "chip.h" +#include "northbridge.h" + +/* PCI Domain 1 Device 0 Function 0 */ + +#define SR_INDEX 0x3c4 +#define SR_DATA 0x3c5 +#define CRTM_INDEX 0x3b4 +#define CRTM_DATA 0x3b5 +#define CRTC_INDEX 0x3d4 +#define CRTC_DATA 0x3d5 + +void setup_realmode_idt(void); +void do_vgabios(void); +void vga_enable_console(void); + +void write_protect_vgabios(void) +{ + device_t dev; + + printk_debug("write_protect_vgabios\n"); + + dev = dev_find_device(PCI_VENDOR_ID_VIA, 0x3324, 0); + if (dev) + pci_write_config8(dev, 0x80, 0xff); + + dev = dev_find_device(PCI_VENDOR_ID_VIA, 0x7324, 0); + if (dev) + pci_write_config8(dev, 0x61, 0xff); +} + +static void vga_init(device_t dev) +{ + u8 reg8; + + printk_debug("Initializing VGA...\n"); + + //* + pci_write_config8(dev, 0x04, 0x07); + pci_write_config8(dev, 0x3e, 0x02); + pci_write_config8(dev, 0x0d, 0x40); + pci_write_config32(dev, 0x10, 0xa0000008); + pci_write_config32(dev, 0x14, 0xdd000000); + pci_write_config8(dev, 0x3c, 0x0b); + //*/ + + printk_debug("Executing VGA option rom in real mode\n"); + setup_realmode_idt(); + do_vgabios(); + printk_debug("Enable VGA console\n"); + vga_enable_console(); + + /* It's not clear if these need to be programmed before or after + * the VGA bios runs. Try both, clean up later */ + /* Set memory rate to 200MHz */ + outb(0x3d, CRTM_INDEX); + reg8 = inb(CRTM_DATA); + reg8 &= 0x0f; + reg8 |= (0x3 << 4); + outb(0x3d, CRTM_INDEX); + outb(reg8, CRTM_DATA); + + /* Set framebuffer size to 32mb */ + reg8 = (32 / 4); + outb(0x39, SR_INDEX); + outb(reg8, SR_DATA); +} + +static void vga_read_resources(device_t dev) +{ + dev->rom_address = 0xfff80000; + dev->on_mainboard = 1; + pci_dev_read_resources(dev); +} + +static struct device_operations vga_operations = { + .read_resources = vga_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = vga_init, + .ops_pci = 0, +}; + +static const struct pci_driver vga_driver __pci_driver = { + .ops = &vga_operations, + .vendor = PCI_VENDOR_ID_VIA, + .device = 0x3157, +}; diff --git a/src/northbridge/via/cx700/northbridge.c b/src/northbridge/via/cx700/northbridge.c new file mode 100644 index 0000000000..dc0c667d10 --- /dev/null +++ b/src/northbridge/via/cx700/northbridge.c @@ -0,0 +1,182 @@ +/* + * 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 <console/console.h> +#include <arch/io.h> +#include <stdint.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/hypertransport.h> +#include <device/pci_ids.h> +#include <stdlib.h> +#include <string.h> +#include <bitops.h> +#include <cpu/cpu.h> +#include <cpu/x86/mtrr.h> +#include "chip.h" +#include "northbridge.h" + +static void pci_domain_read_resources(device_t dev) +{ + struct resource *resource; + + /* Initialize the system wide io space constraints */ + resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0)); + resource->limit = 0xffffUL; + resource->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; + + /* Initialize the system wide memory resources constraints */ + resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0)); + resource->limit = 0xffffffffULL; + resource->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; +} + +static void ram_resource(device_t dev, unsigned long index, + unsigned long basek, unsigned long sizek) +{ + struct resource *resource; + + if (!sizek) { + return; + } + resource = new_resource(dev, index); + resource->base = ((resource_t) basek) << 10; + resource->size = ((resource_t) sizek) << 10; + resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE | + IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; +} + +static void tolm_test(void *gp, struct device *dev, struct resource *new) +{ + struct resource **best_p = gp; + struct resource *best; + best = *best_p; + if (!best || (best->base > new->base)) { + best = new; + } + *best_p = best; +} + +static u32 find_pci_tolm(struct bus *bus) +{ + struct resource *min = NULL; + u32 tolm; + + search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min); + tolm = 0xffffffffUL; + if (min && tolm > min->base) { + tolm = min->base; + } + + return tolm; +} + +static void pci_domain_set_resources(device_t dev) +{ + device_t mc_dev; + u32 pci_tolm; + unsigned char reg; + unsigned long tomk, tolmk; + unsigned char rambits; + int idx; + + pci_tolm = find_pci_tolm(&dev->link[0]); + mc_dev = dev_find_device(PCI_VENDOR_ID_VIA, 0x3324, 0); + + rambits = pci_read_config8(mc_dev, 0x88); + rambits >>= 2; + + /* Get memory size and frame buffer from northbridge's registers. + * + * If register contains an invalid value we set frame buffer size to a + * default of 32M, but that probably won't happen. + */ + reg = pci_read_config8(mc_dev, 0xa1); + reg &= 0x70; + reg = reg >> 4; + + /* TOP 1M SMM Memory */ + if (reg == 0x0 || reg == 0x6 || reg == 0x7) + tomk = (((rambits << 6) - 32 - 1) * 1024); // Set frame buffer 32M for default + else + tomk = (((rambits << 6) - (4 << reg) - 1) * 1024); + + /* Compute the top of Low memory */ + tolmk = pci_tolm >> 10; + if (tolmk >= tomk) { + /* The PCI hole does does not overlap the memory. */ + tolmk = tomk; + tolmk -= 1024; // TOP 1M SM Memory + } + + /* Report the memory regions */ + idx = 10; + + /* TODO: Hole needed? Should this go elsewhere? */ + ram_resource(dev, idx++, 0, 640); /* first 640k */ + ram_resource(dev, idx++, 768, (tolmk - 768)); /* leave a hole for vga */ + assign_resources(&dev->link[0]); +} + +static unsigned int pci_domain_scan_bus(device_t dev, unsigned int max) +{ + max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0, 0), 0xff, max); + return max; +} + +static struct device_operations pci_domain_ops = { + .read_resources = pci_domain_read_resources, + .set_resources = pci_domain_set_resources, + .enable_resources = enable_childrens_resources, + .init = 0, + .scan_bus = pci_domain_scan_bus, +}; + +static void cpu_bus_init(device_t dev) +{ + initialize_cpus(&dev->link[0]); +} + +static void cpu_bus_noop(device_t dev) +{ +} + +static struct device_operations cpu_bus_ops = { + .read_resources = cpu_bus_noop, + .set_resources = cpu_bus_noop, + .enable_resources = cpu_bus_noop, + .init = cpu_bus_init, + .scan_bus = 0, +}; + +static void enable_dev(struct device *dev) +{ + /* Our wonderful device model */ + if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) { + dev->ops = &pci_domain_ops; + pci_set_method(dev); + } else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) { + dev->ops = &cpu_bus_ops; + } +} + +struct chip_operations northbridge_via_cx700_ops = { + CHIP_NAME("VIA CX700 Northbridge") + .enable_dev = enable_dev +}; diff --git a/src/northbridge/via/cx700/northbridge.h b/src/northbridge/via/cx700/northbridge.h new file mode 100644 index 0000000000..1048a96643 --- /dev/null +++ b/src/northbridge/via/cx700/northbridge.h @@ -0,0 +1,25 @@ +/* + * 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 + */ + +#ifndef NORTHBRIDGE_VIA_CX700_H +#define NORTHBRIDGE_VIA_CX700_H + +extern unsigned int cx700_scan_root_bus(device_t root, unsigned int max); + +#endif /* NORTHBRIDGE_VIA_CX700_H */ diff --git a/src/northbridge/via/cx700/raminit.c b/src/northbridge/via/cx700/raminit.c new file mode 100644 index 0000000000..ff21e537ca --- /dev/null +++ b/src/northbridge/via/cx700/raminit.c @@ -0,0 +1,1480 @@ +/* + * 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 <types.h> +#include <spd.h> +#include <spd_ddr2.h> +#include <sdram_mode.h> +#include <delay.h> +#include "cx700_registers.h" + +// #define DEBUG_RAM_SETUP 1 + +/* Debugging macros. */ +#if defined(DEBUG_RAM_SETUP) +#define PRINTK_DEBUG(x...) printk_debug(x) +#else +#define PRINTK_DEBUG(x...) +#endif + +#define RAM_COMMAND_NORMAL 0x0 +#define RAM_COMMAND_NOP 0x1 +#define RAM_COMMAND_PRECHARGE 0x2 +#define RAM_COMMAND_MRS 0x3 +#define RAM_COMMAND_CBR 0x4 + +#define HOSTCTRL PCI_DEV(0, 0, 2) +#define MEMCTRL PCI_DEV(0, 0, 3) + +#define DDRII_666 0x5 +#define DDRII_533 0x4 +#define DDRII_400 0x3 +#define DDRII_333 0x2 +#define DDRII_266 0x1 +#define DDRII_200 0x0 + +#define OHM_150 1 + +#ifdef MEM_WIDTH_32BIT_MODE +#define SDRAM1X_RA_14 30 +#define SDRAM1X_RA_13 29 +#define SDRAM1X_RA_12 28 +#define SDRAM1X_RA_12_8bk 26 +#define SDRAM1X_CA_12 15 +#define SDRAM1X_CA_11 14 +#define SDRAM1X_CA_09 11 +#define SDRAM1X_CA_09_8bk 11 +#define SDRAM1X_BA1 13 +#define SDRAM1X_BA2_8bk 14 +#define SDRAM1X_BA1_8bk 13 +#else +#define SDRAM1X_RA_14 31 +#define SDRAM1X_RA_13 30 +#define SDRAM1X_RA_12 29 +#define SDRAM1X_RA_12_8bk 27 +#define SDRAM1X_CA_12 16 +#define SDRAM1X_CA_11 15 +#define SDRAM1X_CA_09 12 +#define SDRAM1X_CA_09_8bk 12 +#define SDRAM1X_BA1 14 +#define SDRAM1X_BA2_8bk 15 +#define SDRAM1X_BA1_8bk 14 +#endif + +#define MA_Column 0x06 +#define MA_Bank 0x08 +#define MA_Row 0x30 +#define MA_4_Bank 0x00 +#define MA_8_Bank 0x08 +#define MA_12_Row 0x00 +#define MA_13_Row 0x10 +#define MA_14_Row 0x20 +#define MA_15_Row 0x30 +#define MA_9_Column 0x00 +#define MA_10_Column 0x02 +#define MA_11_Column 0x04 +#define MA_12_Column 0x06 + +#define GET_SPD(i, val, tmp, reg) \ + do{ \ + val = 0; \ + tmp = 0; \ + for(i = 0; i < 2; i++) { \ + if(pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_REG_BASE + (i << 1)))) { \ + tmp = get_spd_data(ctrl, i, reg); \ + if(tmp > val) \ + val = tmp; \ + } \ + } \ + } while ( 0 ) + +#define REGISTERPRESET(bus,dev,fun,bdfspec) \ + { u8 i, reg; \ + for (i=0; i<(sizeof((bdfspec))/sizeof(struct regmask)); i++) { \ + printk_debug("Writing bus " #bus " dev " #dev " fun " #fun " register "); \ + printk_debug("%02x", (bdfspec)[i].reg); \ + printk_debug("\n"); \ + reg = pci_read_config8(PCI_DEV((bus), (dev), (fun)), (bdfspec)[i].reg); \ + reg &= (bdfspec)[i].mask; \ + reg |= (bdfspec)[i].val; \ + pci_write_config8(PCI_DEV((bus), (dev), (fun)), (bdfspec)[i].reg, reg); \ + } \ + } + + +static void do_ram_command(const struct mem_controller *ctrl, u8 command) +{ + u8 reg; + + reg = pci_read_config8(MEMCTRL, 0x6b); + reg &= 0xf8; /* Clear bits 2-0. */ + reg |= command; + pci_write_config8(MEMCTRL, 0x6b, reg); + + PRINTK_DEBUG(" Sending RAM command 0x%02x\n", reg); +} + +// TODO factor out to another file +static void c7_cpu_setup(const struct mem_controller *ctrl) +{ + u8 size, i; + size = sizeof(Reg_Val) / sizeof(Reg_Val[0]); + for (i = 0; i < size; i += 2) + pci_write_config8(HOSTCTRL, Reg_Val[i], Reg_Val[i + 1]); +} + +static void ddr_detect(const struct mem_controller *ctrl) +{ + /* FIXME: Only supports 2 ranks per DIMM */ + u8 val, rsize, dimm; + u8 nrank = 0; + u8 ndimm = 0; + u8 rmap = 0; + for (dimm = 0; dimm < DIMM_SOCKETS; dimm++) { + val = get_spd_data(ctrl, dimm, 0); + if ((val == 0x80) || (val == 0xff)) { + ndimm++; + rsize = get_spd_data(ctrl, dimm, SPD_RANK_SIZE); + /* unit is 128M */ + rsize = (rsize << 3) | (rsize >> 5); + val = + get_spd_data(ctrl, dimm, + SPD_MOD_ATTRIB_RANK) & SPD_MOD_ATTRIB_RANK_NUM_MASK; + switch (val) { + case 1: + pci_write_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_1 + (dimm << 1)), + rsize); + rmap |= (1 << ((dimm << 1) + 1)); + nrank++; + case 0: + pci_write_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + (dimm << 1)), + rsize); + rmap |= (1 << (dimm << 1)); + nrank++; + } + } + } + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_DIMM_NUM, ndimm); + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_NUM, nrank); + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_MAP, rmap); +} + +static void sdram_set_safe_values(const struct mem_controller *ctrl) +{ + /* The purpose of this function is to set initial values for the dram + * size and timings. It will be replaced with the SPD based function + * once the RAM commands are working with these values. + */ + u8 regs, val, t, dimm; + u32 spds, tmp; + + regs = pci_read_config8(MEMCTRL, 0x6c); + if (regs & (1 << 6)) + printk_debug("DDR2 Detected.\n"); + else + die("ERROR: DDR1 memory detected but not supported by coreboot.\n"); + + /* Enable DDR2 */ + regs |= (1 << 7); + pci_write_config8(MEMCTRL, 0x6c, regs); + + /* SPD 5 # of ranks */ + pci_write_config8(MEMCTRL, 0x6d, 0xc0); + + /**********************************************/ + /* Set DRAM Freq (DDR2 533) */ + /**********************************************/ + /* SPD 9 SDRAM Cycle Time */ + GET_SPD(dimm, spds, regs, 9); + + printk_debug("\nDDRII "); + if (spds <= 0x3d) { + printk_debug("533"); + val = DDRII_533; + t = 38; + } else if (spds <= 0x50) { + printk_debug("400"); + val = DDRII_400; + t = 50; + } else if (spds <= 0x60) { + printk_debug("333"); + val = DDRII_333; + t = 60; + } else if (spds <= 0x75) { + printk_debug("266"); + val = DDRII_266; + t = 75; + } else { + printk_debug("200"); + val = DDRII_200; + t = 100; + } + /* To store DDRII frequence */ + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_FREQ, val); + + /* Manual reset and adjust DLL when DRAM change frequency + * This is a necessary sequence. + */ + udelay(2000); + regs = pci_read_config8(MEMCTRL, 0x90); + regs |= 0x7; + pci_write_config8(MEMCTRL, 0x90, regs); + udelay(2000); + regs = pci_read_config8(MEMCTRL, 0x90); + regs &= ~0x7; + regs |= val; + pci_write_config8(MEMCTRL, 0x90, regs); + udelay(2000); + regs = pci_read_config8(MEMCTRL, 0x6b); + regs |= 0xc0; + regs &= ~0x10; + pci_write_config8(MEMCTRL, 0x6b, regs); + udelay(1); + regs |= 0x10; + pci_write_config8(MEMCTRL, 0x6b, regs); + udelay(1); + regs &= ~0xc0; + pci_write_config8(MEMCTRL, 0x6b, regs); + regs = pci_read_config8(MEMCTRL, 0x6f); + regs |= 0x1; + pci_write_config8(MEMCTRL, 0x6f, regs); + + /**********************************************/ + /* Set DRAM Timing Setting (DDR2 533) */ + /**********************************************/ + /* SPD 9 18 23 25 CAS Latency NB3DRAM_REG62[2:0] */ + /* Read SPD byte 18 CAS Latency */ + GET_SPD(dimm, spds, regs, SPD_CAS_LAT); + printk_debug("\nCAS Supported "); + if (spds & SPD_CAS_LAT_2) + printk_debug("2 "); + if (spds & SPD_CAS_LAT_3) + printk_debug("3 "); + if (spds & SPD_CAS_LAT_4) + printk_debug("4 "); + if (spds & SPD_CAS_LAT_5) + printk_debug("5 "); + if (spds & SPD_CAS_LAT_6) + printk_debug("6"); + + /* We don't consider CAS = 6, because CX700 doesn't support it */ + printk_debug("\n CAS:"); + if (spds & SPD_CAS_LAT_5) { + printk_debug("Starting at CL5"); + val = 0x3; + /* See whether we can improve it */ + GET_SPD(dimm, tmp, regs, SPD_CAS_LAT_MIN_X_1); + if ((spds & SPD_CAS_LAT_4) && (tmp < 0x50)) { + printk_debug("\n... going to CL4"); + val = 0x2; + } + GET_SPD(dimm, tmp, regs, SPD_CAS_LAT_MIN_X_2); + if ((spds & SPD_CAS_LAT_3) && (tmp < 0x50)) { + printk_debug("\n... going to CL3"); + val = 0x1; + } + } else { + printk_debug("Starting at CL4"); + val = 0x2; + GET_SPD(dimm, tmp, regs, SPD_CAS_LAT_MIN_X_1); + if ((spds & SPD_CAS_LAT_3) && (tmp < 0x50)) { + printk_debug("\n... going to CL3"); + val = 0x1; + } + GET_SPD(dimm, tmp, regs, SPD_CAS_LAT_MIN_X_2); + if ((spds & SPD_CAS_LAT_2) && (tmp < 0x50)) { + printk_debug("\n... going to CL2"); + val = 0x0; + } + } + regs = pci_read_config8(MEMCTRL, 0x62); + regs &= ~0x7; + regs |= val; + pci_write_config8(MEMCTRL, 0x62, regs); + + /* SPD 27 Trp NB3DRAM_REG64[3:2] */ + GET_SPD(dimm, spds, regs, SPD_TRP); + printk_debug("\nTrp %d", spds); + spds >>= 2; + for (val = 2; val <= 5; val++) { + if (spds <= (val * t / 10)) { + val = val - 2; + break; + } + } + val <<= 2; + regs = pci_read_config8(MEMCTRL, 0x64); + regs &= ~0xc; + regs |= val; + pci_write_config8(MEMCTRL, 0x64, regs); + + /* SPD 29 Trcd NB3DRAM_REG64[7:6] */ + GET_SPD(dimm, spds, regs, SPD_TRCD); + printk_debug("\nTrcd %d", spds); + spds >>= 2; + for (val = 2; val <= 5; val++) { + if (spds <= (val * t / 10)) { + val = val - 2; + break; + } + } + val <<= 6; + regs = pci_read_config8(MEMCTRL, 0x64); + regs &= ~0xc0; + regs |= val; + pci_write_config8(MEMCTRL, 0x64, regs); + + /* SPD 30 Tras NB3DRAM_REG62[7:4] */ + GET_SPD(dimm, spds, regs, SPD_TRAS); + printk_debug("\nTras %d", spds); + for (val = 5; val <= 20; val++) { + if (spds <= (val * t / 10)) { + val = val - 5; + break; + } + } + val <<= 4; + regs = pci_read_config8(MEMCTRL, 0x62); + regs &= ~0xf0; + regs |= val; + pci_write_config8(MEMCTRL, 0x62, regs); + + /* SPD 42 SPD 40 Trfc NB3DRAM_REG61[5:0] */ + GET_SPD(dimm, spds, regs, SPD_TRFC); + printk_debug("\nTrfc %d", spds); + tmp = spds; + GET_SPD(dimm, spds, regs, SPD_EX_TRC_TRFC); + if (spds & 0x1) + tmp += 256; + if (spds & 0xe) + tmp++; + for (val = 8; val <= 71; val++) { + if (tmp <= (val * t / 10)) { + val = val - 8; + break; + } + } + regs = pci_read_config8(MEMCTRL, 0x61); + regs &= ~0x3f; + regs |= val; + pci_write_config8(MEMCTRL, 0x61, regs); + + /* SPD 28 Trrd NB3DRAM_REG63[7:6] */ + GET_SPD(dimm, spds, regs, SPD_TRRD); + for (val = 2; val <= 5; val++) { + if (spds <= (val * t / 10)) { + val = val - 2; + break; + } + } + val <<= 6; + printk_debug("\nTrrd val = 0x%x", val); + regs = pci_read_config8(MEMCTRL, 0x63); + regs &= ~0xc0; + regs |= val; + pci_write_config8(MEMCTRL, 0x63, regs); + + /* SPD 36 Twr NB3DRAM_REG61[7:6] */ + GET_SPD(dimm, spds, regs, SPD_TWR); + for (val = 2; val <= 5; val++) { + if (spds <= (val * t / 10)) { + val = val - 2; + break; + } + } + val <<= 6; + printk_debug("\nTwr val = 0x%x", val); + + regs = pci_read_config8(MEMCTRL, 0x61); + regs &= ~0xc0; + regs |= val; + pci_write_config8(MEMCTRL, 0x61, regs); + + /* SPD 37 Twtr NB3DRAM_REG63[1] */ + GET_SPD(dimm, spds, regs, SPD_TWTR); + spds >>= 2; + printk_debug("\nTwtr 0x%x", spds); + if (spds <= (t * 2 / 10)) + val = 0; + else + val = 1; + val <<= 1; + printk_debug("\nTwtr val = 0x%x", val); + + regs = pci_read_config8(MEMCTRL, 0x63); + regs &= ~0x2; + regs |= val; + pci_write_config8(MEMCTRL, 0x63, regs); + + /* SPD 38 Trtp NB3DRAM_REG63[3] */ + GET_SPD(dimm, spds, regs, SPD_TRTP); + spds >>= 2; + printk_debug("\nTrtp 0x%x", spds); + if (spds <= (t * 2 / 10)) + val = 0; + else + val = 1; + val <<= 3; + printk_debug("\nTrtp val = 0x%x", val); + + regs = pci_read_config8(MEMCTRL, 0x63); + regs &= ~0x8; + regs |= val; + pci_write_config8(MEMCTRL, 0x63, regs); + + /**********************************************/ + /* Set DRAM DRDY Setting */ + /**********************************************/ + /* Write slowest value to register */ + tmp = sizeof(Host_Reg_Val) / sizeof(Host_Reg_Val[0]); + for (val = 0; val < tmp; val += 2) + pci_write_config8(HOSTCTRL, Host_Reg_Val[val], Host_Reg_Val[val + 1]); + + /* F2_RX51[7]=0, disable DRDY timing */ + regs = pci_read_config8(HOSTCTRL, 0x51); + regs &= ~0x80; + pci_write_config8(HOSTCTRL, 0x51, regs); + + /**********************************************/ + /* Set DRAM BurstLength */ + /**********************************************/ + regs = pci_read_config8(MEMCTRL, 0x6c); + for (dimm = 0; dimm < DIMM_SOCKETS; dimm++) { + if (pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_REG_BASE + (dimm << 1)))) { + spds = get_spd_data(ctrl, dimm, 16); + if (!(spds & 0x8)) + break; + } + } + if (dimm == 2) + regs |= 0x8; + pci_write_config8(MEMCTRL, 0x6c, regs); + val = pci_read_config8(HOSTCTRL, 0x54); + val &= ~0x10; + if (dimm == 2) + val |= 0x10; + pci_write_config8(HOSTCTRL, 0x54, val); + + /**********************************************/ + /* Set DRAM Driving Setting */ + /**********************************************/ + /* DRAM Timing ODT */ + tmp = sizeof(Dram_Driving_ODT_CTRL) / sizeof(Dram_Driving_ODT_CTRL[0]); + for (val = 0; val < tmp; val += 2) + pci_write_config8(MEMCTRL, Dram_Driving_ODT_CTRL[val], + Dram_Driving_ODT_CTRL[val + 1]); + + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_NUM); + val = pci_read_config8(MEMCTRL, 0xd5); + val &= ~0xaa; + switch (regs) { + case 3: + case 2: + val |= 0xa0; + break; + default: + val |= 0x80; + } + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DIMM_NUM); + if (regs == 1) + val |= 0xa; + pci_write_config8(MEMCTRL, 0xd5, val); + + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DIMM_NUM); + val = pci_read_config8(MEMCTRL, 0xd6); + val &= ~0x2; + if (regs == 1) + val |= 0x2; + pci_write_config8(MEMCTRL, 0xd6, val); + + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_MAP); + tmp = sizeof(ODT_TBL) / sizeof(ODT_TBL[0]); + for (val = 0; val < tmp; val += 3) { + if (regs == ODT_TBL[val]) { + pci_write_config8(MEMCTRL, 0xd8, ODT_TBL[val + 1]); + /* Store DRAM & NB ODT setting in d0f4_Rxd8 */ + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_NB_ODT, ODT_TBL[val + 2]); + break; + } + } + + pci_write_config8(MEMCTRL, 0xd9, 0x0a); + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_NUM); + regs--; + regs = regs << 1; + pci_write_config8(MEMCTRL, 0xe0, DQS_DQ_TBL[regs++]); + pci_write_config8(MEMCTRL, 0xe2, DQS_DQ_TBL[regs]); + + /* DRAM Timing CS */ + pci_write_config8(MEMCTRL, 0xe4, 0x66); + + /* DRAM Timing MAA */ + val = 0; + for (dimm = 0; dimm < DIMM_SOCKETS; dimm++) { + if (pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_REG_BASE + (dimm << 1)))) { + spds = get_spd_data(ctrl, dimm, SPD_PRI_WIDTH); + spds = 64 / spds; + if (pci_read_config8 + (PCI_DEV(0, 0, 4), (SCRATCH_REG_BASE + (dimm << 1) + 1))) + spds = spds << 1; + val += spds; + } + } + printk_debug("\nchip #%d", val); + if (val > 18) + regs = 0xdb; + else + regs = 0x86; + pci_write_config8(MEMCTRL, 0xe8, regs); + + /* DRAM Timing MAB */ + pci_write_config8(MEMCTRL, 0xe9, 0x0); + + /* DRAM Timing DCLK VT8454C always 0x66 */ + pci_write_config8(MEMCTRL, 0xe6, 0xaa); + + /**********************************************/ + /* Set DRAM Duty Control */ + /**********************************************/ + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_NUM); + switch (regs) { + case 1: + case 2: /* 1~2 rank */ + val = 0; + break; + case 3: + case 4: /* 3~4 rank */ + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_FREQ); + if (regs == DDRII_533) + val = 4; + else /* DDRII-400 */ + val = 0; + break; + } + regs = 0xec; + for (t = 0; t < 4; t++) { + pci_write_config8(MEMCTRL, regs, Duty_Control_DDR2[val]); + regs++; + val++; + } + + /**********************************************/ + /* Set DRAM Clock Control */ + /**********************************************/ + /* Write Data Phase */ + val = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_FREQ); + regs = pci_read_config8(MEMCTRL, 0x75); + regs &= 0xf0; + switch (val) { + case DDRII_533: + pci_write_config8(MEMCTRL, 0x74, 0x07); + regs |= 0x7; + break; + case DDRII_400: + default: + pci_write_config8(MEMCTRL, 0x74, 0x05); + regs |= 0x5; + break; + } + pci_write_config8(MEMCTRL, 0x75, regs); + pci_write_config8(MEMCTRL, 0x76, 0x80); + + /* Clock Phase Control for FeedBack Mode */ + regs = pci_read_config8(MEMCTRL, 0x90); +// regs |= 0x80; + pci_write_config8(MEMCTRL, 0x90, regs); + + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_FREQ); + switch (regs) { + case DDRII_533: + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_NUM); + if (regs == 1) + val = 0; + else + val = 3; + break; + case DDRII_400: + default: + val = 6; + break; + } + regs = pci_read_config8(MEMCTRL, 0x91); + regs &= ~0xc0; + regs |= 0x80; + pci_write_config8(MEMCTRL, 0x91, regs); + regs = 0x91; + for (t = 0; t < 3; t++) { + dimm = pci_read_config8(MEMCTRL, regs); + dimm &= ~0x7; + dimm |= ChA_Clk_Phase_DDR2_Table[val]; + pci_write_config8(MEMCTRL, regs, dimm); + regs++; + val++; + } + + pci_write_config8(MEMCTRL, 0x97, 0x12); + pci_write_config8(MEMCTRL, 0x98, 0x33); + + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_0); + val = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_2); + if (regs && val) + pci_write_config8(MEMCTRL, 0x9d, 0x00); + else + pci_write_config8(MEMCTRL, 0x9d, 0x0f); + + tmp = sizeof(DQ_DQS_Table) / sizeof(DQ_DQS_Table[0]); + for (val = 0; val < tmp; val += 2) + pci_write_config8(MEMCTRL, DQ_DQS_Table[val], DQ_DQS_Table[val + 1]); + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_FREQ); + if (regs == DDRII_533) + pci_write_config8(MEMCTRL, 0x7b, 0xa0); + else + pci_write_config8(MEMCTRL, 0x7b, 0x10); + + /***************************************************/ + /* Set necessary register before DRAM initialize */ + /***************************************************/ + tmp = sizeof(Mem_Reg_Init) / sizeof(Mem_Reg_Init[0]); + for (val = 0; val < tmp; val += 3) { + regs = pci_read_config8(MEMCTRL, Mem_Reg_Init[val]); + regs &= Mem_Reg_Init[val + 1]; + regs |= Mem_Reg_Init[val + 2]; + pci_write_config8(MEMCTRL, Mem_Reg_Init[val], regs); + } + regs = pci_read_config8(HOSTCTRL, 0x51); + regs &= 0xbf; // Clear bit 6 Disable Read Around Write + pci_write_config8(HOSTCTRL, 0x51, regs); + + regs = pci_read_config8(HOSTCTRL, 0x54); + t = regs >> 5; + val = pci_read_config8(HOSTCTRL, 0x57); + dimm = val >> 5; + if (t == dimm) + t = 0x0; + else + t = 0x1; + regs &= ~0x1; + regs |= t; + val &= ~0x1; + val |= t; + pci_write_config8(HOSTCTRL, 0x57, val); + + regs = pci_read_config8(HOSTCTRL, 0x51); + regs |= t; + pci_write_config8(HOSTCTRL, 0x51, regs); + + regs = pci_read_config8(MEMCTRL, 0x90); + regs &= 0x7; + val = 0; + if (regs < 0x2) + val = 0x80; + regs = pci_read_config8(MEMCTRL, 0x76); + regs &= 0x80; + regs |= val; + pci_write_config8(MEMCTRL, 0x76, regs); + + regs = pci_read_config8(MEMCTRL, 0x6f); + regs |= 0x10; + pci_write_config8(MEMCTRL, 0x6f, regs); + + /***************************************************/ + /* Find suitable DQS value for ChA and ChB */ + /***************************************************/ + // Set DQS output delay for Channel A + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_FREQ); + val = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_NUM); + switch (regs) { + case DDRII_533: + if (val < 2) + val = 0; + else + val = 2; + break; + case DDRII_400: + default: + if (val < 2) + val = 4; + else + val = 6; + break; + } + for (t = 0; t < 2; t++) + pci_write_config8(MEMCTRL, (0x70 + t), DQSOChA_DDR2_Driving_Table[val + t]); + // Set DQS output delay for Channel B + pci_write_config8(MEMCTRL, 0x72, 0x0); + + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_0); + val = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_2); + if (regs && val) + pci_write_config8(MEMCTRL, 0x73, 0xfd); + else + pci_write_config8(MEMCTRL, 0x73, 0x01); +} + +static void sdram_set_registers(const struct mem_controller *ctrl) +{ + c7_cpu_setup(ctrl); + ddr_detect(ctrl); + sdram_set_safe_values(ctrl); +} + +static void step_20_21(const struct mem_controller *ctrl) +{ + u8 val; + + // Step 20 + udelay(200); + + val = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_NB_ODT); + if (val & DDR2_ODT_150ohm) + read32(0x102200); + else + read32(0x102020); + + /* Step 21. Normal operation */ + print_spew("RAM Enable 5: Normal operation\n"); + do_ram_command(ctrl, RAM_COMMAND_NORMAL); + udelay(3); +} + +static void step_2_19(const struct mem_controller *ctrl) +{ + u32 i; + u8 val; + + // Step 2 + val = pci_read_config8(MEMCTRL, 0x69); + val &= ~0x03; + pci_write_config8(MEMCTRL, 0x69, val); + + /* Step 3 Apply NOP. */ + print_spew("RAM Enable 1: Apply NOP\n"); + do_ram_command(ctrl, RAM_COMMAND_NOP); + + udelay(15); + + // Step 4 + print_spew("SEND: "); + read32(0); + print_spew("OK\n"); + + // Step 5 + udelay(400); + + /* 6. Precharge all. Wait tRP. */ + print_spew("RAM Enable 2: Precharge all\n"); + do_ram_command(ctrl, RAM_COMMAND_PRECHARGE); + + // Step 7 + print_spew("SEND: "); + read32(0); + print_spew("OK\n"); + + /* Step 8. Mode register set. */ + print_spew("RAM Enable 4: Mode register set\n"); + do_ram_command(ctrl, RAM_COMMAND_MRS); //enable dll + + // Step 9 + print_spew("SEND: "); + + val = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_NB_ODT); + if (val & DDR2_ODT_150ohm) + read32(0x102200); //DDR2_ODT_150ohm + else + read32(0x102020); + print_spew("OK\n"); + + // Step 10 + print_spew("SEND: "); + read32(0x800); + print_spew("OK\n"); + + /* Step 11. Precharge all. Wait tRP. */ + print_spew("RAM Enable 2: Precharge all\n"); + do_ram_command(ctrl, RAM_COMMAND_PRECHARGE); + + // Step 12 + print_spew("SEND: "); + read32(0x0); + print_spew("OK\n"); + + /* Step 13. Perform 8 refresh cycles. Wait tRC each time. */ + print_spew("RAM Enable 3: CBR\n"); + do_ram_command(ctrl, RAM_COMMAND_CBR); + + /* JEDEC says only twice, do 8 times for posterity */ + // Step 16: Repeat Step 14 and 15 another 7 times + for (i = 0; i < 8; i++) { + // Step 14 + read32(0); + print_spew("."); + + // Step 15 + udelay(100); + } + + /* Step 17. Mode register set. Wait 200us. */ + print_spew("\nRAM Enable 4: Mode register set\n"); + + //safe value for now, BL=8, WR=4, CAS=4 + do_ram_command(ctrl, RAM_COMMAND_MRS); + udelay(200); + + /* Use Single Chanel temporarily */ + val = pci_read_config8(MEMCTRL, 0x6c); + if (val & 0x8) { /* Burst Length = 8 */ + val = pci_read_config8(MEMCTRL, 0x62); + val &= 0x7; + i = DDR2_MRS_table[4 + val]; + } else { + val = pci_read_config8(MEMCTRL, 0x62); + val &= 0x7; + i = DDR2_MRS_table[val]; + } + + // Step 18 + val = pci_read_config8(MEMCTRL, 0x61); + val = val >> 6; + i |= DDR2_Twr_table[val]; + read32(i); + + printk_debug("MRS = %08x\n", i); + + udelay(15); + + // Step 19 + val = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_NB_ODT); + if (val & DDR2_ODT_150ohm) + read32(0x103e00); //EMRS OCD Default + else + read32(0x103c20); +} + +static void sdram_set_vr(const struct mem_controller *ctrl, u8 num) +{ + u8 reg, val; + val = 0x54 + (num >> 1); + reg = pci_read_config8(MEMCTRL, val); + reg &= (0xf << (4 * (num & 0x1))); + reg |= (((0x8 | num) << 4) >> (4 * (num & 0x1))); + pci_write_config8(MEMCTRL, val, reg); +} +static void sdram_ending_addr(const struct mem_controller *ctrl, u8 num) +{ + u8 reg, val; + /* Set Ending Address */ + val = 0x40 + num; + reg = pci_read_config8(MEMCTRL, val); + reg += 0x10; + pci_write_config8(MEMCTRL, val, reg); + /* Set Beginning Address */ + val = 0x48 + num; + pci_write_config8(MEMCTRL, val, 0x0); +} + +static void sdram_clear_vr_addr(const struct mem_controller *ctrl, u8 num) +{ + u8 reg, val; + val = 0x54 + (num >> 1); + reg = pci_read_config8(MEMCTRL, val); + reg = ~(0x80 >> (4 * (num & 0x1))); + pci_write_config8(MEMCTRL, val, reg); + val = 0x40 + num; + reg = pci_read_config8(MEMCTRL, val); + reg -= 0x10; + pci_write_config8(MEMCTRL, val, reg); + val = 0x48 + num; + pci_write_config8(MEMCTRL, val, 0x0); +} + +/* Perform sizing DRAM by dynamic method */ +static void sdram_calc_size(const struct mem_controller *ctrl, u8 num) +{ + u8 ca, ra, ba, reg; + ba = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_FLAGS); + if (ba == 8) { + write8(0, 0x0d); + ra = read8(0); + write8((1 << SDRAM1X_RA_12_8bk), 0x0c); + ra = read8(0); + + write8(0, 0x0a); + ca = read8(0); + write8((1 << SDRAM1X_CA_09_8bk), 0x0c); + ca = read8(0); + + write8(0, 0x03); + ba = read8(0); + write8((1 << SDRAM1X_BA2_8bk), 0x02); + ba = read8(0); + write8((1 << SDRAM1X_BA1_8bk), 0x01); + ba = read8(0); + } else { + write8(0, 0x0f); + ra = read8(0); + write8((1 << SDRAM1X_RA_14), 0x0e); + ra = read8(0); + write8((1 << SDRAM1X_RA_13), 0x0d); + ra = read8(0); + write8((1 << SDRAM1X_RA_12), 0x0c); + ra = read8(0); + + write8(0, 0x0c); + ca = read8(0); + write8((1 << SDRAM1X_CA_12), 0x0b); + ca = read8(0); + write8((1 << SDRAM1X_CA_11), 0x0a); + ca = read8(0); + write8((1 << SDRAM1X_CA_09), 0x09); + ca = read8(0); + + write8(0, 0x02); + ba = read8(0); + write8((1 << SDRAM1X_BA1), 0x01); + ba = read8(0); + } + + if (ra < 10 || ra > 15) + die("bad RA"); + if (ca < 8 || ca > 12) + die("bad CA"); + if (ba < 1 || ba > 3) + die("bad BA"); + + /* Calculate MA type save to scratch register */ + reg = 0; + + switch (ra) { + case 12: + reg |= MA_12_Row; + break; + case 13: + reg |= MA_13_Row; + break; + case 14: + reg |= MA_14_Row; + break; + default: + reg |= MA_15_Row; + } + + switch (ca) { + case 9: + reg |= MA_9_Column; + break; + case 10: + reg |= MA_10_Column; + break; + case 11: + reg |= MA_11_Column; + break; + default: + reg |= MA_12_Column; + } + + switch (ba) { + case 3: + reg |= MA_8_Bank; + break; + default: + reg |= MA_4_Bank; + } + + pci_write_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK0_MA_REG + num), reg); + + if (ra >= 13) + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_256M_BIT, 1); + + /* Calculate rank size save to scratch register */ + ra = ra + ca + ba + 3 - 26; /* 1 unit = 64M */ + ra = 1 << ra; + pci_write_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK0_SIZE_REG + num), ra); +} + +static void sdram_enable(const struct mem_controller *ctrl) +{ + u8 reg8; + u8 val, i; + device_t dev; + u8 dl, dh; + u32 quot; + + /* Init Present Bank */ + val = sizeof(Init_Rank_Reg_Table) / sizeof(Init_Rank_Reg_Table[0]); + for (i = 0; i < val; i++) + pci_write_config8(MEMCTRL, Init_Rank_Reg_Table[i], 0x0); + + /* Init other banks */ + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + sdram_set_vr(ctrl, i); + sdram_ending_addr(ctrl, i); + step_2_19(ctrl); + step_20_21(ctrl); + sdram_clear_vr_addr(ctrl, i); + } + } + +#ifdef MEM_WIDTH_32BIT_MODE + /****************************************************************/ + /* Set Dram 32bit Mode */ + /****************************************************************/ + reg8 = pci_read_config8(MEMCTRL, 0x6c); + reg8 |= 0x20; + pci_write_config(MEMCTRL, 0x6c, reg8); +#endif + + /****************************************************************/ + /* Find the DQSI Low/High bound and save it to Scratch register */ + /****************************************************************/ + for (dl = 0; dl < 0x3f; dl += 2) { + reg8 = dl & 0x3f; + reg8 |= 0x80; /* Set Manual Mode */ + pci_write_config8(MEMCTRL, 0x77, reg8); + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + sdram_set_vr(ctrl, i); + sdram_ending_addr(ctrl, i); + write32(0, 0x55555555); + write32(4, 0x55555555); + udelay(15); + if (read32(0) != 0x55555555) + break; + if (read32(4) != 0x55555555) + break; + write32(0, 0xaaaaaaaa); + write32(4, 0xaaaaaaaa); + udelay(15); + if (read32(0) != 0xaaaaaaaa) + break; + if (read32(4) != 0xaaaaaaaa) + break; + sdram_clear_vr_addr(ctrl, i); + } + } + if (i == 4) + break; + else + sdram_clear_vr_addr(ctrl, i); + } + printk_debug("\nDQSI Low %08x", dl); + for (dh = dl; dh < 0x3f; dh += 2) { + reg8 = dh & 0x3f; + reg8 |= 0x80; /* Set Manual Mode */ + pci_write_config8(MEMCTRL, 0x77, reg8); + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + sdram_set_vr(ctrl, i); + sdram_ending_addr(ctrl, i); + + write32(0, 0x55555555); + write32(4, 0x55555555); + udelay(15); + if (read32(0) != 0x55555555) + break; + if (read32(4) != 0x55555555) + break; + write32(0, 0xaaaaaaaa); + write32(4, 0xaaaaaaaa); + udelay(15); + if (read32(0) != 0xaaaaaaaa) + break; + if (read32(4) != 0xaaaaaaaa) + break; + sdram_clear_vr_addr(ctrl, i); + } + } + if (i != 4) { + sdram_clear_vr_addr(ctrl, i); + break; + } + } + printk_debug("\nDQSI High %02x", dh); + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_CHA_DQSI_LOW_REG, dl); + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_CHA_DQSI_HIGH_REG, dh); + reg8 = pci_read_config8(MEMCTRL, 0X90) & 0X7; + val = DQSI_Rate_Table[reg8]; + quot = dh - dl; + quot = quot * val; + quot >>= 4; + val = quot + dl; + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_ChA_DQSI_REG, val); + reg8 = val & 0x3f; + reg8 |= 0x80; + pci_write_config8(MEMCTRL, 0x77, reg8); + + /****************************************************************/ + /* Find out the lowest Bank Interleave and Set Register */ + /****************************************************************/ +#if 0 + //TODO + reg8 = pci_read_config8(MEMCTRL, 0x69); + reg8 &= ~0xc0; + reg8 |= 0x80; //8 banks + pci_write_config8(MEMCTRL, 0x69, reg8); +#endif + dl = 2; + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + reg8 = get_spd_data(ctrl, (i >> 1), 17); + sdram_set_vr(ctrl, i); + sdram_ending_addr(ctrl, i); + if (reg8 == 4) { + write8(0, 0x02); + val = read8(0); + write8((1 << SDRAM1X_BA1), 0x01); + val = read8(0); + } else { + write8(0, 0x03); + val = read8(0); + write8((1 << SDRAM1X_BA2_8bk), 0x02); + val = read8(0); + write8((1 << SDRAM1X_BA1_8bk), 0x01); + val = read8(0); + } + if (val < dl) + dl = val; + sdram_clear_vr_addr(ctrl, i); + } + } + dl <<= 6; + reg8 = pci_read_config8(MEMCTRL, 0x69); + reg8 &= ~0xc0; + reg8 |= dl; + pci_write_config8(MEMCTRL, 0x69, reg8); + + /****************************************************************/ + /* DRAM Sizing and Fill MA type */ + /****************************************************************/ + for (i = 0; i < 4; i++) { + val = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (val) { + reg8 = get_spd_data(ctrl, (i >> 1), 17); + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_FLAGS, reg8); + if (reg8 == 4) { + /* Use MA Type 3 for DRAM sizing */ + reg8 = pci_read_config8(MEMCTRL, 0x50); + reg8 &= 0x11; + reg8 |= 0x66; + pci_write_config8(MEMCTRL, 0x50, reg8); + pci_write_config8(MEMCTRL, 0x51, reg8); + } else { + /* Use MA Type 5 for DRAM sizing */ + reg8 = pci_read_config8(MEMCTRL, 0x50); + reg8 &= 0x11; + reg8 |= 0xaa; + pci_write_config8(MEMCTRL, 0x50, reg8); + pci_write_config8(MEMCTRL, 0x51, reg8); + reg8 = pci_read_config8(MEMCTRL, 0x53); + reg8 &= 0x0f; + reg8 |= 0x90; + pci_write_config8(MEMCTRL, 0x53, reg8); + } + sdram_set_vr(ctrl, i); + val = 0x40 + i; + reg8 = pci_read_config8(MEMCTRL, val); + /* max size 3G for new MA table */ + reg8 += 0x30; + pci_write_config8(MEMCTRL, val, reg8); + /* Set Beginning Address */ + val = 0x48 + i; + pci_write_config8(MEMCTRL, val, 0x0); + + sdram_calc_size(ctrl, i); + + /* Clear */ + val = 0x54 + (i >> 1); + reg8 = pci_read_config8(MEMCTRL, val); + reg8 = ~(0x80 >> (4 * (i & 0x1))); + pci_write_config8(MEMCTRL, val, reg8); + val = 0x40 + i; + reg8 = pci_read_config8(MEMCTRL, val); + reg8 -= 0x30; + pci_write_config8(MEMCTRL, val, reg8); + val = 0x48 + i; + pci_write_config8(MEMCTRL, val, 0x0); + + } + } + /* Clear MA Type */ + reg8 = pci_read_config8(MEMCTRL, 0x50); + reg8 &= 0x11; + pci_write_config8(MEMCTRL, 0x50, reg8); + pci_write_config8(MEMCTRL, 0x51, reg8); + reg8 = pci_read_config8(MEMCTRL, 0x6b); + reg8 &= ~0x08; + pci_write_config8(MEMCTRL, 0x6b, reg8); + + /****************************************************************/ + /* DRAM re-initialize for burst length */ + /****************************************************************/ + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + sdram_set_vr(ctrl, i); + sdram_ending_addr(ctrl, i); + step_2_19(ctrl); + step_20_21(ctrl); + sdram_clear_vr_addr(ctrl, i); + } + } + + /****************************************************************/ + /* Set the MA Type */ + /****************************************************************/ + reg8 = pci_read_config8(MEMCTRL, 0x50); + reg8 &= 0x11; + pci_write_config8(MEMCTRL, 0x50, reg8); + + reg8 = pci_read_config8(MEMCTRL, 0x51); + reg8 &= 0x11; + pci_write_config8(MEMCTRL, 0x51, reg8); + + reg8 = pci_read_config8(MEMCTRL, 0x6b); + reg8 &= ~0x08; + pci_write_config8(MEMCTRL, 0x6b, reg8); + + for (i = 0; i < 4; i += 2) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK0_MA_REG + i)); + reg8 &= (MA_Bank + MA_Column); + val = pci_read_config8(MEMCTRL, 0x50); + if (i == 0) { + reg8 <<= 4; + val &= 0x1f; + } else + val &= 0xf1; + val |= reg8; + pci_write_config8(MEMCTRL, 0x50, val); + } + } + + /****************************************************************/ + /* Set Start and Ending Address */ + /****************************************************************/ + dl = 0; /* Begin Address */ + dh = 0; /* Ending Address */ + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK0_SIZE_REG + i)); + if (reg8 == 0) + continue; + dh += reg8; + pci_write_config8(MEMCTRL, (0x40 + i), dh); + pci_write_config8(MEMCTRL, (0x48 + i), dl); + dl = dh; + } + } + dh <<= 2; + // F7_Rx57 Ending address mirror register + pci_write_config8(PCI_DEV(0, 0, 7), 0x57, dh); + dev = pci_locate_device(PCI_ID(0x1106, 0x324e), 0); + pci_write_config8(dev, 0x57, dh); + // LOW TOP Address + pci_write_config8(MEMCTRL, 0x88, dh); + pci_write_config8(MEMCTRL, 0x85, dh); + // also program vlink mirror + pci_write_config8(PCI_DEV(0, 0, 7), 0xe5, dh); + + /****************************************************************/ + /* Set Physical to Virtual Rank mapping */ + /****************************************************************/ + pci_write_config32(MEMCTRL, 0x54, 0x0); + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + reg8 = pci_read_config8(MEMCTRL, (0x54 + (i >> 1))); + if (i & 0x1) { /* Odd Rank */ + reg8 &= 0xf0; + reg8 |= (0x8 | i); + } else { /* Even Rank */ + + reg8 &= 0x0f; + reg8 |= ((0x8 | i) << 4); + } + pci_write_config8(MEMCTRL, (0x54 + (i >> 1)), reg8); + } + } + + /****************************************************************/ + /* Set DRAM Refresh Counter */ + /****************************************************************/ + val = pci_read_config8(MEMCTRL, 0X90) & 0X7; + val <<= 1; + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_256M_BIT); + if (reg8) + val++; + pci_write_config8(MEMCTRL, 0x6a, REFC_Table[val]); + + /****************************************************************/ + /* Chipset Performance UP and other setting after DRAM Sizing */ + /****************************************************************/ + /* Dram Registers */ + val = sizeof(Dram_Table) / sizeof(Dram_Table[0]); + for (i = 0; i < val; i += 3) { + reg8 = pci_read_config8(MEMCTRL, Dram_Table[i]); + reg8 &= Dram_Table[i + 1]; + reg8 |= Dram_Table[i + 2]; + pci_write_config8(MEMCTRL, Dram_Table[i], reg8); + } + + /* Host Registers */ + val = sizeof(Host_Table) / sizeof(Host_Table[0]); + for (i = 0; i < val; i += 3) { + reg8 = pci_read_config8(HOSTCTRL, Host_Table[i]); + reg8 &= Host_Table[i + 1]; + reg8 |= Host_Table[i + 2]; + pci_write_config8(HOSTCTRL, Host_Table[i], reg8); + } + + /* PM Registers */ +#ifdef SETUP_PM_REGISTERS + val = sizeof(PM_Table) / sizeof(PM_Table[0]); + for (i = 0; i < val; i += 3) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), PM_Table[i]); + reg8 &= PM_Table[i + 1]; + reg8 |= PM_Table[i + 2]; + pci_write_config8(PCI_DEV(0, 0, 4), PM_Table[i], reg8); + } +#endif + pci_write_config8(HOSTCTRL, 0x5d, 0xb2); + + /****************************************************************/ + /* UMA registers for N-series projects */ + /****************************************************************/ + + /* Manual setting frame buffer bank */ + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) + val = i; + } + pci_write_config8(MEMCTRL, 0xb0, val); + reg8 = 0x40; // Frame buffer size 64M + reg8 |= 0x80; // VGA Enable + reg8 |= 0x0a; // A[31:28] = 1010b + pci_write_config8(MEMCTRL, 0xa1, reg8); + +#ifdef ECC + // Clear Ecc + outl(0x80000180, 0xcf8); + outb(0xff, 0xcfc); + // Enable Ecc + outl(0x80000188, 0xcf8); + outb(0xcf, 0xcfc); + + reg8 = pci_read_config8(PCI_DEV(0, 0, 0), 0xa5); + reg8 |= 0x10; + pci_write_config8(PCI_DEV(0, 0, 0), 0xa5, reg8); + + reg8 = pci_read_config8(PCI_DEV(0, 0, 0), 0x91); + reg8 |= 0x20; + pci_write_config8(PCI_DEV(0, 0, 0), 0x91, reg8); +#endif + + static const struct regmask { + u8 reg; + u8 mask; + u8 val; + } b0d1f0[] = { + { 0x40, 0x00, 0x8b}, + { 0x41, 0x80, 0x43}, + { 0x42, 0x00, 0x62}, + { 0x43, 0x00, 0x44}, + { 0x44, 0x00, 0x34}, + { 0x45, 0x00, 0x72} + }, b0d0f3[] = { + { 0x53, 0xf0, 0x0f}, + { 0x60, 0x00, 0x03}, + { 0x65, 0x00, 0xd9}, + { 0x66, 0x00, 0x80}, + { 0x67, 0x00, 0x00}, + { 0x68, 0x00, 0x01}, + { 0x69, 0xe0, 0x03}, + { 0x6b, 0x00, 0x10}, + { 0x6c, 0xc1, 0x08}, + { 0x6e, 0x00, 0x89}, + { 0x6f, 0x00, 0x51}, + { 0x75, ~0x40, 0x40}, + { 0x76, 0x8f, 0x00}, + { 0x7b, 0x00, 0xa0}, + { 0x86, 0x01, 0x24}, + { 0x86, 0x04, 0x29}, + { 0x8c, 0x00, 0x00}, + { 0x8d, 0x00, 0x00}, + { 0x95, ~0x40, 0x00}, + { 0xa2, 0x00, 0x44}, + { 0xb1, 0x00, 0xaa} + }, b0d0f0[] = { + { 0x4d, 0x00, 0x24}, + { 0x4f, 0x00, 0x01}, + { 0xbc, 0x00, 0x21}, + { 0xbe, 0x00, 0x00}, + { 0xbf, 0x7f, 0x80} + }, b0d17f0[] = { + { 0x40, ~0x01, 0x01}, // enable timer/counter shadow registers + { 0x67, ~0x03, 0x01}, + { 0x5b, ~0x01, 0x00}, + { 0x8d, ~0x02, 0x02}, + { 0x97, ~0x80, 0x00}, + { 0xd2, ~0x18, 0x00}, + { 0xe2, ~0x36, 0x06}, + { 0xe4, ~0x80, 0x00}, + { 0xe5, 0x00, 0x40}, + { 0xe6, 0x00, 0x20}, + { 0xe7, ~0xd0, 0xc0}, + { 0xec, ~0x08, 0x00} + }, b0d17f7[] = { + { 0x4e, ~0x80, 0x80}, + { 0x4f, ~(1 << 6), 1 << 6 }, /* PG_CX700: 14.1.1 enable P2P Bridge Header for External PCI Bus */ + { 0x74, ~0x00, 0x04}, /* PG_CX700: 14.1.2 APIC FSB directly up to snmic, not on pci */ + { 0x7c, ~0x00, 0x02}, /* PG_CX700: 14.1.1 APIC FSB directly up to snmic, not on pci */ + { 0xe6, 0x0, 0x04} // MSI post + }, b0d19f0[] = { /* P2PE */ + { 0x42, ~0x08, 0x08}, // Disable HD Audio, + { 0x40, ~0xc0, 0x80} // 14.1.3.1.1 of the PG: extended cfg mode for pcie. enable capability, but don't activate + }, b0d0f2[] = { + { 0x50, ~0x40, 0x88}, + { 0x51, 0x80, 0x7b}, + { 0x52, 0x90, 0x6f}, + { 0x53, 0x00, 0x88}, + { 0x54, 0xe4, 0x16}, + { 0x55, 0xf2, 0x04}, + { 0x56, 0x0f, 0x00}, + { 0x57, ~0x04, 0x00}, + { 0x5d, 0x00, 0xb2}, + { 0x5e, 0x00, 0x88}, + { 0x5f, 0x00, 0xc7}, + { 0x5c, 0x00, 0x01} + }; + + REGISTERPRESET(0, 0, 0, b0d0f0); + REGISTERPRESET(0, 0, 2, b0d0f2); + REGISTERPRESET(0, 0, 3, b0d0f3); + REGISTERPRESET(0, 1, 0, b0d1f0); + REGISTERPRESET(0, 17, 0, b0d17f0); + REGISTERPRESET(0, 17, 7, b0d17f7); + REGISTERPRESET(0, 19, 0, b0d19f0); +} diff --git a/src/northbridge/via/cx700/raminit.h b/src/northbridge/via/cx700/raminit.h new file mode 100644 index 0000000000..482902e59b --- /dev/null +++ b/src/northbridge/via/cx700/raminit.h @@ -0,0 +1,28 @@ +/* + * 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 + */ + +#ifndef RAMINIT_H +#define RAMINIT_H + +#define DIMM_SOCKETS 2 + +struct mem_controller { + u16 channel0[DIMM_SOCKETS]; +}; +#endif diff --git a/src/northbridge/via/cx700/vgabios.c b/src/northbridge/via/cx700/vgabios.c new file mode 100644 index 0000000000..e7ba33ab3b --- /dev/null +++ b/src/northbridge/via/cx700/vgabios.c @@ -0,0 +1,783 @@ +/* + * This file is part of the coreboot project. + * + * (C) 2007-2009 coresystems GmbH + * (See further copyright notices below) + * + * NOTE: This file is supposed to go away once the generic vm86 handler + * in util/x86emu is able to handle intXX hooks like yabel does. + * + * 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/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#undef __KERNEL__ +#include <arch/io.h> +#include <string.h> + +void write_protect_vgabios(void); + +/* vgabios.c. Derived from: */ + +/*------------------------------------------------------------ -*- C -*- + * 2 Kernel Monte a.k.a. Linux loading Linux on x86 + * + * Erik Arjan Hendriks <hendriks@lanl.gov> + * + * This version is a derivative of the original two kernel monte + * which is (C) 2000 Scyld. + * + * Copyright (C) 2000 Scyld Computing Corporation + * + * Portions related to the alpha architecture are: + * + * Copyright(C) 2001 University of California. LA-CC Number 01-67. + * This software has been authored by an employee or employees of the + * University of California, operator of the Los Alamos National + * Laboratory under Contract No. W-7405-ENG-36 with the U.S. + * Department of Energy. The U.S. Government has rights to use, + * reproduce, and distribute this software. If the software is + * modified to produce derivative works, such modified software should + * be clearly marked, so as not to confuse it with the version + * available from LANL. + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by + * reference to http://www.gnu.org/licenses/gpl.html. + * + * This software is provided by the author(s) "as is" and any express + * or implied warranties, including, but not limited to, the implied + * warranties of merchantability and fitness for a particular purpose + * are disclaimed. In no event shall the author(s) be liable for any + * direct, indirect, incidental, special, exemplary, or consequential + * damages (including, but not limited to, procurement of substitute + * goods or services; loss of use, data, or profits; or business + * interruption) however caused and on any theory of liability, + * whether in contract, strict liability, or tort (including + * negligence or otherwise) arising in any way out of the use of this + * software, even if advised of the possibility of such damage. + * + *--------------------------------------------------------------------*/ + +/* Modified to be a self sufficient plug in so that it can be used + without reliance on other parts of core Linuxbios + (C) 2005 Nick.Barker9@btinternet.com + + Used initially for epia-m where there are problems getting the bios + emulator to successfully run this bios. +*/ + +/* Declare a temporary global descriptor table - necessary because the + Core part of the bios no longer sets up any 16 bit segments */ +__asm__( + /* pointer to original gdt */ + "gdtarg: \n" + " .word gdt_limit \n" + " .long gdt \n" + /* compute the table limit */ + "__mygdt_limit = __mygdt_end - __mygdt - 1 \n" + "__mygdtaddr: \n" + " .word __mygdt_limit \n" + " .long __mygdt \n" + "__mygdt: \n" + /* selgdt 0, unused */ + " .word 0x0000, 0x0000 \n" + " .byte 0x00, 0x00, 0x00, 0x00 \n" + /* selgdt 8, unused */ + " .word 0x0000, 0x0000 \n" + " .byte 0x00, 0x00, 0x00, 0x00 \n" + /* selgdt 0x10, flat code segment */ + " .word 0xffff, 0x0000 \n" + " .byte 0x00, 0x9b, 0xcf, 0x00 \n" + /* selgdt 0x18, flat data segment */ + " .word 0xffff, 0x0000 \n" + " .byte 0x00, 0x93, 0xcf, 0x00 \n" + /* selgdt 0x20, unused */ + " .word 0x0000, 0x0000 \n" + " .byte 0x00, 0x00, 0x00, 0x00 \n" + /* selgdt 0x28 16-bit 64k code at 0x00000000 */ + " .word 0xffff, 0x0000 \n" + " .byte 0, 0x9a, 0, 0 \n" + /* selgdt 0x30 16-bit 64k data at 0x00000000 */ + " .word 0xffff, 0x0000 \n" + " .byte 0, 0x92, 0, 0 \n" + "__mygdt_end: \n"); + +/* Declare a pointer to where our idt is going to be i.e. at mem zero */ +__asm__("__myidt: \n" + /* 16-bit limit */ + " .word 1023 \n" + /* 24-bit base */ + " .long 0 \n" " .word 0 \n"); + +/* The address arguments to this function are PHYSICAL ADDRESSES */ +static void real_mode_switch_call_vga(unsigned long devfn) +{ + __asm__ __volatile__( + // paranoia -- does ecx get saved? not sure. This is + // the easiest safe thing to do. + " pushal \n" + /* save the stack */ + " mov %esp, __stack \n" + " jmp 1f \n" + "__stack: .long 0 \n" "1:\n" + /* get devfn into %ecx */ + " movl %esp, %ebp \n" + " movl 8(%ebp), %ecx \n" + /* load 'our' gdt */ + " lgdt %cs:__mygdtaddr \n" + /* This configures CS properly for real mode. */ + " ljmp $0x28, $__rms_16bit\n" + "__rms_16bit: \n" + " .code16 \n" + /* 16 bit code from here on... */ + /* Load the segment registers w/ properly configured segment + * descriptors. They will retain these configurations (limits, + * writability, etc.) once protected mode is turned off. */ + " mov $0x30, %ax \n" + " mov %ax, %ds \n" + " mov %ax, %es \n" + " mov %ax, %fs \n" + " mov %ax, %gs \n" + " mov %ax, %ss \n" + /* Turn off protection (bit 0 in CR0) */ + " movl %cr0, %eax \n" + " andl $0xFFFFFFFE, %eax \n" + " movl %eax, %cr0 \n" + /* Now really going into real mode */ + " ljmp $0, $__rms_real\n" + "__rms_real: \n" + /* put the stack at the end of page zero. + * that way we can easily share it between real and protected, + * since the 16-bit ESP at segment 0 will work for any case. + */ + /* Setup a stack */ + " mov $0x0, %ax \n" + " mov %ax, %ss \n" + " movl $0x1000, %eax \n" + " movl %eax, %esp \n" + /* Load our 16 it idt */ + " xor %ax, %ax \n" + " mov %ax, %ds \n" + " lidt __myidt \n" + /* Dump zeros in the other segregs */ + " mov %ax, %es \n" + " mov %ax, %fs \n" + " mov %ax, %gs \n" + " mov $0x40, %ax \n" + " mov %ax, %ds \n" + " mov %cx, %ax \n" + /* run VGA BIOS at 0xc000:0003 */ + " lcall $0xc000, $0x0003\n" + /* if we got here, just about done. + * Need to get back to protected mode */ + " movl %cr0, %eax \n" " orl $0x0000001, %eax\n" /* PE = 1 */ + " movl %eax, %cr0 \n" + /* Now that we are in protected mode jump to a 32 bit code segment. */ + " data32 ljmp $0x10, $vgarestart\n" + "vgarestart:\n" + " .code32\n" + " movw $0x18, %ax \n" + " mov %ax, %ds \n" + " mov %ax, %es \n" + " mov %ax, %fs \n" + " mov %ax, %gs \n" + " mov %ax, %ss \n" + /* restore proper gdt and idt */ + " lgdt %cs:gdtarg \n" + " lidt idtarg \n" + ".globl vga_exit \n" + "vga_exit: \n" + " mov __stack, %esp \n" + " popal \n"); +} + +__asm__(".text\n" "real_mode_switch_end:\n"); +extern char real_mode_switch_end[]; + +/* call vga bios int 10 function 0x4f14 to enable main console + epia-m does not always autosence the main console so forcing it on is good !! */ +void vga_enable_console(void) +{ + __asm__ __volatile__( + /* paranoia -- does ecx get saved? not sure. This is + * the easiest safe thing to do. */ + " pushal \n" + /* save the stack */ + " mov %esp, __stack \n" + /* load 'our' gdt */ + " lgdt %cs:__mygdtaddr \n" + /* This configures CS properly for real mode. */ + " ljmp $0x28, $__vga_ec_16bit\n" + "__vga_ec_16bit: \n" + " .code16 \n" + /* 16 bit code from here on... */ + /* Load the segment registers w/ properly configured segment + * descriptors. They will retain these configurations (limits, + * writability, etc.) once protected mode is turned off. */ + " mov $0x30, %ax \n" + " mov %ax, %ds \n" + " mov %ax, %es \n" + " mov %ax, %fs \n" + " mov %ax, %gs \n" + " mov %ax, %ss \n" + /* Turn off protection (bit 0 in CR0) */ + " movl %cr0, %eax \n" + " andl $0xFFFFFFFE, %eax\n" + " movl %eax, %cr0 \n" + /* Now really going into real mode */ + " ljmp $0, $__vga_ec_real \n" + "__vga_ec_real: \n" + /* put the stack at the end of page zero. + * that way we can easily share it between real and protected, + * since the 16-bit ESP at segment 0 will work for any case. + */ + /* Setup a stack */ + " mov $0x0, %ax \n" + " mov %ax, %ss \n" + " movl $0x1000, %eax \n" + " movl %eax, %esp \n" + /* debugging for RGM */ + " mov $0x11, %al \n" + " outb %al, $0x80 \n" + /* Load our 16 it idt */ + " xor %ax, %ax \n" + " mov %ax, %ds \n" + " lidt __myidt \n" + /* Dump zeros in the other segregs */ + " mov %ax, %ds \n" + " mov %ax, %es \n" + " mov %ax, %fs \n" + " mov %ax, %gs \n" + /* ask bios to enable main console */ + /* set up for int 10 call - values found from X server + * bios call routines */ + " movw $0x4f14,%ax \n" + " movw $0x8003,%bx \n" + " movw $1, %cx \n" + " movw $0, %dx \n" + " movw $0, %di \n" + " int $0x10 \n" + " movb $0x55, %al \n" + " outb %al, $0x80 \n" + /* if we got here, just about done. + * Need to get back to protected mode */ + " movl %cr0, %eax \n" " orl $0x0000001, %eax\n" /* PE = 1 */ + " movl %eax, %cr0 \n" + /* Now that we are in protected mode jump to a 32 bit code segment. */ + " data32 ljmp $0x10, $vga_ec_restart\n" + "vga_ec_restart:\n" + " .code32\n" + " movw $0x18, %ax \n" + " mov %ax, %ds \n" + " mov %ax, %es \n" + " mov %ax, %fs \n" + " mov %ax, %gs \n" + " mov %ax, %ss \n" + /* restore proper gdt and idt */ + " lgdt %cs:gdtarg \n" + " lidt idtarg \n" + " .globl vga__ec_exit \n" + "vga_ec_exit:\n" + " mov __stack, %esp \n" + " popal\n"); +} + +void do_vgabios(void) +{ + device_t dev; + unsigned long busdevfn; + unsigned int rom = 0; + unsigned char *buf; + unsigned int size = 64 * 1024; + int i; + + /* clear vga bios data area */ + for (i = 0x400; i < 0x500; i++) { + *(unsigned char *)i = 0; + } + + dev = dev_find_class(PCI_CLASS_DISPLAY_VGA << 8, 0); + + if (!dev) { + printk_debug("NO VGA FOUND\n"); + return; + } + printk_debug("found VGA: vid=%x, did=%x\n", dev->vendor, dev->device); + + /* declare rom address here - keep any config data out of the way + * of core LXB stuff */ + +#warning ROM address hardcoded to 512K + rom = 0xfff80000; + pci_write_config32(dev, PCI_ROM_ADDRESS, rom | 1); + printk_debug("rom base, size: %x\n", rom); + + buf = (unsigned char *)rom; + if ((buf[0] == 0x55) && (buf[1] == 0xaa)) { + memcpy((void *)0xc0000, buf, size); + + write_protect_vgabios(); // in northbridge + + // check signature again + buf = (unsigned char *)0xc0000; + if (buf[0] == 0x55 && buf[1] == 0xAA) { + busdevfn = + (dev->bus->secondary << 8) | dev->path.pci.devfn; + printk_debug("bus/devfn = %#x\n", busdevfn); + + real_mode_switch_call_vga(busdevfn); + } else + printk_debug("Failed to copy VGA BIOS to 0xc0000\n"); + } else + printk_debug("BAD SIGNATURE 0x%x 0x%x\n", buf[0], buf[1]); + + pci_write_config32(dev, PCI_ROM_ADDRESS, 0); +} + +// we had hoped to avoid this. +// this is a stub IDT only. It's main purpose is to ignore calls +// to the BIOS. +// no longer. Dammit. We have to respond to these. +struct realidt { + unsigned short offset, cs; +}; + +// from a handy writeup that andrey found. + +// handler. +// There are some assumptions we can make here. +// First, the Top Of Stack (TOS) is located on the top of page zero. +// we can share this stack between real and protected mode. +// that simplifies a lot of things ... +// we'll just push all the registers on the stack as longwords, +// and pop to protected mode. +// second, since this only ever runs as part of linuxbios, +// we know all the segment register values -- so we don't save any. +// keep the handler that calls things small. It can do a call to +// more complex code in linuxbios itself. This helps a lot as we don't +// have to do address fixup in this little stub, and calls are absolute +// so the handler is relocatable. +void handler(void) +{ + __asm__ __volatile__(" .code16 \n" + "idthandle: \n" + " pushal \n" + " movb $0, %al \n" + " ljmp $0, $callbiosint16\n" + "end_idthandle: \n" + " .code32 \n"); +} + +void debughandler(void) +{ + __asm__ __volatile__(" .code16 \n" + "debughandle: \n" + " pushw %cx \n" + " movw $250, %cx \n" + "dbh1: \n" + " loop dbh1 \n" + " popw %cx \n" + " iret \n" + "end_debughandle: \n" ".code32 \n"); +} + +// Calling conventions. The first C function is called with this stuff +// on the stack. They look like value parameters, but note that if you +// modify them they will go back to the INTx function modified. +// the C function will call the biosint function with these as +// REFERENCE parameters. In this way, we can easily get +// returns back to the INTx caller (i.e. vgabios) +void callbiosint(void) +{ + __asm__ __volatile__(" .code16 \n" + "callbiosint16: \n" + " push %ds \n" + " push %es \n" + " push %fs \n" " push %gs \n" + // clean up the int #. To save space we put it in the lower + // byte. But the top 24 bits are junk. + " andl $0xff, %eax\n" + // this push does two things: + // - put the INT # on the stack as a parameter + // - provides us with a temp for the %cr0 mods. + " pushl %eax \n" " movl %cr0, %eax\n" " orl $0x00000001, %eax\n" /* PE = 1 */ + " movl %eax, %cr0\n" + /* Now that we are in protected mode jump to a 32 bit code segment. */ + " data32 ljmp $0x10, $biosprotect\n" + "biosprotect: \n" + " .code32 \n" + " movw $0x18, %ax \n" + " mov %ax, %ds \n" + " mov %ax, %es \n" + " mov %ax, %fs \n" + " mov %ax, %gs \n" + " mov %ax, %ss \n" + " lidt idtarg \n" + " call biosint \n" + // back to real mode ... + " ljmp $0x28, $__rms_16bit2\n" + "__rms_16bit2: \n" + " .code16 \n" + /* 16 bit code from here on... */ + /* Load the segment registers w/ properly configured segment + * descriptors. They will retain these configurations (limits, + * writability, etc.) once protected mode is turned off. */ + " mov $0x30, %ax \n" + " mov %ax, %ds \n" + " mov %ax, %es \n" + " mov %ax, %fs \n" + " mov %ax, %gs \n" + " mov %ax, %ss \n" + /* Turn off protection (bit 0 in CR0) */ + " movl %cr0, %eax \n" + " andl $0xFFFFFFFE, %eax \n" + " movl %eax, %cr0 \n" + /* Now really going into real mode */ + " ljmp $0, $__rms_real2 \n" + "__rms_real2: \n" + /* Setup a stack + * FixME: where is esp? */ + " mov $0x0, %ax \n" + " mov %ax, %ss \n" + /* ebugging for RGM */ + " mov $0x11, %al \n" + " outb %al, $0x80 \n" + /* Load our 16 it idt */ + " xor %ax, %ax \n" + " mov %ax, %ds \n" + " lidt __myidt \n" + /* Dump zeros in the other segregs */ + " mov %ax, %es \n" + " mov %ax, %fs \n" + " mov %ax, %gs \n" + " mov $0x40, %ax \n" + " mov %ax, %ds \n" + /* pop the INT # that you pushed earlier */ + " popl %eax \n" + " pop %gs \n" + " pop %fs \n" + " pop %es \n" + " pop %ds \n" + " popal \n" + " iret \n" + " .code32 \n"); +} + +enum { + PCIBIOS = 0x1a, + MEMSIZE = 0x12 +}; + +int pcibios(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp, + unsigned long *pesp, unsigned long *pebx, unsigned long *pedx, + unsigned long *pecx, unsigned long *peax, unsigned long *pflags); + +int handleint21(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp, + unsigned long *pesp, unsigned long *pebx, unsigned long *pedx, + unsigned long *pecx, unsigned long *peax, + unsigned long *pflags); + +extern void vga_exit(void); + +int biosint(unsigned long intnumber, + unsigned long gsfs, unsigned long dses, + unsigned long edi, unsigned long esi, + unsigned long ebp, unsigned long esp, + unsigned long ebx, unsigned long edx, + unsigned long ecx, unsigned long eax, + unsigned long cs_ip, unsigned short stackflags) +{ + unsigned long ip; + unsigned long cs; + unsigned long flags; + int ret = -1; + + ip = cs_ip & 0xffff; + cs = cs_ip >> 16; + flags = stackflags; + + printk_debug("biosint: INT# 0x%lx\n", intnumber); + printk_debug("biosint: eax 0x%lx ebx 0x%lx ecx 0x%lx edx 0x%lx\n", + eax, ebx, ecx, edx); + printk_debug("biosint: ebp 0x%lx esp 0x%lx edi 0x%lx esi 0x%lx\n", + ebp, esp, edi, esi); + printk_debug("biosint: ip 0x%x cs 0x%x flags 0x%x\n", + ip, cs, flags); + + // cases in a good compiler are just as good as your own tables. + switch (intnumber) { + case 0 ... 15: + // These are not BIOS service, but the CPU-generated exceptions + printk_info("biosint: Oops, exception %u\n", intnumber); + if (esp < 0x1000) { + printk_debug("Stack contents: "); + while (esp < 0x1000) { + printk_debug("0x%04x ", *(unsigned short *)esp); + esp += 2; + } + printk_debug("\n"); + } + printk_debug("biosint: Bailing out\n"); + // "longjmp" + vga_exit(); + break; + + case PCIBIOS: + ret = pcibios(&edi, &esi, &ebp, &esp, + &ebx, &edx, &ecx, &eax, &flags); + break; + case MEMSIZE: + // who cares. + eax = 64 * 1024; + ret = 0; + break; + case 0x15: + ret = handleint21(&edi, &esi, &ebp, &esp, + &ebx, &edx, &ecx, &eax, &flags); + break; + default: + printk_info("BIOSINT: Unsupport int #0x%x\n", intnumber); + break; + } + if (ret) + flags |= 1; // carry flags + else + flags &= ~1; + stackflags = flags; + return ret; +} + +void setup_realmode_idt(void) +{ + extern unsigned char idthandle, end_idthandle; + extern unsigned char debughandle, end_debughandle; + + int i; + struct realidt *idts = (struct realidt *)0; + int codesize = &end_idthandle - &idthandle; + unsigned char *intbyte, *codeptr; + + // for each int, we create a customized little handler + // that just pushes %ax, puts the int # in %al, + // then calls the common interrupt handler. + // this necessitated because intel didn't know much about + // architecture when they did the 8086 (it shows) + // (hmm do they know anymore even now :-) + // obviously you can see I don't really care about memory + // efficiency. If I did I would probe back through the stack + // and get it that way. But that's really disgusting. + for (i = 0; i < 256; i++) { + idts[i].cs = 0; + codeptr = (unsigned char *)4096 + i * codesize; + idts[i].offset = (unsigned)codeptr; + memcpy(codeptr, &idthandle, codesize); + intbyte = codeptr + 3; + *intbyte = i; + } + + // fixed entry points + + // VGA BIOSes tend to hardcode f000:f065 as the previous handler of + // int10. + // calling convention here is the same as INTs, we can reuse + // the int entry code. + codeptr = (unsigned char *)0xff065; + memcpy(codeptr, &idthandle, codesize); + intbyte = codeptr + 3; + *intbyte = 0x42; /* int42 is the relocated int10 */ + + // VIA's VBIOS will call f000:f859 instead of sending int15. + codeptr = (unsigned char *)0xff859; + memcpy(codeptr, &idthandle, codesize); + intbyte = codeptr + 3; + *intbyte = 0x15; + + /* debug handler - useful to set a programmable delay between instructions if the + TF bit is set upon call to real mode */ + idts[1].cs = 0; + idts[1].offset = 16384; + memcpy((void *)16384UL, &debughandle, &end_debughandle - &debughandle); +} + +enum { + CHECK = 0xb001, + FINDDEV = 0xb102, + READCONFBYTE = 0xb108, + READCONFWORD = 0xb109, + READCONFDWORD = 0xb10a, + WRITECONFBYTE = 0xb10b, + WRITECONFWORD = 0xb10c, + WRITECONFDWORD = 0xb10d +}; + +// errors go in AH. Just set these up so that word assigns +// will work. KISS. +enum { + PCIBIOS_NODEV = 0x8600, + PCIBIOS_BADREG = 0x8700 +}; + +int +pcibios(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp, + unsigned long *pesp, unsigned long *pebx, unsigned long *pedx, + unsigned long *pecx, unsigned long *peax, unsigned long *pflags) +{ + unsigned short func = (unsigned short)(*peax); + int retval = 0; + unsigned short devid, vendorid, devfn; + short devindex; /* Use short to get rid of garbage in upper half of 32-bit register */ + unsigned char bus; + device_t dev; + + switch (func) { + case CHECK: + *pedx = 0x4350; + *pecx = 0x2049; + retval = 0; + break; + case FINDDEV: + { + devid = *pecx; + vendorid = *pedx; + devindex = *pesi; + dev = 0; + while ((dev = dev_find_device(vendorid, devid, dev))) { + if (devindex <= 0) + break; + devindex--; + } + if (dev) { + unsigned short busdevfn; + *peax = 0; + // busnum is an unsigned char; + // devfn is an int, so we mask it off. + busdevfn = (dev->bus->secondary << 8) + | (dev->path.pci.devfn & 0xff); + printk_debug("0x%x: return 0x%x\n", func, + busdevfn); + *pebx = busdevfn; + retval = 0; + } else { + *peax = PCIBIOS_NODEV; + retval = -1; + } + } + break; + case READCONFDWORD: + case READCONFWORD: + case READCONFBYTE: + case WRITECONFDWORD: + case WRITECONFWORD: + case WRITECONFBYTE: + { + unsigned long dword; + unsigned short word; + unsigned char byte; + unsigned char reg; + + devfn = *pebx & 0xff; + bus = *pebx >> 8; + reg = *pedi; + dev = dev_find_slot(bus, devfn); + if (!dev) { + printk_debug + ("0x%x: BAD DEVICE bus %d devfn 0x%x\n", + func, bus, devfn); + // idiots. the pcibios guys assumed you'd never pass a bad bus/devfn! + *peax = PCIBIOS_BADREG; + retval = -1; + } + switch (func) { + case READCONFBYTE: + byte = pci_read_config8(dev, reg); + *pecx = byte; + break; + case READCONFWORD: + word = pci_read_config16(dev, reg); + *pecx = word; + break; + case READCONFDWORD: + dword = pci_read_config32(dev, reg); + *pecx = dword; + break; + case WRITECONFBYTE: + byte = *pecx; + pci_write_config8(dev, reg, byte); + break; + case WRITECONFWORD: + word = *pecx; + pci_write_config16(dev, reg, word); + break; + case WRITECONFDWORD: + dword = *pecx; + pci_write_config32(dev, reg, dword); + break; + } + + if (retval) + retval = PCIBIOS_BADREG; + printk_debug + ("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%lx\n", + func, bus, devfn, reg, *pecx); + *peax = 0; + retval = 0; + } + break; + default: + printk_err("UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func); + break; + } + + return retval; +} + +int handleint21(unsigned long *edi, unsigned long *esi, unsigned long *ebp, + unsigned long *esp, unsigned long *ebx, unsigned long *edx, + unsigned long *ecx, unsigned long *eax, unsigned long *flags) +{ + int res = -1; + switch (*eax & 0xffff) { + case 0x5f19: + break; + case 0x5f18: + *eax = 0x5f; + *ebx = 0x545; // MCLK = 133, 32M frame buffer, 256 M main memory + *ecx = 0x060; + res = 0; + break; + case 0x5f00: + *eax = 0x8600; + break; + case 0x5f01: + *eax = 0x5f; + *ecx = (*ecx & 0xffffff00) | 2; // panel type = 2 = 1024 * 768 + res = 0; + break; + case 0x5f02: + *eax = 0x5f; + *ebx = (*ebx & 0xffff0000) | 2; + *ecx = (*ecx & 0xffff0000) | 0x401; // PAL + crt only + *edx = (*edx & 0xffff0000) | 0; // TV Layout - default + res = 0; + break; + case 0x5f0f: + *eax = 0x860f; + break; + } + return res; +} diff --git a/src/pc80/udelay_io.c b/src/pc80/udelay_io.c index a67b5a1986..7a5320e370 100644 --- a/src/pc80/udelay_io.c +++ b/src/pc80/udelay_io.c @@ -1,6 +1,6 @@ #include <arch/io.h> -void udelay(int usecs) +void udelay(unsigned usecs) { int i; for(i = 0; i < usecs; i++) |