[coreboot-gerrit] Patch set updated for coreboot: soc/apollolake: add GPIO SMI support

Shaunak Saha (shaunak.saha@intel.com) gerrit at coreboot.org
Thu Aug 4 20:29:09 CEST 2016


Shaunak Saha (shaunak.saha at intel.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/15833

-gerrit

commit 6645576052acb9f5448470e41c74ede4a4440d6e
Author: Shaunak Saha <shaunak.saha at intel.com>
Date:   Sun Jul 24 20:50:12 2016 -0700

    soc/apollolake: add GPIO SMI support
    
    GPIOs which trigger SMIs set the GPIO_SMI_STS status bits in SMI_STS
    register. This patch also sets the SMI_EN bit in enable register for
    each community based on GPIOROUTSMI bit in gpio pad. When SMI on a
    gpio happens status needs to be gathered on gpio number which is done
    by reading the GPI_SMI_STS and GPI_SMI_EN registers.
    
    BUG=chrome-os-partner:54977
    TEST=When system is in firmware mode executing the command
         lidclose from ec console shuts down the system.
    
    Change-Id: Id89a526106d1989c2bd3416ab81913e6cf743d17
    Signed-off-by: Shaunak Saha <shaunak.saha at intel.com>
---
 src/soc/intel/apollolake/Makefile.inc            |  1 +
 src/soc/intel/apollolake/gpio.c                  | 90 ++++++++++++++++++++++++
 src/soc/intel/apollolake/include/soc/gpio.h      | 22 ++++++
 src/soc/intel/apollolake/include/soc/gpio_defs.h | 28 ++++++++
 src/soc/intel/apollolake/include/soc/pm.h        |  1 +
 src/soc/intel/apollolake/include/soc/smm.h       |  3 +
 src/soc/intel/apollolake/pmc.c                   | 11 +++
 src/soc/intel/apollolake/smi.c                   |  2 +-
 src/soc/intel/apollolake/smihandler.c            | 16 +++++
 9 files changed, 173 insertions(+), 1 deletion(-)

diff --git a/src/soc/intel/apollolake/Makefile.inc b/src/soc/intel/apollolake/Makefile.inc
index 9e30df8..6eb9d9a 100644
--- a/src/soc/intel/apollolake/Makefile.inc
+++ b/src/soc/intel/apollolake/Makefile.inc
@@ -40,6 +40,7 @@ romstage-y += spi.c
 
 smm-y += mmap_boot.c
 smm-y += pmutil.c
+smm-y += gpio.c
 smm-y += smihandler.c
 smm-y += spi.c
 smm-y += tsc_freq.c
diff --git a/src/soc/intel/apollolake/gpio.c b/src/soc/intel/apollolake/gpio.c
index 8ac00cd..e2541d9 100644
--- a/src/soc/intel/apollolake/gpio.c
+++ b/src/soc/intel/apollolake/gpio.c
@@ -26,19 +26,29 @@
 static const struct pad_community {
 	uint16_t first_pad;
 	uint8_t port;
+	uint8_t num_gpi_regs;
+	const char *grp_name;
 } gpio_communities[] = {
 	{
 		.port = GPIO_SOUTHWEST,
 		.first_pad = SW_OFFSET,
+		.num_gpi_regs = NUM_SW_GPI_REGS,
+		.grp_name = "GPIO_GPE_SW",
 	}, {
 		.port = GPIO_WEST,
 		.first_pad = W_OFFSET,
+		.num_gpi_regs = NUM_W_GPI_REGS,
+		.grp_name = "GPIO_GPE_W",
 	}, {
 		.port = GPIO_NORTHWEST,
 		.first_pad = NW_OFFSET,
+		.num_gpi_regs = NUM_NW_GPI_REGS,
+		.grp_name = "GPIO_GPE_NW",
 	}, {
 		.port = GPIO_NORTH,
 		.first_pad = N_OFFSET,
+		.num_gpi_regs = NUM_N_GPI_REGS,
+		.grp_name = "GPIO_GPE_N",
 	}
 };
 
@@ -104,6 +114,25 @@ static void gpio_configure_owner(const struct pad_config *cfg,
 	iosf_write(port, hostsw_reg, val);
 }
 
+static void gpi_enable_smi(const struct pad_config *cfg,
+                                 uint16_t port, int pin)
+{
+	uint32_t pad_mask;
+	uint32_t value;
+
+	if (((cfg->config0) & PAD_CFG0_ROUTE_SMI)  != PAD_CFG0_ROUTE_SMI)
+		return;
+
+	pad_mask = iosf_read(port, GPI_SMI_STS_OFFSET(pin / GPIO_MAX_NUM_PER_GROUP));
+	/* Write back 1 to reset the sts bits */
+	iosf_write(port, GPI_SMI_STS_OFFSET(pin / GPIO_MAX_NUM_PER_GROUP), pad_mask);
+	
+	/* Set enable bits */
+	value = iosf_read(port, GPI_SMI_EN_OFFSET(pin / GPIO_MAX_NUM_PER_GROUP) );
+	value |= 1 << (pin % GPIO_MAX_NUM_PER_GROUP);
+	iosf_write(port, GPI_SMI_EN_OFFSET(pin / GPIO_MAX_NUM_PER_GROUP) , value);
+}
+
 void gpio_configure_pad(const struct pad_config *cfg)
 {
 	uint32_t dw1;
@@ -123,6 +152,7 @@ void gpio_configure_pad(const struct pad_config *cfg)
 	gpio_configure_itss(cfg, comm->port, config_offset);
 	gpio_configure_owner(cfg, comm->port, cfg->pad - comm->first_pad);
 
+	gpi_enable_smi(cfg, comm->port, cfg->pad - comm->first_pad);
 }
 
 void gpio_configure_pads(const struct pad_config *cfg, size_t num_pads)
@@ -216,6 +246,66 @@ uint16_t gpio_acpi_pin(gpio_t gpio_num)
 	return gpio_num;
 }
 
