diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h index 5a405d1365..ac9435ab8d 100644 --- a/src/include/device/pci_ids.h +++ b/src/include/device/pci_ids.h @@ -1138,6 +1138,21 @@ #define PCI_DEVICE_ID_VIA_8505_1 0x8605 #define PCI_DEVICE_ID_VIA_8633_1 0xB091 #define PCI_DEVICE_ID_VIA_8367_1 0xB099 +#define PCI_DEVICE_ID_VIA_K8T890CE_0 0x0238 +#define PCI_DEVICE_ID_VIA_K8T890CE_1 0x1238 +#define PCI_DEVICE_ID_VIA_K8T890CE_2 0x2238 +#define PCI_DEVICE_ID_VIA_K8T890CE_3 0x3238 +#define PCI_DEVICE_ID_VIA_K8T890CE_4 0x4238 +#define PCI_DEVICE_ID_VIA_K8T890CE_5 0x5238 +#define PCI_DEVICE_ID_VIA_K8T890CE_7 0x7238 +#define PCI_DEVICE_ID_VIA_K8T890CE_PEG 0xa238 +#define PCI_DEVICE_ID_VIA_K8T890CE_PEX0 0xc238 +#define PCI_DEVICE_ID_VIA_K8T890CE_PEX1 0xd238 +#define PCI_DEVICE_ID_VIA_K8T890CE_PEX2 0xe238 +#define PCI_DEVICE_ID_VIA_K8T890CE_PEX3 0xf238 +#define PCI_DEVICE_ID_VIA_K8T890CE_BR 0xb188 +#define PCI_DEVICE_ID_VIA_VT6420_SATA 0x3149 +#define PCI_DEVICE_ID_VIA_VT8237R_LPC 0x3227 #define PCI_VENDOR_ID_SIEMENS 0x110A #define PCI_DEVICE_ID_SIEMENS_DSCC4 0x2102 diff --git a/src/southbridge/via/vt8237r/Config.lb b/src/southbridge/via/vt8237r/Config.lb new file mode 100644 index 0000000000..eccc0a76a9 --- /dev/null +++ b/src/southbridge/via/vt8237r/Config.lb @@ -0,0 +1,26 @@ +## +## This file is part of the LinuxBIOS project. +## +## Copyright (C) 2007 Rudolf Marek +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License v2 as published by +## the Free Software Foundation. +## +## 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 +## + +config chip.h + +driver vt8237r.o +driver vt8237r_ide.o +driver vt8237r_lpc.o +driver vt8237r_sata.o +driver vt8237r_bridge.o diff --git a/src/southbridge/via/vt8237r/chip.h b/src/southbridge/via/vt8237r/chip.h new file mode 100644 index 0000000000..67731f0d42 --- /dev/null +++ b/src/southbridge/via/vt8237r/chip.h @@ -0,0 +1,60 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 Rudolf Marek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * 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 + */ + +#ifndef SOUTHBRIDGE_VIA_VT8237R_CHIP_H +#define SOUTHBRIDGE_VIA_VT8237R_CHIP_H + +#include + +extern struct chip_operations southbridge_via_vt8237r_ops; + +struct southbridge_via_vt8237r_config { + /** + * Function disable. 1 = disabled. + * 7 Dev 17 fn 6 MC97 + * 6 Dev 17 fn 5 AC97 + * 5 Dev 16 fn 1 USB 1.1 UHCI Ports 2-3 + * 4 Dev 16 fn 0 USB 1.1 UHCI Ports 0-1 + * 3 Dev 15 fn 0 Serial ATA + * 2 Dev 16 fn 2 USB 1.1 UHCI Ports 4-5 + * 1 Dev 16 fn 4 USB 2.0 EHCI + * 0 Dev 16 fn 3 USB 1.1 UHCI Ports 6-7 + */ + u16 fn_ctrl_lo; + + /** + * 7 USB Device Mode 1=dis + * 6 Reserved + * 5 Internal LAN Controller Clock Gating 1=gated + * 4 Internal LAN Controller 1=di + * 3 Internal RTC 1=en + * 2 Internal PS2 Mouse 1=en + * 1 Internal KBC Configuration 0=dis ports 0x2e/0x2f off 0xe0-0xef + * 0 Internal Keyboard Controller 1=en + */ + u16 fn_ctrl_hi; + + int ide0_enable:1; + int ide1_enable:1; + /* 1 = 80-pin cable */ + int ide0_80pin_cable:1; + int ide1_80pin_cable:1; +}; + +#endif /* SOUTHBRIDGE_VIA_VT8237R_CHIP_H */ diff --git a/src/southbridge/via/vt8237r/vt8237r.c b/src/southbridge/via/vt8237r/vt8237r.c new file mode 100644 index 0000000000..f810de2c19 --- /dev/null +++ b/src/southbridge/via/vt8237r/vt8237r.c @@ -0,0 +1,89 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 Rudolf Marek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * 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 +#include +#include +#include +#include +#include +#include "chip.h" + +/* + * Datasheet: http://www.via.com.tw/en/downloads/datasheets/chipsets/ + * VT8237R_SouthBridge_Revision2.06_Lead-Free.zip + */ + +void hard_reset(void) +{ + printk_err("NO HARD RESET ON VT8237R! FIX ME!\n"); +} + +#if DEFAULT_CONSOLE_LOGLEVEL > 7 +void writeback(struct device *dev, u16 where, u8 what) +{ + u8 regval; + + pci_write_config8(dev, where, what); + regval = pci_read_config8(dev, where); + + if (regval != what) { + print_debug("Writeback to "); + print_debug_hex8(where); + print_debug("failed "); + print_debug_hex8(regval); + print_debug("\n "); /* TODO: Drop the space? */ + } +} +#else +void writeback(struct device *dev, u16 where, u8 what) +{ + pci_write_config8(dev, where, what); +} +#endif + +void dump_south(device_t dev) +{ + int i, j; + + for (i = 0; i < 256; i += 16) { + printk_debug("%02x: ", i); + for (j = 0; j < 16; j++) { + printk_debug("%02x ", + pci_read_config8(dev, i + j)); + } + printk_debug("\n"); + } +} + +static void vt8237r_enable(struct device *dev) +{ + struct southbridge_via_vt8237r_config *sb = + (struct southbridge_via_vt8237r_config *) dev->chip_info; + + pci_write_config8(dev, 0x50, sb->fn_ctrl_lo); + pci_write_config8(dev, 0x51, sb->fn_ctrl_hi); + + /* TODO: If SATA is disabled, move IDE to fn0 to conform PCI specs. */ +} + +struct chip_operations southbridge_via_vt8237r_ops = { + CHIP_NAME("VIA VT8237R Southbridge") + .enable_dev = vt8237r_enable, +}; diff --git a/src/southbridge/via/vt8237r/vt8237r.h b/src/southbridge/via/vt8237r/vt8237r.h new file mode 100644 index 0000000000..f1a8e6886e --- /dev/null +++ b/src/southbridge/via/vt8237r/vt8237r.h @@ -0,0 +1,33 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 Rudolf Marek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * 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 + */ + +#ifndef SOUTHBRIDGE_VIA_VT8237R_VT8237R_H +#define SOUTHBRIDGE_VIA_VT8237R_VT8237R_H + +/* Static resources for the VT8237R southbridge. */ + +#define VT8237R_APIC_ID 0x2 +#define VT8237R_ACPI_IO_BASE 0x500 +#define VT8237R_SMBUS_IO_BASE 0x400 +/* 0x0 disabled, 0x2 reserved, 0xf = IRQ15 */ +#define VT8237R_ACPI_IRQ 0x9 +#define VT8237R_HPET_ADDR 0xfed00000ULL +#define VT8237R_APIC_BASE 0xfec00000ULL + +#endif diff --git a/src/southbridge/via/vt8237r/vt8237r_bridge.c b/src/southbridge/via/vt8237r/vt8237r_bridge.c new file mode 100644 index 0000000000..6a15ecfda2 --- /dev/null +++ b/src/southbridge/via/vt8237r/vt8237r_bridge.c @@ -0,0 +1,57 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 Rudolf Marek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * 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 +#include +#include +#include +#include + +static void bridge_enable(struct device *dev) +{ + print_debug("B188 device dump\n"); + + /* VIA recommends this, sorry no known info. */ + writeback(dev, 0x40, 0x91); + writeback(dev, 0x41, 0x40); + writeback(dev, 0x43, 0x44); + writeback(dev, 0x44, 0x31); + writeback(dev, 0x45, 0x3a); + writeback(dev, 0x46, 0x88); /* PCI ID lo */ + writeback(dev, 0x47, 0xb1); /* PCI ID hi */ + writeback(dev, 0x3e, 0x16); /* Bridge control */ + + dump_south(dev); +} + +static struct device_operations bridge_ops = { + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .enable = bridge_enable, + .scan_bus = pci_scan_bridge, + .reset_bus = pci_bus_reset, + .ops_pci = 0, +}; + +static struct pci_driver northbridge_driver __pci_driver = { + .ops = &bridge_ops, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_K8T890CE_BR, +}; diff --git a/src/southbridge/via/vt8237r/vt8237r_early_smbus.c b/src/southbridge/via/vt8237r/vt8237r_early_smbus.c new file mode 100644 index 0000000000..4834c5799d --- /dev/null +++ b/src/southbridge/via/vt8237r/vt8237r_early_smbus.c @@ -0,0 +1,168 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 Corey Osgood + * Copyright (C) 2007 Rudolf Marek + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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 +#include "vt8237r.h" + +#define VT8237R_POWER_WELL 0x94 +#define VT8237R_SMBUS_IO_BASE_REG 0xd0 +#define VT8237R_SMBUS_HOST_CONF 0xd2 + +#define SMBHSTSTAT (VT8237R_SMBUS_IO_BASE + 0x0) +#define SMBSLVSTAT (VT8237R_SMBUS_IO_BASE + 0x1) +#define SMBHSTCTL (VT8237R_SMBUS_IO_BASE + 0x2) +#define SMBHSTCMD (VT8237R_SMBUS_IO_BASE + 0x3) +#define SMBXMITADD (VT8237R_SMBUS_IO_BASE + 0x4) +#define SMBHSTDAT0 (VT8237R_SMBUS_IO_BASE + 0x5) + +#define HOST_RESET 0xff +/* 1 in the 0 bit of SMBHSTADD states to READ. */ +#define READ_CMD 0x01 +#define SMBUS_TIMEOUT (100 * 1000 * 10) +#define I2C_TRANS_CMD 0x40 +#define CLOCK_SLAVE_ADDRESS 0x69 + +#if DEBUG_SMBUS == 1 +#define PRINT_DEBUG(x) print_debug(x) +#define PRINT_DEBUG_HEX16(x) print_debug_hex16(x) +#else +#define PRINT_DEBUG(x) +#define PRINT_DEBUG_HEX16(x) +#endif + +#define SMBUS_DELAY() inb(0x80) + +static void smbus_print_error(u8 host_status, int loops) +{ + /* Check if there actually was an error. */ + if (host_status == 0x00 || host_status == 0x40 || + host_status == 0x42) + return; + + if (loops >= SMBUS_TIMEOUT) + print_err("SMBus timeout\r\n"); + if (host_status & (1 << 4)) + print_err("Interrupt/SMI# was Failed Bus Transaction\r\n"); + if (host_status & (1 << 3)) + print_err("Bus error\r\n"); + if (host_status & (1 << 2)) + print_err("Device error\r\n"); + if (host_status & (1 << 1)) + print_err("Interrupt/SMI# was Successful Completion\r\n"); + if (host_status & (1 << 0)) + print_err("Host busy\r\n"); +} + +static void smbus_wait_until_ready(void) +{ + int loops; + + PRINT_DEBUG("Waiting until SMBus ready\r\n"); + + loops = 0; + /* Yes, this is a mess, but it's the easiest way to do it. */ + while ((inb(SMBHSTSTAT) & 1) == 1 && loops <= SMBUS_TIMEOUT) + ++loops; + smbus_print_error(inb(SMBHSTSTAT), loops); +} + +static void smbus_reset(void) +{ + outb(HOST_RESET, SMBHSTSTAT); + /* Datasheet says we have to read it to take ownership of SMBus. */ + inb(SMBHSTSTAT); + + PRINT_DEBUG("After reset status: "); + PRINT_DEBUG_HEX16(inb(SMBHSTSTAT)); + PRINT_DEBUG("\r\n"); +} + +u8 smbus_read_byte(u32 dimm, u32 offset) +{ + u32 val; + + PRINT_DEBUG("DIMM "); + PRINT_DEBUG_HEX16(dimm); + PRINT_DEBUG(" OFFSET "); + PRINT_DEBUG_HEX16(offset); + PRINT_DEBUG("\r\n"); + + smbus_reset(); + /* Clear host data port. */ + outb(0x00, SMBHSTDAT0); + SMBUS_DELAY(); + smbus_wait_until_ready(); + + /* Actual addr to reg format. */ + dimm = (dimm << 1); + dimm |= 1; + outb(dimm, SMBXMITADD); + outb(offset, SMBHSTCMD); + /* Start transaction, byte data read. */ + outb(0x48, SMBHSTCTL); + + SMBUS_DELAY(); + + smbus_wait_until_ready(); + + val = inb(SMBHSTDAT0); + PRINT_DEBUG("Read: "); + PRINT_DEBUG_HEX16(val); + PRINT_DEBUG("\r\n"); + + /* Probably don't have to do this, but it can't hurt. */ + smbus_reset(); + + /* Can I just "return inb(SMBHSTDAT0)"? */ + return val; +} + +void enable_smbus(void) +{ + device_t dev; + + /* Power management controller */ + dev = pci_locate_device(PCI_ID(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VT8237R_LPC), 0); + + if (dev == PCI_DEV_INVALID) + die("Power Management Controller not found\r\n"); + + /* 7 = SMBus Clock from RTC 32.768KHz + * 5 = Internal PLL reset from susp + */ + pci_write_config8(dev, VT8237R_POWER_WELL, 0xa0); + + /* Enable SMBus */ + pci_write_config16(dev, VT8237R_SMBUS_IO_BASE_REG, + VT8237R_SMBUS_IO_BASE | 0x1); + + /* SMBus Host Configuration, enable */ + pci_write_config8(dev, VT8237R_SMBUS_HOST_CONF, 0x01); + + /* Make it work for I/O. */ + pci_write_config16(dev, PCI_COMMAND, PCI_COMMAND_IO); + + smbus_reset(); + + /* Reset the internal pointer. */ + inb(SMBHSTCTL); +} diff --git a/src/southbridge/via/vt8237r/vt8237r_ide.c b/src/southbridge/via/vt8237r/vt8237r_ide.c new file mode 100644 index 0000000000..39b735831c --- /dev/null +++ b/src/southbridge/via/vt8237r/vt8237r_ide.c @@ -0,0 +1,116 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 Rudolf Marek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * 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 + */ + +/* Based on other VIA SB code. */ + +#include +#include +#include +#include +#include +#include "vt8237r.h" +#include "chip.h" + +#define IDE_CS 0x40 +#define IDE_CONF_I 0x41 +#define IDE_CONF_II 0x42 +#define IDE_CONF_FIFO 0x43 +#define IDE_MISC_I 0x44 +#define IDE_MISC_II 0x45 +#define IDE_UDMA 0x50 + +/** + * No native mode. Interrupts from unconnected HDDs might occur if + * IRQ14/15 is used for PCI. Therefore no native mode support. + */ +static void ide_init(struct device *dev) +{ + struct southbridge_via_vt8237r_config *sb = + (struct southbridge_via_vt8237r_config *) dev->chip_info; + + u8 enables; + u32 cablesel; + + printk_info("%s IDE interface %s\n", "Primary", + sb->ide0_enable ? "enabled" : "disabled"); + printk_info("%s IDE interface %s\n", "Secondary", + sb->ide1_enable ? "enabled" : "disabled"); + enables = pci_read_config8(dev, IDE_CS) & ~0x3; + enables |= (sb->ide0_enable << 1) | sb->ide1_enable; + pci_write_config8(dev, IDE_CS, enables); + enables = pci_read_config8(dev, IDE_CS); + printk_debug("Enables in reg 0x40 read back as 0x%x\n", enables); + + /* Enable only compatibility mode. */ + enables = pci_read_config8(dev, IDE_CONF_II); + enables &= ~0xc0; + pci_write_config8(dev,IDE_CONF_II, enables); + enables = pci_read_config8(dev, IDE_CONF_II); + printk_debug("Enables in reg 0x42 read back as 0x%x\n", enables); + + /* Enable prefetch buffers. */ + enables = pci_read_config8(dev, IDE_CONF_I); + enables |= 0xf0; + pci_write_config8(dev, IDE_CONF_I, enables); + + /* Flush FIFOs at half. */ + enables = pci_read_config8(dev, IDE_CONF_FIFO); + enables &= 0xf0; + enables |= (1 << 2) | (1 << 0); + pci_write_config8(dev, IDE_CONF_FIFO, enables); + + /* PIO read prefetch counter, Bus Master IDE Status Reg. Read Retry. */ + enables = pci_read_config8(dev, IDE_MISC_I); + enables &= 0xe2; + enables |= (1 << 4) | (1 << 3); + pci_write_config8(dev, IDE_MISC_I, enables); + + /* Use memory read multiple, Memory-Write-and-Invalidate. */ + enables = pci_read_config8(dev, IDE_MISC_II); + enables |= (1 << 2) | (1 << 3); + pci_write_config8(dev, IDE_MISC_II, enables); + + /* Force interrupts to use compat mode. */ + pci_write_config8(dev, PCI_INTERRUPT_PIN, 0x0); + pci_write_config8(dev, PCI_INTERRUPT_LINE, 0xff); + + /* Cable guy... */ + cablesel = pci_read_config32(dev, IDE_UDMA); + cablesel &= ~((1 << 28) | (1 << 20) | (1 <<12) | (1 << 4)); + cablesel |= (sb->ide0_80pin_cable << 28) | + (sb->ide0_80pin_cable << 20) | + (sb->ide1_80pin_cable << 12) | + (sb->ide1_80pin_cable << 4); + pci_write_config32(dev, IDE_UDMA, cablesel); +} + +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, + .enable = 0, + .ops_pci = 0, +}; + +static struct pci_driver northbridge_driver __pci_driver = { + .ops = &ide_ops, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_82C586_1, +}; diff --git a/src/southbridge/via/vt8237r/vt8237r_lpc.c b/src/southbridge/via/vt8237r/vt8237r_lpc.c new file mode 100644 index 0000000000..cd4464b6da --- /dev/null +++ b/src/southbridge/via/vt8237r/vt8237r_lpc.c @@ -0,0 +1,350 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 Rudolf Marek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * 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 + */ + +/* Inspiration from other VIA SB code. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vt8237r.h" +#include "chip.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) + +extern void dump_south(device_t dev); + +struct ioapicreg { + u32 reg; + u32 value_low; + u32 value_high; +} ioapic_table[] = { + /* IO-APIC virtual wire mode configuration. */ + /* mask, trigger, polarity, destination, delivery, vector */ + {0, ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | + ExtINT, NONE}, + {1, DISABLED, NONE}, + {2, DISABLED, NONE}, + {3, DISABLED, NONE}, + {4, DISABLED, NONE}, + {5, DISABLED, NONE}, + {6, DISABLED, NONE}, + {7, DISABLED, NONE}, + {8, DISABLED, NONE}, + {9, DISABLED, NONE}, + {10, DISABLED, NONE}, + {11, DISABLED, NONE}, + {12, DISABLED, NONE}, + {13, DISABLED, NONE}, + {14, DISABLED, NONE}, + {15, DISABLED, NONE}, + {16, DISABLED, NONE}, + {17, DISABLED, NONE}, + {18, DISABLED, NONE}, + {19, DISABLED, NONE}, + {20, DISABLED, NONE}, + {21, DISABLED, NONE}, + {22, DISABLED, NONE}, + {23, DISABLED, NONE}, +}; + +static void setup_ioapic(u32 ioapic_base) +{ + u32 value_low, value_high, val; + volatile u32 *l; + int i; + + /* All delivered to CPU0. */ + ioapic_table[0].value_high = (lapicid()) << (56 - 32); + l = (unsigned long *) ioapic_base; + + /* Set APIC to FSB message bus. */ + l[0] = 0x3; + val = l[4]; + l[4] = (val & 0xFFFFFE) | 1; + + /* Set APIC ADDR - this will be VT8237R_APIC_ID. */ + l[0] = 0; + val = l[4]; + l[4] = (val & 0xF0FFFF) | (VT8237R_APIC_ID << 24); + + for (i = 0; i < ARRAY_SIZE(ioapic_table); i++) { + l[0] = (ioapic_table[i].reg * 2) + 0x10; + l[4] = ioapic_table[i].value_low; + value_low = l[4]; + l[0] = (ioapic_table[i].reg * 2) + 0x11; + l[4] = ioapic_table[i].value_high; + value_high = l[4]; + + if ((i == 0) && (value_low == 0xffffffff)) { + printk_warning("IO APIC not responding.\n"); + return; + } + } +} + +/** Set up PCI IRQ routing, route everything through APIC. */ +static void pci_routing_fixup(struct device *dev) +{ + /* PCI PNP Interrupt Routing INTE/F - disable */ + pci_write_config8(dev, 0x44, 0x00); + + /* PCI PNP Interrupt Routing INTG/H - disable */ + pci_write_config8(dev, 0x45, 0x00); + + /* Route INTE-INTH through registers above, no map to INTA-INTD. */ + pci_write_config8(dev, 0x46, 0x10); + + /* PCI Interrupt Polarity */ + pci_write_config8(dev, 0x54, 0x00); + + /* PCI INTA# Routing */ + pci_write_config8(dev, 0x55, 0x00); + + /* PCI INTB#/C# Routing */ + pci_write_config8(dev, 0x56, 0x00); + + /* PCI INTD# Routing */ + pci_write_config8(dev, 0x57, 0x00); +} + +/** + * Set up the power management capabilities directly into ACPI mode. + * This avoids having to handle any System Management Interrupts (SMIs). + */ +void setup_pm(device_t dev) +{ + /* Debounce LID and PWRBTN# Inputs for 16ms. */ + pci_write_config8(dev, 0x80, 0x20); + + /* Set ACPI base address to I/O VT8237R_ACPI_IO_BASE. */ + pci_write_config16(dev, 0x88, VT8237R_ACPI_IO_BASE | 0x1); + + /* Set ACPI to 9, must set IRQ 9 override to level! Set PSON gating. */ + pci_write_config8(dev, 0x82, 0x40 | VT8237R_ACPI_IRQ); + + /* Primary interupt channel, define wake events 0=IRQ0 15=IRQ15 1=en. */ + pci_write_config16(dev, 0x84, 0x30b2); + + /* 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); + + /* 7 = SMBus clock from RTC 32.768KHz + * 5 = Internal PLL reset from susp + * 2 = GPO2 is GPIO + */ + pci_write_config8(dev, 0x94, 0xa4); + + /* 7 = stp to sust delay 1msec + * 6 = SUSST# Deasserted Before PWRGD for STD + * 3 = GPO26/GPO27 is GPO + * 2 = Disable Alert on Lan + */ + pci_write_config8(dev, 0x95, 0xcc); + + /* Disable GP3 timer. */ + pci_write_config8(dev, 0x98, 0); + + /* Enable SATA LED, disable special CPU Frequency Change - + * GPIO28 GPIO22 GPIO29 GPIO23 are GPIOs. + */ + pci_write_config8(dev, 0xe5, 0x9); + + /* REQ5 as PCI request input - should be together with INTE-INTH. */ + pci_write_config8(dev, 0xe4, 0x4); + + /* Enable ACPI accessm RTC signal gated with PSON. */ + pci_write_config8(dev, 0x81, 0x84); + + /* Clear status events. */ + outw(0xffff, VT8237R_ACPI_IO_BASE + 0x00); + outw(0xffff, VT8237R_ACPI_IO_BASE + 0x20); + outw(0xffff, VT8237R_ACPI_IO_BASE + 0x28); + outl(0xffffffff, VT8237R_ACPI_IO_BASE + 0x30); + + /* Disable SCI on GPIO. */ + outw(0x0, VT8237R_ACPI_IO_BASE + 0x22); + + /* Disable SMI on GPIO. */ + outw(0x0, VT8237R_ACPI_IO_BASE + 0x24); + + /* Disable all global enable SMIs. */ + outw(0x0, VT8237R_ACPI_IO_BASE + 0x2a); + + /* All SMI off, both IDE buses ON, PSON rising edge. */ + outw(0x0, VT8237R_ACPI_IO_BASE + 0x2c); + + /* Primary activity SMI disable. */ + outl(0x0, VT8237R_ACPI_IO_BASE + 0x34); + + /* GP timer reload on none. */ + outl(0x0, VT8237R_ACPI_IO_BASE + 0x38); + + /* Disable extended IO traps. */ + outb(0x0, VT8237R_ACPI_IO_BASE + 0x42); + + /* SCI is generated for RTC/pwrBtn/slpBtn. */ + outw(0x001, VT8237R_ACPI_IO_BASE + 0x04); +} + +static void vt8237r_init(struct device *dev) +{ + u8 enables, byte; + + /* Enable addr/data stepping. */ + byte = pci_read_config8(dev, PCI_COMMAND); + byte |= PCI_COMMAND_WAIT; + pci_write_config8(dev, PCI_COMMAND, byte); + + /* Enable the internal I/O decode. */ + enables = pci_read_config8(dev, 0x6C); + enables |= 0x80; + pci_write_config8(dev, 0x6C, enables); + + /* FIXME: Map 4MB of flash into the address space, + * this should be in CAR call. + */ + /* pci_write_config8(dev, 0x41, 0x7f); */ + + /* Set bit 6 of 0x40 (I/O recovery time). + * IMPORTANT FIX - EISA = ECLR reg at 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); + + /* Line buffer control */ + enables = pci_read_config8(dev, 0x42); + enables |= 0xf8; + pci_write_config8(dev, 0x42, enables); + + /* Delay transaction control */ + pci_write_config8(dev, 0x43, 0xb); + + /* I/O recovery time */ + pci_write_config8(dev, 0x4c, 0x44); + + /* ROM memory cycles go to LPC. */ + pci_write_config8(dev, 0x59, 0x80); + + /* Bypass APIC De-Assert Message, INTE#, INTF#, INTG#, INTH# as PCI. */ + pci_write_config8(dev, 0x5B, 0xb); + + /* Set Read Pass Write Control Enable (force A2 from APIC FSB to low). */ + pci_write_config8(dev, 0x48, 0x8c); + + /* Set 0x58 to 0x43 APIC and RTC. */ + pci_write_config8(dev, 0x58, 0x43); + + /* Set bit 3 of 0x4f (use INIT# as CPU reset). */ + enables = pci_read_config8(dev, 0x4f); + enables |= 0x08; + pci_write_config8(dev, 0x4f, enables); + + /* Enable serial IRQ, 6PCI clocks. */ + pci_write_config8(dev, 0x52, 0x9); + + /* Enable HPET at VT8237R_HPET_ADDR. */ + pci_write_config32(dev, 0x68, (VT8237R_HPET_ADDR | 0x80)); + + /* Power management setup */ + setup_pm(dev); + + /* Start the RTC. */ + rtc_init(0); +} + +void vt8237r_read_resources(device_t dev) +{ + struct resource *res; + + pci_dev_read_resources(dev); + /* Fixed APIC resource */ + res = new_resource(dev, 0x44); + res->base = VT8237R_APIC_BASE; + 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; +} + +/** + * The VT8237R 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. + */ +void vt8237r_enable_resources(device_t dev) +{ + pci_dev_enable_resources(dev); + enable_childrens_resources(dev); +} + +static void init_keyboard(struct device *dev) +{ + u8 regval = pci_read_config8(dev, 0x51); + if (regval & 0x1) + init_pc_keyboard(0x60, 0x64, 0); +} + +static void southbridge_init(struct device *dev) +{ + vt8237r_init(dev); + pci_routing_fixup(dev); + setup_ioapic(VT8237R_APIC_BASE); + setup_i8259(); + init_keyboard(dev); +} + +static struct device_operations vt8237r_lpc_ops = { + .read_resources = vt8237r_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = vt8237r_enable_resources, + .init = &southbridge_init, + .scan_bus = scan_static_bus, +}; + +static struct pci_driver lpc_driver __pci_driver = { + .ops = &vt8237r_lpc_ops, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_VT8237R_LPC, +}; diff --git a/src/southbridge/via/vt8237r/vt8237r_sata.c b/src/southbridge/via/vt8237r/vt8237r_sata.c new file mode 100644 index 0000000000..fb54b5ca39 --- /dev/null +++ b/src/southbridge/via/vt8237r/vt8237r_sata.c @@ -0,0 +1,58 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 Rudolf Marek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * 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 +#include +#include +#include +#include + +#define SATA_MISC_CTRL 0x45 + +static void sata_init(struct device *dev) +{ + u8 reg; + + printk_debug("Configuring VIA SATA controller\n"); + + /* Class IDE Disk */ + reg = pci_read_config8(dev, SATA_MISC_CTRL); + reg &= 0x7f; /* Sub Class Write Protect off */ + pci_write_config8(dev, SATA_MISC_CTRL, reg); + + /* Change the device class to SATA from RAID. */ + pci_write_config8(dev, PCI_CLASS_DEVICE, 0x1); + reg |= 0x80; /* Sub Class Write Protect on */ + pci_write_config8(dev, SATA_MISC_CTRL, reg); +} + +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, + .enable = 0, + .ops_pci = 0, +}; + +static struct pci_driver northbridge_driver __pci_driver = { + .ops = &sata_ops, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_VT6420_SATA, +};