Skip to contentSkip to conversation

soc: samsung: Modify and enhance power domain driver

PATCH Superseded Amit Daniel Kachhap 7 participants 32 messages Nov 3, 2014 – Nov 28, 2014

Subsystems (15)

v1 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

cover soc: samsung: Modify and enhance power domain driver

This patch series[3 - 12] performs several implementations as described below,

1) Converts power domain driver to platform driver.
2) Registers this driver as MFD client driver.
3) Moves them into driver/soc/samsung folder.
4) Add new power domain notifier feature.
5) Uses those notfier from exynos clk.
6) Adds parent power domain and some other features mostly for exynos7 platforms.

This patch will change the DT representation of all the exynos power domain DT nodes which will be posted as a new patch series.

This patch has dependency on following patches posted earlier and most of them are already accepted or in final stages of review.
1) http://www.spinics.net/lists/linux-samsung-soc/msg37050.html
2) https://lkml.org/lkml/2014/10/6/581

Patches 1-2 are from Pankaj and have been posted earlier.
(http://lists.infradead.org/pipermail/linux-arm-kernel/2014-July/271555.html
They are kept in this patch series for completeness after rebase fixes.

This complete patch series is rebased on linux-next as it involves many subsystems.

Amit Daniel Kachhap (10):
PM / Domains: Add notifier support for power domain transitions
mfd: exynos-pmu: Register exynos-pmu driver as a mfd driver
arm: exynos: Add platform driver support for power domain driver
soc: exynos: Move exynos power domain file to driver/soc/samsung
folder
soc: samsung: pm_domain: Use compatible name for power domain name
soc: samsung: pm_domain: Add a new parameter for power configuration
soc: samsung: pm_domain: Add support for parent power domain
soc: samsung: pm_domain: Use the recently added PM Domain notifiers
clk: samsung: save and restore clock registers for power domain
arm64: Kconfig: Enable PM_GENERIC_DOMAINS for exynos7

Pankaj Dubey (2):
ARM: EXYNOS: Move pmu specific header files under "linux/mfd/samsung"
drivers: mfd: Add support for Exynos PMU driver

 .../bindings/arm/exynos/power_domain.txt           |   21 +++-
 arch/arm/mach-exynos/Kconfig                       |    1 +
 arch/arm/mach-exynos/Makefile                      |    3 +-
 arch/arm/mach-exynos/exynos.c                      |    2 +-
 arch/arm/mach-exynos/mcpm-exynos.c                 |    2 +-
 arch/arm/mach-exynos/platsmp.c                     |    2 +-
 arch/arm/mach-exynos/pm.c                          |    5 +-
 arch/arm/mach-exynos/suspend.c                     |    3 +-
 arch/arm64/Kconfig                                 |    1 +
 drivers/base/power/domain.c                        |  112 +++++++++++++++++-
 drivers/clk/samsung/clk.c                          |   66 +++++++++++
 drivers/clk/samsung/clk.h                          |   14 +++
 drivers/mfd/Kconfig                                |    9 ++
 drivers/mfd/Makefile                               |    1 +
 .../mach-exynos/pmu.c => drivers/mfd/exynos-pmu.c  |   30 ++++-
 drivers/soc/Kconfig                                |    1 +
 drivers/soc/Makefile                               |    1 +
 drivers/soc/samsung/Kconfig                        |   11 ++
 drivers/soc/samsung/Makefile                       |    1 +
 .../soc/samsung}/pm_domains.c                      |  124 ++++++++++++++++----
 .../linux/mfd/samsung}/exynos-pmu.h                |    5 +
 .../linux/mfd/samsung/exynos-regs-pmu.h            |    0
 include/linux/pm_domain.h                          |   31 +++++
 23 files changed, 409 insertions(+), 37 deletions(-)
 rename arch/arm/mach-exynos/pmu.c => drivers/mfd/exynos-pmu.c (96%)
 create mode 100644 drivers/soc/samsung/Kconfig
 create mode 100644 drivers/soc/samsung/Makefile
 rename {arch/arm/mach-exynos => drivers/soc/samsung}/pm_domains.c (51%)
 rename {arch/arm/mach-exynos => include/linux/mfd/samsung}/exynos-pmu.h (86%)
 rename arch/arm/mach-exynos/regs-pmu.h => include/linux/mfd/samsung/exynos-regs-pmu.h (100%)
Signature · 1 line
1.7.9.5
#1 lore raw

PATCH 1/12 ARM: EXYNOS: Move pmu specific header files under "linux/mfd/samsung"

From: Pankaj Dubey <[email protected]>

Moving Exynos PMU specific header file into "include/linux/mfd/samsung" thus updated affected files under "mach-exynos" to use new location of these header files.

---
 arch/arm/mach-exynos/exynos.c                      |    2 +-
 arch/arm/mach-exynos/mcpm-exynos.c                 |    2 +-
 arch/arm/mach-exynos/platsmp.c                     |    2 +-
 arch/arm/mach-exynos/pm.c                          |    5 +++--
 arch/arm/mach-exynos/pmu.c                         |    5 ++---
 arch/arm/mach-exynos/suspend.c                     |    3 ++-
 .../linux/mfd/samsung}/exynos-pmu.h                |    0
 .../linux/mfd/samsung/exynos-regs-pmu.h            |    0
 8 files changed, 10 insertions(+), 9 deletions(-)
 rename {arch/arm/mach-exynos => include/linux/mfd/samsung}/exynos-pmu.h (100%)
 rename arch/arm/mach-exynos/regs-pmu.h => include/linux/mfd/samsung/exynos-regs-pmu.h (100%)
arch/arm/mach-exynos/exynos.c +1 -1
index a487e59..f6b8cb1 100644
@@ -20,6 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
 #include <linux/irqchip.h>
+#include <linux/mfd/samsung/exynos-regs-pmu.h>
 
 #include <asm/cacheflush.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -29,7 +30,6 @@
 
 #include "common.h"
 #include "mfc.h"
-#include "regs-pmu.h"
 #include "regs-sys.h"
 
 void __iomem *pmu_base_addr;
arch/arm/mach-exynos/mcpm-exynos.c +1 -1
index dc9a764..5326b67 100644
@@ -15,12 +15,12 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/of_address.h>
+#include <linux/mfd/samsung/exynos-regs-pmu.h>
 
 #include <asm/cputype.h>
 #include <asm/cp15.h>
 #include <asm/mcpm.h>
 
-#include "regs-pmu.h"
 #include "common.h"
 
 #define EXYNOS5420_CPUS_PER_CLUSTER	4
arch/arm/mach-exynos/platsmp.c +1 -1
index adb36a8..16d6acd 100644
@@ -20,6 +20,7 @@
 #include <linux/smp.h>
 #include <linux/io.h>
 #include <linux/of_address.h>
+#include <linux/mfd/samsung/exynos-regs-pmu.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -30,7 +31,6 @@
 #include <mach/map.h>
 
 #include "common.h"
-#include "regs-pmu.h"
 
 extern void exynos4_secondary_startup(void);
 
arch/arm/mach-exynos/pm.c +3 -2
index 86f3ecd..8e0ffc3 100644
@@ -18,6 +18,9 @@
 #include <linux/cpu_pm.h>
 #include <linux/io.h>
 #include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/mfd/samsung/exynos-regs-pmu.h>
+#include <linux/mfd/samsung/exynos-pmu.h>
 
 #include <asm/firmware.h>
 #include <asm/smp_scu.h>
@@ -26,8 +29,6 @@
 #include <plat/pm-common.h>
 
 #include "common.h"
-#include "exynos-pmu.h"
-#include "regs-pmu.h"
 #include "regs-sys.h"
 
 static inline void __iomem *exynos_boot_vector_addr(void)
arch/arm/mach-exynos/pmu.c +2 -3
index 1993e08..07019f0 100644
@@ -12,9 +12,8 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
-
-#include "exynos-pmu.h"
-#include "regs-pmu.h"
+#include <linux/mfd/samsung/exynos-regs-pmu.h>
+#include <linux/mfd/samsung/exynos-pmu.h>
 
 #define PMU_TABLE_END	(-1U)
 
arch/arm/mach-exynos/suspend.c +2 -1
index f5d9773..df979f6 100644
@@ -20,6 +20,8 @@
 #include <linux/io.h>
 #include <linux/irqchip/arm-gic.h>
 #include <linux/err.h>
+#include <linux/mfd/samsung/exynos-pmu.h>
+#include <linux/mfd/samsung/exynos-regs-pmu.h>
 
 #include <asm/cacheflush.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -31,7 +33,6 @@
 #include <plat/regs-srom.h>
 
 #include "common.h"
-#include "regs-pmu.h"
 #include "regs-sys.h"
 
 #define S5P_CHECK_SLEEP 0x00000BAD
include/linux/mfd/samsung/exynos-pmu.h renamed from arch/arm/mach-exynos/exynos-pmu.h +0 -0
similarity index 100%
rename from arch/arm/mach-exynos/exynos-pmu.h
rename to include/linux/mfd/samsung/exynos-pmu.h
include/linux/mfd/samsung/exynos-regs-pmu.h renamed from arch/arm/mach-exynos/regs-pmu.h +0 -0
similarity index 100%
rename from arch/arm/mach-exynos/regs-pmu.h
rename to include/linux/mfd/samsung/exynos-regs-pmu.h
Signature · 1 line
1.7.9.5
#2 lore raw

PATCH 2/12 drivers: mfd: Add support for Exynos PMU driver

In reply to Amit Daniel Kachhap

From: Pankaj Dubey <[email protected]>

This patch moves Exynos PMU driver implementation from "arm/mach-exynos" to "drivers/mfd". This driver is mainly used for setting misc bits of register from PMU IP of Exynos SoC which will be required to configure before Suspend/Resume. Currently all these settings are done in "arch/arm/mach-exynos/pmu.c" but moving ahead for ARM64 based SoC support, there is a need of DT based implementation of PMU driver.

This driver uses already existing DT binding information.

---
 arch/arm/mach-exynos/Kconfig                       |    1 +
 arch/arm/mach-exynos/Makefile                      |    2 +-
 drivers/mfd/Kconfig                                |    9 +++++++++
 drivers/mfd/Makefile                               |    1 +
 .../mach-exynos/pmu.c => drivers/mfd/exynos-pmu.c  |    0
 5 files changed, 12 insertions(+), 1 deletion(-)
 rename arch/arm/mach-exynos/pmu.c => drivers/mfd/exynos-pmu.c (100%)
arch/arm/mach-exynos/Kconfig +1 -0
index 96d56ab..c2aef3f 100644
@@ -25,6 +25,7 @@ menuconfig ARCH_EXYNOS
 	select S5P_DEV_MFC
 	select SRAM
 	select MFD_SYSCON
+	select MFD_EXYNOS_PMU
 	help
 	  Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5)
 
arch/arm/mach-exynos/Makefile +1 -1
index bcefb54..b91b382 100644
@@ -9,7 +9,7 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) += -I$(srctree)/$(src)/include -I$(srctree)
 
 # Core
 
-obj-$(CONFIG_ARCH_EXYNOS)	+= exynos.o pmu.o exynos-smc.o firmware.o
+obj-$(CONFIG_ARCH_EXYNOS)	+= exynos.o exynos-smc.o firmware.o
 
 obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm.o sleep.o
 obj-$(CONFIG_PM_SLEEP)		+= suspend.o
drivers/mfd/Kconfig +9 -0
index cbdb109..619a9ba 100644
@@ -1323,6 +1323,15 @@ config MFD_STW481X
 	  in various ST Microelectronics and ST-Ericsson embedded
 	  Nomadik series.
 
+config MFD_EXYNOS_PMU
+	tristate "Support Exynos Power Management Unit"
+	depends on ARM || ARM64
+	help
+	  Exynos SoC have Power Management Unit (PMU) which controls power and
+	  operation state of Exynos SoC in two different ways. This driver
+	  provides implementation of PMU driver and provides basic functionality
+	  required during these operation state.
+
 menu "Multimedia Capabilities Port drivers"
 	depends on ARCH_SA1100
 
drivers/mfd/Makefile +1 -0
index 8e679d6..33489b4 100644
@@ -175,6 +175,7 @@ obj-$(CONFIG_MFD_STW481X)	+= stw481x.o
 obj-$(CONFIG_MFD_IPAQ_MICRO)	+= ipaq-micro.o
 obj-$(CONFIG_MFD_MENF21BMC)	+= menf21bmc.o
 obj-$(CONFIG_MFD_HI6421_PMIC)	+= hi6421-pmic-core.o
+obj-$(CONFIG_MFD_EXYNOS_PMU)	+= exynos-pmu.o
 
 intel-soc-pmic-objs		:= intel_soc_pmic_core.o intel_soc_pmic_crc.o
 obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
drivers/mfd/exynos-pmu.c renamed from arch/arm/mach-exynos/pmu.c +0 -0
similarity index 100%
rename from arch/arm/mach-exynos/pmu.c
rename to drivers/mfd/exynos-pmu.c
Signature · 1 line
1.7.9.5
#3 lore raw

PATCH 2/12 drivers: mfd: Add support for Exynos PMU driver

Quoted 16 lines · Amit Daniel Kachhap

From: Pankaj Dubey <[email protected]>

This patch moves Exynos PMU driver implementation from "arm/mach-exynos" to "drivers/mfd". This driver is mainly used for setting misc bits of register from PMU IP of Exynos SoC which will be required to configure before Suspend/Resume. Currently all these settings are done in "arch/arm/mach-exynos/pmu.c" but moving ahead for ARM64 based SoC support, there is a need of DT based implementation of PMU driver.

This driver uses already existing DT binding information.

Quoted 8 lines
---
 arch/arm/mach-exynos/Kconfig                       |    1 +
 arch/arm/mach-exynos/Makefile                      |    2 +-
 drivers/mfd/Kconfig                                |    9 +++++++++
 drivers/mfd/Makefile                               |    1 +
 .../mach-exynos/pmu.c => drivers/mfd/exynos-pmu.c  |    0
 5 files changed, 12 insertions(+), 1 deletion(-)
 rename arch/arm/mach-exynos/pmu.c => drivers/mfd/exynos-pmu.c (100%)

I thought we spoke about this already [1]? What's changed?

[1] https://lkml.org/lkml/2014/4/29/193

Signature · 4 lines
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
#4 lore raw

PATCH 2/12 drivers: mfd: Add support for Exynos PMU driver

Hi Lee,

On Monday, November 03, 2014 8:56 PM, Lee Jones wrote,

Quoted 29 lines

Subject: Re: [PATCH 02/12] drivers: mfd: Add support for Exynos PMU driver

Quoted 16 lines · Amit Daniel Kachhap

From: Pankaj Dubey <[email protected]>

This patch moves Exynos PMU driver implementation from "arm/mach-exynos" to "drivers/mfd". This driver is mainly used for setting misc bits of register from PMU IP of Exynos SoC which will be required to configure before Suspend/Resume. Currently all these settings are done in "arch/arm/mach-exynos/pmu.c" but moving ahead for ARM64 based SoC support, there is a need of DT based implementation of PMU driver.

This driver uses already existing DT binding information.

Quoted 8 lines
---
 arch/arm/mach-exynos/Kconfig                       |    1 +
 arch/arm/mach-exynos/Makefile                      |    2 +-
 drivers/mfd/Kconfig                                |    9 +++++++++
 drivers/mfd/Makefile                               |    1 +
 .../mach-exynos/pmu.c => drivers/mfd/exynos-pmu.c  |    0
 5 files changed, 12 insertions(+), 1 deletion(-)  rename

arch/arm/mach-exynos/pmu.c => drivers/mfd/exynos-pmu.c (100%)

Quoted 4 lines

I thought we spoke about this already [1]? What's changed?

[1] https://lkml.org/lkml/2014/4/29/193

Yes correct, we had discussion about this in above post. But at that time I was not having enough points to put forward for keeping Exynos PMU driver in MFD folder.
At that point there was only one idea behind keeping Exynos PMU that in future it will be reused for ARM64 based SoC for PM related functionalities.
But in this series we have implemented Exynos Power Domain for Samsung's ARM64 based SoCs.

As far as I can see this will in following ways -

1: Moving out PM domain specific code from mach-exynos and reuse of same code for ARM64 based SoC also. 2: Since PM domain relies on PMU registers and does not have its own DT binding, MFD client and MFD device is most suitable for making this kind of platform drivers.

Quoted 4 lines

--
Lee Jones

Linaro STMicroelectronics Landing Team Lead Linaro.org │ Open source software
for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
#5 lore raw

PATCH 2/12 drivers: mfd: Add support for Exynos PMU driver

Quoted 30 lines · Pankaj Dubey

On Monday, November 03, 2014 8:56 PM, Lee Jones wrote,

Quoted 29 lines

Subject: Re: [PATCH 02/12] drivers: mfd: Add support for Exynos PMU driver

Quoted 24 lines · Amit Daniel Kachhap

