sb/intel/i82801jx: Copy i82801ix

Change-Id: I878960e7e0f992426382ca717b8b42787f01ebc6
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/19248
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Martin Roth <martinroth@google.com>
This commit is contained in:
Arthur Heymans 2017-04-09 20:40:39 +02:00 committed by Martin Roth
parent c3198543b6
commit 7b9c139ac2
33 changed files with 5972 additions and 0 deletions

View File

@ -0,0 +1,43 @@
##
## This file is part of the coreboot project.
##
## Copyright (C) 2008-2009 coresystems GmbH
## 2012 secunet security Networks AG
##
## 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.
##
## 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.
##
config SOUTHBRIDGE_INTEL_I82801JX
bool
select SOUTHBRIDGE_INTEL_COMMON
select IOAPIC
select HAVE_USBDEBUG
select HAVE_HARD_RESET
select USE_WATCHDOG_ON_BOOT
select HAVE_SMI_HANDLER
select HAVE_USBDEBUG_OPTIONS
select SOUTHBRIDGE_INTEL_COMMON_GPIO
select HAVE_INTEL_FIRMWARE
if SOUTHBRIDGE_INTEL_I82801JX
config EHCI_BAR
hex
default 0xfef00000
config HPET_MIN_TICKS
hex
default 0x80
config BOOTBLOCK_SOUTHBRIDGE_INIT
string
default "southbridge/intel/i82801ix/bootblock.c"
endif

View File

@ -0,0 +1,43 @@
##
## This file is part of the coreboot project.
##
## Copyright (C) 2008-2009 coresystems GmbH
## 2012 secunet Security Networks AG
##
## 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.
##
## 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.
##
ifeq ($(CONFIG_SOUTHBRIDGE_INTEL_I82801JX),y)
ramstage-y += i82801ix.c
ramstage-y += pci.c
ramstage-y += lpc.c
ramstage-y += pcie.c
ramstage-y += usb_ehci.c
ramstage-y += sata.c
ramstage-y += hdaudio.c
ramstage-y += thermal.c
ramstage-y += smbus.c
ramstage-y += ../common/pciehp.c
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/hda_verb.c
ramstage-y += ../i82801gx/reset.c
ramstage-y += ../i82801gx/watchdog.c
ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c
ramstage-$(CONFIG_HAVE_SMI_HANDLER) += ../../../cpu/x86/smm/smmrelocate.S
smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c
romstage-y += early_init.c
romstage-y += early_smbus.c
romstage-y += dmi_setup.c
endif

View File

@ -0,0 +1,30 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2009 coresystems GmbH
*
* 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.
*
* 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.
*/
/* Intel i82801I HDA */
// Intel High Definition Audio (Azalia) 0:1b.0
Device (HDEF)
{
Name (_ADR, 0x001b0000)
// Power Resources for Wake
Name (_PRW, Package(){
5, // Bit 5 of GPE
4 // Can wake from S4 state.
})
}

View File

@ -0,0 +1,167 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2009 coresystems GmbH
*
* 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.
*
* 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.
*/
/* Global Variables */
Name(\PICM, 0) // IOAPIC/8259
Name(\DSEN, 1) // Display Output Switching Enable
/* Global ACPI memory region. This region is used for passing information
* between coreboot (aka "the system bios"), ACPI, and the SMI handler.
* Since we don't know where this will end up in memory at ACPI compile time,
* we have to fix it up in coreboot's ACPI creation phase.
*/
External(NVSA)
OperationRegion (GNVS, SystemMemory, NVSA, 0x100)
Field (GNVS, ByteAcc, NoLock, Preserve)
{
/* Miscellaneous */
Offset (0x00),
OSYS, 16, // 0x00 - Operating System
SMIF, 8, // 0x02 - SMI function
PRM0, 8, // 0x03 - SMI function parameter
PRM1, 8, // 0x04 - SMI function parameter
SCIF, 8, // 0x05 - SCI function
PRM2, 8, // 0x06 - SCI function parameter
PRM3, 8, // 0x07 - SCI function parameter
LCKF, 8, // 0x08 - Global Lock function for EC
PRM4, 8, // 0x09 - Lock function parameter
PRM5, 8, // 0x0a - Lock function parameter
P80D, 32, // 0x0b - Debug port (IO 0x80) value
LIDS, 8, // 0x0f - LID state (open = 1)
PWRS, 8, // 0x10 - Power State (AC = 1)
DBGS, 8, // 0x11 - Debug State
LINX, 8, // 0x12 - Linux OS
DCKN, 8, // 0x13 - PCIe docking state
/* Thermal policy */
Offset (0x14),
ACTT, 8, // 0x14 - active trip point
PSVT, 8, // 0x15 - passive trip point
TC1V, 8, // 0x16 - passive trip point TC1
TC2V, 8, // 0x17 - passive trip point TC2
TSPV, 8, // 0x18 - passive trip point TSP
CRTT, 8, // 0x19 - critical trip point
DTSE, 8, // 0x1a - Digital Thermal Sensor enable
DTS1, 8, // 0x1b - DT sensor 1
DTS2, 8, // 0x1c - DT sensor 2
/* Battery Support */
Offset (0x1e),
BNUM, 8, // 0x1e - number of batteries
B0SC, 8, // 0x1f - BAT0 stored capacity
B1SC, 8, // 0x20 - BAT1 stored capacity
B2SC, 8, // 0x21 - BAT2 stored capacity
B0SS, 8, // 0x22 - BAT0 stored status
B1SS, 8, // 0x23 - BAT1 stored status
B2SS, 8, // 0x24 - BAT2 stored status
/* Processor Identification */
Offset (0x28),
APIC, 8, // 0x28 - APIC Enabled by coreboot
MPEN, 8, // 0x29 - Multi Processor Enable
PCP0, 8, // 0x2a - PDC CPU/CORE 0
PCP1, 8, // 0x2b - PDC CPU/CORE 1
PPCM, 8, // 0x2c - Max. PPC state
/* Super I/O & CMOS config */
Offset (0x32),
NATP, 8, // 0x32 -
CMAP, 8, // 0x33 -
CMBP, 8, // 0x34 -
LPTP, 8, // 0x35 - LPT Port
FDCP, 8, // 0x36 - Floppy Disk Controller
RFDV, 8, // 0x37 -
HOTK, 8, // 0x38 -
RTCF, 8, // 0x39 -
UTIL, 8, // 0x3a -
ACIN, 8, // 0x3b -
/* Integrated Graphics Device */
Offset (0x3c),
IGDS, 8, // 0x3c - IGD state (primary = 1)
TLST, 8, // 0x3d - Display Toggle List pointer
CADL, 8, // 0x3e - Currently Attached Devices List
PADL, 8, // 0x3f - Previously Attached Devices List
CSTE, 16, // 0x40 - Current display state
NSTE, 16, // 0x42 - Next display state
SSTE, 16, // 0x44 - Set display state
Offset (0x46),
NDID, 8, // 0x46 - Number of Device IDs
DID1, 32, // 0x47 - Device ID 1
DID2, 32, // 0x4b - Device ID 2
DID3, 32, // 0x4f - Device ID 3
DID4, 32, // 0x53 - Device ID 4
DID5, 32, // 0x57 - Device ID 5
/* Backlight Control */
Offset (0x64),
BLCS, 8, // 0x64 - Backlight control possible?
BRTL, 8, // 0x65 - Brightness Level
ODDS, 8, // 0x66
/* Ambient Light Sensors */
Offset (0x6e),
ALSE, 8, // 0x6e - ALS enable
ALAF, 8, // 0x6f - Ambient light adjustment factor
LLOW, 8, // 0x70 - LUX Low
LHIH, 8, // 0x71 - LUX High
/* EMA */
Offset (0x78),
EMAE, 8, // 0x78 - EMA enable
EMAP, 16, // 0x79 - EMA pointer
EMAL, 16, // 0x7b - EMA length
/* MEF */
Offset (0x82),
MEFE, 8, // 0x82 - MEF enable
/* TPM support */
Offset (0x8c),
TPMP, 8, // 0x8c - TPM
TPME, 8, // 0x8d - TPM enable
/* SATA */
Offset (0x96),
GTF0, 56, // 0x96 - GTF task file buffer for port 0
GTF1, 56, // 0x9d - GTF task file buffer for port 1
GTF2, 56, // 0xa4 - GTF task file buffer for port 2
IDEM, 8, // 0xab - IDE mode (compatible / enhanced)
IDET, 8, // 0xac - IDE
/* IGD OpRegion */
Offset (0xb4),
ASLB, 32, // 0xb4 - IGD OpRegion Base Address
IBTT, 8, // 0xb8 - IGD boot panel device
IPAT, 8, // 0xb9 - IGD panel type cmos option
ITVF, 8, // 0xba - IGD TV format cmos option
ITVM, 8, // 0xbb - IGD TV minor format option
IPSC, 8, // 0xbc - IGD panel scaling
IBLC, 8, // 0xbd - IGD BLC config
IBIA, 8, // 0xbe - IGD BIA config
ISSC, 8, // 0xbf - IGD SSC config
I409, 8, // 0xc0 - IGD 0409 modified settings
I509, 8, // 0xc1 - IGD 0509 modified settings
I609, 8, // 0xc2 - IGD 0609 modified settings
I709, 8, // 0xc3 - IGD 0709 modified settings
IDMM, 8, // 0xc4 - IGD DVMT Mode
IDMS, 8, // 0xc5 - IGD DVMT memory size
IF1E, 8, // 0xc6 - IGD function 1 enable
HVCO, 8, // 0xc7 - IGD HPLL VCO
NXD1, 32, // 0xc8 - IGD _DGS next DID1
NXD2, 32, // 0xcc - IGD _DGS next DID2
NXD3, 32, // 0xd0 - IGD _DGS next DID3
NXD4, 32, // 0xd4 - IGD _DGS next DID4
NXD5, 32, // 0xd8 - IGD _DGS next DID5
NXD6, 32, // 0xdc - IGD _DGS next DID6
NXD7, 32, // 0xe0 - IGD _DGS next DID7
NXD8, 32, // 0xe4 - IGD _DGS next DID8
/* Mainboard Specific (TODO move elsewhere) */
Offset (0xf0),
DOCK, 8, // 0xf0 - Docking Status
BTEN, 8, // 0xf1 - Bluetooth Enable
}

View File

@ -0,0 +1,203 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2009 coresystems GmbH
*
* 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.
*
* 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.
*/
/* Intel 82801Ix support */
Scope(\)
{
// IO-Trap at 0x800. This is the ACPI->SMI communication interface.
OperationRegion(IO_T, SystemIO, 0x800, 0x10)
Field(IO_T, ByteAcc, NoLock, Preserve)
{
Offset(0x8),
TRP0, 8 // IO-Trap at 0x808
}
// ICH9 Power Management Registers, located at PMBASE (0x1f.0 0x40.l)
OperationRegion(PMIO, SystemIO, DEFAULT_PMBASE, 0x80)
Field(PMIO, ByteAcc, NoLock, Preserve)
{
Offset(0x11),
THRO, 1, // force thermal throttling
Offset(0x42), // General Purpose Control
, 1, // skip 1 bit
GPEC, 1, // TCO status
Offset(0x64),
, 9, // skip 9 more bits
SCIS, 1 // TCO DMI status
}
// FIXME: purposes of the GPIOs (comments) are probably wrong
// ICH9 GPIO IO mapped registers (0x1f.0 reg 0x48.l)
OperationRegion(GPIO, SystemIO, DEFAULT_GPIOBASE, 0x3c)
Field(GPIO, ByteAcc, NoLock, Preserve)
{
Offset(0x00), // GPIO Use Select
GU00, 8,
GU01, 8,
GU02, 8,
GU03, 8,
Offset(0x04), // GPIO IO Select
GIO0, 8,
GIO1, 8,
GIO2, 8,
GIO3, 8,
Offset(0x0c), // GPIO Level
GP00, 1,
GP01, 1,
GP02, 1,
GP03, 1,
GP04, 1,
GP05, 1,
GP06, 1, // GDET
GP07, 1,
GP08, 1,
GP09, 1, // HPMU
GP10, 1, // GPSE
GP11, 1,
GP12, 1, // WLED
GP13, 1, // BLED
GP14, 1, // GLED
GP15, 1, // GDIS
GP16, 1,
GP17, 1,
GP18, 1, // SPCI
GP19, 1, // TSDT
GP20, 1, // SCPU
GP21, 1,
GP22, 1,
GP23, 1, // LANP
GP24, 1, // DKLR
GP25, 1, // WLAN
GP26, 1, // SATA_PWR_EN #0 / SPOF
GP27, 1, // SATA_PWR_EN #1 / SPMU
GP28, 1,
GP29, 1,
GP30, 1,
GP31, 1,
Offset(0x18), // GPIO Blink
GB00, 8,
GB01, 8,
GB02, 8,
GB03, 8,
Offset(0x2c), // GPIO Invert
GIV0, 8,
GIV1, 8,
GIV2, 8,
GIV3, 8,
Offset(0x30), // GPIO Use Select 2
GU04, 8,
GU05, 8,
GU06, 8,
GU07, 8,
Offset(0x34), // GPIO IO Select 2
GIO4, 8,
GIO5, 8,
GIO6, 8,
GIO7, 8,
Offset(0x38), // GPIO Level 2
GP32, 1,
GP33, 1, // CREN
GP34, 1, // CRRS
GP35, 1,
GP36, 1, // STAD
GP37, 1, // PATA_PWR_EN / HDDE
GP38, 1, // Battery / Power (?) / MB00
GP39, 1, // ?? / MB01
GL05, 8,
GL06, 8,
GL07, 8
}
// ICH9 Root Complex Register Block. Memory Mapped through RCBA)
OperationRegion(RCRB, SystemMemory, DEFAULT_RCBA, 0x4000)
Field(RCRB, DWordAcc, Lock, Preserve)
{
Offset(0x0000), // Backbone
Offset(0x1000), // Chipset
Offset(0x3000), // Legacy Configuration Registers
Offset(0x3404), // High Performance Timer Configuration
HPAS, 2, // Address Select
, 5,
HPTE, 1, // Address Enable
Offset(0x3418), // FD (Function Disable)
, 2, // Reserved
SA1D, 1, // SATA disable
SMBD, 1, // SMBUS disable
HDAD, 1, // Azalia disable
, 2, // Reserved
US6D, 1, // UHCI #6 disable
US1D, 1, // UHCI #1 disable
US2D, 1, // UHCI #2 disable
US3D, 1, // UHCI #3 disable
US4D, 1, // UHCI #4 disable
US5D, 1, // UHCI #5 disable
EH2D, 1, // EHCI disable
LPBD, 1, // LPC bridge disable
EH1D, 1, // EHCI disable
Offset(0x341a), // FD Root Ports
RP1D, 1, // Root Port 1 disable
RP2D, 1, // Root Port 2 disable
RP3D, 1, // Root Port 3 disable
RP4D, 1, // Root Port 4 disable
RP5D, 1, // Root Port 5 disable
RP6D, 1, // Root Port 6 disable
, 2, // Reserved
THRD, 1, // Thermal Throttle disable
SA2D, 1, // SATA disable
}
}
// 0:1b.0 High Definition Audio (Azalia)
#include "audio.asl"
// PCI Express Ports
#include "pcie.asl"
// USB
#include "usb.asl"
// PCI Bridge
#include "pci.asl"
// LPC Bridge
#include "lpc.asl"
// SATA
#include "sata.asl"
// SMBus
#include "smbus.asl"
Method (_OSC, 4)
{
/* Check for proper GUID */
If (LEqual (Arg0, ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766")))
{
/* Let OS control everything */
Return (Arg3)
}
Else
{
/* Unrecognized UUID */
CreateDWordField (Arg3, 0, CDW1)
Or (CDW1, 4, CDW1)
Return (Arg3)
}
}

View File

@ -0,0 +1,487 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2009 coresystems GmbH
*
* 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.
*
* 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.
*/
Device (LNKA)
{
Name (_HID, EISAID("PNP0C0F"))
Name (_UID, 1)
// Disable method
Method (_DIS, 0, Serialized)
{
Store (0x80, PRTA)
}
// Possible Resource Settings for this Link
Name (_PRS, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared)
{ 3, 4, 5, 6, 7, 10, 12, 14, 15 }
})
// Current Resource Settings for this link
Method (_CRS, 0, Serialized)
{
Name (RTLA, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared) {}
})
CreateWordField(RTLA, 1, IRQ0)
// Clear the WordField
Store (Zero, IRQ0)
// Set the bit from PRTA
ShiftLeft(1, And(PRTA, 0x0f), IRQ0)
Return (RTLA)
}
// Set Resource Setting for this IRQ link
Method (_SRS, 1, Serialized)
{
CreateWordField(Arg0, 1, IRQ0)
// Which bit is set?
FindSetRightBit(IRQ0, Local0)
Decrement(Local0)
Store(Local0, PRTA)
}
// Status
Method (_STA, 0, Serialized)
{
If(And(PRTA, 0x80)) {
Return (0x9)
} Else {
Return (0xb)
}
}
}
Device (LNKB)
{
Name (_HID, EISAID("PNP0C0F"))
Name (_UID, 2)
// Disable method
Method (_DIS, 0, Serialized)
{
Store (0x80, PRTB)
}
// Possible Resource Settings for this Link
Name (_PRS, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared)
{ 3, 4, 5, 6, 7, 11, 12, 14, 15 }
})
// Current Resource Settings for this link
Method (_CRS, 0, Serialized)
{
Name (RTLB, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared) {}
})
CreateWordField(RTLB, 1, IRQ0)
// Clear the WordField
Store (Zero, IRQ0)
// Set the bit from PRTB
ShiftLeft(1, And(PRTB, 0x0f), IRQ0)
Return (RTLB)
}
// Set Resource Setting for this IRQ link
Method (_SRS, 1, Serialized)
{
CreateWordField(Arg0, 1, IRQ0)
// Which bit is set?
FindSetRightBit(IRQ0, Local0)
Decrement(Local0)
Store(Local0, PRTB)
}
// Status
Method (_STA, 0, Serialized)
{
If(And(PRTB, 0x80)) {
Return (0x9)
} Else {
Return (0xb)
}
}
}
Device (LNKC)
{
Name (_HID, EISAID("PNP0C0F"))
Name (_UID, 3)
// Disable method
Method (_DIS, 0, Serialized)
{
Store (0x80, PRTC)
}
// Possible Resource Settings for this Link
Name (_PRS, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared)
{ 3, 4, 5, 6, 7, 10, 12, 14, 15 }
})
// Current Resource Settings for this link
Method (_CRS, 0, Serialized)
{
Name (RTLC, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared) {}
})
CreateWordField(RTLC, 1, IRQ0)
// Clear the WordField
Store (Zero, IRQ0)
// Set the bit from PRTC
ShiftLeft(1, And(PRTC, 0x0f), IRQ0)
Return (RTLC)
}
// Set Resource Setting for this IRQ link
Method (_SRS, 1, Serialized)
{
CreateWordField(Arg0, 1, IRQ0)
// Which bit is set?
FindSetRightBit(IRQ0, Local0)
Decrement(Local0)
Store(Local0, PRTC)
}
// Status
Method (_STA, 0, Serialized)
{
If(And(PRTC, 0x80)) {
Return (0x9)
} Else {
Return (0xb)
}
}
}
Device (LNKD)
{
Name (_HID, EISAID("PNP0C0F"))
Name (_UID, 4)
// Disable method
Method (_DIS, 0, Serialized)
{
Store (0x80, PRTD)
}
// Possible Resource Settings for this Link
Name (_PRS, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared)
{ 3, 4, 5, 6, 7, 11, 12, 14, 15 }
})
// Current Resource Settings for this link
Method (_CRS, 0, Serialized)
{
Name (RTLD, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared) {}
})
CreateWordField(RTLD, 1, IRQ0)
// Clear the WordField
Store (Zero, IRQ0)
// Set the bit from PRTD
ShiftLeft(1, And(PRTD, 0x0f), IRQ0)
Return (RTLD)
}
// Set Resource Setting for this IRQ link
Method (_SRS, 1, Serialized)
{
CreateWordField(Arg0, 1, IRQ0)
// Which bit is set?
FindSetRightBit(IRQ0, Local0)
Decrement(Local0)
Store(Local0, PRTD)
}
// Status
Method (_STA, 0, Serialized)
{
If(And(PRTD, 0x80)) {
Return (0x9)
} Else {
Return (0xb)
}
}
}
Device (LNKE)
{
Name (_HID, EISAID("PNP0C0F"))
Name (_UID, 5)
// Disable method
Method (_DIS, 0, Serialized)
{
Store (0x80, PRTE)
}
// Possible Resource Settings for this Link
Name (_PRS, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared)
{ 3, 4, 5, 6, 7, 10, 12, 14, 15 }
})
// Current Resource Settings for this link
Method (_CRS, 0, Serialized)
{
Name (RTLE, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared) {}
})
CreateWordField(RTLE, 1, IRQ0)
// Clear the WordField
Store (Zero, IRQ0)
// Set the bit from PRTE
ShiftLeft(1, And(PRTE, 0x0f), IRQ0)
Return (RTLE)
}
// Set Resource Setting for this IRQ link
Method (_SRS, 1, Serialized)
{
CreateWordField(Arg0, 1, IRQ0)
// Which bit is set?
FindSetRightBit(IRQ0, Local0)
Decrement(Local0)
Store(Local0, PRTE)
}
// Status
Method (_STA, 0, Serialized)
{
If(And(PRTE, 0x80)) {
Return (0x9)
} Else {
Return (0xb)
}
}
}
Device (LNKF)
{
Name (_HID, EISAID("PNP0C0F"))
Name (_UID, 6)
// Disable method
Method (_DIS, 0, Serialized)
{
Store (0x80, PRTF)
}
// Possible Resource Settings for this Link
Name (_PRS, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared)
{ 3, 4, 5, 6, 7, 11, 12, 14, 15 }
})
// Current Resource Settings for this link
Method (_CRS, 0, Serialized)
{
Name (RTLF, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared) {}
})
CreateWordField(RTLF, 1, IRQ0)
// Clear the WordField
Store (Zero, IRQ0)
// Set the bit from PRTF
ShiftLeft(1, And(PRTF, 0x0f), IRQ0)
Return (RTLF)
}
// Set Resource Setting for this IRQ link
Method (_SRS, 1, Serialized)
{
CreateWordField(Arg0, 1, IRQ0)
// Which bit is set?
FindSetRightBit(IRQ0, Local0)
Decrement(Local0)
Store(Local0, PRTF)
}
// Status
Method (_STA, 0, Serialized)
{
If(And(PRTF, 0x80)) {
Return (0x9)
} Else {
Return (0xb)
}
}
}
Device (LNKG)
{
Name (_HID, EISAID("PNP0C0F"))
Name (_UID, 7)
// Disable method
Method (_DIS, 0, Serialized)
{
Store (0x80, PRTG)
}
// Possible Resource Settings for this Link
Name (_PRS, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared)
{ 3, 4, 5, 6, 7, 10, 12, 14, 15 }
})
// Current Resource Settings for this link
Method (_CRS, 0, Serialized)
{
Name (RTLG, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared) {}
})
CreateWordField(RTLG, 1, IRQ0)
// Clear the WordField
Store (Zero, IRQ0)
// Set the bit from PRTG
ShiftLeft(1, And(PRTG, 0x0f), IRQ0)
Return (RTLG)
}
// Set Resource Setting for this IRQ link
Method (_SRS, 1, Serialized)
{
CreateWordField(Arg0, 1, IRQ0)
// Which bit is set?
FindSetRightBit(IRQ0, Local0)
Decrement(Local0)
Store(Local0, PRTG)
}
// Status
Method (_STA, 0, Serialized)
{
If(And(PRTG, 0x80)) {
Return (0x9)
} Else {
Return (0xb)
}
}
}
Device (LNKH)
{
Name (_HID, EISAID("PNP0C0F"))
Name (_UID, 8)
// Disable method
Method (_DIS, 0, Serialized)
{
Store (0x80, PRTH)
}
// Possible Resource Settings for this Link
Name (_PRS, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared)
{ 3, 4, 5, 6, 7, 11, 12, 14, 15 }
})
// Current Resource Settings for this link
Method (_CRS, 0, Serialized)
{
Name (RTLH, ResourceTemplate()
{
IRQ(Level, ActiveLow, Shared) {}
})
CreateWordField(RTLH, 1, IRQ0)
// Clear the WordField
Store (Zero, IRQ0)
// Set the bit from PRTH
ShiftLeft(1, And(PRTH, 0x0f), IRQ0)
Return (RTLH)
}
// Set Resource Setting for this IRQ link
Method (_SRS, 1, Serialized)
{
CreateWordField(Arg0, 1, IRQ0)
// Which bit is set?
FindSetRightBit(IRQ0, Local0)
Decrement(Local0)
Store(Local0, PRTH)
}
// Status
Method (_STA, 0, Serialized)
{
If(And(PRTH, 0x80)) {
Return (0x9)
} Else {
Return (0xb)
}
}
}

