X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fsouthbridge%2Fintel%2Fi82801dx%2Fi82801dx_lpc.c;h=768e70096bbf809aa9fb31a3c4759e57953d2c0c;hb=74d1a6e8a166cd477f667a6fcb1e96b8a0cbdac1;hp=6c2ef3c57351bacdaa8328bef39e54c239c17294;hpb=b319b1778c0546d9fc0777ccb9a0b82291b5a60e;p=coreboot.git diff --git a/src/southbridge/intel/i82801dx/i82801dx_lpc.c b/src/southbridge/intel/i82801dx/i82801dx_lpc.c index 6c2ef3c57..768e70096 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 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -28,170 +29,270 @@ #include #include #include +#include #include "i82801dx.h" #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(BIOS_DEBUG, "IOAPIC Southbridge enabled %x\n", reg32); + + *ioapic_index = 0; + *ioapic_data = (1 << 25); + + *ioapic_index = 0; + reg32 = *ioapic_data; + printk(BIOS_DEBUG, "Southbridge APIC ID = %x\n", reg32); + if (reg32 != (1 << 25)) + die("APIC Error\n"); + + *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); + /* 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); +} + +static void i82801dx_power_options(device_t dev) +{ + u8 reg8; + u16 reg16, pmbase; + u32 reg32; + const char *state; + + int pwr_on = CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL; + int nmi_option; + + /* Which state do we want to goto after g3 (power restored)? + * 0 == S0 Full On + * 1 == S5 Soft Off + * + * If the option is not existent (Laptops), use MAINBOARD_POWER_ON. + */ + if (get_option(&pwr_on, "power_on_after_fail") < 0) + pwr_on = MAINBOARD_POWER_ON; + + reg8 = pci_read_config8(dev, GEN_PMCON_3); + reg8 &= 0xfe; + switch (pwr_on) { + case MAINBOARD_POWER_OFF: + reg8 |= 1; + state = "off"; + break; + case MAINBOARD_POWER_ON: + reg8 &= ~1; + state = "on"; + break; + case MAINBOARD_POWER_KEEP: + reg8 &= ~1; + state = "state keep"; + break; + default: + state = "undefined"; + } + + reg8 &= ~(1 << 3); /* minimum asssertion is 1 to 2 RTCCLK */ + + pci_write_config8(dev, GEN_PMCON_3, reg8); + printk(BIOS_INFO, "Set power %s after power failure.\n", state); + + /* Set up NMI on errors. */ + reg8 = inb(0x61); + reg8 &= 0x0f; /* Higher Nibble must be 0 */ + reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */ + // reg8 &= ~(1 << 2); /* PCI SERR# Enable */ + reg8 |= (1 << 2); /* PCI SERR# Disable for now */ + outb(reg8, 0x61); + + reg8 = inb(0x70); + nmi_option = NMI_OFF; + get_option(&nmi_option, "nmi"); + if (nmi_option) { + printk(BIOS_INFO, "NMI sources enabled.\n"); + reg8 &= ~(1 << 7); /* Set NMI. */ + } else { + printk(BIOS_INFO, "NMI sources disabled.\n"); + reg8 |= ( 1 << 7); /* Disable NMI. */ } - pci_write_config16(dev, PCI_DMA_CFG, word); + outb(reg8, 0x70); + + /* Set SMI# rate down and enable CPU_SLP# */ + reg16 = pci_read_config16(dev, GEN_PMCON_1); + reg16 &= ~(3 << 0); // SMI# rate 1 minute + reg16 |= (1 << 5); // CPUSLP_EN Desktop only + pci_write_config16(dev, GEN_PMCON_1, reg16); + + pmbase = pci_read_config16(dev, 0x40) & 0xfffe; + + /* Set up power management block and determine sleep mode */ + reg32 = inl(pmbase + 0x04); // PM1_CNT + + reg32 &= ~(7 << 10); // SLP_TYP + reg32 |= (1 << 0); // SCI_EN + outl(reg32, pmbase + 0x04); +} + +static void gpio_init(device_t dev) +{ + /* This should be done in romstage.c already */ + pci_write_config32(dev, GPIO_BASE, (GPIOBASE_ADDR | 1)); + pci_write_config8(dev, GPIO_CNTL, 0x10); } -void i82801dx_rtc_init(struct device *dev) +static void i82801dx_rtc_init(struct device *dev) { - u8 byte; - u32 dword; + u8 reg8; + u32 reg32; int rtc_failed; - byte = pci_read_config8(dev, GEN_PMCON_3); - rtc_failed = byte & RTC_FAILED; + + reg8 = pci_read_config8(dev, GEN_PMCON_3); + rtc_failed = reg8 & RTC_BATTERY_DEAD; if (rtc_failed) { - byte &= ~(1 << 1); /* preserve the power fail state */ - pci_write_config8(dev, GEN_PMCON_3, byte); + reg8 &= ~(1 << 1); /* Preserve the power fail state. */ + pci_write_config8(dev, GEN_PMCON_3, reg8); } - dword = pci_read_config32(dev, GEN_STS); - rtc_failed |= dword & (1 << 2); + reg32 = pci_read_config32(dev, GEN_STS); + rtc_failed |= reg32 & (1 << 2); rtc_init(rtc_failed); -} -void i82801dx_1f0_misc(struct device *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); - pci_write_config8(dev, GPIO_CNTL, 0x10); - pci_write_config32(dev, PIRQA_ROUT, 0x0A05030B); - pci_write_config8(dev, PIRQE_ROUT, 0x07); + /* Enable access to the upper 128 byte bank of CMOS RAM. */ pci_write_config8(dev, RTC_CONF, 0x04); - 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; - - u32 dword; - u32 code = (0 & 0x3); + u16 reg16; + int i; - 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 */ + 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 &= ~(3 << 15); /* clear it */ - dword |= (code << 15); +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); +} - printk_debug("enabling HPET @0x%lx\n", hpet_address | (code << 12)); +/* ICH4 does not mention HPET in the docs, but + * all ICH3 and ICH4 do have HPETs built in. + */ +static void enable_hpet(struct device *dev) +{ + u32 reg32, hpet, val; + + /* Set HPET base address and enable it */ + printk(BIOS_DEBUG, "Enabling HPET at 0x%x\n", HPET_ADDR); + reg32 = pci_read_config32(dev, GEN_CNTL); + /* + * Bit 17 is HPET enable bit. + * Bit 16:15 control the HPET base address. + */ + reg32 &= ~(3 << 15); /* Clear it */ + + hpet = HPET_ADDR >> 12; + hpet &= 0x3; + + reg32 |= (hpet << 15); + reg32 |= (1 << 17); /* Enable HPET. */ + pci_write_config32(dev, GEN_CNTL, reg32); + + /* Check to see whether it took */ + reg32 = pci_read_config32(dev, GEN_CNTL); + val = reg32 >> 15; + val &= 0x7; + + if ((val & 0x4) && (hpet == (val & 0x3))) { + printk(BIOS_INFO, "HPET enabled at 0x%x\n", HPET_ADDR); + } else { + printk(BIOS_WARNING, "HPET was not enabled correctly\n"); + reg32 &= ~(1 << 17); /* Clear Enable */ + pci_write_config32(dev, GEN_CNTL, reg32); + } } 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,33 +309,27 @@ 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->base = 0xfec00000; + res = new_resource(dev, 3); /* IOAPIC */ + res->base = IO_APIC_ADDR; res->size = 0x00001000; res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; } -static void i82801dx_lpc_enable_resources(device_t dev) -{ - pci_dev_enable_resources(dev); - enable_childrens_resources(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 = pci_dev_enable_resources, + .init = lpc_init, + .scan_bus = scan_static_bus, + .enable = i82801dx_enable, }; /* 82801DB/DBL */