stoneyridge GPIO: Create and use PAD_INT for interrupt pins

The default interrupt control for GPIO pins within stoneyridge is for
edge triggered, high. However, sometimes these need to change, or maybe
the interrupt needs to be reported or delivered. This was the case of
platform grunt, where the interrupt related bits were being changed
afterwards. Ideally all the bits should be programmed through the same
procedure. Create several PAD_INT definitions (for general configuration,
for trigger configuration and for interrupt type configuration) and change
function sb_program_gpios() to accept the output from PAD_INT_XX and
program all the necessary bits while keeping compatibility with other
PAD_XX definitions.

BUG=b:72875858
TEST=Add code to report GPIO and interrupt configuration, build grunt and
record a baseline. Add new code, rebuild grunt and record a test output.
Compare baseline against test, there should be no change in GPIO or
interrupt programming.
Remove code that reports GPIO/interrupt configuration.

Change-Id: I3457543bdf64ec757fd82df53c83fdc1d03c1f22
Signed-off-by: Richard Spiegel <richard.spiegel@silverbackltd.com>
Reviewed-on: https://review.coreboot.org/25758
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Martin Roth <martinroth@google.com>
diff --git a/src/mainboard/google/kahlee/bootblock/bootblock.c b/src/mainboard/google/kahlee/bootblock/bootblock.c
index aac1d95..8f124b3 100644
--- a/src/mainboard/google/kahlee/bootblock/bootblock.c
+++ b/src/mainboard/google/kahlee/bootblock/bootblock.c
@@ -50,11 +50,4 @@
 
 	/* Setup TPM decode before verstage */
 	sb_tpm_decode_spi();
-
-	/* Configure cr50 interrupt pin for use in polling tpm status */
-	if (IS_ENABLED(CONFIG_MAINBOARD_HAS_TPM_CR50)) {
-		const uint32_t flags = GPIO_EDGE_TRIG | GPIO_ACTIVE_LOW |
-					GPIO_INT_STATUS_EN;
-		gpio_set_interrupt(H1_PCH_INT, flags);
-	}
 }
diff --git a/src/mainboard/google/kahlee/mainboard.c b/src/mainboard/google/kahlee/mainboard.c
index a01ae0a..e090401 100644
--- a/src/mainboard/google/kahlee/mainboard.c
+++ b/src/mainboard/google/kahlee/mainboard.c
@@ -169,8 +169,16 @@
 	gpios = variant_gpio_table(&num_gpios);
 	sb_program_gpios(gpios, num_gpios);
 
+	/*
+	 * Some platforms use SCI not generated by a GPIO pin (event above 23).
+	 * For these boards, gpe_configure_sci() is still needed, but all GPIO
+	 * generated events (23-0) must be removed from gpe_table[].
+	 * For boards that only have GPIO generated events, table gpe_table[]
+	 * must be removed, and get_gpe_table() should return NULL.
+	 */
 	gpes = get_gpe_table(&num);
-	gpe_configure_sci(gpes, num);
+	if (gpes != NULL)
+		gpe_configure_sci(gpes, num);
 
 	/* Initialize i2c busses that were not initialized in bootblock */
 	i2c_soc_init();
diff --git a/src/mainboard/google/kahlee/variants/baseboard/gpio.c b/src/mainboard/google/kahlee/variants/baseboard/gpio.c
index ff6141e..c7bd6a5 100644
--- a/src/mainboard/google/kahlee/variants/baseboard/gpio.c
+++ b/src/mainboard/google/kahlee/variants/baseboard/gpio.c
@@ -32,16 +32,17 @@
 	PAD_GPO(GPIO_4, HIGH),
 
 	/* GPIO_6 - APU_RST_L / EC_SMI_ODL, SMI */
-	PAD_GPI(GPIO_6, PULL_UP),
+	PAD_SMI(GPIO_6, PULL_UP, LEVEL_LOW),
 
 	/* GPIO_9 - H1_PCH_INT_ODL, SCI */
-	PAD_GPI(GPIO_9, PULL_UP),
+	PAD_INT(GPIO_9, PULL_UP, EDGE_LOW, STATUS),
+	PAD_SCI(GPIO_9, PULL_UP, EDGE_LOW),
 
 	/* GPIO_15 - EC_IN_RW_OD */
 	PAD_GPI(GPIO_15, PULL_UP),
 
 	/* GPIO_22 - EC_SCI_ODL, SCI */
-	PAD_GPI(GPIO_22, PULL_UP),
+	PAD_SCI(GPIO_22, PULL_UP, EDGE_LOW),
 
 	/* GPIO_26 - APU_PCIE_RST_L */
 	PAD_NF(GPIO_26, PCIE_RST_L, PULL_NONE),
@@ -85,16 +86,17 @@
 	PAD_GPO(GPIO_4, HIGH),
 
 	/* GPIO_6 - APU_RST_L / EC_SMI_ODL, SMI */
-	PAD_GPI(GPIO_6, PULL_UP),
+	PAD_SMI(GPIO_6, PULL_UP, LEVEL_LOW),
 
 	/* GPIO_9 - H1_PCH_INT_ODL, SCI */