View File

@ -0,0 +1,261 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2009 coresystems GmbH
*
* 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.
*
* 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.
*/
// Intel LPC Bus Device - 0:1f.0
Device (LPCB)
{
Name(_ADR, 0x001f0000)
OperationRegion(LPC0, PCI_Config, 0x00, 0x100)
Field (LPC0, AnyAcc, NoLock, Preserve)
{
Offset (0x40),
PMBS, 16, // PMBASE
Offset (0x60), // Interrupt Routing Registers
PRTA, 8,
PRTB, 8,
PRTC, 8,
PRTD, 8,
Offset (0x68),
PRTE, 8,
PRTF, 8,
PRTG, 8,
PRTH, 8,
Offset (0x80), // IO Decode Ranges
IOD0, 8,
IOD1, 8,
Offset (0xf0), // RCBA
RCEN, 1,
, 13,
RCBA, 18,
}
#include "irqlinks.asl"
#include "acpi/ec.asl"
Device (DMAC) // DMA Controller
{
Name(_HID, EISAID("PNP0200"))
Name(_CRS, ResourceTemplate()
{
IO (Decode16, 0x00, 0x00, 0x01, 0x20)
IO (Decode16, 0x81, 0x81, 0x01, 0x11)
IO (Decode16, 0x93, 0x93, 0x01, 0x0d)
IO (Decode16, 0xc0, 0xc0, 0x01, 0x20)
DMA (Compatibility, NotBusMaster, Transfer8_16) { 4 }
})
}
Device (FWH) // Firmware Hub
{
Name (_HID, EISAID("INT0800"))
Name (_CRS, ResourceTemplate()
{
Memory32Fixed(ReadOnly, 0xff000000, 0x01000000)
})
}
Device (HPET)
{
Name (_HID, EISAID("PNP0103"))
Name (_CID, 0x010CD041)
Name(BUF0, ResourceTemplate()
{
Memory32Fixed(ReadOnly, 0xfed00000, 0x400, FED0)
})
Method (_STA, 0) // Device Status
{
If (HPTE) {
// Note: Ancient versions of Windows don't want
// to see the HPET in order to work right
If (LGreaterEqual(OSYS, 2001)) {
Return (0xf) // Enable and show device
} Else {
Return (0xb) // Enable and don't show device
}
}
Return (0x0) // Not enabled, don't show.
}
Method (_CRS, 0, Serialized) // Current resources
{
If (HPTE) {
CreateDWordField(BUF0, \_SB.PCI0.LPCB.HPET.FED0._BAS, HPT0)
If (Lequal(HPAS, 1)) {
Store(0xfed01000, HPT0)
}
If (Lequal(HPAS, 2)) {
Store(0xfed02000, HPT0)
}
If (Lequal(HPAS, 3)) {
Store(0xfed03000, HPT0)
}
}
Return (BUF0)
}
}
Device(PIC) // 8259 Interrupt Controller
{
Name(_HID,EISAID("PNP0000"))
Name(_CRS, ResourceTemplate()
{
IO (Decode16, 0x20, 0x20, 0x01, 0x02)
IO (Decode16, 0x24, 0x24, 0x01, 0x02)
IO (Decode16, 0x28, 0x28, 0x01, 0x02)
IO (Decode16, 0x2c, 0x2c, 0x01, 0x02)
IO (Decode16, 0x30, 0x30, 0x01, 0x02)
IO (Decode16, 0x34, 0x34, 0x01, 0x02)
IO (Decode16, 0x38, 0x38, 0x01, 0x02)
IO (Decode16, 0x3c, 0x3c, 0x01, 0x02)
IO (Decode16, 0xa0, 0xa0, 0x01, 0x02)
IO (Decode16, 0xa4, 0xa4, 0x01, 0x02)
IO (Decode16, 0xa8, 0xa8, 0x01, 0x02)
IO (Decode16, 0xac, 0xac, 0x01, 0x02)
IO (Decode16, 0xb0, 0xb0, 0x01, 0x02)
IO (Decode16, 0xb4, 0xb4, 0x01, 0x02)
IO (Decode16, 0xb8, 0xb8, 0x01, 0x02)
IO (Decode16, 0xbc, 0xbc, 0x01, 0x02)
IO (Decode16, 0x4d0, 0x4d0, 0x01, 0x02)
IRQNoFlags () { 2 }
})
}
Device(MATH) // FPU
{
Name (_HID, EISAID("PNP0C04"))
Name (_CRS, ResourceTemplate()
{
IO (Decode16, 0xf0, 0xf0, 0x01, 0x01)
IRQNoFlags() { 13 }
})
}
Device(LDRC) // LPC device: Resource consumption
{
Name (_HID, EISAID("PNP0C02"))
Name (_UID, 2)
Name (_CRS, ResourceTemplate()
{
IO (Decode16, 0x2e, 0x2e, 0x1, 0x02) // First SuperIO
IO (Decode16, 0x4e, 0x4e, 0x1, 0x02) // Second SuperIO
IO (Decode16, 0x61, 0x61, 0x1, 0x01) // NMI Status
IO (Decode16, 0x63, 0x63, 0x1, 0x01) // CPU Reserved
IO (Decode16, 0x65, 0x65, 0x1, 0x01) // CPU Reserved
IO (Decode16, 0x67, 0x67, 0x1, 0x01) // CPU Reserved
IO (Decode16, 0x80, 0x80, 0x1, 0x01) // Port 80 Post
IO (Decode16, 0x92, 0x92, 0x1, 0x01) // CPU Reserved
IO (Decode16, 0xb2, 0xb2, 0x1, 0x02) // SWSMI
IO (Decode16, 0x800, 0x800, 0x1, 0x10) // ACPI I/O trap
IO (Decode16, DEFAULT_PMBASE, DEFAULT_PMBASE, 0x1, 0x80) // ICH9 ACPI
IO (Decode16, DEFAULT_GPIOBASE, DEFAULT_GPIOBASE, 0x1, 0x40) // ICH9 GPIO
})
}
Device (RTC) // Real Time Clock
{
Name (_HID, EISAID("PNP0B00"))
Name (_CRS, ResourceTemplate()
{
IO (Decode16, 0x70, 0x70, 1, 8)
// Disable as Windows doesn't like it, and systems don't seem to use it.
// IRQNoFlags() { 8 }
})
}
Device (TIMR) // Intel 8254 timer
{
Name(_HID, EISAID("PNP0100"))
Name(_CRS, ResourceTemplate()
{
IO (Decode16, 0x40, 0x40, 0x01, 0x04)
IO (Decode16, 0x50, 0x50, 0x10, 0x04)
IRQNoFlags() {0}
})
}
#include "acpi/superio.asl"
Device (PS2K) // Keyboard
{
Name(_HID, EISAID("PNP0303"))
Name(_CID, EISAID("PNP030B"))
Name(_CRS, ResourceTemplate()
{
IO (Decode16, 0x60, 0x60, 0x01, 0x01)
IO (Decode16, 0x64, 0x64, 0x01, 0x01)
IRQ (Edge, ActiveHigh, Exclusive) { 0x01 } // IRQ 1
})
Method (_STA, 0)
{
Return (0xf)
}
}
Device (PS2M) // Mouse
{
Name(_HID, EISAID("PNP0F13"))
Name(_CRS, ResourceTemplate()
{
IRQ (Edge, ActiveHigh, Exclusive) { 0x0c } // IRQ 12
})
Method(_STA, 0)
{
Return (0xf)
}
}
#ifdef ENABLE_FDC
Device (FDC0) // Floppy controller
{
Name (_HID, EisaId ("PNP0700"))
Method (_STA, 0, NotSerialized)
{
Return (0x0f) // FIXME
}
Name(_CRS, ResourceTemplate()
{
IO (Decode16, 0x03F0, 0x03F0, 0x01, 0x06)
IO (Decode16, 0x03F7, 0x03F7, 0x01, 0x01)
IRQNoFlags () {6}
DMA (Compatibility, NotBusMaster, Transfer8) {2}
})
Name(_PRS, ResourceTemplate()
{
IO (Decode16, 0x03F0, 0x03F0, 0x01, 0x06)
IO (Decode16, 0x03F7, 0x03F7, 0x01, 0x01)
IRQNoFlags () {6}
DMA (Compatibility, NotBusMaster, Transfer8) {2}
})
}
#endif
}

View File

@ -0,0 +1,71 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2009 coresystems GmbH
*
* 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.
*
* 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.
*/
// Intel PCI to PCI bridge 0:1e.0
Device (PCIB)
{
Name (_ADR, 0x001e0000)
Device (SLT1)
{
Name (_ADR, 0x00000000)
Name (_PRW, Package(){ 11, 4 })
}
Device (SLT2)
{
Name (_ADR, 0x00010000)
Name (_PRW, Package(){ 11, 4 })
}
Device (SLT3)
{
Name (_ADR, 0x00020000)
Name (_PRW, Package(){ 11, 4 })
}
Device (SLT6)
{
Name (_ADR, 0x00050000)
Name (_PRW, Package(){ 11, 4 })
}
Device (LANC)
{
Name (_ADR, 0x00080000)
Name (_PRW, Package(){ 11, 3 })
}
Device (LANR)
{
Name (_ADR, 0x00000000)
Name (_PRW, Package(){ 11, 3 })
}
// TODO: How many slots, where?
// PCI Interrupt Routing.
// If PICM is set, interrupts are routed over the i8259, otherwise
// over the IOAPIC. (Really? If they're above 15 they need to be routed
// fixed over the IOAPIC?)
Method (_PRT)
{
#include "acpi/ich9_pci_irqs.asl"
}
}

View File

@ -0,0 +1,179 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2009 coresystems GmbH
*
* 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.
*
* 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.
*/
/* Intel i82801G PCIe support */
// PCI Express Ports
Device (RP01)
{
NAME(_ADR, 0x001c0000) // FIXME: Have a macro for PCI Devices -> ACPI notation?
#include "pcie_port.asl"
Method(_PRT)
{
If (PICM) {
Return (Package() {
Package() { 0x0000ffff, 0, 0, 16 },
Package() { 0x0000ffff, 1, 0, 17 },
Package() { 0x0000ffff, 2, 0, 18 },
Package() { 0x0000ffff, 3, 0, 19 }
})
} Else {
Return (Package() {
Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKA, 0 },
Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKB, 0 },
Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKC, 0 },
Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKD, 0 }
})
}
}
}
Device (RP02)
{
NAME(_ADR, 0x001c0001) // FIXME: Have a macro for PCI Devices -> ACPI notation?
#include "pcie_port.asl"
Method(_PRT)
{
If (PICM) {
Return (Package() {
Package() { 0x0000ffff, 0, 0, 17 },
Package() { 0x0000ffff, 1, 0, 18 },
Package() { 0x0000ffff, 2, 0, 19 },
Package() { 0x0000ffff, 3, 0, 16 }
})
} Else {
Return (Package() {
Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKB, 0 },
Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKC, 0 },
Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKD, 0 },
Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKA, 0 }
})
}
}
}
Device (RP03)
{
NAME(_ADR, 0x001c0002) // FIXME: Have a macro for PCI Devices -> ACPI notation?
#include "pcie_port.asl"
Method(_PRT)
{
If (PICM) {
Return (Package() {
Package() { 0x0000ffff, 0, 0, 18 },
Package() { 0x0000ffff, 1, 0, 19 },
Package() { 0x0000ffff, 2, 0, 16 },
Package() { 0x0000ffff, 3, 0, 17 }
})
} Else {
Return (Package() {
Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKC, 0 },
Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKD, 0 },
Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKA, 0 },
Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKB, 0 }
})
}
}
}
Device (RP04)
{
NAME(_ADR, 0x001c0003) // FIXME: Have a macro for PCI Devices -> ACPI notation?
#include "pcie_port.asl"
Method(_PRT)
{
If (PICM) {
Return (Package() {
Package() { 0x0000ffff, 0, 0, 19 },
Package() { 0x0000ffff, 1, 0, 16 },
Package() { 0x0000ffff, 2, 0, 17 },
Package() { 0x0000ffff, 3, 0, 18 }
})
} Else {
Return (Package() {
Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKD, 0 },
Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKA, 0 },
Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKB, 0 },
Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKC, 0 }
})
}
}
}
Device (RP05)
{
NAME(_ADR, 0x001c0004) // FIXME: Have a macro for PCI Devices -> ACPI notation?
#include "pcie_port.asl"
Method(_PRT)
{
If (PICM) {
Return (Package() {
Package() { 0x0000ffff, 0, 0, 16 },
Package() { 0x0000ffff, 1, 0, 17 },
Package() { 0x0000ffff, 2, 0, 18 },
Package() { 0x0000ffff, 3, 0, 19 }
})
} Else {
Return (Package() {
Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKA, 0 },
Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKB, 0 },
Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKC, 0 },
Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKD, 0 }
})
}
}
}
Device (RP06)
{
NAME(_ADR, 0x001c0005) // FIXME: Have a macro for PCI Devices -> ACPI notation?
#include "pcie_port.asl"
Method(_PRT)
{
If (PICM) {
Return (Package() {
Package() { 0x0000ffff, 0, 0, 17 },
Package() { 0x0000ffff, 1, 0, 18 },
Package() { 0x0000ffff, 2, 0, 19 },
Package() { 0x0000ffff, 3, 0, 16 }
})
} Else {
Return (Package() {
Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKB, 0 },
Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKC, 0 },
Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKD, 0 },
Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKA, 0 }
})
}
}
}

View File

@ -0,0 +1,31 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 The Chromium OS Authors. All Rights Reserved.
*
* 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.
*
* 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.
*/
/* Included in each PCIe Root Port device */
OperationRegion (RPCS, PCI_Config, 0x00, 0xFF)
Field (RPCS, AnyAcc, NoLock, Preserve)
{
Offset (0x4c), // Link Capabilities
, 24,
RPPN, 8, // Root Port Number
Offset (0x5A),
, 3,
PDC, 1,
Offset (0xDF),
, 6,
HPCS, 1,
}

View File

@ -0,0 +1,136 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2009 coresystems GmbH
*
* 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.
*
* 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.
*/
// Note: Some BIOSes put the S-ATA code into an SSDT to make it easily
// pluggable
// Intel SATA Controller 0:1f.2
Device (AHC1)
{
Name (_ADR, 0x001f0002)
Device (PRID)
{
Name (_ADR, 0)
// Get Timing Mode
Method (_GTM)
{
Name(PBUF, Buffer(20) {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 })
CreateDwordField (PBUF, 0, PIO0)
CreateDwordField (PBUF, 4, DMA0)
CreateDwordField (PBUF, 8, PIO1)
CreateDwordField (PBUF, 12, DMA1)
CreateDwordField (PBUF, 16, FLAG)
// TODO fill return structure
Return (PBUF)
}
// Set Timing Mode
Method (_STM, 3)
{
CreateDwordField (Arg0, 0, PIO0)
CreateDwordField (Arg0, 4, DMA0)
CreateDwordField (Arg0, 8, PIO1)
CreateDwordField (Arg0, 12, DMA1)
CreateDwordField (Arg0, 16, FLAG)
// TODO: Do the deed
}
Device (DSK0)
{
Name (_ADR, 0)
// TODO: _RMV ?
// TODO: _GTF ?
}
Device (DSK1)
{
Name (_ADR, 1)
// TODO: _RMV ?
// TODO: _GTF ?
}
}
}
// Intel SATA Controller 0:1f.5
Device (AHC2)
{
Name (_ADR, 0x001f0005)
Device (PRID)
{
Name (_ADR, 0)
// Get Timing Mode
Method (_GTM)
{
Name(PBUF, Buffer(20) {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 })
CreateDwordField (PBUF, 0, PIO0)
CreateDwordField (PBUF, 4, DMA0)
CreateDwordField (PBUF, 8, PIO1)
CreateDwordField (PBUF, 12, DMA1)
CreateDwordField (PBUF, 16, FLAG)
// TODO fill return structure
Return (PBUF)
}
// Set Timing Mode
Method (_STM, 3)
{
CreateDwordField (Arg0, 0, PIO0)
CreateDwordField (Arg0, 4, DMA0)
CreateDwordField (Arg0, 8, PIO1)
CreateDwordField (Arg0, 12, DMA1)
CreateDwordField (Arg0, 16, FLAG)
// TODO: Do the deed
}
Device (DSK0)
{
Name (_ADR, 0)
// TODO: _RMV ?
// TODO: _GTF ?
}
Device (DSK1)
{
Name (_ADR, 1)
// TODO: _RMV ?
// TODO: _GTF ?
}
}
}

View File

@ -0,0 +1,24 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2009 coresystems GmbH
*
* 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.
*
* 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.
*/
Name(\_S0, Package(){0x0,0x0,0x0,0x0})
#if !CONFIG_HAVE_ACPI_RESUME
Name(\_S1, Package(){0x1,0x0,0x0,0x0})
#else
Name(\_S3, Package(){0x5,0x0,0x0,0x0})
#endif
Name(\_S4, Package(){0x6,0x0,0x0,0x0})
Name(\_S5, Package(){0x7,0x0,0x0,0x0})

View File

