Add support for Intel Panther Point PCH
authorStefan Reinauer <stefan.reinauer@coreboot.org>
Tue, 3 Apr 2012 22:07:22 +0000 (00:07 +0200)
committerStefan Reinauer <stefan.reinauer@coreboot.org>
Wed, 4 Apr 2012 17:10:51 +0000 (19:10 +0200)
Change-Id: Iac3cd25b36493bb203e849674320e113cc5fce32
Signed-off-by: Duncan Laurie <dlaurie@google.com>
Signed-off-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/853
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
43 files changed:
src/Kconfig
src/southbridge/intel/Kconfig
src/southbridge/intel/Makefile.inc
src/southbridge/intel/bd82x6x/Kconfig [new file with mode: 0644]
src/southbridge/intel/bd82x6x/Makefile.inc [new file with mode: 0644]
src/southbridge/intel/bd82x6x/acpi/audio.asl [new file with mode: 0644]
src/southbridge/intel/bd82x6x/acpi/globalnvs.asl [new file with mode: 0644]
src/southbridge/intel/bd82x6x/acpi/irqlinks.asl [new file with mode: 0644]
src/southbridge/intel/bd82x6x/acpi/lpc.asl [new file with mode: 0644]
src/southbridge/intel/bd82x6x/acpi/pch.asl [new file with mode: 0644]
src/southbridge/intel/bd82x6x/acpi/pcie.asl [new file with mode: 0644]
src/southbridge/intel/bd82x6x/acpi/sata.asl [new file with mode: 0644]
src/southbridge/intel/bd82x6x/acpi/sleepstates.asl [new file with mode: 0644]
src/southbridge/intel/bd82x6x/acpi/smbus.asl [new file with mode: 0644]
src/southbridge/intel/bd82x6x/acpi/usb.asl [new file with mode: 0644]
src/southbridge/intel/bd82x6x/azalia.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/bootblock.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/chip.h [new file with mode: 0644]
src/southbridge/intel/bd82x6x/early_me.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/early_smbus.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/early_usb.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/finalize.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/gpio.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/gpio.h [new file with mode: 0644]
src/southbridge/intel/bd82x6x/lpc.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/me.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/me.h [new file with mode: 0644]
src/southbridge/intel/bd82x6x/me_8.x.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/me_status.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/nvs.h [new file with mode: 0644]
src/southbridge/intel/bd82x6x/pch.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/pch.h [new file with mode: 0644]
src/southbridge/intel/bd82x6x/pci.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/pcie.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/reset.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/sata.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/smbus.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/smbus.h [new file with mode: 0644]
src/southbridge/intel/bd82x6x/smi.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/smihandler.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/usb_debug.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/usb_ehci.c [new file with mode: 0644]
src/southbridge/intel/bd82x6x/watchdog.c [new file with mode: 0644]

index 0696feb24640c9794885226c03525ecc8b709790..b0261d90683e56d693fc933942ca0ee1d30dc374 100644 (file)
@@ -869,6 +869,16 @@ config DEBUG_TPM
        help
          This option enables additional TPM related debug messages.
 
+if SOUTHBRIDGE_INTEL_BD82X6X && DEFAULT_CONSOLE_LOGLEVEL_8
+# Only visible with the right southbridge and loglevel.
+config DEBUG_INTEL_ME
+       bool "Verbose logging for Intel Management Engine"
+       default n
+       help
+         Enable verbose logging for Intel Management Engine driver that
+         is present on Intel 6-series chipsets.
+endif
+
 config LLSHELL
        bool "Built-in low-level shell"
        default n
index e6ffac96947caddb52f6962273a82d8ad9450060..cb0ac830081bd8431d93eaa4b296666dd5ad8f54 100644 (file)
@@ -10,3 +10,4 @@ source src/southbridge/intel/i82801gx/Kconfig
 source src/southbridge/intel/i82870/Kconfig
 source src/southbridge/intel/pxhd/Kconfig
 source src/southbridge/intel/sch/Kconfig
+source src/southbridge/intel/bd82x6x/Kconfig
index b399955744178f82dd0f09bdef5a6f88a1883977..6869e5b837d7ac30eda02c64fc0360a7556f075c 100644 (file)
@@ -10,3 +10,5 @@ subdirs-$(CONFIG_SOUTHBRIDGE_INTEL_I82801GX) += i82801gx
 subdirs-$(CONFIG_SOUTHBRIDGE_INTEL_I82870) += i82870
 subdirs-$(CONFIG_SOUTHBRIDGE_INTEL_PXHD) += pxhd
 subdirs-$(CONFIG_SOUTHBRIDGE_INTEL_SCH) += sch
