diff options
author | Shaunak Saha <shaunak.saha@intel.com> | 2016-07-24 20:50:12 -0700 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2016-08-10 21:10:59 +0200 |
commit | 09115a92f6ac6123a6f1ed435c05fe60dc01d58c (patch) | |
tree | 9c6b16087c872cb140c5b447c33ebae3a78e2e23 /src/soc/intel/apollolake/gpio.c | |
parent | a46ee4d34d6b7ce7d47882779c7fb36270ccbda1 (diff) | |
download | coreboot-09115a92f6ac6123a6f1ed435c05fe60dc01d58c.tar.xz |
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@intel.com>
Reviewed-on: https://review.coreboot.org/15833
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Tested-by: build bot (Jenkins)
Diffstat (limited to 'src/soc/intel/apollolake/gpio.c')
-rw-r--r-- | src/soc/intel/apollolake/gpio.c | 114 |
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) { |