From: Pankaj Dubey <[email protected]>

This patch moves Exynos PMU driver implementation from "arm/mach-exynos" to "drivers/mfd". This driver is mainly used for setting misc bits of register from PMU IP of Exynos SoC which will be required to configure before Suspend/Resume. Currently all these settings are done in "arch/arm/mach-exynos/pmu.c" but moving ahead for ARM64 based SoC support, there is a need of DT based implementation of PMU driver.

This driver uses already existing DT binding information.

---
 arch/arm/mach-exynos/Kconfig                       |    1 +
 arch/arm/mach-exynos/Makefile                      |    2 +-
 drivers/mfd/Kconfig                                |    9 +++++++++
 drivers/mfd/Makefile                               |    1 +
 .../mach-exynos/pmu.c => drivers/mfd/exynos-pmu.c  |    0
 5 files changed, 12 insertions(+), 1 deletion(-)  rename

arch/arm/mach-exynos/pmu.c => drivers/mfd/exynos-pmu.c (100%)

Quoted 7 lines
Quoted 4 lines

I thought we spoke about this already [1]? What's changed?

[1] https://lkml.org/lkml/2014/4/29/193

Yes correct, we had discussion about this in above post. But at that time I was not having enough points to put forward for keeping Exynos PMU driver in MFD folder.

There are no valid points for keeping PMU code in MFD.

Quoted 9 lines

At that point there was only one idea behind keeping Exynos PMU that in future it will be reused for ARM64 based SoC for PM related functionalities.
But in this series we have implemented Exynos Power Domain for Samsung's ARM64 based SoCs.

As far as I can see this will in following ways -

1: Moving out PM domain specific code from mach-exynos and reuse of same code for ARM64 based SoC also. 2: Since PM domain relies on PMU registers and does not have its own DT binding, MFD client and MFD device is most suitable for making this kind of platform drivers.

MFD can be used to register the device, but the driver must not live in MFD. Please relocate it into drivers/power.

Signature · 4 lines
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
#6 lore raw

PATCH 2/12 drivers: mfd: Add support for Exynos PMU driver

In reply to Pankaj Dubey
Quoted 3 lines · Pankaj Dubey

2: Since PM domain relies on PMU registers and does not have its own DT binding, MFD client and MFD device
is most suitable for making this kind of platform drivers.

We have DT binding for the Exynos power domains:
Documentation/devicetree/bindings/arm/exynos/power_domain.txt In fact the IO memory regions used in the power domain bindings fall within the (sparse) PMU registers region.

There is also DT binding for the PMU subsystem:
Documentation/devicetree/bindings/arm/samsung/pmu.txt

I guess a platform device driver in drivers/power would be a better fit than drivers/mfd. I doubt introducing an mfd driver now makes much sense, we have already DT bindings for PHYs, the power domains, etc.

--
Thanks,
Sylwester

#7 lore raw

PATCH 3/12 PM / Domains: Add notifier support for power domain transitions

In reply to Amit Daniel Kachhap

These power domain transition notifiers will assist in carrying out some activity associated with domain power on/off such as some registers which may lose its contents and need save/restore across domain power off/on.

4 type of notifications are added,

GPD_OFF_PRE     - GPD state before power off
GPD_OFF_POST    - GPD state after power off
GPD_ON_PRE      - GPD state before power off
GPD_ON_POST     - GPD state after power off

3 notfication API's are exported.
1) int genpd_register_notifier(struct notifier_block *nb, char *pd_name);
2) int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name);
3) void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,

			enum gpd_on_off_state state);

In this approach the notifiers are registered/unregistered with pd name. The actual invoking of the notfiers will be done by the platform implementing power domain enable/disable low level handlers according to the above defined notification types. This approach will considerably reduce the number of call to notifiers as compared to calling always from core powerdomain subsystem.

Also the registered domain's will be managed inside a cache list and not part of the genpd structure. This will help in registration of notifiers from subsystems (such as clock) even when the PD subsystem is still not initialised. This list also filters out the unregistered pd's requesting notification.

---
 drivers/base/power/domain.c |  112 ++++++++++++++++++++++++++++++++++++++++++-
 include/linux/pm_domain.h   |   31 ++++++++++++
 2 files changed, 142 insertions(+), 1 deletion(-)
drivers/base/power/domain.c +111 -1
index 40bc2f4..e05045e 100644
@@ -46,10 +46,19 @@
 	__retval;								\
 })
 
+struct cache_notify_domains {
+	char *name;
+	/* Node in the cache pm domain name list */
+	struct list_head cache_list_node;
+};
+
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
+static LIST_HEAD(domain_notify_list);
+static DEFINE_MUTEX(domain_notify_list_lock);
+static BLOCKING_NOTIFIER_HEAD(genpd_transition_notifier_list);
 
-static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
+struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
 {
 	struct generic_pm_domain *genpd = NULL, *gpd;
 
@@ -66,6 +75,7 @@ static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
 	mutex_unlock(&gpd_list_lock);
 	return genpd;
 }
+EXPORT_SYMBOL_GPL(pm_genpd_lookup_name);
 
 struct generic_pm_domain *dev_to_genpd(struct device *dev)
 {
@@ -1908,6 +1918,106 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
 	mutex_unlock(&gpd_list_lock);
 }
 
+/**
+ * genpd_register_notifier - Register a PM domain for future notification.
+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */
+int genpd_register_notifier(struct notifier_block *nb, char *pd_name)
+{
+	int ret;
+	struct cache_notify_domains *entry;
+
+	if (!pd_name)
+		return -EINVAL;
+
+	/* Search if the pd is already registered */
+	mutex_lock(&domain_notify_list_lock);
+	list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+		if (!strcmp(entry->name, pd_name))
+			break;
+	}
+	mutex_unlock(&domain_notify_list_lock);
+
+	if (entry) {
+		pr_err("%s: pd already exists\n", __func__);
+		return -EINVAL;
+	}
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	entry->name = pd_name;
+
+	mutex_lock(&domain_notify_list_lock);
+	list_add(&entry->cache_list_node, &domain_notify_list);
+	mutex_unlock(&domain_notify_list_lock);
+	ret = blocking_notifier_chain_register(
+				&genpd_transition_notifier_list, nb);
+	return ret;
+}
+
+/**
+ * genpd_unregister_notifier - Un-register a PM domain for future notification.
+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */
+int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name)
+{
+	int ret;
+	struct cache_notify_domains *entry;
+
+	mutex_lock(&domain_notify_list_lock);
+	list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+		if (!strcmp(entry->name, pd_name))
+			break;
+	}
+	if (!entry) {
+		mutex_unlock(&domain_notify_list_lock);
+		pr_err("%s: Invalid pd name\n", __func__);
+		return -EINVAL;
+	}
+	list_del(&entry->cache_list_node);
+	mutex_unlock(&domain_notify_list_lock);
+	ret = blocking_notifier_chain_unregister(
+				&genpd_transition_notifier_list, nb);
+	return ret;
+}
+
+/**
+ * genpd_invoke_transition_notifier - Calls the matching notification handler.
+ * @genpd: generic power domain structure.
+ * @state: can be of type - GPD_OFF_PRE/GPD_OFF_POST/GPD_ON_PRE/GPD_ON_POST.
+ */
+void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+			enum gpd_on_off_state state)
+{
+	struct cache_notify_domains *entry;
+
+	if (!genpd) {
+		pr_err("Invalid genpd parameter\n");
+		return;
+	}
+
+	if (state != GPD_OFF_PRE || state != GPD_OFF_POST
+			|| state != GPD_ON_PRE || state != GPD_ON_POST) {
+		pr_err("Invalid state parameter\n");
+		return;
+	}
+
+	mutex_lock(&domain_notify_list_lock);
+	list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+		if (!strcmp(entry->name, genpd->name))
+			break;
+	}
+	mutex_unlock(&domain_notify_list_lock);
+	if (!entry) /* Simply ignore */
+		return;
+
+	blocking_notifier_call_chain(&genpd_transition_notifier_list, state,
+				genpd);
+}
 #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
 /*
  * Device Tree based PM domain providers.
include/linux/pm_domain.h +31 -0
index 73e938b..659997f 100644
@@ -25,6 +25,13 @@ enum gpd_status {
 	GPD_STATE_POWER_OFF,	/* PM domain is off */
 };
 
+enum gpd_on_off_state {
+	GPD_OFF_PRE = 0,	/* GPD state before power off */
+	GPD_OFF_POST,		/* GPD state after power off */
+	GPD_ON_PRE,		/* GPD state before power on */
+	GPD_ON_POST,		/* GPD state after power on */
+};
+
 struct dev_power_governor {
 	bool (*power_down_ok)(struct dev_pm_domain *domain);
 	bool (*stop_ok)(struct device *dev);
@@ -148,6 +155,12 @@ extern int pm_genpd_name_poweron(const char *domain_name);
 
 extern struct dev_power_governor simple_qos_governor;
 extern struct dev_power_governor pm_domain_always_on_gov;
+
+struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name);
+int genpd_register_notifier(struct notifier_block *nb, char *pd_name);
+int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name);
+void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+			enum gpd_on_off_state state);
 #else
 
 static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev)
@@ -219,6 +232,24 @@ static inline int pm_genpd_name_poweron(const char *domain_name)
 {
 	return -ENOSYS;
 }
+static inline struct
+generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
+{
+	return NULL;
+}
+static inline int
+genpd_register_notifier(struct notifier_block *nb, char *pd_name)
+{
+	return 0;
+}
+static inline int
+genpd_unregister_notifier(struct notifier_block *nb, char *pd_name)
+{
+	return 0;
+}
+static inline void
+genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+			enum gpd_on_off_state state) { }
 #define simple_qos_governor NULL
 #define pm_domain_always_on_gov NULL
 #endif
Signature · 1 line
1.7.9.5
#8 lore raw

PATCH 3/12 PM / Domains: Add notifier support for power domain transitions

CC Kevin, Ulf, Geert.
Quoted 234 lines · Amit Daniel Kachhap

These power domain transition notifiers will assist in carrying out some activity associated with domain power on/off such as some registers which may lose its contents and need save/restore across domain power off/on.

4 type of notifications are added,

GPD_OFF_PRE     - GPD state before power off
GPD_OFF_POST    - GPD state after power off
GPD_ON_PRE      - GPD state before power off
GPD_ON_POST     - GPD state after power off

3 notfication API's are exported.
1) int genpd_register_notifier(struct notifier_block *nb, char *pd_name);
2) int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name);
3) void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,

			enum gpd_on_off_state state);

In this approach the notifiers are registered/unregistered with pd name. The actual invoking of the notfiers will be done by the platform implementing power domain enable/disable low level handlers according to the above defined notification types. This approach will considerably reduce the number of call to notifiers as compared to calling always from core powerdomain subsystem.

Also the registered domain's will be managed inside a cache list and not part of the genpd structure. This will help in registration of notifiers from subsystems (such as clock) even when the PD subsystem is still not initialised. This list also filters out the unregistered pd's requesting notification.

---
 drivers/base/power/domain.c |  112 ++++++++++++++++++++++++++++++++++++++++++-
 include/linux/pm_domain.h   |   31 ++++++++++++
 2 files changed, 142 insertions(+), 1 deletion(-)
drivers/base/power/domain.c +111 -1
index 40bc2f4..e05045e 100644
@@ -46,10 +46,19 @@
 	__retval;								\
 })
 
+struct cache_notify_domains {
+	char *name;
+	/* Node in the cache pm domain name list */
+	struct list_head cache_list_node;
+};
+
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
+static LIST_HEAD(domain_notify_list);
+static DEFINE_MUTEX(domain_notify_list_lock);
+static BLOCKING_NOTIFIER_HEAD(genpd_transition_notifier_list);
 
-static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
+struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
 {
 	struct generic_pm_domain *genpd = NULL, *gpd;
 
@@ -66,6 +75,7 @@ static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
 	mutex_unlock(&gpd_list_lock);
 	return genpd;
 }
+EXPORT_SYMBOL_GPL(pm_genpd_lookup_name);
 
 struct generic_pm_domain *dev_to_genpd(struct device *dev)
 {
@@ -1908,6 +1918,106 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
 	mutex_unlock(&gpd_list_lock);
 }
 
+/**
+ * genpd_register_notifier - Register a PM domain for future notification.
+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */
+int genpd_register_notifier(struct notifier_block *nb, char *pd_name)
+{
+	int ret;
+	struct cache_notify_domains *entry;
+
+	if (!pd_name)
+		return -EINVAL;
+
+	/* Search if the pd is already registered */
+	mutex_lock(&domain_notify_list_lock);
+	list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+		if (!strcmp(entry->name, pd_name))
+			break;
+	}
+	mutex_unlock(&domain_notify_list_lock);
+
+	if (entry) {
+		pr_err("%s: pd already exists\n", __func__);
+		return -EINVAL;
+	}
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	entry->name = pd_name;
+
+	mutex_lock(&domain_notify_list_lock);
+	list_add(&entry->cache_list_node, &domain_notify_list);
+	mutex_unlock(&domain_notify_list_lock);
+	ret = blocking_notifier_chain_register(
+				&genpd_transition_notifier_list, nb);
+	return ret;
+}
+
+/**
+ * genpd_unregister_notifier - Un-register a PM domain for future notification.
+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */
+int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name)
+{
+	int ret;
+	struct cache_notify_domains *entry;
+
+	mutex_lock(&domain_notify_list_lock);
+	list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+		if (!strcmp(entry->name, pd_name))
+			break;
+	}
+	if (!entry) {
+		mutex_unlock(&domain_notify_list_lock);
+		pr_err("%s: Invalid pd name\n", __func__);
+		return -EINVAL;
+	}
+	list_del(&entry->cache_list_node);
+	mutex_unlock(&domain_notify_list_lock);
+	ret = blocking_notifier_chain_unregister(
+				&genpd_transition_notifier_list, nb);
+	return ret;
+}
+
+/**
+ * genpd_invoke_transition_notifier - Calls the matching notification handler.
+ * @genpd: generic power domain structure.
+ * @state: can be of type - GPD_OFF_PRE/GPD_OFF_POST/GPD_ON_PRE/GPD_ON_POST.
+ */
+void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+			enum gpd_on_off_state state)
+{
+	struct cache_notify_domains *entry;
+
+	if (!genpd) {
+		pr_err("Invalid genpd parameter\n");
+		return;
+	}
+
+	if (state != GPD_OFF_PRE || state != GPD_OFF_POST
+			|| state != GPD_ON_PRE || state != GPD_ON_POST) {
+		pr_err("Invalid state parameter\n");
+		return;
+	}
+
+	mutex_lock(&domain_notify_list_lock);
+	list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+		if (!strcmp(entry->name, genpd->name))
+			break;
+	}
+	mutex_unlock(&domain_notify_list_lock);
+	if (!entry) /* Simply ignore */
+		return;
+
+	blocking_notifier_call_chain(&genpd_transition_notifier_list, state,
+				genpd);
+}
 #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
 /*
  * Device Tree based PM domain providers.
include/linux/pm_domain.h +31 -0
index 73e938b..659997f 100644
@@ -25,6 +25,13 @@ enum gpd_status {
 	GPD_STATE_POWER_OFF,	/* PM domain is off */
 };
 
+enum gpd_on_off_state {
+	GPD_OFF_PRE = 0,	/* GPD state before power off */
+	GPD_OFF_POST,		/* GPD state after power off */
+	GPD_ON_PRE,		/* GPD state before power on */
+	GPD_ON_POST,		/* GPD state after power on */
+};
+
 struct dev_power_governor {
 	bool (*power_down_ok)(struct dev_pm_domain *domain);
 	bool (*stop_ok)(struct device *dev);
@@ -148,6 +155,12 @@ extern int pm_genpd_name_poweron(const char *domain_name);
 
 extern struct dev_power_governor simple_qos_governor;
 extern struct dev_power_governor pm_domain_always_on_gov;
+
+struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name);
+int genpd_register_notifier(struct notifier_block *nb, char *pd_name);
+int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name);
+void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+			enum gpd_on_off_state state);
 #else
 
 static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev)
@@ -219,6 +232,24 @@ static inline int pm_genpd_name_poweron(const char *domain_name)
 {
 	return -ENOSYS;
 }
+static inline struct
+generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
+{
+	return NULL;
+}
+static inline int
+genpd_register_notifier(struct notifier_block *nb, char *pd_name)
+{
+	return 0;
+}
+static inline int
+genpd_unregister_notifier(struct notifier_block *nb, char *pd_name)
+{
+	return 0;
+}
+static inline void
+genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+			enum gpd_on_off_state state) { }
 #define simple_qos_governor NULL
 #define pm_domain_always_on_gov NULL
 #endif
Signature · 2 lines
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
#9 lore raw

PATCH 3/12 PM / Domains: Add notifier support for power domain transitions

