diff options
author | Steven J. Magnani <steve@digidescorp.com> | 2005-09-14 15:34:03 +0000 |
---|---|---|
committer | Steven J. Magnani <steve@digidescorp.com> | 2005-09-14 15:34:03 +0000 |
commit | 706aed8eb9c1836d1b6c53b081f789a1d3afaa25 (patch) | |
tree | 953355608f5491e7e046a30e0cba007e27522bf9 /src | |
parent | 09e4ef670245566f1ee50759976babac17aae55d (diff) | |
download | coreboot-706aed8eb9c1836d1b6c53b081f789a1d3afaa25.tar.xz |
Initial revision.
Based on i82801er and LB v1 code.
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@2036 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src')
-rw-r--r-- | src/southbridge/intel/i82801ca/Config.lb | 17 | ||||
-rw-r--r-- | src/southbridge/intel/i82801ca/chip.h | 9 | ||||
-rw-r--r-- | src/southbridge/intel/i82801ca/cmos_failover.c | 19 | ||||
-rw-r--r-- | src/southbridge/intel/i82801ca/i82801ca.c | 53 | ||||
-rw-r--r-- | src/southbridge/intel/i82801ca/i82801ca.h | 78 | ||||
-rw-r--r-- | src/southbridge/intel/i82801ca/i82801ca_ac97.c | 41 | ||||
-rw-r--r-- | src/southbridge/intel/i82801ca/i82801ca_early_smbus.c | 138 | ||||
-rw-r--r-- | src/southbridge/intel/i82801ca/i82801ca_ide.c | 48 | ||||
-rw-r--r-- | src/southbridge/intel/i82801ca/i82801ca_lpc.c | 240 | ||||
-rw-r--r-- | src/southbridge/intel/i82801ca/i82801ca_nic.c | 21 | ||||
-rw-r--r-- | src/southbridge/intel/i82801ca/i82801ca_pci.c | 30 | ||||
-rw-r--r-- | src/southbridge/intel/i82801ca/i82801ca_reset.c | 8 | ||||
-rw-r--r-- | src/southbridge/intel/i82801ca/i82801ca_smbus.c | 83 | ||||
-rw-r--r-- | src/southbridge/intel/i82801ca/i82801ca_usb.c | 49 |
14 files changed, 834 insertions, 0 deletions
diff --git a/src/southbridge/intel/i82801ca/Config.lb b/src/southbridge/intel/i82801ca/Config.lb new file mode 100644 index 0000000000..60ae38cb35 --- /dev/null +++ b/src/southbridge/intel/i82801ca/Config.lb @@ -0,0 +1,17 @@ +uses CONFIG_IDE + +config chip.h +driver i82801ca.o + +driver i82801ca_usb.o + +driver i82801ca_lpc.o + +if CONFIG_IDE + driver i82801ca_ide.o +end + +driver i82801ca_ac97.o +#driver i82801ca_nic.o +driver i82801ca_pci.o +object i82801ca_reset.o diff --git a/src/southbridge/intel/i82801ca/chip.h b/src/southbridge/intel/i82801ca/chip.h new file mode 100644 index 0000000000..f9583ca1fd --- /dev/null +++ b/src/southbridge/intel/i82801ca/chip.h @@ -0,0 +1,9 @@ +#ifndef I82801CA_CHIP_H +#define I82801CA_CHIP_H + +struct southbridge_intel_i82801ca_config +{ +}; +extern struct chip_operations southbridge_intel_i82801ca_ops; + +#endif /* I82801CA_CHIP_H */ diff --git a/src/southbridge/intel/i82801ca/cmos_failover.c b/src/southbridge/intel/i82801ca/cmos_failover.c new file mode 100644 index 0000000000..6197ef677a --- /dev/null +++ b/src/southbridge/intel/i82801ca/cmos_failover.c @@ -0,0 +1,19 @@ +//kind of cmos_err for ich3
+
+#include "i82801ca.h"
+ +static void check_cmos_failed(void) +{
+#if 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 |= MAX_REBOOT_CNT << 4; + cmos_write(byte, RTC_BOOT_BYTE); + }
+#endif +} diff --git a/src/southbridge/intel/i82801ca/i82801ca.c b/src/southbridge/intel/i82801ca/i82801ca.c new file mode 100644 index 0000000000..27432d95fb --- /dev/null +++ b/src/southbridge/intel/i82801ca/i82801ca.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 "i82801ca.h" + +void i82801ca_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.u.pci.devfn) == 31) { + index = PCI_FUNC(dev->path.u.pci.devfn);
+
+ if ((index == 1) || (index == 3) || (index == 5) || (index == 6))
+ bHasDisableBit = 1;
+ + } else if (PCI_SLOT(dev->path.u.pci.devfn) == 29) { + index = 8 + PCI_FUNC(dev->path.u.pci.devfn);
+
+ if (PCI_FUNC(dev->path.u.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_i82801ca_ops = { + CHIP_NAME("Intel 82801ca Southbridge") + .enable_dev = i82801ca_enable, +}; diff --git a/src/southbridge/intel/i82801ca/i82801ca.h b/src/southbridge/intel/i82801ca/i82801ca.h new file mode 100644 index 0000000000..a5117f23b6 --- /dev/null +++ b/src/southbridge/intel/i82801ca/i82801ca.h @@ -0,0 +1,78 @@ +#ifndef I82801CA_H +#define I82801CA_H +
+#ifndef __ROMCC__
+#include "chip.h" +extern void i82801ca_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 /* I82801CA_H */ diff --git a/src/southbridge/intel/i82801ca/i82801ca_ac97.c b/src/southbridge/intel/i82801ca/i82801ca_ac97.c new file mode 100644 index 0000000000..0bef1f4f68 --- /dev/null +++ b/src/southbridge/intel/i82801ca/i82801ca_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 "i82801ca.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 = i82801ca_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_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 = i82801ca_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_82801CA_AC97_MODEM, +}; diff --git a/src/southbridge/intel/i82801ca/i82801ca_early_smbus.c b/src/southbridge/intel/i82801ca/i82801ca_early_smbus.c new file mode 100644 index 0000000000..054af75089 --- /dev/null +++ b/src/southbridge/intel/i82801ca/i82801ca_early_smbus.c @@ -0,0 +1,138 @@ +#include <device/pci_ids.h> +#include "i82801ca.h"
+ +static void enable_smbus(void) +{ + device_t dev; + dev = pci_locate_device(PCI_ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_SMB), 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, 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://openbios.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/i82801ca/i82801ca_ide.c b/src/southbridge/intel/i82801ca/i82801ca_ide.c new file mode 100644 index 0000000000..50539fc5f7 --- /dev/null +++ b/src/southbridge/intel/i82801ca/i82801ca_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 "i82801ca.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 = i82801ca_enable, +}; + +static 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/i82801ca/i82801ca_lpc.c b/src/southbridge/intel/i82801ca/i82801ca_lpc.c new file mode 100644 index 0000000000..306d01a972 --- /dev/null +++ b/src/southbridge/intel/i82801ca/i82801ca_lpc.c @@ -0,0 +1,240 @@ +/* + * (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 "i82801ca.h" + +#define NMI_OFF 0 +
+#ifndef MAINBOARD_POWER_ON_AFTER_POWER_FAIL
+#define MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON
+#endif
+
+#define MAINBOARD_POWER_OFF 0
+#define MAINBOARD_POWER_ON 1
+
+ +void i82801ca_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 i82801ca_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: i82801ca_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 i82801ca_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 i82801ca_rtc_init(struct device *dev) +{ + uint32_t dword; + int rtc_failed;
+ int pwr_on = 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 i82801ca_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 0x1000 (I/O space) + pci_write_config32(dev, PMBASE, 0x00001001); + + // 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 */ + i82801ca_enable_ioapic(dev); + + i82801ca_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 */ + i82801ca_rtc_init(dev); + + i82801ca_lpc_route_dma(dev, 0xff); + + /* Initialize isa dma */ + isa_dma_init(); + + i82801ca_1f0_misc(dev); +} + +static void i82801ca_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->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; + + res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0)); + res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; +} + +static void i82801ca_lpc_enable_resources(device_t dev) +{ + pci_dev_enable_resources(dev); + enable_childrens_resources(dev); +} + +static struct device_operations lpc_ops = { + .read_resources = i82801ca_lpc_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = i82801ca_lpc_enable_resources, + .init = lpc_init, + .scan_bus = scan_static_bus, + .enable = 0, +}; + +static 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/i82801ca/i82801ca_nic.c b/src/southbridge/intel/i82801ca/i82801ca_nic.c new file mode 100644 index 0000000000..61d3977158 --- /dev/null +++ b/src/southbridge/intel/i82801ca/i82801ca_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 "i82801ca.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 = PCI_DEVICE_ID_INTEL_82801CA_LAN, +}; diff --git a/src/southbridge/intel/i82801ca/i82801ca_pci.c b/src/southbridge/intel/i82801ca/i82801ca_pci.c new file mode 100644 index 0000000000..d5355cb62a --- /dev/null +++ b/src/southbridge/intel/i82801ca/i82801ca_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 "i82801ca.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 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/i82801ca/i82801ca_reset.c b/src/southbridge/intel/i82801ca/i82801ca_reset.c new file mode 100644 index 0000000000..93ef6d9f23 --- /dev/null +++ b/src/southbridge/intel/i82801ca/i82801ca_reset.c @@ -0,0 +1,8 @@ +#include <arch/io.h> + +void i82801ca_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/i82801ca/i82801ca_smbus.c b/src/southbridge/intel/i82801ca/i82801ca_smbus.c new file mode 100644 index 0000000000..ab95e69e70 --- /dev/null +++ b/src/southbridge/intel/i82801ca/i82801ca_smbus.c @@ -0,0 +1,83 @@ +#include <smbus.h> +#include <pci.h> +#include <arch/io.h> +#include "i82801ca.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/i82801ca/i82801ca_usb.c b/src/southbridge/intel/i82801ca/i82801ca_usb.c new file mode 100644 index 0000000000..fd8d3fb45a --- /dev/null +++ b/src/southbridge/intel/i82801ca/i82801ca_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 "i82801ca.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 = i82801ca_enable, +}; + +static struct pci_driver usb_driver_1 __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801CA_USB, +}; +static struct pci_driver usb_driver_2 __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801CA_USB2, +}; +static struct pci_driver usb_driver_3 __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801CA_USB3, +}; + |