diff options
author | Duncan Laurie <dlaurie@chromium.org> | 2016-09-19 12:02:54 -0700 |
---|---|---|
committer | Duncan Laurie <dlaurie@chromium.org> | 2016-09-19 19:03:34 -0700 |
commit | 5e3dad66227bba4be9365ee76d00231bb5577b56 (patch) | |
tree | d37e1d608326d34fbc9fd85f514cbbd437323a77 /src/soc/intel/apollolake/pmutil.c | |
parent | 884dfe632940b940df68d09f997fa5cd25121def (diff) |
soc/intel/apollolake: Initialize GPEs in bootblock
Initialize the GPEs from mainboard config in bootblock, so they
can be used in verstage to query latched interrupt status.
I still left it called in ramstage just to be sure that the
configuration was not overwritten in FSP stages.
Tested by reading and reporting GPE status in a loop in verstage
and manually triggering an interrupt on EC console.
BUG=chrome-os-partner:53336
Change-Id: I1af3e9ac1e5c59b9ebb5c6dd1599309c1f036581
Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Diffstat (limited to 'src/soc/intel/apollolake/pmutil.c')
-rw-r--r-- | src/soc/intel/apollolake/pmutil.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/src/soc/intel/apollolake/pmutil.c b/src/soc/intel/apollolake/pmutil.c index 39edc45886..2aef18c8e6 100644 --- a/src/soc/intel/apollolake/pmutil.c +++ b/src/soc/intel/apollolake/pmutil.c @@ -29,6 +29,7 @@ #include <device/device.h> #include <device/pci.h> #include <vboot/vboot_common.h> +#include "chip.h" static uintptr_t read_pmc_mmio_bar(void) { @@ -462,3 +463,60 @@ void poweroff(void) if (!ENV_SMM) halt(); } + +void pmc_gpe_init(void) +{ + uint32_t gpio_cfg = 0; + uint32_t gpio_cfg_reg; + uint8_t dw1, dw2, dw3; + ROMSTAGE_CONST struct soc_intel_apollolake_config *config; + + /* Look up the device in devicetree */ + ROMSTAGE_CONST struct device *dev = dev_find_slot(0, NB_DEVFN); + if (!dev || !dev->chip_info) { + printk(BIOS_ERR, "BUG! Could not find SOC devicetree config\n"); + return; + } + config = dev->chip_info; + + uintptr_t pmc_bar = get_pmc_mmio_bar(); + + const uint32_t gpio_cfg_mask = + (GPE0_DWX_MASK << GPE0_DW1_SHIFT) | + (GPE0_DWX_MASK << GPE0_DW2_SHIFT) | + (GPE0_DWX_MASK << GPE0_DW3_SHIFT); + + /* Assign to local variable */ + dw1 = config->gpe0_dw1; + dw2 = config->gpe0_dw2; + dw3 = config->gpe0_dw3; + + /* Making sure that bad values don't bleed into the other fields */ + dw1 &= GPE0_DWX_MASK; + dw2 &= GPE0_DWX_MASK; + dw3 &= GPE0_DWX_MASK; + + /* Route the GPIOs to the GPE0 block. Determine that all values + * are different, and if they aren't use the reset values. + * DW0 is reserved/unused */ + if (dw1 == dw2 || dw2 == dw3) { + printk(BIOS_INFO, "PMC: Using default GPE route.\n"); + gpio_cfg = read32((void *)pmc_bar + GPIO_GPE_CFG); + + dw1 = (gpio_cfg >> GPE0_DW1_SHIFT) & GPE0_DWX_MASK; + dw2 = (gpio_cfg >> GPE0_DW2_SHIFT) & GPE0_DWX_MASK; + dw3 = (gpio_cfg >> GPE0_DW3_SHIFT) & GPE0_DWX_MASK; + } else { + gpio_cfg |= (uint32_t)dw1 << GPE0_DW1_SHIFT; + gpio_cfg |= (uint32_t)dw2 << GPE0_DW2_SHIFT; + gpio_cfg |= (uint32_t)dw3 << GPE0_DW3_SHIFT; + } + + gpio_cfg_reg = read32((void *)pmc_bar + GPIO_GPE_CFG) & ~gpio_cfg_mask; + gpio_cfg_reg |= gpio_cfg & gpio_cfg_mask; + + write32((void *)pmc_bar + GPIO_GPE_CFG, gpio_cfg_reg); + + /* Set the routes in the GPIO communities as well. */ + gpio_route_gpe(dw1, dw2, dw3); +} |