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>
This commit is contained in:
Simon Glass
2019-12-06 21:42:57 -07:00
committed by Bin Meng
parent 5690d5c8f8
commit 28eefefccf
4 changed files with 296 additions and 0 deletions

View File

@@ -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);