@ -0,0 +1,236 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2009 coresystems GmbH
*
* 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.
*
* 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.
*/
// Intel SMBus Controller 0:1f.3
Device (SBUS)
{
Name (_ADR, 0x001f0003)
#ifdef ENABLE_SMBUS_METHODS
OperationRegion (SMBP, PCI_Config, 0x00, 0x100)
Field(SMBP, DWordAcc, NoLock, Preserve)
{
Offset(0x40),
, 2,
I2CE, 1
}
OperationRegion (SMBI, SystemIO, 0x400, 0x20)
Field (SMBI, ByteAcc, NoLock, Preserve)
{
HSTS, 8, // Host Status
, 8,
HCNT, 8, // Host Control
HCMD, 8, // Host Command
TXSA, 8, // Transmit Slave Address
DAT0, 8, // Host Data 0
DAT1, 8, // Host Data 1
HBDB, 8, // Host Block Data Byte
PECK, 8, // Packet Error Check
RXSA, 8, // Receive Slave Address
RXDA, 16, // Receive Slave Data
AUXS, 8, // Auxiliary Status
AUXC, 8, // Auxiliary Control
SLPC, 8, // SMLink Pin Control
SBPC, 8, // SMBus Pin Control
SSTS, 8, // Slave Status
SCMD, 8, // Slave Command
NADR, 8, // Notify Device Address
NDLB, 8, // Notify Data Low Byte
NDLH, 8, // Notify Data High Byte
}
// Kill all SMBus communication
Method (KILL, 0, Serialized)
{
Or (HCNT, 0x02, HCNT) // Send Kill
Or (HSTS, 0xff, HSTS) // Clean Status
}
// Check if last operation completed
// return Failure = 0, Success = 1
Method (CMPL, 0, Serialized)
{
Store (4000, Local0) // Timeout 200ms in 50us steps
While (Local0) {
If (And(HSTS, 0x02)) { // Completion Status?
Return (1) // Operation Completed
} Else {
Stall (50)
Decrement (Local0)
If (LEqual(Local0, 0)) {
KILL()
}
}
}
Return (0) // Failure
}
// Wait for SMBus to become ready
Method (SRDY, 0, Serialized)
{
Store (200, Local0) // Timeout 200ms
While (Local0) {
If (And(HSTS, 0x40)) { // IN_USE?
Sleep(1) // Wait 1ms
Decrement(Local0) // timeout--
If (LEqual(Local0, 0)) {
Return (1)
}
} Else {
Store (0, Local0) // We're ready
}
}
Store (4000, Local0) // Timeout 200ms (50us * 4000)
While (Local0) {
If (And (HSTS, 0x01)) { // Host Busy?
Stall(50) // Wait 50us
Decrement(Local0) // timeout--
If (LEqual(Local0, 0)) {
KILL()
}
} Else {
Return (0) // Success
}
}
Return (1) // Failure
}
// SMBus Send Byte
// Arg0: Address
// Arg1: Data
// Return: 1 = Success, 0=Failure
Method (SSXB, 2, Serialized)
{
// Is the SMBus Controller Ready?
If (SRDY()) {
Return (0)
}
// Send Byte
Store (0, I2CE) // SMBus Enable
Store (0xbf, HSTS)
Store (Arg0, TXSA) // Write Address
Store (Arg1, HCMD) // Write Data
Store (0x48, HCNT) // Start + Byte Data Protocol
If (CMPL()) {
Or (HSTS, 0xff, HSTS) // Clean up
Return (1) // Success
}
Return (0)
}
// SMBus Receive Byte
// Arg0: Address
// Return: 0xffff = Failure, Data (8bit) = Success
Method (SRXB, 2, Serialized)
{
// Is the SMBus Controller Ready?
If (SRDY()) {
Return (0xffff)
}
// Receive Byte
Store (0, I2CE) // SMBus Enable
Store (0xbf, HSTS)
Store (Or (Arg0, 1), TXSA) // Write Address
Store (0x44, HCNT) // Start
If (CMPL()) {
Or (HSTS, 0xff, HSTS) // Clean up
Return (DAT0) // Success
}
Return (0xffff)
}
// SMBus Write Byte
// Arg0: Address
// Arg1: Command
// Arg2: Data
// Return: 1 = Success, 0=Failure
Method (SWRB, 3, Serialized)
{
// Is the SMBus Controller Ready?
If (SRDY()) {
Return (0)
}
// Send Byte
Store (0, I2CE) // SMBus Enable
Store (0xbf, HSTS)
Store (Arg0, TXSA) // Write Address
Store (Arg1, HCMD) // Write Command
Store (Arg2, DAT0) // Write Data
Store (0x48, HCNT) // Start + Byte Protocol
If (CMPL()) {
Or (HSTS, 0xff, HSTS) // Clean up
Return (1) // Success
}
Return (0)
}
// SMBus Read Byte
// Arg0: Address
// Arg1: Command
// Return: 0xffff = Failure, Data (8bit) = Success
Method (SRDB, 2, Serialized)
{
// Is the SMBus Controller Ready?
If (SRDY()) {
Return (0xffff)
}
// Receive Byte
Store (0, I2CE) // SMBus Enable
Store (0xbf, HSTS)
Store (Or (Arg0, 1), TXSA) // Write Address
Store (Arg1, HCMD) // Command
Store (0x48, HCNT) // Start
If (CMPL()) {
Or (HSTS, 0xff, HSTS) // Clean up
Return (DAT0) // Success
}
Return (0xffff)
}
#endif
}

View File

@ -0,0 +1,324 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2009 coresystems GmbH
*
* 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.
*
* 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.
*/
/* Intel i82801I USB support */
// USB Controller 0:1d.0
Device (USB1)
{
Name(_ADR, 0x001d0000)
OperationRegion(U01P, PCI_Config, 0, 256)
Field(U01P, DWordAcc, NoLock, Preserve)
{
Offset(0xc4),
U1WE, 2 // USB Wake Enable
}
Name (_PRW, Package(){ 3, 4 }) // Power Resources for Wake
Method (_PSW, 1) // Power State Wake method
{
// USB Controller can wake OS from Sleep State
If (Arg0) {
Store (3, U1WE)
} Else {
Store (0, U1WE)
}
}
// Leave USB ports on for to allow Wake from USB
Method(_S3D,0) // Highest D State in S3 State
{
Return (2)
}
Method(_S4D,0) // Highest D State in S4 State
{
Return (2)
}
}
// USB Controller 0:1d.1
Device (USB2)
{
Name(_ADR, 0x001d0001)
OperationRegion(U02P, PCI_Config, 0, 256)
Field(U02P, DWordAcc, NoLock, Preserve)
{
Offset(0xc4),
U2WE, 2 // USB Wake Enable
}
Name (_PRW, Package(){ 3, 4 }) // Power Resources for Wake
Method (_PSW, 1) // Power State Wake method
{
// USB Controller can wake OS from Sleep State
If (Arg0) {
Store (3, U2WE)
} Else {
Store (0, U2WE)
}
}
// Leave USB ports on for to allow Wake from USB
Method(_S3D,0) // Highest D State in S3 State
{
Return (2)
}
Method(_S4D,0) // Highest D State in S4 State
{
Return (2)
}
}
// USB Controller 0:1d.2
Device (USB3)
{
Name(_ADR, 0x001d0002)
OperationRegion(U03P, PCI_Config, 0, 256)
Field(U03P, DWordAcc, NoLock, Preserve)
{
Offset(0xc4),
U3WE, 2 // USB Wake Enable
}
Name (_PRW, Package(){ 3, 4 }) // Power Resources for Wake
Method (_PSW, 1) // Power State Wake method
{
// USB Controller can wake OS from Sleep State
If (Arg0) {
Store (3, U3WE)
} Else {
Store (0, U3WE)
}
}
// Leave USB ports on for to allow Wake from USB
Method(_S3D,0) // Highest D State in S3 State
{
Return (2)
}
Method(_S4D,0) // Highest D State in S4 State
{
Return (2)
}
}
// EHCI Controller 0:1d.7
Device (EHC1)
{
Name(_ADR, 0x001d0007)
Name (_PRW, Package(){ 13, 4 }) // Power Resources for Wake
// Leave USB ports on for to allow Wake from USB
Method(_S3D,0) // Highest D State in S3 State
{
Return (2)
}
Method(_S4D,0) // Highest D State in S4 State
{
Return (2)
}
Device (HUB7)
{
Name (_ADR, 0x00000000)
// How many are there?
Device (PRT1) { Name (_ADR, 1) } // USB Port 0
Device (PRT2) { Name (_ADR, 2) } // USB Port 1
Device (PRT3) { Name (_ADR, 3) } // USB Port 2
Device (PRT4) { Name (_ADR, 4) } // USB Port 3
Device (PRT5) { Name (_ADR, 5) } // USB Port 4
Device (PRT6) { Name (_ADR, 6) } // USB Port 5
}
}
// USB Controller 0:1a.0
Device (USB4)
{
Name(_ADR, 0x001a0000)
OperationRegion(U01P, PCI_Config, 0, 256)
Field(U01P, DWordAcc, NoLock, Preserve)
{
Offset(0xc4),
U1WE, 2 // USB Wake Enable
}
Name (_PRW, Package(){ 3, 4 }) // Power Resources for Wake
Method (_PSW, 1) // Power State Wake method
{
// USB Controller can wake OS from Sleep State
If (Arg0) {
Store (3, U1WE)
} Else {
Store (0, U1WE)
}
}
// Leave USB ports on for to allow Wake from USB
Method(_S3D,0) // Highest D State in S3 State
{
Return (2)
}
Method(_S4D,0) // Highest D State in S4 State
{
Return (2)
}
}
// USB Controller 0:1a.1
Device (USB5)
{
Name(_ADR, 0x001a0001)
OperationRegion(U02P, PCI_Config, 0, 256)
Field(U02P, DWordAcc, NoLock, Preserve)
{
Offset(0xc4),
U2WE, 2 // USB Wake Enable
}
Name (_PRW, Package(){ 3, 4 }) // Power Resources for Wake
Method (_PSW, 1) // Power State Wake method
{
// USB Controller can wake OS from Sleep State
If (Arg0) {
Store (3, U2WE)
} Else {
Store (0, U2WE)
}
}
// Leave USB ports on for to allow Wake from USB
Method(_S3D,0) // Highest D State in S3 State
{
Return (2)
}
Method(_S4D,0) // Highest D State in S4 State
{
Return (2)
}
}
// USB Controller 0:1a.2
Device (USB6)
{
Name(_ADR, 0x001a0002)
OperationRegion(U03P, PCI_Config, 0, 256)
Field(U03P, DWordAcc, NoLock, Preserve)
{
Offset(0xc4),
U3WE, 2 // USB Wake Enable
}
Name (_PRW, Package(){ 3, 4 }) // Power Resources for Wake
Method (_PSW, 1) // Power State Wake method
{
// USB Controller can wake OS from Sleep State
If (Arg0) {
Store (3, U3WE)
} Else {
Store (0, U3WE)
}
}
// Leave USB ports on for to allow Wake from USB
Method(_S3D,0) // Highest D State in S3 State
{
Return (2)
}
Method(_S4D,0) // Highest D State in S4 State
{
Return (2)
}
}
// EHCI Controller 0:1a.7
Device (EHC2)
{
Name(_ADR, 0x001a0007)
Name (_PRW, Package(){ 13, 4 }) // Power Resources for Wake
// Leave USB ports on for to allow Wake from USB
Method(_S3D,0) // Highest D State in S3 State
{
Return (2)
}
Method(_S4D,0) // Highest D State in S4 State
{
Return (2)
}
Device (HUB7)
{
Name (_ADR, 0x00000000)
// How many are there?
Device (PRT1) { Name (_ADR, 1) } // USB Port 0
Device (PRT2) { Name (_ADR, 2) } // USB Port 1
Device (PRT3) { Name (_ADR, 3) } // USB Port 2
Device (PRT4) { Name (_ADR, 4) } // USB Port 3
Device (PRT5) { Name (_ADR, 5) } // USB Port 4
Device (PRT6) { Name (_ADR, 6) } // USB Port 5
}
}

View File

@ -0,0 +1,34 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2011 Sven Schnelle <svens@stackframe.org>
*
* 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.
*
* 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.
*/
#include <arch/io.h>
static void enable_spi_prefetch(void)
{
u8 reg8;
pci_devfn_t dev;
dev = PCI_DEV(0, 0x1f, 0);
reg8 = pci_read_config8(dev, 0xdc);
reg8 &= ~(3 << 2);
reg8 |= (2 << 2); /* Prefetching and Caching Enabled */
pci_write_config8(dev, 0xdc, reg8);
}
static void bootblock_southbridge_init(void)
{
enable_spi_prefetch();
}

View File

@ -0,0 +1,91 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
* 2012 secunet Security Networks AG
*
* 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.
*
* 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.
*/
#ifndef SOUTHBRIDGE_INTEL_I82801IX_CHIP_H
#define SOUTHBRIDGE_INTEL_I82801IX_CHIP_H
enum {
THTL_DEF = 0, THTL_87_5 = 1, THTL_75_0 = 2, THTL_62_5 = 3,
THTL_50_0 = 4, THTL_37_5 = 5, THTL_25_0 = 6, THTL_12_5 = 7
};
struct southbridge_intel_i82801ix_config {
/**
* Interrupt Routing configuration
* If bit7 is 1, the interrupt is disabled.
*/
uint8_t pirqa_routing;
uint8_t pirqb_routing;
uint8_t pirqc_routing;
uint8_t pirqd_routing;
uint8_t pirqe_routing;
uint8_t pirqf_routing;
uint8_t pirqg_routing;
uint8_t pirqh_routing;
/**
* GPI Routing configuration
*
* Only the lower two bits have a meaning:
* 00: No effect
* 01: SMI# (if corresponding ALT_GPI_SMI_EN bit is also set)
* 10: SCI (if corresponding GPIO_EN bit is also set)
* 11: reserved
*/
uint8_t gpi0_routing;
uint8_t gpi1_routing;
uint8_t gpi2_routing;
uint8_t gpi3_routing;
uint8_t gpi4_routing;
uint8_t gpi5_routing;
uint8_t gpi6_routing;
uint8_t gpi7_routing;
uint8_t gpi8_routing;
uint8_t gpi9_routing;
uint8_t gpi10_routing;
uint8_t gpi11_routing;
uint8_t gpi12_routing;
uint8_t gpi13_routing;
uint8_t gpi14_routing;
uint8_t gpi15_routing;
uint32_t gpe0_en;
uint16_t alt_gp_smi_en;
/* IDE configuration */
uint8_t sata_port_map : 6;
int sata_clock_request : 1;
int sata_traffic_monitor : 1;
int c4onc3_enable:1;
int c5_enable : 1;
int c6_enable : 1;
int throttle_duty : 3;
/* Bit mask to tell whether a PCIe slot is implemented as slot. */
int pcie_slot_implemented : 6;
/* Power limits for PCIe ports. Values are in 10^(-scale) watts. */
struct {
uint8_t value : 8;
uint8_t scale : 2;
} pcie_power_limits[6];
uint8_t pcie_hotplug_map[8];
};
#endif /* SOUTHBRIDGE_INTEL_I82801IX_CHIP_H */

View File

