All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/7] i.MX6 PU power domain support
@ 2014-02-13 14:39 ` Philipp Zabel
  0 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Rob Herring, Mark Rutland, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Philipp Zabel

The i.MX6Q can gate off the CPU and PU (GPU/VPU) power domains using the
Power Gating Controller (PGC) in the GPC register space. The CPU power
domain is already handled by wait state code, but the PU power domain can
be controlled using the generic power domain framework and power off the PU
supply regulator if all devices in the power domain are (runtime) suspended.

This patchset adds a GPC platform device initialized at subsys_initcall time
(after anatop regulators) that binds to the gpc device tree node and sets up
the PU power domain:

	gpc: gpc@020dc000 {
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "fsl,imx6q-gpc";
		reg = <0x020dc000 0x4000>;
		interrupts = <0 89 0x04 0 90 0x04>;
		pu-supply = <&reg_pu>;

		pd_pu: pu-power-domain@020dc260 {
			compatible = "fsl,imx6q-power-domain";
			reg = <0x020dc260 0x10>;
		};

		pd_arm: cpu-power-domain@020dc2a0 {
			compatible = "fsl,imx6q-power-domain";
			reg = <0x020dc2a0 0x10>;
		};
	};

The cpu-power-domain node is included for completeness' sake, it is not
currently used by the code.
It registers a platform bus notifier so that it can add GPU and VPU devices
to the power domain when they are bound. If finds devices to be added to the
power domain by scanning the device tree for nodes that contain a
	power-domain = <&pd_pu>;
property.

For i.MX6QDL there is only one power domain that can be disabled at runtime,
on i.MX6SL there is an additional DISPLAY power domain, which is not yet
handled by the code.

Changes since v1:
 - Added device tree binding documentation
 - Removed a superfluous comment in gpc.c
 - Changed the power domain compatible to be less generic
 - Link PU domain with its DT node, check for PU domain in bus notifier
 - Turn off the PU power domain on boot
 - Renamed power-domain node to pu-power-domain and added cpu-power-domain
   for i.MX6QDL
 - Added dts patch for i.MX6SL

regards
Philipp

Philipp Zabel (7):
  Documentation: Add device tree bindings for Freescale i.MX GPC
  ARM: imx6: gpc: Add PU power domain for GPU/VPU
  ARM: imx6: gpc: Add pm clock support to PU power domain
  ARM: imx6: gpc: Add observed worst case latencies
  ARM: dts: imx6qdl: Allow disabling the PU regulator, add a enable ramp
    delay
  ARM: dts: imx6qdl: Add power-domain information to gpc node
  ARM: dts: imx6sl: Add power-domain information to gpc node

 .../devicetree/bindings/power/fsl,imx-gpc.txt      |  61 +++++
 arch/arm/boot/dts/imx6qdl.dtsi                     |  16 +-
 arch/arm/boot/dts/imx6sl.dtsi                      |  18 ++
 arch/arm/mach-imx/Kconfig                          |   2 +
 arch/arm/mach-imx/gpc.c                            | 253 +++++++++++++++++++++
 5 files changed, 349 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/power/fsl,imx-gpc.txt

-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 0/7] i.MX6 PU power domain support
@ 2014-02-13 14:39 ` Philipp Zabel
  0 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

The i.MX6Q can gate off the CPU and PU (GPU/VPU) power domains using the
Power Gating Controller (PGC) in the GPC register space. The CPU power
domain is already handled by wait state code, but the PU power domain can
be controlled using the generic power domain framework and power off the PU
supply regulator if all devices in the power domain are (runtime) suspended.

This patchset adds a GPC platform device initialized at subsys_initcall time
(after anatop regulators) that binds to the gpc device tree node and sets up
the PU power domain:

	gpc: gpc at 020dc000 {
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "fsl,imx6q-gpc";
		reg = <0x020dc000 0x4000>;
		interrupts = <0 89 0x04 0 90 0x04>;
		pu-supply = <&reg_pu>;

		pd_pu: pu-power-domain at 020dc260 {
			compatible = "fsl,imx6q-power-domain";
			reg = <0x020dc260 0x10>;
		};

		pd_arm: cpu-power-domain at 020dc2a0 {
			compatible = "fsl,imx6q-power-domain";
			reg = <0x020dc2a0 0x10>;
		};
	};

The cpu-power-domain node is included for completeness' sake, it is not
currently used by the code.
It registers a platform bus notifier so that it can add GPU and VPU devices
to the power domain when they are bound. If finds devices to be added to the
power domain by scanning the device tree for nodes that contain a
	power-domain = <&pd_pu>;
property.

For i.MX6QDL there is only one power domain that can be disabled at runtime,
on i.MX6SL there is an additional DISPLAY power domain, which is not yet
handled by the code.

Changes since v1:
 - Added device tree binding documentation
 - Removed a superfluous comment in gpc.c
 - Changed the power domain compatible to be less generic
 - Link PU domain with its DT node, check for PU domain in bus notifier
 - Turn off the PU power domain on boot
 - Renamed power-domain node to pu-power-domain and added cpu-power-domain
   for i.MX6QDL
 - Added dts patch for i.MX6SL

regards
Philipp

Philipp Zabel (7):
  Documentation: Add device tree bindings for Freescale i.MX GPC
  ARM: imx6: gpc: Add PU power domain for GPU/VPU
  ARM: imx6: gpc: Add pm clock support to PU power domain
  ARM: imx6: gpc: Add observed worst case latencies
  ARM: dts: imx6qdl: Allow disabling the PU regulator, add a enable ramp
    delay
  ARM: dts: imx6qdl: Add power-domain information to gpc node
  ARM: dts: imx6sl: Add power-domain information to gpc node

 .../devicetree/bindings/power/fsl,imx-gpc.txt      |  61 +++++
 arch/arm/boot/dts/imx6qdl.dtsi                     |  16 +-
 arch/arm/boot/dts/imx6sl.dtsi                      |  18 ++
 arch/arm/mach-imx/Kconfig                          |   2 +
 arch/arm/mach-imx/gpc.c                            | 253 +++++++++++++++++++++
 5 files changed, 349 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/power/fsl,imx-gpc.txt

-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 1/7] Documentation: Add device tree bindings for Freescale i.MX GPC
  2014-02-13 14:39 ` Philipp Zabel
@ 2014-02-13 14:39     ` Philipp Zabel
  -1 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Rob Herring, Mark Rutland, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Philipp Zabel

The i.MX6 contains a power controller that controls power gating and
sequencing for the SoC's power domains.

Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
 .../devicetree/bindings/power/fsl,imx-gpc.txt      | 61 ++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/fsl,imx-gpc.txt

diff --git a/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt b/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt
new file mode 100644
index 0000000..3ec8c0e
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt
@@ -0,0 +1,61 @@
+Freescale i.MX General Power Controller
+=======================================
+
+The i.MX6Q General Power Control (GPC) block contains DVFS load tracking
+counters and Power Gating Control (PGC) for the CPU and PU (GPU/VPU) power
+domains.
+
+Required properties:
+- compatible: Should be "fsl,imx6q-gpc"
+- reg: should be register base and length as documented in the
+  datasheet
+- interrupts: Should contain GPC interrupt request 1
+- pu-supply: Link to the LDO regulator powering the PU power domain
+- #address-cells, #size-cells: Should be <1>
+
+The gpc node should contain 'power-domain' subnodes for each power domain.
+These serve as phandle targets for devices belonging to the power domain:
+
+Power domains controlled by a PGC register set
+==============================================
+
+Required properties:
+- compatible: Should be "fsl,imx6q-power-domain"
+- reg: should be register base and length as documented in the
+  datasheet
+
+Specifying power domain for IP modules
+======================================
+
+IP cores belonging to a power domain should contain a 'power-domain' property
+that is a phandle pointing to the power-domain subnode of the gpc device node.
+
+Required properties:
+- power-domain: A phandle pointing to the power-domain device tree node
+
+
+Example:
+
+	gpc: gpc@020dc000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "fsl,imx6q-gpc";
+		reg = <0x020dc000 0x4000>;
+		interrupts = <0 89 0x04 0 90 0x04>;
+		pu-supply = <&reg_pu>;
+
+		pd_pu: power-domain@020dc260 {
+			compatible = "fsl,imx6q-power-domain";
+			reg = <0x020dc260 0x10>;
+		};
+	};
+
+Example of a device that is part of a power domain:
+
+	vpu: vpu@02040000 {
+		reg = <0x02040000 0x3c000>;
+		/* ... */
+		power-domain = <&pd_pu>;
+		/* ... */
+	};
+
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 1/7] Documentation: Add device tree bindings for Freescale i.MX GPC
@ 2014-02-13 14:39     ` Philipp Zabel
  0 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

The i.MX6 contains a power controller that controls power gating and
sequencing for the SoC's power domains.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
 .../devicetree/bindings/power/fsl,imx-gpc.txt      | 61 ++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/fsl,imx-gpc.txt

diff --git a/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt b/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt
new file mode 100644
index 0000000..3ec8c0e
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt
@@ -0,0 +1,61 @@
+Freescale i.MX General Power Controller
+=======================================
+
+The i.MX6Q General Power Control (GPC) block contains DVFS load tracking
+counters and Power Gating Control (PGC) for the CPU and PU (GPU/VPU) power
+domains.
+
+Required properties:
+- compatible: Should be "fsl,imx6q-gpc"
+- reg: should be register base and length as documented in the
+  datasheet
+- interrupts: Should contain GPC interrupt request 1
+- pu-supply: Link to the LDO regulator powering the PU power domain
+- #address-cells, #size-cells: Should be <1>
+
+The gpc node should contain 'power-domain' subnodes for each power domain.
+These serve as phandle targets for devices belonging to the power domain:
+
+Power domains controlled by a PGC register set
+==============================================
+
+Required properties:
+- compatible: Should be "fsl,imx6q-power-domain"
+- reg: should be register base and length as documented in the
+  datasheet
+
+Specifying power domain for IP modules
+======================================
+
+IP cores belonging to a power domain should contain a 'power-domain' property
+that is a phandle pointing to the power-domain subnode of the gpc device node.
+
+Required properties:
+- power-domain: A phandle pointing to the power-domain device tree node
+
+
+Example:
+
+	gpc: gpc at 020dc000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "fsl,imx6q-gpc";
+		reg = <0x020dc000 0x4000>;
+		interrupts = <0 89 0x04 0 90 0x04>;
+		pu-supply = <&reg_pu>;
+
+		pd_pu: power-domain at 020dc260 {
+			compatible = "fsl,imx6q-power-domain";
+			reg = <0x020dc260 0x10>;
+		};
+	};
+
+Example of a device that is part of a power domain:
+
+	vpu: vpu at 02040000 {
+		reg = <0x02040000 0x3c000>;
+		/* ... */
+		power-domain = <&pd_pu>;
+		/* ... */
+	};
+
-- 
1.8.5.3

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 2/7] ARM: imx6: gpc: Add PU power domain for GPU/VPU
  2014-02-13 14:39 ` Philipp Zabel
