intel SMI handlers: Refactor GPI SMI/SCI routing

Move the GPI interrupt routing selection between SMI/SCI from
mainboards to southbridge. There is speculation if this is all
just legacy APM stuff that could be removed with a followup.

Change-Id: Iab14cf347584513793f417febc47f0559e17f5a5
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Signed-off-by: Nicolas Reinecke <nr@das-labor.org>
Reviewed-on: http://review.coreboot.org/7967
Tested-by: build bot (Jenkins)
Reviewed-by: Alexander Couzens <lynxis@fe80.eu>
diff --git a/src/southbridge/intel/bd82x6x/lpc.c b/src/southbridge/intel/bd82x6x/lpc.c
index d8f98c1..b207137 100644
--- a/src/southbridge/intel/bd82x6x/lpc.c
+++ b/src/southbridge/intel/bd82x6x/lpc.c
@@ -167,7 +167,7 @@
 	reg32 |= (config->gpi14_routing & 0x03) << 28;
 	reg32 |= (config->gpi15_routing & 0x03) << 30;
 
-	pci_write_config32(dev, 0xb8, reg32);
+	pci_write_config32(dev, GPIO_ROUT, reg32);
 }
 
 static void pch_power_options(device_t dev)
diff --git a/src/southbridge/intel/bd82x6x/pch.h b/src/southbridge/intel/bd82x6x/pch.h
index 4ec2903..a76bf36 100644
--- a/src/southbridge/intel/bd82x6x/pch.h
+++ b/src/southbridge/intel/bd82x6x/pch.h
@@ -70,6 +70,7 @@
 int pch_silicon_type(void);
 int pch_silicon_supported(int type, int rev);
 void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue);
+void gpi_route_interrupt(u8 gpi, u8 mode);
 #if CONFIG_ELOG
 void pch_log_state(void);
 #endif
@@ -146,7 +147,12 @@
 #define BIOS_CNTL		0xDC
 #define GPIO_BASE		0x48 /* LPC GPIO Base Address Register */
 #define GPIO_CNTL		0x4C /* LPC GPIO Control Register */
+
 #define GPIO_ROUT		0xb8
+#define   GPI_DISABLE		0x00
+#define   GPI_IS_SMI		0x01
+#define   GPI_IS_SCI		0x02
+#define   GPI_IS_NMI		0x03
 
 #define PIRQA_ROUT		0x60
 #define PIRQB_ROUT		0x61
diff --git a/src/southbridge/intel/bd82x6x/smihandler.c b/src/southbridge/intel/bd82x6x/smihandler.c
index f69c1f4..7ecbd81e 100644
--- a/src/southbridge/intel/bd82x6x/smihandler.c
+++ b/src/southbridge/intel/bd82x6x/smihandler.c
@@ -75,6 +75,42 @@
 }
 #endif
 
