[coreboot-gerrit] New patch to review for coreboot: skylake: provide GPE0 routing devicetree configuration

Aaron Durbin (adurbin@chromium.org) gerrit at coreboot.org
Wed Aug 12 17:52:23 CEST 2015


Aaron Durbin (adurbin at chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/11203

-gerrit

commit 937b46fc66eea9daa51703deb2d25c2aab3e81e5
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Fri Aug 7 22:29:42 2015 -0500

    skylake: provide GPE0 routing devicetree configuration
    
    On skylake the GPE0 routing can be dynamically changed to
    a particular GPIO group. Provide the ability for the mainboard
    to set the route accordingly. If any of the values in the
    devicetree are the same the current setting in the PMC register
    is used. The GPIO communities need to have matching configuration
    for the plumbing to work properly.
    
    BUG=chrome-os-partner:43778
    BRANCH=None
    TEST=Built and booted glados w/ and w/o devicetree changes. Fields
         are set accordingly.
    
    Original-Change-Id: I263d648c8ea8a70b21570f01b333d05a5fa2a4e3
    Original-Signed-off-by: Aaron Durbin <adurbin at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/291930
    Original-Reviewed-by: Duncan Laurie <dlaurie at chromium.org>
    
    Change-Id: I966d38bc197dbb52a2ba50927c06e243e169afbe
    Signed-off-by: Aaron Durbin <adurbin at chromium.org>
---
 src/soc/intel/skylake/chip.h                  | 21 ++++++++-----
 src/soc/intel/skylake/gpio.c                  | 23 ++++++++++++++
 src/soc/intel/skylake/include/soc/gpio.h      |  9 ++++++
 src/soc/intel/skylake/include/soc/gpio_defs.h | 31 ++++++++++++++++---
 src/soc/intel/skylake/include/soc/pmc.h       |  5 ++++
 src/soc/intel/skylake/pmc.c                   | 43 +++++++++++++++++++++++++--
 6 files changed, 118 insertions(+), 14 deletions(-)

diff --git a/src/soc/intel/skylake/chip.h b/src/soc/intel/skylake/chip.h
index 96389a9..873342a 100644
--- a/src/soc/intel/skylake/chip.h
+++ b/src/soc/intel/skylake/chip.h
@@ -19,14 +19,16 @@
  * Foundation, Inc.
  */
 
+
+#ifndef _SOC_CHIP_H_
+#define _SOC_CHIP_H_
+
 #include <stdint.h>
+#include <soc/gpio_defs.h>
 #include <soc/pci_devs.h>
 #include <soc/pmc.h>
 #include <soc/serialio.h>
 
-#ifndef _SOC_CHIP_H_
-#define _SOC_CHIP_H_
-
 struct soc_intel_skylake_config {
 	/*
 	 * Interrupt Routing configuration
@@ -42,10 +44,15 @@ struct soc_intel_skylake_config {
 	uint8_t pirqh_routing;
 
 	/* GPE configuration */
-	uint32_t gpe0_en_1;
-	uint32_t gpe0_en_2;
-	uint32_t gpe0_en_3;
-	uint32_t gpe0_en_4;
+	uint32_t gpe0_en_1; /* GPE0_EN_31_0 */
+	uint32_t gpe0_en_2; /* GPE0_EN_63_32 */
+	uint32_t gpe0_en_3; /* GPE0_EN_95_64 */
+	uint32_t gpe0_en_4; /* GPE0_EN_127_96 / GPE_STD */
+	/* Gpio group routed to each dword of the GPE0 block. Values are
+	 * of the form GPP_[A:G] or GPD. */
+	uint8_t gpe0_dw0; /* GPE0_31_0 STS/EN */
+	uint8_t gpe0_dw1; /* GPE0_63_32 STS/EN */
+	uint8_t gpe0_dw2; /* GPE0_95_64 STS/EN */
 
 	/* GPIO SMI configuration */
 	uint32_t ec_smi_gpio;
diff --git a/src/soc/intel/skylake/gpio.c b/src/soc/intel/skylake/gpio.c
index 28ed07e..1863887 100644
--- a/src/soc/intel/skylake/gpio.c
+++ b/src/soc/intel/skylake/gpio.c
@@ -71,6 +71,29 @@ static const struct gpio_community *gpio_get_community(gpio_t pad)
 	return NULL;
 }
 
+void gpio_route_gpe(uint16_t gpe0_route)
+{
+	int i;
+	uint32_t misc_cfg;
+	const uint32_t misc_cfg_reg_mask = GPE_DW_MASK;
+
+	misc_cfg = (uint32_t)gpe0_route << GPE_DW_SHIFT;
+	misc_cfg &= misc_cfg_reg_mask;
+
+	for (i = 0; i < ARRAY_SIZE(communities); i++) {
+		uint8_t *regs;
+		uint32_t reg;
+		const struct gpio_community *comm = &communities[i];
+
+		regs = pcr_port_regs(comm->port_id);
+
+		reg = read32(regs + MISCCFG_OFFSET);
+		reg &= ~misc_cfg_reg_mask;
+		reg |= misc_cfg;
+		write32(regs + MISCCFG_OFFSET, reg);
+	}
+}
+
 static void *gpio_dw_regs(gpio_t pad)
 {
 	const struct gpio_community *comm;
diff --git a/src/soc/intel/skylake/include/soc/gpio.h b/src/soc/intel/skylake/include/soc/gpio.h
index a7d9158..321f04c 100644
--- a/src/soc/intel/skylake/include/soc/gpio.h
+++ b/src/soc/intel/skylake/include/soc/gpio.h
@@ -43,6 +43,15 @@ void gpio_enable_all_smi(void);
 /* Enable GPIO individual Group SMI  */
 void gpio_enable_groupsmi(gpio_t gpio_num, u32 mask);
 
+/*
+ * Set the GPIO groups for the GPE blocks. The gpe0_route is interpreted
+ * as the packed configuration for GPE0_DW[2:0]:
+ *  dw0 = gpe0_route[3:0]
+ *  dw1 = gpe0_route[7:4]
+ *  dw2 = gpe0_route[11:8].
+ */
+void gpio_route_gpe(uint16_t gpe0_route);
+
 /* Configure the pads according to the pad_config array. */
 struct pad_config;
 void gpio_configure_pads(const struct pad_config *cfgs, size_t num);
diff --git a/src/soc/intel/skylake/include/soc/gpio_defs.h b/src/soc/intel/skylake/include/soc/gpio_defs.h
index 625acdb..09f5019 100644
--- a/src/soc/intel/skylake/include/soc/gpio_defs.h
+++ b/src/soc/intel/skylake/include/soc/gpio_defs.h
@@ -21,6 +21,23 @@
 #define _SOC_GPIO_DEFS_H_
 
 /*
+ * There are 8 GPIO groups. GPP_A -> GPP_G and GPD. GPD is the special case
+ * where that group is not so generic. So most of the fixed numbers and macros
+ * are based on the GPP groups. The GPIO groups are accessed through register
+ * blocks called communities.
+ */
+#define GPP_A			0
+#define GPP_B			1
+#define GPP_C			2
+#define GPP_D			3
+#define GPP_E			4
+#define GPP_F			5
+#define GPP_G			6
+#define GPD			7
+#define GPIO_NUM_GROUPS		8
+#define GPIO_MAX_NUM_PER_GROUP	24
+
+/*
  * GPIOs are ordered monotonically increasing to match ACPI/OS driver.
  */
 
@@ -375,6 +392,12 @@
 #define GPD11_IRQ		0x5b
 
 /* Register defines. */
+#define MISCCFG_OFFSET		0x10
+#define  GPIO_DRIVER_IRQ_ROUTE_MASK	8
+#define  GPIO_DRIVER_IRQ_ROUTE_IRQ14	0
+#define  GPIO_DRIVER_IRQ_ROUTE_IRQ15	8
+#define  GPE_DW_SHIFT		8
+#define  GPE_DW_MASK		0xfff00
 #define PAD_OWN_REG_OFFSET	0x20
 #define  PAD_OWN_PADS_PER	8
 #define  PAD_OWN_WIDTH_PER	4
@@ -476,9 +499,9 @@
 #define  PAD_TERM_667_PU	13
 #define  PAD_TERM_NATIVE	15
 
-#define  MISCCFG_OFFSET			0x10
-#define  GPIO_DRIVER_IRQ_ROUTE_MASK	8
-#define  GPIO_DRIVER_IRQ_ROUTE_IRQ14	0
-#define  GPIO_DRIVER_IRQ_ROUTE_IRQ15	8
+#define GPI_GPE_STS_OFFSET	0x140
+#define GPI_GPE_EN_OFFSET	0x160
+#define GPI_SMI_STS_OFFSET	0x180
+#define GPI_SMI_EN_OFFSET	0x1a0
 
 #endif /* _SOC_GPIO_DEFS_H_ */
diff --git a/src/soc/intel/skylake/include/soc/pmc.h b/src/soc/intel/skylake/include/soc/pmc.h
index 5774d46..9c9b175 100644
--- a/src/soc/intel/skylake/include/soc/pmc.h
+++ b/src/soc/intel/skylake/include/soc/pmc.h
@@ -91,6 +91,11 @@
 #define  DSX_EN_LAN_WAKE_PIN	(1 << 0)
 #define PMSYNC_TPR_CFG		0xc4
 #define  PMSYNC_LOCK		(1 << 31)
+#define GPIO_CFG		0x120
+#define  GPE0_DWX_MASK		0xf
+#define  GPE0_DW0_SHIFT		0
+#define  GPE0_DW1_SHIFT		4
+#define  GPE0_DW2_SHIFT		8
 #define GBLRST_CAUSE0		0x124
 #define GBLRST_CAUSE1		0x128
 
diff --git a/src/soc/intel/skylake/pmc.c b/src/soc/intel/skylake/pmc.c
index 2c794ca..b6c35eb 100644
--- a/src/soc/intel/skylake/pmc.c
+++ b/src/soc/intel/skylake/pmc.c
@@ -27,6 +27,7 @@
 #include <pc80/mc146818rtc.h>
 #include <reg_script.h>
 #include <string.h>
+#include <soc/gpio.h>
 #include <soc/iomap.h>
 #include <soc/pci_devs.h>
 #include <soc/pmc.h>
@@ -147,6 +148,42 @@ static void pch_rtc_init(void)
 #endif
 }
 
+static void pmc_gpe_init(config_t *config)
+{
+	uint8_t *pmc_regs;
+	uint32_t gpio_cfg;
+	uint32_t gpio_cfg_reg;
+	const uint32_t gpio_cfg_mask =
+		(GPE0_DWX_MASK << GPE0_DW0_SHIFT) |
+		(GPE0_DWX_MASK << GPE0_DW1_SHIFT) |
+		(GPE0_DWX_MASK << GPE0_DW2_SHIFT);
+
+	pmc_regs = pmc_mmio_regs();
+	gpio_cfg = 0;
+
+	/* Route the GPIOs to the GPE0 block. Determine that all values
+	 * are different, and if they aren't use the reset values. */
+	if (config->gpe0_dw0 == config->gpe0_dw1 ||
+		config->gpe0_dw1 == config->gpe0_dw2) {
+		printk(BIOS_INFO, "PMC: Using default GPE route.\n");
+		gpio_cfg = read32(pmc_regs + GPIO_CFG);
+	} else {
+		gpio_cfg |= (uint32_t)config->gpe0_dw0 << GPE0_DW0_SHIFT;
+		gpio_cfg |= (uint32_t)config->gpe0_dw1 << GPE0_DW1_SHIFT;
+		gpio_cfg |= (uint32_t)config->gpe0_dw2 << GPE0_DW2_SHIFT;
+	}
+	gpio_cfg_reg = read32(pmc_regs + GPIO_CFG) & ~gpio_cfg_mask;
+	gpio_cfg_reg |= gpio_cfg & gpio_cfg_mask;
+	write32(pmc_regs + GPIO_CFG, gpio_cfg_reg);
+
+	/* Set the routes in the GPIO communities as well. */
+	gpio_route_gpe(gpio_cfg_reg >> GPE0_DW0_SHIFT);
+
+	/* Set GPE enables based on devictree. */
+	enable_all_gpe(config->gpe0_en_1, config->gpe0_en_2,
+			config->gpe0_en_3, config->gpe0_en_4);
+}
+
 static void pch_power_options(void)
 {
 	u16 reg16;
@@ -187,9 +224,9 @@ static void pch_power_options(void)
 	}
 	pci_write_config16(dev, GEN_PMCON_B, reg16);
 	printk(BIOS_INFO, "Set power %s after power failure.\n", state);
-	/* GPE setup based on device tree configuration */
-	enable_all_gpe(config->gpe0_en_1, config->gpe0_en_2,
-			config->gpe0_en_3, config->gpe0_en_4);
+
+	/* Set up GPE configuration. */
+	pmc_gpe_init(config);
 
 	/* SMI setup based on device tree configuration */
 	enable_alt_smi(config->ec_smi_gpio, config->alt_gp_smi_en);



More information about the coreboot-gerrit mailing list