+void gpi_clear_get_smi_status(struct gpi_status *sts)
+{
+	int i;
+	int group;
+	int index = 0;
+	int bit_set;
+
+	for (i = 0; i < ARRAY_SIZE(gpio_communities); i++) {
+		/* For every community we loop through the groups now */
+		for (group = 0; group < gpio_communities[i].num_gpi_regs;
+							group++) {
+			sts->grp[index] = iosf_read(gpio_communities[i].port,
+				GPI_SMI_STS_OFFSET(group)) &
+				iosf_read(gpio_communities[i].port,
+				GPI_SMI_EN_OFFSET(group));
+			/* Clear the set status bits. */
+			iosf_write(gpio_communities[i].port,
+				GPI_SMI_STS_OFFSET(group), sts->grp[index]);
+			/*
+			 * We can check sts group index now as for a single
+			 * smi only one index in sts will have a non zero value.
+			 */
+			if( (sts->grp[index]) != 0)
+			{
+				for (bit_set = 31; bit_set >= 0; bit_set--) {
+					if (sts->grp[index] & (1 << bit_set))
+						printk(BIOS_DEBUG, "%s %d \n",
+						gpio_communities[i].grp_name,
+						bit_set);
+				}
+			}
+			index++;
+		}
+	}
+}
+
+int gpi_status_get(const struct gpi_status *sts, gpio_t gpi)
+{
+	const uint32_t *gpi_sts = NULL;
+	uint8_t sts_index = 0;
+	uint8_t gpi_offset = 0;
+	uint16_t config_offset;
+
+	const struct pad_community *comm = gpio_get_community(gpi);
+
+	/* Check if valid gpi */
+	if (comm == NULL)
+		return 0;
+
+	config_offset = gpi - comm->first_pad;
+	gpi_offset = config_offset % GPIO_MAX_NUM_PER_GROUP;
+
+	for (sts_index = 0; sts_index < ARRAY_SIZE(sts->grp); sts_index++) {
+		if (sts->grp[sts_index] == (1 << gpi_offset))
+			gpi_sts = &sts->grp[sts_index];
+	}
+
+	return !!(*gpi_sts & (1 << (gpi % GPIO_MAX_NUM_PER_GROUP)));
+}
+
 /* Helper function to map PMC register groups to tier1 sci groups */
 static int pmc_gpe_route_to_gpio(int route)
 {
diff --git a/src/soc/intel/apollolake/include/soc/gpio.h b/src/soc/intel/apollolake/include/soc/gpio.h
index 8ef74bb..a4a02c7 100644
--- a/src/soc/intel/apollolake/include/soc/gpio.h
+++ b/src/soc/intel/apollolake/include/soc/gpio.h
@@ -25,6 +25,28 @@
 
 typedef uint32_t gpio_t;
 
+/*
+ * Structure to represent GPI status for GPE and SMI. Use helper
+ * functions for interrogating particular GPIs. Here the number of
+ * array elements is total number of groups that can be present in all
+ * the communities. We use this type of representation instead of
+ * actual groups present in apollolake soc to makes logic in code simple
+ * as it creates a 1:1 maping.
+ */
+struct gpi_status {
+	uint32_t grp[NUM_N_GPI_REGS + NUM_NW_GPI_REGS + NUM_W_GPI_REGS +
+							NUM_SW_GPI_REGS];
+};
+
+/*
+ * Clear GPI SMI status and fill in the structure representing enabled
+ * and set status.
+ */
+void gpi_clear_get_smi_status(struct gpi_status *sts);
+
+/* Return 1 if gpio is set in the gpi_status struct. Otherwise 0. */
+int gpi_status_get(const struct gpi_status *sts, gpio_t gpi);
+
 #define PAD_FUNC(value)		PAD_CFG0_MODE_##value
 #define PAD_RESET(value)	PAD_CFG0_RESET_##value
 #define PAD_PULL(value)		PAD_CFG1_PULL_##value
diff --git a/src/soc/intel/apollolake/include/soc/gpio_defs.h b/src/soc/intel/apollolake/include/soc/gpio_defs.h
index d85f844..6946823 100644
--- a/src/soc/intel/apollolake/include/soc/gpio_defs.h
+++ b/src/soc/intel/apollolake/include/soc/gpio_defs.h
@@ -38,6 +38,8 @@
 #define  GPIO_GPE_N_31_0	7 /* NORTH     GPIO#  0 ~ 31 belong to GROUP7 */
 #define  GPIO_GPE_N_63_32	8 /* NORTH     GPIO# 32 ~ 61 belong to GROUP8 */
 
+#define GPIO_MAX_NUM_PER_GROUP	32
+
 #define MISCCFG_GPE0_DW0_SHIFT 8
 #define MISCCFG_GPE0_DW0_MASK (0xf << MISCCFG_GPE0_DW0_SHIFT)
 #define MISCCFG_GPE0_DW1_SHIFT 12
@@ -134,6 +136,32 @@
 #define GPIO_NORTH			0xc5
 #define GPIO_WEST			0xc7
 
+#define GPI_SMI_STS_0			0x140
+#define GPI_SMI_EN_0			0x150
+#define GPI_SMI_STS_OFFSET(group)	(GPI_SMI_STS_0 + ((group) * 4))
+#define GPI_SMI_EN_OFFSET(group)	(GPI_SMI_EN_0 + ((group) * 4))
+
+#define NUM_N_PADS			(PAD_N(SVID0_CLK) + 1)
+#define NUM_NW_PADS			(PAD_NW(GPIO_123) + 1)
+#define NUM_W_PADS			(PAD_W(SUSPWRDNACK) + 1)
+#define NUM_SW_PADS			(PAD_SW(LPC_FRAMEB) + 1)
+
+#define NUM_N_GPI_REGS			(ALIGN_UP(NUM_N_PADS, \
+					GPIO_MAX_NUM_PER_GROUP) / \
+					GPIO_MAX_NUM_PER_GROUP)
+
+#define NUM_NW_GPI_REGS			(ALIGN_UP(NUM_NW_PADS, \
+					GPIO_MAX_NUM_PER_GROUP) / \
+					GPIO_MAX_NUM_PER_GROUP)
+
+#define NUM_W_GPI_REGS			(ALIGN_UP(NUM_W_PADS, \
+					GPIO_MAX_NUM_PER_GROUP) / \
+					GPIO_MAX_NUM_PER_GROUP)
+
+#define NUM_SW_GPI_REGS			(ALIGN_UP(NUM_SW_PADS, \
+					GPIO_MAX_NUM_PER_GROUP) / \
+					GPIO_MAX_NUM_PER_GROUP)
+
 /* North community pads */
 #define GPIO_0				0
 #define GPIO_1				1
