All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/5] Add runtime PM support for clocks (on Exynos SoC example)
       [not found] <CGME20160919105545eucas1p1026e435bbaeb1f5c866a9abcdd051464@eucas1p1.samsung.com>
@ 2016-09-19 10:55   ` Marek Szyprowski
  0 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2016-09-19 10:55 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-v2

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

Best regards
Marek Szyprowski
Samsung R&D Institute Poland

Changelog:
v2:
- Simplified clk_pm_runtime_get/put functions, removed workaround for devices
  with disabled runtime pm. Such workaround is no longer needed since commit
  4d23a5e84806b202d9231929c9507ef7cf7a0185 ("PM / Domains: Allow runtime PM
  during system PM phases").
- Added CLK_RUNTIME_PM flag to indicate clocks, for which clock core should
  call runtime pm functions. This solves problem with clocks, for which struct
  device is already registered, but no runtime pm is enabled.
- Extended commit messages according to Ulf suggestions.
- Fixed some style issues pointed by Barlomiej.

v1: http://www.spinics.net/lists/arm-kernel/msg528128.html
- initial version

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                                  | 107 +++++-
 drivers/clk/samsung/clk-exynos4.c                  | 227 ++++++++----
 drivers/clk/samsung/clk-exynos5433.c               | 385 ++++++++++++++++-----
 drivers/clk/samsung/clk-pll.c                      |   4 +-
 drivers/clk/samsung/clk.c                          |  36 +-
 drivers/clk/samsung/clk.h                          |   7 +
 include/linux/clk-provider.h                       |   1 +
 9 files changed, 632 insertions(+), 162 deletions(-)

-- 
1.9.1

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

* [PATCH v2 0/5] Add runtime PM support for clocks (on Exynos SoC example)
@ 2016-09-19 10:55   ` Marek Szyprowski
  0 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2016-09-19 10:55 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-v2

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

Best regards
Marek Szyprowski
Samsung R&D Institute Poland

Changelog:
v2:
- Simplified clk_pm_runtime_get/put functions, removed workaround for devices
  with disabled runtime pm. Such workaround is no longer needed since commit
  4d23a5e84806b202d9231929c9507ef7cf7a0185 ("PM / Domains: Allow runtime PM
  during system PM phases").
- Added CLK_RUNTIME_PM flag to indicate clocks, for which clock core should
  call runtime pm functions. This solves problem with clocks, for which struct
  device is already registered, but no runtime pm is enabled.
- Extended commit messages according to Ulf suggestions.
- Fixed some style issues pointed by Barlomiej.

v1: http://www.spinics.net/lists/arm-kernel/msg528128.html
- initial version

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                                  | 107 +++++-
 drivers/clk/samsung/clk-exynos4.c                  | 227 ++++++++----
 drivers/clk/samsung/clk-exynos5433.c               | 385 ++++++++++++++++-----
 drivers/clk/samsung/clk-pll.c                      |   4 +-
 drivers/clk/samsung/clk.c                          |  36 +-
 drivers/clk/samsung/clk.h                          |   7 +
 include/linux/clk-provider.h                       |   1 +
 9 files changed, 632 insertions(+), 162 deletions(-)

-- 
1.9.1

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

* [PATCH v2 1/5] clk: add support for runtime pm
       [not found]   ` <CGME20160919105548eucas1p24b28143fab25eb47f5629d31f817b0bc@eucas1p2.samsung.com>
@ 2016-09-19 10:55       ` Marek Szyprowski
  0 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2016-09-19 10:55 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/changing clock rates and unpreparing/disabling
unused clocks on boot) will be done with clock controller in runtime resumend
state.

When one wants to register clock controller, which make use of this feature, he
has to:
1. Provide a struct device to the core when registering the provider and set
   CLK_RUNTIME_PM flags for its clocks.
2. It needs to enable runtime PM for that device.
3. It needs to make sure the runtime PM status of the controller device reflects
   the HW state.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/clk/clk.c            | 107 +++++++++++++++++++++++++++++++++++++++----
 include/linux/clk-provider.h |   1 +
 2 files changed, 98 insertions(+), 10 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 820a939fb6bb..096a199b8e46 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,26 @@ 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;
+
+	ret = pm_runtime_get_sync(core->dev);
+	return ret < 0 ? ret : 0;
+}
+
+static void clk_pm_runtime_put(struct clk_core *core)
+{
+	if (!core->dev)
+		return;
+
+	pm_runtime_put(core->dev);
+}
+
 /***           locking             ***/
 static void clk_prepare_lock(void)
 {
@@ -150,6 +172,8 @@ static void clk_enable_unlock(unsigned long flags)
 
 static bool clk_core_is_prepared(struct clk_core *core)
 {
+	bool status;
+
 	/*
 	 * .is_prepared is optional for clocks that can prepare
 	 * fall back to software usage counter if it is missing
@@ -157,11 +181,17 @@ static bool clk_core_is_prepared(struct clk_core *core)
 	if (!core->ops->is_prepared)
 		return core->prepare_count;
 
-	return core->ops->is_prepared(core->hw);
+	clk_pm_runtime_get(core);
+	status = core->ops->is_prepared(core->hw);
+	clk_pm_runtime_put(core);
+
+	return status;
 }
 
 static bool clk_core_is_enabled(struct clk_core *core)
 {
+	bool status;
+
 	/*
 	 * .is_enabled is only mandatory for clocks that gate
 	 * fall back to software usage counter if .is_enabled is missing
@@ -169,7 +199,29 @@ static bool clk_core_is_enabled(struct clk_core *core)
 	if (!core->ops->is_enabled)
 		return core->enable_count;
 
-	return core->ops->is_enabled(core->hw);
+	/*
+	 * Check if runtime pm is enabled before calling .is_enabled callback,
+	 * if not assume that clock is disabled, because we might be called
+	 * from atomic context, from which pm_runtime_get() is not allowed.
+	 * This function is called mainly from clk_disable_unused_subtree,
+	 * which ensures proper runtime pm activation of controller before
+	 * taking enable spinlock, but the below check is needed if one tries
+	 * to call it from other place.
+	 */
+	if (core->dev) {
+		pm_runtime_get_noresume(core->dev);
+		if (pm_runtime_suspended(core->dev)) {
+			status = false;
+			goto done;
+		}
+	}
+
+	status = core->ops->is_enabled(core->hw);
+done:
+	if (core->dev)
+		pm_runtime_put(core->dev);
+
+	return status;
 }
 
 /***    helper functions   ***/
@@ -489,6 +541,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 +584,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 +599,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)
@@ -745,6 +806,9 @@ static void clk_unprepare_unused_subtree(struct clk_core *core)
 	if (core->flags & CLK_IGNORE_UNUSED)
 		return;
 
+	if (clk_pm_runtime_get(core) != 0)
+		return;
+
 	if (clk_core_is_prepared(core)) {
 		trace_clk_unprepare(core);
 		if (core->ops->unprepare_unused)
@@ -753,6 +817,8 @@ static void clk_unprepare_unused_subtree(struct clk_core *core)
 			core->ops->unprepare(core->hw);
 		trace_clk_unprepare_complete(core);
 	}
+
+	clk_pm_runtime_put(core);
 }
 
 static void clk_disable_unused_subtree(struct clk_core *core)
@@ -768,6 +834,9 @@ static void clk_disable_unused_subtree(struct clk_core *core)
 	if (core->flags & CLK_OPS_PARENT_ENABLE)
 		clk_core_prepare_enable(core->parent);
 
+	if (clk_pm_runtime_get(core) != 0)
+		return;
+
 	flags = clk_enable_lock();
 
 	if (core->enable_count)
@@ -794,6 +863,8 @@ unlock_out:
 	clk_enable_unlock(flags);
 	if (core->flags & CLK_OPS_PARENT_ENABLE)
 		clk_core_disable_unprepare(core->parent);
+
+	clk_pm_runtime_put(core);
 }
 
 static bool clk_ignore_unused;
@@ -1563,6 +1634,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 +1651,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 +1903,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 +1925,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 +2631,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
 		goto fail_name;
 	}
 	core->ops = hw->init->ops;
+	if (dev && (hw->init->flags & CLK_RUNTIME_PM))
+		core->dev = dev;
 	if (dev && dev->driver)
 		core->owner = dev->driver->owner;
 	core->hw = hw;
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index a39c0c530778..8a131eb71fdf 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -35,6 +35,7 @@
 #define CLK_IS_CRITICAL		BIT(11) /* do not gate, ever */
 /* parents need enable during gate/ungate, set rate and re-parent */
 #define CLK_OPS_PARENT_ENABLE	BIT(12)
+#define CLK_RUNTIME_PM		BIT(13)
 
 struct clk;
 struct clk_hw;
-- 
1.9.1

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

* [PATCH v2 1/5] clk: add support for runtime pm
@ 2016-09-19 10:55       ` Marek Szyprowski
  0 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2016-09-19 10:55 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/changing clock rates and unpreparing/disabling
unused clocks on boot) will be done with clock controller in runtime resumend
state.

When one wants to register clock controller, which make use of this feature, he
has to:
1. Provide a struct device to the core when registering the provider and set
   CLK_RUNTIME_PM flags for its clocks.
2. It needs to enable runtime PM for that device.
3. It needs to make sure the runtime PM status of the controller device reflects
   the HW state.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/clk/clk.c            | 107 +++++++++++++++++++++++++++++++++++++++----
 include/linux/clk-provider.h |   1 +
 2 files changed, 98 insertions(+), 10 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 820a939fb6bb..096a199b8e46 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,26 @@ 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;
+
+	ret = pm_runtime_get_sync(core->dev);
+	return ret < 0 ? ret : 0;
+}
+
+static void clk_pm_runtime_put(struct clk_core *core)
+{
+	if (!core->dev)
+		return;
+
+	pm_runtime_put(core->dev);
+}
+
 /***           locking             ***/
 static void clk_prepare_lock(void)
 {
@@ -150,6 +172,8 @@ static void clk_enable_unlock(unsigned long flags)
 
 static bool clk_core_is_prepared(struct clk_core *core)
 {
+	bool status;
+
 	/*
 	 * .is_prepared is optional for clocks that can prepare
 	 * fall back to software usage counter if it is missing
@@ -157,11 +181,17 @@ static bool clk_core_is_prepared(struct clk_core *core)
 	if (!core->ops->is_prepared)
 		return core->prepare_count;
 
-	return core->ops->is_prepared(core->hw);
+	clk_pm_runtime_get(core);
+	status = core->ops->is_prepared(core->hw);
+	clk_pm_runtime_put(core);
+
+	return status;
 }
 
 static bool clk_core_is_enabled(struct clk_core *core)
 {
+	bool status;
+
 	/*
 	 * .is_enabled is only mandatory for clocks that gate
 	 * fall back to software usage counter if .is_enabled is missing
@@ -169,7 +199,29 @@ static bool clk_core_is_enabled(struct clk_core *core)
 	if (!core->ops->is_enabled)
 		return core->enable_count;
 
-	return core->ops->is_enabled(core->hw);
+	/*
+	 * Check if runtime pm is enabled before calling .is_enabled callback,
+	 * if not assume that clock is disabled, because we might be called
+	 * from atomic context, from which pm_runtime_get() is not allowed.
+	 * This function is called mainly from clk_disable_unused_subtree,
+	 * which ensures proper runtime pm activation of controller before
+	 * taking enable spinlock, but the below check is needed if one tries
+	 * to call it from other place.
+	 */
+	if (core->dev) {
+		pm_runtime_get_noresume(core->dev);
+		if (pm_runtime_suspended(core->dev)) {
+			status = false;
+			goto done;
+		}
+	}
+
+	status = core->ops->is_enabled(core->hw);
+done:
+	if (core->dev)
+		pm_runtime_put(core->dev);
+
+	return status;
 }
 
 /***    helper functions   ***/
@@ -489,6 +541,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 +584,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 +599,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)
@@ -745,6 +806,9 @@ static void clk_unprepare_unused_subtree(struct clk_core *core)
 	if (core->flags & CLK_IGNORE_UNUSED)
 		return;
 
+	if (clk_pm_runtime_get(core) != 0)
+		return;
+
 	if (clk_core_is_prepared(core)) {
 		trace_clk_unprepare(core);
 		if (core->ops->unprepare_unused)
@@ -753,6 +817,8 @@ static void clk_unprepare_unused_subtree(struct clk_core *core)
 			core->ops->unprepare(core->hw);
 		trace_clk_unprepare_complete(core);
 	}
+
+	clk_pm_runtime_put(core);
 }
 
 static void clk_disable_unused_subtree(struct clk_core *core)
@@ -768,6 +834,9 @@ static void clk_disable_unused_subtree(struct clk_core *core)
 	if (core->flags & CLK_OPS_PARENT_ENABLE)
 		clk_core_prepare_enable(core->parent);
 
+	if (clk_pm_runtime_get(core) != 0)
+		return;
+
 	flags = clk_enable_lock();
 
 	if (core->enable_count)
@@ -794,6 +863,8 @@ unlock_out:
 	clk_enable_unlock(flags);
 	if (core->flags & CLK_OPS_PARENT_ENABLE)
 		clk_core_disable_unprepare(core->parent);
+
+	clk_pm_runtime_put(core);
 }
 
 static bool clk_ignore_unused;
@@ -1563,6 +1634,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 +1651,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 +1903,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 +1925,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 +2631,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
 		goto fail_name;
 	}
 	core->ops = hw->init->ops;
+	if (dev && (hw->init->flags & CLK_RUNTIME_PM))
+		core->dev = dev;
 	if (dev && dev->driver)
 		core->owner = dev->driver->owner;
 	core->hw = hw;
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index a39c0c530778..8a131eb71fdf 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -35,6 +35,7 @@
 #define CLK_IS_CRITICAL		BIT(11) /* do not gate, ever */
 /* parents need enable during gate/ungate, set rate and re-parent */
 #define CLK_OPS_PARENT_ENABLE	BIT(12)
+#define CLK_RUNTIME_PM		BIT(13)
 
 struct clk;
 struct clk_hw;
-- 
1.9.1

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

* [PATCH v2 2/5] clock: samsung: add support for runtime pm
       [not found]   ` <CGME20160919105549eucas1p1a2df94dc0ff48c7623949adbc5453bca@eucas1p1.samsung.com>
@ 2016-09-19 10:55       ` Marek Szyprowski
  0 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2016-09-19 10:55 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. It also adds CLK_RUNTIME_PM flag to all clocks for which such
device have been provided.

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

diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index 48139bd510f1..fa929ddf3551 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -1174,7 +1174,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
 	}
 
 	init.name = pll_clk->name;
-	init.flags = pll_clk->flags;
+	init.flags = pll_clk->flags | (ctx->dev ? CLK_RUNTIME_PM : 0);
 	init.parent_names = &pll_clk->parent_name;
 	init.num_parents = 1;
 
@@ -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..762019893383 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -143,8 +143,11 @@ 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,
-			list->parent_name, list->flags, list->fixed_rate);
+		unsigned int pm_flags = ctx->dev ? CLK_RUNTIME_PM : 0;
+
+		clk = clk_register_fixed_rate(ctx->dev, list->name,
+			list->parent_name, list->flags | pm_flags,
+			list->fixed_rate);
 		if (IS_ERR(clk)) {
 			pr_err("%s: failed to register clock %s\n", __func__,
 				list->name);
@@ -172,8 +175,11 @@ 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,
-			list->parent_name, list->flags, list->mult, list->div);
+		unsigned int pm_flags = ctx->dev ? CLK_RUNTIME_PM : 0;
+
+		clk = clk_register_fixed_factor(ctx->dev, list->name,
+			list->parent_name, list->flags | pm_flags, list->mult,
+			list->div);
 		if (IS_ERR(clk)) {
 			pr_err("%s: failed to register clock %s\n", __func__,
 				list->name);
@@ -193,8 +199,10 @@ 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,
-			list->num_parents, list->flags,
+		unsigned int pm_flags = ctx->dev ? CLK_RUNTIME_PM : 0;
+
+		clk = clk_register_mux(ctx->dev, list->name, list->parent_names,
+			list->num_parents, list->flags | pm_flags,
 			ctx->reg_base + list->offset,
 			list->shift, list->width, list->mux_flags, &ctx->lock);
 		if (IS_ERR(clk)) {
@@ -225,15 +233,17 @@ void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
 	unsigned int idx, ret;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
+		unsigned int pm_flags = ctx->dev ? CLK_RUNTIME_PM : 0;
+
 		if (list->table)
-			clk = clk_register_divider_table(NULL, list->name,
-				list->parent_name, list->flags,
+			clk = clk_register_divider_table(ctx->dev, list->name,
+				list->parent_name, list->flags | pm_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,
-				list->parent_name, list->flags,
+			clk = clk_register_divider(ctx->dev, list->name,
+				list->parent_name, list->flags | pm_flags,
 				ctx->reg_base + list->offset, list->shift,
 				list->width, list->div_flags, &ctx->lock);
 		if (IS_ERR(clk)) {
@@ -264,8 +274,10 @@ 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,
-				list->flags, ctx->reg_base + list->offset,
+		unsigned int pm_flags = ctx->dev ? CLK_RUNTIME_PM : 0;
+
+		clk = clk_register_gate(ctx->dev, list->name, list->parent_name,
+				list->flags | pm_flags, ctx->reg_base + list->offset,
 				list->bit_idx, list->gate_flags, &ctx->lock);
 		if (IS_ERR(clk)) {
 			pr_err("%s: failed to register clock %s\n", __func__,
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] 27+ messages in thread

* [PATCH v2 2/5] clock: samsung: add support for runtime pm
@ 2016-09-19 10:55       ` Marek Szyprowski
  0 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2016-09-19 10:55 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. It also adds CLK_RUNTIME_PM flag to all clocks for which such
device have been provided.

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

diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index 48139bd510f1..fa929ddf3551 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -1174,7 +1174,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
 	}
 
 	init.name = pll_clk->name;
-	init.flags = pll_clk->flags;
+	init.flags = pll_clk->flags | (ctx->dev ? CLK_RUNTIME_PM : 0);
 	init.parent_names = &pll_clk->parent_name;
 	init.num_parents = 1;
 