@ 2014-02-13 14:39     ` Philipp Zabel
  -1 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Rob Herring, Mark Rutland, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Philipp Zabel

When generic pm domain support is enabled, the PGC can be used
to completely gate power to the PU power domain containing GPU3D,
GPU2D, and VPU cores.
This code triggers the PGC powerdown sequence to disable the GPU/VPU
isolation cells and gate power and then disables the PU regulator.
To reenable, the reverse powerup sequence is triggered after the PU
regulaotor is enabled again.

Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
Changes since v1:
 - Removed superfluous comment
 - Link PU domain with its DT node, check for PU domain in bus notifier
 - Turn off the PU power domain on boot
---
 arch/arm/mach-imx/Kconfig |   2 +
 arch/arm/mach-imx/gpc.c   | 170 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 172 insertions(+)

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 33567aa..3c58f2e 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -808,6 +808,7 @@ config SOC_IMX6Q
 	select PL310_ERRATA_727915 if CACHE_PL310
 	select PL310_ERRATA_769419 if CACHE_PL310
 	select PM_OPP if PM
+	select PM_GENERIC_DOMAINS if PM
 
 	help
 	  This enables support for Freescale i.MX6 Quad processor.
@@ -827,6 +828,7 @@ config SOC_IMX6SL
 	select PL310_ERRATA_588369 if CACHE_PL310
 	select PL310_ERRATA_727915 if CACHE_PL310
 	select PL310_ERRATA_769419 if CACHE_PL310
+	select PM_GENERIC_DOMAINS if PM
 
 	help
 	  This enables support for Freescale i.MX6 SoloLite processor.
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 586e017..1dc4301 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -10,19 +10,32 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
+#include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/regulator/consumer.h>
 #include <linux/irqchip/arm-gic.h>
 #include "common.h"
+#include "hardware.h"
 
+#define GPC_CNTR		0x000
 #define GPC_IMR1		0x008
+#define GPC_PGC_GPU_PDN		0x260
+#define GPC_PGC_GPU_PUPSCR	0x264
+#define GPC_PGC_GPU_PDNSCR	0x268
 #define GPC_PGC_CPU_PDN		0x2a0
 
 #define IMR_NUM			4
 
+#define GPU_VPU_PUP_REQ		BIT(1)
+#define GPU_VPU_PDN_REQ		BIT(0)
+
 static void __iomem *gpc_base;
 static u32 gpc_wake_irqs[IMR_NUM];
 static u32 gpc_saved_imrs[IMR_NUM];
@@ -138,3 +151,160 @@ void __init imx_gpc_init(void)
 	gic_arch_extn.irq_unmask = imx_gpc_irq_unmask;
 	gic_arch_extn.irq_set_wake = imx_gpc_irq_set_wake;
 }
+
+static struct regulator *pu_reg;
+
+static int imx6q_pm_pu_power_off(struct generic_pm_domain *genpd)
+{
+	u32 val;
+	int iso, iso2sw;
+
+	/* Read ISO and ISO2SW power down delays */
+	val = readl_relaxed(gpc_base + GPC_PGC_GPU_PDNSCR);
+	iso = val & 0x3f;
+	iso2sw = (val >> 8) & 0x3f;
+
+	/* Gate off PU domain when GPU/VPU when powered down */
+	writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
+
+	/* Request GPC to power down GPU/VPU */
+	val = readl_relaxed(gpc_base + GPC_CNTR);
+	val |= GPU_VPU_PDN_REQ;
+	writel_relaxed(val, gpc_base + GPC_CNTR);
+
+	/* Wait ISO + ISO2SW IPG clock cycles */
+	ndelay((iso + iso2sw) * 1000 / 66);
+
+	regulator_disable(pu_reg);
+
+	return 0;
+}
+
+static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd)
+{
+	int ret;
+	u32 val;
+	int sw, sw2iso;
+
+	ret = regulator_enable(pu_reg);
+	if (ret) {
+		pr_err("%s: failed to enable regulator: %d\n", __func__, ret);
+		return ret;
+	}
+
+	/* Gate off PU domain when GPU/VPU when powered down */
+	writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
+
+	/* Read ISO and ISO2SW power down delays */
+	val = readl_relaxed(gpc_base + GPC_PGC_GPU_PUPSCR);
+	sw = val & 0x3f;
+	sw2iso = (val >> 8) & 0x3f;
+
+	/* Request GPC to power up GPU/VPU */
+	val = readl_relaxed(gpc_base + GPC_CNTR);
+	val |= GPU_VPU_PUP_REQ;
+	writel_relaxed(val, gpc_base + GPC_CNTR);
+
+	/* Wait ISO + ISO2SW IPG clock cycles */
+	ndelay((sw + sw2iso) * 1000 / 66);
+
+	return 0;
+}
+
+static struct generic_pm_domain imx6q_pu_domain = {
+	.name = "PU",
+	.power_off = imx6q_pm_pu_power_off,
+	.power_on = imx6q_pm_pu_power_on,
+};
+
+static int imx6q_pm_notifier_call(struct notifier_block *nb,
+				  unsigned long event, void *data)
+{
+	struct generic_pm_domain *genpd;
+	struct device *dev = data;
+	struct device_node *np;
+	int ret;
+
+	switch (event) {
+	case BUS_NOTIFY_BIND_DRIVER:
+		np = of_parse_phandle(dev->of_node, "power-domain", 0);
+		if (!np || np != imx6q_pu_domain.of_node)
+			return NOTIFY_DONE;
+
+		ret = pm_genpd_of_add_device(np, dev);
+		if (ret)
+			dev_err(dev, "failed to add to power domain: %d\n",
+				ret);
+		break;
+	case BUS_NOTIFY_UNBOUND_DRIVER:
+		genpd = dev_to_genpd(dev);
+		if (IS_ERR(genpd) || genpd != &imx6q_pu_domain)
+			return NOTIFY_DONE;
+
+		ret = pm_genpd_remove_device(genpd, dev);
+		if (ret)
+			dev_err(dev, "failed to remove from power domain: %d\n",
+				ret);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block imx6q_platform_nb = {
+	.notifier_call = imx6q_pm_notifier_call,
+};
+
+static int imx_gpc_probe(struct platform_device *pdev)
+{
+	struct device_node *np;
+	int ret;
+
+	np = of_get_child_by_name(pdev->dev.of_node, "pu-power-domain");
+	if (!np) {
+		dev_err(&pdev->dev, "missing pu-power-domain node\n");
+		return -EINVAL;
+	}
+	imx6q_pu_domain.of_node = np;
+
+	pu_reg = devm_regulator_get(&pdev->dev, "pu");
+	if (IS_ERR(pu_reg)) {
+		ret = PTR_ERR(pu_reg);
+		dev_err(&pdev->dev, "failed to get pu regulator: %d\n", ret);
+		return ret;
+	}
+
+	/* The regulator is initially enabled */
+	ret = regulator_enable(pu_reg);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to enable pu regulator: %d\n", ret);
+		return ret;
+	}
+
+	imx6q_pu_domain.of_node = np;
+	imx6q_pm_pu_power_off(&imx6q_pu_domain);
+	pm_genpd_init(&imx6q_pu_domain, NULL, true);
+	bus_register_notifier(&platform_bus_type, &imx6q_platform_nb);
+
+	return 0;
+}
+
+static struct of_device_id imx_gpc_dt_ids[] = {
+	{ .compatible = "fsl,imx6q-gpc" },
+	{ }
+};
+
+static struct platform_driver imx_gpc_driver = {
+	.driver = {
+		.name = "imx-gpc",
+		.owner = THIS_MODULE,
+		.of_match_table = imx_gpc_dt_ids,
+	},
+	.probe = imx_gpc_probe,
+};
+
+static int __init imx_pgc_init(void)
+{
+	return platform_driver_register(&imx_gpc_driver);
+}
+subsys_initcall(imx_pgc_init);
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 2/7] ARM: imx6: gpc: Add PU power domain for GPU/VPU
@ 2014-02-13 14:39     ` Philipp Zabel
  0 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

