sb/intel/i82801gx: Detect if the southbridge supports AHCI

This automatically detects whether the southbridge supports AHCI.
If AHCI support is selected it will be used unless "sata_no_ahci" is
set in the devicetree to override the behavior.

Change-Id: I8d9f4e63ae8b2862c422938f3103c44e761bcda4
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/30822
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nico Huber <nico.h@gmx.de>
diff --git a/src/mainboard/apple/macbook21/devicetree.cb b/src/mainboard/apple/macbook21/devicetree.cb
index 9da3891..5ce28a2 100644
--- a/src/mainboard/apple/macbook21/devicetree.cb
+++ b/src/mainboard/apple/macbook21/devicetree.cb
@@ -64,7 +64,6 @@
 			register "gpi1_routing" = "2"
 			register "gpi7_routing" = "2"
 
-			register "sata_ahci" = "0x1"
 			register "sata_ports_implemented" = "0x04"
 
 			register "gpe0_en" = "0x11000006"
diff --git a/src/mainboard/asrock/g41c-gs/variants/g41c-gs-r2/devicetree.cb b/src/mainboard/asrock/g41c-gs/variants/g41c-gs-r2/devicetree.cb
index 156fe3f..acb8ac6 100644
--- a/src/mainboard/asrock/g41c-gs/variants/g41c-gs-r2/devicetree.cb
+++ b/src/mainboard/asrock/g41c-gs/variants/g41c-gs-r2/devicetree.cb
@@ -51,7 +51,6 @@
 			register "gpi13_routing" = "2"
 
 			register "ide_enable_primary" = "0x1"
-			register "sata_ahci" = "0x0" # AHCI not supported on this ICH7 variant
 			register "sata_ports_implemented" = "0x3"
 			register "gpe0_en" = "0x440"
 
diff --git a/src/mainboard/asrock/g41c-gs/variants/g41m-gs/devicetree.cb b/src/mainboard/asrock/g41c-gs/variants/g41m-gs/devicetree.cb
index ba2f00d..f4d1dc4 100644
--- a/src/mainboard/asrock/g41c-gs/variants/g41m-gs/devicetree.cb
+++ b/src/mainboard/asrock/g41c-gs/variants/g41m-gs/devicetree.cb
@@ -46,7 +46,6 @@
 			register "pirqh_routing" = "0x0b"
 
 			register "ide_enable_primary" = "0x1"
-			register "sata_ahci" = "0x0" # AHCI not supported on this ICH7 variant
 			register "sata_ports_implemented" = "0x3"
 			register "gpe0_en" = "0x440"
 
diff --git a/src/mainboard/asrock/g41c-gs/variants/g41m-s3/devicetree.cb b/src/mainboard/asrock/g41c-gs/variants/g41m-s3/devicetree.cb
index 45a2014..2fd6e4f 100644
--- a/src/mainboard/asrock/g41c-gs/variants/g41m-s3/devicetree.cb
+++ b/src/mainboard/asrock/g41c-gs/variants/g41m-s3/devicetree.cb
@@ -44,7 +44,6 @@
 			register "pirqh_routing" = "0x0b"
 
 			register "ide_enable_primary" = "0x1"
-			register "sata_ahci" = "0x0" # AHCI not supported on this ICH7 variant
 			register "sata_ports_implemented" = "0x3"
 			register "gpe0_en" = "0x440"
 
diff --git a/src/mainboard/asrock/g41c-gs/variants/g41m-vs3-r2/devicetree.cb b/src/mainboard/asrock/g41c-gs/variants/g41m-vs3-r2/devicetree.cb
index b458115..5479faf 100644
--- a/src/mainboard/asrock/g41c-gs/variants/g41m-vs3-r2/devicetree.cb
+++ b/src/mainboard/asrock/g41c-gs/variants/g41m-vs3-r2/devicetree.cb
@@ -46,7 +46,6 @@
 			register "pirqh_routing" = "0x0b"
 
 			register "ide_enable_primary" = "0x1"
-			register "sata_ahci" = "0x0" # AHCI not supported on this ICH7 variant
 			register "gpe0_en" = "0x440"
 
 			device pci 1b.0 on		# Audio