diff --git a/src/soc/intel/apollolake/include/soc/pm.h b/src/soc/intel/apollolake/include/soc/pm.h
index 467c8f1..5641e54 100644
--- a/src/soc/intel/apollolake/include/soc/pm.h
+++ b/src/soc/intel/apollolake/include/soc/pm.h
@@ -70,6 +70,7 @@
 #define   USB_EN		(1 << SMI_XHCI) /* Legacy USB2 SMI logic */
 #define   PERIODIC_EN		(1 << SMI_PERIODIC) /* SMI on PERIODIC_STS in SMI_STS */
 #define   TCO_EN		(1 << SMI_TCO) /* Enable TCO Logic (BIOSWE et al) */
+#define   GPIO_EN		(1 << SMI_GPIO) /* Enable GPIO SMI */
 #define   BIOS_RLS		(1 << SMI_BIOS_RLS) /* asserts SCI on bit set */
 #define   SWSMI_TMR_EN		(1 << SMI_SWSMI_TMR) /* start software smi timer on bit set */
 #define   APMC_EN		(1 << SMI_APMC) /* Writes to APM_CNT cause SMI# */
diff --git a/src/soc/intel/apollolake/include/soc/smm.h b/src/soc/intel/apollolake/include/soc/smm.h
index 0774974..7a9846e 100644
--- a/src/soc/intel/apollolake/include/soc/smm.h
+++ b/src/soc/intel/apollolake/include/soc/smm.h
@@ -19,6 +19,7 @@
 #define _SOC_SMM_H_
 
 #include <stdint.h>
