From 5cd81730ecef18690f92d193b0381c103a5b3d9b Mon Sep 17 00:00:00 2001 From: Eric Biederman Date: Thu, 11 Mar 2004 15:01:31 +0000 Subject: - Moved hlt() to it's own header. - Reworked pnp superio device support. Now complete superio support is less than 100 lines. - Added support for hard coding resource assignments in Config.lb - Minor bug fixes to romcc - Initial support for catching the x86 processor BIST error codes. I've only seen this trigger once in production during a very suspcious reset but... - added raminit_test to test the code paths in raminit.c for the Opteron - Removed the IORESOURCE_SET bit and added IORESOURCE_ASSIGNED and IORESOURCE_STORED so we can tell what we have really done. - Added generic AGP/IOMMU setting code to x86 - Added an implementation of memmove and removed reserved identifiers from memcpy - Added minimal support for booting on pre b3 stepping K8 cores - Moved the checksum on amd8111 boards because our default location was on top of extended RTC registers - On the Hdama added support for enabling i2c hub so we can get at the temperature sensors. Not that i2c bus was implemented well enough to make that useful. - Redid the Opteron port so we should only need one reset and most of memory initialization is done in cpu_fixup. This is much, much faster. - Attempted to make the VGA IO region assigment work. The code seems to work now... - Redid the error handling in amdk8/raminit.c to distinguish between a bad value and a smbus error, and moved memory clearing out to cpufixup. - Removed CONFIG_KEYBOARD as it was useless. See pc87360/superio.c for how to setup a legacy keyboard properly. - Reworked the register values for standard hardware, moving the defintions from chip.h into the headers of the initialization routines. This is much saner and is actually implemented. - Made the hdama port an under clockers BIOS. I debuged so many interesting problems. - On amd8111_lpc added setup of architectural/legacy hardware - Enabled PCI error reporting as much as possible. - Enhanded build_opt_tbl to generate a header of the cmos option locations so that romcc compiled code can query the cmos options. - In romcc gracefully handle function names that degenerate into function pointers - Bumped the version to 1.1.6 as we are getting closer to 2.0 TODO finish optimizing the HT links of non dual boards TODO make all Opteron board work again TODO convert all superio devices to use the new helpers TODO convert the via/epia to freebios2 conventions TODO cpu fixup/setup by cpu type git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1390 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1 --- src/arch/i386/include/arch/hlt.h | 20 + src/arch/i386/include/arch/romcc_io.h | 57 +- src/arch/i386/include/arch/smp/lapic.h | 55 ++ src/arch/i386/lib/cpu.c | 4 +- src/arch/i386/smp/start_stop.c | 9 +- src/arch/ppc/boot/linuxbios_table.c | 3 + src/config/Config.lb | 15 +- src/config/Options.lb | 41 +- src/cpu/i386/bist32.inc | 4 + src/cpu/i386/bist32_fail.inc | 44 ++ src/cpu/i386/entry16.inc | 5 + src/cpu/i386/entry32.inc | 6 + src/cpu/k8/cpufixup.c | 287 ++++++- src/cpu/k8/earlymtrr.c | 26 +- src/cpu/k8/earlymtrr.inc | 22 +- src/cpu/k8/enable_mmx_sse.inc | 6 + src/cpu/p6/Config.lb | 1 + src/cpu/p6/boot_cpu.c | 2 - src/cpu/p6/earlymtrr.c | 10 +- src/cpu/p6/mtrr.c | 37 +- src/cpu/p6/pgtbl.c | 91 +++ src/devices/Config.lb | 1 + src/devices/chip.c | 11 + src/devices/device.c | 20 +- src/devices/device_util.c | 73 +- src/devices/hypertransport.c | 51 +- src/devices/pci_device.c | 124 +-- src/devices/pnp_device.c | 217 ++++++ src/include/cpu/k8/mtrr.h | 3 + src/include/cpu/p6/mtrr.h | 2 +- src/include/cpu/p6/pgtbl.h | 7 + src/include/device/chip.h | 23 +- src/include/device/device.h | 16 +- src/include/device/hypertransport.h | 2 + src/include/device/hypertransport_def.h | 16 + src/include/device/pci_def.h | 4 +- src/include/device/pnp.h | 97 ++- src/include/device/pnp_def.h | 12 + src/include/device/resource.h | 6 +- src/include/pc80/keyboard.h | 10 + src/include/pc80/mc146818rtc.h | 22 +- src/include/string.h | 1 + src/include/uart8250.h | 6 + src/lib/Config.lb | 3 +- src/lib/memcpy.c | 11 +- src/lib/memmove.c | 20 + src/lib/uart8250.c | 16 + src/mainboard/amd/quartet/Config.lb | 36 +- src/mainboard/amd/solo/Config.lb | 81 +- src/mainboard/amd/solo/auto.c | 104 +-- src/mainboard/amd/solo/cmos.layout | 26 +- src/mainboard/amd/solo/failover.c | 72 +- src/mainboard/amd/solo/mptable.c | 1 - src/mainboard/arima/hdama/Config.lb | 61 +- src/mainboard/arima/hdama/auto.c | 134 +--- src/mainboard/arima/hdama/cmos.layout | 26 +- src/mainboard/arima/hdama/failover.c | 72 +- src/mainboard/arima/hdama/irq_tables.c | 36 +- src/mainboard/arima/hdama/mainboard.c | 247 +++++- src/mainboard/newisys/khepri/Config.lb | 36 +- src/mainboard/newisys/khepri/auto.c | 127 +-- src/northbridge/amd/amdk8/Config.lb | 7 +- src/northbridge/amd/amdk8/amdk8.h | 12 + src/northbridge/amd/amdk8/coherent_ht.c | 469 ++++++----- src/northbridge/amd/amdk8/cpu_rev.c | 7 +- src/northbridge/amd/amdk8/early_ht.c | 3 +- src/northbridge/amd/amdk8/incoherent_ht.c | 244 ++++++ src/northbridge/amd/amdk8/misc_control.c | 198 +++-- src/northbridge/amd/amdk8/northbridge.c | 86 +- src/northbridge/amd/amdk8/raminit.c | 907 +++++++++------------- src/northbridge/amd/amdk8/raminit.h | 5 +- src/northbridge/amd/amdk8/raminit_test.c | 442 +++++++++++ src/northbridge/amd/amdk8/reset_test.c | 11 +- src/pc80/Config.lb | 7 +- src/pc80/isa-dma.c | 43 + src/pc80/keyboard.c | 11 +- src/pc80/mc146818rtc_early.c | 11 + src/pc80/serial.c | 3 +- src/pc80/serial.inc | 7 +- src/southbridge/amd/amd8111/Config.lb | 5 +- src/southbridge/amd/amd8111/amd8111.c | 21 +- src/southbridge/amd/amd8111/amd8111_acpi.c | 41 +- src/southbridge/amd/amd8111/amd8111_early_smbus.c | 3 +- src/southbridge/amd/amd8111/amd8111_ide.c | 3 - src/southbridge/amd/amd8111/amd8111_lpc.c | 35 +- src/southbridge/amd/amd8111/amd8111_pci.c | 61 ++ src/southbridge/amd/amd8111/amd8111_usb.c | 2 + src/southbridge/amd/amd8111/amd8111_usb2.c | 3 +- src/southbridge/amd/amd8131/amd8131_bridge.c | 43 +- src/superio/NSC/pc87360/chip.h | 14 +- src/superio/NSC/pc87360/pc87360.h | 11 + src/superio/NSC/pc87360/pc87360_early_serial.c | 11 + src/superio/NSC/pc87360/superio.c | 339 ++------ 93 files changed, 3806 insertions(+), 1837 deletions(-) create mode 100644 src/arch/i386/include/arch/hlt.h create mode 100644 src/arch/i386/include/arch/smp/lapic.h create mode 100644 src/cpu/i386/bist32.inc create mode 100644 src/cpu/i386/bist32_fail.inc create mode 100644 src/cpu/p6/pgtbl.c create mode 100644 src/devices/pnp_device.c create mode 100644 src/include/cpu/p6/pgtbl.h create mode 100644 src/include/device/hypertransport_def.h create mode 100644 src/include/device/pnp_def.h create mode 100644 src/include/pc80/keyboard.h create mode 100644 src/lib/memmove.c create mode 100644 src/northbridge/amd/amdk8/incoherent_ht.c create mode 100644 src/northbridge/amd/amdk8/raminit_test.c create mode 100644 src/pc80/isa-dma.c create mode 100644 src/southbridge/amd/amd8111/amd8111_pci.c create mode 100644 src/superio/NSC/pc87360/pc87360.h create mode 100644 src/superio/NSC/pc87360/pc87360_early_serial.c (limited to 'src') diff --git a/src/arch/i386/include/arch/hlt.h b/src/arch/i386/include/arch/hlt.h new file mode 100644 index 0000000000..86ed7c8f41 --- /dev/null +++ b/src/arch/i386/include/arch/hlt.h @@ -0,0 +1,20 @@ +#ifndef ARCH_HLT_H +#define ARCH_HLT_H + +#ifdef __ROMCC__ +static void hlt(void) +{ + __builtin_hlt(); +} + +#endif + +#ifdef __GNUC__ +static inline void hlt(void) +{ + asm("hlt"); + return; +} +#endif + +#endif /* ARCH_HLT_H */ diff --git a/src/arch/i386/include/arch/romcc_io.h b/src/arch/i386/include/arch/romcc_io.h index 1a646359a7..c3a0ff76fa 100644 --- a/src/arch/i386/include/arch/romcc_io.h +++ b/src/arch/i386/include/arch/romcc_io.h @@ -1,11 +1,7 @@ #ifndef ARCH_ROMCC_IO_H #define ARCH_ROMCC_IO_H 1 - -static void hlt(void) -{ - __builtin_hlt(); -} +#include typedef __builtin_div_t div_t; typedef __builtin_ldiv_t ldiv_t; @@ -59,6 +55,9 @@ int log2(int value) #define PCI_ID(VENDOR_ID, DEVICE_ID) \ ((((DEVICE_ID) & 0xFFFF) << 16) | ((VENDOR_ID) & 0xFFFF)) + +#define PNP_DEV(PORT, FUNC) (((PORT) << 8) | (FUNC)) + typedef unsigned device_t; static unsigned char pci_read_config8(device_t dev, unsigned where) @@ -122,4 +121,52 @@ static device_t pci_locate_device(unsigned pci_id, device_t dev) return PCI_DEV_INVALID; } + +/* Generic functions for pnp devices */ +static inline void pnp_write_config(device_t dev, uint8_t reg, uint8_t value) +{ + unsigned port = dev >> 8; + outb(reg, port ); + outb(value, port +1); +} + +static inline uint8_t pnp_read_config(device_t dev, uint8_t reg) +{ + unsigned port = dev >> 8; + outb(reg, port); + return inb(port +1); +} + +static inline void pnp_set_logical_device(device_t dev) +{ + unsigned device = dev & 0xff; + pnp_write_config(dev, 0x07, device); +} + +static inline void pnp_set_enable(device_t dev, int enable) +{ + pnp_write_config(dev, 0x30, enable?0x1:0x0); +} + +static inline int pnp_read_enable(device_t dev) +{ + return !!pnp_read_config(dev, 0x30); +} + +static inline void pnp_set_iobase(device_t dev, unsigned index, unsigned iobase) +{ + pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff); + pnp_write_config(dev, index + 1, iobase & 0xff); +} + +static inline void pnp_set_irq(device_t dev, unsigned index, unsigned irq) +{ + pnp_write_config(dev, index, irq); +} + +static inline void pnp_set_drq(device_t dev, unsigned index, unsigned drq) +{ + pnp_write_config(dev, index, drq & 0xff); +} + #endif /* ARCH_ROMCC_IO_H */ diff --git a/src/arch/i386/include/arch/smp/lapic.h b/src/arch/i386/include/arch/smp/lapic.h new file mode 100644 index 0000000000..0ac87aa2d3 --- /dev/null +++ b/src/arch/i386/include/arch/smp/lapic.h @@ -0,0 +1,55 @@ +#ifndef ARCH_SMP_LAPIC_H +#define ARCH_SMP_LAPIC_H + +#include +#include +#include + +static void enable_lapic(void) +{ + + msr_t msr; + msr = rdmsr(0x1b); + msr.hi &= 0xffffff00; + msr.lo &= 0x000007ff; + msr.lo |= APIC_DEFAULT_BASE | (1 << 11); + wrmsr(0x1b, msr); +} + +static void disable_lapic(void) +{ + msr_t msr; + msr = rdmsr(0x1b); + msr.lo &= ~ (1 << 11); + wrmsr(0x1b, msr); +} + +static inline unsigned long lapicid(void) +{ + return apic_read(APIC_ID) >> 24; +} + +static void stop_this_cpu(void) +{ + unsigned apicid; + apicid = lapicid(); + + /* Send an APIC INIT to myself */ + apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); + apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT); + /* Wait for the ipi send to finish */ + apic_wait_icr_idle(); + + /* Deassert the APIC INIT */ + apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); + apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); + /* Wait for the ipi send to finish */ + apic_wait_icr_idle(); + + /* If I haven't halted spin forever */ + for(;;) { + hlt(); + } +} + +#endif /* ARCH_SMP_LAPIC_H */ diff --git a/src/arch/i386/lib/cpu.c b/src/arch/i386/lib/cpu.c index ad982dbc6c..f459f3a853 100644 --- a/src/arch/i386/lib/cpu.c +++ b/src/arch/i386/lib/cpu.c @@ -10,6 +10,7 @@ #include #include #include +#include #if 0 #include #endif @@ -97,8 +98,7 @@ static void interrupts_on() APIC_DELIVERY_MODE_NMI) ); - printk_debug(" apic_id: %d ", - apic_read(APIC_ID)); + printk_debug(" apic_id: %d ", lapicid()); #else /* APIC */ #if i686==1 diff --git a/src/arch/i386/smp/start_stop.c b/src/arch/i386/smp/start_stop.c index b40452403c..bf26437984 100644 --- a/src/arch/i386/smp/start_stop.c +++ b/src/arch/i386/smp/start_stop.c @@ -4,16 +4,13 @@ #include #include #include +#include +#include -static inline void hlt(void) -{ - asm("hlt"); - return; -} unsigned long this_processors_id(void) { - return apic_read(APIC_ID) >> 24; + return lapicid(); } int processor_index(unsigned long apicid) diff --git a/src/arch/ppc/boot/linuxbios_table.c b/src/arch/ppc/boot/linuxbios_table.c index 20264c202c..f199615d5f 100644 --- a/src/arch/ppc/boot/linuxbios_table.c +++ b/src/arch/ppc/boot/linuxbios_table.c @@ -227,6 +227,9 @@ unsigned long write_linuxbios_table( struct mem_range *ramp; struct lb_header *head; struct lb_memory *mem; +#if HAVE_OPTION_TABLE == 1 + struct lb_record *rec_dest, *rec_src; +#endif head = lb_table_init(low_table_end); low_table_end = (unsigned long)head; diff --git a/src/config/Config.lb b/src/config/Config.lb index 4a99d07ffa..636e5537c6 100644 --- a/src/config/Config.lb +++ b/src/config/Config.lb @@ -7,7 +7,7 @@ makedefine LIBGCC_FILE_NAME := $(shell $(CC) -print-libgcc-file-name) makedefine GCC_INC_DIR := $(shell $(CC) -print-search-dirs | sed -ne "s/install: \(.*\)/\1include/gp") makedefine CPPFLAGS := -I$(TOP)/src/include -I$(TOP)/src/arch/$(ARCH)/include -I$(GCC_INC_DIR) $(CPUFLAGS) -makedefine ROMCCPPFLAGS := -D__ROMCC__=0 -D__ROMCC_MINOR__=37 +makedefine ROMCCPPFLAGS := -D__ROMCC__=0 -D__ROMCC_MINOR__=38 makedefine CFLAGS := $(CPU_OPT) $(CPPFLAGS) -Os -nostdinc -nostdlib -fno-builtin -Wall makedefine HOSTCFLAGS:= -Os -Wall @@ -116,12 +116,12 @@ end makerule ./romcc depends "$(TOP)/util/romcc/romcc.c" - action "$(HOSTCC) -g $(HOSTCFLAGS) -DVERSION='\"0.37\"' -DRELEASE_DATE='\"21 October 2003\"' $< -o $@" + action "$(HOSTCC) -g $(HOSTCFLAGS) -DVERSION='\"0.38\"' -DRELEASE_DATE='\"18 December 2003\"' $< -o $@" end makerule build_opt_tbl - depends "$(TOP)/util/options/build_opt_tbl.c $(TOP)/src/include/pc80/mc146818rtc.h $(TOP)/src/include/boot/linuxbios_tables.h" - action "$(HOSTCC) $(HOSTCFLAGS) $< -o $@" + depends "$(TOP)/util/options/build_opt_tbl.c $(TOP)/src/include/pc80/mc146818rtc.h $(TOP)/src/include/boot/linuxbios_tables.h Makefile.settings Makefile" + action "$(HOSTCC) $(HOSTCFLAGS) $(CPUFLAGS) $< -o $@" end #makerule /$(TARGET_DIR)/option_table.c @@ -131,7 +131,12 @@ end makerule option_table.c depends "build_opt_tbl $(MAINBOARD)/cmos.layout" - action "./build_opt_tbl -b --config $(MAINBOARD)/cmos.layout" + action "./build_opt_tbl -b --config $(MAINBOARD)/cmos.layout --header option_table.h" +end + +makerule option_table.h + depends "build_opt_tbl $(MAINBOARD)/cmos.layout" + action "./build_opt_tbl -b --config $(MAINBOARD)/cmos.layout --header option_table.h" end if HAVE_OPTION_TABLE diff --git a/src/config/Options.lb b/src/config/Options.lb index 936f9c3727..a175f358e8 100644 --- a/src/config/Options.lb +++ b/src/config/Options.lb @@ -117,7 +117,7 @@ define OBJCOPY comment "Objcopy command" end define LINUXBIOS_VERSION - default "1.1.5" + default "1.1.6" export always comment "LinuxBIOS version" end @@ -318,6 +318,12 @@ define CONFIG_UNCOMPRESSED export always comment "Set for uncompressed image" end +define CONFIG_LB_MEM_TOPK + format "%d" + default 1024 + export always + comment "Kilobytes of memory to initialized before executing code from RAM" +end define HAVE_OPTION_TABLE default 0 export always @@ -330,6 +336,29 @@ define USE_OPTION_TABLE comment "Use option table" end +############################################### +# CMOS variable options +############################################### +define LB_CKS_RANGE_START + default 49 + format "%d" + export always + comment "First CMOS byte to use for LinuxBIOS options" +end +define LB_CKS_RANGE_END + default 125 + format "%d" + export always + comment "Last CMOS byte to use for LinuxBIOS options" +end +define LB_CKS_LOC + default 126 + format "%d" + export always + comment "Pair of bytes to use for CMOS checksum" +end + + ############################################### # Build targets ############################################### @@ -427,15 +456,15 @@ define MAINBOARD_VENDOR export always comment "Vendor of mainboard" end -define CONFIG_SYS_CLK_FREQ +define MAINBOARD_POWER_ON_AFTER_POWER_FAIL default none export used - comment "System clock frequency in MHz" + comment "Default power on after power fail setting" end -define CONFIG_KEYBOARD - default 0 +define CONFIG_SYS_CLK_FREQ + default none export used - comment "Run PC keyboard enable code" + comment "System clock frequency in MHz" end define CONFIG_LEGACY_VGABIOS default 0 diff --git a/src/cpu/i386/bist32.inc b/src/cpu/i386/bist32.inc new file mode 100644 index 0000000000..d2fb98cdc3 --- /dev/null +++ b/src/cpu/i386/bist32.inc @@ -0,0 +1,4 @@ + + /* Carefully print the failure if the built in self test did not pass */ + testl %eax, %eax + jnz bist32_fail diff --git a/src/cpu/i386/bist32_fail.inc b/src/cpu/i386/bist32_fail.inc new file mode 100644 index 0000000000..f467b065bc --- /dev/null +++ b/src/cpu/i386/bist32_fail.inc @@ -0,0 +1,44 @@ + + + jmp bist32_fail_0 +bist32_fail: + movl %eax, %ebp + +#if 1 +#define SIO_BASE 0x2e +#define SIO_INDEX SIO_BASE +#define SIO_DATA SIO_BASE+1 +#define SIO_WRITE_CONFIG(value, reg) \ + movb reg, %al ; \ + outb %al, $(SIO_INDEX) ; \ + movb value, %al ; \ + outb %al, $(SIO_DATA) + +#define SIO_READ_CONFIG(reg) \ + movb reg, %al ; \ + outb %al, $(SIO_INDEX) ; \ + inb $(SIO_DATA), %al + +#define SIO_SET_LOGICAL_DEVICE(device) \ + SIO_WRITE_CONFIG(device, $0x07) + + /* Enable serial 1 */ + SIO_SET_LOGICAL_DEVICE($3) + SIO_WRITE_CONFIG($1, $0x30) + SIO_WRITE_CONFIG($0x3, $0x60) + SIO_WRITE_CONFIG($0xf8, $0x61) + +#endif + CALLSP(serial_init) + CONSOLE_DEBUG_TX_STRING($str_bist_failed) + CONSOLE_DEBUG_TX_HEX32(%ebp) + CONSOLE_DEBUG_TX_STRING($str_bist_newline) + jmp .Lhlt + +bist32_fail_0: + +.section ".rom.data" +str_bist_failed: .string "BIST failed: " +str_bist_newline: .string "\r\n" +.previous + diff --git a/src/cpu/i386/entry16.inc b/src/cpu/i386/entry16.inc index 7ab3ff3bf0..f9e921f291 100644 --- a/src/cpu/i386/entry16.inc +++ b/src/cpu/i386/entry16.inc @@ -33,6 +33,8 @@ it with the version available from LANL. _start: cli + /* Save the BIST result */ + movl %eax, %ebp /* thanks to kmliu@sis.tw.com for this TBL fix ... */ /**/ @@ -93,6 +95,9 @@ _start: orl $0x60000001, %eax /* CD, NW, PE = 1 */ movl %eax, %cr0 + /* Restore BIST to %eax */ + movl %ebp, %eax + /* Now that we are in protected mode jump to a 32 bit code segment. */ data32 ljmp $ROM_CODE_SEG, $__protected_start diff --git a/src/cpu/i386/entry32.inc b/src/cpu/i386/entry32.inc index 6f55f00203..3d30a3f85f 100644 --- a/src/cpu/i386/entry32.inc +++ b/src/cpu/i386/entry32.inc @@ -44,6 +44,9 @@ protected_start: ljmp $ROM_CODE_SEG, $__protected_start __protected_start: + /* Save the BIST value */ + movl %eax, %ebp + intel_chip_post_macro(0x10) /* post 10 */ movw $ROM_DATA_SEG, %ax @@ -53,3 +56,6 @@ __protected_start: movw %ax, %fs movw %ax, %gs + /* Restore the BIST value to %eax */ + movl %ebp, %eax + diff --git a/src/cpu/k8/cpufixup.c b/src/cpu/k8/cpufixup.c index 6aa6722579..2d347de829 100644 --- a/src/cpu/k8/cpufixup.c +++ b/src/cpu/k8/cpufixup.c @@ -4,8 +4,17 @@ #include #include #include -#include "../../northbridge/amd/amdk8/cpu_rev.c" #include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../northbridge/amd/amdk8/amdk8.h" +#include "../../northbridge/amd/amdk8/cpu_rev.c" #include "chip.h" #define MCI_STATUS 0x401 @@ -14,7 +23,7 @@ static inline void disable_cache(void) { unsigned int tmp; /* Disable cache */ - /* Write back the cache and flush TLB */ + /* Write back the cache */ asm volatile ( "movl %%cr0, %0\n\t" "orl $0x40000000, %0\n\t" @@ -57,6 +66,232 @@ static inline void wrmsr_amd(unsigned index, msr_t msr) ); } + + +#define MTRR_COUNT 8 +#define ZERO_CHUNK_KB 0x800UL /* 2M */ +#define TOLM_KB 0x400000UL + +struct mtrr { + msr_t base; + msr_t mask; +}; +struct mtrr_state { + struct mtrr mtrrs[MTRR_COUNT]; + msr_t top_mem, top_mem2; + msr_t def_type; +}; + +static void save_mtrr_state(struct mtrr_state *state) +{ + int i; + for(i = 0; i < MTRR_COUNT; i++) { + state->mtrrs[i].base = rdmsr(MTRRphysBase_MSR(i)); + state->mtrrs[i].mask = rdmsr(MTRRphysMask_MSR(i)); + } + state->top_mem = rdmsr(TOP_MEM); + state->top_mem2 = rdmsr(TOP_MEM2); + state->def_type = rdmsr(MTRRdefType_MSR); +} + +static void restore_mtrr_state(struct mtrr_state *state) +{ + int i; + disable_cache(); + + for(i = 0; i < MTRR_COUNT; i++) { + wrmsr(MTRRphysBase_MSR(i), state->mtrrs[i].base); + wrmsr(MTRRphysMask_MSR(i), state->mtrrs[i].mask); + } + wrmsr(TOP_MEM, state->top_mem); + wrmsr(TOP_MEM2, state->top_mem2); + wrmsr(MTRRdefType_MSR, state->def_type); + + enable_cache(); +} + + +#if 0 +static void print_mtrr_state(struct mtrr_state *state) +{ + int i; + for(i = 0; i < MTRR_COUNT; i++) { + printk_debug("var mtrr %d: %08x%08x mask: %08x%08x\n", + i, + state->mtrrs[i].base.hi, state->mtrrs[i].base.lo, + state->mtrrs[i].mask.hi, state->mtrrs[i].mask.lo); + } + printk_debug("top_mem: %08x%08x\n", + state->top_mem.hi, state->top_mem.lo); + printk_debug("top_mem2: %08x%08x\n", + state->top_mem2.hi, state->top_mem2.lo); + printk_debug("def_type: %08x%08x\n", + state->def_type.hi, state->def_type.lo); +} +#endif + +static void set_init_ecc_mtrrs(void) +{ + msr_t msr; + int i; + disable_cache(); + + /* First clear all of the msrs to be safe */ + for(i = 0; i < MTRR_COUNT; i++) { + msr_t zero; + zero.lo = zero.hi = 0; + wrmsr(MTRRphysBase_MSR(i), zero); + wrmsr(MTRRphysMask_MSR(i), zero); + } + + /* Write back cache the first 1MB */ + msr.hi = 0x00000000; + msr.lo = 0x00000000 | MTRR_TYPE_WRBACK; + wrmsr(MTRRphysBase_MSR(0), msr); + msr.hi = 0x000000ff; + msr.lo = ~((CONFIG_LB_MEM_TOPK << 10) - 1) | 0x800; + wrmsr(MTRRphysMask_MSR(0), msr); + + /* Set the default type to write combining */ + msr.hi = 0x00000000; + msr.lo = 0xc00 | MTRR_TYPE_WRCOMB; + wrmsr(MTRRdefType_MSR, msr); + + /* Set TOP_MEM to 4G */ + msr.hi = 0x00000001; + msr.lo = 0x00000000; + wrmsr(TOP_MEM, msr); + + enable_cache(); +} + + +static void init_ecc_memory(void) +{ + unsigned long startk, begink, endk; + unsigned long basek; + struct mtrr_state mtrr_state; + device_t f1_dev, f2_dev, f3_dev; + int cpu_index, cpu_id, node_id; + int enable_scrubbing; + uint32_t dcl; + cpu_id = this_processors_id(); + cpu_index = processor_index(cpu_id); + /* For now there is a 1-1 mapping between node_id and cpu_id */ + node_id = cpu_id; + + f1_dev = dev_find_slot(0, PCI_DEVFN(0x18 + node_id, 1)); + if (!f1_dev) { + die("Cannot find cpu function 1\n"); + } + f2_dev = dev_find_slot(0, PCI_DEVFN(0x18 + node_id, 2)); + if (!f2_dev) { + die("Cannot find cpu function 2\n"); + } + f3_dev = dev_find_slot(0, PCI_DEVFN(0x18 + node_id, 3)); + if (!f3_dev) { + die("Cannot find cpu function 3\n"); + } + + /* See if we scrubbing should be enabled */ + enable_scrubbing = 1; + get_option(&enable_scrubbing, "hw_scrubber"); + + /* Enable cache scrubbing at the lowest possible rate */ + if (enable_scrubbing) { + pci_write_config32(f3_dev, SCRUB_CONTROL, + (SCRUB_84ms << 16) | (SCRUB_84ms << 8) | (SCRUB_NONE << 0)); + } else { + pci_write_config32(f3_dev, SCRUB_CONTROL, + (SCRUB_NONE << 16) | (SCRUB_NONE << 8) | (SCRUB_NONE << 0)); + printk_debug("Scrubbing Disabled\n"); + } + + + /* If ecc support is not enabled don't touch memory */ + dcl = pci_read_config32(f2_dev, DRAM_CONFIG_LOW); + if (!(dcl & DCL_DimmEccEn)) { + return; + } + + startk = (pci_read_config32(f1_dev, 0x40 + (node_id*8)) & 0xffff0000) >> 2; + endk = ((pci_read_config32(f1_dev, 0x44 + (node_id*8)) & 0xffff0000) >> 2) + 0x4000; + + /* Don't start too early */ + begink = startk; + if (begink < CONFIG_LB_MEM_TOPK) { + begink = CONFIG_LB_MEM_TOPK; + } + printk_debug("Clearing memory %uK - %uK: ", startk, endk); + + /* Save the normal state */ + save_mtrr_state(&mtrr_state); + + /* Switch to the init ecc state */ + set_init_ecc_mtrrs(); + disable_lapic(); + + /* Walk through 2M chunks and zero them */ + for(basek = begink; basek < endk; basek = ((basek + ZERO_CHUNK_KB) & ~(ZERO_CHUNK_KB - 1))) { + unsigned long limitk; + unsigned long size; + void *addr; + + /* Report every 64M */ + if ((basek % (64*1024)) == 0) { + /* Restore the normal state */ + map_2M_page(cpu_index, 0); + restore_mtrr_state(&mtrr_state); + enable_lapic(); + + /* Print a status message */ + printk_debug("%c", (basek >= TOLM_KB)?'+':'-'); + + /* Return to the initialization state */ + set_init_ecc_mtrrs(); + disable_lapic(); + } + limitk = (basek + ZERO_CHUNK_KB) & ~(ZERO_CHUNK_KB - 1); + if (limitk > endk) { + limitk = endk; + } + size = (limitk - basek) << 10; + addr = map_2M_page(cpu_index, basek >> 11); + addr = (void *)(((uint32_t)addr) | ((basek & 0x7ff) << 10)); + if (addr == MAPPING_ERROR) { + continue; + } + + /* clear memory 2M (limitk - basek) */ + __asm__ volatile( + "1: \n\t" + "movl %0, (%1)\n\t" + "addl $4,%1\n\t" + "subl $4,%2\n\t" + "jnz 1b\n\t" + : + : "a" (0), "D" (addr), "c" (size) + ); + } + /* Restore the normal state */ + map_2M_page(cpu_index, 0); + restore_mtrr_state(&mtrr_state); + enable_lapic(); + + /* Set the scrub base address registers */ + pci_write_config32(f3_dev, SCRUB_ADDR_LOW, startk << 10); + pci_write_config32(f3_dev, SCRUB_ADDR_HIGH, startk >> 22); + + /* Enable the scrubber? */ + if (enable_scrubbing) { + /* Enable scrubbing at the lowest possible rate */ + pci_write_config32(f3_dev, SCRUB_CONTROL, + (SCRUB_84ms << 16) | (SCRUB_84ms << 8) | (SCRUB_84ms << 0)); + } + + printk_debug(" done\n"); +} + void k8_cpufixup(struct mem_range *mem) { unsigned long mmio_basek, tomk; @@ -83,7 +318,11 @@ void k8_cpufixup(struct mem_range *mem) if (mmio_basek > tomk) { mmio_basek = tomk; } - + /* Round mmio_basek down to the nearst size that will fit in TOP_MEM */ + mmio_basek = mmio_basek & ~TOP_MEM_MASK_KB; + /* Round tomk up to the next greater size that will fit in TOP_MEM */ + tomk = (tomk + TOP_MEM_MASK_KB) & ~TOP_MEM_MASK_KB; + /* Setup TOP_MEM */ msr.hi = mmio_basek >> 22; msr.lo = mmio_basek << 10; @@ -101,7 +340,7 @@ void k8_cpufixup(struct mem_range *mem) for(i = IORR_FIRST; i <= IORR_LAST; i++) { wrmsr(i, msr); } - + msr = rdmsr(SYSCFG_MSR); msr.lo |= SYSCFG_MSR_MtrrVarDramEn | SYSCFG_MSR_TOM2En; wrmsr(SYSCFG_MSR, msr); @@ -118,33 +357,34 @@ void k8_cpufixup(struct mem_range *mem) msr = rdmsr(HWCR_MSR); msr.lo |= (1 << 6); wrmsr(HWCR_MSR, msr); + /* Erratum 69... */ -#if 1 msr = rdmsr_amd(BU_CFG_MSR); msr.hi |= (1 << (45 - 32)); wrmsr_amd(BU_CFG_MSR, msr); -#endif + /* Erratum 81... */ -#if 1 msr = rdmsr_amd(DC_CFG_MSR); msr.lo |= (1 << 10); wrmsr_amd(DC_CFG_MSR, msr); -#endif } - /* Erratum 89 ... */ - msr = rdmsr(NB_CFG_MSR); - msr.lo |= 1 << 3; + /* I can't touch this msr on early buggy cpus */ + if (!is_cpu_pre_b3()) { - if (!is_cpu_pre_c0()) { - /* Erratum 86 Disable data masking on C0 and - * later processor revs. - * FIXME this is only needed if ECC is enabled. - */ - msr.hi |= 1 << (36 - 32); - } - wrmsr(NB_CFG_MSR, msr); -#if 1 /* The following erratum fixes reset the cpu ???? */ + /* Erratum 89 ... */ + msr = rdmsr(NB_CFG_MSR); + msr.lo |= 1 << 3; + + if (!is_cpu_pre_c0()) { + /* Erratum 86 Disable data masking on C0 and + * later processor revs. + * FIXME this is only needed if ECC is enabled. + */ + msr.hi |= 1 << (36 - 32); + } + wrmsr(NB_CFG_MSR, msr); + } /* Erratum 97 ... */ if (!is_cpu_pre_c0()) { @@ -158,11 +398,14 @@ void k8_cpufixup(struct mem_range *mem) msr.lo |= 1 << 11; wrmsr_amd(IC_CFG_MSR, msr); -#endif - /* Erratum 91 prefetch miss is handled in the kernel */ enable_cache(); + + /* Is this a bad location? In particular can another node prefecth + * data from this node before we have initialized it? + */ + init_ecc_memory(); } static diff --git a/src/cpu/k8/earlymtrr.c b/src/cpu/k8/earlymtrr.c index 47ddd12340..5fb63d2e7d 100644 --- a/src/cpu/k8/earlymtrr.c +++ b/src/cpu/k8/earlymtrr.c @@ -6,7 +6,7 @@ static void early_mtrr_init(void) { - static unsigned long mtrr_msrs[] = { + static const unsigned long mtrr_msrs[] = { /* fixed mtrr */ 0x250, 0x258, 0x259, 0x268, 0x269, 0x26A @@ -25,46 +25,46 @@ static void early_mtrr_init(void) 0 }; msr_t msr; - unsigned long *msr_addr; + const unsigned long *msr_addr; /* Inialize all of the relevant msrs to 0 */ msr.lo = 0; msr.hi = 0; - for(msr_addr = &mtrr_msrs; *msr_addr; msr_addr++) { + for(msr_addr = mtrr_msrs; *msr_addr; msr_addr++) { wrmsr(*msr_addr, msr); } - /* Enable memory access for 0 - 8MB using top_mem */ + /* Enable memory access for 0 - 1MB using top_mem */ msr.hi = 0; - msr.lo = 0x08000000; + msr.lo = ((CONFIG_LB_MEM_TOPK << 10) + TOP_MEM_MASK) & ~TOP_MEM_MASK; wrmsr(TOP_MEM, msr); - /* Enable caching for 0 - 128MB using variable mtrr */ + /* Enable caching for 0 - 1MB using variable mtrr */ msr = rdmsr(0x200); msr.hi &= 0xfffffff0; msr.hi |= 0x00000000; msr.lo &= 0x00000f00; - msr.lo |= 0x00000006; + msr.lo |= 0x00000000 | MTRR_TYPE_WRBACK; wrmsr(0x200, msr); msr = rdmsr(0x201); msr.hi &= 0xfffffff0; msr.hi |= 0x0000000f; msr.lo &= 0x000007ff; - msr.lo |= 0xf0000800; + msr.lo |= (~((CONFIG_LB_MEM_TOPK << 10) - 1)) | 0x800; wrmsr(0x201, msr); #if defined(XIP_ROM_SIZE) && defined(XIP_ROM_BASE) - /* enable write back caching so we can do execute in place + /* enable write through caching so we can do execute in place * on the flash rom. */ msr.hi = 0x00000000; - msr.lo = XIP_ROM_BASE | 0x005; - wrmsr(0x202); + msr.lo = XIP_ROM_BASE | MTRR_TYPE_WRTHROUGH; + wrmsr(0x202, msr); #error "FIXME verify the type of MTRR I have setup" msr.hi = 0x0000000f; msr.lo = ~(XIP_ROM_SIZE - 1) | 0x800; - wrmsr(0x203); + wrmsr(0x203, msr); #endif /* Set the default memory type and enable fixed and variable MTRRs @@ -72,7 +72,7 @@ static void early_mtrr_init(void) /* Enable Variable MTRRs */ msr.hi = 0x00000000; msr.lo = 0x00000800; - wrmsr(0x2ff, msr); + wrmsr(MTRRdefType_MSR, msr); /* Enale the MTRRs in SYSCFG */ msr = rdmsr(SYSCFG_MSR); diff --git a/src/cpu/k8/earlymtrr.inc b/src/cpu/k8/earlymtrr.inc index d14afb1a31..acc917be7d 100644 --- a/src/cpu/k8/earlymtrr.inc +++ b/src/cpu/k8/earlymtrr.inc @@ -1,7 +1,11 @@ #include + + /* Save off the BIST value */ + movl %eax, %ebp + /* The fixed and variable MTRRs are powered-up with random values, clear them to - * MTRR_TYPE_UNCACHABLE for safty reason + * MTRR_TYPE_UNCACHEABLE for safty reason */ earlymtrr_start: @@ -21,20 +25,20 @@ clear_fixed_var_mtrr: jmp clear_fixed_var_mtrr clear_fixed_var_mtrr_out: -/* enable memory access for 0 - 8MB using top_mem */ +/* enable memory access for 0 - 1MB using top_mem */ movl $TOP_MEM, %ecx xorl %edx, %edx - movl $0x0800000, %eax + movl $(((CONFIG_LB_MEM_TOPK << 10) + TOP_MEM_MASK) & ~TOP_MEM_MASK) , %eax wrmsr set_var_mtrr: - /* enable caching for 0 - 128MB using variable mtrr */ + /* enable caching for 0 - 1MB using variable mtrr */ movl $0x200, %ecx rdmsr andl $0xfffffff0, %edx orl $0x00000000, %edx andl $0x00000f00, %eax - orl $0x00000006, %eax + orl $(0x00000000 | MTRR_TYPE_WRBACK), %eax wrmsr movl $0x201, %ecx @@ -42,7 +46,7 @@ set_var_mtrr: andl $0xfffffff0, %edx orl $0x0000000f, %edx andl $0x000007ff, %eax - orl $0xf0000800, %eax + orl $((~((CONFIG_LB_MEM_TOPK << 10) - 1)) | 0x800), %eax wrmsr #if defined(XIP_ROM_SIZE) && defined(XIP_ROM_BASE) @@ -51,7 +55,7 @@ set_var_mtrr: */ movl $0x202, %ecx xorl %edx, %edx - movl $(XIP_ROM_BASE | 0x006), %eax + movl $(XIP_ROM_BASE | MTRR_TYPE_WRBACK), %eax wrmsr movl $0x203, %ecx @@ -62,7 +66,7 @@ set_var_mtrr: enable_mtrr: /* Set the default memory type and enable fixed and variable MTRRs */ - movl $0x2ff, %ecx + movl $MTRRdefType_MSR, %ecx xorl %edx, %edx /* Enable Variable MTRRs */ movl $0x00000800, %eax @@ -97,3 +101,5 @@ mem_top: .long 0xC001001A, 0xC001001D .long 0x000 /* NULL, end of table */ earlymtrr_end: + /* Restore the BIST value */ + movl %ebp, %eax \ No newline at end of file diff --git a/src/cpu/k8/enable_mmx_sse.inc b/src/cpu/k8/enable_mmx_sse.inc index 5551525d68..907e817325 100644 --- a/src/cpu/k8/enable_mmx_sse.inc +++ b/src/cpu/k8/enable_mmx_sse.inc @@ -1,3 +1,6 @@ + /* Save the BIST result */ + movl %eax, %ebp + /* * Enabling mmx registers is a noop * Enable the use of the xmm registers @@ -12,3 +15,6 @@ movl %cr4, %eax orl $(1<<9), %eax movl %eax, %cr4 + + /* Restore the BIST result */ + movl %ebp, %eax diff --git a/src/cpu/p6/Config.lb b/src/cpu/p6/Config.lb index c9d483480a..f6e9777bcd 100644 --- a/src/cpu/p6/Config.lb +++ b/src/cpu/p6/Config.lb @@ -3,4 +3,5 @@ uses INTEL_PPRO_MTRR dir /cpu/p5 object cpufixup.o object mtrr.o +object pgtbl.o #object l2_cache.o diff --git a/src/cpu/p6/boot_cpu.c b/src/cpu/p6/boot_cpu.c index 803eecdd5d..77b060b219 100644 --- a/src/cpu/p6/boot_cpu.c +++ b/src/cpu/p6/boot_cpu.c @@ -2,8 +2,6 @@ int boot_cpu(void) { - volatile unsigned long *local_apic; - unsigned long apic_id; int bsp; msr_t msr; msr = rdmsr(0x1b); diff --git a/src/cpu/p6/earlymtrr.c b/src/cpu/p6/earlymtrr.c index f352f3d791..df74f905c8 100644 --- a/src/cpu/p6/earlymtrr.c +++ b/src/cpu/p6/earlymtrr.c @@ -51,7 +51,7 @@ static void early_mtrr_init(void) /* Disable Variable MTRRs */ msr.hi = 0x00000000; msr.lo = 0x00000000; - wrmsr(0x2ff, msr); + wrmsr(MTRRdefType_MSR, msr); /* Invalidate the cache again */ asm volatile ("invd"); @@ -65,19 +65,19 @@ static void early_mtrr_init(void) wrmsr(*msr_addr, msr); } - /* Enable caching for 0 - 128MB using variable mtrr */ + /* Enable caching for 0 - 1MB using variable mtrr */ msr = rdmsr(0x200); msr.hi &= 0xfffffff0; msr.hi |= 0x00000000; msr.lo &= 0x00000f00; - msr.lo |= 0x00000006; + msr.lo |= 0x00000000 | MTRR_TYPE_WRBACK; wrmsr(0x200, msr); msr = rdmsr(0x201); msr.hi &= 0xfffffff0; msr.hi |= 0x0000000f; msr.lo &= 0x000007ff; - msr.lo |= 0xf0000800; + msr.lo |= (~((CONFIG_LB_MEM_TOPK << 10) - 1)) | 0x800; wrmsr(0x201, msr); #if defined(XIP_ROM_SIZE) && defined(XIP_ROM_BASE) @@ -98,7 +98,7 @@ static void early_mtrr_init(void) /* Enable Variable MTRRs */ msr.hi = 0x00000000; msr.lo = 0x00000800; - wrmsr(0x2ff, msr); + wrmsr(MTRRdefType_MSR, msr); /* Enable the cache */ cr0 = read_cr0(); diff --git a/src/cpu/p6/mtrr.c b/src/cpu/p6/mtrr.c index ac6fd1db37..7e2eb06e95 100644 --- a/src/cpu/p6/mtrr.c +++ b/src/cpu/p6/mtrr.c @@ -104,7 +104,8 @@ static void intel_set_var_mtrr(unsigned int reg, unsigned long basek, unsigned l if (sizek < 4*1024*1024) { mask.hi = ADDRESS_MASK_HIGH; mask.lo = ~((sizek << 10) -1); - } else { + } + else { mask.hi = ADDRESS_MASK_HIGH & (~((sizek >> 22) -1)); mask.lo = 0; } @@ -131,6 +132,36 @@ static void intel_set_var_mtrr(unsigned int reg, unsigned long basek, unsigned l enable_cache(); } +/* setting variable mtrr, comes from linux kernel source */ +void set_var_mtrr(unsigned int reg, unsigned long base, unsigned long size, unsigned char type) +{ + if (reg >= 8) + return; + + // it is recommended that we disable and enable cache when we + // do this. + disable_cache(); + if (size == 0) { + /* The invalid bit is kept in the mask, so we simply clear the + relevant mask register to disable a range. */ + msr_t zero; + zero.lo = zero.hi = 0; + wrmsr (MTRRphysMask_MSR(reg), zero); + } else { + /* Bit 32-35 of MTRRphysMask should be set to 1 */ + msr_t basem, maskm; + basem.lo = base | type; + basem.hi = 0; + maskm.lo = ~(size - 1) | 0x800; + maskm.hi = 0x0F; + wrmsr (MTRRphysBase_MSR(reg), basem); + wrmsr (MTRRphysMask_MSR(reg), maskm); + } + + // turn cache back on. + enable_cache(); +} + /* fms: find most sigificant bit set, stolen from Linux Kernel Source. */ static inline unsigned int fms(unsigned int x) { @@ -250,7 +281,7 @@ static unsigned int range_to_mtrr(unsigned int reg, } sizek = 1 << align; printk_debug("Setting variable MTRR %d, base: %4dMB, range: %4dMB, type WB\n", - reg, range_startk >>10, sizek >> 10); + reg, range_startk >>10, sizek >> 10); intel_set_var_mtrr(reg++, range_startk, sizek, MTRR_TYPE_WRBACK); range_startk += sizek; range_sizek -= sizek; @@ -274,7 +305,7 @@ void setup_mtrrs(struct mem_range *mem) /* Initialized the fixed_mtrrs to uncached */ printk_debug("Setting fixed MTRRs(%d-%d) type: UC\n", 0, NUM_FIXED_RANGES); - set_fixed_mtrrs(0, NUM_FIXED_RANGES, MTRR_TYPE_UNCACHABLE); + set_fixed_mtrrs(0, NUM_FIXED_RANGES, MTRR_TYPE_UNCACHEABLE); /* Now see which of the fixed mtrrs cover ram. */ diff --git a/src/cpu/p6/pgtbl.c b/src/cpu/p6/pgtbl.c new file mode 100644 index 0000000000..e996dd0e69 --- /dev/null +++ b/src/cpu/p6/pgtbl.c @@ -0,0 +1,91 @@ +#include +#include +#include + +static void paging_off(void) +{ + __asm__ __volatile__ ( + /* Disable paging */ + "movl %%cr0, %%eax\n\t" + "andl $0x7FFFFFFF, %%eax\n\t" + "movl %%eax, %%cr0\n\t" + /* Disable pae */ + "movl %%cr4, %%eax\n\t" + "andl $0xFFFFFFDF, %%eax\n\t" + : + : + : "eax" + ); +} + +static void paging_on(void *pdp) +{ + __asm__ __volatile__( + /* Load the page table address */ + "movl %0, %%cr3\n\t" + /* Enable pae */ + "movl %%cr4, %%eax\n\t" + "orl $0x00000020, %%eax\n\t" + "movl %%eax, %%cr4\n\t" + /* Enable paging */ + "movl %%cr0, %%eax\n\t" + "orl $0x80000000, %%eax\n\t" + "movl %%eax, %%cr0\n\t" + : + : "r" (pdp) + : "eax" + ); +} + +void *map_2M_page(int cpu_index, unsigned long page) +{ + struct pde { + uint32_t addr_lo; + uint32_t addr_hi; + } __attribute__ ((packed)); + struct pg_table { + struct pde pd[2048]; + struct pde pdp[512]; + } __attribute__ ((packed)); + static struct pg_table pgtbl[CONFIG_MAX_CPUS] __attribute__ ((aligned(4096))); + static unsigned long mapped_window[CONFIG_MAX_CPUS]; + unsigned long window; + void *result; + int i; + if ((cpu_index < 0) || (cpu_index >= CONFIG_MAX_CPUS)) { + return MAPPING_ERROR; + } + window = page >> 10; + if (window != mapped_window[cpu_index]) { + paging_off(); + if (window > 1) { + struct pde *pd, *pdp; + /* Point the page directory pointers at the page directories */ + memset(&pgtbl[cpu_index].pdp, 0, sizeof(pgtbl[cpu_index].pdp)); + pd = pgtbl[cpu_index].pd; + pdp = pgtbl[cpu_index].pdp; + pdp[0].addr_lo = ((uint32_t)&pd[512*0])|1; + pdp[1].addr_lo = ((uint32_t)&pd[512*1])|1; + pdp[2].addr_lo = ((uint32_t)&pd[512*2])|1; + pdp[3].addr_lo = ((uint32_t)&pd[512*3])|1; + /* The first half of the page table is identity mapped */ + for(i = 0; i < 1024; i++) { + pd[i].addr_lo = ((i & 0x3ff) << 21)| 0xE3; + pd[i].addr_hi = 0; + } + /* The second half of the page table holds the mapped page */ + for(i = 1024; i < 2048; i++) { + pd[i].addr_lo = ((window & 1) << 31) | ((i & 0x3ff) << 21) | 0xE3; + pd[i].addr_hi = (window >> 1); + } + paging_on(pdp); + } + mapped_window[cpu_index] = window; + } + if (window == 0) { + result = (void *)(page << 21); + } else { + result = (void *)(0x80000000 | ((page & 0x3ff) << 21)); + } + return result; +} diff --git a/src/devices/Config.lb b/src/devices/Config.lb index 6da04ee2e4..50d05579e5 100644 --- a/src/devices/Config.lb +++ b/src/devices/Config.lb @@ -2,5 +2,6 @@ object device.o object root_device.o object device_util.o object pci_device.o +object pnp_device.o object hypertransport.o object chip.o diff --git a/src/devices/chip.c b/src/devices/chip.c index c9e1ac5643..d8a59e3062 100644 --- a/src/devices/chip.c +++ b/src/devices/chip.c @@ -80,6 +80,7 @@ void chip_enumerate(struct chip *chip) link += 1; } if (dev) { + struct chip_resource *res, *res_limit; printk_spew("path (%p) %s %s", dev, dev_path(dev), identical_paths?"identical":""); printk_spew(" parent: (%p) %s\n",dev->bus->dev, dev_path(dev->bus->dev)); dev->chip = chip; @@ -90,6 +91,16 @@ void chip_enumerate(struct chip *chip) child->bus = &dev->link[link]; } } + res = &chip->path[i].resource[0]; + res_limit = &chip->path[i].resource[MAX_RESOURCES]; + for(; res < res_limit; res++) { + if (res->flags) { + struct resource *resource; + resource = get_resource(dev, res->index); + resource->flags = res->flags | IORESOURCE_FIXED | IORESOURCE_ASSIGNED; + resource->base = res->base; + } + } } if (dev && !chip->dev) { chip->dev = dev; diff --git a/src/devices/device.c b/src/devices/device.c index 4f1cbb2c5d..b54e770294 100644 --- a/src/devices/device.c +++ b/src/devices/device.c @@ -23,9 +23,9 @@ #include /* Linked list of ALL devices */ -struct device *all_devices = 0; +struct device *all_devices = &dev_root; /* pointer to the last device */ -static struct device **last_dev_p = &all_devices; +static struct device **last_dev_p = &dev_root.next; #define DEVICE_MEM_HIGH 0xFEC00000UL /* Reserve 20M for the system */ #define DEVICE_IO_START 0x1000 @@ -323,7 +323,8 @@ void compute_allocate_resource( /* base must be aligned to size */ base = round(base, 1UL << align); resource->base = base; - resource->flags |= IORESOURCE_SET; + resource->flags |= IORESOURCE_ASSIGNED; + resource->flags &= ~IORESOURCE_STORED; base += size; printk_spew( @@ -459,19 +460,24 @@ void dev_configure(void) * safe. */ root->resource[0].base = DEVICE_IO_START; - root->resource[0].flags |= IORESOURCE_SET; + root->resource[0].flags |= IORESOURCE_ASSIGNED; + root->resource[0].flags &= ~IORESOURCE_STORED; /* Now reallocate the pci resources memory with the * highest addresses I can manage. */ root->resource[1].base = round_down(DEVICE_MEM_HIGH - root->resource[1].size, 1UL << root->resource[1].align); - root->resource[1].flags |= IORESOURCE_SET; + root->resource[1].flags |= IORESOURCE_ASSIGNED; + root->resource[1].flags &= ~IORESOURCE_STORED; + + /* Allocate the VGA I/O resource.. + */ + allocate_vga_resource(); + // now just set things into registers ... we hope ... root->ops->set_resources(root); - allocate_vga_resource(); - printk_info("done.\n"); } diff --git a/src/devices/device_util.c b/src/devices/device_util.c index c806726853..013501474c 100644 --- a/src/devices/device_util.c +++ b/src/devices/device_util.c @@ -34,7 +34,8 @@ struct device *dev_find_slot(unsigned int bus, unsigned int devfn) result = 0; for (dev = all_devices; dev; dev = dev->next) { - if ((dev->bus->secondary == bus) && + if ((dev->path.type == DEVICE_PATH_PCI) && + (dev->bus->secondary == bus) && (dev->path.u.pci.devfn == devfn)) { result = dev; break; @@ -57,8 +58,9 @@ struct device *dev_find_device(unsigned int vendor, unsigned int device, struct from = all_devices; else from = from->next; - while (from && (from->vendor != vendor || from->device != device)) + while (from && (from->vendor != vendor || from->device != device)) { from = from->next; + } return from; } @@ -142,3 +144,70 @@ int path_eq(struct device_path *path1, struct device_path *path2) } return equal; } + +/** + * See if we have unused but allocated resource structures. + * If so remove the allocation. + * @param dev The device to find the resource on + */ +void compact_resources(device_t dev) +{ + struct resource *resource; + int i; + /* Move all of the free resources to the end */ + for(i = 0; i < dev->resources;) { + resource = &dev->resource[i]; + if (!resource->flags) { + memmove(resource, resource + 1, dev->resources - i); + dev->resources -= 1; + memset(&dev->resource[dev->resources], 0, sizeof(*resource)); + } else { + i++; + } + } +} + +/** + * See if a resource structure already exists for a given index and if + * not allocate one. + * @param dev The device to find the resource on + * @param index The index of the resource on the device. + */ +struct resource *get_resource(device_t dev, unsigned index) +{ + struct resource *resource; + int i; + + /* First move all of the free resources to the end */ + compact_resources(dev); + + /* See if there is a resource with the appropriate index */ + resource = 0; + for(i = 0; i < dev->resources; i++) { + if (dev->resource[i].index == index) { + resource = &dev->resource[i]; + break; + } + } + if (!resource) { + if (dev->resources == MAX_RESOURCES) { + die("MAX_RESOURCES exceeded."); + } + resource = &dev->resource[dev->resources]; + memset(resource, 0, sizeof(*resource)); + dev->resources++; + } + /* Initialize the resource values */ + if (!(resource->flags & IORESOURCE_FIXED)) { + resource->flags = 0; + resource->base = 0; + } + resource->size = 0; + resource->limit = 0; + resource->index = index; + resource->align = 0; + resource->gran = 0; + + return resource; +} + diff --git a/src/devices/hypertransport.c b/src/devices/hypertransport.c index b65f518d3a..e50ebf6f20 100644 --- a/src/devices/hypertransport.c +++ b/src/devices/hypertransport.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,30 @@ static device_t ht_scan_get_devs(device_t *old_devices) return first; } +static unsigned ht_read_freq_cap(device_t dev, unsigned pos) +{ + /* Handle bugs in valid hypertransport frequency reporting */ + unsigned freq_cap; + + freq_cap = pci_read_config16(dev, pos); + freq_cap &= ~(1 << HT_FREQ_VENDOR); /* Ignore Vendor HT frequencies */ + + /* AMD 8131 Errata 48 */ + if ((dev->vendor == PCI_VENDOR_ID_AMD) && + (dev->device == PCI_DEVICE_ID_AMD_8131_PCIX)) { + freq_cap &= ~(1 << HT_FREQ_800Mhz); + } + /* AMD 8151 Errata 23 */ + if ((dev->vendor == PCI_VENDOR_ID_AMD) && + (dev->device == PCI_DEVICE_ID_AMD_8151_SYSCTRL)) { + freq_cap &= ~(1 << HT_FREQ_800Mhz); + } + /* AMD K8 Unsupported 1Ghz? */ + if ((dev->vendor == PCI_VENDOR_ID_AMD) && (dev->device == 0x1100)) { + freq_cap &= ~(1 << HT_FREQ_1000Mhz); + } + return freq_cap; +} struct prev_link { struct device *dev; @@ -48,18 +73,13 @@ static int ht_setup_link(struct prev_link *prev, device_t dev, unsigned pos) reset_needed = 0; /* Read the capabilities */ - present_freq_cap = pci_read_config16(dev, pos + PCI_HT_CAP_SLAVE_FREQ_CAP0); - upstream_freq_cap = pci_read_config16(prev->dev, prev->pos + prev->freq_cap_off); + present_freq_cap = ht_read_freq_cap(dev, pos + PCI_HT_CAP_SLAVE_FREQ_CAP0); + upstream_freq_cap = ht_read_freq_cap(prev->dev, prev->pos + prev->freq_cap_off); present_width_cap = pci_read_config8(dev, pos + PCI_HT_CAP_SLAVE_WIDTH0); upstream_width_cap = pci_read_config8(prev->dev, prev->pos + prev->config_off); /* Calculate the highest useable frequency */ -#if 0 freq = log2(present_freq_cap & upstream_freq_cap); -#else - /* Errata for 8131 - freq 5 has hardware problems don't support it */ - freq = log2(present_freq_cap & upstream_freq_cap & 0x1f); -#endif /* Calculate the highest width */ ln_upstream_width_in = link_width_to_pow2[upstream_width_cap & 7]; @@ -144,9 +164,7 @@ static unsigned ht_lookup_slave_capability(struct device *dev) break; } } - if(pos) { - pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT); - } + pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT); } return pos; } @@ -244,9 +262,12 @@ unsigned int hypertransport_scan_chain(struct bus *bus, unsigned int max) else { /* Add this device to the pci bus chain */ *chain_last = dev; - /* Run the magice enable/disable sequence for the device */ + /* Run the magice enable sequence for the device */ if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) { + int enable = dev->enable; + dev->enable = 1; dev->chip->control->enable_dev(dev); + dev->enable = enable; } /* Now read the vendor and device id */ id = pci_read_config32(dev, PCI_VENDOR_ID); @@ -320,9 +341,11 @@ unsigned int hypertransport_scan_chain(struct bus *bus, unsigned int max) #if HAVE_HARD_RESET == 1 if(reset_needed) { printk_info("HyperT reset needed\n"); -// By LYH hard_reset(); - } else - printk_debug("HyperT reset not needed\n"); + hard_reset(); + } + else { + printk_debug("HyperT reset not needed\n"); + } #endif if (next_unitid > 0x1f) { next_unitid = 0x1f; diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c index 734b982a6d..c3f1f6ac8c 100644 --- a/src/devices/pci_device.c +++ b/src/devices/pci_device.c @@ -27,19 +27,14 @@ * @param resource Pointer to the resource structure * @param index Address of the pci configuration register */ -static void pci_get_resource(struct device *dev, struct resource *resource, unsigned long index) +static struct resource *pci_get_resource(struct device *dev, unsigned long index) { + struct resource *resource; uint32_t addr, size, base; unsigned long type; /* Initialize the resources to nothing */ - resource->base = 0; - resource->size = 0; - resource->align = 0; - resource->gran = 0; - resource->limit = 0; - resource->flags = 0; - resource->index = index; + resource = get_resource(dev, index); addr = pci_read_config32(dev, index); @@ -87,7 +82,7 @@ static void pci_get_resource(struct device *dev, struct resource *resource, unsi resource->size = (~((size | 0xffff0000) & PCI_BASE_ADDRESS_IO_MASK)) +1; resource->align = log2(resource->size); resource->gran = resource->align; - resource->flags = IORESOURCE_IO; + resource->flags |= IORESOURCE_IO; resource->limit = 0xffff; } else { @@ -96,7 +91,7 @@ static void pci_get_resource(struct device *dev, struct resource *resource, unsi resource->size = (~(size &PCI_BASE_ADDRESS_MEM_MASK)) +1; resource->align = log2(resource->size); resource->gran = resource->align; - resource->flags = IORESOURCE_MEM; + resource->flags |= IORESOURCE_MEM; if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { resource->flags |= IORESOURCE_PREFETCH; } @@ -145,7 +140,7 @@ static void pci_get_resource(struct device *dev, struct resource *resource, unsi } } /* dev->size holds the flags... */ - return; + return resource; } /** Read the base address registers for a given device. @@ -154,75 +149,63 @@ static void pci_get_resource(struct device *dev, struct resource *resource, unsi */ static void pci_read_bases(struct device *dev, unsigned int howmany) { - unsigned int reg; unsigned long index; - reg = dev->resources; - for(index = PCI_BASE_ADDRESS_0; - (reg < MAX_RESOURCES) && (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) { + for(index = PCI_BASE_ADDRESS_0; (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) { struct resource *resource; - resource = &dev->resource[reg]; - pci_get_resource(dev, resource, index); - reg += (resource->flags & (IORESOURCE_IO | IORESOURCE_MEM))? 1:0; + resource = pci_get_resource(dev, index); index += (resource->flags & IORESOURCE_PCI64)?8:4; } - dev->resources = reg; + compact_resources(dev); } static void pci_bridge_read_bases(struct device *dev) { - unsigned int reg = dev->resources; + struct resource *resource; /* FIXME handle bridges without some of the optional resources */ /* Initialize the io space constraints on the current bus */ - dev->resource[reg].base = 0; - dev->resource[reg].size = 0; - dev->resource[reg].align = log2(PCI_IO_BRIDGE_ALIGN); - dev->resource[reg].gran = log2(PCI_IO_BRIDGE_ALIGN); - dev->resource[reg].limit = 0xffffUL; - dev->resource[reg].flags = IORESOURCE_IO | IORESOURCE_PCI_BRIDGE; - dev->resource[reg].index = PCI_IO_BASE; - compute_allocate_resource(&dev->link[0], &dev->resource[reg], + resource = get_resource(dev, PCI_IO_BASE); + resource->size = 0; + resource->align = log2(PCI_IO_BRIDGE_ALIGN); + resource->gran = log2(PCI_IO_BRIDGE_ALIGN); + resource->limit = 0xffffUL; + resource->flags |= IORESOURCE_IO | IORESOURCE_PCI_BRIDGE; + compute_allocate_resource(&dev->link[0], resource, IORESOURCE_IO, IORESOURCE_IO); - reg++; /* Initiliaze the prefetchable memory constraints on the current bus */ - dev->resource[reg].base = 0; - dev->resource[reg].size = 0; - dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN); - dev->resource[reg].gran = log2(PCI_MEM_BRIDGE_ALIGN); - dev->resource[reg].limit = 0xffffffffUL; - dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_PCI_BRIDGE; - dev->resource[reg].index = PCI_PREF_MEMORY_BASE; - compute_allocate_resource(&dev->link[0], &dev->resource[reg], + resource = get_resource(dev, PCI_PREF_MEMORY_BASE); + resource->size = 0; + resource->align = log2(PCI_MEM_BRIDGE_ALIGN); + resource->gran = log2(PCI_MEM_BRIDGE_ALIGN); + resource->limit = 0xffffffffUL; + resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_PCI_BRIDGE; + resource->index = PCI_PREF_MEMORY_BASE; + compute_allocate_resource(&dev->link[0], resource, IORESOURCE_MEM | IORESOURCE_PREFETCH, IORESOURCE_MEM | IORESOURCE_PREFETCH); - reg++; /* Initialize the memory resources on the current bus */ - dev->resource[reg].base = 0; - dev->resource[reg].size = 0; - dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN); - dev->resource[reg].gran = log2(PCI_MEM_BRIDGE_ALIGN); - dev->resource[reg].limit = 0xffffffffUL; - dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PCI_BRIDGE; - dev->resource[reg].index = PCI_MEMORY_BASE; - compute_allocate_resource(&dev->link[0], &dev->resource[reg], - IORESOURCE_MEM | IORESOURCE_PREFETCH, + resource = get_resource(dev, PCI_MEMORY_BASE); + resource->size = 0; + resource->align = log2(PCI_MEM_BRIDGE_ALIGN); + resource->gran = log2(PCI_MEM_BRIDGE_ALIGN); + resource->limit = 0xffffffffUL; + resource->flags = IORESOURCE_MEM | IORESOURCE_PCI_BRIDGE; + compute_allocate_resource(&dev->link[0], resource, + IORESOURCE_MEM | IORESOURCE_PREFETCH, IORESOURCE_MEM); - reg++; - dev->resources = reg; + compact_resources(dev); } void pci_dev_read_resources(struct device *dev) { uint32_t addr; - dev->resources = 0; - memset(&dev->resource[0], 0, sizeof(dev->resource)); pci_read_bases(dev, 6); addr = pci_read_config32(dev, PCI_ROM_ADDRESS); dev->rom_address = (addr == 0xffffffff)? 0 : addr; @@ -231,8 +214,6 @@ void pci_dev_read_resources(struct device *dev) void pci_bus_read_resources(struct device *dev) { uint32_t addr; - dev->resources = 0; - memset(&dev->resource, 0, sizeof(dev->resource)); pci_bridge_read_bases(dev); pci_read_bases(dev, 2); @@ -246,10 +227,10 @@ static void pci_set_resource(struct device *dev, struct resource *resource) { unsigned long base, limit; unsigned char buf[10]; - unsigned long align; + unsigned long gran; /* Make certain the resource has actually been set */ - if (!(resource->flags & IORESOURCE_SET)) { + if (!(resource->flags & IORESOURCE_ASSIGNED)) { #if 1 printk_err("ERROR: %s %02x not allocated\n", dev_path(dev), resource->index); @@ -257,6 +238,11 @@ static void pci_set_resource(struct device *dev, struct resource *resource) return; } + /* If I have already stored this resource don't worry about it */ + if (resource->flags & IORESOURCE_STORED) { + return; + } + /* Only handle PCI memory and IO resources for now */ if (!(resource->flags & (IORESOURCE_MEM |IORESOURCE_IO))) return; @@ -272,12 +258,20 @@ static void pci_set_resource(struct device *dev, struct resource *resource) } /* Get the base address */ base = resource->base; - /* Get the resource alignment */ - align = 1UL << resource->align; + /* Get the resource granularity */ + gran = 1UL << resource->gran; + + /* For a non bridge resource granularity and alignment are the same. + * For a bridge resource align is the largest needed alignment below + * the bridge. While the granularity is simply how many low bits of the + * address cannot be set. + */ /* Get the limit (rounded up) */ - limit = base + ((resource->size + align - 1UL) & ~(align - 1UL)) -1UL; + limit = base + ((resource->size + gran - 1UL) & ~(gran - 1UL)) -1UL; + /* Now store the resource */ + resource->flags |= IORESOURCE_STORED; if (!(resource->flags & IORESOURCE_PCI_BRIDGE)) { /* * some chipsets allow us to set/clear the IO bit. @@ -326,6 +320,8 @@ static void pci_set_resource(struct device *dev, struct resource *resource) pci_write_config32(dev, PCI_PREF_LIMIT_UPPER32, 0); } else { + /* Don't let me think I stored the resource */ + resource->flags &= ~IORESOURCE_STORED; printk_err("ERROR: invalid resource->index %x\n", resource->index); } @@ -386,6 +382,7 @@ void pci_dev_enable_resources(struct device *dev) uint16_t command; command = pci_read_config16(dev, PCI_COMMAND); command |= dev->command; + command |= (PCI_COMMAND_PARITY + PCI_COMMAND_SERR); /* error check */ printk_debug("%s cmd <- %02x\n", dev_path(dev), command); pci_write_config16(dev, PCI_COMMAND, command); @@ -397,6 +394,7 @@ void pci_bus_enable_resources(struct device *dev) uint16_t ctrl; ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL); ctrl |= dev->link[0].bridge_ctrl; + ctrl |= (PCI_BRIDGE_CTL_PARITY + PCI_BRIDGE_CTL_SERR); /* error check */ printk_debug("%s bridge ctrl <- %04x\n", dev_path(dev), ctrl); pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl); @@ -560,9 +558,12 @@ unsigned int pci_scan_bus(struct bus *bus, dev = alloc_dev(bus, &dummy.path); } else { - /* Run the magic enable/disable sequence for the device */ + /* Run the magic enable sequence for the device */ if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) { + int enable = dev->enable; + dev->enable = 1; dev->chip->control->enable_dev(dev); + dev->enable = enable; } /* Now read the vendor and device id */ id = pci_read_config32(dev, PCI_VENDOR_ID); @@ -584,7 +585,7 @@ unsigned int pci_scan_bus(struct bus *bus, */ set_pci_ops(dev); /* Error if we don't have some pci operations for it */ - if (dev->enable && !dev->ops) { + if (!dev->ops) { printk_err("%s No device operations\n", dev_path(dev)); continue; @@ -594,6 +595,9 @@ unsigned int pci_scan_bus(struct bus *bus, if (dev->ops && dev->ops->enable) { dev->ops->enable(dev); } + else if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) { + dev->chip->control->enable_dev(dev); + } printk_debug("%s [%04x/%04x] %s\n", dev_path(dev), diff --git a/src/devices/pnp_device.c b/src/devices/pnp_device.c new file mode 100644 index 0000000000..0bccd7d151 --- /dev/null +++ b/src/devices/pnp_device.c @@ -0,0 +1,217 @@ +/* Copyright 2004 Linux Networx */ +/* This code is distrubted wihtout warrant under the GPL v2 (see COPYING) */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* PNP fundamental operations */ + +void pnp_write_config(device_t dev, uint8_t reg, uint8_t value) +{ + outb(reg, dev->path.u.pnp.port); + outb(value, dev->path.u.pnp.port + 1); +} + +uint8_t pnp_read_config(device_t dev, uint8_t reg) +{ + outb(reg, dev->path.u.pnp.port); + return inb(dev->path.u.pnp.port + 1); +} + +void pnp_set_logical_device(device_t dev) +{ + pnp_write_config(dev, 0x07, dev->path.u.pnp.device); +} + +void pnp_set_enable(device_t dev, int enable) +{ + pnp_write_config(dev, 0x30, enable?0x1:0x0); +} + +int pnp_read_enable(device_t dev) +{ + return !!pnp_read_config(dev, 0x30); +} + +void pnp_set_iobase(device_t dev, unsigned index, unsigned iobase) +{ + /* Index == 0x60 or 0x62 */ + pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff); + pnp_write_config(dev, index + 1, iobase & 0xff); +} + +void pnp_set_irq(device_t dev, unsigned index, unsigned irq) +{ + /* Index == 0x70 or 0x72 */ + pnp_write_config(dev, index, irq); +} + + +void pnp_set_drq(device_t dev, unsigned drq, unsigned index) +{ + /* Index == 0x74 */ + pnp_write_config(dev, index, drq & 0xff); +} + +/* PNP device operations */ + +void pnp_read_resources(device_t dev) +{ + return; +} + +static void pnp_set_resource(device_t dev, struct resource *resource) +{ + if (!(resource->flags & IORESOURCE_ASSIGNED)) { +#if 1 + printk_err("ERROR: %s %02x not allocated\n", + dev_path(dev), resource->index); +#endif + return; + } + /* Now store the resource */ + resource->flags |= IORESOURCE_STORED; + if (resource->flags & IORESOURCE_IO) { + pnp_set_iobase(dev, resource->index, resource->base); + } + else if (resource->flags & IORESOURCE_DRQ) { + pnp_set_drq(dev, resource->index, resource->base); + } + else if (resource->flags & IORESOURCE_IRQ) { + pnp_set_irq(dev, resource->index, resource->base); + } + else { + /* Don't let me think I stored the resource */ + resource->flags &= IORESOURCE_STORED; + printk_err("ERROR: %s %02x unknown resource type\n", + dev_path(dev), resource->index); + return; + } + + printk_debug( + "%s %02x <- [0x%08lx - 0x%08lx] %s\n", + dev_path(dev), + resource->index, + resource->base, resource->base + resource->size - 1, + (resource->flags & IORESOURCE_IO)? "io": + (resource->flags & IORESOURCE_DRQ)? "drq": + (resource->flags & IORESOURCE_IRQ)? "irq": + (resource->flags & IORESOURCE_MEM)? "mem": + "???"); +} + +void pnp_set_resources(device_t dev) +{ + int i; + + /* Select the device */ + pnp_set_logical_device(dev); + + /* Paranoia says I should disable the device here... */ + for(i = 0; i < dev->resources; i++) { + pnp_set_resource(dev, &dev->resource[i]); + } +} + +void pnp_enable_resources(device_t dev) +{ + pnp_set_logical_device(dev); + pnp_set_enable(dev, 1); + +} + +void pnp_enable(device_t dev) +{ + pnp_set_logical_device(dev); + if (!dev->enable) { + pnp_set_enable(dev, 0); + } +} + +struct device_operations pnp_ops = { + .read_resources = pnp_read_resources, + .set_resources = pnp_set_resources, + .enable_resources = pnp_enable_resources, + .enable = pnp_enable, +}; + +/* PNP chip opertations */ + +static void pnp_get_ioresource(device_t dev, unsigned index, struct io_info *info) +{ + struct resource *resource; + uint32_t size; + resource = get_resource(dev, index); + + /* Initilize the resource */ + resource->limit = 0xffff; + resource->flags |= IORESOURCE_IO; + + /* Set the resource size and alignment */ + size = (0xffff & info->mask); + resource->size = (~(size | 0xfffff800) + 1); + resource->align = log2(resource->size); + resource->gran = resource->align; +} + +static void get_resources(device_t dev, struct pnp_info *info) +{ + struct resource *resource; + + pnp_set_logical_device(dev); + + if (info->flags & PNP_IO0) { + pnp_get_ioresource(dev, PNP_IDX_IO0, &info->io0); + } + if (info->flags & PNP_IO1) { + pnp_get_ioresource(dev, PNP_IDX_IO1, &info->io1); + } + if (info->flags & PNP_IRQ0) { + resource = get_resource(dev, PNP_IDX_IRQ0); + resource->size = 1; + resource->flags |= IORESOURCE_IRQ; + } + if (info->flags & PNP_IRQ1) { + resource = get_resource(dev, PNP_IDX_IRQ1); + resource->size = 1; + resource->flags |= IORESOURCE_IRQ; + } + if (info->flags & PNP_DRQ0) { + resource = get_resource(dev, PNP_IDX_DRQ0); + resource->size = 1; + resource->flags |= IORESOURCE_DRQ; + } + if (info->flags & PNP_DRQ1) { + resource = get_resource(dev, PNP_IDX_DRQ1); + resource->size = 1; + resource->flags |= IORESOURCE_DRQ; + } + +} + +void pnp_enumerate(struct chip *chip, unsigned functions, + struct device_operations *ops, struct pnp_info *info) +{ + struct device_path path; + device_t dev; + int i; + + chip_enumerate(chip); + path.type = DEVICE_PATH_PNP; + path.u.pnp.port = chip->dev->path.u.pnp.port; + + /* Setup the ops and resources on the newly allocated devices */ + for(i = 0; i < functions; i++) { + path.u.pnp.device = info[i].function; + dev = alloc_find_dev(chip->bus, &path); + dev->ops = ops; + get_resources(dev, &info[i]); + } +} diff --git a/src/include/cpu/k8/mtrr.h b/src/include/cpu/k8/mtrr.h index 5a965eebb8..890820b12f 100644 --- a/src/include/cpu/k8/mtrr.h +++ b/src/include/cpu/k8/mtrr.h @@ -35,4 +35,7 @@ #define DC_CFG_MSR 0xC0011022 #define BU_CFG_MSR 0xC0011023 +#define TOP_MEM_MASK 0x007fffff +#define TOP_MEM_MASK_KB (TOP_MEM_MASK >> 10) + #endif /* CPU_K8_MTRR_H */ diff --git a/src/include/cpu/p6/mtrr.h b/src/include/cpu/p6/mtrr.h index 16af10b81b..92bf62e5c2 100644 --- a/src/include/cpu/p6/mtrr.h +++ b/src/include/cpu/p6/mtrr.h @@ -2,7 +2,7 @@ #define __LINUXBIOS_CPU_P6_MTRR_H /* These are the region types */ -#define MTRR_TYPE_UNCACHABLE 0 +#define MTRR_TYPE_UNCACHEABLE 0 #define MTRR_TYPE_WRCOMB 1 /*#define MTRR_TYPE_ 2*/ /*#define MTRR_TYPE_ 3*/ diff --git a/src/include/cpu/p6/pgtbl.h b/src/include/cpu/p6/pgtbl.h new file mode 100644 index 0000000000..68e327cd7a --- /dev/null +++ b/src/include/cpu/p6/pgtbl.h @@ -0,0 +1,7 @@ +#ifndef CPU_P6_PGTBL_H +#define CPU_P6_PGTBL_H + +#define MAPPING_ERROR ((void *)0xffffffffUL) +void *map_2M_page(int cpu_index, unsigned long page); + +#endif /* CPU_P6_PGTBL_H */ diff --git a/src/include/device/chip.h b/src/include/device/chip.h index dc078a96b7..7dface868f 100644 --- a/src/include/device/chip.h +++ b/src/include/device/chip.h @@ -1,6 +1,8 @@ #ifndef DEVICE_CHIP_H +#define DEVICE_CHIP_H #include +#include /* chips are arbitrary chips (superio, southbridge, etc.) * They have private structures that define chip resources and default @@ -16,21 +18,6 @@ #define CONFIGURE(pass) #endif -struct com_ports { - unsigned int enable,baud, base, irq; -}; - -/* lpt port description. - * Note that for many chips you only really need to define the - * enable. - */ -struct lpt_ports { - unsigned int enable, // 1 if this port is enabled - mode, // pp mode - base, // IO base of the parallel port - irq; // irq -}; - enum chip_pass { CONF_PASS_PRE_CONSOLE, CONF_PASS_PRE_PCI, @@ -60,11 +47,17 @@ struct chip_control { void (*enable_dev)(struct device *dev); }; +struct chip_resource { + unsigned long flags; + unsigned long index; + unsigned long base; +}; struct chip_device_path { struct device_path path; unsigned channel; int enable; + struct chip_resource resource[MAX_RESOURCES]; }; struct device; diff --git a/src/include/device/device.h b/src/include/device/device.h index 1b2b0169dc..20d9c22298 100644 --- a/src/include/device/device.h +++ b/src/include/device/device.h @@ -28,7 +28,7 @@ struct bus { unsigned char cap; /* PCi capability offset */ }; -#define MAX_RESOURCES 6 +#define MAX_RESOURCES 8 #define MAX_LINKS 3 /* * There is one device structure for each slot-number/function-number @@ -49,18 +49,6 @@ struct device { unsigned int enable : 1; /* set if we should enable the device */ uint8_t command; - /* - * In theory, the irq level can be read from configuration - * space and all would be fine. However, old PCI chips don't - * support these registers and return 0 instead. For example, - * the Vision864-P rev 0 chip can uses INTA, but returns 0 in - * the interrupt line and pin registers. pci_init() - * initializes this field with the value at PCI_INTERRUPT_LINE - * and it is the job of pcibios_fixup() to change it if - * necessary. The field must not be 0 unless the device - * cannot generate interrupts at all. - */ - unsigned int irq; /* irq generated by this device */ /* Base registers for this device, can be adjusted by * pcibios_fixup() as necessary. @@ -94,6 +82,8 @@ extern void assign_resources(struct bus *bus); extern void enable_resources(struct device *dev); extern void enumerate_static_device(void); extern const char *dev_path(device_t dev); +extern void compact_resources(device_t dev); +extern struct resource *get_resource(device_t dev, unsigned index); /* Helper functions */ device_t alloc_find_dev(struct bus *parent, struct device_path *path); diff --git a/src/include/device/hypertransport.h b/src/include/device/hypertransport.h index e342aeb506..410495cdcb 100644 --- a/src/include/device/hypertransport.h +++ b/src/include/device/hypertransport.h @@ -1,6 +1,8 @@ #ifndef DEVICE_HYPERTRANSPORT_H #define DEVICE_HYPERTRANSPORT_H +#include + unsigned int hypertransport_scan_chain(struct bus *bus, unsigned int max); #define HT_IO_HOST_ALIGN 4096 diff --git a/src/include/device/hypertransport_def.h b/src/include/device/hypertransport_def.h new file mode 100644 index 0000000000..0b44109f9f --- /dev/null +++ b/src/include/device/hypertransport_def.h @@ -0,0 +1,16 @@ +#ifndef DEVICE_HYPERTRANSPORT_DEF_H +#define DEVICE_HYPERTRANSPORT_DEF_H + +#define HT_FREQ_200Mhz 0 +#define HT_FREQ_300Mhz 1 +#define HT_FREQ_400Mhz 2 +#define HT_FREQ_500Mhz 3 +#define HT_FREQ_600Mhz 4 +#define HT_FREQ_800Mhz 5 +#define HT_FREQ_1000Mhz 6 +#define HT_FREQ_1200Mhz 7 +#define HT_FREQ_1400Mhz 8 +#define HT_FREQ_1600Mhz 9 +#define HT_FREQ_VENDOR 15 /* AMD defines this to be 100Mhz */ + +#endif /* DEVICE_HYPERTRANSPORT_DEF_H */ diff --git a/src/include/device/pci_def.h b/src/include/device/pci_def.h index ad8f1e6b88..46229a12f4 100644 --- a/src/include/device/pci_def.h +++ b/src/include/device/pci_def.h @@ -179,7 +179,9 @@ #define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ #define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ -#define PCI_CAP_ID_HT 0x08 +#define PCI_CAP_ID_PCIX 0x07 /* PCIX */ +#define PCI_CAP_ID_HT 0x08 /* Hypertransport */ +#define PCI_CAP_ID_PCIE 0x10 /* PCI Express */ #define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ #define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ diff --git a/src/include/device/pnp.h b/src/include/device/pnp.h index 0d39fc1663..508fac68ed 100644 --- a/src/include/device/pnp.h +++ b/src/include/device/pnp.h @@ -1,58 +1,49 @@ #ifndef DEVICE_PNP_H #define DEVICE_PNP_H -static inline void pnp_write_config(unsigned char port, unsigned char value, unsigned char reg) -{ - outb(reg, port); - outb(value, port +1); -} - -static inline unsigned char pnp_read_config(unsigned char port, unsigned char reg) -{ - outb(reg, port); - return inb(port +1); -} - -static inline void pnp_set_logical_device(unsigned char port, int device) -{ - pnp_write_config(port, device, 0x07); -} - -static inline void pnp_set_enable(unsigned char port, int enable) -{ - pnp_write_config(port, enable?0x1:0x0, 0x30); -} - -static inline int pnp_read_enable(unsigned char port) -{ - return !!pnp_read_config(port, 0x30); -} - -static inline void pnp_set_iobase0(unsigned char port, unsigned iobase) -{ - pnp_write_config(port, (iobase >> 8) & 0xff, 0x60); - pnp_write_config(port, iobase & 0xff, 0x61); -} - -static inline void pnp_set_iobase1(unsigned char port, unsigned iobase) -{ - pnp_write_config(port, (iobase >> 8) & 0xff, 0x62); - pnp_write_config(port, iobase & 0xff, 0x63); -} - -static inline void pnp_set_irq0(unsigned char port, unsigned irq) -{ - pnp_write_config(port, irq, 0x70); -} - -static inline void pnp_set_irq1(unsigned char port, unsigned irq) -{ - pnp_write_config(port, irq, 0x72); -} - -static inline void pnp_set_drq(unsigned char port, unsigned drq) -{ - pnp_write_config(port, drq & 0xff, 0x74); -} +#include +#include +#include +#include + +/* Primitive pnp resource manipulation */ +void pnp_write_config(device_t dev, uint8_t reg, uint8_t value); +uint8_t pnp_read_config(device_t dev, uint8_t reg); +void pnp_set_logical_device(device_t dev); +void pnp_set_enable(device_t dev, int enable); +int pnp_read_enable(device_t dev); +void pnp_set_iobase(device_t dev, unsigned index, unsigned iobase); +void pnp_set_irq(device_t dev, unsigned index, unsigned irq); +void pnp_set_drq(device_t dev, unsigned index, unsigned drq); + +/* PNP device operations */ +void pnp_read_resources(device_t dev); +void pnp_set_resources(device_t dev); +void pnp_enable_resources(device_t dev); +void pnp_enable(device_t dev); + +struct device_operations pnp_ops; + +/* PNP helper operations */ + +struct io_info { + unsigned mask, set; +}; + +struct pnp_info { + struct device_operations *ops; + unsigned function; + unsigned flags; +#define PNP_IO0 0x01 +#define PNP_IO1 0x02 +#define PNP_IRQ0 0x04 +#define PNP_IRQ1 0x08 +#define PNP_DRQ0 0x10 +#define PNP_DRQ1 0x20 + struct io_info io0, io1; +}; +struct resource *pnp_get_resource(device_t dev, unsigned index); +void pnp_enumerate(struct chip *chip, unsigned functions, + struct device_operations *ops, struct pnp_info *info); #endif /* DEVICE_PNP_H */ diff --git a/src/include/device/pnp_def.h b/src/include/device/pnp_def.h new file mode 100644 index 0000000000..b077837d02 --- /dev/null +++ b/src/include/device/pnp_def.h @@ -0,0 +1,12 @@ +#ifndef DEVICE_PNP_DEF_H +#define DEVICE_PNP_DEF_H + +#define PNP_IDX_IO0 0x60 +#define PNP_IDX_IO1 0x62 +#define PNP_IDX_IRQ0 0x70 +#define PNP_IDX_IRQ1 0x72 +#define PNP_IDX_DRQ0 0x74 +#define PNP_IDX_DRQ1 0x75 + + +#endif /* DEVICE_PNP_DEF_H */ diff --git a/src/include/device/resource.h b/src/include/device/resource.h index f90aba19f4..73a3f6e0d5 100644 --- a/src/include/device/resource.h +++ b/src/include/device/resource.h @@ -18,9 +18,9 @@ #define IORESOURCE_SUBTRACTIVE 0x00040000 /* This resource filters all of the unclaimed transactions * to the bus below. */ - -#define IORESOURCE_SET 0x80000000 /* An IO resource that has been assigned a value */ -#define IORESOURCE_FIXED 0x40000000 /* An IO resource the allocator must not change */ +#define IORESOURCE_STORED 0x20000000 /* The IO resource assignment has been stored in the device */ +#define IORESOURCE_ASSIGNED 0x40000000 /* An IO resource that has been assigned a value */ +#define IORESOURCE_FIXED 0x80000000 /* An IO resource the allocator must not change */ /* PCI specific resource bits */ #define IORESOURCE_PCI64 (1<<0) /* 64bit long pci resource */ diff --git a/src/include/pc80/keyboard.h b/src/include/pc80/keyboard.h new file mode 100644 index 0000000000..775dbee6e4 --- /dev/null +++ b/src/include/pc80/keyboard.h @@ -0,0 +1,10 @@ +#ifndef PC80_KEYBOARD_H +#define PC80_KEYBOARD_H + +struct pc_keyboard { + /* No initialization parameters for now */ +}; + +void init_pc_keyboard(unsigned port0, unsigned port1, struct pc_keyboard *kbd); + +#endif /* PC80_KEYBOARD_H */ diff --git a/src/include/pc80/mc146818rtc.h b/src/include/pc80/mc146818rtc.h index 1daf39aa25..e7e13c85b7 100644 --- a/src/include/pc80/mc146818rtc.h +++ b/src/include/pc80/mc146818rtc.h @@ -7,18 +7,6 @@ #define RTC_PORT(x) (RTC_BASE_PORT + (x)) -/* On PCs, the checksum is built only over bytes 16..45 */ -#define PC_CKS_RANGE_START 16 -#define PC_CKS_RANGE_END 45 -#define PC_CKS_LOC 46 - - -/* Linux bios checksum is built only over bytes 49..125 */ -#define LB_CKS_RANGE_START 49 -#define LB_CKS_RANGE_END 125 -#define LB_CKS_LOC 126 - - /* control registers - Moto names */ #define RTC_REG_A 10 @@ -88,22 +76,28 @@ # define RTC_VRT 0x80 /* valid RAM and time */ /**********************************************************************/ - /* On PCs, the checksum is built only over bytes 16..45 */ #define PC_CKS_RANGE_START 16 #define PC_CKS_RANGE_END 45 #define PC_CKS_LOC 46 +/* Linux bios checksum is built only over bytes 49..125 */ +#ifndef LB_CKS_RANGE_START #define LB_CKS_RANGE_START 49 +#endif +#ifndef LB_CKS_RANGE_END #define LB_CKS_RANGE_END 125 +#endif +#ifndef LB_CKS_LOC #define LB_CKS_LOC 126 +#endif #if !defined(ASSEMBLY) void rtc_init(int invalid); #if USE_OPTION_TABLE == 1 int get_option(void *dest, char *name); #else -#define get_option(dest, name) (-2) +static inline int get_option(void *dest, char *name) { return -2; } #endif #endif diff --git a/src/include/string.h b/src/include/string.h index cf9bbb14d2..111e23bc15 100644 --- a/src/include/string.h +++ b/src/include/string.h @@ -29,6 +29,7 @@ static inline size_t strlen(const char *src) } extern void *memcpy(void *dest, const void *src, size_t n); +extern void *memmove(void *dest, const void *src, size_t n); extern void *memset(void *s, int c, size_t n); extern int memcmp(const void *s1, const void *s2, size_t n); diff --git a/src/include/uart8250.h b/src/include/uart8250.h index ae45615758..f610026614 100644 --- a/src/include/uart8250.h +++ b/src/include/uart8250.h @@ -1,7 +1,13 @@ #ifndef UART8250_H #define UART8250_H +struct uart8250 { + unsigned int baud; + /* Do I need an lcs parameter here? */ +}; + void uart8250_tx_byte(unsigned base_port, unsigned char data); void uart8250_init(unsigned base_port, unsigned divisor, unsigned lcs); +void init_uart8250(unsigned base_port, struct uart8250 *uart); #endif /* UART8250_H */ diff --git a/src/lib/Config.lb b/src/lib/Config.lb index a0de47c570..bd6a2a9090 100644 --- a/src/lib/Config.lb +++ b/src/lib/Config.lb @@ -6,10 +6,11 @@ object uart8250.o object memset.o object memcpy.o object memcmp.o +object memmove.o object malloc.o object delay.o if HAVE_FALLBACK_BOOT - object fallback_boot.o + object fallback_boot.o end object compute_ip_checksum.o object version.o diff --git a/src/lib/memcpy.c b/src/lib/memcpy.c index ad8e8bd3f0..16db67766d 100644 --- a/src/lib/memcpy.c +++ b/src/lib/memcpy.c @@ -1,11 +1,12 @@ #include -void *memcpy(void *__dest, __const void *__src, size_t __n) +void *memcpy(void *vdest, const void *vsrc, size_t bytes) { + const char *src = vsrc; + char *dest = vdest; int i; - char *d = (char *) __dest, *s = (char *) __src; - for (i = 0; i < __n; i++) - d[i] = s[i]; + for (i = 0; i < bytes; i++) + dest[i] = src[i]; - return __dest; + return vdest; } diff --git a/src/lib/memmove.c b/src/lib/memmove.c new file mode 100644 index 0000000000..0a4908325e --- /dev/null +++ b/src/lib/memmove.c @@ -0,0 +1,20 @@ +#include +void *memmove(void *vdest, const void *vsrc, size_t count) +{ + const char *src = vsrc; + char *dest = vdest; + int i; + + if (dest <= src) { + while (count--) { + *dest++ = *src++; + } + } else { + src += count - 1; + dest += count - 1; + while(count--) { + *dest-- = *src--; + } + } + return vdest; +} diff --git a/src/lib/uart8250.c b/src/lib/uart8250.c index ceb4e4aa86..67b0a95cfb 100644 --- a/src/lib/uart8250.c +++ b/src/lib/uart8250.c @@ -58,3 +58,19 @@ void uart8250_init(unsigned base_port, unsigned divisor, unsigned lcs) outb((divisor >> 8) & 0xFF, base_port + UART_DLM); outb(lcs, base_port + UART_LCR); } + +/* Initialize a generic uart */ +void init_uart8250(unsigned base_port, struct uart8250 *uart) +{ + int divisor; + int lcs; + divisor = 115200/(uart->baud ? uart->baud: 1); + lcs = 3; + if (base_port == TTYS0_BASE) { + /* Don't reinitialize the console serial port, + * This is espeically nasty in SMP. + */ + return; + } + uart8250_init(base_port, divisor, lcs); +} diff --git a/src/mainboard/amd/quartet/Config.lb b/src/mainboard/amd/quartet/Config.lb index 1a2d8cd09f..d38ab96407 100644 --- a/src/mainboard/amd/quartet/Config.lb +++ b/src/mainboard/amd/quartet/Config.lb @@ -251,19 +251,29 @@ northbridge amd/amdk8 "mc0" pci 1:0.2 on pci 1:1.0 on superio NSC/pc87360 link 1 - pnp 2e.0 - pnp 2e.1 - pnp 2e.2 - pnp 2e.3 - pnp 2e.4 - pnp 2e.5 - pnp 2e.6 - pnp 2e.7 - pnp 2e.8 - pnp 2e.9 - pnp 2e.a - register "com1" = "{1, 0, 0x3f8, 4}" - register "lpt" = "{1}" + pnp 2e.0 off # Floppy + io 0x60 = 0x3f0 + irq 0x70 = 6 + drq 0x74 = 2 + pnp 2e.1 off # Parallel Port + io 0x60 = 0x378 + irq 0x70 = 7 + pnp 2e.2 off # Com 2 + io 0x60 = 0x2f8 + irq 0x70 = 3 + pnp 2e.3 on # Com 1 + io 0x60 = 0x3f8 + irq 0x70 = 4 + pnp 2e.4 off # SWC + pnp 2e.5 off # Mouse + pnp 2e.6 on # Keyboard + io 0x60 = 0x60 + io 0x62 = 0x64 + irq 0x70 = 1 + pnp 2e.7 off # GPIO + pnp 2e.8 off # ACB + pnp 2e.9 off # FSCM + pnp 2e.a off # WDT end end end diff --git a/src/mainboard/amd/solo/Config.lb b/src/mainboard/amd/solo/Config.lb index 1372e46005..bb9044eb0a 100644 --- a/src/mainboard/amd/solo/Config.lb +++ b/src/mainboard/amd/solo/Config.lb @@ -23,6 +23,12 @@ uses XIP_ROM_BASE uses STACK_SIZE uses HEAP_SIZE uses USE_OPTION_TABLE +uses LB_CKS_RANGE_START +uses LB_CKS_RANGE_END +uses LB_CKS_LOC +uses MAINBOARD_PART_NUMBER +uses MAINBOARD_VENDOR + ## ROM_SIZE is the size of boot ROM that this board will use. default ROM_SIZE=262144 @@ -59,7 +65,14 @@ default HAVE_MP_TABLE=1 default HAVE_OPTION_TABLE=1 ## -## AMD Solo is a 1cpu board +## Move the default LinuxBIOS cmos range off of AMD RTC registers +## +default LB_CKS_RANGE_START=49 +default LB_CKS_RANGE_END=122 +default LB_CKS_LOC=123 + +## +## AMD Solo is a 1cpu board ## default CONFIG_SMP=1 default CONFIG_MAX_CPUS=1 @@ -152,7 +165,7 @@ object reset.o ## Romcc output ## makerule ./failover.E - depends "$(MAINBOARD)/failover.c" + depends "$(MAINBOARD)/failover.c" action "$(CPP) -I$(TOP)/src $(ROMCCPPFLAGS) $(CPPFLAGS) $(MAINBOARD)/failover.c > ./failover.E" end @@ -161,13 +174,13 @@ makerule ./failover.inc action "./romcc -O -o failover.inc --label-prefix=failover ./failover.E" end -makerule ./auto.E - depends "$(MAINBOARD)/auto.c" - action "$(CPP) -I$(TOP)/src $(ROMCCPPFLAGS) $(CPPFLAGS) $(MAINBOARD)/auto.c > ./auto.E" +makerule ./auto.E + depends "$(MAINBOARD)/auto.c option_table.h " + action "$(CPP) -I$(TOP)/src -I. $(ROMCCPPFLAGS) $(CPPFLAGS) $(MAINBOARD)/auto.c > ./auto.E" end -makerule ./auto.inc +makerule ./auto.inc depends "./auto.E ./romcc" - action "./romcc -mcpu=k8 -O ./auto.E > auto.inc" + action "./romcc -mcpu=k8 -O2 ./auto.E > auto.inc" end ## @@ -175,18 +188,19 @@ end ## mainboardinit cpu/i386/entry16.inc mainboardinit cpu/i386/entry32.inc +#mainboardinit cpu/i386/bist32.inc ldscript /cpu/i386/entry16.lds ldscript /cpu/i386/entry32.lds ## ## Build our reset vector (This is where linuxBIOS is entered) ## -if USE_FALLBACK_IMAGE - mainboardinit cpu/i386/reset16.inc - ldscript /cpu/i386/reset16.lds +if USE_FALLBACK_IMAGE + mainboardinit cpu/i386/reset16.inc + ldscript /cpu/i386/reset16.lds else - mainboardinit cpu/i386/reset32.inc - ldscript /cpu/i386/reset32.lds + mainboardinit cpu/i386/reset32.inc + ldscript /cpu/i386/reset32.lds end ### Should this be in the northbridge code? @@ -204,12 +218,12 @@ ldscript /arch/i386/lib/id.lds mainboardinit cpu/k8/earlymtrr.inc ### -### This is the early phase of linuxBIOS startup +### This is the early phase of linuxBIOS startup ### Things are delicate and we test to see if we should ### failover to another image. ### if USE_FALLBACK_IMAGE - ldscript /arch/i386/lib/failover.lds + ldscript /arch/i386/lib/failover.lds mainboardinit ./failover.inc end @@ -225,7 +239,7 @@ mainboardinit ./auto.inc mainboardinit cpu/k8/disable_mmx_sse.inc ## -## Include the secondary Configuration files +## Include the secondary Configuration files ## dir /pc80 config chip.h @@ -254,19 +268,29 @@ northbridge amd/amdk8 "mc0" pci 1:0.2 on # pci 1:1.0 off superio NSC/pc87360 link 1 - pnp 2e.0 - pnp 2e.1 - pnp 2e.2 - pnp 2e.3 - pnp 2e.4 - pnp 2e.5 - pnp 2e.6 - pnp 2e.7 - pnp 2e.8 - pnp 2e.9 - pnp 2e.a - register "com1" = "{1, 0, 0x3f8, 4}" - register "lpt" = "{1}" + pnp 2e.0 off # Floppy + io 0x60 = 0x3f0 + irq 0x70 = 6 + drq 0x74 = 2 + pnp 2e.1 off # Parallel Port + io 0x60 = 0x378 + irq 0x70 = 7 + pnp 2e.2 off # Com 2 + io 0x60 = 0x2f8 + irq 0x70 = 3 + pnp 2e.3 on # Com 1 + io 0x60 = 0x3f8 + irq 0x70 = 4 + pnp 2e.4 off # SWC + pnp 2e.5 off # Mouse + pnp 2e.6 on # Keyboard + io 0x60 = 0x60 + io 0x62 = 0x64 + irq 0x70 = 1 + pnp 2e.7 off # GPIO + pnp 2e.8 off # ACB + pnp 2e.9 off # FSCM + pnp 2e.a off # WDT end end end @@ -279,4 +303,5 @@ end ## mainboardinit pc80/serial.inc mainboardinit arch/i386/lib/console.inc +#mainboardinit cpu/i386/bist32_fail.inc diff --git a/src/mainboard/amd/solo/auto.c b/src/mainboard/amd/solo/auto.c index 5963934fd5..3a80e4c1bd 100644 --- a/src/mainboard/amd/solo/auto.c +++ b/src/mainboard/amd/solo/auto.c @@ -1,14 +1,16 @@ #define ASSEMBLY 1 #include #include -#include #include #include #include +#include +#include "option_table.h" +#include "pc80/mc146818rtc_early.c" #include "pc80/serial.c" #include "arch/i386/lib/console.c" #include "ram/ramtest.c" -#include "northbridge/amd/amdk8/early_ht.c" +#include "northbridge/amd/amdk8/incoherent_ht.c" #include "southbridge/amd/amd8111/amd8111_early_smbus.c" #include "northbridge/amd/amdk8/raminit.h" #include "cpu/k8/apic_timer.c" @@ -17,9 +19,26 @@ #include "northbridge/amd/amdk8/reset_test.c" #include "debug.c" #include "northbridge/amd/amdk8/cpu_rev.c" +#include "superio/NSC/pc87360/pc87360_early_serial.c" #define SIO_BASE 0x2e +static void hard_reset(void) +{ + set_bios_reset(); + + /* enable cf9 */ + pci_write_config8(PCI_DEV(0, 0x05, 3), 0x41, 0xf1); + /* reset */ + outb(0x0e, 0x0cf9); +} + +static void soft_reset(void) +{ + set_bios_reset(); + pci_write_config8(PCI_DEV(0, 0x05, 0), 0x47, 1); +} + static void memreset_setup(void) { if (is_cpu_pre_c0()) { @@ -54,7 +73,7 @@ static unsigned int generate_row(uint8_t node, uint8_t row, uint8_t maxnodes) static inline void activate_spd_rom(const struct mem_controller *ctrl) { - /* nothing here */ + /* nothing to do */ } static inline int spd_read_byte(unsigned device, unsigned address) @@ -62,69 +81,11 @@ static inline int spd_read_byte(unsigned device, unsigned address) return smbus_read_byte(device, address); } -/* no specific code here. this should go away completely */ -static void coherent_ht_mainboard(unsigned cpus) -{ -} #include "northbridge/amd/amdk8/raminit.c" #include "northbridge/amd/amdk8/coherent_ht.c" #include "sdram/generic_sdram.c" -static void enable_lapic(void) -{ - - msr_t msr; - msr = rdmsr(0x1b); - msr.hi &= 0xffffff00; - msr.lo &= 0x000007ff; - msr.lo |= APIC_DEFAULT_BASE | (1 << 11); - wrmsr(0x1b, msr); -} - -static void stop_this_cpu(void) -{ - unsigned apicid; - apicid = apic_read(APIC_ID) >> 24; - - /* Send an APIC INIT to myself */ - apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); - apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT); - /* Wait for the ipi send to finish */ - apic_wait_icr_idle(); - - /* Deassert the APIC INIT */ - apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); - apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); - /* Wait for the ipi send to finish */ - apic_wait_icr_idle(); - - /* If I haven't halted spin forever */ - for(;;) { - hlt(); - } -} - -#define PC87360_FDC 0x00 -#define PC87360_PP 0x01 -#define PC87360_SP2 0x02 -#define PC87360_SP1 0x03 -#define PC87360_SWC 0x04 -#define PC87360_KBCM 0x05 -#define PC87360_KBCK 0x06 -#define PC87360_GPIO 0x07 -#define PC87360_ACB 0x08 -#define PC87360_FSCM 0x09 -#define PC87360_WDT 0x0A - -/* FIXME: Do we really need this on Solo boards? */ -static void pc87360_enable_serial(void) -{ - pnp_set_logical_device(SIO_BASE, PC87360_SP1); - pnp_set_enable(SIO_BASE, 1); - pnp_set_iobase0(SIO_BASE, 0x3f8); -} - static void main(void) { static const struct mem_controller cpu[] = { @@ -138,26 +99,29 @@ static void main(void) .channel1 = { 0, 0, 0, 0 }, } }; + int needs_reset; + enable_lapic(); + init_timer(); if (cpu_init_detected()) { asm("jmp __cpu_reset"); } enable_lapic(); init_timer(); - -#if 0 - /* Enabling this will make romcc segfault - 2003/10/13 */ + distinguish_cpu_resets(); if (!boot_cpu()) { print_err("This LinuxBIOS image is built for UP only.\n"); + stop_this_cpu(); } -#endif - pc87360_enable_serial(); + pc87360_enable_serial(SIO_BASE, TTYS0_BASE); uart_init(); console_init(); setup_default_resource_map(); - setup_coherent_ht_domain(); - enumerate_ht_chain(0); - distinguish_cpu_resets(0); - + needs_reset = setup_coherent_ht_domain(); + needs_reset = ht_setup_chain(PCI_DEV(0, 0x18, 0), 0x80); + if (needs_reset) { + print_info("ht reset -"); + soft_reset(); + } #if 0 print_pci_devices(); #endif diff --git a/src/mainboard/amd/solo/cmos.layout b/src/mainboard/amd/solo/cmos.layout index 5ba4c032c1..247715e6ac 100644 --- a/src/mainboard/amd/solo/cmos.layout +++ b/src/mainboard/amd/solo/cmos.layout @@ -29,6 +29,9 @@ entries 386 1 e 1 ECC_memory 388 4 r 0 reboot_bits 392 3 e 5 baud_rate +395 1 e 1 hw_scrubber +396 1 e 1 interleave_chip_selects +397 2 e 8 max_mem_clock 400 1 e 1 power_on_after_fail 412 4 e 6 debug_level 416 4 e 7 boot_first @@ -36,7 +39,14 @@ entries 424 4 e 7 boot_third 428 4 h 0 boot_index 432 8 h 0 boot_countdown -1008 16 h 0 check_sum +440 4 e 9 slow_cpu +444 1 e 1 nmi +728 256 h 0 user_data +984 16 h 0 check_sum +# Reserve the extended AMD configuration registers +1000 24 r 0 reserved_memory + + enumerations @@ -66,9 +76,21 @@ enumerations 7 9 Fallback_HDD 7 10 Fallback_Floppy #7 3 ROM +8 0 200Mhz +8 1 166Mhz +8 2 133Mhz +8 3 100Mhz +9 0 off +9 1 87.5% +9 2 75.0% +9 3 62.5% +9 4 50.0% +9 5 37.5% +9 6 25.0% +9 7 12.5% checksums -checksum 392 1007 1008 +checksum 392 983 984 diff --git a/src/mainboard/amd/solo/failover.c b/src/mainboard/amd/solo/failover.c index bd9c17020e..bd5869fead 100644 --- a/src/mainboard/amd/solo/failover.c +++ b/src/mainboard/amd/solo/failover.c @@ -3,40 +3,78 @@ #include #include #include -#include "arch/romcc_io.h" +#include +#include #include "pc80/mc146818rtc_early.c" #include "southbridge/amd/amd8111/amd8111_enable_rom.c" #include "northbridge/amd/amdk8/early_ht.c" #include "cpu/p6/boot_cpu.c" #include "northbridge/amd/amdk8/reset_test.c" +#define HAVE_REGPARM_SUPPORT 0 +#if HAVE_REGPARM_SUPPORT +static unsigned long main(unsigned long bist) +{ +#else static void main(void) { - /* Nothing special needs to be done to find bus 0 */ - /* Allow the HT devices to be found */ - enumerate_ht_chain(0); + unsigned long bist = 0; +#endif + /* Make cerain my local apic is useable */ + enable_lapic(); - /* Setup the 8111 */ - amd8111_enable_rom(); - - /* Is this a cpu reset? */ + /* Is this a cpu only reset? */ if (cpu_init_detected()) { if (last_boot_normal()) { - asm("jmp __normal_image"); + goto normal_image; } else { - asm("jmp __cpu_reset"); + goto cpu_reset; } } - /* Is this a deliberate reset by the bios */ - else if (bios_reset_detected() && last_boot_normal()) { - asm("jmp __normal_image"); - } /* Is this a secondary cpu? */ - else if (!boot_cpu() && last_boot_normal()) { - asm("jmp __normal_image"); + if (!boot_cpu()) { + if (last_boot_normal()) { + goto normal_image; + } else { + goto fallback_image; + } + } + + + /* Nothing special needs to be done to find bus 0 */ + /* Allow the HT devices to be found */ + enumerate_ht_chain(0); + + /* Setup the 8111 */ + amd8111_enable_rom(); + + /* Is this a deliberate reset by the bios */ + if (bios_reset_detected() && last_boot_normal()) { + goto normal_image; } /* This is the primary cpu how should I boot? */ else if (do_normal_boot()) { - asm("jmp __normal_image"); + goto normal_image; + } + else { + goto fallback_image; } + normal_image: + asm("jmp __normal_image" + : /* outputs */ + : "a" (bist) /* inputs */ + : /* clobbers */ + ); + cpu_reset: + asm("jmp __cpu_reset" + : /* outputs */ + : "a"(bist) /* inputs */ + : /* clobbers */ + ); + fallback_image: +#if HAVE_REGPARM_SUPPORT + return bist; +#else + return; +#endif } diff --git a/src/mainboard/amd/solo/mptable.c b/src/mainboard/amd/solo/mptable.c index dfe4320181..42c2e6b33c 100644 --- a/src/mainboard/amd/solo/mptable.c +++ b/src/mainboard/amd/solo/mptable.c @@ -178,7 +178,6 @@ void *smp_write_config_table(void *v, unsigned long * processor_map) 1, (5<<2)|1, 0x02, 0x11); - /* There is no extension information... */ /* Compute the checksums */ diff --git a/src/mainboard/arima/hdama/Config.lb b/src/mainboard/arima/hdama/Config.lb index 60d74da0ab..fbb1a2bbee 100644 --- a/src/mainboard/arima/hdama/Config.lb +++ b/src/mainboard/arima/hdama/Config.lb @@ -23,6 +23,12 @@ uses XIP_ROM_BASE uses STACK_SIZE uses HEAP_SIZE uses USE_OPTION_TABLE +uses LB_CKS_RANGE_START +uses LB_CKS_RANGE_END +uses LB_CKS_LOC +uses MAINBOARD_PART_NUMBER +uses MAINBOARD_VENDOR + ## ROM_SIZE is the size of boot ROM that this board will use. default ROM_SIZE=524288 @@ -58,6 +64,13 @@ default HAVE_MP_TABLE=1 ## default HAVE_OPTION_TABLE=1 +## +## Move the default LinuxBIOS cmos range off of AMD RTC registers +## +default LB_CKS_RANGE_START=49 +default LB_CKS_RANGE_END=122 +default LB_CKS_LOC=123 + ## ## Build code for SMP support ## Only worry about 2 micro processors @@ -73,8 +86,8 @@ default CONFIG_IOAPIC=1 ## ## Clean up the motherboard id strings ## -#default MAINBOARD_PART_NUMBER="HDAMA" -#default MAINBOARD_VENDOR="ARIMA" +default MAINBOARD_PART_NUMBER="HDAMA" +default MAINBOARD_VENDOR="ARIMA" ### ### LinuxBIOS layout values @@ -144,9 +157,7 @@ arch i386 end ## Build the objects we have code for in this directory. ## -#object mainboard.o driver mainboard.o -#object static_devices.o if HAVE_MP_TABLE object mptable.o end if HAVE_PIRQ_TABLE object irq_tables.o end object reset.o @@ -165,8 +176,8 @@ makerule ./failover.inc end makerule ./auto.E - depends "$(MAINBOARD)/auto.c" - action "$(CPP) -I$(TOP)/src $(ROMCCPPFLAGS) $(CPPFLAGS) $(MAINBOARD)/auto.c > ./auto.E" + depends "$(MAINBOARD)/auto.c option_table.h " + action "$(CPP) -I$(TOP)/src -I. $(ROMCCPPFLAGS) $(CPPFLAGS) $(MAINBOARD)/auto.c > ./auto.E" end makerule ./auto.inc depends "./auto.E ./romcc" @@ -178,6 +189,7 @@ end ## mainboardinit cpu/i386/entry16.inc mainboardinit cpu/i386/entry32.inc +mainboardinit cpu/i386/bist32.inc ldscript /cpu/i386/entry16.lds ldscript /cpu/i386/entry32.lds @@ -259,19 +271,29 @@ northbridge amd/amdk8 "mc0" pci 1:0.2 on pci 1:1.0 off superio NSC/pc87360 link 1 - pnp 2e.0 - pnp 2e.1 - pnp 2e.2 - pnp 2e.3 - pnp 2e.4 - pnp 2e.5 - pnp 2e.6 - pnp 2e.7 - pnp 2e.8 - pnp 2e.9 - pnp 2e.a - register "com1" = "{1, 0, 0x3f8, 4}" - register "lpt" = "{1}" + pnp 2e.0 off # Floppy + io 0x60 = 0x3f0 + irq 0x70 = 6 + drq 0x74 = 2 + pnp 2e.1 off # Parallel Port + io 0x60 = 0x378 + irq 0x70 = 7 + pnp 2e.2 off # Com 2 + io 0x60 = 0x2f8 + irq 0x70 = 3 + pnp 2e.3 on # Com 1 + io 0x60 = 0x3f8 + irq 0x70 = 4 + pnp 2e.4 off # SWC + pnp 2e.5 off # Mouse + pnp 2e.6 on # Keyboard + io 0x60 = 0x60 + io 0x62 = 0x64 + irq 0x70 = 1 + pnp 2e.7 off # GPIO + pnp 2e.8 off # ACB + pnp 2e.9 off # FSCM + pnp 2e.a off # WDT end end end @@ -297,4 +319,5 @@ end ## mainboardinit pc80/serial.inc mainboardinit arch/i386/lib/console.inc +mainboardinit cpu/i386/bist32_fail.inc diff --git a/src/mainboard/arima/hdama/auto.c b/src/mainboard/arima/hdama/auto.c index 689346e6f2..e011809f49 100644 --- a/src/mainboard/arima/hdama/auto.c +++ b/src/mainboard/arima/hdama/auto.c @@ -1,14 +1,16 @@ #define ASSEMBLY 1 #include #include -#include #include -#include +#include #include +#include +#include "option_table.h" +#include "pc80/mc146818rtc_early.c" #include "pc80/serial.c" #include "arch/i386/lib/console.c" #include "ram/ramtest.c" -#include "northbridge/amd/amdk8/early_ht.c" +#include "northbridge/amd/amdk8/incoherent_ht.c" #include "southbridge/amd/amd8111/amd8111_early_smbus.c" #include "northbridge/amd/amdk8/raminit.h" #include "cpu/k8/apic_timer.c" @@ -17,8 +19,25 @@ #include "northbridge/amd/amdk8/reset_test.c" #include "debug.c" #include "northbridge/amd/amdk8/cpu_rev.c" +#include "superio/NSC/pc87360/pc87360_early_serial.c" -#define SIO_BASE 0x2e +#define SERIAL_DEV PNP_DEV(0x2e, PC87360_SP1) + +static void hard_reset(void) +{ + set_bios_reset(); + + /* enable cf9 */ + pci_write_config8(PCI_DEV(0, 0x04, 3), 0x41, 0xf1); + /* reset */ + outb(0x0e, 0x0cf9); +} + +static void soft_reset(void) +{ + set_bios_reset(); + pci_write_config8(PCI_DEV(0, 0x04, 0), 0x47, 1); +} static void memreset_setup(void) { @@ -75,13 +94,13 @@ static unsigned int generate_row(uint8_t node, uint8_t row, uint8_t maxnodes) { 0x00010404, 0x00050101 } }; - if(maxnodes>2) { + if(maxnodes > 2) { print_debug("this mainboard is only designed for 2 cpus\r\n"); maxnodes=2; } - if (!(node>=maxnodes || row>=maxnodes)) { + if (!(node >= maxnodes || row >= maxnodes)) { ret=rows_2p[node][row]; } @@ -98,67 +117,12 @@ static inline int spd_read_byte(unsigned device, unsigned address) return smbus_read_byte(device, address); } -/* no specific code here. this should go away completely */ -static void coherent_ht_mainboard(unsigned cpus) -{ -} - #include "northbridge/amd/amdk8/raminit.c" #include "northbridge/amd/amdk8/coherent_ht.c" #include "sdram/generic_sdram.c" -static void enable_lapic(void) -{ - msr_t msr; - msr = rdmsr(0x1b); - msr.hi &= 0xffffff00; - msr.lo &= 0x000007ff; - msr.lo |= APIC_DEFAULT_BASE | (1 << 11); - wrmsr(0x1b, msr); -} - -static void stop_this_cpu(void) -{ - unsigned apicid; - apicid = apic_read(APIC_ID) >> 24; - /* Send an APIC INIT to myself */ - apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); - apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT); - /* Wait for the ipi send to finish */ - apic_wait_icr_idle(); - - /* Deassert the APIC INIT */ - apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); - apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); - /* Wait for the ipi send to finish */ - apic_wait_icr_idle(); - - /* If I haven't halted spin forever */ - for(;;) { - hlt(); - } -} - -#define PC87360_FDC 0x00 -#define PC87360_PP 0x01 -#define PC87360_SP2 0x02 -#define PC87360_SP1 0x03 -#define PC87360_SWC 0x04 -#define PC87360_KBCM 0x05 -#define PC87360_KBCK 0x06 -#define PC87360_GPIO 0x07 -#define PC87360_ACB 0x08 -#define PC87360_FSCM 0x09 -#define PC87360_WDT 0x0A - -static void pc87360_enable_serial(void) -{ - pnp_set_logical_device(SIO_BASE, PC87360_SP1); - pnp_set_enable(SIO_BASE, 1); - pnp_set_iobase0(SIO_BASE, 0x3f8); -} #define FIRST_CPU 1 #define SECOND_CPU 1 @@ -193,22 +157,26 @@ static void main(void) }, #endif }; + int needs_reset; + enable_lapic(); + init_timer(); if (cpu_init_detected()) { asm("jmp __cpu_reset"); } - enable_lapic(); - init_timer(); + distinguish_cpu_resets(); if (!boot_cpu()) { stop_this_cpu(); } - pc87360_enable_serial(); + pc87360_enable_serial(SERIAL_DEV, TTYS0_BASE); uart_init(); console_init(); setup_default_resource_map(); - setup_coherent_ht_domain(); - enumerate_ht_chain(0); - distinguish_cpu_resets(0); - + needs_reset = setup_coherent_ht_domain(); + needs_reset |= ht_setup_chain(PCI_DEV(0, 0x18, 0), 0x80); + if (needs_reset) { + print_info("ht reset -"); + soft_reset(); + } #if 0 print_pci_devices(); #endif @@ -219,39 +187,15 @@ static void main(void) memreset_setup(); sdram_initialize(sizeof(cpu)/sizeof(cpu[0]), cpu); -#if 1 +#if 0 dump_pci_devices(); #endif #if 0 dump_pci_device(PCI_DEV(0, 0x18, 2)); #endif - /* Check all of memory */ -#if 0 - msr_t msr; - msr = rdmsr(TOP_MEM); - print_debug("TOP_MEM: "); - print_debug_hex32(msr.hi); - print_debug_hex32(msr.lo); - print_debug("\r\n"); -#endif -#if 0 - ram_check(0x00000000, msr.lo); -#endif #if 0 - static const struct { - unsigned long lo, hi; - } check_addrs[] = { - /* Check 16MB of memory @ 0*/ - { 0x00000000, 0x01000000 }, -#if TOTAL_CPUS > 1 - /* Check 16MB of memory @ 2GB */ - { 0x80000000, 0x81000000 }, -#endif - }; - int i; - for(i = 0; i < sizeof(check_addrs)/sizeof(check_addrs[0]); i++) { - ram_check(check_addrs[i].lo, check_addrs[i].hi); - } + /* Check the first 1M */ + ram_check(0x00000000, 0x000100000); #endif } diff --git a/src/mainboard/arima/hdama/cmos.layout b/src/mainboard/arima/hdama/cmos.layout index 5ba4c032c1..247715e6ac 100644 --- a/src/mainboard/arima/hdama/cmos.layout +++ b/src/mainboard/arima/hdama/cmos.layout @@ -29,6 +29,9 @@ entries 386 1 e 1 ECC_memory 388 4 r 0 reboot_bits 392 3 e 5 baud_rate +395 1 e 1 hw_scrubber +396 1 e 1 interleave_chip_selects +397 2 e 8 max_mem_clock 400 1 e 1 power_on_after_fail 412 4 e 6 debug_level 416 4 e 7 boot_first @@ -36,7 +39,14 @@ entries 424 4 e 7 boot_third 428 4 h 0 boot_index 432 8 h 0 boot_countdown -1008 16 h 0 check_sum +440 4 e 9 slow_cpu +444 1 e 1 nmi +728 256 h 0 user_data +984 16 h 0 check_sum +# Reserve the extended AMD configuration registers +1000 24 r 0 reserved_memory + + enumerations @@ -66,9 +76,21 @@ enumerations 7 9 Fallback_HDD 7 10 Fallback_Floppy #7 3 ROM +8 0 200Mhz +8 1 166Mhz +8 2 133Mhz +8 3 100Mhz +9 0 off +9 1 87.5% +9 2 75.0% +9 3 62.5% +9 4 50.0% +9 5 37.5% +9 6 25.0% +9 7 12.5% checksums -checksum 392 1007 1008 +checksum 392 983 984 diff --git a/src/mainboard/arima/hdama/failover.c b/src/mainboard/arima/hdama/failover.c index bd9c17020e..b22abfea06 100644 --- a/src/mainboard/arima/hdama/failover.c +++ b/src/mainboard/arima/hdama/failover.c @@ -3,40 +3,78 @@ #include #include #include -#include "arch/romcc_io.h" +#include +#include #include "pc80/mc146818rtc_early.c" #include "southbridge/amd/amd8111/amd8111_enable_rom.c" #include "northbridge/amd/amdk8/early_ht.c" #include "cpu/p6/boot_cpu.c" #include "northbridge/amd/amdk8/reset_test.c" +#define HAVE_REGPARM_SUPPORT 0 +#if HAVE_REGPARM_SUPPORT +static unsigned long main(unsigned long bist) +{ +#else static void main(void) { - /* Nothing special needs to be done to find bus 0 */ - /* Allow the HT devices to be found */ - enumerate_ht_chain(0); - - /* Setup the 8111 */ - amd8111_enable_rom(); + unsigned long bist = 0; +#endif + /* Make cerain my local apic is useable */ + enable_lapic(); - /* Is this a cpu reset? */ + /* Is this a cpu only reset? */ if (cpu_init_detected()) { if (last_boot_normal()) { - asm("jmp __normal_image"); + goto normal_image; } else { - asm("jmp __cpu_reset"); + goto cpu_reset; } } - /* Is this a deliberate reset by the bios */ - else if (bios_reset_detected() && last_boot_normal()) { - asm("jmp __normal_image"); - } /* Is this a secondary cpu? */ - else if (!boot_cpu() && last_boot_normal()) { - asm("jmp __normal_image"); + if (!boot_cpu()) { + if (last_boot_normal()) { + goto normal_image; + } else { + goto fallback_image; + } + } + + + /* Nothing special needs to be done to find bus 0 */ + /* Allow the HT devices to be found */ + enumerate_ht_chain(); + + /* Setup the 8111 */ + amd8111_enable_rom(); + + /* Is this a deliberate reset by the bios */ + if (bios_reset_detected() && last_boot_normal()) { + goto normal_image; } /* This is the primary cpu how should I boot? */ else if (do_normal_boot()) { - asm("jmp __normal_image"); + goto normal_image; + } + else { + goto fallback_image; } + normal_image: + asm("jmp __normal_image" + : /* outputs */ + : "a" (bist) /* inputs */ + : /* clobbers */ + ); + cpu_reset: + asm("jmp __cpu_reset" + : /* outputs */ + : "a"(bist) /* inputs */ + : /* clobbers */ + ); + fallback_image: +#if HAVE_REGPARM_SUPPORT + return bist; +#else + return; +#endif } diff --git a/src/mainboard/arima/hdama/irq_tables.c b/src/mainboard/arima/hdama/irq_tables.c index 9be2d1cf14..c54d43bbd1 100644 --- a/src/mainboard/arima/hdama/irq_tables.c +++ b/src/mainboard/arima/hdama/irq_tables.c @@ -17,36 +17,28 @@ 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 IRQ_SLOT_COUNT - * devices on the bus */ + PIRQ_VERSION, /* u16 version */ + 32+16*IRQ_SLOT_COUNT, /* there can be total IRQ_SLOT_COUNT table entries */ IRQ_ROUTER_BUS, /* Where the interrupt router lies (bus) */ IRQ_ROUTER_DEVFN, /* Where the interrupt router lies (dev) */ 0x00, /* IRQs devoted exclusively to PCI usage */ IRQ_ROUTER_VENDOR, /* Vendor */ IRQ_ROUTER_DEVICE, /* Device */ 0x00, /* Crap (miniport) */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */ - 0x00, /* u8 checksum , mod 256 checksum must give - * zero, will be corrected later - */ - { - - /* slot(0=onboard), devfn, irqlinks (line id, 0=not routed) */ - + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */ + 0xb0, /* u8 checksum , mod 256 checksum must give zero */ + { /* slot(0=onboard), devfn, irqlinks (line id, 0=not routed) */ /* PCI Slot 1-6 */ - IRQ_SLOT (1, 3,1,0, 2,3,4,1 ), - IRQ_SLOT (2, 3,2,0, 3,4,1,2 ), - IRQ_SLOT (3, 2,1,0, 2,3,4,1 ), - IRQ_SLOT (4, 2,2,0, 3,4,1,2 ), - IRQ_SLOT (5, 4,5,0, 2,3,4,1 ), - IRQ_SLOT (6, 4,4,0, 1,2,3,4 ), - + IRQ_SLOT(1, 3,1,0, 2,3,4,1 ), + IRQ_SLOT(2, 3,2,0, 3,4,1,2 ), + IRQ_SLOT(3, 2,1,0, 2,3,4,1 ), + IRQ_SLOT(4, 2,2,0, 3,4,1,2 ), + IRQ_SLOT(5, 4,5,0, 2,3,4,1 ), + IRQ_SLOT(6, 4,4,0, 1,2,3,4 ), /* Onboard NICs */ - IRQ_SLOT (0, 2,3,0, 4,0,0,0 ), - IRQ_SLOT (0, 2,4,0, 4,0,0,0 ), - + IRQ_SLOT(0, 2,3,0, 4,0,0,0 ), + IRQ_SLOT(0, 2,4,0, 4,0,0,0 ), /* Let Linux know about bus 1 */ - IRQ_SLOT (0, 1,4,3, 0,0,0,0 ), + IRQ_SLOT(0, 1,4,3, 0,0,0,0 ), } }; diff --git a/src/mainboard/arima/hdama/mainboard.c b/src/mainboard/arima/hdama/mainboard.c index 82041282f6..bbc6f53716 100644 --- a/src/mainboard/arima/hdama/mainboard.c +++ b/src/mainboard/arima/hdama/mainboard.c @@ -3,23 +3,268 @@ #include #include #include +#include #include #include #include "../../../northbridge/amd/amdk8/northbridge.h" #include "chip.h" +#include "pc80/mc146818rtc.h" + + unsigned long initial_apicid[CONFIG_MAX_CPUS] = { 0, 1, }; +#define SMBGSTATUS 0xe0 +#define SMBGCTL 0xe2 +#define SMBHSTADDR 0xe4 +#define SMBHSTDAT 0xe6 +#define SMBHSTCMD 0xe8 +#define SMBHSTFIFO 0xe9 + +#define SMBUS_TIMEOUT (100*1000*10) + +static inline void smbus_delay(void) +{ + outb(0x80, 0x80); +} + +static int smbus_wait_until_ready(unsigned smbus_io_base) +{ + unsigned long loops; + loops = SMBUS_TIMEOUT; + do { + unsigned short val; + smbus_delay(); + val = inw(smbus_io_base + SMBGSTATUS); + if ((val & 0x800) == 0) { + break; + } + if(loops == (SMBUS_TIMEOUT / 2)) { + outw(inw(smbus_io_base + SMBGSTATUS), + smbus_io_base + SMBGSTATUS); + } + } while(--loops); + return loops?0:-2; +} + +static int smbus_wait_until_done(unsigned smbus_io_base) +{ + unsigned long loops; + loops = SMBUS_TIMEOUT; + do { + unsigned short val; + smbus_delay(); + + val = inw(smbus_io_base + SMBGSTATUS); + if (((val & 0x8) == 0) | ((val & 0x437) != 0)) { + break; + } + } while(--loops); + return loops?0:-3; +} + +static int smbus_send_byte(unsigned smbus_io_base, unsigned device, unsigned value) +{ + unsigned char global_status_register; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; + } + + /* setup transaction */ + /* disable interrupts */ + outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL); + /* set the device I'm talking too */ + outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR); + /* set the command/address... */ + outb(0, smbus_io_base + SMBHSTCMD); + /* set up for a send byte */ + outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL); + + /* clear any lingering errors, so the transaction will run */ + /* Do I need to write the bits to a 1 to clear an error? */ + outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS); + + /* set the data word...*/ + outw(value, smbus_io_base + SMBHSTDAT); + + /* start the command */ + outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL); + + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; + } + global_status_register = inw(smbus_io_base + SMBGSTATUS); + + if (global_status_register != (1 << 4)) { + return -1; + } + return 0; +} + +static int smbus_recv_byte(unsigned smbus_io_base, unsigned device) +{ + unsigned char global_status_register; + unsigned char byte; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; + } + + /* setup transaction */ + /* disable interrupts */ + outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL); + /* set the device I'm talking too */ + outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR); + /* set the command/address... */ + outb(0, smbus_io_base + SMBHSTCMD); + /* set up for a send byte */ + outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL); + + /* clear any lingering errors, so the transaction will run */ + /* Do I need to write the bits to a 1 to clear an error? */ + outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS); + + /* set the data word...*/ + outw(0, smbus_io_base + SMBHSTDAT); + + /* start the command */ + outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL); + + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; + } + + global_status_register = inw(smbus_io_base + SMBGSTATUS); + + /* read results of transaction */ + byte = inw(smbus_io_base + SMBHSTDAT) & 0xff; + + if (global_status_register != (1 << 4)) { + return -1; + } + return byte; +} + +#if 0 +static int smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address) +{ + unsigned char global_status_register; + unsigned char byte; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; + } + + /* setup transaction */ + /* disable interrupts */ + outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL); + /* set the device I'm talking too */ + outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR); + /* set the command/address... */ + outb(address & 0xFF, smbus_io_base + SMBHSTCMD); + /* set up for a byte data read */ + outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x2), smbus_io_base + SMBGCTL); + + /* clear any lingering errors, so the transaction will run */ + /* Do I need to write the bits to a 1 to clear an error? */ + outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS); + + /* clear the data word...*/ + outw(0, smbus_io_base + SMBHSTDAT); + + /* start the command */ + outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL); + + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; + } + + global_status_register = inw(smbus_io_base + SMBGSTATUS); + + /* read results of transaction */ + byte = inw(smbus_io_base + SMBHSTDAT) & 0xff; + + if (global_status_register != (1 << 4)) { + return -1; + } + return byte; +} + +static int smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned address, unsigned char val) +{ + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; + } + + /* setup transaction */ + /* disable interrupts */ + outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), + smbus_io_base + SMBGCTL); + /* set the device I'm talking too */ + outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR); + outb(address & 0xFF, smbus_io_base + SMBHSTCMD); + /* set up for a byte data write */ /* FIXME */ + outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL); + /* clear any lingering errors, so the transaction will run */ + /* Do I need to write the bits to a 1 to clear an error? */ + outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS); + + /* clear the data word...*/ + outw(val, smbus_io_base + SMBHSTDAT); + + /* start the command */ + outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; + } + return 0; +} +#endif + +#define SMBUS_MUX 0x70 +static void mainboard_init(device_t dev) +{ + /* Set the mux to see the temperature sensors */ + dev = dev_find_device(0x1022, 0x746b, 0); + if (dev) { + unsigned smbus_io_base; + unsigned device; + int result; + int mux_setting; + device = SMBUS_MUX; + mux_setting = 1; + smbus_io_base = pci_read_config32(dev, 0x58) & ~1;; + result = smbus_send_byte(smbus_io_base, device, mux_setting); + if ((result < 0) || + (smbus_recv_byte(smbus_io_base, device) != mux_setting)) { + printk_err("SMBUS mux would not set to %d\n", mux_setting); + } + + } + else { + printk_err("SMBUS_controller not found\n"); + } +} + static struct device_operations mainboard_operations = { .read_resources = root_dev_read_resources, .set_resources = root_dev_set_resources, .enable_resources = enable_childrens_resources, - .init = 0, + .init = mainboard_init, .scan_bus = amdk8_scan_root_bus, .enable = 0, }; diff --git a/src/mainboard/newisys/khepri/Config.lb b/src/mainboard/newisys/khepri/Config.lb index 6deb3611ba..f0ffeb4e76 100644 --- a/src/mainboard/newisys/khepri/Config.lb +++ b/src/mainboard/newisys/khepri/Config.lb @@ -252,19 +252,29 @@ northbridge amd/amdk8 "mc0" pci 1:0.2 on pci 1:1.0 on superio NSC/pc87360 link 1 - pnp 2e.0 - pnp 2e.1 - pnp 2e.2 - pnp 2e.3 - pnp 2e.4 - pnp 2e.5 - pnp 2e.6 - pnp 2e.7 - pnp 2e.8 - pnp 2e.9 - pnp 2e.a - register "com1" = "{1, 0, 0x3f8, 4}" - register "lpt" = "{1}" + pnp 2e.0 off # Floppy + io 0x60 = 0x3f0 + irq 0x70 = 6 + drq 0x74 = 2 + pnp 2e.1 off # Parallel Port + io 0x60 = 0x378 + irq 0x70 = 7 + pnp 2e.2 off # Com 2 + io 0x60 = 0x2f8 + irq 0x70 = 3 + pnp 2e.3 on # Com 1 + io 0x60 = 0x3f8 + irq 0x70 = 4 + pnp 2e.4 off # SWC + pnp 2e.5 off # Mouse + pnp 2e.6 on # Keyboard + io 0x60 = 0x60 + io 0x62 = 0x64 + irq 0x70 = 1 + pnp 2e.7 off # GPIO + pnp 2e.8 off # ACB + pnp 2e.9 off # FSCM + pnp 2e.a off # WDT end end end diff --git a/src/mainboard/newisys/khepri/auto.c b/src/mainboard/newisys/khepri/auto.c index df6ad6c88c..44f128addc 100644 --- a/src/mainboard/newisys/khepri/auto.c +++ b/src/mainboard/newisys/khepri/auto.c @@ -2,17 +2,19 @@ #define MAXIMUM_CONSOLE_LOGLEVEL 9 #define DEFAULT_CONSOLE_LOGLEVEL 9 - #include #include #include #include #include #include +#include +#include "option_table.h" +#include "pc80/mc146818rtc_early.c" #include "pc80/serial.c" #include "arch/i386/lib/console.c" #include "ram/ramtest.c" -#include "northbridge/amd/amdk8/early_ht.c" +#include "northbridge/amd/amdk8/incoherent_ht.c" #include "southbridge/amd/amd8111/amd8111_early_smbus.c" #include "northbridge/amd/amdk8/raminit.h" #include "cpu/k8/apic_timer.c" @@ -21,8 +23,25 @@ #include "northbridge/amd/amdk8/reset_test.c" #include "debug.c" #include "northbridge/amd/amdk8/cpu_rev.c" +#include "superio/NSC/pc87360/pc87360_early_serial.c" + +#define SERIAL_DEV PNP_DEV(0x2e, PC87360_SP1) + +static void hard_reset(void) +{ + set_bios_reset(); + + /* enable cf9 */ + pci_write_config8(PCI_DEV(0, 0x04, 3), 0x41, 0xf1); + /* reset */ + outb(0x0e, 0x0cf9); +} -#define SIO_BASE 0x2e +static void soft_reset(void) +{ + set_bios_reset(); + pci_write_config8(PCI_DEV(0, 0x04, 0), 0x47, 1); +} static void memreset_setup(void) { @@ -102,11 +121,6 @@ static inline int spd_read_byte(unsigned device, unsigned address) return smbus_read_byte(device, address); } -/* no specific code here. this should go away completely */ -static void coherent_ht_mainboard(unsigned cpus) -{ -} - #include "northbridge/amd/amdk8/raminit.c" #define CONNECTION_0_1 DOWN @@ -116,59 +130,6 @@ static void coherent_ht_mainboard(unsigned cpus) #include "resourcemap.c" /* newisys khepri does not want the default */ -static void enable_lapic(void) -{ - - msr_t msr; - msr = rdmsr(0x1b); - msr.hi &= 0xffffff00; - msr.lo &= 0x000007ff; - msr.lo |= APIC_DEFAULT_BASE | (1 << 11); - wrmsr(0x1b, msr); -} - -static void stop_this_cpu(void) -{ - unsigned apicid; - apicid = apic_read(APIC_ID) >> 24; - - /* Send an APIC INIT to myself */ - apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); - apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT); - /* Wait for the ipi send to finish */ - apic_wait_icr_idle(); - - /* Deassert the APIC INIT */ - apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); - apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); - /* Wait for the ipi send to finish */ - apic_wait_icr_idle(); - - /* If I haven't halted spin forever */ - for(;;) { - hlt(); - } -} - -#define PC87360_FDC 0x00 -#define PC87360_PP 0x01 -#define PC87360_SP2 0x02 -#define PC87360_SP1 0x03 -#define PC87360_SWC 0x04 -#define PC87360_KBCM 0x05 -#define PC87360_KBCK 0x06 -#define PC87360_GPIO 0x07 -#define PC87360_ACB 0x08 -#define PC87360_FSCM 0x09 -#define PC87360_WDT 0x0A - -static void pc87360_enable_serial(void) -{ - pnp_set_logical_device(SIO_BASE, PC87360_SP1); - pnp_set_enable(SIO_BASE, 1); - pnp_set_iobase0(SIO_BASE, 0x3f8); -} - static void main(void) { /* @@ -195,21 +156,26 @@ static void main(void) .channel1 = { (0xa<<3)|5, (0xa<<3)|7, 0, 0 }, }, }; + int needs_reset; + enable_lapic(); + init_timer(); if (cpu_init_detected()) { asm("jmp __cpu_reset"); } - enable_lapic(); - init_timer(); + distinguish_cpu_resets(); if (!boot_cpu()) { stop_this_cpu(); } - pc87360_enable_serial(); + pc87360_enable_serial(SERIAL_DEV, TTYS0_BASE); uart_init(); console_init(); setup_khepri_resource_map(); - setup_coherent_ht_domain(); - enumerate_ht_chain(0); - distinguish_cpu_resets(0); + needs_reset = setup_coherent_ht_domain(); + needs_reset |= ht_setup_chain(PCI_DEV(0, 0x18, 0), 0x80); + if (needs_reset) { + print_info("ht reset -"); + soft_reset(); + } #if 0 print_pci_devices(); @@ -230,30 +196,7 @@ static void main(void) /* Check all of memory */ #if 0 - msr_t msr; - msr = rdmsr(TOP_MEM); - print_debug("TOP_MEM: "); - print_debug_hex32(msr.hi); - print_debug_hex32(msr.lo); - print_debug("\r\n"); -#endif -#if 0 - ram_check(0x00000000, msr.lo); -#endif -#if 0 - static const struct { - unsigned long lo, hi; - } check_addrs[] = { - /* Check 16MB of memory @ 0*/ - { 0x00000000, 0x01000000 }, -#if TOTAL_CPUS > 1 - /* Check 16MB of memory @ 2GB */ - { 0x80000000, 0x81000000 }, -#endif - }; - int i; - for(i = 0; i < sizeof(check_addrs)/sizeof(check_addrs[0]); i++) { - ram_check(check_addrs[i].lo, check_addrs[i].hi); - } + /* Check the first 1M */ + ram_check(0x00000000, 0x000100000); #endif } diff --git a/src/northbridge/amd/amdk8/Config.lb b/src/northbridge/amd/amdk8/Config.lb index 0110e218ce..3b249161fd 100644 --- a/src/northbridge/amd/amdk8/Config.lb +++ b/src/northbridge/amd/amdk8/Config.lb @@ -1,4 +1,9 @@ config chip.h object northbridge.o driver misc_control.o -driver mcf0_control.o + +makerule raminit_test + depends "$(TOP)/src/northbridge/amd/amdk8/raminit_test.c" + depends "$(TOP)/src/northbridge/amd/amdk8/raminit.c" + action "$(HOSTCC) $(HOSTCFLAGS) $(CPUFLAGS) -Wno-unused-function -I$(TOP)/src/include -g $< -o $@" +end diff --git a/src/northbridge/amd/amdk8/amdk8.h b/src/northbridge/amd/amdk8/amdk8.h index c8ae95e383..ca8e8dc3d2 100644 --- a/src/northbridge/amd/amdk8/amdk8.h +++ b/src/northbridge/amd/amdk8/amdk8.h @@ -38,6 +38,15 @@ #define HTTC_HI_PRI_BYP_CNT_MASK 3 +/* Function 1 */ +#define PCI_IO_BASE0 0xc0 +#define PCI_IO_BASE1 0xc8 +#define PCI_IO_BASE2 0xd0 +#define PCI_IO_BASE3 0xd8 +#define PCI_IO_BASE_VGA_EN (1 << 4) +#define PCI_IO_BASE_NO_ISA (1 << 5) + + /* Function 2 */ #define DRAM_CSBASE 0x40 #define DRAM_CSMASK 0x60 @@ -124,6 +133,9 @@ #define DCL_UnBufDimm (1<<18) #define DCL_32ByteEn (1<<19) #define DCL_x4DIMM_SHIFT 20 +#define DCL_DisInRcvrs (1<<24) +#define DCL_BypMax_SHIFT 25 +#define DCL_En2T (1<<28) #define DRAM_CONFIG_HIGH 0x94 #define DCH_ASYNC_LAT_SHIFT 0 #define DCH_ASYNC_LAT_MASK 0xf diff --git a/src/northbridge/amd/amdk8/coherent_ht.c b/src/northbridge/amd/amdk8/coherent_ht.c index 83fbd40beb..5b6ea16e4e 100644 --- a/src/northbridge/amd/amdk8/coherent_ht.c +++ b/src/northbridge/amd/amdk8/coherent_ht.c @@ -14,7 +14,10 @@ */ #include +#include +#include #include "arch/romcc_io.h" +#include "amdk8.h" /* * Until we have a completely dynamic setup we want @@ -39,10 +42,6 @@ #define CONNECTION_0_2 UP #endif -#ifndef CONNECTION_1_0 -#define CONNECTION_1_0 ACROSS -#endif - #ifndef CONNECTION_1_3 #define CONNECTION_1_3 UP #endif @@ -63,7 +62,7 @@ typedef uint8_t u8; typedef uint32_t u32; -typedef int8_t bool; +typedef int bool; #define TRUE (-1) #define FALSE (0) @@ -95,51 +94,15 @@ static void disable_probes(void) u32 val; - print_debug("Disabling read/write/fill probes for UP... "); + print_spew("Disabling read/write/fill probes for UP... "); val=pci_read_config32(NODE_HT(0), 0x68); val |= (1<<10)|(1<<9)|(1<<8)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1 << 0); pci_write_config32(NODE_HT(0), 0x68, val); - print_debug("done.\r\n"); + print_spew("done.\r\n"); } -//BY LYH -#if 0 -#define WAIT_TIMES 1000 -static void wait_ap_stop(u8 node) -{ - unsigned long reg; - unsigned long i; - for(i=0;i>= 24; -/* print_debug("applicaton cpu apic_id: "); - print_debug_hex32(apic_id); - }*/ - if(apic_id!=0) { //AP apic_id == node_id ?? -// set the ColdResetbit to notify BSP that AP is stopped - reg = pci_read_config32(NODE_HT(apic_id), 0x6C); - reg |= 1<<4; - pci_write_config32(NODE_HT(apic_id), 0x6C, reg); - } - -} -#endif -//BY LYH END static void enable_routing(u8 node) { @@ -168,14 +131,14 @@ static void enable_routing(u8 node) */ /* Enable routing table */ - print_debug("Enabling routing table for node "); - print_debug_hex32(node); + print_spew("Enabling routing table for node "); + print_spew_hex32(node); val=pci_read_config32(NODE_HT(node), 0x6c); - val &= ~((1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)); + val &= ~((1<<1)|(1<<0)); pci_write_config32(NODE_HT(node), 0x6c, val); - print_debug(" done.\r\n"); + print_spew(" done.\r\n"); } #if CONFIG_MAX_CPUS > 1 @@ -184,84 +147,97 @@ static void rename_temp_node(u8 node) { uint32_t val; - print_debug("Renaming current temp node to "); - print_debug_hex32(node); + print_spew("Renaming current temp node to "); + print_spew_hex32(node); val=pci_read_config32(NODE_HT(7), 0x60); val &= (~7); /* clear low bits. */ val |= node; /* new node */ pci_write_config32(NODE_HT(7), 0x60, val); -//BY LYH -#if 0 - if(node!=0) { - wait_ap_stop(node); - } -#endif -//BY LYH END - - - print_debug(" done.\r\n"); - - + print_spew(" done.\r\n"); } static bool check_connection(u8 src, u8 dest, u8 link) { - /* this function does 2 things: - * 1) detect whether the coherent HT link is connected. - * 2) verify that the coherent hypertransport link - * is established and actually working by reading the - * remote node's vendor/device id - */ - + /* See if we have a valid connection to dest */ u32 val; - /* 1) */ - val=pci_read_config32(NODE_HT(src), 0x98+link); + /* Detect if the coherent HT link is connected. */ + val = pci_read_config32(NODE_HT(src), 0x98+link); if ( (val&0x17) != 0x03) return 0; - /* 2) */ - val=pci_read_config32(NODE_HT(dest),0); + /* Verify that the coherent hypertransport link is + * established and actually working by reading the + * remode node's vendor/device id + */ + val = pci_read_config32(NODE_HT(dest),0); if(val != 0x11001022) return 0; return 1; } -static void optimize_connection(u8 node1, u8 link1, u8 node2, u8 link2) +static unsigned read_freq_cap(device_t dev, unsigned pos) +{ + /* Handle bugs in valid hypertransport frequency reporting */ + unsigned freq_cap; + uint32_t id; + + freq_cap = pci_read_config16(dev, pos); + freq_cap &= ~(1 << HT_FREQ_VENDOR); /* Ignore Vendor HT frequencies */ + + id = pci_read_config32(dev, 0); + + /* AMD 8131 Errata 48 */ + if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8131_PCIX << 16))) { + freq_cap &= ~(1 << HT_FREQ_800Mhz); + } + /* AMD 8151 Errata 23 */ + if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8151_SYSCTRL << 16))) { + freq_cap &= ~(1 << HT_FREQ_800Mhz); + } + /* AMD K8 Unsupported 1Ghz? */ + if (id == (PCI_VENDOR_ID_AMD | (0x1100 << 16))) { + freq_cap &= ~(1 << HT_FREQ_1000Mhz); + } + return freq_cap; +} + +static int optimize_connection(device_t node1, uint8_t link1, device_t node2, uint8_t link2) { static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 }; static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 }; uint16_t freq_cap1, freq_cap2, freq_cap, freq_mask; - uint8_t width_cap1, width_cap2, width_cap, width, ln_width1, ln_width2; - uint8_t freq; + uint8_t width_cap1, width_cap2, width_cap, width, old_width, ln_width1, ln_width2; + uint8_t freq, old_freq; + int needs_reset; /* Set link width and frequency */ + /* Initially assume everything is already optimized and I don't need a reset */ + needs_reset = 0; + /* Get the frequency capabilities */ - freq_cap1 = pci_read_config16(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_FREQ_CAP); - freq_cap2 = pci_read_config16(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_FREQ_CAP); + freq_cap1 = read_freq_cap(node1, link1 + PCI_HT_CAP_HOST_FREQ_CAP); + freq_cap2 = read_freq_cap(node2, link2 + PCI_HT_CAP_HOST_FREQ_CAP); /* Calculate the highest possible frequency */ -#if 1 - /* FIXME!!!!!!! - * This method of computing the fastes frequency is broken. - * Because the frequencies (i.e. 100Mhz) are not ordered. - */ - freq = log2(freq_cap1 & freq_cap2 & 0xff); -#else - /* Only allow supported frequencies 800Mhz and below */ - freq = log2(freq_cap1 & freq_cap2 & 0x3f); -#endif + freq = log2(freq_cap1 & freq_cap2); + + /* See if I am changing the link freqency */ + old_freq = pci_read_config8(node1, link1 + PCI_HT_CAP_HOST_FREQ); + needs_reset |= old_freq != freq; + old_freq = pci_read_config8(node2, link2 + PCI_HT_CAP_HOST_FREQ); + needs_reset |= old_freq != freq; /* Set the Calulcated link frequency */ - pci_write_config8(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_FREQ, freq); - pci_write_config8(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_FREQ, freq); + pci_write_config8(node1, link1 + PCI_HT_CAP_HOST_FREQ, freq); + pci_write_config8(node2, link2 + PCI_HT_CAP_HOST_FREQ, freq); /* Get the width capabilities */ - width_cap1 = pci_read_config8(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_WIDTH); - width_cap2 = pci_read_config8(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_WIDTH); + width_cap1 = pci_read_config8(node1, link1 + PCI_HT_CAP_HOST_WIDTH); + width_cap2 = pci_read_config8(node2, link2 + PCI_HT_CAP_HOST_WIDTH); /* Calculate node1's input width */ ln_width1 = link_width_to_pow2[width_cap1 & 7]; @@ -278,45 +254,38 @@ static void optimize_connection(u8 node1, u8 link1, u8 node2, u8 link2) } width |= pow2_to_link_width[ln_width1] << 4; + /* See if I am changing node1's width */ + old_width = pci_read_config8(node1, link1 + PCI_HT_CAP_HOST_WIDTH + 1); + needs_reset |= old_width != width; + /* Set node1's widths */ - pci_write_config8(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_WIDTH + 1, width); + pci_write_config8(node1, link1 + PCI_HT_CAP_HOST_WIDTH + 1, width); - /* Set node2's widths */ + /* Calculate node2's width */ width = ((width & 0x70) >> 4) | ((width & 0x7) << 4); - pci_write_config8(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_WIDTH + 1, width); + + /* See if I am changing node2's width */ + old_width = pci_read_config8(node2, link2 + PCI_HT_CAP_HOST_WIDTH + 1); + needs_reset |= old_width != width; + + /* Set node2's widths */ + pci_write_config8(node2, link2 + PCI_HT_CAP_HOST_WIDTH + 1, width); + + return needs_reset; } static void fill_row(u8 node, u8 row, u32 value) { -#if 0 - print_debug("fill_row: pci_write_config32("); - print_debug_hex32(NODE_HT(node)); - print_debug_char(','); - print_debug_hex32(0x40 + (row << 2)); - print_debug_char(','); - print_debug_hex32(value); - print_debug(")\r\n"); -#endif pci_write_config32(NODE_HT(node), 0x40+(row<<2), value); } static void setup_row(u8 source, u8 dest, u8 cpus) { -#if 0 - printk_spew("setting up link from node %d to %d (%d cpus)\r\n", - source, dest, cpus); -#endif - fill_row(source,dest,generate_row(source,dest,cpus)); } static void setup_temp_row(u8 source, u8 dest, u8 cpus) { -#if 0 - printk_spew("setting up temp. link from node %d to %d (%d cpus)\r\n", - source, dest, cpus); -#endif - fill_row(source,7,generate_temp_row(source,dest,cpus)); } @@ -345,9 +314,8 @@ static void setup_remote_node(u8 node, u8 cpus) }; uint8_t row; int i; -#if 1 - print_debug("setup_remote_node\r\n"); -#endif + + print_spew("setup_remote_node\r\n"); for(row=0; row 1 -static u8 setup_smp(void) +static struct setup_smp_result setup_smp(void) { - u8 cpus=2; + struct setup_smp_result result; + result.cpus = 2; + result.needs_reset = 0; - print_debug("Enabling SMP settings\r\n"); + print_spew("Enabling SMP settings\r\n"); - setup_row(0,0,cpus); + setup_row(0, 0, result.cpus); /* Setup and check a temporary connection to node 1 */ - setup_temp_row(0,1,cpus); + setup_temp_row(0, 1, result.cpus); if (!check_connection(0, 7, CONNECTION_0_1)) { - print_debug("No connection to Node 1.\r\n"); + print_spew("No connection to Node 1.\r\n"); clear_temp_row(0); /* delete temp connection */ setup_uniprocessor(); /* and get up working */ - return 1; + result.cpus = 1; + return result; } /* We found 2 nodes so far */ - optimize_connection(0, CONNECTION_0_1, 7, CONNECTION_1_0); - setup_node(0, cpus); /* Node 1 is there. Setup Node 0 correctly */ - setup_remote_node(1, cpus); /* Setup the routes on the remote node */ + result.needs_reset = + optimize_connection(NODE_HT(0), 0x80 + CONNECTION_0_1, NODE_HT(7), 0x80 + CONNECTION_0_1); + setup_node(0, result.cpus); /* Node 1 is there. Setup Node 0 correctly */ + setup_remote_node(1, result.cpus); /* Setup the routes on the remote node */ rename_temp_node(1); /* Rename Node 7 to Node 1 */ enable_routing(1); /* Enable routing on Node 1 */ clear_temp_row(0); /* delete temporary connection */ #if CONFIG_MAX_CPUS > 2 - cpus=4; + result.cpus=4; /* Setup and check temporary connection from Node 0 to Node 2 */ - setup_temp_row(0,2,cpus); + setup_temp_row(0,2, result.cpus); if (!check_connection(0, 7, CONNECTION_0_2)) { - print_debug("No connection to Node 2.\r\n"); + print_spew("No connection to Node 2.\r\n"); clear_temp_row(0); /* delete temp connection */ - return 2; + result.cpus = 2; + return result; } /* We found 3 nodes so far. Now setup a temporary * connection from node 0 to node 3 via node 1 */ - setup_temp_row(0,1,cpus); /* temp. link between nodes 0 and 1 */ - setup_temp_row(1,3,cpus); /* temp. link between nodes 1 and 3 */ + setup_temp_row(0,1, result.cpus); /* temp. link between nodes 0 and 1 */ + setup_temp_row(1,3, result.cpus); /* temp. link between nodes 1 and 3 */ if (!check_connection(1, 7, CONNECTION_1_3)) { - print_debug("No connection to Node 3.\r\n"); + print_spew("No connection to Node 3.\r\n"); clear_temp_row(0); /* delete temp connection */ clear_temp_row(1); /* delete temp connection */ - return 2; + result.cpus = 2; + return result; } +#warning "FIXME optimize the physical connections" + /* We found 4 nodes so far. Now setup all nodes for 4p */ - setup_node(0, cpus); /* The first 2 nodes are configured */ - setup_node(1, cpus); /* already. Just configure them for 4p */ + setup_node(0, result.cpus); /* The first 2 nodes are configured */ + setup_node(1, result.cpus); /* already. Just configure them for 4p */ - setup_temp_row(0,2,cpus); - setup_temp_node(2,cpus); + setup_temp_row(0,2, result.cpus); + setup_temp_node(2, result.cpus); rename_temp_node(2); enable_routing(2); - setup_temp_row(0,1,cpus); - setup_temp_row(1,3,cpus); - setup_temp_node(3,cpus); + setup_temp_row(0,1, result.cpus); + setup_temp_row(1,3, result.cpus); + setup_temp_node(3, result.cpus); rename_temp_node(3); enable_routing(3); /* enable routing on node 3 (temp.) */ @@ -463,52 +436,52 @@ static u8 setup_smp(void) clear_temp_row(3); #endif - print_debug_hex32(cpus); + print_debug_hex32(result.cpus); print_debug(" nodes initialized.\r\n"); - return cpus; + return result; } #endif #if CONFIG_MAX_CPUS > 1 -static unsigned detect_mp_capabilities(unsigned cpus) +static unsigned verify_mp_capabilities(unsigned cpus) { unsigned node, row, mask; bool mp_cap=TRUE; -#if 1 - print_debug("detect_mp_capabilities: "); - print_debug_hex32(cpus); - print_debug("\r\n"); -#endif - if (cpus>2) + if (cpus > 2) { mask=0x06; /* BigMPCap */ - else + } else { mask=0x02; /* MPCap */ + } for (node=0; node0; node--) - for (row=cpus; row>0; row--) - fill_row(NODE_HT(node-1), row-1, DEFAULT); - - return setup_uniprocessor(); + for (node = cpus; node > 0; node--) { + for (row = cpus; row > 0; row--) { + fill_row(NODE_HT(node-1), row-1, DEFAULT); + } + } + setup_uniprocessor(); + return 1; } #endif static void coherent_ht_finalize(unsigned cpus) { - int node; + unsigned node; bool rev_a0; /* set up cpu count and node count and enable Limit @@ -517,53 +490,149 @@ static void coherent_ht_finalize(unsigned cpus) * registers on Hammer A0 revision. */ -#if 1 +#if 0 print_debug("coherent_ht_finalize\r\n"); #endif - rev_a0= is_cpu_rev_a0(); - - for (node=0; node0f00c800 BY LYH -#endif - pci_write_config32(NODE_HT(node),0x68,val); + pci_write_config32(dev, 0x60, val); + + /* Only respond to real cpu pci configuration cycles + * and optimize the HT settings + */ + val=pci_read_config32(dev, 0x68); + val &= ~((HTTC_BUF_REL_PRI_MASK << HTTC_BUF_REL_PRI_SHIFT) | + (HTTC_MED_PRI_BYP_CNT_MASK << HTTC_MED_PRI_BYP_CNT_SHIFT) | + (HTTC_HI_PRI_BYP_CNT_MASK << HTTC_HI_PRI_BYP_CNT_SHIFT)); + val |= HTTC_LIMIT_CLDT_CFG | + (HTTC_BUF_REL_PRI_8 << HTTC_BUF_REL_PRI_SHIFT) | + HTTC_RSP_PASS_PW | + (3 << HTTC_MED_PRI_BYP_CNT_SHIFT) | + (3 << HTTC_HI_PRI_BYP_CNT_SHIFT); + pci_write_config32(dev, 0x68, val); if (rev_a0) { - pci_write_config32(NODE_HT(node),0x94,0); - pci_write_config32(NODE_HT(node),0xb4,0); - pci_write_config32(NODE_HT(node),0xd4,0); + pci_write_config32(dev, 0x94, 0); + pci_write_config32(dev, 0xb4, 0); + pci_write_config32(dev, 0xd4, 0); } + + } -#if 1 + +#if 0 print_debug("done\r\n"); #endif } +static int apply_cpu_errata_fixes(unsigned cpus, int needs_reset) +{ + unsigned node; + for(node = 0; node < cpus; node++) { + device_t dev; + uint32_t cmd; + dev = NODE_MC(node); + if (is_cpu_pre_c0()) { + + /* Errata 66 + * Limit the number of downstream posted requests to 1 + */ + cmd = pci_read_config32(dev, 0x70); + if ((cmd & (3 << 0)) != 2) { + cmd &= ~(3<<0); + cmd |= (2<<0); + pci_write_config32(dev, 0x70, cmd ); + needs_reset = 1; + } + cmd = pci_read_config32(dev, 0x7c); + if ((cmd & (3 << 4)) != 0) { + cmd &= ~(3<<4); + cmd |= (0<<4); + pci_write_config32(dev, 0x7c, cmd ); + needs_reset = 1; + } + /* Clock Power/Timing Low */ + cmd = pci_read_config32(dev, 0xd4); + if (cmd != 0x000D0001) { + cmd = 0x000D0001; + pci_write_config32(dev, 0xd4, cmd); + needs_reset = 1; /* Needed? */ + } + + } + else { + uint32_t cmd_ref; + /* Errata 98 + * Set Clk Ramp Hystersis to 7 + * Clock Power/Timing Low + */ + cmd_ref = 0x04e20707; /* Registered */ + cmd = pci_read_config32(dev, 0xd4); + if(cmd != cmd_ref) { + pci_write_config32(dev, 0xd4, cmd_ref ); + needs_reset = 1; /* Needed? */ + } + } + } + return needs_reset; +} + +static int optimize_link_read_pointers(unsigned cpus, int needs_reset) +{ + unsigned node; + for(node = 0; node < cpus; node = node + 1) { + device_t f0_dev, f3_dev; + uint32_t cmd_ref, cmd; + int link; + f0_dev = NODE_HT(node); + f3_dev = NODE_MC(node); + cmd_ref = cmd = pci_read_config32(f3_dev, 0xdc); + for(link = 0; link < 3; link = link + 1) { + uint32_t link_type; + unsigned reg; + reg = 0x98 + (link * 0x20); + link_type = pci_read_config32(f0_dev, reg); + if (link_type & LinkConnected) { + cmd &= 0xff << (link *8); + /* FIXME this assumes the device on the other side is an AMD device */ + cmd |= 0x25 << (link *8); + } + } + if (cmd != cmd_ref) { + pci_write_config32(f3_dev, 0xdc, cmd); + needs_reset = 1; + } + } + return needs_reset; +} + static int setup_coherent_ht_domain(void) { - unsigned cpus; - int reset_needed = 0; + struct setup_smp_result result; + result.cpus = 1; + result.needs_reset = 0; enable_bsp_routing(); #if CONFIG_MAX_CPUS == 1 - cpus=setup_uniprocessor(); + setup_uniprocessor(); #else - cpus=setup_smp(); - cpus=detect_mp_capabilities(cpus); + result = setup_smp(); + result.cpus = verify_mp_capabilities(result.cpus); +#endif + coherent_ht_finalize(result.cpus); + result.needs_reset = apply_cpu_errata_fixes(result.cpus, result.needs_reset); +#if CONFIG_MAX_CPUS > 1 /* Why doesn't this work on the solo? */ + result.needs_reset = optimize_link_read_pointers(result.cpus, result.needs_reset); #endif - coherent_ht_finalize(cpus); - /* FIXME this should probably go away again. */ - coherent_ht_mainboard(cpus); - return reset_needed; + return result.needs_reset; } diff --git a/src/northbridge/amd/amdk8/cpu_rev.c b/src/northbridge/amd/amdk8/cpu_rev.c index 51f235905e..0c4c5f8fbd 100644 --- a/src/northbridge/amd/amdk8/cpu_rev.c +++ b/src/northbridge/amd/amdk8/cpu_rev.c @@ -16,10 +16,15 @@ static unsigned int cpuid(unsigned int op) static int is_cpu_rev_a0(void) { - return (cpuid(1) & 0xffff) == 0x0f10; + return (cpuid(1) & 0xffef) == 0x0f00; } static int is_cpu_pre_c0(void) { return (cpuid(1) & 0xffef) < 0x0f48; } + +static int is_cpu_pre_b3(void) +{ + return (cpuid(1) & 0xffef) < 0x0f41; +} diff --git a/src/northbridge/amd/amdk8/early_ht.c b/src/northbridge/amd/amdk8/early_ht.c index 4de8fa1075..90f258e1bc 100644 --- a/src/northbridge/amd/amdk8/early_ht.c +++ b/src/northbridge/amd/amdk8/early_ht.c @@ -1,4 +1,4 @@ -static int enumerate_ht_chain(unsigned link) +static int enumerate_ht_chain(void) { /* Assumption the HT chain that is bus 0 has the HT I/O Hub on it. * On most boards this just happens. If a cpu has multiple @@ -49,3 +49,4 @@ static int enumerate_ht_chain(unsigned link) } while((last_unitid != next_unitid) && (next_unitid <= 0x1f)); return reset_needed; } + diff --git a/src/northbridge/amd/amdk8/incoherent_ht.c b/src/northbridge/amd/amdk8/incoherent_ht.c new file mode 100644 index 0000000000..711100a045 --- /dev/null +++ b/src/northbridge/amd/amdk8/incoherent_ht.c @@ -0,0 +1,244 @@ +#include +#include +#include + +static unsigned ht_lookup_slave_capability(device_t dev) +{ + unsigned pos; + uint8_t hdr_type; + + hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE); + pos = 0; + hdr_type &= 0x7f; + + if ((hdr_type == PCI_HEADER_TYPE_NORMAL) || + (hdr_type == PCI_HEADER_TYPE_BRIDGE)) { + pos = PCI_CAPABILITY_LIST; + } + if (pos > PCI_CAP_LIST_NEXT) { + pos = pci_read_config8(dev, pos); + } + while(pos != 0) { /* loop through the linked list */ + uint8_t cap; + cap = pci_read_config8(dev, pos + PCI_CAP_LIST_ID); + if (cap == PCI_CAP_ID_HT) { + uint16_t flags; + + flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS); + if ((flags >> 13) == 0) { + /* Entry is a Slave secondary, success... */ + break; + } + } + pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT); + } + return pos; +} + +static void ht_collapse_previous_enumeration(unsigned bus) +{ + device_t dev; + + /* Spin through the devices and collapse any previous + * hypertransport enumeration. + */ + for(dev = PCI_DEV(bus, 0, 0); dev <= PCI_DEV(bus, 0x1f, 0x7); dev += PCI_DEV(0, 1, 0)) { + uint32_t id; + unsigned pos, flags; + + id = pci_read_config32(dev, PCI_VENDOR_ID); + if ((id == 0xffffffff) || (id == 0x00000000) || + (id == 0x0000ffff) || (id == 0xffff0000)) { + continue; + } + pos = ht_lookup_slave_capability(dev); + if (!pos) { + continue; + } + + /* Clear the unitid */ + flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS); + flags &= ~0x1f; + pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags); + } +} + + +static unsigned ht_read_freq_cap(device_t dev, unsigned pos) +{ + /* Handle bugs in valid hypertransport frequency reporting */ + unsigned freq_cap; + uint32_t id; + + freq_cap = pci_read_config16(dev, pos); + freq_cap &= ~(1 << HT_FREQ_VENDOR); /* Ignore Vendor HT frequencies */ + + id = pci_read_config32(dev, 0); + + /* AMD 8131 Errata 48 */ + if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8131_PCIX << 16))) { + freq_cap &= ~(1 << HT_FREQ_800Mhz); + } + /* AMD 8151 Errata 23 */ + if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8151_SYSCTRL << 16))) { + freq_cap &= ~(1 << HT_FREQ_800Mhz); + } + /* AMD K8 Unsupported 1Ghz? */ + if (id == (PCI_VENDOR_ID_AMD | (0x1100 << 16))) { + freq_cap &= ~(1 << HT_FREQ_1000Mhz); + } + return freq_cap; +} + +#define LINK_OFFS(WIDTH,FREQ,FREQ_CAP) \ + (((WIDTH & 0xff) << 16) | ((FREQ & 0xff) << 8) | (FREQ_CAP & 0xFF)) + +#define LINK_WIDTH(OFFS) ((OFFS >> 16) & 0xFF) +#define LINK_FREQ(OFFS) ((OFFS >> 8) & 0xFF) +#define LINK_FREQ_CAP(OFFS) ((OFFS) & 0xFF) + +#define PCI_HT_HOST_OFFS LINK_OFFS( \ + PCI_HT_CAP_HOST_WIDTH, \ + PCI_HT_CAP_HOST_FREQ, \ + PCI_HT_CAP_HOST_FREQ_CAP) + +#define PCI_HT_SLAVE0_OFFS LINK_OFFS( \ + PCI_HT_CAP_SLAVE_WIDTH0, \ + PCI_HT_CAP_SLAVE_FREQ0, \ + PCI_HT_CAP_SLAVE_FREQ_CAP0) + +#define PCI_HT_SLAVE1_OFFS LINK_OFFS( \ + PCI_HT_CAP_SLAVE_WIDTH1, \ + PCI_HT_CAP_SLAVE_FREQ1, \ + PCI_HT_CAP_SLAVE_FREQ_CAP1) + +static int ht_optimize_link( + device_t dev1, uint8_t pos1, unsigned offs1, + device_t dev2, uint8_t pos2, unsigned offs2) +{ + static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 }; + static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 }; + uint16_t freq_cap1, freq_cap2, freq_cap, freq_mask; + uint8_t width_cap1, width_cap2, width_cap, width, old_width, ln_width1, ln_width2; + uint8_t freq, old_freq; + int needs_reset; + /* Set link width and frequency */ + + /* Initially assume everything is already optimized and I don't need a reset */ + needs_reset = 0; + + /* Get the frequency capabilities */ + freq_cap1 = ht_read_freq_cap(dev1, pos1 + LINK_FREQ_CAP(offs1)); + freq_cap2 = ht_read_freq_cap(dev2, pos2 + LINK_FREQ_CAP(offs2)); + + /* Calculate the highest possible frequency */ + freq = log2(freq_cap1 & freq_cap2); + + /* See if I am changing the link freqency */ + old_freq = pci_read_config8(dev1, pos1 + LINK_FREQ(offs1)); + needs_reset |= old_freq != freq; + old_freq = pci_read_config8(dev2, pos2 + LINK_FREQ(offs2)); + needs_reset |= old_freq != freq; + + /* Set the Calulcated link frequency */ + pci_write_config8(dev1, pos1 + LINK_FREQ(offs1), freq); + pci_write_config8(dev2, pos2 + LINK_FREQ(offs2), freq); + + /* Get the width capabilities */ + width_cap1 = pci_read_config8(dev1, pos1 + LINK_WIDTH(offs1)); + width_cap2 = pci_read_config8(dev2, pos2 + LINK_WIDTH(offs2)); + + /* Calculate dev1's input width */ + ln_width1 = link_width_to_pow2[width_cap1 & 7]; + ln_width2 = link_width_to_pow2[(width_cap2 >> 4) & 7]; + if (ln_width1 > ln_width2) { + ln_width1 = ln_width2; + } + width = pow2_to_link_width[ln_width1]; + /* Calculate dev1's output width */ + ln_width1 = link_width_to_pow2[(width_cap1 >> 4) & 7]; + ln_width2 = link_width_to_pow2[width_cap2 & 7]; + if (ln_width1 > ln_width2) { + ln_width1 = ln_width2; + } + width |= pow2_to_link_width[ln_width1] << 4; + + /* See if I am changing dev1's width */ + old_width = pci_read_config8(dev1, pos1 + LINK_WIDTH(offs1) + 1); + needs_reset |= old_width != width; + + /* Set dev1's widths */ + pci_write_config8(dev1, pos1 + LINK_WIDTH(offs1) + 1, width); + + /* Calculate dev2's width */ + width = ((width & 0x70) >> 4) | ((width & 0x7) << 4); + + /* See if I am changing dev2's width */ + old_width = pci_read_config8(dev2, pos2 + LINK_WIDTH(offs2) + 1); + needs_reset |= old_width != width; + + /* Set dev2's widths */ + pci_write_config8(dev2, pos2 + LINK_WIDTH(offs2) + 1, width); + + return needs_reset; +} + +static int ht_setup_chain(device_t udev, unsigned upos) +{ + /* Assumption the HT chain that is bus 0 has the HT I/O Hub on it. + * On most boards this just happens. If a cpu has multiple + * non Coherent links the appropriate bus registers for the + * links needs to be programed to point at bus 0. + */ + unsigned next_unitid, last_unitid; + int reset_needed; + unsigned uoffs; + +#warning "FIXME handle multiple chains!" + + /* Make certain the HT bus is not enumerated */ + ht_collapse_previous_enumeration(0); + + reset_needed = 0; + uoffs = PCI_HT_HOST_OFFS; + next_unitid = 1; + do { + uint32_t id; + uint8_t pos; + unsigned flags, count; + device_t dev = PCI_DEV(0, 0, 0); + last_unitid = next_unitid; + + id = pci_read_config32(dev, PCI_VENDOR_ID); + /* If the chain is enumerated quit */ + if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0x0000)) { + break; + } + pos = ht_lookup_slave_capability(dev); + if (!pos) { + print_err("HT link capability not found\r\n"); + break; + } + /* Setup the Hypertransport link */ + reset_needed |= ht_optimize_link(udev, upos, uoffs, dev, pos, PCI_HT_SLAVE0_OFFS); + + /* Update the Unitid of the current device */ + flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS); + flags &= ~0x1f; /* mask out the bse Unit ID */ + flags |= next_unitid & 0x1f; + pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags); + + /* Remeber the location of the last device */ + udev = PCI_DEV(0, next_unitid, 0); + upos = pos; + uoffs = PCI_HT_SLAVE1_OFFS; + + /* Compute the number of unitids consumed */ + count = (flags >> 5) & 0x1f; + next_unitid += count; + + } while((last_unitid != next_unitid) && (next_unitid <= 0x1f)); + return reset_needed; +} diff --git a/src/northbridge/amd/amdk8/misc_control.c b/src/northbridge/amd/amdk8/misc_control.c index fe797aa580..df28bd0331 100644 --- a/src/northbridge/amd/amdk8/misc_control.c +++ b/src/northbridge/amd/amdk8/misc_control.c @@ -14,21 +14,96 @@ #include #include #include +#include #include "./cpu_rev.c" +#include "amdk8.h" + +#define IOMMU_APETURE_SIZE (64*1024*1024) /* 64M */ +static void mcf3_read_resources(device_t dev) +{ + struct resource *resource; + /* Read the generic PCI resources */ + pci_dev_read_resources(dev); + + /* If we are not the first processor don't allocate the gart apeture */ + if (dev->path.u.pci.devfn != PCI_DEVFN(24, 3)) { + return; + } + + /* Add a 64M Gart apeture resource */ + if (dev->resources < MAX_RESOURCES) { + resource = &dev->resource[dev->resources]; + dev->resources++; + resource->base = 0; + resource->size = IOMMU_APETURE_SIZE; + resource->align = log2(resource->size); + resource->gran = log2(resource->size); + resource->limit = 0xffffffff; /* 4G */ + resource->flags = IORESOURCE_MEM; + resource->index = 0x94; + } + else { + printk_err("%s Unexpeted resource shortage\n", dev_path(dev)); + } +} + +static void mcf3_set_resources(device_t dev) +{ + struct resource *resource, *last; + last = &dev->resource[dev->resources]; + for(resource = &dev->resource[0]; resource < last; resource++) { + if (resource->index == 0x94) { + device_t pdev; + uint32_t base; + uint32_t size; + + size = (0<<6)|(0<<5)|(0<<4)|((log2(resource->size) - 25) << 1)|(0<<0); + base = ((resource->base) >> 25) & 0x00007fff; + + pdev = 0; + while(pdev = dev_find_device(PCI_VENDOR_ID_AMD, 0x1103, pdev)) { + /* I want a 64M GART apeture */ + pci_write_config32(pdev, 0x90, (0<<6)|(0<<5)|(0<<4)|(1<<1)|(0<<0)); + /* Store the GART base address */ + pci_write_config32(pdev, 0x94, base); + /* Don't set the GART Table base address */ + pci_write_config32(pdev, 0x98, 0); + + printk_debug( + "%s %02x <- [0x%08lx - 0x%08lx] mem \n", + dev_path(pdev), + resource->index, + resource->base, resource->base + resource->size - 1); + } + /* Remember this resource has been stored */ + resource->flags |= IORESOURCE_STORED; + + } + } + /* Set the generic PCI resources */ + pci_dev_set_resources(dev); +} -static cpu_reset_count = 0; static void misc_control_init(struct device *dev) { - uint32_t cmd; + uint32_t cmd, cmd_ref; + int needs_reset; + struct device *f0_dev, *f2_dev; printk_debug("NB: Function 3 Misc Control.. "); - - /* disable error reporting */ + needs_reset = 0; + + /* Disable Machine checks from Invalid Locations. + * This is needed for PC backwards compatibility. + */ cmd = pci_read_config32(dev, 0x44); cmd |= (1<<6) | (1<<25); pci_write_config32(dev, 0x44, cmd ); if (is_cpu_pre_c0()) { - /* errata 58 */ + + /* Errata 58 + * Disable CPU low power states C2, C1 and throttling + */ cmd = pci_read_config32(dev, 0x80); cmd &= ~(1<<0); pci_write_config32(dev, 0x80, cmd ); @@ -36,62 +111,86 @@ static void misc_control_init(struct device *dev) cmd &= ~(1<<24); cmd &= ~(1<<8); pci_write_config32(dev, 0x84, cmd ); - /* errata 66 */ + + /* Errata 66 + * Limit the number of downstream posted requests to 1 + */ cmd = pci_read_config32(dev, 0x70); - cmd &= ~(1<<0); - cmd |= (1<<1); - pci_write_config32(dev, 0x70, cmd ); + if ((cmd & (3 << 0)) != 2) { + cmd &= ~(3<<0); + cmd |= (2<<0); + pci_write_config32(dev, 0x70, cmd ); + needs_reset = 1; + } cmd = pci_read_config32(dev, 0x7c); - cmd &= ~(3<<4); - pci_write_config32(dev, 0x7c, cmd ); + if ((cmd & (3 << 4)) != 0) { + cmd &= ~(3<<4); + cmd |= (0<<4); + pci_write_config32(dev, 0x7c, cmd ); + needs_reset = 1; + } + /* Clock Power/Timing Low */ + cmd = pci_read_config32(dev, 0xd4); + if (cmd != 0x000D0001) { + cmd = 0x000D0001; + pci_write_config32(dev, 0xd4, cmd); + needs_reset = 1; /* Needed? */ + } } else { - /* errata 98 */ -#if 0 + uint32_t dcl; + f2_dev = dev_find_slot(0, dev->path.u.pci.devfn - 3 + 2); + /* Errata 98 + * Set Clk Ramp Hystersis to 7 + * Clock Power/Timing Low + */ + cmd_ref = 0x04e20707; /* Registered */ + dcl = pci_read_config32(f2_dev, DRAM_CONFIG_LOW); + if (dcl & DCL_UnBufDimm) { + cmd_ref = 0x000D0701; /* Unbuffered */ + } cmd = pci_read_config32(dev, 0xd4); - if(cmd != 0x04e20707) { - cmd = 0x04e20707; - pci_write_config32(dev, 0xd4, cmd ); - hard_reset(); + if(cmd != cmd_ref) { + pci_write_config32(dev, 0xd4, cmd_ref ); + needs_reset = 1; /* Needed? */ } -#endif - - cmd = 0x04e20707; - pci_write_config32(dev, 0xd4, cmd ); } - -/* - * FIXME: This preprocessor check is a mere workaround. - * The right fix is to walk over all links on all nodes - * and set the FIFO read pointer optimization value to - * 0x25 for each link connected to an AMD HT device. - * - * The reason this is only enabled for machines with more - * than one CPU is that Athlon64 machines don't have the - * link at all that is optimized in the code. - */ - -#if CONFIG_MAX_CPUS > 1 -#if HAVE_HARD_RESET==1 - cpu_reset_count++; - cmd = pci_read_config32(dev, 0xdc); - if((cmd & 0x0000ff00) != 0x02500) { - cmd &= 0xffff00ff; - cmd |= 0x00002500; - pci_write_config32(dev, 0xdc, cmd ); - if(cpu_reset_count==CONFIG_MAX_CPUS) { - printk_debug("resetting cpu\n"); - hard_reset(); + /* Optimize the Link read pointers */ + f0_dev = dev_find_slot(0, dev->path.u.pci.devfn - 3); + if (f0_dev) { + int link; + cmd_ref = cmd = pci_read_config32(dev, 0xdc); + for(link = 0; link < 3; link++) { + uint32_t link_type; + unsigned reg; + /* This works on an Athlon64 because unimplemented links return 0 */ + reg = 0x98 + (link * 0x20); + link_type = pci_read_config32(f0_dev, reg); + if (link_type & LinkConnected) { + cmd &= 0xff << (link *8); + /* FIXME this assumes the device on the other side is an AMD device */ + cmd |= 0x25 << (link *8); + } + } + if (cmd != cmd_ref) { + pci_write_config32(dev, 0xdc, cmd); + needs_reset = 1; } - } -#endif -#endif + } + else { + printk_err("Missing f0 device!\n"); + } + if (needs_reset) { + printk_debug("resetting cpu\n"); + hard_reset(); + } printk_debug("done.\n"); } + static struct device_operations mcf3_ops = { - .read_resources = pci_dev_read_resources, - .set_resources = pci_dev_set_resources, + .read_resources = mcf3_read_resources, + .set_resources = mcf3_set_resources, .enable_resources = pci_dev_enable_resources, .init = misc_control_init, .scan_bus = 0, @@ -102,4 +201,3 @@ static struct pci_driver mcf3_driver __pci_driver = { .vendor = PCI_VENDOR_ID_AMD, .device = 0x1103, }; - diff --git a/src/northbridge/amd/amdk8/northbridge.c b/src/northbridge/amd/amdk8/northbridge.c index e62aded451..12d8f73c0b 100644 --- a/src/northbridge/amd/amdk8/northbridge.c +++ b/src/northbridge/amd/amdk8/northbridge.c @@ -38,7 +38,7 @@ struct mem_range *sizeram(void) mmio_basek &= ~((256*1024) - 1); #endif -#if 1 +#if 0 printk_debug("mmio_base: %dKB\n", mmio_basek); #endif @@ -383,8 +383,14 @@ static void amdk8_set_resource(device_t dev, struct resource *resource, unsigned { unsigned long rbase, rlimit; unsigned reg, link; + /* Make certain the resource has actually been set */ - if (!(resource->flags & IORESOURCE_SET)) { + if (!(resource->flags & IORESOURCE_ASSIGNED)) { + return; + } + + /* If I have already stored this resource don't worry about it */ + if (resource->flags & IORESOURCE_STORED) { return; } @@ -401,7 +407,7 @@ static void amdk8_set_resource(device_t dev, struct resource *resource, unsigned /* Get the register and link */ reg = resource->index & ~3; link = resource->index & 3; - + if (resource->flags & IORESOURCE_IO) { uint32_t base, limit; compute_allocate_resource(&dev->link[link], resource, @@ -415,13 +421,14 @@ static void amdk8_set_resource(device_t dev, struct resource *resource, unsigned limit |= rlimit & 0x01fff000; limit |= (link & 3) << 4; limit |= (nodeid & 7); - if (reg == 0xc8){ - /* hack to set vga for test */ - /* factory: b0: 03 0a 00 00 00 0b 00 00 */ - f1_write_config32(0xb0, 0xa03); - f1_write_config32(0xb4, 0xb00); - base |= 0x30; + + if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_VGA) { + base |= PCI_IO_BASE_VGA_EN; + } + if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_NO_ISA) { + base |= PCI_IO_BASE_NO_ISA; } + f1_write_config32(reg + 0x4, limit); f1_write_config32(reg, base); } @@ -441,6 +448,7 @@ static void amdk8_set_resource(device_t dev, struct resource *resource, unsigned f1_write_config32(reg + 0x4, limit); f1_write_config32(reg, base); } + resource->flags |= IORESOURCE_STORED; printk_debug( "%s %02x <- [0x%08lx - 0x%08lx] node %d link %d %s\n", dev_path(dev), @@ -483,51 +491,46 @@ unsigned int amdk8_scan_root_bus(device_t root, unsigned int max) return max; } -void amdk8_enable_resources(struct device *dev) +static void mcf0_control_init(struct device *dev) { - uint16_t ctrl; - unsigned link; - unsigned int vgalink = -1; - - ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL); - ctrl |= dev->link[0].bridge_ctrl; - printk_debug("%s bridge ctrl <- %04x\n", dev_path(dev), ctrl); - printk_err("%s bridge ctrl <- %04x\n", dev_path(dev), ctrl); - pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl); - -#if 0 - /* let's see what link VGA is on */ - for(link = 0; link < dev->links; link++) { - device_t child; - printk_err("Kid %d of k8: bridge ctrl says: 0x%x\n", link, dev->link[link].bridge_ctrl); - if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_VGA) - vgalink = link; - } - - if (vgalink != =1) { - /* now find the IOPAIR that goes to vgalink and set the vga enable in the base part (0x30) */ - /* now allocate an MMIOPAIR and point it to the CPU0, LINK=vgalink */ - /* now set IORR1 so it has a hole for the 0xa0000-0xcffff region */ - } + uint32_t cmd; + +#if 1 + printk_debug("NB: Function 0 Misc Control.. "); + /* improve latency and bandwith on HT */ + cmd = pci_read_config32(dev, 0x68); + cmd &= 0xffff80ff; + cmd |= 0x00004800; + pci_write_config32(dev, 0x68, cmd ); #endif - pci_dev_enable_resources(dev); - //enable_childrens_resources(dev); +#if 0 + /* over drive the ht port to 1000 Mhz */ + cmd = pci_read_config32(dev, 0xa8); + cmd &= 0xfffff0ff; + cmd |= 0x00000600; + pci_write_config32(dev, 0xdc, cmd ); +#endif + printk_debug("done.\n"); } - - static struct device_operations northbridge_operations = { .read_resources = amdk8_read_resources, .set_resources = amdk8_set_resources, -// .enable_resources = pci_dev_enable_resources, - .enable_resources = amdk8_enable_resources, - .init = 0, + .enable_resources = pci_dev_enable_resources, + .init = mcf0_control_init, .scan_bus = amdk8_scan_chains, .enable = 0, }; +static struct pci_driver mcf0_driver __pci_driver = { + .ops = &northbridge_operations, + .vendor = PCI_VENDOR_ID_AMD, + .device = 0x1100, +}; + + static void enumerate(struct chip *chip) { chip_enumerate(chip); @@ -538,4 +541,3 @@ struct chip_control northbridge_amd_amdk8_control = { .name = "AMD K8 Northbridge", .enumerate = enumerate, }; - diff --git a/src/northbridge/amd/amdk8/raminit.c b/src/northbridge/amd/amdk8/raminit.c index 006ab196df..bc73fcba16 100644 --- a/src/northbridge/amd/amdk8/raminit.c +++ b/src/northbridge/amd/amdk8/raminit.c @@ -1,202 +1,21 @@ #include #include "raminit.h" +#include "amdk8.h" -#define ENABLE_IOMMU 1 - -/* Function 2 */ -#define DRAM_CSBASE 0x40 -#define DRAM_CSMASK 0x60 -#define DRAM_BANK_ADDR_MAP 0x80 -#define DRAM_TIMING_LOW 0x88 -#define DTL_TCL_SHIFT 0 -#define DTL_TCL_MASK 0x7 -#define DTL_CL_2 1 -#define DTL_CL_3 2 -#define DTL_CL_2_5 5 -#define DTL_TRC_SHIFT 4 -#define DTL_TRC_MASK 0xf -#define DTL_TRC_BASE 7 -#define DTL_TRC_MIN 7 -#define DTL_TRC_MAX 22 -#define DTL_TRFC_SHIFT 8 -#define DTL_TRFC_MASK 0xf -#define DTL_TRFC_BASE 9 -#define DTL_TRFC_MIN 9 -#define DTL_TRFC_MAX 24 -#define DTL_TRCD_SHIFT 12 -#define DTL_TRCD_MASK 0x7 -#define DTL_TRCD_BASE 0 -#define DTL_TRCD_MIN 2 -#define DTL_TRCD_MAX 6 -#define DTL_TRRD_SHIFT 16 -#define DTL_TRRD_MASK 0x7 -#define DTL_TRRD_BASE 0 -#define DTL_TRRD_MIN 2 -#define DTL_TRRD_MAX 4 -#define DTL_TRAS_SHIFT 20 -#define DTL_TRAS_MASK 0xf -#define DTL_TRAS_BASE 0 -#define DTL_TRAS_MIN 5 -#define DTL_TRAS_MAX 15 -#define DTL_TRP_SHIFT 24 -#define DTL_TRP_MASK 0x7 -#define DTL_TRP_BASE 0 -#define DTL_TRP_MIN 2 -#define DTL_TRP_MAX 6 -#define DTL_TWR_SHIFT 28 -#define DTL_TWR_MASK 0x1 -#define DTL_TWR_BASE 2 -#define DTL_TWR_MIN 2 -#define DTL_TWR_MAX 3 -#define DRAM_TIMING_HIGH 0x8c -#define DTH_TWTR_SHIFT 0 -#define DTH_TWTR_MASK 0x1 -#define DTH_TWTR_BASE 1 -#define DTH_TWTR_MIN 1 -#define DTH_TWTR_MAX 2 -#define DTH_TRWT_SHIFT 4 -#define DTH_TRWT_MASK 0x7 -#define DTH_TRWT_BASE 1 -#define DTH_TRWT_MIN 1 -#define DTH_TRWT_MAX 6 -#define DTH_TREF_SHIFT 8 -#define DTH_TREF_MASK 0x1f -#define DTH_TREF_100MHZ_4K 0x00 -#define DTH_TREF_133MHZ_4K 0x01 -#define DTH_TREF_166MHZ_4K 0x02 -#define DTH_TREF_200MHZ_4K 0x03 -#define DTH_TREF_100MHZ_8K 0x08 -#define DTH_TREF_133MHZ_8K 0x09 -#define DTH_TREF_166MHZ_8K 0x0A -#define DTH_TREF_200MHZ_8K 0x0B -#define DTH_TWCL_SHIFT 20 -#define DTH_TWCL_MASK 0x7 -#define DTH_TWCL_BASE 1 -#define DTH_TWCL_MIN 1 -#define DTH_TWCL_MAX 2 -#define DRAM_CONFIG_LOW 0x90 -#define DCL_DLL_Disable (1<<0) -#define DCL_D_DRV (1<<1) -#define DCL_QFC_EN (1<<2) -#define DCL_DisDqsHys (1<<3) -#define DCL_DramInit (1<<8) -#define DCL_DramEnable (1<<10) -#define DCL_MemClrStatus (1<<11) -#define DCL_ESR (1<<12) -#define DCL_SRS (1<<13) -#define DCL_128BitEn (1<<16) -#define DCL_DimmEccEn (1<<17) -#define DCL_UnBufDimm (1<<18) -#define DCL_32ByteEn (1<<19) -#define DCL_x4DIMM_SHIFT 20 -#define DRAM_CONFIG_HIGH 0x94 -#define DCH_ASYNC_LAT_SHIFT 0 -#define DCH_ASYNC_LAT_MASK 0xf -#define DCH_ASYNC_LAT_BASE 0 -#define DCH_ASYNC_LAT_MIN 0 -#define DCH_ASYNC_LAT_MAX 15 -#define DCH_RDPREAMBLE_SHIFT 8 -#define DCH_RDPREAMBLE_MASK 0xf -#define DCH_RDPREAMBLE_BASE ((2<<1)+0) /* 2.0 ns */ -#define DCH_RDPREAMBLE_MIN ((2<<1)+0) /* 2.0 ns */ -#define DCH_RDPREAMBLE_MAX ((9<<1)+1) /* 9.5 ns */ -#define DCH_IDLE_LIMIT_SHIFT 16 -#define DCH_IDLE_LIMIT_MASK 0x7 -#define DCH_IDLE_LIMIT_0 0 -#define DCH_IDLE_LIMIT_4 1 -#define DCH_IDLE_LIMIT_8 2 -#define DCH_IDLE_LIMIT_16 3 -#define DCH_IDLE_LIMIT_32 4 -#define DCH_IDLE_LIMIT_64 5 -#define DCH_IDLE_LIMIT_128 6 -#define DCH_IDLE_LIMIT_256 7 -#define DCH_DYN_IDLE_CTR_EN (1 << 19) -#define DCH_MEMCLK_SHIFT 20 -#define DCH_MEMCLK_MASK 0x7 -#define DCH_MEMCLK_100MHZ 0 -#define DCH_MEMCLK_133MHZ 2 -#define DCH_MEMCLK_166MHZ 5 -#define DCH_MEMCLK_200MHZ 7 -#define DCH_MEMCLK_VALID (1 << 25) -#define DCH_MEMCLK_EN0 (1 << 26) -#define DCH_MEMCLK_EN1 (1 << 27) -#define DCH_MEMCLK_EN2 (1 << 28) -#define DCH_MEMCLK_EN3 (1 << 29) - -/* Function 3 */ -#define MCA_NB_CONFIG 0x44 -#define MNC_ECC_EN (1 << 22) -#define MNC_CHIPKILL_EN (1 << 23) -#define SCRUB_CONTROL 0x58 -#define SCRUB_NONE 0 -#define SCRUB_40ns 1 -#define SCRUB_80ns 2 -#define SCRUB_160ns 3 -#define SCRUB_320ns 4 -#define SCRUB_640ns 5 -#define SCRUB_1_28us 6 -#define SCRUB_2_56us 7 -#define SCRUB_5_12us 8 -#define SCRUB_10_2us 9 -#define SCRUB_20_5us 10 -#define SCRUB_41_0us 11 -#define SCRUB_81_9us 12 -#define SCRUB_163_8us 13 -#define SCRUB_327_7us 14 -#define SCRUB_655_4us 15 -#define SCRUB_1_31ms 16 -#define SCRUB_2_62ms 17 -#define SCRUB_5_24ms 18 -#define SCRUB_10_49ms 19 -#define SCRUB_20_97ms 20 -#define SCRUB_42ms 21 -#define SCRUB_84ms 22 -#define SC_DRAM_SCRUB_RATE_SHFIT 0 -#define SC_DRAM_SCRUB_RATE_MASK 0x1f -#define SC_L2_SCRUB_RATE_SHIFT 8 -#define SC_L2_SCRUB_RATE_MASK 0x1f -#define SC_L1D_SCRUB_RATE_SHIFT 16 -#define SC_L1D_SCRUB_RATE_MASK 0x1f -#define SCRUB_ADDR_LOW 0x5C -#define SCRUB_ADDR_HIGH 0x60 -#define NORTHBRIDGE_CAP 0xE8 -#define NBCAP_128Bit 0x0001 -#define NBCAP_MP 0x0002 -#define NBCAP_BIG_MP 0x0004 -#define NBCAP_ECC 0x0004 -#define NBCAP_CHIPKILL_ECC 0x0010 -#define NBCAP_MEMCLK_SHIFT 5 -#define NBCAP_MEMCLK_MASK 3 -#define NBCAP_MEMCLK_100MHZ 3 -#define NBCAP_MEMCLK_133MHZ 2 -#define NBCAP_MEMCLK_166MHZ 1 -#define NBCAP_MEMCLK_200MHZ 0 -#define NBCAP_MEMCTRL 0x0100 - - +#if (CONFIG_LB_MEM_TOPK & (CONFIG_LB_MEM_TOPK -1)) != 0 +# error "CONFIG_LB_MEM_TOPK must be a power of 2" +#endif static void setup_resource_map(const unsigned int *register_values, int max) { int i; - - unsigned int amd8111_link_nr; - - print_debug("setting up resource map....\r\n"); - /* - * determine the HT link number the southbridge is connected to - * bits 8-9 of the Unit ID register - */ - amd8111_link_nr = (pci_read_config32(PCI_DEV(0, 0x18, 0), 0x64) & 0x00000300) >> 8; - print_debug(" AMD8111 southbridge is connected to HT link "); - print_debug_hex32(amd8111_link_nr); - print_debug("\r\n"); - - - print_debug("setting up resource map....\r\n"); + print_debug("setting up resource map...."); +#if 0 + print_debug("\r\n"); +#endif for(i = 0; i < max; i += 3) { device_t dev; unsigned where; unsigned long reg; - #if 0 print_debug_hex32(register_values[i]); print_debug(" <-"); @@ -208,19 +27,6 @@ static void setup_resource_map(const unsigned int *register_values, int max) reg = pci_read_config32(dev, where); reg &= register_values[i+1]; reg |= register_values[i+2]; - - /* - * set correct HT link to the southbridge - * otherwise we cut of the acces to the flash we are from - * - */ - if (where == 0xBC) - reg |= amd8111_link_nr << 4; - if (where == 0xC4) - reg |= amd8111_link_nr << 4; - if (where == 0xE0) - reg |= amd8111_link_nr << 8; - pci_write_config32(dev, where, reg); #if 0 reg = pci_read_config32(register_values[i]); @@ -952,29 +758,22 @@ static void sdram_set_registers(const struct mem_controller *ctrl) * [31: 8] Reserved */ PCI_ADDR(0, 0x18, 3, 0x60), 0xffffff00, 0x00000000, - -#if ENABLE_IOMMU != 0 - /* BY LYH add IOMMU 64M APERTURE */ - PCI_ADDR(0, 0x18, 3, 0x94), 0xffff8000, 0x00000f70, - PCI_ADDR(0, 0x18, 3, 0x90), 0xffffff80, 0x00000002, - PCI_ADDR(0, 0x18, 3, 0x98), 0x0000000f, 0x00068300, -#endif }; int i; int max; - print_debug("setting up CPU"); - print_debug_hex8(ctrl->node_id); - print_debug(" northbridge registers\r\n"); + print_spew("setting up CPU"); + print_spew_hex8(ctrl->node_id); + print_spew(" northbridge registers\r\n"); max = sizeof(register_values)/sizeof(register_values[0]); for(i = 0; i < max; i += 3) { device_t dev; unsigned where; unsigned long reg; #if 0 - print_debug_hex32(register_values[i]); - print_debug(" <-"); - print_debug_hex32(register_values[i+2]); - print_debug("\r\n"); + print_spew_hex32(register_values[i]); + print_spew(" <-"); + print_spew_hex32(register_values[i+2]); + print_spew("\r\n"); #endif dev = (register_values[i] & ~0xff) - PCI_DEV(0, 0x18, 0) + ctrl->f0; where = register_values[i] & 0xff; @@ -990,10 +789,26 @@ static void sdram_set_registers(const struct mem_controller *ctrl) pci_write_config32(register_values[i], reg); #endif } - print_debug("done.\r\n"); + print_spew("done.\r\n"); } +static void hw_enable_ecc(const struct mem_controller *ctrl) +{ + uint32_t dcl, nbcap; + nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP); + dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); + dcl &= ~DCL_DimmEccEn; + if (nbcap & NBCAP_ECC) { + dcl |= DCL_DimmEccEn; + } + if (read_option(CMOS_VSTART_ECC_memory, CMOS_VLEN_ECC_memory, 1) == 0) { + dcl &= ~DCL_DimmEccEn; + } + pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); + +} + static int is_dual_channel(const struct mem_controller *ctrl) { uint32_t dcl; @@ -1042,46 +857,60 @@ static struct dimm_size spd_get_dimm_size(unsigned device) * sides of an assymetric dimm. */ value = spd_read_byte(device, 3); /* rows */ - if (value < 0) goto out; + if (value < 0) goto hw_err; + if ((value & 0xf) == 0) goto val_err; sz.side1 += value & 0xf; value = spd_read_byte(device, 4); /* columns */ - if (value < 0) goto out; + if (value < 0) goto hw_err; + if ((value & 0xf) == 0) goto val_err; sz.side1 += value & 0xf; value = spd_read_byte(device, 17); /* banks */ - if (value < 0) goto out; + if (value < 0) goto hw_err; + if ((value & 0xff) == 0) goto val_err; sz.side1 += log2(value & 0xff); /* Get the module data width and convert it to a power of two */ value = spd_read_byte(device, 7); /* (high byte) */ - if (value < 0) goto out; + if (value < 0) goto hw_err; value &= 0xff; value <<= 8; low = spd_read_byte(device, 6); /* (low byte) */ - if (low < 0) goto out; + if (low < 0) goto hw_err; value = value | (low & 0xff); + if ((value != 72) && (value &= 64)) goto val_err; sz.side1 += log2(value); /* side 2 */ value = spd_read_byte(device, 5); /* number of physical banks */ - if (value <= 1) goto out; + if (value < 0) goto hw_err; + if (value == 1) goto out; + if (value != 2) goto val_err; /* Start with the symmetrical case */ sz.side2 = sz.side1; value = spd_read_byte(device, 3); /* rows */ - if (value < 0) goto out; + if (value < 0) goto hw_err; if ((value & 0xf0) == 0) goto out; /* If symmetrical we are done */ sz.side2 -= (value & 0x0f); /* Subtract out rows on side 1 */ sz.side2 += ((value >> 4) & 0x0f); /* Add in rows on side 2 */ value = spd_read_byte(device, 4); /* columns */ - if (value < 0) goto out; + if (value < 0) goto hw_err; + if ((value & 0xff) == 0) goto val_err; sz.side2 -= (value & 0x0f); /* Subtract out columns on side 1 */ sz.side2 += ((value >> 4) & 0x0f); /* Add in columsn on side 2 */ + goto out; + val_err: + die("Bad SPD value\r\n"); + /* If an hw_error occurs report that I have no memory */ +hw_err: + sz.side1 = 0; + sz.side2 = 0; out: return sz; } @@ -1091,15 +920,6 @@ static void set_dimm_size(const struct mem_controller *ctrl, struct dimm_size sz uint32_t base0, base1, map; uint32_t dch; -#if 0 - print_debug("set_dimm_size: ("); - print_debug_hex32(sz.side1); - print_debug_char(','); - print_debug_hex32(sz.side2); - print_debug_char(','); - print_debug_hex32(index); - print_debug(")\r\n"); -#endif if (sz.side1 != sz.side2) { sz.side2 = 0; } @@ -1147,15 +967,22 @@ static void set_dimm_size(const struct mem_controller *ctrl, struct dimm_size sz } } -static void spd_set_ram_size(const struct mem_controller *ctrl) +static long spd_set_ram_size(const struct mem_controller *ctrl, long dimm_mask) { int i; - for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { + for(i = 0; i < DIMM_SOCKETS; i++) { struct dimm_size sz; + if (!(dimm_mask & (1 << i))) { + continue; + } sz = spd_get_dimm_size(ctrl->channel0[i]); + if (sz.side1 == 0) { + return -1; /* Report SPD error */ + } set_dimm_size(ctrl, sz, i); } + return dimm_mask; } static void route_dram_accesses(const struct mem_controller *ctrl, @@ -1191,20 +1018,13 @@ static void set_top_mem(unsigned tom_k) { /* Error if I don't have memory */ if (!tom_k) { - set_bios_reset(); - print_debug("No memory - reset"); - /* enable cf9 */ - pci_write_config8(PCI_DEV(0, 0x04, 3), 0x41, 0xf1); - /* reset */ - outb(0x0e, 0x0cf9); + die("No memory?"); } -#if 1 /* Report the amount of memory. */ - print_debug("RAM: 0x"); - print_debug_hex32(tom_k); - print_debug(" KB\r\n"); -#endif + print_spew("RAM: 0x"); + print_spew_hex32(tom_k); + print_spew(" KB\r\n"); /* Now set top of memory */ msr_t msr; @@ -1238,7 +1058,6 @@ static unsigned long interleave_chip_selects(const struct mem_controller *ctrl) uint32_t csbase_inc; int chip_selects, index; int bits; - int dual_channel; unsigned common_size; uint32_t csbase, csmask; @@ -1306,9 +1125,8 @@ static unsigned long interleave_chip_selects(const struct mem_controller *ctrl) csbase += csbase_inc; } -#if 1 - print_debug("Interleaved\r\n"); -#endif + print_spew("Interleaved\r\n"); + /* Return the memory size in K */ return common_size << (15 + bits); } @@ -1368,7 +1186,6 @@ static unsigned long order_chip_selects(const struct mem_controller *ctrl) /* Compute the memory mask */ csmask = ((size -1) << 21); csmask |= 0xfe00; /* For now don't optimize */ -#warning "Don't forget to optimize the DIMM size" /* Write the new base register */ pci_write_config32(ctrl->f2, DRAM_CSBASE + (canidate << 2), csbase); @@ -1380,18 +1197,13 @@ static unsigned long order_chip_selects(const struct mem_controller *ctrl) return (tom & ~0xff000000) << 15; } -static void order_dimms(const struct mem_controller *ctrl) +unsigned long memory_end_k(const struct mem_controller *ctrl, int max_node_id) { - unsigned long tom, tom_k, base_k; unsigned node_id; - - tom_k = interleave_chip_selects(ctrl); - if (!tom_k) { - tom_k = order_chip_selects(ctrl); - } - /* Compute the memory base address */ - base_k = 0; - for(node_id = 0; node_id < ctrl->node_id; node_id++) { + unsigned end_k; + /* Find the last memory address used */ + end_k = 0; + for(node_id = 0; node_id < max_node_id; node_id++) { uint32_t limit, base; unsigned index; index = node_id << 3; @@ -1399,32 +1211,44 @@ static void order_dimms(const struct mem_controller *ctrl) /* Only look at the limit if the base is enabled */ if ((base & 3) == 3) { limit = pci_read_config32(ctrl->f1, 0x44 + index); - base_k = ((limit + 0x00010000) & 0xffff0000) >> 2; + end_k = ((limit + 0x00010000) & 0xffff0000) >> 2; } } + return end_k; +} + +static void order_dimms(const struct mem_controller *ctrl) +{ + unsigned long tom_k, base_k; + + if (read_option(CMOS_VSTART_interleave_chip_selects, CMOS_VLEN_interleave_chip_selects, 1) != 0) { + tom_k = interleave_chip_selects(ctrl); + } else { + print_debug("Interleaving disabled\r\n"); + tom_k = 0; + } + if (!tom_k) { + tom_k = order_chip_selects(ctrl); + } + /* Compute the memory base address */ + base_k = memory_end_k(ctrl, ctrl->node_id); tom_k += base_k; -#if 0 - print_debug("base_k: "); - print_debug_hex32(base_k); - print_debug(" tom_k: "); - print_debug_hex32(tom_k); - print_debug("\r\n"); -#endif route_dram_accesses(ctrl, base_k, tom_k); set_top_mem(tom_k); } -static void disable_dimm(const struct mem_controller *ctrl, unsigned index) +static long disable_dimm(const struct mem_controller *ctrl, unsigned index, long dimm_mask) { print_debug("disabling dimm"); print_debug_hex8(index); print_debug("\r\n"); pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+0)<<2), 0); pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+1)<<2), 0); + dimm_mask &= ~(1 << index); + return dimm_mask; } - -static void spd_handle_unbuffered_dimms(const struct mem_controller *ctrl) +static long spd_handle_unbuffered_dimms(const struct mem_controller *ctrl, long dimm_mask) { int i; int registered; @@ -1432,12 +1256,14 @@ static void spd_handle_unbuffered_dimms(const struct mem_controller *ctrl) uint32_t dcl; unbuffered = 0; registered = 0; - for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { + for(i = 0; (i < DIMM_SOCKETS); i++) { int value; + if (!(dimm_mask & (1 << i))) { + continue; + } value = spd_read_byte(ctrl->channel0[i], 21); if (value < 0) { - disable_dimm(ctrl, i); - continue; + return -1; } /* Registered dimm ? */ if (value & (1 << 1)) { @@ -1468,15 +1294,40 @@ static void spd_handle_unbuffered_dimms(const struct mem_controller *ctrl) print_debug("Unbuffered\r\n"); } #endif + return dimm_mask; } -static void spd_enable_2channels(const struct mem_controller *ctrl) +static unsigned int spd_detect_dimms(const struct mem_controller *ctrl) +{ + unsigned dimm_mask; + int i; + dimm_mask = 0; + for(i = 0; i < DIMM_SOCKETS; i++) { + int byte; + unsigned device; + device = ctrl->channel0[i]; + if (device) { + byte = spd_read_byte(ctrl->channel0[i], 2); /* Type */ + if (byte == 7) { + dimm_mask |= (1 << i); + } + } + device = ctrl->channel1[i]; + if (device) { + byte = spd_read_byte(ctrl->channel1[i], 2); + if (byte == 7) { + dimm_mask |= (1 << (i + DIMM_SOCKETS)); + } + } + } + return dimm_mask; +} + +static long spd_enable_2channels(const struct mem_controller *ctrl, long dimm_mask) { int i; uint32_t nbcap; /* SPD addresses to verify are identical */ -#warning "FINISHME review and see if these are the bytes I need" - /* FINISHME review and see if these are the bytes I need */ static const unsigned addresses[] = { 2, /* Type should be DDR SDRAM */ 3, /* *Row addresses */ @@ -1499,40 +1350,52 @@ static void spd_enable_2channels(const struct mem_controller *ctrl) 41, /* *Minimum Active to Active/Auto Refresh Time(Trc) */ 42, /* *Minimum Auto Refresh Command Time(Trfc) */ }; + /* If the dimms are not in pairs do not do dual channels */ + if ((dimm_mask & ((1 << DIMM_SOCKETS) - 1)) != + ((dimm_mask >> DIMM_SOCKETS) & ((1 << DIMM_SOCKETS) - 1))) { + goto single_channel; + } + /* If the cpu is not capable of doing dual channels don't do dual channels */ nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP); if (!(nbcap & NBCAP_128Bit)) { - return; + goto single_channel; } for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { unsigned device0, device1; int value0, value1; int j; + /* If I don't have a dimm skip this one */ + if (!(dimm_mask & (1 << i))) { + continue; + } device0 = ctrl->channel0[i]; device1 = ctrl->channel1[i]; - if (!device1) - return; for(j = 0; j < sizeof(addresses)/sizeof(addresses[0]); j++) { unsigned addr; addr = addresses[j]; value0 = spd_read_byte(device0, addr); if (value0 < 0) { - break; + return -1; } value1 = spd_read_byte(device1, addr); if (value1 < 0) { - return; + return -1; } if (value0 != value1) { - return; + goto single_channel; } } } - print_debug("Enabling dual channel memory\r\n"); + print_spew("Enabling dual channel memory\r\n"); uint32_t dcl; dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); dcl &= ~DCL_32ByteEn; dcl |= DCL_128BitEn; pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); + return dimm_mask; + single_channel: + dimm_mask &= ~((1 << (DIMM_SOCKETS *2)) - (1 << DIMM_SOCKETS)); + return dimm_mask; } struct mem_param { @@ -1606,17 +1469,22 @@ static const struct mem_param *get_mem_param(unsigned min_cycle_time) if (!param->cycle_time) { die("min_cycle_time to low"); } -#if 1 + print_spew(param->name); +#ifdef DRAM_MIN_CYCLE_TIME print_debug(param->name); #endif return param; } -static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl) +struct spd_set_memclk_result { + const struct mem_param *param; + long dimm_mask; +}; +static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *ctrl, long dimm_mask) { /* Compute the minimum cycle time for these dimms */ - const struct mem_param *param; - unsigned min_cycle_time, min_latency; + struct spd_set_memclk_result result; + unsigned min_cycle_time, min_latency, bios_cycle_time; int i; uint32_t value; @@ -1631,25 +1499,26 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl) value = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP); min_cycle_time = min_cycle_times[(value >> NBCAP_MEMCLK_SHIFT) & NBCAP_MEMCLK_MASK]; + bios_cycle_time = min_cycle_times[ + read_option(CMOS_VSTART_max_mem_clock, CMOS_VLEN_max_mem_clock, 0)]; + if (bios_cycle_time > min_cycle_time) { + min_cycle_time = bios_cycle_time; + } min_latency = 2; -#if 0 - print_debug("min_cycle_time: "); - print_debug_hex8(min_cycle_time); - print_debug(" min_latency: "); - print_debug_hex8(min_latency); - print_debug("\r\n"); -#endif - /* Compute the least latency with the fastest clock supported * by both the memory controller and the dimms. */ - for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { + for(i = 0; i < DIMM_SOCKETS; i++) { int new_cycle_time, new_latency; int index; int latencies; int latency; + if (!(dimm_mask & (1 << i))) { + continue; + } + /* First find the supported CAS latencies * Byte 18 for DDR SDRAM is interpreted: * bit 0 == CAS Latency = 1.0 @@ -1679,7 +1548,7 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl) } value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]); if (value < 0) { - continue; + goto hw_error; } /* Only increase the latency if we decreas the clock */ @@ -1699,15 +1568,6 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl) if (new_latency > min_latency) { min_latency = new_latency; } -#if 0 - print_debug("i: "); - print_debug_hex8(i); - print_debug(" min_cycle_time: "); - print_debug_hex8(min_cycle_time); - print_debug(" min_latency: "); - print_debug_hex8(min_latency); - print_debug("\r\n"); -#endif } /* Make a second pass through the dimms and disable * any that cannot support the selected memclk and cas latency. @@ -1718,9 +1578,12 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl) int latency; int index; int value; - int dimm; + if (!(dimm_mask & (1 << i))) { + continue; + } latencies = spd_read_byte(ctrl->channel0[i], 18); - if (latencies <= 0) { + if (latencies < 0) goto hw_error; + if (latencies == 0) { goto dimm_err; } @@ -1742,6 +1605,7 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl) /* Read the min_cycle_time for this latency */ value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]); + if (value < 0) goto hw_error; /* All is good if the selected clock speed * is what I need or slower. @@ -1751,22 +1615,15 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl) } /* Otherwise I have an error, disable the dimm */ dimm_err: - disable_dimm(ctrl, i); + dimm_mask = disable_dimm(ctrl, i, dimm_mask); } -#if 0 - print_debug("min_cycle_time: "); - print_debug_hex8(min_cycle_time); - print_debug(" min_latency: "); - print_debug_hex8(min_latency); - print_debug("\r\n"); -#endif /* Now that I know the minimum cycle time lookup the memory parameters */ - param = get_mem_param(min_cycle_time); + result.param = get_mem_param(min_cycle_time); /* Update DRAM Config High with our selected memory speed */ value = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); value &= ~(DCH_MEMCLK_MASK << DCH_MEMCLK_SHIFT); - value |= param->dch_memclk; + value |= result.param->dch_memclk; pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, value); static const unsigned latencies[] = { DTL_CL_2, DTL_CL_2_5, DTL_CL_3 }; @@ -1776,7 +1633,12 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl) value |= latencies[min_latency - 2] << DTL_TCL_SHIFT; pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, value); - return param; + result.dimm_mask = dimm_mask; + return result; + hw_error: + result.param = (const struct mem_param *)0; + result.dimm_mask = -1; + return result; } @@ -1795,7 +1657,7 @@ static int update_dimm_Trc(const struct mem_controller *ctrl, const struct mem_p clocks = DTL_TRC_MIN; } if (clocks > DTL_TRC_MAX) { - return -1; + return 0; } dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); @@ -1806,7 +1668,7 @@ static int update_dimm_Trc(const struct mem_controller *ctrl, const struct mem_p dtl &= ~(DTL_TRC_MASK << DTL_TRC_SHIFT); dtl |= ((clocks - DTL_TRC_BASE) << DTL_TRC_SHIFT); pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); - return 0; + return 1; } static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_param *param, int i) @@ -1824,7 +1686,7 @@ static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_ clocks = DTL_TRFC_MIN; } if (clocks > DTL_TRFC_MAX) { - return -1; + return 0; } dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); old_clocks = ((dtl >> DTL_TRFC_SHIFT) & DTL_TRFC_MASK) + DTL_TRFC_BASE; @@ -1834,7 +1696,7 @@ static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_ dtl &= ~(DTL_TRFC_MASK << DTL_TRFC_SHIFT); dtl |= ((clocks - DTL_TRFC_BASE) << DTL_TRFC_SHIFT); pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); - return 0; + return 1; } @@ -1845,16 +1707,12 @@ static int update_dimm_Trcd(const struct mem_controller *ctrl, const struct mem_ int value; value = spd_read_byte(ctrl->channel0[i], 29); if (value < 0) return -1; -#if 0 clocks = (value + (param->divisor << 1) -1)/(param->divisor << 1); -#else - clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1); -#endif if (clocks < DTL_TRCD_MIN) { clocks = DTL_TRCD_MIN; } if (clocks > DTL_TRCD_MAX) { - return -1; + return 0; } dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); old_clocks = ((dtl >> DTL_TRCD_SHIFT) & DTL_TRCD_MASK) + DTL_TRCD_BASE; @@ -1864,7 +1722,7 @@ static int update_dimm_Trcd(const struct mem_controller *ctrl, const struct mem_ dtl &= ~(DTL_TRCD_MASK << DTL_TRCD_SHIFT); dtl |= ((clocks - DTL_TRCD_BASE) << DTL_TRCD_SHIFT); pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); - return 0; + return 1; } static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_param *param, int i) @@ -1874,12 +1732,12 @@ static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_ int value; value = spd_read_byte(ctrl->channel0[i], 28); if (value < 0) return -1; - clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1); + clocks = (value + (param->divisor << 1) -1)/(param->divisor << 1); if (clocks < DTL_TRRD_MIN) { clocks = DTL_TRRD_MIN; } if (clocks > DTL_TRRD_MAX) { - return -1; + return 0; } dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); old_clocks = ((dtl >> DTL_TRRD_SHIFT) & DTL_TRRD_MASK) + DTL_TRRD_BASE; @@ -1889,7 +1747,7 @@ static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_ dtl &= ~(DTL_TRRD_MASK << DTL_TRRD_SHIFT); dtl |= ((clocks - DTL_TRRD_BASE) << DTL_TRRD_SHIFT); pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); - return 0; + return 1; } static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_param *param, int i) @@ -1904,7 +1762,7 @@ static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_ clocks = DTL_TRAS_MIN; } if (clocks > DTL_TRAS_MAX) { - return -1; + return 0; } dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); old_clocks = ((dtl >> DTL_TRAS_SHIFT) & DTL_TRAS_MASK) + DTL_TRAS_BASE; @@ -1914,7 +1772,7 @@ static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_ dtl &= ~(DTL_TRAS_MASK << DTL_TRAS_SHIFT); dtl |= ((clocks - DTL_TRAS_BASE) << DTL_TRAS_SHIFT); pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); - return 0; + return 1; } static int update_dimm_Trp(const struct mem_controller *ctrl, const struct mem_param *param, int i) @@ -1924,25 +1782,12 @@ static int update_dimm_Trp(const struct mem_controller *ctrl, const struct mem_p int value; value = spd_read_byte(ctrl->channel0[i], 27); if (value < 0) return -1; -#if 0 clocks = (value + (param->divisor << 1) - 1)/(param->divisor << 1); -#else - clocks = (value + ((param->divisor & 0xff) << 1) - 1)/((param->divisor & 0xff) << 1); -#endif -#if 0 - print_debug("Trp: "); - print_debug_hex8(clocks); - print_debug(" spd value: "); - print_debug_hex8(value); - print_debug(" divisor: "); - print_debug_hex8(param->divisor); - print_debug("\r\n"); -#endif if (clocks < DTL_TRP_MIN) { clocks = DTL_TRP_MIN; } if (clocks > DTL_TRP_MAX) { - return -1; + return 0; } dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); old_clocks = ((dtl >> DTL_TRP_SHIFT) & DTL_TRP_MASK) + DTL_TRP_BASE; @@ -1952,7 +1797,7 @@ static int update_dimm_Trp(const struct mem_controller *ctrl, const struct mem_p dtl &= ~(DTL_TRP_MASK << DTL_TRP_SHIFT); dtl |= ((clocks - DTL_TRP_BASE) << DTL_TRP_SHIFT); pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); - return 0; + return 1; } static void set_Twr(const struct mem_controller *ctrl, const struct mem_param *param) @@ -1998,7 +1843,7 @@ static int update_dimm_Tref(const struct mem_controller *ctrl, const struct mem_ dth &= ~(DTH_TREF_MASK << DTH_TREF_SHIFT); dth |= (tref << DTH_TREF_SHIFT); pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth); - return 0; + return 1; } @@ -2019,7 +1864,7 @@ static int update_dimm_x4(const struct mem_controller *ctrl, const struct mem_pa dcl |= (1 << dimm); } pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - return 0; + return 1; } static int update_dimm_ecc(const struct mem_controller *ctrl, const struct mem_param *param, int i) @@ -2035,7 +1880,7 @@ static int update_dimm_ecc(const struct mem_controller *ctrl, const struct mem_p dcl &= ~DCL_DimmEccEn; pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); } - return 0; + return 1; } static int count_dimms(const struct mem_controller *ctrl) @@ -2045,7 +1890,7 @@ static int count_dimms(const struct mem_controller *ctrl) dimms = 0; for(index = 0; index < 8; index += 2) { uint32_t csbase; - csbase = pci_read_config32(ctrl->f2, (DRAM_CSBASE + index << 2)); + csbase = pci_read_config32(ctrl->f2, (DRAM_CSBASE + (index << 2))); if (csbase & 1) { dimms += 1; } @@ -2126,7 +1971,7 @@ static void set_Trwt(const struct mem_controller *ctrl, const struct mem_param * } } if ((clocks < DTH_TRWT_MIN) || (clocks > DTH_TRWT_MAX)) { - die("Unknown Trwt"); + die("Unknown Trwt\r\n"); } dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH); @@ -2240,7 +2085,6 @@ static void set_read_preamble(const struct mem_controller *ctrl, const struct me static void set_max_async_latency(const struct mem_controller *ctrl, const struct mem_param *param) { uint32_t dch; - int i; unsigned async_lat; int dimms; @@ -2287,33 +2131,37 @@ static void set_idle_cycle_limit(const struct mem_controller *ctrl, const struct pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch); } -static void spd_set_dram_timing(const struct mem_controller *ctrl, const struct mem_param *param) +static long spd_set_dram_timing(const struct mem_controller *ctrl, const struct mem_param *param, long dimm_mask) { - int dimms; int i; - int rc; init_Tref(ctrl, param); - for(i = 0; (i < 4) && ctrl->channel0[i]; i++) { + for(i = 0; i < DIMM_SOCKETS; i++) { int rc; + if (!(dimm_mask & (1 << i))) { + continue; + } /* DRAM Timing Low Register */ - if (update_dimm_Trc (ctrl, param, i) < 0) goto dimm_err; - if (update_dimm_Trfc(ctrl, param, i) < 0) goto dimm_err; - if (update_dimm_Trcd(ctrl, param, i) < 0) goto dimm_err; - if (update_dimm_Trrd(ctrl, param, i) < 0) goto dimm_err; - if (update_dimm_Tras(ctrl, param, i) < 0) goto dimm_err; - if (update_dimm_Trp (ctrl, param, i) < 0) goto dimm_err; + if ((rc = update_dimm_Trc (ctrl, param, i)) <= 0) goto dimm_err; + if ((rc = update_dimm_Trfc(ctrl, param, i)) <= 0) goto dimm_err; + if ((rc = update_dimm_Trcd(ctrl, param, i)) <= 0) goto dimm_err; + if ((rc = update_dimm_Trrd(ctrl, param, i)) <= 0) goto dimm_err; + if ((rc = update_dimm_Tras(ctrl, param, i)) <= 0) goto dimm_err; + if ((rc = update_dimm_Trp (ctrl, param, i)) <= 0) goto dimm_err; /* DRAM Timing High Register */ - if (update_dimm_Tref(ctrl, param, i) < 0) goto dimm_err; + if ((rc = update_dimm_Tref(ctrl, param, i)) <= 0) goto dimm_err; + /* DRAM Config Low */ - if (update_dimm_x4 (ctrl, param, i) < 0) goto dimm_err; - if (update_dimm_ecc(ctrl, param, i) < 0) goto dimm_err; + if ((rc = update_dimm_x4 (ctrl, param, i)) <= 0) goto dimm_err; + if ((rc = update_dimm_ecc(ctrl, param, i)) <= 0) goto dimm_err; continue; dimm_err: - disable_dimm(ctrl, i); - + if (rc < 0) { + return -1; + } + dimm_mask = disable_dimm(ctrl, i, dimm_mask); } /* DRAM Timing Low Register */ set_Twr(ctrl, param); @@ -2327,18 +2175,45 @@ static void spd_set_dram_timing(const struct mem_controller *ctrl, const struct set_read_preamble(ctrl, param); set_max_async_latency(ctrl, param); set_idle_cycle_limit(ctrl, param); + return dimm_mask; } static void sdram_set_spd_registers(const struct mem_controller *ctrl) { + struct spd_set_memclk_result result; const struct mem_param *param; + long dimm_mask; + hw_enable_ecc(ctrl); activate_spd_rom(ctrl); - spd_enable_2channels(ctrl); - spd_set_ram_size(ctrl); - spd_handle_unbuffered_dimms(ctrl); - param = spd_set_memclk(ctrl); - spd_set_dram_timing(ctrl, param); + dimm_mask = spd_detect_dimms(ctrl); + if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1))) { + print_debug("No memory for this cpu\r\n"); + return; + } + dimm_mask = spd_enable_2channels(ctrl, dimm_mask); + if (dimm_mask < 0) + goto hw_spd_err; + dimm_mask = spd_set_ram_size(ctrl , dimm_mask); + if (dimm_mask < 0) + goto hw_spd_err; + dimm_mask = spd_handle_unbuffered_dimms(ctrl, dimm_mask); + if (dimm_mask < 0) + goto hw_spd_err; + result = spd_set_memclk(ctrl, dimm_mask); + param = result.param; + dimm_mask = result.dimm_mask; + if (dimm_mask < 0) + goto hw_spd_err; + dimm_mask = spd_set_dram_timing(ctrl, param , dimm_mask); + if (dimm_mask < 0) + goto hw_spd_err; order_dimms(ctrl); + return; + hw_spd_err: + /* Unrecoverable error reading SPD data */ + print_err("SPD error - reset\r\n"); + hard_reset(); + return; } #define TIMEOUT_LOOPS 300000 @@ -2346,29 +2221,44 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl) { int i; + /* Error if I don't have memory */ + if (memory_end_k(ctrl, controllers) == 0) { + die("No memory\r\n"); + } + /* Before enabling memory start the memory clocks */ for(i = 0; i < controllers; i++) { uint32_t dch; dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH); - dch |= DCH_MEMCLK_VALID; - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_HIGH, dch); + if (dch & (DCH_MEMCLK_EN0|DCH_MEMCLK_EN1|DCH_MEMCLK_EN2|DCH_MEMCLK_EN3)) { + dch |= DCH_MEMCLK_VALID; + pci_write_config32(ctrl[i].f2, DRAM_CONFIG_HIGH, dch); + } + else { + /* Disable dram receivers */ + uint32_t dcl; + dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); + dcl |= DCL_DisInRcvrs; + pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); + } } /* And if necessary toggle the the reset on the dimms by hand */ memreset(controllers, ctrl); for(i = 0; i < controllers; i++) { - uint32_t dcl; + uint32_t dcl, dch; + /* Skip everything if I don't have any memory on this controller */ + dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH); + if (!(dch & DCH_MEMCLK_VALID)) { + continue; + } + /* Toggle DisDqsHys to get it working */ dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); -#if 0 - print_debug("dcl: "); - print_debug_hex32(dcl); - print_debug("\r\n"); -#endif if (dcl & DCL_DimmEccEn) { uint32_t mnc; - print_debug("ECC enabled\r\n"); + print_spew("ECC enabled\r\n"); mnc = pci_read_config32(ctrl[i].f3, MCA_NB_CONFIG); mnc |= MNC_ECC_EN; if (dcl & DCL_128BitEn) { @@ -2387,7 +2277,13 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl) } for(i = 0; i < controllers; i++) { - uint32_t dcl; + uint32_t dcl, dch; + /* Skip everything if I don't have any memory on this controller */ + dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH); + if (!(dch & DCH_MEMCLK_VALID)) { + continue; + } + print_debug("Initializing memory: "); int loops = 0; do { @@ -2399,151 +2295,98 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl) } while(((dcl & DCL_DramInit) != 0) && (loops < TIMEOUT_LOOPS)); if (loops >= TIMEOUT_LOOPS) { print_debug(" failed\r\n"); - } else { - print_debug(" done\r\n"); + continue; } - if (dcl & DCL_DimmEccEn) { - print_debug("Clearing memory: "); - if (!is_cpu_pre_c0()) { - /* Wait until the automatic ram scrubber is finished */ - dcl &= ~(DCL_MemClrStatus | DCL_DramEnable); - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); - do { - dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); - } while(((dcl & DCL_MemClrStatus) == 0) || ((dcl & DCL_DramEnable) == 0) ); - } - uint32_t base, last_scrub_k, scrub_k; - uint32_t cnt,zstart,zend; - msr_t msr,msr_201; - - /* First make certain the scrubber is disabled */ - pci_write_config32(ctrl[i].f3, SCRUB_CONTROL, - (SCRUB_NONE << 16) | (SCRUB_NONE << 8) | (SCRUB_NONE << 0)); - - /* load the start and end for the memory block to clear */ - msr_201 = rdmsr(0x201); - zstart = pci_read_config32(ctrl[0].f1, 0x40 + (i*8)); - zend = pci_read_config32(ctrl[0].f1, 0x44 + (i*8)); - zstart >>= 16; - zend >>=16; -#if 1 - print_debug("addr "); - print_debug_hex32(zstart); - print_debug("-"); - print_debug_hex32(zend); - print_debug("\r\n"); -#endif - - /* Disable fixed mtrrs */ - msr = rdmsr(MTRRdefType_MSR); - msr.lo &= ~(1<<10); - wrmsr(MTRRdefType_MSR, msr); - - /* turn on the wrap 32 disable */ - msr = rdmsr(0xc0010015); - msr.lo |= (1<<17); - wrmsr(0xc0010015,msr); - - for(;zstart>8; - wrmsr(0x200,msr); - - /* Set the limit to 64 meg of ram */ - msr.hi = 0x000000ff; - msr.lo = 0xfc000800; - wrmsr(0x201,msr); - - /* enable cache */ - __asm__ volatile( - "movl %%cr0, %0\n\t" - "andl $0x9fffffff, %0\n\t" - "movl %0, %%cr0\n\t" - :"=r" (cnt) - ); - /* Set fs base address */ - msr.lo = (zstart&0xff) << 24; - msr.hi = (zstart&0xff00) >> 8; - wrmsr(0xc0000100,msr); - - print_debug_char((zstart > 0x0ff)?'+':'-'); - - /* clear memory 64meg */ - __asm__ volatile( - "1: \n\t" - "movl %0, %%fs:(%1)\n\t" - "addl $4,%1\n\t" - "subl $1,%2\n\t" - "jnz 1b\n\t" - : - : "a" (0), "D" (0), "c" (0x01000000) - ); - } - - /* disable cache */ - __asm__ volatile( - "movl %%cr0, %0\n\t" - "orl $0x40000000, %0\n\t" - "movl %0, %%cr0\n\t" - :"=r" (cnt) - ); - - /* restore msr registers */ - msr = rdmsr(MTRRdefType_MSR); - msr.lo |= 0x0400; - wrmsr(MTRRdefType_MSR, msr); - - /* Restore the variable mtrrs */ - msr.lo = 6; - msr.hi = 0; - wrmsr(0x200,msr); - wrmsr(0x201,msr_201); - - /* Set fs base to 0 */ - msr.lo = 0; - msr.hi = 0; - wrmsr(0xc0000100,msr); - - /* enable cache */ - __asm__ volatile( - "movl %%cr0, %0\n\t" - "andl $0x9fffffff, %0\n\t" - "movl %0, %%cr0\n\t" - :"=r" (cnt) - ); - - /* turn off the wrap 32 disable */ - msr = rdmsr(0xc0010015); - msr.lo &= ~(1<<17); - wrmsr(0xc0010015,msr); - - /* Find the Srub base address for this cpu */ - base = pci_read_config32(ctrl[i].f1, 0x40 + (ctrl[i].node_id << 3)); - base &= 0xffff0000; - - /* Set the scrub base address registers */ - pci_write_config32(ctrl[i].f3, SCRUB_ADDR_LOW, base << 8); - pci_write_config32(ctrl[i].f3, SCRUB_ADDR_HIGH, base >> 24); - - /* Enable scrubbing at the lowest possible rate */ - pci_write_config32(ctrl[i].f3, SCRUB_CONTROL, - (SCRUB_84ms << 16) | (SCRUB_84ms << 8) | (SCRUB_84ms << 0)); - - print_debug("done\r\n"); + if (!is_cpu_pre_c0()) { + /* Wait until it is safe to touch memory */ + dcl &= ~(DCL_MemClrStatus | DCL_DramEnable); + pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); + do { + dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); + } while(((dcl & DCL_MemClrStatus) == 0) || ((dcl & DCL_DramEnable) == 0) ); } + print_debug(" done\r\n"); } + + /* Make certain the first 1M of memory is intialized */ + msr_t msr, msr_201; + uint32_t cnt; + + /* Save the value of msr_201 */ + msr_201 = rdmsr(0x201); + + print_debug("Clearing LinuxBIOS memory: "); + + /* disable cache */ + __asm__ volatile( + "movl %%cr0, %0\n\t" + "orl $0x40000000, %0\n\t" + "movl %0, %%cr0\n\t" + :"=r" (cnt) + ); + + /* Disable fixed mtrrs */ + msr = rdmsr(MTRRdefType_MSR); + msr.lo &= ~(1<<10); + wrmsr(MTRRdefType_MSR, msr); + + + /* Set the variable mtrrs to write combine */ + msr.hi = 0; + msr.lo = 0 | MTRR_TYPE_WRCOMB; + wrmsr(0x200, msr); + + /* Set the limit to 1M of ram */ + msr.hi = 0x000000ff; + msr.lo = (~((CONFIG_LB_MEM_TOPK << 10) - 1)) | 0x800; + wrmsr(0x201, msr); + + /* enable cache */ + __asm__ volatile( + "movl %%cr0, %0\n\t" + "andl $0x9fffffff, %0\n\t" + "movl %0, %%cr0\n\t" + :"=r" (cnt) + ); + + /* clear memory 1meg */ + __asm__ volatile( + "1: \n\t" + "movl %0, %%fs:(%1)\n\t" + "addl $4,%1\n\t" + "subl $4,%2\n\t" + "jnz 1b\n\t" + : + : "a" (0), "D" (0), "c" (1024*1024) + ); + + /* disable cache */ + __asm__ volatile( + "movl %%cr0, %0\n\t" + "orl $0x40000000, %0\n\t" + "movl %0, %%cr0\n\t" + :"=r" (cnt) + ); + + /* restore msr registers */ + msr = rdmsr(MTRRdefType_MSR); + msr.lo |= 0x0400; + wrmsr(MTRRdefType_MSR, msr); + + + /* Restore the variable mtrrs */ + msr.hi = 0; + msr.lo = MTRR_TYPE_WRBACK; + wrmsr(0x200, msr); + wrmsr(0x201, msr_201); + + /* enable cache */ + __asm__ volatile( + "movl %%cr0, %0\n\t" + "andl $0x9fffffff, %0\n\t" + "movl %0, %%cr0\n\t" + :"=r" (cnt) + ); + + print_debug(" done\r\n"); } diff --git a/src/northbridge/amd/amdk8/raminit.h b/src/northbridge/amd/amdk8/raminit.h index 7622cb7621..157dd13ee3 100644 --- a/src/northbridge/amd/amdk8/raminit.h +++ b/src/northbridge/amd/amdk8/raminit.h @@ -1,11 +1,12 @@ #ifndef RAMINIT_H #define RAMINIT_H +#define DIMM_SOCKETS 4 struct mem_controller { unsigned node_id; device_t f0, f1, f2, f3; - uint16_t channel0[4]; //By LYH - uint16_t channel1[4]; //By LYH + uint16_t channel0[DIMM_SOCKETS]; + uint16_t channel1[DIMM_SOCKETS]; }; diff --git a/src/northbridge/amd/amdk8/raminit_test.c b/src/northbridge/amd/amdk8/raminit_test.c new file mode 100644 index 0000000000..8e323ea859 --- /dev/null +++ b/src/northbridge/amd/amdk8/raminit_test.c @@ -0,0 +1,442 @@ +#include +#include +#include +#include +#include +#include +#include "amdk8.h" + +jmp_buf end_buf; + +static int is_cpu_pre_c0(void) +{ + return 0; +} + +#define PCI_ADDR(BUS, DEV, FN, WHERE) ( \ + (((BUS) & 0xFF) << 16) | \ + (((DEV) & 0x1f) << 11) | \ + (((FN) & 0x07) << 8) | \ + ((WHERE) & 0xFF)) + +#define PCI_DEV(BUS, DEV, FN) ( \ + (((BUS) & 0xFF) << 16) | \ + (((DEV) & 0x1f) << 11) | \ + (((FN) & 0x7) << 8)) + +#define PCI_ID(VENDOR_ID, DEVICE_ID) \ + ((((DEVICE_ID) & 0xFFFF) << 16) | ((VENDOR_ID) & 0xFFFF)) + +typedef unsigned device_t; + +unsigned char pci_register[256*5*3*256]; + +static uint8_t pci_read_config8(device_t dev, unsigned where) +{ + unsigned addr; + addr = dev | where; + return pci_register[addr]; +} + +static uint16_t pci_read_config16(device_t dev, unsigned where) +{ + unsigned addr; + addr = dev | where; + return pci_register[addr] | (pci_register[addr + 1] << 8); +} + +static uint32_t pci_read_config32(device_t dev, unsigned where) +{ + unsigned addr; + uint32_t value; + addr = dev | where; + value = pci_register[addr] | + (pci_register[addr + 1] << 8) | + (pci_register[addr + 2] << 16) | + (pci_register[addr + 3] << 24); + +#if 0 + print_debug("pcir32("); + print_debug_hex32(addr); + print_debug("):"); + print_debug_hex32(value); + print_debug("\n"); +#endif + return value; + +} + +static void pci_write_config8(device_t dev, unsigned where, uint8_t value) +{ + unsigned addr; + addr = dev | where; + pci_register[addr] = value; +} + +static void pci_write_config16(device_t dev, unsigned where, uint16_t value) +{ + unsigned addr; + addr = dev | where; + pci_register[addr] = value & 0xff; + pci_register[addr + 1] = (value >> 8) & 0xff; +} + +static void pci_write_config32(device_t dev, unsigned where, uint32_t value) +{ + unsigned addr; + addr = dev | where; + pci_register[addr] = value & 0xff; + pci_register[addr + 1] = (value >> 8) & 0xff; + pci_register[addr + 2] = (value >> 16) & 0xff; + pci_register[addr + 3] = (value >> 24) & 0xff; + +#if 0 + print_debug("pciw32("); + print_debug_hex32(addr); + print_debug(", "); + print_debug_hex32(value); + print_debug(")\n"); +#endif +} + +#define PCI_DEV_INVALID (0xffffffffU) +static device_t pci_locate_device(unsigned pci_id, device_t dev) +{ + for(; dev <= PCI_DEV(255, 31, 7); dev += PCI_DEV(0,0,1)) { + unsigned int id; + id = pci_read_config32(dev, 0); + if (id == pci_id) { + return dev; + } + } + return PCI_DEV_INVALID; +} + + + + +static void uart_tx_byte(unsigned char data) +{ + write(STDOUT_FILENO, &data, 1); +} +static void hlt(void) +{ + longjmp(end_buf, 2); +} +#include "../../../arch/i386/lib/console.c" + +unsigned long log2(unsigned long x) +{ + // assume 8 bits per byte. + unsigned long i = 1 << (sizeof(x)*8 - 1); + unsigned long pow = sizeof(x) * 8 - 1; + + if (! x) { + static const char errmsg[] = " called with invalid parameter of 0\n"; + write(STDERR_FILENO, __func__, sizeof(__func__) - 1); + write(STDERR_FILENO, errmsg, sizeof(errmsg) - 1); + hlt(); + } + for(; i > x; i >>= 1, pow--) + ; + + return pow; +} + +typedef struct msr_struct +{ + unsigned lo; + unsigned hi; +} msr_t; + +static inline msr_t rdmsr(unsigned index) +{ + msr_t result; + result.lo = 0; + result.hi = 0; + return result; +} + +static inline void wrmsr(unsigned index, msr_t msr) +{ +} + +#include "raminit.h" + +#define SIO_BASE 0x2e + +static void hard_reset(void) +{ + /* FIXME implement the hard reset case... */ + longjmp(end_buf, 3); +} + +static void memreset_setup(void) +{ + /* Nothing to do */ +} + +static void memreset(int controllers, const struct mem_controller *ctrl) +{ + /* Nothing to do */ +} + +static inline void activate_spd_rom(const struct mem_controller *ctrl) +{ + /* nothing to do */ +} + + +static uint8_t spd_mt4lsdt464a[256] = +{ + 0x80, 0x08, 0x04, 0x0C, 0x08, 0x01, 0x40, 0x00, 0x01, 0x70, + 0x54, 0x00, 0x80, 0x10, 0x00, 0x01, 0x8F, 0x04, 0x06, 0x01, + 0x01, 0x00, 0x0E, 0x75, 0x54, 0x00, 0x00, 0x0F, 0x0E, 0x0F, + + 0x25, 0x08, 0x15, 0x08, 0x15, 0x08, 0x00, 0x12, 0x01, 0x4E, + 0x9C, 0xE4, 0xB7, 0x46, 0x2C, 0xFF, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x00, +}; + +static uint8_t spd_micron_512MB_DDR333[256] = +{ + 0x80, 0x08, 0x07, 0x0d, 0x0b, 0x02, 0x48, 0x00, 0x04, 0x60, + 0x70, 0x02, 0x82, 0x04, 0x04, 0x01, 0x0e, 0x04, 0x0c, 0x01, + 0x02, 0x26, 0xc0, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, + 0x2a, 0x80, 0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x48, 0x30, 0x28, 0x50, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x6f, 0x2c, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x01, 0x33, 0x36, 0x56, 0x44, 0x44, 0x46, 0x31, + 0x32, 0x38, 0x37, 0x32, 0x47, 0x2d, 0x33, 0x33, 0x35, 0x43, + 0x33, 0x03, 0x00, 0x03, 0x23, 0x17, 0x07, 0x5a, 0xb2, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +static uint8_t spd_micron_256MB_DDR333[256] = +{ + 0x80, 0x08, 0x07, 0x0d, 0x0b, 0x01, 0x48, 0x00, 0x04, 0x60, + 0x70, 0x02, 0x82, 0x04, 0x04, 0x01, 0x0e, 0x04, 0x0c, 0x01, + 0x02, 0x26, 0xc0, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, + 0x2a, 0x80, 0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x48, 0x30, 0x23, 0x50, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x58, 0x2c, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x01, 0x31, 0x38, 0x56, 0x44, 0x44, 0x46, 0x36, + 0x34, 0x37, 0x32, 0x47, 0x2d, 0x33, 0x33, 0x35, 0x43, 0x31, + 0x20, 0x01, 0x00, 0x03, 0x19, 0x17, 0x05, 0xb2, 0xf4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +#define MAX_DIMMS 16 +static uint8_t spd_data[MAX_DIMMS*256]; + +static unsigned spd_count, spd_fail_count; +static int spd_read_byte(unsigned device, unsigned address) +{ + int result; + spd_count++; + if ((device < 0x50) || (device >= (0x50 +MAX_DIMMS))) { + result = -1; + } + else { + device -= 0x50; + + if (address > 256) { + result = -1; + } + else if (spd_data[(device << 8) | 2] != 7) { + result = -1; + } + else { + result = spd_data[(device << 8) | address]; + } + } +#if 0 + print_debug("spd_read_byte("); + print_debug_hex32(device); + print_debug(", "); + print_debug_hex32(address); + print_debug(") -> "); + print_debug_hex32(result); + print_debug("\n"); +#endif + if (spd_count >= spd_fail_count) { + result = -1; + } + return result; +} + +/* no specific code here. this should go away completely */ +static void coherent_ht_mainboard(unsigned cpus) +{ +} + +#include "raminit.c" +#include "../../../sdram/generic_sdram.c" + +#define FIRST_CPU 1 +#define SECOND_CPU 1 +#define TOTAL_CPUS (FIRST_CPU + SECOND_CPU) +static void raminit_main(void) +{ + /* + * GPIO28 of 8111 will control H0_MEMRESET_L + * GPIO29 of 8111 will control H1_MEMRESET_L + */ + static const struct mem_controller cpu[] = { +#if FIRST_CPU + { + .node_id = 0, + .f0 = PCI_DEV(0, 0x18, 0), + .f1 = PCI_DEV(0, 0x18, 1), + .f2 = PCI_DEV(0, 0x18, 2), + .f3 = PCI_DEV(0, 0x18, 3), + .channel0 = { 0x50+0, 0x50+2, 0x50+4, 0x50+6 }, + .channel1 = { 0x50+1, 0x50+3, 0x50+5, 0x50+7 }, + }, +#endif +#if SECOND_CPU + { + .node_id = 1, + .f0 = PCI_DEV(0, 0x19, 0), + .f1 = PCI_DEV(0, 0x19, 1), + .f2 = PCI_DEV(0, 0x19, 2), + .f3 = PCI_DEV(0, 0x19, 3), + .channel0 = { 0x50+8, 0x50+10, 0x50+12, 0x50+14 }, + .channel1 = { 0x50+9, 0x50+11, 0x50+13, 0x50+15 }, + }, +#endif + }; + console_init(); + memreset_setup(); + sdram_initialize(sizeof(cpu)/sizeof(cpu[0]), cpu); + +} + +static void reset_tests(void) +{ + /* Clear the results of any previous tests */ + memset(pci_register, 0, sizeof(pci_register)); + memset(spd_data, 0, sizeof(spd_data)); + spd_count = 0; + spd_fail_count = UINT_MAX; + + pci_write_config32(PCI_DEV(0, 0x18, 3), NORTHBRIDGE_CAP, + NBCAP_128Bit | + NBCAP_MP| NBCAP_BIG_MP | + /* NBCAP_ECC | NBCAP_CHIPKILL_ECC | */ + (NBCAP_MEMCLK_200MHZ << NBCAP_MEMCLK_SHIFT) | + NBCAP_MEMCTRL); + + pci_write_config32(PCI_DEV(0, 0x19, 3), NORTHBRIDGE_CAP, + NBCAP_128Bit | + NBCAP_MP| NBCAP_BIG_MP | + /* NBCAP_ECC | NBCAP_CHIPKILL_ECC | */ + (NBCAP_MEMCLK_200MHZ << NBCAP_MEMCLK_SHIFT) | + NBCAP_MEMCTRL); + +#if 0 + pci_read_config32(PCI_DEV(0, 0x18, 3), NORTHBRIDGE_CAP); +#endif +} + +static void test1(void) +{ + reset_tests(); + + memcpy(&spd_data[0*256], spd_micron_512MB_DDR333, 256); + memcpy(&spd_data[1*256], spd_micron_512MB_DDR333, 256); +#if 0 + memcpy(&spd_data[2*256], spd_micron_512MB_DDR333, 256); + memcpy(&spd_data[3*256], spd_micron_512MB_DDR333, 256); + + memcpy(&spd_data[8*256], spd_micron_512MB_DDR333, 256); + memcpy(&spd_data[9*256], spd_micron_512MB_DDR333, 256); + memcpy(&spd_data[10*256], spd_micron_512MB_DDR333, 256); + memcpy(&spd_data[11*256], spd_micron_512MB_DDR333, 256); +#endif + + raminit_main(); + +#if 0 + print_debug("spd_count: "); + print_debug_hex32(spd_count); + print_debug("\r\n"); +#endif + +} + + +static void do_test2(int i) +{ + jmp_buf tmp_buf; + memcpy(&tmp_buf, &end_buf, sizeof(end_buf)); + if (setjmp(end_buf) != 0) { + goto done; + } + reset_tests(); + spd_fail_count = i; + + print_debug("\r\nSPD will fail after: "); + print_debug_hex32(spd_fail_count); + print_debug(" accesses.\r\n"); + + memcpy(&spd_data[0*256], spd_micron_512MB_DDR333, 256); + memcpy(&spd_data[1*256], spd_micron_512MB_DDR333, 256); + + raminit_main(); + + done: + memcpy(&end_buf, &tmp_buf, sizeof(end_buf)); +} + +static void test2(void) +{ + int i; + for(i = 0; i < 0x48; i++) { + do_test2(i); + } + +} + +int main(int argc, char **argv) +{ + if (setjmp(end_buf) != 0) { + return -1; + } + test1(); + test2(); + return 0; +} diff --git a/src/northbridge/amd/amdk8/reset_test.c b/src/northbridge/amd/amdk8/reset_test.c index 9105324f33..7f4336ce5f 100644 --- a/src/northbridge/amd/amdk8/reset_test.c +++ b/src/northbridge/amd/amdk8/reset_test.c @@ -1,4 +1,5 @@ #include +#include #define NODE_ID 0x60 #define HT_INIT_CONTROL 0x6c @@ -6,11 +7,13 @@ #define HTIC_BIOSR_Detect (1<<5) #define HTIC_INIT_Detect (1<<6) - static int cpu_init_detected(void) { unsigned long htic; - htic = pci_read_config32(PCI_DEV(0, 0x18, 0), HT_INIT_CONTROL); + device_t dev; + + dev = PCI_DEV(0, 0x18 + lapicid(), 0); + htic = pci_read_config32(dev, HT_INIT_CONTROL); return !!(htic & HTIC_INIT_Detect); } @@ -31,11 +34,11 @@ static int cold_reset_detected(void) return !(htic & HTIC_ColdR_Detect); } -static void distinguish_cpu_resets(unsigned node_id) +static void distinguish_cpu_resets(void) { uint32_t htic; device_t device; - device = PCI_DEV(0, 0x18 + node_id, 0); + device = PCI_DEV(0, 0x18 + lapicid(), 0); htic = pci_read_config32(device, HT_INIT_CONTROL); htic |= HTIC_ColdR_Detect | HTIC_BIOSR_Detect | HTIC_INIT_Detect; pci_write_config32(device, HT_INIT_CONTROL, htic); diff --git a/src/pc80/Config.lb b/src/pc80/Config.lb index 0237fa96af..26d548b897 100644 --- a/src/pc80/Config.lb +++ b/src/pc80/Config.lb @@ -1,9 +1,8 @@ uses CONFIG_IDE_STREAM -uses CONFIG_KEYBOARD uses CONFIG_LEGACY_VGABIOS object mc146818rtc.o -#object isa-dma.o +object isa-dma.o #object i8259.o CONFIG_I8259 #object udelay_timer2.o CONFIG_UDELAY_TIMER2 #object beep.o CONFIG_BEEP @@ -16,9 +15,7 @@ if CONFIG_IDE_STREAM dir ide end -if CONFIG_KEYBOARD - object keyboard.o -end +object keyboard.o if CONFIG_LEGACY_VGABIOS object vgabios.o diff --git a/src/pc80/isa-dma.c b/src/pc80/isa-dma.c new file mode 100644 index 0000000000..45cfb88a97 --- /dev/null +++ b/src/pc80/isa-dma.c @@ -0,0 +1,43 @@ +#include + +/* DMA controller registers */ +#define DMA1_CMD_REG 0x08 /* command register (w) */ +#define DMA1_STAT_REG 0x08 /* status register (r) */ +#define DMA1_REQ_REG 0x09 /* request register (w) */ +#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */ +#define DMA1_MODE_REG 0x0B /* mode register (w) */ +#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */ +#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */ +#define DMA1_RESET_REG 0x0D /* Master Clear (w) */ +#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */ +#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */ + +#define DMA2_CMD_REG 0xD0 /* command register (w) */ +#define DMA2_STAT_REG 0xD0 /* status register (r) */ +#define DMA2_REQ_REG 0xD2 /* request register (w) */ +#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */ +#define DMA2_MODE_REG 0xD6 /* mode register (w) */ +#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */ +#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */ +#define DMA2_RESET_REG 0xDA /* Master Clear (w) */ +#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */ +#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */ + +#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */ +#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */ +#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */ + +#define DMA_AUTOINIT 0x10 + + +void isa_dma_init(void) +{ + /* slave at 0x00 - 0x0f */ + /* master at 0xc0 - 0xdf */ + /* 0x80 - 0x8f DMA page registers */ + /* DMA: 0x00, 0x02, 0x4, 0x06 base address for DMA channel */ + outb(0, DMA1_RESET_REG); + outb(0, DMA2_RESET_REG); + outb(DMA_MODE_CASCADE, DMA2_MODE_REG); + outb(0, DMA2_MASK_REG); +} diff --git a/src/pc80/keyboard.c b/src/pc80/keyboard.c index a7ecf8cbd3..d293f714de 100644 --- a/src/pc80/keyboard.c +++ b/src/pc80/keyboard.c @@ -1,8 +1,11 @@ +#include +#include +#include #include /* much better keyboard init courtesy ollie@sis.com.tw TODO: Typematic Setting, the keyboard is too slow for me */ -void pc_keyboard_init() +static void pc_keyboard_init(struct pc_keyboard *keyboard) { volatile unsigned char regval; @@ -49,3 +52,9 @@ void pc_keyboard_init() return; } +void init_pc_keyboard(unsigned port0, unsigned port1, struct pc_keyboard *kbd) +{ + if ((port0 == 0x60) && (port1 == 0x64)) { + pc_keyboard_init(kbd); + } +} diff --git a/src/pc80/mc146818rtc_early.c b/src/pc80/mc146818rtc_early.c index 35f3f5910f..0c7d822718 100644 --- a/src/pc80/mc146818rtc_early.c +++ b/src/pc80/mc146818rtc_early.c @@ -97,3 +97,14 @@ static int do_normal_boot(void) return (byte & (1<<1)); } + +static unsigned read_option(unsigned start, unsigned size, unsigned def) +{ +#if USE_OPTION_TABLE == 1 + unsigned byte; + byte = cmos_read(start/8); + return (byte >> (start & 7U)) & ((1U << size) - 1U); +#else + return def; +#endif +} diff --git a/src/pc80/serial.c b/src/pc80/serial.c index c2788d6ec7..89ac425c56 100644 --- a/src/pc80/serial.c +++ b/src/pc80/serial.c @@ -77,8 +77,7 @@ static void uart_init(void) #if USE_OPTION_TABLE == 1 static const unsigned char divisor[] = { 1,2,3,6,12,24,48,96 }; unsigned ttys0_div, ttys0_index; - outb(RTC_BOOT_BYTE + 1, 0x70); - ttys0_index = inb(0x71); + ttys0_index = read_option(CMOS_VSTART_baud_rate, CMOS_VLEN_baud_rate, 0); ttys0_index &= 7; ttys0_div = divisor[ttys0_index]; outb(ttys0_div & 0xff, TTYS0_BASE + UART_DLL); diff --git a/src/pc80/serial.inc b/src/pc80/serial.inc index b0f12699e1..7b80697c85 100644 --- a/src/pc80/serial.inc +++ b/src/pc80/serial.inc @@ -67,8 +67,7 @@ div: mov %ah, %al ; \ outb %al, %dx - -serial0: +serial_init: /* Set 115.2Kbps,8n1 */ /* Set 8bit, 1 stop bit, no parity, DLAB */ mov $TTYS0_LCR, %dx @@ -102,5 +101,7 @@ serial0: mov $TTYS0_LCR, %dx mov $(TTYS0_LCS & 0x7f), %al out %al, %dx + RETSP - +serial0: + CALLSP(serial_init) diff --git a/src/southbridge/amd/amd8111/Config.lb b/src/southbridge/amd/amd8111/Config.lb index 904b0995b5..5bbbaba65e 100644 --- a/src/southbridge/amd/amd8111/Config.lb +++ b/src/southbridge/amd/amd8111/Config.lb @@ -5,5 +5,6 @@ driver amd8111_lpc.o driver amd8111_ide.o driver amd8111_acpi.o driver amd8111_usb2.o -#driver amd8111_ac97.o -#driver amd8111_nic.o +driver amd8111_ac97.o +driver amd8111_nic.o +driver amd8111_pci.o diff --git a/src/southbridge/amd/amd8111/amd8111.c b/src/southbridge/amd/amd8111/amd8111.c index 8dde5f13c6..d3fdf3b7ba 100644 --- a/src/southbridge/amd/amd8111/amd8111.c +++ b/src/southbridge/amd/amd8111/amd8111.c @@ -26,27 +26,24 @@ void amd8111_enable(device_t dev) lpc_dev = dev_find_slot(dev->bus->secondary, devfn); index = dev->path.u.pci.devfn & 7; } - if ((!lpc_dev) || (index >= 16) || - (lpc_dev->vendor != PCI_VENDOR_ID_AMD) || - (lpc_dev->device != PCI_DEVICE_ID_AMD_8111_ISA)) { + if ((!lpc_dev) || (index >= 16)) { return; } - + if ((lpc_dev->vendor != PCI_VENDOR_ID_AMD) || + (lpc_dev->device != PCI_DEVICE_ID_AMD_8111_ISA)) { + uint32_t id; + id = pci_read_config32(lpc_dev, PCI_VENDOR_ID); + if (id != (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8111_ISA << 16))) { + return; + } + } reg = reg_old = pci_read_config16(lpc_dev, 0x48); reg &= ~(1 << index); if (dev->enable) { reg |= (1 << index); } if (reg != reg_old) { -#if 1 - printk_warning("amd8111_enable dev: %s", dev_path(dev)); - printk_warning(" lpc_dev: %s index: %d reg: %04x -> %04x ", - dev_path(lpc_dev), index, reg_old, reg); -#endif pci_write_config16(lpc_dev, 0x48, reg); -#if 1 - printk_warning("done\n"); -#endif } } diff --git a/src/southbridge/amd/amd8111/amd8111_acpi.c b/src/southbridge/amd/amd8111/amd8111_acpi.c index 3a5a594f57..e3b7038e46 100644 --- a/src/southbridge/amd/amd8111/amd8111_acpi.c +++ b/src/southbridge/amd/amd8111/amd8111_acpi.c @@ -4,11 +4,15 @@ #include #include #include +#include +#include #include "amd8111.h" #define PREVIOUS_POWER_STATE 0x43 #define MAINBOARD_POWER_OFF 0 #define MAINBOARD_POWER_ON 1 +#define SLOW_CPU_OFF 0 +#define SLOW_CPU__ON 1 #ifndef MAINBOARD_POWER_ON_AFTER_POWER_FAIL #define MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON @@ -19,6 +23,8 @@ static void acpi_init(struct device *dev) { uint8_t byte; uint16_t word; + uint16_t pm10_bar; + uint32_t dword; int on; #if 0 @@ -57,10 +63,43 @@ static void acpi_init(struct device *dev) pci_write_config8(dev, PREVIOUS_POWER_STATE, byte); printk_info("set power %s after power fail\n", on?"on":"off"); + /* Throttle the CPU speed down for testing */ + on = SLOW_CPU_OFF; + get_option(&on, "slow_cpu"); + if(on) { + pm10_bar = (pci_read_config16(dev, 0x58)&0xff00); + outl(((on<<1)+0x10) ,(pm10_bar + 0x10)); + dword = inl(pm10_bar + 0x10); + on = 8-on; + printk_debug("Throttling CPU %2d.%1.1d percent.\n", + (on*12)+(on>>1),(on&1)*5); + } +} + +static void acpi_read_resources(device_t dev) +{ + /* Handle the generic bars */ + pci_dev_read_resources(dev); + + if ((dev->resources + 1) < MAX_RESOURCES) { + struct resource *resource = &dev->resource[dev->resources]; + dev->resources++; + resource->base = 0; + resource->size = 256; + resource->align = log2(256); + resource->gran = log2(256); + resource->limit = 65536; + resource->flags = IORESOURCE_IO; + resource->index = 0x58; + } + else { + printk_err("%s Unexpected resource shortage\n", + dev_path(dev)); + } } static struct device_operations acpi_ops = { - .read_resources = pci_dev_read_resources, + .read_resources = acpi_read_resources, .set_resources = pci_dev_set_resources, .enable_resources = pci_dev_enable_resources, .init = acpi_init, diff --git a/src/southbridge/amd/amd8111/amd8111_early_smbus.c b/src/southbridge/amd/amd8111/amd8111_early_smbus.c index 4bc515c75d..5157609639 100644 --- a/src/southbridge/amd/amd8111/amd8111_early_smbus.c +++ b/src/southbridge/amd/amd8111/amd8111_early_smbus.c @@ -17,7 +17,7 @@ static void enable_smbus(void) die("SMBUS controller not found\r\n"); } uint8_t enable; - print_debug("SMBus controller enabled\r\n"); + print_spew("SMBus controller enabled\r\n"); pci_write_config32(dev, 0x58, SMBUS_IO_BASE | 1); enable = pci_read_config8(dev, 0x41); pci_write_config8(dev, 0x41, enable | (1 << 7)); @@ -134,6 +134,5 @@ static void smbus_write_byte(unsigned device, unsigned address, unsigned char va /* poll for transaction completion */ smbus_wait_until_done(); - return; } diff --git a/src/southbridge/amd/amd8111/amd8111_ide.c b/src/southbridge/amd/amd8111/amd8111_ide.c index 4502bb3c45..6f8e018fe6 100644 --- a/src/southbridge/amd/amd8111/amd8111_ide.c +++ b/src/southbridge/amd/amd8111/amd8111_ide.c @@ -12,9 +12,6 @@ static void ide_init(struct device *dev) uint16_t word; int enable_a=1, enable_b=1; - - printk_debug("ide_init\n"); - word = pci_read_config16(dev, 0x40); /* Ensure prefetch is disabled */ word &= ~((1 << 15) | (1 << 13)); diff --git a/src/southbridge/amd/amd8111/amd8111_lpc.c b/src/southbridge/amd/amd8111/amd8111_lpc.c index 535cbece66..b6e25d2c5e 100644 --- a/src/southbridge/amd/amd8111/amd8111_lpc.c +++ b/src/southbridge/amd/amd8111/amd8111_lpc.c @@ -7,8 +7,10 @@ #include #include #include +#include #include "amd8111.h" +#define NMI_OFF 0 struct ioapicreg { unsigned int reg; @@ -100,8 +102,7 @@ static void lpc_init(struct device *dev) { uint8_t byte; int pwr_on=-1; - - printk_debug("lpc_init\n"); + int nmi_option; /* IO APIC initialization */ byte = pci_read_config8(dev, 0x4B); @@ -127,6 +128,31 @@ static void lpc_init(struct device *dev) byte |= (1 << 5); pci_write_config8(dev, 0x41, byte); + /* Enable Error reporting */ + /* Set up sync flood detected */ + byte = pci_read_config8(dev, 0x47); + byte |= (1 << 1); + pci_write_config8(dev, 0x47, byte); + + /* Set up NMI on errors */ + byte = pci_read_config8(dev, 0x40); + byte |= (1 << 1); /* clear PW2LPC error */ + byte |= (1 << 6); /* clear LPCERR */ + pci_write_config8(dev, 0x40, byte); + nmi_option = NMI_OFF; + get_option(&nmi_option, "nmi"); + if(nmi_option) { + byte |= (1 << 7); /* set NMI */ + pci_write_config8(dev, 0x40, byte); + } + + /* Initialize the real time clock */ + rtc_init(0); + + /* Initialize isa dma */ + isa_dma_init(); + + /* Initialize the High Precision Event Timers */ enable_hpet(dev); } @@ -146,7 +172,7 @@ static void amd8111_lpc_read_resources(device_t dev) dev->resource[reg].align = 0; dev->resource[reg].gran = 0; dev->resource[reg].limit = 0; - dev->resource[reg].flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_SET; + dev->resource[reg].flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; dev->resource[reg].index = 0; reg++; @@ -155,7 +181,7 @@ static void amd8111_lpc_read_resources(device_t dev) dev->resource[reg].align = 0; dev->resource[reg].gran = 0; dev->resource[reg].limit = 0; - dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_SET; + dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; dev->resource[reg].index = 0; reg++; @@ -176,4 +202,3 @@ static struct pci_driver lpc_driver __pci_driver = { .vendor = PCI_VENDOR_ID_AMD, .device = PCI_DEVICE_ID_AMD_8111_ISA, }; - diff --git a/src/southbridge/amd/amd8111/amd8111_pci.c b/src/southbridge/amd/amd8111/amd8111_pci.c new file mode 100644 index 0000000000..29d3fb88d8 --- /dev/null +++ b/src/southbridge/amd/amd8111/amd8111_pci.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include "amd8111.h" + +static void pci_init(struct device *dev) +{ + + /* Enable pci error detecting */ + uint32_t dword; + + /* System error enable */ + dword = pci_read_config32(dev, 0x04); + dword |= (1<<8); /* System error enable */ + dword |= (7<<28); /* Clear possible errors */ + pci_write_config32(dev, 0x04, dword); + + /* System,Parity,timer,and abort error enable */ + dword = pci_read_config32(dev, 0x3c); + dword |= (1<<16); /* Parity */ + dword |= (1<<17); /* System */ + dword |= (1<<21); /* Master abort */ +// dword &= ~(1<<21); /* Master abort */ + dword |= (1<<27); /* Discard timer */ + dword |= (1<<26); /* DTSTAT error clear */ + pci_write_config32(dev, 0x3c, dword); + + /* CRC flood enable */ + dword = pci_read_config32(dev, 0xc4); + dword |= (1<<1); /* CRC Flood enable */ + dword |= (1<<8); /* Clear any CRC errors */ + dword |= (1<<4); /* Clear any LKFAIL errors */ + pci_write_config32(dev, 0xc4, dword); + + /* Clear possible errors */ + dword = pci_read_config32(dev, 0x1c); + dword |= (1<<27); /* STA */ + dword |= (1<<28); /* RTA */ + dword |= (1<<29); /* RMA */ + dword |= (1<<30); /* RSE */ + dword |= (1<<31); /* DPE */ + dword |= (1<<24); /* MDPE */ + pci_write_config32(dev, 0x1c, dword); +} + +static struct device_operations pci_ops = { + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .init = pci_init, + .scan_bus = pci_scan_bridge, +}; + +static struct pci_driver pci_driver __pci_driver = { + .ops = &pci_ops, + .vendor = PCI_VENDOR_ID_AMD, + .device = PCI_DEVICE_ID_AMD_8111_PCI, +}; + diff --git a/src/southbridge/amd/amd8111/amd8111_usb.c b/src/southbridge/amd/amd8111/amd8111_usb.c index 46cfabbcda..407729a381 100644 --- a/src/southbridge/amd/amd8111/amd8111_usb.c +++ b/src/southbridge/amd/amd8111/amd8111_usb.c @@ -9,6 +9,7 @@ static void usb_init(struct device *dev) { uint32_t cmd; +#if 0 printk_debug("USB: Setting up controller.. "); cmd = pci_read_config32(dev, PCI_COMMAND); pci_write_config32(dev, PCI_COMMAND, @@ -17,6 +18,7 @@ static void usb_init(struct device *dev) printk_debug("done.\n"); +#endif } diff --git a/src/southbridge/amd/amd8111/amd8111_usb2.c b/src/southbridge/amd/amd8111/amd8111_usb2.c index 15ed69b0f1..e6dd1e9da2 100644 --- a/src/southbridge/amd/amd8111/amd8111_usb2.c +++ b/src/southbridge/amd/amd8111/amd8111_usb2.c @@ -13,6 +13,7 @@ static void usb2_init(struct device *dev) { uint32_t cmd; +#if 0 printk_debug("USB: Setting up controller.. "); cmd = pci_read_config32(dev, PCI_COMMAND); pci_write_config32(dev, PCI_COMMAND, @@ -21,7 +22,7 @@ static void usb2_init(struct device *dev) printk_debug("done.\n"); - +#endif } static struct device_operations usb2_ops = { diff --git a/src/southbridge/amd/amd8131/amd8131_bridge.c b/src/southbridge/amd/amd8131/amd8131_bridge.c index e730997bbc..b96f46db45 100644 --- a/src/southbridge/amd/amd8131/amd8131_bridge.c +++ b/src/southbridge/amd/amd8131/amd8131_bridge.c @@ -6,11 +6,16 @@ #include #include #include +#include + +#define NMI_OFF 0 static void pcix_init(device_t dev) { + uint32_t dword; uint16_t word; uint8_t byte; + int nmi_option; /* Enable memory write and invalidate ??? */ byte = pci_read_config8(dev, 0x04); @@ -40,6 +45,37 @@ static void pcix_init(device_t dev) pci_write_config16(dev, 0xaa, word); word = pci_read_config16(dev, 0xac); pci_write_config16(dev, 0xae, word); + + /* Set up error reporting, enable all */ + /* system error enable */ + dword = pci_read_config32(dev, 0x04); + dword |= (1<<8); + pci_write_config32(dev, 0x04, dword); + + /* system and error parity enable */ + dword = pci_read_config32(dev, 0x3c); + dword |= (3<<16); + pci_write_config32(dev, 0x3c, dword); + + /* NMI enable */ + nmi_option = NMI_OFF; + get_option(&nmi_option, "nmi"); + if(nmi_option) { + dword = pci_read_config32(dev, 0x44); + dword |= (1<<0); + pci_write_config32(dev, 0x44, dword); + } + + /* Set up CRC flood enable */ + dword = pci_read_config32(dev, 0xc0); + if(dword) { /* do device A only */ + dword = pci_read_config32(dev, 0xc4); + dword |= (1<<1); + pci_write_config32(dev, 0xc4, dword); + dword = pci_read_config32(dev, 0xc8); + dword |= (1<<1); + pci_write_config32(dev, 0xc8, dword); + } return; } @@ -69,13 +105,6 @@ static void ioapic_enable(device_t dev) value &= ~((1 << 1) | (1 << 0)); } pci_write_config32(dev, 0x44, value); - -//BY LYH - value = pci_read_config32(dev, 0x4); - value |= 6; - pci_write_config32(dev, 0x4, value); -//BY LYH END - } static struct device_operations ioapic_ops = { diff --git a/src/superio/NSC/pc87360/chip.h b/src/superio/NSC/pc87360/chip.h index 55787566fc..9e0ef6f976 100644 --- a/src/superio/NSC/pc87360/chip.h +++ b/src/superio/NSC/pc87360/chip.h @@ -1,9 +1,3 @@ -#ifndef PNP_INDEX_REG -#define PNP_INDEX_REG 0x15C -#endif -#ifndef PNP_DATA_REG -#define PNP_DATA_REG 0x15D -#endif #ifndef SIO_COM1 #define SIO_COM1_BASE 0x3F8 #endif @@ -13,8 +7,10 @@ extern struct chip_control superio_NSC_pc87360_control; +#include +#include + struct superio_NSC_pc87360_config { - struct com_ports com1; - struct lpt_ports lpt; - int port; + struct uart8250 com1, com2; + struct pc_keyboard keyboard; }; diff --git a/src/superio/NSC/pc87360/pc87360.h b/src/superio/NSC/pc87360/pc87360.h new file mode 100644 index 0000000000..201da8eb6e --- /dev/null +++ b/src/superio/NSC/pc87360/pc87360.h @@ -0,0 +1,11 @@ +#define PC87360_FDC 0x00 /* Floppy */ +#define PC87360_PP 0x01 /* Parallel port */ +#define PC87360_SP2 0x02 /* Com2 */ +#define PC87360_SP1 0x03 /* Com1 */ +#define PC87360_SWC 0x04 +#define PC87360_KBCM 0x05 /* Mouse */ +#define PC87360_KBCK 0x06 /* Keyboard */ +#define PC87360_GPIO 0x07 +#define PC87360_ACB 0x08 +#define PC87360_FSCM 0x09 +#define PC87360_WDT 0x0A diff --git a/src/superio/NSC/pc87360/pc87360_early_serial.c b/src/superio/NSC/pc87360/pc87360_early_serial.c new file mode 100644 index 0000000000..696d3a0570 --- /dev/null +++ b/src/superio/NSC/pc87360/pc87360_early_serial.c @@ -0,0 +1,11 @@ +#include +#include "pc87360.h" + + +static void pc87360_enable_serial(device_t dev, unsigned iobase) +{ + pnp_set_logical_device(dev); + pnp_set_enable(dev, 0); + pnp_set_iobase(dev, PNP_IDX_IO0, iobase); + pnp_set_enable(dev, 1); +} diff --git a/src/superio/NSC/pc87360/superio.c b/src/superio/NSC/pc87360/superio.c index 8765eb35cc..50d71ea927 100644 --- a/src/superio/NSC/pc87360/superio.c +++ b/src/superio/NSC/pc87360/superio.c @@ -1,324 +1,77 @@ /* Copyright 2000 AG Electronics Ltd. */ +/* Copyright 2003-2004 Linux Networx */ /* This code is distributed without warranty under the GPL v2 (see COPYING) */ #include #include +#include #include #include #include #include +#include +#include #include "chip.h" +#include "pc87360.h" -void pnp_output(char address, char data) +static void init(device_t dev) { - outb(address, PNP_INDEX_REG); - outb(data, PNP_DATA_REG); -} - -static void sio_enable(struct chip *chip, enum chip_pass pass) -{ - - struct superio_NSC_pc87360_config *conf = (struct superio_NSC_pc87360_config *)chip->chip_info; - - switch (pass) { - case CONF_PASS_PRE_CONSOLE: - /* Enable Super IO Chip */ - pnp_output(0x07, 6); /* LD 6 = UART1 */ - pnp_output(0x30, 0); /* Dectivate */ - pnp_output(0x60, conf->port >> 8); /* IO Base */ - pnp_output(0x61, conf->port & 0xFF); /* IO Base */ - pnp_output(0x30, 1); /* Activate */ - break; - default: - /* nothing yet */ - break; - } -} - -static void pnp_write_config(device_t dev, unsigned char value, unsigned char reg) -{ - outb(reg, dev->path.u.pnp.port); - outb(value, dev->path.u.pnp.port + 1); -} - -static unsigned char pnp_read_config(device_t dev, unsigned char reg) -{ - outb(reg, dev->path.u.pnp.port); - return inb(dev->path.u.pnp.port + 1); -} - -static void pnp_set_logical_device(device_t dev) -{ - pnp_write_config(dev, dev->path.u.pnp.device, 0x07); -} - -static void pnp_set_enable(device_t dev, int enable) -{ - pnp_write_config(dev, enable?0x1:0x0, 0x30); -} - -static int pnp_read_enable(device_t dev) -{ - return !!pnp_read_config(dev, 0x30); -} - -#define FLOPPY_DEVICE 0 -#define PARALLEL_DEVICE 1 -#define COM2_DEVICE 2 -#define COM1_DEVICE 3 -#define SWC_DEVICE 4 -#define MOUSE_DEVICE 5 -#define KBC_DEVICE 6 -#define GPIO_DEVICE 7 -#define ACB_DEVICE 8 -#define FSCM_DEVICE 9 -#define WDT_DEVICE 10 - -struct io_info { - unsigned mask, set; -}; -struct pnp_info { - unsigned flags; -#define PNP_IO0 0x01 -#define PNP_IO1 0x02 -#define PNP_IRQ0 0x04 -#define PNP_IRQ1 0x08 -#define PNP_DRQ0 0x10 -#define PNP_DRQ1 0x20 - struct io_info io0, io1; -}; - -static struct pnp_info pnp_dev_info[] = { - [ 0] = { PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x07fa, 0}, }, - [ 1] = { PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x04f8, 0}, }, - [ 2] = { PNP_IO0 | PNP_IRQ0 | PNP_DRQ0 | PNP_DRQ1, { 0x7f8, 0 }, }, - [ 3] = { PNP_IO0 | PNP_IRQ0, { 0x7f8, 0 }, }, - [ 4] = { PNP_IO0 | PNP_IRQ0, { 0xfff0, 0 }, }, - [ 5] = { PNP_IRQ0 }, - [ 6] = { PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x7f8, 0 }, { 0x7f8, 0x4}, }, - [ 7] = { PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } }, - [ 8] = { PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } }, - [ 9] = { PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } }, - [10] = { PNP_IO0 | PNP_IRQ0, { 0xfffc, 0 } }, -}; - -static struct resource *get_resource(device_t dev, unsigned index) -{ - struct resource *resource; - int i; - resource = 0; - for(i = 0; i < dev->resources; i++) { - resource = &dev->resource[i]; - if (resource->index == index) { - break; - } - } - if (!resource || (resource->index != index)) { - resource = &dev->resource[dev->resources]; - memset(resource, 0, sizeof(*resource)); - dev->resources++; - } - /* Initialize the resource values */ - if (!(resource->flags & IORESOURCE_FIXED)) { - resource->flags = 0; - resource->base = 0; - } - resource->size = 0; - resource->limit = 0; - resource->flags = 0; - resource->index = index; - resource->align = 0; - resource->gran = 0; - - return resource; -} - -static void pnp_read_ioresource(device_t dev, unsigned index, struct io_info *info) -{ - struct resource *resource; - uint32_t size; - resource = get_resource(dev, index); - - /* Initilize the resource */ - resource->limit = 0xffff; - resource->flags |= IORESOURCE_IO; - - /* Set the resource size and alignment */ - size = (0xffff & info->mask); - resource->size = (~(size | 0xfffff800) + 1); - resource->align = log2(resource->size); - resource->gran = resource->align; -} - - -static void pnp_read_resources(device_t dev) -{ - struct pnp_info *info; - struct resource *resource; - pnp_set_logical_device(dev); - - info = &pnp_dev_info[dev->path.u.pnp.device]; - - if (info->flags & PNP_IO0) { - pnp_read_ioresource(dev, 0x60, &info->io0); - } - if (info->flags & PNP_IO1) { - pnp_read_ioresource(dev, 0x62, &info->io1); - } - if (info->flags & PNP_IRQ0) { - resource = get_resource(dev, 0x70); - resource->size = 1; - resource->flags |= IORESOURCE_IRQ; - } - if (info->flags & PNP_IRQ1) { - resource = get_resource(dev, 0x72); - resource->size = 1; - resource->flags |= IORESOURCE_IRQ; - } - if (info->flags & PNP_DRQ0) { - resource = get_resource(dev, 0x74); - resource->size = 1; - resource->flags |= IORESOURCE_DRQ; - } - if (info->flags & PNP_DRQ1) { - resource = get_resource(dev, 0x75); - resource->size = 1; - resource->flags |= IORESOURCE_DRQ; - } -} - -static void pnp_set_iobase(device_t dev, unsigned iobase, unsigned index) -{ - /* Index == 0x60 or 0x62 */ - pnp_write_config(dev, (iobase >> 8) & 0xff, index); - pnp_write_config(dev, iobase & 0xff, index + 1); -} - -static void pnp_set_irq(device_t dev, unsigned irq, unsigned index) -{ - /* Index == 0x70 or 0x72 */ - pnp_write_config(dev, irq, index); -} - -static void pnp_set_drq(device_t dev, unsigned drq, unsigned index) -{ - /* Index == 0x74 */ - pnp_write_config(dev, drq & 0xff, index); -} - - -static void pnp_set_resource(device_t dev, struct resource *resource) -{ - if (!(resource->flags & IORESOURCE_SET)) { -#if 1 - printk_err("ERROR: %s %02x not allocated\n", - dev_path(dev), resource->index); -#endif - return; - } - if (resource->flags & IORESOURCE_IO) { - pnp_set_iobase(dev, resource->base, resource->index); - } - else if (resource->flags & IORESOURCE_DRQ) { - pnp_set_drq(dev, resource->base, resource->index); - } - else if (resource->flags & IORESOURCE_IRQ) { - pnp_set_irq(dev, resource->base, resource->index); - } - else { - printk_err("ERROR: %s %02x unknown resource type\n", - dev_path(dev), resource->index); + struct superio_NSC_pc87360_config *conf; + struct resource *res0, *res1; + /* Wishlist handle well known programming interfaces more + * generically. + */ + if (!dev->enable) { return; } - printk_debug( - "%s %02x <- [0x%08lx - 0x%08lx %s\n", - dev_path(dev), - resource->index, - resource->base, resource->base + resource->size - 1, - (resource->flags & IORESOURCE_IO)? "io": - (resource->flags & IORESOURCE_DRQ)? "drq": - (resource->flags & IORESOURCE_IRQ)? "irq": - (resource->flags & IORESOURCE_MEM)? "mem": - "???"); -} - -static void pnp_set_resources(device_t dev) -{ - int i; - pnp_set_logical_device(dev); - for(i = 0; i < dev->resources; i++) { - pnp_set_resource(dev, &dev->resource[i]); - } - -} -static void pnp_enable_resources(device_t dev) -{ - pnp_set_logical_device(dev); - pnp_set_enable(dev, 1); - -} -static void pnp_enable(device_t dev) -{ - pnp_set_logical_device(dev); - if (!dev->enable) { - pnp_set_enable(dev, 0); + conf = dev->chip->chip_info; + switch(dev->path.u.pnp.device) { + case PC87360_SP1: + res0 = get_resource(dev, PNP_IDX_IO0); + init_uart8250(res0->base, &conf->com1); + break; + case PC87360_SP2: + res0 = get_resource(dev, PNP_IDX_IO0); + init_uart8250(res0->base, &conf->com2); + break; + case PC87360_KBCK: + res0 = get_resource(dev, PNP_IDX_IO0); + res1 = get_resource(dev, PNP_IDX_IO1); + init_pc_keyboard(res0->base, res1->base, &conf->keyboard); + break; } } -static struct device_operations pnp_ops = { +static struct device_operations ops = { .read_resources = pnp_read_resources, .set_resources = pnp_set_resources, .enable_resources = pnp_enable_resources, .enable = pnp_enable, + .init = init, }; -#define MAX_FUNCTION 10 -static void enumerate(struct chip *chip) -{ - struct superio_NSC_pc87360_config *conf = (struct superio_NSC_pc87360_config *)chip->chip_info; - struct resource *resource; - struct device_path path; - device_t dev; - int i; - - chip_enumerate(chip); - path.type = DEVICE_PATH_PNP; - path.u.pnp.port = chip->dev->path.u.pnp.port; - - /* Set the ops on the newly allocated devices */ - for(i = 0; i <= WDT_DEVICE; i++) { - path.u.pnp.device = i; - dev = alloc_find_dev(chip->bus, &path); - dev->ops = &pnp_ops; - } +static struct pnp_info pnp_dev_info[] = { + { &ops, PC87360_FDC, PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x07fa, 0}, }, + { &ops, PC87360_PP, PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x04f8, 0}, }, + { &ops, PC87360_SP2, PNP_IO0 | PNP_IRQ0 | PNP_DRQ0 | PNP_DRQ1, { 0x7f8, 0 }, }, + { &ops, PC87360_SP1, PNP_IO0 | PNP_IRQ0, { 0x7f8, 0 }, }, + { &ops, PC87360_SWC, PNP_IO0 | PNP_IRQ0, { 0xfff0, 0 }, }, + { &ops, PC87360_KBCM, PNP_IRQ0 }, + { &ops, PC87360_KBCK, PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x7f8, 0 }, { 0x7f8, 0x4}, }, + { &ops, PC87360_GPIO, PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } }, + { &ops, PC87360_ACB, PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } }, + { &ops, PC87360_FSCM, PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } }, + { &ops, PC87360_WDT, PNP_IO0 | PNP_IRQ0, { 0xfffc, 0 } }, +}; - /* Processes the hard codes for com1 */ - path.u.pnp.device = COM1_DEVICE; - dev = alloc_find_dev(chip->bus, &path); - resource = get_resource(dev, 0x60); - if (conf->com1.base) { - resource->base = conf->com1.base; - resource->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_SET; - } - resource = get_resource(dev, 0x70); - if (conf->com1.irq) { - resource->base = conf->com1.irq; - resource->flags = IORESOURCE_IRQ | IORESOURCE_FIXED | IORESOURCE_SET; - } - /* Process the hard codes for the keyboard controller */ - path.u.pnp.device = KBC_DEVICE; - dev = alloc_find_dev(dev, &path); - resource = get_resource(dev, 0x60); - resource->base = 0x60; - resource->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_SET; - resource = get_resource(dev, 0x62); - resource->base = 0x64; - resource->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_SET; +static void enumerate(struct chip *chip) +{ + pnp_enumerate(chip, sizeof(pnp_dev_info)/sizeof(pnp_dev_info[0]), + &pnp_ops, pnp_dev_info); } struct chip_control superio_NSC_pc87360_control = { - .enable = sio_enable, .enumerate = enumerate, .name = "NSC 87360" }; -- cgit v1.2.3