diff options
Diffstat (limited to 'src/southbridge/intel/i82801er')
-rw-r--r-- | src/southbridge/intel/i82801er/Config.lb | 12 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/chip.h | 36 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/cmos_failover.c | 16 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/i82801er.c | 48 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/i82801er.h | 15 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/i82801er_ac97.c | 37 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/i82801er_early_smbus.c | 140 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/i82801er_ehci.c | 50 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/i82801er_ide.c | 43 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/i82801er_lpc.c | 392 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/i82801er_pci.c | 45 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/i82801er_reset.c | 7 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/i82801er_sata.c | 63 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/i82801er_smbus.c | 45 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/i82801er_smbus.h | 105 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/i82801er_uhci.c | 56 | ||||
-rw-r--r-- | src/southbridge/intel/i82801er/i82801er_watchdog.c | 28 |
17 files changed, 1138 insertions, 0 deletions
diff --git a/src/southbridge/intel/i82801er/Config.lb b/src/southbridge/intel/i82801er/Config.lb new file mode 100644 index 0000000000..1953eaabdf --- /dev/null +++ b/src/southbridge/intel/i82801er/Config.lb @@ -0,0 +1,12 @@ +config chip.h +driver i82801er.o +driver i82801er_uhci.o +driver i82801er_lpc.o +driver i82801er_ide.o +driver i82801er_sata.o +driver i82801er_ehci.o +driver i82801er_smbus.o +driver i82801er_pci.o +driver i82801er_ac97.o +object i82801er_watchdog.o +object i82801er_reset.o diff --git a/src/southbridge/intel/i82801er/chip.h b/src/southbridge/intel/i82801er/chip.h new file mode 100644 index 0000000000..eb63889794 --- /dev/null +++ b/src/southbridge/intel/i82801er/chip.h @@ -0,0 +1,36 @@ +#ifndef I82801ER_CHIP_H +#define I82801ER_CHIP_H + +struct southbridge_intel_i82801er_config +{ + +#define ICH5R_GPIO_USE_MASK 0x03 +#define ICH5R_GPIO_USE_DEFAULT 0x00 +#define ICH5R_GPIO_USE_AS_NATIVE 0x01 +#define ICH5R_GPIO_USE_AS_GPIO 0x02 + +#define ICH5R_GPIO_SEL_MASK 0x0c +#define ICH5R_GPIO_SEL_DEFAULT 0x00 +#define ICH5R_GPIO_SEL_OUTPUT 0x04 +#define ICH5R_GPIO_SEL_INPUT 0x08 + +#define ICH5R_GPIO_LVL_MASK 0x30 +#define ICH5R_GPIO_LVL_DEFAULT 0x00 +#define ICH5R_GPIO_LVL_LOW 0x10 +#define ICH5R_GPIO_LVL_HIGH 0x20 +#define ICH5R_GPIO_LVL_BLINK 0x30 + +#define ICH5R_GPIO_INV_MASK 0xc0 +#define ICH5R_GPIO_INV_DEFAULT 0x00 +#define ICH5R_GPIO_INV_OFF 0x40 +#define ICH5R_GPIO_INV_ON 0x80 + + /* GPIO use select */ + unsigned char gpio[64]; + unsigned int pirq_a_d; + unsigned int pirq_e_h; +}; +extern struct chip_operations southbridge_intel_i82801er_ops; + +#endif /* I82801ER_CHIP_H */ + diff --git a/src/southbridge/intel/i82801er/cmos_failover.c b/src/southbridge/intel/i82801er/cmos_failover.c new file mode 100644 index 0000000000..9702313f9c --- /dev/null +++ b/src/southbridge/intel/i82801er/cmos_failover.c @@ -0,0 +1,16 @@ +//kind of cmos_err for ich5 +#define RTC_FAILED (1 <<2) +#define GEN_PMCON_3 0xa4 +static void check_cmos_failed(void) +{ + + uint8_t byte; + byte = pci_read_config8(PCI_DEV(0,0x1f,0),GEN_PMCON_3); + if( byte & RTC_FAILED){ +//clear bit 1 and bit 2 + byte = cmos_read(RTC_BOOT_BYTE); + byte &= 0x0c; + byte |= MAX_REBOOT_CNT << 4; + cmos_write(byte, RTC_BOOT_BYTE); + } +} diff --git a/src/southbridge/intel/i82801er/i82801er.c b/src/southbridge/intel/i82801er/i82801er.c new file mode 100644 index 0000000000..5e38ac3acb --- /dev/null +++ b/src/southbridge/intel/i82801er/i82801er.c @@ -0,0 +1,48 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include "i82801er.h" + +void i82801er_enable(device_t dev) +{ + device_t lpc_dev; + unsigned index = 0; + uint16_t reg_old, reg; + + /* See if we are behind the i82801er pci bridge */ + lpc_dev = dev_find_slot(dev->bus->secondary, PCI_DEVFN(0x1f, 0)); + if((dev->path.u.pci.devfn &0xf8)== 0xf8) { + index = dev->path.u.pci.devfn & 7; + } + else if((dev->path.u.pci.devfn &0xf8)== 0xe8) { + index = (dev->path.u.pci.devfn & 7) +8; + } + if ((!lpc_dev) || (index >= 16) || ((1<<index)&0x3091)) { + return; + } + if ((lpc_dev->vendor != PCI_VENDOR_ID_INTEL) || + (lpc_dev->device != PCI_DEVICE_ID_INTEL_82801ER_ISA)) { + uint32_t id; + id = pci_read_config32(lpc_dev, PCI_VENDOR_ID); + if (id != (PCI_VENDOR_ID_INTEL | + (PCI_DEVICE_ID_INTEL_82801ER_ISA << 16))) { + return; + } + } + + reg = reg_old = pci_read_config16(lpc_dev, 0xf2); + reg &= ~(1 << index); + if (!dev->enabled) { + reg |= (1 << index); + } + if (reg != reg_old) { + pci_write_config16(lpc_dev, 0xf2, reg); + } + +} + +struct chip_operations southbridge_intel_i82801er_ops = { + CHIP_NAME("Intel 82801ER Southbridge") + .enable_dev = i82801er_enable, +}; diff --git a/src/southbridge/intel/i82801er/i82801er.h b/src/southbridge/intel/i82801er/i82801er.h new file mode 100644 index 0000000000..bd7410162b --- /dev/null +++ b/src/southbridge/intel/i82801er/i82801er.h @@ -0,0 +1,15 @@ +#ifndef I82801ER_H +#define I82801ER_H + +#include "chip.h" + +extern void i82801er_enable(device_t dev); + +#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 + +#endif /* I82801ER_H */ diff --git a/src/southbridge/intel/i82801er/i82801er_ac97.c b/src/southbridge/intel/i82801er/i82801er_ac97.c new file mode 100644 index 0000000000..ffc062e718 --- /dev/null +++ b/src/southbridge/intel/i82801er/i82801er_ac97.c @@ -0,0 +1,37 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "i82801er.h" + +static void ac97_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + /* Write the subsystem vendor and device id */ + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} + +static struct pci_operations lops_pci = { + .set_subsystem = ac97_set_subsystem, +}; +static struct device_operations ac97_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = 0, + .scan_bus = 0, + .enable = i82801er_enable, + .ops_pci = &lops_pci, +}; + +static struct pci_driver ac97_audio_driver __pci_driver = { + .ops = &ac97_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801ER_AC97_AUDIO, +}; +static struct pci_driver ac97_modem_driver __pci_driver = { + .ops = &ac97_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801ER_AC97_MODEM, +}; diff --git a/src/southbridge/intel/i82801er/i82801er_early_smbus.c b/src/southbridge/intel/i82801er/i82801er_early_smbus.c new file mode 100644 index 0000000000..ef40e16b9f --- /dev/null +++ b/src/southbridge/intel/i82801er/i82801er_early_smbus.c @@ -0,0 +1,140 @@ +#include "i82801er_smbus.h" + +#define SMBUS_IO_BASE 0x0f00 + +static void enable_smbus(void) +{ + device_t dev; + dev = pci_locate_device(PCI_ID(0x8086, 0x24d3), 0); + if (dev == PCI_DEV_INVALID) { + die("SMBUS controller not found\r\n"); + } + print_spew("SMBus controller enabled\r\n"); + + pci_write_config32(dev, 0x20, SMBUS_IO_BASE | 1); + /* Set smbus enable */ + pci_write_config8(dev, 0x40, 1); + /* Set smbus iospace enable */ + pci_write_config8(dev, 0x4, 1); + /* SMBALERT_DIS */ + pci_write_config8(dev, 0x11, 4); + + /* 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); + +#if 0 // It's unlikely that half the southbridge suddenly vanishes? + dev = pci_locate_device(PCI_ID(0x8086, 0x24d0), 0); + if (dev == PCI_DEV_INVALID) { + die("ISA bridge not found\r\n"); + } +#endif +} + +static int smbus_read_byte(unsigned device, unsigned address) +{ + return do_smbus_read_byte(SMBUS_IO_BASE, device, address); +} + +static void smbus_write_byte(unsigned device, unsigned address, unsigned char val) +{ + if (smbus_wait_until_ready(SMBUS_IO_BASE) < 0) { + return; + } + + print_debug("Unimplemented smbus_write_byte() called.\r\n"); + +#if 0 + /* setup transaction */ + /* disable interrupts */ + outw(inw(SMBUS_IO_BASE + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), + SMBUS_IO_BASE + SMBGCTL); + /* set the device I'm talking too */ + outw(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBHSTADDR); + outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD); + /* set up for a byte data write */ /* FIXME */ + outw((inw(SMBUS_IO_BASE + SMBGCTL) & ~7) | (0x1), SMBUS_IO_BASE + SMBGCTL); + /* clear any lingering errors, so the transaction will run */ + /* Do I need to write the bits to a 1 to clear an error? */ + outw(inw(SMBUS_IO_BASE + SMBGSTATUS), SMBUS_IO_BASE + SMBGSTATUS); + + /* clear the data word...*/ + outw(val, SMBUS_IO_BASE + SMBHSTDAT); + + /* start the command */ + outw((inw(SMBUS_IO_BASE + SMBGCTL) | (1 << 3)), SMBUS_IO_BASE + SMBGCTL); + + /* poll for transaction completion */ + smbus_wait_until_done(SMBUS_IO_BASE); +#endif + return; +} + +static int smbus_write_block(unsigned device, unsigned length, unsigned cmd, + unsigned data1, unsigned data2) +{ + unsigned char global_control_register; + unsigned char global_status_register; + unsigned char byte; + unsigned char stat; + int i; + + /* chear the PM timeout flags, SECOND_TO_STS */ + outw(inw(0x0400 + 0x66), 0x0400 + 0x66); + + if (smbus_wait_until_ready(SMBUS_IO_BASE) < 0) { + return -2; + } + + /* setup transaction */ + /* Obtain ownership */ + outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); + for(stat=0;(stat&0x40)==0;) { + stat = inb(SMBUS_IO_BASE + SMBHSTSTAT); + } + /* clear the done bit */ + outb(0x80, SMBUS_IO_BASE + SMBHSTSTAT); + /* disable interrupts */ + outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL); + + /* set the device I'm talking too */ + outb(((device & 0x7f) << 1), SMBUS_IO_BASE + SMBXMITADD); + + /* set the command address */ + outb(cmd & 0xFF, SMBUS_IO_BASE + SMBHSTCMD); + + /* set the block length */ + outb(length & 0xFF, SMBUS_IO_BASE + SMBHSTDAT0); + + /* try sending out the first byte of data here */ + byte=(data1>>(0))&0x0ff; + outb(byte,SMBUS_IO_BASE + SMBBLKDAT); + /* issue a block write command */ + outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x5 << 2) | 0x40, + SMBUS_IO_BASE + SMBHSTCTL); + + for(i=0;i<length;i++) { + + /* poll for transaction completion */ + if (smbus_wait_until_blk_done(SMBUS_IO_BASE) < 0) { + return -3; + } + + /* load the next byte */ + if(i>3) + byte=(data2>>(i%4))&0x0ff; + else + byte=(data1>>(i))&0x0ff; + outb(byte,SMBUS_IO_BASE + SMBBLKDAT); + + /* clear the done bit */ + outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), + SMBUS_IO_BASE + SMBHSTSTAT); + } + + print_debug("SMBUS Block complete\r\n"); + return 0; +} + diff --git a/src/southbridge/intel/i82801er/i82801er_ehci.c b/src/southbridge/intel/i82801er/i82801er_ehci.c new file mode 100644 index 0000000000..c7a291233f --- /dev/null +++ b/src/southbridge/intel/i82801er/i82801er_ehci.c @@ -0,0 +1,50 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "i82801er.h" + +static void ehci_init(struct device *dev) +{ + uint32_t cmd; + + printk_debug("EHCI: Setting up controller.. "); + cmd = pci_read_config32(dev, PCI_COMMAND); + pci_write_config32(dev, PCI_COMMAND, + cmd | PCI_COMMAND_MASTER); + + printk_debug("done.\n"); +} + +static void ehci_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + uint8_t access_cntl; + access_cntl = pci_read_config8(dev, 0x80); + /* Enable writes to protected registers */ + pci_write_config8(dev, 0x80, access_cntl | 1); + /* Write the subsystem vendor and device id */ + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + /* Restore protection */ + pci_write_config8(dev, 0x80, access_cntl); +} + +static struct pci_operations lops_pci = { + .set_subsystem = &ehci_set_subsystem, +}; +static struct device_operations ehci_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = ehci_init, + .scan_bus = 0, + .enable = i82801er_enable, + .ops_pci = &lops_pci, +}; + +static struct pci_driver ehci_driver __pci_driver = { + .ops = &ehci_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801ER_EHCI, +}; diff --git a/src/southbridge/intel/i82801er/i82801er_ide.c b/src/southbridge/intel/i82801er/i82801er_ide.c new file mode 100644 index 0000000000..e42f775029 --- /dev/null +++ b/src/southbridge/intel/i82801er/i82801er_ide.c @@ -0,0 +1,43 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "i82801er.h" + +static void ide_init(struct device *dev) +{ + /* Enable IDE devices and timmings */ + pci_write_config16(dev, 0x40, 0x0a307); // IDE0 + pci_write_config16(dev, 0x42, 0x0a307); // IDE1 + pci_write_config8(dev, 0x48, 0x05); + pci_write_config16(dev, 0x4a, 0x0101); + pci_write_config16(dev, 0x54, 0x5055); + printk_debug("IDE Enabled\n"); +} + +static void i82801er_ide_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + /* This value is also visible in uchi[0-2] and smbus functions */ + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} + +static struct pci_operations lops_pci = { + .set_subsystem = i82801er_ide_set_subsystem, +}; +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, + .ops_pci = &lops_pci, +}; + +static struct pci_driver ide_driver __pci_driver = { + .ops = &ide_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801ER_IDE, +}; + diff --git a/src/southbridge/intel/i82801er/i82801er_lpc.c b/src/southbridge/intel/i82801er/i82801er_lpc.c new file mode 100644 index 0000000000..3f77b51409 --- /dev/null +++ b/src/southbridge/intel/i82801er/i82801er_lpc.c @@ -0,0 +1,392 @@ +/* + * (C) 2004 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 <pc80/mc146818rtc.h> +#include <pc80/isa-dma.h> +#include <arch/io.h> +#include "i82801er.h" + +#define ACPI_BAR 0x40 +#define GPIO_BAR 0x58 + +#define NMI_OFF 0 +#define MAINBOARD_POWER_OFF 0 +#define MAINBOARD_POWER_ON 1 + +#ifndef MAINBOARD_POWER_ON_AFTER_POWER_FAIL +#define MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON +#endif + +#define ALL (0xff << 24) +#define NONE (0) +#define DISABLED (1 << 16) +#define ENABLED (0 << 16) +#define TRIGGER_EDGE (0 << 15) +#define TRIGGER_LEVEL (1 << 15) +#define POLARITY_HIGH (0 << 13) +#define POLARITY_LOW (1 << 13) +#define PHYSICAL_DEST (0 << 11) +#define LOGICAL_DEST (1 << 11) +#define ExtINT (7 << 8) +#define NMI (4 << 8) +#define SMI (2 << 8) +#define INT (1 << 8) + +static void setup_ioapic(void) +{ + int i; + unsigned long value_low, value_high; + unsigned long ioapic_base = 0xfec00000; + volatile unsigned long *l; + unsigned interrupts; + + l = (unsigned long *) ioapic_base; + + l[0] = 0x01; + interrupts = (l[04] >> 16) & 0xff; + for (i = 0; i < interrupts; i++) { + l[0] = (i * 2) + 0x10; + l[4] = DISABLED; + value_low = l[4]; + l[0] = (i * 2) + 0x11; + l[4] = NONE; /* Should this be an address? */ + value_high = l[4]; + if (value_low == 0xffffffff) { + printk_warning("IO APIC not responding.\n"); + return; + } + } + + /* Put the ioapic in virtual wire mode */ + l[0] = 0 + 0x10; + l[4] = ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT; +} + +#define SERIRQ_CNTL 0x64 +static void i82801er_enable_serial_irqs(device_t dev) +{ + /* set packet length and toggle silent mode bit */ + pci_write_config8(dev, SERIRQ_CNTL, (1 << 7)|(1 << 6)|((21 - 17) << 2)|(0 << 0)); + pci_write_config8(dev, SERIRQ_CNTL, (1 << 7)|(0 << 6)|((21 - 17) << 2)|(0 << 0)); +} + +#define PCI_DMA_CFG 0x90 +static void i82801er_pci_dma_cfg(device_t dev) +{ + /* Set PCI DMA CFG to lpc I/F DMA */ + pci_write_config16(dev, PCI_DMA_CFG, 0xfcff); +} + +#define LPC_EN 0xe6 +static void i82801er_enable_lpc(device_t dev) +{ + /* lpc i/f enable */ + pci_write_config8(dev, LPC_EN, 0x0d); +} + +typedef struct southbridge_intel_i82801er_config config_t; + +static void set_i82801er_gpio_use_sel( + device_t dev, struct resource *res, config_t *config) +{ + uint32_t gpio_use_sel, gpio_use_sel2; + int i; + + gpio_use_sel = 0x1A003180; + gpio_use_sel2 = 0x00000007; + for(i = 0; i < 64; i++) { + int val; + switch(config->gpio[i] & ICH5R_GPIO_USE_MASK) { + case ICH5R_GPIO_USE_AS_NATIVE: val = 0; break; + case ICH5R_GPIO_USE_AS_GPIO: val = 1; break; + default: + continue; + } + /* The caller is responsible for not playing with unimplemented bits */ + if (i < 32) { + gpio_use_sel &= ~( 1 << i); + gpio_use_sel |= (val << i); + } else { + gpio_use_sel2 &= ~( 1 << (i - 32)); + gpio_use_sel2 |= (val << (i - 32)); + } + } + outl(gpio_use_sel, res->base + 0x00); + outl(gpio_use_sel2, res->base + 0x30); +} + +static void set_i82801er_gpio_direction( + device_t dev, struct resource *res, config_t *config) +{ + uint32_t gpio_io_sel, gpio_io_sel2; + int i; + + gpio_io_sel = 0x0000ffff; + gpio_io_sel2 = 0x00000300; + for(i = 0; i < 64; i++) { + int val; + switch(config->gpio[i] & ICH5R_GPIO_SEL_MASK) { + case ICH5R_GPIO_SEL_OUTPUT: val = 0; break; + case ICH5R_GPIO_SEL_INPUT: val = 1; break; + default: + continue; + } + /* The caller is responsible for not playing with unimplemented bits */ + if (i < 32) { + gpio_io_sel &= ~( 1 << i); + gpio_io_sel |= (val << i); + } else { + gpio_io_sel2 &= ~( 1 << (i - 32)); + gpio_io_sel2 |= (val << (i - 32)); + } + } + outl(gpio_io_sel, res->base + 0x04); + outl(gpio_io_sel2, res->base + 0x34); +} + +static void set_i82801er_gpio_level( + device_t dev, struct resource *res, config_t *config) +{ + uint32_t gpio_lvl, gpio_lvl2; + uint32_t gpio_blink; + int i; + + gpio_lvl = 0x1b3f0000; + gpio_blink = 0x00040000; + gpio_lvl2 = 0x00030207; + for(i = 0; i < 64; i++) { + int val, blink; + switch(config->gpio[i] & ICH5R_GPIO_LVL_MASK) { + case ICH5R_GPIO_LVL_LOW: val = 0; blink = 0; break; + case ICH5R_GPIO_LVL_HIGH: val = 1; blink = 0; break; + case ICH5R_GPIO_LVL_BLINK: val = 1; blink = 1; break; + default: + continue; + } + /* The caller is responsible for not playing with unimplemented bits */ + if (i < 32) { + gpio_lvl &= ~( 1 << i); + gpio_blink &= ~( 1 << i); + gpio_lvl |= ( val << i); + gpio_blink |= (blink << i); + } else { + gpio_lvl2 &= ~( 1 << (i - 32)); + gpio_lvl2 |= (val << (i - 32)); + } + } + outl(gpio_lvl, res->base + 0x0c); + outl(gpio_blink, res->base + 0x18); + outl(gpio_lvl2, res->base + 0x38); +} + +static void set_i82801er_gpio_inv( + device_t dev, struct resource *res, config_t *config) +{ + uint32_t gpio_inv; + int i; + + gpio_inv = 0x00000000; + for(i = 0; i < 32; i++) { + int val; + switch(config->gpio[i] & ICH5R_GPIO_INV_MASK) { + case ICH5R_GPIO_INV_OFF: val = 0; break; + case ICH5R_GPIO_INV_ON: val = 1; break; + default: + continue; + } + gpio_inv &= ~( 1 << i); + gpio_inv |= (val << i); + } + outl(gpio_inv, res->base + 0x2c); +} + +static void i82801er_pirq_init(device_t dev) +{ + config_t *config; + + /* Get the chip configuration */ + config = dev->chip_info; + + if(config->pirq_a_d) { + pci_write_config32(dev, 0x60, config->pirq_a_d); + } + if(config->pirq_e_h) { + pci_write_config32(dev, 0x68, config->pirq_e_h); + } +} + + +static void i82801er_gpio_init(device_t dev) +{ + struct resource *res; + config_t *config; + + /* Skip if I don't have any configuration */ + if (!dev->chip_info) { + return; + } + /* The programmer is responsible for ensuring + * a valid gpio configuration. + */ + + /* Get the chip configuration */ + config = dev->chip_info; + /* Find the GPIO bar */ + res = find_resource(dev, GPIO_BAR); + if (!res) { + return; + } + + /* Set the use selects */ + set_i82801er_gpio_use_sel(dev, res, config); + + /* Set the IO direction */ + set_i82801er_gpio_direction(dev, res, config); + + /* Setup the input inverters */ + set_i82801er_gpio_inv(dev, res, config); + + /* Set the value on the GPIO output pins */ + set_i82801er_gpio_level(dev, res, config); + +} + +static void enable_hpet(struct device *dev) +{ +const unsigned long hpet_address = 0xfed0000; + + uint32_t dword; + uint32_t code = (0 & 0x3); + + dword = pci_read_config32(dev, GEN_CNTL); + dword |= (1 << 17); /* enable hpet */ + + /* Bits [16:15] Memory Address Range + * 00 FED0_0000h - FED0_03FFh + * 01 FED0_1000h - FED0_13FFh + * 10 FED0_2000h - FED0_23FFh + * 11 FED0_3000h - FED0_33FFh + */ + + dword &= ~(3 << 15); /* clear it */ + dword |= (code<<15); + + printk_debug("enabling HPET @0x%x\n", hpet_address | (code <<12) ); +} + +static void lpc_init(struct device *dev) +{ + uint8_t byte; + uint32_t value; + int pwr_on=MAINBOARD_POWER_ON_AFTER_POWER_FAIL; + + /* IO APIC initialization */ + value = pci_read_config32(dev, 0xd0); + value |= (1 << 8)|(1<<7)|(1<<1); + pci_write_config32(dev, 0xd0, value); + value = pci_read_config32(dev, 0xd4); + value |= (1<<1); + pci_write_config32(dev, 0xd4, value); + setup_ioapic(); + + i82801er_enable_serial_irqs(dev); + + i82801er_pci_dma_cfg(dev); + + i82801er_enable_lpc(dev); + + /* Clear SATA to non raid */ + pci_write_config8(dev, 0xae, 0x00); + + get_option(&pwr_on, "power_on_after_fail"); + byte = pci_read_config8(dev, 0xa4); + byte &= 0xfe; + if (!pwr_on) { + byte |= 1; + } + pci_write_config8(dev, 0xa4, byte); + printk_info("set power %s after power fail\n", pwr_on?"on":"off"); + + /* Set up the PIRQ */ + i82801er_pirq_init(dev); + + /* Set the state of the gpio lines */ + i82801er_gpio_init(dev); + + /* Initialize the real time clock */ + rtc_init(0); + + /* Initialize isa dma */ + isa_dma_init(); + + /* Disable IDE (needed when sata is enabled) */ + pci_write_config8(dev, 0xf2, 0x60); + + enable_hpet(dev); +} + +static void i82801er_lpc_read_resources(device_t dev) +{ + struct resource *res; + + /* Get the normal pci resources of this device */ + pci_dev_read_resources(dev); + + /* Add the ACPI BAR */ + res = pci_get_resource(dev, ACPI_BAR); + + /* Add the GPIO BAR */ + res = pci_get_resource(dev, GPIO_BAR); + + /* 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_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; +} + +static void i82801er_lpc_enable_resources(device_t dev) +{ + uint8_t acpi_cntl, gpio_cntl; + + /* Enable the normal pci resources */ + pci_dev_enable_resources(dev); + + /* Enable the ACPI bar */ + acpi_cntl = pci_read_config8(dev, 0x44); + acpi_cntl |= (1 << 4); + pci_write_config8(dev, 0x44, acpi_cntl); + + /* Enable the GPIO bar */ + gpio_cntl = pci_read_config8(dev, 0x5c); + gpio_cntl |= (1 << 4); + pci_write_config8(dev, 0x5c, gpio_cntl); + + enable_childrens_resources(dev); +} + +static struct pci_operations lops_pci = { + .set_subsystem = 0, +}; + +static struct device_operations lpc_ops = { + .read_resources = i82801er_lpc_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = i82801er_lpc_enable_resources, + .init = lpc_init, + .scan_bus = scan_static_bus, + .enable = i82801er_enable, + .ops_pci = &lops_pci, +}; + +static struct pci_driver lpc_driver __pci_driver = { + .ops = &lpc_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801ER_ISA, +}; diff --git a/src/southbridge/intel/i82801er/i82801er_pci.c b/src/southbridge/intel/i82801er/i82801er_pci.c new file mode 100644 index 0000000000..c0b6aa9ad3 --- /dev/null +++ b/src/southbridge/intel/i82801er/i82801er_pci.c @@ -0,0 +1,45 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "i82801er.h" + +static void pci_init(struct device *dev) +{ + uint32_t dword; + uint16_t word; + + /* Clear system errors */ + word = pci_read_config16(dev, 0x06); + word |= 0xf900; /* Clear possible errors */ + pci_write_config16(dev, 0x06, word); + +#if 0 + /* System error enable */ + dword = pci_read_config32(dev, 0x04); + dword |= (1<<8); /* SERR# Enable */ + dword |= (1<<6); /* Parity Error Response */ + pci_write_config32(dev, 0x04, dword); +#endif + + word = pci_read_config16(dev, 0x1e); + word |= 0xf800; /* Clear possible errors */ + pci_write_config16(dev, 0x1e, word); +} + +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, + .ops_pci = 0, +}; + +static struct pci_driver pci_driver __pci_driver = { + .ops = &pci_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801ER_PCI, +}; + diff --git a/src/southbridge/intel/i82801er/i82801er_reset.c b/src/southbridge/intel/i82801er/i82801er_reset.c new file mode 100644 index 0000000000..fa41756557 --- /dev/null +++ b/src/southbridge/intel/i82801er/i82801er_reset.c @@ -0,0 +1,7 @@ +#include <arch/io.h> + +void i82801er_hard_reset(void) +{ + /* Try rebooting through port 0xcf9 */ + outb((0 <<3)|(1<<2)|(1<<1), 0xcf9); +} diff --git a/src/southbridge/intel/i82801er/i82801er_sata.c b/src/southbridge/intel/i82801er/i82801er_sata.c new file mode 100644 index 0000000000..d9eba3c5a1 --- /dev/null +++ b/src/southbridge/intel/i82801er/i82801er_sata.c @@ -0,0 +1,63 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "i82801er.h" + +static void sata_init(struct device *dev) +{ + + uint16_t word; + + printk_debug("SATA init\n"); + /* SATA configuration */ + pci_write_config8(dev, 0x04, 0x07); + pci_write_config8(dev, 0x09, 0x8f); + + /* Set timmings */ + pci_write_config16(dev, 0x40, 0x0a307); + pci_write_config16(dev, 0x42, 0x0a307); + + /* Sync DMA */ + pci_write_config16(dev, 0x48, 0x000f); + pci_write_config16(dev, 0x4a, 0x1111); + + /* 66 mhz */ + pci_write_config16(dev, 0x54, 0xf00f); + + /* Combine ide - sata configuration */ + pci_write_config8(dev, 0x90, 0x0); + + /* port 0 & 1 enable */ + pci_write_config8(dev, 0x92, 0x33); + + /* initialize SATA */ + pci_write_config16(dev, 0xa0, 0x0018); + pci_write_config32(dev, 0xa4, 0x00000264); + pci_write_config16(dev, 0xa0, 0x0040); + pci_write_config32(dev, 0xa4, 0x00220043); + +} + +static struct device_operations sata_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = sata_init, + .scan_bus = 0, + .ops_pci = 0, +}; + +static struct pci_driver sata_driver __pci_driver = { + .ops = &sata_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801ER_1F2_R, +}; + +static struct pci_driver sata_driver_nr __pci_driver = { + .ops = &sata_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801ER_1F2, +}; + diff --git a/src/southbridge/intel/i82801er/i82801er_smbus.c b/src/southbridge/intel/i82801er/i82801er_smbus.c new file mode 100644 index 0000000000..67bdd8722c --- /dev/null +++ b/src/southbridge/intel/i82801er/i82801er_smbus.c @@ -0,0 +1,45 @@ +#include <device/device.h> +#include <device/path.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <device/smbus.h> +#include <arch/io.h> +#include "i82801er.h" +#include "i82801er_smbus.h" + +static int lsmbus_read_byte(struct bus *bus, device_t dev, uint8_t address) +{ + unsigned device; + struct resource *res; + + device = dev->path.u.i2c.device; + res = find_resource(bus->dev, 0x20); + + return do_smbus_read_byte(res->base, device, address); +} + +static struct smbus_bus_operations lops_smbus_bus = { + .read_byte = lsmbus_read_byte, +}; +static struct pci_operations lops_pci = { + /* The subsystem id follows the ide controller */ + .set_subsystem = 0, +}; +static struct device_operations smbus_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = 0, + .scan_bus = scan_static_bus, + .enable = i82801er_enable, + .ops_pci = &lops_pci, + .ops_smbus_bus = &lops_smbus_bus, +}; + +static struct pci_driver smbus_driver __pci_driver = { + .ops = &smbus_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801ER_SMB, +}; + diff --git a/src/southbridge/intel/i82801er/i82801er_smbus.h b/src/southbridge/intel/i82801er/i82801er_smbus.h new file mode 100644 index 0000000000..861230e130 --- /dev/null +++ b/src/southbridge/intel/i82801er/i82801er_smbus.h @@ -0,0 +1,105 @@ +#include <device/smbus_def.h> + +#define SMBHSTSTAT 0x0 +#define SMBHSTCTL 0x2 +#define SMBHSTCMD 0x3 +#define SMBXMITADD 0x4 +#define SMBHSTDAT0 0x5 +#define SMBHSTDAT1 0x6 +#define SMBBLKDAT 0x7 +#define SMBTRNSADD 0x9 +#define SMBSLVDATA 0xa +#define SMLINK_PIN_CTL 0xe +#define SMBUS_PIN_CTL 0xf + +#define SMBUS_TIMEOUT (100*1000*10) + + +static void smbus_delay(void) +{ + outb(0x80, 0x80); +} + +static int smbus_wait_until_ready(unsigned smbus_io_base) +{ + unsigned loops = SMBUS_TIMEOUT; + unsigned char byte; + do { + smbus_delay(); + if (--loops == 0) + break; + byte = inb(smbus_io_base + SMBHSTSTAT); + } while(byte & 1); + return loops?0:-1; +} + +static int smbus_wait_until_done(unsigned smbus_io_base) +{ + unsigned loops = SMBUS_TIMEOUT; + unsigned char byte; + do { + smbus_delay(); + if (--loops == 0) + break; + byte = inb(smbus_io_base + SMBHSTSTAT); + } while((byte & 1) || (byte & ~((1<<6)|(1<<0))) == 0); + return loops?0:-1; +} + +static int smbus_wait_until_blk_done(unsigned smbus_io_base) +{ + unsigned loops = SMBUS_TIMEOUT; + unsigned char byte; + do { + smbus_delay(); + if (--loops == 0) + break; + byte = inb(smbus_io_base + SMBHSTSTAT); + } while((byte&(1<<7)) == 0); + return loops?0:-1; +} + +static int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address) +{ + unsigned char global_status_register; + unsigned char byte; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + } + /* setup transaction */ + /* disable interrupts */ + outb(inb(smbus_io_base + SMBHSTCTL) & (~1), smbus_io_base + SMBHSTCTL); + /* set the device I'm talking too */ + outb(((device & 0x7f) << 1) | 1, smbus_io_base + 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 the command */ + outb((inb(smbus_io_base + SMBHSTCTL) | 0x40), smbus_io_base + SMBHSTCTL); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; + } + + global_status_register = inb(smbus_io_base + SMBHSTSTAT); + + /* Ignore the In Use Status... */ + global_status_register &= ~(3 << 5); + + /* read results of transaction */ + byte = inb(smbus_io_base + SMBHSTDAT0); + if (global_status_register != (1 << 1)) { + return SMBUS_ERROR; + } + return byte; +} + diff --git a/src/southbridge/intel/i82801er/i82801er_uhci.c b/src/southbridge/intel/i82801er/i82801er_uhci.c new file mode 100644 index 0000000000..733acb7410 --- /dev/null +++ b/src/southbridge/intel/i82801er/i82801er_uhci.c @@ -0,0 +1,56 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "i82801er.h" + +static void uhci_init(struct device *dev) +{ + uint32_t cmd; + +#if 1 + printk_debug("UHCI: Setting up controller.. "); + cmd = pci_read_config32(dev, PCI_COMMAND); + pci_write_config32(dev, PCI_COMMAND, + cmd | PCI_COMMAND_MASTER); + + + printk_debug("done.\n"); +#endif + +} + +static struct pci_operations lops_pci = { + /* The subsystem id follows the ide controller */ + .set_subsystem = 0, +}; + +static struct device_operations uhci_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = uhci_init, + .scan_bus = 0, + .enable = i82801er_enable, + .ops_pci = &lops_pci, +}; + +static struct pci_driver uhci_driver __pci_driver = { + .ops = &uhci_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801ER_USB, +}; + +static struct pci_driver usb2_driver __pci_driver = { + .ops = &uhci_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801ER_USB2, +}; + +static struct pci_driver usb3_driver __pci_driver = { + .ops = &uhci_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801ER_USB3, +}; + diff --git a/src/southbridge/intel/i82801er/i82801er_watchdog.c b/src/southbridge/intel/i82801er/i82801er_watchdog.c new file mode 100644 index 0000000000..c9c09f5896 --- /dev/null +++ b/src/southbridge/intel/i82801er/i82801er_watchdog.c @@ -0,0 +1,28 @@ +#include <console/console.h> +#include <arch/io.h> +#include <device/device.h> +#include <device/pci.h> + +void watchdog_off(void) +{ + device_t dev; + unsigned long value,base; + + /* turn off the ICH5 watchdog */ + dev = dev_find_slot(0, PCI_DEVFN(0x1f,0)); + /* Enable I/O space */ + value = pci_read_config16(dev, 0x04); + value |= (1 << 10); + pci_write_config16(dev, 0x04, value); + /* Get TCO base */ + base = (pci_read_config32(dev, 0x40) & 0x0fffe) + 0x60; + /* Disable the watchdog timer */ + value = inw(base + 0x08); + value |= 1 << 11; + outw(value, base + 0x08); + /* Clear TCO timeout status */ + outw(0x0008, base + 0x04); + outw(0x0002, base + 0x06); + printk_debug("Watchdog ICH5 disabled\r\n"); +} + |