@ -0,0 +1,141 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 secunet Security Networks AG
*
* 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.
*
* 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.
*/
#include <arch/io.h>
#include <device/pci_def.h>
#include <console/console.h>
#include <northbridge/intel/gm45/gm45.h>
#include "i82801ix.h"
/* VC1 Port Arbitration Table */
static const u8 vc1_pat[] = {
0x0f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00,
0xf0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0f,
0x00, 0x00, 0x00, 0x00,
0x00, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x0f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00,
0xf0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0f,
0x00, 0x00, 0x00, 0x00,
0x00, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
void i82801ix_dmi_setup(void)
{
int i;
u32 reg32;
RCBA32(RCBA_V1CAP) = (RCBA32(RCBA_V1CAP) & ~(0x7f<<16)) | (0x12<<16);
RCBA32(0x0088) = 0x00109000;
RCBA16(0x01fc) = 0x060b;
RCBA32(0x01f4) = 0x86000040;
RCBA8 (0x0220) = 0x45;
RCBA32(0x2024) &= ~(1 << 7);
/* VC1 setup for isochronous transfers: */
/* Set VC1 virtual channel id to 1. */
RCBA32(RCBA_V1CTL) = (RCBA32(RCBA_V1CTL) & ~(0x7 << 24)) | (0x1 << 24);
/* Enable TC7 traffic on VC1. */
RCBA32(RCBA_V1CTL) = (RCBA32(RCBA_V1CTL) & ~(0x7f << 1)) | (1 << 7);
/* Disable TC7-TC1 traffic on VC0. */
RCBA32(RCBA_V0CTL) &= ~(0x7f << 1);
/* TC7-TC1 traffic on PCIe root ports will be disabled in pci driver. */
/* Set table type to time-based WRR. */
RCBA32(RCBA_V1CTL) = (RCBA32(RCBA_V1CTL) & ~(0x7 << 17)) | (0x4 << 17);
/* Program port arbitration table. */
for (i = 0; i < sizeof(vc1_pat); ++i)
RCBA8(RCBA_PAT + i) = vc1_pat[i];
/* Load port arbitration table. */
RCBA32(RCBA_V1CTL) |= (1 << 16);
/* Enable VC1. */
RCBA32(RCBA_V1CTL) |= (1 << 31);
/* Setup RCRB: */
/* Set component id to 2 for southbridge, northbridge has id 1. */
RCBA8(RCBA_ESD + 2) = 2;
/* Set target port number and target component id of the northbridge. */
RCBA8(RCBA_ULD + 3) = 1;
RCBA8(RCBA_ULD + 2) = 1;
/* Set target rcrb base address, i.e. DMIBAR. */
RCBA32(RCBA_ULBA) = (uintptr_t)DEFAULT_DMIBAR;
/* Enable ASPM. */
if (LPC_IS_MOBILE(PCI_DEV(0, 0x1f, 0))) {
reg32 = RCBA32(RCBA_DMC);
/* Enable mobile specific power saving (set this first). */
reg32 = (reg32 & ~(3 << 10)) | (1 << 10);
RCBA32(RCBA_DMC) = reg32;
/* Enable DMI power savings. */
reg32 |= (1 << 19);
RCBA32(RCBA_DMC) = reg32;
/* Advertise L0s and L1. */
RCBA32(RCBA_LCAP) |= (3 << 10);
/* Enable L0s and L1. */
RCBA32(RCBA_LCTL) |= (3 << 0);
} else {
/* Enable DMI power savings. */
RCBA32(RCBA_DMC) |= (1 << 19);
/* Advertise L0s only. */
RCBA32(RCBA_LCAP) = (RCBA32(RCBA_LCAP) & ~(3<<10)) | (1<<10);
/* Enable L0s only. */
RCBA32(RCBA_LCTL) = (RCBA32(RCBA_LCTL) & ~(3<< 0)) | (1<< 0);
}
}
/* Should be called after VC1 has been enabled on both sides. */
void i82801ix_dmi_poll_vc1(void)
{
int timeout;
timeout = 0x7ffff;
printk(BIOS_DEBUG, "ICH9 waits for VC1 negotiation... ");
while ((RCBA32(RCBA_V1STS) & (1 << 1)) && --timeout) {}
if (!timeout)
printk(BIOS_DEBUG, "timeout!\n");
else
printk(BIOS_DEBUG, "done.\n");
/* Check for x2 DMI link. */
if (((RCBA16(RCBA_LSTS) >> 4) & 0x3f) == 2) {
printk(BIOS_DEBUG, "x2 DMI link detected.\n");
RCBA32(0x2024) = (RCBA32(0x2024) & ~(7 << 21)) | (3 << 21);
RCBA16(0x20c4) |= (1 << 15);
RCBA16(0x20e4) |= (1 << 15);
/* TODO: Maybe we have to save and
restore these settings across S3. */
}
timeout = 0x7ffff;
printk(BIOS_DEBUG, "ICH9 waits for port arbitration table update... ");
while ((RCBA32(RCBA_V1STS) & (1 << 0)) && --timeout) {}
if (!timeout)
printk(BIOS_DEBUG, "timeout!\n");
else
printk(BIOS_DEBUG, "done.\n");
}

View File

@ -0,0 +1,59 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 secunet Security Networks AG
*
* 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.
*
* 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.
*/
#include <arch/io.h>
#include "i82801ix.h"
void i82801ix_early_init(void)
{
const pci_devfn_t d31f0 = PCI_DEV(0, 0x1f, 0);
/* Set up RCBA. */
pci_write_config32(d31f0, D31F0_RCBA, (uintptr_t)DEFAULT_RCBA | 1);
/* Set up PMBASE. */
pci_write_config32(d31f0, D31F0_PMBASE, DEFAULT_PMBASE | 1);
/* Enable PMBASE. */
pci_write_config8(d31f0, D31F0_ACPI_CNTL, 0x80);
/* Set up GPIOBASE. */
pci_write_config32(d31f0, D31F0_GPIO_BASE, DEFAULT_GPIOBASE);
/* Enable GPIO. */
pci_write_config8(d31f0, D31F0_GPIO_CNTL,
pci_read_config8(d31f0, D31F0_GPIO_CNTL) | 0x10);
/* Reset watchdog. */
outw(0x0008, DEFAULT_TCOBASE + 0x04); /* R/WC, clear TCO caused SMI. */
outw(0x0002, DEFAULT_TCOBASE + 0x06); /* R/WC, clear second timeout. */
/* Enable upper 128bytes of CMOS. */
RCBA32(0x3400) = (1 << 2);
/* Initialize power management initialization
register early as it affects reboot behavior. */
/* Bit 20 activates global reset of host and ME on cf9 writes of 0x6
and 0xe (required if ME is disabled but present), bit 31 locks it.
The other bits are 'must write'. */
u8 reg8 = pci_read_config8(d31f0, 0xac);
reg8 |= (1 << 31) | (1 << 30) | (1 << 20) | (3 << 8);
pci_write_config8(d31f0, 0xac, reg8);
/* TODO: If RTC power failed, reset RTC state machine
(set, then reset RTC 0x0b bit7) */
/* TODO: Check power state bits in GEN_PMCON_2 (D31F0 0xa2)
before they get cleared. */
}

View File

@ -0,0 +1,58 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
* 2012 secunet Security Networks AG
*
* 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.
*
* 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.
*/
#include <arch/io.h>
#include <console/console.h>
#include <device/pci_ids.h>
#include <device/pci_def.h>
#include "i82801ix.h"
#include "smbus.h"
void enable_smbus(void)
{
pci_devfn_t dev;
/* Set the SMBus device statically. */
dev = PCI_DEV(0x0, 0x1f, 0x3);
/* Check to make sure we've got the right device. */
if (pci_read_config16(dev, 0x2) != 0x2930) {
die("SMBus controller not found!");
}
/* Set SMBus I/O base. */
pci_write_config32(dev, SMB_BASE,
SMBUS_IO_BASE | PCI_BASE_ADDRESS_SPACE_IO);
/* Set SMBus enable. */
pci_write_config8(dev, HOSTC, HST_EN);
/* Set SMBus I/O space enable. */
pci_write_config16(dev, PCI_COMMAND, PCI_COMMAND_IO);
/* Disable interrupt generation. */
outb(0, SMBUS_IO_BASE + SMBHSTCTL);
/* Clear any lingering errors, so transactions can run. */
outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
printk(BIOS_DEBUG, "SMBus controller enabled.\n");
}
int smbus_read_byte(unsigned device, unsigned address)
{
return do_smbus_read_byte(SMBUS_IO_BASE, device, address);
}

View File

@ -0,0 +1,319 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008 Advanced Micro Devices, Inc.
* Copyright (C) 2008-2009 coresystems GmbH
* Copyright (C) 2012 secunet Security Networks AG
*
* 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.
*
* 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.
*/
#include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <device/pci_ops.h>
#include <arch/io.h>
#include <delay.h>
#include <device/azalia_device.h>
#include "i82801ix.h"
#define HDA_ICII_REG 0x68
#define HDA_ICII_BUSY (1 << 0)
#define HDA_ICII_VALID (1 << 1)
typedef struct southbridge_intel_i82801ix_config config_t;
static int set_bits(void *port, u32 mask, u32 val)
{
u32 reg32;
int count;
/* Write (val & mask) to port */
val &= mask;
reg32 = read32(port);
reg32 &= ~mask;
reg32 |= val;
write32(port, reg32);
/* Wait for readback of register to
* match what was just written to it
*/
count = 50;
do {
/* Wait 1ms based on BKDG wait time */
mdelay(1);
reg32 = read32(port);
reg32 &= mask;
} while ((reg32 != val) && --count);
/* Timeout occurred */
if (!count)
return -1;
return 0;
}
static int codec_detect(u8 *base)
{
u32 reg32;
/* Set Bit0 to 0 to enter reset state (BAR + 0x8)[0] */
if (set_bits(base + 0x08, 1, 0) == -1)
goto no_codec;
/* Set Bit 0 to 1 to exit reset state (BAR + 0x8)[0] */
if (set_bits(base + 0x08, 1, 1) == -1)
goto no_codec;
/* Read in Codec location (BAR + 0xe)[2..0]*/
reg32 = read32(base + 0xe);
reg32 &= 0x0f;
if (!reg32)
goto no_codec;
return reg32;
no_codec:
/* Codec Not found */
/* Put HDA back in reset (BAR + 0x8) [0] */
set_bits(base + 0x08, 1, 0);
printk(BIOS_DEBUG, "Azalia: No codec!\n");
return 0;
}
static u32 find_verb(struct device *dev, u32 viddid, const u32 ** verb)
{
int idx=0;
while (idx < (cim_verb_data_size / sizeof(u32))) {
u32 verb_size = 4 * cim_verb_data[idx+2]; // in u32
if (cim_verb_data[idx] != viddid) {
idx += verb_size + 3; // skip verb + header
continue;
}
*verb = &cim_verb_data[idx+3];
return verb_size;
}
/* Not all codecs need to load another verb */
return 0;
}
/**
* Wait 50usec for the codec to indicate it is ready
* no response would imply that the codec is non-operative
*/
static int wait_for_ready(u8 *base)
{
/* Use a 50 usec timeout - the Linux kernel uses the
* same duration */
int timeout = 50;
while (timeout--) {
u32 reg32 = read32(base + HDA_ICII_REG);
if (!(reg32 & HDA_ICII_BUSY))
return 0;
udelay(1);
}
return -1;
}
/**
* Wait 50usec for the codec to indicate that it accepted
* the previous command. No response would imply that the code
* is non-operative
*/
static int wait_for_valid(u8 *base)
{
u32 reg32;
/* Send the verb to the codec */
reg32 = read32(base + 0x68);
reg32 |= (1 << 0) | (1 << 1);
write32(base + 0x68, reg32);
/* Use a 50 usec timeout - the Linux kernel uses the
* same duration */
int timeout = 50;
while (timeout--) {
reg32 = read32(base + HDA_ICII_REG);
if ((reg32 & (HDA_ICII_VALID | HDA_ICII_BUSY)) ==
HDA_ICII_VALID)
return 0;
udelay(1);
}
return -1;
}
static void codec_init(struct device *dev, u8 *base, int addr)
{
u32 reg32;
const u32 *verb;
u32 verb_size;
int i;
printk(BIOS_DEBUG, "HD Audio: Initializing codec #%d\n", addr);
/* 1 */
if (wait_for_ready(base) == -1)
return;
reg32 = (addr << 28) | 0x000f0000;
write32(base + 0x60, reg32);
if (wait_for_valid(base) == -1)
return;
reg32 = read32(base + 0x64);
/* 2 */
printk(BIOS_DEBUG, "Azalia: codec viddid: %08x\n", reg32);
verb_size = find_verb(dev, reg32, &verb);
if (!verb_size) {
printk(BIOS_DEBUG, "Azalia: No verb!\n");
return;
}
printk(BIOS_DEBUG, "Azalia: verb_size: %d\n", verb_size);
/* 3 */
for (i = 0; i < verb_size; i++) {
if (wait_for_ready(base) == -1)
return;
write32(base + 0x60, verb[i]);
if (wait_for_valid(base) == -1)
return;
}
printk(BIOS_DEBUG, "Azalia: verb loaded.\n");
}
static void codecs_init(struct device *dev, u8 *base, u32 codec_mask)
{
int i;
for (i = 2; i >= 0; i--) {
if (codec_mask & (1 << i))
codec_init(dev, base, i);
}
for (i = 0; i < pc_beep_verbs_size; i++) {
if (wait_for_ready(base) == -1)
return;
write32(base + 0x60, pc_beep_verbs[i]);
if (wait_for_valid(base) == -1)
return;
}
}
static void azalia_init(struct device *dev)
{
u8 *base;
struct resource *res;
u32 codec_mask;
u8 reg8;
u32 reg32;
// ESD
reg32 = pci_read_config32(dev, 0x134);
reg32 &= 0xff00ffff;
reg32 |= (2 << 16);
pci_write_config32(dev, 0x134, reg32);
// Link1 description
reg32 = pci_read_config32(dev, 0x140);
reg32 &= 0xff00ffff;
reg32 |= (2 << 16);
pci_write_config32(dev, 0x140, reg32);
// Port VC0 Resource Control Register
reg32 = pci_read_config32(dev, 0x114);
reg32 &= 0xffffff00;
reg32 |= 1;
pci_write_config32(dev, 0x114, reg32);
// VCi traffic class
reg8 = pci_read_config8(dev, 0x44);
reg8 |= (7 << 0); // TC7
pci_write_config8(dev, 0x44, reg8);
// VCi Resource Control
reg32 = pci_read_config32(dev, 0x120);
reg32 |= (1 << 31);
reg32 |= (1 << 24); // VCi ID
reg32 |= (0x80 << 0); // VCi map
pci_write_config32(dev, 0x120, reg32);
/* Set Bus Master */
reg32 = pci_read_config32(dev, PCI_COMMAND);
pci_write_config32(dev, PCI_COMMAND, reg32 | PCI_COMMAND_MASTER);
reg8 = pci_read_config8(dev, 0x4d); // Docking Status
reg8 &= ~(1 << 7); // Docking not supported
pci_write_config8(dev, 0x4d, reg8);
/* Lock some R/WO bits by writing their current value. */
reg32 = pci_read_config32(dev, 0x74);
pci_write_config32(dev, 0x74, reg32);
res = find_resource(dev, 0x10);
if (!res)
return;
// NOTE this will break as soon as the Azalia get's a bar above
// 4G. Is there anything we can do about it?
base = res2mmio(res, 0, 0);
printk(BIOS_DEBUG, "Azalia: base = %08x\n", (u32)base);
codec_mask = codec_detect(base);
if (codec_mask) {
printk(BIOS_DEBUG, "Azalia: codec_mask = %02x\n", codec_mask);
codecs_init(dev, base, codec_mask);
}
}
static void azalia_set_subsystem(device_t dev, unsigned vendor, unsigned device)
{
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));
}
}
static struct pci_operations azalia_pci_ops = {
.set_subsystem = azalia_set_subsystem,
};
static struct device_operations azalia_ops = {
.read_resources = pci_dev_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.init = azalia_init,
.scan_bus = 0,
.ops_pci = &azalia_pci_ops,
};
/* ICH9DH/ICH9DO/ICH9R/ICH9/ICH9M-E/ICH9M */
static const struct pci_driver i82801ix_azalia __pci_driver = {
.ops = &azalia_ops,
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x293e,
};

View File

@ -0,0 +1,235 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
* 2012 secunet Security Networks AG
* (Written by Nico Huber <nico.huber@secunet.com> for secunet)
*
* 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.
*
* 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.
*/
#include <stdlib.h>
#include <arch/io.h>
#include <device/device.h>
#include <device/pci.h>
#include <console/console.h>
#include "i82801ix.h"
typedef struct southbridge_intel_i82801ix_config config_t;
static void i82801ix_enable_device(device_t dev)
{
u32 reg32;
/* Enable SERR */
reg32 = pci_read_config32(dev, PCI_COMMAND);
reg32 |= PCI_COMMAND_SERR;
pci_write_config32(dev, PCI_COMMAND, reg32);
}
static void i82801ix_early_settings(const config_t *const info)
{
/* Program FERR# as processor break event indicator. */
RCBA32(0x3410) |= (1 << 6);
/* BIOS must program... */
RCBA32(0x3430) = (RCBA32(0x3430) & ~(0x3 << 0)) | (0x2 << 0);
RCBA32(0x3418) |= (1 << 0);
RCBA32(0x350c) = (RCBA32(0x350c) & ~(0x3 << 26)) | (0x2 << 26);
RCBA32(0x2034) = (RCBA32(0x2034) & ~(0xf << 16)) | (0x5 << 16);
RCBA32(0x0f20) = (RCBA32(0x0f20) & ~(0xf << 16)) | (0x5 << 16);
RCBA32(0x1d40) |= (1 << 0);
RCBA32(0x352c) |= (3 << 16);
}
static void i82801ix_pcie_init(const config_t *const info)
{
device_t pciePort[6];
int i, slot_number = 1; /* Reserve slot number 0 for nb's PEG. */
u32 reg32;
/* PCIe - BIOS must program... */
for (i = 0; i < 6; ++i) {
pciePort[i] = dev_find_slot(0, PCI_DEVFN(0x1c, i));
if (!pciePort[i]) {
printk(BIOS_EMERG, "PCIe port 00:1c.%x", i);
die(" is not listed in devicetree.\n");
}
reg32 = pci_read_config32(pciePort[i], 0x300);
pci_write_config32(pciePort[i], 0x300, reg32 | (1 << 21));
pci_write_config8(pciePort[i], 0x324, 0x40);
}
if (LPC_IS_MOBILE(dev_find_slot(0, PCI_DEVFN(0x1f, 0)))) {
for (i = 0; i < 6; ++i) {
if (pciePort[i]->enabled) {
reg32 = pci_read_config32(pciePort[i], 0xe8);
reg32 |= 1;
pci_write_config32(pciePort[i], 0xe8, reg32);
}
}
}
for (i = 5; (i >= 0) && !pciePort[i]->enabled; --i) {
/* Only for the top disabled ports. */
reg32 = pci_read_config32(pciePort[i], 0x300);
reg32 |= 0x3 << 16;
pci_write_config32(pciePort[i], 0x300, reg32);
}
/* Set slot implemented, slot number and slot power limits. */
for (i = 0; i < 6; ++i) {
const device_t dev = pciePort[i];
u32 xcap = pci_read_config32(dev, D28Fx_XCAP);
if (info->pcie_slot_implemented & (1 << i))
xcap |= PCI_EXP_FLAGS_SLOT;
else
xcap &= ~PCI_EXP_FLAGS_SLOT;
pci_write_config32(dev, D28Fx_XCAP, xcap);
if (info->pcie_slot_implemented & (1 << i)) {
u32 slcap = pci_read_config32(dev, D28Fx_SLCAP);
slcap &= ~(0x1fff << 19);
slcap |= (slot_number++ << 19);
slcap &= ~(0x0003 << 16);
slcap |= (info->pcie_power_limits[i].scale << 16);
slcap &= ~(0x00ff << 7);
slcap |= (info->pcie_power_limits[i].value << 7);
pci_write_config32(dev, D28Fx_SLCAP, slcap);
}
}
/* Lock R/WO ASPM support bits. */
for (i = 0; i < 6; ++i) {
reg32 = pci_read_config32(pciePort[i], 0x4c);
pci_write_config32(pciePort[i], 0x4c, reg32);
}
}
static void i82801ix_ehci_init(void)
{
const device_t pciEHCI1 = dev_find_slot(0, PCI_DEVFN(0x1d, 7));
if (!pciEHCI1)
die("EHCI controller (00:1d.7) not listed in devicetree.\n");
const device_t pciEHCI2 = dev_find_slot(0, PCI_DEVFN(0x1a, 7));
if (!pciEHCI2)
die("EHCI controller (00:1a.7) not listed in devicetree.\n");
u32 reg32;
/* TODO: Maybe we have to save and
restore these settings across S3. */
reg32 = pci_read_config32(pciEHCI1, 0xfc);
pci_write_config32(pciEHCI1, 0xfc, (reg32 & ~(3 << 2)) |
(1 << 29) | (1 << 17) | (2 << 2));
reg32 = pci_read_config32(pciEHCI2, 0xfc);
pci_write_config32(pciEHCI2, 0xfc, (reg32 & ~(3 << 2)) |
(1 << 29) | (1 << 17) | (2 << 2));
}
static int i82801ix_function_disabled(const unsigned devfn)
{
const struct device *const dev = dev_find_slot(0, devfn);
if (!dev) {
printk(BIOS_EMERG,
"PCI device 00:%x.%x",
PCI_SLOT(devfn), PCI_FUNC(devfn));
die(" is not listed in devicetree.\n");
}
return !dev->enabled;
}
static void i82801ix_hide_functions(void)
{
int i;
u32 reg32;
/* FIXME: This works pretty good if the devicetree is consistent. But
some functions have to be disabled in right order and/or have
other constraints. */
if (i82801ix_function_disabled(PCI_DEVFN(0x19, 0)))
RCBA32(RCBA_BUC) |= BUC_LAND;
reg32 = RCBA32(RCBA_FD);
struct {
int devfn;
u32 mask;
} functions[] = {
{ PCI_DEVFN(0x1a, 0), FD_U4D }, /* UHCI #4 */
{ PCI_DEVFN(0x1a, 1), FD_U5D }, /* UHCI #5 */
{ PCI_DEVFN(0x1a, 2), FD_U6D }, /* UHCI #6 */
{ PCI_DEVFN(0x1a, 7), FD_EHCI2D }, /* EHCI #2 */
{ PCI_DEVFN(0x1b, 0), FD_HDAD }, /* HD Audio */
{ PCI_DEVFN(0x1c, 0), FD_PE1D }, /* PCIe #1 */
{ PCI_DEVFN(0x1c, 1), FD_PE2D }, /* PCIe #2 */
{ PCI_DEVFN(0x1c, 2), FD_PE3D }, /* PCIe #3 */
{ PCI_DEVFN(0x1c, 3), FD_PE4D }, /* PCIe #4 */
{ PCI_DEVFN(0x1c, 4), FD_PE5D }, /* PCIe #5 */
{ PCI_DEVFN(0x1c, 5), FD_PE6D }, /* PCIe #6 */
{ PCI_DEVFN(0x1d, 0), FD_U1D }, /* UHCI #1 */
{ PCI_DEVFN(0x1d, 1), FD_U2D }, /* UHCI #2 */
{ PCI_DEVFN(0x1d, 2), FD_U3D }, /* UHCI #3 */
{ PCI_DEVFN(0x1d, 7), FD_EHCI1D }, /* EHCI #1 */
{ PCI_DEVFN(0x1f, 0), FD_LBD }, /* LPC */
{ PCI_DEVFN(0x1f, 2), FD_SAD1 }, /* SATA #1 */
{ PCI_DEVFN(0x1f, 3), FD_SD }, /* SMBus */
{ PCI_DEVFN(0x1f, 5), FD_SAD2 }, /* SATA #2 */
{ PCI_DEVFN(0x1f, 6), FD_TTD }, /* Thermal Throttle */
};
for (i = 0; i < ARRAY_SIZE(functions); ++i) {
if (i82801ix_function_disabled(functions[i].devfn))
reg32 |= functions[i].mask;
}
RCBA32(RCBA_FD) = reg32;
RCBA32(RCBA_FD) |= (1 << 0); /* BIOS must write this... */
RCBA32(RCBA_FDSW) |= (1 << 7); /* Lock function-disable? */
/* Hide PCIe root port PCI functions. RPFN is partially R/WO. */
reg32 = RCBA32(RCBA_RPFN);
for (i = 0; i < 6; ++i) {
if (i82801ix_function_disabled(PCI_DEVFN(0x1c, i)))
reg32 |= (1 << ((i * 4) + 3));
}
RCBA32(RCBA_RPFN) = reg32;
/* Lock R/WO UHCI controller #6 remapping. */
RCBA32(RCBA_MAP) = RCBA32(RCBA_MAP);
}
static void i82801ix_init(void *chip_info)
{
const config_t *const info = (config_t *)chip_info;
printk(BIOS_DEBUG, "Initializing i82801ix southbridge...\n");
i82801ix_early_settings(info);
/* PCI Express setup. */
i82801ix_pcie_init(info);
/* EHCI configuration. */
i82801ix_ehci_init();
/* Now hide internal functions. We can't access them after this. */
i82801ix_hide_functions();
/* Reset watchdog timer. */
#if !CONFIG_HAVE_SMI_HANDLER
outw(0x0008, DEFAULT_TCOBASE + 0x12); /* Set higher timer value. */
#endif
outw(0x0000, DEFAULT_TCOBASE + 0x00); /* Update timer. */
}
struct chip_operations southbridge_intel_i82801ix_ops = {
CHIP_NAME("Intel ICH9/ICH9-M (82801Ix) Series Southbridge")
.enable_dev = i82801ix_enable_device,
.init = i82801ix_init,
};

View File

