2 * This file is part of the coreboot project.
4 * Copyright (C) 2008 coresystems GmbH
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <console/console.h>
22 #include <device/device.h>
23 #include <device/pci.h>
24 #include <device/pci_ids.h>
25 #include <pc80/mc146818rtc.h>
26 #include <pc80/isa-dma.h>
30 #include "../../../northbridge/intel/i945/ich7.h"
32 #define MAINBOARD_POWER_OFF 0
33 #define MAINBOARD_POWER_ON 1
35 #ifndef MAINBOARD_POWER_ON_AFTER_FAIL
36 #define MAINBOARD_POWER_ON_AFTER_FAIL MAINBOARD_POWER_ON
41 /* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
42 * 0x00 - 0000 = Reserved
43 * 0x01 - 0001 = Reserved
44 * 0x02 - 0010 = Reserved
50 * 0x08 - 1000 = Reserved
55 * 0x0D - 1101 = Reserved
58 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
59 * 0x80 - The PIRQ is not routed.
71 static void i82801gx_enable_apic(struct device *dev)
75 volatile u32 *ioapic_index = (volatile u32 *)0xfec00000;
76 volatile u32 *ioapic_data = (volatile u32 *)0xfec00010;
78 /* Enable ACPI I/O and power management. */
79 pci_write_config8(dev, ACPI_CNTL, 0x80);
82 *ioapic_data = (1 << 25);
86 printk_debug("Southbridge APIC ID = %x\n", (reg32 >> 24) & 0x0f);
87 if (reg32 != (1 << 25))
90 printk_spew("Dumping IOAPIC registers\n");
93 printk_spew(" reg 0x%04x:", i);
95 printk_spew(" 0x%08x\n", reg32);
98 *ioapic_index = 3; /* Select Boot Configuration register. */
99 *ioapic_data = 1; /* Use Processor System Bus to deliver interrupts. */
102 static void i82801gx_enable_serial_irqs(struct device *dev)
104 /* Set packet length and toggle silent mode bit for one frame. */
105 pci_write_config8(dev, SERIRQ_CNTL,
106 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
109 static void i82801gx_pirq_init(device_t dev)
111 pci_write_config8(dev, PIRQA_ROUT, 0x85);
112 pci_write_config8(dev, PIRQB_ROUT, 0x87);
113 pci_write_config8(dev, PIRQC_ROUT, 0x86);
114 pci_write_config8(dev, PIRQD_ROUT, 0x87);
116 pci_write_config8(dev, PIRQE_ROUT, 0x80);
117 pci_write_config8(dev, PIRQF_ROUT, 0x80);
118 pci_write_config8(dev, PIRQG_ROUT, 0x80);
119 pci_write_config8(dev, PIRQH_ROUT, 0x85);
122 static void i82801gx_power_options(device_t dev)
127 int pwr_on=MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
130 /* Which state do we want to goto after g3 (power restored)?
134 get_option(&pwr_on, "power_on_after_fail");
135 reg8 = pci_read_config8(dev, GEN_PMCON_3);
142 reg8 |= (3 << 4); /* avoid #S4 assertions */
144 pci_write_config8(dev, GEN_PMCON_3, reg8);
145 printk_info("Set power %s after power failure.\n", pwr_on ? "on" : "off");
147 /* Set up NMI on errors. */
149 reg8 &= 0x0f; /* Higher Nibble must be 0 */
150 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
151 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
152 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
156 nmi_option = NMI_OFF;
157 get_option(&nmi_option, "nmi");
159 printk_info ("NMI sources enabled.\n");
160 reg8 &= ~(1 << 7); /* Set NMI. */
162 printk_info ("NMI sources disabled.\n");
163 reg8 |= ( 1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
167 // Enable CPU_SLP# and Intel Speedstep, set SMI# rate down
168 reg16 = pci_read_config16(dev, GEN_PMCON_1);
170 reg16 |= (1 << 3) | (1 << 5) | (1 << 10);
171 pci_write_config16(dev, GEN_PMCON_1, reg16);
173 // Set GPIO13 to SCI (?)
174 // This might be board specific
175 pci_write_config32(dev, 0xb8, 0x08000000);
178 void i82801gx_rtc_init(struct device *dev)
184 reg8 = pci_read_config8(dev, GEN_PMCON_3);
185 rtc_failed = reg8 & RTC_BATTERY_DEAD;
187 reg8 &= ~RTC_BATTERY_DEAD;
188 pci_write_config8(dev, GEN_PMCON_3, reg8);
190 printk_debug("rtc_failed = 0x%x\n", rtc_failed);
192 rtc_init(rtc_failed);
195 static void enable_hpet(struct device *dev)
200 static void i82801gx_lock_smm(struct device *dev)
205 #if ENABLE_ACPI_MODE_IN_COREBOOT
206 printk_debug("Enabling ACPI via APMC:\n");
207 outb(0xe1, 0xb2); // Enable ACPI mode
208 printk_debug("done.\n");
210 printk_debug("Disabling ACPI via APMC:\n");
211 outb(0x1e, 0xb2); // Disable ACPI mode
212 printk_debug("done.\n");
214 /* Don't allow evil boot loaders, kernels, or
215 * userspace applications to deceive us:
219 #if TEST_SMM_FLASH_LOCKDOWN
221 printk_debug("Locking BIOS to RO... ");
222 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
223 printk_debug(" BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
225 reg8 &= ~(1 << 0); /* clear BIOSWE */
226 pci_write_config8(dev, 0xdc, reg8);
227 reg8 |= (1 << 1); /* set BLE */
228 pci_write_config8(dev, 0xdc, reg8);
229 printk_debug("ok.\n");
230 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
231 printk_debug(" BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
234 printk_debug("Writing:\n");
235 *(volatile u8 *)0xfff00000 = 0x00;
236 printk_debug("Testing:\n");
237 reg8 |= (1 << 0); /* set BIOSWE */
238 pci_write_config8(dev, 0xdc, reg8);
240 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
241 printk_debug(" BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
243 printk_debug("Done.\n");
247 static void lpc_init(struct device *dev)
249 printk_debug("i82801gx: lpc_init\n");
251 /* Set the value for PCI command register. */
252 pci_write_config16(dev, PCI_COMMAND, 0x000f);
254 /* IO APIC initialization. */
255 i82801gx_enable_apic(dev);
257 i82801gx_enable_serial_irqs(dev);
259 /* Setup the PIRQ. */
260 i82801gx_pirq_init(dev);
262 /* Setup power options. */
263 i82801gx_power_options(dev);
265 /* Set the state of the GPIO lines. */
268 /* Initialize the real time clock. */
269 i82801gx_rtc_init(dev);
271 /* Initialize ISA DMA. */
274 /* Initialize the High Precision Event Timers, if present. */
279 i82801gx_lock_smm(dev);
282 static void i82801gx_lpc_read_resources(device_t dev)
284 struct resource *res;
286 /* Get the normal PCI resources of this device. */
287 pci_dev_read_resources(dev);
289 /* Add an extra subtractive resource for both memory and I/O. */
290 res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
292 IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
294 res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
296 IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
299 static void i82801gx_lpc_enable_resources(device_t dev)
301 pci_dev_enable_resources(dev);
302 enable_childrens_resources(dev);
305 static void set_subsystem(device_t dev, unsigned vendor, unsigned device)
307 printk_debug("Setting LPC bridge subsystem ID\n");
308 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
309 pci_read_config32(dev, 0));
312 static struct pci_operations pci_ops = {
313 .set_subsystem = set_subsystem,
316 static struct device_operations device_ops = {
317 .read_resources = i82801gx_lpc_read_resources,
318 .set_resources = pci_dev_set_resources,
319 .enable_resources = i82801gx_lpc_enable_resources,
321 .scan_bus = scan_static_bus,
322 .enable = i82801gx_enable,
326 /* 82801GB/GR/GDH (ICH7/ICH7R/ICH7DH) */
327 static const struct pci_driver ich7_ich7r_ich7dh_lpc __pci_driver = {
329 .vendor = PCI_VENDOR_ID_INTEL,
333 /* 82801GBM/GU (ICH7-M/ICH7-U) */
334 static const struct pci_driver ich7m_ich7u_lpc __pci_driver = {
336 .vendor = PCI_VENDOR_ID_INTEL,
340 /* 82801GHM (ICH7-M DH) */
341 static const struct pci_driver ich7m_dh_lpc __pci_driver = {
343 .vendor = PCI_VENDOR_ID_INTEL,