Quoted 7 lines · Rafael J. Wysocki
CC Kevin, Ulf, Geert.
Quoted 4 lines · Amit Daniel Kachhap

These power domain transition notifiers will assist in carrying out some activity associated with domain power on/off such as some registers which may lose its contents and need save/restore across domain power off/on.

Hi Amit,

This mechanism seems to be needed - somehow.
A similar approach has been posted earlier, I am not sure that discussion was fully settled though.

http://marc.info/?l=linux-pm&m=136448756308203&w=2

Anyway, I plan to review this shortly.

Kind regards
Uffe

Quoted 238 lines
Quoted 220 lines

4 type of notifications are added,

GPD_OFF_PRE     - GPD state before power off
GPD_OFF_POST    - GPD state after power off
GPD_ON_PRE      - GPD state before power off
GPD_ON_POST     - GPD state after power off

3 notfication API's are exported.
1) int genpd_register_notifier(struct notifier_block *nb, char *pd_name);
2) int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name);
3) void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,

                      enum gpd_on_off_state state);

In this approach the notifiers are registered/unregistered with pd name. The actual invoking of the notfiers will be done by the platform implementing power domain enable/disable low level handlers according to the above defined notification types. This approach will considerably reduce the number of call to notifiers as compared to calling always from core powerdomain subsystem.

Also the registered domain's will be managed inside a cache list and not part of the genpd structure. This will help in registration of notifiers from subsystems (such as clock) even when the PD subsystem is still not initialised. This list also filters out the unregistered pd's requesting notification.

---
 drivers/base/power/domain.c |  112 ++++++++++++++++++++++++++++++++++++++++++-
 include/linux/pm_domain.h   |   31 ++++++++++++
 2 files changed, 142 insertions(+), 1 deletion(-)
drivers/base/power/domain.c +111 -1
index 40bc2f4..e05045e 100644
@@ -46,10 +46,19 @@
      __retval;                                                               \
 })
 
+struct cache_notify_domains {
+     char *name;
+     /* Node in the cache pm domain name list */
+     struct list_head cache_list_node;
+};
+
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
+static LIST_HEAD(domain_notify_list);
+static DEFINE_MUTEX(domain_notify_list_lock);
+static BLOCKING_NOTIFIER_HEAD(genpd_transition_notifier_list);
 
-static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
+struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
 {
      struct generic_pm_domain *genpd = NULL, *gpd;
 
@@ -66,6 +75,7 @@ static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
      mutex_unlock(&gpd_list_lock);
      return genpd;
 }
+EXPORT_SYMBOL_GPL(pm_genpd_lookup_name);
 
 struct generic_pm_domain *dev_to_genpd(struct device *dev)
 {
@@ -1908,6 +1918,106 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
      mutex_unlock(&gpd_list_lock);
 }
 
+/**
+ * genpd_register_notifier - Register a PM domain for future notification.
+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */
+int genpd_register_notifier(struct notifier_block *nb, char *pd_name)
+{
+     int ret;
+     struct cache_notify_domains *entry;
+
+     if (!pd_name)
+             return -EINVAL;
+
+     /* Search if the pd is already registered */
+     mutex_lock(&domain_notify_list_lock);
+     list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+             if (!strcmp(entry->name, pd_name))
+                     break;
+     }
+     mutex_unlock(&domain_notify_list_lock);
+
+     if (entry) {
+             pr_err("%s: pd already exists\n", __func__);
+             return -EINVAL;
+     }
+
+     entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+     if (!entry)
+             return -ENOMEM;
+
+     entry->name = pd_name;
+
+     mutex_lock(&domain_notify_list_lock);
+     list_add(&entry->cache_list_node, &domain_notify_list);
+     mutex_unlock(&domain_notify_list_lock);
+     ret = blocking_notifier_chain_register(
+                             &genpd_transition_notifier_list, nb);
+     return ret;
+}
+
+/**
+ * genpd_unregister_notifier - Un-register a PM domain for future notification.
+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */
+int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name)
+{
+     int ret;
+     struct cache_notify_domains *entry;
+
+     mutex_lock(&domain_notify_list_lock);
+     list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+             if (!strcmp(entry->name, pd_name))
+                     break;
+     }
+     if (!entry) {
+             mutex_unlock(&domain_notify_list_lock);
+             pr_err("%s: Invalid pd name\n", __func__);
+             return -EINVAL;
+     }
+     list_del(&entry->cache_list_node);
+     mutex_unlock(&domain_notify_list_lock);
+     ret = blocking_notifier_chain_unregister(
+                             &genpd_transition_notifier_list, nb);
+     return ret;
+}
+
+/**
+ * genpd_invoke_transition_notifier - Calls the matching notification handler.
+ * @genpd: generic power domain structure.
+ * @state: can be of type - GPD_OFF_PRE/GPD_OFF_POST/GPD_ON_PRE/GPD_ON_POST.
+ */
+void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+                     enum gpd_on_off_state state)
+{
+     struct cache_notify_domains *entry;
+
+     if (!genpd) {
+             pr_err("Invalid genpd parameter\n");
+             return;
+     }
+
+     if (state != GPD_OFF_PRE || state != GPD_OFF_POST
+                     || state != GPD_ON_PRE || state != GPD_ON_POST) {
+             pr_err("Invalid state parameter\n");
+             return;
+     }
+
+     mutex_lock(&domain_notify_list_lock);
+     list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+             if (!strcmp(entry->name, genpd->name))
+                     break;
+     }
+     mutex_unlock(&domain_notify_list_lock);
+     if (!entry) /* Simply ignore */
+             return;
+
+     blocking_notifier_call_chain(&genpd_transition_notifier_list, state,
+                             genpd);
+}
 #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
 /*
  * Device Tree based PM domain providers.
include/linux/pm_domain.h +24 -0
index 73e938b..659997f 100644
@@ -25,6 +25,13 @@ enum gpd_status {
      GPD_STATE_POWER_OFF,    /* PM domain is off */
 };
 
+enum gpd_on_off_state {
+     GPD_OFF_PRE = 0,        /* GPD state before power off */
+     GPD_OFF_POST,           /* GPD state after power off */
+     GPD_ON_PRE,             /* GPD state before power on */
+     GPD_ON_POST,            /* GPD state after power on */
+};
+
 struct dev_power_governor {
      bool (*power_down_ok)(struct dev_pm_domain *domain);
      bool (*stop_ok)(struct device *dev);
@@ -148,6 +155,12 @@ extern int pm_genpd_name_poweron(const char *domain_name);
 
 extern struct dev_power_governor simple_qos_governor;
 extern struct dev_power_governor pm_domain_always_on_gov;
+
+struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name);
+int genpd_register_notifier(struct notifier_block *nb, char *pd_name);
+int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name);
+void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+                     enum gpd_on_off_state state);
 #else
 
 static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev)
@@ -219,6 +232,24 @@ static inline int pm_genpd_name_poweron(const char *domain_name)
 {
      return -ENOSYS;
 }
+static inline struct
+generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
+{
+     return NULL;
+}
+static inline int
+genpd_register_notifier(struct notifier_block *nb, char *pd_name)
+{
+     return 0;
+}
+static inline int

include/linux/pm_domain.h static inline int pm_genpd_name_poweron(const char *domain_name) · line 255

Quoted 10 lines
include/linux/pm_domain.h +7 -0
+genpd_unregister_notifier(struct notifier_block *nb, char *pd_name)
+{
+     return 0;
+}
+static inline void
+genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+                     enum gpd_on_off_state state) { }
 #define simple_qos_governor NULL
 #define pm_domain_always_on_gov NULL
 #endif

--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#10 lore raw

PATCH 3/12 PM / Domains: Add notifier support for power domain transitions

Quoted 9 lines · Ulf Hansson
Quoted 7 lines · Rafael J. Wysocki
CC Kevin, Ulf, Geert.
Quoted 4 lines · Amit Daniel Kachhap

These power domain transition notifiers will assist in carrying out some activity associated with domain power on/off such as some registers which may lose its contents and need save/restore across domain power off/on.

Quoted 7 lines

Hi Amit,

This mechanism seems to be needed - somehow.
A similar approach has been posted earlier, I am not sure that discussion was fully settled though.

http://marc.info/?l=linux-pm&m=136448756308203&w=2

Missed looking into it. Thanks for the pointer.

Quoted 2 lines

Anyway, I plan to review this shortly.

Sure.

Quoted 246 lines

Kind regards
Uffe

Quoted 231 lines
Quoted 220 lines

4 type of notifications are added,

GPD_OFF_PRE     - GPD state before power off
GPD_OFF_POST    - GPD state after power off
GPD_ON_PRE      - GPD state before power off
GPD_ON_POST     - GPD state after power off

3 notfication API's are exported.
1) int genpd_register_notifier(struct notifier_block *nb, char *pd_name);
2) int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name);
3) void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,

                      enum gpd_on_off_state state);

In this approach the notifiers are registered/unregistered with pd name. The actual invoking of the notfiers will be done by the platform implementing power domain enable/disable low level handlers according to the above defined notification types. This approach will considerably reduce the number of call to notifiers as compared to calling always from core powerdomain subsystem.

Also the registered domain's will be managed inside a cache list and not part of the genpd structure. This will help in registration of notifiers from subsystems (such as clock) even when the PD subsystem is still not initialised. This list also filters out the unregistered pd's requesting notification.

---
 drivers/base/power/domain.c |  112 ++++++++++++++++++++++++++++++++++++++++++-
 include/linux/pm_domain.h   |   31 ++++++++++++
 2 files changed, 142 insertions(+), 1 deletion(-)
drivers/base/power/domain.c +111 -1
index 40bc2f4..e05045e 100644
@@ -46,10 +46,19 @@
      __retval;                                                               \
 })
 
+struct cache_notify_domains {
+     char *name;
+     /* Node in the cache pm domain name list */
+     struct list_head cache_list_node;
+};
+
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
+static LIST_HEAD(domain_notify_list);
+static DEFINE_MUTEX(domain_notify_list_lock);
+static BLOCKING_NOTIFIER_HEAD(genpd_transition_notifier_list);
 
-static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
+struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
 {
      struct generic_pm_domain *genpd = NULL, *gpd;
 
@@ -66,6 +75,7 @@ static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
      mutex_unlock(&gpd_list_lock);
      return genpd;
 }
+EXPORT_SYMBOL_GPL(pm_genpd_lookup_name);
 
 struct generic_pm_domain *dev_to_genpd(struct device *dev)
 {
@@ -1908,6 +1918,106 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
      mutex_unlock(&gpd_list_lock);
 }
 
+/**
+ * genpd_register_notifier - Register a PM domain for future notification.
+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */
+int genpd_register_notifier(struct notifier_block *nb, char *pd_name)
+{
+     int ret;
+     struct cache_notify_domains *entry;
+
+     if (!pd_name)
+             return -EINVAL;
+
+     /* Search if the pd is already registered */
+     mutex_lock(&domain_notify_list_lock);
+     list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+             if (!strcmp(entry->name, pd_name))
+                     break;
+     }
+     mutex_unlock(&domain_notify_list_lock);
+
+     if (entry) {
+             pr_err("%s: pd already exists\n", __func__);
+             return -EINVAL;
+     }
+
+     entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+     if (!entry)
+             return -ENOMEM;
+
+     entry->name = pd_name;
+
+     mutex_lock(&domain_notify_list_lock);
+     list_add(&entry->cache_list_node, &domain_notify_list);
+     mutex_unlock(&domain_notify_list_lock);
+     ret = blocking_notifier_chain_register(
+                             &genpd_transition_notifier_list, nb);
+     return ret;
+}
+
+/**
+ * genpd_unregister_notifier - Un-register a PM domain for future notification.
+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */
+int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name)
+{
+     int ret;
+     struct cache_notify_domains *entry;
+
+     mutex_lock(&domain_notify_list_lock);
+     list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+             if (!strcmp(entry->name, pd_name))
+                     break;
+     }
+     if (!entry) {
+             mutex_unlock(&domain_notify_list_lock);
+             pr_err("%s: Invalid pd name\n", __func__);
+             return -EINVAL;
+     }
+     list_del(&entry->cache_list_node);
+     mutex_unlock(&domain_notify_list_lock);
+     ret = blocking_notifier_chain_unregister(
+                             &genpd_transition_notifier_list, nb);
+     return ret;
+}
+
+/**
+ * genpd_invoke_transition_notifier - Calls the matching notification handler.
+ * @genpd: generic power domain structure.
+ * @state: can be of type - GPD_OFF_PRE/GPD_OFF_POST/GPD_ON_PRE/GPD_ON_POST.
+ */
+void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+                     enum gpd_on_off_state state)
+{
+     struct cache_notify_domains *entry;
+
+     if (!genpd) {
+             pr_err("Invalid genpd parameter\n");
+             return;
+     }
+
+     if (state != GPD_OFF_PRE || state != GPD_OFF_POST
+                     || state != GPD_ON_PRE || state != GPD_ON_POST) {
+             pr_err("Invalid state parameter\n");
+             return;
+     }
+
+     mutex_lock(&domain_notify_list_lock);
+     list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+             if (!strcmp(entry->name, genpd->name))
+                     break;
+     }
+     mutex_unlock(&domain_notify_list_lock);
+     if (!entry) /* Simply ignore */
+             return;
+
+     blocking_notifier_call_chain(&genpd_transition_notifier_list, state,
+                             genpd);
+}
 #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
 /*
  * Device Tree based PM domain providers.
include/linux/pm_domain.h +24 -0
index 73e938b..659997f 100644
@@ -25,6 +25,13 @@ enum gpd_status {
      GPD_STATE_POWER_OFF,    /* PM domain is off */
 };
 
+enum gpd_on_off_state {
+     GPD_OFF_PRE = 0,        /* GPD state before power off */
+     GPD_OFF_POST,           /* GPD state after power off */
+     GPD_ON_PRE,             /* GPD state before power on */
+     GPD_ON_POST,            /* GPD state after power on */
+};
+
 struct dev_power_governor {
      bool (*power_down_ok)(struct dev_pm_domain *domain);
      bool (*stop_ok)(struct device *dev);
@@ -148,6 +155,12 @@ extern int pm_genpd_name_poweron(const char *domain_name);
 
 extern struct dev_power_governor simple_qos_governor;
 extern struct dev_power_governor pm_domain_always_on_gov;
+
+struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name);
+int genpd_register_notifier(struct notifier_block *nb, char *pd_name);
+int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name);
+void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+                     enum gpd_on_off_state state);
 #else
 
 static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev)
@@ -219,6 +232,24 @@ static inline int pm_genpd_name_poweron(const char *domain_name)
 {
      return -ENOSYS;
 }
+static inline struct
+generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
+{
+     return NULL;
+}
+static inline int
+genpd_register_notifier(struct notifier_block *nb, char *pd_name)
+{
+     return 0;
+}
+static inline int

include/linux/pm_domain.h static inline int pm_genpd_name_poweron(const char *domain_name) · line 255

Quoted 10 lines
include/linux/pm_domain.h +7 -0
+genpd_unregister_notifier(struct notifier_block *nb, char *pd_name)
+{
+     return 0;
+}
+static inline void
+genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+                     enum gpd_on_off_state state) { }
 #define simple_qos_governor NULL
 #define pm_domain_always_on_gov NULL
 #endif
Quoted 7 lines

--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

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

#11 lore raw

PATCH 3/12 PM / Domains: Add notifier support for power domain transitions

In reply to Rafael J. Wysocki

+Mike Turquette

Hi Amit,

Quoted 7 lines · Rafael J. Wysocki
CC Kevin, Ulf, Geert.
Quoted 4 lines · Amit Daniel Kachhap

These power domain transition notifiers will assist in carrying out some activity associated with domain power on/off such as some registers which may lose its contents and need save/restore across domain power off/on.

The runtime PM framework already provides callbacks that are useful for context save/restore for devices. Could you please describe in more detail which registers in which kind of devices need to be saved/restored, and why they cannot be saved/restored using existing mechanisms.

Personally, I'm uncomfortable with notifiers like this because it suggests that underlying frameworks are not doing the right thing, or are not being used. (I also don't like the implementation here where a single global notifier list is maintained by the core, but the notifiers are actually triggered by SoC specific code.)

IIUC, the usage in this series seems to be that certain clock related registers need to be saved/restored across a power domain transition.

Wouldn't an alternative solution be to add a feature to the clock driver such that the state of each clock is saved when the clock is disabled,
and restored when the clock is enabled? That would allow any clock
context to survive any power domain transtion also, correct?

I have some issues with the implementaion as well, but I think we need to first sort out the real need for this before going into those details.

Kevin

#12 lore raw

PATCH 3/12 PM / Domains: Add notifier support for power domain transitions

Quoted 14 lines · Kevin Hilman

+Mike Turquette

Hi Amit,

Quoted 7 lines · Rafael J. Wysocki
CC Kevin, Ulf, Geert.
Quoted 4 lines · Amit Daniel Kachhap