@ -0,0 +1,232 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
* Copyright (C) 2008-2009 coresystems GmbH
* 2012 secunet Security Networks AG
*
* 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.
*
* 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.
*/
#ifndef SOUTHBRIDGE_INTEL_I82801GX_I82801IX_H
#define SOUTHBRIDGE_INTEL_I82801GX_I82801IX_H
#ifndef __ACPI__
#ifndef __ASSEMBLER__
#include "chip.h"
#endif
#endif
#define DEFAULT_TBAR ((u8 *)0xfed1b000)
#ifndef __ACPI__
#define DEFAULT_RCBA ((u8 *)0xfed1c000)
#else
#define DEFAULT_RCBA 0xfed1c000
#endif
#define DEFAULT_PMBASE 0x00000500
#define DEFAULT_TCOBASE (DEFAULT_PMBASE + 0x60)
#define DEFAULT_GPIOBASE 0x00000580
#define APM_CNT 0xb2
#define PM1_STS 0x00
#define PWRBTN_STS (1 << 8)
#define RTC_STS (1 << 10)
#define PM1_EN 0x02
#define PWRBTN_EN (1 << 8)
#define GBL_EN (1 << 5)
#define PM1_CNT 0x04
#define SCI_EN (1 << 0)
#define PM_LV2 0x14
#define PM_LV3 0x15
#define PM_LV4 0x16
#define PM_LV5 0x17
#define PM_LV6 0x18
#define GPE0_STS 0x20
#define SMI_EN 0x30
#define PERIODIC_EN (1 << 14)
#define TCO_EN (1 << 13)
#define APMC_EN (1 << 5)
#define BIOS_EN (1 << 2)
#define EOS (1 << 1)
#define GBL_SMI_EN (1 << 0)
#define SMI_STS 0x34
#define ALT_GP_SMI_EN 0x38
#define ALT_GP_SMI_STS 0x3a
#define GP_IO_USE_SEL 0x00
#define GP_IO_SEL 0x04
#define GP_LVL 0x0c
#define GPO_BLINK 0x18
#define GPI_INV 0x2c
#define GP_IO_USE_SEL2 0x30
#define GP_IO_SEL2 0x34
#define GP_LVL2 0x38
#define DEBUG_PERIODIC_SMIS 0
#define MAINBOARD_POWER_OFF 0
#define MAINBOARD_POWER_ON 1
#define MAINBOARD_POWER_KEEP 2
#ifndef CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL
#define CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON
#endif
/* D31:F0 LPC bridge */
#define D31F0_PMBASE 0x40
#define D31F0_ACPI_CNTL 0x44
#define D31F0_GPIO_BASE 0x48
#define D31F0_GPIO_CNTL 0x4c
#define D31F0_PIRQA_ROUT 0x60
#define D31F0_PIRQB_ROUT 0x61
#define D31F0_PIRQC_ROUT 0x62
#define D31F0_PIRQD_ROUT 0x63
#define D31F0_SERIRQ_CNTL 0x64
#define D31F0_PIRQE_ROUT 0x68
#define D31F0_PIRQF_ROUT 0x69
#define D31F0_PIRQG_ROUT 0x6a
#define D31F0_PIRQH_ROUT 0x6b
#define D31F0_LPC_IODEC 0x80
#define D31F0_LPC_EN 0x82
#define D31F0_GEN1_DEC 0x84
#define D31F0_GEN2_DEC 0x88
#define D31F0_GEN3_DEC 0x8c
#define D31F0_GEN4_DEC 0x90
#define D31F0_GEN_PMCON_1 0xa0
#define D31F0_GEN_PMCON_3 0xa4
#define D31F0_C5_EXIT_TIMING 0xa8
#define D31F0_CxSTATE_CNF 0xa9
#define D31F0_C4TIMING_CNT 0xaa
#define D31F0_GPIO_ROUT 0xb8
#define D31F0_RCBA 0xf0
/* GEN_PMCON_3 bits */
#define RTC_BATTERY_DEAD (1 << 2)
#define RTC_POWER_FAILED (1 << 1)
#define SLEEP_AFTER_POWER_FAIL (1 << 0)
/* D31:F2 SATA */
#define D31F2_IDE_TIM_PRI 0x40
#define D31F2_IDE_TIM_SEC 0x42
#define D31F2_SIDX 0xa0
#define D31F2_SDAT 0xa4
/* D30:F0 PCI-to-PCI bridge */
#define D30F0_SMLT 0x1b
/* D28:F0-5 PCIe root ports */
#define D28Fx_XCAP 0x42
#define D28Fx_SLCAP 0x54
#define SMBUS_IO_BASE 0x0400
/* PCI Configuration Space (D31:F3): SMBus */
#define SMB_BASE 0x20
#define HOSTC 0x40
/* HOSTC bits */
#define I2C_EN (1 << 2)
#define SMB_SMI_EN (1 << 1)
#define HST_EN (1 << 0)
/* SMBus I/O bits. */
#define SMBHSTSTAT 0x0
#define SMBHSTCTL 0x2
#define SMBHSTCMD 0x3
#define SMBXMITADD 0x4
#define SMBHSTDAT0 0x5
#define SMBHSTDAT1 0x6
#define SMBBLKDAT 0x7
#define SMBTRNSADD 0x9
#define SMBSLVDATA 0xa
#define SMLINK_PIN_CTL 0xe
#define SMBUS_PIN_CTL 0xf
#define SMBUS_TIMEOUT (10 * 1000 * 100)
#define RCBA8(x) *((volatile u8 *)(DEFAULT_RCBA + x))
#define RCBA16(x) *((volatile u16 *)(DEFAULT_RCBA + x))
#define RCBA32(x) *((volatile u32 *)(DEFAULT_RCBA + x))
#define RCBA_V0CTL 0x0014
#define RCBA_V1CAP 0x001c
#define RCBA_V1CTL 0x0020
#define RCBA_V1STS 0x0026
#define RCBA_PAT 0x0030
#define RCBA_ESD 0x0104
#define RCBA_ULD 0x0110
#define RCBA_ULBA 0x0118
#define RCBA_LCAP 0x01a4
#define RCBA_LCTL 0x01a8
#define RCBA_LSTS 0x01aa
#define RCBA_DMIC 0x0234
#define RCBA_RPFN 0x0238
#define RCBA_DMC 0x2010
#define RCBA_HPTC 0x3404
#define RCBA_BUC 0x3414
#define RCBA_FD 0x3418 /* Function Disable, see below. */
#define RCBA_CG 0x341c
#define RCBA_FDSW 0x3420
#define RCBA_MAP 0x35f0 /* UHCI controller #6 remapping */
#define BUC_LAND (1 << 5) /* LAN */
#define FD_SAD2 (1 << 25) /* SATA #2 */
#define FD_TTD (1 << 24) /* Thermal Throttle */
#define FD_PE6D (1 << 21) /* PCIe root port 6 */
#define FD_PE5D (1 << 20) /* PCIe root port 5 */
#define FD_PE4D (1 << 19) /* PCIe root port 4 */
#define FD_PE3D (1 << 18) /* PCIe root port 3 */
#define FD_PE2D (1 << 17) /* PCIe root port 2 */
#define FD_PE1D (1 << 16) /* PCIe root port 1 */
#define FD_EHCI1D (1 << 15) /* EHCI #1 */
#define FD_LBD (1 << 14) /* LPC bridge */
#define FD_EHCI2D (1 << 13) /* EHCI #2 */
#define FD_U5D (1 << 12) /* UHCI #5 */
#define FD_U4D (1 << 11) /* UHCI #4 */
#define FD_U3D (1 << 10) /* UHCI #3 */
#define FD_U2D (1 << 9) /* UHCI #2 */
#define FD_U1D (1 << 8) /* UHCI #1 */
#define FD_U6D (1 << 7) /* UHCI #6 */
#define FD_HDAD (1 << 4) /* HD audio */
#define FD_SD (1 << 3) /* SMBus */
#define FD_SAD1 (1 << 2) /* SATA #1 */
#ifndef __ACPI__
#ifndef __ASSEMBLER__
static inline int lpc_is_mobile(const u16 devid)
{
return (devid == 0x2917) || (devid == 0x2919);
}
#define LPC_IS_MOBILE(dev) lpc_is_mobile(pci_read_config16(dev, PCI_DEVICE_ID))
#if defined(__PRE_RAM__)
void enable_smbus(void);
int smbus_read_byte(unsigned device, unsigned address);
void i82801ix_early_init(void);
void i82801ix_dmi_setup(void);
void i82801ix_dmi_poll_vc1(void);
#endif
#endif
#endif
#endif

View File

@ -0,0 +1,599 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
* 2012 secunet Security Networks AG
*
* 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.
*
* 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.
*/
#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>
#include <pc80/i8259.h>
#include <arch/io.h>
#include <arch/ioapic.h>
#include <arch/acpi.h>
#include <cpu/cpu.h>
#include <cpu/x86/smm.h>
#include <arch/acpigen.h>
#include <cbmem.h>
#include <string.h>
#include "i82801ix.h"
#include "nvs.h"
#include <southbridge/intel/common/pciehp.h>
#include <drivers/intel/gma/i915.h>
#define NMI_OFF 0
#define ENABLE_ACPI_MODE_IN_COREBOOT 0
#define TEST_SMM_FLASH_LOCKDOWN 0
typedef struct southbridge_intel_i82801ix_config config_t;
static void i82801ix_enable_apic(struct device *dev)
{
u32 reg32;
volatile u32 *ioapic_index = (volatile u32 *)(IO_APIC_ADDR);
volatile u32 *ioapic_data = (volatile u32 *)(IO_APIC_ADDR + 0x10);
/* Enable IOAPIC. Keep APIC Range Select at zero. */
RCBA8(0x31ff) = 0x03;
/* We have to read 0x31ff back if bit0 changed. */
RCBA8(0x31ff);
/* Lock maximum redirection entries (MRE), R/WO register. */
*ioapic_index = 0x01;
reg32 = *ioapic_data;
*ioapic_index = 0x01;
*ioapic_data = reg32;
setup_ioapic(VIO_APIC_VADDR, 2); /* ICH7 code uses id 2. */
}
static void i82801ix_enable_serial_irqs(struct device *dev)
{
/* Set packet length and toggle silent mode bit for one frame. */
pci_write_config8(dev, D31F0_SERIRQ_CNTL,
(1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
}
/* 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.
*/
static void i82801ix_pirq_init(device_t dev)
{
device_t irq_dev;
/* Get the chip configuration */
config_t *config = dev->chip_info;
pci_write_config8(dev, D31F0_PIRQA_ROUT, config->pirqa_routing);
pci_write_config8(dev, D31F0_PIRQB_ROUT, config->pirqb_routing);
pci_write_config8(dev, D31F0_PIRQC_ROUT, config->pirqc_routing);
pci_write_config8(dev, D31F0_PIRQD_ROUT, config->pirqd_routing);
pci_write_config8(dev, D31F0_PIRQE_ROUT, config->pirqe_routing);
pci_write_config8(dev, D31F0_PIRQF_ROUT, config->pirqf_routing);
pci_write_config8(dev, D31F0_PIRQG_ROUT, config->pirqg_routing);
pci_write_config8(dev, D31F0_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);
}
}
static void i82801ix_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, D31F0_GPIO_ROUT, reg32);
}
static void i82801ix_power_options(device_t dev)
{
u8 reg8;
u16 reg16, pmbase;
u32 reg32;
const char *state;
/* Get the chip configuration */
config_t *config = dev->chip_info;
int pwr_on=CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
int nmi_option;
/* BIOS must program... */
reg32 = pci_read_config32(dev, 0xac);
pci_write_config32(dev, 0xac, reg32 | (1 << 30) | (3 << 8));
/* Which state do we want to goto after g3 (power restored)?
* 0 == S0 Full On
* 1 == S5 Soft Off
*
* If the option is not existent (Laptops), use MAINBOARD_POWER_ON.
*/
pwr_on = MAINBOARD_POWER_ON;
get_option(&pwr_on, "power_on_after_fail");
reg8 = pci_read_config8(dev, D31F0_GEN_PMCON_3);
reg8 &= 0xfe;
switch (pwr_on) {
case MAINBOARD_POWER_OFF:
reg8 |= 1;
state = "off";
break;
case MAINBOARD_POWER_ON:
reg8 &= ~1;
state = "on";
break;
case MAINBOARD_POWER_KEEP:
reg8 &= ~1;
state = "state keep";
break;
default:
state = "undefined";
}
reg8 |= (3 << 4); /* avoid #S4 assertions */
reg8 &= ~(1 << 3); /* minimum asssertion is 1 to 2 RTCCLK */
pci_write_config8(dev, D31F0_GEN_PMCON_3, reg8);
printk(BIOS_INFO, "Set power %s after power failure.\n", state);
/* 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(0x74); /* Read from 0x74 as 0x70 is write only. */
nmi_option = NMI_OFF;
get_option(&nmi_option, "nmi");
if (nmi_option) {
printk(BIOS_INFO, "NMI sources enabled.\n");
reg8 &= ~(1 << 7); /* Set NMI. */
} else {
printk(BIOS_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, D31F0_GEN_PMCON_1);
reg16 &= ~(3 << 0); // SMI# rate 1 minute
reg16 |= (1 << 2); // CLKRUN_EN - Mobile/Ultra only
reg16 |= (1 << 3); // Speedstep Enable - Mobile/Ultra only
reg16 |= (1 << 5); // CPUSLP_EN Desktop only
if (config->c4onc3_enable)
reg16 |= (1 << 7);
// another laptop wants this?
// reg16 &= ~(1 << 10); // BIOS_PCI_EXP_EN - Desktop/Mobile only
reg16 |= (1 << 10); // BIOS_PCI_EXP_EN - Desktop/Mobile only
#if DEBUG_PERIODIC_SMIS
/* Set DEBUG_PERIODIC_SMIS in i82801ix.h to debug using
* periodic SMIs.
*/
reg16 |= (3 << 0); // Periodic SMI every 8s
#endif
if (config->c5_enable)
reg16 |= (1 << 11); /* Enable C5, C6 and PMSYNC# */
pci_write_config16(dev, D31F0_GEN_PMCON_1, reg16);
/* Set exit timings for C5/C6. */
if (config->c5_enable) {
reg8 = pci_read_config8(dev, D31F0_C5_EXIT_TIMING);
reg8 &= ~((7 << 3) | (7 << 0));
if (config->c6_enable)
reg8 |= (5 << 3) | (3 << 0); /* 38-44us PMSYNC# to STPCLK#,
95-102us DPRSTP# to STP_CPU# */
else
reg8 |= (0 << 3) | (1 << 0); /* 16-17us PMSYNC# to STPCLK#,
34-40us DPRSTP# to STP_CPU# */
pci_write_config8(dev, D31F0_C5_EXIT_TIMING, reg8);
}
// Set the board's GPI routing.
i82801ix_gpi_routing(dev);
pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
outl(config->gpe0_en, pmbase + 0x28);
outw(config->alt_gp_smi_en, pmbase + 0x38);
/* Set up power management block and determine sleep mode */
reg16 = inw(pmbase + 0x00); /* PM1_STS */
outw(reg16, pmbase + 0x00); /* Clear status bits. At least bit11 (power
button override) must be cleared or SCI
will be constantly fired and OSPM must
not know about it (ACPI spec says to
ignore the bit). */
reg32 = inl(pmbase + 0x04); // PM1_CNT
reg32 &= ~(7 << 10); // SLP_TYP
outl(reg32, pmbase + 0x04);
/* Set duty cycle for hardware throttling (defaults to 0x0: 50%). */
reg32 = inl(pmbase + 0x10);
reg32 &= ~(7 << 5);
reg32 |= (config->throttle_duty & 7) << 5;
outl(reg32, pmbase + 0x10);
}
static void i82801ix_configure_cstates(device_t dev)
{
u8 reg8;
reg8 = pci_read_config8(dev, D31F0_CxSTATE_CNF);
reg8 |= (1 << 4) | (1 << 3) | (1 << 2); // Enable Popup & Popdown
pci_write_config8(dev, D31F0_CxSTATE_CNF, reg8);
// Set Deeper Sleep configuration to recommended values
reg8 = pci_read_config8(dev, D31F0_C4TIMING_CNT);
reg8 &= 0xf0;
reg8 |= (2 << 2); // Deeper Sleep to Stop CPU: 34-40us
reg8 |= (2 << 0); // Deeper Sleep to Sleep: 15us
pci_write_config8(dev, D31F0_C4TIMING_CNT, reg8);
/* We could enable slow-C4 exit here, if someone needs it? */
}
static void i82801ix_rtc_init(struct device *dev)
{
u8 reg8;
int rtc_failed;
reg8 = pci_read_config8(dev, D31F0_GEN_PMCON_3);
rtc_failed = reg8 & RTC_BATTERY_DEAD;
if (rtc_failed) {
reg8 &= ~RTC_BATTERY_DEAD;
pci_write_config8(dev, D31F0_GEN_PMCON_3, reg8);
}
printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
cmos_init(rtc_failed);
}
static void enable_hpet(void)
{
u32 reg32;
/* Move HPET to default address 0xfed00000 and enable it */
reg32 = RCBA32(RCBA_HPTC);
reg32 |= (1 << 7); // HPET Address Enable
reg32 &= ~(3 << 0);
RCBA32(RCBA_HPTC) = reg32;
}
static void enable_clock_gating(void)
{
u32 reg32;
/* Enable DMI dynamic clock gating. */
RCBA32(RCBA_DMIC) |= 3;
/* Enable Clock Gating for most devices. */
reg32 = RCBA32(RCBA_CG);
reg32 |= (1 << 31); /* LPC dynamic clock gating */
/* USB UHCI dynamic clock gating: */
reg32 |= (1 << 29) | (1 << 28);
/* SATA dynamic clock gating [0-3]: */
reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
reg32 |= (1 << 23); /* LAN static clock gating (if LAN disabled) */
reg32 |= (1 << 22); /* HD audio dynamic clock gating */
reg32 &= ~(1 << 21); /* No HD audio static clock gating */
reg32 &= ~(1 << 20); /* No USB EHCI static clock gating */
reg32 |= (1 << 19); /* USB EHCI dynamic clock gating */
/* More SATA dynamic clock gating [4-5]: */
reg32 |= (1 << 18) | (1 << 17);
reg32 |= (1 << 16); /* PCI dynamic clock gating */
/* PCIe, DMI dynamic clock gating: */
reg32 |= (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1);
reg32 |= (1 << 0); /* PCIe root port static clock gating */
RCBA32(RCBA_CG) = reg32;
/* Enable SPI dynamic clock gating. */
RCBA32(0x38c0) |= 7;
}
#if CONFIG_HAVE_SMI_HANDLER
static void i82801ix_lock_smm(struct device *dev)
{
#if TEST_SMM_FLASH_LOCKDOWN
u8 reg8;
#endif
if (!acpi_is_wakeup_s3()) {
#if ENABLE_ACPI_MODE_IN_COREBOOT
printk(BIOS_DEBUG, "Enabling ACPI via APMC:\n");
outb(APM_CNT_ACPI_ENABLE, APM_CNT); // Enable ACPI mode
printk(BIOS_DEBUG, "done.\n");
#else
printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
printk(BIOS_DEBUG, "done.\n");
#endif
} else {
printk(BIOS_DEBUG, "S3 wakeup, enabling ACPI via APMC\n");
outb(APM_CNT_ACPI_ENABLE, APM_CNT);
}
/* Don't allow evil boot loaders, kernels, or
* userspace applications to deceive us:
*/
smm_lock();
#if TEST_SMM_FLASH_LOCKDOWN
/* Now try this: */
printk(BIOS_DEBUG, "Locking BIOS to RO... ");
reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
printk(BIOS_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(BIOS_DEBUG, "ok.\n");
reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
printk(BIOS_DEBUG, " BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
(reg8&1)?"rw":"ro");
printk(BIOS_DEBUG, "Writing:\n");
*(volatile u8 *)0xfff00000 = 0x00;
printk(BIOS_DEBUG, "Testing:\n");
reg8 |= (1 << 0); /* set BIOSWE */
pci_write_config8(dev, 0xdc, reg8);
reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
printk(BIOS_DEBUG, " BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
(reg8&1)?"rw":"ro");
printk(BIOS_DEBUG, "Done.\n");
#endif
}
#endif
static void lpc_init(struct device *dev)
{
printk(BIOS_DEBUG, "i82801ix: lpc_init\n");
/* Set the value for PCI command register. */
pci_write_config16(dev, PCI_COMMAND, 0x000f);
/* IO APIC initialization. */
i82801ix_enable_apic(dev);
i82801ix_enable_serial_irqs(dev);
/* Setup the PIRQ. */
i82801ix_pirq_init(dev);
/* Setup power options. */
i82801ix_power_options(dev);
/* Configure Cx state registers */
if (LPC_IS_MOBILE(dev))
i82801ix_configure_cstates(dev);
/* Initialize the real time clock. */
i82801ix_rtc_init(dev);
/* Initialize ISA DMA. */
isa_dma_init();
/* Initialize the High Precision Event Timers, if present. */
enable_hpet();
/* Initialize Clock Gating */
enable_clock_gating();
setup_i8259();
/* The OS should do this? */
/* Interrupt 9 should be level triggered (SCI) */
i8259_configure_irq_trigger(9, 1);
#if CONFIG_HAVE_SMI_HANDLER
i82801ix_lock_smm(dev);
#endif
}
static void i82801ix_lpc_read_resources(device_t dev)
{
/*
* I/O Resources
*
* 0x0000 - 0x000f....ISA DMA
* 0x0010 - 0x001f....ISA DMA aliases
* 0x0020 ~ 0x003d....PIC
* 0x002e - 0x002f....Maybe Super I/O
* 0x0040 - 0x0043....Timer
* 0x004e - 0x004f....Maybe Super I/O
* 0x0050 - 0x0053....Timer aliases
* 0x0061.............NMI_SC
* 0x0070.............NMI_EN (readable in alternative access mode)
* 0x0070 - 0x0077....RTC
* 0x0080 - 0x008f....ISA DMA
* 0x0090 ~ 0x009f....ISA DMA aliases
* 0x0092.............Fast A20 and Init
* 0x00a0 ~ 0x00bd....PIC
* 0x00b2 - 0x00b3....APM
* 0x00c0 ~ 0x00de....ISA DMA
* 0x00c1 ~ 0x00df....ISA DMA aliases
* 0x00f0.............Coprocessor Error
* (0x0400-0x041f)....SMBus (SMBUS_IO_BASE, during raminit)
* 0x04d0 - 0x04d1....PIC
* 0x0500 - 0x057f....PM (DEFAULT_PMBASE)
* 0x0580 - 0x05bf....SB GPIO (DEFAULT_GPIOBASE)
* 0x05c0 - 0x05ff....SB GPIO cont. (mobile only)
* 0x0cf8 - 0x0cff....PCI
* 0x0cf9.............Reset Control
*/
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->base = 0;
res->size = 0x1000;
res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
res->base = 0xff800000;
res->size = 0x00800000; /* 8 MB for flash */
res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
res = new_resource(dev, 3); /* IOAPIC */
res->base = IO_APIC_ADDR;
res->size = 0x00001000;
res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
}
static void set_subsystem(device_t dev, unsigned vendor, unsigned device)
{
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));
}
}
static void southbridge_inject_dsdt(device_t dev)
{
global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
if (gnvs) {
const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
memset(gnvs, 0, sizeof(*gnvs));
acpi_create_gnvs(gnvs);
gnvs->ndid = gfx->ndid;
memcpy(gnvs->did, gfx->did, sizeof(gnvs->did));
/* And tell SMI about it */
smm_setup_structures(gnvs, NULL, NULL);
/* Add it to SSDT. */
acpigen_write_scope("\\");
acpigen_write_name_dword("NVSA", (u32) gnvs);
acpigen_pop_len();
}
}
static void southbridge_fill_ssdt(device_t device)
{
device_t dev = dev_find_slot(0, PCI_DEVFN(0x1f,0));
config_t *chip = dev->chip_info;
intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
}
static struct pci_operations pci_ops = {
.set_subsystem = set_subsystem,
};
static struct device_operations device_ops = {
.read_resources = i82801ix_lpc_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.acpi_inject_dsdt_generator = southbridge_inject_dsdt,
.write_acpi_tables = acpi_write_hpet,
.acpi_fill_ssdt_generator = southbridge_fill_ssdt,
.init = lpc_init,
.scan_bus = scan_lpc_bus,
.ops_pci = &pci_ops,
};
static const unsigned short pci_device_ids[] = {
0x2912, /* ICH9DH */
0x2914, /* ICH9DO */
0x2916, /* ICH9R */
0x2918, /* ICH9 */
0x2917, /* ICH9M-E */
0x2919, /* ICH9M */
0
};
static const struct pci_driver ich9_lpc __pci_driver = {
.ops = &device_ops,
.vendor = PCI_VENDOR_ID_INTEL,
.devices = pci_device_ids,
};