When generic pm domain support is enabled, the PGC can be used
to completely gate power to the PU power domain containing GPU3D,
GPU2D, and VPU cores.
This code triggers the PGC powerdown sequence to disable the GPU/VPU
isolation cells and gate power and then disables the PU regulator.
To reenable, the reverse powerup sequence is triggered after the PU
regulaotor is enabled again.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
Changes since v1:
 - Removed superfluous comment
 - Link PU domain with its DT node, check for PU domain in bus notifier
 - Turn off the PU power domain on boot
---
 arch/arm/mach-imx/Kconfig |   2 +
 arch/arm/mach-imx/gpc.c   | 170 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 172 insertions(+)

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 33567aa..3c58f2e 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -808,6 +808,7 @@ config SOC_IMX6Q
 	select PL310_ERRATA_727915 if CACHE_PL310
 	select PL310_ERRATA_769419 if CACHE_PL310
 	select PM_OPP if PM
+	select PM_GENERIC_DOMAINS if PM
 
 	help
 	  This enables support for Freescale i.MX6 Quad processor.
@@ -827,6 +828,7 @@ config SOC_IMX6SL
 	select PL310_ERRATA_588369 if CACHE_PL310
 	select PL310_ERRATA_727915 if CACHE_PL310
 	select PL310_ERRATA_769419 if CACHE_PL310
+	select PM_GENERIC_DOMAINS if PM
 
 	help
 	  This enables support for Freescale i.MX6 SoloLite processor.
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 586e017..1dc4301 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -10,19 +10,32 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
+#include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/regulator/consumer.h>
 #include <linux/irqchip/arm-gic.h>
 #include "common.h"
+#include "hardware.h"
 
+#define GPC_CNTR		0x000
 #define GPC_IMR1		0x008
+#define GPC_PGC_GPU_PDN		0x260
+#define GPC_PGC_GPU_PUPSCR	0x264
+#define GPC_PGC_GPU_PDNSCR	0x268
 #define GPC_PGC_CPU_PDN		0x2a0
 
 #define IMR_NUM			4
 
+#define GPU_VPU_PUP_REQ		BIT(1)
+#define GPU_VPU_PDN_REQ		BIT(0)
+
 static void __iomem *gpc_base;
 static u32 gpc_wake_irqs[IMR_NUM];
 static u32 gpc_saved_imrs[IMR_NUM];
@@ -138,3 +151,160 @@ void __init imx_gpc_init(void)
 	gic_arch_extn.irq_unmask = imx_gpc_irq_unmask;
 	gic_arch_extn.irq_set_wake = imx_gpc_irq_set_wake;
 }
+
+static struct regulator *pu_reg;
+
+static int imx6q_pm_pu_power_off(struct generic_pm_domain *genpd)
+{
+	u32 val;
+	int iso, iso2sw;
+
+	/* Read ISO and ISO2SW power down delays */
+	val = readl_relaxed(gpc_base + GPC_PGC_GPU_PDNSCR);
+	iso = val & 0x3f;
+	iso2sw = (val >> 8) & 0x3f;
+
+	/* Gate off PU domain when GPU/VPU when powered down */
+	writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
+
+	/* Request GPC to power down GPU/VPU */
+	val = readl_relaxed(gpc_base + GPC_CNTR);
+	val |= GPU_VPU_PDN_REQ;
+	writel_relaxed(val, gpc_base + GPC_CNTR);
+
+	/* Wait ISO + ISO2SW IPG clock cycles */
+	ndelay((iso + iso2sw) * 1000 / 66);
+
+	regulator_disable(pu_reg);
+
+	return 0;
+}
+
+static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd)
+{
+	int ret;
+	u32 val;
+	int sw, sw2iso;
+
+	ret = regulator_enable(pu_reg);
+	if (ret) {
+		pr_err("%s: failed to enable regulator: %d\n", __func__, ret);
+		return ret;
+	}
+
+	/* Gate off PU domain when GPU/VPU when powered down */
+	writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
+
+	/* Read ISO and ISO2SW power down delays */
+	val = readl_relaxed(gpc_base + GPC_PGC_GPU_PUPSCR);
+	sw = val & 0x3f;
+	sw2iso = (val >> 8) & 0x3f;
+
+	/* Request GPC to power up GPU/VPU */
+	val = readl_relaxed(gpc_base + GPC_CNTR);
+	val |= GPU_VPU_PUP_REQ;
+	writel_relaxed(val, gpc_base + GPC_CNTR);
+
+	/* Wait ISO + ISO2SW IPG clock cycles */
+	ndelay((sw + sw2iso) * 1000 / 66);
+
+	return 0;
+}
+
+static struct generic_pm_domain imx6q_pu_domain = {
+	.name = "PU",
+	.power_off = imx6q_pm_pu_power_off,
+	.power_on = imx6q_pm_pu_power_on,
+};
+
+static int imx6q_pm_notifier_call(struct notifier_block *nb,
+				  unsigned long event, void *data)
+{
+	struct generic_pm_domain *genpd;
+	struct device *dev = data;
+	struct device_node *np;
+	int ret;
+
+	switch (event) {
+	case BUS_NOTIFY_BIND_DRIVER:
+		np = of_parse_phandle(dev->of_node, "power-domain", 0);
+		if (!np || np != imx6q_pu_domain.of_node)
+			return NOTIFY_DONE;
+
+		ret = pm_genpd_of_add_device(np, dev);
+		if (ret)
+			dev_err(dev, "failed to add to power domain: %d\n",
+				ret);
+		break;
+	case BUS_NOTIFY_UNBOUND_DRIVER:
+		genpd = dev_to_genpd(dev);
+		if (IS_ERR(genpd) || genpd != &imx6q_pu_domain)
+			return NOTIFY_DONE;
+
+		ret = pm_genpd_remove_device(genpd, dev);
+		if (ret)
+			dev_err(dev, "failed to remove from power domain: %d\n",
+				ret);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block imx6q_platform_nb = {
+	.notifier_call = imx6q_pm_notifier_call,
+};
+
+static int imx_gpc_probe(struct platform_device *pdev)
+{
+	struct device_node *np;
+	int ret;
+
+	np = of_get_child_by_name(pdev->dev.of_node, "pu-power-domain");
+	if (!np) {
+		dev_err(&pdev->dev, "missing pu-power-domain node\n");
+		return -EINVAL;
+	}
+	imx6q_pu_domain.of_node = np;
+
+	pu_reg = devm_regulator_get(&pdev->dev, "pu");
+	if (IS_ERR(pu_reg)) {
+		ret = PTR_ERR(pu_reg);
+		dev_err(&pdev->dev, "failed to get pu regulator: %d\n", ret);
+		return ret;
+	}
+
+	/* The regulator is initially enabled */
+	ret = regulator_enable(pu_reg);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to enable pu regulator: %d\n", ret);
+		return ret;
+	}
+
+	imx6q_pu_domain.of_node = np;
+	imx6q_pm_pu_power_off(&imx6q_pu_domain);
+	pm_genpd_init(&imx6q_pu_domain, NULL, true);
+	bus_register_notifier(&platform_bus_type, &imx6q_platform_nb);
+
+	return 0;
+}
+
+static struct of_device_id imx_gpc_dt_ids[] = {
+	{ .compatible = "fsl,imx6q-gpc" },
+	{ }
+};
+
+static struct platform_driver imx_gpc_driver = {
+	.driver = {
+		.name = "imx-gpc",
+		.owner = THIS_MODULE,
+		.of_match_table = imx_gpc_dt_ids,
+	},
+	.probe = imx_gpc_probe,
+};
+
+static int __init imx_pgc_init(void)
+{
+	return platform_driver_register(&imx_gpc_driver);
+}
+subsys_initcall(imx_pgc_init);
-- 
1.8.5.3

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 3/7] ARM: imx6: gpc: Add pm clock support to PU power domain
  2014-02-13 14:39 ` Philipp Zabel
@ 2014-02-13 14:39     ` Philipp Zabel
  -1 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Rob Herring, Mark Rutland, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Philipp Zabel

Drivers still handle clocks themselves, we only enable pm clocks of the
GPU and VPU devices in the PU power domain temporarily during powerup
so that the reset machinery can work.

Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
 arch/arm/mach-imx/gpc.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)

diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 1dc4301..607a6ea 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -18,6 +18,7 @@
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
+#include <linux/pm_clock.h>
 #include <linux/pm_domain.h>
 #include <linux/regulator/consumer.h>
 #include <linux/irqchip/arm-gic.h>