These power domain transition notifiers will assist in carrying out some activity associated with domain power on/off such as some registers which may lose its contents and need save/restore across domain power off/on.

Quoted 5 lines

The runtime PM framework already provides callbacks that are useful for context save/restore for devices. Could you please describe in more detail which registers in which kind of devices need to be saved/restored, and why they cannot be saved/restored using existing mechanisms.

Basically the requirement is mandated by exynos7 manual. It tells that before turning off the power domain, some clock registers need to saved and should be restored just after turning the power domain. These clock registers are not necessarily gate clocks but could be mux clocks etc. The driver may not have all information of these clocks also. I suppose these are Soc specific changes but drivers should work across Socs. This behavior is almost similar to suspend/resume case where a whole list of clock registers are saved/restored.

Even earlier post by Sylwester (https://lkml.org/lkml/2014/8/5/182) also points to the need of this feature.

Quoted 6 lines

Personally, I'm uncomfortable with notifiers like this because it suggests that underlying frameworks are not doing the right thing, or are not being used. (I also don't like the implementation here where a single global notifier list is maintained by the core, but the notifiers are actually triggered by SoC specific code.)

Yes right the global notifier block can be moved to per genpd structure. Also SoC trigger can be moved to core files.

Quoted 8 lines

IIUC, the usage in this series seems to be that certain clock related registers need to be saved/restored across a power domain transition.

Wouldn't an alternative solution be to add a feature to the clock driver such that the state of each clock is saved when the clock is disabled,
and restored when the clock is enabled? That would allow any clock
context to survive any power domain transtion also, correct?

I also thought about same. But the trigger point for this would be driver calling
clk disable/enable and not the power domain. so this will lead to lot of save/restore for each power domain child.

Quoted 4 lines

I have some issues with the implementaion as well, but I think we need to first sort out the real need for this before going into those details.

right :( may be I should have posted this as RFC
Thanks for the review.

Regards,
Amit D

Quoted 7 lines

Kevin

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

#13 lore raw

PATCH 3/12 PM / Domains: Add notifier support for power domain transitions

Quoted 14 lines · amit daniel kachhap
Quoted 7 lines · Kevin Hilman
Quoted 5 lines · Rafael J. Wysocki
Quoted 4 lines · Amit Daniel Kachhap

These power domain transition notifiers will assist in carrying out some activity associated with domain power on/off such as some registers which may lose its contents and need save/restore across domain power off/on.

Quoted 5 lines

The runtime PM framework already provides callbacks that are useful for context save/restore for devices. Could you please describe in more detail which registers in which kind of devices need to be saved/restored, and why they cannot be saved/restored using existing mechanisms.

Quoted 8 lines

Basically the requirement is mandated by exynos7 manual. It tells that before turning off the power domain, some clock registers need to saved and should be restored just after turning the power domain. These clock registers are not necessarily gate clocks but could be mux clocks etc. The driver may not have all information of these clocks also. I suppose these are Soc specific changes but drivers should work across Socs. This behavior is almost similar to suspend/resume case where a whole list of clock registers are saved/restored.

Indeed, the somehow complicated power domain power on/off sequences are SoC specific. They involve not only groups of clocks (usually gate, mux clock registers of all devices in a power domain) but also SoC-specific PMU (Power Management Unit) registers.
I assume it would be inappropriate to push such details to device drivers. Moreover, a device driver could not be even loaded.

Since the clocks' state is already maintained by clk driver we came up with an idea of having generic calls from power domain driver back to the clock controller driver.

It might not to be the prettiest solution, nevertheless I couldn't come up with a better one which would satisfy all the requirements. The power domain should only be provided for use with all the clk/PMU sequences handling in place.

Clocks need to also be touched before a power domain switch on or off, so attaching the clock controller to some power domain wouldn't help, unless we modify/add to existing power domain related callbacks for devices. Another issue is the clock controller device would need to be attached to multiple power domains, and for each power domain the power on/off sequence is usually slightly different.

There are also hierarchical power domains where each: the master and the sub-domain need they own sequence and device usually is attached only to a sub-domain.

Quoted 15 lines

Even earlier post by Sylwester (https://lkml.org/lkml/2014/8/5/182)
also points to the need of this feature.

Quoted 6 lines

Personally, I'm uncomfortable with notifiers like this because it suggests that underlying frameworks are not doing the right thing, or are not being used. (I also don't like the implementation here where a single global notifier list is maintained by the core, but the notifiers are actually triggered by SoC specific code.)

Yes right the global notifier block can be moved to per genpd structure. Also SoC trigger can be moved to core files.

Quoted 4 lines

IIUC, the usage in this series seems to be that certain clock related registers need to be saved/restored across a power domain transition.

Quoted 8 lines
Quoted 4 lines

Wouldn't an alternative solution be to add a feature to the clock driver such that the state of each clock is saved when the clock is disabled,
and restored when the clock is enabled? That would allow any clock
context to survive any power domain transtion also, correct?

I also thought about same. But the trigger point for this would be driver calling clk disable/enable and not the power domain. so this will lead to lot of save/restore for each power domain child.

Even though we would have saved/restored at that points still the power domain driver would need to enforce some specific clock/PMU registers state before/after a power domain state transition. And this is what I found difficult with the existing APIs.

--
Thanks,
Sylwester

#14 lore raw

PATCH 3/12 PM / Domains: Add notifier support for power domain transitions

Quoted 31 lines · Sylwester Nawrocki
Quoted 14 lines · amit daniel kachhap
Quoted 7 lines · Kevin Hilman
Quoted 5 lines · Rafael J. Wysocki
Quoted 4 lines · Amit Daniel Kachhap

These power domain transition notifiers will assist in carrying out some activity associated with domain power on/off such as some registers which may lose its contents and need save/restore across domain power off/on.

Quoted 5 lines

The runtime PM framework already provides callbacks that are useful for context save/restore for devices. Could you please describe in more detail which registers in which kind of devices need to be saved/restored, and why they cannot be saved/restored using existing mechanisms.

Quoted 8 lines

Basically the requirement is mandated by exynos7 manual. It tells that before turning off the power domain, some clock registers need to saved and should be restored just after turning the power domain. These clock registers are not necessarily gate clocks but could be mux clocks etc. The driver may not have all information of these clocks also. I suppose these are Soc specific changes but drivers should work across Socs. This behavior is almost similar to suspend/resume case where a whole list of clock registers are saved/restored.

Indeed, the somehow complicated power domain power on/off sequences are SoC specific. They involve not only groups of clocks (usually gate, mux clock registers of all devices in a power domain) but also SoC-specific PMU (Power Management Unit) registers.
I assume it would be inappropriate to push such details to device drivers. Moreover, a device driver could not be even loaded.

Quoted 3 lines

Since the clocks' state is already maintained by clk driver we came up with an idea of having generic calls from power domain driver back to the clock controller driver.

For the clock tree, it still seems to me that this is better handled in the SoC clock driver. For example, when a power domain is about to be gated, all the devices in that domain are runtime suspended, and presumably all of their gate clocks are disabled. Now, doesn't the clock driver know the clock tree parent-child hierarchy and shouldn't it be capable of saving the state of parent clocks (like mux clocks) etc?

Stated diffrently, it still seems to me like we're pushing functionality in PM core notifiers that should be the responsibility of subsystem drivers.

Quoted 36 lines

It might not to be the prettiest solution, nevertheless I couldn't come up with a better one which would satisfy all the requirements. The power domain should only be provided for use with all the clk/PMU sequences handling in place.

Clocks need to also be touched before a power domain switch on or off, so attaching the clock controller to some power domain wouldn't help, unless we modify/add to existing power domain related callbacks for devices. Another issue is the clock controller device would need to be attached to multiple power domains, and for each power domain the power on/off sequence is usually slightly different.

There are also hierarchical power domains where each: the master and the sub-domain need they own sequence and device usually is attached only to a sub-domain.

Quoted 20 lines

Even earlier post by Sylwester (https://lkml.org/lkml/2014/8/5/182)
also points to the need of this feature.

Quoted 6 lines

Personally, I'm uncomfortable with notifiers like this because it suggests that underlying frameworks are not doing the right thing, or are not being used. (I also don't like the implementation here where a single global notifier list is maintained by the core, but the notifiers are actually triggered by SoC specific code.)

Yes right the global notifier block can be moved to per genpd structure. Also SoC trigger can be moved to core files.

Quoted 8 lines

IIUC, the usage in this series seems to be that certain clock related registers need to be saved/restored across a power domain transition.

Wouldn't an alternative solution be to add a feature to the clock driver such that the state of each clock is saved when the clock is disabled,
and restored when the clock is enabled? That would allow any clock
context to survive any power domain transtion also, correct?

Quoted 8 lines
Quoted 3 lines

I also thought about same. But the trigger point for this would be driver calling clk disable/enable and not the power domain. so this will lead to lot of save/restore for each power domain child.

Even though we would have saved/restored at that points still the power domain driver would need to enforce some specific clock/PMU registers state before/after a power domain state transition. And this is what I found difficult with the existing APIs.

This is what I'm not understanding.

Why can't the power domain driver's power_on/power_off callback just call the PMU APIs and/or the clk_enable/_disable calls it needs?

Kevin

#15 lore raw

PATCH 3/12 PM / Domains: Add notifier support for power domain transitions

Quoted 93 lines · Kevin Hilman
Quoted 31 lines · Sylwester Nawrocki
Quoted 14 lines · amit daniel kachhap
Quoted 7 lines · Kevin Hilman
Quoted 5 lines · Rafael J. Wysocki
Quoted 4 lines · Amit Daniel Kachhap

These power domain transition notifiers will assist in carrying out some activity associated with domain power on/off such as some registers which may lose its contents and need save/restore across domain power off/on.

Quoted 5 lines

The runtime PM framework already provides callbacks that are useful for context save/restore for devices. Could you please describe in more detail which registers in which kind of devices need to be saved/restored, and why they cannot be saved/restored using existing mechanisms.

Quoted 8 lines

Basically the requirement is mandated by exynos7 manual. It tells that before turning off the power domain, some clock registers need to saved and should be restored just after turning the power domain. These clock registers are not necessarily gate clocks but could be mux clocks etc. The driver may not have all information of these clocks also. I suppose these are Soc specific changes but drivers should work across Socs. This behavior is almost similar to suspend/resume case where a whole list of clock registers are saved/restored.

Indeed, the somehow complicated power domain power on/off sequences are SoC specific. They involve not only groups of clocks (usually gate, mux clock registers of all devices in a power domain) but also SoC-specific PMU (Power Management Unit) registers.
I assume it would be inappropriate to push such details to device drivers. Moreover, a device driver could not be even loaded.

Quoted 3 lines

Since the clocks' state is already maintained by clk driver we came up with an idea of having generic calls from power domain driver back to the clock controller driver.

For the clock tree, it still seems to me that this is better handled in the SoC clock driver. For example, when a power domain is about to be gated, all the devices in that domain are runtime suspended, and presumably all of their gate clocks are disabled. Now, doesn't the clock driver know the clock tree parent-child hierarchy and shouldn't it be capable of saving the state of parent clocks (like mux clocks) etc?

Stated diffrently, it still seems to me like we're pushing functionality in PM core notifiers that should be the responsibility of subsystem drivers.

Quoted 36 lines

It might not to be the prettiest solution, nevertheless I couldn't come up with a better one which would satisfy all the requirements. The power domain should only be provided for use with all the clk/PMU sequences handling in place.

Clocks need to also be touched before a power domain switch on or off, so attaching the clock controller to some power domain wouldn't help, unless we modify/add to existing power domain related callbacks for devices. Another issue is the clock controller device would need to be attached to multiple power domains, and for each power domain the power on/off sequence is usually slightly different.

There are also hierarchical power domains where each: the master and the sub-domain need they own sequence and device usually is attached only to a sub-domain.

Quoted 20 lines

Even earlier post by Sylwester (https://lkml.org/lkml/2014/8/5/182)
also points to the need of this feature.

Quoted 6 lines

Personally, I'm uncomfortable with notifiers like this because it suggests that underlying frameworks are not doing the right thing, or are not being used. (I also don't like the implementation here where a single global notifier list is maintained by the core, but the notifiers are actually triggered by SoC specific code.)

Yes right the global notifier block can be moved to per genpd structure. Also SoC trigger can be moved to core files.

Quoted 8 lines

IIUC, the usage in this series seems to be that certain clock related registers need to be saved/restored across a power domain transition.

Wouldn't an alternative solution be to add a feature to the clock driver such that the state of each clock is saved when the clock is disabled,
and restored when the clock is enabled? That would allow any clock
context to survive any power domain transtion also, correct?

Quoted 8 lines
Quoted 3 lines

I also thought about same. But the trigger point for this would be driver calling clk disable/enable and not the power domain. so this will lead to lot of save/restore for each power domain child.

Even though we would have saved/restored at that points still the power domain driver would need to enforce some specific clock/PMU registers state before/after a power domain state transition. And this is what I found difficult with the existing APIs.

Quoted 4 lines

This is what I'm not understanding.

Why can't the power domain driver's power_on/power_off callback just call the PMU APIs and/or the clk_enable/_disable calls it needs?

This looks possible for clock enable/disable at least. Will further check the implementation
feasibility and reply.

Regards,
Amit

Quoted 9 lines

Kevin

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

#16 lore raw

PATCH 3/12 PM / Domains: Add notifier support for power domain transitions

In reply to Kevin Hilman
Quoted 5 lines · Kevin Hilman
Quoted 4 lines · Sylwester Nawrocki
Quoted 3 lines · amit daniel kachhap
Quoted 2 lines · Kevin Hilman
Quoted 1 line · Rafael J. Wysocki

On Monday, November 03, 2014 09:23:01 AM Amit Daniel Kachhap wrote:

[...]

Quoted 18 lines
Quoted 10 lines

Indeed, the somehow complicated power domain power on/off sequences are SoC specific. They involve not only groups of clocks (usually gate, mux clock registers of all devices in a power domain) but also SoC-specific PMU (Power Management Unit) registers.
I assume it would be inappropriate to push such details to device drivers. Moreover, a device driver could not be even loaded.

Since the clocks' state is already maintained by clk driver we came up with an idea of having generic calls from power domain driver back to the clock controller driver.

For the clock tree, it still seems to me that this is better handled in the SoC clock driver. For example, when a power domain is about to be gated, all the devices in that domain are runtime suspended, and presumably all of their gate clocks are disabled. Now, doesn't the clock driver know the clock tree parent-child hierarchy and shouldn't it be capable of saving the state of parent clocks (like mux clocks) etc?

Quoted 3 lines

Stated diffrently, it still seems to me like we're pushing functionality in PM core notifiers that should be the responsibility of subsystem drivers.

My apologies for not replying earlier, I got distracted by other activities.

I'd prefer not adding anything new to the PM core, however there are dependencies between the power domain and clock controller driver which are hard to model in the current APIs. I assume resorting to inter-exynos-driver API is not a good idea either.

Saving/restoring the clock hierarchy in the clock controller driver during the power domain state transitions has a caveat that the clock turn off/on sequences are IP/SoC subsystem specific. So simply restoring saved registers from memory is not going to work.

The other detail I might have forgotten to mention is that the whole clock controller may be in same power domain as the consumer devices. That means the clock controller's registers must not be touched when a related power domain is turned off. Naturally when a power domain gets switched off all the clock controller's registers reset to their default values. If we decided to use pm_runtime_{get_sync, put} in the clock controller driver I'm not sure how it would need to interact with the clk API.
In current mainline there is an issue with exynos4x12 that the system may hang if clk_summary is attempted to read as the clock controller driver doesn't take the ISP power domain into account.

[...]

Quoted 26 lines
Quoted 17 lines
Quoted 17 lines
Quoted 5 lines

Personally, I'm uncomfortable with notifiers like this because it suggests that underlying frameworks are not doing the right thing, or are not being used. (I also don't like the implementation here where a single global notifier list is maintained by the core, but the notifiers are actually triggered by SoC specific code.)

Yes right the global notifier block can be moved to per genpd structure. Also SoC trigger can be moved to core files.

Quoted 8 lines

IIUC, the usage in this series seems to be that certain clock related registers need to be saved/restored across a power domain transition.

Wouldn't an alternative solution be to add a feature to the clock driver such that the state of each clock is saved when the clock is disabled,
and restored when the clock is enabled? That would allow any clock
context to survive any power domain transtion also, correct?

Quoted 8 lines
Quoted 3 lines

I also thought about same. But the trigger point for this would be driver calling clk disable/enable and not the power domain. so this will lead to lot of save/restore for each power domain child.

Even though we would have saved/restored at that points still the power domain driver would need to enforce some specific clock/PMU registers state before/after a power domain state transition. And this is what I found difficult with the existing APIs.

Quoted 4 lines

This is what I'm not understanding.

