diff --git a/src/soc/intel/skylake/chip.h b/src/soc/intel/skylake/chip.h index 96389a9471..873342ae47 100644 --- a/src/soc/intel/skylake/chip.h +++ b/src/soc/intel/skylake/chip.h @@ -19,14 +19,16 @@ * Foundation, Inc. */ -#include -#include -#include -#include #ifndef _SOC_CHIP_H_ #define _SOC_CHIP_H_ +#include +#include +#include +#include +#include + struct soc_intel_skylake_config { /* * Interrupt Routing configuration @@ -42,10 +44,15 @@ struct soc_intel_skylake_config { uint8_t pirqh_routing; /* GPE configuration */ - uint32_t gpe0_en_1; - uint32_t gpe0_en_2; - uint32_t gpe0_en_3; - uint32_t gpe0_en_4; + uint32_t gpe0_en_1; /* GPE0_EN_31_0 */ + uint32_t gpe0_en_2; /* GPE0_EN_63_32 */ + uint32_t gpe0_en_3; /* GPE0_EN_95_64 */ + uint32_t gpe0_en_4; /* GPE0_EN_127_96 / GPE_STD */ + /* Gpio group routed to each dword of the GPE0 block. Values are + * of the form GPP_[A:G] or GPD. */ + uint8_t gpe0_dw0; /* GPE0_31_0 STS/EN */ + uint8_t gpe0_dw1; /* GPE0_63_32 STS/EN */ + uint8_t gpe0_dw2; /* GPE0_95_64 STS/EN */ /* GPIO SMI configuration */ uint32_t ec_smi_gpio; diff --git a/src/soc/intel/skylake/gpio.c b/src/soc/intel/skylake/gpio.c index 28ed07ebd3..18638873f7 100644 --- a/src/soc/intel/skylake/gpio.c +++ b/src/soc/intel/skylake/gpio.c @@ -71,6 +71,29 @@ static const struct gpio_community *gpio_get_community(gpio_t pad) return NULL; } +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 = pcr_port_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; diff --git a/src/soc/intel/skylake/include/soc/gpio.h b/src/soc/intel/skylake/include/soc/gpio.h index a7d9158ed5..321f04c5d3 100644 --- a/src/soc/intel/skylake/include/soc/gpio.h +++ b/src/soc/intel/skylake/include/soc/gpio.h @@ -43,6 +43,15 @@ void gpio_enable_all_smi(void); /* Enable GPIO individual Group SMI */ void gpio_enable_groupsmi(gpio_t gpio_num, u32 mask); +/* + * Set the GPIO groups for the GPE blocks. The gpe0_route is interpreted + * as the packed configuration for GPE0_DW[2:0]: + * dw0 = gpe0_route[3:0] + * dw1 = gpe0_route[7:4] + * dw2 = gpe0_route[11:8]. + */ +void gpio_route_gpe(uint16_t gpe0_route); + /* Configure the pads according to the pad_config array. */ struct pad_config; void gpio_configure_pads(const struct pad_config *cfgs, size_t num); diff --git a/src/soc/intel/skylake/include/soc/gpio_defs.h b/src/soc/intel/skylake/include/soc/gpio_defs.h index 625acdb74e..09f50199f6 100644 --- a/src/soc/intel/skylake/include/soc/gpio_defs.h +++ b/src/soc/intel/skylake/include/soc/gpio_defs.h @@ -20,6 +20,23 @@ #ifndef _SOC_GPIO_DEFS_H_ #define _SOC_GPIO_DEFS_H_ +/* + * There are 8 GPIO groups. GPP_A -> GPP_G and GPD. GPD is the special case + * where that group is not so generic. So most of the fixed numbers and macros + * are based on the GPP groups. The GPIO groups are accessed through register + * blocks called communities. + */ +#define GPP_A 0 +#define GPP_B 1 +#define GPP_C 2 +#define GPP_D 3 +#define GPP_E 4 +#define GPP_F 5 +#define GPP_G 6 +#define GPD 7 +#define GPIO_NUM_GROUPS 8 +#define GPIO_MAX_NUM_PER_GROUP 24 + /* * GPIOs are ordered monotonically increasing to match ACPI/OS driver. */ @@ -375,6 +392,12 @@ #define GPD11_IRQ 0x5b /* Register defines. */ +#define MISCCFG_OFFSET 0x10 +#define GPIO_DRIVER_IRQ_ROUTE_MASK 8 +#define GPIO_DRIVER_IRQ_ROUTE_IRQ14 0 +#define GPIO_DRIVER_IRQ_ROUTE_IRQ15 8 +#define GPE_DW_SHIFT 8 +#define GPE_DW_MASK 0xfff00 #define PAD_OWN_REG_OFFSET 0x20 #define PAD_OWN_PADS_PER 8 #define PAD_OWN_WIDTH_PER 4 @@ -476,9 +499,9 @@ #define PAD_TERM_667_PU 13 #define PAD_TERM_NATIVE 15 -#define MISCCFG_OFFSET 0x10 -#define GPIO_DRIVER_IRQ_ROUTE_MASK 8 -#define GPIO_DRIVER_IRQ_ROUTE_IRQ14 0 -#define GPIO_DRIVER_IRQ_ROUTE_IRQ15 8 +#define GPI_GPE_STS_OFFSET 0x140 +#define GPI_GPE_EN_OFFSET 0x160 +#define GPI_SMI_STS_OFFSET 0x180 +#define GPI_SMI_EN_OFFSET 0x1a0 #endif /* _SOC_GPIO_DEFS_H_ */ diff --git a/src/soc/intel/skylake/include/soc/pmc.h b/src/soc/intel/skylake/include/soc/pmc.h index 5774d46a4b..9c9b175285 100644 --- a/src/soc/intel/skylake/include/soc/pmc.h +++ b/src/soc/intel/skylake/include/soc/pmc.h @@ -91,6 +91,11 @@ #define DSX_EN_LAN_WAKE_PIN (1 << 0) #define PMSYNC_TPR_CFG 0xc4 #define PMSYNC_LOCK (1 << 31) +#define GPIO_CFG 0x120 +#define GPE0_DWX_MASK 0xf +#define GPE0_DW0_SHIFT 0 +#define GPE0_DW1_SHIFT 4 +#define GPE0_DW2_SHIFT 8 #define GBLRST_CAUSE0 0x124 #define GBLRST_CAUSE1 0x128 diff --git a/src/soc/intel/skylake/pmc.c b/src/soc/intel/skylake/pmc.c index 2c794cabea..b6c35ebb4f 100644 --- a/src/soc/intel/skylake/pmc.c +++ b/src/soc/intel/skylake/pmc.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -147,6 +148,42 @@ static void pch_rtc_init(void) #endif } +static void pmc_gpe_init(config_t *config) +{ + uint8_t *pmc_regs; + uint32_t gpio_cfg; + uint32_t gpio_cfg_reg; + const uint32_t gpio_cfg_mask = + (GPE0_DWX_MASK << GPE0_DW0_SHIFT) | + (GPE0_DWX_MASK << GPE0_DW1_SHIFT) | + (GPE0_DWX_MASK << GPE0_DW2_SHIFT); + + pmc_regs = pmc_mmio_regs(); + gpio_cfg = 0; + + /* Route the GPIOs to the GPE0 block. Determine that all values + * are different, and if they aren't use the reset values. */ + if (config->gpe0_dw0 == config->gpe0_dw1 || + config->gpe0_dw1 == config->gpe0_dw2) { + printk(BIOS_INFO, "PMC: Using default GPE route.\n"); + gpio_cfg = read32(pmc_regs + GPIO_CFG); + } else { + gpio_cfg |= (uint32_t)config->gpe0_dw0 << GPE0_DW0_SHIFT; + gpio_cfg |= (uint32_t)config->gpe0_dw1 << GPE0_DW1_SHIFT; + gpio_cfg |= (uint32_t)config->gpe0_dw2 << GPE0_DW2_SHIFT; + } + gpio_cfg_reg = read32(pmc_regs + GPIO_CFG) & ~gpio_cfg_mask; + gpio_cfg_reg |= gpio_cfg & gpio_cfg_mask; + write32(pmc_regs + GPIO_CFG, gpio_cfg_reg); + + /* Set the routes in the GPIO communities as well. */ + gpio_route_gpe(gpio_cfg_reg >> GPE0_DW0_SHIFT); + + /* Set GPE enables based on devictree. */ + enable_all_gpe(config->gpe0_en_1, config->gpe0_en_2, + config->gpe0_en_3, config->gpe0_en_4); +} + static void pch_power_options(void) { u16 reg16; @@ -187,9 +224,9 @@ static void pch_power_options(void) } pci_write_config16(dev, GEN_PMCON_B, reg16); printk(BIOS_INFO, "Set power %s after power failure.\n", state); - /* GPE setup based on device tree configuration */ - enable_all_gpe(config->gpe0_en_1, config->gpe0_en_2, - config->gpe0_en_3, config->gpe0_en_4); + + /* Set up GPE configuration. */ + pmc_gpe_init(config); /* SMI setup based on device tree configuration */ enable_alt_smi(config->ec_smi_gpio, config->alt_gp_smi_en);