@@ -182,6 +183,7 @@ static int imx6q_pm_pu_power_off(struct generic_pm_domain *genpd)
 
 static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd)
 {
+	struct pm_domain_data *pdd;
 	int ret;
 	u32 val;
 	int sw, sw2iso;
@@ -192,6 +194,10 @@ static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd)
 		return ret;
 	}
 
+	/* Enable PM clocks for all devices in the PU domain */
+	list_for_each_entry(pdd, &genpd->dev_list, list_node)
+		pm_clk_resume(pdd->dev);
+
 	/* Gate off PU domain when GPU/VPU when powered down */
 	writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
 
@@ -208,6 +214,10 @@ static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd)
 	/* Wait ISO + ISO2SW IPG clock cycles */
 	ndelay((sw + sw2iso) * 1000 / 66);
 
+	/* Disable PM clocks for all devices in the PU domain */
+	list_for_each_entry(pdd, &genpd->dev_list, list_node)
+		pm_clk_suspend(pdd->dev);
+
 	return 0;
 }
 
@@ -217,6 +227,68 @@ static struct generic_pm_domain imx6q_pu_domain = {
 	.power_on = imx6q_pm_pu_power_on,
 };
 
+int imx6q_pm_clk_add(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	const char *con_id;
+	struct clk *clk;
+	int i = 0;
+
+	/* Add and prepare named clocks */
+	while (!of_property_read_string_index(np, "clock-names", i, &con_id)) {
+		pm_clk_add(dev, con_id);
+		clk = of_clk_get(np, i);
+		if (!IS_ERR(clk)) {
+			clk_prepare(clk);
+			clk_put(clk);
+		}
+		i++;
+	}
+
+	/* If no named clocks are given, add and prepare unnamed clock */
+	if (i == 1 && of_find_property(dev->of_node, "clocks", NULL)) {
+		pm_clk_add(dev, NULL);
+		clk = of_clk_get(np, 0);
+		if (!IS_ERR(clk)) {
+			clk_prepare(clk);
+			clk_put(clk);
+		}
+	}
+
+	return 0;
+}
+
+int imx6q_pm_clk_remove(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	const char *con_id;
+	struct clk *clk;
+	int i = 0;
+
+	/* Remove and unprepare named clocks */
+	while (!of_property_read_string_index(np, "clock-names", i, &con_id)) {
+		pm_clk_remove(dev, con_id);
+		clk = of_clk_get(np, i);
+		if (!IS_ERR(clk)) {
+			clk_unprepare(clk);
+			clk_put(clk);
+		}
+		i++;
+	}
+
+	/* If no named clocks are given, remove and unprepare unnamed clock */
+	if (i == 1 && of_find_property(dev->of_node, "clocks", NULL)) {
+		pm_clk_remove(dev, NULL);
+		clk = of_clk_get(np, 0);
+		if (!IS_ERR(clk)) {
+			clk_unprepare(clk);
+			clk_put(clk);
+		}
+	}
+
+	return 0;
+}
+
 static int imx6q_pm_notifier_call(struct notifier_block *nb,
 				  unsigned long event, void *data)
 {
@@ -235,6 +307,7 @@ static int imx6q_pm_notifier_call(struct notifier_block *nb,
 		if (ret)
 			dev_err(dev, "failed to add to power domain: %d\n",
 				ret);
+		imx6q_pm_clk_add(dev);
 		break;
 	case BUS_NOTIFY_UNBOUND_DRIVER:
 		genpd = dev_to_genpd(dev);
@@ -245,6 +318,7 @@ static int imx6q_pm_notifier_call(struct notifier_block *nb,
 		if (ret)
 			dev_err(dev, "failed to remove from power domain: %d\n",
 				ret);
+		imx6q_pm_clk_remove(dev);
 		break;
 	}
 
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 3/7] ARM: imx6: gpc: Add pm clock support to PU power domain
@ 2014-02-13 14:39     ` Philipp Zabel
  0 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

Drivers still handle clocks themselves, we only enable pm clocks of the
GPU and VPU devices in the PU power domain temporarily during powerup
so that the reset machinery can work.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
 arch/arm/mach-imx/gpc.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)

diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 1dc4301..607a6ea 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -18,6 +18,7 @@
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
+#include <linux/pm_clock.h>
 #include <linux/pm_domain.h>
 #include <linux/regulator/consumer.h>
 #include <linux/irqchip/arm-gic.h>
@@ -182,6 +183,7 @@ static int imx6q_pm_pu_power_off(struct generic_pm_domain *genpd)
 
 static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd)
 {
+	struct pm_domain_data *pdd;
 	int ret;
 	u32 val;
 	int sw, sw2iso;
@@ -192,6 +194,10 @@ static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd)
 		return ret;
 	}
 
+	/* Enable PM clocks for all devices in the PU domain */
+	list_for_each_entry(pdd, &genpd->dev_list, list_node)
+		pm_clk_resume(pdd->dev);
+
 	/* Gate off PU domain when GPU/VPU when powered down */
 	writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
 
@@ -208,6 +214,10 @@ static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd)
 	/* Wait ISO + ISO2SW IPG clock cycles */
 	ndelay((sw + sw2iso) * 1000 / 66);
 
+	/* Disable PM clocks for all devices in the PU domain */
+	list_for_each_entry(pdd, &genpd->dev_list, list_node)
+		pm_clk_suspend(pdd->dev);
+
 	return 0;
 }
 
@@ -217,6 +227,68 @@ static struct generic_pm_domain imx6q_pu_domain = {
 	.power_on = imx6q_pm_pu_power_on,
 };
 
+int imx6q_pm_clk_add(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	const char *con_id;
+	struct clk *clk;
+	int i = 0;
+
+	/* Add and prepare named clocks */
+	while (!of_property_read_string_index(np, "clock-names", i, &con_id)) {
+		pm_clk_add(dev, con_id);
+		clk = of_clk_get(np, i);
+		if (!IS_ERR(clk)) {
+			clk_prepare(clk);
+			clk_put(clk);
+		}
+		i++;
+	}
+
+	/* If no named clocks are given, add and prepare unnamed clock */
+	if (i == 1 && of_find_property(dev->of_node, "clocks", NULL)) {
+		pm_clk_add(dev, NULL);
+		clk = of_clk_get(np, 0);
+		if (!IS_ERR(clk)) {
+			clk_prepare(clk);
+			clk_put(clk);
+		}
+	}
+
+	return 0;
+}
+
+int imx6q_pm_clk_remove(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	const char *con_id;
+	struct clk *clk;
+	int i = 0;
+
+	/* Remove and unprepare named clocks */
+	while (!of_property_read_string_index(np, "clock-names", i, &con_id)) {
+		pm_clk_remove(dev, con_id);
+		clk = of_clk_get(np, i);
+		if (!IS_ERR(clk)) {
+			clk_unprepare(clk);
+			clk_put(clk);
+		}
+		i++;
+	}
+
+	/* If no named clocks are given, remove and unprepare unnamed clock */
+	if (i == 1 && of_find_property(dev->of_node, "clocks", NULL)) {
+		pm_clk_remove(dev, NULL);
+		clk = of_clk_get(np, 0);
+		if (!IS_ERR(clk)) {
+			clk_unprepare(clk);
+			clk_put(clk);
+		}
+	}
+
+	return 0;
+}
+
 static int imx6q_pm_notifier_call(struct notifier_block *nb,
 				  unsigned long event, void *data)
 {
@@ -235,6 +307,7 @@ static int imx6q_pm_notifier_call(struct notifier_block *nb,
 		if (ret)
 			dev_err(dev, "failed to add to power domain: %d\n",
 				ret);
+		imx6q_pm_clk_add(dev);
 		break;
 	case BUS_NOTIFY_UNBOUND_DRIVER:
 		genpd = dev_to_genpd(dev);
@@ -245,6 +318,7 @@ static int imx6q_pm_notifier_call(struct notifier_block *nb,
 		if (ret)
 			dev_err(dev, "failed to remove from power domain: %d\n",
 				ret);
+		imx6q_pm_clk_remove(dev);
 		break;
 	}
 
-- 
1.8.5.3

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 4/7] ARM: imx6: gpc: Add observed worst case latencies
  2014-02-13 14:39 ` Philipp Zabel
@ 2014-02-13 14:39     ` Philipp Zabel
  -1 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Rob Herring, Mark Rutland, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Philipp Zabel

This avoids the "... latency exceeded, new value ..." warnings
emitted by the power domain framework code whenever the PU domain
is enabled or disabled.

Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
 arch/arm/mach-imx/gpc.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 607a6ea..cbac099 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -225,6 +225,8 @@ static struct generic_pm_domain imx6q_pu_domain = {
 	.name = "PU",
 	.power_off = imx6q_pm_pu_power_off,
 	.power_on = imx6q_pm_pu_power_on,
+	.power_off_latency_ns = 25000,
+	.power_on_latency_ns = 2000000,
 };
 
 int imx6q_pm_clk_add(struct device *dev)
@@ -289,6 +291,13 @@ int imx6q_pm_clk_remove(struct device *dev)
 	return 0;
 }
 
+static struct gpd_timing_data pu_timing_data = {
+	.stop_latency_ns = 2000,
+	.start_latency_ns = 2000,
+	.save_state_latency_ns = 5000,
+	.restore_state_latency_ns = 20000000, /* VPU firmware reload */
+};
+
 static int imx6q_pm_notifier_call(struct notifier_block *nb,
 				  unsigned long event, void *data)
 {
@@ -303,7 +312,7 @@ static int imx6q_pm_notifier_call(struct notifier_block *nb,
 		if (!np || np != imx6q_pu_domain.of_node)
 			return NOTIFY_DONE;
 
-		ret = pm_genpd_of_add_device(np, dev);
+		ret = __pm_genpd_of_add_device(np, dev, &pu_timing_data);
 		if (ret)
 			dev_err(dev, "failed to add to power domain: %d\n",
 				ret);
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 4/7] ARM: imx6: gpc: Add observed worst case latencies
@ 2014-02-13 14:39     ` Philipp Zabel
  0 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

This avoids the "... latency exceeded, new value ..." warnings
emitted by the power domain framework code whenever the PU domain
is enabled or disabled.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
 arch/arm/mach-imx/gpc.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 607a6ea..cbac099 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -225,6 +225,8 @@ static struct generic_pm_domain imx6q_pu_domain = {
 	.name = "PU",
 	.power_off = imx6q_pm_pu_power_off,
 	.power_on = imx6q_pm_pu_power_on,
+	.power_off_latency_ns = 25000,
+	.power_on_latency_ns = 2000000,
 };
 
 int imx6q_pm_clk_add(struct device *dev)
@@ -289,6 +291,13 @@ int imx6q_pm_clk_remove(struct device *dev)
 	return 0;
 }
 