+static void alt_gpi_mask(u16 clr, u16 set)
+{
+	u16 alt_gp = inw(pmbase + ALT_GP_SMI_EN);
+	alt_gp &= ~clr;
+	alt_gp |= set;
+	outw(alt_gp, pmbase + ALT_GP_SMI_EN);
+}
+
+static void gpe0_mask(u32 clr, u32 set)
+{
+	u32 gpe0 = inl(pmbase + GPE0_EN);
+	gpe0 &= ~clr;
+	gpe0 |= set;
+	outl(gpe0, pmbase + GPE0_EN);
+}
+
+void gpi_route_interrupt(u8 gpi, u8 mode)
+{
+	u32 gpi_rout;
+	if (gpi >= 16)
+		return;
+
+	alt_gpi_mask(1 << gpi, 0);
+	gpe0_mask(1 << (gpi+16), 0);
+
+	gpi_rout = pci_read_config32(PCI_DEV(0, 0x1f, 0), GPIO_ROUT);
+	gpi_rout &= ~(3 << (2 * gpi));
+	gpi_rout |= ((mode & 3) << (2 * gpi));
+	pci_write_config32(PCI_DEV(0, 0x1f, 0), GPIO_ROUT, gpi_rout);
+
+	if (mode == GPI_IS_SCI)
+		gpe0_mask(0, 1 << (gpi+16));
+	else if (mode == GPI_IS_SMI)
+		alt_gpi_mask(0, 1 << gpi);
+}
+
 /**
  * @brief read and clear PM1_STS
  * @return PM1_STS register
diff --git a/src/southbridge/intel/fsp_bd82x6x/lpc.c b/src/southbridge/intel/fsp_bd82x6x/lpc.c
index f9961f9..6b95d08 100644
--- a/src/southbridge/intel/fsp_bd82x6x/lpc.c
+++ b/src/southbridge/intel/fsp_bd82x6x/lpc.c
@@ -185,7 +185,7 @@
 	reg32 |= (config->gpi14_routing & 0x03) << 28;
 	reg32 |= (config->gpi15_routing & 0x03) << 30;
 
-	pci_write_config32(dev, 0xb8, reg32);
+	pci_write_config32(dev, GPIO_ROUT, reg32);
 }
 
 static void pch_power_options(device_t dev)
diff --git a/src/southbridge/intel/i82801gx/i82801gx.h b/src/southbridge/intel/i82801gx/i82801gx.h
index 4624841..815768b 100644
--- a/src/southbridge/intel/i82801gx/i82801gx.h
+++ b/src/southbridge/intel/i82801gx/i82801gx.h
@@ -45,6 +45,7 @@
 #if !defined(__PRE_RAM__)
 #include "chip.h"
 extern void i82801gx_enable(device_t dev);
+void gpi_route_interrupt(u8 gpi, u8 mode);
 #else
 void enable_smbus(void);
 int smbus_read_byte(unsigned device, unsigned address);
@@ -78,6 +79,12 @@
 #define GEN_PMCON_2		0xa2
 #define GEN_PMCON_3		0xa4
 
+#define GPIO_ROUT		0xb8
+#define   GPI_DISABLE		0x00
+#define   GPI_IS_SMI		0x01
+#define   GPI_IS_SCI		0x02
+#define   GPI_IS_NMI		0x03
+
 /* GEN_PMCON_3 bits */
 #define RTC_BATTERY_DEAD	(1 << 2)
 #define RTC_POWER_FAILED	(1 << 1)
diff --git a/src/southbridge/intel/i82801gx/lpc.c b/src/southbridge/intel/i82801gx/lpc.c
index b8edfe3..2e3182b 100644
--- a/src/southbridge/intel/i82801gx/lpc.c
+++ b/src/southbridge/intel/i82801gx/lpc.c
@@ -158,7 +158,7 @@
 	reg32 |= (config->gpi14_routing & 0x03) << 28;
 	reg32 |= (config->gpi15_routing & 0x03) << 30;
 
-	pci_write_config32(dev, 0xb8, reg32);
+	pci_write_config32(dev, GPIO_ROUT, reg32);
 }
 
 static void i82801gx_power_options(device_t dev)
diff --git a/src/southbridge/intel/i82801gx/smihandler.c b/src/southbridge/intel/i82801gx/smihandler.c
index e83c722..6db0831 100644
--- a/src/southbridge/intel/i82801gx/smihandler.c
+++ b/src/southbridge/intel/i82801gx/smihandler.c
@@ -50,6 +50,42 @@
  */
 global_nvs_t *gnvs = (global_nvs_t *)0x0;
 
+static void alt_gpi_mask(u16 clr, u16 set)
+{
+	u16 alt_gp = inw(pmbase + ALT_GP_SMI_EN);
+	alt_gp &= ~clr;
+	alt_gp |= set;
+	outw(alt_gp, pmbase + ALT_GP_SMI_EN);
+}
+
+static void gpe0_mask(u32 clr, u32 set)
+{
+	u32 gpe0 = inl(pmbase + GPE0_EN);
+	gpe0 &= ~clr;
+	gpe0 |= set;
+	outl(gpe0, pmbase + GPE0_EN);
+}
+
+void gpi_route_interrupt(u8 gpi, u8 mode)
+{
+	u32 gpi_rout;
+	if (gpi >= 16)
+		return;
+
+	alt_gpi_mask(1 << gpi, 0);
+	gpe0_mask(1 << (gpi+16), 0);
+
+	gpi_rout = pci_read_config32(PCI_DEV(0, 0x1f, 0), GPIO_ROUT);
+	gpi_rout &= ~(3 << (2 * gpi));
+	gpi_rout |= ((mode & 3) << (2 * gpi));
+	pci_write_config32(PCI_DEV(0, 0x1f, 0), GPIO_ROUT, gpi_rout);
+
+	if (mode == GPI_IS_SCI)
+		gpe0_mask(0, 1 << (gpi+16));
+	else if (mode == GPI_IS_SMI)
+		alt_gpi_mask(0, 1 << gpi);
+}
+
 /**
  * @brief read and clear PM1_STS
  * @return PM1_STS register
diff --git a/src/southbridge/intel/ibexpeak/lpc.c b/src/southbridge/intel/ibexpeak/lpc.c
index db73b0a..9550a9e 100644
--- a/src/southbridge/intel/ibexpeak/lpc.c
+++ b/src/southbridge/intel/ibexpeak/lpc.c
@@ -166,7 +166,7 @@
 	reg32 |= (config->gpi14_routing & 0x03) << 28;
 	reg32 |= (config->gpi15_routing & 0x03) << 30;
 
-	pci_write_config32(dev, 0xb8, reg32);
+	pci_write_config32(dev, GPIO_ROUT, reg32);
 }
 
 static void pch_power_options(device_t dev)
diff --git a/src/southbridge/intel/ibexpeak/pch.h b/src/southbridge/intel/ibexpeak/pch.h
index 12e9345..23eb6cd 100644
--- a/src/southbridge/intel/ibexpeak/pch.h
+++ b/src/southbridge/intel/ibexpeak/pch.h
@@ -71,6 +71,7 @@
 int pch_silicon_type(void);
 int pch_silicon_supported(int type, int rev);
 void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue);
+void gpi_route_interrupt(u8 gpi, u8 mode);
 #if CONFIG_ELOG
 void pch_log_state(void);
 #endif
@@ -133,7 +134,12 @@
 #define BIOS_CNTL		0xDC
 #define GPIO_BASE		0x48 /* LPC GPIO Base Address Register */
 #define GPIO_CNTL		0x4C /* LPC GPIO Control Register */