View File

@ -0,0 +1,135 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
*
* 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.
*
* 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.
*/
typedef struct {
/* Miscellaneous */
u16 osys; /* 0x00 - Operating System */
u8 smif; /* 0x02 - SMI function call ("TRAP") */
u8 prm0; /* 0x03 - SMI function call parameter */
u8 prm1; /* 0x04 - SMI function call parameter */
u8 scif; /* 0x05 - SCI function call (via _L00) */
u8 prm2; /* 0x06 - SCI function call parameter */
u8 prm3; /* 0x07 - SCI function call parameter */
u8 lckf; /* 0x08 - Global Lock function for EC */
u8 prm4; /* 0x09 - Lock function parameter */
u8 prm5; /* 0x0a - Lock function parameter */
u32 p80d; /* 0x0b - Debug port (IO 0x80) value */
u8 lids; /* 0x0f - LID state (open = 1) */
u8 pwrs; /* 0x10 - Power state (AC = 1) */
u8 dbgs; /* 0x11 - Debug state */
u8 linx; /* 0x12 - Linux OS */
u8 dckn; /* 0x13 - PCIe docking state */
/* Thermal policy */
u8 actt; /* 0x14 - active trip point */
u8 psvt; /* 0x15 - passive trip point */
u8 tc1v; /* 0x16 - passive trip point TC1 */
u8 tc2v; /* 0x17 - passive trip point TC2 */
u8 tspv; /* 0x18 - passive trip point TSP */
u8 crtt; /* 0x19 - critical trip point */
u8 dtse; /* 0x1a - Digital Thermal Sensor enable */
u8 dts1; /* 0x1b - DT sensor 1 */
u8 dts2; /* 0x1c - DT sensor 2 */
u8 rsvd2;
/* Battery Support */
u8 bnum; /* 0x1e - number of batteries */
u8 b0sc, b1sc, b2sc; /* 0x1f-0x21 - stored capacity */
u8 b0ss, b1ss, b2ss; /* 0x22-0x24 - stored status */
u8 rsvd3[3];
/* Processor Identification */
u8 apic; /* 0x28 - APIC enabled */
u8 mpen; /* 0x29 - MP capable/enabled */
u8 pcp0; /* 0x2a - PDC CPU/CORE 0 */
u8 pcp1; /* 0x2b - PDC CPU/CORE 1 */
u8 ppcm; /* 0x2c - Max. PPC state */
u8 rsvd4[5];
/* Super I/O & CMOS config */
u8 natp; /* 0x32 - SIO type */
u8 cmap; /* 0x33 - */
u8 cmbp; /* 0x34 - */
u8 lptp; /* 0x35 - LPT port */
u8 fdcp; /* 0x36 - Floppy Disk Controller */
u8 rfdv; /* 0x37 - */
u8 hotk; /* 0x38 - Hot Key */
u8 rtcf;
u8 util;
u8 acin;
/* Integrated Graphics Device */
u8 igds; /* 0x3c - IGD state */
u8 tlst; /* 0x3d - Display Toggle List Pointer */
u8 cadl; /* 0x3e - currently attached devices */
u8 padl; /* 0x3f - previously attached devices */
u16 cste; /* 0x40 - current display state */
u16 nste; /* 0x42 - next display state */
u16 sste; /* 0x44 - set display state */
u8 ndid; /* 0x46 - number of device ids */
u32 did[5]; /* 0x47 - 5b device id 1..5 */
u8 rsvd5[0x9];
/* Backlight Control */
u8 blcs; /* 0x64 - Backlight Control possible */
u8 brtl;
u8 odds;
u8 rsvd6[0x7];
/* Ambient Light Sensors*/
u8 alse; /* 0x6e - ALS enable */
u8 alaf;
u8 llow;
u8 lhih;
u8 rsvd7[0x6];
/* EMA */
u8 emae; /* 0x78 - EMA enable */
u16 emap;
u16 emal;
u8 rsvd8[0x5];
/* MEF */
u8 mefe; /* 0x82 - MEF enable */
u8 rsvd9[0x9];
/* TPM support */
u8 tpmp; /* 0x8c - TPM */
u8 tpme;
u8 rsvd10[8];
/* SATA */
u8 gtf0[7]; /* 0x96 - GTF task file buffer for port 0 */
u8 gtf1[7];
u8 gtf2[7];
u8 idem;
u8 idet;
u8 rsvd11[7];
/* IGD OpRegion (not implemented yet) */
u32 aslb; /* 0xb4 - IGD OpRegion Base Address */
u8 ibtt;
u8 ipat;
u8 itvf;
u8 itvm;
u8 ipsc;
u8 iblc;
u8 ibia;
u8 issc;
u8 i409;
u8 i509;
u8 i609;
u8 i709;
u8 idmm;
u8 idms;
u8 if1e;
u8 hvco;
u32 nxd[8];
u8 rsvd12[8];
/* Mainboard specific */
u8 dock; /* 0xf0 - Docking Status */
u8 bten;
u8 rsvd13[14];
} __attribute__((packed)) global_nvs_t;
void acpi_create_gnvs(global_nvs_t *gnvs);

View File

@ -0,0 +1,82 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
*
* 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.
*
* 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.
*/
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include "i82801ix.h"
static void pci_init(struct device *dev)
{
u16 reg16;
u8 reg8;
/* This device has no interrupt */
pci_write_config8(dev, PCI_INTERRUPT_LINE, 0xff);
/* Master Latency Count must be set to 0x04! */
reg8 = pci_read_config8(dev, D30F0_SMLT);
reg8 &= 0x07;
reg8 |= (0x04 << 3);
pci_write_config8(dev, D30F0_SMLT, reg8);
/* Clear errors in status registers */
reg16 = pci_read_config16(dev, PCI_STATUS);
//reg16 |= 0xf900;
pci_write_config16(dev, PCI_STATUS, reg16);
reg16 = pci_read_config16(dev, PCI_SEC_STATUS);
// reg16 |= 0xf900;
pci_write_config16(dev, PCI_SEC_STATUS, reg16);
}
static void set_subsystem(device_t dev, unsigned vendor, unsigned device)
{
/* NOTE: 0x54 is not the default position! */
if (!vendor || !device) {
pci_write_config32(dev, 0x54,
pci_read_config32(dev, PCI_VENDOR_ID));
} else {
pci_write_config32(dev, 0x54,
((device & 0xffff) << 16) | (vendor & 0xffff));
}
}
static struct pci_operations pci_ops = {
.set_subsystem = set_subsystem,
};
static struct device_operations device_ops = {
.read_resources = pci_bus_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_bus_enable_resources,
.init = pci_init,
.scan_bus = pci_scan_bridge,
.reset_bus = pci_bus_reset,
.ops_pci = &pci_ops,
};
static const unsigned short pci_device_ids[] = {
0x244e, /* Desktop */
0x2448, /* Mobile */
0
};
static const struct pci_driver ich9_pci __pci_driver = {
.ops = &device_ops,
.vendor = PCI_VENDOR_ID_INTEL,
.devices = pci_device_ids,
};

View File

@ -0,0 +1,148 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
* 2012 secunet Security Networks AG
*
* 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.
*
* 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.
*/
#include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pciexp.h>
#include <device/pci_ids.h>
#include <southbridge/intel/common/pciehp.h>
#include "chip.h"
static void pci_init(struct device *dev)
{
u16 reg16;
u32 reg32;
struct southbridge_intel_i82801ix_config *config = dev->chip_info;
printk(BIOS_DEBUG, "Initializing ICH9 PCIe root port.\n");
/* Enable Bus Master */
reg32 = pci_read_config32(dev, PCI_COMMAND);
reg32 |= PCI_COMMAND_MASTER;
pci_write_config32(dev, PCI_COMMAND, reg32);
/* Set Cache Line Size to 0x10 */
// This has no effect but the OS might expect it
pci_write_config8(dev, 0x0c, 0x10);
reg16 = pci_read_config16(dev, 0x3e);
reg16 &= ~(1 << 0); /* disable parity error response */
reg16 |= (1 << 2); /* ISA enable */
pci_write_config16(dev, 0x3e, reg16);
/* Enable IO xAPIC on this PCIe port */
reg32 = pci_read_config32(dev, 0xd8);
reg32 |= (1 << 7);
pci_write_config32(dev, 0xd8, reg32);
/* Enable Backbone Clock Gating */
reg32 = pci_read_config32(dev, 0xe1);
reg32 |= (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0);
pci_write_config32(dev, 0xe1, reg32);
/* Set VC0 transaction class */
reg32 = pci_read_config32(dev, 0x114);
reg32 &= 0xffffff00;
reg32 |= 1;
pci_write_config32(dev, 0x114, reg32);
/* Mask completion timeouts */
reg32 = pci_read_config32(dev, 0x148);
reg32 |= (1 << 14);
pci_write_config32(dev, 0x148, reg32);
/* Lock R/WO Correctable Error Mask. */
pci_write_config32(dev, 0x154, pci_read_config32(dev, 0x154));
/* Clear errors in status registers */
reg16 = pci_read_config16(dev, 0x06);
pci_write_config16(dev, 0x06, reg16);
reg16 = pci_read_config16(dev, 0x1e);
pci_write_config16(dev, 0x1e, reg16);
/* Get configured ASPM state */
const enum aspm_type apmc = pci_read_config32(dev, 0x50) & 3;
/* If both L0s and L1 enabled then set root port 0xE8[1]=1 */
if (apmc == PCIE_ASPM_BOTH) {
reg32 = pci_read_config32(dev, 0xe8);
reg32 |= (1 << 1);
pci_write_config32(dev, 0xe8, reg32);
}
/* Enable expresscard hotplug events. */
if (config->pcie_hotplug_map[PCI_FUNC(dev->path.pci.devfn)]) {
pci_write_config32(dev, 0xd8,
pci_read_config32(dev, 0xd8)
| (1 << 30));
pci_write_config16(dev, 0x42, 0x142);
}
}
static void pcie_set_subsystem(device_t dev, unsigned vendor, unsigned device)
{
/* NOTE: 0x94 is not the default position! */
if (!vendor || !device) {
pci_write_config32(dev, 0x94,
pci_read_config32(dev, 0));
} else {
pci_write_config32(dev, 0x94,
((device & 0xffff) << 16) | (vendor & 0xffff));
}
}
static void pch_pciexp_scan_bridge(device_t dev)
{
struct southbridge_intel_i82801ix_config *config = dev->chip_info;
/* Normal PCIe Scan */
pciexp_scan_bridge(dev);
if (config->pcie_hotplug_map[PCI_FUNC(dev->path.pci.devfn)]) {
intel_acpi_pcie_hotplug_scan_slot(dev->link_list);
}
}
static struct pci_operations pci_ops = {
.set_subsystem = pcie_set_subsystem,
};
static struct device_operations device_ops = {
.read_resources = pci_bus_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_bus_enable_resources,
.init = pci_init,
.scan_bus = pch_pciexp_scan_bridge,
.ops_pci = &pci_ops,
};
/* 82801Ix (ICH9DH/ICH9DO/ICH9R/ICH9/ICH9M-E/ICH9M) */
static const unsigned short pci_device_ids[] = {
0x2940, /* Port 1 */
0x2942, /* Port 2 */
0x2944, /* Port 3 */
0x2946, /* Port 4 */
0x2948, /* Port 5 */
0x294a, /* Port 6 */
0
};
static const struct pci_driver ich9_pcie __pci_driver = {
.ops = &device_ops,
.vendor = PCI_VENDOR_ID_INTEL,
.devices = pci_device_ids,
};

View File

@ -0,0 +1,289 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
* 2012 secunet Security Networks AG
*
* 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.
*
* 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.
*/
#include <arch/io.h>
#include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include "i82801ix.h"
#include <pc80/mc146818rtc.h>
typedef struct southbridge_intel_i82801ix_config config_t;
static void sata_enable_ahci_mmap(struct device *const dev, const u8 port_map,
const int is_mobile)
{
int i;
u32 reg32;
/* Initialize AHCI memory-mapped space */
u8 *abar = (u8 *)pci_read_config32(dev, PCI_BASE_ADDRESS_5);
printk(BIOS_DEBUG, "ABAR: %p\n", abar);
/* Set AHCI access mode.
No other ABAR registers should be accessed before this. */
reg32 = read32(abar + 0x04);
reg32 |= 1 << 31;
write32(abar + 0x04, reg32);
/* CAP (HBA Capabilities) : enable power management */
reg32 = read32(abar + 0x00);
/* CCCS must be set. */
reg32 |= 0x0c006080; /* set CCCS+PSC+SSC+SALP+SSS */
reg32 &= ~0x00020060; /* clear SXS+EMS+PMS */
write32(abar + 0x00, reg32);
/* PI (Ports implemented) */
write32(abar + 0x0c, port_map);
/* PCH code reads back twice, do we need it, too? */
(void) read32(abar + 0x0c); /* Read back 1 */
(void) read32(abar + 0x0c); /* Read back 2 */
/* VSP (Vendor Specific Register) */
reg32 = read32(abar + 0xa0);
reg32 &= ~0x00000001; /* clear SLPD */
write32(abar + 0xa0, reg32);
/* Lock R/WO bits in Port command registers. */
for (i = 0; i < 6; ++i) {
if (((i == 2) || (i == 3)) && is_mobile)
continue;
u8 *addr = abar + 0x118 + (i * 0x80);
write32(addr, read32(addr));
}
}
static void sata_program_indexed(struct device *const dev, const int is_mobile)
{
u32 reg32;
pci_write_config8(dev, D31F2_SIDX, 0x18);
reg32 = pci_read_config32(dev, D31F2_SDAT);
reg32 &= ~((7 << 6) | (7 << 3) | (7 << 0));
reg32 |= (3 << 3) | (3 << 0);
pci_write_config32(dev, D31F2_SDAT, reg32);
pci_write_config8(dev, D31F2_SIDX, 0x28);
pci_write_config32(dev, D31F2_SDAT, 0x00cc2080);
pci_write_config8(dev, D31F2_SIDX, 0x40);
pci_write_config8(dev, D31F2_SDAT + 2, 0x22);
pci_write_config8(dev, D31F2_SIDX, 0x78);
pci_write_config8(dev, D31F2_SDAT + 2, 0x22);
if (!is_mobile) {
pci_write_config8(dev, D31F2_SIDX, 0x84);
reg32 = pci_read_config32(dev, D31F2_SDAT);
reg32 &= ~((7 << 3) | (7 << 0));
reg32 |= (3 << 3) | (3 << 0);
pci_write_config32(dev, D31F2_SDAT, reg32);
}
pci_write_config8(dev, D31F2_SIDX, 0x88);
reg32 = pci_read_config32(dev, D31F2_SDAT);
if (!is_mobile)
reg32 &= ~((7 << 27) | (7 << 24) | (7 << 11) | (7 << 8));
reg32 &= ~((7 << 19) | (7 << 16) | (7 << 3) | (7 << 0));
if (!is_mobile)
reg32 |= (4 << 27) | (4 << 24) | (2 << 11) | (2 << 8);
reg32 |= (4 << 19) | (4 << 16) | (2 << 3) | (2 << 0);
pci_write_config32(dev, D31F2_SDAT, reg32);
pci_write_config8(dev, D31F2_SIDX, 0x8c);
reg32 = pci_read_config32(dev, D31F2_SDAT);
if (!is_mobile)
reg32 &= ~((7 << 27) | (7 << 24));
reg32 &= ~((7 << 19) | (7 << 16) | 0xffff);
if (!is_mobile)
reg32 |= (2 << 27) | (2 << 24);
reg32 |= (2 << 19) | (2 << 16) | 0x00aa;
pci_write_config32(dev, D31F2_SDAT, reg32);
pci_write_config8(dev, D31F2_SIDX, 0x94);
pci_write_config32(dev, D31F2_SDAT, 0x00000022);
pci_write_config8(dev, D31F2_SIDX, 0xa0);
reg32 = pci_read_config32(dev, D31F2_SDAT);
reg32 &= ~((7 << 3) | (7 << 0));
reg32 |= (3 << 3) | (3 << 0);
pci_write_config32(dev, D31F2_SDAT, reg32);
pci_write_config8(dev, D31F2_SIDX, 0xa8);
reg32 = pci_read_config32(dev, D31F2_SDAT);
reg32 &= ~((7 << 19) | (7 << 16) | (7 << 3) | (7 << 0));
reg32 |= (4 << 19) | (4 << 16) | (2 << 3) | (2 << 0);
pci_write_config32(dev, D31F2_SDAT, reg32);
pci_write_config8(dev, D31F2_SIDX, 0xac);
reg32 = pci_read_config32(dev, D31F2_SDAT);
reg32 &= ~((7 << 19) | (7 << 16) | 0xffff);
reg32 |= (2 << 19) | (2 << 16) | 0x000a;
pci_write_config32(dev, D31F2_SDAT, reg32);
}
static void sata_init(struct device *const dev)
{
u16 reg16;
/* Get the chip configuration */
const config_t *const config = dev->chip_info;
const u16 devid = pci_read_config16(dev, PCI_DEVICE_ID);
const int is_mobile = (devid == 0x2928) || (devid == 0x2929);
u8 sata_mode;
printk(BIOS_DEBUG, "i82801ix_sata: initializing...\n");
if (config == NULL) {
printk(BIOS_ERR, "i82801ix_sata: error: "
"device not in devicetree.cb!\n");
return;
}
if (get_option(&sata_mode, "sata_mode") != CB_SUCCESS)
/* Default to AHCI */
sata_mode = 0;
/*
* TODO: In contrast to ICH7 and PCH code we don't set
* timings, dma and IDE-I/O settings here. Looks like they
* became obsolete with the fading of real IDE ports.
* Maybe we can safely remove those settings from PCH code and
* even ICH7 code if it doesn't use the feature to combine the
* IDE and SATA controllers.
*/
pci_write_config16(dev, PCI_COMMAND,
PCI_COMMAND_MASTER |
PCI_COMMAND_MEMORY | /* read-only in IDE modes */
PCI_COMMAND_IO);
if (sata_mode != 0)
/* No AHCI: clear AHCI base */
pci_write_config32(dev, PCI_BASE_ADDRESS_5, 0x00000000);
if (sata_mode == 0) {
printk(BIOS_DEBUG, "SATA controller in AHCI mode.\n");
} else {
printk(BIOS_DEBUG, "SATA controller in native mode.\n");
/* Enable native mode on both primary and secondary. */
pci_write_config8(dev, PCI_CLASS_PROG, 0x8f);
}
/* Looks like we should only enable decoding here. */
pci_write_config16(dev, D31F2_IDE_TIM_PRI, (1 << 15));
pci_write_config16(dev, D31F2_IDE_TIM_SEC, (1 << 15));
/* Port enable. For AHCI, it's managed in memory mapped space. */
reg16 = pci_read_config16(dev, 0x92);
reg16 &= ~0x3f;
reg16 |= (1 << 15) | ((sata_mode == 0) ? 0x3f : config->sata_port_map);
pci_write_config16(dev, 0x92, reg16);
/* SATA clock settings */
u32 sclkcg = 0;
if (config->sata_clock_request &&
!(inb(DEFAULT_GPIOBASE + 0x30) & (1 << (35 - 32))))
sclkcg |= 1 << 30; /* Enable SATA clock request. */
/* Disable unused ports. */
sclkcg |= ((~config->sata_port_map) & 0x3f) << 24;
/* Must be programmed. */
sclkcg |= 0x193;
pci_write_config32(dev, 0x94, sclkcg);
if (is_mobile && config->sata_traffic_monitor) {
const device_t lpc_dev = dev_find_slot(0, PCI_DEVFN(0x1f, 0));
if (((pci_read_config8(lpc_dev, D31F0_CxSTATE_CNF)
>> 3) & 3) == 3) {
u8 reg8 = pci_read_config8(dev, 0x9c);
reg8 &= ~(0x1f << 2);
reg8 |= 3 << 2;
pci_write_config8(dev, 0x9c, reg8);
}
}
if (sata_mode == 0)
sata_enable_ahci_mmap(dev, config->sata_port_map, is_mobile);
sata_program_indexed(dev, is_mobile);
}
static void sata_enable(device_t dev)
{
/* Get the chip configuration */
const config_t *const config = dev->chip_info;
u16 map = 0;
u8 sata_mode;
if (!config)
return;
if (get_option(&sata_mode, "sata_mode") != CB_SUCCESS)
/* Default to AHCI */
sata_mode = 0;
/*
* Set SATA controller mode early so the resource allocator can
* properly assign IO/Memory resources for the controller.
*/
if (sata_mode == 0)
map = 0x0040 | 0x0020; /* SATA mode + all ports on D31:F2 */
map |= (config->sata_port_map ^ 0x3f) << 8;
pci_write_config16(dev, 0x90, map);
}
static void sata_set_subsystem(device_t dev, unsigned vendor, unsigned device)
{
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));
}
}
static struct pci_operations sata_pci_ops = {
.set_subsystem = sata_set_subsystem,
};
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 = sata_enable,
.scan_bus = 0,
.ops_pci = &sata_pci_ops,
};
static const unsigned short pci_device_ids[] = {
0x2920, 0x2921, 0x2922, 0x2923,
0x2928, 0x2929,
0,
};
static const struct pci_driver pch_sata __pci_driver = {
.ops = &sata_ops,
.vendor = PCI_VENDOR_ID_INTEL,
.devices = pci_device_ids,
};