+static struct gpd_timing_data pu_timing_data = {
+	.stop_latency_ns = 2000,
+	.start_latency_ns = 2000,
+	.save_state_latency_ns = 5000,
+	.restore_state_latency_ns = 20000000, /* VPU firmware reload */
+};
+
 static int imx6q_pm_notifier_call(struct notifier_block *nb,
 				  unsigned long event, void *data)
 {
@@ -303,7 +312,7 @@ static int imx6q_pm_notifier_call(struct notifier_block *nb,
 		if (!np || np != imx6q_pu_domain.of_node)
 			return NOTIFY_DONE;
 
-		ret = pm_genpd_of_add_device(np, dev);
+		ret = __pm_genpd_of_add_device(np, dev, &pu_timing_data);
 		if (ret)
 			dev_err(dev, "failed to add to power domain: %d\n",
 				ret);
-- 
1.8.5.3

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 5/7] ARM: dts: imx6qdl: Allow disabling the PU regulator, add a enable ramp delay
  2014-02-13 14:39 ` Philipp Zabel
@ 2014-02-13 14:39     ` Philipp Zabel
  -1 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Rob Herring, Mark Rutland, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Philipp Zabel

The PU regulator is enabled during boot, but not necessarily always-on.
It can be disabled by the generic pm domain framework when the PU power
domain is shut down. The ramp delay of 150 us might be a bit conservative,
the value is taken from the Freescale kernel.

Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
 arch/arm/boot/dts/imx6qdl.dtsi | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index fb28b2e..253d82c 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -515,7 +515,8 @@
 					regulator-name = "vddpu";
 					regulator-min-microvolt = <725000>;
 					regulator-max-microvolt = <1450000>;
-					regulator-always-on;
+					regulator-enable-ramp-delay = <150>;
+					regulator-boot-on;
 					anatop-reg-offset = <0x140>;
 					anatop-vol-bit-shift = <9>;
 					anatop-vol-bit-width = <5>;
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 5/7] ARM: dts: imx6qdl: Allow disabling the PU regulator, add a enable ramp delay
@ 2014-02-13 14:39     ` Philipp Zabel
  0 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

The PU regulator is enabled during boot, but not necessarily always-on.
It can be disabled by the generic pm domain framework when the PU power
domain is shut down. The ramp delay of 150 us might be a bit conservative,
the value is taken from the Freescale kernel.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
 arch/arm/boot/dts/imx6qdl.dtsi | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index fb28b2e..253d82c 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -515,7 +515,8 @@
 					regulator-name = "vddpu";
 					regulator-min-microvolt = <725000>;
 					regulator-max-microvolt = <1450000>;
-					regulator-always-on;
+					regulator-enable-ramp-delay = <150>;
+					regulator-boot-on;
 					anatop-reg-offset = <0x140>;
 					anatop-vol-bit-shift = <9>;
 					anatop-vol-bit-width = <5>;
-- 
1.8.5.3

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 6/7] ARM: dts: imx6qdl: Add power-domain information to gpc node
  2014-02-13 14:39 ` Philipp Zabel
@ 2014-02-13 14:39     ` Philipp Zabel
  -1 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Rob Herring, Mark Rutland, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Philipp Zabel

The PGC that is part of GPC controls isolation and power sequencing of the
power domains. The PU power domain will be handled by the generic pm domain
framework and needs a phandle to the PU regulator to turn off power when
the domain is disabled.

Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
Changes since v1:
 - Renamed power-domain to pu-power-domain and added
   cpu-power-domain
---
 arch/arm/boot/dts/imx6qdl.dtsi | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 253d82c..fd1be55 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -598,9 +598,22 @@
 			};
 
 			gpc: gpc@020dc000 {
+				#address-cells = <1>;
+				#size-cells = <1>;
 				compatible = "fsl,imx6q-gpc";
 				reg = <0x020dc000 0x4000>;
 				interrupts = <0 89 0x04 0 90 0x04>;
+				pu-supply = <&reg_pu>;
+
+				pd_pu: pu-power-domain@020dc260 {
+					compatible = "fsl,imx6q-power-domain";
+					reg = <0x020dc260 0x10>;
+				};
+
+				pd_arm: cpu-power-domain@020dc2a0 {
+					compatible = "fsl,imx6q-power-domain";
+					reg = <0x020dc2a0 0x10>;
+				};
 			};
 
 			gpr: iomuxc-gpr@020e0000 {
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 6/7] ARM: dts: imx6qdl: Add power-domain information to gpc node
@ 2014-02-13 14:39     ` Philipp Zabel
  0 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

The PGC that is part of GPC controls isolation and power sequencing of the
power domains. The PU power domain will be handled by the generic pm domain
framework and needs a phandle to the PU regulator to turn off power when
the domain is disabled.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
Changes since v1:
 - Renamed power-domain to pu-power-domain and added
   cpu-power-domain
---
 arch/arm/boot/dts/imx6qdl.dtsi | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 253d82c..fd1be55 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -598,9 +598,22 @@
 			};
 
 			gpc: gpc at 020dc000 {
+				#address-cells = <1>;
+				#size-cells = <1>;
 				compatible = "fsl,imx6q-gpc";
 				reg = <0x020dc000 0x4000>;
 				interrupts = <0 89 0x04 0 90 0x04>;
+				pu-supply = <&reg_pu>;
+
+				pd_pu: pu-power-domain at 020dc260 {
+					compatible = "fsl,imx6q-power-domain";
+					reg = <0x020dc260 0x10>;
+				};
+
+				pd_arm: cpu-power-domain at 020dc2a0 {
+					compatible = "fsl,imx6q-power-domain";
+					reg = <0x020dc2a0 0x10>;
+				};
 			};
 
 			gpr: iomuxc-gpr at 020e0000 {
-- 
1.8.5.3

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 7/7] ARM: dts: imx6sl: Add power-domain information to gpc node
  2014-02-13 14:39 ` Philipp Zabel
@ 2014-02-13 14:39     ` Philipp Zabel
  -1 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Rob Herring, Mark Rutland, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Philipp Zabel

The PGC that is part of GPC controls isolation and power sequencing of the
power domains. The PU power domain will be handled by the generic pm domain
framework and needs a phandle to the PU regulator to turn off power when
the domain is disabled.

Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
 arch/arm/boot/dts/imx6sl.dtsi | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index 28558f1..774e1fb 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -529,9 +529,27 @@
 			};
 
 			gpc: gpc@020dc000 {
+				#address-cells = <1>;
+				#size-cells = <1>;
 				compatible = "fsl,imx6sl-gpc", "fsl,imx6q-gpc";
 				reg = <0x020dc000 0x4000>;
 				interrupts = <0 89 0x04>;
+				pu-supply = <&reg_pu>;
+
+				pd_display: display-power-domain@020dc240 {
+					compatible = "fsl,imx6q-power-domain";
+					reg = <0x020dc240 0x10>;
+				};
+
+				pd_pu: pu-power-domain@020dc260 {
+					compatible = "fsl,imx6q-power-domain";
+					reg = <0x020dc260 0x10>;
+				};
+
+				pd_arm: cpu-power-domain@020dc2a0 {
+					compatible = "fsl,imx6q-power-domain";
+					reg = <0x020dc2a0 0x10>;
+				};
 			};
 
 			gpr: iomuxc-gpr@020e0000 {
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 7/7] ARM: dts: imx6sl: Add power-domain information to gpc node
@ 2014-02-13 14:39     ` Philipp Zabel
  0 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

The PGC that is part of GPC controls isolation and power sequencing of the
power domains. The PU power domain will be handled by the generic pm domain
framework and needs a phandle to the PU regulator to turn off power when
the domain is disabled.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
 arch/arm/boot/dts/imx6sl.dtsi | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index 28558f1..774e1fb 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -529,9 +529,27 @@
 			};
 
 			gpc: gpc at 020dc000 {
+				#address-cells = <1>;
+				#size-cells = <1>;
 				compatible = "fsl,imx6sl-gpc", "fsl,imx6q-gpc";
 				reg = <0x020dc000 0x4000>;
 				interrupts = <0 89 0x04>;
+				pu-supply = <&reg_pu>;
+
+				pd_display: display-power-domain at 020dc240 {
+					compatible = "fsl,imx6q-power-domain";
+					reg = <0x020dc240 0x10>;
+				};
+
+				pd_pu: pu-power-domain at 020dc260 {
+					compatible = "fsl,imx6q-power-domain";
+					reg = <0x020dc260 0x10>;
+				};
+
+				pd_arm: cpu-power-domain at 020dc2a0 {
+					compatible = "fsl,imx6q-power-domain";
+					reg = <0x020dc2a0 0x10>;
+				};
 			};
 
 			gpr: iomuxc-gpr at 020e0000 {
-- 
1.8.5.3

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 2/7] ARM: imx6: gpc: Add PU power domain for GPU/VPU
  2014-02-13 14:39     ` Philipp Zabel