@@ -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..762019893383 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -143,8 +143,11 @@ 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,
-			list->parent_name, list->flags, list->fixed_rate);
+		unsigned int pm_flags = ctx->dev ? CLK_RUNTIME_PM : 0;
+
+		clk = clk_register_fixed_rate(ctx->dev, list->name,
+			list->parent_name, list->flags | pm_flags,
+			list->fixed_rate);
 		if (IS_ERR(clk)) {
 			pr_err("%s: failed to register clock %s\n", __func__,
 				list->name);
@@ -172,8 +175,11 @@ 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,
-			list->parent_name, list->flags, list->mult, list->div);
+		unsigned int pm_flags = ctx->dev ? CLK_RUNTIME_PM : 0;
+
+		clk = clk_register_fixed_factor(ctx->dev, list->name,
+			list->parent_name, list->flags | pm_flags, list->mult,
+			list->div);
 		if (IS_ERR(clk)) {
 			pr_err("%s: failed to register clock %s\n", __func__,
 				list->name);
@@ -193,8 +199,10 @@ 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,
-			list->num_parents, list->flags,
+		unsigned int pm_flags = ctx->dev ? CLK_RUNTIME_PM : 0;
+
+		clk = clk_register_mux(ctx->dev, list->name, list->parent_names,
+			list->num_parents, list->flags | pm_flags,
 			ctx->reg_base + list->offset,
 			list->shift, list->width, list->mux_flags, &ctx->lock);
 		if (IS_ERR(clk)) {
@@ -225,15 +233,17 @@ void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
 	unsigned int idx, ret;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
+		unsigned int pm_flags = ctx->dev ? CLK_RUNTIME_PM : 0;
+
 		if (list->table)
-			clk = clk_register_divider_table(NULL, list->name,
-				list->parent_name, list->flags,
+			clk = clk_register_divider_table(ctx->dev, list->name,
+				list->parent_name, list->flags | pm_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,
-				list->parent_name, list->flags,
+			clk = clk_register_divider(ctx->dev, list->name,
+				list->parent_name, list->flags | pm_flags,
 				ctx->reg_base + list->offset, list->shift,
 				list->width, list->div_flags, &ctx->lock);
 		if (IS_ERR(clk)) {
@@ -264,8 +274,10 @@ 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,
-				list->flags, ctx->reg_base + list->offset,
+		unsigned int pm_flags = ctx->dev ? CLK_RUNTIME_PM : 0;
+
+		clk = clk_register_gate(ctx->dev, list->name, list->parent_name,
+				list->flags | pm_flags, ctx->reg_base + list->offset,
 				list->bit_idx, list->gate_flags, &ctx->lock);
 		if (IS_ERR(clk)) {
 			pr_err("%s: failed to register clock %s\n", __func__,
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] 27+ messages in thread

* [PATCH v2 3/5] clocks: exynos4x12: add runtime pm support for ISP clocks
       [not found]   ` <CGME20160919105550eucas1p2d9bcb35f5464e14bd3c5925baf62e111@eucas1p2.samsung.com>
@ 2016-09-19 10:55       ` Marek Szyprowski
  0 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2016-09-19 10:55 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                  | 227 +++++++++++++++------
 2 files changed, 188 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..3d65e3f92f5a 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,116 @@ 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 {
+		pm_runtime_set_active(&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 __refdata = {
+	.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 +1632,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] 27+ messages in thread

* [PATCH v2 3/5] clocks: exynos4x12: add runtime pm support for ISP clocks
@ 2016-09-19 10:55       ` Marek Szyprowski
  0 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2016-09-19 10:55 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                  | 227 +++++++++++++++------
 2 files changed, 188 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..3d65e3f92f5a 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,116 @@ 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 {
+		pm_runtime_set_active(&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 __refdata = {
+	.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 +1632,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] 27+ messages in thread

* [PATCH v2 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
       [not found]   ` <CGME20160919105552eucas1p2964f3f16b0d0b38379e4f97abebf2785@eucas1p2.samsung.com>
@ 2016-09-19 10:55       ` Marek Szyprowski
  0 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2016-09-19 10:55 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.

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

* [PATCH v2 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device
@ 2016-09-19 10:55       ` Marek Szyprowski
  0 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2016-09-19 10:55 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.

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

* [PATCH v2 5/5] clocks: exynos5433: add runtime pm support
       [not found]   ` <CGME20160919105811eucas1p255d75d38bc9f2ceb9772c87241458969@eucas1p2.samsung.com>
@ 2016-09-19 10:58       ` Marek Szyprowski
  0 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2016-09-19 10:58 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 | 385 ++++++++++++++++++++++++++++-------
 drivers/clk/samsung/clk.h            |   6 +
 2 files changed, 314 insertions(+), 77 deletions(-)

diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c
index ea1608682d7f..d507f2ace6c2 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>
 
@@ -2333,6 +2338,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", };
@@ -2418,16 +2427,11 @@ static const struct samsung_cmu_info g2d_cmu_info __initconst = {
 	.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 +2496,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", };
@@ -2837,16 +2849,11 @@ static const struct samsung_cmu_info disp_cmu_info __initconst = {
 	.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 +2888,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",};
@@ -3007,16 +3019,10 @@ static const struct samsung_cmu_info aud_cmu_info __initconst = {
 	.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 +3224,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", };
@@ -3291,15 +3301,11 @@ static const struct samsung_cmu_info g3d_cmu_info __initconst = {
 	.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 +3344,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", };
@@ -3432,15 +3444,11 @@ static const struct samsung_cmu_info gscl_cmu_info __initconst = {
 	.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 +3974,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", };
@@ -4078,15 +4091,11 @@ static const struct samsung_cmu_info mscl_cmu_info __initconst = {
 	.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 +4125,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 = {
@@ -4186,15 +4199,11 @@ static const struct samsung_cmu_info mfc_cmu_info __initconst = {
 	.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 +4233,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 = {
@@ -4296,15 +4309,11 @@ static const struct samsung_cmu_info hevc_cmu_info __initconst = {
 	.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 +4347,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", };
 
@@ -4549,15 +4562,11 @@ static const struct samsung_cmu_info isp_cmu_info __initconst = {
 	.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 +4630,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", };
@@ -5026,15 +5044,11 @@ static const struct samsung_cmu_info cam0_cmu_info __initconst = {
 	.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 +5095,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", };
@@ -5399,11 +5419,222 @@ static const struct samsung_cmu_info cam1_cmu_info __initconst = {
 	.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 samsung_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)
+		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 __refdata = {
+	.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);
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 9263d8a27c6b..664020cb4794 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -354,6 +354,12 @@ struct samsung_cmu_info {
 	/* 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;
 };
 
 extern struct samsung_clk_provider *__init samsung_clk_init(
-- 
1.9.1

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

* [PATCH v2 5/5] clocks: exynos5433: add runtime pm support
@ 2016-09-19 10:58       ` Marek Szyprowski
  0 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2016-09-19 10:58 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 | 385 ++++++++++++++++++++++++++++-------
 drivers/clk/samsung/clk.h            |   6 +
 2 files changed, 314 insertions(+), 77 deletions(-)

diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c
index ea1608682d7f..d507f2ace6c2 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>
 
@@ -2333,6 +2338,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", };
@@ -2418,16 +2427,11 @@ static const struct samsung_cmu_info g2d_cmu_info __initconst = {
 	.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 +2496,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", };
@@ -2837,16 +2849,11 @@ static const struct samsung_cmu_info disp_cmu_info __initconst = {
 	.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 +2888,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",};
@@ -3007,16 +3019,10 @@ static const struct samsung_cmu_info aud_cmu_info __initconst = {
 	.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 +3224,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", };
@@ -3291,15 +3301,11 @@ static const struct samsung_cmu_info g3d_cmu_info __initconst = {
 	.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 +3344,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", };
@@ -3432,15 +3444,11 @@ static const struct samsung_cmu_info gscl_cmu_info __initconst = {
 	.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 +3974,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", };
@@ -4078,15 +4091,11 @@ static const struct samsung_cmu_info mscl_cmu_info __initconst = {
 	.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 +4125,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 = {
@@ -4186,15 +4199,11 @@ static const struct samsung_cmu_info mfc_cmu_info __initconst = {
 	.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 +4233,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 = {
@@ -4296,15 +4309,11 @@ static const struct samsung_cmu_info hevc_cmu_info __initconst = {
 	.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 +4347,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", };
 
@@ -4549,15 +4562,11 @@ static const struct samsung_cmu_info isp_cmu_info __initconst = {
 	.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 +4630,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", };
@@ -5026,15 +5044,11 @@ static const struct samsung_cmu_info cam0_cmu_info __initconst = {
 	.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 +5095,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", };
@@ -5399,11 +5419,222 @@ static const struct samsung_cmu_info cam1_cmu_info __initconst = {
 	.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 samsung_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)
+		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 __refdata = {
+	.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);
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 9263d8a27c6b..664020cb4794 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -354,6 +354,12 @@ struct samsung_cmu_info {
 	/* 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;
 };
 
 extern struct samsung_clk_provider *__init samsung_clk_init(
-- 
1.9.1

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

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

Hello Marek,

I'm using the patches from the v4.8-clocks-pm-v2 branch plus the ones
from the v4.8-clocks-pm-v2 branch on top of 4.8.0.

I see some warnings on boot coming from driver core. It appears that the
warnings are actually meaningful, since IOMMUs stop working completly.
E.g. if I modprobe s5p-mfc later, firmware loading fails because
apparantly the IOMMU domain isn't online.

> WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c

I added some debug printk() to device_links_driver_bound(), to show the
link status. Apparantly it is always DEVICE_LINK_AVAILABLE.

Here's the (semi) full log:
> [    0.000000] Booting Linux on physical CPU 0xa00
> [    0.000000] Linux version 4.8.0-vanilla+ (liquid@chidori) (gcc version 4.9.3 (Gentoo 4.9.3 p1.5, pie-0.6.4) ) #3 SMP PREEMPT Thu Oct 6 19:14:15 CEST 2016
> [    0.000000] CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=10c5387d
> [    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
> [    0.000000] OF: fdt:Machine model: Hardkernel ODROID-X2 board based on Exynos4412
> [    0.000000] Reserved memory: created DMA memory pool at 0xbf700000, size 8 MiB
> [    0.000000] OF: reserved mem: initialized node region_mfc_right, compatible id shared-dma-pool
> [    0.000000] Reserved memory: created DMA memory pool at 0xbe700000, size 16 MiB
> [    0.000000] OF: reserved mem: initialized node region_mfc_left, compatible id shared-dma-pool
> [    0.000000] cma: Reserved 128 MiB at 0xb6400000
> [    0.000000] Memory policy: Data cache writealloc
> [    0.000000] Samsung CPU ID: 0xe4412220
> [    0.000000] Running under secure firmware.
> [    0.000000] percpu: Embedded 14 pages/cpu @eefb3000 s26176 r8192 d22976 u57344
> [    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 516352
> [    0.000000] Kernel command line: video=HDMI-A-1:1280x720M@60 console=ttySAC1,115200n8 root=PARTUUID=8c900d97-367f-47a9-bd66-6eced1a29836 rootfstype=f2fs rootwait ro earlyprintk console=tty1 console=ttySAC1,115200
> [    0.000000] PID hash table entries: 4096 (order: 2, 16384 bytes)
> [    0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
> [    0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
> [    0.000000] Memory: 1913244K/2071552K available (6144K kernel code, 223K rwdata, 1432K rodata, 1024K init, 246K bss, 27236K reserved, 131072K cma-reserved, 1154048K highmem)
> [    0.000000] Virtual kernel memory layout:
> [    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
> [    0.000000]     fixmap  : 0xffc00000 - 0xfff00000   (3072 kB)
> [    0.000000]     vmalloc : 0xf0800000 - 0xff800000   ( 240 MB)
> [    0.000000]     lowmem  : 0xc0000000 - 0xf0000000   ( 768 MB)
> [    0.000000]     pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)
> [    0.000000]     modules : 0xbf000000 - 0xbfe00000   (  14 MB)
> [    0.000000]       .text : 0xc0008000 - 0xc0700000   (7136 kB)
> [    0.000000]       .init : 0xc0900000 - 0xc0a00000   (1024 kB)
> [    0.000000]       .data : 0xc0a00000 - 0xc0a37fc0   ( 224 kB)
> [    0.000000]        .bss : 0xc0a39000 - 0xc0a76a08   ( 247 kB)
> [    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
> [    0.000000] Preemptible hierarchical RCU implementation.
> [    0.000000]  Build-time adjustment of leaf fanout to 32.
> [    0.000000] NR_IRQS:16 nr_irqs:16 16
> [    0.000000] L2C: platform modifies aux control register: 0x02070000 -> 0x3e470001
> [    0.000000] L2C: platform provided aux values permit register corruption.
> [    0.000000] L2C: DT/platform modifies aux control register: 0x02070000 -> 0x3e470001
> [    0.000000] L2C-310 enabling early BRESP for Cortex-A9
> [    0.000000] L2C-310: enabling full line of zeros but not enabled in Cortex-A9
> [    0.000000] L2C-310 ID prefetch enabled, offset 8 lines
> [    0.000000] L2C-310 dynamic clock gating enabled, standby mode enabled
> [    0.000000] L2C-310 cache controller enabled, 16 ways, 1024 kB
> [    0.000000] L2C-310: CACHE_ID 0x4100c4c8, AUX_CTRL 0x7e470001
> [    0.000000] Exynos4x12 clocks: sclk_apll = 1000000000, sclk_mpll = 800000000
> [    0.000000]  sclk_epll = 96000000, sclk_vpll = 350000000, arm_clk = 1000000000
> [    0.000000] Switching to timer-based delay loop, resolution 41ns
> [    0.000000] clocksource: mct-frc: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 79635851949 ns
> [    0.000004] sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 89478484971ns
> [    0.000263] Console: colour dummy device 80x30
> [    0.000978] console [tty1] enabled
> [    0.001003] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=120000)
> [    0.001039] pid_max: default: 32768 minimum: 301
> [    0.001118] Mount-cache hash table entries: 2048 (order: 1, 8192 bytes)
> [    0.001142] Mountpoint-cache hash table entries: 2048 (order: 1, 8192 bytes)
> [    0.001577] CPU: Testing write buffer coherency: ok
> [    0.001875] CPU0: thread -1, cpu 0, socket 10, mpidr 80000a00
> [    0.002240] Setting up static identity map for 0x40100000 - 0x40100058
> [    0.055360] CPU1: thread -1, cpu 1, socket 10, mpidr 80000a01
> [    0.075335] CPU2: thread -1, cpu 2, socket 10, mpidr 80000a02
> [    0.095316] CPU3: thread -1, cpu 3, socket 10, mpidr 80000a03
> [    0.095374] Brought up 4 CPUs
> [    0.095445] SMP: Total of 4 processors activated (192.00 BogoMIPS).
> [    0.095464] CPU: All CPU(s) started in SVC mode.
> [    0.096280] devtmpfs: initialized
> [    0.110373] VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 4
> [    0.110612] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 9556302231375000 ns
> [    0.114190] pinctrl core: initialized pinctrl subsystem
> [    0.114738] lcd0-power-domain@10023C80 has as child subdomain: tv-power-domain@10023C20.
> [    0.115573] NET: Registered protocol family 16
> [    0.117150] DMA: preallocated 256 KiB pool for atomic coherent allocations
> [    0.134991] cpuidle: using governor ladder
> [    0.154989] cpuidle: using governor menu
> [    0.155398] hw-breakpoint: found 5 (+1 reserved) breakpoint and 1 watchpoint registers.
> [    0.155434] hw-breakpoint: maximum watchpoint size is 4 bytes.
> [    0.197368] SCSI subsystem initialized
> [    0.197498] usbcore: registered new interface driver usbfs
> [    0.197568] usbcore: registered new interface driver hub
> [    0.197664] usbcore: registered new device driver usb
> [    0.198081] s3c-i2c 13860000.i2c: slave address 0x10
> [    0.198111] s3c-i2c 13860000.i2c: bus frequency set to 390 KHz
> [    0.198570] s3c-i2c 13860000.i2c: i2c-0: S3C I2C adapter
> [    0.198763] s3c-i2c 13870000.i2c: slave address 0x10
> [    0.198791] s3c-i2c 13870000.i2c: bus frequency set to 390 KHz
> [    0.199046] s3c-i2c 13870000.i2c: i2c-1: S3C I2C adapter
> [    0.199192] s3c-i2c 13880000.i2c: slave address 0x00
> [    0.199218] s3c-i2c 13880000.i2c: bus frequency set to 97 KHz
> [    0.199375] s3c-i2c 13880000.i2c: i2c-2: S3C I2C adapter
> [    0.199481] s3c-i2c 138e0000.i2c: slave address 0x00
> [    0.199506] s3c-i2c 138e0000.i2c: bus frequency set to 97 KHz
> [    0.199758] s3c-i2c 138e0000.i2c: i2c-8: S3C I2C adapter
> [    0.200052] Linux video capture interface: v2.00
> [    0.205439] Advanced Linux Sound Architecture Driver Initialized.
> [    0.205901] Bluetooth: Core ver 2.21
> [    0.205947] NET: Registered protocol family 31
> [    0.205966] Bluetooth: HCI device and connection manager initialized
> [    0.205992] Bluetooth: HCI socket layer initialized
> [    0.206014] Bluetooth: L2CAP socket layer initialized
> [    0.206036] Bluetooth: SCO socket layer initialized
> [    0.206567] clocksource: Switched to clocksource mct-frc
> [    0.214799] NET: Registered protocol family 2
> [    0.215264] TCP established hash table entries: 8192 (order: 3, 32768 bytes)
> [    0.215352] TCP bind hash table entries: 8192 (order: 4, 65536 bytes)
> [    0.215463] TCP: Hash tables configured (established 8192 bind 8192)
> [    0.215531] UDP hash table entries: 512 (order: 2, 16384 bytes)
> [    0.215573] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
> [    0.215717] NET: Registered protocol family 1
> [    0.216073] hw perfevents: enabled with armv7_cortex_a9 PMU driver, 7 counters available
> [    0.217474] futex hash table entries: 1024 (order: 4, 65536 bytes)
> [    0.217587] audit: initializing netlink subsys (disabled)
> [    0.217641] audit: type=2000 audit(0.215:1): initialized
> [    0.218191] workingset: timestamp_bits=30 max_order=19 bucket_order=0
> [    0.230957] bounce: pool size: 64 pages
> [    0.231124] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 251)
> [    0.231157] io scheduler noop registered
> [    0.231175] io scheduler deadline registered
> [    0.231306] io scheduler cfq registered (default)
> [    0.231963] 125b0000.exynos-usbphy supply vbus not found, using dummy regulator
> [    0.235681] dma-pl330 12680000.pdma: Loaded driver for PL330 DMAC-141330
> [    0.235717] dma-pl330 12680000.pdma:         DBUFF-32x4bytes Num_Chans-8 Num_Peri-32 Num_Events-32
> [    0.238256] dma-pl330 12690000.pdma: Loaded driver for PL330 DMAC-141330
> [    0.238291] dma-pl330 12690000.pdma:         DBUFF-32x4bytes Num_Chans-8 Num_Peri-32 Num_Events-32
> [    0.239110] dma-pl330 12850000.mdma: Loaded driver for PL330 DMAC-141330
> [    0.239141] dma-pl330 12850000.mdma:         DBUFF-64x8bytes Num_Chans-8 Num_Peri-1 Num_Events-32
> [    0.239800] 13800000.serial: ttySAC0 at MMIO 0x13800000 (irq = 53, base_baud = 0) is a S3C6400/10
> [    0.240144] 13810000.serial: ttySAC1 at MMIO 0x13810000 (irq = 54, base_baud = 0) is a S3C6400/10
> [    1.015731] console [ttySAC1] enabled
> [    1.019770] 13820000.serial: ttySAC2 at MMIO 0x13820000 (irq = 55, base_baud = 0) is a S3C6400/10
> [    1.028570] 13830000.serial: ttySAC3 at MMIO 0x13830000 (irq = 56, base_baud = 0) is a S3C6400/10
> [    1.038157] [drm] Initialized drm 1.1.0 20060810
> [    1.042093] exynos-mixer 12c10000.mixer: Linked as a consumer to 12e20000.sysmmu
> [    1.049118] iommu: Adding device 12c10000.mixer to group 0
> [    1.055403] DEBUG: device_links_driver_bound(): 1
> [    1.059238] ------------[ cut here ]------------
> [    1.063826] WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
> [    1.072851] Modules linked in:
> [    1.075859] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.8.0-vanilla+ #3
> [    1.082458] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
> [    1.088533] Backtrace: 
> [    1.090970] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
> [    1.098524]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
> [    1.104161] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
> [    1.111376] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
> [    1.118306]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
> [    1.123946] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
> [    1.131506]  r9:00000000 r8:c0a258d8 r7:ee3114e4 r6:eeafa874 r5:00000000 r4:ee3114c0
> [    1.139231] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
> [    1.148615] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
> [    1.157287]  r9:00000000 r8:c0a258d8 r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eeafa810
> [    1.165011] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
> [    1.173345]  r4:eeafa810 r3:600000d3
> [    1.176894] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
> [    1.185323]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eeafa844 r5:c0a258d8
> [    1.193128]  r4:eeafa810 r3:00000000
> [    1.196685] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
> [    1.204853]  r6:c0407eb0 r5:c0a258d8 r4:00000000 r3:c0407eb0
> [    1.210485] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
> [    1.218480]  r6:c0a26758 r5:ee27f780 r4:c0a258d8
> [    1.223072] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
> [    1.231072] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
> [    1.239139]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a258d8
> [    1.244773] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
> [    1.253809]  r5:00000000 r4:00000004
> [    1.257364] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
> [    1.266402] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
> [    1.274554]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
> [    1.281232] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
> [    1.289917]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
> [    1.297722]  r4:c093a520
> [    1.300243] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
> [    1.308493]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
> [    1.316297]  r4:00000000
> [    1.318815] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
> [    1.326373]  r4:00000000 r3:ee880000
> [    1.329952] ---[ end trace 402e0b75dfe2947b ]---
> [    1.336115] exynos-hdmi 12d00000.hdmi: Failed to get supply 'vdd': -517
> [    1.341761] s5p-g2d 10800000.g2d: Linked as a consumer to 10a40000.sysmmu
> [    1.347960] iommu: Adding device 10800000.g2d to group 1
> [    1.353512] s5p-g2d 10800000.g2d: The Exynos G2D (ver 4.1) successfully probed.
> [    1.360510] DEBUG: device_links_driver_bound(): 1
> [    1.365183] ------------[ cut here ]------------
> [    1.369786] WARNING: CPU: 1 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
> [    1.378819] Modules linked in:
> [    1.381829] CPU: 1 PID: 1 Comm: swapper/0 Tainted: G        W       4.8.0-vanilla+ #3
> [    1.389651] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
> [    1.395718] Backtrace: 
> [    1.398154] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
> [    1.405709]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
> [    1.411344] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
> [    1.418560] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
> [    1.425491]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
> [    1.431132] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
> [    1.438691]  r9:00000000 r8:c0a2621c r7:ee910ae4 r6:eeac4a74 r5:00000000 r4:ee910ac0
> [    1.446416] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
> [    1.455800] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
> [    1.464472]  r9:00000000 r8:c0a2621c r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eeac4a10
> [    1.472196] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
> [    1.480530]  r4:eeac4a10 r3:00000000
> [    1.484080] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
> [    1.492508]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eeac4a44 r5:c0a2621c
> [    1.500313]  r4:eeac4a10 r3:00000000
> [    1.503870] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
> [    1.512038]  r6:c0407eb0 r5:c0a2621c r4:00000000 r3:c0407eb0
> [    1.517671] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
> [    1.525665]  r6:c0a26758 r5:ee932b80 r4:c0a2621c
> [    1.530257] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
> [    1.538257] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
> [    1.546324]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a2621c
> [    1.551959] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
> [    1.560994]  r5:00000000 r4:0000000a
> [    1.564548] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
> [    1.573587] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
> [    1.581739]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
> [    1.588415] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
> [    1.597103]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
> [    1.604907]  r4:c093a520
> [    1.607427] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
> [    1.615678]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
> [    1.623482]  r4:00000000
> [    1.625999] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
> [    1.633558]  r4:00000000 r3:ee880000
> [    1.637133] ---[ end trace 402e0b75dfe2947c ]---
> [    1.642227] exynos-drm-fimc 11800000.fimc: Linked as a consumer to 11a20000.sysmmu
> [    1.649335] iommu: Adding device 11800000.fimc to group 2
> [    1.655529] exynos-drm-fimc 11810000.fimc: Linked as a consumer to 11a30000.sysmmu
> [    1.662263] iommu: Adding device 11810000.fimc to group 3
> [    1.668447] exynos-drm-fimc 11820000.fimc: Linked as a consumer to 11a40000.sysmmu
> [    1.675196] iommu: Adding device 11820000.fimc to group 4
> [    1.681278] exynos-drm-fimc 11820000.fimc: drm fimc registered successfully.
> [    1.687589] DEBUG: device_links_driver_bound(): 1
> [    1.692264] ------------[ cut here ]------------
> [    1.696852] WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
> [    1.705880] Modules linked in:
> [    1.708891] CPU: 0 PID: 1 Comm: swapper/0 Tainted: G        W       4.8.0-vanilla+ #3
> [    1.716713] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
> [    1.722780] Backtrace: 
> [    1.725216] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
> [    1.732771]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
> [    1.738407] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
> [    1.745624] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
> [    1.752553]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
> [    1.758194] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
> [    1.765754]  r9:00000000 r8:c0a26330 r7:ee311d24 r6:eea83074 r5:00000000 r4:ee311d00
> [    1.773479] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
> [    1.782862] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
> [    1.791534]  r9:00000000 r8:c0a26330 r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eea83010
> [    1.799258] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
> [    1.807592]  r4:eea83010 r3:600000d3
> [    1.811142] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
> [    1.819571]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eea83044 r5:c0a26330
> [    1.827376]  r4:eea83010 r3:00000000
> [    1.830932] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
> [    1.839100]  r6:c0407eb0 r5:c0a26330 r4:00000000 r3:c0407eb0
> [    1.844733] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
> [    1.852728]  r6:c0a26758 r5:ee27fa00 r4:c0a26330
> [    1.857319] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
> [    1.865320] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
> [    1.873386]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a26330
> [    1.879021] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
> [    1.888057]  r5:00000000 r4:0000000b
> [    1.891610] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
> [    1.900649] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
> [    1.908801]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
> [    1.915478] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
> [    1.924165]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
> [    1.931969]  r4:c093a520
> [    1.934489] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
> [    1.942740]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
> [    1.950545]  r4:00000000
> [    1.953062] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
> [    1.960620]  r4:00000000 r3:ee880000
> [    1.964193] ---[ end trace 402e0b75dfe2947d ]---
> [    1.969039] exynos-drm-fimc 11830000.fimc: Linked as a consumer to 11a50000.sysmmu
> [    1.976392] iommu: Adding device 11830000.fimc to group 5
> [    1.982437] exynos-drm-fimc 11830000.fimc: drm fimc registered successfully.
> [    1.988799] DEBUG: device_links_driver_bound(): 1
> [    1.993464] ------------[ cut here ]------------
> [    1.998056] WARNING: CPU: 2 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
> [    2.007076] Modules linked in:
> [    2.010087] CPU: 2 PID: 1 Comm: swapper/0 Tainted: G        W       4.8.0-vanilla+ #3
> [    2.017909] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
> [    2.023975] Backtrace: 
> [    2.026412] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
> [    2.033967]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
> [    2.039603] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
> [    2.046819] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
> [    2.053750]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
> [    2.059390] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
> [    2.066950]  r9:00000000 r8:c0a26330 r7:ee313264 r6:eea83274 r5:00000000 r4:ee313240
> [    2.074675] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
> [    2.084058] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
> [    2.092731]  r9:00000000 r8:c0a26330 r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eea83210
> [    2.100454] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
> [    2.108788]  r4:eea83210 r3:600000d3
> [    2.112338] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
> [    2.120767]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eea83244 r5:c0a26330
> [    2.128571]  r4:eea83210 r3:00000000
> [    2.132128] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
> [    2.140296]  r6:c0407eb0 r5:c0a26330 r4:00000000 r3:c0407eb0
> [    2.145929] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
> [    2.153924]  r6:c0a26758 r5:ee27fa00 r4:c0a26330
> [    2.158516] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
> [    2.166516] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
> [    2.174582]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a26330
> [    2.180217] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
> [    2.189252]  r5:00000000 r4:0000000b
> [    2.192806] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
> [    2.201845] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
> [    2.209997]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
> [    2.216674] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
> [    2.225361]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
> [    2.233165]  r4:c093a520
> [    2.235685] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
> [    2.243936]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
> [    2.251740]  r4:00000000
> [    2.254258] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
> [    2.261816]  r4:00000000 r3:ee880000
> [    2.265388] ---[ end trace 402e0b75dfe2947e ]---
> [    2.270457] exynos-drm-ipp exynos-drm-ipp: drm ipp registered successfully.
> [    2.280368] loop: module loaded
> [    2.293185] random: fast init done
> [    2.303857] usbcore: registered new interface driver smsc95xx
> [    2.491598] dwc2 12480000.hsotg: Specified GNPTXFDEP=1024 > 768
> [    2.491906] dwc2 12480000.hsotg: EPs: 16, dedicated fifos, 7808 entries in SPRAM
> [    2.499801] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
> [    2.505798] ehci-exynos: EHCI EXYNOS driver
> [    2.510438] exynos-ehci 12580000.ehci: EHCI Host Controller
> [    2.515535] exynos-ehci 12580000.ehci: new USB bus registered, assigned bus number 1
> [    2.523434] exynos-ehci 12580000.ehci: irq 51, io mem 0x12580000
> [    2.541596] exynos-ehci 12580000.ehci: USB 2.0 started, EHCI 1.00
> <snip>

I'll try to do another test with just the 5 patches from this set
applied (without the IOMMU probe deferral).

With best wishes,
Tobias



Marek Szyprowski wrote:
> 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-v2
> 
> Patches are based on vanilla v4.8-rc7 kernel.
> 
> Best regards
> Marek Szyprowski
> Samsung R&D Institute Poland
> 
> Changelog:
> v2:
> - Simplified clk_pm_runtime_get/put functions, removed workaround for devices
>   with disabled runtime pm. Such workaround is no longer needed since commit
>   4d23a5e84806b202d9231929c9507ef7cf7a0185 ("PM / Domains: Allow runtime PM
>   during system PM phases").
> - Added CLK_RUNTIME_PM flag to indicate clocks, for which clock core should
>   call runtime pm functions. This solves problem with clocks, for which struct
>   device is already registered, but no runtime pm is enabled.
> - Extended commit messages according to Ulf suggestions.
> - Fixed some style issues pointed by Barlomiej.
> 
> v1: http://www.spinics.net/lists/arm-kernel/msg528128.html
> - initial version
> 
> 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                                  | 107 +++++-
>  drivers/clk/samsung/clk-exynos4.c                  | 227 ++++++++----
>  drivers/clk/samsung/clk-exynos5433.c               | 385 ++++++++++++++++-----
>  drivers/clk/samsung/clk-pll.c                      |   4 +-
>  drivers/clk/samsung/clk.c                          |  36 +-
>  drivers/clk/samsung/clk.h                          |   7 +
>  include/linux/clk-provider.h                       |   1 +
>  9 files changed, 632 insertions(+), 162 deletions(-)
> 

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

* [PATCH v2 0/5] Add runtime PM support for clocks (on Exynos SoC example)
@ 2016-10-06 18:05     ` Tobias Jakobi
  0 siblings, 0 replies; 27+ messages in thread
From: Tobias Jakobi @ 2016-10-06 18:05 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Marek,

I'm using the patches from the v4.8-clocks-pm-v2 branch plus the ones
from the v4.8-clocks-pm-v2 branch on top of 4.8.0.

I see some warnings on boot coming from driver core. It appears that the
warnings are actually meaningful, since IOMMUs stop working completly.
E.g. if I modprobe s5p-mfc later, firmware loading fails because
apparantly the IOMMU domain isn't online.

> WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c

I added some debug printk() to device_links_driver_bound(), to show the
link status. Apparantly it is always DEVICE_LINK_AVAILABLE.

Here's the (semi) full log:
> [    0.000000] Booting Linux on physical CPU 0xa00
> [    0.000000] Linux version 4.8.0-vanilla+ (liquid at chidori) (gcc version 4.9.3 (Gentoo 4.9.3 p1.5, pie-0.6.4) ) #3 SMP PREEMPT Thu Oct 6 19:14:15 CEST 2016
> [    0.000000] CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=10c5387d
> [    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
> [    0.000000] OF: fdt:Machine model: Hardkernel ODROID-X2 board based on Exynos4412
> [    0.000000] Reserved memory: created DMA memory pool at 0xbf700000, size 8 MiB
> [    0.000000] OF: reserved mem: initialized node region_mfc_right, compatible id shared-dma-pool
> [    0.000000] Reserved memory: created DMA memory pool at 0xbe700000, size 16 MiB
> [    0.000000] OF: reserved mem: initialized node region_mfc_left, compatible id shared-dma-pool
> [    0.000000] cma: Reserved 128 MiB at 0xb6400000
> [    0.000000] Memory policy: Data cache writealloc
> [    0.000000] Samsung CPU ID: 0xe4412220
> [    0.000000] Running under secure firmware.
> [    0.000000] percpu: Embedded 14 pages/cpu @eefb3000 s26176 r8192 d22976 u57344
> [    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 516352
> [    0.000000] Kernel command line: video=HDMI-A-1:1280x720M at 60 console=ttySAC1,115200n8 root=PARTUUID=8c900d97-367f-47a9-bd66-6eced1a29836 rootfstype=f2fs rootwait ro earlyprintk console=tty1 console=ttySAC1,115200
> [    0.000000] PID hash table entries: 4096 (order: 2, 16384 bytes)
> [    0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
> [    0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
> [    0.000000] Memory: 1913244K/2071552K available (6144K kernel code, 223K rwdata, 1432K rodata, 1024K init, 246K bss, 27236K reserved, 131072K cma-reserved, 1154048K highmem)
> [    0.000000] Virtual kernel memory layout:
> [    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
> [    0.000000]     fixmap  : 0xffc00000 - 0xfff00000   (3072 kB)
> [    0.000000]     vmalloc : 0xf0800000 - 0xff800000   ( 240 MB)
> [    0.000000]     lowmem  : 0xc0000000 - 0xf0000000   ( 768 MB)
> [    0.000000]     pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)
> [    0.000000]     modules : 0xbf000000 - 0xbfe00000   (  14 MB)
> [    0.000000]       .text : 0xc0008000 - 0xc0700000   (7136 kB)
> [    0.000000]       .init : 0xc0900000 - 0xc0a00000   (1024 kB)
> [    0.000000]       .data : 0xc0a00000 - 0xc0a37fc0   ( 224 kB)
> [    0.000000]        .bss : 0xc0a39000 - 0xc0a76a08   ( 247 kB)
> [    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
> [    0.000000] Preemptible hierarchical RCU implementation.
> [    0.000000]  Build-time adjustment of leaf fanout to 32.
> [    0.000000] NR_IRQS:16 nr_irqs:16 16
> [    0.000000] L2C: platform modifies aux control register: 0x02070000 -> 0x3e470001
> [    0.000000] L2C: platform provided aux values permit register corruption.
> [    0.000000] L2C: DT/platform modifies aux control register: 0x02070000 -> 0x3e470001
> [    0.000000] L2C-310 enabling early BRESP for Cortex-A9
> [    0.000000] L2C-310: enabling full line of zeros but not enabled in Cortex-A9
> [    0.000000] L2C-310 ID prefetch enabled, offset 8 lines
> [    0.000000] L2C-310 dynamic clock gating enabled, standby mode enabled
> [    0.000000] L2C-310 cache controller enabled, 16 ways, 1024 kB
> [    0.000000] L2C-310: CACHE_ID 0x4100c4c8, AUX_CTRL 0x7e470001
> [    0.000000] Exynos4x12 clocks: sclk_apll = 1000000000, sclk_mpll = 800000000
> [    0.000000]  sclk_epll = 96000000, sclk_vpll = 350000000, arm_clk = 1000000000
> [    0.000000] Switching to timer-based delay loop, resolution 41ns
> [    0.000000] clocksource: mct-frc: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 79635851949 ns
> [    0.000004] sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 89478484971ns
> [    0.000263] Console: colour dummy device 80x30
> [    0.000978] console [tty1] enabled
> [    0.001003] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=120000)
> [    0.001039] pid_max: default: 32768 minimum: 301
> [    0.001118] Mount-cache hash table entries: 2048 (order: 1, 8192 bytes)
> [    0.001142] Mountpoint-cache hash table entries: 2048 (order: 1, 8192 bytes)
> [    0.001577] CPU: Testing write buffer coherency: ok
> [    0.001875] CPU0: thread -1, cpu 0, socket 10, mpidr 80000a00
> [    0.002240] Setting up static identity map for 0x40100000 - 0x40100058
> [    0.055360] CPU1: thread -1, cpu 1, socket 10, mpidr 80000a01
> [    0.075335] CPU2: thread -1, cpu 2, socket 10, mpidr 80000a02
> [    0.095316] CPU3: thread -1, cpu 3, socket 10, mpidr 80000a03
> [    0.095374] Brought up 4 CPUs
> [    0.095445] SMP: Total of 4 processors activated (192.00 BogoMIPS).
> [    0.095464] CPU: All CPU(s) started in SVC mode.
> [    0.096280] devtmpfs: initialized
> [    0.110373] VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 4
> [    0.110612] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 9556302231375000 ns
> [    0.114190] pinctrl core: initialized pinctrl subsystem
> [    0.114738] lcd0-power-domain at 10023C80 has as child subdomain: tv-power-domain at 10023C20.
> [    0.115573] NET: Registered protocol family 16
> [    0.117150] DMA: preallocated 256 KiB pool for atomic coherent allocations
> [    0.134991] cpuidle: using governor ladder
> [    0.154989] cpuidle: using governor menu
> [    0.155398] hw-breakpoint: found 5 (+1 reserved) breakpoint and 1 watchpoint registers.
> [    0.155434] hw-breakpoint: maximum watchpoint size is 4 bytes.
> [    0.197368] SCSI subsystem initialized
> [    0.197498] usbcore: registered new interface driver usbfs
> [    0.197568] usbcore: registered new interface driver hub
> [    0.197664] usbcore: registered new device driver usb
> [    0.198081] s3c-i2c 13860000.i2c: slave address 0x10
> [    0.198111] s3c-i2c 13860000.i2c: bus frequency set to 390 KHz
> [    0.198570] s3c-i2c 13860000.i2c: i2c-0: S3C I2C adapter
> [    0.198763] s3c-i2c 13870000.i2c: slave address 0x10
> [    0.198791] s3c-i2c 13870000.i2c: bus frequency set to 390 KHz
> [    0.199046] s3c-i2c 13870000.i2c: i2c-1: S3C I2C adapter
> [    0.199192] s3c-i2c 13880000.i2c: slave address 0x00
> [    0.199218] s3c-i2c 13880000.i2c: bus frequency set to 97 KHz
> [    0.199375] s3c-i2c 13880000.i2c: i2c-2: S3C I2C adapter
> [    0.199481] s3c-i2c 138e0000.i2c: slave address 0x00
> [    0.199506] s3c-i2c 138e0000.i2c: bus frequency set to 97 KHz
> [    0.199758] s3c-i2c 138e0000.i2c: i2c-8: S3C I2C adapter
> [    0.200052] Linux video capture interface: v2.00
> [    0.205439] Advanced Linux Sound Architecture Driver Initialized.
> [    0.205901] Bluetooth: Core ver 2.21
> [    0.205947] NET: Registered protocol family 31
> [    0.205966] Bluetooth: HCI device and connection manager initialized
> [    0.205992] Bluetooth: HCI socket layer initialized
> [    0.206014] Bluetooth: L2CAP socket layer initialized
> [    0.206036] Bluetooth: SCO socket layer initialized
> [    0.206567] clocksource: Switched to clocksource mct-frc
> [    0.214799] NET: Registered protocol family 2
> [    0.215264] TCP established hash table entries: 8192 (order: 3, 32768 bytes)
> [    0.215352] TCP bind hash table entries: 8192 (order: 4, 65536 bytes)
> [    0.215463] TCP: Hash tables configured (established 8192 bind 8192)
> [    0.215531] UDP hash table entries: 512 (order: 2, 16384 bytes)
> [    0.215573] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
> [    0.215717] NET: Registered protocol family 1
> [    0.216073] hw perfevents: enabled with armv7_cortex_a9 PMU driver, 7 counters available
> [    0.217474] futex hash table entries: 1024 (order: 4, 65536 bytes)
> [    0.217587] audit: initializing netlink subsys (disabled)
> [    0.217641] audit: type=2000 audit(0.215:1): initialized
> [    0.218191] workingset: timestamp_bits=30 max_order=19 bucket_order=0
> [    0.230957] bounce: pool size: 64 pages
> [    0.231124] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 251)
> [    0.231157] io scheduler noop registered
> [    0.231175] io scheduler deadline registered
> [    0.231306] io scheduler cfq registered (default)
> [    0.231963] 125b0000.exynos-usbphy supply vbus not found, using dummy regulator
> [    0.235681] dma-pl330 12680000.pdma: Loaded driver for PL330 DMAC-141330
> [    0.235717] dma-pl330 12680000.pdma:         DBUFF-32x4bytes Num_Chans-8 Num_Peri-32 Num_Events-32
> [    0.238256] dma-pl330 12690000.pdma: Loaded driver for PL330 DMAC-141330
> [    0.238291] dma-pl330 12690000.pdma:         DBUFF-32x4bytes Num_Chans-8 Num_Peri-32 Num_Events-32
> [    0.239110] dma-pl330 12850000.mdma: Loaded driver for PL330 DMAC-141330
> [    0.239141] dma-pl330 12850000.mdma:         DBUFF-64x8bytes Num_Chans-8 Num_Peri-1 Num_Events-32
> [    0.239800] 13800000.serial: ttySAC0 at MMIO 0x13800000 (irq = 53, base_baud = 0) is a S3C6400/10
> [    0.240144] 13810000.serial: ttySAC1 at MMIO 0x13810000 (irq = 54, base_baud = 0) is a S3C6400/10
> [    1.015731] console [ttySAC1] enabled
> [    1.019770] 13820000.serial: ttySAC2 at MMIO 0x13820000 (irq = 55, base_baud = 0) is a S3C6400/10
> [    1.028570] 13830000.serial: ttySAC3 at MMIO 0x13830000 (irq = 56, base_baud = 0) is a S3C6400/10
> [    1.038157] [drm] Initialized drm 1.1.0 20060810
> [    1.042093] exynos-mixer 12c10000.mixer: Linked as a consumer to 12e20000.sysmmu
> [    1.049118] iommu: Adding device 12c10000.mixer to group 0
> [    1.055403] DEBUG: device_links_driver_bound(): 1
> [    1.059238] ------------[ cut here ]------------
> [    1.063826] WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
> [    1.072851] Modules linked in:
> [    1.075859] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.8.0-vanilla+ #3
> [    1.082458] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
> [    1.088533] Backtrace: 
> [    1.090970] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
> [    1.098524]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
> [    1.104161] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
> [    1.111376] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
> [    1.118306]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
> [    1.123946] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
> [    1.131506]  r9:00000000 r8:c0a258d8 r7:ee3114e4 r6:eeafa874 r5:00000000 r4:ee3114c0
> [    1.139231] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
> [    1.148615] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
> [    1.157287]  r9:00000000 r8:c0a258d8 r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eeafa810
> [    1.165011] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
> [    1.173345]  r4:eeafa810 r3:600000d3
> [    1.176894] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
> [    1.185323]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eeafa844 r5:c0a258d8
> [    1.193128]  r4:eeafa810 r3:00000000
> [    1.196685] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
> [    1.204853]  r6:c0407eb0 r5:c0a258d8 r4:00000000 r3:c0407eb0
> [    1.210485] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
> [    1.218480]  r6:c0a26758 r5:ee27f780 r4:c0a258d8
> [    1.223072] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
> [    1.231072] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
> [    1.239139]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a258d8
> [    1.244773] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
> [    1.253809]  r5:00000000 r4:00000004
> [    1.257364] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
> [    1.266402] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
> [    1.274554]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
> [    1.281232] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
> [    1.289917]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
> [    1.297722]  r4:c093a520
> [    1.300243] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
> [    1.308493]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
> [    1.316297]  r4:00000000
> [    1.318815] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
> [    1.326373]  r4:00000000 r3:ee880000
> [    1.329952] ---[ end trace 402e0b75dfe2947b ]---
> [    1.336115] exynos-hdmi 12d00000.hdmi: Failed to get supply 'vdd': -517
> [    1.341761] s5p-g2d 10800000.g2d: Linked as a consumer to 10a40000.sysmmu
> [    1.347960] iommu: Adding device 10800000.g2d to group 1
> [    1.353512] s5p-g2d 10800000.g2d: The Exynos G2D (ver 4.1) successfully probed.
> [    1.360510] DEBUG: device_links_driver_bound(): 1
> [    1.365183] ------------[ cut here ]------------
> [    1.369786] WARNING: CPU: 1 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
> [    1.378819] Modules linked in:
> [    1.381829] CPU: 1 PID: 1 Comm: swapper/0 Tainted: G        W       4.8.0-vanilla+ #3
> [    1.389651] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
> [    1.395718] Backtrace: 
> [    1.398154] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
> [    1.405709]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
> [    1.411344] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
> [    1.418560] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
> [    1.425491]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
> [    1.431132] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
> [    1.438691]  r9:00000000 r8:c0a2621c r7:ee910ae4 r6:eeac4a74 r5:00000000 r4:ee910ac0
> [    1.446416] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
> [    1.455800] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
> [    1.464472]  r9:00000000 r8:c0a2621c r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eeac4a10
> [    1.472196] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
> [    1.480530]  r4:eeac4a10 r3:00000000
> [    1.484080] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
> [    1.492508]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eeac4a44 r5:c0a2621c
> [    1.500313]  r4:eeac4a10 r3:00000000
> [    1.503870] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
> [    1.512038]  r6:c0407eb0 r5:c0a2621c r4:00000000 r3:c0407eb0
> [    1.517671] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
> [    1.525665]  r6:c0a26758 r5:ee932b80 r4:c0a2621c
> [    1.530257] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
> [    1.538257] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
> [    1.546324]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a2621c
> [    1.551959] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
> [    1.560994]  r5:00000000 r4:0000000a
> [    1.564548] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
> [    1.573587] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
> [    1.581739]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
> [    1.588415] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
> [    1.597103]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
> [    1.604907]  r4:c093a520
> [    1.607427] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
> [    1.615678]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
> [    1.623482]  r4:00000000
> [    1.625999] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
> [    1.633558]  r4:00000000 r3:ee880000
> [    1.637133] ---[ end trace 402e0b75dfe2947c ]---
> [    1.642227] exynos-drm-fimc 11800000.fimc: Linked as a consumer to 11a20000.sysmmu
> [    1.649335] iommu: Adding device 11800000.fimc to group 2
> [    1.655529] exynos-drm-fimc 11810000.fimc: Linked as a consumer to 11a30000.sysmmu
> [    1.662263] iommu: Adding device 11810000.fimc to group 3
> [    1.668447] exynos-drm-fimc 11820000.fimc: Linked as a consumer to 11a40000.sysmmu
> [    1.675196] iommu: Adding device 11820000.fimc to group 4
> [    1.681278] exynos-drm-fimc 11820000.fimc: drm fimc registered successfully.
> [    1.687589] DEBUG: device_links_driver_bound(): 1
> [    1.692264] ------------[ cut here ]------------
> [    1.696852] WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
> [    1.705880] Modules linked in:
> [    1.708891] CPU: 0 PID: 1 Comm: swapper/0 Tainted: G        W       4.8.0-vanilla+ #3
> [    1.716713] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
> [    1.722780] Backtrace: 
> [    1.725216] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
> [    1.732771]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
> [    1.738407] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
> [    1.745624] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
> [    1.752553]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
> [    1.758194] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
> [    1.765754]  r9:00000000 r8:c0a26330 r7:ee311d24 r6:eea83074 r5:00000000 r4:ee311d00
> [    1.773479] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
> [    1.782862] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
> [    1.791534]  r9:00000000 r8:c0a26330 r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eea83010
> [    1.799258] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
> [    1.807592]  r4:eea83010 r3:600000d3
> [    1.811142] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
> [    1.819571]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eea83044 r5:c0a26330
> [    1.827376]  r4:eea83010 r3:00000000
> [    1.830932] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
> [    1.839100]  r6:c0407eb0 r5:c0a26330 r4:00000000 r3:c0407eb0
> [    1.844733] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
> [    1.852728]  r6:c0a26758 r5:ee27fa00 r4:c0a26330
> [    1.857319] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
> [    1.865320] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
> [    1.873386]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a26330
> [    1.879021] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
> [    1.888057]  r5:00000000 r4:0000000b
> [    1.891610] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
> [    1.900649] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
> [    1.908801]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
> [    1.915478] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
> [    1.924165]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
> [    1.931969]  r4:c093a520
> [    1.934489] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
> [    1.942740]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
> [    1.950545]  r4:00000000
> [    1.953062] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
> [    1.960620]  r4:00000000 r3:ee880000
> [    1.964193] ---[ end trace 402e0b75dfe2947d ]---
> [    1.969039] exynos-drm-fimc 11830000.fimc: Linked as a consumer to 11a50000.sysmmu
> [    1.976392] iommu: Adding device 11830000.fimc to group 5
> [    1.982437] exynos-drm-fimc 11830000.fimc: drm fimc registered successfully.
> [    1.988799] DEBUG: device_links_driver_bound(): 1
> [    1.993464] ------------[ cut here ]------------
> [    1.998056] WARNING: CPU: 2 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
> [    2.007076] Modules linked in:
> [    2.010087] CPU: 2 PID: 1 Comm: swapper/0 Tainted: G        W       4.8.0-vanilla+ #3
> [    2.017909] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
> [    2.023975] Backtrace: 
> [    2.026412] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
> [    2.033967]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
> [    2.039603] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
> [    2.046819] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
> [    2.053750]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
> [    2.059390] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
> [    2.066950]  r9:00000000 r8:c0a26330 r7:ee313264 r6:eea83274 r5:00000000 r4:ee313240
> [    2.074675] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
> [    2.084058] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
> [    2.092731]  r9:00000000 r8:c0a26330 r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eea83210
> [    2.100454] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
> [    2.108788]  r4:eea83210 r3:600000d3
> [    2.112338] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
> [    2.120767]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eea83244 r5:c0a26330
> [    2.128571]  r4:eea83210 r3:00000000
> [    2.132128] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
> [    2.140296]  r6:c0407eb0 r5:c0a26330 r4:00000000 r3:c0407eb0
> [    2.145929] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
> [    2.153924]  r6:c0a26758 r5:ee27fa00 r4:c0a26330
> [    2.158516] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
> [    2.166516] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
> [    2.174582]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a26330
> [    2.180217] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
> [    2.189252]  r5:00000000 r4:0000000b
> [    2.192806] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
> [    2.201845] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
> [    2.209997]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
> [    2.216674] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
> [    2.225361]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
> [    2.233165]  r4:c093a520
> [    2.235685] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
> [    2.243936]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
> [    2.251740]  r4:00000000
> [    2.254258] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
> [    2.261816]  r4:00000000 r3:ee880000
> [    2.265388] ---[ end trace 402e0b75dfe2947e ]---
> [    2.270457] exynos-drm-ipp exynos-drm-ipp: drm ipp registered successfully.
> [    2.280368] loop: module loaded
> [    2.293185] random: fast init done
> [    2.303857] usbcore: registered new interface driver smsc95xx
> [    2.491598] dwc2 12480000.hsotg: Specified GNPTXFDEP=1024 > 768
> [    2.491906] dwc2 12480000.hsotg: EPs: 16, dedicated fifos, 7808 entries in SPRAM
> [    2.499801] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
> [    2.505798] ehci-exynos: EHCI EXYNOS driver
> [    2.510438] exynos-ehci 12580000.ehci: EHCI Host Controller
> [    2.515535] exynos-ehci 12580000.ehci: new USB bus registered, assigned bus number 1
> [    2.523434] exynos-ehci 12580000.ehci: irq 51, io mem 0x12580000
> [    2.541596] exynos-ehci 12580000.ehci: USB 2.0 started, EHCI 1.00
> <snip>

I'll try to do another test with just the 5 patches from this set
applied (without the IOMMU probe deferral).

With best wishes,
Tobias



Marek Szyprowski wrote:
> 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-v2
> 
> Patches are based on vanilla v4.8-rc7 kernel.
> 
> Best regards
> Marek Szyprowski
> Samsung R&D Institute Poland
> 
> Changelog:
> v2:
> - Simplified clk_pm_runtime_get/put functions, removed workaround for devices
>   with disabled runtime pm. Such workaround is no longer needed since commit
>   4d23a5e84806b202d9231929c9507ef7cf7a0185 ("PM / Domains: Allow runtime PM
>   during system PM phases").
> - Added CLK_RUNTIME_PM flag to indicate clocks, for which clock core should
>   call runtime pm functions. This solves problem with clocks, for which struct
>   device is already registered, but no runtime pm is enabled.
> - Extended commit messages according to Ulf suggestions.
> - Fixed some style issues pointed by Barlomiej.
> 
> v1: http://www.spinics.net/lists/arm-kernel/msg528128.html
> - initial version
> 
> 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                                  | 107 +++++-
>  drivers/clk/samsung/clk-exynos4.c                  | 227 ++++++++----
>  drivers/clk/samsung/clk-exynos5433.c               | 385 ++++++++++++++++-----
>  drivers/clk/samsung/clk-pll.c                      |   4 +-
>  drivers/clk/samsung/clk.c                          |  36 +-
>  drivers/clk/samsung/clk.h                          |   7 +
>  include/linux/clk-provider.h                       |   1 +
>  9 files changed, 632 insertions(+), 162 deletions(-)
> 

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

* Re: [PATCH v2 0/5] Add runtime PM support for clocks (on Exynos SoC example)
  2016-10-06 18:05     ` Tobias Jakobi
@ 2016-10-06 18:07       ` Tobias Jakobi
  -1 siblings, 0 replies; 27+ messages in thread
From: Tobias Jakobi @ 2016-10-06 18:07 UTC (permalink / raw)
  To: Tobias Jakobi, Marek Szyprowski, linux-clk, linux-pm,
	linux-samsung-soc, linux-arm-kernel
  Cc: Stephen Boyd, Michael Turquette, Ulf Hansson, Sylwester Nawrocki,
	Chanwoo Choi, Inki Dae, Krzysztof Kozlowski,
	Bartlomiej Zolnierkiewicz

For reference, the build was done with this config:
https://github.com/tobiasjakobi/odroid-environment/blob/master/sourcecode/system/vanilla-4.8.conf

- Tobias


Tobias Jakobi wrote:
> Hello Marek,
> 
> I'm using the patches from the v4.8-clocks-pm-v2 branch plus the ones
> from the v4.8-clocks-pm-v2 branch on top of 4.8.0.
> 
> I see some warnings on boot coming from driver core. It appears that the
> warnings are actually meaningful, since IOMMUs stop working completly.
> E.g. if I modprobe s5p-mfc later, firmware loading fails because
> apparantly the IOMMU domain isn't online.
> 
>> WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
> 
> I added some debug printk() to device_links_driver_bound(), to show the
> link status. Apparantly it is always DEVICE_LINK_AVAILABLE.
> 
> Here's the (semi) full log:
>> [    0.000000] Booting Linux on physical CPU 0xa00
>> [    0.000000] Linux version 4.8.0-vanilla+ (liquid@chidori) (gcc version 4.9.3 (Gentoo 4.9.3 p1.5, pie-0.6.4) ) #3 SMP PREEMPT Thu Oct 6 19:14:15 CEST 2016
>> [    0.000000] CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=10c5387d
>> [    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
>> [    0.000000] OF: fdt:Machine model: Hardkernel ODROID-X2 board based on Exynos4412
>> [    0.000000] Reserved memory: created DMA memory pool at 0xbf700000, size 8 MiB
>> [    0.000000] OF: reserved mem: initialized node region_mfc_right, compatible id shared-dma-pool
>> [    0.000000] Reserved memory: created DMA memory pool at 0xbe700000, size 16 MiB
>> [    0.000000] OF: reserved mem: initialized node region_mfc_left, compatible id shared-dma-pool
>> [    0.000000] cma: Reserved 128 MiB at 0xb6400000
>> [    0.000000] Memory policy: Data cache writealloc
>> [    0.000000] Samsung CPU ID: 0xe4412220
>> [    0.000000] Running under secure firmware.
>> [    0.000000] percpu: Embedded 14 pages/cpu @eefb3000 s26176 r8192 d22976 u57344
>> [    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 516352
>> [    0.000000] Kernel command line: video=HDMI-A-1:1280x720M@60 console=ttySAC1,115200n8 root=PARTUUID=8c900d97-367f-47a9-bd66-6eced1a29836 rootfstype=f2fs rootwait ro earlyprintk console=tty1 console=ttySAC1,115200
>> [    0.000000] PID hash table entries: 4096 (order: 2, 16384 bytes)
>> [    0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
>> [    0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
>> [    0.000000] Memory: 1913244K/2071552K available (6144K kernel code, 223K rwdata, 1432K rodata, 1024K init, 246K bss, 27236K reserved, 131072K cma-reserved, 1154048K highmem)
>> [    0.000000] Virtual kernel memory layout:
>> [    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
>> [    0.000000]     fixmap  : 0xffc00000 - 0xfff00000   (3072 kB)
>> [    0.000000]     vmalloc : 0xf0800000 - 0xff800000   ( 240 MB)
>> [    0.000000]     lowmem  : 0xc0000000 - 0xf0000000   ( 768 MB)
>> [    0.000000]     pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)
>> [    0.000000]     modules : 0xbf000000 - 0xbfe00000   (  14 MB)
>> [    0.000000]       .text : 0xc0008000 - 0xc0700000   (7136 kB)
>> [    0.000000]       .init : 0xc0900000 - 0xc0a00000   (1024 kB)
>> [    0.000000]       .data : 0xc0a00000 - 0xc0a37fc0   ( 224 kB)
>> [    0.000000]        .bss : 0xc0a39000 - 0xc0a76a08   ( 247 kB)
>> [    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
>> [    0.000000] Preemptible hierarchical RCU implementation.
>> [    0.000000]  Build-time adjustment of leaf fanout to 32.
>> [    0.000000] NR_IRQS:16 nr_irqs:16 16
>> [    0.000000] L2C: platform modifies aux control register: 0x02070000 -> 0x3e470001
>> [    0.000000] L2C: platform provided aux values permit register corruption.
>> [    0.000000] L2C: DT/platform modifies aux control register: 0x02070000 -> 0x3e470001
>> [    0.000000] L2C-310 enabling early BRESP for Cortex-A9
>> [    0.000000] L2C-310: enabling full line of zeros but not enabled in Cortex-A9
>> [    0.000000] L2C-310 ID prefetch enabled, offset 8 lines
>> [    0.000000] L2C-310 dynamic clock gating enabled, standby mode enabled
>> [    0.000000] L2C-310 cache controller enabled, 16 ways, 1024 kB
>> [    0.000000] L2C-310: CACHE_ID 0x4100c4c8, AUX_CTRL 0x7e470001
>> [    0.000000] Exynos4x12 clocks: sclk_apll = 1000000000, sclk_mpll = 800000000
>> [    0.000000]  sclk_epll = 96000000, sclk_vpll = 350000000, arm_clk = 1000000000
>> [    0.000000] Switching to timer-based delay loop, resolution 41ns
>> [    0.000000] clocksource: mct-frc: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 79635851949 ns
>> [    0.000004] sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 89478484971ns
>> [    0.000263] Console: colour dummy device 80x30
>> [    0.000978] console [tty1] enabled
>> [    0.001003] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=120000)
>> [    0.001039] pid_max: default: 32768 minimum: 301
>> [    0.001118] Mount-cache hash table entries: 2048 (order: 1, 8192 bytes)
>> [    0.001142] Mountpoint-cache hash table entries: 2048 (order: 1, 8192 bytes)
>> [    0.001577] CPU: Testing write buffer coherency: ok
>> [    0.001875] CPU0: thread -1, cpu 0, socket 10, mpidr 80000a00
>> [    0.002240] Setting up static identity map for 0x40100000 - 0x40100058
>> [    0.055360] CPU1: thread -1, cpu 1, socket 10, mpidr 80000a01
>> [    0.075335] CPU2: thread -1, cpu 2, socket 10, mpidr 80000a02
>> [    0.095316] CPU3: thread -1, cpu 3, socket 10, mpidr 80000a03
>> [    0.095374] Brought up 4 CPUs
>> [    0.095445] SMP: Total of 4 processors activated (192.00 BogoMIPS).
>> [    0.095464] CPU: All CPU(s) started in SVC mode.
>> [    0.096280] devtmpfs: initialized
>> [    0.110373] VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 4
>> [    0.110612] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 9556302231375000 ns
>> [    0.114190] pinctrl core: initialized pinctrl subsystem
>> [    0.114738] lcd0-power-domain@10023C80 has as child subdomain: tv-power-domain@10023C20.
>> [    0.115573] NET: Registered protocol family 16
>> [    0.117150] DMA: preallocated 256 KiB pool for atomic coherent allocations
>> [    0.134991] cpuidle: using governor ladder
>> [    0.154989] cpuidle: using governor menu
>> [    0.155398] hw-breakpoint: found 5 (+1 reserved) breakpoint and 1 watchpoint registers.
>> [    0.155434] hw-breakpoint: maximum watchpoint size is 4 bytes.
>> [    0.197368] SCSI subsystem initialized
>> [    0.197498] usbcore: registered new interface driver usbfs
>> [    0.197568] usbcore: registered new interface driver hub
>> [    0.197664] usbcore: registered new device driver usb
>> [    0.198081] s3c-i2c 13860000.i2c: slave address 0x10
>> [    0.198111] s3c-i2c 13860000.i2c: bus frequency set to 390 KHz
>> [    0.198570] s3c-i2c 13860000.i2c: i2c-0: S3C I2C adapter
>> [    0.198763] s3c-i2c 13870000.i2c: slave address 0x10
>> [    0.198791] s3c-i2c 13870000.i2c: bus frequency set to 390 KHz
>> [    0.199046] s3c-i2c 13870000.i2c: i2c-1: S3C I2C adapter
>> [    0.199192] s3c-i2c 13880000.i2c: slave address 0x00
>> [    0.199218] s3c-i2c 13880000.i2c: bus frequency set to 97 KHz
>> [    0.199375] s3c-i2c 13880000.i2c: i2c-2: S3C I2C adapter
>> [    0.199481] s3c-i2c 138e0000.i2c: slave address 0x00
>> [    0.199506] s3c-i2c 138e0000.i2c: bus frequency set to 97 KHz
>> [    0.199758] s3c-i2c 138e0000.i2c: i2c-8: S3C I2C adapter
>> [    0.200052] Linux video capture interface: v2.00
>> [    0.205439] Advanced Linux Sound Architecture Driver Initialized.
>> [    0.205901] Bluetooth: Core ver 2.21
>> [    0.205947] NET: Registered protocol family 31
>> [    0.205966] Bluetooth: HCI device and connection manager initialized
>> [    0.205992] Bluetooth: HCI socket layer initialized
>> [    0.206014] Bluetooth: L2CAP socket layer initialized
>> [    0.206036] Bluetooth: SCO socket layer initialized
>> [    0.206567] clocksource: Switched to clocksource mct-frc
>> [    0.214799] NET: Registered protocol family 2
>> [    0.215264] TCP established hash table entries: 8192 (order: 3, 32768 bytes)
>> [    0.215352] TCP bind hash table entries: 8192 (order: 4, 65536 bytes)
>> [    0.215463] TCP: Hash tables configured (established 8192 bind 8192)
>> [    0.215531] UDP hash table entries: 512 (order: 2, 16384 bytes)
>> [    0.215573] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
>> [    0.215717] NET: Registered protocol family 1
>> [    0.216073] hw perfevents: enabled with armv7_cortex_a9 PMU driver, 7 counters available
>> [    0.217474] futex hash table entries: 1024 (order: 4, 65536 bytes)
>> [    0.217587] audit: initializing netlink subsys (disabled)
>> [    0.217641] audit: type=2000 audit(0.215:1): initialized
>> [    0.218191] workingset: timestamp_bits=30 max_order=19 bucket_order=0
>> [    0.230957] bounce: pool size: 64 pages
>> [    0.231124] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 251)
>> [    0.231157] io scheduler noop registered
>> [    0.231175] io scheduler deadline registered
>> [    0.231306] io scheduler cfq registered (default)
>> [    0.231963] 125b0000.exynos-usbphy supply vbus not found, using dummy regulator
>> [    0.235681] dma-pl330 12680000.pdma: Loaded driver for PL330 DMAC-141330
>> [    0.235717] dma-pl330 12680000.pdma:         DBUFF-32x4bytes Num_Chans-8 Num_Peri-32 Num_Events-32
>> [    0.238256] dma-pl330 12690000.pdma: Loaded driver for PL330 DMAC-141330
>> [    0.238291] dma-pl330 12690000.pdma:         DBUFF-32x4bytes Num_Chans-8 Num_Peri-32 Num_Events-32
>> [    0.239110] dma-pl330 12850000.mdma: Loaded driver for PL330 DMAC-141330
>> [    0.239141] dma-pl330 12850000.mdma:         DBUFF-64x8bytes Num_Chans-8 Num_Peri-1 Num_Events-32
>> [    0.239800] 13800000.serial: ttySAC0 at MMIO 0x13800000 (irq = 53, base_baud = 0) is a S3C6400/10
>> [    0.240144] 13810000.serial: ttySAC1 at MMIO 0x13810000 (irq = 54, base_baud = 0) is a S3C6400/10
>> [    1.015731] console [ttySAC1] enabled
>> [    1.019770] 13820000.serial: ttySAC2 at MMIO 0x13820000 (irq = 55, base_baud = 0) is a S3C6400/10
>> [    1.028570] 13830000.serial: ttySAC3 at MMIO 0x13830000 (irq = 56, base_baud = 0) is a S3C6400/10
>> [    1.038157] [drm] Initialized drm 1.1.0 20060810
>> [    1.042093] exynos-mixer 12c10000.mixer: Linked as a consumer to 12e20000.sysmmu
>> [    1.049118] iommu: Adding device 12c10000.mixer to group 0
>> [    1.055403] DEBUG: device_links_driver_bound(): 1
>> [    1.059238] ------------[ cut here ]------------
>> [    1.063826] WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
>> [    1.072851] Modules linked in:
>> [    1.075859] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.8.0-vanilla+ #3
>> [    1.082458] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
>> [    1.088533] Backtrace: 
>> [    1.090970] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
>> [    1.098524]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
>> [    1.104161] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
>> [    1.111376] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
>> [    1.118306]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
>> [    1.123946] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
>> [    1.131506]  r9:00000000 r8:c0a258d8 r7:ee3114e4 r6:eeafa874 r5:00000000 r4:ee3114c0
>> [    1.139231] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
>> [    1.148615] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
>> [    1.157287]  r9:00000000 r8:c0a258d8 r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eeafa810
>> [    1.165011] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
>> [    1.173345]  r4:eeafa810 r3:600000d3
>> [    1.176894] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
>> [    1.185323]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eeafa844 r5:c0a258d8
>> [    1.193128]  r4:eeafa810 r3:00000000
>> [    1.196685] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
>> [    1.204853]  r6:c0407eb0 r5:c0a258d8 r4:00000000 r3:c0407eb0
>> [    1.210485] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
>> [    1.218480]  r6:c0a26758 r5:ee27f780 r4:c0a258d8
>> [    1.223072] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
>> [    1.231072] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
>> [    1.239139]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a258d8
>> [    1.244773] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
>> [    1.253809]  r5:00000000 r4:00000004
>> [    1.257364] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
>> [    1.266402] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
>> [    1.274554]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
>> [    1.281232] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
>> [    1.289917]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
>> [    1.297722]  r4:c093a520
>> [    1.300243] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
>> [    1.308493]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
>> [    1.316297]  r4:00000000
>> [    1.318815] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
>> [    1.326373]  r4:00000000 r3:ee880000
>> [    1.329952] ---[ end trace 402e0b75dfe2947b ]---
>> [    1.336115] exynos-hdmi 12d00000.hdmi: Failed to get supply 'vdd': -517
>> [    1.341761] s5p-g2d 10800000.g2d: Linked as a consumer to 10a40000.sysmmu
>> [    1.347960] iommu: Adding device 10800000.g2d to group 1
>> [    1.353512] s5p-g2d 10800000.g2d: The Exynos G2D (ver 4.1) successfully probed.
>> [    1.360510] DEBUG: device_links_driver_bound(): 1
>> [    1.365183] ------------[ cut here ]------------
>> [    1.369786] WARNING: CPU: 1 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
>> [    1.378819] Modules linked in:
>> [    1.381829] CPU: 1 PID: 1 Comm: swapper/0 Tainted: G        W       4.8.0-vanilla+ #3
>> [    1.389651] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
>> [    1.395718] Backtrace: 
>> [    1.398154] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
>> [    1.405709]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
>> [    1.411344] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
>> [    1.418560] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
>> [    1.425491]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
>> [    1.431132] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
>> [    1.438691]  r9:00000000 r8:c0a2621c r7:ee910ae4 r6:eeac4a74 r5:00000000 r4:ee910ac0
>> [    1.446416] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
>> [    1.455800] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
>> [    1.464472]  r9:00000000 r8:c0a2621c r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eeac4a10
>> [    1.472196] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
>> [    1.480530]  r4:eeac4a10 r3:00000000
>> [    1.484080] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
>> [    1.492508]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eeac4a44 r5:c0a2621c
>> [    1.500313]  r4:eeac4a10 r3:00000000
>> [    1.503870] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
>> [    1.512038]  r6:c0407eb0 r5:c0a2621c r4:00000000 r3:c0407eb0
>> [    1.517671] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
>> [    1.525665]  r6:c0a26758 r5:ee932b80 r4:c0a2621c
>> [    1.530257] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
>> [    1.538257] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
>> [    1.546324]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a2621c
>> [    1.551959] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
>> [    1.560994]  r5:00000000 r4:0000000a
>> [    1.564548] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
>> [    1.573587] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
>> [    1.581739]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
>> [    1.588415] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
>> [    1.597103]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
>> [    1.604907]  r4:c093a520
>> [    1.607427] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
>> [    1.615678]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
>> [    1.623482]  r4:00000000
>> [    1.625999] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
>> [    1.633558]  r4:00000000 r3:ee880000
>> [    1.637133] ---[ end trace 402e0b75dfe2947c ]---
>> [    1.642227] exynos-drm-fimc 11800000.fimc: Linked as a consumer to 11a20000.sysmmu
>> [    1.649335] iommu: Adding device 11800000.fimc to group 2
>> [    1.655529] exynos-drm-fimc 11810000.fimc: Linked as a consumer to 11a30000.sysmmu
>> [    1.662263] iommu: Adding device 11810000.fimc to group 3
>> [    1.668447] exynos-drm-fimc 11820000.fimc: Linked as a consumer to 11a40000.sysmmu
>> [    1.675196] iommu: Adding device 11820000.fimc to group 4
>> [    1.681278] exynos-drm-fimc 11820000.fimc: drm fimc registered successfully.
>> [    1.687589] DEBUG: device_links_driver_bound(): 1
>> [    1.692264] ------------[ cut here ]------------
>> [    1.696852] WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
>> [    1.705880] Modules linked in:
>> [    1.708891] CPU: 0 PID: 1 Comm: swapper/0 Tainted: G        W       4.8.0-vanilla+ #3
>> [    1.716713] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
>> [    1.722780] Backtrace: 
>> [    1.725216] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
>> [    1.732771]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
>> [    1.738407] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
>> [    1.745624] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
>> [    1.752553]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
>> [    1.758194] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
>> [    1.765754]  r9:00000000 r8:c0a26330 r7:ee311d24 r6:eea83074 r5:00000000 r4:ee311d00
>> [    1.773479] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
>> [    1.782862] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
>> [    1.791534]  r9:00000000 r8:c0a26330 r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eea83010
>> [    1.799258] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
>> [    1.807592]  r4:eea83010 r3:600000d3
>> [    1.811142] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
>> [    1.819571]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eea83044 r5:c0a26330
>> [    1.827376]  r4:eea83010 r3:00000000
>> [    1.830932] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
>> [    1.839100]  r6:c0407eb0 r5:c0a26330 r4:00000000 r3:c0407eb0
>> [    1.844733] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
>> [    1.852728]  r6:c0a26758 r5:ee27fa00 r4:c0a26330
>> [    1.857319] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
>> [    1.865320] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
>> [    1.873386]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a26330
>> [    1.879021] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
>> [    1.888057]  r5:00000000 r4:0000000b
>> [    1.891610] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
>> [    1.900649] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
>> [    1.908801]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
>> [    1.915478] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
>> [    1.924165]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
>> [    1.931969]  r4:c093a520
>> [    1.934489] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
>> [    1.942740]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
>> [    1.950545]  r4:00000000
>> [    1.953062] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
>> [    1.960620]  r4:00000000 r3:ee880000
>> [    1.964193] ---[ end trace 402e0b75dfe2947d ]---
>> [    1.969039] exynos-drm-fimc 11830000.fimc: Linked as a consumer to 11a50000.sysmmu
>> [    1.976392] iommu: Adding device 11830000.fimc to group 5
>> [    1.982437] exynos-drm-fimc 11830000.fimc: drm fimc registered successfully.
>> [    1.988799] DEBUG: device_links_driver_bound(): 1
>> [    1.993464] ------------[ cut here ]------------
>> [    1.998056] WARNING: CPU: 2 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
>> [    2.007076] Modules linked in:
>> [    2.010087] CPU: 2 PID: 1 Comm: swapper/0 Tainted: G        W       4.8.0-vanilla+ #3
>> [    2.017909] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
>> [    2.023975] Backtrace: 
>> [    2.026412] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
>> [    2.033967]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
>> [    2.039603] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
>> [    2.046819] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
>> [    2.053750]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
>> [    2.059390] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
>> [    2.066950]  r9:00000000 r8:c0a26330 r7:ee313264 r6:eea83274 r5:00000000 r4:ee313240
>> [    2.074675] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
>> [    2.084058] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
>> [    2.092731]  r9:00000000 r8:c0a26330 r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eea83210
>> [    2.100454] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
>> [    2.108788]  r4:eea83210 r3:600000d3
>> [    2.112338] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
>> [    2.120767]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eea83244 r5:c0a26330
>> [    2.128571]  r4:eea83210 r3:00000000
>> [    2.132128] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
>> [    2.140296]  r6:c0407eb0 r5:c0a26330 r4:00000000 r3:c0407eb0
>> [    2.145929] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
>> [    2.153924]  r6:c0a26758 r5:ee27fa00 r4:c0a26330
>> [    2.158516] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
>> [    2.166516] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
>> [    2.174582]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a26330
>> [    2.180217] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
>> [    2.189252]  r5:00000000 r4:0000000b
>> [    2.192806] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
>> [    2.201845] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
>> [    2.209997]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
>> [    2.216674] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
>> [    2.225361]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
>> [    2.233165]  r4:c093a520
>> [    2.235685] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
>> [    2.243936]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
>> [    2.251740]  r4:00000000
>> [    2.254258] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
>> [    2.261816]  r4:00000000 r3:ee880000
>> [    2.265388] ---[ end trace 402e0b75dfe2947e ]---
>> [    2.270457] exynos-drm-ipp exynos-drm-ipp: drm ipp registered successfully.
>> [    2.280368] loop: module loaded
>> [    2.293185] random: fast init done
>> [    2.303857] usbcore: registered new interface driver smsc95xx
>> [    2.491598] dwc2 12480000.hsotg: Specified GNPTXFDEP=1024 > 768
>> [    2.491906] dwc2 12480000.hsotg: EPs: 16, dedicated fifos, 7808 entries in SPRAM
>> [    2.499801] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
>> [    2.505798] ehci-exynos: EHCI EXYNOS driver
>> [    2.510438] exynos-ehci 12580000.ehci: EHCI Host Controller
>> [    2.515535] exynos-ehci 12580000.ehci: new USB bus registered, assigned bus number 1
>> [    2.523434] exynos-ehci 12580000.ehci: irq 51, io mem 0x12580000
>> [    2.541596] exynos-ehci 12580000.ehci: USB 2.0 started, EHCI 1.00
>> <snip>
> 
> I'll try to do another test with just the 5 patches from this set
> applied (without the IOMMU probe deferral).
> 
> With best wishes,
> Tobias
> 
> 
> 
> Marek Szyprowski wrote:
>> 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-v2
>>
>> Patches are based on vanilla v4.8-rc7 kernel.
>>
>> Best regards
>> Marek Szyprowski
>> Samsung R&D Institute Poland
>>
>> Changelog:
>> v2:
>> - Simplified clk_pm_runtime_get/put functions, removed workaround for devices
>>   with disabled runtime pm. Such workaround is no longer needed since commit
>>   4d23a5e84806b202d9231929c9507ef7cf7a0185 ("PM / Domains: Allow runtime PM
>>   during system PM phases").
>> - Added CLK_RUNTIME_PM flag to indicate clocks, for which clock core should
>>   call runtime pm functions. This solves problem with clocks, for which struct
>>   device is already registered, but no runtime pm is enabled.
>> - Extended commit messages according to Ulf suggestions.
>> - Fixed some style issues pointed by Barlomiej.
>>
>> v1: http://www.spinics.net/lists/arm-kernel/msg528128.html
>> - initial version
>>
>> 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                                  | 107 +++++-
>>  drivers/clk/samsung/clk-exynos4.c                  | 227 ++++++++----
>>  drivers/clk/samsung/clk-exynos5433.c               | 385 ++++++++++++++++-----
>>  drivers/clk/samsung/clk-pll.c                      |   4 +-
>>  drivers/clk/samsung/clk.c                          |  36 +-
>>  drivers/clk/samsung/clk.h                          |   7 +
>>  include/linux/clk-provider.h                       |   1 +
>>  9 files changed, 632 insertions(+), 162 deletions(-)
>>
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

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

* [PATCH v2 0/5] Add runtime PM support for clocks (on Exynos SoC example)
@ 2016-10-06 18:07       ` Tobias Jakobi
  0 siblings, 0 replies; 27+ messages in thread
From: Tobias Jakobi @ 2016-10-06 18:07 UTC (permalink / raw)
  To: linux-arm-kernel

For reference, the build was done with this config:
https://github.com/tobiasjakobi/odroid-environment/blob/master/sourcecode/system/vanilla-4.8.conf

- Tobias


Tobias Jakobi wrote:
> Hello Marek,
> 
> I'm using the patches from the v4.8-clocks-pm-v2 branch plus the ones
> from the v4.8-clocks-pm-v2 branch on top of 4.8.0.
> 
> I see some warnings on boot coming from driver core. It appears that the
> warnings are actually meaningful, since IOMMUs stop working completly.
> E.g. if I modprobe s5p-mfc later, firmware loading fails because
> apparantly the IOMMU domain isn't online.
> 
>> WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
> 
> I added some debug printk() to device_links_driver_bound(), to show the
> link status. Apparantly it is always DEVICE_LINK_AVAILABLE.
> 
> Here's the (semi) full log:
>> [    0.000000] Booting Linux on physical CPU 0xa00
>> [    0.000000] Linux version 4.8.0-vanilla+ (liquid at chidori) (gcc version 4.9.3 (Gentoo 4.9.3 p1.5, pie-0.6.4) ) #3 SMP PREEMPT Thu Oct 6 19:14:15 CEST 2016
>> [    0.000000] CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=10c5387d
>> [    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
>> [    0.000000] OF: fdt:Machine model: Hardkernel ODROID-X2 board based on Exynos4412
>> [    0.000000] Reserved memory: created DMA memory pool at 0xbf700000, size 8 MiB
>> [    0.000000] OF: reserved mem: initialized node region_mfc_right, compatible id shared-dma-pool
>> [    0.000000] Reserved memory: created DMA memory pool at 0xbe700000, size 16 MiB
>> [    0.000000] OF: reserved mem: initialized node region_mfc_left, compatible id shared-dma-pool
>> [    0.000000] cma: Reserved 128 MiB at 0xb6400000
>> [    0.000000] Memory policy: Data cache writealloc
>> [    0.000000] Samsung CPU ID: 0xe4412220
>> [    0.000000] Running under secure firmware.
>> [    0.000000] percpu: Embedded 14 pages/cpu @eefb3000 s26176 r8192 d22976 u57344
>> [    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 516352
>> [    0.000000] Kernel command line: video=HDMI-A-1:1280x720M at 60 console=ttySAC1,115200n8 root=PARTUUID=8c900d97-367f-47a9-bd66-6eced1a29836 rootfstype=f2fs rootwait ro earlyprintk console=tty1 console=ttySAC1,115200
>> [    0.000000] PID hash table entries: 4096 (order: 2, 16384 bytes)
>> [    0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
>> [    0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
>> [    0.000000] Memory: 1913244K/2071552K available (6144K kernel code, 223K rwdata, 1432K rodata, 1024K init, 246K bss, 27236K reserved, 131072K cma-reserved, 1154048K highmem)
>> [    0.000000] Virtual kernel memory layout:
>> [    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
>> [    0.000000]     fixmap  : 0xffc00000 - 0xfff00000   (3072 kB)
>> [    0.000000]     vmalloc : 0xf0800000 - 0xff800000   ( 240 MB)
>> [    0.000000]     lowmem  : 0xc0000000 - 0xf0000000   ( 768 MB)
>> [    0.000000]     pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)
>> [    0.000000]     modules : 0xbf000000 - 0xbfe00000   (  14 MB)
>> [    0.000000]       .text : 0xc0008000 - 0xc0700000   (7136 kB)
>> [    0.000000]       .init : 0xc0900000 - 0xc0a00000   (1024 kB)
>> [    0.000000]       .data : 0xc0a00000 - 0xc0a37fc0   ( 224 kB)
>> [    0.000000]        .bss : 0xc0a39000 - 0xc0a76a08   ( 247 kB)
>> [    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
>> [    0.000000] Preemptible hierarchical RCU implementation.
>> [    0.000000]  Build-time adjustment of leaf fanout to 32.
>> [    0.000000] NR_IRQS:16 nr_irqs:16 16
>> [    0.000000] L2C: platform modifies aux control register: 0x02070000 -> 0x3e470001
>> [    0.000000] L2C: platform provided aux values permit register corruption.
>> [    0.000000] L2C: DT/platform modifies aux control register: 0x02070000 -> 0x3e470001
>> [    0.000000] L2C-310 enabling early BRESP for Cortex-A9
>> [    0.000000] L2C-310: enabling full line of zeros but not enabled in Cortex-A9
>> [    0.000000] L2C-310 ID prefetch enabled, offset 8 lines
>> [    0.000000] L2C-310 dynamic clock gating enabled, standby mode enabled
>> [    0.000000] L2C-310 cache controller enabled, 16 ways, 1024 kB
>> [    0.000000] L2C-310: CACHE_ID 0x4100c4c8, AUX_CTRL 0x7e470001
>> [    0.000000] Exynos4x12 clocks: sclk_apll = 1000000000, sclk_mpll = 800000000
>> [    0.000000]  sclk_epll = 96000000, sclk_vpll = 350000000, arm_clk = 1000000000
>> [    0.000000] Switching to timer-based delay loop, resolution 41ns
>> [    0.000000] clocksource: mct-frc: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 79635851949 ns
>> [    0.000004] sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 89478484971ns
>> [    0.000263] Console: colour dummy device 80x30
>> [    0.000978] console [tty1] enabled
>> [    0.001003] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=120000)
>> [    0.001039] pid_max: default: 32768 minimum: 301
>> [    0.001118] Mount-cache hash table entries: 2048 (order: 1, 8192 bytes)
>> [    0.001142] Mountpoint-cache hash table entries: 2048 (order: 1, 8192 bytes)
>> [    0.001577] CPU: Testing write buffer coherency: ok
>> [    0.001875] CPU0: thread -1, cpu 0, socket 10, mpidr 80000a00
>> [    0.002240] Setting up static identity map for 0x40100000 - 0x40100058
>> [    0.055360] CPU1: thread -1, cpu 1, socket 10, mpidr 80000a01
>> [    0.075335] CPU2: thread -1, cpu 2, socket 10, mpidr 80000a02
>> [    0.095316] CPU3: thread -1, cpu 3, socket 10, mpidr 80000a03
>> [    0.095374] Brought up 4 CPUs
>> [    0.095445] SMP: Total of 4 processors activated (192.00 BogoMIPS).
>> [    0.095464] CPU: All CPU(s) started in SVC mode.
>> [    0.096280] devtmpfs: initialized
>> [    0.110373] VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 4
>> [    0.110612] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 9556302231375000 ns
>> [    0.114190] pinctrl core: initialized pinctrl subsystem
>> [    0.114738] lcd0-power-domain at 10023C80 has as child subdomain: tv-power-domain at 10023C20.
>> [    0.115573] NET: Registered protocol family 16
>> [    0.117150] DMA: preallocated 256 KiB pool for atomic coherent allocations
>> [    0.134991] cpuidle: using governor ladder
>> [    0.154989] cpuidle: using governor menu
>> [    0.155398] hw-breakpoint: found 5 (+1 reserved) breakpoint and 1 watchpoint registers.
>> [    0.155434] hw-breakpoint: maximum watchpoint size is 4 bytes.
>> [    0.197368] SCSI subsystem initialized
>> [    0.197498] usbcore: registered new interface driver usbfs
>> [    0.197568] usbcore: registered new interface driver hub
>> [    0.197664] usbcore: registered new device driver usb
>> [    0.198081] s3c-i2c 13860000.i2c: slave address 0x10
>> [    0.198111] s3c-i2c 13860000.i2c: bus frequency set to 390 KHz
>> [    0.198570] s3c-i2c 13860000.i2c: i2c-0: S3C I2C adapter
>> [    0.198763] s3c-i2c 13870000.i2c: slave address 0x10
>> [    0.198791] s3c-i2c 13870000.i2c: bus frequency set to 390 KHz
>> [    0.199046] s3c-i2c 13870000.i2c: i2c-1: S3C I2C adapter
>> [    0.199192] s3c-i2c 13880000.i2c: slave address 0x00
>> [    0.199218] s3c-i2c 13880000.i2c: bus frequency set to 97 KHz
>> [    0.199375] s3c-i2c 13880000.i2c: i2c-2: S3C I2C adapter
>> [    0.199481] s3c-i2c 138e0000.i2c: slave address 0x00
>> [    0.199506] s3c-i2c 138e0000.i2c: bus frequency set to 97 KHz
>> [    0.199758] s3c-i2c 138e0000.i2c: i2c-8: S3C I2C adapter
>> [    0.200052] Linux video capture interface: v2.00
>> [    0.205439] Advanced Linux Sound Architecture Driver Initialized.
>> [    0.205901] Bluetooth: Core ver 2.21
>> [    0.205947] NET: Registered protocol family 31
>> [    0.205966] Bluetooth: HCI device and connection manager initialized
>> [    0.205992] Bluetooth: HCI socket layer initialized
>> [    0.206014] Bluetooth: L2CAP socket layer initialized
>> [    0.206036] Bluetooth: SCO socket layer initialized
>> [    0.206567] clocksource: Switched to clocksource mct-frc
>> [    0.214799] NET: Registered protocol family 2
>> [    0.215264] TCP established hash table entries: 8192 (order: 3, 32768 bytes)
>> [    0.215352] TCP bind hash table entries: 8192 (order: 4, 65536 bytes)
>> [    0.215463] TCP: Hash tables configured (established 8192 bind 8192)
>> [    0.215531] UDP hash table entries: 512 (order: 2, 16384 bytes)
>> [    0.215573] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
>> [    0.215717] NET: Registered protocol family 1
>> [    0.216073] hw perfevents: enabled with armv7_cortex_a9 PMU driver, 7 counters available
>> [    0.217474] futex hash table entries: 1024 (order: 4, 65536 bytes)
>> [    0.217587] audit: initializing netlink subsys (disabled)
>> [    0.217641] audit: type=2000 audit(0.215:1): initialized
>> [    0.218191] workingset: timestamp_bits=30 max_order=19 bucket_order=0
>> [    0.230957] bounce: pool size: 64 pages
>> [    0.231124] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 251)
>> [    0.231157] io scheduler noop registered
>> [    0.231175] io scheduler deadline registered
>> [    0.231306] io scheduler cfq registered (default)
>> [    0.231963] 125b0000.exynos-usbphy supply vbus not found, using dummy regulator
>> [    0.235681] dma-pl330 12680000.pdma: Loaded driver for PL330 DMAC-141330
>> [    0.235717] dma-pl330 12680000.pdma:         DBUFF-32x4bytes Num_Chans-8 Num_Peri-32 Num_Events-32
>> [    0.238256] dma-pl330 12690000.pdma: Loaded driver for PL330 DMAC-141330
>> [    0.238291] dma-pl330 12690000.pdma:         DBUFF-32x4bytes Num_Chans-8 Num_Peri-32 Num_Events-32
>> [    0.239110] dma-pl330 12850000.mdma: Loaded driver for PL330 DMAC-141330
>> [    0.239141] dma-pl330 12850000.mdma:         DBUFF-64x8bytes Num_Chans-8 Num_Peri-1 Num_Events-32
>> [    0.239800] 13800000.serial: ttySAC0 at MMIO 0x13800000 (irq = 53, base_baud = 0) is a S3C6400/10
>> [    0.240144] 13810000.serial: ttySAC1 at MMIO 0x13810000 (irq = 54, base_baud = 0) is a S3C6400/10
>> [    1.015731] console [ttySAC1] enabled
>> [    1.019770] 13820000.serial: ttySAC2 at MMIO 0x13820000 (irq = 55, base_baud = 0) is a S3C6400/10
>> [    1.028570] 13830000.serial: ttySAC3 at MMIO 0x13830000 (irq = 56, base_baud = 0) is a S3C6400/10
>> [    1.038157] [drm] Initialized drm 1.1.0 20060810
>> [    1.042093] exynos-mixer 12c10000.mixer: Linked as a consumer to 12e20000.sysmmu
>> [    1.049118] iommu: Adding device 12c10000.mixer to group 0
>> [    1.055403] DEBUG: device_links_driver_bound(): 1
>> [    1.059238] ------------[ cut here ]------------
>> [    1.063826] WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
>> [    1.072851] Modules linked in:
>> [    1.075859] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.8.0-vanilla+ #3
>> [    1.082458] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
>> [    1.088533] Backtrace: 
>> [    1.090970] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
>> [    1.098524]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
>> [    1.104161] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
>> [    1.111376] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
>> [    1.118306]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
>> [    1.123946] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
>> [    1.131506]  r9:00000000 r8:c0a258d8 r7:ee3114e4 r6:eeafa874 r5:00000000 r4:ee3114c0
>> [    1.139231] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
>> [    1.148615] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
>> [    1.157287]  r9:00000000 r8:c0a258d8 r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eeafa810
>> [    1.165011] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
>> [    1.173345]  r4:eeafa810 r3:600000d3
>> [    1.176894] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
>> [    1.185323]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eeafa844 r5:c0a258d8
>> [    1.193128]  r4:eeafa810 r3:00000000
>> [    1.196685] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
>> [    1.204853]  r6:c0407eb0 r5:c0a258d8 r4:00000000 r3:c0407eb0
>> [    1.210485] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
>> [    1.218480]  r6:c0a26758 r5:ee27f780 r4:c0a258d8
>> [    1.223072] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
>> [    1.231072] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
>> [    1.239139]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a258d8
>> [    1.244773] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
>> [    1.253809]  r5:00000000 r4:00000004
>> [    1.257364] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
>> [    1.266402] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
>> [    1.274554]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
>> [    1.281232] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
>> [    1.289917]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
>> [    1.297722]  r4:c093a520
>> [    1.300243] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
>> [    1.308493]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
>> [    1.316297]  r4:00000000
>> [    1.318815] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
>> [    1.326373]  r4:00000000 r3:ee880000
>> [    1.329952] ---[ end trace 402e0b75dfe2947b ]---
>> [    1.336115] exynos-hdmi 12d00000.hdmi: Failed to get supply 'vdd': -517
>> [    1.341761] s5p-g2d 10800000.g2d: Linked as a consumer to 10a40000.sysmmu
>> [    1.347960] iommu: Adding device 10800000.g2d to group 1
>> [    1.353512] s5p-g2d 10800000.g2d: The Exynos G2D (ver 4.1) successfully probed.
>> [    1.360510] DEBUG: device_links_driver_bound(): 1
>> [    1.365183] ------------[ cut here ]------------
>> [    1.369786] WARNING: CPU: 1 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
>> [    1.378819] Modules linked in:
>> [    1.381829] CPU: 1 PID: 1 Comm: swapper/0 Tainted: G        W       4.8.0-vanilla+ #3
>> [    1.389651] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
>> [    1.395718] Backtrace: 
>> [    1.398154] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
>> [    1.405709]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
>> [    1.411344] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
>> [    1.418560] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
>> [    1.425491]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
>> [    1.431132] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
>> [    1.438691]  r9:00000000 r8:c0a2621c r7:ee910ae4 r6:eeac4a74 r5:00000000 r4:ee910ac0
>> [    1.446416] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
>> [    1.455800] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
>> [    1.464472]  r9:00000000 r8:c0a2621c r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eeac4a10
>> [    1.472196] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
>> [    1.480530]  r4:eeac4a10 r3:00000000
>> [    1.484080] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
>> [    1.492508]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eeac4a44 r5:c0a2621c
>> [    1.500313]  r4:eeac4a10 r3:00000000
>> [    1.503870] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
>> [    1.512038]  r6:c0407eb0 r5:c0a2621c r4:00000000 r3:c0407eb0
>> [    1.517671] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
>> [    1.525665]  r6:c0a26758 r5:ee932b80 r4:c0a2621c
>> [    1.530257] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
>> [    1.538257] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
>> [    1.546324]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a2621c
>> [    1.551959] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
>> [    1.560994]  r5:00000000 r4:0000000a
>> [    1.564548] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
>> [    1.573587] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
>> [    1.581739]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
>> [    1.588415] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
>> [    1.597103]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
>> [    1.604907]  r4:c093a520
>> [    1.607427] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
>> [    1.615678]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
>> [    1.623482]  r4:00000000
>> [    1.625999] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
>> [    1.633558]  r4:00000000 r3:ee880000
>> [    1.637133] ---[ end trace 402e0b75dfe2947c ]---
>> [    1.642227] exynos-drm-fimc 11800000.fimc: Linked as a consumer to 11a20000.sysmmu
>> [    1.649335] iommu: Adding device 11800000.fimc to group 2
>> [    1.655529] exynos-drm-fimc 11810000.fimc: Linked as a consumer to 11a30000.sysmmu
>> [    1.662263] iommu: Adding device 11810000.fimc to group 3
>> [    1.668447] exynos-drm-fimc 11820000.fimc: Linked as a consumer to 11a40000.sysmmu
>> [    1.675196] iommu: Adding device 11820000.fimc to group 4
>> [    1.681278] exynos-drm-fimc 11820000.fimc: drm fimc registered successfully.
>> [    1.687589] DEBUG: device_links_driver_bound(): 1
>> [    1.692264] ------------[ cut here ]------------
>> [    1.696852] WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
>> [    1.705880] Modules linked in:
>> [    1.708891] CPU: 0 PID: 1 Comm: swapper/0 Tainted: G        W       4.8.0-vanilla+ #3
>> [    1.716713] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
>> [    1.722780] Backtrace: 
>> [    1.725216] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
>> [    1.732771]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
>> [    1.738407] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
>> [    1.745624] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
>> [    1.752553]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
>> [    1.758194] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
>> [    1.765754]  r9:00000000 r8:c0a26330 r7:ee311d24 r6:eea83074 r5:00000000 r4:ee311d00
>> [    1.773479] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
>> [    1.782862] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
>> [    1.791534]  r9:00000000 r8:c0a26330 r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eea83010
>> [    1.799258] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
>> [    1.807592]  r4:eea83010 r3:600000d3
>> [    1.811142] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
>> [    1.819571]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eea83044 r5:c0a26330
>> [    1.827376]  r4:eea83010 r3:00000000
>> [    1.830932] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
>> [    1.839100]  r6:c0407eb0 r5:c0a26330 r4:00000000 r3:c0407eb0
>> [    1.844733] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
>> [    1.852728]  r6:c0a26758 r5:ee27fa00 r4:c0a26330
>> [    1.857319] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
>> [    1.865320] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
>> [    1.873386]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a26330
>> [    1.879021] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
>> [    1.888057]  r5:00000000 r4:0000000b
>> [    1.891610] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
>> [    1.900649] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
>> [    1.908801]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
>> [    1.915478] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
>> [    1.924165]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
>> [    1.931969]  r4:c093a520
>> [    1.934489] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
>> [    1.942740]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
>> [    1.950545]  r4:00000000
>> [    1.953062] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
>> [    1.960620]  r4:00000000 r3:ee880000
>> [    1.964193] ---[ end trace 402e0b75dfe2947d ]---
>> [    1.969039] exynos-drm-fimc 11830000.fimc: Linked as a consumer to 11a50000.sysmmu
>> [    1.976392] iommu: Adding device 11830000.fimc to group 5
>> [    1.982437] exynos-drm-fimc 11830000.fimc: drm fimc registered successfully.
>> [    1.988799] DEBUG: device_links_driver_bound(): 1
>> [    1.993464] ------------[ cut here ]------------
>> [    1.998056] WARNING: CPU: 2 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
>> [    2.007076] Modules linked in:
>> [    2.010087] CPU: 2 PID: 1 Comm: swapper/0 Tainted: G        W       4.8.0-vanilla+ #3
>> [    2.017909] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
>> [    2.023975] Backtrace: 
>> [    2.026412] [<c010bb84>] (dump_backtrace) from [<c010bd80>] (show_stack+0x18/0x1c)
>> [    2.033967]  r6:60000053 r5:c0a1ff00 r4:00000000 r3:00040800
>> [    2.039603] [<c010bd68>] (show_stack) from [<c0353640>] (dump_stack+0x9c/0xb0)
>> [    2.046819] [<c03535a4>] (dump_stack) from [<c011fa74>] (__warn+0xec/0x104)
>> [    2.053750]  r6:c08038b0 r5:00000000 r4:00000000 r3:00040800
>> [    2.059390] [<c011f988>] (__warn) from [<c011fb44>] (warn_slowpath_null+0x28/0x30)
>> [    2.066950]  r9:00000000 r8:c0a26330 r7:ee313264 r6:eea83274 r5:00000000 r4:ee313240
>> [    2.074675] [<c011fb1c>] (warn_slowpath_null) from [<c0404114>] (device_links_driver_bound+0x124/0x12c)
>> [    2.084058] [<c0403ff0>] (device_links_driver_bound) from [<c0407950>] (driver_bound+0x68/0xb8)
>> [    2.092731]  r9:00000000 r8:c0a26330 r7:00000001 r6:c0a6d79c r5:c0a6d794 r4:eea83210
>> [    2.100454] [<c04078e8>] (driver_bound) from [<c0407e4c>] (driver_probe_device+0x280/0x2e4)
>> [    2.108788]  r4:eea83210 r3:600000d3
>> [    2.112338] [<c0407bcc>] (driver_probe_device) from [<c0407f64>] (__driver_attach+0xb4/0xb8)
>> [    2.120767]  r10:00000000 r9:c03f1178 r8:ffffffff r7:00000000 r6:eea83244 r5:c0a26330
>> [    2.128571]  r4:eea83210 r3:00000000
>> [    2.132128] [<c0407eb0>] (__driver_attach) from [<c0405f1c>] (bus_for_each_dev+0x74/0xa8)
>> [    2.140296]  r6:c0407eb0 r5:c0a26330 r4:00000000 r3:c0407eb0
>> [    2.145929] [<c0405ea8>] (bus_for_each_dev) from [<c0407760>] (driver_attach+0x24/0x28)
>> [    2.153924]  r6:c0a26758 r5:ee27fa00 r4:c0a26330
>> [    2.158516] [<c040773c>] (driver_attach) from [<c0407320>] (bus_add_driver+0x1a8/0x220)
>> [    2.166516] [<c0407178>] (bus_add_driver) from [<c0408894>] (driver_register+0x80/0x100)
>> [    2.174582]  r7:c0744e38 r6:c0744dc0 r5:00000000 r4:c0a26330
>> [    2.180217] [<c0408814>] (driver_register) from [<c0409920>] (__platform_driver_register+0x48/0x50)
>> [    2.189252]  r5:00000000 r4:0000000b
>> [    2.192806] [<c04098d8>] (__platform_driver_register) from [<c03f1240>] (exynos_drm_init+0xc8/0xfc)
>> [    2.201845] [<c03f1178>] (exynos_drm_init) from [<c01017c4>] (do_one_initcall+0x58/0x19c)
>> [    2.209997]  r8:c0a02448 r7:c0a39000 r6:c0a39000 r5:00000006 r4:c093a520
>> [    2.216674] [<c010176c>] (do_one_initcall) from [<c0900edc>] (kernel_init_freeable+0x1e4/0x288)
>> [    2.225361]  r10:c0926834 r9:c090060c r8:0000008e r7:c0a39000 r6:c0a39000 r5:00000006
>> [    2.233165]  r4:c093a520
>> [    2.235685] [<c0900cf8>] (kernel_init_freeable) from [<c06dc2dc>] (kernel_init+0x10/0x11c)
>> [    2.243936]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06dc2cc
>> [    2.251740]  r4:00000000
>> [    2.254258] [<c06dc2cc>] (kernel_init) from [<c0107dd8>] (ret_from_fork+0x14/0x3c)
>> [    2.261816]  r4:00000000 r3:ee880000
>> [    2.265388] ---[ end trace 402e0b75dfe2947e ]---
>> [    2.270457] exynos-drm-ipp exynos-drm-ipp: drm ipp registered successfully.
>> [    2.280368] loop: module loaded
>> [    2.293185] random: fast init done
>> [    2.303857] usbcore: registered new interface driver smsc95xx
>> [    2.491598] dwc2 12480000.hsotg: Specified GNPTXFDEP=1024 > 768
>> [    2.491906] dwc2 12480000.hsotg: EPs: 16, dedicated fifos, 7808 entries in SPRAM
>> [    2.499801] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
>> [    2.505798] ehci-exynos: EHCI EXYNOS driver
>> [    2.510438] exynos-ehci 12580000.ehci: EHCI Host Controller
>> [    2.515535] exynos-ehci 12580000.ehci: new USB bus registered, assigned bus number 1
>> [    2.523434] exynos-ehci 12580000.ehci: irq 51, io mem 0x12580000
>> [    2.541596] exynos-ehci 12580000.ehci: USB 2.0 started, EHCI 1.00
>> <snip>
> 
> I'll try to do another test with just the 5 patches from this set
> applied (without the IOMMU probe deferral).
> 
> With best wishes,
> Tobias
> 
> 
> 
> Marek Szyprowski wrote:
>> 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-v2
>>
>> Patches are based on vanilla v4.8-rc7 kernel.
>>
>> Best regards
>> Marek Szyprowski
>> Samsung R&D Institute Poland
>>
>> Changelog:
>> v2:
>> - Simplified clk_pm_runtime_get/put functions, removed workaround for devices
>>   with disabled runtime pm. Such workaround is no longer needed since commit
>>   4d23a5e84806b202d9231929c9507ef7cf7a0185 ("PM / Domains: Allow runtime PM
>>   during system PM phases").
>> - Added CLK_RUNTIME_PM flag to indicate clocks, for which clock core should
>>   call runtime pm functions. This solves problem with clocks, for which struct
>>   device is already registered, but no runtime pm is enabled.
>> - Extended commit messages according to Ulf suggestions.
>> - Fixed some style issues pointed by Barlomiej.
>>
>> v1: http://www.spinics.net/lists/arm-kernel/msg528128.html
>> - initial version
>>
>> 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                                  | 107 +++++-
>>  drivers/clk/samsung/clk-exynos4.c                  | 227 ++++++++----
>>  drivers/clk/samsung/clk-exynos5433.c               | 385 ++++++++++++++++-----
>>  drivers/clk/samsung/clk-pll.c                      |   4 +-
>>  drivers/clk/samsung/clk.c                          |  36 +-
>>  drivers/clk/samsung/clk.h                          |   7 +
>>  include/linux/clk-provider.h                       |   1 +
>>  9 files changed, 632 insertions(+), 162 deletions(-)
>>
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

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

* Re: [PATCH v2 0/5] Add runtime PM support for clocks (on Exynos SoC example)
  2016-10-06 18:05     ` Tobias Jakobi
@ 2016-10-07  9:12       ` Marek Szyprowski
  -1 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2016-10-07  9:12 UTC (permalink / raw)
  To: Tobias Jakobi, linux-clk, linux-pm, linux-samsung-soc, linux-arm-kernel
  Cc: Stephen Boyd, Michael Turquette, Ulf Hansson, Sylwester Nawrocki,
	Chanwoo Choi, Inki Dae, Krzysztof Kozlowski,
	Bartlomiej Zolnierkiewicz

Hi Tobias,


On 2016-10-06 20:05, Tobias Jakobi wrote:
> Hello Marek,
>
> I'm using the patches from the v4.8-clocks-pm-v2 branch plus the ones
> from the v4.8-clocks-pm-v2 branch on top of 4.8.0.
>
> I see some warnings on boot coming from driver core. It appears that the
> warnings are actually meaningful, since IOMMUs stop working completly.
> E.g. if I modprobe s5p-mfc later, firmware loading fails because
> apparantly the IOMMU domain isn't online.
>
>> WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
> I added some debug printk() to device_links_driver_bound(), to show the
> link status. Apparantly it is always DEVICE_LINK_AVAILABLE.

Please note that some additional patches are needed to get IOMMU working 
properly with both runtime-pm patches and deferred probe, which feature 
in turn is needed to get it working after adding clocks-pm changes. I 
will send such patch soon (as a new version of IOMMU deferred probe 
support patches were posted a few days ago).

 > (...)

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

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

* [PATCH v2 0/5] Add runtime PM support for clocks (on Exynos SoC example)
@ 2016-10-07  9:12       ` Marek Szyprowski
  0 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2016-10-07  9:12 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Tobias,


On 2016-10-06 20:05, Tobias Jakobi wrote:
> Hello Marek,
>
> I'm using the patches from the v4.8-clocks-pm-v2 branch plus the ones
> from the v4.8-clocks-pm-v2 branch on top of 4.8.0.
>
> I see some warnings on boot coming from driver core. It appears that the
> warnings are actually meaningful, since IOMMUs stop working completly.
> E.g. if I modprobe s5p-mfc later, firmware loading fails because
> apparantly the IOMMU domain isn't online.
>
>> WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356 device_links_driver_bound+0x124/0x12c
> I added some debug printk() to device_links_driver_bound(), to show the
> link status. Apparantly it is always DEVICE_LINK_AVAILABLE.

Please note that some additional patches are needed to get IOMMU working 
properly with both runtime-pm patches and deferred probe, which feature 
in turn is needed to get it working after adding clocks-pm changes. I 
will send such patch soon (as a new version of IOMMU deferred probe 
support patches were posted a few days ago).

 > (...)

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

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

* Re: [PATCH v2 1/5] clk: add support for runtime pm
  2016-09-19 10:55       ` Marek Szyprowski
@ 2016-10-07 10:07         ` Ulf Hansson
  -1 siblings, 0 replies; 27+ messages in thread
From: Ulf Hansson @ 2016-10-07 10:07 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 19 September 2016 at 12:55, 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 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/changing clock rates and unpreparing/disabling
> unused clocks on boot) will be done with clock controller in runtime resumend
> state.
>
> When one wants to register clock controller, which make use of this feature, he
> has to:
> 1. Provide a struct device to the core when registering the provider and set
>    CLK_RUNTIME_PM flags for its clocks.
> 2. It needs to enable runtime PM for that device.
> 3. It needs to make sure the runtime PM status of the controller device reflects
>    the HW state.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>  drivers/clk/clk.c            | 107 +++++++++++++++++++++++++++++++++++++++----
>  include/linux/clk-provider.h |   1 +
>  2 files changed, 98 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 820a939fb6bb..096a199b8e46 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,26 @@ 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;
> +
> +       ret = pm_runtime_get_sync(core->dev);
> +       return ret < 0 ? ret : 0;
> +}
> +
> +static void clk_pm_runtime_put(struct clk_core *core)
> +{
> +       if (!core->dev)
> +               return;
> +
> +       pm_runtime_put(core->dev);
> +}
> +
>  /***           locking             ***/
>  static void clk_prepare_lock(void)
>  {
> @@ -150,6 +172,8 @@ static void clk_enable_unlock(unsigned long flags)
>
>  static bool clk_core_is_prepared(struct clk_core *core)
>  {
> +       bool status;
> +
>         /*
>          * .is_prepared is optional for clocks that can prepare
>          * fall back to software usage counter if it is missing
> @@ -157,11 +181,17 @@ static bool clk_core_is_prepared(struct clk_core *core)
>         if (!core->ops->is_prepared)
>                 return core->prepare_count;
>
> -       return core->ops->is_prepared(core->hw);
> +       clk_pm_runtime_get(core);

I guess you should assign status to the return code, and check it.

> +       status = core->ops->is_prepared(core->hw);
> +       clk_pm_runtime_put(core);
> +
> +       return status;
>  }
>
>  static bool clk_core_is_enabled(struct clk_core *core)
>  {
> +       bool status;
> +
>         /*
>          * .is_enabled is only mandatory for clocks that gate
>          * fall back to software usage counter if .is_enabled is missing
> @@ -169,7 +199,29 @@ static bool clk_core_is_enabled(struct clk_core *core)
>         if (!core->ops->is_enabled)
>                 return core->enable_count;
>
> -       return core->ops->is_enabled(core->hw);
> +       /*
> +        * Check if runtime pm is enabled before calling .is_enabled callback,
> +        * if not assume that clock is disabled, because we might be called
> +        * from atomic context, from which pm_runtime_get() is not allowed.
> +        * This function is called mainly from clk_disable_unused_subtree,
> +        * which ensures proper runtime pm activation of controller before
> +        * taking enable spinlock, but the below check is needed if one tries
> +        * to call it from other place.
> +        */
> +       if (core->dev) {
> +               pm_runtime_get_noresume(core->dev);
> +               if (pm_runtime_suspended(core->dev)) {

I think it's wrong to use pm_runtime_suspended().

What you should be checking, is whether the device is RPM_ACTIVE or if
runtime PM isn't enabled for device.

In other words, you should use pm_runtime_active() to find out whether
it's okay to invoke the ->is_enabled() ops or not.

Accordingly, I think the upper comment you added then needs to be a
rephrased a bit to reflect this.

> +                       status = false;
> +                       goto done;
> +               }
> +       }
> +
> +       status = core->ops->is_enabled(core->hw);
> +done:
> +       if (core->dev)
> +               pm_runtime_put(core->dev);
> +
> +       return status;
>  }
>
>  /***    helper functions   ***/
> @@ -489,6 +541,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 +584,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 +599,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)
> @@ -745,6 +806,9 @@ static void clk_unprepare_unused_subtree(struct clk_core *core)
>         if (core->flags & CLK_IGNORE_UNUSED)
>                 return;
>
> +       if (clk_pm_runtime_get(core) != 0)

You may simplify this:
if (clk_pm_runtime_get(core))

> +               return;
> +
>         if (clk_core_is_prepared(core)) {
>                 trace_clk_unprepare(core);
>                 if (core->ops->unprepare_unused)
> @@ -753,6 +817,8 @@ static void clk_unprepare_unused_subtree(struct clk_core *core)
>                         core->ops->unprepare(core->hw);
>                 trace_clk_unprepare_complete(core);
>         }
> +
> +       clk_pm_runtime_put(core);
>  }
>
>  static void clk_disable_unused_subtree(struct clk_core *core)
> @@ -768,6 +834,9 @@ static void clk_disable_unused_subtree(struct clk_core *core)
>         if (core->flags & CLK_OPS_PARENT_ENABLE)
>                 clk_core_prepare_enable(core->parent);
>
> +       if (clk_pm_runtime_get(core) != 0)

Is there any reason to why you haven't moved this further down in this
function, like just before calling clk_core_is_enabled()?

You may also simplify this:
if (clk_pm_runtime_get(core))

> +               return;
> +

You need to restore the call made to clk_core_prepare_enable()
earlier, so please update the error handling to cope with this.

>         flags = clk_enable_lock();
>
>         if (core->enable_count)
> @@ -794,6 +863,8 @@ unlock_out:
>         clk_enable_unlock(flags);
>         if (core->flags & CLK_OPS_PARENT_ENABLE)
>                 clk_core_disable_unprepare(core->parent);
> +
> +       clk_pm_runtime_put(core);
>  }
>
>  static bool clk_ignore_unused;
> @@ -1563,6 +1634,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 +1651,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 +1903,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 +1925,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 +2631,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
>                 goto fail_name;
>         }
>         core->ops = hw->init->ops;
> +       if (dev && (hw->init->flags & CLK_RUNTIME_PM))
> +               core->dev = dev;

I guess you need this to play safe, although I am really wondering if
we should try without.

Not that many clocks are currently being registered with a valid
struct device pointer. For the other cases why not try to use runtime
PM as per default?

Moreover we anyway rely on the clock provider to enable runtime PM for
the clock device, and when that isn't the case the runtime PM
deployment in the core should still be safe, right!?

>         if (dev && dev->driver)
>                 core->owner = dev->driver->owner;
>         core->hw = hw;
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index a39c0c530778..8a131eb71fdf 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -35,6 +35,7 @@
>  #define CLK_IS_CRITICAL                BIT(11) /* do not gate, ever */
>  /* parents need enable during gate/ungate, set rate and re-parent */
>  #define CLK_OPS_PARENT_ENABLE  BIT(12)
> +#define CLK_RUNTIME_PM         BIT(13)
>
>  struct clk;
>  struct clk_hw;
> --
> 1.9.1
>

Kind regards
Uffe

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

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

On 19 September 2016 at 12:55, 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 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/changing clock rates and unpreparing/disabling
> unused clocks on boot) will be done with clock controller in runtime resumend
> state.
>
> When one wants to register clock controller, which make use of this feature, he
> has to:
> 1. Provide a struct device to the core when registering the provider and set
>    CLK_RUNTIME_PM flags for its clocks.
> 2. It needs to enable runtime PM for that device.
> 3. It needs to make sure the runtime PM status of the controller device reflects
>    the HW state.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>  drivers/clk/clk.c            | 107 +++++++++++++++++++++++++++++++++++++++----
>  include/linux/clk-provider.h |   1 +
>  2 files changed, 98 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 820a939fb6bb..096a199b8e46 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,26 @@ 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;
> +
> +       ret = pm_runtime_get_sync(core->dev);
> +       return ret < 0 ? ret : 0;
> +}
> +
> +static void clk_pm_runtime_put(struct clk_core *core)
> +{
> +       if (!core->dev)
> +               return;
> +
> +       pm_runtime_put(core->dev);
> +}
> +
>  /***           locking             ***/
>  static void clk_prepare_lock(void)
>  {
> @@ -150,6 +172,8 @@ static void clk_enable_unlock(unsigned long flags)
>
>  static bool clk_core_is_prepared(struct clk_core *core)
>  {
> +       bool status;
> +
>         /*
>          * .is_prepared is optional for clocks that can prepare
>          * fall back to software usage counter if it is missing
> @@ -157,11 +181,17 @@ static bool clk_core_is_prepared(struct clk_core *core)
>         if (!core->ops->is_prepared)
>                 return core->prepare_count;
>
> -       return core->ops->is_prepared(core->hw);
> +       clk_pm_runtime_get(core);

I guess you should assign status to the return code, and check it.

> +       status = core->ops->is_prepared(core->hw);
> +       clk_pm_runtime_put(core);
> +
> +       return status;
>  }
>
>  static bool clk_core_is_enabled(struct clk_core *core)
>  {
> +       bool status;
> +
>         /*
>          * .is_enabled is only mandatory for clocks that gate
>          * fall back to software usage counter if .is_enabled is missing
> @@ -169,7 +199,29 @@ static bool clk_core_is_enabled(struct clk_core *core)
>         if (!core->ops->is_enabled)
>                 return core->enable_count;
>
> -       return core->ops->is_enabled(core->hw);
> +       /*
> +        * Check if runtime pm is enabled before calling .is_enabled callback,
> +        * if not assume that clock is disabled, because we might be called
> +        * from atomic context, from which pm_runtime_get() is not allowed.
> +        * This function is called mainly from clk_disable_unused_subtree,
> +        * which ensures proper runtime pm activation of controller before
> +        * taking enable spinlock, but the below check is needed if one tries
> +        * to call it from other place.
> +        */
> +       if (core->dev) {
> +               pm_runtime_get_noresume(core->dev);
> +               if (pm_runtime_suspended(core->dev)) {

I think it's wrong to use pm_runtime_suspended().

What you should be checking, is whether the device is RPM_ACTIVE or if
runtime PM isn't enabled for device.

In other words, you should use pm_runtime_active() to find out whether
it's okay to invoke the ->is_enabled() ops or not.

Accordingly, I think the upper comment you added then needs to be a
rephrased a bit to reflect this.

> +                       status = false;
> +                       goto done;
> +               }
> +       }
> +
> +       status = core->ops->is_enabled(core->hw);
> +done:
> +       if (core->dev)
> +               pm_runtime_put(core->dev);
> +
> +       return status;
>  }
>
>  /***    helper functions   ***/
> @@ -489,6 +541,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 +584,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 +599,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)
> @@ -745,6 +806,9 @@ static void clk_unprepare_unused_subtree(struct clk_core *core)
>         if (core->flags & CLK_IGNORE_UNUSED)
>                 return;
>
> +       if (clk_pm_runtime_get(core) != 0)

You may simplify this:
if (clk_pm_runtime_get(core))

> +               return;
> +
>         if (clk_core_is_prepared(core)) {
>                 trace_clk_unprepare(core);
>                 if (core->ops->unprepare_unused)
> @@ -753,6 +817,8 @@ static void clk_unprepare_unused_subtree(struct clk_core *core)
>                         core->ops->unprepare(core->hw);
>                 trace_clk_unprepare_complete(core);
>         }
> +
> +       clk_pm_runtime_put(core);
>  }
>
>  static void clk_disable_unused_subtree(struct clk_core *core)
> @@ -768,6 +834,9 @@ static void clk_disable_unused_subtree(struct clk_core *core)
>         if (core->flags & CLK_OPS_PARENT_ENABLE)
>                 clk_core_prepare_enable(core->parent);
>
> +       if (clk_pm_runtime_get(core) != 0)

Is there any reason to why you haven't moved this further down in this
function, like just before calling clk_core_is_enabled()?

You may also simplify this:
if (clk_pm_runtime_get(core))

> +               return;
> +

You need to restore the call made to clk_core_prepare_enable()
earlier, so please update the error handling to cope with this.

>         flags = clk_enable_lock();
>
>         if (core->enable_count)
> @@ -794,6 +863,8 @@ unlock_out:
>         clk_enable_unlock(flags);
>         if (core->flags & CLK_OPS_PARENT_ENABLE)
>                 clk_core_disable_unprepare(core->parent);
> +
> +       clk_pm_runtime_put(core);
>  }
>
>  static bool clk_ignore_unused;
> @@ -1563,6 +1634,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 +1651,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 +1903,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 +1925,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 +2631,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
>                 goto fail_name;
>         }
>         core->ops = hw->init->ops;
> +       if (dev && (hw->init->flags & CLK_RUNTIME_PM))
> +               core->dev = dev;

I guess you need this to play safe, although I am really wondering if
we should try without.

Not that many clocks are currently being registered with a valid
struct device pointer. For the other cases why not try to use runtime
PM as per default?

Moreover we anyway rely on the clock provider to enable runtime PM for
the clock device, and when that isn't the case the runtime PM
deployment in the core should still be safe, right!?

>         if (dev && dev->driver)
>                 core->owner = dev->driver->owner;
>         core->hw = hw;
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index a39c0c530778..8a131eb71fdf 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -35,6 +35,7 @@
>  #define CLK_IS_CRITICAL                BIT(11) /* do not gate, ever */
>  /* parents need enable during gate/ungate, set rate and re-parent */
>  #define CLK_OPS_PARENT_ENABLE  BIT(12)
> +#define CLK_RUNTIME_PM         BIT(13)
>
>  struct clk;
>  struct clk_hw;
> --
> 1.9.1
>

Kind regards
Uffe

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

* Re: [PATCH v2 0/5] Add runtime PM support for clocks (on Exynos SoC example)
  2016-10-07  9:12       ` Marek Szyprowski
@ 2016-10-07 11:17         ` Tobias Jakobi
  -1 siblings, 0 replies; 27+ messages in thread
From: Tobias Jakobi @ 2016-10-07 11:17 UTC (permalink / raw)
  To: Marek Szyprowski, linux-clk, linux-pm, linux-samsung-soc,
	linux-arm-kernel
  Cc: Stephen Boyd, Michael Turquette, Ulf Hansson, Sylwester Nawrocki,
	Chanwoo Choi, Inki Dae, Krzysztof Kozlowski,
	Bartlomiej Zolnierkiewicz

Hey Marek,


Marek Szyprowski wrote:
> Hi Tobias,
> 
> 
> On 2016-10-06 20:05, Tobias Jakobi wrote:
>> Hello Marek,
>>
>> I'm using the patches from the v4.8-clocks-pm-v2 branch plus the ones
>> from the v4.8-clocks-pm-v2 branch on top of 4.8.0.
>>
>> I see some warnings on boot coming from driver core. It appears that the
>> warnings are actually meaningful, since IOMMUs stop working completly.
>> E.g. if I modprobe s5p-mfc later, firmware loading fails because
>> apparantly the IOMMU domain isn't online.
>>
>>> WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356
>>> device_links_driver_bound+0x124/0x12c
>> I added some debug printk() to device_links_driver_bound(), to show the
>> link status. Apparantly it is always DEVICE_LINK_AVAILABLE.
> 
> Please note that some additional patches are needed to get IOMMU working
> properly with both runtime-pm patches and deferred probe, which feature
> in turn is needed to get it working after adding clocks-pm changes. I
> will send such patch soon (as a new version of IOMMU deferred probe
> support patches were posted a few days ago).
I see. I thought that this was supposed to work with the patches in
v4.8-clocks-pm-v2.

I picked the patches in this range (endpoints included).
- arm: dma-mapping: Don't override dma_ops in arch_setup_dma_ops()
- clocks: exynos5433: add runtime pm support

And this range in v4.8-iommu-pm-v4>
- driver core: Add a wrapper around __device_release_driver()
- iommu/exynos: Add proper runtime pm support


Anyway, looking forward to test the new patchset.


- Tobias


> 
>> (...)
> 
> Best regards

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

* [PATCH v2 0/5] Add runtime PM support for clocks (on Exynos SoC example)
@ 2016-10-07 11:17         ` Tobias Jakobi
  0 siblings, 0 replies; 27+ messages in thread
From: Tobias Jakobi @ 2016-10-07 11:17 UTC (permalink / raw)
  To: linux-arm-kernel

Hey Marek,


Marek Szyprowski wrote:
> Hi Tobias,
> 
> 
> On 2016-10-06 20:05, Tobias Jakobi wrote:
>> Hello Marek,
>>
>> I'm using the patches from the v4.8-clocks-pm-v2 branch plus the ones
>> from the v4.8-clocks-pm-v2 branch on top of 4.8.0.
>>
>> I see some warnings on boot coming from driver core. It appears that the
>> warnings are actually meaningful, since IOMMUs stop working completly.
>> E.g. if I modprobe s5p-mfc later, firmware loading fails because
>> apparantly the IOMMU domain isn't online.
>>
>>> WARNING: CPU: 0 PID: 1 at drivers/base/core.c:356
>>> device_links_driver_bound+0x124/0x12c
>> I added some debug printk() to device_links_driver_bound(), to show the
>> link status. Apparantly it is always DEVICE_LINK_AVAILABLE.
> 
> Please note that some additional patches are needed to get IOMMU working
> properly with both runtime-pm patches and deferred probe, which feature
> in turn is needed to get it working after adding clocks-pm changes. I
> will send such patch soon (as a new version of IOMMU deferred probe
> support patches were posted a few days ago).
I see. I thought that this was supposed to work with the patches in
v4.8-clocks-pm-v2.

I picked the patches in this range (endpoints included).
- arm: dma-mapping: Don't override dma_ops in arch_setup_dma_ops()
- clocks: exynos5433: add runtime pm support

And this range in v4.8-iommu-pm-v4>
- driver core: Add a wrapper around __device_release_driver()
- iommu/exynos: Add proper runtime pm support


Anyway, looking forward to test the new patchset.


- Tobias


> 
>> (...)
> 
> Best regards

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

* Re: [PATCH v2 1/5] clk: add support for runtime pm
  2016-10-07 10:07         ` Ulf Hansson
@ 2016-10-10 11:21           ` Marek Szyprowski
  -1 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2016-10-10 11:21 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 Kozłowski,
	Bartlomiej Zolnierkiewicz

Hi Ulf,

Thanks for your comments!

On 2016-10-07 12:07, Ulf Hansson wrote:
> On 19 September 2016 at 12:55, 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 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/changing clock rates and unpreparing/disabling
>> unused clocks on boot) will be done with clock controller in runtime resumend
>> state.
>>
>> When one wants to register clock controller, which make use of this feature, he
>> has to:
>> 1. Provide a struct device to the core when registering the provider and set
>>     CLK_RUNTIME_PM flags for its clocks.
>> 2. It needs to enable runtime PM for that device.
>> 3. It needs to make sure the runtime PM status of the controller device reflects
>>     the HW state.
>>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> ---
>>   drivers/clk/clk.c            | 107 +++++++++++++++++++++++++++++++++++++++----
>>   include/linux/clk-provider.h |   1 +
>>   2 files changed, 98 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
>> index 820a939fb6bb..096a199b8e46 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,26 @@ 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;
>> +
>> +       ret = pm_runtime_get_sync(core->dev);
>> +       return ret < 0 ? ret : 0;
>> +}
>> +
>> +static void clk_pm_runtime_put(struct clk_core *core)
>> +{
>> +       if (!core->dev)
>> +               return;
>> +
>> +       pm_runtime_put(core->dev);
>> +}
>> +
>>   /***           locking             ***/
>>   static void clk_prepare_lock(void)
>>   {
>> @@ -150,6 +172,8 @@ static void clk_enable_unlock(unsigned long flags)
>>
>>   static bool clk_core_is_prepared(struct clk_core *core)
>>   {
>> +       bool status;
>> +
>>          /*
>>           * .is_prepared is optional for clocks that can prepare
>>           * fall back to software usage counter if it is missing
>> @@ -157,11 +181,17 @@ static bool clk_core_is_prepared(struct clk_core *core)
>>          if (!core->ops->is_prepared)
>>                  return core->prepare_count;
>>
>> -       return core->ops->is_prepared(core->hw);
>> +       clk_pm_runtime_get(core);
> I guess you should assign status to the return code, and check it.

Okay. I assume that in case of any failure from runtime pm, the function
should return false?

>
>> +       status = core->ops->is_prepared(core->hw);
>> +       clk_pm_runtime_put(core);
>> +
>> +       return status;
>>   }
>>
>>   static bool clk_core_is_enabled(struct clk_core *core)
>>   {
>> +       bool status;
>> +
>>          /*
>>           * .is_enabled is only mandatory for clocks that gate
>>           * fall back to software usage counter if .is_enabled is missing
>> @@ -169,7 +199,29 @@ static bool clk_core_is_enabled(struct clk_core *core)
>>          if (!core->ops->is_enabled)
>>                  return core->enable_count;
>>
>> -       return core->ops->is_enabled(core->hw);
>> +       /*
>> +        * Check if runtime pm is enabled before calling .is_enabled callback,
>> +        * if not assume that clock is disabled, because we might be called
>> +        * from atomic context, from which pm_runtime_get() is not allowed.
>> +        * This function is called mainly from clk_disable_unused_subtree,
>> +        * which ensures proper runtime pm activation of controller before
>> +        * taking enable spinlock, but the below check is needed if one tries
>> +        * to call it from other place.
>> +        */
>> +       if (core->dev) {
>> +               pm_runtime_get_noresume(core->dev);
>> +               if (pm_runtime_suspended(core->dev)) {
> I think it's wrong to use pm_runtime_suspended().
>
> What you should be checking, is whether the device is RPM_ACTIVE or if
> runtime PM isn't enabled for device.
>
> In other words, you should use pm_runtime_active() to find out whether
> it's okay to invoke the ->is_enabled() ops or not.
>
> Accordingly, I think the upper comment you added then needs to be a
> rephrased a bit to reflect this.

Okay, I will change it to use pm_runtime_active(). It looks that mentally
I still assume that runtime pm will be disabled in system sleep transitions
phase, so the only check that provided some useful information about
previous runtime pm state was pm_runtime_suspended().

>
>> +                       status = false;
>> +                       goto done;
>> +               }
>> +       }
>> +
>> +       status = core->ops->is_enabled(core->hw);
>> +done:
>> +       if (core->dev)
>> +               pm_runtime_put(core->dev);
>> +
>> +       return status;
>>   }
>>
>>   /***    helper functions   ***/
>> @@ -489,6 +541,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 +584,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 +599,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)
>> @@ -745,6 +806,9 @@ static void clk_unprepare_unused_subtree(struct clk_core *core)
>>          if (core->flags & CLK_IGNORE_UNUSED)
>>                  return;
>>
>> +       if (clk_pm_runtime_get(core) != 0)
> You may simplify this:
> if (clk_pm_runtime_get(core))
>
>> +               return;
>> +
>>          if (clk_core_is_prepared(core)) {
>>                  trace_clk_unprepare(core);
>>                  if (core->ops->unprepare_unused)
>> @@ -753,6 +817,8 @@ static void clk_unprepare_unused_subtree(struct clk_core *core)
>>                          core->ops->unprepare(core->hw);
>>                  trace_clk_unprepare_complete(core);
>>          }
>> +
>> +       clk_pm_runtime_put(core);
>>   }
>>
>>   static void clk_disable_unused_subtree(struct clk_core *core)
>> @@ -768,6 +834,9 @@ static void clk_disable_unused_subtree(struct clk_core *core)
>>          if (core->flags & CLK_OPS_PARENT_ENABLE)
>>                  clk_core_prepare_enable(core->parent);
>>
>> +       if (clk_pm_runtime_get(core) != 0)
> Is there any reason to why you haven't moved this further down in this
> function, like just before calling clk_core_is_enabled()?

Yes, clk_enable_lock() takes a spinlock, so I cannot call pm_runtime_get 
after it.

>
> You may also simplify this:
> if (clk_pm_runtime_get(core))
>
>> +               return;
>> +
> You need to restore the call made to clk_core_prepare_enable()
> earlier, so please update the error handling to cope with this.
>
>>          flags = clk_enable_lock();
>>
>>          if (core->enable_count)
>> @@ -794,6 +863,8 @@ unlock_out:
>>          clk_enable_unlock(flags);
>>          if (core->flags & CLK_OPS_PARENT_ENABLE)
>>                  clk_core_disable_unprepare(core->parent);
>> +
>> +       clk_pm_runtime_put(core);
>>   }
>>
>>   static bool clk_ignore_unused;
>> @@ -1563,6 +1634,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 +1651,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 +1903,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 +1925,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 +2631,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
>>                  goto fail_name;
>>          }
>>          core->ops = hw->init->ops;
>> +       if (dev && (hw->init->flags & CLK_RUNTIME_PM))
>> +               core->dev = dev;
> I guess you need this to play safe, although I am really wondering if
> we should try without.
>
> Not that many clocks are currently being registered with a valid
> struct device pointer. For the other cases why not try to use runtime
> PM as per default?

I've that tried initially, but it causes failure for all the clock
controllers, which don't enable runtime pm. One of such case is max77686
PMIC, which provides 3 clocks. Maybe a negative flag (CLK_NO_RUNTIME_PM)
will be a better solution, so by default the runtime pm calls will be
enabled for every driver providing struct device?

> Moreover we anyway rely on the clock provider to enable runtime PM for
> the clock device, and when that isn't the case the runtime PM
> deployment in the core should still be safe, right!?

I don't get the above comment. Do you want to check if runtime pm has
been enabled during clock registration?

>>         if (dev && dev->driver)
>>                  core->owner = dev->driver->owner;
>>          core->hw = hw;
>> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
>> index a39c0c530778..8a131eb71fdf 100644
>> --- a/include/linux/clk-provider.h
>> +++ b/include/linux/clk-provider.h
>> @@ -35,6 +35,7 @@
>>   #define CLK_IS_CRITICAL                BIT(11) /* do not gate, ever */
>>   /* parents need enable during gate/ungate, set rate and re-parent */
>>   #define CLK_OPS_PARENT_ENABLE  BIT(12)
>> +#define CLK_RUNTIME_PM         BIT(13)
>>
>>   struct clk;
>>   struct clk_hw;
>> --
>> 1.9.1
>>
>

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

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

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

Hi Ulf,

Thanks for your comments!

On 2016-10-07 12:07, Ulf Hansson wrote:
> On 19 September 2016 at 12:55, 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 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/changing clock rates and unpreparing/disabling
>> unused clocks on boot) will be done with clock controller in runtime resumend
>> state.
>>
>> When one wants to register clock controller, which make use of this feature, he
>> has to:
>> 1. Provide a struct device to the core when registering the provider and set
>>     CLK_RUNTIME_PM flags for its clocks.
>> 2. It needs to enable runtime PM for that device.
>> 3. It needs to make sure the runtime PM status of the controller device reflects
>>     the HW state.
>>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> ---
>>   drivers/clk/clk.c            | 107 +++++++++++++++++++++++++++++++++++++++----
>>   include/linux/clk-provider.h |   1 +
>>   2 files changed, 98 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
>> index 820a939fb6bb..096a199b8e46 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,26 @@ 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;
>> +
>> +       ret = pm_runtime_get_sync(core->dev);
>> +       return ret < 0 ? ret : 0;
>> +}
>> +
>> +static void clk_pm_runtime_put(struct clk_core *core)
>> +{
>> +       if (!core->dev)
>> +               return;
>> +
>> +       pm_runtime_put(core->dev);
>> +}
>> +
>>   /***           locking             ***/
>>   static void clk_prepare_lock(void)
>>   {
>> @@ -150,6 +172,8 @@ static void clk_enable_unlock(unsigned long flags)
>>
>>   static bool clk_core_is_prepared(struct clk_core *core)
>>   {
>> +       bool status;
>> +
>>          /*
>>           * .is_prepared is optional for clocks that can prepare
>>           * fall back to software usage counter if it is missing
>> @@ -157,11 +181,17 @@ static bool clk_core_is_prepared(struct clk_core *core)
>>          if (!core->ops->is_prepared)
>>                  return core->prepare_count;
>>
>> -       return core->ops->is_prepared(core->hw);
>> +       clk_pm_runtime_get(core);
> I guess you should assign status to the return code, and check it.

Okay. I assume that in case of any failure from runtime pm, the function
should return false?

>
>> +       status = core->ops->is_prepared(core->hw);
>> +       clk_pm_runtime_put(core);
>> +
>> +       return status;
>>   }
>>
>>   static bool clk_core_is_enabled(struct clk_core *core)
>>   {
>> +       bool status;
>> +
>>          /*
>>           * .is_enabled is only mandatory for clocks that gate
>>           * fall back to software usage counter if .is_enabled is missing
>> @@ -169,7 +199,29 @@ static bool clk_core_is_enabled(struct clk_core *core)
>>          if (!core->ops->is_enabled)
>>                  return core->enable_count;
>>
>> -       return core->ops->is_enabled(core->hw);
>> +       /*
>> +        * Check if runtime pm is enabled before calling .is_enabled callback,
>> +        * if not assume that clock is disabled, because we might be called
>> +        * from atomic context, from which pm_runtime_get() is not allowed.
>> +        * This function is called mainly from clk_disable_unused_subtree,
>> +        * which ensures proper runtime pm activation of controller before
>> +        * taking enable spinlock, but the below check is needed if one tries
>> +        * to call it from other place.
>> +        */
>> +       if (core->dev) {
>> +               pm_runtime_get_noresume(core->dev);
>> +               if (pm_runtime_suspended(core->dev)) {
> I think it's wrong to use pm_runtime_suspended().
>
> What you should be checking, is whether the device is RPM_ACTIVE or if
> runtime PM isn't enabled for device.
>
> In other words, you should use pm_runtime_active() to find out whether
> it's okay to invoke the ->is_enabled() ops or not.
>
> Accordingly, I think the upper comment you added then needs to be a
> rephrased a bit to reflect this.

Okay, I will change it to use pm_runtime_active(). It looks that mentally
I still assume that runtime pm will be disabled in system sleep transitions
phase, so the only check that provided some useful information about
previous runtime pm state was pm_runtime_suspended().

>
>> +                       status = false;
>> +                       goto done;
>> +               }
>> +       }
>> +
>> +       status = core->ops->is_enabled(core->hw);
>> +done:
>> +       if (core->dev)
>> +               pm_runtime_put(core->dev);
>> +
>> +       return status;
>>   }
>>
>>   /***    helper functions   ***/
>> @@ -489,6 +541,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 +584,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 +599,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)
>> @@ -745,6 +806,9 @@ static void clk_unprepare_unused_subtree(struct clk_core *core)
>>          if (core->flags & CLK_IGNORE_UNUSED)
>>                  return;
>>
>> +       if (clk_pm_runtime_get(core) != 0)
> You may simplify this:
> if (clk_pm_runtime_get(core))
>
>> +               return;
>> +
>>          if (clk_core_is_prepared(core)) {
>>                  trace_clk_unprepare(core);
>>                  if (core->ops->unprepare_unused)
>> @@ -753,6 +817,8 @@ static void clk_unprepare_unused_subtree(struct clk_core *core)
>>                          core->ops->unprepare(core->hw);
>>                  trace_clk_unprepare_complete(core);
>>          }
>> +
>> +       clk_pm_runtime_put(core);
>>   }
>>
>>   static void clk_disable_unused_subtree(struct clk_core *core)
>> @@ -768,6 +834,9 @@ static void clk_disable_unused_subtree(struct clk_core *core)
>>          if (core->flags & CLK_OPS_PARENT_ENABLE)
>>                  clk_core_prepare_enable(core->parent);
>>
>> +       if (clk_pm_runtime_get(core) != 0)
> Is there any reason to why you haven't moved this further down in this
> function, like just before calling clk_core_is_enabled()?

Yes, clk_enable_lock() takes a spinlock, so I cannot call pm_runtime_get 
after it.

>
> You may also simplify this:
> if (clk_pm_runtime_get(core))
>
>> +               return;
>> +
> You need to restore the call made to clk_core_prepare_enable()
> earlier, so please update the error handling to cope with this.
>
>>          flags = clk_enable_lock();
>>
>>          if (core->enable_count)
>> @@ -794,6 +863,8 @@ unlock_out:
>>          clk_enable_unlock(flags);
>>          if (core->flags & CLK_OPS_PARENT_ENABLE)
>>                  clk_core_disable_unprepare(core->parent);
>> +
>> +       clk_pm_runtime_put(core);
>>   }
>>
>>   static bool clk_ignore_unused;
>> @@ -1563,6 +1634,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 +1651,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 +1903,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 +1925,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 +2631,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
>>                  goto fail_name;
>>          }
>>          core->ops = hw->init->ops;
>> +       if (dev && (hw->init->flags & CLK_RUNTIME_PM))
>> +               core->dev = dev;
> I guess you need this to play safe, although I am really wondering if
> we should try without.
>
> Not that many clocks are currently being registered with a valid
> struct device pointer. For the other cases why not try to use runtime
> PM as per default?

I've that tried initially, but it causes failure for all the clock
controllers, which don't enable runtime pm. One of such case is max77686
PMIC, which provides 3 clocks. Maybe a negative flag (CLK_NO_RUNTIME_PM)
will be a better solution, so by default the runtime pm calls will be
enabled for every driver providing struct device?

> Moreover we anyway rely on the clock provider to enable runtime PM for
> the clock device, and when that isn't the case the runtime PM
> deployment in the core should still be safe, right!?

I don't get the above comment. Do you want to check if runtime pm has
been enabled during clock registration?

>>         if (dev && dev->driver)
>>                  core->owner = dev->driver->owner;
>>          core->hw = hw;
>> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
>> index a39c0c530778..8a131eb71fdf 100644
>> --- a/include/linux/clk-provider.h
>> +++ b/include/linux/clk-provider.h
>> @@ -35,6 +35,7 @@
>>   #define CLK_IS_CRITICAL                BIT(11) /* do not gate, ever */
>>   /* parents need enable during gate/ungate, set rate and re-parent */
>>   #define CLK_OPS_PARENT_ENABLE  BIT(12)
>> +#define CLK_RUNTIME_PM         BIT(13)
>>
>>   struct clk;
>>   struct clk_hw;
>> --
>> 1.9.1
>>
>

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

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

* Re: [PATCH v2 1/5] clk: add support for runtime pm
  2016-10-10 11:21           ` Marek Szyprowski
  (?)
@ 2016-10-10 13:44             ` Ulf Hansson
  -1 siblings, 0 replies; 27+ messages in thread
From: Ulf Hansson @ 2016-10-10 13:44 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 Kozłowski,
	Bartlomiej Zolnierkiewicz

[...]

>>> @@ -157,11 +181,17 @@ static bool clk_core_is_prepared(struct clk_core
>>> *core)
>>>          if (!core->ops->is_prepared)
>>>                  return core->prepare_count;
>>>
>>> -       return core->ops->is_prepared(core->hw);
>>> +       clk_pm_runtime_get(core);
>>
>> I guess you should assign status to the return code, and check it.
>
>
> Okay. I assume that in case of any failure from runtime pm, the function
> should return false?

I think so, yes.

>
>

[...]

>>>   static void clk_disable_unused_subtree(struct clk_core *core)
>>> @@ -768,6 +834,9 @@ static void clk_disable_unused_subtree(struct
>>> clk_core *core)
>>>          if (core->flags & CLK_OPS_PARENT_ENABLE)
>>>                  clk_core_prepare_enable(core->parent);
>>>
>>> +       if (clk_pm_runtime_get(core) != 0)
>>
>> Is there any reason to why you haven't moved this further down in this
>> function, like just before calling clk_core_is_enabled()?
>
>
> Yes, clk_enable_lock() takes a spinlock, so I cannot call pm_runtime_get
> after it.

Of course, you are right!

>
>
>>
>> You may also simplify this:
>> if (clk_pm_runtime_get(core))
>>
>>> +               return;
>>> +
>>
>> You need to restore the call made to clk_core_prepare_enable()
>> earlier, so please update the error handling to cope with this.
>>

[...]

>>> @@ -2546,6 +2631,8 @@ struct clk *clk_register(struct device *dev, struct
>>> clk_hw *hw)
>>>                  goto fail_name;
>>>          }
>>>          core->ops = hw->init->ops;
>>> +       if (dev && (hw->init->flags & CLK_RUNTIME_PM))
>>> +               core->dev = dev;
>>
>> I guess you need this to play safe, although I am really wondering if
>> we should try without.
>>
>> Not that many clocks are currently being registered with a valid
>> struct device pointer. For the other cases why not try to use runtime
>> PM as per default?
>
>
> I've that tried initially, but it causes failure for all the clock
> controllers, which don't enable runtime pm. One of such case is max77686
> PMIC, which provides 3 clocks. Maybe a negative flag (CLK_NO_RUNTIME_PM)
> will be a better solution, so by default the runtime pm calls will be
> enabled for every driver providing struct device?

I assume that's because the runtime PM errors in clk_pm_runtime_get()
and friends, are being propagated to the callers? Especially because
the runtime PM core returns error codes, in cases when runtime PM
hasn't been enabled for the device.

>
>> Moreover we anyway rely on the clock provider to enable runtime PM for
>> the clock device, and when that isn't the case the runtime PM
>> deployment in the core should still be safe, right!?
>
>
> I don't get the above comment. Do you want to check if runtime pm has
> been enabled during clock registration?

Yes, something like that. Apologize, I was clearly being too vague.

My point is, we don't need to invent a specific clock provider flag
for this. Instead the clock core could just at clock registration
check if runtime PM is enabled for the device (pm_runtime_enabled()),.
and from that assign an internal clock core flag to keep track of
whether runtime PM should be managed or not.

>
>>>         if (dev && dev->driver)
>>>                  core->owner = dev->driver->owner;
>>>          core->hw = hw;
>>> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
>>> index a39c0c530778..8a131eb71fdf 100644
>>> --- a/include/linux/clk-provider.h
>>> +++ b/include/linux/clk-provider.h
>>> @@ -35,6 +35,7 @@
>>>   #define CLK_IS_CRITICAL                BIT(11) /* do not gate, ever */
>>>   /* parents need enable during gate/ungate, set rate and re-parent */
>>>   #define CLK_OPS_PARENT_ENABLE  BIT(12)
>>> +#define CLK_RUNTIME_PM         BIT(13)
>>>
>>>   struct clk;
>>>   struct clk_hw;
>>> --
>>> 1.9.1
>>>
>>
>
> Best regards
> --
> Marek Szyprowski, PhD
> Samsung R&D Institute Poland
>

Kind regards
Uffe

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

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

[...]

>>> @@ -157,11 +181,17 @@ static bool clk_core_is_prepared(struct clk_core
>>> *core)
>>>          if (!core->ops->is_prepared)
>>>                  return core->prepare_count;
>>>
>>> -       return core->ops->is_prepared(core->hw);
>>> +       clk_pm_runtime_get(core);
>>
>> I guess you should assign status to the return code, and check it.
>
>
> Okay. I assume that in case of any failure from runtime pm, the function
> should return false?

I think so, yes.

>
>

[...]

>>>   static void clk_disable_unused_subtree(struct clk_core *core)
>>> @@ -768,6 +834,9 @@ static void clk_disable_unused_subtree(struct
>>> clk_core *core)
>>>          if (core->flags & CLK_OPS_PARENT_ENABLE)
>>>                  clk_core_prepare_enable(core->parent);
>>>
>>> +       if (clk_pm_runtime_get(core) != 0)
>>
>> Is there any reason to why you haven't moved this further down in this
>> function, like just before calling clk_core_is_enabled()?
>
>
> Yes, clk_enable_lock() takes a spinlock, so I cannot call pm_runtime_get
> after it.

Of course, you are right!

>
>
>>
>> You may also simplify this:
>> if (clk_pm_runtime_get(core))
>>
>>> +               return;
>>> +
>>
>> You need to restore the call made to clk_core_prepare_enable()
>> earlier, so please update the error handling to cope with this.
>>

[...]

>>> @@ -2546,6 +2631,8 @@ struct clk *clk_register(struct device *dev, struct
>>> clk_hw *hw)
>>>                  goto fail_name;
>>>          }
>>>          core->ops = hw->init->ops;
>>> +       if (dev && (hw->init->flags & CLK_RUNTIME_PM))
>>> +               core->dev = dev;
>>
>> I guess you need this to play safe, although I am really wondering if
>> we should try without.
>>
>> Not that many clocks are currently being registered with a valid
>> struct device pointer. For the other cases why not try to use runtime
>> PM as per default?
>
>
> I've that tried initially, but it causes failure for all the clock
> controllers, which don't enable runtime pm. One of such case is max77686
> PMIC, which provides 3 clocks. Maybe a negative flag (CLK_NO_RUNTIME_PM)
> will be a better solution, so by default the runtime pm calls will be
> enabled for every driver providing struct device?

I assume that's because the runtime PM errors in clk_pm_runtime_get()
and friends, are being propagated to the callers? Especially because
the runtime PM core returns error codes, in cases when runtime PM
hasn't been enabled for the device.

>
>> Moreover we anyway rely on the clock provider to enable runtime PM for
>> the clock device, and when that isn't the case the runtime PM
>> deployment in the core should still be safe, right!?
>
>
> I don't get the above comment. Do you want to check if runtime pm has
> been enabled during clock registration?

Yes, something like that. Apologize, I was clearly being too vague.

My point is, we don't need to invent a specific clock provider flag
for this. Instead the clock core could just at clock registration
check if runtime PM is enabled for the device (pm_runtime_enabled()),.
and from that assign an internal clock core flag to keep track of
whether runtime PM should be managed or not.

>
>>>         if (dev && dev->driver)
>>>                  core->owner = dev->driver->owner;
>>>          core->hw = hw;
>>> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
>>> index a39c0c530778..8a131eb71fdf 100644
>>> --- a/include/linux/clk-provider.h
>>> +++ b/include/linux/clk-provider.h
>>> @@ -35,6 +35,7 @@
>>>   #define CLK_IS_CRITICAL                BIT(11) /* do not gate, ever */
>>>   /* parents need enable during gate/ungate, set rate and re-parent */
>>>   #define CLK_OPS_PARENT_ENABLE  BIT(12)
>>> +#define CLK_RUNTIME_PM         BIT(13)
>>>
>>>   struct clk;
>>>   struct clk_hw;
>>> --
>>> 1.9.1
>>>
>>
>
> Best regards
> --
> Marek Szyprowski, PhD
> Samsung R&D Institute Poland
>

Kind regards
Uffe

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

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

[...]

>>> @@ -157,11 +181,17 @@ static bool clk_core_is_prepared(struct clk_core
>>> *core)
>>>          if (!core->ops->is_prepared)
>>>                  return core->prepare_count;
>>>
>>> -       return core->ops->is_prepared(core->hw);
>>> +       clk_pm_runtime_get(core);
>>
>> I guess you should assign status to the return code, and check it.
>
>
> Okay. I assume that in case of any failure from runtime pm, the function
> should return false?

I think so, yes.

>
>

[...]

>>>   static void clk_disable_unused_subtree(struct clk_core *core)
>>> @@ -768,6 +834,9 @@ static void clk_disable_unused_subtree(struct
>>> clk_core *core)
>>>          if (core->flags & CLK_OPS_PARENT_ENABLE)
>>>                  clk_core_prepare_enable(core->parent);
>>>
>>> +       if (clk_pm_runtime_get(core) != 0)
>>
>> Is there any reason to why you haven't moved this further down in this
>> function, like just before calling clk_core_is_enabled()?
>
>
> Yes, clk_enable_lock() takes a spinlock, so I cannot call pm_runtime_get
> after it.

Of course, you are right!

>
>
>>
>> You may also simplify this:
>> if (clk_pm_runtime_get(core))
>>
>>> +               return;
>>> +
>>
>> You need to restore the call made to clk_core_prepare_enable()
>> earlier, so please update the error handling to cope with this.
>>

[...]

>>> @@ -2546,6 +2631,8 @@ struct clk *clk_register(struct device *dev, struct
>>> clk_hw *hw)
>>>                  goto fail_name;
>>>          }
>>>          core->ops = hw->init->ops;
>>> +       if (dev && (hw->init->flags & CLK_RUNTIME_PM))
>>> +               core->dev = dev;
>>
>> I guess you need this to play safe, although I am really wondering if
>> we should try without.
>>
>> Not that many clocks are currently being registered with a valid
>> struct device pointer. For the other cases why not try to use runtime
>> PM as per default?
>
>
> I've that tried initially, but it causes failure for all the clock
> controllers, which don't enable runtime pm. One of such case is max77686
> PMIC, which provides 3 clocks. Maybe a negative flag (CLK_NO_RUNTIME_PM)
> will be a better solution, so by default the runtime pm calls will be
> enabled for every driver providing struct device?

I assume that's because the runtime PM errors in clk_pm_runtime_get()
and friends, are being propagated to the callers? Especially because
the runtime PM core returns error codes, in cases when runtime PM
hasn't been enabled for the device.

>
>> Moreover we anyway rely on the clock provider to enable runtime PM for
>> the clock device, and when that isn't the case the runtime PM
>> deployment in the core should still be safe, right!?
>
>
> I don't get the above comment. Do you want to check if runtime pm has
> been enabled during clock registration?

Yes, something like that. Apologize, I was clearly being too vague.

My point is, we don't need to invent a specific clock provider flag
for this. Instead the clock core could just at clock registration
check if runtime PM is enabled for the device (pm_runtime_enabled()),.
and from that assign an internal clock core flag to keep track of
whether runtime PM should be managed or not.

>
>>>         if (dev && dev->driver)
>>>                  core->owner = dev->driver->owner;
>>>          core->hw = hw;
>>> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
>>> index a39c0c530778..8a131eb71fdf 100644
>>> --- a/include/linux/clk-provider.h
>>> +++ b/include/linux/clk-provider.h
>>> @@ -35,6 +35,7 @@
>>>   #define CLK_IS_CRITICAL                BIT(11) /* do not gate, ever */
>>>   /* parents need enable during gate/ungate, set rate and re-parent */
>>>   #define CLK_OPS_PARENT_ENABLE  BIT(12)
>>> +#define CLK_RUNTIME_PM         BIT(13)
>>>
>>>   struct clk;
>>>   struct clk_hw;
>>> --
>>> 1.9.1
>>>
>>
>
> Best regards
> --
> Marek Szyprowski, PhD
> Samsung R&D Institute Poland
>

Kind regards
Uffe

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

end of thread, other threads:[~2016-10-10 13:44 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20160919105545eucas1p1026e435bbaeb1f5c866a9abcdd051464@eucas1p1.samsung.com>
2016-09-19 10:55 ` [PATCH v2 0/5] Add runtime PM support for clocks (on Exynos SoC example) Marek Szyprowski
2016-09-19 10:55   ` Marek Szyprowski
     [not found]   ` <CGME20160919105548eucas1p24b28143fab25eb47f5629d31f817b0bc@eucas1p2.samsung.com>
2016-09-19 10:55     ` [PATCH v2 1/5] clk: add support for runtime pm Marek Szyprowski
2016-09-19 10:55       ` Marek Szyprowski
2016-10-07 10:07       ` Ulf Hansson
2016-10-07 10:07         ` Ulf Hansson
2016-10-10 11:21         ` Marek Szyprowski
2016-10-10 11:21           ` Marek Szyprowski
2016-10-10 13:44           ` Ulf Hansson
2016-10-10 13:44             ` Ulf Hansson
2016-10-10 13:44             ` Ulf Hansson
     [not found]   ` <CGME20160919105549eucas1p1a2df94dc0ff48c7623949adbc5453bca@eucas1p1.samsung.com>
2016-09-19 10:55     ` [PATCH v2 2/5] clock: samsung: " Marek Szyprowski
2016-09-19 10:55       ` Marek Szyprowski
     [not found]   ` <CGME20160919105550eucas1p2d9bcb35f5464e14bd3c5925baf62e111@eucas1p2.samsung.com>
2016-09-19 10:55     ` [PATCH v2 3/5] clocks: exynos4x12: add runtime pm support for ISP clocks Marek Szyprowski
2016-09-19 10:55       ` Marek Szyprowski
     [not found]   ` <CGME20160919105552eucas1p2964f3f16b0d0b38379e4f97abebf2785@eucas1p2.samsung.com>
2016-09-19 10:55     ` [PATCH v2 4/5] ARM: dts: exynos: add support for ISP power domain to exynos4x12 clocks device Marek Szyprowski
2016-09-19 10:55       ` Marek Szyprowski
     [not found]   ` <CGME20160919105811eucas1p255d75d38bc9f2ceb9772c87241458969@eucas1p2.samsung.com>
2016-09-19 10:58     ` [PATCH v2 5/5] clocks: exynos5433: add runtime pm support Marek Szyprowski
2016-09-19 10:58       ` Marek Szyprowski
2016-10-06 18:05   ` [PATCH v2 0/5] Add runtime PM support for clocks (on Exynos SoC example) Tobias Jakobi
2016-10-06 18:05     ` Tobias Jakobi
2016-10-06 18:07     ` Tobias Jakobi
2016-10-06 18:07       ` Tobias Jakobi
2016-10-07  9:12     ` Marek Szyprowski
2016-10-07  9:12       ` Marek Szyprowski
2016-10-07 11:17       ` Tobias Jakobi
2016-10-07 11:17         ` Tobias Jakobi

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.