All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] Add runtime PM support for clocks (on Exynos SoC example)
@ 2016-09-01 13:45 ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel
  Cc: Marek Szyprowski, Stephen Boyd, Michael Turquette, Ulf Hansson,
	Sylwester Nawrocki, Chanwoo Choi, Inki Dae, Krzysztof Kozlowski,
	Bartlomiej Zolnierkiewicz

Dear All,

This patchset adds runtime PM support to common clock framework. This is an
attempt to implement support for clock controllers, which belongs to a power
domain. This approach works surprisingly well on Exynos 4412 and 5433 SoCs,
what allowed us to solve various freeze/crash issues related to power
management.

The main idea behind this patchset is to keep clock's controller power domain
enabled every time when at least one of its clock is enabled or access to its
registers is being made. Clock controller driver (clock provider) can
supply a struct device pointer, which is the used by clock core for tracking and
managing clock's controller runtime pm state. Each clk_prepare() operation will
first call pm_runtime_get_sync() on the supplied device, while clk_unprepare()
will do pm_runtime_put() at the end.

This runtime PM feature has been tested with Exynos4412 and Exynos5433 clocks
drivers. Both have some clocks, which belongs to respective power domains and
need special handling during power on/off procedures. Till now it wasn't handled
at all, what caused various problems.

Patches for exynos 4412 and 5433 clocks drivers change the way the clock
provider is initialized. Instead of CLK_OF_DECLARE based initialization, a
complete platform device driver infrastructure is being used. This is needed to
let driver to use runtime pm feature and integrate with generic power domains.
The side-effect of this change is a delay in clock provider registeration
during system boot, so early initialized drivers might get EPROBEDEFER error
when requesting their clocks. This is an issue for IOMMU drivers, so
this patchset will be fully functional once the deferred probe for IOMMU
will be merged.

The side-effect of this patchset is the one can finally read
/sys/kernel/debug/clk/clk_summary on all Exynos4412 boards without any freeze.

If one wants to test this patchset (on Exynos4412 Trats2 device with FIMC-IS
driver), I've provided a branch with all needed patches (fixes for Exynos,
FIMC-IS driver and IOMMU deferred probe):
https://git.linaro.org/people/marek.szyprowski/linux-srpol.git v4.8-clocks-pm

Patches are based on vanilla v4.8-rc4 kernel.

Best regards
Marek Szyprowski
Samsung R&D Institute Poland

Marek Szyprowski (5):
  clk: add support for runtime pm
  clock: samsung: add support for runtime pm
  clocks: exynos4x12: add runtime pm support for ISP clocks
  ARM: dts: exynos: add support for ISP power domain to exynos4x12
    clocks device
  clocks: exynos5433: add runtime pm support

 .../devicetree/bindings/clock/exynos4-clock.txt    |  22 +
 arch/arm/boot/dts/exynos4x12.dtsi                  |   5 +
 drivers/clk/clk.c                                  |  84 +++-
 drivers/clk/samsung/clk-exynos4.c                  | 228 +++++++---
 drivers/clk/samsung/clk-exynos5433.c               | 462 ++++++++++++++++-----
 drivers/clk/samsung/clk-pll.c                      |   2 +-
 drivers/clk/samsung/clk.c                          |  12 +-
 drivers/clk/samsung/clk.h                          |   1 +
 8 files changed, 641 insertions(+), 175 deletions(-)

-- 
1.9.1

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

* [PATCH 0/5] Add runtime PM support for clocks (on Exynos SoC example)
@ 2016-09-01 13:45 ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel
  Cc: Ulf Hansson, Bartlomiej Zolnierkiewicz, Michael Turquette,
	Stephen Boyd, Krzysztof Kozlowski, Inki Dae, Chanwoo Choi,
	Sylwester Nawrocki, Marek Szyprowski

Dear All,

This patchset adds runtime PM support to common clock framework. This is an
attempt to implement support for clock controllers, which belongs to a power
domain. This approach works surprisingly well on Exynos 4412 and 5433 SoCs,
what allowed us to solve various freeze/crash issues related to power
management.

The main idea behind this patchset is to keep clock's controller power domain
enabled every time when at least one of its clock is enabled or access to its
registers is being made. Clock controller driver (clock provider) can
supply a struct device pointer, which is the used by clock core for tracking and
managing clock's controller runtime pm state. Each clk_prepare() operation will
first call pm_runtime_get_sync() on the supplied device, while clk_unprepare()
will do pm_runtime_put() at the end.

This runtime PM feature has been tested with Exynos4412 and Exynos5433 clocks
drivers. Both have some clocks, which belongs to respective power domains and
need special handling during power on/off procedures. Till now it wasn't handled
at all, what caused various problems.

Patches for exynos 4412 and 5433 clocks drivers change the way the clock
provider is initialized. Instead of CLK_OF_DECLARE based initialization, a
complete platform device driver infrastructure is being used. This is needed to
let driver to use runtime pm feature and integrate with generic power domains.
The side-effect of this change is a delay in clock provider registeration
during system boot, so early initialized drivers might get EPROBEDEFER error
when requesting their clocks. This is an issue for IOMMU drivers, so
this patchset will be fully functional once the deferred probe for IOMMU
will be merged.

The side-effect of this patchset is the one can finally read
/sys/kernel/debug/clk/clk_summary on all Exynos4412 boards without any freeze.

If one wants to test this patchset (on Exynos4412 Trats2 device with FIMC-IS
driver), I've provided a branch with all needed patches (fixes for Exynos,
FIMC-IS driver and IOMMU deferred probe):
https://git.linaro.org/people/marek.szyprowski/linux-srpol.git v4.8-clocks-pm

Patches are based on vanilla v4.8-rc4 kernel.

Best regards
Marek Szyprowski
Samsung R&D Institute Poland

Marek Szyprowski (5):
  clk: add support for runtime pm
  clock: samsung: add support for runtime pm
  clocks: exynos4x12: add runtime pm support for ISP clocks
  ARM: dts: exynos: add support for ISP power domain to exynos4x12
    clocks device
  clocks: exynos5433: add runtime pm support

 .../devicetree/bindings/clock/exynos4-clock.txt    |  22 +
 arch/arm/boot/dts/exynos4x12.dtsi                  |   5 +
 drivers/clk/clk.c                                  |  84 +++-
 drivers/clk/samsung/clk-exynos4.c                  | 228 +++++++---
 drivers/clk/samsung/clk-exynos5433.c               | 462 ++++++++++++++++-----
 drivers/clk/samsung/clk-pll.c                      |   2 +-
 drivers/clk/samsung/clk.c                          |  12 +-
 drivers/clk/samsung/clk.h                          |   1 +
 8 files changed, 641 insertions(+), 175 deletions(-)

-- 
1.9.1

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

* [PATCH 0/5] Add runtime PM support for clocks (on Exynos SoC example)
@ 2016-09-01 13:45 ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-arm-kernel

Dear All,

This patchset adds runtime PM support to common clock framework. This is an
attempt to implement support for clock controllers, which belongs to a power
domain. This approach works surprisingly well on Exynos 4412 and 5433 SoCs,
what allowed us to solve various freeze/crash issues related to power
management.

The main idea behind this patchset is to keep clock's controller power domain
enabled every time when at least one of its clock is enabled or access to its
registers is being made. Clock controller driver (clock provider) can
supply a struct device pointer, which is the used by clock core for tracking and
managing clock's controller runtime pm state. Each clk_prepare() operation will
first call pm_runtime_get_sync() on the supplied device, while clk_unprepare()
will do pm_runtime_put() at the end.

This runtime PM feature has been tested with Exynos4412 and Exynos5433 clocks
drivers. Both have some clocks, which belongs to respective power domains and
need special handling during power on/off procedures. Till now it wasn't handled
at all, what caused various problems.

Patches for exynos 4412 and 5433 clocks drivers change the way the clock
provider is initialized. Instead of CLK_OF_DECLARE based initialization, a
complete platform device driver infrastructure is being used. This is needed to
let driver to use runtime pm feature and integrate with generic power domains.
The side-effect of this change is a delay in clock provider registeration
during system boot, so early initialized drivers might get EPROBEDEFER error
when requesting their clocks. This is an issue for IOMMU drivers, so
this patchset will be fully functional once the deferred probe for IOMMU
will be merged.

The side-effect of this patchset is the one can finally read
/sys/kernel/debug/clk/clk_summary on all Exynos4412 boards without any freeze.

If one wants to test this patchset (on Exynos4412 Trats2 device with FIMC-IS
driver), I've provided a branch with all needed patches (fixes for Exynos,
FIMC-IS driver and IOMMU deferred probe):
https://git.linaro.org/people/marek.szyprowski/linux-srpol.git v4.8-clocks-pm

Patches are based on vanilla v4.8-rc4 kernel.

Best regards
Marek Szyprowski
Samsung R&D Institute Poland

Marek Szyprowski (5):
  clk: add support for runtime pm
  clock: samsung: add support for runtime pm
  clocks: exynos4x12: add runtime pm support for ISP clocks
  ARM: dts: exynos: add support for ISP power domain to exynos4x12
    clocks device
  clocks: exynos5433: add runtime pm support

 .../devicetree/bindings/clock/exynos4-clock.txt    |  22 +
 arch/arm/boot/dts/exynos4x12.dtsi                  |   5 +
 drivers/clk/clk.c                                  |  84 +++-
 drivers/clk/samsung/clk-exynos4.c                  | 228 +++++++---
 drivers/clk/samsung/clk-exynos5433.c               | 462 ++++++++++++++++-----
 drivers/clk/samsung/clk-pll.c                      |   2 +-
 drivers/clk/samsung/clk.c                          |  12 +-
 drivers/clk/samsung/clk.h                          |   1 +
 8 files changed, 641 insertions(+), 175 deletions(-)

-- 
1.9.1

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

* [PATCH 1/5] clk: add support for runtime pm
  2016-09-01 13:45 ` Marek Szyprowski
  (?)
@ 2016-09-01 13:45   ` Marek Szyprowski
  -1 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel
  Cc: Marek Szyprowski, Stephen Boyd, Michael Turquette, Ulf Hansson,
	Sylwester Nawrocki, Chanwoo Choi, Inki Dae, Krzysztof Kozlowski,
	Bartlomiej Zolnierkiewicz

Registers for some clocks might be located in the SOC area, which are under the
power domain. To enable access to those registers respective domain has to be
turned on. Additionally, registers for such clocks will usually loose its
contents when power domain is turned off, so additional saving and restoring of
them might be needed in the clock controller driver.

This patch adds basic infrastructure in the clocks core to allow implementing
driver for such clocks under power domains. Clock provider can supply a
struct device pointer, which is the used by clock core for tracking and managing
clock's controller runtime pm state. Each clk_prepare() operation
will first call pm_runtime_get_sync() on the supplied device, while
clk_unprepare() will do pm_runtime_put() at the end.

Additional calls to pm_runtime_get/put functions are required to ensure that any
register access (like calculating/chaning clock rates) will be done with clock
controller in active runtime state.

Special handling of the case when runtime pm is disabled for clock controller's
device is needed to let this feature work properly also during system sleep
suspend/resume operations (runtime pm is first disabled before entering sleep
state's, but controller is usually still operational until its suspend pm
callback is called).

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/clk/clk.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 76 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 820a939fb6bb..a1934e9b4e95 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -21,6 +21,7 @@
 #include <linux/of.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/pm_runtime.h>
 #include <linux/sched.h>
 #include <linux/clkdev.h>
 
@@ -46,6 +47,7 @@ struct clk_core {
 	const struct clk_ops	*ops;
 	struct clk_hw		*hw;
 	struct module		*owner;
+	struct device		*dev;
 	struct clk_core		*parent;
 	const char		**parent_names;
 	struct clk_core		**parents;
@@ -87,6 +89,42 @@ struct clk {
 	struct hlist_node clks_node;
 };
 
+/***           runtime pm          ***/
+static int clk_pm_runtime_get(struct clk_core *core)
+{
+	int ret = 0;
+
+	if (!core->dev)
+		return 0;
+
+	if (pm_runtime_enabled(core->dev)) {
+		ret = pm_runtime_get_sync(core->dev);
+	} else {
+		if (!pm_runtime_status_suspended(core->dev))
+			pm_runtime_get_noresume(core->dev);
+	}
+	return ret < 0 ? ret : 0;
+}
+
+static void clk_pm_runtime_put(struct clk_core *core)
+{
+	if (!core->dev)
+		return;
+
+	if (pm_runtime_enabled(core->dev))
+		pm_runtime_put(core->dev);
+	else
+		pm_runtime_put_noidle(core->dev);
+}
+
+static bool clk_pm_runtime_suspended(struct clk_core *core)
+{
+	if (!core->dev)
+		return 0;
+
+	return pm_runtime_suspended(core->dev);
+}
+
 /***           locking             ***/
 static void clk_prepare_lock(void)
 {
@@ -150,6 +188,9 @@ static void clk_enable_unlock(unsigned long flags)
 
 static bool clk_core_is_prepared(struct clk_core *core)
 {
+	if (clk_pm_runtime_suspended(core))
+		return false;
+
 	/*
 	 * .is_prepared is optional for clocks that can prepare
 	 * fall back to software usage counter if it is missing
@@ -162,6 +203,9 @@ static bool clk_core_is_prepared(struct clk_core *core)
 
 static bool clk_core_is_enabled(struct clk_core *core)
 {
+	if (clk_pm_runtime_suspended(core))
+		return false;
+
 	/*
 	 * .is_enabled is only mandatory for clocks that gate
 	 * fall back to software usage counter if .is_enabled is missing
@@ -489,6 +533,8 @@ static void clk_core_unprepare(struct clk_core *core)
 	if (core->ops->unprepare)
 		core->ops->unprepare(core->hw);
 
+	clk_pm_runtime_put(core);
+
 	trace_clk_unprepare_complete(core);
 	clk_core_unprepare(core->parent);
 }
@@ -530,10 +576,14 @@ static int clk_core_prepare(struct clk_core *core)
 		return 0;
 
 	if (core->prepare_count == 0) {
-		ret = clk_core_prepare(core->parent);
+		ret = clk_pm_runtime_get(core);
 		if (ret)
 			return ret;
 
+		ret = clk_core_prepare(core->parent);
+		if (ret)
+			goto runtime_put;
+
 		trace_clk_prepare(core);
 
 		if (core->ops->prepare)
@@ -541,15 +591,18 @@ static int clk_core_prepare(struct clk_core *core)
 
 		trace_clk_prepare_complete(core);
 
-		if (ret) {
-			clk_core_unprepare(core->parent);
-			return ret;
-		}
+		if (ret)
+			goto unprepare;
 	}
 
 	core->prepare_count++;
 
 	return 0;
+unprepare:
+	clk_core_unprepare(core->parent);
+runtime_put:
+	clk_pm_runtime_put(core);
+	return ret;
 }
 
 static int clk_core_prepare_lock(struct clk_core *core)
@@ -1563,6 +1616,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
 {
 	struct clk_core *top, *fail_clk;
 	unsigned long rate = req_rate;
+	int ret = 0;
 
 	if (!core)
 		return 0;
@@ -1579,21 +1633,28 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
 	if (!top)
 		return -EINVAL;
 
+	ret = clk_pm_runtime_get(core);
+	if (ret)
+		return ret;
+
 	/* notify that we are about to change rates */
 	fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
 	if (fail_clk) {
 		pr_debug("%s: failed to set %s rate\n", __func__,
 				fail_clk->name);
 		clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
-		return -EBUSY;
+		ret = -EBUSY;
+		goto err;
 	}
 
 	/* change the rates */
 	clk_change_rate(top);
 
 	core->req_rate = req_rate;
+err:
+	clk_pm_runtime_put(core);
 
-	return 0;
+	return ret;
 }
 
 /**
@@ -1824,12 +1885,16 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
 		p_rate = parent->rate;
 	}
 
+	ret = clk_pm_runtime_get(core);
+	if (ret)
+		goto out;
+
 	/* propagate PRE_RATE_CHANGE notifications */
 	ret = __clk_speculate_rates(core, p_rate);
 
 	/* abort if a driver objects */
 	if (ret & NOTIFY_STOP_MASK)
-		goto out;
+		goto runtime_put;
 
 	/* do the re-parent */
 	ret = __clk_set_parent(core, parent, p_index);
@@ -1842,6 +1907,8 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
 		__clk_recalc_accuracies(core);
 	}
 
+runtime_put:
+	clk_pm_runtime_put(core);
 out:
 	clk_prepare_unlock();
 
@@ -2546,6 +2613,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
 		goto fail_name;
 	}
 	core->ops = hw->init->ops;
+	core->dev = dev;
 	if (dev && dev->driver)
 		core->owner = dev->driver->owner;
 	core->hw = hw;
-- 
1.9.1

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

* [PATCH 1/5] clk: add support for runtime pm
@ 2016-09-01 13:45   ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel
  Cc: Ulf Hansson, Bartlomiej Zolnierkiewicz, Michael Turquette,
	Stephen Boyd, Krzysztof Kozlowski, Inki Dae, Chanwoo Choi,
	Sylwester Nawrocki, Marek Szyprowski

Registers for some clocks might be located in the SOC area, which are under the
power domain. To enable access to those registers respective domain has to be
turned on. Additionally, registers for such clocks will usually loose its
contents when power domain is turned off, so additional saving and restoring of
them might be needed in the clock controller driver.

This patch adds basic infrastructure in the clocks core to allow implementing
driver for such clocks under power domains. Clock provider can supply a
struct device pointer, which is the used by clock core for tracking and managing
clock's controller runtime pm state. Each clk_prepare() operation
will first call pm_runtime_get_sync() on the supplied device, while
clk_unprepare() will do pm_runtime_put() at the end.

Additional calls to pm_runtime_get/put functions are required to ensure that any
register access (like calculating/chaning clock rates) will be done with clock
controller in active runtime state.

Special handling of the case when runtime pm is disabled for clock controller's
device is needed to let this feature work properly also during system sleep
suspend/resume operations (runtime pm is first disabled before entering sleep
state's, but controller is usually still operational until its suspend pm
callback is called).

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/clk/clk.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 76 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 820a939fb6bb..a1934e9b4e95 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -21,6 +21,7 @@
 #include <linux/of.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/pm_runtime.h>
 #include <linux/sched.h>
 #include <linux/clkdev.h>
 
@@ -46,6 +47,7 @@ struct clk_core {
 	const struct clk_ops	*ops;
 	struct clk_hw		*hw;
 	struct module		*owner;
+	struct device		*dev;
 	struct clk_core		*parent;
 	const char		**parent_names;
 	struct clk_core		**parents;
@@ -87,6 +89,42 @@ struct clk {
 	struct hlist_node clks_node;
 };
 
+/***           runtime pm          ***/
+static int clk_pm_runtime_get(struct clk_core *core)
+{
+	int ret = 0;
+
+	if (!core->dev)
+		return 0;
+
+	if (pm_runtime_enabled(core->dev)) {
+		ret = pm_runtime_get_sync(core->dev);
+	} else {
+		if (!pm_runtime_status_suspended(core->dev))
+			pm_runtime_get_noresume(core->dev);
+	}
+	return ret < 0 ? ret : 0;
+}
+
+static void clk_pm_runtime_put(struct clk_core *core)
+{
+	if (!core->dev)
+		return;
+
+	if (pm_runtime_enabled(core->dev))
+		pm_runtime_put(core->dev);
+	else
+		pm_runtime_put_noidle(core->dev);
+}
+
+static bool clk_pm_runtime_suspended(struct clk_core *core)
+{
+	if (!core->dev)
+		return 0;
+
+	return pm_runtime_suspended(core->dev);
+}
+
 /***           locking             ***/
 static void clk_prepare_lock(void)
 {
@@ -150,6 +188,9 @@ static void clk_enable_unlock(unsigned long flags)
 
 static bool clk_core_is_prepared(struct clk_core *core)
 {
+	if (clk_pm_runtime_suspended(core))
+		return false;
+
 	/*
 	 * .is_prepared is optional for clocks that can prepare
 	 * fall back to software usage counter if it is missing
@@ -162,6 +203,9 @@ static bool clk_core_is_prepared(struct clk_core *core)
 
 static bool clk_core_is_enabled(struct clk_core *core)
 {
+	if (clk_pm_runtime_suspended(core))
+		return false;
+
 	/*
 	 * .is_enabled is only mandatory for clocks that gate
 	 * fall back to software usage counter if .is_enabled is missing
@@ -489,6 +533,8 @@ static void clk_core_unprepare(struct clk_core *core)
 	if (core->ops->unprepare)
 		core->ops->unprepare(core->hw);
 
+	clk_pm_runtime_put(core);
+
 	trace_clk_unprepare_complete(core);
 	clk_core_unprepare(core->parent);
 }
@@ -530,10 +576,14 @@ static int clk_core_prepare(struct clk_core *core)
 		return 0;
 
 	if (core->prepare_count == 0) {
-		ret = clk_core_prepare(core->parent);
+		ret = clk_pm_runtime_get(core);
 		if (ret)
 			return ret;
 
+		ret = clk_core_prepare(core->parent);
+		if (ret)
+			goto runtime_put;
+
 		trace_clk_prepare(core);
 
 		if (core->ops->prepare)
@@ -541,15 +591,18 @@ static int clk_core_prepare(struct clk_core *core)
 
 		trace_clk_prepare_complete(core);
 
-		if (ret) {
-			clk_core_unprepare(core->parent);
-			return ret;
-		}
+		if (ret)
+			goto unprepare;
 	}
 
 	core->prepare_count++;
 
 	return 0;
+unprepare:
+	clk_core_unprepare(core->parent);
+runtime_put:
+	clk_pm_runtime_put(core);
+	return ret;
 }
 
 static int clk_core_prepare_lock(struct clk_core *core)
@@ -1563,6 +1616,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
 {
 	struct clk_core *top, *fail_clk;
 	unsigned long rate = req_rate;
+	int ret = 0;
 
 	if (!core)
 		return 0;
@@ -1579,21 +1633,28 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
 	if (!top)
 		return -EINVAL;
 
+	ret = clk_pm_runtime_get(core);
+	if (ret)
+		return ret;
+
 	/* notify that we are about to change rates */
 	fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
 	if (fail_clk) {
 		pr_debug("%s: failed to set %s rate\n", __func__,
 				fail_clk->name);
 		clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
-		return -EBUSY;
+		ret = -EBUSY;
+		goto err;
 	}
 
 	/* change the rates */
 	clk_change_rate(top);
 
 	core->req_rate = req_rate;
+err:
+	clk_pm_runtime_put(core);
 
-	return 0;
+	return ret;
 }
 
 /**
@@ -1824,12 +1885,16 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
 		p_rate = parent->rate;
 	}
 
+	ret = clk_pm_runtime_get(core);
+	if (ret)
+		goto out;
+
 	/* propagate PRE_RATE_CHANGE notifications */
 	ret = __clk_speculate_rates(core, p_rate);
 
 	/* abort if a driver objects */
 	if (ret & NOTIFY_STOP_MASK)
-		goto out;
+		goto runtime_put;
 
 	/* do the re-parent */
 	ret = __clk_set_parent(core, parent, p_index);
@@ -1842,6 +1907,8 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
 		__clk_recalc_accuracies(core);
 	}
 
+runtime_put:
+	clk_pm_runtime_put(core);
 out:
 	clk_prepare_unlock();
 
@@ -2546,6 +2613,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
 		goto fail_name;
 	}
 	core->ops = hw->init->ops;
+	core->dev = dev;
 	if (dev && dev->driver)
 		core->owner = dev->driver->owner;
 	core->hw = hw;
-- 
1.9.1

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

* [PATCH 1/5] clk: add support for runtime pm
@ 2016-09-01 13:45   ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-arm-kernel

Registers for some clocks might be located in the SOC area, which are under the
power domain. To enable access to those registers respective domain has to be
turned on. Additionally, registers for such clocks will usually loose its
contents when power domain is turned off, so additional saving and restoring of
them might be needed in the clock controller driver.

This patch adds basic infrastructure in the clocks core to allow implementing
driver for such clocks under power domains. Clock provider can supply a
struct device pointer, which is the used by clock core for tracking and managing
clock's controller runtime pm state. Each clk_prepare() operation
will first call pm_runtime_get_sync() on the supplied device, while
clk_unprepare() will do pm_runtime_put() at the end.

Additional calls to pm_runtime_get/put functions are required to ensure that any
register access (like calculating/chaning clock rates) will be done with clock
controller in active runtime state.

Special handling of the case when runtime pm is disabled for clock controller's
device is needed to let this feature work properly also during system sleep
suspend/resume operations (runtime pm is first disabled before entering sleep
state's, but controller is usually still operational until its suspend pm
callback is called).

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/clk/clk.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 76 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 820a939fb6bb..a1934e9b4e95 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -21,6 +21,7 @@
 #include <linux/of.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/pm_runtime.h>
 #include <linux/sched.h>
 #include <linux/clkdev.h>
 
@@ -46,6 +47,7 @@ struct clk_core {
 	const struct clk_ops	*ops;
 	struct clk_hw		*hw;
 	struct module		*owner;
+	struct device		*dev;
 	struct clk_core		*parent;
 	const char		**parent_names;
 	struct clk_core		**parents;
@@ -87,6 +89,42 @@ struct clk {
 	struct hlist_node clks_node;
 };
 
+/***           runtime pm          ***/
+static int clk_pm_runtime_get(struct clk_core *core)
+{
+	int ret = 0;
+
+	if (!core->dev)
+		return 0;
+
+	if (pm_runtime_enabled(core->dev)) {
+		ret = pm_runtime_get_sync(core->dev);
+	} else {
+		if (!pm_runtime_status_suspended(core->dev))
+			pm_runtime_get_noresume(core->dev);
+	}
+	return ret < 0 ? ret : 0;
+}
+
+static void clk_pm_runtime_put(struct clk_core *core)
+{
+	if (!core->dev)
+		return;
+
+	if (pm_runtime_enabled(core->dev))
+		pm_runtime_put(core->dev);
+	else
+		pm_runtime_put_noidle(core->dev);
+}
+
+static bool clk_pm_runtime_suspended(struct clk_core *core)
+{
+	if (!core->dev)
+		return 0;
+
+	return pm_runtime_suspended(core->dev);
+}
+
 /***           locking             ***/
 static void clk_prepare_lock(void)
 {
@@ -150,6 +188,9 @@ static void clk_enable_unlock(unsigned long flags)
 
 static bool clk_core_is_prepared(struct clk_core *core)
 {
+	if (clk_pm_runtime_suspended(core))
+		return false;
+
 	/*
 	 * .is_prepared is optional for clocks that can prepare
 	 * fall back to software usage counter if it is missing
@@ -162,6 +203,9 @@ static bool clk_core_is_prepared(struct clk_core *core)
 
 static bool clk_core_is_enabled(struct clk_core *core)
 {
+	if (clk_pm_runtime_suspended(core))
+		return false;
+
 	/*
 	 * .is_enabled is only mandatory for clocks that gate
 	 * fall back to software usage counter if .is_enabled is missing
@@ -489,6 +533,8 @@ static void clk_core_unprepare(struct clk_core *core)
 	if (core->ops->unprepare)
 		core->ops->unprepare(core->hw);
 
+	clk_pm_runtime_put(core);
+
 	trace_clk_unprepare_complete(core);
 	clk_core_unprepare(core->parent);
 }
@@ -530,10 +576,14 @@ static int clk_core_prepare(struct clk_core *core)
 		return 0;
 
 	if (core->prepare_count == 0) {
-		ret = clk_core_prepare(core->parent);
+		ret = clk_pm_runtime_get(core);
 		if (ret)
 			return ret;
 
+		ret = clk_core_prepare(core->parent);
+		if (ret)
+			goto runtime_put;
+
 		trace_clk_prepare(core);
 
 		if (core->ops->prepare)
@@ -541,15 +591,18 @@ static int clk_core_prepare(struct clk_core *core)
 
 		trace_clk_prepare_complete(core);
 
-		if (ret) {
-			clk_core_unprepare(core->parent);
-			return ret;
-		}
+		if (ret)
+			goto unprepare;
 	}
 
 	core->prepare_count++;
 
 	return 0;
+unprepare:
+	clk_core_unprepare(core->parent);
+runtime_put:
+	clk_pm_runtime_put(core);
+	return ret;
 }
 
 static int clk_core_prepare_lock(struct clk_core *core)
@@ -1563,6 +1616,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
 {
 	struct clk_core *top, *fail_clk;
 	unsigned long rate = req_rate;
+	int ret = 0;
 
 	if (!core)
 		return 0;
@@ -1579,21 +1633,28 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
 	if (!top)
 		return -EINVAL;
 
+	ret = clk_pm_runtime_get(core);
+	if (ret)
+		return ret;
+
 	/* notify that we are about to change rates */
 	fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
 	if (fail_clk) {
 		pr_debug("%s: failed to set %s rate\n", __func__,
 				fail_clk->name);
 		clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
-		return -EBUSY;
+		ret = -EBUSY;
+		goto err;
 	}
 
 	/* change the rates */
 	clk_change_rate(top);
 
 	core->req_rate = req_rate;
+err:
+	clk_pm_runtime_put(core);
 
-	return 0;
+	return ret;
 }
 
 /**
@@ -1824,12 +1885,16 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
 		p_rate = parent->rate;
 	}
 
+	ret = clk_pm_runtime_get(core);
+	if (ret)
+		goto out;
+
 	/* propagate PRE_RATE_CHANGE notifications */
 	ret = __clk_speculate_rates(core, p_rate);
 
 	/* abort if a driver objects */
 	if (ret & NOTIFY_STOP_MASK)
-		goto out;
+		goto runtime_put;
 
 	/* do the re-parent */
 	ret = __clk_set_parent(core, parent, p_index);
@@ -1842,6 +1907,8 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
 		__clk_recalc_accuracies(core);
 	}
 
+runtime_put:
+	clk_pm_runtime_put(core);
 out:
 	clk_prepare_unlock();
 
@@ -2546,6 +2613,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
 		goto fail_name;
 	}
 	core->ops = hw->init->ops;
+	core->dev = dev;
 	if (dev && dev->driver)
 		core->owner = dev->driver->owner;
 	core->hw = hw;
-- 
1.9.1

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

* [PATCH 2/5] clock: samsung: add support for runtime pm
  2016-09-01 13:45 ` Marek Szyprowski
  (?)
@ 2016-09-01 13:45   ` Marek Szyprowski
  -1 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel
  Cc: Marek Szyprowski, Stephen Boyd, Michael Turquette, Ulf Hansson,
	Sylwester Nawrocki, Chanwoo Choi, Inki Dae, Krzysztof Kozlowski,
	Bartlomiej Zolnierkiewicz

This patch adds struct device pointer to samsung_clk_provider and forwarding it
to clk_register_* functions, so drivers can register clocks, which use runtime
pm feature.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/clk/samsung/clk-pll.c |  2 +-
 drivers/clk/samsung/clk.c     | 12 ++++++------
 drivers/clk/samsung/clk.h     |  1 +
 3 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index 48139bd510f1..644a7b748792 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -1285,7 +1285,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
 	pll->lock_reg = base + pll_clk->lock_offset;
 	pll->con_reg = base + pll_clk->con_offset;
 
