2008-10-29 05:46:52 +01:00
|
|
|
/*
|
|
|
|
* This file is part of the coreboot project.
|
|
|
|
*
|
2009-01-20 23:53:10 +01:00
|
|
|
* Copyright (C) 2008-2009 coresystems GmbH
|
2008-10-29 05:46:52 +01:00
|
|
|
*
|
2009-03-11 15:54:18 +01:00
|
|
|
* 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.
|
2008-10-29 05:46:52 +01:00
|
|
|
*
|
|
|
|
* 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 <console/console.h>
|
|
|
|
#include <device/device.h>
|
|
|
|
#include <device/pci.h>
|
|
|
|
#include <device/pci_ids.h>
|
|
|
|
#include <pc80/mc146818rtc.h>
|
|
|
|
#include <pc80/isa-dma.h>
|
2009-01-20 23:53:10 +01:00
|
|
|
#include <pc80/i8259.h>
|
2008-10-29 05:46:52 +01:00
|
|
|
#include <arch/io.h>
|
|
|
|
#include "i82801gx.h"
|
|
|
|
|
|
|
|
#include "../../../northbridge/intel/i945/ich7.h"
|
|
|
|
|
|
|
|
#define MAINBOARD_POWER_OFF 0
|
|
|
|
#define MAINBOARD_POWER_ON 1
|
|
|
|
|
|
|
|
#ifndef MAINBOARD_POWER_ON_AFTER_FAIL
|
|
|
|
#define MAINBOARD_POWER_ON_AFTER_FAIL MAINBOARD_POWER_ON
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define NMI_OFF 0
|
|
|
|
|
2009-01-20 23:53:10 +01:00
|
|
|
typedef struct southbridge_intel_i82801gx_config config_t;
|
|
|
|
|
2008-10-29 05:46:52 +01:00
|
|
|
/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
|
|
|
|
* 0x00 - 0000 = Reserved
|
|
|
|
* 0x01 - 0001 = Reserved
|
|
|
|
* 0x02 - 0010 = Reserved
|
|
|
|
* 0x03 - 0011 = IRQ3
|
|
|
|
* 0x04 - 0100 = IRQ4
|
|
|
|
* 0x05 - 0101 = IRQ5
|
|
|
|
* 0x06 - 0110 = IRQ6
|
|
|
|
* 0x07 - 0111 = IRQ7
|
|
|
|
* 0x08 - 1000 = Reserved
|
|
|
|
* 0x09 - 1001 = IRQ9
|
|
|
|
* 0x0A - 1010 = IRQ10
|
|
|
|
* 0x0B - 1011 = IRQ11
|
|
|
|
* 0x0C - 1100 = IRQ12
|
|
|
|
* 0x0D - 1101 = Reserved
|
|
|
|
* 0x0E - 1110 = IRQ14
|
|
|
|
* 0x0F - 1111 = IRQ15
|
|
|
|
* PIRQ[n]_ROUT[7] - PIRQ Routing Control
|
|
|
|
* 0x80 - The PIRQ is not routed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define PIRQA 0x03
|
|
|
|
#define PIRQB 0x05
|
|
|
|
#define PIRQC 0x06
|
|
|
|
#define PIRQD 0x07
|
|
|
|
#define PIRQE 0x09
|
|
|
|
#define PIRQF 0x0A
|
|
|
|
#define PIRQG 0x0B
|
|
|
|
#define PIRQH 0x0C
|
|
|
|
|
|
|
|
static void i82801gx_enable_apic(struct device *dev)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
u32 reg32;
|
|
|
|
volatile u32 *ioapic_index = (volatile u32 *)0xfec00000;
|
|
|
|
volatile u32 *ioapic_data = (volatile u32 *)0xfec00010;
|
|
|
|
|
|
|
|
/* Enable ACPI I/O and power management. */
|
|
|
|
pci_write_config8(dev, ACPI_CNTL, 0x80);
|
|
|
|
|
|
|
|
*ioapic_index = 0;
|
|
|
|
*ioapic_data = (1 << 25);
|
|
|
|
|
|
|
|
*ioapic_index = 0;
|
|
|
|
reg32 = *ioapic_data;
|
|
|
|
printk_debug("Southbridge APIC ID = %x\n", (reg32 >> 24) & 0x0f);
|
|
|
|
if (reg32 != (1 << 25))
|
|
|
|
die("APIC Error\n");
|
|
|
|
|
|
|
|
printk_spew("Dumping IOAPIC registers\n");
|
|
|
|
for (i=0; i<3; i++) {
|
|
|
|
*ioapic_index = i;
|
|
|
|
printk_spew(" reg 0x%04x:", i);
|
|
|
|
reg32 = *ioapic_data;
|
|
|
|
printk_spew(" 0x%08x\n", reg32);
|
|
|
|
}
|
|
|
|
|
|
|
|
*ioapic_index = 3; /* Select Boot Configuration register. */
|
|
|
|
*ioapic_data = 1; /* Use Processor System Bus to deliver interrupts. */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i82801gx_enable_serial_irqs(struct device *dev)
|
|
|
|
{
|
|
|
|
/* Set packet length and toggle silent mode bit for one frame. */
|
|
|
|
pci_write_config8(dev, SERIRQ_CNTL,
|
|
|
|
(1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i82801gx_pirq_init(device_t dev)
|
|
|
|
{
|
2009-01-20 23:53:10 +01:00
|
|
|
device_t irq_dev;
|
|
|
|
/* Get the chip configuration */
|
|
|
|
config_t *config = dev->chip_info;
|
|
|
|
|
|
|
|
pci_write_config8(dev, PIRQA_ROUT, config->pirqa_routing);
|
|
|
|
pci_write_config8(dev, PIRQB_ROUT, config->pirqb_routing);
|
|
|
|
pci_write_config8(dev, PIRQC_ROUT, config->pirqc_routing);
|
|
|
|
pci_write_config8(dev, PIRQD_ROUT, config->pirqd_routing);
|
|
|
|
|
|
|
|
pci_write_config8(dev, PIRQE_ROUT, config->pirqe_routing);
|
|
|
|
pci_write_config8(dev, PIRQF_ROUT, config->pirqf_routing);
|
|
|
|
pci_write_config8(dev, PIRQG_ROUT, config->pirqg_routing);
|
|
|
|
pci_write_config8(dev, PIRQH_ROUT, config->pirqh_routing);
|
|
|
|
|
|
|
|
/* Eric Biederman once said we should let the OS do this.
|
|
|
|
* I am not so sure anymore he was right.
|
|
|
|
*/
|
|
|
|
|
|
|
|
for(irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
|
|
|
|
u8 int_pin=0, int_line=0;
|
|
|
|
|
|
|
|
if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
|
|
|
|
|
|
|
|
switch (int_pin) {
|
|
|
|
case 1: /* INTA# */ int_line = config->pirqa_routing; break;
|
|
|
|
case 2: /* INTB# */ int_line = config->pirqb_routing; break;
|
|
|
|
case 3: /* INTC# */ int_line = config->pirqc_routing; break;
|
|
|
|
case 4: /* INTD# */ int_line = config->pirqd_routing; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!int_line)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line);
|
|
|
|
}
|
2008-10-29 05:46:52 +01:00
|
|
|
}
|
|
|
|
|
2009-03-11 15:54:18 +01:00
|
|
|
static void i82801gx_gpi_routing(device_t dev)
|
|
|
|
{
|
|
|
|
/* Get the chip configuration */
|
|
|
|
config_t *config = dev->chip_info;
|
|
|
|
u32 reg32 = 0;
|
|
|
|
|
|
|
|
/* An array would be much nicer here, or some
|
|
|
|
* other method of doing this.
|
|
|
|
*/
|
|
|
|
reg32 |= (config->gpi0_routing & 0x03) << 0;
|
|
|
|
reg32 |= (config->gpi1_routing & 0x03) << 2;
|
|
|
|
reg32 |= (config->gpi2_routing & 0x03) << 4;
|
|
|
|
reg32 |= (config->gpi3_routing & 0x03) << 6;
|
|
|
|
reg32 |= (config->gpi4_routing & 0x03) << 8;
|
|
|
|
reg32 |= (config->gpi5_routing & 0x03) << 10;
|
|
|
|
reg32 |= (config->gpi6_routing & 0x03) << 12;
|
|
|
|
reg32 |= (config->gpi7_routing & 0x03) << 14;
|
|
|
|
reg32 |= (config->gpi8_routing & 0x03) << 16;
|
|
|
|
reg32 |= (config->gpi9_routing & 0x03) << 18;
|
|
|
|
reg32 |= (config->gpi10_routing & 0x03) << 20;
|
|
|
|
reg32 |= (config->gpi11_routing & 0x03) << 22;
|
|
|
|
reg32 |= (config->gpi12_routing & 0x03) << 24;
|
|
|
|
reg32 |= (config->gpi13_routing & 0x03) << 26;
|
|
|
|
reg32 |= (config->gpi14_routing & 0x03) << 28;
|
|
|
|
reg32 |= (config->gpi15_routing & 0x03) << 30;
|
|
|
|
|
|
|
|
pci_write_config32(dev, 0xb8, reg32);
|
|
|
|
}
|
|
|
|
|
2008-10-29 05:46:52 +01:00
|
|
|
static void i82801gx_power_options(device_t dev)
|
|
|
|
{
|
|
|
|
u8 reg8;
|
|
|
|
u16 reg16;
|
|
|
|
|
CMOS: Add set_option and rework get_option.
To ease some of my debugging pain on the unichrome, i decided i needed to
move FB size selection into cmos, so i could test a size and then reset it
to the default after loading this value so that the next reboot uses the
(working) default again. This meant implementing set_option in parallel to
get_option.
get_option was then found to have inversed argument ordering (like outb) and
passing char * and then depending on the cmos layout length, which made me
feel quite uncomfortable. Since we either have reserved space (which we
shouldn't do anything with in these two functions), an enum or a
hexadecimal value, unsigned int seemed like the way to go. So all users of
get_option now have their arguments inversed and switched from using ints
to unsigned ints now.
The way get_cmos_value was implemented forced us to not overlap byte and to
have multibyte values be byte aligned. This logic is now adapted to do a
full uint32_t read (when needed) at any offset and any length up to 32, and
the shifting all happens inside an uint32_t as well. set_cmos_value was
implemented similarly. Both routines have been extensively tested in a
quick separate little program as it is not easy to get this stuff right.
build_opt_tbl.c was altered to function correctly within these new
parameters. The enum value retrieval has been changed strol(..., NULL, 10)
to stroul(..., NULL, 0), so that we not only are able to use unsigned ints
now but so that we also interprete hex values correctly. The 32bit limit
gets imposed on all entries not marked reserved, an unused "user_data" field
that appeared in a lot of cmos.layouts has been changed to reserved as well.
Signed-off-by: Luc Verhaegen <libv@skynet.be>
Acked-by: Peter Stuge <peter@stuge.se>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4332 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
2009-06-03 12:47:19 +02:00
|
|
|
uint32_t pwr_on=MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
|
|
|
|
uint32_t nmi_option;
|
2008-10-29 05:46:52 +01:00
|
|
|
|
|
|
|
/* Which state do we want to goto after g3 (power restored)?
|
|
|
|
* 0 == S0 Full On
|
|
|
|
* 1 == S5 Soft Off
|
|
|
|
*/
|
CMOS: Add set_option and rework get_option.
To ease some of my debugging pain on the unichrome, i decided i needed to
move FB size selection into cmos, so i could test a size and then reset it
to the default after loading this value so that the next reboot uses the
(working) default again. This meant implementing set_option in parallel to
get_option.
get_option was then found to have inversed argument ordering (like outb) and
passing char * and then depending on the cmos layout length, which made me
feel quite uncomfortable. Since we either have reserved space (which we
shouldn't do anything with in these two functions), an enum or a
hexadecimal value, unsigned int seemed like the way to go. So all users of
get_option now have their arguments inversed and switched from using ints
to unsigned ints now.
The way get_cmos_value was implemented forced us to not overlap byte and to
have multibyte values be byte aligned. This logic is now adapted to do a
full uint32_t read (when needed) at any offset and any length up to 32, and
the shifting all happens inside an uint32_t as well. set_cmos_value was
implemented similarly. Both routines have been extensively tested in a
quick separate little program as it is not easy to get this stuff right.
build_opt_tbl.c was altered to function correctly within these new
parameters. The enum value retrieval has been changed strol(..., NULL, 10)
to stroul(..., NULL, 0), so that we not only are able to use unsigned ints
now but so that we also interprete hex values correctly. The 32bit limit
gets imposed on all entries not marked reserved, an unused "user_data" field
that appeared in a lot of cmos.layouts has been changed to reserved as well.
Signed-off-by: Luc Verhaegen <libv@skynet.be>
Acked-by: Peter Stuge <peter@stuge.se>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4332 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
2009-06-03 12:47:19 +02:00
|
|
|
get_option("power_on_after_fail", &pwr_on);
|
2008-10-29 05:46:52 +01:00
|
|
|
reg8 = pci_read_config8(dev, GEN_PMCON_3);
|
|
|
|
reg8 &= 0xfe;
|
|
|
|
if (pwr_on) {
|
|
|
|
reg8 &= ~1;
|
|
|
|
} else {
|
|
|
|
reg8 |= 1;
|
|
|
|
}
|
|
|
|
reg8 |= (3 << 4); /* avoid #S4 assertions */
|
2009-03-11 15:54:18 +01:00
|
|
|
reg8 &= ~(1 << 3); /* minimum asssertion is 1 to 2 RTCCLK */
|
2008-10-29 05:46:52 +01:00
|
|
|
|
|
|
|
pci_write_config8(dev, GEN_PMCON_3, reg8);
|
|
|
|
printk_info("Set power %s after power failure.\n", pwr_on ? "on" : "off");
|
|
|
|
|
|
|
|
/* Set up NMI on errors. */
|
|
|
|
reg8 = inb(0x61);
|
|
|
|
reg8 &= 0x0f; /* Higher Nibble must be 0 */
|
|
|
|
reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
|
|
|
|
// reg8 &= ~(1 << 2); /* PCI SERR# Enable */
|
|
|
|
reg8 |= (1 << 2); /* PCI SERR# Disable for now */
|
|
|
|
outb(reg8, 0x61);
|
|
|
|
|
|
|
|
reg8 = inb(0x70);
|
|
|
|
nmi_option = NMI_OFF;
|
CMOS: Add set_option and rework get_option.
To ease some of my debugging pain on the unichrome, i decided i needed to
move FB size selection into cmos, so i could test a size and then reset it
to the default after loading this value so that the next reboot uses the
(working) default again. This meant implementing set_option in parallel to
get_option.
get_option was then found to have inversed argument ordering (like outb) and
passing char * and then depending on the cmos layout length, which made me
feel quite uncomfortable. Since we either have reserved space (which we
shouldn't do anything with in these two functions), an enum or a
hexadecimal value, unsigned int seemed like the way to go. So all users of
get_option now have their arguments inversed and switched from using ints
to unsigned ints now.
The way get_cmos_value was implemented forced us to not overlap byte and to
have multibyte values be byte aligned. This logic is now adapted to do a
full uint32_t read (when needed) at any offset and any length up to 32, and
the shifting all happens inside an uint32_t as well. set_cmos_value was
implemented similarly. Both routines have been extensively tested in a
quick separate little program as it is not easy to get this stuff right.
build_opt_tbl.c was altered to function correctly within these new
parameters. The enum value retrieval has been changed strol(..., NULL, 10)
to stroul(..., NULL, 0), so that we not only are able to use unsigned ints
now but so that we also interprete hex values correctly. The 32bit limit
gets imposed on all entries not marked reserved, an unused "user_data" field
that appeared in a lot of cmos.layouts has been changed to reserved as well.
Signed-off-by: Luc Verhaegen <libv@skynet.be>
Acked-by: Peter Stuge <peter@stuge.se>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4332 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
2009-06-03 12:47:19 +02:00
|
|
|
get_option("nmi", &nmi_option);
|
2008-10-29 05:46:52 +01:00
|
|
|
if (nmi_option) {
|
|
|
|
printk_info ("NMI sources enabled.\n");
|
|
|
|
reg8 &= ~(1 << 7); /* Set NMI. */
|
|
|
|
} else {
|
|
|
|
printk_info ("NMI sources disabled.\n");
|
|
|
|
reg8 |= ( 1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
|
|
|
|
}
|
|
|
|
outb(reg8, 0x70);
|
|
|
|
|
|
|
|
// Enable CPU_SLP# and Intel Speedstep, set SMI# rate down
|
|
|
|
reg16 = pci_read_config16(dev, GEN_PMCON_1);
|
2009-03-11 15:54:18 +01:00
|
|
|
reg16 &= ~((3 << 0) | (1 << 10));
|
|
|
|
reg16 |= (1 << 3) | (1 << 5);
|
|
|
|
reg16 |= (1 << 2); // CLKRUN_EN
|
2008-10-29 05:46:52 +01:00
|
|
|
pci_write_config16(dev, GEN_PMCON_1, reg16);
|
|
|
|
|
2009-03-11 15:54:18 +01:00
|
|
|
// Set the board's GPI routing.
|
|
|
|
i82801gx_gpi_routing(dev);
|
2008-10-29 05:46:52 +01:00
|
|
|
}
|
|
|
|
|
2009-03-11 15:54:18 +01:00
|
|
|
static void i82801gx_configure_cstates(device_t dev)
|
|
|
|
{
|
|
|
|
u8 reg8;
|
|
|
|
|
|
|
|
reg8 = pci_read_config8(dev, 0xa9); // Cx state configuration
|
|
|
|
reg8 |= (1 << 4) | (1 << 3) | (1 << 2); // Enable Popup & Popdown
|
|
|
|
pci_write_config8(dev, 0xa9, reg8);
|
|
|
|
|
|
|
|
// Set Deeper Sleep configuration to recommended values
|
|
|
|
reg8 = pci_read_config8(dev, 0xaa);
|
|
|
|
reg8 &= 0xf0;
|
|
|
|
reg8 |= (2 << 2); // Deeper Sleep to Stop CPU: 34-40us
|
|
|
|
reg8 |= (2 << 0); // Deeper Sleep to Sleep: 15us
|
|
|
|
pci_write_config8(dev, 0xaa, reg8);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i82801gx_rtc_init(struct device *dev)
|
2008-10-29 05:46:52 +01:00
|
|
|
{
|
|
|
|
u8 reg8;
|
|
|
|
int rtc_failed;
|
|
|
|
|
|
|
|
reg8 = pci_read_config8(dev, GEN_PMCON_3);
|
|
|
|
rtc_failed = reg8 & RTC_BATTERY_DEAD;
|
|
|
|
if (rtc_failed) {
|
|
|
|
reg8 &= ~RTC_BATTERY_DEAD;
|
|
|
|
pci_write_config8(dev, GEN_PMCON_3, reg8);
|
|
|
|
}
|
|
|
|
printk_debug("rtc_failed = 0x%x\n", rtc_failed);
|
|
|
|
|
|
|
|
rtc_init(rtc_failed);
|
|
|
|
}
|
|
|
|
|
2009-03-11 15:54:18 +01:00
|
|
|
static void enable_hpet(void)
|
2008-10-29 05:46:52 +01:00
|
|
|
{
|
2009-03-11 15:54:18 +01:00
|
|
|
u32 reg32;
|
|
|
|
|
|
|
|
/* Leave HPET at default address, but enable it */
|
|
|
|
reg32 = RCBA32(0x3404);
|
|
|
|
reg32 |= (1 << 7); // HPET Address Enable
|
|
|
|
RCBA32(0x3404) = reg32;
|
2008-10-29 05:46:52 +01:00
|
|
|
}
|
|
|
|
|
2009-03-11 15:54:18 +01:00
|
|
|
static void enable_clock_gating(void)
|
|
|
|
{
|
|
|
|
u32 reg32;
|
|
|
|
|
|
|
|
/* Enable Clock Gating for most devices */
|
|
|
|
reg32 = RCBA32(0x341c);
|
|
|
|
reg32 |= (1 << 31); // LPC clock gating
|
|
|
|
reg32 |= (1 << 30); // PATA clock gating
|
|
|
|
// SATA clock gating
|
|
|
|
reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
|
|
|
|
reg32 |= (1 << 23); // AC97 clock gating
|
|
|
|
reg32 |= (1 << 20) | (1 << 19); // USB EHCI clock gating
|
|
|
|
reg32 |= (1 << 3) | (1 << 1); // DMI clock gating
|
|
|
|
reg32 |= (1 << 2); // PCIe clock gating;
|
|
|
|
RCBA32(0x341c) = reg32;
|
|
|
|
}
|
2009-01-19 22:20:22 +01:00
|
|
|
|
|
|
|
#if HAVE_SMI_HANDLER
|
2008-10-29 05:46:52 +01:00
|
|
|
static void i82801gx_lock_smm(struct device *dev)
|
|
|
|
{
|
|
|
|
void smm_lock(void);
|
2009-03-11 15:54:18 +01:00
|
|
|
#if TEST_SMM_FLASH_LOCKDOWN
|
2008-10-29 05:46:52 +01:00
|
|
|
u8 reg8;
|
2009-03-11 15:54:18 +01:00
|
|
|
#endif
|
2008-10-29 05:46:52 +01:00
|
|
|
|
|
|
|
#if ENABLE_ACPI_MODE_IN_COREBOOT
|
|
|
|
printk_debug("Enabling ACPI via APMC:\n");
|
|
|
|
outb(0xe1, 0xb2); // Enable ACPI mode
|
|
|
|
printk_debug("done.\n");
|
|
|
|
#else
|
|
|
|
printk_debug("Disabling ACPI via APMC:\n");
|
|
|
|
outb(0x1e, 0xb2); // Disable ACPI mode
|
|
|
|
printk_debug("done.\n");
|
|
|
|
#endif
|
|
|
|
/* Don't allow evil boot loaders, kernels, or
|
|
|
|
* userspace applications to deceive us:
|
|
|
|
*/
|
|
|
|
smm_lock();
|
|
|
|
|
|
|
|
#if TEST_SMM_FLASH_LOCKDOWN
|
|
|
|
/* Now try this: */
|
|
|
|
printk_debug("Locking BIOS to RO... ");
|
|
|
|
reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
|
|
|
|
printk_debug(" BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
|
|
|
|
(reg8&1)?"rw":"ro");
|
|
|
|
reg8 &= ~(1 << 0); /* clear BIOSWE */
|
|
|
|
pci_write_config8(dev, 0xdc, reg8);
|
|
|
|
reg8 |= (1 << 1); /* set BLE */
|
|
|
|
pci_write_config8(dev, 0xdc, reg8);
|
|
|
|
printk_debug("ok.\n");
|
|
|
|
reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
|
|
|
|
printk_debug(" BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
|
|
|
|
(reg8&1)?"rw":"ro");
|
|
|
|
|
|
|
|
printk_debug("Writing:\n");
|
|
|
|
*(volatile u8 *)0xfff00000 = 0x00;
|
|
|
|
printk_debug("Testing:\n");
|
|
|
|
reg8 |= (1 << 0); /* set BIOSWE */
|
|
|
|
pci_write_config8(dev, 0xdc, reg8);
|
|
|
|
|
|
|
|
reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
|
|
|
|
printk_debug(" BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
|
|
|
|
(reg8&1)?"rw":"ro");
|
|
|
|
printk_debug("Done.\n");
|
|
|
|
#endif
|
|
|
|
}
|
2009-01-19 22:20:22 +01:00
|
|
|
#endif
|
2008-10-29 05:46:52 +01:00
|
|
|
|
2009-03-11 15:54:18 +01:00
|
|
|
#define SPIBASE 0x3020
|
|
|
|
static void i82801gx_spi_init(void)
|
|
|
|
{
|
|
|
|
u16 spicontrol;
|
|
|
|
|
|
|
|
spicontrol = RCBA16(SPIBASE + 2);
|
|
|
|
spicontrol &= ~(1 << 0); // SPI Access Request
|
|
|
|
RCBA16(SPIBASE + 2) = spicontrol;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i82801gx_fixups(void)
|
|
|
|
{
|
|
|
|
/* This needs to happen after PCI enumeration */
|
|
|
|
RCBA32(0x1d40) |= 1;
|
|
|
|
}
|
|
|
|
|
2008-10-29 05:46:52 +01:00
|
|
|
static void lpc_init(struct device *dev)
|
|
|
|
{
|
|
|
|
printk_debug("i82801gx: lpc_init\n");
|
|
|
|
|
|
|
|
/* Set the value for PCI command register. */
|
|
|
|
pci_write_config16(dev, PCI_COMMAND, 0x000f);
|
|
|
|
|
|
|
|
/* IO APIC initialization. */
|
|
|
|
i82801gx_enable_apic(dev);
|
|
|
|
|
|
|
|
i82801gx_enable_serial_irqs(dev);
|
|
|
|
|
|
|
|
/* Setup the PIRQ. */
|
|
|
|
i82801gx_pirq_init(dev);
|
|
|
|
|
|
|
|
/* Setup power options. */
|
|
|
|
i82801gx_power_options(dev);
|
|
|
|
|
2009-03-11 15:54:18 +01:00
|
|
|
/* Configure Cx state registers */
|
|
|
|
i82801gx_configure_cstates(dev);
|
|
|
|
|
2008-10-29 05:46:52 +01:00
|
|
|
/* Set the state of the GPIO lines. */
|
|
|
|
//gpio_init(dev);
|
|
|
|
|
|
|
|
/* Initialize the real time clock. */
|
|
|
|
i82801gx_rtc_init(dev);
|
|
|
|
|
|
|
|
/* Initialize ISA DMA. */
|
|
|
|
isa_dma_init();
|
|
|
|
|
|
|
|
/* Initialize the High Precision Event Timers, if present. */
|
2009-03-11 15:54:18 +01:00
|
|
|
enable_hpet();
|
|
|
|
|
|
|
|
/* Initialize Clock Gating */
|
|
|
|
enable_clock_gating();
|
2008-10-29 05:46:52 +01:00
|
|
|
|
|
|
|
setup_i8259();
|
|
|
|
|
2009-01-19 22:20:22 +01:00
|
|
|
#if HAVE_SMI_HANDLER
|
2008-10-29 05:46:52 +01:00
|
|
|
i82801gx_lock_smm(dev);
|
2009-01-19 22:20:22 +01:00
|
|
|
#endif
|
2009-03-11 15:54:18 +01:00
|
|
|
|
|
|
|
i82801gx_spi_init();
|
|
|
|
|
|
|
|
i82801gx_fixups();
|
2008-10-29 05:46:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void i82801gx_lpc_read_resources(device_t dev)
|
|
|
|
{
|
|
|
|
struct resource *res;
|
|
|
|
|
|
|
|
/* Get the normal PCI resources of this device. */
|
|
|
|
pci_dev_read_resources(dev);
|
|
|
|
|
|
|
|
/* Add an extra subtractive resource for both memory and I/O. */
|
|
|
|
res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
|
|
|
|
res->flags =
|
|
|
|
IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
|
|
|
|
|
|
|
|
res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
|
|
|
|
res->flags =
|
|
|
|
IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i82801gx_lpc_enable_resources(device_t dev)
|
|
|
|
{
|
|
|
|
pci_dev_enable_resources(dev);
|
|
|
|
enable_childrens_resources(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_subsystem(device_t dev, unsigned vendor, unsigned device)
|
|
|
|
{
|
2009-03-11 15:54:18 +01:00
|
|
|
if (!vendor || !device) {
|
|
|
|
pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
|
|
|
|
pci_read_config32(dev, PCI_VENDOR_ID));
|
|
|
|
} else {
|
|
|
|
pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
|
|
|
|
((device & 0xffff) << 16) | (vendor & 0xffff));
|
|
|
|
}
|
2008-10-29 05:46:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct pci_operations pci_ops = {
|
|
|
|
.set_subsystem = set_subsystem,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct device_operations device_ops = {
|
|
|
|
.read_resources = i82801gx_lpc_read_resources,
|
|
|
|
.set_resources = pci_dev_set_resources,
|
|
|
|
.enable_resources = i82801gx_lpc_enable_resources,
|
|
|
|
.init = lpc_init,
|
|
|
|
.scan_bus = scan_static_bus,
|
|
|
|
.enable = i82801gx_enable,
|
|
|
|
.ops_pci = &pci_ops,
|
|
|
|
};
|
|
|
|
|
2009-01-20 23:53:10 +01:00
|
|
|
/* 82801GB/GR (ICH7/ICH7R) */
|
|
|
|
static const struct pci_driver ich7_ich7r_lpc __pci_driver = {
|
2008-10-29 05:46:52 +01:00
|
|
|
.ops = &device_ops,
|
|
|
|
.vendor = PCI_VENDOR_ID_INTEL,
|
2008-10-31 19:41:09 +01:00
|
|
|
.device = 0x27b8,
|
2008-10-29 05:46:52 +01:00
|
|
|
};
|
|
|
|
|
2008-10-29 14:51:31 +01:00
|
|
|
/* 82801GBM/GU (ICH7-M/ICH7-U) */
|
2008-10-29 05:46:52 +01:00
|
|
|
static const struct pci_driver ich7m_ich7u_lpc __pci_driver = {
|
|
|
|
.ops = &device_ops,
|
|
|
|
.vendor = PCI_VENDOR_ID_INTEL,
|
2008-10-31 19:41:09 +01:00
|
|
|
.device = 0x27b9,
|
2008-10-29 05:46:52 +01:00
|
|
|
};
|
|
|
|
|
2008-10-29 14:51:31 +01:00
|
|
|
/* 82801GHM (ICH7-M DH) */
|
2008-10-29 05:46:52 +01:00
|
|
|
static const struct pci_driver ich7m_dh_lpc __pci_driver = {
|
|
|
|
.ops = &device_ops,
|
|
|
|
.vendor = PCI_VENDOR_ID_INTEL,
|
2008-10-31 19:41:09 +01:00
|
|
|
.device = 0x27bd,
|
2008-10-29 05:46:52 +01:00
|
|
|
};
|