diff options
author | Ronald G. Minnich <rminnich@gmail.com> | 2003-09-26 04:45:52 +0000 |
---|---|---|
committer | Ronald G. Minnich <rminnich@gmail.com> | 2003-09-26 04:45:52 +0000 |
commit | c817926a6bd4195cff6b6a0d8fa35b8637cee1b8 (patch) | |
tree | 0e359b22069293ab81af97c81c4e36ed083c2caa /src | |
parent | 10941401e8c040ade7456b0f49ab21c6306791fd (diff) |
via epia; also yh lu tyan.
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1138 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src')
-rw-r--r-- | src/mainboard/arima/hdama/Config.lb | 6 | ||||
-rw-r--r-- | src/mainboard/via/epia/Config.lb | 250 | ||||
-rw-r--r-- | src/mainboard/via/epia/auto.c | 89 | ||||
-rw-r--r-- | src/mainboard/via/epia/chip.h | 5 | ||||
-rw-r--r-- | src/mainboard/via/epia/cmos.layout | 74 | ||||
-rw-r--r-- | src/mainboard/via/epia/debug.c | 128 | ||||
-rw-r--r-- | src/mainboard/via/epia/failover.c | 38 | ||||
-rw-r--r-- | src/mainboard/via/epia/irq_tables.c | 25 | ||||
-rw-r--r-- | src/mainboard/via/epia/mainboard.c | 37 | ||||
-rw-r--r-- | src/mainboard/via/epia/reset.c | 43 | ||||
-rw-r--r-- | src/northbridge/via/vt8601/raminit.c | 2574 | ||||
-rw-r--r-- | src/northbridge/via/vt8601/raminit.h | 4 | ||||
-rw-r--r-- | src/southbridge/via/vt8231/vt8231_early_smbus.c | 114 |
13 files changed, 1103 insertions, 2284 deletions
diff --git a/src/mainboard/arima/hdama/Config.lb b/src/mainboard/arima/hdama/Config.lb index 97882302ed..b056124b74 100644 --- a/src/mainboard/arima/hdama/Config.lb +++ b/src/mainboard/arima/hdama/Config.lb @@ -15,6 +15,9 @@ uses _ROMBASE uses XIP_ROM_SIZE uses XIP_ROM_BASE +## ROM_SIZE is the size of boot ROM that this board will use. +default ROM_SIZE 524288 + ### ### Build options ### @@ -68,9 +71,6 @@ option MAINBOARD_VENDOR="ARIMA" ### LinuxBIOS layout values ### -## ROM_SIZE is the size of boot ROM that this board will use. -default ROM_SIZE = 524288 - ## ROM_IMAGE_SIZE is the amount of space to allow linuxBIOS to occupy. option ROM_IMAGE_SIZE = 65536 diff --git a/src/mainboard/via/epia/Config.lb b/src/mainboard/via/epia/Config.lb new file mode 100644 index 0000000000..6d30820105 --- /dev/null +++ b/src/mainboard/via/epia/Config.lb @@ -0,0 +1,250 @@ +uses HAVE_MP_TABLE +uses HAVE_PIRQ_TABLE +uses USE_FALLBACK_IMAGE +uses MAINBOARD +uses ARCH +uses FALLBACK_SIZE +uses ROM_SIZE +uses ROM_SECTION_SIZE +uses ROM_IMAGE_SIZE +uses ROM_SECTION_SIZE +uses ROM_SECTION_OFFSET +uses CONFIG_ROM_STREAM_START +uses PAYLOAD_SIZE +uses _ROMBASE +uses XIP_ROM_SIZE +uses XIP_ROM_BASE + +## ROM_SIZE is the size of boot ROM that this board will use. +default ROM_SIZE 524288 + +### +### Build options +### + +## +## Build code for the fallback boot +## +option HAVE_FALLBACK_BOOT=1 + +## +## Build code to reset the motherboard from linuxBIOS +## +option HAVE_HARD_RESET=1 + +## +## Build code to export a programmable irq routing table +## +option HAVE_PIRQ_TABLE=1 +option IRQ_SLOT_COUNT=7 + +## +## Build code to export an x86 MP table +## Useful for specifying IRQ routing values +## +option HAVE_MP_TABLE=1 + +## +## Build code to export a CMOS option table +## +option HAVE_OPTION_TABLE=1 + +## +## Build code for SMP support +## Only worry about 2 micro processors +## +option CONFIG_SMP=1 +option CONFIG_MAX_CPUS=2 + +## +## Build code to setup a generic IOAPIC +## +option CONFIG_IOAPIC=1 + +## +## Clean up the motherboard id strings +## +option MAINBOARD_PART_NUMBER="HDAMA" +option MAINBOARD_VENDOR="ARIMA" + +### +### LinuxBIOS layout values +### + +## ROM_IMAGE_SIZE is the amount of space to allow linuxBIOS to occupy. +option ROM_IMAGE_SIZE = 65536 + +## +## Use a small 8K stack +## +option STACK_SIZE=0x2000 + +## +## Use a small 16K heap +## +option HEAP_SIZE=0x4000 + +## +## Only use the option table in a normal image +## +option USE_OPTION_TABLE = !USE_FALLBACK_IMAGE + +## +## Compute the location and size of where this firmware image +## (linuxBIOS plus bootloader) will live in the boot rom chip. +## +if USE_FALLBACK_IMAGE + option ROM_SECTION_SIZE = FALLBACK_SIZE + option ROM_SECTION_OFFSET = ( ROM_SIZE - FALLBACK_SIZE ) +else + option ROM_SECTION_SIZE = ( ROM_SIZE - FALLBACK_SIZE ) + option ROM_SECTION_OFFSET = 0 +end + +## +## Compute the start location and size size of +## The linuxBIOS bootloader. +## +option PAYLOAD_SIZE = ( ROM_SECTION_SIZE - ROM_IMAGE_SIZE ) +option CONFIG_ROM_STREAM_START = (0xffffffff - ROM_SIZE + ROM_SECTION_OFFSET + 1) +option CONFIG_ROM_STREAM = 1 + +## +## Compute where this copy of linuxBIOS will start in the boot rom +## +option _ROMBASE = ( CONFIG_ROM_STREAM_START + PAYLOAD_SIZE ) + +## +## Compute a range of ROM that can cached to speed up linuxBIOS, +## execution speed. +## +## XIP_ROM_SIZE must be a power of 2. +## XIP_ROM_BASE must be a multiple of XIP_ROM_SIZE +## +option XIP_ROM_SIZE=65536 +option XIP_ROM_BASE = ( _ROMBASE + ROM_IMAGE_SIZE - XIP_ROM_SIZE ) + +## +## Set all of the defaults for an x86 architecture +## + +arch i386 end + +## +## Build the objects we have code for in this directory. +## + + +driver mainboard.o +#object reset.o + +## +## Romcc output +## +makerule ./failover.E + depends "$(MAINBOARD)/failover.c" + action "$(CPP) -I$(TOP)/src $(ROMCCPPFLAGS) $(CPPFLAGS) $(MAINBOARD)/failover.c > ./failover.E" +end + +makerule ./failover.inc + depends "./failover.E ./romcc" + 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" +end +makerule ./auto.inc + depends "./auto.E ./romcc" + action "./romcc -O ./auto.E > auto.inc" +end + +## +## Build our 16 bit and 32 bit linuxBIOS entry code +## +mainboardinit cpu/i386/entry16.inc +mainboardinit cpu/i386/entry32.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 +else + mainboardinit cpu/i386/reset32.inc + ldscript /cpu/i386/reset32.lds +end + +### Should this be in the northbridge code? +mainboardinit arch/i386/lib/cpu_reset.inc + +## +## Include an id string (For safe flashing) +## +mainboardinit arch/i386/lib/id.inc +ldscript /arch/i386/lib/id.lds + +## +## Setup our mtrrs +## +# mainboardinit cpu/p6/earlymtrr.inc + +### +### 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 + mainboardinit ./failover.inc +end + +### +### O.k. We aren't just an intermediary anymore! +### + +## +## Setup RAM +## +mainboardinit ./auto.inc + +## +## Include the secondary Configuration files +## +dir /pc80 +config chip.h + +northbridge via/vt8601 "vt8601" + pci 0:18.0 + pci 0:18.0 + pci 0:18.0 + pci 0:18.1 + pci 0:18.2 + pci 0:18.3 + southbridge via/vt8231 "vt8231" + register "enable_usb" = "0" + register "enable_native_ide" = "1" + register "enable_com_ports" = "1" + register "enable_keyboard" = "0" + register "enable_nvram" = "1" + pci 0:0.0 + pci 0:0.1 + pci 0:1.0 + pci 0:1.1 + end +end + +cpu p5 "cpu0" + +end + +## +## Include the old serial code for those few places that still need it. +## +mainboardinit pc80/serial.inc +mainboardinit arch/i386/lib/console.inc + diff --git a/src/mainboard/via/epia/auto.c b/src/mainboard/via/epia/auto.c new file mode 100644 index 0000000000..5b8aa0bbdd --- /dev/null +++ b/src/mainboard/via/epia/auto.c @@ -0,0 +1,89 @@ +#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 "pc80/serial.c" +#include "arch/i386/lib/console.c" +#include "ram/ramtest.c" +#include "northbridge/via/vt8601/raminit.h" +void udelay(int usecs) { + int i; + for(i = 0; i < usecs; i++) + outb(0x80, 0x80); +} + +#include "lib/delay.c" +#include "cpu/p6/boot_cpu.c" +#include "debug.c" + +#include "southbridge/via/vt8231/vt8231_early_smbus.c" +#define SIO_BASE 0x2e +#define MAXIMUM_CONSOLE_LOGLEVEL 9 +#define DEFAULT_CONSOLE_LOGLEVEL 9 + +static void memreset_setup(void) +{ +} + +/* +static void memreset(int controllers, const struct mem_controller *ctrl) +{ +} +*/ +static inline int spd_read_byte(unsigned device, unsigned address) +{ + return smbus_read_byte(device, address); +} + + + +#include "northbridge/via/vt8601/raminit.c" +#include "sdram/generic_sdram.c" + +static void main(void) +{ + struct mem_controller cpu[1]; + // init_timer(); + + uart_init(); + console_init(); + + enable_smbus(); + memreset_setup(); + sdram_initialize(sizeof(cpu)/sizeof(cpu[0]), cpu); + + + /* 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); + } +#endif +} diff --git a/src/mainboard/via/epia/chip.h b/src/mainboard/via/epia/chip.h new file mode 100644 index 0000000000..9836e2dfa9 --- /dev/null +++ b/src/mainboard/via/epia/chip.h @@ -0,0 +1,5 @@ +struct chip_control mainboard_arima_hdama_control; + +struct mainboard_arima_hdama_config { + int nothing; +}; diff --git a/src/mainboard/via/epia/cmos.layout b/src/mainboard/via/epia/cmos.layout new file mode 100644 index 0000000000..5ba4c032c1 --- /dev/null +++ b/src/mainboard/via/epia/cmos.layout @@ -0,0 +1,74 @@ +entries + +#start-bit length config config-ID name +#0 8 r 0 seconds +#8 8 r 0 alarm_seconds +#16 8 r 0 minutes +#24 8 r 0 alarm_minutes +#32 8 r 0 hours +#40 8 r 0 alarm_hours +#48 8 r 0 day_of_week +#56 8 r 0 day_of_month +#64 8 r 0 month +#72 8 r 0 year +#80 4 r 0 rate_select +#84 3 r 0 REF_Clock +#87 1 r 0 UIP +#88 1 r 0 auto_switch_DST +#89 1 r 0 24_hour_mode +#90 1 r 0 binary_values_enable +#91 1 r 0 square-wave_out_enable +#92 1 r 0 update_finished_enable +#93 1 r 0 alarm_interrupt_enable +#94 1 r 0 periodic_interrupt_enable +#95 1 r 0 disable_clock_updates +#96 288 r 0 temporary_filler +0 384 r 0 reserved_memory +384 1 e 4 boot_option +385 1 e 4 last_boot +386 1 e 1 ECC_memory +388 4 r 0 reboot_bits +392 3 e 5 baud_rate +400 1 e 1 power_on_after_fail +412 4 e 6 debug_level +416 4 e 7 boot_first +420 4 e 7 boot_second +424 4 e 7 boot_third +428 4 h 0 boot_index +432 8 h 0 boot_countdown +1008 16 h 0 check_sum + +enumerations + +#ID value text +1 0 Disable +1 1 Enable +2 0 Enable +2 1 Disable +4 0 Fallback +4 1 Normal +5 0 115200 +5 1 57600 +5 2 38400 +5 3 19200 +5 4 9600 +5 5 4800 +5 6 2400 +5 7 1200 +6 6 Notice +6 7 Info +6 8 Debug +6 9 Spew +7 0 Network +7 1 HDD +7 2 Floppy +7 8 Fallback_Network +7 9 Fallback_HDD +7 10 Fallback_Floppy +#7 3 ROM + +checksums + +checksum 392 1007 1008 + + diff --git a/src/mainboard/via/epia/debug.c b/src/mainboard/via/epia/debug.c new file mode 100644 index 0000000000..714fcc5783 --- /dev/null +++ b/src/mainboard/via/epia/debug.c @@ -0,0 +1,128 @@ + +static void print_debug_pci_dev(unsigned dev) +{ + print_debug("PCI: "); + print_debug_hex8((dev >> 16) & 0xff); + print_debug_char(':'); + print_debug_hex8((dev >> 11) & 0x1f); + print_debug_char('.'); + print_debug_hex8((dev >> 8) & 7); +} + +static void print_pci_devices(void) +{ + device_t dev; + for(dev = PCI_DEV(0, 0, 0); + dev <= PCI_DEV(0, 0x1f, 0x7); + dev += PCI_DEV(0,0,1)) { + uint32_t id; + id = pci_read_config32(dev, PCI_VENDOR_ID); + if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0x0000)) { + continue; + } + print_debug_pci_dev(dev); + print_debug("\r\n"); + } +} + +static void dump_pci_device(unsigned dev) +{ + int i; + print_debug_pci_dev(dev); + print_debug("\r\n"); + + for(i = 0; i <= 255; i++) { + unsigned char val; + if ((i & 0x0f) == 0) { + print_debug_hex8(i); + print_debug_char(':'); + } + val = pci_read_config8(dev, i); + print_debug_char(' '); + print_debug_hex8(val); + if ((i & 0x0f) == 0x0f) { + print_debug("\r\n"); + } + } +} + +static void dump_pci_devices(void) +{ + device_t dev; + for(dev = PCI_DEV(0, 0, 0); + dev <= PCI_DEV(0, 0x1f, 0x7); + dev += PCI_DEV(0,0,1)) { + uint32_t id; + id = pci_read_config32(dev, PCI_VENDOR_ID); + if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0x0000)) { + continue; + } + dump_pci_device(dev); + } +} +#if 0 +static void dump_spd_registers(const struct mem_controller *ctrl) +{ + int i; + print_debug("\r\n"); + for(i = 0; i < 4; i++) { + unsigned device; + device = ctrl->channel0[i]; + if (device) { + int j; + print_debug("dimm: "); + print_debug_hex8(i); + print_debug(".0: "); + print_debug_hex8(device); + for(j = 0; j < 256; j++) { + int status; + unsigned char byte; + if ((j & 0xf) == 0) { + print_debug("\r\n"); + print_debug_hex8(j); + print_debug(": "); + } + status = smbus_read_byte(device, j); + if (status < 0) { + print_debug("bad device\r\n"); + break; + } + byte = status & 0xff; + print_debug_hex8(byte); + print_debug_char(' '); + } + print_debug("\r\n"); + } + device = ctrl->channel1[i]; + if (device) { + int j; + print_debug("dimm: "); + print_debug_hex8(i); + print_debug(".1: "); + print_debug_hex8(device); + for(j = 0; j < 256; j++) { + int status; + unsigned char byte; + if ((j & 0xf) == 0) { + print_debug("\r\n"); + print_debug_hex8(j); + print_debug(": "); + } + status = smbus_read_byte(device, j); + if (status < 0) { + print_debug("bad device\r\n"); + break; + } + byte = status & 0xff; + print_debug_hex8(byte); + print_debug_char(' '); + } + print_debug("\r\n"); + } + } +} +#endif diff --git a/src/mainboard/via/epia/failover.c b/src/mainboard/via/epia/failover.c new file mode 100644 index 0000000000..8eeeaef7e1 --- /dev/null +++ b/src/mainboard/via/epia/failover.c @@ -0,0 +1,38 @@ +#define ASSEMBLY 1 +#include <stdint.h> +#include <device/pci_def.h> +#include <device/pci_ids.h> +#include <arch/io.h> +#include "arch/romcc_io.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" + +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(); + + /* Is this a cpu reset? */ + if (cpu_init_detected()) { + if (last_boot_normal()) { + asm("jmp __normal_image"); + } else { + asm("jmp __cpu_reset"); + } + } + /* Is this a secondary cpu? */ + else if (!boot_cpu() && last_boot_normal()) { + asm("jmp __normal_image"); + } + /* This is the primary cpu how should I boot? */ + else if (do_normal_boot()) { + asm("jmp __normal_image"); + } +} diff --git a/src/mainboard/via/epia/irq_tables.c b/src/mainboard/via/epia/irq_tables.c new file mode 100644 index 0000000000..b59ce9f1e9 --- /dev/null +++ b/src/mainboard/via/epia/irq_tables.c @@ -0,0 +1,25 @@ +/* This file was generated by getpir.c, do not modify! + (but if you do, please run checkpir on it to verify) + Contains the IRQ Routing Table dumped directly from your memory , wich BIOS sets up + + Documentation at : http://www.microsoft.com/hwdev/busbios/PCIIRQ.HTM +*/ + +#include <arch/pirq_routing.h> + + +const struct irq_routing_table intel_irq_routing_table = { + PIRQ_SIGNATURE, /* u32 signature */ + PIRQ_VERSION, /* u16 version */ + 32+16*18, /* there can be total 18 devices on the bus */ + 1, /* Where the interrupt router lies (bus) */ + 0x23, /* Where the interrupt router lies (dev) */ + 0, /* IRQs devoted exclusively to PCI usage */ + 0x0, /* Vendor */ + 0x0, /* Device */ + 0, /* Crap (miniport) */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */ + 0x35, /* u8 checksum , this hase to set to some value that would give 0 after the sum of all bytes for this structure (including checksum) */ + { + } +}; diff --git a/src/mainboard/via/epia/mainboard.c b/src/mainboard/via/epia/mainboard.c new file mode 100644 index 0000000000..6790aaca1b --- /dev/null +++ b/src/mainboard/via/epia/mainboard.c @@ -0,0 +1,37 @@ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> + +#include <arch/io.h> +#include <device/chip.h> +#include "../../../northbridge/amd/amdk8/northbridge.h" +#include "chip.h" + + +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, + .scan_bus = vt8_scan_root_bus, + .enable = 0, +}; + +static void enumerate(struct chip *chip) +{ + struct chip *child; + dev_root.ops = &mainboard_operations; + chip->dev = &dev_root; + chip->bus = 0; + for(child = chip->children; child; child = child->next) { + child->bus = &dev_root.link[0]; + } +} +struct chip_control mainboard_via_epia_control = { + .enumerate = enumerate, + .name = "Arima HDAMA mainboard ", +}; + diff --git a/src/mainboard/via/epia/reset.c b/src/mainboard/via/epia/reset.c new file mode 100644 index 0000000000..5796e17dc8 --- /dev/null +++ b/src/mainboard/via/epia/reset.c @@ -0,0 +1,43 @@ +#if 0 +//#include "arch/romcc_io.h" +#include <arch/io.h> + +typedef unsigned device_t; + +#define PCI_DEV(BUS, DEV, FN) ( \ + (((BUS) & 0xFF) << 16) | \ + (((DEV) & 0x1f) << 11) | \ + (((FN) & 0x7) << 8)) + +static void pci_write_config8(device_t dev, unsigned where, unsigned char value) +{ + unsigned addr; + addr = dev | where; + outl(0x80000000 | (addr & ~3), 0xCF8); + outb(value, 0xCFC + (addr & 3)); +} + +static void pci_write_config32(device_t dev, unsigned where, unsigned value) +{ + unsigned addr; + addr = dev | where; + outl(0x80000000 | (addr & ~3), 0xCF8); + outl(value, 0xCFC); +} + +static unsigned pci_read_config32(device_t dev, unsigned where) +{ + unsigned addr; + addr = dev | where; + outl(0x80000000 | (addr & ~3), 0xCF8); + return inl(0xCFC); +} + +#include "../../../northbridge/amd/amdk8/reset_test.c" + +void hard_reset(void) +{ + set_bios_reset(); + pci_write_config8(PCI_DEV(1, 0x04, 0), 0x47, 1); +} +#endif diff --git a/src/northbridge/via/vt8601/raminit.c b/src/northbridge/via/vt8601/raminit.c index 802e4318b4..864fbbe282 100644 --- a/src/northbridge/via/vt8601/raminit.c +++ b/src/northbridge/via/vt8601/raminit.c @@ -1,2308 +1,320 @@ -#include <cpu/k8/mtrr.h> +#include <cpu/p6/mtrr.h> #include "raminit.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 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 - - -static void setup_resource_map(const unsigned int *register_values, int max) -{ - int i; - print_debug("setting up resource map....\r\n"); - 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"); -#endif - dev = register_values[i] & ~0xff; - where = register_values[i] & 0xff; - reg = pci_read_config32(dev, where); - reg &= register_values[i+1]; - reg |= register_values[i+2]; - pci_write_config32(dev, where, reg); #if 0 - reg = pci_read_config32(register_values[i]); - reg &= register_values[i+1]; - reg |= register_values[i+2] & ~register_values[i+1]; - pci_write_config32(register_values[i], reg); +/* +This software and ancillary information (herein called SOFTWARE ) +called LinuxBIOS is made available under the terms described +here. The SOFTWARE has been approved for release with associated +LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has +been authored by an employee or employees of the University of +California, operator of the Los Alamos National Laboratory under +Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The +U.S. Government has rights to use, reproduce, and distribute this +SOFTWARE. The public may copy, distribute, prepare derivative works +and publicly display this SOFTWARE without charge, provided that this +Notice and any statement of authorship are reproduced on all copies. +Neither the Government nor the University makes any warranty, express +or implied, or assumes any liability or responsibility for the use of +this SOFTWARE. If SOFTWARE is modified to produce derivative works, +such modified SOFTWARE should be clearly marked, so as not to confuse +it with the version available from LANL. + */ +/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL + * rminnich@lanl.gov + */ +/* + * 11/26/02 - kevinh@ispiri.com - The existing comments implied that + * this didn't work yet. Therefore, I've updated it so that it works + * correctly - at least on my VIA epia motherboard. 64MB DIMM in slot 0. + */ + +/* Added automatic detection of first equipped bank and its MA mapping type. + * (Rest of configuration is done in C) + * 5/19/03 by SONE Takeshi <ts1@tsn.or.jp> + */ + +// Set to 1 if your DIMMs are PC133 +// Note that I'm assuming CPU's FSB frequency is 133MHz. If your CPU runs +// at another bus speed, you might need to change some of register values. +#ifndef DIMM_PC133 +#define DIMM_PC133 0 #endif - } - print_debug("done.\r\n"); -} - -static void setup_default_resource_map(void) -{ - static const unsigned int register_values[] = { - /* Careful set limit registers before base registers which contain the enables */ - /* DRAM Limit i Registers - * F1:0x44 i = 0 - * F1:0x4C i = 1 - * F1:0x54 i = 2 - * F1:0x5C i = 3 - * F1:0x64 i = 4 - * F1:0x6C i = 5 - * F1:0x74 i = 6 - * F1:0x7C i = 7 - * [ 2: 0] Destination Node ID - * 000 = Node 0 - * 001 = Node 1 - * 010 = Node 2 - * 011 = Node 3 - * 100 = Node 4 - * 101 = Node 5 - * 110 = Node 6 - * 111 = Node 7 - * [ 7: 3] Reserved - * [10: 8] Interleave select - * specifies the values of A[14:12] to use with interleave enable. - * [15:11] Reserved - * [31:16] DRAM Limit Address i Bits 39-24 - * This field defines the upper address bits of a 40 bit address - * that define the end of the DRAM region. - */ - PCI_ADDR(0, 0x18, 1, 0x44), 0x0000f8f8, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x4C), 0x0000f8f8, 0x00000001, - PCI_ADDR(0, 0x18, 1, 0x54), 0x0000f8f8, 0x00000002, - PCI_ADDR(0, 0x18, 1, 0x5C), 0x0000f8f8, 0x00000003, - PCI_ADDR(0, 0x18, 1, 0x64), 0x0000f8f8, 0x00000004, - PCI_ADDR(0, 0x18, 1, 0x6C), 0x0000f8f8, 0x00000005, - PCI_ADDR(0, 0x18, 1, 0x74), 0x0000f8f8, 0x00000006, - PCI_ADDR(0, 0x18, 1, 0x7C), 0x0000f8f8, 0x00000007, - /* DRAM Base i Registers - * F1:0x40 i = 0 - * F1:0x48 i = 1 - * F1:0x50 i = 2 - * F1:0x58 i = 3 - * F1:0x60 i = 4 - * F1:0x68 i = 5 - * F1:0x70 i = 6 - * F1:0x78 i = 7 - * [ 0: 0] Read Enable - * 0 = Reads Disabled - * 1 = Reads Enabled - * [ 1: 1] Write Enable - * 0 = Writes Disabled - * 1 = Writes Enabled - * [ 7: 2] Reserved - * [10: 8] Interleave Enable - * 000 = No interleave - * 001 = Interleave on A[12] (2 nodes) - * 010 = reserved - * 011 = Interleave on A[12] and A[14] (4 nodes) - * 100 = reserved - * 101 = reserved - * 110 = reserved - * 111 = Interleve on A[12] and A[13] and A[14] (8 nodes) - * [15:11] Reserved - * [13:16] DRAM Base Address i Bits 39-24 - * This field defines the upper address bits of a 40-bit address - * that define the start of the DRAM region. - */ - PCI_ADDR(0, 0x18, 1, 0x40), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x48), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x50), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x58), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x60), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x68), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x70), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x78), 0x0000f8fc, 0x00000000, - - /* Memory-Mapped I/O Limit i Registers - * F1:0x84 i = 0 - * F1:0x8C i = 1 - * F1:0x94 i = 2 - * F1:0x9C i = 3 - * F1:0xA4 i = 4 - * F1:0xAC i = 5 - * F1:0xB4 i = 6 - * F1:0xBC i = 7 - * [ 2: 0] Destination Node ID - * 000 = Node 0 - * 001 = Node 1 - * 010 = Node 2 - * 011 = Node 3 - * 100 = Node 4 - * 101 = Node 5 - * 110 = Node 6 - * 111 = Node 7 - * [ 3: 3] Reserved - * [ 5: 4] Destination Link ID - * 00 = Link 0 - * 01 = Link 1 - * 10 = Link 2 - * 11 = Reserved - * [ 6: 6] Reserved - * [ 7: 7] Non-Posted - * 0 = CPU writes may be posted - * 1 = CPU writes must be non-posted - * [31: 8] Memory-Mapped I/O Limit Address i (39-16) - * This field defines the upp adddress bits of a 40-bit address that - * defines the end of a memory-mapped I/O region n - */ - PCI_ADDR(0, 0x18, 1, 0x84), 0x00000048, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x8C), 0x00000048, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x94), 0x00000048, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x9C), 0x00000048, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xA4), 0x00000048, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xAC), 0x00000048, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xB4), 0x00000048, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xBC), 0x00000048, 0x00ffff00, - - /* Memory-Mapped I/O Base i Registers - * F1:0x80 i = 0 - * F1:0x88 i = 1 - * F1:0x90 i = 2 - * F1:0x98 i = 3 - * F1:0xA0 i = 4 - * F1:0xA8 i = 5 - * F1:0xB0 i = 6 - * F1:0xB8 i = 7 - * [ 0: 0] Read Enable - * 0 = Reads disabled - * 1 = Reads Enabled - * [ 1: 1] Write Enable - * 0 = Writes disabled - * 1 = Writes Enabled - * [ 2: 2] Cpu Disable - * 0 = Cpu can use this I/O range - * 1 = Cpu requests do not use this I/O range - * [ 3: 3] Lock - * 0 = base/limit registers i are read/write - * 1 = base/limit registers i are read-only - * [ 7: 4] Reserved - * [31: 8] Memory-Mapped I/O Base Address i (39-16) - * This field defines the upper address bits of a 40bit address - * that defines the start of memory-mapped I/O region i - */ - PCI_ADDR(0, 0x18, 1, 0x80), 0x000000f0, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x88), 0x000000f0, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x90), 0x000000f0, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x98), 0x000000f0, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xA0), 0x000000f0, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xA8), 0x000000f0, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xB0), 0x000000f0, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xB8), 0x000000f0, 0x00fc0003, - - /* PCI I/O Limit i Registers - * F1:0xC4 i = 0 - * F1:0xCC i = 1 - * F1:0xD4 i = 2 - * F1:0xDC i = 3 - * [ 2: 0] Destination Node ID - * 000 = Node 0 - * 001 = Node 1 - * 010 = Node 2 - * 011 = Node 3 - * 100 = Node 4 - * 101 = Node 5 - * 110 = Node 6 - * 111 = Node 7 - * [ 3: 3] Reserved - * [ 5: 4] Destination Link ID - * 00 = Link 0 - * 01 = Link 1 - * 10 = Link 2 - * 11 = reserved - * [11: 6] Reserved - * [24:12] PCI I/O Limit Address i - * This field defines the end of PCI I/O region n - * [31:25] Reserved - */ - PCI_ADDR(0, 0x18, 1, 0xC4), 0xFE000FC8, 0x01fff000, - PCI_ADDR(0, 0x18, 1, 0xCC), 0xFE000FC8, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xD4), 0xFE000FC8, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xDC), 0xFE000FC8, 0x00000000, - /* PCI I/O Base i Registers - * F1:0xC0 i = 0 - * F1:0xC8 i = 1 - * F1:0xD0 i = 2 - * F1:0xD8 i = 3 - * [ 0: 0] Read Enable - * 0 = Reads Disabled - * 1 = Reads Enabled - * [ 1: 1] Write Enable - * 0 = Writes Disabled - * 1 = Writes Enabled - * [ 3: 2] Reserved - * [ 4: 4] VGA Enable - * 0 = VGA matches Disabled - * 1 = matches all address < 64K and where A[9:0] is in the - * range 3B0-3BB or 3C0-3DF independen of the base & limit registers - * [ 5: 5] ISA Enable - * 0 = ISA matches Disabled - * 1 = Blocks address < 64K and in the last 768 bytes of eack 1K block - * from matching agains this base/limit pair - * [11: 6] Reserved - * [24:12] PCI I/O Base i - * This field defines the start of PCI I/O region n - * [31:25] Reserved - */ - PCI_ADDR(0, 0x18, 1, 0xC0), 0xFE000FCC, 0x00000003, - PCI_ADDR(0, 0x18, 1, 0xC8), 0xFE000FCC, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xD0), 0xFE000FCC, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xD8), 0xFE000FCC, 0x00000000, - - /* Config Base and Limit i Registers - * F1:0xE0 i = 0 - * F1:0xE4 i = 1 - * F1:0xE8 i = 2 - * F1:0xEC i = 3 - * [ 0: 0] Read Enable - * 0 = Reads Disabled - * 1 = Reads Enabled - * [ 1: 1] Write Enable - * 0 = Writes Disabled - * 1 = Writes Enabled - * [ 2: 2] Device Number Compare Enable - * 0 = The ranges are based on bus number - * 1 = The ranges are ranges of devices on bus 0 - * [ 3: 3] Reserved - * [ 6: 4] Destination Node - * 000 = Node 0 - * 001 = Node 1 - * 010 = Node 2 - * 011 = Node 3 - * 100 = Node 4 - * 101 = Node 5 - * 110 = Node 6 - * 111 = Node 7 - * [ 7: 7] Reserved - * [ 9: 8] Destination Link - * 00 = Link 0 - * 01 = Link 1 - * 10 = Link 2 - * 11 - Reserved - * [15:10] Reserved - * [23:16] Bus Number Base i - * This field defines the lowest bus number in configuration region i - * [31:24] Bus Number Limit i - * This field defines the highest bus number in configuration regin i - */ - PCI_ADDR(0, 0x18, 1, 0xE0), 0x0000FC88, 0xff000003, - PCI_ADDR(0, 0x18, 1, 0xE4), 0x0000FC88, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xE8), 0x0000FC88, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xEC), 0x0000FC88, 0x00000000, - }; - int max; - max = sizeof(register_values)/sizeof(register_values[0]); - setup_resource_map(register_values, max); -} - -static void sdram_set_registers(const struct mem_controller *ctrl) -{ - static const unsigned int register_values[] = { - - /* Careful set limit registers before base registers which contain the enables */ - /* DRAM Limit i Registers - * F1:0x44 i = 0 - * F1:0x4C i = 1 - * F1:0x54 i = 2 - * F1:0x5C i = 3 - * F1:0x64 i = 4 - * F1:0x6C i = 5 - * F1:0x74 i = 6 - * F1:0x7C i = 7 - * [ 2: 0] Destination Node ID - * 000 = Node 0 - * 001 = Node 1 - * 010 = Node 2 - * 011 = Node 3 - * 100 = Node 4 - * 101 = Node 5 - * 110 = Node 6 - * 111 = Node 7 - * [ 7: 3] Reserved - * [10: 8] Interleave select - * specifies the values of A[14:12] to use with interleave enable. - * [15:11] Reserved - * [31:16] DRAM Limit Address i Bits 39-24 - * This field defines the upper address bits of a 40 bit address - * that define the end of the DRAM region. - */ - PCI_ADDR(0, 0x18, 1, 0x44), 0x0000f8f8, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x4C), 0x0000f8f8, 0x00000001, - PCI_ADDR(0, 0x18, 1, 0x54), 0x0000f8f8, 0x00000002, - PCI_ADDR(0, 0x18, 1, 0x5C), 0x0000f8f8, 0x00000003, - PCI_ADDR(0, 0x18, 1, 0x64), 0x0000f8f8, 0x00000004, - PCI_ADDR(0, 0x18, 1, 0x6C), 0x0000f8f8, 0x00000005, - PCI_ADDR(0, 0x18, 1, 0x74), 0x0000f8f8, 0x00000006, - PCI_ADDR(0, 0x18, 1, 0x7C), 0x0000f8f8, 0x00000007, - /* DRAM Base i Registers - * F1:0x40 i = 0 - * F1:0x48 i = 1 - * F1:0x50 i = 2 - * F1:0x58 i = 3 - * F1:0x60 i = 4 - * F1:0x68 i = 5 - * F1:0x70 i = 6 - * F1:0x78 i = 7 - * [ 0: 0] Read Enable - * 0 = Reads Disabled - * 1 = Reads Enabled - * [ 1: 1] Write Enable - * 0 = Writes Disabled - * 1 = Writes Enabled - * [ 7: 2] Reserved - * [10: 8] Interleave Enable - * 000 = No interleave - * 001 = Interleave on A[12] (2 nodes) - * 010 = reserved - * 011 = Interleave on A[12] and A[14] (4 nodes) - * 100 = reserved - * 101 = reserved - * 110 = reserved - * 111 = Interleve on A[12] and A[13] and A[14] (8 nodes) - * [15:11] Reserved - * [13:16] DRAM Base Address i Bits 39-24 - * This field defines the upper address bits of a 40-bit address - * that define the start of the DRAM region. - */ - PCI_ADDR(0, 0x18, 1, 0x40), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x48), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x50), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x58), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x60), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x68), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x70), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x78), 0x0000f8fc, 0x00000000, - - /* DRAM CS Base Address i Registers - * F2:0x40 i = 0 - * F2:0x44 i = 1 - * F2:0x48 i = 2 - * F2:0x4C i = 3 - * F2:0x50 i = 4 - * F2:0x54 i = 5 - * F2:0x58 i = 6 - * F2:0x5C i = 7 - * [ 0: 0] Chip-Select Bank Enable - * 0 = Bank Disabled - * 1 = Bank Enabled - * [ 8: 1] Reserved - * [15: 9] Base Address (19-13) - * An optimization used when all DIMM are the same size... - * [20:16] Reserved - * [31:21] Base Address (35-25) - * This field defines the top 11 addresses bit of a 40-bit - * address that define the memory address space. These - * bits decode 32-MByte blocks of memory. - */ - PCI_ADDR(0, 0x18, 2, 0x40), 0x001f01fe, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x44), 0x001f01fe, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x48), 0x001f01fe, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x4C), 0x001f01fe, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x50), 0x001f01fe, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x54), 0x001f01fe, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x58), 0x001f01fe, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x5C), 0x001f01fe, 0x00000000, - /* DRAM CS Mask Address i Registers - * F2:0x60 i = 0 - * F2:0x64 i = 1 - * F2:0x68 i = 2 - * F2:0x6C i = 3 - * F2:0x70 i = 4 - * F2:0x74 i = 5 - * F2:0x78 i = 6 - * F2:0x7C i = 7 - * Select bits to exclude from comparison with the DRAM Base address register. - * [ 8: 0] Reserved - * [15: 9] Address Mask (19-13) - * Address to be excluded from the optimized case - * [20:16] Reserved - * [29:21] Address Mask (33-25) - * The bits with an address mask of 1 are excluded from address comparison - * [31:30] Reserved - * - */ - PCI_ADDR(0, 0x18, 2, 0x60), 0xC01f01ff, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x64), 0xC01f01ff, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x68), 0xC01f01ff, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x6C), 0xC01f01ff, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x70), 0xC01f01ff, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x74), 0xC01f01ff, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x78), 0xC01f01ff, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x7C), 0xC01f01ff, 0x00000000, - /* DRAM Bank Address Mapping Register - * F2:0x80 - * Specify the memory module size - * [ 2: 0] CS1/0 - * [ 6: 4] CS3/2 - * [10: 8] CS5/4 - * [14:12] CS7/6 - * 000 = 32Mbyte (Rows = 12 & Col = 8) - * 001 = 64Mbyte (Rows = 12 & Col = 9) - * 010 = 128Mbyte (Rows = 13 & Col = 9)|(Rows = 12 & Col = 10) - * 011 = 256Mbyte (Rows = 13 & Col = 10)|(Rows = 12 & Col = 11) - * 100 = 512Mbyte (Rows = 13 & Col = 11)|(Rows = 14 & Col = 10) - * 101 = 1Gbyte (Rows = 14 & Col = 11)|(Rows = 13 & Col = 12) - * 110 = 2Gbyte (Rows = 14 & Col = 12) - * 111 = reserved - * [ 3: 3] Reserved - * [ 7: 7] Reserved - * [11:11] Reserved - * [31:15] - */ - PCI_ADDR(0, 0x18, 2, 0x80), 0xffff8888, 0x00000000, - /* DRAM Timing Low Register - * F2:0x88 - * [ 2: 0] Tcl (Cas# Latency, Cas# to read-data-valid) - * 000 = reserved - * 001 = CL 2 - * 010 = CL 3 - * 011 = reserved - * 100 = reserved - * 101 = CL 2.5 - * 110 = reserved - * 111 = reserved - * [ 3: 3] Reserved - * [ 7: 4] Trc (Row Cycle Time, Ras#-active to Ras#-active/bank auto refresh) - * 0000 = 7 bus clocks - * 0001 = 8 bus clocks - * ... - * 1110 = 21 bus clocks - * 1111 = 22 bus clocks - * [11: 8] Trfc (Row refresh Cycle time, Auto-refresh-active to RAS#-active or RAS#auto-refresh) - * 0000 = 9 bus clocks - * 0010 = 10 bus clocks - * .... - * 1110 = 23 bus clocks - * 1111 = 24 bus clocks - * [14:12] Trcd (Ras#-active to Case#-read/write Delay) - * 000 = reserved - * 001 = reserved - * 010 = 2 bus clocks - * 011 = 3 bus clocks - * 100 = 4 bus clocks - * 101 = 5 bus clocks - * 110 = 6 bus clocks - * 111 = reserved - * [15:15] Reserved - * [18:16] Trrd (Ras# to Ras# Delay) - * 000 = reserved - * 001 = reserved - * 010 = 2 bus clocks - * 011 = 3 bus clocks - * 100 = 4 bus clocks - * 101 = reserved - * 110 = reserved - * 111 = reserved - * [19:19] Reserved - * [23:20] Tras (Minmum Ras# Active Time) - * 0000 to 0100 = reserved - * 0101 = 5 bus clocks - * ... - * 1111 = 15 bus clocks - * [26:24] Trp (Row Precharge Time) - * 000 = reserved - * 001 = reserved - * 010 = 2 bus clocks - * 011 = 3 bus clocks - * 100 = 4 bus clocks - * 101 = 5 bus clocks - * 110 = 6 bus clocks - * 111 = reserved - * [27:27] Reserved - * [28:28] Twr (Write Recovery Time) - * 0 = 2 bus clocks - * 1 = 3 bus clocks - * [31:29] Reserved - */ - PCI_ADDR(0, 0x18, 2, 0x88), 0xe8088008, 0x02522001 /* 0x03623125 */ , - /* DRAM Timing High Register - * F2:0x8C - * [ 0: 0] Twtr (Write to Read Delay) - * 0 = 1 bus Clocks - * 1 = 2 bus Clocks - * [ 3: 1] Reserved - * [ 6: 4] Trwt (Read to Write Delay) - * 000 = 1 bus clocks - * 001 = 2 bus clocks - * 010 = 3 bus clocks - * 011 = 4 bus clocks - * 100 = 5 bus clocks - * 101 = 6 bus clocks - * 110 = reserved - * 111 = reserved - * [ 7: 7] Reserved - * [12: 8] Tref (Refresh Rate) - * 00000 = 100Mhz 4K rows - * 00001 = 133Mhz 4K rows - * 00010 = 166Mhz 4K rows - * 00011 = 200Mhz 4K rows - * 01000 = 100Mhz 8K/16K rows - * 01001 = 133Mhz 8K/16K rows - * 01010 = 166Mhz 8K/16K rows - * 01011 = 200Mhz 8K/16K rows - * [19:13] Reserved - * [22:20] Twcl (Write CAS Latency) - * 000 = 1 Mem clock after CAS# (Unbuffered Dimms) - * 001 = 2 Mem clocks after CAS# (Registered Dimms) - * [31:23] Reserved - */ - PCI_ADDR(0, 0x18, 2, 0x8c), 0xff8fe08e, (0 << 20)|(0 << 8)|(0 << 4)|(0 << 0), - /* DRAM Config Low Register - * F2:0x90 - * [ 0: 0] DLL Disable - * 0 = Enabled - * 1 = Disabled - * [ 1: 1] D_DRV - * 0 = Normal Drive - * 1 = Weak Drive - * [ 2: 2] QFC_EN - * 0 = Disabled - * 1 = Enabled - * [ 3: 3] Disable DQS Hystersis (FIXME handle this one carefully) - * 0 = Enable DQS input filter - * 1 = Disable DQS input filtering - * [ 7: 4] Reserved - * [ 8: 8] DRAM_Init - * 0 = Initialization done or not yet started. - * 1 = Initiate DRAM intialization sequence - * [ 9: 9] SO-Dimm Enable - * 0 = Do nothing - * 1 = SO-Dimms present - * [10:10] DramEnable - * 0 = DRAM not enabled - * 1 = DRAM initialized and enabled - * [11:11] Memory Clear Status - * 0 = Memory Clear function has not completed - * 1 = Memory Clear function has completed - * [12:12] Exit Self-Refresh - * 0 = Exit from self-refresh done or not yet started - * 1 = DRAM exiting from self refresh - * [13:13] Self-Refresh Status - * 0 = Normal Operation - * 1 = Self-refresh mode active - * [15:14] Read/Write Queue Bypass Count - * 00 = 2 - * 01 = 4 - * 10 = 8 - * 11 = 16 - * [16:16] 128-bit/64-Bit - * 0 = 64bit Interface to DRAM - * 1 = 128bit Interface to DRAM - * [17:17] DIMM ECC Enable - * 0 = Some DIMMs do not have ECC - * 1 = ALL DIMMS have ECC bits - * [18:18] UnBuffered DIMMs - * 0 = Buffered DIMMS - * 1 = Unbuffered DIMMS - * [19:19] Enable 32-Byte Granularity - * 0 = Optimize for 64byte bursts - * 1 = Optimize for 32byte bursts - * [20:20] DIMM 0 is x4 - * [21:21] DIMM 1 is x4 - * [22:22] DIMM 2 is x4 - * [23:23] DIMM 3 is x4 - * 0 = DIMM is not x4 - * 1 = x4 DIMM present - * [24:24] Disable DRAM Receivers - * 0 = Receivers enabled - * 1 = Receivers disabled - * [27:25] Bypass Max - * 000 = Arbiters chois is always respected - * 001 = Oldest entry in DCQ can be bypassed 1 time - * 010 = Oldest entry in DCQ can be bypassed 2 times - * 011 = Oldest entry in DCQ can be bypassed 3 times - * 100 = Oldest entry in DCQ can be bypassed 4 times - * 101 = Oldest entry in DCQ can be bypassed 5 times - * 110 = Oldest entry in DCQ can be bypassed 6 times - * 111 = Oldest entry in DCQ can be bypassed 7 times - * [31:28] Reserved - */ - PCI_ADDR(0, 0x18, 2, 0x90), 0xf0000000, - (4 << 25)|(0 << 24)| - (0 << 23)|(0 << 22)|(0 << 21)|(0 << 20)| - (1 << 19)|(0 << 18)|(1 << 17)|(0 << 16)| - (2 << 14)|(0 << 13)|(0 << 12)| - (0 << 11)|(0 << 10)|(0 << 9)|(0 << 8)| - (0 << 3) |(0 << 1) |(0 << 0), - /* DRAM Config High Register - * F2:0x94 - * [ 0: 3] Maximum Asynchronous Latency - * 0000 = 0 ns - * ... - * 1111 = 15 ns - * [ 7: 4] Reserved - * [11: 8] Read Preamble - * 0000 = 2.0 ns - * 0001 = 2.5 ns - * 0010 = 3.0 ns - * 0011 = 3.5 ns - * 0100 = 4.0 ns - * 0101 = 4.5 ns - * 0110 = 5.0 ns - * 0111 = 5.5 ns - * 1000 = 6.0 ns - * 1001 = 6.5 ns - * 1010 = 7.0 ns - * 1011 = 7.5 ns - * 1100 = 8.0 ns - * 1101 = 8.5 ns - * 1110 = 9.0 ns - * 1111 = 9.5 ns - * [15:12] Reserved - * [18:16] Idle Cycle Limit - * 000 = 0 cycles - * 001 = 4 cycles - * 010 = 8 cycles - * 011 = 16 cycles - * 100 = 32 cycles - * 101 = 64 cycles - * 110 = 128 cycles - * 111 = 256 cycles - * [19:19] Dynamic Idle Cycle Center Enable - * 0 = Use Idle Cycle Limit - * 1 = Generate a dynamic Idle cycle limit - * [22:20] DRAM MEMCLK Frequency - * 000 = 100Mhz - * 001 = reserved - * 010 = 133Mhz - * 011 = reserved - * 100 = reserved - * 101 = 166Mhz - * 110 = reserved - * 111 = reserved - * [24:23] Reserved - * [25:25] Memory Clock Ratio Valid (FIXME carefully enable memclk) - * 0 = Disable MemClks - * 1 = Enable MemClks - * [26:26] Memory Clock 0 Enable - * 0 = Disabled - * 1 = Enabled - * [27:27] Memory Clock 1 Enable - * 0 = Disabled - * 1 = Enabled - * [28:28] Memory Clock 2 Enable - * 0 = Disabled - * 1 = Enabled - * [29:29] Memory Clock 3 Enable - * 0 = Disabled - * 1 = Enabled - * [31:30] Reserved - */ - PCI_ADDR(0, 0x18, 2, 0x94), 0xc180f0f0, - (0 << 29)|(0 << 28)|(0 << 27)|(0 << 26)|(0 << 25)| - (0 << 20)|(0 << 19)|(DCH_IDLE_LIMIT_16 << 16)|(0 << 8)|(0 << 0), - /* DRAM Delay Line Register - * F2:0x98 - * Adjust the skew of the input DQS strobe relative to DATA - * [15: 0] Reserved - * [23:16] Delay Line Adjust - * Adjusts the DLL derived PDL delay by one or more delay stages - * in either the faster or slower direction. - * [24:24} Adjust Slower - * 0 = Do Nothing - * 1 = Adj is used to increase the PDL delay - * [25:25] Adjust Faster - * 0 = Do Nothing - * 1 = Adj is used to decrease the PDL delay - * [31:26] Reserved - */ - PCI_ADDR(0, 0x18, 2, 0x98), 0xfc00ffff, 0x00000000, - /* DRAM Scrub Control Register - * F3:0x58 - * [ 4: 0] DRAM Scrube Rate - * [ 7: 5] reserved - * [12: 8] L2 Scrub Rate - * [15:13] reserved - * [20:16] Dcache Scrub - * [31:21] reserved - * Scrub Rates - * 00000 = Do not scrub - * 00001 = 40.00 ns - * 00010 = 80.00 ns - * 00011 = 160.00 ns - * 00100 = 320.00 ns - * 00101 = 640.00 ns - * 00110 = 1.28 us - * 00111 = 2.56 us - * 01000 = 5.12 us - * 01001 = 10.20 us - * 01011 = 41.00 us - * 01100 = 81.90 us - * 01101 = 163.80 us - * 01110 = 327.70 us - * 01111 = 655.40 us - * 10000 = 1.31 ms - * 10001 = 2.62 ms - * 10010 = 5.24 ms - * 10011 = 10.49 ms - * 10100 = 20.97 ms - * 10101 = 42.00 ms - * 10110 = 84.00 ms - * All Others = Reserved - */ - PCI_ADDR(0, 0x18, 3, 0x58), 0xffe0e0e0, 0x00000000, - /* DRAM Scrub Address Low Register - * F3:0x5C - * [ 0: 0] DRAM Scrubber Redirect Enable - * 0 = Do nothing - * 1 = Scrubber Corrects errors found in normal operation - * [ 5: 1] Reserved - * [31: 6] DRAM Scrub Address 31-6 - */ - PCI_ADDR(0, 0x18, 3, 0x5C), 0x0000003e, 0x00000000, - /* DRAM Scrub Address High Register - * F3:0x60 - * [ 7: 0] DRAM Scrubb Address 39-32 - * [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, +// Set to 1 if your DIMMs are CL=2 +#ifndef DIMM_CL2 +#define DIMM_CL2 0 #endif - }; - int i; - int max; - print_debug("setting up CPU"); - print_debug_hex8(ctrl->node_id); - print_debug(" 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"); -#endif - dev = (register_values[i] & ~0xff) - PCI_DEV(0, 0x18, 0) + ctrl->f0; - where = register_values[i] & 0xff; - reg = pci_read_config32(dev, where); - reg &= register_values[i+1]; - reg |= register_values[i+2]; - pci_write_config32(dev, where, reg); -#if 0 - reg = pci_read_config32(register_values[i]); - reg &= register_values[i+1]; - reg |= register_values[i+2]; - pci_write_config32(register_values[i], reg); -#endif - } - print_debug("done.\r\n"); -} - -static int is_dual_channel(const struct mem_controller *ctrl) -{ - uint32_t dcl; - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - return dcl & DCL_128BitEn; -} - -static int is_opteron(const struct mem_controller *ctrl) -{ - /* Test to see if I am an Opteron. - * FIXME Testing dual channel capability is correct for now - * but a beter test is probably required. - */ -#warning "FIXME implement a better test for opterons" - uint32_t nbcap; - nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP); - return !!(nbcap & NBCAP_128Bit); -} - -static int is_registered(const struct mem_controller *ctrl) -{ - /* Test to see if we are dealing with registered SDRAM. - * If we are not registered we are unbuffered. - * This function must be called after spd_handle_unbuffered_dimms. - */ - uint32_t dcl; - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - return !(dcl & DCL_UnBufDimm); -} - -struct dimm_size { - unsigned long side1; - unsigned long side2; -}; - -static struct dimm_size spd_get_dimm_size(unsigned device) -{ - /* Calculate the log base 2 size of a DIMM in bits */ - struct dimm_size sz; - int value, low; - sz.side1 = 0; - sz.side2 = 0; - - /* Note it might be easier to use byte 31 here, it has the DIMM size as - * a multiple of 4MB. The way we do it now we can size both - * sides of an assymetric dimm. - */ - value = spd_read_byte(device, 3); /* rows */ - if (value < 0) goto out; - sz.side1 += value & 0xf; - - value = spd_read_byte(device, 4); /* columns */ - if (value < 0) goto out; - sz.side1 += value & 0xf; - - value = spd_read_byte(device, 17); /* banks */ - if (value < 0) goto out; - 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; - value &= 0xff; - value <<= 8; - - low = spd_read_byte(device, 6); /* (low byte) */ - if (low < 0) goto out; - value = value | (low & 0xff); - sz.side1 += log2(value); - - /* side 2 */ - value = spd_read_byte(device, 5); /* number of physical banks */ - if (value <= 1) goto out; - - /* Start with the symmetrical case */ - sz.side2 = sz.side1; - - value = spd_read_byte(device, 3); /* rows */ - if (value < 0) goto out; - 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; - sz.side2 -= (value & 0x0f); /* Subtract out columns on side 1 */ - sz.side2 += ((value >> 4) & 0x0f); /* Add in columsn on side 2 */ - - out: - return sz; -} - -static void set_dimm_size(const struct mem_controller *ctrl, struct dimm_size sz, unsigned index) -{ - 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; - } - map = pci_read_config32(ctrl->f2, DRAM_BANK_ADDR_MAP); - map &= ~(0xf << (index + 4)); - - /* For each base register. - * Place the dimm size in 32 MB quantities in the bits 31 - 21. - * The initialize dimm size is in bits. - * Set the base enable bit0. - */ - - base0 = base1 = 0; - - /* Make certain side1 of the dimm is at least 32MB */ - if (sz.side1 >= (25 +3)) { - map |= (sz.side1 - (25 + 3)) << (index *4); - base0 = (1 << ((sz.side1 - (25 + 3)) + 21)) | 1; - } - /* Make certain side2 of the dimm is at least 32MB */ - if (sz.side2 >= (25 + 3)) { - base1 = (1 << ((sz.side2 - (25 + 3)) + 21)) | 1; - } - - /* Double the size if we are using dual channel memory */ - if (is_dual_channel(ctrl)) { - base0 = (base0 << 1) | (base0 & 1); - base1 = (base1 << 1) | (base1 & 1); - } - - /* Clear the reserved bits */ - base0 &= ~0x001ffffe; - base1 &= ~0x001ffffe; - - /* Set the appropriate DIMM base address register */ - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+0)<<2), base0); - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+1)<<2), base1); - pci_write_config32(ctrl->f2, DRAM_BANK_ADDR_MAP, map); - - /* Enable the memory clocks for this DIMM */ - if (base0) { - dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - dch |= DCH_MEMCLK_EN0 << index; - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch); - } -} - -static void spd_set_ram_size(const struct mem_controller *ctrl) -{ - int i; - - for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { - struct dimm_size sz; - sz = spd_get_dimm_size(ctrl->channel0[i]); - set_dimm_size(ctrl, sz, i); - } -} - -//BY LYH //Fill next base reg with right value -static void fill_last(unsigned long node_id,unsigned long base) -{ - unsigned i; - unsigned base_reg; - base &=0xffff0000; - device_t device; - for(device = PCI_DEV(0, 0x18, 1); device <= PCI_DEV(0, 0x1f, 1); device -+= PCI_DEV(0, 1, 0)) { - for(i=node_id+1;i<=7;i++) { - base_reg=0x40+(i<<3); - pci_write_config32(device,base_reg,base); - } - } -} -//BY LYH END - -static void route_dram_accesses(const struct mem_controller *ctrl, - unsigned long base_k, unsigned long limit_k) -{ - /* Route the addresses to the controller node */ - unsigned node_id; - unsigned limit; - unsigned base; - unsigned index; - unsigned limit_reg, base_reg; - device_t device; - - node_id = ctrl->node_id; - index = (node_id << 3); - limit = (limit_k << 2); - limit &= 0xffff0000; - limit -= 0x00010000; - limit |= ( 0 << 8) | (node_id << 0); - base = (base_k << 2); - base &= 0xffff0000; - base |= (0 << 8) | (1<<1) | (1<<0); - - limit_reg = 0x44 + index; - base_reg = 0x40 + index; - for(device = PCI_DEV(0, 0x18, 1); device <= PCI_DEV(0, 0x1f, 1); device += PCI_DEV(0, 1, 0)) { - pci_write_config32(device, limit_reg, limit); - pci_write_config32(device, base_reg, base); - } -} - -static void set_top_mem(unsigned tom_k) -{ - /* Error if I don't have memory */ - if (!tom_k) { - 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 - - /* Now set top of memory */ - msr_t msr; - msr.lo = (tom_k & 0x003fffff) << 10; - msr.hi = (tom_k & 0xffc00000) >> 22; - wrmsr(TOP_MEM2, msr); - - /* Leave a 64M hole between TOP_MEM and TOP_MEM2 - * so I can see my rom chip and other I/O devices. - */ - if (tom_k >= 0x003f0000) { - tom_k = 0x3f0000; - } - msr.lo = (tom_k & 0x003fffff) << 10; - msr.hi = (tom_k & 0xffc00000) >> 22; - wrmsr(TOP_MEM, msr); -} - -static void order_dimms(const struct mem_controller *ctrl) -{ - unsigned long tom, tom_k, base_k; - unsigned node_id; - - /* Compute the memory base address address */ - base_k = 0; - /* Remember which registers we have used in the high 8 bits of tom */ - tom = base_k >> 15; - for(;;) { - /* Find the largest remaining canidate */ - unsigned index, canidate; - uint32_t csbase, csmask; - unsigned size; - csbase = 0; - canidate = 0; - for(index = 0; index < 8; index++) { - uint32_t value; - value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2)); - - /* Is it enabled? */ - if (!(value & 1)) { - continue; - } - - /* Is it greater? */ - if (value <= csbase) { - continue; - } - - /* Has it already been selected */ - if (tom & (1 << (index + 24))) { - continue; - } - /* I have a new canidate */ - csbase = value; - canidate = index; - } - /* See if I have found a new canidate */ - if (csbase == 0) { - break; - } - - /* Remember the dimm size */ - size = csbase >> 21; - - /* Remember I have used this register */ - tom |= (1 << (canidate + 24)); - - /* Recompute the cs base register value */ - csbase = (tom << 21) | 1; - - /* Increment the top of memory */ - tom += size; - - /* 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); - /* Write the new mask register */ - pci_write_config32(ctrl->f2, DRAM_CSMASK + (canidate << 2), csmask); - - } - tom_k = (tom & ~0xff000000) << 15; - - /* Compute the memory base address */ - base_k = 0; - for(node_id = 0; node_id < ctrl->node_id; node_id++) { - uint32_t limit, base; - unsigned index; - index = node_id << 3; - base = pci_read_config32(ctrl->f1, 0x40 + index); - /* 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; - } - } - tom_k += base_k; -#if 0 - print_debug("tom: "); - print_debug_hex32(tom); - 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); -//BY LYH - fill_last(ctrl->node_id, tom_k<<2); -//BY LYH END - set_top_mem(tom_k); -} - -static void disable_dimm(const struct mem_controller *ctrl, unsigned index) -{ - 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); -} - - -static void spd_handle_unbuffered_dimms(const struct mem_controller *ctrl) -{ - int i; - int registered; - int unbuffered; - uint32_t dcl; - unbuffered = 0; - registered = 0; - for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { - int value; - value = spd_read_byte(ctrl->channel0[i], 21); - if (value < 0) { - disable_dimm(ctrl, i); - continue; - } - /* Registered dimm ? */ - if (value & (1 << 1)) { - registered = 1; - } - /* Otherwise it must be an unbuffered dimm */ - else { - unbuffered = 1; - } - } - if (unbuffered && registered) { - die("Mixed buffered and registered dimms not supported"); - } - if (unbuffered && is_opteron(ctrl)) { - die("Unbuffered Dimms not supported on Opteron"); - } - - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dcl &= ~DCL_UnBufDimm; - if (unbuffered) { - dcl |= DCL_UnBufDimm; - } - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); -#if 0 - if (is_registered(ctrl)) { - print_debug("Registered\r\n"); - } else { - print_debug("Unbuffered\r\n"); - } -#endif -} - -static void spd_enable_2channels(const struct mem_controller *ctrl) -{ - 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 */ - 4, /* *Column addresses */ - 5, /* *Physical Banks */ - 6, /* *Module Data Width low */ - 7, /* *Module Data Width high */ - 9, /* *Cycle time at highest CAS Latency CL=X */ - 11, /* *SDRAM Type */ - 13, /* *SDRAM Width */ - 17, /* *Logical Banks */ - 18, /* *Supported CAS Latencies */ - 21, /* *SDRAM Module Attributes */ - 23, /* *Cycle time at CAS Latnecy (CLX - 0.5) */ - 26, /* *Cycle time at CAS Latnecy (CLX - 1.0) */ - 27, /* *tRP Row precharge time */ - 28, /* *Minimum Row Active to Row Active Delay (tRRD) */ - 29, /* *tRCD RAS to CAS */ - 30, /* *tRAS Activate to Precharge */ - 41, /* *Minimum Active to Active/Auto Refresh Time(Trc) */ - 42, /* *Minimum Auto Refresh Command Time(Trfc) */ - }; - nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP); - if (!(nbcap & NBCAP_128Bit)) { - return; - } - for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { - unsigned device0, device1; - int value0, value1; - int j; - 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; - } - value1 = spd_read_byte(device1, addr); - if (value1 < 0) { - return; - } - if (value0 != value1) { - return; - } - } - } - print_debug("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); -} - -struct mem_param { - uint8_t cycle_time; - uint8_t divisor; /* In 1/2 ns increments */ - uint8_t tRC; - uint8_t tRFC; - uint32_t dch_memclk; - uint16_t dch_tref4k, dch_tref8k; - uint8_t dtl_twr; - char name[9]; -}; - -static const struct mem_param *get_mem_param(unsigned min_cycle_time) -{ - static const struct mem_param speed[] = { - { - .name = "100Mhz\r\n", - .cycle_time = 0xa0, - .divisor = (10 <<1), - .tRC = 0x46, - .tRFC = 0x50, - .dch_memclk = DCH_MEMCLK_100MHZ << DCH_MEMCLK_SHIFT, - .dch_tref4k = DTH_TREF_100MHZ_4K, - .dch_tref8k = DTH_TREF_100MHZ_8K, - .dtl_twr = 2, - }, - { - .name = "133Mhz\r\n", - .cycle_time = 0x75, - .divisor = (7<<1)+1, - .tRC = 0x41, - .tRFC = 0x4B, - .dch_memclk = DCH_MEMCLK_133MHZ << DCH_MEMCLK_SHIFT, - .dch_tref4k = DTH_TREF_133MHZ_4K, - .dch_tref8k = DTH_TREF_133MHZ_8K, - .dtl_twr = 2, - }, - { - .name = "166Mhz\r\n", - .cycle_time = 0x60, - .divisor = (6<<1), - .tRC = 0x3C, - .tRFC = 0x48, - .dch_memclk = DCH_MEMCLK_166MHZ << DCH_MEMCLK_SHIFT, - .dch_tref4k = DTH_TREF_166MHZ_4K, - .dch_tref8k = DTH_TREF_166MHZ_8K, - .dtl_twr = 3, - }, - { - .name = "200Mhz\r\n", - .cycle_time = 0x50, - .divisor = (5<<1), - .tRC = 0x37, - .tRFC = 0x46, - .dch_memclk = DCH_MEMCLK_200MHZ << DCH_MEMCLK_SHIFT, - .dch_tref4k = DTH_TREF_200MHZ_4K, - .dch_tref8k = DTH_TREF_200MHZ_8K, - .dtl_twr = 3, - }, - { - .cycle_time = 0x00, - }, - }; - const struct mem_param *param; - for(param = &speed[0]; param->cycle_time ; param++) { - if (min_cycle_time > (param+1)->cycle_time) { - break; - } - } - if (!param->cycle_time) { - die("min_cycle_time to low"); - } -#if 1 - print_debug(param->name); +/* Stable ~1 usec delay by hitting unused ISA port. */ +#define UDELAY(x) movl $x,%ecx; 9: outb %al,$0x81; loop 9b + +#define DIMMS_READ(x) \ + movl 0x00000000+x, %eax; \ + movl 0x10000000+x, %eax; \ + movl 0x20000000+x, %eax; \ + movl 0x30000000+x, %eax; \ + movl 0x40000000+x, %eax; \ + movl 0x50000000+x, %eax + +#define DIMMS_WRITE(x) \ + movl %eax, 0x00000000+x; \ + movl %eax, 0x10000000+x; \ + movl %eax, 0x20000000+x; \ + movl %eax, 0x30000000+x; \ + movl %eax, 0x40000000+x; \ + movl %eax, 0x50000000+x + +raminit: + intel_chip_post_macro(0x35) + + // memory clk enable. We are not using ECC + CS_WRITE($0x78, $0x01) + // dram control, see the book. +#if DIMM_PC133 + CS_WRITE($0x68, $0x52) +#else + CS_WRITE($0x68, $0x42) #endif - return param; -} - -static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl) -{ - /* Compute the minimum cycle time for these dimms */ - const struct mem_param *param; - unsigned min_cycle_time, min_latency; - int i; - uint32_t value; - - static const int latency_indicies[] = { 26, 23, 9 }; - static const unsigned char min_cycle_times[] = { - [NBCAP_MEMCLK_200MHZ] = 0x50, /* 5ns */ - [NBCAP_MEMCLK_166MHZ] = 0x60, /* 6ns */ - [NBCAP_MEMCLK_133MHZ] = 0x75, /* 7.5ns */ - [NBCAP_MEMCLK_100MHZ] = 0xa0, /* 10ns */ - }; - - - value = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP); - min_cycle_time = min_cycle_times[(value >> NBCAP_MEMCLK_SHIFT) & NBCAP_MEMCLK_MASK]; - 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"); + // dram control, see the book. + CS_WRITE($0x6B, $0x0c) + // Initial setting, 256MB in each bank, will be rewritten later. + CS_WRITE($0x5A, $0x20) + CS_WRITE($0x5B, $0x40) + CS_WRITE($0x5C, $0x60) + CS_WRITE($0x5D, $0x80) + CS_WRITE($0x5E, $0xA0) + CS_WRITE($0x5F, $0xC0) + // It seems we have to take care of these 2 registers as if + // they are bank 6 and 7. + CS_WRITE($0x56, $0xC0) + CS_WRITE($0x57, $0xC0) + + // SDRAM in all banks + CS_WRITE($0x60, $0x3F) + // DRAM timing. I'm suspicious of this + // This is for all banks, 64 is 0,1. 65 is 2,3. 66 is 4,5. + // ras precharge 4T, RAS pulse 5T + // cas2 is 0xd6, cas3 is 0xe6 + // we're also backing off write pulse width to 2T, so result is 0xee +#if DIMM_CL2 + CS_WRITE($0x64, $0xd4) + CS_WRITE($0x65, $0xd4) + CS_WRITE($0x66, $0xd4) +#else // CL=3 + CS_WRITE($0x64, $0xe4) + CS_WRITE($0x65, $0xe4) + CS_WRITE($0x66, $0xe4) #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++) { - int new_cycle_time, new_latency; - int index; - int latencies; - int latency; - - /* First find the supported CAS latencies - * Byte 18 for DDR SDRAM is interpreted: - * bit 0 == CAS Latency = 1.0 - * bit 1 == CAS Latency = 1.5 - * bit 2 == CAS Latency = 2.0 - * bit 3 == CAS Latency = 2.5 - * bit 4 == CAS Latency = 3.0 - * bit 5 == CAS Latency = 3.5 - * bit 6 == TBD - * bit 7 == TBD - */ - new_cycle_time = 0xa0; - new_latency = 5; - - latencies = spd_read_byte(ctrl->channel0[i], 18); - if (latencies <= 0) continue; - - /* Compute the lowest cas latency supported */ - latency = log2(latencies) -2; - - /* Loop through and find a fast clock with a low latency */ - for(index = 0; index < 3; index++, latency++) { - int value; - if ((latency < 2) || (latency > 4) || - (!(latencies & (1 << latency)))) { - continue; - } - value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]); - if (value < 0) { - continue; - } - - /* Only increase the latency if we decreas the clock */ - if ((value >= min_cycle_time) && (value < new_cycle_time)) { - new_cycle_time = value; - new_latency = latency; - } - } - if (new_latency > 4){ - continue; - } - /* Does min_latency need to be increased? */ - if (new_cycle_time > min_cycle_time) { - min_cycle_time = new_cycle_time; - } - /* Does min_cycle_time need to be increased? */ - 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"); + // dram frequency select. + // enable 4K pages for 64M dram. +#if DIMM_PC133 + CS_WRITE($0x69, $0x3c) +#else + CS_WRITE($0x69, $0xac) #endif - } - /* Make a second pass through the dimms and disable - * any that cannot support the selected memclk and cas latency. - */ + // refresh counter, disabled. + CS_WRITE($0x6A, $0x00) + // clkenable configuration. kevinh FIXME - add precharge + CS_WRITE($0x6C, $0x00) + // dram read latch delay of 1 ns, MD drive 8 mA, + // high drive strength on MA[2: 13], we#, cas#, ras# + // As per Cindy Lee, set to 0x37, not 0x57 + CS_WRITE($0x6D, $0x7f) + + /* Initialize all banks at once */ + +/* begin to initialize*/ + // I forget why we need this, but we do + mov $0xa55a5aa5, %eax + DIMMS_WRITE(0) - for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { - int latencies; - int latency; - int index; - int value; - int dimm; - latencies = spd_read_byte(ctrl->channel0[i], 18); - if (latencies <= 0) { - goto dimm_err; - } +/* set NOP*/ + CS_WRITE($0x6C, $0x01) - /* Compute the lowest cas latency supported */ - latency = log2(latencies) -2; +/* wait 200us*/ + // You need to do the memory reference. That causes the nop cycle. + DIMMS_READ(0) + UDELAY(400) - /* Walk through searching for the selected latency */ - for(index = 0; index < 3; index++, latency++) { - if (!(latencies & (1 << latency))) { - continue; - } - if (latency == min_latency) - break; - } - /* If I can't find the latency or my index is bad error */ - if ((latency != min_latency) || (index >= 3)) { - goto dimm_err; - } - - /* Read the min_cycle_time for this latency */ - value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]); - - /* All is good if the selected clock speed - * is what I need or slower. - */ - if (value <= min_cycle_time) { - continue; - } - /* Otherwise I have an error, disable the dimm */ - dimm_err: - disable_dimm(ctrl, i); - } -#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); +/* set precharge */ + CS_WRITE($0x6C, $0x02) - /* 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; - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, value); +/* dummy reads*/ + DIMMS_READ(0) + UDELAY(200) - static const unsigned latencies[] = { DTL_CL_2, DTL_CL_2_5, DTL_CL_3 }; - /* Update DRAM Timing Low with our selected cas latency */ - value = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - value &= ~(DTL_TCL_MASK << DTL_TCL_SHIFT); - value |= latencies[min_latency - 2] << DTL_TCL_SHIFT; - pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, value); +/* set CBR*/ + CS_WRITE($0x6C, $0x04) - return param; -} - - -static int update_dimm_Trc(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - unsigned clocks, old_clocks; - uint32_t dtl; - int value; - value = spd_read_byte(ctrl->channel0[i], 41); - if (value < 0) return -1; - if ((value == 0) || (value == 0xff)) { - value = param->tRC; - } - clocks = ((value << 1) + param->divisor - 1)/param->divisor; - if (clocks < DTL_TRC_MIN) { - clocks = DTL_TRC_MIN; - } - if (clocks > DTL_TRC_MAX) { - return -1; - } - - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - old_clocks = ((dtl >> DTL_TRC_SHIFT) & DTL_TRC_MASK) + DTL_TRC_BASE; - if (old_clocks > clocks) { - clocks = old_clocks; - } - 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; -} - -static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - unsigned clocks, old_clocks; - uint32_t dtl; - int value; - value = spd_read_byte(ctrl->channel0[i], 42); - if (value < 0) return -1; - if ((value == 0) || (value == 0xff)) { - value = param->tRFC; - } - clocks = ((value << 1) + param->divisor - 1)/param->divisor; - if (clocks < DTL_TRFC_MIN) { - clocks = DTL_TRFC_MIN; - } - if (clocks > DTL_TRFC_MAX) { - return -1; - } - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - old_clocks = ((dtl >> DTL_TRFC_SHIFT) & DTL_TRFC_MASK) + DTL_TRFC_BASE; - if (old_clocks > clocks) { - clocks = old_clocks; - } - 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; -} - - -static int update_dimm_Trcd(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - unsigned clocks, old_clocks; - uint32_t dtl; - 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); +/* do 8 reads and wait >100us between each - from via*/ + DIMMS_READ(0) + UDELAY(200) + DIMMS_READ(0) + UDELAY(200) + DIMMS_READ(0) + UDELAY(200) + DIMMS_READ(0) + UDELAY(200) + DIMMS_READ(0) + UDELAY(200) + DIMMS_READ(0) + UDELAY(200) + DIMMS_READ(0) + UDELAY(200) + DIMMS_READ(0) + UDELAY(200) + +/* set MRS*/ + CS_WRITE($0x6c, $0x03) +#if DIMM_CL2 + DIMMS_READ(0x150) +#else // CL=3 + DIMMS_READ(0x1d0) #endif - if (clocks < DTL_TRCD_MIN) { - clocks = DTL_TRCD_MIN; - } - if (clocks > DTL_TRCD_MAX) { - return -1; - } - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - old_clocks = ((dtl >> DTL_TRCD_SHIFT) & DTL_TRCD_MASK) + DTL_TRCD_BASE; - if (old_clocks > clocks) { - clocks = old_clocks; - } - 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; -} - -static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - unsigned clocks, old_clocks; - uint32_t dtl; - 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); - if (clocks < DTL_TRRD_MIN) { - clocks = DTL_TRRD_MIN; - } - if (clocks > DTL_TRRD_MAX) { - return -1; - } - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - old_clocks = ((dtl >> DTL_TRRD_SHIFT) & DTL_TRRD_MASK) + DTL_TRRD_BASE; - if (old_clocks > clocks) { - clocks = old_clocks; - } - 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; -} - -static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - unsigned clocks, old_clocks; - uint32_t dtl; - int value; - value = spd_read_byte(ctrl->channel0[i], 30); - if (value < 0) return -1; - clocks = ((value << 1) + param->divisor - 1)/param->divisor; - if (clocks < DTL_TRAS_MIN) { - clocks = DTL_TRAS_MIN; - } - if (clocks > DTL_TRAS_MAX) { - return -1; - } - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - old_clocks = ((dtl >> DTL_TRAS_SHIFT) & DTL_TRAS_MASK) + DTL_TRAS_BASE; - if (old_clocks > clocks) { - clocks = old_clocks; - } - 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; -} - -static int update_dimm_Trp(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - unsigned clocks, old_clocks; - uint32_t dtl; - 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); + UDELAY(200) + +/* set to normal mode */ + CS_WRITE($0x6C, $0x08) + movl $0x55aa55aa, %eax + DIMMS_WRITE(0) + DIMMS_READ(0) + UDELAY(200) + + // Set the refresh rate. +#if DIMM_PC133 + CS_WRITE($0x6A, $0x86) #else - clocks = (value + ((param->divisor & 0xff) << 1) - 1)/((param->divisor & 0xff) << 1); + CS_WRITE($0x6A, $0x65) #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"); + // enable multi-page open + CS_WRITE($0x6B, $0x0d) + + /* Begin auto-detection + * Find the first bank with DIMM equipped. */ + + /* Maximum possible memory in bank 0, none in other banks. + * Starting from bank 0, we's fill 0 in these registers + * until memory is found. */ + CS_WRITE($0x5A, $0xff) + CS_WRITE($0x5B, $0xff) + CS_WRITE($0x5C, $0xff) + CS_WRITE($0x5D, $0xff) + CS_WRITE($0x5E, $0xff) + CS_WRITE($0x5F, $0xff) + CS_WRITE($0x56, $0xff) + CS_WRITE($0x57, $0xff) + + movl $0x5A, %ebx // first bank +1: + /* Write different values to 0 and 8, then read from 0. + * If values of address 0 match, we have something there. */ + movl $0x12345678, %eax + movl %eax, 0 + movl $0x87654321, %edx + movl %edx, 8 + movl 0, %edx + cmpl %eax, %edx + je 2f + /* No memory in this bank. Tell it to the bridge. */ + movl %ebx, %eax + xorl %edx, %edx + PCI_WRITE_CONFIG_BYTE + incl %ebx + cmpl $0x60, %ebx + jne 1b + /* No memory at all! */ + CONSOLE_EMERG_TX_STRING($msg_nomem) +1: + hlt + jmp 1b +2: + + /* Detect MA mapping type of the first bank. */ + + jmp raminit_ma +raminit_ma_reg_table: + /* Values for MA type register to try */ + .word 0x0000, 0x8088, 0xe0ee + .word 0xffff // end mark + +raminit_ma: + xorl %esi, %esi // highest address + movl $raminit_ma_reg_table, %ebx +1: + movw (%ebx), %cx + cmpw $0xffff, %cx + je raminit_ma_done + movl $0x58, %eax + PCI_WRITE_CONFIG_WORD + + xorl %eax, %eax + movl %eax, (%eax) + + // Write to addresses with only one address bit on, + // from 0x80000000 to 0x00000008 (lower 3 bits are ignored, assuming + // 64-bit bus). + // Then what is read at address 0 is the value written to the lowest + // address where it gets wrap-around. That address is either the size + // of the bank, or a missing bit due to incorrect MA mapping. + movl $0x80000000, %eax +2: + movl %eax, (%eax) + shrl $1, %eax + cmpl $4, %eax + jne 2b + + movl 0, %eax + cmpl %eax, %esi + jnc 3f + + // This is the current best MA mapping. + // Save the address and its MA mapping value. + movl %eax, %esi + movl %ecx, %edi +3: + incl %ebx + incl %ebx + jmp 1b + + +raminit_ma_done: + // Set the best (hopefully correct) MA mapping type. + movl $0x58, %eax + movl %edi, %ecx + PCI_WRITE_CONFIG_WORD + + CONSOLE_DEBUG_TX_STRING($msg_enabled) + CONSOLE_DEBUG_TX_HEX32(%esi) + CONSOLE_DEBUG_TX_STRING($msg_bytes) + + /* + * We have the size of first bank in %esi, but throwing it away. + * Sizing will again be done in C, because we'll configure the rest + * of banks in there anyway. + */ + + //CALLSP(dumpnorth) + + intel_chip_post_macro(0x36) + + + .section ".rom.data" +msg_nomem: + .asciz "No memory\r\n" +msg_enabled: + .asciz "Enabled first bank of RAM: 0x" +msg_bytes: + .asciz " bytes\r\n" + .previous #endif - if (clocks < DTL_TRP_MIN) { - clocks = DTL_TRP_MIN; - } - if (clocks > DTL_TRP_MAX) { - return -1; - } - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - old_clocks = ((dtl >> DTL_TRP_SHIFT) & DTL_TRP_MASK) + DTL_TRP_BASE; - if (old_clocks > clocks) { - clocks = old_clocks; - } - 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; -} - -static void set_Twr(const struct mem_controller *ctrl, const struct mem_param *param) -{ - uint32_t dtl; - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - dtl &= ~(DTL_TWR_MASK << DTL_TWR_SHIFT); - dtl |= (param->dtl_twr - DTL_TWR_BASE) << DTL_TWR_SHIFT; - pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); -} - -static void init_Tref(const struct mem_controller *ctrl, const struct mem_param *param) -{ - uint32_t dth; - dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH); - dth &= ~(DTH_TREF_MASK << DTH_TREF_SHIFT); - dth |= (param->dch_tref4k << DTH_TREF_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth); +static void sdram_set_registers(const struct mem_controller *ctrl) { } -static int update_dimm_Tref(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - uint32_t dth; - int value; - unsigned tref, old_tref; - value = spd_read_byte(ctrl->channel0[i], 3); - if (value < 0) return -1; - value &= 0xf; - - tref = param->dch_tref8k; - if (value == 12) { - tref = param->dch_tref4k; - } - - dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH); - old_tref = (dth >> DTH_TREF_SHIFT) & DTH_TREF_MASK; - if ((value == 12) && (old_tref == param->dch_tref4k)) { - tref = param->dch_tref4k; - } else { - tref = param->dch_tref8k; - } - dth &= ~(DTH_TREF_MASK << DTH_TREF_SHIFT); - dth |= (tref << DTH_TREF_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth); - return 0; -} - - -static int update_dimm_x4(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - uint32_t dcl; - int value; - int dimm; - value = spd_read_byte(ctrl->channel0[i], 13); - if (value < 0) { - return -1; - } - dimm = i; - dimm += DCL_x4DIMM_SHIFT; - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dcl &= ~(1 << dimm); - if (value == 4) { - dcl |= (1 << dimm); - } - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - return 0; -} - -static int update_dimm_ecc(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - uint32_t dcl; - int value; - value = spd_read_byte(ctrl->channel0[i], 11); - if (value < 0) { - return -1; - } - if (value != 2) { - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dcl &= ~DCL_DimmEccEn; - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - } - return 0; -} - -static int count_dimms(const struct mem_controller *ctrl) -{ - int dimms; - unsigned index; - dimms = 0; - for(index = 0; index < 8; index += 2) { - uint32_t csbase; - csbase = pci_read_config32(ctrl->f2, (DRAM_CSBASE + index << 2)); - if (csbase & 1) { - dimms += 1; - } - } - return dimms; -} - -static void set_Twtr(const struct mem_controller *ctrl, const struct mem_param *param) -{ - uint32_t dth; - unsigned clocks; - clocks = 1; /* AMD says hard code this */ - dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH); - dth &= ~(DTH_TWTR_MASK << DTH_TWTR_SHIFT); - dth |= ((clocks - DTH_TWTR_BASE) << DTH_TWTR_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth); -} - -static void set_Trwt(const struct mem_controller *ctrl, const struct mem_param *param) -{ - uint32_t dth, dtl; - unsigned divisor; - unsigned latency; - unsigned clocks; - - clocks = 0; - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - latency = (dtl >> DTL_TCL_SHIFT) & DTL_TCL_MASK; - divisor = param->divisor; - - if (is_opteron(ctrl)) { - if (latency == DTL_CL_2) { - if (divisor == ((6 << 0) + 0)) { - /* 166Mhz */ - clocks = 3; - } - else if (divisor > ((6 << 0)+0)) { - /* 100Mhz && 133Mhz */ - clocks = 2; - } - } - else if (latency == DTL_CL_2_5) { - clocks = 3; - } - else if (latency == DTL_CL_3) { - if (divisor == ((6 << 0)+0)) { - /* 166Mhz */ - clocks = 4; - } - else if (divisor > ((6 << 0)+0)) { - /* 100Mhz && 133Mhz */ - clocks = 3; - } - } - } - else /* Athlon64 */ { - if (is_registered(ctrl)) { - if (latency == DTL_CL_2) { - clocks = 2; - } - else if (latency == DTL_CL_2_5) { - clocks = 3; - } - else if (latency == DTL_CL_3) { - clocks = 3; - } - } - else /* Unbuffered */{ - if (latency == DTL_CL_2) { - clocks = 3; - } - else if (latency == DTL_CL_2_5) { - clocks = 4; - } - else if (latency == DTL_CL_3) { - clocks = 4; - } - } - } - if ((clocks < DTH_TRWT_MIN) || (clocks > DTH_TRWT_MAX)) { - die("Unknown Trwt"); - } - - dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH); - dth &= ~(DTH_TRWT_MASK << DTH_TRWT_SHIFT); - dth |= ((clocks - DTH_TRWT_BASE) << DTH_TRWT_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth); - return; -} - -static void set_Twcl(const struct mem_controller *ctrl, const struct mem_param *param) -{ - /* Memory Clocks after CAS# */ - uint32_t dth; - unsigned clocks; - if (is_registered(ctrl)) { - clocks = 2; - } else { - clocks = 1; - } - dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH); - dth &= ~(DTH_TWCL_MASK << DTH_TWCL_SHIFT); - dth |= ((clocks - DTH_TWCL_BASE) << DTH_TWCL_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth); -} - - -static void set_read_preamble(const struct mem_controller *ctrl, const struct mem_param *param) -{ - uint32_t dch; - unsigned divisor; - unsigned rdpreamble; - divisor = param->divisor; - dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - dch &= ~(DCH_RDPREAMBLE_MASK << DCH_RDPREAMBLE_SHIFT); - rdpreamble = 0; - if (is_registered(ctrl)) { - if (divisor == ((10 << 1)+0)) { - /* 100Mhz, 9ns */ - rdpreamble = ((9 << 1)+ 0); - } - else if (divisor == ((7 << 1)+1)) { - /* 133Mhz, 8ns */ - rdpreamble = ((8 << 1)+0); - } - else if (divisor == ((6 << 1)+0)) { - /* 166Mhz, 7.5ns */ - rdpreamble = ((7 << 1)+1); - } - } - else { - int slots; - int i; - slots = 0; - for(i = 0; i < 4; i++) { - if (ctrl->channel0[i]) { - slots += 1; - } - } - if (divisor == ((10 << 1)+0)) { - /* 100Mhz */ - if (slots <= 2) { - /* 9ns */ - rdpreamble = ((9 << 1)+0); - } else { - /* 14ns */ - rdpreamble = ((14 << 1)+0); - } - } - else if (divisor == ((7 << 1)+1)) { - /* 133Mhz */ - if (slots <= 2) { - /* 7ns */ - rdpreamble = ((7 << 1)+0); - } else { - /* 11 ns */ - rdpreamble = ((11 << 1)+0); - } - } - else if (divisor == ((6 << 1)+0)) { - /* 166Mhz */ - if (slots <= 2) { - /* 6ns */ - rdpreamble = ((7 << 1)+0); - } else { - /* 9ns */ - rdpreamble = ((9 << 1)+0); - } - } - else if (divisor == ((5 << 1)+0)) { - /* 200Mhz */ - if (slots <= 2) { - /* 5ns */ - rdpreamble = ((5 << 1)+0); - } else { - /* 7ns */ - rdpreamble = ((7 << 1)+0); - } - } - } - if ((rdpreamble < DCH_RDPREAMBLE_MIN) || (rdpreamble > DCH_RDPREAMBLE_MAX)) { - die("Unknown rdpreamble"); - } - dch |= (rdpreamble - DCH_RDPREAMBLE_BASE) << DCH_RDPREAMBLE_SHIFT; - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch); -} - -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; - - dimms = count_dimms(ctrl); - - dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - dch &= ~(DCH_ASYNC_LAT_MASK << DCH_ASYNC_LAT_SHIFT); - async_lat = 0; - if (is_registered(ctrl)) { - if (dimms == 4) { - /* 9ns */ - async_lat = 9; - } - else { - /* 8ns */ - async_lat = 8; - } - } - else { - if (dimms > 3) { - die("Too many unbuffered dimms"); - } - else if (dimms == 3) { - /* 7ns */ - async_lat = 7; - } - else { - /* 6ns */ - async_lat = 6; - } - } - dch |= ((async_lat - DCH_ASYNC_LAT_BASE) << DCH_ASYNC_LAT_SHIFT); - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch); -} - -static void set_idle_cycle_limit(const struct mem_controller *ctrl, const struct mem_param *param) -{ - uint32_t dch; - /* AMD says to Hardcode this */ - dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - dch &= ~(DCH_IDLE_LIMIT_MASK << DCH_IDLE_LIMIT_SHIFT); - dch |= DCH_IDLE_LIMIT_16 << DCH_IDLE_LIMIT_SHIFT; - dch |= DCH_DYN_IDLE_CTR_EN; - 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) -{ - int dimms; - int i; - init_Tref(ctrl, param); - for(i = 0; (i < 4) && ctrl->channel0[i]; i++) { - int rc; - /* 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; - - /* DRAM Timing High Register */ - if (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; - continue; - dimm_err: - disable_dimm(ctrl, i); - - } - /* DRAM Timing Low Register */ - set_Twr(ctrl, param); - - /* DRAM Timing High Register */ - set_Twtr(ctrl, param); - set_Trwt(ctrl, param); - set_Twcl(ctrl, param); - - /* DRAM Config High */ - set_read_preamble(ctrl, param); - set_max_async_latency(ctrl, param); - set_idle_cycle_limit(ctrl, param); +static void sdram_set_spd_registers(const struct mem_controller *ctrl) { } -static void sdram_set_spd_registers(const struct mem_controller *ctrl) -{ - const struct mem_param *param; - 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); - order_dimms(ctrl); -} - -#define TIMEOUT_LOOPS 300000 -static void sdram_enable(int controllers, const struct mem_controller *ctrl) -{ - int i; - - /* 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); - } - - /* And if necessary toggle the the reset on the dimms by hand */ - memreset(controllers, ctrl); - - for(i = 0; i < controllers; i++) { - uint32_t dcl; - /* 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 -#warning "FIXME set the ECC type to perform" -#warning "FIXME initialize the scrub registers" -#if 1 - if (dcl & DCL_DimmEccEn) { - print_debug("ECC enabled\r\n"); - } -#endif - dcl |= DCL_DisDqsHys; - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); - dcl &= ~DCL_DisDqsHys; - dcl &= ~DCL_DLL_Disable; - dcl &= ~DCL_D_DRV; - dcl &= ~DCL_QFC_EN; - dcl |= DCL_DramInit; - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); - - } - for(i = 0; i < controllers; i++) { - uint32_t dcl; - print_debug("Initializing memory: "); - int loops = 0; - do { - dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); - loops += 1; - if ((loops & 1023) == 0) { - print_debug("."); - } - } while(((dcl & DCL_DramInit) != 0) && (loops < TIMEOUT_LOOPS)); - if (loops >= TIMEOUT_LOOPS) { - print_debug(" failed\r\n"); - } else { - print_debug(" done\r\n"); - } -#if 0 - if (dcl & DCL_DimmEccEn) { - print_debug("Clearing memory: "); - loops = 0; - dcl &= ~DCL_MemClrStatus; - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); - - do { - dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); - loops += 1; - if ((loops & 1023) == 0) { - print_debug(" "); - print_debug_hex32(loops); - } - } while(((dcl & DCL_MemClrStatus) == 0) && (loops < TIMEOUT_LOOPS)); - if (loops >= TIMEOUT_LOOPS) { - print_debug("failed\r\n"); - } else { - print_debug("done\r\n"); - } - pci_write_config32(ctrl[i].f3, SCRUB_ADDR_LOW, 0); - pci_write_config32(ctrl[i].f3, SCRUB_ADDR_HIGH, 0); - } -#endif - } +static void sdram_enable(int controllers, const struct mem_controller *ctrl) { } diff --git a/src/northbridge/via/vt8601/raminit.h b/src/northbridge/via/vt8601/raminit.h index 4d3cdc16ce..a72535de1d 100644 --- a/src/northbridge/via/vt8601/raminit.h +++ b/src/northbridge/via/vt8601/raminit.h @@ -1,4 +1,8 @@ #ifndef RAMINIT_H #define RAMINIT_H +struct mem_controller { + int empty; +}; + #endif /* RAMINIT_H */ diff --git a/src/southbridge/via/vt8231/vt8231_early_smbus.c b/src/southbridge/via/vt8231/vt8231_early_smbus.c new file mode 100644 index 0000000000..44672be310 --- /dev/null +++ b/src/southbridge/via/vt8231/vt8231_early_smbus.c @@ -0,0 +1,114 @@ +#define SMBUS_IO_BASE 0x5000 + +#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 void enable_smbus(void) +{ + device_t dev; + /* Power management controller */ + dev = pci_locate_device(PCI_ID(0x1106,0x8235), 0); + + if (dev == PCI_DEV_INVALID) { + die("SMBUS controller not found\r\n"); + } + + // set IO base address to SMBUS_IO_BASE + pci_write_config32(dev, 0x90, SMBUS_IO_BASE|1); + + // Enable SMBus + pci_write_config8(dev, 0xd2, 0x01); + + + print_debug("SMBus controller enabled\r\n"); +} + + +static inline void smbus_delay(void) +{ + outb(0x80, 0x80); +} + +static int smbus_wait_until_ready(void) +{ + unsigned long loops; + loops = SMBUS_TIMEOUT; + do { + unsigned short val; + smbus_delay(); + val = inw(SMBUS_IO_BASE + SMBGSTATUS); + if ((val & 0x800) == 0) { + break; + } + } while(--loops); + return loops?0:-1; +} + +static int smbus_wait_until_done(void) +{ + 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:-1; +} + +static int smbus_read_byte(unsigned device, unsigned address) +{ + unsigned char global_control_register; + unsigned char global_status_register; + unsigned char byte; + + if (smbus_wait_until_ready() < 0) { + return -1; + } + + /* 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() < 0) { + return -1; + } + + 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; +} |