@ 2014-02-13 16:41         ` Philipp Zabel
  -1 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 16:41 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Rob Herring, Mark Rutland, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Am Donnerstag, den 13.02.2014, 15:39 +0100 schrieb Philipp Zabel:
> When generic pm domain support is enabled, the PGC can be used
> to completely gate power to the PU power domain containing GPU3D,
> GPU2D, and VPU cores.
> This code triggers the PGC powerdown sequence to disable the GPU/VPU
> isolation cells and gate power and then disables the PU regulator.
> To reenable, the reverse powerup sequence is triggered after the PU
> regulaotor is enabled again.
> 
> Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> ---
> Changes since v1:
>  - Removed superfluous comment
>  - Link PU domain with its DT node, check for PU domain in bus notifier
>  - Turn off the PU power domain on boot
> ---
>  arch/arm/mach-imx/Kconfig |   2 +
>  arch/arm/mach-imx/gpc.c   | 170 ++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 172 insertions(+)
> 
> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> index 33567aa..3c58f2e 100644
> --- a/arch/arm/mach-imx/Kconfig
> +++ b/arch/arm/mach-imx/Kconfig
> @@ -808,6 +808,7 @@ config SOC_IMX6Q
>  	select PL310_ERRATA_727915 if CACHE_PL310
>  	select PL310_ERRATA_769419 if CACHE_PL310
>  	select PM_OPP if PM
> +	select PM_GENERIC_DOMAINS if PM
>  
>  	help
>  	  This enables support for Freescale i.MX6 Quad processor.
> @@ -827,6 +828,7 @@ config SOC_IMX6SL
>  	select PL310_ERRATA_588369 if CACHE_PL310
>  	select PL310_ERRATA_727915 if CACHE_PL310
>  	select PL310_ERRATA_769419 if CACHE_PL310
> +	select PM_GENERIC_DOMAINS if PM
>  
>  	help
>  	  This enables support for Freescale i.MX6 SoloLite processor.
> diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
> index 586e017..1dc4301 100644
> --- a/arch/arm/mach-imx/gpc.c
> +++ b/arch/arm/mach-imx/gpc.c
> @@ -10,19 +10,32 @@
>   * http://www.gnu.org/copyleft/gpl.html
>   */
>  
> +#include <linux/clk.h>
> +#include <linux/delay.h>
>  #include <linux/io.h>
>  #include <linux/irq.h>
>  #include <linux/of.h>
>  #include <linux/of_address.h>
>  #include <linux/of_irq.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_domain.h>
> +#include <linux/regulator/consumer.h>
>  #include <linux/irqchip/arm-gic.h>
>  #include "common.h"
> +#include "hardware.h"
>  
> +#define GPC_CNTR		0x000
>  #define GPC_IMR1		0x008
> +#define GPC_PGC_GPU_PDN		0x260
> +#define GPC_PGC_GPU_PUPSCR	0x264
> +#define GPC_PGC_GPU_PDNSCR	0x268
>  #define GPC_PGC_CPU_PDN		0x2a0
>  
>  #define IMR_NUM			4
>  
> +#define GPU_VPU_PUP_REQ		BIT(1)
> +#define GPU_VPU_PDN_REQ		BIT(0)
> +
>  static void __iomem *gpc_base;
>  static u32 gpc_wake_irqs[IMR_NUM];
>  static u32 gpc_saved_imrs[IMR_NUM];
> @@ -138,3 +151,160 @@ void __init imx_gpc_init(void)
>  	gic_arch_extn.irq_unmask = imx_gpc_irq_unmask;
>  	gic_arch_extn.irq_set_wake = imx_gpc_irq_set_wake;
>  }
> +
> +static struct regulator *pu_reg;
> +
> +static int imx6q_pm_pu_power_off(struct generic_pm_domain *genpd)
> +{
> +	u32 val;
> +	int iso, iso2sw;
> +
> +	/* Read ISO and ISO2SW power down delays */
> +	val = readl_relaxed(gpc_base + GPC_PGC_GPU_PDNSCR);
> +	iso = val & 0x3f;
> +	iso2sw = (val >> 8) & 0x3f;
> +
> +	/* Gate off PU domain when GPU/VPU when powered down */
> +	writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
> +
> +	/* Request GPC to power down GPU/VPU */
> +	val = readl_relaxed(gpc_base + GPC_CNTR);
> +	val |= GPU_VPU_PDN_REQ;
> +	writel_relaxed(val, gpc_base + GPC_CNTR);
> +
> +	/* Wait ISO + ISO2SW IPG clock cycles */
> +	ndelay((iso + iso2sw) * 1000 / 66);
> +
> +	regulator_disable(pu_reg);
> +
> +	return 0;
> +}
> +
> +static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd)
> +{
> +	int ret;
> +	u32 val;
> +	int sw, sw2iso;
> +
> +	ret = regulator_enable(pu_reg);
> +	if (ret) {
> +		pr_err("%s: failed to enable regulator: %d\n", __func__, ret);
> +		return ret;
> +	}
> +
> +	/* Gate off PU domain when GPU/VPU when powered down */
> +	writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
> +
> +	/* Read ISO and ISO2SW power down delays */
> +	val = readl_relaxed(gpc_base + GPC_PGC_GPU_PUPSCR);
> +	sw = val & 0x3f;
> +	sw2iso = (val >> 8) & 0x3f;
> +
> +	/* Request GPC to power up GPU/VPU */
> +	val = readl_relaxed(gpc_base + GPC_CNTR);
> +	val |= GPU_VPU_PUP_REQ;
> +	writel_relaxed(val, gpc_base + GPC_CNTR);
> +
> +	/* Wait ISO + ISO2SW IPG clock cycles */
> +	ndelay((sw + sw2iso) * 1000 / 66);
> +
> +	return 0;
> +}
> +
> +static struct generic_pm_domain imx6q_pu_domain = {
> +	.name = "PU",
> +	.power_off = imx6q_pm_pu_power_off,
> +	.power_on = imx6q_pm_pu_power_on,
> +};
> +
> +static int imx6q_pm_notifier_call(struct notifier_block *nb,
> +				  unsigned long event, void *data)
> +{
> +	struct generic_pm_domain *genpd;
> +	struct device *dev = data;
> +	struct device_node *np;
> +	int ret;
> +
> +	switch (event) {
> +	case BUS_NOTIFY_BIND_DRIVER:
> +		np = of_parse_phandle(dev->of_node, "power-domain", 0);
> +		if (!np || np != imx6q_pu_domain.of_node)
> +			return NOTIFY_DONE;
> +
> +		ret = pm_genpd_of_add_device(np, dev);
> +		if (ret)
> +			dev_err(dev, "failed to add to power domain: %d\n",
> +				ret);
> +		break;
> +	case BUS_NOTIFY_UNBOUND_DRIVER:
> +		genpd = dev_to_genpd(dev);
> +		if (IS_ERR(genpd) || genpd != &imx6q_pu_domain)
> +			return NOTIFY_DONE;
> +
> +		ret = pm_genpd_remove_device(genpd, dev);
> +		if (ret)
> +			dev_err(dev, "failed to remove from power domain: %d\n",
> +				ret);
> +		break;
> +	}
> +
> +	return NOTIFY_DONE;
> +}
> +
> +static struct notifier_block imx6q_platform_nb = {
> +	.notifier_call = imx6q_pm_notifier_call,
> +};
> +
> +static int imx_gpc_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np;
> +	int ret;
> +
> +	np = of_get_child_by_name(pdev->dev.of_node, "pu-power-domain");
> +	if (!np) {
> +		dev_err(&pdev->dev, "missing pu-power-domain node\n");
> +		return -EINVAL;
> +	}
> +	imx6q_pu_domain.of_node = np;
> +
> +	pu_reg = devm_regulator_get(&pdev->dev, "pu");
> +	if (IS_ERR(pu_reg)) {
> +		ret = PTR_ERR(pu_reg);
> +		dev_err(&pdev->dev, "failed to get pu regulator: %d\n", ret);
> +		return ret;
> +	}
> +
> +	/* The regulator is initially enabled */
> +	ret = regulator_enable(pu_reg);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to enable pu regulator: %d\n", ret);
> +		return ret;
> +	}
> +
> +	imx6q_pu_domain.of_node = np;
> +	imx6q_pm_pu_power_off(&imx6q_pu_domain);
> +	pm_genpd_init(&imx6q_pu_domain, NULL, true);

Turning off the PU power domain and supply voltage on boot isn't a good
idea if the kernel doesn't have runtime PM support compiled in. In that
case it should be left enabled:

--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -366,8 +366,12 @@ static int imx_gpc_probe(struct platform_device *pdev)
        regulator_allow_bypass(pu_reg, true);
 
        imx6q_pu_domain.of_node = np;
+#ifdef CONFIG_PM_RUNTIME
        imx6q_pm_pu_power_off(&imx6q_pu_domain);
        pm_genpd_init(&imx6q_pu_domain, NULL, true);
+#else
+       pm_genpd_init(&imx6q_pu_domain, NULL, false);
+#endif
        bus_register_notifier(&platform_bus_type, &imx6q_platform_nb);
 
        return 0;

> +	bus_register_notifier(&platform_bus_type, &imx6q_platform_nb);
> +
> +	return 0;
> +}
> +
> +static struct of_device_id imx_gpc_dt_ids[] = {
> +	{ .compatible = "fsl,imx6q-gpc" },
> +	{ }
> +};
> +
> +static struct platform_driver imx_gpc_driver = {
> +	.driver = {
> +		.name = "imx-gpc",
> +		.owner = THIS_MODULE,
> +		.of_match_table = imx_gpc_dt_ids,
> +	},
> +	.probe = imx_gpc_probe,
> +};
> +
> +static int __init imx_pgc_init(void)
> +{
> +	return platform_driver_register(&imx_gpc_driver);
> +}
> +subsys_initcall(imx_pgc_init);

regards
Philipp

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 2/7] ARM: imx6: gpc: Add PU power domain for GPU/VPU
@ 2014-02-13 16:41         ` Philipp Zabel
  0 siblings, 0 replies; 20+ messages in thread
