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

Andy Shevchenko andriy.shevchenko at linux.intel.com
Sun Mar 5 19:17:13 UTC 2017


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 at linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko at 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

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),
+};
-- 
2.11.0



More information about the U-Boot mailing list