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

Shaunak Saha (shaunak.saha@intel.com) gerrit at coreboot.org
Wed Aug 10 00:42:38 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 3f428b990931d7f5f7f8ad959aef457deff8ae32
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                  | 112 +++++++++++++++++++++++
 src/soc/intel/apollolake/include/soc/gpio.h      |  19 ++++
 src/soc/intel/apollolake/include/soc/gpio_defs.h |  27 ++++++
 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, 191 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..485c87d 100644
--- a/src/soc/intel/apollolake/gpio.c
+++ b/src/soc/intel/apollolake/gpio.c
@@ -26,19 +26,34 @@
 static const struct pad_community {
 	uint16_t first_pad;
 	uint8_t port;
+	uint8_t num_gpi_regs;
+	uint8_t gpi_offset;
+	const char *grp_name;
 } gpio_communities[] = {
 	{
 		.port = GPIO_SOUTHWEST,
 		.first_pad = SW_OFFSET,
+		.num_gpi_regs = NUM_SW_GPI_REGS,
+		.gpi_offset = 0,
+		.grp_name = "GPIO_GPE_SW",
 	}, {
 		.port = GPIO_WEST,
 		.first_pad = W_OFFSET,
+		.num_gpi_regs = NUM_W_GPI_REGS,
+		.gpi_offset = NUM_SW_GPI_REGS,
+		.grp_name = "GPIO_GPE_W",
 	}, {
 		.port = GPIO_NORTHWEST,
 		.first_pad = NW_OFFSET,
+		.num_gpi_regs = NUM_NW_GPI_REGS,
+		.gpi_offset = NUM_W_GPI_REGS + NUM_SW_GPI_REGS,
+		.grp_name = "GPIO_GPE_NW",
 	}, {
 		.port = GPIO_NORTH,
 		.first_pad = N_OFFSET,
+		.num_gpi_regs = NUM_N_GPI_REGS,
+		.gpi_offset = NUM_NW_GPI_REGS+ NUM_W_GPI_REGS + NUM_SW_GPI_REGS,
+		.grp_name = "GPIO_GPE_N",
 	}
 };
 
@@ -104,6 +119,30 @@ 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 value;
+	uint16_t sts_reg;
+	uint16_t en_reg;
+	int group;
+
+	if (((cfg->config0) & PAD_CFG0_ROUTE_SMI) != PAD_CFG0_ROUTE_SMI)
+		return;
+
+	group = pin / GPIO_MAX_NUM_PER_GROUP;
+
+	sts_reg = GPI_SMI_STS_OFFSET(group);
+	value = iosf_read(port, sts_reg);
+	/* Write back 1 to reset the sts bits */
+	iosf_write(port, sts_reg, value);
+
+	/* Set enable bits */
+	en_reg = GPI_SMI_EN_OFFSET(group);
+	value = iosf_read(port, en_reg );
+	value |= 1 << (pin % GPIO_MAX_NUM_PER_GROUP);
+	iosf_write(port, en_reg , value);
+}
+
 void gpio_configure_pad(const struct pad_config *cfg)
 {
 	uint32_t dw1;
@@ -123,6 +162,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 +256,78 @@ uint16_t gpio_acpi_pin(gpio_t gpio_num)
 	return gpio_num;
 }
 
+static void print_gpi_status(const struct gpi_status *sts)
+{
+	int i;
+	int group;
+	int index = 0;
+	int bit_set;
+	int num_groups;
+	const struct pad_community *comm;
+
+	for (i = 0; i < ARRAY_SIZE(gpio_communities); i++) {
+		comm = &gpio_communities[i];
+		num_groups = comm->num_gpi_regs;
+		index = comm->gpi_offset;
+		for (group = 0; group < num_groups; group++, index++) {
+			for (bit_set = 31; bit_set >= 0; bit_set--) {
+				if (!(sts->grp[index] & (1 << bit_set)))
+					continue;
+
+				printk(BIOS_DEBUG, "%s %d \n",
+				gpio_communities[i].grp_name,
+				bit_set + (group * GPIO_MAX_NUM_PER_GROUP));
+			}
+		}
+	}
+}
+
+void gpi_clear_get_smi_status(struct gpi_status *sts)
+{
+	int i;
+	int group;
+	int index = 0;
+	uint32_t sts_value;
+	uint32_t en_value;
+	int num_groups;
+	const struct pad_community *comm;
+
+	for (i = 0; i < ARRAY_SIZE(gpio_communities); i++) {
+		comm = &gpio_communities[i];
+		num_groups = comm->num_gpi_regs;
+		index = comm->gpi_offset;
+		for (group = 0; group < num_groups; group++, index++) {
+			sts_value = iosf_read(gpio_communities[i].port,
+					GPI_SMI_STS_OFFSET(group));
+			en_value = iosf_read(gpio_communities[i].port,
+					GPI_SMI_EN_OFFSET(group));
+			sts->grp[index] = sts_value & en_value;
+			/* Clear the set status bits. */
+			iosf_write(gpio_communities[i].port,
+				GPI_SMI_STS_OFFSET(group), sts->grp[index]);
+		}
+	}
+
+	if (IS_ENABLED(CONFIG_DEBUG_SMI))
+		print_gpi_status(sts);
+
+}
+
+int gpi_status_get(const struct gpi_status *sts, gpio_t gpi)
+{
+	uint8_t sts_index;
+	const struct pad_community *comm = gpio_get_community(gpi);
+
+	/* Check if valid gpi */
+	if (comm == NULL)
+		return 0;
+
+	sts_index = comm->gpi_offset + (gpi - (comm->first_pad) /
+					GPIO_MAX_NUM_PER_GROUP);
+
+	return !!(sts->grp[sts_index] & (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..0089444 100644
--- a/src/soc/intel/apollolake/include/soc/gpio.h
+++ b/src/soc/intel/apollolake/include/soc/gpio.h
@@ -25,6 +25,25 @@
 
 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.
+ */
+struct gpi_status {
+	uint32_t grp[NUM_GPI_STATUS_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..88fa475 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,31 @@
 #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)
+
+#define NUM_GPI_STATUS_REGS		(NUM_N_GPI_REGS + NUM_NW_GPI_REGS \
+					+ NUM_W_GPI_REGS + NUM_SW_GPI_REGS)
+
 /* 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