Patchwork sb800 code derived from sb700 implementation

login
register
about
Submitter She, Kerry
Date 2011-01-04 08:12:01
Message ID <F53A09371FB723428826B442A4B20A41048FF665@sbjgexmb1.amd.com>
Download mbox | patch
Permalink /patch/2484/
State New
Headers show

Comments

She, Kerry - 2011-01-04 08:12:01
Sorry to send again, forget the subject last email

 

I have made a little bit cleanup from the patches originally made by Bao Zheng,

This sb800 code is derived from sb700 implementation.

Release this patch is NOT to confusing people, but make other patches based on this implementation also works. 

 

So this patch don’t need to be checked into the tree. 

 

Regards, 
Kerry She < kerry.she@amd.com>
Tel:  86-10-6280-1415
sb800 support, non CIMx wrapper way
bimini mainboard should do following modification to use 'non CIMx wrapper way' sb800 code

have two versions may be confusing, it doesn't need to checked into the tree
sb800 support, non CIMx wrapper way
this sb800 code is derived from sb700 implementation.

have two versions may be confusing, it doesn't need to be checked into the tree.
Peter Stuge - 2011-01-04 11:21:26
She, Kerry wrote:
> I have made a little bit cleanup from the patches originally made
> by Bao Zheng,
> 
> This sb800 code is derived from sb700 implementation.
> 
> Release this patch is NOT to confusing people, but make other
> patches based on this implementation also works.
> 
> So this patch don’t need to be checked into the tree. 

Thanks! I think this is a nice addition. Maybe we should add a
Kconfig option to choose between cimx and non-cimx?


//Peter
Stefan Reinauer - 2011-01-04 21:07:52
* Peter Stuge <peter@stuge.se> [110104 12:21]:
> She, Kerry wrote:
> Thanks! I think this is a nice addition. Maybe we should add a
> Kconfig option to choose between cimx and non-cimx?

I think we should, once we actually hit a use case.
Peter Stuge - 2011-01-04 21:18:42
Stefan Reinauer wrote:
> > Maybe we should add a Kconfig option to choose between cimx and
> > non-cimx?
> 
> I think we should, once we actually hit a use case.

Um? This is the case right here. I say add it now and get the patch
commited, then can remove in future if not used.


//Peter
Stefan Reinauer - 2011-01-04 21:21:37
* Peter Stuge <peter@stuge.se> [110104 22:18]:
> Stefan Reinauer wrote:
> > > Maybe we should add a Kconfig option to choose between cimx and
> > > non-cimx?
> > 
> > I think we should, once we actually hit a use case.
> 
> Um? This is the case right here.

Oh? Which board? I thought the patch said "for reference only, not for
checkin". Sorry if I missed something.

Stefan
Carl-Daniel Hailfinger - 2011-01-04 23:05:02
Auf 04.01.2011 22:21, Stefan Reinauer schrieb:
> * Peter Stuge <peter@stuge.se> [110104 22:18]:
>   
>> Stefan Reinauer wrote:
>>     
>>>> Maybe we should add a Kconfig option to choose between cimx and
>>>> non-cimx?
>>>>         
>>> I think we should, once we actually hit a use case.
>>>       
>> Um? This is the case right here.
>>     
> Oh? Which board? I thought the patch said "for reference only, not for
> checkin". Sorry if I missed something.
>   

Still, having the code checked in is IMHO better than having it on the
list. If there are any CIMx integration issues later, we still have the
alternative code (and as a nice benefit, we can actually touch that code
whereas CIMx should be kept unchanged to allow easier updates).

Regards,
Carl-Daniel
Stefan Reinauer - 2011-01-05 00:11:23
* Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net> [110105 00:05]:
> Still, having the code checked in is IMHO better than having it on the
> list. If there are any CIMx integration issues later, we still have the
> alternative code (and as a nice benefit, we can actually touch that code
> whereas CIMx should be kept unchanged to allow easier updates).

I would prefer to see CIMx integration issues fixed rather than worked
around with an in-tree fork for a non-existant user base that might
experience problems in the unforseeable future.

There is nothing that prevents us from reporting issues with the CIMx
code back to AMD to have it fixed.

Stefan

Patch

Index: trunk/src/southbridge/amd/Kconfig
===================================================================
--- trunk.orig/src/southbridge/amd/Kconfig
+++ trunk/src/southbridge/amd/Kconfig
@@ -11,3 +11,4 @@  source src/southbridge/amd/sb600/Kconfig
 source src/southbridge/amd/rs780/Kconfig
 source src/southbridge/amd/sb700/Kconfig
 source src/southbridge/amd/cimx_wrapper/Kconfig
+source src/southbridge/amd/sb800/Kconfig
Index: trunk/src/southbridge/amd/Makefile.inc
===================================================================
--- trunk.orig/src/southbridge/amd/Makefile.inc
+++ trunk/src/southbridge/amd/Makefile.inc
@@ -10,4 +10,5 @@  subdirs-$(CONFIG_SOUTHBRIDGE_AMD_CS5530)
 subdirs-$(CONFIG_SOUTHBRIDGE_AMD_CS5535) += cs5535
 subdirs-$(CONFIG_SOUTHBRIDGE_AMD_CS5536) += cs5536
 subdirs-$(CONFIG_SOUTHBRIDGE_AMD_CIMX_WRAPPER) += cimx_wrapper
+subdirs-$(CONFIG_SOUTHBRIDGE_AMD_SB800) += sb800
 