diff --git a/src/mainboard/asus/p5gc-mx/devicetree.cb b/src/mainboard/asus/p5gc-mx/devicetree.cb
index 2f7d278..de63da2 100644
--- a/src/mainboard/asus/p5gc-mx/devicetree.cb
+++ b/src/mainboard/asus/p5gc-mx/devicetree.cb
@@ -53,7 +53,6 @@
 			register "ide_legacy_combined" = "0x0"
 			register "ide_enable_primary" = "0x1"
 			register "ide_enable_secondary" = "0x0"
-			register "sata_ahci" = "0x0"
 
 			register "p_cnt_throttling_supported" = "0"
 
diff --git a/src/mainboard/asus/p5qpl-am/devicetree.cb b/src/mainboard/asus/p5qpl-am/devicetree.cb
index 63ae8ce..bc023d2 100644
--- a/src/mainboard/asus/p5qpl-am/devicetree.cb
+++ b/src/mainboard/asus/p5qpl-am/devicetree.cb
@@ -43,7 +43,6 @@
 			#  2 SCI (if corresponding GPIO_EN bit is also set)
 
 			register "ide_enable_primary" = "0x1"
-			register "sata_ahci" = "0x0" # AHCI not supported on this ICH7 variant
 			register "gpe0_en" = "0x04000440"
 
 			device pci 1b.0 on  end		# Audio
diff --git a/src/mainboard/foxconn/d41s/devicetree.cb b/src/mainboard/foxconn/d41s/devicetree.cb
index 75df88e..a611ee3 100644
--- a/src/mainboard/foxconn/d41s/devicetree.cb
+++ b/src/mainboard/foxconn/d41s/devicetree.cb
@@ -40,7 +40,6 @@
       register "pirqf_routing" = "0x0b"
       register "pirqg_routing" = "0x0b"
       register "pirqh_routing" = "0x0b"
-      register "sata_ahci" = "0x1"
       register "sata_ports_implemented" = "0x3"
       register "gpe0_en" = "0x441"
 
diff --git a/src/mainboard/foxconn/g41s-k/devicetree.cb b/src/mainboard/foxconn/g41s-k/devicetree.cb
index ca952ba..b196e24 100644
--- a/src/mainboard/foxconn/g41s-k/devicetree.cb
+++ b/src/mainboard/foxconn/g41s-k/devicetree.cb
@@ -47,7 +47,6 @@
 
 			register "ide_enable_primary" = "0x0"
 			register "ide_enable_secondary" = "0x0"
-			register "sata_ahci" = "0x0"	# AHCI does not work
 			register "sata_ports_implemented" = "0x3"
 
 			device pci 1b.0 on end		# Audio
diff --git a/src/mainboard/getac/p470/devicetree.cb b/src/mainboard/getac/p470/devicetree.cb
index c0cad6a..c994553 100644
--- a/src/mainboard/getac/p470/devicetree.cb
+++ b/src/mainboard/getac/p470/devicetree.cb
@@ -57,7 +57,6 @@
                         register "ide_legacy_combined" = "0x1"
                         register "ide_enable_primary" = "0x1"
                         register "ide_enable_secondary" = "0x0"
-                        register "sata_ahci" = "0x0"
 
 			register "c3_latency" = "85"
 			register "docking_supported" = "1"
diff --git a/src/mainboard/gigabyte/ga-945gcm-s2l/devicetree.cb b/src/mainboard/gigabyte/ga-945gcm-s2l/devicetree.cb
index 7ed4d19..1c69613 100644
--- a/src/mainboard/gigabyte/ga-945gcm-s2l/devicetree.cb
+++ b/src/mainboard/gigabyte/ga-945gcm-s2l/devicetree.cb
@@ -76,7 +76,6 @@
 			register "ide_legacy_combined" = "0x0"
 			register "ide_enable_primary" = "0x1"
 			register "ide_enable_secondary" = "0x0"
-			register "sata_ahci" = "0x0"
 			register "c3_latency" = "85"
 
 			register "p_cnt_throttling_supported" = "0"
diff --git a/src/mainboard/gigabyte/ga-g41m-es2l/devicetree.cb b/src/mainboard/gigabyte/ga-g41m-es2l/devicetree.cb
index 8b47c4f..d24eb5d 100644
--- a/src/mainboard/gigabyte/ga-g41m-es2l/devicetree.cb
+++ b/src/mainboard/gigabyte/ga-g41m-es2l/devicetree.cb
@@ -48,7 +48,6 @@
       register "ide_legacy_combined" = "0x0"	# Combined mode broken
       register "ide_enable_primary" = "0x1"
       register "ide_enable_secondary" = "0x0"