View File

@ -0,0 +1,112 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
*
* 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.
*
* 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.
*/
#include <console/console.h>
#include <device/device.h>
#include <device/path.h>
#include <device/smbus.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <device/pci_ops.h>
#include <arch/io.h>
#include "smbus.h"
static void pch_smbus_init(device_t dev)
{
u16 reg16;
/* Enable clock gating */
reg16 = pci_read_config16(dev, 0x80);
reg16 &= ~((1 << 8)|(1 << 10)|(1 << 12)|(1 << 14));
pci_write_config16(dev, 0x80, reg16);
}
static int lsmbus_read_byte(device_t dev, u8 address)
{
u16 device;
struct resource *res;
struct bus *pbus;
device = dev->path.i2c.device;
pbus = get_pbus_smbus(dev);
res = find_resource(pbus->dev, 0x20);
return do_smbus_read_byte(res->base, device, address);
}
static int lsmbus_write_byte(device_t dev, u8 address, u8 val)
{
u16 device;
struct resource *res;
struct bus *pbus;
device = dev->path.i2c.device;
pbus = get_pbus_smbus(dev);
res = find_resource(pbus->dev, 0x20);
return do_smbus_write_byte(res->base, device, address, val);
}
static struct smbus_bus_operations lops_smbus_bus = {
.read_byte = lsmbus_read_byte,
.write_byte = lsmbus_write_byte,
};
static void smbus_set_subsystem(device_t dev, unsigned vendor, unsigned device)
{
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));
}
}
static struct pci_operations smbus_pci_ops = {
.set_subsystem = smbus_set_subsystem,
};
static void smbus_read_resources(device_t dev)
{
struct resource *res = new_resource(dev, PCI_BASE_ADDRESS_4);
res->base = SMBUS_IO_BASE;
res->size = 32;
res->limit = res->base + res->size - 1;
res->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_RESERVE |
IORESOURCE_STORED | IORESOURCE_ASSIGNED;
/* Also add MMIO resource */
res = pci_get_resource(dev, PCI_BASE_ADDRESS_0);
}
static struct device_operations smbus_ops = {
.read_resources = smbus_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.scan_bus = scan_smbus,
.init = pch_smbus_init,
.ops_smbus_bus = &lops_smbus_bus,
.ops_pci = &smbus_pci_ops,
};
static const unsigned short pci_device_ids[] = { 0x2930, 0 };
static const struct pci_driver pch_smbus __pci_driver = {
.ops = &smbus_ops,
.vendor = PCI_VENDOR_ID_INTEL,
.devices = pci_device_ids,
};

View File

@ -0,0 +1,140 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
* Copyright (C) 2009 coresystems GmbH
*
* 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.
*
* 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.
*/
#include <device/smbus_def.h>
#include "i82801ix.h"
static void smbus_delay(void)
{
inb(0x80);
}
static int smbus_wait_until_ready(u16 smbus_base)
{
unsigned loops = SMBUS_TIMEOUT;
unsigned char byte;
do {
smbus_delay();
if (--loops == 0)
break;
byte = inb(smbus_base + SMBHSTSTAT);
} while (byte & 1);
return loops ? 0 : -1;
}
static int smbus_wait_until_done(u16 smbus_base)
{
unsigned loops = SMBUS_TIMEOUT;
unsigned char byte;
do {
smbus_delay();
if (--loops == 0)
break;
byte = inb(smbus_base + SMBHSTSTAT);
} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
return loops ? 0 : -1;
}
static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
{
unsigned char global_status_register;
unsigned char byte;
if (smbus_wait_until_ready(smbus_base) < 0) {
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
}
/* Setup transaction */
/* Disable interrupts */
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
/* Set the device I'm talking too */
outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
/* Set the command/address... */
outb(address & 0xff, smbus_base + SMBHSTCMD);
/* Set up for a byte data read */
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
(smbus_base + SMBHSTCTL));
/* Clear any lingering errors, so the transaction will run */
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
/* Clear the data byte... */
outb(0, smbus_base + SMBHSTDAT0);
/* Start the command */
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
smbus_base + SMBHSTCTL);
/* Poll for transaction completion */
if (smbus_wait_until_done(smbus_base) < 0) {
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
}
global_status_register = inb(smbus_base + SMBHSTSTAT);
/* Ignore the "In Use" status... */
global_status_register &= ~(3 << 5);
/* Read results of transaction */
byte = inb(smbus_base + SMBHSTDAT0);
if (global_status_register != (1 << 1)) {
return SMBUS_ERROR;
}
return byte;
}
#ifndef __PRE_RAM__
static int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned address, unsigned data)
{
unsigned char global_status_register;
if (smbus_wait_until_ready(smbus_base) < 0)
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
/* Setup transaction */
/* Disable interrupts */
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
/* Set the device I'm talking too */
outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
/* Set the command/address... */
outb(address & 0xff, smbus_base + SMBHSTCMD);
/* Set up for a byte data read */
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
(smbus_base + SMBHSTCTL));
/* Clear any lingering errors, so the transaction will run */
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
/* Clear the data byte... */
outb(data, smbus_base + SMBHSTDAT0);
/* Start the command */
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
smbus_base + SMBHSTCTL);
/* Poll for transaction completion */
if (smbus_wait_until_done(smbus_base) < 0)
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
global_status_register = inb(smbus_base + SMBHSTSTAT);
/* Ignore the "In Use" status... */
global_status_register &= ~(3 << 5);
/* Read results of transaction */
if (global_status_register != (1 << 1))
return SMBUS_ERROR;
return 0;
}
#endif

View File

@ -0,0 +1,377 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
* 2012 secunet Security Networks AG
*
* 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.
*
* 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.
*/
#include <device/device.h>
#include <device/pci.h>
#include <console/console.h>
#include <arch/io.h>
#include <arch/acpi.h>
#include <cpu/cpu.h>
#include <cpu/x86/cache.h>
#include <cpu/x86/smm.h>
#include <string.h>
#include "i82801ix.h"
/* I945/GM45 */
#define SMRAM 0x9d
#define D_OPEN (1 << 6)
#define D_CLS (1 << 5)
#define D_LCK (1 << 4)
#define G_SMRAME (1 << 3)
#define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0))
/* While we read PMBASE dynamically in case it changed, let's
* initialize it with a sane value
*/
static u16 pmbase = DEFAULT_PMBASE;
/**
* @brief read and clear PM1_STS
* @return PM1_STS register
*/
static u16 reset_pm1_status(void)
{
u16 reg16;
reg16 = inw(pmbase + PM1_STS);
/* set status bits are cleared by writing 1 to them */
outw(reg16, pmbase + PM1_STS);
return reg16;
}
static void dump_pm1_status(u16 pm1_sts)
{
printk(BIOS_DEBUG, "PM1_STS: ");
if (pm1_sts & (1 << 15)) printk(BIOS_DEBUG, "WAK ");
if (pm1_sts & (1 << 14)) printk(BIOS_DEBUG, "PCIEXPWAK ");
if (pm1_sts & (1 << 11)) printk(BIOS_DEBUG, "PRBTNOR ");
if (pm1_sts & (1 << 10)) printk(BIOS_DEBUG, "RTC ");
if (pm1_sts & (1 << 8)) printk(BIOS_DEBUG, "PWRBTN ");
if (pm1_sts & (1 << 5)) printk(BIOS_DEBUG, "GBL ");
if (pm1_sts & (1 << 4)) printk(BIOS_DEBUG, "BM ");
if (pm1_sts & (1 << 0)) printk(BIOS_DEBUG, "TMROF ");
printk(BIOS_DEBUG, "\n");
}
/**
* @brief read and clear SMI_STS
* @return SMI_STS register
*/
static u32 reset_smi_status(void)
{
u32 reg32;
reg32 = inl(pmbase + SMI_STS);
/* set status bits are cleared by writing 1 to them */
outl(reg32, pmbase + SMI_STS);
return reg32;
}
static void dump_smi_status(u32 smi_sts)
{
printk(BIOS_DEBUG, "SMI_STS: ");
if (smi_sts & (1 << 27)) printk(BIOS_DEBUG, "GPIO_UNLOCK ");
if (smi_sts & (1 << 26)) printk(BIOS_DEBUG, "SPI ");
if (smi_sts & (1 << 21)) printk(BIOS_DEBUG, "MONITOR ");
if (smi_sts & (1 << 20)) printk(BIOS_DEBUG, "PCI_EXP_SMI ");
if (smi_sts & (1 << 18)) printk(BIOS_DEBUG, "INTEL_USB2 ");
if (smi_sts & (1 << 17)) printk(BIOS_DEBUG, "LEGACY_USB2 ");
if (smi_sts & (1 << 16)) printk(BIOS_DEBUG, "SMBUS_SMI ");
if (smi_sts & (1 << 15)) printk(BIOS_DEBUG, "SERIRQ_SMI ");
if (smi_sts & (1 << 14)) printk(BIOS_DEBUG, "PERIODIC ");
if (smi_sts & (1 << 13)) printk(BIOS_DEBUG, "TCO ");
if (smi_sts & (1 << 12)) printk(BIOS_DEBUG, "DEVMON ");
if (smi_sts & (1 << 11)) printk(BIOS_DEBUG, "MCSMI ");
if (smi_sts & (1 << 10)) printk(BIOS_DEBUG, "GPI ");
if (smi_sts & (1 << 9)) printk(BIOS_DEBUG, "GPE0 ");
if (smi_sts & (1 << 8)) printk(BIOS_DEBUG, "PM1 ");
if (smi_sts & (1 << 6)) printk(BIOS_DEBUG, "SWSMI_TMR ");
if (smi_sts & (1 << 5)) printk(BIOS_DEBUG, "APM ");
if (smi_sts & (1 << 4)) printk(BIOS_DEBUG, "SLP_SMI ");
if (smi_sts & (1 << 3)) printk(BIOS_DEBUG, "LEGACY_USB ");
if (smi_sts & (1 << 2)) printk(BIOS_DEBUG, "BIOS ");
printk(BIOS_DEBUG, "\n");
}
/**
* @brief read and clear GPE0_STS
* @return GPE0_STS register
*/
static u64 reset_gpe0_status(void)
{
u32 reg_h, reg_l;
reg_l = inl(pmbase + GPE0_STS);
reg_h = inl(pmbase + GPE0_STS + 4);
/* set status bits are cleared by writing 1 to them */
outl(reg_l, pmbase + GPE0_STS);
outl(reg_h, pmbase + GPE0_STS + 4);
return (((u64)reg_h) << 32) | reg_l;
}
static void dump_gpe0_status(u64 gpe0_sts)
{
int i;
printk(BIOS_DEBUG, "GPE0_STS: ");
if (gpe0_sts & (1LL << 32)) printk(BIOS_DEBUG, "USB6 ");
for (i=31; i>= 16; i--) {
if (gpe0_sts & (1 << i)) printk(BIOS_DEBUG, "GPIO%d ", (i-16));
}
if (gpe0_sts & (1 << 14)) printk(BIOS_DEBUG, "USB4 ");
if (gpe0_sts & (1 << 13)) printk(BIOS_DEBUG, "PME_B0 ");
if (gpe0_sts & (1 << 12)) printk(BIOS_DEBUG, "USB3 ");
if (gpe0_sts & (1 << 11)) printk(BIOS_DEBUG, "PME ");
if (gpe0_sts & (1 << 10)) printk(BIOS_DEBUG, "EL_SCI/BATLOW ");
if (gpe0_sts & (1 << 9)) printk(BIOS_DEBUG, "PCI_EXP ");
if (gpe0_sts & (1 << 8)) printk(BIOS_DEBUG, "RI ");
if (gpe0_sts & (1 << 7)) printk(BIOS_DEBUG, "SMB_WAK ");
if (gpe0_sts & (1 << 6)) printk(BIOS_DEBUG, "TCO_SCI ");
if (gpe0_sts & (1 << 5)) printk(BIOS_DEBUG, "USB5 ");
if (gpe0_sts & (1 << 4)) printk(BIOS_DEBUG, "USB2 ");
if (gpe0_sts & (1 << 3)) printk(BIOS_DEBUG, "USB1 ");
if (gpe0_sts & (1 << 2)) printk(BIOS_DEBUG, "SWGPE ");
if (gpe0_sts & (1 << 1)) printk(BIOS_DEBUG, "HOT_PLUG ");
if (gpe0_sts & (1 << 0)) printk(BIOS_DEBUG, "THRM ");
printk(BIOS_DEBUG, "\n");
}
/**
* @brief read and clear ALT_GP_SMI_STS
* @return ALT_GP_SMI_STS register
*/
static u16 reset_alt_gp_smi_status(void)
{
u16 reg16;
reg16 = inl(pmbase + ALT_GP_SMI_STS);
/* set status bits are cleared by writing 1 to them */
outl(reg16, pmbase + ALT_GP_SMI_STS);
return reg16;
}
static void dump_alt_gp_smi_status(u16 alt_gp_smi_sts)
{
int i;
printk(BIOS_DEBUG, "ALT_GP_SMI_STS: ");
for (i=15; i>= 0; i--) {
if (alt_gp_smi_sts & (1 << i)) printk(BIOS_DEBUG, "GPI%d ", i);
}
printk(BIOS_DEBUG, "\n");
}
/**
* @brief read and clear TCOx_STS
* @return TCOx_STS registers
*/
static u32 reset_tco_status(void)
{
u32 tcobase = pmbase + 0x60;
u32 reg32;
reg32 = inl(tcobase + 0x04);
/* set status bits are cleared by writing 1 to them */
outl(reg32 & ~(1<<18), tcobase + 0x04); // Don't clear BOOT_STS before SECOND_TO_STS
if (reg32 & (1 << 18))
outl(reg32 & (1<<18), tcobase + 0x04); // clear BOOT_STS
return reg32;
}
static void dump_tco_status(u32 tco_sts)
{
printk(BIOS_DEBUG, "TCO_STS: ");
if (tco_sts & (1 << 20)) printk(BIOS_DEBUG, "SMLINK_SLV ");
if (tco_sts & (1 << 18)) printk(BIOS_DEBUG, "BOOT ");
if (tco_sts & (1 << 17)) printk(BIOS_DEBUG, "SECOND_TO ");
if (tco_sts & (1 << 16)) printk(BIOS_DEBUG, "INTRD_DET ");
if (tco_sts & (1 << 12)) printk(BIOS_DEBUG, "DMISERR ");
if (tco_sts & (1 << 10)) printk(BIOS_DEBUG, "DMISMI ");
if (tco_sts & (1 << 9)) printk(BIOS_DEBUG, "DMISCI ");
if (tco_sts & (1 << 8)) printk(BIOS_DEBUG, "BIOSWR ");
if (tco_sts & (1 << 7)) printk(BIOS_DEBUG, "NEWCENTURY ");
if (tco_sts & (1 << 3)) printk(BIOS_DEBUG, "TIMEOUT ");
if (tco_sts & (1 << 2)) printk(BIOS_DEBUG, "TCO_INT ");
if (tco_sts & (1 << 1)) printk(BIOS_DEBUG, "SW_TCO ");
if (tco_sts & (1 << 0)) printk(BIOS_DEBUG, "NMI2SMI ");
printk(BIOS_DEBUG, "\n");
}
/**
* @brief Set the EOS bit
*/
static void smi_set_eos(void)
{
u8 reg8;
reg8 = inb(pmbase + SMI_EN);
reg8 |= EOS;
outb(reg8, pmbase + SMI_EN);
}
extern uint8_t smm_relocation_start, smm_relocation_end;
static void smm_relocate(void)
{
u32 smi_en;
u16 pm1_en;
printk(BIOS_DEBUG, "Initializing SMM handler...");
pmbase = pci_read_config16(dev_find_slot(0, PCI_DEVFN(0x1f, 0)), D31F0_PMBASE) & 0xfffc;
printk(BIOS_SPEW, " ... pmbase = 0x%04x\n", pmbase);
smi_en = inl(pmbase + SMI_EN);
if (smi_en & GBL_SMI_EN) {
printk(BIOS_INFO, "SMI# handler already enabled?\n");
return;
}
/* copy the SMM relocation code */
memcpy((void *)0x38000, &smm_relocation_start,
&smm_relocation_end - &smm_relocation_start);
wbinvd();
printk(BIOS_DEBUG, "\n");
dump_smi_status(reset_smi_status());
dump_pm1_status(reset_pm1_status());
dump_gpe0_status(reset_gpe0_status());
dump_alt_gp_smi_status(reset_alt_gp_smi_status());
dump_tco_status(reset_tco_status());
/* Enable SMI generation:
* - on TCO events
* - on APMC writes (io 0xb2)
* - on writes to GBL_RLS (bios commands)
* No SMIs:
* - on microcontroller writes (io 0x62/0x66)
*/
smi_en = 0; /* reset SMI enables */
smi_en |= TCO_EN;
smi_en |= APMC_EN;
#if DEBUG_PERIODIC_SMIS
/* Set DEBUG_PERIODIC_SMIS in i82801ix.h to debug using
* periodic SMIs.
*/
smi_en |= PERIODIC_EN;
#endif
smi_en |= BIOS_EN;
/* The following need to be on for SMIs to happen */
smi_en |= EOS | GBL_SMI_EN;
outl(smi_en, pmbase + SMI_EN);
pm1_en = 0;
pm1_en |= PWRBTN_EN;
pm1_en |= GBL_EN;
outw(pm1_en, pmbase + PM1_EN);
/**
* There are several methods of raising a controlled SMI# via
* software, among them:
* - Writes to io 0xb2 (APMC)
* - Writes to the Local Apic ICR with Delivery mode SMI.
*
* Using the local apic is a bit more tricky. According to
* AMD Family 11 Processor BKDG no destination shorthand must be
* used.
* The whole SMM initialization is quite a bit hardware specific, so
* I'm not too worried about the better of the methods at the moment
*/
/* raise an SMI interrupt */
printk(BIOS_SPEW, " ... raise SMI#\n");
outb(0x00, 0xb2);
}
static int smm_handler_copied = 0;
static void smm_install(void)
{
/* The first CPU running this gets to copy the SMM handler. But not all
* of them.
*/
if (smm_handler_copied)
return;
smm_handler_copied = 1;
/* if we're resuming from S3, the SMM code is already in place,
* so don't copy it again to keep the current SMM state */
if (!acpi_is_wakeup_s3()) {
/* enable the SMM memory window */
pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM,
D_OPEN | G_SMRAME | C_BASE_SEG);
/* copy the real SMM handler */
memcpy((void *)0xa0000, _binary_smm_start,
_binary_smm_end - _binary_smm_start);
wbinvd();
}
/* close the SMM memory window and enable normal SMM */
pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM,
G_SMRAME | C_BASE_SEG);
}
void smm_init(void)
{
/* Put SMM code to 0xa0000 */
smm_install();
/* Put relocation code to 0x38000 and relocate SMBASE */
smm_relocate();
/* We're done. Make sure SMIs can happen! */
smi_set_eos();
}
void smm_lock(void)
{
/* LOCK the SMM memory window and enable normal SMM.
* After running this function, only a full reset can
* make the SMM registers writable again.
*/
printk(BIOS_DEBUG, "Locking SMM.\n");
pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM,
D_LCK | G_SMRAME | C_BASE_SEG);
}
void smm_setup_structures(void *gnvs, void *tcg, void *smi1)
{
/* The GDT or coreboot table is going to live here. But a long time
* after we relocated the GNVS, so this is not troublesome.
*/
*(u32 *)0x500 = (u32)gnvs;
*(u32 *)0x504 = (u32)tcg;
*(u32 *)0x508 = (u32)smi1;
outb(APM_CNT_GNVS_UPDATE, 0xb2);
}

View File