+
 #define GPIO_ROUT		0xb8
+#define   GPI_DISABLE		0x00
+#define   GPI_IS_SMI		0x01
+#define   GPI_IS_SCI		0x02
+#define   GPI_IS_NMI		0x03
 
 #define PIRQA_ROUT		0x60
 #define PIRQB_ROUT		0x61
diff --git a/src/southbridge/intel/ibexpeak/smihandler.c b/src/southbridge/intel/ibexpeak/smihandler.c
index 019e6db..bfe5f5d 100644
--- a/src/southbridge/intel/ibexpeak/smihandler.c
+++ b/src/southbridge/intel/ibexpeak/smihandler.c
@@ -75,6 +75,42 @@
 }
 #endif
 
+static void alt_gpi_mask(u16 clr, u16 set)
+{
+	u16 alt_gp = inw(pmbase + ALT_GP_SMI_EN);
+	alt_gp &= ~clr;
+	alt_gp |= set;
+	outw(alt_gp, pmbase + ALT_GP_SMI_EN);
+}
+
+static void gpe0_mask(u32 clr, u32 set)
+{
+	u32 gpe0 = inl(pmbase + GPE0_EN);
+	gpe0 &= ~clr;
+	gpe0 |= set;
+	outl(gpe0, pmbase + GPE0_EN);
+}
+
+void gpi_route_interrupt(u8 gpi, u8 mode)
+{
+	u32 gpi_rout;
+	if (gpi >= 16)
+		return;
+
+	alt_gpi_mask(1 << gpi, 0);
+	gpe0_mask(1 << (gpi+16), 0);
+
+	gpi_rout = pci_read_config32(PCI_DEV(0, 0x1f, 0), GPIO_ROUT);
+	gpi_rout &= ~(3 << (2 * gpi));
+	gpi_rout |= ((mode & 3) << (2 * gpi));
+	pci_write_config32(PCI_DEV(0, 0x1f, 0), GPIO_ROUT, gpi_rout);
+
+	if (mode == GPI_IS_SCI)
+		gpe0_mask(0, 1 << (gpi+16));
+	else if (mode == GPI_IS_SMI)
+		alt_gpi_mask(0, 1 << gpi);
+}
+
 /**
  * @brief read and clear PM1_STS
  * @return PM1_STS register
diff --git a/src/southbridge/intel/lynxpoint/lpc.c b/src/southbridge/intel/lynxpoint/lpc.c
index d753bea..d83ec0a 100644
--- a/src/southbridge/intel/lynxpoint/lpc.c
+++ b/src/southbridge/intel/lynxpoint/lpc.c
@@ -175,7 +175,7 @@
 	reg32 |= (config->gpi14_routing & 0x03) << 28;
 	reg32 |= (config->gpi15_routing & 0x03) << 30;
 
-	pci_write_config32(dev, 0xb8, reg32);
+	pci_write_config32(dev, GPIO_ROUT, reg32);
 }
 
 static void pch_power_options(device_t dev)