-      register "sata_ahci" = "0x0"		# AHCI does not work
       register "sata_ports_implemented" = "0x3"
       register "gpe0_en" = "0x40"
 
diff --git a/src/mainboard/ibase/mb899/devicetree.cb b/src/mainboard/ibase/mb899/devicetree.cb
index f81a68b..0c5962f 100644
--- a/src/mainboard/ibase/mb899/devicetree.cb
+++ b/src/mainboard/ibase/mb899/devicetree.cb
@@ -36,7 +36,6 @@
 			register "ide_legacy_combined" = "0x0"
 			register "ide_enable_primary" = "0x1"
 			register "ide_enable_secondary" = "0x0"
-			register "sata_ahci" = "0x1"
 
 			register "c3_latency" = "85"
 			register "p_cnt_throttling_supported" = "0"
diff --git a/src/mainboard/intel/d510mo/devicetree.cb b/src/mainboard/intel/d510mo/devicetree.cb
index a008610..825611e 100644
--- a/src/mainboard/intel/d510mo/devicetree.cb
+++ b/src/mainboard/intel/d510mo/devicetree.cb
@@ -38,7 +38,6 @@
       register "pirqf_routing" = "0x0b"
       register "pirqg_routing" = "0x0b"
       register "pirqh_routing" = "0x0b"
-      register "sata_ahci" = "0x1"
       register "sata_ports_implemented" = "0x3"
       register "gpe0_en" = "0x20000040"
 
diff --git a/src/mainboard/intel/d945gclf/devicetree.cb b/src/mainboard/intel/d945gclf/devicetree.cb
index 716654c..573b9c8 100644
--- a/src/mainboard/intel/d945gclf/devicetree.cb
+++ b/src/mainboard/intel/d945gclf/devicetree.cb
@@ -50,7 +50,6 @@
                         register "ide_legacy_combined" = "0x0"
                         register "ide_enable_primary" = "0x1"
                         register "ide_enable_secondary" = "0x0"
-                        register "sata_ahci" = "0x0"
 			register "c3_latency" = "85"
 			register "p_cnt_throttling_supported" = "0"
 
diff --git a/src/mainboard/intel/dg41wv/devicetree.cb b/src/mainboard/intel/dg41wv/devicetree.cb
index be28763..295fbc4 100644
--- a/src/mainboard/intel/dg41wv/devicetree.cb
+++ b/src/mainboard/intel/dg41wv/devicetree.cb
@@ -63,7 +63,6 @@
 			register "gpi15_routing" = "2"
 
 			register "ide_enable_primary" = "0x1"
-			register "sata_ahci" = "0x0" # AHCI not supported on this ICH7 variant
 			register "gpe0_en" = "0x440"
 
 			device pci 1b.0 on		# Audio
diff --git a/src/mainboard/kontron/986lcd-m/devicetree.cb b/src/mainboard/kontron/986lcd-m/devicetree.cb
index 5e00109..cd7929c 100644
--- a/src/mainboard/kontron/986lcd-m/devicetree.cb
+++ b/src/mainboard/kontron/986lcd-m/devicetree.cb
@@ -36,7 +36,6 @@
 			register "ide_legacy_combined" = "0x1"
 			register "ide_enable_primary" = "0x1"
 			register "ide_enable_secondary" = "0x1"
-			register "sata_ahci" = "0x0"
 			register "c3_latency" = "85"
 			register "p_cnt_throttling_supported" = "0"
 
diff --git a/src/mainboard/lenovo/t60/devicetree.cb b/src/mainboard/lenovo/t60/devicetree.cb
index b4c8fb8..28e0574 100644
--- a/src/mainboard/lenovo/t60/devicetree.cb
+++ b/src/mainboard/lenovo/t60/devicetree.cb
@@ -72,7 +72,6 @@
 			register "gpi12_routing" = "2"
 			register "gpi8_routing" = "2"
 
-			register "sata_ahci" = "0x1"
 			register "sata_ports_implemented" = "0x01"
 
 			register "gpe0_en" = "0x11000006"