@ -0,0 +1,525 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
* 2012 secunet Security Networks AG
*
* 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.
*
* 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.
*/
#include <types.h>
#include <arch/io.h>
#include <console/console.h>
#include <cpu/x86/cache.h>
#include <cpu/x86/smm.h>
#include <device/pci_def.h>
#include <pc80/mc146818rtc.h>
#include "i82801ix.h"
#include "nvs.h"
/* While we read PMBASE dynamically in case it changed, let's
* initialize it with a sane value
*/
u16 pmbase = DEFAULT_PMBASE;
u8 smm_initialized = 0;
/* GNVS needs to be updated by an 0xEA PM Trap (B2) after it has been located
* by coreboot.
*/
global_nvs_t *gnvs = (global_nvs_t *)0x0;
void *tcg = (void *)0x0;
void *smi1 = (void *)0x0;
/**
* @brief read and clear PM1_STS
* @return PM1_STS register
*/
static u16 reset_pm1_status(void)
{
u16 reg16;
reg16 = inw(pmbase + PM1_STS);
/* set status bits are cleared by writing 1 to them */
outw(reg16, pmbase + PM1_STS);
return reg16;
}
static void dump_pm1_status(u16 pm1_sts)
{
printk(BIOS_DEBUG, "PM1_STS: ");
if (pm1_sts & (1 << 15)) printk(BIOS_DEBUG, "WAK ");
if (pm1_sts & (1 << 14)) printk(BIOS_DEBUG, "PCIEXPWAK ");
if (pm1_sts & (1 << 11)) printk(BIOS_DEBUG, "PRBTNOR ");
if (pm1_sts & (1 << 10)) printk(BIOS_DEBUG, "RTC ");
if (pm1_sts & (1 << 8)) printk(BIOS_DEBUG, "PWRBTN ");
if (pm1_sts & (1 << 5)) printk(BIOS_DEBUG, "GBL ");
if (pm1_sts & (1 << 4)) printk(BIOS_DEBUG, "BM ");
if (pm1_sts & (1 << 0)) printk(BIOS_DEBUG, "TMROF ");
printk(BIOS_DEBUG, "\n");
}
/**
* @brief read and clear SMI_STS
* @return SMI_STS register
*/
static u32 reset_smi_status(void)
{
u32 reg32;
reg32 = inl(pmbase + SMI_STS);
/* set status bits are cleared by writing 1 to them */
outl(reg32, pmbase + SMI_STS);
return reg32;
}
static void dump_smi_status(u32 smi_sts)
{
printk(BIOS_DEBUG, "SMI_STS: ");
if (smi_sts & (1 << 27)) printk(BIOS_DEBUG, "GPIO_UNLOCK ");
if (smi_sts & (1 << 26)) printk(BIOS_DEBUG, "SPI ");
if (smi_sts & (1 << 21)) printk(BIOS_DEBUG, "MONITOR ");
if (smi_sts & (1 << 20)) printk(BIOS_DEBUG, "PCI_EXP_SMI ");
if (smi_sts & (1 << 18)) printk(BIOS_DEBUG, "INTEL_USB2 ");
if (smi_sts & (1 << 17)) printk(BIOS_DEBUG, "LEGACY_USB2 ");
if (smi_sts & (1 << 16)) printk(BIOS_DEBUG, "SMBUS_SMI ");
if (smi_sts & (1 << 15)) printk(BIOS_DEBUG, "SERIRQ_SMI ");
if (smi_sts & (1 << 14)) printk(BIOS_DEBUG, "PERIODIC ");
if (smi_sts & (1 << 13)) printk(BIOS_DEBUG, "TCO ");
if (smi_sts & (1 << 12)) printk(BIOS_DEBUG, "DEVMON ");
if (smi_sts & (1 << 11)) printk(BIOS_DEBUG, "MCSMI ");
if (smi_sts & (1 << 10)) printk(BIOS_DEBUG, "GPI ");
if (smi_sts & (1 << 9)) printk(BIOS_DEBUG, "GPE0 ");
if (smi_sts & (1 << 8)) printk(BIOS_DEBUG, "PM1 ");
if (smi_sts & (1 << 6)) printk(BIOS_DEBUG, "SWSMI_TMR ");
if (smi_sts & (1 << 5)) printk(BIOS_DEBUG, "APM ");
if (smi_sts & (1 << 4)) printk(BIOS_DEBUG, "SLP_SMI ");
if (smi_sts & (1 << 3)) printk(BIOS_DEBUG, "LEGACY_USB ");
if (smi_sts & (1 << 2)) printk(BIOS_DEBUG, "BIOS ");
printk(BIOS_DEBUG, "\n");
}
/**
* @brief read and clear GPE0_STS
* @return GPE0_STS register
*/
static u64 reset_gpe0_status(void)
{
u32 reg_h, reg_l;
reg_l = inl(pmbase + GPE0_STS);
reg_h = inl(pmbase + GPE0_STS + 4);
/* set status bits are cleared by writing 1 to them */
outl(reg_l, pmbase + GPE0_STS);
outl(reg_h, pmbase + GPE0_STS + 4);
return (((u64)reg_h) << 32) | reg_l;
}
static void dump_gpe0_status(u64 gpe0_sts)
{
int i;
printk(BIOS_DEBUG, "GPE0_STS: ");
if (gpe0_sts & (1LL << 32)) printk(BIOS_DEBUG, "USB6 ");
for (i=31; i>= 16; i--) {
if (gpe0_sts & (1 << i)) printk(BIOS_DEBUG, "GPIO%d ", (i-16));
}
if (gpe0_sts & (1 << 14)) printk(BIOS_DEBUG, "USB4 ");
if (gpe0_sts & (1 << 13)) printk(BIOS_DEBUG, "PME_B0 ");
if (gpe0_sts & (1 << 12)) printk(BIOS_DEBUG, "USB3 ");
if (gpe0_sts & (1 << 11)) printk(BIOS_DEBUG, "PME ");
if (gpe0_sts & (1 << 10)) printk(BIOS_DEBUG, "EL_SCI/BATLOW ");
if (gpe0_sts & (1 << 9)) printk(BIOS_DEBUG, "PCI_EXP ");
if (gpe0_sts & (1 << 8)) printk(BIOS_DEBUG, "RI ");
if (gpe0_sts & (1 << 7)) printk(BIOS_DEBUG, "SMB_WAK ");
if (gpe0_sts & (1 << 6)) printk(BIOS_DEBUG, "TCO_SCI ");
if (gpe0_sts & (1 << 5)) printk(BIOS_DEBUG, "USB5 ");
if (gpe0_sts & (1 << 4)) printk(BIOS_DEBUG, "USB2 ");
if (gpe0_sts & (1 << 3)) printk(BIOS_DEBUG, "USB1 ");
if (gpe0_sts & (1 << 2)) printk(BIOS_DEBUG, "SWGPE ");
if (gpe0_sts & (1 << 1)) printk(BIOS_DEBUG, "HOT_PLUG ");
if (gpe0_sts & (1 << 0)) printk(BIOS_DEBUG, "THRM ");
printk(BIOS_DEBUG, "\n");
}
/**
* @brief read and clear TCOx_STS
* @return TCOx_STS registers
*/
static u32 reset_tco_status(void)
{
u32 tcobase = pmbase + 0x60;
u32 reg32;
reg32 = inl(tcobase + 0x04);
/* set status bits are cleared by writing 1 to them */
outl(reg32 & ~(1<<18), tcobase + 0x04); // Don't clear BOOT_STS before SECOND_TO_STS
if (reg32 & (1 << 18))
outl(reg32 & (1<<18), tcobase + 0x04); // clear BOOT_STS
return reg32;
}
static void dump_tco_status(u32 tco_sts)
{
printk(BIOS_DEBUG, "TCO_STS: ");
if (tco_sts & (1 << 20)) printk(BIOS_DEBUG, "SMLINK_SLV ");
if (tco_sts & (1 << 18)) printk(BIOS_DEBUG, "BOOT ");
if (tco_sts & (1 << 17)) printk(BIOS_DEBUG, "SECOND_TO ");
if (tco_sts & (1 << 16)) printk(BIOS_DEBUG, "INTRD_DET ");
if (tco_sts & (1 << 12)) printk(BIOS_DEBUG, "DMISERR ");
if (tco_sts & (1 << 10)) printk(BIOS_DEBUG, "DMISMI ");
if (tco_sts & (1 << 9)) printk(BIOS_DEBUG, "DMISCI ");
if (tco_sts & (1 << 8)) printk(BIOS_DEBUG, "BIOSWR ");
if (tco_sts & (1 << 7)) printk(BIOS_DEBUG, "NEWCENTURY ");
if (tco_sts & (1 << 3)) printk(BIOS_DEBUG, "TIMEOUT ");
if (tco_sts & (1 << 2)) printk(BIOS_DEBUG, "TCO_INT ");
if (tco_sts & (1 << 1)) printk(BIOS_DEBUG, "SW_TCO ");
if (tco_sts & (1 << 0)) printk(BIOS_DEBUG, "NMI2SMI ");
printk(BIOS_DEBUG, "\n");
}
int southbridge_io_trap_handler(int smif)
{
switch (smif) {
case 0x32:
printk(BIOS_DEBUG, "OS Init\n");
/* gnvs->smif:
* On success, the IO Trap Handler returns 0
* On failure, the IO Trap Handler returns a value != 0
*/
gnvs->smif = 0;
return 1; /* IO trap handled */
}
/* Not handled */
return 0;
}
/**
* @brief Set the EOS bit
*/
void southbridge_smi_set_eos(void)
{
u8 reg8;
reg8 = inb(pmbase + SMI_EN);
reg8 |= EOS;
outb(reg8, pmbase + SMI_EN);
}
static void southbridge_smi_apmc(unsigned int node, smm_state_save_area_t *state_save)
{
u32 pmctrl;
u8 reg8;
/* Emulate B2 register as the FADT / Linux expects it */
reg8 = inb(APM_CNT);
if (mainboard_smi_apmc(reg8))
return;
switch (reg8) {
case APM_CNT_CST_CONTROL:
/* Calling this function seems to cause
* some kind of race condition in Linux
* and causes a kernel oops
*/
printk(BIOS_DEBUG, "C-state control\n");
break;
case APM_CNT_PST_CONTROL:
/* Calling this function seems to cause
* some kind of race condition in Linux
* and causes a kernel oops
*/
printk(BIOS_DEBUG, "P-state control\n");
break;
case APM_CNT_ACPI_DISABLE:
pmctrl = inl(pmbase + PM1_CNT);
pmctrl &= ~SCI_EN;
outl(pmctrl, pmbase + PM1_CNT);
printk(BIOS_DEBUG, "SMI#: ACPI disabled.\n");
break;
case APM_CNT_ACPI_ENABLE:
pmctrl = inl(pmbase + PM1_CNT);
pmctrl |= SCI_EN;
outl(pmctrl, pmbase + PM1_CNT);
printk(BIOS_DEBUG, "SMI#: ACPI enabled.\n");
break;
case APM_CNT_GNVS_UPDATE:
if (smm_initialized) {
printk(BIOS_DEBUG, "SMI#: SMM structures already initialized!\n");
return;
}
gnvs = *(global_nvs_t **)0x500;
tcg = *(void **)0x504;
smi1 = *(void **)0x508;
smm_initialized = 1;
printk(BIOS_DEBUG, "SMI#: Setting up structures to %p, %p, %p\n", gnvs, tcg, smi1);
break;
default:
printk(BIOS_DEBUG, "SMI#: Unknown function APM_CNT=%02x\n", reg8);
}
}
static void southbridge_smi_pm1(unsigned int node, smm_state_save_area_t *state_save)
{
u16 pm1_sts;
volatile u8 cmos_status;
pm1_sts = reset_pm1_status();
dump_pm1_status(pm1_sts);
/* While OSPM is not active, poweroff immediately
* on a power button event.
*/
if (pm1_sts & PWRBTN_STS) {
// power button pressed
u32 reg32;
reg32 = (7 << 10) | (1 << 13);
outl(reg32, pmbase + PM1_CNT);
}
if (pm1_sts & RTC_STS) {
/* read RTC status register to disable the interrupt */
cmos_status = cmos_read(RTC_REG_C);
printk(BIOS_DEBUG, "RTC IRQ status: %02X\n", cmos_status);
}
}
static void southbridge_smi_gpe0(unsigned int node, smm_state_save_area_t *state_save)
{
u32 gpe0_sts;
gpe0_sts = reset_gpe0_status();
dump_gpe0_status(gpe0_sts);
}
static void southbridge_smi_gpi(unsigned int node, smm_state_save_area_t *state_save)
{
u16 reg16;
reg16 = inw(pmbase + ALT_GP_SMI_STS);
outl(reg16, pmbase + ALT_GP_SMI_STS);
reg16 &= inw(pmbase + ALT_GP_SMI_EN);
mainboard_smi_gpi(reg16);
if (reg16)
printk(BIOS_DEBUG, "GPI (mask %04x)\n",reg16);
}
static void southbridge_smi_tco(unsigned int node, smm_state_save_area_t *state_save)
{
u32 tco_sts;
tco_sts = reset_tco_status();
/* Any TCO event? */
if (!tco_sts)
return;
if (tco_sts & (1 << 8)) { // BIOSWR
u8 bios_cntl;
bios_cntl = pci_read_config16(PCI_DEV(0, 0x1f, 0), 0xdc);
if (bios_cntl & 1) {
/* BWE is RW, so the SMI was caused by a
* write to BWE, not by a write to the BIOS
*/
/* This is the place where we notice someone
* is trying to tinker with the BIOS. We are
* trying to be nice and just ignore it. A more
* resolute answer would be to power down the
* box.
*/
printk(BIOS_DEBUG, "Switching back to RO\n");
pci_write_config32(PCI_DEV(0, 0x1f, 0), 0xdc, (bios_cntl & ~1));
} /* No else for now? */
} else if (tco_sts & (1 << 3)) { /* TIMEOUT */
/* Handle TCO timeout */
printk(BIOS_DEBUG, "TCO Timeout.\n");
} else {
dump_tco_status(tco_sts);
}
}
#if DEBUG_PERIODIC_SMIS
static void southbridge_smi_periodic(unsigned int node, smm_state_save_area_t *state_save)
{
printk(BIOS_DEBUG, "Periodic SMI.\n");
}
#endif
static void southbridge_smi_monitor(unsigned int node, smm_state_save_area_t *state_save)
{
#define IOTRAP(x) (trap_sts & (1 << x))
u32 trap_sts, trap_cycle;
u32 data, mask = 0;
int i;
trap_sts = RCBA32(0x1e00); // TRSR - Trap Status Register
RCBA32(0x1e00) = trap_sts; // Clear trap(s) in TRSR
trap_cycle = RCBA32(0x1e10);
for (i=16; i<20; i++) {
if (trap_cycle & (1 << i))
mask |= (0xff << ((i - 16) << 3));
}
/* IOTRAP(3) SMI function call */
if (IOTRAP(3)) {
if (gnvs && gnvs->smif)
io_trap_handler(gnvs->smif); // call function smif
return;
}
/* IOTRAP(2) currently unused
* IOTRAP(1) currently unused */
/* IOTRAP(0) SMIC */
if (IOTRAP(0)) {
if (!(trap_cycle & (1 << 24))) { // It's a write
printk(BIOS_DEBUG, "SMI1 command\n");
data = RCBA32(0x1e18);
data &= mask;
// if (smi1)
// southbridge_smi_command(data);
// return;
}
// Fall through to debug
}
printk(BIOS_DEBUG, " trapped io address = 0x%x\n", trap_cycle & 0xfffc);
for (i=0; i < 4; i++) if (IOTRAP(i)) printk(BIOS_DEBUG, " TRAP = %d\n", i);
printk(BIOS_DEBUG, " AHBE = %x\n", (trap_cycle >> 16) & 0xf);
printk(BIOS_DEBUG, " MASK = 0x%08x\n", mask);
printk(BIOS_DEBUG, " read/write: %s\n", (trap_cycle & (1 << 24)) ? "read" : "write");
if (!(trap_cycle & (1 << 24))) {
/* Write Cycle */
data = RCBA32(0x1e18);
printk(BIOS_DEBUG, " iotrap written data = 0x%08x\n", data);
}
#undef IOTRAP
}
typedef void (*smi_handler_t)(unsigned int node,
smm_state_save_area_t *state_save);
smi_handler_t southbridge_smi[32] = {
NULL, // [0] reserved
NULL, // [1] reserved
NULL, // [2] BIOS_STS
NULL, // [3] LEGACY_USB_STS
NULL, // [4] SLP_SMI_STS
southbridge_smi_apmc, // [5] APM_STS
NULL, // [6] SWSMI_TMR_STS
NULL, // [7] reserved
southbridge_smi_pm1, // [8] PM1_STS
southbridge_smi_gpe0, // [9] GPE0_STS
southbridge_smi_gpi, // [10] GPI_STS
NULL, // [11] MCSMI_STS
NULL, // [12] DEVMON_STS
southbridge_smi_tco, // [13] TCO_STS
#if DEBUG_PERIODIC_SMIS
southbridge_smi_periodic, // [14] PERIODIC_STS
#else
NULL, // [14] PERIODIC_STS
#endif
NULL, // [15] SERIRQ_SMI_STS
NULL, // [16] SMBUS_SMI_STS
NULL, // [17] LEGACY_USB2_STS
NULL, // [18] INTEL_USB2_STS
NULL, // [19] reserved
NULL, // [20] PCI_EXP_SMI_STS
southbridge_smi_monitor, // [21] MONITOR_STS
NULL, // [22] reserved
NULL, // [23] reserved
NULL, // [24] reserved
NULL, // [25] reserved
NULL, // [26] SPI_STS
NULL, // [27] reserved
NULL, // [28] reserved
NULL, // [29] reserved
NULL, // [30] reserved
NULL // [31] reserved
};
static u32 southbrigde_smi_mask_events(u32 smi_sts)
{
/* Clear all disabled bits in SMI_EN but the reserved ones. */
smi_sts &= inl(pmbase + SMI_EN) | 0xf7f99700;
/* Check if SCI is enabled. */
if (inl(pmbase + PM1_CNT) & SCI_EN)
/* Clear PM1, GPE. */
smi_sts &= ~((1 << 8) | (1 << 9));
/* Check if SPI generates SMI. */
if (!(RCBA16(0x3806) & (1 << 15)) &&
!(RCBA16(0x3891) & (1 << 15)))
/* Clear SPI. */
smi_sts &= ~(1 << 26);
return smi_sts;
}
/**
* @brief Interrupt handler for SMI#
*
* @param node
* @param *state_save
*/
void southbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save)
{
int i, dump = 0;
u32 smi_sts;
/* Update global variable pmbase */
pmbase = pci_read_config16(PCI_DEV(0, 0x1f, 0), D31F0_PMBASE) & 0xfffc;
/* We need to clear the SMI status registers, or we won't see what's
* happening in the following calls.
*/
smi_sts = reset_smi_status();
/* Filter all non-enabled SMI events */
smi_sts = southbrigde_smi_mask_events(smi_sts);
/* Call SMI sub handler for each of the status bits */
for (i = 0; i < 31; i++) {
if (smi_sts & (1 << i)) {
if (southbridge_smi[i])
southbridge_smi[i](node, state_save);
else {
printk(BIOS_DEBUG, "SMI_STS[%d] occurred, but no "
"handler available.\n", i);
dump = 1;
}
}
}
if (dump) {
dump_smi_status(smi_sts);
}
}

View File

@ -0,0 +1,81 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 secunet Security Networks AG
* (Written by Nico Huber <nico.huber@secunet.com> for secunet)
*
* 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.
*
* 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.
*/
#include <arch/io.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include "i82801ix.h"
static void thermal_init(struct device *dev)
{
if (LPC_IS_MOBILE(dev_find_slot(0, PCI_DEVFN(0x1f, 0))))
return;
u8 reg8;
u32 reg32;
pci_write_config32(dev, 0x10, (uintptr_t)DEFAULT_TBAR);
reg32 = pci_read_config32(dev, 0x04);
pci_write_config32(dev, 0x04, reg32 | (1 << 1));
write32(DEFAULT_TBAR + 0x04, 0); /* Clear thermal trip points. */
write32(DEFAULT_TBAR + 0x44, 0);
write8(DEFAULT_TBAR + 0x01, 0xba); /* Enable sensor 0 + 1. */
write8(DEFAULT_TBAR + 0x41, 0xba);
reg8 = read8(DEFAULT_TBAR + 0x08); /* Lock thermal registers. */
write8(DEFAULT_TBAR + 0x08, reg8 | (1 << 7));
reg8 = read8(DEFAULT_TBAR + 0x48);
write8(DEFAULT_TBAR + 0x48, reg8 | (1 << 7));
reg32 = pci_read_config32(dev, 0x04);
pci_write_config32(dev, 0x04, reg32 & ~(1 << 1));
pci_write_config32(dev, 0x10, 0);
}
static void thermal_set_subsystem(device_t dev, unsigned vendor, unsigned device)
{
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));
}
}
static struct pci_operations thermal_pci_ops = {
.set_subsystem = thermal_set_subsystem,
};
static struct device_operations device_ops = {
.read_resources = pci_dev_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.init = thermal_init,
.scan_bus = 0,
.ops_pci = &thermal_pci_ops,
};
static const struct pci_driver ich9_thermal __pci_driver = {
.ops = &device_ops,
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x2932,
};

View File

@ -0,0 +1,80 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
*
* 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.
*
* 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.
*/
#include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include "i82801ix.h"
#include <device/pci_ehci.h>
static void usb_ehci_init(struct device *dev)
{
u32 reg32;
printk(BIOS_DEBUG, "EHCI: Setting up controller.. ");
reg32 = pci_read_config32(dev, PCI_COMMAND);
reg32 |= PCI_COMMAND_MASTER;
pci_write_config32(dev, PCI_COMMAND, reg32);
printk(BIOS_DEBUG, "done.\n");
}
static void usb_ehci_set_subsystem(device_t dev, unsigned vendor, unsigned device)
{
u8 access_cntl;
access_cntl = pci_read_config8(dev, 0x80);
/* Enable writes to protected registers. */
pci_write_config8(dev, 0x80, access_cntl | 1);
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));
}
/* Restore protection. */
pci_write_config8(dev, 0x80, access_cntl);
}
static const unsigned short pci_device_ids[] = {
0x293a,
0x293c,
0
};
static struct pci_operations lops_pci = {
.set_subsystem = &usb_ehci_set_subsystem,
};
static struct device_operations usb_ehci_ops = {
.read_resources = pci_ehci_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.init = usb_ehci_init,
.scan_bus = 0,
.ops_pci = &lops_pci,
};
static const struct pci_driver pch_usb_ehci1 __pci_driver = {
.ops = &usb_ehci_ops,
.vendor = PCI_VENDOR_ID_INTEL,
.devices = pci_device_ids,
};