diff --git a/src/mainboard/intel/Clearwater533/Config b/src/mainboard/intel/Clearwater533/Config new file mode 100644 index 0000000000..bf23fc5a22 --- /dev/null +++ b/src/mainboard/intel/Clearwater533/Config @@ -0,0 +1,296 @@ + +## Set all of the defaults for an x86 architecture +## +arch i386 + +## +## 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 + +## +## Test for logical cpu thats not BSP +## This is hyperthreading! +## it may break! +## +#mainboardinit cpu/i786/logical_cpu.inc + +## +## Build our reset vector (This is where linuxBIOS is entered) +## +mainboardinit cpu/i386/reset16.inc USE_FALLBACK_IMAGE +ldscript cpu/i386/reset16.lds USE_FALLBACK_IMAGE + +mainboardinit cpu/i386/reset32.inc USE_NORMAL_IMAGE +ldscript cpu/i386/reset32.lds USE_NORMAL_IMAGE + +## +## Include an id string (For safe flashing) +## +mainboardinit arch/i386/lib/id.inc +ldscript arch/i386/lib/id.lds + +## +## Startup code for secondary CPUS +## +#mainboardinit arch/i386/smp/secondary.inc +#mainboardinit arch/i386/lib/cpu_reset.inc + +## This is the early phase of linuxBIOS startup +## Things are delicate and we test to see if we should +## failover to another image. + +mainboardinit northbridge/intel/E7501/reset_test.inc +mainboardinit arch/i386/lib/noop_failover.inc USE_NORMAL_IMAGE +mainboardinit southbridge/intel/82801/cmos_failover.inc USE_FALLBACK_IMAGE +ldscript mainboard/intel/Clearwater533/failover.lds USE_FALLBACK_IMAGE + +### +### O.k. We aren't just an intermediary anymore! +### + + +## +## Setup our mtrrs +## +mainboardinit cpu/i786/earlymtrr.inc + +## +## TESTING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +## +mainboardinit mainboard/intel/Clearwater/preserial.inc + +## +## Setup the serial port +## +mainboardinit superio/winbond/w83627hf/setup_serial.inc +#mainboardinit superio/winbond/w83627hf/setup_led.inc +mainboardinit pc80/serial.inc +mainboardinit arch/i386/lib/console.inc + +mainboardinit ram/ramtest.inc +option RAMTEST=1 + +#Debug SMJ +mainboardinit ram/dump_northbridge.inc +#mainboardinit mainboard/intel/Clearwater/dumpdev.inc + +## +## Setup RAM +## +mainboardinit southbridge/intel/82801ca/smbus.inc +mainboardinit southbridge/intel/82801ca/smbus_read_block.inc +mainboardinit southbridge/intel/82801ca/smbus_noop_read_block.inc +mainboardinit southbridge/intel/82801ca/smbus_read_byte.inc + +#debugging +mainboardinit sdram/generic_dump_spd.inc USE_FALLBACK_IMAGE + + +## +## Include the secondary Configuration files +## +northbridge intel/E7501 +southbridge intel/82801ca +southbridge intel/82870 +#nsuperio NSC/pc87309 com1={1} com2={1} floppy=1 lpt=1 keyboard=1 +nsuperio winbond/w83627hf com1={1} com2={1} floppy=1 lpt=1 keyboard=1 +dir /src/pc80 +dir /src/superio/winbond/w83627hf +dir /src/ram/ +cpu p5 +cpu p6 +cpu i786 + +## +## We'll need a udelay function +## + +option CONFIG_UDELAY_TSC=1 + +## +## Build the objects we have code for in this directory. +## +object mainboard.o +#object mtrr_values.o +object mptable.o HAVE_MP_TABLE +object irq_tables.o HAVE_PIRQ_TABLE + + +### +### Build options +### + +## +## Location of the DIMM EEPROMS on the SMBUS +## This is fixed into a narrow range by the DIMM package standard. +## +option SMBUS_MEM_CHANNEL_OFF=4 +option SMBUS_MEM_DEVICE_START=(0xa << 3) +option SMBUS_MEM_DEVICE_END=(SMBUS_MEM_DEVICE_START +2) +option SMBUS_MEM_DEVICE_INC=1 + +## +## Customize our winbond superio chip for this motherboard +## +#option SIO_BASE=0x2e +#option SIO_SYSTEM_CLK_INPUT=SIO_SYSTEM_CLK_INPUT_48MHZ + +## +## Build code for the fallback boot +## +#option HAVE_FALLBACK_BOOT=1 + +## +## Build code for using cache as RAM +## +#option USE_CACHE_RAM=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 + + +## +## Do not build special code to the keyboard +## +option NO_KEYBOARD=1 + +## +## 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 tabe table +## +option HAVE_OPTION_TABLE=1 + +## +## Build code for SMP support +## Only worry about 2 micro processors +## +option SMP=1 +option MAX_CPUS=4 +option MAX_PHYSICAL_CPUS=2 + +## +## Build code to setup a generic IOAPIC +## +option IOAPIC=1 + +## +## MEMORY_HOLE instructs earlymtrr.inc to +## enable caching from 0-640KB and to disable +## caching from 640KB-1MB using fixed MTRRs +## +## Enabling this option breaks SMP because secondary +## CPU identification depends on only variable MTRRs +## being enabled. +## +nooption MEMORY_HOLE + +## +## Don't do a generic MTRR setup +## Instead use values from the fixed_mtrr_values array +## +#option HAVE_MTRR_TABLE=1 + +## +## Enable both fixed and variable MTRRS +## When we setup MTRRs in mtrr.c +## +## We must setup the fixed mtrrs or we confuse SMP secondary +## processor identification +## +#option ENABLE_FIXED_AND_VARIABLE_MTRRS=1 + + +## +## Figure out which type of linuxBIOS image to build +## If we aren't a fallback image we must be a normal image +## This is useful for optional includes +## +option USE_FALLBACK_IMAGE=1 +expr USE_NORMAL_IMAGE=!USE_FALLBACK_IMAGE + +### +### LinuxBIOS layout values +### + +## ROM_SIZE is the size of boot ROM that this board will use. +option ROM_SIZE=1048576 + +## ROM_IMAGE_SIZE is the amount of space to allow linuxBIOS to occupy. +option ROM_IMAGE_SIZE=65536 + +## LinuxBIOS C code runs at this location in RAM +option _RAMBASE=0x00008000 + +## For the trick of using cache as ram +## put the fake ram location at this address +#option CACHE_RAM_BASE=0xfff70000 +#option CACHE_RAM_SIZE=0x00010000 + +## +## Use a small 8K stack +## +option STACK_SIZE=0x2000 + +## +## Use a small 8K heap +## +option HEAP_SIZE=0x2000 + +## +## Clean up the motherboard id strings +## +option MAINBOARD_PART_NUMBER=Clearwater +option MAINBOARD_VENDOR=Intel + +option PYRO_SERIAL=1 + +## +## Only use the option table in a normal image +## +expr 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. +## +expr ROM_SECTION_SIZE =(USE_FALLBACK_IMAGE*65536)+(USE_NORMAL_IMAGE*(ROM_SIZE - 65536)) +expr ROM_SECTION_OFFSET=(USE_FALLBACK_IMAGE*(ROM_SIZE-65536))+(USE_NORMAL_IMAGE*0) + + +## +## Compute the start location and size size of +## The linuxBIOS bootloader. +## +#expr ZKERNEL_START =(0xffffffff - ROM_SIZE + ROM_SECTION_OFFSET + 1) +expr ZKERNEL_START = 0xfff00000 + (USE_NORMAL_IMAGE * 0x10000) + +expr PAYLOAD_SIZE =ROM_SECTION_SIZE - ROM_IMAGE_SIZE + +## +## Compute where this copy of linuxBIOS will start in the boot rom +## +#expr _ROMBASE =ZKERNEL_START + PAYLOAD_SIZE +expr _ROMBASE = 0xffff0000 - (USE_NORMAL_IMAGE*0x10000) + +## +## Compute a range of ROM that can cached to speed of linuxBIOS, +## execution speed. +## +expr XIP_ROM_SIZE = 65536 +expr XIP_ROM_BASE = _ROMBASE + ROM_IMAGE_SIZE - XIP_ROM_SIZE diff --git a/src/mainboard/intel/Clearwater533/STATUS b/src/mainboard/intel/Clearwater533/STATUS new file mode 100644 index 0000000000..32fea374bb --- /dev/null +++ b/src/mainboard/intel/Clearwater533/STATUS @@ -0,0 +1,27 @@ +# These are keyword-value pairs. +# a : separates the keyword from the value +# the value is arbitrary text delimited by newline. +# continuation, if needed, will be via the \ at the end of a line +# comments are indicated by a '#' as the first character. +# the keywords are case-INSENSITIVE +owner: Steven James +email: pyro@linuxlabs.com +#status: One of unsupported, unstable, stable +status: unstable +explanation: Brand new, some memory configs untested +flash-types: Intel 82802ac8 FWH (8Mbit), 82802ab8 (4Mbit) can be substituted +payload-types: etherboot, memtest86, pforth (an embedded Forth environment) +# e.g. linux, plan 9, wince, etc. +OS-types: linux +# e.g. "Plan 9 interrupts don't work on this chipset" +OS-issues: +console-types: serial +# vga is unsupported, unstable, or stable +vga: unsupported +# Last-known-good follows the internationl date standard: day/month/year +last-known-good: 06/02/2003 +Comments: +Links: +Mainboard-revision: 0 (pre-production sample) +# What other mainboards are like this one? List them here. +AKA: diff --git a/src/mainboard/intel/Clearwater533/defines b/src/mainboard/intel/Clearwater533/defines new file mode 100644 index 0000000000..1a3be2d4ce --- /dev/null +++ b/src/mainboard/intel/Clearwater533/defines @@ -0,0 +1,40 @@ +#define S0_WAIT() \ + movw $0x3fd, %dx ;\ +9: inb %dx, %al ;\ + test $0x40, %al ;\ + je 9b + +#define S0_EMIT(char) \ +9: movw $0x3fd, %dx ;\ + inb %dx, %al ;\ + test $0x20, %al ;\ + je 9b ;\ + movb $char,%al ;\ + movw $0x3f8, %dx ;\ + outb %al, %dx + +#define __CONSOLE_INLINE_TX_HEX8(byte) \ + movb byte, %al ; \ + shr $4, %al ; \ + add $'0', %al ; \ + cmp $'9', %al ; \ + jle 9f ; \ + add $39, %al ; \ +9: ; \ + movw $0x3f8, %dx ;\ + outb %al, %dx ;\ +10: movw $0x3fd, %dx ;\ + inb %dx, %al ;\ + test $0x20, %al ;\ + je 10b ;\ + movw $0x3f8, %dx ;\ + mov byte, %al ; \ + and $0x0f, %al ; \ + add $'0', %al ; \ + cmp $'9', %al ; \ + jle 9f ; \ + add $39, %al ; \ +9: ; \ + movw $0x3f8, %dx ;\ + outb %al, %dx + diff --git a/src/mainboard/intel/Clearwater533/example-fallback.config b/src/mainboard/intel/Clearwater533/example-fallback.config new file mode 100644 index 0000000000..095038f105 --- /dev/null +++ b/src/mainboard/intel/Clearwater533/example-fallback.config @@ -0,0 +1,33 @@ +# This will make a target directory of ./clearwater1 +# Note that this is RELATIVE TO WHERE YOU ARE WHEN YOU RUN THE +# CONFIG TOOL. Make it absolute if you like +target clearwater533-fallback + +# Intel Clearwater (cw2) mainboard +mainboard intel/Clearwater533 + +# Enable Serial Console for debugging +# It will come up at 115200,8n1 +option SERIAL_CONSOLE=1 + +# Enable MicroCode update and L2 Cache init for PII and PIII +option UPDATE_MICROCODE=1 +#option CONFIGURE_L2_CACHE=1 + +# Use the internal VGA frame buffer device +#option HAVE_FRAMEBUFFER=1 + +option USE_ELF_BOOT=1 + +option USE_GENERIC_ROM=1 + +option STD_FLASH=1 + +option USE_FALLBACK_IMAGE = 1 + +option HAVE_PIRQ_TABLE=1 + +option DEFAULT_CONSOLE_LOGLEVEL=9 + +#payload /usr/local/src/LinuxBIOS/etherboot-5.0.6/src/bin32/eepro100.elf + diff --git a/src/mainboard/intel/Clearwater533/example-normal.config b/src/mainboard/intel/Clearwater533/example-normal.config new file mode 100644 index 0000000000..9453247d48 --- /dev/null +++ b/src/mainboard/intel/Clearwater533/example-normal.config @@ -0,0 +1,32 @@ +# Note that this is RELATIVE TO WHERE YOU ARE WHEN YOU RUN THE +# CONFIG TOOL. Make it absolute if you like +target clearwater533-primary + +# Intel Clearwater (cw2) mainboard +mainboard intel/Clearwater533 + +# Enable Serial Console for debugging +# It will come up at 115200,8n1 +option SERIAL_CONSOLE=1 + +# Enable MicroCode update and L2 Cache init for PII and PIII +option UPDATE_MICROCODE=1 +#option CONFIGURE_L2_CACHE=1 + +# Use the internal VGA frame buffer device +#option HAVE_FRAMEBUFFER=1 + +option USE_ELF_BOOT=1 + +option USE_GENERIC_ROM=1 + +option STD_FLASH=1 + +option USE_FALLBACK_IMAGE = 0 + +option HAVE_PIRQ_TABLE=1 + +option DEFAULT_CONSOLE_LOGLEVEL=8 + +#payload /usr/local/src/LinuxBIOS/etherboot-5.0.6/src/bin32/eepro100.elf + diff --git a/src/mainboard/intel/Clearwater533/failover.lds b/src/mainboard/intel/Clearwater533/failover.lds new file mode 100644 index 0000000000..309a33adb9 --- /dev/null +++ b/src/mainboard/intel/Clearwater533/failover.lds @@ -0,0 +1 @@ + __normal_image = 0xf0000 - 8; diff --git a/src/mainboard/intel/Clearwater533/irq_tables.c b/src/mainboard/intel/Clearwater533/irq_tables.c new file mode 100644 index 0000000000..ca38a7eafe --- /dev/null +++ b/src/mainboard/intel/Clearwater533/irq_tables.c @@ -0,0 +1,41 @@ +/* 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 + +const struct irq_routing_table intel_irq_routing_table = { + PIRQ_SIGNATURE, /* u32 signature */ + PIRQ_VERSION, /* u16 version */ + 32+16*17, /* there can be total 17 devices on the bus */ + 0, /* Where the interrupt router lies (bus) */ + 0xf8, /* Where the interrupt router lies (dev) */ + 0, /* IRQs devoted exclusively to PCI usage */ + 0, /* Vendor */ + 0, /* Device */ + 0, /* Crap (miniport) */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */ + 0xd3, /* u8 checksum , this hase to set to some value that would give 0 after the sum of all bytes for this structure (including checksum) */ + { + {0,0, {{0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, + {0,0x10, {{0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, + {0x1,0xe8, {{0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, + {0x2,0x8, {{0x62, 0xdcb8}, {0x62, 0xdcb8}, {0x62, 0xdcb8}, {0x62, 0xdcb8}}, 0x2, 0}, + {0x2,0x10, {{0x62, 0xdcb8}, {0x62, 0xdcb8}, {0x62, 0xdcb8}, {0x62, 0xdcb8}}, 0x3, 0}, + {0x1,0xf8, {{0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, + {0x3,0x8, {{0x62, 0xdcb8}, {0x62, 0xdcb8}, {0x62, 0xdcb8}, {0x62, 0xdcb8}}, 0x1, 0}, + {0,0xe8, {{0x60, 0xdcb8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, + {0,0xe9, {{0, 0xdef8}, {0x63, 0xdcb8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, + {0,0xf0, {{0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, + {0x4,0x8, {{0x61, 0xdcb8}, {0x62, 0xdcb8}, {0x61, 0xdcb8}, {0x62, 0xdcb8}}, 0x4, 0}, + {0x4,0x10, {{0x63, 0xdcb8}, {0x60, 0xdcb8}, {0x63, 0xdcb8}, {0x60, 0xdcb8}}, 0x5, 0}, + {0x4,0x18, {{0x69, 0xdcb8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, + {0x4,0x20, {{0x68, 0xdcb8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, + {0x4,0x28, {{0x6b, 0xdcb8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, + {0x4,0x30, {{0x6a, 0xdcb8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, + {0,0xfb, {{0, 0xdef8}, {0x61, 0xdcb8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, + } +}; diff --git a/src/mainboard/intel/Clearwater533/mainboard.c b/src/mainboard/intel/Clearwater533/mainboard.c new file mode 100644 index 0000000000..88223cca77 --- /dev/null +++ b/src/mainboard/intel/Clearwater533/mainboard.c @@ -0,0 +1,255 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include +#include +#include +#include +#include +// #include +#include + + +#define SMBUS_MEM_DEVICE_0 (0xa << 3) +extern int rdram_chips; /* number of ram chips on the rimms */ + + +unsigned long initial_apicid[MAX_CPUS] = +{ + 0, 6, 1, 7 +}; + +#ifndef CPU_CLOCK_MULTIPLIER +#define CPU_CLOCK_MULTIPLIER XEON_X17 +#endif + +#define MAINBOARD_POWER_ON 1 +#define MAINBOARD_POWER_OFF 2 + +#ifndef MAINBOARD_POWER_ON_AFTER_POWER_FAIL +#define MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON +#endif + +#if 0 +void dump_pci_dev(int bus, int dev, int fn) +{ + + unsigned int offset = 0x80000000; + unsigned int i; + unsigned short devfn; + unsigned char byte; + + devfn = (dev <<3) | fn; + offset |= (bus << 16) | (devfn << 8); + + printk_notice("dump %u:%u.%u:\n", bus,dev,fn); + + for(i=0; i<256; i++) { + + if(! (i & 0x0f)) + printk_notice( "\n%02x: ", i); + + pcibios_read_config_byte(bus, devfn, i, &byte); + printk_notice( "%02x ", byte); + } + + printk_notice("\nDone.\n\n"); + +} + +#endif + + + + + +static void set_power_on_after_power_fail(int setting) +{ + switch(setting) { + case MAINBOARD_POWER_ON: + default: + ich3_power_after_power_fail(1); +// w832627hf_power_after_power_fail(POWER_ON); + break; + case MAINBOARD_POWER_OFF: + ich3_power_after_power_fail(0); +// w832627hf_power_after_power_fail(POWER_OFF); + break; + + } +} + +static void set_thermal_monitoring(int thermal_monitoring) +{ + int tm_high,tm_low; + + rdmsr(MISC_ENABLE,tm_low,tm_high); + if(thermal_monitoring != THERMAL_MONITORING_OFF) { + tm_low |= THERMAL_MONITORING_SET; + } + else { + tm_low &= ~THERMAL_MONITORING_SET; + } + wrmsr(MISC_ENABLE,tm_low,tm_high); + return; +} + +void mainboard_fixup(void) +{ + int cpu_clock_multiplier; + int power_on_after_power_fail; + int thermal_monitoring; + + printk_notice("CW2 mainboard fixup:\n"); + ich3_enable_ioapic(); + p64h2_enable_ioapic(); + ich3_enable_serial_irqs(); + ich3_enable_ide(1,1); + // test, SMJ +// ich3_rtc_init(); + ich3_lpc_route_dma(0xff); + isa_dma_init(); + ich3_1e0_misc(); + ich3_1f0_misc(); + + // SMJ dump some registers! +#if 0 + dump_pci_dev(0, 0, 0); + + printk_notice("1st bridge:\n"); + dump_pci_dev(0, 3, 0); + + + printk_notice("APIC:\n"); + dump_pci_dev(1, 0x1c, 0); + dump_pci_dev(1, 0x1e, 0); + + printk_notice("bridge:\n"); + dump_pci_dev(1, 0x1d, 0); + dump_pci_dev(1, 0x1f, 0); + + printk_notice("ether (connected to 1:0x1f.0):\n"); + dump_pci_dev(3, 0x7, 0); + dump_pci_dev(3, 0x7, 1); +#endif + + // test only SMJ + return; + + cpu_clock_multiplier = CPU_CLOCK_MULTIPLIER; + if(get_option(&cpu_clock_multiplier, "CPU_clock_speed")) + cpu_clock_multiplier = CPU_CLOCK_MULTIPLIER; + ich3_set_cpu_multiplier(cpu_clock_multiplier); + + power_on_after_power_fail = MAINBOARD_POWER_ON_AFTER_POWER_FAIL; + if(get_option(&power_on_after_power_fail, "power_on_after_power_fail")) + power_on_after_power_fail = MAINBOARD_POWER_ON_AFTER_POWER_FAIL; + set_power_on_after_power_fail(power_on_after_power_fail); + + thermal_monitoring = THERMAL_MONITORING_OFF; + if(get_option(&thermal_monitoring, "thermal_monitoring")) + thermal_monitoring = THERMAL_MONITORING_OFF; + set_thermal_monitoring(thermal_monitoring); + + return; +} + +void hard_reset(void) +{ + ich3_hard_reset(); +} + +#ifdef USE_CACHE_RAM + +void cache_ram_start(void) +{ + int error; + + error = 0; + /* displayinit MUST PRECEDE ALL PRINTK! */ + +#if 1 + displayinit(); +#endif + printk_info("Finding PCI configuration type.\n"); + pci_set_method(); + printk_info("Setting up smbus controller\n"); + smbus_setup(); + ich3_rtc_init(); + printk_info("Selecting rdram i2c bus\n"); +// select_rdram_i2c(); + +#if 0 + display_smbus_spd(); +#endif + + init_memory(); + +#if 0 + { + unsigned long addr; + for(addr = 0; addr < 0x20000000; addr += 0x02000000) { + ram_fill(addr, addr + 0x400); + } + /* Do some dummy writes to flush a write cache, in the + * processor. + */ + ram_fill(0xc0000000, 0xc0000400); + for(addr = 0; addr < 0x20000000; addr += 0x02000000) { + ram_verify(addr, addr + 0x400, 1); + } + } +#endif +#if 1 + printk_debug("starting ramcheck\n"); + error |= ramcheck(0x00000000, 0x00080000, 40); + error |= ramcheck(0x02000000, 0x02080000, 40); + error |= ramcheck(0x04000000, 0x04080000, 40); + error |= ramcheck(0x06000000, 0x06080000, 40); + error |= ramcheck(0x08000000, 0x08080000, 40); + error |= ramcheck(0x0a000000, 0x0a080000, 40); + error |= ramcheck(0x0c000000, 0x0c080000, 40); + error |= ramcheck(0x0e000000, 0x0e080000, 40); + error |= ramcheck(0x1a000000, 0x1a080000, 40); +#if 0 + error |= ramcheck(0x10000000, 0x10080000, 20); + error |= ramcheck(0x12000000, 0x12080000, 20); + error |= ramcheck(0x14000000, 0x14080000, 20); + error |= ramcheck(0x16000000, 0x16080000, 20); + error |= ramcheck(0x18000000, 0x18080000, 20); + error |= ramcheck(0x1a000000, 0x1a080000, 20); + error |= ramcheck(0x1c000000, 0x1c080000, 20); + error |= ramcheck(0x1e000000, 0x1e080000, 20); +#endif +#endif +#if 0 + error |= ramcheck(0x00000000, 0x00080000, 20); +#endif +#if 0 + display_rdram_regs(rdram_chips ); +#endif +#if 0 + display_mch_regs(); +#endif + if (error) { + printk_err("Something isn't working!!!\n"); + while(1); + } else { + printk_info("Leaving cacheram...\n"); + } + +} + + +#endif + + + diff --git a/src/mainboard/intel/Clearwater533/mptable.c b/src/mainboard/intel/Clearwater533/mptable.c new file mode 100644 index 0000000000..4aed0ebf70 --- /dev/null +++ b/src/mainboard/intel/Clearwater533/mptable.c @@ -0,0 +1,161 @@ +/* generatred by MPTable, version 2.0.15*/ +/* as modified by RGM for LinuxBIOS */ +#include +#include +#include +#include +#include + +void *smp_write_config_table(void *v, unsigned long * processor_map) +{ + static const char sig[4] = "PCMP"; + static const char oem[8] = "LnxLabs "; + static const char productid[12] = "7501CW2 "; + struct mp_config_table *mc; + + mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN); + memset(mc, 0, sizeof(*mc)); + + memcpy(mc->mpc_signature, sig, sizeof(sig)); + mc->mpc_length = sizeof(*mc); /* initially just the header */ + mc->mpc_spec = 0x04; + mc->mpc_checksum = 0; /* not yet computed */ + memcpy(mc->mpc_oem, oem, sizeof(oem)); + memcpy(mc->mpc_productid, productid, sizeof(productid)); + mc->mpc_oemptr = 0; + mc->mpc_oemsize = 0; + mc->mpc_entry_count = 0; /* No entries yet... */ + mc->mpc_lapic = LAPIC_ADDR; + mc->mpe_length = 0; + mc->mpe_checksum = 0; + mc->reserved = 0; + +#if 0 + smp_write_processor(mc, 0x00, 0x14, CPU_BOOTPROCESSOR | CPU_ENABLED, + 0x00000f24, 0x3febfbff); + smp_write_processor(mc, 0x06, 0x14, CPU_ENABLED, 0x00000f24, 0x3febfbff); + smp_write_processor(mc, 0x01, 0x14, CPU_ENABLED, 0x00000f24, 0x3febfbff); + smp_write_processor(mc, 0x07, 0x14, CPU_ENABLED, 0x00000f24, 0x3febfbff); +#else + smp_write_processors(mc, processor_map); +#endif + + +/*Bus: Bus ID Type*/ + smp_write_bus(mc, 0, "PCI "); + smp_write_bus(mc, 1, "PCI "); + smp_write_bus(mc, 2, "PCI "); + smp_write_bus(mc, 3, "PCI "); + smp_write_bus(mc, 4, "PCI "); + smp_write_bus(mc, 5, "ISA "); +/*I/O APICs: APIC ID Version State Address*/ + smp_write_ioapic(mc, 2, 0x20, 0xfec00000); + { + struct pci_dev *dev; + uint32_t base; + dev = pci_find_slot(1, PCI_DEVFN(0x1e,0)); + if (dev) { + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &base); + base &= PCI_BASE_ADDRESS_MEM_MASK; + smp_write_ioapic(mc, 3, 0x20, base); + } + dev = pci_find_slot(1, PCI_DEVFN(0x1c,0)); + if (dev) { + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &base); + base &= PCI_BASE_ADDRESS_MEM_MASK; + smp_write_ioapic(mc, 4, 0x20, base); + } + dev = pci_find_slot(4, PCI_DEVFN(0x1e,0)); + if (dev) { + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &base); + base &= PCI_BASE_ADDRESS_MEM_MASK; + smp_write_ioapic(mc, 5, 0x20, base); + } + dev = pci_find_slot(4, PCI_DEVFN(0x1c,0)); + if (dev) { + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &base); + base &= PCI_BASE_ADDRESS_MEM_MASK; + smp_write_ioapic(mc, 8, 0x20, base); + } + } +/*I/O Ints: Type Polarity Trigger Bus ID IRQ APIC ID PIN# +*/ smp_write_intsrc(mc, mp_ExtINT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x0, 0x2, 0x0); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x1, 0x2, 0x1); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x0, 0x2, 0x2); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x3, 0x2, 0x3); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x4, 0x2, 0x4); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x0, 0x75, 0x2, 0x13); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x6, 0x2, 0x6); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x7, 0x2, 0x7); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x8, 0x2, 0x8); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x9, 0x2, 0x9); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x0, 0x74, 0x2, 0x10); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x0, 0x7d, 0x2, 0x11); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0xc, 0x2, 0xc); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0xd, 0x2, 0xd); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0xe, 0x2, 0xe); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0xf, 0x2, 0xf); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x4, 0xc, 0x2, 0x15); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x4, 0x10, 0x2, 0x14); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x4, 0x14, 0x2, 0x17); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x4, 0x18, 0x2, 0x16); +/*Local Ints: Type Polarity Trigger Bus ID IRQ APIC ID PIN#*/ + smp_write_intsrc(mc, mp_ExtINT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x0, MP_APIC_ALL, 0x0); + smp_write_intsrc(mc, mp_NMI, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x0, MP_APIC_ALL, 0x1); +/* MP Config Extended Table Entries: + +-- +System Address Space + bus ID: 0 address type: I/O address + address base: 0x0 + address range: 0x10000 +-- +System Address Space + bus ID: 0 address type: memory address + address base: 0x40000000 + address range: 0xbee00000 +-- +System Address Space + bus ID: 0 address type: memory address + address base: 0xfee01000 + address range: 0x11ff000 +-- +System Address Space + bus ID: 4 address type: memory address + address base: 0xa0000 + address range: 0x20000 +-- +System Address Space + bus ID: 4 address type: memory address + address base: 0xcc000 + address range: 0x10000 +-- +System Address Space + bus ID: 4 address type: memory address + address base: 0xe0000 + address range: 0x4000 +-- +Bus Heirarchy + bus ID: 5 bus info: 0x01 parent bus ID: 0-- +Compatibility Bus Address + bus ID: 0 address modifier: add + predefined range: 0x00000000-- +Compatibility Bus Address + bus ID: 0 address modifier: add + predefined range: 0x00000001 There is no extension information... */ + + /* Compute the checksums */ + mc->mpe_checksum = smp_compute_checksum(smp_next_mpc_entry(mc), mc->mpe_length); + mc->mpc_checksum = smp_compute_checksum(mc, mc->mpc_length); + printk_debug("Wrote the mp table end at: %p - %p +", + mc, smp_next_mpe_entry(mc)); + return smp_next_mpe_entry(mc); +} + +unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map) +{ + void *v; + v = smp_write_floating_table(addr); + return (unsigned long)smp_write_config_table(v, processor_map); +} diff --git a/src/mainboard/intel/Clearwater533/mtrr_values.c b/src/mainboard/intel/Clearwater533/mtrr_values.c new file mode 100644 index 0000000000..68c1a6eefc --- /dev/null +++ b/src/mainboard/intel/Clearwater533/mtrr_values.c @@ -0,0 +1,49 @@ +#include + +/* We want to cache memory as efficiently as possible. + */ +#define RAM MTRR_TYPE_WRBACK +/* We can't use Write Combining on a legacy frame buffer because + * it is incompatible with EGA 16 color video modes... + */ +#define FB MTRR_TYPE_UNCACHABLE +/* For areas that are supposed to cover roms it makes no + * sense to cache writes. + */ +#define ROM MTRR_TYPE_WRPROT + + +unsigned char fixed_mtrr_values[][4] = { + /* MTRRfix64K_00000_MSR, defines memory range from 0KB to 512 KB, each byte cover 64KB area */ + {RAM, RAM, RAM, RAM}, {RAM, RAM, RAM, RAM}, + + /* MTRRfix16K_80000_MSR, defines memory range from 512KB to 640KB, each byte cover 16KB area */ + {RAM, RAM, RAM, RAM}, {RAM, RAM, RAM, RAM}, + + /* MTRRfix16K_A0000_MSR, defines memory range from A0000 to C0000, each byte cover 16KB area */ + {FB, FB, FB, FB}, {FB, FB, FB, FB}, + + /* MTRRfix4K_C0000_MSR, defines memory range from C0000 to C8000, each byte cover 4KB area */ + {RAM, RAM, RAM, RAM}, {RAM, RAM, RAM, RAM}, + + /* MTRRfix4K_C8000_MSR, defines memory range from C8000 to D0000, each byte cover 4KB area */ + {RAM, RAM, RAM, RAM}, {RAM, RAM, RAM, RAM}, + + /* MTRRfix4K_D0000_MSR, defines memory range from D0000 to D8000, each byte cover 4KB area */ + {RAM, RAM, RAM, RAM}, {RAM, RAM, RAM, RAM}, + + /* MTRRfix4K_D8000_MSR, defines memory range from D8000 to E0000, each byte cover 4KB area */ + {RAM, RAM, RAM, RAM}, {RAM, RAM, RAM, RAM}, + + /* MTRRfix4K_E0000_MSR, defines memory range from E0000 to E8000, each byte cover 4KB area */ + {RAM, RAM, RAM, RAM}, {RAM, RAM, RAM, RAM}, + + /* MTRRfix4K_E8000_MSR, defines memory range from E8000 to F0000, each byte cover 4KB area */ + {RAM, RAM, RAM, RAM}, {RAM, RAM, RAM, RAM}, + + /* MTRRfix4K_F0000_MSR, defines memory range from F0000 to F8000, each byte cover 4KB area */ + {RAM, RAM, RAM, RAM}, {RAM, RAM, RAM, RAM}, + + /* MTRRfix4K_F8000_MSR, defines memory range from F8000 to 100000, each byte cover 4KB area */ + {RAM, RAM, RAM, RAM}, {RAM, RAM, RAM, RAM}, +}; diff --git a/src/mainboard/intel/Clearwater533/preserial.inc b/src/mainboard/intel/Clearwater533/preserial.inc new file mode 100644 index 0000000000..fd6f8a5e02 --- /dev/null +++ b/src/mainboard/intel/Clearwater533/preserial.inc @@ -0,0 +1,458 @@ + jmp preserial + + +#define S0_WAIT() \ + movw $0x3fd, %dx ;\ +9: inb %dx, %al ;\ + test $0x40, %al ;\ + je 9b + +#define S0_EMIT(char) \ +9: movw $0x3fd, %dx ;\ + inb %dx, %al ;\ + test $0x20, %al ;\ + je 9b ;\ + movb $char,%al ;\ + movw $0x3f8, %dx ;\ + outb %al, %dx + +#define __CONSOLE_INLINE_TX_HEX8(byte) \ + movb byte, %al ; \ + shr $4, %al ; \ + add $'0', %al ; \ + cmp $'9', %al ; \ + jle 9f ; \ + add $39, %al ; \ +9: ; \ + movw $0x3f8, %dx ;\ + outb %al, %dx ;\ +10: movw $0x3fd, %dx ;\ + inb %dx, %al ;\ + test $0x20, %al ;\ + je 10b ;\ + movw $0x3f8, %dx ;\ + mov byte, %al ; \ + and $0x0f, %al ; \ + add $'0', %al ; \ + cmp $'9', %al ; \ + jle 9f ; \ + add $39, %al ; \ +9: ; \ + movw $0x3f8, %dx ;\ + outb %al, %dx + +southbridge_table_start: + + .byte 0x01, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00 # 40 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 # 50 + .byte 0x0a, 0x0b, 0x80, 0x09, 0xd1, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00 # 60 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 # 70 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 # 80 + .byte 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 # 90 + .byte 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 # a0 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 # b0 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 # c0 + .byte 0x86, 0x39, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 # d0 + .byte 0x10, 0x00, 0x00, 0xc0, 0x00, 0xa0, 0x0f, 0x1c, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 0x67, 0x45 # e0 + .byte 0x0f, 0x00, 0x60, 0x84, 0x00, 0x00, 0x00, 0x00, 0x47, 0x0f, 0x0e, 0x00, 0x00, 0x00, 0x81, 0x00 # f0 + +southbridge_end: + +.globl preserial + preserial: + + .code32 + + cli + +#call off the dog + movw $0x461, %dx + movb $0x20, %al + outb %al, %dx + dec %dx + movb $0x01, %al + outb %al, %dx + + movl $0x8000f8d4, %eax + movw $0xcf8, %dx + outl %eax, %dx + movw $0xcfc, %dx + movb $0x2, %al +# movb $0x0, %al # 0x02 here to disable watchdog function + outb %al, %dx + +# movw $0x468, %dx +# movw $0x800, %ax +# outw %ax, %dx +# + +#turn on LPC I/o access to superio + movl $0x8000f8e6, %eax + mov $0xcf8, %dx + outl %eax, %dx + + mov $0xcfc, %dx + movw $0x1c0f, %ax + outw %ax, %dx + +#assign i/o ranges for serial I/O + movl $0x8000f8e0, %eax + mov $0xcf8, %dx + outl %eax, %dx + + mov $0xcfc, %dx + mov $0x10, %al + outb %al, %dx + +#attempt to get Natsemi superio to ID itself +#movw $0x2e, %dx +#movb $0x20, %al +#outb %al, %dx + +#inc %dx +#inb %dx, %al + +#cmp $0x0ee, %al +#je corrupt_cmos + + #OK, now, lets turn serial on! + + jmp noreset + #first, reset the serial chip to defaults + movw $0x2e, %dx + movb $0x21, %al + outb %al, %dx + + inc %dx + movb $0x13, %al + outb %al, %dx + +noreset: + movw $0x2e, %dx + movb $0x21, %al + outb %al, %dx + + inc %dx + movb $0x19, %al + outb %al, %dx + + dec %dx + movb $0x22, %al + outb %al, %dx + inc %dx + outb %al, %dx # YES! 22->22 + + dec %dx + movb $0x23, %al + outb %al, %dx + inc %dx + movb $0x72, %al + outb %al, %dx + + dec %dx + movb $0x24, %al + outb %al, %dx + inc %dx + movb $0x26, %al + outb %al, %dx + + dec %dx + movb $0x2a, %al + outb %al, %dx + inc %dx + movb $0x0b, %al + outb %al, %dx + +#enable serial + dec %dx + movb $0x07, %al + outb %al, %dx + inc %dx + movb $0x03, %al + outb %al, %dx + + dec %dx + movb $0x30, %al + outb %al, %dx + inc %dx + movb $0x01, %al + outb %al, %dx + +#O.K. now lets try to set up serial part way, then confirm that its active + + #turn off serial interrupts, we have no vectors + movw $0x3f9, %dx + movb $0x0, %al + outb %al, %dx + + #set divisor to 115200 + movw $0x3fb, %dx + movb $0x83, %al + outb %al, %dx + + movw $0x3f8, %dx + movb $0x01, %al + outb %al, %dx + inc %dx + + movb $0x00, %al + outb %al, %dx + + #set n81 + movw $0x3fb, %dx + movb $0x03, %al + outb %al, %dx + + #FIFO setup $0xc7 -> 0x3fa + movw $0x3fa, %dx + movb $0xc7, %al + out %al, %dx + + + + #set DTR, RTS, OUT2 (whatever that is) + movw $0x3fc, %dx + movb $0xb, %al + outb %al, %dx + + jmp preserial_out + +#set null descriptor to all but CS +#movw $0x0, %ax +#movw %ax, %ds +#movw %ax, %es +#movw %ax, %fs +#movw %ax, %gs + + S0_EMIT('C') + S0_EMIT('S') + S0_EMIT(':') + movw %cs, %ax + movw %ax, %bx + __CONSOLE_INLINE_TX_HEX8(%bh) + __CONSOLE_INLINE_TX_HEX8(%bl) + S0_EMIT('\r') + S0_EMIT('\n') + + S0_EMIT('D') + S0_EMIT('S') + S0_EMIT(':') + S0_WAIT() + movw %ds, %ax + movw %ax, %bx + __CONSOLE_INLINE_TX_HEX8(%bh) + __CONSOLE_INLINE_TX_HEX8(%bl) + S0_EMIT('\r') + S0_EMIT('\n') + + S0_EMIT('C') + S0_EMIT('R') + S0_EMIT('0') + S0_EMIT(':') + + S0_WAIT() + + movl %cr0, %eax + movl %eax, %ebx + movl %eax, %ecx + shr $0x16, %ebx + + __CONSOLE_INLINE_TX_HEX8(%bh) + __CONSOLE_INLINE_TX_HEX8(%bl) + movw %cx,%bx + + __CONSOLE_INLINE_TX_HEX8(%bh) + __CONSOLE_INLINE_TX_HEX8(%bl) + + S0_EMIT('\r') + S0_EMIT('\n') + + movl $0x10002, %esi +#sgdt %cs:(%esi) + sgdt (%esi) + + S0_EMIT('G') + S0_EMIT('D') + S0_EMIT('T') + S0_EMIT(':') + + movw (0x10002), %cx + movl (0x10004), %ebx + +out1: + __CONSOLE_INLINE_TX_HEX8( %cs:(%ebx) ) + inc %bx + dec %cx + jnz out1 + +#movw $0x4, %cx +#loop3: +#__CONSOLE_INLINE_TX_HEX8(%bl) +#shr $0x08, %ebx +#dec %cx +#jnz loop3 + + + #just a test, emit a PYRO + S0_EMIT('P') + + jmp dolgdt + + .align 4 +dolgdt: + lgdt %cs:gdtptr + S0_EMIT('Y') + ljmp $0x10,$csload +csload: + S0_EMIT('R') + + movw $0x18, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + + S0_EMIT('O') + S0_EMIT('\r') + S0_EMIT('\n') + +#movb $0x50, %al +#movw $0x3f8, %dx +#outb %al, %dx +#movb $0x59, %al +#outb %al, %dx +#movb $0x52, %al +#outb %al, %dx +#movb $0x4f, %al +#outb %al, %dx + +#movb $0x0d, %al +#outb %al, %dx + +#movb $0x0a, %al +#outb %al, %dx + + + #indicate we did it by clearing DTR + movw $0x3fc, %dx + movb $0x0a, %al + outb %al, %dx + + + + jmp preserial_out + + movl $southbridge_table_start, %esi + movl $(southbridge_end - southbridge_table_start), %ecx + shrl $0x02, %ecx + movl $0x8000f840, %eax + movl %eax, %ebx + +next_dword: + movw $0xcf8, %dx + movl %ebx, %eax + outl %eax, %dx + inc %eax + inc %eax + inc %eax + inc %eax + movl %eax, %ebx + lodsl (%esi), %eax + movw $0xcfc, %dx + outl %eax, %dx + loopnz next_dword + + + jmp preserial_out + + + movl $0x8000f8e0, %eax + mov $0xcf8, %dx + outl %eax, %dx + + mov $0xcfc, %dx + mov $0x10, %al + outb %al, %dx + + + + jmp preserial_out + +corrupt_cmos: + mov $0x72, %dx + mov $0x50, %al + outb %al, %dx + inc %dx + mov $0x42, %al + outb %al, %dx + + dec %dx + mov $0x51, %al + outb %al, %dx + inc %dx + mov $0xbe, %al + outb %al, %dx + + +#now, strobe HD light a few times to prove we made it here + + mov $30, %bx + mov $0x480, %dx +again: + mov $0xa7, %al + outb %al, %dx + movl $0xfffffff,%ecx +loop1: + dec %ecx + jnz loop1 + + mov $0xa6, %al + outb %al, %dx + movl $0xfffffff,%ecx +loop2: + dec %ecx + jnz loop2 + + + dec %bx + jnz again + + +preserial_out: + + S0_EMIT('A') + S0_EMIT('P') + S0_EMIT('I') + S0_EMIT('C') + S0_EMIT('I') + S0_EMIT('D') + S0_EMIT(':') + + movl $APIC_DEFAULT_BASE, %edi + movl APIC_ID(%edi), %eax + shrl $24, %eax + + __CONSOLE_INLINE_TX_HEX8(%al) + S0_EMIT('\r') + S0_EMIT('\n') + + +#very temporary, set TOLM to 1 Gig. This should be enumerated or otherwise tested! + movl $0x800000c4, %eax + movw $0xcf8, %dx + outl %eax, %dx + movw $0x4000, %ax + movw $0xcfc, %dx + outw %ax, %dx + +#set PCI dev 0:0.0.e0 < 0x1e + movl $0x800000e0, %eax + movw $0xcf8, %dx + outl %eax, %dx + movb $0x1e, %al + movw $0xcfc, %dx + outb %al, %dx + +jmp console0 + diff --git a/src/northbridge/intel/E7501/Config b/src/northbridge/intel/E7501/Config new file mode 100644 index 0000000000..cec520a186 --- /dev/null +++ b/src/northbridge/intel/E7501/Config @@ -0,0 +1,10 @@ +#mainboardinit cpu/i786/enable_sse.inc +mainboardinit arch/i386/lib/cpu_reset.inc +mainboardinit ram/spotcheck.inc +mainboardinit northbridge/intel/E7501/raminit.inc +mainboardinit northbridge/intel/E7501/sdram_enable.inc +mainboardinit sdram/generic_sdram.inc +#mainboardinit cpu/i786/disable_sse.inc +mainboardinit sdram/generic_cache_linuxbios.inc + +object northbridge.o diff --git a/src/northbridge/intel/E7501/northbridge.c b/src/northbridge/intel/E7501/northbridge.c new file mode 100644 index 0000000000..b3de702469 --- /dev/null +++ b/src/northbridge/intel/E7501/northbridge.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include + +struct mem_range *sizeram(void) +{ + static struct mem_range mem[4]; + /* the units of tolm are 64 KB */ + /* the units of drb16 are 64 MB */ + uint16_t tolm, remapbase, remaplimit, drb16; + uint16_t tolm_r, remapbase_r, remaplimit_r; + uint8_t drb; + int remap_high; + + /* Calculate and report the top of low memory and + * any remapping. + */ + /* Test if the remap memory high option is set */ + remap_high = 0; + if(get_option(&remap_high, "remap_memory_high")){ + remap_high = 0; + } + printk_debug("remap_high is %d\n", remap_high); + /* get out the value of the highest DRB. This tells the end of + * physical memory. The units are ticks of 64 MB i.e. 1 means + * 64 MB. + */ + pcibios_read_config_byte(0, 0, 0x67, &drb); + drb16 = (uint16_t)drb; + if(remap_high && (drb16 > 0x08)) { + /* We only come here if we have at least 512MB of memory, + * so it is safe to hard code tolm. + * 0x2000 means 512MB + */ + + tolm = 0x2000; + /* i.e 0x40 * 0x40 is 0x1000 which is 4 GB */ + if(drb16 > 0x0040) { + /* There is more than 4GB of memory put + * the remap window at the end of ram. + */ + remapbase = drb16; + remaplimit = remapbase + 0x38; + } + else { + remapbase = 0x0040; + remaplimit = remapbase + (drb16-8); + } + } + else { + tolm = (uint16_t)((pci_memory_base >> 16)&0x0f800); + if((tolm>>8) >= (drb16<<2)) { + tolm = (drb16<<10); + remapbase = 0x3ff; + remaplimit = 0; + } + else { + remapbase = drb16; + remaplimit = remapbase + ((0x0040-(tolm>>10))-1); + } + } + /* Write the ram configruation registers, + * preserving the reserved bits. + */ + pcibios_read_config_word(0, 0, 0xc4, &tolm_r); + tolm |= (tolm_r & 0x7ff); + pcibios_write_config_word(0, 0, 0xc4, tolm); + pcibios_read_config_word(0, 0, 0xc6, &remapbase_r); + remapbase |= (remapbase_r & 0xfc00); + pcibios_write_config_word(0, 0, 0xc6, remapbase); + pcibios_read_config_word(0, 0, 0xc8, &remaplimit_r); + remaplimit |= (remaplimit_r & 0xfc00); + pcibios_write_config_word(0, 0, 0xc8, remaplimit); + +#if 0 + printk_debug("mem info tolm = %x, drb = %x, pci_memory_base = %x, remap = %x-%x\n",tolm,drb,pci_memory_base,remapbase,remaplimit); +#endif + + mem[0].basek = 0; + mem[0].sizek = 640; + mem[1].basek = 768; + /* Convert size in 64K bytes to size in K bytes */ + mem[1].sizek = (tolm << 6) - mem[1].basek; + mem[2].basek = 0; + mem[2].sizek = 0; + if ((drb << 16) > (tolm << 6)) { + /* We don't need to consider the remap window + * here because we put it immediately after the + * rest of ram. + * All we must do is calculate the amount + * of unused memory and report it at 4GB. + */ + mem[2].basek = 4096*1024; + mem[2].sizek = (drb << 16) - (tolm << 6); + } + mem[3].basek = 0; + mem[3].sizek = 0; + + return mem; +} diff --git a/src/northbridge/intel/E7501/raminit.inc b/src/northbridge/intel/E7501/raminit.inc new file mode 100644 index 0000000000..2f26371b59 --- /dev/null +++ b/src/northbridge/intel/E7501/raminit.inc @@ -0,0 +1,1922 @@ +jmp intel_E7500_out + +/* This was originally for the e7500, modified for e7501 + * The primary differences are that 7501 apparently can + * support single channel RAM (i haven't tested), + * CAS1.5 is no longer supported, The ECC scrubber + * now supports a mode to zero RAM and init ECC in one step + * and the undocumented registers at 0x80 require new + * (undocumented) values determined by guesswork and + * comparison w/ OEM BIOS values. + * Steven James 02/06/2003 + */ + +#define DEBUG_RAM_CONFIG 0 + + +/* DDR DIMM Mode register Definitions */ + +#define BURST_2 (1<<0) +#define BURST_4 (2<<0) +#define BURST_8 (3<<0) + +#define BURST_SEQUENTIAL (0<<3) +#define BURST_INTERLEAVED (1<<3) + +#define CAS_2_0 (0x2<<4) +#define CAS_3_0 (0x3<<4) +#define CAS_1_5 (0x5<<4) +#define CAS_2_5 (0x6<<4) + +#define MODE_NORM (0 << 7) +#define MODE_DLL_RESET (2 << 7) +#define MODE_TEST (1 << 7) + +#define BURST_LENGTH BURST_4 +#define BURST_TYPE BURST_INTERLEAVED +#define CAS_LATENCY CAS_2_0 +//#define CAS_LATENCY CAS_1_5 + +#define MRS_VALUE (MODE_NORM | CAS_LATENCY | BURST_TYPE | BURST_LENGTH) +#define EMRS_VALUE 0x000 + +#define MD_SHIFT 4 + +#define RAM_COMMAND_NONE 0x0 +#define RAM_COMMAND_NOP 0x1 +#define RAM_COMMAND_PRECHARGE 0x2 +#define RAM_COMMAND_MRS 0x3 +#define RAM_COMMAND_EMRS 0x4 +#define RAM_COMMAND_CBR 0x6 +#define RAM_COMMAND_NORMAL 0x7 + +#define RAM_CMD(command, offset) \ + movl $(((offset) << (MD_SHIFT + 16))|((command << 4) & 0x70)), %ebx ; \ + CALLSP(do_ram_command) + +#define RAM_NOP() RAM_CMD(RAM_COMMAND_NOP, 0) +#define RAM_PRECHARGE() RAM_CMD(RAM_COMMAND_PRECHARGE, 0) +#define RAM_CBR() RAM_CMD(RAM_COMMAND_CBR, 0) +#define RAM_EMRS() RAM_CMD(RAM_COMMAND_EMRS, EMRS_VALUE) + +ram_cas_latency: + .byte CAS_2_5, CAS_2_0, CAS_1_5, CAS_2_5 +ram_mrs: + /* Read the cas latency setting */ + movl $0x78, %eax + PCI_READ_CONFIG_BYTE + /* Transform it into the form expected by SDRAM */ + shrl $4, %eax + andl $3, %eax + movb ram_cas_latency(%eax), %al + shll $(16+MD_SHIFT), %eax + orl %eax, %ebx + orl $((MODE_NORM | BURST_TYPE | BURST_LENGTH) << (16+MD_SHIFT)), %ebx + jmp do_ram_command + +#define RAM_MRS(dll_reset) \ + movl $((dll_reset << (8+MD_SHIFT+ 16))|((RAM_COMMAND_MRS <<4)& 0x70)), %ebx ; \ + CALLSP(ram_mrs) + +#define RAM_NORMAL() \ + movl $0x7c, %eax ;\ + PCI_READ_CONFIG_BYTE ;\ + andl $0x8F, %eax ;\ + orb $(RAM_COMMAND_NORMAL << 4), %al ;\ + movl %eax, %edx ;\ + movl $0x7c, %eax ;\ + PCI_WRITE_CONFIG_BYTE + +#define RAM_RESET_DDR_PTR() \ + movl $0x88, %eax ;\ + PCI_READ_CONFIG_BYTE ;\ + orb $(1 << 4), %al ;\ + movl %eax, %edx ;\ + movl $0x88, %eax ;\ + PCI_WRITE_CONFIG_BYTE ;\ + movl $0x88, %eax ;\ + PCI_READ_CONFIG_BYTE ;\ + andb $~(1 << 4), %al ;\ + movl %eax, %edx ;\ + movl $0x88, %eax ;\ + PCI_WRITE_CONFIG_BYTE + +do_ram_command: +#if DEBUG_RAM_CONFIG >= 2 + movl %esp, %esi + movl %ebx, %edi + CONSOLE_DEBUG_TX_CHAR($'P') + CONSOLE_DEBUG_TX_CHAR($':') + CONSOLE_DEBUG_TX_HEX8(%bl) + CONSOLE_DEBUG_TX_CHAR($'\r') + CONSOLE_DEBUG_TX_CHAR($'\n') + movl %edi, %ebx + movl %esi, %esp +#endif + /* %ecx - initial address to read from */ + /* Compute the offset */ + movl %ebx, %ecx + shrl $16, %ecx + +1: + /* Set the ram command */ + movl $0x7c, %eax + PCI_READ_CONFIG_BYTE + andl $0x8F, %eax + orb %bl, %al + movl %eax, %edx + movl $0x7c, %eax + PCI_WRITE_CONFIG_BYTE + + /* Assert the command to the memory */ +#if DEBUG_RAM_CONFIG >= 2 + movl %esp, %esi + movl %ebx, %edi + CONSOLE_DEBUG_TX_CHAR($'R') + CONSOLE_DEBUG_TX_CHAR($':') + CONSOLE_DEBUG_TX_HEX32(%ecx) + CONSOLE_DEBUG_TX_CHAR($'\r') + CONSOLE_DEBUG_TX_CHAR($'\n') + movl %edi, %ebx + movl %esi, %esp +#endif + movl (%ecx), %eax + + /* Go to the next base address */ + addl $0x04000000, %ecx + + /* Increment the counter */ + incb %bh + + /* See if we are done */ + cmpb $8, %bh + jb 1b + +3: /* The command has been sent to all dimms so get out */ + RETSP + +#define ENABLE_REFRESH() \ + movl $0x7c, %eax ;\ + PCI_READ_CONFIG_DWORD ;\ + orl $(1 << 29), %eax ;\ + movl %eax, %ecx ;\ + mov $0x7c, %eax ;\ + PCI_WRITE_CONFIG_DWORD + + /* + * Table: constant_register_values + */ + .p2align 3 +constant_register_values: + /* SVID - Subsystem Vendor Identification Register + * 0x2c - 0x2d + * [15:00] Subsytem Vendor ID (Indicates system board vendor) + */ + /* SID - Subsystem Identification Register + * 0x2e - 0x2f + * [15:00] Subsystem ID + */ + .long 0x2c, 0, (0x15d9 << 0) | (0x3480 << 16) + + /* Undocumented + * 0x80 - 0x80 + * This register has something to do with CAS latencies, + * possibily this is the real chipset control. + * At 0x00 CAS latency 1.5 works. + * At 0x06 CAS latency 2.5 works. + * At 0x01 CAS latency 2.0 works. + */ + /* This is still undocumented in e7501, but with different values + * CAS 2.0 values taken from Intel BIOS settings, others are a guess + * and may be terribly wrong. Old values preserved as comments until I + * figure this out for sure. + * e7501 docs claim that CAS1.5 is unsupported, so it may or may not + * work at all. + * Steven James 02/06/2003 + */ +#if CAS_LATENCY == CAS_2_5 +# .long 0x80, 0xfffffe00, 0x06 /* Intel E7500 recommended */ + .long 0x80, 0xfffff000, 0x0bb6 /* Intel E7500 recommended */ +#elif CAS_LATENCY == CAS_2_0 +# .long 0x80, 0xfffffe00, 0x0d /* values for register 0x80 */ + .long 0x80, 0xfffff000, 0x0bb1 /* values for register 0x80 */ +#elif CAS_LATENCY == CAS_1_5 +# .long 0x80, 0xfffffe00, 0x05 + .long 0x80, 0xfffff000, 0x0bb5 +#endif + + /* Enable periodic memory recalibration */ + .long 0x88, 0xffffff00, 0x80 + + /* FDHC - Fixed DRAM Hole Control + * 0x58 + * [7:7] Hole_Enable + * 0 == No memory Hole + * 1 == Memory Hole from 15MB to 16MB + * [6:0] Reserved + * + * PAM - Programmable Attribute Map + * 0x59 [1:0] Reserved + * 0x59 [5:4] 0xF0000 - 0xFFFFF + * 0x5A [1:0] 0xC0000 - 0xC3FFF + * 0x5A [5:4] 0xC4000 - 0xC7FFF + * 0x5B [1:0] 0xC8000 - 0xCBFFF + * 0x5B [5:4] 0xCC000 - 0xCFFFF + * 0x5C [1:0] 0xD0000 - 0xD3FFF + * 0x5C [5:4] 0xD4000 - 0xD7FFF + * 0x5D [1:0] 0xD8000 - 0xDBFFF + * 0x5D [5:4] 0xDC000 - 0xDFFFF + * 0x5E [1:0] 0xE0000 - 0xE3FFF + * 0x5E [5:4] 0xE4000 - 0xE7FFF + * 0x5F [1:0] 0xE8000 - 0xEBFFF + * 0x5F [5:4] 0xEC000 - 0xEFFFF + * 00 == DRAM Disabled (All Access go to memory mapped I/O space) + * 01 == Read Only (Reads to DRAM, Writes to memory mapped I/O space) + * 10 == Write Only (Writes to DRAM, Reads to memory mapped I/O space) + * 11 == Normal (All Access go to DRAM) + */ + .long 0x58, 0xcccccf7f, (0x00 << 0) | (0x30 << 8) | (0x33 << 16) | (0x33 << 24) + .long 0x5C, 0xcccccccc, (0x33 << 0) | (0x33 << 8) | (0x33 << 16) | (0x33 << 24) + + /* DRB - DRAM Row Boundary Registers + * 0x60 - 0x6F + * An array of 8 byte registers, which hold the ending + * memory address assigned to each pair of DIMMS, in 64MB + * granularity. + */ + /* Conservatively say each row has 64MB of ram, we will fix this up later */ + .long 0x60, 0x00000000, (0x01 << 0) | (0x02 << 8) | (0x03 << 16) | (0x04 << 24) + .long 0x64, 0x00000000, (0x05 << 0) | (0x06 << 8) | (0x07 << 16) | (0x08 << 24) + .long 0x68, 0xffffffff, 0 + .long 0x6C, 0xffffffff, 0 + + /* DRA - DRAM Row Attribute Register + * 0x70 Row 0,1 + * 0x71 Row 2,3 + * 0x72 Row 4,5 + * 0x73 Row 6,7 + * [7:7] Device width for Odd numbered rows + * 0 == 8 bits wide x8 + * 1 == 4 bits wide x4 + * [6:4] Row Attributes for Odd numbered rows + * 010 == 8KB + * 011 == 16KB + * 100 == 32KB + * 101 == 64KB + * Others == Reserved + * [3:3] Device width for Even numbered rows + * 0 == 8 bits wide x8 + * 1 == 4 bits wide x4 + * [2:0] Row Attributes for Even numbered rows + * 010 == 8KB + * 011 == 16KB + * 100 == 32KB + * 101 == 64KB (This page size appears broken) + * Others == Reserved + */ + .long 0x70, 0x00000000, \ + (((0<<3)|(0<<0))<< 0) | \ + (((0<<3)|(0<<0))<< 4) | \ + (((0<<3)|(0<<0))<< 8) | \ + (((0<<3)|(0<<0))<<12) | \ + (((0<<3)|(0<<0))<<16) | \ + (((0<<3)|(0<<0))<<20) | \ + (((0<<3)|(0<<0))<<24) | \ + (((0<<3)|(0<<0))<<28) + .long 0x74, 0xffffffff, 0 + + /* DRT - DRAM Time Register + * 0x78 + * [31:30] Reserved + * [29:29] Back to Back Write-Read Turn Around + * 0 == 3 clocks between WR-RD commands + * 1 == 2 clocks between WR-RD commands + * [28:28] Back to Back Read-Write Turn Around + * 0 == 5 clocks between RD-WR commands + * 1 == 4 clocks between RD-WR commands + * [27:27] Back to Back Read Turn Around + * 0 == 4 clocks between RD commands + * 1 == 3 clocks between RD commands + * [26:24] Read Delay (tRD) + * 000 == 7 clocks + * 001 == 6 clocks + * 010 == 5 clocks + * Others == Reserved + * [23:19] Reserved + * [18:16] DRAM idle timer + * 000 == infinite + * 011 == 16 dram clocks + * 001 == Datasheet says reserved, but Intel BIOS sets it + * [15:11] Reserved + * [10:09] Active to Precharge (tRAS) + * 00 == 7 clocks + * 01 == 6 clocks + * 10 == 5 clocks + * 11 == Reserved + * [08:06] Reserved + * [05:04] Cas Latency (tCL) + * 00 == 2.5 Clocks + * 01 == 2.0 Clocks + * 10 == 1.5 Clocks + * 11 == Reserved + * [03:03] Write Ras# to Cas# Delay (tRCD) + * 0 == 3 DRAM Clocks + * 1 == 2 DRAM Clocks + * [02:01] Read RAS# to CAS# Delay (tRCD) + * 00 == reserved + * 01 == reserved + * 10 == 3 DRAM Clocks + * 11 == 2 DRAM Clocks + * [00:00] DRAM RAS# to Precharge (tRP) + * 0 == 3 DRAM Clocks + * 1 == 2 DRAM Clocks + */ +#define DRT_CAS_2_5 (0<<4) +#define DRT_CAS_2_0 (1<<4) +#define DRT_CAS_1_5 (2<<4) +#define DRT_CAS_MASK (3<<4) + +#if CAS_LATENCY == CAS_2_5 +#define DRT_CL DRT_CAS_2_5 +#elif CAS_LATENCY == CAS_2_0 +#define DRT_CL DRT_CAS_2_0 +#elif CAS_LATENCY == CAS_1_5 +#define DRT_CL DRT_CAS_1_5 +#endif + + /* Most aggressive settings possible */ +# .long 0x78, 0xc0fff8c4, (1<<29)|(1<<28)|(1<<27)|(2<<24)|(2<<9)|DRT_CL|(1<<3)|(1<<1)|(1<<0) + .long 0x78, 0xc0f8f8c0, (1<<29)|(1<<28)|(1<<27)|(1<<24)|(1<<16)|(2<<9)|DRT_CL|(1<<3)|(3<<1)|(1<<0) + + /* FIXME why was I attempting to set a reserved bit? */ + /* 0x0100040f */ + + /* DRC - DRAM Contoller Mode Register + * 0x7c + * [31:30] Reserved + * [29:29] Initialization Complete + * 0 == Not Complete + * 1 == Complete + * [28:23] Reserved + * [22:22] Channels + * 0 == Single channel + * 1 == Dual Channel + * [21:20] DRAM Data Integrity Mode + * 00 == Disabled, no ECC + * 01 == Reserved + * 10 == Error checking, using chip-kill, with correction + * 11 == Reserved + * [19:18] Reserved + * Must equal 01 + * [17:17] Reserved Intel BIOS sets this to 1 + * [16:16] Command Per Clock - Address/Control Assertion Rule (CPC) + * 0 == 2n Rule + * 1 == 1n rule + * [15:11] Reserved + * [10:08] Refresh mode select + * 000 == Refresh disabled + * 001 == Refresh interval 15.6 usec + * 010 == Refresh interval 7.8 usec + * 011 == Refresh interval 64 usec + * 111 == Refresh every 64 clocks (fast refresh) + * [07:07] Reserved + * [06:04] Mode Select (SMS) + * 000 == Self Refresh Mode + * 001 == NOP Command + * 010 == All Banks Precharge + * 011 == Mode Register Set + * 100 == Extended Mode Register Set + * 101 == Reserved + * 110 == CBR Refresh + * 111 == Normal Operation + * [03:00] Reserved + */ +# .long 0x7c, 0xffcefcff, (1<<22)|(2 << 20)|(1 << 16)| (0 << 8) + .long 0x7c, 0xff8cfcff, (1<<22)|(2 << 20)|(1 << 17)|(1 << 16)| (0 << 8) + + /* CLOCK_DIS - CK/CK# Disable Register + * 0x8C + * [7:4] Reserved + * [3:3] CK3 + * 0 == Enable + * 1 == Disable + * [2:2] CK2 + * 0 == Enable + * 1 == Disable + * [1:1] CK1 + * 0 == Enable + * 1 == Disable + * [0:0] CK0 + * 0 == Enable + * 1 == Disable + */ + .long 0x8C, 0xfffffff0, 0xf + + /* TOLM - Top of Low Memory Register + * 0xC4 - 0xC5 + * [15:11] Top of low memory (TOLM) + * The address below 4GB that should be treated as RAM, + * on a 128MB granularity. + * [10:00] Reserved + */ + /* REMAPBASE - Remap Base Address Regsiter + * 0xC6 - 0xC7 + * [15:10] Reserved + * [09:00] Remap Base Address [35:26] 64M aligned + * Bits [25:0] are assumed to be 0. + */ + .long 0xc4, 0xfc0007ff, (0x2000 << 0) | (0x3ff << 16) + /* REMAPLIMIT - Remap Limit Address Register + * 0xC8 - 0xC9 + * [15:10] Reserved + * [09:00] Remap Limit Address [35:26] 64M aligned + * When remaplimit < remapbase this register is disabled. + */ + .long 0xc8, 0xfffffc00, 0 + /* DVNP - Device Not Present Register + * 0xE0 - 0xE1 + * [15:05] Reserved + * [04:04] Device 4 Function 1 Present + * 0 == Present + * 1 == Absent + * [03:03] Device 3 Function 1 Present + * 0 == Present + * 1 == Absent + * [02:02] Device 2 Function 1 Present + * 0 == Present + * 1 == Absent + * [01:01] Reserved + * [00:00] Device 0 Function 1 Present + * 0 == Present + * 1 == Absent + */ + .long 0xe0, 0xffffffe2, (1<<4)|(1<<3)|(1<<2)|(0<<0) + +constant_register_values_end: + + /* + * Routine: ram_set_registers + * Arguments: none + * Results: none + * Trashed: %eax, %ebx, %ecx, %edx, %esi, %eflags + * Effects: Do basic ram setup that does not depend on serial + * presence detect information. + * This sets PCI configuration registers to known good + * values based on the table: + * constant_register_values + * Which are a triple of configuration regiser, mask, and value. + * + */ + /* DDR RECOMP/SCOMP table */ + .p2align 3 +ddr_rcomp_scomp_table: + /* register, function 2, function 3 */ + .long 0x054, 0x000000000, 0x000000000 + .long 0x058, 0x076433221, 0x076433221 + .long 0x05c, 0x0fedca988, 0x0fedca988 + .long 0x060, 0x0ffffffff, 0x0ffffffff + .long 0x064, 0x000000000, 0x000000000 + .long 0x068, 0x076433221, 0x076433221 + .long 0x06c, 0x0fedca988, 0x0fedca988 + .long 0x070, 0x0ffffffff, 0x0ffffffff + .long 0x084, 0x000000000, 0x099999999 + .long 0x088, 0x076433221, 0x099999999 + .long 0x08c, 0x0fedca988, 0x099999999 + .long 0x090, 0x0ffffffff, 0x099999999 + .long 0x094, 0x000000000, 0x0aaaaaaaa + .long 0x098, 0x076433221, 0x0aaaaaaaa + .long 0x09c, 0x0fedca988, 0x0aaaaaaaa + .long 0x0a0, 0x0ffffffff, 0x0aaaaaaaa + .long 0x0b4, 0x000000000, 0x000000000 + .long 0x0b8, 0x076433221, 0x076433221 + .long 0x0bc, 0x0fedca988, 0x0fedca988 + .long 0x0c0, 0x0ffffffff, 0x0ffffffff + .long 0x0c4, 0x000000000, 0x000000000 + .long 0x0c8, 0x076433221, 0x076433221 + .long 0x0cc, 0x0fedca988, 0x0fedca988 + .long 0x0d0, 0x0ffffffff, 0x0ffffffff +ddr_rcomp_scomp_table_end: + + .p2align 3 +ram_set_registers: + CALL_LABEL(ram_set_rcomp_regs) + CALL_LABEL(ram_set_d0f0_regs) + RET_LABEL(ram_set_registers) +ram_set_rcomp_regs: + movl $0x0e0, %eax /*enable device 0 functions 2 & 3 */ + PCI_READ_CONFIG_BYTE + andb $~(1<<1), %al + movb %al, %dl /* Put data in dl */ + movl $0x0e0, %eax /* write to offset e0 */ + PCI_WRITE_CONFIG_BYTE + + /* load the tables in device 0 functions 2 and 3 */ + movl $ddr_rcomp_scomp_table, %ebx +1: movl 0(%ebx), %eax /* get the register address */ + orl $0x200, %eax /* set to function 2 */ + movl 4(%ebx), %ecx /* get the data for function 2 */ + PCI_WRITE_CONFIG_DWORD + movl 0(%ebx), %eax /* get the register address */ + orl $0x300, %eax /* set to function 3 */ + movl 8(%ebx), %ecx /* get the data for function 3 */ + PCI_WRITE_CONFIG_DWORD + addl $12, %ebx + cmpl $ddr_rcomp_scomp_table_end, %ebx + jb 1b + + movl $0x088, %eax /* RCOMP evaluation phase */ + PCI_READ_CONFIG_BYTE + andb $~(1<<5), %al + movb %al, %dl /* Put data in dl */ + movb %al, %cl /* save the byte */ + movl $0x088, %eax /* write to offset 88 */ + PCI_WRITE_CONFIG_BYTE + orb $(1<<5), %cl + movb %cl, %dl /* Put data in dl */ + movl $0x088, %eax /* write to offset 88 */ + PCI_WRITE_CONFIG_BYTE +2: movl $0x088, %eax /* poll for RCOMP evaluation complete */ + PCI_READ_CONFIG_BYTE + andb $(1<<5), %al + jnz 2b + movl $0x088, %eax /* RCOMP/SCOMP register update */ + PCI_READ_CONFIG_BYTE + andb $~(1<<6), %al + movb %al, %dl /* Put data in dl */ + movb %al, %cl /* save the byte */ + movl $0x088, %eax /* write to offset 88 */ + PCI_WRITE_CONFIG_BYTE + orb $(1<<6), %cl + movb %cl, %dl /* Put data in dl */ + movl $0x088, %eax /* write to offset 88 */ + PCI_WRITE_CONFIG_BYTE +3: movl $0x088,%eax /* poll for RCOMP/SCOMP update complete */ + PCI_READ_CONFIG_BYTE + andb $(1<<6), %al + jnz 3b + + /* place the command clock drive strength comp in static override */ + movl $0x0380, %eax /* read function 3 offset 80 */ + PCI_READ_CONFIG_DWORD + /* not sure this next section is correct, documentation on device 0 + function 3, register 80 is lacking. */ + movl %eax, %ecx + + andl $0xff01ffff, %ecx + shrl $7, %eax + andl $0x00fe0000, %eax + orl %eax, %ecx + movl $0x0380, %eax + PCI_WRITE_CONFIG_DWORD /* Set pull up values */ + movl %ecx, %eax + andl $0xffffff01, %ecx + shrl $7, %eax + andl $0x000000fe, %eax + orl %eax, %ecx + movl $0x0380, %eax + PCI_WRITE_CONFIG_DWORD /* Set pull down values */ + orl $0x80008000, %ecx + movl $0x0380, %eax + PCI_WRITE_CONFIG_DWORD /* enable mode overide */ + + movl $0x0088, %eax /* enable periodic compensaion */ + PCI_READ_CONFIG_BYTE + orb $(1<<7), %al + mov %al, %dl + movl $0x0088, %eax + PCI_WRITE_CONFIG_BYTE + RET_LABEL(ram_set_rcomp_regs) + +ram_set_d0f0_regs: +#if DEBUG_RAM_CONFIG + CALLSP(dumpnorth) +#endif + movl $constant_register_values, %ebx + jmp ram_set_one_register_start +ram_set_one_register: +#if DEBUG_RAM_CONFIG + movl %ebx, %esi + CONSOLE_DEBUG_TX_CHAR($'C') + CONSOLE_DEBUG_TX_CHAR($':') + movl 0(%esi), %eax + CONSOLE_DEBUG_TX_HEX32(%eax) + CONSOLE_DEBUG_TX_CHAR($':') + movl 4(%esi), %eax + CONSOLE_DEBUG_TX_HEX32(%eax) + CONSOLE_DEBUG_TX_CHAR($':') + movl 8(%esi), %eax + CONSOLE_DEBUG_TX_HEX32(%eax) + CONSOLE_DEBUG_TX_CHAR($'\r') + CONSOLE_DEBUG_TX_CHAR($'\n') + movl %esi, %ebx +#endif /* DEBUG_RAM_CONFIG */ + movl 0(%ebx), %eax /* Read the original value to preserve the reserved bits */ + PCI_READ_CONFIG_DWORD + movl 4(%ebx), %edx /* Reserved bits mask */ + andl %edx, %eax /* Preserve only the reserved bits */ + movl 8(%ebx), %ecx /* Read the new values into %ecx */ + notl %edx + andl %edx, %ecx /* Keep only the unreserved bits */ + orl %eax, %ecx /* Put the two sets of bits together */ + movl 0(%ebx), %eax /* Refetch the address to write */ + PCI_WRITE_CONFIG_DWORD + addl $12, %ebx +ram_set_one_register_start: + cmpl $constant_register_values_end, %ebx + jb ram_set_one_register +#if DEBUG_RAM_CONFIG + CALLSP(dumpnorth) +#endif + RET_LABEL(ram_set_registers) + + + /* + * Routine: sdram_spd_get_page_size + * Arguments: %bl SMBUS_MEM_DEVICE + * Results: + * %edi log base 2 page size of DIMM side 1 in bits + * %esi log base 2 page size of DIMM side 2 in bits + * + * Preserved: %ebx (except %bh), %ebp + * + * Trashed: %eax, %bh, %ecx, %edx, %esp, %eflags + * Used: %eax, %ebx, %ecx, %edx, %esi, %edi, %esp, %eflags + * + * Effects: Uses serial presence detect to set %edi & %esi + * to the page size of a dimm. + * Notes: + * %bl SMBUS_MEM_DEVICE + * %edi holds the page size for the first side of the DIMM. + * %esi holds the page size for the second side of the DIMM. + * memory size is represent as a power of 2. + * + * This routine may be worth moving into generic code somewhere. + */ +sdram_spd_get_page_size: + xorl %edi, %edi + xorl %esi, %esi + + movb $4, %bh /* columns */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_page_size_out + andl $0xf, %eax + addl %eax, %edi + + /* Get the module data width and convert it to a power of two */ + movb $7, %bh /* (high byte) */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_page_size_out + andl $0xff, %eax + movl %eax, %ecx + shll $8, %ecx + + movb $6, %bh /* (low byte) */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_page_size_out + andl $0xff, %eax + orl %eax, %ecx + bsrl %ecx, %eax /* compute cheap log base 2 */ + addl %eax, %edi + + /* side two */ + movb $5, %bh /* number of physical banks */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_page_size_out + cmp $1, %al + jbe sdram_spd_get_page_size_out + + /* Start with the symmetrical case */ + movl %edi, %esi + + movb $4, %bh /* columns */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_page_size_out + testb $0xf0, %al + jz sdram_spd_get_page_size_out + movl %eax, %ecx + andl $0xf, %ecx + subl %ecx, %esi /* Subtract out columns on side 1 */ + shrl $4, %eax + andl $0xf, %eax + addl %eax, %esi /* Add in columns on side 2 */ +sdram_spd_get_page_size_out: + RET_LABEL(sdram_spd_get_page_size) + + + /* + * Routine: sdram_spd_get_width + * Arguments: %bl SMBUS_MEM_DEVICE + * Results: + * %edi width of SDRAM chips on DIMM side 1 in bits + * %esi width of SDRAM chips on DIMM side 2 in bits + * + * Preserved: %ebx (except %bh), %ebp + * + * Trashed: %eax, %bh, %ecx, %edx, %esp, %eflags + * Used: %eax, %ebx, %ecx, %edx, %esi, %edi, %esp, %eflags + * + * Effects: Uses serial presence detect to set %edi & %esi + * to the width of a dimm. + * Notes: + * %bl SMBUS_MEM_DEVICE + * %edi holds the width for the first side of the DIMM. + * %esi holds the width for the second side of the DIMM. + * memory size is represent as a power of 2. + * + * This routine may be worth moving into generic code somewhere. + */ +sdram_spd_get_width: + xorl %edi, %edi + xorl %esi, %esi + + movb $13, %bh /* sdram width */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_width_out + movl %eax, %ecx + andl $0x7f, %eax + addl %eax, %edi + + /* side two */ + movb $5, %bh /* number of physical banks */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_width_out + cmp $1, %al + jbe sdram_spd_get_width_out + + /* Start with the symmetrical case */ + movl %edi, %esi + + /* See if I need to double the width */ + testl $0x80, %ecx + jz sdram_spd_get_width_out + + /* Double the width on side 2 */ + addl %esi, %esi +sdram_spd_get_width_out: + RET_LABEL(sdram_spd_get_width) + + + /* + * Routine: sdram_spd_get_dimm_size + * Arguments: %bl SMBUS_MEM_DEVICE + * Results: + * %edi log base 2 size of DIMM side 1 in bits + * %esi log base 2 size of DIMM side 2 in bits + * + * Preserved: %ebx (except %bh), %ebp + * + * Trashed: %eax, %bh, %ecx, %edx, %esp, %eflags + * Used: %eax, %ebx, %ecx, %edx, %esi, %edi, %esp, %eflags + * + * Effects: Uses serial presence detect to set %edi & %esi + * the size of a dimm. + * Notes: + * %bl SMBUS_MEM_DEVICE + * %edi holds the memory size for the first side of the DIMM. + * %esi holds the memory size for the second side of the DIMM. + * memory size is represent as a power of 2. + * + * This routine may be worth moving into generic code somewhere. + */ + +sdram_spd_get_dimm_size: + xorl %edi, %edi + xorl %esi, %esi + + /* 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. + */ + movb $3, %bh /* rows */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_dimm_size_out + andl $0xf, %eax + addl %eax, %edi + + movb $4, %bh /* columns */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_dimm_size_out + andl $0xf, %eax + addl %eax, %edi + + movb $17, %bh /* banks */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_dimm_size_out + andl $0xff, %eax + bsrl %eax, %ecx /* compute cheap log base 2 */ + addl %ecx, %edi + + /* Get the module data width and convert it to a power of two */ + movb $7, %bh /* (high byte) */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_dimm_size_out + andl $0xff, %eax + movl %eax, %ecx + shll $8, %ecx + + movb $6, %bh /* (low byte) */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_dimm_size_out + andl $0xff, %eax + orl %eax, %ecx + bsrl %ecx, %eax /* compute cheap log base 2 */ + addl %eax, %edi + + /* side two */ + movb $5, %bh /* number of physical banks */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_dimm_size_out + cmp $1, %al + jbe sdram_spd_get_dimm_size_out + + /* Start with the symmetrical case */ + movl %edi, %esi + + movb $3, %bh /* rows */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_dimm_size_out + testb $0xf0, %al + jz sdram_spd_get_dimm_size_out + movl %eax, %ecx + andl $0xf, %ecx + subl %ecx, %esi /* Subtract out rows on side 1 */ + shrl $4, %eax + andl $0xf, %eax + addl %eax, %esi /* Add in rows on side 2 */ + + movb $4, %bh /* columns */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_dimm_size_out + movl %eax, %ecx + andl $0xf, %ecx + subl %ecx, %esi /* Subtract out columns on side 1 */ + shrl $4, %eax + andl $0xf, %eax + addl %eax, %esi /* Add in columns on side 2 */ + +sdram_spd_get_dimm_size_out: + RET_LABEL(sdram_spd_get_dimm_size) + + + + /* + * This is a place holder fill this out + * Routine: spd_set_row_attributes + * Arguments: %bl SMBUS_MEM_DEVICE + * Results: + * %edi log base 2 size of DIMM side 1 in bits + * %esi log base 2 size of DIMM side 2 in bits + * + * Preserved: %ebx (except %bh), %ebp + * + * Trashed: %eax, %bh, %ecx, %edx, %esp, %eflags + * Used: %eax, %ebx, %ecx, %edx, %esi, %edi, %esp, %eflags + * + * Effects: Uses serial presence detect to set %edi & %esi + * the size of a dimm. + * Notes: + * %bl SMBUS_MEM_DEVICE + * %edi holds the memory size for the first side of the DIMM. + * %esi holds the memory size for the second side of the DIMM. + * memory size is represent as a power of 2. + * + * This routine may be worth moving into generic code somewhere. + */ +spd_set_row_attributes: + movl $(SMBUS_MEM_DEVICE_START), %ebx + xorl %ebp, %ebp +spd_get_row_attributes: + CALL_LABEL(sdram_spd_get_page_size) + + /* Test to see if the dimm is present */ + testl %edi, %edi + jz spd_get_row_attributes_dimm_width + + /* Test for a valid dimm width */ + cmpl $15, %edi + jb unsupported_page_size + cmpl $18, %edi + ja unsupported_page_size + + /* double because I have 2 channels */ + addl $1, %edi + + /* Convert to the format needed for the DRA register */ + subl $14, %edi + + /* Place in the %ebp the dra place holder */ + movb %bl, %cl + subb $(SMBUS_MEM_DEVICE_START), %cl + shlb $3, %cl + shll %cl, %edi + orl %edi, %ebp + + /* Test to see if the second side is present */ + testl %esi, %esi + jz spd_get_row_attributes_dimm_width + + /* Test for a valid dimm width */ + cmpl $15, %esi + jb unsupported_page_size + cmpl $18, %esi + ja unsupported_page_size + + /* double because I have 2 channels */ + addl $1, %esi + + /* Convert to the format needed for the DRA register */ + subl $14, %esi + + /* Place in the %ebp the dra place holder */ + movb %bl, %cl + subb $(SMBUS_MEM_DEVICE_START), %cl + shlb $3, %cl + addb $4, %cl + shll %cl, %esi + orl %esi, %ebp + +spd_get_row_attributes_dimm_width: + /* Now add the SDRAM chip width to the DRA */ + CALL_LABEL(sdram_spd_get_width) + testl %edi, %edi + jz spd_get_row_attributes_next_dimm + cmpl $4, %edi + jne 1f + + /* Enable an x4 device */ + movl $0x08, %edi + movb %bl, %cl + subb $(SMBUS_MEM_DEVICE_START), %cl + shlb $3, %cl + shll %cl, %edi + orl %edi, %ebp +1: + testl %esi, %esi + jz spd_get_row_attributes_next_dimm + cmpl $4, %esi + jne spd_get_row_attributes_next_dimm + + /* Enable an x4 device */ + movl $0x08, %esi + movb %bl, %cl + subb $(SMBUS_MEM_DEVICE_START), %cl + shlb $3, %cl + addb $4, %cl + shll %cl, %esi + orl %esi, %ebp + +spd_get_row_attributes_next_dimm: + /* go to the next DIMM */ + addb $(SMBUS_MEM_DEVICE_INC), %bl /* increment the smbus device */ + cmpb $SMBUS_MEM_DEVICE_END, %bl + jbe spd_get_row_attributes + + /* Write the new row attributes register */ + movl $0x70, %eax + movl %ebp, %ecx + PCI_WRITE_CONFIG_DWORD + + RET_LABEL(spd_set_row_attributes) + + /* + * Routine: sdram_read_paired_byte + * Arguments: %esp return address + * %bl device on the smbus to read from + * %bh address on the smbus to read + * Results: + * zf clear + * byte read in %al + * On Error: + * zf set + * %eax trashed + * + * Preserved: %ebx, %esi, %edi + * + * Trashed: %eax, %ecx, %edx, %ebp, %esp, %eflags + * Used: %eax, %ebx, %ecx, %edx, %esp, %eflags + * + * Effects: Reads two spd bytes from both ram channesl + * and errors if they are not equal. + * It then returns the equal result. + */ +spd_read_paired_byte: + movl %esp, %ebp + CALLSP(smbus_read_byte) + setnz %cl + movb %al, %ch + addb $(SMBUS_MEM_CHANNEL_OFF), %bl + CALLSP(smbus_read_byte) + movb %ch, %ah + setnz %ch + subb $(SMBUS_MEM_CHANNEL_OFF), %bl + + /* See if dimms on both sides are equally present */ + cmp %cl, %ch + jne sdram_presence_mismatch + + /* Leave if I have no data */ + testb %cl, %cl + jz spd_verify_byte_out + + /* Verify the data is identical */ + cmp %ah, %al + jne sdram_value_mismatch + + /* Clear the zero flag */ + testb %cl, %cl +spd_verify_byte_out: + movl %ebp, %esp + RETSP + + /* + * Routine: spd_verify_dimms + * Arguments: none + * Results: none + * Preserved: none + * Trashed: %eax, %ebx, %ecx, %edx, %ebp, %esi, %edi, %esp, %eflags + * Used: %eax, %ebx, %ecx, %edx, %ebp, %esi, %edi, %esp, %eflags + * + * Effects: + * - Verify all interesting spd information + * matches for both dimm channels. + * - Additional error checks that can be easily done + * here are computed as well, so I don't need to + * worry about them later. + */ +spd_verify_dimms: + movl $(SMBUS_MEM_DEVICE_START), %ebx +spd_verify_dimm: + /* Verify this is DDR SDRAM */ + movb $2, %bh + CALLSP(spd_read_paired_byte) + jz spd_verify_next_dimm + cmpb $7, %al + jne invalid_dimm_type + + /* Verify the row addresses */ + movb $3, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + testb $0x0f, %al + jz spd_invalid_data + + /* Column addresses */ + movb $4, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + testb $0xf, %al + jz spd_invalid_data + + /* Physical Banks */ + movb $5, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + cmp $1, %al + jb spd_invalid_data + cmp $2, %al + ja spd_invalid_data + + /* Module Data Width */ + movb $7, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + cmpb $0, %al + jne spd_invalid_data + + movb $6, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + cmpb $64, %al + je 1f + cmpb $72, %al + je 1f + jmp spd_unsupported_data +1: + + /* Cycle time at highest CAS latency CL=X */ + movb $9, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + + /* SDRAM type */ + movb $11, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + + /* Refresh Interval */ + movb $12, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + + /* SDRAM Width */ + movb $13, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + andb $0x7f, %al + cmpb $4, %al + je 1f + cmpb $8, %al + je 1f + jmp spd_unsupported_data +1: + + /* Back-to-Back Random Column Accesses */ + movb $15, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + testb %al, %al + jz spd_invalid_data + cmpb $4, %al + ja spd_unsupported_data + + /* Burst Lengths */ + movb $16, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + testb $(1<<2), %al + jz spd_unsupported_data + + /* Logical Banks */ + movb $17, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + testb %al, %al + jz spd_invalid_data + + /* Supported CAS Latencies */ + movb $18, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + testb $(1 << 1), %al /* CL 1.5 */ + jnz 1f + testb $(1 << 2), %al /* CL 2.0 */ + jnz 1f + testb $(1 << 3), %al /* CL 2.5 */ + jnz 1f + jmp spd_unsupported_data +1: + + /* Cycle time at Cas Latency (CLX - 0.5) */ + movb $23, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + + /* Cycle time at Cas Latency (CLX - 1.0) */ + movb $26, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + + /* tRP Row precharge time */ + movb $27, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + testb $0xfc, %al + jz spd_invalid_data + + + /* tRCD RAS to CAS */ + movb $29, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + testb $0xfc, %al + jz spd_invalid_data + + /* tRAS Activate to Precharge */ + movb $30, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + testb %al, %al + jz spd_invalid_data + + /* Module Bank Density */ + movb $31, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + testb $(1<<2), %al /* 16MB */ + jnz spd_unsupported_data + testb $(1<<3), %al + jnz spd_unsupported_data /* 32MB */ + + /* Address and Command Hold Time After Clock */ + movb $33, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + +spd_verify_next_dimm: + /* go to the next DIMM */ + addb $(SMBUS_MEM_DEVICE_INC), %bl /* increment the smbus device */ + cmpb $SMBUS_MEM_DEVICE_END, %bl + jbe spd_verify_dimm +spd_verify_dimms_out: + RET_LABEL(spd_verify_dimms) + + .section ".rom.data" +spd_pre_init: .string "Reading SPD data...\r\n" +spd_pre_set: .string "setting based on SPD data...\r\n" +spd_post_init: .string "done\r\n" + .previous + + +refresh_rate_rank: + /* Refresh rates ordered from most conservative (lowest) + * to most agressive (highest) + /* disabled 0 -> rank 3 + * 15.6usec 1 -> rank 1 + * 7.8 usec 2 -> rank 0 + * 64usec 3 -> rank 2 + */ + .byte 3, 1, 0, 2 +refresh_rate_index: + /* Map the spd refresh rates to memory controller settings + * 15.625us -> 15.6us + * 3.9us -> err + * 7.8us -> 7.8us + * 31.3s -> 15.6us + * 62.5us -> 15.6us + * 125us -> 64us + */ + .byte 1, 0xff, 2, 1, 1, 3 +#define MAX_SPD_REFRESH_RATE 5 + +spd_set_dram_controller_mode: + /* Walk through all dimms and find the interesection of the support + * for ecc sdram and refresh rates + */ + movl $(SMBUS_MEM_DEVICE_START), %ebx + /* Read the inititial state */ + movl $0x7c, %eax + PCI_READ_CONFIG_DWORD + movl %eax, %esi + +#if USE_OPTION_TABLE == 1 + /* Test if ECC cmos option is enabled */ + movb $RTC_BOOT_BYTE, %al + outb %al, $0x70 + inb $0x71, %al + testb $(1<<2), %al + jnz 1f + /* Clear the ecc enable */ + andl $~(3 << 20), %esi +1: +#endif +spd_get_dram_controller_mode: + + /* Test to see if I have ecc sdram */ + movb $11, %bh /* SDRAM type */ + CALLSP(smbus_read_byte) + jz spd_set_dram_controller_mode_next_dimm + cmpb $2, %al + je spd_ecc + /* Clear the ecc enable */ + andl $~(3 << 20), %esi +spd_ecc: + movb $12, %bh /* SDRAM refresh rate */ + CALLSP(smbus_read_byte) + jz spd_set_dram_controller_mode_next_dimm + andl $0x7f, %eax + cmpb $MAX_SPD_REFRESH_RATE, %al + ja unsupported_refresh_rate + cmpb $0xff, %al + je unsupported_refresh_rate + xorl %ecx, %ecx + movb refresh_rate_index(%eax, 1), %cl + + /* Isolate the old refresh rate setting */ + movl %esi, %edx + shrl $8, %edx + andl $3, %edx + + /* Load the refresh rate ranks */ + movb refresh_rate_rank(%edx), %dh + movb refresh_rate_rank(%ecx), %dl + + /* See if the new refresh rate is more conservative than the old + * refresh rate setting. (Lower ranks are more conservative) + */ + cmpb %dh, %dl + jae 1f + /* Clear the old refresh rate */ + andl $~(3<<8), %esi + /* Move in the new refresh rate */ + shll $8, %ecx + orl %ecx, %esi +1: + + movb $33, %bh /* Address and command hold time after clock */ + CALLSP(smbus_read_byte) + jz spd_set_dram_controller_mode_next_dimm + cmpb $0xa0, %al /* At 133Mhz this constant should be 0x75 */ + jb 1f + andl $~(1<<16), %esi /* Use two clock cyles instead of one */ +1: + +spd_set_dram_controller_mode_next_dimm: + /* go to the next DIMM */ + addb $(SMBUS_MEM_DEVICE_INC), %bl /* increment the smbus device */ + cmpb $SMBUS_MEM_DEVICE_END, %bl + jbe spd_get_dram_controller_mode + + /* Now write the controller mode */ + movl $0x7c, %eax + movl %esi, %ecx + PCI_WRITE_CONFIG_DWORD + + RET_LABEL(spd_set_dram_controller_mode) + + +spd_enable_clocks: + /* Walk through all dimms and enable clocks for those that are present. + */ + movl $(SMBUS_MEM_DEVICE_START), %ebx + /* Read the inititial state */ + movl $0x8c, %eax + PCI_READ_CONFIG_DWORD + movl %eax, %esi + +# Intel clears top bit here, should we? + andl $0x7f, %esi + +spd_get_clocks: + /* Read any spd byte to see if the dimm is present */ + movb $5, %bh /* Physical Banks */ + CALLSP(smbus_read_byte) + jz spd_enable_clocks_next_dimm + + /* Find the index of the dimm */ + movb %bl, %cl + subb $(SMBUS_MEM_DEVICE_START), %cl + /* Now construct the mask to clear the enable bit */ + movl $1, %eax + shll %cl, %eax + notl %eax + andl %eax, %esi + +spd_enable_clocks_next_dimm: + /* go to the next DIMM */ + addb $(SMBUS_MEM_DEVICE_INC), %bl /* increment the smbus device */ + cmpb $SMBUS_MEM_DEVICE_END, %bl + jbe spd_get_clocks + + movl $0x8c, %eax + movl %esi, %ecx + PCI_WRITE_CONFIG_DWORD + + /* If we have no dimm modules bail out */ + andl $0xf, %esi + cmpl $0xf, %esi + je no_memory + RET_LABEL(spd_enable_clocks) + +cas_latency_80: + /* For cas latency 2.0 0x01 works and until I see a large test sample + * I am not prepared to change this value, to the intel recommended value + * of 0x0d. Eric Biederman + */ + /* The E7501 requires b1 rather than 01 for CAS2 or memory will be hosed + * CAS 1.5 is claimed to be unsupported, will try to test that + * will need to determine correct values for other CAS values + * (perhaps b5, b1, b6?) + * Steven James 02/06/2003 + */ + +# .byte 0x05, 0x01, 0x06 + .byte 0xb5, 0xb1, 0xb6 +cas_latency_78: + .byte DRT_CAS_1_5, DRT_CAS_2_0, DRT_CAS_2_5 + +spd_set_cas_latency: + /* Walk through all dimms and find the interesection of the + * supported cas latencies. + */ + movl $(SMBUS_MEM_DEVICE_START), %ebx + /* Initially allow cas latencies 2.5, 2.0, 1.5 + * which the chipset supports. + */ + movl $((1 << 3)|(1 << 2)|(1 <<1)), %esi +spd_get_cas_latencies: + movb $18, %bh + CALLSP(smbus_read_byte) + jz spd_set_cas_latency_next_dimm + + /* Find the highest supported cas latency */ + bsrl %eax, %ecx + movl $1, %edi + shll %cl, %edi + + /* Remember the supported cas latencies */ + movl %eax, %ecx + + /* Verify each cas latency at 100Mhz */ + /* Verify slowest/highest CAS latency */ + movb $9, %bh + CALLSP(smbus_read_byte) + jz spd_set_cas_latency_next_dimm + + cmpb $0xa0, %al + jbe 1f + /* The bus is too fast so we cannot support this case latency */ + notl %edi + andl %edi, %ecx + notl %edi +1: + + /* Verify the highest CAS latency - 0.5 clocks */ + shrl $1, %edi + testl %edi,%edi + jz 1f + + movb $23, %bh + CALLSP(smbus_read_byte) + jz spd_set_cas_latency_next_dimm + + cmpb $0xa0, %al + jbe 1f + /* The bus is too fast so we cannot support this cas latency */ + notl %edi + andl %edi, %ecx + notl %edi +1: + + /* Verify the highest CAS latency - 1.0 clocks */ + shrl $1, %edi + testl %edi, %edi + jz 1f + + movb $25, %bh + CALLSP(smbus_read_byte) + jz spd_set_cas_latency_next_dimm + + movb $0xa0, %al + jbe 1f + /* The bus is too fast so we cannot support this cas latency */ + notl %edi + andl %edi, %ecx + notl %edi +1: + + /* Now find which cas latencies are supported for the bus */ + andl %ecx, %esi +spd_set_cas_latency_next_dimm: + /* go to the next DIMM */ + addb $(SMBUS_MEM_DEVICE_INC), %bl /* increment the smbus device */ + cmpb $SMBUS_MEM_DEVICE_END, %bl + jbe spd_get_cas_latencies + + /* After all of the arduous calculation setup with the fastest + * cas latency I can use. + */ + bsfl %esi, %eax + jz inconsistent_cas_latencies + subl $1, %eax + movl %eax, %ecx + + movl $0x78, %eax + PCI_READ_CONFIG_BYTE + andb $~(DRT_CAS_MASK), %al + orb cas_latency_78(%ecx), %al + movb %al, %dl + movl $0x78, %eax + PCI_WRITE_CONFIG_BYTE + + movl $0x88, %eax /* set master DLL reset */ + PCI_READ_CONFIG_DWORD + orl $(1<<26), %eax + movl %ecx, %ebx + movl %eax, %ecx + movl $0x88, %eax + PCI_WRITE_CONFIG_DWORD + andl $0xfc00ffff, %ecx /* set DQS delays to 2.2ns */ + orl $0x02310000, %ecx + movl $0x88, %eax + PCI_WRITE_CONFIG_DWORD + movl %ebx, %ecx + movl $0x80, %eax + movb cas_latency_80(%ecx), %dl + PCI_WRITE_CONFIG_BYTE + movl $0x88, %eax /* reset master DLL reset */ + PCI_READ_CONFIG_DWORD + andl $~(1<<26), %eax + movl %eax, %ecx + movl $0x88, %eax + PCI_WRITE_CONFIG_DWORD + + RET_LABEL(spd_set_cas_latency) + +spd_set_dram_timing: + /* Walk through all dimms and find the interesection of the + * supported dram timings. + */ + movl $(SMBUS_MEM_DEVICE_START), %ebx + /* Read the inititial state */ + movl $0x78, %eax + PCI_READ_CONFIG_DWORD + movl %eax, %esi +spd_get_dram_timing: + + /* + * tRP + */ + movb $27, %bh + CALLSP(smbus_read_byte) + jz spd_set_dram_timing_next_dimm + cmpb $(20<<2), %al + jbe 1f + /* At 100Mhz if row precharge time is above than 20ns than we + * need 3 clocks not 2 clocks. + */ + andl $~(1<<0), %esi +1: + /* + * tRCD + */ + movb $29, %bh + CALLSP(smbus_read_byte) + jz spd_set_dram_timing_next_dimm + cmpb $(20<<2), %al + jbe 1f + /* At 100Mhz if the Minimum ras to cas delay is about 20ns we + * need 3 clocks not 2 clocks. + */ + andl $~((1<<3)|(1<<1)), %esi +1: + + /* + * tRAS + */ + movb $30, %bh + CALLSP(smbus_read_byte) + jz spd_set_dram_timing_next_dimm + /* Convert tRAS from ns to 100Mhz clock cycles */ + movb $10, %dl + addb %dl, %al /* Make certain we round up */ + subb $1, %al + andl $0xff, %eax /* Clear the upper bits of eax */ + divb %dl, %al + + /* Don't even process small timings */ + cmpb $5, %al + jbe 1f + + /* Die if the value is to large */ + cmpb $7, %al + ja unsupported_rcd + + /* Convert to clocks - 5 */ + subb $5, %al + + /* Convert the existing value into clocks - 5 */ + movl %esi, %ecx + shrl $9, %ecx + andl $3, %ecx + notl %ecx + subl $1, %ecx + + /* See if we need a slower timing */ + cmpb %al, %cl + jbe 1f + + /* O.k. put in our slower timing */ + movb %al, %cl + addb $1, %cl + notl %ecx + shll $9, %ecx + andl $(3<<9), %esi + orl %ecx, %esi + +1: + /* + * tRD + */ + /* Set to a 7 clock read delay */ + andl $~(7<<24), %esi + + /* + * Back to Back Read Turn Around + */ + /* Set to a 4 clock back to back read turn around */ + andl $~(1<<27), %esi + /* + * Back to Back Read-Write Turn Around + */ + /* Set to a 5 clock back to back read to write turn around */ + andl $~(1<<28), %esi + /* + * Back to Back Write-Read Turn Around + */ + /* Set to a 3 clock back to back write to read turn around */ + andl $~(1<<29), %esi + +spd_set_dram_timing_next_dimm: + /* go to the next DIMM */ + addb $(SMBUS_MEM_DEVICE_INC), %bl /* increment the smbus device */ + cmpb $SMBUS_MEM_DEVICE_END, %bl + jbe spd_get_dram_timing + + movl $0x78, %eax + movl %esi, %ecx + PCI_WRITE_CONFIG_DWORD + + RET_LABEL(spd_set_dram_timing) + + +ram_set_spd_registers: + CONSOLE_INFO_TX_STRING($spd_pre_init) + CALL_LABEL(spd_enable_clocks) + CALL_LABEL(spd_verify_dimms) + CONSOLE_INFO_TX_STRING($spd_pre_set) + CALL_LABEL(spd_set_row_attributes) + CALL_LABEL(spd_set_dram_controller_mode) + CALL_LABEL(spd_set_cas_latency) + CALL_LABEL(spd_set_dram_timing) + CONSOLE_INFO_TX_STRING($spd_post_init) + RET_LABEL(ram_set_spd_registers) + +/* LAST_DRB_SLOT is a constant for any E7500 board */ +#define LAST_DRB_SLOT 0x67 + +spd_set_ram_size: + movl $(SMBUS_MEM_DEVICE_START), %ebx + xorl %ebp, %ebp + /* Read the necessary SPD bytes for the first dimm */ +spd_get_dimm_size: + CALL_LABEL(sdram_spd_get_dimm_size) + + /* Since I have 2 identical channels double the sizes */ + incl %edi + incl %esi + + /* Convert bits to multiples of 64MB */ + subl $29, %edi + jb 1f + movl %edi, %ecx + movl $1, %eax + shll %cl, %eax + addl %eax, %ebp +1: + /* Write the size of side 1 of the dimm */ + xorl %eax, %eax + movb %bl, %al + subl $(SMBUS_MEM_DEVICE_START), %eax + addl %eax, %eax + addl $0x60, %eax + movl %ebp, %edx + PCI_WRITE_CONFIG_BYTE + + /* Convert bits to multiples of 64MB */ + subl $29, %esi + jb 1f + movl %esi, %ecx + movl $1, %eax + shll %cl, %eax + addl %eax, %ebp +1: + /* Write the size of side 2 of the dimm */ + xorl %eax, %eax + movb %bl, %al + subl $(SMBUS_MEM_DEVICE_START), %eax + addl %eax, %eax + addl $0x61, %eax + movl %ebp, %edx + PCI_WRITE_CONFIG_BYTE + + /* go to the next DIMM */ + addb $(SMBUS_MEM_DEVICE_INC), %bl /* increment the smbus device */ + cmpb $SMBUS_MEM_DEVICE_END, %bl + jbe spd_get_dimm_size + + /* now, fill in DRBs where no physical slot exists */ + movl $(SMBUS_MEM_DEVICE_END - SMBUS_MEM_DEVICE_START), %ecx + addl %ecx, %ecx + addl $0x61, %ecx +1: + incl %ecx + cmpl $LAST_DRB_SLOT, %ecx + ja spd_set_ram_size_computed + movl %ebp, %edx + movl %ecx, %eax + PCI_WRITE_CONFIG_BYTE + jmp 1b + +spd_set_ram_size_computed: + /* For now hardset everything at 128MB boundaries */ + /* %ebp has the ram size in multiples of 64MB */ + cmpl $0, %ebp /* test if there is no mem - smbus went bad */ + jz no_memory_bad_smbus + cmpl $0x30, %ebp + jae spd_set_large_ram_size +spd_set_small_ram_size: + /* I should really adjust all of this in C after I have resources + * to all of the pcie devices. + */ + + /* Round up to 128M granularity */ + addl $1, %ebp + andl $0xfe, %ebp + shll $10, %ebp + movl $0xC4, %eax + movl %ebp, %ecx + PCI_WRITE_CONFIG_WORD + jmp spd_set_ram_size_out +spd_set_large_ram_size: + /* FIXME will this work with 3.5G of ram? */ + /* Put TOLM at 3G */ + movl $0xC4, %eax + movl $0xc000, %ecx + PCI_WRITE_CONFIG_WORD + /* Hard code a 1G remap window, right after the ram */ + cmp $0x40, %ebp + jae 1f + movl $0x40, %ebp /* Ensure we are over 4G */ +1: + movl $0xC6, %eax + movl %ebp, %ecx + PCI_WRITE_CONFIG_WORD + movl $0xC8, %eax + movl %ebp, %edx + addl $0x10, %ecx + PCI_WRITE_CONFIG_WORD + jmp spd_set_ram_size_out + +spd_set_ram_size_out: + RET_LABEL(spd_set_ram_size) + + /* I have finally seen ram bad enough to cause LinuxBIOS + * to die in mysterious ways, before booting up far + * enough to run a memory tester. This code attempts + * to catch this blatantly bad ram, with a spot check. + * For most cases you should boot all of the way up + * and run a memory tester. + */ + /* Ensure I read/write each stick of bank of memory && + * that I do more than 1000 bytes to avoid the northbridge cache. + * Only 64M of each side of each DIMM is currently mapped, + * so we can handle > 4GB of ram here. + */ +bank_msg: .asciz "Bank " +side_msg: .asciz " Side " +verify_ram: + xorl %ecx, %ecx + /* Check to see if the RAM is present, + * in the specified bank and side. + */ +1: movl %ecx, %ebx + shrl $1, %ebx + addl $((5<<8) | SMBUS_MEM_DEVICE_START), %ebx + CALLSP(smbus_read_byte) + jz 5f + testl $1, %ecx + jz 2f + cmpb $2, %al + jne 5f + + /* Display the bank and side we are spot checking. + */ +2: CONSOLE_INFO_TX_STRING($bank_msg) + movl %ecx, %ebx + shrl $1, %ebx + incl %ebx + CONSOLE_INFO_TX_HEX8(%bl) + CONSOLE_INFO_TX_STRING($side_msg) + movl %ecx, %ebx + andl $1, %ebx + CONSOLE_INFO_TX_HEX8(%bl) + + /* Compute the memory address to spot check. */ + movl %ecx, %ebx + xorl %eax, %eax +3: testl %ebx, %ebx + jz 4f + addl $0x04000000, %eax + decl %ebx + jmp 3b +4: + /* Spot check 512K of RAM */ + movl %eax, %ebx + addl $0x0007ffff, %ebx + CALLSP(spot_check) +5: + /* Now find the next bank and side to spot check */ + incl %ecx + cmpl $((SMBUS_MEM_DEVICE_END - SMBUS_MEM_DEVICE_START)<<1), %ecx + jb 1b + RET_LABEL(verify_ram) + + +ram_postinit: +#if DEBUG_RAM_CONFIG + CALLSP(dumpnorth) +#endif + /* Include a test to verify that memory is more or less working o.k. + * This test is to catch programming errors and hardware that is out of + * spec, not a test to see if the memory dimms are working 100% + */ +# CALL_LABEL(verify_ram) + CALL_LABEL(spd_set_ram_size) + RET_LABEL(ram_postinit) + + +#define FIRST_NORMAL_REFERENCE() CALL_LABEL(ram_postinit) + +#define SPECIAL_FINISHUP() CALL_LABEL(dram_finish) + + .section ".rom.data" +ecc_pre_init: .string "Initializing ECC state...\r\n" +ecc_post_init: .string "ECC state initialized.\r\n" + .previous +dram_finish: + /* Test to see if ECC support is enabled */ + movl $0x7c, %eax + PCI_READ_CONFIG_DWORD + shrl $20, %eax + andl $3, %eax + cmpb $2, %al + jne noecc_init + + CONSOLE_INFO_TX_STRING($ecc_pre_init) + /* Initialize ECC bits , use ECC zero mode (new to 7501)*/ + movl $0x52, %eax + movl $0x06, %edx + PCI_WRITE_CONFIG_BYTE + movl $0x52, %eax + movl $0x07, %edx + PCI_WRITE_CONFIG_BYTE +1: movl $0x52, %eax + PCI_READ_CONFIG_BYTE + andl $0x08, %eax + jz 1b + andl $0xfffffffc, %eax + movl %eax, %edx + movl $0x52, %eax + PCI_WRITE_CONFIG_BYTE + + CONSOLE_INFO_TX_STRING($ecc_post_init) + + /* Clear the ECC error bits */ + movl $0x0180, %eax /* dev 0, function 1, offset 80 */ + movl $0x03, %edx + PCI_WRITE_CONFIG_BYTE + movl $0x0182, %eax /* dev 0, function 1, offset 82 */ + movl $0x03, %edx + PCI_WRITE_CONFIG_BYTE + + movl $0x0140, %eax /* clear dev 0, function 1, offset 40 */ + movl $(1<<18), %edx /* bit 18 by writing a 1 to it */ + PCI_WRITE_CONFIG_DWORD + movl $0x0144, %eax /* clear dev 0, function 1, offset 44 */ + movl $(1<<18), %edx /* bit 18 by writing a 1 to it */ + PCI_WRITE_CONFIG_DWORD + + movl $0x52, %eax + movl $0x0d, %edx + PCI_WRITE_CONFIG_BYTE + +noecc_init: + +#if DEBUG_RAM_CONFIG + CALLSP(dumpnorth) +#endif + CALL_LABEL(verify_ram) + RET_LABEL(dram_finish) + +#define ERRFUNC(x, str) \ + .section ".rom.data" ;\ +x##_str: ;\ + .string str ;\ + .ascii str ;\ + .previous ;\ +x: ;\ + movl $x##_str, %esi ;\ + jmp mem_err + + +ERRFUNC(invalid_dimm_type, "Invalid dimm type") +ERRFUNC(spd_missing_data, "Missing sdram spd data") +ERRFUNC(spd_invalid_data, "Invalid sdram spd data") +ERRFUNC(spd_unsupported_data, "Unsupported sdram spd value") +ERRFUNC(unsupported_page_size, "Unsupported page size") +ERRFUNC(sdram_presence_mismatch, "DIMM presence mismatch") +ERRFUNC(sdram_value_mismatch, "spd data does not match") +ERRFUNC(unsupported_refresh_rate, "Unsuported spd refresh rate") +ERRFUNC(inconsistent_cas_latencies, "No cas latency supported by all dimms") +ERRFUNC(unsupported_rcd, "Unsupported ras to cas delay") +#undef ERRFUNC + +.section ".rom.data" +mem_err_err: .string "ERROR: " +mem_err_pair: .string " on dimm pair " +mem_err_byte: .string " spd byte " +.previous +mem_err: + movl %ebx, %edi + CONSOLE_ERR_TX_STRING($mem_err_err) + CONSOLE_ERR_TX_STRING(%esi) + CONSOLE_ERR_TX_STRING($mem_err_pair) + movl %edi, %ebx + subb $(SMBUS_MEM_DEVICE_START), %bl + CONSOLE_ERR_TX_HEX8(%bl) + CONSOLE_ERR_TX_STRING($mem_err_byte) + movl %edi, %ebx + CONSOLE_ERR_TX_HEX8(%bh) + jmp mem_stop + +intel_E7500_out: diff --git a/src/northbridge/intel/E7501/reset_test.inc b/src/northbridge/intel/E7501/reset_test.inc new file mode 100644 index 0000000000..f615ecb7a8 --- /dev/null +++ b/src/northbridge/intel/E7501/reset_test.inc @@ -0,0 +1,10 @@ +#define MCH_DRC 0x7c +#define DRC_DONE (1 << 29) + /* If I have already booted once skip a bunch of initialization */ + /* To see if I have already booted I check to see if memory + * has been enabled. + */ + movl $MCH_DRC, %eax + PCI_READ_CONFIG_DWORD + testl $DRC_DONE, %eax + setnz %al diff --git a/src/northbridge/intel/E7501/sdram_enable.inc b/src/northbridge/intel/E7501/sdram_enable.inc new file mode 100644 index 0000000000..0141551572 --- /dev/null +++ b/src/northbridge/intel/E7501/sdram_enable.inc @@ -0,0 +1,132 @@ +jmp sdram_enable_out + +#ifndef RAM_NOP +#error RAM_NOP not defined +#endif + +#ifndef RAM_PRECHARGE +#error RAM_PRECHARGE not defined +#endif + +#ifndef RAM_EMRS +#error RAM_EMRS not defined +#endif + +#ifndef RAM_MRS +#error RAM_MRS not defined +#endif + +#ifndef RAM_CBR +#error RAM_CBR not defined +#endif + +#ifndef RAM_NORMAL +#error RAM_NORMAL not defined +#endif + +#if ASM_CONSOLE_LOGLEVEL > BIOS_DEBUG +ram_enable_1: .string "Ram Enable 1\r\n" +ram_enable_2: .string "Ram Enable 2\r\n" +ram_enable_3: .string "Ram Enable 3\r\n" +ram_enable_4: .string "Ram Enable 4\r\n" +ram_enable_5: .string "Ram Enable 5\r\n" +ram_enable_6: .string "Ram Enable 6\r\n" +ram_enable_7: .string "Ram Enable 7\r\n" +ram_enable_8: .string "Ram Enable 8\r\n" +ram_enable_9: .string "Ram Enable 9\r\n" +ram_enable_10: .string "Ram Enable 10\r\n" +ram_enable_11: .string "Ram Enable 11\r\n" +#endif + + /* Estimate that SLOW_DOWN_IO takes about 50&76us*/ + /* delay for 200us */ + +#define DO_DELAY \ + movl $16, %edi ; \ +1: SLOW_DOWN_IO ; \ + decl %edi ; \ + jnz 1b + + +#define EXTRA_DELAY DO_DELAY + +enable_sdram: + /* 1 & 2 Power up and start clocks */ + CONSOLE_DEBUG_TX_STRING($ram_enable_1) + CONSOLE_DEBUG_TX_STRING($ram_enable_2) + + /* A 200us delay is needed */ + + DO_DELAY + EXTRA_DELAY + + /* 3. Apply NOP */ + CONSOLE_DEBUG_TX_STRING($ram_enable_3) + RAM_NOP() + EXTRA_DELAY + + /* 4 Precharge all */ + CONSOLE_DEBUG_TX_STRING($ram_enable_4) + RAM_PRECHARGE() + EXTRA_DELAY + + /* wait until the all banks idle state... */ + /* 5. Issue EMRS to enable DLL */ + CONSOLE_DEBUG_TX_STRING($ram_enable_5) + RAM_EMRS() + EXTRA_DELAY + + /* 6. Reset DLL */ + CONSOLE_DEBUG_TX_STRING($ram_enable_6) + RAM_MRS(1) + EXTRA_DELAY + + /* Ensure a 200us delay between the DLL reset in step 6 and the final + * mode register set in step 9. + * Infineon needs this before any other command is sent to the ram. + */ + DO_DELAY + EXTRA_DELAY + + /* 7 Precharge all */ + CONSOLE_DEBUG_TX_STRING($ram_enable_7) + RAM_PRECHARGE() + EXTRA_DELAY + + /* 8 Now we need 2 AUTO REFRESH / CBR cycles to be performed */ + CONSOLE_DEBUG_TX_STRING($ram_enable_8) + RAM_CBR() + EXTRA_DELAY + RAM_CBR() + EXTRA_DELAY + /* And for good luck 6 more CBRs */ + RAM_CBR() + EXTRA_DELAY + RAM_CBR() + EXTRA_DELAY + RAM_CBR() + EXTRA_DELAY + RAM_CBR() + EXTRA_DELAY + RAM_CBR() + EXTRA_DELAY + RAM_CBR() + EXTRA_DELAY + + /* 9 mode register set */ + CONSOLE_DEBUG_TX_STRING($ram_enable_9) + RAM_MRS(0) + EXTRA_DELAY + + /* 10 DDR Receive FIFO RE-Sync */ + CONSOLE_DEBUG_TX_STRING($ram_enable_10) + RAM_RESET_DDR_PTR() + EXTRA_DELAY + + /* 11 normal operation */ + CONSOLE_DEBUG_TX_STRING($ram_enable_11) + RAM_NORMAL() + + RET_LABEL(enable_sdram) + +sdram_enable_out: diff --git a/src/ram/spotcheck.inc b/src/ram/spotcheck.inc index b0bc0388a5..7cca497de7 100644 --- a/src/ram/spotcheck.inc +++ b/src/ram/spotcheck.inc @@ -12,6 +12,10 @@ #ifndef CONFIG_MAX_SPOTCHECK_ERRORS #define CONFIG_MAX_SPOTCHECK_ERRORS 20 #endif + +# debugging SMJ +#define NO_HLT + spot_test: .string " Spot checking: " spot_error: .string "Blatant memory errors found.\r\n" @@ -79,15 +83,19 @@ spot_check: incl %esi cmpl $CONFIG_MAX_SPOTCHECK_ERRORS, %esi jbe 3b +#ifndef NO_HLT 5: CONSOLE_INFO_TX_STRING($spot_error) intel_chip_post_macro(0xf1) jmp .Lhlt +#endif 6: +#ifndef NO_HLT /* If any memory errors occured hlt */ testl %esi, %esi jnz 5b +#endif mov %ebp, %esp RETSP