diff options
author | Bari Ari <bari@onelabs.com> | 2009-05-27 13:12:42 +0000 |
---|---|---|
committer | Uwe Hermann <uwe@hermann-uwe.de> | 2009-05-27 13:12:42 +0000 |
commit | 612163e3833e807caeed8889dae41d24026241e7 (patch) | |
tree | e0a711474dd3f82eaf43954dc6074ce6857d9be7 /src/northbridge/via/vx800/vx800_lpc.c | |
parent | e6e899dde951823ebc9abf997a6af06debac82a3 (diff) |
Here's the VIA vx800 patch from OLPC.
It's untested, but a good starting point for everyone.
Signed-off-by: Bari Ari <bari@onelabs.com>
Acked-by: Ronald G. Minnich <rminnich@gmail.com>
Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4313 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/northbridge/via/vx800/vx800_lpc.c')
-rw-r--r-- | src/northbridge/via/vx800/vx800_lpc.c | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/src/northbridge/via/vx800/vx800_lpc.c b/src/northbridge/via/vx800/vx800_lpc.c new file mode 100644 index 0000000000..92660212cf --- /dev/null +++ b/src/northbridge/via/vx800/vx800_lpc.c @@ -0,0 +1,384 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009 One Laptop per Child, Association, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <arch/io.h> +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ops.h> +#include <device/pci_ids.h> + +#include <pc80/mc146818rtc.h> +#include <pc80/keyboard.h> +#include <pc80/i8259.h> +#include "vx800.h" +#include "chip.h" + +static const unsigned char pciIrqs[4] = {0xa, 0x9, 0xb, 0xa}; + +static const unsigned char vgaPins[4] = { 'A', 'B', 'C', 'D' };//only INTA + +static const unsigned char slotPins[4] = { 'A', 'A', 'A', 'A'};//all 4 + +static const unsigned char usbdevicePins[4] = { 'A', 'B', 'C', 'D' };//only INTA +static const unsigned char sdioPins[4] = { 'A', 'B', 'C', 'D' };//only INTA +static const unsigned char sd_ms_ctrl_Pins[4] = { 'B', 'C', 'D', 'A' };//only INTA +static const unsigned char ce_ata_nf_ctrl_Pins[4] = { 'C', 'C', 'D', 'A' };//only INTA +static const unsigned char idePins[4] = { 'B', 'C', 'D', 'A' };//only INTA + +static const unsigned char usbPins[4] = { 'A', 'B', 'C', 'D' };//all 4 + +static const unsigned char hdacaudioPins[4] = { 'B', 'C', 'D', 'A' };//only INTA + +static unsigned char *pin_to_irq(const unsigned char *pin) +{ + static unsigned char Irqs[4]; + int i; + for (i = 0 ; i < 4 ; i++) + Irqs[i] = pciIrqs[ pin[i] - 'A' ]; + + return Irqs; +} + +static void pci_routing_fixup(struct device *dev) +{ + printk_info("%s: dev is %p\n", __FUNCTION__, dev); + + /* set up PCI IRQ routing */ + pci_write_config8(dev, 0x55, pciIrqs[0] << 4); + pci_write_config8(dev, 0x56, pciIrqs[1] | (pciIrqs[2] << 4) ); + pci_write_config8(dev, 0x57, pciIrqs[3] << 4); + + /* VGA */ + printk_info("setting vga\n"); + pci_assign_irqs(0, 0x1, pin_to_irq(vgaPins)); + + /* PCI slot */ + printk_info("setting pci slot\n"); + pci_assign_irqs(0, 0x08, pin_to_irq(slotPins)); + + /* PCI slot */ + printk_info("setting USB Device Controller\n"); + pci_assign_irqs(0, 0x0b, pin_to_irq(usbdevicePins)); + + /* PCI slot */ + printk_info("setting SDIO Controller\n"); + pci_assign_irqs(0, 0x0c, pin_to_irq(sdioPins)); + + /* PCI slot */ + printk_info("setting SD $ MS Controller\n"); + pci_assign_irqs(0, 0x0d, pin_to_irq(sd_ms_ctrl_Pins)); + + /* PCI slot */ + printk_info("setting CE-ATA NF Controller(Card Boot)\n"); + pci_assign_irqs(0, 0x0e, pin_to_irq(ce_ata_nf_ctrl_Pins)); + + /* PCI slot */ + printk_info("setting ide\n"); + //pci_assign_irqs(0, 0x0f, pin_to_irq(idePins)); + + /* Standard usb components */ + printk_info("setting usb1-2\n"); +// pci_assign_irqs(0, 0x10, pin_to_irq(usbPins)); + + /* sound hardware */ + printk_info("setting hdac audio\n"); + pci_assign_irqs(0, 0x14, pin_to_irq(hdacaudioPins)); + + printk_spew("%s: DONE\n", __FUNCTION__); +} + +void setup_pm(device_t dev) +{ + u16 tmp; + /* Debounce LID and PWRBTN# Inputs for 16ms. */ + pci_write_config8(dev, 0x80, 0x20); + + /* Set ACPI base address to IO VX800_ACPI_IO_BASE */ + pci_write_config16(dev, 0x88, VX800_ACPI_IO_BASE|1); + + /* set ACPI irq to 9 */ + pci_write_config8(dev, 0x82, 0x49); + + /* Primary interupt channel, define wake events 0=IRQ0 15=IRQ15 1=en. */ +// pci_write_config16(dev, 0x84, 0x30f2); + pci_write_config16(dev, 0x84, 0x609a); // 0x609a?? + + /* SMI output level to low, 7.5us throttle clock */ + pci_write_config8(dev, 0x8d, 0x18); + + /* GP Timer Control 1s */ + pci_write_config8(dev, 0x93, 0x88); + + /* Power Well */ + pci_write_config8(dev, 0x94, 0x20); // 0x20?? + + /* 7 = stp to sust delay 1msec + * 6 = SUSST# Deasserted Before PWRGD for STD + */ + pci_write_config8(dev, 0x95, 0xc0); // 0xc1?? + + /* Disable GP2 & GP3 Timer */ + pci_write_config8(dev, 0x98, 0); + + /* GP2 Timer Counter */ + pci_write_config8(dev, 0x99, 0xfb); + /* GP3 Timer Counter */ + //pci_write_config8(dev, 0x9a, 0x20); + + /* Multi Function Select 1 */ + pci_write_config8(dev, 0xe4, 0x00); + /* Multi Function Select 2 */ + pci_write_config8(dev, 0xe5, 0x41); //?? + + + /* Enable ACPI access (and setup like award) */ + pci_write_config8(dev, 0x81, 0x84); + + /* Clear status events. */ + outw(0xffff, VX800_ACPI_IO_BASE + 0x00); + outw(0xffff, VX800_ACPI_IO_BASE + 0x20); + outw(0xffff, VX800_ACPI_IO_BASE + 0x28); + outl(0xffffffff, VX800_ACPI_IO_BASE + 0x30); + + /* Disable SCI on GPIO. */ + outw(0x0, VX800_ACPI_IO_BASE + 0x22); + + /* Disable SMI on GPIO. */ + outw(0x0, VX800_ACPI_IO_BASE + 0x24); + + /* Disable all global enable SMIs. */ + outw(0x0, VX800_ACPI_IO_BASE + 0x2a); + + /* All SMI off, both IDE buses ON, PSON rising edge. */ + outw(0x0, VX800_ACPI_IO_BASE + 0x2c); + + /* Primary activity SMI disable. */ + outl(0x0, VX800_ACPI_IO_BASE + 0x34); + + /* GP timer reload on none. */ + outl(0x0, VX800_ACPI_IO_BASE + 0x38); + + /* Disable extended IO traps. */ + outb(0x0, VX800_ACPI_IO_BASE + 0x42); + + tmp = inw(VX800_ACPI_IO_BASE + 0x04); + /* SCI is generated for RTC/pwrBtn/slpBtn. */ + tmp |= 1; + outw(tmp, VX800_ACPI_IO_BASE + 0x04); + + /* Allow SLP# signal to assert LDTSTOP_L. + * Will work for C3 and for FID/VID change. + */ + outb(0x1, VX800_ACPI_IO_BASE + 0x11); +/* + outw(0x0, 0x424); + outw(0x0, 0x42a); + outw(0x1, 0x42c); + outl(0x0, 0x434); + outl(0x01, 0x438); + outb(0x0, 0x442); + outl(0xffff7fff, 0x448); + outw(0x001, 0x404); +*/ +} +void S3_ps2_kb_ms_wakeup(struct device *dev) +{ u8 enables; + enables = pci_read_config8(dev, 0x51); + enables |= 2; + pci_write_config8(dev, 0x51, enables); + + outb(0xe0, 0x2e); + outb(0x0b, 0x2f);//if 09,then only support kb wakeup + + outb(0xe1, 0x2e);//set any key scan code can wakeup + outb(0x00, 0x2f); + + outb(0xe9, 0x2e);//set any mouse scan code can wakeup + outb(0x00, 0x2f); + + enables &= 0xd; + pci_write_config8(dev, 0x51, enables); + + outb(inb(VX800_ACPI_IO_BASE+0x02)|0x20, VX800_ACPI_IO_BASE+0x02);//ACPI golabe enable for sci smi trigger + outw(inw(VX800_ACPI_IO_BASE+0x22)|0x204, VX800_ACPI_IO_BASE+0x22);//ACPI SCI on Internal KBC PME and mouse PME + +} +void S3_usb_wakeup(struct device *dev) +{ + outw(inw(VX800_ACPI_IO_BASE+0x22)|0x4000, VX800_ACPI_IO_BASE+0x22);//SCI on USB PME +} + +void S3_lid_wakeup(struct device *dev) +{ + outw(inw(VX800_ACPI_IO_BASE+0x22)|0x800, VX800_ACPI_IO_BASE+0x22);//SCI on LID PME +} + + +/* This looks good enough to work, maybe */ +static void vx800_sb_init(struct device *dev) +{ + unsigned char enables; + + // enable the internal I/O decode + enables = pci_read_config8(dev, 0x6C); + enables |= 0x80; + pci_write_config8(dev, 0x6C, enables); + + // Map 4MB of FLASH into the address space +// pci_write_config8(dev, 0x41, 0x7f); + + // Set bit 6 of 0x40, because Award does it (IO recovery time) + // IMPORTANT FIX - EISA 0x4d0 decoding must be on so that PCI + // interrupts can be properly marked as level triggered. + enables = pci_read_config8(dev, 0x40); + enables |= 0x44; + pci_write_config8(dev, 0x40, enables); + + /* DMA Line buffer control */ + enables = pci_read_config8(dev, 0x42); + enables |= 0xf0; + pci_write_config8(dev, 0x42, enables); + + /* I/O recovery time */ + pci_write_config8(dev, 0x4c, 0x44); + + /* ROM memory cycles go to LPC. */ + pci_write_config8(dev, 0x59, 0x80); + + /* Set 0x5b to 0x01 to match Award */ + //pci_write_config8(dev, 0x5b, 0x01); + enables = pci_read_config8(dev, 0x5b); + enables |= 0x01; + pci_write_config8(dev, 0x5b, enables); + + + /* Set Read Pass Write Control Enable */ + pci_write_config8(dev, 0x48, 0x0c); + + /* Set 0x58 to 0x42 APIC and RTC. */ + //pci_write_config8(dev, 0x58, 0x42); this cmd cause the irq0 can not be triggerd,since bit 5 was set to 0. + enables=pci_read_config8(dev, 0x58); + enables|=0x41;// + pci_write_config8(dev, 0x58,enables); + + + /* Set bit 3 of 0x4f to match award (use INIT# as cpu reset) */ + enables = pci_read_config8(dev, 0x4f); + enables |= 0x08; + pci_write_config8(dev, 0x4f, enables); + + /* enable serial irq */ + pci_write_config8(dev, 0x52, 0x9); + + /* dma */ + pci_write_config8(dev, 0x53, 0x00); + + // Power management setup + setup_pm(dev); + + /* set up isa bus -- i/o recovery time, rom write enable, extend-ale */ + pci_write_config8(dev, 0x40, 0x54); + + // Start the rtc + rtc_init(0); +} + +/* total kludge to get lxb to call our childrens set/enable functions - these are + not called unless this device has a resource to set - so set a dummy one */ +void vx800_read_resources(device_t dev) +{ + + struct resource *resource; + pci_dev_read_resources(dev); + resource = new_resource(dev, 1); + resource->flags |= IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_IO | IORESOURCE_STORED; + resource->size = 2; + resource->base = 0x2e; + +} +void vx800_set_resources(device_t dev) +{ + struct resource *resource; + resource = find_resource(dev,1); + resource->flags |= IORESOURCE_STORED; + pci_dev_set_resources(dev); +} + +void vx800_enable_resources(device_t dev) + { + /* vx800 is not a pci bridge and has no resources of its own (other than + standard PC i/o addresses). however it does control the isa bus and so + we need to manually call enable childrens resources on that bus */ + /* TODO: do we even care about ISA? If so, for what? SuperIO on LPC bus */ + pci_dev_enable_resources(dev); + enable_childrens_resources(dev); +} + +static void southbridge_init(struct device *dev) +{ + printk_debug("vx800 sb init\n"); + vx800_sb_init(dev); + pci_routing_fixup(dev); + + setup_i8259(); // make sure interupt controller is configured before keyboard init + + /* turn on keyboard and RTC, no need to visit this reg twice */ + init_pc_keyboard(0x60, 0x64, 0); + printk_debug("ps2 usb lid, you set who can wakeup system from s3 sleep\n"); + S3_ps2_kb_ms_wakeup(dev); + S3_usb_wakeup(dev); + +/* enable acpi cpu c3 state. (c2 state need not do anything.) + #1 + fadt->pm2_cnt_blk = 0x22;//to support cpu-c3 + fadt->p_lvl2_lat = 0x50; //this is the coreboot source + fadt->p_lvl3_lat = 0x320;// + fadt->pm2_cnt_len = 1;//to support cpu-c3 + #2 + ssdt? ->every cpu has a P_BLK address. set it to 0x10 (so that "Read Processor Level3 register(PMIORx15<7:0>) to enter C3 state"---VIA vx800 P SPEC ) + #3 write 0x17 in to PMIO=VX800_ACPI_IO_BASE + 0x26, following the describtion in the P-spec. + 1 enable SLP# asserts in C3 state PMIORx26<1> =1 + 2 enable CPUSTP# asserts in C3 state; PMIORx26<2> =1 + 3 CLKRUN# is always asserted PMIORx26<3> =0 + 4 Disable PCISTP# When CLKRUN# is asserted + 1: PCISTP# will not assert When CLKRUN# is asserted + PMIORx26<4> =1 + 5 This bit controls whether the CPU voltage is lowered when in C3/S1 state. + VRDSLP will be active in either this bit set in C3 or LVL4 register read + PMIORx26<0> =0 + 6 Read Processor Level3 register(PMIORx15<7:0>) to enter C3 state PMIORx15 + */ + outb(0x17, VX800_ACPI_IO_BASE + 0x26); + +} + +static struct device_operations vx800_lpc_ops = { + .read_resources = vx800_read_resources, + .set_resources = vx800_set_resources, + .enable_resources = vx800_enable_resources, + .init = &southbridge_init, + .scan_bus = scan_static_bus, +}; + +static struct pci_driver lpc_driver __pci_driver = { + .ops = &vx800_lpc_ops, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_VX855_LPC, +}; |