Add generic PM domain support for Tegra
Subsystems (10)
v6 cover Add generic PM domain support for Tegra
Adds generic PM domain support for Tegra SoCs but this series only enables support for it on Tegra 64-bit devices. There is no reason why this cannot be enable for Tegra 32-bit devices, but to keep the patch series to a minimum only 64-bit devices are enabled so far.
This series has been boot tested on Tegra210 as well as various 32-bit Tegra platforms.
Summary of changes since V5 [2]:
- Split series into 2 series, separating PMC fixes [3] from genpd changes
- This series is based upon fixes series (which is now in -next)
- Added patch to fix removal of genpd subdomain
- Added patch to get last genpd that was added
- Fixed locking in function to remove genpd
- Updated Tegra PMC driver to ensure power-domains cannot be controlled by both legacy Tegra APIs and generic PM domain framework
- Removed powergate list from Tegra PMC driver and updated removal of power domains to use new genpd APIs.
Summary of changes since V4 [1]:
- Re-worked fix to handle base address on probe failure
- Added patch to lock around simultaneuous accesses to PMC registers
- Added patch to change powergate and rail IDs to unsigned type
- Added patch to fix testing of powergate state
- Updated patch to check for valid powergates to use a bitmap
- Updated Tegra DT PMC bindings per Rob H's feedback
- Updated Tegra power domains binding per Thierry's feedback
- Updated Tegra generic power domain support per Thierry's feedback
Summary of changes since V3 [0]:
- Dropped tegra124 support for now
- Removed MC flush support per feedback from Thierry
- Cleaned up the PMC changes per feedback from Thierry
- Added support for tegra210
[0] http://comments.gmane.org/gmane.linux.ports.tegra/22944
[1] http://marc.info/?l=linux-tegra&m=144924153600529&w=2
[2] http://marc.info/?l=linux-tegra&m=145399885003830&w=2
[3] http://marc.info/?l=linux-tegra&m=145521381331144&w=2
Jon Hunter (10):
PM / Domains: Fix removal of a subdomain
PM / Domains: Add function to get the last domain added PM / Domains: Add function to remove a pm-domain
Documentation: DT: bindings: Update NVIDIA PMC for Tegra
Documentation: DT: bindings: Add power domain info for NVIDIA PMC
soc: tegra: pmc: Wait for powergate state to change
soc: tegra: pmc: Add generic PM domain support
soc: tegra: pmc: Move powergate definitions to dt-bindings
ARM64: tegra: select PM_GENERIC_DOMAINS
ARM64: tegra: Add audio PM domain device node for Tegra210
.../bindings/arm/tegra/nvidia,tegra20-pmc.txt | 73 ++- arch/arm/mach-tegra/platsmp.c | 16 +- arch/arm64/Kconfig.platforms | 2 + arch/arm64/boot/dts/nvidia/tegra210.dtsi | 14 +- drivers/base/power/domain.c | 58 +- drivers/soc/tegra/pmc.c | 594 ++++++++++++++++++--- include/dt-bindings/power/tegra-powergate.h | 88 +++ include/linux/pm_domain.h | 12 + include/soc/tegra/pmc.h | 38 +- 9 files changed, 776 insertions(+), 119 deletions(-) create mode 100644 include/dt-bindings/power/tegra-powergate.h
Signature · 1 line
2.1.4
A message that is not in the archive (sent off-list or not yet received): 1456501724-28477-1-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org
PATCH v6 1/10 PM / Domains: Fix removal of a subdomain
Commit 30e7a65b3fdb ("PM / Domains: Ensure subdomain is not in use before removing") added a test to ensure that a subdomain is not is not a master to another subdomain or if any devices are using the subdomain before removing. This change incorrectly used the "slave_links" list to determine if the subdomain is a master to another subdomain, where it should have been using the "master_links" list instead. The "slave_links" list will never be empty for a subdomain and so a subdomain can never be removed. Fix this by testing if the "master_links" list is empty instead.
before removing")
--- drivers/base/power/domain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/base/power/domain.c +1 -1
@@ -1382,7 +1382,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,mutex_lock (&subdomain->lock);mutex_lock_nested (&genpd->lock,SINGLE_DEPTH_NESTING ); -if (!list_empty (&subdomain->slave_links) || subdomain->device_count) { +if (!list_empty (&subdomain->master_links) || subdomain->device_count) {pr_warn ("%s: unable to remove subdomain %s\n" , genpd->name, subdomain->name); ret = -EBUSY ;
Signature · 1 line
2.1.4
A message that is not in the archive (sent off-list or not yet received): 1456501724-28477-2-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org
Thierry Reding
Reviewed-byRe: [PATCH V6 01/10] PM / Domains: Fix removal of a subdomain
Quoted 2 lines · Jon Hunter
Commit
30e7a65b3fdb("PM / Domains: Ensure subdomain is not in use before removing") added a test to ensure that a subdomain is not is not
Double "is not".
Quoted 8 lines
a master to another subdomain or if any devices are using the subdomain before removing. This change incorrectly used the "
slave_links" list to determine if the subdomain is a master to another subdomain, where it should have been using the "master_links" list instead. The "slave_links" list will never be empty for a subdomain and so a subdomain can never be removed. Fix this by testing if the "master_links" list is empty instead.
Quoted 4 lines
Fixes 30e7a65b3fdb ("PM / Domains: Ensure subdomain is not in usebefore removing")
Signed-off-by Jon Hunter <[email protected]>
I think the Fixes: line is allowed to be longer than 72 characters (the important bits are in the first few characters anyway) and it doesn't need to be separated from other tags by a blank line. That said, I doubt that any of the automation tools will be confused.
Other than that, the change looks correct:
Quoted 20 lines
--- drivers/base/power/domain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/base/power/domain.c +1
-1@@ -1382,7 +1382,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,mutex_lock (&subdomain->lock);mutex_lock_nested (&genpd->lock,SINGLE_DEPTH_NESTING ); -if (!list_empty (&subdomain->slave_links) || subdomain->device_count) { +if (!list_empty (&subdomain->master_links) || subdomain->device_count) {pr_warn ("%s: unable to remove subdomain %s\n" , genpd->name, subdomain->name); ret = -EBUSY ;Signature · 1 line
2.1.4
Ulf Hansson
Acked-byRe: [PATCH V6 01/10] PM / Domains: Fix removal of a subdomain
In reply to a message not in the archiveQuoted 10 lines · Jon Hunter
Commit
30e7a65b3fdb("PM / Domains: Ensure subdomain is not in use before removing") added a test to ensure that a subdomain is not is not a master to another subdomain or if any devices are using the subdomain before removing. This change incorrectly used the "slave_links" list to determine if the subdomain is a master to another subdomain, where it should have been using the "master_links" list instead. The "slave_links" list will never be empty for a subdomain and so a subdomain can never be removed. Fix this by testing if the "master_links" list is empty instead.
Quoted 4 lines
Fixes 30e7a65b3fdb ("PM / Domains: Ensure subdomain is not in usebefore removing")
Signed-off-by Jon Hunter <[email protected]>
When you addressed the comments from Thierry, this also looks good to me.
Kind regards
Uffe
Quoted 20 lines
--- drivers/base/power/domain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/base/power/domain.c +1
-2@@ -1382,7 +1382,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,mutex_lock (&subdomain->lock);mutex_lock_nested (&genpd->lock,SINGLE_DEPTH_NESTING ); -if (!list_empty (&subdomain->slave_links) || subdomain->device_count) { +if (!list_empty (&subdomain->master_links) || subdomain->device_count) {pr_warn ("%s: unable to remove subdomain %s\n" , genpd->name, subdomain->name); ret = -EBUSY ; --2.1.4
PATCH v6 3/10 PM / Domains: Add function to remove a pm-domain
In reply to a message not in the archiveThe genpd framework allows users to add power-domains via the pm_genpd_init() function, however, there is no corresponding function to remove a power-domain. For most devices this may be fine as the power domains are never removed, however, for devices that wish to populate the power-domains from within a driver, having the ability to remove a power domain if the probing of the device fails or the driver is unloaded is necessary. Therefore, add a function to remove a power-domain. Please note that the power domain can only be removed if there are no devices using the power-domain and it is not linked to another domain.
--- drivers/base/power/domain.c | 31 +++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 5 +++++ 2 files changed, 36 insertions(+)
drivers/base/power/domain.c +31 -0
@@ -1557,6 +1557,37 @@ void pm_genpd_init(struct generic_pm_domain *genpd, }EXPORT_SYMBOL_GPL (pm_genpd_init); +/** +* pm_genpd_remove - Remove a generic I/O PM domain object. +* @genpd: PM domain object to remove. +*/ +int pm_genpd_remove (struct generic_pm_domain *genpd) +{ +int ret =0 ; + +if (IS_ERR_OR_NULL (genpd)) +return -EINVAL ; + +mutex_lock (&gpd_list_lock); +mutex_lock (&genpd->lock); + +if (!list_empty (&genpd->master_links) + || !list_empty (&genpd->slave_links) || genpd->device_count) { + ret = -EBUSY ; + goto out; + } + +cancel_work_sync (&genpd->power_off_work); +list_del (&genpd->gpd_list_node); + +out: +mutex_unlock (&genpd->lock); +mutex_unlock (&gpd_list_lock); + +return ret; +} +EXPORT_SYMBOL_GPL (pm_genpd_remove); +#ifdef CONFIG_PM_GENERIC_DOMAINS_OF /* * Device Tree based PM domain providers.
include/linux/pm_domain.h +5 -0
@@ -134,6 +134,7 @@ extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, struct generic_pm_domain *target);extern void pm_genpd_init (struct generic_pm_domain *genpd,struct dev_power_governor *gov,bool is_off); +extern int pm_genpd_remove (struct generic_pm_domain *genpd);extern struct dev_power_governor simple_qos_governor;extern struct dev_power_governor pm_domain_always_on_gov;
@@ -177,6 +178,10 @@ static inline void pm_genpd_init(struct generic_pm_domain *genpd, struct dev_power_governor *gov, bool is_off) { } +static inline int pm_genpd_remove (struct generic_pm_domain *genpd) +{ +return -ENOTSUPP ; +}#endif static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
Signature · 1 line
2.1.4
Re: [PATCH V6 03/10] PM / Domains: Add function to remove a pm-domain
Quoted 9 lines · Jon Hunter
The genpd framework allows users to add power-domains via the
pm_genpd_init()function, however, there is no corresponding function to remove a power-domain. For most devices this may be fine as the power domains are never removed, however, for devices that wish to populate the power-domains from within a driver, having the ability to remove a power domain if the probing of the device fails or the driver is unloaded is necessary. Therefore, add a function to remove a power-domain. Please note that the power domain can only be removed if there are no devices using the power-domain and it is not linked to another domain.
So I guess this introduces a problem not uncommon to other types of resources. If you remove the driver, even if you fail ->remove() the module may still go away along with any code associated with it. So even if the PM domains can't be removed, you can't prevent the module from going away. That could be somewhat mitigated if we were holding a module reference count, because then the only way to unload the driver would be via sysfs (we could prevent that too, which might be the best way to do this today).
There is work underway to solve this generically, Rafael was working on this, so I'm not sure we need to add additional infrastructure to the PM domain code as part of this series. But we may want to mark the Tegra PMC driver as .suppress_bind_attrs = true, to make sure it can't be removed.
Quoted 11 lines
Signed-off-by Jon Hunter <[email protected]>--- drivers/base/power/domain.c | 31 +++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 5 +++++ 2 files changed, 36 insertions(+)drivers/base/power/domain.c +0
-0
drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 1563
Quoted 7 lines
drivers/base/power/domain.c +4
-0@@ -1557,6 +1557,37 @@ void pm_genpd_init(struct generic_pm_domain *genpd, }EXPORT_SYMBOL_GPL (pm_genpd_init); +/** +* pm_genpd_remove - Remove a generic I/O PM domain object. +* @genpd: PM domain object to remove. +*/
Would it be worth noting here that the object is only removed from the list of domains, but that users are still responsible for freeing any resources (such as memory) associated with it? It seems like this might be obvious enough given the usage model of pm_genpd_init(), but it's something that I noticed missing from the function.
Otherwise this looks fine:
Re: [PATCH V6 03/10] PM / Domains: Add function to remove a pm-domain
Quoted 22 lines · Thierry Reding
* PGP Signed by an unknown key
Quoted 9 lines · Jon Hunter
The genpd framework allows users to add power-domains via the
pm_genpd_init()function, however, there is no corresponding function to remove a power-domain. For most devices this may be fine as the power domains are never removed, however, for devices that wish to populate the power-domains from within a driver, having the ability to remove a power domain if the probing of the device fails or the driver is unloaded is necessary. Therefore, add a function to remove a power-domain. Please note that the power domain can only be removed if there are no devices using the power-domain and it is not linked to another domain.So I guess this introduces a problem not uncommon to other types of resources. If you remove the driver, even if you fail ->remove() the module may still go away along with any code associated with it. So even if the PM domains can't be removed, you can't prevent the module from going away. That could be somewhat mitigated if we were holding a module reference count, because then the only way to unload the driver would be via sysfs (we could prevent that too, which might be the best way to do this today).
Quoted 5 lines
There is work underway to solve this generically, Rafael was working on this, so I'm not sure we need to add additional infrastructure to the PM domain code as part of this series. But we may want to mark the Tegra PMC driver as .suppress_bind_attrs = true, to make sure it can't be removed.
I see what you are saying. It nearly seemed to me that I should use BUG_ON() if we fail to remove a genpd in the PMC driver, however, I know that using BUG_ON should be avoided. I will add the suppress_bind_attrs = true for the PMC driver as that does make sense for now.
Jon
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH V6 03/10] PM / Domains: Add function to remove a pm-domain
Quoted 30 lines · Jon Hunter
Quoted 22 lines · Thierry Reding
* PGP Signed by an unknown key
Quoted 9 lines · Jon Hunter
The genpd framework allows users to add power-domains via the
pm_genpd_init()function, however, there is no corresponding function to remove a power-domain. For most devices this may be fine as the power domains are never removed, however, for devices that wish to populate the power-domains from within a driver, having the ability to remove a power domain if the probing of the device fails or the driver is unloaded is necessary. Therefore, add a function to remove a power-domain. Please note that the power domain can only be removed if there are no devices using the power-domain and it is not linked to another domain.So I guess this introduces a problem not uncommon to other types of resources. If you remove the driver, even if you fail ->remove() the module may still go away along with any code associated with it. So even if the PM domains can't be removed, you can't prevent the module from going away. That could be somewhat mitigated if we were holding a module reference count, because then the only way to unload the driver would be via sysfs (we could prevent that too, which might be the best way to do this today).
Quoted 5 lines
There is work underway to solve this generically, Rafael was working on this, so I'm not sure we need to add additional infrastructure to the PM domain code as part of this series. But we may want to mark the Tegra PMC driver as .suppress_bind_attrs = true, to make sure it can't be removed.
Quoted 4 lines
I see what you are saying. It nearly seemed to me that I should use
BUG_ON()if we fail to remove a genpd in the PMC driver, however, I know that usingBUG_ONshould be avoided. I will add thesuppress_bind_attrs= true for the PMC driver as that does make sense for now.
Just to let you know, the PMC driver already has suppress_bind_attrs = true.
Cheers
Jon
Re: [PATCH V6 03/10] PM / Domains: Add function to remove a pm-domain
In reply to Jon HunterQuoted 9 lines · Jon Hunter
The genpd framework allows users to add power-domains via the
pm_genpd_init()function, however, there is no corresponding function to remove a power-domain. For most devices this may be fine as the power domains are never removed, however, for devices that wish to populate the power-domains from within a driver, having the ability to remove a power domain if the probing of the device fails or the driver is unloaded is necessary. Therefore, add a function to remove a power-domain. Please note that the power domain can only be removed if there are no devices using the power-domain and it is not linked to another domain.
In general I think you can work a bit on the changelog, for example split it into a few sections to make it more readable.
I would like it to state clearly what constraint we have to be able to remove a PM domain. More precisely, the device structure is needed, no of genpd provider etc. Maybe also "linked to another domain" can be rephrased to tell about both masters and subdomains.
Finally, perhaps change terminology for the "power-domain" to "PM domain" as I think that's more widely used.
Quoted 26 lines
Signed-off-by Jon Hunter <[email protected]>--- drivers/base/power/domain.c | 31 +++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 5 +++++ 2 files changed, 36 insertions(+)drivers/base/power/domain.c +11
-0@@ -1557,6 +1557,37 @@ void pm_genpd_init(struct generic_pm_domain *genpd, }EXPORT_SYMBOL_GPL (pm_genpd_init); +/** +* pm_genpd_remove - Remove a generic I/O PM domain object. +* @genpd: PM domain object to remove. +*/ +int pm_genpd_remove (struct generic_pm_domain *genpd) +{ +int ret =0 ; + +if (IS_ERR_OR_NULL (genpd)) +return -EINVAL ; +
drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 1580
Quoted 10 lines
drivers/base/power/domain.c +10
-0+mutex_lock (&gpd_list_lock); +mutex_lock (&genpd->lock); + +if (!list_empty (&genpd->master_links) + || !list_empty (&genpd->slave_links) || genpd->device_count) { + ret = -EBUSY ; + goto out; + } + +cancel_work_sync (&genpd->power_off_work);
This can deadlock as the work function tries to lock the genpd mutex.
I suggest to move this outside of the locking section just before returning, but of course still only in case of a non-error.
drivers/base/power/domain.c void pm_genpd_init(struct generic_pm_domain *genpd, · line 1586
Quoted 6 lines
drivers/base/power/domain.c +6
-0+list_del (&genpd->gpd_list_node); + +out: +mutex_unlock (&genpd->lock); +mutex_unlock (&gpd_list_lock); +
Besides the minor comment above.
1) Have you considered how to protects against a registered of_genpd_provider for the genpd?
2) Theoretically some could call pm_genpd_add_subdomain() after this point. I guess we can consider that as an abuse of the API, although do you think we need to protect that from really happening?
Quoted 31 lines
drivers/base/power/domain.c +4
-0+return ret; +} +EXPORT_SYMBOL_GPL (pm_genpd_remove); +#ifdef CONFIG_PM_GENERIC_DOMAINS_OF /* * Device Tree based PM domain providers. include/linux/pm_domain.h +5
-1@@ -134,6 +134,7 @@ extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, struct generic_pm_domain *target);extern void pm_genpd_init (struct generic_pm_domain *genpd,struct dev_power_governor *gov,bool is_off); +extern int pm_genpd_remove (struct generic_pm_domain *genpd);extern struct dev_power_governor simple_qos_governor;extern struct dev_power_governor pm_domain_always_on_gov;@@ -177,6 +178,10 @@ static inline void pm_genpd_init(struct generic_pm_domain *genpd, struct dev_power_governor *gov, bool is_off) { } +static inline int pm_genpd_remove (struct generic_pm_domain *genpd) +{ +return -ENOTSUPP ; +}#endif static inline int pm_genpd_add_device(struct generic_pm_domain *genpd, --
Quoted 2 lines
2.1.4
Kind regards
Uffe
PATCH v6 4/10 Documentation: DT: bindings: Update NVIDIA PMC for Tegra
In reply to a message not in the archiveAdd the PMC driver compatible strings for Tegra132 and Tegra210.
--- .../devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt +7 -5
@@ -6,11 +6,13 @@ modes. It provides power-gating controllers for SoC and CPU power-islands. Required properties: - name : Should be pmc -- compatible : For Tegra20, must contain "nvidia,tegra20-pmc". For Tegra30, - must contain "nvidia,tegra30-pmc". For Tegra114, must contain - "nvidia,tegra114-pmc". For Tegra124, must contain "nvidia,tegra124-pmc". - Otherwise, must contain "nvidia,<chip>-pmc", plus at least one of the - above, where <chip> is tegra132. +- compatible : Should contain one of the following: + For Tegra20 must contain "nvidia,tegra20-pmc". + For Tegra30 must contain "nvidia,tegra30-pmc". + For Tegra114 must contain "nvidia,tegra114-pmc" + For Tegra124 must contain "nvidia,tegra124-pmc" + For Tegra132 must contain "nvidia,tegra124-pmc" + For Tegra210 must contain "nvidia,tegra210-pmc" - reg : Offset and length of the register set for the device - clocks : Must contain an entry for each entry in clock-names. See ../clocks/clock-bindings.txt for details.
Signature · 1 line
2.1.4
Thierry Reding
AppliedRe: [PATCH V6 04/10] Documentation: DT: bindings: Update NVIDIA PMC for Tegra
Quoted 7 lines · Jon Hunter
Add the PMC driver compatible strings for Tegra132 and Tegra210.
Signed-off-by Jon Hunter <[email protected]>Acked-by Rob Herring <[email protected]>--- .../devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
Applied, thanks.
Thierry
PATCH v6 6/10 soc: tegra: pmc: Wait for powergate state to change
In reply to a message not in the archiveCurrently, the function tegra_powergate_set() simply sets the desired powergate state but does not wait for the state to change. In most cases we should wait for the state to change before proceeding. Currently, there is a case for tegra114 and tegra124 devices where we do not wait when starting the secondary CPU as this is not necessary. However, this is only done at boot time and so waiting here will only have a small impact on boot time. Therefore, update tegra_powergate_set() to wait when setting the powergate.
By adding this feature, we can also eliminate the polling loop from tegra30_boot_secondary().
A function has been added for checking the status of the powergate and so update the tegra_powergate_is_powered() to use this macro as well.
--- arch/arm/mach-tegra/platsmp.c | 16 +++------------- drivers/soc/tegra/pmc.c | 9 ++++++++- 2 files changed, 11 insertions(+), 14 deletions(-)
arch/arm/mach-tegra/platsmp.c +3 -13
@@ -108,19 +108,9 @@ static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle)* be un-gated by un-toggling the power gate register * manually. */ -if (!tegra_pmc_cpu_is_powered (cpu)) { - ret =tegra_pmc_cpu_power_on (cpu); -if (ret) -return ret; - -/* Wait for the power to come up. */ - timeout = jiffies +msecs_to_jiffies (100 ); -while (!tegra_pmc_cpu_is_powered (cpu)) { -if (time_after (jiffies, timeout)) -return -ETIMEDOUT ; -udelay (10 ); - } - } + ret =tegra_pmc_cpu_power_on (cpu); +if (ret) +return ret; remove_clamps:/* CPU partition is powered. Enable the CPU clock. */
drivers/soc/tegra/pmc.c +8 -1
@@ -28,6 +28,7 @@#include <linux/export.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/platform_device.h>
@@ -194,6 +195,9 @@ static inline bool tegra_powergate_is_valid(int id)*/ static int tegra_powergate_set (unsigned int id,bool new_state) { +bool status; +int err; +if (id ==TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps)return -EINVAL ;
@@ -206,9 +210,12 @@ static int tegra_powergate_set(unsigned int id, bool new_state)tegra_pmc_writel (PWRGATE_TOGGLE_START | id,PWRGATE_TOGGLE ); + err =readx_poll_timeout (tegra_powergate_state, id, status, + status == new_state,10 ,100000 ); +mutex_unlock (&pmc->powergates_lock); -return 0 ; +return err; }/**
Signature · 1 line
2.1.4
A message that is not in the archive (sent off-list or not yet received): 1456501724-28477-7-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org
Re: [PATCH V6 06/10] soc: tegra: pmc: Wait for powergate state to change
Quoted 12 lines · Jon Hunter
Currently, the function
tegra_powergate_set()simply sets the desired powergate state but does not wait for the state to change. In most cases we should wait for the state to change before proceeding. Currently, there is a case for tegra114 and tegra124 devices where we do not wait when starting the secondary CPU as this is not necessary. However, this is only done at boot time and so waiting here will only have a small impact on boot time. Therefore, updatetegra_powergate_set()to wait when setting the powergate.By adding this feature, we can also eliminate the polling loop from
tegra30_boot_secondary().
Quoted 8 lines
A function has been added for checking the status of the powergate and so update the
tegra_powergate_is_powered()to use this macro as well.Signed-off-by Jon Hunter <[email protected]>--- arch/arm/mach-tegra/platsmp.c | 16 +++------------- drivers/soc/tegra/pmc.c | 9 ++++++++- 2 files changed, 11 insertions(+), 14 deletions(-)
This looks to be independent from the generic power domain support. Can I apply this separately (for 4.6, without waiting for the power domain series' dependencies to go in)?
Thierry
Re: [PATCH V6 06/10] soc: tegra: pmc: Wait for powergate state to change
Quoted 24 lines · Thierry Reding
* PGP Signed by an unknown key
Quoted 12 lines · Jon Hunter
Currently, the function
tegra_powergate_set()simply sets the desired powergate state but does not wait for the state to change. In most cases we should wait for the state to change before proceeding. Currently, there is a case for tegra114 and tegra124 devices where we do not wait when starting the secondary CPU as this is not necessary. However, this is only done at boot time and so waiting here will only have a small impact on boot time. Therefore, updatetegra_powergate_set()to wait when setting the powergate.By adding this feature, we can also eliminate the polling loop from
tegra30_boot_secondary().Quoted 8 lines
A function has been added for checking the status of the powergate and so update the
tegra_powergate_is_powered()to use this macro as well.Signed-off-by Jon Hunter <[email protected]>--- arch/arm/mach-tegra/platsmp.c | 16 +++------------- drivers/soc/tegra/pmc.c | 9 ++++++++- 2 files changed, 11 insertions(+), 14 deletions(-)
Quoted 3 lines
This looks to be independent from the generic power domain support. Can I apply this separately (for 4.6, without waiting for the power domain series' dependencies to go in)?
Yes this could be applied independently of this series for v4.6. I just wanted to make sure that this change is added before the genpd changes are applied.
Cheers
Jon
Thierry Reding
AppliedRe: [PATCH V6 06/10] soc: tegra: pmc: Wait for powergate state to change
In reply to a message not in the archiveQuoted 12 lines · Jon Hunter
Currently, the function
tegra_powergate_set()simply sets the desired powergate state but does not wait for the state to change. In most cases we should wait for the state to change before proceeding. Currently, there is a case for tegra114 and tegra124 devices where we do not wait when starting the secondary CPU as this is not necessary. However, this is only done at boot time and so waiting here will only have a small impact on boot time. Therefore, updatetegra_powergate_set()to wait when setting the powergate.By adding this feature, we can also eliminate the polling loop from
tegra30_boot_secondary().
Quoted 8 lines
A function has been added for checking the status of the powergate and so update the
tegra_powergate_is_powered()to use this macro as well.Signed-off-by Jon Hunter <[email protected]>--- arch/arm/mach-tegra/platsmp.c | 16 +++------------- drivers/soc/tegra/pmc.c | 9 ++++++++- 2 files changed, 11 insertions(+), 14 deletions(-)
Applied, thanks.
Thierry
PATCH v6 8/10 soc: tegra: pmc: Move powergate definitions to dt-bindings
In reply to a message not in the archiveMove the Tegra Powergate definitions into include/dt-bindings so that these can be used by the powergate bindings in device-tree source files.
Remove the TEGRA_POWERGATE_3D0 definition as this is an alias and is not used anywhere.
--- drivers/soc/tegra/pmc.c | 2 + include/dt-bindings/power/tegra-powergate.h | 88 +++++++++++++++++++++++++++++ include/soc/tegra/pmc.h | 39 +------------ 3 files changed, 93 insertions(+), 36 deletions(-) create mode 100644 include/dt-bindings/power/tegra-powergate.h
drivers/soc/tegra/pmc.c +2 -0
@@ -19,6 +19,8 @@#define pr_fmt (fmt) "tegra-pmc: " fmt +#include <dt-bindings/power/tegra-powergate.h> +#include <linux/kernel.h> #include <linux/clk.h> #include <linux/clk/tegra.h>
include/dt-bindings/power/tegra-powergate.h new file +88 -0
88 lines not on this page · raw message
include/soc/tegra/pmc.h +3 -36
@@ -19,6 +19,8 @@#ifndef __SOC_TEGRA_PMC_H__#define __SOC_TEGRA_PMC_H__ +#include <dt-bindings/power/tegra-powergate.h> +#include <linux/reboot.h> #include <soc/tegra/pm.h>
@@ -39,43 +41,8 @@ int tegra_pmc_cpu_remove_clamping(unsigned int cpuid);#endif /* CONFIG_SMP */ /* -* powergate and I/O rail APIs +* I/O rail APIs */ - -#define TEGRA_POWERGATE_CPU 0 -#define TEGRA_POWERGATE_3D 1 -#define TEGRA_POWERGATE_VENC 2 -#define TEGRA_POWERGATE_PCIE 3 -#define TEGRA_POWERGATE_VDEC 4 -#define TEGRA_POWERGATE_L2 5 -#define TEGRA_POWERGATE_MPE 6 -#define TEGRA_POWERGATE_HEG 7 -#define TEGRA_POWERGATE_SATA 8 -#define TEGRA_POWERGATE_CPU1 9 -#define TEGRA_POWERGATE_CPU2 10 -#define TEGRA_POWERGATE_CPU3 11 -#define TEGRA_POWERGATE_CELP 12 -#define TEGRA_POWERGATE_3D1 13 -#define TEGRA_POWERGATE_CPU0 14 -#define TEGRA_POWERGATE_C0NC 15 -#define TEGRA_POWERGATE_C1NC 16 -#define TEGRA_POWERGATE_SOR 17 -#define TEGRA_POWERGATE_DIS 18 -#define TEGRA_POWERGATE_DISB 19 -#define TEGRA_POWERGATE_XUSBA 20 -#define TEGRA_POWERGATE_XUSBB 21 -#define TEGRA_POWERGATE_XUSBC 22 -#define TEGRA_POWERGATE_VIC 23 -#define TEGRA_POWERGATE_IRAM 24 -#define TEGRA_POWERGATE_NVDEC 25 -#define TEGRA_POWERGATE_NVJPG 26 -#define TEGRA_POWERGATE_AUD 27 -#define TEGRA_POWERGATE_DFD 28 -#define TEGRA_POWERGATE_VE2 29 -#define TEGRA_POWERGATE_MAX TEGRA_POWERGATE_VE2 - -#define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D -#define TEGRA_IO_RAIL_CSIA 0#define TEGRA_IO_RAIL_CSIB 1#define TEGRA_IO_RAIL_DSI 2
Signature · 6 lines
2.1.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v6 9/10 ARM64: tegra: select PM_GENERIC_DOMAINS
In reply to a message not in the archiveEnable PM_GENERIC_DOMAINS for tegra 64-bit devices. To ensure that devices dependent upon a particular power-domain are only probed when that power domain has been powered up, requires that PM is made mandatory for tegra 64-bit devices and so select this option for tegra as well.
--- arch/arm64/Kconfig.platforms | 2 ++ 1 file changed, 2 insertions(+)
arch/arm64/Kconfig.platforms +2 -0
@@ -113,6 +113,8 @@ config ARCH_TEGRA select GENERIC_CLOCKEVENTS select HAVE_CLK select PINCTRL + select PM + select PM_GENERIC_DOMAINS select RESET_CONTROLLER help This enables support for the NVIDIA Tegra SoC family.
Signature · 1 line
2.1.4
A message that is not in the archive (sent off-list or not yet received): 1456501724-28477-10-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org
Ulf Hansson
Reviewed-byRe: [PATCH V6 09/10] ARM64: tegra: select PM_GENERIC_DOMAINS
Quoted 6 lines · Jon Hunter
Enable
PM_GENERIC_DOMAINSfor tegra 64-bit devices. To ensure that devices dependent upon a particular power-domain are only probed when that power domain has been powered up, requires that PM is made mandatory for tegra 64-bit devices and so select this option for tegra as well.Signed-off-by Jon Hunter <[email protected]>
Kind regards
Uffe
Quoted 20 lines
--- arch/arm64/Kconfig.platforms | 2 ++ 1 file changed, 2 insertions(+)arch/arm64/Kconfig.platforms +2
-1@@ -113,6 +113,8 @@ config ARCH_TEGRA select GENERIC_CLOCKEVENTS select HAVE_CLK select PINCTRL + select PM + select PM_GENERIC_DOMAINS select RESET_CONTROLLER help This enables support for the NVIDIA Tegra SoC family. --2.1.4
Jon Hunter
maintainerPATCH v6 2/10 PM / Domains: Add function to get the last domain added
In reply to Jon HunterTo remove generic PM domains in a sane way, we need to remove them by starting from the last PM domain added. The reason for this is that a PM domain may be a subdomain of another and so we need to remove the child PM domains for a given domain first. By removing PM domains in reverse order we can ensure that the children are removed first.
Add a new function to get the last PM domain that was added. In case PM domains are added by more than one device in the system (for example, on-chip domains and off-chip domains) add a 'owner' device structure to the generic PM domain structure so that the ownership of a PM domain can be identified by the device structure of the device that added it Use this 'owner' device structure to return the last PM domain added by this device.
Note that because pm_genpd_init() simply adds each PM domain to the head of the gpd_list object, list_for_each_entry() will start from the last PM domain added.
---
This is the outcome from a discussion I had with Ulf on how best to handle the removal of power-domains [0]. I opted to call the device structure 'owner' because 'parent' could be misleading if a power domain is a child of another power domain. However, open to suggestions!
[0] http://marc.info/?l=linux-pm&m=145460070816340&w=2
drivers/base/power/domain.c | 25 +++++++++++++++++++++++++ include/linux/pm_domain.h | 7 +++++++ 2 files changed, 32 insertions(+)
drivers/base/power/domain.c +25 -0
@@ -65,6 +65,31 @@ struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev) }/* +* Get the last generic PM domain added whose 'owner' device structure +* matches the device structure provided. The 'owner' device structure +* for a given PM domain should be initialised by the device that is +* creating the PM domains and hence, calling pm_genpd_init(). +*/ +struct generic_pm_domain *pm_genpd_list_get_tail (struct device *dev) +{ +struct generic_pm_domain *genpd =NULL , *gpd; + +if (IS_ERR_OR_NULL (dev)) +return NULL ; + +mutex_lock (&gpd_list_lock); +list_for_each_entry (gpd, &gpd_list, gpd_list_node) { +if (gpd->owner == dev) { + genpd = gpd; +break ; + } + } +mutex_unlock (&gpd_list_lock); + +return genpd; +} + +/* * This should only be used where we are certain that the pm_domain * attached to the device is a genpd domain. */
include/linux/pm_domain.h +7 -0
@@ -46,6 +46,7 @@ struct genpd_power_state {struct generic_pm_domain {struct dev_pm_domain domain;/* PM domain operations */ +struct device *owner;/* Identity of the domain owner */ struct list_head gpd_list_node;/* Node in the global PM domains list */ struct list_head master_links;/* Links with PM domain as a master */ struct list_head slave_links;/* Links with PM domain as a slave */
@@ -120,6 +121,7 @@ static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev) }extern struct generic_pm_domain *pm_genpd_lookup_dev (struct device *dev); +extern struct generic_pm_domain *pm_genpd_list_get_tail (struct device *dev);extern int __pm_genpd_add_device (struct generic_pm_domain *genpd,struct device *dev,struct gpd_timing_data *td);
@@ -145,6 +147,11 @@ static inline struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev) {return NULL ; } +static inline +struct generic_pm_domain *pm_genpd_list_get_tail (struct device *dev) +{ +return NULL ; +}static inline int __pm_genpd_add_device (struct generic_pm_domain *genpd,struct device *dev,struct gpd_timing_data *td)
Signature · 1 line
2.1.4
A message that is not in the archive (sent off-list or not yet received): 1456501724-28477-3-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org
Thierry Reding
Reviewed-byRe: [PATCH V6 02/10] PM / Domains: Add function to get the last domain added
Quoted 18 lines · Jon Hunter
To remove generic PM domains in a sane way, we need to remove them by starting from the last PM domain added. The reason for this is that a PM domain may be a subdomain of another and so we need to remove the child PM domains for a given domain first. By removing PM domains in reverse order we can ensure that the children are removed first.
Add a new function to get the last PM domain that was added. In case PM domains are added by more than one device in the system (for example, on-chip domains and off-chip domains) add a 'owner' device structure to the generic PM domain structure so that the ownership of a PM domain can be identified by the device structure of the device that added it Use this 'owner' device structure to return the last PM domain added by this device.
Note that because
pm_genpd_init()simply adds each PM domain to the head of thegpd_listobject,list_for_each_entry()will start from the last PM domain added.
Quoted 6 lines
Signed-off-by Jon Hunter <[email protected]>---
This is the outcome from a discussion I had with Ulf on how best to handle the removal of power-domains [0]. I opted to call the device structure 'owner' because 'parent' could be misleading if a power domain is a child of another power domain. However, open to suggestions!
I've seen "dev" used a lot in other subsystems when an entity is provided by a specific device. "provider" might be another alternative, but I don't have any strong objections against "owner" either.
Quoted 6 lines
[0] http://marc.info/?l=linux-pm&m=145460070816340&w=2
drivers/base/power/domain.c | 25 +++++++++++++++++++++++++ include/linux/pm_domain.h | 7 +++++++ 2 files changed, 32 insertions(+)
Besides the name bikeshedding, the change looks correct:
Re: [PATCH V6 02/10] PM / Domains: Add function to get the last domain added
In reply to Jon HunterQuoted 14 lines · Jon Hunter
To remove generic PM domains in a sane way, we need to remove them by starting from the last PM domain added. The reason for this is that a PM domain may be a subdomain of another and so we need to remove the child PM domains for a given domain first. By removing PM domains in reverse order we can ensure that the children are removed first.
Add a new function to get the last PM domain that was added. In case PM domains are added by more than one device in the system (for example, on-chip domains and off-chip domains) add a 'owner' device structure to the generic PM domain structure so that the ownership of a PM domain can be identified by the device structure of the device that added it Use this 'owner' device structure to return the last PM domain added by this device.
Quoted 5 lines
Note that because
pm_genpd_init()simply adds each PM domain to the head of thegpd_listobject,list_for_each_entry()will start from the last PM domain added.Signed-off-by Jon Hunter <[email protected]>
I don't have a strong opinion about what to call the device structure. Both "owner" or "dev" is okay by me.
Kind regards
Uffe
Quoted 83 lines
---
This is the outcome from a discussion I had with Ulf on how best to handle the removal of power-domains [0]. I opted to call the device structure 'owner' because 'parent' could be misleading if a power domain is a child of another power domain. However, open to suggestions![0] http://marc.info/?l=linux-pm&m=145460070816340&w=2
drivers/base/power/domain.c | 25 +++++++++++++++++++++++++ include/linux/pm_domain.h | 7 +++++++ 2 files changed, 32 insertions(+)drivers/base/power/domain.c +25
-0@@ -65,6 +65,31 @@ struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev) }/* +* Get the last generic PM domain added whose 'owner' device structure +* matches the device structure provided. The 'owner' device structure +* for a given PM domain should be initialised by the device that is +* creating the PM domains and hence, calling pm_genpd_init(). +*/ +struct generic_pm_domain *pm_genpd_list_get_tail (struct device *dev) +{ +struct generic_pm_domain *genpd =NULL , *gpd; + +if (IS_ERR_OR_NULL (dev)) +return NULL ; + +mutex_lock (&gpd_list_lock); +list_for_each_entry (gpd, &gpd_list, gpd_list_node) { +if (gpd->owner == dev) { + genpd = gpd; +break ; + } + } +mutex_unlock (&gpd_list_lock); + +return genpd; +} + +/* * This should only be used where we are certain that the pm_domain * attached to the device is a genpd domain. */ include/linux/pm_domain.h +7
-1@@ -46,6 +46,7 @@ struct genpd_power_state {struct generic_pm_domain {struct dev_pm_domain domain;/* PM domain operations */ +struct device *owner;/* Identity of the domain owner */ struct list_head gpd_list_node;/* Node in the global PM domains list */ struct list_head master_links;/* Links with PM domain as a master */ struct list_head slave_links;/* Links with PM domain as a slave */ @@ -120,6 +121,7 @@ static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev) }extern struct generic_pm_domain *pm_genpd_lookup_dev (struct device *dev); +extern struct generic_pm_domain *pm_genpd_list_get_tail (struct device *dev);extern int __pm_genpd_add_device (struct generic_pm_domain *genpd,struct device *dev,struct gpd_timing_data *td);@@ -145,6 +147,11 @@ static inline struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev) {return NULL ; } +static inline +struct generic_pm_domain *pm_genpd_list_get_tail (struct device *dev) +{ +return NULL ; +}static inline int __pm_genpd_add_device (struct generic_pm_domain *genpd,struct device *dev,struct gpd_timing_data *td) --2.1.4
Jon Hunter
maintainerPATCH v6 5/10 Documentation: DT: bindings: Add power domain info for NVIDIA PMC
In reply to Jon HunterAdd power-domain binding documentation for the NVIDIA PMC driver in order to support generic power-domains.
--- .../bindings/arm/tegra/nvidia,tegra20-pmc.txt | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+)
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt +61 -0
@@ -1,5 +1,7 @@ NVIDIA Tegra Power Management Controller (PMC) +== Power Management Controller Node == + The PMC block interacts with an external Power Management Unit. The PMC mostly controls the entry and exit of the system from different sleep modes. It provides power-gating controllers for SoC and CPU power-islands.
@@ -70,6 +72,11 @@ Optional properties for hardware-triggered thermal reset (inside 'i2c-thermtrip' Defaults to 0. Valid values are described in section 12.5.2 "Pinmux Support" of the Tegra4 Technical Reference Manual. +Optional nodes: +- powergates : This node contains a hierarchy of power domain nodes, which + should match the powergates on the Tegra SoC. See "Powergate + Nodes" below. + Example: / SoC dts including file
@@ -115,3 +122,57 @@ pmc@7000f400 { }; ... }; + + +== Powergate Nodes == + +Each of the powergate nodes represents a power-domain on the Tegra SoC +that can be power-gated by the PMC and should be named appropriately. + +Required properties: + - reg: Contains an integer value that identifies the PMC power-gate. + Please refer to the Tegra TRM for more details. The parent node + must contain the following two properties: + - #address-cells: Must be 1, + - #size-cells: Must be 0. + - clocks: Must contain an entry for each clock required by the PMC for + controlling a power-gate. See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each reset required by the PMC for + controlling a power-gate. See ../reset/reset.txt for details. + - #power-domain-cells: Must be 0. + +Example: + + pmc: pmc@0,7000e400 { + compatible = "nvidia,tegra210-pmc"; + reg = <0x0 0x7000e400 0x0 0x400>; + clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>; + clock-names = "pclk", "clk32k_in"; + + powergates { + #address-cells = <1>; + #size-cells = <0>; + + pd_audio: aud { + reg = <TEGRA_POWERGATE_AUD>; + clocks = <&tegra_car TEGRA210_CLK_APE>, + <&tegra_car TEGRA210_CLK_APB2APE>; + resets = <&tegra_car 198>; + #power-domain-cells = <0>; + }; + }; + }; + + +== Powergate Clients == + +Hardware blocks belonging to a power domain should contain a "power-domains" +property that is a phandle pointing to the corresponding powergate node. + +Example: + + adma: adma@702e2000 { + ... + power-domains = <&pd_audio>; + ... + };
Signature · 1 line
2.1.4
A message that is not in the archive (sent off-list or not yet received): 1456501724-28477-6-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org
Re: [PATCH V6 05/10] Documentation: DT: bindings: Add power domain info for NVIDIA PMC
Quoted 67 lines · Jon Hunter
Add power-domain binding documentation for the NVIDIA PMC driver in order to support generic power-domains.
Signed-off-by Jon Hunter <[email protected]>Acked-by Rob Herring <[email protected]>--- .../bindings/arm/tegra/nvidia,tegra20-pmc.txt | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+)Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt +37
-0@@ -1,5 +1,7 @@ NVIDIA Tegra Power Management Controller (PMC) +== Power Management Controller Node == + The PMC block interacts with an external Power Management Unit. The PMC mostly controls the entry and exit of the system from different sleep modes. It provides power-gating controllers for SoC and CPU power-islands.@@ -70,6 +72,11 @@ Optional properties for hardware-triggered thermal reset (inside 'i2c-thermtrip' Defaults to 0. Valid values are described in section 12.5.2 "Pinmux Support" of the Tegra4 Technical Reference Manual. +Optional nodes: +- powergates : This node contains a hierarchy of power domain nodes, which + should match the powergates on the Tegra SoC. See "Powergate + Nodes" below. + Example: / SoC dts including file@@ -115,3 +122,57 @@ pmc@7000f400 { }; }; + + +== Powergate Nodes == + +Each of the powergate nodes represents a power-domain on the Tegra SoC +that can be power-gated by the PMC and should be named appropriately. + +Required properties: + - reg: Contains an integer value that identifies the PMC power-gate. + Please refer to the Tegra TRM for more details. The parent node + must contain the following two properties: + - #address-cells: Must be 1, + - #size-cells: Must be 0. + - clocks: Must contain an entry for each clock required by the PMC for + controlling a power-gate. See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each reset required by the PMC for + controlling a power-gate. See ../reset/reset.txt for details. + - #power-domain-cells: Must be 0. + +Example: + + pmc: pmc@0,7000e400 { + compatible = "nvidia,tegra210-pmc"; + reg = <0x0 0x7000e400 0x0 0x400>; + clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>; + clock-names = "pclk", "clk32k_in"; + + powergates { + #address-cells = <1>; + #size-cells = <0>;
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt pmc@7000f400 { · line 164
Quoted 10 lines
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt +10
-0+ + pd_audio: aud { + reg = <TEGRA_POWERGATE_AUD>; + clocks = <&tegra_car TEGRA210_CLK_APE>, + <&tegra_car TEGRA210_CLK_APB2APE>; + resets = <&tegra_car 198>; + #power-domain-cells = <0>; + }; + }; + };
Should we not spell out the list of supported power domains per SoC here? The example gives only one, but we have a bunch of others. If they can be referred to by phandle I'd expect there to be a list of them. I'm not sure if this was discussed earlier, but does it perhaps make sense to tie names to IDs, such that we don't need the reg property? That'd be analogous to how PMICs define regulators.
The reason why I'm asking is that in the above example it's possible to have this:
pd_audio: pcie {
reg = <TEGRA_POWERGATE_SOR>;
...
};And there'd be no way to sanity check other than by human inspection. Perhaps I'm being overly paranoid and we can easily filter these out during code review.
I suppose that if Rob's fine with it, I can be too.
Thierry
Jon Hunter
maintainerRe: [PATCH V6 05/10] Documentation: DT: bindings: Add power domain info for NVIDIA PMC
Quoted 79 lines · Thierry Reding
* PGP Signed by an unknown key
Quoted 76 lines · Jon Hunter
Add power-domain binding documentation for the NVIDIA PMC driver in order to support generic power-domains.
Signed-off-by Jon Hunter <[email protected]>Acked-by Rob Herring <[email protected]>--- .../bindings/arm/tegra/nvidia,tegra20-pmc.txt | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+)Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt +46
-0@@ -1,5 +1,7 @@ NVIDIA Tegra Power Management Controller (PMC) +== Power Management Controller Node == + The PMC block interacts with an external Power Management Unit. The PMC mostly controls the entry and exit of the system from different sleep modes. It provides power-gating controllers for SoC and CPU power-islands.@@ -70,6 +72,11 @@ Optional properties for hardware-triggered thermal reset (inside 'i2c-thermtrip' Defaults to 0. Valid values are described in section 12.5.2 "Pinmux Support" of the Tegra4 Technical Reference Manual. +Optional nodes: +- powergates : This node contains a hierarchy of power domain nodes, which + should match the powergates on the Tegra SoC. See "Powergate + Nodes" below. + Example: / SoC dts including file@@ -115,3 +122,57 @@ pmc@7000f400 { }; }; + + +== Powergate Nodes == + +Each of the powergate nodes represents a power-domain on the Tegra SoC +that can be power-gated by the PMC and should be named appropriately. + +Required properties: + - reg: Contains an integer value that identifies the PMC power-gate. + Please refer to the Tegra TRM for more details. The parent node + must contain the following two properties: + - #address-cells: Must be 1, + - #size-cells: Must be 0. + - clocks: Must contain an entry for each clock required by the PMC for + controlling a power-gate. See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each reset required by the PMC for + controlling a power-gate. See ../reset/reset.txt for details. + - #power-domain-cells: Must be 0. + +Example: + + pmc: pmc@0,7000e400 { + compatible = "nvidia,tegra210-pmc"; + reg = <0x0 0x7000e400 0x0 0x400>; + clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>; + clock-names = "pclk", "clk32k_in"; + + powergates { + #address-cells = <1>; + #size-cells = <0>; + + pd_audio: aud { + reg = <TEGRA_POWERGATE_AUD>; + clocks = <&tegra_car TEGRA210_CLK_APE>, + <&tegra_car TEGRA210_CLK_APB2APE>; + resets = <&tegra_car 198>; + #power-domain-cells = <0>; + }; + };
Quoted 8 lines
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
Quoted 1 line
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt +1
-0+ };Should we not spell out the list of supported power domains per SoC here? The example gives only one, but we have a bunch of others. If they can be referred to by phandle I'd expect there to be a list of them. I'm not sure if this was discussed earlier, but does it perhaps make sense to tie names to IDs, such that we don't need the reg property? That'd be analogous to how PMICs define regulators.
So the supported power-domains per SoC are described in the header "include/dt-bindings/power/tegra-powergate.h" (see patch #8). Perhaps, I can move patch #8 to before this patch and add a reference to the header file for a list of supported power-domains. However ...
Quoted 7 lines
The reason why I'm asking is that in the above example it's possible to have this:
pd_audio: pcie { reg = <TEGRA_POWERGATE_SOR>; ... };
... if we eliminate the "reg" property and just use the name, then yes it would make sense to move the list of support power-domains into the binding doc.
It all depends on whether we want to define the IDs in the binding or in the PMC driver. Right now we have a static list of power-domains in the PMC driver per SoC and I had thought that in the long term we would be able to get rid of these and just rely on the binding. But ...
Quoted 3 lines
And there'd be no way to sanity check other than by human inspection. Perhaps I'm being overly paranoid and we can easily filter these out during code review.
... that would mean that we have to rely on the binding being correct
and inspect manually. On the other hand, if we don't have the IDs in the binding we still need to inspect the static arrays in the PMC driver and so far I have found a few errors with these. So does it really change/improve anything?
Cheers
Jon
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH V6 05/10] Documentation: DT: bindings: Add power domain info for NVIDIA PMC
Quoted 116 lines · Jon Hunter
Quoted 79 lines · Thierry Reding
* PGP Signed by an unknown key
Quoted 76 lines · Jon Hunter
Add power-domain binding documentation for the NVIDIA PMC driver in order to support generic power-domains.
Signed-off-by Jon Hunter <[email protected]>Acked-by Rob Herring <[email protected]>--- .../bindings/arm/tegra/nvidia,tegra20-pmc.txt | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+)Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt +46
-0@@ -1,5 +1,7 @@ NVIDIA Tegra Power Management Controller (PMC) +== Power Management Controller Node == + The PMC block interacts with an external Power Management Unit. The PMC mostly controls the entry and exit of the system from different sleep modes. It provides power-gating controllers for SoC and CPU power-islands.@@ -70,6 +72,11 @@ Optional properties for hardware-triggered thermal reset (inside 'i2c-thermtrip' Defaults to 0. Valid values are described in section 12.5.2 "Pinmux Support" of the Tegra4 Technical Reference Manual. +Optional nodes: +- powergates : This node contains a hierarchy of power domain nodes, which + should match the powergates on the Tegra SoC. See "Powergate + Nodes" below. + Example: / SoC dts including file@@ -115,3 +122,57 @@ pmc@7000f400 { }; }; + + +== Powergate Nodes == + +Each of the powergate nodes represents a power-domain on the Tegra SoC +that can be power-gated by the PMC and should be named appropriately. + +Required properties: + - reg: Contains an integer value that identifies the PMC power-gate. + Please refer to the Tegra TRM for more details. The parent node + must contain the following two properties: + - #address-cells: Must be 1, + - #size-cells: Must be 0. + - clocks: Must contain an entry for each clock required by the PMC for + controlling a power-gate. See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each reset required by the PMC for + controlling a power-gate. See ../reset/reset.txt for details. + - #power-domain-cells: Must be 0. + +Example: + + pmc: pmc@0,7000e400 { + compatible = "nvidia,tegra210-pmc"; + reg = <0x0 0x7000e400 0x0 0x400>; + clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>; + clock-names = "pclk", "clk32k_in"; + + powergates { + #address-cells = <1>; + #size-cells = <0>; + + pd_audio: aud { + reg = <TEGRA_POWERGATE_AUD>; + clocks = <&tegra_car TEGRA210_CLK_APE>, + <&tegra_car TEGRA210_CLK_APB2APE>; + resets = <&tegra_car 198>; + #power-domain-cells = <0>; + }; + };Quoted 8 lines
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
Quoted 1 line
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt +1
-0+ };Should we not spell out the list of supported power domains per SoC here? The example gives only one, but we have a bunch of others. If they can be referred to by phandle I'd expect there to be a list of them. I'm not sure if this was discussed earlier, but does it perhaps make sense to tie names to IDs, such that we don't need the reg property? That'd be analogous to how PMICs define regulators.
So the supported power-domains per SoC are described in the header "
include/dt-bindings/power/tegra-powergate.h" (see patch #8). Perhaps, I can move patch #8 to before this patch and add a reference to the header file for a list of supported power-domains. However ...Quoted 7 lines
The reason why I'm asking is that in the above example it's possible to have this:
pd_audio: pcie { reg = <TEGRA_POWERGATE_SOR>; ... };... if we eliminate the "reg" property and just use the name, then yes it would make sense to move the list of support power-domains into the binding doc.
It all depends on whether we want to define the IDs in the binding or in the PMC driver. Right now we have a static list of power-domains in the PMC driver per SoC and I had thought that in the long term we would be able to get rid of these and just rely on the binding. But ...
Quoted 3 lines
And there'd be no way to sanity check other than by human inspection. Perhaps I'm being overly paranoid and we can easily filter these out during code review.
Quoted 5 lines
... that would mean that we have to rely on the binding being correct
and inspect manually. On the other hand, if we don't have the IDs in the binding we still need to inspect the static arrays in the PMC driver and so far I have found a few errors with these. So does it really change/improve anything?
I've always considered per-SoC invariant data to not belong into bindings. That is, constants such as power partition IDs or SMMU client IDs should be defined via tables in drivers, and DT should be used to hook them up to devices.
Defining the existing power domains in DT seems rather brittle to me. A compatible string would imply the set of supported power domains anyway and having that set specified in DT would technically require us to add code in the driver to validate that the DT is sane, which would entail the addition of a very similar table anyway.
One further reason why I prefer not to have these things specified (as opposed to "glued" together) in DT is that the DT is ABI, so if we ever happen to ship a broken DT we won't be able to easily fix it. Driver code, on the other hand, can always easily be fixed.
Thierry
Re: [PATCH V6 05/10] Documentation: DT: bindings: Add power domain info for NVIDIA PMC
On 29/02/16 11:01, Thierry Reding wrote:
[snip]
Quoted 11 lines
I've always considered per-SoC invariant data to not belong into bindings. That is, constants such as power partition IDs or SMMU client IDs should be defined via tables in drivers, and DT should be used to hook them up to devices.
Defining the existing power domains in DT seems rather brittle to me. A compatible string would imply the set of supported power domains anyway and having that set specified in DT would technically require us to add code in the driver to validate that the DT is sane, which would entail the addition of a very similar table anyway.
Quoted 4 lines
One further reason why I prefer not to have these things specified (as opposed to "glued" together) in DT is that the DT is ABI, so if we ever happen to ship a broken DT we won't be able to easily fix it. Driver code, on the other hand, can always easily be fixed.
Yes, I guess that is consistent with other Tegra drivers too. Ok, I will drop the reg property and just use the name.
Cheers
Jon
Jon Hunter
maintainerPATCH v6 7/10 soc: tegra: pmc: Add generic PM domain support
In reply to Jon HunterAdds generic PM support to the PMC driver where the PM domains are populated from device-tree and the PM domain consumer devices are bound to their relevant PM domains via device-tree as well.
Update the tegra_powergate_sequence_power_up() API so that internally it calls the same tegra_powergate_xxx functions that are used by the tegra generic power domain code for consistency.
To ensure that the Tegra power domains (a.k.a powergates) cannot be controlled via both the legacy tegra_powergate_xxx functions as well as the generic PM domain framework, add a bit map for available powergates that can be controlled via the legacy powergate functions.
Move the majority of the tegra_powergate_remove_clamping() function to a sub-function, so that this can be used by both the legacy and generic power domain code.
This is based upon work by Thierry Reding <[email protected]> and Vince Hsu <[email protected]>.
--- drivers/soc/tegra/pmc.c | 585 ++++++++++++++++++++++++++++++++++++++++++------ include/soc/tegra/pmc.h | 1 + 2 files changed, 522 insertions(+), 64 deletions(-)
drivers/soc/tegra/pmc.c +521 -64
@@ -31,10 +31,13 @@#include <linux/iopoll.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/pm_domain.h> #include <linux/reboot.h> #include <linux/reset.h> #include <linux/seq_file.h> +#include <linux/slab.h> #include <linux/spinlock.h> #include <soc/tegra/common.h>
@@ -102,6 +105,18 @@#define GPU_RG_CNTRL 0x2d4 +struct tegra_powergate { +struct generic_pm_domain genpd; +struct generic_pm_domain *parent; +struct tegra_pmc *pmc; +unsigned int id; +struct device_node *of_node; +struct clk **clks; +unsigned int num_clks; +struct reset_control **resets; +unsigned int num_resets; +}; +struct tegra_pmc_soc {unsigned int num_powergates;const char *const *powergates;
@@ -132,6 +147,7 @@ struct tegra_pmc_soc {* @cpu_pwr_good_en: CPU power good signal is enabled * @lp0_vec_phys: physical base address of the LP0 warm boot code * @lp0_vec_size: size of the LP0 warm boot code +* @powergates_available: Bitmap of available power gates * @powergates_lock: mutex for power gate register access */ struct tegra_pmc {
@@ -156,6 +172,7 @@ struct tegra_pmc {bool cpu_pwr_good_en;u32 lp0_vec_phys;u32 lp0_vec_size; +DECLARE_BITMAP (powergates_available,TEGRA_POWERGATE_MAX );struct mutex powergates_lock; };
@@ -165,6 +182,12 @@ static struct tegra_pmc *pmc = &(struct tegra_pmc) { .suspend_mode = TEGRA_SUSPEND_NONE, }; +static inline struct tegra_powergate * +to_powergate (struct generic_pm_domain *domain) +{ + return container_of(domain, struct tegra_powergate, genpd); +} +static u32 tegra_pmc_readl (unsigned long offset) {return readl (pmc->base + offset);
@@ -188,6 +211,11 @@ static inline bool tegra_powergate_is_valid(int id)return (pmc->soc && pmc->soc->powergates[id]); } +static inline bool tegra_powergate_is_available (int id) +{ +return test_bit (id, pmc->powergates_available); +} +/** * tegra_powergate_set() - set the state of a partition * @id: partition ID
@@ -218,13 +246,219 @@ static int tegra_powergate_set(unsigned int id, bool new_state)return err; } +static int __tegra_powergate_remove_clamping (unsigned int id) +{ +u32 mask; + +mutex_lock (&pmc->powergates_lock); + +/* +* On Tegra124 and later, the clamps for the GPU are controlled by a +* separate register (with different semantics). +*/ +if (id ==TEGRA_POWERGATE_3D ) { +if (pmc->soc->has_gpu_clamps) { +tegra_pmc_writel (0 ,GPU_RG_CNTRL ); + goto out; + } + } + +/* +* Tegra 2 has a bug where PCIE and VDE clamping masks are +* swapped relatively to the partition ids +*/ +if (id ==TEGRA_POWERGATE_VDEC ) + mask = (1 <<TEGRA_POWERGATE_PCIE ); +else if (id ==TEGRA_POWERGATE_PCIE ) + mask = (1 <<TEGRA_POWERGATE_VDEC ); +else + mask = (1 << id); + +tegra_pmc_writel (mask,REMOVE_CLAMPING ); + +out: +mutex_unlock (&pmc->powergates_lock); + +return 0 ; +} + +static void tegra_powergate_disable_clocks (struct tegra_powergate *pg) +{ +unsigned int i; + +for (i =0 ; i < pg->num_clks; i++) +clk_disable_unprepare (pg->clks[i]); +} + +static int tegra_powergate_enable_clocks (struct tegra_powergate *pg) +{ +unsigned int i; +int err; + +for (i =0 ; i < pg->num_clks; i++) { + err =clk_prepare_enable (pg->clks[i]); +if (err) + goto out; + } + +return 0 ; + +out: +while (i--) +clk_disable_unprepare (pg->clks[i]); + +return err; +} + +static int tegra_powergate_reset_assert (struct tegra_powergate *pg) +{ +unsigned int i; +int err; + +for (i =0 ; i < pg->num_resets; i++) { + err =reset_control_assert (pg->resets[i]); +if (err) +return err; + } + +return 0 ; +} + +static int tegra_powergate_reset_deassert (struct tegra_powergate *pg) +{ +unsigned int i; +int err; + +for (i =0 ; i < pg->num_resets; i++) { + err =reset_control_deassert (pg->resets[i]); +if (err) +return err; + } + +return 0 ; +} + +static int tegra_powergate_power_up (struct tegra_powergate *pg, +bool disable_clocks) +{ +int err; + + err =tegra_powergate_reset_assert (pg); +if (err) +return err; + +usleep_range (10 ,20 ); + + err =tegra_powergate_set (pg->id, true); +if (err <0 ) +return err; + +usleep_range (10 ,20 ); + + err =tegra_powergate_enable_clocks (pg); +if (err) + goto disable_clks; + +usleep_range (10 ,20 ); + + err =__tegra_powergate_remove_clamping (pg->id); +if (err) + goto disable_clks; + +usleep_range (10 ,20 ); + + err =tegra_powergate_reset_deassert (pg); +if (err) + goto powergate_off; + +usleep_range (10 ,20 ); + +if (disable_clocks) +tegra_powergate_disable_clocks (pg); + +return 0 ; + +disable_clks: +tegra_powergate_disable_clocks (pg); +usleep_range (10 ,20 ); +powergate_off: +tegra_powergate_set (pg->id, false); + +return err; +} + +static int tegra_powergate_power_down (struct tegra_powergate *pg) +{ +int err; + + err =tegra_powergate_enable_clocks (pg); +if (err) +return err; + +usleep_range (10 ,20 ); + + err =tegra_powergate_reset_assert (pg); +if (err) + goto disable_clks; + +usleep_range (10 ,20 ); + +tegra_powergate_disable_clocks (pg); + +usleep_range (10 ,20 ); + + err =tegra_powergate_set (pg->id, false); +if (err) + goto assert_resets; + +return 0 ; + +assert_resets: +tegra_powergate_enable_clocks (pg); +usleep_range (10 ,20 ); +tegra_powergate_reset_deassert (pg); +usleep_range (10 ,20 ); +disable_clks: +tegra_powergate_disable_clocks (pg); + +return err; +} + +static int tegra_genpd_power_on (struct generic_pm_domain *domain) +{ +struct tegra_powergate *pg =to_powergate (domain); +struct tegra_pmc *pmc = pg->pmc; +int err; + + err =tegra_powergate_power_up (pg, true); +if (err) +dev_err (pmc->dev,"failed to turn on PM domain %s: %d\n" , + pg->of_node->name, err); + +return err; +} + +static int tegra_genpd_power_off (struct generic_pm_domain *domain) +{ +struct tegra_powergate *pg =to_powergate (domain); +struct tegra_pmc *pmc = pg->pmc; +int err; + + err =tegra_powergate_power_down (pg); +if (err) +dev_err (pmc->dev,"failed to turn off PM domain %s: %d\n" , + pg->of_node->name, err); + +return err; +} +/** * tegra_powergate_power_on() - power on partition * @id: partition ID */ int tegra_powergate_power_on (unsigned int id) { -if (!tegra_powergate_is_valid (id)) +if (!tegra_powergate_is_available (id))return -EINVAL ;return tegra_powergate_set (id, true);
@@ -236,7 +470,7 @@ int tegra_powergate_power_on(unsigned int id)*/ int tegra_powergate_power_off (unsigned int id) { -if (!tegra_powergate_is_valid (id)) +if (!tegra_powergate_is_available (id))return -EINVAL ;return tegra_powergate_set (id, false);
@@ -267,41 +501,10 @@ int tegra_powergate_is_powered(unsigned int id)*/ int tegra_powergate_remove_clamping (unsigned int id) { -u32 mask; - -if (!tegra_powergate_is_valid (id)) +if (!tegra_powergate_is_available (id))return -EINVAL ; -mutex_lock (&pmc->powergates_lock); - -/* -* On Tegra124 and later, the clamps for the GPU are controlled by a -* separate register (with different semantics). -*/ -if (id ==TEGRA_POWERGATE_3D ) { -if (pmc->soc->has_gpu_clamps) { -tegra_pmc_writel (0 ,GPU_RG_CNTRL ); - goto out; - } - } - -/* -* Tegra 2 has a bug where PCIE and VDE clamping masks are -* swapped relatively to the partition ids -*/ -if (id ==TEGRA_POWERGATE_VDEC ) - mask = (1 <<TEGRA_POWERGATE_PCIE ); -else if (id ==TEGRA_POWERGATE_PCIE ) - mask = (1 <<TEGRA_POWERGATE_VDEC ); -else - mask = (1 << id); - -tegra_pmc_writel (mask,REMOVE_CLAMPING ); - -out: -mutex_unlock (&pmc->powergates_lock); - -return 0 ; +return __tegra_powergate_remove_clamping (id); }EXPORT_SYMBOL (tegra_powergate_remove_clamping);
@@ -316,35 +519,20 @@ EXPORT_SYMBOL(tegra_powergate_remove_clamping);int tegra_powergate_sequence_power_up (unsigned int id,struct clk *clk,struct reset_control *rst) { -int ret; - -reset_control_assert (rst); - - ret =tegra_powergate_power_on (id); -if (ret) - goto err_power; - - ret =clk_prepare_enable (clk); -if (ret) - goto err_clk; - -usleep_range (10 ,20 ); - - ret =tegra_powergate_remove_clamping (id); -if (ret) - goto err_clamp; +struct tegra_powergate pg; +int err; -usleep_range (10 ,20 ); -reset_control_deassert (rst); + pg.id = id; + pg.clks = &clk; + pg.num_clks =1 ; + pg.resets = &rst; + pg.num_resets =1 ; -return 0 ; + err =tegra_powergate_power_up (&pg, false); +if (err) +pr_err ("failed to turn on partition %d: %d\n" , id, err); -err_clamp: -clk_disable_unprepare (clk); -err_clk: -tegra_powergate_power_off (id); -err_power: -return ret; +return err; }EXPORT_SYMBOL (tegra_powergate_sequence_power_up);
@@ -486,6 +674,259 @@ static int tegra_powergate_debugfs_init(void)return 0 ; } +static int tegra_powergate_of_get_clks (struct device *dev, +struct tegra_powergate *pg) +{ +struct clk *clk; +unsigned int i, count; +int err; + + count =of_count_phandle_with_args (pg->of_node,"clocks" , +"#clock-cells" ); +if (count ==0 ) +return -ENODEV ; + + pg->clks =devm_kcalloc (dev, count,sizeof (clk),GFP_KERNEL ); +if (!pg->clks) +return -ENOMEM ; + +for (i =0 ; i < count; i++) { + pg->clks[i] =of_clk_get (pg->of_node, i); +if (IS_ERR (pg->clks[i])) { + err =PTR_ERR (pg->clks[i]); + goto err; + } + } + + pg->num_clks = count; + +return 0 ; + +err: +while (i--) +clk_put (pg->clks[i]); + +return err; +} + +static int tegra_powergate_of_get_resets (struct device *dev, +struct tegra_powergate *pg) +{ +struct reset_control *rst; +unsigned int i, count; +int err; + + count =of_count_phandle_with_args (pg->of_node,"resets" , +"#reset-cells" ); +if (count ==0 ) +return -ENODEV ; + + pg->resets =devm_kcalloc (dev, count,sizeof (rst),GFP_KERNEL ); +if (!pg->resets) +return -ENOMEM ; + +for (i =0 ; i < count; i++) { + pg->resets[i] =of_reset_control_get_by_index (pg->of_node, i); +if (IS_ERR (pg->resets[i])) { + err =PTR_ERR (pg->resets[i]); + goto error; + } + } + + pg->num_resets = count; + +return 0 ; + +error: +while (i--) +reset_control_put (pg->resets[i]); + +return err; +} + +static struct tegra_powergate * +tegra_powergate_add_one (struct tegra_pmc *pmc,struct device_node *np, +struct generic_pm_domain *parent) +{ +struct tegra_powergate *pg; +const __be32 *reg; +unsigned int id; +bool off; +int err; + +/* +* If the powergate ID is missing or invalid then return NULL +* to skip this one and allow any others to be created. +*/ + reg =of_get_property (np,"reg" ,NULL ); +if (!reg) { +dev_WARN (pmc->dev,"reg node missing for %s\n" , np->name); +return NULL ; + } + + id =be32_to_cpup (reg); + +if (!tegra_powergate_is_available (id)) { +dev_WARN (pmc->dev,"%s powergate is not available\n" , np->name); +return NULL ; + } + +/* +* Clear the bit for this powergate so it cannot be managed +* directly via the legacy APIs for controlling powergates. +*/ +clear_bit (id, pmc->powergates_available); + + pg =kzalloc (sizeof (*pg),GFP_KERNEL ); +if (!pg) { + err = -ENOMEM ; + goto set_available; + } + + pg->id = id; + pg->of_node = np; + pg->parent = parent; + pg->genpd.owner = pmc->dev; + pg->genpd.name = np->name; + pg->genpd.power_off = tegra_genpd_power_off; + pg->genpd.power_on = tegra_genpd_power_on; + pg->pmc = pmc; + + err =tegra_powergate_of_get_clks (pmc->dev, pg); +if (err) + goto free_mem; + + err =tegra_powergate_of_get_resets (pmc->dev, pg); +if (err) + goto remove_clks; + + off = !tegra_powergate_is_powered (pg->id); + +pm_genpd_init (&pg->genpd,NULL , off); + +if (pg->parent) { + err =pm_genpd_add_subdomain (pg->parent, &pg->genpd); +if (err) + goto remove_domain_and_resets; + } + + err =of_genpd_add_provider_simple (pg->of_node, &pg->genpd); +if (err) + goto remove_subdomain; + +dev_dbg (pmc->dev,"added power domain %s\n" , pg->genpd.name); + +return pg; + +remove_subdomain: +if (pg->parent) +if (WARN_ON (pm_genpd_remove_subdomain (pg->parent, &pg->genpd))) + goto error; + +remove_domain_and_resets: +if (WARN_ON (pm_genpd_remove (&pg->genpd))) + goto error; + +while (pg->num_resets--) +reset_control_put (pg->resets[pg->num_resets]); + +remove_clks: +while (pg->num_clks--) +clk_put (pg->clks[pg->num_clks]); + +free_mem: +kfree (pg); + +set_available: +set_bit (id, pmc->powergates_available); + +error: +dev_err (pmc->dev,"failed to create power domain for node %s\n" , + np->name); + +return ERR_PTR (err); +} + +static int tegra_powergate_add (struct tegra_pmc *pmc,struct device_node *np, +struct generic_pm_domain *parent) +{ +struct tegra_powergate *pg; +struct device_node *child; +int err =0 ; + +for_each_child_of_node (np, child) { + pg =tegra_powergate_add_one (pmc, child, parent); +if (IS_ERR (pg)) { + err =PTR_ERR (pg); + goto error; + } + +if (pg) + err =tegra_powergate_add (pmc, child, &pg->genpd); + +error: +of_node_put (child); + +if (err) +break ; + } + +return err; +} + +static void tegra_powergate_remove (struct tegra_pmc *pmc) +{ +struct generic_pm_domain *genpd =pm_genpd_list_get_tail (pmc->dev); +struct tegra_powergate *pg; + +while (genpd) { + pg =to_powergate (genpd); + +of_genpd_del_provider (pg->of_node); + +if (pg->parent) { +if (WARN_ON (pm_genpd_remove_subdomain (pg->parent, + &pg->genpd))) +return ; + + pg->parent =NULL ; + } + +if (WARN_ON (pm_genpd_remove (&pg->genpd))) +return ; + +while (pg->num_clks--) +clk_put (pg->clks[pg->num_clks]); + +while (pg->num_resets--) +reset_control_put (pg->resets[pg->num_resets]); + +kfree (pg); + +set_bit (pg->id, pmc->powergates_available); + + genpd =pm_genpd_list_get_tail (pmc->dev); + } +} + +static int tegra_powergate_init (struct tegra_pmc *pmc) +{ +struct device_node *np; +int err; + + np =of_get_child_by_name (pmc->dev->of_node,"powergates" ); +if (!np) +return 0 ; + + err =tegra_powergate_add (pmc, np,NULL ); +if (err) +tegra_powergate_remove (pmc); + +of_node_put (np); + +return err; +} +static int tegra_io_rail_prepare (unsigned int id,unsigned long *request,unsigned long *status,unsigned int *bit) {
@@ -873,18 +1314,21 @@ static int tegra_pmc_probe(struct platform_device *pdev)tegra_pmc_init_tsense_reset (pmc); + err =tegra_powergate_init (pmc); +if (err <0 ) +return err; +if (IS_ENABLED (CONFIG_DEBUG_FS )) { err =tegra_powergate_debugfs_init ();if (err <0 ) -return err; + goto remove_powergates; } err =register_restart_handler (&tegra_pmc_restart_handler);if (err) { -debugfs_remove (pmc->debugfs);dev_err (&pdev->dev,"unable to register restart handler, %d\n" , err); -return err; + goto remove_debugfs; }mutex_lock (&pmc->powergates_lock);
@@ -893,6 +1337,13 @@ static int tegra_pmc_probe(struct platform_device *pdev)mutex_unlock (&pmc->powergates_lock);return 0 ; + +remove_debugfs: +debugfs_remove (pmc->debugfs); +remove_powergates: +tegra_powergate_remove (pmc); + +return err; }#if defined(CONFIG_PM_SLEEP ) && defined(CONFIG_ARM )
@@ -1120,6 +1571,7 @@ static int __init tegra_pmc_early_init(void)const struct of_device_id *match;struct device_node *np;struct resource regs; +unsigned int i;bool invert;u32 value;
@@ -1169,6 +1621,11 @@ static int __init tegra_pmc_early_init(void)return -ENXIO ; } +/* Create a bit-map of the available and valid partitions */ +for (i =0 ; i < pmc->soc->num_powergates; i++) +if (pmc->soc->powergates[i]) +set_bit (i, pmc->powergates_available); +mutex_init (&pmc->powergates_lock);/*
include/soc/tegra/pmc.h +1 -0
@@ -72,6 +72,7 @@ int tegra_pmc_cpu_remove_clamping(unsigned int cpuid);#define TEGRA_POWERGATE_AUD 27#define TEGRA_POWERGATE_DFD 28#define TEGRA_POWERGATE_VE2 29 +#define TEGRA_POWERGATE_MAX TEGRA_POWERGATE_VE2#define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D
Signature · 1 line
2.1.4
A message that is not in the archive (sent off-list or not yet received): 1456501724-28477-8-git-send-email-jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org
Kevin Hilman
Acked-byRe: [PATCH V6 07/10] soc: tegra: pmc: Add generic PM domain support
Quoted 13 lines · Jon Hunter
Adds generic PM support to the PMC driver where the PM domains are populated from device-tree and the PM domain consumer devices are bound to their relevant PM domains via device-tree as well.
Update the
tegra_powergate_sequence_power_up()API so that internally it calls the sametegra_powergate_xxxfunctions that are used by the tegra generic power domain code for consistency.To ensure that the Tegra power domains (a.k.a powergates) cannot be controlled via both the legacy
tegra_powergate_xxxfunctions as well as the generic PM domain framework, add a bit map for available powergates that can be controlled via the legacy powergate functions.
Quoted 8 lines
Move the majority of the
tegra_powergate_remove_clamping()function to a sub-function, so that this can be used by both the legacy and generic power domain code.This is based upon work by Thierry Reding <[email protected]> and Vince Hsu <[email protected]>.
Signed-off-by Jon Hunter <[email protected]>
I didn't look in great detail at the SoC specifics, but for the for the general genpd approach:
Jon Hunter
maintainerPATCH v6 10/10 ARM64: tegra: Add audio PM domain device node for Tegra210
In reply to Jon HunterAdd the audio power-domain for tegra210. Note that this also removes the existing "#power-domain-cells" which was incorrectly included by commit e53095857166 ("arm64: tegra: Add Tegra210 support").
---
So far I have only added the audio power-domain for tegra210 as this is what I have been testing with to date. However, once this series is accepted then we can begin to add more.
arch/arm64/boot/dts/nvidia/tegra210.dtsi | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
arch/arm64/boot/dts/nvidia/tegra210.dtsi +13 -1
@@ -2,6 +2,7 @@ #include <dt-bindings/gpio/tegra-gpio.h> #include <dt-bindings/memory/tegra210-mc.h> #include <dt-bindings/pinctrl/pinctrl-tegra.h> +#include <dt-bindings/power/tegra-powergate.h> #include <dt-bindings/interrupt-controller/arm-gic.h> / {
@@ -581,7 +582,18 @@ clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>; clock-names = "pclk", "clk32k_in"; - #power-domain-cells = <1>; + powergates { + #address-cells = <1>; + #size-cells = <0>; + + pd_audio: aud { + reg = <TEGRA_POWERGATE_AUD>; + clocks = <&tegra_car TEGRA210_CLK_APE>, + <&tegra_car TEGRA210_CLK_APB2APE>; + resets = <&tegra_car 198>; + #power-domain-cells = <0>; + }; + }; }; fuse@0,7000f800 {
Signature · 1 line
2.1.4
Re: [PATCH V6 10/10] ARM64: tegra: Add audio PM domain device node for Tegra210
Quoted 6 lines · Jon Hunter
Add the audio power-domain for tegra210. Note that this also removes the existing "#power-domain-cells" which was incorrectly included by commit
e53095857166("arm64: tegra: Add Tegra210 support").Signed-off-by Jon Hunter <[email protected]>
Quoted 8 lines
---
So far I have only added the audio power-domain for tegra210 as this is what I have been testing with to date. However, once this series is accepted then we can begin to add more.
arch/arm64/boot/dts/nvidia/tegra210.dtsi | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
I'm slightly reluctant to apply this, since the domain isn't used anywhere. I'm assuming it will be used by the audio driver that you've been working on, but if that's not going to be merged this cycle, we'd end up with an unused label. Not that that's invalid in any way, but my rule of thumb has been not to introduce labels until they are used.
Therefore I suggest we postpone this to the series that adds audio support.
Thierry
Jon Hunter
maintainerRe: [PATCH V6 10/10] ARM64: tegra: Add audio PM domain device node for Tegra210
Quoted 18 lines · Thierry Reding
* PGP Signed by an unknown key
Quoted 6 lines · Jon Hunter
Add the audio power-domain for tegra210. Note that this also removes the existing "#power-domain-cells" which was incorrectly included by commit
e53095857166("arm64: tegra: Add Tegra210 support").Signed-off-by Jon Hunter <[email protected]>Quoted 8 lines
---
So far I have only added the audio power-domain for tegra210 as this is what I have been testing with to date. However, once this series is accepted then we can begin to add more.
arch/arm64/boot/dts/nvidia/tegra210.dtsi | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
Quoted 8 lines
I'm slightly reluctant to apply this, since the domain isn't used anywhere. I'm assuming it will be used by the audio driver that you've been working on, but if that's not going to be merged this cycle, we'd end up with an unused label. Not that that's invalid in any way, but my rule of thumb has been not to introduce labels until they are used.
Therefore I suggest we postpone this to the series that adds audio support.
That's fine with me or I can drop the label, until it is used by a device?
Jon
Re: [PATCH V6 10/10] ARM64: tegra: Add audio PM domain device node for Tegra210
Quoted 27 lines · Jon Hunter
Quoted 24 lines · Thierry Reding
* PGP Signed by an unknown key
Quoted 6 lines · Jon Hunter
Add the audio power-domain for tegra210. Note that this also removes the existing "#power-domain-cells" which was incorrectly included by commit
e53095857166("arm64: tegra: Add Tegra210 support").Signed-off-by Jon Hunter <[email protected]>Quoted 8 lines
---
So far I have only added the audio power-domain for tegra210 as this is what I have been testing with to date. However, once this series is accepted then we can begin to add more.
arch/arm64/boot/dts/nvidia/tegra210.dtsi | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)I'm slightly reluctant to apply this, since the domain isn't used anywhere. I'm assuming it will be used by the audio driver that you've been working on, but if that's not going to be merged this cycle, we'd end up with an unused label. Not that that's invalid in any way, but my rule of thumb has been not to introduce labels until they are used.
Quoted 4 lines
Quoted 2 lines
Therefore I suggest we postpone this to the series that adds audio support.
That's fine with me or I can drop the label, until it is used by a device?
I'd prefer the former, no use in having anything in device tree that we're not using anyway. Unless we need this somehow to automatically turn off the domain at boot, in which case it might make more sense to add all others as well.
Thierry
Quoted 40 lines · Jon Hunter
Adds generic PM domain support for Tegra SoCs but this series only enables support for it on Tegra 64-bit devices. There is no reason why this cannot be enable for Tegra 32-bit devices, but to keep the patch series to a minimum only 64-bit devices are enabled so far.
This series has been boot tested on Tegra210 as well as various 32-bit Tegra platforms.
Summary of changes since V5 [2]:
- Split series into 2 series, separating PMC fixes [3] from genpd changes
- This series is based upon fixes series (which is now in -next)
- Added patch to fix removal of genpd subdomain
- Added patch to get last genpd that was added
- Fixed locking in function to remove genpd
- Updated Tegra PMC driver to ensure power-domains cannot be controlled by both legacy Tegra APIs and generic PM domain framework
- Removed powergate list from Tegra PMC driver and updated removal of power domains to use new genpd APIs.Summary of changes since V4 [1]:
- Re-worked fix to handle base address on probe failure
- Added patch to lock around simultaneuous accesses to PMC registers
- Added patch to change powergate and rail IDs to unsigned type
- Added patch to fix testing of powergate state
- Updated patch to check for valid powergates to use a bitmap
- Updated Tegra DT PMC bindings per Rob H's feedback
- Updated Tegra power domains binding per Thierry's feedback
- Updated Tegra generic power domain support per Thierry's feedbackSummary of changes since V3 [0]:
- Dropped tegra124 support for now
- Removed MC flush support per feedback from Thierry
- Cleaned up the PMC changes per feedback from Thierry
- Added support for tegra210[0] http://comments.gmane.org/gmane.linux.ports.tegra/22944
[1] http://marc.info/?l=linux-tegra&m=144924153600529&w=2
[2] http://marc.info/?l=linux-tegra&m=145399885003830&w=2
[3] http://marc.info/?l=linux-tegra&m=145521381331144&w=2
Quoted 4 lines
Jon Hunter (10):
PM / Domains: Fix removal of a subdomain
PM / Domains: Add function to get the last domain added PM / Domains: Add function to remove a pm-domain
Ulf, Kevin, Rafael,
It's too late to take these patches through the Tegra tree for v4.6, but if Jon can get the above three patches ready before the merge window, would you be willing to pick them up into your trees for v4.6? Doing so might make it easier to deal with the dependencies. The prerequisites would already be in Linus' tree when I apply the Tegra bits for v4.7.
I don't mind taking all of it through the Tegra tree for v4.7, though. I can provide a stable branch with the PM / Domains patches for you to pull in, in case there are any conflicts.
Thierry
A message that is not in the archive (sent off-list or not yet received): 20160302153556.GB21035-AwZRO8vwLAwmlAP/[email protected]
Quoted 8 lines · Thierry Reding
Quoted 7 lines · Jon Hunter
Adds generic PM domain support for Tegra SoCs but this series only enables support for it on Tegra 64-bit devices. There is no reason why this cannot be enable for Tegra 32-bit devices, but to keep the patch series to a minimum only 64-bit devices are enabled so far.
This series has been boot tested on Tegra210 as well as various 32-bit Tegra platforms.
[...]
Quoted 10 lines
Quoted 4 lines
Jon Hunter (10):
PM / Domains: Fix removal of a subdomain
PM / Domains: Add function to get the last domain added PM / Domains: Add function to remove a pm-domainUlf, Kevin, Rafael,
It's too late to take these patches through the Tegra tree for v4.6, but if Jon can get the above three patches ready before the merge window, would you be willing to pick them up into your trees for v4.6?
It's a bit late in the cycle, but since one is a fix and the other two add functions that aren't (yet) used, I think it would be fine to get them in for v4.6. But, the final decision is with Rafael.
Quoted 3 lines
Doing so
might make it easier to deal with the dependencies. The prerequisites would already be in Linus' tree when I apply the Tegra bits for v4.7.
Yeah, makes sense.
Quoted 3 lines
I don't mind taking all of it through the Tegra tree for v4.7, though. I can provide a stable branch with the PM / Domains patches for you to pull in, in case there are any conflicts.
I think it makes the most sense for these prereqs to merge through linux-pm. Let's see what Rafael thinks about the timing.
Kevin
A message that is not in the archive (sent off-list or not yet received): 7h7fhk3c4o.fsf-rdvid1DuHRBWk0Htik3J/[email protected]
Quoted 32 lines · Kevin Hilman
Quoted 8 lines · Thierry Reding
Quoted 7 lines · Jon Hunter
Adds generic PM domain support for Tegra SoCs but this series only enables support for it on Tegra 64-bit devices. There is no reason why this cannot be enable for Tegra 32-bit devices, but to keep the patch series to a minimum only 64-bit devices are enabled so far.
This series has been boot tested on Tegra210 as well as various 32-bit Tegra platforms.
[...]
Quoted 10 lines
Quoted 4 lines
Jon Hunter (10):
PM / Domains: Fix removal of a subdomain
PM / Domains: Add function to get the last domain added PM / Domains: Add function to remove a pm-domainUlf, Kevin, Rafael,
It's too late to take these patches through the Tegra tree for v4.6, but if Jon can get the above three patches ready before the merge window, would you be willing to pick them up into your trees for v4.6?
It's a bit late in the cycle, but since one is a fix and the other two add functions that aren't (yet) used, I think it would be fine to get them in for v4.6. But, the final decision is with Rafael.
Quoted 3 lines
Doing so
might make it easier to deal with the dependencies. The prerequisites would already be in Linus' tree when I apply the Tegra bits for v4.7.
Quoted 8 lines
Yeah, makes sense.
Quoted 3 lines
I don't mind taking all of it through the Tegra tree for v4.7, though. I can provide a stable branch with the PM / Domains patches for you to pull in, in case there are any conflicts.
I think it makes the most sense for these prereqs to merge through linux-pm. Let's see what Rafael thinks about the timing.
The timing is fine by me.
Do you want me to apply [1-3/10] from this series, then?
Thanks,
Rafael
Kevin Hilman
Acked-byQuoted 39 lines · Rafael J. Wysocki
Quoted 38 lines · Kevin Hilman
Quoted 8 lines · Thierry Reding
Quoted 7 lines · Jon Hunter
Adds generic PM domain support for Tegra SoCs but this series only enables support for it on Tegra 64-bit devices. There is no reason why this cannot be enable for Tegra 32-bit devices, but to keep the patch series to a minimum only 64-bit devices are enabled so far.
This series has been boot tested on Tegra210 as well as various 32-bit Tegra platforms.
[...]
Quoted 10 lines
Quoted 4 lines
Jon Hunter (10):
PM / Domains: Fix removal of a subdomain
PM / Domains: Add function to get the last domain added PM / Domains: Add function to remove a pm-domainUlf, Kevin, Rafael,
It's too late to take these patches through the Tegra tree for v4.6, but if Jon can get the above three patches ready before the merge window, would you be willing to pick them up into your trees for v4.6?
It's a bit late in the cycle, but since one is a fix and the other two add functions that aren't (yet) used, I think it would be fine to get them in for v4.6. But, the final decision is with Rafael.
Quoted 3 lines
Doing so
might make it easier to deal with the dependencies. The prerequisites would already be in Linus' tree when I apply the Tegra bits for v4.7.Yeah, makes sense.
Quoted 3 lines
I don't mind taking all of it through the Tegra tree for v4.7, though. I can provide a stable branch with the PM / Domains patches for you to pull in, in case there are any conflicts.
Quoted 6 lines
Quoted 2 lines
I think it makes the most sense for these prereqs to merge through linux-pm. Let's see what Rafael thinks about the timing.
The timing is fine by me.
Do you want me to apply [1-3/10] from this series, then?
Jon has some minor tweaks to do, so he'll respin and then you can take them.
Jon, feel free to add:
For those as well. I thought I responded, but looks like I didn't.
Kevin
A message that is not in the archive (sent off-list or not yet received): 7h7fhkxn1r.fsf-rdvid1DuHRBWk0Htik3J/[email protected]
Quoted 48 lines · Kevin Hilman
Quoted 39 lines · Rafael J. Wysocki
Quoted 38 lines · Kevin Hilman
Quoted 8 lines · Thierry Reding
Quoted 7 lines · Jon Hunter
Adds generic PM domain support for Tegra SoCs but this series only enables support for it on Tegra 64-bit devices. There is no reason why this cannot be enable for Tegra 32-bit devices, but to keep the patch series to a minimum only 64-bit devices are enabled so far.
This series has been boot tested on Tegra210 as well as various 32-bit Tegra platforms.
[...]
Quoted 10 lines
Quoted 4 lines
Jon Hunter (10):
PM / Domains: Fix removal of a subdomain
PM / Domains: Add function to get the last domain added PM / Domains: Add function to remove a pm-domainUlf, Kevin, Rafael,
It's too late to take these patches through the Tegra tree for v4.6, but if Jon can get the above three patches ready before the merge window, would you be willing to pick them up into your trees for v4.6?
It's a bit late in the cycle, but since one is a fix and the other two add functions that aren't (yet) used, I think it would be fine to get them in for v4.6. But, the final decision is with Rafael.
Quoted 3 lines
Doing so
might make it easier to deal with the dependencies. The prerequisites would already be in Linus' tree when I apply the Tegra bits for v4.7.Yeah, makes sense.
Quoted 3 lines
I don't mind taking all of it through the Tegra tree for v4.7, though. I can provide a stable branch with the PM / Domains patches for you to pull in, in case there are any conflicts.
Quoted 6 lines
Quoted 2 lines
I think it makes the most sense for these prereqs to merge through linux-pm. Let's see what Rafael thinks about the timing.
The timing is fine by me.
Do you want me to apply [1-3/10] from this series, then?
Quoted 8 lines
Jon has some minor tweaks to do, so he'll respin and then you can take them.
Jon, feel free to add:
For those as well. I thought I responded, but looks like I didn't.
I am preparing a V7 that I will send out today/tomorrow (latest). I am going to drop the removal parts for now and send that out separately as an RFC because it is bigger than I have expected.
Cheers
Jon
Jon Hunter
maintainerQuoted 55 lines · Jon Hunter
Quoted 53 lines · Kevin Hilman
Quoted 39 lines · Rafael J. Wysocki
Quoted 38 lines · Kevin Hilman
Quoted 8 lines · Thierry Reding
Quoted 7 lines · Jon Hunter
Adds generic PM domain support for Tegra SoCs but this series only enables support for it on Tegra 64-bit devices. There is no reason why this cannot be enable for Tegra 32-bit devices, but to keep the patch series to a minimum only 64-bit devices are enabled so far.
This series has been boot tested on Tegra210 as well as various 32-bit Tegra platforms.
[...]
Quoted 10 lines
Quoted 4 lines
Jon Hunter (10):
PM / Domains: Fix removal of a subdomain
PM / Domains: Add function to get the last domain added PM / Domains: Add function to remove a pm-domainUlf, Kevin, Rafael,
It's too late to take these patches through the Tegra tree for v4.6, but if Jon can get the above three patches ready before the merge window, would you be willing to pick them up into your trees for v4.6?
It's a bit late in the cycle, but since one is a fix and the other two add functions that aren't (yet) used, I think it would be fine to get them in for v4.6. But, the final decision is with Rafael.
Quoted 3 lines
Doing so
might make it easier to deal with the dependencies. The prerequisites would already be in Linus' tree when I apply the Tegra bits for v4.7.Yeah, makes sense.
Quoted 3 lines
I don't mind taking all of it through the Tegra tree for v4.7, though. I can provide a stable branch with the PM / Domains patches for you to pull in, in case there are any conflicts.
Quoted 6 lines
Quoted 2 lines
I think it makes the most sense for these prereqs to merge through linux-pm. Let's see what Rafael thinks about the timing.
The timing is fine by me.
Do you want me to apply [1-3/10] from this series, then?
Jon has some minor tweaks to do, so he'll respin and then you can take them.
Jon, feel free to add:
Quoted 7 lines
Quoted 3 lines
Acked-by Kevin Hilman <[email protected]>For those as well. I thought I responded, but looks like I didn't.
I am preparing a V7 that I will send out today/tomorrow (latest). I am going to drop the removal parts for now and send that out separately as an RFC because it is bigger than I have expected.
Rafael,
By the way, I posted the genpd fixes separately here [0][1].
Cheers
Jon
[0] http://marc.info/?l=linux-pm&m=145708892606515&w=2
[1] http://marc.info/?l=linux-pm&m=145708892606516&w=2