From 2ddaf32b63d12d630da6726ba6fa46caa0e5940f Mon Sep 17 00:00:00 2001
From: Timothy Pearson <tpearson@raptorengineeringinc.com>
Date: Tue, 9 Jun 2015 18:09:50 -0500
Subject: [PATCH 049/143] southbridge/amd/sb700: Add AHCI support

Change-Id: I147284e6a435f4b96d6821a122c1f4f9ddc2ea33
Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
---
 src/include/device/pci_ids.h             |    2 +
 src/mainboard/asus/kgpe-d16/Kconfig      |    4 +
 src/mainboard/asus/kgpe-d16/cmos.default |    1 +
 src/mainboard/asus/kgpe-d16/cmos.layout  |    3 +-
 src/southbridge/amd/sb700/Kconfig        |    4 +
 src/southbridge/amd/sb700/early_setup.c  |   73 ++++++---
 src/southbridge/amd/sb700/ide.c          |   42 +++--
 src/southbridge/amd/sb700/sata.c         |  256 ++++++++++++++++++++----------
 src/southbridge/amd/sb800/fadt.c         |    1 +
 9 files changed, 267 insertions(+), 119 deletions(-)

diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h
index fcaf4aa..664ac49 100644
--- a/src/include/device/pci_ids.h
+++ b/src/include/device/pci_ids.h
@@ -311,6 +311,8 @@
 
 #define PCI_DEVICE_ID_ATI_SB700_LPC		0x439D
 #define PCI_DEVICE_ID_ATI_SB700_SATA		0x4390
+#define PCI_DEVICE_ID_ATI_SB700_SATA_AHCI	0x4391
+#define PCI_DEVICE_ID_ATI_SB700_SATA_AHCI_AMD	0x4394
 #define PCI_DEVICE_ID_ATI_SB700_IDE		0x439C
 #define PCI_DEVICE_ID_ATI_SB700_HDA		0x4383
 #define PCI_DEVICE_ID_ATI_SB700_PCI		0x4384
diff --git a/src/mainboard/asus/kgpe-d16/Kconfig b/src/mainboard/asus/kgpe-d16/Kconfig
index 8906dee..75bf0ee 100644
--- a/src/mainboard/asus/kgpe-d16/Kconfig
+++ b/src/mainboard/asus/kgpe-d16/Kconfig
@@ -89,6 +89,10 @@ config IRQ_SLOT_COUNT
 	int
 	default 13
 
+config SOUTHBRIDGE_AMD_SB700_SATA_PORT_COUNT_BITFIELD
+	hex
+	default 0x3f
+
 config ONBOARD_VGA_IS_PRIMARY
 	bool
 	default y
diff --git a/src/mainboard/asus/kgpe-d16/cmos.default b/src/mainboard/asus/kgpe-d16/cmos.default
index e3eb4fe..5bfaadd 100644
--- a/src/mainboard/asus/kgpe-d16/cmos.default
+++ b/src/mainboard/asus/kgpe-d16/cmos.default
@@ -16,6 +16,7 @@ interleave_nodes = Disable
 interleave_memory_channels = Enable
 cpu_c_states = Enable
 cpu_cc6_state = Enable
+sata_ahci_mode = Enable
 ieee1394 = Enable
 power_on_after_fail = On
 boot_option = Fallback
diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout b/src/mainboard/asus/kgpe-d16/cmos.layout
index 7f9f661..247fd7b 100644
--- a/src/mainboard/asus/kgpe-d16/cmos.layout
+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
@@ -45,7 +45,8 @@ entries
 464          1       e       2        compute_unit_siblings
 465          1       e       1        cpu_c_states
 466          1       e       1        cpu_cc6_state
-467          1       r       0        allow_spd_nvram_cache_restore
+467          1       e       1        sata_ahci_mode
+468          1       r       0        allow_spd_nvram_cache_restore
 477          1       e       1        ieee1394
 728        256       h       0        user_data
 984         16       h       0        check_sum