+#include <soc/gpio.h>
 
 /* These helpers are for performing SMM relocation. */
 void southbridge_clear_smi_status(void);
@@ -31,6 +32,8 @@ void southbridge_clear_smi_status(void);
 void southbridge_smm_clear_state(void);
 void southbridge_smm_enable_smi(void);
 
+/* Mainboard handler for GPI SMIs*/
+void mainboard_smi_gpi_handler(const struct gpi_status *sts);
 
 /* Fills in the arguments for the entire SMM region covered by chipset
  * protections. e.g. TSEG. */
diff --git a/src/soc/intel/apollolake/pmc.c b/src/soc/intel/apollolake/pmc.c
index f303632..92a150d 100644
--- a/src/soc/intel/apollolake/pmc.c
+++ b/src/soc/intel/apollolake/pmc.c
@@ -19,6 +19,7 @@
 #include <device/pci.h>
 #include <device/pci_ids.h>
 #include <console/console.h>
+#include <cpu/x86/smm.h>
 #include <soc/iomap.h>
 #include <soc/pci_ids.h>
 #include <soc/gpio.h>
@@ -122,10 +123,20 @@ static void pmc_gpe_init(void)
 	fixup_power_state();
 }
 
+static void pch_set_acpi_mode(void)
+{
+	if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER) && !acpi_is_wakeup_s3()) {
+		printk(BIOS_DEBUG, "Disabling ACPI via APMC:");
+		outb(APM_CNT_ACPI_DISABLE, APM_CNT);
+		printk(BIOS_DEBUG, "Done.\n");
+	}
+}
+
 static void pmc_init(struct device *dev)
 {
 	/* Set up GPE configuration */
 	pmc_gpe_init();
+	pch_set_acpi_mode();
 }
 
 static const struct device_operations device_ops = {
diff --git a/src/soc/intel/apollolake/smi.c b/src/soc/intel/apollolake/smi.c
index 4f151fe..3ad33fd 100644
--- a/src/soc/intel/apollolake/smi.c
+++ b/src/soc/intel/apollolake/smi.c
@@ -52,7 +52,7 @@ void southbridge_smm_enable_smi(void)
 	disable_gpe(PME_B0_EN);
 
 	/* Enable SMI generation */
-	enable_smi(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | EOS);
+	enable_smi(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | EOS | GPIO_EN);
 }
 
 void southbridge_clear_smi_status(void)
diff --git a/src/soc/intel/apollolake/smihandler.c b/src/soc/intel/apollolake/smihandler.c
index 1521920..b84e5cb 100644
--- a/src/soc/intel/apollolake/smihandler.c
+++ b/src/soc/intel/apollolake/smihandler.c
@@ -30,6 +30,7 @@
 #include <spi-generic.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <soc/smm.h>
 
 int smm_disable_busmaster(device_t dev)
 {
@@ -43,10 +44,25 @@ const struct smm_save_state_ops *get_smm_save_state_ops(void)
 	return &em64t100_smm_ops;
 }
 
+void __attribute__((weak))
+mainboard_smi_gpi_handler(const struct gpi_status *sts) { }
+
+static void southbridge_smi_gpi(const struct smm_save_state_ops *save_state_ops)
+{
+	struct gpi_status smi_sts;
+
+	gpi_clear_get_smi_status(&smi_sts);
+	mainboard_smi_gpi_handler(&smi_sts);
+
+	/* Clear again after mainboard handler */
+	gpi_clear_get_smi_status(&smi_sts);
+}
+
 const smi_handler_t southbridge_smi[32] = {
 	[SLP_SMI_STS] = southbridge_smi_sleep,
 	[APM_SMI_STS] = southbridge_smi_apmc,
 	[FAKE_PM1_SMI_STS] = southbridge_smi_pm1,
+	[GPIO_SMI_STS] = southbridge_smi_gpi,
 	[TCO_SMI_STS] = southbridge_smi_tco,
 	[PERIODIC_SMI_STS] = southbridge_smi_periodic,
 };



More information about the coreboot-gerrit mailing list