Index: trunk/src/southbridge/amd/sb800/bootblock.c
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/bootblock.c
@@ -0,0 +1,113 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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 <arch/io.h>
+#include <arch/romcc_io.h>
+
+#if CONFIG_SERIAL_POST == 1
+
+/* Data */
+#define UART_RBR 0x00
+#define UART_TBR 0x00
+
+/* Control */
+#define UART_IER 0x01
+#define UART_IIR 0x02
+#define UART_FCR 0x02
+#define UART_LCR 0x03
+#define UART_MCR 0x04
+#define UART_DLL 0x00
+#define UART_DLM 0x01
+
+/* Status */
+#define UART_LSR 0x05
+#define UART_MSR 0x06
+#define UART_SCR 0x07
+
+#ifndef CONFIG_TTYS0_DIV
+#if ((115200%CONFIG_TTYS0_BAUD) != 0)
+#error Bad ttys0 baud rate
+#endif
+#define CONFIG_TTYS0_DIV	(115200/CONFIG_TTYS0_BAUD)
+#endif // CONFIG_TTYS0_DIV
+
+#define UART_LCS	CONFIG_TTYS0_LCS
+
+#endif // CONFIG_SERIAL_POST == 1
+
+static void sb800_enable_rom(void)
+{
+	u32 word;
+	u32 dword;
+	device_t dev;
+
+	dev = PCI_DEV(0, 0x14, 0x03);
+	/* SB800 LPC Bridge 0:20:3:44h.
+	 * BIT6: Port Enable for serial port 0x3f8-0x3ff
+	 * BIT29: Port Enable for KBC port 0x60 and 0x64
+	 * BIT30: Port Enable for ACPI Micro-Controller port 0x66 and 0x62
+	 */
+	dword = pci_io_read_config32(dev, 0x44);
+	//dword |= (1<<6) | (1<<29) | (1<<30) ;
+	/*Turn on all of LPC IO Port decode enable */
+	dword = 0xffffffff;
+	pci_io_write_config32(dev, 0x44, dword);
+
+	/* SB800 LPC Bridge 0:20:3:48h.
+	 * BIT0: Port Enable for SuperIO 0x2E-0x2F
+	 * BIT1: Port Enable for SuperIO 0x4E-0x4F
+	 * BIT4: Port Enable for LPC ROM Address Arrage2 (0x68-0x6C)
+	 * BIT6: Port Enable for RTC IO 0x70-0x73
+	 * BIT21: Port Enable for Port 0x80
+	 */
+	dword = pci_io_read_config32(dev, 0x48);
+	dword |= (1<<0) | (1<<1) | (1<<4) | (1<<6) | (1<<21) ;
+	pci_io_write_config32(dev, 0x48, dword);
+
+	/* Enable 2MB rom access at 0xFFE00000 - 0xFFFFFFFF */
+	/* Set the 2MB enable bits */
+	word = pci_io_read_config16(dev, 0x6c);
+	word = 0xFFE0;
+	pci_io_write_config16(dev, 0x6c, word);
+}
+
+/*
+ * For peanuts
+ */
+static void uart_init(void)
+{
+#if CONFIG_SERIAL_POST == 1
+	/* disable interrupts */
+	outb(0x0, CONFIG_TTYS0_BASE + UART_IER);
+	/* enable fifo's */
+	outb(0x01, CONFIG_TTYS0_BASE + UART_FCR);
+	/* Set Baud Rate Divisor to 12 ==> 115200 Baud */
+	outb(0x80 | UART_LCS, CONFIG_TTYS0_BASE + UART_LCR);
+	outb(CONFIG_TTYS0_DIV & 0xFF,   CONFIG_TTYS0_BASE + UART_DLL);
+	outb((CONFIG_TTYS0_DIV >> 8) & 0xFF,    CONFIG_TTYS0_BASE + UART_DLM);
+	outb(UART_LCS, CONFIG_TTYS0_BASE + UART_LCR);
+#endif // CONFIG_SERIAL_POST == 1
+}
+
+static void bootblock_southbridge_init(void)
+{
+	/* Setup the rom access for 2M */
+	sb800_enable_rom();
+	uart_init();
+}
Index: trunk/src/southbridge/amd/sb800/chip.h
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/chip.h
@@ -0,0 +1,31 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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 SB800_CHIP_H
+#define SB800_CHIP_H
+
+struct southbridge_amd_sb800_config
+{
+	u32 boot_switch_sata_ide : 1;
+	u8  gpp_configuration;
+};
+struct chip_operations;
+extern struct chip_operations southbridge_amd_sb800_ops;
+
+#endif /* SB800_CHIP_H */
Index: trunk/src/southbridge/amd/sb800/early_setup.c
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/early_setup.c
@@ -0,0 +1,643 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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  _SB800_EARLY_SETUP_C_
+#define  _SB800_EARLY_SETUP_C_
+
+#include <reset.h>
+#include <arch/cpu.h>
+#include "sb800.h"
+#include "smbus.c"
+
+#define SMBUS_IO_BASE 0x6000	/* Is it a temporary SMBus I/O base address? */
+	 /*SIZE 0x40 */
+
+static void pmio_write(u8 reg, u8 value)
+{
+	outb(reg, PM_INDEX);
+	outb(value, PM_INDEX + 1);
+}
+
+static u8 pmio_read(u8 reg)
+{
+	outb(reg, PM_INDEX);
+	return inb(PM_INDEX + 1);
+}
+
+/* RPR 2.28 Get SB ASIC Revision.*/
+static u8 get_sb800_revision(void)
+{
+	device_t dev;
+	u8 rev_id;
+	u8 rev = 0;
+
+	/* if (rev != 0) return rev; */
+
+	dev = PCI_DEV(0, 0x14, 0);//pci_locate_device(PCI_ID(0x1002, 0x4385), 0);
+
+	if (dev == PCI_DEV_INVALID) {
+		die("SMBUS controller not found\n");
+		/* NOT REACHED */
+	}
+	rev_id =  pci_read_config8(dev, 0x08);
+
+	if (rev_id == 0x40) {
+		rev = REV_SB800_A11;
+	} else if (rev_id == 0x41) {
+		rev = REV_SB800_A12;
+	} else {
+		die("It is not SB800 or SB810\r\n");
+	}
+
+	return rev;
+}
+
+#if 0
+static void sb800_clk_output_48Mhz(void)
+{
+	/* AcpiMMioDecodeEn */
+	u8 reg8;
+	reg8 = pmio_read(0x24);
+	reg8 |= 1;
+	reg8 &= ~(1 << 1);
+	pmio_write(0x24, reg8);
+
+	*(volatile u32 *)(0xFED80000+0xE00+0x40) &= ~((1 << 0) | (1 << 2)); /* 48Mhz */
+	*(volatile u32 *)(0xFED80000+0xE00+0x40) |= 1 << 1; /* 48Mhz */
+}
+#endif
+
+/***************************************
+* Legacy devices are mapped to LPC space.
+*	Serial port 0
+*	KBC Port
+*	ACPI Micro-controller port
+*	LPC ROM size
+*	This function does not change port 0x80 decoding.
+*	Console output through any port besides 0x3f8 is unsupported.
+*	If you use FWH ROMs, you have to setup IDSEL.
+***************************************/
+static void sb800_lpc_init(void)
+{
+	u8 reg8;
+	device_t dev;
+
+	//dev = pci_locate_device(PCI_ID(0x1002, 0x4385), 0);	/* SMBUS controller */
+	dev = PCI_DEV(0, 0x14, 0);
+	/* NOTE: Set BootTimerDisable, otherwise it would keep rebooting!!
+	 * This bit has no meaning if debug strap is not enabled. So if the
+	 * board keeps rebooting and the code fails to reach here, we could
+	 * disable the debug strap first. */
+	reg8 = pmio_read(0x44+3);
+	reg8 |= 1 << 7;
+	pmio_write(0x44+3, reg8);
+
+	/* Enable lpc controller */
+	reg8 = pmio_read(0xEC);
+	reg8 |= 1 << 0;
+	pmio_write(0xEC, reg8);
+
+	dev = PCI_DEV(0, 0x14, 3);//pci_locate_device(PCI_ID(0x1002, 0x439d), 0);	/* LPC Controller */
+	/* Decode port 0x3f8-0x3ff (Serial 0) */
+	//#warning Serial port decode on LPC is hardcoded to 0x3f8
+	reg8 = pci_read_config8(dev, 0x44);
+	reg8 |= 1 << 6;
+	pci_write_config8(dev, 0x44, reg8);
+
+	/* Decode port 0x60 & 0x64 (PS/2 keyboard) and port 0x62 & 0x66 (ACPI)*/
+	reg8 = pci_read_config8(dev, 0x47);
+	reg8 |= (1 << 5) | (1 << 6);
+	pci_write_config8(dev, 0x47, reg8);
+
+	/* SuperIO, LPC ROM */
+	reg8 = pci_read_config8(dev, 0x48);
+	/* Decode ports 0x2e-0x2f, 0x4e-0x4f (SuperI/O configuration) */
+	reg8 |= (1 << 1) | (1 << 0);
+	/* Decode variable LPC ROM address ranges 1&2 (see register 0x68-0x6b, 0x6c-0x6f) */
+	reg8 |= (1 << 3) | (1 << 4);
+	/* Decode port 0x70-0x73 (RTC) */
+	reg8 |= 1 << 6;
+	pci_write_config8(dev, 0x48, reg8);
+
+	/* hardware should enable LPC ROM by pin straps */
+	/* ROM access at 0xFFF80000/0xFFF00000 - 0xFFFFFFFF */
+	/* See detail in 43366_sb800_bdg_nda_1.01.pdf page 17. */
+	/* enable LPC ROM range mirroring start 0x000e(0000) */
+	pci_write_config16(dev, 0x68, 0x000e);
+	/* enable LPC ROM range mirroring end   0x000f(ffff) */
+	pci_write_config16(dev, 0x6a, 0x000f);
+	/* enable LPC ROM range start, 0xfff8(0000): 512KB, 0xfff0(0000): 1MB, 0xffe0: 2MB. */
+	pci_write_config16(dev, 0x6c, 0xffe0);
+	/* enable LPC ROM range end at 0xffff(ffff) */
+	pci_write_config16(dev, 0x6e, 0xffff);
+}
+
+/* what is its usage? */
+static u32 get_sbdn(u32 bus)
+{
+	device_t dev;
+
+	/* Find the device. */
+	dev = PCI_DEV(bus, 0x14, 0);//pci_locate_device_on_bus(PCI_ID(0x1002, 0x4385), bus);
+	return (dev >> 15) & 0x1f;
+}
+
+#if 0
+static u8 dual_core(void)
+{
+	return (pci_read_config32(PCI_DEV(0, 0x18, 3), 0xE8) & (0x3<<12)) != 0;
+}
+
+/*
+ * RPR 2.6 C-state and VID/FID change for the K8 platform.
+ */
+static void enable_fid_change_on_sb(u32 sbbusn, u32 sbdn)
+{
+	u8 byte;
+	byte = pmio_read(0x80);
+	if (dual_core())
+		byte |= 1 << 2 | 1 << 1;
+	byte |= 1 << 3;
+	byte |= 1 << 4;
+	byte &= ~(1 << 7);
+	pmio_write(0x80, byte);
+
+	byte = pmio_read(0x7E);
+	byte |= 1 << 6;
+	byte &= ~(1 << 2);
+	pmio_write(0x7E, byte);
+
+	pmio_write(0x94, 0x01);
+
+	byte = pmio_read(0x89);
+	byte |= 1 << 4;
+	pmio_write(0x89, byte);
+
+	byte = pmio_read(0x9b);
+	byte &= ~(7 << 4);
+	byte |= 1 << 4;
+	pmio_write(0x9b, byte);
+
+	pmio_write(0x99, 0x10);
+
+	pmio_write(0x9A, 0x00);
+	pmio_write(0x96, 0x10);
+	pmio_write(0x97, 0x00);
+
+	byte = pmio_read(0x81);
+	byte &= ~(1 << 1);
+	pmio_write(0x81, byte);
+}
+#endif
+
+void hard_reset(void)
+{
+	set_bios_reset();
+
+	/* full reset */
+	outb(0x0a, 0x0cf9);
+	outb(0x0e, 0x0cf9);
+}
+
+#if 0
+void soft_reset(void)
+{
+	set_bios_reset();
+	/* link reset */
+	outb(0x06, 0x0cf9);
+}
+#endif
+
+void sb800_pci_port80(void)
+{
+	u8 byte;
+	device_t dev;
+
+	/* P2P Bridge */
+	dev = PCI_DEV(0, 0x14, 4);//pci_locate_device(PCI_ID(0x1002, 0x4384), 0);
+
+	/* Chip Control: Enable subtractive decoding */
+	byte = pci_read_config8(dev, 0x40);
+	byte |= 1 << 5;
+	pci_write_config8(dev, 0x40, byte);
+
+	/* Misc Control: Enable subtractive decoding if 0x40 bit 5 is set */
+	byte = pci_read_config8(dev, 0x4B);
+	byte |= 1 << 7;
+	pci_write_config8(dev, 0x4B, byte);
+
+	/* The same IO Base and IO Limit here is meaningful because we set the
+	 * bridge to be subtractive. During early setup stage, we have to make
+	 * sure that data can go through port 0x80.
+	 */
+	/* IO Base: 0xf000 */
+	byte = pci_read_config8(dev, 0x1C);
+	byte |= 0xF << 4;
+	pci_write_config8(dev, 0x1C, byte);
+
+	/* IO Limit: 0xf000 */
+	byte = pci_read_config8(dev, 0x1D);
+	byte |= 0xF << 4;
+	pci_write_config8(dev, 0x1D, byte);
+
+	/* PCI Command: Enable IO response */
+	byte = pci_read_config8(dev, 0x04);
+	byte |= 1 << 0;
+	pci_write_config8(dev, 0x04, byte);
+
+	/* LPC controller */
+	dev = PCI_DEV(0, 0x14, 3);;//pci_locate_device(PCI_ID(0x1002, 0x439D), 0);
+
+	byte = pci_read_config8(dev, 0x4A);
+	byte &= ~(1 << 5);	/* disable lpc port 80 */
+	pci_write_config8(dev, 0x4A, byte);
+}
+#define BIT0	(1 << 0)
+#define BIT1	(1 << 1)
+#define BIT2	(1 << 2)
+#define BIT3	(1 << 3)
+#define BIT4	(1 << 4)
+#define BIT5	(1 << 5)
+#define BIT6	(1 << 6)
+#define BIT7	(1 << 7)
+
+struct pm_entry {
+	u8	port;
+	u8	mask;
+	u8	bit;
+};
+struct pm_entry const pm_table[] =
+{
+  {0x5D, 0x00, BIT0},
+  {0xD2, 0xCF, BIT4 + BIT5},
+  {0x12, 0x00, BIT0},
+  {0x28, 0xFF, BIT0},
+  {0x44 + 3, 0x7F, BIT7},
+  {0x48, 0xFF, BIT0},
+  {0x00, 0xFF, 0x0E},
+  {0x00 + 2, 0xFF, 0x40},
+  {0x00 + 3, 0xFF, 0x08},
+  {0x34, 0xEF, BIT0 + BIT1},
+  {0xEC, 0xFD, BIT1},
+  {0x5B, 0xF9, BIT1 + BIT2},
+  {0x08, 0xFE, BIT2 + BIT4},
+  {0x08 + 1, 0xFF, BIT0},
+  {0x54, 0x00, BIT4 + BIT7},
+  {0x04 + 3, 0xFD, BIT1},
+  {0x74, 0xF6, BIT0 + BIT3},
+  {0xF0, ~BIT2, 0x00},
+  {0xF8,     0x00, 0x6C},
+  {0xF8 + 1, 0x00, 0x27},
+  {0xF8 + 2, 0x00, 0x00},
+  {0xC4, 0xFE, 0x14},
+  {0xC0 + 2, 0xBF, 0x40},
+  {0xBE, 0xDD, BIT5},
+  // HPET workaround
+  {0x54 + 3, 0xFC, BIT0 + BIT1},
+  {0x54 + 2, 0x7F, BIT7},
+  {0x54 + 2, 0x7F, 0x00},
+  {0xC4, ~(BIT2 + BIT4), BIT2 + BIT4},
+  {0xC0, 0, 0xF9},
+  {0xC0 + 1, 0x04, 0x03},
+  {0xC2, 0x20, 0x58},
+  {0xC2 + 1, 0, 0x40},
+  {0xC2, ~(BIT4), BIT4},
+  {0x74, 0x00, BIT0 + BIT1 + BIT2 + BIT4},
+  {0xDE + 1, ~(BIT0 + BIT1), BIT0 + BIT1},
+  {0xDE, ~BIT4, BIT4},
+  {0xBA, ~BIT3, BIT3},
+  {0xBA + 1, ~BIT6, BIT6},
+  {0xBC, ~BIT1, BIT1},
+  {0xED, ~(BIT0 + BIT1), 0},
+  {0xDC, 0x7C, BIT0},
+
+//  {0xFF, 0xFF, 0xFF},
+  
+};
+
+void sb800_lpc_port80(void)
+{
+	u8 byte;
+	device_t dev;
+
+	/* Enable LPC controller */
+	byte = pmio_read(0xEC);
+	byte |= 1 << 0;
+	pmio_write(0xEC, byte);
+
+	/* Enable port 80 LPC decode in pci function 3 configuration space. */
+	dev = PCI_DEV(0, 0x14, 3);//pci_locate_device(PCI_ID(0x1002, 0x439D), 0);
+	byte = pci_read_config8(dev, 0x4a);
+	byte |= 1 << 5;		/* enable port 80 */
+	pci_write_config8(dev, 0x4a, byte);
+}
+
+/* sbDevicesPorInitTable */
+static void sb800_devices_por_init(void)
+{
+	device_t dev;
+	u8 byte;
+
+	printk(BIOS_INFO, "sb800_devices_por_init()\n");
+	/* SMBus Device, BDF:0-20-0 */
+	printk(BIOS_INFO, "sb800_devices_por_init(): SMBus Device, BDF:0-20-0\n");
+	dev = PCI_DEV(0, 0x14, 0);//pci_locate_device(PCI_ID(0x1002, 0x4385), 0);
+
+	if (dev == PCI_DEV_INVALID) {
+		die("SMBUS controller not found\n");
+		/* NOT REACHED */
+	}
+	printk(BIOS_INFO, "SMBus controller enabled, sb revision is A%x\n",
+		    get_sb800_revision());
+
+	/* sbPorAtStartOfTblCfg */
+	/* rpr 4.1.Set A-Link bridge access address.
+	 * This is an I/O address. The I/O address must be on 16-byte boundry.  */
+	//pci_write_config32(dev, 0xf0, AB_INDX);
+	pmio_write(0xE0, AB_INDX & 0xFF);
+	pmio_write(0xE1, (AB_INDX >> 8) & 0xFF);
+	pmio_write(0xE2, (AB_INDX >> 16) & 0xFF);
+	pmio_write(0xE3, (AB_INDX >> 24) & 0xFF);
+
+	/* To enable AB/BIF DMA access, a specific register inside the BIF register space needs to be configured first. */
+	/* 4.2:Enables the SB800 to send transactions upstream over A-Link Express interface. */
+	axcfg_reg(0x04, 1 << 2, 1 << 2);
+	//axindxc_reg(0x21, 0xff, 0);
+
+	/* 4.15:Enabling Non-Posted Memory Write for the K8 Platform */
+	axindxc_reg(0x10, 1 << 9, 1 << 9);
+	/* END of sbPorAtStartOfTblCfg */
+
+	/* sbDevicesPorInitTables */
+	/* set smbus iobase */
+	//pci_write_config32(dev, 0x90, SMBUS_IO_BASE | 1);
+	/* The base address of SMBUS is set in a different way with sb700. */
+	byte = (SMBUS_IO_BASE & 0xFF) | 1;
+	pmio_write(0x2c, byte & 0xFF);
+	pmio_write(0x2d, SMBUS_IO_BASE >> 8);
+
+	/* AcpiMMioDecodeEn */
+	byte = pmio_read(0x24);
+	byte |= 1;
+	byte &= ~(1 << 1);
+	pmio_write(0x24, byte);
+	/* enable smbus controller interface */
+	//byte = pci_read_config8(dev, 0xd2);
+	//byte |= (1 << 0);
+	//pci_write_config8(dev, 0xd2, byte);
+
+	/* KB2RstEnable */
+	//pci_write_config8(dev, 0x40, 0x44);
+
+	/* Enable ISA Address 0-960K decoding */
+	//pci_write_config8(dev, 0x48, 0x0f);
+
+	/* Enable ISA  Address 0xC0000-0xDFFFF decode */
+	//pci_write_config8(dev, 0x49, 0xff);
+
+	/* Enable decode cycles to IO C50, C51, C52 GPM controls. */
+	//byte = pci_read_config8(dev, 0x41);
+	//byte &= 0x80;
+	//byte |= 0x33;
+	//pci_write_config8(dev, 0x41, byte);
+
+	/* Legacy DMA Prefetch Enhancement, CIM masked it. */
+	/* pci_write_config8(dev, 0x43, 0x1); */
+
+	/* clear any lingering errors, so the transaction will run */
+	outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
+
+	/* IDE Device, BDF:0-20-1 */
+	printk(BIOS_INFO, "sb800_devices_por_init(): IDE Device, BDF:0-20-1\n");
+	dev = PCI_DEV(0, 0x14, 1);//pci_locate_device(PCI_ID(0x1002, 0x439C), 0);
+	/* Disable prefetch */
+	byte = pci_read_config8(dev, 0x63);
+	byte |= 0x1;
+	pci_write_config8(dev, 0x63, byte);
+
+	/* LPC Device, BDF:0-20-3 */
+	printk(BIOS_INFO, "sb800_devices_por_init(): LPC Device, BDF:0-20-3\n");
+	dev = PCI_DEV(0, 0x14, 3);//pci_locate_device(PCI_ID(0x1002, 0x439D), 0);
+	/* DMA enable */
+	pci_write_config8(dev, 0x40, 0x04);
+
+	/* IO Port Decode Enable */
+	pci_write_config8(dev, 0x44, 0xFF);
+	pci_write_config8(dev, 0x45, 0xFF);
+	pci_write_config8(dev, 0x46, 0xC3);
+	pci_write_config8(dev, 0x47, 0xFF);
+
+	/* IO/Mem Port Decode Enable, I don't know why CIM disable some ports.
+	 *  Disable LPC TimeOut counter, enable SuperIO Configuration Port (2e/2f),
+	 * Alternate SuperIO Configuration Port (4e/4f), Wide Generic IO Port (64/65).
+	 * Enable bits for LPC ROM memory address range 1&2 for 1M ROM setting.*/
+	byte = pci_read_config8(dev, 0x48);
+	byte |= (1 << 1) | (1 << 0);	/* enable Super IO config port 2e-2h, 4e-4f */
+	byte |= (1 << 3) | (1 << 4);	/* enable for LPC ROM address range1&2, Enable 512KB rom access at 0xFFF80000 - 0xFFFFFFFF */
+	byte |= 1 << 6;		/* enable for RTC I/O range */
+	pci_write_config8(dev, 0x48, byte);
+	pci_write_config8(dev, 0x49, 0xFF);
+	/* Enable 0x480-0x4bf, 0x4700-0x470B */
+	byte = pci_read_config8(dev, 0x4A);
+	byte |= ((1 << 1) + (1 << 6));	/*0x42, save the configuraion for port 0x80. */
+	pci_write_config8(dev, 0x4A, byte);
+
+	/* Set LPC ROM size, it has been done in sb800_lpc_init().
+	 * enable LPC ROM range, 0xfff8: 512KB, 0xfff0: 1MB;
+	 * enable LPC ROM range, 0xfff8: 512KB, 0xfff0: 1MB
+	 * pci_write_config16(dev, 0x68, 0x000e)
+	 * pci_write_config16(dev, 0x6c, 0xfff0);*/
+
+	/* Enable Tpm12_en and Tpm_legacy. I don't know what is its usage and copied from CIM. */
+	pci_write_config8(dev, 0x7C, 0x05);
+
+	/* P2P Bridge, BDF:0-20-4, the configuration of the registers in this dev are copied from CIM,
+	 */
+	printk(BIOS_INFO, "sb800_devices_por_init(): P2P Bridge, BDF:0-20-4\n");
+	dev = PCI_DEV(0, 0x14, 4);//pci_locate_device(PCI_ID(0x1002, 0x4384), 0);
+
+	/* Arbiter enable. */
+	pci_write_config8(dev, 0x43, 0xff);
+
+	/* Set PCDMA request into hight priority list. */
+	/* pci_write_config8(dev, 0x49, 0x1) */ ;
+
+	pci_write_config8(dev, 0x40, 0x26);
+
+	pci_write_config8(dev, 0x0d, 0x40);
+	pci_write_config8(dev, 0x1b, 0x40);
+	/* Enable PCIB_DUAL_EN_UP will fix potential problem with PCI cards. */
+	pci_write_config8(dev, 0x50, 0x01);
+
+	/* SATA Device, BDF:0-17-0, Non-Raid-5 SATA controller */
+	printk(BIOS_INFO, "sb800_devices_por_init(): SATA Device, BDF:0-18-0\n");
+	dev = PCI_DEV(0, 0x11, 0);//pci_locate_device(PCI_ID(0x1002, 0x4390), 0);
+
+	/*PHY Global Control*/
+	pci_write_config16(dev, 0x86, 0x2C00);
+}
+
+#ifdef UNUSED_CODE
+/* sbPmioPorInitTable, Pre-initializing PMIO register space
+* The power management (PM) block is resident in the PCI/LPC/ISA bridge.
+* The PM regs are accessed via IO mapped regs 0xcd6 and 0xcd7.
+* The index address is first programmed into IO reg 0xcd6.
+* Read or write values are accessed through IO reg 0xcd7.
+*/
+static void sb800_pmio_por_init(void)
+{
+	u8 byte, i;
+
+	printk(BIOS_INFO, "sb800_pmio_por_init()\n");
+
+	byte = pmio_read(0xD2);
+	byte |= 3 << 4;
+	pmio_write(0xD2, byte);
+
+	byte = pmio_read(0x5D);
+	byte &= 3;
+	byte |= 1;
+	pmio_write(0x5D, byte);
+
+	/* Watch Dog Timer Control
+	 * Set watchdog time base to 0xfec000f0 to avoid SCSI card boot failure.
+	 * But I don't find WDT is enabled in SMBUS 0x41 bit3 in CIM.
+	 */
+	pmio_write(0x6c, 0xf0);
+	pmio_write(0x6d, 0x00);
+	pmio_write(0x6e, 0xc0);
+	pmio_write(0x6f, 0xfe);
+
+	/* rpr2.15: Enabling Spread Spectrum */
+	byte = pmio_read(0x42);
+	byte |= 1 << 7;
+	pmio_write(0x42, byte);
+	/* TODO: Check if it is necessary. IDE reset */
+	byte = pmio_read(0xB2);
+	byte |= 1 << 0;
+	pmio_write(0xB2, byte);
+
+	for (i=0; i<sizeof(pm_table)/sizeof(struct pm_entry); i++) {
+		byte = pmio_read(pm_table[i].port);
+		byte &= pm_table[i].mask;
+		byte |= pm_table[i].bit;
+		pmio_write(pm_table[i].port, byte);
+	}
+	pmio_write(0x00, 0x0E);
+	pmio_write(0x01, 0x00);
+	pmio_write(0x02, 0x4F);
+	pmio_write(0x03, 0x4A);
+}
+#endif
+
+/*
+* Add any south bridge setting.
+*/
+static void sb800_pci_cfg(void)
+{
+	device_t dev;
+	u8 byte;
+
+	/* SMBus Device, BDF:0-20-0 */
+	dev = PCI_DEV(0, 0x14, 0);//pci_locate_device(PCI_ID(0x1002, 0x4385), 0);
+	/* Enable watchdog decode timer */
+	byte = pci_read_config8(dev, 0x41);
+	byte |= (1 << 3);
+	pci_write_config8(dev, 0x41, byte);
+
+	/* Set to 1 to reset USB on the software (such as IO-64 or IO-CF9 cycles)
+	 * generated PCIRST#. */
+	byte = pmio_read(0x65);
+	byte |= (1 << 4);
+	pmio_write(0x65, byte);
+
+	/* IDE Device, BDF:0-20-1 */
+	dev = PCI_DEV(0, 0x14, 1);//pci_locate_device(PCI_ID(0x1002, 0x439C), 0);
+	/* Enable IDE Explicit prefetch, 0x63[0] clear */
+	byte = pci_read_config8(dev, 0x63);
+	byte &= 0xfe;
+	pci_write_config8(dev, 0x63, byte);
+
+	/* LPC Device, BDF:0-20-3 */
+	/* The code below is ported from old chipset. It is not
+	 * metioned in RPR. But I keep them. The registers and the
+	 * comments are compatible. */
+	dev = PCI_DEV(0, 0x14, 3);//pci_locate_device(PCI_ID(0x1002, 0x439D), 0);
+	/* Enabling LPC DMA function. */
+	byte = pci_read_config8(dev, 0x40);
+	byte |= (1 << 2);
+	pci_write_config8(dev, 0x40, byte);
+	/* Disabling LPC TimeOut. 0x48[7] clear. */
+	byte = pci_read_config8(dev, 0x48);
+	byte &= 0x7f;
+	pci_write_config8(dev, 0x48, byte);
+	/* Disabling LPC MSI Capability, 0x78[1] clear. */
+	byte = pci_read_config8(dev, 0x78);
+	byte &= 0xfd;
+	pci_write_config8(dev, 0x78, byte);
+
+	/* SATA Device, BDF:0-17-0, Non-Raid-5 SATA controller */
+	dev = PCI_DEV(0, 0x11, 0);//pci_locate_device(PCI_ID(0x1002, 0x4390), 0);
+	/* rpr7.12 SATA MSI and D3 Power State Capability. */
+	byte = pci_read_config8(dev, 0x40);
+	byte |= 1 << 0;
+	pci_write_config8(dev, 0x40, byte);
+	if (get_sb800_revision() <= 0x12)
+		pci_write_config8(dev, 0x34, 0x70); /* set 0x61 to 0x70 if S1 is not supported. */
+	else
+		pci_write_config8(dev, 0x34, 0x50); /* set 0x61 to 0x50 if S1 is not supported. */
+	byte &= ~(1 << 0);
+	pci_write_config8(dev, 0x40, byte);
+}
+
+/*
+*/
+static void sb800_por_init(void)
+{
+	/* sbDevicesPorInitTable + sbK8PorInitTable */
+	sb800_devices_por_init();
+
+	/* sbPmioPorInitTable + sbK8PmioPorInitTable */
+	//sb800_pmio_por_init();
+}
+
+/*
+* It should be called during early POST after memory detection and BIOS shadowing but before PCI bus enumeration.
+*/
+static void sb800_before_pci_init(void)
+{
+	sb800_pci_cfg();
+}
+
+/*
+* This function should be called after enable_sb800_smbus().
+*/
+static void sb800_early_setup(void)
+{
+	printk(BIOS_INFO, "sb800_early_setup()\n");
+	sb800_por_init();
+}
+
+#if 0
+static int smbus_read_byte(u32 device, u32 address)
+{
+	return do_smbus_read_byte(SMBUS_IO_BASE, device, address);
+}
+#endif
+#endif
Index: trunk/src/southbridge/amd/sb800/hda.c
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/hda.c
@@ -0,0 +1,213 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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 <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 "sb800.h"
+
+#define HDA_ICII_REG 0x68
+#define   HDA_ICII_BUSY (1 << 0)
+#define   HDA_ICII_VALID  (1 << 1)
+
+static int set_bits(u32 port, u32 mask, u32 val)
+{
+	u32 dword;
+	int count;
+
+	/* Write (val & ~mask) to port */
+	val &= mask;
+	dword = read32(port);
+	dword &= ~mask;
+	dword |= val;
+	write32(port, dword);
+
+	/* 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);
+		dword = read32(port);
+		dword &= mask;
+	} while ((dword != val) && --count);
+
+	/* Timeout occured */
+	if (!count)
+		return -1;
+	return 0;
+}
+
+static u32 codec_detect(u32 base)
+{
+	u32 dword;
+
+	/* Before Codec detection, we need to set the GPIO167-170 as
+	 * AZ_SDINx. */
+	/* Set Bit0 to 0 to enter reset state (BAR + 0x8)[0] */
+	if (set_bits(base + 0x08, 1, 0) == -1)
+		goto no_codec;
+
+	/* Set Bit 0 to 1 to exit reset state (BAR + 0x8)[0] */
+	if (set_bits(base + 0x08, 1, 1) == -1)
+		goto no_codec;
+
+	/* Delay for 1 ms since the BKDG does */
+	mdelay(1);
+
+	/* Read in Codec location (BAR + 0xe)[3..0]*/
+	dword = read32(base + 0xe);
+	dword &= 0x0F;
+	if (!dword)
+		goto no_codec;
+
+	return dword;
+
+no_codec:
+	/* Codec Not found */
+	/* Put HDA back in reset (BAR + 0x8) [0] */
+	set_bits(base + 0x08, 1, 0);
+	printk(BIOS_DEBUG, "No codec!\n");
+	return 0;
+}
+
+/**
+ *  Wait 50usec for 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 dword=read32(base +  HDA_ICII_REG);
+		if (!(dword & HDA_ICII_BUSY))
+			return 0;
+		udelay(1);
+	}
+
+	return -1;
+}
+
+/**
+ *  Wait 50usec for 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)
+{
+	/* Use a 50 usec timeout - the Linux kernel uses the
+	 * same duration */
+
+	int timeout = 50;
+	while(timeout--) {
+		u32 dword = read32(base + HDA_ICII_REG);
+		if ((dword & (HDA_ICII_VALID | HDA_ICII_BUSY)) ==
+			HDA_ICII_VALID)
+			return 0;
+		udelay(1);
+	}
+
+	return 1;
+}
+
+static void codec_init(u32 base, int addr)
+{
+	u32 dword;
+
+	/* 1 */
+	if (wait_for_ready(base) == -1)
+		return;
+
+	dword = (addr << 28) | 0x000f0000;
+	write32(base + 0x60, dword);
+
+	if (wait_for_valid(base) == -1)
+		return;
+
+	dword = read32(base + 0x64);
+
+	/* 2 */
+	printk(BIOS_DEBUG, "%x(th) codec viddid: %08x\n", addr, dword);
+}
+
+static void codecs_init(u32 base, u32 codec_mask)
+{
+	int i;
+	for (i = 3; i >= 0; i--) {
+		if (codec_mask & (1 << i))
+			codec_init(base, i);
+	}
+}
+
+static void hda_init(struct device *dev)
+{
+	u32 dword;
+	u32 base;
+	struct resource *res;
+	u32 codec_mask;
+
+	/* Program the 2C to 0x437b1002 */
+	dword = 0x43831002;
+	pci_write_config32(dev, 0x2c, dword);
+
+	/* Read in BAR */
+	/* Is this right? HDA allows for a 64-bit BAR
+	 * but this is only setup for a 32-bit one
+	 */
+	res = find_resource(dev, 0x10);
+	if (!res)
+		return;
+
+	base = (u32)res->base;
+	printk(BIOS_DEBUG, "base = 0x%x\n", base);
+	codec_mask = codec_detect(base);
+
+	if (codec_mask) {
+		printk(BIOS_DEBUG, "codec_mask = %02x\n", codec_mask);
+		codecs_init(base, codec_mask);
+	}
+}
+
+static struct pci_operations lops_pci = {
+	.set_subsystem = pci_dev_set_subsystem,
+};
+
+static struct device_operations hda_audio_ops = {
+	.read_resources = pci_dev_read_resources,
+	.set_resources = pci_dev_set_resources,
+	.enable_resources = pci_dev_enable_resources,
+	.init = hda_init,
+	.scan_bus = 0,
+	.ops_pci = &lops_pci,
+};
+
+static const struct pci_driver hdaaudio_driver __pci_driver = {
+	.ops = &hda_audio_ops,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB800_HDA,
+};
Index: trunk/src/southbridge/amd/sb800/lpc.c
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/lpc.c
@@ -0,0 +1,243 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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 <device/device.h>
+#include <device/pci.h>
+#include <device/pnp.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <pc80/mc146818rtc.h>
+#include <pc80/isa-dma.h>
+#include <bitops.h>
+#include <arch/io.h>
+#include "sb800.h"
+
+static void lpc_init(device_t dev)
+{
+	u8 byte;
+	u32 dword;
+	device_t sm_dev;
+
+	/* Enable the LPC Controller */
+	sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
+	dword = pci_read_config32(sm_dev, 0x64);
+	dword |= 1 << 20;
+	pci_write_config32(sm_dev, 0x64, dword);
+
+	/* Initialize isa dma */
+	isa_dma_init();
+
+	/* Enable DMA transaction on the LPC bus */
+	byte = pci_read_config8(dev, 0x40);
+	byte |= (1 << 2);
+	pci_write_config8(dev, 0x40, byte);
+
+	/* Disable the timeout mechanism on LPC */
+	byte = pci_read_config8(dev, 0x48);
+	byte &= ~(1 << 7);
+	pci_write_config8(dev, 0x48, byte);
+
+	/* Disable LPC MSI Capability */
+	byte = pci_read_config8(dev, 0x78);
+	byte &= ~(1 << 1);
+	byte &= ~(1 << 0);	/* Keep the old way. i.e., when bus master/DMA cycle is going
+				   on on LPC, it holds PCI grant, so no LPC slave cycle can
+				   interrupt and visit LPC. */
+	pci_write_config8(dev, 0x78, byte);
+
+	/* bit0: Enable prefetch a cacheline (64 bytes) when Host reads code from SPI rom */
+	/* bit3: Fix SPI_CS# timing issue when running at 66M. TODO:A12. */
+	byte = pci_read_config8(dev, 0xBB);
+	byte |= 1 << 0 | 1 << 3;
+	pci_write_config8(dev, 0xBB, byte);
+}
+
+static void sb800_lpc_read_resources(device_t dev)
+{
+	struct resource *res;
+
+	/* Get the normal pci resources of this device */
+	pci_dev_read_resources(dev);	/* We got one for APIC, or one more for TRAP */
+
+	pci_get_resource(dev, 0xA0); /* SPI ROM base address */
+
+	/* 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 = 0xfec00000;
+	//res->size = 0x00001000;
+	//res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+
+	compact_resources(dev);
+}
+
+static void sb800_lpc_set_resources(struct device *dev)
+{
+	struct resource *res;
+
+	pci_dev_set_resources(dev);
+
+	/* Specical case. SPI Base Address. The SpiRomEnable should be set. */
+	res = find_resource(dev, 0xA0);
+	pci_write_config32(dev, 0xA0, res->base | 1 << 1);
+
+}
+
+/**
+ * @brief Enable resources for children devices
+ *
+ * @param dev the device whos children's resources are to be enabled
+ *
+ */
+static void sb800_lpc_enable_childrens_resources(device_t dev)
+{
+	struct bus *link;
+	u32 reg, reg_x;
+	int var_num = 0;
+	u16 reg_var[3];
+
+	reg = pci_read_config32(dev, 0x44);
+	reg_x = pci_read_config32(dev, 0x48);
+
+	for (link = dev->link_list; link; link = link->next) {
+		device_t child;
+		for (child = link->children; child;
+		     child = child->sibling) {
+			if (child->enabled
+			    && (child->path.type == DEVICE_PATH_PNP)) {
+				struct resource *res;
+				for (res = child->resource_list; res; res = res->next) {
+					u32 base, end;	/*  don't need long long */
+					if (!(res->flags & IORESOURCE_IO))
+						continue;
+					base = res->base;
+					end = resource_end(res);
+					printk(BIOS_DEBUG, "sb800 lpc decode:%s, base=0x%08x, end=0x%08x\n",
+					     dev_path(child), base, end);
+					switch (base) {
+					case 0x60:	/*  KB */
+					case 0x64:	/*  MS */
+						reg |= (1 << 29);
+						break;
+					case 0x3f8:	/*  COM1 */
+						reg |= (1 << 6);
+						break;
+					case 0x2f8:	/*  COM2 */
+						reg |= (1 << 7);
+						break;
+					case 0x378:	/*  Parallal 1 */
+						reg |= (1 << 0);
+						break;
+					case 0x3f0:	/*  FD0 */
+						reg |= (1 << 26);
+						break;
+					case 0x220:	/*  Aduio 0 */
+						reg |= (1 << 8);
+						break;
+					case 0x300:	/*  Midi 0 */
+						reg |= (1 << 18);
+						break;
+					case 0x400:
+						reg_x |= (1 << 16);
+						break;
+					case 0x480:
+						reg_x |= (1 << 17);
+						break;
+					case 0x500:
+						reg_x |= (1 << 18);
+						break;
+					case 0x580:
+						reg_x |= (1 << 19);
+						break;
+					case 0x4700:
+						reg_x |= (1 << 22);
+						break;
+					case 0xfd60:
+						reg_x |= (1 << 23);
+						break;
+					default:
+						if (var_num >= 3)
+							continue;	/* only 3 var ; compact them ? */
+						switch (var_num) {
+						case 0:
+							reg_x |= (1 << 2);
+							break;
+						case 1:
+							reg_x |= (1 << 24);
+							break;
+						case 2:
+							reg_x |= (1 << 25);
+							break;
+						}
+						reg_var[var_num++] =
+						    base & 0xffff;
+					}
+				}
+			}
+		}
+	}
+	pci_write_config32(dev, 0x44, reg);
+	pci_write_config32(dev, 0x48, reg_x);
+	/* Set WideIO for as many IOs found (fall through is on purpose) */
+	switch (var_num) {
+	case 2:
+		pci_write_config16(dev, 0x90, reg_var[2]);
+	case 1:
+		pci_write_config16(dev, 0x66, reg_var[1]);
+	case 0:
+		pci_write_config16(dev, 0x64, reg_var[0]);
+		break;
+	}
+}
+
+static void sb800_lpc_enable_resources(device_t dev)
+{
+	pci_dev_enable_resources(dev);
+	sb800_lpc_enable_childrens_resources(dev);
+}
+
+static struct pci_operations lops_pci = {
+	.set_subsystem = pci_dev_set_subsystem,
+};
+
+static struct device_operations lpc_ops = {
+	.read_resources = sb800_lpc_read_resources,
+	.set_resources = sb800_lpc_set_resources,
+	.enable_resources = sb800_lpc_enable_resources,
+	.init = lpc_init,
+	.scan_bus = scan_static_bus,
+	.ops_pci = &lops_pci,
+};
+static const struct pci_driver lpc_driver __pci_driver = {
+	.ops = &lpc_ops,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB800_LPC,
+};
Index: trunk/src/southbridge/amd/sb800/pci.c
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/pci.c
@@ -0,0 +1,76 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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 <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "sb800.h"
+
+static void pci_init(struct device *dev)
+{
+	u32 dword;
+	u8 byte;
+
+	/* RPR 6.1 Enables the PCI-bridge subtractive decode */
+	/* This setting is strongly recommended since it supports some legacy PCI add-on cards,such as BIOS debug cards */
+	byte = pci_read_config8(dev, 0x4B);
+	byte |= 1 << 7;
+	pci_write_config8(dev, 0x4B, byte);
+	byte = pci_read_config8(dev, 0x40);
+	byte |= 1 << 5;
+	pci_write_config8(dev, 0x40, byte);
+
+	/* RPR6.2 PCI-bridge upstream dual address window */
+	/* this setting is applicable if the system memory is more than 4GB,and the PCI device can support dual address access */
+	byte = pci_read_config8(dev, 0x50);
+	byte |= 1 << 0;
+	pci_write_config8(dev, 0x50, byte);
+
+	/* RPR 6.3 Enable One-Prefetch-Channel Mode */
+	dword = pci_read_config32(dev, 0x64);
+	dword |= 1 << 20;
+	pci_write_config32(dev, 0x64, dword);
+
+	/* rpr6.4 Adjusting CLKRUN# */
+	dword = pci_read_config32(dev, 0x64);
+	dword |= (1 << 15);
+	pci_write_config32(dev, 0x64, dword);
+}
+
+static struct pci_operations lops_pci = {
+	.set_subsystem = 0,
+};
+
+static struct device_operations pci_ops = {
+	.read_resources = pci_bus_read_resources,
+	.set_resources = pci_dev_set_resources,
+	.enable_resources = pci_bus_enable_resources,
+	.init = pci_init,
+	.scan_bus = pci_scan_bridge,
+	.reset_bus = pci_bus_reset,
+	.ops_pci = &lops_pci,
+};
+
+static const struct pci_driver pci_driver __pci_driver = {
+	.ops = &pci_ops,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB800_PCI,
+};
Index: trunk/src/southbridge/amd/sb800/pcie.c
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/pcie.c
@@ -0,0 +1,74 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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 <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "sb800.h"
+
+static void pcie_init(struct device *dev)
+{
+	u32 dword;
+
+	printk(BIOS_INFO, "pcie_init in sb800_pcie.c\n");
+
+	/* System error enable */
+	dword = pci_read_config32(dev, 0x04);
+	dword |= (1 << 8);	/* System error enable */
+	dword |= (1 << 30);	/* Clear possible errors */
+	pci_write_config32(dev, 0x04, dword);
+}
+
+static struct pci_operations lops_pci = {
+	.set_subsystem = 0,
+};
+
+static struct device_operations pci_ops = {
+	.read_resources = pci_bus_read_resources,
+	.set_resources = pci_dev_set_resources,
+	.enable_resources = pci_bus_enable_resources,
+	.init = pcie_init,
+	.scan_bus = pci_scan_bridge,
+	.reset_bus = pci_bus_reset,
+	.ops_pci = &lops_pci,
+};
+
+static const struct pci_driver pciea_driver __pci_driver = {
+	.ops = &pci_ops,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB800_PCIEA,
+};
+
+static const struct pci_driver pcieb_driver __pci_driver = {
+	.ops = &pci_ops,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB800_PCIEB,
+};
+static const struct pci_driver pciec_driver __pci_driver = {
+	.ops = &pci_ops,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB800_PCIEC,
+};
+static const struct pci_driver pcied_driver __pci_driver = {
+	.ops = &pci_ops,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB800_PCIED,
+};
Index: trunk/src/southbridge/amd/sb800/reset.c
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/reset.c
@@ -0,0 +1,33 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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 <reset.h>
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+
+#include "../../../northbridge/amd/amdk8/reset_test.c"
+
+void hard_reset(void)
+{
+	set_bios_reset();
+	/* Try rebooting through port 0xcf9 */
+	/* Actually it is not a real hard_reset --- it only reset coherent link table, but not reset link freq and width */
+	outb((0 << 3) | (0 << 2) | (1 << 1), 0xcf9);
+	outb((0 << 3) | (1 << 2) | (1 << 1), 0xcf9);
+}
Index: trunk/src/southbridge/amd/sb800/sata.c
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/sata.c
@@ -0,0 +1,258 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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 <device/device.h>
+#include <delay.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <arch/io.h>
+#include "sb800.h"
+
+static int sata_drive_detect(int portnum, u16 iobar)
+{
+	u8 byte, byte2;
+	int i = 0;
+	outb(0xA0 + 0x10 * (portnum % 2), iobar + 0x6);
+	while (byte = inb(iobar + 0x6), byte2 = inb(iobar + 0x7),
+		(byte != (0xA0 + 0x10 * (portnum % 2))) ||
+		((byte2 & 0x88) != 0)) {
+		printk(BIOS_SPEW, "0x6=%x, 0x7=%x\n", byte, byte2);
+		if (byte != (0xA0 + 0x10 * (portnum % 2))) {
+			/* This will happen at the first iteration of this loop
+			 * if the first SATA port is unpopulated and the
+			 * second SATA port is poulated.
+			 */
+			printk(BIOS_DEBUG, "drive no longer selected after %i ms, "
+				"retrying init\n", i * 10);
+			return 1;
+		} else
+			printk(BIOS_SPEW, "drive detection not yet completed, "
+				"waiting...\n");
+		mdelay(10);
+		i++;
+	}
+	printk(BIOS_SPEW, "drive detection done after %i ms\n", i * 10);
+	return 0;
+}
+
+static void sata_init(struct device *dev)
+{
+	u8 byte;
+	u16 word;
+	u32 dword;
+	u8 rev_id;
+	u32 sata_bar5;
+	u16 sata_bar0, sata_bar1, sata_bar2, sata_bar3, sata_bar4;
+	int i, j;
+
+	struct southbridge_ati_sb800_config *conf;
+	conf = dev->chip_info;
+
+	device_t sm_dev;
+	/* SATA SMBus Disable */
+	/* sm_dev = pci_locate_device(PCI_ID(0x1002, 0x4385), 0); */
+	sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
+
+	/* get rev_id */
+	rev_id = pci_read_config8(sm_dev, 0x08) - 0x2F;
+
+	/* get base addresss */
+	sata_bar5 = pci_read_config32(dev, 0x24) & ~0x3FF;
+	sata_bar0 = pci_read_config16(dev, 0x10) & ~0x7;
+	sata_bar1 = pci_read_config16(dev, 0x14) & ~0x3;
+	sata_bar2 = pci_read_config16(dev, 0x18) & ~0x7;
+	sata_bar3 = pci_read_config16(dev, 0x1C) & ~0x3;
+	sata_bar4 = pci_read_config16(dev, 0x20) & ~0xf;
+
+	printk(BIOS_SPEW, "sata_bar0=%x\n", sata_bar0);	/* 3030 */
+	printk(BIOS_SPEW, "sata_bar1=%x\n", sata_bar1);	/* 3070 */
+	printk(BIOS_SPEW, "sata_bar2=%x\n", sata_bar2);	/* 3040 */
+	printk(BIOS_SPEW, "sata_bar3=%x\n", sata_bar3);	/* 3080 */
+	printk(BIOS_SPEW, "sata_bar4=%x\n", sata_bar4);	/* 3000 */
+	printk(BIOS_SPEW, "sata_bar5=%x\n", sata_bar5);	/* e0309000 */
+
+	/* SERR-Enable */
+	word = pci_read_config16(dev, 0x04);
+	word |= (1 << 8);
+	pci_write_config16(dev, 0x04, word);
+
+	/* Set SATA Operation Mode, Set to IDE mode */
+	byte = pci_read_config8(dev, 0x40);
+	byte |= (1 << 0);
+	//byte |= (1 << 4);
+	pci_write_config8(dev, 0x40, byte);
+
+	dword = 0x01018f00;
+	pci_write_config32(dev, 0x8, dword);
+
+	/* Program the 2C to 0x43801002 */
+	dword = 0x43801002;
+	pci_write_config32(dev, 0x2c, dword);
+
+	pci_write_config8(dev, 0x34, 0x70); /* 8.11 SATA MSI and D3 Power State Capability */
+
+	dword = read32(sata_bar5 + 0xFC);
+	dword &= ~(1 << 11);	/* rpr 8.8. Disabling Aggressive Link Power Management */
+	dword &= ~(1 << 12);	/* rpr 8.9.1 Disabling Port Multiplier support. */
+	dword &= ~(1 << 10);	/* rpr 8.9.2 disabling FIS-based Switching support */
+	dword &= ~(1 << 19);	/* rpr 8.10. Disabling CCC (Command Completion Coalescing) Support */
+	write32((sata_bar5 + 0xFC), dword);
+
+	dword = read32(sata_bar5 + 0xF8);
+	dword &= ~(0x3F << 22);	/* rpr 8.9.2 disabling FIS-based Switching support */
+	write32(sata_bar5 + 0xF8, dword);
+
+	byte = pci_read_config8(dev, 0x40);
+	byte &= ~(1 << 0);
+	pci_write_config8(dev, 0x40, byte);
+
+	/* rpr 8.3 */
+	printk(BIOS_SPEW, "rev_id=%x\n", rev_id);
+	dword = pci_read_config32(dev, 0x84);
+	if (rev_id == 0x11)	/* A11 */
+		dword |= 1 << 22;
+	pci_write_config32(dev, 0x84, dword);
+
+	/* rpr8.12 Program the watchdog counter to 0x20 */
+	byte = pci_read_config8(dev, 0x44);
+	byte |= 1 << 0;
+	pci_write_config8(dev, 0x44, byte);
+
+	pci_write_config8(dev, 0x46, 0x20);
+
+	/* RPR8.4 */
+	/* Port 0 */
+	for (i = 0; i < 6; i++) {
+		pci_write_config16(dev, 0x84, 0x3006 | i << 9);
+		pci_write_config32(dev, 0x94, 0x0056A700);
+		pci_write_config16(dev, 0x84, 0x2006 | i << 9);
+		pci_write_config32(dev, 0x94, 0x00061400);
+		pci_write_config16(dev, 0x84, 0x1006 | i << 9);
+		pci_write_config32(dev, 0x94, 0x00061302);
+	}
+
+	/* Enable the I/O, MM, BusMaster access for SATA */
+	byte = pci_read_config8(dev, 0x4);
+	byte |= 7 << 0;
+	pci_write_config8(dev, 0x4, byte);
+
+	/* RPR7.7 SATA drive detection. */
+	/* Use BAR5+0x128,BAR0 for Primary Slave */
+	/* Use BAR5+0x1A8,BAR0 for Primary Slave */
+	/* Use BAR5+0x228,BAR2 for Secondary Master */
+	/* Use BAR5+0x2A8,BAR2 for Secondary Slave */
+	/* Use BAR5+0x328,PATA_BAR0/2 for Primary/Secondary master emulation */
+	/* Use BAR5+0x3A8,PATA_BAR0/2 for Primary/Secondary Slave emulation */
+
+	/* TODO: port 4,5, which are PATA emulations. What are PATA_BARs? */
+
+	for (i = 0; i < 4; i++) {
+		byte = read8(sata_bar5 + 0x128 + 0x80 * i);
+		printk(BIOS_SPEW, "SATA port %i status = %x\n", i, byte);
+		byte &= 0xF;
+		if( byte == 0x1 ) {
+			/* If the drive status is 0x1 then we see it but we aren't talking to it. */
+			/* Try to do something about it. */
+			printk(BIOS_SPEW, "SATA device detected but not talking. Trying lower speed.\n");
+
+			/* Read in Port-N Serial ATA Control Register */
+			byte = read8(sata_bar5 + 0x12C + 0x80 * i);
+
+			/* Set Reset Bit and 1.5g bit */
+			byte |= 0x11;
+			write8((sata_bar5 + 0x12C + 0x80 * i), byte);
+
+			/* Wait 1ms */
+			mdelay(1);
+
+			/* Clear Reset Bit */
+			byte &= ~0x01;
+			write8((sata_bar5 + 0x12C + 0x80 * i), byte);
+
+			/* Wait 1ms */
+			mdelay(1);
+
+			/* Reread status */
+			byte = read8(sata_bar5 + 0x128 + 0x80 * i);
+			printk(BIOS_SPEW, "SATA port %i status = %x\n", i, byte);
+			byte &= 0xF;
+		}
+
+		if (byte == 0x3) {
+			for (j = 0; j < 10; j++) {
+				if (!sata_drive_detect(i, ((i / 2) == 0) ? sata_bar0 : sata_bar2))
+					break;
+			}
+			printk(BIOS_DEBUG, "%s %s device is %sready after %i tries\n",
+					(i / 2) ? "Secondary" : "Primary",
+					(i % 2 ) ? "Slave" : "Master",
+					(j == 10) ? "not " : "",
+					(j == 10) ? j : j + 1);
+		} else {
+			printk(BIOS_DEBUG, "No %s %s SATA drive on Slot%i\n",
+					(i / 2) ? "Secondary" : "Primary",
+					(i % 2 ) ? "Slave" : "Master", i);
+		}
+	}
+
+	/* Below is CIM InitSataLateFar */
+	/* Enable interrupts from the HBA  */
+	byte = read8(sata_bar5 + 0x4);
+	byte |= 1 << 1;
+	write8((sata_bar5 + 0x4), byte);
+
+	/* Clear error status */
+	write32((sata_bar5 + 0x130), 0xFFFFFFFF);
+	write32((sata_bar5 + 0x1b0), 0xFFFFFFFF);
+	write32((sata_bar5 + 0x230), 0xFFFFFFFF);
+	write32((sata_bar5 + 0x2b0), 0xFFFFFFFF);
+	write32((sata_bar5 + 0x330), 0xFFFFFFFF);
+	write32((sata_bar5 + 0x3b0), 0xFFFFFFFF);
+
+	/* Clear SATA status,Firstly we get the AcpiGpe0BlkAddr */
+	/* ????? why CIM does not set the AcpiGpe0BlkAddr , but use it??? */
+
+	/* word = 0x0000; */
+	/* word = pm_ioread(0x28); */
+	/* byte = pm_ioread(0x29); */
+	/* word |= byte<<8; */
+	/* printk(BIOS_DEBUG, "AcpiGpe0Blk addr = %x\n", word); */
+	/* write32(word, 0x80000000); */
+}
+
+static struct pci_operations lops_pci = {
+	/* .set_subsystem = pci_dev_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 = &lops_pci,
+};
+
+static const struct pci_driver sata0_driver __pci_driver = {
+	.ops = &sata_ops,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB800_SATA,
+};
Index: trunk/src/southbridge/amd/sb800/sb800.c
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/sb800.c
@@ -0,0 +1,391 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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 <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "sb800.h"
+#include "smbus.h"
+
+static device_t find_sm_dev(device_t dev, u32 devfn)
+{
+	device_t sm_dev;
+
+	sm_dev = dev_find_slot(dev->bus->secondary, devfn);
+	if (!sm_dev)
+		return sm_dev;
+
+	if ((sm_dev->vendor != PCI_VENDOR_ID_ATI) ||
+	    ((sm_dev->device != PCI_DEVICE_ID_ATI_SB800_SM))) {
+		u32 id;
+		id = pci_read_config32(sm_dev, PCI_VENDOR_ID);
+		if ((id !=
+		     (PCI_VENDOR_ID_ATI | (PCI_DEVICE_ID_ATI_SB800_SM << 16))))
+		{
+			sm_dev = 0;
+		}
+	}
+
+	return sm_dev;
+}
+
+void set_sm_enable_bits(device_t sm_dev, u32 reg_pos, u32 mask, u32 val)
+{
+	u32 reg_old, reg;
+	reg = reg_old = pci_read_config32(sm_dev, reg_pos);
+	reg &= ~mask;
+	reg |= val;
+	if (reg != reg_old) {
+		pci_write_config32(sm_dev, reg_pos, reg);
+	}
+}
+
+static void pmio_write_index(u16 port_base, u8 reg, u8 value)
+{
+	outb(reg, port_base);
+	outb(value, port_base + 1);
+}
+
+static u8 pmio_read_index(u16 port_base, u8 reg)
+{
+	outb(reg, port_base);
+	return inb(port_base + 1);
+}
+
+void pm_iowrite(u8 reg, u8 value)
+{
+	pmio_write_index(PM_INDEX, reg, value);
+}
+
+u8 pm_ioread(u8 reg)
+{
+	return pmio_read_index(PM_INDEX, reg);
+}
+
+void pm2_iowrite(u8 reg, u8 value)
+{
+	pmio_write_index(PM2_INDEX, reg, value);
+}
+
+u8 pm2_ioread(u8 reg)
+{
+	return pmio_read_index(PM2_INDEX, reg);
+}
+
+static void set_pmio_enable_bits(u32 reg_pos, u32 mask, u32 val)
+{
+	u8 reg_old, reg;
+	reg = reg_old = pm_ioread(reg_pos);
+	reg &= ~mask;
+	reg |= val;
+	if (reg != reg_old) {
+		pm_iowrite(reg_pos, reg);
+	}
+}
+
+u16 tx_convert_table[] = {
+	[0x0] = 0xFFFF,
+	[0x1] = 0xFFFE,
+	[0x2] = 0xFFFC,
+	[0x3] = 0xFFF8,
+	[0x4] = 0xFFF0,
+	[0x5] = 0xFFE0,
+	[0x6] = 0xFFC0,
+	[0x7] = 0xFF80,
+	[0x8] = 0xFF00,
+	[0x9] = 0xFE00,
+	[0xA] = 0xFC00,
+	[0xB] = 0xF800,
+	[0xC] = 0xF000,
+	[0xD] = 0xE000,
+	[0xE] = 0xC000,
+	[0xF] = 0x8000
+};
+
+u16 rx_convert_table[] = {
+	[0x0] = 0x0001,
+	[0x1] = 0x0003,
+	[0x2] = 0x0007,
+	[0x3] = 0x000F,
+	[0x4] = 0x001F,
+	[0x5] = 0x003F,
+	[0x6] = 0x007F,
+	[0x7] = 0x00FF,
+	[0x8] = 0x01FF,
+	[0x9] = 0x03FF,
+	[0xA] = 0x07FF,
+	[0xB] = 0x0FFF,
+	[0xC] = 0x1FFF,
+	[0xD] = 0x3FFF,
+	[0xE] = 0x7FFF,
+	[0xF] = 0xFFFF
+};
+
+/* PCIe General Purpose Ports */
+/* v:1814, d:3090. cp421A */
+static void set_sb800_gpp(device_t dev)
+{
+	struct southbridge_amd_sb800_config *conf;
+	u32 imp_rb, lc_status;
+	u8 port;
+
+	conf = dev->chip_info;
+	port = dev->path.pci.devfn & 3;
+
+	/* 5.1 GPP Lane Configuration */
+	/* To support one of 4 legal configurations:
+	 * 0000: PortA lanes[3:0]
+	 * 0001: N/A
+	 * 0010: PortA lanes[1:0], PortB lanes[3:2]
+	 * 0011: PortA lanes[1:0], PortB lane2, PortC lane3
+	 * 0100: PortA lane0, PortB lane1, PortC lane2, PortD lane3.
+	 * Other combinations are not supported.
+	 */
+	/* CIMx: Set abcfg:0x90[20] = 1 to enable GPP bridge multi-function */
+	abcfg_reg(0x90, 1 << 20, 1 << 20);
+
+	printk(BIOS_DEBUG, "set_sb800_gpp() 1\n");
+	//abcfg_reg(0xC0, 0xF << 0, 0x4 << 0); /* bimini:4; tarpon:3 */
+	abcfg_reg(0xC0, 0xF << 0, (conf->gpp_configuration & 0xF) << 0); /* bimini:4; tarpon:3 */
+
+	printk(BIOS_DEBUG, "set_sb800_gpp() 2,\n");
+	/* 5.2 Enabling GPP Port A/B/C/D */
+	//abcfg_reg(0xC0, 0xF << 4, 0x1 << 4);
+	abcfg_reg(0xC0, 0xF << 4, dev->enabled ? 0x1 << (4 + port) : 0);
+
+	printk(BIOS_DEBUG, "set_sb800_gpp() 3\n");
+	/* 5.3 Releasing GPP Reset */
+	abcfg_reg(0xC0, 0x1 << 8, 0x0 << 8);
+
+	/* release training */
+	abcfg_reg(0xC0, 0xF << 12, 0x0 << 12);
+	/* 5.4 Power Saving Feature for GPP Lanes. Skip */
+	/* 5.5 PCIe Ports De-emphasis Settings. Skip */
+	abcfg_reg(0x340, 1 << 21, 0 << 21);
+	abcfg_reg(0x344, 1 << 21, 0 << 21);
+	abcfg_reg(0x348, 1 << 21, 0 << 21);
+	abcfg_reg(0x34C, 1 << 21, 0 << 21);
+	/* 5.6 PCIe PHY Calibration Impedance Value Setting */
+	/* AXINDC_Reg 0x60: TX_IMP_RB */
+	outl(0x30, 0xCD8);
+	outl(0x60, 0xCDC);
+	outl(0x34, 0xCD8);
+	imp_rb = inl(0xCDC);
+
+	printk(BIOS_DEBUG, "imp_rb 1=%x\n", imp_rb);
+	/* tx */
+	abcfg_reg(0xA4, 0x1FFF, (rx_convert_table[(imp_rb>>8)&0xF]) & 0x1FFF);
+	abcfg_reg(0xA4, 0x1FFF<<19, ((tx_convert_table[(imp_rb>>4)&0xF] >> 3) & 0x1FFF) << 19);
+
+	/* 5.4. */
+	abcfg_reg(0xA0, 3 << 12, 3 << 12);
+
+	axindxp_reg(0xa0, 0xf<<4, 3<<4);
+	rcindxp_reg(0xA0, 0, 0xF << 4, 1 << 0);
+	rcindxp_reg(0xA0, 1, 0xF << 4, 1 << 0);
+	rcindxp_reg(0xA0, 2, 0xF << 4, 1 << 0);
+	rcindxp_reg(0xA0, 3, 0xF << 4, 1 << 0);
+
+	/* 5.8 Disabling Serial Number Capability */
+	abcfg_reg(0x330, 1 << 26, 0 << 26);
+
+	abcfg_reg(0x50, 0xFFFFFFFF, 0x04000004);
+	abcfg_reg(0x54, 0xFFFFFFFF, 0x00040000);
+	abcfg_reg(0x80, 0xFFFFFFFF, 0x03060001);
+	abcfg_reg(0x90, 0xFFFFFFFF, 0x00300000);
+	abcfg_reg(0x98, 0xFFFFFFFF, 0x03034700);
+
+	pci_write_config32(dev, 0x80, 0x00000006);
+	/* Set PCIEIND_P:PCIE_RX_CNTL[RX_RCB_CPL_TIMEOUT_MODE] (0x70:[19]) = 1 */
+	rcindxp_reg(0x70, 0, 1 << 19, 1 << 19);
+	//outl(3<<29|0<<24|0x70, 0xCD8);
+	/* Set PCIEIND_P:PCIE_TX_CNTL[TX_FLUSH_TLP_DIS] (0x20:[19]) = 0 */
+	rcindxp_reg(0x20, 0, 1 << 19, 0 << 19);
+	printk(BIOS_DEBUG, "imp_rb 5=%x\n", imp_rb);
+	outl(3<<29|0<<24|0xA5, 0xCD8);
+	lc_status = inl(0xCDC);
+	printk(BIOS_DEBUG, "lc_status=%x\n", lc_status);
+}
+
+void sb800_enable(device_t dev)
+{
+	device_t sm_dev = 0;
+	device_t bus_dev = 0;
+	int index = -1;
+	u32 deviceid;
+	u32 vendorid;
+
+	/* struct southbridge_ati_sb800_config *conf; */
+	/* conf = dev->chip_info; */
+	int i;
+
+	u32 devfn, dword;
+
+	printk(BIOS_DEBUG, "sb800_enable()\n");
+
+	/*
+	 *	0:11.0  SATA		bit 8 of pmio 0xDA : 1 - enable
+	 *	0:12.0  OHCI-USB1	bit 0 of pmio 0xEF
+	 *	0:12.2  EHCI-USB1	bit 1 of pmio 0xEF
+	 *	0:13.0  OHCI-USB2	bit 2 of pmio 0xEF
+	 *	0:13.2  EHCI-USB2	bit 3 of pmio 0xEF
+	 *	0:16.1  OHCI-USB3	bit 4 of pmio 0xEF
+	 *	0:16.2  EHCI-USB3	bit 5 of pmio 0xEF
+	 *	0:14.5  OHCI-USB4	bit 6 of pmio 0xEF
+	 *	0:14.0  SMBUS							0
+	 *	0:14.1  IDE							1
+	 *	0:14.2  HDA	bit 0 of pm_io 0xEB : 1 - enable
+	 *	0:14.3  LPC	bit 0 of pm_io 0xEC : 1 - enable
+	 *	0:14.4  PCI	bit 0 of pm_io 0xEA : 0 - enable
+	 *	0:14.6  GEC	bit 0 of pm_io 0xF6 : 0 - enable
+	 */
+	if (dev->device == 0x0000) {
+		vendorid = pci_read_config32(dev, PCI_VENDOR_ID);
+		deviceid = (vendorid >> 16) & 0xffff;
+		vendorid &= 0xffff;
+	} else {
+		vendorid = dev->vendor;
+		deviceid = dev->device;
+	}
+	bus_dev = dev->bus->dev;
+	if ((bus_dev->vendor == PCI_VENDOR_ID_ATI) &&
+	    (bus_dev->device == PCI_DEVICE_ID_ATI_SB800_PCI)) {
+		devfn = (bus_dev->path.pci.devfn) & ~7;
+		sm_dev = find_sm_dev(bus_dev, devfn);
+		if (!sm_dev)
+			return;
+
+		/* something under 00:01.0 */
+		switch (dev->path.pci.devfn) {
+		case 5 << 3:
+			;
+		}
+
+		return;
+	}
+
+	i = (dev->path.pci.devfn) & ~7;
+	i += (3 << 3);
+	for (devfn = (0x14 << 3); devfn <= i; devfn += (1 << 3)) {
+		sm_dev = find_sm_dev(dev, devfn);
+		if (sm_dev)
+			break;
+	}
+	if (!sm_dev)
+		return;
+
+	switch (dev->path.pci.devfn - (devfn - (0x14 << 3))) {
+	case (0x11 << 3) | 0:
+		index = 8;
+		set_pmio_enable_bits(0xDA, 1 << 0,
+				     (dev->enabled ? 1 : 0) << 0);
+		/* Set the device ID of SATA as 0x4390 to reduce the confusing. */
+		dword = pci_read_config32(dev, 0x40);
+		dword |= 1 << 0;
+		pci_write_config32(dev, 0x40, dword);
+		pci_write_config16(dev, 0x2, 0x4390);
+		dword &= ~1;
+		pci_write_config32(dev, 0x40, dword);//for (;;);
+		index += 32 * 3;
+		break;
+	case (0x12 << 3) | 0:
+	case (0x12 << 3) | 2:
+		index = (dev->path.pci.devfn & 0x3) / 2;
+		set_pmio_enable_bits(0xEF, 1 << index,
+				     (dev->enabled ? 1 : 0) << index);
+		break;
+	case (0x13 << 3) | 0:
+	case (0x13 << 3) | 2:
+		index = (dev->path.pci.devfn & 0x3) / 2 + 2;
+		set_pmio_enable_bits(0xEF, 1 << index,
+				     (dev->enabled ? 1 : 0) << index);
+		index += 32 * 2;
+		break;
+	case (0x14 << 3) | 0:
+		index = 0;
+		break;
+	case (0x14 << 3) | 1:
+		index = 1;
+		set_pmio_enable_bits(0xDA, 1 << 3,
+				     (dev->enabled ? 0 : 1) << 3);
+		break;
+	case (0x14 << 3) | 2:
+		index = 0;
+		set_pmio_enable_bits(0xEB, 1 << index,
+				     (dev->enabled ? 1 : 0) << index);
+		break;
+	case (0x14 << 3) | 3:
+		index = 0;
+		set_pmio_enable_bits(0xEC, 1 << index,
+				     (dev->enabled ? 1 : 0) << index);
+		index += 32 * 1;
+		break;
+	case (0x14 << 3) | 4:
+		index = 0;
+		set_pmio_enable_bits(0xEA, 1 << index,
+				     (dev->enabled ? 0 : 1) << index);
+		break;
+	case (0x14 << 3) | 5:
+		index = 6;
+		set_pmio_enable_bits(0xEF, 1 << index,
+				     (dev->enabled ? 1 : 0) << index);
+		break;
+	case (0x14 << 3) | 6:
+		/* From linux-2.6.32 to 2.6.34, the broadcom has problems
+		 * about the sequence of installing drivers. The solution is
+		 * modifying the file "/etc/rc.local", or just running:
+		 *
+		 * touch /var/lock/subsys/local
+		 * modprobe -r tg3
+		 * modprobe broadcom
+		 * modprobe tg3
+		 */
+		index = 0;
+		set_pmio_enable_bits(0xF6, 1 << index,
+				     (dev->enabled ? 0 : 1) << index);
+		break;
+	case (0x15 << 3) | 0:
+		set_sb800_gpp(dev);
+		index = 4;
+		break;
+	case (0x15 << 3) | 1:
+	case (0x15 << 3) | 2:
+	case (0x15 << 3) | 3:
+		break;
+	case (0x16 << 3) | 0:
+	case (0x16 << 3) | 2:
+		index = (dev->path.pci.devfn & 0x3) / 2 + 4;
+		set_pmio_enable_bits(0xEF, 1 << index,
+				     (dev->enabled ? 1 : 0) << index);
+		break;
+	default:
+		printk(BIOS_DEBUG, "unknown dev: %s deviceid=%4x\n", dev_path(dev),
+			     deviceid);
+	}
+}
+
+struct chip_operations southbridge_amd_sb800_ops = {
+	CHIP_NAME("ATI SB800")
+	.enable_dev = sb800_enable,
+};
Index: trunk/src/southbridge/amd/sb800/sm.c
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/sm.c
@@ -0,0 +1,356 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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 <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <device/smbus.h>
+#include <pc80/mc146818rtc.h>
+#include <bitops.h>
+#include <arch/io.h>
+#include <cpu/x86/lapic.h>
+#include <arch/ioapic.h>
+#include <stdlib.h>
+#include "sb800.h"
+#include "smbus.c"
+
+#define NMI_OFF 0
+
+#define MAINBOARD_POWER_OFF 0
+#define MAINBOARD_POWER_ON 1
+
+#ifndef CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL
+#define CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON
+#endif
+
+#define BIT0	(1 << 0)
+#define BIT1	(1 << 1)
+#define BIT2	(1 << 2)
+#define BIT3	(1 << 3)
+#define BIT4	(1 << 4)
+#define BIT5	(1 << 5)
+#define BIT6	(1 << 6)
+#define BIT7	(1 << 7)
+
+#define BIT8	(1 << 8 )
+#define BIT9	(1 << 9 )
+#define BIT10	(1 << 10)
+#define BIT11	(1 << 11)
+#define BIT12	(1 << 12)
+#define BIT13	(1 << 13)
+#define BIT14	(1 << 14)
+#define BIT15	(1 << 15)
+
+#define BIT16	(1 << 16)
+#define BIT17	(1 << 17)
+#define BIT18	(1 << 18)
+#define BIT19	(1 << 19)
+#define BIT20	(1 << 20)
+#define BIT21	(1 << 21)
+#define BIT22	(1 << 22)
+#define BIT23	(1 << 23)
+#define BIT24	(1 << 24)
+#define BIT25	(1 << 25)
+#define BIT26	(1 << 26)
+#define BIT27	(1 << 27)
+#define BIT28	(1 << 28)
+#define BIT29	(1 << 29)
+#define BIT30	(1 << 30)
+#define BIT31	(1 << 31)
+
+/*
+* SB800 enables all USB controllers by default in SMBUS Control.
+* SB800 enables SATA by default in SMBUS Control.
+*/
+
+static void sm_init(device_t dev)
+{
+	u8 byte;
+	u32 ioapic_base;
+
+	printk(BIOS_INFO, "sm_init().\n");
+
+	ioapic_base = 0xFEC00000;//pci_read_config32(dev, 0x74) & (0xffffffe0);	/* some like mem resource, but does not have  enable bit */
+	/* Don't rename APIC ID */
+	/* TODO: We should call setup_ioapic() here. But kernel hangs if cpu is K8.
+	 * We need to check out why and change back. */
+	clear_ioapic(ioapic_base);
+	//setup_ioapic(ioapic_base, 0);
+
+	/* enable serial irq */
+	byte = pm_ioread(0x54);
+	byte |= 1 << 7;		/* enable serial irq function */
+	byte &= ~(0xF << 2);
+	byte |= 4 << 2;		/* set NumSerIrqBits=4 */
+	pm_iowrite(0x54, byte);
+
+	pm_iowrite(0x00, 0x0E);
+	pm_iowrite(0x0B, 0x02);
+	/* 2.11 IO Trap Settings */
+	abcfg_reg(0x10090, 1 << 16, 1 << 16);
+
+	/* 4.1 ab index */
+	//pci_write_config32(dev, 0xF0, AB_INDX);
+	pm_iowrite(0xE0, AB_INDX & 0xFF);
+	pm_iowrite(0xE1, (AB_INDX >> 8) & 0xFF);
+	pm_iowrite(0xE2, (AB_INDX >> 16) & 0xFF);
+	pm_iowrite(0xE3, (AB_INDX >> 24) & 0xFF);
+	/* Initialize the real time clock */
+	rtc_init(0);
+
+	byte = pm_ioread(0x8);
+	byte |= 1 << 2 | 1 << 4;
+	pm_iowrite(0x08, byte);
+	byte = pm_ioread(0x9);
+	byte |= 1 << 0;
+	pm_iowrite(0x09, byte);
+
+	abcfg_reg(0x10060, (BIT31), BIT31);
+	abcfg_reg(0x1009C, (BIT4 + BIT5), BIT4 + BIT5);
+	abcfg_reg(0x9C,    (BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7), BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7);
+	abcfg_reg(0x90,    (BIT21 + BIT22 + BIT23), BIT21 + BIT22 + BIT23);
+	abcfg_reg(0xF0,    (BIT6 + BIT5), BIT6 + BIT5);
+	abcfg_reg(0x10090, (BIT9 + BIT10 + BIT11 + BIT12), BIT9 + BIT10 + BIT11 + BIT12);
+	abcfg_reg(0x58,    (BIT10), BIT10);
+	abcfg_reg(0xF0,    (BIT3 + BIT4), BIT3 + BIT4);
+	abcfg_reg(0x54,    (BIT1), BIT1);
+	//
+	axindxc_reg(0x02, BIT9, BIT9);
+	axindxc_reg(0x10, BIT9, BIT9);
+
+	/* 4.2 Enabling Upstream DMA Access */
+	axcfg_reg(0x04, 1 << 2, 1 << 2);
+	/* 4.3 Enabling PCIB Prefetch Settings */
+	abcfg_reg(0x10060, 1 << 20, 1 << 20);
+	abcfg_reg(0x10064, 1 << 20, 1 << 20);
+
+	/* 4.4 Enabling OHCI Prefetch for Performance Enhancement, A12 */
+	abcfg_reg(0x80, 1 << 0, 1<< 0);
+
+	/* 4.5 B-Link Client's Credit Variable Settings for the Downstream Arbitration Equation */
+	/* 4.6 Enabling Additional Address Bits Checking in Downstream */
+	abcfg_reg(0x9c, 1 << 0, 1 << 0);
+	//abcfg_reg(0x9c, 3 << 0, 3 << 0); //A11
+
+	/* 4.7 Set B-Link Prefetch Mode */
+	abcfg_reg(0x80, 3 << 17, 3 << 17);
+
+	// RPR Enabled SMI ordering enhancement. ABCFG 0x90[21]
+	// RPR USB Delay A-Link Express L1 State. ABCFG 0x90[17]
+	abcfg_reg(0x90, 1 << 17 | 1 << 21, 1 << 17 | 1 << 21);
+	/* 4.8 Enabling Detection of Upstream Interrupts */
+	abcfg_reg(0x94, 1 << 20 | 0x7FFFF, 1 << 20 | 0x00FEE);
+
+	/* 4.9: Enabling Downstream Posted Transactions to Pass Non-Posted
+	 *  Transactions for the K8 Platform (for All Revisions) */
+	abcfg_reg(0x10090, 1 << 8, 1 << 8);
+
+	/* 4.10:Programming Cycle Delay for AB and BIF Clock Gating */
+	/* 4.11:Enabling AB Int_Arbiter Enhancement (for All Revisions) */
+	abcfg_reg(0x10054, 0xFFFF0000, 0x01040000);
+	abcfg_reg(0x54, 0xFF << 16, 4 << 16);
+	abcfg_reg(0x54, 1 << 24, 0 << 24);
+	abcfg_reg(0x54, 1 << 26, 1 << 26);
+	abcfg_reg(0x98, 0xFFFFFF00, 0x00004700);
+
+	/* 4.12: Enabling AB and BIF Clock Gating */
+	abcfg_reg(0x10054, 0x0000FFFF, 0x07FF);
+
+	/* 4.13:Enabling Requester ID for upstream traffic. */
+	abcfg_reg(0x98, 3 << 16, 3 << 16);
+
+	abcfg_reg(0x50, 1 << 2, 0 << 2);
+
+	/* 5.2 Enabling GPP Port A/B/C/D */
+	//abcfg_reg(0xC0, 0xF << 4, 0xF << 4);
+
+	/* Enable SCI as irq9. */
+	outb(0x10, 0xC00);
+	outb(0x9, 0xC01);
+	/* Enabled IRQ input */
+	outb(0x9, 0xC00);
+	outb(0xF7, 0xC01);
+
+	abcfg_reg(0x90, 0xFFFFFFFF, 0x00F80040);
+	abcfg_reg(0xA0, 0xFFFFFFFF, 0x00000000);
+	abcfg_reg(0xA4, 0xFFFFFFFF, 0x00000000);
+	abcfg_reg(0xC0, 0xFFFFFFFF, 0x0000F014);
+	abcfg_reg(0x98, 0xFFFFFFFF, 0X01034700);
+}
+
+static int lsmbus_recv_byte(device_t dev)
+{
+	u32 device;
+	struct resource *res;
+	struct bus *pbus;
+
+	device = dev->path.i2c.device;
+	pbus = get_pbus_smbus(dev);
+
+	res = find_resource(pbus->dev, 0x90);
+
+	return do_smbus_recv_byte(res->base, device);
+}
+
+static int lsmbus_send_byte(device_t dev, u8 val)
+{
+	u32 device;
+	struct resource *res;
+	struct bus *pbus;
+
+	device = dev->path.i2c.device;
+	pbus = get_pbus_smbus(dev);
+
+	res = find_resource(pbus->dev, 0x90);
+
+	return do_smbus_send_byte(res->base, device, val);
+}
+
+static int lsmbus_read_byte(device_t dev, u8 address)
+{
+	u32 device;
+	struct resource *res;
+	struct bus *pbus;
+
+	device = dev->path.i2c.device;
+	pbus = get_pbus_smbus(dev);
+
+	res = find_resource(pbus->dev, 0x90);
+
+	return do_smbus_read_byte(res->base, device, address);
+}
+
+static int lsmbus_write_byte(device_t dev, u8 address, u8 val)
+{
+	u32 device;
+	struct resource *res;
+	struct bus *pbus;
+
+	device = dev->path.i2c.device;
+	pbus = get_pbus_smbus(dev);
+
+	res = find_resource(pbus->dev, 0x90);
+
+	return do_smbus_write_byte(res->base, device, address, val);
+}
+static struct smbus_bus_operations lops_smbus_bus = {
+	.recv_byte = lsmbus_recv_byte,
+	.send_byte = lsmbus_send_byte,
+	.read_byte = lsmbus_read_byte,
+	.write_byte = lsmbus_write_byte,
+};
+
+static void sb800_sm_read_resources(device_t dev)
+{
+	struct resource *res;
+	u8 byte;
+
+	/* rpr2.14: Hides SM bus controller Bar1 where stores HPET MMIO base address */
+	byte = pm_ioread(0x55);
+	byte |= 1 << 7;
+	pm_iowrite(0x55, byte);
+
+	/* Get the normal pci resources of this device */
+	/* pci_dev_read_resources(dev); */
+
+	byte = pm_ioread(0x55);
+	byte &= ~(1 << 7);
+	pm_iowrite(0x55, byte);
+
+	/* apic */
+	res = new_resource(dev, 0x74);
+	res->base  = 0xfec00000;
+	res->size = 256 * 0x10;
+	res->limit = 0xFEFFFFFUL;	/* res->base + res->size -1; */
+	res->align = 8;
+	res->gran = 8;
+	res->flags = IORESOURCE_MEM | IORESOURCE_FIXED;
+
+	#if 0			       /* Linux ACPI crashes when it is 1. For late debugging. */
+	res = new_resource(dev, 0x14); /* TODO: hpet */
+	res->base  = 0xfed00000;	/* reset hpet to widely accepted address */
+	res->size = 0x400;
+	res->limit = 0xFFFFFFFFUL;	/* res->base + res->size -1; */
+	res->align = 8;
+	res->gran = 8;
+	res->flags = IORESOURCE_MEM | IORESOURCE_FIXED;
+	#endif
+	/* dev->command |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; */
+
+	/* smbus */
+	//res = new_resource(dev, 0x90);
+	//res->base  = 0xB00;
+	//res->size = 0x10;
+	//res->limit = 0xFFFFUL;	/* res->base + res->size -1; */
+	//res->align = 8;
+	//res->gran = 8;
+	//res->flags = IORESOURCE_IO | IORESOURCE_FIXED;
+
+
+	compact_resources(dev);
+}
+
+static void sb800_sm_set_resources(struct device *dev)
+{
+	struct resource *res;
+	u8 byte;
+
+	pci_dev_set_resources(dev);
+
+
+	/* rpr2.14: Make HPET MMIO decoding controlled by the memory enable bit in command register of LPC ISA bridage */
+	byte = pm_ioread(0x52);
+	byte |= 1 << 6;
+	pm_iowrite(0x52, byte);
+
+	res = find_resource(dev, 0x74);
+
+	printk(BIOS_INFO, "sb800_sm_set_resources, res->base=%x\n", (u32)(res->base));
+
+	pm_iowrite(0x34, res->base | 0x7);
+	pm_iowrite(0x35, (res->base >> 8) & 0xFF);
+	pm_iowrite(0x36, (res->base >> 16) & 0xFF);
+	pm_iowrite(0x37, (res->base >> 24) & 0xFF);
+#if 0				/* TODO:hpet */
+	res = find_resource(dev, 0x14);
+	pci_write_config32(dev, 0x14, res->base);
+#endif
+	//res = find_resource(dev, 0x90);
+	//pci_write_config32(dev, 0x90, res->base | 1);
+}
+
+static struct pci_operations lops_pci = {
+	.set_subsystem = pci_dev_set_subsystem,
+};
+static struct device_operations smbus_ops = {
+	.read_resources = sb800_sm_read_resources,
+	.set_resources = sb800_sm_set_resources,
+	.enable_resources = pci_dev_enable_resources,
+	.init = sm_init,
+	.scan_bus = scan_static_bus,
+	.ops_pci = &lops_pci,
+	.ops_smbus_bus = &lops_smbus_bus,
+};
+static const struct pci_driver smbus_driver __pci_driver = {
+	.ops = &smbus_ops,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB800_SM,
+};
Index: trunk/src/southbridge/amd/sb800/smbus.c
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/smbus.c
@@ -0,0 +1,253 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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  _SB800_SMBUS_C_
+#define  _SB800_SMBUS_C_
+
+#include "smbus.h"
+
+static inline void smbus_delay(void)
+{
+	outb(inb(0x80), 0x80);
+}
+
+static int smbus_wait_until_ready(u32 smbus_io_base)
+{
+	u32 loops;
+	loops = SMBUS_TIMEOUT;
+	do {
+		u8 val;
+		val = inb(smbus_io_base + SMBHSTSTAT);
+		val &= 0x1f;
+		if (val == 0) {	/* ready now */
+			return 0;
+		}
+		outb(val, smbus_io_base + SMBHSTSTAT);
+	} while (--loops);
+	return -2;		/* time out */
+}
+
+static int smbus_wait_until_done(u32 smbus_io_base)
+{
+	u32 loops;
+	loops = SMBUS_TIMEOUT;
+	do {
+		u8 val;
+
+		val = inb(smbus_io_base + SMBHSTSTAT);
+		val &= 0x1f;	/* mask off reserved bits */
+		if (val & 0x1c) {
+			return -5;	/* error */
+		}
+		if (val == 0x02) {
+			outb(val, smbus_io_base + SMBHSTSTAT);	/* clear status */
+			return 0;
+		}
+	} while (--loops);
+	return -3;		/* timeout */
+}
+
+int do_smbus_recv_byte(u32 smbus_io_base, u32 device)
+{
+	u8 byte;
+
+	if (smbus_wait_until_ready(smbus_io_base) < 0) {
+		return -2;	/* not ready */
+	}
+
+	/* set the device I'm talking too */
+	outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
+
+	byte = inb(smbus_io_base + SMBHSTCTRL);
+	byte &= 0xe3;		/* Clear [4:2] */
+	byte |= (1 << 2) | (1 << 6);	/* Byte data read/write command, start the command */
+	outb(byte, smbus_io_base + SMBHSTCTRL);
+
+	/* poll for transaction completion */
+	if (smbus_wait_until_done(smbus_io_base) < 0) {
+		return -3;	/* timeout or error */
+	}
+
+	/* read results of transaction */
+	byte = inb(smbus_io_base + SMBHSTCMD);
+
+	return byte;
+}
+
+int do_smbus_send_byte(u32 smbus_io_base, u32 device, u8 val)
+{
+	u8 byte;
+
+	if (smbus_wait_until_ready(smbus_io_base) < 0) {
+		return -2;	/* not ready */
+	}
+
+	/* set the command... */
+	outb(val, smbus_io_base + SMBHSTCMD);
+
+	/* set the device I'm talking too */
+	outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
+
+	byte = inb(smbus_io_base + SMBHSTCTRL);
+	byte &= 0xe3;		/* Clear [4:2] */
+	byte |= (1 << 2) | (1 << 6);	/* Byte data read/write command, start the command */
+	outb(byte, smbus_io_base + SMBHSTCTRL);
+
+	/* poll for transaction completion */
+	if (smbus_wait_until_done(smbus_io_base) < 0) {
+		return -3;	/* timeout or error */
+	}
+
+	return 0;
+}
+
+int do_smbus_read_byte(u32 smbus_io_base, u32 device,
+			      u32 address)
+{
+	u8 byte;
+
+	if (smbus_wait_until_ready(smbus_io_base) < 0) {
+		return -2;	/* not ready */
+	}
+
+	/* set the command/address... */
+	outb(address & 0xff, smbus_io_base + SMBHSTCMD);
+
+	/* set the device I'm talking too */
+	outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
+
+	byte = inb(smbus_io_base + SMBHSTCTRL);
+	byte &= 0xe3;		/* Clear [4:2] */
+	byte |= (1 << 3) | (1 << 6);	/* Byte data read/write command, start the command */
+	outb(byte, smbus_io_base + SMBHSTCTRL);
+
+	/* poll for transaction completion */
+	if (smbus_wait_until_done(smbus_io_base) < 0) {
+		return -3;	/* timeout or error */
+	}
+
+	/* read results of transaction */
+	byte = inb(smbus_io_base + SMBHSTDAT0);
+
+	return byte;
+}
+
+int do_smbus_write_byte(u32 smbus_io_base, u32 device,
+			       u32 address, u8 val)
+{
+	u8 byte;
+
+	if (smbus_wait_until_ready(smbus_io_base) < 0) {
+		return -2;	/* not ready */
+	}
+
+	/* set the command/address... */
+	outb(address & 0xff, smbus_io_base + SMBHSTCMD);
+
+	/* set the device I'm talking too */
+	outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
+
+	/* output value */
+	outb(val, smbus_io_base + SMBHSTDAT0);
+
+	byte = inb(smbus_io_base + SMBHSTCTRL);
+	byte &= 0xe3;		/* Clear [4:2] */
+	byte |= (1 << 3) | (1 << 6);	/* Byte data read/write command, start the command */
+	outb(byte, smbus_io_base + SMBHSTCTRL);
+
+	/* poll for transaction completion */
+	if (smbus_wait_until_done(smbus_io_base) < 0) {
+		return -3;	/* timeout or error */
+	}
+
+	return 0;
+}
+
+void alink_ab_indx(u32 reg_space, u32 reg_addr,
+			  u32 mask, u32 val)
+{
+	u32 tmp;
+
+	outl((reg_space & 0x7) << 29 | reg_addr, AB_INDX);
+	tmp = inl(AB_DATA);
+	/* rpr 4.2
+	 * For certain revisions of the chip, the ABCFG registers,
+	 * with an address of 0x100NN (where 'N' is any hexadecimal
+	 * number), require an extra programming step.*/
+	outl(0, AB_INDX);
+
+	tmp &= ~mask;
+	tmp |= val;
+
+	/* printk(BIOS_DEBUG, "about write %x, index=%x", tmp, (reg_space&0x3)<<29 | reg_addr); */
+	outl((reg_space & 0x7) << 29 | reg_addr, AB_INDX);	/* probably we dont have to do it again. */
+	outl(tmp, AB_DATA);
+	outl(0, AB_INDX);
+}
+
+void alink_rc_indx(u32 reg_space, u32 reg_addr, u32 port,
+			  u32 mask, u32 val)
+{
+	u32 tmp;
+
+	outl((reg_space & 0x7) << 29 | (port & 3) << 24 | reg_addr, AB_INDX);
+	tmp = inl(AB_DATA);
+	/* rpr 4.2
+	 * For certain revisions of the chip, the ABCFG registers,
+	 * with an address of 0x100NN (where 'N' is any hexadecimal
+	 * number), require an extra programming step.*/
+	outl(0, AB_INDX);
+
+	tmp &= ~mask;
+	tmp |= val;
+
+	//printk(BIOS_DEBUG, "about write %x, index=%x", tmp, (reg_space&0x3)<<29 | (port&3) << 24 | reg_addr);
+	outl((reg_space & 0x7) << 29 | (port & 3) << 24 | reg_addr, AB_INDX);	/* probably we dont have to do it again. */
+	outl(tmp, AB_DATA);
+	outl(0, AB_INDX);
+}
+
+/* space = 0: AX_INDXC, AX_DATAC
+ * space = 1: AX_INDXP, AX_DATAP
+ */
+void alink_ax_indx(u32 space /*c or p? */ , u32 axindc,
+			  u32 mask, u32 val)
+{
+	u32 tmp;
+
+	/* read axindc to tmp */
+	outl(space << 29 | space << 3 | 0x30, AB_INDX);
+	outl(axindc, AB_DATA);
+	outl(0, AB_INDX);
+	outl(space << 29 | space << 3 | 0x34, AB_INDX);
+	tmp = inl(AB_DATA);
+	outl(0, AB_INDX);
+
+	tmp &= ~mask;
+	tmp |= val;
+
+	/* write tmp */
+	outl(space << 29 | space << 3 | 0x30, AB_INDX);
+	outl(axindc, AB_DATA);
+	outl(0, AB_INDX);
+	outl(space << 29 | space << 3 | 0x34, AB_INDX);
+	outl(tmp, AB_DATA);
+	outl(0, AB_INDX);
+}
+#endif
Index: trunk/src/southbridge/amd/sb800/usb.c
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/usb.c
@@ -0,0 +1,234 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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 <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <usbdebug.h>
+#include <arch/io.h>
+#include "sb800.h"
+
+static struct pci_operations lops_pci = {
+	.set_subsystem = pci_dev_set_subsystem,
+};
+
+static void usb_init(struct device *dev)
+{
+	u8 byte;
+	u16 word;
+
+	/* 7.1 Enable OHCI0-4 and EHCI Controllers */
+	/* pmio 0xEF; */
+
+	/* RPR 7.2 USB S4/S5 Wake-up or PHY Power-down Support */
+	byte = pm_ioread(0xF0);
+	byte |= 1 << 0;		/* A12, USB Wake from S5 not supported on the platform */
+	pm_iowrite(0xF0, byte);
+
+	/* RPR 7.4 Enable the USB controller to get reset by any software that generate a PCIRst# condition */
+	byte = pm_ioread(0xF0);
+	byte |= (1 << 2);
+	byte |= 3 << 8;		/* rpr 7.5 */
+	pm_iowrite(0xF0, byte);
+
+	/* RPR 7.9 Disable OHCI MSI Capability. */
+	word = pci_read_config16(dev, 0x40);
+	word |= (0x1 << 8);
+	pci_write_config16(dev, 0x40, word);
+}
+
+static void usb_init2(struct device *dev)
+{
+	u32 dword;
+	u32 usb2_bar0;
+	device_t sm_dev;
+
+	sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
+	//rev = get_sb800_revision(sm_dev);
+
+	/* dword = pci_read_config32(dev, 0xf8); */
+	/* dword |= 40; */
+	/* pci_write_config32(dev, 0xf8, dword); */
+
+	usb2_bar0 = pci_read_config32(dev, 0x10) & ~0xFF;
+	printk(BIOS_INFO, "usb2_bar0=0x%x\n", usb2_bar0);
+
+	/* RPR7.3 Enables the USB PHY auto calibration resister to match 45ohm resistence */
+	dword = 0x00020F00;
+	write32(usb2_bar0 + 0xC0, dword);
+
+	/* RPR7.8 Sets In/OUT FIFO threshold for best performance */
+	dword = 0x00400040;
+	write32(usb2_bar0 + 0xA4, dword);
+
+	/* RPR7.10 Disable EHCI MSI support */
+	dword = pci_read_config32(dev, 0x50);
+	dword |= (1 << 6);
+	pci_write_config32(dev, 0x50, dword);
+
+	/* RPR7.12 EHCI Async Park Mode */
+	dword = pci_read_config32(dev, 0x50);
+	dword &= ~(0xF << 8);
+	dword &= ~(0xF << 12);
+	dword |= 1 << 8;
+	dword |= 2 << 12;
+	pci_write_config32(dev, 0x50, dword);
+
+	/* RPR 6.12 EHCI Advance PHY Power Savings */
+	/* RPR says it is just for A12. CIMM sets it when it is above A11. */
+	/* But it makes the linux crash, so we skip it */
+	#if 0
+	dword = pci_read_config32(dev, 0x50);
+	dword |= 1 << 31;
+	pci_write_config32(dev, 0x50, dword);
+	#endif
+
+	/* Each step below causes the linux crashes. Leave them here
+	 * for future debugging. */
+#if 0
+	u8 byte;
+	u16 word;
+
+
+	/* RPR6.17 Disable the EHCI Dynamic Power Saving feature */
+	word = read32(usb2_bar0 + 0xBC);
+	word &= ~(1 << 12);
+	write16(usb2_bar0 + 0xBC, word);
+
+	/* RPR6.19 USB Controller DMA Read Delay Tolerant. */
+	if (rev >= REV_SB800_A14) {
+		byte = pci_read_config8(dev, 0x50);
+		byte |= (1 << 7);
+		pci_write_config8(dev, 0x50, byte);
+	}
+
+	/* RPR6.20 Async Park Mode. */
+	/* RPR recommends not to set these bits. */
+	#if 0
+	dword = pci_read_config32(dev, 0x50);
+	dword |= 1 << 23;
+	if (rev >= REV_SB800_A14) {
+		dword &= ~(1 << 2);
+	}
+	pci_write_config32(dev, 0x50, dword);
+	#endif
+
+	/* RPR6.22 Advance Async Enhancement */
+	/* RPR6.23 USB Periodic Cache Setting */
+	dword = pci_read_config32(dev, 0x50);
+	if (rev == REV_SB800_A12) {
+		dword |= 1 << 28; /* 6.22 */
+		dword |= 1 << 27; /* 6.23 */
+	} else if (rev >= REV_SB800_A14) {
+		dword |= 1 << 3;
+		dword &= ~(1 << 28); /* 6.22 */
+		dword |= 1 << 8;
+		dword &= ~(1 << 27); /* 6.23 */
+	}
+	printk(BIOS_DEBUG, "rpr 6.23, final dword=%x\n", dword);
+#endif
+}
+
+static void usb_set_resources(struct device *dev)
+{
+#if CONFIG_USBDEBUG
+	struct resource *res;
+	u32 base;
+	u32 old_debug;
+
+	old_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(old_debug);
+	if (!res)
+		return;
+	base = res->base;
+	set_ehci_base(base);
+	report_resource_stored(dev, res, "");
+#endif
+
+}
+
+static struct device_operations usb_ops = {
+	.read_resources = pci_dev_read_resources,
+	.set_resources = usb_set_resources, /* pci_dev_set_resources, */
+	.enable_resources = pci_dev_enable_resources,
+	.init = usb_init,
+	.scan_bus = 0,
+	.ops_pci = &lops_pci,
+};
+
+static const struct pci_driver usb_0_driver __pci_driver = {
+	.ops = &usb_ops,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB800_USB_18_0,
+};
+static const struct pci_driver usb_1_driver __pci_driver = {
+	.ops = &usb_ops,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB800_USB_18_2,
+};
+
+/* the pci id of usb ctrl 0 and 1 are the same. */
+/*
+ * static const struct pci_driver usb_3_driver __pci_driver = {
+ * 	.ops = &usb_ops,
+ * 	.vendor = PCI_VENDOR_ID_ATI,
+ * 	.device = PCI_DEVICE_ID_ATI_SB800_USB_19_0,
+ * };
+ * static const struct pci_driver usb_4_driver __pci_driver = {
+ * 	.ops = &usb_ops,
+ * 	.vendor = PCI_VENDOR_ID_ATI,
+ * 	.device = PCI_DEVICE_ID_ATI_SB800_USB_19_1,
+ * };
+ */
+
+static const struct pci_driver usb_4_driver __pci_driver = {
+	.ops = &usb_ops,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB800_USB_20_5,
+};
+
+static struct device_operations usb_ops2 = {
+	.read_resources = pci_dev_read_resources,
+	.set_resources = usb_set_resources, /* pci_dev_set_resources, */
+	.enable_resources = pci_dev_enable_resources,
+	.init = usb_init2,
+	.scan_bus = 0,
+	.ops_pci = &lops_pci,
+};
+
+static const struct pci_driver usb_5_driver __pci_driver = {
+	.ops = &usb_ops2,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB800_USB_18_2,
+};
+/*
+ * static const struct pci_driver usb_5_driver __pci_driver = {
+ * 	.ops = &usb_ops2,
+ * 	.vendor = PCI_VENDOR_ID_ATI,
+ * 	.device = PCI_DEVICE_ID_ATI_SB800_USB_19_2,
+ * };
+ */
Index: trunk/src/southbridge/amd/sb800/Kconfig
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/Kconfig
@@ -0,0 +1,27 @@ 
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2010 Advanced Micro Devices, 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_AMD_SB800
+	bool
+	select IOAPIC
+
+config BOOTBLOCK_SOUTHBRIDGE_INIT
+        string
+        default "southbridge/amd/sb800/bootblock.c"
+
Index: trunk/src/southbridge/amd/sb800/Makefile.inc
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/Makefile.inc
@@ -0,0 +1,10 @@ 
+driver-y += sb800.c
+driver-y += usb.c
+driver-y += lpc.c
+driver-y += sm.c
+driver-y += ide.c
+driver-y += sata.c
+driver-y += hda.c
+driver-y += pci.c
+driver-y += pcie.c
+ramstage-y += reset.c
Index: trunk/src/southbridge/amd/sb800/enable_usbdebug.c
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/enable_usbdebug.c
@@ -0,0 +1,36 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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 SB800_DEVN_BASE
+
+#define SB800_DEVN_BASE 0
+
+#endif
+
+#define EHCI_BAR_INDEX 0x10
+#define EHCI_BAR 0xFEF00000
+#define EHCI_DEBUG_OFFSET 0xE0
+
+static void sb800_enable_usbdebug(u32 port)
+{
+	set_debug_port(port);
+	pci_write_config32(PCI_DEV(0, SB800_DEVN_BASE + 0x13, 5),
+			   EHCI_BAR_INDEX, EHCI_BAR);
+y	pci_write_config8(PCI_DEV(0, SB800_DEVN_BASE + 0x13, 5), 0x04, 0x2);	/* mem space enabe */
+}
Index: trunk/src/southbridge/amd/sb800/ide.c
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/ide.c
@@ -0,0 +1,83 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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 <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "sb800.h"
+
+static void ide_init(struct device *dev)
+{
+	struct southbridge_amd_sb800_config *conf;
+	/* Enable ide devices so the linux ide driver will work */
+	u32 dword;
+	u8 byte;
+
+	conf = dev->chip_info;
+
+	/* RPR9.1 disable MSI */
+	/* TODO: For A14, it should set as 1. I doubt it. */
+	dword = pci_read_config32(dev, 0x70);
+	dword &= ~(1 << 16);
+	pci_write_config32(dev, 0x70, dword);
+
+	/* Ultra DMA mode */
+	/* enable UDMA */
+	byte = pci_read_config8(dev, 0x54);
+	byte |= 1 << 0;
+	pci_write_config8(dev, 0x54, byte);
+
+	/* Enable I/O Access&& Bus Master */
+	dword = pci_read_config16(dev, 0x4);
+	dword |= 1 << 2;
+	pci_write_config16(dev, 0x4, dword);
+
+	/* set ide as primary, if you want to boot from IDE, you'd better set it
+	 * in mainboard/Config.lb */
+	if (conf->boot_switch_sata_ide == 1) {
+		byte = pci_read_config8(dev, 0xAD);
+		byte |= 1 << 4;
+		pci_write_config8(dev, 0xAD, byte);
+	}
+
+#if CONFIG_PCI_ROM_RUN == 1
+	pci_dev_init(dev);
+#endif
+}
+
+static struct pci_operations lops_pci = {
+	.set_subsystem = pci_dev_set_subsystem,
+};
+
+static struct device_operations ide_ops = {
+	.read_resources = pci_dev_read_resources,
+	.set_resources = pci_dev_set_resources,
+	.enable_resources = pci_dev_enable_resources,
+	.init = ide_init,
+	.scan_bus = 0,
+	.ops_pci = &lops_pci,
+};
+
+static const struct pci_driver ide_driver __pci_driver = {
+	.ops = &ide_ops,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB800_IDE,
+};
Index: trunk/src/southbridge/amd/sb800/sb800.h
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/sb800.h
@@ -0,0 +1,65 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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 SB800_H
+#define SB800_H
+
+#include <device/pci_ids.h>
+#include "chip.h"
+
+#define SMBUS_IO_BASE	0x6000
+
+/* Power management index/data registers */
+#define PM_INDEX	0xcd6
+#define PM_DATA		0xcd7
+#define PM2_INDEX	0xcd0
+#define PM2_DATA	0xcd1
+
+#define PM_BASE			0x800
+#define ACPI_PM_EVT_BLK		(PM_BASE + 0x00) /* 4 bytes */
+#define ACPI_PM1_CNT_BLK	(PM_BASE + 0x04) /* 2 bytes */
+#define ACPI_PMA_CNT_BLK	(PM_BASE + 0x0F) /* 1 byte  */
+#define ACPI_PM_TMR_BLK		(PM_BASE + 0x18) /* 4 bytes */
+#define ACPI_GPE0_BLK		(PM_BASE + 0x10) /* 8 bytes */
+#define ACPI_CPU_CONTORL	(PM_BASE + 0x08) /* 6 bytes */
+
+#define REV_SB800_A11	0x11
+#define REV_SB800_A12	0x12
+
+extern void pm_iowrite(u8 reg, u8 value);
+extern u8 pm_ioread(u8 reg);
+extern void pm2_iowrite(u8 reg, u8 value);
+extern u8 pm2_ioread(u8 reg);
+extern void set_sm_enable_bits(device_t sm_dev, u32 reg_pos, u32 mask, u32 val);
+
+/* This shouldn't be called before set_sb800_revision() is called.
+ * Once set_sb800_revision() is called, we use get_sb800_revision(),
+ * the simpler one, to get the sb800 revision ID.
+ * The id is 0x39 if A11, 0x3A if A12, 0x3C if A14, 0x3D if A15.
+ * The differentiate is 0x28, isn't it? */
+//#define get_sb800_revision(sm_dev)	(pci_read_config8((sm_dev), 0x08) - 0x28)
+
+void sb800_enable(device_t dev);
+
+#ifdef __PRE_RAM__
+void sb800_lpc_port80(void);
+void sb800_pci_port80(void);
+#endif
+
+#endif /* SB800_H */
Index: trunk/src/southbridge/amd/sb800/smbus.h
===================================================================
--- /dev/null
+++ trunk/src/southbridge/amd/sb800/smbus.h
@@ -0,0 +1,76 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, 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 SB800_SMBUS_H
+#define SB800_SMBUS_H
+
+//#include <stdint.h>
+
+#define SMBHSTSTAT 0x0
+#define SMBSLVSTAT 0x1
+#define SMBHSTCTRL 0x2
+#define SMBHSTCMD  0x3
+#define SMBHSTADDR 0x4
+#define SMBHSTDAT0 0x5
+#define SMBHSTDAT1 0x6
+#define SMBHSTBLKDAT 0x7
+
+#define SMBSLVCTRL 0x8
+#define SMBSLVCMD_SHADOW 0x9
+#define SMBSLVEVT 0xa
+#define SMBSLVDAT 0xc
+
+#define AX_INDXC  0
+#define AX_INDXP  2
+#define AXCFG     4
+#define ABCFG     6
+#define RC_INDXC  1
+#define RC_INDXP  3
+
+#define AB_INDX   0xCD8
+#define AB_DATA   (AB_INDX+4)
+
+/* Between 1-10 seconds, We should never timeout normally
+ * Longer than this is just painful when a timeout condition occurs.
+ */
+#define SMBUS_TIMEOUT (100*1000*10)
+
+#define abcfg_reg(reg, mask, val)	\
+	alink_ab_indx((ABCFG), (reg), (mask), (val))
+#define axcfg_reg(reg, mask, val)	\
+	alink_ab_indx((AXCFG), (reg), (mask), (val))
+#define axindxc_reg(reg, mask, val)	\
+	alink_ax_indx((AX_INDXC), (reg), (mask), (val))
+#define axindxp_reg(reg, mask, val)		\
+	alink_ax_indx((AX_INDXP), (reg), (mask), (val))
+#define rcindxc_reg(reg, port, mask, val)	\
+	alink_rc_indx((RC_INDXC), (reg), (port), (mask), (val))
+#define rcindxp_reg(reg, port, mask, val)	\
+	alink_rc_indx((RC_INDXP), (reg), (port), (mask), (val))
+
+int do_smbus_recv_byte(u32 smbus_io_base, u32 device);
+int do_smbus_send_byte(u32 smbus_io_base, u32 device, u8 val);
+int do_smbus_read_byte(u32 smbus_io_base, u32 device, u32 address);
+int do_smbus_write_byte(u32 smbus_io_base, u32 device, u32 address, u8 val);
+
+void alink_ab_indx(u32 reg_space, u32 reg_addr, u32 mask, u32 val);
+void alink_ax_indx(u32 space, u32 axindc, u32 mask, u32 val);
+void alink_rc_indx(u32 reg_space, u32 reg_addr, u32 port, u32 mask, u32 val);
+
+#endif