diff options
author | Yinghai Lu <yinghailu@gmail.com> | 2005-07-08 02:49:49 +0000 |
---|---|---|
committer | Yinghai Lu <yinghailu@gmail.com> | 2005-07-08 02:49:49 +0000 |
commit | 13f1c2af8be2cd7f7e99a678f5d428a65b771811 (patch) | |
tree | 27cad5581f1fa150f573149d48e82f70ba1b1d9f /src/southbridge/intel | |
parent | 14cde9e96a777f9d75016a13b23fab0480515f58 (diff) | |
download | coreboot-13f1c2af8be2cd7f7e99a678f5d428a65b771811.tar.xz |
eric patch
1. x86_setup_mtrr take address bit.
2. generic ht, pcix, pcie beidge...
3. scan bus and reset_bus
4. ht read ctrl to decide if the ht chain
is ready
5. Intel e7520 and e7525 support
6. new ich5r support
7. intel sb 6300 support.
yhlu patch
1. split x86_setup_mtrrs to fixed and var
2. if (resource->flags & IORESOURCE_FIXED ) return; in device.c pick_largest_resource
3. in_conherent.c K8_SCAN_PCI_BUS
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1982 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/southbridge/intel')
37 files changed, 2570 insertions, 1 deletions
diff --git a/src/southbridge/intel/esb6300/Config.lb b/src/southbridge/intel/esb6300/Config.lb new file mode 100644 index 0000000000..9674c1f818 --- /dev/null +++ b/src/southbridge/intel/esb6300/Config.lb @@ -0,0 +1,12 @@ +config chip.h +driver esb6300.o +driver esb6300_uhci.o +driver esb6300_lpc.o +driver esb6300_ide.o +driver esb6300_sata.o +driver esb6300_ehci.o +driver esb6300_smbus.o +driver esb6300_pci.o +driver esb6300_pic.o +driver esb6300_bridge1c.o +driver esb6300_ac97.o diff --git a/src/southbridge/intel/esb6300/chip.h b/src/southbridge/intel/esb6300/chip.h new file mode 100644 index 0000000000..ff74e615fd --- /dev/null +++ b/src/southbridge/intel/esb6300/chip.h @@ -0,0 +1,30 @@ +struct southbridge_intel_esb6300_config +{ +#define ESB6300_GPIO_USE_MASK 0x03 +#define ESB6300_GPIO_USE_DEFAULT 0x00 +#define ESB6300_GPIO_USE_AS_NATIVE 0x01 +#define ESB6300_GPIO_USE_AS_GPIO 0x02 + +#define ESB6300_GPIO_SEL_MASK 0x0c +#define ESB6300_GPIO_SEL_DEFAULT 0x00 +#define ESB6300_GPIO_SEL_OUTPUT 0x04 +#define ESB6300_GPIO_SEL_INPUT 0x08 + +#define ESB6300_GPIO_LVL_MASK 0x30 +#define ESB6300_GPIO_LVL_DEFAULT 0x00 +#define ESB6300_GPIO_LVL_LOW 0x10 +#define ESB6300_GPIO_LVL_HIGH 0x20 +#define ESB6300_GPIO_LVL_BLINK 0x30 + +#define ESB6300_GPIO_INV_MASK 0xc0 +#define ESB6300_GPIO_INV_DEFAULT 0x00 +#define ESB6300_GPIO_INV_OFF 0x40 +#define ESB6300_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_esb6300_ops; + diff --git a/src/southbridge/intel/esb6300/esb6300.c b/src/southbridge/intel/esb6300/esb6300.c new file mode 100644 index 0000000000..3551a59ea6 --- /dev/null +++ b/src/southbridge/intel/esb6300/esb6300.c @@ -0,0 +1,48 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include "esb6300.h" + +void esb6300_enable(device_t dev) +{ + device_t lpc_dev; + unsigned index = 0; + uint16_t reg_old, reg; + + /* See if we are on the behind the 6300 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_6300ESB_ISA)) { + uint32_t id; + id = pci_read_config32(lpc_dev, PCI_VENDOR_ID); + if (id != (PCI_VENDOR_ID_INTEL | + (PCI_DEVICE_ID_INTEL_6300ESB_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_esb6300_ops = { + CHIP_NAME("INTEL 6300ESB") + .enable_dev = esb6300_enable, +}; diff --git a/src/southbridge/intel/esb6300/esb6300.h b/src/southbridge/intel/esb6300/esb6300.h new file mode 100644 index 0000000000..2c91fcba98 --- /dev/null +++ b/src/southbridge/intel/esb6300/esb6300.h @@ -0,0 +1,7 @@ +#ifndef ESB6300_H +#define ESB6300_H +#include "chip.h" + +void esb6300_enable(device_t dev); + +#endif /* ESB6300 */ diff --git a/src/southbridge/intel/esb6300/esb6300_ac97.c b/src/southbridge/intel/esb6300/esb6300_ac97.c new file mode 100644 index 0000000000..cc221f6e64 --- /dev/null +++ b/src/southbridge/intel/esb6300/esb6300_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 "esb6300.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 = esb6300_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_6300ESB_AC97_AUDIO, +}; +static struct pci_driver ac97_modem_driver __pci_driver = { + .ops = &ac97_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_6300ESB_AC97_MODEM, +}; diff --git a/src/southbridge/intel/esb6300/esb6300_bridge1c.c b/src/southbridge/intel/esb6300/esb6300_bridge1c.c new file mode 100644 index 0000000000..49e3b056a0 --- /dev/null +++ b/src/southbridge/intel/esb6300/esb6300_bridge1c.c @@ -0,0 +1,51 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "esb6300.h" + +static void bridge1c_init(struct device *dev) +{ + + uint16_t word; + + /* configuration */ + pci_write_config8(dev, 0x1b, 0x30); +// pci_write_config8(dev, 0x3e, 0x07); + pci_write_config8(dev, 0x3e, 0x04); /* parity ignore */ + pci_write_config8(dev, 0x6c, 0x0c); /* undocumented */ + pci_write_config8(dev, 0xe0, 0x20); + + /* SRB enable */ + pci_write_config16(dev, 0xe4, 0x0232); + + /* Burst size */ + pci_write_config8(dev, 0xf0, 0x02); + + /* prefetch threshold size */ + pci_write_config16(dev, 0xf8, 0x2121); + + /* primary latency */ + pci_write_config8(dev, 0x0d, 0x28); + + /* multi transaction timer */ + pci_write_config8(dev, 0x42, 0x08); + +} + +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 = bridge1c_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_6300ESB_BRIDGE1C, +}; + diff --git a/src/southbridge/intel/esb6300/esb6300_early_smbus.c b/src/southbridge/intel/esb6300/esb6300_early_smbus.c new file mode 100644 index 0000000000..e115e3a2fa --- /dev/null +++ b/src/southbridge/intel/esb6300/esb6300_early_smbus.c @@ -0,0 +1,107 @@ +#include "esb6300_smbus.h" + +#define SMBUS_IO_BASE 0x0f00 + +static void enable_smbus(void) +{ + device_t dev; + dev = pci_locate_device(PCI_ID(0x8086, 0x25a4), 0); + if (dev == PCI_DEV_INVALID) { + die("SMBUS controller not found\r\n"); + } + uint8_t enable; + print_spew("SMBus controller enabled\r\n"); + pci_write_config32(dev, 0x20, SMBUS_IO_BASE | 1); + pci_write_config8(dev, 0x40, 1); + pci_write_config8(dev, 0x4, 1); + /* SMBALERT_DIS */ + pci_write_config8(dev, 0x11, 4); + + /* Disable interrupt generation */ + outb(0, SMBUS_IO_BASE + SMBHSTCTL); + + dev = pci_locate_device(PCI_ID(0x8086, 0x25a1), 0); + if (dev == PCI_DEV_INVALID) { + die("ISA bridge not found\r\n"); + } +} + +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; + } + 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/esb6300/esb6300_ehci.c b/src/southbridge/intel/esb6300/esb6300_ehci.c new file mode 100644 index 0000000000..58dcd9593c --- /dev/null +++ b/src/southbridge/intel/esb6300/esb6300_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 "esb6300.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 = esb6300_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_6300ESB_EHCI, +}; diff --git a/src/southbridge/intel/esb6300/esb6300_ide.c b/src/southbridge/intel/esb6300/esb6300_ide.c new file mode 100644 index 0000000000..bb77ad7726 --- /dev/null +++ b/src/southbridge/intel/esb6300/esb6300_ide.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 "esb6300.h" + +static void ide_init(struct device *dev) +{ + + /* Enable ide devices so the linux ide driver will work */ + uint16_t word; + + /* Enable IDE devices */ + pci_write_config16(dev, 0x40, 0x0a307); + pci_write_config16(dev, 0x42, 0x0a307); + pci_write_config8(dev, 0x48, 0x05); + pci_write_config16(dev, 0x4a, 0x0101); + pci_write_config16(dev, 0x54, 0x5055); + +#if 0 + word = pci_read_config16(dev, 0x40); + word |= (1 << 15); + pci_write_config16(dev, 0x40, word); + word = pci_read_config16(dev, 0x42); + word |= (1 << 15); + pci_write_config16(dev, 0x42, word); +#endif + printk_debug("IDE Enabled\n"); +} + +static void esb6300_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 = esb6300_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_6300ESB_IDE, +}; + diff --git a/src/southbridge/intel/esb6300/esb6300_lpc.c b/src/southbridge/intel/esb6300/esb6300_lpc.c new file mode 100644 index 0000000000..caef888d2a --- /dev/null +++ b/src/southbridge/intel/esb6300/esb6300_lpc.c @@ -0,0 +1,410 @@ +/* + * (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 "esb6300.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_FAIL +#define MAINBOARD_POWER_ON_AFTER_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(device_t dev) +{ + 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("%d IO APIC not responding.\n", + dev_path(dev)); + 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 esb6300_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 esb6300_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 esb6300_enable_lpc(device_t dev) +{ + /* lpc i/f enable */ + pci_write_config8(dev, LPC_EN, 0x0d); +} + +typedef struct southbridge_intel_esb6300_config config_t; + +static void set_esb6300_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 = 0x1B003100; +// gpio_use_sel2 = 0x03000000; + gpio_use_sel = 0x1BBC31C0; + gpio_use_sel2 = 0x03000FE1; +#if 0 + for(i = 0; i < 64; i++) { + int val; + switch(config->gpio[i] & ESB6300_GPIO_USE_MASK) { + case ESB6300_GPIO_USE_AS_NATIVE: val = 0; break; + case ESB6300_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)); + } + } +#endif + outl(gpio_use_sel, res->base + 0x00); + outl(gpio_use_sel2, res->base + 0x30); +} + +static void set_esb6300_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 = 0x00000000; + gpio_io_sel = 0x1900ffff; + gpio_io_sel2 = 0x00000fe1; +#if 0 + for(i = 0; i < 64; i++) { + int val; + switch(config->gpio[i] & ESB6300_GPIO_SEL_MASK) { + case ESB6300_GPIO_SEL_OUTPUT: val = 0; break; + case ESB6300_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)); + } + } +#endif + outl(gpio_io_sel, res->base + 0x04); + outl(gpio_io_sel2, res->base + 0x34); +} + +static void set_esb6300_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 = 0x00000fff; + gpio_lvl = 0x19370000; + gpio_blink = 0x00000000; + gpio_lvl2 = 0x00000fff; +#if 0 + for(i = 0; i < 64; i++) { + int val, blink; + switch(config->gpio[i] & ESB6300_GPIO_LVL_MASK) { + case ESB6300_GPIO_LVL_LOW: val = 0; blink = 0; break; + case ESB6300_GPIO_LVL_HIGH: val = 1; blink = 0; break; + case ESB6300_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)); + } + } +#endif + outl(gpio_lvl, res->base + 0x0c); + outl(gpio_blink, res->base + 0x18); + outl(gpio_lvl2, res->base + 0x38); +} + +static void set_esb6300_gpio_inv( + device_t dev, struct resource *res, config_t *config) +{ + uint32_t gpio_inv; + int i; + + gpio_inv = 0x00003100; +#if 0 + for(i = 0; i < 32; i++) { + int val; + switch(config->gpio[i] & ESB6300_GPIO_INV_MASK) { + case ESB6300_GPIO_INV_OFF: val = 0; break; + case ESB6300_GPIO_INV_ON: val = 1; break; + default: + continue; + } + gpio_inv &= ~( 1 << i); + gpio_inv |= (val << i); + } +#endif + outl(gpio_inv, res->base + 0x2c); +} + +static void esb6300_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 esb6300_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_esb6300_gpio_use_sel(dev, res, config); + + /* Set the IO direction */ + set_esb6300_gpio_direction(dev, res, config); + + /* Setup the input inverters */ + set_esb6300_gpio_inv(dev, res, config); + + /* Set the value on the GPIO output pins */ + set_esb6300_gpio_level(dev, res, config); + +} + + +static void lpc_init(struct device *dev) +{ + uint8_t byte; + uint32_t value; + int pwr_on=MAINBOARD_POWER_ON_AFTER_FAIL; + + /* sata settings */ + pci_write_config32(dev, 0x58, 0x00001181); + + /* IO APIC initialization */ + value = pci_read_config32(dev, 0xd0); + value |= (1 << 8)|(1<<7); + value |= (6 << 0)|(1<<13)|(1<<11); + pci_write_config32(dev, 0xd0, value); + setup_ioapic(dev); + + /* disable reset timer */ + pci_write_config8(dev, 0xd4, 0x02); + + /* cmos ram 2nd 128 */ + pci_write_config8(dev, 0xd8, 0x04); + + /* comm 2 */ + pci_write_config8(dev, 0xe0, 0x10); + + /* fwh sellect */ + pci_write_config32(dev, 0xe8, 0x00112233); + + /* fwh decode */ + pci_write_config8(dev, 0xf0, 0x0f); + + /* av disable, sata controller */ + pci_write_config8(dev, 0xf2, 0xc0); + + /* undocumented */ + pci_write_config8(dev, 0xa0, 0x20); + pci_write_config8(dev, 0xad, 0x03); + pci_write_config8(dev, 0xbb, 0x09); + + /* apic1 rout */ + pci_write_config8(dev, 0xf4, 0x40); + + /* undocumented */ + pci_write_config8(dev, 0xa0, 0x20); + pci_write_config8(dev, 0xad, 0x03); + pci_write_config8(dev, 0xbb, 0x09); + + esb6300_enable_serial_irqs(dev); + + esb6300_pci_dma_cfg(dev); + + esb6300_enable_lpc(dev); + + 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 */ + esb6300_pirq_init(dev); + + /* Set the state of the gpio lines */ + esb6300_gpio_init(dev); + + /* Initialize the real time clock */ + rtc_init(0); + + /* Initialize isa dma */ + isa_dma_init(); +} + +static void esb6300_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 esb6300_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 = esb6300_lpc_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = esb6300_lpc_enable_resources, + .init = lpc_init, + .scan_bus = scan_static_bus, + .enable = esb6300_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_6300ESB_ISA, +}; diff --git a/src/southbridge/intel/esb6300/esb6300_pci.c b/src/southbridge/intel/esb6300/esb6300_pci.c new file mode 100644 index 0000000000..1131941728 --- /dev/null +++ b/src/southbridge/intel/esb6300/esb6300_pci.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 "esb6300.h" + +static void pci_init(struct device *dev) +{ + + uint16_t word; + + /* Clear system errors */ + word = pci_read_config16(dev, 0x06); + word |= 0xf900; /* Clear possible errors */ + pci_write_config16(dev, 0x06, word); + + 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_6300ESB_PCI, +}; + diff --git a/src/southbridge/intel/esb6300/esb6300_pic.c b/src/southbridge/intel/esb6300/esb6300_pic.c new file mode 100644 index 0000000000..024c7e2980 --- /dev/null +++ b/src/southbridge/intel/esb6300/esb6300_pic.c @@ -0,0 +1,109 @@ +/* + * (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 "esb6300.h" + +#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(device_t dev) +{ + int i; + unsigned long value_low, value_high; + unsigned long ioapic_base = 0xfec10000; + 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("%s IO APIC not responding.\n", + dev_path(dev)); + return; + } + } +} + +static void pic_init(struct device *dev) +{ + + uint16_t word; + + /* Clear system errors */ + word = pci_read_config16(dev, 0x06); + word |= 0xf900; /* Clear possible errors */ + pci_write_config16(dev, 0x06, word); + + /* enable interrupt lines */ + pci_write_config8(dev, 0x3c, 0xff); + + /* Setup the ioapic */ + setup_ioapic(dev); +} + +static void pic_read_resources(device_t dev) +{ + struct resource *res; + + /* Get the normal pci resources of this device */ + pci_dev_read_resources(dev); + + /* Report the pic1 mbar resource */ + res = new_resource(dev, 0x44); + res->base = 0xfec10000; + res->size = 256; + res->limit = res->base + res->size -1; + res->align = 8; + res->gran = 8; + res->flags = IORESOURCE_MEM | IORESOURCE_FIXED | + IORESOURCE_STORED | IORESOURCE_ASSIGNED; + dev->command |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; +} + +static struct pci_operations lops_pci = { + /* Can we set the pci subsystem and device id? */ + .set_subsystem = 0, +}; + +static struct device_operations pci_ops = { + .read_resources = pic_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = pic_init, + .scan_bus = 0, + .enable = esb6300_enable, + .ops_pci = &lops_pci, +}; + +static struct pci_driver pci_driver __pci_driver = { + .ops = &pci_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_6300ESB_PIC1, +}; + diff --git a/src/southbridge/intel/esb6300/esb6300_sata.c b/src/southbridge/intel/esb6300/esb6300_sata.c new file mode 100644 index 0000000000..9d8fb759fc --- /dev/null +++ b/src/southbridge/intel/esb6300/esb6300_sata.c @@ -0,0 +1,77 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "esb6300.h" + +static void sata_init(struct device *dev) +{ + + /* Enable sata devices so the linux sata driver will work */ + uint16_t word; + + /* Enable SATA devices */ + + 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); + + printk_debug("SATA Enabled\n"); +} + +static void esb6300_sata_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + /* This value is also visible in usb1, usb2 and smbus functions */ + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} + +static struct pci_operations lops_pci = { + .set_subsystem = esb6300_sata_set_subsystem, +}; +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 = &lops_pci, +}; + +static struct pci_driver sata_driver __pci_driver = { + .ops = &sata_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_6300ESB_SATA, +}; + +static struct pci_driver sata_driver_nr __pci_driver = { + .ops = &sata_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_6300ESB_SATA_R, +}; + diff --git a/src/southbridge/intel/esb6300/esb6300_smbus.c b/src/southbridge/intel/esb6300/esb6300_smbus.c new file mode 100644 index 0000000000..6cb6f2d9bb --- /dev/null +++ b/src/southbridge/intel/esb6300/esb6300_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 "esb6300.h" +#include "esb6300_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 = esb6300_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_6300ESB_SMB, +}; + diff --git a/src/southbridge/intel/esb6300/esb6300_smbus.h b/src/southbridge/intel/esb6300/esb6300_smbus.h new file mode 100644 index 0000000000..861230e130 --- /dev/null +++ b/src/southbridge/intel/esb6300/esb6300_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/esb6300/esb6300_uhci.c b/src/southbridge/intel/esb6300/esb6300_uhci.c new file mode 100644 index 0000000000..835a39c2e4 --- /dev/null +++ b/src/southbridge/intel/esb6300/esb6300_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 "esb6300.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 = esb6300_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_6300ESB_USB, +}; + +static struct pci_driver usb2_driver __pci_driver = { + .ops = &uhci_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_6300ESB_USB2, +}; + +static struct pci_driver usb3_driver __pci_driver = { + .ops = &uhci_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_6300ESB_USB3, +}; + diff --git a/src/southbridge/intel/i82801er/i82801er_reset.c b/src/southbridge/intel/i82801er/i82801er_reset.c index 3d7a4b79b6..fa41756557 100644 --- a/src/southbridge/intel/i82801er/i82801er_reset.c +++ b/src/southbridge/intel/i82801er/i82801er_reset.c @@ -1,6 +1,6 @@ #include <arch/io.h> -void hard_reset(void) +void i82801er_hard_reset(void) { /* Try rebooting through port 0xcf9 */ outb((0 <<3)|(1<<2)|(1<<1), 0xcf9); diff --git a/src/southbridge/intel/i82870/p64h2_pcibridge.c b/src/southbridge/intel/i82870/p64h2_pcibridge.c index 6f161e900b..01f871766d 100644 --- a/src/southbridge/intel/i82870/p64h2_pcibridge.c +++ b/src/southbridge/intel/i82870/p64h2_pcibridge.c @@ -29,6 +29,7 @@ static struct device_operations pcix_ops = { .enable_resources = pci_bus_enable_resources, .init = p64h2_pcix_init, .scan_bus = pci_scan_bridge, + .reset_bus = pci_bus_reset, }; static struct pci_driver pcix_driver __pci_driver = { diff --git a/src/southbridge/intel/ich5r/Config.lb b/src/southbridge/intel/ich5r/Config.lb new file mode 100644 index 0000000000..0bad3f0bf5 --- /dev/null +++ b/src/southbridge/intel/ich5r/Config.lb @@ -0,0 +1,11 @@ +config chip.h +driver ich5r.o +driver ich5r_uhci.o +driver ich5r_lpc.o +driver ich5r_ide.o +driver ich5r_sata.o +driver ich5r_ehci.o +driver ich5r_smbus.o +driver ich5r_pci.o +driver ich5r_ac97.o +object ich5r_watchdog.o diff --git a/src/southbridge/intel/ich5r/chip.h b/src/southbridge/intel/ich5r/chip.h new file mode 100644 index 0000000000..b3abeabca7 --- /dev/null +++ b/src/southbridge/intel/ich5r/chip.h @@ -0,0 +1,30 @@ +struct southbridge_intel_ich5r_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_ich5r_ops; diff --git a/src/southbridge/intel/ich5r/ich5r.c b/src/southbridge/intel/ich5r/ich5r.c new file mode 100644 index 0000000000..1b65465234 --- /dev/null +++ b/src/southbridge/intel/ich5r/ich5r.c @@ -0,0 +1,48 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include "ich5r.h" + +void ich5r_enable(device_t dev) +{ + device_t lpc_dev; + unsigned index = 0; + uint16_t reg_old, reg; + + /* See if we are on the behind the ich5r 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_ich5r_ops = { + CHIP_NAME("INTEL 82801ER") + .enable_dev = ich5r_enable, +}; diff --git a/src/southbridge/intel/ich5r/ich5r.h b/src/southbridge/intel/ich5r/ich5r.h new file mode 100644 index 0000000000..28572c9c27 --- /dev/null +++ b/src/southbridge/intel/ich5r/ich5r.h @@ -0,0 +1,7 @@ +#ifndef ICH5R_H +#define ICH5R_H + +#include "chip.h" +void ich5r_enable(device_t dev); + +#endif /* ICH5R_H */ diff --git a/src/southbridge/intel/ich5r/ich5r_ac97.c b/src/southbridge/intel/ich5r/ich5r_ac97.c new file mode 100644 index 0000000000..17d924b196 --- /dev/null +++ b/src/southbridge/intel/ich5r/ich5r_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 "ich5r.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 = ich5r_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/ich5r/ich5r_early_smbus.c b/src/southbridge/intel/ich5r/ich5r_early_smbus.c new file mode 100644 index 0000000000..6880fde126 --- /dev/null +++ b/src/southbridge/intel/ich5r/ich5r_early_smbus.c @@ -0,0 +1,130 @@ +#include "ich5r_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"); + } + uint8_t enable; + print_spew("SMBus controller enabled\r\n"); + pci_write_config32(dev, 0x20, SMBUS_IO_BASE | 1); + pci_write_config8(dev, 0x40, 1); + pci_write_config8(dev, 0x4, 1); + /* SMBALERT_DIS */ + pci_write_config8(dev, 0x11, 4); + + /* Disable interrupt generation */ + outb(0, SMBUS_IO_BASE + SMBHSTCTL); + + dev = pci_locate_device(PCI_ID(0x8086, 0x24d0), 0); + if (dev == PCI_DEV_INVALID) { + die("ISA bridge not found\r\n"); + } +} + +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; + } +#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/ich5r/ich5r_ehci.c b/src/southbridge/intel/ich5r/ich5r_ehci.c new file mode 100644 index 0000000000..d1650c1385 --- /dev/null +++ b/src/southbridge/intel/ich5r/ich5r_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 "ich5r.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 = ich5r_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/ich5r/ich5r_ide.c b/src/southbridge/intel/ich5r/ich5r_ide.c new file mode 100644 index 0000000000..7bfd92555c --- /dev/null +++ b/src/southbridge/intel/ich5r/ich5r_ide.c @@ -0,0 +1,44 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "ich5r.h" + +static void ide_init(struct device *dev) +{ + + /* Enable IDE devices and timmings */ + pci_write_config16(dev, 0x40, 0x0a307); + pci_write_config16(dev, 0x42, 0x0a307); + 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 ich5r_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 = ich5r_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/ich5r/ich5r_lpc.c b/src/southbridge/intel/ich5r/ich5r_lpc.c new file mode 100644 index 0000000000..d9d98891ad --- /dev/null +++ b/src/southbridge/intel/ich5r/ich5r_lpc.c @@ -0,0 +1,369 @@ +/* + * (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 "ich5r.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 ich5r_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 ich5r_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 ich5r_enable_lpc(device_t dev) +{ + /* lpc i/f enable */ + pci_write_config8(dev, LPC_EN, 0x0d); +} + +typedef struct southbridge_intel_ich5r_config config_t; + +static void set_ich5r_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_ich5r_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_ich5r_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_ich5r_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 ich5r_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 ich5r_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_ich5r_gpio_use_sel(dev, res, config); + + /* Set the IO direction */ + set_ich5r_gpio_direction(dev, res, config); + + /* Setup the input inverters */ + set_ich5r_gpio_inv(dev, res, config); + + /* Set the value on the GPIO output pins */ + set_ich5r_gpio_level(dev, res, config); + +} + + +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(); + + ich5r_enable_serial_irqs(dev); + + ich5r_pci_dma_cfg(dev); + + ich5r_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 */ + ich5r_pirq_init(dev); + + /* Set the state of the gpio lines */ + ich5r_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); + +} + +static void ich5r_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 ich5r_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 = ich5r_lpc_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = ich5r_lpc_enable_resources, + .init = lpc_init, + .scan_bus = scan_static_bus, + .enable = ich5r_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/ich5r/ich5r_pci.c b/src/southbridge/intel/ich5r/ich5r_pci.c new file mode 100644 index 0000000000..d2c94c778e --- /dev/null +++ b/src/southbridge/intel/ich5r/ich5r_pci.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 "ich5r.h" + +static void pci_init(struct device *dev) +{ + + uint16_t word; + + /* Clear system errors */ + word = pci_read_config16(dev, 0x06); + word |= 0xf900; /* Clear possible errors */ + pci_write_config16(dev, 0x06, word); + + 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/ich5r/ich5r_sata.c b/src/southbridge/intel/ich5r/ich5r_sata.c new file mode 100644 index 0000000000..803d8789cf --- /dev/null +++ b/src/southbridge/intel/ich5r/ich5r_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 "ich5r.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/ich5r/ich5r_smbus.c b/src/southbridge/intel/ich5r/ich5r_smbus.c new file mode 100644 index 0000000000..3337a65b15 --- /dev/null +++ b/src/southbridge/intel/ich5r/ich5r_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 "ich5r.h" +#include "ich5r_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 = ich5r_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/ich5r/ich5r_smbus.h b/src/southbridge/intel/ich5r/ich5r_smbus.h new file mode 100644 index 0000000000..861230e130 --- /dev/null +++ b/src/southbridge/intel/ich5r/ich5r_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/ich5r/ich5r_uhci.c b/src/southbridge/intel/ich5r/ich5r_uhci.c new file mode 100644 index 0000000000..ad4ae978cf --- /dev/null +++ b/src/southbridge/intel/ich5r/ich5r_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 "ich5r.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 = ich5r_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/ich5r/ich5r_watchdog.c b/src/southbridge/intel/ich5r/ich5r_watchdog.c new file mode 100644 index 0000000000..c9c09f5896 --- /dev/null +++ b/src/southbridge/intel/ich5r/ich5r_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"); +} + diff --git a/src/southbridge/intel/pxhd/Config.lb b/src/southbridge/intel/pxhd/Config.lb new file mode 100644 index 0000000000..349b8dd624 --- /dev/null +++ b/src/southbridge/intel/pxhd/Config.lb @@ -0,0 +1,2 @@ +config chip.h +driver pxhd_bridge.o diff --git a/src/southbridge/intel/pxhd/chip.h b/src/southbridge/intel/pxhd/chip.h new file mode 100644 index 0000000000..516f1df7d2 --- /dev/null +++ b/src/southbridge/intel/pxhd/chip.h @@ -0,0 +1,5 @@ +struct southbridge_intel_pxhd_config +{ + /* nothing */ +}; +struct chip_operations southbridge_intel_pxhd_ops; diff --git a/src/southbridge/intel/pxhd/pxhd.h b/src/southbridge/intel/pxhd/pxhd.h new file mode 100644 index 0000000000..c3e6ce5cd7 --- /dev/null +++ b/src/southbridge/intel/pxhd/pxhd.h @@ -0,0 +1,6 @@ +#ifndef PXHD_H +#define PXHD_H + +#include "chip.h" + +#endif /* PXHD_H */ diff --git a/src/southbridge/intel/pxhd/pxhd_bridge.c b/src/southbridge/intel/pxhd/pxhd_bridge.c new file mode 100644 index 0000000000..bceca29db9 --- /dev/null +++ b/src/southbridge/intel/pxhd/pxhd_bridge.c @@ -0,0 +1,258 @@ +/* + * (C) 2003-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 <device/pcix.h> +#include <pc80/mc146818rtc.h> +#include <delay.h> +#include "pxhd.h" + +static void pxhd_enable(device_t dev) +{ + device_t bridge; + uint16_t value; + if ((dev->path.u.pci.devfn & 1) == 0) { + /* Can we enable/disable the bridges? */ + return; + } + bridge = dev_find_slot(dev->bus->secondary, dev->path.u.pci.devfn & ~1); + if (!bridge) { + printk_err("Cannot find bridge for ioapic: %s\n", + dev_path(dev)); + return; + } + value = pci_read_config16(bridge, 0x40); + value &= ~(1 << 13); + if (!dev->enabled) { + value |= (1 << 13); + } + pci_write_config16(bridge, 0x40, value); +} + + +#define NMI_OFF 0 + +static unsigned int pxhd_scan_bridge(device_t dev, unsigned int max) +{ + int bus_100Mhz = 0; + + dev->link[0].dev = dev; + dev->links = 1; + + get_option(&bus_100Mhz, "pxhd_bus_speed_100"); + if(bus_100Mhz) { + uint16_t word; + + printk_debug("setting pxhd bus to 100 Mhz\n"); + /* set to pcix 100 mhz */ + word = pci_read_config16(dev, 0x40); + word &= ~(3 << 14); + word |= (1 << 14); + word &= ~(3 << 9); + word |= (2 << 9); + pci_write_config16(dev, 0x40, word); + + /* reset the bus to make the new frequencies effective */ + pci_bus_reset(&dev->link[0]); + } + return pcix_scan_bridge(dev, max); +} +static void pcix_init(device_t dev) +{ + uint32_t dword; + uint16_t word; + uint8_t byte; + int nmi_option; + + /* Bridge control ISA enable */ + pci_write_config8(dev, 0x3e, 0x07); + +#if 0 + + /* Enable memory write and invalidate ??? */ + byte = pci_read_config8(dev, 0x04); + byte |= 0x10; + pci_write_config8(dev, 0x04, byte); + + /* Set drive strength */ + word = pci_read_config16(dev, 0xe0); + word = 0x0404; + pci_write_config16(dev, 0xe0, word); + word = pci_read_config16(dev, 0xe4); + word = 0x0404; + pci_write_config16(dev, 0xe4, word); + + /* Set impedance */ + word = pci_read_config16(dev, 0xe8); + word = 0x0404; + pci_write_config16(dev, 0xe8, word); + + /* Set discard unrequested prefetch data */ + word = pci_read_config16(dev, 0x4c); + word |= 1; + pci_write_config16(dev, 0x4c, word); + + /* Set split transaction limits */ + word = pci_read_config16(dev, 0xa8); + pci_write_config16(dev, 0xaa, word); + word = pci_read_config16(dev, 0xac); + pci_write_config16(dev, 0xae, word); + + /* Set up error reporting, enable all */ + /* system error enable */ + dword = pci_read_config32(dev, 0x04); + dword |= (1<<8); + pci_write_config32(dev, 0x04, dword); + + /* system and error parity enable */ + dword = pci_read_config32(dev, 0x3c); + dword |= (3<<16); + pci_write_config32(dev, 0x3c, dword); + + /* NMI enable */ + nmi_option = NMI_OFF; + get_option(&nmi_option, "nmi"); + if(nmi_option) { + dword = pci_read_config32(dev, 0x44); + dword |= (1<<0); + pci_write_config32(dev, 0x44, dword); + } + + /* Set up CRC flood enable */ + dword = pci_read_config32(dev, 0xc0); + if(dword) { /* do device A only */ + dword = pci_read_config32(dev, 0xc4); + dword |= (1<<1); + pci_write_config32(dev, 0xc4, dword); + dword = pci_read_config32(dev, 0xc8); + dword |= (1<<1); + pci_write_config32(dev, 0xc8, dword); + } + + return; +#endif +} + +static struct device_operations pcix_ops = { + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .init = pcix_init, + .scan_bus = pxhd_scan_bridge, + .reset_bus = pci_bus_reset, + .ops_pci = 0, +}; + +static struct pci_driver pcix_driver __pci_driver = { + .ops = &pcix_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x0329, +}; + +static struct pci_driver pcix_driver2 __pci_driver = { + .ops = &pcix_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x032a, +}; + +#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) + /* IO-APIC virtual wire mode configuration */ + /* mask, trigger, polarity, destination, delivery, vector */ + +static void setup_ioapic(device_t dev) +{ + int i; + unsigned long value_low, value_high; + unsigned long ioapic_base; + volatile unsigned long *l; + unsigned interrupts; + + ioapic_base = pci_read_config32(dev, PCI_BASE_ADDRESS_0); + l = (unsigned long *) ioapic_base; + + /* Enable front side bus delivery */ + l[0] = 0x03; + l[4] = 1; + + 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; + } + } +} + +static void ioapic_init(device_t dev) +{ + uint32_t value; + /* Enable bus mastering so IOAPICs work */ + value = pci_read_config16(dev, PCI_COMMAND); + value |= PCI_COMMAND_MASTER; + pci_write_config16(dev, PCI_COMMAND, value); + + setup_ioapic(dev); +} + +static void intel_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} + +static struct pci_operations intel_ops_pci = { + .set_subsystem = intel_set_subsystem, +}; + +static struct device_operations ioapic_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = ioapic_init, + .scan_bus = 0, + .enable = pxhd_enable, + .ops_pci = &intel_ops_pci, +}; + +static struct pci_driver ioapic_driver __pci_driver = { + .ops = &ioapic_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x0326, + +}; + +static struct pci_driver ioapic2_driver __pci_driver = { + .ops = &ioapic_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x0327, + +}; + +struct chip_operations southbridge_intel_pxhd_ops = { + CHIP_NAME("PXHD") + .enable_dev = pxhd_enable, +}; |