diff mbox

[PATCH/RFC,4/5] ARM: shmobile: R-Mobile: Add DT support for PM domains

Message ID 1410183344-14756-5-git-send-email-geert+renesas@glider.be (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Geert Uytterhoeven Sept. 8, 2014, 1:35 p.m. UTC
Populate the PM domains from DT, and provide support to hook up devices
to their respective PM domain.

The always-on power area (e.g. C5 on r8a7740) is created as a PM domain
without software control, to allow Run-Time management of module clocks
for hardware blocks inside this area in the future.
Power-on/off latencies are supported.

Limitations and special cases in the non-DT case are handled through
rmobile_pm_quirks(). Checks for hardcoded PM domain indices should be
replaced by the analysis of relations between devices and PM domains in
DT.

Initialization is done from core_initcall(), as the
"renesas,intc-irqpin" driver uses postcore_initcall().

This is functionally almost equivalent to the non-DT case. Missing are
Run-Time management of the module clocks (pm_clk_*()), and device
latencies.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 arch/arm/mach-shmobile/Kconfig      |   3 +-
 arch/arm/mach-shmobile/pm-rmobile.c | 145 +++++++++++++++++++++++++++++++++++-
 2 files changed, 145 insertions(+), 3 deletions(-)

Comments

Kevin Hilman Sept. 9, 2014, 3:40 p.m. UTC | #1
Geert Uytterhoeven <geert+renesas@glider.be> writes:

> Populate the PM domains from DT, and provide support to hook up devices
> to their respective PM domain.
>
> The always-on power area (e.g. C5 on r8a7740) is created as a PM domain
> without software control, to allow Run-Time management of module clocks
> for hardware blocks inside this area in the future.
> Power-on/off latencies are supported.
>
> Limitations and special cases in the non-DT case are handled through
> rmobile_pm_quirks(). Checks for hardcoded PM domain indices should be
> replaced by the analysis of relations between devices and PM domains in
> DT.
>
> Initialization is done from core_initcall(), as the
> "renesas,intc-irqpin" driver uses postcore_initcall().
>
> This is functionally almost equivalent to the non-DT case. Missing are
> Run-Time management of the module clocks (pm_clk_*()), and device
> latencies.
>
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>

[...]

> +static int r8a7740_pd_a4s_suspend(void)
> +{
> +	/*
> +	 * The A4S domain contains the CPU core and therefore it should
> +	 * only be turned off if the CPU is in use.

I think you meant "if the CPU is *not* in use."  ?  :)

Kevin

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kevin Hilman Sept. 9, 2014, 4:11 p.m. UTC | #2
Geert Uytterhoeven <geert+renesas@glider.be> writes:

> Populate the PM domains from DT, and provide support to hook up devices
> to their respective PM domain.
>
> The always-on power area (e.g. C5 on r8a7740) is created as a PM domain
> without software control, to allow Run-Time management of module clocks
> for hardware blocks inside this area in the future.
> Power-on/off latencies are supported.
>
> Limitations and special cases in the non-DT case are handled through
> rmobile_pm_quirks(). Checks for hardcoded PM domain indices should be
> replaced by the analysis of relations between devices and PM domains in
> DT.
>
> Initialization is done from core_initcall(), as the
> "renesas,intc-irqpin" driver uses postcore_initcall().
>
> This is functionally almost equivalent to the non-DT case. Missing are
> Run-Time management of the module clocks (pm_clk_*()), and device
> latencies.
>
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>

[...]

This series looks really good to me.  Just a minor question about a
possible next step...

> +static int r8a7740_pd_a4s_suspend(void)
> +{
> +	/*
> +	 * The A4S domain contains the CPU core and therefore it should
> +	 * only be turned off if the CPU is in use.
> +	 */
> +	return -EBUSY;
> +}


Do you have plans to use pm_genpd_attach_cpuidle() for this eventually,
maybe by checking if the enclosing node is a CPU?  If not, are there
other plans to handle idle for the power domains that contain CPUs?

Kevin
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Geert Uytterhoeven Sept. 10, 2014, 12:37 p.m. UTC | #3
Hi Kevin,

On Tue, Sep 9, 2014 at 5:40 PM, Kevin Hilman <khilman@kernel.org> wrote:
>> +static int r8a7740_pd_a4s_suspend(void)
>> +{
>> +     /*
>> +      * The A4S domain contains the CPU core and therefore it should
>> +      * only be turned off if the CPU is in use.
>
> I think you meant "if the CPU is *not* in use."  ?  :)

Ah, this was copied from pm-r8a7740.c, which was copied from pm-sh7372.c.
The thinko has been fixed in the latter, when more advanced suspend support
was added.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Geert Uytterhoeven Sept. 10, 2014, 12:40 p.m. UTC | #4
Hi Kevin,

On Tue, Sep 9, 2014 at 6:11 PM, Kevin Hilman <khilman@kernel.org> wrote:
>> +static int r8a7740_pd_a4s_suspend(void)
>> +{
>> +     /*
>> +      * The A4S domain contains the CPU core and therefore it should
>> +      * only be turned off if the CPU is in use.
>> +      */
>> +     return -EBUSY;
>> +}
>
>
> Do you have plans to use pm_genpd_attach_cpuidle() for this eventually,
> maybe by checking if the enclosing node is a CPU?  If not, are there
> other plans to handle idle for the power domains that contain CPUs?

Yes, the plan is to add more power saving features, and use DT topology
analysis to get rid of the hardcoded domain logic.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 21f457b56c01..ad007d3b384f 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -6,6 +6,7 @@  config PM_RCAR
 
 config PM_RMOBILE
 	bool
+	select PM_GENERIC_DOMAINS
 
 config ARCH_RCAR_GEN1
 	bool
@@ -21,7 +22,7 @@  config ARCH_RCAR_GEN2
 
 config ARCH_RMOBILE
 	bool
-	select PM_RMOBILE if PM && !ARCH_SHMOBILE_MULTI
+	select PM_RMOBILE if PM
 	select SYS_SUPPORTS_SH_CMT
 	select SYS_SUPPORTS_SH_TMU
 
diff --git a/arch/arm/mach-shmobile/pm-rmobile.c b/arch/arm/mach-shmobile/pm-rmobile.c
index 578446af6e7b..5628bf2b0cb7 100644
--- a/arch/arm/mach-shmobile/pm-rmobile.c
+++ b/arch/arm/mach-shmobile/pm-rmobile.c
@@ -3,6 +3,7 @@ 
  *
  * Copyright (C) 2012  Renesas Solutions Corp.
  * Copyright (C) 2012  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ * Copyright (C) 2014  Glider bvba
  *
  * based on pm-sh7372.c
  *  Copyright (C) 2011 Magnus Damm
@@ -13,9 +14,13 @@ 
  */
 #include <linux/console.h>
 #include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/pm_clock.h>
+#include <linux/slab.h>
 #include <asm/io.h>
 #include "pm-rmobile.h"
 
@@ -30,8 +35,12 @@ 
 static int rmobile_pd_power_down(struct generic_pm_domain *genpd)
 {
 	struct rmobile_pm_domain *rmobile_pd = to_rmobile_pd(genpd);
-	unsigned int mask = 1 << rmobile_pd->bit_shift;
+	unsigned int mask;
 
+	if (rmobile_pd->bit_shift == ~0)
+		return -EBUSY;
+
+	mask = 1 << rmobile_pd->bit_shift;
 	if (rmobile_pd->suspend) {
 		int ret = rmobile_pd->suspend();
 
@@ -61,10 +70,14 @@  static int rmobile_pd_power_down(struct generic_pm_domain *genpd)
 static int __rmobile_pd_power_up(struct rmobile_pm_domain *rmobile_pd,
 				 bool do_resume)
 {
-	unsigned int mask = 1 << rmobile_pd->bit_shift;
+	unsigned int mask;
 	unsigned int retry_count;
 	int ret = 0;
 
+	if (rmobile_pd->bit_shift == ~0)
+		return 0;
+
+	mask = 1 << rmobile_pd->bit_shift;
 	if (__raw_readl(rmobile_pd->base + PSTR) & mask)
 		goto out;
 
@@ -117,6 +130,8 @@  static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
 	__rmobile_pd_power_up(rmobile_pd, false);
 }
 
+#ifdef CONFIG_ARCH_SHMOBILE_LEGACY
+
 void rmobile_init_domains(struct rmobile_pm_domain domains[], int num)
 {
 	int j;
@@ -132,6 +147,7 @@  void rmobile_add_device_to_domain_td(const char *domain_name,
 	struct device *dev = &pdev->dev;
 
 	__pm_genpd_name_add_device(domain_name, dev, td);
+	// FIXME Not yet done from DT
 	if (pm_clk_no_clocks(dev))
 		pm_clk_add(dev, NULL);
 }
@@ -139,6 +155,7 @@  void rmobile_add_device_to_domain_td(const char *domain_name,
 void rmobile_add_devices_to_domains(struct pm_domain_device data[],
 				    int size)
 {
+	// FIXME Not yet done from DT
 	struct gpd_timing_data latencies = {
 		.stop_latency_ns = DEFAULT_DEV_LATENCY_NS,
 		.start_latency_ns = DEFAULT_DEV_LATENCY_NS,
@@ -151,3 +168,127 @@  void rmobile_add_devices_to_domains(struct pm_domain_device data[],
 		rmobile_add_device_to_domain_td(data[j].domain_name,
 						data[j].pdev, &latencies);
 }
+
+#else /* !CONFIG_ARCH_SHMOBILE_LEGACY */
+
+static int r8a7740_pd_a4s_suspend(void)
+{
+	/*
+	 * The A4S domain contains the CPU core and therefore it should
+	 * only be turned off if the CPU is in use.
+	 */
+	return -EBUSY;
+}
+
+static int r8a7740_pd_a3sp_suspend(void)
+{
+	/*
+	 * Serial consoles make use of SCIF hardware located in A3SP,
+	 * keep such power domain on if "no_console_suspend" is set.
+	 */
+	return console_suspend_enabled ? 0 : -EBUSY;
+}
+
+// FIXME Quirks
+static bool rmobile_pm_quirks(struct rmobile_pm_domain *pd)
+{
+	unsigned int idx = pd->bit_shift;
+	const char *name = pd->genpd.name;
+
+	if (idx == 2 || idx == 3) {
+		// Do not enable
+		pr_info("Skipping pm domain %s\n", name);
+		return false;
+	}
+	if (idx == 10) {
+		pr_info("%s is parent of CPU domain\n", name);
+		pd->gov = &pm_domain_always_on_gov;
+		pd->suspend = r8a7740_pd_a4s_suspend;
+	}
+	if (idx == 11) {
+		pr_info("%s contains serial console\n", name);
+		pd->gov = &pm_domain_always_on_gov;
+		pd->suspend = r8a7740_pd_a3sp_suspend;
+	}
+	if (idx == 12) {
+		pr_info("%s contains CPU\n", name);
+		pd->gov = &pm_domain_always_on_gov;
+	}
+
+	return true;
+}
+
+static int rmobile_add_pm_domains(void __iomem *base,
+				  struct device_node *parent,
+				  struct generic_pm_domain *genpd_parent)
+{
+	struct device_node *np;
+
+	for_each_child_of_node(parent, np) {
+		struct rmobile_pm_domain *pd;
+		u32 idx = ~0;
+		u32 latency;
+
+		if (of_property_read_u32(np, "reg", &idx)) {
+			/* always-on domain */
+		}
+
+		pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+		if (!pd)
+			return -ENOMEM;
+
+		pd->genpd.name = np->name;
+		if (!of_property_read_u32(np, "power-on-latency", &latency))
+			pd->genpd.power_on_latency_ns = latency;
+		if (!of_property_read_u32(np, "power-off-latency", &latency))
+			pd->genpd.power_off_latency_ns = latency;
+		pd->base = base;
+		pd->bit_shift = idx;
+
+		if (!rmobile_pm_quirks(pd)) {
+			kfree(pd);
+			continue;
+		}
+
+		rmobile_init_pm_domain(pd);
+		if (genpd_parent)
+			pm_genpd_add_subdomain(genpd_parent, &pd->genpd);
+
+		of_genpd_add_provider_simple(np, &pd->genpd);
+
+		rmobile_add_pm_domains(base, np, &pd->genpd);
+	}
+	return 0;
+}
+
+static __init int rmobile_init_pm_domains(void)
+{
+	struct device_node *np, *pmd;
+	void __iomem *base;
+	int ret = 0;
+
+	for_each_compatible_node(np, NULL, "renesas,sysc-rmobile") {
+		base = of_iomap(np, 0);
+		if (!base) {
+			pr_warn("%s cannot map reg 0\n", np->full_name);
+			continue;
+		}
+
+		pmd = of_find_node_by_name(np, "pm-domains");
+		if (!pmd) {
+			pr_warn("%s lacks pm-domains node\n", np->full_name);
+			continue;
+		}
+
+		ret = rmobile_add_pm_domains(base, pmd, NULL);
+		of_node_put(pmd);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+core_initcall(rmobile_init_pm_domains);
+
+#endif /* !CONFIG_ARCH_SHMOBILE_LEGACY */