+subdirs-$(CONFIG_SOUTHBRIDGE_INTEL_BD82X6X) += bd82x6x
+subdirs-$(CONFIG_SOUTHBRIDGE_INTEL_C216) += bd82x6x
diff --git a/src/southbridge/intel/bd82x6x/Kconfig b/src/southbridge/intel/bd82x6x/Kconfig
new file mode 100644 (file)
index 0000000..3891be1
--- /dev/null
@@ -0,0 +1,68 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2011 Google Inc.
+##
+## 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.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+config SOUTHBRIDGE_INTEL_BD82X6X
+       bool
+
+config SOUTHBRIDGE_INTEL_C216
+       bool
+
+if SOUTHBRIDGE_INTEL_BD82X6X || SOUTHBRIDGE_INTEL_C216
+
+config SOUTH_BRIDGE_OPTIONS # dummy
+       def_bool y
+       select IOAPIC
+       select HAVE_HARD_RESET
+       select HAVE_USBDEBUG
+       select USE_WATCHDOG_ON_BOOT
+       select PCIEXP_ASPM
+       select PCIEXP_COMMON_CLOCK
+
+config EHCI_BAR
+       hex
+       default 0xfef00000
+
+config EHCI_DEBUG_OFFSET
+       hex
+       default 0xa0
+
+config BOOTBLOCK_SOUTHBRIDGE_INIT
+       string
+       default "southbridge/intel/bd82x6x/bootblock.c"
+
+config SERIRQ_CONTINUOUS_MODE
+       bool
+       default n
+       help
+         If you set this option to y, the serial IRQ machine will be
+         operated in continuous mode.
+
+endif
+
+if SOUTHBRIDGE_INTEL_BD82X6X
+config PCH_CHIP_NAME
+       string
+       default "Cougar Point"
+endif
+
+if SOUTHBRIDGE_INTEL_C216
+config PCH_CHIP_NAME
+       string
+       default "Panther Point"
+endif
diff --git a/src/southbridge/intel/bd82x6x/Makefile.inc b/src/southbridge/intel/bd82x6x/Makefile.inc
new file mode 100644 (file)
index 0000000..5732254
--- /dev/null
@@ -0,0 +1,43 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2010 Google Inc.
+##
+## 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.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+me-src-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += me.c
+me-src-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += me_8.x.c
+
+driver-y += pch.c
+driver-y += azalia.c
+driver-y += lpc.c
+driver-y += pci.c
+driver-y += pcie.c
+driver-y += sata.c
+driver-y += usb_ehci.c
+driver-y += $(me-src-y)
+driver-y += smbus.c
+
+ramstage-y += me_status.c
+ramstage-y += reset.c
+ramstage-y += watchdog.c
+
+ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c
+smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c $(me-src-y) finalize.c
+
+romstage-y += early_usb.c early_smbus.c early_me.c me_status.c gpio.c
+romstage-$(CONFIG_USBDEBUG) += usb_debug.c
+romstage-y += reset.c
+
diff --git a/src/southbridge/intel/bd82x6x/acpi/audio.asl b/src/southbridge/intel/bd82x6x/acpi/audio.asl
new file mode 100644 (file)
index 0000000..a455328
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+/* Intel PCH HDA */
+
+// Intel High Definition Audio (Azalia) 0:1b.0
+
+Device (HDEF)
+{
+       Name (_ADR, 0x001b0000)
+
+       // Power Resources for Wake
+       Name (_PRW, Package(){
+               13,  // Bit 13 of GPE
+                4   // Can wake from S4 state.
+       })
+}
+
diff --git a/src/southbridge/intel/bd82x6x/acpi/globalnvs.asl b/src/southbridge/intel/bd82x6x/acpi/globalnvs.asl
new file mode 100644 (file)
index 0000000..df450e3
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+/* 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.
+ */
+
+
+OperationRegion (GNVS, SystemMemory, 0xC0DEBABE, 0xf00)
+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)
+       /* Thermal policy */
+       Offset (0x11),
+       TLVL,    8,     // 0x11 - Throttle Level Limit
+       FLVL,    8,     // 0x12 - Current FAN Level
+       TCRT,    8,     // 0x13 - Critical Threshold
+       TPSV,    8,     // 0x14 - Passive Threshold
+       TMAX,    8,     // 0x15 - CPU Tj_max
+       F0OF,    8,     // 0x16 - FAN 0 OFF Threshold
+       F0ON,    8,     // 0x17 - FAN 0 ON Threshold
+       F0PW,    8,     // 0x18 - FAN 0 PWM value
+       F1OF,    8,     // 0x19 - FAN 1 OFF Threshold
+       F1ON,    8,     // 0x1a - FAN 1 ON Threshold
+       F1PW,    8,     // 0x1b - FAN 1 PWM value
+       F2OF,    8,     // 0x1c - FAN 2 OFF Threshold
+       F2ON,    8,     // 0x1d - FAN 2 ON Threshold
+       F2PW,    8,     // 0x1e - FAN 2 PWM value
+       F3OF,    8,     // 0x1f - FAN 3 OFF Threshold
+       F3ON,    8,     // 0x20 - FAN 3 ON Threshold
+       F3PW,    8,     // 0x21 - FAN 3 PWM value
+       F4OF,    8,     // 0x22 - FAN 4 OFF Threshold
+       F4ON,    8,     // 0x23 - FAN 4 ON Threshold
+       F4PW,    8,     // 0x24 - FAN 4 PWM value
+       /* 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
+       PCNT,    8,     // 0x2d - Processor count
+       /* Super I/O & CMOS config */
+       Offset (0x32),
+       NATP,    8,     // 0x32 -
+       S5U0,    8,     // 0x32 - Enable USB0 in S5
+       S5U1,    8,     // 0x33 - Enable USB1 in S5
+       S3U0,    8,     // 0x35 - Enable USB0 in S3
+       S3U1,    8,     // 0x36 - Enable USB1 in S3
+       S33G,    8,     // 0x37 - Enable 3G in S3
+       CMEM,    32,    // 0x38 - CBMEM TOC
+       /* 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
+
+       /* ChromeOS specific */
+       Offset (0xf0),
+       #include <vendorcode/google/chromeos/acpi/gnvs.asl>
+       // 0xe8a - end
+}
+
+/* Set flag to enable USB charging in S3 */
+Method (S3UE)
+{
+       Store (One, \S3U0)
+       Store (One, \S3U1)
+}
+
+/* Set flag to disable USB charging in S3 */
+Method (S3UD)
+{
+       Store (Zero, \S3U0)
+       Store (Zero, \S3U1)
+}
+
+/* Set flag to enable USB charging in S5 */
+Method (S5UE)
+{
+       Store (One, \S5U0)
+       Store (One, \S5U1)
+}
+
+/* Set flag to disable USB charging in S5 */
+Method (S5UD)
+{
+       Store (Zero, \S5U0)
+       Store (Zero, \S5U1)
+}
+
+/* Set flag to enable 3G module in S3 */
+Method (S3GE)
+{
+       Store (One, \S33G)
+}
+
+/* Set flag to disable 3G module in S3 */
+Method (S3GD)
+{
+       Store (Zero, \S33G)
+}
+
+/* Update Fan 0 thresholds */
+Method (F0UT, 2)
+{
+       Store (Arg0, \F0OF)
+       Store (Arg1, \F0ON)
+}
+
+/* Update Fan 1 thresholds */
+Method (F1UT, 2)
+{
+       Store (Arg0, \F1OF)
+       Store (Arg1, \F1ON)
+}
+
+/* Update Fan 2 thresholds */
+Method (F2UT, 2)
+{
+       Store (Arg0, \F2OF)
+       Store (Arg1, \F2ON)
+}
+
+/* Update Fan 3 thresholds */
+Method (F3UT, 2)
+{
+       Store (Arg0, \F3OF)
+       Store (Arg1, \F3ON)
+}
+
+/* Update Fan 4 thresholds */
+Method (F4UT, 2)
+{
+       Store (Arg0, \F4OF)
+       Store (Arg1, \F4ON)
+}
diff --git a/src/southbridge/intel/bd82x6x/acpi/irqlinks.asl b/src/southbridge/intel/bd82x6x/acpi/irqlinks.asl
new file mode 100644 (file)
index 0000000..5fcee45
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+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)
+                       { 1, 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)
+                       { 1, 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)
+                       { 1, 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)
+                       { 1, 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)
+                       { 1, 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)
+                       { 1, 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)
+                       { 1, 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)
+                       { 1, 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)
+               }
+       }
+}
+
diff --git a/src/southbridge/intel/bd82x6x/acpi/lpc.asl b/src/southbridge/intel/bd82x6x/acpi/lpc.asl
new file mode 100644 (file)
index 0000000..cc59850
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+// 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 (0xb8),  // GPIO Routing Control
+               GR00,    2,
+               GR01,    2,
+               GR02,    2,
+               GR03,    2,
+               GR04,    2,
+               GR05,    2,
+               GR06,    2,
+               GR07,    2,
+               GR08,    2,
+               GR09,    2,
+               GR10,    2,
+               GR11,    2,
+               GR12,    2,
+               GR13,    2,
+               GR14,    2,
+               GR15,    2,
+
+               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)        // ICH7-M ACPI
+                       IO (Decode16, DEFAULT_GPIOBASE, DEFAULT_GPIOBASE, 0x1, 0x40)    // ICH7-M 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"
+
+#ifdef ENABLE_TPM
+       Device (TPM)            // Trusted Platform Module
+       {
+               Name(_HID, EISAID("IFX0102"))
+               Name(_CID, 0x310cd041)
+               Name(_UID, 1)
+
+               Method(_STA, 0)
+               {
+                       If (TPMP) {
+                               Return (0xf)
+                       }
+                       Return (0x0)
+               }
+
+               Name(_CRS, ResourceTemplate() {
+                       IO (Decode16, 0x2e, 0x2e, 0x01, 0x02)
+                       IO (Decode16, 0x6f0, 0x6f0, 0x01, 0x10)
+                       Memory32Fixed (ReadWrite, 0xfed40000, 0x5000)
+                       IRQ (Edge, Activehigh, Exclusive) { 6 }
+               })
+       }
+#endif
+}
diff --git a/src/southbridge/intel/bd82x6x/acpi/pch.asl b/src/southbridge/intel/bd82x6x/acpi/pch.asl
new file mode 100644 (file)
index 0000000..3e6651d
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+/* Intel Cougar Point PCH 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
+       }
+
+       // PCH Power Management Registers, located at PMBASE (0x1f.0 0x40.l)
+       OperationRegion(PMIO, SystemIO, DEFAULT_PMBASE, 0x80)
+       Field(PMIO, ByteAcc, NoLock, Preserve)
+       {
+               Offset(0x20),   // GPE0_STS
+               , 16,
+               GS00, 1,        // GPIO00 SCI/Wake Status
+               GS01, 1,        // GPIO01 SCI/Wake Status
+               GS02, 1,        // GPIO02 SCI/Wake Status
+               GS03, 1,        // GPIO03 SCI/Wake Status
+               GS04, 1,        // GPIO04 SCI/Wake Status
+               GS05, 1,        // GPIO05 SCI/Wake Status
+               GS06, 1,        // GPIO06 SCI/Wake Status
+               GS07, 1,        // GPIO07 SCI/Wake Status
+               GS08, 1,        // GPIO08 SCI/Wake Status
+               GS09, 1,        // GPIO09 SCI/Wake Status
+               GS10, 1,        // GPIO10 SCI/Wake Status
+               GS11, 1,        // GPIO11 SCI/Wake Status
+               GS12, 1,        // GPIO12 SCI/Wake Status
+               GS13, 1,        // GPIO13 SCI/Wake Status
+               GS14, 1,        // GPIO14 SCI/Wake Status
+               GS15, 1,        // GPIO15 SCI/Wake Status
+               Offset(0x28),   // GPE0_EN
+               , 16,
+               GE00, 1,        // GPIO00 SCI/Wake Enable
+               GE01, 1,        // GPIO01 SCI/Wake Enable
+               GE02, 1,        // GPIO02 SCI/Wake Enable
+               GE03, 1,        // GPIO03 SCI/Wake Enable
+               GE04, 1,        // GPIO04 SCI/Wake Enable
+               GE05, 1,        // GPIO05 SCI/Wake Enable
+               GE06, 1,        // GPIO06 SCI/Wake Enable
+               GE07, 1,        // GPIO07 SCI/Wake Enable
+               GE08, 1,        // GPIO08 SCI/Wake Enable
+               GE09, 1,        // GPIO09 SCI/Wake Enable
+               GE10, 1,        // GPIO10 SCI/Wake Enable
+               GE11, 1,        // GPIO11 SCI/Wake Enable
+               GE12, 1,        // GPIO12 SCI/Wake Enable
+               GE13, 1,        // GPIO13 SCI/Wake Enable
+               GE14, 1,        // GPIO14 SCI/Wake Enable
+               GE15, 1,        // GPIO15 SCI/Wake Enable
+               Offset(0x42),   // General Purpose Control
+               , 1,            // skip 1 bit
+               GPEC, 1,        // SWGPE_CTRL
+       }
+
+       // GPIO IO mapped registers (0x1f.0 reg 0x48.l)
+       OperationRegion(GPIO, SystemIO, DEFAULT_GPIOBASE, 0x6c)
+       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
+               GL00, 1,
+               GP01, 1,
+               GP02, 1,
+               GP0e, 1,
+               GP04, 1,
+               GP05, 1,
+               GP06, 1,
+               GP07, 1,
+               GP08, 1,
+               GP09, 1,
+               GP10, 1,
+               GP11, 1,
+               GP12, 1,
+               GP13, 1,
+               GP14, 1,
+               GP15, 1,
+               GP16, 1,
+               GP17, 1,
+               GP18, 1,
+               GP19, 1,
+               GP20, 1,
+               GP21, 1,
+               GP22, 1,
+               GP23, 1,
+               GP24, 1,
+               GP25, 1,
+               GP26, 1,
+               GP27, 1,
+               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,
+               GP34, 1,
+               GP35, 1,
+               GP36, 1,
+               GP37, 1,
+               GP38, 1,
+               GP39, 1,
+               GP40, 1,
+               GP41, 1,
+               GP42, 1,
+               GP43, 1,
+               GP44, 1,
+               GP45, 1,
+               GP46, 1,
+               GP47, 1,
+               GP48, 1,
+               GP49, 1,
+               GP50, 1,
+               GP51, 1,
+               GP52, 1,
+               GP53, 1,
+               GP54, 1,
+               GP55, 1,
+               GP56, 1,
+               GP57, 1,
+               GP58, 1,
+               GP59, 1,
+               GP60, 1,
+               GP61, 1,
+               GP62, 1,
+               GP63, 1,
+               Offset(0x40),   // GPIO Use Select 3
+               GU08, 8,
+               GU09, 4,
+               Offset(0x44),   // GPIO IO Select 3
+               GIO8, 8,
+               GIO9, 4,
+               Offset(0x48),   // GPIO Level 3
+               GP64, 1,
+               GP65, 1,
+               GP66, 1,
+               GP67, 1,
+               GP68, 1,
+               GP69, 1,
+               GP70, 1,
+               GP71, 1,
+               GP72, 1,
+               GP73, 1,
+               GP74, 1,
+               GP75, 1,
+       }
+
+
+       // ICH7 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
+               SATD, 1,        // SATA disable
+               SMBD, 1,        // SMBUS disable
+               HDAD, 1,        // Azalia disable
+               , 2,            // Reserved
+               ILND, 1,        // Internal LAN disable
+               US1D, 1,        // UHCI #1 disable
+               US2D, 1,        // UHCI #2 disable
+               US3D, 1,        // UHCI #3 disable
+               US4D, 1,        // UHCI #4 disable
+               , 2,            // Reserved
+               LPBD, 1,        // LPC bridge disable
+               EHCD, 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
+       }
+
+}
+
+// High Definition Audio (Azalia) 0:1b.0
+#include "audio.asl"
+
+// PCI Express Ports 0:1c.x
+#include "pcie.asl"
+
+// USB 0:1d.0 and 0:1a.0
+#include "usb.asl"
+
+// LPC Bridge 0:1f.0
+#include "lpc.asl"
+
+// SATA 0:1f.2, 0:1f.5
+#include "sata.asl"
+
+// SMBus 0:1f.3
+#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)
+       }
+}
diff --git a/src/southbridge/intel/bd82x6x/acpi/pcie.asl b/src/southbridge/intel/bd82x6x/acpi/pcie.asl
new file mode 100644 (file)
index 0000000..f6b93bf
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+/* Intel Cougar Point PCH 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, 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 (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 }
+                       })
+
+               }
+
+       }
+}
+
+Device (RP07)
+{
+       NAME(_ADR, 0x001c0006) // 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 (RP08)
+{
+       NAME(_ADR, 0x001c0007) // 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 }
+                       })
+
+               }
+
+       }
+}
+
+
diff --git a/src/southbridge/intel/bd82x6x/acpi/sata.asl b/src/southbridge/intel/bd82x6x/acpi/sata.asl
new file mode 100644 (file)
index 0000000..e0c336a
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+// Intel SATA Controller 0:1f.2
+
+// Note: Some BIOSes put the S-ATA code into an SSDT to make it easily
+// pluggable
+
+Device (SATA)
+{
+       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 ?
+               }
+
+       }
+}
+
diff --git a/src/southbridge/intel/bd82x6x/acpi/sleepstates.asl b/src/southbridge/intel/bd82x6x/acpi/sleepstates.asl
new file mode 100644 (file)
index 0000000..06bfcb6
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+Name(\_S0, Package(){0x0,0x0,0x0,0x0})
+// Name(\_S1, Package(){0x1,0x1,0x0,0x0})
+Name(\_S3, Package(){0x5,0x5,0x0,0x0})
+Name(\_S4, Package(){0x6,0x6,0x0,0x0})
+Name(\_S5, Package(){0x7,0x7,0x0,0x0})
+
diff --git a/src/southbridge/intel/bd82x6x/acpi/smbus.asl b/src/southbridge/intel/bd82x6x/acpi/smbus.asl
new file mode 100644 (file)
index 0000000..4409308
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+// 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, SMBUS_IO_BASE, 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
+}
+
diff --git a/src/southbridge/intel/bd82x6x/acpi/usb.asl b/src/southbridge/intel/bd82x6x/acpi/usb.asl
new file mode 100644 (file)
index 0000000..cf3e6a0
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+/* Intel Cougar Point USB support */
+
+// EHCI Controller 0:1d.0
+
+Device (EHC1)
+{
+       Name(_ADR, 0x001d0000)
+
+       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
+       }
+}
+
+// EHCI #2 Controller 0:1a.0
+
+Device (EHC2)
+{
+       Name(_ADR, 0x001a0000)
+
+       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
+       }
+}
+
diff --git a/src/southbridge/intel/bd82x6x/azalia.c b/src/southbridge/intel/bd82x6x/azalia.c
new file mode 100644 (file)
index 0000000..5a83e38
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008 Advanced Micro Devices, Inc.
+ * Copyright (C) 2008-2009 coresystems GmbH
+ * Copyright (C) 2011 The ChromiumOS 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <arch/io.h>
+#include <delay.h>
+#include "pch.h"
+
+#define HDA_ICII_REG 0x68
+#define   HDA_ICII_BUSY (1 << 0)
+#define   HDA_ICII_VALID  (1 << 1)
+
+typedef struct southbridge_intel_bd82x6x_config config_t;
+
+static int set_bits(u32 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(u32 base)
+{
+       u8 reg8;
+
+       /* Set Bit 0 to 1 to exit reset state (BAR + 0x8)[0] */
+       if (set_bits(base + 0x08, 1, 1) == -1)
+               goto no_codec;
+
+       /* Write back the value once reset bit is set. */
+       write16(base + 0x0, read16(base + 0x0));
+
+       /* Read in Codec location (BAR + 0xe)[2..0]*/
+       reg8 = read8(base + 0xe);
+       reg8 &= 0x0f;
+       if (!reg8)
+               goto no_codec;
+
+       return reg8;
+
+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;
+}
+
+const u32 * cim_verb_data = NULL;
+u32 cim_verb_data_size = 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(u32 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(u32 base)
+{
+       u32 reg32;
+
+       /* Send the verb to the codec */
+       reg32 = read32(base + HDA_ICII_REG);
+       reg32 |= HDA_ICII_BUSY | HDA_ICII_VALID;
+       write32(base + HDA_ICII_REG, 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, u32 base, int addr)
+{
+       u32 reg32;
+       const u32 *verb;
+       u32 verb_size;
+       int i;
+
+       printk(BIOS_DEBUG, "Azalia: Initializing codec #%d\n", addr);
+
+       /* 1 */
+       if (wait_for_ready(base) == -1) {
+               printk(BIOS_DEBUG, "  codec not ready.\n");
+               return;
+       }
+
+       reg32 = (addr << 28) | 0x000f0000;
+       write32(base + 0x60, reg32);
+
+       if (wait_for_valid(base) == -1) {
+               printk(BIOS_DEBUG, "  codec not valid.\n");
+               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, u32 base, u32 codec_mask)
+{
+       int i;
+       for (i = 3; i >= 0; i--) {
+               if (codec_mask & (1 << i))
+                       codec_init(dev, base, i);
+       }
+}
+
+static void azalia_init(struct device *dev)
+{
+       u32 base;
+       struct resource *res;
+       u32 codec_mask;
+       u8 reg8;
+       u16 reg16;
+       u32 reg32;
+
+       /* Find base address */
+       res = find_resource(dev, PCI_BASE_ADDRESS_0);
+       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 = (u32)res->base;
+       printk(BIOS_DEBUG, "Azalia: base = %08x\n", (u32)base);
+
+       if (RCBA32(0x2030) & (1 << 31)) {
+               reg32 = pci_mmio_read_config32(dev, 0x120);
+               reg32 &= 0xf8ffff01;
+               reg32 |= (1 << 24); // 25 for server
+               reg32 |= RCBA32(0x2030) & 0xfe;
+               pci_mmio_write_config32(dev, 0x120, reg32);
+
+               reg16 = pci_mmio_read_config16(dev, 0x78);
+               reg16 &= ~(1 << 11);
+               pci_mmio_write_config16(dev, 0x78, reg16);
+       } else
+               printk(BIOS_DEBUG, "Azalia: V1CTL disabled.\n");
+
+       reg32 = pci_mmio_read_config32(dev, 0x114);
+       reg32 &= ~0xfe;
+       pci_mmio_write_config32(dev, 0x114, reg32);
+
+       // Set VCi enable bit
+       if (pci_mmio_read_config32(dev, 0x120) & ((1 << 24) |
+                                               (1 << 25) | (1 << 26))) {
+               reg32 = pci_mmio_read_config32(dev, 0x120);
+               reg32 |= (1 << 31);
+               pci_mmio_write_config32(dev, 0x120, reg32);
+       }
+
+       // Enable HDMI codec:
+       reg32 = pci_read_config32(dev, 0xc4);
+       reg32 |= (1 << 1);
+       pci_write_config32(dev, 0xc4, reg32);
+
+       reg8 = pci_read_config8(dev, 0x43);
+       reg8 |= (1 << 6);
+       pci_write_config8(dev, 0x43, reg8);
+
+       /* Additional programming steps */
+       reg32 = pci_read_config32(dev, 0xc4);
+       reg32 |= (1 << 13) | (1 << 10);
+       pci_write_config32(dev, 0xc4, reg32);
+
+       reg32 = pci_read_config32(dev, 0xd0);
+       reg32 &= ~(1 << 31);
+       pci_write_config32(dev, 0xd0, reg32);
+
+       /* Additional programming steps */
+       reg32 = pci_read_config32(dev, 0xc4);
+       reg32 |= (1 << 13);
+       pci_write_config32(dev, 0xc4, reg32);
+
+       reg32 = pci_read_config32(dev, 0xc4);
+       reg32 |= (1 << 10);
+       pci_write_config32(dev, 0xc4, reg32);
+
+       reg32 = pci_read_config32(dev, 0xd0);
+       reg32 &= ~(1 << 31);
+       pci_write_config32(dev, 0xd0, reg32);
+
+       /* Set Bus Master */
+       reg32 = pci_read_config32(dev, PCI_COMMAND);
+       pci_write_config32(dev, PCI_COMMAND, reg32 | PCI_COMMAND_MASTER);
+
+       pci_write_config8(dev, 0x3c, 0x0a); // unused?
+
+       /* Codec Initialization Programming Sequence */
+       reg32 = read32(base + 0x08);
+       reg32 |= (1 << 0);
+       write32(base + 0x08, reg32);
+
+       //
+       reg8 = pci_read_config8(dev, 0x40); // Audio Control
+       reg8 |= 1; // Select Azalia mode. This needs to be controlled via devicetree.cb
+       pci_write_config8(dev, 0x40, reg8);
+
+       reg8 = pci_read_config8(dev, 0x4d); // Docking Status
+       reg8 &= ~(1 << 7); // Docking not supported
+       pci_write_config8(dev, 0x4d, reg8);
+
+       codec_mask = codec_detect(base);
+
+       if (codec_mask) {
+               printk(BIOS_DEBUG, "Azalia: codec_mask = %02x\n", codec_mask);
+               codecs_init(dev, base, codec_mask);
+       }
+
+       /* Enable dynamic clock gating */
+       reg8 = pci_read_config8(dev, 0x43);
+       reg8 &= ~0x7;
+       reg8 |= (1 << 2) | (1 << 0);
+       pci_write_config8(dev, 0x43, reg8);
+}
+
+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,
+};
+
+static const struct pci_driver azalia_0 __pci_driver = {
+       .ops    = &azalia_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c20,
+};
+
+static const struct pci_driver azalia_1 __pci_driver = {
+       .ops    = &azalia_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1e20,
+};
+
diff --git a/src/southbridge/intel/bd82x6x/bootblock.c b/src/southbridge/intel/bd82x6x/bootblock.c
new file mode 100644 (file)
index 0000000..686e820
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Google Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "pch.h"
+
+static void store_initial_timestamp(void)
+{
+       /* On Cougar Point we have two 32bit scratchpad registers available:
+        * D0:F0  0xdc (SKPAD)
+        * D31:F2 0xd0 (SATA SP)
+        */
+       tsc_t tsc = rdtsc();
+       pci_write_config32(PCI_DEV(0, 0x00, 0), 0xdc, tsc.lo);
+       pci_write_config32(PCI_DEV(0, 0x1f, 2), 0xd0, tsc.hi);
+}
+
+/*
+ * Enable Prefetching and Caching.
+ */
+static void enable_spi_prefetch(void)
+{
+       u8 reg8;
+       device_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 enable_port80_on_lpc(void)
+{
+       device_t dev = PCI_DEV(0, 0x1f, 0);
+
+       /* Enable port 80 POST on LPC */
+       pci_write_config32(dev, RCBA, DEFAULT_RCBA | 1);
+#if 0
+       RCBA32(GCS) &= (~0x04);
+#else
+       volatile u32 *gcs = (volatile u32 *)(DEFAULT_RCBA + GCS);
+       u32 reg32 = *gcs;
+       reg32 = reg32 & ~0x04;
+       *gcs = reg32;
+       post_code(0x01);
+#endif
+}
+
+static void bootblock_southbridge_init(void)
+{
+#if CONFIG_COLLECT_TIMESTAMPS
+       store_initial_timestamp();
+#endif
+       enable_spi_prefetch();
+       enable_port80_on_lpc();
+}
diff --git a/src/southbridge/intel/bd82x6x/chip.h b/src/southbridge/intel/bd82x6x/chip.h
new file mode 100644 (file)
index 0000000..2786d72
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef SOUTHBRIDGE_INTEL_BD82X6X_CHIP_H
+#define SOUTHBRIDGE_INTEL_BD82X6X_CHIP_H
+
+struct southbridge_intel_bd82x6x_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 */
+       uint32_t ide_legacy_combined;
+       uint32_t sata_ahci;
+       uint8_t sata_port_map;
+
+       uint32_t gen1_dec;
+       uint32_t gen2_dec;
+       uint32_t gen3_dec;
+       uint32_t gen4_dec;
+};
+
+extern struct chip_operations southbridge_intel_bd82x6x_ops;
+
+#endif                         /* SOUTHBRIDGE_INTEL_BD82X6X_CHIP_H */
diff --git a/src/southbridge/intel/bd82x6x/early_me.c b/src/southbridge/intel/bd82x6x/early_me.c
new file mode 100644 (file)
index 0000000..5b266cc
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <arch/hlt.h>
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+#include <console/console.h>
+#include <delay.h>
+#include <device/pci_ids.h>
+#include <string.h>
+#include "me.h"
+#include "pch.h"
+
+static const char *me_ack_values[] = {
+       [ME_HFS_ACK_NO_DID]     = "No DID Ack received",
+       [ME_HFS_ACK_RESET]      = "Non-power cycle reset",
+       [ME_HFS_ACK_PWR_CYCLE]  = "Power cycle reset",
+       [ME_HFS_ACK_S3]         = "Go to S3",
+       [ME_HFS_ACK_S4]         = "Go to S4",
+       [ME_HFS_ACK_S5]         = "Go to S5",
+       [ME_HFS_ACK_GBL_RESET]  = "Global Reset",
+       [ME_HFS_ACK_CONTINUE]   = "Continue to boot"
+};
+
+static inline void pci_read_dword_ptr(void *ptr, int offset)
+{
+       u32 dword = pci_read_config32(PCH_ME_DEV, offset);
+       memcpy(ptr, &dword, sizeof(dword));
+}
+
+static inline void pci_write_dword_ptr(void *ptr, int offset)
+{
+       u32 dword = 0;
+       memcpy(&dword, ptr, sizeof(dword));
+       pci_write_config32(PCH_ME_DEV, offset, dword);
+}
+
+void intel_early_me_status(void)
+{
+       struct me_hfs hfs;
+       struct me_gmes gmes;
+
+       pci_read_dword_ptr(&hfs, PCI_ME_HFS);
+       pci_read_dword_ptr(&gmes, PCI_ME_GMES);
+
+       intel_me_status(&hfs, &gmes);
+}
+
+int intel_early_me_init(void)
+{
+       int count;
+       struct me_uma uma;
+       struct me_hfs hfs;
+
+       printk(BIOS_INFO, "Intel ME early init\n");
+
+       /* Wait for ME UMA SIZE VALID bit to be set */
+       for (count = ME_RETRY; count > 0; --count) {
+               pci_read_dword_ptr(&uma, PCI_ME_UMA);
+               if (uma.valid)
+                       break;
+               udelay(ME_DELAY);
+       }
+       if (!count) {
+               printk(BIOS_ERR, "ERROR: ME is not ready!\n");
+               return -1;
+       }
+
+       /* Check for valid firmware */
+       pci_read_dword_ptr(&hfs, PCI_ME_HFS);
+       if (hfs.fpt_bad) {
+               printk(BIOS_WARNING, "WARNING: ME has bad firmware\n");
+               return -1;
+       }
+
+       printk(BIOS_INFO, "Intel ME firmware is ready\n");
+       return 0;
+}
+
+int intel_early_me_uma_size(void)
+{
+       struct me_uma uma;
+
+       pci_read_dword_ptr(&uma, PCI_ME_UMA);
+       if (uma.valid) {
+               printk(BIOS_DEBUG, "ME: Requested %uMB UMA\n", uma.size);
+               return uma.size;
+       }
+
+       printk(BIOS_DEBUG, "ME: Invalid UMA size\n");
+       return 0;
+}
+
+static inline void set_global_reset(int enable)
+{
+       u32 etr3 = pci_read_config32(PCH_LPC_DEV, ETR3);
+
+       /* Clear CF9 Without Resume Well Reset Enable */
+       etr3 &= ~ETR3_CWORWRE;
+
+       /* CF9GR indicates a Global Reset */
+       if (enable)
+               etr3 |= ETR3_CF9GR;
+       else
+               etr3 &= ~ETR3_CF9GR;
+
+       pci_write_config32(PCH_LPC_DEV, ETR3, etr3);
+}
+
+int intel_early_me_init_done(u8 status)
+{
+       u8 reset;
+       int count;
+       u32 mebase_l, mebase_h;
+       struct me_hfs hfs;
+       struct me_did did = {
+               .init_done = ME_INIT_DONE,
+               .status = status
+       };
+
+       /* MEBASE from MESEG_BASE[35:20] */
+       mebase_l = pci_read_config32(PCI_CPU_DEVICE, PCI_CPU_MEBASE_L);
+       mebase_h = pci_read_config32(PCI_CPU_DEVICE, PCI_CPU_MEBASE_H) & 0xf;
+       did.uma_base = (mebase_l >> 20) | (mebase_h << 12);
+
+       /* Send message to ME */
+       printk(BIOS_DEBUG, "ME: Sending Init Done with status: %d, "
+              "UMA base: 0x%04x\n", status, did.uma_base);
+
+       pci_write_dword_ptr(&did, PCI_ME_H_GS);
+
+       /* Must wait for ME acknowledgement */
+       for (count = ME_RETRY; count > 0; --count) {
+               pci_read_dword_ptr(&hfs, PCI_ME_HFS);
+               if (hfs.bios_msg_ack)
+                       break;
+               udelay(ME_DELAY);
+       }
+       if (!count) {
+               printk(BIOS_ERR, "ERROR: ME failed to respond\n");
+               return -1;
+       }
+
+       /* Return the requested BIOS action */
+       printk(BIOS_NOTICE, "ME: Requested BIOS Action: %s\n",
+              me_ack_values[hfs.ack_data]);
+
+       /* Check status after acknowledgement */
+       intel_early_me_status();
+
+       reset = 0;
+       switch (hfs.ack_data) {
+       case ME_HFS_ACK_CONTINUE:
+               /* Continue to boot */
+               return 0;
+       case ME_HFS_ACK_RESET:
+               /* Non-power cycle reset */
+               set_global_reset(0);
+               reset = 0x06;
+               break;
+       case ME_HFS_ACK_PWR_CYCLE:
+               /* Power cycle reset */
+               set_global_reset(0);
+               reset = 0x0e;
+               break;
+       case ME_HFS_ACK_GBL_RESET:
+               /* Global reset */
+               set_global_reset(1);
+               reset = 0x0e;
+               break;
+       case ME_HFS_ACK_S3:
+       case ME_HFS_ACK_S4:
+       case ME_HFS_ACK_S5:
+               break;
+       }
+
+       /* Perform the requested reset */
+       if (reset) {
+               outb(reset, 0xcf9);
+               hlt();
+       }
+       return -1;
+}
diff --git a/src/southbridge/intel/bd82x6x/early_smbus.c b/src/southbridge/intel/bd82x6x/early_smbus.c
new file mode 100644 (file)
index 0000000..b13369a
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+#include <console/console.h>
+#include <device/pci_ids.h>
+#include <device/pci_def.h>
+#include "pch.h"
+#include "smbus.h"
+
+void enable_smbus(void)
+{
+       device_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, 0x0) != 0x8086) {
+               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);
+       print_debug("SMBus controller enabled.\n");
+}
+
+int smbus_read_byte(unsigned device, unsigned address)
+{
+       return do_smbus_read_byte(SMBUS_IO_BASE, device, address);
+}
+
diff --git a/src/southbridge/intel/bd82x6x/early_usb.c b/src/southbridge/intel/bd82x6x/early_usb.c
new file mode 100644 (file)
index 0000000..95906e3
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+#include <console/console.h>
+#include <device/pci_ids.h>
+#include <device/pci_def.h>
+#include "pch.h"
+
+#define PCH_EHCI1_TEMP_BAR0 0xe8000000
+#define PCH_EHCI2_TEMP_BAR0 0xe8000400
+
+/*
+ * Setup USB controller MMIO BAR to prevent the
+ * reference code from resetting the controller.
+ *
+ * The BAR will be re-assigned during device
+ * enumeration so these are only temporary.
+ */
+void enable_usb_bar(void)
+{
+       device_t usb0 = PCH_EHCI1_DEV;
+       device_t usb1 = PCH_EHCI2_DEV;
+       u32 cmd;
+
+       /* USB Controller 1 */
+       pci_write_config32(usb0, PCI_BASE_ADDRESS_0,
+                          PCH_EHCI1_TEMP_BAR0);
+       cmd = pci_read_config32(usb0, PCI_COMMAND);
+       cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+       pci_write_config32(usb0, PCI_COMMAND, cmd);
+
+       /* USB Controller 1 */
+       pci_write_config32(usb1, PCI_BASE_ADDRESS_0,
+                          PCH_EHCI1_TEMP_BAR0);
+       cmd = pci_read_config32(usb1, PCI_COMMAND);
+       cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+       pci_write_config32(usb1, PCI_COMMAND, cmd);
+}
diff --git a/src/southbridge/intel/bd82x6x/finalize.c b/src/southbridge/intel/bd82x6x/finalize.c
new file mode 100644 (file)
index 0000000..ed1ebf7
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+#include <northbridge/intel/sandybridge/pcie_config.c>
+#include "pch.h"
+
+void intel_pch_finalize_smm(void)
+{
+       /* Set SPI opcode menu */
+       RCBA16(0x3894) = SPI_OPPREFIX;
+       RCBA16(0x3896) = SPI_OPTYPE;
+       RCBA32(0x3898) = SPI_OPMENU_LOWER;
+       RCBA32(0x389c) = SPI_OPMENU_UPPER;
+
+       /* Lock SPIBAR */
+       RCBA32_OR(0x3804, (1 << 15));
+
+       /* TCLOCKDN: TC Lockdown */
+       RCBA32_OR(0x0050, (1 << 31));
+
+       /* BIOS Interface Lockdown */
+       RCBA32_OR(0x3410, (1 << 0));
+
+       /* Function Disable SUS Well Lockdown */
+       RCBA_AND_OR(8, 0x3420, ~0U, (1 << 7));
+
+       /* Global SMI Lock */
+       pcie_or_config16(PCH_LPC_DEV, 0xa0, 1 << 4);
+
+       /* GEN_PMCON Lock */
+       pcie_or_config8(PCH_LPC_DEV, 0xa6, (1 << 1) | (1 << 2));
+
+       /* R/WO registers */
+       RCBA32(0x21a4) = RCBA32(0x21a4);
+       pcie_write_config32(PCI_DEV(0, 27, 0), 0x74,
+                   pcie_read_config32(PCI_DEV(0, 27, 0), 0x74));
+}
diff --git a/src/southbridge/intel/bd82x6x/gpio.c b/src/southbridge/intel/bd82x6x/gpio.c
new file mode 100644 (file)
index 0000000..598726a
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+
+#include "pch.h"
+#include "gpio.h"
+
+void setup_pch_gpios(const struct pch_gpio_map *gpio)
+{
+       u16 gpiobase = pci_read_config16(PCH_LPC_DEV, GPIO_BASE) & 0xfffc;
+
+       /* GPIO Set 1 */
+       if (gpio->set1.level)
+               outl(*((u32*)gpio->set1.level), gpiobase + GP_LVL);
+       if (gpio->set1.mode)
+               outl(*((u32*)gpio->set1.mode), gpiobase + GPIO_USE_SEL);
+       if (gpio->set1.direction)
+               outl(*((u32*)gpio->set1.direction), gpiobase + GP_IO_SEL);
+       if (gpio->set1.reset)
+               outl(*((u32*)gpio->set1.reset), gpiobase + GP_RST_SEL1);
+       if (gpio->set1.invert)
+               outl(*((u32*)gpio->set1.invert), gpiobase + GPI_INV);
+       if (gpio->set1.blink)
+               outl(*((u32*)gpio->set1.blink), gpiobase + GPO_BLINK);
+
+       /* GPIO Set 2 */
+       if (gpio->set2.level)
+               outl(*((u32*)gpio->set2.level), gpiobase + GP_LVL2);
+       if (gpio->set2.mode)
+               outl(*((u32*)gpio->set2.mode), gpiobase + GPIO_USE_SEL2);
+       if (gpio->set2.direction)
+               outl(*((u32*)gpio->set2.direction), gpiobase + GP_IO_SEL2);
+       if (gpio->set2.reset)
+               outl(*((u32*)gpio->set2.reset), gpiobase + GP_RST_SEL2);
+
+       /* GPIO Set 3 */
+       if (gpio->set3.level)
+               outl(*((u32*)gpio->set3.level), gpiobase + GP_LVL3);
+       if (gpio->set3.mode)
+               outl(*((u32*)gpio->set3.mode), gpiobase + GPIO_USE_SEL3);
+       if (gpio->set3.direction)
+               outl(*((u32*)gpio->set3.direction), gpiobase + GP_IO_SEL3);
+       if (gpio->set3.reset)
+               outl(*((u32*)gpio->set3.reset), gpiobase + GP_RST_SEL3);
+}
diff --git a/src/southbridge/intel/bd82x6x/gpio.h b/src/southbridge/intel/bd82x6x/gpio.h
new file mode 100644 (file)
index 0000000..214947f
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef INTEL_BD82X6X_GPIO_H
+#define INTEL_BD82X6X_GPIO_H
+
+#define GPIO_MODE_NATIVE       0
+#define GPIO_MODE_GPIO         1
+#define GPIO_MODE_NONE         1
+
+#define GPIO_DIR_OUTPUT                0
+#define GPIO_DIR_INPUT         1
+
+#define GPIO_NO_INVERT         0
+#define GPIO_INVERT            1
+
+#define GPIO_LEVEL_LOW         0
+#define GPIO_LEVEL_HIGH                1
+
+#define GPIO_NO_BLINK          0
+#define GPIO_BLINK             1
+
+#define GPIO_RESET_PWROK       0
+#define GPIO_RESET_RSMRST      1
+
+struct pch_gpio_set1 {
+       u32 gpio0 : 1;
+       u32 gpio1 : 1;
+       u32 gpio2 : 1;
+       u32 gpio3 : 1;
+       u32 gpio4 : 1;
+       u32 gpio5 : 1;
+       u32 gpio6 : 1;
+       u32 gpio7 : 1;
+       u32 gpio8 : 1;
+       u32 gpio9 : 1;
+       u32 gpio10 : 1;
+       u32 gpio11 : 1;
+       u32 gpio12 : 1;
+       u32 gpio13 : 1;
+       u32 gpio14 : 1;
+       u32 gpio15 : 1;
+       u32 gpio16 : 1;
+       u32 gpio17 : 1;
+       u32 gpio18 : 1;
+       u32 gpio19 : 1;
+       u32 gpio20 : 1;
+       u32 gpio21 : 1;
+       u32 gpio22 : 1;
+       u32 gpio23 : 1;
+       u32 gpio24 : 1;
+       u32 gpio25 : 1;
+       u32 gpio26 : 1;
+       u32 gpio27 : 1;
+       u32 gpio28 : 1;
+       u32 gpio29 : 1;
+       u32 gpio30 : 1;
+       u32 gpio31 : 1;
+} __attribute__ ((packed));
+
+struct pch_gpio_set2 {
+       u32 gpio32 : 1;
+       u32 gpio33 : 1;
+       u32 gpio34 : 1;
+       u32 gpio35 : 1;
+       u32 gpio36 : 1;
+       u32 gpio37 : 1;
+       u32 gpio38 : 1;
+       u32 gpio39 : 1;
+       u32 gpio40 : 1;
+       u32 gpio41 : 1;
+       u32 gpio42 : 1;
+       u32 gpio43 : 1;
+       u32 gpio44 : 1;
+       u32 gpio45 : 1;
+       u32 gpio46 : 1;
+       u32 gpio47 : 1;
+       u32 gpio48 : 1;
+       u32 gpio49 : 1;
+       u32 gpio50 : 1;
+       u32 gpio51 : 1;
+       u32 gpio52 : 1;
+       u32 gpio53 : 1;
+       u32 gpio54 : 1;
+       u32 gpio55 : 1;
+       u32 gpio56 : 1;
+       u32 gpio57 : 1;
+       u32 gpio58 : 1;
+       u32 gpio59 : 1;
+       u32 gpio60 : 1;
+       u32 gpio61 : 1;
+       u32 gpio62 : 1;
+       u32 gpio63 : 1;
+} __attribute__ ((packed));
+
+struct pch_gpio_set3 {
+       u32 gpio64 : 1;
+       u32 gpio65 : 1;
+       u32 gpio66 : 1;
+       u32 gpio67 : 1;
+       u32 gpio68 : 1;
+       u32 gpio69 : 1;
+       u32 gpio70 : 1;
+       u32 gpio71 : 1;
+       u32 gpio72 : 1;
+       u32 gpio73 : 1;
+       u32 gpio74 : 1;
+       u32 gpio75 : 1;
+} __attribute__ ((packed));
+
+struct pch_gpio_map {
+       struct {
+               const struct pch_gpio_set1 *mode;
+               const struct pch_gpio_set1 *direction;
+               const struct pch_gpio_set1 *level;
+               const struct pch_gpio_set1 *reset;
+               const struct pch_gpio_set1 *invert;
+               const struct pch_gpio_set1 *blink;
+       } set1;
+       struct {
+               const struct pch_gpio_set2 *mode;
+               const struct pch_gpio_set2 *direction;
+               const struct pch_gpio_set2 *level;
+               const struct pch_gpio_set2 *reset;
+       } set2;
+       struct {
+               const struct pch_gpio_set3 *mode;
+               const struct pch_gpio_set3 *direction;
+               const struct pch_gpio_set3 *level;
+               const struct pch_gpio_set3 *reset;
+       } set3;
+};
+
+/* Configure GPIOs with mainboard provided settings */
+void setup_pch_gpios(const struct pch_gpio_map *gpio);
+
+#endif
diff --git a/src/southbridge/intel/bd82x6x/lpc.c b/src/southbridge/intel/bd82x6x/lpc.c
new file mode 100644 (file)
index 0000000..1ecaf8f
--- /dev/null
@@ -0,0 +1,678 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <pc80/mc146818rtc.h>
+#include <pc80/isa-dma.h>
+#include <pc80/i8259.h>
+#include <arch/io.h>
+#include <arch/ioapic.h>
+#include <arch/acpi.h>
+#include <cpu/cpu.h>
+#include "pch.h"
+
+#define NMI_OFF        0
+
+#define ENABLE_ACPI_MODE_IN_COREBOOT   0
+#define TEST_SMM_FLASH_LOCKDOWN                0
+
+typedef struct southbridge_intel_bd82x6x_config config_t;
+
+static void pch_enable_apic(struct device *dev)
+{
+       int i;
+       u32 reg32;
+       volatile u32 *ioapic_index = (volatile u32 *)(IO_APIC_ADDR);
+       volatile u32 *ioapic_data = (volatile u32 *)(IO_APIC_ADDR + 0x10);
+
+       /* Enable ACPI I/O and power management.
+        * Set SCI IRQ to IRQ9
+        */
+       pci_write_config8(dev, ACPI_CNTL, 0x80);
+
+       *ioapic_index = 0;
+       *ioapic_data = (1 << 25);
+
+       /* affirm full set of redirection table entries ("write once") */
+       *ioapic_index = 1;
+       reg32 = *ioapic_data;
+       *ioapic_index = 1;
+       *ioapic_data = reg32;
+
+       *ioapic_index = 0;
+       reg32 = *ioapic_data;
+       printk(BIOS_DEBUG, "Southbridge APIC ID = %x\n", (reg32 >> 24) & 0x0f);
+       if (reg32 != (1 << 25))
+               die("APIC Error\n");
+
+       printk(BIOS_SPEW, "Dumping IOAPIC registers\n");
+       for (i=0; i<3; i++) {
+               *ioapic_index = i;
+               printk(BIOS_SPEW, "  reg 0x%04x:", i);
+               reg32 = *ioapic_data;
+               printk(BIOS_SPEW, " 0x%08x\n", reg32);
+       }
+
+       *ioapic_index = 3; /* Select Boot Configuration register. */
+       *ioapic_data = 1; /* Use Processor System Bus to deliver interrupts. */
+}
+
+static void pch_enable_serial_irqs(struct device *dev)
+{
+       /* Set packet length and toggle silent mode bit for one frame. */
+       pci_write_config8(dev, SERIRQ_CNTL,
+                         (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
+#if !CONFIG_SERIRQ_CONTINUOUS_MODE
+       pci_write_config8(dev, SERIRQ_CNTL,
+                         (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
+#endif
+}
+
+/* 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 pch_pirq_init(device_t dev)
+{
+       device_t irq_dev;
+       /* Get the chip configuration */
+       config_t *config = dev->chip_info;
+
+       pci_write_config8(dev, PIRQA_ROUT, config->pirqa_routing);
+       pci_write_config8(dev, PIRQB_ROUT, config->pirqb_routing);
+       pci_write_config8(dev, PIRQC_ROUT, config->pirqc_routing);
+       pci_write_config8(dev, PIRQD_ROUT, config->pirqd_routing);
+
+       pci_write_config8(dev, PIRQE_ROUT, config->pirqe_routing);
+       pci_write_config8(dev, PIRQF_ROUT, config->pirqf_routing);
+       pci_write_config8(dev, PIRQG_ROUT, config->pirqg_routing);
+       pci_write_config8(dev, PIRQH_ROUT, config->pirqh_routing);
+
+       /* Eric Biederman once said we should let the OS do this.
+        * I am not so sure anymore he was right.
+        */
+
+       for(irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
+               u8 int_pin=0, int_line=0;
+
+               if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
+                       continue;
+
+               int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
+
+               switch (int_pin) {
+               case 1: /* INTA# */ int_line = config->pirqa_routing; break;
+               case 2: /* INTB# */ int_line = config->pirqb_routing; break;
+               case 3: /* INTC# */ int_line = config->pirqc_routing; break;
+               case 4: /* INTD# */ int_line = config->pirqd_routing; break;
+               }
+
+               if (!int_line)
+                       continue;
+
+               pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line);
+       }
+}
+
+static void pch_gpi_routing(device_t dev)
+{
+       /* Get the chip configuration */
+       config_t *config = dev->chip_info;
+       u32 reg32 = 0;
+
+       /* An array would be much nicer here, or some
+        * other method of doing this.
+        */
+       reg32 |= (config->gpi0_routing & 0x03) << 0;
+       reg32 |= (config->gpi1_routing & 0x03) << 2;
+       reg32 |= (config->gpi2_routing & 0x03) << 4;
+       reg32 |= (config->gpi3_routing & 0x03) << 6;
+       reg32 |= (config->gpi4_routing & 0x03) << 8;
+       reg32 |= (config->gpi5_routing & 0x03) << 10;
+       reg32 |= (config->gpi6_routing & 0x03) << 12;
+       reg32 |= (config->gpi7_routing & 0x03) << 14;
+       reg32 |= (config->gpi8_routing & 0x03) << 16;
+       reg32 |= (config->gpi9_routing & 0x03) << 18;
+       reg32 |= (config->gpi10_routing & 0x03) << 20;
+       reg32 |= (config->gpi11_routing & 0x03) << 22;
+       reg32 |= (config->gpi12_routing & 0x03) << 24;
+       reg32 |= (config->gpi13_routing & 0x03) << 26;
+       reg32 |= (config->gpi14_routing & 0x03) << 28;
+       reg32 |= (config->gpi15_routing & 0x03) << 30;
+
+       pci_write_config32(dev, 0xb8, reg32);
+}
+
+static void pch_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;
+
+       /* 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 Kconfig setting.
+        */
+       get_option(&pwr_on, "power_on_after_fail");
+
+       reg16 = pci_read_config16(dev, GEN_PMCON_3);
+       reg16 &= 0xfffe;
+       switch (pwr_on) {
+       case MAINBOARD_POWER_OFF:
+               reg16 |= 1;
+               state = "off";
+               break;
+       case MAINBOARD_POWER_ON:
+               reg16 &= ~1;
+               state = "on";
+               break;
+       case MAINBOARD_POWER_KEEP:
+               reg16 &= ~1;
+               state = "state keep";
+               break;
+       default:
+               state = "undefined";
+       }
+
+       reg16 &= ~(3 << 4);     /* SLP_S4# Assertion Stretch 4s */
+       reg16 |= (1 << 3);      /* SLP_S4# Assertion Stretch Enable */
+
+       reg16 &= ~(1 << 10);
+       reg16 |= (1 << 11);     /* SLP_S3# Min Assertion Width 50ms */
+
+       reg16 |= (1 << 12);     /* Disable SLP stretch after SUS well */
+
+       pci_write_config16(dev, GEN_PMCON_3, reg16);
+       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(0x70);
+       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, GEN_PMCON_1);
+       reg16 &= ~(3 << 0);     // SMI# rate 1 minute
+       reg16 &= ~(1 << 10);    // Disable BIOS_PCI_EXP_EN for native PME
+#if DEBUG_PERIODIC_SMIS
+       /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
+        * periodic SMIs.
+        */
+       reg16 |= (3 << 0); // Periodic SMI every 8s
+#endif
+       pci_write_config16(dev, GEN_PMCON_1, reg16);
+
+       // Set the board's GPI routing.
+       pch_gpi_routing(dev);
+
+       pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
+
+       outl(config->gpe0_en, pmbase + GPE0_EN);
+       outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
+
+       /* Set up power management block and determine sleep mode */
+       reg32 = inl(pmbase + 0x04); // PM1_CNT
+       reg32 &= ~(7 << 10);    // SLP_TYP
+       reg32 |= (1 << 0);      // SCI_EN
+       outl(reg32, pmbase + 0x04);
+
+       /* Clear magic status bits to prevent unexpected wake */
+       reg32 = RCBA32(0x3310);
+       reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
+       RCBA32(0x3310) = reg32;
+
+       reg32 = RCBA32(0x3f02);
+       reg32 &= ~0xf;
+       RCBA32(0x3f02) = reg32;
+}
+
+static void pch_rtc_init(struct device *dev)
+{
+       u8 reg8;
+       int rtc_failed;
+
+       reg8 = pci_read_config8(dev, GEN_PMCON_3);
+       rtc_failed = reg8 & RTC_BATTERY_DEAD;
+       if (rtc_failed) {
+               reg8 &= ~RTC_BATTERY_DEAD;
+               pci_write_config8(dev, GEN_PMCON_3, reg8);
+       }
+       printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
+
+       rtc_init(rtc_failed);
+}
+
+static void pch_pm_init(struct device *dev)
+{
+       pci_write_config8(dev, 0xa9, 0x47);
+       RCBA32_AND_OR(0x2238, ~0UL, (1 << 6)|(1 << 0));
+       RCBA32_AND_OR(0x228c, ~0UL, (1 << 0));
+       RCBA16_AND_OR(0x1100, ~0UL, (1 << 13)|(1 << 14));
+       RCBA16_AND_OR(0x0900, ~0UL, (1 << 14));
+       RCBA32(0x2304) = 0xc0388400;
+       RCBA32_AND_OR(0x2314, ~0UL, (1 << 5)|(1 << 18));
+       RCBA32_AND_OR(0x2320, ~0UL, (1 << 15)|(1 << 1));
+       RCBA32_AND_OR(0x3314, ~0x1f, 0xf);
+       RCBA32(0x3318) = 0x050f0000;
+       RCBA32(0x3324) = 0x04000000;
+       RCBA32_AND_OR(0x3340, ~0UL, 0xfffff);
+       RCBA32_AND_OR(0x3344, ~0UL, (1 << 1));
+       RCBA32(0x3360) = 0x0001c000;
+       RCBA32(0x3368) = 0x00061100;
+       RCBA32(0x3378) = 0x7f8fdfff;
+       RCBA32(0x337c) = 0x000003fc;
+       RCBA32(0x3388) = 0x00001000;
+       RCBA32(0x3390) = 0x0001c000;
+       RCBA32(0x33a0) = 0x00000800;
+       RCBA32(0x33b0) = 0x00001000;
+       RCBA32(0x33c0) = 0x00093900;
+       RCBA32(0x33cc) = 0x24653002;
+       RCBA32(0x33d0) = 0x062108fe;
+       RCBA32_AND_OR(0x33d4, 0xf000f000, 0x00670060);
+       RCBA32(0x3a28) = 0x01010000;
+       RCBA32(0x3a2c) = 0x01010404;
+       RCBA32(0x3a80) = 0x01041041;
+       RCBA32_AND_OR(0x3a84, ~0x0000ffff, 0x00001001);
+       RCBA32_AND_OR(0x3a84, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
+       RCBA32_AND_OR(0x3a88, ~0UL, (1 << 0));  /* SATA 4/5 disabled */
+       RCBA32(0x3a6c) = 0x00000001;
+       RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
+       RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
+       RCBA32(0x33c8) = 0;
+       RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
+}
+
+static void enable_hpet(void)
+{
+       u32 reg32;
+
+       /* Move HPET to default address 0xfed00000 and enable it */
+       reg32 = RCBA32(HPTC);
+       reg32 |= (1 << 7); // HPET Address Enable
+       reg32 &= ~(3 << 0);
+       RCBA32(HPTC) = reg32;
+}
+
+static void enable_clock_gating(device_t dev)
+{
+       u32 reg32;
+       u16 reg16;
+
+       RCBA32_AND_OR(0x2234, ~0UL, 0xf);
+
+       reg16 = pci_read_config16(dev, GEN_PMCON_1);
+       reg16 |= (1 << 2) | (1 << 11);
+       pci_write_config16(dev, GEN_PMCON_1, reg16);
+
+       pch_iobp_update(0xEB007F07, ~0UL, (1 << 31));
+       pch_iobp_update(0xEB004000, ~0UL, (1 << 7));
+       pch_iobp_update(0xEC007F07, ~0UL, (1 << 31));
+       pch_iobp_update(0xEC004000, ~0UL, (1 << 7));
+
+       reg32 = RCBA32(CG);
+       reg32 |= (1 << 31);
+       reg32 |= (1 << 29) | (1 << 28);
+       reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
+       reg32 |= (1 << 16);
+       reg32 |= (1 << 17);
+       reg32 |= (1 << 18);
+       reg32 |= (1 << 22);
+       reg32 |= (1 << 23);
+       reg32 &= ~(1 << 20);
+       reg32 |= (1 << 19);
+       reg32 |= (1 << 0);
+       reg32 |= (0xf << 1);
+       RCBA32(CG) = reg32;
+
+       RCBA32_OR(0x38c0, 0x7);
+       RCBA32_OR(0x36d4, 0x6680c004);
+       RCBA32_OR(0x3564, 0x3);
+}
+
+#if CONFIG_HAVE_SMI_HANDLER
+static void pch_lock_smm(struct device *dev)
+{
+#if TEST_SMM_FLASH_LOCKDOWN
+       u8 reg8;
+#endif
+
+#if ENABLE_ACPI_MODE_IN_COREBOOT
+       printk(BIOS_DEBUG, "Enabling ACPI via APMC:\n");
+       outb(0xe1, 0xb2); // Enable ACPI mode
+       printk(BIOS_DEBUG, "done.\n");
+#else
+       printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
+       outb(0x1e, 0xb2); // Disable ACPI mode
+       printk(BIOS_DEBUG, "done.\n");
+#endif
+       /* Don't allow evil boot loaders, kernels, or
+        * userspace applications to deceive us:
+        */
+       smm_lock();
+
+#if TEST_SMM_FLASH_LOCKDOWN
+       /* Now try this: */
+       printk(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 pch_disable_smm_only_flashing(struct device *dev)
+{
+       u8 reg8;
+
+       printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
+       reg8 = pci_read_config8(dev, 0xdc);     /* BIOS_CNTL */
+       reg8 &= ~(1 << 5);
+       pci_write_config8(dev, 0xdc, reg8);
+}
+
+static void pch_fixups(struct device *dev)
+{
+       u8 gen_pmcon_2;
+
+       /* Indicate DRAM init done for MRC S3 to know it can resume */
+       gen_pmcon_2 = pci_read_config8(dev, GEN_PMCON_2);
+       gen_pmcon_2 |= (1 << 7);
+       pci_write_config8(dev, GEN_PMCON_2, gen_pmcon_2);
+
+       /*
+        * Enable DMI ASPM in the PCH
+        */
+       RCBA32_AND_OR(0x2304, ~(1 << 10), 0);
+       RCBA32_OR(0x21a4, (1 << 11)|(1 << 10));
+       RCBA32_OR(0x21a8, 0x3);
+}
+
+static void pch_decode_init(struct device *dev)
+{
+       config_t *config = dev->chip_info;
+
+       printk(BIOS_DEBUG, "pch_decode_init\n");
+
+       pci_write_config32(dev, LPC_GEN1_DEC, config->gen1_dec);
+       pci_write_config32(dev, LPC_GEN2_DEC, config->gen2_dec);
+       pci_write_config32(dev, LPC_GEN3_DEC, config->gen3_dec);
+       pci_write_config32(dev, LPC_GEN4_DEC, config->gen4_dec);
+}
+
+static void lpc_init(struct device *dev)
+{
+       printk(BIOS_DEBUG, "pch: lpc_init\n");
+
+       /* Set the value for PCI command register. */
+       pci_write_config16(dev, PCI_COMMAND, 0x000f);
+
+       /* IO APIC initialization. */
+       pch_enable_apic(dev);
+
+       pch_enable_serial_irqs(dev);
+
+       /* Setup the PIRQ. */
+       pch_pirq_init(dev);
+
+       /* Setup power options. */
+       pch_power_options(dev);
+
+       /* Initialize power management */
+       pch_pm_init(dev);
+
+       /* Set the state of the GPIO lines. */
+       //gpio_init(dev);
+
+       /* Initialize the real time clock. */
+       pch_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(dev);
+
+       setup_i8259();
+
+       /* The OS should do this? */
+       /* Interrupt 9 should be level triggered (SCI) */
+       i8259_configure_irq_trigger(9, 1);
+
+       pch_disable_smm_only_flashing(dev);
+
+#if CONFIG_HAVE_SMI_HANDLER
+       pch_lock_smm(dev);
+#endif
+
+       pch_fixups(dev);
+}
+
+static void pch_lpc_read_resources(device_t dev)
+{
+       struct resource *res;
+
+       /* Get the normal PCI resources of this device. */
+       pci_dev_read_resources(dev);
+
+       /* Add an extra subtractive resource for both memory and I/O. */
+       res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
+       res->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 pch_lpc_enable_resources(device_t dev)
+{
+       pch_decode_init(dev);
+       return pci_dev_enable_resources(dev);
+}
+
+static void pch_lpc_enable(device_t dev)
+{
+       /* Enable PCH Display Port */
+       RCBA16(DISPBDF) = 0x0010;
+       RCBA32_OR(FD2, PCH_ENABLE_DBDF);
+
+       pch_enable(dev);
+}
+
+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 struct pci_operations pci_ops = {
+       .set_subsystem = set_subsystem,
+};
+
+static struct device_operations device_ops = {
+       .read_resources         = pch_lpc_read_resources,
+       .set_resources          = pci_dev_set_resources,
+       .enable_resources       = pch_lpc_enable_resources,
+       .init                   = lpc_init,
+       .enable                 = pch_lpc_enable,
+       .scan_bus               = scan_static_bus,
+       .ops_pci                = &pci_ops,
+};
+
+
+/* IDs for LPC device of Intel 6 series Chipset and
+ * Intel C200 Series Chipset according to specification
+ * update from August 2011
+ */
+
+static const struct pci_driver q67_lpc __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c4e,
+};
+static const struct pci_driver q65_lpc __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c4c,
+};
+static const struct pci_driver b65_lpc __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c50,
+};
+static const struct pci_driver h67_lpc __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c4a,
+};
+static const struct pci_driver z68_lpc __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c46,
+};
+static const struct pci_driver h61_lpc __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c5c,
+};
+static const struct pci_driver c202_lpc __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c52,
+};
+static const struct pci_driver c204_lpc __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c54,
+};
+static const struct pci_driver c206_lpc __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c56,
+};
+static const struct pci_driver qm67_lpc __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c4f,
+};
+static const struct pci_driver um67_lpc __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c47,
+};
+static const struct pci_driver hm67_lpc __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c4b,
+};
+static const struct pci_driver hm65_lpc __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c49,
+};
+static const struct pci_driver qs67_lpc __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c4d,
+};
+static const struct pci_driver c216_lpc __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1e55,
+};
diff --git a/src/southbridge/intel/bd82x6x/me.c b/src/southbridge/intel/bd82x6x/me.c
new file mode 100644 (file)
index 0000000..a1ae06d
--- /dev/null
@@ -0,0 +1,750 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+/*
+ * This is a ramstage driver for the Intel Management Engine found in the
+ * 6-series chipset.  It handles the required boot-time messages over the
+ * MMIO-based Management Engine Interface to tell the ME that the BIOS is
+ * finished with POST.  Additional messages are defined for debug but are
+ * not used unless the console loglevel is high enough.
+ */
+
+#include <arch/acpi.h>
+#include <arch/hlt.h>
+#include <arch/io.h>
+#include <console/console.h>
+#include <device/pci_ids.h>
+#include <device/pci_def.h>
+#include <string.h>
+#include <delay.h>
+
+#ifdef __SMM__
+# include <arch/romcc_io.h>
+# include <northbridge/intel/sandybridge/pcie_config.c>
+#else
+# include <device/device.h>
+# include <device/pci.h>
+#endif
+
+#include "me.h"
+#include "pch.h"
+
+#if CONFIG_CHROMEOS
+#include <vendorcode/google/chromeos/gnvs.h>
+#endif
+
+#ifndef __SMM__
+/* Path that the BIOS should take based on ME state */
+static const char *me_bios_path_values[] = {
+       [ME_NORMAL_BIOS_PATH]           = "Normal",
+       [ME_S3WAKE_BIOS_PATH]           = "S3 Wake",
+       [ME_ERROR_BIOS_PATH]            = "Error",
+       [ME_RECOVERY_BIOS_PATH]         = "Recovery",
+       [ME_DISABLE_BIOS_PATH]          = "Disable",
+       [ME_FIRMWARE_UPDATE_BIOS_PATH]  = "Firmware Update",
+};
+#endif
+
+/* MMIO base address for MEI interface */
+static u32 mei_base_address;
+
+#if CONFIG_DEBUG_INTEL_ME
+static void mei_dump(void *ptr, int dword, int offset, const char *type)
+{
+       struct mei_csr *csr;
+
+       printk(BIOS_SPEW, "%-9s[%02x] : ", type, offset);
+
+       switch (offset) {
+       case MEI_H_CSR:
+       case MEI_ME_CSR_HA:
+               csr = ptr;
+               if (!csr) {
+                       printk(BIOS_SPEW, "ERROR: 0x%08x\n", dword);
+                       break;
+               }
+               printk(BIOS_SPEW, "cbd=%u cbrp=%02u cbwp=%02u ready=%u "
+                      "reset=%u ig=%u is=%u ie=%u\n", csr->buffer_depth,
+                      csr->buffer_read_ptr, csr->buffer_write_ptr,
+                      csr->ready, csr->reset, csr->interrupt_generate,
+                      csr->interrupt_status, csr->interrupt_enable);
+               break;
+       case MEI_ME_CB_RW:
+       case MEI_H_CB_WW:
+               printk(BIOS_SPEW, "CB: 0x%08x\n", dword);
+               break;
+       default:
+               printk(BIOS_SPEW, "0x%08x\n", offset);
+               break;
+       }
+}
+#else
+# define mei_dump(ptr,dword,offset,type) do {} while (0)
+#endif
+
+/*
+ * ME/MEI access helpers using memcpy to avoid aliasing.
+ */
+
+static inline void mei_read_dword_ptr(void *ptr, int offset)
+{
+       u32 dword = read32(mei_base_address + offset);
+       memcpy(ptr, &dword, sizeof(dword));
+       mei_dump(ptr, dword, offset, "READ");
+}
+
+static inline void mei_write_dword_ptr(void *ptr, int offset)
+{
+       u32 dword = 0;
+       memcpy(&dword, ptr, sizeof(dword));
+       write32(mei_base_address + offset, dword);
+       mei_dump(ptr, dword, offset, "WRITE");
+}
+
+#ifndef __SMM__
+static inline void pci_read_dword_ptr(device_t dev, void *ptr, int offset)
+{
+       u32 dword = pci_read_config32(dev, offset);
+       memcpy(ptr, &dword, sizeof(dword));
+       mei_dump(ptr, dword, offset, "PCI READ");
+}
+#endif
+
+static inline void read_host_csr(struct mei_csr *csr)
+{
+       mei_read_dword_ptr(csr, MEI_H_CSR);
+}
+
+static inline void write_host_csr(struct mei_csr *csr)
+{
+       mei_write_dword_ptr(csr, MEI_H_CSR);
+}
+
+static inline void read_me_csr(struct mei_csr *csr)
+{
+       mei_read_dword_ptr(csr, MEI_ME_CSR_HA);
+}
+
+static inline void write_cb(u32 dword)
+{
+       write32(mei_base_address + MEI_H_CB_WW, dword);
+       mei_dump(NULL, dword, MEI_H_CB_WW, "WRITE");
+}
+
+static inline u32 read_cb(void)
+{
+       u32 dword = read32(mei_base_address + MEI_ME_CB_RW);
+       mei_dump(NULL, dword, MEI_ME_CB_RW, "READ");
+       return dword;
+}
+
+/* Wait for ME ready bit to be asserted */
+static int mei_wait_for_me_ready(void)
+{
+       struct mei_csr me;
+       unsigned try = ME_RETRY;
+
+       while (try--) {
+               read_me_csr(&me);
+               if (me.ready)
+                       return 0;
+               udelay(ME_DELAY);
+       }
+
+       printk(BIOS_ERR, "ME: failed to become ready\n");
+       return -1;
+}
+
+static void mei_reset(void)
+{
+       struct mei_csr host;
+
+       if (mei_wait_for_me_ready() < 0)
+               return;
+
+       /* Reset host and ME circular buffers for next message */
+       read_host_csr(&host);
+       host.reset = 1;
+       host.interrupt_generate = 1;
+       write_host_csr(&host);
+
+       if (mei_wait_for_me_ready() < 0)
+               return;
+
+       /* Re-init and indicate host is ready */
+       read_host_csr(&host);
+       host.interrupt_generate = 1;
+       host.ready = 1;
+       host.reset = 0;
+       write_host_csr(&host);
+}
+
+static int mei_send_msg(struct mei_header *mei, struct mkhi_header *mkhi,
+                       void *req_data)
+{
+       struct mei_csr host;
+       unsigned ndata, n;
+       u32 *data;
+
+       /* Number of dwords to write, ignoring MKHI */
+       ndata = mei->length >> 2;
+
+       /* Pad non-dword aligned request message length */
+       if (mei->length & 3)
+               ndata++;
+       if (!ndata) {
+               printk(BIOS_DEBUG, "ME: request does not include MKHI\n");
+               return -1;
+       }
+       ndata++; /* Add MEI header */
+
+       /*
+        * Make sure there is still room left in the circular buffer.
+        * Reset the buffer pointers if the requested message will not fit.
+        */
+       read_host_csr(&host);
+       if ((host.buffer_depth - host.buffer_write_ptr) < ndata) {
+               printk(BIOS_ERR, "ME: circular buffer full, resetting...\n");
+               mei_reset();
+               read_host_csr(&host);
+       }
+
+       /*
+        * This implementation does not handle splitting large messages
+        * across multiple transactions.  Ensure the requested length
+        * will fit in the available circular buffer depth.
+        */
+       if ((host.buffer_depth - host.buffer_write_ptr) < ndata) {
+               printk(BIOS_ERR, "ME: message (%u) too large for buffer (%u)\n",
+                      ndata + 2, host.buffer_depth);
+               return -1;
+       }
+
+       /* Write MEI header */
+       mei_write_dword_ptr(mei, MEI_H_CB_WW);
+       ndata--;
+
+       /* Write MKHI header */
+       mei_write_dword_ptr(mkhi, MEI_H_CB_WW);
+       ndata--;
+
+       /* Write message data */
+       data = req_data;
+       for (n = 0; n < ndata; ++n)
+               write_cb(*data++);
+
+       /* Generate interrupt to the ME */
+       read_host_csr(&host);
+       host.interrupt_generate = 1;
+       write_host_csr(&host);
+
+       /* Make sure ME is ready after sending request data */
+       return mei_wait_for_me_ready();
+}
+
+static int mei_recv_msg(struct mei_header *mei, struct mkhi_header *mkhi,
+                       void *rsp_data, int rsp_bytes)
+{
+       struct mei_header mei_rsp;
+       struct mkhi_header mkhi_rsp;
+       struct mei_csr me, host;
+       unsigned ndata, n;
+       unsigned expected;
+       u32 *data;
+
+       /* Total number of dwords to read from circular buffer */
+       expected = (rsp_bytes + sizeof(mei_rsp) + sizeof(mkhi_rsp)) >> 2;
+       if (rsp_bytes & 3)
+               expected++;
+
+       /*
+        * The interrupt status bit does not appear to indicate that the
+        * message has actually been received.  Instead we wait until the
+        * expected number of dwords are present in the circular buffer.
+        */
+       for (n = ME_RETRY; n; --n) {
+               read_me_csr(&me);
+               if ((me.buffer_write_ptr - me.buffer_read_ptr) >= expected)
+                       break;
+               udelay(ME_DELAY);
+       }
+       if (!n) {
+               printk(BIOS_ERR, "ME: timeout waiting for data: expected "
+                      "%u, available %u\n", expected,
+                      me.buffer_write_ptr - me.buffer_read_ptr);
+               return -1;
+       }
+
+       /* Read and verify MEI response header from the ME */
+       mei_read_dword_ptr(&mei_rsp, MEI_ME_CB_RW);
+       if (!mei_rsp.is_complete) {
+               printk(BIOS_ERR, "ME: response is not complete\n");
+               return -1;
+       }
+
+       /* Handle non-dword responses and expect at least MKHI header */
+       ndata = mei_rsp.length >> 2;
+       if (mei_rsp.length & 3)
+               ndata++;
+       if (ndata != (expected - 1)) {
+               printk(BIOS_ERR, "ME: response is missing data\n");
+               return -1;
+       }
+
+       /* Read and verify MKHI response header from the ME */
+       mei_read_dword_ptr(&mkhi_rsp, MEI_ME_CB_RW);
+       if (!mkhi_rsp.is_response ||
+           mkhi->group_id != mkhi_rsp.group_id ||
+           mkhi->command != mkhi_rsp.command) {
+               printk(BIOS_ERR, "ME: invalid response, group %u ?= %u, "
+                      "command %u ?= %u, is_response %u\n", mkhi->group_id,
+                      mkhi_rsp.group_id, mkhi->command, mkhi_rsp.command,
+                      mkhi_rsp.is_response);
+               return -1;
+       }
+       ndata--; /* MKHI header has been read */
+
+       /* Make sure caller passed a buffer with enough space */
+       if (ndata != (rsp_bytes >> 2)) {
+               printk(BIOS_ERR, "ME: not enough room in response buffer: "
+                      "%u != %u\n", ndata, rsp_bytes >> 2);
+               return -1;
+       }
+
+       /* Read response data from the circular buffer */
+       data = rsp_data;
+       for (n = 0; n < ndata; ++n)
+               *data++ = read_cb();
+
+       /* Tell the ME that we have consumed the response */
+       read_host_csr(&host);
+       host.interrupt_status = 1;
+       host.interrupt_generate = 1;
+       write_host_csr(&host);
+
+       return mei_wait_for_me_ready();
+}
+
+static inline int mei_sendrecv(struct mei_header *mei, struct mkhi_header *mkhi,
+                              void *req_data, void *rsp_data, int rsp_bytes)
+{
+       if (mei_send_msg(mei, mkhi, req_data) < 0)
+               return -1;
+       if (mei_recv_msg(mei, mkhi, rsp_data, rsp_bytes) < 0)
+               return -1;
+       return 0;
+}
+
+/* Send END OF POST message to the ME */
+int mkhi_end_of_post(void)
+{
+       struct mkhi_header mkhi = {
+               .group_id       = MKHI_GROUP_ID_GEN,
+               .command        = MKHI_END_OF_POST,
+       };
+       struct mei_header mei = {
+               .is_complete    = 1,
+               .host_address   = MEI_HOST_ADDRESS,
+               .client_address = MEI_ADDRESS_MKHI,
+               .length         = sizeof(mkhi),
+       };
+
+       /* Send request and wait for response */
+       if (mei_sendrecv(&mei, &mkhi, NULL, NULL, 0) < 0) {
+               printk(BIOS_ERR, "ME: END OF POST message failed\n");
+               return -1;
+       }
+
+       printk(BIOS_INFO, "ME: END OF POST message successful\n");
+       return 0;
+}
+
+#if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG) && !defined(__SMM__)
+/* Get ME firmware version */
+static int mkhi_get_fw_version(void)
+{
+       struct me_fw_version version;
+       struct mkhi_header mkhi = {
+               .group_id       = MKHI_GROUP_ID_GEN,
+               .command        = MKHI_GET_FW_VERSION,
+       };
+       struct mei_header mei = {
+               .is_complete    = 1,
+               .host_address   = MEI_HOST_ADDRESS,
+               .client_address = MEI_ADDRESS_MKHI,
+               .length         = sizeof(mkhi),
+       };
+
+       /* Send request and wait for response */
+       if (mei_sendrecv(&mei, &mkhi, NULL, &version, sizeof(version)) < 0) {
+               printk(BIOS_ERR, "ME: GET FW VERSION message failed\n");
+               return -1;
+       }
+
+       printk(BIOS_INFO, "ME: Firmware Version %u.%u.%u.%u (code) "
+              "%u.%u.%u.%u (recovery)\n",
+              version.code_major, version.code_minor,
+              version.code_build_number, version.code_hot_fix,
+              version.recovery_major, version.recovery_minor,
+              version.recovery_build_number, version.recovery_hot_fix);
+
+       return 0;
+}
+
+static inline void print_cap(const char *name, int state)
+{
+       printk(BIOS_DEBUG, "ME Capability: %-30s : %sabled\n",
+              name, state ? "en" : "dis");
+}
+
+/* Get ME Firmware Capabilities */
+static int mkhi_get_fwcaps(void)
+{
+       u32 rule_id = 0;
+       struct me_fwcaps cap;
+       struct mkhi_header mkhi = {
+               .group_id       = MKHI_GROUP_ID_FWCAPS,
+               .command        = MKHI_FWCAPS_GET_RULE,
+       };
+       struct mei_header mei = {
+               .is_complete    = 1,
+               .host_address   = MEI_HOST_ADDRESS,
+               .client_address = MEI_ADDRESS_MKHI,
+               .length         = sizeof(mkhi) + sizeof(rule_id),
+       };
+
+       /* Send request and wait for response */
+       if (mei_sendrecv(&mei, &mkhi, &rule_id, &cap, sizeof(cap)) < 0) {
+               printk(BIOS_ERR, "ME: GET FWCAPS message failed\n");
+               return -1;
+       }
+
+       print_cap("Full Network manageability", cap.caps_sku.full_net);
+       print_cap("Regular Network manageability", cap.caps_sku.std_net);
+       print_cap("Manageability", cap.caps_sku.manageability);
+       print_cap("Small business technology", cap.caps_sku.small_business);
+       print_cap("Level III manageability", cap.caps_sku.l3manageability);
+       print_cap("IntelR Anti-Theft (AT)", cap.caps_sku.intel_at);
+       print_cap("IntelR Capability Licensing Service (CLS)",
+                 cap.caps_sku.intel_cls);
+       print_cap("IntelR Power Sharing Technology (MPC)",
+                 cap.caps_sku.intel_mpc);
+       print_cap("ICC Over Clocking", cap.caps_sku.icc_over_clocking);
+        print_cap("Protected Audio Video Path (PAVP)", cap.caps_sku.pavp);
+       print_cap("IPV6", cap.caps_sku.ipv6);
+       print_cap("KVM Remote Control (KVM)", cap.caps_sku.kvm);
+       print_cap("Outbreak Containment Heuristic (OCH)", cap.caps_sku.och);
+       print_cap("Virtual LAN (VLAN)", cap.caps_sku.vlan);
+       print_cap("TLS", cap.caps_sku.tls);
+       print_cap("Wireless LAN (WLAN)", cap.caps_sku.wlan);
+
+       return 0;
+}
+#endif
+
+/* Tell ME to issue a global reset */
+int mkhi_global_reset(void)
+{
+       struct me_global_reset reset = {
+               .request_origin = GLOBAL_RESET_BIOS_POST,
+               .reset_type     = CBM_RR_GLOBAL_RESET,
+       };
+       struct mkhi_header mkhi = {
+               .group_id       = MKHI_GROUP_ID_CBM,
+               .command        = MKHI_GLOBAL_RESET,
+       };
+       struct mei_header mei = {
+               .is_complete    = 1,
+               .length         = sizeof(mkhi) + sizeof(reset),
+               .host_address   = MEI_HOST_ADDRESS,
+               .client_address = MEI_ADDRESS_MKHI,
+       };
+
+       printk(BIOS_NOTICE, "ME: Requesting global reset\n");
+
+       /* Send request and wait for response */
+       if (mei_sendrecv(&mei, &mkhi, &reset, NULL, 0) < 0) {
+               /* No response means reset will happen shortly... */
+               hlt();
+       }
+
+       /* If the ME responded it rejected the reset request */
+       printk(BIOS_ERR, "ME: Global Reset failed\n");
+       return -1;
+}
+
+#ifdef __SMM__
+
+void intel_me_finalize_smm(void)
+{
+       struct me_hfs hfs;
+       u32 reg32;
+
+       mei_base_address =
+               pcie_read_config32(PCH_ME_DEV, PCI_BASE_ADDRESS_0) & ~0xf;
+
+       /* S3 path will have hidden this device already */
+       if (!mei_base_address || mei_base_address == 0xfffffff0)
+               return;
+
+       /* Make sure ME is in a mode that expects EOP */
+       reg32 = pcie_read_config32(PCH_ME_DEV, PCI_ME_HFS);
+       memcpy(&hfs, &reg32, sizeof(u32));
+
+       /* Abort and leave device alone if not normal mode */
+       if (hfs.fpt_bad ||
+           hfs.working_state != ME_HFS_CWS_NORMAL ||
+           hfs.operation_mode != ME_HFS_MODE_NORMAL)
+               return;
+
+       /* Try to send EOP command so ME stops accepting other commands */
+       mkhi_end_of_post();
+
+       /* Make sure IO is disabled */
+       reg32 = pcie_read_config32(PCH_ME_DEV, PCI_COMMAND);
+       reg32 &= ~(PCI_COMMAND_MASTER |
+                  PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
+       pcie_write_config32(PCH_ME_DEV, PCI_COMMAND, reg32);
+
+       /* Hide the PCI device */
+       RCBA32_OR(FD2, PCH_DISABLE_MEI1);
+}
+
+#else /* !__SMM__ */
+
+/* Determine the path that we should take based on ME status */
+static me_bios_path intel_me_path(device_t dev)
+{
+       me_bios_path path = ME_DISABLE_BIOS_PATH;
+       struct me_hfs hfs;
+       struct me_gmes gmes;
+
+#if CONFIG_HAVE_ACPI_RESUME
+       /* S3 wake skips all MKHI messages */
+       if (acpi_slp_type == 3) {
+               return ME_S3WAKE_BIOS_PATH;
+       }
+#endif
+
+       pci_read_dword_ptr(dev, &hfs, PCI_ME_HFS);
+       pci_read_dword_ptr(dev, &gmes, PCI_ME_GMES);
+
+       /* Check and dump status */
+       intel_me_status(&hfs, &gmes);
+
+       /* Check for valid firmware */
+       if (hfs.fpt_bad)
+               return ME_ERROR_BIOS_PATH;
+
+       /* Check Current Working State */
+       switch (hfs.working_state) {
+       case ME_HFS_CWS_NORMAL:
+               path = ME_NORMAL_BIOS_PATH;
+               break;
+       case ME_HFS_CWS_REC:
+               path = ME_RECOVERY_BIOS_PATH;
+               break;
+       default:
+               path = ME_DISABLE_BIOS_PATH;
+               break;
+       }
+
+       /* Check Current Operation Mode */
+       switch (hfs.operation_mode) {
+       case ME_HFS_MODE_NORMAL:
+               break;
+       case ME_HFS_MODE_DEBUG:
+       case ME_HFS_MODE_DIS:
+       case ME_HFS_MODE_OVER_JMPR:
+       case ME_HFS_MODE_OVER_MEI:
+       default:
+               path = ME_DISABLE_BIOS_PATH;
+               break;
+       }
+
+       /* Check for any error code */
+       if (hfs.error_code)
+               path = ME_ERROR_BIOS_PATH;
+
+       return path;
+}
+
+/* Prepare ME for MEI messages */
+static int intel_mei_setup(device_t dev)
+{
+       struct resource *res;
+       struct mei_csr host;
+       u32 reg32;
+
+       /* Find the MMIO base for the ME interface */
+       res = find_resource(dev, PCI_BASE_ADDRESS_0);
+       if (!res || res->base == 0 || res->size == 0) {
+               printk(BIOS_DEBUG, "ME: MEI resource not present!\n");
+               return -1;
+       }
+       mei_base_address = res->base;
+
+       /* Ensure Memory and Bus Master bits are set */
+       reg32 = pci_read_config32(dev, PCI_COMMAND);
+       reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+       pci_write_config32(dev, PCI_COMMAND, reg32);
+
+       /* Clean up status for next message */
+       read_host_csr(&host);
+       host.interrupt_generate = 1;
+       host.ready = 1;
+       host.reset = 0;
+       write_host_csr(&host);
+
+       return 0;
+}
+
+/* Read the Extend register hash of ME firmware */
+static int intel_me_extend_valid(device_t dev)
+{
+       struct me_heres status;
+       u32 extend[] = {0};
+       int i, count = 0;
+
+       pci_read_dword_ptr(dev, &status, PCI_ME_HERES);
+       if (!status.extend_feature_present) {
+               printk(BIOS_ERR, "ME: Extend Feature not present\n");
+               return -1;
+       }
+
+       if (!status.extend_reg_valid) {
+               printk(BIOS_ERR, "ME: Extend Register not valid\n");
+               return -1;
+       }
+
+       switch (status.extend_reg_algorithm) {
+       case PCI_ME_EXT_SHA1:
+               count = 5;
+               printk(BIOS_DEBUG, "ME: Extend SHA-1: ");
+               break;
+       case PCI_ME_EXT_SHA256:
+               count = 8;
+               printk(BIOS_DEBUG, "ME: Extend SHA-256: ");
+               break;
+       default:
+               printk(BIOS_ERR, "ME: Extend Algorithm %d unknown\n",
+                      status.extend_reg_algorithm);
+               return -1;
+       }
+
+       for (i = 0; i < count; ++i) {
+               extend[i] = pci_read_config32(dev, PCI_ME_HER(i));
+               printk(BIOS_DEBUG, "%08x", extend[i]);
+       }
+       printk(BIOS_DEBUG, "\n");
+
+#if CONFIG_CHROMEOS
+       /* Save hash in NVS for the OS to verify */
+       chromeos_set_me_hash(extend, count);
+#endif
+
+       return 0;
+}
+
+/* Hide the ME virtual PCI devices */
+static void intel_me_hide(device_t dev)
+{
+       dev->enabled = 0;
+       pch_enable(dev);
+}
+
+/* Check whether ME is present and do basic init */
+static void intel_me_init(device_t dev)
+{
+       me_bios_path path = intel_me_path(dev);
+
+       /* Do initial setup and determine the BIOS path */
+       printk(BIOS_NOTICE, "ME: BIOS path: %s\n", me_bios_path_values[path]);
+
+       switch (path) {
+       case ME_S3WAKE_BIOS_PATH:
+               intel_me_hide(dev);
+               break;
+
+       case ME_NORMAL_BIOS_PATH:
+               /* Validate the extend register */
+               if (intel_me_extend_valid(dev) < 0)
+                       break; /* TODO: force recovery mode */
+
+               /* Prepare MEI MMIO interface */
+               if (intel_mei_setup(dev) < 0)
+                       break;
+
+#if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG)
+               /* Print ME firmware version */
+               mkhi_get_fw_version();
+               /* Print ME firmware capabilities */
+               mkhi_get_fwcaps();
+#endif
+
+               /*
+                * Leave the ME unlocked in this path.
+                * It will be locked via SMI command later.
+                */
+               break;
+
+       case ME_ERROR_BIOS_PATH:
+       case ME_RECOVERY_BIOS_PATH:
+       case ME_DISABLE_BIOS_PATH:
+       case ME_FIRMWARE_UPDATE_BIOS_PATH:
+               /*
+                * TODO(dlaurie) Force recovery mode if ME is unhappy?
+                */
+               break;
+       }
+}
+
+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 struct pci_operations pci_ops = {
+       .set_subsystem = 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                   = intel_me_init,
+       .scan_bus               = scan_static_bus,
+       .ops_pci                = &pci_ops,
+};
+
+static const struct pci_driver intel_me __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c3a,
+};
+
+#endif /* !__SMM__ */
diff --git a/src/southbridge/intel/bd82x6x/me.h b/src/southbridge/intel/bd82x6x/me.h
new file mode 100644 (file)
index 0000000..53964a2
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#ifndef _INTEL_ME_H
+#define _INTEL_ME_H
+
+#define ME_RETRY               100000  /* 1 second */
+#define ME_DELAY               10      /* 10 us */
+
+/*
+ * Management Engine PCI registers
+ */
+
+#define PCI_CPU_DEVICE         PCI_DEV(0,0,0)
+#define PCI_CPU_MEBASE_L       0x70    /* Set by MRC */
+#define PCI_CPU_MEBASE_H       0x74    /* Set by MRC */
+
+#define PCI_ME_HFS             0x40
+#define  ME_HFS_CWS_RESET      0
+#define  ME_HFS_CWS_INIT       1
+#define  ME_HFS_CWS_REC                2
+#define  ME_HFS_CWS_NORMAL     5
+#define  ME_HFS_CWS_WAIT       6
+#define  ME_HFS_CWS_TRANS      7
+#define  ME_HFS_CWS_INVALID    8
+#define  ME_HFS_STATE_PREBOOT  0
+#define  ME_HFS_STATE_M0_UMA   1
+#define  ME_HFS_STATE_M3       4
+#define  ME_HFS_STATE_M0       5
+#define  ME_HFS_STATE_BRINGUP  6
+#define  ME_HFS_STATE_ERROR    7
+#define  ME_HFS_ERROR_NONE     0
+#define  ME_HFS_ERROR_UNCAT    1
+#define  ME_HFS_ERROR_IMAGE    3
+#define  ME_HFS_ERROR_DEBUG    4
+#define  ME_HFS_MODE_NORMAL    0
+#define  ME_HFS_MODE_DEBUG     2
+#define  ME_HFS_MODE_DIS       3
+#define  ME_HFS_MODE_OVER_JMPR 4
+#define  ME_HFS_MODE_OVER_MEI  5
+#define  ME_HFS_BIOS_DRAM_ACK  1
+#define  ME_HFS_ACK_NO_DID     0
+#define  ME_HFS_ACK_RESET      1
+#define  ME_HFS_ACK_PWR_CYCLE  2
+#define  ME_HFS_ACK_S3         3
+#define  ME_HFS_ACK_S4         4
+#define  ME_HFS_ACK_S5         5
+#define  ME_HFS_ACK_GBL_RESET  6
+#define  ME_HFS_ACK_CONTINUE   7
+
+struct me_hfs {
+       u32 working_state: 4;
+       u32 mfg_mode: 1;
+       u32 fpt_bad: 1;
+       u32 operation_state: 3;
+       u32 fw_init_complete: 1;
+       u32 ft_bup_ld_flr: 1;
+       u32 update_in_progress: 1;
+       u32 error_code: 4;
+       u32 operation_mode: 4;
+       u32 reserved: 4;
+       u32 boot_options_present: 1;
+       u32 ack_data: 3;
+       u32 bios_msg_ack: 4;
+} __attribute__ ((packed));
+
+#define PCI_ME_UMA             0x44
+
+struct me_uma {
+       u32 size: 6;
+       u32 reserved_1: 10;
+       u32 valid: 1;
+       u32 reserved_0: 14;
+       u32 set_to_one: 1;
+} __attribute__ ((packed));
+
+#define PCI_ME_H_GS            0x4c
+#define  ME_INIT_DONE          1
+#define  ME_INIT_STATUS_SUCCESS        0
+#define  ME_INIT_STATUS_NOMEM  1
+#define  ME_INIT_STATUS_ERROR  2
+
+struct me_did {
+       u32 uma_base: 16;
+       u32 reserved: 8;
+       u32 status: 4;
+       u32 init_done: 4;
+} __attribute__ ((packed));
+
+#define PCI_ME_GMES            0x48
+#define  ME_GMES_PHASE_ROM     0
+#define  ME_GMES_PHASE_BUP     1
+#define  ME_GMES_PHASE_UKERNEL 2
+#define  ME_GMES_PHASE_POLICY  3
+#define  ME_GMES_PHASE_MODULE  4
+#define  ME_GMES_PHASE_UNKNOWN 5
+#define  ME_GMES_PHASE_HOST    6
+
+struct me_gmes {
+       u32 bist_in_prog : 1;
+       u32 icc_prog_sts : 2;
+       u32 invoke_mebx : 1;
+       u32 cpu_replaced_sts : 1;
+       u32 mbp_rdy : 1;
+       u32 mfs_failure : 1;
+       u32 warm_rst_req_for_df : 1;
+       u32 cpu_replaced_valid : 1;
+       u32 reserved_1 : 2;
+       u32 fw_upd_ipu : 1;
+       u32 reserved_2 : 4;
+       u32 current_state: 8;
+       u32 current_pmevent: 4;
+       u32 progress_code: 4;
+} __attribute__ ((packed));
+
+#define PCI_ME_HERES           0xbc
+#define  PCI_ME_EXT_SHA1       0x00
+#define  PCI_ME_EXT_SHA256     0x02
+#define PCI_ME_HER(x)          (0xc0+(4*(x)))
+
+struct me_heres {
+       u32 extend_reg_algorithm: 4;
+       u32 reserved: 26;
+       u32 extend_feature_present: 1;
+       u32 extend_reg_valid: 1;
+} __attribute__ ((packed));
+
+/*
+ * Management Engine MEI registers
+ */
+
+#define MEI_H_CB_WW            0x00
+#define MEI_H_CSR              0x04
+#define MEI_ME_CB_RW           0x08
+#define MEI_ME_CSR_HA          0x0c
+
+struct mei_csr {
+       u32 interrupt_enable: 1;
+       u32 interrupt_status: 1;
+       u32 interrupt_generate: 1;
+       u32 ready: 1;
+       u32 reset: 1;
+       u32 reserved: 3;
+       u32 buffer_read_ptr: 8;
+       u32 buffer_write_ptr: 8;
+       u32 buffer_depth: 8;
+} __attribute__ ((packed));
+
+#define MEI_ADDRESS_CORE       0x01
+#define MEI_ADDRESS_AMT                0x02
+#define MEI_ADDRESS_RESERVED   0x03
+#define MEI_ADDRESS_WDT                0x04
+#define MEI_ADDRESS_MKHI       0x07
+#define MEI_ADDRESS_ICC                0x08
+#define MEI_ADDRESS_THERMAL    0x09
+
+#define MEI_HOST_ADDRESS       0
+
+struct mei_header {
+       u32 client_address: 8;
+       u32 host_address: 8;
+       u32 length: 9;
+       u32 reserved: 6;
+       u32 is_complete: 1;
+} __attribute__ ((packed));
+
+#define MKHI_GROUP_ID_CBM      0x00
+#define MKHI_GROUP_ID_FWCAPS   0x03
+#define MKHI_GROUP_ID_MDES     0x08
+#define MKHI_GROUP_ID_GEN      0xff
+
+#define MKHI_GLOBAL_RESET      0x0b
+
+#define MKHI_FWCAPS_GET_RULE   0x02
+
+#define MKHI_MDES_ENABLE       0x09
+
+#define MKHI_GET_FW_VERSION    0x02
+#define MKHI_END_OF_POST       0x0c
+#define MKHI_FEATURE_OVERRIDE  0x14
+
+struct mkhi_header {
+       u32 group_id: 8;
+       u32 command: 7;
+       u32 is_response: 1;
+       u32 reserved: 8;
+       u32 result: 8;
+} __attribute__ ((packed));
+
+struct me_fw_version {
+       u16 code_minor;
+       u16 code_major;
+       u16 code_build_number;
+       u16 code_hot_fix;
+       u16 recovery_minor;
+       u16 recovery_major;
+       u16 recovery_build_number;
+       u16 recovery_hot_fix;
+} __attribute__ ((packed));
+
+
+#define HECI_EOP_STATUS_SUCCESS       0x0
+#define HECI_EOP_PERFORM_GLOBAL_RESET 0x1
+
+#define CBM_RR_GLOBAL_RESET    0x01
+
+#define GLOBAL_RESET_BIOS_MRC  0x01
+#define GLOBAL_RESET_BIOS_POST 0x02
+#define GLOBAL_RESET_MEBX      0x03
+
+struct me_global_reset {
+       u8 request_origin;
+       u8 reset_type;
+} __attribute__ ((packed));
+
+typedef enum {
+       ME_NORMAL_BIOS_PATH,
+       ME_S3WAKE_BIOS_PATH,
+       ME_ERROR_BIOS_PATH,
+       ME_RECOVERY_BIOS_PATH,
+       ME_DISABLE_BIOS_PATH,
+       ME_FIRMWARE_UPDATE_BIOS_PATH,
+} me_bios_path;
+
+/* Defined in me_status.c for both romstage and ramstage */
+void intel_me_status(struct me_hfs *hfs, struct me_gmes *gmes);
+
+#ifdef __PRE_RAM__
+void intel_early_me_status(void);
+int intel_early_me_init(void);
+int intel_early_me_uma_size(void);
+int intel_early_me_init_done(u8 status);
+#else
+/* ME Kernel Host Interface Messages */
+int mkhi_end_of_post(void);
+int mkhi_global_reset(void);
+#endif
+
+#ifdef __SMM__
+void intel_me_finalize_smm(void);
+#endif
+typedef struct {
+       u32       major_version  : 16;
+       u32       minor_version  : 16;
+       u32       hotfix_version : 16;
+       u32       build_version  : 16;
+} __attribute__ ((packed)) mbp_fw_version_name;
+
+typedef struct {
+       u8        num_icc_profiles;
+       u8        icc_profile_soft_strap;
+       u8        icc_profile_index;
+       u8        reserved;
+       u32       register_lock_mask[3];
+} __attribute__ ((packed)) mbp_icc_profile;
+
+typedef struct {
+       u32  full_net           : 1;
+       u32  std_net            : 1;
+       u32  manageability      : 1;
+       u32  small_business     : 1;
+       u32  l3manageability    : 1;
+       u32  intel_at           : 1;
+       u32  intel_cls          : 1;
+       u32  reserved           : 3;
+       u32  intel_mpc          : 1;
+       u32  icc_over_clocking  : 1;
+       u32  pavp               : 1;
+       u32  reserved_1         : 4;
+       u32  ipv6               : 1;
+       u32  kvm                : 1;
+       u32  och                : 1;
+       u32  vlan               : 1;
+       u32  tls                : 1;
+       u32  reserved_4         : 1;
+       u32  wlan               : 1;
+       u32  reserved_5         : 8;
+} __attribute__ ((packed)) mefwcaps_sku;
+
+typedef struct {
+       u16  lock_state              : 1;
+       u16  authenticate_module     : 1;
+       u16  s3authentication        : 1;
+       u16  flash_wear_out          : 1;
+       u16  flash_variable_security : 1;
+       u16  wwan3gpresent           : 1;
+       u16  wwan3goob               : 1;
+       u16  reserved                : 9;
+} __attribute__ ((packed)) tdt_state_flag;
+
+typedef struct {
+       u8           state;
+       u8           last_theft_trigger;
+       tdt_state_flag  flags;
+}  __attribute__ ((packed)) tdt_state_info;
+
+typedef struct {
+       u32  platform_target_usage_type  : 4;
+       u32  platform_target_market_type : 2;
+       u32  super_sku                   : 1;
+       u32  reserved                    : 1;
+       u32  intel_me_fw_image_type      : 4;
+       u32  platform_brand              : 4;
+       u32  reserved_1                  : 16;
+}  __attribute__ ((packed)) platform_type_rule_data;
+
+typedef struct {
+       mefwcaps_sku fw_capabilities;
+       u8      available;
+} mbp_fw_caps;
+
+typedef struct {
+       u16        device_id;
+       u16        fuse_test_flags;
+       u32        umchid[4];
+}  __attribute__ ((packed)) mbp_rom_bist_data;
+
+typedef struct {
+       u32        key[8];
+} mbp_platform_key;
+
+typedef struct {
+       platform_type_rule_data rule_data;
+       u8                available;
+} mbp_plat_type;
+
+typedef struct {
+       mbp_fw_version_name fw_version_name;
+       mbp_fw_caps         fw_caps_sku;
+       mbp_rom_bist_data   rom_bist_data;
+       mbp_platform_key    platform_key;
+       mbp_plat_type       fw_plat_type;
+       mbp_icc_profile     icc_profile;
+       tdt_state_info      at_state;
+       u32                 mfsintegrity;
+} me_bios_payload;
+
+typedef  struct {
+       u32  mbp_size    : 8;
+       u32  num_entries : 8;
+       u32  rsvd        : 16;
+} __attribute__ ((packed)) mbp_header;
+
+typedef struct {
+       u32  app_id  : 8;
+       u32  item_id : 8;
+       u32  length  : 8;
+       u32  rsvd    : 8;
+}  __attribute__ ((packed)) mbp_item_header;
+
+struct me_fwcaps {
+       u32 id;
+       u8 length;
+       mefwcaps_sku caps_sku;
+       u8 reserved[3];
+} __attribute__ ((packed));
+
+#endif /* _INTEL_ME_H */
diff --git a/src/southbridge/intel/bd82x6x/me_8.x.c b/src/southbridge/intel/bd82x6x/me_8.x.c
new file mode 100644 (file)
index 0000000..1bb2ce3
--- /dev/null
@@ -0,0 +1,919 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+/*
+ * This is a ramstage driver for the Intel Management Engine found in the
+ * 6-series chipset.  It handles the required boot-time messages over the
+ * MMIO-based Management Engine Interface to tell the ME that the BIOS is
+ * finished with POST.  Additional messages are defined for debug but are
+ * not used unless the console loglevel is high enough.
+ */
+
+#include <arch/acpi.h>
+#include <arch/hlt.h>
+#include <arch/io.h>
+#include <console/console.h>
+#include <device/pci_ids.h>
+#include <device/pci_def.h>
+#include <string.h>
+#include <delay.h>
+
+#ifdef __SMM__
+# include <arch/romcc_io.h>
+# include <northbridge/intel/sandybridge/pcie_config.c>
+#else
+# include <device/device.h>
+# include <device/pci.h>
+#endif
+
+#include "me.h"
+#include "pch.h"
+
+#if CONFIG_CHROMEOS
+#include <vendorcode/google/chromeos/chromeos.h>
+#endif
+
+#ifndef __SMM__
+/* Path that the BIOS should take based on ME state */
+static const char *me_bios_path_values[] = {
+       [ME_NORMAL_BIOS_PATH]           = "Normal",
+       [ME_S3WAKE_BIOS_PATH]           = "S3 Wake",
+       [ME_ERROR_BIOS_PATH]            = "Error",
+       [ME_RECOVERY_BIOS_PATH]         = "Recovery",
+       [ME_DISABLE_BIOS_PATH]          = "Disable",
+       [ME_FIRMWARE_UPDATE_BIOS_PATH]  = "Firmware Update",
+};
+static int intel_me_read_mbp(me_bios_payload *mbp_data);
+#endif
+
+/* MMIO base address for MEI interface */
+static u32 mei_base_address;
+
+#if CONFIG_DEBUG_INTEL_ME
+static void mei_dump(void *ptr, int dword, int offset, const char *type)
+{
+       struct mei_csr *csr;
+
+       printk(BIOS_SPEW, "%-9s[%02x] : ", type, offset);
+
+       switch (offset) {
+       case MEI_H_CSR:
+       case MEI_ME_CSR_HA:
+               csr = ptr;
+               if (!csr) {
+                       printk(BIOS_SPEW, "ERROR: 0x%08x\n", dword);
+                       break;
+               }
+               printk(BIOS_SPEW, "cbd=%u cbrp=%02u cbwp=%02u ready=%u "
+                      "reset=%u ig=%u is=%u ie=%u\n", csr->buffer_depth,
+                      csr->buffer_read_ptr, csr->buffer_write_ptr,
+                      csr->ready, csr->reset, csr->interrupt_generate,
+                      csr->interrupt_status, csr->interrupt_enable);
+               break;
+       case MEI_ME_CB_RW:
+       case MEI_H_CB_WW:
+               printk(BIOS_SPEW, "CB: 0x%08x\n", dword);
+               break;
+       default:
+               printk(BIOS_SPEW, "0x%08x\n", offset);
+               break;
+       }
+}
+#else
+# define mei_dump(ptr,dword,offset,type) do {} while (0)
+#endif
+
+/*
+ * ME/MEI access helpers using memcpy to avoid aliasing.
+ */
+
+static inline void mei_read_dword_ptr(void *ptr, int offset)
+{
+       u32 dword = read32(mei_base_address + offset);
+       memcpy(ptr, &dword, sizeof(dword));
+       mei_dump(ptr, dword, offset, "READ");
+}
+
+static inline void mei_write_dword_ptr(void *ptr, int offset)
+{
+       u32 dword = 0;
+       memcpy(&dword, ptr, sizeof(dword));
+       write32(mei_base_address + offset, dword);
+       mei_dump(ptr, dword, offset, "WRITE");
+}
+
+#ifndef __SMM__
+static inline void pci_read_dword_ptr(device_t dev, void *ptr, int offset)
+{
+       u32 dword = pci_read_config32(dev, offset);
+       memcpy(ptr, &dword, sizeof(dword));
+       mei_dump(ptr, dword, offset, "PCI READ");
+}
+#endif
+
+static inline void read_host_csr(struct mei_csr *csr)
+{
+       mei_read_dword_ptr(csr, MEI_H_CSR);
+}
+
+static inline void write_host_csr(struct mei_csr *csr)
+{
+       mei_write_dword_ptr(csr, MEI_H_CSR);
+}
+
+static inline void read_me_csr(struct mei_csr *csr)
+{
+       mei_read_dword_ptr(csr, MEI_ME_CSR_HA);
+}
+
+static inline void write_cb(u32 dword)
+{
+       write32(mei_base_address + MEI_H_CB_WW, dword);
+       mei_dump(NULL, dword, MEI_H_CB_WW, "WRITE");
+}
+
+static inline u32 read_cb(void)
+{
+       u32 dword = read32(mei_base_address + MEI_ME_CB_RW);
+       mei_dump(NULL, dword, MEI_ME_CB_RW, "READ");
+       return dword;
+}
+
+/* Wait for ME ready bit to be asserted */
+static int mei_wait_for_me_ready(void)
+{
+       struct mei_csr me;
+       unsigned try = ME_RETRY;
+
+       while (try--) {
+               read_me_csr(&me);
+               if (me.ready)
+                       return 0;
+               udelay(ME_DELAY);
+       }
+
+       printk(BIOS_ERR, "ME: failed to become ready\n");
+       return -1;
+}
+
+static void mei_reset(void)
+{
+       struct mei_csr host;
+
+       if (mei_wait_for_me_ready() < 0)
+               return;
+
+       /* Reset host and ME circular buffers for next message */
+       read_host_csr(&host);
+       host.reset = 1;
+       host.interrupt_generate = 1;
+       write_host_csr(&host);
+
+       if (mei_wait_for_me_ready() < 0)
+               return;
+
+       /* Re-init and indicate host is ready */
+       read_host_csr(&host);
+       host.interrupt_generate = 1;
+       host.ready = 1;
+       host.reset = 0;
+       write_host_csr(&host);
+}
+
+static int mei_send_msg(struct mei_header *mei, struct mkhi_header *mkhi,
+                       void *req_data)
+{
+       struct mei_csr host;
+       unsigned ndata, n;
+       u32 *data;
+
+       /* Number of dwords to write, ignoring MKHI */
+       ndata = mei->length >> 2;
+
+       /* Pad non-dword aligned request message length */
+       if (mei->length & 3)
+               ndata++;
+       if (!ndata) {
+               printk(BIOS_DEBUG, "ME: request does not include MKHI\n");
+               return -1;
+       }
+       ndata++; /* Add MEI header */
+
+       /*
+        * Make sure there is still room left in the circular buffer.
+        * Reset the buffer pointers if the requested message will not fit.
+        */
+       read_host_csr(&host);
+       if ((host.buffer_depth - host.buffer_write_ptr) < ndata) {
+               printk(BIOS_ERR, "ME: circular buffer full, resetting...\n");
+               mei_reset();
+               read_host_csr(&host);
+       }
+
+       /*
+        * This implementation does not handle splitting large messages
+        * across multiple transactions.  Ensure the requested length
+        * will fit in the available circular buffer depth.
+        */
+       if ((host.buffer_depth - host.buffer_write_ptr) < ndata) {
+               printk(BIOS_ERR, "ME: message (%u) too large for buffer (%u)\n",
+                      ndata + 2, host.buffer_depth);
+               return -1;
+       }
+
+       /* Write MEI header */
+       mei_write_dword_ptr(mei, MEI_H_CB_WW);
+       ndata--;
+
+       /* Write MKHI header */
+       mei_write_dword_ptr(mkhi, MEI_H_CB_WW);
+       ndata--;
+
+       /* Write message data */
+       data = req_data;
+       for (n = 0; n < ndata; ++n)
+               write_cb(*data++);
+
+       /* Generate interrupt to the ME */
+       read_host_csr(&host);
+       host.interrupt_generate = 1;
+       write_host_csr(&host);
+
+       /* Make sure ME is ready after sending request data */
+       return mei_wait_for_me_ready();
+}
+
+static int mei_recv_msg(struct mkhi_header *mkhi,
+                       void *rsp_data, int rsp_bytes)
+{
+       struct mei_header mei_rsp;
+       struct mkhi_header mkhi_rsp;
+       struct mei_csr me, host;
+       unsigned ndata, n/*, me_data_len*/;
+       unsigned expected;
+       u32 *data;
+
+       /* Total number of dwords to read from circular buffer */
+       expected = (rsp_bytes + sizeof(mei_rsp) + sizeof(mkhi_rsp)) >> 2;
+       if (rsp_bytes & 3)
+               expected++;
+
+       /*
+        * The interrupt status bit does not appear to indicate that the
+        * message has actually been received.  Instead we wait until the
+        * expected number of dwords are present in the circular buffer.
+        */
+       for (n = ME_RETRY; n; --n) {
+               read_me_csr(&me);
+               if ((me.buffer_write_ptr - me.buffer_read_ptr) >= expected)
+                       break;
+               udelay(ME_DELAY);
+       }
+       if (!n) {
+               printk(BIOS_ERR, "ME: timeout waiting for data: expected "
+                      "%u, available %u\n", expected,
+                      me.buffer_write_ptr - me.buffer_read_ptr);
+               return -1;
+       }
+
+       /* Read and verify MEI response header from the ME */
+       mei_read_dword_ptr(&mei_rsp, MEI_ME_CB_RW);
+       if (!mei_rsp.is_complete) {
+               printk(BIOS_ERR, "ME: response is not complete\n");
+               return -1;
+       }
+
+       /* Handle non-dword responses and expect at least MKHI header */
+       ndata = mei_rsp.length >> 2;
+       if (mei_rsp.length & 3)
+               ndata++;
+       if (ndata != (expected - 1)) {
+               printk(BIOS_ERR, "ME: response is missing data %d != %d\n",
+                      ndata, (expected - 1));
+               return -1;
+       }
+
+       /* Read and verify MKHI response header from the ME */
+       mei_read_dword_ptr(&mkhi_rsp, MEI_ME_CB_RW);
+       if (!mkhi_rsp.is_response ||
+           mkhi->group_id != mkhi_rsp.group_id ||
+           mkhi->command != mkhi_rsp.command) {
+               printk(BIOS_ERR, "ME: invalid response, group %u ?= %u,"
+                      "command %u ?= %u, is_response %u\n", mkhi->group_id,
+                      mkhi_rsp.group_id, mkhi->command, mkhi_rsp.command,
+                      mkhi_rsp.is_response);
+               return -1;
+       }
+       ndata--; /* MKHI header has been read */
+
+       /* Make sure caller passed a buffer with enough space */
+       if (ndata != (rsp_bytes >> 2)) {
+               printk(BIOS_ERR, "ME: not enough room in response buffer: "
+                      "%u != %u\n", ndata, rsp_bytes >> 2);
+               return -1;
+       }
+
+       /* Read response data from the circular buffer */
+       data = rsp_data;
+       for (n = 0; n < ndata; ++n)
+               *data++ = read_cb();
+
+       /* Tell the ME that we have consumed the response */
+       read_host_csr(&host);
+       host.interrupt_status = 1;
+       host.interrupt_generate = 1;
+       write_host_csr(&host);
+
+       return mei_wait_for_me_ready();
+}
+
+static inline int mei_sendrecv(struct mei_header *mei, struct mkhi_header *mkhi,
+                              void *req_data, void *rsp_data, int rsp_bytes)
+{
+       if (mei_send_msg(mei, mkhi, req_data) < 0)
+               return -1;
+       if (mei_recv_msg(mkhi, rsp_data, rsp_bytes) < 0)
+               return -1;
+       return 0;
+}
+
+/* Send END OF POST message to the ME */
+int mkhi_end_of_post(void)
+{
+       struct mkhi_header mkhi = {
+               .group_id       = MKHI_GROUP_ID_GEN,
+               .command        = MKHI_END_OF_POST,
+       };
+       struct mei_header mei = {
+               .is_complete    = 1,
+               .host_address   = MEI_HOST_ADDRESS,
+               .client_address = MEI_ADDRESS_MKHI,
+               .length         = sizeof(mkhi),
+       };
+
+       u32 eop_ack;
+
+       /* Send request and wait for response */
+       printk(BIOS_NOTICE, "ME: %s\n", __FUNCTION__);
+       if (mei_sendrecv(&mei, &mkhi, NULL, &eop_ack, sizeof(eop_ack)) < 0) {
+               printk(BIOS_ERR, "ME: END OF POST message failed\n");
+               return -1;
+       }
+
+       printk(BIOS_INFO, "ME: END OF POST message successful (%d)\n", eop_ack);
+       return 0;
+}
+
+#if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG) && !defined(__SMM__)
+static inline void print_cap(const char *name, int state)
+{
+       printk(BIOS_DEBUG, "ME Capability: %-41s : %sabled\n",
+              name, state ? " en" : "dis");
+}
+
+static void me_print_fw_version(mbp_fw_version_name *vers_name)
+{
+       if (!vers_name->major_version) {
+               printk(BIOS_ERR, "ME: mbp missing version report\n");
+               return;
+       }
+
+       printk(BIOS_DEBUG, "ME: found version %d.%d.%d.%d\n",
+              vers_name->major_version, vers_name->minor_version,
+              vers_name->hotfix_version, vers_name->build_version);
+}
+
+/* Get ME Firmware Capabilities */
+static int mkhi_get_fwcaps(mefwcaps_sku *cap)
+{
+       u32 rule_id = 0;
+       struct me_fwcaps cap_msg;
+       struct mkhi_header mkhi = {
+               .group_id       = MKHI_GROUP_ID_FWCAPS,
+               .command        = MKHI_FWCAPS_GET_RULE,
+       };
+       struct mei_header mei = {
+               .is_complete    = 1,
+               .host_address   = MEI_HOST_ADDRESS,
+               .client_address = MEI_ADDRESS_MKHI,
+               .length         = sizeof(mkhi) + sizeof(rule_id),
+       };
+
+       /* Send request and wait for response */
+       if (mei_sendrecv(&mei, &mkhi, &rule_id, &cap_msg, sizeof(cap_msg))
+           < 0) {
+               printk(BIOS_ERR, "ME: GET FWCAPS message failed\n");
+               return -1;
+        }
+       *cap = cap_msg.caps_sku;
+       return 0;
+}
+
+/* Get ME Firmware Capabilities */
+static void me_print_fwcaps(mbp_fw_caps *caps_section)
+{
+       mefwcaps_sku *cap = &caps_section->fw_capabilities;
+       if (!caps_section->available) {
+               printk(BIOS_ERR, "ME: mbp missing fwcaps report\n");
+               if (mkhi_get_fwcaps(cap))
+                       return;
+       }
+
+       print_cap("Full Network manageability", cap->full_net);
+       print_cap("Regular Network manageability", cap->std_net);
+       print_cap("Manageability", cap->manageability);
+       print_cap("Small business technology", cap->small_business);
+       print_cap("Level III manageability", cap->l3manageability);
+       print_cap("IntelR Anti-Theft (AT)", cap->intel_at);
+       print_cap("IntelR Capability Licensing Service (CLS)", cap->intel_cls);
+       print_cap("IntelR Power Sharing Technology (MPC)", cap->intel_mpc);
+       print_cap("ICC Over Clocking", cap->icc_over_clocking);
+        print_cap("Protected Audio Video Path (PAVP)", cap->pavp);
+       print_cap("IPV6", cap->ipv6);
+       print_cap("KVM Remote Control (KVM)", cap->kvm);
+       print_cap("Outbreak Containment Heuristic (OCH)", cap->och);
+       print_cap("Virtual LAN (VLAN)", cap->vlan);
+       print_cap("TLS", cap->tls);
+       print_cap("Wireless LAN (WLAN)", cap->wlan);
+}
+#endif
+
+/* Tell ME to issue a global reset */
+int mkhi_global_reset(void)
+{
+       struct me_global_reset reset = {
+               .request_origin = GLOBAL_RESET_BIOS_POST,
+               .reset_type     = CBM_RR_GLOBAL_RESET,
+       };
+       struct mkhi_header mkhi = {
+               .group_id       = MKHI_GROUP_ID_CBM,
+               .command        = MKHI_GLOBAL_RESET,
+       };
+       struct mei_header mei = {
+               .is_complete    = 1,
+               .length         = sizeof(mkhi) + sizeof(reset),
+               .host_address   = MEI_HOST_ADDRESS,
+               .client_address = MEI_ADDRESS_MKHI,
+       };
+
+       /* Send request and wait for response */
+       printk(BIOS_NOTICE, "ME: %s\n", __FUNCTION__);
+       if (mei_sendrecv(&mei, &mkhi, &reset, NULL, 0) < 0) {
+               /* No response means reset will happen shortly... */
+               hlt();
+       }
+
+       /* If the ME responded it rejected the reset request */
+       printk(BIOS_ERR, "ME: Global Reset failed\n");
+       return -1;
+}
+
+#ifdef __SMM__
+
+void intel_me_finalize_smm(void)
+{
+       struct me_hfs hfs;
+       u32 reg32;
+
+       mei_base_address =
+               pcie_read_config32(PCH_ME_DEV, PCI_BASE_ADDRESS_0) & ~0xf;
+
+       /* S3 path will have hidden this device already */
+       if (!mei_base_address || mei_base_address == 0xfffffff0)
+               return;
+
+       /* Make sure ME is in a mode that expects EOP */
+       reg32 = pcie_read_config32(PCH_ME_DEV, PCI_ME_HFS);
+       memcpy(&hfs, &reg32, sizeof(u32));
+
+       /* Abort and leave device alone if not normal mode */
+       if (hfs.fpt_bad ||
+           hfs.working_state != ME_HFS_CWS_NORMAL ||
+           hfs.operation_mode != ME_HFS_MODE_NORMAL)
+               return;
+
+       /* Try to send EOP command so ME stops accepting other commands */
+       mkhi_end_of_post();
+
+       /* Make sure IO is disabled */
+       reg32 = pcie_read_config32(PCH_ME_DEV, PCI_COMMAND);
+       reg32 &= ~(PCI_COMMAND_MASTER |
+                  PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
+       pcie_write_config32(PCH_ME_DEV, PCI_COMMAND, reg32);
+
+       /* Hide the PCI device */
+       RCBA32_OR(FD2, PCH_DISABLE_MEI1);
+}
+
+#else /* !__SMM__ */
+
+/* Determine the path that we should take based on ME status */
+static me_bios_path intel_me_path(device_t dev)
+{
+       me_bios_path path = ME_DISABLE_BIOS_PATH;
+       struct me_hfs hfs;
+       struct me_gmes gmes;
+
+#if CONFIG_HAVE_ACPI_RESUME
+       /* S3 wake skips all MKHI messages */
+       if (acpi_slp_type == 3) {
+               return ME_S3WAKE_BIOS_PATH;
+       }
+#endif
+
+       pci_read_dword_ptr(dev, &hfs, PCI_ME_HFS);
+       pci_read_dword_ptr(dev, &gmes, PCI_ME_GMES);
+
+       /* Check and dump status */
+       intel_me_status(&hfs, &gmes);
+
+       /* Check for valid firmware */
+       if (hfs.fpt_bad)
+               return ME_ERROR_BIOS_PATH;
+
+       /* Check Current Working State */
+       switch (hfs.working_state) {
+       case ME_HFS_CWS_NORMAL:
+               path = ME_NORMAL_BIOS_PATH;
+               /* check if the MBP is ready */
+               if (!gmes.mbp_rdy) {
+                       printk(BIOS_CRIT, "%s: mbp is not ready!\n",
+                              __FUNCTION__);
+                       return ME_ERROR_BIOS_PATH;
+               }
+               break;
+       case ME_HFS_CWS_REC:
+               path = ME_RECOVERY_BIOS_PATH;
+               break;
+       default:
+               path = ME_DISABLE_BIOS_PATH;
+               break;
+       }
+
+       /* Check Current Operation Mode */
+       switch (hfs.operation_mode) {
+       case ME_HFS_MODE_NORMAL:
+               break;
+       case ME_HFS_MODE_DEBUG:
+       case ME_HFS_MODE_DIS:
+       case ME_HFS_MODE_OVER_JMPR:
+       case ME_HFS_MODE_OVER_MEI:
+       default:
+               path = ME_DISABLE_BIOS_PATH;
+               break;
+       }
+
+       /* Check for any error code */
+       if (hfs.error_code)
+               path = ME_ERROR_BIOS_PATH;
+
+       return path;
+}
+
+/* Prepare ME for MEI messages */
+static int intel_mei_setup(device_t dev)
+{
+       struct resource *res;
+       struct mei_csr host;
+       u32 reg32;
+
+       /* Find the MMIO base for the ME interface */
+       res = find_resource(dev, PCI_BASE_ADDRESS_0);
+       if (!res || res->base == 0 || res->size == 0) {
+               printk(BIOS_DEBUG, "ME: MEI resource not present!\n");
+               return -1;
+       }
+       mei_base_address = res->base;
+
+       /* Ensure Memory and Bus Master bits are set */
+       reg32 = pci_read_config32(dev, PCI_COMMAND);
+       reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+       pci_write_config32(dev, PCI_COMMAND, reg32);
+
+       /* Clean up status for next message */
+       read_host_csr(&host);
+       host.interrupt_generate = 1;
+       host.ready = 1;
+       host.reset = 0;
+       write_host_csr(&host);
+
+       return 0;
+}
+
+/* Read the Extend register hash of ME firmware */
+static int intel_me_extend_valid(device_t dev)
+{
+       struct me_heres status;
+       u32 extend;
+       int i, count = 0;
+
+       pci_read_dword_ptr(dev, &status, PCI_ME_HERES);
+       if (!status.extend_feature_present) {
+               printk(BIOS_ERR, "ME: Extend Feature not present\n");
+               return -1;
+       }
+
+       if (!status.extend_reg_valid) {
+               printk(BIOS_ERR, "ME: Extend Register not valid\n");
+               return -1;
+       }
+
+       switch (status.extend_reg_algorithm) {
+       case PCI_ME_EXT_SHA1:
+               count = 5;
+               printk(BIOS_DEBUG, "ME: Extend SHA-1: ");
+               break;
+       case PCI_ME_EXT_SHA256:
+               count = 8;
+               printk(BIOS_DEBUG, "ME: Extend SHA-256: ");
+               break;
+       default:
+               printk(BIOS_ERR, "ME: Extend Algorithm %d unknown\n",
+                      status.extend_reg_algorithm);
+               return -1;
+       }
+
+       /*
+        * TODO(dlaurie) Verify the hash against a saved good value.
+        */
+
+       for (i = 0; i < count; ++i) {
+               extend = pci_read_config32(dev, PCI_ME_HER(i));
+               printk(BIOS_DEBUG, "%08x", extend);
+       }
+       printk(BIOS_DEBUG, "\n");
+
+       return 0;
+}
+
+/* Hide the ME virtual PCI devices */
+static void intel_me_hide(device_t dev)
+{
+       dev->enabled = 0;
+       pch_enable(dev);
+}
+
+/* Check whether ME is present and do basic init */
+static void intel_me_init(device_t dev)
+{
+       me_bios_path path = intel_me_path(dev);
+       me_bios_payload mbp_data;
+
+       /* Do initial setup and determine the BIOS path */
+       printk(BIOS_NOTICE, "ME: BIOS path: %s\n", me_bios_path_values[path]);
+
+       switch (path) {
+       case ME_S3WAKE_BIOS_PATH:
+               intel_me_hide(dev);
+               break;
+
+       case ME_NORMAL_BIOS_PATH:
+               /* Validate the extend register */
+               if (intel_me_extend_valid(dev) < 0)
+                       break; /* TODO: force recovery mode */
+
+               /* Prepare MEI MMIO interface */
+               if (intel_mei_setup(dev) < 0)
+                       break;
+
+               if(intel_me_read_mbp(&mbp_data))
+                       break;
+
+#if CONFIG_CHROMEOS && 0 /* DISABLED */
+               /*
+                * Unlock ME in recovery mode.
+                */
+               if (recovery_mode_enabled()) {
+                       /* Unlock ME flash region */
+                       mkhi_hmrfpo_enable();
+
+                       /* Issue global reset */
+                       mkhi_global_reset();
+                       return;
+               }
+#endif
+
+#if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG)
+               me_print_fw_version(&mbp_data.fw_version_name);
+               me_print_fwcaps(&mbp_data.fw_caps_sku);
+#endif
+               /* Tell ME that BIOS is done */
+               mkhi_end_of_post();
+               /* Hide the virtual PCI device */
+               intel_me_hide(dev);
+               break;
+
+       case ME_ERROR_BIOS_PATH:
+       case ME_RECOVERY_BIOS_PATH:
+       case ME_DISABLE_BIOS_PATH:
+       case ME_FIRMWARE_UPDATE_BIOS_PATH:
+               /*
+                * TODO(dlaurie) Force recovery mode if ME is unhappy?
+                */
+               break;
+       }
+}
+
+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 struct pci_operations pci_ops = {
+       .set_subsystem = 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                   = intel_me_init,
+       .scan_bus               = scan_static_bus,
+       .ops_pci                = &pci_ops,
+};
+
+static const struct pci_driver intel_me __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1e3a,
+};
+
+/******************************************************************************
+ *                                                                          */
+static u32 me_to_host_words_pending(void)
+{
+       struct mei_csr me;
+       read_me_csr(&me);
+       if (!me.ready)
+               return 0;
+       return (me.buffer_write_ptr - me.buffer_read_ptr) &
+               (me.buffer_depth - 1);
+}
+
+#if 0
+/* This function is not yet being used, keep it in for the future. */
+static u32 host_to_me_words_room(void)
+{
+       struct mei_csr csr;
+
+       read_me_csr(&csr);
+       if (!csr.ready)
+               return 0;
+
+       read_host_csr(&csr);
+       return (csr.buffer_read_ptr - csr.buffer_write_ptr - 1) &
+               (csr.buffer_depth - 1);
+}
+#endif
+/*
+ * mbp seems to be following its own flow, let's retrieve it in a dedicated
+ * function.
+ */
+static int intel_me_read_mbp(me_bios_payload *mbp_data)
+{
+       mbp_header mbp_hdr;
+       mbp_item_header mbp_item_hdr;
+       u32 me2host_pending;
+       u32 mbp_item_id;
+       struct mei_csr host;
+
+       me2host_pending = me_to_host_words_pending();
+       if (!me2host_pending) {
+               printk(BIOS_ERR, "ME: no mbp data!\n");
+               return -1;
+       }
+
+       /* we know for sure that at least the header is there */
+       mei_read_dword_ptr(&mbp_hdr, MEI_ME_CB_RW);
+
+       if ((mbp_hdr.num_entries > (mbp_hdr.mbp_size / 2)) ||
+           (me2host_pending < mbp_hdr.mbp_size)) {
+               printk(BIOS_ERR, "ME: mbp of %d entries, total size %d words"
+                      " buffer contains %d words\n",
+                      mbp_hdr.num_entries, mbp_hdr.mbp_size,
+                      me2host_pending);
+               return -1;
+       }
+
+       me2host_pending--;
+       memset(mbp_data, 0, sizeof(*mbp_data));
+
+       while (mbp_hdr.num_entries--) {
+               u32* copy_addr;
+               u32 copy_size, buffer_room;
+               void *p;
+
+               if (!me2host_pending) {
+                       printk(BIOS_ERR, "ME: no mbp data %d entries to go!\n",
+                              mbp_hdr.num_entries + 1);
+                       return -1;
+               }
+
+               mei_read_dword_ptr(&mbp_item_hdr, MEI_ME_CB_RW);
+
+               if (mbp_item_hdr.length > me2host_pending) {
+                       printk(BIOS_ERR, "ME: insufficient mbp data %d "
+                              "entries to go!\n",
+                              mbp_hdr.num_entries + 1);
+                       return -1;
+               }
+
+               me2host_pending -= mbp_item_hdr.length;
+
+               mbp_item_id = (((u32)mbp_item_hdr.item_id) << 8) +
+                       mbp_item_hdr.app_id;
+
+               copy_size = mbp_item_hdr.length - 1;
+
+#define SET_UP_COPY(field) { copy_addr = (u32 *)&mbp_data->field;           \
+                       buffer_room = sizeof(mbp_data->field) / sizeof(u32); \
+                       break;                                               \
+               }
+
+               p = &mbp_item_hdr;
+               printk(BIOS_INFO, "ME: MBP item header %8.8x\n", *((u32*)p));
+
+               switch(mbp_item_id) {
+               case 0x101:
+                       SET_UP_COPY(fw_version_name);
+
+               case 0x102:
+                       SET_UP_COPY(icc_profile);
+
+               case 0x103:
+                       SET_UP_COPY(at_state);
+
+               case 0x201:
+                       mbp_data->fw_caps_sku.available = 1;
+                       SET_UP_COPY(fw_caps_sku.fw_capabilities);
+
+               case 0x301:
+                       SET_UP_COPY(rom_bist_data);
+
+               case 0x401:
+                       SET_UP_COPY(platform_key);
+
+               case 0x501:
+                       mbp_data->fw_plat_type.available = 1;
+                       SET_UP_COPY(fw_plat_type.rule_data);
+
+               case 0x601:
+                       SET_UP_COPY(mfsintegrity);
+
+               default:
+                       printk(BIOS_ERR, "ME: unknown mbp item id 0x%x!!!\n",
+                              mbp_item_id);
+                       return -1;
+               }
+
+               if (buffer_room != copy_size) {
+                       printk(BIOS_ERR, "ME: buffer room %d != %d copy size"
+                              " for item  0x%x!!!\n",
+                              buffer_room, copy_size, mbp_item_id);
+                       return -1;
+               }
+               while(copy_size--)
+                       *copy_addr++ = read_cb();
+       }
+
+       read_host_csr(&host);
+       host.interrupt_generate = 1;
+       write_host_csr(&host);
+
+       {
+               int cntr = 0;
+               while(host.interrupt_generate) {
+                       read_host_csr(&host);
+                       cntr++;
+               }
+               printk(BIOS_SPEW, "ME: mbp read OK after %d cycles\n", cntr);
+       }
+
+       return 0;
+}
+
+#endif /* !__SMM__ */
diff --git a/src/southbridge/intel/bd82x6x/me_status.c b/src/southbridge/intel/bd82x6x/me_status.c
new file mode 100644 (file)
index 0000000..b2f38d6
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <console/console.h>
+#include "me.h"
+
+#if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG)
+/* HFS1[3:0] Current Working State Values */
+static const char *me_cws_values[] = {
+       [ME_HFS_CWS_RESET]      = "Reset",
+       [ME_HFS_CWS_INIT]       = "Initializing",
+       [ME_HFS_CWS_REC]        = "Recovery",
+       [ME_HFS_CWS_NORMAL]     = "Normal",
+       [ME_HFS_CWS_WAIT]       = "Platform Disable Wait",
+       [ME_HFS_CWS_TRANS]      = "OP State Transition",
+       [ME_HFS_CWS_INVALID]    = "Invalid CPU Plugged In"
+};
+
+/* HFS1[8:6] Current Operation State Values */
+static const char *me_opstate_values[] = {
+       [ME_HFS_STATE_PREBOOT]  = "Preboot",
+       [ME_HFS_STATE_M0_UMA]   = "M0 with UMA",
+       [ME_HFS_STATE_M3]       = "M3 without UMA",
+       [ME_HFS_STATE_M0]       = "M0 without UMA",
+       [ME_HFS_STATE_BRINGUP]  = "Bring up",
+       [ME_HFS_STATE_ERROR]    = "M0 without UMA but with error"
+};
+
+/* HFS[19:16] Current Operation Mode Values */
+static const char *me_opmode_values[] = {
+       [ME_HFS_MODE_NORMAL]    = "Normal",
+       [ME_HFS_MODE_DEBUG]     = "Debug",
+       [ME_HFS_MODE_DIS]       = "Soft Temporary Disable",
+       [ME_HFS_MODE_OVER_JMPR] = "Security Override via Jumper",
+       [ME_HFS_MODE_OVER_MEI]  = "Security Override via MEI Message"
+};
+
+/* HFS[15:12] Error Code Values */
+static const char *me_error_values[] = {
+       [ME_HFS_ERROR_NONE]     = "No Error",
+       [ME_HFS_ERROR_UNCAT]    = "Uncategorized Failure",
+       [ME_HFS_ERROR_IMAGE]    = "Image Failure",
+       [ME_HFS_ERROR_DEBUG]    = "Debug Failure"
+};
+
+/* GMES[31:28] ME Progress Code */
+static const char *me_progress_values[] = {
+       [ME_GMES_PHASE_ROM]     = "ROM Phase",
+       [ME_GMES_PHASE_BUP]     = "BUP Phase",
+       [ME_GMES_PHASE_UKERNEL] = "uKernel Phase",
+       [ME_GMES_PHASE_POLICY]  = "Policy Module",
+       [ME_GMES_PHASE_MODULE]  = "Module Loading",
+       [ME_GMES_PHASE_UNKNOWN] = "Unknown",
+       [ME_GMES_PHASE_HOST]    = "Host Communication"
+};
+
+/* GMES[27:24] Power Management Event */
+static const char *me_pmevent_values[] = {
+       [0x00] = "Clean Moff->Mx wake",
+       [0x01] = "Moff->Mx wake after an error",
+       [0x02] = "Clean global reset",
+       [0x03] = "Global reset after an error",
+       [0x04] = "Clean Intel ME reset",
+       [0x05] = "Intel ME reset due to exception",
+       [0x06] = "Pseudo-global reset",
+       [0x07] = "S0/M0->Sx/M3",
+       [0x08] = "Sx/M3->S0/M0",
+       [0x09] = "Non-power cycle reset",
+       [0x0a] = "Power cycle reset through M3",
+       [0x0b] = "Power cycle reset through Moff",
+       [0x0c] = "Sx/Mx->Sx/Moff"
+};
+
+/* Progress Code 0 states */
+static const char *me_progress_rom_values[] = {
+       [0x00] = "BEGIN",
+       [0x06] = "DISABLE"
+};
+
+/* Progress Code 1 states */
+static const char *me_progress_bup_values[] = {
+       [0x00] = "Initialization starts",
+       [0x01] = "Disable the host wake event",
+       [0x04] = "Flow determination start process",
+       [0x08] = "Error reading/matching the VSCC table in the descriptor",
+       [0x0a] = "Check to see if straps say ME DISABLED",
+       [0x0b] = "Timeout waiting for PWROK",
+       [0x0d] = "Possibly handle BUP manufacturing override strap",
+       [0x11] = "Bringup in M3",
+       [0x12] = "Bringup in M0",
+       [0x13] = "Flow detection error",
+       [0x15] = "M3 clock switching error",
+       [0x18] = "M3 kernel load",
+       [0x1c] = "T34 missing - cannot program ICC",
+       [0x1f] = "Waiting for DID BIOS message",
+       [0x20] = "Waiting for DID BIOS message failure",
+       [0x21] = "DID reported an error",
+       [0x22] = "Enabling UMA",
+       [0x23] = "Enabling UMA error",
+       [0x24] = "Sending DID Ack to BIOS",
+       [0x25] = "Sending DID Ack to BIOS error",
+       [0x26] = "Switching clocks in M0",
+       [0x27] = "Switching clocks in M0 error",
+       [0x28] = "ME in temp disable",
+       [0x32] = "M0 kernel load",
+};
+
+/* Progress Code 3 states */
+static const char *me_progress_policy_values[] = {
+       [0x00] = "Entery into Policy Module",
+       [0x03] = "Received S3 entry",
+       [0x04] = "Received S4 entry",
+       [0x05] = "Received S5 entry",
+       [0x06] = "Received UPD entry",
+       [0x07] = "Received PCR entry",
+       [0x08] = "Received NPCR entry",
+       [0x09] = "Received host wake",
+       [0x0a] = "Received AC<>DC switch",
+       [0x0b] = "Received DRAM Init Done",
+       [0x0c] = "VSCC Data not found for flash device",
+       [0x0d] = "VSCC Table is not valid",
+       [0x0e] = "Flash Partition Boundary is outside address space",
+       [0x0f] = "ME cannot access the chipset descriptor region",
+       [0x10] = "Required VSCC values for flash parts do not match",
+};
+#endif
+
+void intel_me_status(struct me_hfs *hfs, struct me_gmes *gmes)
+{
+#if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG)
+       /* Check Current States */
+       printk(BIOS_DEBUG, "ME: FW Partition Table      : %s\n",
+              hfs->fpt_bad ? "BAD" : "OK");
+       printk(BIOS_DEBUG, "ME: Bringup Loader Failure  : %s\n",
+              hfs->ft_bup_ld_flr ? "YES" : "NO");
+       printk(BIOS_DEBUG, "ME: Firmware Init Complete  : %s\n",
+              hfs->fw_init_complete ? "YES" : "NO");
+       printk(BIOS_DEBUG, "ME: Manufacturing Mode      : %s\n",
+              hfs->mfg_mode ? "YES" : "NO");
+       printk(BIOS_DEBUG, "ME: Boot Options Present    : %s\n",
+              hfs->boot_options_present ? "YES" : "NO");
+       printk(BIOS_DEBUG, "ME: Update In Progress      : %s\n",
+              hfs->update_in_progress ? "YES" : "NO");
+       printk(BIOS_DEBUG, "ME: Current Working State   : %s\n",
+              me_cws_values[hfs->working_state]);
+       printk(BIOS_DEBUG, "ME: Current Operation State : %s\n",
+              me_opstate_values[hfs->operation_state]);
+       printk(BIOS_DEBUG, "ME: Current Operation Mode  : %s\n",
+              me_opmode_values[hfs->operation_mode]);
+       printk(BIOS_DEBUG, "ME: Error Code              : %s\n",
+              me_error_values[hfs->error_code]);
+       printk(BIOS_DEBUG, "ME: Progress Phase          : %s\n",
+              me_progress_values[gmes->progress_code]);
+       printk(BIOS_DEBUG, "ME: Power Management Event  : %s\n",
+              me_pmevent_values[gmes->current_pmevent]);
+
+       printk(BIOS_DEBUG, "ME: Progress Phase State    : ");
+       switch (gmes->progress_code) {
+       case ME_GMES_PHASE_ROM:         /* ROM Phase */
+               printk(BIOS_DEBUG, "%s",
+                      me_progress_rom_values[gmes->current_state]);
+               break;
+
+       case ME_GMES_PHASE_BUP:         /* Bringup Phase */
+               if (gmes->current_state < ARRAY_SIZE(me_progress_bup_values)
+                   && me_progress_bup_values[gmes->current_state])
+                       printk(BIOS_DEBUG, "%s",
+                              me_progress_bup_values[gmes->current_state]);
+               else
+                       printk(BIOS_DEBUG, "0x%02x", gmes->current_state);
+               break;
+
+       case ME_GMES_PHASE_POLICY:      /* Policy Module Phase */
+               if (gmes->current_state < ARRAY_SIZE(me_progress_policy_values)
+                   && me_progress_policy_values[gmes->current_state])
+                       printk(BIOS_DEBUG, "%s",
+                              me_progress_policy_values[gmes->current_state]);
+               else
+                       printk(BIOS_DEBUG, "0x%02x", gmes->current_state);
+               break;
+
+       case ME_GMES_PHASE_HOST:        /* Host Communication Phase */
+               if (!gmes->current_state)
+                       printk(BIOS_DEBUG, "Host communication established");
+               else
+                       printk(BIOS_DEBUG, "0x%02x", gmes->current_state);
+               break;
+
+       default:
+               printk(BIOS_DEBUG, "Unknown 0x%02x", gmes->current_state);
+       }
+       printk(BIOS_DEBUG, "\n");
+#endif
+}
diff --git a/src/southbridge/intel/bd82x6x/nvs.h b/src/southbridge/intel/bd82x6x/nvs.h
new file mode 100644 (file)
index 0000000..3928804
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008-2009 coresystems GmbH
+ * Copyright (C) 2011 Google Inc
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "vendorcode/google/chromeos/gnvs.h"
+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) */
+       /* Thermal policy */
+       u8      tlvl; /* 0x11 - Throttle Level Limit */
+       u8      flvl; /* 0x12 - Current FAN Level */
+       u8      tcrt; /* 0x13 - Critical Threshold */
+       u8      tpsv; /* 0x14 - Passive Threshold */
+       u8      tmax; /* 0x15 - CPU Tj_max */
+       u8      f0of; /* 0x16 - FAN 0 OFF Threshold */
+       u8      f0on; /* 0x17 - FAN 0 ON Threshold */
+       u8      f0pw; /* 0x18 - FAN 0 PWM value */
+       u8      f1of; /* 0x19 - FAN 1 OFF Threshold */
+       u8      f1on; /* 0x1a - FAN 1 ON Threshold */
+       u8      f1pw; /* 0x1b - FAN 1 PWM value */
+       u8      f2of; /* 0x1c - FAN 2 OFF Threshold */
+       u8      f2on; /* 0x1d - FAN 2 ON Threshold */
+       u8      f2pw; /* 0x1e - FAN 2 PWM value */
+       u8      f3of; /* 0x1f - FAN 3 OFF Threshold */
+       u8      f3on; /* 0x20 - FAN 3 ON Threshold */
+       u8      f3pw; /* 0x21 - FAN 3 PWM value */
+       u8      f4of; /* 0x22 - FAN 4 OFF Threshold */
+       u8      f4on; /* 0x23 - FAN 4 ON Threshold */
+       u8      f4pw; /* 0x24 - FAN 4 PWM value */
+       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      pcnt; /* 0x2d - Processor Count */
+       u8      rsvd4[4];
+       /* Super I/O & CMOS config */
+       u8      natp; /* 0x32 - SIO type */
+       u8      s5u0; /* 0x33 - Enable USB0 in S5 */
+       u8      s5u1; /* 0x34 - Enable USB1 in S5 */
+       u8      s3u0; /* 0x35 - Enable USB0 in S3 */
+       u8      s3u1; /* 0x36 - Enable USB1 in S3 */
+       u8      s33g; /* 0x37 - Enable S3 in 3G */
+       u32     cmem; /* 0x38 - CBMEM TOC */
+       /* 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];
+       /* ChromeOS specific (starts at 0xf0)*/
+       chromeos_acpi_t chromeos;
+} __attribute__((packed)) global_nvs_t;
+
diff --git a/src/southbridge/intel/bd82x6x/pch.c b/src/southbridge/intel/bd82x6x/pch.c
new file mode 100644 (file)
index 0000000..e83c2e6
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <console/console.h>
+#include <delay.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include "pch.h"
+
+static int pch_revision_id = -1;
+
+int pch_silicon_revision(void)
+{
+       if (pch_revision_id < 0)
+               pch_revision_id = pci_read_config8(
+                       dev_find_slot(0, PCI_DEVFN(0x1f, 0)),
+                       PCI_REVISION_ID);
+       return pch_revision_id;
+}
+
+/* Set bit in Function Disble register to hide this device */
+static void pch_hide_devfn(unsigned devfn)
+{
+       switch (devfn) {
+       case PCI_DEVFN(22, 0): /* MEI #1 */
+               RCBA32_OR(FD2, PCH_DISABLE_MEI1);
+               break;
+       case PCI_DEVFN(22, 1): /* MEI #2 */
+               RCBA32_OR(FD2, PCH_DISABLE_MEI2);
+               break;
+       case PCI_DEVFN(22, 2): /* IDE-R */
+               RCBA32_OR(FD2, PCH_DISABLE_IDER);
+               break;
+       case PCI_DEVFN(22, 3): /* KT */
+               RCBA32_OR(FD2, PCH_DISABLE_KT);
+               break;
+       case PCI_DEVFN(25, 0): /* Gigabit Ethernet */
+               RCBA32_OR(BUC, PCH_DISABLE_GBE);
+               break;
+       case PCI_DEVFN(26, 0): /* EHCI #2 */
+               RCBA32_OR(FD, PCH_DISABLE_EHCI2);
+               break;
+       case PCI_DEVFN(27, 0): /* HD Audio Controller */
+               RCBA32_OR(FD, PCH_DISABLE_HD_AUDIO);
+               break;
+       case PCI_DEVFN(28, 0): /* PCI Express Root Port 1 */
+       case PCI_DEVFN(28, 1): /* PCI Express Root Port 2 */
+       case PCI_DEVFN(28, 2): /* PCI Express Root Port 3 */
+       case PCI_DEVFN(28, 3): /* PCI Express Root Port 4 */
+       case PCI_DEVFN(28, 4): /* PCI Express Root Port 5 */
+       case PCI_DEVFN(28, 5): /* PCI Express Root Port 6 */
+       case PCI_DEVFN(28, 6): /* PCI Express Root Port 7 */
+       case PCI_DEVFN(28, 7): /* PCI Express Root Port 8 */
+               RCBA32_OR(FD, PCH_DISABLE_PCIE(PCI_FUNC(devfn)));
+               break;
+       case PCI_DEVFN(29, 0): /* EHCI #1 */
+               RCBA32_OR(FD, PCH_DISABLE_EHCI1);
+               break;
+       case PCI_DEVFN(30, 0): /* PCI-to-PCI Bridge */
+               RCBA32_OR(FD, PCH_DISABLE_P2P);
+               break;
+       case PCI_DEVFN(31, 0): /* LPC */
+               RCBA32_OR(FD, PCH_DISABLE_LPC);
+               break;
+       case PCI_DEVFN(31, 2): /* SATA #1 */
+               RCBA32_OR(FD, PCH_DISABLE_SATA1);
+               break;
+       case PCI_DEVFN(31, 3): /* SMBUS */
+               RCBA32_OR(FD, PCH_DISABLE_SMBUS);
+               break;
+       case PCI_DEVFN(31, 5): /* SATA #22 */
+               RCBA32_OR(FD, PCH_DISABLE_SATA2);
+               break;
+       case PCI_DEVFN(31, 6): /* Thermal Subsystem */
+               RCBA32_OR(FD, PCH_DISABLE_THERMAL);
+               break;
+       }
+}
+
+#define IOBP_RETRY 1000
+static inline int iobp_poll(void)
+{
+       unsigned try = IOBP_RETRY;
+       u32 data;
+
+       while (try--) {
+               data = RCBA32(IOBPS);
+               if ((data & 1) == 0)
+                       return 1;
+               udelay(10);
+       }
+
+       printk(BIOS_ERR, "IOBP timeout\n");
+       return 0;
+}
+
+void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
+{
+       u32 data;
+
+       /* Set the address */
+       RCBA32(IOBPIRI) = address;
+
+       /* READ OPCODE */
+       if (pch_silicon_revision() >= PCH_STEP_B0)
+               RCBA32(IOBPS) = IOBPS_RW_BX;
+       else
+               RCBA32(IOBPS) = IOBPS_READ_AX;
+       if (!iobp_poll())
+               return;
+
+       /* Read IOBP data */
+       data = RCBA32(IOBPD);
+       if (!iobp_poll())
+               return;
+
+       /* Check for successful transaction */
+       if ((RCBA32(IOBPS) & 0x6) != 0) {
+               printk(BIOS_ERR, "IOBP read 0x%08x failed\n", address);
+               return;
+       }
+
+       /* Update the data */
+       data &= andvalue;
+       data |= orvalue;
+
+       /* WRITE OPCODE */
+       if (pch_silicon_revision() >= PCH_STEP_B0)
+               RCBA32(IOBPS) = IOBPS_RW_BX;
+       else
+               RCBA32(IOBPS) = IOBPS_WRITE_AX;
+       if (!iobp_poll())
+               return;
+
+       /* Write IOBP data */
+       RCBA32(IOBPD) = data;
+       if (!iobp_poll())
+               return;
+}
+
+/* Check if any port in set X to X+3 is enabled */
+static int pch_pcie_check_set_enabled(device_t dev)
+{
+       device_t port;
+       int port_func;
+       int dev_func = PCI_FUNC(dev->path.pci.devfn);
+
+       printk(BIOS_DEBUG, "%s: check set enabled\n", dev_path(dev));
+
+       /* Go through static device tree list of devices
+        * because enumeration is still in progress */
+       for (port = all_devices; port; port = port->next) {
+               /* Only care about PCIe root ports */
+               if (PCI_SLOT(port->path.pci.devfn) !=
+                   PCI_SLOT(dev->path.pci.devfn))
+                       continue;
+
+               /* Check if port is in range and enabled */
+               port_func = PCI_FUNC(port->path.pci.devfn);
+               if (port_func >= dev_func &&
+                   port_func < (dev_func + 4) &&
+                   port->enabled)
+                       return 1;
+       }
+
+       /* None of the ports in this set are enabled */
+       return 0;
+}
+
+void pch_enable(device_t dev)
+{
+       u32 reg32;
+
+       if (!dev->enabled) {
+               printk(BIOS_DEBUG, "%s: Disabling device\n",  dev_path(dev));
+
+               /*
+                * PCIE Power Savings for stepping B1+:
+                *
+                * If PCIe 0-3 disabled set Function 0 0xE2[0] = 1
+                * If PCIe 4-7 disabled set Function 4 0xE2[0] = 1
+                *
+                * This check is done here instead of pcie driver
+                * because the pcie driver enable() handler is not
+                * called unless the device is enabled.
+                */
+               if (pch_silicon_revision() >= PCH_STEP_B1 &&
+                   PCI_SLOT(dev->path.pci.devfn) == PCH_PCIE_DEV_SLOT &&
+                   (PCI_FUNC(dev->path.pci.devfn) == 0 ||
+                    PCI_FUNC(dev->path.pci.devfn) == 4)) {
+                       if (!pch_pcie_check_set_enabled(dev)) {
+                               u8 reg8 = pci_read_config8(dev, 0xe2);
+                               reg8 |= 1;
+                               pci_write_config8(dev, 0xe2, reg8);
+                       }
+               }
+
+               /* Ensure memory, io, and bus master are all disabled */
+               reg32 = pci_read_config32(dev, PCI_COMMAND);
+               reg32 &= ~(PCI_COMMAND_MASTER |
+                          PCI_COMMAND_MEMORY | PCI_COMMAND_IO  );
+               pci_write_config32(dev, PCI_COMMAND, reg32);
+
+               /* Hide this device if possible */
+               pch_hide_devfn(dev->path.pci.devfn);
+       } else {
+               /* Enable SERR */
+               reg32 = pci_read_config32(dev, PCI_COMMAND);
+               reg32 |= PCI_COMMAND_SERR;
+               pci_write_config32(dev, PCI_COMMAND, reg32);
+       }
+}
+
+struct chip_operations southbridge_intel_bd82x6x_ops = {
+       CHIP_NAME("Intel Series 6 (" CONFIG_PCH_CHIP_NAME ") Southbridge")
+       .enable_dev = pch_enable,
+};
diff --git a/src/southbridge/intel/bd82x6x/pch.h b/src/southbridge/intel/bd82x6x/pch.h
new file mode 100644 (file)
index 0000000..80b09e2
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008-2009 coresystems GmbH
+ * Copyright (C) 2011 Google Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef SOUTHBRIDGE_INTEL_BD82X6X_PCH_H
+#define SOUTHBRIDGE_INTEL_BD82X6X_PCH_H
+
+/* PCH stepping values for LPC device */
+#define PCH_STEP_A0    0
+#define PCH_STEP_A1    1
+#define PCH_STEP_B0    2
+#define PCH_STEP_B1    3
+#define PCH_STEP_B2    4
+#define PCH_STEP_B3    5
+
+/*
+ * It does not matter where we put the SMBus I/O base, as long as we
+ * keep it consistent and don't interfere with other devices.  Stage2
+ * will relocate this anyways.
+ * Our solution is to have SMB initialization move the I/O to SMBUS_IO_BASE
+ * again. But handling static BARs is a generic problem that should be
+ * solved in the device allocator.
+ */
+#define SMBUS_IO_BASE          0x0400
+#define SMBUS_SLAVE_ADDR       0x24
+/* TODO Make sure these don't get changed by stage2 */
+#define DEFAULT_GPIOBASE       0x0480
+#define DEFAULT_PMBASE         0x0500
+
+#define HPET_ADDR              0xfed00000
+#define DEFAULT_RCBA           0xfed1c000
+
+#ifndef __ACPI__
+#define DEBUG_PERIODIC_SMIS 0
+
+#if defined (__SMM__) && !defined(__ASSEMBLER__)
+void intel_pch_finalize_smm(void);
+#endif
+
+#if !defined(__ASSEMBLER__) && !defined(__ROMCC__)
+#if !defined(__PRE_RAM__) && !defined(__SMM__)
+#include "chip.h"
+int pch_silicon_revision(void);
+void pch_enable(device_t dev);
+void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue);
+#else
+void enable_smbus(void);
+void enable_usb_bar(void);
+int smbus_read_byte(unsigned device, unsigned address);
+#endif
+#endif
+
+#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
+
+/* PCI Configuration Space (D30:F0): PCI2PCI */
+#define PSTS   0x06
+#define SMLT   0x1b
+#define SECSTS 0x1e
+#define INTR   0x3c
+#define BCTRL  0x3e
+#define   SBR  (1 << 6)
+#define   SEE  (1 << 1)
+#define   PERE (1 << 0)
+
+#define PCH_EHCI1_DEV          PCI_DEV(0, 0x1d, 0)
+#define PCH_EHCI2_DEV          PCI_DEV(0, 0x1a, 0)
+#define PCH_ME_DEV             PCI_DEV(0, 0x16, 0)
+#define PCH_PCIE_DEV_SLOT      28
+
+/* PCI Configuration Space (D31:F0): LPC */
+#define PCH_LPC_DEV            PCI_DEV(0, 0x1f, 0)
+#define SERIRQ_CNTL            0x64
+
+#define GEN_PMCON_1            0xa0
+#define GEN_PMCON_2            0xa2
+#define GEN_PMCON_3            0xa4
+#define ETR3                   0xac
+#define  ETR3_CWORWRE          (1 << 18)
+#define  ETR3_CF9GR            (1 << 20)
+
+/* GEN_PMCON_3 bits */
+#define RTC_BATTERY_DEAD       (1 << 2)
+#define RTC_POWER_FAILED       (1 << 1)
+#define SLEEP_AFTER_POWER_FAIL (1 << 0)
+
+#define PMBASE                 0x40
+#define ACPI_CNTL              0x44
+#define BIOS_CNTL              0xDC
+#define GPIO_BASE              0x48 /* LPC GPIO Base Address Register */
+#define GPIO_CNTL              0x4C /* LPC GPIO Control Register */
+#define GPIO_ROUT              0xb8
+
+#define PIRQA_ROUT             0x60
+#define PIRQB_ROUT             0x61
+#define PIRQC_ROUT             0x62
+#define PIRQD_ROUT             0x63
+#define PIRQE_ROUT             0x68
+#define PIRQF_ROUT             0x69
+#define PIRQG_ROUT             0x6A
+#define PIRQH_ROUT             0x6B
+
+#define LPC_IO_DEC             0x80 /* IO Decode Ranges Register */
+#define LPC_EN                 0x82 /* LPC IF Enables Register */
+#define  CNF2_LPC_EN           (1 << 13) /* 0x4e/0x4f */
+#define  CNF1_LPC_EN           (1 << 12) /* 0x2e/0x2f */
+#define  MC_LPC_EN             (1 << 11) /* 0x62/0x66 */
+#define  KBC_LPC_EN            (1 << 10) /* 0x60/0x64 */
+#define  GAMEH_LPC_EN          (1 << 9)  /* 0x208/0x20f */
+#define  GAMEL_LPC_EN          (1 << 8)  /* 0x200/0x207 */
+#define  FDD_LPC_EN            (1 << 3)  /* LPC_IO_DEC[12] */
+#define  LPT_LPC_EN            (1 << 2)  /* LPC_IO_DEC[9:8] */
+#define  COMB_LPC_EN           (1 << 1)  /* LPC_IO_DEC[6:4] */
+#define  COMA_LPC_EN           (1 << 0)  /* LPC_IO_DEC[3:2] */
+#define LPC_GEN1_DEC           0x84 /* LPC IF Generic Decode Range 1 */
+#define LPC_GEN2_DEC           0x88 /* LPC IF Generic Decode Range 2 */
+#define LPC_GEN3_DEC           0x8c /* LPC IF Generic Decode Range 3 */
+#define LPC_GEN4_DEC           0x90 /* LPC IF Generic Decode Range 4 */
+
+/* PCI Configuration Space (D31:F1): IDE */
+#define PCH_IDE_DEV            PCI_DEV(0, 0x1f, 1)
+#define PCH_SATA_DEV           PCI_DEV(0, 0x1f, 2)
+#define PCH_SATA2_DEV          PCI_DEV(0, 0x1f, 5)
+#define INTR_LN                        0x3c
+#define IDE_TIM_PRI            0x40    /* IDE timings, primary */
+#define   IDE_DECODE_ENABLE    (1 << 15)
+#define   IDE_SITRE            (1 << 14)
+#define   IDE_ISP_5_CLOCKS     (0 << 12)
+#define   IDE_ISP_4_CLOCKS     (1 << 12)
+#define   IDE_ISP_3_CLOCKS     (2 << 12)
+#define   IDE_RCT_4_CLOCKS     (0 <<  8)
+#define   IDE_RCT_3_CLOCKS     (1 <<  8)
+#define   IDE_RCT_2_CLOCKS     (2 <<  8)
+#define   IDE_RCT_1_CLOCKS     (3 <<  8)
+#define   IDE_DTE1             (1 <<  7)
+#define   IDE_PPE1             (1 <<  6)
+#define   IDE_IE1              (1 <<  5)
+#define   IDE_TIME1            (1 <<  4)
+#define   IDE_DTE0             (1 <<  3)
+#define   IDE_PPE0             (1 <<  2)
+#define   IDE_IE0              (1 <<  1)
+#define   IDE_TIME0            (1 <<  0)
+#define IDE_TIM_SEC            0x42    /* IDE timings, secondary */
+
+#define IDE_SDMA_CNT           0x48    /* Synchronous DMA control */
+#define   IDE_SSDE1            (1 <<  3)
+#define   IDE_SSDE0            (1 <<  2)
+#define   IDE_PSDE1            (1 <<  1)
+#define   IDE_PSDE0            (1 <<  0)
+
+#define IDE_SDMA_TIM           0x4a
+
+#define IDE_CONFIG             0x54    /* IDE I/O Configuration Register */
+#define   SIG_MODE_SEC_NORMAL  (0 << 18)
+#define   SIG_MODE_SEC_TRISTATE        (1 << 18)
+#define   SIG_MODE_SEC_DRIVELOW        (2 << 18)
+#define   SIG_MODE_PRI_NORMAL  (0 << 16)
+#define   SIG_MODE_PRI_TRISTATE        (1 << 16)
+#define   SIG_MODE_PRI_DRIVELOW        (2 << 16)
+#define   FAST_SCB1            (1 << 15)
+#define   FAST_SCB0            (1 << 14)
+#define   FAST_PCB1            (1 << 13)
+#define   FAST_PCB0            (1 << 12)
+#define   SCB1                 (1 <<  3)
+#define   SCB0                 (1 <<  2)
+#define   PCB1                 (1 <<  1)
+#define   PCB0                 (1 <<  0)
+
+#define SATA_SP                        0xd0 /* Scratchpad */
+
+/* PCI Configuration Space (D31:F3): SMBus */
+#define PCH_SMBUS_DEV          PCI_DEV(0, 0x1f, 3)
+#define SMB_BASE               0x20
+#define HOSTC                  0x40
+#define SMB_RCV_SLVA           0x09
+
+/* 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)
+
+
+/* Southbridge IO BARs */
+
+#define GPIOBASE               0x48
+
+#define PMBASE         0x40
+
+/* Root Complex Register Block */
+#define RCBA           0xf0
+
+#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_AND_OR(bits, x, and, or) \
+        RCBA##bits(x) = ((RCBA##bits(x) & (and)) | (or))
+#define RCBA8_AND_OR(x, and, or)  RCBA_AND_OR(8, x, and, or)
+#define RCBA16_AND_OR(x, and, or) RCBA_AND_OR(16, x, and, or)
+#define RCBA32_AND_OR(x, and, or) RCBA_AND_OR(32, x, and, or)
+#define RCBA32_OR(x, or) RCBA_AND_OR(32, x, ~0UL, or)
+
+#define VCH            0x0000  /* 32bit */
+#define VCAP1          0x0004  /* 32bit */
+#define VCAP2          0x0008  /* 32bit */
+#define PVC            0x000c  /* 16bit */
+#define PVS            0x000e  /* 16bit */
+
+#define V0CAP          0x0010  /* 32bit */
+#define V0CTL          0x0014  /* 32bit */
+#define V0STS          0x001a  /* 16bit */
+
+#define V1CAP          0x001c  /* 32bit */
+#define V1CTL          0x0020  /* 32bit */
+#define V1STS          0x0026  /* 16bit */
+
+#define RCTCL          0x0100  /* 32bit */
+#define ESD            0x0104  /* 32bit */
+#define ULD            0x0110  /* 32bit */
+#define ULBA           0x0118  /* 64bit */
+
+#define RP1D           0x0120  /* 32bit */
+#define RP1BA          0x0128  /* 64bit */
+#define RP2D           0x0130  /* 32bit */
+#define RP2BA          0x0138  /* 64bit */
+#define RP3D           0x0140  /* 32bit */
+#define RP3BA          0x0148  /* 64bit */
+#define RP4D           0x0150  /* 32bit */
+#define RP4BA          0x0158  /* 64bit */
+#define HDD            0x0160  /* 32bit */
+#define HDBA           0x0168  /* 64bit */
+#define RP5D           0x0170  /* 32bit */
+#define RP5BA          0x0178  /* 64bit */
+#define RP6D           0x0180  /* 32bit */
+#define RP6BA          0x0188  /* 64bit */
+
+#define RPC            0x0224  /* 32bit */
+#define RPFN           0x0238  /* 32bit */
+
+#define TRSR           0x1e00  /*  8bit */
+#define TRCR           0x1e10  /* 64bit */
+#define TWDR           0x1e18  /* 64bit */
+
+#define IOTR0          0x1e80  /* 64bit */
+#define IOTR1          0x1e88  /* 64bit */
+#define IOTR2          0x1e90  /* 64bit */
+#define IOTR3          0x1e98  /* 64bit */
+
+#define TCTL           0x3000  /*  8bit */
+
+#define NOINT          0
+#define INTA           1
+#define INTB           2
+#define INTC           3
+#define INTD           4
+
+#define DIR_IDR                12      /* Interrupt D Pin Offset */
+#define DIR_ICR                8       /* Interrupt C Pin Offset */
+#define DIR_IBR                4       /* Interrupt B Pin Offset */
+#define DIR_IAR                0       /* Interrupt A Pin Offset */
+
+#define PIRQA          0
+#define PIRQB          1
+#define PIRQC          2
+#define PIRQD          3
+#define PIRQE          4
+#define PIRQF          5
+#define PIRQG          6
+#define PIRQH          7
+
+/* IO Buffer Programming */
+#define IOBPIRI                0x2330
+#define IOBPD          0x2334
+#define IOBPS          0x2338
+#define  IOBPS_RW_BX    ((1 << 9)|(1 << 10))
+#define  IOBPS_WRITE_AX        ((1 << 9)|(1 << 10))
+#define  IOBPS_READ_AX ((1 << 8)|(1 << 9)|(1 << 10))
+
+#define D31IP          0x3100  /* 32bit */
+#define D31IP_TTIP     24      /* Thermal Throttle Pin */
+#define D31IP_SIP2     20      /* SATA Pin 2 */
+#define D31IP_SMIP     12      /* SMBUS Pin */
+#define D31IP_SIP      8       /* SATA Pin */
+#define D30IP          0x3104  /* 32bit */
+#define D30IP_PIP      0       /* PCI Bridge Pin */
+#define D29IP          0x3108  /* 32bit */
+#define D29IP_E1P      0       /* EHCI #1 Pin */
+#define D28IP          0x310c  /* 32bit */
+#define D28IP_P8IP     28      /* PCI Express Port 8 */
+#define D28IP_P7IP     24      /* PCI Express Port 7 */
+#define D28IP_P6IP     20      /* PCI Express Port 6 */
+#define D28IP_P5IP     16      /* PCI Express Port 5 */
+#define D28IP_P4IP     12      /* PCI Express Port 4 */
+#define D28IP_P3IP     8       /* PCI Express Port 3 */
+#define D28IP_P2IP     4       /* PCI Express Port 2 */
+#define D28IP_P1IP     0       /* PCI Express Port 1 */
+#define D27IP          0x3110  /* 32bit */
+#define D27IP_ZIP      0       /* HD Audio Pin */
+#define D26IP          0x3114  /* 32bit */
+#define D26IP_E2P      0       /* EHCI #2 Pin */
+#define D25IP          0x3118  /* 32bit */
+#define D25IP_LIP      0       /* GbE LAN Pin */
+#define D22IP          0x3124  /* 32bit */
+#define D22IP_KTIP     12      /* KT Pin */
+#define D22IP_IDERIP   8       /* IDE-R Pin */
+#define D22IP_MEI2IP   4       /* MEI #2 Pin */
+#define D22IP_MEI1IP   0       /* MEI #1 Pin */
+#define D31IR          0x3140  /* 16bit */
+#define D30IR          0x3142  /* 16bit */
+#define D29IR          0x3144  /* 16bit */
+#define D28IR          0x3146  /* 16bit */
+#define D27IR          0x3148  /* 16bit */
+#define D26IR          0x314c  /* 16bit */
+#define D25IR          0x3150  /* 16bit */
+#define D22IR          0x315c  /* 16bit */
+#define OIC            0x31fe  /* 16bit */
+
+#define DIR_ROUTE(x,a,b,c,d) \
+  RCBA32(x) = (((d) << DIR_IDR) | ((c) << DIR_ICR) | \
+               ((b) << DIR_IBR) | ((a) << DIR_IAR))
+
+#define RC             0x3400  /* 32bit */
+#define HPTC           0x3404  /* 32bit */
+#define GCS            0x3410  /* 32bit */
+#define BUC            0x3414  /* 32bit */
+#define PCH_DISABLE_GBE                (1 << 5)
+#define FD             0x3418  /* 32bit */
+#define DISPBDF                0x3424  /* 16bit */
+#define FD2            0x3428  /* 32bit */
+#define CG             0x341c  /* 32bit */
+
+/* Function Disable 1 RCBA 0x3418 */
+#define PCH_DISABLE_ALWAYS     ((1 << 0)|(1 << 26)|(1 << 27))
+#define PCH_DISABLE_P2P                (1 << 1)
+#define PCH_DISABLE_SATA1      (1 << 2)
+#define PCH_DISABLE_SMBUS      (1 << 3)
+#define PCH_DISABLE_HD_AUDIO   (1 << 4)
+#define PCH_DISABLE_EHCI2      (1 << 13)
+#define PCH_DISABLE_LPC                (1 << 14)
+#define PCH_DISABLE_EHCI1      (1 << 15)
+#define PCH_DISABLE_PCIE(x)    (1 << (16 + x))
+#define PCH_DISABLE_THERMAL    (1 << 24)
+#define PCH_DISABLE_SATA2      (1 << 25)
+
+/* Function Disable 2 RCBA 0x3428 */
+#define PCH_DISABLE_KT         (1 << 4)
+#define PCH_DISABLE_IDER       (1 << 3)
+#define PCH_DISABLE_MEI2       (1 << 2)
+#define PCH_DISABLE_MEI1       (1 << 1)
+#define PCH_ENABLE_DBDF                (1 << 0)
+
+/* ICH7 GPIOBASE */
+#define GPIO_USE_SEL   0x00
+#define GP_IO_SEL      0x04
+#define GP_LVL         0x0c
+#define GPO_BLINK      0x18
+#define GPI_INV                0x2c
+#define GPIO_USE_SEL2  0x30
+#define GP_IO_SEL2     0x34
+#define GP_LVL2                0x38
+#define GPIO_USE_SEL3  0x40
+#define GP_IO_SEL3     0x44
+#define GP_LVL3                0x48
+#define GP_RST_SEL1    0x60
+#define GP_RST_SEL2    0x64
+#define GP_RST_SEL3    0x68
+
+/* ICH7 PMBASE */
+#define PM1_STS                0x00
+#define   WAK_STS      (1 << 15)
+#define   PCIEXPWAK_STS        (1 << 14)
+#define   PRBTNOR_STS  (1 << 11)
+#define   RTC_STS      (1 << 10)
+#define   PWRBTN_STS   (1 << 8)
+#define   GBL_STS      (1 << 5)
+#define   BM_STS       (1 << 4)
+#define   TMROF_STS    (1 << 0)
+#define PM1_EN         0x02
+#define   PCIEXPWAK_DIS        (1 << 14)
+#define   RTC_EN       (1 << 10)
+#define   PWRBTN_EN    (1 << 8)
+#define   GBL_EN       (1 << 5)
+#define   TMROF_EN     (1 << 0)
+#define PM1_CNT                0x04
+#define   SLP_EN       (1 << 13)
+#define   SLP_TYP      (7 << 10)
+#define    SLP_TYP_S0  0
+#define    SLP_TYP_S1  1
+#define    SLP_TYP_S3  5
+#define    SLP_TYP_S4  6
+#define    SLP_TYP_S5  7
+#define   GBL_RLS      (1 << 2)
+#define   BM_RLD       (1 << 1)
+#define   SCI_EN       (1 << 0)
+#define PM1_TMR                0x08
+#define PROC_CNT       0x10
+#define LV2            0x14
+#define LV3            0x15
+#define LV4            0x16
+#define PM2_CNT                0x50 // mobile only
+#define GPE0_STS       0x20
+#define   PME_B0_STS   (1 << 13)
+#define   PME_STS      (1 << 11)
+#define   BATLOW_STS   (1 << 10)
+#define   PCI_EXP_STS  (1 << 9)
+#define   RI_STS       (1 << 8)
+#define   SMB_WAK_STS  (1 << 7)
+#define   TCOSCI_STS   (1 << 6)
+#define   SWGPE_STS    (1 << 2)
+#define   HOT_PLUG_STS (1 << 1)
+#define GPE0_EN                0x28
+#define   PME_B0_EN    (1 << 13)
+#define   PME_EN       (1 << 11)
+#define SMI_EN         0x30
+#define   INTEL_USB2_EN         (1 << 18) // Intel-Specific USB2 SMI logic
+#define   LEGACY_USB2_EN (1 << 17) // Legacy USB2 SMI logic
+#define   PERIODIC_EN   (1 << 14) // SMI on PERIODIC_STS in SMI_STS
+#define   TCO_EN        (1 << 13) // Enable TCO Logic (BIOSWE et al)
+#define   MCSMI_EN      (1 << 11) // Trap microcontroller range access
+#define   BIOS_RLS      (1 <<  7) // asserts SCI on bit set
+#define   SWSMI_TMR_EN  (1 <<  6) // start software smi timer on bit set
+#define   APMC_EN       (1 <<  5) // Writes to APM_CNT cause SMI#
+#define   SLP_SMI_EN    (1 <<  4) // Write to SLP_EN in PM1_CNT asserts SMI#
+#define   LEGACY_USB_EN  (1 <<  3) // Legacy USB circuit SMI logic
+#define   BIOS_EN       (1 <<  2) // Assert SMI# on setting GBL_RLS bit
+#define   EOS           (1 <<  1) // End of SMI (deassert SMI#)
+#define   GBL_SMI_EN    (1 <<  0) // SMI# generation at all?
+#define SMI_STS                0x34
+#define ALT_GP_SMI_EN  0x38
+#define ALT_GP_SMI_STS 0x3a
+#define GPE_CNTL       0x42
+#define DEVACT_STS     0x44
+#define SS_CNT         0x50
+#define C3_RES         0x54
+
+/*
+ * SPI Opcode Menu setup for SPIBAR lockdown
+ * should support most common flash chips.
+ */
+
+#define SPI_OPMENU_0 0x01 /* WRSR: Write Status Register */
+#define SPI_OPTYPE_0 0x01 /* Write, no address */
+
+#define SPI_OPMENU_1 0x02 /* BYPR: Byte Program */
+#define SPI_OPTYPE_1 0x03 /* Write, address required */
+
+#define SPI_OPMENU_2 0x03 /* READ: Read Data */
+#define SPI_OPTYPE_2 0x02 /* Read, address required */
+
+#define SPI_OPMENU_3 0x05 /* RDSR: Read Status Register */
+#define SPI_OPTYPE_3 0x00 /* Read, no address */
+
+#define SPI_OPMENU_4 0x20 /* SE20: Sector Erase 0x20 */
+#define SPI_OPTYPE_4 0x03 /* Write, address required */
+
+#define SPI_OPMENU_5 0x9f /* RDID: Read ID */
+#define SPI_OPTYPE_5 0x00 /* Read, no address */
+
+#define SPI_OPMENU_6 0xd8 /* BED8: Block Erase 0xd8 */
+#define SPI_OPTYPE_6 0x03 /* Write, address required */
+
+#define SPI_OPMENU_7 0x52 /* BE52: Block Erase 0x52 */
+#define SPI_OPTYPE_7 0x03 /* Write, address required */
+
+#define SPI_OPMENU_UPPER ((SPI_OPMENU_7 << 24) | (SPI_OPMENU_6 << 16) | \
+                         (SPI_OPMENU_5 << 8) | SPI_OPMENU_4)
+#define SPI_OPMENU_LOWER ((SPI_OPMENU_3 << 24) | (SPI_OPMENU_2 << 16) | \
+                         (SPI_OPMENU_1 << 8) | SPI_OPMENU_0)
+
+#define SPI_OPTYPE ((SPI_OPTYPE_7 << 14) | (SPI_OPTYPE_6 << 12) | \
+                   (SPI_OPTYPE_5 << 10) | (SPI_OPTYPE_4 << 8) |  \
+                   (SPI_OPTYPE_3 << 6) | (SPI_OPTYPE_2 << 4) |   \
+                   (SPI_OPTYPE_1 << 2) | (SPI_OPTYPE_0))
+
+#define SPI_OPPREFIX ((0x50 << 8) | 0x06) /* EWSR and WREN */
+
+#endif /* __ACPI__ */
+#endif                         /* SOUTHBRIDGE_INTEL_BD82X6X_PCH_H */
diff --git a/src/southbridge/intel/bd82x6x/pci.c b/src/southbridge/intel/bd82x6x/pci.c
new file mode 100644 (file)
index 0000000..845a6fe
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include "pch.h"
+
+static void pci_init(struct device *dev)
+{
+       u16 reg16;
+       u8 reg8;
+
+       printk(BIOS_DEBUG, "PCI init.\n");
+       /* Enable Bus Master */
+       reg16 = pci_read_config16(dev, PCI_COMMAND);
+       reg16 |= PCI_COMMAND_MASTER;
+       pci_write_config16(dev, PCI_COMMAND, reg16);
+
+       /* This device has no interrupt */
+       pci_write_config8(dev, INTR, 0xff);
+
+       /* disable parity error response and SERR */
+       reg16 = pci_read_config16(dev, BCTRL);
+       reg16 &= ~(1 << 0);
+       reg16 &= ~(1 << 1);
+       pci_write_config16(dev, BCTRL, reg16);
+
+       /* Master Latency Count must be set to 0x04! */
+       reg8 = pci_read_config8(dev, SMLT);
+       reg8 &= 0x07;
+       reg8 |= (0x04 << 3);
+       pci_write_config8(dev, SMLT, reg8);
+
+       /* Will this improve throughput of bus masters? */
+       pci_write_config8(dev, PCI_MIN_GNT, 0x06);
+
+       /* Clear errors in status registers */
+       reg16 = pci_read_config16(dev, PSTS);
+       //reg16 |= 0xf900;
+       pci_write_config16(dev, PSTS, reg16);
+
+       reg16 = pci_read_config16(dev, SECSTS);
+       // reg16 |= 0xf900;
+       pci_write_config16(dev, SECSTS, reg16);
+}
+
+#undef PCI_BRIDGE_UPDATE_COMMAND
+static void ich_pci_dev_enable_resources(struct device *dev)
+{
+       const struct pci_operations *ops;
+       uint16_t command;
+
+       /* Set the subsystem vendor and device id for mainboard devices */
+       ops = ops_pci(dev);
+       if (dev->on_mainboard && ops && ops->set_subsystem) {
+               printk(BIOS_DEBUG, "%s subsystem <- %02x/%02x\n",
+                       dev_path(dev),
+                       CONFIG_MAINBOARD_PCI_SUBSYSTEM_VENDOR_ID,
+                       CONFIG_MAINBOARD_PCI_SUBSYSTEM_DEVICE_ID);
+               ops->set_subsystem(dev,
+                       CONFIG_MAINBOARD_PCI_SUBSYSTEM_VENDOR_ID,
+                       CONFIG_MAINBOARD_PCI_SUBSYSTEM_DEVICE_ID);
+       }
+
+       command = pci_read_config16(dev, PCI_COMMAND);
+       command |= dev->command;
+#ifdef PCI_BRIDGE_UPDATE_COMMAND
+       /* If we write to PCI_COMMAND, on some systems
+        * this will cause the ROM and APICs not being visible
+        * anymore.
+        */
+       printk(BIOS_DEBUG, "%s cmd <- %02x\n", dev_path(dev), command);
+       pci_write_config16(dev, PCI_COMMAND, command);
+#else
+       printk(BIOS_DEBUG, "%s cmd <- %02x (NOT WRITTEN!)\n", dev_path(dev), command);
+#endif
+}
+
+static void ich_pci_bus_enable_resources(struct device *dev)
+{
+       uint16_t ctrl;
+       /* enable IO in command register if there is VGA card
+        * connected with (even it does not claim IO resource)
+        */
+       if (dev->link_list->bridge_ctrl & PCI_BRIDGE_CTL_VGA)
+               dev->command |= PCI_COMMAND_IO;
+       ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL);
+       ctrl |= dev->link_list->bridge_ctrl;
+       ctrl |= (PCI_BRIDGE_CTL_PARITY + PCI_BRIDGE_CTL_SERR); /* error check */
+       printk(BIOS_DEBUG, "%s bridge ctrl <- %04x\n", dev_path(dev), ctrl);
+       pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl);
+
+       /* This is the reason we need our own pci_bus_enable_resources */
+       ich_pci_dev_enable_resources(dev);
+}
+
+static void set_subsystem(device_t dev, unsigned vendor, unsigned device)
+{
+       /* NOTE: This 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       = ich_pci_bus_enable_resources,
+       .init                   = pci_init,
+       .scan_bus               = pci_scan_bridge,
+       .ops_pci                = &pci_ops,
+};
+
+static const struct pci_driver pch_pci __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x2448,
+};
diff --git a/src/southbridge/intel/bd82x6x/pcie.c b/src/southbridge/intel/bd82x6x/pcie.c
new file mode 100644 (file)
index 0000000..599692d
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pciexp.h>
+#include <device/pci_ids.h>
+#include "pch.h"
+
+static u16 pcie_port_link_width(int port)
+{
+       u16 link_width;
+
+       link_width = pci_read_config16(
+               dev_find_slot(0, PCI_DEVFN(0x1c, port)), 0x52);
+       link_width >>= 4;
+       link_width &= 0x3f;
+       return link_width;
+}
+
+static void pch_pcie_pm_early(struct device *dev)
+{
+       u16 link_width_p0, link_width_p4;
+       u8 slot_power_limit = 10; /* 10W for x1 */
+       u32 reg32;
+       u8 reg8;
+
+       link_width_p0 = pcie_port_link_width(0);
+       link_width_p4 = pcie_port_link_width(4);
+
+       /* Enable dynamic clock gating where needed */
+       reg8 = pci_read_config8(dev, 0xe1);
+       switch (PCI_FUNC(dev->path.pci.devfn)) {
+       case 0: /* Port 0 */
+               if (link_width_p0 == 4)
+                       slot_power_limit = 40; /* 40W for x4 */
+               else if (link_width_p0 == 2)
+                       slot_power_limit = 20; /* 20W for x2 */
+       case 4: /* Port 4 */
+               if (link_width_p4 == 4)
+                       slot_power_limit = 40; /* 40W for x4 */
+               else if (link_width_p4 == 2)
+                       slot_power_limit = 20; /* 20W for x2 */
+               reg8 |= 0x3f;
+               break;
+       case 1: /* Port 1 only if Port 0 is x1 */
+               if (link_width_p0 == 1)
+                       reg8 |= 0x3;
+               break;
+       case 2: /* Port 2 only if Port 0 is x1 or x2 */
+       case 3: /* Port 3 only if Port 0 is x1 or x2 */
+               if (link_width_p0 <= 2)
+                       reg8 |= 0x3;
+               break;
+       case 5: /* Port 5 only if Port 4 is x1 */
+               if (link_width_p4 == 1)
+                       reg8 |= 0x3;
+               break;
+       case 6: /* Port 7 only if Port 4 is x1 or x2 */
+       case 7: /* Port 7 only if Port 4 is x1 or x2 */
+               if (link_width_p4 <= 2)
+                       reg8 |= 0x3;
+               break;
+       }
+       pci_write_config8(dev, 0xe1, reg8);
+
+       /* Set 0xE8[0] = 1 */
+       reg32 = pci_read_config32(dev, 0xe8);
+       reg32 |= 1;
+       pci_write_config32(dev, 0xe8, reg32);
+
+       /* Adjust Common Clock exit latency */
+       reg32 = pci_read_config32(dev, 0xd8);
+       reg32 &= ~(1 << 17);
+       reg32 |= (1 << 16) | (1 << 15);
+       reg32 &= ~(1 << 31); /* Disable PME# SCI for native PME handling */
+       pci_write_config32(dev, 0xd8, reg32);
+
+       /* Adjust ASPM L1 exit latency */
+       reg32 = pci_read_config32(dev, 0x4c);
+       reg32 &= ~((1 << 17) | (1 << 16) | (1 << 15));
+       if (RCBA32(0x2320) & (1 << 16)) {
+               /* If RCBA+2320[15]=1 set ASPM L1 to 8-16us */
+               reg32 |= (1 << 17);
+       } else {
+               /* Else set ASPM L1 to 2-4us */
+               reg32 |= (1 << 16);
+       }
+       pci_write_config32(dev, 0x4c, reg32);
+
+       /* Set slot power limit as configured above */
+       reg32 = pci_read_config32(dev, 0x54);
+       reg32 &= ~((1 << 15) | (1 << 16)); /* 16:15 = Slot power scale */
+       reg32 &= ~(0xff << 7);             /* 14:7  = Slot power limit */
+       reg32 |= (slot_power_limit << 7);
+       pci_write_config32(dev, 0x54, reg32);
+}
+
+static void pch_pcie_pm_late(struct device *dev)
+{
+       enum aspm_type apmc;
+       u32 reg32;
+
+       /* Set 0x314 = 0x743a361b */
+       pci_mmio_write_config32(dev, 0x314, 0x743a361b);
+
+       /* Set 0x318[31:16] = 0x1414 */
+       reg32 = pci_mmio_read_config32(dev, 0x318);
+       reg32 &= 0x0000ffff;
+       reg32 |= 0x14140000;
+       pci_mmio_write_config32(dev, 0x318, reg32);
+
+       /* Set 0x324[5] = 1 */
+       reg32 = pci_mmio_read_config32(dev, 0x324);
+       reg32 |= (1 << 5);
+       pci_mmio_write_config32(dev, 0x324, reg32);
+
+       /* Set 0x330[7:0] = 0x40 */
+       reg32 = pci_mmio_read_config32(dev, 0x330);
+       reg32 &= ~(0xff);
+       reg32 |= 0x40;
+       pci_mmio_write_config32(dev, 0x330, reg32);
+
+       /* Set 0x33C[24:0] = 0x854c74 */
+       reg32 = pci_mmio_read_config32(dev, 0x33c);
+       reg32 &= 0xff000000;
+       reg32 |= 0x00854c74;
+       pci_mmio_write_config32(dev, 0x33c, reg32);
+
+       /* No IO-APIC, Disable EOI forwarding */
+       reg32 = pci_read_config32(dev, 0xd4);
+       reg32 |= (1 << 1);
+       pci_write_config32(dev, 0xd4, reg32);
+
+       /* Get configured ASPM state */
+       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);
+       }
+}
+
+static void pci_init(struct device *dev)
+{
+       u16 reg16;
+       u32 reg32;
+
+       printk(BIOS_DEBUG, "Initializing PCH PCIe bridge.\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 << 1); /* disable SERR */
+       reg16 |= (1 << 2); /* ISA enable */
+       pci_write_config16(dev, 0x3e, reg16);
+
+#ifdef EVEN_MORE_DEBUG
+       reg32 = pci_read_config32(dev, 0x20);
+       printk(BIOS_SPEW, "    MBL    = 0x%08x\n", reg32);
+       reg32 = pci_read_config32(dev, 0x24);
+       printk(BIOS_SPEW, "    PMBL   = 0x%08x\n", reg32);
+       reg32 = pci_read_config32(dev, 0x28);
+       printk(BIOS_SPEW, "    PMBU32 = 0x%08x\n", reg32);
+       reg32 = pci_read_config32(dev, 0x2c);
+       printk(BIOS_SPEW, "    PMLU32 = 0x%08x\n", reg32);
+#endif
+
+       /* Clear errors in status registers */
+       reg16 = pci_read_config16(dev, 0x06);
+       //reg16 |= 0xf900;
+       pci_write_config16(dev, 0x06, reg16);
+
+       reg16 = pci_read_config16(dev, 0x1e);
+       //reg16 |= 0xf900;
+       pci_write_config16(dev, 0x1e, reg16);
+
+       /* Power Management init after enumeration */
+       pch_pcie_pm_late(dev);
+}
+
+static void pch_pcie_enable(device_t dev)
+{
+       /* Power Management init before enumeration */
+       pch_pcie_pm_early(dev);
+}
+
+static void pcie_set_subsystem(device_t dev, unsigned vendor, unsigned device)
+{
+       /* NOTE: This 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 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,
+       .enable                 = pch_pcie_enable,
+       .scan_bus               = pciexp_scan_bridge,
+       .ops_pci                = &pci_ops,
+};
+
+static const struct pci_driver pch_pcie_port1 __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c10,       /* D28:F0 */
+};
+
+static const struct pci_driver pch_pcie_port1_a __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1e10,       /* D28:F0 */
+};
+
+static const struct pci_driver pch_pcie_port2 __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c12,       /* D28:F1 */
+};
+
+static const struct pci_driver pch_pcie_port3 __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c14,       /* D28:F2 */
+};
+
+static const struct pci_driver pch_pcie_port3_a __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1e14,       /* D28:F2 */
+};
+
+static const struct pci_driver pch_pcie_port4 __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c16,       /* D28:F3 */
+};
+
+static const struct pci_driver pch_pcie_port4_a __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1e16,       /* D28:F3 */
+};
+
+static const struct pci_driver pch_pcie_port5 __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c18,       /* D28:F4 */
+};
+
+static const struct pci_driver pch_pcie_port6 __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c1a,       /* D28:F5 */
+};
+
+static const struct pci_driver pch_pcie_port7 __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c1c,       /* D28:F6 */
+};
+
+static const struct pci_driver pch_pcie_port8 __pci_driver = {
+       .ops    = &device_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c1e,       /* D28:F7 */
+};
diff --git a/src/southbridge/intel/bd82x6x/reset.c b/src/southbridge/intel/bd82x6x/reset.c
new file mode 100644 (file)
index 0000000..29b69ff
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <arch/io.h>
+#include <reset.h>
+
+void soft_reset(void)
+{
+        outb(0x04, 0xcf9);
+}
+
+#if 0
+void hard_reset(void)
+{
+       /* Try rebooting through port 0xcf9. */
+       outb((1 << 2) | (1 << 1), 0xcf9);
+}
+#endif
+
+void hard_reset(void)
+{
+        outb(0x02, 0xcf9);
+        outb(0x06, 0xcf9);
+}
diff --git a/src/southbridge/intel/bd82x6x/sata.c b/src/southbridge/intel/bd82x6x/sata.c
new file mode 100644 (file)
index 0000000..057b882
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <arch/io.h>
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include "pch.h"
+
+typedef struct southbridge_intel_bd82x6x_config config_t;
+
+static void sata_init(struct device *dev)
+{
+       u32 reg32;
+       u16 reg16;
+       /* Get the chip configuration */
+       config_t *config = dev->chip_info;
+
+       printk(BIOS_DEBUG, "pch_sata: initializing...\n");
+
+       if (config == NULL) {
+               printk(BIOS_ERR, "pch_sata: error: device not in devicetree.cb!\n");
+               return;
+       }
+
+       /* SATA configuration */
+
+       /* Enable BARs */
+       pci_write_config16(dev, PCI_COMMAND, 0x0007);
+
+       if (config->ide_legacy_combined) {
+               printk(BIOS_DEBUG, "SATA controller in combined mode.\n");
+               /* Combine IDE - SATA configuration */
+               pci_write_config16(dev, 0x90, 0x0000);
+
+               /* No AHCI: clear AHCI base */
+               pci_write_config32(dev, 0x24, 0x00000000);
+               /* And without AHCI BAR no memory decoding */
+               reg16 = pci_read_config16(dev, PCI_COMMAND);
+               reg16 &= ~PCI_COMMAND_MEMORY;
+               pci_write_config16(dev, PCI_COMMAND, reg16);
+
+               pci_write_config8(dev, 0x09, 0x80);
+
+               /* Set timings */
+               pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE |
+                               IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS);
+               pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE |
+                               IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS |
+                               IDE_PPE0 | IDE_IE0 | IDE_TIME0);
+
+               /* Sync DMA */
+               pci_write_config16(dev, IDE_SDMA_CNT, IDE_SSDE0);
+               pci_write_config16(dev, IDE_SDMA_TIM, 0x0200);
+
+               /* Set IDE I/O Configuration */
+               reg32 = SIG_MODE_PRI_NORMAL | FAST_PCB1 | FAST_PCB0 | PCB1 | PCB0;
+               pci_write_config32(dev, IDE_CONFIG, reg32);
+
+               /* Port enable */
+               reg16 = pci_read_config16(dev, 0x92);
+               reg16 &= ~0x3f;
+               reg16 |= config->sata_port_map;
+               pci_write_config16(dev, 0x92, reg16);
+
+               /* SATA Initialization register */
+               pci_write_config32(dev, 0x94,
+                          ((config->sata_port_map ^ 0x3f) << 24) | 0x183);
+       } else if(config->sata_ahci) {
+               u32 abar;
+
+               printk(BIOS_DEBUG, "SATA controller in AHCI mode.\n");
+               /* Set Sata Controller Mode. */
+               pci_write_config16(dev, 0x90, 0x0060 |
+                                  ((config->sata_port_map ^ 0x3f) << 8));
+
+               /* Set Interrupt Line */
+               /* Interrupt Pin is set by D31IP.PIP */
+               pci_write_config8(dev, INTR_LN, 0x0a);
+
+               /* Set timings */
+               pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE |
+                               IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS |
+                               IDE_PPE0 | IDE_IE0 | IDE_TIME0);
+               pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE |
+                               IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS);
+
+               /* Sync DMA */
+               pci_write_config16(dev, IDE_SDMA_CNT, IDE_PSDE0);
+               pci_write_config16(dev, IDE_SDMA_TIM, 0x0001);
+
+               /* Set IDE I/O Configuration */
+               reg32 = SIG_MODE_PRI_NORMAL | FAST_PCB1 | FAST_PCB0 | PCB1 | PCB0;
+               pci_write_config32(dev, IDE_CONFIG, reg32);
+
+               /* for AHCI, Port Enable is managed in memory mapped space */
+               reg16 = pci_read_config16(dev, 0x92);
+               reg16 &= ~0x3f; /* 6 ports SKU + ORM */
+               reg16 |= 0x8000 | config->sata_port_map;
+               pci_write_config16(dev, 0x92, reg16);
+
+               /* SATA Initialization register */
+               pci_write_config32(dev, 0x94,
+                          ((config->sata_port_map ^ 0x3f) << 24) | 0x183);
+
+               /* Initialize AHCI memory-mapped space */
+               abar = pci_read_config32(dev, PCI_BASE_ADDRESS_5);
+               printk(BIOS_DEBUG, "ABAR: %08X\n", abar);
+               /* CAP (HBA Capabilities) : enable power management */
+               reg32 = read32(abar + 0x00);
+               reg32 |= 0x0c006000;  // set PSC+SSC+SALP+SSS
+               reg32 &= ~0x00020060; // clear SXS+EMS+PMS
+               write32(abar + 0x00, reg32);
+               /* PI (Ports implemented) */
+               write32(abar + 0x0c, config->sata_port_map);
+               (void) read32(abar + 0x0c); /* Read back 1 */
+               (void) read32(abar + 0x0c); /* Read back 2 */
+               /* CAP2 (HBA Capabilities Extended)*/
+               reg32 = read32(abar + 0x24);
+               reg32 &= ~0x00000002;
+               write32(abar + 0x24, reg32);
+               /* VSP (Vendor Specific Register */
+               reg32 = read32(abar + 0xa0);
+               reg32 &= ~0x00000005;
+               write32(abar + 0xa0, reg32);
+       } else {
+               printk(BIOS_DEBUG, "SATA controller in plain mode.\n");
+               /* Set Sata Controller Mode. No Mapping(?) */
+               pci_write_config16(dev, 0x90, 0x0000);
+
+               /* No AHCI: clear AHCI base */
+               pci_write_config32(dev, 0x24, 0x00000000);
+
+               /* And without AHCI BAR no memory decoding */
+               reg16 = pci_read_config16(dev, PCI_COMMAND);
+               reg16 &= ~PCI_COMMAND_MEMORY;
+               pci_write_config16(dev, PCI_COMMAND, reg16);
+
+               /* Native mode capable on both primary and secondary (0xa)
+                * or'ed with enabled (0x50) = 0xf
+                */
+               pci_write_config8(dev, 0x09, 0x8f);
+
+               /* Set Interrupt Line */
+               /* Interrupt Pin is set by D31IP.PIP */
+               pci_write_config8(dev, INTR_LN, 0xff);
+
+               /* Set timings */
+               pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE |
+                               IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS |
+                               IDE_PPE0 | IDE_IE0 | IDE_TIME0);
+               pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE |
+                               IDE_SITRE | IDE_ISP_3_CLOCKS |
+                               IDE_RCT_1_CLOCKS | IDE_IE0 | IDE_TIME0);
+
+               /* Sync DMA */
+               pci_write_config16(dev, IDE_SDMA_CNT, IDE_SSDE0 | IDE_PSDE0);
+               pci_write_config16(dev, IDE_SDMA_TIM, 0x0201);
+
+               /* Set IDE I/O Configuration */
+               reg32 = SIG_MODE_PRI_NORMAL | FAST_PCB1 | FAST_PCB0 | PCB1 | PCB0;
+               pci_write_config32(dev, IDE_CONFIG, reg32);
+
+               /* Port enable */
+               reg16 = pci_read_config16(dev, 0x92);
+               reg16 &= ~0x3f;
+               reg16 |= config->sata_port_map;
+               pci_write_config16(dev, 0x92, reg16);
+
+               /* SATA Initialization register */
+               pci_write_config32(dev, 0x94,
+                          ((config->sata_port_map ^ 0x3f) << 24) | 0x183);
+       }
+}
+
+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,
+       .scan_bus               = 0,
+       .ops_pci                = &sata_pci_ops,
+};
+
+/* Non-AHCI and Non-RAID Mode */
+static const struct pci_driver pch_sata_normal_driver __pci_driver = {
+       .ops    = &sata_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c00,
+};
+static const struct pci_driver pch_sata_mobile_normal_driver __pci_driver = {
+       .ops    = &sata_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c01,
+};
+
+/* AHCI Mode */
+static const struct pci_driver pch_sata_ahci_driver __pci_driver = {
+       .ops    = &sata_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c02,
+};
+static const struct pci_driver pch_sata_mobile_ahci_driver __pci_driver = {
+       .ops    = &sata_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c03,
+};
+static const struct pci_driver pch_sata_mobile_ahci_driver_a __pci_driver = {
+       .ops    = &sata_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1e03,
+};
+
diff --git a/src/southbridge/intel/bd82x6x/smbus.c b/src/southbridge/intel/bd82x6x/smbus.c
new file mode 100644 (file)
index 0000000..baa3cfb
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/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 "pch.h"
+#include "smbus.h"
+
+static void pch_smbus_init(device_t dev)
+{
+       struct resource *res;
+       u16 reg16;
+
+       /* Enable clock gating */
+       reg16 = pci_read_config32(dev, 0x80);
+       reg16 &= ~((1 << 8)|(1 << 10)|(1 << 12)|(1 << 14));
+       pci_write_config32(dev, 0x80, reg16);
+
+       /* Set Receive Slave Address */
+       res = find_resource(dev, PCI_BASE_ADDRESS_4);
+       if (res)
+               outb(SMBUS_SLAVE_ADDR, res->base + SMB_RCV_SLVA);
+}
+
+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 struct smbus_bus_operations lops_smbus_bus = {
+       .read_byte      = lsmbus_read_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_static_bus,
+       .init                   = pch_smbus_init,
+       .ops_smbus_bus          = &lops_smbus_bus,
+       .ops_pci                = &smbus_pci_ops,
+};
+
+static const struct pci_driver pch_smbus __pci_driver = {
+       .ops    = &smbus_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c22,
+};
+
+static const struct pci_driver pch_smbus_a __pci_driver = {
+       .ops    = &smbus_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1e22,
+};
diff --git a/src/southbridge/intel/bd82x6x/smbus.h b/src/southbridge/intel/bd82x6x/smbus.h
new file mode 100644 (file)
index 0000000..f2f7f60
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <device/smbus_def.h>
+#include "pch.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;
+}
+
diff --git a/src/southbridge/intel/bd82x6x/smi.c b/src/southbridge/intel/bd82x6x/smi.c
new file mode 100644 (file)
index 0000000..da10840
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+
+#include <device/device.h>
+#include <device/pci.h>
+#include <console/console.h>
+#include <arch/io.h>
+#include <cpu/cpu.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/smm.h>
+#include <string.h>
+#include "pch.h"
+
+#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE
+#include "northbridge/intel/sandybridge/sandybridge.h"
+#endif
+
+extern unsigned char _binary_smm_start;
+extern unsigned char _binary_smm_size;
+
+/* 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 << 26)) printk(BIOS_DEBUG, "SPI ");
+       if (smi_sts & (1 << 25)) printk(BIOS_DEBUG, "EL_SMI ");
+       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 u32 reset_gpe0_status(void)
+{
+       u32 reg32;
+
+       reg32 = inl(pmbase + GPE0_STS);
+       /* set status bits are cleared by writing 1 to them */
+       outl(reg32, pmbase + GPE0_STS);
+
+       return reg32;
+}
+
+static void dump_gpe0_status(u32 gpe0_sts)
+{
+       int i;
+       printk(BIOS_DEBUG, "GPE0_STS: ");
+       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, "AC97 ");
+       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, "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-16));
+       }
+       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;
+       u32 gpe0_en;
+
+       printk(BIOS_DEBUG, "Initializing SMM handler...");
+
+       pmbase = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x1f, 0)),
+                                                       PMBASE) & 0xff80;
+
+       printk(BIOS_SPEW, " ... pmbase = 0x%04x\n", pmbase);
+
+       smi_en = inl(pmbase + SMI_EN);
+       if (smi_en & APMC_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);
+
+       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());
+
+       /* Disable GPE0 PME_B0 */
+       gpe0_en = inl(pmbase + GPE0_EN);
+       gpe0_en &= ~PME_B0_EN;
+       outl(gpe0_en, pmbase + GPE0_EN);
+
+       /* Enable SMI generation:
+        *  - on TCO events
+        *  - on APMC writes (io 0xb2)
+        *  - on writes to SLP_EN (sleep states)
+        *  - on writes to GBL_RLS (bios commands)
+        * No SMIs:
+        *  - on microcontroller writes (io 0x62/0x66)
+        */
+
+       smi_en = 0; /* reset SMI enables */
+
+#if 0
+       smi_en |= LEGACY_USB2_EN | LEGACY_USB_EN;
+#endif
+       smi_en |= TCO_EN;
+       smi_en |= APMC_EN;
+#if DEBUG_PERIODIC_SMIS
+       /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
+        * periodic SMIs.
+        */
+       smi_en |= PERIODIC_EN;
+#endif
+       smi_en |= SLP_SMI_EN;
+#if 0
+       smi_en |= BIOS_EN;
+#endif
+
+       /* 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)
+{
+       device_t dev = dev_find_slot(0, PCI_DEVFN(0, 0));
+       u32 smm_base = 0xa0000;
+       struct ied_header ied = {
+               .signature = "INTEL RSVD",
+               .size = IED_SIZE,
+               .reserved = {0},
+       };
+
+       /* 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;
+
+       /* enable the SMM memory window */
+       pci_write_config8(dev, SMRAM, D_OPEN | G_SMRAME | C_BASE_SEG);
+
+#if CONFIG_SMM_TSEG
+       smm_base = pci_read_config32(dev, TSEG) & ~1;
+#endif
+
+       /* copy the real SMM handler */
+       printk(BIOS_DEBUG, "Installing SMM handler to 0x%08x\n", smm_base);
+       memcpy((void *)smm_base, &_binary_smm_start, (size_t)&_binary_smm_size);
+
+       /* copy the IED header into place */
+       if (CONFIG_SMM_TSEG_SIZE > IED_SIZE) {
+               /* Top of TSEG region */
+               smm_base += CONFIG_SMM_TSEG_SIZE - IED_SIZE;
+               printk(BIOS_DEBUG, "Installing IED header to 0x%08x\n",
+                      smm_base);
+               memcpy((void *)smm_base, &ied, sizeof(ied));
+       }
+       wbinvd();
+
+       /* close the SMM memory window and enable normal SMM */
+       pci_write_config8(dev, 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(0xea, 0xb2);
+}
diff --git a/src/southbridge/intel/bd82x6x/smihandler.c b/src/southbridge/intel/bd82x6x/smihandler.c
new file mode 100644 (file)
index 0000000..e311d95
--- /dev/null
@@ -0,0 +1,709 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <types.h>
+#include <arch/hlt.h>
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+#include <console/console.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/smm.h>
+#include <device/pci_def.h>
+#include <cpu/x86/smm.h>
+#include "pch.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;
+
+#if CONFIG_SMM_TSEG
+static u32 tseg_base = 0;
+static inline void tseg_fixup(void **ptr)
+{
+       /* Adjust pointer with TSEG base */
+       if (*ptr)
+               *ptr = (void *)(((u8*)*ptr) + tseg_base);
+}
+#else
+#define tseg_fixup(x) do {} while(0)
+#endif
+
+/**
+ * @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_SPEW, "PM1_STS: ");
+       if (pm1_sts & (1 << 15)) printk(BIOS_SPEW, "WAK ");
+       if (pm1_sts & (1 << 14)) printk(BIOS_SPEW, "PCIEXPWAK ");
+       if (pm1_sts & (1 << 11)) printk(BIOS_SPEW, "PRBTNOR ");
+       if (pm1_sts & (1 << 10)) printk(BIOS_SPEW, "RTC ");
+       if (pm1_sts & (1 <<  8)) printk(BIOS_SPEW, "PWRBTN ");
+       if (pm1_sts & (1 <<  5)) printk(BIOS_SPEW, "GBL ");
+       if (pm1_sts & (1 <<  4)) printk(BIOS_SPEW, "BM ");
+       if (pm1_sts & (1 <<  0)) printk(BIOS_SPEW, "TMROF ");
+       printk(BIOS_SPEW, "\n");
+       int reg16 = inw(pmbase + PM1_EN);
+       printk(BIOS_SPEW, "PM1_EN: %x\n", reg16);
+}
+
+/**
+ * @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 << 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 u32 reset_gpe0_status(void)
+{
+       u32 reg32;
+
+       reg32 = inl(pmbase + GPE0_STS);
+       /* set status bits are cleared by writing 1 to them */
+       outl(reg32, pmbase + GPE0_STS);
+
+       return reg32;
+}
+
+static void dump_gpe0_status(u32 gpe0_sts)
+{
+       int i;
+       printk(BIOS_DEBUG, "GPE0_STS: ");
+       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, "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, "AC97 ");
+       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, "HOTPLUG ");
+       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");
+}
+
+/* We are using PCIe accesses for now
+ *  1. the chipset can do it
+ *  2. we don't need to worry about how we leave 0xcf8/0xcfc behind
+ */
+#include <northbridge/intel/sandybridge/sandybridge.h>
+#include <northbridge/intel/sandybridge/pcie_config.c>
+
+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 busmaster_disable_on_bus(int bus)
+{
+        int slot, func;
+        unsigned int val;
+        unsigned char hdr;
+
+        for (slot = 0; slot < 0x20; slot++) {
+                for (func = 0; func < 8; func++) {
+                        u32 reg32;
+                        device_t dev = PCI_DEV(bus, slot, func);
+
+                        val = pci_read_config32(dev, PCI_VENDOR_ID);
+
+                        if (val == 0xffffffff || val == 0x00000000 ||
+                            val == 0x0000ffff || val == 0xffff0000)
+                                continue;
+
+                        /* Disable Bus Mastering for this one device */
+                        reg32 = pci_read_config32(dev, PCI_COMMAND);
+                        reg32 &= ~PCI_COMMAND_MASTER;
+                        pci_write_config32(dev, PCI_COMMAND, reg32);
+
+                        /* If this is a bridge, then follow it. */
+                        hdr = pci_read_config8(dev, PCI_HEADER_TYPE);
+                        hdr &= 0x7f;
+                        if (hdr == PCI_HEADER_TYPE_BRIDGE ||
+                            hdr == PCI_HEADER_TYPE_CARDBUS) {
+                                unsigned int buses;
+                                buses = pci_read_config32(dev, PCI_PRIMARY_BUS);
+                                busmaster_disable_on_bus((buses >> 8) & 0xff);
+                        }
+                }
+        }
+}
+
+/*
+ * Drive GPIO 60 low to gate memory reset in S3.
+ *
+ * Intel reference designs all use GPIO 60 but it is
+ * not a requirement and boards could use a different pin.
+ */
+static void southbridge_gate_memory_reset(void)
+{
+       u32 reg32;
+       u16 gpiobase;
+
+       gpiobase = pcie_read_config16(PCI_DEV(0, 0x1f, 0), GPIOBASE) & 0xfffc;
+       if (!gpiobase)
+               return;
+
+       /* Make sure it is set as GPIO */
+       reg32 = inl(gpiobase + GPIO_USE_SEL2);
+       if (!(reg32 & (1 << 28))) {
+               reg32 |= (1 << 28);
+               outl(reg32, gpiobase + GPIO_USE_SEL2);
+       }
+
+       /* Make sure it is set as output */
+       reg32 = inl(gpiobase + GP_IO_SEL2);
+       if (reg32 & (1 << 28)) {
+               reg32 &= ~(1 << 28);
+               outl(reg32, gpiobase + GP_IO_SEL2);
+       }
+
+       /* Drive the output low */
+       reg32 = inl(gpiobase + GP_LVL2);
+       reg32 &= ~(1 << 28);
+       outl(reg32, gpiobase + GP_LVL2);
+}
+
+static void southbridge_smi_sleep(unsigned int node, smm_state_save_area_t *state_save)
+{
+       u8 reg8;
+       u32 reg32;
+       u8 slp_typ;
+       /* FIXME: the power state on boot should be read from
+        * CMOS or even better from GNVS. Right now it's hard
+        * coded at compile time.
+        */
+       u8 s5pwr = CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
+       void (*mainboard_sleep)(u8 slp_typ) = mainboard_smi_sleep;
+
+       /* First, disable further SMIs */
+       reg8 = inb(pmbase + SMI_EN);
+       reg8 &= ~SLP_SMI_EN;
+       outb(reg8, pmbase + SMI_EN);
+
+       /* Figure out SLP_TYP */
+       reg32 = inl(pmbase + PM1_CNT);
+       printk(BIOS_SPEW, "SMI#: SLP = 0x%08x\n", reg32);
+       slp_typ = (reg32 >> 10) & 7;
+
+       /* Do any mainboard sleep handling */
+       tseg_fixup((void **)&mainboard_sleep);
+       if (mainboard_sleep)
+               mainboard_sleep(slp_typ);
+
+       /* Next, do the deed.
+        */
+
+       switch (slp_typ) {
+       case 0: printk(BIOS_DEBUG, "SMI#: Entering S0 (On)\n"); break;
+       case 1: printk(BIOS_DEBUG, "SMI#: Entering S1 (Assert STPCLK#)\n"); break;
+       case 5:
+               printk(BIOS_DEBUG, "SMI#: Entering S3 (Suspend-To-RAM)\n");
+
+               /* Gate memory reset */
+               southbridge_gate_memory_reset();
+
+               /* Invalidate the cache before going to S3 */
+               wbinvd();
+               break;
+       case 6: printk(BIOS_DEBUG, "SMI#: Entering S4 (Suspend-To-Disk)\n"); break;
+       case 7:
+               printk(BIOS_DEBUG, "SMI#: Entering S5 (Soft Power off)\n");
+
+               outl(0, pmbase + GPE0_EN);
+
+               /* Should we keep the power state after a power loss?
+                * In case the setting is "ON" or "OFF" we don't have
+                * to do anything. But if it's "KEEP" we have to switch
+                * to "OFF" before entering S5.
+                */
+               if (s5pwr == MAINBOARD_POWER_KEEP) {
+                       reg8 = pcie_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3);
+                       reg8 |= 1;
+                       pcie_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3, reg8);
+               }
+
+               /* also iterates over all bridges on bus 0 */
+               busmaster_disable_on_bus(0);
+               break;
+       default: printk(BIOS_DEBUG, "SMI#: ERROR: SLP_TYP reserved\n"); break;
+       }
+
+       /* Write back to the SLP register to cause the originally intended
+        * event again. We need to set BIT13 (SLP_EN) though to make the
+        * sleep happen.
+        */
+       outl(reg32 | SLP_EN, pmbase + PM1_CNT);
+
+       /* Make sure to stop executing code here for S3/S4/S5 */
+       if (slp_typ > 1)
+               hlt();
+
+       /* In most sleep states, the code flow of this function ends at
+        * the line above. However, if we entered sleep state S1 and wake
+        * up again, we will continue to execute code in this function.
+        */
+       reg32 = inl(pmbase + PM1_CNT);
+       if (reg32 & SCI_EN) {
+               /* The OS is not an ACPI OS, so we set the state to S0 */
+               reg32 &= ~(SLP_EN | SLP_TYP);
+               outl(reg32, pmbase + PM1_CNT);
+       }
+}
+
+static void southbridge_smi_apmc(unsigned int node, smm_state_save_area_t *state_save)
+{
+       u32 pmctrl;
+       u8 reg8;
+       void (*mainboard_apmc)(u8 apmc) = mainboard_smi_apmc;
+
+       /* Emulate B2 register as the FADT / Linux expects it */
+
+       reg8 = inb(APM_CNT);
+       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;
+       }
+
+       tseg_fixup((void **)&mainboard_apmc);
+       if (mainboard_apmc)
+               mainboard_apmc(reg8);
+}
+
+static void southbridge_smi_pm1(unsigned int node, smm_state_save_area_t *state_save)
+{
+       u16 pm1_sts;
+
+       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);
+       }
+}
+
+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)
+{
+       void (*mainboard_gpi)(u16 gpi_sts) = mainboard_smi_gpi;
+       u16 reg16;
+       reg16 = inw(pmbase + ALT_GP_SMI_STS);
+       outw(reg16, pmbase + ALT_GP_SMI_STS);
+
+       reg16 &= inw(pmbase + ALT_GP_SMI_EN);
+
+       tseg_fixup((void **)&mainboard_gpi);
+       if (mainboard_gpi) {
+               mainboard_gpi(reg16);
+       } else {
+               if (reg16)
+                       printk(BIOS_DEBUG, "GPI (mask %04x)\n",reg16);
+       }
+
+       outw(reg16, pmbase + ALT_GP_SMI_STS);
+}
+
+static void southbridge_smi_mc(unsigned int node, smm_state_save_area_t *state_save)
+{
+       u32 reg32;
+
+       reg32 = inl(pmbase + SMI_EN);
+
+       /* Are periodic SMIs enabled? */
+       if ((reg32 & MCSMI_EN) == 0)
+               return;
+
+       printk(BIOS_DEBUG, "Microcontroller SMI.\n");
+}
+
+
+
+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 = pcie_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");
+                       pcie_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 if (!tco_sts) {
+               dump_tco_status(tco_sts);
+       }
+}
+
+static void southbridge_smi_periodic(unsigned int node, smm_state_save_area_t *state_save)
+{
+       u32 reg32;
+
+       reg32 = inl(pmbase + SMI_EN);
+
+       /* Are periodic SMIs enabled? */
+       if ((reg32 & PERIODIC_EN) == 0)
+               return;
+
+       printk(BIOS_DEBUG, "Periodic SMI.\n");
+}
+
+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) << 2));
+       }
+
+
+       /* 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);
+
+static smi_handler_t southbridge_smi[32] = {
+       NULL,                     //  [0] reserved
+       NULL,                     //  [1] reserved
+       NULL,                     //  [2] BIOS_STS
+       NULL,                     //  [3] LEGACY_USB_STS
+       southbridge_smi_sleep,    //  [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
+       southbridge_smi_mc,       // [11] MCSMI_STS
+       NULL,                     // [12] DEVMON_STS
+       southbridge_smi_tco,      // [13] TCO_STS
+       southbridge_smi_periodic, // [14] PERIODIC_STS
+       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] EL_SMI_STS
+       NULL,                     // [26] SPI_STS
+       NULL,                     // [27] reserved
+       NULL,                     // [28] reserved
+       NULL,                     // [29] reserved
+       NULL,                     // [30] reserved
+       NULL                      // [31] reserved
+};
+
+/**
+ * @brief Interrupt handler for SMI#
+ *
+ * @param smm_revision revision of the smm state save map
+ */
+
+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 = pcie_read_config16(PCI_DEV(0, 0x1f, 0), 0x40) & 0xfffc;
+
+#if CONFIG_SMM_TSEG
+       /* Update global variable TSEG base */
+       tseg_base = pcie_read_config32(PCI_DEV(0, 0, 0), TSEG) & ~1;
+#endif
+
+       /* 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();
+
+       /* 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]) {
+#if CONFIG_SMM_TSEG
+                               smi_handler_t handler = (smi_handler_t)
+                                       ((u8*)southbridge_smi[i] + tseg_base);
+                               if (handler)
+                                       handler(node, state_save);
+#else
+                               southbridge_smi[i](node, state_save);
+#endif
+                       } else {
+                               printk(BIOS_DEBUG, "SMI_STS[%d] occured, but no "
+                                               "handler available.\n", i);
+                               dump = 1;
+                       }
+               }
+       }
+
+       if(dump) {
+               dump_smi_status(smi_sts);
+       }
+
+}
diff --git a/src/southbridge/intel/bd82x6x/usb_debug.c b/src/southbridge/intel/bd82x6x/usb_debug.c
new file mode 100644 (file)
index 0000000..4258a03
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdint.h>
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+#include <console/console.h>
+#include <usbdebug.h>
+#include <device/pci_def.h>
+#include "pch.h"
+
+/* Required for successful build, but currently empty. */
+void set_debug_port(unsigned int port)
+{
+       /* Not needed, the ICH* southbridges hardcode physical USB port 1. */
+}
+
+void enable_usbdebug(unsigned int port)
+{
+       u32 dbgctl;
+       device_t dev = PCI_DEV(0, 0x1d, 7); /* USB EHCI, D29:F7 */
+
+       /* Set the EHCI BAR address. */
+       pci_write_config32(dev, EHCI_BAR_INDEX, CONFIG_EHCI_BAR);
+
+       /* Enable access to the EHCI memory space registers. */
+       pci_write_config8(dev, PCI_COMMAND, PCI_COMMAND_MEMORY);
+
+       /* Force ownership of the Debug Port to the EHCI controller. */
+       printk(BIOS_DEBUG, "Enabling OWNER_CNT\n");
+       dbgctl = read32(CONFIG_EHCI_BAR + CONFIG_EHCI_DEBUG_OFFSET);
+       dbgctl |= (1 << 30);
+       write32(CONFIG_EHCI_BAR + CONFIG_EHCI_DEBUG_OFFSET, dbgctl);
+}
+
diff --git a/src/southbridge/intel/bd82x6x/usb_ehci.c b/src/southbridge/intel/bd82x6x/usb_ehci.c
new file mode 100644 (file)
index 0000000..c299535
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include "pch.h"
+#include <usbdebug.h>
+#include <arch/io.h>
+
+static void usb_ehci_init(struct device *dev)
+{
+       u32 reg32;
+
+       /* Disable Wake on Disconnect in RMH */
+       reg32 = RCBA32(0x35b0);
+       reg32 |= 0x22;
+       RCBA32(0x35b0) = reg32;
+
+       printk(BIOS_DEBUG, "EHCI: Setting up controller.. ");
+       reg32 = pci_read_config32(dev, PCI_COMMAND);
+       reg32 |= PCI_COMMAND_MASTER;
+       //reg32 |= PCI_COMMAND_SERR;
+       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 void usb_ehci_set_resources(struct device *dev)
+{
+#if CONFIG_USBDEBUG
+       struct resource *res;
+       u32 base;
+       u32 usb_debug;
+
+       usb_debug = get_ehci_debug();
+       set_ehci_debug(0);
+#endif
+       pci_dev_set_resources(dev);
+
+#if CONFIG_USBDEBUG
+       res = find_resource(dev, 0x10);
+       set_ehci_debug(usb_debug);
+       if (!res) return;
+       base = res->base;
+       set_ehci_base(base);
+       report_resource_stored(dev, res, "");
+#endif
+}
+
+
+
+static struct pci_operations lops_pci = {
+       .set_subsystem  = &usb_ehci_set_subsystem,
+};
+
+static struct device_operations usb_ehci_ops = {
+       .read_resources         = pci_dev_read_resources,
+       .set_resources          = usb_ehci_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,
+       .device = 0x1c26,
+};
+static const struct pci_driver pch_usb_ehci2 __pci_driver = {
+       .ops    = &usb_ehci_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1c2d,
+};
+static const struct pci_driver pch_usb_ehci3 __pci_driver = {
+       .ops    = &usb_ehci_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1e26,
+};
+static const struct pci_driver pch_usb_ehci4 __pci_driver = {
+       .ops    = &usb_ehci_ops,
+       .vendor = PCI_VENDOR_ID_INTEL,
+       .device = 0x1e2d,
+};
diff --git a/src/southbridge/intel/bd82x6x/watchdog.c b/src/southbridge/intel/bd82x6x/watchdog.c
new file mode 100644 (file)
index 0000000..362e896
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008-2009 coresystems GmbH
+ * Copyright (C) 2011 Google Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <console/console.h>
+#include <arch/io.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <watchdog.h>
+
+  //
+  //  Disable PCH Watchdog timer at SB_RCBA+0x3410
+  //
+  //  Mmio32((MmPci32(0, 0, 0x1F, 0, 0xF0) & ~BIT0), 0x3410) |= 0x20;
+  //
+void watchdog_off(void)
+{
+       device_t dev;
+       unsigned long value, base;
+
+       /* Turn off the ICH7 watchdog. */
+       dev = dev_find_slot(0, PCI_DEVFN(0x1f, 0));
+
+       /* Enable I/O space. */
+       value = pci_read_config16(dev, 0x04);
+       value |= (1 << 10);
+       pci_write_config16(dev, 0x04, value);
+
+       /* Get TCO base. */
+       base = (pci_read_config32(dev, 0x40) & 0x0fffe) + 0x60;
+
+       /* Disable the watchdog timer. */
+       value = inw(base + 0x08);
+       value |= 1 << 11;
+       outw(value, base + 0x08);
+
+       /* Clear TCO timeout status. */
+       outw(0x0008, base + 0x04);
+       outw(0x0002, base + 0x06);
+
+       printk(BIOS_DEBUG, "PCH watchdog disabled\n");
+}