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)
198 u32 code = (0 & 0x3);
200 reg32 = pci_read_config32(dev, GEN_CNTL);
201 reg32 |= (1 << 17); /* Enable HPET. */
203 * Bits [16:15] Memory Address Range
204 * 00 FED0_0000h - FED0_03FFh
205 * 01 FED0_1000h - FED0_13FFh
206 * 10 FED0_2000h - FED0_23FFh
207 * 11 FED0_3000h - FED0_33FFh
209 reg32 &= ~(3 << 15); /* Clear it */
210 reg32 |= (code << 15);
211 /* TODO: reg32 is never written to anywhere? */
212 printk_debug("Enabling HPET @0x%x\n", HPET_ADDR | (code << 12));
215 static void i82801gx_lock_smm(struct device *dev)
220 #if ENABLE_ACPI_MODE_IN_COREBOOT
221 printk_debug("Enabling ACPI via APMC:\n");
222 outb(0xe1, 0xb2); // Enable ACPI mode
223 printk_debug("done.\n");
225 printk_debug("Disabling ACPI via APMC:\n");
226 outb(0x1e, 0xb2); // Disable ACPI mode
227 printk_debug("done.\n");
229 /* Don't allow evil boot loaders, kernels, or
230 * userspace applications to deceive us:
234 #if TEST_SMM_FLASH_LOCKDOWN
236 printk_debug("Locking BIOS to RO... ");
237 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
238 printk_debug(" BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
240 reg8 &= ~(1 << 0); /* clear BIOSWE */
241 pci_write_config8(dev, 0xdc, reg8);
242 reg8 |= (1 << 1); /* set BLE */
243 pci_write_config8(dev, 0xdc, reg8);
244 printk_debug("ok.\n");
245 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
246 printk_debug(" BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
249 printk_debug("Writing:\n");
250 *(volatile u8 *)0xfff00000 = 0x00;
251 printk_debug("Testing:\n");
252 reg8 |= (1 << 0); /* set BIOSWE */
253 pci_write_config8(dev, 0xdc, reg8);
255 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
256 printk_debug(" BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
258 printk_debug("Done.\n");
262 static void lpc_init(struct device *dev)
264 printk_debug("i82801gx: lpc_init\n");
266 /* Set the value for PCI command register. */
267 pci_write_config16(dev, PCI_COMMAND, 0x000f);
269 /* IO APIC initialization. */
270 i82801gx_enable_apic(dev);
272 i82801gx_enable_serial_irqs(dev);
274 /* Setup the PIRQ. */
275 i82801gx_pirq_init(dev);
277 /* Setup power options. */
278 i82801gx_power_options(dev);
280 /* Set the state of the GPIO lines. */
283 /* Initialize the real time clock. */
284 i82801gx_rtc_init(dev);
286 /* Initialize ISA DMA. */
289 /* Initialize the High Precision Event Timers, if present. */
294 i82801gx_lock_smm(dev);
297 static void i82801gx_lpc_read_resources(device_t dev)
299 struct resource *res;
301 /* Get the normal PCI resources of this device. */
302 pci_dev_read_resources(dev);
304 /* Add an extra subtractive resource for both memory and I/O. */
305 res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
307 IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
309 res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
311 IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
314 static void i82801gx_lpc_enable_resources(device_t dev)
316 pci_dev_enable_resources(dev);
317 enable_childrens_resources(dev);
320 static void set_subsystem(device_t dev, unsigned vendor, unsigned device)
322 printk_debug("Setting LPC bridge subsystem ID\n");
323 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
324 pci_read_config32(dev, 0));
327 static struct pci_operations pci_ops = {
328 .set_subsystem = set_subsystem,
331 static struct device_operations device_ops = {
332 .read_resources = i82801gx_lpc_read_resources,
333 .set_resources = pci_dev_set_resources,
334 .enable_resources = i82801gx_lpc_enable_resources,
336 .scan_bus = scan_static_bus,
337 .enable = i82801gx_enable,
342 static const struct pci_driver ich7_ich7r_lpc __pci_driver = {
344 .vendor = PCI_VENDOR_ID_INTEL,
349 static const struct pci_driver ich7m_ich7u_lpc __pci_driver = {
351 .vendor = PCI_VENDOR_ID_INTEL,
356 static const struct pci_driver ich7m_dh_lpc __pci_driver = {
358 .vendor = PCI_VENDOR_ID_INTEL,