Why can't the power domain driver's power_on/power_off callback just call the PMU APIs and/or the clk_enable/_disable calls it needs?

I was concerned that it would not have been reliable by using the clk API due to the clk enable refcounting. But that might not be a valid argument, since as you pointed out when a power domain is about to be gated related the clocks should be already disabled.

The other concern was atomicity in enabling/disabling groups of clocks, i.e. setting group of bits in a clock gate register at once, rather than a bit for each clock one by one. But I'm not 100% sure about such a hardware requirement myself, would need to do some more testing and/or find a hardware engineer who could explain this.

Additionally specifying clocks in device tree would be a bit messy and there would very likely anyway be an additional information required in the power domain driver per each power domain regarding the clock handling sequence.

Signature · 2 lines
Regards,
Sylwester
#17 lore raw

PATCH 3/12 PM / Domains: Add notifier support for power domain transitions

In reply to Amit Daniel Kachhap

Hi,

Cc Ulf, Kevin, Geert.
Quoted 4 lines · Amit Daniel Kachhap

These power domain transition notifiers will assist in carrying out some activity associated with domain power on/off such as some registers which may lose its contents and need save/restore across domain power off/on.

Other specific use cases I could add here is gating selected clocks to ensure proper signal propagation for devices attached to a power domain, e.g. ungating selected clocks before the power domain on and restoring them to previous state after the power domain was switched on.

Quoted 19 lines

4 type of notifications are added,

GPD_OFF_PRE     - GPD state before power off
GPD_OFF_POST    - GPD state after power off
GPD_ON_PRE      - GPD state before power off
GPD_ON_POST     - GPD state after power off

3 notfication API's are exported.
1) int genpd_register_notifier(struct notifier_block *nb, char *pd_name);
2) int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name);
3) void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,

			enum gpd_on_off_state state);

In this approach the notifiers are registered/unregistered with pd name. The actual invoking of the notfiers will be done by the platform implementing power domain enable/disable low level handlers according to the above defined notification types. This approach will considerably reduce the number of call to notifiers as compared to calling always from core powerdomain subsystem.

Quoted 4 lines

Also the registered domain's will be managed inside a cache list and not part of the genpd structure. This will help in registration of notifiers from subsystems (such as clock) even when the PD subsystem is still not initialised. This list also filters out the unregistered pd's requesting notification.

This patch is somewhat similar my patch adding power domain state change notifications [1]. I have already a reworked version of that patch, with the notifier list moved to struct generic_pm_domain and using genpd->lock instead of dev->power.lock. Anyway, while I'd leave the decision about the location from where the notifier chains are supposed to be called to the subsystem's maintainers preference, I'm rather reluctant to having one global notifiers list for all possible power domains and all the notification clients. The possibly long list needs to be traversed at each notifier call and it seems in your implementation any registered user of the notification gets notifications for all possible power domains.

[1] https://lkml.org/lkml/2014/8/5/182

Quoted 59 lines
---
 drivers/base/power/domain.c |  112 ++++++++++++++++++++++++++++++++++++++++++-
 include/linux/pm_domain.h   |   31 ++++++++++++
 2 files changed, 142 insertions(+), 1 deletion(-)
drivers/base/power/domain.c +25 -1
index 40bc2f4..e05045e 100644
@@ -46,10 +46,19 @@
 	__retval;								\
 })
 
+struct cache_notify_domains {
+	char *name;
+	/* Node in the cache pm domain name list */
+	struct list_head cache_list_node;
+};
+
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
+static LIST_HEAD(domain_notify_list);
+static DEFINE_MUTEX(domain_notify_list_lock);
+static BLOCKING_NOTIFIER_HEAD(genpd_transition_notifier_list);
 
-static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
+struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
 {
 	struct generic_pm_domain *genpd = NULL, *gpd;
 
@@ -66,6 +75,7 @@ static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
 	mutex_unlock(&gpd_list_lock);
 	return genpd;
 }
+EXPORT_SYMBOL_GPL(pm_genpd_lookup_name);
 
 struct generic_pm_domain *dev_to_genpd(struct device *dev)
 {
@@ -1908,6 +1918,106 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
 	mutex_unlock(&gpd_list_lock);
 }
 
+/**
+ * genpd_register_notifier - Register a PM domain for future notification.
+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */
+int genpd_register_notifier(struct notifier_block *nb, char *pd_name)
+{
+	int ret;
+	struct cache_notify_domains *entry;
+
+	if (!pd_name)
+		return -EINVAL;
+
+	/* Search if the pd is already registered */

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 1944

Quoted 10 lines
drivers/base/power/domain.c +10 -0
+	mutex_lock(&domain_notify_list_lock);
+	list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+		if (!strcmp(entry->name, pd_name))
+			break;
+	}
+	mutex_unlock(&domain_notify_list_lock);
+
+	if (entry) {
+		pr_err("%s: pd already exists\n", __func__);
+		return -EINVAL;

I suspect this code doesn't work as expected. 'entry' will be NULL only in case of an empty domain_notify_list list. Have you tested multiple calls to genpd_register_notifier() ? It looks like only the first call would work.

Quoted 27 lines
drivers/base/power/domain.c +27 -0
+	}
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	entry->name = pd_name;
+
+	mutex_lock(&domain_notify_list_lock);
+	list_add(&entry->cache_list_node, &domain_notify_list);
+	mutex_unlock(&domain_notify_list_lock);
+	ret = blocking_notifier_chain_register(
+				&genpd_transition_notifier_list, nb);
+	return ret;
+}
+
+/**
+ * genpd_unregister_notifier - Un-register a PM domain for future notification.
+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */
+int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name)
+{
+	int ret;
+	struct cache_notify_domains *entry;
+
+	mutex_lock(&domain_notify_list_lock);

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 1981

Quoted 10 lines
drivers/base/power/domain.c +10 -0
+	list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+		if (!strcmp(entry->name, pd_name))
+			break;
+	}
+	if (!entry) {
+		mutex_unlock(&domain_notify_list_lock);
+		pr_err("%s: Invalid pd name\n", __func__);
+		return -EINVAL;
+	}
+	list_del(&entry->cache_list_node);

'entry' will not be NULL even when the requested notification entry was not found above. In such case it looks like last entry in the domain_notify_list list will be removed, not something we would expect.

Quoted 24 lines
drivers/base/power/domain.c +24 -0
+	mutex_unlock(&domain_notify_list_lock);
+	ret = blocking_notifier_chain_unregister(
+				&genpd_transition_notifier_list, nb);
+	return ret;
+}
+
+/**
+ * genpd_invoke_transition_notifier - Calls the matching notification handler.
+ * @genpd: generic power domain structure.
+ * @state: can be of type - GPD_OFF_PRE/GPD_OFF_POST/GPD_ON_PRE/GPD_ON_POST.
+ */
+void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+			enum gpd_on_off_state state)
+{
+	struct cache_notify_domains *entry;
+
+	if (!genpd) {
+		pr_err("Invalid genpd parameter\n");
+		return;
+	}
+
+	if (state != GPD_OFF_PRE || state != GPD_OFF_POST
+			|| state != GPD_ON_PRE || state != GPD_ON_POST) {
+		pr_err("Invalid state parameter\n");

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 2015

Quoted 10 lines
drivers/base/power/domain.c +10 -0
+		return;
+	}
+
+	mutex_lock(&domain_notify_list_lock);
+	list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+		if (!strcmp(entry->name, genpd->name))
+			break;
+	}
+	mutex_unlock(&domain_notify_list_lock);
+	if (!entry) /* Simply ignore */

Similar issue here, this condition will only be true when the notifications list is empty.

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 2019

Quoted 4 lines
drivers/base/power/domain.c +4 -0
+		return;
+
+	blocking_notifier_call_chain(&genpd_transition_notifier_list, state,
+				genpd);

And finally regardless of to what power domain the notification user has registered it will get notification for each possible power domain in the system? Are the notification users supposed to test the 'genpd' argument to react on a specific power domain? If so, how? I guess not by nother strcmp() ?

Quoted 9 lines
drivers/base/power/domain.c +1 -0
+}
 #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
 /*
  * Device Tree based PM domain providers.
include/linux/pm_domain.h +0 -0
index 73e938b..659997f 100644

include/linux/pm_domain.h enum gpd_status { · line 29

Quoted 5 lines
include/linux/pm_domain.h +2 -0
@@ -25,6 +25,13 @@ enum gpd_status {
 	GPD_STATE_POWER_OFF,	/* PM domain is off */
 };
 
+enum gpd_on_off_state {
+	GPD_OFF_PRE = 0,	/* GPD state before power off */

The assignment is not needed.

include/linux/pm_domain.h extern int pm_genpd_name_poweron(const char *domain_name);

Quoted 9 lines
include/linux/pm_domain.h +5 -0
+	GPD_OFF_POST,		/* GPD state after power off */
+	GPD_ON_PRE,		/* GPD state before power on */
+	GPD_ON_POST,		/* GPD state after power on */
+};
+
 struct dev_power_governor {
 	bool (*power_down_ok)(struct dev_pm_domain *domain);
 	bool (*stop_ok)(struct device *dev);
@@ -148,6 +155,12 @@ extern int pm_genpd_name_poweron(const char *domain_name);

--
Regards,
Sylwester

#18 lore raw

PATCH 3/12 PM / Domains: Add notifier support for power domain transitions

Now really filling in the CC list, apologies for duplicate post.

Quoted 249 lines · Sylwester Nawrocki

Hi,

Cc Ulf, Kevin, Geert.
Quoted 4 lines · Amit Daniel Kachhap

These power domain transition notifiers will assist in carrying out some activity associated with domain power on/off such as some registers which may lose its contents and need save/restore across domain power off/on.

Other specific use cases I could add here is gating selected clocks to ensure proper signal propagation for devices attached to a power domain, e.g. ungating selected clocks before the power domain on and restoring them to previous state after the power domain was switched on.

Quoted 19 lines

4 type of notifications are added,

GPD_OFF_PRE     - GPD state before power off
GPD_OFF_POST    - GPD state after power off
GPD_ON_PRE      - GPD state before power off
GPD_ON_POST     - GPD state after power off

3 notfication API's are exported.
1) int genpd_register_notifier(struct notifier_block *nb, char *pd_name);
2) int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name);
3) void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,

			enum gpd_on_off_state state);

In this approach the notifiers are registered/unregistered with pd name. The actual invoking of the notfiers will be done by the platform implementing power domain enable/disable low level handlers according to the above defined notification types. This approach will considerably reduce the number of call to notifiers as compared to calling always from core powerdomain subsystem.

Quoted 4 lines

Also the registered domain's will be managed inside a cache list and not part of the genpd structure. This will help in registration of notifiers from subsystems (such as clock) even when the PD subsystem is still not initialised. This list also filters out the unregistered pd's requesting notification.

This patch is somewhat similar my patch adding power domain state change notifications [1]. I have already a reworked version of that patch, with the notifier list moved to struct generic_pm_domain and using genpd->lock instead of dev->power.lock. Anyway, while I'd leave the decision about the location from where the notifier chains are supposed to be called to the subsystem's maintainers preference, I'm rather reluctant to having one global notifiers list for all possible power domains and all the notification clients. The possibly long list needs to be traversed at each notifier call and it seems in your implementation any registered user of the notification gets notifications for all possible power domains.

[1] https://lkml.org/lkml/2014/8/5/182

Quoted 59 lines
---
 drivers/base/power/domain.c |  112 ++++++++++++++++++++++++++++++++++++++++++-
 include/linux/pm_domain.h   |   31 ++++++++++++
 2 files changed, 142 insertions(+), 1 deletion(-)
drivers/base/power/domain.c +25 -1
index 40bc2f4..e05045e 100644
@@ -46,10 +46,19 @@
 	__retval;								\
 })
 
+struct cache_notify_domains {
+	char *name;
+	/* Node in the cache pm domain name list */
+	struct list_head cache_list_node;
+};
+
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
+static LIST_HEAD(domain_notify_list);
+static DEFINE_MUTEX(domain_notify_list_lock);
+static BLOCKING_NOTIFIER_HEAD(genpd_transition_notifier_list);
 
-static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
+struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
 {
 	struct generic_pm_domain *genpd = NULL, *gpd;
 
@@ -66,6 +75,7 @@ static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
 	mutex_unlock(&gpd_list_lock);
 	return genpd;
 }
+EXPORT_SYMBOL_GPL(pm_genpd_lookup_name);
 
 struct generic_pm_domain *dev_to_genpd(struct device *dev)
 {
@@ -1908,6 +1918,106 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
 	mutex_unlock(&gpd_list_lock);
 }
 
+/**
+ * genpd_register_notifier - Register a PM domain for future notification.
+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */
+int genpd_register_notifier(struct notifier_block *nb, char *pd_name)
+{
+	int ret;
+	struct cache_notify_domains *entry;
+
+	if (!pd_name)
+		return -EINVAL;
+
+	/* Search if the pd is already registered */

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 1944

Quoted 10 lines
drivers/base/power/domain.c +10 -0
+	mutex_lock(&domain_notify_list_lock);
+	list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+		if (!strcmp(entry->name, pd_name))
+			break;
+	}
+	mutex_unlock(&domain_notify_list_lock);
+
+	if (entry) {
+		pr_err("%s: pd already exists\n", __func__);
+		return -EINVAL;

I suspect this code doesn't work as expected. 'entry' will be NULL only in case of an empty domain_notify_list list. Have you tested multiple calls to genpd_register_notifier() ? It looks like only the first call would work.

Quoted 27 lines
drivers/base/power/domain.c +27 -0
+	}
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	entry->name = pd_name;
+
+	mutex_lock(&domain_notify_list_lock);
+	list_add(&entry->cache_list_node, &domain_notify_list);
+	mutex_unlock(&domain_notify_list_lock);
+	ret = blocking_notifier_chain_register(
+				&genpd_transition_notifier_list, nb);
+	return ret;
+}
+
+/**
+ * genpd_unregister_notifier - Un-register a PM domain for future notification.
+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */
+int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name)
+{
+	int ret;
+	struct cache_notify_domains *entry;
+
+	mutex_lock(&domain_notify_list_lock);

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 1981

Quoted 10 lines
drivers/base/power/domain.c +10 -0
+	list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+		if (!strcmp(entry->name, pd_name))
+			break;
+	}
+	if (!entry) {
+		mutex_unlock(&domain_notify_list_lock);
+		pr_err("%s: Invalid pd name\n", __func__);
+		return -EINVAL;
+	}
+	list_del(&entry->cache_list_node);

'entry' will not be NULL even when the requested notification entry was not found above. In such case it looks like last entry in the domain_notify_list list will be removed, not something we would expect.

Quoted 24 lines
drivers/base/power/domain.c +24 -0
+	mutex_unlock(&domain_notify_list_lock);
+	ret = blocking_notifier_chain_unregister(
+				&genpd_transition_notifier_list, nb);
+	return ret;
+}
+
+/**
+ * genpd_invoke_transition_notifier - Calls the matching notification handler.
+ * @genpd: generic power domain structure.
+ * @state: can be of type - GPD_OFF_PRE/GPD_OFF_POST/GPD_ON_PRE/GPD_ON_POST.
+ */
+void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+			enum gpd_on_off_state state)
+{
+	struct cache_notify_domains *entry;
+
+	if (!genpd) {
+		pr_err("Invalid genpd parameter\n");
+		return;
+	}
+
+	if (state != GPD_OFF_PRE || state != GPD_OFF_POST
+			|| state != GPD_ON_PRE || state != GPD_ON_POST) {
+		pr_err("Invalid state parameter\n");

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 2015

Quoted 10 lines
drivers/base/power/domain.c +10 -0
+		return;
+	}
+
+	mutex_lock(&domain_notify_list_lock);
+	list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+		if (!strcmp(entry->name, genpd->name))
+			break;
+	}
+	mutex_unlock(&domain_notify_list_lock);
+	if (!entry) /* Simply ignore */

Similar issue here, this condition will only be true when the notifications list is empty.

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 2019

Quoted 4 lines
drivers/base/power/domain.c +4 -0
+		return;
+
+	blocking_notifier_call_chain(&genpd_transition_notifier_list, state,
+				genpd);

And finally regardless of to what power domain the notification user has registered it will get notification for each possible power domain in the system? Are the notification users supposed to test the 'genpd' argument to react on a specific power domain? If so, how? I guess not by nother strcmp() ?

Quoted 9 lines
drivers/base/power/domain.c +1 -0
+}
 #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
 /*
  * Device Tree based PM domain providers.
include/linux/pm_domain.h +0 -0
index 73e938b..659997f 100644

include/linux/pm_domain.h enum gpd_status { · line 29

Quoted 5 lines
include/linux/pm_domain.h +2 -0
@@ -25,6 +25,13 @@ enum gpd_status {
 	GPD_STATE_POWER_OFF,	/* PM domain is off */
 };
 
