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:
parent
c3198543b6
commit
7b9c139ac2
|
@ -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
|
|
@ -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
|
|
@ -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.
|
||||
})
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
|
||||
}
|
|
@ -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 }
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
}
|
|
@ -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 ?
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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})
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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 */
|
|
@ -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");
|
||||
}
|
|
@ -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. */
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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,
|
||||
};
|
|
@ -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,
|
||||
};
|
|
@ -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
|
|
@ -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,
|
||||
};
|
|
@ -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);
|
|
@ -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,
|
||||
};
|
|
@ -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,
|
||||
};
|
|
@ -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,
|
||||
};
|
|
@ -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,
|
||||
};
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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,
|
||||
};
|
|
@ -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,
|
||||
};
|
Loading…
Reference in New Issue