-	clk = clk_register(NULL, &pll->hw);
+	clk = clk_register(ctx->dev, &pll->hw);
 	if (IS_ERR(clk)) {
 		pr_err("%s: failed to register pll clock %s : %ld\n",
 			__func__, pll_clk->name, PTR_ERR(clk));
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index b7d87d6db9dc..e6923714f024 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -143,7 +143,7 @@ void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx,
 	unsigned int idx, ret;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
-		clk = clk_register_fixed_rate(NULL, list->name,
+		clk = clk_register_fixed_rate(ctx->dev, list->name,
 			list->parent_name, list->flags, list->fixed_rate);
 		if (IS_ERR(clk)) {
 			pr_err("%s: failed to register clock %s\n", __func__,
@@ -172,7 +172,7 @@ void __init samsung_clk_register_fixed_factor(struct samsung_clk_provider *ctx,
 	unsigned int idx;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
-		clk = clk_register_fixed_factor(NULL, list->name,
+		clk = clk_register_fixed_factor(ctx->dev, list->name,
 			list->parent_name, list->flags, list->mult, list->div);
 		if (IS_ERR(clk)) {
 			pr_err("%s: failed to register clock %s\n", __func__,
@@ -193,7 +193,7 @@ void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx,
 	unsigned int idx, ret;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
-		clk = clk_register_mux(NULL, list->name, list->parent_names,
+		clk = clk_register_mux(ctx->dev, list->name, list->parent_names,
 			list->num_parents, list->flags,
 			ctx->reg_base + list->offset,
 			list->shift, list->width, list->mux_flags, &ctx->lock);
@@ -226,13 +226,13 @@ void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
 		if (list->table)
-			clk = clk_register_divider_table(NULL, list->name,
+			clk = clk_register_divider_table(ctx->dev, list->name,
 				list->parent_name, list->flags,
 				ctx->reg_base + list->offset,
 				list->shift, list->width, list->div_flags,
 				list->table, &ctx->lock);
 		else
-			clk = clk_register_divider(NULL, list->name,
+			clk = clk_register_divider(ctx->dev, list->name,
 				list->parent_name, list->flags,
 				ctx->reg_base + list->offset, list->shift,
 				list->width, list->div_flags, &ctx->lock);
@@ -264,7 +264,7 @@ void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
 	unsigned int idx, ret;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
-		clk = clk_register_gate(NULL, list->name, list->parent_name,
+		clk = clk_register_gate(ctx->dev, list->name, list->parent_name,
 				list->flags, ctx->reg_base + list->offset,
 				list->bit_idx, list->gate_flags, &ctx->lock);
 		if (IS_ERR(clk)) {
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index da3bdebabf1e..9263d8a27c6b 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -26,6 +26,7 @@ struct clk;
  */
 struct samsung_clk_provider {
 	void __iomem *reg_base;
+	struct device *dev;
 	struct clk_onecell_data clk_data;
 	spinlock_t lock;
 };
-- 
1.9.1

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

* [PATCH 2/5] clock: samsung: add support for runtime pm
@ 2016-09-01 13:45   ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel
  Cc: Ulf Hansson, Bartlomiej Zolnierkiewicz, Michael Turquette,
	Stephen Boyd, Krzysztof Kozlowski, Inki Dae, Chanwoo Choi,
	Sylwester Nawrocki, Marek Szyprowski

This patch adds struct device pointer to samsung_clk_provider and forwarding it
to clk_register_* functions, so drivers can register clocks, which use runtime
pm feature.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/clk/samsung/clk-pll.c |  2 +-
 drivers/clk/samsung/clk.c     | 12 ++++++------
 drivers/clk/samsung/clk.h     |  1 +
 3 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index 48139bd510f1..644a7b748792 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -1285,7 +1285,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
 	pll->lock_reg = base + pll_clk->lock_offset;
 	pll->con_reg = base + pll_clk->con_offset;
 
-	clk = clk_register(NULL, &pll->hw);
+	clk = clk_register(ctx->dev, &pll->hw);
 	if (IS_ERR(clk)) {
 		pr_err("%s: failed to register pll clock %s : %ld\n",
 			__func__, pll_clk->name, PTR_ERR(clk));
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index b7d87d6db9dc..e6923714f024 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -143,7 +143,7 @@ void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx,
 	unsigned int idx, ret;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
-		clk = clk_register_fixed_rate(NULL, list->name,
+		clk = clk_register_fixed_rate(ctx->dev, list->name,
 			list->parent_name, list->flags, list->fixed_rate);
 		if (IS_ERR(clk)) {
 			pr_err("%s: failed to register clock %s\n", __func__,
@@ -172,7 +172,7 @@ void __init samsung_clk_register_fixed_factor(struct samsung_clk_provider *ctx,
 	unsigned int idx;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
-		clk = clk_register_fixed_factor(NULL, list->name,
+		clk = clk_register_fixed_factor(ctx->dev, list->name,
 			list->parent_name, list->flags, list->mult, list->div);
 		if (IS_ERR(clk)) {
 			pr_err("%s: failed to register clock %s\n", __func__,
@@ -193,7 +193,7 @@ void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx,
 	unsigned int idx, ret;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
-		clk = clk_register_mux(NULL, list->name, list->parent_names,
+		clk = clk_register_mux(ctx->dev, list->name, list->parent_names,
 			list->num_parents, list->flags,
 			ctx->reg_base + list->offset,
 			list->shift, list->width, list->mux_flags, &ctx->lock);
@@ -226,13 +226,13 @@ void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
 		if (list->table)
-			clk = clk_register_divider_table(NULL, list->name,
+			clk = clk_register_divider_table(ctx->dev, list->name,
 				list->parent_name, list->flags,
 				ctx->reg_base + list->offset,
 				list->shift, list->width, list->div_flags,
 				list->table, &ctx->lock);
 		else
-			clk = clk_register_divider(NULL, list->name,
+			clk = clk_register_divider(ctx->dev, list->name,
 				list->parent_name, list->flags,
 				ctx->reg_base + list->offset, list->shift,
 				list->width, list->div_flags, &ctx->lock);
@@ -264,7 +264,7 @@ void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
 	unsigned int idx, ret;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
-		clk = clk_register_gate(NULL, list->name, list->parent_name,
+		clk = clk_register_gate(ctx->dev, list->name, list->parent_name,
 				list->flags, ctx->reg_base + list->offset,
 				list->bit_idx, list->gate_flags, &ctx->lock);
 		if (IS_ERR(clk)) {
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index da3bdebabf1e..9263d8a27c6b 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -26,6 +26,7 @@ struct clk;
  */
 struct samsung_clk_provider {
 	void __iomem *reg_base;
+	struct device *dev;
 	struct clk_onecell_data clk_data;
 	spinlock_t lock;
 };
-- 
1.9.1

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

* [PATCH 2/5] clock: samsung: add support for runtime pm
@ 2016-09-01 13:45   ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds struct device pointer to samsung_clk_provider and forwarding it
to clk_register_* functions, so drivers can register clocks, which use runtime
pm feature.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/clk/samsung/clk-pll.c |  2 +-
 drivers/clk/samsung/clk.c     | 12 ++++++------
 drivers/clk/samsung/clk.h     |  1 +
 3 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index 48139bd510f1..644a7b748792 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -1285,7 +1285,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
 	pll->lock_reg = base + pll_clk->lock_offset;
 	pll->con_reg = base + pll_clk->con_offset;
 
-	clk = clk_register(NULL, &pll->hw);
+	clk = clk_register(ctx->dev, &pll->hw);
 	if (IS_ERR(clk)) {
 		pr_err("%s: failed to register pll clock %s : %ld\n",
 			__func__, pll_clk->name, PTR_ERR(clk));
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index b7d87d6db9dc..e6923714f024 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -143,7 +143,7 @@ void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx,
 	unsigned int idx, ret;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
-		clk = clk_register_fixed_rate(NULL, list->name,
+		clk = clk_register_fixed_rate(ctx->dev, list->name,
 			list->parent_name, list->flags, list->fixed_rate);
 		if (IS_ERR(clk)) {
 			pr_err("%s: failed to register clock %s\n", __func__,
@@ -172,7 +172,7 @@ void __init samsung_clk_register_fixed_factor(struct samsung_clk_provider *ctx,
 	unsigned int idx;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
-		clk = clk_register_fixed_factor(NULL, list->name,
+		clk = clk_register_fixed_factor(ctx->dev, list->name,
 			list->parent_name, list->flags, list->mult, list->div);
 		if (IS_ERR(clk)) {
 			pr_err("%s: failed to register clock %s\n", __func__,
@@ -193,7 +193,7 @@ void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx,
 	unsigned int idx, ret;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
-		clk = clk_register_mux(NULL, list->name, list->parent_names,
+		clk = clk_register_mux(ctx->dev, list->name, list->parent_names,
 			list->num_parents, list->flags,
 			ctx->reg_base + list->offset,
 			list->shift, list->width, list->mux_flags, &ctx->lock);
@@ -226,13 +226,13 @@ void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
 		if (list->table)
-			clk = clk_register_divider_table(NULL, list->name,
+			clk = clk_register_divider_table(ctx->dev, list->name,
 				list->parent_name, list->flags,
 				ctx->reg_base + list->offset,
 				list->shift, list->width, list->div_flags,
 				list->table, &ctx->lock);
 		else
-			clk = clk_register_divider(NULL, list->name,
+			clk = clk_register_divider(ctx->dev, list->name,
 				list->parent_name, list->flags,
 				ctx->reg_base + list->offset, list->shift,
 				list->width, list->div_flags, &ctx->lock);
@@ -264,7 +264,7 @@ void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
 	unsigned int idx, ret;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
-		clk = clk_register_gate(NULL, list->name, list->parent_name,
+		clk = clk_register_gate(ctx->dev, list->name, list->parent_name,
 				list->flags, ctx->reg_base + list->offset,
 				list->bit_idx, list->gate_flags, &ctx->lock);
 		if (IS_ERR(clk)) {
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index da3bdebabf1e..9263d8a27c6b 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -26,6 +26,7 @@ struct clk;
  */
 struct samsung_clk_provider {
 	void __iomem *reg_base;
+	struct device *dev;
 	struct clk_onecell_data clk_data;
 	spinlock_t lock;
 };
-- 
1.9.1

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

* [PATCH 3/5] clocks: exynos4x12: add runtime pm support for ISP clocks
  2016-09-01 13:45 ` Marek Szyprowski
  (?)
@ 2016-09-01 13:45   ` Marek Szyprowski
  -1 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel
  Cc: Marek Szyprowski, Stephen Boyd, Michael Turquette, Ulf Hansson,
	Sylwester Nawrocki, Chanwoo Choi, Inki Dae, Krzysztof Kozlowski,
	Bartlomiej Zolnierkiewicz

Exynos4412 clock controller contains some additional clocks for FIMC-ISP
(Camera ISP) subsystem. Registers for those clocks are partially located
in the SOC area, which belongs to ISP power domain.

This patch implements integration of ISP clocks with ISP power domain
by using runtime pm feature of clocks core. This finally solves all the
mysterious freezes in accessing ISP clocks when ISP power domain is disabled.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 .../devicetree/bindings/clock/exynos4-clock.txt    |  22 ++
 drivers/clk/samsung/clk-exynos4.c                  | 228 +++++++++++++++------
 2 files changed, 189 insertions(+), 61 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/exynos4-clock.txt b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
index f5a5b19ed3b2..429dd7e420e4 100644
--- a/Documentation/devicetree/bindings/clock/exynos4-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
@@ -41,3 +41,25 @@ Example 2: UART controller node that consumes the clock generated by the clock
 		clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>;
 		clock-names = "uart", "clk_uart_baud0";
 	};
+
+Exynos4412 clock controller contains some additional clocks for FIMC-ISP
+(Camera ISP) subsystem. Registers for those clocks are partially located
+in the SOC area, which belongs to ISP power domain. To properly handle
+additional ISP clocks and their integration with power domains, an
+additional subnode "isp-clock-controller" with "samsung,exynos4412-isp-clock"
+compatible has to be defined under the main Exynos4 clock node. This subnode
+can be then used for linking with respective ISP power domain (for more
+information, see Samsung Exynos power domains bindings).
+
+Example 3: An example of a clock controller for Exynos4412 with ISP clocks.
+
+	clock: clock-controller@10030000 {
+		compatible = "samsung,exynos4412-clock";
+		reg = <0x10030000 0x20000>;
+		#clock-cells = <1>;
+
+		isp-clock-controller {
+			compatible = "samsung,exynos4412-isp-clock";
+			power-domains = <&pd_isp>;
+		};
+	};
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index faab9b31baf5..50a98fb3e895 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -16,7 +16,10 @@
 #include <linux/clk-provider.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_platform.h>
 #include <linux/syscore_ops.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #include "clk.h"
 #include "clk-cpu.h"
@@ -123,6 +126,8 @@
 #define CLKOUT_CMU_CPU		0x14a00
 #define PWR_CTRL1		0x15020
 #define E4X12_PWR_CTRL2		0x15024
+
+/* Exynos4x12 specific registers, which belong to ISP power domain */
 #define E4X12_DIV_ISP0		0x18300
 #define E4X12_DIV_ISP1		0x18304
 #define E4X12_GATE_ISP0		0x18800
@@ -156,6 +161,8 @@ enum exynos4_plls {
 
 static void __iomem *reg_base;
 static enum exynos4_soc exynos4_soc;
+static struct samsung_clk_provider *exynos4412_ctx;
+static struct device_node *exynos4412_clk_node;
 
 /*
  * Support for CMU save/restore across system suspends
@@ -164,6 +171,7 @@ static enum exynos4_soc exynos4_soc;
 static struct samsung_clk_reg_dump *exynos4_save_common;
 static struct samsung_clk_reg_dump *exynos4_save_soc;
 static struct samsung_clk_reg_dump *exynos4_save_pll;
+static struct samsung_clk_reg_dump *exynos4x12_save_isp;
 
 /*
  * list of controller registers to be saved and restored during a
@@ -192,6 +200,13 @@ static const unsigned long exynos4x12_clk_save[] __initconst = {
 	E4X12_PWR_CTRL2,
 };
 
+static const unsigned long exynos4x12_clk_isp_save[] __initconst = {
+	E4X12_DIV_ISP0,
+	E4X12_DIV_ISP1,
+	E4X12_GATE_ISP0,
+	E4X12_GATE_ISP1,
+};
+
 static const unsigned long exynos4_clk_pll_regs[] __initconst = {
 	EPLL_LOCK,
 	VPLL_LOCK,
@@ -822,20 +837,21 @@ static const struct samsung_div_clock exynos4x12_div_clks[] __initconst = {
 	DIV(0, "div_spi1_isp", "mout_spi1_isp", E4X12_DIV_ISP, 16, 4),
 	DIV(0, "div_spi1_isp_pre", "div_spi1_isp", E4X12_DIV_ISP, 20, 8),
 	DIV(0, "div_uart_isp", "mout_uart_isp", E4X12_DIV_ISP, 28, 4),
-	DIV_F(CLK_DIV_ISP0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3,
-						CLK_GET_RATE_NOCACHE, 0),
-	DIV_F(CLK_DIV_ISP1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3,
-						CLK_GET_RATE_NOCACHE, 0),
-	DIV(0, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3),
-	DIV_F(CLK_DIV_MCUISP0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1,
-						4, 3, CLK_GET_RATE_NOCACHE, 0),
-	DIV_F(CLK_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1,
-						8, 3, CLK_GET_RATE_NOCACHE, 0),
 	DIV(CLK_SCLK_FIMG2D, "sclk_fimg2d", "mout_g2d", DIV_DMC1, 0, 4),
 	DIV(CLK_DIV_C2C, "div_c2c", "mout_c2c", DIV_DMC1, 4, 3),
 	DIV(0, "div_c2c_aclk", "div_c2c", DIV_DMC1, 12, 3),
 };
 
+static struct samsung_div_clock exynos4x12_isp_div_clks[] = {
+	DIV_F(CLK_DIV_ISP0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3, 0, 0),
+	DIV_F(CLK_DIV_ISP1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3, 0, 0),
+	DIV_F(CLK_DIV_MCUISP0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1,
+						4, 3, 0, 0),
+	DIV_F(CLK_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1,
+						8, 3, 0, 0),
+	DIV_F(0, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3, 0, 0),
+};
+
 /* list of gate clocks supported in all exynos4 soc's */
 static const struct samsung_gate_clock exynos4_gate_clks[] __initconst = {
 	/*
@@ -1132,64 +1148,41 @@ static const struct samsung_gate_clock exynos4x12_gate_clks[] __initconst = {
 			0, 0),
 	GATE(CLK_I2S0, "i2s0", "aclk100", E4X12_GATE_IP_MAUDIO, 3,
 			0, 0),
-	GATE(CLK_FIMC_ISP, "isp", "aclk200", E4X12_GATE_ISP0, 0,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_FIMC_DRC, "drc", "aclk200", E4X12_GATE_ISP0, 1,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_FIMC_FD, "fd", "aclk200", E4X12_GATE_ISP0, 2,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_FIMC_LITE0, "lite0", "aclk200", E4X12_GATE_ISP0, 3,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_FIMC_LITE1, "lite1", "aclk200", E4X12_GATE_ISP0, 4,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_MCUISP, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_GICISP, "gicisp", "aclk200", E4X12_GATE_ISP0, 7,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_ISP, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_DRC, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_FD, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_LITE0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_LITE1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_PPMUISPMX, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_PPMUISPX, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_MCUCTL_ISP, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_MPWM_ISP, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_I2C0_ISP, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_I2C1_ISP, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_MTCADC_ISP, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_PWM_ISP, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_WDT_ISP, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_UART_ISP, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_ASYNCAXIM, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_ISPCX, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SPI0_ISP, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
 	GATE(CLK_G2D, "g2d", "aclk200", GATE_IP_DMC, 23, 0, 0),
 	GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk200", GATE_IP_DMC, 24, 0, 0),
 	GATE(CLK_TMU_APBIF, "tmu_apbif", "aclk100", E4X12_GATE_IP_PERIR, 17, 0,
 		0),
 };
 
+static struct samsung_gate_clock exynos4x12_isp_gate_clks[] = {
+	GATE(CLK_FIMC_ISP, "isp", "aclk200", E4X12_GATE_ISP0, 0, 0, 0),
+	GATE(CLK_FIMC_DRC, "drc", "aclk200", E4X12_GATE_ISP0, 1, 0, 0),
+	GATE(CLK_FIMC_FD, "fd", "aclk200", E4X12_GATE_ISP0, 2, 0, 0),
+	GATE(CLK_FIMC_LITE0, "lite0", "aclk200", E4X12_GATE_ISP0, 3, 0, 0),
+	GATE(CLK_FIMC_LITE1, "lite1", "aclk200", E4X12_GATE_ISP0, 4, 0, 0),
+	GATE(CLK_MCUISP, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5, 0, 0),
+	GATE(CLK_GICISP, "gicisp", "aclk200", E4X12_GATE_ISP0, 7, 0, 0),
+	GATE(CLK_SMMU_ISP, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8, 0, 0),
+	GATE(CLK_SMMU_DRC, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9, 0, 0),
+	GATE(CLK_SMMU_FD, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10, 0, 0),
+	GATE(CLK_SMMU_LITE0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11, 0, 0),
+	GATE(CLK_SMMU_LITE1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12, 0, 0),
+	GATE(CLK_PPMUISPMX, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20, 0, 0),
+	GATE(CLK_PPMUISPX, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21, 0, 0),
+	GATE(CLK_MCUCTL_ISP, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23, 0, 0),
+	GATE(CLK_MPWM_ISP, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24, 0, 0),
+	GATE(CLK_I2C0_ISP, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25, 0, 0),
+	GATE(CLK_I2C1_ISP, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26, 0, 0),
+	GATE(CLK_MTCADC_ISP, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27, 0, 0),
+	GATE(CLK_PWM_ISP, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28, 0, 0),
+	GATE(CLK_WDT_ISP, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30, 0, 0),
+	GATE(CLK_UART_ISP, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31, 0, 0),
+	GATE(CLK_ASYNCAXIM, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0, 0, 0),
+	GATE(CLK_SMMU_ISPCX, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4, 0, 0),
+	GATE(CLK_SPI0_ISP, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12, 0, 0),
+	GATE(CLK_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13, 0, 0),
+};
+
 static const struct samsung_clock_alias exynos4_aliases[] __initconst = {
 	ALIAS(CLK_MOUT_CORE, NULL, "moutcore"),
 	ALIAS(CLK_ARM_CLK, NULL, "armclk"),
@@ -1438,6 +1431,117 @@ static const struct exynos_cpuclk_cfg_data e4412_armclk_d[] __initconst = {
 	{  0 },
 };
 
+static int exynos4x12_isp_clk_suspend(struct device *dev)
+{
+	samsung_clk_save(reg_base, exynos4x12_save_isp,
+				ARRAY_SIZE(exynos4x12_clk_isp_save));
+	return 0;
+}
+
+static int exynos4x12_isp_clk_resume(struct device *dev)
+{
+	samsung_clk_restore(reg_base, exynos4x12_save_isp,
+				ARRAY_SIZE(exynos4x12_clk_isp_save));
+	return 0;
+}
+
+static int __init exynos4x12_isp_clk_probe(struct platform_device *pdev)
+{
+	struct samsung_clk_provider *ctx = exynos4412_ctx;
+
+	if (!ctx)
+		return -ENODEV;
+
+	dev_set_name(&pdev->dev, pdev->dev.of_node->name);
+
+	ctx->dev = &pdev->dev;
+	samsung_clk_register_div(ctx, exynos4x12_isp_div_clks,
+		ARRAY_SIZE(exynos4x12_isp_div_clks));
+
+	samsung_clk_register_gate(ctx, exynos4x12_isp_gate_clks,
+		ARRAY_SIZE(exynos4x12_isp_gate_clks));
+	ctx->dev = NULL;
+
+	exynos4x12_save_isp = samsung_clk_alloc_reg_dump(exynos4x12_clk_isp_save,
+					ARRAY_SIZE(exynos4x12_clk_isp_save));
+	if (!exynos4x12_save_isp)
+		dev_warn(&pdev->dev, "failed to allocate sleep save data, no sleep support!\n");
+	else {
+		/* save initial values */
+		exynos4x12_isp_clk_suspend(&pdev->dev);
+		pm_runtime_enable(&pdev->dev);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id exynos4x12_isp_clk_of_match[] = {
+	{ .compatible = "samsung,exynos4412-isp-clock", },
+	{ },
+};
+
+static const struct dev_pm_ops exynos4x12_isp_pm_ops = {
+	SET_RUNTIME_PM_OPS(exynos4x12_isp_clk_suspend,
+			   exynos4x12_isp_clk_resume, NULL)
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				     pm_runtime_force_resume)
+};
+
+static struct platform_driver exynos4x12_isp_clk_driver = {
+	.driver	= {
+		.name = "exynos-isp-clk",
+		.of_match_table = exynos4x12_isp_clk_of_match,
+		.suppress_bind_attrs = true,
+		.pm = &exynos4x12_isp_pm_ops,
+	},
+	.probe = exynos4x12_isp_clk_probe,
+};
+
+static int __init exynos4x12_isp_clk_init(void)
+{
+	struct platform_device *parent_pdev;
+	struct device *parent;
+	int ret;
+
+	if (!exynos4412_clk_node)
+		return 0;
+
+	parent_pdev = of_find_device_by_node(exynos4412_clk_node);
+	if (!parent_pdev)
+		return -ENODEV;
+
+	parent = &parent_pdev->dev;
+	ret = of_platform_populate(parent->of_node, NULL, NULL, parent);
+	if (ret)
+		return ret;
+
+	return platform_driver_register(&exynos4x12_isp_clk_driver);
+}
+arch_initcall_sync(exynos4x12_isp_clk_init);
+
+static void __init exynos4x12_isp_defer_clocks(struct samsung_clk_provider *ctx,
+					       struct device_node *parent)
+{
+	struct device_node *np = of_get_next_available_child(parent, NULL);
+	if (!np)
+		return;
+
+	if (of_device_is_compatible(np,
+		    exynos4x12_isp_clk_of_match[0].compatible)) {
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(exynos4x12_isp_div_clks); i++)
+			samsung_clk_add_lookup(ctx, ERR_PTR(-EPROBE_DEFER),
+					       exynos4x12_isp_div_clks[i].id);
+		for (i = 0; i < ARRAY_SIZE(exynos4x12_isp_gate_clks); i++)
+			samsung_clk_add_lookup(ctx, ERR_PTR(-EPROBE_DEFER),
+					       exynos4x12_isp_gate_clks[i].id);
+		exynos4412_ctx = ctx;
+		exynos4412_clk_node = parent;
+	}
+	of_node_put(np);
+}
+
 /* register exynos4 clocks */
 static void __init exynos4_clk_init(struct device_node *np,
 				    enum exynos4_soc soc)
@@ -1529,6 +1633,8 @@ static void __init exynos4_clk_init(struct device_node *np,
 		samsung_clk_register_fixed_factor(ctx,
 			exynos4x12_fixed_factor_clks,
 			ARRAY_SIZE(exynos4x12_fixed_factor_clks));
+		exynos4x12_isp_defer_clocks(ctx, np);
+
 		if (of_machine_is_compatible("samsung,exynos4412")) {
 			exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk",
 				mout_core_p4x12[0], mout_core_p4x12[1], 0x14200,
-- 
1.9.1

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

* [PATCH 3/5] clocks: exynos4x12: add runtime pm support for ISP clocks
@ 2016-09-01 13:45   ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel
  Cc: Ulf Hansson, Bartlomiej Zolnierkiewicz, Michael Turquette,
	Stephen Boyd, Krzysztof Kozlowski, Inki Dae, Chanwoo Choi,
	Sylwester Nawrocki, Marek Szyprowski

Exynos4412 clock controller contains some additional clocks for FIMC-ISP
(Camera ISP) subsystem. Registers for those clocks are partially located
in the SOC area, which belongs to ISP power domain.

This patch implements integration of ISP clocks with ISP power domain
by using runtime pm feature of clocks core. This finally solves all the
mysterious freezes in accessing ISP clocks when ISP power domain is disabled.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 .../devicetree/bindings/clock/exynos4-clock.txt    |  22 ++
 drivers/clk/samsung/clk-exynos4.c                  | 228 +++++++++++++++------
 2 files changed, 189 insertions(+), 61 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/exynos4-clock.txt b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
index f5a5b19ed3b2..429dd7e420e4 100644
--- a/Documentation/devicetree/bindings/clock/exynos4-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
@@ -41,3 +41,25 @@ Example 2: UART controller node that consumes the clock generated by the clock
 		clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>;
 		clock-names = "uart", "clk_uart_baud0";
 	};
+
+Exynos4412 clock controller contains some additional clocks for FIMC-ISP
+(Camera ISP) subsystem. Registers for those clocks are partially located
+in the SOC area, which belongs to ISP power domain. To properly handle
+additional ISP clocks and their integration with power domains, an
+additional subnode "isp-clock-controller" with "samsung,exynos4412-isp-clock"
+compatible has to be defined under the main Exynos4 clock node. This subnode
+can be then used for linking with respective ISP power domain (for more
+information, see Samsung Exynos power domains bindings).
+
+Example 3: An example of a clock controller for Exynos4412 with ISP clocks.
+
+	clock: clock-controller@10030000 {
+		compatible = "samsung,exynos4412-clock";
+		reg = <0x10030000 0x20000>;
+		#clock-cells = <1>;
+
+		isp-clock-controller {
+			compatible = "samsung,exynos4412-isp-clock";
+			power-domains = <&pd_isp>;
+		};
+	};
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index faab9b31baf5..50a98fb3e895 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -16,7 +16,10 @@
 #include <linux/clk-provider.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_platform.h>
 #include <linux/syscore_ops.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #include "clk.h"
 #include "clk-cpu.h"
@@ -123,6 +126,8 @@
 #define CLKOUT_CMU_CPU		0x14a00
 #define PWR_CTRL1		0x15020
 #define E4X12_PWR_CTRL2		0x15024
+
+/* Exynos4x12 specific registers, which belong to ISP power domain */
 #define E4X12_DIV_ISP0		0x18300
 #define E4X12_DIV_ISP1		0x18304
 #define E4X12_GATE_ISP0		0x18800
@@ -156,6 +161,8 @@ enum exynos4_plls {
 
 static void __iomem *reg_base;
 static enum exynos4_soc exynos4_soc;
+static struct samsung_clk_provider *exynos4412_ctx;
+static struct device_node *exynos4412_clk_node;
 
 /*
  * Support for CMU save/restore across system suspends
@@ -164,6 +171,7 @@ static enum exynos4_soc exynos4_soc;
 static struct samsung_clk_reg_dump *exynos4_save_common;
 static struct samsung_clk_reg_dump *exynos4_save_soc;
 static struct samsung_clk_reg_dump *exynos4_save_pll;
+static struct samsung_clk_reg_dump *exynos4x12_save_isp;
 
 /*
  * list of controller registers to be saved and restored during a
@@ -192,6 +200,13 @@ static const unsigned long exynos4x12_clk_save[] __initconst = {
 	E4X12_PWR_CTRL2,
 };
 
+static const unsigned long exynos4x12_clk_isp_save[] __initconst = {
+	E4X12_DIV_ISP0,
+	E4X12_DIV_ISP1,
+	E4X12_GATE_ISP0,
+	E4X12_GATE_ISP1,
+};
+
 static const unsigned long exynos4_clk_pll_regs[] __initconst = {
 	EPLL_LOCK,
 	VPLL_LOCK,
@@ -822,20 +837,21 @@ static const struct samsung_div_clock exynos4x12_div_clks[] __initconst = {
 	DIV(0, "div_spi1_isp", "mout_spi1_isp", E4X12_DIV_ISP, 16, 4),
 	DIV(0, "div_spi1_isp_pre", "div_spi1_isp", E4X12_DIV_ISP, 20, 8),
 	DIV(0, "div_uart_isp", "mout_uart_isp", E4X12_DIV_ISP, 28, 4),
-	DIV_F(CLK_DIV_ISP0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3,
-						CLK_GET_RATE_NOCACHE, 0),
-	DIV_F(CLK_DIV_ISP1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3,
-						CLK_GET_RATE_NOCACHE, 0),
-	DIV(0, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3),
-	DIV_F(CLK_DIV_MCUISP0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1,
-						4, 3, CLK_GET_RATE_NOCACHE, 0),
-	DIV_F(CLK_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1,
-						8, 3, CLK_GET_RATE_NOCACHE, 0),
 	DIV(CLK_SCLK_FIMG2D, "sclk_fimg2d", "mout_g2d", DIV_DMC1, 0, 4),
 	DIV(CLK_DIV_C2C, "div_c2c", "mout_c2c", DIV_DMC1, 4, 3),
 	DIV(0, "div_c2c_aclk", "div_c2c", DIV_DMC1, 12, 3),
 };
 
+static struct samsung_div_clock exynos4x12_isp_div_clks[] = {
+	DIV_F(CLK_DIV_ISP0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3, 0, 0),
+	DIV_F(CLK_DIV_ISP1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3, 0, 0),
+	DIV_F(CLK_DIV_MCUISP0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1,
+						4, 3, 0, 0),
+	DIV_F(CLK_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1,
+						8, 3, 0, 0),
+	DIV_F(0, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3, 0, 0),
+};
+
 /* list of gate clocks supported in all exynos4 soc's */
 static const struct samsung_gate_clock exynos4_gate_clks[] __initconst = {
 	/*
@@ -1132,64 +1148,41 @@ static const struct samsung_gate_clock exynos4x12_gate_clks[] __initconst = {
 			0, 0),
 	GATE(CLK_I2S0, "i2s0", "aclk100", E4X12_GATE_IP_MAUDIO, 3,
 			0, 0),
-	GATE(CLK_FIMC_ISP, "isp", "aclk200", E4X12_GATE_ISP0, 0,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_FIMC_DRC, "drc", "aclk200", E4X12_GATE_ISP0, 1,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_FIMC_FD, "fd", "aclk200", E4X12_GATE_ISP0, 2,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_FIMC_LITE0, "lite0", "aclk200", E4X12_GATE_ISP0, 3,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_FIMC_LITE1, "lite1", "aclk200", E4X12_GATE_ISP0, 4,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_MCUISP, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_GICISP, "gicisp", "aclk200", E4X12_GATE_ISP0, 7,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_ISP, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_DRC, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_FD, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_LITE0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_LITE1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_PPMUISPMX, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_PPMUISPX, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_MCUCTL_ISP, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_MPWM_ISP, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_I2C0_ISP, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_I2C1_ISP, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_MTCADC_ISP, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_PWM_ISP, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_WDT_ISP, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_UART_ISP, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_ASYNCAXIM, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_ISPCX, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SPI0_ISP, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
 	GATE(CLK_G2D, "g2d", "aclk200", GATE_IP_DMC, 23, 0, 0),
 	GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk200", GATE_IP_DMC, 24, 0, 0),
 	GATE(CLK_TMU_APBIF, "tmu_apbif", "aclk100", E4X12_GATE_IP_PERIR, 17, 0,
 		0),
 };
 
+static struct samsung_gate_clock exynos4x12_isp_gate_clks[] = {
+	GATE(CLK_FIMC_ISP, "isp", "aclk200", E4X12_GATE_ISP0, 0, 0, 0),
+	GATE(CLK_FIMC_DRC, "drc", "aclk200", E4X12_GATE_ISP0, 1, 0, 0),
+	GATE(CLK_FIMC_FD, "fd", "aclk200", E4X12_GATE_ISP0, 2, 0, 0),
+	GATE(CLK_FIMC_LITE0, "lite0", "aclk200", E4X12_GATE_ISP0, 3, 0, 0),
+	GATE(CLK_FIMC_LITE1, "lite1", "aclk200", E4X12_GATE_ISP0, 4, 0, 0),
+	GATE(CLK_MCUISP, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5, 0, 0),
+	GATE(CLK_GICISP, "gicisp", "aclk200", E4X12_GATE_ISP0, 7, 0, 0),
+	GATE(CLK_SMMU_ISP, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8, 0, 0),
+	GATE(CLK_SMMU_DRC, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9, 0, 0),
+	GATE(CLK_SMMU_FD, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10, 0, 0),
+	GATE(CLK_SMMU_LITE0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11, 0, 0),
+	GATE(CLK_SMMU_LITE1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12, 0, 0),
+	GATE(CLK_PPMUISPMX, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20, 0, 0),
+	GATE(CLK_PPMUISPX, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21, 0, 0),
+	GATE(CLK_MCUCTL_ISP, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23, 0, 0),
+	GATE(CLK_MPWM_ISP, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24, 0, 0),
+	GATE(CLK_I2C0_ISP, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25, 0, 0),
+	GATE(CLK_I2C1_ISP, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26, 0, 0),
+	GATE(CLK_MTCADC_ISP, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27, 0, 0),
+	GATE(CLK_PWM_ISP, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28, 0, 0),
+	GATE(CLK_WDT_ISP, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30, 0, 0),
+	GATE(CLK_UART_ISP, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31, 0, 0),
+	GATE(CLK_ASYNCAXIM, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0, 0, 0),
+	GATE(CLK_SMMU_ISPCX, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4, 0, 0),
+	GATE(CLK_SPI0_ISP, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12, 0, 0),
+	GATE(CLK_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13, 0, 0),
+};
+
 static const struct samsung_clock_alias exynos4_aliases[] __initconst = {
 	ALIAS(CLK_MOUT_CORE, NULL, "moutcore"),
 	ALIAS(CLK_ARM_CLK, NULL, "armclk"),
@@ -1438,6 +1431,117 @@ static const struct exynos_cpuclk_cfg_data e4412_armclk_d[] __initconst = {
 	{  0 },
 };
 
+static int exynos4x12_isp_clk_suspend(struct device *dev)
+{
+	samsung_clk_save(reg_base, exynos4x12_save_isp,
+				ARRAY_SIZE(exynos4x12_clk_isp_save));
+	return 0;
+}
+
+static int exynos4x12_isp_clk_resume(struct device *dev)
+{
+	samsung_clk_restore(reg_base, exynos4x12_save_isp,
+				ARRAY_SIZE(exynos4x12_clk_isp_save));
+	return 0;
+}
+
+static int __init exynos4x12_isp_clk_probe(struct platform_device *pdev)
+{
+	struct samsung_clk_provider *ctx = exynos4412_ctx;
+
+	if (!ctx)
+		return -ENODEV;
+
+	dev_set_name(&pdev->dev, pdev->dev.of_node->name);
+
+	ctx->dev = &pdev->dev;
+	samsung_clk_register_div(ctx, exynos4x12_isp_div_clks,
+		ARRAY_SIZE(exynos4x12_isp_div_clks));
+
+	samsung_clk_register_gate(ctx, exynos4x12_isp_gate_clks,
+		ARRAY_SIZE(exynos4x12_isp_gate_clks));
+	ctx->dev = NULL;
+
+	exynos4x12_save_isp = samsung_clk_alloc_reg_dump(exynos4x12_clk_isp_save,
+					ARRAY_SIZE(exynos4x12_clk_isp_save));
+	if (!exynos4x12_save_isp)
+		dev_warn(&pdev->dev, "failed to allocate sleep save data, no sleep support!\n");
+	else {
+		/* save initial values */
+		exynos4x12_isp_clk_suspend(&pdev->dev);
+		pm_runtime_enable(&pdev->dev);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id exynos4x12_isp_clk_of_match[] = {
+	{ .compatible = "samsung,exynos4412-isp-clock", },
+	{ },
+};
+
+static const struct dev_pm_ops exynos4x12_isp_pm_ops = {
+	SET_RUNTIME_PM_OPS(exynos4x12_isp_clk_suspend,
+			   exynos4x12_isp_clk_resume, NULL)
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				     pm_runtime_force_resume)
+};
+
+static struct platform_driver exynos4x12_isp_clk_driver = {
+	.driver	= {
+		.name = "exynos-isp-clk",
+		.of_match_table = exynos4x12_isp_clk_of_match,
+		.suppress_bind_attrs = true,
+		.pm = &exynos4x12_isp_pm_ops,
+	},
+	.probe = exynos4x12_isp_clk_probe,
+};
+
+static int __init exynos4x12_isp_clk_init(void)
+{
+	struct platform_device *parent_pdev;
+	struct device *parent;
+	int ret;
+
+	if (!exynos4412_clk_node)
+		return 0;
+
+	parent_pdev = of_find_device_by_node(exynos4412_clk_node);
+	if (!parent_pdev)
+		return -ENODEV;
+
+	parent = &parent_pdev->dev;
+	ret = of_platform_populate(parent->of_node, NULL, NULL, parent);
+	if (ret)
+		return ret;
+
+	return platform_driver_register(&exynos4x12_isp_clk_driver);
+}
+arch_initcall_sync(exynos4x12_isp_clk_init);
+
+static void __init exynos4x12_isp_defer_clocks(struct samsung_clk_provider *ctx,
+					       struct device_node *parent)
+{
+	struct device_node *np = of_get_next_available_child(parent, NULL);
+	if (!np)
+		return;
+
+	if (of_device_is_compatible(np,
+		    exynos4x12_isp_clk_of_match[0].compatible)) {
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(exynos4x12_isp_div_clks); i++)
+			samsung_clk_add_lookup(ctx, ERR_PTR(-EPROBE_DEFER),
+					       exynos4x12_isp_div_clks[i].id);
+		for (i = 0; i < ARRAY_SIZE(exynos4x12_isp_gate_clks); i++)
+			samsung_clk_add_lookup(ctx, ERR_PTR(-EPROBE_DEFER),
+					       exynos4x12_isp_gate_clks[i].id);
+		exynos4412_ctx = ctx;
+		exynos4412_clk_node = parent;
+	}
+	of_node_put(np);
+}
+
 /* register exynos4 clocks */
 static void __init exynos4_clk_init(struct device_node *np,
 				    enum exynos4_soc soc)
@@ -1529,6 +1633,8 @@ static void __init exynos4_clk_init(struct device_node *np,
 		samsung_clk_register_fixed_factor(ctx,
 			exynos4x12_fixed_factor_clks,
 			ARRAY_SIZE(exynos4x12_fixed_factor_clks));
+		exynos4x12_isp_defer_clocks(ctx, np);
+
 		if (of_machine_is_compatible("samsung,exynos4412")) {
 			exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk",
 				mout_core_p4x12[0], mout_core_p4x12[1], 0x14200,
-- 
1.9.1

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

* [PATCH 3/5] clocks: exynos4x12: add runtime pm support for ISP clocks
@ 2016-09-01 13:45   ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-arm-kernel

Exynos4412 clock controller contains some additional clocks for FIMC-ISP
(Camera ISP) subsystem. Registers for those clocks are partially located
in the SOC area, which belongs to ISP power domain.

This patch implements integration of ISP clocks with ISP power domain
by using runtime pm feature of clocks core. This finally solves all the
mysterious freezes in accessing ISP clocks when ISP power domain is disabled.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 .../devicetree/bindings/clock/exynos4-clock.txt    |  22 ++
 drivers/clk/samsung/clk-exynos4.c                  | 228 +++++++++++++++------
 2 files changed, 189 insertions(+), 61 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/exynos4-clock.txt b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
index f5a5b19ed3b2..429dd7e420e4 100644
--- a/Documentation/devicetree/bindings/clock/exynos4-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
@@ -41,3 +41,25 @@ Example 2: UART controller node that consumes the clock generated by the clock
 		clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>;
 		clock-names = "uart", "clk_uart_baud0";
 	};
+
+Exynos4412 clock controller contains some additional clocks for FIMC-ISP
+(Camera ISP) subsystem. Registers for those clocks are partially located
+in the SOC area, which belongs to ISP power domain. To properly handle
+additional ISP clocks and their integration with power domains, an
+additional subnode "isp-clock-controller" with "samsung,exynos4412-isp-clock"
+compatible has to be defined under the main Exynos4 clock node. This subnode
+can be then used for linking with respective ISP power domain (for more
+information, see Samsung Exynos power domains bindings).
+
+Example 3: An example of a clock controller for Exynos4412 with ISP clocks.
+
+	clock: clock-controller at 10030000 {
+		compatible = "samsung,exynos4412-clock";
+		reg = <0x10030000 0x20000>;
+		#clock-cells = <1>;
+
+		isp-clock-controller {
+			compatible = "samsung,exynos4412-isp-clock";
+			power-domains = <&pd_isp>;
+		};
+	};
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index faab9b31baf5..50a98fb3e895 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -16,7 +16,10 @@
 #include <linux/clk-provider.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_platform.h>
 #include <linux/syscore_ops.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #include "clk.h"
 #include "clk-cpu.h"
@@ -123,6 +126,8 @@
 #define CLKOUT_CMU_CPU		0x14a00
 #define PWR_CTRL1		0x15020
 #define E4X12_PWR_CTRL2		0x15024
+
+/* Exynos4x12 specific registers, which belong to ISP power domain */
 #define E4X12_DIV_ISP0		0x18300
 #define E4X12_DIV_ISP1		0x18304
 #define E4X12_GATE_ISP0		0x18800
@@ -156,6 +161,8 @@ enum exynos4_plls {
 
 static void __iomem *reg_base;
 static enum exynos4_soc exynos4_soc;
+static struct samsung_clk_provider *exynos4412_ctx;
+static struct device_node *exynos4412_clk_node;
 
 /*
  * Support for CMU save/restore across system suspends
@@ -164,6 +171,7 @@ static enum exynos4_soc exynos4_soc;
 static struct samsung_clk_reg_dump *exynos4_save_common;
 static struct samsung_clk_reg_dump *exynos4_save_soc;
 static struct samsung_clk_reg_dump *exynos4_save_pll;
+static struct samsung_clk_reg_dump *exynos4x12_save_isp;
 
 /*
  * list of controller registers to be saved and restored during a
@@ -192,6 +200,13 @@ static const unsigned long exynos4x12_clk_save[] __initconst = {
 	E4X12_PWR_CTRL2,
 };
 
+static const unsigned long exynos4x12_clk_isp_save[] __initconst = {
+	E4X12_DIV_ISP0,
+	E4X12_DIV_ISP1,
+	E4X12_GATE_ISP0,
+	E4X12_GATE_ISP1,
+};
+
 static const unsigned long exynos4_clk_pll_regs[] __initconst = {
 	EPLL_LOCK,
 	VPLL_LOCK,
@@ -822,20 +837,21 @@ static const struct samsung_div_clock exynos4x12_div_clks[] __initconst = {
 	DIV(0, "div_spi1_isp", "mout_spi1_isp", E4X12_DIV_ISP, 16, 4),
 	DIV(0, "div_spi1_isp_pre", "div_spi1_isp", E4X12_DIV_ISP, 20, 8),
 	DIV(0, "div_uart_isp", "mout_uart_isp", E4X12_DIV_ISP, 28, 4),
-	DIV_F(CLK_DIV_ISP0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3,
-						CLK_GET_RATE_NOCACHE, 0),
-	DIV_F(CLK_DIV_ISP1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3,
-						CLK_GET_RATE_NOCACHE, 0),
-	DIV(0, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3),
-	DIV_F(CLK_DIV_MCUISP0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1,
-						4, 3, CLK_GET_RATE_NOCACHE, 0),
-	DIV_F(CLK_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1,
-						8, 3, CLK_GET_RATE_NOCACHE, 0),
 	DIV(CLK_SCLK_FIMG2D, "sclk_fimg2d", "mout_g2d", DIV_DMC1, 0, 4),
 	DIV(CLK_DIV_C2C, "div_c2c", "mout_c2c", DIV_DMC1, 4, 3),
 	DIV(0, "div_c2c_aclk", "div_c2c", DIV_DMC1, 12, 3),
 };
 
+static struct samsung_div_clock exynos4x12_isp_div_clks[] = {
+	DIV_F(CLK_DIV_ISP0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3, 0, 0),
+	DIV_F(CLK_DIV_ISP1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3, 0, 0),
+	DIV_F(CLK_DIV_MCUISP0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1,
+						4, 3, 0, 0),
+	DIV_F(CLK_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1,
+						8, 3, 0, 0),
+	DIV_F(0, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3, 0, 0),
+};
+
 /* list of gate clocks supported in all exynos4 soc's */
 static const struct samsung_gate_clock exynos4_gate_clks[] __initconst = {
 	/*
@@ -1132,64 +1148,41 @@ static const struct samsung_gate_clock exynos4x12_gate_clks[] __initconst = {
 			0, 0),
 	GATE(CLK_I2S0, "i2s0", "aclk100", E4X12_GATE_IP_MAUDIO, 3,
 			0, 0),
-	GATE(CLK_FIMC_ISP, "isp", "aclk200", E4X12_GATE_ISP0, 0,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_FIMC_DRC, "drc", "aclk200", E4X12_GATE_ISP0, 1,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_FIMC_FD, "fd", "aclk200", E4X12_GATE_ISP0, 2,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_FIMC_LITE0, "lite0", "aclk200", E4X12_GATE_ISP0, 3,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_FIMC_LITE1, "lite1", "aclk200", E4X12_GATE_ISP0, 4,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_MCUISP, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_GICISP, "gicisp", "aclk200", E4X12_GATE_ISP0, 7,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_ISP, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_DRC, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_FD, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_LITE0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_LITE1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_PPMUISPMX, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_PPMUISPX, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_MCUCTL_ISP, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_MPWM_ISP, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_I2C0_ISP, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_I2C1_ISP, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_MTCADC_ISP, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_PWM_ISP, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_WDT_ISP, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_UART_ISP, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_ASYNCAXIM, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SMMU_ISPCX, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SPI0_ISP, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-	GATE(CLK_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13,
-			CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
 	GATE(CLK_G2D, "g2d", "aclk200", GATE_IP_DMC, 23, 0, 0),
 	GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk200", GATE_IP_DMC, 24, 0, 0),
 	GATE(CLK_TMU_APBIF, "tmu_apbif", "aclk100", E4X12_GATE_IP_PERIR, 17, 0,
 		0),
 };
 
+static struct samsung_gate_clock exynos4x12_isp_gate_clks[] = {
+	GATE(CLK_FIMC_ISP, "isp", "aclk200", E4X12_GATE_ISP0, 0, 0, 0),
+	GATE(CLK_FIMC_DRC, "drc", "aclk200", E4X12_GATE_ISP0, 1, 0, 0),
+	GATE(CLK_FIMC_FD, "fd", "aclk200", E4X12_GATE_ISP0, 2, 0, 0),
+	GATE(CLK_FIMC_LITE0, "lite0", "aclk200", E4X12_GATE_ISP0, 3, 0, 0),
+	GATE(CLK_FIMC_LITE1, "lite1", "aclk200", E4X12_GATE_ISP0, 4, 0, 0),
+	GATE(CLK_MCUISP, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5, 0, 0),
+	GATE(CLK_GICISP, "gicisp", "aclk200", E4X12_GATE_ISP0, 7, 0, 0),
+	GATE(CLK_SMMU_ISP, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8, 0, 0),
+	GATE(CLK_SMMU_DRC, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9, 0, 0),
+	GATE(CLK_SMMU_FD, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10, 0, 0),
+	GATE(CLK_SMMU_LITE0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11, 0, 0),
+	GATE(CLK_SMMU_LITE1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12, 0, 0),
+	GATE(CLK_PPMUISPMX, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20, 0, 0),
+	GATE(CLK_PPMUISPX, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21, 0, 0),
+	GATE(CLK_MCUCTL_ISP, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23, 0, 0),
+	GATE(CLK_MPWM_ISP, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24, 0, 0),
+	GATE(CLK_I2C0_ISP, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25, 0, 0),
+	GATE(CLK_I2C1_ISP, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26, 0, 0),
+	GATE(CLK_MTCADC_ISP, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27, 0, 0),
+	GATE(CLK_PWM_ISP, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28, 0, 0),
+	GATE(CLK_WDT_ISP, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30, 0, 0),
+	GATE(CLK_UART_ISP, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31, 0, 0),
+	GATE(CLK_ASYNCAXIM, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0, 0, 0),
+	GATE(CLK_SMMU_ISPCX, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4, 0, 0),
+	GATE(CLK_SPI0_ISP, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12, 0, 0),
+	GATE(CLK_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13, 0, 0),
+};
+
 static const struct samsung_clock_alias exynos4_aliases[] __initconst = {
 	ALIAS(CLK_MOUT_CORE, NULL, "moutcore"),
 	ALIAS(CLK_ARM_CLK, NULL, "armclk"),
@@ -1438,6 +1431,117 @@ static const struct exynos_cpuclk_cfg_data e4412_armclk_d[] __initconst = {
 	{  0 },
 };
 
+static int exynos4x12_isp_clk_suspend(struct device *dev)
+{
+	samsung_clk_save(reg_base, exynos4x12_save_isp,
+				ARRAY_SIZE(exynos4x12_clk_isp_save));
+	return 0;
+}
+
+static int exynos4x12_isp_clk_resume(struct device *dev)
+{
+	samsung_clk_restore(reg_base, exynos4x12_save_isp,
+				ARRAY_SIZE(exynos4x12_clk_isp_save));
+	return 0;
+}
+
+static int __init exynos4x12_isp_clk_probe(struct platform_device *pdev)
+{
+	struct samsung_clk_provider *ctx = exynos4412_ctx;
+
+	if (!ctx)
+		return -ENODEV;
+
+	dev_set_name(&pdev->dev, pdev->dev.of_node->name);
+
+	ctx->dev = &pdev->dev;
+	samsung_clk_register_div(ctx, exynos4x12_isp_div_clks,
+		ARRAY_SIZE(exynos4x12_isp_div_clks));
+
+	samsung_clk_register_gate(ctx, exynos4x12_isp_gate_clks,
+		ARRAY_SIZE(exynos4x12_isp_gate_clks));
+	ctx->dev = NULL;
+
+	exynos4x12_save_isp = samsung_clk_alloc_reg_dump(exynos4x12_clk_isp_save,
+					ARRAY_SIZE(exynos4x12_clk_isp_save));
+	if (!exynos4x12_save_isp)
+		dev_warn(&pdev->dev, "failed to allocate sleep save data, no sleep support!\n");
+	else {
+		/* save initial values */
+		exynos4x12_isp_clk_suspend(&pdev->dev);
+		pm_runtime_enable(&pdev->dev);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id exynos4x12_isp_clk_of_match[] = {
+	{ .compatible = "samsung,exynos4412-isp-clock", },
+	{ },
+};
+
+static const struct dev_pm_ops exynos4x12_isp_pm_ops = {
+	SET_RUNTIME_PM_OPS(exynos4x12_isp_clk_suspend,
+			   exynos4x12_isp_clk_resume, NULL)
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				     pm_runtime_force_resume)
+};
+
+static struct platform_driver exynos4x12_isp_clk_driver = {
+	.driver	= {
+		.name = "exynos-isp-clk",
+		.of_match_table = exynos4x12_isp_clk_of_match,
+		.suppress_bind_attrs = true,
+		.pm = &exynos4x12_isp_pm_ops,
+	},
+	.probe = exynos4x12_isp_clk_probe,
+};
+
+static int __init exynos4x12_isp_clk_init(void)
+{
+	struct platform_device *parent_pdev;
+	struct device *parent;
+	int ret;
+
+	if (!exynos4412_clk_node)
+		return 0;
+
+	parent_pdev = of_find_device_by_node(exynos4412_clk_node);
+	if (!parent_pdev)
+		return -ENODEV;
+
+	parent = &parent_pdev->dev;
+	ret = of_platform_populate(parent->of_node, NULL, NULL, parent);
+	if (ret)
+		return ret;
+
+	return platform_driver_register(&exynos4x12_isp_clk_driver);
+}
+arch_initcall_sync(exynos4x12_isp_clk_init);
+
+static void __init exynos4x12_isp_defer_clocks(struct samsung_clk_provider *ctx,
+					       struct device_node *parent)
+{
+	struct device_node *np = of_get_next_available_child(parent, NULL);
+	if (!np)
+		return;
+
+	if (of_device_is_compatible(np,
+		    exynos4x12_isp_clk_of_match[0].compatible)) {
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(exynos4x12_isp_div_clks); i++)
+			samsung_clk_add_lookup(ctx, ERR_PTR(-EPROBE_DEFER),
+					       exynos4x12_isp_div_clks[i].id);
+		for (i = 0; i < ARRAY_SIZE(exynos4x12_isp_gate_clks); i++)
+			samsung_clk_add_lookup(ctx, ERR_PTR(-EPROBE_DEFER),
+					       exynos4x12_isp_gate_clks[i].id);
+		exynos4412_ctx = ctx;
+		exynos4412_clk_node = parent;
+	}
+	of_node_put(np);
+}
+
 /* register exynos4 clocks */
 static void __init exynos4_clk_init(struct device_node *np,
 				    enum exynos4_soc soc)
@@ -1529,6 +1633,8 @@ static void __init exynos4_clk_init(struct device_node *np,
 		samsung_clk_register_fixed_factor(ctx,
 			exynos4x12_fixed_factor_clks,
 			ARRAY_SIZE(exynos4x12_fixed_factor_clks));
+		exynos4x12_isp_defer_clocks(ctx, np);
+
 		if (of_machine_is_compatible("samsung,exynos4412")) {
 			exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk",
 				mout_core_p4x12[0], mout_core_p4x12[1], 0x14200,
-- 
1.9.1

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

* [PATCH 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
  2016-09-01 13:45 ` Marek Szyprowski
  (?)
@ 2016-09-01 13:45   ` Marek Szyprowski
  -1 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel
  Cc: Marek Szyprowski, Stephen Boyd, Michael Turquette, Ulf Hansson,
	Sylwester Nawrocki, Chanwoo Choi, Inki Dae, Krzysztof Kozlowski,
	Bartlomiej Zolnierkiewicz

Exynos4412 clock controller contains some additional clocks for FIMC-ISP
(Camera ISP) subsystem. Registers for those clocks are partially located
in the SOC area, which belongs to ISP power domain.

This patch extends clock controller node with ISP clock sub-node and link
(phandle) to ISP power domain.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 arch/arm/boot/dts/exynos4x12.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
index 3394bdcf10ae..4daea67546b9 100644
--- a/arch/arm/boot/dts/exynos4x12.dtsi
+++ b/arch/arm/boot/dts/exynos4x12.dtsi
@@ -74,6 +74,11 @@
 		compatible = "samsung,exynos4412-clock";
 		reg = <0x10030000 0x20000>;
 		#clock-cells = <1>;
+
+		isp-clock-controller {
+			compatible = "samsung,exynos4412-isp-clock";
+			power-domains = <&pd_isp>;
+		};
 	};
 
 	mct@10050000 {
-- 
1.9.1

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

* [PATCH 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
@ 2016-09-01 13:45   ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel
  Cc: Ulf Hansson, Bartlomiej Zolnierkiewicz, Michael Turquette,
	Stephen Boyd, Krzysztof Kozlowski, Inki Dae, Chanwoo Choi,
	Sylwester Nawrocki, Marek Szyprowski

Exynos4412 clock controller contains some additional clocks for FIMC-ISP
(Camera ISP) subsystem. Registers for those clocks are partially located
in the SOC area, which belongs to ISP power domain.

This patch extends clock controller node with ISP clock sub-node and link
(phandle) to ISP power domain.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 arch/arm/boot/dts/exynos4x12.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
index 3394bdcf10ae..4daea67546b9 100644
--- a/arch/arm/boot/dts/exynos4x12.dtsi
+++ b/arch/arm/boot/dts/exynos4x12.dtsi
@@ -74,6 +74,11 @@
 		compatible = "samsung,exynos4412-clock";
 		reg = <0x10030000 0x20000>;
 		#clock-cells = <1>;
+
+		isp-clock-controller {
+			compatible = "samsung,exynos4412-isp-clock";
+			power-domains = <&pd_isp>;
+		};
 	};
 
 	mct@10050000 {
-- 
1.9.1

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

* [PATCH 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
@ 2016-09-01 13:45   ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-arm-kernel

Exynos4412 clock controller contains some additional clocks for FIMC-ISP
(Camera ISP) subsystem. Registers for those clocks are partially located
in the SOC area, which belongs to ISP power domain.

This patch extends clock controller node with ISP clock sub-node and link
(phandle) to ISP power domain.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 arch/arm/boot/dts/exynos4x12.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
index 3394bdcf10ae..4daea67546b9 100644
--- a/arch/arm/boot/dts/exynos4x12.dtsi
+++ b/arch/arm/boot/dts/exynos4x12.dtsi
@@ -74,6 +74,11 @@
 		compatible = "samsung,exynos4412-clock";
 		reg = <0x10030000 0x20000>;
 		#clock-cells = <1>;
+
+		isp-clock-controller {
+			compatible = "samsung,exynos4412-isp-clock";
+			power-domains = <&pd_isp>;
+		};
 	};
 
 	mct at 10050000 {
-- 
1.9.1

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

* [PATCH 5/5] clocks: exynos5433: add runtime pm support
  2016-09-01 13:45 ` Marek Szyprowski
@ 2016-09-01 13:45   ` Marek Szyprowski
  -1 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel
  Cc: Marek Szyprowski, Stephen Boyd, Michael Turquette, Ulf Hansson,
	Sylwester Nawrocki, Chanwoo Choi, Inki Dae, Krzysztof Kozlowski,
	Bartlomiej Zolnierkiewicz

Add runtime pm support for all clock controller units (CMU), which belongs
to power domains and require special handling during on/off operations.
Typically special values has to be written to MUX registers to change
internal clocks parents to OSC clock before turning power off. During such
operation all clocks, which enters CMU has to be enabled to let MUX to
stabilize. Also for each CMU there is one special parent clock, which has
to be enabled all the time when any access to CMU registers is done.

This patch solves most of the mysterious external abort and freeze issues
caused by a lack of proper parent CMU clock enabled or incorrect turn off
procedure.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/clk/samsung/clk-exynos5433.c | 462 +++++++++++++++++++++++++++--------
 1 file changed, 363 insertions(+), 99 deletions(-)

diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c
index ea1608682d7f..9fb896b56ddf 100644
--- a/drivers/clk/samsung/clk-exynos5433.c
+++ b/drivers/clk/samsung/clk-exynos5433.c
@@ -9,9 +9,14 @@
  * Common Clock Framework support for Exynos5443 SoC.
  */
 
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
 
 #include <dt-bindings/clock/exynos5433.h>
 
@@ -19,6 +24,37 @@
 #include "clk-cpu.h"
 #include "clk-pll.h"
 
+struct exynos5433_cmu_info {
+	/* total number of clocks with IDs assigned*/
+	unsigned int nr_clk_ids;
+	/* list of pll clocks and respective count */
+	const struct samsung_pll_clock *pll_clks;
+	unsigned int nr_pll_clks;
+	/* list of mux clocks and respective count */
+	const struct samsung_mux_clock *mux_clks;
+	unsigned int nr_mux_clks;
+	/* list of div clocks and respective count */
+	const struct samsung_div_clock *div_clks;
+	unsigned int nr_div_clks;
+	/* list of gate clocks and respective count */
+	const struct samsung_gate_clock *gate_clks;
+	unsigned int nr_gate_clks;
+	/* list of fixed clocks and respective count */
+	const struct samsung_fixed_rate_clock *fixed_clks;
+	unsigned int nr_fixed_clks;
+	/* list of fixed factor clocks and respective count */
+	const struct samsung_fixed_factor_clock *fixed_factor_clks;
+	unsigned int nr_fixed_factor_clks;
+	/* list and number of clocks registers */
+	const unsigned long *clk_regs;
+	unsigned int nr_clk_regs;
+	/* list and number of clocks registers to set before suspend */
+	const struct samsung_clk_reg_dump *suspend_regs;
+	unsigned int nr_suspend_regs;
+	/* name of the parent clock needed for CMU register access */
+	const char *clk_name;
+};
+
 /*
  * Register offset definitions for CMU_TOP
  */
@@ -2333,6 +2369,10 @@ static const unsigned long g2d_clk_regs[] __initconst = {
 	DIV_ENABLE_IP_G2D_SECURE_SMMU_G2D,
 };
 
+static const struct samsung_clk_reg_dump g2d_suspend_regs[] = {
+	{MUX_SEL_G2D0, 0},
+};
+
 /* list of all parent clock list */
 PNAME(mout_aclk_g2d_266_user_p)		= { "oscclk", "aclk_g2d_266", };
 PNAME(mout_aclk_g2d_400_user_p)		= { "oscclk", "aclk_g2d_400", };
@@ -2408,26 +2448,21 @@ static const struct samsung_gate_clock g2d_gate_clks[] __initconst = {
 		DIV_ENABLE_PCLK_G2D_SECURE_SMMU_G2D, 0, 0, 0),
 };
 
-static const struct samsung_cmu_info g2d_cmu_info __initconst = {
+static const struct exynos5433_cmu_info g2d_cmu_info __initconst = {
+	.nr_clk_ids		= G2D_NR_CLK,
 	.mux_clks		= g2d_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(g2d_mux_clks),
 	.div_clks		= g2d_div_clks,
 	.nr_div_clks		= ARRAY_SIZE(g2d_div_clks),
 	.gate_clks		= g2d_gate_clks,
 	.nr_gate_clks		= ARRAY_SIZE(g2d_gate_clks),
-	.nr_clk_ids		= G2D_NR_CLK,
 	.clk_regs		= g2d_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(g2d_clk_regs),
+	.suspend_regs		= g2d_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(g2d_suspend_regs),
+	.clk_name		= "aclk_g2d_400",
 };
 
-static void __init exynos5433_cmu_g2d_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &g2d_cmu_info);
-}
-
-CLK_OF_DECLARE(exynos5433_cmu_g2d, "samsung,exynos5433-cmu-g2d",
-		exynos5433_cmu_g2d_init);
-
 /*
  * Register offset definitions for CMU_DISP
  */
@@ -2492,6 +2527,14 @@ static const unsigned long disp_clk_regs[] __initconst = {
 	CLKOUT_CMU_DISP_DIV_STAT,
 };
 
+static const struct samsung_clk_reg_dump disp_suspend_regs[] = {
+	{MUX_SEL_DISP0, 0},
+	{MUX_SEL_DISP1, 0},
+	{MUX_SEL_DISP2, 0},
+	{MUX_SEL_DISP3, 0},
+	{MUX_SEL_DISP4, 0},
+};
+
 /* list of all parent clock list */
 PNAME(mout_disp_pll_p)			= { "oscclk", "fout_disp_pll", };
 PNAME(mout_sclk_dsim1_user_p)		= { "oscclk", "sclk_dsim1_disp", };
@@ -2821,7 +2864,8 @@ static const struct samsung_gate_clock disp_gate_clks[] __initconst = {
 			"div_sclk_decon_eclk_disp", ENABLE_SCLK_DISP, 2, 0, 0),
 };
 
-static const struct samsung_cmu_info disp_cmu_info __initconst = {
+static const struct exynos5433_cmu_info disp_cmu_info __initconst = {
+	.nr_clk_ids		= DISP_NR_CLK,
 	.pll_clks		= disp_pll_clks,
 	.nr_pll_clks		= ARRAY_SIZE(disp_pll_clks),
 	.mux_clks		= disp_mux_clks,
@@ -2834,19 +2878,13 @@ static const struct samsung_cmu_info disp_cmu_info __initconst = {
 	.nr_fixed_clks		= ARRAY_SIZE(disp_fixed_clks),
 	.fixed_factor_clks	= disp_fixed_factor_clks,
 	.nr_fixed_factor_clks	= ARRAY_SIZE(disp_fixed_factor_clks),
-	.nr_clk_ids		= DISP_NR_CLK,
 	.clk_regs		= disp_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(disp_clk_regs),
+	.suspend_regs		= disp_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(disp_suspend_regs),
+	.clk_name		= "aclk_disp_333",
 };
 
-static void __init exynos5433_cmu_disp_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &disp_cmu_info);
-}
-
-CLK_OF_DECLARE(exynos5433_cmu_disp, "samsung,exynos5433-cmu-disp",
-		exynos5433_cmu_disp_init);
-
 /*
  * Register offset definitions for CMU_AUD
  */
@@ -2881,6 +2919,11 @@ static const unsigned long aud_clk_regs[] __initconst = {
 	ENABLE_IP_AUD1,
 };
 
+static const struct samsung_clk_reg_dump aud_suspend_regs[] = {
+	{MUX_SEL_AUD0, 0},
+	{MUX_SEL_AUD1, 0},
+};
+
 /* list of all parent clock list */
 PNAME(mout_aud_pll_user_aud_p)	= { "oscclk", "fout_aud_pll", };
 PNAME(mout_sclk_aud_pcm_p)	= { "mout_aud_pll_user", "ioclk_audiocdclk0",};
@@ -2995,7 +3038,8 @@ static const struct samsung_gate_clock aud_gate_clks[] __initconst = {
 			ENABLE_SCLK_AUD1, 0, CLK_IGNORE_UNUSED, 0),
 };
 
-static const struct samsung_cmu_info aud_cmu_info __initconst = {
+static const struct exynos5433_cmu_info aud_cmu_info __initconst = {
+	.nr_clk_ids		= AUD_NR_CLK,
 	.mux_clks		= aud_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(aud_mux_clks),
 	.div_clks		= aud_div_clks,
@@ -3004,19 +3048,12 @@ static const struct samsung_cmu_info aud_cmu_info __initconst = {
 	.nr_gate_clks		= ARRAY_SIZE(aud_gate_clks),
 	.fixed_clks		= aud_fixed_clks,
 	.nr_fixed_clks		= ARRAY_SIZE(aud_fixed_clks),
-	.nr_clk_ids		= AUD_NR_CLK,
 	.clk_regs		= aud_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(aud_clk_regs),
+	.suspend_regs		= aud_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(aud_suspend_regs),
 };
 
-static void __init exynos5433_cmu_aud_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &aud_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_aud, "samsung,exynos5433-cmu-aud",
-		exynos5433_cmu_aud_init);
-
-
 /*
  * Register offset definitions for CMU_BUS{0|1|2}
  */
@@ -3218,6 +3255,10 @@ static const unsigned long g3d_clk_regs[] __initconst = {
 	CLK_STOPCTRL,
 };
 
+static const struct samsung_clk_reg_dump g3d_suspend_regs[] = {
+	{MUX_SEL_G3D, 0},
+};
+
 /* list of all parent clock list */
 PNAME(mout_aclk_g3d_400_p)	= { "mout_g3d_pll", "aclk_g3d_400", };
 PNAME(mout_g3d_pll_p)		= { "oscclk", "fout_g3d_pll", };
@@ -3279,7 +3320,8 @@ static const struct samsung_gate_clock g3d_gate_clks[] __initconst = {
 			ENABLE_SCLK_G3D, 0, 0, 0),
 };
 
-static const struct samsung_cmu_info g3d_cmu_info __initconst = {
+static const struct exynos5433_cmu_info g3d_cmu_info __initconst = {
+	.nr_clk_ids		= G3D_NR_CLK,
 	.pll_clks		= g3d_pll_clks,
 	.nr_pll_clks		= ARRAY_SIZE(g3d_pll_clks),
 	.mux_clks		= g3d_mux_clks,
@@ -3288,18 +3330,13 @@ static const struct samsung_cmu_info g3d_cmu_info __initconst = {
 	.nr_div_clks		= ARRAY_SIZE(g3d_div_clks),
 	.gate_clks		= g3d_gate_clks,
 	.nr_gate_clks		= ARRAY_SIZE(g3d_gate_clks),
-	.nr_clk_ids		= G3D_NR_CLK,
 	.clk_regs		= g3d_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(g3d_clk_regs),
+	.suspend_regs		= g3d_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(g3d_suspend_regs),
+	.clk_name		= "aclk_g3d_400",
 };
 
-static void __init exynos5433_cmu_g3d_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &g3d_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_g3d, "samsung,exynos5433-cmu-g3d",
-		exynos5433_cmu_g3d_init);
-
 /*
  * Register offset definitions for CMU_GSCL
  */
@@ -3338,6 +3375,12 @@ static const unsigned long gscl_clk_regs[] __initconst = {
 	ENABLE_IP_GSCL_SECURE_SMMU_GSCL2,
 };
 
+static const struct samsung_clk_reg_dump gscl_suspend_regs[] = {
+	{MUX_SEL_GSCL, 0},
+	{ENABLE_ACLK_GSCL, 0xfff},
+	{ENABLE_PCLK_GSCL, 0xff},
+};
+
 /* list of all parent clock list */
 PNAME(aclk_gscl_111_user_p)	= { "oscclk", "aclk_gscl_111", };
 PNAME(aclk_gscl_333_user_p)	= { "oscclk", "aclk_gscl_333", };
@@ -3424,23 +3467,19 @@ static const struct samsung_gate_clock gscl_gate_clks[] __initconst = {
 		ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL2, 0, 0, 0),
 };
 
-static const struct samsung_cmu_info gscl_cmu_info __initconst = {
+static const struct exynos5433_cmu_info gscl_cmu_info __initconst = {
+	.nr_clk_ids		= GSCL_NR_CLK,
 	.mux_clks		= gscl_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(gscl_mux_clks),
 	.gate_clks		= gscl_gate_clks,
 	.nr_gate_clks		= ARRAY_SIZE(gscl_gate_clks),
-	.nr_clk_ids		= GSCL_NR_CLK,
 	.clk_regs		= gscl_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(gscl_clk_regs),
+	.suspend_regs		= gscl_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(gscl_suspend_regs),
+	.clk_name		= "aclk_gscl_111",
 };
 
-static void __init exynos5433_cmu_gscl_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &gscl_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_gscl, "samsung,exynos5433-cmu-gscl",
-		exynos5433_cmu_gscl_init);
-
 /*
  * Register offset definitions for CMU_APOLLO
  */
@@ -3966,6 +4005,11 @@ static const unsigned long mscl_clk_regs[] __initconst = {
 	ENABLE_IP_MSCL_SECURE_SMMU_JPEG,
 };
 
+static const struct samsung_clk_reg_dump mscl_suspend_regs[] = {
+	{MUX_SEL_MSCL0, 0},
+	{MUX_SEL_MSCL1, 0},
+};
+
 /* list of all parent clock list */
 PNAME(mout_sclk_jpeg_user_p)		= { "oscclk", "sclk_jpeg_mscl", };
 PNAME(mout_aclk_mscl_400_user_p)	= { "oscclk", "aclk_mscl_400", };
@@ -4068,25 +4112,21 @@ static const struct samsung_gate_clock mscl_gate_clks[] __initconst = {
 			CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0),
 };
 
-static const struct samsung_cmu_info mscl_cmu_info __initconst = {
+static const struct exynos5433_cmu_info mscl_cmu_info __initconst = {
+	.nr_clk_ids		= MSCL_NR_CLK,
 	.mux_clks		= mscl_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(mscl_mux_clks),
 	.div_clks		= mscl_div_clks,
 	.nr_div_clks		= ARRAY_SIZE(mscl_div_clks),
 	.gate_clks		= mscl_gate_clks,
 	.nr_gate_clks		= ARRAY_SIZE(mscl_gate_clks),
-	.nr_clk_ids		= MSCL_NR_CLK,
 	.clk_regs		= mscl_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(mscl_clk_regs),
+	.suspend_regs		= mscl_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(mscl_suspend_regs),
+	.clk_name		= "aclk_mscl_400",
 };
 
-static void __init exynos5433_cmu_mscl_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &mscl_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_mscl, "samsung,exynos5433-cmu-mscl",
-		exynos5433_cmu_mscl_init);
-
 /*
  * Register offset definitions for CMU_MFC
  */
@@ -4116,6 +4156,10 @@ static const unsigned long mfc_clk_regs[] __initconst = {
 	ENABLE_IP_MFC_SECURE_SMMU_MFC,
 };
 
+static const struct samsung_clk_reg_dump mfc_suspend_regs[] = {
+	{MUX_SEL_MFC, 0},
+};
+
 PNAME(mout_aclk_mfc_400_user_p)		= { "oscclk", "aclk_mfc_400", };
 
 static const struct samsung_mux_clock mfc_mux_clks[] __initconst = {
@@ -4176,25 +4220,21 @@ static const struct samsung_gate_clock mfc_gate_clks[] __initconst = {
 			0, CLK_IGNORE_UNUSED, 0),
 };
 
-static const struct samsung_cmu_info mfc_cmu_info __initconst = {
+static const struct exynos5433_cmu_info mfc_cmu_info __initconst = {
+	.nr_clk_ids		= MFC_NR_CLK,
 	.mux_clks		= mfc_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(mfc_mux_clks),
 	.div_clks		= mfc_div_clks,
 	.nr_div_clks		= ARRAY_SIZE(mfc_div_clks),
 	.gate_clks		= mfc_gate_clks,
 	.nr_gate_clks		= ARRAY_SIZE(mfc_gate_clks),
-	.nr_clk_ids		= MFC_NR_CLK,
 	.clk_regs		= mfc_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(mfc_clk_regs),
+	.suspend_regs		= mfc_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(mfc_suspend_regs),
+	.clk_name		= "aclk_mfc_400",
 };
 
-static void __init exynos5433_cmu_mfc_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &mfc_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_mfc, "samsung,exynos5433-cmu-mfc",
-		exynos5433_cmu_mfc_init);
-
 /*
  * Register offset definitions for CMU_HEVC
  */
@@ -4224,6 +4264,10 @@ static const unsigned long hevc_clk_regs[] __initconst = {
 	ENABLE_IP_HEVC_SECURE_SMMU_HEVC,
 };
 
+static const struct samsung_clk_reg_dump hevc_suspend_regs[] = {
+	{MUX_SEL_HEVC, 0},
+};
+
 PNAME(mout_aclk_hevc_400_user_p)	= { "oscclk", "aclk_hevc_400", };
 
 static const struct samsung_mux_clock hevc_mux_clks[] __initconst = {
@@ -4286,25 +4330,21 @@ static const struct samsung_gate_clock hevc_gate_clks[] __initconst = {
 			0, CLK_IGNORE_UNUSED, 0),
 };
 
-static const struct samsung_cmu_info hevc_cmu_info __initconst = {
+static const struct exynos5433_cmu_info hevc_cmu_info __initconst = {
+	.nr_clk_ids		= HEVC_NR_CLK,
 	.mux_clks		= hevc_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(hevc_mux_clks),
 	.div_clks		= hevc_div_clks,
 	.nr_div_clks		= ARRAY_SIZE(hevc_div_clks),
 	.gate_clks		= hevc_gate_clks,
 	.nr_gate_clks		= ARRAY_SIZE(hevc_gate_clks),
-	.nr_clk_ids		= HEVC_NR_CLK,
 	.clk_regs		= hevc_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(hevc_clk_regs),
+	.suspend_regs		= hevc_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(hevc_suspend_regs),
+	.clk_name		= "aclk_hevc_400",
 };
 
-static void __init exynos5433_cmu_hevc_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &hevc_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_hevc, "samsung,exynos5433-cmu-hevc",
-		exynos5433_cmu_hevc_init);
-
 /*
  * Register offset definitions for CMU_ISP
  */
@@ -4338,6 +4378,10 @@ static const unsigned long isp_clk_regs[] __initconst = {
 	ENABLE_IP_ISP3,
 };
 
+static const struct samsung_clk_reg_dump isp_suspend_regs[] = {
+	{MUX_SEL_ISP, 0},
+};
+
 PNAME(mout_aclk_isp_dis_400_user_p)	= { "oscclk", "aclk_isp_dis_400", };
 PNAME(mout_aclk_isp_400_user_p)		= { "oscclk", "aclk_isp_400", };
 
@@ -4539,25 +4583,21 @@ static const struct samsung_gate_clock isp_gate_clks[] __initconst = {
 			0, CLK_IGNORE_UNUSED, 0),
 };
 
-static const struct samsung_cmu_info isp_cmu_info __initconst = {
+static const struct exynos5433_cmu_info isp_cmu_info __initconst = {
+	.nr_clk_ids		= ISP_NR_CLK,
 	.mux_clks		= isp_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(isp_mux_clks),
 	.div_clks		= isp_div_clks,
 	.nr_div_clks		= ARRAY_SIZE(isp_div_clks),
 	.gate_clks		= isp_gate_clks,
 	.nr_gate_clks		= ARRAY_SIZE(isp_gate_clks),
-	.nr_clk_ids		= ISP_NR_CLK,
 	.clk_regs		= isp_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(isp_clk_regs),
+	.suspend_regs		= isp_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(isp_suspend_regs),
+	.clk_name		= "aclk_isp_400",
 };
 
-static void __init exynos5433_cmu_isp_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &isp_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_isp, "samsung,exynos5433-cmu-isp",
-		exynos5433_cmu_isp_init);
-
 /*
  * Register offset definitions for CMU_CAM0
  */
@@ -4621,6 +4661,15 @@ static const unsigned long cam0_clk_regs[] __initconst = {
 	ENABLE_IP_CAM02,
 	ENABLE_IP_CAM03,
 };
+
+static const struct samsung_clk_reg_dump cam0_suspend_regs[] = {
+	{MUX_SEL_CAM00, 0},
+	{MUX_SEL_CAM01, 0},
+	{MUX_SEL_CAM02, 0},
+	{MUX_SEL_CAM03, 0},
+	{MUX_SEL_CAM04, 0},
+};
+
 PNAME(mout_aclk_cam0_333_user_p)	= { "oscclk", "aclk_cam0_333", };
 PNAME(mout_aclk_cam0_400_user_p)	= { "oscclk", "aclk_cam0_400", };
 PNAME(mout_aclk_cam0_552_user_p)	= { "oscclk", "aclk_cam0_552", };
@@ -5014,7 +5063,8 @@ static const struct samsung_gate_clock cam0_gate_clks[] __initconst = {
 			ENABLE_SCLK_CAM0, 0, 0, 0),
 };
 
-static const struct samsung_cmu_info cam0_cmu_info __initconst = {
+static const struct exynos5433_cmu_info cam0_cmu_info __initconst = {
+	.nr_clk_ids		= CAM0_NR_CLK,
 	.mux_clks		= cam0_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(cam0_mux_clks),
 	.div_clks		= cam0_div_clks,
@@ -5023,18 +5073,13 @@ static const struct samsung_cmu_info cam0_cmu_info __initconst = {
 	.nr_gate_clks		= ARRAY_SIZE(cam0_gate_clks),
 	.fixed_clks		= cam0_fixed_clks,
 	.nr_fixed_clks		= ARRAY_SIZE(cam0_fixed_clks),
-	.nr_clk_ids		= CAM0_NR_CLK,
 	.clk_regs		= cam0_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(cam0_clk_regs),
+	.suspend_regs		= cam0_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(cam0_suspend_regs),
+	.clk_name		= "aclk_cam0_400",
 };
 
-static void __init exynos5433_cmu_cam0_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &cam0_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_cam0, "samsung,exynos5433-cmu-cam0",
-		exynos5433_cmu_cam0_init);
-
 /*
  * Register offset definitions for CMU_CAM1
  */
@@ -5081,6 +5126,12 @@ static const unsigned long cam1_clk_regs[] __initconst = {
 	ENABLE_IP_CAM12,
 };
 
+static const struct samsung_clk_reg_dump cam1_suspend_regs[] = {
+	{MUX_SEL_CAM10, 0},
+	{MUX_SEL_CAM11, 0},
+	{MUX_SEL_CAM12, 0},
+};
+
 PNAME(mout_sclk_isp_uart_user_p)	= { "oscclk", "sclk_isp_uart_cam1", };
 PNAME(mout_sclk_isp_spi1_user_p)	= { "oscclk", "sclk_isp_spi1_cam1", };
 PNAME(mout_sclk_isp_spi0_user_p)	= { "oscclk", "sclk_isp_spi0_cam1", };
@@ -5387,7 +5438,8 @@ static const struct samsung_gate_clock cam1_gate_clks[] __initconst = {
 			ENABLE_SCLK_CAM1, 0, 0, 0),
 };
 
-static const struct samsung_cmu_info cam1_cmu_info __initconst = {
+static const struct exynos5433_cmu_info cam1_cmu_info __initconst = {
+	.nr_clk_ids		= CAM1_NR_CLK,
 	.mux_clks		= cam1_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(cam1_mux_clks),
 	.div_clks		= cam1_div_clks,
@@ -5396,14 +5448,226 @@ static const struct samsung_cmu_info cam1_cmu_info __initconst = {
 	.nr_gate_clks		= ARRAY_SIZE(cam1_gate_clks),
 	.fixed_clks		= cam1_fixed_clks,
 	.nr_fixed_clks		= ARRAY_SIZE(cam1_fixed_clks),
-	.nr_clk_ids		= CAM1_NR_CLK,
 	.clk_regs		= cam1_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(cam1_clk_regs),
+	.suspend_regs		= cam1_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(cam1_suspend_regs),
+	.clk_name		= "aclk_cam1_400",
+};
+
+
+struct exynos5433_cmu_data {
+	struct samsung_clk_provider ctx;
+
+	struct samsung_clk_reg_dump *clk_save;
+	unsigned int nr_clk_save;
+	const struct samsung_clk_reg_dump *clk_suspend;
+	unsigned int nr_clk_suspend;
+
+	struct clk *clk;
+	struct clk **pclks;
+	int nr_pclks;
+};
+
+static int exynos5433_cmu_suspend(struct device *dev)
+{
+	struct exynos5433_cmu_data *data = dev_get_drvdata(dev);
+	int i;
+
+	samsung_clk_save(data->ctx.reg_base, data->clk_save,
+			 data->nr_clk_save);
+
+	for (i = 0; i < data->nr_pclks; i++)
+		clk_enable(data->pclks[i]);
+
+	samsung_clk_restore(data->ctx.reg_base, data->clk_suspend,
+			    data->nr_clk_suspend);
+
+	for (i = 0; i < data->nr_pclks; i++)
+		clk_disable(data->pclks[i]);
+
+	clk_disable(data->clk);
+
+	return 0;
+}
+
+static int exynos5433_cmu_resume(struct device *dev)
+{
+	struct exynos5433_cmu_data *data = dev_get_drvdata(dev);
+	int i;
+
+	clk_enable(data->clk);
+
+	for (i = 0; i < data->nr_pclks; i++)
+		clk_enable(data->pclks[i]);
+
+	samsung_clk_restore(data->ctx.reg_base, data->clk_save,
+			    data->nr_clk_save);
+
+	for (i = 0; i < data->nr_pclks; i++)
+		clk_disable(data->pclks[i]);
+
+	return 0;
+}
+
+static int __init exynos5433_cmu_probe(struct platform_device *pdev)
+{
+	const struct exynos5433_cmu_info *info;
+	struct exynos5433_cmu_data *data;
+	struct samsung_clk_provider *ctx;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	void __iomem *reg_base;
+	struct clk **clk_table;
+	int i;
+
+	info = of_device_get_match_data(dev);
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	ctx = &data->ctx;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	reg_base = devm_ioremap_resource(dev, res);
+	if (!reg_base) {
+		dev_err(dev, "failed to map registers\n");
+		return -ENOMEM;
+	}
+
+	clk_table = devm_kcalloc(dev, info->nr_clk_ids, sizeof(struct clk *),
+				 GFP_KERNEL);
+	if (!clk_table) {
+		dev_err(dev, "could not allocate clock lookup table\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < info->nr_clk_ids; ++i)
+		clk_table[i] = ERR_PTR(-ENOENT);
+
+	ctx->clk_data.clks = clk_table;
+	ctx->clk_data.clk_num = info->nr_clk_ids;
+	ctx->reg_base = reg_base;
+	ctx->dev = dev;
+	spin_lock_init(&ctx->lock);
+
+	data->clk_save = samsung_clk_alloc_reg_dump(info->clk_regs,
+						    info->nr_clk_regs);
+	data->nr_clk_save = info->nr_clk_regs;
+	data->clk_suspend = info->suspend_regs;
+	data->nr_clk_suspend = info->nr_suspend_regs;
+	data->nr_pclks = of_count_phandle_with_args(dev->of_node, "clocks",
+						    "#clock-cells");
+	if (data->nr_pclks > 0) {
+		data->pclks = devm_kcalloc(dev, sizeof(struct clk *),
+					   data->nr_pclks, GFP_KERNEL);
+
+		for (i = 0; i < data->nr_pclks; i++) {
+			struct clk *clk = of_clk_get(dev->of_node, i);
+
+			if (IS_ERR(clk))
+				return PTR_ERR(clk);
+			data->pclks[i] = clk;
+		}
+	}
+
+	/*
+	 * Prepare all parent clocks here to avoid potential deadlock caused
+	 * by global clock "prepare lock" grabbed by runtime pm callbacks
+	 * from pm workers.
+	 */
+	for (i = 0; i < data->nr_pclks; i++)
+		clk_prepare(data->pclks[i]);
+
+	if (info->pll_clks)
+		samsung_clk_register_pll(ctx, info->pll_clks, info->nr_pll_clks,
+					 reg_base);
+	if (info->mux_clks)
+		samsung_clk_register_mux(ctx, info->mux_clks,
+					 info->nr_mux_clks);
+	if (info->div_clks)
+		samsung_clk_register_div(ctx, info->div_clks,
+					 info->nr_div_clks);
+	if (info->gate_clks)
+		samsung_clk_register_gate(ctx, info->gate_clks,
+					  info->nr_gate_clks);
+	if (info->fixed_clks)
+		samsung_clk_register_fixed_rate(ctx, info->fixed_clks,
+						info->nr_fixed_clks);
+	if (info->fixed_factor_clks)
+		samsung_clk_register_fixed_factor(ctx, info->fixed_factor_clks,
+						  info->nr_fixed_factor_clks);
+
+	if (info->clk_name)
+		data->clk = clk_get(dev, info->clk_name);
+	clk_prepare_enable(data->clk);
+
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+
+	platform_set_drvdata(pdev, data);
+	samsung_clk_of_add_provider(dev->of_node, ctx);
+
+	return 0;
+}
+
+static const struct of_device_id exynos5433_cmu_of_match[] = {
+	{
+		.compatible = "samsung,exynos5433-cmu-aud",
+		.data = &aud_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-cam0",
+		.data = &cam0_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-cam1",
+		.data = &cam1_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-disp",
+		.data = &disp_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-g2d",
+		.data = &g2d_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-g3d",
+		.data = &g3d_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-gscl",
+		.data = &gscl_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-mfc",
+		.data = &mfc_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-hevc",
+		.data = &hevc_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-isp",
+		.data = &isp_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-mscl",
+		.data = &mscl_cmu_info,
+	}, {
+	},
+};
+
+static const struct dev_pm_ops exynos5433_cmu_pm_ops = {
+	SET_RUNTIME_PM_OPS(exynos5433_cmu_suspend, exynos5433_cmu_resume,
+			   NULL)
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				     pm_runtime_force_resume)
+};
+
+static struct platform_driver exynos5433_cmu_driver = {
+	.driver	= {
+		.name = "exynos5433-cmu",
+		.of_match_table = exynos5433_cmu_of_match,
+		.suppress_bind_attrs = true,
+		.pm = &exynos5433_cmu_pm_ops,
+	},
+	.probe = exynos5433_cmu_probe,
 };
 
-static void __init exynos5433_cmu_cam1_init(struct device_node *np)
+static int __init exynos5433_cmu_init(void)
 {
-	samsung_cmu_register_one(np, &cam1_cmu_info);
+	return platform_driver_register(&exynos5433_cmu_driver);
 }
-CLK_OF_DECLARE(exynos5433_cmu_cam1, "samsung,exynos5433-cmu-cam1",
-		exynos5433_cmu_cam1_init);
+core_initcall(exynos5433_cmu_init);
-- 
1.9.1

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

* [PATCH 5/5] clocks: exynos5433: add runtime pm support
@ 2016-09-01 13:45   ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-01 13:45 UTC (permalink / raw)
  To: linux-arm-kernel

Add runtime pm support for all clock controller units (CMU), which belongs
to power domains and require special handling during on/off operations.
Typically special values has to be written to MUX registers to change
internal clocks parents to OSC clock before turning power off. During such
operation all clocks, which enters CMU has to be enabled to let MUX to
stabilize. Also for each CMU there is one special parent clock, which has
to be enabled all the time when any access to CMU registers is done.

This patch solves most of the mysterious external abort and freeze issues
caused by a lack of proper parent CMU clock enabled or incorrect turn off
procedure.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/clk/samsung/clk-exynos5433.c | 462 +++++++++++++++++++++++++++--------
 1 file changed, 363 insertions(+), 99 deletions(-)

diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c
index ea1608682d7f..9fb896b56ddf 100644
--- a/drivers/clk/samsung/clk-exynos5433.c
+++ b/drivers/clk/samsung/clk-exynos5433.c
@@ -9,9 +9,14 @@
  * Common Clock Framework support for Exynos5443 SoC.
  */
 
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
 
 #include <dt-bindings/clock/exynos5433.h>
 
@@ -19,6 +24,37 @@
 #include "clk-cpu.h"
 #include "clk-pll.h"
 
+struct exynos5433_cmu_info {
+	/* total number of clocks with IDs assigned*/
+	unsigned int nr_clk_ids;
+	/* list of pll clocks and respective count */
+	const struct samsung_pll_clock *pll_clks;
+	unsigned int nr_pll_clks;
+	/* list of mux clocks and respective count */
+	const struct samsung_mux_clock *mux_clks;
+	unsigned int nr_mux_clks;
+	/* list of div clocks and respective count */
+	const struct samsung_div_clock *div_clks;
+	unsigned int nr_div_clks;
+	/* list of gate clocks and respective count */
+	const struct samsung_gate_clock *gate_clks;
+	unsigned int nr_gate_clks;
+	/* list of fixed clocks and respective count */
+	const struct samsung_fixed_rate_clock *fixed_clks;
+	unsigned int nr_fixed_clks;
+	/* list of fixed factor clocks and respective count */
+	const struct samsung_fixed_factor_clock *fixed_factor_clks;
+	unsigned int nr_fixed_factor_clks;
+	/* list and number of clocks registers */
+	const unsigned long *clk_regs;
+	unsigned int nr_clk_regs;
+	/* list and number of clocks registers to set before suspend */
+	const struct samsung_clk_reg_dump *suspend_regs;
+	unsigned int nr_suspend_regs;
+	/* name of the parent clock needed for CMU register access */
+	const char *clk_name;
+};
+
 /*
  * Register offset definitions for CMU_TOP
  */
@@ -2333,6 +2369,10 @@ static const unsigned long g2d_clk_regs[] __initconst = {
 	DIV_ENABLE_IP_G2D_SECURE_SMMU_G2D,
 };
 
+static const struct samsung_clk_reg_dump g2d_suspend_regs[] = {
+	{MUX_SEL_G2D0, 0},
+};
+
 /* list of all parent clock list */
 PNAME(mout_aclk_g2d_266_user_p)		= { "oscclk", "aclk_g2d_266", };
 PNAME(mout_aclk_g2d_400_user_p)		= { "oscclk", "aclk_g2d_400", };
@@ -2408,26 +2448,21 @@ static const struct samsung_gate_clock g2d_gate_clks[] __initconst = {
 		DIV_ENABLE_PCLK_G2D_SECURE_SMMU_G2D, 0, 0, 0),
 };
 
-static const struct samsung_cmu_info g2d_cmu_info __initconst = {
+static const struct exynos5433_cmu_info g2d_cmu_info __initconst = {
+	.nr_clk_ids		= G2D_NR_CLK,
 	.mux_clks		= g2d_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(g2d_mux_clks),
 	.div_clks		= g2d_div_clks,
 	.nr_div_clks		= ARRAY_SIZE(g2d_div_clks),
 	.gate_clks		= g2d_gate_clks,
 	.nr_gate_clks		= ARRAY_SIZE(g2d_gate_clks),
-	.nr_clk_ids		= G2D_NR_CLK,
 	.clk_regs		= g2d_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(g2d_clk_regs),
+	.suspend_regs		= g2d_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(g2d_suspend_regs),
+	.clk_name		= "aclk_g2d_400",
 };
 
-static void __init exynos5433_cmu_g2d_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &g2d_cmu_info);
-}
-
-CLK_OF_DECLARE(exynos5433_cmu_g2d, "samsung,exynos5433-cmu-g2d",
-		exynos5433_cmu_g2d_init);
-
 /*
  * Register offset definitions for CMU_DISP
  */
@@ -2492,6 +2527,14 @@ static const unsigned long disp_clk_regs[] __initconst = {
 	CLKOUT_CMU_DISP_DIV_STAT,
 };
 
+static const struct samsung_clk_reg_dump disp_suspend_regs[] = {
+	{MUX_SEL_DISP0, 0},
+	{MUX_SEL_DISP1, 0},
+	{MUX_SEL_DISP2, 0},
+	{MUX_SEL_DISP3, 0},
+	{MUX_SEL_DISP4, 0},
+};
+
 /* list of all parent clock list */
 PNAME(mout_disp_pll_p)			= { "oscclk", "fout_disp_pll", };
 PNAME(mout_sclk_dsim1_user_p)		= { "oscclk", "sclk_dsim1_disp", };
@@ -2821,7 +2864,8 @@ static const struct samsung_gate_clock disp_gate_clks[] __initconst = {
 			"div_sclk_decon_eclk_disp", ENABLE_SCLK_DISP, 2, 0, 0),
 };
 
-static const struct samsung_cmu_info disp_cmu_info __initconst = {
+static const struct exynos5433_cmu_info disp_cmu_info __initconst = {
+	.nr_clk_ids		= DISP_NR_CLK,
 	.pll_clks		= disp_pll_clks,
 	.nr_pll_clks		= ARRAY_SIZE(disp_pll_clks),
 	.mux_clks		= disp_mux_clks,
@@ -2834,19 +2878,13 @@ static const struct samsung_cmu_info disp_cmu_info __initconst = {
 	.nr_fixed_clks		= ARRAY_SIZE(disp_fixed_clks),
 	.fixed_factor_clks	= disp_fixed_factor_clks,
 	.nr_fixed_factor_clks	= ARRAY_SIZE(disp_fixed_factor_clks),
-	.nr_clk_ids		= DISP_NR_CLK,
 	.clk_regs		= disp_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(disp_clk_regs),
+	.suspend_regs		= disp_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(disp_suspend_regs),
+	.clk_name		= "aclk_disp_333",
 };
 
-static void __init exynos5433_cmu_disp_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &disp_cmu_info);
-}
-
-CLK_OF_DECLARE(exynos5433_cmu_disp, "samsung,exynos5433-cmu-disp",
-		exynos5433_cmu_disp_init);
-
 /*
  * Register offset definitions for CMU_AUD
  */
@@ -2881,6 +2919,11 @@ static const unsigned long aud_clk_regs[] __initconst = {
 	ENABLE_IP_AUD1,
 };
 
+static const struct samsung_clk_reg_dump aud_suspend_regs[] = {
+	{MUX_SEL_AUD0, 0},
+	{MUX_SEL_AUD1, 0},
+};
+
 /* list of all parent clock list */
 PNAME(mout_aud_pll_user_aud_p)	= { "oscclk", "fout_aud_pll", };
 PNAME(mout_sclk_aud_pcm_p)	= { "mout_aud_pll_user", "ioclk_audiocdclk0",};
@@ -2995,7 +3038,8 @@ static const struct samsung_gate_clock aud_gate_clks[] __initconst = {
 			ENABLE_SCLK_AUD1, 0, CLK_IGNORE_UNUSED, 0),
 };
 
-static const struct samsung_cmu_info aud_cmu_info __initconst = {
+static const struct exynos5433_cmu_info aud_cmu_info __initconst = {
+	.nr_clk_ids		= AUD_NR_CLK,
 	.mux_clks		= aud_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(aud_mux_clks),
 	.div_clks		= aud_div_clks,
@@ -3004,19 +3048,12 @@ static const struct samsung_cmu_info aud_cmu_info __initconst = {
 	.nr_gate_clks		= ARRAY_SIZE(aud_gate_clks),
 	.fixed_clks		= aud_fixed_clks,
 	.nr_fixed_clks		= ARRAY_SIZE(aud_fixed_clks),
-	.nr_clk_ids		= AUD_NR_CLK,
 	.clk_regs		= aud_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(aud_clk_regs),
+	.suspend_regs		= aud_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(aud_suspend_regs),
 };
 
-static void __init exynos5433_cmu_aud_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &aud_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_aud, "samsung,exynos5433-cmu-aud",
-		exynos5433_cmu_aud_init);
-
-
 /*
  * Register offset definitions for CMU_BUS{0|1|2}
  */
@@ -3218,6 +3255,10 @@ static const unsigned long g3d_clk_regs[] __initconst = {
 	CLK_STOPCTRL,
 };
 
+static const struct samsung_clk_reg_dump g3d_suspend_regs[] = {
+	{MUX_SEL_G3D, 0},
+};
+
 /* list of all parent clock list */
 PNAME(mout_aclk_g3d_400_p)	= { "mout_g3d_pll", "aclk_g3d_400", };
 PNAME(mout_g3d_pll_p)		= { "oscclk", "fout_g3d_pll", };
@@ -3279,7 +3320,8 @@ static const struct samsung_gate_clock g3d_gate_clks[] __initconst = {
 			ENABLE_SCLK_G3D, 0, 0, 0),
 };
 
-static const struct samsung_cmu_info g3d_cmu_info __initconst = {
+static const struct exynos5433_cmu_info g3d_cmu_info __initconst = {
+	.nr_clk_ids		= G3D_NR_CLK,
 	.pll_clks		= g3d_pll_clks,
 	.nr_pll_clks		= ARRAY_SIZE(g3d_pll_clks),
 	.mux_clks		= g3d_mux_clks,
@@ -3288,18 +3330,13 @@ static const struct samsung_cmu_info g3d_cmu_info __initconst = {
 	.nr_div_clks		= ARRAY_SIZE(g3d_div_clks),
 	.gate_clks		= g3d_gate_clks,
 	.nr_gate_clks		= ARRAY_SIZE(g3d_gate_clks),
-	.nr_clk_ids		= G3D_NR_CLK,
 	.clk_regs		= g3d_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(g3d_clk_regs),
+	.suspend_regs		= g3d_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(g3d_suspend_regs),
+	.clk_name		= "aclk_g3d_400",
 };
 
-static void __init exynos5433_cmu_g3d_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &g3d_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_g3d, "samsung,exynos5433-cmu-g3d",
-		exynos5433_cmu_g3d_init);
-
 /*
  * Register offset definitions for CMU_GSCL
  */
@@ -3338,6 +3375,12 @@ static const unsigned long gscl_clk_regs[] __initconst = {
 	ENABLE_IP_GSCL_SECURE_SMMU_GSCL2,
 };
 
+static const struct samsung_clk_reg_dump gscl_suspend_regs[] = {
+	{MUX_SEL_GSCL, 0},
+	{ENABLE_ACLK_GSCL, 0xfff},
+	{ENABLE_PCLK_GSCL, 0xff},
+};
+
 /* list of all parent clock list */
 PNAME(aclk_gscl_111_user_p)	= { "oscclk", "aclk_gscl_111", };
 PNAME(aclk_gscl_333_user_p)	= { "oscclk", "aclk_gscl_333", };
@@ -3424,23 +3467,19 @@ static const struct samsung_gate_clock gscl_gate_clks[] __initconst = {
 		ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL2, 0, 0, 0),
 };
 
-static const struct samsung_cmu_info gscl_cmu_info __initconst = {
+static const struct exynos5433_cmu_info gscl_cmu_info __initconst = {
+	.nr_clk_ids		= GSCL_NR_CLK,
 	.mux_clks		= gscl_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(gscl_mux_clks),
 	.gate_clks		= gscl_gate_clks,
 	.nr_gate_clks		= ARRAY_SIZE(gscl_gate_clks),
-	.nr_clk_ids		= GSCL_NR_CLK,
 	.clk_regs		= gscl_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(gscl_clk_regs),
+	.suspend_regs		= gscl_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(gscl_suspend_regs),
+	.clk_name		= "aclk_gscl_111",
 };
 
-static void __init exynos5433_cmu_gscl_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &gscl_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_gscl, "samsung,exynos5433-cmu-gscl",
-		exynos5433_cmu_gscl_init);
-
 /*
  * Register offset definitions for CMU_APOLLO
  */
@@ -3966,6 +4005,11 @@ static const unsigned long mscl_clk_regs[] __initconst = {
 	ENABLE_IP_MSCL_SECURE_SMMU_JPEG,
 };
 
+static const struct samsung_clk_reg_dump mscl_suspend_regs[] = {
+	{MUX_SEL_MSCL0, 0},
+	{MUX_SEL_MSCL1, 0},
+};
+
 /* list of all parent clock list */
 PNAME(mout_sclk_jpeg_user_p)		= { "oscclk", "sclk_jpeg_mscl", };
 PNAME(mout_aclk_mscl_400_user_p)	= { "oscclk", "aclk_mscl_400", };
@@ -4068,25 +4112,21 @@ static const struct samsung_gate_clock mscl_gate_clks[] __initconst = {
 			CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0),
 };
 
-static const struct samsung_cmu_info mscl_cmu_info __initconst = {
+static const struct exynos5433_cmu_info mscl_cmu_info __initconst = {
+	.nr_clk_ids		= MSCL_NR_CLK,
 	.mux_clks		= mscl_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(mscl_mux_clks),
 	.div_clks		= mscl_div_clks,
 	.nr_div_clks		= ARRAY_SIZE(mscl_div_clks),
 	.gate_clks		= mscl_gate_clks,
 	.nr_gate_clks		= ARRAY_SIZE(mscl_gate_clks),
-	.nr_clk_ids		= MSCL_NR_CLK,
 	.clk_regs		= mscl_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(mscl_clk_regs),
+	.suspend_regs		= mscl_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(mscl_suspend_regs),
+	.clk_name		= "aclk_mscl_400",
 };
 
-static void __init exynos5433_cmu_mscl_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &mscl_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_mscl, "samsung,exynos5433-cmu-mscl",
-		exynos5433_cmu_mscl_init);
-
 /*
  * Register offset definitions for CMU_MFC
  */
@@ -4116,6 +4156,10 @@ static const unsigned long mfc_clk_regs[] __initconst = {
 	ENABLE_IP_MFC_SECURE_SMMU_MFC,
 };
 
+static const struct samsung_clk_reg_dump mfc_suspend_regs[] = {
+	{MUX_SEL_MFC, 0},
+};
+
 PNAME(mout_aclk_mfc_400_user_p)		= { "oscclk", "aclk_mfc_400", };
 
 static const struct samsung_mux_clock mfc_mux_clks[] __initconst = {
@@ -4176,25 +4220,21 @@ static const struct samsung_gate_clock mfc_gate_clks[] __initconst = {
 			0, CLK_IGNORE_UNUSED, 0),
 };
 
-static const struct samsung_cmu_info mfc_cmu_info __initconst = {
+static const struct exynos5433_cmu_info mfc_cmu_info __initconst = {
+	.nr_clk_ids		= MFC_NR_CLK,
 	.mux_clks		= mfc_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(mfc_mux_clks),
 	.div_clks		= mfc_div_clks,
 	.nr_div_clks		= ARRAY_SIZE(mfc_div_clks),
 	.gate_clks		= mfc_gate_clks,
 	.nr_gate_clks		= ARRAY_SIZE(mfc_gate_clks),
-	.nr_clk_ids		= MFC_NR_CLK,
 	.clk_regs		= mfc_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(mfc_clk_regs),
+	.suspend_regs		= mfc_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(mfc_suspend_regs),
+	.clk_name		= "aclk_mfc_400",
 };
 
-static void __init exynos5433_cmu_mfc_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &mfc_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_mfc, "samsung,exynos5433-cmu-mfc",
-		exynos5433_cmu_mfc_init);
-
 /*
  * Register offset definitions for CMU_HEVC
  */
@@ -4224,6 +4264,10 @@ static const unsigned long hevc_clk_regs[] __initconst = {
 	ENABLE_IP_HEVC_SECURE_SMMU_HEVC,
 };
 
+static const struct samsung_clk_reg_dump hevc_suspend_regs[] = {
+	{MUX_SEL_HEVC, 0},
+};
+
 PNAME(mout_aclk_hevc_400_user_p)	= { "oscclk", "aclk_hevc_400", };
 
 static const struct samsung_mux_clock hevc_mux_clks[] __initconst = {
@@ -4286,25 +4330,21 @@ static const struct samsung_gate_clock hevc_gate_clks[] __initconst = {
 			0, CLK_IGNORE_UNUSED, 0),
 };
 
-static const struct samsung_cmu_info hevc_cmu_info __initconst = {
+static const struct exynos5433_cmu_info hevc_cmu_info __initconst = {
+	.nr_clk_ids		= HEVC_NR_CLK,
 	.mux_clks		= hevc_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(hevc_mux_clks),
 	.div_clks		= hevc_div_clks,
 	.nr_div_clks		= ARRAY_SIZE(hevc_div_clks),
 	.gate_clks		= hevc_gate_clks,
 	.nr_gate_clks		= ARRAY_SIZE(hevc_gate_clks),
-	.nr_clk_ids		= HEVC_NR_CLK,
 	.clk_regs		= hevc_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(hevc_clk_regs),
+	.suspend_regs		= hevc_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(hevc_suspend_regs),
+	.clk_name		= "aclk_hevc_400",
 };
 
-static void __init exynos5433_cmu_hevc_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &hevc_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_hevc, "samsung,exynos5433-cmu-hevc",
-		exynos5433_cmu_hevc_init);
-
 /*
  * Register offset definitions for CMU_ISP
  */
@@ -4338,6 +4378,10 @@ static const unsigned long isp_clk_regs[] __initconst = {
 	ENABLE_IP_ISP3,
 };
 
+static const struct samsung_clk_reg_dump isp_suspend_regs[] = {
+	{MUX_SEL_ISP, 0},
+};
+
 PNAME(mout_aclk_isp_dis_400_user_p)	= { "oscclk", "aclk_isp_dis_400", };
 PNAME(mout_aclk_isp_400_user_p)		= { "oscclk", "aclk_isp_400", };
 
@@ -4539,25 +4583,21 @@ static const struct samsung_gate_clock isp_gate_clks[] __initconst = {
 			0, CLK_IGNORE_UNUSED, 0),
 };
 
-static const struct samsung_cmu_info isp_cmu_info __initconst = {
+static const struct exynos5433_cmu_info isp_cmu_info __initconst = {
+	.nr_clk_ids		= ISP_NR_CLK,
 	.mux_clks		= isp_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(isp_mux_clks),
 	.div_clks		= isp_div_clks,
 	.nr_div_clks		= ARRAY_SIZE(isp_div_clks),
 	.gate_clks		= isp_gate_clks,
 	.nr_gate_clks		= ARRAY_SIZE(isp_gate_clks),
-	.nr_clk_ids		= ISP_NR_CLK,
 	.clk_regs		= isp_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(isp_clk_regs),
+	.suspend_regs		= isp_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(isp_suspend_regs),
+	.clk_name		= "aclk_isp_400",
 };
 
-static void __init exynos5433_cmu_isp_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &isp_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_isp, "samsung,exynos5433-cmu-isp",
-		exynos5433_cmu_isp_init);
-
 /*
  * Register offset definitions for CMU_CAM0
  */
@@ -4621,6 +4661,15 @@ static const unsigned long cam0_clk_regs[] __initconst = {
 	ENABLE_IP_CAM02,
 	ENABLE_IP_CAM03,
 };
+
+static const struct samsung_clk_reg_dump cam0_suspend_regs[] = {
+	{MUX_SEL_CAM00, 0},
+	{MUX_SEL_CAM01, 0},
+	{MUX_SEL_CAM02, 0},
+	{MUX_SEL_CAM03, 0},
+	{MUX_SEL_CAM04, 0},
+};
+
 PNAME(mout_aclk_cam0_333_user_p)	= { "oscclk", "aclk_cam0_333", };
 PNAME(mout_aclk_cam0_400_user_p)	= { "oscclk", "aclk_cam0_400", };
 PNAME(mout_aclk_cam0_552_user_p)	= { "oscclk", "aclk_cam0_552", };
@@ -5014,7 +5063,8 @@ static const struct samsung_gate_clock cam0_gate_clks[] __initconst = {
 			ENABLE_SCLK_CAM0, 0, 0, 0),
 };
 
-static const struct samsung_cmu_info cam0_cmu_info __initconst = {
+static const struct exynos5433_cmu_info cam0_cmu_info __initconst = {
+	.nr_clk_ids		= CAM0_NR_CLK,
 	.mux_clks		= cam0_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(cam0_mux_clks),
 	.div_clks		= cam0_div_clks,
@@ -5023,18 +5073,13 @@ static const struct samsung_cmu_info cam0_cmu_info __initconst = {
 	.nr_gate_clks		= ARRAY_SIZE(cam0_gate_clks),
 	.fixed_clks		= cam0_fixed_clks,
 	.nr_fixed_clks		= ARRAY_SIZE(cam0_fixed_clks),
-	.nr_clk_ids		= CAM0_NR_CLK,
 	.clk_regs		= cam0_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(cam0_clk_regs),
+	.suspend_regs		= cam0_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(cam0_suspend_regs),
+	.clk_name		= "aclk_cam0_400",
 };
 
-static void __init exynos5433_cmu_cam0_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &cam0_cmu_info);
-}
-CLK_OF_DECLARE(exynos5433_cmu_cam0, "samsung,exynos5433-cmu-cam0",
-		exynos5433_cmu_cam0_init);
-
 /*
  * Register offset definitions for CMU_CAM1
  */
@@ -5081,6 +5126,12 @@ static const unsigned long cam1_clk_regs[] __initconst = {
 	ENABLE_IP_CAM12,
 };
 
+static const struct samsung_clk_reg_dump cam1_suspend_regs[] = {
+	{MUX_SEL_CAM10, 0},
+	{MUX_SEL_CAM11, 0},
+	{MUX_SEL_CAM12, 0},
+};
+
 PNAME(mout_sclk_isp_uart_user_p)	= { "oscclk", "sclk_isp_uart_cam1", };
 PNAME(mout_sclk_isp_spi1_user_p)	= { "oscclk", "sclk_isp_spi1_cam1", };
 PNAME(mout_sclk_isp_spi0_user_p)	= { "oscclk", "sclk_isp_spi0_cam1", };
@@ -5387,7 +5438,8 @@ static const struct samsung_gate_clock cam1_gate_clks[] __initconst = {
 			ENABLE_SCLK_CAM1, 0, 0, 0),
 };
 
-static const struct samsung_cmu_info cam1_cmu_info __initconst = {
+static const struct exynos5433_cmu_info cam1_cmu_info __initconst = {
+	.nr_clk_ids		= CAM1_NR_CLK,
 	.mux_clks		= cam1_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(cam1_mux_clks),
 	.div_clks		= cam1_div_clks,
@@ -5396,14 +5448,226 @@ static const struct samsung_cmu_info cam1_cmu_info __initconst = {
 	.nr_gate_clks		= ARRAY_SIZE(cam1_gate_clks),
 	.fixed_clks		= cam1_fixed_clks,
 	.nr_fixed_clks		= ARRAY_SIZE(cam1_fixed_clks),
-	.nr_clk_ids		= CAM1_NR_CLK,
 	.clk_regs		= cam1_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(cam1_clk_regs),
+	.suspend_regs		= cam1_suspend_regs,
+	.nr_suspend_regs	= ARRAY_SIZE(cam1_suspend_regs),
+	.clk_name		= "aclk_cam1_400",
+};
+
+
+struct exynos5433_cmu_data {
+	struct samsung_clk_provider ctx;
+
+	struct samsung_clk_reg_dump *clk_save;
+	unsigned int nr_clk_save;
+	const struct samsung_clk_reg_dump *clk_suspend;
+	unsigned int nr_clk_suspend;
+
+	struct clk *clk;
+	struct clk **pclks;
+	int nr_pclks;
+};
+
+static int exynos5433_cmu_suspend(struct device *dev)
+{
+	struct exynos5433_cmu_data *data = dev_get_drvdata(dev);
+	int i;
+
+	samsung_clk_save(data->ctx.reg_base, data->clk_save,
+			 data->nr_clk_save);
+
+	for (i = 0; i < data->nr_pclks; i++)
+		clk_enable(data->pclks[i]);
+
+	samsung_clk_restore(data->ctx.reg_base, data->clk_suspend,
+			    data->nr_clk_suspend);
+
+	for (i = 0; i < data->nr_pclks; i++)
+		clk_disable(data->pclks[i]);
+
+	clk_disable(data->clk);
+
+	return 0;
+}
+
+static int exynos5433_cmu_resume(struct device *dev)
+{
+	struct exynos5433_cmu_data *data = dev_get_drvdata(dev);
+	int i;
+
+	clk_enable(data->clk);
+
+	for (i = 0; i < data->nr_pclks; i++)
+		clk_enable(data->pclks[i]);
+
+	samsung_clk_restore(data->ctx.reg_base, data->clk_save,
+			    data->nr_clk_save);
+
+	for (i = 0; i < data->nr_pclks; i++)
+		clk_disable(data->pclks[i]);
+
+	return 0;
+}
+
+static int __init exynos5433_cmu_probe(struct platform_device *pdev)
+{
+	const struct exynos5433_cmu_info *info;
+	struct exynos5433_cmu_data *data;
+	struct samsung_clk_provider *ctx;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	void __iomem *reg_base;
+	struct clk **clk_table;
+	int i;
+
+	info = of_device_get_match_data(dev);
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	ctx = &data->ctx;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	reg_base = devm_ioremap_resource(dev, res);
+	if (!reg_base) {
+		dev_err(dev, "failed to map registers\n");
+		return -ENOMEM;
+	}
+
+	clk_table = devm_kcalloc(dev, info->nr_clk_ids, sizeof(struct clk *),
+				 GFP_KERNEL);
+	if (!clk_table) {
+		dev_err(dev, "could not allocate clock lookup table\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < info->nr_clk_ids; ++i)
+		clk_table[i] = ERR_PTR(-ENOENT);
+
+	ctx->clk_data.clks = clk_table;
+	ctx->clk_data.clk_num = info->nr_clk_ids;
+	ctx->reg_base = reg_base;
+	ctx->dev = dev;
+	spin_lock_init(&ctx->lock);
+
+	data->clk_save = samsung_clk_alloc_reg_dump(info->clk_regs,
+						    info->nr_clk_regs);
+	data->nr_clk_save = info->nr_clk_regs;
+	data->clk_suspend = info->suspend_regs;
+	data->nr_clk_suspend = info->nr_suspend_regs;
+	data->nr_pclks = of_count_phandle_with_args(dev->of_node, "clocks",
+						    "#clock-cells");
+	if (data->nr_pclks > 0) {
+		data->pclks = devm_kcalloc(dev, sizeof(struct clk *),
+					   data->nr_pclks, GFP_KERNEL);
+
+		for (i = 0; i < data->nr_pclks; i++) {
+			struct clk *clk = of_clk_get(dev->of_node, i);
+
+			if (IS_ERR(clk))
+				return PTR_ERR(clk);
+			data->pclks[i] = clk;
+		}
+	}
+
+	/*
+	 * Prepare all parent clocks here to avoid potential deadlock caused
+	 * by global clock "prepare lock" grabbed by runtime pm callbacks
+	 * from pm workers.
+	 */
+	for (i = 0; i < data->nr_pclks; i++)
+		clk_prepare(data->pclks[i]);
+
+	if (info->pll_clks)
+		samsung_clk_register_pll(ctx, info->pll_clks, info->nr_pll_clks,
+					 reg_base);
+	if (info->mux_clks)
+		samsung_clk_register_mux(ctx, info->mux_clks,
+					 info->nr_mux_clks);
+	if (info->div_clks)
+		samsung_clk_register_div(ctx, info->div_clks,
+					 info->nr_div_clks);
+	if (info->gate_clks)
+		samsung_clk_register_gate(ctx, info->gate_clks,
+					  info->nr_gate_clks);
+	if (info->fixed_clks)
+		samsung_clk_register_fixed_rate(ctx, info->fixed_clks,
+						info->nr_fixed_clks);
+	if (info->fixed_factor_clks)
+		samsung_clk_register_fixed_factor(ctx, info->fixed_factor_clks,
+						  info->nr_fixed_factor_clks);
+
+	if (info->clk_name)
+		data->clk = clk_get(dev, info->clk_name);
+	clk_prepare_enable(data->clk);
+
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+
+	platform_set_drvdata(pdev, data);
+	samsung_clk_of_add_provider(dev->of_node, ctx);
+
+	return 0;
+}
+
+static const struct of_device_id exynos5433_cmu_of_match[] = {
+	{
+		.compatible = "samsung,exynos5433-cmu-aud",
+		.data = &aud_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-cam0",
+		.data = &cam0_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-cam1",
+		.data = &cam1_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-disp",
+		.data = &disp_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-g2d",
+		.data = &g2d_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-g3d",
+		.data = &g3d_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-gscl",
+		.data = &gscl_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-mfc",
+		.data = &mfc_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-hevc",
+		.data = &hevc_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-isp",
+		.data = &isp_cmu_info,
+	}, {
+		.compatible = "samsung,exynos5433-cmu-mscl",
+		.data = &mscl_cmu_info,
+	}, {
+	},
+};
+
+static const struct dev_pm_ops exynos5433_cmu_pm_ops = {
+	SET_RUNTIME_PM_OPS(exynos5433_cmu_suspend, exynos5433_cmu_resume,
+			   NULL)
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				     pm_runtime_force_resume)
+};
+
+static struct platform_driver exynos5433_cmu_driver = {
+	.driver	= {
+		.name = "exynos5433-cmu",
+		.of_match_table = exynos5433_cmu_of_match,
+		.suppress_bind_attrs = true,
+		.pm = &exynos5433_cmu_pm_ops,
+	},
+	.probe = exynos5433_cmu_probe,
 };
 
-static void __init exynos5433_cmu_cam1_init(struct device_node *np)
+static int __init exynos5433_cmu_init(void)
 {
-	samsung_cmu_register_one(np, &cam1_cmu_info);
+	return platform_driver_register(&exynos5433_cmu_driver);
 }
-CLK_OF_DECLARE(exynos5433_cmu_cam1, "samsung,exynos5433-cmu-cam1",
-		exynos5433_cmu_cam1_init);
+core_initcall(exynos5433_cmu_init);
-- 
1.9.1

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

* [PATCH] clk: fix boolreturn.cocci warnings
  2016-09-01 13:45   ` Marek Szyprowski
  (?)
@ 2016-09-01 15:10     ` kbuild test robot
  -1 siblings, 0 replies; 68+ messages in thread
From: kbuild test robot @ 2016-09-01 15:10 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: kbuild-all, linux-clk, linux-pm, linux-samsung-soc,
	linux-arm-kernel, Marek Szyprowski, Stephen Boyd,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz

drivers/clk/clk.c:123:9-10: WARNING: return of 0/1 in function 'clk_pm_runtime_suspended' with return type bool

 Return statements in functions returning bool should use
 true/false instead of 1/0.
Generated by: scripts/coccinelle/misc/boolreturn.cocci

CC: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
---

 clk.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -120,7 +120,7 @@ static void clk_pm_runtime_put(struct cl
 static bool clk_pm_runtime_suspended(struct clk_core *core)
 {
 	if (!core->dev)
-		return 0;
+		return false;
 
 	return pm_runtime_suspended(core->dev);
 }

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

* Re: [PATCH 1/5] clk: add support for runtime pm
  2016-09-01 13:45   ` Marek Szyprowski
  (?)
@ 2016-09-01 15:10     ` kbuild test robot
  -1 siblings, 0 replies; 68+ messages in thread
From: kbuild test robot @ 2016-09-01 15:10 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: kbuild-all, linux-clk, linux-pm, linux-samsung-soc,
	linux-arm-kernel, Marek Szyprowski, Stephen Boyd,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz

Hi Marek,

[auto build test WARNING on clk/clk-next]
[also build test WARNING on v4.8-rc4 next-20160825]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Marek-Szyprowski/Add-runtime-PM-support-for-clocks-on-Exynos-SoC-example/20160901-215042
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next


coccinelle warnings: (new ones prefixed by >>)

>> drivers/clk/clk.c:123:9-10: WARNING: return of 0/1 in function 'clk_pm_runtime_suspended' with return type bool

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

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

* Re: [PATCH 1/5] clk: add support for runtime pm
@ 2016-09-01 15:10     ` kbuild test robot
  0 siblings, 0 replies; 68+ messages in thread
From: kbuild test robot @ 2016-09-01 15:10 UTC (permalink / raw)
  Cc: kbuild-all, linux-clk, linux-pm, linux-samsung-soc,
	linux-arm-kernel, Marek Szyprowski, Stephen Boyd,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz

Hi Marek,

[auto build test WARNING on clk/clk-next]
[also build test WARNING on v4.8-rc4 next-20160825]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Marek-Szyprowski/Add-runtime-PM-support-for-clocks-on-Exynos-SoC-example/20160901-215042
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next


coccinelle warnings: (new ones prefixed by >>)

>> drivers/clk/clk.c:123:9-10: WARNING: return of 0/1 in function 'clk_pm_runtime_suspended' with return type bool

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

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

* [PATCH] clk: fix boolreturn.cocci warnings
@ 2016-09-01 15:10     ` kbuild test robot
  0 siblings, 0 replies; 68+ messages in thread
From: kbuild test robot @ 2016-09-01 15:10 UTC (permalink / raw)
  Cc: kbuild-all, linux-clk, linux-pm, linux-samsung-soc,
	linux-arm-kernel, Marek Szyprowski, Stephen Boyd,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz

drivers/clk/clk.c:123:9-10: WARNING: return of 0/1 in function 'clk_pm_runtime_suspended' with return type bool

 Return statements in functions returning bool should use
 true/false instead of 1/0.
Generated by: scripts/coccinelle/misc/boolreturn.cocci

CC: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
---

 clk.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -120,7 +120,7 @@ static void clk_pm_runtime_put(struct cl
 static bool clk_pm_runtime_suspended(struct clk_core *core)
 {
 	if (!core->dev)
-		return 0;
+		return false;
 
 	return pm_runtime_suspended(core->dev);
 }

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

* [PATCH 1/5] clk: add support for runtime pm
@ 2016-09-01 15:10     ` kbuild test robot
  0 siblings, 0 replies; 68+ messages in thread
From: kbuild test robot @ 2016-09-01 15:10 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marek,

[auto build test WARNING on clk/clk-next]
[also build test WARNING on v4.8-rc4 next-20160825]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Marek-Szyprowski/Add-runtime-PM-support-for-clocks-on-Exynos-SoC-example/20160901-215042
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next


coccinelle warnings: (new ones prefixed by >>)

>> drivers/clk/clk.c:123:9-10: WARNING: return of 0/1 in function 'clk_pm_runtime_suspended' with return type bool

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

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

* [PATCH] clk: fix boolreturn.cocci warnings
@ 2016-09-01 15:10     ` kbuild test robot
  0 siblings, 0 replies; 68+ messages in thread
From: kbuild test robot @ 2016-09-01 15:10 UTC (permalink / raw)
  To: linux-arm-kernel

drivers/clk/clk.c:123:9-10: WARNING: return of 0/1 in function 'clk_pm_runtime_suspended' with return type bool

 Return statements in functions returning bool should use
 true/false instead of 1/0.
Generated by: scripts/coccinelle/misc/boolreturn.cocci

CC: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
---

 clk.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -120,7 +120,7 @@ static void clk_pm_runtime_put(struct cl
 static bool clk_pm_runtime_suspended(struct clk_core *core)
 {
 	if (!core->dev)
-		return 0;
+		return false;
 
 	return pm_runtime_suspended(core->dev);
 }

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

* Re: [PATCH 5/5] clocks: exynos5433: add runtime pm support
  2016-09-01 13:45   ` Marek Szyprowski
  (?)
@ 2016-09-01 16:55     ` Bartlomiej Zolnierkiewicz
  -1 siblings, 0 replies; 68+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2016-09-01 16:55 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel,
	Stephen Boyd, Michael Turquette, Ulf Hansson, Sylwester Nawrocki,
	Chanwoo Choi, Inki Dae, Krzysztof Kozlowski


Hi,

On Thursday, September 01, 2016 03:45:51 PM Marek Szyprowski wrote:
> Add runtime pm support for all clock controller units (CMU), which belongs
> to power domains and require special handling during on/off operations.
> Typically special values has to be written to MUX registers to change
> internal clocks parents to OSC clock before turning power off. During such
> operation all clocks, which enters CMU has to be enabled to let MUX to
> stabilize. Also for each CMU there is one special parent clock, which has
> to be enabled all the time when any access to CMU registers is done.
> 
> This patch solves most of the mysterious external abort and freeze issues
> caused by a lack of proper parent CMU clock enabled or incorrect turn off
> procedure.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>  drivers/clk/samsung/clk-exynos5433.c | 462 +++++++++++++++++++++++++++--------
>  1 file changed, 363 insertions(+), 99 deletions(-)
> 
> diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c
> index ea1608682d7f..9fb896b56ddf 100644
> --- a/drivers/clk/samsung/clk-exynos5433.c
> +++ b/drivers/clk/samsung/clk-exynos5433.c
> @@ -9,9 +9,14 @@
>   * Common Clock Framework support for Exynos5443 SoC.
>   */
>  
> +#include <linux/clk.h>
>  #include <linux/clk-provider.h>
>  #include <linux/of.h>
>  #include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/slab.h>
>  
>  #include <dt-bindings/clock/exynos5433.h>
>  
> @@ -19,6 +24,37 @@
>  #include "clk-cpu.h"
>  #include "clk-pll.h"
>  
> +struct exynos5433_cmu_info {
> +	/* total number of clocks with IDs assigned*/
> +	unsigned int nr_clk_ids;
> +	/* list of pll clocks and respective count */
> +	const struct samsung_pll_clock *pll_clks;
> +	unsigned int nr_pll_clks;
> +	/* list of mux clocks and respective count */
> +	const struct samsung_mux_clock *mux_clks;
> +	unsigned int nr_mux_clks;
> +	/* list of div clocks and respective count */
> +	const struct samsung_div_clock *div_clks;
> +	unsigned int nr_div_clks;
> +	/* list of gate clocks and respective count */
> +	const struct samsung_gate_clock *gate_clks;
> +	unsigned int nr_gate_clks;
> +	/* list of fixed clocks and respective count */
> +	const struct samsung_fixed_rate_clock *fixed_clks;
> +	unsigned int nr_fixed_clks;
> +	/* list of fixed factor clocks and respective count */
> +	const struct samsung_fixed_factor_clock *fixed_factor_clks;
> +	unsigned int nr_fixed_factor_clks;
> +	/* list and number of clocks registers */
> +	const unsigned long *clk_regs;
> +	unsigned int nr_clk_regs;
> +	/* list and number of clocks registers to set before suspend */
> +	const struct samsung_clk_reg_dump *suspend_regs;
> +	unsigned int nr_suspend_regs;
> +	/* name of the parent clock needed for CMU register access */
> +	const char *clk_name;
> +};

Have you considered extending struct samsung_cmu_info instead
(all instances are __initdata anyway so slight increase of struct's
size shouldn't be a problem)?

> +static const struct samsung_clk_reg_dump g2d_suspend_regs[] = {
> +	{MUX_SEL_G2D0, 0},

Minor nit: preferred CodingStyle is:

	{ MUX_SEL_G2D0, 0 },

( ditto for other struct samsung_clk_reg_dump instances )

> +	clk_table = devm_kcalloc(dev, info->nr_clk_ids, sizeof(struct clk *),
> +				 GFP_KERNEL);
> +	if (!clk_table) {
> +		dev_err(dev, "could not allocate clock lookup table\n");
> +		return -ENOMEM;
> +	}

checkpatch.pl complains with:

WARNING: Possible unnecessary 'out of memory' message
#681: FILE: drivers/clk/samsung/clk-exynos5433.c:5541:
+       if (!clk_table) {
+               dev_err(dev, "could not allocate clock lookup table\n");

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

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

* Re: [PATCH 5/5] clocks: exynos5433: add runtime pm support
@ 2016-09-01 16:55     ` Bartlomiej Zolnierkiewicz
  0 siblings, 0 replies; 68+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2016-09-01 16:55 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: Ulf Hansson, linux-samsung-soc, linux-pm, Michael Turquette,
	Stephen Boyd, Krzysztof Kozlowski, Inki Dae, Chanwoo Choi,
	Sylwester Nawrocki, linux-clk, linux-arm-kernel


Hi,

On Thursday, September 01, 2016 03:45:51 PM Marek Szyprowski wrote:
> Add runtime pm support for all clock controller units (CMU), which belongs
> to power domains and require special handling during on/off operations.
> Typically special values has to be written to MUX registers to change
> internal clocks parents to OSC clock before turning power off. During such
> operation all clocks, which enters CMU has to be enabled to let MUX to
> stabilize. Also for each CMU there is one special parent clock, which has
> to be enabled all the time when any access to CMU registers is done.
> 
> This patch solves most of the mysterious external abort and freeze issues
> caused by a lack of proper parent CMU clock enabled or incorrect turn off
> procedure.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>  drivers/clk/samsung/clk-exynos5433.c | 462 +++++++++++++++++++++++++++--------
>  1 file changed, 363 insertions(+), 99 deletions(-)
> 
> diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c
> index ea1608682d7f..9fb896b56ddf 100644
> --- a/drivers/clk/samsung/clk-exynos5433.c
> +++ b/drivers/clk/samsung/clk-exynos5433.c
> @@ -9,9 +9,14 @@
>   * Common Clock Framework support for Exynos5443 SoC.
>   */
>  
> +#include <linux/clk.h>
>  #include <linux/clk-provider.h>
>  #include <linux/of.h>
>  #include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/slab.h>
>  
>  #include <dt-bindings/clock/exynos5433.h>
>  
> @@ -19,6 +24,37 @@
>  #include "clk-cpu.h"
>  #include "clk-pll.h"
>  
> +struct exynos5433_cmu_info {
> +	/* total number of clocks with IDs assigned*/
> +	unsigned int nr_clk_ids;
> +	/* list of pll clocks and respective count */
> +	const struct samsung_pll_clock *pll_clks;
> +	unsigned int nr_pll_clks;
> +	/* list of mux clocks and respective count */
> +	const struct samsung_mux_clock *mux_clks;
> +	unsigned int nr_mux_clks;
> +	/* list of div clocks and respective count */
> +	const struct samsung_div_clock *div_clks;
> +	unsigned int nr_div_clks;
> +	/* list of gate clocks and respective count */
> +	const struct samsung_gate_clock *gate_clks;
> +	unsigned int nr_gate_clks;
> +	/* list of fixed clocks and respective count */
> +	const struct samsung_fixed_rate_clock *fixed_clks;
> +	unsigned int nr_fixed_clks;
> +	/* list of fixed factor clocks and respective count */
> +	const struct samsung_fixed_factor_clock *fixed_factor_clks;
> +	unsigned int nr_fixed_factor_clks;
> +	/* list and number of clocks registers */
> +	const unsigned long *clk_regs;
> +	unsigned int nr_clk_regs;
> +	/* list and number of clocks registers to set before suspend */
> +	const struct samsung_clk_reg_dump *suspend_regs;
> +	unsigned int nr_suspend_regs;
> +	/* name of the parent clock needed for CMU register access */
> +	const char *clk_name;
> +};

Have you considered extending struct samsung_cmu_info instead
(all instances are __initdata anyway so slight increase of struct's
size shouldn't be a problem)?

> +static const struct samsung_clk_reg_dump g2d_suspend_regs[] = {
> +	{MUX_SEL_G2D0, 0},

Minor nit: preferred CodingStyle is:

	{ MUX_SEL_G2D0, 0 },

( ditto for other struct samsung_clk_reg_dump instances )

> +	clk_table = devm_kcalloc(dev, info->nr_clk_ids, sizeof(struct clk *),
> +				 GFP_KERNEL);
> +	if (!clk_table) {
> +		dev_err(dev, "could not allocate clock lookup table\n");
> +		return -ENOMEM;
> +	}

checkpatch.pl complains with:

WARNING: Possible unnecessary 'out of memory' message
#681: FILE: drivers/clk/samsung/clk-exynos5433.c:5541:
+       if (!clk_table) {
+               dev_err(dev, "could not allocate clock lookup table\n");

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

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

* [PATCH 5/5] clocks: exynos5433: add runtime pm support
@ 2016-09-01 16:55     ` Bartlomiej Zolnierkiewicz
  0 siblings, 0 replies; 68+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2016-09-01 16:55 UTC (permalink / raw)
  To: linux-arm-kernel


Hi,

On Thursday, September 01, 2016 03:45:51 PM Marek Szyprowski wrote:
> Add runtime pm support for all clock controller units (CMU), which belongs
> to power domains and require special handling during on/off operations.
> Typically special values has to be written to MUX registers to change
> internal clocks parents to OSC clock before turning power off. During such
> operation all clocks, which enters CMU has to be enabled to let MUX to
> stabilize. Also for each CMU there is one special parent clock, which has
> to be enabled all the time when any access to CMU registers is done.
> 
> This patch solves most of the mysterious external abort and freeze issues
> caused by a lack of proper parent CMU clock enabled or incorrect turn off
> procedure.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>  drivers/clk/samsung/clk-exynos5433.c | 462 +++++++++++++++++++++++++++--------
>  1 file changed, 363 insertions(+), 99 deletions(-)
> 
> diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c
> index ea1608682d7f..9fb896b56ddf 100644
> --- a/drivers/clk/samsung/clk-exynos5433.c
> +++ b/drivers/clk/samsung/clk-exynos5433.c
> @@ -9,9 +9,14 @@
>   * Common Clock Framework support for Exynos5443 SoC.
>   */
>  
> +#include <linux/clk.h>
>  #include <linux/clk-provider.h>
>  #include <linux/of.h>
>  #include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/slab.h>
>  
>  #include <dt-bindings/clock/exynos5433.h>
>  
> @@ -19,6 +24,37 @@
>  #include "clk-cpu.h"
>  #include "clk-pll.h"
>  
> +struct exynos5433_cmu_info {
> +	/* total number of clocks with IDs assigned*/
> +	unsigned int nr_clk_ids;
> +	/* list of pll clocks and respective count */
> +	const struct samsung_pll_clock *pll_clks;
> +	unsigned int nr_pll_clks;
> +	/* list of mux clocks and respective count */
> +	const struct samsung_mux_clock *mux_clks;
> +	unsigned int nr_mux_clks;
> +	/* list of div clocks and respective count */
> +	const struct samsung_div_clock *div_clks;
> +	unsigned int nr_div_clks;
> +	/* list of gate clocks and respective count */
> +	const struct samsung_gate_clock *gate_clks;
> +	unsigned int nr_gate_clks;
> +	/* list of fixed clocks and respective count */
> +	const struct samsung_fixed_rate_clock *fixed_clks;
> +	unsigned int nr_fixed_clks;
> +	/* list of fixed factor clocks and respective count */
> +	const struct samsung_fixed_factor_clock *fixed_factor_clks;
> +	unsigned int nr_fixed_factor_clks;
> +	/* list and number of clocks registers */
> +	const unsigned long *clk_regs;
> +	unsigned int nr_clk_regs;
> +	/* list and number of clocks registers to set before suspend */
> +	const struct samsung_clk_reg_dump *suspend_regs;
> +	unsigned int nr_suspend_regs;
> +	/* name of the parent clock needed for CMU register access */
> +	const char *clk_name;
> +};

Have you considered extending struct samsung_cmu_info instead
(all instances are __initdata anyway so slight increase of struct's
size shouldn't be a problem)?

> +static const struct samsung_clk_reg_dump g2d_suspend_regs[] = {
> +	{MUX_SEL_G2D0, 0},

Minor nit: preferred CodingStyle is:

	{ MUX_SEL_G2D0, 0 },

( ditto for other struct samsung_clk_reg_dump instances )

> +	clk_table = devm_kcalloc(dev, info->nr_clk_ids, sizeof(struct clk *),
> +				 GFP_KERNEL);
> +	if (!clk_table) {
> +		dev_err(dev, "could not allocate clock lookup table\n");
> +		return -ENOMEM;
> +	}

checkpatch.pl complains with:

WARNING: Possible unnecessary 'out of memory' message
#681: FILE: drivers/clk/samsung/clk-exynos5433.c:5541:
+       if (!clk_table) {
+               dev_err(dev, "could not allocate clock lookup table\n");

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

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

* Re: [PATCH 3/5] clocks: exynos4x12: add runtime pm support for ISP clocks
  2016-09-01 13:45   ` Marek Szyprowski
  (?)
@ 2016-09-01 21:49     ` kbuild test robot
  -1 siblings, 0 replies; 68+ messages in thread
From: kbuild test robot @ 2016-09-01 21:49 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: kbuild-all, linux-clk, linux-pm, linux-samsung-soc,
	linux-arm-kernel, Marek Szyprowski, Stephen Boyd,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz

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

Hi Marek,

[auto build test WARNING on clk/clk-next]
[also build test WARNING on next-20160825]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Marek-Szyprowski/Add-runtime-PM-support-for-clocks-on-Exynos-SoC-example/20160901-215042
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 5.4.0-6) 5.4.0 20160609
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm 

All warnings (new ones prefixed by >>):

>> WARNING: vmlinux.o(.data+0x135420): Section mismatch in reference from the variable exynos4x12_isp_clk_driver to the function .init.text:exynos4x12_isp_clk_probe()
   The variable exynos4x12_isp_clk_driver references
   the function __init exynos4x12_isp_clk_probe()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 58542 bytes --]

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

* Re: [PATCH 3/5] clocks: exynos4x12: add runtime pm support for ISP clocks
@ 2016-09-01 21:49     ` kbuild test robot
  0 siblings, 0 replies; 68+ messages in thread
From: kbuild test robot @ 2016-09-01 21:49 UTC (permalink / raw)
  Cc: kbuild-all, linux-clk, linux-pm, linux-samsung-soc,
	linux-arm-kernel, Marek Szyprowski, Stephen Boyd,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz

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

Hi Marek,

[auto build test WARNING on clk/clk-next]
[also build test WARNING on next-20160825]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Marek-Szyprowski/Add-runtime-PM-support-for-clocks-on-Exynos-SoC-example/20160901-215042
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 5.4.0-6) 5.4.0 20160609
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm 

All warnings (new ones prefixed by >>):

>> WARNING: vmlinux.o(.data+0x135420): Section mismatch in reference from the variable exynos4x12_isp_clk_driver to the function .init.text:exynos4x12_isp_clk_probe()
   The variable exynos4x12_isp_clk_driver references
   the function __init exynos4x12_isp_clk_probe()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 58542 bytes --]

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

* [PATCH 3/5] clocks: exynos4x12: add runtime pm support for ISP clocks
@ 2016-09-01 21:49     ` kbuild test robot
  0 siblings, 0 replies; 68+ messages in thread
From: kbuild test robot @ 2016-09-01 21:49 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marek,

[auto build test WARNING on clk/clk-next]
[also build test WARNING on next-20160825]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Marek-Szyprowski/Add-runtime-PM-support-for-clocks-on-Exynos-SoC-example/20160901-215042
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 5.4.0-6) 5.4.0 20160609
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm 

All warnings (new ones prefixed by >>):

>> WARNING: vmlinux.o(.data+0x135420): Section mismatch in reference from the variable exynos4x12_isp_clk_driver to the function .init.text:exynos4x12_isp_clk_probe()
   The variable exynos4x12_isp_clk_driver references
   the function __init exynos4x12_isp_clk_probe()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/octet-stream
Size: 58542 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160902/fb16b17c/attachment-0001.obj>

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

* Re: [PATCH 5/5] clocks: exynos5433: add runtime pm support
  2016-09-01 13:45   ` Marek Szyprowski
  (?)
@ 2016-09-01 23:00     ` kbuild test robot
  -1 siblings, 0 replies; 68+ messages in thread
From: kbuild test robot @ 2016-09-01 23:00 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: kbuild-all, linux-clk, linux-pm, linux-samsung-soc,
	linux-arm-kernel, Marek Szyprowski, Stephen Boyd,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz

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

Hi Marek,

[auto build test WARNING on clk/clk-next]
[also build test WARNING on v4.8-rc4 next-20160825]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Marek-Szyprowski/Add-runtime-PM-support-for-clocks-on-Exynos-SoC-example/20160901-215042
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gnu-gcc (Debian 5.4.0-6) 5.4.0 20160609
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=sh 

All warnings (new ones prefixed by >>):

>> WARNING: drivers/built-in.o(.data+0x1546c): Section mismatch in reference from the variable exynos5433_cmu_driver to the function .init.text:irqchip_init()
   The variable exynos5433_cmu_driver references
   the function __init irqchip_init()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   
--
>> WARNING: drivers/clk/built-in.o(.data+0x31dc): Section mismatch in reference from the variable exynos5433_cmu_driver to the function .init.text:clk_ignore_unused_setup()
   The variable exynos5433_cmu_driver references
   the function __init clk_ignore_unused_setup()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   
--
>> WARNING: drivers/clk/samsung/built-in.o(.data+0x9c): Section mismatch in reference from the variable exynos5433_cmu_driver to the function .init.text:samsung_clk_init()
   The variable exynos5433_cmu_driver references
   the function __init samsung_clk_init()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 41355 bytes --]

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

* Re: [PATCH 5/5] clocks: exynos5433: add runtime pm support
@ 2016-09-01 23:00     ` kbuild test robot
  0 siblings, 0 replies; 68+ messages in thread
From: kbuild test robot @ 2016-09-01 23:00 UTC (permalink / raw)
  Cc: kbuild-all, linux-clk, linux-pm, linux-samsung-soc,
	linux-arm-kernel, Marek Szyprowski, Stephen Boyd,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz

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

Hi Marek,

[auto build test WARNING on clk/clk-next]
[also build test WARNING on v4.8-rc4 next-20160825]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Marek-Szyprowski/Add-runtime-PM-support-for-clocks-on-Exynos-SoC-example/20160901-215042
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gnu-gcc (Debian 5.4.0-6) 5.4.0 20160609
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=sh 

All warnings (new ones prefixed by >>):

>> WARNING: drivers/built-in.o(.data+0x1546c): Section mismatch in reference from the variable exynos5433_cmu_driver to the function .init.text:irqchip_init()
   The variable exynos5433_cmu_driver references
   the function __init irqchip_init()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   
--
>> WARNING: drivers/clk/built-in.o(.data+0x31dc): Section mismatch in reference from the variable exynos5433_cmu_driver to the function .init.text:clk_ignore_unused_setup()
   The variable exynos5433_cmu_driver references
   the function __init clk_ignore_unused_setup()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   
--
>> WARNING: drivers/clk/samsung/built-in.o(.data+0x9c): Section mismatch in reference from the variable exynos5433_cmu_driver to the function .init.text:samsung_clk_init()
   The variable exynos5433_cmu_driver references
   the function __init samsung_clk_init()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 41355 bytes --]

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

* [PATCH 5/5] clocks: exynos5433: add runtime pm support
@ 2016-09-01 23:00     ` kbuild test robot
  0 siblings, 0 replies; 68+ messages in thread
From: kbuild test robot @ 2016-09-01 23:00 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marek,

[auto build test WARNING on clk/clk-next]
[also build test WARNING on v4.8-rc4 next-20160825]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Marek-Szyprowski/Add-runtime-PM-support-for-clocks-on-Exynos-SoC-example/20160901-215042
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gnu-gcc (Debian 5.4.0-6) 5.4.0 20160609
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=sh 

All warnings (new ones prefixed by >>):

>> WARNING: drivers/built-in.o(.data+0x1546c): Section mismatch in reference from the variable exynos5433_cmu_driver to the function .init.text:irqchip_init()
   The variable exynos5433_cmu_driver references
   the function __init irqchip_init()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   
--
>> WARNING: drivers/clk/built-in.o(.data+0x31dc): Section mismatch in reference from the variable exynos5433_cmu_driver to the function .init.text:clk_ignore_unused_setup()
   The variable exynos5433_cmu_driver references
   the function __init clk_ignore_unused_setup()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   
--
>> WARNING: drivers/clk/samsung/built-in.o(.data+0x9c): Section mismatch in reference from the variable exynos5433_cmu_driver to the function .init.text:samsung_clk_init()
   The variable exynos5433_cmu_driver references
   the function __init samsung_clk_init()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/octet-stream
Size: 41355 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160902/a3ead47d/attachment-0001.obj>

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

* Re: [PATCH 5/5] clocks: exynos5433: add runtime pm support
  2016-09-01 13:45   ` Marek Szyprowski
  (?)
@ 2016-09-02 19:05     ` kbuild test robot
  -1 siblings, 0 replies; 68+ messages in thread
From: kbuild test robot @ 2016-09-02 19:05 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: kbuild-all, linux-clk, linux-pm, linux-samsung-soc,
	linux-arm-kernel, Marek Szyprowski, Stephen Boyd,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz

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

Hi Marek,

[auto build test WARNING on clk/clk-next]
[also build test WARNING on v4.8-rc4 next-20160825]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Marek-Szyprowski/Add-runtime-PM-support-for-clocks-on-Exynos-SoC-example/20160901-215042
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: xtensa-allmodconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 4.9.0
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=xtensa 

All warnings (new ones prefixed by >>):

>> WARNING: vmlinux.o(.data+0x1a3a38): Section mismatch in reference from the variable exynos5433_cmu_driver to the function .init.text:set_reset_devices()
   The variable exynos5433_cmu_driver references
   the function __init set_reset_devices()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 46061 bytes --]

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

* Re: [PATCH 5/5] clocks: exynos5433: add runtime pm support
@ 2016-09-02 19:05     ` kbuild test robot
  0 siblings, 0 replies; 68+ messages in thread
From: kbuild test robot @ 2016-09-02 19:05 UTC (permalink / raw)
  Cc: Ulf Hansson, linux-samsung-soc, linux-pm, Michael Turquette,
	Bartlomiej Zolnierkiewicz, Stephen Boyd, Krzysztof Kozlowski,
	Inki Dae, Chanwoo Choi, kbuild-all, Sylwester Nawrocki,
	linux-clk, linux-arm-kernel, Marek Szyprowski

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

Hi Marek,

[auto build test WARNING on clk/clk-next]
[also build test WARNING on v4.8-rc4 next-20160825]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Marek-Szyprowski/Add-runtime-PM-support-for-clocks-on-Exynos-SoC-example/20160901-215042
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: xtensa-allmodconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 4.9.0
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=xtensa 

All warnings (new ones prefixed by >>):

>> WARNING: vmlinux.o(.data+0x1a3a38): Section mismatch in reference from the variable exynos5433_cmu_driver to the function .init.text:set_reset_devices()
   The variable exynos5433_cmu_driver references
   the function __init set_reset_devices()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 46061 bytes --]

[-- Attachment #3: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 5/5] clocks: exynos5433: add runtime pm support
@ 2016-09-02 19:05     ` kbuild test robot
  0 siblings, 0 replies; 68+ messages in thread
From: kbuild test robot @ 2016-09-02 19:05 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marek,

[auto build test WARNING on clk/clk-next]
[also build test WARNING on v4.8-rc4 next-20160825]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Marek-Szyprowski/Add-runtime-PM-support-for-clocks-on-Exynos-SoC-example/20160901-215042
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: xtensa-allmodconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 4.9.0
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=xtensa 

All warnings (new ones prefixed by >>):

>> WARNING: vmlinux.o(.data+0x1a3a38): Section mismatch in reference from the variable exynos5433_cmu_driver to the function .init.text:set_reset_devices()
   The variable exynos5433_cmu_driver references
   the function __init set_reset_devices()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/octet-stream
Size: 46061 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160903/7281a9c1/attachment-0001.obj>

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

* Re: [PATCH 1/5] clk: add support for runtime pm
  2016-09-01 13:45   ` Marek Szyprowski
@ 2016-09-08  0:19     ` Stephen Boyd
  -1 siblings, 0 replies; 68+ messages in thread
From: Stephen Boyd @ 2016-09-08  0:19 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz

On 09/01, Marek Szyprowski wrote:
> Registers for some clocks might be located in the SOC area, which are under the
> power domain. To enable access to those registers respective domain has to be
> turned on. Additionally, registers for such clocks will usually loose its
> contents when power domain is turned off, so additional saving and restoring of
> them might be needed in the clock controller driver.
> 
> This patch adds basic infrastructure in the clocks core to allow implementing
> driver for such clocks under power domains. Clock provider can supply a
> struct device pointer, which is the used by clock core for tracking and managing
> clock's controller runtime pm state. Each clk_prepare() operation
> will first call pm_runtime_get_sync() on the supplied device, while
> clk_unprepare() will do pm_runtime_put() at the end.
> 
> Additional calls to pm_runtime_get/put functions are required to ensure that any
> register access (like calculating/chaning clock rates) will be done with clock
> controller in active runtime state.
> 
> Special handling of the case when runtime pm is disabled for clock controller's
> device is needed to let this feature work properly also during system sleep
> suspend/resume operations (runtime pm is first disabled before entering sleep
> state's, but controller is usually still operational until its suspend pm
> callback is called).
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

My "knee jerk" concern is that we're going to take a runtime PM
lock underneath the prepare lock. That seems like a situation
where we could hit a lock inversion if the runtime PM callbacks
themselves acquire the prepare lock by calling clk APIs? But this
concern is false right? We release the runtime PM lock before
calling the PM callback, so we shouldn't hit any deadlock and
lockdep won't complain?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH 1/5] clk: add support for runtime pm
@ 2016-09-08  0:19     ` Stephen Boyd
  0 siblings, 0 replies; 68+ messages in thread
From: Stephen Boyd @ 2016-09-08  0:19 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/01, Marek Szyprowski wrote:
> Registers for some clocks might be located in the SOC area, which are under the
> power domain. To enable access to those registers respective domain has to be
> turned on. Additionally, registers for such clocks will usually loose its
> contents when power domain is turned off, so additional saving and restoring of
> them might be needed in the clock controller driver.
> 
> This patch adds basic infrastructure in the clocks core to allow implementing
> driver for such clocks under power domains. Clock provider can supply a
> struct device pointer, which is the used by clock core for tracking and managing
> clock's controller runtime pm state. Each clk_prepare() operation
> will first call pm_runtime_get_sync() on the supplied device, while
> clk_unprepare() will do pm_runtime_put() at the end.
> 
> Additional calls to pm_runtime_get/put functions are required to ensure that any
> register access (like calculating/chaning clock rates) will be done with clock
> controller in active runtime state.
> 
> Special handling of the case when runtime pm is disabled for clock controller's
> device is needed to let this feature work properly also during system sleep
> suspend/resume operations (runtime pm is first disabled before entering sleep
> state's, but controller is usually still operational until its suspend pm
> callback is called).
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

My "knee jerk" concern is that we're going to take a runtime PM
lock underneath the prepare lock. That seems like a situation
where we could hit a lock inversion if the runtime PM callbacks
themselves acquire the prepare lock by calling clk APIs? But this
concern is false right? We release the runtime PM lock before
calling the PM callback, so we shouldn't hit any deadlock and
lockdep won't complain?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
  2016-09-01 13:45   ` Marek Szyprowski
@ 2016-09-08  0:22     ` Stephen Boyd
  -1 siblings, 0 replies; 68+ messages in thread
From: Stephen Boyd @ 2016-09-08  0:22 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz,
	devicetree, Rob Herring, Frank Rowand

On 09/01, Marek Szyprowski wrote:
> Exynos4412 clock controller contains some additional clocks for FIMC-ISP
> (Camera ISP) subsystem. Registers for those clocks are partially located
> in the SOC area, which belongs to ISP power domain.
> 
> This patch extends clock controller node with ISP clock sub-node and link
> (phandle) to ISP power domain.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>  arch/arm/boot/dts/exynos4x12.dtsi | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
> index 3394bdcf10ae..4daea67546b9 100644
> --- a/arch/arm/boot/dts/exynos4x12.dtsi
> +++ b/arch/arm/boot/dts/exynos4x12.dtsi
> @@ -74,6 +74,11 @@
>  		compatible = "samsung,exynos4412-clock";
>  		reg = <0x10030000 0x20000>;
>  		#clock-cells = <1>;
> +
> +		isp-clock-controller {
> +			compatible = "samsung,exynos4412-isp-clock";
> +			power-domains = <&pd_isp>;
> +		};

Why can't we extend support in power domains code to have
multiple domains for a single device node? i.e. power-domains =
<&pd_isp>, <&pd_foo>, <&pd_bar>, and then pick the right one with
power-domain-names or something like that? Making a subnode
(which seems to turn into a child platform device?) seems like a
quick solution for larger problems.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
@ 2016-09-08  0:22     ` Stephen Boyd
  0 siblings, 0 replies; 68+ messages in thread
From: Stephen Boyd @ 2016-09-08  0:22 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/01, Marek Szyprowski wrote:
> Exynos4412 clock controller contains some additional clocks for FIMC-ISP
> (Camera ISP) subsystem. Registers for those clocks are partially located
> in the SOC area, which belongs to ISP power domain.
> 
> This patch extends clock controller node with ISP clock sub-node and link
> (phandle) to ISP power domain.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>  arch/arm/boot/dts/exynos4x12.dtsi | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
> index 3394bdcf10ae..4daea67546b9 100644
> --- a/arch/arm/boot/dts/exynos4x12.dtsi
> +++ b/arch/arm/boot/dts/exynos4x12.dtsi
> @@ -74,6 +74,11 @@
>  		compatible = "samsung,exynos4412-clock";
>  		reg = <0x10030000 0x20000>;
>  		#clock-cells = <1>;
> +
> +		isp-clock-controller {
> +			compatible = "samsung,exynos4412-isp-clock";
> +			power-domains = <&pd_isp>;
> +		};

Why can't we extend support in power domains code to have
multiple domains for a single device node? i.e. power-domains =
<&pd_isp>, <&pd_foo>, <&pd_bar>, and then pick the right one with
power-domain-names or something like that? Making a subnode
(which seems to turn into a child platform device?) seems like a
quick solution for larger problems.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH 1/5] clk: add support for runtime pm
       [not found]     ` <CGME20160912101857eucas1p29b2bbd5ac0eda92284091ad1b86decc4@eucas1p2.samsung.com>
@ 2016-09-12 10:18         ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-12 10:18 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz

Hi Stephen,


On 2016-09-08 02:19, Stephen Boyd wrote:
> On 09/01, Marek Szyprowski wrote:
>> Registers for some clocks might be located in the SOC area, which are under the
>> power domain. To enable access to those registers respective domain has to be
>> turned on. Additionally, registers for such clocks will usually loose its
>> contents when power domain is turned off, so additional saving and restoring of
>> them might be needed in the clock controller driver.
>>
>> This patch adds basic infrastructure in the clocks core to allow implementing
>> driver for such clocks under power domains. Clock provider can supply a
>> struct device pointer, which is the used by clock core for tracking and managing
>> clock's controller runtime pm state. Each clk_prepare() operation
>> will first call pm_runtime_get_sync() on the supplied device, while
>> clk_unprepare() will do pm_runtime_put() at the end.
>>
>> Additional calls to pm_runtime_get/put functions are required to ensure that any
>> register access (like calculating/chaning clock rates) will be done with clock
>> controller in active runtime state.
>>
>> Special handling of the case when runtime pm is disabled for clock controller's
>> device is needed to let this feature work properly also during system sleep
>> suspend/resume operations (runtime pm is first disabled before entering sleep
>> state's, but controller is usually still operational until its suspend pm
>> callback is called).
>>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> My "knee jerk" concern is that we're going to take a runtime PM
> lock underneath the prepare lock. That seems like a situation
> where we could hit a lock inversion if the runtime PM callbacks
> themselves acquire the prepare lock by calling clk APIs? But this
> concern is false right? We release the runtime PM lock before
> calling the PM callback, so we shouldn't hit any deadlock and
> lockdep won't complain?

Runtime PM uses fine grained locking based on per-device locks, so there
should be no problem with global clock prepare lock. The only lock 
interaction
is between clock controller device's rpm lock and clocks global prepare 
lock, but
it always done with the same access pattern. I've tested it extensively 
(also
with lock dep) with various use cases and found no problems.

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

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

* [PATCH 1/5] clk: add support for runtime pm
@ 2016-09-12 10:18         ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-12 10:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Stephen,


On 2016-09-08 02:19, Stephen Boyd wrote:
> On 09/01, Marek Szyprowski wrote:
>> Registers for some clocks might be located in the SOC area, which are under the
>> power domain. To enable access to those registers respective domain has to be
>> turned on. Additionally, registers for such clocks will usually loose its
>> contents when power domain is turned off, so additional saving and restoring of
>> them might be needed in the clock controller driver.
>>
>> This patch adds basic infrastructure in the clocks core to allow implementing
>> driver for such clocks under power domains. Clock provider can supply a
>> struct device pointer, which is the used by clock core for tracking and managing
>> clock's controller runtime pm state. Each clk_prepare() operation
>> will first call pm_runtime_get_sync() on the supplied device, while
>> clk_unprepare() will do pm_runtime_put() at the end.
>>
>> Additional calls to pm_runtime_get/put functions are required to ensure that any
>> register access (like calculating/chaning clock rates) will be done with clock
>> controller in active runtime state.
>>
>> Special handling of the case when runtime pm is disabled for clock controller's
>> device is needed to let this feature work properly also during system sleep
>> suspend/resume operations (runtime pm is first disabled before entering sleep
>> state's, but controller is usually still operational until its suspend pm
>> callback is called).
>>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> My "knee jerk" concern is that we're going to take a runtime PM
> lock underneath the prepare lock. That seems like a situation
> where we could hit a lock inversion if the runtime PM callbacks
> themselves acquire the prepare lock by calling clk APIs? But this
> concern is false right? We release the runtime PM lock before
> calling the PM callback, so we shouldn't hit any deadlock and
> lockdep won't complain?

Runtime PM uses fine grained locking based on per-device locks, so there
should be no problem with global clock prepare lock. The only lock 
interaction
is between clock controller device's rpm lock and clocks global prepare 
lock, but
it always done with the same access pattern. I've tested it extensively 
(also
with lock dep) with various use cases and found no problems.

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

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

* Re: [PATCH 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
       [not found]     ` <CGME20160912102332eucas1p145e79669788329b44343da62dcbe50ca@eucas1p1.samsung.com>
@ 2016-09-12 10:23         ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-12 10:23 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz,
	devicetree, Rob Herring, Frank Rowand

Hi Stephen,


On 2016-09-08 02:22, Stephen Boyd wrote:
> On 09/01, Marek Szyprowski wrote:
>> Exynos4412 clock controller contains some additional clocks for FIMC-ISP
>> (Camera ISP) subsystem. Registers for those clocks are partially located
>> in the SOC area, which belongs to ISP power domain.
>>
>> This patch extends clock controller node with ISP clock sub-node and link
>> (phandle) to ISP power domain.
>>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> ---
>>   arch/arm/boot/dts/exynos4x12.dtsi | 5 +++++
>>   1 file changed, 5 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
>> index 3394bdcf10ae..4daea67546b9 100644
>> --- a/arch/arm/boot/dts/exynos4x12.dtsi
>> +++ b/arch/arm/boot/dts/exynos4x12.dtsi
>> @@ -74,6 +74,11 @@
>>   		compatible = "samsung,exynos4412-clock";
>>   		reg = <0x10030000 0x20000>;
>>   		#clock-cells = <1>;
>> +
>> +		isp-clock-controller {
>> +			compatible = "samsung,exynos4412-isp-clock";
>> +			power-domains = <&pd_isp>;
>> +		};
> Why can't we extend support in power domains code to have
> multiple domains for a single device node? i.e. power-domains =
> <&pd_isp>, <&pd_foo>, <&pd_bar>, and then pick the right one with
> power-domain-names or something like that? Making a subnode
> (which seems to turn into a child platform device?) seems like a
> quick solution for larger problems.

The larger problem here is the fact that clock controller is partially 
located
in different power areas of SoC. Majority of the clock controllers is 
located
in the area which is typically always powered (besides system sleep case),
while a few Camera ISP registers are located in the ISP block, which have
separate power domain. Having a separate nodes for sub-parts of the 
device is
rather common approach, already practices by some more complex devices.

I see some serious design problems with multiple entries in power domains
property. First how to show that some part of the device IS NOT in any 
domain?
The question is how the automated assignment to domains would be handled for
such case?

The second is related to Linux kernel internals. Right now device 
drivers are
not aware of the power domains - there are no direct calls to power domains
code, everything is hidden behind runtime pm which does all the hard work.

Similar situation is on Exynos 542x/5800, which will look more or less like
this:

         clock: clock-controller@10010000 {
              compatible = "samsung,exynos5420-clock";
              reg = <0x10010000 0x30000>;
              #clock-cells = <1>;
+
+            gsc-clock-controller {
+                 compatible = "samsung,exynos5420-gsc-clock";
+                 power-domains = <&gsc_pd>;
+            };
+
+            isp-clock-controller {
+                 compatible = "samsung,exynos5420-isp-clock";
+                 power-domains = <&isp_pd>;
+            };
+
+            mfc-clock-controller {
+                 compatible = "samsung,exynos5420-mfc-clock";
+                 power-domains = <&mfc_pd>;
+            };
+
+            msc-clock-controller {
+                 compatible = "samsung,exynos5420-msc-clock";
+                 power-domains = <&msc_pd>;
+            };
+
+            disp-clock-controller {
+                 compatible = "samsung,exynos5420-disp-clock";
+                 power-domains = <&disp_pd>;
+            };
          };

The patch is not yet ready, so I didn't include it in this patchset.

The clock controller evolved and in the latest Exynos 5433 it is divided in
several parts (each related to given hw block and its power domains), which
each is now modeled by a separate device node. This allows to bind power
domains cleanly without any need for sub-nodes for the clock controllers.

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland


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

* [PATCH 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
@ 2016-09-12 10:23         ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-12 10:23 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Stephen,


On 2016-09-08 02:22, Stephen Boyd wrote:
> On 09/01, Marek Szyprowski wrote:
>> Exynos4412 clock controller contains some additional clocks for FIMC-ISP
>> (Camera ISP) subsystem. Registers for those clocks are partially located
>> in the SOC area, which belongs to ISP power domain.
>>
>> This patch extends clock controller node with ISP clock sub-node and link
>> (phandle) to ISP power domain.
>>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> ---
>>   arch/arm/boot/dts/exynos4x12.dtsi | 5 +++++
>>   1 file changed, 5 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
>> index 3394bdcf10ae..4daea67546b9 100644
>> --- a/arch/arm/boot/dts/exynos4x12.dtsi
>> +++ b/arch/arm/boot/dts/exynos4x12.dtsi
>> @@ -74,6 +74,11 @@
>>   		compatible = "samsung,exynos4412-clock";
>>   		reg = <0x10030000 0x20000>;
>>   		#clock-cells = <1>;
>> +
>> +		isp-clock-controller {
>> +			compatible = "samsung,exynos4412-isp-clock";
>> +			power-domains = <&pd_isp>;
>> +		};
> Why can't we extend support in power domains code to have
> multiple domains for a single device node? i.e. power-domains =
> <&pd_isp>, <&pd_foo>, <&pd_bar>, and then pick the right one with
> power-domain-names or something like that? Making a subnode
> (which seems to turn into a child platform device?) seems like a
> quick solution for larger problems.

The larger problem here is the fact that clock controller is partially 
located
in different power areas of SoC. Majority of the clock controllers is 
located
in the area which is typically always powered (besides system sleep case),
while a few Camera ISP registers are located in the ISP block, which have
separate power domain. Having a separate nodes for sub-parts of the 
device is
rather common approach, already practices by some more complex devices.

I see some serious design problems with multiple entries in power domains
property. First how to show that some part of the device IS NOT in any 
domain?
The question is how the automated assignment to domains would be handled for
such case?

The second is related to Linux kernel internals. Right now device 
drivers are
not aware of the power domains - there are no direct calls to power domains
code, everything is hidden behind runtime pm which does all the hard work.

Similar situation is on Exynos 542x/5800, which will look more or less like
this:

         clock: clock-controller at 10010000 {
              compatible = "samsung,exynos5420-clock";
              reg = <0x10010000 0x30000>;
              #clock-cells = <1>;
+
+            gsc-clock-controller {
+                 compatible = "samsung,exynos5420-gsc-clock";
+                 power-domains = <&gsc_pd>;
+            };
+
+            isp-clock-controller {
+                 compatible = "samsung,exynos5420-isp-clock";
+                 power-domains = <&isp_pd>;
+            };
+
+            mfc-clock-controller {
+                 compatible = "samsung,exynos5420-mfc-clock";
+                 power-domains = <&mfc_pd>;
+            };
+
+            msc-clock-controller {
+                 compatible = "samsung,exynos5420-msc-clock";
+                 power-domains = <&msc_pd>;
+            };
+
+            disp-clock-controller {
+                 compatible = "samsung,exynos5420-disp-clock";
+                 power-domains = <&disp_pd>;
+            };
          };

The patch is not yet ready, so I didn't include it in this patchset.

The clock controller evolved and in the latest Exynos 5433 it is divided in
several parts (each related to given hw block and its power domains), which
each is now modeled by a separate device node. This allows to bind power
domains cleanly without any need for sub-nodes for the clock controllers.

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

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

* Re: [PATCH 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
  2016-09-12 10:23         ` Marek Szyprowski
@ 2016-09-12 22:28           ` Stephen Boyd
  -1 siblings, 0 replies; 68+ messages in thread
From: Stephen Boyd @ 2016-09-12 22:28 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz,
	devicetree, Rob Herring, Frank Rowand

On 09/12, Marek Szyprowski wrote:
> Hi Stephen,
> 
> 
> On 2016-09-08 02:22, Stephen Boyd wrote:
> >On 09/01, Marek Szyprowski wrote:
> >>Exynos4412 clock controller contains some additional clocks for FIMC-ISP
> >>(Camera ISP) subsystem. Registers for those clocks are partially located
> >>in the SOC area, which belongs to ISP power domain.
> >>
> >>This patch extends clock controller node with ISP clock sub-node and link
> >>(phandle) to ISP power domain.
> >>
> >>Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> >>---
> >>  arch/arm/boot/dts/exynos4x12.dtsi | 5 +++++
> >>  1 file changed, 5 insertions(+)
> >>
> >>diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
> >>index 3394bdcf10ae..4daea67546b9 100644
> >>--- a/arch/arm/boot/dts/exynos4x12.dtsi
> >>+++ b/arch/arm/boot/dts/exynos4x12.dtsi
> >>@@ -74,6 +74,11 @@
> >>  		compatible = "samsung,exynos4412-clock";
> >>  		reg = <0x10030000 0x20000>;
> >>  		#clock-cells = <1>;
> >>+
> >>+		isp-clock-controller {
> >>+			compatible = "samsung,exynos4412-isp-clock";
> >>+			power-domains = <&pd_isp>;
> >>+		};
> >Why can't we extend support in power domains code to have
> >multiple domains for a single device node? i.e. power-domains =
> ><&pd_isp>, <&pd_foo>, <&pd_bar>, and then pick the right one with
> >power-domain-names or something like that? Making a subnode
> >(which seems to turn into a child platform device?) seems like a
> >quick solution for larger problems.
> 
> The larger problem here is the fact that clock controller is
> partially located
> in different power areas of SoC. Majority of the clock controllers
> is located
> in the area which is typically always powered (besides system sleep case),
> while a few Camera ISP registers are located in the ISP block, which have
> separate power domain. Having a separate nodes for sub-parts of the
> device is
> rather common approach, already practices by some more complex devices.
> 
> I see some serious design problems with multiple entries in power domains
> property. First how to show that some part of the device IS NOT in
> any domain?

Is that even possible? Every device should be in some power
domain, even if it's just an "always on" power domain that we
don't really control from software.

> The question is how the automated assignment to domains would be handled for
> such case?

I don't get this part. Do you mean how we indicate to the driver
which power domain to use at the right time?

> 
> The second is related to Linux kernel internals. Right now device
> drivers are
> not aware of the power domains - there are no direct calls to power domains
> code, everything is hidden behind runtime pm which does all the hard work.

Right. Runtime PM will need to be improved to allow this case.

> 
> Similar situation is on Exynos 542x/5800, which will look more or less like
> this:
> 
>         clock: clock-controller@10010000 {
>              compatible = "samsung,exynos5420-clock";
>              reg = <0x10010000 0x30000>;
>              #clock-cells = <1>;
> +
> +            gsc-clock-controller {
> +                 compatible = "samsung,exynos5420-gsc-clock";
> +                 power-domains = <&gsc_pd>;
> +            };
> +
> +            isp-clock-controller {
> +                 compatible = "samsung,exynos5420-isp-clock";
> +                 power-domains = <&isp_pd>;
> +            };
> +
> +            mfc-clock-controller {
> +                 compatible = "samsung,exynos5420-mfc-clock";
> +                 power-domains = <&mfc_pd>;
> +            };
> +
> +            msc-clock-controller {
> +                 compatible = "samsung,exynos5420-msc-clock";
> +                 power-domains = <&msc_pd>;
> +            };
> +
> +            disp-clock-controller {
> +                 compatible = "samsung,exynos5420-disp-clock";
> +                 power-domains = <&disp_pd>;
> +            };
>          };
> 
> The patch is not yet ready, so I didn't include it in this patchset.

Ok. From a DT perspective the sub-nodes seem to be a workaround
for how the linux device model is mapped to power domains. I'm
not sure we want to make subnodes in the clk controller just to
make sub devices that we can target from the clk registration
path. Those sub nodes aren't devices at all. I understand why
it's being done this way, I just don't see how it fits into DT
design methodologies.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
@ 2016-09-12 22:28           ` Stephen Boyd
  0 siblings, 0 replies; 68+ messages in thread
From: Stephen Boyd @ 2016-09-12 22:28 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/12, Marek Szyprowski wrote:
> Hi Stephen,
> 
> 
> On 2016-09-08 02:22, Stephen Boyd wrote:
> >On 09/01, Marek Szyprowski wrote:
> >>Exynos4412 clock controller contains some additional clocks for FIMC-ISP
> >>(Camera ISP) subsystem. Registers for those clocks are partially located
> >>in the SOC area, which belongs to ISP power domain.
> >>
> >>This patch extends clock controller node with ISP clock sub-node and link
> >>(phandle) to ISP power domain.
> >>
> >>Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> >>---
> >>  arch/arm/boot/dts/exynos4x12.dtsi | 5 +++++
> >>  1 file changed, 5 insertions(+)
> >>
> >>diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
> >>index 3394bdcf10ae..4daea67546b9 100644
> >>--- a/arch/arm/boot/dts/exynos4x12.dtsi
> >>+++ b/arch/arm/boot/dts/exynos4x12.dtsi
> >>@@ -74,6 +74,11 @@
> >>  		compatible = "samsung,exynos4412-clock";
> >>  		reg = <0x10030000 0x20000>;
> >>  		#clock-cells = <1>;
> >>+
> >>+		isp-clock-controller {
> >>+			compatible = "samsung,exynos4412-isp-clock";
> >>+			power-domains = <&pd_isp>;
> >>+		};
> >Why can't we extend support in power domains code to have
> >multiple domains for a single device node? i.e. power-domains =
> ><&pd_isp>, <&pd_foo>, <&pd_bar>, and then pick the right one with
> >power-domain-names or something like that? Making a subnode
> >(which seems to turn into a child platform device?) seems like a
> >quick solution for larger problems.
> 
> The larger problem here is the fact that clock controller is
> partially located
> in different power areas of SoC. Majority of the clock controllers
> is located
> in the area which is typically always powered (besides system sleep case),
> while a few Camera ISP registers are located in the ISP block, which have
> separate power domain. Having a separate nodes for sub-parts of the
> device is
> rather common approach, already practices by some more complex devices.
> 
> I see some serious design problems with multiple entries in power domains
> property. First how to show that some part of the device IS NOT in
> any domain?

Is that even possible? Every device should be in some power
domain, even if it's just an "always on" power domain that we
don't really control from software.

> The question is how the automated assignment to domains would be handled for
> such case?

I don't get this part. Do you mean how we indicate to the driver
which power domain to use at the right time?

> 
> The second is related to Linux kernel internals. Right now device
> drivers are
> not aware of the power domains - there are no direct calls to power domains
> code, everything is hidden behind runtime pm which does all the hard work.

Right. Runtime PM will need to be improved to allow this case.

> 
> Similar situation is on Exynos 542x/5800, which will look more or less like
> this:
> 
>         clock: clock-controller at 10010000 {
>              compatible = "samsung,exynos5420-clock";
>              reg = <0x10010000 0x30000>;
>              #clock-cells = <1>;
> +
> +            gsc-clock-controller {
> +                 compatible = "samsung,exynos5420-gsc-clock";
> +                 power-domains = <&gsc_pd>;
> +            };
> +
> +            isp-clock-controller {
> +                 compatible = "samsung,exynos5420-isp-clock";
> +                 power-domains = <&isp_pd>;
> +            };
> +
> +            mfc-clock-controller {
> +                 compatible = "samsung,exynos5420-mfc-clock";
> +                 power-domains = <&mfc_pd>;
> +            };
> +
> +            msc-clock-controller {
> +                 compatible = "samsung,exynos5420-msc-clock";
> +                 power-domains = <&msc_pd>;
> +            };
> +
> +            disp-clock-controller {
> +                 compatible = "samsung,exynos5420-disp-clock";
> +                 power-domains = <&disp_pd>;
> +            };
>          };
> 
> The patch is not yet ready, so I didn't include it in this patchset.

Ok. From a DT perspective the sub-nodes seem to be a workaround
for how the linux device model is mapped to power domains. I'm
not sure we want to make subnodes in the clk controller just to
make sub devices that we can target from the clk registration
path. Those sub nodes aren't devices at all. I understand why
it's being done this way, I just don't see how it fits into DT
design methodologies.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH 1/5] clk: add support for runtime pm
  2016-09-12 10:18         ` Marek Szyprowski
@ 2016-09-12 22:31           ` Stephen Boyd
  -1 siblings, 0 replies; 68+ messages in thread
From: Stephen Boyd @ 2016-09-12 22:31 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz

On 09/12, Marek Szyprowski wrote:
> Hi Stephen,
> 
> 
> On 2016-09-08 02:19, Stephen Boyd wrote:
> >On 09/01, Marek Szyprowski wrote:
> >>Registers for some clocks might be located in the SOC area, which are under the
> >>power domain. To enable access to those registers respective domain has to be
> >>turned on. Additionally, registers for such clocks will usually loose its
> >>contents when power domain is turned off, so additional saving and restoring of
> >>them might be needed in the clock controller driver.
> >>
> >>This patch adds basic infrastructure in the clocks core to allow implementing
> >>driver for such clocks under power domains. Clock provider can supply a
> >>struct device pointer, which is the used by clock core for tracking and managing
> >>clock's controller runtime pm state. Each clk_prepare() operation
> >>will first call pm_runtime_get_sync() on the supplied device, while
> >>clk_unprepare() will do pm_runtime_put() at the end.
> >>
> >>Additional calls to pm_runtime_get/put functions are required to ensure that any
> >>register access (like calculating/chaning clock rates) will be done with clock
> >>controller in active runtime state.
> >>
> >>Special handling of the case when runtime pm is disabled for clock controller's
> >>device is needed to let this feature work properly also during system sleep
> >>suspend/resume operations (runtime pm is first disabled before entering sleep
> >>state's, but controller is usually still operational until its suspend pm
> >>callback is called).
> >>
> >>Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> >My "knee jerk" concern is that we're going to take a runtime PM
> >lock underneath the prepare lock. That seems like a situation
> >where we could hit a lock inversion if the runtime PM callbacks
> >themselves acquire the prepare lock by calling clk APIs? But this
> >concern is false right? We release the runtime PM lock before
> >calling the PM callback, so we shouldn't hit any deadlock and
> >lockdep won't complain?
> 
> Runtime PM uses fine grained locking based on per-device locks, so there
> should be no problem with global clock prepare lock. The only lock
> interaction
> is between clock controller device's rpm lock and clocks global
> prepare lock, but
> it always done with the same access pattern. I've tested it
> extensively (also
> with lock dep) with various use cases and found no problems.
> 

Great! So you have runtime PM callbacks that are calling
clk_prepare/unprepare?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH 1/5] clk: add support for runtime pm
@ 2016-09-12 22:31           ` Stephen Boyd
  0 siblings, 0 replies; 68+ messages in thread
From: Stephen Boyd @ 2016-09-12 22:31 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/12, Marek Szyprowski wrote:
> Hi Stephen,
> 
> 
> On 2016-09-08 02:19, Stephen Boyd wrote:
> >On 09/01, Marek Szyprowski wrote:
> >>Registers for some clocks might be located in the SOC area, which are under the
> >>power domain. To enable access to those registers respective domain has to be
> >>turned on. Additionally, registers for such clocks will usually loose its
> >>contents when power domain is turned off, so additional saving and restoring of
> >>them might be needed in the clock controller driver.
> >>
> >>This patch adds basic infrastructure in the clocks core to allow implementing
> >>driver for such clocks under power domains. Clock provider can supply a
> >>struct device pointer, which is the used by clock core for tracking and managing
> >>clock's controller runtime pm state. Each clk_prepare() operation
> >>will first call pm_runtime_get_sync() on the supplied device, while
> >>clk_unprepare() will do pm_runtime_put() at the end.
> >>
> >>Additional calls to pm_runtime_get/put functions are required to ensure that any
> >>register access (like calculating/chaning clock rates) will be done with clock
> >>controller in active runtime state.
> >>
> >>Special handling of the case when runtime pm is disabled for clock controller's
> >>device is needed to let this feature work properly also during system sleep
> >>suspend/resume operations (runtime pm is first disabled before entering sleep
> >>state's, but controller is usually still operational until its suspend pm
> >>callback is called).
> >>
> >>Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> >My "knee jerk" concern is that we're going to take a runtime PM
> >lock underneath the prepare lock. That seems like a situation
> >where we could hit a lock inversion if the runtime PM callbacks
> >themselves acquire the prepare lock by calling clk APIs? But this
> >concern is false right? We release the runtime PM lock before
> >calling the PM callback, so we shouldn't hit any deadlock and
> >lockdep won't complain?
> 
> Runtime PM uses fine grained locking based on per-device locks, so there
> should be no problem with global clock prepare lock. The only lock
> interaction
> is between clock controller device's rpm lock and clocks global
> prepare lock, but
> it always done with the same access pattern. I've tested it
> extensively (also
> with lock dep) with various use cases and found no problems.
> 

Great! So you have runtime PM callbacks that are calling
clk_prepare/unprepare?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH 1/5] clk: add support for runtime pm
  2016-09-08  0:19     ` Stephen Boyd
@ 2016-09-13  7:24       ` Ulf Hansson
  -1 siblings, 0 replies; 68+ messages in thread
From: Ulf Hansson @ 2016-09-13  7:24 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Marek Szyprowski, linux-clk, linux-pm, linux-samsung-soc,
	linux-arm-kernel, Michael Turquette, Sylwester Nawrocki,
	Chanwoo Choi, Inki Dae, Krzysztof Kozlowski,
	Bartlomiej Zolnierkiewicz

On 8 September 2016 at 02:19, Stephen Boyd <sboyd@codeaurora.org> wrote:
> On 09/01, Marek Szyprowski wrote:
>> Registers for some clocks might be located in the SOC area, which are under the
>> power domain. To enable access to those registers respective domain has to be
>> turned on. Additionally, registers for such clocks will usually loose its
>> contents when power domain is turned off, so additional saving and restoring of
>> them might be needed in the clock controller driver.
>>
>> This patch adds basic infrastructure in the clocks core to allow implementing
>> driver for such clocks under power domains. Clock provider can supply a
>> struct device pointer, which is the used by clock core for tracking and managing
>> clock's controller runtime pm state. Each clk_prepare() operation
>> will first call pm_runtime_get_sync() on the supplied device, while
>> clk_unprepare() will do pm_runtime_put() at the end.
>>
>> Additional calls to pm_runtime_get/put functions are required to ensure that any
>> register access (like calculating/chaning clock rates) will be done with clock
>> controller in active runtime state.
>>
>> Special handling of the case when runtime pm is disabled for clock controller's
>> device is needed to let this feature work properly also during system sleep
>> suspend/resume operations (runtime pm is first disabled before entering sleep
>> state's, but controller is usually still operational until its suspend pm
>> callback is called).
>>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>
> My "knee jerk" concern is that we're going to take a runtime PM
> lock underneath the prepare lock. That seems like a situation
> where we could hit a lock inversion if the runtime PM callbacks
> themselves acquire the prepare lock by calling clk APIs? But this
> concern is false right? We release the runtime PM lock before
> calling the PM callback, so we shouldn't hit any deadlock and
> lockdep won't complain?

You assumption is correct!

Before the runtime PM core invokes a runtime PM callback it will
unlock the -">dev->power.lock" spinlock. When the callback returns it
will re-lock the spinlock.

Kind regards
Uffe

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

* [PATCH 1/5] clk: add support for runtime pm
@ 2016-09-13  7:24       ` Ulf Hansson
  0 siblings, 0 replies; 68+ messages in thread
From: Ulf Hansson @ 2016-09-13  7:24 UTC (permalink / raw)
  To: linux-arm-kernel

On 8 September 2016 at 02:19, Stephen Boyd <sboyd@codeaurora.org> wrote:
> On 09/01, Marek Szyprowski wrote:
>> Registers for some clocks might be located in the SOC area, which are under the
>> power domain. To enable access to those registers respective domain has to be
>> turned on. Additionally, registers for such clocks will usually loose its
>> contents when power domain is turned off, so additional saving and restoring of
>> them might be needed in the clock controller driver.
>>
>> This patch adds basic infrastructure in the clocks core to allow implementing
>> driver for such clocks under power domains. Clock provider can supply a
>> struct device pointer, which is the used by clock core for tracking and managing
>> clock's controller runtime pm state. Each clk_prepare() operation
>> will first call pm_runtime_get_sync() on the supplied device, while
>> clk_unprepare() will do pm_runtime_put() at the end.
>>
>> Additional calls to pm_runtime_get/put functions are required to ensure that any
>> register access (like calculating/chaning clock rates) will be done with clock
>> controller in active runtime state.
>>
>> Special handling of the case when runtime pm is disabled for clock controller's
>> device is needed to let this feature work properly also during system sleep
>> suspend/resume operations (runtime pm is first disabled before entering sleep
>> state's, but controller is usually still operational until its suspend pm
>> callback is called).
>>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>
> My "knee jerk" concern is that we're going to take a runtime PM
> lock underneath the prepare lock. That seems like a situation
> where we could hit a lock inversion if the runtime PM callbacks
> themselves acquire the prepare lock by calling clk APIs? But this
> concern is false right? We release the runtime PM lock before
> calling the PM callback, so we shouldn't hit any deadlock and
> lockdep won't complain?

You assumption is correct!

Before the runtime PM core invokes a runtime PM callback it will
unlock the -">dev->power.lock" spinlock. When the callback returns it
will re-lock the spinlock.

Kind regards
Uffe

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

* Re: [PATCH 1/5] clk: add support for runtime pm
  2016-09-01 13:45   ` Marek Szyprowski
@ 2016-09-13  8:49     ` Ulf Hansson
  -1 siblings, 0 replies; 68+ messages in thread
From: Ulf Hansson @ 2016-09-13  8:49 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel,
	Stephen Boyd, Michael Turquette, Sylwester Nawrocki,
	Chanwoo Choi, Inki Dae, Krzysztof Kozlowski,
	Bartlomiej Zolnierkiewicz

On 1 September 2016 at 15:45, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> Registers for some clocks might be located in the SOC area, which are under the
> power domain. To enable access to those registers respective domain has to be
> turned on. Additionally, registers for such clocks will usually loose its
> contents when power domain is turned off, so additional saving and restoring of
> them might be needed in the clock controller driver.

This is indeed correct, I can confirm that the UX500 SoC's PRCC clock
controllers also needs to be managed like this.

>
> This patch adds basic infrastructure in the clocks core to allow implementing
> driver for such clocks under power domains. Clock provider can supply a
> struct device pointer, which is the used by clock core for tracking and managing
> clock's controller runtime pm state. Each clk_prepare() operation
> will first call pm_runtime_get_sync() on the supplied device, while
> clk_unprepare() will do pm_runtime_put() at the end.

This make sense!

>
> Additional calls to pm_runtime_get/put functions are required to ensure that any
> register access (like calculating/chaning clock rates) will be done with clock

/s/chaning/changing

> controller in active runtime state.

/s/active runtime/runtime resumed

>
> Special handling of the case when runtime pm is disabled for clock controller's
> device is needed to let this feature work properly also during system sleep
> suspend/resume operations (runtime pm is first disabled before entering sleep
> state's, but controller is usually still operational until its suspend pm
> callback is called).

This needs to be clarified. I agree we need to cover system PM as
well, but let's try be a bit more precise about it.

>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

I would also like to extend the change log to describe a little bit of
how a clk provider should interact with this new and nice feature.
Something like:

*) It needs to provide a struct device to the core when registering
the provider.
**) It needs to enable runtime PM.
***) It needs to make sure the runtime PM status of the controller
device reflects the HW state.

> ---
>  drivers/clk/clk.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 76 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 820a939fb6bb..a1934e9b4e95 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -21,6 +21,7 @@
>  #include <linux/of.h>
>  #include <linux/device.h>
>  #include <linux/init.h>
> +#include <linux/pm_runtime.h>
>  #include <linux/sched.h>
>  #include <linux/clkdev.h>
>
> @@ -46,6 +47,7 @@ struct clk_core {
>         const struct clk_ops    *ops;
>         struct clk_hw           *hw;
>         struct module           *owner;
> +       struct device           *dev;
>         struct clk_core         *parent;
>         const char              **parent_names;
>         struct clk_core         **parents;
> @@ -87,6 +89,42 @@ struct clk {
>         struct hlist_node clks_node;
>  };
>
> +/***           runtime pm          ***/
> +static int clk_pm_runtime_get(struct clk_core *core)
> +{
> +       int ret = 0;
> +
> +       if (!core->dev)
> +               return 0;
> +
> +       if (pm_runtime_enabled(core->dev)) {

Why do you need to check for this?

> +               ret = pm_runtime_get_sync(core->dev);
> +       } else {
> +               if (!pm_runtime_status_suspended(core->dev))
> +                       pm_runtime_get_noresume(core->dev);

This looks weird. I guess it's related to the system PM case somehow?

> +       }
> +       return ret < 0 ? ret : 0;
> +}
> +
> +static void clk_pm_runtime_put(struct clk_core *core)
> +{

Similar comments as for clk_pm_runtime_get().

> +       if (!core->dev)
> +               return;
> +
> +       if (pm_runtime_enabled(core->dev))
> +               pm_runtime_put(core->dev);
> +       else
> +               pm_runtime_put_noidle(core->dev);
> +}
> +
> +static bool clk_pm_runtime_suspended(struct clk_core *core)
> +{
> +       if (!core->dev)
> +               return 0;
> +
> +       return pm_runtime_suspended(core->dev);
> +}
> +
>  /***           locking             ***/
>  static void clk_prepare_lock(void)
>  {
> @@ -150,6 +188,9 @@ static void clk_enable_unlock(unsigned long flags)
>
>  static bool clk_core_is_prepared(struct clk_core *core)
>  {
> +       if (clk_pm_runtime_suspended(core))
> +               return false;
> +

This isn't safe, as even if the clock controller is runtime resumed at
this point, that's *not* a guarantee that is stays runtime resumed
while invoking the ->ops->is_prepared().

Instead you must call a pm_runtime_get_noresume() before you check the
runtime PM status, as that should avoid the device from being runtime
suspended. Then when the ->ops->is_prepared() has been invoked, we
should call pm_runtime_put().

Although, I am not sure the above change becomes entirely correct as I
think we are mixing the runtime PM status with the clock prepare
status here. In other words, the next time the clock controller
becomes runtime resumed, it may very well restore some register
context which may prepare the clock, unless someone explicitly has
unprepared it.

Of course, it all depends on how clk_core_is_prepared() is used by the
clock framework.

>         /*
>          * .is_prepared is optional for clocks that can prepare
>          * fall back to software usage counter if it is missing
> @@ -162,6 +203,9 @@ static bool clk_core_is_prepared(struct clk_core *core)
>
>  static bool clk_core_is_enabled(struct clk_core *core)
>  {
> +       if (clk_pm_runtime_suspended(core))
> +               return false;
> +

Similar comment as for clk_core_is_prepared().

>         /*
>          * .is_enabled is only mandatory for clocks that gate
>          * fall back to software usage counter if .is_enabled is missing
> @@ -489,6 +533,8 @@ static void clk_core_unprepare(struct clk_core *core)
>         if (core->ops->unprepare)
>                 core->ops->unprepare(core->hw);
>
> +       clk_pm_runtime_put(core);
> +
>         trace_clk_unprepare_complete(core);
>         clk_core_unprepare(core->parent);
>  }
> @@ -530,10 +576,14 @@ static int clk_core_prepare(struct clk_core *core)
>                 return 0;
>
>         if (core->prepare_count == 0) {
> -               ret = clk_core_prepare(core->parent);
> +               ret = clk_pm_runtime_get(core);
>                 if (ret)
>                         return ret;
>
> +               ret = clk_core_prepare(core->parent);
> +               if (ret)
> +                       goto runtime_put;
> +
>                 trace_clk_prepare(core);
>
>                 if (core->ops->prepare)
> @@ -541,15 +591,18 @@ static int clk_core_prepare(struct clk_core *core)
>
>                 trace_clk_prepare_complete(core);
>
> -               if (ret) {
> -                       clk_core_unprepare(core->parent);
> -                       return ret;
> -               }
> +               if (ret)
> +                       goto unprepare;
>         }
>
>         core->prepare_count++;
>
>         return 0;
> +unprepare:
> +       clk_core_unprepare(core->parent);
> +runtime_put:
> +       clk_pm_runtime_put(core);
> +       return ret;
>  }
>
>  static int clk_core_prepare_lock(struct clk_core *core)
> @@ -1563,6 +1616,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
>  {
>         struct clk_core *top, *fail_clk;
>         unsigned long rate = req_rate;
> +       int ret = 0;
>
>         if (!core)
>                 return 0;
> @@ -1579,21 +1633,28 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
>         if (!top)
>                 return -EINVAL;
>
> +       ret = clk_pm_runtime_get(core);
> +       if (ret)
> +               return ret;
> +
>         /* notify that we are about to change rates */
>         fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
>         if (fail_clk) {
>                 pr_debug("%s: failed to set %s rate\n", __func__,
>                                 fail_clk->name);
>                 clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
> -               return -EBUSY;
> +               ret = -EBUSY;
> +               goto err;
>         }
>
>         /* change the rates */
>         clk_change_rate(top);
>
>         core->req_rate = req_rate;
> +err:
> +       clk_pm_runtime_put(core);
>
> -       return 0;
> +       return ret;
>  }
>
>  /**
> @@ -1824,12 +1885,16 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
>                 p_rate = parent->rate;
>         }
>
> +       ret = clk_pm_runtime_get(core);
> +       if (ret)
> +               goto out;
> +
>         /* propagate PRE_RATE_CHANGE notifications */
>         ret = __clk_speculate_rates(core, p_rate);
>
>         /* abort if a driver objects */
>         if (ret & NOTIFY_STOP_MASK)
> -               goto out;
> +               goto runtime_put;
>
>         /* do the re-parent */
>         ret = __clk_set_parent(core, parent, p_index);
> @@ -1842,6 +1907,8 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
>                 __clk_recalc_accuracies(core);
>         }
>
> +runtime_put:
> +       clk_pm_runtime_put(core);
>  out:
>         clk_prepare_unlock();
>
> @@ -2546,6 +2613,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
>                 goto fail_name;
>         }
>         core->ops = hw->init->ops;
> +       core->dev = dev;
>         if (dev && dev->driver)
>                 core->owner = dev->driver->owner;
>         core->hw = hw;
> --
> 1.9.1
>

I believe we are also accessing the clock controller HW from the
late_initcall_sync(clk_disable_unused) function.

More precisely, in clk_disable_unused_subtree(), we probably need a
pm_runtime_get_sync() before calling clk_core_is_enabled(). And then
restore that with a pm_runtime_put() after the clock has been
disabled.
The similar is needed in clk_unprepare_unused_subtree().

Kind regards
Uffe

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

* [PATCH 1/5] clk: add support for runtime pm
@ 2016-09-13  8:49     ` Ulf Hansson
  0 siblings, 0 replies; 68+ messages in thread
From: Ulf Hansson @ 2016-09-13  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

On 1 September 2016 at 15:45, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> Registers for some clocks might be located in the SOC area, which are under the
> power domain. To enable access to those registers respective domain has to be
> turned on. Additionally, registers for such clocks will usually loose its
> contents when power domain is turned off, so additional saving and restoring of
> them might be needed in the clock controller driver.

This is indeed correct, I can confirm that the UX500 SoC's PRCC clock
controllers also needs to be managed like this.

>
> This patch adds basic infrastructure in the clocks core to allow implementing
> driver for such clocks under power domains. Clock provider can supply a
> struct device pointer, which is the used by clock core for tracking and managing
> clock's controller runtime pm state. Each clk_prepare() operation
> will first call pm_runtime_get_sync() on the supplied device, while
> clk_unprepare() will do pm_runtime_put() at the end.

This make sense!

>
> Additional calls to pm_runtime_get/put functions are required to ensure that any
> register access (like calculating/chaning clock rates) will be done with clock

/s/chaning/changing

> controller in active runtime state.

/s/active runtime/runtime resumed

>
> Special handling of the case when runtime pm is disabled for clock controller's
> device is needed to let this feature work properly also during system sleep
> suspend/resume operations (runtime pm is first disabled before entering sleep
> state's, but controller is usually still operational until its suspend pm
> callback is called).

This needs to be clarified. I agree we need to cover system PM as
well, but let's try be a bit more precise about it.

>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

I would also like to extend the change log to describe a little bit of
how a clk provider should interact with this new and nice feature.
Something like:

*) It needs to provide a struct device to the core when registering
the provider.
**) It needs to enable runtime PM.
***) It needs to make sure the runtime PM status of the controller
device reflects the HW state.

> ---
>  drivers/clk/clk.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 76 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 820a939fb6bb..a1934e9b4e95 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -21,6 +21,7 @@
>  #include <linux/of.h>
>  #include <linux/device.h>
>  #include <linux/init.h>
> +#include <linux/pm_runtime.h>
>  #include <linux/sched.h>
>  #include <linux/clkdev.h>
>
> @@ -46,6 +47,7 @@ struct clk_core {
>         const struct clk_ops    *ops;
>         struct clk_hw           *hw;
>         struct module           *owner;
> +       struct device           *dev;
>         struct clk_core         *parent;
>         const char              **parent_names;
>         struct clk_core         **parents;
> @@ -87,6 +89,42 @@ struct clk {
>         struct hlist_node clks_node;
>  };
>
> +/***           runtime pm          ***/
> +static int clk_pm_runtime_get(struct clk_core *core)
> +{
> +       int ret = 0;
> +
> +       if (!core->dev)
> +               return 0;
> +
> +       if (pm_runtime_enabled(core->dev)) {

Why do you need to check for this?

> +               ret = pm_runtime_get_sync(core->dev);
> +       } else {
> +               if (!pm_runtime_status_suspended(core->dev))
> +                       pm_runtime_get_noresume(core->dev);

This looks weird. I guess it's related to the system PM case somehow?

> +       }
> +       return ret < 0 ? ret : 0;
> +}
> +
> +static void clk_pm_runtime_put(struct clk_core *core)
> +{

Similar comments as for clk_pm_runtime_get().

> +       if (!core->dev)
> +               return;
> +
> +       if (pm_runtime_enabled(core->dev))
> +               pm_runtime_put(core->dev);
> +       else
> +               pm_runtime_put_noidle(core->dev);
> +}
> +
> +static bool clk_pm_runtime_suspended(struct clk_core *core)
> +{
> +       if (!core->dev)
> +               return 0;
> +
> +       return pm_runtime_suspended(core->dev);
> +}
> +
>  /***           locking             ***/
>  static void clk_prepare_lock(void)
>  {
> @@ -150,6 +188,9 @@ static void clk_enable_unlock(unsigned long flags)
>
>  static bool clk_core_is_prepared(struct clk_core *core)
>  {
> +       if (clk_pm_runtime_suspended(core))
> +               return false;
> +

This isn't safe, as even if the clock controller is runtime resumed at
this point, that's *not* a guarantee that is stays runtime resumed
while invoking the ->ops->is_prepared().

Instead you must call a pm_runtime_get_noresume() before you check the
runtime PM status, as that should avoid the device from being runtime
suspended. Then when the ->ops->is_prepared() has been invoked, we
should call pm_runtime_put().

Although, I am not sure the above change becomes entirely correct as I
think we are mixing the runtime PM status with the clock prepare
status here. In other words, the next time the clock controller
becomes runtime resumed, it may very well restore some register
context which may prepare the clock, unless someone explicitly has
unprepared it.

Of course, it all depends on how clk_core_is_prepared() is used by the
clock framework.

>         /*
>          * .is_prepared is optional for clocks that can prepare
>          * fall back to software usage counter if it is missing
> @@ -162,6 +203,9 @@ static bool clk_core_is_prepared(struct clk_core *core)
>
>  static bool clk_core_is_enabled(struct clk_core *core)
>  {
> +       if (clk_pm_runtime_suspended(core))
> +               return false;
> +

Similar comment as for clk_core_is_prepared().

>         /*
>          * .is_enabled is only mandatory for clocks that gate
>          * fall back to software usage counter if .is_enabled is missing
> @@ -489,6 +533,8 @@ static void clk_core_unprepare(struct clk_core *core)
>         if (core->ops->unprepare)
>                 core->ops->unprepare(core->hw);
>
> +       clk_pm_runtime_put(core);
> +
>         trace_clk_unprepare_complete(core);
>         clk_core_unprepare(core->parent);
>  }
> @@ -530,10 +576,14 @@ static int clk_core_prepare(struct clk_core *core)
>                 return 0;
>
>         if (core->prepare_count == 0) {
> -               ret = clk_core_prepare(core->parent);
> +               ret = clk_pm_runtime_get(core);
>                 if (ret)
>                         return ret;
>
> +               ret = clk_core_prepare(core->parent);
> +               if (ret)
> +                       goto runtime_put;
> +
>                 trace_clk_prepare(core);
>
>                 if (core->ops->prepare)
> @@ -541,15 +591,18 @@ static int clk_core_prepare(struct clk_core *core)
>
>                 trace_clk_prepare_complete(core);
>
> -               if (ret) {
> -                       clk_core_unprepare(core->parent);
> -                       return ret;
> -               }
> +               if (ret)
> +                       goto unprepare;
>         }
>
>         core->prepare_count++;
>
>         return 0;
> +unprepare:
> +       clk_core_unprepare(core->parent);
> +runtime_put:
> +       clk_pm_runtime_put(core);
> +       return ret;
>  }
>
>  static int clk_core_prepare_lock(struct clk_core *core)
> @@ -1563,6 +1616,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
>  {
>         struct clk_core *top, *fail_clk;
>         unsigned long rate = req_rate;
> +       int ret = 0;
>
>         if (!core)
>                 return 0;
> @@ -1579,21 +1633,28 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
>         if (!top)
>                 return -EINVAL;
>
> +       ret = clk_pm_runtime_get(core);
> +       if (ret)
> +               return ret;
> +
>         /* notify that we are about to change rates */
>         fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
>         if (fail_clk) {
>                 pr_debug("%s: failed to set %s rate\n", __func__,
>                                 fail_clk->name);
>                 clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
> -               return -EBUSY;
> +               ret = -EBUSY;
> +               goto err;
>         }
>
>         /* change the rates */
>         clk_change_rate(top);
>
>         core->req_rate = req_rate;
> +err:
> +       clk_pm_runtime_put(core);
>
> -       return 0;
> +       return ret;
>  }
>
>  /**
> @@ -1824,12 +1885,16 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
>                 p_rate = parent->rate;
>         }
>
> +       ret = clk_pm_runtime_get(core);
> +       if (ret)
> +               goto out;
> +
>         /* propagate PRE_RATE_CHANGE notifications */
>         ret = __clk_speculate_rates(core, p_rate);
>
>         /* abort if a driver objects */
>         if (ret & NOTIFY_STOP_MASK)
> -               goto out;
> +               goto runtime_put;
>
>         /* do the re-parent */
>         ret = __clk_set_parent(core, parent, p_index);
> @@ -1842,6 +1907,8 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
>                 __clk_recalc_accuracies(core);
>         }
>
> +runtime_put:
> +       clk_pm_runtime_put(core);
>  out:
>         clk_prepare_unlock();
>
> @@ -2546,6 +2613,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
>                 goto fail_name;
>         }
>         core->ops = hw->init->ops;
> +       core->dev = dev;
>         if (dev && dev->driver)
>                 core->owner = dev->driver->owner;
>         core->hw = hw;
> --
> 1.9.1
>

I believe we are also accessing the clock controller HW from the
late_initcall_sync(clk_disable_unused) function.

More precisely, in clk_disable_unused_subtree(), we probably need a
pm_runtime_get_sync() before calling clk_core_is_enabled(). And then
restore that with a pm_runtime_put() after the clock has been
disabled.
The similar is needed in clk_unprepare_unused_subtree().

Kind regards
Uffe

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

* Re: [PATCH 1/5] clk: add support for runtime pm
  2016-09-12 22:31           ` Stephen Boyd
@ 2016-09-13  9:07             ` Marek Szyprowski
  -1 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-13  9:07 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz

Hi Stephen,


On 2016-09-13 00:31, Stephen Boyd wrote:
> On 09/12, Marek Szyprowski wrote:
>> Hi Stephen,
>>
>>
>> On 2016-09-08 02:19, Stephen Boyd wrote:
>>> On 09/01, Marek Szyprowski wrote:
>>>> Registers for some clocks might be located in the SOC area, which are under the
>>>> power domain. To enable access to those registers respective domain has to be
>>>> turned on. Additionally, registers for such clocks will usually loose its
>>>> contents when power domain is turned off, so additional saving and restoring of
>>>> them might be needed in the clock controller driver.
>>>>
>>>> This patch adds basic infrastructure in the clocks core to allow implementing
>>>> driver for such clocks under power domains. Clock provider can supply a
>>>> struct device pointer, which is the used by clock core for tracking and managing
>>>> clock's controller runtime pm state. Each clk_prepare() operation
>>>> will first call pm_runtime_get_sync() on the supplied device, while
>>>> clk_unprepare() will do pm_runtime_put() at the end.
>>>>
>>>> Additional calls to pm_runtime_get/put functions are required to ensure that any
>>>> register access (like calculating/chaning clock rates) will be done with clock
>>>> controller in active runtime state.
>>>>
>>>> Special handling of the case when runtime pm is disabled for clock controller's
>>>> device is needed to let this feature work properly also during system sleep
>>>> suspend/resume operations (runtime pm is first disabled before entering sleep
>>>> state's, but controller is usually still operational until its suspend pm
>>>> callback is called).
>>>>
>>>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>>> My "knee jerk" concern is that we're going to take a runtime PM
>>> lock underneath the prepare lock. That seems like a situation
>>> where we could hit a lock inversion if the runtime PM callbacks
>>> themselves acquire the prepare lock by calling clk APIs? But this
>>> concern is false right? We release the runtime PM lock before
>>> calling the PM callback, so we shouldn't hit any deadlock and
>>> lockdep won't complain?
>> Runtime PM uses fine grained locking based on per-device locks, so there
>> should be no problem with global clock prepare lock. The only lock
>> interaction
>> is between clock controller device's rpm lock and clocks global
>> prepare lock, but
>> it always done with the same access pattern. I've tested it
>> extensively (also
>> with lock dep) with various use cases and found no problems.
>>
> Great! So you have runtime PM callbacks that are calling
> clk_prepare/unprepare?

Well, not really. clock controller's runtime pm functions must not call
clk_prepare/unprepare yet.

I didn't get your question. I thought that you are asking if my change
won't introduce any deadlock related to prepare and dev->pm locks. My
runtime pm functions doesn't do any call to clk_prepare/unprepare.
Although global clock prepare lock is re-entrant from the same process, it
would cause deadlock if called from runtime pm functions, because runtime
pm functions might be called from the worker running on the different
cpu/process.

I hope that the work started by Krzysztof Kozlowski on splitting prepare
lock on per-controller basis will solve limitation and one would be able
to call clk_prapare/unprepare on clocks from other controllers even from
the runtime pm functions.

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

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

* [PATCH 1/5] clk: add support for runtime pm
@ 2016-09-13  9:07             ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-13  9:07 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Stephen,


On 2016-09-13 00:31, Stephen Boyd wrote:
> On 09/12, Marek Szyprowski wrote:
>> Hi Stephen,
>>
>>
>> On 2016-09-08 02:19, Stephen Boyd wrote:
>>> On 09/01, Marek Szyprowski wrote:
>>>> Registers for some clocks might be located in the SOC area, which are under the
>>>> power domain. To enable access to those registers respective domain has to be
>>>> turned on. Additionally, registers for such clocks will usually loose its
>>>> contents when power domain is turned off, so additional saving and restoring of
>>>> them might be needed in the clock controller driver.
>>>>
>>>> This patch adds basic infrastructure in the clocks core to allow implementing
>>>> driver for such clocks under power domains. Clock provider can supply a
>>>> struct device pointer, which is the used by clock core for tracking and managing
>>>> clock's controller runtime pm state. Each clk_prepare() operation
>>>> will first call pm_runtime_get_sync() on the supplied device, while
>>>> clk_unprepare() will do pm_runtime_put() at the end.
>>>>
>>>> Additional calls to pm_runtime_get/put functions are required to ensure that any
>>>> register access (like calculating/chaning clock rates) will be done with clock
>>>> controller in active runtime state.
>>>>
>>>> Special handling of the case when runtime pm is disabled for clock controller's
>>>> device is needed to let this feature work properly also during system sleep
>>>> suspend/resume operations (runtime pm is first disabled before entering sleep
>>>> state's, but controller is usually still operational until its suspend pm
>>>> callback is called).
>>>>
>>>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>>> My "knee jerk" concern is that we're going to take a runtime PM
>>> lock underneath the prepare lock. That seems like a situation
>>> where we could hit a lock inversion if the runtime PM callbacks
>>> themselves acquire the prepare lock by calling clk APIs? But this
>>> concern is false right? We release the runtime PM lock before
>>> calling the PM callback, so we shouldn't hit any deadlock and
>>> lockdep won't complain?
>> Runtime PM uses fine grained locking based on per-device locks, so there
>> should be no problem with global clock prepare lock. The only lock
>> interaction
>> is between clock controller device's rpm lock and clocks global
>> prepare lock, but
>> it always done with the same access pattern. I've tested it
>> extensively (also
>> with lock dep) with various use cases and found no problems.
>>
> Great! So you have runtime PM callbacks that are calling
> clk_prepare/unprepare?

Well, not really. clock controller's runtime pm functions must not call
clk_prepare/unprepare yet.

I didn't get your question. I thought that you are asking if my change
won't introduce any deadlock related to prepare and dev->pm locks. My
runtime pm functions doesn't do any call to clk_prepare/unprepare.
Although global clock prepare lock is re-entrant from the same process, it
would cause deadlock if called from runtime pm functions, because runtime
pm functions might be called from the worker running on the different
cpu/process.

I hope that the work started by Krzysztof Kozlowski on splitting prepare
lock on per-controller basis will solve limitation and one would be able
to call clk_prapare/unprepare on clocks from other controllers even from
the runtime pm functions.

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

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

* Re: [PATCH 1/5] clk: add support for runtime pm
  2016-09-13  8:49     ` Ulf Hansson
@ 2016-09-13 13:13       ` Marek Szyprowski
  -1 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-13 13:13 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel,
	Stephen Boyd, Michael Turquette, Sylwester Nawrocki,
	Chanwoo Choi, Inki Dae, Krzysztof Kozlowski,
	Bartlomiej Zolnierkiewicz

Hi Ulf,

Thanks for looking into this patch!

On 2016-09-13 10:49, Ulf Hansson wrote:
> On 1 September 2016 at 15:45, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
>> Registers for some clocks might be located in the SOC area, which are under the
>> power domain. To enable access to those registers respective domain has to be
>> turned on. Additionally, registers for such clocks will usually loose its
>> contents when power domain is turned off, so additional saving and restoring of
>> them might be needed in the clock controller driver.
> This is indeed correct, I can confirm that the UX500 SoC's PRCC clock
> controllers also needs to be managed like this.
>
>> This patch adds basic infrastructure in the clocks core to allow implementing
>> driver for such clocks under power domains. Clock provider can supply a
>> struct device pointer, which is the used by clock core for tracking and managing
>> clock's controller runtime pm state. Each clk_prepare() operation
>> will first call pm_runtime_get_sync() on the supplied device, while
>> clk_unprepare() will do pm_runtime_put() at the end.
> This make sense!
>
>> Additional calls to pm_runtime_get/put functions are required to ensure that any
>> register access (like calculating/chaning clock rates) will be done with clock
> /s/chaning/changing
>
>> controller in active runtime state.
> /s/active runtime/runtime resumed
>
>> Special handling of the case when runtime pm is disabled for clock controller's
>> device is needed to let this feature work properly also during system sleep
>> suspend/resume operations (runtime pm is first disabled before entering sleep
>> state's, but controller is usually still operational until its suspend pm
>> callback is called).
> This needs to be clarified. I agree we need to cover system PM as
> well, but let's try be a bit more precise about it.

Right, I wasn't precise here. I've developed this code on older (v4.1 
and v4.6)
kernels, which had a code which disables runtime pm during system sleep 
transition
time. Maybe I need to revisit it and consider your change merged to 
v4.8-rc1, which
keeps runtime pm enabled during system sleep transitions.

>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> I would also like to extend the change log to describe a little bit of
> how a clk provider should interact with this new and nice feature.
> Something like:
>
> *) It needs to provide a struct device to the core when registering
> the provider.
> **) It needs to enable runtime PM.
> ***) It needs to make sure the runtime PM status of the controller
> device reflects the HW state.

Right, this definitely has to be added. Thank you for reminding about 
such obvious
things.

>> ---
>>   drivers/clk/clk.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++------
>>   1 file changed, 76 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
>> index 820a939fb6bb..a1934e9b4e95 100644
>> --- a/drivers/clk/clk.c
>> +++ b/drivers/clk/clk.c
>> @@ -21,6 +21,7 @@
>>   #include <linux/of.h>
>>   #include <linux/device.h>
>>   #include <linux/init.h>
>> +#include <linux/pm_runtime.h>
>>   #include <linux/sched.h>
>>   #include <linux/clkdev.h>
>>
>> @@ -46,6 +47,7 @@ struct clk_core {
>>          const struct clk_ops    *ops;
>>          struct clk_hw           *hw;
>>          struct module           *owner;
>> +       struct device           *dev;
>>          struct clk_core         *parent;
>>          const char              **parent_names;
>>          struct clk_core         **parents;
>> @@ -87,6 +89,42 @@ struct clk {
>>          struct hlist_node clks_node;
>>   };
>>
>> +/***           runtime pm          ***/
>> +static int clk_pm_runtime_get(struct clk_core *core)
>> +{
>> +       int ret = 0;
>> +
>> +       if (!core->dev)
>> +               return 0;
>> +
>> +       if (pm_runtime_enabled(core->dev)) {
> Why do you need to check for this?

This was a workaround, which let it work during the system sleep transition
state.

>
>> +               ret = pm_runtime_get_sync(core->dev);
>> +       } else {
>> +               if (!pm_runtime_status_suspended(core->dev))
>> +                       pm_runtime_get_noresume(core->dev);
> This looks weird. I guess it's related to the system PM case somehow?
>
>> +       }
>> +       return ret < 0 ? ret : 0;
>> +}
>> +
>> +static void clk_pm_runtime_put(struct clk_core *core)
>> +{
> Similar comments as for clk_pm_runtime_get().
>
>> +       if (!core->dev)
>> +               return;
>> +
>> +       if (pm_runtime_enabled(core->dev))
>> +               pm_runtime_put(core->dev);
>> +       else
>> +               pm_runtime_put_noidle(core->dev);
>> +}
>> +
>> +static bool clk_pm_runtime_suspended(struct clk_core *core)
>> +{
>> +       if (!core->dev)
>> +               return 0;
>> +
>> +       return pm_runtime_suspended(core->dev);
>> +}
>> +
>>   /***           locking             ***/
>>   static void clk_prepare_lock(void)
>>   {
>> @@ -150,6 +188,9 @@ static void clk_enable_unlock(unsigned long flags)
>>
>>   static bool clk_core_is_prepared(struct clk_core *core)
>>   {
>> +       if (clk_pm_runtime_suspended(core))
>> +               return false;
>> +
> This isn't safe, as even if the clock controller is runtime resumed at
> this point, that's *not* a guarantee that is stays runtime resumed
> while invoking the ->ops->is_prepared().
>
> Instead you must call a pm_runtime_get_noresume() before you check the
> runtime PM status, as that should avoid the device from being runtime
> suspended. Then when the ->ops->is_prepared() has been invoked, we
> should call pm_runtime_put().
>
> Although, I am not sure the above change becomes entirely correct as I
> think we are mixing the runtime PM status with the clock prepare
> status here. In other words, the next time the clock controller
> becomes runtime resumed, it may very well restore some register
> context which may prepare the clock, unless someone explicitly has
> unprepared it.
>
> Of course, it all depends on how clk_core_is_prepared() is used by the
> clock framework.

clk_core_is_prepared() is mainly used by disable_unused_tree_*. You are
right that it mixes a bit clock prepared state with runtime pm active
state of clock controller's, but I assumed here that clock cannot be
prepared if runtime pm state of controller is suspended. Other approach
here would be to call pm_runtime_get(), check status and then
pm_runtime_put(). If you prefer such approach, I will change it.

>
>>          /*
>>           * .is_prepared is optional for clocks that can prepare
>>           * fall back to software usage counter if it is missing
>> @@ -162,6 +203,9 @@ static bool clk_core_is_prepared(struct clk_core *core)
>>
>>   static bool clk_core_is_enabled(struct clk_core *core)
>>   {
>> +       if (clk_pm_runtime_suspended(core))
>> +               return false;
>> +
> Similar comment as for clk_core_is_prepared().
>
>>          /*
>>           * .is_enabled is only mandatory for clocks that gate
>>           * fall back to software usage counter if .is_enabled is missing
>> @@ -489,6 +533,8 @@ static void clk_core_unprepare(struct clk_core *core)
>>          if (core->ops->unprepare)
>>                  core->ops->unprepare(core->hw);
>>
>> +       clk_pm_runtime_put(core);
>> +
>>          trace_clk_unprepare_complete(core);
>>          clk_core_unprepare(core->parent);
>>   }
>> @@ -530,10 +576,14 @@ static int clk_core_prepare(struct clk_core *core)
>>                  return 0;
>>
>>          if (core->prepare_count == 0) {
>> -               ret = clk_core_prepare(core->parent);
>> +               ret = clk_pm_runtime_get(core);
>>                  if (ret)
>>                          return ret;
>>
>> +               ret = clk_core_prepare(core->parent);
>> +               if (ret)
>> +                       goto runtime_put;
>> +
>>                  trace_clk_prepare(core);
>>
>>                  if (core->ops->prepare)
>> @@ -541,15 +591,18 @@ static int clk_core_prepare(struct clk_core *core)
>>
>>                  trace_clk_prepare_complete(core);
>>
>> -               if (ret) {
>> -                       clk_core_unprepare(core->parent);
>> -                       return ret;
>> -               }
>> +               if (ret)
>> +                       goto unprepare;
>>          }
>>
>>          core->prepare_count++;
>>
>>          return 0;
>> +unprepare:
>> +       clk_core_unprepare(core->parent);
>> +runtime_put:
>> +       clk_pm_runtime_put(core);
>> +       return ret;
>>   }
>>
>>   static int clk_core_prepare_lock(struct clk_core *core)
>> @@ -1563,6 +1616,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
>>   {
>>          struct clk_core *top, *fail_clk;
>>          unsigned long rate = req_rate;
>> +       int ret = 0;
>>
>>          if (!core)
>>                  return 0;
>> @@ -1579,21 +1633,28 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
>>          if (!top)
>>                  return -EINVAL;
>>
>> +       ret = clk_pm_runtime_get(core);
>> +       if (ret)
>> +               return ret;
>> +
>>          /* notify that we are about to change rates */
>>          fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
>>          if (fail_clk) {
>>                  pr_debug("%s: failed to set %s rate\n", __func__,
>>                                  fail_clk->name);
>>                  clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
>> -               return -EBUSY;
>> +               ret = -EBUSY;
>> +               goto err;
>>          }
>>
>>          /* change the rates */
>>          clk_change_rate(top);
>>
>>          core->req_rate = req_rate;
>> +err:
>> +       clk_pm_runtime_put(core);
>>
>> -       return 0;
>> +       return ret;
>>   }
>>
>>   /**
>> @@ -1824,12 +1885,16 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
>>                  p_rate = parent->rate;
>>          }
>>
>> +       ret = clk_pm_runtime_get(core);
>> +       if (ret)
>> +               goto out;
>> +
>>          /* propagate PRE_RATE_CHANGE notifications */
>>          ret = __clk_speculate_rates(core, p_rate);
>>
>>          /* abort if a driver objects */
>>          if (ret & NOTIFY_STOP_MASK)
>> -               goto out;
>> +               goto runtime_put;
>>
>>          /* do the re-parent */
>>          ret = __clk_set_parent(core, parent, p_index);
>> @@ -1842,6 +1907,8 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
>>                  __clk_recalc_accuracies(core);
>>          }
>>
>> +runtime_put:
>> +       clk_pm_runtime_put(core);
>>   out:
>>          clk_prepare_unlock();
>>
>> @@ -2546,6 +2613,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
>>                  goto fail_name;
>>          }
>>          core->ops = hw->init->ops;
>> +       core->dev = dev;
>>          if (dev && dev->driver)
>>                  core->owner = dev->driver->owner;
>>          core->hw = hw;
>> --
>> 1.9.1
>>
> I believe we are also accessing the clock controller HW from the
> late_initcall_sync(clk_disable_unused) function.

This was indirectly handled by the runtime pm state check in is_prepared
and is_enabled().

> More precisely, in clk_disable_unused_subtree(), we probably need a
> pm_runtime_get_sync() before calling clk_core_is_enabled(). And then
> restore that with a pm_runtime_put() after the clock has been
> disabled.
> The similar is needed in clk_unprepare_unused_subtree().

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

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

* [PATCH 1/5] clk: add support for runtime pm
@ 2016-09-13 13:13       ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-13 13:13 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ulf,

Thanks for looking into this patch!

On 2016-09-13 10:49, Ulf Hansson wrote:
> On 1 September 2016 at 15:45, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
>> Registers for some clocks might be located in the SOC area, which are under the
>> power domain. To enable access to those registers respective domain has to be
>> turned on. Additionally, registers for such clocks will usually loose its
>> contents when power domain is turned off, so additional saving and restoring of
>> them might be needed in the clock controller driver.
> This is indeed correct, I can confirm that the UX500 SoC's PRCC clock
> controllers also needs to be managed like this.
>
>> This patch adds basic infrastructure in the clocks core to allow implementing
>> driver for such clocks under power domains. Clock provider can supply a
>> struct device pointer, which is the used by clock core for tracking and managing
>> clock's controller runtime pm state. Each clk_prepare() operation
>> will first call pm_runtime_get_sync() on the supplied device, while
>> clk_unprepare() will do pm_runtime_put() at the end.
> This make sense!
>
>> Additional calls to pm_runtime_get/put functions are required to ensure that any
>> register access (like calculating/chaning clock rates) will be done with clock
> /s/chaning/changing
>
>> controller in active runtime state.
> /s/active runtime/runtime resumed
>
>> Special handling of the case when runtime pm is disabled for clock controller's
>> device is needed to let this feature work properly also during system sleep
>> suspend/resume operations (runtime pm is first disabled before entering sleep
>> state's, but controller is usually still operational until its suspend pm
>> callback is called).
> This needs to be clarified. I agree we need to cover system PM as
> well, but let's try be a bit more precise about it.

Right, I wasn't precise here. I've developed this code on older (v4.1 
and v4.6)
kernels, which had a code which disables runtime pm during system sleep 
transition
time. Maybe I need to revisit it and consider your change merged to 
v4.8-rc1, which
keeps runtime pm enabled during system sleep transitions.

>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> I would also like to extend the change log to describe a little bit of
> how a clk provider should interact with this new and nice feature.
> Something like:
>
> *) It needs to provide a struct device to the core when registering
> the provider.
> **) It needs to enable runtime PM.
> ***) It needs to make sure the runtime PM status of the controller
> device reflects the HW state.

Right, this definitely has to be added. Thank you for reminding about 
such obvious
things.

>> ---
>>   drivers/clk/clk.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++------
>>   1 file changed, 76 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
>> index 820a939fb6bb..a1934e9b4e95 100644
>> --- a/drivers/clk/clk.c
>> +++ b/drivers/clk/clk.c
>> @@ -21,6 +21,7 @@
>>   #include <linux/of.h>
>>   #include <linux/device.h>
>>   #include <linux/init.h>
>> +#include <linux/pm_runtime.h>
>>   #include <linux/sched.h>
>>   #include <linux/clkdev.h>
>>
>> @@ -46,6 +47,7 @@ struct clk_core {
>>          const struct clk_ops    *ops;
>>          struct clk_hw           *hw;
>>          struct module           *owner;
>> +       struct device           *dev;
>>          struct clk_core         *parent;
>>          const char              **parent_names;
>>          struct clk_core         **parents;
>> @@ -87,6 +89,42 @@ struct clk {
>>          struct hlist_node clks_node;
>>   };
>>
>> +/***           runtime pm          ***/
>> +static int clk_pm_runtime_get(struct clk_core *core)
>> +{
>> +       int ret = 0;
>> +
>> +       if (!core->dev)
>> +               return 0;
>> +
>> +       if (pm_runtime_enabled(core->dev)) {
> Why do you need to check for this?

This was a workaround, which let it work during the system sleep transition
state.

>
>> +               ret = pm_runtime_get_sync(core->dev);
>> +       } else {
>> +               if (!pm_runtime_status_suspended(core->dev))
>> +                       pm_runtime_get_noresume(core->dev);
> This looks weird. I guess it's related to the system PM case somehow?
>
>> +       }
>> +       return ret < 0 ? ret : 0;
>> +}
>> +
>> +static void clk_pm_runtime_put(struct clk_core *core)
>> +{
> Similar comments as for clk_pm_runtime_get().
>
>> +       if (!core->dev)
>> +               return;
>> +
>> +       if (pm_runtime_enabled(core->dev))
>> +               pm_runtime_put(core->dev);
>> +       else
>> +               pm_runtime_put_noidle(core->dev);
>> +}
>> +
>> +static bool clk_pm_runtime_suspended(struct clk_core *core)
>> +{
>> +       if (!core->dev)
>> +               return 0;
>> +
>> +       return pm_runtime_suspended(core->dev);
>> +}
>> +
>>   /***           locking             ***/
>>   static void clk_prepare_lock(void)
>>   {
>> @@ -150,6 +188,9 @@ static void clk_enable_unlock(unsigned long flags)
>>
>>   static bool clk_core_is_prepared(struct clk_core *core)
>>   {
>> +       if (clk_pm_runtime_suspended(core))
>> +               return false;
>> +
> This isn't safe, as even if the clock controller is runtime resumed at
> this point, that's *not* a guarantee that is stays runtime resumed
> while invoking the ->ops->is_prepared().
>
> Instead you must call a pm_runtime_get_noresume() before you check the
> runtime PM status, as that should avoid the device from being runtime
> suspended. Then when the ->ops->is_prepared() has been invoked, we
> should call pm_runtime_put().
>
> Although, I am not sure the above change becomes entirely correct as I
> think we are mixing the runtime PM status with the clock prepare
> status here. In other words, the next time the clock controller
> becomes runtime resumed, it may very well restore some register
> context which may prepare the clock, unless someone explicitly has
> unprepared it.
>
> Of course, it all depends on how clk_core_is_prepared() is used by the
> clock framework.

clk_core_is_prepared() is mainly used by disable_unused_tree_*. You are
right that it mixes a bit clock prepared state with runtime pm active
state of clock controller's, but I assumed here that clock cannot be
prepared if runtime pm state of controller is suspended. Other approach
here would be to call pm_runtime_get(), check status and then
pm_runtime_put(). If you prefer such approach, I will change it.

>
>>          /*
>>           * .is_prepared is optional for clocks that can prepare
>>           * fall back to software usage counter if it is missing
>> @@ -162,6 +203,9 @@ static bool clk_core_is_prepared(struct clk_core *core)
>>
>>   static bool clk_core_is_enabled(struct clk_core *core)
>>   {
>> +       if (clk_pm_runtime_suspended(core))
>> +               return false;
>> +
> Similar comment as for clk_core_is_prepared().
>
>>          /*
>>           * .is_enabled is only mandatory for clocks that gate
>>           * fall back to software usage counter if .is_enabled is missing
>> @@ -489,6 +533,8 @@ static void clk_core_unprepare(struct clk_core *core)
>>          if (core->ops->unprepare)
>>                  core->ops->unprepare(core->hw);
>>
>> +       clk_pm_runtime_put(core);
>> +
>>          trace_clk_unprepare_complete(core);
>>          clk_core_unprepare(core->parent);
>>   }
>> @@ -530,10 +576,14 @@ static int clk_core_prepare(struct clk_core *core)
>>                  return 0;
>>
>>          if (core->prepare_count == 0) {
>> -               ret = clk_core_prepare(core->parent);
>> +               ret = clk_pm_runtime_get(core);
>>                  if (ret)
>>                          return ret;
>>
>> +               ret = clk_core_prepare(core->parent);
>> +               if (ret)
>> +                       goto runtime_put;
>> +
>>                  trace_clk_prepare(core);
>>
>>                  if (core->ops->prepare)
>> @@ -541,15 +591,18 @@ static int clk_core_prepare(struct clk_core *core)
>>
>>                  trace_clk_prepare_complete(core);
>>
>> -               if (ret) {
>> -                       clk_core_unprepare(core->parent);
>> -                       return ret;
>> -               }
>> +               if (ret)
>> +                       goto unprepare;
>>          }
>>
>>          core->prepare_count++;
>>
>>          return 0;
>> +unprepare:
>> +       clk_core_unprepare(core->parent);
>> +runtime_put:
>> +       clk_pm_runtime_put(core);
>> +       return ret;
>>   }
>>
>>   static int clk_core_prepare_lock(struct clk_core *core)
>> @@ -1563,6 +1616,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
>>   {
>>          struct clk_core *top, *fail_clk;
>>          unsigned long rate = req_rate;
>> +       int ret = 0;
>>
>>          if (!core)
>>                  return 0;
>> @@ -1579,21 +1633,28 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
>>          if (!top)
>>                  return -EINVAL;
>>
>> +       ret = clk_pm_runtime_get(core);
>> +       if (ret)
>> +               return ret;
>> +
>>          /* notify that we are about to change rates */
>>          fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
>>          if (fail_clk) {
>>                  pr_debug("%s: failed to set %s rate\n", __func__,
>>                                  fail_clk->name);
>>                  clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
>> -               return -EBUSY;
>> +               ret = -EBUSY;
>> +               goto err;
>>          }
>>
>>          /* change the rates */
>>          clk_change_rate(top);
>>
>>          core->req_rate = req_rate;
>> +err:
>> +       clk_pm_runtime_put(core);
>>
>> -       return 0;
>> +       return ret;
>>   }
>>
>>   /**
>> @@ -1824,12 +1885,16 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
>>                  p_rate = parent->rate;
>>          }
>>
>> +       ret = clk_pm_runtime_get(core);
>> +       if (ret)
>> +               goto out;
>> +
>>          /* propagate PRE_RATE_CHANGE notifications */
>>          ret = __clk_speculate_rates(core, p_rate);
>>
>>          /* abort if a driver objects */
>>          if (ret & NOTIFY_STOP_MASK)
>> -               goto out;
>> +               goto runtime_put;
>>
>>          /* do the re-parent */
>>          ret = __clk_set_parent(core, parent, p_index);
>> @@ -1842,6 +1907,8 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
>>                  __clk_recalc_accuracies(core);
>>          }
>>
>> +runtime_put:
>> +       clk_pm_runtime_put(core);
>>   out:
>>          clk_prepare_unlock();
>>
>> @@ -2546,6 +2613,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
>>                  goto fail_name;
>>          }
>>          core->ops = hw->init->ops;
>> +       core->dev = dev;
>>          if (dev && dev->driver)
>>                  core->owner = dev->driver->owner;
>>          core->hw = hw;
>> --
>> 1.9.1
>>
> I believe we are also accessing the clock controller HW from the
> late_initcall_sync(clk_disable_unused) function.

This was indirectly handled by the runtime pm state check in is_prepared
and is_enabled().

> More precisely, in clk_disable_unused_subtree(), we probably need a
> pm_runtime_get_sync() before calling clk_core_is_enabled(). And then
> restore that with a pm_runtime_put() after the clock has been
> disabled.
> The similar is needed in clk_unprepare_unused_subtree().

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

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

* Re: [PATCH 1/5] clk: add support for runtime pm
  2016-09-13 13:13       ` Marek Szyprowski
@ 2016-09-13 15:03         ` Ulf Hansson
  -1 siblings, 0 replies; 68+ messages in thread
From: Ulf Hansson @ 2016-09-13 15:03 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel,
	Stephen Boyd, Michael Turquette, Sylwester Nawrocki,
	Chanwoo Choi, Inki Dae, Krzysztof Kozlowski,
	Bartlomiej Zolnierkiewicz

[...]

>>
>> This needs to be clarified. I agree we need to cover system PM as
>> well, but let's try be a bit more precise about it.
>
>
> Right, I wasn't precise here. I've developed this code on older (v4.1 and
> v4.6)
> kernels, which had a code which disables runtime pm during system sleep
> transition
> time. Maybe I need to revisit it and consider your change merged to
> v4.8-rc1, which
> keeps runtime pm enabled during system sleep transitions.

Right, I see.

>>>   static bool clk_core_is_prepared(struct clk_core *core)
>>>   {
>>> +       if (clk_pm_runtime_suspended(core))
>>> +               return false;
>>> +
>>
>> This isn't safe, as even if the clock controller is runtime resumed at
>> this point, that's *not* a guarantee that is stays runtime resumed
>> while invoking the ->ops->is_prepared().
>>
>> Instead you must call a pm_runtime_get_noresume() before you check the
>> runtime PM status, as that should avoid the device from being runtime
>> suspended. Then when the ->ops->is_prepared() has been invoked, we
>> should call pm_runtime_put().
>>
>> Although, I am not sure the above change becomes entirely correct as I
>> think we are mixing the runtime PM status with the clock prepare
>> status here. In other words, the next time the clock controller
>> becomes runtime resumed, it may very well restore some register
>> context which may prepare the clock, unless someone explicitly has
>> unprepared it.
>>
>> Of course, it all depends on how clk_core_is_prepared() is used by the
>> clock framework.
>
>
> clk_core_is_prepared() is mainly used by disable_unused_tree_*. You are
> right that it mixes a bit clock prepared state with runtime pm active
> state of clock controller's, but I assumed here that clock cannot be
> prepared if runtime pm state of controller is suspended. Other approach
> here would be to call pm_runtime_get(), check status and then
> pm_runtime_put(). If you prefer such approach, I will change it.

Using pm_runtime_get|put() would work for the clk_core_is_prepared()
case, although perhaps not for the clk_core_is_enabled() case.

The reason is that I guess the clk_core_is_enabled() API may be called
from atomic context? Thus we would need to enable
pm_runtime_irq_safe() for the clock provider device, which I *really*
would like to avoid.

[...]

>>
>> I believe we are also accessing the clock controller HW from the
>> late_initcall_sync(clk_disable_unused) function.
>
>
> This was indirectly handled by the runtime pm state check in is_prepared
> and is_enabled().

I see.

Although, I was thinking that you explicitly would like to
disable/unprepare unused clocks in this phase, so then it isn't
sufficient to rely on the runtime PM status to know whether the clock
is prepared/enabled.

Perhaps, this is the only case when you actually need a
pm_runtime_get|put() around the ->is_enabled|prepared()!?

>
>> More precisely, in clk_disable_unused_subtree(), we probably need a
>> pm_runtime_get_sync() before calling clk_core_is_enabled(). And then
>> restore that with a pm_runtime_put() after the clock has been
>> disabled.
>> The similar is needed in clk_unprepare_unused_subtree().
>
>
> Best regards
> --
> Marek Szyprowski, PhD
> Samsung R&D Institute Poland
>

Kind regards
Uffe

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

* [PATCH 1/5] clk: add support for runtime pm
@ 2016-09-13 15:03         ` Ulf Hansson
  0 siblings, 0 replies; 68+ messages in thread
From: Ulf Hansson @ 2016-09-13 15:03 UTC (permalink / raw)
  To: linux-arm-kernel

[...]

>>
>> This needs to be clarified. I agree we need to cover system PM as
>> well, but let's try be a bit more precise about it.
>
>
> Right, I wasn't precise here. I've developed this code on older (v4.1 and
> v4.6)
> kernels, which had a code which disables runtime pm during system sleep
> transition
> time. Maybe I need to revisit it and consider your change merged to
> v4.8-rc1, which
> keeps runtime pm enabled during system sleep transitions.

Right, I see.

>>>   static bool clk_core_is_prepared(struct clk_core *core)
>>>   {
>>> +       if (clk_pm_runtime_suspended(core))
>>> +               return false;
>>> +
>>
>> This isn't safe, as even if the clock controller is runtime resumed at
>> this point, that's *not* a guarantee that is stays runtime resumed
>> while invoking the ->ops->is_prepared().
>>
>> Instead you must call a pm_runtime_get_noresume() before you check the
>> runtime PM status, as that should avoid the device from being runtime
>> suspended. Then when the ->ops->is_prepared() has been invoked, we
>> should call pm_runtime_put().
>>
>> Although, I am not sure the above change becomes entirely correct as I
>> think we are mixing the runtime PM status with the clock prepare
>> status here. In other words, the next time the clock controller
>> becomes runtime resumed, it may very well restore some register
>> context which may prepare the clock, unless someone explicitly has
>> unprepared it.
>>
>> Of course, it all depends on how clk_core_is_prepared() is used by the
>> clock framework.
>
>
> clk_core_is_prepared() is mainly used by disable_unused_tree_*. You are
> right that it mixes a bit clock prepared state with runtime pm active
> state of clock controller's, but I assumed here that clock cannot be
> prepared if runtime pm state of controller is suspended. Other approach
> here would be to call pm_runtime_get(), check status and then
> pm_runtime_put(). If you prefer such approach, I will change it.

Using pm_runtime_get|put() would work for the clk_core_is_prepared()
case, although perhaps not for the clk_core_is_enabled() case.

The reason is that I guess the clk_core_is_enabled() API may be called
from atomic context? Thus we would need to enable
pm_runtime_irq_safe() for the clock provider device, which I *really*
would like to avoid.

[...]

>>
>> I believe we are also accessing the clock controller HW from the
>> late_initcall_sync(clk_disable_unused) function.
>
>
> This was indirectly handled by the runtime pm state check in is_prepared
> and is_enabled().

I see.

Although, I was thinking that you explicitly would like to
disable/unprepare unused clocks in this phase, so then it isn't
sufficient to rely on the runtime PM status to know whether the clock
is prepared/enabled.

Perhaps, this is the only case when you actually need a
pm_runtime_get|put() around the ->is_enabled|prepared()!?

>
>> More precisely, in clk_disable_unused_subtree(), we probably need a
>> pm_runtime_get_sync() before calling clk_core_is_enabled(). And then
>> restore that with a pm_runtime_put() after the clock has been
>> disabled.
>> The similar is needed in clk_unprepare_unused_subtree().
>
>
> Best regards
> --
> Marek Szyprowski, PhD
> Samsung R&D Institute Poland
>

Kind regards
Uffe

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

* Re: [PATCH 1/5] clk: add support for runtime pm
  2016-09-13 15:03         ` Ulf Hansson
@ 2016-09-14 10:11           ` Marek Szyprowski
  -1 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-14 10:11 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel,
	Stephen Boyd, Michael Turquette, Sylwester Nawrocki,
	Chanwoo Choi, Inki Dae, Krzysztof Kozlowski,
	Bartlomiej Zolnierkiewicz

Hi Ulf,


On 2016-09-13 17:03, Ulf Hansson wrote:
> [...]
>
>>> This needs to be clarified. I agree we need to cover system PM as
>>> well, but let's try be a bit more precise about it.
>>
>> Right, I wasn't precise here. I've developed this code on older (v4.1 and
>> v4.6)
>> kernels, which had a code which disables runtime pm during system sleep
>> transition
>> time. Maybe I need to revisit it and consider your change merged to
>> v4.8-rc1, which
>> keeps runtime pm enabled during system sleep transitions.
> Right, I see.
>
>>>>    static bool clk_core_is_prepared(struct clk_core *core)
>>>>    {
>>>> +       if (clk_pm_runtime_suspended(core))
>>>> +               return false;
>>>> +
>>> This isn't safe, as even if the clock controller is runtime resumed at
>>> this point, that's *not* a guarantee that is stays runtime resumed
>>> while invoking the ->ops->is_prepared().
>>>
>>> Instead you must call a pm_runtime_get_noresume() before you check the
>>> runtime PM status, as that should avoid the device from being runtime
>>> suspended. Then when the ->ops->is_prepared() has been invoked, we
>>> should call pm_runtime_put().
>>>
>>> Although, I am not sure the above change becomes entirely correct as I
>>> think we are mixing the runtime PM status with the clock prepare
>>> status here. In other words, the next time the clock controller
>>> becomes runtime resumed, it may very well restore some register
>>> context which may prepare the clock, unless someone explicitly has
>>> unprepared it.
>>>
>>> Of course, it all depends on how clk_core_is_prepared() is used by the
>>> clock framework.
>>
>> clk_core_is_prepared() is mainly used by disable_unused_tree_*. You are
>> right that it mixes a bit clock prepared state with runtime pm active
>> state of clock controller's, but I assumed here that clock cannot be
>> prepared if runtime pm state of controller is suspended. Other approach
>> here would be to call pm_runtime_get(), check status and then
>> pm_runtime_put(). If you prefer such approach, I will change it.
> Using pm_runtime_get|put() would work for the clk_core_is_prepared()
> case, although perhaps not for the clk_core_is_enabled() case.
>
> The reason is that I guess the clk_core_is_enabled() API may be called
> from atomic context? Thus we would need to enable
> pm_runtime_irq_safe() for the clock provider device, which I *really*
> would like to avoid.

I've checked clk_core_is_enabled() is only used for implementing disabling
of unused clock trees or implementing ->is_enabled() callback, which is used
for the same purpose, so it should be safe to use standard 
pm_runtime_get/put
there.

There should be no other usecases for ->is_enabled() method, as it itself is
not really race prone, as other caller might enable/disable given clock in
meantime.

I will remove clk_pm_runtime_suspended() usage then.

> [...]
>
>>> I believe we are also accessing the clock controller HW from the
>>> late_initcall_sync(clk_disable_unused) function.
>>
>> This was indirectly handled by the runtime pm state check in is_prepared
>> and is_enabled().
> I see.
>
> Although, I was thinking that you explicitly would like to
> disable/unprepare unused clocks in this phase, so then it isn't
> sufficient to rely on the runtime PM status to know whether the clock
> is prepared/enabled.
>
> Perhaps, this is the only case when you actually need a
> pm_runtime_get|put() around the ->is_enabled|prepared()!?

Right.

[...]

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

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

* [PATCH 1/5] clk: add support for runtime pm
@ 2016-09-14 10:11           ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-14 10:11 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ulf,


On 2016-09-13 17:03, Ulf Hansson wrote:
> [...]
>
>>> This needs to be clarified. I agree we need to cover system PM as
>>> well, but let's try be a bit more precise about it.
>>
>> Right, I wasn't precise here. I've developed this code on older (v4.1 and
>> v4.6)
>> kernels, which had a code which disables runtime pm during system sleep
>> transition
>> time. Maybe I need to revisit it and consider your change merged to
>> v4.8-rc1, which
>> keeps runtime pm enabled during system sleep transitions.
> Right, I see.
>
>>>>    static bool clk_core_is_prepared(struct clk_core *core)
>>>>    {
>>>> +       if (clk_pm_runtime_suspended(core))
>>>> +               return false;
>>>> +
>>> This isn't safe, as even if the clock controller is runtime resumed at
>>> this point, that's *not* a guarantee that is stays runtime resumed
>>> while invoking the ->ops->is_prepared().
>>>
>>> Instead you must call a pm_runtime_get_noresume() before you check the
>>> runtime PM status, as that should avoid the device from being runtime
>>> suspended. Then when the ->ops->is_prepared() has been invoked, we
>>> should call pm_runtime_put().
>>>
>>> Although, I am not sure the above change becomes entirely correct as I
>>> think we are mixing the runtime PM status with the clock prepare
>>> status here. In other words, the next time the clock controller
>>> becomes runtime resumed, it may very well restore some register
>>> context which may prepare the clock, unless someone explicitly has
>>> unprepared it.
>>>
>>> Of course, it all depends on how clk_core_is_prepared() is used by the
>>> clock framework.
>>
>> clk_core_is_prepared() is mainly used by disable_unused_tree_*. You are
>> right that it mixes a bit clock prepared state with runtime pm active
>> state of clock controller's, but I assumed here that clock cannot be
>> prepared if runtime pm state of controller is suspended. Other approach
>> here would be to call pm_runtime_get(), check status and then
>> pm_runtime_put(). If you prefer such approach, I will change it.
> Using pm_runtime_get|put() would work for the clk_core_is_prepared()
> case, although perhaps not for the clk_core_is_enabled() case.
>
> The reason is that I guess the clk_core_is_enabled() API may be called
> from atomic context? Thus we would need to enable
> pm_runtime_irq_safe() for the clock provider device, which I *really*
> would like to avoid.

I've checked clk_core_is_enabled() is only used for implementing disabling
of unused clock trees or implementing ->is_enabled() callback, which is used
for the same purpose, so it should be safe to use standard 
pm_runtime_get/put
there.

There should be no other usecases for ->is_enabled() method, as it itself is
not really race prone, as other caller might enable/disable given clock in
meantime.

I will remove clk_pm_runtime_suspended() usage then.

> [...]
>
>>> I believe we are also accessing the clock controller HW from the
>>> late_initcall_sync(clk_disable_unused) function.
>>
>> This was indirectly handled by the runtime pm state check in is_prepared
>> and is_enabled().
> I see.
>
> Although, I was thinking that you explicitly would like to
> disable/unprepare unused clocks in this phase, so then it isn't
> sufficient to rely on the runtime PM status to know whether the clock
> is prepared/enabled.
>
> Perhaps, this is the only case when you actually need a
> pm_runtime_get|put() around the ->is_enabled|prepared()!?

Right.

[...]

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

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

* Re: [PATCH 1/5] clk: add support for runtime pm
  2016-09-13  9:07             ` Marek Szyprowski
@ 2016-09-14 21:39               ` Stephen Boyd
  -1 siblings, 0 replies; 68+ messages in thread
From: Stephen Boyd @ 2016-09-14 21:39 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz

On 09/13, Marek Szyprowski wrote:
> On 2016-09-13 00:31, Stephen Boyd wrote:
> >
> >Great! So you have runtime PM callbacks that are calling
> >clk_prepare/unprepare?
> 
> Well, not really. clock controller's runtime pm functions must not call
> clk_prepare/unprepare yet.
> 
> I didn't get your question. I thought that you are asking if my change
> won't introduce any deadlock related to prepare and dev->pm locks. My
> runtime pm functions doesn't do any call to clk_prepare/unprepare.
> Although global clock prepare lock is re-entrant from the same process, it
> would cause deadlock if called from runtime pm functions, because runtime
> pm functions might be called from the worker running on the different
> cpu/process.

I mean non-clk controller driver based runtime PM callbacks that
call clk_prepare/unprepare in them. For example, some i2c or spi
device driver that has clk operations in the runtime PM
callbacks. That would allow lockdep to see any potential deadlock
because of aliasing lock classes for the device power lock and
the global prepare lock.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH 1/5] clk: add support for runtime pm
@ 2016-09-14 21:39               ` Stephen Boyd
  0 siblings, 0 replies; 68+ messages in thread
From: Stephen Boyd @ 2016-09-14 21:39 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/13, Marek Szyprowski wrote:
> On 2016-09-13 00:31, Stephen Boyd wrote:
> >
> >Great! So you have runtime PM callbacks that are calling
> >clk_prepare/unprepare?
> 
> Well, not really. clock controller's runtime pm functions must not call
> clk_prepare/unprepare yet.
> 
> I didn't get your question. I thought that you are asking if my change
> won't introduce any deadlock related to prepare and dev->pm locks. My
> runtime pm functions doesn't do any call to clk_prepare/unprepare.
> Although global clock prepare lock is re-entrant from the same process, it
> would cause deadlock if called from runtime pm functions, because runtime
> pm functions might be called from the worker running on the different
> cpu/process.

I mean non-clk controller driver based runtime PM callbacks that
call clk_prepare/unprepare in them. For example, some i2c or spi
device driver that has clk operations in the runtime PM
callbacks. That would allow lockdep to see any potential deadlock
because of aliasing lock classes for the device power lock and
the global prepare lock.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH 1/5] clk: add support for runtime pm
  2016-09-14 21:39               ` Stephen Boyd
@ 2016-09-15  8:32                 ` Marek Szyprowski
  -1 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-15  8:32 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz

Hi Stephen,


On 2016-09-14 23:39, Stephen Boyd wrote:
> On 09/13, Marek Szyprowski wrote:
>> On 2016-09-13 00:31, Stephen Boyd wrote:
>>> Great! So you have runtime PM callbacks that are calling
>>> clk_prepare/unprepare?
>> Well, not really. clock controller's runtime pm functions must not call
>> clk_prepare/unprepare yet.
>>
>> I didn't get your question. I thought that you are asking if my change
>> won't introduce any deadlock related to prepare and dev->pm locks. My
>> runtime pm functions doesn't do any call to clk_prepare/unprepare.
>> Although global clock prepare lock is re-entrant from the same process, it
>> would cause deadlock if called from runtime pm functions, because runtime
>> pm functions might be called from the worker running on the different
>> cpu/process.
> I mean non-clk controller driver based runtime PM callbacks that
> call clk_prepare/unprepare in them. For example, some i2c or spi
> device driver that has clk operations in the runtime PM
> callbacks. That would allow lockdep to see any potential deadlock
> because of aliasing lock classes for the device power lock and
> the global prepare lock.

This works perfectly fine. Runtime pm callbacks are called with power lock
released, so there is no deadlock possible related to dev->power.lock.
See __rpm_callback() function in drivers/base/power/runtime.c

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

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

* [PATCH 1/5] clk: add support for runtime pm
@ 2016-09-15  8:32                 ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-15  8:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Stephen,


On 2016-09-14 23:39, Stephen Boyd wrote:
> On 09/13, Marek Szyprowski wrote:
>> On 2016-09-13 00:31, Stephen Boyd wrote:
>>> Great! So you have runtime PM callbacks that are calling
>>> clk_prepare/unprepare?
>> Well, not really. clock controller's runtime pm functions must not call
>> clk_prepare/unprepare yet.
>>
>> I didn't get your question. I thought that you are asking if my change
>> won't introduce any deadlock related to prepare and dev->pm locks. My
>> runtime pm functions doesn't do any call to clk_prepare/unprepare.
>> Although global clock prepare lock is re-entrant from the same process, it
>> would cause deadlock if called from runtime pm functions, because runtime
>> pm functions might be called from the worker running on the different
>> cpu/process.
> I mean non-clk controller driver based runtime PM callbacks that
> call clk_prepare/unprepare in them. For example, some i2c or spi
> device driver that has clk operations in the runtime PM
> callbacks. That would allow lockdep to see any potential deadlock
> because of aliasing lock classes for the device power lock and
> the global prepare lock.

This works perfectly fine. Runtime pm callbacks are called with power lock
released, so there is no deadlock possible related to dev->power.lock.
See __rpm_callback() function in drivers/base/power/runtime.c

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

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

* Re: [PATCH 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
  2016-09-12 22:28           ` Stephen Boyd
  (?)
@ 2016-09-15 12:06               ` Marek Szyprowski
  -1 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-15 12:06 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Frank Rowand

Hi Stephen,

On 2016-09-13 00:28, Stephen Boyd wrote:
> On 09/12, Marek Szyprowski wrote:
>> On 2016-09-08 02:22, Stephen Boyd wrote:
>>> On 09/01, Marek Szyprowski wrote:
>>>> Exynos4412 clock controller contains some additional clocks for FIMC-ISP
>>>> (Camera ISP) subsystem. Registers for those clocks are partially located
>>>> in the SOC area, which belongs to ISP power domain.
>>>>
>>>> This patch extends clock controller node with ISP clock sub-node and link
>>>> (phandle) to ISP power domain.
>>>>
>>>> Signed-off-by: Marek Szyprowski <m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>>>> ---
>>>>   arch/arm/boot/dts/exynos4x12.dtsi | 5 +++++
>>>>   1 file changed, 5 insertions(+)
>>>>
>>>> diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
>>>> index 3394bdcf10ae..4daea67546b9 100644
>>>> --- a/arch/arm/boot/dts/exynos4x12.dtsi
>>>> +++ b/arch/arm/boot/dts/exynos4x12.dtsi
>>>> @@ -74,6 +74,11 @@
>>>>   		compatible = "samsung,exynos4412-clock";
>>>>   		reg = <0x10030000 0x20000>;
>>>>   		#clock-cells = <1>;
>>>> +
>>>> +		isp-clock-controller {
>>>> +			compatible = "samsung,exynos4412-isp-clock";
>>>> +			power-domains = <&pd_isp>;
>>>> +		};
>>> Why can't we extend support in power domains code to have
>>> multiple domains for a single device node? i.e. power-domains =
>>> <&pd_isp>, <&pd_foo>, <&pd_bar>, and then pick the right one with
>>> power-domain-names or something like that? Making a subnode
>>> (which seems to turn into a child platform device?) seems like a
>>> quick solution for larger problems.
>> The larger problem here is the fact that clock controller is
>> partially located
>> in different power areas of SoC. Majority of the clock controllers
>> is located
>> in the area which is typically always powered (besides system sleep case),
>> while a few Camera ISP registers are located in the ISP block, which have
>> separate power domain. Having a separate nodes for sub-parts of the
>> device is
>> rather common approach, already practices by some more complex devices.
>>
>> I see some serious design problems with multiple entries in power domains
>> property. First how to show that some part of the device IS NOT in
>> any domain?
> Is that even possible? Every device should be in some power
> domain, even if it's just an "always on" power domain that we
> don't really control from software.

Right now none dts of which I'm aware of doesn't define the power domain for
the parts of the SoC, which are always on and doesn't need any additional
management.

>
>> The question is how the automated assignment to domains would be handled for
>> such case?
> I don't get this part. Do you mean how we indicate to the driver
> which power domain to use at the right time?

This was about Linux device core, which assigns device to its power domain
and ensures that the power domain is in right state during device probe and
then during device operation. Currently core supports only one domain per
device, so the question was which domain to chose if there are more than
one listed.

>
>> The second is related to Linux kernel internals. Right now device
>> drivers are
>> not aware of the power domains - there are no direct calls to power domains
>> code, everything is hidden behind runtime pm which does all the hard work.
> Right. Runtime PM will need to be improved to allow this case.
>
>> Similar situation is on Exynos 542x/5800, which will look more or less like
>> this:
>>
>>          clock: clock-controller@10010000 {
>>               compatible = "samsung,exynos5420-clock";
>>               reg = <0x10010000 0x30000>;
>>               #clock-cells = <1>;
>> +
>> +            gsc-clock-controller {
>> +                 compatible = "samsung,exynos5420-gsc-clock";
>> +                 power-domains = <&gsc_pd>;
>> +            };
>> +
>> +            isp-clock-controller {
>> +                 compatible = "samsung,exynos5420-isp-clock";
>> +                 power-domains = <&isp_pd>;
>> +            };
>> +
>> +            mfc-clock-controller {
>> +                 compatible = "samsung,exynos5420-mfc-clock";
>> +                 power-domains = <&mfc_pd>;
>> +            };
>> +
>> +            msc-clock-controller {
>> +                 compatible = "samsung,exynos5420-msc-clock";
>> +                 power-domains = <&msc_pd>;
>> +            };
>> +
>> +            disp-clock-controller {
>> +                 compatible = "samsung,exynos5420-disp-clock";
>> +                 power-domains = <&disp_pd>;
>> +            };
>>           };
>>
>> The patch is not yet ready, so I didn't include it in this patchset.
> Ok. From a DT perspective the sub-nodes seem to be a workaround
> for how the linux device model is mapped to power domains. I'm
> not sure we want to make subnodes in the clk controller just to
> make sub devices that we can target from the clk registration
> path. Those sub nodes aren't devices at all. I understand why
> it's being done this way, I just don't see how it fits into DT
> design methodologies.

I don't think that using sub-nodes for describing details of the given
hardware block is something uncommon in DT. Please check pin control
or PMICs (especially regulator providers). Same for various "port"
sub-nodes often used by various video/display devices and bridges.

The above presented method describes well which sub-part of clock
controller is placed in which power domain.

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

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

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

* Re: [PATCH 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
@ 2016-09-15 12:06               ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-15 12:06 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel,
	Michael Turquette, Ulf Hansson, Sylwester Nawrocki, Chanwoo Choi,
	Inki Dae, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz,
	devicetree, Rob Herring, Frank Rowand

Hi Stephen,

On 2016-09-13 00:28, Stephen Boyd wrote:
> On 09/12, Marek Szyprowski wrote:
>> On 2016-09-08 02:22, Stephen Boyd wrote:
>>> On 09/01, Marek Szyprowski wrote:
>>>> Exynos4412 clock controller contains some additional clocks for FIMC-ISP
>>>> (Camera ISP) subsystem. Registers for those clocks are partially located
>>>> in the SOC area, which belongs to ISP power domain.
>>>>
>>>> This patch extends clock controller node with ISP clock sub-node and link
>>>> (phandle) to ISP power domain.
>>>>
>>>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>>>> ---
>>>>   arch/arm/boot/dts/exynos4x12.dtsi | 5 +++++
>>>>   1 file changed, 5 insertions(+)
>>>>
>>>> diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
>>>> index 3394bdcf10ae..4daea67546b9 100644
>>>> --- a/arch/arm/boot/dts/exynos4x12.dtsi
>>>> +++ b/arch/arm/boot/dts/exynos4x12.dtsi
>>>> @@ -74,6 +74,11 @@
>>>>   		compatible = "samsung,exynos4412-clock";
>>>>   		reg = <0x10030000 0x20000>;
>>>>   		#clock-cells = <1>;
>>>> +
>>>> +		isp-clock-controller {
>>>> +			compatible = "samsung,exynos4412-isp-clock";
>>>> +			power-domains = <&pd_isp>;
>>>> +		};
>>> Why can't we extend support in power domains code to have
>>> multiple domains for a single device node? i.e. power-domains =
>>> <&pd_isp>, <&pd_foo>, <&pd_bar>, and then pick the right one with
>>> power-domain-names or something like that? Making a subnode
>>> (which seems to turn into a child platform device?) seems like a
>>> quick solution for larger problems.
>> The larger problem here is the fact that clock controller is
>> partially located
>> in different power areas of SoC. Majority of the clock controllers
>> is located
>> in the area which is typically always powered (besides system sleep case),
>> while a few Camera ISP registers are located in the ISP block, which have
>> separate power domain. Having a separate nodes for sub-parts of the
>> device is
>> rather common approach, already practices by some more complex devices.
>>
>> I see some serious design problems with multiple entries in power domains
>> property. First how to show that some part of the device IS NOT in
>> any domain?
> Is that even possible? Every device should be in some power
> domain, even if it's just an "always on" power domain that we
> don't really control from software.

Right now none dts of which I'm aware of doesn't define the power domain for
the parts of the SoC, which are always on and doesn't need any additional
management.

>
>> The question is how the automated assignment to domains would be handled for
>> such case?
> I don't get this part. Do you mean how we indicate to the driver
> which power domain to use at the right time?

This was about Linux device core, which assigns device to its power domain
and ensures that the power domain is in right state during device probe and
then during device operation. Currently core supports only one domain per
device, so the question was which domain to chose if there are more than
one listed.

>
>> The second is related to Linux kernel internals. Right now device
>> drivers are
>> not aware of the power domains - there are no direct calls to power domains
>> code, everything is hidden behind runtime pm which does all the hard work.
> Right. Runtime PM will need to be improved to allow this case.
>
>> Similar situation is on Exynos 542x/5800, which will look more or less like
>> this:
>>
>>          clock: clock-controller@10010000 {
>>               compatible = "samsung,exynos5420-clock";
>>               reg = <0x10010000 0x30000>;
>>               #clock-cells = <1>;
>> +
>> +            gsc-clock-controller {
>> +                 compatible = "samsung,exynos5420-gsc-clock";
>> +                 power-domains = <&gsc_pd>;
>> +            };
>> +
>> +            isp-clock-controller {
>> +                 compatible = "samsung,exynos5420-isp-clock";
>> +                 power-domains = <&isp_pd>;
>> +            };
>> +
>> +            mfc-clock-controller {
>> +                 compatible = "samsung,exynos5420-mfc-clock";
>> +                 power-domains = <&mfc_pd>;
>> +            };
>> +
>> +            msc-clock-controller {
>> +                 compatible = "samsung,exynos5420-msc-clock";
>> +                 power-domains = <&msc_pd>;
>> +            };
>> +
>> +            disp-clock-controller {
>> +                 compatible = "samsung,exynos5420-disp-clock";
>> +                 power-domains = <&disp_pd>;
>> +            };
>>           };
>>
>> The patch is not yet ready, so I didn't include it in this patchset.
> Ok. From a DT perspective the sub-nodes seem to be a workaround
> for how the linux device model is mapped to power domains. I'm
> not sure we want to make subnodes in the clk controller just to
> make sub devices that we can target from the clk registration
> path. Those sub nodes aren't devices at all. I understand why
> it's being done this way, I just don't see how it fits into DT
> design methodologies.

I don't think that using sub-nodes for describing details of the given
hardware block is something uncommon in DT. Please check pin control
or PMICs (especially regulator providers). Same for various "port"
sub-nodes often used by various video/display devices and bridges.

The above presented method describes well which sub-part of clock
controller is placed in which power domain.

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

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

* [PATCH 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
@ 2016-09-15 12:06               ` Marek Szyprowski
  0 siblings, 0 replies; 68+ messages in thread
From: Marek Szyprowski @ 2016-09-15 12:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Stephen,

On 2016-09-13 00:28, Stephen Boyd wrote:
> On 09/12, Marek Szyprowski wrote:
>> On 2016-09-08 02:22, Stephen Boyd wrote:
>>> On 09/01, Marek Szyprowski wrote:
>>>> Exynos4412 clock controller contains some additional clocks for FIMC-ISP
>>>> (Camera ISP) subsystem. Registers for those clocks are partially located
>>>> in the SOC area, which belongs to ISP power domain.
>>>>
>>>> This patch extends clock controller node with ISP clock sub-node and link
>>>> (phandle) to ISP power domain.
>>>>
>>>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>>>> ---
>>>>   arch/arm/boot/dts/exynos4x12.dtsi | 5 +++++
>>>>   1 file changed, 5 insertions(+)
>>>>
>>>> diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
>>>> index 3394bdcf10ae..4daea67546b9 100644
>>>> --- a/arch/arm/boot/dts/exynos4x12.dtsi
>>>> +++ b/arch/arm/boot/dts/exynos4x12.dtsi
>>>> @@ -74,6 +74,11 @@
>>>>   		compatible = "samsung,exynos4412-clock";
>>>>   		reg = <0x10030000 0x20000>;
>>>>   		#clock-cells = <1>;
>>>> +
>>>> +		isp-clock-controller {
>>>> +			compatible = "samsung,exynos4412-isp-clock";
>>>> +			power-domains = <&pd_isp>;
>>>> +		};
>>> Why can't we extend support in power domains code to have
>>> multiple domains for a single device node? i.e. power-domains =
>>> <&pd_isp>, <&pd_foo>, <&pd_bar>, and then pick the right one with
>>> power-domain-names or something like that? Making a subnode
>>> (which seems to turn into a child platform device?) seems like a
>>> quick solution for larger problems.
>> The larger problem here is the fact that clock controller is
>> partially located
>> in different power areas of SoC. Majority of the clock controllers
>> is located
>> in the area which is typically always powered (besides system sleep case),
>> while a few Camera ISP registers are located in the ISP block, which have
>> separate power domain. Having a separate nodes for sub-parts of the
>> device is
>> rather common approach, already practices by some more complex devices.
>>
>> I see some serious design problems with multiple entries in power domains
>> property. First how to show that some part of the device IS NOT in
>> any domain?
> Is that even possible? Every device should be in some power
> domain, even if it's just an "always on" power domain that we
> don't really control from software.

Right now none dts of which I'm aware of doesn't define the power domain for
the parts of the SoC, which are always on and doesn't need any additional
management.

>
>> The question is how the automated assignment to domains would be handled for
>> such case?
> I don't get this part. Do you mean how we indicate to the driver
> which power domain to use at the right time?

This was about Linux device core, which assigns device to its power domain
and ensures that the power domain is in right state during device probe and
then during device operation. Currently core supports only one domain per
device, so the question was which domain to chose if there are more than
one listed.

>
>> The second is related to Linux kernel internals. Right now device
>> drivers are
>> not aware of the power domains - there are no direct calls to power domains
>> code, everything is hidden behind runtime pm which does all the hard work.
> Right. Runtime PM will need to be improved to allow this case.
>
>> Similar situation is on Exynos 542x/5800, which will look more or less like
>> this:
>>
>>          clock: clock-controller at 10010000 {
>>               compatible = "samsung,exynos5420-clock";
>>               reg = <0x10010000 0x30000>;
>>               #clock-cells = <1>;
>> +
>> +            gsc-clock-controller {
>> +                 compatible = "samsung,exynos5420-gsc-clock";
>> +                 power-domains = <&gsc_pd>;
>> +            };
>> +
>> +            isp-clock-controller {
>> +                 compatible = "samsung,exynos5420-isp-clock";
>> +                 power-domains = <&isp_pd>;
>> +            };
>> +
>> +            mfc-clock-controller {
>> +                 compatible = "samsung,exynos5420-mfc-clock";
>> +                 power-domains = <&mfc_pd>;
>> +            };
>> +
>> +            msc-clock-controller {
>> +                 compatible = "samsung,exynos5420-msc-clock";
>> +                 power-domains = <&msc_pd>;
>> +            };
>> +
>> +            disp-clock-controller {
>> +                 compatible = "samsung,exynos5420-disp-clock";
>> +                 power-domains = <&disp_pd>;
>> +            };
>>           };
>>
>> The patch is not yet ready, so I didn't include it in this patchset.
> Ok. From a DT perspective the sub-nodes seem to be a workaround
> for how the linux device model is mapped to power domains. I'm
> not sure we want to make subnodes in the clk controller just to
> make sub devices that we can target from the clk registration
> path. Those sub nodes aren't devices at all. I understand why
> it's being done this way, I just don't see how it fits into DT
> design methodologies.

I don't think that using sub-nodes for describing details of the given
hardware block is something uncommon in DT. Please check pin control
or PMICs (especially regulator providers). Same for various "port"
sub-nodes often used by various video/display devices and bridges.

The above presented method describes well which sub-part of clock
controller is placed in which power domain.

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

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

* Re: [PATCH 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
  2016-09-15 12:06               ` Marek Szyprowski
@ 2016-09-15 14:13                 ` Ulf Hansson
  -1 siblings, 0 replies; 68+ messages in thread
From: Ulf Hansson @ 2016-09-15 14:13 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: Stephen Boyd, linux-clk, linux-pm, linux-samsung-soc,
	linux-arm-kernel, Michael Turquette, Sylwester Nawrocki,
	Chanwoo Choi, Inki Dae, Krzysztof Kozlowski,
	Bartlomiej Zolnierkiewicz, devicetree, Rob Herring, Frank Rowand

[...]

>>> I see some serious design problems with multiple entries in power domains
>>> property. First how to show that some part of the device IS NOT in
>>> any domain?
>>
>> Is that even possible? Every device should be in some power
>> domain, even if it's just an "always on" power domain that we
>> don't really control from software.
>
>
> Right now none dts of which I'm aware of doesn't define the power domain for
> the parts of the SoC, which are always on and doesn't need any additional
> management.

Actually there's is one reason for doing this, as it would allow
devices to be monitored for device PM QoS constraints by the genpd
governor.

Although, I doubt's someone actually does it because of this benefit,
at least yet.

[...]

Kind regards
Uffe

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

* [PATCH 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
@ 2016-09-15 14:13                 ` Ulf Hansson
  0 siblings, 0 replies; 68+ messages in thread
From: Ulf Hansson @ 2016-09-15 14:13 UTC (permalink / raw)
  To: linux-arm-kernel

[...]

>>> I see some serious design problems with multiple entries in power domains
>>> property. First how to show that some part of the device IS NOT in
>>> any domain?
>>
>> Is that even possible? Every device should be in some power
>> domain, even if it's just an "always on" power domain that we
>> don't really control from software.
>
>
> Right now none dts of which I'm aware of doesn't define the power domain for
> the parts of the SoC, which are always on and doesn't need any additional
> management.

Actually there's is one reason for doing this, as it would allow
devices to be monitored for device PM QoS constraints by the genpd
governor.

Although, I doubt's someone actually does it because of this benefit,
at least yet.

[...]

Kind regards
Uffe

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

end of thread, other threads:[~2016-09-15 14:13 UTC | newest]

Thread overview: 68+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-01 13:45 [PATCH 0/5] Add runtime PM support for clocks (on Exynos SoC example) Marek Szyprowski
2016-09-01 13:45 ` Marek Szyprowski
2016-09-01 13:45 ` Marek Szyprowski
2016-09-01 13:45 ` [PATCH 1/5] clk: add support for runtime pm Marek Szyprowski
2016-09-01 13:45   ` Marek Szyprowski
2016-09-01 13:45   ` Marek Szyprowski
2016-09-01 15:10   ` kbuild test robot
2016-09-01 15:10     ` kbuild test robot
2016-09-01 15:10     ` kbuild test robot
2016-09-01 15:10   ` [PATCH] clk: fix boolreturn.cocci warnings kbuild test robot
2016-09-01 15:10     ` kbuild test robot
2016-09-01 15:10     ` kbuild test robot
2016-09-08  0:19   ` [PATCH 1/5] clk: add support for runtime pm Stephen Boyd
2016-09-08  0:19     ` Stephen Boyd
     [not found]     ` <CGME20160912101857eucas1p29b2bbd5ac0eda92284091ad1b86decc4@eucas1p2.samsung.com>
2016-09-12 10:18       ` Marek Szyprowski
2016-09-12 10:18         ` Marek Szyprowski
2016-09-12 22:31         ` Stephen Boyd
2016-09-12 22:31           ` Stephen Boyd
2016-09-13  9:07           ` Marek Szyprowski
2016-09-13  9:07             ` Marek Szyprowski
2016-09-14 21:39             ` Stephen Boyd
2016-09-14 21:39               ` Stephen Boyd
2016-09-15  8:32               ` Marek Szyprowski
2016-09-15  8:32                 ` Marek Szyprowski
2016-09-13  7:24     ` Ulf Hansson
2016-09-13  7:24       ` Ulf Hansson
2016-09-13  8:49   ` Ulf Hansson
2016-09-13  8:49     ` Ulf Hansson
2016-09-13 13:13     ` Marek Szyprowski
2016-09-13 13:13       ` Marek Szyprowski
2016-09-13 15:03       ` Ulf Hansson
2016-09-13 15:03         ` Ulf Hansson
2016-09-14 10:11         ` Marek Szyprowski
2016-09-14 10:11           ` Marek Szyprowski
2016-09-01 13:45 ` [PATCH 2/5] clock: samsung: " Marek Szyprowski
2016-09-01 13:45   ` Marek Szyprowski
2016-09-01 13:45   ` Marek Szyprowski
2016-09-01 13:45 ` [PATCH 3/5] clocks: exynos4x12: add runtime pm support for ISP clocks Marek Szyprowski
2016-09-01 13:45   ` Marek Szyprowski
2016-09-01 13:45   ` Marek Szyprowski
2016-09-01 21:49   ` kbuild test robot
2016-09-01 21:49     ` kbuild test robot
2016-09-01 21:49     ` kbuild test robot
2016-09-01 13:45 ` [PATCH 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device Marek Szyprowski
2016-09-01 13:45   ` Marek Szyprowski
2016-09-01 13:45   ` Marek Szyprowski
2016-09-08  0:22   ` Stephen Boyd
2016-09-08  0:22     ` Stephen Boyd
     [not found]     ` <CGME20160912102332eucas1p145e79669788329b44343da62dcbe50ca@eucas1p1.samsung.com>
2016-09-12 10:23       ` Marek Szyprowski
2016-09-12 10:23         ` Marek Szyprowski
2016-09-12 22:28         ` Stephen Boyd
2016-09-12 22:28           ` Stephen Boyd
     [not found]           ` <20160912222852.GH7243-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2016-09-15 12:06             ` Marek Szyprowski
2016-09-15 12:06               ` Marek Szyprowski
2016-09-15 12:06               ` Marek Szyprowski
2016-09-15 14:13               ` Ulf Hansson
2016-09-15 14:13                 ` Ulf Hansson
2016-09-01 13:45 ` [PATCH 5/5] clocks: exynos5433: add runtime pm support Marek Szyprowski
2016-09-01 13:45   ` Marek Szyprowski
2016-09-01 16:55   ` Bartlomiej Zolnierkiewicz
2016-09-01 16:55     ` Bartlomiej Zolnierkiewicz
2016-09-01 16:55     ` Bartlomiej Zolnierkiewicz
2016-09-01 23:00   ` kbuild test robot
2016-09-01 23:00     ` kbuild test robot
2016-09-01 23:00     ` kbuild test robot
2016-09-02 19:05   ` kbuild test robot
2016-09-02 19:05     ` kbuild test robot
2016-09-02 19:05     ` kbuild test robot

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.