summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cpu/p6/Config.lb7
-rw-r--r--src/cpu/p6/apic_timer.c26
-rw-r--r--src/cpu/p6/chip.h5
-rw-r--r--src/cpu/p6/cpufixup.c24
-rw-r--r--src/cpu/p6/disable_mmx_sse.inc27
-rw-r--r--src/cpu/p6/enable_mmx_sse.inc25
-rw-r--r--src/include/device/pci_ids.h14
-rw-r--r--src/mainboard/tyan/s2735/Config.lb222
-rw-r--r--src/mainboard/tyan/s2735/auto.c135
-rw-r--r--src/mainboard/tyan/s2735/chip.h6
-rw-r--r--src/mainboard/tyan/s2735/cmos.layout96
-rw-r--r--src/mainboard/tyan/s2735/failover.c59
-rw-r--r--src/mainboard/tyan/s2735/irq_tables.c40
-rw-r--r--src/mainboard/tyan/s2735/mainboard.c183
-rw-r--r--src/mainboard/tyan/s2735/mptable.c165
-rw-r--r--src/northbridge/intel/e7501/Config.lb4
-rw-r--r--src/northbridge/intel/e7501/chip.h5
-rw-r--r--src/northbridge/intel/e7501/debug.c164
-rw-r--r--src/northbridge/intel/e7501/e7501.h0
-rw-r--r--src/northbridge/intel/e7501/northbridge.c151
-rw-r--r--src/northbridge/intel/e7501/raminit.c2099
-rw-r--r--src/northbridge/intel/e7501/raminit.h12
-rw-r--r--src/northbridge/intel/e7501/reset_test.c18
-rw-r--r--src/southbridge/intel/i82801er/Config.lb11
-rw-r--r--src/southbridge/intel/i82801er/cmos_failover.c16
-rw-r--r--src/southbridge/intel/i82801er/i82801er.c57
-rw-r--r--src/southbridge/intel/i82801er/i82801er.h81
-rw-r--r--src/southbridge/intel/i82801er/i82801er_ac97.c41
-rw-r--r--src/southbridge/intel/i82801er/i82801er_early_smbus.c156
-rw-r--r--src/southbridge/intel/i82801er/i82801er_ide.c53
-rw-r--r--src/southbridge/intel/i82801er/i82801er_lpc.c219
-rw-r--r--src/southbridge/intel/i82801er/i82801er_nic.c21
-rw-r--r--src/southbridge/intel/i82801er/i82801er_pci.c33
-rw-r--r--src/southbridge/intel/i82801er/i82801er_reset.c7
-rw-r--r--src/southbridge/intel/i82801er/i82801er_sata.c75
-rw-r--r--src/southbridge/intel/i82801er/i82801er_smbus.c92
-rw-r--r--src/southbridge/intel/i82801er/i82801er_usb.c54
-rw-r--r--src/southbridge/intel/i82801er/i82801er_usb2.c39
-rw-r--r--src/southbridge/intel/i82870/82870.h10
-rw-r--r--src/southbridge/intel/i82870/Config.lb3
-rw-r--r--src/southbridge/intel/i82870/p64h2_ioapic.c89
-rw-r--r--src/southbridge/intel/i82870/p64h2_pci_parity.c26
-rw-r--r--src/southbridge/intel/i82870/p64h2_pcibridge.c39
-rw-r--r--src/superio/winbond/w83627hf/superio.c163
44 files changed, 4761 insertions, 11 deletions
diff --git a/src/cpu/p6/Config.lb b/src/cpu/p6/Config.lb
index d4918f9147..8242a6e874 100644
--- a/src/cpu/p6/Config.lb
+++ b/src/cpu/p6/Config.lb
@@ -1,5 +1,10 @@
uses INTEL_PPRO_MTRR
+uses CPU_FIXUP
dir /cpu/p5
-object cpufixup.o
+config chip.h
+if CPU_FIXUP
+ object cpufixup.o
+ object apic_timer.o
+end
object mtrr.o
object pgtbl.o
diff --git a/src/cpu/p6/apic_timer.c b/src/cpu/p6/apic_timer.c
new file mode 100644
index 0000000000..fa7e9b905f
--- /dev/null
+++ b/src/cpu/p6/apic_timer.c
@@ -0,0 +1,26 @@
+#include <stdint.h>
+#include <delay.h>
+#include <cpu/p6/msr.h>
+#include <cpu/p6/apic.h>
+
+void init_timer(void)
+{
+ /* Set the apic timer to no interrupts and periodic mode */
+ apic_write(APIC_LVTT, (1 << 17)|(1<< 16)|(0 << 12)|(0 << 0));
+ /* Set the divider to 1, no divider */
+ apic_write(APIC_TDCR, APIC_TDR_DIV_1);
+ /* Set the initial counter to 0xffffffff */
+ apic_write(APIC_TMICT, 0xffffffff);
+}
+
+void udelay(unsigned usecs)
+{
+ uint32_t start, value, ticks;
+ /* Calculate the number of ticks to run, our FSB runs a 200Mhz */
+ ticks = usecs * 200;
+ start = apic_read(APIC_TMCCT);
+ do {
+ value = apic_read(APIC_TMCCT);
+ } while((start - value) < ticks);
+
+}
diff --git a/src/cpu/p6/chip.h b/src/cpu/p6/chip.h
new file mode 100644
index 0000000000..bfcdf79ed7
--- /dev/null
+++ b/src/cpu/p6/chip.h
@@ -0,0 +1,5 @@
+extern struct chip_control cpu_p6_control;
+
+struct cpu_p6_config {
+ int nothing;
+};
diff --git a/src/cpu/p6/cpufixup.c b/src/cpu/p6/cpufixup.c
index e5cd3fc017..f611524fab 100644
--- a/src/cpu/p6/cpufixup.c
+++ b/src/cpu/p6/cpufixup.c
@@ -351,3 +351,27 @@ void p6_cpufixup(struct mem_range *mem)
printk_debug("Updating microcode\n");
display_cpuid_update_microcode();
}
+
+
+static
+void p6_enable(struct chip *chip, enum chip_pass pass)
+{
+
+ struct cpu_p6_config *conf = (struct cpu_p6_config *)chip->chip_info;
+
+ switch (pass) {
+ case CONF_PASS_PRE_CONSOLE:
+ break;
+ case CONF_PASS_PRE_PCI:
+ init_timer();
+ break;
+ default:
+ /* nothing yet */
+ break;
+ }
+}
+
+struct chip_control cpu_p6_control = {
+ .enable = p6_enable,
+ .name = "Intel P6 CPU",
+};
diff --git a/src/cpu/p6/disable_mmx_sse.inc b/src/cpu/p6/disable_mmx_sse.inc
new file mode 100644
index 0000000000..5ce9dfdc1f
--- /dev/null
+++ b/src/cpu/p6/disable_mmx_sse.inc
@@ -0,0 +1,27 @@
+ /* Clear out an mmx state */
+ emms
+
+ /*
+ * Put the processor back into a reset state
+ * with respect to the xmm registers.
+ */
+
+ pxor %xmm0, %xmm0
+ pxor %xmm1, %xmm1
+ pxor %xmm2, %xmm2
+ pxor %xmm3, %xmm3
+ pxor %xmm4, %xmm4
+ pxor %xmm5, %xmm5
+ pxor %xmm6, %xmm6
+ pxor %xmm7, %xmm7
+
+ /* Disable floating point emulation */
+ movl %cr0, %eax
+ andl $~(1<<2), %eax
+ movl %eax, %cr0
+
+ /* Disable sse instructions */
+ movl %cr4, %eax
+ andl $~(3<<9), %eax
+ movl %eax, %cr4
+
diff --git a/src/cpu/p6/enable_mmx_sse.inc b/src/cpu/p6/enable_mmx_sse.inc
new file mode 100644
index 0000000000..f0b2487b8c
--- /dev/null
+++ b/src/cpu/p6/enable_mmx_sse.inc
@@ -0,0 +1,25 @@
+ /* Save the BIST result */
+ movl %eax, %ebp
+
+ /*
+ * Enabling mmx registers is a noop
+ * Enable the use of the xmm registers
+ */
+
+ /* Enable sse instructions */
+ movl %cr4, %eax
+ orl $(1<<9), %eax
+ movl %eax, %cr4
+
+ /* Disable floating point emulation */
+ movl %cr0, %eax
+ andl $~(1<<2), %eax
+ movl %eax, %cr0
+
+ /* enable sse extension */
+ movl %cr0, %eax
+ andl $~(1<<1), %eax
+ movl %eax, %cr0
+
+ /* Restore the BIST result */
+ movl %ebp, %eax
diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h
index 586083a966..eeab66cc16 100644
--- a/src/include/device/pci_ids.h
+++ b/src/include/device/pci_ids.h
@@ -1890,6 +1890,20 @@
#define PCI_DEVICE_ID_INTEL_82801CA_1F5 0x2485
#define PCI_DEVICE_ID_INTEL_82801CA_1D2 0x2487
+#define PCI_DEVICE_ID_INTEL_82801ER_1E0 0x244e
+#define PCI_DEVICE_ID_INTEL_82801ER_1F0 0x24d0
+#define PCI_DEVICE_ID_INTEL_82801ER_1F1 0x24db
+#define PCI_DEVICE_ID_INTEL_82801ER_1F2 0x24d1
+#define PCI_DEVICE_ID_INTEL_82801ER_1F2_R 0x24df
+#define PCI_DEVICE_ID_INTEL_82801ER_1F3 0x24d3
+#define PCI_DEVICE_ID_INTEL_82801ER_1F5 0x24d5
+#define PCI_DEVICE_ID_INTEL_82801ER_1F6 0x24d6
+#define PCI_DEVICE_ID_INTEL_82801ER_1D0 0x24d2
+#define PCI_DEVICE_ID_INTEL_82801ER_1D1 0x24d4
+#define PCI_DEVICE_ID_INTEL_82801ER_1D2 0x24d7
+#define PCI_DEVICE_ID_INTEL_82801ER_1D3 0x24de
+#define PCI_DEVICE_ID_INTEL_82801ER_1D7 0x24dd
+
#define PCI_DEVICE_ID_INTEL_82870_1E0 0x1461
#define PCI_DEVICE_ID_INTEL_82870_1F0 0x1460
diff --git a/src/mainboard/tyan/s2735/Config.lb b/src/mainboard/tyan/s2735/Config.lb
new file mode 100644
index 0000000000..2b94689ba6
--- /dev/null
+++ b/src/mainboard/tyan/s2735/Config.lb
@@ -0,0 +1,222 @@
+uses HAVE_MP_TABLE
+uses HAVE_PIRQ_TABLE
+uses USE_FALLBACK_IMAGE
+uses LB_CKS_RANGE_START
+uses LB_CKS_RANGE_END
+uses LB_CKS_LOC
+uses MAINBOARD
+uses ARCH
+uses HARD_RESET_BUS
+uses HARD_RESET_DEVICE
+uses HARD_RESET_FUNCTION
+#
+#
+###
+### Set all of the defaults for an x86 architecture
+###
+#
+#
+###
+### Build the objects we have code for in this directory.
+###
+##object mainboard.o
+config chip.h
+register "fixup_scsi" = "1"
+register "fixup_vga" = "1"
+
+
+##
+## Move the default LinuxBIOS cmos range off of AMD RTC registers
+##
+default LB_CKS_RANGE_START=49
+default LB_CKS_RANGE_END=122
+default LB_CKS_LOC=123
+
+driver mainboard.o
+#dir /drvers/adaptec/7902
+#dir /drivers/si/3114
+#dir /drivers/intel/82551_ipmi
+#dir /drivers/ati/ragexl
+if HAVE_MP_TABLE object mptable.o end
+if HAVE_PIRQ_TABLE object irq_tables.o end
+#
+#default HARD_RESET_BUS=1
+#default HARD_RESET_DEVICE=4
+#default HARD_RESET_FUNCTION=0
+#
+arch i386 end
+#
+###
+### Build our 16 bit and 32 bit linuxBIOS entry code
+###
+mainboardinit cpu/i386/entry16.inc
+mainboardinit cpu/i386/entry32.inc
+mainboardinit cpu/i386/bist32.inc
+ldscript /cpu/i386/entry16.lds
+ldscript /cpu/i386/entry32.lds
+#
+###
+### Build our reset vector (This is where linuxBIOS is entered)
+###
+if USE_FALLBACK_IMAGE
+ mainboardinit cpu/i386/reset16.inc
+ ldscript /cpu/i386/reset16.lds
+else
+ mainboardinit cpu/i386/reset32.inc
+ ldscript /cpu/i386/reset32.lds
+end
+#
+#### Should this be in the northbridge code?
+mainboardinit arch/i386/lib/cpu_reset.inc
+#
+###
+### Include an id string (For safe flashing)
+###
+mainboardinit arch/i386/lib/id.inc
+ldscript /arch/i386/lib/id.lds
+#
+####
+#### This is the early phase of linuxBIOS startup
+#### Things are delicate and we test to see if we should
+#### failover to another image.
+####
+#option MAX_REBOOT_CNT=2
+if USE_FALLBACK_IMAGE
+ ldscript /arch/i386/lib/failover.lds
+end
+#
+###
+### Setup our mtrrs
+###
+#mainboardinit cpu/p6/earlymtrr.inc
+###
+### Only the bootstrap cpu makes it here.
+### Failover if we need to
+###
+#
+if USE_FALLBACK_IMAGE
+ mainboardinit ./failover.inc
+end
+
+#
+#
+###
+### Setup the serial port
+###
+mainboardinit pc80/serial.inc
+mainboardinit arch/i386/lib/console.inc
+mainboardinit cpu/i386/bist32_fail.inc
+#
+####
+#### O.k. We aren't just an intermediary anymore!
+####
+#
+###
+### When debugging disable the watchdog timer
+###
+##option MAXIMUM_CONSOLE_LOGLEVEL=7
+#default MAXIMUM_CONSOLE_LOGLEVEL=7
+#
+#if USE_FALLBACK_IMAGE mainboardinit arch/i386/lib/noop_failover.inc end
+#
+###
+### Romcc output
+###
+
+makerule ./failover.E
+ depends "$(MAINBOARD)/failover.c"
+ action "$(CPP) -I$(TOP)/src $(ROMCCPPFLAGS) $(CPPFLAGS) $(MAINBOARD)/failover.c > ./failover.E"
+end
+
+makerule ./failover.inc
+ depends "./romcc ./failover.E"
+ action "./romcc -O -o failover.inc --label-prefix=failover ./failover.E"
+end
+
+makerule ./auto.E
+ depends "$(MAINBOARD)/auto.c option_table.h"
+ action "$(CPP) -I$(TOP)/src -I. $(ROMCCPPFLAGS) $(CPPFLAGS) $(MAINBOARD)/auto.c > ./auto.E"
+end
+makerule ./auto.inc
+ depends "./romcc ./auto.E"
+ action "./romcc -O2 -mcpu=k8 -o auto.inc --label-prefix=auto ./auto.E"
+# action "./romcc -O2 ./auto.E > auto.inc"
+end
+mainboardinit cpu/p6/enable_mmx_sse.inc
+mainboardinit ./auto.inc
+mainboardinit cpu/p6/disable_mmx_sse.inc
+#
+###
+### Include the secondary Configuration files
+###
+
+config chip.h
+
+northbridge intel/e7501 "e7501"
+ pci 0:2.0
+ pci 0:0.0
+ pci 0:0.1
+ pci 0:6.0
+ southbridge intel/i82870 "i82870"
+ pci 0:1c.0
+ pci 0:1d.0
+ pci 0:1e.0
+ pci 0:1f.0
+ end
+end
+ southbridge intel/i82801er "i82801er"
+ pci 0:1f.0
+ pci 0:1d.0 on
+ pci 0:1d.1 on
+ pci 0:1d.2 on
+ pci 0:1d.3 on
+ pci 0:1d.7 on
+ pci 0:1e.0 on
+ pci 0:1f.1 off
+ pci 0:1f.2 on
+ pci 0:1f.3 on
+ pci 0:1f.5 off
+ pci 0:1f.6 off
+# pci 1:8.0 off
+ superio winbond/w83627hf
+ pnp 2e.0 on # Floppy
+ io 0x60 = 0x3f0
+ irq 0x70 = 6
+ drq 0x74 = 2
+ pnp 2e.1 off # Parallel Port
+ io 0x60 = 0x378
+ irq 0x70 = 7
+ pnp 2e.2 on # Com1
+ io 0x60 = 0x3f8
+ irq 0x70 = 4
+ pnp 2e.3 off # Com2
+ io 0x60 = 0x2f8
+ irq 0x70 = 3
+ pnp 2e.5 on # Keyboard
+ io 0x60 = 0x60
+ io 0x62 = 0x64
+ irq 0x70 = 1
+ irq 0x72 = 12
+ pnp 2e.6 off # CIR
+ pnp 2e.7 off # GAME_MIDI_GIPO1
+ pnp 2e.8 off # GPIO2
+ pnp 2e.9 off # GPIO3
+ pnp 2e.a off # ACPI
+ pnp 2e.b on # HW Monitor
+ io 0x60 = 0x290
+ end
+ end
+#end
+dir /pc80
+#dir /bioscall
+cpu p6 "cpu0"
+end
+
+cpu p6 "cpu1"
+end
+
+cpu p6 "cpu2"
+end
+
+cpu p6 "cpu3"
+end
diff --git a/src/mainboard/tyan/s2735/auto.c b/src/mainboard/tyan/s2735/auto.c
new file mode 100644
index 0000000000..3a99aa29a9
--- /dev/null
+++ b/src/mainboard/tyan/s2735/auto.c
@@ -0,0 +1,135 @@
+#define ASSEMBLY 1
+#include <stdint.h>
+#include <device/pci_def.h>
+#include <arch/io.h>
+#include <device/pnp_def.h>
+#include <arch/romcc_io.h>
+#include <arch/smp/lapic.h>
+#include "option_table.h"
+#include "pc80/mc146818rtc_early.c"
+#include "pc80/serial.c"
+#include "arch/i386/lib/console.c"
+#include "ram/ramtest.c"
+#include "southbridge/intel/i82801er/i82801er_early_smbus.c"
+#include "northbridge/intel/e7501/raminit.h"
+
+#if 1
+#include "cpu/p6/apic_timer.c"
+#include "lib/delay.c"
+#endif
+
+#include "cpu/p6/boot_cpu.c"
+#include "northbridge/intel/e7501/debug.c"
+#include "superio/winbond/w83627hf/w83627hf_early_serial.c"
+
+#include "cpu/p6/earlymtrr.c"
+
+#define SERIAL_DEV PNP_DEV(0x2e, W83627HF_SP1)
+
+static void hard_reset(void)
+{
+ outb(0x0e, 0x0cf9);
+}
+
+static void memreset_setup(void)
+{
+}
+
+static void memreset(int controllers, const struct mem_controller *ctrl)
+{
+}
+
+
+
+static inline void activate_spd_rom(const struct mem_controller *ctrl)
+{
+ /* nothing to do */
+}
+
+static inline int spd_read_byte(unsigned device, unsigned address)
+{
+ return smbus_read_byte(device, address);
+}
+
+#include "northbridge/intel/e7501/raminit.c"
+#include "northbridge/intel/e7501/reset_test.c"
+#include "sdram/generic_sdram.c"
+
+static void main(void)
+{
+ static const struct mem_controller memctrl[] = {
+ {
+ .d0 = PCI_DEV(0, 0, 0),
+ .d0f1 = PCI_DEV(0, 0, 1),
+ .channel0 = { (0xa<<3)|0, (0xa<<3)|1, (0xa<<3)|2, 0 },
+ .channel1 = { (0xa<<3)|4, (0xa<<3)|5, (0xa<<3)|6, 0 },
+ },
+ };
+
+#if 1
+ enable_lapic();
+ init_timer();
+#endif
+
+ w83627hf_enable_serial(SERIAL_DEV, TTYS0_BASE);
+ uart_init();
+ console_init();
+// setup_default_resource_map();
+#if 0
+ print_pci_devices();
+#endif
+ if(!bios_reset_detected()) {
+ enable_smbus();
+#if 0
+// dump_spd_registers(&memctrl[0]);
+ dump_smbus_registers();
+#endif
+
+ memreset_setup();
+ sdram_initialize(sizeof(memctrl)/sizeof(memctrl[0]), memctrl);
+ }
+#if 0
+ else {
+ /* clear memory 1meg */
+ __asm__ volatile(
+ "1: \n\t"
+ "movl %0, %%fs:(%1)\n\t"
+ "addl $4,%1\n\t"
+ "subl $4,%2\n\t"
+ "jnz 1b\n\t"
+ :
+ : "a" (0), "D" (0), "c" (1024*1024)
+ );
+
+ }
+#endif
+
+#if 0
+ dump_pci_devices();
+#endif
+#if 0
+ dump_pci_device(PCI_DEV(0, 0, 0));
+#endif
+
+#if 0
+ msr_t msr;
+ msr = rdmsr(TOP_MEM2);
+ print_debug("TOP_MEM2: ");
+ print_debug_hex32(msr.hi);
+ print_debug_hex32(msr.lo);
+ print_debug("\r\n");
+#endif
+/*
+#if 0
+ ram_check(0x00000000, msr.lo+(msr.hi<<32));
+#else
+#if 0
+ // Check 16MB of memory @ 0
+ ram_check(0x00000000, 0x01000000);
+#else
+ // Check 16MB of memory @ 2GB
+ ram_check(0x80000000, 0x81000000);
+#endif
+#endif
+*/
+}
diff --git a/src/mainboard/tyan/s2735/chip.h b/src/mainboard/tyan/s2735/chip.h
new file mode 100644
index 0000000000..f3a2ec6962
--- /dev/null
+++ b/src/mainboard/tyan/s2735/chip.h
@@ -0,0 +1,6 @@
+extern struct chip_control mainboard_tyan_s2735_control;
+
+struct mainboard_tyan_s2735_config {
+ int fixup_scsi;
+ int fixup_vga;
+};
diff --git a/src/mainboard/tyan/s2735/cmos.layout b/src/mainboard/tyan/s2735/cmos.layout
new file mode 100644
index 0000000000..2252e6720c
--- /dev/null
+++ b/src/mainboard/tyan/s2735/cmos.layout
@@ -0,0 +1,96 @@
+entries
+
+#start-bit length config config-ID name
+#0 8 r 0 seconds
+#8 8 r 0 alarm_seconds
+#16 8 r 0 minutes
+#24 8 r 0 alarm_minutes
+#32 8 r 0 hours
+#40 8 r 0 alarm_hours
+#48 8 r 0 day_of_week
+#56 8 r 0 day_of_month
+#64 8 r 0 month
+#72 8 r 0 year
+#80 4 r 0 rate_select
+#84 3 r 0 REF_Clock
+#87 1 r 0 UIP
+#88 1 r 0 auto_switch_DST
+#89 1 r 0 24_hour_mode
+#90 1 r 0 binary_values_enable
+#91 1 r 0 square-wave_out_enable
+#92 1 r 0 update_finished_enable
+#93 1 r 0 alarm_interrupt_enable
+#94 1 r 0 periodic_interrupt_enable
+#95 1 r 0 disable_clock_updates
+#96 288 r 0 temporary_filler
+0 384 r 0 reserved_memory
+384 1 e 4 boot_option
+385 1 e 4 last_boot
+386 1 e 1 ECC_memory
+388 4 r 0 reboot_bits
+392 3 e 5 baud_rate
+395 1 e 2 hyper_threading
+396 1 e 1 thermal_monitoring
+397 1 e 1 remap_memory_high
+400 1 e 1 power_on_after_fail
+412 4 e 6 debug_level
+416 4 e 7 boot_first
+420 4 e 7 boot_second
+424 4 e 7 boot_third
+428 4 h 0 boot_index
+432 8 h 0 boot_countdown
+#440 4 e 9 slow_cpu
+444 1 e 1 nmi
+728 256 h 0 user_data
+984 16 h 0 check_sum
+# Reserve the extended AMD configuration registers
+1000 24 r 0 reserved_memory
+
+
+
+enumerations
+
+#ID value text
+1 0 Disable
+1 1 Enable
+2 0 Enable
+2 1 Disable
+4 0 Fallback
+4 1 Normal
+5 0 115200
+5 1 57600
+5 2 38400
+5 3 19200
+5 4 9600
+5 5 4800
+5 6 2400
+5 7 1200
+6 6 Notice
+6 7 Info
+6 8 Debug
+6 9 Spew
+7 0 Network
+7 1 HDD
+7 2 Floppy
+7 8 Fallback_Network
+7 9 Fallback_HDD
+7 10 Fallback_Floppy
+#7 3 ROM
+#8 0 200Mhz
+#8 1 166Mhz
+#8 2 133Mhz
+#8 3 100Mhz
+#9 0 off
+#9 1 87.5%
+#9 2 75.0%
+#9 3 62.5%
+#9 4 50.0%
+#9 5 37.5%
+#9 6 25.0%
+#9 7 12.5%
+
+checksums
+
+checksum 392 983 984
+
+
diff --git a/src/mainboard/tyan/s2735/failover.c b/src/mainboard/tyan/s2735/failover.c
new file mode 100644
index 0000000000..6ba3cae62a
--- /dev/null
+++ b/src/mainboard/tyan/s2735/failover.c
@@ -0,0 +1,59 @@
+#define ASSEMBLY 1
+#include <stdint.h>
+#include <device/pci_def.h>
+#include <device/pci_ids.h>
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+#include <arch/smp/lapic.h>
+#include "pc80/mc146818rtc_early.c"
+#include "southbridge/intel/i82801er/cmos_failover.c"
+#include "cpu/p6/boot_cpu.c"
+#include "northbridge/intel/e7501/reset_test.c"
+
+#define HAVE_REGPARM_SUPPORT 0
+#if HAVE_REGPARM_SUPPORT
+static unsigned long main(unsigned long bist)
+{
+#else
+static void main(void)
+{
+ unsigned long bist = 0;
+
+#endif
+ /* Is this a deliberate reset by the bios */
+ if (bios_reset_detected() && last_boot_normal()) {
+ goto normal_image;
+ }
+ /* This is the primary cpu how should I boot? */
+ else {
+
+ check_cmos_failed();
+
+ if (do_normal_boot()) {
+ goto normal_image;
+ }
+ else {
+ goto fallback_image;
+ }
+ }
+ normal_image:
+ asm volatile ("jmp __normal_image"
+ : /* outputs */
+ : "a" (bist) /* inputs */
+ : /* clobbers */
+ );
+#if 0
+ cpu_reset:
+ asm volatile ("jmp __cpu_reset"
+ : /* outputs */
+ : "a"(bist) /* inputs */
+ : /* clobbers */
+ );
+#endif
+ fallback_image:
+#if HAVE_REGPARM_SUPPORT
+ return bist;
+#else
+ return;
+#endif
+}
diff --git a/src/mainboard/tyan/s2735/irq_tables.c b/src/mainboard/tyan/s2735/irq_tables.c
new file mode 100644
index 0000000000..b85847e9aa
--- /dev/null
+++ b/src/mainboard/tyan/s2735/irq_tables.c
@@ -0,0 +1,40 @@
+/* This file was generated by getpir.c, do not modify!
+ (but if you do, please run checkpir on it to verify)
+ Contains the IRQ Routing Table dumped directly from your memory , wich BIOS sets up
+
+ Documentation at : http://www.microsoft.com/hwdev/busbios/PCIIRQ.HTM
+*/
+
+#include <arch/pirq_routing.h>
+
+const struct irq_routing_table intel_irq_routing_table = {
+ PIRQ_SIGNATURE, /* u32 signature */
+ PIRQ_VERSION, /* u16 version */
+ 32+16*15, /* there can be total 15 devices on the bus */
+ 0x00, /* Where the interrupt router lies (bus) */
+ (0x1f<<3)|0x0, /* Where the interrupt router lies (dev) */
+ 0, /* IRQs devoted exclusively to PCI usage */
+ 0x8086, /* Vendor */
+ 0x24d0, /* Device */
+ 0, /* Crap (miniport) */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */
+ 0x9a, /* u8 checksum , this hase to set to some value that would give 0 after the sum of all bytes for this structure (including checksum) */
+ {
+ /* bus, dev|fn, {link, bitmap}, {link, bitmap}, {link, bitmap}, {link, bitmap}, slot, rfu */
+ {0x04,(0x08<<3)|0x0, {{0x68, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}, {0x00, 0x00000}}, 0x0, 0x0},
+ {0x00,(0x1f<<3)|0x0, {{0x62, 0xdcf8}, {0x61, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x00000}}, 0x0, 0x0},
+ {0x00,(0x1d<<3)|0x0, {{0x60, 0xdcf8}, {0x63, 0xdcf8}, {0x62, 0xdcf8}, {0x6b, 0x0dcf8}}, 0x0, 0x0},
+ {0x04,(0x03<<3)|0x0, {{0x62, 0xdcf8}, {0x63, 0xdcf8}, {0x60, 0xdcf8}, {0x61, 0x0dcf8}}, 0x3, 0x0},
+ {0x04,(0x02<<3)|0x0, {{0x62, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}, {0x00, 0x00000}}, 0x0, 0x0},
+ {0x03,(0x1f<<3)|0x0, {{0x60, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}, {0x00, 0x00000}}, 0x0, 0x0},
+ {0x02,(0x1f<<3)|0x0, {{0x60, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}, {0x00, 0x00000}}, 0x0, 0x0},
+ {0x03,(0x03<<3)|0x0, {{0x60, 0xdcf8}, {0x60, 0xdcf8}, {0x60, 0xdcf8}, {0x60, 0x0dcf8}}, 0x1, 0x0},
+ {0x03,(0x06<<3)|0x0, {{0x60, 0xdcf8}, {0x60, 0xdcf8}, {0x60, 0xdcf8}, {0x60, 0x0dcf8}}, 0x2, 0x0},
+ {0x02,(0x01<<3)|0x0, {{0x60, 0xdcf8}, {0x60, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x00000}}, 0x0, 0x0},
+ {0x02,(0x02<<3)|0x0, {{0x60, 0xdcf8}, {0x60, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x00000}}, 0x0, 0x0},
+ {0x04,(0x01<<3)|0x0, {{0x61, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}, {0x00, 0x00000}}, 0x0, 0x0},
+ {0x04,(0x04<<3)|0x0, {{0x63, 0xdcf8}, {0x60, 0xdcf8}, {0x61, 0xdcf8}, {0x62, 0x0dcf8}}, 0x4, 0x0},
+ {0x03,(0x04<<3)|0x0, {{0x60, 0xdcf8}, {0x60, 0xdcf8}, {0x60, 0xdcf8}, {0x60, 0x0dcf8}}, 0x5, 0x0},
+ {0x03,(0x05<<3)|0x0, {{0x60, 0xdcf8}, {0x60, 0xdcf8}, {0x60, 0xdcf8}, {0x60, 0x0dcf8}}, 0x6, 0x0},
+ }
+};
diff --git a/src/mainboard/tyan/s2735/mainboard.c b/src/mainboard/tyan/s2735/mainboard.c
new file mode 100644
index 0000000000..143909f1a5
--- /dev/null
+++ b/src/mainboard/tyan/s2735/mainboard.c
@@ -0,0 +1,183 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/chip.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "chip.h"
+//#include <part/mainboard.h>
+//#include "lsi_scsi.c"
+unsigned long initial_apicid[CONFIG_MAX_CPUS] =
+{
+ 0, 6, 1, 7
+};
+#if 0
+static void fixup_lsi_53c1030(struct device *pdev)
+{
+// uint8_t byte;
+ uint16_t word;
+
+ byte = 1;
+ pci_write_config8(pdev, 0xff, byte);
+ // Set the device id
+// pci_write_config_word(pdev, PCI_DEVICE_ID, PCI_DEVICE_ID_LSILOGIC_53C1030);
+ // Set the subsytem vendor id
+// pci_write_config16(pdev, PCI_SUBSYSTEM_VENDOR_ID, PCI_VENDOR_ID_TYAN);
+ word = 0x10f1;
+ pci_write_config16(pdev, PCI_SUBSYSTEM_VENDOR_ID, word);
+ // Set the subsytem id
+ word = 0x2880;
+ pci_write_config16(pdev, PCI_SUBSYSTEM_ID, word);
+ // Disable writes to the device id
+ byte = 0;
+ pci_write_config8(pdev, 0xff, byte);
+
+// lsi_scsi_init(pdev);
+
+}
+#endif
+//extern static void lsi_scsi_init(struct device *dev);
+#if 0
+static void print_pci_regs(struct device *dev)
+{
+ uint8_t byte;
+ int i;
+
+ for(i=0;i<256;i++) {
+ byte = pci_read_config8(dev, i);
+
+ if((i%16)==0) printk_info("\n%02x:",i);
+ printk_debug(" %02x",byte);
+ }
+ printk_debug("\n");
+
+// pci_write_config8(dev, 0x4, byte);
+
+}
+#endif
+#if 0
+static void print_mem(void)
+{
+ int i;
+ int low_1MB = 0;
+ for(i=low_1MB;i<low_1MB+1024*4;i++) {
+ if((i%16)==0) printk_debug("\n %08x:",i);
+ printk_debug(" %02x ",(unsigned char)*((unsigned char *)i));
+ }
+
+ for(i=low_1MB;i<low_1MB+1024*4;i++) {
+ if((i%16)==0) printk_debug("\n %08x:",i);
+ printk_debug(" %c ",(unsigned char)*((unsigned char *)i));
+ }
+ }
+#endif
+#if 0
+static void onboard_scsi_fixup(void)
+{
+ struct device *dev;
+ unsigned char i,j,k;
+#if 1
+ for(i=0;i<=5;i++) {
+ for(j=0;j<=0x1f;j++) {
+ for (k=0;k<=6;k++){
+ dev = dev_find_slot(i, PCI_DEVFN(j, k));
+ if (dev) {
+ printk_debug("%02x:%02x:%02x",i,j,k);
+ print_pci_regs(dev);
+ }
+ }
+ }
+ }
+#endif
+
+
+#if 0
+ dev = dev_find_device(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1030,0);
+ if(!dev) {
+ printk_info("LSI_SCSI_FW_FIXUP: No Device Found!");
+ return;
+ }
+
+ lsi_scsi_init(dev);
+#endif
+// print_mem();
+// amd8111_enable_rom();
+}
+#endif
+/*
+static void vga_fixup(void) {
+ // we do this right here because:
+ // - all the hardware is working, and some VGA bioses seem to need
+ // that
+ // - we need page 0 below for linuxbios tables.
+#if CONFIG_REALMODE_IDT == 1
+ printk_debug("INSTALL REAL-MODE IDT\n");
+ setup_realmode_idt();
+#endif
+#if CONFIG_VGABIOS == 1
+ printk_debug("DO THE VGA BIOS\n");
+ do_vgabios();
+ post_code(0x93);
+#endif
+
+}
+ */
+
+static void
+enable(struct chip *chip, enum chip_pass pass)
+{
+
+ struct mainboard_tyan_s2735_config *conf =
+ (struct mainboard_tyan_s2735_config *)chip->chip_info;
+
+ switch (pass) {
+ default: break;
+// case CONF_PASS_PRE_CONSOLE:
+// case CONF_PASS_PRE_PCI:
+ case CONF_PASS_POST_PCI:
+ case CONF_PASS_PRE_BOOT:
+// if (conf->fixup_scsi)
+// onboard_scsi_fixup();
+// if (conf->fixup_vga)
+// vga_fixup();
+// printk_debug("mainboard fixup pass %d done\r\n",pass);
+ break;
+ }
+
+}
+
+static int
+mainboard_scan_bus(device_t root, int maxbus)
+{
+ int retval;
+ printk_spew("%s: root %p maxbus %d\n", __FUNCTION__, root, maxbus);
+ retval = pci_scan_bus(root->bus, 0, 0xff, maxbus);
+ printk_spew("DONE %s: return %d\n", __FUNCTION__, maxbus);
+ return maxbus;
+}
+
+static struct device_operations mainboard_operations = {
+ .read_resources = root_dev_read_resources,
+ .set_resources = root_dev_set_resources,
+ .enable_resources = enable_childrens_resources,
+ .init = 0,
+ .scan_bus = mainboard_scan_bus,
+ .enable = 0,
+};
+
+static void enumerate(struct chip *chip)
+{
+ struct chip *child;
+ dev_root.ops = &mainboard_operations;
+ chip->dev = &dev_root;
+ chip->bus = 0;
+ for(child = chip->children; child; child = child->next) {
+ child->bus = &dev_root.link[0];
+ }
+}
+struct chip_control mainboard_tyan_s2735_control = {
+ .enable = enable,
+ .enumerate = enumerate,
+ .name = "Tyan s2735 mainboard ",
+};
+
diff --git a/src/mainboard/tyan/s2735/mptable.c b/src/mainboard/tyan/s2735/mptable.c
new file mode 100644
index 0000000000..25b1929eba
--- /dev/null
+++ b/src/mainboard/tyan/s2735/mptable.c
@@ -0,0 +1,165 @@
+#include <console/console.h>
+#include <arch/smp/mpspec.h>
+#include <device/pci.h>
+#include <string.h>
+#include <stdint.h>
+
+void *smp_write_config_table(void *v, unsigned long * processor_map)
+{
+ static const char sig[4] = "PCMP";
+ static const char oem[8] = "TYAN ";
+ static const char productid[12] = "S2735 ";
+ struct mp_config_table *mc;
+
+ mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN);
+ memset(mc, 0, sizeof(*mc));
+
+ memcpy(mc->mpc_signature, sig, sizeof(sig));
+ mc->mpc_length = sizeof(*mc); /* initially just the header */
+ mc->mpc_spec = 0x04;
+ mc->mpc_checksum = 0; /* not yet computed */
+ memcpy(mc->mpc_oem, oem, sizeof(oem));
+ memcpy(mc->mpc_productid, productid, sizeof(productid));
+ mc->mpc_oemptr = 0;
+ mc->mpc_oemsize = 0;
+ mc->mpc_entry_count = 0; /* No entries yet... */
+ mc->mpc_lapic = LAPIC_ADDR;
+ mc->mpe_length = 0;
+ mc->mpe_checksum = 0;
+ mc->reserved = 0;
+
+ smp_write_processors(mc, processor_map);
+
+
+/*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, 8, 0x20, 0xfec00000);
+ {
+ struct pci_dev *dev;
+ uint32_t base;
+ dev = dev_find_slot(1, PCI_DEVFN(0x1e,0));
+ if (dev) {
+ base = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
+ base &= PCI_BASE_ADDRESS_MEM_MASK;
+ smp_write_ioapic(mc, 9, 0x20, base);
+ }
+ dev = dev_find_slot(1, PCI_DEVFN(0x1c,0));
+ if (dev) {
+ base = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
+ base &= PCI_BASE_ADDRESS_MEM_MASK;
+ smp_write_ioapic(mc, 0xa, 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, 0x8, 0x0);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x1, 0x8, 0x1);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x0, 0x8, 0x2);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x3, 0x8, 0x3);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x4, 0x8, 0x4);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x6, 0x8, 0x6);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x8, 0x8, 0x8);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0x9, 0x8, 0x9);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0xc, 0x8, 0xc);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0xd, 0x8, 0xd);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0xe, 0x8, 0xe);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x5, 0xf, 0x8, 0xf);
+//USB
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x0, 0x7c, 0x8, 0x12);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x0, 0x7d, 0x8, 0x11);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x0, 0x74, 0x8, 0x10);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x0, 0x75, 0x8, 0x13);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x0, 0x77, 0x8, 0x17);
+
+//onboard ati
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x4, 0x8, 0x8, 0x12);
+
+//onboard intel 82551 10/100
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x4, 0x4, 0x8, 0x11);
+
+// onboard Intel 82547 1000
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x2, 0x4, 0xa, 0x0);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x2, 0x5, 0xa, 0x1);
+
+//Slot 4
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x4, (0x3<<2)|0, 0x8, 0x12);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x4, (0x3<<2)|1, 0x8, 0x13);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x4, (0x3<<2)|2, 0x8, 0x10);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x4, (0x3<<2)|3, 0x8, 0x11);
+//Slot 3
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x4, (0x4<<2)|0, 0x8, 0x13);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x4, (0x4<<2)|1, 0x8, 0x10);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x4, (0x4<<2)|2, 0x8, 0x11);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x4, (0x4<<2)|3, 0x8, 0x12);
+//Slot 1
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x3, (0x3<<2)|0, 0x9, 0x0);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x3, (0x3<<2)|1, 0x9, 0x1);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x3, (0x3<<2)|2, 0x9, 0x2);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x3, (0x3<<2)|3, 0x9, 0x3);
+//Slot 2
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x3, (0x6<<2)|0, 0x9, 0x4);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x3, (0x6<<2)|1, 0x9, 0x5);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x3, (0x6<<2)|2, 0x9, 0x6);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x3, (0x6<<2)|3, 0x9, 0x7);
+
+/*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, 0x0, 0x0, MP_APIC_ALL, 0x0);
+ smp_write_intsrc(mc, mp_NMI, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, 0x0, 0x0, MP_APIC_ALL, 0x1);
+/*
+MP Config Extended Table Entries:
+
+--
+System Address Space
+ bus ID: 0 address type: I/O address
+ address base: 0x9000
+ address range: 0x6000
+--
+System Address Space
+ bus ID: 0 address type: I/O address
+ address base: 0x0
+ address range: 0x100
+--
+System Address Space
+ bus ID: 0 address type: memory address
+ address base: 0xa0000
+ address range: 0x20000
+--
+System Address Space
+ bus ID: 0 address type: memory address
+ address base: 0xfc700000
+ address range: 0x2500000
+--
+System Address Space
+ bus ID: 0 address type: prefetch address
+ address base: 0xff600000
+ address range: 0x500000
+--
+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\n",
+ 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/northbridge/intel/e7501/Config.lb b/src/northbridge/intel/e7501/Config.lb
new file mode 100644
index 0000000000..f101a921fd
--- /dev/null
+++ b/src/northbridge/intel/e7501/Config.lb
@@ -0,0 +1,4 @@
+config chip.h
+object northbridge.o
+#driver misc_control.o
+
diff --git a/src/northbridge/intel/e7501/chip.h b/src/northbridge/intel/e7501/chip.h
new file mode 100644
index 0000000000..4fa6df49b3
--- /dev/null
+++ b/src/northbridge/intel/e7501/chip.h
@@ -0,0 +1,5 @@
+struct northbridge_intel_e7501_config
+{
+};
+
+extern struct chip_control northbridge_intel_e7501_control;
diff --git a/src/northbridge/intel/e7501/debug.c b/src/northbridge/intel/e7501/debug.c
new file mode 100644
index 0000000000..67670f9844
--- /dev/null
+++ b/src/northbridge/intel/e7501/debug.c
@@ -0,0 +1,164 @@
+/*
+ * generic K8 debug code, used by mainboard specific auto.c
+ *
+ */
+#if 1
+static void print_debug_pci_dev(unsigned dev)
+{
+ print_debug("PCI: ");
+ print_debug_hex8((dev >> 16) & 0xff);
+ print_debug_char(':');
+ print_debug_hex8((dev >> 11) & 0x1f);
+ print_debug_char('.');
+ print_debug_hex8((dev >> 8) & 7);
+}
+
+static void print_pci_devices(void)
+{
+ device_t dev;
+ for(dev = PCI_DEV(0, 0, 0);
+ dev <= PCI_DEV(0, 0x1f, 0x7);
+ dev += PCI_DEV(0,0,1)) {
+ uint32_t id;
+ id = pci_read_config32(dev, PCI_VENDOR_ID);
+ if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0x0000)) {
+ continue;
+ }
+ print_debug_pci_dev(dev);
+ print_debug("\r\n");
+ }
+}
+
+static void dump_pci_device(unsigned dev)
+{
+ int i;
+ print_debug_pci_dev(dev);
+ print_debug("\r\n");
+
+ for(i = 0; i <= 255; i++) {
+ unsigned char val;
+ if ((i & 0x0f) == 0) {
+ print_debug_hex8(i);
+ print_debug_char(':');
+ }
+ val = pci_read_config8(dev, i);
+ print_debug_char(' ');
+ print_debug_hex8(val);
+ if ((i & 0x0f) == 0x0f) {
+ print_debug("\r\n");
+ }
+ }
+}
+
+static void dump_pci_devices(void)
+{
+ device_t dev;
+ for(dev = PCI_DEV(0, 0, 0);
+ dev <= PCI_DEV(0, 0x1f, 0x7);
+ dev += PCI_DEV(0,0,1)) {
+ uint32_t id;
+ id = pci_read_config32(dev, PCI_VENDOR_ID);
+ if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0x0000)) {
+ continue;
+ }
+ dump_pci_device(dev);
+ }
+}
+
+static void dump_spd_registers(const struct mem_controller *ctrl)
+{
+ int i;
+ print_debug("\r\n");
+ for(i = 0; i < 4; i++) {
+ unsigned device;
+ device = ctrl->channel0[i];
+ if (device) {
+ int j;
+ print_debug("dimm: ");
+ print_debug_hex8(i);
+ print_debug(".0: ");
+ print_debug_hex8(device);
+ for(j = 0; j < 256; j++) {
+ int status;
+ unsigned char byte;
+ if ((j & 0xf) == 0) {
+ print_debug("\r\n");
+ print_debug_hex8(j);
+ print_debug(": ");
+ }
+ status = smbus_read_byte(device, j);
+ if (status < 0) {
+ print_debug("bad device\r\n");
+ break;
+ }
+ byte = status & 0xff;
+ print_debug_hex8(byte);
+ print_debug_char(' ');
+ }
+ print_debug("\r\n");
+ }
+#if 0
+ device = ctrl->channel1[i];
+ if (device) {
+ int j;
+ print_debug("dimm: ");
+ print_debug_hex8(i);
+ print_debug(".1: ");
+ print_debug_hex8(device);
+ for(j = 0; j < 256; j++) {
+ int status;
+ unsigned char byte;
+ if ((j & 0xf) == 0) {
+ print_debug("\r\n");
+ print_debug_hex8(j);
+ print_debug(": ");
+ }
+ status = smbus_read_byte(device, j);
+ if (status < 0) {
+ print_debug("bad device\r\n");
+ break;
+ }
+ byte = status & 0xff;
+ print_debug_hex8(byte);
+ print_debug_char(' ');
+ }
+ print_debug("\r\n");
+ }
+#endif
+ }
+}
+static void dump_smbus_registers(void)
+{
+ int i;
+ print_debug("\r\n");
+ for(i = 1; i < 0x80; i++) {
+ unsigned device;
+ device = i;
+ int j;
+ print_debug("smbus: ");
+ print_debug_hex8(device);
+ for(j = 0; j < 256; j++) {
+ int status;
+ unsigned char byte;
+ if ((j & 0xf) == 0) {
+ print_debug("\r\n");
+ print_debug_hex8(j);
+ print_debug(": ");
+ }
+ status = smbus_read_byte(device, j);
+ if (status < 0) {
+ print_debug("bad device\r\n");
+ break;
+ }
+ byte = status & 0xff;
+ print_debug_hex8(byte);
+ print_debug_char(' ');
+ }
+ print_debug("\r\n");
+ }
+}
+#endif
diff --git a/src/northbridge/intel/e7501/e7501.h b/src/northbridge/intel/e7501/e7501.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/northbridge/intel/e7501/e7501.h
diff --git a/src/northbridge/intel/e7501/northbridge.c b/src/northbridge/intel/e7501/northbridge.c
new file mode 100644
index 0000000000..452166ba28
--- /dev/null
+++ b/src/northbridge/intel/e7501/northbridge.c
@@ -0,0 +1,151 @@
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <mem.h>
+#include <part/sizeram.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/chip.h>
+#include <stdlib.h>
+#include <string.h>
+#include <bitops.h>
+#include "chip.h"
+
+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;
+ device_t dev;
+
+ dev = dev_find_slot(0, 0); // d0f0
+ if (!dev) {
+ printk_err("Cannot find PCI: 0:0\n");
+ return 0;
+ }
+
+ /* 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.
+ */
+ drb = pci_read_config8(dev, 0x67);
+ 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)((dev_root.resource[1].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.
+ */
+ tolm_r = pci_read_config16(dev, 0xc4);
+ tolm |= (tolm_r & 0x7ff);
+ pci_write_config16(dev, 0xc4, tolm);
+ remapbase_r = pci_read_config16(dev, 0xc6);
+ remapbase |= (remapbase_r & 0xfc00);
+ pci_write_config16(dev, 0xc6, remapbase);
+ remaplimit_r = pci_read_config16(dev, 0xc8);
+ remaplimit |= (remaplimit_r & 0xfc00);
+ pci_write_config16(dev, 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;
+}
+static void enumerate(struct chip *chip)
+{
+ extern struct device_operations default_pci_ops_bus;
+ chip_enumerate(chip);
+ chip->dev->ops = &default_pci_ops_bus;
+}
+#if 0
+static void northbridge_init(struct chip *chip, enum chip_pass pass)
+{
+
+ struct northbridge_intel_e7501_config *conf =
+ (struct northbridge_intel_e7501_config *)chip->chip_info;
+
+ switch (pass) {
+ case CONF_PASS_PRE_PCI:
+ break;
+
+ case CONF_PASS_POST_PCI:
+ break;
+
+ case CONF_PASS_PRE_BOOT:
+ break;
+
+ default:
+ /* nothing yet */
+ break;
+ }
+}
+#endif
+
+struct chip_control northbridge_intel_e7501_control = {
+ .enumerate = enumerate,
+// .enable = northbridge_init,
+ .name = "intel E7501 Northbridge",
+};
diff --git a/src/northbridge/intel/e7501/raminit.c b/src/northbridge/intel/e7501/raminit.c
new file mode 100644
index 0000000000..09743ba5fd
--- /dev/null
+++ b/src/northbridge/intel/e7501/raminit.c
@@ -0,0 +1,2099 @@
+
+/* 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
+ */
+
+/* converted to C 6/2004 yhlu */
+
+#define DEBUG_RAM_CONFIG 0
+
+#define dumpnorth() dump_pci_device(PCI_DEV(0, 0, 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_2_5
+//#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
+
+
+static inline void do_ram_command (const struct mem_controller *ctrl, uint32_t value) {
+ uint32_t dword;
+ uint8_t byte;
+ int i;
+ uint32_t result;
+#if DEBUG_RAM_CONFIG >= 2
+ print_debug("P:");
+ print_debug_hex8(value);
+ print_debug("\r\n");
+#endif
+ /* %ecx - initial address to read from */
+ /* Compute the offset */
+ dword = value >> 16;
+ for(i=0;i<8;i++) {
+ /* Set the ram command */
+ byte = pci_read_config8(ctrl->d0, 0x7c);
+ byte &= 0x8f;
+ byte |= (uint8_t)(value & 0xff);
+ pci_write_config8(ctrl->d0, 0x7c, byte);
+
+ /* Assert the command to the memory */
+#if DEBUG_RAM_CONFIG >= 2
+ print_debug("R:");
+ print_debug_hex32(dword);
+ print_debug("\r\n");
+#endif
+
+ result = read32(dword);
+
+ /* Go to the next base address */
+ dword += 0x04000000;
+
+ }
+
+ /* The command has been sent to all dimms so get out */
+}
+
+
+static inline void RAM_CMD(const struct mem_controller *ctrl, uint32_t command, uint32_t offset) {
+ uint32_t value = ((offset) << (MD_SHIFT + 16))|((command << 4) & 0x70) ;
+ do_ram_command(ctrl, value);
+}
+
+#define RAM_NOP(ctrl) RAM_CMD(ctrl, RAM_COMMAND_NOP, 0)
+#define RAM_PRECHARGE(ctrl) RAM_CMD(ctrl, RAM_COMMAND_PRECHARGE, 0)
+#define RAM_CBR(ctrl) RAM_CMD(ctrl, RAM_COMMAND_CBR, 0)
+#define RAM_EMRS(ctrl) RAM_CMD(ctrl, RAM_COMMAND_EMRS, EMRS_VALUE)
+
+static const uint8_t ram_cas_latency[] = {
+ CAS_2_5, CAS_2_0, CAS_1_5, CAS_2_5
+ };
+
+static inline void ram_mrs(const struct mem_controller *ctrl, uint32_t value){
+ /* Read the cas latency setting */
+ uint8_t byte;
+ uint32_t dword;
+ byte = pci_read_config8(ctrl->d0, 0x78);
+ /* Transform it into the form expected by SDRAM */
+ dword = ram_cas_latency[(byte>>4) & 3];
+
+ value |= (dword<<(16+MD_SHIFT));
+
+ value |= (MODE_NORM | BURST_TYPE | BURST_LENGTH) << (16+MD_SHIFT);
+
+ do_ram_command(ctrl, value);
+}
+
+#define RAM_MRS(ctrl, dll_reset) ram_mrs( ctrl, (dll_reset << (8+MD_SHIFT+ 16)) | ((RAM_COMMAND_MRS <<4)& 0x70) )
+
+static void RAM_NORMAL(const struct mem_controller *ctrl) {
+ uint8_t byte;
+ byte = pci_read_config8(ctrl->d0, 0x7c);
+ byte &= 0x8f;
+ byte |= (RAM_COMMAND_NORMAL << 4);
+ pci_write_config8(ctrl->d0, 0x7c, byte);
+}
+
+static void RAM_RESET_DDR_PTR(const struct mem_controller *ctrl) {
+ uint8_t byte;
+ byte = pci_read_config8(ctrl->d0, 0x88);
+ byte |= (1 << 4 );
+ pci_write_config8(ctrl->d0, 0x88, byte);
+ byte = pci_read_config8(ctrl->d0, 0x88);
+ byte &= ~(1 << 4);
+ pci_write_config8(ctrl->d0, 0x88, byte);
+}
+
+static void ENABLE_REFRESH(const struct mem_controller *ctrl)
+{
+ uint32_t dword;
+ dword = pci_read_config32(ctrl->d0, 0x7c);
+ dword |= (1 << 29);
+ pci_write_config32(ctrl->d0, 0x7c, dword);
+}
+
+ /*
+ * Table: constant_register_values
+ */
+static const long 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
+ */
+ 0x2c, 0, (0x15d9 << 0) | (0x3580 << 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
+// 0x80, 0xfffffe00, 0x06 /* Intel E7500 recommended */
+ 0x80, 0xfffff000, 0x0662, /* from Factory Bios */
+#elif CAS_LATENCY == CAS_2_0
+// 0x80, 0xfffffe00, 0x0d /* values for register 0x80 */
+ 0x80, 0xfffff000, 0x0bb1, /* values for register 0x80 */
+#endif
+
+ /* Enable periodic memory recalibration */
+ 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)
+ */
+ 0x58, 0xcccccf7f, (0x00 << 0) | (0x30 << 8) | (0x33 << 16) | (0x33 << 24),
+ 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 */
+ 0x60, 0x00000000, (0x01 << 0) | (0x02 << 8) | (0x03 << 16) | (0x04 << 24),
+ 0x64, 0x00000000, (0x05 << 0) | (0x06 << 8) | (0x07 << 16) | (0x08 << 24),
+ 0x68, 0xffffffff, 0,
+ 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
+ */
+ 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),
+ 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 */
+// 0x78, 0xc0fff8c4, (1<<29)|(1<<28)|(1<<27)|(2<<24)|(2<<9)|DRT_CL|(1<<3)|(1<<1)|(1<<0),
+// 0x78, 0xc0f8f8c0, (1<<29)|(1<<28)|(1<<27)|(1<<24)|(1<<16)|(2<<9)|DRT_CL|(1<<3)|(3<<1)|(1<<0),
+ 0x78, 0xc0f8f9c0, (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] (Intel Undocumented) should always be set 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),
+// .long 0x7c, 0xff80fcff, (1<<22)|(2 << 20)|(1 << 18)|(1 << 17)|(1 << 16)| (0 << 8),
+ 0x7c, 0xff82fcff, (1<<22)|(2 << 20)|(1 << 18)|(1 << 16)| (0 << 8),
+
+
+ /* Another Intel undocumented register */
+ 0x88, 0x080007ff, (1<<31)|(1 << 30)|(1<<28)|(0 << 26)|(0x10 << 21)|(10 << 16)|(0x13 << 11),
+
+ /* 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
+ */
+ 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.
+ */
+ 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.
+ */
+ 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
+ */
+ 0xe0, 0xffffffe2, (1<<4)|(1<<3)|(1<<2)|(0<<0),
+ 0xd8, 0xffff9fff, 0x00000000,
+ 0xf4, 0x3f8ffffd, 0x40300002,
+ 0x1050, 0xffffffcf, 0x00000030,
+};
+
+
+ /*
+ * 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.
+ *
+ */
+/* from 1M or 512K */
+#define RCOMP_MMIO 0x100000
+
+ /* DDR RECOMP table */
+
+static const long ddr_rcomp_1[] = {
+ 0x44332211, 0xc9776655, 0xffffffff, 0xffffffff,
+ 0x22111111, 0x55444332, 0xfffca876, 0xffffffff,
+};
+static const long ddr_rcomp_2[] = {
+ 0x00000000, 0x76543210, 0xffffeca8, 0xffffffff,
+ 0x21000000, 0xa8765432, 0xffffffec, 0xffffffff,
+};
+static const long ddr_rcomp_3[] = {
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x88888888, 0x88888888, 0x88888888, 0x88888888,
+};
+
+#define rcomp_init_str "Setting RCOMP registers.\r\n"
+
+static void write_8dwords(uint32_t src_addr, uint32_t dst_addr) {
+ int i;
+ uint32_t dword;
+ for(i=0;i<8;i++) {
+ dword = read32(src_addr);
+ write32(dst_addr, dword);
+ src_addr+=4;
+ dst_addr+=4;
+
+ }
+}
+
+//#define SLOW_DOWN_IO inb(0x80);
+#define SLOW_DOWN_IO udelay(40);
+
+static void ram_set_rcomp_regs(const struct mem_controller *ctrl) {
+ uint32_t dword;
+#if DEBUG_RAM_CONFIG
+ print_debug(rcomp_init_str);
+#endif
+
+ /*enable access to the rcomp bar */
+ dword = pci_read_config32(ctrl->d0, 0x0f4);
+ dword &= ~(1<<31);
+ dword |=((1<<30)|1<<22);
+ pci_write_config32(ctrl->d0, 0x0f4, dword);
+
+
+ /* Set the MMIO address to 512K */
+ pci_write_config32(ctrl->d0, 0x14, RCOMP_MMIO);
+
+ dword = read32(RCOMP_MMIO + 0x20);
+ dword |= (1<<9);
+ write32(RCOMP_MMIO + 0x20, dword);
+
+
+ /* Begin to write the RCOMP registers */
+
+ write8(RCOMP_MMIO + 0x2c, 0xff);
+ write32(RCOMP_MMIO + 0x30, 0x01040444);
+ write8(RCOMP_MMIO + 0x34, 0x04);
+ write32(RCOMP_MMIO + 0x40, 0);
+ write16(RCOMP_MMIO + 0x44, 0);
+ write16(RCOMP_MMIO + 0x48, 0);
+ write16(RCOMP_MMIO + 0x50, 0);
+ write_8dwords((uint32_t)ddr_rcomp_1, RCOMP_MMIO + 0x60);
+ write_8dwords((uint32_t)ddr_rcomp_2, RCOMP_MMIO + 0x80);
+ write_8dwords((uint32_t)ddr_rcomp_2, RCOMP_MMIO + 0xa0);
+ write_8dwords((uint32_t)ddr_rcomp_2, RCOMP_MMIO + 0x140);
+ write_8dwords((uint32_t)ddr_rcomp_2, RCOMP_MMIO + 0x1c0);
+ write_8dwords((uint32_t)ddr_rcomp_3, RCOMP_MMIO + 0x180);
+
+#if 0 /* Print the RCOMP registers */
+ movl $RCOMP_MMIO, %ecx
+1: movl %ecx, %eax
+ andb $0x0f, %al
+ jnz 2f
+ CONSOLE_INFO_TX_CHAR($'\r')
+ CONSOLE_INFO_TX_CHAR($'\n')
+ CONSOLE_INFO_TX_HEX32(%ecx)
+ CONSOLE_INFO_TX_CHAR($' ')
+ CONSOLE_INFO_TX_CHAR($'-')
+ CONSOLE_INFO_TX_CHAR($' ')
+2: movl (%ecx), %eax
+ CONSOLE_INFO_TX_HEX32(%eax)
+ CONSOLE_INFO_TX_CHAR($' ')
+ addl $4, %ecx
+ cmpl $(RCOMP_MMIO + 0x1e0), %ecx
+ jnz 1b
+ CONSOLE_INFO_TX_CHAR($'\r')
+ CONSOLE_INFO_TX_CHAR($'\n')
+#endif
+
+ dword = read32(RCOMP_MMIO + 0x20);
+ dword &= ~(3);
+ dword |= 1;
+ write32(RCOMP_MMIO + 0x20, dword);
+
+ /* Wait 40 usec */
+ SLOW_DOWN_IO;
+
+ /* unblock updates */
+ dword = read32(RCOMP_MMIO + 0x20);
+ dword &= ~(1<<9);
+ write32(RCOMP_MMIO+0x20, dword);
+ dword |= (1<<8);
+ write32(RCOMP_MMIO+0x20, dword);
+ dword &= ~(1<<8);
+ write32(RCOMP_MMIO+0x20, dword);
+
+ /* Wait 40 usec */
+ SLOW_DOWN_IO;
+
+ /*disable access to the rcomp bar */
+ dword = pci_read_config32(ctrl->d0, 0x0f4);
+ dword &= ~(1<<22);
+ pci_write_config32(ctrl->d0, 0x0f4, dword);
+
+}
+
+static void ram_set_d0f0_regs(const struct mem_controller *ctrl) {
+#if DEBUG_RAM_CONFIG
+ dumpnorth();
+#endif
+ int i;
+ int max;
+ max = sizeof(register_values)/sizeof(register_values[0]);
+ for(i = 0; i < max; i += 3) {
+ uint32_t reg;
+#if DEBUG_RAM_CONFIG
+ print_debug_hex32(register_values[i]);
+ print_debug(" <-");
+ print_debug_hex32(register_values[i+2]);
+ print_debug("\r\n");
+#endif
+ reg = pci_read_config32(ctrl->d0,register_values[i]);
+ reg &= register_values[i+1];
+ reg |= register_values[i+2] & ~(register_values[i+1]);
+ pci_write_config32(ctrl->d0,register_values[i], reg);
+
+
+ }
+#if DEBUG_RAM_CONFIG
+ dumpnorth();
+#endif
+}
+static void sdram_set_registers(const struct mem_controller *ctrl){
+ ram_set_rcomp_regs(ctrl);
+ ram_set_d0f0_regs(ctrl);
+}
+
+
+ /*
+ * 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.
+ */
+struct dimm_page_size {
+ unsigned long side1;
+ unsigned long side2;
+};
+
+static struct dimm_page_size sdram_spd_get_page_size(unsigned device) {
+
+ uint32_t ecx;
+ int value;
+ struct dimm_page_size pgsz;
+
+ pgsz.side1 = 0;
+ pgsz.side2 = 0;
+
+ value = spd_read_byte(device, 4); /* columns */
+ if(value < 0) goto hw_err;
+ pgsz.side1 = value & 0xf;
+
+ /* Get the module data width and convert it to a power of two */
+ value = spd_read_byte(device,7); /* (high byte) */
+ if(value < 0) goto hw_err;
+ ecx = value & 0xff;
+ ecx <<= 8;
+
+ value = spd_read_byte(device, 6); /* (low byte) */
+ if(value < 0) goto hw_err;
+ ecx |= (value & 0xff);
+
+ pgsz.side1 += log2(ecx); /* compute cheap log base 2 */
+
+ /* side two */
+ value = spd_read_byte(device, 5); /* number of physical banks */
+ if(value < 0) goto hw_err;
+ if(value==1) goto out;
+ if(value!=2) goto val_err;
+
+ /* Start with the symmetrical case */
+ pgsz.side2 = pgsz.side1;
+ value = spd_read_byte(device,4); /* columns */
+ if(value < 0) goto hw_err;
+ if((value & 0xf0)==0 ) goto out;
+ pgsz.side2 -=value & 0xf; /* Subtract out columns on side 1 */
+ pgsz.side2 +=(value>>4)& 0xf; /* Add in columns on side 2 */
+ goto out;
+
+ val_err:
+ die("Bad SPD value\r\n");
+ /* If an hw_error occurs report that I have no memory */
+hw_err:
+ pgsz.side1 = 0;
+ pgsz.side2 = 0;
+out:
+ return pgsz;
+}
+
+
+ /*
+ * 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.
+ */
+struct dimm_width {
+ unsigned side1;
+ unsigned side2;
+};
+
+static struct dimm_width sdram_spd_get_width(unsigned device) {
+ int value;
+ struct dimm_width wd;
+ uint32_t ecx;
+
+ wd.side1 = 0;
+ wd.side2 = 0;
+
+ value = spd_read_byte(device, 13); /* sdram width */
+ if(value < 0 ) goto hw_err;
+ ecx = value;
+
+ wd.side1 = value & 0x7f;
+
+ /* side two */
+ value = spd_read_byte(device, 5); /* number of physical banks */
+ if(value < 0 ) goto hw_err;
+ if(value <=1 ) goto out;
+
+ /* Start with the symmetrical case */
+ wd.side2 = wd.side1;
+
+ if((ecx & 0x80)==0) goto out;
+
+ wd.side2 <<=1;
+hw_err:
+ wd.side1 = 0;
+ wd.side2 = 0;
+
+ out:
+ return wd;
+}
+
+ /*
+ * 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.
+ */
+
+struct dimm_size {
+ unsigned long side1;
+ unsigned long side2;
+};
+
+static struct dimm_size spd_get_dimm_size(unsigned device)
+{
+ /* Calculate the log base 2 size of a DIMM in bits */
+ struct dimm_size sz;
+ int value, low;
+ sz.side1 = 0;
+ sz.side2 = 0;
+
+ /* Note it might be easier to use byte 31 here, it has the DIMM size as
+ * a multiple of 4MB. The way we do it now we can size both
+ * sides of an assymetric dimm.
+ */
+ value = spd_read_byte(device, 3); /* rows */
+ if (value < 0) goto hw_err;
+// if ((value & 0xf) == 0) goto val_err;
+ sz.side1 += value & 0xf;
+
+ value = spd_read_byte(device, 4); /* columns */
+ if (value < 0) goto hw_err;
+// if ((value & 0xf) == 0) goto val_err;
+ sz.side1 += value & 0xf;
+
+ value = spd_read_byte(device, 17); /* banks */
+ if (value < 0) goto hw_err;
+// if ((value & 0xff) == 0) goto val_err;
+ value &=0xff;
+ sz.side1 += log2(value);
+
+ /* Get the module data width and convert it to a power of two */
+ value = spd_read_byte(device, 7); /* (high byte) */
+ if (value < 0) goto hw_err;
+ value &= 0xff;
+ value <<= 8;
+
+ low = spd_read_byte(device, 6); /* (low byte) */
+ if (low < 0) goto hw_err;
+ value |= (low & 0xff);
+// if ((value != 72) && (value != 64)) goto val_err;
+ sz.side1 += log2(value);
+
+ /* side 2 */
+ value = spd_read_byte(device, 5); /* number of physical banks */
+ if (value < 0) goto hw_err;
+ if (value == 1) goto out;
+// if (value != 2) goto val_err;
+
+ /* Start with the symmetrical case */
+ sz.side2 = sz.side1;
+
+ value = spd_read_byte(device, 3); /* rows */
+ if (value < 0) goto hw_err;
+ if ((value & 0xf0) == 0) goto out; /* If symmetrical we are done */
+ sz.side2 -= (value & 0x0f); /* Subtract out rows on side 1 */
+ sz.side2 += ((value >> 4) & 0x0f); /* Add in rows on side 2 */
+
+ value = spd_read_byte(device, 4); /* columns */
+ if (value < 0) goto hw_err;
+// if ((value & 0xff) == 0) goto val_err;
+ sz.side2 -= (value & 0x0f); /* Subtract out columns on side 1 */
+ sz.side2 += ((value >> 4) & 0x0f); /* Add in columsn on side 2 */
+ goto out;
+
+ val_err:
+ die("Bad SPD value\r\n");
+ /* If an hw_error occurs report that I have no memory */
+hw_err:
+ sz.side1 = 0;
+ sz.side2 = 0;
+ out:
+ return sz;
+}
+
+
+
+ /*
+ * 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.
+ */
+static long spd_set_row_attributes(const struct mem_controller *ctrl, long dimm_mask) {
+ int i;
+ uint32_t dword=0;
+ int value;
+
+
+ /* Walk through all dimms and find the interesection of the support
+ * for ecc sdram and refresh rates
+ */
+
+
+ for(i = 0; i < DIMM_SOCKETS; i++) {
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
+ /* Test to see if I have ecc sdram */
+ struct dimm_page_size sz;
+ sz = sdram_spd_get_page_size(ctrl->channel0[i]); /* SDRAM type */
+#if DEBUG_RAM_CONFIG
+ print_debug("page size =");
+ print_debug_hex32(sz.side1);
+ print_debug(" ");
+ print_debug_hex32(sz.side2);
+ print_debug("\r\n");
+#endif
+
+ /* Test to see if the dimm is present */
+ if( sz.side1 !=0) {
+
+ /* Test for a valid dimm width */
+ if((sz.side1 <15) || (sz.side1>18) ) {
+ print_err("unsupported page size\r\n");
+ }
+
+ /* double because I have 2 channels */
+ sz.side1++;
+
+ /* Convert to the format needed for the DRA register */
+ sz.side1-=14;
+
+ /* Place in the %ebp the dra place holder */ //i
+ dword |= sz.side1<<(i<<3);
+
+ /* Test to see if the second side is present */
+
+ if( sz.side2 !=0) {
+
+ /* Test for a valid dimm width */
+ if((sz.side2 <15) || (sz.side2>18) ) {
+ print_err("unsupported page size\r\n");
+ }
+
+ /* double because I have 2 channels */
+ sz.side2++;
+
+ /* Convert to the format needed for the DRA register */
+ sz.side2-=14;
+
+ /* Place in the %ebp the dra place holder */ //i
+ dword |= sz.side2<<((i<<3) + 4 );
+
+ }
+ }
+
+ /* Now add the SDRAM chip width to the DRA */
+ struct dimm_width wd;
+ wd = sdram_spd_get_width(ctrl->channel0[i]);
+
+#if DEBUG_RAM_CONFIG
+ print_debug("width =");
+ print_debug_hex32(wd.side1);
+ print_debug(" ");
+ print_debug_hex32(wd.side2);
+ print_debug("\r\n");
+#endif
+
+ if(wd.side1 == 0) continue;
+ if(wd.side1 == 4) {
+ /* Enable an x4 device */
+ dword |= 0x08 << (i<<3);
+ }
+
+ if(wd.side2 == 0) continue;
+ if(wd.side2 == 4) {
+ /* Enable an x4 device */
+ dword |= 0x08 << ((i<<3 ) + 4);
+ }
+
+ /* go to the next DIMM */
+ }
+
+ /* Write the new row attributes register */
+ pci_write_config32(ctrl->d0, 0x70, dword);
+
+ return dimm_mask;
+
+}
+#if 0
+ /*
+ * 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.
+ */
+static 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.
+ */
+static 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)
+}
+#endif
+#define spd_pre_init "Reading SPD data...\r\n"
+#define spd_pre_set "setting based on SPD data...\r\n"
+#define spd_post_init "done\r\n"
+
+
+static const uint32_t 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
+ */
+ 3, 1, 0, 2 };
+static const uint32_t 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
+ */
+ 1, 0xff, 2, 1, 1, 3
+};
+#define MAX_SPD_REFRESH_RATE 5
+
+static long spd_set_dram_controller_mode (const struct mem_controller *ctrl, long dimm_mask) {
+
+ int i;
+ uint32_t dword;
+ int value;
+ uint32_t ecx;
+ uint32_t edx;
+
+ /* Read the inititial state */
+ dword = pci_read_config32(ctrl->d0, 0x7c);
+
+#if 0
+ /* 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
+
+
+ /* Walk through all dimms and find the interesection of the support
+ * for ecc sdram and refresh rates
+ */
+
+
+ for(i = 0; i < DIMM_SOCKETS; i++) {
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
+ /* Test to see if I have ecc sdram */
+ value = spd_read_byte(ctrl->channel0[i], 11); /* SDRAM type */
+ if(value < 0) continue;
+ if(value !=2 ) {
+ /* Clear the ecc enable */
+ dword &= ~(3 << 20);
+ }
+ value = spd_read_byte(ctrl->channel0[i], 12); /* SDRAM refresh rate */
+ if(value < 0 ) continue;
+ value &= 0x7f;
+ if(value > MAX_SPD_REFRESH_RATE) { print_err("unsupported refresh rate\r\n");}
+// if(value == 0xff) { print_err("unsupported refresh rate\r\n");}
+
+ ecx = refresh_rate_index[value];
+
+ /* Isolate the old refresh rate setting */
+ /* Load the refresh rate ranks */
+ edx = refresh_rate_rank[(dword >> 8) & 3]<<8;
+ edx |= refresh_rate_rank[ecx] & 0xff;
+
+ /* See if the new refresh rate is more conservative than the old
+ * refresh rate setting. (Lower ranks are more conservative)
+ */
+ if((edx & 0xff)< ((edx >> 8) & 0xff) ) {
+ /* Clear the old refresh rate */
+ dword &= ~(3<<8);
+ /* Move in the new refresh rate */
+ dword |= (ecx<<8);
+ }
+
+ value = spd_read_byte(ctrl->channel0[i], 33); /* Address and command hold time after clock */
+ if(value < 0) continue;
+ if(value >= 0xa0) { /* At 133Mhz this constant should be 0x75 */
+ dword &= ~(1<<16); /* Use two clock cyles instead of one */
+ }
+
+ /* go to the next DIMM */
+ }
+
+ /* Now write the controller mode */
+ pci_write_config32(ctrl->d0, 0x7c, dword);
+
+ return dimm_mask;
+
+}
+static long spd_enable_clocks(const struct mem_controller *ctrl, long dimm_mask)
+{
+ int i;
+ uint32_t dword;
+ int value;
+
+ /* Read the inititial state */
+ dword = pci_read_config32(ctrl->d0, 0x8c);
+#if 0
+# Intel clears top bit here, should we?
+# No the default is on and for normal timming it should be on. Tom Z
+ andl $0x7f, %esi
+#endif
+
+
+ for(i = 0; i < DIMM_SOCKETS; i++) {
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
+ /* Read any spd byte to see if the dimm is present */
+ value = spd_read_byte(ctrl->channel0[i], 5); /* Physical Banks */
+ if(value < 0) continue;
+
+ dword &= ~(1<<i);
+ }
+
+ pci_write_config32(ctrl->d0, 0x8c, dword);
+
+ return dimm_mask;
+}
+
+static const uint16_t 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
+ 0x0, 0x0bb1, 0x0662 /* RCVEN */
+};
+static const uint16_t cas_latency_80_4dimms[] = {
+ 0x0, 0x0bb1, 0x0882
+};
+
+
+static const uint8_t cas_latency_78[] = {
+ DRT_CAS_1_5, DRT_CAS_2_0, DRT_CAS_2_5
+};
+
+static long spd_set_cas_latency(const struct mem_controller *ctrl, long dimm_mask) {
+ /* Walk through all dimms and find the interesection of the
+ * supported cas latencies.
+ */
+ int i;
+ /* Initially allow cas latencies 2.5, 2.0
+ * which the chipset supports.
+ */
+ uint32_t dword = (1<<3)| (1<<2);// esi
+ uint32_t edi;
+ uint32_t ecx;
+ unsigned device;
+ int value;
+ uint8_t byte;
+ uint16_t word;
+
+
+ for(i = 0; i < DIMM_SOCKETS; i++) {
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
+ value = spd_read_byte(ctrl->channel0[i], 18);
+ if(value < 0) continue;
+ /* Find the highest supported cas latency */
+ ecx = log2(value & 0xff);
+ edi = (1<< ecx);
+
+ /* Remember the supported cas latencies */
+ ecx = (value & 0xff);
+
+ /* Verify each cas latency at 133Mhz */
+ /* Verify slowest/highest CAS latency */
+ value = spd_read_byte(ctrl->channel0[i], 9);
+ if(value < 0 ) continue;
+ if(value > 0x75 ) {
+ /* The bus is too fast so we cannot support this case latency */
+ ecx &= ~edi;
+ }
+
+ /* Verify the highest CAS latency - 0.5 clocks */
+ edi >>= 1;
+ if(edi != 0) {
+ value = spd_read_byte(ctrl->channel0[i], 23);
+ if(value < 0 ) continue;
+ if(value > 0x75) {
+ /* The bus is too fast so we cannot support this cas latency */
+ ecx &= ~edi;
+ }
+ }
+
+ /* Verify the highest CAS latency - 1.0 clocks */
+ edi >>=1;
+ if(edi !=0) {
+ value = spd_read_byte(ctrl->channel0[i], 25);
+ if(value < 0 ) continue;
+ if(value > 0x75) {
+ /* The bus is too fast so we cannot support this cas latency */
+ ecx &= ~edi;
+ }
+ }
+
+ /* Now find which cas latencies are supported for the bus */
+ dword &= ecx;
+ /* go to the next DIMM */
+ }
+
+ /* After all of the arduous calculation setup with the fastest
+ * cas latency I can use.
+ */
+ value = __builtin_bsf(dword); // bsrl = log2 how about bsfl?
+ if(value ==0 ) return -1;
+ ecx = value -1;
+
+ byte = pci_read_config8(ctrl->d0, 0x78);
+ byte &= ~(DRT_CAS_MASK);
+ byte |= cas_latency_78[ecx];
+ pci_write_config8(ctrl->d0,0x78, byte);
+
+ /* set master DLL reset */
+ dword = pci_read_config32(ctrl->d0, 0x88);
+ dword |= (1<<26);
+
+ /* the rest of the references are words */
+// ecx<<=1; // don't need shift left, because we already define that in u16 array
+ pci_write_config32(ctrl->d0, 0x88, dword);
+
+
+ dword &= 0x0c0000ff; /* patch try register 88 is undocumented tnz */
+ dword |= 0xd2109800;
+
+ pci_write_config32(ctrl->d0, 0x88, dword);
+
+ word = pci_read_config16(ctrl->d0, 0x80);
+ word &= ~(0x0fff);
+ word |= cas_latency_80[ecx];
+
+ dword = pci_read_config32(ctrl->d0, 0x70);
+
+ if((dword & 0xff) !=0 ) {
+ dword >>=8;
+ if((dword & 0xff)!=0) {
+ dword >>=8;
+ if((dword & 0xff)!=0) {
+ dword >>= 8;
+ if( (dword & 0xff)!=0) {
+ word &=~(0x0fff); /* we have dimms in all 4 slots */
+ word |=cas_latency_80_4dimms[ecx];
+ }
+ }
+ }
+ }
+
+ pci_write_config16(ctrl->d0, 0x80, word);
+
+ dword = pci_read_config32(ctrl->d0, 0x88); /* reset master DLL reset */
+ dword &= ~(1<<26);
+ pci_write_config32(ctrl->d0, 0x88, dword);
+
+ RAM_RESET_DDR_PTR(ctrl);
+
+ return dimm_mask;
+
+}
+
+static long spd_set_dram_timing(const struct mem_controller *ctrl, long dimm_mask) {
+ /* Walk through all dimms and find the interesection of the
+ * supported dram timings.
+ */
+
+ int i;
+ uint32_t dword;
+ int value;
+
+ /* Read the inititial state */
+ dword = pci_read_config32(ctrl->d0, 0x78);
+#if 0
+# Intel clears top bit here, should we?
+# No the default is on and for normal timming it should be on. Tom Z
+ andl $0x7f, %esi
+#endif
+
+
+ for(i = 0; i < DIMM_SOCKETS; i++) {
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
+ /* Trp */
+ value = spd_read_byte(ctrl->channel0[i], 27);
+ if(value < 0) continue;
+ if(value > (15<<2)) {
+ /* At 133Mhz if row precharge time is above than 15ns than we
+ * need 3 clocks not 2 clocks.
+ */
+ dword &= ~(1<<0);
+ }
+ /* Trcd */
+ value = spd_read_byte(ctrl->channel0[i],29);
+ if(value < 0 ) continue;
+ if(value > (15<<2)) {
+ /* At 133Mhz if the Minimum ras to cas delay is about 15ns we
+ * need 3 clocks not 2 clocks.
+ */
+ dword &= ~((1<<3)|(1<<1));
+ }
+ /* Tras */
+ value = spd_read_byte(ctrl->channel0[i],30);
+ if(value < 0 ) continue;
+ /* Convert tRAS from ns to 133Mhz clock cycles */
+ value <<=1; /* mult by 2 to make 7.5 15 */
+ value += 15; /* Make certain we round up */
+ value --;
+ value &= 0xff; /* Clear the upper bits of eax */
+ value /= 15;
+
+ /* Don't even process small timings */
+ if(value >5) {
+ uint32_t tmp;
+ /* Die if the value is to large */
+ if(value>7) {
+ die ("unsupported_rcd\r\n");
+ }
+ /* Convert to clocks - 5 */
+ value -=5;
+ /* Convert the existing value into clocks - 5 */
+ tmp = (~((dword>>9) & 3) - 1) & 3;
+ /* See if we need a slower timing */
+ if(value > tmp ) {
+ /* O.k. put in our slower timing */
+ dword &= ~(3<<9);
+ dword |= ((~(value + 1)) & 3)<<9 ;
+ }
+ }
+
+ /* Trd */
+ /* Set to a 7 clock read delay. This is for 133Mhz
+ * with a CAS latency of 2.5 if 2.0 a 6 clock
+ * delay is good */
+ if( (pci_read_config8(ctrl->d0, 0x78) & 0x30) ==0 ){
+ dword &= ~(7<<24); /* CAS latency is 2.5, make 7 clks */
+ }
+
+ /*
+ * Back to Back Read Turn Around
+ */
+ /* Set to a 3 clock back to back read turn around. This
+ * is good for CAS latencys 2.5 and 2.0 */
+ dword |= (1<<27);
+ /*
+ * Back to Back Read-Write Turn Around
+ */
+ /* Set to a 5 clock back to back read to write turn around.
+ * 4 is a good delay if the CAS latency is 2.0 */
+ if( ( pci_read_config8(ctrl->d0, 0x78) & (1<<4)) == 0) {
+ dword &= ~(1<<28);
+ }
+ /*
+ * Back to Back Write-Read Turn Around
+ */
+ /* Set to a 2 clock back to back write to read turn around.
+ * This is good for 2.5 and 2.0 CAS Latencies. */
+ dword |= (1<<29);
+ }
+
+ pci_write_config32(ctrl->d0, 0x78, dword);
+
+ return dimm_mask;
+
+}
+static unsigned int spd_detect_dimms(const struct mem_controller *ctrl)
+{
+ unsigned dimm_mask;
+ int i;
+ dimm_mask = 0;
+#if DEBUG_RAM_CONFIG
+ print_debug("spd_detect_dimms:\r\n");
+#endif
+ for(i = 0; i < DIMM_SOCKETS; i++) {
+ int byte;
+ unsigned device;
+#if DEBUG_RAM_CONFIG
+ print_debug_hex32(i);
+ print_debug("\r\n");
+#endif
+ device = ctrl->channel0[i];
+ if (device) {
+ byte = spd_read_byte(ctrl->channel0[i], 2); /* Type */
+ if (byte == 7) {
+ dimm_mask |= (1 << i);
+ }
+ }
+#if 1
+ device = ctrl->channel1[i];
+ if (device) {
+ byte = spd_read_byte(ctrl->channel1[i], 2);
+ if (byte == 7) {
+ dimm_mask |= (1 << (i + DIMM_SOCKETS));
+ }
+ }
+#endif
+ }
+#if 1
+ i = (dimm_mask>>DIMM_SOCKETS);
+ if(i != (dimm_mask & ( (1<<DIMM_SOCKETS) - 1) ) ) {
+ die("now we only support dual channel\r\n");
+ }
+
+#endif
+
+ return dimm_mask;
+}
+
+static uint32_t set_dimm_size(const struct mem_controller *ctrl, struct dimm_size sz, uint32_t memsz, unsigned index)
+{
+ int i;
+ uint32_t base0, base1;
+ uint32_t dch;
+ uint8_t byte;
+
+ /* Double the size if we are using dual channel memory */
+// if (is_dual_channel(ctrl)) {
+ /* Since I have 2 identical channels double the sizes */
+ sz.side1++ ;
+ sz.side2++;
+// }
+
+ if (sz.side1 != sz.side2) {
+ sz.side2 = 0;
+ }
+
+ /* Make certain side1 of the dimm is at least 64MB */
+ if (sz.side1 >= (25 + 4)) {
+ memsz += (1 << (sz.side1 - (25 + 4)) ) ;
+ }
+ /* Write the size of side 1 of the dimm */
+ byte = memsz;
+ pci_write_config8(ctrl->d0, 0x60+(index<<1), byte);
+
+ /* Make certain side2 of the dimm is at least 64MB */
+ if (sz.side2 >= (25 + 4)) {
+ memsz += (1 << (sz.side2 - (25 + 4)) ) ;
+ }
+
+ /* Write the size of side 2 of the dimm */
+ byte = memsz;
+ pci_write_config8(ctrl->d0, 0x61+(index<<1), byte);
+
+ /* now, fill in DRBs where no physical slot exists */
+
+ for(i=index+1;i<4;i++) {
+ pci_write_config8(ctrl->d0, 0x60+(i<<1),byte);
+ pci_write_config8(ctrl->d0, 0x61+(i<<1),byte);
+
+ }
+
+ return memsz;
+
+}
+/* LAST_DRB_SLOT is a constant for any E7500 board */
+#define LAST_DRB_SLOT 0x67
+
+static long spd_set_ram_size(const struct mem_controller *ctrl, long dimm_mask)
+{
+ int i;
+ uint32_t memsz=0;
+ uint16_t word;
+
+ for(i = 0; i < DIMM_SOCKETS; i++) {
+ struct dimm_size sz;
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
+ sz = spd_get_dimm_size(ctrl->channel0[i]);
+#if DEBUG_RAM_CONFIG
+ print_debug("dimm size =");
+ print_debug_hex32(sz.side1);
+ print_debug(" ");
+ print_debug_hex32(sz.side2);
+ print_debug("\r\n");
+#endif
+
+ if (sz.side1 == 0) {
+ return -1; /* Report SPD error */
+ }
+ memsz = set_dimm_size(ctrl, sz, memsz, i);
+ }
+ /* 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
+ if(memsz < 0x30) {
+ /* I should really adjust all of this in C after I have resources
+ * to all of the pcie devices.
+ */
+
+ /* Round up to 128M granularity */
+ memsz++;
+ memsz &= 0xfe;
+ memsz<<= 10;
+ word = memsz;
+ pci_write_config16(ctrl->d0, 0xc4, word);
+ } else {
+
+ /* FIXME will this work with 3.5G of ram? */
+ /* Put TOLM at 3G */
+ pci_write_config16(ctrl->d0, 0xc4, 0xc000);
+ /* Hard code a 1G remap window, right after the ram */
+ if(memsz< 0x40){
+ word = 0x40; /* Ensure we are over 4G */
+ } else {
+ word = memsz;
+ }
+ pci_write_config16(ctrl->d0, 0xc6, word);
+ word += 0x10;
+ pci_write_config16(ctrl->d0, 0xc8, word);
+
+ }
+
+ return dimm_mask;
+}
+
+static void sdram_set_spd_registers(const struct mem_controller *ctrl) {
+ long dimm_mask;
+#if DEBUG_RAM_CONFIG
+ print_debug(spd_pre_init);
+#endif
+ //activate_spd_rom(ctrl);
+ dimm_mask = spd_detect_dimms(ctrl);
+ if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1))) {
+ print_debug("No memory for this controller\n");
+ return;
+ }
+ dimm_mask = spd_enable_clocks(ctrl, dimm_mask);
+ if (dimm_mask < 0)
+ goto hw_spd_err;
+ //spd_verify_dimms(ctrl);
+#if DEBUG_RAM_CONFIG
+ print_debug(spd_pre_set);
+#endif
+ dimm_mask = spd_set_row_attributes(ctrl,dimm_mask);
+ if (dimm_mask < 0)
+ goto hw_spd_err;
+ dimm_mask = spd_set_dram_controller_mode(ctrl,dimm_mask);
+ if (dimm_mask < 0)
+ goto hw_spd_err;
+ dimm_mask = spd_set_cas_latency(ctrl,dimm_mask);
+ if (dimm_mask < 0)
+ goto hw_spd_err;
+ dimm_mask = spd_set_dram_timing(ctrl,dimm_mask);
+ if (dimm_mask < 0)
+ goto hw_spd_err;
+#if DEBUG_RAM_CONFIG
+ print_debug(spd_post_init);
+#endif
+ //moved from dram_post_init
+ spd_set_ram_size(ctrl, dimm_mask);
+ return;
+ hw_spd_err:
+ /* Unrecoverable error reading SPD data */
+ print_err("SPD error - reset\r\n");
+ hard_reset();
+ return;
+}
+
+
+ /* 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.
+ */
+#if 0
+#define bank_msg "Bank "
+#define side_msg " Side "
+static void 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)
+
+}
+#endif
+
+#if 0
+static void ram_postinit(const struct mem_controller *ctrl) {
+#if DEBUG_RAM_CONFIG
+ 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)
+ spd_set_ram_size(ctrl);
+}
+#define FIRST_NORMAL_REFERENCE() CALL_LABEL(ram_postinit)
+
+#define SPECIAL_FINISHUP() CALL_LABEL(dram_finish)
+
+#endif
+
+#define ecc_pre_init "Initializing ECC state...\r\n"
+#define ecc_post_init "ECC state initialized.\r\n"
+static void dram_finish(const struct mem_controller *ctrl)
+{
+ uint32_t dword;
+ uint8_t byte;
+ /* Test to see if ECC support is enabled */
+ dword = pci_read_config32(ctrl->d0, 0x7c);
+ dword >>=20;
+ dword &=3;
+ if(dword == 2) {
+
+#if DEBUG_RAM_CONFIG
+ print_debug(ecc_pre_init);
+#endif
+ /* Initialize ECC bits , use ECC zero mode (new to 7501)*/
+ pci_write_config8(ctrl->d0, 0x52, 0x06);
+ pci_write_config8(ctrl->d0, 0x52, 0x07);
+ do {
+ byte = pci_read_config8(ctrl->d0, 0x52);
+
+ } while ( (byte & 0x08 ) == 0);
+
+ pci_write_config8(ctrl->d0, 0x52, byte & 0xfc);
+#if DEBUG_RAM_CONFIG
+ print_debug(ecc_post_init);
+#endif
+
+ /* Clear the ECC error bits */
+ pci_write_config8(ctrl->d0f1, 0x80, 0x03); /* dev 0, function 1, offset 80 */
+ pci_write_config8(ctrl->d0f1, 0x82, 0x03); /* dev 0, function 1, offset 82 */
+
+ pci_write_config32(ctrl->d0f1, 0x40, 1<<18); /* clear dev 0, function 1, offset 40; bit 18 by writing a 1 to it */
+ pci_write_config32(ctrl->d0f1, 0x44, 1<<18); /* clear dev 0, function 1, offset 44; bit 18 by writing a 1 to it */
+
+ pci_write_config8(ctrl->d0, 0x52, 0x0d);
+ }
+
+ dword = pci_read_config32(ctrl->d0, 0x7c); /* FCS_EN */
+ dword |= (1<<17);
+ pci_write_config32(ctrl->d0, 0x7c, dword);
+
+
+#if DEBUG_RAM_CONFIG
+ dumpnorth();
+#endif
+
+// verify_ram();
+}
+#if 0
+#define ERRFUNC(x, str) mem_err(x, str)
+
+
+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
+
+#define mem_err_err "ERROR: "
+#define mem_err_pair " on dimm pair "
+#define mem_err_byte " spd byte "
+static void 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
+
+}
+
+#endif
+
+
+#if ASM_CONSOLE_LOGLEVEL > BIOS_DEBUG
+#define ram_enable_1 "Ram Enable 1\r\n"
+#define ram_enable_2 "Ram Enable 2\r\n"
+#define ram_enable_3 "Ram Enable 3\r\n"
+#define ram_enable_4 "Ram Enable 4\r\n"
+#define ram_enable_5 "Ram Enable 5\r\n"
+#define ram_enable_6 "Ram Enable 6\r\n"
+#define ram_enable_7 "Ram Enable 7\r\n"
+#define ram_enable_8 "Ram Enable 8\r\n"
+#define ram_enable_9 "Ram Enable 9\r\n"
+#define ram_enable_10 "Ram Enable 10\r\n"
+#define ram_enable_11 "Ram Enable 11\r\n"
+#endif
+
+ /* Estimate that SLOW_DOWN_IO takes about 50&76us*/
+ /* delay for 200us */
+
+#define DO_DELAY \
+ udelay(200);
+// for(i=0; i<16;i++) { SLOW_DOWN_IO }
+
+
+#define EXTRA_DELAY DO_DELAY
+
+static void sdram_enable(int controllers, const struct mem_controller *ctrl)
+{
+ int i;
+ /* 1 & 2 Power up and start clocks */
+#if DEBUG_RAM_CONFIG
+ print_debug(ram_enable_1);
+ print_debug(ram_enable_2);
+#endif
+
+ /* A 200us delay is needed */
+
+ DO_DELAY
+ EXTRA_DELAY
+
+ /* 3. Apply NOP */
+#if DEBUG_RAM_CONFIG
+ print_debug(ram_enable_3);
+#endif
+ RAM_NOP(ctrl);
+ EXTRA_DELAY
+
+ /* 4 Precharge all */
+#if DEBUG_RAM_CONFIG
+ print_debug(ram_enable_4);
+#endif
+ RAM_PRECHARGE(ctrl);
+ EXTRA_DELAY
+
+ /* wait until the all banks idle state... */
+ /* 5. Issue EMRS to enable DLL */
+#if DEBUG_RAM_CONFIG
+ print_debug(ram_enable_5);
+#endif
+ RAM_EMRS(ctrl);
+ EXTRA_DELAY
+
+ /* 6. Reset DLL */
+#if DEBUG_RAM_CONFIG
+ print_debug(ram_enable_6);
+#endif
+ RAM_MRS(ctrl,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 */
+#if DEBUG_RAM_CONFIG
+ print_debug(ram_enable_7);
+#endif
+ RAM_PRECHARGE(ctrl);
+ EXTRA_DELAY
+
+ /* 8 Now we need 2 AUTO REFRESH / CBR cycles to be performed */
+#if DEBUG_RAM_CONFIG
+ print_debug(ram_enable_8);
+#endif
+ RAM_CBR(ctrl);
+ EXTRA_DELAY
+ RAM_CBR(ctrl);
+ EXTRA_DELAY
+ /* And for good luck 6 more CBRs */
+ RAM_CBR(ctrl);
+ EXTRA_DELAY
+ RAM_CBR(ctrl);
+ EXTRA_DELAY
+ RAM_CBR(ctrl);
+ EXTRA_DELAY
+ RAM_CBR(ctrl);
+ EXTRA_DELAY
+ RAM_CBR(ctrl);
+ EXTRA_DELAY
+ RAM_CBR(ctrl);
+ EXTRA_DELAY
+
+ /* 9 mode register set */
+#if DEBUG_RAM_CONFIG
+ print_debug(ram_enable_9);
+#endif
+ RAM_MRS(ctrl,0);
+ EXTRA_DELAY
+
+ /* 10 DDR Receive FIFO RE-Sync */
+#if DEBUG_RAM_CONFIG
+ print_debug(ram_enable_10);
+#endif
+ RAM_RESET_DDR_PTR(ctrl);
+ EXTRA_DELAY
+
+ /* 11 normal operation */
+#if DEBUG_RAM_CONFIG
+ print_debug(ram_enable_11);
+#endif
+ RAM_NORMAL(ctrl);
+
+
+ // special from v1
+ //FIRST_NORMAL_REFERENCE();
+ //spd_set_ram_size(ctrl, 0x03);
+
+ /* Finally enable refresh */
+ ENABLE_REFRESH(ctrl);
+
+ //SPECIAL_FINISHUP();
+ dram_finish(ctrl);
+
+}
+
diff --git a/src/northbridge/intel/e7501/raminit.h b/src/northbridge/intel/e7501/raminit.h
new file mode 100644
index 0000000000..c1dc4baeaf
--- /dev/null
+++ b/src/northbridge/intel/e7501/raminit.h
@@ -0,0 +1,12 @@
+#ifndef RAMINIT_H
+#define RAMINIT_H
+
+#define DIMM_SOCKETS 4
+struct mem_controller {
+ device_t d0, d0f1;
+ uint16_t channel0[DIMM_SOCKETS];
+ uint16_t channel1[DIMM_SOCKETS];
+};
+
+
+#endif /* RAMINIT_H */
diff --git a/src/northbridge/intel/e7501/reset_test.c b/src/northbridge/intel/e7501/reset_test.c
new file mode 100644
index 0000000000..79a5cdaee1
--- /dev/null
+++ b/src/northbridge/intel/e7501/reset_test.c
@@ -0,0 +1,18 @@
+/* Convert to C by yhlu */
+#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.
+ */
+static int bios_reset_detected(void) {
+ uint32_t dword;
+
+ dword = pci_read_config32(PCI_DEV(0, 0, 0), MCH_DRC);
+
+ if( (dword & DRC_DONE) != 0 ) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/src/southbridge/intel/i82801er/Config.lb b/src/southbridge/intel/i82801er/Config.lb
new file mode 100644
index 0000000000..cc77c755a7
--- /dev/null
+++ b/src/southbridge/intel/i82801er/Config.lb
@@ -0,0 +1,11 @@
+config i82801er.h
+driver i82801er.o
+driver i82801er_usb.o
+driver i82801er_lpc.o
+driver i82801er_ide.o
+driver i82801er_sata.o
+driver i82801er_usb2.o
+driver i82801er_ac97.o
+#driver i82801er_nic.o
+#driver i82801er_pci.o
+object i82801er_reset.o
diff --git a/src/southbridge/intel/i82801er/cmos_failover.c b/src/southbridge/intel/i82801er/cmos_failover.c
new file mode 100644
index 0000000000..9702313f9c
--- /dev/null
+++ b/src/southbridge/intel/i82801er/cmos_failover.c
@@ -0,0 +1,16 @@
+//kind of cmos_err for ich5
+#define RTC_FAILED (1 <<2)
+#define GEN_PMCON_3 0xa4
+static void check_cmos_failed(void)
+{
+
+ uint8_t byte;
+ byte = pci_read_config8(PCI_DEV(0,0x1f,0),GEN_PMCON_3);
+ if( byte & RTC_FAILED){
+//clear bit 1 and bit 2
+ byte = cmos_read(RTC_BOOT_BYTE);
+ byte &= 0x0c;
+ byte |= MAX_REBOOT_CNT << 4;
+ cmos_write(byte, RTC_BOOT_BYTE);
+ }
+}
diff --git a/src/southbridge/intel/i82801er/i82801er.c b/src/southbridge/intel/i82801er/i82801er.c
new file mode 100644
index 0000000000..565d672260
--- /dev/null
+++ b/src/southbridge/intel/i82801er/i82801er.c
@@ -0,0 +1,57 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/chip.h>
+#include "i82801er.h"
+
+void i82801er_enable(device_t dev)
+{
+ device_t lpc_dev;
+ unsigned int index;
+ uint16_t reg_old, reg;
+
+// all 82801er device ares in bus 0
+ unsigned int devfn;
+ devfn = PCI_DEVFN(0x1f, 0); // lpc
+ lpc_dev = dev_find_slot(0, devfn); // 0
+ if (!lpc_dev ) {
+ return;
+ }
+#if 0
+ if ((lpc_dev->vendor != PCI_VENDOR_ID_INTEL) ||
+ (lpc_dev->device != PCI_DEVICE_ID_INTEL_82801ER_1F0)) {
+ uint32_t id;
+ id = pci_read_config32(lpc_dev, PCI_VENDOR_ID);
+ if (id != (PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_82801ER_1F0 << 16))) {
+ return;
+ }
+ }
+#endif
+
+ index = (dev->path.u.pci.devfn & 7);
+ if((dev->path.u.pci.devfn & ~0x7)==devfn) { // D=0x1f
+ if(index==0){ //1f0
+ index = 14;
+ }
+ } else { // D=0x1d
+ index += 8;
+ }
+
+ reg_old = pci_read_config16(lpc_dev, FUNC_DIS);
+ reg = reg_old;
+ reg &= ~(1<<index); // enable it
+ if (!dev->enabled) {
+ reg |= (1<<index); // disable it
+ }
+ if (reg != reg_old) {
+ pci_write_config16(lpc_dev, FUNC_DIS, reg);
+ }
+ reg = pci_read_config16(lpc_dev, FUNC_DIS);
+
+}
+
+struct chip_control southbridge_intel_i82801er_control = {
+ .name = "Intel 82801er Southbridge",
+ .enable_dev = i82801er_enable,
+};
diff --git a/src/southbridge/intel/i82801er/i82801er.h b/src/southbridge/intel/i82801er/i82801er.h
new file mode 100644
index 0000000000..85dce4ecb7
--- /dev/null
+++ b/src/southbridge/intel/i82801er/i82801er.h
@@ -0,0 +1,81 @@
+#ifndef I82801ER_H
+#define I82801ER_H
+
+struct southbridge_intel_i82801er_config
+{
+};
+struct chip_control;
+extern struct chip_control southbridge_intel_i82801er_control;
+
+extern void i82801er_enable(device_t dev);
+
+/*
+000 = Non-combined. P0 is primary master. P1 is secondary master.
+001 = Non-combined. P0 is secondary master. P1 is primary master.
+100 = Combined. P0 is primary master. P1 is primary slave. IDE is secondary; Primary IDE channel
+disabled.
+101 = Combined. P0 is primary slave. P1 is primary master. IDE is secondary.
+110 = Combined. IDE is primary. P0 is secondary master. P1 is secondary slave; Secondary IDE
+channel disabled.
+111 = Combined. IDE is primary. P0 is secondary slave. P1 is secondary master.
+*/
+
+#define ICH5_SATA_ADDRESS_MAP 0
+
+
+#define PCI_DMA_CFG 0x90
+#define SERIRQ_CNTL 0x64
+#define GEN_CNTL 0xd0
+#define GEN_STS 0xd4
+#define RTC_CONF 0xd8
+#define GEN_PMCON_3 0xa4
+
+#define PCICMD 0x04
+#define PMBASE 0x40
+#define ACPI_CNTL 0x44
+#define BIOS_CNTL 0x4E
+#define GPIO_BASE 0x58
+#define GPIO_CNTL 0x5C
+#define PIRQA_ROUT 0x60
+#define PIRQE_ROUT 0x68
+#define COM_DEC 0xE0
+#define LPC_EN 0xE6
+#define FUNC_DIS 0xF2
+
+/* 1e f0 244e */
+
+#define CMD 0x04
+#define SBUS_NUM 0x19
+#define SUB_BUS_NUM 0x1A
+#define SMLT 0x1B
+#define IOBASE 0x1C
+#define IOLIM 0x1D
+#define MEMBASE 0x20
+#define MEMLIM 0x22
+#define CNF 0x50
+#define MTT 0x70
+#define PCI_MAST_STS 0x82
+
+#define RTC_FAILED (1 <<2)
+
+
+#define SMBUS_IO_BASE 0x1000
+
+#define SMBHSTSTAT 0x0
+#define SMBHSTCTL 0x2
+#define SMBHSTCMD 0x3
+#define SMBXMITADD 0x4
+#define SMBHSTDAT0 0x5
+#define SMBHSTDAT1 0x6
+#define SMBBLKDAT 0x7
+#define SMBTRNSADD 0x9
+#define SMBSLVDATA 0xa
+#define SMLINK_PIN_CTL 0xe
+#define SMBUS_PIN_CTL 0xf
+
+/* Between 1-10 seconds, We should never timeout normally
+ * Longer than this is just painful when a timeout condition occurs.
+ */
+#define SMBUS_TIMEOUT (100*1000)
+
+#endif /* I82801ER_H */
diff --git a/src/southbridge/intel/i82801er/i82801er_ac97.c b/src/southbridge/intel/i82801er/i82801er_ac97.c
new file mode 100644
index 0000000000..d16ab84fd9
--- /dev/null
+++ b/src/southbridge/intel/i82801er/i82801er_ac97.c
@@ -0,0 +1,41 @@
+/*
+ * (C) 2003 Linux Networx
+ */
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "i82801er.h"
+
+
+static struct device_operations ac97audio_ops = {
+ .read_resources = pci_dev_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .enable = i82801er_enable,
+ .init = 0,
+ .scan_bus = 0,
+};
+
+static struct pci_driver ac97audio_driver __pci_driver = {
+ .ops = &ac97audio_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801ER_1F5,
+};
+
+
+static struct device_operations ac97modem_ops = {
+ .read_resources = pci_dev_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .enable = i82801er_enable,
+ .init = 0,
+ .scan_bus = 0,
+};
+
+static struct pci_driver ac97modem_driver __pci_driver = {
+ .ops = &ac97modem_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801ER_1F6,
+};
diff --git a/src/southbridge/intel/i82801er/i82801er_early_smbus.c b/src/southbridge/intel/i82801er/i82801er_early_smbus.c
new file mode 100644
index 0000000000..ed014f1a86
--- /dev/null
+++ b/src/southbridge/intel/i82801er/i82801er_early_smbus.c
@@ -0,0 +1,156 @@
+
+//#define SMBUS_IO_BASE 0x1000
+#define SMBUS_IO_BASE 0x0f00
+
+#define SMBHSTSTAT 0x0
+#define SMBHSTCTL 0x2
+#define SMBHSTCMD 0x3
+#define SMBXMITADD 0x4
+#define SMBHSTDAT0 0x5
+#define SMBHSTDAT1 0x6
+#define SMBBLKDAT 0x7
+#define SMBTRNSADD 0x9
+#define SMBSLVDATA 0xa
+#define SMLINK_PIN_CTL 0xe
+#define SMBUS_PIN_CTL 0xf
+
+/* Between 1-10 seconds, We should never timeout normally
+ * Longer than this is just painful when a timeout condition occurs.
+ */
+#define SMBUS_TIMEOUT (100*1000*10)
+
+static void enable_smbus(void)
+{
+ device_t dev;
+ dev = pci_locate_device(PCI_ID(0x8086, 0x24d3), 0);
+ if (dev == PCI_DEV_INVALID) {
+ die("SMBUS controller not found\r\n");
+ }
+
+ print_debug("SMBus controller enabled\r\n");
+ /* set smbus iobase */
+ pci_write_config32(dev, 0x20, SMBUS_IO_BASE | 1);
+ /* Set smbus enable */
+ pci_write_config8(dev, 0x40, 0x01);
+ /* Set smbus iospace enable */
+ pci_write_config16(dev, 0x4, 0x01);
+ /* Disable interrupt generation */
+ outb(0, SMBUS_IO_BASE + SMBHSTCTL);
+ /* clear any lingering errors, so the transaction will run */
+ outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
+}
+
+
+static inline void smbus_delay(void)
+{
+ outb(0x80, 0x80);
+}
+
+static int smbus_wait_until_ready(void)
+{
+ unsigned long loops;
+ loops = SMBUS_TIMEOUT;
+ do {
+ unsigned char val;
+ smbus_delay();
+ val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
+ if ((val & 1) == 0) {
+ break;
+ }
+ if(loops == (SMBUS_TIMEOUT / 2)) {
+ outb(inb(SMBUS_IO_BASE + SMBHSTSTAT),
+ SMBUS_IO_BASE + SMBHSTSTAT);
+ }
+ } while(--loops);
+ return loops?0:-2;
+}
+
+static int smbus_wait_until_done(void)
+{
+ unsigned long loops;
+ loops = SMBUS_TIMEOUT;
+ do {
+ unsigned char val;
+ smbus_delay();
+
+ val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
+ if ( (val & 1) == 0) {
+ break;
+ }
+ if ((val & ~((1<<6)|(1<<0)) ) != 0 ) {
+ break;
+ }
+ } while(--loops);
+ return loops?0:-3;
+}
+
+static int smbus_read_byte(unsigned device, unsigned address)
+{
+ unsigned char global_control_register;
+ unsigned char global_status_register;
+ unsigned char byte;
+
+ if (smbus_wait_until_ready() < 0) {
+ return -2;
+ }
+
+ /* setup transaction */
+ /* disable interrupts */
+ outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xfe, SMBUS_IO_BASE + SMBHSTCTL);
+ /* set the device I'm talking too */
+ outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
+ /* set the command/address... */
+ outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
+ /* set up for a byte data read */
+ outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xe3) | (0x2<<2), SMBUS_IO_BASE + SMBHSTCTL);
+
+ /* clear any lingering errors, so the transaction will run */
+ outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
+
+ /* clear the data byte...*/
+ outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
+
+ /* start a byte read, with interrupts disabled */
+ outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), SMBUS_IO_BASE + SMBHSTCTL);
+
+
+ /* poll for transaction completion */
+ if (smbus_wait_until_done() < 0) {
+ return -3;
+ }
+
+ global_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT) & ~(1<<6); /* Ignore the In Use Status... */
+
+ /* read results of transaction */
+ byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
+
+ if (global_status_register != 2) {
+ return -1;
+ }
+ return byte;
+}
+#if 0
+static void smbus_write_byte(unsigned device, unsigned address, unsigned char val)
+{
+ if (smbus_wait_until_ready() < 0) {
+ return;
+ }
+
+ /* by LYH */
+ outb(0x37,SMBUS_IO_BASE + SMBHSTSTAT);
+ /* set the device I'm talking too */
+ outw(((device & 0x7f) << 1) | 0, SMBUS_IO_BASE + SMBHSTADDR);
+
+ /* data to send */
+ outb(val, SMBUS_IO_BASE + SMBHSTDAT);
+
+ outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
+
+ /* start the command */
+ outb(0xa, SMBUS_IO_BASE + SMBHSTCTL);
+
+ /* poll for transaction completion */
+ smbus_wait_until_done();
+ return;
+}
+#endif
diff --git a/src/southbridge/intel/i82801er/i82801er_ide.c b/src/southbridge/intel/i82801er/i82801er_ide.c
new file mode 100644
index 0000000000..b33a0b0f09
--- /dev/null
+++ b/src/southbridge/intel/i82801er/i82801er_ide.c
@@ -0,0 +1,53 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "i82801er.h"
+
+
+static void ide_init(struct device *dev)
+{
+#if ICH5_SATA_ADDRESS_MAP<=1
+ /* Enable ide devices so the linux ide driver will work */
+ uint16_t word;
+ uint8_t byte;
+ int enable_a=1, enable_b=1;
+
+
+ word = pci_read_config16(dev, 0x40);
+ word &= ~((1 << 15));
+ if (enable_a) {
+ /* Enable first ide interface */
+ word |= (1<<15);
+ printk_debug("IDE0 ");
+ }
+ pci_write_config16(dev, 0x40, word);
+
+ word = pci_read_config16(dev, 0x42);
+ word &= ~((1 << 15));
+ if (enable_a) {
+ /* Enable secondary ide interface */
+ word |= (1<<15);
+ printk_debug("IDE1 ");
+ }
+ pci_write_config16(dev, 0x42, word);
+#endif
+
+}
+
+static struct device_operations ide_ops = {
+ .read_resources = pci_dev_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = ide_init,
+ .scan_bus = 0,
+ .enable = i82801er_enable,
+};
+
+static struct pci_driver ide_driver __pci_driver = {
+ .ops = &ide_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801ER_1F1,
+};
+
diff --git a/src/southbridge/intel/i82801er/i82801er_lpc.c b/src/southbridge/intel/i82801er/i82801er_lpc.c
new file mode 100644
index 0000000000..c1ee7410ed
--- /dev/null
+++ b/src/southbridge/intel/i82801er/i82801er_lpc.c
@@ -0,0 +1,219 @@
+/*
+ * (C) 2003 Linux Networx, SuSE Linux AG
+ * (C) 2004 Tyan Computer
+ */
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <device/chip.h>
+#include <pc80/mc146818rtc.h>
+#include "i82801er.h"
+
+void isa_dma_init(void); /* from /pc80/isa-dma.c */
+
+#define NMI_OFF 0
+
+void i82801er_enable_ioapic( struct device *dev)
+{
+ uint32_t dword;
+ volatile uint32_t *ioapic_sba = (volatile uint32_t *)0xfec00000;
+ volatile uint32_t *ioapic_sbd = (volatile uint32_t *)0xfec00010;
+
+ dword = pci_read_config32(dev, GEN_CNTL);
+ dword |= (3 << 7); /* enable ioapic */
+ dword |= (1 <<13); /* coprocessor error enable */
+ dword |= (1 << 1); /* delay transaction enable */
+ dword |= (1 << 2); /* DMA collection buf enable */
+ pci_write_config32(dev, GEN_CNTL, dword);
+ printk_debug("ioapic southbridge enabled %x\n",dword);
+ *ioapic_sba=0;
+ *ioapic_sbd=(2<<24);
+ //lyh *ioapic_sba=3;
+ //lyh *ioapic_sbd=1;
+ *ioapic_sba=0;
+ dword=*ioapic_sbd;
+ printk_debug("Southbridge apic id = %x\n",dword);
+ if(dword!=(2<<24))
+ for(;;);
+ //lyh *ioapic_sba=3;
+ //lyh dword=*ioapic_sbd;
+ //lyh printk_debug("Southbridge apic DT = %x\n",dword);
+ //lyh if(dword!=1)
+ //lyh for(;;);
+
+
+}
+void i82801er_enable_serial_irqs( struct device *dev)
+{
+ pci_write_config8(dev, SERIRQ_CNTL, (1 << 7)|(1 << 6)|((21 - 17) << 2)|(0<< 0));
+}
+void i82801er_lpc_route_dma( struct device *dev, uint8_t mask)
+{
+ uint16_t word;
+ int i;
+ word = pci_read_config8(dev, PCI_DMA_CFG);
+ word &= ((1 << 10) - (1 << 8));
+ for(i = 0; i < 8; i++) {
+ if (i == 4)
+ continue;
+ word |= ((mask & (1 << i))? 3:1) << (i*2);
+ }
+ pci_write_config16(dev, PCI_DMA_CFG, word);
+}
+void i82801er_rtc_init(struct device *dev)
+{
+ uint8_t byte;
+ uint32_t dword;
+ int rtc_failed;
+ byte = pci_read_config8(dev, GEN_PMCON_3);
+ rtc_failed = byte & RTC_FAILED;
+ if (rtc_failed) {
+ byte &= ~(1 << 1); /* preserve the power fail state */
+ pci_write_config8(dev, GEN_PMCON_3, byte);
+ }
+ dword = pci_read_config32(dev, GEN_STS);
+ rtc_failed |= dword & (1 << 2);
+ rtc_init(rtc_failed);
+}
+
+
+void i82801er_1f0_misc(struct device *dev)
+{
+ pci_write_config16(dev, PCICMD, 0x014f);
+ pci_write_config32(dev, PMBASE, 0x00001001);
+ pci_write_config8(dev, ACPI_CNTL, 0x10);
+ pci_write_config32(dev, GPIO_BASE, 0x00001181);
+ pci_write_config8(dev, GPIO_CNTL, 0x10);
+ pci_write_config32(dev, PIRQA_ROUT, 0x0A05030B);
+ pci_write_config8(dev, PIRQE_ROUT, 0x07);
+ pci_write_config8(dev, RTC_CONF, 0x04);
+ pci_write_config8(dev, COM_DEC, 0x10); //lyh E0->
+ pci_write_config16(dev, LPC_EN, 0x000F); //LYH 000D->
+}
+
+static void enable_hpet(struct device *dev)
+{
+ const unsigned long hpet_address = 0xfed0000;
+
+ uint32_t dword;
+ uint32_t code = (0 & 0x3);
+
+ dword = pci_read_config32(dev, GEN_CNTL);
+ dword |= (1 << 17); /* enable hpet */
+ /*Bits [16:15]Memory Address Range
+ 00 FED0_0000h - FED0_03FFh
+ 01 FED0_1000h - FED0_13FFh
+ 10 FED0_2000h - FED0_23FFh
+ 11 FED0_3000h - FED0_33FFh*/
+
+ dword &= ~(3 << 15); /* clear it */
+ dword |= (code<<15);
+
+ printk_debug("enabling HPET @0x%x\n", hpet_address | (code <<12) );
+}
+
+static void lpc_init(struct device *dev)
+{
+ uint8_t byte;
+ int pwr_on=-1;
+ int nmi_option;
+
+ /* IO APIC initialization */
+ i82801er_enable_ioapic(dev);
+
+ i82801er_enable_serial_irqs(dev);
+
+ /* posted memory write enable */
+ byte = pci_read_config8(dev, 0x46);
+ pci_write_config8(dev, 0x46, byte | (1<<0));
+
+ /* power after power fail */
+ /* FIXME this doesn't work! */
+ /* Which state do we want to goto after g3 (power restored)?
+ * 0 == S0 Full On
+ * 1 == S5 Soft Off
+ */
+ pci_write_config8(dev, GEN_PMCON_3, pwr_on?0:1);
+ printk_info("set power %s after power fail\n", pwr_on?"on":"off");
+#if 0
+ /* Enable Error reporting */
+ /* Set up sync flood detected */
+ byte = pci_read_config8(dev, 0x47);
+ byte |= (1 << 1);
+ pci_write_config8(dev, 0x47, byte);
+#endif
+
+ /* Set up NMI on errors */
+ byte = pci_read_config8(dev, 0x61);
+ byte |= (1 << 3); /* IOCHK# NMI Enable */
+ byte |= (1 << 6); /* PCI SERR# Enable */
+ pci_write_config8(dev, 0x61, byte);
+ byte = pci_read_config8(dev, 0x70);
+ nmi_option = NMI_OFF;
+ get_option(&nmi_option, "nmi");
+ if (nmi_option) {
+ byte |= (1 << 7); /* set NMI */
+ pci_write_config8(dev, 0x70, byte);
+ }
+
+ /* Initialize the real time clock */
+ i82801er_rtc_init(dev);
+
+ i82801er_lpc_route_dma(dev, 0xff);
+
+ /* Initialize isa dma */
+ isa_dma_init();
+
+ i82801er_1f0_misc(dev);
+ /* Initialize the High Precision Event Timers */
+ enable_hpet(dev);
+}
+
+static void i82801er_lpc_read_resources(device_t dev)
+{
+ unsigned int reg;
+
+ /* Get the normal pci resources of this device */
+ pci_dev_read_resources(dev);
+
+ /* Find my place in the resource list */
+ reg = dev->resources;
+
+ /* Add an extra subtractive resource for both memory and I/O */
+ dev->resource[reg].base = 0;
+ dev->resource[reg].size = 0;
+ dev->resource[reg].align = 0;
+ dev->resource[reg].gran = 0;
+ dev->resource[reg].limit = 0;
+ dev->resource[reg].flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
+ dev->resource[reg].index = 0;
+ reg++;
+
+ dev->resource[reg].base = 0;
+ dev->resource[reg].size = 0;
+ dev->resource[reg].align = 0;
+ dev->resource[reg].gran = 0;
+ dev->resource[reg].limit = 0;
+ dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
+ dev->resource[reg].index = 0;
+ reg++;
+
+ dev->resources = reg;
+}
+
+static struct device_operations lpc_ops = {
+ .read_resources = i82801er_lpc_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = lpc_init,
+ .scan_bus = scan_static_bus,
+ .enable = i82801er_enable,
+};
+
+static struct pci_driver lpc_driver __pci_driver = {
+ .ops = &lpc_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801ER_1F0,
+};
diff --git a/src/southbridge/intel/i82801er/i82801er_nic.c b/src/southbridge/intel/i82801er/i82801er_nic.c
new file mode 100644
index 0000000000..4815cf19e0
--- /dev/null
+++ b/src/southbridge/intel/i82801er/i82801er_nic.c
@@ -0,0 +1,21 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "i82801er.h"
+
+
+static struct device_operations nic_ops = {
+ .read_resources = pci_dev_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = 0,
+ .scan_bus = 0,
+};
+
+static struct pci_driver nic_driver __pci_driver = {
+ .ops = &nic_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = 0x1051,
+};
diff --git a/src/southbridge/intel/i82801er/i82801er_pci.c b/src/southbridge/intel/i82801er/i82801er_pci.c
new file mode 100644
index 0000000000..201cedb1a9
--- /dev/null
+++ b/src/southbridge/intel/i82801er/i82801er_pci.c
@@ -0,0 +1,33 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "i82801er.h"
+
+static void pci_init(struct device *dev)
+{
+ /* Enable pci error detecting */
+ uint32_t dword;
+ /* System error enable */
+ dword = pci_read_config32(dev, 0x04);
+ dword |= (1<<8); /* SERR# Enable */
+ dword |= (1<<6); /* Parity Error Response */
+ pci_write_config32(dev, 0x04, dword);
+
+}
+
+static struct device_operations pci_ops = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = pci_init,
+ .scan_bus = pci_scan_bridge,
+};
+
+static struct pci_driver pci_driver __pci_driver = {
+ .ops = &pci_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801ER_1E0,
+};
+
diff --git a/src/southbridge/intel/i82801er/i82801er_reset.c b/src/southbridge/intel/i82801er/i82801er_reset.c
new file mode 100644
index 0000000000..3d7a4b79b6
--- /dev/null
+++ b/src/southbridge/intel/i82801er/i82801er_reset.c
@@ -0,0 +1,7 @@
+#include <arch/io.h>
+
+void hard_reset(void)
+{
+ /* Try rebooting through port 0xcf9 */
+ outb((0 <<3)|(1<<2)|(1<<1), 0xcf9);
+}
diff --git a/src/southbridge/intel/i82801er/i82801er_sata.c b/src/southbridge/intel/i82801er/i82801er_sata.c
new file mode 100644
index 0000000000..b00231e459
--- /dev/null
+++ b/src/southbridge/intel/i82801er/i82801er_sata.c
@@ -0,0 +1,75 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "i82801er.h"
+
+static void sata_init(struct device *dev)
+{
+
+ uint16_t word;
+ uint8_t byte;
+ int enable_c=1, enable_d=1;
+ int i;
+
+ //Enable Serial ATA port
+ byte = pci_read_config8(dev,0x90);
+ byte &= 0xf8;
+ byte |= ICH5_SATA_ADDRESS_MAP & 7;
+ pci_write_config8(dev,0x90,byte);
+
+// for(i=0;i<10;i++) {
+ word = pci_read_config16(dev,0x92);
+ word &= 0xfffc;
+// if( (word & 0x0003) == 0x0003) break;
+ word |= 0x0003; // enable P0/P1
+ pci_write_config16(dev,0x92,word);
+// }
+
+// for(i=0;i<10;i++) {
+ /* enable ide0 */
+ word = pci_read_config16(dev, 0x40);
+ word &= ~(1 << 15);
+ if(enable_c==0) {
+// if( (word & 0x8000) == 0x0000) break;
+ word |= 0x0000;
+ }
+ else {
+// if( (word & 0x8000) == 0x8000) break;
+ word |= 0x8000;
+ }
+ pci_write_config16(dev, 0x40, word);
+// }
+ /* enable ide1 */
+// for(i=0;i<10;i++) {
+ word = pci_read_config16(dev, 0x42);
+ word &= ~(1 << 15);
+ if(enable_d==0) {
+// if( (word & 0x8000) == 0x0000) break;
+ word |= 0x0000;
+ }
+ else {
+// if( (word & 0x8000) == 0x8000) break;
+ word |= 0x8000;
+ }
+ pci_write_config16(dev, 0x42, word);
+// }
+
+}
+
+static struct device_operations sata_ops = {
+ .read_resources = pci_dev_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = sata_init,
+ .scan_bus = 0,
+ .enable = i82801er_enable,
+};
+
+static struct pci_driver stat_driver __pci_driver = {
+ .ops = &sata_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801ER_1F2_R,
+};
+
diff --git a/src/southbridge/intel/i82801er/i82801er_smbus.c b/src/southbridge/intel/i82801er/i82801er_smbus.c
new file mode 100644
index 0000000000..fd06871234
--- /dev/null
+++ b/src/southbridge/intel/i82801er/i82801er_smbus.c
@@ -0,0 +1,92 @@
+#include <smbus.h>
+#include <pci.h>
+#include <arch/io.h>
+
+#define PM_BUS 0
+#define PM_DEVFN PCI_DEVFN(0x1f,3)
+
+#define SMBUS_IO_BASE 0x1000
+#define SMBHSTSTAT 0
+#define SMBHSTCTL 2
+#define SMBHSTCMD 3
+#define SMBHSTADD 4
+#define SMBHSTDAT0 5
+#define SMBHSTDAT1 6
+#define SMBBLKDAT 7
+
+void smbus_enable(void)
+{
+ unsigned char byte;
+ /* iobase addr */
+ pcibios_write_config_dword(PM_BUS, PM_DEVFN, 0x20, SMBUS_IO_BASE | 1);
+ /* smbus enable */
+ pcibios_write_config_byte(PM_BUS, PM_DEVFN, 0x40, 1);
+ /* iospace enable */
+ pcibios_write_config_word(PM_BUS, PM_DEVFN, 0x4, 1);
+
+ /* Disable interrupt generation */
+ outb(0, SMBUS_IO_BASE + SMBHSTCTL);
+
+}
+
+void smbus_setup(void)
+{
+ outb(0, SMBUS_IO_BASE + SMBHSTSTAT);
+}
+
+static void smbus_wait_until_ready(void)
+{
+ while((inb(SMBUS_IO_BASE + SMBHSTSTAT) & 1) == 1) {
+ /* nop */
+ }
+}
+
+static void smbus_wait_until_done(void)
+{
+ unsigned char byte;
+ do {
+ byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
+ }
+ while((byte &1) == 1);
+ while( (byte & ~1) == 0) {
+ byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
+ }
+}
+
+int smbus_read_byte(unsigned device, unsigned address, unsigned char *result)
+{
+ unsigned char host_status_register;
+ unsigned char byte;
+
+ smbus_wait_until_ready();
+
+ /* setup transaction */
+ /* disable interrupts */
+ outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL);
+ /* set the device I'm talking too */
+ outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBHSTADD);
+ /* set the command/address... */
+ outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
+ /* set up for a byte data read */
+ outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x2 << 2), SMBUS_IO_BASE + SMBHSTCTL);
+
+ /* clear any lingering errors, so the transaction will run */
+ outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
+
+ /* clear the data byte...*/
+ outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
+
+ /* start the command */
+ outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), SMBUS_IO_BASE + SMBHSTCTL);
+
+ /* poll for transaction completion */
+ smbus_wait_until_done();
+
+ host_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT);
+
+ /* read results of transaction */
+ byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
+
+ *result = byte;
+ return host_status_register != 0x02;
+}
diff --git a/src/southbridge/intel/i82801er/i82801er_usb.c b/src/southbridge/intel/i82801er/i82801er_usb.c
new file mode 100644
index 0000000000..49c6263add
--- /dev/null
+++ b/src/southbridge/intel/i82801er/i82801er_usb.c
@@ -0,0 +1,54 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "i82801er.h"
+
+static void usb_init(struct device *dev)
+{
+ uint32_t cmd;
+
+#if 0
+ printk_debug("USB: Setting up controller.. ");
+ cmd = pci_read_config32(dev, PCI_COMMAND);
+ pci_write_config32(dev, PCI_COMMAND,
+ cmd | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE);
+
+
+ printk_debug("done.\n");
+#endif
+
+}
+
+static struct device_operations usb_ops = {
+ .read_resources = pci_dev_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = usb_init,
+ .scan_bus = 0,
+ .enable = i82801er_enable,
+};
+
+static struct pci_driver usb_driver_1 __pci_driver = {
+ .ops = &usb_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801ER_1D0,
+};
+static struct pci_driver usb_driver_2 __pci_driver = {
+ .ops = &usb_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801ER_1D1,
+};
+static struct pci_driver usb_driver_3 __pci_driver = {
+ .ops = &usb_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801ER_1D2,
+};
+static struct pci_driver usb_driver_4 __pci_driver = {
+ .ops = &usb_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801ER_1D3,
+};
+
diff --git a/src/southbridge/intel/i82801er/i82801er_usb2.c b/src/southbridge/intel/i82801er/i82801er_usb2.c
new file mode 100644
index 0000000000..551d4ed3e0
--- /dev/null
+++ b/src/southbridge/intel/i82801er/i82801er_usb2.c
@@ -0,0 +1,39 @@
+//2003 Copywright Tyan
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "i82801er.h"
+
+static void usb2_init(struct device *dev)
+{
+ uint32_t cmd;
+
+#if 0
+ printk_debug("USB: Setting up controller.. ");
+ cmd = pci_read_config32(dev, PCI_COMMAND);
+ pci_write_config32(dev, PCI_COMMAND,
+ cmd | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE);
+
+
+ printk_debug("done.\n");
+#endif
+}
+
+static struct device_operations usb2_ops = {
+ .read_resources = pci_dev_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = usb2_init,
+ .scan_bus = 0,
+ .enable = i82801er_enable,
+};
+
+static struct pci_driver usb2_driver __pci_driver = {
+ .ops = &usb2_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801ER_1D7,
+};
diff --git a/src/southbridge/intel/i82870/82870.h b/src/southbridge/intel/i82870/82870.h
new file mode 100644
index 0000000000..f9289d4027
--- /dev/null
+++ b/src/southbridge/intel/i82870/82870.h
@@ -0,0 +1,10 @@
+/* for io apic 1461 */
+#define PCICMD 0x04
+#define SUBSYS 0x2c
+#define MBAR 0x10
+#define ABAR 0x40
+
+/* for pci bridge 1460 */
+#define MTT 0x042
+#define HCCR 0x0f0
+#define ACNF 0x0e0
diff --git a/src/southbridge/intel/i82870/Config.lb b/src/southbridge/intel/i82870/Config.lb
new file mode 100644
index 0000000000..e6a96517f0
--- /dev/null
+++ b/src/southbridge/intel/i82870/Config.lb
@@ -0,0 +1,3 @@
+driver p64h2_ioapic.o
+driver p64h2_pcibridge.o
+#driver p64h2_pci_parity.o
diff --git a/src/southbridge/intel/i82870/p64h2_ioapic.c b/src/southbridge/intel/i82870/p64h2_ioapic.c
new file mode 100644
index 0000000000..e2bb33883d
--- /dev/null
+++ b/src/southbridge/intel/i82870/p64h2_ioapic.c
@@ -0,0 +1,89 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <pc80/mc146818rtc.h>
+#include "82870.h"
+
+static int ioapic_no = 0;
+
+static void p64h2_ioapic_enable(device_t dev)
+{
+ uint32_t dword;
+ uint16_t word;
+
+ /* We have to enable MEM and Bus Master for IOAPIC */
+ word = 0x0146;
+ pci_write_config16(dev, PCICMD, word);
+ dword = 0x358015d9;
+ pci_write_config32(dev, SUBSYS, dword);
+
+
+}
+
+static void p64h2_ioapic_init(device_t dev)
+{
+ uint32_t dword;
+ uint16_t word;
+ int i, addr;
+
+ volatile uint32_t *ioapic_a; /* io apic io memory space command address */
+ volatile uint32_t *ioapic_d; /* io apic io memory space data address */
+
+ i = ioapic_no++;
+
+ if(i<3) /* io apic address numbers are 3,4,5,&8 */
+ addr=i+3;
+ else
+ addr=i+5;
+ /* Read the MBAR address for setting up the io apic in io memory space */
+ dword = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
+ ioapic_a = (uint32_t *) dword;
+ ioapic_d = ioapic_a +0x04;
+ printk_debug("IOAPIC %d at %02x:%02x.%01x MBAR = %x DataAddr = %x\n",
+ addr, dev->bus->secondary,
+ PCI_SLOT(dev->path.u.pci.devfn), PCI_FUNC(dev->path.u.pci.devfn),
+ ioapic_a, ioapic_d);
+
+#if 0
+ dword = (u32)ioapic_a;
+ word = 0x8000 + ((dword >>8)&0x0fff);
+ pci_write_config_word(dev, ABAR, word);
+#endif
+ /* Set up the io apic for the p64h2 - 1461 */
+ *ioapic_a=0;
+ *ioapic_d=(addr<<24); /* Set the address number */
+ *ioapic_a=3;
+ *ioapic_d=1; /* Enable the io apic */
+
+ /* This code test the setup to see if we really found the io apic */
+ *ioapic_a=0;
+ dword=*ioapic_d;
+ printk_debug("PCI %d apic id = %x\n",addr,dword);
+ if(dword!=(addr<<24))
+ for(;;);
+ *ioapic_a=3;
+ dword=*ioapic_d;
+ printk_debug("PCI %d apic DT = %x\n",addr,dword);
+ if(dword!=1)
+ for(;;);
+
+
+}
+
+static struct device_operations ioapic_ops = {
+ .read_resources = pci_dev_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = p64h2_ioapic_init,
+ .scan_bus = 0,
+ .enable = p64h2_ioapic_enable,
+};
+
+static struct pci_driver ioapic_driver __pci_driver = {
+ .ops = &ioapic_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82870_1E0,
+
+};
diff --git a/src/southbridge/intel/i82870/p64h2_pci_parity.c b/src/southbridge/intel/i82870/p64h2_pci_parity.c
new file mode 100644
index 0000000000..d80f9213c9
--- /dev/null
+++ b/src/southbridge/intel/i82870/p64h2_pci_parity.c
@@ -0,0 +1,26 @@
+#include <mem.h>
+#include <pci.h>
+#include <arch/io.h>
+#include <printk.h>
+#
+
+void p64h2_pci_parity_enable(void)
+{
+ uint8_t reg;
+
+ /* 2SERREN - SERR enable for PCI bridge secondary device */
+ /* 2PEREN - Parity error for PCI bridge secondary device */
+ pcibios_read_config_byte(1, ((29 << 3) + (0 << 0)), 0x3e, &reg);
+ reg |= ((1 << 1) + (1 << 0));
+ pcibios_write_config_byte(1, ((29 << 3) + (0 << 0)), 0x3e, reg);
+
+ /* 2SERREN - SERR enable for PCI bridge secondary device */
+ /* 2PEREN - Parity error for PCI bridge secondary device */
+ pcibios_read_config_byte(1, ((31 << 3) + (0 << 0)), 0x3e, &reg);
+ reg |= ((1 << 1) + (1 << 0));
+ pcibios_write_config_byte(1, ((31 << 3) + (0 << 0)), 0x3e, reg);
+
+ return;
+}
+
+
diff --git a/src/southbridge/intel/i82870/p64h2_pcibridge.c b/src/southbridge/intel/i82870/p64h2_pcibridge.c
new file mode 100644
index 0000000000..6f161e900b
--- /dev/null
+++ b/src/southbridge/intel/i82870/p64h2_pcibridge.c
@@ -0,0 +1,39 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <pc80/mc146818rtc.h>
+#include "82870.h"
+
+static void p64h2_pcix_init(device_t dev)
+{
+ uint32_t dword;
+ uint16_t word;
+ uint8_t byte;
+
+
+ /* The purpose of changes to HCCR, ACNF, and MTT is to speed up the
+ PCI bus for cards having high speed transfers. */
+ dword = 0xc2040002;
+ pci_write_config32(dev, HCCR, dword);
+ dword = 0x0000c3bf;
+ pci_write_config32(dev, ACNF, dword);
+ byte = 0x08;
+ pci_write_config8(dev, MTT, byte);
+
+}
+static struct device_operations pcix_ops = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = p64h2_pcix_init,
+ .scan_bus = pci_scan_bridge,
+};
+
+static struct pci_driver pcix_driver __pci_driver = {
+ .ops = &pcix_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82870_1F0,
+};
+
diff --git a/src/superio/winbond/w83627hf/superio.c b/src/superio/winbond/w83627hf/superio.c
index 04a6e2a7e8..ee0a6872e3 100644
--- a/src/superio/winbond/w83627hf/superio.c
+++ b/src/superio/winbond/w83627hf/superio.c
@@ -16,13 +16,100 @@
#include "chip.h"
#include "w83627hf.h"
-static void init(device_t dev)
+
+void pnp_enter_ext_func_mode(device_t dev) {
+ outb(0x87, dev->path.u.pnp.port);
+ outb(0x87, dev->path.u.pnp.port);
+}
+void pnp_exit_ext_func_mode(device_t dev) {
+ outb(0xaa, dev->path.u.pnp.port);
+}
+
+void pnp_write_hwm(unsigned long port_base, uint8_t reg, uint8_t value)
+{
+ outb(reg, port_base+5);
+ outb(value, port_base+6);
+}
+
+uint8_t pnp_read_hwm(unsigned long port_base, uint8_t reg)
+{
+ outb(reg, port_base + 5);
+ return inb(port_base + 6);
+}
+
+static void enable_hwm_smbus(device_t dev) {
+ uint8_t reg, value;
+ reg = 0x2b;
+ value = pnp_read_config(dev, reg);
+ value &= 0x3f;
+ pnp_write_config(dev, reg, value);
+}
+
+#if 0
+static void dump_pnp_device(device_t dev)
+{
+ int i;
+ print_debug("\r\n");
+
+ for(i = 0; i <= 255; i++) {
+ uint8_t reg, val;
+ if ((i & 0x0f) == 0) {
+ print_debug_hex8(i);
+ print_debug_char(':');
+ }
+ reg = i;
+ if(i!=0xaa) {
+ val = pnp_read_config(dev, reg);
+ }
+ else {
+ val = 0xaa;
+ }
+ print_debug_char(' ');
+ print_debug_hex8(val);
+ if ((i & 0x0f) == 0x0f) {
+ print_debug("\r\n");
+ }
+ }
+}
+#endif
+
+static void init_hwm(unsigned long base)
+{
+ uint8_t reg, value;
+ int i;
+
+ unsigned hwm_reg_values[] = {
+// reg mask data
+ 0x40 , 0xff , 0x81, // ; Start Hardware Monitoring for WIN627
+ 0x48 , 0xaa , 0x2a, // ; Program SIO SMBus BAR to 54h>>1
+// 0x48 , 0xc8 , 0x48, // ; Program SIO SMBus BAR to 90h>>1
+ 0x4A , 0x21 , 0x21, // ; Program T2 SMBus BAR to 92h>>1 &
+ // ; Program T3 SMBus BAR to 94h>>1
+ 0x4E , 0x80 , 0x00,
+ 0x43 , 0x00 , 0xFF,
+ 0x44 , 0x00 , 0x3F,
+ 0x4C , 0xBF , 0x18,
+ 0x4D , 0xFF , 0x80 // ; Turn Off Beep
+
+ };
+
+ for(i = 0; i< sizeof(hwm_reg_values)/sizeof(hwm_reg_values[0]); i+=3 ) {
+ reg = hwm_reg_values[i];
+ value = pnp_read_hwm(base, reg);
+ value &= 0xff & hwm_reg_values[i+1];
+ value |= 0xff & hwm_reg_values[i+2];
+#if 0
+ printk_debug("base = 0x%04x, reg = 0x%02x, value = 0x%02x\r\n", base,reg,value);
+#endif
+ pnp_write_hwm(base,reg, value);
+ }
+}
+
+
+static void w83627hf_init(device_t dev)
{
struct superio_winbond_w83627hf_config *conf;
struct resource *res0, *res1;
- /* Wishlist handle well known programming interfaces more
- * generically.
- */
if (!dev->enabled) {
return;
}
@@ -41,15 +128,70 @@ static void init(device_t dev)
res1 = get_resource(dev, PNP_IDX_IO1);
init_pc_keyboard(res0->base, res1->base, &conf->keyboard);
break;
+ case W83627HF_HWM:
+ res0 = get_resource(dev, PNP_IDX_IO0);
+ init_hwm(res0->base);
+ break;
+ }
+
+}
+
+void w83627hf_pnp_set_resources(device_t dev)
+{
+
+ pnp_enter_ext_func_mode(dev);
+
+ pnp_set_resources(dev);
+
+#if 0
+ dump_pnp_device(dev);
+#endif
+
+ pnp_exit_ext_func_mode(dev);
+
+}
+
+void w83627hf_pnp_enable_resources(device_t dev)
+{
+ pnp_enter_ext_func_mode(dev);
+
+ pnp_enable_resources(dev);
+
+ switch(dev->path.u.pnp.device) {
+ case W83627HF_HWM:
+ //set the pin 91,92 as I2C bus
+ printk_debug("w83627hf hwm smbus enabled\r\n");
+ enable_hwm_smbus(dev);
+ break;
}
+
+#if 0
+ dump_pnp_device(dev);
+#endif
+
+ pnp_exit_ext_func_mode(dev);
+
+}
+
+void w83627hf_pnp_enable(device_t dev)
+{
+
+ if (!dev->enabled) {
+ pnp_enter_ext_func_mode(dev);
+
+ pnp_set_logical_device(dev);
+ pnp_set_enable(dev, 0);
+
+ pnp_exit_ext_func_mode(dev);
+ }
}
static struct device_operations ops = {
.read_resources = pnp_read_resources,
- .set_resources = pnp_set_resources,
- .enable_resources = pnp_enable_resources,
- .enable = pnp_enable,
- .init = init,
+ .set_resources = w83627hf_pnp_set_resources,
+ .enable_resources = w83627hf_pnp_enable_resources,
+ .enable = w83627hf_pnp_enable,
+ .init = w83627hf_init,
};
static struct pnp_info pnp_dev_info[] = {
@@ -61,8 +203,8 @@ static struct pnp_info pnp_dev_info[] = {
{ &ops, W83627HF_KBC, PNP_IO0 | PNP_IO1 | PNP_IRQ0 | PNP_IRQ1, { 0x7ff, 0 }, { 0x7ff, 0x4}, },
{ &ops, W83627HF_CIR, PNP_IO0 | PNP_IRQ0, { 0x7f8, 0 }, },
{ &ops, W83627HF_GAME_MIDI_GPIO1, PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x7ff, 0 }, {0x7fe, 4} },
- { &ops, W83627HF_GPIO2, PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x7ff, 0 }, {0x7fe, 4} },
- { &ops, W83627HF_GPIO3, PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x7ff, 0 }, {0x7fe, 4} },
+ { &ops, W83627HF_GPIO2,},
+ { &ops, W83627HF_GPIO3,},
{ &ops, W83627HF_ACPI, PNP_IRQ0, },
{ &ops, W83627HF_HWM, PNP_IO0 | PNP_IRQ0, { 0xff8, 0 } },
};
@@ -77,3 +219,4 @@ struct chip_control superio_winbond_w83627hf_control = {
.enumerate = enumerate,
.name = "Winbond w83627hf"
};
+