From: Philipp Zabel @ 2014-02-13 16:41 UTC (permalink / raw)
  To: linux-arm-kernel

Am Donnerstag, den 13.02.2014, 15:39 +0100 schrieb Philipp Zabel:
> When generic pm domain support is enabled, the PGC can be used
> to completely gate power to the PU power domain containing GPU3D,
> GPU2D, and VPU cores.
> This code triggers the PGC powerdown sequence to disable the GPU/VPU
> isolation cells and gate power and then disables the PU regulator.
> To reenable, the reverse powerup sequence is triggered after the PU
> regulaotor is enabled again.
> 
> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> ---
> Changes since v1:
>  - Removed superfluous comment
>  - Link PU domain with its DT node, check for PU domain in bus notifier
>  - Turn off the PU power domain on boot
> ---
>  arch/arm/mach-imx/Kconfig |   2 +
>  arch/arm/mach-imx/gpc.c   | 170 ++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 172 insertions(+)
> 
> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> index 33567aa..3c58f2e 100644
> --- a/arch/arm/mach-imx/Kconfig
> +++ b/arch/arm/mach-imx/Kconfig
> @@ -808,6 +808,7 @@ config SOC_IMX6Q
>  	select PL310_ERRATA_727915 if CACHE_PL310
>  	select PL310_ERRATA_769419 if CACHE_PL310
>  	select PM_OPP if PM
> +	select PM_GENERIC_DOMAINS if PM
>  
>  	help
>  	  This enables support for Freescale i.MX6 Quad processor.
> @@ -827,6 +828,7 @@ config SOC_IMX6SL
>  	select PL310_ERRATA_588369 if CACHE_PL310
>  	select PL310_ERRATA_727915 if CACHE_PL310
>  	select PL310_ERRATA_769419 if CACHE_PL310
> +	select PM_GENERIC_DOMAINS if PM
>  
>  	help
>  	  This enables support for Freescale i.MX6 SoloLite processor.
> diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
> index 586e017..1dc4301 100644
> --- a/arch/arm/mach-imx/gpc.c
> +++ b/arch/arm/mach-imx/gpc.c
> @@ -10,19 +10,32 @@
>   * http://www.gnu.org/copyleft/gpl.html
>   */
>  
> +#include <linux/clk.h>
> +#include <linux/delay.h>
>  #include <linux/io.h>
>  #include <linux/irq.h>
>  #include <linux/of.h>
>  #include <linux/of_address.h>
>  #include <linux/of_irq.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_domain.h>
> +#include <linux/regulator/consumer.h>
>  #include <linux/irqchip/arm-gic.h>
>  #include "common.h"
> +#include "hardware.h"
>  
> +#define GPC_CNTR		0x000
>  #define GPC_IMR1		0x008
> +#define GPC_PGC_GPU_PDN		0x260
> +#define GPC_PGC_GPU_PUPSCR	0x264
> +#define GPC_PGC_GPU_PDNSCR	0x268
>  #define GPC_PGC_CPU_PDN		0x2a0
>  
>  #define IMR_NUM			4
>  
> +#define GPU_VPU_PUP_REQ		BIT(1)
> +#define GPU_VPU_PDN_REQ		BIT(0)
> +
>  static void __iomem *gpc_base;
>  static u32 gpc_wake_irqs[IMR_NUM];
>  static u32 gpc_saved_imrs[IMR_NUM];
> @@ -138,3 +151,160 @@ void __init imx_gpc_init(void)
>  	gic_arch_extn.irq_unmask = imx_gpc_irq_unmask;
>  	gic_arch_extn.irq_set_wake = imx_gpc_irq_set_wake;
>  }
> +
> +static struct regulator *pu_reg;
> +
> +static int imx6q_pm_pu_power_off(struct generic_pm_domain *genpd)
> +{
> +	u32 val;
> +	int iso, iso2sw;
> +
> +	/* Read ISO and ISO2SW power down delays */
> +	val = readl_relaxed(gpc_base + GPC_PGC_GPU_PDNSCR);
> +	iso = val & 0x3f;
> +	iso2sw = (val >> 8) & 0x3f;
> +
> +	/* Gate off PU domain when GPU/VPU when powered down */
> +	writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
> +
> +	/* Request GPC to power down GPU/VPU */
> +	val = readl_relaxed(gpc_base + GPC_CNTR);
> +	val |= GPU_VPU_PDN_REQ;
> +	writel_relaxed(val, gpc_base + GPC_CNTR);
> +
> +	/* Wait ISO + ISO2SW IPG clock cycles */
> +	ndelay((iso + iso2sw) * 1000 / 66);
> +
> +	regulator_disable(pu_reg);
> +
> +	return 0;
> +}
> +
> +static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd)
> +{
> +	int ret;
> +	u32 val;
> +	int sw, sw2iso;
> +
> +	ret = regulator_enable(pu_reg);
> +	if (ret) {
> +		pr_err("%s: failed to enable regulator: %d\n", __func__, ret);
> +		return ret;
> +	}
> +
> +	/* Gate off PU domain when GPU/VPU when powered down */
> +	writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
> +
> +	/* Read ISO and ISO2SW power down delays */
> +	val = readl_relaxed(gpc_base + GPC_PGC_GPU_PUPSCR);
> +	sw = val & 0x3f;
> +	sw2iso = (val >> 8) & 0x3f;
> +
> +	/* Request GPC to power up GPU/VPU */
> +	val = readl_relaxed(gpc_base + GPC_CNTR);
> +	val |= GPU_VPU_PUP_REQ;
> +	writel_relaxed(val, gpc_base + GPC_CNTR);
> +
> +	/* Wait ISO + ISO2SW IPG clock cycles */
> +	ndelay((sw + sw2iso) * 1000 / 66);
> +
> +	return 0;
> +}
> +
> +static struct generic_pm_domain imx6q_pu_domain = {
> +	.name = "PU",
> +	.power_off = imx6q_pm_pu_power_off,
> +	.power_on = imx6q_pm_pu_power_on,
> +};
> +
> +static int imx6q_pm_notifier_call(struct notifier_block *nb,
> +				  unsigned long event, void *data)
> +{
> +	struct generic_pm_domain *genpd;
> +	struct device *dev = data;
> +	struct device_node *np;
> +	int ret;
> +
> +	switch (event) {
> +	case BUS_NOTIFY_BIND_DRIVER:
> +		np = of_parse_phandle(dev->of_node, "power-domain", 0);
> +		if (!np || np != imx6q_pu_domain.of_node)
> +			return NOTIFY_DONE;
> +
> +		ret = pm_genpd_of_add_device(np, dev);
> +		if (ret)
> +			dev_err(dev, "failed to add to power domain: %d\n",
> +				ret);
> +		break;
> +	case BUS_NOTIFY_UNBOUND_DRIVER:
> +		genpd = dev_to_genpd(dev);
> +		if (IS_ERR(genpd) || genpd != &imx6q_pu_domain)
> +			return NOTIFY_DONE;
> +
> +		ret = pm_genpd_remove_device(genpd, dev);
> +		if (ret)
> +			dev_err(dev, "failed to remove from power domain: %d\n",
> +				ret);
> +		break;
> +	}
> +
> +	return NOTIFY_DONE;
> +}
> +
> +static struct notifier_block imx6q_platform_nb = {
> +	.notifier_call = imx6q_pm_notifier_call,
> +};
> +
> +static int imx_gpc_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np;
> +	int ret;
> +
> +	np = of_get_child_by_name(pdev->dev.of_node, "pu-power-domain");
> +	if (!np) {
> +		dev_err(&pdev->dev, "missing pu-power-domain node\n");
> +		return -EINVAL;
> +	}
> +	imx6q_pu_domain.of_node = np;
> +
> +	pu_reg = devm_regulator_get(&pdev->dev, "pu");
> +	if (IS_ERR(pu_reg)) {
> +		ret = PTR_ERR(pu_reg);
> +		dev_err(&pdev->dev, "failed to get pu regulator: %d\n", ret);
> +		return ret;
> +	}
> +
> +	/* The regulator is initially enabled */
> +	ret = regulator_enable(pu_reg);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to enable pu regulator: %d\n", ret);
> +		return ret;
> +	}
> +
> +	imx6q_pu_domain.of_node = np;
> +	imx6q_pm_pu_power_off(&imx6q_pu_domain);
> +	pm_genpd_init(&imx6q_pu_domain, NULL, true);