+enum gpd_on_off_state {
+	GPD_OFF_PRE = 0,	/* GPD state before power off */

The assignment is not needed.

include/linux/pm_domain.h extern int pm_genpd_name_poweron(const char *domain_name);

Quoted 9 lines
include/linux/pm_domain.h +5 -0
+	GPD_OFF_POST,		/* GPD state after power off */
+	GPD_ON_PRE,		/* GPD state before power on */
+	GPD_ON_POST,		/* GPD state after power on */
+};
+
 struct dev_power_governor {
 	bool (*power_down_ok)(struct dev_pm_domain *domain);
 	bool (*stop_ok)(struct device *dev);
@@ -148,6 +155,12 @@ extern int pm_genpd_name_poweron(const char *domain_name);

--
Regards,
Sylwester

#19 lore raw

PATCH 3/12 PM / Domains: Add notifier support for power domain transitions

Hi,

On Tuesday, November 04, 2014 12:11 AM, Sylwester Nawrocki wrote,

Quoted 3 lines

To: [email protected]
Cc: Amit Daniel Kachhap; [email protected]; linux- [email protected]; [email protected]; [email protected];

Rafael

Quoted 1 line

J. Wysocki; Beata Michalska; [email protected]; Kevin Hilman; Ulf

Hansson

Quoted 1 line

Subject: Re: [PATCH 03/12] PM / Domains: Add notifier support for power

domain

Quoted 34 lines

transitions

Now really filling in the CC list, apologies for duplicate post.

Quoted 28 lines · Sylwester Nawrocki

Hi,

Cc Ulf, Kevin, Geert.
Quoted 4 lines · Amit Daniel Kachhap

These power domain transition notifiers will assist in carrying out some activity associated with domain power on/off such as some registers which may lose its contents and need save/restore across domain power off/on.

Other specific use cases I could add here is gating selected clocks to ensure proper signal propagation for devices attached to a power domain, e.g. ungating selected clocks before the power domain on and restoring them to previous state after the power domain was switched on.

Quoted 12 lines

4 type of notifications are added,

GPD_OFF_PRE     - GPD state before power off
GPD_OFF_POST    - GPD state after power off
GPD_ON_PRE      - GPD state before power off
GPD_ON_POST     - GPD state after power off

3 notfication API's are exported.
1) int genpd_register_notifier(struct notifier_block *nb, char *pd_name);
2) int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name);
3) void genpd_invoke_transition_notifier(struct generic_pm_domain

*genpd,

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
			enum gpd_on_off_state state);

In this approach the notifiers are registered/unregistered with pd

name.

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

The actual invoking of the notfiers will be done by the platform implementing power domain enable/disable low level handlers according to the above defined notification types. This approach will considerably reduce the number of call to notifiers as compared to calling always from core powerdomain subsystem.

Also the registered domain's will be managed inside a cache list and not part of the genpd structure. This will help in registration of notifiers from subsystems (such as clock) even when the PD subsystem is

still not

Quoted 2 lines

initialised.

Quoted 1 line
Quoted 1 line

This list also filters out the unregistered pd's requesting

notification.

Quoted 8 lines
Quoted 8 lines

This patch is somewhat similar my patch adding power domain state change notifications [1]. I have already a reworked version of that patch, with the notifier list moved to struct generic_pm_domain and using genpd->lock instead of dev->power.lock. Anyway, while I'd leave the decision about the location from where the notifier chains are supposed to be called to the subsystem's maintainers preference, I'm rather reluctant to having one global notifiers list for all possible

power domains

Quoted 16 lines

and all the notification clients.

Quoted 11 lines

The possibly long list needs to be traversed at each notifier call and it seems in your implementation any registered user of the notification gets notifications for all possible power domains.

[1] https://lkml.org/lkml/2014/8/5/182

Quoted 5 lines
---
 drivers/base/power/domain.c |  112

++++++++++++++++++++++++++++++++++++++++++-

Quoted 3 lines
Quoted 3 lines
 include/linux/pm_domain.h   |   31 ++++++++++++
 2 files changed, 142 insertions(+), 1 deletion(-)
Quoted 6 lines
Quoted 6 lines

drivers/base/power/domain.c line 46

Quoted 6 lines
(quoted diff) +0 -0

b/drivers/base/power/domain.c index 40bc2f4..e05045e 100644

drivers/base/power/domain.c +0 -0
@@ -46,10 +46,19 @@
 	__retval;

\

Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
drivers/base/power/domain.c +11 -1
 })
 
+struct cache_notify_domains {
+	char *name;
+	/* Node in the cache pm domain name list */
+	struct list_head cache_list_node;
+};
+
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
+static LIST_HEAD(domain_notify_list); static
+DEFINE_MUTEX(domain_notify_list_lock);
+static BLOCKING_NOTIFIER_HEAD(genpd_transition_notifier_list);
 
-static struct generic_pm_domain *pm_genpd_lookup_name(const char
 *domain_name)
+struct generic_pm_domain *pm_genpd_lookup_name(const char
+*domain_name)
 {
 	struct generic_pm_domain *genpd = NULL, *gpd;
Quoted 9 lines
Quoted 1 line

drivers/base/power/domain.c static struct generic_pm_domain

Quoted 1 line
drivers/base/power/domain.c +0 -0
@@ -66,6 +75,7 @@ static struct generic_pm_domain

*pm_genpd_lookup_name(const char *domain_name)

Quoted 7 lines
Quoted 7 lines
drivers/base/power/domain.c +1 -1
 	mutex_unlock(&gpd_list_lock);
 	return genpd;
 }
+EXPORT_SYMBOL_GPL(pm_genpd_lookup_name);
 
 struct generic_pm_domain *dev_to_genpd(struct device *dev)  { @@
-1908,6 +1918,106 @@ void pm_genpd_init(struct generic_pm_domain

*genpd,

Quoted 5 lines
Quoted 5 lines

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd,

Quoted 5 lines
drivers/base/power/domain.c +2 -0
 	mutex_unlock(&gpd_list_lock);
 }
 
+/**
+ * genpd_register_notifier - Register a PM domain for future

notification.

Quoted 20 lines
Quoted 20 lines
Quoted 20 lines

+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */

drivers/base/power/domain.c +17 -0
+int genpd_register_notifier(struct notifier_block *nb, char
+*pd_name) {
+	int ret;
+	struct cache_notify_domains *entry;
+
+	if (!pd_name)
+		return -EINVAL;
+
+	/* Search if the pd is already registered */
+	mutex_lock(&domain_notify_list_lock);
+	list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+		if (!strcmp(entry->name, pd_name))
+			break;
+	}
+	mutex_unlock(&domain_notify_list_lock);
+
+	if (entry) {
Quoted 8 lines
Quoted 8 lines

drivers/base/power/domain.c

Quoted 2 lines
drivers/base/power/domain.c +2 -0
+		pr_err("%s: pd already exists\n", __func__);
+		return -EINVAL;

I suspect this code doesn't work as expected. 'entry' will be NULL only in case of an empty domain_notify_list list. Have you tested multiple calls to genpd_register_notifier() ? It looks like only the first call would work.

You are correct it should fail for multiple calls. Somehow we missed this in internal review. Thanks for pointing out.

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
drivers/base/power/domain.c +10 -0
+	}
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	entry->name = pd_name;
+
+	mutex_lock(&domain_notify_list_lock);
+	list_add(&entry->cache_list_node, &domain_notify_list);
Quoted 8 lines
Quoted 8 lines

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd,

Quoted 8 lines
drivers/base/power/domain.c +8 -0
+	mutex_unlock(&domain_notify_list_lock);
+	ret = blocking_notifier_chain_register(
+				&genpd_transition_notifier_list, nb);
+	return ret;
+}
+
+/**
+ * genpd_unregister_notifier - Un-register a PM domain for future

notification.

Quoted 24 lines
Quoted 24 lines
Quoted 9 lines

+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */

drivers/base/power/domain.c +6 -0
+int genpd_unregister_notifier(struct notifier_block *nb, char
+*pd_name) {
+	int ret;
+	struct cache_notify_domains *entry;
+
+	mutex_lock(&domain_notify_list_lock);

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 1981

Quoted 10 lines
drivers/base/power/domain.c +10 -0
+	list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+		if (!strcmp(entry->name, pd_name))
+			break;
+	}
+	if (!entry) {
+		mutex_unlock(&domain_notify_list_lock);
+		pr_err("%s: Invalid pd name\n", __func__);
+		return -EINVAL;
+	}
+	list_del(&entry->cache_list_node);

'entry' will not be NULL even when the requested notification entry was not found above. In such case it looks like last entry in the domain_notify_list list will be removed, not something we would expect.

Quoted 8 lines
Quoted 8 lines

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd,

Quoted 8 lines
drivers/base/power/domain.c +8 -0
+	mutex_unlock(&domain_notify_list_lock);
+	ret = blocking_notifier_chain_unregister(
+				&genpd_transition_notifier_list, nb);
+	return ret;
+}
+
+/**
+ * genpd_invoke_transition_notifier - Calls the matching notification

handler.

Quoted 30 lines
Quoted 2 lines
Quoted 2 lines

+ * @genpd: generic power domain structure.
+ * @state: can be of type -

GPD_OFF_PRE/GPD_OFF_POST/GPD_ON_PRE/GPD_ON_POST.

Quoted 27 lines
Quoted 14 lines

+ */

drivers/base/power/domain.c +13 -0
+void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+			enum gpd_on_off_state state)
+{
+	struct cache_notify_domains *entry;
+
+	if (!genpd) {
+		pr_err("Invalid genpd parameter\n");
+		return;
+	}
+
+	if (state != GPD_OFF_PRE || state != GPD_OFF_POST
+			|| state != GPD_ON_PRE || state != GPD_ON_POST) {
+		pr_err("Invalid state parameter\n");

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 2015

Quoted 10 lines
drivers/base/power/domain.c +10 -0
+		return;
+	}
+
+	mutex_lock(&domain_notify_list_lock);
+	list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+		if (!strcmp(entry->name, genpd->name))
+			break;
+	}
+	mutex_unlock(&domain_notify_list_lock);
+	if (!entry) /* Simply ignore */

Similar issue here, this condition will only be true when the notifications list is empty.

I also think so.

Quoted 42 lines
Quoted 42 lines

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 2019

Quoted 5 lines
drivers/base/power/domain.c +4 -0
+		return;
+
+	blocking_notifier_call_chain(&genpd_transition_notifier_list, state,
+				genpd);

And finally regardless of to what power domain the notification user has registered it will get notification for each possible power domain in the system? Are the notification users supposed to test the 'genpd' argument to react on a specific power domain? If so, how? I guess not by nother strcmp() ?

Quoted 9 lines
drivers/base/power/domain.c +1 -0
+}
 #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
 /*
  * Device Tree based PM domain providers.
include/linux/pm_domain.h +0 -0
index 73e938b..659997f 100644

include/linux/pm_domain.h enum gpd_status { · line 29

Quoted 5 lines
include/linux/pm_domain.h +2 -0
@@ -25,6 +25,13 @@ enum gpd_status {
 	GPD_STATE_POWER_OFF,	/* PM domain is off */
 };
 
+enum gpd_on_off_state {
+	GPD_OFF_PRE = 0,	/* GPD state before power off */

The assignment is not needed.

Quoted 9 lines
include/linux/pm_domain.h +5 -0
+	GPD_OFF_POST,		/* GPD state after power off */
+	GPD_ON_PRE,		/* GPD state before power on */
+	GPD_ON_POST,		/* GPD state after power on */
+};
+
 struct dev_power_governor {
 	bool (*power_down_ok)(struct dev_pm_domain *domain);
 	bool (*stop_ok)(struct device *dev); @@ -148,6 +155,12 @@ extern

int pm_genpd_name_poweron(const char *domain_name);

--
Regards,
Sylwester

#20 lore raw

PATCH 3/12 PM / Domains: Add notifier support for power domain transitions

In reply to Sylwester Nawrocki
Quoted 10 lines · Sylwester Nawrocki

Hi,

Cc Ulf, Kevin, Geert.
Quoted 4 lines · Amit Daniel Kachhap

These power domain transition notifiers will assist in carrying out some activity associated with domain power on/off such as some registers which may lose its contents and need save/restore across domain power off/on.

Quoted 5 lines

Other specific use cases I could add here is gating selected clocks to ensure proper signal propagation for devices attached to a power domain, e.g. ungating selected clocks before the power domain on and restoring them to previous state after the power domain was switched on.

yes correct.

Quoted 20 lines
Quoted 20 lines

4 type of notifications are added,

GPD_OFF_PRE     - GPD state before power off
GPD_OFF_POST    - GPD state after power off
GPD_ON_PRE      - GPD state before power off
GPD_ON_POST     - GPD state after power off

3 notfication API's are exported.
1) int genpd_register_notifier(struct notifier_block *nb, char *pd_name);
2) int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name);
3) void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,

                      enum gpd_on_off_state state);

In this approach the notifiers are registered/unregistered with pd name. The actual invoking of the notfiers will be done by the platform implementing power domain enable/disable low level handlers according to the above defined notification types. This approach will considerably reduce the number of call to notifiers as compared to calling always from core powerdomain subsystem.

Quoted 8 lines
Quoted 4 lines

Also the registered domain's will be managed inside a cache list and not part of the genpd structure. This will help in registration of notifiers from subsystems (such as clock) even when the PD subsystem is still not initialised. This list also filters out the unregistered pd's requesting notification.

This patch is somewhat similar my patch adding power domain state change notifications [1]. I have already a reworked version of that patch, with the notifier list moved to struct generic_pm_domain and using genpd->lock instead

Yes this will be correct as others also suggested to make per genpd notifier block.

Quoted 9 lines

of dev->power.lock. Anyway, while I'd leave the decision about the location from where the notifier chains are supposed to be called to the subsystem's maintainers preference, I'm rather reluctant to having one global notifiers list for all possible power domains and all the notification clients. The possibly long list needs to be traversed at each notifier call and it seems in your implementation any registered user of the notification gets notifications for all possible power domains.

[1] https://lkml.org/lkml/2014/8/5/182

My fault, I somehow missed this link earlier. After going through this, I found it registers genpd from the platform driver, so the function signature is
int pm_genpd_register_notifier(struct device *dev, struct notifier_block *nb); I suggest to make the function signature to be like,
int pm_genpd_register_notifier(struct device_node *np, struct notifier_block *nb)

In this way this function should should be able to support both platform devices and non platform devices like clk.

The function may work like,

pdev = of_find_device_by_node(np);

if (pdev) {
         //  get genpd from device and go ahead with notfier registration.
         // blocking_notifier_chain_register(genpd->pd_notifier, nb)
} else
{
        // get pd_handle from np
        // get the pd_name from phandle and try registering this gen pd
        // if the genpd subsystem is not initialised then add this in

a temporary list and register the notifier later
}

Can you post your implementation with 1st part ? Later I can post the else part with my changes.

Quoted 67 lines
Quoted 67 lines
---
 drivers/base/power/domain.c |  112 ++++++++++++++++++++++++++++++++++++++++++-
 include/linux/pm_domain.h   |   31 ++++++++++++
 2 files changed, 142 insertions(+), 1 deletion(-)
drivers/base/power/domain.c +32 -1
index 40bc2f4..e05045e 100644
@@ -46,10 +46,19 @@
      __retval;                                                               \
 })
 
+struct cache_notify_domains {
+     char *name;
+     /* Node in the cache pm domain name list */
+     struct list_head cache_list_node;
+};
+
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
+static LIST_HEAD(domain_notify_list);
+static DEFINE_MUTEX(domain_notify_list_lock);
+static BLOCKING_NOTIFIER_HEAD(genpd_transition_notifier_list);
 
-static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
+struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
 {
      struct generic_pm_domain *genpd = NULL, *gpd;
 
@@ -66,6 +75,7 @@ static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
      mutex_unlock(&gpd_list_lock);
      return genpd;
 }
+EXPORT_SYMBOL_GPL(pm_genpd_lookup_name);
 
 struct generic_pm_domain *dev_to_genpd(struct device *dev)
 {
@@ -1908,6 +1918,106 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
      mutex_unlock(&gpd_list_lock);
 }
 
+/**
+ * genpd_register_notifier - Register a PM domain for future notification.
+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */
+int genpd_register_notifier(struct notifier_block *nb, char *pd_name)
+{
+     int ret;
+     struct cache_notify_domains *entry;
+
+     if (!pd_name)
+             return -EINVAL;
+
+     /* Search if the pd is already registered */
+     mutex_lock(&domain_notify_list_lock);
+     list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+             if (!strcmp(entry->name, pd_name))
+                     break;
+     }
+     mutex_unlock(&domain_notify_list_lock);
+
Quoted 8 lines

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 1944

