diff mbox

[U-Boot,v1,2/2] misc: Introduce minimal PMU driver for Intel MID platforms

Message ID 20170305191713.49255-2-andriy.shevchenko@linux.intel.com
State Superseded
Delegated to: Bin Meng
Headers show

Commit Message

Andy Shevchenko March 5, 2017, 7:17 p.m. UTC
This simple PMU driver enables access to MMC controllers during probe
so tangier_sdhci can probe and be useful.

In the future it might be expanded to cover other Intel MID platforms,
that's why it's called intel_mid_pmu.c.

Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 arch/x86/Kconfig             |   2 +
 drivers/misc/Kconfig         |   6 +++
 drivers/misc/Makefile        |   1 +
 drivers/misc/intel_mid_pmu.c | 124 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 133 insertions(+)
 create mode 100644 drivers/misc/intel_mid_pmu.c

Comments

Simon Glass March 12, 2017, 8:21 p.m. UTC | #1
Hi Andy,

On 5 March 2017 at 12:17, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> This simple PMU driver enables access to MMC controllers during probe
> so tangier_sdhci can probe and be useful.
>
> In the future it might be expanded to cover other Intel MID platforms,
> that's why it's called intel_mid_pmu.c.
>
> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

Please consider my comments on the previous driver to apply to this one also.

One more thing - you cannot call device_probe() from the bind
function. That is breaking the rules.

Instead, it should be found by the first user, perhaps using syscon or
perhaps with a device_get_...() function, and that will automatically
probe it.

Regards,
Andy Shevchenko March 15, 2017, 6:01 p.m. UTC | #2
On Sun, Mar 12, 2017 at 10:21 PM, Simon Glass <sjg@chromium.org> wrote:
> Hi Andy,
>
> On 5 March 2017 at 12:17, Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
>> This simple PMU driver enables access to MMC controllers during probe
>> so tangier_sdhci can probe and be useful.
>>
>> In the future it might be expanded to cover other Intel MID platforms,
>> that's why it's called intel_mid_pmu.c.
>>
>> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
>> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>
> Please consider my comments on the previous driver to apply to this one also.
>
> One more thing - you cannot call device_probe() from the bind
> function. That is breaking the rules.
>
> Instead, it should be found by the first user, perhaps using syscon or
> perhaps with a device_get_...() function, and that will automatically
> probe it.

While SCU works fine with this model, PMU doesn't.
MMC  (sdhci) requires to power on controllers, it looks like device
can't be probed at that time (too early). What do you suggest to do?
Andy Shevchenko March 15, 2017, 6:14 p.m. UTC | #3
On Wed, Mar 15, 2017 at 8:01 PM, Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Sun, Mar 12, 2017 at 10:21 PM, Simon Glass <sjg@chromium.org> wrote:
>> Hi Andy,
>>
>> On 5 March 2017 at 12:17, Andy Shevchenko
>> <andriy.shevchenko@linux.intel.com> wrote:
>>> This simple PMU driver enables access to MMC controllers during probe
>>> so tangier_sdhci can probe and be useful.
>>>
>>> In the future it might be expanded to cover other Intel MID platforms,
>>> that's why it's called intel_mid_pmu.c.
>>>
>>> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
>>> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>>
>> Please consider my comments on the previous driver to apply to this one also.
>>
>> One more thing - you cannot call device_probe() from the bind
>> function. That is breaking the rules.
>>
>> Instead, it should be found by the first user, perhaps using syscon or
>> perhaps with a device_get_...() function, and that will automatically
>> probe it.
>
> While SCU works fine with this model, PMU doesn't.
> MMC  (sdhci) requires to power on controllers, it looks like device
> can't be probed at that time (too early). What do you suggest to do?

Whoof, found three mistakes - two typos in my code and an issue in
sdhci generic driver.

Works now.
diff mbox

Patch

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 6a747c332e..04310653bb 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -83,7 +83,9 @@  endchoice
 # subarchitectures-specific options below
 config INTEL_MID
 	bool "Intel MID platform support"
+	select MISC
 	select INTEL_SCU
+	select INTEL_MID_PMU
 	help
 	  Select to build a U-Boot capable of supporting Intel MID
 	  (Mobile Internet Device) platform systems which do not have
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 8d81f9c51c..0222a8beed 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -168,6 +168,12 @@  config I2C_EEPROM
 	help
 	  Enable a generic driver for EEPROMs attached via I2C.
 
