diff options
author | Simon Glass <sjg@chromium.org> | 2019-12-07 07:42:57 +0300 |
---|---|---|
committer | Bin Meng <bmeng.cn@gmail.com> | 2019-12-15 06:44:26 +0300 |
commit | 28eefefccfaa695fb44935ce8b04d50548d78b13 (patch) | |
tree | 39b1d8aa7406cd5beb2c360445f1e9cb1d9e52dd /drivers/power | |
parent | 5690d5c8f878846d862bd4a0256c2e8285413bff (diff) | |
download | u-boot-28eefefccfaa695fb44935ce8b04d50548d78b13.tar.xz |
x86: apl: Add PMC driver
Add a driver for the Apollo Lake SoC. It supports the basic operations and
can use device tree or of-platdata.
Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/acpi_pmc/acpi-pmc-uclass.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/drivers/power/acpi_pmc/acpi-pmc-uclass.c b/drivers/power/acpi_pmc/acpi-pmc-uclass.c index 653c71b948..d43de87126 100644 --- a/drivers/power/acpi_pmc/acpi-pmc-uclass.c +++ b/drivers/power/acpi_pmc/acpi-pmc-uclass.c @@ -9,6 +9,9 @@ #include <acpi_s3.h> #include <dm.h> #include <log.h> +#ifdef CONFIG_X86 +#include <asm/intel_pinctrl.h> +#endif #include <asm/io.h> #include <power/acpi_pmc.h> @@ -34,6 +37,59 @@ enum { TCO1_CNT_HLT = 1 << 11, }; +#ifdef CONFIG_X86 +static int gpe0_shift(struct acpi_pmc_upriv *upriv, int regnum) +{ + return upriv->gpe0_dwx_shift_base + regnum * 4; +} + +int pmc_gpe_init(struct udevice *dev) +{ + struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev); + struct udevice *itss; + u32 *dw; + u32 gpio_cfg_mask; + u32 gpio_cfg; + int ret, i; + u32 mask; + + if (device_get_uclass_id(dev) != UCLASS_ACPI_PMC) + return log_msg_ret("uclass", -EPROTONOSUPPORT); + dw = upriv->gpe0_dw; + mask = upriv->gpe0_dwx_mask; + gpio_cfg_mask = 0; + for (i = 0; i < upriv->gpe0_count; i++) { + gpio_cfg_mask |= mask << gpe0_shift(upriv, i); + if (dw[i] & ~mask) + return log_msg_ret("Base GPE0 value", -EINVAL); + } + + /* + * Route the GPIOs to the GPE0 block. Determine that all values + * are different and if they aren't, use the reset values. + */ + if (dw[0] == dw[1] || dw[1] == dw[2]) { + log_info("PMC: Using default GPE route"); + gpio_cfg = readl(upriv->gpe_cfg); + for (i = 0; i < upriv->gpe0_count; i++) + dw[i] = gpio_cfg >> gpe0_shift(upriv, i); + } else { + gpio_cfg = 0; + for (i = 0; i < upriv->gpe0_count; i++) + gpio_cfg |= dw[i] << gpe0_shift(upriv, i); + clrsetbits_le32(upriv->gpe_cfg, gpio_cfg_mask, gpio_cfg); + } + + /* Set the routes in the GPIO communities as well */ + ret = uclass_first_device_err(UCLASS_IRQ, &itss); + if (ret) + return log_msg_ret("Cannot find itss", ret); + pinctrl_route_gpe(itss, dw[0], dw[1], dw[2]); + + return 0; +} +#endif /* CONFIG_X86 */ + static void pmc_fill_pm_reg_info(struct udevice *dev) { struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev); |