aboutsummaryrefslogtreecommitdiff
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.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/src/soc/intel/apollolake/gpio.c b/src/soc/intel/apollolake/gpio.c
index 8ac00cde36..ac72203ed5 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,80 @@ 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;
+ int abs_bit;
+ 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;
+
+ abs_bit = bit_set;
+ abs_bit += group * GPIO_MAX_NUM_PER_GROUP;
+ printk(BIOS_DEBUG, "%s %d \n",comm->grp_name,
+ abs_bit);
+ }
+ }
+ }
+}
+
+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)
{