aboutsummaryrefslogtreecommitdiff
path: root/src/southbridge/intel/i82801cx
diff options
context:
space:
mode:
Diffstat (limited to 'src/southbridge/intel/i82801cx')
-rw-r--r--src/southbridge/intel/i82801cx/Kconfig2
-rw-r--r--src/southbridge/intel/i82801cx/Makefile.inc8
-rw-r--r--src/southbridge/intel/i82801cx/chip.h9
-rw-r--r--src/southbridge/intel/i82801cx/cmos_failover.c19
-rw-r--r--src/southbridge/intel/i82801cx/i82801cx.c53
-rw-r--r--src/southbridge/intel/i82801cx/i82801cx.h78
-rw-r--r--src/southbridge/intel/i82801cx/i82801cx_ac97.c41
-rw-r--r--src/southbridge/intel/i82801cx/i82801cx_early_smbus.c134
-rw-r--r--src/southbridge/intel/i82801cx/i82801cx_ide.c48
-rw-r--r--src/southbridge/intel/i82801cx/i82801cx_lpc.c251
-rw-r--r--src/southbridge/intel/i82801cx/i82801cx_nic.c21
-rw-r--r--src/southbridge/intel/i82801cx/i82801cx_pci.c30
-rw-r--r--src/southbridge/intel/i82801cx/i82801cx_reset.c8
-rw-r--r--src/southbridge/intel/i82801cx/i82801cx_smbus.c83
-rw-r--r--src/southbridge/intel/i82801cx/i82801cx_usb.c49
15 files changed, 834 insertions, 0 deletions
diff --git a/src/southbridge/intel/i82801cx/Kconfig b/src/southbridge/intel/i82801cx/Kconfig
new file mode 100644
index 0000000000..a0c775d31e
--- /dev/null
+++ b/src/southbridge/intel/i82801cx/Kconfig
@@ -0,0 +1,2 @@
+config SOUTHBRIDGE_INTEL_I82801CX
+ bool
diff --git a/src/southbridge/intel/i82801cx/Makefile.inc b/src/southbridge/intel/i82801cx/Makefile.inc
new file mode 100644
index 0000000000..163c0726cb
--- /dev/null
+++ b/src/southbridge/intel/i82801cx/Makefile.inc
@@ -0,0 +1,8 @@
+driver-y += i82801cx.o
+driver-y += i82801cx_usb.o
+driver-y += i82801cx_lpc.o
+driver-y += i82801cx_ide.o
+driver-y += i82801cx_ac97.o
+#driver-y += i82801cx_nic.o
+driver-y += i82801cx_pci.o
+obj-y += i82801cx_reset.o
diff --git a/src/southbridge/intel/i82801cx/chip.h b/src/southbridge/intel/i82801cx/chip.h
new file mode 100644
index 0000000000..99b069e82d
--- /dev/null
+++ b/src/southbridge/intel/i82801cx/chip.h
@@ -0,0 +1,9 @@
+#ifndef I82801CX_CHIP_H
+#define I82801CX_CHIP_H
+
+struct southbridge_intel_i82801cx_config
+{
+};
+extern struct chip_operations southbridge_intel_i82801cx_ops;
+
+#endif /* I82801CX_CHIP_H */
diff --git a/src/southbridge/intel/i82801cx/cmos_failover.c b/src/southbridge/intel/i82801cx/cmos_failover.c
new file mode 100644
index 0000000000..ab1816fbd8
--- /dev/null
+++ b/src/southbridge/intel/i82801cx/cmos_failover.c
@@ -0,0 +1,19 @@
+//kind of cmos_err for ich3
+
+#include "i82801cx.h"
+
+static void check_cmos_failed(void)
+{
+#if CONFIG_HAVE_OPTION_TABLE
+ uint8_t byte = pci_read_config8(PCI_DEV(0,0x1f,0),GEN_PMCON_3);
+
+ if( byte & RTC_BATTERY_DEAD) {
+ // Set boot_option and last_boot to 'Fallback',
+ // clear reboot_bits
+ byte = cmos_read(RTC_BOOT_BYTE);
+ byte &= 0x0c;
+ byte |= CONFIG_MAX_REBOOT_CNT << 4;
+ cmos_write(byte, RTC_BOOT_BYTE);
+ }
+#endif
+}
diff --git a/src/southbridge/intel/i82801cx/i82801cx.c b/src/southbridge/intel/i82801cx/i82801cx.c
new file mode 100644
index 0000000000..ddbbc7da37
--- /dev/null
+++ b/src/southbridge/intel/i82801cx/i82801cx.c
@@ -0,0 +1,53 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <assert.h>
+#include "i82801cx.h"
+
+void i82801cx_enable(device_t dev)
+{
+ unsigned int index = 0;
+ uint8_t bHasDisableBit = 0;
+ uint16_t cur_disable_mask, new_disable_mask;
+
+// all 82801ca devices are in bus 0
+ unsigned int devfn = PCI_DEVFN(0x1f, 0); // lpc
+ device_t lpc_dev = dev_find_slot(0, devfn); // 0
+ if (!lpc_dev)
+ return;
+
+ // Calculate disable bit position for specified device:function
+ // NOTE: For ICH-3, only the following devices can be disabled:
+ // D31:F1, D31:F3, D31:F5, D31:F6,
+ // D29:F0, D29:F1, D29:F2
+
+ if (PCI_SLOT(dev->path.pci.devfn) == 31) {
+ index = PCI_FUNC(dev->path.pci.devfn);
+
+ if ((index == 1) || (index == 3) || (index == 5) || (index == 6))
+ bHasDisableBit = 1;
+
+ } else if (PCI_SLOT(dev->path.pci.devfn) == 29) {
+ index = 8 + PCI_FUNC(dev->path.pci.devfn);
+
+ if (PCI_FUNC(dev->path.pci.devfn) < 3)
+ bHasDisableBit = 1;
+ }
+
+ if (bHasDisableBit) {
+ cur_disable_mask = pci_read_config16(lpc_dev, FUNC_DIS);
+ new_disable_mask = cur_disable_mask & ~(1<<index); // enable it
+ if (!dev->enabled) {
+ new_disable_mask |= (1<<index); // disable it
+ }
+ if (new_disable_mask != cur_disable_mask) {
+ pci_write_config16(lpc_dev, FUNC_DIS, new_disable_mask);
+ }
+ }
+}
+
+struct chip_operations southbridge_intel_i82801cx_ops = {
+ CHIP_NAME("Intel ICH3 (82801Cx) Series Southbridge")
+ .enable_dev = i82801cx_enable,
+};
diff --git a/src/southbridge/intel/i82801cx/i82801cx.h b/src/southbridge/intel/i82801cx/i82801cx.h
new file mode 100644
index 0000000000..b9b3511a4a
--- /dev/null
+++ b/src/southbridge/intel/i82801cx/i82801cx.h
@@ -0,0 +1,78 @@
+#ifndef I82801CX_H
+#define I82801CX_H
+
+#if !defined( __ROMCC__ ) && !defined(__PRE_RAM__)
+#include "chip.h"
+extern void i82801cx_enable(device_t dev);
+#endif
+
+
+#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 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
+
+// GEN_PMCON_3 bits
+#define RTC_BATTERY_DEAD (1<<2)
+#define RTC_POWER_FAILED (1<<1)
+#define SLEEP_AFTER_POWER_FAIL (1<<0)
+
+/********************************************************************/
+/* IDE Controller */
+/********************************************************************/
+
+// PCI Configuration Space (D31:F1)
+#define IDE_TIM_PRI 0x40 // IDE timings, primary
+#define IDE_TIM_SEC 0x42 // IDE timings, secondary
+
+
+// IDE_TIM bits
+#define IDE_DECODE_ENABLE (1<<15)
+
+/********************************************************************/
+/* SMBus */
+/********************************************************************/
+
+// PCI Configuration Space (D31:F3)
+#define SMB_BASE 0x20
+#define HOSTC 0x40
+
+// HOSTC bits
+#define I2C_EN (1<<2)
+#define SMB_SMI_EN (1<<1)
+#define HST_EN (1<<0)
+
+#define SMBUS_IO_BASE 0x1000
+
+// I/O registers (relative to SMBUS_IO_BASE)
+#define SMBHSTSTAT 0
+#define SMBHSTCTL 2
+#define SMBHSTCMD 3
+#define SMBXMITADD 4
+#define SMBHSTDAT0 5
+#define SMBHSTDAT1 6
+#define SMBBLKDAT 7
+#define SMBTRNSADD 9
+#define SMBSLVDATA 10
+#define SMLINK_PIN_CTL 14
+#define SMBUS_PIN_CTL 15
+
+/* 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 /* I82801CX_H */
diff --git a/src/southbridge/intel/i82801cx/i82801cx_ac97.c b/src/southbridge/intel/i82801cx/i82801cx_ac97.c
new file mode 100644
index 0000000000..5de44fc382
--- /dev/null
+++ b/src/southbridge/intel/i82801cx/i82801cx_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 "i82801cx.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 = i82801cx_enable,
+ .init = 0,
+ .scan_bus = 0,
+};
+
+static const struct pci_driver ac97audio_driver __pci_driver = {
+ .ops = &ac97audio_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801CA_AC97_AUDIO,
+};
+
+
+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 = i82801cx_enable,
+ .init = 0,
+ .scan_bus = 0,
+};
+
+static const struct pci_driver ac97modem_driver __pci_driver = {
+ .ops = &ac97modem_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801CA_AC97_MODEM,
+};
diff --git a/src/southbridge/intel/i82801cx/i82801cx_early_smbus.c b/src/southbridge/intel/i82801cx/i82801cx_early_smbus.c
new file mode 100644
index 0000000000..9c3480283c
--- /dev/null
+++ b/src/southbridge/intel/i82801cx/i82801cx_early_smbus.c
@@ -0,0 +1,134 @@
+#include <device/pci_ids.h>
+#include "i82801cx.h"
+
+static void enable_smbus(void)
+{
+ device_t dev = PCI_DEV(0x0, 0x1f, 0x3);
+
+ print_debug("SMBus controller enabled\r\n");
+ /* set smbus iobase */
+ pci_write_config32(dev, SMB_BASE, SMBUS_IO_BASE | PCI_BASE_ADDRESS_SPACE_IO);
+ /* Set smbus enable */
+ pci_write_config8(dev, HOSTC, HST_EN);
+ /* Set smbus iospace enable */
+ pci_write_config16(dev, PCI_COMMAND, PCI_COMMAND_IO);
+ /* 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);
+}
+
+// See http://www.coreboot.org/pipermail/linuxbios/2004-September/009077.html
+// for a description of this function.
+static int smbus_wait_until_active(void)
+{
+ unsigned long loops;
+ loops = SMBUS_TIMEOUT;
+ do {
+ unsigned char val;
+ smbus_delay();
+ val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
+ if ((val & 1)) {
+ break;
+ }
+ } while (--loops);
+ return loops ? 0 : -4;
+}
+
+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);
+ // !HOST_BUSY?
+ if ((val & 1) == 0) {
+ break;
+ }
+ if(loops == (SMBUS_TIMEOUT / 2)) {
+ // Clear status flags
+ 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);
+ // !HOST_BUSY?
+ if ( (val & 1) == 0) {
+ break;
+ }
+ // BYTE_DONE or SUCCESS or error?
+ 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 to read from the specified device */
+ 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 it to start */
+ if (smbus_wait_until_active() < 0) {
+ return -4;
+ }
+
+ /* 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);
+
+ // SUCCESS?
+ if (global_status_register != 2) {
+ return -1;
+ }
+ return byte;
+}
diff --git a/src/southbridge/intel/i82801cx/i82801cx_ide.c b/src/southbridge/intel/i82801cx/i82801cx_ide.c
new file mode 100644
index 0000000000..2506b2f329
--- /dev/null
+++ b/src/southbridge/intel/i82801cx/i82801cx_ide.c
@@ -0,0 +1,48 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "i82801cx.h"
+
+
+static void ide_init(struct device *dev)
+{
+ /* Enable ide devices so the linux ide driver will work */
+ uint16_t ideTimingConfig;
+ int enable_primary = 1;
+ int enable_secondary = 1;
+
+ ideTimingConfig = pci_read_config16(dev, IDE_TIM_PRI);
+ ideTimingConfig &= ~IDE_DECODE_ENABLE;
+ if (enable_primary) {
+ /* Enable first ide interface */
+ ideTimingConfig |= IDE_DECODE_ENABLE;
+ printk_debug("IDE0 ");
+ }
+ pci_write_config16(dev, IDE_TIM_PRI, ideTimingConfig);
+
+ ideTimingConfig = pci_read_config16(dev, IDE_TIM_SEC);
+ ideTimingConfig &= ~IDE_DECODE_ENABLE;
+ if (enable_secondary) {
+ /* Enable secondary ide interface */
+ ideTimingConfig |= IDE_DECODE_ENABLE;
+ printk_debug("IDE1 ");
+ }
+ pci_write_config16(dev, IDE_TIM_SEC, ideTimingConfig);
+}
+
+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 = i82801cx_enable,
+};
+
+static const struct pci_driver ide_driver __pci_driver = {
+ .ops = &ide_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801CA_IDE,
+};
diff --git a/src/southbridge/intel/i82801cx/i82801cx_lpc.c b/src/southbridge/intel/i82801cx/i82801cx_lpc.c
new file mode 100644
index 0000000000..4785242a79
--- /dev/null
+++ b/src/southbridge/intel/i82801cx/i82801cx_lpc.c
@@ -0,0 +1,251 @@
+/*
+ * (C) 2003 Linux Networx, SuSE Linux AG
+ * (C) 2004 Tyan Computer
+ * (c) 2005 Digital Design Corporation
+ */
+#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 <pc80/isa-dma.h>
+#include <arch/io.h>
+#include "i82801cx.h"
+
+#define NMI_OFF 0
+
+#ifndef CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL
+#define CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON
+#endif
+
+#define MAINBOARD_POWER_OFF 0
+#define MAINBOARD_POWER_ON 1
+
+
+void i82801cx_enable_ioapic( struct device *dev)
+{
+ uint32_t dword;
+ volatile uint32_t* ioapic_index = (volatile uint32_t*)0xfec00000;
+ volatile uint32_t* ioapic_data = (volatile uint32_t*)0xfec00010;
+
+ dword = pci_read_config32(dev, GEN_CNTL);
+ dword |= (3 << 7); /* enable ioapic & disable SMBus interrupts */
+ 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);
+
+ // Must program the APIC's ID before using it
+
+ *ioapic_index = 0; // Select APIC ID register
+ *ioapic_data = (2<<24);
+
+ // Hang if the ID didn't take (chip not present?)
+ *ioapic_index = 0;
+ dword = *ioapic_data;
+ printk_debug("Southbridge apic id = %x\n", (dword>>24) & 0xF);
+ if(dword != (2<<24))
+ die("");
+
+ *ioapic_index = 3; // Select Boot Configuration register
+ *ioapic_data = 1; // Use Processor System Bus to deliver interrupts
+}
+
+// This is how interrupts are received from the Super I/O chip
+void i82801cx_enable_serial_irqs( struct device *dev)
+{
+ // Recognize serial IRQs, continuous mode, frame size 21, 4 clock start frame pulse width
+ pci_write_config8(dev, SERIRQ_CNTL, (1 << 7)|(1 << 6)|((21 - 17) << 2)|(0<< 0));
+}
+
+//----------------------------------------------------------------------------------
+// Function: i82801cx_lpc_route_dma
+// Parameters: dev
+// mask - identifies whether each channel should be used for PCI DMA
+// (bit = 0) or LPC DMA (bit = 1). The LSb controls channel 0.
+// Channel 4 is not used (reserved).
+// Return Value: None
+// Description: Route all DMA channels to either PCI or LPC.
+//
+void i82801cx_lpc_route_dma( struct device *dev, uint8_t mask)
+{
+ uint16_t dmaConfig;
+ int channelIndex;
+
+ dmaConfig = pci_read_config16(dev, PCI_DMA_CFG);
+ dmaConfig &= 0x300; // Preserve reserved bits
+ for(channelIndex = 0; channelIndex < 8; channelIndex++) {
+ if (channelIndex == 4)
+ continue; // Register doesn't support channel 4
+ dmaConfig |= ((mask & (1 << channelIndex))? 3:1) << (channelIndex*2);
+ }
+ pci_write_config16(dev, PCI_DMA_CFG, dmaConfig);
+}
+
+void i82801cx_rtc_init(struct device *dev)
+{
+ uint32_t dword;
+ int rtc_failed;
+ int pwr_on = CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
+ uint8_t pmcon3 = pci_read_config8(dev, GEN_PMCON_3);
+
+ rtc_failed = pmcon3 & RTC_BATTERY_DEAD;
+ if (rtc_failed) {
+ // Clear the RTC_BATTERY_DEAD bit, but preserve
+ // the RTC_POWER_FAILED, G3 state, and reserved bits
+ // NOTE: RTC_BATTERY_DEAD and RTC_POWER_FAILED are "write-1-clear" bits
+ pmcon3 &= ~RTC_POWER_FAILED;
+ }
+
+ get_option(&pwr_on, "power_on_after_fail");
+ pmcon3 &= ~SLEEP_AFTER_POWER_FAIL;
+ if (!pwr_on) {
+ pmcon3 |= SLEEP_AFTER_POWER_FAIL;
+ }
+ pci_write_config8(dev, GEN_PMCON_3, pmcon3);
+ printk_info("set power %s after power fail\n",
+ pwr_on ? "on" : "off");
+
+ // See if the Safe Mode jumper is set
+ dword = pci_read_config32(dev, GEN_STS);
+ rtc_failed |= dword & (1 << 2);
+
+ rtc_init(rtc_failed);
+}
+
+
+void i82801cx_1f0_misc(struct device *dev)
+{
+ // Prevent LPC disabling, enable parity errors, and SERR# (System Error)
+ pci_write_config16(dev, PCI_COMMAND, 0x014f);
+
+ // Set ACPI base address to 0x1100 (I/O space)
+ pci_write_config32(dev, PMBASE, 0x00001101);
+
+ // Enable ACPI I/O and power management
+ pci_write_config8(dev, ACPI_CNTL, 0x10);
+
+ // Set GPIO base address to 0x1180 (I/O space)
+ pci_write_config32(dev, GPIO_BASE, 0x00001181);
+
+ // Enable GPIO
+ pci_write_config8(dev, GPIO_CNTL, 0x10);
+
+ // Route PIRQA to IRQ11, PIRQB to IRQ3, PIRQC to IRQ5, PIRQD to IRQ10
+ pci_write_config32(dev, PIRQA_ROUT, 0x0A05030B);
+
+ // Route PIRQE to IRQ7. Leave PIRQF - PIRQH unrouted.
+ pci_write_config8(dev, PIRQE_ROUT, 0x07);
+
+ // Enable access to the upper 128 byte bank of CMOS RAM
+ pci_write_config8(dev, RTC_CONF, 0x04);
+
+ // Decode 0x3F8-0x3FF (COM1) for COMA port,
+ // 0x2F8-0x2FF (COM2) for COMB
+ pci_write_config8(dev, COM_DEC, 0x10);
+
+ // LPT decode defaults to 0x378-0x37F and 0x778-0x77F
+ // Floppy decode defaults to 0x3F0-0x3F5, 0x3F7
+
+ // Enable COMA, COMB, LPT, floppy;
+ // disable microcontroller, Super I/O, sound, gameport
+ pci_write_config16(dev, LPC_EN, 0x000F);
+}
+
+static void lpc_init(struct device *dev)
+{
+ uint8_t byte;
+ int pwr_on=-1;
+ int nmi_option;
+
+ /* IO APIC initialization */
+ i82801cx_enable_ioapic(dev);
+
+ i82801cx_enable_serial_irqs(dev);
+
+ /* 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
+ */
+ byte = pci_read_config8(dev, GEN_PMCON_3);
+ if (pwr_on)
+ byte &= ~1; // Return to S0 (boot) after power is re-applied
+ else
+ byte |= 1; // Return to S5
+ pci_write_config8(dev, GEN_PMCON_3, byte);
+ printk_info("set power %s after power fail\n", pwr_on?"on":"off");
+
+ /* Set up NMI on errors */
+ byte = inb(0x61);
+ byte &= ~(1 << 3); /* IOCHK# NMI Enable */
+ byte &= ~(1 << 2); /* PCI SERR# Enable */
+ outb(byte, 0x61);
+ byte = inb(0x70);
+ nmi_option = NMI_OFF;
+ get_option(&nmi_option, "nmi");
+ if (nmi_option) {
+ byte &= ~(1 << 7); /* set NMI */
+ outb(byte, 0x70);
+ }
+
+ /* Initialize the real time clock */
+ i82801cx_rtc_init(dev);
+
+ i82801cx_lpc_route_dma(dev, 0xff);
+
+ /* Initialize isa dma */
+ isa_dma_init();
+
+ i82801cx_1f0_misc(dev);
+}
+
+static void i82801cx_lpc_read_resources(device_t dev)
+{
+ struct resource *res;
+
+ /* Get the normal PCI resources of this device. */
+ pci_dev_read_resources(dev);
+
+ /* Add an extra subtractive resource for both memory and I/O. */
+ res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
+ res->base = 0;
+ res->size = 0x1000;
+ res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
+ IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+
+ res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
+ res->base = 0xff800000;
+ res->size = 0x00800000; /* 8 MB for flash */
+ res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
+ IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+
+ res = new_resource(dev, 3); /* IOAPIC */
+ res->base = 0xfec00000;
+ res->size = 0x00001000;
+ res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+}
+
+static void i82801cx_lpc_enable_resources(device_t dev)
+{
+ pci_dev_enable_resources(dev);
+ enable_childrens_resources(dev);
+}
+
+static struct device_operations lpc_ops = {
+ .read_resources = i82801cx_lpc_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = i82801cx_lpc_enable_resources,
+ .init = lpc_init,
+ .scan_bus = scan_static_bus,
+ .enable = 0,
+};
+
+static const struct pci_driver lpc_driver __pci_driver = {
+ .ops = &lpc_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801CA_LPC,
+};
diff --git a/src/southbridge/intel/i82801cx/i82801cx_nic.c b/src/southbridge/intel/i82801cx/i82801cx_nic.c
new file mode 100644
index 0000000000..00ce038143
--- /dev/null
+++ b/src/southbridge/intel/i82801cx/i82801cx_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 "i82801cx.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 const struct pci_driver nic_driver __pci_driver = {
+ .ops = &nic_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801CA_LAN,
+};
diff --git a/src/southbridge/intel/i82801cx/i82801cx_pci.c b/src/southbridge/intel/i82801cx/i82801cx_pci.c
new file mode 100644
index 0000000000..842b214fc8
--- /dev/null
+++ b/src/southbridge/intel/i82801cx/i82801cx_pci.c
@@ -0,0 +1,30 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "i82801cx.h"
+
+static void pci_init(struct device *dev)
+{
+ // NOTE: the original (v1) 'CA code set these in the bridge register (0x3E-3F)
+ /* Enable pci error detecting */
+ uint32_t dword = pci_read_config32(dev, PCI_COMMAND);
+ dword |= (PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
+ pci_write_config32(dev, PCI_COMMAND, 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 const struct pci_driver pci_driver __pci_driver = {
+ .ops = &pci_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801CA_PCI,
+};
+
diff --git a/src/southbridge/intel/i82801cx/i82801cx_reset.c b/src/southbridge/intel/i82801cx/i82801cx_reset.c
new file mode 100644
index 0000000000..20e8530c54
--- /dev/null
+++ b/src/southbridge/intel/i82801cx/i82801cx_reset.c
@@ -0,0 +1,8 @@
+#include <arch/io.h>
+
+void i82801cx_hard_reset(void)
+{
+ /* Try rebooting through port 0xcf9 */
+ // Hard reset without power cycle
+ outb((0 <<3)|(1<<2)|(1<<1), 0xcf9);
+}
diff --git a/src/southbridge/intel/i82801cx/i82801cx_smbus.c b/src/southbridge/intel/i82801cx/i82801cx_smbus.c
new file mode 100644
index 0000000000..b69bbc1d9d
--- /dev/null
+++ b/src/southbridge/intel/i82801cx/i82801cx_smbus.c
@@ -0,0 +1,83 @@
+#include <smbus.h>
+#include <pci.h>
+#include <arch/io.h>
+#include "i82801cx.h"
+
+#define PM_BUS 0
+#define PM_DEVFN PCI_DEVFN(0x1f,3)
+
+void smbus_enable(void)
+{
+ /* iobase addr */
+ pcibios_write_config_dword(PM_BUS, PM_DEVFN, SMB_BASE,
+ SMBUS_IO_BASE | PCI_BASE_ADDRESS_SPACE_IO);
+ /* smbus enable */
+ pcibios_write_config_byte(PM_BUS, PM_DEVFN, HOSTC, HST_EN);
+ /* iospace enable */
+ pcibios_write_config_word(PM_BUS, PM_DEVFN, PCI_COMMAND, PCI_COMMAND_IO);
+
+ /* Disable interrupt generation */
+ outb(0, SMBUS_IO_BASE + SMBHSTCTL);
+}
+
+static void smbus_wait_until_ready(void)
+{
+ // Loop while HOST_BUSY
+ while((inb(SMBUS_IO_BASE + SMBHSTSTAT) & 1) == 1) {
+ /* nop */
+ }
+}
+
+static void smbus_wait_until_done(void)
+{
+ unsigned char byte;
+
+ // Loop while HOST_BUSY
+ do {
+ byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
+ }
+ while((byte &1) == 1);
+
+ // Wait for SUCCESS or error or BYTE_DONE
+ 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 to read from the specified device */
+ 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; // return true if !SUCCESS
+}
diff --git a/src/southbridge/intel/i82801cx/i82801cx_usb.c b/src/southbridge/intel/i82801cx/i82801cx_usb.c
new file mode 100644
index 0000000000..258581a78b
--- /dev/null
+++ b/src/southbridge/intel/i82801cx/i82801cx_usb.c
@@ -0,0 +1,49 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "i82801cx.h"
+
+static void usb_init(struct device *dev)
+{
+
+#if 0
+ uint32_t cmd;
+ 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 = i82801cx_enable,
+};
+
+static const struct pci_driver usb_driver_1 __pci_driver = {
+ .ops = &usb_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801CA_USB1,
+};
+static const struct pci_driver usb_driver_2 __pci_driver = {
+ .ops = &usb_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801CA_USB2,
+};
+static const struct pci_driver usb_driver_3 __pci_driver = {
+ .ops = &usb_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801CA_USB3,
+};
+