-	PAD_GPI(GPIO_9, PULL_UP),
+	PAD_INT(GPIO_9, PULL_UP, EDGE_LOW, STATUS),
+	PAD_SCI(GPIO_9, PULL_UP, EDGE_LOW),
 
 	/* GPIO_15 - EC_IN_RW_OD */
 	PAD_GPI(GPIO_15, PULL_UP),
 
 	/* GPIO_22 - EC_SCI_ODL, SCI */
-	PAD_GPI(GPIO_22, PULL_UP),
+	PAD_SCI(GPIO_22, PULL_UP, EDGE_LOW),
 
 	/* GPIO_24 - EC_PCH_WAKE_L */
 	PAD_GPI(GPIO_24, PULL_UP),
@@ -150,7 +152,7 @@
 	PAD_GPI(GPIO_3, PULL_UP),
 
 	/* GPIO_5 - PCH_TRACKPAD_INT_3V3_ODL, SCI */
-	PAD_GPI(GPIO_5, PULL_UP),
+	PAD_SCI(GPIO_5, PULL_UP, EDGE_LOW),
 
 	/* GPIO_7 - APU_PWROK_OD (currently not used) */
 	PAD_GPI(GPIO_7, PULL_UP),
@@ -162,7 +164,7 @@
 	PAD_NF(GPIO_10, S0A3_GPIO, PULL_UP),
 
 	/* GPIO_11 - TOUCHSCREEN_INT_3V3_ODL, SCI */
-	PAD_GPI(GPIO_11, PULL_UP),
+	PAD_SCI(GPIO_11, PULL_UP, EDGE_LOW),
 
 	/* GPIO_12 - Unused (TP126) */
 	PAD_GPI(GPIO_12, PULL_UP),
@@ -171,7 +173,7 @@
 	PAD_GPI(GPIO_13, PULL_UP),
 
 	/* GPIO_14 - APU_HP_INT_ODL, SCI */
-	PAD_GPI(GPIO_14, PULL_UP),
+	PAD_SCI(GPIO_14, PULL_UP, EDGE_LOW),
 
 	/* GPIO_16 - USB_C0_OC_L */
 	PAD_NF(GPIO_16, USB_OC0_L, PULL_UP),
@@ -189,7 +191,7 @@
 	PAD_NF(GPIO_20, I2C3_SDA, PULL_UP),
 
 	/* GPIO_21 - APU_PEN_INT_ODL, SCI */
-	PAD_GPI(GPIO_21, PULL_UP),
+	PAD_SCI(GPIO_21, PULL_UP, EDGE_LOW),
 
 	/* GPIO_24 - USB_A1_OC_ODL */
 	PAD_NF(GPIO_24, USB_OC3_L, PULL_UP),
@@ -314,7 +316,7 @@
 	PAD_GPI(GPIO_3, PULL_UP),
 
 	/* GPIO_5 - PCH_TRACKPAD_INT_3V3_ODL, SCI */
-	PAD_GPI(GPIO_5, PULL_UP),
+	PAD_SCI(GPIO_5, PULL_UP, EDGE_LOW),
 
 	/* GPIO_7 - APU_PWROK_OD (currently not used) */
 	PAD_GPI(GPIO_7, PULL_UP),
@@ -326,7 +328,7 @@
 	PAD_NF(GPIO_10, S0A3_GPIO, PULL_UP),
 
 	/* GPIO_11 - TOUCHSCREEN_INT_3V3_ODL, SCI */
-	PAD_GPI(GPIO_11, PULL_UP),
+	PAD_SCI(GPIO_11, PULL_UP, EDGE_LOW),
 
 	/* GPIO_12 - EN_PP3300_TRACKPAD */
 	PAD_GPO(GPIO_12, HIGH),
@@ -335,7 +337,7 @@
 	PAD_GPI(GPIO_13, PULL_UP),
 
 	/* GPIO_14 - APU_HP_INT_ODL, SCI */
-	PAD_GPI(GPIO_14, PULL_UP),
+	PAD_SCI(GPIO_14, PULL_UP, EDGE_LOW),
 
 	/* GPIO_16 - USB_C0_OC_L */
 	PAD_NF(GPIO_16, USB_OC0_L, PULL_UP),
@@ -353,7 +355,7 @@
 	PAD_NF(GPIO_20, I2C3_SDA, PULL_UP),
 
 	/* GPIO_21 - APU_PEN_INT_ODL, SCI */
-	PAD_GPI(GPIO_21, PULL_UP),
+	PAD_SCI(GPIO_21, PULL_UP, EDGE_LOW),
 
 	/* GPIO_25 - SD_CD */
 	PAD_NF(GPIO_25, SD0_CD, PULL_UP),
@@ -486,73 +488,15 @@
 }
 
 /*
- * GPE setup table must match ACPI GPE ASL
- *  { gevent, gpe, direction, level }
+ * This function is still needed for boards that sets gevents above 23
+ * that will generate SCI or SMI, such as kahlee. Normally this function
+ * points to a table of gevents and what needs to be set. The code that
+ * calls it was modified so that when this function returns NULL then the
+ * caller does nothing.
  */