+config INTEL_MID_PMU
+	bool "Support for PMU on Intel MID platforms"
+	depends on MISC
+	depends on INTEL_MID
+	default y
+
 config INTEL_SCU
 	bool "Enable support for SCU on Intel MID platforms"
 	depends on INTEL_MID
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 47551e44d6..98a58f241c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -51,4 +51,5 @@  obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
 obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o
 obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o
 obj-$(CONFIG_QFW) += qfw.o
+obj-$(CONFIG_INTEL_MID_PMU) += intel_mid_pmu.o
 obj-$(CONFIG_INTEL_SCU) += intel_scu_ipc.o
diff --git a/drivers/misc/intel_mid_pmu.c b/drivers/misc/intel_mid_pmu.c
new file mode 100644
index 0000000000..0eda3b4349
--- /dev/null
+++ b/drivers/misc/intel_mid_pmu.c
@@ -0,0 +1,124 @@ 
+/*
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/device.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <malloc.h>
+
+/* Registers */
+#define PM_STS  		0x00
+#define PM_CMD  		0x04
+#define PM_ICS  		0x08
+#define PM_WKC(x)		(0x10 + (x) * 4)
+#define PM_WKS(x)		(0x18 + (x) * 4)
+#define PM_SSC(x)		(0x20 + (x) * 4)
+#define PM_SSS(x)		(0x30 + (x) * 4)
+
+/* Bits in PM_STS */
+#define PM_STS_BUSY		(1 << 8)
+
+/* List of Intel Tangier LSSs */
+#define PMU_LSS_TANGIER_SDIO0_01	1
+
+struct pmu_mid {
+	void __iomem *ioaddr;
+};
+
+static unsigned int pmu_readl(void __iomem *base, unsigned int offset)
+{
+	return readl(base + offset);
+}
+
+static void pmu_writel(void __iomem *base, unsigned int offset,
+		unsigned int value)
+{
+	writel(value, base + offset);
+}
+
+static int pmu_read_status(struct pmu_mid *pmu)
+{
+	int retry = 500000;
+	u32 reg;
+
+	do {
+		reg = pmu_readl(pmu->ioaddr, PM_STS);
+		if (!(reg & PM_STS_BUSY))
+			return 0;
+
+		udelay(1);
+	} while (--retry);
+
+	printf("WARNING: PMU still busy\n");
+	return -EBUSY;
+}
+
+static int pmu_enable_mmc(struct pmu_mid *pmu)
+{
+	u32 pm_ssc0;
+	int ret;
+
+	/* Check PMU status */
+	ret = pmu_read_status(pmu);
+	if (ret)
+		return ret;
+
+	/* Read PMU values */
+	pm_ssc0 = pmu_readl(pmu->ioaddr, PM_SSS(0));
+
+	/* Modify PMU values */
+
+	/* Enable SDIO0, sdhci for SD card */
+	pm_ssc0 &= ~(0x3 << (PMU_LSS_TANGIER_SDIO0_01 * 2));
+
+	/* Write modified PMU values */
+	pmu_writel(pmu->ioaddr, PM_SSC(0), pm_ssc0);
+
+	/* Update modified PMU values */
+	pmu_writel(pmu->ioaddr, PM_CMD, 0x00002201);
+
+	/* Check PMU status */
+	return pmu_read_status(pmu);
+}
+
+static int pmu_mid_bind(struct udevice *dev)
+{
+	/* This device is needed straight away */
+	return device_probe(dev);
+}
+
+static int pmu_mid_probe(struct udevice *dev)
+{
+	struct pmu_mid	*pmu = dev_get_uclass_priv(dev);
+	fdt_addr_t	base;
+
+	base = dev_get_addr(dev);
+	if (base == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	pmu->ioaddr = devm_ioremap(dev, base, SZ_1K);
+	if (!pmu->ioaddr)
+		return -ENOMEM;
+
+	return pmu_enable_mmc(pmu);
+}
+
+static const struct udevice_id pmu_mid_match[] = {
+	{ .compatible = "intel,pmu-mid" },
+	{ .compatible = "intel,pmu-tangier" },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(intel_mid_pmu) = {
+	.name		= "intel_mid_pmu",
+	.id		= UCLASS_MISC,
+	.of_match	= pmu_mid_match,
+	.bind		= pmu_mid_bind,
+	.probe		= pmu_mid_probe,
+	.priv_auto_alloc_size = sizeof(struct pmu_mid),
+};