Quoted 3 lines
drivers/base/power/domain.c +3 -0
+     if (entry) {
+             pr_err("%s: pd already exists\n", __func__);
+             return -EINVAL;

I suspect this code doesn't work as expected. 'entry' will be NULL only in case of an empty domain_notify_list list. Have you tested multiple calls to genpd_register_notifier() ? It looks like only the first call would work.

Yes this list check is not correct. Will update this. Thanks.

Quoted 104 lines
Quoted 28 lines
drivers/base/power/domain.c +27 -0
+     }
+
+     entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+     if (!entry)
+             return -ENOMEM;
+
+     entry->name = pd_name;
+
+     mutex_lock(&domain_notify_list_lock);
+     list_add(&entry->cache_list_node, &domain_notify_list);
+     mutex_unlock(&domain_notify_list_lock);
+     ret = blocking_notifier_chain_register(
+                             &genpd_transition_notifier_list, nb);
+     return ret;
+}
+
+/**
+ * genpd_unregister_notifier - Un-register a PM domain for future notification.
+ * @nb: notification block containing notification handle.
+ * @pd_name: PM domain name.
+ */
+int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name)
+{
+     int ret;
+     struct cache_notify_domains *entry;
+
+     mutex_lock(&domain_notify_list_lock);

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 1981

Quoted 10 lines
drivers/base/power/domain.c +10 -0
+     list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+             if (!strcmp(entry->name, pd_name))
+                     break;
+     }
+     if (!entry) {
+             mutex_unlock(&domain_notify_list_lock);
+             pr_err("%s: Invalid pd name\n", __func__);
+             return -EINVAL;
+     }
+     list_del(&entry->cache_list_node);

'entry' will not be NULL even when the requested notification entry was not found above. In such case it looks like last entry in the domain_notify_list list will be removed, not something we would expect.

Quoted 24 lines
drivers/base/power/domain.c +24 -0
+     mutex_unlock(&domain_notify_list_lock);
+     ret = blocking_notifier_chain_unregister(
+                             &genpd_transition_notifier_list, nb);
+     return ret;
+}
+
+/**
+ * genpd_invoke_transition_notifier - Calls the matching notification handler.
+ * @genpd: generic power domain structure.
+ * @state: can be of type - GPD_OFF_PRE/GPD_OFF_POST/GPD_ON_PRE/GPD_ON_POST.
+ */
+void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
+                     enum gpd_on_off_state state)
+{
+     struct cache_notify_domains *entry;
+
+     if (!genpd) {
+             pr_err("Invalid genpd parameter\n");
+             return;
+     }
+
+     if (state != GPD_OFF_PRE || state != GPD_OFF_POST
+                     || state != GPD_ON_PRE || state != GPD_ON_POST) {
+             pr_err("Invalid state parameter\n");

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 2015

Quoted 10 lines
drivers/base/power/domain.c +10 -0
+             return;
+     }
+
+     mutex_lock(&domain_notify_list_lock);
+     list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
+             if (!strcmp(entry->name, genpd->name))
+                     break;
+     }
+     mutex_unlock(&domain_notify_list_lock);
+     if (!entry) /* Simply ignore */

Similar issue here, this condition will only be true when the notifications list is empty.

drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 2019

Quoted 4 lines
drivers/base/power/domain.c +4 -0
+             return;
+
+     blocking_notifier_call_chain(&genpd_transition_notifier_list, state,
+                             genpd);

And finally regardless of to what power domain the notification user has registered it will get notification for each possible power domain in the system? Are the notification users supposed to test the 'genpd' argument to react on a specific power domain? If so, how? I guess not by nother strcmp() ?

Quoted 12 lines
drivers/base/power/domain.c +1 -0
+}
 #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
 /*
  * Device Tree based PM domain providers.
include/linux/pm_domain.h +0 -0
index 73e938b..659997f 100644
@@ -25,6 +25,13 @@ enum gpd_status {
      GPD_STATE_POWER_OFF,    /* PM domain is off */
 };
 
Quoted 4 lines

include/linux/pm_domain.h enum gpd_status { · line 29

Quoted 2 lines
include/linux/pm_domain.h +2 -0
+enum gpd_on_off_state {
+     GPD_OFF_PRE = 0,        /* GPD state before power off */

The assignment is not needed.

yes correct.

Regards,
Amit

Quoted 19 lines

include/linux/pm_domain.h extern int pm_genpd_name_poweron(const char *domain_name);

Quoted 10 lines
include/linux/pm_domain.h +5 -0
+     GPD_OFF_POST,           /* GPD state after power off */
+     GPD_ON_PRE,             /* GPD state before power on */
+     GPD_ON_POST,            /* GPD state after power on */
+};
+
 struct dev_power_governor {
      bool (*power_down_ok)(struct dev_pm_domain *domain);
      bool (*stop_ok)(struct device *dev);
@@ -148,6 +155,12 @@ extern int pm_genpd_name_poweron(const char *domain_name);

--
Regards,
Sylwester

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

#21 lore raw

PATCH 3/12 PM / Domains: Add notifier support for power domain transitions

Quoted 3 lines · amit daniel kachhap
Quoted 1 line · Sylwester Nawrocki

On 03/11/14 04:53, Amit Daniel Kachhap wrote:

[...]

Quoted 63 lines
Quoted 19 lines
Quoted 19 lines

4 type of notifications are added,

GPD_OFF_PRE     - GPD state before power off
GPD_OFF_POST    - GPD state after power off
GPD_ON_PRE      - GPD state before power off
GPD_ON_POST     - GPD state after power off

3 notfication API's are exported.
1) int genpd_register_notifier(struct notifier_block *nb, char *pd_name);
2) int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name);
3) void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,

                      enum gpd_on_off_state state);

In this approach the notifiers are registered/unregistered with pd name. The actual invoking of the notfiers will be done by the platform implementing power domain enable/disable low level handlers according to the above defined notification types. This approach will considerably reduce the number of call to notifiers as compared to calling always from core powerdomain subsystem.

Quoted 8 lines
Quoted 4 lines

Also the registered domain's will be managed inside a cache list and not part of the genpd structure. This will help in registration of notifiers from subsystems (such as clock) even when the PD subsystem is still not initialised. This list also filters out the unregistered pd's requesting notification.

This patch is somewhat similar my patch adding power domain state change notifications [1]. I have already a reworked version of that patch, with the notifier list moved to struct generic_pm_domain and using genpd->lock instead

Yes this will be correct as others also suggested to make per genpd notifier block.

Quoted 9 lines

of dev->power.lock. Anyway, while I'd leave the decision about the location from where the notifier chains are supposed to be called to the subsystem's maintainers preference, I'm rather reluctant to having one global notifiers list for all possible power domains and all the notification clients. The possibly long list needs to be traversed at each notifier call and it seems in your implementation any registered user of the notification gets notifications for all possible power domains.

[1] https://lkml.org/lkml/2014/8/5/182

My fault, I somehow missed this link earlier. After going through this, I found it registers genpd from the platform driver, so the function signature is
int pm_genpd_register_notifier(struct device *dev, struct notifier_block *nb); I suggest to make the function signature to be like,
int pm_genpd_register_notifier(struct device_node *np, struct notifier_block *nb)

In this way this function should should be able to support both platform devices and non platform devices like clk.

The function may work like,

pdev = of_find_device_by_node(np);

if (pdev) {
         //  get genpd from device and go ahead with notfier registration.
         // blocking_notifier_chain_register(genpd->pd_notifier, nb)
} else
{
        // get pd_handle from np
        // get the pd_name from phandle and try registering this gen pd
        // if the genpd subsystem is not initialised then add this in
Quoted 5 lines

a temporary list and register the notifier later
}

Can you post your implementation with 1st part ? Later I can post the else part with my changes.

Hmm, I doubt making the first argument of the notifier registration function 'struct device_node *' is a good idea. AFAIK we shouldn't be introducing and requiring device tree in generic interfaces.

We already tried an approach with pending notifier registration list. I.e. when the power domain is not yet available we put the notification registration request onto a separate list, which is then traversed right before the power domain is registered with PM core. Then we had a separate notification type for the notification client, to let it know if his registration request has finally failed permanently (invoked at some late initcall).

It all works, but it's not something we're really happy with. I hope we can work out some reasonable solution for mainline. I will post my PD transition notification patch, however it's mostly to demonstrate the problem. In v2 PD can be also referred to by name, beside allowing to just pass a struct device * to a device which belongs to a power domain.

--
Thanks,
Sylwester

#22 lore raw

RFC PATCH 1/1 pm: Add PM domain state transition notifications

This patch adds support for the power domain state transition notifiers. The notifiers are mostly intended to be used in SoC-specific subsystem, e.g. clock controller, power management unit, etc. drivers.

It is an attempt to address dependencies between power domains in an SoC and other subsystems like clocks controller, where the power domain on/off sequences are relatively complex and involve subsystems which are split in the kernel across various frameworks/subsystems.

---
The deferred notifier registration is not included in this patch.

---
 Documentation/power/notifiers.txt |   14 ++++
 drivers/base/power/domain.c       |  136 +++++++++++++++++++++++++++++++++++--
 include/linux/pm_domain.h         |   46 +++++++++++++
 3 files changed, 192 insertions(+), 4 deletions(-)
Documentation/power/notifiers.txt +14 -0
index a81fa25..e70957d 100644
@@ -53,3 +53,17 @@ NULL).  To register and/or unregister a suspend notifier use the functions
 register_pm_notifier() and unregister_pm_notifier(), respectively, defined in
 include/linux/suspend.h .  If you don't need to unregister the notifier, you can
 also use the pm_notifier() macro defined in include/linux/suspend.h .
+
+Power Domain notifiers
+----------------------
+
+The power domain notifiers allow subsystems or drivers to register for power
+domain on/off notifications, should they need to perform any actions right
+before or right after the power domain on/off.  The device must be already
+added to a power domain before its subsystem or driver registers the notifier.
+Following events are supported:
+
+GPD_NOTIFY_POWER_ON_PREPARE	The power domain is about to turn on.
+GPD_NOTIFY_POST_POWER_ON	The power domain has just turned on.
+GPD_NOTIFY_POWER_OFF_PREPARE	The power domain is about to turn off.
+GPD_NOTIFY_POST_POWER_OFF	The power domain has just turned off.
drivers/base/power/domain.c +132 -4

192 lines not on this page · raw message

include/linux/pm_domain.h +46 -0

76 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#23 lore raw

PATCH 4/12 mfd: exynos-pmu: Register exynos-pmu driver as a mfd driver

In reply to Amit Daniel Kachhap

This can be used later to probe and configure PMU client drivers like pm_domain etc.
A global structure pmu_dev_client_data is created to pass exynos-pmu platform data to all the clients. Currently the data passed is register base addresses.
Although the exynos-pmu driver also provides the sysreg interfaces to provide register base addresses but this is costlier than readl/writel, so both the interfaces are provided to mfd based exynos-pmu client drivers.

---
 drivers/mfd/exynos-pmu.c               |   25 +++++++++++++++++++++++++
 include/linux/mfd/samsung/exynos-pmu.h |    5 +++++
 2 files changed, 30 insertions(+)
drivers/mfd/exynos-pmu.c +25 -0
index 07019f0..c46f3f5 100644
@@ -11,12 +11,19 @@
 
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/core.h>
 #include <linux/mfd/samsung/exynos-regs-pmu.h>
 #include <linux/mfd/samsung/exynos-pmu.h>
 
 #define PMU_TABLE_END	(-1U)
 
+enum pmu_mfd_list {
+	MFD_POWER_DOMAIN,
+	MFD_MAX,
+};
+
 struct exynos_pmu_conf {
 	unsigned int offset;
 	unsigned int val[NUM_SYS_POWERDOWN];
@@ -33,6 +40,8 @@ struct exynos_pmu_data {
 struct exynos_pmu_context {
 	struct device *dev;
 	const struct exynos_pmu_data *pmu_data;
+	struct mfd_cell cells[MFD_MAX];
+	struct pmu_dev_client_data mfd_data;
 };
 
 static void __iomem *pmu_base_addr;
@@ -482,6 +491,8 @@ static int exynos_pmu_probe(struct platform_device *pdev)
 	const struct of_device_id *match;
 	struct device *dev = &pdev->dev;
 	struct resource *res;
+	struct mfd_cell *cell;
+	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	pmu_base_addr = devm_ioremap_resource(dev, res);
@@ -506,6 +517,20 @@ static int exynos_pmu_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, pmu_context);
 
+	/* Initialize and invoke mfd clients */
+	cell = &pmu_context->cells[MFD_POWER_DOMAIN];
+	cell->name = "exynos-pmu-domain";
+	pmu_context->mfd_data.mem_base_addr = pmu_base_addr;
+	pmu_context->mfd_data.mem_size = resource_size(res);
+	cell->platform_data = &pmu_context->mfd_data;
+	cell->pdata_size = sizeof(pmu_context->mfd_data);
+	ret = mfd_add_devices(&pdev->dev, pdev->id, pmu_context->cells, MFD_MAX,
+				NULL, 0, NULL);
+	if (ret) {
+		dev_err(&pdev->dev, "fail to register client devices\n");
+		return ret;
+	}
+
 	dev_dbg(dev, "Exynos PMU Driver probe done\n");
 	return 0;
 }
include/linux/mfd/samsung/exynos-pmu.h +5 -0
index a2ab0d5..d2f4083 100644
@@ -19,6 +19,11 @@ enum sys_powerdown {
 	NUM_SYS_POWERDOWN,
 };
 
+struct pmu_dev_client_data {
+	void __iomem *mem_base_addr;
+	unsigned int mem_size;
+};
+
 extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
 
 #endif /* __EXYNOS_PMU_H */
Signature · 1 line
1.7.9.5
#24 lore raw

PATCH 5/12 arm: exynos: Add platform driver support for power domain driver

In reply to Amit Daniel Kachhap

This patch modifies Exynos Power Domain driver initialization implementation in following way:

- Added platform driver support and probe function where Exynos PM Domain driver will register itself as MFD PMU client driver.
- This driver will now use the PMU base address with certain offset for power domain register address so reg property is not required. This change will avoid unnecessary ioremap of the power register.
- PMU base address is directly accessed and syscon interface is not used as PM Domain driver is quite critical and syscon based lock protected register access(regmap) is not used.

---
 .../bindings/arm/exynos/power_domain.txt           |    8 +--
 arch/arm/mach-exynos/pm_domains.c                  |   59 ++++++++++++++------
 2 files changed, 47 insertions(+), 20 deletions(-)
Documentation/devicetree/bindings/arm/exynos/power_domain.txt +4 -4
index abde1ea..5599017 100644
@@ -6,8 +6,8 @@ to gate power to one or more peripherals on the processor.
 Required Properties:
 - compatible: should be one of the following.
     * samsung,exynos4210-pd - for exynos4210 type power domain.
-- reg: physical base address of the controller and length of memory mapped
-    region.
+- pd-offset: this gives the offset of PM power domain register from
+	     the PMU base address.
 - #power-domain-cells: number of cells in power domain specifier;
     must be 0.
 
@@ -30,13 +30,13 @@ Example:
 
 	lcd0: power-domain-lcd0 {
 		compatible = "samsung,exynos4210-pd";
-		reg = <0x10023C00 0x10>;
+		pd-offset = <0x3C00>;
 		#power-domain-cells = <0>;
 	};
 
 	mfc_pd: power-domain at 10044060 {
 		compatible = "samsung,exynos4210-pd";
-		reg = <0x10044060 0x20>;
+		pd-offset = <0x4060>;
 		clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_SW_ACLK333>,
 			<&clock CLK_MOUT_USER_ACLK333>;
 		clock-names = "oscclk", "pclk0", "clk0";
arch/arm/mach-exynos/pm_domains.c +43 -16

97 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#25 lore raw

PATCH 6/12 soc: exynos: Move exynos power domain file to driver/soc/samsung folder

In reply to Amit Daniel Kachhap

This patch moves arch/arm/mach-exynos/pm_domains.c to driver/soc/samsung folder. This will be useful to use it for both arm and arm64 platforms. This file is moved in this directory as this driver is soc specific and only used by exynos platforms.

---
 arch/arm/mach-exynos/Makefile                      |    1 -
 drivers/soc/Kconfig                                |    1 +
 drivers/soc/Makefile                               |    1 +
 drivers/soc/samsung/Kconfig                        |   11 +++++++++++
 drivers/soc/samsung/Makefile                       |    1 +
 .../soc/samsung}/pm_domains.c                      |    0
 6 files changed, 14 insertions(+), 1 deletion(-)
 create mode 100644 drivers/soc/samsung/Kconfig
 create mode 100644 drivers/soc/samsung/Makefile
 rename {arch/arm/mach-exynos => drivers/soc/samsung}/pm_domains.c (100%)
arch/arm/mach-exynos/Makefile +0 -1
index b91b382..9ea6c54 100644
@@ -13,7 +13,6 @@ obj-$(CONFIG_ARCH_EXYNOS)	+= exynos.o exynos-smc.o firmware.o
 
 obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm.o sleep.o
 obj-$(CONFIG_PM_SLEEP)		+= suspend.o
-obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o
 
 obj-$(CONFIG_SMP)		+= platsmp.o headsmp.o
 
drivers/soc/Kconfig +1 -0
index 76d6bd4..90f33b9 100644
@@ -3,5 +3,6 @@ menu "SOC (System On Chip) specific Drivers"
 source "drivers/soc/qcom/Kconfig"
 source "drivers/soc/ti/Kconfig"
 source "drivers/soc/versatile/Kconfig"
+source "drivers/soc/samsung/Kconfig"
 
 endmenu
drivers/soc/Makefile +1 -0
index 063113d..44d220d 100644
@@ -6,3 +6,4 @@ obj-$(CONFIG_ARCH_QCOM)		+= qcom/
 obj-$(CONFIG_ARCH_TEGRA)	+= tegra/
 obj-$(CONFIG_SOC_TI)		+= ti/
 obj-$(CONFIG_PLAT_VERSATILE)	+= versatile/
+obj-$(CONFIG_ARCH_EXYNOS)	+= samsung/
drivers/soc/samsung/Kconfig new file +11 -0
new file mode 100644
index 0000000..1dc6a35
@@ -0,0 +1,11 @@
+#
+# Samsung Soc drivers
+#
+config EXYNOS_POWER_DOMAIN
+	tristate "Support Exynos PM Power Domain"
+	depends on ARCH_EXYNOS && PM_GENERIC_DOMAINS
+	default y
+	help
+	  Exynos SOC have power domain gating support. This driver implements that
+	  functionality and registers all the necessary hooks to the generic power domain
+	  core kernel infrastructure.
drivers/soc/samsung/Makefile new file +1 -0
new file mode 100644
index 0000000..f4efce7
@@ -0,0 +1 @@
+obj-$(CONFIG_EXYNOS_POWER_DOMAIN)	+=	pm_domains.o
drivers/soc/samsung/pm_domains.c renamed from arch/arm/mach-exynos/pm_domains.c +0 -0
similarity index 100%
rename from arch/arm/mach-exynos/pm_domains.c
rename to drivers/soc/samsung/pm_domains.c
Signature · 1 line
1.7.9.5
#26 lore raw

PATCH 7/12 soc: samsung: pm_domain: Use compatible name for power domain name

In reply to Amit Daniel Kachhap

This patch adds support for second optional compatible complate name. If this compatible name is present then this name will be used to create the Power Domain and not the DT node name.
The benefit of this approach is to hook the notifier to the correct Power Domain.

---
 .../bindings/arm/exynos/power_domain.txt           |    8 ++++++++
 drivers/soc/samsung/pm_domains.c                   |    7 ++++++-
 2 files changed, 14 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/arm/exynos/power_domain.txt +8 -0
index 5599017..7250a5c 100644
@@ -12,6 +12,8 @@ Required Properties:
     must be 0.
 
 Optional Properties:
+- compatible: This is a second compatible name and gives the complete Power Domain
+	name like "samsung,exynos7-pd-mfc"
 - clocks: List of clock handles. The parent clocks of the input clocks to the
 	devices in this power domain are set to oscclk before power gating
 	and restored back after powering on a domain. This is required for
@@ -43,5 +45,11 @@ Example:
 		#power-domain-cells = <0>;
 	};
 
+	mfc_pd: power-domain at 10044060 {
+		compatible = "samsung,exynos4210-pd", "samsung,exynos7-pd-mfc";
+		pd-offset = <0x4060>;
+		#power-domain-cells = <0>;
+	};
+
 See Documentation/devicetree/bindings/power/power_domain.txt for description
 of consumer-side bindings.
drivers/soc/samsung/pm_domains.c +6 -1
index 923eb57..e63d129 100644
@@ -124,12 +124,17 @@ static int exynos_power_domain_probe(struct platform_device *pdev)
 	for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") {
 		struct exynos_pm_domain *pd;
 		int on, i;
+		const char *name;
 
 		pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL);
 		if (!pd)
 			return -ENOMEM;
 
-		pd->pd.name = kstrdup(np->name, GFP_KERNEL);
+		if (of_property_read_string_index(np, "compatible", 1, &name)) {
+			/* Second entry not found, use the node name*/
+			name = np->name;
+		}
+		pd->pd.name = kstrdup(name, GFP_KERNEL);
 		pd->name = pd->pd.name;
 		if (of_property_read_u32(np, "pd-offset", &offset)) {
 			pr_err("%s: failed to find offset for power domain\n",
Signature · 1 line
1.7.9.5
#27 lore raw

PATCH 8/12 soc: samsung: pm_domain: Add a new parameter for power configuration

In reply to Amit Daniel Kachhap

This patch adds a new optional parameter "pd-power-conf" to fetch the correct power configuration value. In exynos7 soc, this field is different from previous exynos soc's.

---
 .../bindings/arm/exynos/power_domain.txt           |    3 +++
 drivers/soc/samsung/pm_domains.c                   |   13 +++++++++----
 2 files changed, 12 insertions(+), 4 deletions(-)
Documentation/devicetree/bindings/arm/exynos/power_domain.txt +3 -0
index 7250a5c..07e4ffe 100644
@@ -24,6 +24,8 @@ Optional Properties:
 	- pclkN, clkN: Pairs of parent of input clock and input clock to the
 		devices in this power domain. Maximum of 4 pairs (N = 0 to 3)
 		are supported currently.
+- pd-power-conf: This optional parameter provides the local power configuration
+	value for the power domain.
 
 Node of a device using power domains must have a samsung,power-domain property
 defined with a phandle to respective power domain.
@@ -48,6 +50,7 @@ Example:
 	mfc_pd: power-domain at 10044060 {
 		compatible = "samsung,exynos4210-pd", "samsung,exynos7-pd-mfc";
 		pd-offset = <0x4060>;
+		pd-power-conf = <0xf>;
 		#power-domain-cells = <0>;
 	};
 
drivers/soc/samsung/pm_domains.c +9 -4
index e63d129..84a3f1f 100644
@@ -34,6 +34,7 @@ struct exynos_pm_domain {
 	void __iomem *base;
 	char const *name;
 	bool is_off;
+	unsigned int pwr_conf_val;
 	struct generic_pm_domain pd;
 	struct clk *oscclk;
 	struct clk *clk[MAX_CLK_PER_DOMAIN];
@@ -63,13 +64,13 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
 		}
 	}
 
-	pwr = power_on ? INT_LOCAL_PWR_EN : 0;
+	pwr = power_on ? pd->pwr_conf_val : 0;
 	__raw_writel(pwr, base);
 
 	/* Wait max 1ms */
 	timeout = 10;
 
-	while ((__raw_readl(base + 0x4) & INT_LOCAL_PWR_EN) != pwr) {
+	while ((__raw_readl(base + 0x4) & pd->pwr_conf_val) != pwr) {
 		if (!timeout) {
 			op = (power_on) ? "enable" : "disable";
 			pr_err("Power domain %s %s failed\n", domain->name, op);
@@ -111,7 +112,7 @@ static int exynos_power_domain_probe(struct platform_device *pdev)
 	struct device_node *np;
 	struct pmu_dev_client_data *pdata = NULL;
 	void __iomem *pmu_base_addr;
-	unsigned int offset;
+	unsigned int offset, pwr_conf;
 
 	pdata = pdev->dev.platform_data;
 	if (!pdata) {
@@ -141,9 +142,13 @@ static int exynos_power_domain_probe(struct platform_device *pdev)
 					__func__);
 			return -EINVAL;
 		}
+		if (of_property_read_u32(np, "pd-power-conf", &pwr_conf))
+			pwr_conf = INT_LOCAL_PWR_EN;
+
 		pd->base = pmu_base_addr + offset;
 		pd->pd.power_off = exynos_pd_power_off;
 		pd->pd.power_on = exynos_pd_power_on;
+		pd->pwr_conf_val = pwr_conf;
 
 		pd->oscclk = of_clk_get_by_name(np, "oscclk");
 		if (IS_ERR(pd->oscclk))
@@ -169,7 +174,7 @@ static int exynos_power_domain_probe(struct platform_device *pdev)
 			clk_put(pd->oscclk);
 
 no_clk:
-		on = __raw_readl(pd->base + 0x4) & INT_LOCAL_PWR_EN;
+		on = __raw_readl(pd->base + 0x4) & pwr_conf;
 
 		pm_genpd_init(&pd->pd, NULL, !on);
 		of_genpd_add_provider_simple(np, &pd->pd);
Signature · 1 line
1.7.9.5
#28 lore raw

PATCH 9/12 soc: samsung: pm_domain: Add support for parent power domain

In reply to Amit Daniel Kachhap

This patch adds supports for parent power domain. This will ensure invoking of parent/child power domain on/off in a correct sequence. In exynos7 SOC's, power domain controllers have parent and child hierarchy.

---
 .../bindings/arm/exynos/power_domain.txt           |    2 +
 drivers/soc/samsung/pm_domains.c                   |   42 +++++++++++++++++++-
 2 files changed, 43 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/arm/exynos/power_domain.txt +2 -0
index 07e4ffe..07752a4 100644
@@ -26,6 +26,7 @@ Optional Properties:
 		are supported currently.
 - pd-power-conf: This optional parameter provides the local power configuration
 	value for the power domain.
+- parent: phandle of parent power domain.
 
 Node of a device using power domains must have a samsung,power-domain property
 defined with a phandle to respective power domain.
@@ -51,6 +52,7 @@ Example:
 		compatible = "samsung,exynos4210-pd", "samsung,exynos7-pd-mfc";
 		pd-offset = <0x4060>;
 		pd-power-conf = <0xf>;
+		parent = <&pd_top>;
 		#power-domain-cells = <0>;
 	};
 
drivers/soc/samsung/pm_domains.c +41 -1

55 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#29 lore raw

PATCH 10/12 soc: samsung: pm_domain: Use the recently added PM Domain notifiers

In reply to Amit Daniel Kachhap

Invoke the GPD_OFF_PRE/GPD_ON_POST power Domain notifiers. This will allow some clocks to be saved and restored. These notifiers can also be invoked from the core power domain files but is not done as exynos is the only user of these notifiers as of now.
In exynos7 SOC's only GPD_OFF_PRE/GPD_ON_POST are required.

---
 drivers/soc/samsung/pm_domains.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/soc/samsung/pm_domains.c +6 -1
index f14f182..11633c2 100644
@@ -99,11 +99,16 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
 
 static int exynos_pd_power_on(struct generic_pm_domain *domain)
 {
-	return exynos_pd_power(domain, true);
+	int ret;
+
+	ret = exynos_pd_power(domain, true);
+	genpd_invoke_transition_notifier(domain, GPD_ON_POST);
+	return ret;
 }
 
 static int exynos_pd_power_off(struct generic_pm_domain *domain)
 {
+	genpd_invoke_transition_notifier(domain, GPD_OFF_PRE);
 	return exynos_pd_power(domain, false);
 }
 
Signature · 1 line
1.7.9.5
#30 lore raw

PATCH 11/12 clk: samsung: save and restore clock registers for power domain

In reply to Amit Daniel Kachhap

This patch adds support for save and restore for clock registers which loses register contents across power domain off/on sequence.

---
 drivers/clk/samsung/clk.c |   66 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/samsung/clk.h |   14 ++++++++++
 2 files changed, 80 insertions(+)
drivers/clk/samsung/clk.c +66 -0
index dd1f7c9..9fd1369 100644
@@ -11,10 +11,12 @@
  * clock framework for Samsung platforms.
 */
 
+#include <linux/pm_domain.h>
 #include <linux/syscore_ops.h>
 #include "clk.h"
 
 static LIST_HEAD(clock_reg_cache_list);
+static LIST_HEAD(clock_pd_reg_cache_list);
 
 void samsung_clk_save(void __iomem *base,
 				    struct samsung_clk_reg_dump *rd,
@@ -370,6 +372,67 @@ static void samsung_clk_sleep_init(void __iomem *reg_base,
 		unsigned long nr_rdump) {}
 #endif
 
+static int samsung_power_domain_notifier(struct notifier_block *nb,
+				    unsigned long event, void *data)
+{
+	struct generic_pm_domain *genpd = data;
+	struct samsung_clock_pd_reg_cache *reg_cache;
+
+	switch (event) {
+	case GPD_OFF_PRE:
+		/* save all the pd domain clock registers */
+		list_for_each_entry(reg_cache, &clock_pd_reg_cache_list, node)
+			if (!strcmp(reg_cache->pd_name, genpd->name))
+				samsung_clk_save(reg_cache->reg_base,
+						reg_cache->rdump,
+						reg_cache->rd_num);
+		break;
+	case GPD_ON_POST:
+		/* restore all the pd domain clock registers */
+		list_for_each_entry(reg_cache, &clock_pd_reg_cache_list, node)
+			if (!strcmp(reg_cache->pd_name, genpd->name))
+				samsung_clk_restore(reg_cache->reg_base,
+						reg_cache->rdump,
+						reg_cache->rd_num);
+		break;
+	case GPD_OFF_POST:
+	case GPD_ON_PRE:
+		break;
+	default:
+		pr_err("%s: Invalid pm domain event\n", __func__);
+	}
+	return 0;
+}
+
+/* Notifier for power domain on/off changes */
+static struct notifier_block power_domain_notifier_block = {
+	.notifier_call = samsung_power_domain_notifier,
+};
+
+static void samsung_clk_pd_init(void __iomem *reg_base,
+		const unsigned long *rdump, unsigned long nr_rdump,
+		char *pd_name)
+{
+	struct samsung_clock_pd_reg_cache *pd_reg_cache;
+
+	pd_reg_cache = kzalloc(sizeof(struct samsung_clock_pd_reg_cache),
+			GFP_KERNEL);
+	if (!pd_reg_cache)
+		panic("could not allocate register reg_cache.\n");
+
+	pd_reg_cache->rdump = samsung_clk_alloc_reg_dump(rdump, nr_rdump);
+
+	if (!pd_reg_cache->rdump)
+		panic("could not allocate register dump storage.\n");
+
+	pd_reg_cache->reg_base = reg_base;
+	pd_reg_cache->rd_num = nr_rdump;
+	pd_reg_cache->pd_name = pd_name;
+	list_add_tail(&pd_reg_cache->node, &clock_pd_reg_cache_list);
+
+	genpd_register_notifier(&power_domain_notifier_block, pd_name);
+}
+
 /*
  * Common function which registers plls, muxes, dividers and gates
  * for each CMU. It also add CMU register list to register cache.
@@ -408,6 +471,9 @@ void __init samsung_cmu_register_one(struct device_node *np,
 	if (cmu->clk_regs)
 		samsung_clk_sleep_init(reg_base, cmu->clk_regs,
 			cmu->nr_clk_regs);
+	if (cmu->pd_clk_regs)
+		samsung_clk_pd_init(reg_base, cmu->pd_clk_regs,
+			cmu->nr_clk_regs, cmu->pd_name);
 
 	samsung_clk_of_add_provider(np, ctx);
 }
drivers/clk/samsung/clk.h +14 -0
index 3f471e9..f67f5e5 100644
@@ -331,6 +331,14 @@ struct samsung_clock_reg_cache {
 	unsigned int rd_num;
 };
 
+struct samsung_clock_pd_reg_cache {
+	struct list_head node;
+	void __iomem *reg_base;
+	struct samsung_clk_reg_dump *rdump;
+	unsigned int rd_num;
+	char *pd_name;
+};
+
 struct samsung_cmu_info {
 	/* list of pll clocks and respective count */
 	struct samsung_pll_clock *pll_clks;
@@ -356,6 +364,12 @@ struct samsung_cmu_info {
 	/* list and number of clocks registers */
 	unsigned long *clk_regs;
 	unsigned int nr_clk_regs;
+
+	/* list and number of clocks to be saved/restored during
+	 * power domain shutdown */
+	char *pd_name;
+	unsigned long *pd_clk_regs;
+	unsigned int nr_pd_clk_regs;
 };
 
 extern struct samsung_clk_provider *__init samsung_clk_init(
Signature · 1 line
1.7.9.5
#31 lore raw

PATCH 12/12 arm64: Kconfig: Enable PM_GENERIC_DOMAINS for exynos7

In reply to Amit Daniel Kachhap

Use power domain driver for Exynos7 SOC's

---
 arch/arm64/Kconfig |    1 +
 1 file changed, 1 insertion(+)
arch/arm64/Kconfig +1 -0
index 693db3e..f537558 100644
@@ -152,6 +152,7 @@ config ARCH_EXYNOS7
 	bool "ARMv8 based Samsung Exynos7"
 	select ARCH_EXYNOS
 	select COMMON_CLK_SAMSUNG
+	select PM_GENERIC_DOMAINS
 	help
 	  This enables support for Samsung Exynos7 SoC family
 
Signature · 1 line
1.7.9.5