Turning off the PU power domain and supply voltage on boot isn't a good
idea if the kernel doesn't have runtime PM support compiled in. In that
case it should be left enabled:

--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -366,8 +366,12 @@ static int imx_gpc_probe(struct platform_device *pdev)
        regulator_allow_bypass(pu_reg, true);
 
        imx6q_pu_domain.of_node = np;
+#ifdef CONFIG_PM_RUNTIME
        imx6q_pm_pu_power_off(&imx6q_pu_domain);
        pm_genpd_init(&imx6q_pu_domain, NULL, true);
+#else
+       pm_genpd_init(&imx6q_pu_domain, NULL, false);
+#endif
        bus_register_notifier(&platform_bus_type, &imx6q_platform_nb);
 
        return 0;

> +	bus_register_notifier(&platform_bus_type, &imx6q_platform_nb);
> +
> +	return 0;
> +}
> +
> +static struct of_device_id imx_gpc_dt_ids[] = {
> +	{ .compatible = "fsl,imx6q-gpc" },
> +	{ }
> +};
> +
> +static struct platform_driver imx_gpc_driver = {
> +	.driver = {
> +		.name = "imx-gpc",
> +		.owner = THIS_MODULE,
> +		.of_match_table = imx_gpc_dt_ids,
> +	},
> +	.probe = imx_gpc_probe,
> +};
> +
> +static int __init imx_pgc_init(void)
> +{
> +	return platform_driver_register(&imx_gpc_driver);
> +}
> +subsys_initcall(imx_pgc_init);

regards
Philipp

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 2/7] ARM: imx6: gpc: Add PU power domain for GPU/VPU
  2014-02-13 14:39     ` Philipp Zabel
@ 2014-02-17  1:55         ` Shawn Guo
  -1 siblings, 0 replies; 20+ messages in thread
From: Shawn Guo @ 2014-02-17  1:55 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Rob Herring, Mark Rutland, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Thu, Feb 13, 2014 at 03:39:05PM +0100, Philipp Zabel wrote:
> +static int imx_gpc_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np;
> +	int ret;
> +
> +	np = of_get_child_by_name(pdev->dev.of_node, "pu-power-domain");
> +	if (!np) {
> +		dev_err(&pdev->dev, "missing pu-power-domain node\n");
> +		return -EINVAL;
> +	}
> +	imx6q_pu_domain.of_node = np;

Once ...

> +
> +	pu_reg = devm_regulator_get(&pdev->dev, "pu");
> +	if (IS_ERR(pu_reg)) {
> +		ret = PTR_ERR(pu_reg);
> +		dev_err(&pdev->dev, "failed to get pu regulator: %d\n", ret);
> +		return ret;
> +	}
> +
> +	/* The regulator is initially enabled */
> +	ret = regulator_enable(pu_reg);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to enable pu regulator: %d\n", ret);
> +		return ret;
> +	}
> +
> +	imx6q_pu_domain.of_node = np;

Twice.

Shawn

> +	imx6q_pm_pu_power_off(&imx6q_pu_domain);
> +	pm_genpd_init(&imx6q_pu_domain, NULL, true);
> +	bus_register_notifier(&platform_bus_type, &imx6q_platform_nb);
> +
> +	return 0;
> +}
> +
> +static struct of_device_id imx_gpc_dt_ids[] = {
> +	{ .compatible = "fsl,imx6q-gpc" },
> +	{ }
> +};
> +
> +static struct platform_driver imx_gpc_driver = {
> +	.driver = {
> +		.name = "imx-gpc",
> +		.owner = THIS_MODULE,
> +		.of_match_table = imx_gpc_dt_ids,
> +	},
> +	.probe = imx_gpc_probe,
> +};
> +
> +static int __init imx_pgc_init(void)
> +{
> +	return platform_driver_register(&imx_gpc_driver);
> +}
> +subsys_initcall(imx_pgc_init);
> -- 
> 1.8.5.3
> 

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 2/7] ARM: imx6: gpc: Add PU power domain for GPU/VPU
@ 2014-02-17  1:55         ` Shawn Guo
  0 siblings, 0 replies; 20+ messages in thread
From: Shawn Guo @ 2014-02-17  1:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 13, 2014 at 03:39:05PM +0100, Philipp Zabel wrote:
> +static int imx_gpc_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np;
> +	int ret;
> +
> +	np = of_get_child_by_name(pdev->dev.of_node, "pu-power-domain");
> +	if (!np) {
> +		dev_err(&pdev->dev, "missing pu-power-domain node\n");
> +		return -EINVAL;
> +	}
> +	imx6q_pu_domain.of_node = np;

Once ...

> +
> +	pu_reg = devm_regulator_get(&pdev->dev, "pu");
> +	if (IS_ERR(pu_reg)) {
> +		ret = PTR_ERR(pu_reg);
> +		dev_err(&pdev->dev, "failed to get pu regulator: %d\n", ret);
> +		return ret;
> +	}
> +
> +	/* The regulator is initially enabled */
> +	ret = regulator_enable(pu_reg);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to enable pu regulator: %d\n", ret);
> +		return ret;
> +	}
> +
> +	imx6q_pu_domain.of_node = np;

Twice.

Shawn

> +	imx6q_pm_pu_power_off(&imx6q_pu_domain);
> +	pm_genpd_init(&imx6q_pu_domain, NULL, true);
> +	bus_register_notifier(&platform_bus_type, &imx6q_platform_nb);
> +
> +	return 0;
> +}
> +
> +static struct of_device_id imx_gpc_dt_ids[] = {
> +	{ .compatible = "fsl,imx6q-gpc" },
> +	{ }
> +};
> +
> +static struct platform_driver imx_gpc_driver = {
> +	.driver = {
> +		.name = "imx-gpc",
> +		.owner = THIS_MODULE,
> +		.of_match_table = imx_gpc_dt_ids,
> +	},
> +	.probe = imx_gpc_probe,
> +};
> +
> +static int __init imx_pgc_init(void)
> +{
> +	return platform_driver_register(&imx_gpc_driver);
> +}
> +subsys_initcall(imx_pgc_init);
> -- 
> 1.8.5.3
> 

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2014-02-17  1:55 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-13 14:39 [PATCH v2 0/7] i.MX6 PU power domain support Philipp Zabel
2014-02-13 14:39 ` Philipp Zabel
     [not found] ` <1392302350-11729-1-git-send-email-p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2014-02-13 14:39   ` [PATCH v2 1/7] Documentation: Add device tree bindings for Freescale i.MX GPC Philipp Zabel
2014-02-13 14:39     ` Philipp Zabel
2014-02-13 14:39   ` [PATCH v2 2/7] ARM: imx6: gpc: Add PU power domain for GPU/VPU Philipp Zabel
2014-02-13 14:39     ` Philipp Zabel
     [not found]     ` <1392302350-11729-3-git-send-email-p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2014-02-13 16:41       ` Philipp Zabel
2014-02-13 16:41         ` Philipp Zabel
2014-02-17  1:55       ` Shawn Guo
2014-02-17  1:55         ` Shawn Guo
2014-02-13 14:39   ` [PATCH v2 3/7] ARM: imx6: gpc: Add pm clock support to PU power domain Philipp Zabel
2014-02-13 14:39     ` Philipp Zabel
2014-02-13 14:39   ` [PATCH v2 4/7] ARM: imx6: gpc: Add observed worst case latencies Philipp Zabel
2014-02-13 14:39     ` Philipp Zabel
2014-02-13 14:39   ` [PATCH v2 5/7] ARM: dts: imx6qdl: Allow disabling the PU regulator, add a enable ramp delay Philipp Zabel
2014-02-13 14:39     ` Philipp Zabel
2014-02-13 14:39   ` [PATCH v2 6/7] ARM: dts: imx6qdl: Add power-domain information to gpc node Philipp Zabel
2014-02-13 14:39     ` Philipp Zabel
2014-02-13 14:39   ` [PATCH v2 7/7] ARM: dts: imx6sl: " Philipp Zabel
2014-02-13 14:39     ` Philipp Zabel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.