-static const struct sci_source gpe_table[] = {
-
-	/* PCH_TRACKPAD_INT_3V3_ODL */
-	{
-		.scimap = 7,
-		.gpe = 7,
-		.direction = SMI_SCI_LVL_LOW,
-		.level = SMI_SCI_EDG,
-	},
-
-	/* EC_PCH_WAKE_L */
-	{
-		.scimap = EC_WAKE_GPI,
-		.gpe = EC_WAKE_GPI,
-		.direction = SMI_SCI_LVL_LOW,
-		.level = SMI_SCI_EDG,
-	},
-
-	/* H1_PCH_INT_ODL */
-	{
-		.scimap = 22,
-		.gpe = 22,
-		.direction = SMI_SCI_LVL_LOW,
-		.level = SMI_SCI_EDG,
-	},
-
-	/* TOUCHSCREEN_INT_3V3_ODL */
-	{
-		.scimap = 18,
-		.gpe = 18,
-		.direction = SMI_SCI_LVL_LOW,
-		.level = SMI_SCI_EDG,
-	},
-
-
-	/* APU_HP_INT_ODL */
-	{
-		.scimap = 6,
-		.gpe = 6,
-		.direction = SMI_SCI_LVL_LOW,
-		.level = SMI_SCI_EDG,
-	},
-
-	/* APU_PEN_INT_ODL */
-	{
-		.scimap = 5,
-		.gpe = 5,
-		.direction = SMI_SCI_LVL_LOW,
-		.level = SMI_SCI_EDG,
-	},
-
-	/* EC_SCI_ODL */
-	{
-		.scimap = 3,
-		.gpe = 3,
-		.direction = SMI_SCI_LVL_LOW,
-		.level = SMI_SCI_EDG,
-	},
-};
-
 const __weak struct sci_source *get_gpe_table(size_t *num)
 {
-	*num = ARRAY_SIZE(gpe_table);
-	return gpe_table;
+	return NULL;
 }
 
 int __weak variant_get_xhci_oc_map(uint16_t *map)
