summaryrefslogtreecommitdiff
path: root/src/soc/intel/apollolake/gpio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/intel/apollolake/gpio.c')
-rw-r--r--src/soc/intel/apollolake/gpio.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/src/soc/intel/apollolake/gpio.c b/src/soc/intel/apollolake/gpio.c
index ac0d83b810..525c972b5c 100644
--- a/src/soc/intel/apollolake/gpio.c
+++ b/src/soc/intel/apollolake/gpio.c
@@ -19,6 +19,7 @@
#include <gpio.h>
#include <soc/gpio.h>
#include <soc/iosf.h>
+#include <soc/pm.h>
/* This list must be in order, from highest pad numbers, to lowest pad numbers*/
static const struct pad_community {
@@ -150,3 +151,70 @@ uint16_t gpio_acpi_pin(gpio_t gpio_num)
return gpio_num;
}
+
+/* Helper function to map PMC register groups to tier1 sci groups */
+static int pmc_gpe_route_to_gpio(int route)
+{
+ switch(route) {
+ case PMC_GPE_SW_31_0:
+ return GPIO_GPE_SW_31_0;
+ case PMC_GPE_SW_63_32:
+ return GPIO_GPE_SW_63_32;
+ case PMC_GPE_NW_31_0:
+ return GPIO_GPE_NW_31_0;
+ case PMC_GPE_NW_63_32:
+ return GPIO_GPE_NW_63_32;
+ case PMC_GPE_NW_95_64:
+ return GPIO_GPE_NW_95_64;
+ case PMC_GPE_N_31_0:
+ return GPIO_GPE_N_31_0;
+ case PMC_GPE_N_63_32:
+ return GPIO_GPE_N_63_32;
+ case PMC_GPE_W_31_0:
+ return GPIO_GPE_W_31_0;
+ default:
+ return -1;
+ }
+}
+
+void gpio_route_gpe(uint8_t gpe0b, uint8_t gpe0c, uint8_t gpe0d)
+{
+ int i;
+ uint32_t misccfg_mask;
+ uint32_t misccfg_value;
+ uint32_t value;
+
+ /* Get the group here for community specific MISCCFG register.
+ * If any of these returns -1 then there is some error in devicetree
+ * where the group is probably hardcoded and does not comply with the
+ * PMC group defines. So we return from here and MISCFG is set to
+ * default.
+ */
+ gpe0b = pmc_gpe_route_to_gpio(gpe0b);
+ if(gpe0b == -1)
+ return;
+ gpe0c = pmc_gpe_route_to_gpio(gpe0c);
+ if(gpe0c == -1)
+ return;
+ gpe0d = pmc_gpe_route_to_gpio(gpe0d);
+ if(gpe0d == -1)
+ return;
+
+ misccfg_value = gpe0b << MISCCFG_GPE0_DW0_SHIFT;
+ misccfg_value |= gpe0c << MISCCFG_GPE0_DW1_SHIFT;
+ misccfg_value |= gpe0d << MISCCFG_GPE0_DW2_SHIFT;
+
+ /* Program GPIO_MISCCFG */
+ misccfg_mask = ~(MISCCFG_GPE0_DW2_MASK |
+ MISCCFG_GPE0_DW1_MASK |
+ MISCCFG_GPE0_DW0_MASK);
+
+ for (i = 0; i < ARRAY_SIZE(gpio_communities); i++) {
+ const struct pad_community *comm = &gpio_communities[i];
+
+ value = iosf_read(comm->port, GPIO_MISCCFG);
+ value &= misccfg_mask;
+ value |= misccfg_value;
+ iosf_write(comm->port, GPIO_MISCCFG, value);
+ }
+}