diff --git a/src/mainboard/lenovo/thinkcentre_a58/devicetree.cb b/src/mainboard/lenovo/thinkcentre_a58/devicetree.cb
index cc3ef49..ace2bfb 100644
--- a/src/mainboard/lenovo/thinkcentre_a58/devicetree.cb
+++ b/src/mainboard/lenovo/thinkcentre_a58/devicetree.cb
@@ -44,7 +44,6 @@
 			register "gpi13_routing" = "1" # ??vendor
 
 			register "ide_enable_primary" = "0x1"
-			register "sata_ahci" = "0x0" # AHCI not supported on this ICH7 variant
 			register "gpe0_en" = "0x440"
 
 			device pci 1b.0 on end		# Audio
diff --git a/src/mainboard/lenovo/x60/devicetree.cb b/src/mainboard/lenovo/x60/devicetree.cb
index 87cfa84..b3d87cc 100644
--- a/src/mainboard/lenovo/x60/devicetree.cb
+++ b/src/mainboard/lenovo/x60/devicetree.cb
@@ -65,7 +65,6 @@
 			register "gpi12_routing" = "1"
 			register "gpi8_routing" = "2"
 
-			register "sata_ahci" = "0x1"
 			register "sata_ports_implemented" = "0x01"
 
 			register "gpe0_en" = "0x11000006"
diff --git a/src/mainboard/lenovo/z61t/devicetree.cb b/src/mainboard/lenovo/z61t/devicetree.cb
index 8519b31..d35c62b 100644
--- a/src/mainboard/lenovo/z61t/devicetree.cb
+++ b/src/mainboard/lenovo/z61t/devicetree.cb
@@ -71,7 +71,6 @@
 			register "gpi12_routing" = "2"
 			register "gpi8_routing" = "2"
 
-			register "sata_ahci" = "0x1"
 			register "sata_ports_implemented" = "0x01"
 
 			register "gpe0_en" = "0x11000006"
diff --git a/src/mainboard/roda/rk886ex/devicetree.cb b/src/mainboard/roda/rk886ex/devicetree.cb
index 082a9e8..3ba9d2c 100644
--- a/src/mainboard/roda/rk886ex/devicetree.cb
+++ b/src/mainboard/roda/rk886ex/devicetree.cb
@@ -61,7 +61,6 @@
 			register "ide_legacy_combined" = "0x1"
 			register "ide_enable_primary" = "0x1"
 			register "ide_enable_secondary" = "0x0"
-			register "sata_ahci" = "0x0"
 
 			device pci 1b.0 off end # High Definition Audio
 			device pci 1c.0 on end # PCIe port 1
diff --git a/src/southbridge/intel/i82801gx/chip.h b/src/southbridge/intel/i82801gx/chip.h
index db27ef7..8909f50 100644
--- a/src/southbridge/intel/i82801gx/chip.h
+++ b/src/southbridge/intel/i82801gx/chip.h
@@ -18,6 +18,12 @@
 
 #include <stdint.h>
 