diff --git a/src/mainboard/google/kahlee/variants/kahlee/gpio.c b/src/mainboard/google/kahlee/variants/kahlee/gpio.c
index 8f30e4b..3072350 100644
--- a/src/mainboard/google/kahlee/variants/kahlee/gpio.c
+++ b/src/mainboard/google/kahlee/variants/kahlee/gpio.c
@@ -26,7 +26,7 @@
  */
 static const struct soc_amd_gpio gpio_set_stage_reset[] = {
 	/* AGPIO2, to become event generator */
-	PAD_GPI(GPIO_2, PULL_UP),
+	PAD_SCI(GPIO_2, PULL_UP, EDGE_LOW),
 
 	/* SER_TX */
 	PAD_NF(GPIO_8, SerPortTX_OUT, PULL_UP),
@@ -44,7 +44,7 @@
 	PAD_NF(GPIO_20, I2C3_SDA, PULL_UP),
 
 	/* AGPIO22 EC_SCI */
-	PAD_GPI(GPIO_22, PULL_UP),
+	PAD_SCI(GPIO_22, PULL_UP, EDGE_LOW),
 
 	/* SPI_TPM_CS_L */
 	PAD_NF(GPIO_76, SPI_TPM_CS_L, PULL_DOWN),
@@ -120,22 +120,6 @@
  */
 static const struct sci_source gpe_table[] = {
 
-	/* EC AGPIO22/Gevent3 -> GPE 3 */
-	{
-		.scimap = 3,
-		.gpe = 3,
-		.direction = SMI_SCI_LVL_LOW,
-		.level = SMI_SCI_EDG,
-	},
-
-	/* PCIE/WLAN AGPIO2/Gevent8 -> GPE8 */
-	{
-		.scimap = 8,
-		.gpe = 8,
-		.direction = SMI_SCI_LVL_LOW,
-		.level = SMI_SCI_LVL,
-	},
-
 	/* EHCI USB_PME -> GPE24 */
 	{
 		.scimap = 24,
diff --git a/src/soc/amd/stoneyridge/Makefile.inc b/src/soc/amd/stoneyridge/Makefile.inc
index 54b1198..c2d48d5 100644
--- a/src/soc/amd/stoneyridge/Makefile.inc
+++ b/src/soc/amd/stoneyridge/Makefile.inc
@@ -50,6 +50,7 @@
 bootblock-y += southbridge.c
 bootblock-y += nb_util.c
 bootblock-$(CONFIG_SPI_FLASH) += spi.c
+bootblock-$(CONFIG_HAVE_SMI_HANDLER) += smi_util.c
 
 romstage-y += BiosCallOuts.c
 romstage-y += i2c.c
@@ -69,6 +70,7 @@
 romstage-y += southbridge.c
 romstage-y += nb_util.c
 romstage-$(CONFIG_SPI_FLASH) += spi.c
+romstage-$(CONFIG_HAVE_SMI_HANDLER) += smi_util.c
 
 verstage-y += gpio.c
 verstage-y += i2c.c
diff --git a/src/soc/amd/stoneyridge/gpio.c b/src/soc/amd/stoneyridge/gpio.c
index 4520df7..1b7f055 100644
--- a/src/soc/amd/stoneyridge/gpio.c
+++ b/src/soc/amd/stoneyridge/gpio.c
@@ -19,6 +19,110 @@
 #include <console/console.h>
 #include <gpio.h>
 #include <soc/gpio.h>
+#include <assert.h>
+#include <compiler.h>
+
+static const struct soc_amd_event gpio_event_table[] = {
+	{ GPIO_1, GEVENT_19 },
+	{ GPIO_2, GEVENT_8 },
+	{ GPIO_3, GEVENT_2 },
+	{ GPIO_4, GEVENT_4 },
+	{ GPIO_5, GEVENT_7 },
+	{ GPIO_6, GEVENT_10 },
+	{ GPIO_7, GEVENT_11 },
+	{ GPIO_8, GEVENT_23 },
+	{ GPIO_9, GEVENT_22 },
+	{ GPIO_11, GEVENT_18 },
+	{ GPIO_13, GEVENT_21 },
+	{ GPIO_14, GEVENT_6 },
+	{ GPIO_15, GEVENT_20 },
+	{ GPIO_16, GEVENT_12 },
+	{ GPIO_17, GEVENT_13 },
+	{ GPIO_18, GEVENT_14 },
+	{ GPIO_21, GEVENT_5 },
+	{ GPIO_22, GEVENT_3 },
+	{ GPIO_23, GEVENT_16 },
+	{ GPIO_24, GEVENT_15 },
+	{ GPIO_65, GEVENT_0 },
+	{ GPIO_66, GEVENT_1 },
+	{ GPIO_68, GEVENT_9 },
+	{ GPIO_69, GEVENT_17 },
+};
+
+static int get_gpio_gevent(uint8_t gpio)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(gpio_event_table); i++) {
+		if (gpio_event_table[i].gpio == gpio)
+			return (int)gpio_event_table[i].event;
+	}
+	return -1;
+}
+
+static void mem_read_write32(uint32_t *address, uint32_t value, uint32_t mask)
+{
+	uint32_t reg32;
+
+	value &= mask;
+	reg32 = read32(address);
+	reg32 &= ~mask;
+	reg32 |= value;
+	write32(address, reg32);
+}
+
+__weak void configure_gevent_smi(uint8_t gevent, uint8_t mode, uint8_t level)
+{
+	printk(BIOS_WARNING, "Warning: SMI disabled!\n");
+}
+
+static void program_smi(uint32_t flag, int gevent_num)
+{
+	uint32_t trigger;
+
+	trigger = flag & FLAGS_TRIGGER_MASK;
+	/*
+	 * Only level trigger is allowed for SMI. Trigger values are 0
+	 * through 3, with 0-1 being level trigger and 2-3 being edge
+	 * trigger. GPIO_TRIGGER_EDGE_LOW is 2, so trigger has to be
+	 * less than GPIO_TRIGGER_EDGE_LOW.
+	 */
+	assert(trigger < GPIO_TRIGGER_EDGE_LOW);
+
+	if (trigger == GPIO_TRIGGER_LEVEL_HIGH)
+		configure_gevent_smi(gevent_num, SMI_MODE_SMI,
+					SMI_SCI_LVL_HIGH);
+	if (trigger == GPIO_TRIGGER_LEVEL_LOW)
+		configure_gevent_smi(gevent_num, SMI_MODE_SMI,
+					SMI_SCI_LVL_LOW);
+}
+
+static void get_sci_config_bits(uint32_t flag, uint32_t *edge, uint32_t *level)
+{
+	uint32_t trigger;
+
+	trigger = flag & FLAGS_TRIGGER_MASK;
+	switch (trigger) {
+	case GPIO_TRIGGER_LEVEL_LOW:
+		*edge = SCI_TRIGGER_LEVEL;
+		*level = 0;
+		break;
+	case GPIO_TRIGGER_LEVEL_HIGH:
+		*edge = SCI_TRIGGER_LEVEL;
+		*level = 1;
+		break;
+	case GPIO_TRIGGER_EDGE_LOW:
+		*edge = SCI_TRIGGER_EDGE;
+		*level = 0;
+		break;
+	case GPIO_TRIGGER_EDGE_HIGH:
+		*edge = SCI_TRIGGER_EDGE;
+		*level = 1;
+		break;
+	default:
+		break;
+	}
+}
 
 static uintptr_t gpio_get_address(gpio_t gpio_num)
 {
@@ -108,18 +212,79 @@
 	return gpio;
 }
 
-void gpio_set_interrupt(gpio_t gpio, uint32_t flags)
+void sb_program_gpios(const struct soc_amd_gpio *gpio_list_ptr, size_t size)
 {
-	uintptr_t gpio_address = gpio_get_address(gpio);
-	uint32_t reg = read32((void *)gpio_address);
+	uint8_t *mux_ptr;
+	uint32_t *gpio_ptr;
+	uint32_t control, control_flags, edge_level, direction;
+	uint32_t mask, bit_edge, bit_level;
+	uint8_t mux, index, gpio;
+	int gevent_num;
 
-	/* Clear registers that are being updated */
-	reg &= ~(GPIO_TRIGGER_MASK | GPIO_ACTIVE_MASK | GPIO_INTERRUPT_MASK);
+	direction = 0;
+	edge_level = 0;
+	mask = 0;
+	for (index = 0; index < size; index++) {
+		gpio = gpio_list_ptr[index].gpio;
+		mux = gpio_list_ptr[index].function;
+		control = gpio_list_ptr[index].control;
+		control_flags = gpio_list_ptr[index].flags;
 
-	/* Clear any extra bits in the flags */
-	flags &= (GPIO_TRIGGER_MASK | GPIO_ACTIVE_MASK | GPIO_INTERRUPT_MASK);
+		mux_ptr = (uint8_t *)(uintptr_t)(gpio + AMD_GPIO_MUX);
+		write8(mux_ptr, mux & AMD_GPIO_MUX_MASK);
+		gpio_ptr = (uint32_t *)gpio_get_address(gpio);
 
-	write32((void *)gpio_address, reg | flags);
+		if (control_flags & GPIO_SPECIAL_FLAG) {
+			gevent_num = get_gpio_gevent(gpio);
+			if (gevent_num < 0) {
+				printk(BIOS_WARNING, "Warning: GPIO pin %d has"
+					" no associated gevent!\n", gpio);
+				continue;
+			}
+			switch (control_flags & GPIO_SPECIAL_MASK) {
+			case GPIO_DEBOUNCE_FLAG:
+				mem_read_write32(gpio_ptr, control,
+						GPIO_DEBOUNCE_MASK);
+				break;
+			case GPIO_WAKE_FLAG:
+				mem_read_write32(gpio_ptr, control,
+						INT_WAKE_MASK);
+				break;
+			case GPIO_INT_FLAG:
+				mem_read_write32(gpio_ptr, control,
+						AMD_GPIO_CONTROL_MASK);
+				break;
+			case GPIO_SMI_FLAG:
+				mem_read_write32(gpio_ptr, control,
+						INT_SCI_SMI_MASK);
+				program_smi(control_flags, gevent_num);
+				break;
+			case GPIO_SCI_FLAG:
+				mem_read_write32(gpio_ptr, control,
+						INT_SCI_SMI_MASK);
+				get_sci_config_bits(control_flags, &bit_edge,
+							&bit_level);
+				edge_level |= bit_edge << gevent_num;
+				direction |= bit_level << gevent_num;
+				mask |= (1 << gevent_num);
+				break;
+			default:
+				printk(BIOS_WARNING, "Error, flags 0x%08x\n",
+							control_flags);
+				break;
+			}
+		} else {
+			mem_read_write32(gpio_ptr, control,
+						AMD_GPIO_CONTROL_MASK);
+		}
+	}
+	/* Set all SCI trigger direction (high/low) */
+	mem_read_write32((uint32_t *)(uintptr_t)(APU_SMI_BASE + SMI_SCI_TRIG),
+					direction, mask);
+
+	/* Set all SCI trigger level (edge/level) */
+	mem_read_write32((uint32_t *)(uintptr_t)(APU_SMI_BASE + SMI_SCI_LEVEL),
+					edge_level, mask);
 }
 
 int gpio_interrupt_status(gpio_t gpio)
diff --git a/src/soc/amd/stoneyridge/include/soc/gpio.h b/src/soc/amd/stoneyridge/include/soc/gpio.h
index cbc99e4..e43f2c7 100644
--- a/src/soc/amd/stoneyridge/include/soc/gpio.h
+++ b/src/soc/amd/stoneyridge/include/soc/gpio.h
@@ -21,8 +21,21 @@
 
 #ifndef __ACPI__
 #include <soc/iomap.h>
+#include <soc/smi.h>
 #include <types.h>
 
+struct soc_amd_gpio {
+	uint8_t gpio;
+	uint8_t function;
+	uint32_t control;
+	uint32_t flags;
+};
+
+struct soc_amd_event {
+	uint8_t gpio;
+	uint8_t event;
+};
+
 #define GPIO_EDGE_TRIG		(0 << 8)
 #define GPIO_LEVEL_TRIG		(1 << 8)
 #define GPIO_TRIGGER_MASK	(1 << 8)
@@ -35,12 +48,16 @@
 #define GPIO_INT_STATUS_EN	(1 << 11)
 #define GPIO_INT_DELIVERY_EN	(1 << 12)
 #define GPIO_INTERRUPT_MASK	(3 << 11)
+#define GPIO_S0I3_WAKE_EN	(1 << 13)
+#define GPIO_S3_WAKE_EN		(1 << 14)
+#define GPIO_S4_S5_WAKE_EN	(1 << 15)
 
 #define GPIO_PIN_STS		(1 << 16)
 #define GPIO_PULLUP_ENABLE	(1 << 20)
 #define GPIO_PULLDOWN_ENABLE	(1 << 21)
 #define GPIO_OUTPUT_SHIFT	22
 #define GPIO_OUTPUT_MASK	(1 << GPIO_OUTPUT_SHIFT)
+#define GPIO_OUTPUT_VALUE	(1 << GPIO_OUTPUT_SHIFT)
 #define GPIO_OUTPUT_ENABLE	(1 << 23)
 
 #define GPIO_INT_STATUS		(1 << 28)
@@ -325,38 +342,228 @@
 #define GPIO_148_IOMUX_I2C1_SDA 0
 #define GPIO_148_IOMUX_GPIOxx 1
 
-#define GPIO_ENABLE_OUTPUT	BIT(7)
-#define GPIO_OUTPUT_VALUE	BIT(6)
-#define GPIO_PULL_DOWN_ENABLE	BIT(5)
-#define GPIO_PULL_UP_ENABLE	BIT(4)
+enum {
+	GEVENT_0,
+	GEVENT_1,
+	GEVENT_2,
+	GEVENT_3,
+	GEVENT_4,
+	GEVENT_5,
+	GEVENT_6,
+	GEVENT_7,
+	GEVENT_8,
+	GEVENT_9,
+	GEVENT_10,
+	GEVENT_11,
+	GEVENT_12,
+	GEVENT_13,
+	GEVENT_14,
+	GEVENT_15,
+	GEVENT_16,
+	GEVENT_17,
+	GEVENT_18,
+	GEVENT_19,
+	GEVENT_20,
+	GEVENT_21,
+	GEVENT_22,
+	GEVENT_23,
+};
 
-#define GPIO_OUTPUT_OUT_HIGH (GPIO_ENABLE_OUTPUT | GPIO_OUTPUT_VALUE)
-#define GPIO_OUTPUT_OUT_LOW GPIO_ENABLE_OUTPUT
+#define GPIO_OUTPUT_OUT_HIGH (GPIO_OUTPUT_ENABLE | GPIO_OUTPUT_VALUE)
+#define GPIO_OUTPUT_OUT_LOW GPIO_OUTPUT_ENABLE
 
-#define GPIO_PULL_PULL_UP GPIO_PULL_UP_ENABLE
-#define GPIO_PULL_PULL_DOWN GPIO_PULL_DOWN_ENABLE
+#define GPIO_PULL_PULL_UP GPIO_PULLUP_ENABLE
+#define GPIO_PULL_PULL_DOWN GPIO_PULLDOWN_ENABLE
 #define GPIO_PULL_PULL_NONE 0
 
+#define AMD_GPIO_CONTROL_MASK			0x00f4ff00
+#define AMD_GPIO_MUX_MASK			0x03
+
+/* Definitions for PAD_INT. */
+#define GPIO_INT_EDGE_HIGH		(GPIO_ACTIVE_HIGH | GPIO_EDGE_TRIG)
+#define GPIO_INT_EDGE_LOW		(GPIO_ACTIVE_LOW | GPIO_EDGE_TRIG)
+#define GPIO_INT_BOTH_EDGES		(GPIO_ACTIVE_BOTH | GPIO_EDGE_TRIG)
+#define GPIO_INT_LEVEL_HIGH		(GPIO_ACTIVE_HIGH | GPIO_LEVEL_TRIG)
+#define GPIO_INT_LEVEL_LOW		(GPIO_ACTIVE_LOW | GPIO_LEVEL_TRIG)
+
+enum {
+	GPIO_TRIGGER_LEVEL_LOW,
+	GPIO_TRIGGER_LEVEL_HIGH,
+	GPIO_TRIGGER_EDGE_LOW,
+	GPIO_TRIGGER_EDGE_HIGH,
+};
+
+#define GPIO_TRIGGER_INVALID		-1
+#define SCI_TRIGGER_EDGE		0
+#define SCI_TRIGGER_LEVEL		1
+
+#define GPIO_SPECIAL_FLAG		(1 << 31)
+#define GPIO_DEBOUNCE_FLAG		(1 << 30)
+#define GPIO_WAKE_FLAG			(1 << 29)
+#define GPIO_INT_FLAG			(1 << 28)
+#define GPIO_SMI_FLAG			(1 << 27)
+#define GPIO_SCI_FLAG			(1 << 26)
+#define GPIO_FLAG_DEBOUNCE		(GPIO_SPECIAL_FLAG | GPIO_DEBOUNCE_FLAG)
+#define GPIO_FLAG_WAKE			(GPIO_SPECIAL_FLAG | GPIO_WAKE_FLAG)
+#define GPIO_FLAG_INT			(GPIO_SPECIAL_FLAG | GPIO_INT_FLAG)
+#define GPIO_FLAG_SCI			(GPIO_SPECIAL_FLAG | GPIO_SCI_FLAG)
+#define GPIO_FLAG_SMI			(GPIO_SPECIAL_FLAG | GPIO_SMI_FLAG)
+
+#define FLAGS_TRIGGER_MASK		0x00000003
+#define GPIO_SPECIAL_MASK		0x7c000000
+#define GPIO_DEBOUNCE_MASK		0x000000ff
+#define INT_TRIGGER_MASK		0x00000700
+#define INT_WAKE_MASK			0x0000e700
+#define INT_SCI_SMI_MASK		0x00f40000
+
+#define IN_GLITCH_SHIFT			5
+#define GLITCH_LOW			1
+#define GLITCH_HIGH			2
+#define GLITCH_NONE			3
+#define GPIO_IN_PRESERVE_LOW_GLITCH	(GLITCH_LOW << IN_GLITCH_SHIFT)
+#define GPIO_IN_PRESERVE_HIGH_GLITCH	(GLITCH_HIGH << IN_GLITCH_SHIFT)
+#define GPIO_IN_REMOVE_GLITCH		(GLITCH_NONE << IN_GLITCH_SHIFT)
+
+#define GPIO_TIMEBASE_61uS		0
+#define GPIO_TIMEBASE_183uS		(1 << 4)
+#define GPIO_TIMEBASE_15560uS		(1 << 7)
+#define GPIO_TIMEBASE_62440uS		(GPIO_TIMEBASE_183uS | \
+					GPIO_TIMEBASE_15560uS)
+#define GPIO_IN_60uS			(1 | GPIO_TIMEBASE_61uS)
+#define GPIO_IN_120uS			(2 | GPIO_TIMEBASE_61uS)
+#define GPIO_IN_200uS			(3 | GPIO_TIMEBASE_61uS)
+#define GPIO_IN_500uS			(8 | GPIO_TIMEBASE_61uS)
+#define GPIO_IN_1mS			(5 | GPIO_TIMEBASE_183uS)
+#define GPIO_IN_2mS			(11 | GPIO_TIMEBASE_183uS)
+#define GPIO_IN_15mS			(1 | GPIO_TIMEBASE_15560uS)
+#define GPIO_IN_50mS			(3 | GPIO_TIMEBASE_15560uS)
+#define GPIO_IN_100mS			(6 | GPIO_TIMEBASE_15560uS)
+#define GPIO_IN_200mS			(13 | GPIO_TIMEBASE_15560uS)
+#define GPIO_IN_500mS			(8 | GPIO_TIMEBASE_62440uS)
+
+#define GPIO_IN_NO_DEBOUNCE		(DEBOUNCE_NONE << IN_GLITCH_SHIFT)
+#define GPIO_IN_PRESERVE_LOW_GLITCH	(GLITCH_LOW << IN_GLITCH_SHIFT)
+#define GPIO_IN_PRESERVE_HIGH_GLITCH	(GLITCH_HIGH << IN_GLITCH_SHIFT)
+#define GPIO_IN_REMOVE_GLITCH		(GLITCH_NONE << IN_GLITCH_SHIFT)
+
+#define GPIO_EVENT_INT_STATUS		GPIO_INT_STATUS_EN
+#define GPIO_EVENT_INT_DELIVER		GPIO_INT_DELIVERY_EN
+#define GPIO_EVENT_INT_STATUS_DELIVER	(GPIO_INT_STATUS_EN | \
+					GPIO_INT_DELIVERY_EN)
+#define GPIO_WAKE_S0i3			(1 << 13)
+#define GPIO_WAKE_S3			(1 << 14)
+#define GPIO_WAKE_S4_S5			(1 << 15)
+#define GPIO_WAKE_S0i3_S4_S5		(GPIO_WAKE_S0i3 | GPIO_WAKE_S4_S5)
+#define GPIO_WAKE_S3_S4_S5		(GPIO_WAKE_S3 | GPIO_WAKE_S4_S5)
+
+/*
+ * Several macros are available to declare programming of GPIO pins, and if
+ * needed more than 1 macro can be used for any pin. However, some macros
+ * will have no effect if combined. For example debounce only affects input
+ * or one of the interrupts. Some macros should not be combined, such as SMI
+ * and regular interrupt. The defined macros and their parameters are:
+ * PAD_NF		Define native alternate function for the pin.
+ *	pin		the pin to be programmed
+ *	function	the native function
+ *	pull		pull up, pull down or no pull
+ * PAD_GPI		The pin is a GPIO input
+ *	pin		the pin to be programmed
+ *	pull		pull up, pull down or no pull
+ * PAD_GPO		The pin is a GPIO output
+ *	pin		the pin to be programmed
+ *	direction	high or low
+ * PAD_INT		The pin is regular interrupt that works while booting
+ *	pin		the pin to be programmed
+ *	pull		pull up, pull down or no pull
+ *	trigger		LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, EDGE_HIGH, BOTH_EDGES
+ *	action		STATUS, DELIVER, STATUS_DELIVER
+ * PAD_SCI		The pin is a SCI source
+ *	pin		the pin to be programmed
+ *	pull		pull up, pull down or no pull
+ *	trigger		LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, EDGE_HIGH
+ * PAD_SMI		The pin is a SMI source
+ *	pin		the pin to be programmed
+ *	pull		pull up, pull down or no pull
+ *	trigger		LEVEL_LOW, LEVEL_HIGH
+ * PAD_WAKE		The pin can wake, use after PAD_INT or PAD_SCI
+ *	pin		the pin to be programmed
+ *	pull		pull up, pull down or no pull
+ *	trigger		LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, EDGE_HIGH, BOTH_EDGES
+ *	type		S0i3, S3, S4_S5 or S4_S5 combinations (S0i3_S3 invalid)
+ * PAD_DEBOUNCE		The input or interrupt will be debounced, invalid after
+ *			PAD_NF
+ *	pin		the pin to be programmed
+ *	debounce_type	preserve low glitch, preserve high glitch, no glitch
+ *	debounce_time	the debounce time
+ */
+
 /* Native function pad configuration */
 #define PAD_NF(pin, func, pull) \
 	{ .gpio = (pin), \
 		.function = pin ## _IOMUX_ ## func, \
-		.control = GPIO_PULL ## _ ## pull }
+		.control = GPIO_PULL ## _ ## pull, \
+		.flags = 0 }
 /* General purpose input pad configuration */
 #define PAD_GPI(pin, pull) \
 	{ .gpio = (pin), \
 		.function = pin ## _IOMUX_ ## GPIOxx, \
-		.control = GPIO_PULL ## _ ## pull }
+		.control = GPIO_PULL ## _ ## pull, \
+		.flags = 0 }
 /* General purpose output pad configuration */
 #define PAD_GPO(pin, direction) \
 	{ .gpio = (pin), \
 		.function = pin ## _IOMUX_ ## GPIOxx, \
-		.control = GPIO_OUTPUT ## _OUT_ ## direction }
+		.control = GPIO_OUTPUT ## _OUT_ ## direction, \
+		.flags = 0 }
+/* Auxiliary macro for legacy interrupt and wake */
+#define PAD_AUX1(pull, trigger) (GPIO_PULL ## _ ## pull | \
+				 GPIO_INT ## _ ## trigger)
+/* Legacy interrupt pad configuration */
+#define PAD_INT(pin, pull, trigger, action) \
+	{ .gpio = (pin), \
+		.function = pin ## _IOMUX_ ## GPIOxx, \
+		.control = (PAD_AUX1(pull, trigger) | \
+			    GPIO_EVENT_INT ## _ ## action), \
+		.flags = GPIO_FLAG_INT }
+/* Auxiliary macro for SCI and SMI */
+#define PAD_AUX2(trigger, flag) (GPIO_TRIGGER ## _ ## trigger | flag)
+/* SCI pad configuration */
+#define PAD_SCI(pin, pull, trigger) \
+	{ .gpio = (pin), \
+		.function = pin ## _IOMUX_ ## GPIOxx, \
+		.control = GPIO_PULL ## _ ## pull, \
+		.flags = PAD_AUX2(trigger, GPIO_FLAG_SCI) }
+/* SMI pad configuration */
+#define PAD_SMI(pin, pull, trigger) \
+	{ .gpio = (pin), \
+		.function = pin ## _IOMUX_ ## GPIOxx, \
+		.control = GPIO_PULL ## _ ## pull, \
+		.flags = PAD_AUX2(trigger, GPIO_FLAG_SMI) }
+/* WAKE pad configuration */
+#define PAD_WAKE(pin, pull, trigger, type) \
+	{ .gpio = (pin), \
+		.function = pin ## _IOMUX_ ## GPIOxx, \
+		.control = (PAD_AUX1(pull, trigger) | \
+			    GPIO_WAKE ## _ ## type), \
+		.flags = GPIO_FLAG_WAKE }
+/* pin debounce configuration */
+#define PAD_DEBOUNCE(pin, type, time) \
+	{ .gpio = (pin), \
+		.function = pin ## _IOMUX_ ## GPIOxx, \
+		.control = (GPIO_IN  ## _ ## type | GPIO_IN  ## _ ## time), \
+		.flags = GPIO_FLAG_DEBOUNCE }
 
 typedef uint32_t gpio_t;
 
-/* Update interrupt settings for given GPIO */
-void gpio_set_interrupt(gpio_t gpio, uint32_t flags);
+/**
+ * @brief program a particular set of GPIO
+ *
+ * @param gpio_list_ptr = pointer to array of gpio configurations
+ * @param size = number of entries in array
+ *
+ * @return none
+ */
+void sb_program_gpios(const struct soc_amd_gpio *gpio_list_ptr, size_t size);
 
 /* Return the interrupt status and clear if set. */
 int gpio_interrupt_status(gpio_t gpio);
diff --git a/src/soc/amd/stoneyridge/include/soc/southbridge.h b/src/soc/amd/stoneyridge/include/soc/southbridge.h
index 0a23fca..10b1f43 100644
--- a/src/soc/amd/stoneyridge/include/soc/southbridge.h
+++ b/src/soc/amd/stoneyridge/include/soc/southbridge.h
@@ -306,7 +306,6 @@
 
 #define WIDEIO_RANGE_ERROR		-1
 #define TOTAL_WIDEIO_PORTS		3
-#define AMD_GPIO_MUX_MASK		0x03
 
 #if ENV_BOOTBLOCK
 #define GPIO_TABLE_BOOTBLOCK		1
@@ -354,12 +353,6 @@
 #define   FCH_AOAC_STAT0		BIT(6)
 #define   FCH_AOAC_STAT1		BIT(7)
 
-struct soc_amd_gpio {
-	uint8_t gpio;
-	uint8_t function;
-	uint8_t control;
-};
-
 struct stoneyridge_aoac {
 	int enable;
 	int status;
@@ -443,15 +436,6 @@
  */
 uint64_t get_uma_base(void);
 /**
- * @brief program a particular set of GPIO
- *
- * @param gpio_ptr = pointer to array of gpio configurations
- * @param size = number of entries in array
- *
- * @return none
- */
-void sb_program_gpios(const struct soc_amd_gpio *gpio_ptr, size_t size);
-/**
  * @brief Find the size of a particular wide IO
  *
  * @param index = index of desired wide IO
diff --git a/src/soc/amd/stoneyridge/southbridge.c b/src/soc/amd/stoneyridge/southbridge.c
index 5a3a442..cc21601 100644
--- a/src/soc/amd/stoneyridge/southbridge.c
+++ b/src/soc/amd/stoneyridge/southbridge.c
@@ -173,27 +173,6 @@
 	return irq_association;
 }
 
-void sb_program_gpios(const struct soc_amd_gpio *gpio_ptr, size_t size)
-{
-	void *tmp_ptr;
-	uint8_t control, mux, index;
-
-	for (index = 0; index < size; index++) {
-		mux = gpio_ptr[index].function;
-		control = gpio_ptr[index].control;
-		tmp_ptr = (void *)(gpio_ptr[index].gpio + AMD_GPIO_MUX);
-		write8(tmp_ptr, mux & AMD_GPIO_MUX_MASK);
-
-		/*
-		 * Get the address of AMD_GPIO_CONTROL (dword) relative
-		 * to the desired pin and program bits 16-23.
-		 */
-		tmp_ptr = (void *)(gpio_ptr[index].gpio * sizeof(uint32_t) +
-					AMD_GPIO_CONTROL + 2);
-		write8(tmp_ptr, control);
-	}
-}
-
 /**
  * @brief Find the size of a particular wide IO
  *