diff options
-rw-r--r-- | src/southbridge/intel/i82801dx/i82801dx.h | 19 | ||||
-rw-r--r-- | src/southbridge/intel/i82801dx/i82801dx_lpc.c | 286 |
2 files changed, 178 insertions, 127 deletions
diff --git a/src/southbridge/intel/i82801dx/i82801dx.h b/src/southbridge/intel/i82801dx/i82801dx.h index 070fb7e4a2..cb062bf1d4 100644 --- a/src/southbridge/intel/i82801dx/i82801dx.h +++ b/src/southbridge/intel/i82801dx/i82801dx.h @@ -36,6 +36,9 @@ extern void i82801dx_enable(device_t dev); #endif +#define IO_APIC_ADDR 0xfec00000 +#define HPET_ADDR 0xfed00000 + #define DEBUG_PERIODIC_SMIS 0 #define MAINBOARD_POWER_OFF 0 @@ -79,8 +82,15 @@ extern void i82801dx_enable(device_t dev); #define BIOS_CNTL 0x4E #define GPIO_BASE 0x58 #define GPIO_CNTL 0x5C -#define PIRQA_ROUT 0x60 -#define PIRQE_ROUT 0x68 +#define GPIOBASE_ADDR 0x0500 +#define PIRQA_ROUT 0x60 +#define PIRQB_ROUT 0x61 +#define PIRQC_ROUT 0x62 +#define PIRQD_ROUT 0x63 +#define PIRQE_ROUT 0x68 +#define PIRQF_ROUT 0x69 +#define PIRQG_ROUT 0x6A +#define PIRQH_ROUT 0x6B #define COM_DEC 0xE0 #define LPC_EN 0xE6 #define FUNC_DIS 0xF2 @@ -192,4 +202,9 @@ extern void i82801dx_enable(device_t dev); #define TCOBASE 0x60 /* TCO Base Address Register */ #define TCO1_CNT 0x08 /* TCO1 Control Register */ +/* GEN_PMCON_3 bits */ +#define RTC_BATTERY_DEAD (1 << 2) +#define RTC_POWER_FAILED (1 << 1) +#define SLEEP_AFTER_POWER_FAIL (1 << 0) + #endif /* I82801DX_H */ diff --git a/src/southbridge/intel/i82801dx/i82801dx_lpc.c b/src/southbridge/intel/i82801dx/i82801dx_lpc.c index 6c2ef3c573..99456bae9a 100644 --- a/src/southbridge/intel/i82801dx/i82801dx_lpc.c +++ b/src/southbridge/intel/i82801dx/i82801dx_lpc.c @@ -4,6 +4,7 @@ * Copyright (C) 2003 Linux Networx * Copyright (C) 2004 SuSE Linux AG * Copyright (C) 2004 Tyan Computer + * Copyright (C) 2010 Joseph Smith <joe@settoplinux.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -32,166 +33,201 @@ #define NMI_OFF 0 -void i82801dx_enable_ioapic(struct device *dev) +typedef struct southbridge_intel_i82801dx_config config_t; + +static void i82801dx_enable_ioapic(struct device *dev) { - u32 dword; - volatile u32 *ioapic_sba = (volatile u32 *)0xfec00000; - volatile u32 *ioapic_sbd = (volatile u32 *)0xfec00010; - - dword = pci_read_config32(dev, GEN_CNTL); - dword |= (3 << 7); /* enable ioapic */ - dword |= (1 << 13); /* coprocessor error enable */ - dword |= (1 << 1); /* delay transaction enable */ - dword |= (1 << 2); /* DMA collection buf enable */ - pci_write_config32(dev, GEN_CNTL, dword); - printk_debug("ioapic southbridge enabled %x\n", dword); - *ioapic_sba = 0; - *ioapic_sbd = (2 << 24); - //lyh *ioapic_sba=3; - //lyh *ioapic_sbd=1; - *ioapic_sba = 0; - dword = *ioapic_sbd; - printk_debug("Southbridge apic id = %x\n", dword); - if (dword != (2 << 24)) - die(""); - //lyh *ioapic_sba=3; - //lyh dword=*ioapic_sbd; - //lyh printk_debug("Southbridge apic DT = %x\n",dword); - //lyh if(dword!=1) - //lyh die(""); + u32 reg32; + volatile u32 *ioapic_index = (volatile u32 *)IO_APIC_ADDR; + volatile u32 *ioapic_data = (volatile u32 *)IO_APIC_ADDR + 0x10; + + /* Set ACPI base address (I/O space). */ + pci_write_config32(dev, PMBASE, (PMBASE_ADDR | 1)); + + /* Enable ACPI I/O and power management. */ + pci_write_config8(dev, ACPI_CNTL, 0x10); + reg32 = pci_read_config32(dev, GEN_CNTL); + reg32 |= (3 << 7); /* Enable IOAPIC */ + reg32 |= (1 << 13); /* Coprocessor error enable */ + reg32 |= (1 << 1); /* Delayed transaction enable */ + reg32 |= (1 << 2); /* DMA collection buffer enable */ + pci_write_config32(dev, GEN_CNTL, reg32); + printk_debug("IOAPIC Southbridge enabled %x\n", reg32); + + *ioapic_index = 0; + *ioapic_data = (1 << 25); + + *ioapic_index = 0; + reg32 = *ioapic_data; + printk_debug("Southbridge APIC ID = %x\n", reg32); + if (reg32 != (1 << 25)) + die("APIC Error\n"); + + /* TODO: From i82801ca, needed/useful on other ICH? */ + *ioapic_index = 3; /* Select Boot Configuration register. */ + *ioapic_data = 1; /* Use Processor System Bus to deliver interrupts. */ } -void i82801dx_enable_serial_irqs(struct device *dev) +static void i82801dx_enable_serial_irqs(struct device *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)); } -void i82801dx_lpc_route_dma(struct device *dev, u8 mask) +static void i82801dx_pirq_init(device_t dev) { - u16 word; - int i; - word = pci_read_config16(dev, PCI_DMA_CFG); - word &= ((1 << 10) - (1 << 8)); - for (i = 0; i < 8; i++) { - if (i == 4) - continue; - word |= ((mask & (1 << i)) ? 3 : 1) << (i * 2); - } - pci_write_config16(dev, PCI_DMA_CFG, word); + /* Get the chip configuration */ + config_t *config = dev->chip_info; + + pci_write_config8(dev, PIRQA_ROUT, config->pirqa_routing); + pci_write_config8(dev, PIRQB_ROUT, config->pirqb_routing); + pci_write_config8(dev, PIRQC_ROUT, config->pirqc_routing); + pci_write_config8(dev, PIRQD_ROUT, config->pirqd_routing); + pci_write_config8(dev, PIRQE_ROUT, config->pirqe_routing); + pci_write_config8(dev, PIRQF_ROUT, config->pirqf_routing); + pci_write_config8(dev, PIRQG_ROUT, config->pirqg_routing); + pci_write_config8(dev, PIRQH_ROUT, config->pirqh_routing); + } -void i82801dx_rtc_init(struct device *dev) +static void i82801dx_power_options(device_t dev) { u8 byte; - u32 dword; - int rtc_failed; - byte = pci_read_config8(dev, GEN_PMCON_3); - rtc_failed = byte & RTC_FAILED; - if (rtc_failed) { - byte &= ~(1 << 1); /* preserve the power fail state */ - pci_write_config8(dev, GEN_PMCON_3, byte); + int pwr_on = -1; + int nmi_option; + + /* power after power fail */ + /* FIXME this doesn't work! */ + /* Which state do we want to goto after g3 (power restored)? + * 0 == S0 Full On + * 1 == S5 Soft Off + */ + pci_write_config8(dev, GEN_PMCON_3, pwr_on ? 0 : 1); + printk_info("Set power %s if power fails\n", pwr_on ? "on" : "off"); + + /* Set up NMI on errors. */ + byte = inb(0x61); + byte &= ~(1 << 3); /* IOCHK# NMI Enable */ + byte &= ~(1 << 2); /* PCI SERR# Enable */ + outb(byte, 0x61); + byte = inb(0x70); + + nmi_option = NMI_OFF; + get_option(&nmi_option, "nmi"); + if (nmi_option) { + byte &= ~(1 << 7); /* Set NMI. */ + outb(byte, 0x70); } - dword = pci_read_config32(dev, GEN_STS); - rtc_failed |= dword & (1 << 2); - rtc_init(rtc_failed); } -void i82801dx_1f0_misc(struct device *dev) +static void gpio_init(device_t dev) { - pci_write_config16(dev, PCICMD, 0x014f); - pci_write_config32(dev, PMBASE, 0x00001001); - pci_write_config8(dev, ACPI_CNTL, 0x10); - pci_write_config32(dev, GPIO_BASE, 0x00001181); + /* This should be done in romstage.c already */ + pci_write_config32(dev, GPIO_BASE, (GPIOBASE_ADDR | 1)); pci_write_config8(dev, GPIO_CNTL, 0x10); - pci_write_config32(dev, PIRQA_ROUT, 0x0A05030B); - pci_write_config8(dev, PIRQE_ROUT, 0x07); +} + +static void i82801dx_rtc_init(struct device *dev) +{ + u8 reg8; + u32 reg32; + int rtc_failed; + + reg8 = pci_read_config8(dev, GEN_PMCON_3); + rtc_failed = reg8 & RTC_BATTERY_DEAD; + if (rtc_failed) { + reg8 &= ~(1 << 1); /* Preserve the power fail state. */ + pci_write_config8(dev, GEN_PMCON_3, reg8); + } + reg32 = pci_read_config32(dev, GEN_STS); + rtc_failed |= reg32 & (1 << 2); + rtc_init(rtc_failed); + + /* Enable access to the upper 128 byte bank of CMOS RAM. */ pci_write_config8(dev, RTC_CONF, 0x04); - pci_write_config8(dev, COM_DEC, 0x10); //lyh E0-> - pci_write_config16(dev, LPC_EN, 0x000F); //LYH 000D-> } -static void enable_hpet(struct device *dev) +static void i82801dx_lpc_route_dma(struct device *dev, u8 mask) { - const unsigned long hpet_address = 0xfed00000; + u16 reg16; + int i; - u32 dword; - u32 code = (0 & 0x3); + reg16 = pci_read_config16(dev, PCI_DMA_CFG); + reg16 &= 0x300; + for (i = 0; i < 8; i++) { + if (i == 4) + continue; + reg16 |= ((mask & (1 << i)) ? 3 : 1) << (i * 2); + } + pci_write_config16(dev, PCI_DMA_CFG, reg16); +} - 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 */ +static void i82801dx_lpc_decode_en(device_t dev) +{ + /* Decode 0x3F8-0x3FF (COM1) for COMA port, 0x2F8-0x2FF (COM2) for COMB. + * LPT decode defaults to 0x378-0x37F and 0x778-0x77F. + * Floppy decode defaults to 0x3F0-0x3F5, 0x3F7. + * We also need to set the value for LPC I/F Enables Register. + */ + pci_write_config8(dev, COM_DEC, 0x10); + pci_write_config16(dev, LPC_EN, 0x300F); +} - dword &= ~(3 << 15); /* clear it */ - dword |= (code << 15); +static void enable_hpet(struct device *dev) +{ + u32 reg32; + u32 code = (0 & 0x3); - printk_debug("enabling HPET @0x%lx\n", hpet_address | (code << 12)); + reg32 = pci_read_config32(dev, GEN_CNTL); + reg32 |= (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 + */ + reg32 &= ~(3 << 15); /* Clear it */ + reg32 |= (code << 15); + /* TODO: reg32 is never written to anywhere? */ + printk_debug("Enabling HPET @0x%x\n", HPET_ADDR | (code << 12)); } static void lpc_init(struct device *dev) { - u8 byte; - int pwr_on = -1; - int nmi_option; + /* Set the value for PCI command register. */ + pci_write_config16(dev, PCI_COMMAND, 0x000f); - /* IO APIC initialization */ + /* IO APIC initialization. */ i82801dx_enable_ioapic(dev); i82801dx_enable_serial_irqs(dev); -#ifdef SUSPICIOUS_LOOKING_CODE - // The ICH-4 datasheet does not mention this configuration register. - // This code may have been inherited (incorrectly) from code for the AMD 766 southbridge, - // which *does* support this functionality. + /* Setup the PIRQ. */ + i82801dx_pirq_init(dev); - /* posted memory write enable */ - byte = pci_read_config8(dev, 0x46); - pci_write_config8(dev, 0x46, byte | (1 << 0)); -#endif + /* Setup power options. */ + i82801dx_power_options(dev); - /* power after power fail */ - /* FIXME this doesn't work! */ - /* Which state do we want to goto after g3 (power restored)? - * 0 == S0 Full On - * 1 == S5 Soft Off - */ - pci_write_config8(dev, GEN_PMCON_3, pwr_on ? 0 : 1); - printk_info("set power %s after power fail\n", pwr_on ? "on" : "off"); -#if 0 - /* Enable Error reporting */ - /* Set up sync flood detected */ - byte = pci_read_config8(dev, 0x47); - byte |= (1 << 1); - pci_write_config8(dev, 0x47, byte); -#endif - - /* Set up NMI on errors */ - byte = inb(0x61); - byte &= ~(1 << 3); /* IOCHK# NMI Enable */ - byte &= ~(1 << 2); /* PCI SERR# Enable */ - outb(byte, 0x61); - byte = inb(0x70); - nmi_option = NMI_OFF; - get_option(&nmi_option, "nmi"); - if (nmi_option) { - byte &= ~(1 << 7); /* set NMI */ - outb(byte, 0x70); - } + /* Set the state of the GPIO lines. */ + gpio_init(dev); - /* Initialize the real time clock */ + /* Initialize the real time clock. */ i82801dx_rtc_init(dev); + /* Route DMA. */ i82801dx_lpc_route_dma(dev, 0xff); - /* Initialize isa dma */ + /* Initialize ISA DMA. */ isa_dma_init(); - i82801dx_1f0_misc(dev); + /* Setup decode ports and LPC I/F enables. */ + i82801dx_lpc_decode_en(dev); + /* Initialize the High Precision Event Timers */ enable_hpet(dev); } @@ -208,15 +244,15 @@ static void i82801dx_lpc_read_resources(device_t dev) res->base = 0; res->size = 0x1000; res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | - IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + IORESOURCE_ASSIGNED | IORESOURCE_FIXED; res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0)); res->base = 0xff800000; - res->size = 0x00800000; /* 8 MB for flash */ + res->size = 0x00800000; /* 8 MB for flash */ res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | - IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + IORESOURCE_ASSIGNED | IORESOURCE_FIXED; - res = new_resource(dev, 3); /* IOAPIC */ + res = new_resource(dev, 3); /* IOAPIC */ res->base = 0xfec00000; res->size = 0x00001000; res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; @@ -229,12 +265,12 @@ static void i82801dx_lpc_enable_resources(device_t dev) } static struct device_operations lpc_ops = { - .read_resources = i82801dx_lpc_read_resources, - .set_resources = pci_dev_set_resources, - .enable_resources = i82801dx_lpc_enable_resources, - .init = lpc_init, - .scan_bus = scan_static_bus, - .enable = i82801dx_enable, + .read_resources = i82801dx_lpc_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = i82801dx_lpc_enable_resources, + .init = lpc_init, + .scan_bus = scan_static_bus, + .enable = i82801dx_enable, }; /* 82801DB/DBL */ |