Message ID | 20170401132134.62092-3-andriy.shevchenko@linux.intel.com |
---|---|
State | Accepted |
Delegated to: | Bin Meng |
Headers | show |
Hi Andy, On 1 April 2017 at 07:21, Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote: > This simple PMU driver allows to tyrn power on and off for selected > devices. In particularly Intel Tangier needs to power on SDHCI > controllers in order to access to them during board initialization. > > In the future it might be expanded to cover other Intel MID platforms, > that's why it's located under arch/x86/lib and called pmu.c. > > Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com> > Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> > --- > arch/x86/include/asm/cpu.h | 1 + > arch/x86/include/asm/pmu.h | 11 +++++ > arch/x86/lib/Makefile | 1 + > arch/x86/lib/pmu.c | 117 +++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 130 insertions(+) > create mode 100644 arch/x86/include/asm/pmu.h > create mode 100644 arch/x86/lib/pmu.c Reviewed-by: Simon Glass <sjg@chromium.org> Have you considered making this a PMIC driver? Then you could avoid exporting the function. Also I see that we need to do that sometimes with Intel platforms.
On Thu, Apr 6, 2017 at 11:44 AM, Simon Glass <sjg@chromium.org> wrote: > Hi Andy, > > On 1 April 2017 at 07:21, Andy Shevchenko > <andriy.shevchenko@linux.intel.com> wrote: >> This simple PMU driver allows to tyrn power on and off for selected >> devices. In particularly Intel Tangier needs to power on SDHCI >> controllers in order to access to them during board initialization. >> >> In the future it might be expanded to cover other Intel MID platforms, >> that's why it's located under arch/x86/lib and called pmu.c. >> >> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com> >> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> >> --- >> arch/x86/include/asm/cpu.h | 1 + >> arch/x86/include/asm/pmu.h | 11 +++++ >> arch/x86/lib/Makefile | 1 + >> arch/x86/lib/pmu.c | 117 +++++++++++++++++++++++++++++++++++++++++++++ >> 4 files changed, 130 insertions(+) >> create mode 100644 arch/x86/include/asm/pmu.h >> create mode 100644 arch/x86/lib/pmu.c > > Reviewed-by: Simon Glass <sjg@chromium.org> > > Have you considered making this a PMIC driver? Then you could avoid > exporting the function. Also I see that we need to do that sometimes > with Intel platforms. applied to u-boot-x86, thanks!
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index 0ee13b1eb1..c00687a20a 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -54,6 +54,7 @@ enum { X86_NONE, X86_SYSCON_ME, /* Intel Management Engine */ X86_SYSCON_PINCONF, /* Intel x86 pin configuration */ + X86_SYSCON_PMU, /* Power Management Unit */ X86_SYSCON_SCU, /* System Controller Unit */ }; diff --git a/arch/x86/include/asm/pmu.h b/arch/x86/include/asm/pmu.h new file mode 100644 index 0000000000..96b968ff8f --- /dev/null +++ b/arch/x86/include/asm/pmu.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef _X86_ASM_PMU_IPC_H_ +#define _X86_ASM_PMU_IPC_H_ + +int pmu_turn_power(unsigned int lss, bool on); + +#endif /* _X86_ASM_PMU_IPC_H_ */ diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 320e45e4a0..d1ad37af64 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -31,6 +31,7 @@ obj-y += pinctrl_ich6.o obj-y += pirq_routing.o obj-y += relocate.o obj-y += physmem.o +obj-$(CONFIG_INTEL_MID) += pmu.o obj-$(CONFIG_X86_RAMTEST) += ramtest.o obj-$(CONFIG_INTEL_MID) += scu.o obj-y += sections.o diff --git a/arch/x86/lib/pmu.c b/arch/x86/lib/pmu.c new file mode 100644 index 0000000000..4ceab8dc64 --- /dev/null +++ b/arch/x86/lib/pmu.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <dm.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/cpu.h> +#include <asm/pmu.h> +#include <linux/errno.h> +#include <linux/io.h> + +/* Registers */ +struct pmu_regs { + u32 sts; + u32 cmd; + u32 ics; + u32 reserved; + u32 wkc[4]; + u32 wks[4]; + u32 ssc[4]; + u32 sss[4]; +}; + +/* Bits in PMU_REGS_STS */ +#define PMU_REGS_STS_BUSY (1 << 8) + +struct pmu_mid { + struct pmu_regs *regs; +}; + +static int pmu_read_status(struct pmu_regs *regs) +{ + int retry = 500000; + u32 val; + + do { + val = readl(®s->sts); + if (!(val & PMU_REGS_STS_BUSY)) + return 0; + + udelay(1); + } while (--retry); + + printf("WARNING: PMU still busy\n"); + return -EBUSY; +} + +static int pmu_power_lss(struct pmu_regs *regs, unsigned int lss, bool on) +{ + unsigned int offset = (lss * 2) / 32; + unsigned int shift = (lss * 2) % 32; + u32 ssc; + int ret; + + /* Check PMU status */ + ret = pmu_read_status(regs); + if (ret) + return ret; + + /* Read PMU values */ + ssc = readl(®s->sss[offset]); + + /* Modify PMU values */ + if (on) + ssc &= ~(0x3 << shift); /* D0 */ + else + ssc |= 0x3 << shift; /* D3hot */ + + /* Write modified PMU values */ + writel(ssc, ®s->ssc[offset]); + + /* Update modified PMU values */ + writel(0x00002201, ®s->cmd); + + /* Check PMU status */ + return pmu_read_status(regs); +} + +int pmu_turn_power(unsigned int lss, bool on) +{ + struct pmu_mid *pmu; + struct udevice *dev; + int ret; + + ret = syscon_get_by_driver_data(X86_SYSCON_PMU, &dev); + if (ret) + return ret; + + pmu = dev_get_priv(dev); + + return pmu_power_lss(pmu->regs, lss, on); +} + +static int pmu_mid_probe(struct udevice *dev) +{ + struct pmu_mid *pmu = dev_get_priv(dev); + + pmu->regs = syscon_get_first_range(X86_SYSCON_PMU); + + return 0; +} + +static const struct udevice_id pmu_mid_match[] = { + { .compatible = "intel,pmu-mid", .data = X86_SYSCON_PMU }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(intel_mid_pmu) = { + .name = "pmu_mid", + .id = UCLASS_SYSCON, + .of_match = pmu_mid_match, + .probe = pmu_mid_probe, + .priv_auto_alloc_size = sizeof(struct pmu_mid), +};