diff options
Diffstat (limited to 'src')
93 files changed, 3806 insertions, 1837 deletions
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 <stdint.h> 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 <cpu/p6/msr.h> +#include <cpu/p6/apic.h> +#include <arch/hlt.h> + +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 <cpu/p6/msr.h> #include <cpu/p6/apic.h> #include <cpu/p5/cpuid.h> +#include <arch/smp/lapic.h> #if 0 #include <cpu/l2_cache.h> #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 <delay.h> #include <string.h> #include <console/console.h> +#include <arch/smp/lapic.h> +#include <arch/hlt.h> -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 @@ -331,6 +337,29 @@ define 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 <cpu/p6/msr.h> #include <cpu/k8/mtrr.h> #include <device/device.h> -#include "../../northbridge/amd/amdk8/cpu_rev.c" #include <device/chip.h> +#include <device/device.h> +#include <device/pci.h> +#include <smp/start_stop.h> +#include <string.h> +#include <cpu/p6/msr.h> +#include <cpu/p6/pgtbl.h> +#include <pc80/mc146818rtc.h> +#include <arch/smp/lapic.h> +#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 <cpu/k8/mtrr.h> + + /* 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 <console/console.h> +#include <smp/start_stop.h> +#include <cpu/p6/pgtbl.h> + +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 <string.h> /* 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 <device/device.h> #include <device/path.h> #include <device/pci.h> +#include <device/pci_ids.h> #include <device/hypertransport.h> #include <device/chip.h> #include <part/hard_reset.h> @@ -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 <console/console.h> +#include <stdlib.h> +#include <stdint.h> +#include <bitops.h> +#include <string.h> +#include <arch/io.h> +#include <device/device.h> +#include <device/pnp.h> + + +/* 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 <device/path.h> +#include <device/device.h> /* 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 <device/hypertransport_def.h> + 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 <stdint.h> +#include <device/device.h> +#include <device/pnp_def.h> +#include <device/chip.h> + +/* 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 <string.h> -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 <string.h> +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 <stdint.h> #include <device/pci_def.h> -#include <cpu/p6/apic.h> #include <arch/io.h> #include <device/pnp.h> #include <arch/romcc_io.h> +#include <arch/smp/lapic.h> +#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 <device/pci_def.h> #include <device/pci_ids.h> #include <arch/io.h> -#include "arch/romcc_io.h" +#include <arch/romcc_io.h> +#include <arch/smp/lapic.h> #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 @@ -59,6 +65,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 <stdint.h> #include <device/pci_def.h> -#include <cpu/p6/apic.h> #include <arch/io.h> -#include <device/pnp.h> +#include <device/pnp_def.h> #include <arch/romcc_io.h> +#include <arch/smp/lapic.h> +#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 <device/pci_def.h> #include <device/pci_ids.h> #include <arch/io.h> -#include "arch/romcc_io.h" +#include <arch/romcc_io.h> +#include <arch/smp/lapic.h> #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 <device/pci.h> #include <device/pci_ids.h> #include <device/pci_ops.h> +#include <cpu/p6/msr.h> #include <arch/io.h> #include <device/chip.h> #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 <stdint.h> #include <device/pci_def.h> #include <cpu/p6/apic.h> #include <arch/io.h> #include <device/pnp.h> #include <arch/romcc_io.h> +#include <arch/smp/lapic.h> +#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 <device/pci_def.h> +#include <device/pci_ids.h> +#include <device/hypertransport_def.h> #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<WAIT_TIMES;i++) { - unsigned long regx; - regx = pci_read_config32(NODE_HT(node),0x6c); - if((regx & (1<<4))==1) break; - } - reg = pci_read_config32(NODE_HT(node),0x6c); - reg &= ~(1<<4); // clear it - pci_write_config32(NODE_HT(node), 0x6c, reg); - -} -static void notify_bsp_ap_is_stopped(void) -{ - unsigned long reg; - unsigned long apic_id; - apic_id = *((volatile unsigned long *)(APIC_DEFAULT_BASE+APIC_ID)); - apic_id >>= 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<cpus; row++) setup_remote_row(node, row, cpus); @@ -356,18 +324,11 @@ static void setup_remote_node(u8 node, u8 cpus) uint32_t value; uint8_t reg; reg = pci_reg[i]; -#if 0 - print_debug("copying reg: "); - print_debug_hex8(reg); - print_debug("\r\n"); -#endif value = pci_read_config32(NODE_MP(0), reg); pci_write_config32(NODE_MP(7), reg, value); } -#if 1 - print_debug("setup_remote_done\r\n"); -#endif + print_spew("setup_remote_done\r\n"); } #endif @@ -381,79 +342,91 @@ static void setup_temp_node(u8 node, u8 cpus) } #endif -static u8 setup_uniprocessor(void) +static void setup_uniprocessor(void) { - print_debug("Enabling UP settings\r\n"); + print_spew("Enabling UP settings\r\n"); disable_probes(); - return 1; } +struct setup_smp_result { + int cpus; + int needs_reset; +}; + #if CONFIG_MAX_CPUS > 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; node<cpus; node++) { - if ((pci_read_config32(NODE_MC(node), 0xe8) & mask)!=mask) - mp_cap=FALSE; + if ((pci_read_config32(NODE_MC(node), 0xe8) & mask) != mask) { + mp_cap = FALSE; + } } - if (mp_cap) + if (mp_cap) { return cpus; + } /* one of our cpus is not mp capable */ - print_debug("One of the CPUs is not MP capable. Going back to UP\r\n"); + print_err("One of the CPUs is not MP capable. Going back to UP\r\n"); - for (node=cpus; node>0; 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; node<cpus; node++) { - u32 val; - val=pci_read_config32(NODE_HT(node), 0x60); + rev_a0 = is_cpu_rev_a0(); + for (node = 0; node < cpus; node++) { + device_t dev; + uint32_t val; + dev = NODE_HT(node); + + /* Set the Total CPU and Node count in the system */ + val = pci_read_config32(dev, 0x60); val &= (~0x000F0070); val |= ((cpus-1)<<16)|((cpus-1)<<4); - pci_write_config32(NODE_HT(node),0x60,val); - - val=pci_read_config32(NODE_HT(node), 0x68); -#if 1 - val |= 0x00008000; -#else - val |= 0x0f00c800; // 0x00008000->0f00c800 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 <device/pci_def.h> +#include <device/pci_ids.h> +#include <device/hypertransport_def.h> + +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 <device/pci.h> #include <device/pci_ids.h> #include <device/pci_ops.h> +#include <part/hard_reset.h> #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 <gart>\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 <cpu/k8/mtrr.h> #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<zend;zstart+=4) { - - /* test for the last 64 meg of 4 gig space */ - if(zstart == 0x0fc) - continue; - - /* disable cache */ - __asm__ volatile( - "movl %%cr0, %0\n\t" - "orl $0x40000000, %0\n\t" - "movl %0, %%cr0\n\t" - :"=r" (cnt) - ); - - /* Set the variable mtrrs to write combine */ - msr.lo = 1 + ((zstart&0x0ff)<<24); - msr.hi = (zstart&0x0ff00)>>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 <unistd.h> +#include <limits.h> +#include <stdint.h> +#include <string.h> +#include <setjmp.h> +#include <device/pci_def.h> +#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 <stdint.h> +#include <arch/smp/lapic.h> #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 <arch/io.h> + +/* 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 <console/console.h> +#include <pc80/keyboard.h> +#include <device/device.h> #include <arch/io.h> /* 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 <device/pci_ids.h> #include <device/pci_ops.h> #include <pc80/mc146818rtc.h> +#include <bitops.h> +#include <arch/io.h> #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 <device/pci_ids.h> #include <device/pci_ops.h> #include <device/chip.h> +#include <pc80/mc146818rtc.h> #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 <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#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 <device/pci.h> #include <device/pci_ids.h> #include <device/pci_ops.h> +#include <pc80/mc146818rtc.h> + +#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 <pc80/keyboard.h> +#include <uart8250.h> + 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 <arch/romcc_io.h> +#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 <arch/io.h> #include <device/device.h> +#include <device/pnp.h> #include <device/chip.h> #include <console/console.h> #include <string.h> #include <bitops.h> +#include <uart8250.h> +#include <pc80/keyboard.h> #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" }; |