2 * This file is part of the coreboot project.
4 * Copyright (C) 2008-2009 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>
27 #include <pc80/i8259.h>
31 #include "../../../northbridge/intel/i945/ich7.h"
33 #define MAINBOARD_POWER_OFF 0
34 #define MAINBOARD_POWER_ON 1
36 #ifndef MAINBOARD_POWER_ON_AFTER_FAIL
37 #define MAINBOARD_POWER_ON_AFTER_FAIL MAINBOARD_POWER_ON
42 typedef struct southbridge_intel_i82801gx_config config_t;
44 /* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
45 * 0x00 - 0000 = Reserved
46 * 0x01 - 0001 = Reserved
47 * 0x02 - 0010 = Reserved
53 * 0x08 - 1000 = Reserved
58 * 0x0D - 1101 = Reserved
61 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
62 * 0x80 - The PIRQ is not routed.
74 static void i82801gx_enable_apic(struct device *dev)
78 volatile u32 *ioapic_index = (volatile u32 *)0xfec00000;
79 volatile u32 *ioapic_data = (volatile u32 *)0xfec00010;
81 /* Enable ACPI I/O and power management. */
82 pci_write_config8(dev, ACPI_CNTL, 0x80);
85 *ioapic_data = (1 << 25);
89 printk_debug("Southbridge APIC ID = %x\n", (reg32 >> 24) & 0x0f);
90 if (reg32 != (1 << 25))
93 printk_spew("Dumping IOAPIC registers\n");
96 printk_spew(" reg 0x%04x:", i);
98 printk_spew(" 0x%08x\n", reg32);
101 *ioapic_index = 3; /* Select Boot Configuration register. */
102 *ioapic_data = 1; /* Use Processor System Bus to deliver interrupts. */
105 static void i82801gx_enable_serial_irqs(struct device *dev)
107 /* Set packet length and toggle silent mode bit for one frame. */
108 pci_write_config8(dev, SERIRQ_CNTL,
109 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
112 static void i82801gx_pirq_init(device_t dev)
115 /* Get the chip configuration */
116 config_t *config = dev->chip_info;
118 pci_write_config8(dev, PIRQA_ROUT, config->pirqa_routing);
119 pci_write_config8(dev, PIRQB_ROUT, config->pirqb_routing);
120 pci_write_config8(dev, PIRQC_ROUT, config->pirqc_routing);
121 pci_write_config8(dev, PIRQD_ROUT, config->pirqd_routing);
123 pci_write_config8(dev, PIRQE_ROUT, config->pirqe_routing);
124 pci_write_config8(dev, PIRQF_ROUT, config->pirqf_routing);
125 pci_write_config8(dev, PIRQG_ROUT, config->pirqg_routing);
126 pci_write_config8(dev, PIRQH_ROUT, config->pirqh_routing);
128 /* Eric Biederman once said we should let the OS do this.
129 * I am not so sure anymore he was right.
132 for(irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
133 u8 int_pin=0, int_line=0;
135 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
138 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
141 case 1: /* INTA# */ int_line = config->pirqa_routing; break;
142 case 2: /* INTB# */ int_line = config->pirqb_routing; break;
143 case 3: /* INTC# */ int_line = config->pirqc_routing; break;
144 case 4: /* INTD# */ int_line = config->pirqd_routing; break;
150 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line);
154 static void i82801gx_power_options(device_t dev)
159 int pwr_on=MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
162 /* Which state do we want to goto after g3 (power restored)?
166 get_option(&pwr_on, "power_on_after_fail");
167 reg8 = pci_read_config8(dev, GEN_PMCON_3);
174 reg8 |= (3 << 4); /* avoid #S4 assertions */
176 pci_write_config8(dev, GEN_PMCON_3, reg8);
177 printk_info("Set power %s after power failure.\n", pwr_on ? "on" : "off");
179 /* Set up NMI on errors. */
181 reg8 &= 0x0f; /* Higher Nibble must be 0 */
182 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
183 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
184 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
188 nmi_option = NMI_OFF;
189 get_option(&nmi_option, "nmi");
191 printk_info ("NMI sources enabled.\n");
192 reg8 &= ~(1 << 7); /* Set NMI. */
194 printk_info ("NMI sources disabled.\n");
195 reg8 |= ( 1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
199 // Enable CPU_SLP# and Intel Speedstep, set SMI# rate down
200 reg16 = pci_read_config16(dev, GEN_PMCON_1);
202 reg16 |= (1 << 3) | (1 << 5) | (1 << 10);
203 pci_write_config16(dev, GEN_PMCON_1, reg16);
205 // Set GPIO13 to SCI (?)
206 // This might be board specific
207 pci_write_config32(dev, 0xb8, 0x08000000);
210 void i82801gx_rtc_init(struct device *dev)
216 reg8 = pci_read_config8(dev, GEN_PMCON_3);
217 rtc_failed = reg8 & RTC_BATTERY_DEAD;
219 reg8 &= ~RTC_BATTERY_DEAD;
220 pci_write_config8(dev, GEN_PMCON_3, reg8);
222 printk_debug("rtc_failed = 0x%x\n", rtc_failed);
224 rtc_init(rtc_failed);
227 static void enable_hpet(struct device *dev)
234 static void i82801gx_lock_smm(struct device *dev)
239 #if ENABLE_ACPI_MODE_IN_COREBOOT
240 printk_debug("Enabling ACPI via APMC:\n");
241 outb(0xe1, 0xb2); // Enable ACPI mode
242 printk_debug("done.\n");
244 printk_debug("Disabling ACPI via APMC:\n");
245 outb(0x1e, 0xb2); // Disable ACPI mode
246 printk_debug("done.\n");
248 /* Don't allow evil boot loaders, kernels, or
249 * userspace applications to deceive us:
253 #if TEST_SMM_FLASH_LOCKDOWN
255 printk_debug("Locking BIOS to RO... ");
256 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
257 printk_debug(" BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
259 reg8 &= ~(1 << 0); /* clear BIOSWE */
260 pci_write_config8(dev, 0xdc, reg8);
261 reg8 |= (1 << 1); /* set BLE */
262 pci_write_config8(dev, 0xdc, reg8);
263 printk_debug("ok.\n");
264 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
265 printk_debug(" BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
268 printk_debug("Writing:\n");
269 *(volatile u8 *)0xfff00000 = 0x00;
270 printk_debug("Testing:\n");
271 reg8 |= (1 << 0); /* set BIOSWE */
272 pci_write_config8(dev, 0xdc, reg8);
274 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
275 printk_debug(" BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
277 printk_debug("Done.\n");
282 static void lpc_init(struct device *dev)
284 printk_debug("i82801gx: lpc_init\n");
286 /* Set the value for PCI command register. */
287 pci_write_config16(dev, PCI_COMMAND, 0x000f);
289 /* IO APIC initialization. */
290 i82801gx_enable_apic(dev);
292 i82801gx_enable_serial_irqs(dev);
294 /* Setup the PIRQ. */
295 i82801gx_pirq_init(dev);
297 /* Setup power options. */
298 i82801gx_power_options(dev);
300 /* Set the state of the GPIO lines. */
303 /* Initialize the real time clock. */
304 i82801gx_rtc_init(dev);
306 /* Initialize ISA DMA. */
309 /* Initialize the High Precision Event Timers, if present. */
315 i82801gx_lock_smm(dev);
319 static void i82801gx_lpc_read_resources(device_t dev)
321 struct resource *res;
323 /* Get the normal PCI resources of this device. */
324 pci_dev_read_resources(dev);
326 /* Add an extra subtractive resource for both memory and I/O. */
327 res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
329 IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
331 res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
333 IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
336 static void i82801gx_lpc_enable_resources(device_t dev)
338 pci_dev_enable_resources(dev);
339 enable_childrens_resources(dev);
342 static void set_subsystem(device_t dev, unsigned vendor, unsigned device)
344 printk_debug("Setting LPC bridge subsystem ID\n");
345 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
346 pci_read_config32(dev, 0));
349 static struct pci_operations pci_ops = {
350 .set_subsystem = set_subsystem,
353 static struct device_operations device_ops = {
354 .read_resources = i82801gx_lpc_read_resources,
355 .set_resources = pci_dev_set_resources,
356 .enable_resources = i82801gx_lpc_enable_resources,
358 .scan_bus = scan_static_bus,
359 .enable = i82801gx_enable,
363 /* 82801GB/GR (ICH7/ICH7R) */
364 static const struct pci_driver ich7_ich7r_lpc __pci_driver = {
366 .vendor = PCI_VENDOR_ID_INTEL,
370 /* 82801GBM/GU (ICH7-M/ICH7-U) */
371 static const struct pci_driver ich7m_ich7u_lpc __pci_driver = {
373 .vendor = PCI_VENDOR_ID_INTEL,
377 /* 82801GHM (ICH7-M DH) */
378 static const struct pci_driver ich7m_dh_lpc __pci_driver = {
380 .vendor = PCI_VENDOR_ID_INTEL,