diff --git a/src/southbridge/amd/sb700/Kconfig b/src/southbridge/amd/sb700/Kconfig
index bca74fb..05eac5f 100644
--- a/src/southbridge/amd/sb700/Kconfig
+++ b/src/southbridge/amd/sb700/Kconfig
@@ -46,6 +46,10 @@ config SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA
 	bool
 	default n
 
+config SOUTHBRIDGE_AMD_SB700_SATA_PORT_COUNT_BITFIELD
+	hex
+	default 0xf
+
 config EHCI_BAR
 	hex
 	default 0xfef00000
diff --git a/src/southbridge/amd/sb700/early_setup.c b/src/southbridge/amd/sb700/early_setup.c
index fd3b099..a06a72f 100644
--- a/src/southbridge/amd/sb700/early_setup.c
+++ b/src/southbridge/amd/sb700/early_setup.c
@@ -354,9 +354,13 @@ static void sb700_devices_por_init(void)
 {
 	device_t dev;
 	u8 byte;
-#if CONFIG_SOUTHBRIDGE_AMD_SUBTYPE_SP5100
-	u32 dword;
-#endif
+	uint32_t dword;
+	uint8_t nvram;
+	uint8_t sata_ahci_mode;
+
+	sata_ahci_mode = 0;
+	if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
+		sata_ahci_mode = !!nvram;
 
 	printk(BIOS_INFO, "sb700_devices_por_init()\n");
 	/* SMBus Device, BDF:0-20-0 */
@@ -517,34 +521,56 @@ static void sb700_devices_por_init(void)
 	/* Enable PCIB_DUAL_EN_UP will fix potential problem with PCI cards. */
 	pci_write_config8(dev, 0x50, 0x01);
 
+	if (!sata_ahci_mode){
 #if CONFIG_SOUTHBRIDGE_AMD_SUBTYPE_SP5100
-	/* SP5100 default SATA mode is RAID5 MODE */
-	dev = pci_locate_device(PCI_ID(0x1002, 0x4393), 0);
-	/* Set SATA Operation Mode, Set to IDE mode */
-	byte = pci_read_config8(dev, 0x40);
-	byte |= (1 << 0);
-	pci_write_config8(dev, 0x40, byte);
+		/* SP5100 default SATA mode is RAID5 MODE */
+		dev = pci_locate_device(PCI_ID(0x1002, 0x4393), 0);
+
+		/* Set SATA Operation Mode, Set to IDE mode */
+		byte = pci_read_config8(dev, 0x40);
+		byte |= (1 << 0);
+		pci_write_config8(dev, 0x40, byte);
 
-	dword = 0x01018f00;
-	pci_write_config32(dev, 0x8, dword);
+		dword = 0x01018f00;
+		pci_write_config32(dev, 0x8, dword);
 
-	/* set SATA Device ID writable */
-	dword = pci_read_config32(dev, 0x40);
-	dword &= ~(1 << 24);
-	pci_write_config32(dev, 0x40, dword);
+		/* set SATA Device ID writable */
+		dword = pci_read_config32(dev, 0x40);
+		dword &= ~(1 << 24);
+		pci_write_config32(dev, 0x40, dword);
 
-	/* set Device ID accommodate with IDE emulation mode configuration*/
-	pci_write_config32(dev, 0x0, 0x43901002);
+		/* set Device ID consistent with IDE emulation mode configuration */
+		pci_write_config32(dev, 0x0, 0x43901002);
 
-	/* rpr v2.13 4.17 Reset CPU on Sync Flood */
-	abcfg_reg(0x10050, 1 << 2, 1 << 2);
+		/* rpr v2.13 4.17 Reset CPU on Sync Flood */
+		abcfg_reg(0x10050, 1 << 2, 1 << 2);
 #endif
+	}
 
 	/* SATA Device, BDF:0-17-0, Non-Raid-5 SATA controller */
-	printk(BIOS_INFO, "sb700_devices_por_init(): SATA Device, BDF:0-18-0\n");
+	printk(BIOS_INFO, "sb700_devices_por_init(): SATA Device, BDF:0-17-0\n");
 	dev = pci_locate_device(PCI_ID(0x1002, 0x4390), 0);
 
-	/*PHY Global Control*/
+	if (sata_ahci_mode) {
+		/* Switch to AHCI mode (AMD inbox) */
+		dword = pci_read_config32(dev, 0x40);
+		dword |= (0x1 << 24);		/* Lock Flash Device ID = 1 */
+		pci_write_config32(dev, 0x40, dword);
+
+		/* Deactivate Sub-Class Code write protection */
+		byte = pci_read_config8(dev, 0x40);
+		byte |= (1 << 0);
+		pci_write_config8(dev, 0x40, byte);
+
+		dword = pci_read_config32(dev, 0x08);
+		dword &= ~(0xff << 16);		/* Sub-Class Code = 0x6 */
+		dword |= (0x6 << 16);
+		dword &= ~(0xff << 8);		/* Operating Mode Selection = 0x1 */
+		dword |= (0x1 << 8);
+		pci_write_config32(dev, 0x08, dword);
+	}
+
+	/* PHY Global Control */
 	pci_write_config16(dev, 0x86, 0x2C00);
 }
 
