From 1760cd3eb44ad123b6d3e3e295cdbf43f9465db1 Mon Sep 17 00:00:00 2001 From: Hannah Williams Date: Thu, 6 Apr 2017 20:54:11 -0700 Subject: soc/intel/skylake: Use common/block/gpio Other than switch to use common gpio implementation for skylake based platform, also apply the needed changes for purism board. Change-Id: I06e06dbcb6d0d6fe277dfad57b82aca51f94b099 Signed-off-by: Hannah Williams Signed-off-by: Lijian Zhao Reviewed-on: https://review.coreboot.org/19201 Tested-by: build bot (Jenkins) Reviewed-by: Youness Alaoui Reviewed-by: Aaron Durbin --- src/soc/intel/skylake/gpio.c | 492 ++++++++----------------------------------- 1 file changed, 93 insertions(+), 399 deletions(-) (limited to 'src/soc/intel/skylake/gpio.c') 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 -#include -#include -#include -#include -#include -#include +#include +#include #include #include -#include #include -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 *)®s[GPI_SMI_STS_OFFSET]; - gpi_en_reg = (void *)®s[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 ®s[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 = ®s[HOSTSW_OWN_REG_OFFSET]; - return ®s[(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 *)®s[GPI_SMI_STS_OFFSET]; - gpi_en_reg = (void *)®s[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; } -- cgit v1.2.3