+enum sata_mode {
+	SATA_MODE_AHCI = 0,
+	SATA_MODE_IDE_LEGACY_COMBINED,
+	SATA_MODE_IDE_PLAIN,
+};
+
 struct southbridge_intel_i82801gx_config {
 	/**
 	 * Interrupt Routing configuration
@@ -65,7 +71,7 @@
 	uint32_t ide_legacy_combined;
 	uint32_t ide_enable_primary;
 	uint32_t ide_enable_secondary;
-	uint32_t sata_ahci;
+	enum sata_mode sata_mode;
 	uint32_t sata_ports_implemented;
 
 	/* Enable linear PCIe Root Port function numbers starting at zero */
diff --git a/src/southbridge/intel/i82801gx/i82801gx.h b/src/southbridge/intel/i82801gx/i82801gx.h
index e44fcf5..76420b4 100644
--- a/src/southbridge/intel/i82801gx/i82801gx.h
+++ b/src/southbridge/intel/i82801gx/i82801gx.h
@@ -82,6 +82,7 @@
 
 #define FDVCT			0xe4
 #define   PCIE_4_PORTS_MAX	(1 << 7)
+#define   AHCI_UNSUPPORTED	(1 << 3)
 
 /* GEN_PMCON_3 bits */
 #define RTC_BATTERY_DEAD	(1 << 2)
diff --git a/src/southbridge/intel/i82801gx/sata.c b/src/southbridge/intel/i82801gx/sata.c
index b657513..24dbf7c 100644
--- a/src/southbridge/intel/i82801gx/sata.c
+++ b/src/southbridge/intel/i82801gx/sata.c
@@ -51,18 +51,42 @@
 void sata_enable(struct device *dev)
 {
 	/* Get the chip configuration */
-	config_t *config = dev->chip_info;
+	struct southbridge_intel_i82801gx_config *config = dev->chip_info;
 
-	if (config->sata_ahci) {
-		/* Set map to ahci */
-		pci_write_config8(dev, SATA_MAP,
-			(pci_read_config8(dev, SATA_MAP) & ~0xc3) | 0x40);
-	} else {
-		/* Set map to ide */
-		pci_write_config8(dev, SATA_MAP,
-			pci_read_config8(dev, SATA_MAP) & ~0xc3);
+	if (config->sata_mode == SATA_MODE_AHCI) {
+		/* Check if the southbridge supports AHCI */
+		struct device *lpc_dev = pcidev_on_root(31, 0);
+		if (!lpc_dev) {
+			/* According to the PCI spec function 0 on a bus:device
+			   needs to be active for other functions to be enabled.
+			   Since SATA is on the same bus:device as the LPC
+			   bridge, it makes little sense to continue. */
+			die("Couldn't find the LPC device!\n");
+		}
+
+		const bool ahci_supported = !(pci_read_config32(lpc_dev, FDVCT)
+					      & AHCI_UNSUPPORTED);
+
+		if (!ahci_supported) {
+			/* Fallback to IDE PLAIN for sata for the rest of the
+			   initialization */
+			config->sata_mode = SATA_MODE_IDE_PLAIN;
+			printk(BIOS_DEBUG,
+			       "AHCI not supported, falling back to plain mode.\n");
+		}
+
 	}
 
+	if (config->sata_mode == SATA_MODE_AHCI) {
+		/* Set map to ahci */
+		pci_write_config8(dev, SATA_MAP,
+				  (pci_read_config8(dev, SATA_MAP)
+				   & ~0xc3) | 0x40);
+	} else {
+	/* Set map to ide */
+		pci_write_config8(dev, SATA_MAP,
+				  pci_read_config8(dev, SATA_MAP) & ~0xc3);
+	}
 	/* At this point, the new pci id will appear on the bus */
 }
 
@@ -89,7 +113,8 @@
 	/* Enable BARs */
 	pci_write_config16(dev, PCI_COMMAND, 0x0007);
 
-	if (config->ide_legacy_combined) {
+	switch (config->sata_mode) {
+	case SATA_MODE_IDE_LEGACY_COMBINED:
 		printk(BIOS_DEBUG, "SATA controller in combined mode.\n");
 		/* No AHCI: clear AHCI base */
 		pci_write_config32(dev, 0x24, 0x00000000);
@@ -120,7 +145,8 @@
 
 		/* Restrict ports - 0 and 2 only available */
 		ports &= 0x5;
-	} else if (config->sata_ahci) {
+		break;
+	case SATA_MODE_AHCI:
 		printk(BIOS_DEBUG, "SATA controller in AHCI mode.\n");
 		/* Allow both Legacy and Native mode */
 		pci_write_config8(dev, 0x09, 0x8f);
@@ -131,7 +157,9 @@
 
 		ahci_bar = (u32 *)(pci_read_config32(dev, 0x27) & ~0x3ff);
 		ahci_bar[3] = config->sata_ports_implemented;
-	} else {
+		break;
+	default:
+	case SATA_MODE_IDE_PLAIN:
 		printk(BIOS_DEBUG, "SATA controller in plain mode.\n");
 		/* Set Sata Controller Mode. No Mapping(?) */
 		pci_write_config8(dev, SATA_MAP, 0x00);
@@ -168,6 +196,7 @@
 		/* Set IDE I/O Configuration */
 		reg32 = SIG_MODE_PRI_NORMAL | FAST_PCB1 | FAST_PCB0 | PCB1 | PCB0;
 		pci_write_config32(dev, IDE_CONFIG, reg32);
+		break;
 	}
 
 	/* Set port control */