summaryrefslogtreecommitdiff
path: root/src/southbridge/intel/i82801ex/i82801ex_lpc.c
diff options
context:
space:
mode:
authorStefan Reinauer <stepan@coresystems.de>2010-02-27 01:50:21 +0000
committerStefan Reinauer <stepan@openbios.org>2010-02-27 01:50:21 +0000
commit138be8315b63b0c8955159580d085e7621882b95 (patch)
treeaabbcab390ea1e522524ff7e98d11ac752a051b5 /src/southbridge/intel/i82801ex/i82801ex_lpc.c
parentbe07eb29bc087a97903f72c2253442c285ce5942 (diff)
This does the following:
cd coreboot/src/southbridge svn mv i82801ca i82801cx svn mv i82801dbm i82801dx svn mv i82801er i82801ex svn copy i82801xx i82801bx svn mv i82801xx i82801ax Plus, fixing up the filenames in these directories and the romstage.c and Kconfig files of the mainboards using those drivers. Plus, switching the thomson ip1000 and rca rm4100 to the i82801dx driver. There's a lot more to be done, like - adding device IDs for the ICH3 and newer drivers that have been kept in i82801xx so far - drop the additional parts support from the ax and bx drivers. Signed-off-by: Stefan Reinauer <stepan@coresystems.de> Acked-by: Uwe Hermann <uwe@hermann-uwe.de> Acked-by: Joseph Smith <joe@settoplinux.org> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5167 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/southbridge/intel/i82801ex/i82801ex_lpc.c')
-rw-r--r--src/southbridge/intel/i82801ex/i82801ex_lpc.c359
1 files changed, 359 insertions, 0 deletions
diff --git a/src/southbridge/intel/i82801ex/i82801ex_lpc.c b/src/southbridge/intel/i82801ex/i82801ex_lpc.c
new file mode 100644
index 0000000000..6cf8124c50
--- /dev/null
+++ b/src/southbridge/intel/i82801ex/i82801ex_lpc.c
@@ -0,0 +1,359 @@
+/*
+ * (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 <arch/ioapic.h>
+#include "i82801ex.h"
+
+#define ACPI_BAR 0x40
+#define GPIO_BAR 0x58
+
+#define NMI_OFF 0
+#define MAINBOARD_POWER_OFF 0
+#define MAINBOARD_POWER_ON 1
+
+#ifndef CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL
+#define CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON
+#endif
+
+#define SERIRQ_CNTL 0x64
+static void i82801ex_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 i82801ex_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 i82801ex_enable_lpc(device_t dev)
+{
+ /* lpc i/f enable */
+ pci_write_config8(dev, LPC_EN, 0x0d);
+}
+
+typedef struct southbridge_intel_i82801ex_config config_t;
+
+static void set_i82801ex_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_i82801ex_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_i82801ex_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_i82801ex_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 i82801ex_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 i82801ex_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_i82801ex_gpio_use_sel(dev, res, config);
+
+ /* Set the IO direction */
+ set_i82801ex_gpio_direction(dev, res, config);
+
+ /* Setup the input inverters */
+ set_i82801ex_gpio_inv(dev, res, config);
+
+ /* Set the value on the GPIO output pins */
+ set_i82801ex_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=CONFIG_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(IO_APIC_ADDR, 0); // Don't rename IO APIC ID.
+
+ i82801ex_enable_serial_irqs(dev);
+
+ i82801ex_pci_dma_cfg(dev);
+
+ i82801ex_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 */
+ i82801ex_pirq_init(dev);
+
+ /* Set the state of the gpio lines */
+ i82801ex_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 i82801ex_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->base = 0;
+ res->size = 0x1000;
+ res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
+ IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+
+ res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
+ res->base = 0xff800000;
+ res->size = 0x00800000; /* 8 MB for flash */
+ res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
+ IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+
+ res = new_resource(dev, 3); /* IOAPIC */
+ res->base = 0xfec00000;
+ res->size = 0x00001000;
+ res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+}
+
+static void i82801ex_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 = i82801ex_lpc_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = i82801ex_lpc_enable_resources,
+ .init = lpc_init,
+ .scan_bus = scan_static_bus,
+ .enable = i82801ex_enable,
+ .ops_pci = &lops_pci,
+};
+
+static const struct pci_driver lpc_driver __pci_driver = {
+ .ops = &lpc_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801ER_LPC,
+};