From 706aed8eb9c1836d1b6c53b081f789a1d3afaa25 Mon Sep 17 00:00:00 2001 From: "Steven J. Magnani" Date: Wed, 14 Sep 2005 15:34:03 +0000 Subject: Initial revision. Based on i82801er and LB v1 code. git-svn-id: svn://svn.coreboot.org/coreboot/trunk@2036 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1 --- src/southbridge/intel/i82801ca/Config.lb | 17 ++ src/southbridge/intel/i82801ca/chip.h | 9 + src/southbridge/intel/i82801ca/cmos_failover.c | 19 ++ src/southbridge/intel/i82801ca/i82801ca.c | 53 +++++ src/southbridge/intel/i82801ca/i82801ca.h | 78 +++++++ src/southbridge/intel/i82801ca/i82801ca_ac97.c | 41 ++++ .../intel/i82801ca/i82801ca_early_smbus.c | 138 ++++++++++++ src/southbridge/intel/i82801ca/i82801ca_ide.c | 48 +++++ src/southbridge/intel/i82801ca/i82801ca_lpc.c | 240 +++++++++++++++++++++ src/southbridge/intel/i82801ca/i82801ca_nic.c | 21 ++ src/southbridge/intel/i82801ca/i82801ca_pci.c | 30 +++ src/southbridge/intel/i82801ca/i82801ca_reset.c | 8 + src/southbridge/intel/i82801ca/i82801ca_smbus.c | 83 +++++++ src/southbridge/intel/i82801ca/i82801ca_usb.c | 49 +++++ 14 files changed, 834 insertions(+) create mode 100644 src/southbridge/intel/i82801ca/Config.lb create mode 100644 src/southbridge/intel/i82801ca/chip.h create mode 100644 src/southbridge/intel/i82801ca/cmos_failover.c create mode 100644 src/southbridge/intel/i82801ca/i82801ca.c create mode 100644 src/southbridge/intel/i82801ca/i82801ca.h create mode 100644 src/southbridge/intel/i82801ca/i82801ca_ac97.c create mode 100644 src/southbridge/intel/i82801ca/i82801ca_early_smbus.c create mode 100644 src/southbridge/intel/i82801ca/i82801ca_ide.c create mode 100644 src/southbridge/intel/i82801ca/i82801ca_lpc.c create mode 100644 src/southbridge/intel/i82801ca/i82801ca_nic.c create mode 100644 src/southbridge/intel/i82801ca/i82801ca_pci.c create mode 100644 src/southbridge/intel/i82801ca/i82801ca_reset.c create mode 100644 src/southbridge/intel/i82801ca/i82801ca_smbus.c create mode 100644 src/southbridge/intel/i82801ca/i82801ca_usb.c 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 +#include +#include +#include +#include +#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<enabled) { + new_disable_mask |= (1< +#include +#include +#include +#include +#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 +#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 +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#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 + +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 +#include +#include +#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 +#include +#include +#include +#include +#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, +}; + -- cgit v1.2.3