All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V3 00/19] Add generic PM domain support for Tegra SoCs
@ 2015-07-13 12:39 ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Jon Hunter

This series is based upon the V2 series from Vince Hsu [1]. The code
for the MC flush operations and PMC code for the generic PM domains
has been re-written to simplify and consolidate legacy/existing support
for power-domains on the Tegra SoC.

This series has been boot tested on various 32-bit Tegra platforms
as well as compile tested for 64-bit ARM. A summary of the results is
available here [2]. Would be great to get some more testing for PCI,
SATA, GR3D and DRM.

Summary:

Patch 1:     Adds the new function of_reset_control_get_by_index().
Patch 2-5:   Add the MC flush operations for Tegra30/Tegra114/Tegra124.
Patch 6:     Is a PLLD fix for Tegra114.
Patch 7-9:   PMC preparation for generic PM domains.
Patch 10-13: Update drivers to support generic PM domains
Patch 14:    Add DT documentation for tegra generic PM domains
Patch 15:    Add PMC generic DM domains support
Patch 16:    Remove legacy functions
Patch 17-18: Add DT bindings for tegra124
Patch 19:    Enable generic PM domains for tegra


Changes:
   v3:
   * Re-wrote and simplified MC flush code
   * Re-wrote PMC code for generic PM domains to permit devices to use
     legacy DT blobs without generic PM domain info.
   * Re-worked DRM, PCI, AHCI and GR3D drivers to allow then to work
     with and without generic PM domains.
   * Added DT documentation for tegra generic PM domain bindings.
   * Dropped DT bindings for T30 and T114 (plan to add later)

   v2 (Vince Hsu):
   * Add support for Tegra30/Tegra114
   * Address Alex's comments

[1] https://lkml.org/lkml/2015/3/12/284
[2] https://nvtb.github.io//epmt/jonathanh-tester/test_20150713051933_58fc293c9467f52c51f1e52e5d5a8da174b8550a/20150713051933/


Jon Hunter (12):
  memory: tegra: Add MC flush support
  soc: tegra: pmc: Wait for powergate state to change
  soc: tegra: pmc: Clean-up PMC helper functions
  soc: tegra: pmc: Prepare for migrating to generic PM domains
  drm/tegra: dc: Prepare for generic PM domains
  PCI: tegra: Add support for generic PM domains
  ata: ahci_tegra: Add support for generic PM domains
  drm/tegra: gr3d: Add support for generic PM domains
  Documentation: DT: bindings: Add power domain info for NVIDIA PMC
  soc: tegra: pmc: Add generic PM domain support
  soc: tegra: pmc: Remove the deprecated powergate APIs
  ARM: tegra: Add PM domain device nodes to Tegra124 DT

Vince Hsu (7):
  reset: add of_reset_control_get_by_index()
  memory: tegra: add flush operation for Tegra30 memory clients
  memory: tegra: add flush operation for Tegra114 memory clients
  memory: tegra: add flush operation for Tegra124 memory clients
  clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2
  ARM: tegra: add GPU power supply to Jetson TK1 DT
  ARM: tegra: select PM_GENERIC_DOMAINS

 .../bindings/arm/tegra/nvidia,tegra20-pmc.txt      |  99 ++++
 arch/arm/boot/dts/tegra124-jetson-tk1.dts          |   6 +-
 arch/arm/boot/dts/tegra124.dtsi                    |  80 +++
 arch/arm/mach-tegra/Kconfig                        |   1 +
 arch/arm/mach-tegra/platsmp.c                      |  18 +-
 drivers/ata/ahci_tegra.c                           |  51 +-
 drivers/clk/tegra/clk-tegra114.c                   |   6 +-
 drivers/gpu/drm/tegra/dc.c                         |  94 +--
 drivers/gpu/drm/tegra/gr3d.c                       |  57 +-
 drivers/memory/tegra/mc.c                          | 110 ++++
 drivers/memory/tegra/mc.h                          |   2 +
 drivers/memory/tegra/tegra114.c                    |  21 +
 drivers/memory/tegra/tegra124.c                    |  31 +
 drivers/memory/tegra/tegra30.c                     |  24 +
 drivers/pci/host/pci-tegra.c                       |  49 +-
 drivers/reset/core.c                               |  40 +-
 drivers/soc/tegra/pmc.c                            | 647 ++++++++++++++++++---
 include/dt-bindings/power/tegra-powergate.h        |  42 ++
 include/linux/reset.h                              |   9 +
 include/soc/tegra/mc.h                             |  34 ++
 include/soc/tegra/pmc.h                            |  74 +--
 21 files changed, 1264 insertions(+), 231 deletions(-)
 create mode 100644 include/dt-bindings/power/tegra-powergate.h

-- 
2.1.4

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

* [PATCH V3 00/19] Add generic PM domain support for Tegra SoCs
@ 2015-07-13 12:39 ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

This series is based upon the V2 series from Vince Hsu [1]. The code
for the MC flush operations and PMC code for the generic PM domains
has been re-written to simplify and consolidate legacy/existing support
for power-domains on the Tegra SoC.

This series has been boot tested on various 32-bit Tegra platforms
as well as compile tested for 64-bit ARM. A summary of the results is
available here [2]. Would be great to get some more testing for PCI,
SATA, GR3D and DRM.

Summary:

Patch 1:     Adds the new function of_reset_control_get_by_index().
Patch 2-5:   Add the MC flush operations for Tegra30/Tegra114/Tegra124.
Patch 6:     Is a PLLD fix for Tegra114.
Patch 7-9:   PMC preparation for generic PM domains.
Patch 10-13: Update drivers to support generic PM domains
Patch 14:    Add DT documentation for tegra generic PM domains
Patch 15:    Add PMC generic DM domains support
Patch 16:    Remove legacy functions
Patch 17-18: Add DT bindings for tegra124
Patch 19:    Enable generic PM domains for tegra


Changes:
   v3:
   * Re-wrote and simplified MC flush code
   * Re-wrote PMC code for generic PM domains to permit devices to use
     legacy DT blobs without generic PM domain info.
   * Re-worked DRM, PCI, AHCI and GR3D drivers to allow then to work
     with and without generic PM domains.
   * Added DT documentation for tegra generic PM domain bindings.
   * Dropped DT bindings for T30 and T114 (plan to add later)

   v2 (Vince Hsu):
   * Add support for Tegra30/Tegra114
   * Address Alex's comments

[1] https://lkml.org/lkml/2015/3/12/284
[2] https://nvtb.github.io//epmt/jonathanh-tester/test_20150713051933_58fc293c9467f52c51f1e52e5d5a8da174b8550a/20150713051933/


Jon Hunter (12):
  memory: tegra: Add MC flush support
  soc: tegra: pmc: Wait for powergate state to change
  soc: tegra: pmc: Clean-up PMC helper functions
  soc: tegra: pmc: Prepare for migrating to generic PM domains
  drm/tegra: dc: Prepare for generic PM domains
  PCI: tegra: Add support for generic PM domains
  ata: ahci_tegra: Add support for generic PM domains
  drm/tegra: gr3d: Add support for generic PM domains
  Documentation: DT: bindings: Add power domain info for NVIDIA PMC
  soc: tegra: pmc: Add generic PM domain support
  soc: tegra: pmc: Remove the deprecated powergate APIs
  ARM: tegra: Add PM domain device nodes to Tegra124 DT

Vince Hsu (7):
  reset: add of_reset_control_get_by_index()
  memory: tegra: add flush operation for Tegra30 memory clients
  memory: tegra: add flush operation for Tegra114 memory clients
  memory: tegra: add flush operation for Tegra124 memory clients
  clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2
  ARM: tegra: add GPU power supply to Jetson TK1 DT
  ARM: tegra: select PM_GENERIC_DOMAINS

 .../bindings/arm/tegra/nvidia,tegra20-pmc.txt      |  99 ++++
 arch/arm/boot/dts/tegra124-jetson-tk1.dts          |   6 +-
 arch/arm/boot/dts/tegra124.dtsi                    |  80 +++
 arch/arm/mach-tegra/Kconfig                        |   1 +
 arch/arm/mach-tegra/platsmp.c                      |  18 +-
 drivers/ata/ahci_tegra.c                           |  51 +-
 drivers/clk/tegra/clk-tegra114.c                   |   6 +-
 drivers/gpu/drm/tegra/dc.c                         |  94 +--
 drivers/gpu/drm/tegra/gr3d.c                       |  57 +-
 drivers/memory/tegra/mc.c                          | 110 ++++
 drivers/memory/tegra/mc.h                          |   2 +
 drivers/memory/tegra/tegra114.c                    |  21 +
 drivers/memory/tegra/tegra124.c                    |  31 +
 drivers/memory/tegra/tegra30.c                     |  24 +
 drivers/pci/host/pci-tegra.c                       |  49 +-
 drivers/reset/core.c                               |  40 +-
 drivers/soc/tegra/pmc.c                            | 647 ++++++++++++++++++---
 include/dt-bindings/power/tegra-powergate.h        |  42 ++
 include/linux/reset.h                              |   9 +
 include/soc/tegra/mc.h                             |  34 ++
 include/soc/tegra/pmc.h                            |  74 +--
 21 files changed, 1264 insertions(+), 231 deletions(-)
 create mode 100644 include/dt-bindings/power/tegra-powergate.h

-- 
2.1.4

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

* [PATCH V3 01/19] reset: add of_reset_control_get_by_index()
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39     ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Jon Hunter

From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Add of_reset_control_get_by_index() to allow the drivers to get reset
device without knowing its name.

Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
[jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org: Updated stub function to return -ENOTSUPP instead
 of -ENOSYS which should only be used for system calls.]
Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

---
v3: addressed comments from Philipp
v2: minor changes according to Alex's comments
---
 drivers/reset/core.c  | 40 +++++++++++++++++++++++++++++-----------
 include/linux/reset.h |  9 +++++++++
 2 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 7955e00d04d4..81ae17d15480 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -141,27 +141,24 @@ int reset_control_status(struct reset_control *rstc)
 EXPORT_SYMBOL_GPL(reset_control_status);
 
 /**
- * of_reset_control_get - Lookup and obtain a reference to a reset controller.
+ * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
+ * controller by index.
  * @node: device to be reset by the controller
- * @id: reset line name
- *
- * Returns a struct reset_control or IS_ERR() condition containing errno.
+ * @index: index of the reset controller
  *
- * Use of id names is optional.
+ * This is to be used to perform a list of resets for a device or power domain
+ * in whatever order. Returns a struct reset_control or IS_ERR() condition
+ * containing errno.
  */
-struct reset_control *of_reset_control_get(struct device_node *node,
-					   const char *id)
+struct reset_control *of_reset_control_get_by_index(struct device_node *node,
+					   int index)
 {
 	struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
 	struct reset_controller_dev *r, *rcdev;
 	struct of_phandle_args args;
-	int index = 0;
 	int rstc_id;
 	int ret;
 
-	if (id)
-		index = of_property_match_string(node,
-						 "reset-names", id);
 	ret = of_parse_phandle_with_args(node, "resets", "#reset-cells",
 					 index, &args);
 	if (ret)
@@ -202,6 +199,27 @@ struct reset_control *of_reset_control_get(struct device_node *node,
 
 	return rstc;
 }
+EXPORT_SYMBOL_GPL(of_reset_control_get_by_index);
+
+/**
+ * of_reset_control_get - Lookup and obtain a reference to a reset controller.
+ * @node: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Returns a struct reset_control or IS_ERR() condition containing errno.
+ *
+ * Use of id names is optional.
+ */
+struct reset_control *of_reset_control_get(struct device_node *node,
+					   const char *id)
+{
+	int index = 0;
+
+	if (id)
+		index = of_property_match_string(node,
+						 "reset-names", id);
+	return of_reset_control_get_by_index(node, index);
+}
 EXPORT_SYMBOL_GPL(of_reset_control_get);
 
 /**
diff --git a/include/linux/reset.h b/include/linux/reset.h
index da5602bd77d7..26f1b53386d8 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -38,6 +38,9 @@ static inline struct reset_control *devm_reset_control_get_optional(
 struct reset_control *of_reset_control_get(struct device_node *node,
 					   const char *id);
 
+struct reset_control *of_reset_control_get_by_index(
+					struct device_node *node, int index);
+
 #else
 
 static inline int reset_control_reset(struct reset_control *rstc)
@@ -92,6 +95,12 @@ static inline struct reset_control *of_reset_control_get(
 	return ERR_PTR(-ENOSYS);
 }
 
+static inline struct reset_control *of_reset_control_get_by_index(
+				struct device_node *node, int index)
+{
+	return ERR_PTR(-ENOTSUPP);
+}
+
 #endif /* CONFIG_RESET_CONTROLLER */
 
 #endif
-- 
2.1.4

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

* [PATCH V3 01/19] reset: add of_reset_control_get_by_index()
@ 2015-07-13 12:39     ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vince Hsu <vinceh@nvidia.com>

Add of_reset_control_get_by_index() to allow the drivers to get reset
device without knowing its name.

Signed-off-by: Vince Hsu <vinceh@nvidia.com>
[jonathanh at nvidia.com: Updated stub function to return -ENOTSUPP instead
 of -ENOSYS which should only be used for system calls.]
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>

---
v3: addressed comments from Philipp
v2: minor changes according to Alex's comments
---
 drivers/reset/core.c  | 40 +++++++++++++++++++++++++++++-----------
 include/linux/reset.h |  9 +++++++++
 2 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 7955e00d04d4..81ae17d15480 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -141,27 +141,24 @@ int reset_control_status(struct reset_control *rstc)
 EXPORT_SYMBOL_GPL(reset_control_status);
 
 /**
- * of_reset_control_get - Lookup and obtain a reference to a reset controller.
+ * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
+ * controller by index.
  * @node: device to be reset by the controller
- * @id: reset line name
- *
- * Returns a struct reset_control or IS_ERR() condition containing errno.
+ * @index: index of the reset controller
  *
- * Use of id names is optional.
+ * This is to be used to perform a list of resets for a device or power domain
+ * in whatever order. Returns a struct reset_control or IS_ERR() condition
+ * containing errno.
  */
-struct reset_control *of_reset_control_get(struct device_node *node,
-					   const char *id)
+struct reset_control *of_reset_control_get_by_index(struct device_node *node,
+					   int index)
 {
 	struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
 	struct reset_controller_dev *r, *rcdev;
 	struct of_phandle_args args;
-	int index = 0;
 	int rstc_id;
 	int ret;
 
-	if (id)
-		index = of_property_match_string(node,
-						 "reset-names", id);
 	ret = of_parse_phandle_with_args(node, "resets", "#reset-cells",
 					 index, &args);
 	if (ret)
@@ -202,6 +199,27 @@ struct reset_control *of_reset_control_get(struct device_node *node,
 
 	return rstc;
 }
+EXPORT_SYMBOL_GPL(of_reset_control_get_by_index);
+
+/**
+ * of_reset_control_get - Lookup and obtain a reference to a reset controller.
+ * @node: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Returns a struct reset_control or IS_ERR() condition containing errno.
+ *
+ * Use of id names is optional.
+ */
+struct reset_control *of_reset_control_get(struct device_node *node,
+					   const char *id)
+{
+	int index = 0;
+
+	if (id)
+		index = of_property_match_string(node,
+						 "reset-names", id);
+	return of_reset_control_get_by_index(node, index);
+}
 EXPORT_SYMBOL_GPL(of_reset_control_get);
 
 /**
diff --git a/include/linux/reset.h b/include/linux/reset.h
index da5602bd77d7..26f1b53386d8 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -38,6 +38,9 @@ static inline struct reset_control *devm_reset_control_get_optional(
 struct reset_control *of_reset_control_get(struct device_node *node,
 					   const char *id);
 
+struct reset_control *of_reset_control_get_by_index(
+					struct device_node *node, int index);
+
 #else
 
 static inline int reset_control_reset(struct reset_control *rstc)
@@ -92,6 +95,12 @@ static inline struct reset_control *of_reset_control_get(
 	return ERR_PTR(-ENOSYS);
 }
 
+static inline struct reset_control *of_reset_control_get_by_index(
+				struct device_node *node, int index)
+{
+	return ERR_PTR(-ENOTSUPP);
+}
+
 #endif /* CONFIG_RESET_CONTROLLER */
 
 #endif
-- 
2.1.4

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

* [PATCH V3 02/19] memory: tegra: Add MC flush support
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39     ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Jon Hunter

The Tegra memory controller implements a flush feature to flush pending
accesses and prevent further accesses from occurring. This feature is
used when powering down IP blocks to ensure the IP block is in a good
state. The flushes are organised by software groups and IP blocks are
assigned in hardware to the different software groups. Add helper
functions for requesting a handle to an MC flush for a given
software group and enabling/disabling the MC flush itself.

This is based upon a change by Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>.

Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/memory/tegra/mc.h |   2 +
 include/soc/tegra/mc.h    |  34 ++++++++++++++
 3 files changed, 146 insertions(+)

diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
index c71ede67e6c8..fb8da3d4caf4 100644
--- a/drivers/memory/tegra/mc.c
+++ b/drivers/memory/tegra/mc.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -71,6 +72,107 @@ static const struct of_device_id tegra_mc_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tegra_mc_of_match);
 
+const struct tegra_mc_flush *tegra_mc_flush_get(struct tegra_mc *mc,
+						unsigned int swgroup)
+{
+	const struct tegra_mc_flush *flush = NULL;
+	int i;
+
+	mutex_lock(&mc->lock);
+
+	for (i = 0; i < mc->soc->num_flushes; i++) {
+		if (mc->soc->flushes[i].swgroup == swgroup) {
+			if (mc->flush_reserved[i] == false) {
+				mc->flush_reserved[i] = true;
+				flush = &mc->soc->flushes[i];
+			}
+			break;
+		}
+	}
+
+	mutex_unlock(&mc->lock);
+
+	return flush;
+}
+EXPORT_SYMBOL(tegra_mc_flush_get);
+
+static bool tegra_mc_flush_done(struct tegra_mc *mc,
+				const struct tegra_mc_flush *flush)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(100);
+	int i;
+	u32 val;
+
+	while (time_before(jiffies, timeout)) {
+		val = mc_readl(mc, flush->status);
+
+		/*
+		 * If the flush bit is still set it
+		 * is not done and so wait then retry.
+		 */
+		if (val & BIT(flush->bit))
+			goto retry;
+
+		/*
+		 * Depending on the tegra SoC, it may be necessary to read
+		 * the status register multiple times to ensure the value
+		 * read is correct. Some tegra devices have a HW issue where
+		 * reading the status register shortly after writing the
+		 * control register (on the order of 5 cycles) may return
+		 * an incorrect value.
+		 */
+		for (i = 0; i < mc->soc->metastable_flush_reads; i++) {
+			if (mc_readl(mc, flush->status) != val)
+				goto retry;
+		}
+
+		/*
+		 * The flush is complete and so return.
+		 */
+		return 0;
+retry:
+		udelay(10);
+	}
+
+	return -ETIMEDOUT;
+}
+
+int tegra_mc_flush(struct tegra_mc *mc, const struct tegra_mc_flush *flush,
+		   bool enable)
+{
+	int ret = 0;
+	u32 val;
+
+	if (!mc || !flush)
+		return -EINVAL;
+
+	mutex_lock(&mc->lock);
+
+	val = mc_readl(mc, flush->ctrl);
+
+	if (enable)
+		val |= BIT(flush->bit);
+	else
+		val &= ~BIT(flush->bit);
+
+	mc_writel(mc, val, flush->ctrl);
+	mc_readl(mc, flush->ctrl);
+
+	/*
+	 * If activating the flush, poll the
+	 * status register until the flush is done.
+	 */
+	if (enable)
+		ret = tegra_mc_flush_done(mc, flush);
+
+	mutex_unlock(&mc->lock);
+
+	dev_dbg(mc->dev, "%s bit %d\n", __func__, flush->bit);
+
+	return ret;
+}
+EXPORT_SYMBOL(tegra_mc_flush);
+
 static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
 {
 	unsigned long long tick;
@@ -359,6 +461,12 @@ static int tegra_mc_probe(struct platform_device *pdev)
 	mc->soc = match->data;
 	mc->dev = &pdev->dev;
 
+	mc->flush_reserved = devm_kcalloc(&pdev->dev, mc->soc->num_flushes,
+					  sizeof(mc->flush_reserved),
+					  GFP_KERNEL);
+	if (!mc->flush_reserved)
+		return -ENOMEM;
+
 	/* length of MC tick in nanoseconds */
 	mc->tick = 30;
 
@@ -410,6 +518,8 @@ static int tegra_mc_probe(struct platform_device *pdev)
 		return err;
 	}
 
+	mutex_init(&mc->lock);
+
 	value = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
 		MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
 		MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM;
diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h
index b7361b0a6696..0f59d49b735b 100644
--- a/drivers/memory/tegra/mc.h
+++ b/drivers/memory/tegra/mc.h
@@ -14,6 +14,8 @@
 
 #include <soc/tegra/mc.h>
 
+#define MC_FLUSH_METASTABLE_READS	5
+
 static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset)
 {
 	return readl(mc->regs + offset);
diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h
index 1ab2813273cd..b634c6df79eb 100644
--- a/include/soc/tegra/mc.h
+++ b/include/soc/tegra/mc.h
@@ -45,6 +45,13 @@ struct tegra_mc_client {
 	struct tegra_mc_la la;
 };
 
+struct tegra_mc_flush {
+	unsigned int swgroup;
+	unsigned int ctrl;
+	unsigned int status;
+	unsigned int bit;
+};
+
 struct tegra_smmu_swgroup {
 	const char *name;
 	unsigned int swgroup;
@@ -96,6 +103,10 @@ struct tegra_mc_soc {
 	const struct tegra_mc_client *clients;
 	unsigned int num_clients;
 
+	const struct tegra_mc_flush *flushes;
+	unsigned int num_flushes;
+	unsigned int metastable_flush_reads;
+
 	const unsigned long *emem_regs;
 	unsigned int num_emem_regs;
 
@@ -117,9 +128,32 @@ struct tegra_mc {
 
 	struct tegra_mc_timing *timings;
 	unsigned int num_timings;
+
+	bool *flush_reserved;
+
+	struct mutex lock;
 };
 
 void tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate);
 unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc);
 
+#ifdef CONFIG_TEGRA_MC
+const struct tegra_mc_flush *tegra_mc_flush_get(struct tegra_mc *mc,
+						unsigned int swgroup);
+int tegra_mc_flush(struct tegra_mc *mc, const struct tegra_mc_flush *s,
+		   bool enable);
+#else
+const struct tegra_mc_flush *tegra_mc_flush_get(struct tegra_mc *mc,
+						unsigned int swgroup)
+{
+	return NULL;
+}
+
+int tegra_mc_flush(struct tegra_mc *mc, const struct tegra_mc_flush *s,
+		   bool enable)
+{
+	return -ENOTSUPP;
+}
+#endif
+
 #endif /* __SOC_TEGRA_MC_H__ */
-- 
2.1.4

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

* [PATCH V3 02/19] memory: tegra: Add MC flush support
@ 2015-07-13 12:39     ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

The Tegra memory controller implements a flush feature to flush pending
accesses and prevent further accesses from occurring. This feature is
used when powering down IP blocks to ensure the IP block is in a good
state. The flushes are organised by software groups and IP blocks are
assigned in hardware to the different software groups. Add helper
functions for requesting a handle to an MC flush for a given
software group and enabling/disabling the MC flush itself.

This is based upon a change by Vince Hsu <vinceh@nvidia.com>.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/memory/tegra/mc.h |   2 +
 include/soc/tegra/mc.h    |  34 ++++++++++++++
 3 files changed, 146 insertions(+)

diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
index c71ede67e6c8..fb8da3d4caf4 100644
--- a/drivers/memory/tegra/mc.c
+++ b/drivers/memory/tegra/mc.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -71,6 +72,107 @@ static const struct of_device_id tegra_mc_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tegra_mc_of_match);
 
+const struct tegra_mc_flush *tegra_mc_flush_get(struct tegra_mc *mc,
+						unsigned int swgroup)
+{
+	const struct tegra_mc_flush *flush = NULL;
+	int i;
+
+	mutex_lock(&mc->lock);
+
+	for (i = 0; i < mc->soc->num_flushes; i++) {
+		if (mc->soc->flushes[i].swgroup == swgroup) {
+			if (mc->flush_reserved[i] == false) {
+				mc->flush_reserved[i] = true;
+				flush = &mc->soc->flushes[i];
+			}
+			break;
+		}
+	}
+
+	mutex_unlock(&mc->lock);
+
+	return flush;
+}
+EXPORT_SYMBOL(tegra_mc_flush_get);
+
+static bool tegra_mc_flush_done(struct tegra_mc *mc,
+				const struct tegra_mc_flush *flush)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(100);
+	int i;
+	u32 val;
+
+	while (time_before(jiffies, timeout)) {
+		val = mc_readl(mc, flush->status);
+
+		/*
+		 * If the flush bit is still set it
+		 * is not done and so wait then retry.
+		 */
+		if (val & BIT(flush->bit))
+			goto retry;
+
+		/*
+		 * Depending on the tegra SoC, it may be necessary to read
+		 * the status register multiple times to ensure the value
+		 * read is correct. Some tegra devices have a HW issue where
+		 * reading the status register shortly after writing the
+		 * control register (on the order of 5 cycles) may return
+		 * an incorrect value.
+		 */
+		for (i = 0; i < mc->soc->metastable_flush_reads; i++) {
+			if (mc_readl(mc, flush->status) != val)
+				goto retry;
+		}
+
+		/*
+		 * The flush is complete and so return.
+		 */
+		return 0;
+retry:
+		udelay(10);
+	}
+
+	return -ETIMEDOUT;
+}
+
+int tegra_mc_flush(struct tegra_mc *mc, const struct tegra_mc_flush *flush,
+		   bool enable)
+{
+	int ret = 0;
+	u32 val;
+
+	if (!mc || !flush)
+		return -EINVAL;
+
+	mutex_lock(&mc->lock);
+
+	val = mc_readl(mc, flush->ctrl);
+
+	if (enable)
+		val |= BIT(flush->bit);
+	else
+		val &= ~BIT(flush->bit);
+
+	mc_writel(mc, val, flush->ctrl);
+	mc_readl(mc, flush->ctrl);
+
+	/*
+	 * If activating the flush, poll the
+	 * status register until the flush is done.
+	 */
+	if (enable)
+		ret = tegra_mc_flush_done(mc, flush);
+
+	mutex_unlock(&mc->lock);
+
+	dev_dbg(mc->dev, "%s bit %d\n", __func__, flush->bit);
+
+	return ret;
+}
+EXPORT_SYMBOL(tegra_mc_flush);
+
 static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
 {
 	unsigned long long tick;
@@ -359,6 +461,12 @@ static int tegra_mc_probe(struct platform_device *pdev)
 	mc->soc = match->data;
 	mc->dev = &pdev->dev;
 
+	mc->flush_reserved = devm_kcalloc(&pdev->dev, mc->soc->num_flushes,
+					  sizeof(mc->flush_reserved),
+					  GFP_KERNEL);
+	if (!mc->flush_reserved)
+		return -ENOMEM;
+
 	/* length of MC tick in nanoseconds */
 	mc->tick = 30;
 
@@ -410,6 +518,8 @@ static int tegra_mc_probe(struct platform_device *pdev)
 		return err;
 	}
 
+	mutex_init(&mc->lock);
+
 	value = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
 		MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
 		MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM;
diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h
index b7361b0a6696..0f59d49b735b 100644
--- a/drivers/memory/tegra/mc.h
+++ b/drivers/memory/tegra/mc.h
@@ -14,6 +14,8 @@
 
 #include <soc/tegra/mc.h>
 
+#define MC_FLUSH_METASTABLE_READS	5
+
 static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset)
 {
 	return readl(mc->regs + offset);
diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h
index 1ab2813273cd..b634c6df79eb 100644
--- a/include/soc/tegra/mc.h
+++ b/include/soc/tegra/mc.h
@@ -45,6 +45,13 @@ struct tegra_mc_client {
 	struct tegra_mc_la la;
 };
 
+struct tegra_mc_flush {
+	unsigned int swgroup;
+	unsigned int ctrl;
+	unsigned int status;
+	unsigned int bit;
+};
+
 struct tegra_smmu_swgroup {
 	const char *name;
 	unsigned int swgroup;
@@ -96,6 +103,10 @@ struct tegra_mc_soc {
 	const struct tegra_mc_client *clients;
 	unsigned int num_clients;
 
+	const struct tegra_mc_flush *flushes;
+	unsigned int num_flushes;
+	unsigned int metastable_flush_reads;
+
 	const unsigned long *emem_regs;
 	unsigned int num_emem_regs;
 
@@ -117,9 +128,32 @@ struct tegra_mc {
 
 	struct tegra_mc_timing *timings;
 	unsigned int num_timings;
+
+	bool *flush_reserved;
+
+	struct mutex lock;
 };
 
 void tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate);
 unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc);
 
+#ifdef CONFIG_TEGRA_MC
+const struct tegra_mc_flush *tegra_mc_flush_get(struct tegra_mc *mc,
+						unsigned int swgroup);
+int tegra_mc_flush(struct tegra_mc *mc, const struct tegra_mc_flush *s,
+		   bool enable);
+#else
+const struct tegra_mc_flush *tegra_mc_flush_get(struct tegra_mc *mc,
+						unsigned int swgroup)
+{
+	return NULL;
+}
+
+int tegra_mc_flush(struct tegra_mc *mc, const struct tegra_mc_flush *s,
+		   bool enable)
+{
+	return -ENOTSUPP;
+}
+#endif
+
 #endif /* __SOC_TEGRA_MC_H__ */
-- 
2.1.4

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

* [PATCH V3 03/19] memory: tegra: add flush operation for Tegra30 memory clients
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39     ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Jon Hunter

From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

This patch adds the hot reset register table and flush related callback
functions for Tegra30.

Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
[jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org: Removed tegra_mc_ops and added
 metastable_flush_reads.]
Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

---
v3: removal of tegra_mc_ops
---
 drivers/memory/tegra/tegra30.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
index 1abcd8f6f3ba..3b4987f39b52 100644
--- a/drivers/memory/tegra/tegra30.c
+++ b/drivers/memory/tegra/tegra30.c
@@ -6,6 +6,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/device.h>
 #include <linux/of.h>
 #include <linux/mm.h>
 
@@ -936,6 +937,26 @@ static const struct tegra_smmu_swgroup tegra30_swgroups[] = {
 	{ .name = "isp",  .swgroup = TEGRA_SWGROUP_ISP,  .reg = 0x258 },
 };
 
+static struct tegra_mc_flush tegra30_mc_flush[] = {
+	{TEGRA_SWGROUP_AFI,        0x200, 0x204,  0},
+	{TEGRA_SWGROUP_AVPC,       0x200, 0x204,  1},
+	{TEGRA_SWGROUP_DC,         0x200, 0x204,  2},
+	{TEGRA_SWGROUP_DCB,        0x200, 0x204,  3},
+	{TEGRA_SWGROUP_EPP,        0x200, 0x204,  4},
+	{TEGRA_SWGROUP_G2,         0x200, 0x204,  5},
+	{TEGRA_SWGROUP_HC,         0x200, 0x204,  6},
+	{TEGRA_SWGROUP_HDA,        0x200, 0x204,  7},
+	{TEGRA_SWGROUP_ISP,        0x200, 0x204,  8},
+	{TEGRA_SWGROUP_MPCORE,     0x200, 0x204,  9},
+	{TEGRA_SWGROUP_MPCORELP,   0x200, 0x204, 10},
+	{TEGRA_SWGROUP_MPE,        0x200, 0x204, 11},
+	{TEGRA_SWGROUP_NV,         0x200, 0x204, 12},
+	{TEGRA_SWGROUP_NV2,        0x200, 0x204, 13},
+	{TEGRA_SWGROUP_PPCS,       0x200, 0x204, 14},
+	{TEGRA_SWGROUP_VDE,        0x200, 0x204, 16},
+	{TEGRA_SWGROUP_VI,         0x200, 0x204, 17},
+};
+
 static void tegra30_flush_dcache(struct page *page, unsigned long offset,
 				 size_t size)
 {
@@ -967,4 +988,7 @@ const struct tegra_mc_soc tegra30_mc_soc = {
 	.num_address_bits = 32,
 	.atom_size = 16,
 	.smmu = &tegra30_smmu_soc,
+	.flushes = tegra30_mc_flush,
+	.num_flushes = ARRAY_SIZE(tegra30_mc_flush),
+	.metastable_flush_reads = 0,
 };
-- 
2.1.4

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

* [PATCH V3 03/19] memory: tegra: add flush operation for Tegra30 memory clients
@ 2015-07-13 12:39     ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vince Hsu <vinceh@nvidia.com>

This patch adds the hot reset register table and flush related callback
functions for Tegra30.

Signed-off-by: Vince Hsu <vinceh@nvidia.com>
[jonathanh at nvidia.com: Removed tegra_mc_ops and added
 metastable_flush_reads.]
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>

---
v3: removal of tegra_mc_ops
---
 drivers/memory/tegra/tegra30.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
index 1abcd8f6f3ba..3b4987f39b52 100644
--- a/drivers/memory/tegra/tegra30.c
+++ b/drivers/memory/tegra/tegra30.c
@@ -6,6 +6,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/device.h>
 #include <linux/of.h>
 #include <linux/mm.h>
 
@@ -936,6 +937,26 @@ static const struct tegra_smmu_swgroup tegra30_swgroups[] = {
 	{ .name = "isp",  .swgroup = TEGRA_SWGROUP_ISP,  .reg = 0x258 },
 };
 
+static struct tegra_mc_flush tegra30_mc_flush[] = {
+	{TEGRA_SWGROUP_AFI,        0x200, 0x204,  0},
+	{TEGRA_SWGROUP_AVPC,       0x200, 0x204,  1},
+	{TEGRA_SWGROUP_DC,         0x200, 0x204,  2},
+	{TEGRA_SWGROUP_DCB,        0x200, 0x204,  3},
+	{TEGRA_SWGROUP_EPP,        0x200, 0x204,  4},
+	{TEGRA_SWGROUP_G2,         0x200, 0x204,  5},
+	{TEGRA_SWGROUP_HC,         0x200, 0x204,  6},
+	{TEGRA_SWGROUP_HDA,        0x200, 0x204,  7},
+	{TEGRA_SWGROUP_ISP,        0x200, 0x204,  8},
+	{TEGRA_SWGROUP_MPCORE,     0x200, 0x204,  9},
+	{TEGRA_SWGROUP_MPCORELP,   0x200, 0x204, 10},
+	{TEGRA_SWGROUP_MPE,        0x200, 0x204, 11},
+	{TEGRA_SWGROUP_NV,         0x200, 0x204, 12},
+	{TEGRA_SWGROUP_NV2,        0x200, 0x204, 13},
+	{TEGRA_SWGROUP_PPCS,       0x200, 0x204, 14},
+	{TEGRA_SWGROUP_VDE,        0x200, 0x204, 16},
+	{TEGRA_SWGROUP_VI,         0x200, 0x204, 17},
+};
+
 static void tegra30_flush_dcache(struct page *page, unsigned long offset,
 				 size_t size)
 {
@@ -967,4 +988,7 @@ const struct tegra_mc_soc tegra30_mc_soc = {
 	.num_address_bits = 32,
 	.atom_size = 16,
 	.smmu = &tegra30_smmu_soc,
+	.flushes = tegra30_mc_flush,
+	.num_flushes = ARRAY_SIZE(tegra30_mc_flush),
+	.metastable_flush_reads = 0,
 };
-- 
2.1.4

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

* [PATCH V3 04/19] memory: tegra: add flush operation for Tegra114 memory clients
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39     ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Jon Hunter

From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

This patch adds the hot reset register table and flush related callback
functions for Tegra114.

Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
[jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org: Removed tegra_mc_ops and added
 metastable_flush_reads.]
Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/memory/tegra/tegra114.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c
index 9f579589e800..ba33c402ed68 100644
--- a/drivers/memory/tegra/tegra114.c
+++ b/drivers/memory/tegra/tegra114.c
@@ -914,6 +914,24 @@ static const struct tegra_smmu_swgroup tegra114_swgroups[] = {
 	{ .name = "tsec",      .swgroup = TEGRA_SWGROUP_TSEC,      .reg = 0x294 },
 };
 
+static struct tegra_mc_flush tegra114_mc_flush[] = {
+	{TEGRA_SWGROUP_AVPC,       0x200, 0x204,  1},
+	{TEGRA_SWGROUP_DC,         0x200, 0x204,  2},
+	{TEGRA_SWGROUP_DCB,        0x200, 0x204,  3},
+	{TEGRA_SWGROUP_EPP,        0x200, 0x204,  4},
+	{TEGRA_SWGROUP_G2,         0x200, 0x204,  5},
+	{TEGRA_SWGROUP_HC,         0x200, 0x204,  6},
+	{TEGRA_SWGROUP_HDA,        0x200, 0x204,  7},
+	{TEGRA_SWGROUP_ISP,        0x200, 0x204,  8},
+	{TEGRA_SWGROUP_MPCORE,     0x200, 0x204,  9},
+	{TEGRA_SWGROUP_MPCORELP,   0x200, 0x204, 10},
+	{TEGRA_SWGROUP_MSENC,      0x200, 0x204, 11},
+	{TEGRA_SWGROUP_NV,         0x200, 0x204, 12},
+	{TEGRA_SWGROUP_PPCS,       0x200, 0x204, 14},
+	{TEGRA_SWGROUP_VDE,        0x200, 0x204, 16},
+	{TEGRA_SWGROUP_VI,         0x200, 0x204, 17},
+};
+
 static void tegra114_flush_dcache(struct page *page, unsigned long offset,
 				  size_t size)
 {
@@ -945,4 +963,7 @@ const struct tegra_mc_soc tegra114_mc_soc = {
 	.num_address_bits = 32,
 	.atom_size = 32,
 	.smmu = &tegra114_smmu_soc,
+	.flushes = tegra114_mc_flush,
+	.num_flushes = ARRAY_SIZE(tegra114_mc_flush),
+	.metastable_flush_reads = MC_FLUSH_METASTABLE_READS,
 };
-- 
2.1.4

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

* [PATCH V3 04/19] memory: tegra: add flush operation for Tegra114 memory clients
@ 2015-07-13 12:39     ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vince Hsu <vinceh@nvidia.com>

This patch adds the hot reset register table and flush related callback
functions for Tegra114.

Signed-off-by: Vince Hsu <vinceh@nvidia.com>
[jonathanh at nvidia.com: Removed tegra_mc_ops and added
 metastable_flush_reads.]
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/memory/tegra/tegra114.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c
index 9f579589e800..ba33c402ed68 100644
--- a/drivers/memory/tegra/tegra114.c
+++ b/drivers/memory/tegra/tegra114.c
@@ -914,6 +914,24 @@ static const struct tegra_smmu_swgroup tegra114_swgroups[] = {
 	{ .name = "tsec",      .swgroup = TEGRA_SWGROUP_TSEC,      .reg = 0x294 },
 };
 
+static struct tegra_mc_flush tegra114_mc_flush[] = {
+	{TEGRA_SWGROUP_AVPC,       0x200, 0x204,  1},
+	{TEGRA_SWGROUP_DC,         0x200, 0x204,  2},
+	{TEGRA_SWGROUP_DCB,        0x200, 0x204,  3},
+	{TEGRA_SWGROUP_EPP,        0x200, 0x204,  4},
+	{TEGRA_SWGROUP_G2,         0x200, 0x204,  5},
+	{TEGRA_SWGROUP_HC,         0x200, 0x204,  6},
+	{TEGRA_SWGROUP_HDA,        0x200, 0x204,  7},
+	{TEGRA_SWGROUP_ISP,        0x200, 0x204,  8},
+	{TEGRA_SWGROUP_MPCORE,     0x200, 0x204,  9},
+	{TEGRA_SWGROUP_MPCORELP,   0x200, 0x204, 10},
+	{TEGRA_SWGROUP_MSENC,      0x200, 0x204, 11},
+	{TEGRA_SWGROUP_NV,         0x200, 0x204, 12},
+	{TEGRA_SWGROUP_PPCS,       0x200, 0x204, 14},
+	{TEGRA_SWGROUP_VDE,        0x200, 0x204, 16},
+	{TEGRA_SWGROUP_VI,         0x200, 0x204, 17},
+};
+
 static void tegra114_flush_dcache(struct page *page, unsigned long offset,
 				  size_t size)
 {
@@ -945,4 +963,7 @@ const struct tegra_mc_soc tegra114_mc_soc = {
 	.num_address_bits = 32,
 	.atom_size = 32,
 	.smmu = &tegra114_smmu_soc,
+	.flushes = tegra114_mc_flush,
+	.num_flushes = ARRAY_SIZE(tegra114_mc_flush),
+	.metastable_flush_reads = MC_FLUSH_METASTABLE_READS,
 };
-- 
2.1.4

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

* [PATCH V3 05/19] memory: tegra: add flush operation for Tegra124 memory clients
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39     ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Jon Hunter

From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

This patch adds the hot reset register table and flush related callback
functions for Tegra124.

Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
[jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org: Removed tegra_mc_ops and added
 metastable_flush_reads.]
Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/memory/tegra/tegra124.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
index 966e1557e6f4..a24993db14ed 100644
--- a/drivers/memory/tegra/tegra124.c
+++ b/drivers/memory/tegra/tegra124.c
@@ -1002,6 +1002,34 @@ static const struct tegra_smmu_swgroup tegra124_swgroups[] = {
 };
 
 #ifdef CONFIG_ARCH_TEGRA_124_SOC
+
+static struct tegra_mc_flush tegra124_mc_flush[] = {
+	{TEGRA_SWGROUP_AFI,        0x200, 0x204,  0},
+	{TEGRA_SWGROUP_AVPC,       0x200, 0x204,  1},
+	{TEGRA_SWGROUP_DC,         0x200, 0x204,  2},
+	{TEGRA_SWGROUP_DCB,        0x200, 0x204,  3},
+	{TEGRA_SWGROUP_HC,         0x200, 0x204,  6},
+	{TEGRA_SWGROUP_HDA,        0x200, 0x204,  7},
+	{TEGRA_SWGROUP_ISP2,       0x200, 0x204,  8},
+	{TEGRA_SWGROUP_MPCORE,     0x200, 0x204,  9},
+	{TEGRA_SWGROUP_MPCORELP,   0x200, 0x204, 10},
+	{TEGRA_SWGROUP_MSENC,      0x200, 0x204, 11},
+	{TEGRA_SWGROUP_PPCS,       0x200, 0x204, 14},
+	{TEGRA_SWGROUP_SATA,       0x200, 0x204, 15},
+	{TEGRA_SWGROUP_VDE,        0x200, 0x204, 16},
+	{TEGRA_SWGROUP_VI,         0x200, 0x204, 17},
+	{TEGRA_SWGROUP_VIC,        0x200, 0x204, 18},
+	{TEGRA_SWGROUP_XUSB_HOST,  0x200, 0x204, 19},
+	{TEGRA_SWGROUP_XUSB_DEV,   0x200, 0x204, 20},
+	{TEGRA_SWGROUP_TSEC,       0x200, 0x204, 22},
+	{TEGRA_SWGROUP_SDMMC1A,    0x200, 0x204, 29},
+	{TEGRA_SWGROUP_SDMMC2A,    0x200, 0x204, 30},
+	{TEGRA_SWGROUP_SDMMC3A,    0x200, 0x204, 31},
+	{TEGRA_SWGROUP_SDMMC4A,    0x970, 0x974,  0},
+	{TEGRA_SWGROUP_ISP2B,      0x970, 0x974,  1},
+	{TEGRA_SWGROUP_GPU,        0x970, 0x974,  2},
+};
+
 static void tegra124_flush_dcache(struct page *page, unsigned long offset,
 				  size_t size)
 {
@@ -1035,6 +1063,9 @@ const struct tegra_mc_soc tegra124_mc_soc = {
 	.smmu = &tegra124_smmu_soc,
 	.emem_regs = tegra124_mc_emem_regs,
 	.num_emem_regs = ARRAY_SIZE(tegra124_mc_emem_regs),
+	.flushes = tegra124_mc_flush,
+	.num_flushes = ARRAY_SIZE(tegra124_mc_flush),
+	.metastable_flush_reads = MC_FLUSH_METASTABLE_READS,
 };
 #endif /* CONFIG_ARCH_TEGRA_124_SOC */
 
-- 
2.1.4

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

* [PATCH V3 05/19] memory: tegra: add flush operation for Tegra124 memory clients
@ 2015-07-13 12:39     ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vince Hsu <vinceh@nvidia.com>

This patch adds the hot reset register table and flush related callback
functions for Tegra124.

Signed-off-by: Vince Hsu <vinceh@nvidia.com>
[jonathanh at nvidia.com: Removed tegra_mc_ops and added
 metastable_flush_reads.]
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/memory/tegra/tegra124.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
index 966e1557e6f4..a24993db14ed 100644
--- a/drivers/memory/tegra/tegra124.c
+++ b/drivers/memory/tegra/tegra124.c
@@ -1002,6 +1002,34 @@ static const struct tegra_smmu_swgroup tegra124_swgroups[] = {
 };
 
 #ifdef CONFIG_ARCH_TEGRA_124_SOC
+
+static struct tegra_mc_flush tegra124_mc_flush[] = {
+	{TEGRA_SWGROUP_AFI,        0x200, 0x204,  0},
+	{TEGRA_SWGROUP_AVPC,       0x200, 0x204,  1},
+	{TEGRA_SWGROUP_DC,         0x200, 0x204,  2},
+	{TEGRA_SWGROUP_DCB,        0x200, 0x204,  3},
+	{TEGRA_SWGROUP_HC,         0x200, 0x204,  6},
+	{TEGRA_SWGROUP_HDA,        0x200, 0x204,  7},
+	{TEGRA_SWGROUP_ISP2,       0x200, 0x204,  8},
+	{TEGRA_SWGROUP_MPCORE,     0x200, 0x204,  9},
+	{TEGRA_SWGROUP_MPCORELP,   0x200, 0x204, 10},
+	{TEGRA_SWGROUP_MSENC,      0x200, 0x204, 11},
+	{TEGRA_SWGROUP_PPCS,       0x200, 0x204, 14},
+	{TEGRA_SWGROUP_SATA,       0x200, 0x204, 15},
+	{TEGRA_SWGROUP_VDE,        0x200, 0x204, 16},
+	{TEGRA_SWGROUP_VI,         0x200, 0x204, 17},
+	{TEGRA_SWGROUP_VIC,        0x200, 0x204, 18},
+	{TEGRA_SWGROUP_XUSB_HOST,  0x200, 0x204, 19},
+	{TEGRA_SWGROUP_XUSB_DEV,   0x200, 0x204, 20},
+	{TEGRA_SWGROUP_TSEC,       0x200, 0x204, 22},
+	{TEGRA_SWGROUP_SDMMC1A,    0x200, 0x204, 29},
+	{TEGRA_SWGROUP_SDMMC2A,    0x200, 0x204, 30},
+	{TEGRA_SWGROUP_SDMMC3A,    0x200, 0x204, 31},
+	{TEGRA_SWGROUP_SDMMC4A,    0x970, 0x974,  0},
+	{TEGRA_SWGROUP_ISP2B,      0x970, 0x974,  1},
+	{TEGRA_SWGROUP_GPU,        0x970, 0x974,  2},
+};
+
 static void tegra124_flush_dcache(struct page *page, unsigned long offset,
 				  size_t size)
 {
@@ -1035,6 +1063,9 @@ const struct tegra_mc_soc tegra124_mc_soc = {
 	.smmu = &tegra124_smmu_soc,
 	.emem_regs = tegra124_mc_emem_regs,
 	.num_emem_regs = ARRAY_SIZE(tegra124_mc_emem_regs),
+	.flushes = tegra124_mc_flush,
+	.num_flushes = ARRAY_SIZE(tegra124_mc_flush),
+	.metastable_flush_reads = MC_FLUSH_METASTABLE_READS,
 };
 #endif /* CONFIG_ARCH_TEGRA_124_SOC */
 
-- 
2.1.4

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

* [PATCH V3 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39   ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra, devicetree, linux-arm-kernel, linux-pm, Jon Hunter

From: Vince Hsu <vinceh@nvidia.com>

Tegra114 has a HW bug that the PLLD/PLLD2 lock bit cannot be asserted when
the DIS power domain is during up-powergating process but the clamp to this
domain is not removed yet. That causes a timeout and aborts the power
sequence, although the PLLD/PLLD2 has already locked. To remove the false
alarm, we don't use the lock for PLLD/PLLD2. Just wait 1ms and treat the
clocks as locked.

Signed-off-by: Vince Hsu <vinceh@nvidia.com>
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/clk/tegra/clk-tegra114.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 8237d16b4075..2e5c20c7c088 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -456,8 +456,7 @@ static struct tegra_clk_pll_params pll_d_params = {
 	.lock_delay = 1000,
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_d_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
 };
 
 static struct tegra_clk_pll_params pll_d2_params = {
@@ -474,8 +473,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
 	.lock_delay = 1000,
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_d_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
 };
 
 static struct pdiv_map pllu_p[] = {
-- 
2.1.4


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

* [PATCH V3 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2
@ 2015-07-13 12:39   ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vince Hsu <vinceh@nvidia.com>

Tegra114 has a HW bug that the PLLD/PLLD2 lock bit cannot be asserted when
the DIS power domain is during up-powergating process but the clamp to this
domain is not removed yet. That causes a timeout and aborts the power
sequence, although the PLLD/PLLD2 has already locked. To remove the false
alarm, we don't use the lock for PLLD/PLLD2. Just wait 1ms and treat the
clocks as locked.

Signed-off-by: Vince Hsu <vinceh@nvidia.com>
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/clk/tegra/clk-tegra114.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 8237d16b4075..2e5c20c7c088 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -456,8 +456,7 @@ static struct tegra_clk_pll_params pll_d_params = {
 	.lock_delay = 1000,
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_d_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
 };
 
 static struct tegra_clk_pll_params pll_d2_params = {
@@ -474,8 +473,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
 	.lock_delay = 1000,
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_d_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
 };
 
 static struct pdiv_map pllu_p[] = {
-- 
2.1.4

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

* [PATCH V3 07/19] soc: tegra: pmc: Wait for powergate state to change
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39     ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Jon Hunter

Currently, the function tegra_powergate_set() simply sets the desired
powergate state but does not wait for the state to change. In some
circumstances this can be desirable. However, in most cases we should
wait for the state to change before proceeding. Therefore, add a
parameter to tegra_powergate_set() to indicate whether we should wait
for the state to change.

By adding this feature, we can also eliminate the polling loop from
tegra30_boot_secondary().

Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 arch/arm/mach-tegra/platsmp.c | 18 ++++--------------
 drivers/soc/tegra/pmc.c       | 29 +++++++++++++++++++++++------
 include/soc/tegra/pmc.h       |  2 +-
 3 files changed, 28 insertions(+), 21 deletions(-)

diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index b45086666648..13982b5936c0 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -108,19 +108,9 @@ static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle)
 	 * be un-gated by un-toggling the power gate register
 	 * manually.
 	 */
-	if (!tegra_pmc_cpu_is_powered(cpu)) {
-		ret = tegra_pmc_cpu_power_on(cpu);
-		if (ret)
-			return ret;
-
-		/* Wait for the power to come up. */
-		timeout = jiffies + msecs_to_jiffies(100);
-		while (!tegra_pmc_cpu_is_powered(cpu)) {
-			if (time_after(jiffies, timeout))
-				return -ETIMEDOUT;
-			udelay(10);
-		}
-	}
+	ret = tegra_pmc_cpu_power_on(cpu, true);
+	if (ret)
+		return ret;
 
 remove_clamps:
 	/* CPU partition is powered. Enable the CPU clock. */
@@ -162,7 +152,7 @@ static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle)
 		 * also initial power state in flow controller. After that,
 		 * the CPU's power state is maintained by flow controller.
 		 */
-		ret = tegra_pmc_cpu_power_on(cpu);
+		ret = tegra_pmc_cpu_power_on(cpu, false);
 	}
 
 	return ret;
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 300f11e0c3bb..c0635bdd4ee3 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -175,9 +175,11 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
  * @id: partition ID
  * @new_state: new state of the partition
  */
-static int tegra_powergate_set(int id, bool new_state)
+static int tegra_powergate_set(int id, bool new_state, bool wait)
 {
+	unsigned long timeout;
 	bool status;
+	int ret = 0;
 
 	mutex_lock(&pmc->powergates_lock);
 
@@ -190,9 +192,23 @@ static int tegra_powergate_set(int id, bool new_state)
 
 	tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
 
+	if (wait) {
+		timeout = jiffies + msecs_to_jiffies(100);
+		ret = -ETIMEDOUT;
+
+		while (time_before(jiffies, timeout)) {
+			status = !!(tegra_pmc_readl(PWRGATE_STATUS) & BIT(id));
+			if (status == new_state) {
+				ret = 0;
+				break;
+			}
+			udelay(10);
+		}
+	}
+
 	mutex_unlock(&pmc->powergates_lock);
 
-	return 0;
+	return ret;
 }
 
 /**
@@ -204,7 +220,7 @@ int tegra_powergate_power_on(int id)
 	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
 		return -EINVAL;
 
-	return tegra_powergate_set(id, true);
+	return tegra_powergate_set(id, true, true);
 }
 
 /**
@@ -216,7 +232,7 @@ int tegra_powergate_power_off(int id)
 	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
 		return -EINVAL;
 
-	return tegra_powergate_set(id, false);
+	return tegra_powergate_set(id, false, true);
 }
 EXPORT_SYMBOL(tegra_powergate_power_off);
 
@@ -351,8 +367,9 @@ bool tegra_pmc_cpu_is_powered(int cpuid)
 /**
  * tegra_pmc_cpu_power_on() - power on CPU partition
  * @cpuid: CPU partition ID
+ * @wait:  Wait for CPU state to transition
  */
-int tegra_pmc_cpu_power_on(int cpuid)
+int tegra_pmc_cpu_power_on(int cpuid, bool wait)
 {
 	int id;
 
@@ -360,7 +377,7 @@ int tegra_pmc_cpu_power_on(int cpuid)
 	if (id < 0)
 		return id;
 
-	return tegra_powergate_set(id, true);
+	return tegra_powergate_set(id, true, wait);
 }
 
 /**
diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h
index d18efe402ff1..3a014c121399 100644
--- a/include/soc/tegra/pmc.h
+++ b/include/soc/tegra/pmc.h
@@ -34,7 +34,7 @@ void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
 
 #ifdef CONFIG_SMP
 bool tegra_pmc_cpu_is_powered(int cpuid);
-int tegra_pmc_cpu_power_on(int cpuid);
+int tegra_pmc_cpu_power_on(int cpuid, bool wait);
 int tegra_pmc_cpu_remove_clamping(int cpuid);
 #endif /* CONFIG_SMP */
 
-- 
2.1.4

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

* [PATCH V3 07/19] soc: tegra: pmc: Wait for powergate state to change
@ 2015-07-13 12:39     ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

Currently, the function tegra_powergate_set() simply sets the desired
powergate state but does not wait for the state to change. In some
circumstances this can be desirable. However, in most cases we should
wait for the state to change before proceeding. Therefore, add a
parameter to tegra_powergate_set() to indicate whether we should wait
for the state to change.

By adding this feature, we can also eliminate the polling loop from
tegra30_boot_secondary().

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 arch/arm/mach-tegra/platsmp.c | 18 ++++--------------
 drivers/soc/tegra/pmc.c       | 29 +++++++++++++++++++++++------
 include/soc/tegra/pmc.h       |  2 +-
 3 files changed, 28 insertions(+), 21 deletions(-)

diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index b45086666648..13982b5936c0 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -108,19 +108,9 @@ static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle)
 	 * be un-gated by un-toggling the power gate register
 	 * manually.
 	 */
-	if (!tegra_pmc_cpu_is_powered(cpu)) {
-		ret = tegra_pmc_cpu_power_on(cpu);
-		if (ret)
-			return ret;
-
-		/* Wait for the power to come up. */
-		timeout = jiffies + msecs_to_jiffies(100);
-		while (!tegra_pmc_cpu_is_powered(cpu)) {
-			if (time_after(jiffies, timeout))
-				return -ETIMEDOUT;
-			udelay(10);
-		}
-	}
+	ret = tegra_pmc_cpu_power_on(cpu, true);
+	if (ret)
+		return ret;
 
 remove_clamps:
 	/* CPU partition is powered. Enable the CPU clock. */
@@ -162,7 +152,7 @@ static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle)
 		 * also initial power state in flow controller. After that,
 		 * the CPU's power state is maintained by flow controller.
 		 */
-		ret = tegra_pmc_cpu_power_on(cpu);
+		ret = tegra_pmc_cpu_power_on(cpu, false);
 	}
 
 	return ret;
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 300f11e0c3bb..c0635bdd4ee3 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -175,9 +175,11 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
  * @id: partition ID
  * @new_state: new state of the partition
  */
-static int tegra_powergate_set(int id, bool new_state)
+static int tegra_powergate_set(int id, bool new_state, bool wait)
 {
+	unsigned long timeout;
 	bool status;
+	int ret = 0;
 
 	mutex_lock(&pmc->powergates_lock);
 
@@ -190,9 +192,23 @@ static int tegra_powergate_set(int id, bool new_state)
 
 	tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
 
+	if (wait) {
+		timeout = jiffies + msecs_to_jiffies(100);
+		ret = -ETIMEDOUT;
+
+		while (time_before(jiffies, timeout)) {
+			status = !!(tegra_pmc_readl(PWRGATE_STATUS) & BIT(id));
+			if (status == new_state) {
+				ret = 0;
+				break;
+			}
+			udelay(10);
+		}
+	}
+
 	mutex_unlock(&pmc->powergates_lock);
 
-	return 0;
+	return ret;
 }
 
 /**
@@ -204,7 +220,7 @@ int tegra_powergate_power_on(int id)
 	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
 		return -EINVAL;
 
-	return tegra_powergate_set(id, true);
+	return tegra_powergate_set(id, true, true);
 }
 
 /**
@@ -216,7 +232,7 @@ int tegra_powergate_power_off(int id)
 	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
 		return -EINVAL;
 
-	return tegra_powergate_set(id, false);
+	return tegra_powergate_set(id, false, true);
 }
 EXPORT_SYMBOL(tegra_powergate_power_off);
 
@@ -351,8 +367,9 @@ bool tegra_pmc_cpu_is_powered(int cpuid)
 /**
  * tegra_pmc_cpu_power_on() - power on CPU partition
  * @cpuid: CPU partition ID
+ * @wait:  Wait for CPU state to transition
  */
-int tegra_pmc_cpu_power_on(int cpuid)
+int tegra_pmc_cpu_power_on(int cpuid, bool wait)
 {
 	int id;
 
@@ -360,7 +377,7 @@ int tegra_pmc_cpu_power_on(int cpuid)
 	if (id < 0)
 		return id;
 
-	return tegra_powergate_set(id, true);
+	return tegra_powergate_set(id, true, wait);
 }
 
 /**
diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h
index d18efe402ff1..3a014c121399 100644
--- a/include/soc/tegra/pmc.h
+++ b/include/soc/tegra/pmc.h
@@ -34,7 +34,7 @@ void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
 
 #ifdef CONFIG_SMP
 bool tegra_pmc_cpu_is_powered(int cpuid);
-int tegra_pmc_cpu_power_on(int cpuid);
+int tegra_pmc_cpu_power_on(int cpuid, bool wait);
 int tegra_pmc_cpu_remove_clamping(int cpuid);
 #endif /* CONFIG_SMP */
 
-- 
2.1.4

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

* [PATCH V3 08/19] soc: tegra: pmc: Clean-up PMC helper functions
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39     ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Jon Hunter

The following clean-ups have been made to the PMC code:

1. Add a macro for determining the state of a PMC powergate
2. Use the readx_poll_timeout() function instead of implementing a local
   polling loop with a timeout.
3. Use a case-statement in the function that removes the powergate clamp
   instead of multiple if-statements to improve readability.

Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/soc/tegra/pmc.c | 72 ++++++++++++++++++++++++-------------------------
 1 file changed, 35 insertions(+), 37 deletions(-)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index c0635bdd4ee3..180d434deec5 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -28,6 +28,7 @@
 #include <linux/export.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
@@ -56,6 +57,8 @@
 #define  PWRGATE_TOGGLE_START		(1 << 8)
 
 #define REMOVE_CLAMPING			0x34
+#define  REMOVE_CLAMPING_VDEC		(1 << 3)
+#define  REMOVE_CLAMPING_PCIE		(1 << 4)
 
 #define PWRGATE_STATUS			0x38
 
@@ -101,6 +104,8 @@
 
 #define GPU_RG_CNTRL			0x2d4
 
+#define PMC_PWRGATE_STATE(val, id)	(!!(val & BIT(id)))
+
 struct tegra_pmc_soc {
 	unsigned int num_powergates;
 	const char *const *powergates;
@@ -177,15 +182,14 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
  */
 static int tegra_powergate_set(int id, bool new_state, bool wait)
 {
-	unsigned long timeout;
-	bool status;
 	int ret = 0;
+	u32 val;
 
 	mutex_lock(&pmc->powergates_lock);
 
-	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
+	val = tegra_pmc_readl(PWRGATE_STATUS);
 
-	if (status == new_state) {
+	if (PMC_PWRGATE_STATE(val, id) == new_state) {
 		mutex_unlock(&pmc->powergates_lock);
 		return 0;
 	}
@@ -193,17 +197,9 @@ static int tegra_powergate_set(int id, bool new_state, bool wait)
 	tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
 
 	if (wait) {
-		timeout = jiffies + msecs_to_jiffies(100);
-		ret = -ETIMEDOUT;
-
-		while (time_before(jiffies, timeout)) {
-			status = !!(tegra_pmc_readl(PWRGATE_STATUS) & BIT(id));
-			if (status == new_state) {
-				ret = 0;
-				break;
-			}
-			udelay(10);
-		}
+		ret = readx_poll_timeout(tegra_pmc_readl, PWRGATE_STATUS,
+				val, PMC_PWRGATE_STATE(val, id) == new_state,
+				10, 100000);
 	}
 
 	mutex_unlock(&pmc->powergates_lock);
@@ -242,13 +238,10 @@ EXPORT_SYMBOL(tegra_powergate_power_off);
  */
 int tegra_powergate_is_powered(int id)
 {
-	u32 status;
-
 	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
 		return -EINVAL;
 
-	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
-	return !!status;
+	return PMC_PWRGATE_STATE(tegra_pmc_readl(PWRGATE_STATUS), id);
 }
 
 /**
@@ -257,34 +250,39 @@ int tegra_powergate_is_powered(int id)
  */
 int tegra_powergate_remove_clamping(int id)
 {
-	u32 mask;
+	u32 val, reg;
 
 	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
 		return -EINVAL;
 
 	/*
-	 * On Tegra124 and later, the clamps for the GPU are controlled by a
-	 * separate register (with different semantics).
+	 * In most cases the bit for removing the IO clamping is the same as
+	 * the powergate partition ID, however, this is not always the case.
+	 * Furthermore, on Tegra124 and later, the clamps for the GPU are
+	 * controlled by a separate register (with different semantics). The
+	 * following case-statement handles these exceptions.
 	 */
-	if (id == TEGRA_POWERGATE_3D) {
+	val = 1 << id;
+	reg = REMOVE_CLAMPING;
+
+	switch (id) {
+	case TEGRA_POWERGATE_3D:
 		if (pmc->soc->has_gpu_clamps) {
-			tegra_pmc_writel(0, GPU_RG_CNTRL);
-			return 0;
+			val = 0;
+			reg  = GPU_RG_CNTRL;
 		}
+		break;
+	case TEGRA_POWERGATE_VDEC:
+		val = REMOVE_CLAMPING_VDEC;
+		break;
+	case TEGRA_POWERGATE_PCIE:
+		val = REMOVE_CLAMPING_PCIE;
+		break;
+	default:
+		break;
 	}
 
-	/*
-	 * Tegra 2 has a bug where PCIE and VDE clamping masks are
-	 * swapped relatively to the partition ids
-	 */
-	if (id == TEGRA_POWERGATE_VDEC)
-		mask = (1 << TEGRA_POWERGATE_PCIE);
-	else if (id == TEGRA_POWERGATE_PCIE)
-		mask = (1 << TEGRA_POWERGATE_VDEC);
-	else
-		mask = (1 << id);
-
-	tegra_pmc_writel(mask, REMOVE_CLAMPING);
+	tegra_pmc_writel(val, reg);
 
 	return 0;
 }
-- 
2.1.4

--
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] 110+ messages in thread

* [PATCH V3 08/19] soc: tegra: pmc: Clean-up PMC helper functions
@ 2015-07-13 12:39     ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

The following clean-ups have been made to the PMC code:

1. Add a macro for determining the state of a PMC powergate
2. Use the readx_poll_timeout() function instead of implementing a local
   polling loop with a timeout.
3. Use a case-statement in the function that removes the powergate clamp
   instead of multiple if-statements to improve readability.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/soc/tegra/pmc.c | 72 ++++++++++++++++++++++++-------------------------
 1 file changed, 35 insertions(+), 37 deletions(-)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index c0635bdd4ee3..180d434deec5 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -28,6 +28,7 @@
 #include <linux/export.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
@@ -56,6 +57,8 @@
 #define  PWRGATE_TOGGLE_START		(1 << 8)
 
 #define REMOVE_CLAMPING			0x34
+#define  REMOVE_CLAMPING_VDEC		(1 << 3)
+#define  REMOVE_CLAMPING_PCIE		(1 << 4)
 
 #define PWRGATE_STATUS			0x38
 
@@ -101,6 +104,8 @@
 
 #define GPU_RG_CNTRL			0x2d4
 
+#define PMC_PWRGATE_STATE(val, id)	(!!(val & BIT(id)))
+
 struct tegra_pmc_soc {
 	unsigned int num_powergates;
 	const char *const *powergates;
@@ -177,15 +182,14 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
  */
 static int tegra_powergate_set(int id, bool new_state, bool wait)
 {
-	unsigned long timeout;
-	bool status;
 	int ret = 0;
+	u32 val;
 
 	mutex_lock(&pmc->powergates_lock);
 
-	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
+	val = tegra_pmc_readl(PWRGATE_STATUS);
 
-	if (status == new_state) {
+	if (PMC_PWRGATE_STATE(val, id) == new_state) {
 		mutex_unlock(&pmc->powergates_lock);
 		return 0;
 	}
@@ -193,17 +197,9 @@ static int tegra_powergate_set(int id, bool new_state, bool wait)
 	tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
 
 	if (wait) {
-		timeout = jiffies + msecs_to_jiffies(100);
-		ret = -ETIMEDOUT;
-
-		while (time_before(jiffies, timeout)) {
-			status = !!(tegra_pmc_readl(PWRGATE_STATUS) & BIT(id));
-			if (status == new_state) {
-				ret = 0;
-				break;
-			}
-			udelay(10);
-		}
+		ret = readx_poll_timeout(tegra_pmc_readl, PWRGATE_STATUS,
+				val, PMC_PWRGATE_STATE(val, id) == new_state,
+				10, 100000);
 	}
 
 	mutex_unlock(&pmc->powergates_lock);
@@ -242,13 +238,10 @@ EXPORT_SYMBOL(tegra_powergate_power_off);
  */
 int tegra_powergate_is_powered(int id)
 {
-	u32 status;
-
 	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
 		return -EINVAL;
 
-	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
-	return !!status;
+	return PMC_PWRGATE_STATE(tegra_pmc_readl(PWRGATE_STATUS), id);
 }
 
 /**
@@ -257,34 +250,39 @@ int tegra_powergate_is_powered(int id)
  */
 int tegra_powergate_remove_clamping(int id)
 {
-	u32 mask;
+	u32 val, reg;
 
 	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
 		return -EINVAL;
 
 	/*
-	 * On Tegra124 and later, the clamps for the GPU are controlled by a
-	 * separate register (with different semantics).
+	 * In most cases the bit for removing the IO clamping is the same as
+	 * the powergate partition ID, however, this is not always the case.
+	 * Furthermore, on Tegra124 and later, the clamps for the GPU are
+	 * controlled by a separate register (with different semantics). The
+	 * following case-statement handles these exceptions.
 	 */
-	if (id == TEGRA_POWERGATE_3D) {
+	val = 1 << id;
+	reg = REMOVE_CLAMPING;
+
+	switch (id) {
+	case TEGRA_POWERGATE_3D:
 		if (pmc->soc->has_gpu_clamps) {
-			tegra_pmc_writel(0, GPU_RG_CNTRL);
-			return 0;
+			val = 0;
+			reg  = GPU_RG_CNTRL;
 		}
+		break;
+	case TEGRA_POWERGATE_VDEC:
+		val = REMOVE_CLAMPING_VDEC;
+		break;
+	case TEGRA_POWERGATE_PCIE:
+		val = REMOVE_CLAMPING_PCIE;
+		break;
+	default:
+		break;
 	}
 
-	/*
-	 * Tegra 2 has a bug where PCIE and VDE clamping masks are
-	 * swapped relatively to the partition ids
-	 */
-	if (id == TEGRA_POWERGATE_VDEC)
-		mask = (1 << TEGRA_POWERGATE_PCIE);
-	else if (id == TEGRA_POWERGATE_PCIE)
-		mask = (1 << TEGRA_POWERGATE_VDEC);
-	else
-		mask = (1 << id);
-
-	tegra_pmc_writel(mask, REMOVE_CLAMPING);
+	tegra_pmc_writel(val, reg);
 
 	return 0;
 }
-- 
2.1.4

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

* [PATCH V3 09/19] soc: tegra: pmc: Prepare for migrating to generic PM domains
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39   ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra, devicetree, linux-arm-kernel, linux-pm, Jon Hunter

When turning on and off power-domains it is necessary to enable specific
clocks in order to de-assert/assert various reset signals to place the
logic into a good state.

Currently, clocks required for turning on a power-domain are left enabled
by the PMC driver because these clocks are also needed by the IP blocks
to operated.

When migrating to the generic PM domain infrastructure, control of the
powergates is abstracted from the drivers and therefore, it is desirable
to disabled the clocks after turning on the power-domain and let the
drivers enable the clocks it needs later. However, because this behaviour
is different it is necessary to add a new API that drivers can use
whether generic PM domains are used or not so that the behaviour is the
same. Hence, add a new API that disables the clocks after turning on the
power domain.

Similarly, for disabling a power-domain add a new API to abstract the
management of the clocks so that drivers can be migrated to generic PM
domains.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/soc/tegra/pmc.c | 23 +++++++++++++++++++++++
 include/soc/tegra/pmc.h | 30 ++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 180d434deec5..934653785bb7 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -331,6 +331,29 @@ err_power:
 }
 EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
 
+int tegra_powergate_power_off_legacy(int id, struct clk *clk,
+				     struct reset_control *rst)
+{
+	int ret;
+
+	ret = clk_prepare_enable(clk);
+	if (ret)
+		return ret;
+
+	usleep_range(10, 20);
+
+	reset_control_assert(rst);
+
+	usleep_range(10, 20);
+
+	clk_disable_unprepare(clk);
+
+	usleep_range(10, 20);
+
+	return tegra_powergate_power_off(id);
+}
+EXPORT_SYMBOL(tegra_powergate_power_off_legacy);
+
 #ifdef CONFIG_SMP
 /**
  * tegra_get_cpu_powergate_id() - convert from CPU ID to partition ID
diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h
index 3a014c121399..4ca91d39304d 100644
--- a/include/soc/tegra/pmc.h
+++ b/include/soc/tegra/pmc.h
@@ -19,6 +19,8 @@
 #ifndef __SOC_TEGRA_PMC_H__
 #define __SOC_TEGRA_PMC_H__
 
+#include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/reboot.h>
 
 #include <soc/tegra/pm.h>
@@ -117,6 +119,22 @@ int tegra_powergate_remove_clamping(int id);
 int tegra_powergate_sequence_power_up(int id, struct clk *clk,
 				      struct reset_control *rst);
 
+static inline int tegra_powergate_power_on_legacy(int id, struct clk *clk,
+						  struct reset_control *rst)
+{
+	int err = tegra_powergate_sequence_power_up(id, clk, rst);
+
+	if (!err) {
+		usleep_range(10, 20);
+		clk_disable_unprepare(clk);
+	}
+
+	return err;
+}
+
+int tegra_powergate_power_off_legacy(int id, struct clk *clk,
+				     struct reset_control *rst);
+
 int tegra_io_rail_power_on(int id);
 int tegra_io_rail_power_off(int id);
 #else
@@ -155,6 +173,18 @@ static inline int tegra_io_rail_power_off(int id)
 {
 	return -ENOSYS;
 }
+
+static inline int tegra_powergate_power_on_legacy(int id, struct clk *clk,
+						  struct reset_control *rst)
+{
+	return -ENOTSUPP;
+}
+
+static inline int tegra_powergate_power_off_legacy(int id, struct clk *clk,
+						   struct reset_control *rst)
+{
+	return -ENOTSUPP;
+}
 #endif /* CONFIG_ARCH_TEGRA */
 
 #endif /* __SOC_TEGRA_PMC_H__ */
-- 
2.1.4


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

* [PATCH V3 09/19] soc: tegra: pmc: Prepare for migrating to generic PM domains
@ 2015-07-13 12:39   ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

When turning on and off power-domains it is necessary to enable specific
clocks in order to de-assert/assert various reset signals to place the
logic into a good state.

Currently, clocks required for turning on a power-domain are left enabled
by the PMC driver because these clocks are also needed by the IP blocks
to operated.

When migrating to the generic PM domain infrastructure, control of the
powergates is abstracted from the drivers and therefore, it is desirable
to disabled the clocks after turning on the power-domain and let the
drivers enable the clocks it needs later. However, because this behaviour
is different it is necessary to add a new API that drivers can use
whether generic PM domains are used or not so that the behaviour is the
same. Hence, add a new API that disables the clocks after turning on the
power domain.

Similarly, for disabling a power-domain add a new API to abstract the
management of the clocks so that drivers can be migrated to generic PM
domains.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/soc/tegra/pmc.c | 23 +++++++++++++++++++++++
 include/soc/tegra/pmc.h | 30 ++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 180d434deec5..934653785bb7 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -331,6 +331,29 @@ err_power:
 }
 EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
 
+int tegra_powergate_power_off_legacy(int id, struct clk *clk,
+				     struct reset_control *rst)
+{
+	int ret;
+
+	ret = clk_prepare_enable(clk);
+	if (ret)
+		return ret;
+
+	usleep_range(10, 20);
+
+	reset_control_assert(rst);
+
+	usleep_range(10, 20);
+
+	clk_disable_unprepare(clk);
+
+	usleep_range(10, 20);
+
+	return tegra_powergate_power_off(id);
+}
+EXPORT_SYMBOL(tegra_powergate_power_off_legacy);
+
 #ifdef CONFIG_SMP
 /**
  * tegra_get_cpu_powergate_id() - convert from CPU ID to partition ID
diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h
index 3a014c121399..4ca91d39304d 100644
--- a/include/soc/tegra/pmc.h
+++ b/include/soc/tegra/pmc.h
@@ -19,6 +19,8 @@
 #ifndef __SOC_TEGRA_PMC_H__
 #define __SOC_TEGRA_PMC_H__
 
+#include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/reboot.h>
 
 #include <soc/tegra/pm.h>
@@ -117,6 +119,22 @@ int tegra_powergate_remove_clamping(int id);
 int tegra_powergate_sequence_power_up(int id, struct clk *clk,
 				      struct reset_control *rst);
 
+static inline int tegra_powergate_power_on_legacy(int id, struct clk *clk,
+						  struct reset_control *rst)
+{
+	int err = tegra_powergate_sequence_power_up(id, clk, rst);
+
+	if (!err) {
+		usleep_range(10, 20);
+		clk_disable_unprepare(clk);
+	}
+
+	return err;
+}
+
+int tegra_powergate_power_off_legacy(int id, struct clk *clk,
+				     struct reset_control *rst);
+
 int tegra_io_rail_power_on(int id);
 int tegra_io_rail_power_off(int id);
 #else
@@ -155,6 +173,18 @@ static inline int tegra_io_rail_power_off(int id)
 {
 	return -ENOSYS;
 }
+
+static inline int tegra_powergate_power_on_legacy(int id, struct clk *clk,
+						  struct reset_control *rst)
+{
+	return -ENOTSUPP;
+}
+
+static inline int tegra_powergate_power_off_legacy(int id, struct clk *clk,
+						   struct reset_control *rst)
+{
+	return -ENOTSUPP;
+}
 #endif /* CONFIG_ARCH_TEGRA */
 
 #endif /* __SOC_TEGRA_PMC_H__ */
-- 
2.1.4

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

* [PATCH V3 10/19] drm/tegra: dc: Prepare for generic PM domains
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39   ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra, devicetree, linux-arm-kernel, linux-pm, Jon Hunter

Add support to the tegra dc driver for generic PM domains. However,
to ensure backward compatibility with older device tree blobs ensure
that the driver can work with or without generic PM domains. In order
to migrate to generic PM domain infrastructure the necessary changes
are:

1. If the "power-domains" property is present in the DT device node then
   generic PM domains is supported and pm_runtime_enable() should be
   called for the device. Furthermore, the enabling and disabling of the
   power-domain is handled via calling pm_runtime_get/put, respectively.

2. To ensure that clocks are managed consistently when generic PM domains
   are used and are not used, drivers should be migrated to use the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   functions instead of the current tegra_powergate_sequence_power_up()
   and tegra_powergate_power_off(). The purpose of the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   APIs is to mimick the behaviour of the tegra generic power-domain code,
   such that if generic power domains are not supported the functionality
   is the same.

3. The main difference between the tegra_powergate_sequence_power_up() API
   and the tegra_powergate_power_on_legacy() is that the clock used to
   enable the powergate is not kept enabled when using the
   tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
   the clocks they need after calling tegra_powergate_power_on_legacy()
   and disable these clocks before calling
   tegra_powergate_power_off_legacy().

Helper functions have been added to the dc driver for handling power on
and off the power-domains with and without generic PM domain support.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/gpu/drm/tegra/dc.c | 94 +++++++++++++++++++++++++++++-----------------
 1 file changed, 59 insertions(+), 35 deletions(-)

diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index a287e4fec865..a5b2475a7b9c 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -10,6 +10,7 @@
 #include <linux/clk.h>
 #include <linux/debugfs.h>
 #include <linux/iommu.h>
+#include <linux/pm_runtime.h>
 #include <linux/reset.h>
 
 #include <soc/tegra/pmc.h>
@@ -1880,6 +1881,49 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc)
 	return 0;
 }
 
+static void tegra_dc_power_off(struct tegra_dc *dc)
+{
+	if (!dc->soc->has_powergate)
+		reset_control_assert(dc->rst);
+
+	clk_disable_unprepare(dc->clk);
+
+	if (dc->soc->has_powergate) {
+		if (pm_runtime_enabled(dc->dev))
+			pm_runtime_put_sync(dc->dev);
+		else
+			tegra_powergate_power_off_legacy(dc->powergate,
+							 dc->clk, dc->rst);
+	}
+}
+
+static int tegra_dc_power_on(struct tegra_dc *dc)
+{
+	int err;
+
+	if (dc->soc->has_powergate) {
+		if (pm_runtime_enabled(dc->dev))
+			err = pm_runtime_get_sync(dc->dev);
+		else
+			err = tegra_powergate_power_on_legacy(dc->powergate,
+							      dc->clk, dc->rst);
+		if (err < 0) {
+			dev_err(dc->dev, "failed to power partition: %d\n",
+				err);
+			return err;
+		}
+	}
+
+	err = clk_prepare_enable(dc->clk);
+	if (err < 0)
+		dev_err(dc->dev, "failed to enable clock: %d\n", err);
+
+	if (!dc->soc->has_powergate)
+		reset_control_deassert(dc->rst);
+
+	return err;
+}
+
 static int tegra_dc_probe(struct platform_device *pdev)
 {
 	unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
@@ -1917,35 +1961,6 @@ static int tegra_dc_probe(struct platform_device *pdev)
 		return PTR_ERR(dc->rst);
 	}
 
-	if (dc->soc->has_powergate) {
-		if (dc->pipe == 0)
-			dc->powergate = TEGRA_POWERGATE_DIS;
-		else
-			dc->powergate = TEGRA_POWERGATE_DISB;
-
-		err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk,
-							dc->rst);
-		if (err < 0) {
-			dev_err(&pdev->dev, "failed to power partition: %d\n",
-				err);
-			return err;
-		}
-	} else {
-		err = clk_prepare_enable(dc->clk);
-		if (err < 0) {
-			dev_err(&pdev->dev, "failed to enable clock: %d\n",
-				err);
-			return err;
-		}
-
-		err = reset_control_deassert(dc->rst);
-		if (err < 0) {
-			dev_err(&pdev->dev, "failed to deassert reset: %d\n",
-				err);
-			return err;
-		}
-	}
-
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	dc->regs = devm_ioremap_resource(&pdev->dev, regs);
 	if (IS_ERR(dc->regs))
@@ -1961,6 +1976,20 @@ static int tegra_dc_probe(struct platform_device *pdev)
 	dc->client.ops = &dc_client_ops;
 	dc->client.dev = &pdev->dev;
 
+	if (dc->soc->has_powergate) {
+		if (dc->pipe == 0)
+			dc->powergate = TEGRA_POWERGATE_DIS;
+		else
+			dc->powergate = TEGRA_POWERGATE_DISB;
+
+		if (of_property_read_bool(pdev->dev.of_node, "power-domains"))
+			pm_runtime_enable(&pdev->dev);
+	}
+
+	err = tegra_dc_power_on(dc);
+	if (err < 0)
+		return err;
+
 	err = tegra_dc_rgb_probe(dc);
 	if (err < 0 && err != -ENODEV) {
 		dev_err(&pdev->dev, "failed to probe RGB output: %d\n", err);
@@ -2003,12 +2032,7 @@ static int tegra_dc_remove(struct platform_device *pdev)
 		return err;
 	}
 
-	reset_control_assert(dc->rst);
-
-	if (dc->soc->has_powergate)
-		tegra_powergate_power_off(dc->powergate);
-
-	clk_disable_unprepare(dc->clk);
+	tegra_dc_power_off(dc);
 
 	return 0;
 }
-- 
2.1.4


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

* [PATCH V3 10/19] drm/tegra: dc: Prepare for generic PM domains
@ 2015-07-13 12:39   ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

Add support to the tegra dc driver for generic PM domains. However,
to ensure backward compatibility with older device tree blobs ensure
that the driver can work with or without generic PM domains. In order
to migrate to generic PM domain infrastructure the necessary changes
are:

1. If the "power-domains" property is present in the DT device node then
   generic PM domains is supported and pm_runtime_enable() should be
   called for the device. Furthermore, the enabling and disabling of the
   power-domain is handled via calling pm_runtime_get/put, respectively.

2. To ensure that clocks are managed consistently when generic PM domains
   are used and are not used, drivers should be migrated to use the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   functions instead of the current tegra_powergate_sequence_power_up()
   and tegra_powergate_power_off(). The purpose of the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   APIs is to mimick the behaviour of the tegra generic power-domain code,
   such that if generic power domains are not supported the functionality
   is the same.

3. The main difference between the tegra_powergate_sequence_power_up() API
   and the tegra_powergate_power_on_legacy() is that the clock used to
   enable the powergate is not kept enabled when using the
   tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
   the clocks they need after calling tegra_powergate_power_on_legacy()
   and disable these clocks before calling
   tegra_powergate_power_off_legacy().

Helper functions have been added to the dc driver for handling power on
and off the power-domains with and without generic PM domain support.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/gpu/drm/tegra/dc.c | 94 +++++++++++++++++++++++++++++-----------------
 1 file changed, 59 insertions(+), 35 deletions(-)

diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index a287e4fec865..a5b2475a7b9c 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -10,6 +10,7 @@
 #include <linux/clk.h>
 #include <linux/debugfs.h>
 #include <linux/iommu.h>
+#include <linux/pm_runtime.h>
 #include <linux/reset.h>
 
 #include <soc/tegra/pmc.h>
@@ -1880,6 +1881,49 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc)
 	return 0;
 }
 
+static void tegra_dc_power_off(struct tegra_dc *dc)
+{
+	if (!dc->soc->has_powergate)
+		reset_control_assert(dc->rst);
+
+	clk_disable_unprepare(dc->clk);
+
+	if (dc->soc->has_powergate) {
+		if (pm_runtime_enabled(dc->dev))
+			pm_runtime_put_sync(dc->dev);
+		else
+			tegra_powergate_power_off_legacy(dc->powergate,
+							 dc->clk, dc->rst);
+	}
+}
+
+static int tegra_dc_power_on(struct tegra_dc *dc)
+{
+	int err;
+
+	if (dc->soc->has_powergate) {
+		if (pm_runtime_enabled(dc->dev))
+			err = pm_runtime_get_sync(dc->dev);
+		else
+			err = tegra_powergate_power_on_legacy(dc->powergate,
+							      dc->clk, dc->rst);
+		if (err < 0) {
+			dev_err(dc->dev, "failed to power partition: %d\n",
+				err);
+			return err;
+		}
+	}
+
+	err = clk_prepare_enable(dc->clk);
+	if (err < 0)
+		dev_err(dc->dev, "failed to enable clock: %d\n", err);
+
+	if (!dc->soc->has_powergate)
+		reset_control_deassert(dc->rst);
+
+	return err;
+}
+
 static int tegra_dc_probe(struct platform_device *pdev)
 {
 	unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
@@ -1917,35 +1961,6 @@ static int tegra_dc_probe(struct platform_device *pdev)
 		return PTR_ERR(dc->rst);
 	}
 
-	if (dc->soc->has_powergate) {
-		if (dc->pipe == 0)
-			dc->powergate = TEGRA_POWERGATE_DIS;
-		else
-			dc->powergate = TEGRA_POWERGATE_DISB;
-
-		err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk,
-							dc->rst);
-		if (err < 0) {
-			dev_err(&pdev->dev, "failed to power partition: %d\n",
-				err);
-			return err;
-		}
-	} else {
-		err = clk_prepare_enable(dc->clk);
-		if (err < 0) {
-			dev_err(&pdev->dev, "failed to enable clock: %d\n",
-				err);
-			return err;
-		}
-
-		err = reset_control_deassert(dc->rst);
-		if (err < 0) {
-			dev_err(&pdev->dev, "failed to deassert reset: %d\n",
-				err);
-			return err;
-		}
-	}
-
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	dc->regs = devm_ioremap_resource(&pdev->dev, regs);
 	if (IS_ERR(dc->regs))
@@ -1961,6 +1976,20 @@ static int tegra_dc_probe(struct platform_device *pdev)
 	dc->client.ops = &dc_client_ops;
 	dc->client.dev = &pdev->dev;
 
+	if (dc->soc->has_powergate) {
+		if (dc->pipe == 0)
+			dc->powergate = TEGRA_POWERGATE_DIS;
+		else
+			dc->powergate = TEGRA_POWERGATE_DISB;
+
+		if (of_property_read_bool(pdev->dev.of_node, "power-domains"))
+			pm_runtime_enable(&pdev->dev);
+	}
+
+	err = tegra_dc_power_on(dc);
+	if (err < 0)
+		return err;
+
 	err = tegra_dc_rgb_probe(dc);
 	if (err < 0 && err != -ENODEV) {
 		dev_err(&pdev->dev, "failed to probe RGB output: %d\n", err);
@@ -2003,12 +2032,7 @@ static int tegra_dc_remove(struct platform_device *pdev)
 		return err;
 	}
 
-	reset_control_assert(dc->rst);
-
-	if (dc->soc->has_powergate)
-		tegra_powergate_power_off(dc->powergate);
-
-	clk_disable_unprepare(dc->clk);
+	tegra_dc_power_off(dc);
 
 	return 0;
 }
-- 
2.1.4

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

* [PATCH V3 11/19] PCI: tegra: Add support for generic PM domains
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39   ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra, devicetree, linux-arm-kernel, linux-pm, Jon Hunter

Add support to the tegra PCI driver for generic PM domains. However,
to ensure backward compatibility with older device tree blobs ensure
that the driver can work with or without generic PM domains. In order
to migrate to generic PM domain infrastructure the necessary changes
are:

1. If the "power-domains" property is present in the DT device node then
   generic PM domains is supported and pm_runtime_enable() should be
   called for the device. Furthermore, the enabling and disabling of the
   power-domain is handled via calling pm_runtime_get/put, respectively.

2. To ensure that clocks are managed consistently when generic PM domains
   are used and are not used, drivers should be migrated to use the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   functions instead of the current tegra_powergate_sequence_power_up()
   and tegra_powergate_power_off(). The purpose of the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   APIs is to mimick the behaviour of the tegra generic power-domain code,
   such that if generic power domains are not supported the functionality
   is the same.

3. The main difference between the tegra_powergate_sequence_power_up() API
   and the tegra_powergate_power_on_legacy() is that the clock used to
   enable the powergate is not kept enabled when using the
   tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
   the clocks they need after calling tegra_powergate_power_on_legacy()
   and disable these clocks before calling
   tegra_powergate_power_off_legacy().

The helper functions for handling the powering on and off of the PCI
controller have been updated to support generic PM domains. The
tegra_pcie_power_off() was missing code to disable the clocks enabled in
the tegra_pcie_power_on() function and so this has been added.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/pci/host/pci-tegra.c | 49 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 37 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index 10c05718dbfd..acd1f311eee5 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -40,6 +40,7 @@
 #include <linux/pci.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/reset.h>
 #include <linux/sizes.h>
 #include <linux/slab.h>
@@ -908,19 +909,32 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
 
 static void tegra_pcie_power_off(struct tegra_pcie *pcie)
 {
+	const struct tegra_pcie_soc_data *soc = pcie->soc_data;
 	int err;
 
-	/* TODO: disable and unprepare clocks? */
-
 	err = phy_power_off(pcie->phy);
 	if (err < 0)
 		dev_warn(pcie->dev, "failed to power off PHY: %d\n", err);
 
 	reset_control_assert(pcie->pcie_xrst);
 	reset_control_assert(pcie->afi_rst);
-	reset_control_assert(pcie->pex_rst);
 
-	tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
+	clk_disable_unprepare(pcie->pll_e);
+	if (soc->has_cml_clk)
+		clk_disable_unprepare(pcie->cml_clk);
+	clk_disable_unprepare(pcie->afi_clk);
+	clk_disable_unprepare(pcie->pex_clk);
+
+	if (pm_runtime_enabled(pcie->dev)) {
+		err = pm_runtime_put_sync(pcie->dev);
+	} else {
+		err = tegra_powergate_power_off_legacy(TEGRA_POWERGATE_PCIE,
+						       pcie->pex_clk,
+						       pcie->pex_rst);
+	}
+
+	if (err < 0)
+		dev_warn(pcie->dev, "powergate power-down failed: %d\n", err);
 
 	err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
 	if (err < 0)
@@ -934,20 +948,28 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
 
 	reset_control_assert(pcie->pcie_xrst);
 	reset_control_assert(pcie->afi_rst);
-	reset_control_assert(pcie->pex_rst);
-
-	tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
 
 	/* enable regulators */
 	err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies);
 	if (err < 0)
 		dev_err(pcie->dev, "failed to enable regulators: %d\n", err);
 
-	err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
-						pcie->pex_clk,
-						pcie->pex_rst);
-	if (err) {
-		dev_err(pcie->dev, "powerup sequence failed: %d\n", err);
+	if (pm_runtime_enabled(pcie->dev)) {
+		err = pm_runtime_get_sync(pcie->dev);
+	} else {
+		err = tegra_powergate_power_on_legacy(TEGRA_POWERGATE_PCIE,
+						      pcie->pex_clk,
+						      pcie->pex_rst);
+	}
+
+	if (err < 0) {
+		dev_err(pcie->dev, "powergate power-up failed: %d\n", err);
+		return err;
+	}
+
+	err = clk_prepare_enable(pcie->pex_clk);
+	if (err < 0) {
+		dev_err(pcie->dev, "failed to enable PEX clock: %d\n", err);
 		return err;
 	}
 
@@ -2001,6 +2023,9 @@ static int tegra_pcie_probe(struct platform_device *pdev)
 
 	pcibios_min_mem = 0;
 
+	if (of_property_read_bool(pdev->dev.of_node, "power-domains"))
+		pm_runtime_enable(&pdev->dev);
+
 	err = tegra_pcie_get_resources(pcie);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to request resources: %d\n", err);
-- 
2.1.4


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

* [PATCH V3 11/19] PCI: tegra: Add support for generic PM domains
@ 2015-07-13 12:39   ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

Add support to the tegra PCI driver for generic PM domains. However,
to ensure backward compatibility with older device tree blobs ensure
that the driver can work with or without generic PM domains. In order
to migrate to generic PM domain infrastructure the necessary changes
are:

1. If the "power-domains" property is present in the DT device node then
   generic PM domains is supported and pm_runtime_enable() should be
   called for the device. Furthermore, the enabling and disabling of the
   power-domain is handled via calling pm_runtime_get/put, respectively.

2. To ensure that clocks are managed consistently when generic PM domains
   are used and are not used, drivers should be migrated to use the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   functions instead of the current tegra_powergate_sequence_power_up()
   and tegra_powergate_power_off(). The purpose of the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   APIs is to mimick the behaviour of the tegra generic power-domain code,
   such that if generic power domains are not supported the functionality
   is the same.

3. The main difference between the tegra_powergate_sequence_power_up() API
   and the tegra_powergate_power_on_legacy() is that the clock used to
   enable the powergate is not kept enabled when using the
   tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
   the clocks they need after calling tegra_powergate_power_on_legacy()
   and disable these clocks before calling
   tegra_powergate_power_off_legacy().

The helper functions for handling the powering on and off of the PCI
controller have been updated to support generic PM domains. The
tegra_pcie_power_off() was missing code to disable the clocks enabled in
the tegra_pcie_power_on() function and so this has been added.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/pci/host/pci-tegra.c | 49 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 37 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index 10c05718dbfd..acd1f311eee5 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -40,6 +40,7 @@
 #include <linux/pci.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/reset.h>
 #include <linux/sizes.h>
 #include <linux/slab.h>
@@ -908,19 +909,32 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
 
 static void tegra_pcie_power_off(struct tegra_pcie *pcie)
 {
+	const struct tegra_pcie_soc_data *soc = pcie->soc_data;
 	int err;
 
-	/* TODO: disable and unprepare clocks? */
-
 	err = phy_power_off(pcie->phy);
 	if (err < 0)
 		dev_warn(pcie->dev, "failed to power off PHY: %d\n", err);
 
 	reset_control_assert(pcie->pcie_xrst);
 	reset_control_assert(pcie->afi_rst);
-	reset_control_assert(pcie->pex_rst);
 
-	tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
+	clk_disable_unprepare(pcie->pll_e);
+	if (soc->has_cml_clk)
+		clk_disable_unprepare(pcie->cml_clk);
+	clk_disable_unprepare(pcie->afi_clk);
+	clk_disable_unprepare(pcie->pex_clk);
+
+	if (pm_runtime_enabled(pcie->dev)) {
+		err = pm_runtime_put_sync(pcie->dev);
+	} else {
+		err = tegra_powergate_power_off_legacy(TEGRA_POWERGATE_PCIE,
+						       pcie->pex_clk,
+						       pcie->pex_rst);
+	}
+
+	if (err < 0)
+		dev_warn(pcie->dev, "powergate power-down failed: %d\n", err);
 
 	err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
 	if (err < 0)
@@ -934,20 +948,28 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
 
 	reset_control_assert(pcie->pcie_xrst);
 	reset_control_assert(pcie->afi_rst);
-	reset_control_assert(pcie->pex_rst);
-
-	tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
 
 	/* enable regulators */
 	err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies);
 	if (err < 0)
 		dev_err(pcie->dev, "failed to enable regulators: %d\n", err);
 
-	err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
-						pcie->pex_clk,
-						pcie->pex_rst);
-	if (err) {
-		dev_err(pcie->dev, "powerup sequence failed: %d\n", err);
+	if (pm_runtime_enabled(pcie->dev)) {
+		err = pm_runtime_get_sync(pcie->dev);
+	} else {
+		err = tegra_powergate_power_on_legacy(TEGRA_POWERGATE_PCIE,
+						      pcie->pex_clk,
+						      pcie->pex_rst);
+	}
+
+	if (err < 0) {
+		dev_err(pcie->dev, "powergate power-up failed: %d\n", err);
+		return err;
+	}
+
+	err = clk_prepare_enable(pcie->pex_clk);
+	if (err < 0) {
+		dev_err(pcie->dev, "failed to enable PEX clock: %d\n", err);
 		return err;
 	}
 
@@ -2001,6 +2023,9 @@ static int tegra_pcie_probe(struct platform_device *pdev)
 
 	pcibios_min_mem = 0;
 
+	if (of_property_read_bool(pdev->dev.of_node, "power-domains"))
+		pm_runtime_enable(&pdev->dev);
+
 	err = tegra_pcie_get_resources(pcie);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to request resources: %d\n", err);
-- 
2.1.4

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

* [PATCH V3 12/19] ata: ahci_tegra: Add support for generic PM domains
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39   ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra, devicetree, linux-arm-kernel, linux-pm, Jon Hunter

Add support to the tegra AHCI driver for generic PM domains. However,
to ensure backward compatibility with older device tree blobs ensure
that the driver can work with or without generic PM domains. In order
to migrate to generic PM domain infrastructure the necessary changes
are:

1. If the "power-domains" property is present in the DT device node then
   generic PM domains is supported and the variable has_genpd should be
   set. The ahci_platform_get_resources()/put_resources() calls the
   appropriate pm_runtime functions and so no further changes are needed
   for rpm support.

2. To ensure that clocks are managed consistently when generic PM domains
   are used and are not used, drivers should be migrated to use the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   functions instead of the current tegra_powergate_sequence_power_up()
   and tegra_powergate_power_off(). The purpose of the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   APIs is to mimick the behaviour of the tegra generic power-domain code,
   such that if generic power domains are not supported the functionality
   is the same.

3. The main difference between the tegra_powergate_sequence_power_up() API
   and the tegra_powergate_power_on_legacy() is that the clock used to
   enable the powergate is not kept enabled when using the
   tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
   the clocks they need after calling tegra_powergate_power_on_legacy()
   and disable these clocks before calling
   tegra_powergate_power_off_legacy().

The helper functions for handling the powering on and off of the AHCI
controller have been updated to support generic PM domains and the
following changes have been made:
a). The clocks for the AHCI controller are managed by
    the ahci_platform_enable_resources() and
    ahci_platform_disable_resources() and so the calls to
    clock_disable_unprepare() are not needed and can be removed.
b). The tegra->sata_rst is handled by the tegra powergate code and
    so does not need to be controlled by the driver.
c). AHCI controller resets should be applied before the clocks are
    disabled and so the call to ahci_platform_disable_resources()
    has been moved to after the reset assertion.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/ata/ahci_tegra.c | 51 ++++++++++++++++++++++++++++++++++--------------
 1 file changed, 36 insertions(+), 15 deletions(-)

diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c
index 3a62eb246d80..438849c15e0e 100644
--- a/drivers/ata/ahci_tegra.c
+++ b/drivers/ata/ahci_tegra.c
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 
@@ -108,6 +109,7 @@ struct tegra_ahci_priv {
 	/* Needs special handling, cannot use ahci_platform */
 	struct clk		   *sata_clk;
 	struct regulator_bulk_data supplies[5];
+	bool			   has_genpd;
 };
 
 static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
@@ -120,11 +122,13 @@ static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
 	if (ret)
 		return ret;
 
-	ret = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_SATA,
-						tegra->sata_clk,
-						tegra->sata_rst);
-	if (ret)
-		goto disable_regulators;
+	if (!tegra->has_genpd) {
+		ret = tegra_powergate_power_on_legacy(TEGRA_POWERGATE_SATA,
+						      tegra->sata_clk,
+						      tegra->sata_rst);
+		if (ret)
+			goto disable_regulators;
+	}
 
 	reset_control_assert(tegra->sata_oob_rst);
 	reset_control_assert(tegra->sata_cold_rst);
@@ -139,9 +143,8 @@ static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
 	return 0;
 
 disable_power:
-	clk_disable_unprepare(tegra->sata_clk);
-
-	tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
+	tegra_powergate_power_off_legacy(TEGRA_POWERGATE_SATA, tegra->sata_clk,
+					 tegra->sata_rst);
 
 disable_regulators:
 	regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies);
@@ -149,20 +152,27 @@ disable_regulators:
 	return ret;
 }
 
-static void tegra_ahci_power_off(struct ahci_host_priv *hpriv)
+static int tegra_ahci_power_off(struct ahci_host_priv *hpriv)
 {
 	struct tegra_ahci_priv *tegra = hpriv->plat_data;
+	int ret;
 
-	ahci_platform_disable_resources(hpriv);
-
-	reset_control_assert(tegra->sata_rst);
 	reset_control_assert(tegra->sata_oob_rst);
 	reset_control_assert(tegra->sata_cold_rst);
 
-	clk_disable_unprepare(tegra->sata_clk);
-	tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
+	ahci_platform_disable_resources(hpriv);
+
+	if (!tegra->has_genpd) {
+		ret = tegra_powergate_power_off_legacy(TEGRA_POWERGATE_SATA,
+						       tegra->sata_clk,
+						       tegra->sata_rst);
+		if (ret)
+			return ret;
+	}
 
 	regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies);
+
+	return 0;
 }
 
 static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv)
@@ -263,7 +273,15 @@ static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv)
 
 static void tegra_ahci_controller_deinit(struct ahci_host_priv *hpriv)
 {
-	tegra_ahci_power_off(hpriv);
+	struct tegra_ahci_priv *tegra = hpriv->plat_data;
+	int ret;
+
+	ret = tegra_ahci_power_off(hpriv);
+
+	if (ret)
+		dev_err(&tegra->pdev->dev,
+			"failed to power off AHCI controller: %d\n", ret);
+
 }
 
 static void tegra_ahci_host_stop(struct ata_host *host)
@@ -356,6 +374,9 @@ static int tegra_ahci_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	if (of_property_read_bool(pdev->dev.of_node, "power-domains"))
+		tegra->has_genpd = true;
+
 	ret = tegra_ahci_controller_init(hpriv);
 	if (ret)
 		return ret;
-- 
2.1.4


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

* [PATCH V3 12/19] ata: ahci_tegra: Add support for generic PM domains
@ 2015-07-13 12:39   ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

Add support to the tegra AHCI driver for generic PM domains. However,
to ensure backward compatibility with older device tree blobs ensure
that the driver can work with or without generic PM domains. In order
to migrate to generic PM domain infrastructure the necessary changes
are:

1. If the "power-domains" property is present in the DT device node then
   generic PM domains is supported and the variable has_genpd should be
   set. The ahci_platform_get_resources()/put_resources() calls the
   appropriate pm_runtime functions and so no further changes are needed
   for rpm support.

2. To ensure that clocks are managed consistently when generic PM domains
   are used and are not used, drivers should be migrated to use the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   functions instead of the current tegra_powergate_sequence_power_up()
   and tegra_powergate_power_off(). The purpose of the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   APIs is to mimick the behaviour of the tegra generic power-domain code,
   such that if generic power domains are not supported the functionality
   is the same.

3. The main difference between the tegra_powergate_sequence_power_up() API
   and the tegra_powergate_power_on_legacy() is that the clock used to
   enable the powergate is not kept enabled when using the
   tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
   the clocks they need after calling tegra_powergate_power_on_legacy()
   and disable these clocks before calling
   tegra_powergate_power_off_legacy().

The helper functions for handling the powering on and off of the AHCI
controller have been updated to support generic PM domains and the
following changes have been made:
a). The clocks for the AHCI controller are managed by
    the ahci_platform_enable_resources() and
    ahci_platform_disable_resources() and so the calls to
    clock_disable_unprepare() are not needed and can be removed.
b). The tegra->sata_rst is handled by the tegra powergate code and
    so does not need to be controlled by the driver.
c). AHCI controller resets should be applied before the clocks are
    disabled and so the call to ahci_platform_disable_resources()
    has been moved to after the reset assertion.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/ata/ahci_tegra.c | 51 ++++++++++++++++++++++++++++++++++--------------
 1 file changed, 36 insertions(+), 15 deletions(-)

diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c
index 3a62eb246d80..438849c15e0e 100644
--- a/drivers/ata/ahci_tegra.c
+++ b/drivers/ata/ahci_tegra.c
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 
@@ -108,6 +109,7 @@ struct tegra_ahci_priv {
 	/* Needs special handling, cannot use ahci_platform */
 	struct clk		   *sata_clk;
 	struct regulator_bulk_data supplies[5];
+	bool			   has_genpd;
 };
 
 static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
@@ -120,11 +122,13 @@ static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
 	if (ret)
 		return ret;
 
-	ret = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_SATA,
-						tegra->sata_clk,
-						tegra->sata_rst);
-	if (ret)
-		goto disable_regulators;
+	if (!tegra->has_genpd) {
+		ret = tegra_powergate_power_on_legacy(TEGRA_POWERGATE_SATA,
+						      tegra->sata_clk,
+						      tegra->sata_rst);
+		if (ret)
+			goto disable_regulators;
+	}
 
 	reset_control_assert(tegra->sata_oob_rst);
 	reset_control_assert(tegra->sata_cold_rst);
@@ -139,9 +143,8 @@ static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
 	return 0;
 
 disable_power:
-	clk_disable_unprepare(tegra->sata_clk);
-
-	tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
+	tegra_powergate_power_off_legacy(TEGRA_POWERGATE_SATA, tegra->sata_clk,
+					 tegra->sata_rst);
 
 disable_regulators:
 	regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies);
@@ -149,20 +152,27 @@ disable_regulators:
 	return ret;
 }
 
-static void tegra_ahci_power_off(struct ahci_host_priv *hpriv)
+static int tegra_ahci_power_off(struct ahci_host_priv *hpriv)
 {
 	struct tegra_ahci_priv *tegra = hpriv->plat_data;
+	int ret;
 
-	ahci_platform_disable_resources(hpriv);
-
-	reset_control_assert(tegra->sata_rst);
 	reset_control_assert(tegra->sata_oob_rst);
 	reset_control_assert(tegra->sata_cold_rst);
 
-	clk_disable_unprepare(tegra->sata_clk);
-	tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
+	ahci_platform_disable_resources(hpriv);
+
+	if (!tegra->has_genpd) {
+		ret = tegra_powergate_power_off_legacy(TEGRA_POWERGATE_SATA,
+						       tegra->sata_clk,
+						       tegra->sata_rst);
+		if (ret)
+			return ret;
+	}
 
 	regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies);
+
+	return 0;
 }
 
 static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv)
@@ -263,7 +273,15 @@ static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv)
 
 static void tegra_ahci_controller_deinit(struct ahci_host_priv *hpriv)
 {
-	tegra_ahci_power_off(hpriv);
+	struct tegra_ahci_priv *tegra = hpriv->plat_data;
+	int ret;
+
+	ret = tegra_ahci_power_off(hpriv);
+
+	if (ret)
+		dev_err(&tegra->pdev->dev,
+			"failed to power off AHCI controller: %d\n", ret);
+
 }
 
 static void tegra_ahci_host_stop(struct ata_host *host)
@@ -356,6 +374,9 @@ static int tegra_ahci_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	if (of_property_read_bool(pdev->dev.of_node, "power-domains"))
+		tegra->has_genpd = true;
+
 	ret = tegra_ahci_controller_init(hpriv);
 	if (ret)
 		return ret;
-- 
2.1.4

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

* [PATCH V3 13/19] drm/tegra: gr3d: Add support for generic PM domains
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39   ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra, devicetree, linux-arm-kernel, linux-pm, Jon Hunter

Add support to the tegra gr3d driver for generic PM domains. However,
to ensure backward compatibility with older device tree blobs ensure
that the driver can work with or without generic PM domains. In order
to migrate to generic PM domain infrastructure the necessary changes
are:

1. If the "power-domains" property is present in the DT device node then
   generic PM domains is supported and pm_runtime_enable() should be
   called for the device. Furthermore, the enabling and disabling of the
   power-domain is handled via calling pm_runtime_get/put, respectively.

2. To ensure that clocks are managed consistently when generic PM domains
   are used and are not used, drivers should be migrated to use the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   functions instead of the current tegra_powergate_sequence_power_up()
   and tegra_powergate_power_off(). The purpose of the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   APIs is to mimick the behaviour of the tegra generic power-domain code,
   such that if generic power domains are not supported the functionality
   is the same.

3. The main difference between the tegra_powergate_sequence_power_up() API
   and the tegra_powergate_power_on_legacy() is that the clock used to
   enable the powergate is not kept enabled when using the
   tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
   the clocks they need after calling tegra_powergate_power_on_legacy()
   and disable these clocks before calling
   tegra_powergate_power_off_legacy().

Helper functions have been added to the gr3d driver for handling power on
and off the power-domains with and without generic PM domain support.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/gpu/drm/tegra/gr3d.c | 57 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 50 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c
index 0b3f2b977ba0..43a9d50e7e44 100644
--- a/drivers/gpu/drm/tegra/gr3d.c
+++ b/drivers/gpu/drm/tegra/gr3d.c
@@ -11,6 +11,7 @@
 #include <linux/host1x.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/reset.h>
 
 #include <soc/tegra/pmc.h>
@@ -238,6 +239,32 @@ static const u32 gr3d_addr_regs[] = {
 	GR3D_GLOBAL_SAMP23SURFADDR(15),
 };
 
+static int gr3d_powergate_on(struct platform_device *pdev, int powergate_id,
+			     struct clk *clk, struct reset_control *rst)
+{
+	int err;
+
+	if (pm_runtime_enabled(&pdev->dev))
+		err = pm_runtime_get_sync(&pdev->dev);
+	else
+		err = tegra_powergate_power_on_legacy(powergate_id,
+						      clk, rst);
+	return err;
+}
+
+static int gr3d_powergate_off(struct platform_device *pdev, int powergate_id,
+			      struct clk *clk, struct reset_control *rst)
+{
+	int err;
+
+	if (pm_runtime_enabled(&pdev->dev))
+		err = pm_runtime_put_sync(&pdev->dev);
+	else
+		err = tegra_powergate_power_off_legacy(powergate_id,
+						       clk, rst);
+	return err;
+}
+
 static int gr3d_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -281,22 +308,37 @@ static int gr3d_probe(struct platform_device *pdev)
 		}
 	}
 
-	err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D, gr3d->clk,
-						gr3d->rst);
+	if (of_property_read_bool(pdev->dev.of_node, "power-domains"))
+		pm_runtime_enable(&pdev->dev);
+
+	err = gr3d_powergate_on(pdev, TEGRA_POWERGATE_3D, gr3d->clk, gr3d->rst);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to power up 3D unit\n");
 		return err;
 	}
 
+	err = clk_prepare_enable(gr3d->clk);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to enable 3D unit clock\n");
+		return err;
+	}
+
 	if (gr3d->clk_secondary) {
-		err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D1,
-							gr3d->clk_secondary,
-							gr3d->rst_secondary);
+		err = gr3d_powergate_on(pdev, TEGRA_POWERGATE_3D1,
+					gr3d->clk_secondary,
+					gr3d->rst_secondary);
 		if (err < 0) {
 			dev_err(&pdev->dev,
 				"failed to power up secondary 3D unit\n");
 			return err;
 		}
+
+		err = clk_prepare_enable(gr3d->clk_secondary);
+		if (err < 0) {
+			dev_err(&pdev->dev,
+				"failed to enable secondary 3D unit clock\n");
+			return err;
+		}
 	}
 
 	INIT_LIST_HEAD(&gr3d->client.base.list);
@@ -338,12 +380,13 @@ static int gr3d_remove(struct platform_device *pdev)
 	}
 
 	if (gr3d->clk_secondary) {
-		tegra_powergate_power_off(TEGRA_POWERGATE_3D1);
 		clk_disable_unprepare(gr3d->clk_secondary);
+		gr3d_powergate_off(pdev, TEGRA_POWERGATE_3D1,
+				   gr3d->clk_secondary, gr3d->rst_secondary);
 	}
 
-	tegra_powergate_power_off(TEGRA_POWERGATE_3D);
 	clk_disable_unprepare(gr3d->clk);
+	gr3d_powergate_off(pdev, TEGRA_POWERGATE_3D, gr3d->clk, gr3d->rst);
 
 	return 0;
 }
-- 
2.1.4


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

* [PATCH V3 13/19] drm/tegra: gr3d: Add support for generic PM domains
@ 2015-07-13 12:39   ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

Add support to the tegra gr3d driver for generic PM domains. However,
to ensure backward compatibility with older device tree blobs ensure
that the driver can work with or without generic PM domains. In order
to migrate to generic PM domain infrastructure the necessary changes
are:

1. If the "power-domains" property is present in the DT device node then
   generic PM domains is supported and pm_runtime_enable() should be
   called for the device. Furthermore, the enabling and disabling of the
   power-domain is handled via calling pm_runtime_get/put, respectively.

2. To ensure that clocks are managed consistently when generic PM domains
   are used and are not used, drivers should be migrated to use the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   functions instead of the current tegra_powergate_sequence_power_up()
   and tegra_powergate_power_off(). The purpose of the
   tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
   APIs is to mimick the behaviour of the tegra generic power-domain code,
   such that if generic power domains are not supported the functionality
   is the same.

3. The main difference between the tegra_powergate_sequence_power_up() API
   and the tegra_powergate_power_on_legacy() is that the clock used to
   enable the powergate is not kept enabled when using the
   tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
   the clocks they need after calling tegra_powergate_power_on_legacy()
   and disable these clocks before calling
   tegra_powergate_power_off_legacy().

Helper functions have been added to the gr3d driver for handling power on
and off the power-domains with and without generic PM domain support.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/gpu/drm/tegra/gr3d.c | 57 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 50 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c
index 0b3f2b977ba0..43a9d50e7e44 100644
--- a/drivers/gpu/drm/tegra/gr3d.c
+++ b/drivers/gpu/drm/tegra/gr3d.c
@@ -11,6 +11,7 @@
 #include <linux/host1x.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/reset.h>
 
 #include <soc/tegra/pmc.h>
@@ -238,6 +239,32 @@ static const u32 gr3d_addr_regs[] = {
 	GR3D_GLOBAL_SAMP23SURFADDR(15),
 };
 
+static int gr3d_powergate_on(struct platform_device *pdev, int powergate_id,
+			     struct clk *clk, struct reset_control *rst)
+{
+	int err;
+
+	if (pm_runtime_enabled(&pdev->dev))
+		err = pm_runtime_get_sync(&pdev->dev);
+	else
+		err = tegra_powergate_power_on_legacy(powergate_id,
+						      clk, rst);
+	return err;
+}
+
+static int gr3d_powergate_off(struct platform_device *pdev, int powergate_id,
+			      struct clk *clk, struct reset_control *rst)
+{
+	int err;
+
+	if (pm_runtime_enabled(&pdev->dev))
+		err = pm_runtime_put_sync(&pdev->dev);
+	else
+		err = tegra_powergate_power_off_legacy(powergate_id,
+						       clk, rst);
+	return err;
+}
+
 static int gr3d_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -281,22 +308,37 @@ static int gr3d_probe(struct platform_device *pdev)
 		}
 	}
 
-	err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D, gr3d->clk,
-						gr3d->rst);
+	if (of_property_read_bool(pdev->dev.of_node, "power-domains"))
+		pm_runtime_enable(&pdev->dev);
+
+	err = gr3d_powergate_on(pdev, TEGRA_POWERGATE_3D, gr3d->clk, gr3d->rst);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to power up 3D unit\n");
 		return err;
 	}
 
+	err = clk_prepare_enable(gr3d->clk);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to enable 3D unit clock\n");
+		return err;
+	}
+
 	if (gr3d->clk_secondary) {
-		err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D1,
-							gr3d->clk_secondary,
-							gr3d->rst_secondary);
+		err = gr3d_powergate_on(pdev, TEGRA_POWERGATE_3D1,
+					gr3d->clk_secondary,
+					gr3d->rst_secondary);
 		if (err < 0) {
 			dev_err(&pdev->dev,
 				"failed to power up secondary 3D unit\n");
 			return err;
 		}
+
+		err = clk_prepare_enable(gr3d->clk_secondary);
+		if (err < 0) {
+			dev_err(&pdev->dev,
+				"failed to enable secondary 3D unit clock\n");
+			return err;
+		}
 	}
 
 	INIT_LIST_HEAD(&gr3d->client.base.list);
@@ -338,12 +380,13 @@ static int gr3d_remove(struct platform_device *pdev)
 	}
 
 	if (gr3d->clk_secondary) {
-		tegra_powergate_power_off(TEGRA_POWERGATE_3D1);
 		clk_disable_unprepare(gr3d->clk_secondary);
+		gr3d_powergate_off(pdev, TEGRA_POWERGATE_3D1,
+				   gr3d->clk_secondary, gr3d->rst_secondary);
 	}
 
-	tegra_powergate_power_off(TEGRA_POWERGATE_3D);
 	clk_disable_unprepare(gr3d->clk);
+	gr3d_powergate_off(pdev, TEGRA_POWERGATE_3D, gr3d->clk, gr3d->rst);
 
 	return 0;
 }
-- 
2.1.4

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

* [PATCH V3 14/19] Documentation: DT: bindings: Add power domain info for NVIDIA PMC
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39     ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Jon Hunter

Add power-domain binding documentation for the NVIDIA PMC driver in
order to support generic power-domains.

Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 .../bindings/arm/tegra/nvidia,tegra20-pmc.txt      | 99 ++++++++++++++++++++++
 1 file changed, 99 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
index 02c27004d4a8..93357a450576 100644
--- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
+++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
@@ -1,5 +1,7 @@
 NVIDIA Tegra Power Management Controller (PMC)
 
+== Power Management Controller Node ==
+
 The PMC block interacts with an external Power Management Unit. The PMC
 mostly controls the entry and exit of the system from different sleep
 modes. It provides power-gating controllers for SoC and CPU power-islands.
@@ -68,6 +70,10 @@ Optional properties for hardware-triggered thermal reset (inside 'i2c-thermtrip'
                      Defaults to 0. Valid values are described in section 12.5.2
                      "Pinmux Support" of the Tegra4 Technical Reference Manual.
 
+Optional nodes:
+- pm-domains : This node contains a hierarchy of PM domain nodes, which should
+	       match the power-domains on the Tegra SoC.
+
 Example:
 
 / SoC dts including file
@@ -113,3 +119,96 @@ pmc@7000f400 {
 	};
 	...
 };
+
+
+== PM Domain Nodes ==
+
+Each of the PM domain nodes represents a power-domain on the Tegra SoC
+that can be power-gated by the PMC and should be named appropriately.
+
+Required properties:
+  - clocks:		   Must contain an entry for each clock required by
+			   the PMC for controlling a power-gate. See
+			   ../clocks/clock-bindings.txt for details.
+  - resets:		   Must contain an entry for each reset required by
+			   the PMC for controlling a power-gate. See
+			   ../reset/reset.txt for details.
+  - nvidia,powergate:	   Integer cell that contains an identifier for the
+			   PMC power-gate that is associated with the
+			   power-domain. Please refer to the Tegra TRM for
+			   more details.
+  - #power-domain-cells:   Must be 0.
+
+Optional properties:
+  - nvidia,swgroups:	   Provides details of the software groups that are
+			   associated with a specific power-domain. The
+			   software group specifier consists of a phandle
+			   pointing to the memory controller and a list of
+			   one or more integer cells for each software group
+			   associated with the power domain. The length of
+			   the list of integer cells is specified by
+			   #nvidia,swgroup-cells.
+  - #nvidia,swgroup-cells: Must be 1 or more. See nvidia,swgroups for
+			   more details.
+
+Example:
+
+	pmc@0,7000e400 {
+		compatible = "nvidia,tegra124-pmc";
+		reg = <0x0 0x7000e400 0x0 0x400>;
+		clocks = <&tegra_car TEGRA124_CLK_PCLK>, <&clk32k_in>;
+		clock-names = "pclk", "clk32k_in";
+
+		pm-domains {
+
+			...
+
+			pd_sor: sor-power-domain {
+				clocks = <&tegra_car TEGRA124_CLK_SOR0>,
+					 <&tegra_car TEGRA124_CLK_DSIA>,
+					 <&tegra_car TEGRA124_CLK_DSIB>,
+					 <&tegra_car TEGRA124_CLK_HDMI>,
+					 <&tegra_car TEGRA124_CLK_MIPI_CAL>,
+					 <&tegra_car TEGRA124_CLK_DPAUX>;
+				resets = <&tegra_car 182>,
+					 <&tegra_car 48>,
+					 <&tegra_car 82>,
+					 <&tegra_car 51>,
+					 <&tegra_car 56>;
+				nvidia,powergate = <TEGRA_POWERGATE_SOR>;
+				#power-domain-cells = <0>;
+
+				pd_dc: dc-power-domain {
+					clocks = <&tegra_car TEGRA124_CLK_DISP1>;
+					resets = <&tegra_car 27>;
+					nvidia,powergate = <TEGRA_POWERGATE_DIS>;
+					nvidia,swgroups = <&mc TEGRA_SWGROUP_DC>;
+					#nvidia,swgroup-cells = <1>;
+					#power-domain-cells = <0>;
+
+					pd_dcb: dcb-power-domain {
+						clocks = <&tegra_car TEGRA124_CLK_DISP2>;
+						resets = <&tegra_car 26>;
+						nvidia,powergate = <TEGRA_POWERGATE_DISB>;
+						nvidia,swgroups = <&mc TEGRA_SWGROUP_DCB>;
+						#nvidia,swgroup-cells = <1>;
+						#power-domain-cells = <0>;
+					};
+				};
+			};
+		};
+	};
+
+
+== PM Domain Consumers ==
+
+Hardware blocks belonging to a PM domain should contain a "power-domains"
+property that is a phandle pointing to the corresponding PM domain node.
+
+Example:
+
+	sor@0,54540000 {
+		...
+		power-domains = <&pd_sor>;
+		...
+	};
-- 
2.1.4

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

* [PATCH V3 14/19] Documentation: DT: bindings: Add power domain info for NVIDIA PMC
@ 2015-07-13 12:39     ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

Add power-domain binding documentation for the NVIDIA PMC driver in
order to support generic power-domains.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 .../bindings/arm/tegra/nvidia,tegra20-pmc.txt      | 99 ++++++++++++++++++++++
 1 file changed, 99 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
index 02c27004d4a8..93357a450576 100644
--- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
+++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
@@ -1,5 +1,7 @@
 NVIDIA Tegra Power Management Controller (PMC)
 
+== Power Management Controller Node ==
+
 The PMC block interacts with an external Power Management Unit. The PMC
 mostly controls the entry and exit of the system from different sleep
 modes. It provides power-gating controllers for SoC and CPU power-islands.
@@ -68,6 +70,10 @@ Optional properties for hardware-triggered thermal reset (inside 'i2c-thermtrip'
                      Defaults to 0. Valid values are described in section 12.5.2
                      "Pinmux Support" of the Tegra4 Technical Reference Manual.
 
+Optional nodes:
+- pm-domains : This node contains a hierarchy of PM domain nodes, which should
+	       match the power-domains on the Tegra SoC.
+
 Example:
 
 / SoC dts including file
@@ -113,3 +119,96 @@ pmc at 7000f400 {
 	};
 	...
 };
+
+
+== PM Domain Nodes ==
+
+Each of the PM domain nodes represents a power-domain on the Tegra SoC
+that can be power-gated by the PMC and should be named appropriately.
+
+Required properties:
+  - clocks:		   Must contain an entry for each clock required by
+			   the PMC for controlling a power-gate. See
+			   ../clocks/clock-bindings.txt for details.
+  - resets:		   Must contain an entry for each reset required by
+			   the PMC for controlling a power-gate. See
+			   ../reset/reset.txt for details.
+  - nvidia,powergate:	   Integer cell that contains an identifier for the
+			   PMC power-gate that is associated with the
+			   power-domain. Please refer to the Tegra TRM for
+			   more details.
+  - #power-domain-cells:   Must be 0.
+
+Optional properties:
+  - nvidia,swgroups:	   Provides details of the software groups that are
+			   associated with a specific power-domain. The
+			   software group specifier consists of a phandle
+			   pointing to the memory controller and a list of
+			   one or more integer cells for each software group
+			   associated with the power domain. The length of
+			   the list of integer cells is specified by
+			   #nvidia,swgroup-cells.
+  - #nvidia,swgroup-cells: Must be 1 or more. See nvidia,swgroups for
+			   more details.
+
+Example:
+
+	pmc at 0,7000e400 {
+		compatible = "nvidia,tegra124-pmc";
+		reg = <0x0 0x7000e400 0x0 0x400>;
+		clocks = <&tegra_car TEGRA124_CLK_PCLK>, <&clk32k_in>;
+		clock-names = "pclk", "clk32k_in";
+
+		pm-domains {
+
+			...
+
+			pd_sor: sor-power-domain {
+				clocks = <&tegra_car TEGRA124_CLK_SOR0>,
+					 <&tegra_car TEGRA124_CLK_DSIA>,
+					 <&tegra_car TEGRA124_CLK_DSIB>,
+					 <&tegra_car TEGRA124_CLK_HDMI>,
+					 <&tegra_car TEGRA124_CLK_MIPI_CAL>,
+					 <&tegra_car TEGRA124_CLK_DPAUX>;
+				resets = <&tegra_car 182>,
+					 <&tegra_car 48>,
+					 <&tegra_car 82>,
+					 <&tegra_car 51>,
+					 <&tegra_car 56>;
+				nvidia,powergate = <TEGRA_POWERGATE_SOR>;
+				#power-domain-cells = <0>;
+
+				pd_dc: dc-power-domain {
+					clocks = <&tegra_car TEGRA124_CLK_DISP1>;
+					resets = <&tegra_car 27>;
+					nvidia,powergate = <TEGRA_POWERGATE_DIS>;
+					nvidia,swgroups = <&mc TEGRA_SWGROUP_DC>;
+					#nvidia,swgroup-cells = <1>;
+					#power-domain-cells = <0>;
+
+					pd_dcb: dcb-power-domain {
+						clocks = <&tegra_car TEGRA124_CLK_DISP2>;
+						resets = <&tegra_car 26>;
+						nvidia,powergate = <TEGRA_POWERGATE_DISB>;
+						nvidia,swgroups = <&mc TEGRA_SWGROUP_DCB>;
+						#nvidia,swgroup-cells = <1>;
+						#power-domain-cells = <0>;
+					};
+				};
+			};
+		};
+	};
+
+
+== PM Domain Consumers ==
+
+Hardware blocks belonging to a PM domain should contain a "power-domains"
+property that is a phandle pointing to the corresponding PM domain node.
+
+Example:
+
+	sor at 0,54540000 {
+		...
+		power-domains = <&pd_sor>;
+		...
+	};
-- 
2.1.4

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

* [PATCH V3 15/19] soc: tegra: pmc: Add generic PM domain support
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39     ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Jon Hunter

Adds generic PM support to the PMC driver where the PM domains are
populated from device-tree and the PM domain consumer devices are
bound to their relevant PM domains via device-tree as well.

Update the tegra_powergate_power_on_legacy/off_legacy() APIs so that
internally they call the same tegra_powergate_xxx functions that are
used by the tegra generic power domain code for consistency.

This is based upon work by Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
and Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>.

Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/soc/tegra/pmc.c                     | 545 +++++++++++++++++++++++++++-
 include/dt-bindings/power/tegra-powergate.h |  42 +++
 include/soc/tegra/pmc.h                     |  52 +--
 3 files changed, 580 insertions(+), 59 deletions(-)
 create mode 100644 include/dt-bindings/power/tegra-powergate.h

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 934653785bb7..4de92a9dae65 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -19,8 +19,11 @@
 
 #define pr_fmt(fmt) "tegra-pmc: " fmt
 
+#include <dt-bindings/power/tegra-powergate.h>
+
 #include <linux/kernel.h>
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/clk/tegra.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
@@ -30,17 +33,24 @@
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/pm_domain.h>
 #include <linux/reboot.h>
+#include <linux/regulator/consumer.h>
 #include <linux/reset.h>
+#include <linux/sched.h>
 #include <linux/seq_file.h>
 #include <linux/spinlock.h>
 
 #include <soc/tegra/common.h>
 #include <soc/tegra/fuse.h>
+#include <soc/tegra/mc.h>
 #include <soc/tegra/pmc.h>
 
+#define PMC_POWERGATE_ARRAY_MAX		10
+
 #define PMC_CNTRL			0x0
 #define  PMC_CNTRL_SYSCLK_POLARITY	(1 << 10)  /* sys clk polarity */
 #define  PMC_CNTRL_SYSCLK_OE		(1 << 11)  /* system clock enable */
@@ -106,6 +116,22 @@
 
 #define PMC_PWRGATE_STATE(val, id)	(!!(val & BIT(id)))
 
+struct tegra_powergate {
+	struct generic_pm_domain genpd;
+	struct tegra_pmc *pmc;
+	struct tegra_mc *mc;
+	unsigned int id;
+	struct list_head node;
+	struct device_node *of_node;
+	struct regulator *vdd;
+	struct clk **clks;
+	struct reset_control **resets;
+	const struct tegra_mc_flush **flushes;
+	u32 num_clks;
+	u32 num_resets;
+	u32 num_flushes;
+};
+
 struct tegra_pmc_soc {
 	unsigned int num_powergates;
 	const char *const *powergates;
@@ -118,8 +144,10 @@ struct tegra_pmc_soc {
 
 /**
  * struct tegra_pmc - NVIDIA Tegra PMC
+ * @dev: pointer to parent device
  * @base: pointer to I/O remapped register region
  * @clk: pointer to pclk clock
+ * @soc: SoC-specific data
  * @rate: currently configured rate of pclk
  * @suspend_mode: lowest suspend mode available
  * @cpu_good_time: CPU power good time (in microseconds)
@@ -133,6 +161,7 @@ struct tegra_pmc_soc {
  * @cpu_pwr_good_en: CPU power good signal is enabled
  * @lp0_vec_phys: physical base address of the LP0 warm boot code
  * @lp0_vec_size: size of the LP0 warm boot code
+ * @powergates_list: list of power gates
  * @powergates_lock: mutex for power gate register access
  */
 struct tegra_pmc {
@@ -157,6 +186,7 @@ struct tegra_pmc {
 	u32 lp0_vec_phys;
 	u32 lp0_vec_size;
 
+	struct list_head powergates_list;
 	struct mutex powergates_lock;
 };
 
@@ -165,6 +195,12 @@ static struct tegra_pmc *pmc = &(struct tegra_pmc) {
 	.suspend_mode = TEGRA_SUSPEND_NONE,
 };
 
+static inline struct tegra_powergate *
+to_powergate(struct generic_pm_domain *domain)
+{
+	return container_of(domain, struct tegra_powergate, genpd);
+}
+
 static u32 tegra_pmc_readl(unsigned long offset)
 {
 	return readl(pmc->base + offset);
@@ -175,6 +211,37 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
 	writel(value, pmc->base + offset);
 }
 
+static int tegra_powergate_get_regulator(struct tegra_powergate *powergate)
+{
+	struct platform_device *pdev;
+
+	if (powergate->id != TEGRA_POWERGATE_EXT)
+		return -EINVAL;
+
+	pdev = of_find_device_by_node(powergate->of_node);
+	if (!pdev)
+		return -EINVAL;
+
+	powergate->vdd = devm_regulator_get_optional(&pdev->dev, "vdd");
+	if (IS_ERR(powergate->vdd))
+		return PTR_ERR(powergate->vdd);
+
+	return 0;
+}
+
+static int tegra_powergate_enable_regulator(struct tegra_powergate *powergate)
+{
+	int ret = 0;
+
+	if (IS_ERR_OR_NULL(powergate->vdd))
+		ret = tegra_powergate_get_regulator(powergate);
+
+	if (!ret)
+		ret = regulator_enable(powergate->vdd);
+
+	return ret;
+}
+
 /**
  * tegra_powergate_set() - set the state of a partition
  * @id: partition ID
@@ -207,6 +274,215 @@ static int tegra_powergate_set(int id, bool new_state, bool wait)
 	return ret;
 }
 
+static int tegra_powergate_enable(struct tegra_powergate *powergate,
+				  bool enable)
+{
+	if (powergate->id != TEGRA_POWERGATE_EXT)
+		return tegra_powergate_set(powergate->id, enable, true);
+
+	if (enable)
+		return tegra_powergate_enable_regulator(powergate);
+	else
+		return regulator_disable(powergate->vdd);
+}
+
+static bool tegra_powergate_is_supported(int id)
+{
+	switch (id) {
+	case TEGRA_POWERGATE_CPU:
+	case TEGRA_POWERGATE_CPU1:
+	case TEGRA_POWERGATE_CPU2:
+	case TEGRA_POWERGATE_CPU3:
+	case TEGRA_POWERGATE_CPU0:
+	case TEGRA_POWERGATE_C0NC:
+	case TEGRA_POWERGATE_IRAM:
+		return false;
+	default:
+		return true;
+	}
+}
+
+static bool _tegra_powergate_is_powered(struct tegra_powergate *powergate)
+{
+	if (powergate->id != TEGRA_POWERGATE_EXT)
+		return tegra_powergate_is_powered(powergate->id);
+
+	if (IS_ERR(powergate->vdd))
+		return false;
+	else
+		return regulator_is_enabled(powergate->vdd);
+}
+
+static void tegra_powergate_disable_clocks(struct tegra_powergate *powergate)
+{
+	int i;
+
+	for (i = 0; i < powergate->num_clks; i++)
+		clk_disable_unprepare(powergate->clks[i]);
+}
+
+static int tegra_powergate_enable_clocks(struct tegra_powergate *powergate)
+{
+	int err, i;
+
+	for (i = 0; i < powergate->num_clks; i++) {
+		err = clk_prepare_enable(powergate->clks[i]);
+		if (err)
+			goto out;
+	}
+
+	return 0;
+
+out:
+	while (i--)
+		clk_disable_unprepare(powergate->clks[i]);
+
+	return err;
+}
+
+static int tegra_powergate_mc_flush(struct tegra_powergate *powergate,
+				    bool enable)
+{
+	int i, err;
+
+	for (i = 0; i < powergate->num_flushes; i++) {
+		err = tegra_mc_flush(powergate->mc, powergate->flushes[i],
+				     enable);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int tegra_powergate_reset_assert(struct tegra_powergate *powergate)
+{
+	int err, i;
+
+	for (i = 0; i < powergate->num_resets; i++) {
+		err = reset_control_assert(powergate->resets[i]);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int tegra_powergate_reset_deassert(struct tegra_powergate *powergate)
+{
+	int err, i;
+
+	for (i = 0; i < powergate->num_resets; i++) {
+		err = reset_control_deassert(powergate->resets[i]);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int tegra_powergate_seq_power_up(struct tegra_powergate *powergate)
+{
+	int err;
+
+	err = tegra_powergate_reset_assert(powergate);
+	if (err)
+		goto out;
+	udelay(10);
+
+	err = tegra_powergate_enable(powergate, true);
+	if (err < 0)
+		goto out;
+	udelay(10);
+
+	err = tegra_powergate_enable_clocks(powergate);
+	if (err)
+		goto out;
+	udelay(10);
+
+	tegra_powergate_remove_clamping(powergate->id);
+
+	udelay(10);
+
+	err = tegra_powergate_reset_deassert(powergate);
+	if (err)
+		goto out;
+	udelay(10);
+
+	err = tegra_powergate_mc_flush(powergate, false);
+	if (err)
+		goto out;
+	udelay(10);
+
+	tegra_powergate_disable_clocks(powergate);
+
+	return 0;
+
+out:
+	return err;
+}
+
+static int tegra_powergate_seq_power_down(struct tegra_powergate *powergate)
+{
+	int err;
+
+	err = tegra_powergate_enable_clocks(powergate);
+	if (err)
+		goto out;
+	udelay(10);
+
+	err = tegra_powergate_mc_flush(powergate, true);
+	if (err)
+		goto out;
+	udelay(10);
+
+	err = tegra_powergate_reset_assert(powergate);
+	if (err)
+		goto out;
+	udelay(10);
+
+	tegra_powergate_disable_clocks(powergate);
+
+	udelay(10);
+
+	err = tegra_powergate_enable(powergate, false);
+	if (err)
+		goto out;
+
+	return 0;
+
+out:
+	return err;
+}
+
+static int tegra_genpd_power_on(struct generic_pm_domain *domain)
+{
+	struct tegra_powergate *powergate = to_powergate(domain);
+	struct tegra_pmc *pmc = powergate->pmc;
+	int err;
+
+	err = tegra_powergate_seq_power_up(powergate);
+
+	if (err)
+		dev_err(pmc->dev, "Failed to turn on PM Domain (%d)\n", err);
+
+	return 0;
+}
+
+static int tegra_genpd_power_off(struct generic_pm_domain *domain)
+{
+	struct tegra_powergate *powergate = to_powergate(domain);
+	struct tegra_pmc *pmc = powergate->pmc;
+	int err;
+
+	err = tegra_powergate_seq_power_down(powergate);
+
+	if (err)
+		dev_err(pmc->dev, "Failed to turn off PM Domain (%d)\n", err);
+
+	return err;
+}
+
 /**
  * tegra_powergate_power_on() - power on partition
  * @id: partition ID
@@ -247,6 +523,8 @@ int tegra_powergate_is_powered(int id)
 /**
  * tegra_powergate_remove_clamping() - remove power clamps for partition
  * @id: partition ID
+ *
+ * TODO: make this function static once we get rid of all outside callers
  */
 int tegra_powergate_remove_clamping(int id)
 {
@@ -331,26 +609,41 @@ err_power:
 }
 EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
 
-int tegra_powergate_power_off_legacy(int id, struct clk *clk,
-				     struct reset_control *rst)
+int tegra_powergate_power_on_legacy(int id, struct clk *clk,
+				    struct reset_control *rst)
 {
-	int ret;
+	struct tegra_powergate powergate;
 
-	ret = clk_prepare_enable(clk);
-	if (ret)
-		return ret;
+	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
+		return -EINVAL;
 
-	usleep_range(10, 20);
+	powergate.id = id;
+	powergate.clks = &clk;
+	powergate.resets = &rst;
+	powergate.num_clks = 1;
+	powergate.num_resets = 1;
+	powergate.num_flushes = 0;
 
-	reset_control_assert(rst);
+	return tegra_powergate_seq_power_up(&powergate);
+}
+EXPORT_SYMBOL(tegra_powergate_power_on_legacy);
 
-	usleep_range(10, 20);
+int tegra_powergate_power_off_legacy(int id, struct clk *clk,
+				     struct reset_control *rst)
+{
+	struct tegra_powergate powergate;
 
-	clk_disable_unprepare(clk);
+	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
+		return -EINVAL;
 
-	usleep_range(10, 20);
+	powergate.id = id;
+	powergate.clks = &clk;
+	powergate.resets = &rst;
+	powergate.num_clks = 1;
+	powergate.num_resets = 1;
+	powergate.num_flushes = 0;
 
-	return tegra_powergate_power_off(id);
+	return tegra_powergate_seq_power_down(&powergate);
 }
 EXPORT_SYMBOL(tegra_powergate_power_off_legacy);
 
@@ -493,6 +786,228 @@ static int tegra_powergate_debugfs_init(void)
 	return 0;
 }
 
+static int tegra_powergate_of_get_clks(struct device *dev,
+				       struct tegra_powergate *powergate)
+{
+	struct clk *clks[PMC_POWERGATE_ARRAY_MAX];
+	int i = 0;
+
+	for (i = 0; i < PMC_POWERGATE_ARRAY_MAX; i++) {
+		clks[i] = of_clk_get(powergate->of_node, i);
+		if (IS_ERR(clks[i])) {
+			if (PTR_ERR(clks[i]) != -ENOENT)
+				return PTR_ERR(clks[i]);
+			break;
+		}
+	}
+
+	if (PTR_ERR(clks[i]) != -ENOENT) {
+		dev_err(dev, "unsupported number of clocks defined\n");
+		return -EINVAL;
+	}
+
+	powergate->clks = devm_kcalloc(dev, i, sizeof(*clks), GFP_KERNEL);
+	if (!powergate->clks)
+		return -ENOMEM;
+
+	memcpy(powergate->clks, clks, sizeof(*clks) * i);
+	powergate->num_clks = i;
+
+	return 0;
+}
+
+static int tegra_powergate_of_get_resets(struct device *dev,
+					 struct tegra_powergate *powergate)
+{
+	struct reset_control *rsts[PMC_POWERGATE_ARRAY_MAX];
+	int i = 0;
+
+	for (i = 0; i < PMC_POWERGATE_ARRAY_MAX; i++) {
+		rsts[i] = of_reset_control_get_by_index(powergate->of_node, i);
+		if (IS_ERR(rsts[i])) {
+			if (PTR_ERR(rsts[i]) != -ENOENT)
+				return PTR_ERR(rsts[i]);
+			break;
+		}
+	}
+
+	if (PTR_ERR(rsts[i]) != -ENOENT) {
+		dev_err(dev, "unsupported number of resets defined\n");
+		return -EINVAL;
+	}
+
+	powergate->resets = devm_kcalloc(dev, i, sizeof(*rsts), GFP_KERNEL);
+	if (!powergate->resets)
+		return -ENOMEM;
+
+	memcpy(powergate->resets, rsts, sizeof(*rsts) * i);
+	powergate->num_resets = i;
+
+	return 0;
+}
+
+static int tegra_powergate_of_get_mc_flush(struct device *dev,
+					   struct tegra_powergate *powergate)
+{
+	struct platform_device *pdev;
+	struct of_phandle_args args;
+	int i = 0, ret = 0;
+
+	ret = of_parse_phandle_with_args(dev->of_node, "nvidia-swgroups",
+					"#nvidia,swgroup-cells", 0, &args);
+	if (ret < 0) {
+		/*
+		 * The nvidia-swgroups property is
+		 * optional and so if missing simply return.
+		 */
+		if (ret == -ENOENT)
+			return 0;
+
+		dev_err(dev, "nvidia-swgroups property invalid for %s (%d)\n",
+			powergate->of_node->name, ret);
+		return ret;
+	}
+
+	powergate->flushes = devm_kcalloc(dev, args.args_count,
+					  sizeof(powergate->flushes),
+					  GFP_KERNEL);
+	if (!powergate->flushes) {
+		dev_err(dev, "failed to allocate memory for powergate flush\n");
+		return -ENOMEM;
+	}
+
+	pdev = of_find_device_by_node(args.np);
+	if (!pdev)
+		return -ENODEV;
+
+	powergate->mc = platform_get_drvdata(pdev);
+	if (!powergate->mc)
+		return -EINVAL;
+
+	for (i = 0; i < args.args_count; i++) {
+		powergate->flushes[i] = tegra_mc_flush_get(powergate->mc,
+							   args.args[i]);
+		if (!powergate->flushes[i])
+			return -EINVAL;
+	}
+
+	powergate->num_flushes = args.args_count;
+
+	return 0;
+}
+
+static int tegra_powergate_init_powerdomain(struct tegra_pmc *pmc,
+					    struct device_node *np,
+					    struct tegra_powergate *pg)
+{
+	bool off;
+	int err;
+
+	err = of_property_read_u32(np, "nvidia,powergate", &pg->id);
+	if (err) {
+		dev_err(pmc->dev, "no powergate ID for domain\n");
+		goto err;
+	}
+
+	if (tegra_powergate_is_supported(pg->id) == false) {
+		dev_warn(pmc->dev, "%s not currently supported by genpd\n",
+			 np->name);
+		return -EINVAL;
+	}
+
+	if (pg->id == TEGRA_POWERGATE_EXT) {
+		err = tegra_powergate_get_regulator(pg);
+		if (err) {
+			/*
+			 * The regulator might not be ready yet, so just
+			 * give a warning instead of failing the whole
+			 * init.
+			 */
+			dev_warn(pmc->dev, "couldn't locate regulator\n");
+		}
+	}
+
+	pg->of_node = np;
+	pg->genpd.name = np->name;
+	pg->genpd.power_off = tegra_genpd_power_off;
+	pg->genpd.power_on = tegra_genpd_power_on;
+	pg->pmc = pmc;
+
+	err = tegra_powergate_of_get_clks(pmc->dev, pg);
+	if (err)
+		goto err;
+
+	err = tegra_powergate_of_get_resets(pmc->dev, pg);
+	if (err)
+		goto err;
+
+	err = tegra_powergate_of_get_mc_flush(pmc->dev, pg);
+	if (err)
+		goto err;
+
+	list_add_tail(&pg->node, &pmc->powergates_list);
+
+	if (!IS_ERR(pg->vdd) || pg->id != TEGRA_POWERGATE_EXT)
+		tegra_genpd_power_off(&pg->genpd);
+
+	off = !_tegra_powergate_is_powered(pg);
+
+	pm_genpd_init(&pg->genpd, NULL, off);
+
+	dev_info(pmc->dev, "added power domain %s\n", np->name);
+
+	return 0;
+
+err:
+	dev_err(pmc->dev, "failed to add power domain for node %s\n",
+		np->name);
+	return err;
+}
+
+static int tegra_powergate_add_powerdomains(struct tegra_pmc *pmc,
+					    struct device_node *parent,
+					    struct generic_pm_domain *pd_parent)
+{
+	struct device_node *np;
+	int ret;
+
+	for_each_child_of_node(parent, np) {
+		struct tegra_powergate *pg;
+
+		pg = devm_kzalloc(pmc->dev, sizeof(*pg), GFP_KERNEL);
+		if (!pg)
+			return -ENOMEM;
+
+		ret = tegra_powergate_init_powerdomain(pmc, np, pg);
+		if (ret)
+			return ret;
+
+		if (pd_parent)
+			pm_genpd_add_subdomain(pd_parent, &pg->genpd);
+
+		of_genpd_add_provider_simple(np, &pg->genpd);
+
+		tegra_powergate_add_powerdomains(pmc, np, &pg->genpd);
+	}
+
+	return 0;
+}
+
+static int tegra_powergate_init(struct tegra_pmc *pmc)
+{
+	struct device_node *np;
+
+	INIT_LIST_HEAD(&pmc->powergates_list);
+
+	np = of_get_child_by_name(pmc->dev->of_node, "pm-domains");
+	if (!np) {
+		dev_dbg(pmc->dev, "power-domains node not found\n");
+		return 0;
+	}
+
+	return tegra_powergate_add_powerdomains(pmc, np, NULL);
+}
+
 static int tegra_io_rail_prepare(int id, unsigned long *request,
 				 unsigned long *status, unsigned int *bit)
 {
@@ -875,6 +1390,12 @@ static int tegra_pmc_probe(struct platform_device *pdev)
 
 	tegra_pmc_init_tsense_reset(pmc);
 
+	if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
+		err = tegra_powergate_init(pmc);
+		if (err < 0)
+			return err;
+	}
+
 	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
 		err = tegra_powergate_debugfs_init();
 		if (err < 0)
diff --git a/include/dt-bindings/power/tegra-powergate.h b/include/dt-bindings/power/tegra-powergate.h
new file mode 100644
index 000000000000..b1d51f028a99
--- /dev/null
+++ b/include/dt-bindings/power/tegra-powergate.h
@@ -0,0 +1,42 @@
+#ifndef _DT_BINDINGS_POWER_TEGRA_POWERGATE_H
+#define _DT_BINDINGS_POWER_TEGRA_POWERGATE_H
+
+#define TEGRA_POWERGATE_CPU	0
+#define TEGRA_POWERGATE_3D	1
+#define TEGRA_POWERGATE_VENC	2
+#define TEGRA_POWERGATE_PCIE	3
+#define TEGRA_POWERGATE_VDEC	4
+#define TEGRA_POWERGATE_L2	5
+#define TEGRA_POWERGATE_MPE	6
+#define TEGRA_POWERGATE_HEG	7
+#define TEGRA_POWERGATE_SATA	8
+#define TEGRA_POWERGATE_CPU1	9
+#define TEGRA_POWERGATE_CPU2	10
+#define TEGRA_POWERGATE_CPU3	11
+#define TEGRA_POWERGATE_CELP	12
+#define TEGRA_POWERGATE_3D1	13
+#define TEGRA_POWERGATE_CPU0	14
+#define TEGRA_POWERGATE_C0NC	15
+#define TEGRA_POWERGATE_C1NC	16
+#define TEGRA_POWERGATE_SOR	17
+#define TEGRA_POWERGATE_DIS	18
+#define TEGRA_POWERGATE_DISB	19
+#define TEGRA_POWERGATE_XUSBA	20
+#define TEGRA_POWERGATE_XUSBB	21
+#define TEGRA_POWERGATE_XUSBC	22
+#define TEGRA_POWERGATE_VIC	23
+#define TEGRA_POWERGATE_IRAM	24
+#define TEGRA_POWERGATE_NVDEC	25
+#define TEGRA_POWERGATE_NVJPG	26
+#define TEGRA_POWERGATE_AUD	27
+#define TEGRA_POWERGATE_DFD	28
+#define TEGRA_POWERGATE_VE2	29
+
+/*
+ * Pseudo powergate for power-domains that are power-gated externally.
+ * Make this a large number to allow other powergates to be added.
+ */
+#define TEGRA_POWERGATE_EXT	1000
+
+
+#endif
diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h
index 4ca91d39304d..67b75d82edc7 100644
--- a/include/soc/tegra/pmc.h
+++ b/include/soc/tegra/pmc.h
@@ -19,6 +19,8 @@
 #ifndef __SOC_TEGRA_PMC_H__
 #define __SOC_TEGRA_PMC_H__
 
+#include <dt-bindings/power/tegra-powergate.h>
+
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/reboot.h>
@@ -41,42 +43,8 @@ int tegra_pmc_cpu_remove_clamping(int cpuid);
 #endif /* CONFIG_SMP */
 
 /*
- * powergate and I/O rail APIs
+ * I/O rail APIs
  */
-
-#define TEGRA_POWERGATE_CPU	0
-#define TEGRA_POWERGATE_3D	1
-#define TEGRA_POWERGATE_VENC	2
-#define TEGRA_POWERGATE_PCIE	3
-#define TEGRA_POWERGATE_VDEC	4
-#define TEGRA_POWERGATE_L2	5
-#define TEGRA_POWERGATE_MPE	6
-#define TEGRA_POWERGATE_HEG	7
-#define TEGRA_POWERGATE_SATA	8
-#define TEGRA_POWERGATE_CPU1	9
-#define TEGRA_POWERGATE_CPU2	10
-#define TEGRA_POWERGATE_CPU3	11
-#define TEGRA_POWERGATE_CELP	12
-#define TEGRA_POWERGATE_3D1	13
-#define TEGRA_POWERGATE_CPU0	14
-#define TEGRA_POWERGATE_C0NC	15
-#define TEGRA_POWERGATE_C1NC	16
-#define TEGRA_POWERGATE_SOR	17
-#define TEGRA_POWERGATE_DIS	18
-#define TEGRA_POWERGATE_DISB	19
-#define TEGRA_POWERGATE_XUSBA	20
-#define TEGRA_POWERGATE_XUSBB	21
-#define TEGRA_POWERGATE_XUSBC	22
-#define TEGRA_POWERGATE_VIC	23
-#define TEGRA_POWERGATE_IRAM	24
-#define TEGRA_POWERGATE_NVDEC	25
-#define TEGRA_POWERGATE_NVJPG	26
-#define TEGRA_POWERGATE_AUD	27
-#define TEGRA_POWERGATE_DFD	28
-#define TEGRA_POWERGATE_VE2	29
-
-#define TEGRA_POWERGATE_3D0	TEGRA_POWERGATE_3D
-
 #define TEGRA_IO_RAIL_CSIA	0
 #define TEGRA_IO_RAIL_CSIB	1
 #define TEGRA_IO_RAIL_DSI	2
@@ -119,18 +87,8 @@ int tegra_powergate_remove_clamping(int id);
 int tegra_powergate_sequence_power_up(int id, struct clk *clk,
 				      struct reset_control *rst);
 
-static inline int tegra_powergate_power_on_legacy(int id, struct clk *clk,
-						  struct reset_control *rst)
-{
-	int err = tegra_powergate_sequence_power_up(id, clk, rst);
-
-	if (!err) {
-		usleep_range(10, 20);
-		clk_disable_unprepare(clk);
-	}
-
-	return err;
-}
+int tegra_powergate_power_on_legacy(int id, struct clk *clk,
+				    struct reset_control *rst);
 
 int tegra_powergate_power_off_legacy(int id, struct clk *clk,
 				     struct reset_control *rst);
-- 
2.1.4

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

* [PATCH V3 15/19] soc: tegra: pmc: Add generic PM domain support
@ 2015-07-13 12:39     ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

Adds generic PM support to the PMC driver where the PM domains are
populated from device-tree and the PM domain consumer devices are
bound to their relevant PM domains via device-tree as well.

Update the tegra_powergate_power_on_legacy/off_legacy() APIs so that
internally they call the same tegra_powergate_xxx functions that are
used by the tegra generic power domain code for consistency.

This is based upon work by Thierry Reding <treding@nvidia.com>
and Vince Hsu <vinceh@nvidia.com>.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/soc/tegra/pmc.c                     | 545 +++++++++++++++++++++++++++-
 include/dt-bindings/power/tegra-powergate.h |  42 +++
 include/soc/tegra/pmc.h                     |  52 +--
 3 files changed, 580 insertions(+), 59 deletions(-)
 create mode 100644 include/dt-bindings/power/tegra-powergate.h

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 934653785bb7..4de92a9dae65 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -19,8 +19,11 @@
 
 #define pr_fmt(fmt) "tegra-pmc: " fmt
 
+#include <dt-bindings/power/tegra-powergate.h>
+
 #include <linux/kernel.h>
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/clk/tegra.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
@@ -30,17 +33,24 @@
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/pm_domain.h>
 #include <linux/reboot.h>
+#include <linux/regulator/consumer.h>
 #include <linux/reset.h>
+#include <linux/sched.h>
 #include <linux/seq_file.h>
 #include <linux/spinlock.h>
 
 #include <soc/tegra/common.h>
 #include <soc/tegra/fuse.h>
+#include <soc/tegra/mc.h>
 #include <soc/tegra/pmc.h>
 
+#define PMC_POWERGATE_ARRAY_MAX		10
+
 #define PMC_CNTRL			0x0
 #define  PMC_CNTRL_SYSCLK_POLARITY	(1 << 10)  /* sys clk polarity */
 #define  PMC_CNTRL_SYSCLK_OE		(1 << 11)  /* system clock enable */
@@ -106,6 +116,22 @@
 
 #define PMC_PWRGATE_STATE(val, id)	(!!(val & BIT(id)))
 
+struct tegra_powergate {
+	struct generic_pm_domain genpd;
+	struct tegra_pmc *pmc;
+	struct tegra_mc *mc;
+	unsigned int id;
+	struct list_head node;
+	struct device_node *of_node;
+	struct regulator *vdd;
+	struct clk **clks;
+	struct reset_control **resets;
+	const struct tegra_mc_flush **flushes;
+	u32 num_clks;
+	u32 num_resets;
+	u32 num_flushes;
+};
+
 struct tegra_pmc_soc {
 	unsigned int num_powergates;
 	const char *const *powergates;
@@ -118,8 +144,10 @@ struct tegra_pmc_soc {
 
 /**
  * struct tegra_pmc - NVIDIA Tegra PMC
+ * @dev: pointer to parent device
  * @base: pointer to I/O remapped register region
  * @clk: pointer to pclk clock
+ * @soc: SoC-specific data
  * @rate: currently configured rate of pclk
  * @suspend_mode: lowest suspend mode available
  * @cpu_good_time: CPU power good time (in microseconds)
@@ -133,6 +161,7 @@ struct tegra_pmc_soc {
  * @cpu_pwr_good_en: CPU power good signal is enabled
  * @lp0_vec_phys: physical base address of the LP0 warm boot code
  * @lp0_vec_size: size of the LP0 warm boot code
+ * @powergates_list: list of power gates
  * @powergates_lock: mutex for power gate register access
  */
 struct tegra_pmc {
@@ -157,6 +186,7 @@ struct tegra_pmc {
 	u32 lp0_vec_phys;
 	u32 lp0_vec_size;
 
+	struct list_head powergates_list;
 	struct mutex powergates_lock;
 };
 
@@ -165,6 +195,12 @@ static struct tegra_pmc *pmc = &(struct tegra_pmc) {
 	.suspend_mode = TEGRA_SUSPEND_NONE,
 };
 
+static inline struct tegra_powergate *
+to_powergate(struct generic_pm_domain *domain)
+{
+	return container_of(domain, struct tegra_powergate, genpd);
+}
+
 static u32 tegra_pmc_readl(unsigned long offset)
 {
 	return readl(pmc->base + offset);
@@ -175,6 +211,37 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
 	writel(value, pmc->base + offset);
 }
 
+static int tegra_powergate_get_regulator(struct tegra_powergate *powergate)
+{
+	struct platform_device *pdev;
+
+	if (powergate->id != TEGRA_POWERGATE_EXT)
+		return -EINVAL;
+
+	pdev = of_find_device_by_node(powergate->of_node);
+	if (!pdev)
+		return -EINVAL;
+
+	powergate->vdd = devm_regulator_get_optional(&pdev->dev, "vdd");
+	if (IS_ERR(powergate->vdd))
+		return PTR_ERR(powergate->vdd);
+
+	return 0;
+}
+
+static int tegra_powergate_enable_regulator(struct tegra_powergate *powergate)
+{
+	int ret = 0;
+
+	if (IS_ERR_OR_NULL(powergate->vdd))
+		ret = tegra_powergate_get_regulator(powergate);
+
+	if (!ret)
+		ret = regulator_enable(powergate->vdd);
+
+	return ret;
+}
+
 /**
  * tegra_powergate_set() - set the state of a partition
  * @id: partition ID
@@ -207,6 +274,215 @@ static int tegra_powergate_set(int id, bool new_state, bool wait)
 	return ret;
 }
 
+static int tegra_powergate_enable(struct tegra_powergate *powergate,
+				  bool enable)
+{
+	if (powergate->id != TEGRA_POWERGATE_EXT)
+		return tegra_powergate_set(powergate->id, enable, true);
+
+	if (enable)
+		return tegra_powergate_enable_regulator(powergate);
+	else
+		return regulator_disable(powergate->vdd);
+}
+
+static bool tegra_powergate_is_supported(int id)
+{
+	switch (id) {
+	case TEGRA_POWERGATE_CPU:
+	case TEGRA_POWERGATE_CPU1:
+	case TEGRA_POWERGATE_CPU2:
+	case TEGRA_POWERGATE_CPU3:
+	case TEGRA_POWERGATE_CPU0:
+	case TEGRA_POWERGATE_C0NC:
+	case TEGRA_POWERGATE_IRAM:
+		return false;
+	default:
+		return true;
+	}
+}
+
+static bool _tegra_powergate_is_powered(struct tegra_powergate *powergate)
+{
+	if (powergate->id != TEGRA_POWERGATE_EXT)
+		return tegra_powergate_is_powered(powergate->id);
+
+	if (IS_ERR(powergate->vdd))
+		return false;
+	else
+		return regulator_is_enabled(powergate->vdd);
+}
+
+static void tegra_powergate_disable_clocks(struct tegra_powergate *powergate)
+{
+	int i;
+
+	for (i = 0; i < powergate->num_clks; i++)
+		clk_disable_unprepare(powergate->clks[i]);
+}
+
+static int tegra_powergate_enable_clocks(struct tegra_powergate *powergate)
+{
+	int err, i;
+
+	for (i = 0; i < powergate->num_clks; i++) {
+		err = clk_prepare_enable(powergate->clks[i]);
+		if (err)
+			goto out;
+	}
+
+	return 0;
+
+out:
+	while (i--)
+		clk_disable_unprepare(powergate->clks[i]);
+
+	return err;
+}
+
+static int tegra_powergate_mc_flush(struct tegra_powergate *powergate,
+				    bool enable)
+{
+	int i, err;
+
+	for (i = 0; i < powergate->num_flushes; i++) {
+		err = tegra_mc_flush(powergate->mc, powergate->flushes[i],
+				     enable);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int tegra_powergate_reset_assert(struct tegra_powergate *powergate)
+{
+	int err, i;
+
+	for (i = 0; i < powergate->num_resets; i++) {
+		err = reset_control_assert(powergate->resets[i]);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int tegra_powergate_reset_deassert(struct tegra_powergate *powergate)
+{
+	int err, i;
+
+	for (i = 0; i < powergate->num_resets; i++) {
+		err = reset_control_deassert(powergate->resets[i]);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int tegra_powergate_seq_power_up(struct tegra_powergate *powergate)
+{
+	int err;
+
+	err = tegra_powergate_reset_assert(powergate);
+	if (err)
+		goto out;
+	udelay(10);
+
+	err = tegra_powergate_enable(powergate, true);
+	if (err < 0)
+		goto out;
+	udelay(10);
+
+	err = tegra_powergate_enable_clocks(powergate);
+	if (err)
+		goto out;
+	udelay(10);
+
+	tegra_powergate_remove_clamping(powergate->id);
+
+	udelay(10);
+
+	err = tegra_powergate_reset_deassert(powergate);
+	if (err)
+		goto out;
+	udelay(10);
+
+	err = tegra_powergate_mc_flush(powergate, false);
+	if (err)
+		goto out;
+	udelay(10);
+
+	tegra_powergate_disable_clocks(powergate);
+
+	return 0;
+
+out:
+	return err;
+}
+
+static int tegra_powergate_seq_power_down(struct tegra_powergate *powergate)
+{
+	int err;
+
+	err = tegra_powergate_enable_clocks(powergate);
+	if (err)
+		goto out;
+	udelay(10);
+
+	err = tegra_powergate_mc_flush(powergate, true);
+	if (err)
+		goto out;
+	udelay(10);
+
+	err = tegra_powergate_reset_assert(powergate);
+	if (err)
+		goto out;
+	udelay(10);
+
+	tegra_powergate_disable_clocks(powergate);
+
+	udelay(10);
+
+	err = tegra_powergate_enable(powergate, false);
+	if (err)
+		goto out;
+
+	return 0;
+
+out:
+	return err;
+}
+
+static int tegra_genpd_power_on(struct generic_pm_domain *domain)
+{
+	struct tegra_powergate *powergate = to_powergate(domain);
+	struct tegra_pmc *pmc = powergate->pmc;
+	int err;
+
+	err = tegra_powergate_seq_power_up(powergate);
+
+	if (err)
+		dev_err(pmc->dev, "Failed to turn on PM Domain (%d)\n", err);
+
+	return 0;
+}
+
+static int tegra_genpd_power_off(struct generic_pm_domain *domain)
+{
+	struct tegra_powergate *powergate = to_powergate(domain);
+	struct tegra_pmc *pmc = powergate->pmc;
+	int err;
+
+	err = tegra_powergate_seq_power_down(powergate);
+
+	if (err)
+		dev_err(pmc->dev, "Failed to turn off PM Domain (%d)\n", err);
+
+	return err;
+}
+
 /**
  * tegra_powergate_power_on() - power on partition
  * @id: partition ID
@@ -247,6 +523,8 @@ int tegra_powergate_is_powered(int id)
 /**
  * tegra_powergate_remove_clamping() - remove power clamps for partition
  * @id: partition ID
+ *
+ * TODO: make this function static once we get rid of all outside callers
  */
 int tegra_powergate_remove_clamping(int id)
 {
@@ -331,26 +609,41 @@ err_power:
 }
 EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
 
-int tegra_powergate_power_off_legacy(int id, struct clk *clk,
-				     struct reset_control *rst)
+int tegra_powergate_power_on_legacy(int id, struct clk *clk,
+				    struct reset_control *rst)
 {
-	int ret;
+	struct tegra_powergate powergate;
 
-	ret = clk_prepare_enable(clk);
-	if (ret)
-		return ret;
+	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
+		return -EINVAL;
 
-	usleep_range(10, 20);
+	powergate.id = id;
+	powergate.clks = &clk;
+	powergate.resets = &rst;
+	powergate.num_clks = 1;
+	powergate.num_resets = 1;
+	powergate.num_flushes = 0;
 
-	reset_control_assert(rst);
+	return tegra_powergate_seq_power_up(&powergate);
+}
+EXPORT_SYMBOL(tegra_powergate_power_on_legacy);
 
-	usleep_range(10, 20);
+int tegra_powergate_power_off_legacy(int id, struct clk *clk,
+				     struct reset_control *rst)
+{
+	struct tegra_powergate powergate;
 
-	clk_disable_unprepare(clk);
+	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
+		return -EINVAL;
 
-	usleep_range(10, 20);
+	powergate.id = id;
+	powergate.clks = &clk;
+	powergate.resets = &rst;
+	powergate.num_clks = 1;
+	powergate.num_resets = 1;
+	powergate.num_flushes = 0;
 
-	return tegra_powergate_power_off(id);
+	return tegra_powergate_seq_power_down(&powergate);
 }
 EXPORT_SYMBOL(tegra_powergate_power_off_legacy);
 
@@ -493,6 +786,228 @@ static int tegra_powergate_debugfs_init(void)
 	return 0;
 }
 
+static int tegra_powergate_of_get_clks(struct device *dev,
+				       struct tegra_powergate *powergate)
+{
+	struct clk *clks[PMC_POWERGATE_ARRAY_MAX];
+	int i = 0;
+
+	for (i = 0; i < PMC_POWERGATE_ARRAY_MAX; i++) {
+		clks[i] = of_clk_get(powergate->of_node, i);
+		if (IS_ERR(clks[i])) {
+			if (PTR_ERR(clks[i]) != -ENOENT)
+				return PTR_ERR(clks[i]);
+			break;
+		}
+	}
+
+	if (PTR_ERR(clks[i]) != -ENOENT) {
+		dev_err(dev, "unsupported number of clocks defined\n");
+		return -EINVAL;
+	}
+
+	powergate->clks = devm_kcalloc(dev, i, sizeof(*clks), GFP_KERNEL);
+	if (!powergate->clks)
+		return -ENOMEM;
+
+	memcpy(powergate->clks, clks, sizeof(*clks) * i);
+	powergate->num_clks = i;
+
+	return 0;
+}
+
+static int tegra_powergate_of_get_resets(struct device *dev,
+					 struct tegra_powergate *powergate)
+{
+	struct reset_control *rsts[PMC_POWERGATE_ARRAY_MAX];
+	int i = 0;
+
+	for (i = 0; i < PMC_POWERGATE_ARRAY_MAX; i++) {
+		rsts[i] = of_reset_control_get_by_index(powergate->of_node, i);
+		if (IS_ERR(rsts[i])) {
+			if (PTR_ERR(rsts[i]) != -ENOENT)
+				return PTR_ERR(rsts[i]);
+			break;
+		}
+	}
+
+	if (PTR_ERR(rsts[i]) != -ENOENT) {
+		dev_err(dev, "unsupported number of resets defined\n");
+		return -EINVAL;
+	}
+
+	powergate->resets = devm_kcalloc(dev, i, sizeof(*rsts), GFP_KERNEL);
+	if (!powergate->resets)
+		return -ENOMEM;
+
+	memcpy(powergate->resets, rsts, sizeof(*rsts) * i);
+	powergate->num_resets = i;
+
+	return 0;
+}
+
+static int tegra_powergate_of_get_mc_flush(struct device *dev,
+					   struct tegra_powergate *powergate)
+{
+	struct platform_device *pdev;
+	struct of_phandle_args args;
+	int i = 0, ret = 0;
+
+	ret = of_parse_phandle_with_args(dev->of_node, "nvidia-swgroups",
+					"#nvidia,swgroup-cells", 0, &args);
+	if (ret < 0) {
+		/*
+		 * The nvidia-swgroups property is
+		 * optional and so if missing simply return.
+		 */
+		if (ret == -ENOENT)
+			return 0;
+
+		dev_err(dev, "nvidia-swgroups property invalid for %s (%d)\n",
+			powergate->of_node->name, ret);
+		return ret;
+	}
+
+	powergate->flushes = devm_kcalloc(dev, args.args_count,
+					  sizeof(powergate->flushes),
+					  GFP_KERNEL);
+	if (!powergate->flushes) {
+		dev_err(dev, "failed to allocate memory for powergate flush\n");
+		return -ENOMEM;
+	}
+
+	pdev = of_find_device_by_node(args.np);
+	if (!pdev)
+		return -ENODEV;
+
+	powergate->mc = platform_get_drvdata(pdev);
+	if (!powergate->mc)
+		return -EINVAL;
+
+	for (i = 0; i < args.args_count; i++) {
+		powergate->flushes[i] = tegra_mc_flush_get(powergate->mc,
+							   args.args[i]);
+		if (!powergate->flushes[i])
+			return -EINVAL;
+	}
+
+	powergate->num_flushes = args.args_count;
+
+	return 0;
+}
+
+static int tegra_powergate_init_powerdomain(struct tegra_pmc *pmc,
+					    struct device_node *np,
+					    struct tegra_powergate *pg)
+{
+	bool off;
+	int err;
+
+	err = of_property_read_u32(np, "nvidia,powergate", &pg->id);
+	if (err) {
+		dev_err(pmc->dev, "no powergate ID for domain\n");
+		goto err;
+	}
+
+	if (tegra_powergate_is_supported(pg->id) == false) {
+		dev_warn(pmc->dev, "%s not currently supported by genpd\n",
+			 np->name);
+		return -EINVAL;
+	}
+
+	if (pg->id == TEGRA_POWERGATE_EXT) {
+		err = tegra_powergate_get_regulator(pg);
+		if (err) {
+			/*
+			 * The regulator might not be ready yet, so just
+			 * give a warning instead of failing the whole
+			 * init.
+			 */
+			dev_warn(pmc->dev, "couldn't locate regulator\n");
+		}
+	}
+
+	pg->of_node = np;
+	pg->genpd.name = np->name;
+	pg->genpd.power_off = tegra_genpd_power_off;
+	pg->genpd.power_on = tegra_genpd_power_on;
+	pg->pmc = pmc;
+
+	err = tegra_powergate_of_get_clks(pmc->dev, pg);
+	if (err)
+		goto err;
+
+	err = tegra_powergate_of_get_resets(pmc->dev, pg);
+	if (err)
+		goto err;
+
+	err = tegra_powergate_of_get_mc_flush(pmc->dev, pg);
+	if (err)
+		goto err;
+
+	list_add_tail(&pg->node, &pmc->powergates_list);
+
+	if (!IS_ERR(pg->vdd) || pg->id != TEGRA_POWERGATE_EXT)
+		tegra_genpd_power_off(&pg->genpd);
+
+	off = !_tegra_powergate_is_powered(pg);
+
+	pm_genpd_init(&pg->genpd, NULL, off);
+
+	dev_info(pmc->dev, "added power domain %s\n", np->name);
+
+	return 0;
+
+err:
+	dev_err(pmc->dev, "failed to add power domain for node %s\n",
+		np->name);
+	return err;
+}
+
+static int tegra_powergate_add_powerdomains(struct tegra_pmc *pmc,
+					    struct device_node *parent,
+					    struct generic_pm_domain *pd_parent)
+{
+	struct device_node *np;
+	int ret;
+
+	for_each_child_of_node(parent, np) {
+		struct tegra_powergate *pg;
+
+		pg = devm_kzalloc(pmc->dev, sizeof(*pg), GFP_KERNEL);
+		if (!pg)
+			return -ENOMEM;
+
+		ret = tegra_powergate_init_powerdomain(pmc, np, pg);
+		if (ret)
+			return ret;
+
+		if (pd_parent)
+			pm_genpd_add_subdomain(pd_parent, &pg->genpd);
+
+		of_genpd_add_provider_simple(np, &pg->genpd);
+
+		tegra_powergate_add_powerdomains(pmc, np, &pg->genpd);
+	}
+
+	return 0;
+}
+
+static int tegra_powergate_init(struct tegra_pmc *pmc)
+{
+	struct device_node *np;
+
+	INIT_LIST_HEAD(&pmc->powergates_list);
+
+	np = of_get_child_by_name(pmc->dev->of_node, "pm-domains");
+	if (!np) {
+		dev_dbg(pmc->dev, "power-domains node not found\n");
+		return 0;
+	}
+
+	return tegra_powergate_add_powerdomains(pmc, np, NULL);
+}
+
 static int tegra_io_rail_prepare(int id, unsigned long *request,
 				 unsigned long *status, unsigned int *bit)
 {
@@ -875,6 +1390,12 @@ static int tegra_pmc_probe(struct platform_device *pdev)
 
 	tegra_pmc_init_tsense_reset(pmc);
 
+	if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
+		err = tegra_powergate_init(pmc);
+		if (err < 0)
+			return err;
+	}
+
 	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
 		err = tegra_powergate_debugfs_init();
 		if (err < 0)
diff --git a/include/dt-bindings/power/tegra-powergate.h b/include/dt-bindings/power/tegra-powergate.h
new file mode 100644
index 000000000000..b1d51f028a99
--- /dev/null
+++ b/include/dt-bindings/power/tegra-powergate.h
@@ -0,0 +1,42 @@
+#ifndef _DT_BINDINGS_POWER_TEGRA_POWERGATE_H
+#define _DT_BINDINGS_POWER_TEGRA_POWERGATE_H
+
+#define TEGRA_POWERGATE_CPU	0
+#define TEGRA_POWERGATE_3D	1
+#define TEGRA_POWERGATE_VENC	2
+#define TEGRA_POWERGATE_PCIE	3
+#define TEGRA_POWERGATE_VDEC	4
+#define TEGRA_POWERGATE_L2	5
+#define TEGRA_POWERGATE_MPE	6
+#define TEGRA_POWERGATE_HEG	7
+#define TEGRA_POWERGATE_SATA	8
+#define TEGRA_POWERGATE_CPU1	9
+#define TEGRA_POWERGATE_CPU2	10
+#define TEGRA_POWERGATE_CPU3	11
+#define TEGRA_POWERGATE_CELP	12
+#define TEGRA_POWERGATE_3D1	13
+#define TEGRA_POWERGATE_CPU0	14
+#define TEGRA_POWERGATE_C0NC	15
+#define TEGRA_POWERGATE_C1NC	16
+#define TEGRA_POWERGATE_SOR	17
+#define TEGRA_POWERGATE_DIS	18
+#define TEGRA_POWERGATE_DISB	19
+#define TEGRA_POWERGATE_XUSBA	20
+#define TEGRA_POWERGATE_XUSBB	21
+#define TEGRA_POWERGATE_XUSBC	22
+#define TEGRA_POWERGATE_VIC	23
+#define TEGRA_POWERGATE_IRAM	24
+#define TEGRA_POWERGATE_NVDEC	25
+#define TEGRA_POWERGATE_NVJPG	26
+#define TEGRA_POWERGATE_AUD	27
+#define TEGRA_POWERGATE_DFD	28
+#define TEGRA_POWERGATE_VE2	29
+
+/*
+ * Pseudo powergate for power-domains that are power-gated externally.
+ * Make this a large number to allow other powergates to be added.
+ */
+#define TEGRA_POWERGATE_EXT	1000
+
+
+#endif
diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h
index 4ca91d39304d..67b75d82edc7 100644
--- a/include/soc/tegra/pmc.h
+++ b/include/soc/tegra/pmc.h
@@ -19,6 +19,8 @@
 #ifndef __SOC_TEGRA_PMC_H__
 #define __SOC_TEGRA_PMC_H__
 
+#include <dt-bindings/power/tegra-powergate.h>
+
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/reboot.h>
@@ -41,42 +43,8 @@ int tegra_pmc_cpu_remove_clamping(int cpuid);
 #endif /* CONFIG_SMP */
 
 /*
- * powergate and I/O rail APIs
+ * I/O rail APIs
  */
-
-#define TEGRA_POWERGATE_CPU	0
-#define TEGRA_POWERGATE_3D	1
-#define TEGRA_POWERGATE_VENC	2
-#define TEGRA_POWERGATE_PCIE	3
-#define TEGRA_POWERGATE_VDEC	4
-#define TEGRA_POWERGATE_L2	5
-#define TEGRA_POWERGATE_MPE	6
-#define TEGRA_POWERGATE_HEG	7
-#define TEGRA_POWERGATE_SATA	8
-#define TEGRA_POWERGATE_CPU1	9
-#define TEGRA_POWERGATE_CPU2	10
-#define TEGRA_POWERGATE_CPU3	11
-#define TEGRA_POWERGATE_CELP	12
-#define TEGRA_POWERGATE_3D1	13
-#define TEGRA_POWERGATE_CPU0	14
-#define TEGRA_POWERGATE_C0NC	15
-#define TEGRA_POWERGATE_C1NC	16
-#define TEGRA_POWERGATE_SOR	17
-#define TEGRA_POWERGATE_DIS	18
-#define TEGRA_POWERGATE_DISB	19
-#define TEGRA_POWERGATE_XUSBA	20
-#define TEGRA_POWERGATE_XUSBB	21
-#define TEGRA_POWERGATE_XUSBC	22
-#define TEGRA_POWERGATE_VIC	23
-#define TEGRA_POWERGATE_IRAM	24
-#define TEGRA_POWERGATE_NVDEC	25
-#define TEGRA_POWERGATE_NVJPG	26
-#define TEGRA_POWERGATE_AUD	27
-#define TEGRA_POWERGATE_DFD	28
-#define TEGRA_POWERGATE_VE2	29
-
-#define TEGRA_POWERGATE_3D0	TEGRA_POWERGATE_3D
-
 #define TEGRA_IO_RAIL_CSIA	0
 #define TEGRA_IO_RAIL_CSIB	1
 #define TEGRA_IO_RAIL_DSI	2
@@ -119,18 +87,8 @@ int tegra_powergate_remove_clamping(int id);
 int tegra_powergate_sequence_power_up(int id, struct clk *clk,
 				      struct reset_control *rst);
 
-static inline int tegra_powergate_power_on_legacy(int id, struct clk *clk,
-						  struct reset_control *rst)
-{
-	int err = tegra_powergate_sequence_power_up(id, clk, rst);
-
-	if (!err) {
-		usleep_range(10, 20);
-		clk_disable_unprepare(clk);
-	}
-
-	return err;
-}
+int tegra_powergate_power_on_legacy(int id, struct clk *clk,
+				    struct reset_control *rst);
 
 int tegra_powergate_power_off_legacy(int id, struct clk *clk,
 				     struct reset_control *rst);
-- 
2.1.4

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

* [PATCH V3 16/19] soc: tegra: pmc: Remove the deprecated powergate APIs
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39     ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Jon Hunter

Drivers using the deprecated tegra powergate APIs have been updated and
so now we can remove these unused deprecated APIs.

Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/soc/tegra/pmc.c | 68 -------------------------------------------------
 include/soc/tegra/pmc.h | 22 ----------------
 2 files changed, 90 deletions(-)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 4de92a9dae65..402f13727e75 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -484,31 +484,6 @@ static int tegra_genpd_power_off(struct generic_pm_domain *domain)
 }
 
 /**
- * tegra_powergate_power_on() - power on partition
- * @id: partition ID
- */
-int tegra_powergate_power_on(int id)
-{
-	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
-		return -EINVAL;
-
-	return tegra_powergate_set(id, true, true);
-}
-
-/**
- * tegra_powergate_power_off() - power off partition
- * @id: partition ID
- */
-int tegra_powergate_power_off(int id)
-{
-	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
-		return -EINVAL;
-
-	return tegra_powergate_set(id, false, true);
-}
-EXPORT_SYMBOL(tegra_powergate_power_off);
-
-/**
  * tegra_powergate_is_powered() - check if partition is powered
  * @id: partition ID
  */
@@ -566,49 +541,6 @@ int tegra_powergate_remove_clamping(int id)
 }
 EXPORT_SYMBOL(tegra_powergate_remove_clamping);
 
-/**
- * tegra_powergate_sequence_power_up() - power up partition
- * @id: partition ID
- * @clk: clock for partition
- * @rst: reset for partition
- *
- * Must be called with clk disabled, and returns with clk enabled.
- */
-int tegra_powergate_sequence_power_up(int id, struct clk *clk,
-				      struct reset_control *rst)
-{
-	int ret;
-
-	reset_control_assert(rst);
-
-	ret = tegra_powergate_power_on(id);
-	if (ret)
-		goto err_power;
-
-	ret = clk_prepare_enable(clk);
-	if (ret)
-		goto err_clk;
-
-	usleep_range(10, 20);
-
-	ret = tegra_powergate_remove_clamping(id);
-	if (ret)
-		goto err_clamp;
-
-	usleep_range(10, 20);
-	reset_control_deassert(rst);
-
-	return 0;
-
-err_clamp:
-	clk_disable_unprepare(clk);
-err_clk:
-	tegra_powergate_power_off(id);
-err_power:
-	return ret;
-}
-EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
-
 int tegra_powergate_power_on_legacy(int id, struct clk *clk,
 				    struct reset_control *rst)
 {
diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h
index 67b75d82edc7..509c1a3ca879 100644
--- a/include/soc/tegra/pmc.h
+++ b/include/soc/tegra/pmc.h
@@ -79,14 +79,8 @@ int tegra_pmc_cpu_remove_clamping(int cpuid);
 
 #ifdef CONFIG_ARCH_TEGRA
 int tegra_powergate_is_powered(int id);
-int tegra_powergate_power_on(int id);
-int tegra_powergate_power_off(int id);
 int tegra_powergate_remove_clamping(int id);
 
-/* Must be called with clk disabled, and returns with clk enabled */
-int tegra_powergate_sequence_power_up(int id, struct clk *clk,
-				      struct reset_control *rst);
-
 int tegra_powergate_power_on_legacy(int id, struct clk *clk,
 				    struct reset_control *rst);
 
@@ -101,27 +95,11 @@ static inline int tegra_powergate_is_powered(int id)
 	return -ENOSYS;
 }
 
-static inline int tegra_powergate_power_on(int id)
-{
-	return -ENOSYS;
-}
-
-static inline int tegra_powergate_power_off(int id)
-{
-	return -ENOSYS;
-}
-
 static inline int tegra_powergate_remove_clamping(int id)
 {
 	return -ENOSYS;
 }
 
-static inline int tegra_powergate_sequence_power_up(int id, struct clk *clk,
-						    struct reset_control *rst)
-{
-	return -ENOSYS;
-}
-
 static inline int tegra_io_rail_power_on(int id)
 {
 	return -ENOSYS;
-- 
2.1.4

--
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] 110+ messages in thread

* [PATCH V3 16/19] soc: tegra: pmc: Remove the deprecated powergate APIs
@ 2015-07-13 12:39     ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

Drivers using the deprecated tegra powergate APIs have been updated and
so now we can remove these unused deprecated APIs.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/soc/tegra/pmc.c | 68 -------------------------------------------------
 include/soc/tegra/pmc.h | 22 ----------------
 2 files changed, 90 deletions(-)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 4de92a9dae65..402f13727e75 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -484,31 +484,6 @@ static int tegra_genpd_power_off(struct generic_pm_domain *domain)
 }
 
 /**
- * tegra_powergate_power_on() - power on partition
- * @id: partition ID
- */
-int tegra_powergate_power_on(int id)
-{
-	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
-		return -EINVAL;
-
-	return tegra_powergate_set(id, true, true);
-}
-
-/**
- * tegra_powergate_power_off() - power off partition
- * @id: partition ID
- */
-int tegra_powergate_power_off(int id)
-{
-	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
-		return -EINVAL;
-
-	return tegra_powergate_set(id, false, true);
-}
-EXPORT_SYMBOL(tegra_powergate_power_off);
-
-/**
  * tegra_powergate_is_powered() - check if partition is powered
  * @id: partition ID
  */
@@ -566,49 +541,6 @@ int tegra_powergate_remove_clamping(int id)
 }
 EXPORT_SYMBOL(tegra_powergate_remove_clamping);
 
-/**
- * tegra_powergate_sequence_power_up() - power up partition
- * @id: partition ID
- * @clk: clock for partition
- * @rst: reset for partition
- *
- * Must be called with clk disabled, and returns with clk enabled.
- */
-int tegra_powergate_sequence_power_up(int id, struct clk *clk,
-				      struct reset_control *rst)
-{
-	int ret;
-
-	reset_control_assert(rst);
-
-	ret = tegra_powergate_power_on(id);
-	if (ret)
-		goto err_power;
-
-	ret = clk_prepare_enable(clk);
-	if (ret)
-		goto err_clk;
-
-	usleep_range(10, 20);
-
-	ret = tegra_powergate_remove_clamping(id);
-	if (ret)
-		goto err_clamp;
-
-	usleep_range(10, 20);
-	reset_control_deassert(rst);
-
-	return 0;
-
-err_clamp:
-	clk_disable_unprepare(clk);
-err_clk:
-	tegra_powergate_power_off(id);
-err_power:
-	return ret;
-}
-EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
-
 int tegra_powergate_power_on_legacy(int id, struct clk *clk,
 				    struct reset_control *rst)
 {
diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h
index 67b75d82edc7..509c1a3ca879 100644
--- a/include/soc/tegra/pmc.h
+++ b/include/soc/tegra/pmc.h
@@ -79,14 +79,8 @@ int tegra_pmc_cpu_remove_clamping(int cpuid);
 
 #ifdef CONFIG_ARCH_TEGRA
 int tegra_powergate_is_powered(int id);
-int tegra_powergate_power_on(int id);
-int tegra_powergate_power_off(int id);
 int tegra_powergate_remove_clamping(int id);
 
-/* Must be called with clk disabled, and returns with clk enabled */
-int tegra_powergate_sequence_power_up(int id, struct clk *clk,
-				      struct reset_control *rst);
-
 int tegra_powergate_power_on_legacy(int id, struct clk *clk,
 				    struct reset_control *rst);
 
@@ -101,27 +95,11 @@ static inline int tegra_powergate_is_powered(int id)
 	return -ENOSYS;
 }
 
-static inline int tegra_powergate_power_on(int id)
-{
-	return -ENOSYS;
-}
-
-static inline int tegra_powergate_power_off(int id)
-{
-	return -ENOSYS;
-}
-
 static inline int tegra_powergate_remove_clamping(int id)
 {
 	return -ENOSYS;
 }
 
-static inline int tegra_powergate_sequence_power_up(int id, struct clk *clk,
-						    struct reset_control *rst)
-{
-	return -ENOSYS;
-}
-
 static inline int tegra_io_rail_power_on(int id)
 {
 	return -ENOSYS;
-- 
2.1.4

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

* [PATCH V3 17/19] ARM: tegra: Add PM domain device nodes to Tegra124 DT
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39   ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra, devicetree, linux-arm-kernel, linux-pm, Jon Hunter

Add tegra124 pm-domains provider and consumer nodes.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 arch/arm/boot/dts/tegra124.dtsi | 80 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 87318a72f615..3573bb079791 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -3,6 +3,7 @@
 #include <dt-bindings/memory/tegra124-mc.h>
 #include <dt-bindings/pinctrl/pinctrl-tegra.h>
 #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
+#include <dt-bindings/power/tegra-powergate.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/reset/tegra124-car.h>
 #include <dt-bindings/thermal/tegra124-soctherm.h>
@@ -40,6 +41,8 @@
 			  0x82000000 0 0x13000000 0x0 0x13000000 0 0x0d000000   /* non-prefetchable memory (208 MiB) */
 			  0xc2000000 0 0x20000000 0x0 0x20000000 0 0x20000000>; /* prefetchable memory (512 MiB) */
 
+		power-domains = <&pd_pcie>;
+
 		clocks = <&tegra_car TEGRA124_CLK_PCIE>,
 			 <&tegra_car TEGRA124_CLK_AFI>,
 			 <&tegra_car TEGRA124_CLK_PLL_E>,
@@ -99,6 +102,7 @@
 			compatible = "nvidia,tegra124-dc";
 			reg = <0x0 0x54200000 0x0 0x00040000>;
 			interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+			power-domains = <&pd_dc>;
 			clocks = <&tegra_car TEGRA124_CLK_DISP1>,
 				 <&tegra_car TEGRA124_CLK_PLL_P>;
 			clock-names = "dc", "parent";
@@ -114,6 +118,7 @@
 			compatible = "nvidia,tegra124-dc";
 			reg = <0x0 0x54240000 0x0 0x00040000>;
 			interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+			power-domains = <&pd_dcb>;
 			clocks = <&tegra_car TEGRA124_CLK_DISP2>,
 				 <&tegra_car TEGRA124_CLK_PLL_P>;
 			clock-names = "dc", "parent";
@@ -141,6 +146,7 @@
 			compatible = "nvidia,tegra124-sor";
 			reg = <0x0 0x54540000 0x0 0x00040000>;
 			interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+			power-domains = <&pd_sor>;
 			clocks = <&tegra_car TEGRA124_CLK_SOR0>,
 				 <&tegra_car TEGRA124_CLK_PLL_D_OUT0>,
 				 <&tegra_car TEGRA124_CLK_PLL_DP>,
@@ -155,6 +161,7 @@
 			compatible = "nvidia,tegra124-dpaux";
 			reg = <0x0 0x545c0000 0x0 0x00040000>;
 			interrupts = <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
+			power-domains = <&pd_sor>;
 			clocks = <&tegra_car TEGRA124_CLK_DPAUX>,
 				 <&tegra_car TEGRA124_CLK_PLL_DP>;
 			clock-names = "dpaux", "parent";
@@ -184,6 +191,7 @@
 		interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
 		interrupt-names = "stall", "nonstall";
+		power-domains = <&pd_gpu>;
 		clocks = <&tegra_car TEGRA124_CLK_GPU>,
 			 <&tegra_car TEGRA124_CLK_PLL_P_OUT5>;
 		clock-names = "gpu", "pwr";
@@ -573,6 +581,76 @@
 		reg = <0x0 0x7000e400 0x0 0x400>;
 		clocks = <&tegra_car TEGRA124_CLK_PCLK>, <&clk32k_in>;
 		clock-names = "pclk", "clk32k_in";
+
+		pm-domains {
+			pd_gpu: gpu-power-domain {
+				clocks = <&tegra_car TEGRA124_CLK_GPU>,
+					 <&tegra_car TEGRA124_CLK_PLL_P_OUT5>;
+				resets = <&tegra_car 184>;
+				nvidia,powergate = <TEGRA_POWERGATE_EXT>;
+				nvidia,swgroups = <&mc TEGRA_SWGROUP_GPU>;
+				#nvidia,swgroup-cells = <1>;
+				#power-domain-cells = <0>;
+			};
+
+			pd_pcie: pcie-power-domain {
+				clocks = <&tegra_car TEGRA124_CLK_PCIE>,
+					 <&tegra_car TEGRA124_CLK_AFI>;
+				resets = <&tegra_car 70>,
+					 <&tegra_car 72>;
+				nvidia,powergate = <TEGRA_POWERGATE_PCIE>;
+				nvidia,swgroups = <&mc TEGRA_SWGROUP_AFI>;
+				#nvidia,swgroup-cells = <1>;
+				#power-domain-cells = <0>;
+			};
+
+			pd_sata: sata-power-domain {
+				clocks = <&tegra_car TEGRA124_CLK_SATA>,
+					 <&tegra_car TEGRA124_CLK_SATA_OOB>,
+					 <&tegra_car TEGRA124_CLK_CML1>;
+				resets = <&tegra_car 124>,
+					 <&tegra_car 123>,
+					 <&tegra_car 129>;
+				nvidia,powergate = <TEGRA_POWERGATE_SATA>;
+				nvidia,swgroups = <&mc TEGRA_SWGROUP_SATA>;
+				#nvidia,swgroup-cells = <1>;
+				#power-domain-cells = <0>;
+			};
+
+			pd_sor: sor-power-domain {
+				clocks = <&tegra_car TEGRA124_CLK_SOR0>,
+					 <&tegra_car TEGRA124_CLK_DSIA>,
+					 <&tegra_car TEGRA124_CLK_DSIB>,
+					 <&tegra_car TEGRA124_CLK_HDMI>,
+					 <&tegra_car TEGRA124_CLK_MIPI_CAL>,
+					 <&tegra_car TEGRA124_CLK_DPAUX>;
+				resets = <&tegra_car 182>,
+					 <&tegra_car 48>,
+					 <&tegra_car 82>,
+					 <&tegra_car 51>,
+					 <&tegra_car 56>;
+				nvidia,powergate = <TEGRA_POWERGATE_SOR>;
+				#power-domain-cells = <0>;
+
+				pd_dc: dc-power-domain {
+					clocks = <&tegra_car TEGRA124_CLK_DISP1>;
+					resets = <&tegra_car 27>;
+					nvidia,powergate = <TEGRA_POWERGATE_DIS>;
+					nvidia,swgroups = <&mc TEGRA_SWGROUP_DC>;
+					#nvidia,swgroup-cells = <1>;
+					#power-domain-cells = <0>;
+
+					pd_dcb: dcb-power-domain {
+						clocks = <&tegra_car TEGRA124_CLK_DISP2>;
+						resets = <&tegra_car 26>;
+						nvidia,powergate = <TEGRA_POWERGATE_DISB>;
+						nvidia,swgroups = <&mc TEGRA_SWGROUP_DCB>;
+						#nvidia,swgroup-cells = <1>;
+						#power-domain-cells = <0>;
+					};
+				};
+			};
+		};
 	};
 
 	fuse@0,7000f800 {
@@ -621,6 +699,8 @@
 			<&tegra_car 129>;
 		reset-names = "sata", "sata-oob", "sata-cold";
 
+		power-domains = <&pd_sata>;
+
 		phys = <&padctl TEGRA_XUSB_PADCTL_SATA>;
 		phy-names = "sata-phy";
 
-- 
2.1.4


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

* [PATCH V3 17/19] ARM: tegra: Add PM domain device nodes to Tegra124 DT
@ 2015-07-13 12:39   ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

Add tegra124 pm-domains provider and consumer nodes.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 arch/arm/boot/dts/tegra124.dtsi | 80 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 87318a72f615..3573bb079791 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -3,6 +3,7 @@
 #include <dt-bindings/memory/tegra124-mc.h>
 #include <dt-bindings/pinctrl/pinctrl-tegra.h>
 #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
+#include <dt-bindings/power/tegra-powergate.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/reset/tegra124-car.h>
 #include <dt-bindings/thermal/tegra124-soctherm.h>
@@ -40,6 +41,8 @@
 			  0x82000000 0 0x13000000 0x0 0x13000000 0 0x0d000000   /* non-prefetchable memory (208 MiB) */
 			  0xc2000000 0 0x20000000 0x0 0x20000000 0 0x20000000>; /* prefetchable memory (512 MiB) */
 
+		power-domains = <&pd_pcie>;
+
 		clocks = <&tegra_car TEGRA124_CLK_PCIE>,
 			 <&tegra_car TEGRA124_CLK_AFI>,
 			 <&tegra_car TEGRA124_CLK_PLL_E>,
@@ -99,6 +102,7 @@
 			compatible = "nvidia,tegra124-dc";
 			reg = <0x0 0x54200000 0x0 0x00040000>;
 			interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+			power-domains = <&pd_dc>;
 			clocks = <&tegra_car TEGRA124_CLK_DISP1>,
 				 <&tegra_car TEGRA124_CLK_PLL_P>;
 			clock-names = "dc", "parent";
@@ -114,6 +118,7 @@
 			compatible = "nvidia,tegra124-dc";
 			reg = <0x0 0x54240000 0x0 0x00040000>;
 			interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+			power-domains = <&pd_dcb>;
 			clocks = <&tegra_car TEGRA124_CLK_DISP2>,
 				 <&tegra_car TEGRA124_CLK_PLL_P>;
 			clock-names = "dc", "parent";
@@ -141,6 +146,7 @@
 			compatible = "nvidia,tegra124-sor";
 			reg = <0x0 0x54540000 0x0 0x00040000>;
 			interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+			power-domains = <&pd_sor>;
 			clocks = <&tegra_car TEGRA124_CLK_SOR0>,
 				 <&tegra_car TEGRA124_CLK_PLL_D_OUT0>,
 				 <&tegra_car TEGRA124_CLK_PLL_DP>,
@@ -155,6 +161,7 @@
 			compatible = "nvidia,tegra124-dpaux";
 			reg = <0x0 0x545c0000 0x0 0x00040000>;
 			interrupts = <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
+			power-domains = <&pd_sor>;
 			clocks = <&tegra_car TEGRA124_CLK_DPAUX>,
 				 <&tegra_car TEGRA124_CLK_PLL_DP>;
 			clock-names = "dpaux", "parent";
@@ -184,6 +191,7 @@
 		interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
 		interrupt-names = "stall", "nonstall";
+		power-domains = <&pd_gpu>;
 		clocks = <&tegra_car TEGRA124_CLK_GPU>,
 			 <&tegra_car TEGRA124_CLK_PLL_P_OUT5>;
 		clock-names = "gpu", "pwr";
@@ -573,6 +581,76 @@
 		reg = <0x0 0x7000e400 0x0 0x400>;
 		clocks = <&tegra_car TEGRA124_CLK_PCLK>, <&clk32k_in>;
 		clock-names = "pclk", "clk32k_in";
+
+		pm-domains {
+			pd_gpu: gpu-power-domain {
+				clocks = <&tegra_car TEGRA124_CLK_GPU>,
+					 <&tegra_car TEGRA124_CLK_PLL_P_OUT5>;
+				resets = <&tegra_car 184>;
+				nvidia,powergate = <TEGRA_POWERGATE_EXT>;
+				nvidia,swgroups = <&mc TEGRA_SWGROUP_GPU>;
+				#nvidia,swgroup-cells = <1>;
+				#power-domain-cells = <0>;
+			};
+
+			pd_pcie: pcie-power-domain {
+				clocks = <&tegra_car TEGRA124_CLK_PCIE>,
+					 <&tegra_car TEGRA124_CLK_AFI>;
+				resets = <&tegra_car 70>,
+					 <&tegra_car 72>;
+				nvidia,powergate = <TEGRA_POWERGATE_PCIE>;
+				nvidia,swgroups = <&mc TEGRA_SWGROUP_AFI>;
+				#nvidia,swgroup-cells = <1>;
+				#power-domain-cells = <0>;
+			};
+
+			pd_sata: sata-power-domain {
+				clocks = <&tegra_car TEGRA124_CLK_SATA>,
+					 <&tegra_car TEGRA124_CLK_SATA_OOB>,
+					 <&tegra_car TEGRA124_CLK_CML1>;
+				resets = <&tegra_car 124>,
+					 <&tegra_car 123>,
+					 <&tegra_car 129>;
+				nvidia,powergate = <TEGRA_POWERGATE_SATA>;
+				nvidia,swgroups = <&mc TEGRA_SWGROUP_SATA>;
+				#nvidia,swgroup-cells = <1>;
+				#power-domain-cells = <0>;
+			};
+
+			pd_sor: sor-power-domain {
+				clocks = <&tegra_car TEGRA124_CLK_SOR0>,
+					 <&tegra_car TEGRA124_CLK_DSIA>,
+					 <&tegra_car TEGRA124_CLK_DSIB>,
+					 <&tegra_car TEGRA124_CLK_HDMI>,
+					 <&tegra_car TEGRA124_CLK_MIPI_CAL>,
+					 <&tegra_car TEGRA124_CLK_DPAUX>;
+				resets = <&tegra_car 182>,
+					 <&tegra_car 48>,
+					 <&tegra_car 82>,
+					 <&tegra_car 51>,
+					 <&tegra_car 56>;
+				nvidia,powergate = <TEGRA_POWERGATE_SOR>;
+				#power-domain-cells = <0>;
+
+				pd_dc: dc-power-domain {
+					clocks = <&tegra_car TEGRA124_CLK_DISP1>;
+					resets = <&tegra_car 27>;
+					nvidia,powergate = <TEGRA_POWERGATE_DIS>;
+					nvidia,swgroups = <&mc TEGRA_SWGROUP_DC>;
+					#nvidia,swgroup-cells = <1>;
+					#power-domain-cells = <0>;
+
+					pd_dcb: dcb-power-domain {
+						clocks = <&tegra_car TEGRA124_CLK_DISP2>;
+						resets = <&tegra_car 26>;
+						nvidia,powergate = <TEGRA_POWERGATE_DISB>;
+						nvidia,swgroups = <&mc TEGRA_SWGROUP_DCB>;
+						#nvidia,swgroup-cells = <1>;
+						#power-domain-cells = <0>;
+					};
+				};
+			};
+		};
 	};
 
 	fuse at 0,7000f800 {
@@ -621,6 +699,8 @@
 			<&tegra_car 129>;
 		reset-names = "sata", "sata-oob", "sata-cold";
 
+		power-domains = <&pd_sata>;
+
 		phys = <&padctl TEGRA_XUSB_PADCTL_SATA>;
 		phy-names = "sata-phy";
 
-- 
2.1.4

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

* [PATCH V3 18/19] ARM: tegra: add GPU power supply to Jetson TK1 DT
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39     ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Jon Hunter

From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Add power supply information which is board dependent for GK20A.

Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 arch/arm/boot/dts/tegra124-jetson-tk1.dts | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
index ce5961cd0b77..2b355957635c 100644
--- a/arch/arm/boot/dts/tegra124-jetson-tk1.dts
+++ b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
@@ -1514,7 +1514,7 @@
 					regulator-always-on;
 				};
 
-				sd6 {
+				vdd_gpu: sd6 {
 					regulator-name = "+VDD_GPU_AP";
 					regulator-min-microvolt = <650000>;
 					regulator-max-microvolt = <1200000>;
@@ -1635,6 +1635,10 @@
 		};
 	};
 
+	gpu-power-domain {
+		vdd-supply = <&vdd_gpu>;
+	};
+
 	/* Serial ATA */
 	sata@0,70020000 {
 		status = "okay";
-- 
2.1.4

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

* [PATCH V3 18/19] ARM: tegra: add GPU power supply to Jetson TK1 DT
@ 2015-07-13 12:39     ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vince Hsu <vinceh@nvidia.com>

Add power supply information which is board dependent for GK20A.

Signed-off-by: Vince Hsu <vinceh@nvidia.com>
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 arch/arm/boot/dts/tegra124-jetson-tk1.dts | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
index ce5961cd0b77..2b355957635c 100644
--- a/arch/arm/boot/dts/tegra124-jetson-tk1.dts
+++ b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
@@ -1514,7 +1514,7 @@
 					regulator-always-on;
 				};
 
-				sd6 {
+				vdd_gpu: sd6 {
 					regulator-name = "+VDD_GPU_AP";
 					regulator-min-microvolt = <650000>;
 					regulator-max-microvolt = <1200000>;
@@ -1635,6 +1635,10 @@
 		};
 	};
 
+	gpu-power-domain {
+		vdd-supply = <&vdd_gpu>;
+	};
+
 	/* Serial ATA */
 	sata at 0,70020000 {
 		status = "okay";
-- 
2.1.4

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

* [PATCH V3 19/19] ARM: tegra: select PM_GENERIC_DOMAINS
  2015-07-13 12:39 ` Jon Hunter
@ 2015-07-13 12:39     ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo
  Cc: Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Jon Hunter

From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

We have added generic power domain support for Tegra SoCs. So now the
option M_GENERIC_DOMAINS must be enabled by default to have proper power
sequence.

Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 arch/arm/mach-tegra/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 0fa4c5f8b1be..fdf86cae3b32 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -9,6 +9,7 @@ menuconfig ARCH_TEGRA
 	select HAVE_ARM_TWD if SMP
 	select PINCTRL
 	select PM_OPP
+	select PM_GENERIC_DOMAINS if PM
 	select ARCH_HAS_RESET_CONTROLLER
 	select RESET_CONTROLLER
 	select SOC_BUS
-- 
2.1.4

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

* [PATCH V3 19/19] ARM: tegra: select PM_GENERIC_DOMAINS
@ 2015-07-13 12:39     ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vince Hsu <vinceh@nvidia.com>

We have added generic power domain support for Tegra SoCs. So now the
option M_GENERIC_DOMAINS must be enabled by default to have proper power
sequence.

Signed-off-by: Vince Hsu <vinceh@nvidia.com>
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 arch/arm/mach-tegra/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 0fa4c5f8b1be..fdf86cae3b32 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -9,6 +9,7 @@ menuconfig ARCH_TEGRA
 	select HAVE_ARM_TWD if SMP
 	select PINCTRL
 	select PM_OPP
+	select PM_GENERIC_DOMAINS if PM
 	select ARCH_HAS_RESET_CONTROLLER
 	select RESET_CONTROLLER
 	select SOC_BUS
-- 
2.1.4

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

* Re: [PATCH V3 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2
  2015-07-13 12:39   ` Jon Hunter
@ 2015-07-13 13:41       ` Peter De Schrijver
  -1 siblings, 0 replies; 110+ messages in thread
From: Peter De Schrijver @ 2015-07-13 13:41 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

On Mon, Jul 13, 2015 at 01:39:44PM +0100, Jon Hunter wrote:
> From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> 
> Tegra114 has a HW bug that the PLLD/PLLD2 lock bit cannot be asserted when
> the DIS power domain is during up-powergating process but the clamp to this

I think there is missing 'off' in this sentence?

ie. ... 'the DIS power domain is off during up-powergating process'

Also 'un-powergating sequence' would be nicer.

> domain is not removed yet. That causes a timeout and aborts the power
> sequence, although the PLLD/PLLD2 has already locked. To remove the false
> alarm, we don't use the lock for PLLD/PLLD2. Just wait 1ms and treat the
> clocks as locked.
> 
> Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
>  drivers/clk/tegra/clk-tegra114.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
> index 8237d16b4075..2e5c20c7c088 100644
> --- a/drivers/clk/tegra/clk-tegra114.c
> +++ b/drivers/clk/tegra/clk-tegra114.c
> @@ -456,8 +456,7 @@ static struct tegra_clk_pll_params pll_d_params = {
>  	.lock_delay = 1000,
>  	.div_nmp = &pllp_nmp,
>  	.freq_table = pll_d_freq_table,
> -	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
> -		 TEGRA_PLL_USE_LOCK,
> +	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
>  };
>  
>  static struct tegra_clk_pll_params pll_d2_params = {
> @@ -474,8 +473,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
>  	.lock_delay = 1000,
>  	.div_nmp = &pllp_nmp,
>  	.freq_table = pll_d_freq_table,
> -	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
> -		 TEGRA_PLL_USE_LOCK,
> +	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
>  };
>  
>  static struct pdiv_map pllu_p[] = {
> -- 
> 2.1.4
> 

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

* [PATCH V3 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2
@ 2015-07-13 13:41       ` Peter De Schrijver
  0 siblings, 0 replies; 110+ messages in thread
From: Peter De Schrijver @ 2015-07-13 13:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 13, 2015 at 01:39:44PM +0100, Jon Hunter wrote:
> From: Vince Hsu <vinceh@nvidia.com>
> 
> Tegra114 has a HW bug that the PLLD/PLLD2 lock bit cannot be asserted when
> the DIS power domain is during up-powergating process but the clamp to this

I think there is missing 'off' in this sentence?

ie. ... 'the DIS power domain is off?during up-powergating process'

Also 'un-powergating sequence' would be nicer.

> domain is not removed yet. That causes a timeout and aborts the power
> sequence, although the PLLD/PLLD2 has already locked. To remove the false
> alarm, we don't use the lock for PLLD/PLLD2. Just wait 1ms and treat the
> clocks as locked.
> 
> Signed-off-by: Vince Hsu <vinceh@nvidia.com>
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  drivers/clk/tegra/clk-tegra114.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
> index 8237d16b4075..2e5c20c7c088 100644
> --- a/drivers/clk/tegra/clk-tegra114.c
> +++ b/drivers/clk/tegra/clk-tegra114.c
> @@ -456,8 +456,7 @@ static struct tegra_clk_pll_params pll_d_params = {
>  	.lock_delay = 1000,
>  	.div_nmp = &pllp_nmp,
>  	.freq_table = pll_d_freq_table,
> -	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
> -		 TEGRA_PLL_USE_LOCK,
> +	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
>  };
>  
>  static struct tegra_clk_pll_params pll_d2_params = {
> @@ -474,8 +473,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
>  	.lock_delay = 1000,
>  	.div_nmp = &pllp_nmp,
>  	.freq_table = pll_d_freq_table,
> -	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
> -		 TEGRA_PLL_USE_LOCK,
> +	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
>  };
>  
>  static struct pdiv_map pllu_p[] = {
> -- 
> 2.1.4
> 

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

* Re: [PATCH V3 19/19] ARM: tegra: select PM_GENERIC_DOMAINS
  2015-07-13 12:39     ` Jon Hunter
@ 2015-07-13 13:50       ` Peter De Schrijver
  -1 siblings, 0 replies; 110+ messages in thread
From: Peter De Schrijver @ 2015-07-13 13:50 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra, devicetree, linux-arm-kernel, linux-pm

On Mon, Jul 13, 2015 at 01:39:57PM +0100, Jon Hunter wrote:
> From: Vince Hsu <vinceh@nvidia.com>
> 
> We have added generic power domain support for Tegra SoCs. So now the
> option M_GENERIC_DOMAINS must be enabled by default to have proper power

Missing P :)

> sequence.
> 
> Signed-off-by: Vince Hsu <vinceh@nvidia.com>
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  arch/arm/mach-tegra/Kconfig | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
> index 0fa4c5f8b1be..fdf86cae3b32 100644
> --- a/arch/arm/mach-tegra/Kconfig
> +++ b/arch/arm/mach-tegra/Kconfig
> @@ -9,6 +9,7 @@ menuconfig ARCH_TEGRA
>  	select HAVE_ARM_TWD if SMP
>  	select PINCTRL
>  	select PM_OPP
> +	select PM_GENERIC_DOMAINS if PM
>  	select ARCH_HAS_RESET_CONTROLLER
>  	select RESET_CONTROLLER
>  	select SOC_BUS
> -- 
> 2.1.4
> 

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

* [PATCH V3 19/19] ARM: tegra: select PM_GENERIC_DOMAINS
@ 2015-07-13 13:50       ` Peter De Schrijver
  0 siblings, 0 replies; 110+ messages in thread
From: Peter De Schrijver @ 2015-07-13 13:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 13, 2015 at 01:39:57PM +0100, Jon Hunter wrote:
> From: Vince Hsu <vinceh@nvidia.com>
> 
> We have added generic power domain support for Tegra SoCs. So now the
> option M_GENERIC_DOMAINS must be enabled by default to have proper power

Missing P :)

> sequence.
> 
> Signed-off-by: Vince Hsu <vinceh@nvidia.com>
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  arch/arm/mach-tegra/Kconfig | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
> index 0fa4c5f8b1be..fdf86cae3b32 100644
> --- a/arch/arm/mach-tegra/Kconfig
> +++ b/arch/arm/mach-tegra/Kconfig
> @@ -9,6 +9,7 @@ menuconfig ARCH_TEGRA
>  	select HAVE_ARM_TWD if SMP
>  	select PINCTRL
>  	select PM_OPP
> +	select PM_GENERIC_DOMAINS if PM
>  	select ARCH_HAS_RESET_CONTROLLER
>  	select RESET_CONTROLLER
>  	select SOC_BUS
> -- 
> 2.1.4
> 

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

* Re: [PATCH V3 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2
  2015-07-13 13:41       ` Peter De Schrijver
@ 2015-07-13 14:02         ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 14:02 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra, devicetree, linux-arm-kernel, linux-pm



On 13/07/15 14:41, Peter De Schrijver wrote:
> On Mon, Jul 13, 2015 at 01:39:44PM +0100, Jon Hunter wrote:
>> From: Vince Hsu <vinceh@nvidia.com>
>>
>> Tegra114 has a HW bug that the PLLD/PLLD2 lock bit cannot be asserted when
>> the DIS power domain is during up-powergating process but the clamp to this
> 
> I think there is missing 'off' in this sentence?
> 
> ie. ... 'the DIS power domain is off during up-powergating process'
> 
> Also 'un-powergating sequence' would be nicer.

Yes agree. I will re-word that.

Thanks
Jon

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

* [PATCH V3 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2
@ 2015-07-13 14:02         ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 14:02 UTC (permalink / raw)
  To: linux-arm-kernel



On 13/07/15 14:41, Peter De Schrijver wrote:
> On Mon, Jul 13, 2015 at 01:39:44PM +0100, Jon Hunter wrote:
>> From: Vince Hsu <vinceh@nvidia.com>
>>
>> Tegra114 has a HW bug that the PLLD/PLLD2 lock bit cannot be asserted when
>> the DIS power domain is during up-powergating process but the clamp to this
> 
> I think there is missing 'off' in this sentence?
> 
> ie. ... 'the DIS power domain is off during up-powergating process'
> 
> Also 'un-powergating sequence' would be nicer.

Yes agree. I will re-word that.

Thanks
Jon

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

* Re: [PATCH V3 19/19] ARM: tegra: select PM_GENERIC_DOMAINS
  2015-07-13 13:50       ` Peter De Schrijver
@ 2015-07-13 14:03           ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 14:03 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA



On 13/07/15 14:50, Peter De Schrijver wrote:
> On Mon, Jul 13, 2015 at 01:39:57PM +0100, Jon Hunter wrote:
>> From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
>>
>> We have added generic power domain support for Tegra SoCs. So now the
>> option M_GENERIC_DOMAINS must be enabled by default to have proper power
> 
> Missing P :)

Ooops. I think introduced that error. Will fix.

Cheers
Jon

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

* [PATCH V3 19/19] ARM: tegra: select PM_GENERIC_DOMAINS
@ 2015-07-13 14:03           ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-13 14:03 UTC (permalink / raw)
  To: linux-arm-kernel



On 13/07/15 14:50, Peter De Schrijver wrote:
> On Mon, Jul 13, 2015 at 01:39:57PM +0100, Jon Hunter wrote:
>> From: Vince Hsu <vinceh@nvidia.com>
>>
>> We have added generic power domain support for Tegra SoCs. So now the
>> option M_GENERIC_DOMAINS must be enabled by default to have proper power
> 
> Missing P :)

Ooops. I think introduced that error. Will fix.

Cheers
Jon

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

* Re: [PATCH V3 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2
       [not found]         ` <55A3C50E.7060706-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  2015-07-14 11:59             ` Jon Hunter
@ 2015-07-14 11:59             ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-14 11:59 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA


On 13/07/15 15:02, Jon Hunter wrote:
> 
> 
> On 13/07/15 14:41, Peter De Schrijver wrote:
>> On Mon, Jul 13, 2015 at 01:39:44PM +0100, Jon Hunter wrote:
>>> From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
>>>
>>> Tegra114 has a HW bug that the PLLD/PLLD2 lock bit cannot be asserted when
>>> the DIS power domain is during up-powergating process but the clamp to this
>>
>> I think there is missing 'off' in this sentence?
>>
>> ie. ... 'the DIS power domain is off during up-powergating process'
>>
>> Also 'un-powergating sequence' would be nicer.
> 
> Yes agree. I will re-word that.

Updated version ...


From d5cbecd4e97332cd8373b9c4893731eb8e063660 Mon Sep 17 00:00:00 2001
From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Date: Wed, 11 Mar 2015 16:46:04 +0800
Subject: [PATCH 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2

Tegra114 has a HW bug where the PLLD/PLLD2 lock bit cannot be asserted
while turning on the Display power domain and before the clamp to this
domain has been removed. This issue causes a timeout and aborts the power
up sequence, even though the PLLD/PLLD2 has already locked. To avoid this,
don't use the lock for PLLD/PLLD2, just wait 1ms and treat the clocks as
locked.

Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
[jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org: Updated the changelog description]
Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/clk/tegra/clk-tegra114.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 8237d16b4075..2e5c20c7c088 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -456,8 +456,7 @@ static struct tegra_clk_pll_params pll_d_params = {
 	.lock_delay = 1000,
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_d_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
 };
 
 static struct tegra_clk_pll_params pll_d2_params = {
@@ -474,8 +473,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
 	.lock_delay = 1000,
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_d_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
 };
 
 static struct pdiv_map pllu_p[] = {
-- 
2.1.4

--
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] 110+ messages in thread

* Re: [PATCH V3 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2
@ 2015-07-14 11:59             ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-14 11:59 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA


On 13/07/15 15:02, Jon Hunter wrote:
> 
> 
> On 13/07/15 14:41, Peter De Schrijver wrote:
>> On Mon, Jul 13, 2015 at 01:39:44PM +0100, Jon Hunter wrote:
>>> From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
>>>
>>> Tegra114 has a HW bug that the PLLD/PLLD2 lock bit cannot be asserted when
>>> the DIS power domain is during up-powergating process but the clamp to this
>>
>> I think there is missing 'off' in this sentence?
>>
>> ie. ... 'the DIS power domain is off during up-powergating process'
>>
>> Also 'un-powergating sequence' would be nicer.
> 
> Yes agree. I will re-word that.

Updated version ...


>From d5cbecd4e97332cd8373b9c4893731eb8e063660 Mon Sep 17 00:00:00 2001
From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Date: Wed, 11 Mar 2015 16:46:04 +0800
Subject: [PATCH 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2

Tegra114 has a HW bug where the PLLD/PLLD2 lock bit cannot be asserted
while turning on the Display power domain and before the clamp to this
domain has been removed. This issue causes a timeout and aborts the power
up sequence, even though the PLLD/PLLD2 has already locked. To avoid this,
don't use the lock for PLLD/PLLD2, just wait 1ms and treat the clocks as
locked.

Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
[jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org: Updated the changelog description]
Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/clk/tegra/clk-tegra114.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 8237d16b4075..2e5c20c7c088 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -456,8 +456,7 @@ static struct tegra_clk_pll_params pll_d_params = {
 	.lock_delay = 1000,
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_d_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
 };
 
 static struct tegra_clk_pll_params pll_d2_params = {
@@ -474,8 +473,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
 	.lock_delay = 1000,
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_d_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
 };
 
 static struct pdiv_map pllu_p[] = {
-- 
2.1.4

--
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] 110+ messages in thread

* [PATCH V3 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2
@ 2015-07-14 11:59             ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-14 11:59 UTC (permalink / raw)
  To: linux-arm-kernel


On 13/07/15 15:02, Jon Hunter wrote:
> 
> 
> On 13/07/15 14:41, Peter De Schrijver wrote:
>> On Mon, Jul 13, 2015 at 01:39:44PM +0100, Jon Hunter wrote:
>>> From: Vince Hsu <vinceh@nvidia.com>
>>>
>>> Tegra114 has a HW bug that the PLLD/PLLD2 lock bit cannot be asserted when
>>> the DIS power domain is during up-powergating process but the clamp to this
>>
>> I think there is missing 'off' in this sentence?
>>
>> ie. ... 'the DIS power domain is off during up-powergating process'
>>
>> Also 'un-powergating sequence' would be nicer.
> 
> Yes agree. I will re-word that.

Updated version ...


>From d5cbecd4e97332cd8373b9c4893731eb8e063660 Mon Sep 17 00:00:00 2001
From: Vince Hsu <vinceh@nvidia.com>
Date: Wed, 11 Mar 2015 16:46:04 +0800
Subject: [PATCH 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2

Tegra114 has a HW bug where the PLLD/PLLD2 lock bit cannot be asserted
while turning on the Display power domain and before the clamp to this
domain has been removed. This issue causes a timeout and aborts the power
up sequence, even though the PLLD/PLLD2 has already locked. To avoid this,
don't use the lock for PLLD/PLLD2, just wait 1ms and treat the clocks as
locked.

Signed-off-by: Vince Hsu <vinceh@nvidia.com>
[jonathanh at nvidia.com: Updated the changelog description]
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/clk/tegra/clk-tegra114.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 8237d16b4075..2e5c20c7c088 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -456,8 +456,7 @@ static struct tegra_clk_pll_params pll_d_params = {
 	.lock_delay = 1000,
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_d_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
 };
 
 static struct tegra_clk_pll_params pll_d2_params = {
@@ -474,8 +473,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
 	.lock_delay = 1000,
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_d_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
 };
 
 static struct pdiv_map pllu_p[] = {
-- 
2.1.4

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

* Re: [PATCH V3 19/19] ARM: tegra: select PM_GENERIC_DOMAINS
  2015-07-13 14:03           ` Jon Hunter
  (?)
@ 2015-07-14 11:59             ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-14 11:59 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra, devicetree, linux-arm-kernel, linux-pm



On 13/07/15 15:03, Jon Hunter wrote:
> 
> 
> On 13/07/15 14:50, Peter De Schrijver wrote:
>> On Mon, Jul 13, 2015 at 01:39:57PM +0100, Jon Hunter wrote:
>>> From: Vince Hsu <vinceh@nvidia.com>
>>>
>>> We have added generic power domain support for Tegra SoCs. So now the
>>> option M_GENERIC_DOMAINS must be enabled by default to have proper power
>>
>> Missing P :)
> 
> Ooops. I think introduced that error. Will fix.

Updated version ...


From f7b951cd05973d74fc25e33a1aaec5a6e77bfdc0 Mon Sep 17 00:00:00 2001
From: Vince Hsu <vinceh@nvidia.com>
Date: Wed, 11 Mar 2015 13:40:46 +0800
Subject: [PATCH 19/19] ARM: tegra: select PM_GENERIC_DOMAINS

We have added generic power domain support for Tegra SoCs. So now the
option PM_GENERIC_DOMAINS must be enabled by default to have proper power
sequence.

Signed-off-by: Vince Hsu <vinceh@nvidia.com>
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 arch/arm/mach-tegra/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 0fa4c5f8b1be..fdf86cae3b32 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -9,6 +9,7 @@ menuconfig ARCH_TEGRA
 	select HAVE_ARM_TWD if SMP
 	select PINCTRL
 	select PM_OPP
+	select PM_GENERIC_DOMAINS if PM
 	select ARCH_HAS_RESET_CONTROLLER
 	select RESET_CONTROLLER
 	select SOC_BUS
-- 
2.1.4


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

* Re: [PATCH V3 19/19] ARM: tegra: select PM_GENERIC_DOMAINS
@ 2015-07-14 11:59             ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-14 11:59 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra, devicetree, linux-arm-kernel, linux-pm



On 13/07/15 15:03, Jon Hunter wrote:
> 
> 
> On 13/07/15 14:50, Peter De Schrijver wrote:
>> On Mon, Jul 13, 2015 at 01:39:57PM +0100, Jon Hunter wrote:
>>> From: Vince Hsu <vinceh@nvidia.com>
>>>
>>> We have added generic power domain support for Tegra SoCs. So now the
>>> option M_GENERIC_DOMAINS must be enabled by default to have proper power
>>
>> Missing P :)
> 
> Ooops. I think introduced that error. Will fix.

Updated version ...


>From f7b951cd05973d74fc25e33a1aaec5a6e77bfdc0 Mon Sep 17 00:00:00 2001
From: Vince Hsu <vinceh@nvidia.com>
Date: Wed, 11 Mar 2015 13:40:46 +0800
Subject: [PATCH 19/19] ARM: tegra: select PM_GENERIC_DOMAINS

We have added generic power domain support for Tegra SoCs. So now the
option PM_GENERIC_DOMAINS must be enabled by default to have proper power
sequence.

Signed-off-by: Vince Hsu <vinceh@nvidia.com>
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 arch/arm/mach-tegra/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 0fa4c5f8b1be..fdf86cae3b32 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -9,6 +9,7 @@ menuconfig ARCH_TEGRA
 	select HAVE_ARM_TWD if SMP
 	select PINCTRL
 	select PM_OPP
+	select PM_GENERIC_DOMAINS if PM
 	select ARCH_HAS_RESET_CONTROLLER
 	select RESET_CONTROLLER
 	select SOC_BUS
-- 
2.1.4


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

* [PATCH V3 19/19] ARM: tegra: select PM_GENERIC_DOMAINS
@ 2015-07-14 11:59             ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-14 11:59 UTC (permalink / raw)
  To: linux-arm-kernel



On 13/07/15 15:03, Jon Hunter wrote:
> 
> 
> On 13/07/15 14:50, Peter De Schrijver wrote:
>> On Mon, Jul 13, 2015 at 01:39:57PM +0100, Jon Hunter wrote:
>>> From: Vince Hsu <vinceh@nvidia.com>
>>>
>>> We have added generic power domain support for Tegra SoCs. So now the
>>> option M_GENERIC_DOMAINS must be enabled by default to have proper power
>>
>> Missing P :)
> 
> Ooops. I think introduced that error. Will fix.

Updated version ...


>From f7b951cd05973d74fc25e33a1aaec5a6e77bfdc0 Mon Sep 17 00:00:00 2001
From: Vince Hsu <vinceh@nvidia.com>
Date: Wed, 11 Mar 2015 13:40:46 +0800
Subject: [PATCH 19/19] ARM: tegra: select PM_GENERIC_DOMAINS

We have added generic power domain support for Tegra SoCs. So now the
option PM_GENERIC_DOMAINS must be enabled by default to have proper power
sequence.

Signed-off-by: Vince Hsu <vinceh@nvidia.com>
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 arch/arm/mach-tegra/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 0fa4c5f8b1be..fdf86cae3b32 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -9,6 +9,7 @@ menuconfig ARCH_TEGRA
 	select HAVE_ARM_TWD if SMP
 	select PINCTRL
 	select PM_OPP
+	select PM_GENERIC_DOMAINS if PM
 	select ARCH_HAS_RESET_CONTROLLER
 	select RESET_CONTROLLER
 	select SOC_BUS
-- 
2.1.4

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

* Re: [PATCH V3 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2
  2015-07-14 11:59             ` Jon Hunter
@ 2015-07-15  8:16                 ` Peter De Schrijver
  -1 siblings, 0 replies; 110+ messages in thread
From: Peter De Schrijver @ 2015-07-15  8:16 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

On Tue, Jul 14, 2015 at 12:59:01PM +0100, Jon Hunter wrote:
> 
> On 13/07/15 15:02, Jon Hunter wrote:
> > 
> > 
> > On 13/07/15 14:41, Peter De Schrijver wrote:
> >> On Mon, Jul 13, 2015 at 01:39:44PM +0100, Jon Hunter wrote:
> >>> From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> >>>
> >>> Tegra114 has a HW bug that the PLLD/PLLD2 lock bit cannot be asserted when
> >>> the DIS power domain is during up-powergating process but the clamp to this
> >>
> >> I think there is missing 'off' in this sentence?
> >>
> >> ie. ... 'the DIS power domain is off during up-powergating process'
> >>
> >> Also 'un-powergating sequence' would be nicer.
> > 
> > Yes agree. I will re-word that.
> 
> Updated version ...
> 
> 
> From d5cbecd4e97332cd8373b9c4893731eb8e063660 Mon Sep 17 00:00:00 2001
> From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> Date: Wed, 11 Mar 2015 16:46:04 +0800
> Subject: [PATCH 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2
> 
> Tegra114 has a HW bug where the PLLD/PLLD2 lock bit cannot be asserted
> while turning on the Display power domain and before the clamp to this
> domain has been removed. This issue causes a timeout and aborts the power
> up sequence, even though the PLLD/PLLD2 has already locked. To avoid this,
> don't use the lock for PLLD/PLLD2, just wait 1ms and treat the clocks as
> locked.
> 
> Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> [jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org: Updated the changelog description]
> Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Acked-By: Peter De Schrijver <pdeschrijver-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
>  drivers/clk/tegra/clk-tegra114.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
> index 8237d16b4075..2e5c20c7c088 100644
> --- a/drivers/clk/tegra/clk-tegra114.c
> +++ b/drivers/clk/tegra/clk-tegra114.c
> @@ -456,8 +456,7 @@ static struct tegra_clk_pll_params pll_d_params = {
>  	.lock_delay = 1000,
>  	.div_nmp = &pllp_nmp,
>  	.freq_table = pll_d_freq_table,
> -	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
> -		 TEGRA_PLL_USE_LOCK,
> +	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
>  };
>  
>  static struct tegra_clk_pll_params pll_d2_params = {
> @@ -474,8 +473,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
>  	.lock_delay = 1000,
>  	.div_nmp = &pllp_nmp,
>  	.freq_table = pll_d_freq_table,
> -	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
> -		 TEGRA_PLL_USE_LOCK,
> +	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
>  };
>  
>  static struct pdiv_map pllu_p[] = {
> -- 
> 2.1.4
> 

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

* [PATCH V3 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2
@ 2015-07-15  8:16                 ` Peter De Schrijver
  0 siblings, 0 replies; 110+ messages in thread
From: Peter De Schrijver @ 2015-07-15  8:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 14, 2015 at 12:59:01PM +0100, Jon Hunter wrote:
> 
> On 13/07/15 15:02, Jon Hunter wrote:
> > 
> > 
> > On 13/07/15 14:41, Peter De Schrijver wrote:
> >> On Mon, Jul 13, 2015 at 01:39:44PM +0100, Jon Hunter wrote:
> >>> From: Vince Hsu <vinceh@nvidia.com>
> >>>
> >>> Tegra114 has a HW bug that the PLLD/PLLD2 lock bit cannot be asserted when
> >>> the DIS power domain is during up-powergating process but the clamp to this
> >>
> >> I think there is missing 'off' in this sentence?
> >>
> >> ie. ... 'the DIS power domain is off during up-powergating process'
> >>
> >> Also 'un-powergating sequence' would be nicer.
> > 
> > Yes agree. I will re-word that.
> 
> Updated version ...
> 
> 
> From d5cbecd4e97332cd8373b9c4893731eb8e063660 Mon Sep 17 00:00:00 2001
> From: Vince Hsu <vinceh@nvidia.com>
> Date: Wed, 11 Mar 2015 16:46:04 +0800
> Subject: [PATCH 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2
> 
> Tegra114 has a HW bug where the PLLD/PLLD2 lock bit cannot be asserted
> while turning on the Display power domain and before the clamp to this
> domain has been removed. This issue causes a timeout and aborts the power
> up sequence, even though the PLLD/PLLD2 has already locked. To avoid this,
> don't use the lock for PLLD/PLLD2, just wait 1ms and treat the clocks as
> locked.
> 
> Signed-off-by: Vince Hsu <vinceh@nvidia.com>
> [jonathanh at nvidia.com: Updated the changelog description]
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>

Acked-By: Peter De Schrijver <pdeschrijver@nvidia.com>
> ---
>  drivers/clk/tegra/clk-tegra114.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
> index 8237d16b4075..2e5c20c7c088 100644
> --- a/drivers/clk/tegra/clk-tegra114.c
> +++ b/drivers/clk/tegra/clk-tegra114.c
> @@ -456,8 +456,7 @@ static struct tegra_clk_pll_params pll_d_params = {
>  	.lock_delay = 1000,
>  	.div_nmp = &pllp_nmp,
>  	.freq_table = pll_d_freq_table,
> -	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
> -		 TEGRA_PLL_USE_LOCK,
> +	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
>  };
>  
>  static struct tegra_clk_pll_params pll_d2_params = {
> @@ -474,8 +473,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
>  	.lock_delay = 1000,
>  	.div_nmp = &pllp_nmp,
>  	.freq_table = pll_d_freq_table,
> -	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
> -		 TEGRA_PLL_USE_LOCK,
> +	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
>  };
>  
>  static struct pdiv_map pllu_p[] = {
> -- 
> 2.1.4
> 

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

* Re: [PATCH V3 19/19] ARM: tegra: select PM_GENERIC_DOMAINS
  2015-07-14 11:59             ` Jon Hunter
@ 2015-07-15  8:17                 ` Peter De Schrijver
  -1 siblings, 0 replies; 110+ messages in thread
From: Peter De Schrijver @ 2015-07-15  8:17 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Thierry Reding, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

On Tue, Jul 14, 2015 at 12:59:50PM +0100, Jon Hunter wrote:
> 
> 
> On 13/07/15 15:03, Jon Hunter wrote:
> > 
> > 
> > On 13/07/15 14:50, Peter De Schrijver wrote:
> >> On Mon, Jul 13, 2015 at 01:39:57PM +0100, Jon Hunter wrote:
> >>> From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> >>>
> >>> We have added generic power domain support for Tegra SoCs. So now the
> >>> option M_GENERIC_DOMAINS must be enabled by default to have proper power
> >>
> >> Missing P :)
> > 
> > Ooops. I think introduced that error. Will fix.
> 
> Updated version ...
> 

Acked-By: Peter De Schrijver <pdeschrijver-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> 
> From f7b951cd05973d74fc25e33a1aaec5a6e77bfdc0 Mon Sep 17 00:00:00 2001
> From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> Date: Wed, 11 Mar 2015 13:40:46 +0800
> Subject: [PATCH 19/19] ARM: tegra: select PM_GENERIC_DOMAINS
> 
> We have added generic power domain support for Tegra SoCs. So now the
> option PM_GENERIC_DOMAINS must be enabled by default to have proper power
> sequence.
> 
> Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
>  arch/arm/mach-tegra/Kconfig | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
> index 0fa4c5f8b1be..fdf86cae3b32 100644
> --- a/arch/arm/mach-tegra/Kconfig
> +++ b/arch/arm/mach-tegra/Kconfig
> @@ -9,6 +9,7 @@ menuconfig ARCH_TEGRA
>  	select HAVE_ARM_TWD if SMP
>  	select PINCTRL
>  	select PM_OPP
> +	select PM_GENERIC_DOMAINS if PM
>  	select ARCH_HAS_RESET_CONTROLLER
>  	select RESET_CONTROLLER
>  	select SOC_BUS
> -- 
> 2.1.4
> 

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

* [PATCH V3 19/19] ARM: tegra: select PM_GENERIC_DOMAINS
@ 2015-07-15  8:17                 ` Peter De Schrijver
  0 siblings, 0 replies; 110+ messages in thread
From: Peter De Schrijver @ 2015-07-15  8:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 14, 2015 at 12:59:50PM +0100, Jon Hunter wrote:
> 
> 
> On 13/07/15 15:03, Jon Hunter wrote:
> > 
> > 
> > On 13/07/15 14:50, Peter De Schrijver wrote:
> >> On Mon, Jul 13, 2015 at 01:39:57PM +0100, Jon Hunter wrote:
> >>> From: Vince Hsu <vinceh@nvidia.com>
> >>>
> >>> We have added generic power domain support for Tegra SoCs. So now the
> >>> option M_GENERIC_DOMAINS must be enabled by default to have proper power
> >>
> >> Missing P :)
> > 
> > Ooops. I think introduced that error. Will fix.
> 
> Updated version ...
> 

Acked-By: Peter De Schrijver <pdeschrijver@nvidia.com>
> 
> From f7b951cd05973d74fc25e33a1aaec5a6e77bfdc0 Mon Sep 17 00:00:00 2001
> From: Vince Hsu <vinceh@nvidia.com>
> Date: Wed, 11 Mar 2015 13:40:46 +0800
> Subject: [PATCH 19/19] ARM: tegra: select PM_GENERIC_DOMAINS
> 
> We have added generic power domain support for Tegra SoCs. So now the
> option PM_GENERIC_DOMAINS must be enabled by default to have proper power
> sequence.
> 
> Signed-off-by: Vince Hsu <vinceh@nvidia.com>
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  arch/arm/mach-tegra/Kconfig | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
> index 0fa4c5f8b1be..fdf86cae3b32 100644
> --- a/arch/arm/mach-tegra/Kconfig
> +++ b/arch/arm/mach-tegra/Kconfig
> @@ -9,6 +9,7 @@ menuconfig ARCH_TEGRA
>  	select HAVE_ARM_TWD if SMP
>  	select PINCTRL
>  	select PM_OPP
> +	select PM_GENERIC_DOMAINS if PM
>  	select ARCH_HAS_RESET_CONTROLLER
>  	select RESET_CONTROLLER
>  	select SOC_BUS
> -- 
> 2.1.4
> 

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

* Re: [PATCH V3 18/19] ARM: tegra: add GPU power supply to Jetson TK1 DT
  2015-07-13 12:39     ` Jon Hunter
@ 2015-07-17  9:28         ` Thierry Reding
  -1 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17  9:28 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 1152 bytes --]

On Mon, Jul 13, 2015 at 01:39:56PM +0100, Jon Hunter wrote:
> From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> 
> Add power supply information which is board dependent for GK20A.
> 
> Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
>  arch/arm/boot/dts/tegra124-jetson-tk1.dts | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
> index ce5961cd0b77..2b355957635c 100644
> --- a/arch/arm/boot/dts/tegra124-jetson-tk1.dts
> +++ b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
> @@ -1514,7 +1514,7 @@
>  					regulator-always-on;
>  				};
>  
> -				sd6 {
> +				vdd_gpu: sd6 {
>  					regulator-name = "+VDD_GPU_AP";
>  					regulator-min-microvolt = <650000>;
>  					regulator-max-microvolt = <1200000>;
> @@ -1635,6 +1635,10 @@
>  		};
>  	};
>  
> +	gpu-power-domain {
> +		vdd-supply = <&vdd_gpu>;
> +	};

This doesn't seem to match the path to the original node.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* [PATCH V3 18/19] ARM: tegra: add GPU power supply to Jetson TK1 DT
@ 2015-07-17  9:28         ` Thierry Reding
  0 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17  9:28 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 13, 2015 at 01:39:56PM +0100, Jon Hunter wrote:
> From: Vince Hsu <vinceh@nvidia.com>
> 
> Add power supply information which is board dependent for GK20A.
> 
> Signed-off-by: Vince Hsu <vinceh@nvidia.com>
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  arch/arm/boot/dts/tegra124-jetson-tk1.dts | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
> index ce5961cd0b77..2b355957635c 100644
> --- a/arch/arm/boot/dts/tegra124-jetson-tk1.dts
> +++ b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
> @@ -1514,7 +1514,7 @@
>  					regulator-always-on;
>  				};
>  
> -				sd6 {
> +				vdd_gpu: sd6 {
>  					regulator-name = "+VDD_GPU_AP";
>  					regulator-min-microvolt = <650000>;
>  					regulator-max-microvolt = <1200000>;
> @@ -1635,6 +1635,10 @@
>  		};
>  	};
>  
> +	gpu-power-domain {
> +		vdd-supply = <&vdd_gpu>;
> +	};

This doesn't seem to match the path to the original node.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150717/6e42b0a0/attachment.sig>

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

* Re: [PATCH V3 14/19] Documentation: DT: bindings: Add power domain info for NVIDIA PMC
  2015-07-13 12:39     ` Jon Hunter
@ 2015-07-17  9:38         ` Thierry Reding
  -1 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17  9:38 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 4243 bytes --]

On Mon, Jul 13, 2015 at 01:39:52PM +0100, Jon Hunter wrote:
> Add power-domain binding documentation for the NVIDIA PMC driver in
> order to support generic power-domains.
> 
> Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
>  .../bindings/arm/tegra/nvidia,tegra20-pmc.txt      | 99 ++++++++++++++++++++++
>  1 file changed, 99 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
> index 02c27004d4a8..93357a450576 100644
> --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
> +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
> @@ -1,5 +1,7 @@
>  NVIDIA Tegra Power Management Controller (PMC)
>  
> +== Power Management Controller Node ==
> +
>  The PMC block interacts with an external Power Management Unit. The PMC
>  mostly controls the entry and exit of the system from different sleep
>  modes. It provides power-gating controllers for SoC and CPU power-islands.
> @@ -68,6 +70,10 @@ Optional properties for hardware-triggered thermal reset (inside 'i2c-thermtrip'
>                       Defaults to 0. Valid values are described in section 12.5.2
>                       "Pinmux Support" of the Tegra4 Technical Reference Manual.
>  
> +Optional nodes:
> +- pm-domains : This node contains a hierarchy of PM domain nodes, which should
> +	       match the power-domains on the Tegra SoC.

Perhaps call this simply power-domains to match the property name in
consumer nodes?

> +
>  Example:
>  
>  / SoC dts including file
> @@ -113,3 +119,96 @@ pmc@7000f400 {
>  	};
>  	...
>  };
> +
> +
> +== PM Domain Nodes ==
> +
> +Each of the PM domain nodes represents a power-domain on the Tegra SoC
> +that can be power-gated by the PMC and should be named appropriately.
> +
> +Required properties:
> +  - clocks:		   Must contain an entry for each clock required by
> +			   the PMC for controlling a power-gate. See
> +			   ../clocks/clock-bindings.txt for details.
> +  - resets:		   Must contain an entry for each reset required by
> +			   the PMC for controlling a power-gate. See
> +			   ../reset/reset.txt for details.
> +  - nvidia,powergate:	   Integer cell that contains an identifier for the
> +			   PMC power-gate that is associated with the
> +			   power-domain. Please refer to the Tegra TRM for
> +			   more details.

I find this really difficult to read. Can we use a more conventional
format such as:

	- clocks: Must contain...
	  ... for details.

?

> +  - #power-domain-cells:   Must be 0.
> +
> +Optional properties:
> +  - nvidia,swgroups:	   Provides details of the software groups that are
> +			   associated with a specific power-domain. The
> +			   software group specifier consists of a phandle
> +			   pointing to the memory controller and a list of
> +			   one or more integer cells for each software group
> +			   associated with the power domain. The length of
> +			   the list of integer cells is specified by
> +			   #nvidia,swgroup-cells.
> +  - #nvidia,swgroup-cells: Must be 1 or more. See nvidia,swgroups for
> +			   more details.

That's not how this usually works. #*-cells properties determine the
number of cells required per <phandle spec> pair. So I think this should
be more along the lines of:

  - #nvidia,swgroups: A list of software groups associated with a
    specific power domain. This consists of a list of phandle and
    SWGROUP ID pairs, where the phandle points to the memory
    controller node.
  - #nvidia,swgroup-cells: Must be 1. The single cell in the specifier
    denotes the ID of the software group.

> +
> +Example:
> +
> +	pmc@0,7000e400 {
> +		compatible = "nvidia,tegra124-pmc";
> +		reg = <0x0 0x7000e400 0x0 0x400>;
> +		clocks = <&tegra_car TEGRA124_CLK_PCLK>, <&clk32k_in>;
> +		clock-names = "pclk", "clk32k_in";
> +
> +		pm-domains {

power-domains would convey more clearly what this is about.

> +			...
> +
> +			pd_sor: sor-power-domain {

I don't think it's useful to repeat the -power-domain suffix for all
these nodes.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* [PATCH V3 14/19] Documentation: DT: bindings: Add power domain info for NVIDIA PMC
@ 2015-07-17  9:38         ` Thierry Reding
  0 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17  9:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 13, 2015 at 01:39:52PM +0100, Jon Hunter wrote:
> Add power-domain binding documentation for the NVIDIA PMC driver in
> order to support generic power-domains.
> 
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  .../bindings/arm/tegra/nvidia,tegra20-pmc.txt      | 99 ++++++++++++++++++++++
>  1 file changed, 99 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
> index 02c27004d4a8..93357a450576 100644
> --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
> +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
> @@ -1,5 +1,7 @@
>  NVIDIA Tegra Power Management Controller (PMC)
>  
> +== Power Management Controller Node ==
> +
>  The PMC block interacts with an external Power Management Unit. The PMC
>  mostly controls the entry and exit of the system from different sleep
>  modes. It provides power-gating controllers for SoC and CPU power-islands.
> @@ -68,6 +70,10 @@ Optional properties for hardware-triggered thermal reset (inside 'i2c-thermtrip'
>                       Defaults to 0. Valid values are described in section 12.5.2
>                       "Pinmux Support" of the Tegra4 Technical Reference Manual.
>  
> +Optional nodes:
> +- pm-domains : This node contains a hierarchy of PM domain nodes, which should
> +	       match the power-domains on the Tegra SoC.

Perhaps call this simply power-domains to match the property name in
consumer nodes?

> +
>  Example:
>  
>  / SoC dts including file
> @@ -113,3 +119,96 @@ pmc at 7000f400 {
>  	};
>  	...
>  };
> +
> +
> +== PM Domain Nodes ==
> +
> +Each of the PM domain nodes represents a power-domain on the Tegra SoC
> +that can be power-gated by the PMC and should be named appropriately.
> +
> +Required properties:
> +  - clocks:		   Must contain an entry for each clock required by
> +			   the PMC for controlling a power-gate. See
> +			   ../clocks/clock-bindings.txt for details.
> +  - resets:		   Must contain an entry for each reset required by
> +			   the PMC for controlling a power-gate. See
> +			   ../reset/reset.txt for details.
> +  - nvidia,powergate:	   Integer cell that contains an identifier for the
> +			   PMC power-gate that is associated with the
> +			   power-domain. Please refer to the Tegra TRM for
> +			   more details.

I find this really difficult to read. Can we use a more conventional
format such as:

	- clocks: Must contain...
	  ... for details.

?

> +  - #power-domain-cells:   Must be 0.
> +
> +Optional properties:
> +  - nvidia,swgroups:	   Provides details of the software groups that are
> +			   associated with a specific power-domain. The
> +			   software group specifier consists of a phandle
> +			   pointing to the memory controller and a list of
> +			   one or more integer cells for each software group
> +			   associated with the power domain. The length of
> +			   the list of integer cells is specified by
> +			   #nvidia,swgroup-cells.
> +  - #nvidia,swgroup-cells: Must be 1 or more. See nvidia,swgroups for
> +			   more details.

That's not how this usually works. #*-cells properties determine the
number of cells required per <phandle spec> pair. So I think this should
be more along the lines of:

  - #nvidia,swgroups: A list of software groups associated with a
    specific power domain. This consists of a list of phandle and
    SWGROUP ID pairs, where the phandle points to the memory
    controller node.
  - #nvidia,swgroup-cells: Must be 1. The single cell in the specifier
    denotes the ID of the software group.

> +
> +Example:
> +
> +	pmc at 0,7000e400 {
> +		compatible = "nvidia,tegra124-pmc";
> +		reg = <0x0 0x7000e400 0x0 0x400>;
> +		clocks = <&tegra_car TEGRA124_CLK_PCLK>, <&clk32k_in>;
> +		clock-names = "pclk", "clk32k_in";
> +
> +		pm-domains {

power-domains would convey more clearly what this is about.

> +			...
> +
> +			pd_sor: sor-power-domain {

I don't think it's useful to repeat the -power-domain suffix for all
these nodes.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150717/9a76a930/attachment.sig>

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

* Re: [PATCH V3 02/19] memory: tegra: Add MC flush support
  2015-07-13 12:39     ` Jon Hunter
@ 2015-07-17  9:57       ` Thierry Reding
  -1 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17  9:57 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra, devicetree,
	linux-arm-kernel, linux-pm

[-- Attachment #1: Type: text/plain, Size: 1328 bytes --]

On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
> The Tegra memory controller implements a flush feature to flush pending
> accesses and prevent further accesses from occurring. This feature is
> used when powering down IP blocks to ensure the IP block is in a good
> state. The flushes are organised by software groups and IP blocks are
> assigned in hardware to the different software groups. Add helper
> functions for requesting a handle to an MC flush for a given
> software group and enabling/disabling the MC flush itself.
> 
> This is based upon a change by Vince Hsu <vinceh@nvidia.com>.
> 
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/memory/tegra/mc.h |   2 +
>  include/soc/tegra/mc.h    |  34 ++++++++++++++
>  3 files changed, 146 insertions(+)

Do we know if this is actually necessary? I remember having a discussion
with Arnd Bergmann a while ago, and the Linux driver model kind of
assumes that by the time a device is disabled all outstanding accesses
will have stopped.

Do we have a way to determine that this even makes a difference? Can we
trigger a case where not doing this would cause breakage and see that
adding this fixes that particular issue?

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* [PATCH V3 02/19] memory: tegra: Add MC flush support
@ 2015-07-17  9:57       ` Thierry Reding
  0 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17  9:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
> The Tegra memory controller implements a flush feature to flush pending
> accesses and prevent further accesses from occurring. This feature is
> used when powering down IP blocks to ensure the IP block is in a good
> state. The flushes are organised by software groups and IP blocks are
> assigned in hardware to the different software groups. Add helper
> functions for requesting a handle to an MC flush for a given
> software group and enabling/disabling the MC flush itself.
> 
> This is based upon a change by Vince Hsu <vinceh@nvidia.com>.
> 
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/memory/tegra/mc.h |   2 +
>  include/soc/tegra/mc.h    |  34 ++++++++++++++
>  3 files changed, 146 insertions(+)

Do we know if this is actually necessary? I remember having a discussion
with Arnd Bergmann a while ago, and the Linux driver model kind of
assumes that by the time a device is disabled all outstanding accesses
will have stopped.

Do we have a way to determine that this even makes a difference? Can we
trigger a case where not doing this would cause breakage and see that
adding this fixes that particular issue?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150717/ffe99bd6/attachment.sig>

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

* Re: [PATCH V3 03/19] memory: tegra: add flush operation for Tegra30 memory clients
  2015-07-13 12:39     ` Jon Hunter
@ 2015-07-17 10:03         ` Thierry Reding
  -1 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 10:03 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 2217 bytes --]

On Mon, Jul 13, 2015 at 01:39:41PM +0100, Jon Hunter wrote:
> From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> 
> This patch adds the hot reset register table and flush related callback
> functions for Tegra30.
> 
> Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> [jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org: Removed tegra_mc_ops and added
>  metastable_flush_reads.]
> Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> 
> ---
> v3: removal of tegra_mc_ops
> ---
>  drivers/memory/tegra/tegra30.c | 24 ++++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
> 
> diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
> index 1abcd8f6f3ba..3b4987f39b52 100644
> --- a/drivers/memory/tegra/tegra30.c
> +++ b/drivers/memory/tegra/tegra30.c
> @@ -6,6 +6,7 @@
>   * published by the Free Software Foundation.
>   */
>  
> +#include <linux/device.h>

What do you need this for?

>  #include <linux/of.h>
>  #include <linux/mm.h>
>  
> @@ -936,6 +937,26 @@ static const struct tegra_smmu_swgroup tegra30_swgroups[] = {
>  	{ .name = "isp",  .swgroup = TEGRA_SWGROUP_ISP,  .reg = 0x258 },
>  };
>  
> +static struct tegra_mc_flush tegra30_mc_flush[] = {

const

> +	{TEGRA_SWGROUP_AFI,        0x200, 0x204,  0},
> +	{TEGRA_SWGROUP_AVPC,       0x200, 0x204,  1},
> +	{TEGRA_SWGROUP_DC,         0x200, 0x204,  2},
> +	{TEGRA_SWGROUP_DCB,        0x200, 0x204,  3},
> +	{TEGRA_SWGROUP_EPP,        0x200, 0x204,  4},
> +	{TEGRA_SWGROUP_G2,         0x200, 0x204,  5},
> +	{TEGRA_SWGROUP_HC,         0x200, 0x204,  6},
> +	{TEGRA_SWGROUP_HDA,        0x200, 0x204,  7},
> +	{TEGRA_SWGROUP_ISP,        0x200, 0x204,  8},
> +	{TEGRA_SWGROUP_MPCORE,     0x200, 0x204,  9},
> +	{TEGRA_SWGROUP_MPCORELP,   0x200, 0x204, 10},
> +	{TEGRA_SWGROUP_MPE,        0x200, 0x204, 11},
> +	{TEGRA_SWGROUP_NV,         0x200, 0x204, 12},
> +	{TEGRA_SWGROUP_NV2,        0x200, 0x204, 13},
> +	{TEGRA_SWGROUP_PPCS,       0x200, 0x204, 14},
> +	{TEGRA_SWGROUP_VDE,        0x200, 0x204, 16},
> +	{TEGRA_SWGROUP_VI,         0x200, 0x204, 17},

Spaces around { and }, please.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* [PATCH V3 03/19] memory: tegra: add flush operation for Tegra30 memory clients
@ 2015-07-17 10:03         ` Thierry Reding
  0 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 10:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 13, 2015 at 01:39:41PM +0100, Jon Hunter wrote:
> From: Vince Hsu <vinceh@nvidia.com>
> 
> This patch adds the hot reset register table and flush related callback
> functions for Tegra30.
> 
> Signed-off-by: Vince Hsu <vinceh@nvidia.com>
> [jonathanh at nvidia.com: Removed tegra_mc_ops and added
>  metastable_flush_reads.]
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> 
> ---
> v3: removal of tegra_mc_ops
> ---
>  drivers/memory/tegra/tegra30.c | 24 ++++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
> 
> diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
> index 1abcd8f6f3ba..3b4987f39b52 100644
> --- a/drivers/memory/tegra/tegra30.c
> +++ b/drivers/memory/tegra/tegra30.c
> @@ -6,6 +6,7 @@
>   * published by the Free Software Foundation.
>   */
>  
> +#include <linux/device.h>

What do you need this for?

>  #include <linux/of.h>
>  #include <linux/mm.h>
>  
> @@ -936,6 +937,26 @@ static const struct tegra_smmu_swgroup tegra30_swgroups[] = {
>  	{ .name = "isp",  .swgroup = TEGRA_SWGROUP_ISP,  .reg = 0x258 },
>  };
>  
> +static struct tegra_mc_flush tegra30_mc_flush[] = {

const

> +	{TEGRA_SWGROUP_AFI,        0x200, 0x204,  0},
> +	{TEGRA_SWGROUP_AVPC,       0x200, 0x204,  1},
> +	{TEGRA_SWGROUP_DC,         0x200, 0x204,  2},
> +	{TEGRA_SWGROUP_DCB,        0x200, 0x204,  3},
> +	{TEGRA_SWGROUP_EPP,        0x200, 0x204,  4},
> +	{TEGRA_SWGROUP_G2,         0x200, 0x204,  5},
> +	{TEGRA_SWGROUP_HC,         0x200, 0x204,  6},
> +	{TEGRA_SWGROUP_HDA,        0x200, 0x204,  7},
> +	{TEGRA_SWGROUP_ISP,        0x200, 0x204,  8},
> +	{TEGRA_SWGROUP_MPCORE,     0x200, 0x204,  9},
> +	{TEGRA_SWGROUP_MPCORELP,   0x200, 0x204, 10},
> +	{TEGRA_SWGROUP_MPE,        0x200, 0x204, 11},
> +	{TEGRA_SWGROUP_NV,         0x200, 0x204, 12},
> +	{TEGRA_SWGROUP_NV2,        0x200, 0x204, 13},
> +	{TEGRA_SWGROUP_PPCS,       0x200, 0x204, 14},
> +	{TEGRA_SWGROUP_VDE,        0x200, 0x204, 16},
> +	{TEGRA_SWGROUP_VI,         0x200, 0x204, 17},

Spaces around { and }, please.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150717/c897e0ba/attachment.sig>

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

* Re: [PATCH V3 04/19] memory: tegra: add flush operation for Tegra114 memory clients
  2015-07-13 12:39     ` Jon Hunter
@ 2015-07-17 10:05         ` Thierry Reding
  -1 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 10:05 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 2519 bytes --]

On Mon, Jul 13, 2015 at 01:39:42PM +0100, Jon Hunter wrote:
> From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> 
> This patch adds the hot reset register table and flush related callback
> functions for Tegra114.
> 
> Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> [jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org: Removed tegra_mc_ops and added
>  metastable_flush_reads.]
> Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
>  drivers/memory/tegra/tegra114.c | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
> 
> diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c
> index 9f579589e800..ba33c402ed68 100644
> --- a/drivers/memory/tegra/tegra114.c
> +++ b/drivers/memory/tegra/tegra114.c
> @@ -914,6 +914,24 @@ static const struct tegra_smmu_swgroup tegra114_swgroups[] = {
>  	{ .name = "tsec",      .swgroup = TEGRA_SWGROUP_TSEC,      .reg = 0x294 },
>  };
>  
> +static struct tegra_mc_flush tegra114_mc_flush[] = {

const

> +	{TEGRA_SWGROUP_AVPC,       0x200, 0x204,  1},
> +	{TEGRA_SWGROUP_DC,         0x200, 0x204,  2},
> +	{TEGRA_SWGROUP_DCB,        0x200, 0x204,  3},
> +	{TEGRA_SWGROUP_EPP,        0x200, 0x204,  4},
> +	{TEGRA_SWGROUP_G2,         0x200, 0x204,  5},
> +	{TEGRA_SWGROUP_HC,         0x200, 0x204,  6},
> +	{TEGRA_SWGROUP_HDA,        0x200, 0x204,  7},
> +	{TEGRA_SWGROUP_ISP,        0x200, 0x204,  8},
> +	{TEGRA_SWGROUP_MPCORE,     0x200, 0x204,  9},
> +	{TEGRA_SWGROUP_MPCORELP,   0x200, 0x204, 10},
> +	{TEGRA_SWGROUP_MSENC,      0x200, 0x204, 11},
> +	{TEGRA_SWGROUP_NV,         0x200, 0x204, 12},
> +	{TEGRA_SWGROUP_PPCS,       0x200, 0x204, 14},
> +	{TEGRA_SWGROUP_VDE,        0x200, 0x204, 16},
> +	{TEGRA_SWGROUP_VI,         0x200, 0x204, 17},
> +};

And spaces after { and before }.

> +
>  static void tegra114_flush_dcache(struct page *page, unsigned long offset,
>  				  size_t size)
>  {
> @@ -945,4 +963,7 @@ const struct tegra_mc_soc tegra114_mc_soc = {
>  	.num_address_bits = 32,
>  	.atom_size = 32,
>  	.smmu = &tegra114_smmu_soc,
> +	.flushes = tegra114_mc_flush,
> +	.num_flushes = ARRAY_SIZE(tegra114_mc_flush),
> +	.metastable_flush_reads = MC_FLUSH_METASTABLE_READS,

I don't think it's useful to have this define. Just use the literal
value here. Much of the purpose of having this per-SoC parameter is to
provide the context that otherwise the macro symbol would provide.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* [PATCH V3 04/19] memory: tegra: add flush operation for Tegra114 memory clients
@ 2015-07-17 10:05         ` Thierry Reding
  0 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 10:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 13, 2015 at 01:39:42PM +0100, Jon Hunter wrote:
> From: Vince Hsu <vinceh@nvidia.com>
> 
> This patch adds the hot reset register table and flush related callback
> functions for Tegra114.
> 
> Signed-off-by: Vince Hsu <vinceh@nvidia.com>
> [jonathanh at nvidia.com: Removed tegra_mc_ops and added
>  metastable_flush_reads.]
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  drivers/memory/tegra/tegra114.c | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
> 
> diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c
> index 9f579589e800..ba33c402ed68 100644
> --- a/drivers/memory/tegra/tegra114.c
> +++ b/drivers/memory/tegra/tegra114.c
> @@ -914,6 +914,24 @@ static const struct tegra_smmu_swgroup tegra114_swgroups[] = {
>  	{ .name = "tsec",      .swgroup = TEGRA_SWGROUP_TSEC,      .reg = 0x294 },
>  };
>  
> +static struct tegra_mc_flush tegra114_mc_flush[] = {

const

> +	{TEGRA_SWGROUP_AVPC,       0x200, 0x204,  1},
> +	{TEGRA_SWGROUP_DC,         0x200, 0x204,  2},
> +	{TEGRA_SWGROUP_DCB,        0x200, 0x204,  3},
> +	{TEGRA_SWGROUP_EPP,        0x200, 0x204,  4},
> +	{TEGRA_SWGROUP_G2,         0x200, 0x204,  5},
> +	{TEGRA_SWGROUP_HC,         0x200, 0x204,  6},
> +	{TEGRA_SWGROUP_HDA,        0x200, 0x204,  7},
> +	{TEGRA_SWGROUP_ISP,        0x200, 0x204,  8},
> +	{TEGRA_SWGROUP_MPCORE,     0x200, 0x204,  9},
> +	{TEGRA_SWGROUP_MPCORELP,   0x200, 0x204, 10},
> +	{TEGRA_SWGROUP_MSENC,      0x200, 0x204, 11},
> +	{TEGRA_SWGROUP_NV,         0x200, 0x204, 12},
> +	{TEGRA_SWGROUP_PPCS,       0x200, 0x204, 14},
> +	{TEGRA_SWGROUP_VDE,        0x200, 0x204, 16},
> +	{TEGRA_SWGROUP_VI,         0x200, 0x204, 17},
> +};

And spaces after { and before }.

> +
>  static void tegra114_flush_dcache(struct page *page, unsigned long offset,
>  				  size_t size)
>  {
> @@ -945,4 +963,7 @@ const struct tegra_mc_soc tegra114_mc_soc = {
>  	.num_address_bits = 32,
>  	.atom_size = 32,
>  	.smmu = &tegra114_smmu_soc,
> +	.flushes = tegra114_mc_flush,
> +	.num_flushes = ARRAY_SIZE(tegra114_mc_flush),
> +	.metastable_flush_reads = MC_FLUSH_METASTABLE_READS,

I don't think it's useful to have this define. Just use the literal
value here. Much of the purpose of having this per-SoC parameter is to
provide the context that otherwise the macro symbol would provide.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150717/397468ae/attachment.sig>

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

* Re: [PATCH V3 05/19] memory: tegra: add flush operation for Tegra124 memory clients
  2015-07-13 12:39     ` Jon Hunter
@ 2015-07-17 10:05       ` Thierry Reding
  -1 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 10:05 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra, devicetree,
	linux-arm-kernel, linux-pm

[-- Attachment #1: Type: text/plain, Size: 558 bytes --]

On Mon, Jul 13, 2015 at 01:39:43PM +0100, Jon Hunter wrote:
> From: Vince Hsu <vinceh@nvidia.com>
> 
> This patch adds the hot reset register table and flush related callback
> functions for Tegra124.
> 
> Signed-off-by: Vince Hsu <vinceh@nvidia.com>
> [jonathanh@nvidia.com: Removed tegra_mc_ops and added
>  metastable_flush_reads.]
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  drivers/memory/tegra/tegra124.c | 31 +++++++++++++++++++++++++++++++
>  1 file changed, 31 insertions(+)

Same comments as for Tegra114.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* [PATCH V3 05/19] memory: tegra: add flush operation for Tegra124 memory clients
@ 2015-07-17 10:05       ` Thierry Reding
  0 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 10:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 13, 2015 at 01:39:43PM +0100, Jon Hunter wrote:
> From: Vince Hsu <vinceh@nvidia.com>
> 
> This patch adds the hot reset register table and flush related callback
> functions for Tegra124.
> 
> Signed-off-by: Vince Hsu <vinceh@nvidia.com>
> [jonathanh at nvidia.com: Removed tegra_mc_ops and added
>  metastable_flush_reads.]
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  drivers/memory/tegra/tegra124.c | 31 +++++++++++++++++++++++++++++++
>  1 file changed, 31 insertions(+)

Same comments as for Tegra114.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150717/7bccb043/attachment.sig>

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

* Re: [PATCH V3 07/19] soc: tegra: pmc: Wait for powergate state to change
  2015-07-13 12:39     ` Jon Hunter
@ 2015-07-17 10:17         ` Thierry Reding
  -1 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 10:17 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 5713 bytes --]

On Mon, Jul 13, 2015 at 01:39:45PM +0100, Jon Hunter wrote:
> Currently, the function tegra_powergate_set() simply sets the desired
> powergate state but does not wait for the state to change. In some
> circumstances this can be desirable. However, in most cases we should
> wait for the state to change before proceeding. Therefore, add a
> parameter to tegra_powergate_set() to indicate whether we should wait
> for the state to change.
> 
> By adding this feature, we can also eliminate the polling loop from
> tegra30_boot_secondary().
> 
> Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
>  arch/arm/mach-tegra/platsmp.c | 18 ++++--------------
>  drivers/soc/tegra/pmc.c       | 29 +++++++++++++++++++++++------
>  include/soc/tegra/pmc.h       |  2 +-
>  3 files changed, 28 insertions(+), 21 deletions(-)
> 
> diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
> index b45086666648..13982b5936c0 100644
> --- a/arch/arm/mach-tegra/platsmp.c
> +++ b/arch/arm/mach-tegra/platsmp.c
> @@ -108,19 +108,9 @@ static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle)
>  	 * be un-gated by un-toggling the power gate register
>  	 * manually.
>  	 */
> -	if (!tegra_pmc_cpu_is_powered(cpu)) {
> -		ret = tegra_pmc_cpu_power_on(cpu);
> -		if (ret)
> -			return ret;
> -
> -		/* Wait for the power to come up. */
> -		timeout = jiffies + msecs_to_jiffies(100);
> -		while (!tegra_pmc_cpu_is_powered(cpu)) {
> -			if (time_after(jiffies, timeout))
> -				return -ETIMEDOUT;
> -			udelay(10);
> -		}
> -	}
> +	ret = tegra_pmc_cpu_power_on(cpu, true);
> +	if (ret)
> +		return ret;
>  
>  remove_clamps:
>  	/* CPU partition is powered. Enable the CPU clock. */
> @@ -162,7 +152,7 @@ static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle)
>  		 * also initial power state in flow controller. After that,
>  		 * the CPU's power state is maintained by flow controller.
>  		 */
> -		ret = tegra_pmc_cpu_power_on(cpu);
> +		ret = tegra_pmc_cpu_power_on(cpu, false);
>  	}
>  
>  	return ret;
> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
> index 300f11e0c3bb..c0635bdd4ee3 100644
> --- a/drivers/soc/tegra/pmc.c
> +++ b/drivers/soc/tegra/pmc.c
> @@ -175,9 +175,11 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
>   * @id: partition ID
>   * @new_state: new state of the partition

The comment here isn't updated.

>   */
> -static int tegra_powergate_set(int id, bool new_state)
> +static int tegra_powergate_set(int id, bool new_state, bool wait)

Can we please not chain boolean parameters, it makes the call sites
impossible to parse for humans. Instead, can we simply leave
tegra_powergate_set() as it is and add another function, such as
tegra_powergate_set_sync() or tegra_powergate_set_and_wait(), to achieve
the same? You may have to split out a tegra_powergate_set_unlocked() or
similar to make sure you get to keep the lock across both operations:

	static int tegra_powergate_set_unlocked(int id, bool new_state)
	{
		...
	}

	static int tegra_powergate_set(int id, bool new_state)
	{
		int err;

		mutex_lock(&pmc->powergates_lock);
		err = tegra_powergate_set_unlocked(id, new_state);
		mutex_unlock(&pmc->powergates_lock);

		return err;
	}

	/*
	 * Must be called with pmc->powergates_lock mutex held.
	 */
	static int tegra_powergate_wait(int id, bool new_state)
	{
		...
	}

	static int tegra_powergate_set_and_wait(int id, bool new_state)
	{
		int err;

		mutex_lock(&pmc->powergates_lock);

		err = tegra_powergate_set_unlocked(id, new_state);
		if (err < 0)
			goto unlock;

		err = tegra_powergate_wait(id, new_state);
		if (err < 0)
			goto unlock;

	unlock:
		mutex_unlock(&pmc->powergates_lock);
		return err;
	}

>  {
> +	unsigned long timeout;
>  	bool status;
> +	int ret = 0;
>  
>  	mutex_lock(&pmc->powergates_lock);
>  
> @@ -190,9 +192,23 @@ static int tegra_powergate_set(int id, bool new_state)
>  
>  	tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
>  
> +	if (wait) {
> +		timeout = jiffies + msecs_to_jiffies(100);
> +		ret = -ETIMEDOUT;
> +
> +		while (time_before(jiffies, timeout)) {
> +			status = !!(tegra_pmc_readl(PWRGATE_STATUS) & BIT(id));
> +			if (status == new_state) {
> +				ret = 0;
> +				break;
> +			}
> +			udelay(10);
> +		}
> +	}
> +
>  	mutex_unlock(&pmc->powergates_lock);
>  
> -	return 0;
> +	return ret;
>  }
>  
>  /**
> @@ -204,7 +220,7 @@ int tegra_powergate_power_on(int id)
>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>  		return -EINVAL;
>  
> -	return tegra_powergate_set(id, true);
> +	return tegra_powergate_set(id, true, true);
>  }
>  
>  /**
> @@ -216,7 +232,7 @@ int tegra_powergate_power_off(int id)
>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>  		return -EINVAL;
>  
> -	return tegra_powergate_set(id, false);
> +	return tegra_powergate_set(id, false, true);
>  }
>  EXPORT_SYMBOL(tegra_powergate_power_off);
>  
> @@ -351,8 +367,9 @@ bool tegra_pmc_cpu_is_powered(int cpuid)
>  /**
>   * tegra_pmc_cpu_power_on() - power on CPU partition
>   * @cpuid: CPU partition ID
> + * @wait:  Wait for CPU state to transition
>   */
> -int tegra_pmc_cpu_power_on(int cpuid)
> +int tegra_pmc_cpu_power_on(int cpuid, bool wait)

This one is probably fine since it's the only boolean parameter so far.
That said, I see that we call this exactly twice, so I wonder if there'd
be any harm in having the second occurrence wait as well and hence get
rid of the parameter.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* [PATCH V3 07/19] soc: tegra: pmc: Wait for powergate state to change
@ 2015-07-17 10:17         ` Thierry Reding
  0 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 10:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 13, 2015 at 01:39:45PM +0100, Jon Hunter wrote:
> Currently, the function tegra_powergate_set() simply sets the desired
> powergate state but does not wait for the state to change. In some
> circumstances this can be desirable. However, in most cases we should
> wait for the state to change before proceeding. Therefore, add a
> parameter to tegra_powergate_set() to indicate whether we should wait
> for the state to change.
> 
> By adding this feature, we can also eliminate the polling loop from
> tegra30_boot_secondary().
> 
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  arch/arm/mach-tegra/platsmp.c | 18 ++++--------------
>  drivers/soc/tegra/pmc.c       | 29 +++++++++++++++++++++++------
>  include/soc/tegra/pmc.h       |  2 +-
>  3 files changed, 28 insertions(+), 21 deletions(-)
> 
> diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
> index b45086666648..13982b5936c0 100644
> --- a/arch/arm/mach-tegra/platsmp.c
> +++ b/arch/arm/mach-tegra/platsmp.c
> @@ -108,19 +108,9 @@ static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle)
>  	 * be un-gated by un-toggling the power gate register
>  	 * manually.
>  	 */
> -	if (!tegra_pmc_cpu_is_powered(cpu)) {
> -		ret = tegra_pmc_cpu_power_on(cpu);
> -		if (ret)
> -			return ret;
> -
> -		/* Wait for the power to come up. */
> -		timeout = jiffies + msecs_to_jiffies(100);
> -		while (!tegra_pmc_cpu_is_powered(cpu)) {
> -			if (time_after(jiffies, timeout))
> -				return -ETIMEDOUT;
> -			udelay(10);
> -		}
> -	}
> +	ret = tegra_pmc_cpu_power_on(cpu, true);
> +	if (ret)
> +		return ret;
>  
>  remove_clamps:
>  	/* CPU partition is powered. Enable the CPU clock. */
> @@ -162,7 +152,7 @@ static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle)
>  		 * also initial power state in flow controller. After that,
>  		 * the CPU's power state is maintained by flow controller.
>  		 */
> -		ret = tegra_pmc_cpu_power_on(cpu);
> +		ret = tegra_pmc_cpu_power_on(cpu, false);
>  	}
>  
>  	return ret;
> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
> index 300f11e0c3bb..c0635bdd4ee3 100644
> --- a/drivers/soc/tegra/pmc.c
> +++ b/drivers/soc/tegra/pmc.c
> @@ -175,9 +175,11 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
>   * @id: partition ID
>   * @new_state: new state of the partition

The comment here isn't updated.

>   */
> -static int tegra_powergate_set(int id, bool new_state)
> +static int tegra_powergate_set(int id, bool new_state, bool wait)

Can we please not chain boolean parameters, it makes the call sites
impossible to parse for humans. Instead, can we simply leave
tegra_powergate_set() as it is and add another function, such as
tegra_powergate_set_sync() or tegra_powergate_set_and_wait(), to achieve
the same? You may have to split out a tegra_powergate_set_unlocked() or
similar to make sure you get to keep the lock across both operations:

	static int tegra_powergate_set_unlocked(int id, bool new_state)
	{
		...
	}

	static int tegra_powergate_set(int id, bool new_state)
	{
		int err;

		mutex_lock(&pmc->powergates_lock);
		err = tegra_powergate_set_unlocked(id, new_state);
		mutex_unlock(&pmc->powergates_lock);

		return err;
	}

	/*
	 * Must be called with pmc->powergates_lock mutex held.
	 */
	static int tegra_powergate_wait(int id, bool new_state)
	{
		...
	}

	static int tegra_powergate_set_and_wait(int id, bool new_state)
	{
		int err;

		mutex_lock(&pmc->powergates_lock);

		err = tegra_powergate_set_unlocked(id, new_state);
		if (err < 0)
			goto unlock;

		err = tegra_powergate_wait(id, new_state);
		if (err < 0)
			goto unlock;

	unlock:
		mutex_unlock(&pmc->powergates_lock);
		return err;
	}

>  {
> +	unsigned long timeout;
>  	bool status;
> +	int ret = 0;
>  
>  	mutex_lock(&pmc->powergates_lock);
>  
> @@ -190,9 +192,23 @@ static int tegra_powergate_set(int id, bool new_state)
>  
>  	tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
>  
> +	if (wait) {
> +		timeout = jiffies + msecs_to_jiffies(100);
> +		ret = -ETIMEDOUT;
> +
> +		while (time_before(jiffies, timeout)) {
> +			status = !!(tegra_pmc_readl(PWRGATE_STATUS) & BIT(id));
> +			if (status == new_state) {
> +				ret = 0;
> +				break;
> +			}
> +			udelay(10);
> +		}
> +	}
> +
>  	mutex_unlock(&pmc->powergates_lock);
>  
> -	return 0;
> +	return ret;
>  }
>  
>  /**
> @@ -204,7 +220,7 @@ int tegra_powergate_power_on(int id)
>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>  		return -EINVAL;
>  
> -	return tegra_powergate_set(id, true);
> +	return tegra_powergate_set(id, true, true);
>  }
>  
>  /**
> @@ -216,7 +232,7 @@ int tegra_powergate_power_off(int id)
>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>  		return -EINVAL;
>  
> -	return tegra_powergate_set(id, false);
> +	return tegra_powergate_set(id, false, true);
>  }
>  EXPORT_SYMBOL(tegra_powergate_power_off);
>  
> @@ -351,8 +367,9 @@ bool tegra_pmc_cpu_is_powered(int cpuid)
>  /**
>   * tegra_pmc_cpu_power_on() - power on CPU partition
>   * @cpuid: CPU partition ID
> + * @wait:  Wait for CPU state to transition
>   */
> -int tegra_pmc_cpu_power_on(int cpuid)
> +int tegra_pmc_cpu_power_on(int cpuid, bool wait)

This one is probably fine since it's the only boolean parameter so far.
That said, I see that we call this exactly twice, so I wonder if there'd
be any harm in having the second occurrence wait as well and hence get
rid of the parameter.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150717/90379f1b/attachment.sig>

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

* Re: [PATCH V3 02/19] memory: tegra: Add MC flush support
  2015-07-17  9:57       ` Thierry Reding
@ 2015-07-17 10:20         ` Peter De Schrijver
  -1 siblings, 0 replies; 110+ messages in thread
From: Peter De Schrijver @ 2015-07-17 10:20 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Jon Hunter, Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra, devicetree, linux-arm-kernel, linux-pm

On Fri, Jul 17, 2015 at 11:57:55AM +0200, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
> > The Tegra memory controller implements a flush feature to flush pending
> > accesses and prevent further accesses from occurring. This feature is
> > used when powering down IP blocks to ensure the IP block is in a good
> > state. The flushes are organised by software groups and IP blocks are
> > assigned in hardware to the different software groups. Add helper
> > functions for requesting a handle to an MC flush for a given
> > software group and enabling/disabling the MC flush itself.
> > 
> > This is based upon a change by Vince Hsu <vinceh@nvidia.com>.
> > 
> > Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> > ---
> >  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
> >  drivers/memory/tegra/mc.h |   2 +
> >  include/soc/tegra/mc.h    |  34 ++++++++++++++
> >  3 files changed, 146 insertions(+)
> 
> Do we know if this is actually necessary? I remember having a discussion
> with Arnd Bergmann a while ago, and the Linux driver model kind of
> assumes that by the time a device is disabled all outstanding accesses
> will have stopped.
> 
> Do we have a way to determine that this even makes a difference? Can we
> trigger a case where not doing this would cause breakage and see that
> adding this fixes that particular issue?
> 

Most likely it is. The memory controller can still be processing requests
when the peripheral domain is powergated. This would mean the response cannot
be delivered in that case. So we need to be sure there are no outstanding
requests before shutting down the domain.

Cheers,

Peter.

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

* [PATCH V3 02/19] memory: tegra: Add MC flush support
@ 2015-07-17 10:20         ` Peter De Schrijver
  0 siblings, 0 replies; 110+ messages in thread
From: Peter De Schrijver @ 2015-07-17 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 17, 2015 at 11:57:55AM +0200, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
> > The Tegra memory controller implements a flush feature to flush pending
> > accesses and prevent further accesses from occurring. This feature is
> > used when powering down IP blocks to ensure the IP block is in a good
> > state. The flushes are organised by software groups and IP blocks are
> > assigned in hardware to the different software groups. Add helper
> > functions for requesting a handle to an MC flush for a given
> > software group and enabling/disabling the MC flush itself.
> > 
> > This is based upon a change by Vince Hsu <vinceh@nvidia.com>.
> > 
> > Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> > ---
> >  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
> >  drivers/memory/tegra/mc.h |   2 +
> >  include/soc/tegra/mc.h    |  34 ++++++++++++++
> >  3 files changed, 146 insertions(+)
> 
> Do we know if this is actually necessary? I remember having a discussion
> with Arnd Bergmann a while ago, and the Linux driver model kind of
> assumes that by the time a device is disabled all outstanding accesses
> will have stopped.
> 
> Do we have a way to determine that this even makes a difference? Can we
> trigger a case where not doing this would cause breakage and see that
> adding this fixes that particular issue?
> 

Most likely it is. The memory controller can still be processing requests
when the peripheral domain is powergated. This would mean the response cannot
be delivered in that case. So we need to be sure there are no outstanding
requests before shutting down the domain.

Cheers,

Peter.

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

* Re: [PATCH V3 08/19] soc: tegra: pmc: Clean-up PMC helper functions
  2015-07-13 12:39     ` Jon Hunter
@ 2015-07-17 10:25       ` Thierry Reding
  -1 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 10:25 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra, devicetree,
	linux-arm-kernel, linux-pm

[-- Attachment #1: Type: text/plain, Size: 5573 bytes --]

On Mon, Jul 13, 2015 at 01:39:46PM +0100, Jon Hunter wrote:
> The following clean-ups have been made to the PMC code:
> 
> 1. Add a macro for determining the state of a PMC powergate
> 2. Use the readx_poll_timeout() function instead of implementing a local
>    polling loop with a timeout.
> 3. Use a case-statement in the function that removes the powergate clamp
>    instead of multiple if-statements to improve readability.
> 
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  drivers/soc/tegra/pmc.c | 72 ++++++++++++++++++++++++-------------------------
>  1 file changed, 35 insertions(+), 37 deletions(-)
> 
> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
> index c0635bdd4ee3..180d434deec5 100644
> --- a/drivers/soc/tegra/pmc.c
> +++ b/drivers/soc/tegra/pmc.c
> @@ -28,6 +28,7 @@
>  #include <linux/export.h>
>  #include <linux/init.h>
>  #include <linux/io.h>
> +#include <linux/iopoll.h>
>  #include <linux/of.h>
>  #include <linux/of_address.h>
>  #include <linux/platform_device.h>
> @@ -56,6 +57,8 @@
>  #define  PWRGATE_TOGGLE_START		(1 << 8)
>  
>  #define REMOVE_CLAMPING			0x34
> +#define  REMOVE_CLAMPING_VDEC		(1 << 3)
> +#define  REMOVE_CLAMPING_PCIE		(1 << 4)
>  
>  #define PWRGATE_STATUS			0x38
>  
> @@ -101,6 +104,8 @@
>  
>  #define GPU_RG_CNTRL			0x2d4
>  
> +#define PMC_PWRGATE_STATE(val, id)	(!!(val & BIT(id)))

I find double-negations very difficult to read. ((value & BIT(id)) != 0)
is clearer in my opinion. Also I'd suggest status or value as the first
parameter name, for consistency with other parts of the driver.

> +
>  struct tegra_pmc_soc {
>  	unsigned int num_powergates;
>  	const char *const *powergates;
> @@ -177,15 +182,14 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
>   */
>  static int tegra_powergate_set(int id, bool new_state, bool wait)
>  {
> -	unsigned long timeout;
> -	bool status;
>  	int ret = 0;
> +	u32 val;
>  
>  	mutex_lock(&pmc->powergates_lock);
>  
> -	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
> +	val = tegra_pmc_readl(PWRGATE_STATUS);
>  
> -	if (status == new_state) {
> +	if (PMC_PWRGATE_STATE(val, id) == new_state) {
>  		mutex_unlock(&pmc->powergates_lock);
>  		return 0;
>  	}
> @@ -193,17 +197,9 @@ static int tegra_powergate_set(int id, bool new_state, bool wait)
>  	tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
>  
>  	if (wait) {
> -		timeout = jiffies + msecs_to_jiffies(100);
> -		ret = -ETIMEDOUT;
> -
> -		while (time_before(jiffies, timeout)) {
> -			status = !!(tegra_pmc_readl(PWRGATE_STATUS) & BIT(id));
> -			if (status == new_state) {
> -				ret = 0;
> -				break;
> -			}
> -			udelay(10);
> -		}
> +		ret = readx_poll_timeout(tegra_pmc_readl, PWRGATE_STATUS,
> +				val, PMC_PWRGATE_STATE(val, id) == new_state,
> +				10, 100000);
>  	}
>  
>  	mutex_unlock(&pmc->powergates_lock);
> @@ -242,13 +238,10 @@ EXPORT_SYMBOL(tegra_powergate_power_off);
>   */
>  int tegra_powergate_is_powered(int id)
>  {
> -	u32 status;
> -
>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>  		return -EINVAL;
>  
> -	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
> -	return !!status;
> +	return PMC_PWRGATE_STATE(tegra_pmc_readl(PWRGATE_STATUS), id);

I'd prefer to keep the two steps here. As a general rule I try never to
mix reading or writing a register with other code on the same line.

>  }
>  
>  /**
> @@ -257,34 +250,39 @@ int tegra_powergate_is_powered(int id)
>   */
>  int tegra_powergate_remove_clamping(int id)
>  {
> -	u32 mask;
> +	u32 val, reg;

Side note: Please use value instead of val since that's the form used
elsewhere in the driver. Also reg would be more appropriately called
offset or similar because that's what it really is. It would also be
more naturally an unsized type, such as unsigned int. But...

>  
>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>  		return -EINVAL;
>  
>  	/*
> -	 * On Tegra124 and later, the clamps for the GPU are controlled by a
> -	 * separate register (with different semantics).
> +	 * In most cases the bit for removing the IO clamping is the same as
> +	 * the powergate partition ID, however, this is not always the case.
> +	 * Furthermore, on Tegra124 and later, the clamps for the GPU are
> +	 * controlled by a separate register (with different semantics). The
> +	 * following case-statement handles these exceptions.
>  	 */
> -	if (id == TEGRA_POWERGATE_3D) {
> +	val = 1 << id;
> +	reg = REMOVE_CLAMPING;
> +
> +	switch (id) {
> +	case TEGRA_POWERGATE_3D:
>  		if (pmc->soc->has_gpu_clamps) {
> -			tegra_pmc_writel(0, GPU_RG_CNTRL);
> -			return 0;
> +			val = 0;
> +			reg  = GPU_RG_CNTRL;
>  		}
> +		break;
> +	case TEGRA_POWERGATE_VDEC:
> +		val = REMOVE_CLAMPING_VDEC;
> +		break;
> +	case TEGRA_POWERGATE_PCIE:
> +		val = REMOVE_CLAMPING_PCIE;
> +		break;
> +	default:
> +		break;
>  	}
>  
> -	/*
> -	 * Tegra 2 has a bug where PCIE and VDE clamping masks are
> -	 * swapped relatively to the partition ids
> -	 */
> -	if (id == TEGRA_POWERGATE_VDEC)
> -		mask = (1 << TEGRA_POWERGATE_PCIE);
> -	else if (id == TEGRA_POWERGATE_PCIE)
> -		mask = (1 << TEGRA_POWERGATE_VDEC);
> -	else
> -		mask = (1 << id);
> -
> -	tegra_pmc_writel(mask, REMOVE_CLAMPING);
> +	tegra_pmc_writel(val, reg);

... to be honest, I think the previous code was more straightforward, so
I'd prefer if you dropped this particular hunk.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* [PATCH V3 08/19] soc: tegra: pmc: Clean-up PMC helper functions
@ 2015-07-17 10:25       ` Thierry Reding
  0 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 10:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 13, 2015 at 01:39:46PM +0100, Jon Hunter wrote:
> The following clean-ups have been made to the PMC code:
> 
> 1. Add a macro for determining the state of a PMC powergate
> 2. Use the readx_poll_timeout() function instead of implementing a local
>    polling loop with a timeout.
> 3. Use a case-statement in the function that removes the powergate clamp
>    instead of multiple if-statements to improve readability.
> 
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  drivers/soc/tegra/pmc.c | 72 ++++++++++++++++++++++++-------------------------
>  1 file changed, 35 insertions(+), 37 deletions(-)
> 
> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
> index c0635bdd4ee3..180d434deec5 100644
> --- a/drivers/soc/tegra/pmc.c
> +++ b/drivers/soc/tegra/pmc.c
> @@ -28,6 +28,7 @@
>  #include <linux/export.h>
>  #include <linux/init.h>
>  #include <linux/io.h>
> +#include <linux/iopoll.h>
>  #include <linux/of.h>
>  #include <linux/of_address.h>
>  #include <linux/platform_device.h>
> @@ -56,6 +57,8 @@
>  #define  PWRGATE_TOGGLE_START		(1 << 8)
>  
>  #define REMOVE_CLAMPING			0x34
> +#define  REMOVE_CLAMPING_VDEC		(1 << 3)
> +#define  REMOVE_CLAMPING_PCIE		(1 << 4)
>  
>  #define PWRGATE_STATUS			0x38
>  
> @@ -101,6 +104,8 @@
>  
>  #define GPU_RG_CNTRL			0x2d4
>  
> +#define PMC_PWRGATE_STATE(val, id)	(!!(val & BIT(id)))

I find double-negations very difficult to read. ((value & BIT(id)) != 0)
is clearer in my opinion. Also I'd suggest status or value as the first
parameter name, for consistency with other parts of the driver.

> +
>  struct tegra_pmc_soc {
>  	unsigned int num_powergates;
>  	const char *const *powergates;
> @@ -177,15 +182,14 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
>   */
>  static int tegra_powergate_set(int id, bool new_state, bool wait)
>  {
> -	unsigned long timeout;
> -	bool status;
>  	int ret = 0;
> +	u32 val;
>  
>  	mutex_lock(&pmc->powergates_lock);
>  
> -	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
> +	val = tegra_pmc_readl(PWRGATE_STATUS);
>  
> -	if (status == new_state) {
> +	if (PMC_PWRGATE_STATE(val, id) == new_state) {
>  		mutex_unlock(&pmc->powergates_lock);
>  		return 0;
>  	}
> @@ -193,17 +197,9 @@ static int tegra_powergate_set(int id, bool new_state, bool wait)
>  	tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
>  
>  	if (wait) {
> -		timeout = jiffies + msecs_to_jiffies(100);
> -		ret = -ETIMEDOUT;
> -
> -		while (time_before(jiffies, timeout)) {
> -			status = !!(tegra_pmc_readl(PWRGATE_STATUS) & BIT(id));
> -			if (status == new_state) {
> -				ret = 0;
> -				break;
> -			}
> -			udelay(10);
> -		}
> +		ret = readx_poll_timeout(tegra_pmc_readl, PWRGATE_STATUS,
> +				val, PMC_PWRGATE_STATE(val, id) == new_state,
> +				10, 100000);
>  	}
>  
>  	mutex_unlock(&pmc->powergates_lock);
> @@ -242,13 +238,10 @@ EXPORT_SYMBOL(tegra_powergate_power_off);
>   */
>  int tegra_powergate_is_powered(int id)
>  {
> -	u32 status;
> -
>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>  		return -EINVAL;
>  
> -	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
> -	return !!status;
> +	return PMC_PWRGATE_STATE(tegra_pmc_readl(PWRGATE_STATUS), id);

I'd prefer to keep the two steps here. As a general rule I try never to
mix reading or writing a register with other code on the same line.

>  }
>  
>  /**
> @@ -257,34 +250,39 @@ int tegra_powergate_is_powered(int id)
>   */
>  int tegra_powergate_remove_clamping(int id)
>  {
> -	u32 mask;
> +	u32 val, reg;

Side note: Please use value instead of val since that's the form used
elsewhere in the driver. Also reg would be more appropriately called
offset or similar because that's what it really is. It would also be
more naturally an unsized type, such as unsigned int. But...

>  
>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>  		return -EINVAL;
>  
>  	/*
> -	 * On Tegra124 and later, the clamps for the GPU are controlled by a
> -	 * separate register (with different semantics).
> +	 * In most cases the bit for removing the IO clamping is the same as
> +	 * the powergate partition ID, however, this is not always the case.
> +	 * Furthermore, on Tegra124 and later, the clamps for the GPU are
> +	 * controlled by a separate register (with different semantics). The
> +	 * following case-statement handles these exceptions.
>  	 */
> -	if (id == TEGRA_POWERGATE_3D) {
> +	val = 1 << id;
> +	reg = REMOVE_CLAMPING;
> +
> +	switch (id) {
> +	case TEGRA_POWERGATE_3D:
>  		if (pmc->soc->has_gpu_clamps) {
> -			tegra_pmc_writel(0, GPU_RG_CNTRL);
> -			return 0;
> +			val = 0;
> +			reg  = GPU_RG_CNTRL;
>  		}
> +		break;
> +	case TEGRA_POWERGATE_VDEC:
> +		val = REMOVE_CLAMPING_VDEC;
> +		break;
> +	case TEGRA_POWERGATE_PCIE:
> +		val = REMOVE_CLAMPING_PCIE;
> +		break;
> +	default:
> +		break;
>  	}
>  
> -	/*
> -	 * Tegra 2 has a bug where PCIE and VDE clamping masks are
> -	 * swapped relatively to the partition ids
> -	 */
> -	if (id == TEGRA_POWERGATE_VDEC)
> -		mask = (1 << TEGRA_POWERGATE_PCIE);
> -	else if (id == TEGRA_POWERGATE_PCIE)
> -		mask = (1 << TEGRA_POWERGATE_VDEC);
> -	else
> -		mask = (1 << id);
> -
> -	tegra_pmc_writel(mask, REMOVE_CLAMPING);
> +	tegra_pmc_writel(val, reg);

... to be honest, I think the previous code was more straightforward, so
I'd prefer if you dropped this particular hunk.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150717/a6a93632/attachment.sig>

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

* Re: [PATCH V3 10/19] drm/tegra: dc: Prepare for generic PM domains
  2015-07-13 12:39   ` Jon Hunter
@ 2015-07-17 10:41       ` Thierry Reding
  -1 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 10:41 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 2573 bytes --]

On Mon, Jul 13, 2015 at 01:39:48PM +0100, Jon Hunter wrote:
> Add support to the tegra dc driver for generic PM domains. However,
> to ensure backward compatibility with older device tree blobs ensure
> that the driver can work with or without generic PM domains. In order
> to migrate to generic PM domain infrastructure the necessary changes
> are:
> 
> 1. If the "power-domains" property is present in the DT device node then
>    generic PM domains is supported and pm_runtime_enable() should be
>    called for the device. Furthermore, the enabling and disabling of the
>    power-domain is handled via calling pm_runtime_get/put, respectively.

The device could be PM runtime enabled even if no power-domains property
is set. Couldn't we check something more direct, like for example if the
dev->pm_domain is non-NULL?

Perhaps it'd be worth converting the driver to use runtime PM first, and
move all the powergate and clock handling into suspend/resume functions,
and then we can conditionalize whether or not we call the legacy API iff
dev->pm_domain == NULL?

> 2. To ensure that clocks are managed consistently when generic PM domains
>    are used and are not used, drivers should be migrated to use the
>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>    functions instead of the current tegra_powergate_sequence_power_up()
>    and tegra_powergate_power_off(). The purpose of the
>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>    APIs is to mimick the behaviour of the tegra generic power-domain code,
>    such that if generic power domains are not supported the functionality
>    is the same.
> 
> 3. The main difference between the tegra_powergate_sequence_power_up() API
>    and the tegra_powergate_power_on_legacy() is that the clock used to
>    enable the powergate is not kept enabled when using the
>    tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
>    the clocks they need after calling tegra_powergate_power_on_legacy()
>    and disable these clocks before calling
>    tegra_powergate_power_off_legacy().

This seems like it should go into the previous patch. I'm not sure I
understand why this is necessary. Wouldn't it be easier to update the
drivers to properly cope with this? We'll need to move them to runtime
PM at some point anyway, so if we do that first, we should be able to
hide all these details within the driver's suspend/resume functions
but without the need for the API churn here.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* [PATCH V3 10/19] drm/tegra: dc: Prepare for generic PM domains
@ 2015-07-17 10:41       ` Thierry Reding
  0 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 10:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 13, 2015 at 01:39:48PM +0100, Jon Hunter wrote:
> Add support to the tegra dc driver for generic PM domains. However,
> to ensure backward compatibility with older device tree blobs ensure
> that the driver can work with or without generic PM domains. In order
> to migrate to generic PM domain infrastructure the necessary changes
> are:
> 
> 1. If the "power-domains" property is present in the DT device node then
>    generic PM domains is supported and pm_runtime_enable() should be
>    called for the device. Furthermore, the enabling and disabling of the
>    power-domain is handled via calling pm_runtime_get/put, respectively.

The device could be PM runtime enabled even if no power-domains property
is set. Couldn't we check something more direct, like for example if the
dev->pm_domain is non-NULL?

Perhaps it'd be worth converting the driver to use runtime PM first, and
move all the powergate and clock handling into suspend/resume functions,
and then we can conditionalize whether or not we call the legacy API iff
dev->pm_domain == NULL?

> 2. To ensure that clocks are managed consistently when generic PM domains
>    are used and are not used, drivers should be migrated to use the
>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>    functions instead of the current tegra_powergate_sequence_power_up()
>    and tegra_powergate_power_off(). The purpose of the
>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>    APIs is to mimick the behaviour of the tegra generic power-domain code,
>    such that if generic power domains are not supported the functionality
>    is the same.
> 
> 3. The main difference between the tegra_powergate_sequence_power_up() API
>    and the tegra_powergate_power_on_legacy() is that the clock used to
>    enable the powergate is not kept enabled when using the
>    tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
>    the clocks they need after calling tegra_powergate_power_on_legacy()
>    and disable these clocks before calling
>    tegra_powergate_power_off_legacy().

This seems like it should go into the previous patch. I'm not sure I
understand why this is necessary. Wouldn't it be easier to update the
drivers to properly cope with this? We'll need to move them to runtime
PM at some point anyway, so if we do that first, we should be able to
hide all these details within the driver's suspend/resume functions
but without the need for the API churn here.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150717/0275a247/attachment.sig>

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

* Re: [PATCH V3 11/19] PCI: tegra: Add support for generic PM domains
  2015-07-13 12:39   ` Jon Hunter
@ 2015-07-17 10:45     ` Thierry Reding
  -1 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 10:45 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra, devicetree,
	linux-arm-kernel, linux-pm

[-- Attachment #1: Type: text/plain, Size: 5883 bytes --]

On Mon, Jul 13, 2015 at 01:39:49PM +0100, Jon Hunter wrote:
> Add support to the tegra PCI driver for generic PM domains. However,
> to ensure backward compatibility with older device tree blobs ensure
> that the driver can work with or without generic PM domains. In order
> to migrate to generic PM domain infrastructure the necessary changes
> are:
> 
> 1. If the "power-domains" property is present in the DT device node then
>    generic PM domains is supported and pm_runtime_enable() should be
>    called for the device. Furthermore, the enabling and disabling of the
>    power-domain is handled via calling pm_runtime_get/put, respectively.
> 
> 2. To ensure that clocks are managed consistently when generic PM domains
>    are used and are not used, drivers should be migrated to use the
>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>    functions instead of the current tegra_powergate_sequence_power_up()
>    and tegra_powergate_power_off(). The purpose of the
>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>    APIs is to mimick the behaviour of the tegra generic power-domain code,
>    such that if generic power domains are not supported the functionality
>    is the same.
> 
> 3. The main difference between the tegra_powergate_sequence_power_up() API
>    and the tegra_powergate_power_on_legacy() is that the clock used to
>    enable the powergate is not kept enabled when using the
>    tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
>    the clocks they need after calling tegra_powergate_power_on_legacy()
>    and disable these clocks before calling
>    tegra_powergate_power_off_legacy().

This is the same comment as in the DRM patch, and it applies to all
devices that use powergating, so it should move into the preparatory
patch rather than be repeated in all patches.

> 
> The helper functions for handling the powering on and off of the PCI
> controller have been updated to support generic PM domains. The
> tegra_pcie_power_off() was missing code to disable the clocks enabled in
> the tegra_pcie_power_on() function and so this has been added.
> 
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  drivers/pci/host/pci-tegra.c | 49 +++++++++++++++++++++++++++++++++-----------
>  1 file changed, 37 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
> index 10c05718dbfd..acd1f311eee5 100644
> --- a/drivers/pci/host/pci-tegra.c
> +++ b/drivers/pci/host/pci-tegra.c
> @@ -40,6 +40,7 @@
>  #include <linux/pci.h>
>  #include <linux/phy/phy.h>
>  #include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
>  #include <linux/reset.h>
>  #include <linux/sizes.h>
>  #include <linux/slab.h>
> @@ -908,19 +909,32 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
>  
>  static void tegra_pcie_power_off(struct tegra_pcie *pcie)
>  {
> +	const struct tegra_pcie_soc_data *soc = pcie->soc_data;
>  	int err;
>  
> -	/* TODO: disable and unprepare clocks? */
> -
>  	err = phy_power_off(pcie->phy);
>  	if (err < 0)
>  		dev_warn(pcie->dev, "failed to power off PHY: %d\n", err);
>  
>  	reset_control_assert(pcie->pcie_xrst);
>  	reset_control_assert(pcie->afi_rst);
> -	reset_control_assert(pcie->pex_rst);
>  
> -	tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
> +	clk_disable_unprepare(pcie->pll_e);
> +	if (soc->has_cml_clk)
> +		clk_disable_unprepare(pcie->cml_clk);
> +	clk_disable_unprepare(pcie->afi_clk);
> +	clk_disable_unprepare(pcie->pex_clk);
> +
> +	if (pm_runtime_enabled(pcie->dev)) {
> +		err = pm_runtime_put_sync(pcie->dev);
> +	} else {
> +		err = tegra_powergate_power_off_legacy(TEGRA_POWERGATE_PCIE,
> +						       pcie->pex_clk,
> +						       pcie->pex_rst);
> +	}
> +
> +	if (err < 0)
> +		dev_warn(pcie->dev, "powergate power-down failed: %d\n", err);
>  
>  	err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
>  	if (err < 0)
> @@ -934,20 +948,28 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
>  
>  	reset_control_assert(pcie->pcie_xrst);
>  	reset_control_assert(pcie->afi_rst);
> -	reset_control_assert(pcie->pex_rst);
> -
> -	tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
>  
>  	/* enable regulators */
>  	err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies);
>  	if (err < 0)
>  		dev_err(pcie->dev, "failed to enable regulators: %d\n", err);
>  
> -	err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
> -						pcie->pex_clk,
> -						pcie->pex_rst);
> -	if (err) {
> -		dev_err(pcie->dev, "powerup sequence failed: %d\n", err);
> +	if (pm_runtime_enabled(pcie->dev)) {
> +		err = pm_runtime_get_sync(pcie->dev);
> +	} else {
> +		err = tegra_powergate_power_on_legacy(TEGRA_POWERGATE_PCIE,
> +						      pcie->pex_clk,
> +						      pcie->pex_rst);
> +	}
> +
> +	if (err < 0) {
> +		dev_err(pcie->dev, "powergate power-up failed: %d\n", err);
> +		return err;
> +	}
> +
> +	err = clk_prepare_enable(pcie->pex_clk);
> +	if (err < 0) {
> +		dev_err(pcie->dev, "failed to enable PEX clock: %d\n", err);
>  		return err;
>  	}
>  

Couldn't we simply move the above code into suspend/resume functions and
then call pm_runtime_get() and pm_runtime_put() instead of
tegra_pcie_power_on() and tegra_pcie_power_off()?

> @@ -2001,6 +2023,9 @@ static int tegra_pcie_probe(struct platform_device *pdev)
>  
>  	pcibios_min_mem = 0;
>  
> +	if (of_property_read_bool(pdev->dev.of_node, "power-domains"))
> +		pm_runtime_enable(&pdev->dev);

Then of course we'd have to call pm_runtime_enable() irrespective of the
property and check for the presence of power domain support via another
method (like the dev->pm_domain field).

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* [PATCH V3 11/19] PCI: tegra: Add support for generic PM domains
@ 2015-07-17 10:45     ` Thierry Reding
  0 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 13, 2015 at 01:39:49PM +0100, Jon Hunter wrote:
> Add support to the tegra PCI driver for generic PM domains. However,
> to ensure backward compatibility with older device tree blobs ensure
> that the driver can work with or without generic PM domains. In order
> to migrate to generic PM domain infrastructure the necessary changes
> are:
> 
> 1. If the "power-domains" property is present in the DT device node then
>    generic PM domains is supported and pm_runtime_enable() should be
>    called for the device. Furthermore, the enabling and disabling of the
>    power-domain is handled via calling pm_runtime_get/put, respectively.
> 
> 2. To ensure that clocks are managed consistently when generic PM domains
>    are used and are not used, drivers should be migrated to use the
>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>    functions instead of the current tegra_powergate_sequence_power_up()
>    and tegra_powergate_power_off(). The purpose of the
>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>    APIs is to mimick the behaviour of the tegra generic power-domain code,
>    such that if generic power domains are not supported the functionality
>    is the same.
> 
> 3. The main difference between the tegra_powergate_sequence_power_up() API
>    and the tegra_powergate_power_on_legacy() is that the clock used to
>    enable the powergate is not kept enabled when using the
>    tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
>    the clocks they need after calling tegra_powergate_power_on_legacy()
>    and disable these clocks before calling
>    tegra_powergate_power_off_legacy().

This is the same comment as in the DRM patch, and it applies to all
devices that use powergating, so it should move into the preparatory
patch rather than be repeated in all patches.

> 
> The helper functions for handling the powering on and off of the PCI
> controller have been updated to support generic PM domains. The
> tegra_pcie_power_off() was missing code to disable the clocks enabled in
> the tegra_pcie_power_on() function and so this has been added.
> 
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  drivers/pci/host/pci-tegra.c | 49 +++++++++++++++++++++++++++++++++-----------
>  1 file changed, 37 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
> index 10c05718dbfd..acd1f311eee5 100644
> --- a/drivers/pci/host/pci-tegra.c
> +++ b/drivers/pci/host/pci-tegra.c
> @@ -40,6 +40,7 @@
>  #include <linux/pci.h>
>  #include <linux/phy/phy.h>
>  #include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
>  #include <linux/reset.h>
>  #include <linux/sizes.h>
>  #include <linux/slab.h>
> @@ -908,19 +909,32 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
>  
>  static void tegra_pcie_power_off(struct tegra_pcie *pcie)
>  {
> +	const struct tegra_pcie_soc_data *soc = pcie->soc_data;
>  	int err;
>  
> -	/* TODO: disable and unprepare clocks? */
> -
>  	err = phy_power_off(pcie->phy);
>  	if (err < 0)
>  		dev_warn(pcie->dev, "failed to power off PHY: %d\n", err);
>  
>  	reset_control_assert(pcie->pcie_xrst);
>  	reset_control_assert(pcie->afi_rst);
> -	reset_control_assert(pcie->pex_rst);
>  
> -	tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
> +	clk_disable_unprepare(pcie->pll_e);
> +	if (soc->has_cml_clk)
> +		clk_disable_unprepare(pcie->cml_clk);
> +	clk_disable_unprepare(pcie->afi_clk);
> +	clk_disable_unprepare(pcie->pex_clk);
> +
> +	if (pm_runtime_enabled(pcie->dev)) {
> +		err = pm_runtime_put_sync(pcie->dev);
> +	} else {
> +		err = tegra_powergate_power_off_legacy(TEGRA_POWERGATE_PCIE,
> +						       pcie->pex_clk,
> +						       pcie->pex_rst);
> +	}
> +
> +	if (err < 0)
> +		dev_warn(pcie->dev, "powergate power-down failed: %d\n", err);
>  
>  	err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
>  	if (err < 0)
> @@ -934,20 +948,28 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
>  
>  	reset_control_assert(pcie->pcie_xrst);
>  	reset_control_assert(pcie->afi_rst);
> -	reset_control_assert(pcie->pex_rst);
> -
> -	tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
>  
>  	/* enable regulators */
>  	err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies);
>  	if (err < 0)
>  		dev_err(pcie->dev, "failed to enable regulators: %d\n", err);
>  
> -	err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
> -						pcie->pex_clk,
> -						pcie->pex_rst);
> -	if (err) {
> -		dev_err(pcie->dev, "powerup sequence failed: %d\n", err);
> +	if (pm_runtime_enabled(pcie->dev)) {
> +		err = pm_runtime_get_sync(pcie->dev);
> +	} else {
> +		err = tegra_powergate_power_on_legacy(TEGRA_POWERGATE_PCIE,
> +						      pcie->pex_clk,
> +						      pcie->pex_rst);
> +	}
> +
> +	if (err < 0) {
> +		dev_err(pcie->dev, "powergate power-up failed: %d\n", err);
> +		return err;
> +	}
> +
> +	err = clk_prepare_enable(pcie->pex_clk);
> +	if (err < 0) {
> +		dev_err(pcie->dev, "failed to enable PEX clock: %d\n", err);
>  		return err;
>  	}
>  

Couldn't we simply move the above code into suspend/resume functions and
then call pm_runtime_get() and pm_runtime_put() instead of
tegra_pcie_power_on() and tegra_pcie_power_off()?

> @@ -2001,6 +2023,9 @@ static int tegra_pcie_probe(struct platform_device *pdev)
>  
>  	pcibios_min_mem = 0;
>  
> +	if (of_property_read_bool(pdev->dev.of_node, "power-domains"))
> +		pm_runtime_enable(&pdev->dev);

Then of course we'd have to call pm_runtime_enable() irrespective of the
property and check for the presence of power domain support via another
method (like the dev->pm_domain field).

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150717/baca9294/attachment.sig>

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

* Re: [PATCH V3 15/19] soc: tegra: pmc: Add generic PM domain support
  2015-07-13 12:39     ` Jon Hunter
@ 2015-07-17 11:29         ` Thierry Reding
  -1 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 11:29 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 22000 bytes --]

On Mon, Jul 13, 2015 at 01:39:53PM +0100, Jon Hunter wrote:
> Adds generic PM support to the PMC driver where the PM domains are
> populated from device-tree and the PM domain consumer devices are
> bound to their relevant PM domains via device-tree as well.
> 
> Update the tegra_powergate_power_on_legacy/off_legacy() APIs so that
> internally they call the same tegra_powergate_xxx functions that are
> used by the tegra generic power domain code for consistency.
> 
> This is based upon work by Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> and Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>.
> 
> Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
>  drivers/soc/tegra/pmc.c                     | 545 +++++++++++++++++++++++++++-
>  include/dt-bindings/power/tegra-powergate.h |  42 +++
>  include/soc/tegra/pmc.h                     |  52 +--
>  3 files changed, 580 insertions(+), 59 deletions(-)
>  create mode 100644 include/dt-bindings/power/tegra-powergate.h
> 
> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
> index 934653785bb7..4de92a9dae65 100644
> --- a/drivers/soc/tegra/pmc.c
> +++ b/drivers/soc/tegra/pmc.c
> @@ -19,8 +19,11 @@
>  
>  #define pr_fmt(fmt) "tegra-pmc: " fmt
>  
> +#include <dt-bindings/power/tegra-powergate.h>
> +
>  #include <linux/kernel.h>
>  #include <linux/clk.h>
> +#include <linux/clk-provider.h>

Why are we now providing clocks?

>  #include <linux/clk/tegra.h>
>  #include <linux/debugfs.h>
>  #include <linux/delay.h>
> @@ -30,17 +33,24 @@
>  #include <linux/io.h>
>  #include <linux/iopoll.h>
>  #include <linux/of.h>
> +#include <linux/of_platform.h>
>  #include <linux/of_address.h>
>  #include <linux/platform_device.h>
> +#include <linux/pm_domain.h>
>  #include <linux/reboot.h>
> +#include <linux/regulator/consumer.h>
>  #include <linux/reset.h>
> +#include <linux/sched.h>

What do we need this for?

>  #include <linux/seq_file.h>
>  #include <linux/spinlock.h>
>  
>  #include <soc/tegra/common.h>
>  #include <soc/tegra/fuse.h>
> +#include <soc/tegra/mc.h>
>  #include <soc/tegra/pmc.h>
>  
> +#define PMC_POWERGATE_ARRAY_MAX		10

There should be no need for this.

> +
>  #define PMC_CNTRL			0x0
>  #define  PMC_CNTRL_SYSCLK_POLARITY	(1 << 10)  /* sys clk polarity */
>  #define  PMC_CNTRL_SYSCLK_OE		(1 << 11)  /* system clock enable */
> @@ -106,6 +116,22 @@
>  
>  #define PMC_PWRGATE_STATE(val, id)	(!!(val & BIT(id)))
>  
> +struct tegra_powergate {
> +	struct generic_pm_domain genpd;
> +	struct tegra_pmc *pmc;
> +	struct tegra_mc *mc;
> +	unsigned int id;
> +	struct list_head node;
> +	struct device_node *of_node;
> +	struct regulator *vdd;
> +	struct clk **clks;
> +	struct reset_control **resets;
> +	const struct tegra_mc_flush **flushes;
> +	u32 num_clks;
> +	u32 num_resets;
> +	u32 num_flushes;

These should be unsigned int, and please group them with the arrays that
they define the sizes of.

> +};
> +
>  struct tegra_pmc_soc {
>  	unsigned int num_powergates;
>  	const char *const *powergates;
> @@ -118,8 +144,10 @@ struct tegra_pmc_soc {
>  
>  /**
>   * struct tegra_pmc - NVIDIA Tegra PMC
> + * @dev: pointer to parent device
>   * @base: pointer to I/O remapped register region
>   * @clk: pointer to pclk clock
> + * @soc: SoC-specific data

This could be a separate patch because it isn't related to the power
domain work.

>   * @rate: currently configured rate of pclk
>   * @suspend_mode: lowest suspend mode available
>   * @cpu_good_time: CPU power good time (in microseconds)
> @@ -133,6 +161,7 @@ struct tegra_pmc_soc {
>   * @cpu_pwr_good_en: CPU power good signal is enabled
>   * @lp0_vec_phys: physical base address of the LP0 warm boot code
>   * @lp0_vec_size: size of the LP0 warm boot code
> + * @powergates_list: list of power gates
>   * @powergates_lock: mutex for power gate register access
>   */
>  struct tegra_pmc {
> @@ -157,6 +186,7 @@ struct tegra_pmc {
>  	u32 lp0_vec_phys;
>  	u32 lp0_vec_size;
>  
> +	struct list_head powergates_list;
>  	struct mutex powergates_lock;
>  };
>  
> @@ -165,6 +195,12 @@ static struct tegra_pmc *pmc = &(struct tegra_pmc) {
>  	.suspend_mode = TEGRA_SUSPEND_NONE,
>  };
>  
> +static inline struct tegra_powergate *
> +to_powergate(struct generic_pm_domain *domain)
> +{
> +	return container_of(domain, struct tegra_powergate, genpd);
> +}
> +
>  static u32 tegra_pmc_readl(unsigned long offset)
>  {
>  	return readl(pmc->base + offset);
> @@ -175,6 +211,37 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
>  	writel(value, pmc->base + offset);
>  }
>  
> +static int tegra_powergate_get_regulator(struct tegra_powergate *powergate)
> +{
> +	struct platform_device *pdev;
> +
> +	if (powergate->id != TEGRA_POWERGATE_EXT)
> +		return -EINVAL;
> +
> +	pdev = of_find_device_by_node(powergate->of_node);
> +	if (!pdev)
> +		return -EINVAL;
> +
> +	powergate->vdd = devm_regulator_get_optional(&pdev->dev, "vdd");
> +	if (IS_ERR(powergate->vdd))
> +		return PTR_ERR(powergate->vdd);
> +
> +	return 0;
> +}
> +
> +static int tegra_powergate_enable_regulator(struct tegra_powergate *powergate)
> +{
> +	int ret = 0;
> +
> +	if (IS_ERR_OR_NULL(powergate->vdd))
> +		ret = tegra_powergate_get_regulator(powergate);

Why don't you get the regulator at the time when the powergate is
created? That way you still have a chance of deferring probe to get
another chance at getting it. If you don't do that, then if ever you
happen to want to enable the powergate before the regulator is ready
you'll error out and your consumer will have to deal with that.

> +
> +	if (!ret)
> +		ret = regulator_enable(powergate->vdd);
> +
> +	return ret;
> +}
> +
>  /**
>   * tegra_powergate_set() - set the state of a partition
>   * @id: partition ID
> @@ -207,6 +274,215 @@ static int tegra_powergate_set(int id, bool new_state, bool wait)
>  	return ret;
>  }
>  
> +static int tegra_powergate_enable(struct tegra_powergate *powergate,
> +				  bool enable)
> +{
> +	if (powergate->id != TEGRA_POWERGATE_EXT)
> +		return tegra_powergate_set(powergate->id, enable, true);
> +
> +	if (enable)
> +		return tegra_powergate_enable_regulator(powergate);
> +	else
> +		return regulator_disable(powergate->vdd);
> +}
> +
> +static bool tegra_powergate_is_supported(int id)
> +{
> +	switch (id) {
> +	case TEGRA_POWERGATE_CPU:
> +	case TEGRA_POWERGATE_CPU1:
> +	case TEGRA_POWERGATE_CPU2:
> +	case TEGRA_POWERGATE_CPU3:
> +	case TEGRA_POWERGATE_CPU0:
> +	case TEGRA_POWERGATE_C0NC:
> +	case TEGRA_POWERGATE_IRAM:
> +		return false;
> +	default:
> +		return true;
> +	}
> +}
> +
> +static bool _tegra_powergate_is_powered(struct tegra_powergate *powergate)
> +{
> +	if (powergate->id != TEGRA_POWERGATE_EXT)
> +		return tegra_powergate_is_powered(powergate->id);
> +
> +	if (IS_ERR(powergate->vdd))
> +		return false;
> +	else
> +		return regulator_is_enabled(powergate->vdd);
> +}
> +
> +static void tegra_powergate_disable_clocks(struct tegra_powergate *powergate)
> +{
> +	int i;

Should match the type of powergate->num_clks, that is unsigned int.

> +
> +	for (i = 0; i < powergate->num_clks; i++)
> +		clk_disable_unprepare(powergate->clks[i]);
> +}
> +
> +static int tegra_powergate_enable_clocks(struct tegra_powergate *powergate)
> +{
> +	int err, i;

Same here.

> +
> +	for (i = 0; i < powergate->num_clks; i++) {
> +		err = clk_prepare_enable(powergate->clks[i]);
> +		if (err)
> +			goto out;
> +	}
> +
> +	return 0;
> +
> +out:
> +	while (i--)
> +		clk_disable_unprepare(powergate->clks[i]);
> +
> +	return err;
> +}
> +
> +static int tegra_powergate_mc_flush(struct tegra_powergate *powergate,
> +				    bool enable)
> +{
> +	int i, err;

And here.

> +
> +	for (i = 0; i < powergate->num_flushes; i++) {
> +		err = tegra_mc_flush(powergate->mc, powergate->flushes[i],
> +				     enable);
> +		if (err)
> +			return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static int tegra_powergate_reset_assert(struct tegra_powergate *powergate)
> +{
> +	int err, i;

As well as here.

> +
> +	for (i = 0; i < powergate->num_resets; i++) {
> +		err = reset_control_assert(powergate->resets[i]);
> +		if (err)
> +			return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static int tegra_powergate_reset_deassert(struct tegra_powergate *powergate)
> +{
> +	int err, i;
> +
> +	for (i = 0; i < powergate->num_resets; i++) {
> +		err = reset_control_deassert(powergate->resets[i]);
> +		if (err)
> +			return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static int tegra_powergate_seq_power_up(struct tegra_powergate *powergate)

What does the _seq buy us here? Why not simply call this
tegra_powergate_power_up()?

> +{
> +	int err;
> +
> +	err = tegra_powergate_reset_assert(powergate);
> +	if (err)
> +		goto out;
> +	udelay(10);

There should be a space between the above two lines. Also, is there a
reason why we can't use usleep_range() here?

> +
> +	err = tegra_powergate_enable(powergate, true);
> +	if (err < 0)
> +		goto out;
> +	udelay(10);
> +
> +	err = tegra_powergate_enable_clocks(powergate);
> +	if (err)
> +		goto out;
> +	udelay(10);
> +
> +	tegra_powergate_remove_clamping(powergate->id);
> +
> +	udelay(10);
> +
> +	err = tegra_powergate_reset_deassert(powergate);
> +	if (err)
> +		goto out;
> +	udelay(10);
> +
> +	err = tegra_powergate_mc_flush(powergate, false);
> +	if (err)
> +		goto out;

I mentioned this before, but I think it'd be good to split out the flush
changes from this patch, so that we can test the series without the
flushing to see if it's at all necessary.

> +static int tegra_genpd_power_on(struct generic_pm_domain *domain)
> +{
> +	struct tegra_powergate *powergate = to_powergate(domain);
> +	struct tegra_pmc *pmc = powergate->pmc;
> +	int err;
> +
> +	err = tegra_powergate_seq_power_up(powergate);
> +
> +	if (err)

There should be no blank line between the above.

> +		dev_err(pmc->dev, "Failed to turn on PM Domain (%d)\n", err);

For consistency with other error messages, "Failed" should be "failed".
And "Domain" should be "domain". Also typically the error is separated
from the message with a colon: "failed ... domain: %d\n".

> -int tegra_powergate_power_off_legacy(int id, struct clk *clk,
> -				     struct reset_control *rst)
> +int tegra_powergate_power_on_legacy(int id, struct clk *clk,
> +				    struct reset_control *rst)
>  {
> -	int ret;
> +	struct tegra_powergate powergate;
>  
> -	ret = clk_prepare_enable(clk);
> -	if (ret)
> -		return ret;
> +	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
> +		return -EINVAL;
>  
> -	usleep_range(10, 20);
> +	powergate.id = id;
> +	powergate.clks = &clk;
> +	powergate.resets = &rst;
> +	powergate.num_clks = 1;
> +	powergate.num_resets = 1;
> +	powergate.num_flushes = 0;
>  
> -	reset_control_assert(rst);
> +	return tegra_powergate_seq_power_up(&powergate);
> +}
> +EXPORT_SYMBOL(tegra_powergate_power_on_legacy);
>  
> -	usleep_range(10, 20);
> +int tegra_powergate_power_off_legacy(int id, struct clk *clk,
> +				     struct reset_control *rst)
> +{
> +	struct tegra_powergate powergate;
>  
> -	clk_disable_unprepare(clk);
> +	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
> +		return -EINVAL;
>  
> -	usleep_range(10, 20);
> +	powergate.id = id;
> +	powergate.clks = &clk;
> +	powergate.resets = &rst;
> +	powergate.num_clks = 1;
> +	powergate.num_resets = 1;
> +	powergate.num_flushes = 0;
>  
> -	return tegra_powergate_power_off(id);
> +	return tegra_powergate_seq_power_down(&powergate);
>  }
>  EXPORT_SYMBOL(tegra_powergate_power_off_legacy);

It looks as if you decided to reorder the two functions here, but that
makes the diff very hard to read.

>  
> @@ -493,6 +786,228 @@ static int tegra_powergate_debugfs_init(void)
>  	return 0;
>  }
>  
> +static int tegra_powergate_of_get_clks(struct device *dev,
> +				       struct tegra_powergate *powergate)
> +{
> +	struct clk *clks[PMC_POWERGATE_ARRAY_MAX];
> +	int i = 0;

unsigned int, and no need to initialize here.

> +
> +	for (i = 0; i < PMC_POWERGATE_ARRAY_MAX; i++) {
> +		clks[i] = of_clk_get(powergate->of_node, i);
> +		if (IS_ERR(clks[i])) {
> +			if (PTR_ERR(clks[i]) != -ENOENT)
> +				return PTR_ERR(clks[i]);
> +			break;
> +		}
> +	}

Can we perhaps prepend this with a loop that determines the number of
clocks specified in DT? That way we can avoid the statically sized array
altogether.

Perhaps to make it a little easier to read, keep a local variable clk
and assign to the array only when it's been sanitized:

	for (...) {
		clk = of_clk_get(...);
		if (IS_ERR(clk)) {
			...
		}

		powergate->clks[i] = clk;
	}

> +
> +	if (PTR_ERR(clks[i]) != -ENOENT) {
> +		dev_err(dev, "unsupported number of clocks defined\n");
> +		return -EINVAL;
> +	}
> +
> +	powergate->clks = devm_kcalloc(dev, i, sizeof(*clks), GFP_KERNEL);
> +	if (!powergate->clks)
> +		return -ENOMEM;
> +
> +	memcpy(powergate->clks, clks, sizeof(*clks) * i);
> +	powergate->num_clks = i;
> +
> +	return 0;
> +}

Don't you need to put the clocks that you've obtained above to avoid
leaking them?

> +
> +static int tegra_powergate_of_get_resets(struct device *dev,
> +					 struct tegra_powergate *powergate)
> +{
> +	struct reset_control *rsts[PMC_POWERGATE_ARRAY_MAX];
> +	int i = 0;
> +
> +	for (i = 0; i < PMC_POWERGATE_ARRAY_MAX; i++) {
> +		rsts[i] = of_reset_control_get_by_index(powergate->of_node, i);
> +		if (IS_ERR(rsts[i])) {
> +			if (PTR_ERR(rsts[i]) != -ENOENT)
> +				return PTR_ERR(rsts[i]);
> +			break;
> +		}
> +	}
> +
> +	if (PTR_ERR(rsts[i]) != -ENOENT) {
> +		dev_err(dev, "unsupported number of resets defined\n");
> +		return -EINVAL;
> +	}
> +
> +	powergate->resets = devm_kcalloc(dev, i, sizeof(*rsts), GFP_KERNEL);
> +	if (!powergate->resets)
> +		return -ENOMEM;
> +
> +	memcpy(powergate->resets, rsts, sizeof(*rsts) * i);
> +	powergate->num_resets = i;
> +
> +	return 0;
> +}

Same comments as for clocks.

> +static int tegra_powergate_of_get_mc_flush(struct device *dev,
> +					   struct tegra_powergate *powergate)
> +{
> +	struct platform_device *pdev;
> +	struct of_phandle_args args;
> +	int i = 0, ret = 0;
> +
> +	ret = of_parse_phandle_with_args(dev->of_node, "nvidia-swgroups",
> +					"#nvidia,swgroup-cells", 0, &args);
> +	if (ret < 0) {
> +		/*
> +		 * The nvidia-swgroups property is
> +		 * optional and so if missing simply return.
> +		 */
> +		if (ret == -ENOENT)
> +			return 0;
> +
> +		dev_err(dev, "nvidia-swgroups property invalid for %s (%d)\n",
> +			powergate->of_node->name, ret);
> +		return ret;
> +	}
> +
> +	powergate->flushes = devm_kcalloc(dev, args.args_count,
> +					  sizeof(powergate->flushes),
> +					  GFP_KERNEL);
> +	if (!powergate->flushes) {
> +		dev_err(dev, "failed to allocate memory for powergate flush\n");
> +		return -ENOMEM;
> +	}
> +
> +	pdev = of_find_device_by_node(args.np);
> +	if (!pdev)
> +		return -ENODEV;
> +
> +	powergate->mc = platform_get_drvdata(pdev);
> +	if (!powergate->mc)
> +		return -EINVAL;
> +
> +	for (i = 0; i < args.args_count; i++) {
> +		powergate->flushes[i] = tegra_mc_flush_get(powergate->mc,
> +							   args.args[i]);

Urgs... might be better to make this a struct device *-based API, so
that you don't have to reach into the private structures of the MC
driver. Well, it'd technically have to be struct device_node *-based
because we don't have a struct device * for the power domains. Perhaps
something like this:

	const struct tegra_mc_flush *tegra_mc_flush_get(struct device_node *np,
							unsigned int index);

Then the MC driver can access its own internals, rather than the other
way around.

> +		if (!powergate->flushes[i])
> +			return -EINVAL;
> +	}
> +
> +	powergate->num_flushes = args.args_count;
> +
> +	return 0;
> +}
> +
> +static int tegra_powergate_init_powerdomain(struct tegra_pmc *pmc,
> +					    struct device_node *np,
> +					    struct tegra_powergate *pg)

This is slightly confusing. Why not something like this:

	struct tegra_powergate *tegra_powergate_create(struct tegra_pmc *pmc,
						       struct device_node *np)

?

> +{
> +	bool off;
> +	int err;
> +
> +	err = of_property_read_u32(np, "nvidia,powergate", &pg->id);
> +	if (err) {
> +		dev_err(pmc->dev, "no powergate ID for domain\n");
> +		goto err;
> +	}
> +
> +	if (tegra_powergate_is_supported(pg->id) == false) {
> +		dev_warn(pmc->dev, "%s not currently supported by genpd\n",
> +			 np->name);
> +		return -EINVAL;
> +	}
> +
> +	if (pg->id == TEGRA_POWERGATE_EXT) {
> +		err = tegra_powergate_get_regulator(pg);
> +		if (err) {
> +			/*
> +			 * The regulator might not be ready yet, so just
> +			 * give a warning instead of failing the whole
> +			 * init.
> +			 */
> +			dev_warn(pmc->dev, "couldn't locate regulator\n");

Why won't regular probe deferral work?

> +		}
> +	}
> +
> +	pg->of_node = np;
> +	pg->genpd.name = np->name;
> +	pg->genpd.power_off = tegra_genpd_power_off;
> +	pg->genpd.power_on = tegra_genpd_power_on;
> +	pg->pmc = pmc;
> +
> +	err = tegra_powergate_of_get_clks(pmc->dev, pg);
> +	if (err)
> +		goto err;
> +
> +	err = tegra_powergate_of_get_resets(pmc->dev, pg);
> +	if (err)
> +		goto err;
> +
> +	err = tegra_powergate_of_get_mc_flush(pmc->dev, pg);
> +	if (err)
> +		goto err;
> +
> +	list_add_tail(&pg->node, &pmc->powergates_list);
> +
> +	if (!IS_ERR(pg->vdd) || pg->id != TEGRA_POWERGATE_EXT)
> +		tegra_genpd_power_off(&pg->genpd);
> +
> +	off = !_tegra_powergate_is_powered(pg);
> +
> +	pm_genpd_init(&pg->genpd, NULL, off);
> +
> +	dev_info(pmc->dev, "added power domain %s\n", np->name);
> +
> +	return 0;
> +
> +err:
> +	dev_err(pmc->dev, "failed to add power domain for node %s\n",
> +		np->name);
> +	return err;

This doesn't clean up any of the requested resources on failure.

> +}
> +
> +static int tegra_powergate_add_powerdomains(struct tegra_pmc *pmc,
> +					    struct device_node *parent,
> +					    struct generic_pm_domain *pd_parent)
> +{
> +	struct device_node *np;
> +	int ret;

Please use err consistently as the name for error codes. This patch uses
a mixture of both.

> +
> +	for_each_child_of_node(parent, np) {
> +		struct tegra_powergate *pg;
> +
> +		pg = devm_kzalloc(pmc->dev, sizeof(*pg), GFP_KERNEL);
> +		if (!pg)
> +			return -ENOMEM;
> +
> +		ret = tegra_powergate_init_powerdomain(pmc, np, pg);
> +		if (ret)
> +			return ret;
> +
> +		if (pd_parent)
> +			pm_genpd_add_subdomain(pd_parent, &pg->genpd);
> +
> +		of_genpd_add_provider_simple(np, &pg->genpd);
> +
> +		tegra_powergate_add_powerdomains(pmc, np, &pg->genpd);
> +	}

Nice, I like the recursive nature of this and how it matches up well
with the Tegra hardware.

> +
> +	return 0;
> +}
> +
> +static int tegra_powergate_init(struct tegra_pmc *pmc)
> +{
> +	struct device_node *np;
> +
> +	INIT_LIST_HEAD(&pmc->powergates_list);
> +
> +	np = of_get_child_by_name(pmc->dev->of_node, "pm-domains");
> +	if (!np) {
> +		dev_dbg(pmc->dev, "power-domains node not found\n");
> +		return 0;
> +	}
> +
> +	return tegra_powergate_add_powerdomains(pmc, np, NULL);
> +}
> +
>  static int tegra_io_rail_prepare(int id, unsigned long *request,
>  				 unsigned long *status, unsigned int *bit)
>  {
> @@ -875,6 +1390,12 @@ static int tegra_pmc_probe(struct platform_device *pdev)
>  
>  	tegra_pmc_init_tsense_reset(pmc);
>  
> +	if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
> +		err = tegra_powergate_init(pmc);
> +		if (err < 0)
> +			return err;
> +	}
> +
>  	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
>  		err = tegra_powergate_debugfs_init();
>  		if (err < 0)
> diff --git a/include/dt-bindings/power/tegra-powergate.h b/include/dt-bindings/power/tegra-powergate.h
> new file mode 100644
> index 000000000000..b1d51f028a99
> --- /dev/null
> +++ b/include/dt-bindings/power/tegra-powergate.h
> @@ -0,0 +1,42 @@
> +#ifndef _DT_BINDINGS_POWER_TEGRA_POWERGATE_H
> +#define _DT_BINDINGS_POWER_TEGRA_POWERGATE_H
> +
> +#define TEGRA_POWERGATE_CPU	0
> +#define TEGRA_POWERGATE_3D	1
> +#define TEGRA_POWERGATE_VENC	2
> +#define TEGRA_POWERGATE_PCIE	3
> +#define TEGRA_POWERGATE_VDEC	4
> +#define TEGRA_POWERGATE_L2	5
> +#define TEGRA_POWERGATE_MPE	6
> +#define TEGRA_POWERGATE_HEG	7
> +#define TEGRA_POWERGATE_SATA	8
> +#define TEGRA_POWERGATE_CPU1	9
> +#define TEGRA_POWERGATE_CPU2	10
> +#define TEGRA_POWERGATE_CPU3	11
> +#define TEGRA_POWERGATE_CELP	12
> +#define TEGRA_POWERGATE_3D1	13
> +#define TEGRA_POWERGATE_CPU0	14
> +#define TEGRA_POWERGATE_C0NC	15
> +#define TEGRA_POWERGATE_C1NC	16
> +#define TEGRA_POWERGATE_SOR	17
> +#define TEGRA_POWERGATE_DIS	18
> +#define TEGRA_POWERGATE_DISB	19
> +#define TEGRA_POWERGATE_XUSBA	20
> +#define TEGRA_POWERGATE_XUSBB	21
> +#define TEGRA_POWERGATE_XUSBC	22
> +#define TEGRA_POWERGATE_VIC	23
> +#define TEGRA_POWERGATE_IRAM	24
> +#define TEGRA_POWERGATE_NVDEC	25
> +#define TEGRA_POWERGATE_NVJPG	26
> +#define TEGRA_POWERGATE_AUD	27
> +#define TEGRA_POWERGATE_DFD	28
> +#define TEGRA_POWERGATE_VE2	29
> +
> +/*
> + * Pseudo powergate for power-domains that are power-gated externally.
> + * Make this a large number to allow other powergates to be added.
> + */
> +#define TEGRA_POWERGATE_EXT	1000

Can't we simply cover this case by not specifying the nvidia,powergate
property in the first place? Or make it conditional on the existence of
a vdd-supply property.

> +
> +

There's a gratuitous blank line here.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* [PATCH V3 15/19] soc: tegra: pmc: Add generic PM domain support
@ 2015-07-17 11:29         ` Thierry Reding
  0 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 11:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 13, 2015 at 01:39:53PM +0100, Jon Hunter wrote:
> Adds generic PM support to the PMC driver where the PM domains are
> populated from device-tree and the PM domain consumer devices are
> bound to their relevant PM domains via device-tree as well.
> 
> Update the tegra_powergate_power_on_legacy/off_legacy() APIs so that
> internally they call the same tegra_powergate_xxx functions that are
> used by the tegra generic power domain code for consistency.
> 
> This is based upon work by Thierry Reding <treding@nvidia.com>
> and Vince Hsu <vinceh@nvidia.com>.
> 
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  drivers/soc/tegra/pmc.c                     | 545 +++++++++++++++++++++++++++-
>  include/dt-bindings/power/tegra-powergate.h |  42 +++
>  include/soc/tegra/pmc.h                     |  52 +--
>  3 files changed, 580 insertions(+), 59 deletions(-)
>  create mode 100644 include/dt-bindings/power/tegra-powergate.h
> 
> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
> index 934653785bb7..4de92a9dae65 100644
> --- a/drivers/soc/tegra/pmc.c
> +++ b/drivers/soc/tegra/pmc.c
> @@ -19,8 +19,11 @@
>  
>  #define pr_fmt(fmt) "tegra-pmc: " fmt
>  
> +#include <dt-bindings/power/tegra-powergate.h>
> +
>  #include <linux/kernel.h>
>  #include <linux/clk.h>
> +#include <linux/clk-provider.h>

Why are we now providing clocks?

>  #include <linux/clk/tegra.h>
>  #include <linux/debugfs.h>
>  #include <linux/delay.h>
> @@ -30,17 +33,24 @@
>  #include <linux/io.h>
>  #include <linux/iopoll.h>
>  #include <linux/of.h>
> +#include <linux/of_platform.h>
>  #include <linux/of_address.h>
>  #include <linux/platform_device.h>
> +#include <linux/pm_domain.h>
>  #include <linux/reboot.h>
> +#include <linux/regulator/consumer.h>
>  #include <linux/reset.h>
> +#include <linux/sched.h>

What do we need this for?

>  #include <linux/seq_file.h>
>  #include <linux/spinlock.h>
>  
>  #include <soc/tegra/common.h>
>  #include <soc/tegra/fuse.h>
> +#include <soc/tegra/mc.h>
>  #include <soc/tegra/pmc.h>
>  
> +#define PMC_POWERGATE_ARRAY_MAX		10

There should be no need for this.

> +
>  #define PMC_CNTRL			0x0
>  #define  PMC_CNTRL_SYSCLK_POLARITY	(1 << 10)  /* sys clk polarity */
>  #define  PMC_CNTRL_SYSCLK_OE		(1 << 11)  /* system clock enable */
> @@ -106,6 +116,22 @@
>  
>  #define PMC_PWRGATE_STATE(val, id)	(!!(val & BIT(id)))
>  
> +struct tegra_powergate {
> +	struct generic_pm_domain genpd;
> +	struct tegra_pmc *pmc;
> +	struct tegra_mc *mc;
> +	unsigned int id;
> +	struct list_head node;
> +	struct device_node *of_node;
> +	struct regulator *vdd;
> +	struct clk **clks;
> +	struct reset_control **resets;
> +	const struct tegra_mc_flush **flushes;
> +	u32 num_clks;
> +	u32 num_resets;
> +	u32 num_flushes;

These should be unsigned int, and please group them with the arrays that
they define the sizes of.

> +};
> +
>  struct tegra_pmc_soc {
>  	unsigned int num_powergates;
>  	const char *const *powergates;
> @@ -118,8 +144,10 @@ struct tegra_pmc_soc {
>  
>  /**
>   * struct tegra_pmc - NVIDIA Tegra PMC
> + * @dev: pointer to parent device
>   * @base: pointer to I/O remapped register region
>   * @clk: pointer to pclk clock
> + * @soc: SoC-specific data

This could be a separate patch because it isn't related to the power
domain work.

>   * @rate: currently configured rate of pclk
>   * @suspend_mode: lowest suspend mode available
>   * @cpu_good_time: CPU power good time (in microseconds)
> @@ -133,6 +161,7 @@ struct tegra_pmc_soc {
>   * @cpu_pwr_good_en: CPU power good signal is enabled
>   * @lp0_vec_phys: physical base address of the LP0 warm boot code
>   * @lp0_vec_size: size of the LP0 warm boot code
> + * @powergates_list: list of power gates
>   * @powergates_lock: mutex for power gate register access
>   */
>  struct tegra_pmc {
> @@ -157,6 +186,7 @@ struct tegra_pmc {
>  	u32 lp0_vec_phys;
>  	u32 lp0_vec_size;
>  
> +	struct list_head powergates_list;
>  	struct mutex powergates_lock;
>  };
>  
> @@ -165,6 +195,12 @@ static struct tegra_pmc *pmc = &(struct tegra_pmc) {
>  	.suspend_mode = TEGRA_SUSPEND_NONE,
>  };
>  
> +static inline struct tegra_powergate *
> +to_powergate(struct generic_pm_domain *domain)
> +{
> +	return container_of(domain, struct tegra_powergate, genpd);
> +}
> +
>  static u32 tegra_pmc_readl(unsigned long offset)
>  {
>  	return readl(pmc->base + offset);
> @@ -175,6 +211,37 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
>  	writel(value, pmc->base + offset);
>  }
>  
> +static int tegra_powergate_get_regulator(struct tegra_powergate *powergate)
> +{
> +	struct platform_device *pdev;
> +
> +	if (powergate->id != TEGRA_POWERGATE_EXT)
> +		return -EINVAL;
> +
> +	pdev = of_find_device_by_node(powergate->of_node);
> +	if (!pdev)
> +		return -EINVAL;
> +
> +	powergate->vdd = devm_regulator_get_optional(&pdev->dev, "vdd");
> +	if (IS_ERR(powergate->vdd))
> +		return PTR_ERR(powergate->vdd);
> +
> +	return 0;
> +}
> +
> +static int tegra_powergate_enable_regulator(struct tegra_powergate *powergate)
> +{
> +	int ret = 0;
> +
> +	if (IS_ERR_OR_NULL(powergate->vdd))
> +		ret = tegra_powergate_get_regulator(powergate);

Why don't you get the regulator at the time when the powergate is
created? That way you still have a chance of deferring probe to get
another chance at getting it. If you don't do that, then if ever you
happen to want to enable the powergate before the regulator is ready
you'll error out and your consumer will have to deal with that.

> +
> +	if (!ret)
> +		ret = regulator_enable(powergate->vdd);
> +
> +	return ret;
> +}
> +
>  /**
>   * tegra_powergate_set() - set the state of a partition
>   * @id: partition ID
> @@ -207,6 +274,215 @@ static int tegra_powergate_set(int id, bool new_state, bool wait)
>  	return ret;
>  }
>  
> +static int tegra_powergate_enable(struct tegra_powergate *powergate,
> +				  bool enable)
> +{
> +	if (powergate->id != TEGRA_POWERGATE_EXT)
> +		return tegra_powergate_set(powergate->id, enable, true);
> +
> +	if (enable)
> +		return tegra_powergate_enable_regulator(powergate);
> +	else
> +		return regulator_disable(powergate->vdd);
> +}
> +
> +static bool tegra_powergate_is_supported(int id)
> +{
> +	switch (id) {
> +	case TEGRA_POWERGATE_CPU:
> +	case TEGRA_POWERGATE_CPU1:
> +	case TEGRA_POWERGATE_CPU2:
> +	case TEGRA_POWERGATE_CPU3:
> +	case TEGRA_POWERGATE_CPU0:
> +	case TEGRA_POWERGATE_C0NC:
> +	case TEGRA_POWERGATE_IRAM:
> +		return false;
> +	default:
> +		return true;
> +	}
> +}
> +
> +static bool _tegra_powergate_is_powered(struct tegra_powergate *powergate)
> +{
> +	if (powergate->id != TEGRA_POWERGATE_EXT)
> +		return tegra_powergate_is_powered(powergate->id);
> +
> +	if (IS_ERR(powergate->vdd))
> +		return false;
> +	else
> +		return regulator_is_enabled(powergate->vdd);
> +}
> +
> +static void tegra_powergate_disable_clocks(struct tegra_powergate *powergate)
> +{
> +	int i;

Should match the type of powergate->num_clks, that is unsigned int.

> +
> +	for (i = 0; i < powergate->num_clks; i++)
> +		clk_disable_unprepare(powergate->clks[i]);
> +}
> +
> +static int tegra_powergate_enable_clocks(struct tegra_powergate *powergate)
> +{
> +	int err, i;

Same here.

> +
> +	for (i = 0; i < powergate->num_clks; i++) {
> +		err = clk_prepare_enable(powergate->clks[i]);
> +		if (err)
> +			goto out;
> +	}
> +
> +	return 0;
> +
> +out:
> +	while (i--)
> +		clk_disable_unprepare(powergate->clks[i]);
> +
> +	return err;
> +}
> +
> +static int tegra_powergate_mc_flush(struct tegra_powergate *powergate,
> +				    bool enable)
> +{
> +	int i, err;

And here.

> +
> +	for (i = 0; i < powergate->num_flushes; i++) {
> +		err = tegra_mc_flush(powergate->mc, powergate->flushes[i],
> +				     enable);
> +		if (err)
> +			return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static int tegra_powergate_reset_assert(struct tegra_powergate *powergate)
> +{
> +	int err, i;

As well as here.

> +
> +	for (i = 0; i < powergate->num_resets; i++) {
> +		err = reset_control_assert(powergate->resets[i]);
> +		if (err)
> +			return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static int tegra_powergate_reset_deassert(struct tegra_powergate *powergate)
> +{
> +	int err, i;
> +
> +	for (i = 0; i < powergate->num_resets; i++) {
> +		err = reset_control_deassert(powergate->resets[i]);
> +		if (err)
> +			return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static int tegra_powergate_seq_power_up(struct tegra_powergate *powergate)

What does the _seq buy us here? Why not simply call this
tegra_powergate_power_up()?

> +{
> +	int err;
> +
> +	err = tegra_powergate_reset_assert(powergate);
> +	if (err)
> +		goto out;
> +	udelay(10);

There should be a space between the above two lines. Also, is there a
reason why we can't use usleep_range() here?

> +
> +	err = tegra_powergate_enable(powergate, true);
> +	if (err < 0)
> +		goto out;
> +	udelay(10);
> +
> +	err = tegra_powergate_enable_clocks(powergate);
> +	if (err)
> +		goto out;
> +	udelay(10);
> +
> +	tegra_powergate_remove_clamping(powergate->id);
> +
> +	udelay(10);
> +
> +	err = tegra_powergate_reset_deassert(powergate);
> +	if (err)
> +		goto out;
> +	udelay(10);
> +
> +	err = tegra_powergate_mc_flush(powergate, false);
> +	if (err)
> +		goto out;

I mentioned this before, but I think it'd be good to split out the flush
changes from this patch, so that we can test the series without the
flushing to see if it's at all necessary.

> +static int tegra_genpd_power_on(struct generic_pm_domain *domain)
> +{
> +	struct tegra_powergate *powergate = to_powergate(domain);
> +	struct tegra_pmc *pmc = powergate->pmc;
> +	int err;
> +
> +	err = tegra_powergate_seq_power_up(powergate);
> +
> +	if (err)

There should be no blank line between the above.

> +		dev_err(pmc->dev, "Failed to turn on PM Domain (%d)\n", err);

For consistency with other error messages, "Failed" should be "failed".
And "Domain" should be "domain". Also typically the error is separated
from the message with a colon: "failed ... domain: %d\n".

> -int tegra_powergate_power_off_legacy(int id, struct clk *clk,
> -				     struct reset_control *rst)
> +int tegra_powergate_power_on_legacy(int id, struct clk *clk,
> +				    struct reset_control *rst)
>  {
> -	int ret;
> +	struct tegra_powergate powergate;
>  
> -	ret = clk_prepare_enable(clk);
> -	if (ret)
> -		return ret;
> +	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
> +		return -EINVAL;
>  
> -	usleep_range(10, 20);
> +	powergate.id = id;
> +	powergate.clks = &clk;
> +	powergate.resets = &rst;
> +	powergate.num_clks = 1;
> +	powergate.num_resets = 1;
> +	powergate.num_flushes = 0;
>  
> -	reset_control_assert(rst);
> +	return tegra_powergate_seq_power_up(&powergate);
> +}
> +EXPORT_SYMBOL(tegra_powergate_power_on_legacy);
>  
> -	usleep_range(10, 20);
> +int tegra_powergate_power_off_legacy(int id, struct clk *clk,
> +				     struct reset_control *rst)
> +{
> +	struct tegra_powergate powergate;
>  
> -	clk_disable_unprepare(clk);
> +	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
> +		return -EINVAL;
>  
> -	usleep_range(10, 20);
> +	powergate.id = id;
> +	powergate.clks = &clk;
> +	powergate.resets = &rst;
> +	powergate.num_clks = 1;
> +	powergate.num_resets = 1;
> +	powergate.num_flushes = 0;
>  
> -	return tegra_powergate_power_off(id);
> +	return tegra_powergate_seq_power_down(&powergate);
>  }
>  EXPORT_SYMBOL(tegra_powergate_power_off_legacy);

It looks as if you decided to reorder the two functions here, but that
makes the diff very hard to read.

>  
> @@ -493,6 +786,228 @@ static int tegra_powergate_debugfs_init(void)
>  	return 0;
>  }
>  
> +static int tegra_powergate_of_get_clks(struct device *dev,
> +				       struct tegra_powergate *powergate)
> +{
> +	struct clk *clks[PMC_POWERGATE_ARRAY_MAX];
> +	int i = 0;

unsigned int, and no need to initialize here.

> +
> +	for (i = 0; i < PMC_POWERGATE_ARRAY_MAX; i++) {
> +		clks[i] = of_clk_get(powergate->of_node, i);
> +		if (IS_ERR(clks[i])) {
> +			if (PTR_ERR(clks[i]) != -ENOENT)
> +				return PTR_ERR(clks[i]);
> +			break;
> +		}
> +	}

Can we perhaps prepend this with a loop that determines the number of
clocks specified in DT? That way we can avoid the statically sized array
altogether.

Perhaps to make it a little easier to read, keep a local variable clk
and assign to the array only when it's been sanitized:

	for (...) {
		clk = of_clk_get(...);
		if (IS_ERR(clk)) {
			...
		}

		powergate->clks[i] = clk;
	}

> +
> +	if (PTR_ERR(clks[i]) != -ENOENT) {
> +		dev_err(dev, "unsupported number of clocks defined\n");
> +		return -EINVAL;
> +	}
> +
> +	powergate->clks = devm_kcalloc(dev, i, sizeof(*clks), GFP_KERNEL);
> +	if (!powergate->clks)
> +		return -ENOMEM;
> +
> +	memcpy(powergate->clks, clks, sizeof(*clks) * i);
> +	powergate->num_clks = i;
> +
> +	return 0;
> +}

Don't you need to put the clocks that you've obtained above to avoid
leaking them?

> +
> +static int tegra_powergate_of_get_resets(struct device *dev,
> +					 struct tegra_powergate *powergate)
> +{
> +	struct reset_control *rsts[PMC_POWERGATE_ARRAY_MAX];
> +	int i = 0;
> +
> +	for (i = 0; i < PMC_POWERGATE_ARRAY_MAX; i++) {
> +		rsts[i] = of_reset_control_get_by_index(powergate->of_node, i);
> +		if (IS_ERR(rsts[i])) {
> +			if (PTR_ERR(rsts[i]) != -ENOENT)
> +				return PTR_ERR(rsts[i]);
> +			break;
> +		}
> +	}
> +
> +	if (PTR_ERR(rsts[i]) != -ENOENT) {
> +		dev_err(dev, "unsupported number of resets defined\n");
> +		return -EINVAL;
> +	}
> +
> +	powergate->resets = devm_kcalloc(dev, i, sizeof(*rsts), GFP_KERNEL);
> +	if (!powergate->resets)
> +		return -ENOMEM;
> +
> +	memcpy(powergate->resets, rsts, sizeof(*rsts) * i);
> +	powergate->num_resets = i;
> +
> +	return 0;
> +}

Same comments as for clocks.

> +static int tegra_powergate_of_get_mc_flush(struct device *dev,
> +					   struct tegra_powergate *powergate)
> +{
> +	struct platform_device *pdev;
> +	struct of_phandle_args args;
> +	int i = 0, ret = 0;
> +
> +	ret = of_parse_phandle_with_args(dev->of_node, "nvidia-swgroups",
> +					"#nvidia,swgroup-cells", 0, &args);
> +	if (ret < 0) {
> +		/*
> +		 * The nvidia-swgroups property is
> +		 * optional and so if missing simply return.
> +		 */
> +		if (ret == -ENOENT)
> +			return 0;
> +
> +		dev_err(dev, "nvidia-swgroups property invalid for %s (%d)\n",
> +			powergate->of_node->name, ret);
> +		return ret;
> +	}
> +
> +	powergate->flushes = devm_kcalloc(dev, args.args_count,
> +					  sizeof(powergate->flushes),
> +					  GFP_KERNEL);
> +	if (!powergate->flushes) {
> +		dev_err(dev, "failed to allocate memory for powergate flush\n");
> +		return -ENOMEM;
> +	}
> +
> +	pdev = of_find_device_by_node(args.np);
> +	if (!pdev)
> +		return -ENODEV;
> +
> +	powergate->mc = platform_get_drvdata(pdev);
> +	if (!powergate->mc)
> +		return -EINVAL;
> +
> +	for (i = 0; i < args.args_count; i++) {
> +		powergate->flushes[i] = tegra_mc_flush_get(powergate->mc,
> +							   args.args[i]);

Urgs... might be better to make this a struct device *-based API, so
that you don't have to reach into the private structures of the MC
driver. Well, it'd technically have to be struct device_node *-based
because we don't have a struct device * for the power domains. Perhaps
something like this:

	const struct tegra_mc_flush *tegra_mc_flush_get(struct device_node *np,
							unsigned int index);

Then the MC driver can access its own internals, rather than the other
way around.

> +		if (!powergate->flushes[i])
> +			return -EINVAL;
> +	}
> +
> +	powergate->num_flushes = args.args_count;
> +
> +	return 0;
> +}
> +
> +static int tegra_powergate_init_powerdomain(struct tegra_pmc *pmc,
> +					    struct device_node *np,
> +					    struct tegra_powergate *pg)

This is slightly confusing. Why not something like this:

	struct tegra_powergate *tegra_powergate_create(struct tegra_pmc *pmc,
						       struct device_node *np)

?

> +{
> +	bool off;
> +	int err;
> +
> +	err = of_property_read_u32(np, "nvidia,powergate", &pg->id);
> +	if (err) {
> +		dev_err(pmc->dev, "no powergate ID for domain\n");
> +		goto err;
> +	}
> +
> +	if (tegra_powergate_is_supported(pg->id) == false) {
> +		dev_warn(pmc->dev, "%s not currently supported by genpd\n",
> +			 np->name);
> +		return -EINVAL;
> +	}
> +
> +	if (pg->id == TEGRA_POWERGATE_EXT) {
> +		err = tegra_powergate_get_regulator(pg);
> +		if (err) {
> +			/*
> +			 * The regulator might not be ready yet, so just
> +			 * give a warning instead of failing the whole
> +			 * init.
> +			 */
> +			dev_warn(pmc->dev, "couldn't locate regulator\n");

Why won't regular probe deferral work?

> +		}
> +	}
> +
> +	pg->of_node = np;
> +	pg->genpd.name = np->name;
> +	pg->genpd.power_off = tegra_genpd_power_off;
> +	pg->genpd.power_on = tegra_genpd_power_on;
> +	pg->pmc = pmc;
> +
> +	err = tegra_powergate_of_get_clks(pmc->dev, pg);
> +	if (err)
> +		goto err;
> +
> +	err = tegra_powergate_of_get_resets(pmc->dev, pg);
> +	if (err)
> +		goto err;
> +
> +	err = tegra_powergate_of_get_mc_flush(pmc->dev, pg);
> +	if (err)
> +		goto err;
> +
> +	list_add_tail(&pg->node, &pmc->powergates_list);
> +
> +	if (!IS_ERR(pg->vdd) || pg->id != TEGRA_POWERGATE_EXT)
> +		tegra_genpd_power_off(&pg->genpd);
> +
> +	off = !_tegra_powergate_is_powered(pg);
> +
> +	pm_genpd_init(&pg->genpd, NULL, off);
> +
> +	dev_info(pmc->dev, "added power domain %s\n", np->name);
> +
> +	return 0;
> +
> +err:
> +	dev_err(pmc->dev, "failed to add power domain for node %s\n",
> +		np->name);
> +	return err;

This doesn't clean up any of the requested resources on failure.

> +}
> +
> +static int tegra_powergate_add_powerdomains(struct tegra_pmc *pmc,
> +					    struct device_node *parent,
> +					    struct generic_pm_domain *pd_parent)
> +{
> +	struct device_node *np;
> +	int ret;

Please use err consistently as the name for error codes. This patch uses
a mixture of both.

> +
> +	for_each_child_of_node(parent, np) {
> +		struct tegra_powergate *pg;
> +
> +		pg = devm_kzalloc(pmc->dev, sizeof(*pg), GFP_KERNEL);
> +		if (!pg)
> +			return -ENOMEM;
> +
> +		ret = tegra_powergate_init_powerdomain(pmc, np, pg);
> +		if (ret)
> +			return ret;
> +
> +		if (pd_parent)
> +			pm_genpd_add_subdomain(pd_parent, &pg->genpd);
> +
> +		of_genpd_add_provider_simple(np, &pg->genpd);
> +
> +		tegra_powergate_add_powerdomains(pmc, np, &pg->genpd);
> +	}

Nice, I like the recursive nature of this and how it matches up well
with the Tegra hardware.

> +
> +	return 0;
> +}
> +
> +static int tegra_powergate_init(struct tegra_pmc *pmc)
> +{
> +	struct device_node *np;
> +
> +	INIT_LIST_HEAD(&pmc->powergates_list);
> +
> +	np = of_get_child_by_name(pmc->dev->of_node, "pm-domains");
> +	if (!np) {
> +		dev_dbg(pmc->dev, "power-domains node not found\n");
> +		return 0;
> +	}
> +
> +	return tegra_powergate_add_powerdomains(pmc, np, NULL);
> +}
> +
>  static int tegra_io_rail_prepare(int id, unsigned long *request,
>  				 unsigned long *status, unsigned int *bit)
>  {
> @@ -875,6 +1390,12 @@ static int tegra_pmc_probe(struct platform_device *pdev)
>  
>  	tegra_pmc_init_tsense_reset(pmc);
>  
> +	if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
> +		err = tegra_powergate_init(pmc);
> +		if (err < 0)
> +			return err;
> +	}
> +
>  	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
>  		err = tegra_powergate_debugfs_init();
>  		if (err < 0)
> diff --git a/include/dt-bindings/power/tegra-powergate.h b/include/dt-bindings/power/tegra-powergate.h
> new file mode 100644
> index 000000000000..b1d51f028a99
> --- /dev/null
> +++ b/include/dt-bindings/power/tegra-powergate.h
> @@ -0,0 +1,42 @@
> +#ifndef _DT_BINDINGS_POWER_TEGRA_POWERGATE_H
> +#define _DT_BINDINGS_POWER_TEGRA_POWERGATE_H
> +
> +#define TEGRA_POWERGATE_CPU	0
> +#define TEGRA_POWERGATE_3D	1
> +#define TEGRA_POWERGATE_VENC	2
> +#define TEGRA_POWERGATE_PCIE	3
> +#define TEGRA_POWERGATE_VDEC	4
> +#define TEGRA_POWERGATE_L2	5
> +#define TEGRA_POWERGATE_MPE	6
> +#define TEGRA_POWERGATE_HEG	7
> +#define TEGRA_POWERGATE_SATA	8
> +#define TEGRA_POWERGATE_CPU1	9
> +#define TEGRA_POWERGATE_CPU2	10
> +#define TEGRA_POWERGATE_CPU3	11
> +#define TEGRA_POWERGATE_CELP	12
> +#define TEGRA_POWERGATE_3D1	13
> +#define TEGRA_POWERGATE_CPU0	14
> +#define TEGRA_POWERGATE_C0NC	15
> +#define TEGRA_POWERGATE_C1NC	16
> +#define TEGRA_POWERGATE_SOR	17
> +#define TEGRA_POWERGATE_DIS	18
> +#define TEGRA_POWERGATE_DISB	19
> +#define TEGRA_POWERGATE_XUSBA	20
> +#define TEGRA_POWERGATE_XUSBB	21
> +#define TEGRA_POWERGATE_XUSBC	22
> +#define TEGRA_POWERGATE_VIC	23
> +#define TEGRA_POWERGATE_IRAM	24
> +#define TEGRA_POWERGATE_NVDEC	25
> +#define TEGRA_POWERGATE_NVJPG	26
> +#define TEGRA_POWERGATE_AUD	27
> +#define TEGRA_POWERGATE_DFD	28
> +#define TEGRA_POWERGATE_VE2	29
> +
> +/*
> + * Pseudo powergate for power-domains that are power-gated externally.
> + * Make this a large number to allow other powergates to be added.
> + */
> +#define TEGRA_POWERGATE_EXT	1000

Can't we simply cover this case by not specifying the nvidia,powergate
property in the first place? Or make it conditional on the existence of
a vdd-supply property.

> +
> +

There's a gratuitous blank line here.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150717/120b7be1/attachment.sig>

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

* Re: [PATCH V3 02/19] memory: tegra: Add MC flush support
  2015-07-17 10:20         ` Peter De Schrijver
@ 2015-07-17 11:31             ` Thierry Reding
  -1 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 11:31 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Jon Hunter, Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 2067 bytes --]

On Fri, Jul 17, 2015 at 01:20:49PM +0300, Peter De Schrijver wrote:
> On Fri, Jul 17, 2015 at 11:57:55AM +0200, Thierry Reding wrote:
> > * PGP Signed by an unknown key
> > 
> > On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
> > > The Tegra memory controller implements a flush feature to flush pending
> > > accesses and prevent further accesses from occurring. This feature is
> > > used when powering down IP blocks to ensure the IP block is in a good
> > > state. The flushes are organised by software groups and IP blocks are
> > > assigned in hardware to the different software groups. Add helper
> > > functions for requesting a handle to an MC flush for a given
> > > software group and enabling/disabling the MC flush itself.
> > > 
> > > This is based upon a change by Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>.
> > > 
> > > Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> > > ---
> > >  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
> > >  drivers/memory/tegra/mc.h |   2 +
> > >  include/soc/tegra/mc.h    |  34 ++++++++++++++
> > >  3 files changed, 146 insertions(+)
> > 
> > Do we know if this is actually necessary? I remember having a discussion
> > with Arnd Bergmann a while ago, and the Linux driver model kind of
> > assumes that by the time a device is disabled all outstanding accesses
> > will have stopped.
> > 
> > Do we have a way to determine that this even makes a difference? Can we
> > trigger a case where not doing this would cause breakage and see that
> > adding this fixes that particular issue?
> > 
> 
> Most likely it is. The memory controller can still be processing requests
> when the peripheral domain is powergated. This would mean the response cannot
> be delivered in that case. So we need to be sure there are no outstanding
> requests before shutting down the domain.

My point is that that's the driver's responsibility anyway, hence making
the explicit flush unnecessary.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* [PATCH V3 02/19] memory: tegra: Add MC flush support
@ 2015-07-17 11:31             ` Thierry Reding
  0 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-17 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 17, 2015 at 01:20:49PM +0300, Peter De Schrijver wrote:
> On Fri, Jul 17, 2015 at 11:57:55AM +0200, Thierry Reding wrote:
> > * PGP Signed by an unknown key
> > 
> > On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
> > > The Tegra memory controller implements a flush feature to flush pending
> > > accesses and prevent further accesses from occurring. This feature is
> > > used when powering down IP blocks to ensure the IP block is in a good
> > > state. The flushes are organised by software groups and IP blocks are
> > > assigned in hardware to the different software groups. Add helper
> > > functions for requesting a handle to an MC flush for a given
> > > software group and enabling/disabling the MC flush itself.
> > > 
> > > This is based upon a change by Vince Hsu <vinceh@nvidia.com>.
> > > 
> > > Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> > > ---
> > >  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
> > >  drivers/memory/tegra/mc.h |   2 +
> > >  include/soc/tegra/mc.h    |  34 ++++++++++++++
> > >  3 files changed, 146 insertions(+)
> > 
> > Do we know if this is actually necessary? I remember having a discussion
> > with Arnd Bergmann a while ago, and the Linux driver model kind of
> > assumes that by the time a device is disabled all outstanding accesses
> > will have stopped.
> > 
> > Do we have a way to determine that this even makes a difference? Can we
> > trigger a case where not doing this would cause breakage and see that
> > adding this fixes that particular issue?
> > 
> 
> Most likely it is. The memory controller can still be processing requests
> when the peripheral domain is powergated. This would mean the response cannot
> be delivered in that case. So we need to be sure there are no outstanding
> requests before shutting down the domain.

My point is that that's the driver's responsibility anyway, hence making
the explicit flush unnecessary.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150717/78b5bd92/attachment-0001.sig>

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

* Re: [PATCH V3 01/19] reset: add of_reset_control_get_by_index()
  2015-07-13 12:39     ` Jon Hunter
@ 2015-07-17 12:08         ` Philipp Zabel
  -1 siblings, 0 replies; 110+ messages in thread
From: Philipp Zabel @ 2015-07-17 12:08 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Thierry Reding, Alexandre Courbot,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

Am Montag, den 13.07.2015, 13:39 +0100 schrieb Jon Hunter:
> From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> 
> Add of_reset_control_get_by_index() to allow the drivers to get reset
> device without knowing its name.
> 
> Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> [jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org: Updated stub function to return -ENOTSUPP instead
>  of -ENOSYS which should only be used for system calls.]
> Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Acked-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

regards
Philipp

> ---
> v3: addressed comments from Philipp
> v2: minor changes according to Alex's comments
> ---
>  drivers/reset/core.c  | 40 +++++++++++++++++++++++++++++-----------
>  include/linux/reset.h |  9 +++++++++
>  2 files changed, 38 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
> index 7955e00d04d4..81ae17d15480 100644
> --- a/drivers/reset/core.c
> +++ b/drivers/reset/core.c
> @@ -141,27 +141,24 @@ int reset_control_status(struct reset_control *rstc)
>  EXPORT_SYMBOL_GPL(reset_control_status);
>  
>  /**
> - * of_reset_control_get - Lookup and obtain a reference to a reset controller.
> + * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
> + * controller by index.
>   * @node: device to be reset by the controller
> - * @id: reset line name
> - *
> - * Returns a struct reset_control or IS_ERR() condition containing errno.
> + * @index: index of the reset controller
>   *
> - * Use of id names is optional.
> + * This is to be used to perform a list of resets for a device or power domain
> + * in whatever order. Returns a struct reset_control or IS_ERR() condition
> + * containing errno.
>   */
> -struct reset_control *of_reset_control_get(struct device_node *node,
> -					   const char *id)
> +struct reset_control *of_reset_control_get_by_index(struct device_node *node,
> +					   int index)
>  {
>  	struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
>  	struct reset_controller_dev *r, *rcdev;
>  	struct of_phandle_args args;
> -	int index = 0;
>  	int rstc_id;
>  	int ret;
>  
> -	if (id)
> -		index = of_property_match_string(node,
> -						 "reset-names", id);
>  	ret = of_parse_phandle_with_args(node, "resets", "#reset-cells",
>  					 index, &args);
>  	if (ret)
> @@ -202,6 +199,27 @@ struct reset_control *of_reset_control_get(struct device_node *node,
>  
>  	return rstc;
>  }
> +EXPORT_SYMBOL_GPL(of_reset_control_get_by_index);
> +
> +/**
> + * of_reset_control_get - Lookup and obtain a reference to a reset controller.
> + * @node: device to be reset by the controller
> + * @id: reset line name
> + *
> + * Returns a struct reset_control or IS_ERR() condition containing errno.
> + *
> + * Use of id names is optional.
> + */
> +struct reset_control *of_reset_control_get(struct device_node *node,
> +					   const char *id)
> +{
> +	int index = 0;
> +
> +	if (id)
> +		index = of_property_match_string(node,
> +						 "reset-names", id);
> +	return of_reset_control_get_by_index(node, index);
> +}
>  EXPORT_SYMBOL_GPL(of_reset_control_get);
>  
>  /**
> diff --git a/include/linux/reset.h b/include/linux/reset.h
> index da5602bd77d7..26f1b53386d8 100644
> --- a/include/linux/reset.h
> +++ b/include/linux/reset.h
> @@ -38,6 +38,9 @@ static inline struct reset_control *devm_reset_control_get_optional(
>  struct reset_control *of_reset_control_get(struct device_node *node,
>  					   const char *id);
>  
> +struct reset_control *of_reset_control_get_by_index(
> +					struct device_node *node, int index);
> +
>  #else
>  
>  static inline int reset_control_reset(struct reset_control *rstc)
> @@ -92,6 +95,12 @@ static inline struct reset_control *of_reset_control_get(
>  	return ERR_PTR(-ENOSYS);
>  }
>  
> +static inline struct reset_control *of_reset_control_get_by_index(
> +				struct device_node *node, int index)
> +{
> +	return ERR_PTR(-ENOTSUPP);
> +}
> +
>  #endif /* CONFIG_RESET_CONTROLLER */
>  
>  #endif

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

* [PATCH V3 01/19] reset: add of_reset_control_get_by_index()
@ 2015-07-17 12:08         ` Philipp Zabel
  0 siblings, 0 replies; 110+ messages in thread
From: Philipp Zabel @ 2015-07-17 12:08 UTC (permalink / raw)
  To: linux-arm-kernel

Am Montag, den 13.07.2015, 13:39 +0100 schrieb Jon Hunter:
> From: Vince Hsu <vinceh@nvidia.com>
> 
> Add of_reset_control_get_by_index() to allow the drivers to get reset
> device without knowing its name.
> 
> Signed-off-by: Vince Hsu <vinceh@nvidia.com>
> [jonathanh at nvidia.com: Updated stub function to return -ENOTSUPP instead
>  of -ENOSYS which should only be used for system calls.]
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>

Acked-by: Philipp Zabel <p.zabel@pengutronix.de>

regards
Philipp

> ---
> v3: addressed comments from Philipp
> v2: minor changes according to Alex's comments
> ---
>  drivers/reset/core.c  | 40 +++++++++++++++++++++++++++++-----------
>  include/linux/reset.h |  9 +++++++++
>  2 files changed, 38 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
> index 7955e00d04d4..81ae17d15480 100644
> --- a/drivers/reset/core.c
> +++ b/drivers/reset/core.c
> @@ -141,27 +141,24 @@ int reset_control_status(struct reset_control *rstc)
>  EXPORT_SYMBOL_GPL(reset_control_status);
>  
>  /**
> - * of_reset_control_get - Lookup and obtain a reference to a reset controller.
> + * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
> + * controller by index.
>   * @node: device to be reset by the controller
> - * @id: reset line name
> - *
> - * Returns a struct reset_control or IS_ERR() condition containing errno.
> + * @index: index of the reset controller
>   *
> - * Use of id names is optional.
> + * This is to be used to perform a list of resets for a device or power domain
> + * in whatever order. Returns a struct reset_control or IS_ERR() condition
> + * containing errno.
>   */
> -struct reset_control *of_reset_control_get(struct device_node *node,
> -					   const char *id)
> +struct reset_control *of_reset_control_get_by_index(struct device_node *node,
> +					   int index)
>  {
>  	struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
>  	struct reset_controller_dev *r, *rcdev;
>  	struct of_phandle_args args;
> -	int index = 0;
>  	int rstc_id;
>  	int ret;
>  
> -	if (id)
> -		index = of_property_match_string(node,
> -						 "reset-names", id);
>  	ret = of_parse_phandle_with_args(node, "resets", "#reset-cells",
>  					 index, &args);
>  	if (ret)
> @@ -202,6 +199,27 @@ struct reset_control *of_reset_control_get(struct device_node *node,
>  
>  	return rstc;
>  }
> +EXPORT_SYMBOL_GPL(of_reset_control_get_by_index);
> +
> +/**
> + * of_reset_control_get - Lookup and obtain a reference to a reset controller.
> + * @node: device to be reset by the controller
> + * @id: reset line name
> + *
> + * Returns a struct reset_control or IS_ERR() condition containing errno.
> + *
> + * Use of id names is optional.
> + */
> +struct reset_control *of_reset_control_get(struct device_node *node,
> +					   const char *id)
> +{
> +	int index = 0;
> +
> +	if (id)
> +		index = of_property_match_string(node,
> +						 "reset-names", id);
> +	return of_reset_control_get_by_index(node, index);
> +}
>  EXPORT_SYMBOL_GPL(of_reset_control_get);
>  
>  /**
> diff --git a/include/linux/reset.h b/include/linux/reset.h
> index da5602bd77d7..26f1b53386d8 100644
> --- a/include/linux/reset.h
> +++ b/include/linux/reset.h
> @@ -38,6 +38,9 @@ static inline struct reset_control *devm_reset_control_get_optional(
>  struct reset_control *of_reset_control_get(struct device_node *node,
>  					   const char *id);
>  
> +struct reset_control *of_reset_control_get_by_index(
> +					struct device_node *node, int index);
> +
>  #else
>  
>  static inline int reset_control_reset(struct reset_control *rstc)
> @@ -92,6 +95,12 @@ static inline struct reset_control *of_reset_control_get(
>  	return ERR_PTR(-ENOSYS);
>  }
>  
> +static inline struct reset_control *of_reset_control_get_by_index(
> +				struct device_node *node, int index)
> +{
> +	return ERR_PTR(-ENOTSUPP);
> +}
> +
>  #endif /* CONFIG_RESET_CONTROLLER */
>  
>  #endif

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

* Re: [PATCH V3 02/19] memory: tegra: Add MC flush support
  2015-07-17 11:31             ` Thierry Reding
@ 2015-07-20  8:46               ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-20  8:46 UTC (permalink / raw)
  To: Thierry Reding, Peter De Schrijver
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra, devicetree, linux-arm-kernel, linux-pm


On 17/07/15 12:31, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Fri, Jul 17, 2015 at 01:20:49PM +0300, Peter De Schrijver wrote:
>> On Fri, Jul 17, 2015 at 11:57:55AM +0200, Thierry Reding wrote:
>>>> Old Signed by an unknown key
>>>
>>> On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
>>>> The Tegra memory controller implements a flush feature to flush pending
>>>> accesses and prevent further accesses from occurring. This feature is
>>>> used when powering down IP blocks to ensure the IP block is in a good
>>>> state. The flushes are organised by software groups and IP blocks are
>>>> assigned in hardware to the different software groups. Add helper
>>>> functions for requesting a handle to an MC flush for a given
>>>> software group and enabling/disabling the MC flush itself.
>>>>
>>>> This is based upon a change by Vince Hsu <vinceh@nvidia.com>.
>>>>
>>>> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
>>>> ---
>>>>  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
>>>>  drivers/memory/tegra/mc.h |   2 +
>>>>  include/soc/tegra/mc.h    |  34 ++++++++++++++
>>>>  3 files changed, 146 insertions(+)
>>>
>>> Do we know if this is actually necessary? I remember having a discussion
>>> with Arnd Bergmann a while ago, and the Linux driver model kind of
>>> assumes that by the time a device is disabled all outstanding accesses
>>> will have stopped.
>>>
>>> Do we have a way to determine that this even makes a difference? Can we
>>> trigger a case where not doing this would cause breakage and see that
>>> adding this fixes that particular issue?
>>>
>>
>> Most likely it is. The memory controller can still be processing requests
>> when the peripheral domain is powergated. This would mean the response cannot
>> be delivered in that case. So we need to be sure there are no outstanding
>> requests before shutting down the domain.
> 
> My point is that that's the driver's responsibility anyway, hence making
> the explicit flush unnecessary.

I see your point and it is interesting. The trouble is that we would
need to test every memory client in every power domain to prove this. So
I don't think that is a trivial thing to do. Furthermore, looking at
what we have done in kernel used for android products (which probably
stress PM the most) this is done and so I don't know of any shipping
product that stresses PM that does not do this. May be someone else
might. I personally would not be comfortable removing this without
testing, but as I mentioned it is not a trivial thing to test correctly.
However, I will let you and the other maintainers decide what's best here.

Jon

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

* [PATCH V3 02/19] memory: tegra: Add MC flush support
@ 2015-07-20  8:46               ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-20  8:46 UTC (permalink / raw)
  To: linux-arm-kernel


On 17/07/15 12:31, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Fri, Jul 17, 2015 at 01:20:49PM +0300, Peter De Schrijver wrote:
>> On Fri, Jul 17, 2015 at 11:57:55AM +0200, Thierry Reding wrote:
>>>> Old Signed by an unknown key
>>>
>>> On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
>>>> The Tegra memory controller implements a flush feature to flush pending
>>>> accesses and prevent further accesses from occurring. This feature is
>>>> used when powering down IP blocks to ensure the IP block is in a good
>>>> state. The flushes are organised by software groups and IP blocks are
>>>> assigned in hardware to the different software groups. Add helper
>>>> functions for requesting a handle to an MC flush for a given
>>>> software group and enabling/disabling the MC flush itself.
>>>>
>>>> This is based upon a change by Vince Hsu <vinceh@nvidia.com>.
>>>>
>>>> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
>>>> ---
>>>>  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
>>>>  drivers/memory/tegra/mc.h |   2 +
>>>>  include/soc/tegra/mc.h    |  34 ++++++++++++++
>>>>  3 files changed, 146 insertions(+)
>>>
>>> Do we know if this is actually necessary? I remember having a discussion
>>> with Arnd Bergmann a while ago, and the Linux driver model kind of
>>> assumes that by the time a device is disabled all outstanding accesses
>>> will have stopped.
>>>
>>> Do we have a way to determine that this even makes a difference? Can we
>>> trigger a case where not doing this would cause breakage and see that
>>> adding this fixes that particular issue?
>>>
>>
>> Most likely it is. The memory controller can still be processing requests
>> when the peripheral domain is powergated. This would mean the response cannot
>> be delivered in that case. So we need to be sure there are no outstanding
>> requests before shutting down the domain.
> 
> My point is that that's the driver's responsibility anyway, hence making
> the explicit flush unnecessary.

I see your point and it is interesting. The trouble is that we would
need to test every memory client in every power domain to prove this. So
I don't think that is a trivial thing to do. Furthermore, looking at
what we have done in kernel used for android products (which probably
stress PM the most) this is done and so I don't know of any shipping
product that stresses PM that does not do this. May be someone else
might. I personally would not be comfortable removing this without
testing, but as I mentioned it is not a trivial thing to test correctly.
However, I will let you and the other maintainers decide what's best here.

Jon

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

* Re: [PATCH V3 02/19] memory: tegra: Add MC flush support
  2015-07-20  8:46               ` Jon Hunter
@ 2015-07-20  9:17                 ` Thierry Reding
  -1 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-20  9:17 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Peter De Schrijver, Stephen Warren, Alexandre Courbot,
	Philipp Zabel, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra, devicetree,
	linux-arm-kernel, linux-pm

[-- Attachment #1: Type: text/plain, Size: 3622 bytes --]

On Mon, Jul 20, 2015 at 09:46:02AM +0100, Jon Hunter wrote:
> 
> On 17/07/15 12:31, Thierry Reding wrote:
> > * PGP Signed by an unknown key
> > 
> > On Fri, Jul 17, 2015 at 01:20:49PM +0300, Peter De Schrijver wrote:
> >> On Fri, Jul 17, 2015 at 11:57:55AM +0200, Thierry Reding wrote:
> >>>> Old Signed by an unknown key
> >>>
> >>> On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
> >>>> The Tegra memory controller implements a flush feature to flush pending
> >>>> accesses and prevent further accesses from occurring. This feature is
> >>>> used when powering down IP blocks to ensure the IP block is in a good
> >>>> state. The flushes are organised by software groups and IP blocks are
> >>>> assigned in hardware to the different software groups. Add helper
> >>>> functions for requesting a handle to an MC flush for a given
> >>>> software group and enabling/disabling the MC flush itself.
> >>>>
> >>>> This is based upon a change by Vince Hsu <vinceh@nvidia.com>.
> >>>>
> >>>> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> >>>> ---
> >>>>  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
> >>>>  drivers/memory/tegra/mc.h |   2 +
> >>>>  include/soc/tegra/mc.h    |  34 ++++++++++++++
> >>>>  3 files changed, 146 insertions(+)
> >>>
> >>> Do we know if this is actually necessary? I remember having a discussion
> >>> with Arnd Bergmann a while ago, and the Linux driver model kind of
> >>> assumes that by the time a device is disabled all outstanding accesses
> >>> will have stopped.
> >>>
> >>> Do we have a way to determine that this even makes a difference? Can we
> >>> trigger a case where not doing this would cause breakage and see that
> >>> adding this fixes that particular issue?
> >>>
> >>
> >> Most likely it is. The memory controller can still be processing requests
> >> when the peripheral domain is powergated. This would mean the response cannot
> >> be delivered in that case. So we need to be sure there are no outstanding
> >> requests before shutting down the domain.
> > 
> > My point is that that's the driver's responsibility anyway, hence making
> > the explicit flush unnecessary.
> 
> I see your point and it is interesting. The trouble is that we would
> need to test every memory client in every power domain to prove this. So
> I don't think that is a trivial thing to do. Furthermore, looking at
> what we have done in kernel used for android products (which probably
> stress PM the most) this is done and so I don't know of any shipping
> product that stresses PM that does not do this. May be someone else
> might. I personally would not be comfortable removing this without
> testing, but as I mentioned it is not a trivial thing to test correctly.
> However, I will let you and the other maintainers decide what's best here.

Quite frankly, I'm fairly sure most of this is untested anyway. There
isn't a good way to test gr3d for example.

Generally I lean towards not merging any code that we don't know is
needed. Merely because Android kernels do something doesn't mean it is
necessary to do it (or even sane in some cases).

Now I understand that it might be difficult to test this, but that's all
the more reason not to include the code. If we find that we have bugs
that this can fix, then we can come up with tests to trigger it and
validate that the fix actually fixes something.

In other words, I don't think it makes sense to implement mechanisms to
recover from situations that we have no way of triggering in the first
place.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* [PATCH V3 02/19] memory: tegra: Add MC flush support
@ 2015-07-20  9:17                 ` Thierry Reding
  0 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-20  9:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 20, 2015 at 09:46:02AM +0100, Jon Hunter wrote:
> 
> On 17/07/15 12:31, Thierry Reding wrote:
> > * PGP Signed by an unknown key
> > 
> > On Fri, Jul 17, 2015 at 01:20:49PM +0300, Peter De Schrijver wrote:
> >> On Fri, Jul 17, 2015 at 11:57:55AM +0200, Thierry Reding wrote:
> >>>> Old Signed by an unknown key
> >>>
> >>> On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
> >>>> The Tegra memory controller implements a flush feature to flush pending
> >>>> accesses and prevent further accesses from occurring. This feature is
> >>>> used when powering down IP blocks to ensure the IP block is in a good
> >>>> state. The flushes are organised by software groups and IP blocks are
> >>>> assigned in hardware to the different software groups. Add helper
> >>>> functions for requesting a handle to an MC flush for a given
> >>>> software group and enabling/disabling the MC flush itself.
> >>>>
> >>>> This is based upon a change by Vince Hsu <vinceh@nvidia.com>.
> >>>>
> >>>> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> >>>> ---
> >>>>  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
> >>>>  drivers/memory/tegra/mc.h |   2 +
> >>>>  include/soc/tegra/mc.h    |  34 ++++++++++++++
> >>>>  3 files changed, 146 insertions(+)
> >>>
> >>> Do we know if this is actually necessary? I remember having a discussion
> >>> with Arnd Bergmann a while ago, and the Linux driver model kind of
> >>> assumes that by the time a device is disabled all outstanding accesses
> >>> will have stopped.
> >>>
> >>> Do we have a way to determine that this even makes a difference? Can we
> >>> trigger a case where not doing this would cause breakage and see that
> >>> adding this fixes that particular issue?
> >>>
> >>
> >> Most likely it is. The memory controller can still be processing requests
> >> when the peripheral domain is powergated. This would mean the response cannot
> >> be delivered in that case. So we need to be sure there are no outstanding
> >> requests before shutting down the domain.
> > 
> > My point is that that's the driver's responsibility anyway, hence making
> > the explicit flush unnecessary.
> 
> I see your point and it is interesting. The trouble is that we would
> need to test every memory client in every power domain to prove this. So
> I don't think that is a trivial thing to do. Furthermore, looking at
> what we have done in kernel used for android products (which probably
> stress PM the most) this is done and so I don't know of any shipping
> product that stresses PM that does not do this. May be someone else
> might. I personally would not be comfortable removing this without
> testing, but as I mentioned it is not a trivial thing to test correctly.
> However, I will let you and the other maintainers decide what's best here.

Quite frankly, I'm fairly sure most of this is untested anyway. There
isn't a good way to test gr3d for example.

Generally I lean towards not merging any code that we don't know is
needed. Merely because Android kernels do something doesn't mean it is
necessary to do it (or even sane in some cases).

Now I understand that it might be difficult to test this, but that's all
the more reason not to include the code. If we find that we have bugs
that this can fix, then we can come up with tests to trigger it and
validate that the fix actually fixes something.

In other words, I don't think it makes sense to implement mechanisms to
recover from situations that we have no way of triggering in the first
place.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150720/0c490974/attachment.sig>

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

* Re: [PATCH V3 02/19] memory: tegra: Add MC flush support
  2015-07-17 11:31             ` Thierry Reding
@ 2015-07-20  9:59               ` Peter De Schrijver
  -1 siblings, 0 replies; 110+ messages in thread
From: Peter De Schrijver @ 2015-07-20  9:59 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Jon Hunter, Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra, devicetree, linux-arm-kernel, linux-pm

On Fri, Jul 17, 2015 at 01:31:24PM +0200, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Fri, Jul 17, 2015 at 01:20:49PM +0300, Peter De Schrijver wrote:
> > On Fri, Jul 17, 2015 at 11:57:55AM +0200, Thierry Reding wrote:
> > > > Old Signed by an unknown key
> > > 
> > > On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
> > > > The Tegra memory controller implements a flush feature to flush pending
> > > > accesses and prevent further accesses from occurring. This feature is
> > > > used when powering down IP blocks to ensure the IP block is in a good
> > > > state. The flushes are organised by software groups and IP blocks are
> > > > assigned in hardware to the different software groups. Add helper
> > > > functions for requesting a handle to an MC flush for a given
> > > > software group and enabling/disabling the MC flush itself.
> > > > 
> > > > This is based upon a change by Vince Hsu <vinceh@nvidia.com>.
> > > > 
> > > > Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> > > > ---
> > > >  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
> > > >  drivers/memory/tegra/mc.h |   2 +
> > > >  include/soc/tegra/mc.h    |  34 ++++++++++++++
> > > >  3 files changed, 146 insertions(+)
> > > 
> > > Do we know if this is actually necessary? I remember having a discussion
> > > with Arnd Bergmann a while ago, and the Linux driver model kind of
> > > assumes that by the time a device is disabled all outstanding accesses
> > > will have stopped.
> > > 
> > > Do we have a way to determine that this even makes a difference? Can we
> > > trigger a case where not doing this would cause breakage and see that
> > > adding this fixes that particular issue?
> > > 
> > 
> > Most likely it is. The memory controller can still be processing requests
> > when the peripheral domain is powergated. This would mean the response cannot
> > be delivered in that case. So we need to be sure there are no outstanding
> > requests before shutting down the domain.
> 
> My point is that that's the driver's responsibility anyway, hence making
> the explicit flush unnecessary.
> 

The peripheral driver doesn't know how long a request is queued in the memory
controller. So it can't be responsible for ensuring this.

Cheers,

Peter.

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

* [PATCH V3 02/19] memory: tegra: Add MC flush support
@ 2015-07-20  9:59               ` Peter De Schrijver
  0 siblings, 0 replies; 110+ messages in thread
From: Peter De Schrijver @ 2015-07-20  9:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 17, 2015 at 01:31:24PM +0200, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Fri, Jul 17, 2015 at 01:20:49PM +0300, Peter De Schrijver wrote:
> > On Fri, Jul 17, 2015 at 11:57:55AM +0200, Thierry Reding wrote:
> > > > Old Signed by an unknown key
> > > 
> > > On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
> > > > The Tegra memory controller implements a flush feature to flush pending
> > > > accesses and prevent further accesses from occurring. This feature is
> > > > used when powering down IP blocks to ensure the IP block is in a good
> > > > state. The flushes are organised by software groups and IP blocks are
> > > > assigned in hardware to the different software groups. Add helper
> > > > functions for requesting a handle to an MC flush for a given
> > > > software group and enabling/disabling the MC flush itself.
> > > > 
> > > > This is based upon a change by Vince Hsu <vinceh@nvidia.com>.
> > > > 
> > > > Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> > > > ---
> > > >  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
> > > >  drivers/memory/tegra/mc.h |   2 +
> > > >  include/soc/tegra/mc.h    |  34 ++++++++++++++
> > > >  3 files changed, 146 insertions(+)
> > > 
> > > Do we know if this is actually necessary? I remember having a discussion
> > > with Arnd Bergmann a while ago, and the Linux driver model kind of
> > > assumes that by the time a device is disabled all outstanding accesses
> > > will have stopped.
> > > 
> > > Do we have a way to determine that this even makes a difference? Can we
> > > trigger a case where not doing this would cause breakage and see that
> > > adding this fixes that particular issue?
> > > 
> > 
> > Most likely it is. The memory controller can still be processing requests
> > when the peripheral domain is powergated. This would mean the response cannot
> > be delivered in that case. So we need to be sure there are no outstanding
> > requests before shutting down the domain.
> 
> My point is that that's the driver's responsibility anyway, hence making
> the explicit flush unnecessary.
> 

The peripheral driver doesn't know how long a request is queued in the memory
controller. So it can't be responsible for ensuring this.

Cheers,

Peter.

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

* Re: [PATCH V3 02/19] memory: tegra: Add MC flush support
  2015-07-20  9:59               ` Peter De Schrijver
@ 2015-07-20 13:14                   ` Thierry Reding
  -1 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-20 13:14 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Jon Hunter, Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 3264 bytes --]

On Mon, Jul 20, 2015 at 12:59:41PM +0300, Peter De Schrijver wrote:
> On Fri, Jul 17, 2015 at 01:31:24PM +0200, Thierry Reding wrote:
> > * PGP Signed by an unknown key
> > 
> > On Fri, Jul 17, 2015 at 01:20:49PM +0300, Peter De Schrijver wrote:
> > > On Fri, Jul 17, 2015 at 11:57:55AM +0200, Thierry Reding wrote:
> > > > > Old Signed by an unknown key
> > > > 
> > > > On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
> > > > > The Tegra memory controller implements a flush feature to flush pending
> > > > > accesses and prevent further accesses from occurring. This feature is
> > > > > used when powering down IP blocks to ensure the IP block is in a good
> > > > > state. The flushes are organised by software groups and IP blocks are
> > > > > assigned in hardware to the different software groups. Add helper
> > > > > functions for requesting a handle to an MC flush for a given
> > > > > software group and enabling/disabling the MC flush itself.
> > > > > 
> > > > > This is based upon a change by Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>.
> > > > > 
> > > > > Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> > > > > ---
> > > > >  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
> > > > >  drivers/memory/tegra/mc.h |   2 +
> > > > >  include/soc/tegra/mc.h    |  34 ++++++++++++++
> > > > >  3 files changed, 146 insertions(+)
> > > > 
> > > > Do we know if this is actually necessary? I remember having a discussion
> > > > with Arnd Bergmann a while ago, and the Linux driver model kind of
> > > > assumes that by the time a device is disabled all outstanding accesses
> > > > will have stopped.
> > > > 
> > > > Do we have a way to determine that this even makes a difference? Can we
> > > > trigger a case where not doing this would cause breakage and see that
> > > > adding this fixes that particular issue?
> > > > 
> > > 
> > > Most likely it is. The memory controller can still be processing requests
> > > when the peripheral domain is powergated. This would mean the response cannot
> > > be delivered in that case. So we need to be sure there are no outstanding
> > > requests before shutting down the domain.
> > 
> > My point is that that's the driver's responsibility anyway, hence making
> > the explicit flush unnecessary.
> > 
> 
> The peripheral driver doesn't know how long a request is queued in the memory
> controller. So it can't be responsible for ensuring this.

Surely whenever the peripheral reports that the operation is done (be
that via some DMA controller interrupt or syncpoint increment) the
operation would have flushed from the memory controller. Drivers are
already supposed to make sure this is the case when they are removed or
suspended, so this would mean that we'd be adding all this code for no
real gain.

It would also explain why we're currently not seeing any such problems.

Also note that I'm not saying no to this, I merely want to make sure
that it's necessary, and in order to prove so we need tests to produce
enough traffic for this to be exposed, and then we can also verify that
the patches actually do what they're supposed to.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* [PATCH V3 02/19] memory: tegra: Add MC flush support
@ 2015-07-20 13:14                   ` Thierry Reding
  0 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-20 13:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 20, 2015 at 12:59:41PM +0300, Peter De Schrijver wrote:
> On Fri, Jul 17, 2015 at 01:31:24PM +0200, Thierry Reding wrote:
> > * PGP Signed by an unknown key
> > 
> > On Fri, Jul 17, 2015 at 01:20:49PM +0300, Peter De Schrijver wrote:
> > > On Fri, Jul 17, 2015 at 11:57:55AM +0200, Thierry Reding wrote:
> > > > > Old Signed by an unknown key
> > > > 
> > > > On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
> > > > > The Tegra memory controller implements a flush feature to flush pending
> > > > > accesses and prevent further accesses from occurring. This feature is
> > > > > used when powering down IP blocks to ensure the IP block is in a good
> > > > > state. The flushes are organised by software groups and IP blocks are
> > > > > assigned in hardware to the different software groups. Add helper
> > > > > functions for requesting a handle to an MC flush for a given
> > > > > software group and enabling/disabling the MC flush itself.
> > > > > 
> > > > > This is based upon a change by Vince Hsu <vinceh@nvidia.com>.
> > > > > 
> > > > > Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> > > > > ---
> > > > >  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
> > > > >  drivers/memory/tegra/mc.h |   2 +
> > > > >  include/soc/tegra/mc.h    |  34 ++++++++++++++
> > > > >  3 files changed, 146 insertions(+)
> > > > 
> > > > Do we know if this is actually necessary? I remember having a discussion
> > > > with Arnd Bergmann a while ago, and the Linux driver model kind of
> > > > assumes that by the time a device is disabled all outstanding accesses
> > > > will have stopped.
> > > > 
> > > > Do we have a way to determine that this even makes a difference? Can we
> > > > trigger a case where not doing this would cause breakage and see that
> > > > adding this fixes that particular issue?
> > > > 
> > > 
> > > Most likely it is. The memory controller can still be processing requests
> > > when the peripheral domain is powergated. This would mean the response cannot
> > > be delivered in that case. So we need to be sure there are no outstanding
> > > requests before shutting down the domain.
> > 
> > My point is that that's the driver's responsibility anyway, hence making
> > the explicit flush unnecessary.
> > 
> 
> The peripheral driver doesn't know how long a request is queued in the memory
> controller. So it can't be responsible for ensuring this.

Surely whenever the peripheral reports that the operation is done (be
that via some DMA controller interrupt or syncpoint increment) the
operation would have flushed from the memory controller. Drivers are
already supposed to make sure this is the case when they are removed or
suspended, so this would mean that we'd be adding all this code for no
real gain.

It would also explain why we're currently not seeing any such problems.

Also note that I'm not saying no to this, I merely want to make sure
that it's necessary, and in order to prove so we need tests to produce
enough traffic for this to be exposed, and then we can also verify that
the patches actually do what they're supposed to.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150720/5cb9197d/attachment-0001.sig>

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

* Re: [PATCH V3 03/19] memory: tegra: add flush operation for Tegra30 memory clients
  2015-07-17 10:03         ` Thierry Reding
@ 2015-07-21  8:54           ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-21  8:54 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA


On 17/07/15 11:03, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Mon, Jul 13, 2015 at 01:39:41PM +0100, Jon Hunter wrote:
>> From: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
>>
>> This patch adds the hot reset register table and flush related callback
>> functions for Tegra30.
>>
>> Signed-off-by: Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
>> [jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org: Removed tegra_mc_ops and added
>>  metastable_flush_reads.]
>> Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
>>
>> ---
>> v3: removal of tegra_mc_ops
>> ---
>>  drivers/memory/tegra/tegra30.c | 24 ++++++++++++++++++++++++
>>  1 file changed, 24 insertions(+)
>>
>> diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
>> index 1abcd8f6f3ba..3b4987f39b52 100644
>> --- a/drivers/memory/tegra/tegra30.c
>> +++ b/drivers/memory/tegra/tegra30.c
>> @@ -6,6 +6,7 @@
>>   * published by the Free Software Foundation.
>>   */
>>  
>> +#include <linux/device.h>
> 
> What do you need this for?

Looks like I forgot to remove this, when removing the tegra_mc_ops.
Thanks, will remove.

>>  #include <linux/of.h>
>>  #include <linux/mm.h>
>>  
>> @@ -936,6 +937,26 @@ static const struct tegra_smmu_swgroup tegra30_swgroups[] = {
>>  	{ .name = "isp",  .swgroup = TEGRA_SWGROUP_ISP,  .reg = 0x258 },
>>  };
>>  
>> +static struct tegra_mc_flush tegra30_mc_flush[] = {
> 
> const

Yes, will fix.

>> +	{TEGRA_SWGROUP_AFI,        0x200, 0x204,  0},
>> +	{TEGRA_SWGROUP_AVPC,       0x200, 0x204,  1},
>> +	{TEGRA_SWGROUP_DC,         0x200, 0x204,  2},
>> +	{TEGRA_SWGROUP_DCB,        0x200, 0x204,  3},
>> +	{TEGRA_SWGROUP_EPP,        0x200, 0x204,  4},
>> +	{TEGRA_SWGROUP_G2,         0x200, 0x204,  5},
>> +	{TEGRA_SWGROUP_HC,         0x200, 0x204,  6},
>> +	{TEGRA_SWGROUP_HDA,        0x200, 0x204,  7},
>> +	{TEGRA_SWGROUP_ISP,        0x200, 0x204,  8},
>> +	{TEGRA_SWGROUP_MPCORE,     0x200, 0x204,  9},
>> +	{TEGRA_SWGROUP_MPCORELP,   0x200, 0x204, 10},
>> +	{TEGRA_SWGROUP_MPE,        0x200, 0x204, 11},
>> +	{TEGRA_SWGROUP_NV,         0x200, 0x204, 12},
>> +	{TEGRA_SWGROUP_NV2,        0x200, 0x204, 13},
>> +	{TEGRA_SWGROUP_PPCS,       0x200, 0x204, 14},
>> +	{TEGRA_SWGROUP_VDE,        0x200, 0x204, 16},
>> +	{TEGRA_SWGROUP_VI,         0x200, 0x204, 17},
> 
> Spaces around { and }, please.

Ok.

Cheers
Jon

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

* [PATCH V3 03/19] memory: tegra: add flush operation for Tegra30 memory clients
@ 2015-07-21  8:54           ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-21  8:54 UTC (permalink / raw)
  To: linux-arm-kernel


On 17/07/15 11:03, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Mon, Jul 13, 2015 at 01:39:41PM +0100, Jon Hunter wrote:
>> From: Vince Hsu <vinceh@nvidia.com>
>>
>> This patch adds the hot reset register table and flush related callback
>> functions for Tegra30.
>>
>> Signed-off-by: Vince Hsu <vinceh@nvidia.com>
>> [jonathanh at nvidia.com: Removed tegra_mc_ops and added
>>  metastable_flush_reads.]
>> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
>>
>> ---
>> v3: removal of tegra_mc_ops
>> ---
>>  drivers/memory/tegra/tegra30.c | 24 ++++++++++++++++++++++++
>>  1 file changed, 24 insertions(+)
>>
>> diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
>> index 1abcd8f6f3ba..3b4987f39b52 100644
>> --- a/drivers/memory/tegra/tegra30.c
>> +++ b/drivers/memory/tegra/tegra30.c
>> @@ -6,6 +6,7 @@
>>   * published by the Free Software Foundation.
>>   */
>>  
>> +#include <linux/device.h>
> 
> What do you need this for?

Looks like I forgot to remove this, when removing the tegra_mc_ops.
Thanks, will remove.

>>  #include <linux/of.h>
>>  #include <linux/mm.h>
>>  
>> @@ -936,6 +937,26 @@ static const struct tegra_smmu_swgroup tegra30_swgroups[] = {
>>  	{ .name = "isp",  .swgroup = TEGRA_SWGROUP_ISP,  .reg = 0x258 },
>>  };
>>  
>> +static struct tegra_mc_flush tegra30_mc_flush[] = {
> 
> const

Yes, will fix.

>> +	{TEGRA_SWGROUP_AFI,        0x200, 0x204,  0},
>> +	{TEGRA_SWGROUP_AVPC,       0x200, 0x204,  1},
>> +	{TEGRA_SWGROUP_DC,         0x200, 0x204,  2},
>> +	{TEGRA_SWGROUP_DCB,        0x200, 0x204,  3},
>> +	{TEGRA_SWGROUP_EPP,        0x200, 0x204,  4},
>> +	{TEGRA_SWGROUP_G2,         0x200, 0x204,  5},
>> +	{TEGRA_SWGROUP_HC,         0x200, 0x204,  6},
>> +	{TEGRA_SWGROUP_HDA,        0x200, 0x204,  7},
>> +	{TEGRA_SWGROUP_ISP,        0x200, 0x204,  8},
>> +	{TEGRA_SWGROUP_MPCORE,     0x200, 0x204,  9},
>> +	{TEGRA_SWGROUP_MPCORELP,   0x200, 0x204, 10},
>> +	{TEGRA_SWGROUP_MPE,        0x200, 0x204, 11},
>> +	{TEGRA_SWGROUP_NV,         0x200, 0x204, 12},
>> +	{TEGRA_SWGROUP_NV2,        0x200, 0x204, 13},
>> +	{TEGRA_SWGROUP_PPCS,       0x200, 0x204, 14},
>> +	{TEGRA_SWGROUP_VDE,        0x200, 0x204, 16},
>> +	{TEGRA_SWGROUP_VI,         0x200, 0x204, 17},
> 
> Spaces around { and }, please.

Ok.

Cheers
Jon

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

* Re: [PATCH V3 07/19] soc: tegra: pmc: Wait for powergate state to change
  2015-07-17 10:17         ` Thierry Reding
@ 2015-07-21  9:34           ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-21  9:34 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Alexandre Courbot, Ulf Hansson, Prashant Gaikwad,
	Terje Bergström, Vince Hsu, Stephen Warren, linux-tegra,
	Peter De Schrijver, Kevin Hilman, Rafael J. Wysocki,
	Hans de Goede, devicetree, Philipp Zabel, linux-pm, Tejun Heo,
	linux-arm-kernel


On 17/07/15 11:17, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Mon, Jul 13, 2015 at 01:39:45PM +0100, Jon Hunter wrote:
>> Currently, the function tegra_powergate_set() simply sets the desired
>> powergate state but does not wait for the state to change. In some
>> circumstances this can be desirable. However, in most cases we should
>> wait for the state to change before proceeding. Therefore, add a
>> parameter to tegra_powergate_set() to indicate whether we should wait
>> for the state to change.
>>
>> By adding this feature, we can also eliminate the polling loop from
>> tegra30_boot_secondary().
>>
>> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
>> ---
>>  arch/arm/mach-tegra/platsmp.c | 18 ++++--------------
>>  drivers/soc/tegra/pmc.c       | 29 +++++++++++++++++++++++------
>>  include/soc/tegra/pmc.h       |  2 +-
>>  3 files changed, 28 insertions(+), 21 deletions(-)
>>
>> diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
>> index b45086666648..13982b5936c0 100644
>> --- a/arch/arm/mach-tegra/platsmp.c
>> +++ b/arch/arm/mach-tegra/platsmp.c
>> @@ -108,19 +108,9 @@ static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle)
>>  	 * be un-gated by un-toggling the power gate register
>>  	 * manually.
>>  	 */
>> -	if (!tegra_pmc_cpu_is_powered(cpu)) {
>> -		ret = tegra_pmc_cpu_power_on(cpu);
>> -		if (ret)
>> -			return ret;
>> -
>> -		/* Wait for the power to come up. */
>> -		timeout = jiffies + msecs_to_jiffies(100);
>> -		while (!tegra_pmc_cpu_is_powered(cpu)) {
>> -			if (time_after(jiffies, timeout))
>> -				return -ETIMEDOUT;
>> -			udelay(10);
>> -		}
>> -	}
>> +	ret = tegra_pmc_cpu_power_on(cpu, true);
>> +	if (ret)
>> +		return ret;
>>  
>>  remove_clamps:
>>  	/* CPU partition is powered. Enable the CPU clock. */
>> @@ -162,7 +152,7 @@ static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle)
>>  		 * also initial power state in flow controller. After that,
>>  		 * the CPU's power state is maintained by flow controller.
>>  		 */
>> -		ret = tegra_pmc_cpu_power_on(cpu);
>> +		ret = tegra_pmc_cpu_power_on(cpu, false);
>>  	}
>>  
>>  	return ret;
>> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
>> index 300f11e0c3bb..c0635bdd4ee3 100644
>> --- a/drivers/soc/tegra/pmc.c
>> +++ b/drivers/soc/tegra/pmc.c
>> @@ -175,9 +175,11 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
>>   * @id: partition ID
>>   * @new_state: new state of the partition
> 
> The comment here isn't updated.
> 
>>   */
>> -static int tegra_powergate_set(int id, bool new_state)
>> +static int tegra_powergate_set(int id, bool new_state, bool wait)
> 
> Can we please not chain boolean parameters, it makes the call sites
> impossible to parse for humans. Instead, can we simply leave
> tegra_powergate_set() as it is and add another function, such as
> tegra_powergate_set_sync() or tegra_powergate_set_and_wait(), to achieve
> the same? You may have to split out a tegra_powergate_set_unlocked() or
> similar to make sure you get to keep the lock across both operations:
> 
> 	static int tegra_powergate_set_unlocked(int id, bool new_state)
> 	{
> 		...
> 	}
> 
> 	static int tegra_powergate_set(int id, bool new_state)
> 	{
> 		int err;
> 
> 		mutex_lock(&pmc->powergates_lock);
> 		err = tegra_powergate_set_unlocked(id, new_state);
> 		mutex_unlock(&pmc->powergates_lock);
> 
> 		return err;
> 	}
> 
> 	/*
> 	 * Must be called with pmc->powergates_lock mutex held.
> 	 */
> 	static int tegra_powergate_wait(int id, bool new_state)
> 	{
> 		...
> 	}
> 
> 	static int tegra_powergate_set_and_wait(int id, bool new_state)
> 	{
> 		int err;
> 
> 		mutex_lock(&pmc->powergates_lock);
> 
> 		err = tegra_powergate_set_unlocked(id, new_state);
> 		if (err < 0)
> 			goto unlock;
> 
> 		err = tegra_powergate_wait(id, new_state);
> 		if (err < 0)
> 			goto unlock;
> 
> 	unlock:
> 		mutex_unlock(&pmc->powergates_lock);
> 		return err;
> 	}
> 
>>  {
>> +	unsigned long timeout;
>>  	bool status;
>> +	int ret = 0;
>>  
>>  	mutex_lock(&pmc->powergates_lock);
>>  
>> @@ -190,9 +192,23 @@ static int tegra_powergate_set(int id, bool new_state)
>>  
>>  	tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
>>  
>> +	if (wait) {
>> +		timeout = jiffies + msecs_to_jiffies(100);
>> +		ret = -ETIMEDOUT;
>> +
>> +		while (time_before(jiffies, timeout)) {
>> +			status = !!(tegra_pmc_readl(PWRGATE_STATUS) & BIT(id));
>> +			if (status == new_state) {
>> +				ret = 0;
>> +				break;
>> +			}
>> +			udelay(10);
>> +		}
>> +	}
>> +
>>  	mutex_unlock(&pmc->powergates_lock);
>>  
>> -	return 0;
>> +	return ret;
>>  }
>>  
>>  /**
>> @@ -204,7 +220,7 @@ int tegra_powergate_power_on(int id)
>>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>>  		return -EINVAL;
>>  
>> -	return tegra_powergate_set(id, true);
>> +	return tegra_powergate_set(id, true, true);
>>  }
>>  
>>  /**
>> @@ -216,7 +232,7 @@ int tegra_powergate_power_off(int id)
>>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>>  		return -EINVAL;
>>  
>> -	return tegra_powergate_set(id, false);
>> +	return tegra_powergate_set(id, false, true);
>>  }
>>  EXPORT_SYMBOL(tegra_powergate_power_off);
>>  
>> @@ -351,8 +367,9 @@ bool tegra_pmc_cpu_is_powered(int cpuid)
>>  /**
>>   * tegra_pmc_cpu_power_on() - power on CPU partition
>>   * @cpuid: CPU partition ID
>> + * @wait:  Wait for CPU state to transition
>>   */
>> -int tegra_pmc_cpu_power_on(int cpuid)
>> +int tegra_pmc_cpu_power_on(int cpuid, bool wait)
> 
> This one is probably fine since it's the only boolean parameter so far.
> That said, I see that we call this exactly twice, so I wonder if there'd
> be any harm in having the second occurrence wait as well and hence get
> rid of the parameter.

I would agree and think we should drop the 2nd parameter and just always
wait. This is only done at boot time and so would only add a little
delay at that point.

Cheers
Jon

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

* [PATCH V3 07/19] soc: tegra: pmc: Wait for powergate state to change
@ 2015-07-21  9:34           ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-21  9:34 UTC (permalink / raw)
  To: linux-arm-kernel


On 17/07/15 11:17, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Mon, Jul 13, 2015 at 01:39:45PM +0100, Jon Hunter wrote:
>> Currently, the function tegra_powergate_set() simply sets the desired
>> powergate state but does not wait for the state to change. In some
>> circumstances this can be desirable. However, in most cases we should
>> wait for the state to change before proceeding. Therefore, add a
>> parameter to tegra_powergate_set() to indicate whether we should wait
>> for the state to change.
>>
>> By adding this feature, we can also eliminate the polling loop from
>> tegra30_boot_secondary().
>>
>> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
>> ---
>>  arch/arm/mach-tegra/platsmp.c | 18 ++++--------------
>>  drivers/soc/tegra/pmc.c       | 29 +++++++++++++++++++++++------
>>  include/soc/tegra/pmc.h       |  2 +-
>>  3 files changed, 28 insertions(+), 21 deletions(-)
>>
>> diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
>> index b45086666648..13982b5936c0 100644
>> --- a/arch/arm/mach-tegra/platsmp.c
>> +++ b/arch/arm/mach-tegra/platsmp.c
>> @@ -108,19 +108,9 @@ static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle)
>>  	 * be un-gated by un-toggling the power gate register
>>  	 * manually.
>>  	 */
>> -	if (!tegra_pmc_cpu_is_powered(cpu)) {
>> -		ret = tegra_pmc_cpu_power_on(cpu);
>> -		if (ret)
>> -			return ret;
>> -
>> -		/* Wait for the power to come up. */
>> -		timeout = jiffies + msecs_to_jiffies(100);
>> -		while (!tegra_pmc_cpu_is_powered(cpu)) {
>> -			if (time_after(jiffies, timeout))
>> -				return -ETIMEDOUT;
>> -			udelay(10);
>> -		}
>> -	}
>> +	ret = tegra_pmc_cpu_power_on(cpu, true);
>> +	if (ret)
>> +		return ret;
>>  
>>  remove_clamps:
>>  	/* CPU partition is powered. Enable the CPU clock. */
>> @@ -162,7 +152,7 @@ static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle)
>>  		 * also initial power state in flow controller. After that,
>>  		 * the CPU's power state is maintained by flow controller.
>>  		 */
>> -		ret = tegra_pmc_cpu_power_on(cpu);
>> +		ret = tegra_pmc_cpu_power_on(cpu, false);
>>  	}
>>  
>>  	return ret;
>> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
>> index 300f11e0c3bb..c0635bdd4ee3 100644
>> --- a/drivers/soc/tegra/pmc.c
>> +++ b/drivers/soc/tegra/pmc.c
>> @@ -175,9 +175,11 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
>>   * @id: partition ID
>>   * @new_state: new state of the partition
> 
> The comment here isn't updated.
> 
>>   */
>> -static int tegra_powergate_set(int id, bool new_state)
>> +static int tegra_powergate_set(int id, bool new_state, bool wait)
> 
> Can we please not chain boolean parameters, it makes the call sites
> impossible to parse for humans. Instead, can we simply leave
> tegra_powergate_set() as it is and add another function, such as
> tegra_powergate_set_sync() or tegra_powergate_set_and_wait(), to achieve
> the same? You may have to split out a tegra_powergate_set_unlocked() or
> similar to make sure you get to keep the lock across both operations:
> 
> 	static int tegra_powergate_set_unlocked(int id, bool new_state)
> 	{
> 		...
> 	}
> 
> 	static int tegra_powergate_set(int id, bool new_state)
> 	{
> 		int err;
> 
> 		mutex_lock(&pmc->powergates_lock);
> 		err = tegra_powergate_set_unlocked(id, new_state);
> 		mutex_unlock(&pmc->powergates_lock);
> 
> 		return err;
> 	}
> 
> 	/*
> 	 * Must be called with pmc->powergates_lock mutex held.
> 	 */
> 	static int tegra_powergate_wait(int id, bool new_state)
> 	{
> 		...
> 	}
> 
> 	static int tegra_powergate_set_and_wait(int id, bool new_state)
> 	{
> 		int err;
> 
> 		mutex_lock(&pmc->powergates_lock);
> 
> 		err = tegra_powergate_set_unlocked(id, new_state);
> 		if (err < 0)
> 			goto unlock;
> 
> 		err = tegra_powergate_wait(id, new_state);
> 		if (err < 0)
> 			goto unlock;
> 
> 	unlock:
> 		mutex_unlock(&pmc->powergates_lock);
> 		return err;
> 	}
> 
>>  {
>> +	unsigned long timeout;
>>  	bool status;
>> +	int ret = 0;
>>  
>>  	mutex_lock(&pmc->powergates_lock);
>>  
>> @@ -190,9 +192,23 @@ static int tegra_powergate_set(int id, bool new_state)
>>  
>>  	tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
>>  
>> +	if (wait) {
>> +		timeout = jiffies + msecs_to_jiffies(100);
>> +		ret = -ETIMEDOUT;
>> +
>> +		while (time_before(jiffies, timeout)) {
>> +			status = !!(tegra_pmc_readl(PWRGATE_STATUS) & BIT(id));
>> +			if (status == new_state) {
>> +				ret = 0;
>> +				break;
>> +			}
>> +			udelay(10);
>> +		}
>> +	}
>> +
>>  	mutex_unlock(&pmc->powergates_lock);
>>  
>> -	return 0;
>> +	return ret;
>>  }
>>  
>>  /**
>> @@ -204,7 +220,7 @@ int tegra_powergate_power_on(int id)
>>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>>  		return -EINVAL;
>>  
>> -	return tegra_powergate_set(id, true);
>> +	return tegra_powergate_set(id, true, true);
>>  }
>>  
>>  /**
>> @@ -216,7 +232,7 @@ int tegra_powergate_power_off(int id)
>>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>>  		return -EINVAL;
>>  
>> -	return tegra_powergate_set(id, false);
>> +	return tegra_powergate_set(id, false, true);
>>  }
>>  EXPORT_SYMBOL(tegra_powergate_power_off);
>>  
>> @@ -351,8 +367,9 @@ bool tegra_pmc_cpu_is_powered(int cpuid)
>>  /**
>>   * tegra_pmc_cpu_power_on() - power on CPU partition
>>   * @cpuid: CPU partition ID
>> + * @wait:  Wait for CPU state to transition
>>   */
>> -int tegra_pmc_cpu_power_on(int cpuid)
>> +int tegra_pmc_cpu_power_on(int cpuid, bool wait)
> 
> This one is probably fine since it's the only boolean parameter so far.
> That said, I see that we call this exactly twice, so I wonder if there'd
> be any harm in having the second occurrence wait as well and hence get
> rid of the parameter.

I would agree and think we should drop the 2nd parameter and just always
wait. This is only done at boot time and so would only add a little
delay at that point.

Cheers
Jon

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

* Re: [PATCH V3 08/19] soc: tegra: pmc: Clean-up PMC helper functions
  2015-07-17 10:25       ` Thierry Reding
@ 2015-07-21  9:38         ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-21  9:38 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA


On 17/07/15 11:25, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Mon, Jul 13, 2015 at 01:39:46PM +0100, Jon Hunter wrote:
>> The following clean-ups have been made to the PMC code:
>>
>> 1. Add a macro for determining the state of a PMC powergate
>> 2. Use the readx_poll_timeout() function instead of implementing a local
>>    polling loop with a timeout.
>> 3. Use a case-statement in the function that removes the powergate clamp
>>    instead of multiple if-statements to improve readability.
>>
>> Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
>> ---
>>  drivers/soc/tegra/pmc.c | 72 ++++++++++++++++++++++++-------------------------
>>  1 file changed, 35 insertions(+), 37 deletions(-)
>>
>> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
>> index c0635bdd4ee3..180d434deec5 100644
>> --- a/drivers/soc/tegra/pmc.c
>> +++ b/drivers/soc/tegra/pmc.c
>> @@ -28,6 +28,7 @@
>>  #include <linux/export.h>
>>  #include <linux/init.h>
>>  #include <linux/io.h>
>> +#include <linux/iopoll.h>
>>  #include <linux/of.h>
>>  #include <linux/of_address.h>
>>  #include <linux/platform_device.h>
>> @@ -56,6 +57,8 @@
>>  #define  PWRGATE_TOGGLE_START		(1 << 8)
>>  
>>  #define REMOVE_CLAMPING			0x34
>> +#define  REMOVE_CLAMPING_VDEC		(1 << 3)
>> +#define  REMOVE_CLAMPING_PCIE		(1 << 4)
>>  
>>  #define PWRGATE_STATUS			0x38
>>  
>> @@ -101,6 +104,8 @@
>>  
>>  #define GPU_RG_CNTRL			0x2d4
>>  
>> +#define PMC_PWRGATE_STATE(val, id)	(!!(val & BIT(id)))
> 
> I find double-negations very difficult to read. ((value & BIT(id)) != 0)
> is clearer in my opinion. Also I'd suggest status or value as the first
> parameter name, for consistency with other parts of the driver.
> 
>> +
>>  struct tegra_pmc_soc {
>>  	unsigned int num_powergates;
>>  	const char *const *powergates;
>> @@ -177,15 +182,14 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
>>   */
>>  static int tegra_powergate_set(int id, bool new_state, bool wait)
>>  {
>> -	unsigned long timeout;
>> -	bool status;
>>  	int ret = 0;
>> +	u32 val;
>>  
>>  	mutex_lock(&pmc->powergates_lock);
>>  
>> -	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
>> +	val = tegra_pmc_readl(PWRGATE_STATUS);
>>  
>> -	if (status == new_state) {
>> +	if (PMC_PWRGATE_STATE(val, id) == new_state) {
>>  		mutex_unlock(&pmc->powergates_lock);
>>  		return 0;
>>  	}
>> @@ -193,17 +197,9 @@ static int tegra_powergate_set(int id, bool new_state, bool wait)
>>  	tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
>>  
>>  	if (wait) {
>> -		timeout = jiffies + msecs_to_jiffies(100);
>> -		ret = -ETIMEDOUT;
>> -
>> -		while (time_before(jiffies, timeout)) {
>> -			status = !!(tegra_pmc_readl(PWRGATE_STATUS) & BIT(id));
>> -			if (status == new_state) {
>> -				ret = 0;
>> -				break;
>> -			}
>> -			udelay(10);
>> -		}
>> +		ret = readx_poll_timeout(tegra_pmc_readl, PWRGATE_STATUS,
>> +				val, PMC_PWRGATE_STATE(val, id) == new_state,
>> +				10, 100000);
>>  	}
>>  
>>  	mutex_unlock(&pmc->powergates_lock);
>> @@ -242,13 +238,10 @@ EXPORT_SYMBOL(tegra_powergate_power_off);
>>   */
>>  int tegra_powergate_is_powered(int id)
>>  {
>> -	u32 status;
>> -
>>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>>  		return -EINVAL;
>>  
>> -	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
>> -	return !!status;
>> +	return PMC_PWRGATE_STATE(tegra_pmc_readl(PWRGATE_STATUS), id);
> 
> I'd prefer to keep the two steps here. As a general rule I try never to
> mix reading or writing a register with other code on the same line.
> 
>>  }
>>  
>>  /**
>> @@ -257,34 +250,39 @@ int tegra_powergate_is_powered(int id)
>>   */
>>  int tegra_powergate_remove_clamping(int id)
>>  {
>> -	u32 mask;
>> +	u32 val, reg;
> 
> Side note: Please use value instead of val since that's the form used
> elsewhere in the driver. Also reg would be more appropriately called
> offset or similar because that's what it really is. It would also be
> more naturally an unsized type, such as unsigned int. But...
> 
>>  
>>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>>  		return -EINVAL;
>>  
>>  	/*
>> -	 * On Tegra124 and later, the clamps for the GPU are controlled by a
>> -	 * separate register (with different semantics).
>> +	 * In most cases the bit for removing the IO clamping is the same as
>> +	 * the powergate partition ID, however, this is not always the case.
>> +	 * Furthermore, on Tegra124 and later, the clamps for the GPU are
>> +	 * controlled by a separate register (with different semantics). The
>> +	 * following case-statement handles these exceptions.
>>  	 */
>> -	if (id == TEGRA_POWERGATE_3D) {
>> +	val = 1 << id;
>> +	reg = REMOVE_CLAMPING;
>> +
>> +	switch (id) {
>> +	case TEGRA_POWERGATE_3D:
>>  		if (pmc->soc->has_gpu_clamps) {
>> -			tegra_pmc_writel(0, GPU_RG_CNTRL);
>> -			return 0;
>> +			val = 0;
>> +			reg  = GPU_RG_CNTRL;
>>  		}
>> +		break;
>> +	case TEGRA_POWERGATE_VDEC:
>> +		val = REMOVE_CLAMPING_VDEC;
>> +		break;
>> +	case TEGRA_POWERGATE_PCIE:
>> +		val = REMOVE_CLAMPING_PCIE;
>> +		break;
>> +	default:
>> +		break;
>>  	}
>>  
>> -	/*
>> -	 * Tegra 2 has a bug where PCIE and VDE clamping masks are
>> -	 * swapped relatively to the partition ids
>> -	 */
>> -	if (id == TEGRA_POWERGATE_VDEC)
>> -		mask = (1 << TEGRA_POWERGATE_PCIE);
>> -	else if (id == TEGRA_POWERGATE_PCIE)
>> -		mask = (1 << TEGRA_POWERGATE_VDEC);
>> -	else
>> -		mask = (1 << id);
>> -
>> -	tegra_pmc_writel(mask, REMOVE_CLAMPING);
>> +	tegra_pmc_writel(val, reg);
> 
> ... to be honest, I think the previous code was more straightforward, so
> I'd prefer if you dropped this particular hunk.

Ok, I will drop that part. Jon

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

* [PATCH V3 08/19] soc: tegra: pmc: Clean-up PMC helper functions
@ 2015-07-21  9:38         ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-21  9:38 UTC (permalink / raw)
  To: linux-arm-kernel


On 17/07/15 11:25, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Mon, Jul 13, 2015 at 01:39:46PM +0100, Jon Hunter wrote:
>> The following clean-ups have been made to the PMC code:
>>
>> 1. Add a macro for determining the state of a PMC powergate
>> 2. Use the readx_poll_timeout() function instead of implementing a local
>>    polling loop with a timeout.
>> 3. Use a case-statement in the function that removes the powergate clamp
>>    instead of multiple if-statements to improve readability.
>>
>> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
>> ---
>>  drivers/soc/tegra/pmc.c | 72 ++++++++++++++++++++++++-------------------------
>>  1 file changed, 35 insertions(+), 37 deletions(-)
>>
>> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
>> index c0635bdd4ee3..180d434deec5 100644
>> --- a/drivers/soc/tegra/pmc.c
>> +++ b/drivers/soc/tegra/pmc.c
>> @@ -28,6 +28,7 @@
>>  #include <linux/export.h>
>>  #include <linux/init.h>
>>  #include <linux/io.h>
>> +#include <linux/iopoll.h>
>>  #include <linux/of.h>
>>  #include <linux/of_address.h>
>>  #include <linux/platform_device.h>
>> @@ -56,6 +57,8 @@
>>  #define  PWRGATE_TOGGLE_START		(1 << 8)
>>  
>>  #define REMOVE_CLAMPING			0x34
>> +#define  REMOVE_CLAMPING_VDEC		(1 << 3)
>> +#define  REMOVE_CLAMPING_PCIE		(1 << 4)
>>  
>>  #define PWRGATE_STATUS			0x38
>>  
>> @@ -101,6 +104,8 @@
>>  
>>  #define GPU_RG_CNTRL			0x2d4
>>  
>> +#define PMC_PWRGATE_STATE(val, id)	(!!(val & BIT(id)))
> 
> I find double-negations very difficult to read. ((value & BIT(id)) != 0)
> is clearer in my opinion. Also I'd suggest status or value as the first
> parameter name, for consistency with other parts of the driver.
> 
>> +
>>  struct tegra_pmc_soc {
>>  	unsigned int num_powergates;
>>  	const char *const *powergates;
>> @@ -177,15 +182,14 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
>>   */
>>  static int tegra_powergate_set(int id, bool new_state, bool wait)
>>  {
>> -	unsigned long timeout;
>> -	bool status;
>>  	int ret = 0;
>> +	u32 val;
>>  
>>  	mutex_lock(&pmc->powergates_lock);
>>  
>> -	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
>> +	val = tegra_pmc_readl(PWRGATE_STATUS);
>>  
>> -	if (status == new_state) {
>> +	if (PMC_PWRGATE_STATE(val, id) == new_state) {
>>  		mutex_unlock(&pmc->powergates_lock);
>>  		return 0;
>>  	}
>> @@ -193,17 +197,9 @@ static int tegra_powergate_set(int id, bool new_state, bool wait)
>>  	tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
>>  
>>  	if (wait) {
>> -		timeout = jiffies + msecs_to_jiffies(100);
>> -		ret = -ETIMEDOUT;
>> -
>> -		while (time_before(jiffies, timeout)) {
>> -			status = !!(tegra_pmc_readl(PWRGATE_STATUS) & BIT(id));
>> -			if (status == new_state) {
>> -				ret = 0;
>> -				break;
>> -			}
>> -			udelay(10);
>> -		}
>> +		ret = readx_poll_timeout(tegra_pmc_readl, PWRGATE_STATUS,
>> +				val, PMC_PWRGATE_STATE(val, id) == new_state,
>> +				10, 100000);
>>  	}
>>  
>>  	mutex_unlock(&pmc->powergates_lock);
>> @@ -242,13 +238,10 @@ EXPORT_SYMBOL(tegra_powergate_power_off);
>>   */
>>  int tegra_powergate_is_powered(int id)
>>  {
>> -	u32 status;
>> -
>>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>>  		return -EINVAL;
>>  
>> -	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
>> -	return !!status;
>> +	return PMC_PWRGATE_STATE(tegra_pmc_readl(PWRGATE_STATUS), id);
> 
> I'd prefer to keep the two steps here. As a general rule I try never to
> mix reading or writing a register with other code on the same line.
> 
>>  }
>>  
>>  /**
>> @@ -257,34 +250,39 @@ int tegra_powergate_is_powered(int id)
>>   */
>>  int tegra_powergate_remove_clamping(int id)
>>  {
>> -	u32 mask;
>> +	u32 val, reg;
> 
> Side note: Please use value instead of val since that's the form used
> elsewhere in the driver. Also reg would be more appropriately called
> offset or similar because that's what it really is. It would also be
> more naturally an unsized type, such as unsigned int. But...
> 
>>  
>>  	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
>>  		return -EINVAL;
>>  
>>  	/*
>> -	 * On Tegra124 and later, the clamps for the GPU are controlled by a
>> -	 * separate register (with different semantics).
>> +	 * In most cases the bit for removing the IO clamping is the same as
>> +	 * the powergate partition ID, however, this is not always the case.
>> +	 * Furthermore, on Tegra124 and later, the clamps for the GPU are
>> +	 * controlled by a separate register (with different semantics). The
>> +	 * following case-statement handles these exceptions.
>>  	 */
>> -	if (id == TEGRA_POWERGATE_3D) {
>> +	val = 1 << id;
>> +	reg = REMOVE_CLAMPING;
>> +
>> +	switch (id) {
>> +	case TEGRA_POWERGATE_3D:
>>  		if (pmc->soc->has_gpu_clamps) {
>> -			tegra_pmc_writel(0, GPU_RG_CNTRL);
>> -			return 0;
>> +			val = 0;
>> +			reg  = GPU_RG_CNTRL;
>>  		}
>> +		break;
>> +	case TEGRA_POWERGATE_VDEC:
>> +		val = REMOVE_CLAMPING_VDEC;
>> +		break;
>> +	case TEGRA_POWERGATE_PCIE:
>> +		val = REMOVE_CLAMPING_PCIE;
>> +		break;
>> +	default:
>> +		break;
>>  	}
>>  
>> -	/*
>> -	 * Tegra 2 has a bug where PCIE and VDE clamping masks are
>> -	 * swapped relatively to the partition ids
>> -	 */
>> -	if (id == TEGRA_POWERGATE_VDEC)
>> -		mask = (1 << TEGRA_POWERGATE_PCIE);
>> -	else if (id == TEGRA_POWERGATE_PCIE)
>> -		mask = (1 << TEGRA_POWERGATE_VDEC);
>> -	else
>> -		mask = (1 << id);
>> -
>> -	tegra_pmc_writel(mask, REMOVE_CLAMPING);
>> +	tegra_pmc_writel(val, reg);
> 
> ... to be honest, I think the previous code was more straightforward, so
> I'd prefer if you dropped this particular hunk.

Ok, I will drop that part. Jon

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

* Re: [PATCH V3 02/19] memory: tegra: Add MC flush support
  2015-07-20 13:14                   ` Thierry Reding
@ 2015-07-21 10:57                     ` Peter De Schrijver
  -1 siblings, 0 replies; 110+ messages in thread
From: Peter De Schrijver @ 2015-07-21 10:57 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Jon Hunter, Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Prashant Gaikwad, Terje Bergström, Hans de Goede, Tejun Heo,
	Vince Hsu, Rafael J. Wysocki, Kevin Hilman, Ulf Hansson,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

On Mon, Jul 20, 2015 at 03:14:25PM +0200, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Mon, Jul 20, 2015 at 12:59:41PM +0300, Peter De Schrijver wrote:
> > On Fri, Jul 17, 2015 at 01:31:24PM +0200, Thierry Reding wrote:
> > > > Old Signed by an unknown key
> > > 
> > > On Fri, Jul 17, 2015 at 01:20:49PM +0300, Peter De Schrijver wrote:
> > > > On Fri, Jul 17, 2015 at 11:57:55AM +0200, Thierry Reding wrote:
> > > > > > Old Signed by an unknown key
> > > > > 
> > > > > On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
> > > > > > The Tegra memory controller implements a flush feature to flush pending
> > > > > > accesses and prevent further accesses from occurring. This feature is
> > > > > > used when powering down IP blocks to ensure the IP block is in a good
> > > > > > state. The flushes are organised by software groups and IP blocks are
> > > > > > assigned in hardware to the different software groups. Add helper
> > > > > > functions for requesting a handle to an MC flush for a given
> > > > > > software group and enabling/disabling the MC flush itself.
> > > > > > 
> > > > > > This is based upon a change by Vince Hsu <vinceh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>.
> > > > > > 
> > > > > > Signed-off-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> > > > > > ---
> > > > > >  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
> > > > > >  drivers/memory/tegra/mc.h |   2 +
> > > > > >  include/soc/tegra/mc.h    |  34 ++++++++++++++
> > > > > >  3 files changed, 146 insertions(+)
> > > > > 
> > > > > Do we know if this is actually necessary? I remember having a discussion
> > > > > with Arnd Bergmann a while ago, and the Linux driver model kind of
> > > > > assumes that by the time a device is disabled all outstanding accesses
> > > > > will have stopped.
> > > > > 
> > > > > Do we have a way to determine that this even makes a difference? Can we
> > > > > trigger a case where not doing this would cause breakage and see that
> > > > > adding this fixes that particular issue?
> > > > > 
> > > > 
> > > > Most likely it is. The memory controller can still be processing requests
> > > > when the peripheral domain is powergated. This would mean the response cannot
> > > > be delivered in that case. So we need to be sure there are no outstanding
> > > > requests before shutting down the domain.
> > > 
> > > My point is that that's the driver's responsibility anyway, hence making
> > > the explicit flush unnecessary.
> > > 
> > 
> > The peripheral driver doesn't know how long a request is queued in the memory
> > controller. So it can't be responsible for ensuring this.
> 
> Surely whenever the peripheral reports that the operation is done (be
> that via some DMA controller interrupt or syncpoint increment) the
> operation would have flushed from the memory controller. Drivers are
> already supposed to make sure this is the case when they are removed or
> suspended, so this would mean that we'd be adding all this code for no
> real gain.
> 

That highly depends on how the peripheral is implemented. I'm not sure we
can assume things work this way.

> It would also explain why we're currently not seeing any such problems.
> 

I don't think we are doing agressive enough powergating today to see any
problems. That might also mean we're just lucky.

Cheers,

Peter.

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

* [PATCH V3 02/19] memory: tegra: Add MC flush support
@ 2015-07-21 10:57                     ` Peter De Schrijver
  0 siblings, 0 replies; 110+ messages in thread
From: Peter De Schrijver @ 2015-07-21 10:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 20, 2015 at 03:14:25PM +0200, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Mon, Jul 20, 2015 at 12:59:41PM +0300, Peter De Schrijver wrote:
> > On Fri, Jul 17, 2015 at 01:31:24PM +0200, Thierry Reding wrote:
> > > > Old Signed by an unknown key
> > > 
> > > On Fri, Jul 17, 2015 at 01:20:49PM +0300, Peter De Schrijver wrote:
> > > > On Fri, Jul 17, 2015 at 11:57:55AM +0200, Thierry Reding wrote:
> > > > > > Old Signed by an unknown key
> > > > > 
> > > > > On Mon, Jul 13, 2015 at 01:39:40PM +0100, Jon Hunter wrote:
> > > > > > The Tegra memory controller implements a flush feature to flush pending
> > > > > > accesses and prevent further accesses from occurring. This feature is
> > > > > > used when powering down IP blocks to ensure the IP block is in a good
> > > > > > state. The flushes are organised by software groups and IP blocks are
> > > > > > assigned in hardware to the different software groups. Add helper
> > > > > > functions for requesting a handle to an MC flush for a given
> > > > > > software group and enabling/disabling the MC flush itself.
> > > > > > 
> > > > > > This is based upon a change by Vince Hsu <vinceh@nvidia.com>.
> > > > > > 
> > > > > > Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> > > > > > ---
> > > > > >  drivers/memory/tegra/mc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
> > > > > >  drivers/memory/tegra/mc.h |   2 +
> > > > > >  include/soc/tegra/mc.h    |  34 ++++++++++++++
> > > > > >  3 files changed, 146 insertions(+)
> > > > > 
> > > > > Do we know if this is actually necessary? I remember having a discussion
> > > > > with Arnd Bergmann a while ago, and the Linux driver model kind of
> > > > > assumes that by the time a device is disabled all outstanding accesses
> > > > > will have stopped.
> > > > > 
> > > > > Do we have a way to determine that this even makes a difference? Can we
> > > > > trigger a case where not doing this would cause breakage and see that
> > > > > adding this fixes that particular issue?
> > > > > 
> > > > 
> > > > Most likely it is. The memory controller can still be processing requests
> > > > when the peripheral domain is powergated. This would mean the response cannot
> > > > be delivered in that case. So we need to be sure there are no outstanding
> > > > requests before shutting down the domain.
> > > 
> > > My point is that that's the driver's responsibility anyway, hence making
> > > the explicit flush unnecessary.
> > > 
> > 
> > The peripheral driver doesn't know how long a request is queued in the memory
> > controller. So it can't be responsible for ensuring this.
> 
> Surely whenever the peripheral reports that the operation is done (be
> that via some DMA controller interrupt or syncpoint increment) the
> operation would have flushed from the memory controller. Drivers are
> already supposed to make sure this is the case when they are removed or
> suspended, so this would mean that we'd be adding all this code for no
> real gain.
> 

That highly depends on how the peripheral is implemented. I'm not sure we
can assume things work this way.

> It would also explain why we're currently not seeing any such problems.
> 

I don't think we are doing agressive enough powergating today to see any
problems. That might also mean we're just lucky.

Cheers,

Peter.

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

* Re: [PATCH V3 10/19] drm/tegra: dc: Prepare for generic PM domains
  2015-07-17 10:41       ` Thierry Reding
@ 2015-07-28  8:30         ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-28  8:30 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA


On 17/07/15 11:41, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Mon, Jul 13, 2015 at 01:39:48PM +0100, Jon Hunter wrote:
>> Add support to the tegra dc driver for generic PM domains. However,
>> to ensure backward compatibility with older device tree blobs ensure
>> that the driver can work with or without generic PM domains. In order
>> to migrate to generic PM domain infrastructure the necessary changes
>> are:
>>
>> 1. If the "power-domains" property is present in the DT device node then
>>    generic PM domains is supported and pm_runtime_enable() should be
>>    called for the device. Furthermore, the enabling and disabling of the
>>    power-domain is handled via calling pm_runtime_get/put, respectively.
> 
> The device could be PM runtime enabled even if no power-domains property
> is set. Couldn't we check something more direct, like for example if the
> dev->pm_domain is non-NULL?

Yes could do that instead.

> Perhaps it'd be worth converting the driver to use runtime PM first, and
> move all the powergate and clock handling into suspend/resume functions,
> and then we can conditionalize whether or not we call the legacy API iff
> dev->pm_domain == NULL?

May be that would be a cleaner transition than trying to do it all in
one go.

>> 2. To ensure that clocks are managed consistently when generic PM domains
>>    are used and are not used, drivers should be migrated to use the
>>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>>    functions instead of the current tegra_powergate_sequence_power_up()
>>    and tegra_powergate_power_off(). The purpose of the
>>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>>    APIs is to mimick the behaviour of the tegra generic power-domain code,
>>    such that if generic power domains are not supported the functionality
>>    is the same.
>>
>> 3. The main difference between the tegra_powergate_sequence_power_up() API
>>    and the tegra_powergate_power_on_legacy() is that the clock used to
>>    enable the powergate is not kept enabled when using the
>>    tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
>>    the clocks they need after calling tegra_powergate_power_on_legacy()
>>    and disable these clocks before calling
>>    tegra_powergate_power_off_legacy().
> 
> This seems like it should go into the previous patch. I'm not sure I
> understand why this is necessary. Wouldn't it be easier to update the
> drivers to properly cope with this? We'll need to move them to runtime
> PM at some point anyway, so if we do that first, we should be able to
> hide all these details within the driver's suspend/resume functions
> but without the need for the API churn here.

I will take a look at that. I was trying to get the clock handling in
the driver to be consistent when generic power domains are used and when
they are not. However, may be that is not a big deal.

Jon

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

* [PATCH V3 10/19] drm/tegra: dc: Prepare for generic PM domains
@ 2015-07-28  8:30         ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-28  8:30 UTC (permalink / raw)
  To: linux-arm-kernel


On 17/07/15 11:41, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Mon, Jul 13, 2015 at 01:39:48PM +0100, Jon Hunter wrote:
>> Add support to the tegra dc driver for generic PM domains. However,
>> to ensure backward compatibility with older device tree blobs ensure
>> that the driver can work with or without generic PM domains. In order
>> to migrate to generic PM domain infrastructure the necessary changes
>> are:
>>
>> 1. If the "power-domains" property is present in the DT device node then
>>    generic PM domains is supported and pm_runtime_enable() should be
>>    called for the device. Furthermore, the enabling and disabling of the
>>    power-domain is handled via calling pm_runtime_get/put, respectively.
> 
> The device could be PM runtime enabled even if no power-domains property
> is set. Couldn't we check something more direct, like for example if the
> dev->pm_domain is non-NULL?

Yes could do that instead.

> Perhaps it'd be worth converting the driver to use runtime PM first, and
> move all the powergate and clock handling into suspend/resume functions,
> and then we can conditionalize whether or not we call the legacy API iff
> dev->pm_domain == NULL?

May be that would be a cleaner transition than trying to do it all in
one go.

>> 2. To ensure that clocks are managed consistently when generic PM domains
>>    are used and are not used, drivers should be migrated to use the
>>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>>    functions instead of the current tegra_powergate_sequence_power_up()
>>    and tegra_powergate_power_off(). The purpose of the
>>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>>    APIs is to mimick the behaviour of the tegra generic power-domain code,
>>    such that if generic power domains are not supported the functionality
>>    is the same.
>>
>> 3. The main difference between the tegra_powergate_sequence_power_up() API
>>    and the tegra_powergate_power_on_legacy() is that the clock used to
>>    enable the powergate is not kept enabled when using the
>>    tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
>>    the clocks they need after calling tegra_powergate_power_on_legacy()
>>    and disable these clocks before calling
>>    tegra_powergate_power_off_legacy().
> 
> This seems like it should go into the previous patch. I'm not sure I
> understand why this is necessary. Wouldn't it be easier to update the
> drivers to properly cope with this? We'll need to move them to runtime
> PM at some point anyway, so if we do that first, we should be able to
> hide all these details within the driver's suspend/resume functions
> but without the need for the API churn here.

I will take a look at that. I was trying to get the clock handling in
the driver to be consistent when generic power domains are used and when
they are not. However, may be that is not a big deal.

Jon

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

* Re: [PATCH V3 11/19] PCI: tegra: Add support for generic PM domains
  2015-07-17 10:45     ` Thierry Reding
@ 2015-07-28  8:35       ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-28  8:35 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra, devicetree,
	linux-arm-kernel, linux-pm


On 17/07/15 11:45, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Mon, Jul 13, 2015 at 01:39:49PM +0100, Jon Hunter wrote:
>> Add support to the tegra PCI driver for generic PM domains. However,
>> to ensure backward compatibility with older device tree blobs ensure
>> that the driver can work with or without generic PM domains. In order
>> to migrate to generic PM domain infrastructure the necessary changes
>> are:
>>
>> 1. If the "power-domains" property is present in the DT device node then
>>    generic PM domains is supported and pm_runtime_enable() should be
>>    called for the device. Furthermore, the enabling and disabling of the
>>    power-domain is handled via calling pm_runtime_get/put, respectively.
>>
>> 2. To ensure that clocks are managed consistently when generic PM domains
>>    are used and are not used, drivers should be migrated to use the
>>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>>    functions instead of the current tegra_powergate_sequence_power_up()
>>    and tegra_powergate_power_off(). The purpose of the
>>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>>    APIs is to mimick the behaviour of the tegra generic power-domain code,
>>    such that if generic power domains are not supported the functionality
>>    is the same.
>>
>> 3. The main difference between the tegra_powergate_sequence_power_up() API
>>    and the tegra_powergate_power_on_legacy() is that the clock used to
>>    enable the powergate is not kept enabled when using the
>>    tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
>>    the clocks they need after calling tegra_powergate_power_on_legacy()
>>    and disable these clocks before calling
>>    tegra_powergate_power_off_legacy().
> 
> This is the same comment as in the DRM patch, and it applies to all
> devices that use powergating, so it should move into the preparatory
> patch rather than be repeated in all patches.
> 
>>
>> The helper functions for handling the powering on and off of the PCI
>> controller have been updated to support generic PM domains. The
>> tegra_pcie_power_off() was missing code to disable the clocks enabled in
>> the tegra_pcie_power_on() function and so this has been added.
>>
>> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
>> ---
>>  drivers/pci/host/pci-tegra.c | 49 +++++++++++++++++++++++++++++++++-----------
>>  1 file changed, 37 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
>> index 10c05718dbfd..acd1f311eee5 100644
>> --- a/drivers/pci/host/pci-tegra.c
>> +++ b/drivers/pci/host/pci-tegra.c
>> @@ -40,6 +40,7 @@
>>  #include <linux/pci.h>
>>  #include <linux/phy/phy.h>
>>  #include <linux/platform_device.h>
>> +#include <linux/pm_runtime.h>
>>  #include <linux/reset.h>
>>  #include <linux/sizes.h>
>>  #include <linux/slab.h>
>> @@ -908,19 +909,32 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
>>  
>>  static void tegra_pcie_power_off(struct tegra_pcie *pcie)
>>  {
>> +	const struct tegra_pcie_soc_data *soc = pcie->soc_data;
>>  	int err;
>>  
>> -	/* TODO: disable and unprepare clocks? */
>> -
>>  	err = phy_power_off(pcie->phy);
>>  	if (err < 0)
>>  		dev_warn(pcie->dev, "failed to power off PHY: %d\n", err);
>>  
>>  	reset_control_assert(pcie->pcie_xrst);
>>  	reset_control_assert(pcie->afi_rst);
>> -	reset_control_assert(pcie->pex_rst);
>>  
>> -	tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
>> +	clk_disable_unprepare(pcie->pll_e);
>> +	if (soc->has_cml_clk)
>> +		clk_disable_unprepare(pcie->cml_clk);
>> +	clk_disable_unprepare(pcie->afi_clk);
>> +	clk_disable_unprepare(pcie->pex_clk);
>> +
>> +	if (pm_runtime_enabled(pcie->dev)) {
>> +		err = pm_runtime_put_sync(pcie->dev);
>> +	} else {
>> +		err = tegra_powergate_power_off_legacy(TEGRA_POWERGATE_PCIE,
>> +						       pcie->pex_clk,
>> +						       pcie->pex_rst);
>> +	}
>> +
>> +	if (err < 0)
>> +		dev_warn(pcie->dev, "powergate power-down failed: %d\n", err);
>>  
>>  	err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
>>  	if (err < 0)
>> @@ -934,20 +948,28 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
>>  
>>  	reset_control_assert(pcie->pcie_xrst);
>>  	reset_control_assert(pcie->afi_rst);
>> -	reset_control_assert(pcie->pex_rst);
>> -
>> -	tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
>>  
>>  	/* enable regulators */
>>  	err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies);
>>  	if (err < 0)
>>  		dev_err(pcie->dev, "failed to enable regulators: %d\n", err);
>>  
>> -	err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
>> -						pcie->pex_clk,
>> -						pcie->pex_rst);
>> -	if (err) {
>> -		dev_err(pcie->dev, "powerup sequence failed: %d\n", err);
>> +	if (pm_runtime_enabled(pcie->dev)) {
>> +		err = pm_runtime_get_sync(pcie->dev);
>> +	} else {
>> +		err = tegra_powergate_power_on_legacy(TEGRA_POWERGATE_PCIE,
>> +						      pcie->pex_clk,
>> +						      pcie->pex_rst);
>> +	}
>> +
>> +	if (err < 0) {
>> +		dev_err(pcie->dev, "powergate power-up failed: %d\n", err);
>> +		return err;
>> +	}
>> +
>> +	err = clk_prepare_enable(pcie->pex_clk);
>> +	if (err < 0) {
>> +		dev_err(pcie->dev, "failed to enable PEX clock: %d\n", err);
>>  		return err;
>>  	}
>>  
> 
> Couldn't we simply move the above code into suspend/resume functions and
> then call pm_runtime_get() and pm_runtime_put() instead of
> tegra_pcie_power_on() and tegra_pcie_power_off()?

Possibly, however, the tricky part here is the regulators. We cannot put
the regulators into the runtime resume/suspend hooks, because this would
mean that the regulators are turned on after and turned off before the
power domain. We need to have the regulator on before turning on the
power domain.

So there are two options here AFAICT:
1. Move everything above after the regulators are turned on in the
   runtime resume function.
2. Move handling of all the regulators in the generic power domain
   code.

What do you think?

>> @@ -2001,6 +2023,9 @@ static int tegra_pcie_probe(struct platform_device *pdev)
>>  
>>  	pcibios_min_mem = 0;
>>  
>> +	if (of_property_read_bool(pdev->dev.of_node, "power-domains"))
>> +		pm_runtime_enable(&pdev->dev);
> 
> Then of course we'd have to call pm_runtime_enable() irrespective of the
> property and check for the presence of power domain support via another
> method (like the dev->pm_domain field).

Ok.

Jon

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

* [PATCH V3 11/19] PCI: tegra: Add support for generic PM domains
@ 2015-07-28  8:35       ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-28  8:35 UTC (permalink / raw)
  To: linux-arm-kernel


On 17/07/15 11:45, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Mon, Jul 13, 2015 at 01:39:49PM +0100, Jon Hunter wrote:
>> Add support to the tegra PCI driver for generic PM domains. However,
>> to ensure backward compatibility with older device tree blobs ensure
>> that the driver can work with or without generic PM domains. In order
>> to migrate to generic PM domain infrastructure the necessary changes
>> are:
>>
>> 1. If the "power-domains" property is present in the DT device node then
>>    generic PM domains is supported and pm_runtime_enable() should be
>>    called for the device. Furthermore, the enabling and disabling of the
>>    power-domain is handled via calling pm_runtime_get/put, respectively.
>>
>> 2. To ensure that clocks are managed consistently when generic PM domains
>>    are used and are not used, drivers should be migrated to use the
>>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>>    functions instead of the current tegra_powergate_sequence_power_up()
>>    and tegra_powergate_power_off(). The purpose of the
>>    tegra_powergate_power_on_legacy() and tegra_powergate_power_off_legacy()
>>    APIs is to mimick the behaviour of the tegra generic power-domain code,
>>    such that if generic power domains are not supported the functionality
>>    is the same.
>>
>> 3. The main difference between the tegra_powergate_sequence_power_up() API
>>    and the tegra_powergate_power_on_legacy() is that the clock used to
>>    enable the powergate is not kept enabled when using the
>>    tegra_powergate_power_on_legacy() API. Therefore, drivers must enable
>>    the clocks they need after calling tegra_powergate_power_on_legacy()
>>    and disable these clocks before calling
>>    tegra_powergate_power_off_legacy().
> 
> This is the same comment as in the DRM patch, and it applies to all
> devices that use powergating, so it should move into the preparatory
> patch rather than be repeated in all patches.
> 
>>
>> The helper functions for handling the powering on and off of the PCI
>> controller have been updated to support generic PM domains. The
>> tegra_pcie_power_off() was missing code to disable the clocks enabled in
>> the tegra_pcie_power_on() function and so this has been added.
>>
>> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
>> ---
>>  drivers/pci/host/pci-tegra.c | 49 +++++++++++++++++++++++++++++++++-----------
>>  1 file changed, 37 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
>> index 10c05718dbfd..acd1f311eee5 100644
>> --- a/drivers/pci/host/pci-tegra.c
>> +++ b/drivers/pci/host/pci-tegra.c
>> @@ -40,6 +40,7 @@
>>  #include <linux/pci.h>
>>  #include <linux/phy/phy.h>
>>  #include <linux/platform_device.h>
>> +#include <linux/pm_runtime.h>
>>  #include <linux/reset.h>
>>  #include <linux/sizes.h>
>>  #include <linux/slab.h>
>> @@ -908,19 +909,32 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
>>  
>>  static void tegra_pcie_power_off(struct tegra_pcie *pcie)
>>  {
>> +	const struct tegra_pcie_soc_data *soc = pcie->soc_data;
>>  	int err;
>>  
>> -	/* TODO: disable and unprepare clocks? */
>> -
>>  	err = phy_power_off(pcie->phy);
>>  	if (err < 0)
>>  		dev_warn(pcie->dev, "failed to power off PHY: %d\n", err);
>>  
>>  	reset_control_assert(pcie->pcie_xrst);
>>  	reset_control_assert(pcie->afi_rst);
>> -	reset_control_assert(pcie->pex_rst);
>>  
>> -	tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
>> +	clk_disable_unprepare(pcie->pll_e);
>> +	if (soc->has_cml_clk)
>> +		clk_disable_unprepare(pcie->cml_clk);
>> +	clk_disable_unprepare(pcie->afi_clk);
>> +	clk_disable_unprepare(pcie->pex_clk);
>> +
>> +	if (pm_runtime_enabled(pcie->dev)) {
>> +		err = pm_runtime_put_sync(pcie->dev);
>> +	} else {
>> +		err = tegra_powergate_power_off_legacy(TEGRA_POWERGATE_PCIE,
>> +						       pcie->pex_clk,
>> +						       pcie->pex_rst);
>> +	}
>> +
>> +	if (err < 0)
>> +		dev_warn(pcie->dev, "powergate power-down failed: %d\n", err);
>>  
>>  	err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
>>  	if (err < 0)
>> @@ -934,20 +948,28 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
>>  
>>  	reset_control_assert(pcie->pcie_xrst);
>>  	reset_control_assert(pcie->afi_rst);
>> -	reset_control_assert(pcie->pex_rst);
>> -
>> -	tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
>>  
>>  	/* enable regulators */
>>  	err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies);
>>  	if (err < 0)
>>  		dev_err(pcie->dev, "failed to enable regulators: %d\n", err);
>>  
>> -	err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
>> -						pcie->pex_clk,
>> -						pcie->pex_rst);
>> -	if (err) {
>> -		dev_err(pcie->dev, "powerup sequence failed: %d\n", err);
>> +	if (pm_runtime_enabled(pcie->dev)) {
>> +		err = pm_runtime_get_sync(pcie->dev);
>> +	} else {
>> +		err = tegra_powergate_power_on_legacy(TEGRA_POWERGATE_PCIE,
>> +						      pcie->pex_clk,
>> +						      pcie->pex_rst);
>> +	}
>> +
>> +	if (err < 0) {
>> +		dev_err(pcie->dev, "powergate power-up failed: %d\n", err);
>> +		return err;
>> +	}
>> +
>> +	err = clk_prepare_enable(pcie->pex_clk);
>> +	if (err < 0) {
>> +		dev_err(pcie->dev, "failed to enable PEX clock: %d\n", err);
>>  		return err;
>>  	}
>>  
> 
> Couldn't we simply move the above code into suspend/resume functions and
> then call pm_runtime_get() and pm_runtime_put() instead of
> tegra_pcie_power_on() and tegra_pcie_power_off()?

Possibly, however, the tricky part here is the regulators. We cannot put
the regulators into the runtime resume/suspend hooks, because this would
mean that the regulators are turned on after and turned off before the
power domain. We need to have the regulator on before turning on the
power domain.

So there are two options here AFAICT:
1. Move everything above after the regulators are turned on in the
   runtime resume function.
2. Move handling of all the regulators in the generic power domain
   code.

What do you think?

>> @@ -2001,6 +2023,9 @@ static int tegra_pcie_probe(struct platform_device *pdev)
>>  
>>  	pcibios_min_mem = 0;
>>  
>> +	if (of_property_read_bool(pdev->dev.of_node, "power-domains"))
>> +		pm_runtime_enable(&pdev->dev);
> 
> Then of course we'd have to call pm_runtime_enable() irrespective of the
> property and check for the presence of power domain support via another
> method (like the dev->pm_domain field).

Ok.

Jon

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

* Re: [PATCH V3 10/19] drm/tegra: dc: Prepare for generic PM domains
  2015-07-28  8:30         ` Jon Hunter
@ 2015-07-28 11:20             ` Thierry Reding
  -1 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-28 11:20 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 1628 bytes --]

On Tue, Jul 28, 2015 at 09:30:04AM +0100, Jon Hunter wrote:
> 
> On 17/07/15 11:41, Thierry Reding wrote:
> > * PGP Signed by an unknown key
> > 
> > On Mon, Jul 13, 2015 at 01:39:48PM +0100, Jon Hunter wrote:
> >> Add support to the tegra dc driver for generic PM domains. However,
> >> to ensure backward compatibility with older device tree blobs ensure
> >> that the driver can work with or without generic PM domains. In order
> >> to migrate to generic PM domain infrastructure the necessary changes
> >> are:
> >>
> >> 1. If the "power-domains" property is present in the DT device node then
> >>    generic PM domains is supported and pm_runtime_enable() should be
> >>    called for the device. Furthermore, the enabling and disabling of the
> >>    power-domain is handled via calling pm_runtime_get/put, respectively.
> > 
> > The device could be PM runtime enabled even if no power-domains property
> > is set. Couldn't we check something more direct, like for example if the
> > dev->pm_domain is non-NULL?
> 
> Yes could do that instead.
> 
> > Perhaps it'd be worth converting the driver to use runtime PM first, and
> > move all the powergate and clock handling into suspend/resume functions,
> > and then we can conditionalize whether or not we call the legacy API iff
> > dev->pm_domain == NULL?
> 
> May be that would be a cleaner transition than trying to do it all in
> one go.

I have a couple of patches in my tree to do this for DRM as part of an
effort to restore DPMS. It's fairly tricky to get right in DRM and
requires all sorts of changes to the driver.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* [PATCH V3 10/19] drm/tegra: dc: Prepare for generic PM domains
@ 2015-07-28 11:20             ` Thierry Reding
  0 siblings, 0 replies; 110+ messages in thread
From: Thierry Reding @ 2015-07-28 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 28, 2015 at 09:30:04AM +0100, Jon Hunter wrote:
> 
> On 17/07/15 11:41, Thierry Reding wrote:
> > * PGP Signed by an unknown key
> > 
> > On Mon, Jul 13, 2015 at 01:39:48PM +0100, Jon Hunter wrote:
> >> Add support to the tegra dc driver for generic PM domains. However,
> >> to ensure backward compatibility with older device tree blobs ensure
> >> that the driver can work with or without generic PM domains. In order
> >> to migrate to generic PM domain infrastructure the necessary changes
> >> are:
> >>
> >> 1. If the "power-domains" property is present in the DT device node then
> >>    generic PM domains is supported and pm_runtime_enable() should be
> >>    called for the device. Furthermore, the enabling and disabling of the
> >>    power-domain is handled via calling pm_runtime_get/put, respectively.
> > 
> > The device could be PM runtime enabled even if no power-domains property
> > is set. Couldn't we check something more direct, like for example if the
> > dev->pm_domain is non-NULL?
> 
> Yes could do that instead.
> 
> > Perhaps it'd be worth converting the driver to use runtime PM first, and
> > move all the powergate and clock handling into suspend/resume functions,
> > and then we can conditionalize whether or not we call the legacy API iff
> > dev->pm_domain == NULL?
> 
> May be that would be a cleaner transition than trying to do it all in
> one go.

I have a couple of patches in my tree to do this for DRM as part of an
effort to restore DPMS. It's fairly tricky to get right in DRM and
requires all sorts of changes to the driver.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150728/f7735d82/attachment.sig>

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

* Re: [PATCH V3 10/19] drm/tegra: dc: Prepare for generic PM domains
  2015-07-28 11:20             ` Thierry Reding
@ 2015-07-28 15:30                 ` Jon Hunter
  -1 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-28 15:30 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Stephen Warren, Alexandre Courbot, Philipp Zabel,
	Peter De Schrijver, Prashant Gaikwad, Terje Bergström,
	Hans de Goede, Tejun Heo, Vince Hsu, Rafael J. Wysocki,
	Kevin Hilman, Ulf Hansson, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pm-u79uwXL29TY76Z2rM5mHXA


On 28/07/15 12:20, Thierry Reding wrote:
> On Tue, Jul 28, 2015 at 09:30:04AM +0100, Jon Hunter wrote:
>> May be that would be a cleaner transition than trying to do it all in
>> one go.
> 
> I have a couple of patches in my tree to do this for DRM as part of an
> effort to restore DPMS. It's fairly tricky to get right in DRM and
> requires all sorts of changes to the driver.

Hmmm ... I was just thinking about moving what is currently there in the pm-runtime helpers ...

diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index a287e4fec865..0f1dc01215b1 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -10,6 +10,7 @@
 #include <linux/clk.h>
 #include <linux/debugfs.h>
 #include <linux/iommu.h>
+#include <linux/pm_runtime.h>
 #include <linux/reset.h>
 
 #include <soc/tegra/pmc.h>
@@ -1922,29 +1923,12 @@ static int tegra_dc_probe(struct platform_device *pdev)
 			dc->powergate = TEGRA_POWERGATE_DIS;
 		else
 			dc->powergate = TEGRA_POWERGATE_DISB;
+	}
 
-		err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk,
-							dc->rst);
-		if (err < 0) {
-			dev_err(&pdev->dev, "failed to power partition: %d\n",
-				err);
-			return err;
-		}
-	} else {
-		err = clk_prepare_enable(dc->clk);
-		if (err < 0) {
-			dev_err(&pdev->dev, "failed to enable clock: %d\n",
-				err);
-			return err;
-		}
+	platform_set_drvdata(pdev, dc);
 
-		err = reset_control_deassert(dc->rst);
-		if (err < 0) {
-			dev_err(&pdev->dev, "failed to deassert reset: %d\n",
-				err);
-			return err;
-		}
-	}
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	dc->regs = devm_ioremap_resource(&pdev->dev, regs);
@@ -1978,8 +1962,6 @@ static int tegra_dc_probe(struct platform_device *pdev)
 	if (!dc->syncpt)
 		dev_warn(&pdev->dev, "failed to allocate syncpoint\n");
 
-	platform_set_drvdata(pdev, dc);
-
 	return 0;
 }
 
@@ -2003,6 +1985,17 @@ static int tegra_dc_remove(struct platform_device *pdev)
 		return err;
 	}
 
+	pm_runtime_put(&pdev->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int tegra_dc_runtime_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct tegra_dc *dc = platform_get_drvdata(pdev);
+
 	reset_control_assert(dc->rst);
 
 	if (dc->soc->has_powergate)
@@ -2013,11 +2006,54 @@ static int tegra_dc_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static int tegra_dc_runtime_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct tegra_dc *dc = platform_get_drvdata(pdev);
+	int err;
+
+	if (dc->soc->has_powergate) {
+		err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk,
+							dc->rst);
+		if (err < 0) {
+			dev_err(&pdev->dev, "failed to power partition: %d\n",
+				err);
+			return err;
+		}
+	} else {
+		err = clk_prepare_enable(dc->clk);
+		if (err < 0) {
+			dev_err(&pdev->dev, "failed to enable clock: %d\n",
+				err);
+			return err;
+		}
+
+		err = reset_control_deassert(dc->rst);
+		if (err < 0) {
+			dev_err(&pdev->dev, "failed to deassert reset: %d\n",
+				err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static struct dev_pm_ops tegra_dc_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra_dc_runtime_suspend,
+			   tegra_dc_runtime_resume, NULL)
+};
+#define TEGRA_DC_PM_OPS (&tegra_dc_pm_ops)
+#else
+#define TEGRA_DC_PM_OPS NULL
+#endif /* CONFIG_PM */
+
 struct platform_driver tegra_dc_driver = {
 	.driver = {
 		.name = "tegra-dc",
 		.owner = THIS_MODULE,
 		.of_match_table = tegra_dc_of_match,
+		.pm = TEGRA_DC_PM_OPS,
 	},
 	.probe = tegra_dc_probe,
 	.remove = tegra_dc_remove,
-- 
2.1.4

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

* [PATCH V3 10/19] drm/tegra: dc: Prepare for generic PM domains
@ 2015-07-28 15:30                 ` Jon Hunter
  0 siblings, 0 replies; 110+ messages in thread
From: Jon Hunter @ 2015-07-28 15:30 UTC (permalink / raw)
  To: linux-arm-kernel


On 28/07/15 12:20, Thierry Reding wrote:
> On Tue, Jul 28, 2015 at 09:30:04AM +0100, Jon Hunter wrote:
>> May be that would be a cleaner transition than trying to do it all in
>> one go.
> 
> I have a couple of patches in my tree to do this for DRM as part of an
> effort to restore DPMS. It's fairly tricky to get right in DRM and
> requires all sorts of changes to the driver.

Hmmm ... I was just thinking about moving what is currently there in the pm-runtime helpers ...

diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index a287e4fec865..0f1dc01215b1 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -10,6 +10,7 @@
 #include <linux/clk.h>
 #include <linux/debugfs.h>
 #include <linux/iommu.h>
+#include <linux/pm_runtime.h>
 #include <linux/reset.h>
 
 #include <soc/tegra/pmc.h>
@@ -1922,29 +1923,12 @@ static int tegra_dc_probe(struct platform_device *pdev)
 			dc->powergate = TEGRA_POWERGATE_DIS;
 		else
 			dc->powergate = TEGRA_POWERGATE_DISB;
+	}
 
-		err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk,
-							dc->rst);
-		if (err < 0) {
-			dev_err(&pdev->dev, "failed to power partition: %d\n",
-				err);
-			return err;
-		}
-	} else {
-		err = clk_prepare_enable(dc->clk);
-		if (err < 0) {
-			dev_err(&pdev->dev, "failed to enable clock: %d\n",
-				err);
-			return err;
-		}
+	platform_set_drvdata(pdev, dc);
 
-		err = reset_control_deassert(dc->rst);
-		if (err < 0) {
-			dev_err(&pdev->dev, "failed to deassert reset: %d\n",
-				err);
-			return err;
-		}
-	}
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	dc->regs = devm_ioremap_resource(&pdev->dev, regs);
@@ -1978,8 +1962,6 @@ static int tegra_dc_probe(struct platform_device *pdev)
 	if (!dc->syncpt)
 		dev_warn(&pdev->dev, "failed to allocate syncpoint\n");
 
-	platform_set_drvdata(pdev, dc);
-
 	return 0;
 }
 
@@ -2003,6 +1985,17 @@ static int tegra_dc_remove(struct platform_device *pdev)
 		return err;
 	}
 
+	pm_runtime_put(&pdev->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int tegra_dc_runtime_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct tegra_dc *dc = platform_get_drvdata(pdev);
+
 	reset_control_assert(dc->rst);
 
 	if (dc->soc->has_powergate)
@@ -2013,11 +2006,54 @@ static int tegra_dc_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static int tegra_dc_runtime_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct tegra_dc *dc = platform_get_drvdata(pdev);
+	int err;
+
+	if (dc->soc->has_powergate) {
+		err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk,
+							dc->rst);
+		if (err < 0) {
+			dev_err(&pdev->dev, "failed to power partition: %d\n",
+				err);
+			return err;
+		}
+	} else {
+		err = clk_prepare_enable(dc->clk);
+		if (err < 0) {
+			dev_err(&pdev->dev, "failed to enable clock: %d\n",
+				err);
+			return err;
+		}
+
+		err = reset_control_deassert(dc->rst);
+		if (err < 0) {
+			dev_err(&pdev->dev, "failed to deassert reset: %d\n",
+				err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static struct dev_pm_ops tegra_dc_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra_dc_runtime_suspend,
+			   tegra_dc_runtime_resume, NULL)
+};
+#define TEGRA_DC_PM_OPS (&tegra_dc_pm_ops)
+#else
+#define TEGRA_DC_PM_OPS NULL
+#endif /* CONFIG_PM */
+
 struct platform_driver tegra_dc_driver = {
 	.driver = {
 		.name = "tegra-dc",
 		.owner = THIS_MODULE,
 		.of_match_table = tegra_dc_of_match,
+		.pm = TEGRA_DC_PM_OPS,
 	},
 	.probe = tegra_dc_probe,
 	.remove = tegra_dc_remove,
-- 
2.1.4

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

end of thread, other threads:[~2015-07-28 15:30 UTC | newest]

Thread overview: 110+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-13 12:39 [PATCH V3 00/19] Add generic PM domain support for Tegra SoCs Jon Hunter
2015-07-13 12:39 ` Jon Hunter
2015-07-13 12:39 ` [PATCH V3 06/19] clk: tegra: remove TEGRA_PLL_USE_LOCK for PLLD/PLLD2 Jon Hunter
2015-07-13 12:39   ` Jon Hunter
     [not found]   ` <1436791197-32358-7-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2015-07-13 13:41     ` Peter De Schrijver
2015-07-13 13:41       ` Peter De Schrijver
2015-07-13 14:02       ` Jon Hunter
2015-07-13 14:02         ` Jon Hunter
     [not found]         ` <55A3C50E.7060706-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2015-07-14 11:59           ` Jon Hunter
2015-07-14 11:59             ` Jon Hunter
2015-07-14 11:59             ` Jon Hunter
     [not found]             ` <55A4F985.7010503-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2015-07-15  8:16               ` Peter De Schrijver
2015-07-15  8:16                 ` Peter De Schrijver
     [not found] ` <1436791197-32358-1-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2015-07-13 12:39   ` [PATCH V3 01/19] reset: add of_reset_control_get_by_index() Jon Hunter
2015-07-13 12:39     ` Jon Hunter
     [not found]     ` <1436791197-32358-2-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2015-07-17 12:08       ` Philipp Zabel
2015-07-17 12:08         ` Philipp Zabel
2015-07-13 12:39   ` [PATCH V3 02/19] memory: tegra: Add MC flush support Jon Hunter
2015-07-13 12:39     ` Jon Hunter
2015-07-17  9:57     ` Thierry Reding
2015-07-17  9:57       ` Thierry Reding
2015-07-17 10:20       ` Peter De Schrijver
2015-07-17 10:20         ` Peter De Schrijver
     [not found]         ` <20150717102049.GQ6287-Rysk9IDjsxmJz7etNGeUX8VPkgjIgRvpAL8bYrjMMd8@public.gmane.org>
2015-07-17 11:31           ` Thierry Reding
2015-07-17 11:31             ` Thierry Reding
2015-07-20  8:46             ` Jon Hunter
2015-07-20  8:46               ` Jon Hunter
2015-07-20  9:17               ` Thierry Reding
2015-07-20  9:17                 ` Thierry Reding
2015-07-20  9:59             ` Peter De Schrijver
2015-07-20  9:59               ` Peter De Schrijver
     [not found]               ` <20150720095941.GZ6287-Rysk9IDjsxmJz7etNGeUX8VPkgjIgRvpAL8bYrjMMd8@public.gmane.org>
2015-07-20 13:14                 ` Thierry Reding
2015-07-20 13:14                   ` Thierry Reding
2015-07-21 10:57                   ` Peter De Schrijver
2015-07-21 10:57                     ` Peter De Schrijver
2015-07-13 12:39   ` [PATCH V3 03/19] memory: tegra: add flush operation for Tegra30 memory clients Jon Hunter
2015-07-13 12:39     ` Jon Hunter
     [not found]     ` <1436791197-32358-4-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2015-07-17 10:03       ` Thierry Reding
2015-07-17 10:03         ` Thierry Reding
2015-07-21  8:54         ` Jon Hunter
2015-07-21  8:54           ` Jon Hunter
2015-07-13 12:39   ` [PATCH V3 04/19] memory: tegra: add flush operation for Tegra114 " Jon Hunter
2015-07-13 12:39     ` Jon Hunter
     [not found]     ` <1436791197-32358-5-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2015-07-17 10:05       ` Thierry Reding
2015-07-17 10:05         ` Thierry Reding
2015-07-13 12:39   ` [PATCH V3 05/19] memory: tegra: add flush operation for Tegra124 " Jon Hunter
2015-07-13 12:39     ` Jon Hunter
2015-07-17 10:05     ` Thierry Reding
2015-07-17 10:05       ` Thierry Reding
2015-07-13 12:39   ` [PATCH V3 07/19] soc: tegra: pmc: Wait for powergate state to change Jon Hunter
2015-07-13 12:39     ` Jon Hunter
     [not found]     ` <1436791197-32358-8-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2015-07-17 10:17       ` Thierry Reding
2015-07-17 10:17         ` Thierry Reding
2015-07-21  9:34         ` Jon Hunter
2015-07-21  9:34           ` Jon Hunter
2015-07-13 12:39   ` [PATCH V3 08/19] soc: tegra: pmc: Clean-up PMC helper functions Jon Hunter
2015-07-13 12:39     ` Jon Hunter
2015-07-17 10:25     ` Thierry Reding
2015-07-17 10:25       ` Thierry Reding
2015-07-21  9:38       ` Jon Hunter
2015-07-21  9:38         ` Jon Hunter
2015-07-13 12:39   ` [PATCH V3 14/19] Documentation: DT: bindings: Add power domain info for NVIDIA PMC Jon Hunter
2015-07-13 12:39     ` Jon Hunter
     [not found]     ` <1436791197-32358-15-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2015-07-17  9:38       ` Thierry Reding
2015-07-17  9:38         ` Thierry Reding
2015-07-13 12:39   ` [PATCH V3 15/19] soc: tegra: pmc: Add generic PM domain support Jon Hunter
2015-07-13 12:39     ` Jon Hunter
     [not found]     ` <1436791197-32358-16-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2015-07-17 11:29       ` Thierry Reding
2015-07-17 11:29         ` Thierry Reding
2015-07-13 12:39   ` [PATCH V3 16/19] soc: tegra: pmc: Remove the deprecated powergate APIs Jon Hunter
2015-07-13 12:39     ` Jon Hunter
2015-07-13 12:39   ` [PATCH V3 18/19] ARM: tegra: add GPU power supply to Jetson TK1 DT Jon Hunter
2015-07-13 12:39     ` Jon Hunter
     [not found]     ` <1436791197-32358-19-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2015-07-17  9:28       ` Thierry Reding
2015-07-17  9:28         ` Thierry Reding
2015-07-13 12:39   ` [PATCH V3 19/19] ARM: tegra: select PM_GENERIC_DOMAINS Jon Hunter
2015-07-13 12:39     ` Jon Hunter
2015-07-13 13:50     ` Peter De Schrijver
2015-07-13 13:50       ` Peter De Schrijver
     [not found]       ` <20150713135047.GR6287-Rysk9IDjsxmJz7etNGeUX8VPkgjIgRvpAL8bYrjMMd8@public.gmane.org>
2015-07-13 14:03         ` Jon Hunter
2015-07-13 14:03           ` Jon Hunter
2015-07-14 11:59           ` Jon Hunter
2015-07-14 11:59             ` Jon Hunter
2015-07-14 11:59             ` Jon Hunter
     [not found]             ` <55A4F9B6.1070904-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2015-07-15  8:17               ` Peter De Schrijver
2015-07-15  8:17                 ` Peter De Schrijver
2015-07-13 12:39 ` [PATCH V3 09/19] soc: tegra: pmc: Prepare for migrating to generic PM domains Jon Hunter
2015-07-13 12:39   ` Jon Hunter
2015-07-13 12:39 ` [PATCH V3 10/19] drm/tegra: dc: Prepare for " Jon Hunter
2015-07-13 12:39   ` Jon Hunter
     [not found]   ` <1436791197-32358-11-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2015-07-17 10:41     ` Thierry Reding
2015-07-17 10:41       ` Thierry Reding
2015-07-28  8:30       ` Jon Hunter
2015-07-28  8:30         ` Jon Hunter
     [not found]         ` <55B73D8C.103-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2015-07-28 11:20           ` Thierry Reding
2015-07-28 11:20             ` Thierry Reding
     [not found]             ` <20150728112030.GA10949-AwZRO8vwLAwmlAP/+Wk3EA@public.gmane.org>
2015-07-28 15:30               ` Jon Hunter
2015-07-28 15:30                 ` Jon Hunter
2015-07-13 12:39 ` [PATCH V3 11/19] PCI: tegra: Add support " Jon Hunter
2015-07-13 12:39   ` Jon Hunter
2015-07-17 10:45   ` Thierry Reding
2015-07-17 10:45     ` Thierry Reding
2015-07-28  8:35     ` Jon Hunter
2015-07-28  8:35       ` Jon Hunter
2015-07-13 12:39 ` [PATCH V3 12/19] ata: ahci_tegra: " Jon Hunter
2015-07-13 12:39   ` Jon Hunter
2015-07-13 12:39 ` [PATCH V3 13/19] drm/tegra: gr3d: " Jon Hunter
2015-07-13 12:39   ` Jon Hunter
2015-07-13 12:39 ` [PATCH V3 17/19] ARM: tegra: Add PM domain device nodes to Tegra124 DT Jon Hunter
2015-07-13 12:39   ` Jon Hunter

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.