@@ -695,6 +721,11 @@ static void sb700_pci_cfg(void)
 
 	/* SATA Device, BDF:0-17-0, Non-Raid-5 SATA controller */
 	dev = pci_locate_device(PCI_ID(0x1002, 0x4390), 0);
+	if (dev == PCI_DEV_INVALID)
+		dev = pci_locate_device(PCI_ID(0x1002, 0x4391), 0);
+	if (dev == PCI_DEV_INVALID)
+		dev = pci_locate_device(PCI_ID(0x1002, 0x4394), 0);
+
 	/* rpr7.12 SATA MSI and D3 Power State Capability. */
 	byte = pci_read_config8(dev, 0x40);
 	byte |= 1 << 0;
diff --git a/src/southbridge/amd/sb700/ide.c b/src/southbridge/amd/sb700/ide.c
index 8803d7f..4e07717 100644
--- a/src/southbridge/amd/sb700/ide.c
+++ b/src/southbridge/amd/sb700/ide.c
@@ -1,6 +1,7 @@
 /*
  * This file is part of the coreboot project.
  *
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
  * Copyright (C) 2010 Advanced Micro Devices, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -22,6 +23,7 @@
 #include <device/pci.h>
 #include <device/pci_ids.h>
 #include <device/pci_ops.h>
+#include <option.h>
 #include "sb700.h"
 
 static void ide_init(struct device *dev)
@@ -30,6 +32,12 @@ static void ide_init(struct device *dev)
 	/* Enable ide devices so the linux ide driver will work */
 	u32 dword;
 	u8 byte;
+	uint8_t nvram;
+	uint8_t sata_ahci_mode;
+
+	sata_ahci_mode = 0;
+	if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
+		sata_ahci_mode = !!nvram;
 
 	conf = dev->chip_info;
 
@@ -39,25 +47,25 @@ static void ide_init(struct device *dev)
 	dword &= ~(1 << 16);
 	pci_write_config32(dev, 0x70, dword);
 
-	/* Enable UDMA on all devices, it will become UDMA0 (default PIO is PIO0) */
-	byte = pci_read_config8(dev, 0x54);
-	byte |= 0xf;
-	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 $vendor/$mainboard/devicetree.cb */
+	if (!sata_ahci_mode) {
+		/* Enable UDMA on all devices, it will become UDMA0 (default PIO is PIO0) */
+		byte = pci_read_config8(dev, 0x54);
+		byte |= 0xf;
+		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);
 
-	if (conf->boot_switch_sata_ide == 1) {
-		struct device *sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
-		byte = pci_read_config8(sm_dev, 0xAD);
-		byte |= 1 << 4;
-		pci_write_config8(sm_dev, 0xAD, byte);
+		/* set ide as primary, if you want to boot from IDE, you'd better set it
+		 * in $vendor/$mainboard/devicetree.cb */
+		if (conf->boot_switch_sata_ide == 1) {
+			struct device *sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
+			byte = pci_read_config8(sm_dev, 0xad);
+			byte |= 1 << 4;
+			pci_write_config8(sm_dev, 0xad, byte);
+		}
 	}
 }
 
