summaryrefslogtreecommitdiff
path: root/src/soc/intel/skylake/gpio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/intel/skylake/gpio.c')
-rw-r--r--src/soc/intel/skylake/gpio.c492
1 files changed, 93 insertions, 399 deletions
diff --git a/src/soc/intel/skylake/gpio.c b/src/soc/intel/skylake/gpio.c
index afd65fc007..9c9d041e4f 100644
--- a/src/soc/intel/skylake/gpio.c
+++ b/src/soc/intel/skylake/gpio.c
@@ -2,7 +2,7 @@
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Google Inc.
- * Copyright (C) 2015 Intel Corporation.
+ * Copyright (C) 2015 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,422 +14,116 @@
* GNU General Public License for more details.
*/
-#include <stdint.h>
-#include <string.h>
-#include <arch/io.h>
-#include <console/console.h>
-#include <device/device.h>
-#include <device/pci.h>
-#include <gpio.h>
+#include <assert.h>
+#include <intelblocks/gpio.h>
#include <intelblocks/pcr.h>
#include <soc/pcr_ids.h>
-#include <soc/iomap.h>
#include <soc/pm.h>
-static const int gpio_debug = 0;
+static const struct reset_mapping rst_map[] = {
+ { .logical = PAD_CFG0_LOGICAL_RESET_RSMRST, .chipset = 0U << 30},
+ { .logical = PAD_CFG0_LOGICAL_RESET_DEEP, .chipset = 1U << 30},
+ { .logical = PAD_CFG0_LOGICAL_RESET_PLTRST, .chipset = 2U << 30},
+};
-/* There are 4 communities with 8 GPIO groups (GPP_[A:G] and GPD) */
-struct gpio_community {
- int port_id;
- /* Inclusive pads within the community. */
- gpio_t min;
- gpio_t max;
+static const struct reset_mapping rst_map_com2[] = {
+ { .logical = PAD_CFG0_LOGICAL_RESET_PWROK, .chipset = 0U << 30},
+ { .logical = PAD_CFG0_LOGICAL_RESET_DEEP, .chipset = 1U << 30},
+ { .logical = PAD_CFG0_LOGICAL_RESET_PLTRST, .chipset = 2U << 30},
+ { .logical = PAD_CFG0_LOGICAL_RESET_RSMRST, .chipset = 3U << 30},
};
-/* This is ordered to match ACPI and OS driver. */
-static const struct gpio_community communities[] = {
- {
- .port_id = PID_GPIOCOM0,
- .min = GPP_A0,
- .max = GPP_B23,
- },
+static const struct pad_community skl_gpio_communities[] = {
{
- .port_id = PID_GPIOCOM1,
- .min = GPP_C0,
+ .port = PID_GPIOCOM0,
+ .first_pad = GPP_A0,
+ .last_pad = GPP_B23,
+ .num_gpi_regs = NUM_GPIO_COM0_GPI_REGS,
+ .pad_cfg_base = PAD_CFG_BASE,
+ .host_own_reg_0 = HOSTSW_OWN_REG_0,
+ .gpi_smi_sts_reg_0 = GPI_SMI_STS_0,
+ .gpi_smi_en_reg_0 = GPI_SMI_EN_0,
+ .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
+ .name = "GPIO_COM0",
+ .acpi_path = "\\_SB.PCI0.GPIO",
+ .reset_map = rst_map,
+ .num_reset_vals = ARRAY_SIZE(rst_map),
+ }, {
+ .port = PID_GPIOCOM1,
+ .first_pad = GPP_C0,
#if IS_ENABLED(CONFIG_SKYLAKE_SOC_PCH_H)
- .max = GPP_H23,
+ .last_pad = GPP_H23,
#else
- .max = GPP_E23,
+ .last_pad = GPP_E23,
#endif
- },
- {
- .port_id = PID_GPIOCOM3,
+ .num_gpi_regs = NUM_GPIO_COM1_GPI_REGS,
+ .pad_cfg_base = PAD_CFG_BASE,
+ .host_own_reg_0 = HOSTSW_OWN_REG_0,
+ .gpi_smi_sts_reg_0 = GPI_SMI_STS_0,
+ .gpi_smi_en_reg_0 = GPI_SMI_EN_0,
+ .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
+ .name = "GPIO_COM1",
+ .acpi_path = "\\_SB.PCI0.GPIO",
+ .reset_map = rst_map,
+ .num_reset_vals = ARRAY_SIZE(rst_map),
+ }, {
+ .port = PID_GPIOCOM3,
#if IS_ENABLED(CONFIG_SKYLAKE_SOC_PCH_H)
- .min = GPP_I0,
- .max = GPP_I10,
+ .first_pad = GPP_I0,
+ .last_pad = GPP_I10,
#else
- .min = GPP_F0,
- .max = GPP_G7,
+ .first_pad = GPP_F0,
+ .last_pad = GPP_G7,
#endif
- },
- {
- .port_id = PID_GPIOCOM2,
- .min = GPD0,
- .max = GPD11,
- },
-};
-
-static const char *gpio_group_names[GPIO_NUM_GROUPS] = {
- "GPP_A",
- "GPP_B",
- "GPP_C",
- "GPP_D",
- "GPP_E",
- "GPP_F",
- "GPP_G",
-#if IS_ENABLED(CONFIG_SKYLAKE_SOC_PCH_H)
- "GPP_H",
- "GPP_I",
-#endif
- "GPD",
-};
-
-static inline void *gpio_community_regs(int port_id)
-{
- return pcr_reg_address(port_id, 0);
-}
-
-static inline size_t gpios_in_community(const struct gpio_community *comm)
-{
- /* max is inclusive */
- return comm->max - comm->min + 1;
-}
-
-static inline size_t groups_in_community(const struct gpio_community *comm)
-{
- size_t n = gpios_in_community(comm) + GPIO_MAX_NUM_PER_GROUP - 1;
- return n / GPIO_MAX_NUM_PER_GROUP;
-}
-
-static inline int gpio_index_gpd(gpio_t gpio)
-{
- if (gpio >= GPD0 && gpio <= GPD11)
- return 1;
- return 0;
-}
-
-static const struct gpio_community *gpio_get_community(gpio_t pad)
-{
- size_t i;
-
- for (i = 0; i < ARRAY_SIZE(communities); i++) {
- const struct gpio_community *c = &communities[i];
-
- if (pad >= c->min && pad <= c->max)
- return c;
+ .num_gpi_regs = NUM_GPIO_COM3_GPI_REGS,
+ .pad_cfg_base = PAD_CFG_BASE,
+ .host_own_reg_0 = HOSTSW_OWN_REG_0,
+ .gpi_smi_sts_reg_0 = GPI_SMI_STS_0,
+ .gpi_smi_en_reg_0 = GPI_SMI_EN_0,
+ .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
+ .name = "GPIO_COM3",
+ .acpi_path = "\\_SB.PCI0.GPIO",
+ .reset_map = rst_map,
+ .num_reset_vals = ARRAY_SIZE(rst_map),
+ }, {
+ .port = PID_GPIOCOM2,
+ .first_pad = GPD0,
+ .last_pad = GPD11,
+ .num_gpi_regs = NUM_GPIO_COM2_GPI_REGS,
+ .pad_cfg_base = PAD_CFG_BASE,
+ .host_own_reg_0 = HOSTSW_OWN_REG_0,
+ .gpi_smi_sts_reg_0 = GPI_SMI_STS_0,
+ .gpi_smi_en_reg_0 = GPI_SMI_EN_0,
+ .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
+ .name = "GPIO_COM2",
+ .acpi_path = "\\_SB.PCI0.GPIO",
+ .reset_map = rst_map_com2,
+ .num_reset_vals = ARRAY_SIZE(rst_map_com2),
}
+};
- return NULL;
-}
-
-static size_t community_clr_get_smi_sts(const struct gpio_community *comm,
- uint32_t *sts)
-{
- uint8_t *regs;
- size_t i;
- uint32_t *gpi_status_reg;
- uint32_t *gpi_en_reg;
- const size_t num_grps = groups_in_community(comm);
-
- /* Not all groups can be routed to SMI. However, the registers
- * read as 0. In order to simplify the logic read everything from
- * each community. */
- regs = gpio_community_regs(comm->port_id);
- gpi_status_reg = (void *)&regs[GPI_SMI_STS_OFFSET];
- gpi_en_reg = (void *)&regs[GPI_SMI_EN_OFFSET];
- for (i = 0; i < num_grps; i++) {
- sts[i] = read32(gpi_status_reg + i) & read32(gpi_en_reg + i);
- /* Clear the enabled and set status bits. */
- write32(gpi_status_reg + i, sts[i]);
- }
-
- return num_grps;
-}
-
-static void print_gpi_status(uint32_t status, const char *grp_name)
-{
- int i;
-
- if (!status)
- return;
-
- for (i = 31; i >= 0; i--) {
- if (status & (1 << i))
- printk(BIOS_DEBUG, "%s%d ", grp_name, i);
- }
-}
-
-void gpi_clear_get_smi_status(struct gpi_status *sts)
-{
- int i;
- int do_print;
- size_t sts_index = 0;
-
- for (i = 0; i < ARRAY_SIZE(communities); i++) {
- const struct gpio_community *comm = &communities[i];
- sts_index += community_clr_get_smi_sts(comm,
- &sts->grp[sts_index]);
- }
-
- do_print = 0;
- for (i = 0; i < ARRAY_SIZE(sts->grp); i++) {
- if (sts->grp[i] == 0)
- continue;
- do_print = 1;
- break;
- }
-
- if (!do_print)
- return;
-
- printk(BIOS_DEBUG, "GPI_SMI_STS: ");
- for (i = 0; i < ARRAY_SIZE(sts->grp); i++)
- print_gpi_status(sts->grp[i], gpio_group_names[i]);
- printk(BIOS_DEBUG, "\n");
-}
-
-int gpi_status_get(const struct gpi_status *sts, gpio_t gpi)
-{
- const uint32_t *gpi_sts;
-
- /* Check if valid gpi */
- if (gpio_get_community(gpi) == NULL)
- return 0;
-
- /* If not in GPD group the index is a linear function based on
- * GPI number and GPIO_MAX_NUM_PER_GROUP. */
- if (gpio_index_gpd(gpi))
- gpi_sts = &sts->grp[GPD];
- else
- gpi_sts = &sts->grp[gpi / GPIO_MAX_NUM_PER_GROUP];
-
- return !!(*gpi_sts & (1 << (gpi % GPIO_MAX_NUM_PER_GROUP)));
-}
-
-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 = gpio_community_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;
- uint8_t *regs;
- size_t pad_relative;
-
- comm = gpio_get_community(pad);
-
- if (comm == NULL)
- return NULL;
-
- regs = gpio_community_regs(comm->port_id);
-
- pad_relative = pad - comm->min;
-
- /* DW0 and DW1 regs are 4 bytes each. */
- return &regs[PAD_CFG_DW_OFFSET + pad_relative *
- GPIO_DWx_SIZE(GPIO_DWx_COUNT)];
-}
-
-static void *gpio_hostsw_reg(gpio_t pad, size_t *bit)
-{
- const struct gpio_community *comm;
- uint8_t *regs;
- size_t pad_relative;
-
- comm = gpio_get_community(pad);
-
- if (comm == NULL)
- return NULL;
-
- regs = gpio_community_regs(comm->port_id);
-
- pad_relative = pad - comm->min;
-
- /* Update the bit for this pad. */
- *bit = (pad_relative % HOSTSW_OWN_PADS_PER);
-
- /* HostSw regs are 4 bytes each. */
- regs = &regs[HOSTSW_OWN_REG_OFFSET];
- return &regs[(pad_relative / HOSTSW_OWN_PADS_PER) * 4];
-}
-
-static void gpio_handle_pad_mode(const struct pad_config *cfg)
-{
- size_t bit;
- uint32_t *hostsw_own_reg;
- uint32_t reg;
-
- bit = 0;
- hostsw_own_reg = gpio_hostsw_reg(cfg->pad, &bit);
-
- if (hostsw_own_reg == NULL)
- return;
-
- reg = read32(hostsw_own_reg);
- reg &= ~(1U << bit);
-
- if ((cfg->attrs & PAD_FIELD(HOSTSW, GPIO)) == PAD_FIELD(HOSTSW, GPIO))
- reg |= (HOSTSW_GPIO << bit);
- else
- reg |= (HOSTSW_ACPI << bit);
-
- write32(hostsw_own_reg, reg);
-}
-
-static void gpi_enable_smi(gpio_t pad)
-{
- const struct gpio_community *comm;
- uint8_t *regs;
- uint32_t *gpi_status_reg;
- uint32_t *gpi_en_reg;
- size_t group_offset;
- uint32_t pad_mask;
-
- comm = gpio_get_community(pad);
- if (comm == NULL)
- return;
- regs = gpio_community_regs(comm->port_id);
- gpi_status_reg = (void *)&regs[GPI_SMI_STS_OFFSET];
- gpi_en_reg = (void *)&regs[GPI_SMI_EN_OFFSET];
-
- /* Offset of SMI STS/EN for this pad's group within the community. */
- group_offset = (pad - comm->min) / GPIO_MAX_NUM_PER_GROUP;
-
- /* Clear status then set enable. */
- pad_mask = 1 << ((pad - comm->min) % GPIO_MAX_NUM_PER_GROUP);
- write32(&gpi_status_reg[group_offset], pad_mask);
- write32(&gpi_en_reg[group_offset],
- read32(&gpi_en_reg[group_offset]) | pad_mask);
-}
-
-static void gpio_configure_pad(const struct pad_config *cfg)
-{
- uint32_t *dw_regs;
- uint32_t reg;
- uint32_t dw0;
- uint32_t mask;
-
- dw_regs = gpio_dw_regs(cfg->pad);
-
- if (dw_regs == NULL)
- return;
-
- dw0 = cfg->dw0;
-
- write32(&dw_regs[0], dw0);
- reg = read32(&dw_regs[1]);
-
- /* Apply termination field */
- mask = PAD_TERM_MASK << PAD_TERM_SHIFT;
- reg &= ~mask;
- reg |= cfg->attrs & mask;
-
- /* Apply voltage tolerance field */
- mask = PAD_TOL_MASK << PAD_TOL_SHIFT;
- reg &= ~mask;
- reg |= cfg->attrs & mask;
- write32(&dw_regs[1], reg);
-
- gpio_handle_pad_mode(cfg);
-
- if ((dw0 & PAD_FIELD(GPIROUTSMI, MASK)) == PAD_FIELD(GPIROUTSMI, YES))
- gpi_enable_smi(cfg->pad);
-
- if (gpio_debug)
- printk(BIOS_DEBUG,
- "Write Pad: Base(%p) - conf0 = %x conf1= %x pad # = %d\n",
- &dw_regs[0], dw0, reg, cfg->pad);
-}
-
-void gpio_configure_pads(const struct pad_config *cfgs, size_t num)
-{
- size_t i;
-
- for (i = 0; i < num; i++)
- gpio_configure_pad(&cfgs[i]);
-}
-
-void gpio_input_pulldown(gpio_t gpio)
-{
- struct pad_config cfg = PAD_CFG_GPI(gpio, 5K_PD, DEEP);
- gpio_configure_pad(&cfg);
-}
-
-void gpio_input_pullup(gpio_t gpio)
-{
- struct pad_config cfg = PAD_CFG_GPI(gpio, 5K_PU, DEEP);
- gpio_configure_pad(&cfg);
-}
-
-void gpio_input(gpio_t gpio)
-{
- struct pad_config cfg = PAD_CFG_GPI(gpio, NONE, DEEP);
- gpio_configure_pad(&cfg);
-}
-
-void gpio_output(gpio_t gpio, int value)
-{
- struct pad_config cfg = PAD_CFG_GPO(gpio, value, DEEP);
- gpio_configure_pad(&cfg);
-}
-
-int gpio_get(gpio_t gpio_num)
-{
- uint32_t *dw_regs;
- uint32_t reg;
-
- dw_regs = gpio_dw_regs(gpio_num);
-
- if (dw_regs == NULL)
- return -1;
-
- reg = read32(&dw_regs[0]);
-
- return (reg >> GPIORXSTATE_SHIFT) & GPIORXSTATE_MASK;
-}
-
-void gpio_set(gpio_t gpio_num, int value)
-{
- uint32_t *dw_regs;
- uint32_t reg;
-
- dw_regs = gpio_dw_regs(gpio_num);
-
- if (dw_regs == NULL)
- return;
-
- reg = read32(&dw_regs[0]);
- reg &= ~PAD_FIELD(GPIOTXSTATE, MASK);
- reg |= PAD_FIELD_VAL(GPIOTXSTATE, value);
- write32(&dw_regs[0], reg);
- /* GPIO port ids support posted write semantics. */
-}
-
-const char *gpio_acpi_path(gpio_t gpio_num)
+const struct pad_community *soc_gpio_get_community(size_t *num_communities)
{
- return "\\_SB.PCI0.GPIO";
+ *num_communities = ARRAY_SIZE(skl_gpio_communities);
+ return skl_gpio_communities;
}
-uint16_t gpio_acpi_pin(gpio_t gpio_num)
+const struct pmc_to_gpio_route *soc_pmc_gpio_routes(size_t *num)
{
- return gpio_num;
+ static const struct pmc_to_gpio_route routes[] = {
+ { GPP_A, GPP_A},
+ { GPP_B, GPP_B},
+ { GPP_C, GPP_C},
+ { GPP_D, GPP_D},
+ { GPP_E, GPP_E},
+ { GPP_F, GPP_F},
+ { GPP_G, GPP_G},
+#if IS_ENABLED(CONFIG_SKYLAKE_SOC_PCH_H)
+ { GPP_H, GPP_H},
+ { GPP_I, GPP_I},
+#endif
+ { GPD, GPD},
+ };
+ *num = ARRAY_SIZE(routes);
+ return routes;
}