summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2019-12-06 21:42:57 -0700
committerBin Meng <bmeng.cn@gmail.com>2019-12-15 11:44:26 +0800
commit28eefefccfaa695fb44935ce8b04d50548d78b13 (patch)
tree39b1d8aa7406cd5beb2c360445f1e9cb1d9e52dd /drivers/power
parent5690d5c8f878846d862bd4a0256c2e8285413bff (diff)
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.c56
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);