diff --git a/src/southbridge/amd/sb700/sata.c b/src/southbridge/amd/sb700/sata.c
index 172ad36..d97288a 100644
--- a/src/southbridge/amd/sb700/sata.c
+++ b/src/southbridge/amd/sb700/sata.c
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
  *
  * 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
@@ -24,18 +25,19 @@
 #include <device/pci_ids.h>
 #include <device/pci_ops.h>
 #include <arch/io.h>
+#include <option.h>
 #include "sb700.h"
 
-static int sata_drive_detect(int portnum, u16 iobar)
+static int sata_drive_detect(int portnum, uint16_t iobar)
 {
 	u8 byte, byte2;
 	int i = 0;
-	outb(0xA0 + 0x10 * (portnum % 2), iobar + 0x6);
+	outb(0xa0 + 0x10 * (portnum % 2), iobar + 0x6);
 	while (byte = inb(iobar + 0x6), byte2 = inb(iobar + 0x7),
-		(byte != (0xA0 + 0x10 * (portnum % 2))) ||
+		(byte != (0xa0 + 0x10 * (portnum % 2))) ||
 		((byte2 & 0x88) != 0)) {
 		printk(BIOS_SPEW, "0x6=%x, 0x7=%x\n", byte, byte2);
-		if (byte != (0xA0 + 0x10 * (portnum % 2))) {
+		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 populated.
@@ -65,15 +67,15 @@ void __attribute__((weak)) sb7xx_51xx_setup_sata_phys(struct device *dev)
 	pci_write_config32(dev, 0x90, 0x01B48016);
 	pci_write_config32(dev, 0x94, 0x01B48016);
 	pci_write_config32(dev, 0x98, 0x01B48016);
-	pci_write_config32(dev, 0x9C, 0x01B48016);
+	pci_write_config32(dev, 0x9c, 0x01B48016);
 
 	/* RPR7.6.3 SATA GEN II PHY port setting for port [0~5]. */
-	pci_write_config16(dev, 0xA0, 0xA09A);
-	pci_write_config16(dev, 0xA2, 0xA09F);
-	pci_write_config16(dev, 0xA4, 0xA07A);
-	pci_write_config16(dev, 0xA6, 0xA07A);
-	pci_write_config16(dev, 0xA8, 0xA07A);
-	pci_write_config16(dev, 0xAA, 0xA07A);
+	pci_write_config16(dev, 0xa0, 0xA09A);
+	pci_write_config16(dev, 0xa2, 0xA09F);
+	pci_write_config16(dev, 0xa4, 0xA07A);
+	pci_write_config16(dev, 0xa6, 0xA07A);
+	pci_write_config16(dev, 0xa8, 0xA07A);
+	pci_write_config16(dev, 0xaa, 0xA07A);
 }
 
 static void sata_init(struct device *dev)
@@ -83,8 +85,18 @@ static void sata_init(struct device *dev)
 	u32 dword;
 	u8 rev_id;
 	void *sata_bar5;
-	u16 sata_bar0, sata_bar1, sata_bar2, sata_bar3, sata_bar4;
+	uint16_t sata_bar0, sata_bar1, sata_bar2, sata_bar3, sata_bar4;
+	uint16_t ide_bar0, ide_bar1, ide_bar2, ide_bar3;
+	uint16_t current_bar;
 	int i, j;
+	uint8_t nvram;
+	uint8_t sata_ahci_mode;
+	uint8_t port_count;
+	uint8_t max_port_count;
+
+	sata_ahci_mode = 0;
+	if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
+		sata_ahci_mode = !!nvram;
 
 	device_t sm_dev;
 	/* SATA SMBus Disable */
@@ -98,21 +110,39 @@ static void sata_init(struct device *dev)
 	byte |= (1 << 5);
 	pci_write_config8(sm_dev, 0xad, byte);
 
+	/* get rev_id */
+	rev_id = pci_read_config8(sm_dev, 0x08) - 0x28;
+
+	if (sata_ahci_mode) {
+		/* Enable link latency enhancement on A14 and above */
+		if (rev_id >= 0x14) {
+			byte = pci_read_config8(sm_dev, 0xad);
+			byte &= ~(1 << 5);
+			pci_write_config8(sm_dev, 0xad, byte);
+		}
+	}
+
+	/* Disable combined mode */
+	byte = pci_read_config8(sm_dev, 0xad);
+	byte &= ~(1 << 3);
+	pci_write_config8(sm_dev, 0xad, byte);
+
+	device_t ide_dev;
+	/* IDE Device */
+	ide_dev = dev_find_slot(0, PCI_DEVFN(0x14, 1));
+
 	/* RPR 7.2 SATA Initialization */
 	/* Set the interrupt Mapping to INTG# */
 	byte = pci_read_config8(sm_dev, 0xaf);
 	byte = 0x6 << 2;
 	pci_write_config8(sm_dev, 0xaf, byte);
 
-	/* get rev_id */
-	rev_id = pci_read_config8(sm_dev, 0x08) - 0x28;
-
 	/* get base address */
 	sata_bar5 = (void *)(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_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 */
@@ -122,11 +152,16 @@ static void sata_init(struct device *dev)
 	printk(BIOS_SPEW, "sata_bar4=%x\n", sata_bar4);	/* 3000 */
 	printk(BIOS_SPEW, "sata_bar5=%p\n", sata_bar5);	/* e0309000 */
 
-	/* disable combined mode */
-	byte = pci_read_config8(sm_dev, 0xAD);
-	byte &= ~(1 << 3);
-	pci_write_config8(sm_dev, 0xAD, byte);
-	/* Program the 2C to 0x43801002 */
+	ide_bar0 = pci_read_config16(ide_dev, 0x10) & ~0x7;
+	ide_bar1 = pci_read_config16(ide_dev, 0x14) & ~0x3;
+	ide_bar2 = pci_read_config16(ide_dev, 0x18) & ~0x7;
+	ide_bar3 = pci_read_config16(ide_dev, 0x1c) & ~0x3;
+	printk(BIOS_SPEW, "ide_bar0=%x\n", ide_bar0);
+	printk(BIOS_SPEW, "ide_bar1=%x\n", ide_bar1);
+	printk(BIOS_SPEW, "ide_bar2=%x\n", ide_bar2);
+	printk(BIOS_SPEW, "ide_bar3=%x\n", ide_bar3);
+
+	/* Program the Subsystem ID/VID to 0x43801002 */
 	dword = 0x43801002;
 	pci_write_config32(dev, 0x2c, dword);
 
@@ -140,15 +175,48 @@ static void sata_init(struct device *dev)
 	byte |= (1 << 2);
 	pci_write_config8(dev, 0x40, byte);
 
-	/* Set SATA Operation Mode, Set to IDE mode */
+	/* Unlock subclass and certain BAR R/O registers */
 	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);
+	/* Disable AHCI enhancement (AMD SP5100 RPR page 54) */
+	dword = pci_read_config32(dev, 0x40);
+	dword |= (1 << 23);
+	pci_write_config32(dev, 0x40, dword);
+
+	if (sata_ahci_mode) {
+		/* Force number of ports to 6
+		 * NOTE: This is not documented in the register
+		 * reference guide, but CIMX needs to do this
+		 * to activate all 6 ports when IDE is disabled.
+		 */
+		dword = read32(sata_bar5 + 0x00);
+		dword &= ~0x7;
+		dword |= 0x5;
+		write32(sata_bar5 + 0x00, dword);
+	} else {
+		/* Set SATA Operation Mode, Set to IDE mode */
+		byte = pci_read_config8(dev, 0x40);
+		byte |= (1 << 4);
+		pci_write_config8(dev, 0x40, byte);
+
+		dword = 0x01018f00;
+		pci_write_config32(dev, 0x8, dword);
+	}
+
+	/* Get maximum number of ports */
+	max_port_count = read32(sata_bar5 + 0x00) & 0x1f;
+	max_port_count++;
+	printk(BIOS_SPEW, "Maximum SATA port count supported by silicon: %d\n", max_port_count);
 
+	/* Set number of ports */
+	dword = CONFIG_SOUTHBRIDGE_AMD_SB700_SATA_PORT_COUNT_BITFIELD;
+	for (i = max_port_count; i < 32; i++)
+		dword &= ~(0x1 << i);
+	write32(sata_bar5 + 0x0c, dword);
+
+	/* Write protect Sub-Class Code */
 	byte = pci_read_config8(dev, 0x40);
 	byte &= ~(1 << 0);
 	pci_write_config8(dev, 0x40, byte);
@@ -181,6 +249,7 @@ static void sata_init(struct device *dev)
 	byte = 0x10;
 	pci_write_config8(dev, 0x46, byte);
 	sb7xx_51xx_setup_sata_phys(dev);
+
 	/* Enable the I/O, MM, BusMaster access for SATA */
 	byte = pci_read_config8(dev, 0x4);
 	byte |= 7 << 0;
@@ -191,62 +260,75 @@ static void sata_init(struct device *dev)
 	pci_write_config32(dev, 0xC, 0x00004000);
 #endif
 
-	/* 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");
+	/* Determine port count */
+	port_count = 0;
+	for (i = 0; i < 32; i++) {
+		if (CONFIG_SOUTHBRIDGE_AMD_SB700_SATA_PORT_COUNT_BITFIELD & (0x1 << i))
+			port_count = i;
+	}
+	port_count++;
+	if (port_count > max_port_count)
+		port_count = max_port_count;
+
+	if (!sata_ahci_mode) {
+		/* 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 */
+		for (i = 0; i < port_count; 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);
+				/* 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);
+				/* Set Reset Bit and 1.5g bit */
+				byte |= 0x11;
+				write8((sata_bar5 + 0x12C + 0x80 * i), byte);
 
-			/* Wait 1ms */
-			mdelay(1);
+				/* Wait 1ms */
+				mdelay(1);
 
-			/* Clear Reset Bit */
-			byte &= ~0x01;
-			write8((sata_bar5 + 0x12C + 0x80 * i), byte);
+				/* Clear Reset Bit */
+				byte &= ~0x01;
+				write8((sata_bar5 + 0x12C + 0x80 * i), byte);
 
-			/* Wait 1ms */
-			mdelay(1);
+				/* 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;
-		}
+				/* 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;
+			if (byte == 0x3) {
+				for (j = 0; j < 10; j++) {
+					if (i < 4)
+						current_bar = ((i / 2) == 0) ? sata_bar0 : sata_bar2;
+					else
+						current_bar = ide_bar0;
+					if (!sata_drive_detect(i, current_bar))
+						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);
 			}
-			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);
 		}
 	}
 
@@ -256,13 +338,15 @@ static void sata_init(struct device *dev)
 	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);
+	if (!sata_ahci_mode) {
+		/* 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??? */
@@ -293,3 +377,15 @@ static const struct pci_driver sata0_driver __pci_driver = {
 	.vendor = PCI_VENDOR_ID_ATI,
 	.device = PCI_DEVICE_ID_ATI_SB700_SATA,
 };
+
+static const struct pci_driver sata1_driver __pci_driver = {
+	.ops = &sata_ops,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB700_SATA_AHCI,
+};
+
+static const struct pci_driver sata2_driver __pci_driver = {
+	.ops = &sata_ops,
+	.vendor = PCI_VENDOR_ID_ATI,
+	.device = PCI_DEVICE_ID_ATI_SB700_SATA_AHCI_AMD,
+};
diff --git a/src/southbridge/amd/sb800/fadt.c b/src/southbridge/amd/sb800/fadt.c
index 30b4496..5eb83d7 100644
--- a/src/southbridge/amd/sb800/fadt.c
+++ b/src/southbridge/amd/sb800/fadt.c
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
  *
  * 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
-- 
1.7.9.5

