diff options
Diffstat (limited to 'src/southbridge/intel/i82801cx')
-rw-r--r-- | src/southbridge/intel/i82801cx/Kconfig | 2 | ||||
-rw-r--r-- | src/southbridge/intel/i82801cx/Makefile.inc | 8 | ||||
-rw-r--r-- | src/southbridge/intel/i82801cx/chip.h | 9 | ||||
-rw-r--r-- | src/southbridge/intel/i82801cx/cmos_failover.c | 19 | ||||
-rw-r--r-- | src/southbridge/intel/i82801cx/i82801cx.c | 53 | ||||
-rw-r--r-- | src/southbridge/intel/i82801cx/i82801cx.h | 78 | ||||
-rw-r--r-- | src/southbridge/intel/i82801cx/i82801cx_ac97.c | 41 | ||||
-rw-r--r-- | src/southbridge/intel/i82801cx/i82801cx_early_smbus.c | 134 | ||||
-rw-r--r-- | src/southbridge/intel/i82801cx/i82801cx_ide.c | 48 | ||||
-rw-r--r-- | src/southbridge/intel/i82801cx/i82801cx_lpc.c | 251 | ||||
-rw-r--r-- | src/southbridge/intel/i82801cx/i82801cx_nic.c | 21 | ||||
-rw-r--r-- | src/southbridge/intel/i82801cx/i82801cx_pci.c | 30 | ||||
-rw-r--r-- | src/southbridge/intel/i82801cx/i82801cx_reset.c | 8 | ||||
-rw-r--r-- | src/southbridge/intel/i82801cx/i82801cx_smbus.c | 83 | ||||
-rw-r--r-- | src/southbridge/intel/i82801cx/i82801cx_usb.c | 49 |
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, +}; + |