* Re: sh7372 compile breakage in current -next
From: Guennadi Liakhovetski @ 2011-11-17 12:19 UTC (permalink / raw)
To: linux-sh
In-Reply-To: <201111162325.51517.rjw@sisk.pl>
On Wed, 16 Nov 2011, Rafael J. Wysocki wrote:
> On Wednesday, November 16, 2011, Rafael J. Wysocki wrote:
> > On Wednesday, November 16, 2011, Rafael J. Wysocki wrote:
> > > On Wednesday, November 16, 2011, Guennadi Liakhovetski wrote:
> > > > arch/arm/mach-shmobile/pm-sh7372.c: In function 'sh7372_pm_init':
> > > > arch/arm/mach-shmobile/pm-sh7372.c:476: error: 'sh7372_a3sp' undeclared (first use in this function)
> > > > arch/arm/mach-shmobile/pm-sh7372.c:476: error: (Each undeclared identifier is reported only once
> > > > arch/arm/mach-shmobile/pm-sh7372.c:476: error: for each function it appears in.)
> > > > make[2]: *** [arch/arm/mach-shmobile/pm-sh7372.o] Error 1
> > >
> > > OK, I'll have a look at that.
> > >
> > > What's the .config you used?
> >
> > Do you have CONFIG_PM unset, perchance?
>
> Well, I'm quite sure you do. The appended patch should help, then.
Yes, you're right on both occasions:-)
Tested-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Thanks
Guennadi
> Thanks,
> Rafael
>
> ---
> From: Rafael J. Wysocki <rjw@sisk.pl>
> Subject: PM / shmobile: Fix build of sh7372_pm_init() for CONFIG_PM unset
>
> Fix build regression introduced by commit 056879d2f244001b2888cdc8cf
> (ARM: mach-shmobile: sh7372 A3SP no_suspend_console fix) by moving
> the intialization of the A3SP domain to a separate function and
> providing an empty definition of it for CONFIG_PM unset.
>
> Reported-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
> ---
> arch/arm/mach-shmobile/pm-sh7372.c | 19 ++++++++++++++-----
> 1 file changed, 14 insertions(+), 5 deletions(-)
>
> Index: linux/arch/arm/mach-shmobile/pm-sh7372.c
> =================================> --- linux.orig/arch/arm/mach-shmobile/pm-sh7372.c
> +++ linux/arch/arm/mach-shmobile/pm-sh7372.c
> @@ -232,11 +232,23 @@ struct sh7372_pm_domain sh7372_a3sp = {
> .no_debug = true,
> };
>
> +static void sh7372_a3sp_init(void)
> +{
> + /* serial consoles make use of SCIF hardware located in A3SP,
> + * keep such power domain on if "no_console_suspend" is set.
> + */
> + sh7372_a3sp.stay_on = !console_suspend_enabled;
> +}
> +
> struct sh7372_pm_domain sh7372_a3sg = {
> .bit_shift = 13,
> };
>
> -#endif /* CONFIG_PM */
> +#else /* !CONFIG_PM */
> +
> +static inline void sh7372_a3sp_init(void) {}
> +
> +#endif /* !CONFIG_PM */
>
> #if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE)
> static int sh7372_do_idle_core_standby(unsigned long unused)
> @@ -470,10 +482,7 @@ void __init sh7372_pm_init(void)
> /* do not convert A3SM, A3SP, A3SG, A4R power down into A4S */
> __raw_writel(0, PDNSEL);
>
> - /* serial consoles make use of SCIF hardware located in A3SP,
> - * keep such power domain on if "no_console_suspend" is set.
> - */
> - sh7372_a3sp.stay_on = !console_suspend_enabled;
> + sh7372_a3sp_init();
>
> sh7372_suspend_init();
> sh7372_cpuidle_init();
>
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply
* Re: [PATCH 1/3] sh: sh7724: use runtime PM implementation, common with arm/mach-shmobile
From: Paul Mundt @ 2011-11-17 5:39 UTC (permalink / raw)
To: linux-sh
In-Reply-To: <Pine.LNX.4.64.1111161306190.1100@axis700.grange>
On Wed, Nov 16, 2011 at 01:35:42PM +0100, Guennadi Liakhovetski wrote:
> @@ -195,61 +198,64 @@ static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
> fclkbcr_parent, ARRAY_SIZE(fclkbcr_parent), 6, 2),
> };
>
> +#define MSTP(_parent, _reg, _bit, _flags) \
> + SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
> +
> static struct clk mstp_clks[HWBLK_NR] = {
> - SH_HWBLK_CLK(HWBLK_TLB, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
..
> + [HWBLK_TLB] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT),
No, I'm not interested in wrappers to wrappers. Just use SH_CLK_MSTP32
directly. If you're adhering to 80 character lines you can just do some
additional formatting where necessary.
Other then that it's a good start. I assume once these are tidied up
you'll be sending patches to strip out the hwblk stuff as well as the
shmobile runtime PM implementation completely?
^ permalink raw reply
* Re: [PATCH 2/2 v4] net/smsc911x: Add regulator support
From: Mike Frysinger @ 2011-11-17 5:07 UTC (permalink / raw)
To: Robert MARKLUND
Cc: netdev@vger.kernel.org, Steve Glendinning, Mathieu Poirier,
Paul Mundt, linux-sh@vger.kernel.org, Sascha Hauer, Tony Lindgren,
linux-omap@vger.kernel.org,
uclinux-dist-devel@blackfin.uclinux.org, Linus Walleij
In-Reply-To: <2B1D156D95AE9B4EAD379CB9E465FE7324AECE3650@EXDCVYMBSTM005.EQ1STM.local>
[-- Attachment #1: Type: Text/Plain, Size: 521 bytes --]
On Wednesday 16 November 2011 07:59:41 Robert MARKLUND wrote:
> From: Mike Frysinger [mailto:vapier@gentoo.org]
> > On Monday 31 October 2011 08:38:39 Robert Marklund wrote:
> > > ChangeLog v3->v4:
> > > - Remove dual prints and old comment on Mike's request.
> > > - Split the request_free fucntion on Mike and Sascha request.
> >
> > would be nice if the enable/disable were split as well ...
>
> I interpret this as "nice if", if it's a "must be" then ill change it.
i would prefer it were split
-mike
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH] PM Sleep: Don't extend wakeup paths to devices with
From: Greg KH @ 2011-11-16 23:52 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: Linux PM list, Linux-sh list, LKML, Magnus Damm
In-Reply-To: <201111162321.58572.rjw@sisk.pl>
On Wed, Nov 16, 2011 at 11:21:58PM +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rjw@sisk.pl>
>
> Commit 4ca46ff3e0d8c234cb40ebb6457653b59584426c (PM / Sleep: Mark
> devices involved in wakeup signaling during suspend) introduced
> the power.wakeup_path field in struct dev_pm_info to mark devices
> whose children are enabled to wake up the system from sleep states,
> so that power domains containing the parents that provide their
> children with wakeup power and/or relay their wakeup signals are not
> turned off. Unfortunately, that introduced a PM regression on SH7372
> whose power consumption in the system "memory sleep" state increased
> as a result of it, because it prevented the power domain containing
> the I2C controller from being turned off when some children of that
> controller were enabled to wake up the system, although the
> controller was not necessary for them to signal wakeup.
>
> To fix this issue use the observation that devices whose
> power.ignore_children flag is set for runtime PM should be treated
> analogously during system suspend. Namely, they shouldn't be
> included in wakeup paths going through their children. Since the
> SH7372 I2C controller's power.ignore_children flag is set, doing so
> will restore the previous behavior of that SOC.
>
> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
^ permalink raw reply
* Re: sh7372 compile breakage in current -next
From: Rafael J. Wysocki @ 2011-11-16 22:42 UTC (permalink / raw)
To: linux-sh
In-Reply-To: <201111162325.51517.rjw@sisk.pl>
On Wednesday, November 16, 2011, Rafael J. Wysocki wrote:
> On Wednesday, November 16, 2011, Rafael J. Wysocki wrote:
> > On Wednesday, November 16, 2011, Guennadi Liakhovetski wrote:
> > > arch/arm/mach-shmobile/pm-sh7372.c: In function 'sh7372_pm_init':
> > > arch/arm/mach-shmobile/pm-sh7372.c:476: error: 'sh7372_a3sp' undeclared (first use in this function)
> > > arch/arm/mach-shmobile/pm-sh7372.c:476: error: (Each undeclared identifier is reported only once
> > > arch/arm/mach-shmobile/pm-sh7372.c:476: error: for each function it appears in.)
> > > make[2]: *** [arch/arm/mach-shmobile/pm-sh7372.o] Error 1
> >
> > OK, I'll have a look at that.
> >
> > What's the .config you used?
>
> Do you have CONFIG_PM unset, perchance?
Well, I'm quite sure you do. The appended patch should help, then.
Thanks,
Rafael
---
From: Rafael J. Wysocki <rjw@sisk.pl>
Subject: PM / shmobile: Fix build of sh7372_pm_init() for CONFIG_PM unset
Fix build regression introduced by commit 056879d2f244001b2888cdc8cf
(ARM: mach-shmobile: sh7372 A3SP no_suspend_console fix) by moving
the intialization of the A3SP domain to a separate function and
providing an empty definition of it for CONFIG_PM unset.
Reported-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
arch/arm/mach-shmobile/pm-sh7372.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
Index: linux/arch/arm/mach-shmobile/pm-sh7372.c
=================================--- linux.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux/arch/arm/mach-shmobile/pm-sh7372.c
@@ -232,11 +232,23 @@ struct sh7372_pm_domain sh7372_a3sp = {
.no_debug = true,
};
+static void sh7372_a3sp_init(void)
+{
+ /* serial consoles make use of SCIF hardware located in A3SP,
+ * keep such power domain on if "no_console_suspend" is set.
+ */
+ sh7372_a3sp.stay_on = !console_suspend_enabled;
+}
+
struct sh7372_pm_domain sh7372_a3sg = {
.bit_shift = 13,
};
-#endif /* CONFIG_PM */
+#else /* !CONFIG_PM */
+
+static inline void sh7372_a3sp_init(void) {}
+
+#endif /* !CONFIG_PM */
#if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE)
static int sh7372_do_idle_core_standby(unsigned long unused)
@@ -470,10 +482,7 @@ void __init sh7372_pm_init(void)
/* do not convert A3SM, A3SP, A3SG, A4R power down into A4S */
__raw_writel(0, PDNSEL);
- /* serial consoles make use of SCIF hardware located in A3SP,
- * keep such power domain on if "no_console_suspend" is set.
- */
- sh7372_a3sp.stay_on = !console_suspend_enabled;
+ sh7372_a3sp_init();
sh7372_suspend_init();
sh7372_cpuidle_init();
^ permalink raw reply
* Re: sh7372 compile breakage in current -next
From: Rafael J. Wysocki @ 2011-11-16 22:25 UTC (permalink / raw)
To: linux-sh
On Wednesday, November 16, 2011, Rafael J. Wysocki wrote:
> On Wednesday, November 16, 2011, Guennadi Liakhovetski wrote:
> > arch/arm/mach-shmobile/pm-sh7372.c: In function 'sh7372_pm_init':
> > arch/arm/mach-shmobile/pm-sh7372.c:476: error: 'sh7372_a3sp' undeclared (first use in this function)
> > arch/arm/mach-shmobile/pm-sh7372.c:476: error: (Each undeclared identifier is reported only once
> > arch/arm/mach-shmobile/pm-sh7372.c:476: error: for each function it appears in.)
> > make[2]: *** [arch/arm/mach-shmobile/pm-sh7372.o] Error 1
>
> OK, I'll have a look at that.
>
> What's the .config you used?
Do you have CONFIG_PM unset, perchance?
Rafael
^ permalink raw reply
* [PATCH] PM Sleep: Don't extend wakeup paths to devices with ignore_children set
From: Rafael J. Wysocki @ 2011-11-16 22:21 UTC (permalink / raw)
To: Linux PM list; +Cc: Linux-sh list, LKML, Magnus Damm, Greg Kroah-Hartman
From: Rafael J. Wysocki <rjw@sisk.pl>
Commit 4ca46ff3e0d8c234cb40ebb6457653b59584426c (PM / Sleep: Mark
devices involved in wakeup signaling during suspend) introduced
the power.wakeup_path field in struct dev_pm_info to mark devices
whose children are enabled to wake up the system from sleep states,
so that power domains containing the parents that provide their
children with wakeup power and/or relay their wakeup signals are not
turned off. Unfortunately, that introduced a PM regression on SH7372
whose power consumption in the system "memory sleep" state increased
as a result of it, because it prevented the power domain containing
the I2C controller from being turned off when some children of that
controller were enabled to wake up the system, although the
controller was not necessary for them to signal wakeup.
To fix this issue use the observation that devices whose
power.ignore_children flag is set for runtime PM should be treated
analogously during system suspend. Namely, they shouldn't be
included in wakeup paths going through their children. Since the
SH7372 I2C controller's power.ignore_children flag is set, doing so
will restore the previous behavior of that SOC.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/base/power/main.c | 3 ++-
include/linux/device.h | 5 +++++
include/linux/pm.h | 2 +-
include/linux/pm_runtime.h | 6 ------
4 files changed, 8 insertions(+), 8 deletions(-)
Index: linux/include/linux/pm.h
=================================--- linux.orig/include/linux/pm.h
+++ linux/include/linux/pm.h
@@ -447,6 +447,7 @@ struct dev_pm_info {
unsigned int async_suspend:1;
bool is_prepared:1; /* Owned by the PM core */
bool is_suspended:1; /* Ditto */
+ bool ignore_children:1;
spinlock_t lock;
#ifdef CONFIG_PM_SLEEP
struct list_head entry;
@@ -464,7 +465,6 @@ struct dev_pm_info {
atomic_t usage_count;
atomic_t child_count;
unsigned int disable_depth:3;
- unsigned int ignore_children:1;
unsigned int idle_notification:1;
unsigned int request_pending:1;
unsigned int deferred_resume:1;
Index: linux/drivers/base/power/main.c
=================================--- linux.orig/drivers/base/power/main.c
+++ linux/drivers/base/power/main.c
@@ -920,7 +920,8 @@ static int __device_suspend(struct devic
End:
if (!error) {
dev->power.is_suspended = true;
- if (dev->power.wakeup_path && dev->parent)
+ if (dev->power.wakeup_path
+ && dev->parent && !dev->parent->power.ignore_children)
dev->parent->power.wakeup_path = true;
}
Index: linux/include/linux/pm_runtime.h
=================================--- linux.orig/include/linux/pm_runtime.h
+++ linux/include/linux/pm_runtime.h
@@ -54,11 +54,6 @@ static inline bool pm_children_suspended
|| !atomic_read(&dev->power.child_count);
}
-static inline void pm_suspend_ignore_children(struct device *dev, bool enable)
-{
- dev->power.ignore_children = enable;
-}
-
static inline void pm_runtime_get_noresume(struct device *dev)
{
atomic_inc(&dev->power.usage_count);
@@ -132,7 +127,6 @@ static inline void pm_runtime_allow(stru
static inline void pm_runtime_forbid(struct device *dev) {}
static inline bool pm_children_suspended(struct device *dev) { return false; }
-static inline void pm_suspend_ignore_children(struct device *dev, bool en) {}
static inline void pm_runtime_get_noresume(struct device *dev) {}
static inline void pm_runtime_put_noidle(struct device *dev) {}
static inline bool device_run_wake(struct device *dev) { return false; }
Index: linux/include/linux/device.h
=================================--- linux.orig/include/linux/device.h
+++ linux/include/linux/device.h
@@ -682,6 +682,11 @@ static inline bool device_async_suspend_
return !!dev->power.async_suspend;
}
+static inline void pm_suspend_ignore_children(struct device *dev, bool enable)
+{
+ dev->power.ignore_children = enable;
+}
+
static inline void device_lock(struct device *dev)
{
mutex_lock(&dev->mutex);
^ permalink raw reply
* Re: [PATCH 3/3] ARM: mach-shmobile: sh7372 A4R support (v4)
From: Guennadi Liakhovetski @ 2011-11-16 21:05 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: Magnus Damm, Linux-sh list, Linux PM list, Linux Kernel
In-Reply-To: <201111030017.00780.rjw@sisk.pl>
Hi all
3.2-rc2 halts on ap4evb after
[ 0.085937] NetWinder Floating Point Emulator V0.97 (double precision)
[ 0.085937] msgmni has been set to 246
[ 0.085937] io scheduler noop registered (default)
(normally the following would be printed out afterwards:
[ 0.398437] sh-mobile-hdmi sh-mobile-hdmi: Detected HDMI controller 0x0:0x0
[ 0.406250] sh_mobile_meram sh_mobile_meram.0: sh_mobile_meram initialized.
[ 0.421875] Console: switching to colour frame buffer device 160x45
[ 0.429687] graphics fb0: registered sh_mobile_lcdc_fb/mainlcd as 1280x720 16bpp.
[ 0.437500] graphics fb1: registered sh_mobile_lcdc_fb/mainlcd as 544x961 16bpp.
) and git bisect pointed out at this commit as a culprit. Indeed,
reverting it fixes the hanger. I'll send my .config off-list.
Thanks
Guennadi
On Thu, 3 Nov 2011, Rafael J. Wysocki wrote:
> On Wednesday, November 02, 2011, Magnus Damm wrote:
> > On Wed, Nov 2, 2011 at 11:38 AM, Guennadi Liakhovetski
> > <g.liakhovetski@gmx.de> wrote:
> > > On Thu, 20 Oct 2011, Rafael J. Wysocki wrote:
> > >
> > >> From: Magnus Damm <damm@opensource.se>
> > >>
> > >> This change adds support for the sh7372 A4R power domain.
> > >
> > > This version still breaks I2C (#0) on mackerel. Tested with your
> > > sh7372-test branch of Oct 18th plus these four patches:
> > >
> > > 6b29305a PM / Domains: Add default power off governor function (v2)
> > > 3d578ae PM / Domains: Add device stop governor function (v2)
> > > 6c2cd02 ARM: mach-shmobile: sh7372 A4R support (v4)
> > > 9da11f4 ARM: mach-shmobile: sh7372 A3SP support (v4)
> >
> > Exactly how does it break IIC0?
>
> It causes some initialization issues to happen. I get the following
> messages on every boot:
>
> i2c-sh_mobile i2c-sh_mobile.0: Transfer request timed out
> i2c-sh_mobile i2c-sh_mobile.0: Polling timed out
>
> three times in a row (there's a delay too).
>
> The A4R patch is the source of that.
>
> > Does the same happen with the code base for upcoming 3.2-rc1 from
> > latest linux git?
>
> Yes, it does, AFAICT.
>
> Thanks,
> Rafael
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sh" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply
* RE: [PATCH 2/2 v4] net/smsc911x: Add regulator support
From: Robert MARKLUND @ 2011-11-16 12:59 UTC (permalink / raw)
To: Mike Frysinger
Cc: netdev@vger.kernel.org, Steve Glendinning, Mathieu Poirier,
Paul Mundt, linux-sh@vger.kernel.org, Sascha Hauer, Tony Lindgren,
linux-omap@vger.kernel.org,
uclinux-dist-devel@blackfin.uclinux.org, Linus Walleij
In-Reply-To: <201110311421.18653.vapier@gentoo.org>
DQo+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+IEZyb206IE1pa2UgRnJ5c2luZ2VyIFtt
YWlsdG86dmFwaWVyQGdlbnRvby5vcmddDQo+IFNlbnQ6IGRlbiAzMSBva3RvYmVyIDIwMTEgMTk6
MjENCj4gVG86IFJvYmVydCBNQVJLTFVORA0KPiBDYzogbmV0ZGV2QHZnZXIua2VybmVsLm9yZzsg
U3RldmUgR2xlbmRpbm5pbmc7IE1hdGhpZXUgUG9pcmllcjsgUGF1bCBNdW5kdDsgbGludXgtc2hA
dmdlci5rZXJuZWwub3JnOw0KPiBTYXNjaGEgSGF1ZXI7IFRvbnkgTGluZGdyZW47IGxpbnV4LW9t
YXBAdmdlci5rZXJuZWwub3JnOyB1Y2xpbnV4LWRpc3QtZGV2ZWxAYmxhY2tmaW4udWNsaW51eC5v
cmc7DQo+IExpbnVzIFdhbGxlaWoNCj4gU3ViamVjdDogUmU6IFtQQVRDSCAyLzIgdjRdIG5ldC9z
bXNjOTExeDogQWRkIHJlZ3VsYXRvciBzdXBwb3J0DQo+IA0KPiBPbiBNb25kYXkgMzEgT2N0b2Jl
ciAyMDExIDA4OjM4OjM5IFJvYmVydCBNYXJrbHVuZCB3cm90ZToNCj4gPiBDaGFuZ2VMb2cgdjMt
PnY0Og0KPiA+IC0gUmVtb3ZlIGR1YWwgcHJpbnRzIGFuZCBvbGQgY29tbWVudCBvbiBNaWtlJ3Mg
cmVxdWVzdC4NCj4gPiAtIFNwbGl0IHRoZSByZXF1ZXN0X2ZyZWUgZnVjbnRpb24gb24gTWlrZSBh
bmQgU2FzY2hhIHJlcXVlc3QuDQo+IA0KPiB3b3VsZCBiZSBuaWNlIGlmIHRoZSBlbmFibGUvZGlz
YWJsZSB3ZXJlIHNwbGl0IGFzIHdlbGwgLi4uDQoNCkkgaW50ZXJwcmV0IHRoaXMgYXMgIm5pY2Ug
aWYiLCBpZiBpdCdzIGEgIm11c3QgYmUiIHRoZW4gaWxsIGNoYW5nZSBpdC4NCg0KPiANCj4gPiAg
CWlvdW5tYXAocGRhdGEtPmlvYWRkcik7DQo+ID4NCj4gPiArCSh2b2lkKXNtc2M5MTF4X2VuYWJs
ZV9kaXNhYmxlX3Jlc291cmNlcyhwZGV2LCBmYWxzZSk7DQo+IA0KPiBpIGRvbid0IHRoaW5rIHRo
ZSAodm9pZCkgY2FzdCBpcyBuZWNlc3NhcnkNCg0KSSBsaWtlIHRlbGxpbmcgdGhlIHJlYWRlciBv
ZiB0aGUgY29kZSB0aGF0IEkgaWdub3JlIHRoZSByZXR1cm4gdmFsdWUsIA0KSSBkaWQgbm90IGp1
c3QgZm9yZ2V0IGl0Lg0KDQovUg0KDQo+IA0KPiBvdGhlcndpc2UgbG9va3MgZmluZQ0KPiAtbWlr
ZQ0K
^ permalink raw reply
* [PATCH 3/3] sh: sh7723: use runtime PM implementation, common with
From: Guennadi Liakhovetski @ 2011-11-16 12:35 UTC (permalink / raw)
To: linux-sh
Switch sh7723 to a runtime PM implementation, common with ARM-based
sh-mobile platforms.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
arch/sh/include/asm/hwblk.h | 4 +-
arch/sh/kernel/cpu/Makefile | 2 +-
arch/sh/kernel/cpu/sh4a/Makefile | 2 +-
arch/sh/kernel/cpu/sh4a/clock-sh7723.c | 171 ++++++++++++++------------------
arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c | 117 ----------------------
arch/sh/kernel/cpu/shmobile/Makefile | 2 +-
drivers/sh/Makefile | 3 +-
7 files changed, 84 insertions(+), 217 deletions(-)
delete mode 100644 arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c
diff --git a/arch/sh/include/asm/hwblk.h b/arch/sh/include/asm/hwblk.h
index d6b7dea..e29461b 100644
--- a/arch/sh/include/asm/hwblk.h
+++ b/arch/sh/include/asm/hwblk.h
@@ -44,7 +44,9 @@ struct hwblk_info {
int nr_hwblks;
};
-#if !defined(CONFIG_CPU_SUBTYPE_SH7724) && !defined(CONFIG_CPU_SUBTYPE_SH7722)
+#if !defined(CONFIG_CPU_SUBTYPE_SH7722) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7723) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7724)
/* Should be defined by processor-specific code */
int arch_hwblk_init(void);
int arch_hwblk_sleep_mode(void);
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index b1f515c..5366fdf 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -19,6 +19,6 @@ obj-$(CONFIG_SH_ADC) += adc.o
obj-$(CONFIG_SH_CLK_CPG_LEGACY) += clock-cpg.o
obj-y += irq/ init.o clock.o fpu.o proc.o
-ifneq ($(CONFIG_CPU_SUBTYPE_SH7724)$(CONFIG_CPU_SUBTYPE_SH7722),y)
+ifneq ($(CONFIG_CPU_SUBTYPE_SH7722)$(CONFIG_CPU_SUBTYPE_SH7723)$(CONFIG_CPU_SUBTYPE_SH7724),y)
obj-y += hwblk.o
endif
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index 9f28773..0b22d10 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -28,7 +28,7 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o
clock-$(CONFIG_CPU_SUBTYPE_SH7786) := clock-sh7786.o
clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7723) := clock-sh7723.o hwblk-sh7723.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7723) := clock-sh7723.o
clock-$(CONFIG_CPU_SUBTYPE_SH7724) := clock-sh7724.o
clock-$(CONFIG_CPU_SUBTYPE_SH7366) := clock-sh7366.o
clock-$(CONFIG_CPU_SUBTYPE_SHX3) := clock-shx3.o
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
index 3cc3827..358c7cc 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
@@ -23,8 +23,8 @@
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
+#include <linux/sh_clk.h>
#include <asm/clock.h>
-#include <asm/hwblk.h>
#include <cpu/sh7723.h>
/* SH7723 registers */
@@ -34,6 +34,9 @@
#define SCLKBCR 0xa415000c
#define IRDACLKCR 0xa4150018
#define PLLCR 0xa4150024
+#define MSTPCR0 0xa4150030
+#define MSTPCR1 0xa4150034
+#define MSTPCR2 0xa4150038
#define DLLFRQ 0xa4150050
/* Fixed 32 KHz root clock for RTC and Power Management purposes */
@@ -147,57 +150,60 @@ struct clk div6_clks[DIV6_NR] = {
[DIV6_V] = SH_CLK_DIV6(&pll_clk, VCLKCR, 0),
};
+#define MSTP(_parent, _reg, _bit, _flags) \
+ SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
+
static struct clk mstp_clks[] = {
/* See page 60 of Datasheet V1.0: Overview -> Block Diagram */
- SH_HWBLK_CLK(HWBLK_TLB, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_IC, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_OC, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_L2C, &div4_clks[DIV4_SH], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_ILMEM, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_FPU, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_INTC, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_DMAC0, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_SHYWAY, &div4_clks[DIV4_SH], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_HUDI, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_UBC, &div4_clks[DIV4_I], 0),
- SH_HWBLK_CLK(HWBLK_TMU0, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_CMT, &r_clk, 0),
- SH_HWBLK_CLK(HWBLK_RWDT, &r_clk, 0),
- SH_HWBLK_CLK(HWBLK_DMAC1, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_TMU1, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_FLCTL, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_SCIF0, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_SCIF1, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_SCIF2, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_SCIF3, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_SCIF4, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_SCIF5, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_MSIOF0, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_MSIOF1, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_MERAM, &div4_clks[DIV4_SH], 0),
-
- SH_HWBLK_CLK(HWBLK_IIC, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_RTC, &r_clk, 0),
-
- SH_HWBLK_CLK(HWBLK_ATAPI, &div4_clks[DIV4_SH], 0),
- SH_HWBLK_CLK(HWBLK_ADC, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_TPU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_IRDA, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_TSIF, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_ICB, &div4_clks[DIV4_B], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_SDHI0, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_SDHI1, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_KEYSC, &r_clk, 0),
- SH_HWBLK_CLK(HWBLK_USB, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_2DG, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_SIU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_VEU2H1, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_VOU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_BEU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_CEU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_VEU2H0, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_VPU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_LCDC, &div4_clks[DIV4_B], 0),
+ [HWBLK_TLB] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT),
+ [HWBLK_IC] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 30, CLK_ENABLE_ON_INIT),
+ [HWBLK_OC] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 29, CLK_ENABLE_ON_INIT),
+ [HWBLK_L2C] = MSTP(&div4_clks[DIV4_SH], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
+ [HWBLK_ILMEM] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 27, CLK_ENABLE_ON_INIT),
+ [HWBLK_FPU] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 24, CLK_ENABLE_ON_INIT),
+ [HWBLK_INTC] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 22, CLK_ENABLE_ON_INIT),
+ [HWBLK_DMAC0] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 21, 0),
+ [HWBLK_SHYWAY] = MSTP(&div4_clks[DIV4_SH], MSTPCR0, 20, CLK_ENABLE_ON_INIT),
+ [HWBLK_HUDI] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 19, 0),
+ [HWBLK_UBC] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 17, 0),
+ [HWBLK_TMU0] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
+ [HWBLK_CMT] = MSTP(&r_clk, MSTPCR0, 14, 0),
+ [HWBLK_RWDT] = MSTP(&r_clk, MSTPCR0, 13, 0),
+ [HWBLK_DMAC1] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 12, 0),
+ [HWBLK_TMU1] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 11, 0),
+ [HWBLK_FLCTL] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
+ [HWBLK_SCIF0] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 9, 0),
+ [HWBLK_SCIF1] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 8, 0),
+ [HWBLK_SCIF2] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
+ [HWBLK_SCIF3] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 6, 0),
+ [HWBLK_SCIF4] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 5, 0),
+ [HWBLK_SCIF5] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 4, 0),
+ [HWBLK_MSIOF0] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 2, 0),
+ [HWBLK_MSIOF1] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 1, 0),
+ [HWBLK_MERAM] = MSTP(&div4_clks[DIV4_SH], MSTPCR0, 0, 0),
+
+ [HWBLK_IIC] = MSTP(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
+ [HWBLK_RTC] = MSTP(&r_clk, MSTPCR1, 8, 0),
+
+ [HWBLK_ATAPI] = MSTP(&div4_clks[DIV4_SH], MSTPCR2, 28, 0),
+ [HWBLK_ADC] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 27, 0),
+ [HWBLK_TPU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 25, 0),
+ [HWBLK_IRDA] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 24, 0),
+ [HWBLK_TSIF] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 22, 0),
+ [HWBLK_ICB] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 21, CLK_ENABLE_ON_INIT),
+ [HWBLK_SDHI0] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 18, 0),
+ [HWBLK_SDHI1] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 17, 0),
+ [HWBLK_KEYSC] = MSTP(&r_clk, MSTPCR2, 14, 0),
+ [HWBLK_USB] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 11, 0),
+ [HWBLK_2DG] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 10, 0),
+ [HWBLK_SIU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 8, 0),
+ [HWBLK_VEU2H1] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 6, 0),
+ [HWBLK_VOU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 5, 0),
+ [HWBLK_BEU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 4, 0),
+ [HWBLK_CEU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 3, 0),
+ [HWBLK_VEU2H0] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 2, 0),
+ [HWBLK_VPU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 1, 0),
+ [HWBLK_LCDC] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 0, 0),
};
static struct clk_lookup lookups[] = {
@@ -229,7 +235,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("ilmem0", &mstp_clks[HWBLK_ILMEM]),
CLKDEV_CON_ID("fpu0", &mstp_clks[HWBLK_FPU]),
CLKDEV_CON_ID("intc0", &mstp_clks[HWBLK_INTC]),
- CLKDEV_CON_ID("dmac0", &mstp_clks[HWBLK_DMAC0]),
+ CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[HWBLK_DMAC0]),
CLKDEV_CON_ID("sh0", &mstp_clks[HWBLK_SHYWAY]),
CLKDEV_CON_ID("hudi0", &mstp_clks[HWBLK_HUDI]),
CLKDEV_CON_ID("ubc0", &mstp_clks[HWBLK_UBC]),
@@ -250,8 +256,8 @@ static struct clk_lookup lookups[] = {
.clk = &mstp_clks[HWBLK_TMU0],
},
CLKDEV_CON_ID("cmt_fck", &mstp_clks[HWBLK_CMT]),
- CLKDEV_CON_ID("rwdt0", &mstp_clks[HWBLK_RWDT]),
- CLKDEV_CON_ID("dmac1", &mstp_clks[HWBLK_DMAC1]),
+ CLKDEV_DEV_ID("sh-wdt.0", &mstp_clks[HWBLK_RWDT]),
+ CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[HWBLK_DMAC1]),
{
/* TMU3 */
.dev_id = "sh_tmu.3",
@@ -269,40 +275,15 @@ static struct clk_lookup lookups[] = {
.clk = &mstp_clks[HWBLK_TMU1],
},
CLKDEV_CON_ID("flctl0", &mstp_clks[HWBLK_FLCTL]),
- {
- /* SCIF0 */
- .dev_id = "sh-sci.0",
- .con_id = "sci_fck",
- .clk = &mstp_clks[HWBLK_SCIF0],
- }, {
- /* SCIF1 */
- .dev_id = "sh-sci.1",
- .con_id = "sci_fck",
- .clk = &mstp_clks[HWBLK_SCIF1],
- }, {
- /* SCIF2 */
- .dev_id = "sh-sci.2",
- .con_id = "sci_fck",
- .clk = &mstp_clks[HWBLK_SCIF2],
- }, {
- /* SCIF3 */
- .dev_id = "sh-sci.3",
- .con_id = "sci_fck",
- .clk = &mstp_clks[HWBLK_SCIF3],
- }, {
- /* SCIF4 */
- .dev_id = "sh-sci.4",
- .con_id = "sci_fck",
- .clk = &mstp_clks[HWBLK_SCIF4],
- }, {
- /* SCIF5 */
- .dev_id = "sh-sci.5",
- .con_id = "sci_fck",
- .clk = &mstp_clks[HWBLK_SCIF5],
- },
- CLKDEV_CON_ID("msiof0", &mstp_clks[HWBLK_MSIOF0]),
- CLKDEV_CON_ID("msiof1", &mstp_clks[HWBLK_MSIOF1]),
- CLKDEV_CON_ID("meram0", &mstp_clks[HWBLK_MERAM]),
+ CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
+ CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
+ CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
+ CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
+ CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[HWBLK_SCIF4]),
+ CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[HWBLK_SCIF5]),
+ CLKDEV_DEV_ID("spi_sh_msiof.0", &mstp_clks[HWBLK_MSIOF0]),
+ CLKDEV_DEV_ID("spi_sh_msiof.1", &mstp_clks[HWBLK_MSIOF1]),
+ CLKDEV_DEV_ID("sh_mobile_meram.0", &mstp_clks[HWBLK_MERAM]),
CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC]),
CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),
CLKDEV_CON_ID("atapi0", &mstp_clks[HWBLK_ATAPI]),
@@ -311,19 +292,19 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("irda0", &mstp_clks[HWBLK_IRDA]),
CLKDEV_CON_ID("tsif0", &mstp_clks[HWBLK_TSIF]),
CLKDEV_CON_ID("icb0", &mstp_clks[HWBLK_ICB]),
- CLKDEV_CON_ID("sdhi0", &mstp_clks[HWBLK_SDHI0]),
- CLKDEV_CON_ID("sdhi1", &mstp_clks[HWBLK_SDHI1]),
- CLKDEV_CON_ID("keysc0", &mstp_clks[HWBLK_KEYSC]),
+ CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[HWBLK_SDHI0]),
+ CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[HWBLK_SDHI1]),
+ CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[HWBLK_KEYSC]),
CLKDEV_CON_ID("usb0", &mstp_clks[HWBLK_USB]),
CLKDEV_CON_ID("2dg0", &mstp_clks[HWBLK_2DG]),
- CLKDEV_CON_ID("siu0", &mstp_clks[HWBLK_SIU]),
+ CLKDEV_DEV_ID("siu-pcm-audio", &mstp_clks[HWBLK_SIU]),
CLKDEV_CON_ID("veu1", &mstp_clks[HWBLK_VEU2H1]),
- CLKDEV_CON_ID("vou0", &mstp_clks[HWBLK_VOU]),
+ CLKDEV_DEV_ID("sh-vou.0", &mstp_clks[HWBLK_VOU]),
CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU]),
- CLKDEV_CON_ID("ceu0", &mstp_clks[HWBLK_CEU]),
+ CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU]),
CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU2H0]),
CLKDEV_CON_ID("vpu0", &mstp_clks[HWBLK_VPU]),
- CLKDEV_CON_ID("lcdc0", &mstp_clks[HWBLK_LCDC]),
+ CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]),
};
int __init arch_clk_init(void)
@@ -356,7 +337,7 @@ int __init arch_clk_init(void)
ret = sh_clk_div6_register(div6_clks, DIV6_NR);
if (!ret)
- ret = sh_hwblk_clk_register(mstp_clks, HWBLK_NR);
+ ret = sh_clk_mstp32_register(mstp_clks, HWBLK_NR);
return ret;
}
diff --git a/arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c b/arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c
deleted file mode 100644
index a7f4684..0000000
--- a/arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c
- *
- * SH7723 hardware block support
- *
- * Copyright (C) 2009 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <asm/suspend.h>
-#include <asm/hwblk.h>
-#include <cpu/sh7723.h>
-
-/* SH7723 registers */
-#define MSTPCR0 0xa4150030
-#define MSTPCR1 0xa4150034
-#define MSTPCR2 0xa4150038
-
-/* SH7723 Power Domains */
-enum { CORE_AREA, SUB_AREA, CORE_AREA_BM };
-static struct hwblk_area sh7723_hwblk_area[] = {
- [CORE_AREA] = HWBLK_AREA(0, 0),
- [CORE_AREA_BM] = HWBLK_AREA(HWBLK_AREA_FLAG_PARENT, CORE_AREA),
- [SUB_AREA] = HWBLK_AREA(0, 0),
-};
-
-/* Table mapping HWBLK to Module Stop Bit and Power Domain */
-static struct hwblk sh7723_hwblk[HWBLK_NR] = {
- [HWBLK_TLB] = HWBLK(MSTPCR0, 31, CORE_AREA),
- [HWBLK_IC] = HWBLK(MSTPCR0, 30, CORE_AREA),
- [HWBLK_OC] = HWBLK(MSTPCR0, 29, CORE_AREA),
- [HWBLK_L2C] = HWBLK(MSTPCR0, 28, CORE_AREA),
- [HWBLK_ILMEM] = HWBLK(MSTPCR0, 27, CORE_AREA),
- [HWBLK_FPU] = HWBLK(MSTPCR0, 24, CORE_AREA),
- [HWBLK_INTC] = HWBLK(MSTPCR0, 22, CORE_AREA),
- [HWBLK_DMAC0] = HWBLK(MSTPCR0, 21, CORE_AREA_BM),
- [HWBLK_SHYWAY] = HWBLK(MSTPCR0, 20, CORE_AREA),
- [HWBLK_HUDI] = HWBLK(MSTPCR0, 19, CORE_AREA),
- [HWBLK_DBG] = HWBLK(MSTPCR0, 18, CORE_AREA),
- [HWBLK_UBC] = HWBLK(MSTPCR0, 17, CORE_AREA),
- [HWBLK_SUBC] = HWBLK(MSTPCR0, 16, CORE_AREA),
- [HWBLK_TMU0] = HWBLK(MSTPCR0, 15, CORE_AREA),
- [HWBLK_CMT] = HWBLK(MSTPCR0, 14, SUB_AREA),
- [HWBLK_RWDT] = HWBLK(MSTPCR0, 13, SUB_AREA),
- [HWBLK_DMAC1] = HWBLK(MSTPCR0, 12, CORE_AREA_BM),
- [HWBLK_TMU1] = HWBLK(MSTPCR0, 11, CORE_AREA),
- [HWBLK_FLCTL] = HWBLK(MSTPCR0, 10, CORE_AREA),
- [HWBLK_SCIF0] = HWBLK(MSTPCR0, 9, CORE_AREA),
- [HWBLK_SCIF1] = HWBLK(MSTPCR0, 8, CORE_AREA),
- [HWBLK_SCIF2] = HWBLK(MSTPCR0, 7, CORE_AREA),
- [HWBLK_SCIF3] = HWBLK(MSTPCR0, 6, CORE_AREA),
- [HWBLK_SCIF4] = HWBLK(MSTPCR0, 5, CORE_AREA),
- [HWBLK_SCIF5] = HWBLK(MSTPCR0, 4, CORE_AREA),
- [HWBLK_MSIOF0] = HWBLK(MSTPCR0, 2, CORE_AREA),
- [HWBLK_MSIOF1] = HWBLK(MSTPCR0, 1, CORE_AREA),
- [HWBLK_MERAM] = HWBLK(MSTPCR0, 0, CORE_AREA),
-
- [HWBLK_IIC] = HWBLK(MSTPCR1, 9, CORE_AREA),
- [HWBLK_RTC] = HWBLK(MSTPCR1, 8, SUB_AREA),
-
- [HWBLK_ATAPI] = HWBLK(MSTPCR2, 28, CORE_AREA_BM),
- [HWBLK_ADC] = HWBLK(MSTPCR2, 27, CORE_AREA),
- [HWBLK_TPU] = HWBLK(MSTPCR2, 25, CORE_AREA),
- [HWBLK_IRDA] = HWBLK(MSTPCR2, 24, CORE_AREA),
- [HWBLK_TSIF] = HWBLK(MSTPCR2, 22, CORE_AREA),
- [HWBLK_ICB] = HWBLK(MSTPCR2, 21, CORE_AREA_BM),
- [HWBLK_SDHI0] = HWBLK(MSTPCR2, 18, CORE_AREA),
- [HWBLK_SDHI1] = HWBLK(MSTPCR2, 17, CORE_AREA),
- [HWBLK_KEYSC] = HWBLK(MSTPCR2, 14, SUB_AREA),
- [HWBLK_USB] = HWBLK(MSTPCR2, 11, CORE_AREA),
- [HWBLK_2DG] = HWBLK(MSTPCR2, 10, CORE_AREA_BM),
- [HWBLK_SIU] = HWBLK(MSTPCR2, 8, CORE_AREA),
- [HWBLK_VEU2H1] = HWBLK(MSTPCR2, 6, CORE_AREA_BM),
- [HWBLK_VOU] = HWBLK(MSTPCR2, 5, CORE_AREA_BM),
- [HWBLK_BEU] = HWBLK(MSTPCR2, 4, CORE_AREA_BM),
- [HWBLK_CEU] = HWBLK(MSTPCR2, 3, CORE_AREA_BM),
- [HWBLK_VEU2H0] = HWBLK(MSTPCR2, 2, CORE_AREA_BM),
- [HWBLK_VPU] = HWBLK(MSTPCR2, 1, CORE_AREA_BM),
- [HWBLK_LCDC] = HWBLK(MSTPCR2, 0, CORE_AREA_BM),
-};
-
-static struct hwblk_info sh7723_hwblk_info = {
- .areas = sh7723_hwblk_area,
- .nr_areas = ARRAY_SIZE(sh7723_hwblk_area),
- .hwblks = sh7723_hwblk,
- .nr_hwblks = ARRAY_SIZE(sh7723_hwblk),
-};
-
-int arch_hwblk_sleep_mode(void)
-{
- if (!sh7723_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE])
- return SUSP_SH_STANDBY | SUSP_SH_SF;
-
- if (!sh7723_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE])
- return SUSP_SH_SLEEP | SUSP_SH_SF;
-
- return SUSP_SH_SLEEP;
-}
-
-int __init arch_hwblk_init(void)
-{
- return hwblk_register(&sh7723_hwblk_info);
-}
diff --git a/arch/sh/kernel/cpu/shmobile/Makefile b/arch/sh/kernel/cpu/shmobile/Makefile
index e83c9d5..7eb4502 100644
--- a/arch/sh/kernel/cpu/shmobile/Makefile
+++ b/arch/sh/kernel/cpu/shmobile/Makefile
@@ -5,6 +5,6 @@
# Power Management & Sleep mode
obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
-ifneq ($(CONFIG_CPU_SUBTYPE_SH7724)$(CONFIG_CPU_SUBTYPE_SH7722),y)
+ifneq ($(CONFIG_CPU_SUBTYPE_SH7722)$(CONFIG_CPU_SUBTYPE_SH7723)$(CONFIG_CPU_SUBTYPE_SH7724),y)
obj-$(CONFIG_PM_RUNTIME) += pm_runtime.o
endif
diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile
index ffca2b4..51f171b 100644
--- a/drivers/sh/Makefile
+++ b/drivers/sh/Makefile
@@ -15,5 +15,6 @@ obj-$(CONFIG_GENERIC_GPIO) += pfc.o
# special casing can go away.
#
obj-$(CONFIG_SUPERH)$(CONFIG_ARCH_SHMOBILE) += pm_runtime.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7724) += pm_runtime.o
obj-$(CONFIG_CPU_SUBTYPE_SH7722) += pm_runtime.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7723) += pm_runtime.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7724) += pm_runtime.o
--
1.7.2.5
^ permalink raw reply related
* [PATCH 2/3] sh: sh7722: use runtime PM implementation, common with
From: Guennadi Liakhovetski @ 2011-11-16 12:35 UTC (permalink / raw)
To: linux-sh
Switch sh7722 to a runtime PM implementation, common with ARM-based
sh-mobile platforms.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
arch/sh/include/asm/hwblk.h | 2 +-
arch/sh/kernel/cpu/Makefile | 2 +-
arch/sh/kernel/cpu/sh4a/Makefile | 2 +-
arch/sh/kernel/cpu/sh4a/clock-sh7722.c | 80 +++++++++++++-----------
arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c | 106 --------------------------------
arch/sh/kernel/cpu/shmobile/Makefile | 2 +-
drivers/sh/Makefile | 1 +
7 files changed, 48 insertions(+), 147 deletions(-)
delete mode 100644 arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c
diff --git a/arch/sh/include/asm/hwblk.h b/arch/sh/include/asm/hwblk.h
index 567c9aa..d6b7dea 100644
--- a/arch/sh/include/asm/hwblk.h
+++ b/arch/sh/include/asm/hwblk.h
@@ -44,7 +44,7 @@ struct hwblk_info {
int nr_hwblks;
};
-#if !defined(CONFIG_CPU_SUBTYPE_SH7724)
+#if !defined(CONFIG_CPU_SUBTYPE_SH7724) && !defined(CONFIG_CPU_SUBTYPE_SH7722)
/* Should be defined by processor-specific code */
int arch_hwblk_init(void);
int arch_hwblk_sleep_mode(void);
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index b937f1a..b1f515c 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -19,6 +19,6 @@ obj-$(CONFIG_SH_ADC) += adc.o
obj-$(CONFIG_SH_CLK_CPG_LEGACY) += clock-cpg.o
obj-y += irq/ init.o clock.o fpu.o proc.o
-ifneq ($(CONFIG_CPU_SUBTYPE_SH7724),y)
+ifneq ($(CONFIG_CPU_SUBTYPE_SH7724)$(CONFIG_CPU_SUBTYPE_SH7722),y)
obj-y += hwblk.o
endif
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index cb93287..9f28773 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -27,7 +27,7 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o
clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o
clock-$(CONFIG_CPU_SUBTYPE_SH7786) := clock-sh7786.o
clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o hwblk-sh7722.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o
clock-$(CONFIG_CPU_SUBTYPE_SH7723) := clock-sh7723.o hwblk-sh7723.o
clock-$(CONFIG_CPU_SUBTYPE_SH7724) := clock-sh7724.o
clock-$(CONFIG_CPU_SUBTYPE_SH7366) := clock-sh7366.o
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
index c9a4808..c0c0ae9 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
@@ -22,8 +22,8 @@
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/clkdev.h>
+#include <linux/sh_clk.h>
#include <asm/clock.h>
-#include <asm/hwblk.h>
#include <cpu/sh7722.h>
/* SH7722 registers */
@@ -33,6 +33,9 @@
#define SCLKBCR 0xa415000c
#define IRDACLKCR 0xa4150018
#define PLLCR 0xa4150024
+#define MSTPCR0 0xa4150030
+#define MSTPCR1 0xa4150034
+#define MSTPCR2 0xa4150038
#define DLLFRQ 0xa4150050
/* Fixed 32 KHz root clock for RTC and Power Management purposes */
@@ -147,32 +150,35 @@ struct clk div6_clks[DIV6_NR] = {
[DIV6_V] = SH_CLK_DIV6(&pll_clk, VCLKCR, 0),
};
+#define MSTP(_parent, _reg, _bit, _flags) \
+ SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
+
static struct clk mstp_clks[HWBLK_NR] = {
- SH_HWBLK_CLK(HWBLK_URAM, &div4_clks[DIV4_U], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_XYMEM, &div4_clks[DIV4_B], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_TMU, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_CMT, &r_clk, 0),
- SH_HWBLK_CLK(HWBLK_RWDT, &r_clk, 0),
- SH_HWBLK_CLK(HWBLK_FLCTL, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_SCIF0, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_SCIF1, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_SCIF2, &div4_clks[DIV4_P], 0),
-
- SH_HWBLK_CLK(HWBLK_IIC, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_RTC, &r_clk, 0),
-
- SH_HWBLK_CLK(HWBLK_SDHI, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_KEYSC, &r_clk, 0),
- SH_HWBLK_CLK(HWBLK_USBF, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_2DG, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_SIU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_VOU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_JPU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_BEU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_CEU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_VEU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_VPU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_LCDC, &div4_clks[DIV4_P], 0),
+ [HWBLK_URAM] = MSTP(&div4_clks[DIV4_U], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
+ [HWBLK_XYMEM] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
+ [HWBLK_TMU] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
+ [HWBLK_CMT] = MSTP(&r_clk, MSTPCR0, 14, 0),
+ [HWBLK_RWDT] = MSTP(&r_clk, MSTPCR0, 13, 0),
+ [HWBLK_FLCTL] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
+ [HWBLK_SCIF0] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
+ [HWBLK_SCIF1] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 6, 0),
+ [HWBLK_SCIF2] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 5, 0),
+
+ [HWBLK_IIC] = MSTP(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
+ [HWBLK_RTC] = MSTP(&r_clk, MSTPCR1, 8, 0),
+
+ [HWBLK_SDHI] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 18, 0),
+ [HWBLK_KEYSC] = MSTP(&r_clk, MSTPCR2, 14, 0),
+ [HWBLK_USBF] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 11, 0),
+ [HWBLK_2DG] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 9, 0),
+ [HWBLK_SIU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 8, 0),
+ [HWBLK_JPU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 6, 0),
+ [HWBLK_VOU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 5, 0),
+ [HWBLK_BEU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 4, 0),
+ [HWBLK_CEU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 3, 0),
+ [HWBLK_VEU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 2, 0),
+ [HWBLK_VPU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 1, 0),
+ [HWBLK_LCDC] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 0, 0),
};
static struct clk_lookup lookups[] = {
@@ -205,27 +211,27 @@ static struct clk_lookup lookups[] = {
CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[HWBLK_TMU]),
CLKDEV_CON_ID("cmt_fck", &mstp_clks[HWBLK_CMT]),
- CLKDEV_CON_ID("rwdt0", &mstp_clks[HWBLK_RWDT]),
+ CLKDEV_DEV_ID("sh-wdt.0", &mstp_clks[HWBLK_RWDT]),
CLKDEV_CON_ID("flctl0", &mstp_clks[HWBLK_FLCTL]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
+ CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
+ CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
+ CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC]),
CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),
- CLKDEV_CON_ID("sdhi0", &mstp_clks[HWBLK_SDHI]),
- CLKDEV_CON_ID("keysc0", &mstp_clks[HWBLK_KEYSC]),
+ CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[HWBLK_SDHI]),
+ CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[HWBLK_KEYSC]),
CLKDEV_CON_ID("usbf0", &mstp_clks[HWBLK_USBF]),
CLKDEV_CON_ID("2dg0", &mstp_clks[HWBLK_2DG]),
- CLKDEV_CON_ID("siu0", &mstp_clks[HWBLK_SIU]),
- CLKDEV_CON_ID("vou0", &mstp_clks[HWBLK_VOU]),
+ CLKDEV_DEV_ID("siu-pcm-audio", &mstp_clks[HWBLK_SIU]),
+ CLKDEV_DEV_ID("sh-vou.0", &mstp_clks[HWBLK_VOU]),
CLKDEV_CON_ID("jpu0", &mstp_clks[HWBLK_JPU]),
CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU]),
- CLKDEV_CON_ID("ceu0", &mstp_clks[HWBLK_CEU]),
+ CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU]),
CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU]),
CLKDEV_CON_ID("vpu0", &mstp_clks[HWBLK_VPU]),
- CLKDEV_CON_ID("lcdc0", &mstp_clks[HWBLK_LCDC]),
+ CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]),
};
int __init arch_clk_init(void)
@@ -258,7 +264,7 @@ int __init arch_clk_init(void)
ret = sh_clk_div6_register(div6_clks, DIV6_NR);
if (!ret)
- ret = sh_hwblk_clk_register(mstp_clks, HWBLK_NR);
+ ret = sh_clk_mstp32_register(mstp_clks, HWBLK_NR);
return ret;
}
diff --git a/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c b/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c
deleted file mode 100644
index a288b5d..0000000
--- a/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c
- *
- * SH7722 hardware block support
- *
- * Copyright (C) 2009 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <asm/suspend.h>
-#include <asm/hwblk.h>
-#include <cpu/sh7722.h>
-
-/* SH7722 registers */
-#define MSTPCR0 0xa4150030
-#define MSTPCR1 0xa4150034
-#define MSTPCR2 0xa4150038
-
-/* SH7722 Power Domains */
-enum { CORE_AREA, SUB_AREA, CORE_AREA_BM };
-static struct hwblk_area sh7722_hwblk_area[] = {
- [CORE_AREA] = HWBLK_AREA(0, 0),
- [CORE_AREA_BM] = HWBLK_AREA(HWBLK_AREA_FLAG_PARENT, CORE_AREA),
- [SUB_AREA] = HWBLK_AREA(0, 0),
-};
-
-/* Table mapping HWBLK to Module Stop Bit and Power Domain */
-static struct hwblk sh7722_hwblk[HWBLK_NR] = {
- [HWBLK_TLB] = HWBLK(MSTPCR0, 31, CORE_AREA),
- [HWBLK_IC] = HWBLK(MSTPCR0, 30, CORE_AREA),
- [HWBLK_OC] = HWBLK(MSTPCR0, 29, CORE_AREA),
- [HWBLK_URAM] = HWBLK(MSTPCR0, 28, CORE_AREA),
- [HWBLK_XYMEM] = HWBLK(MSTPCR0, 26, CORE_AREA),
- [HWBLK_INTC] = HWBLK(MSTPCR0, 22, CORE_AREA),
- [HWBLK_DMAC] = HWBLK(MSTPCR0, 21, CORE_AREA_BM),
- [HWBLK_SHYWAY] = HWBLK(MSTPCR0, 20, CORE_AREA),
- [HWBLK_HUDI] = HWBLK(MSTPCR0, 19, CORE_AREA),
- [HWBLK_UBC] = HWBLK(MSTPCR0, 17, CORE_AREA),
- [HWBLK_TMU] = HWBLK(MSTPCR0, 15, CORE_AREA),
- [HWBLK_CMT] = HWBLK(MSTPCR0, 14, SUB_AREA),
- [HWBLK_RWDT] = HWBLK(MSTPCR0, 13, SUB_AREA),
- [HWBLK_FLCTL] = HWBLK(MSTPCR0, 10, CORE_AREA),
- [HWBLK_SCIF0] = HWBLK(MSTPCR0, 7, CORE_AREA),
- [HWBLK_SCIF1] = HWBLK(MSTPCR0, 6, CORE_AREA),
- [HWBLK_SCIF2] = HWBLK(MSTPCR0, 5, CORE_AREA),
- [HWBLK_SIO] = HWBLK(MSTPCR0, 3, CORE_AREA),
- [HWBLK_SIOF0] = HWBLK(MSTPCR0, 2, CORE_AREA),
- [HWBLK_SIOF1] = HWBLK(MSTPCR0, 1, CORE_AREA),
-
- [HWBLK_IIC] = HWBLK(MSTPCR1, 9, CORE_AREA),
- [HWBLK_RTC] = HWBLK(MSTPCR1, 8, SUB_AREA),
-
- [HWBLK_TPU] = HWBLK(MSTPCR2, 25, CORE_AREA),
- [HWBLK_IRDA] = HWBLK(MSTPCR2, 24, CORE_AREA),
- [HWBLK_SDHI] = HWBLK(MSTPCR2, 18, CORE_AREA),
- [HWBLK_SIM] = HWBLK(MSTPCR2, 16, CORE_AREA),
- [HWBLK_KEYSC] = HWBLK(MSTPCR2, 14, SUB_AREA),
- [HWBLK_TSIF] = HWBLK(MSTPCR2, 13, SUB_AREA),
- [HWBLK_USBF] = HWBLK(MSTPCR2, 11, CORE_AREA),
- [HWBLK_2DG] = HWBLK(MSTPCR2, 9, CORE_AREA_BM),
- [HWBLK_SIU] = HWBLK(MSTPCR2, 8, CORE_AREA),
- [HWBLK_JPU] = HWBLK(MSTPCR2, 6, CORE_AREA_BM),
- [HWBLK_VOU] = HWBLK(MSTPCR2, 5, CORE_AREA_BM),
- [HWBLK_BEU] = HWBLK(MSTPCR2, 4, CORE_AREA_BM),
- [HWBLK_CEU] = HWBLK(MSTPCR2, 3, CORE_AREA_BM),
- [HWBLK_VEU] = HWBLK(MSTPCR2, 2, CORE_AREA_BM),
- [HWBLK_VPU] = HWBLK(MSTPCR2, 1, CORE_AREA_BM),
- [HWBLK_LCDC] = HWBLK(MSTPCR2, 0, CORE_AREA_BM),
-};
-
-static struct hwblk_info sh7722_hwblk_info = {
- .areas = sh7722_hwblk_area,
- .nr_areas = ARRAY_SIZE(sh7722_hwblk_area),
- .hwblks = sh7722_hwblk,
- .nr_hwblks = ARRAY_SIZE(sh7722_hwblk),
-};
-
-int arch_hwblk_sleep_mode(void)
-{
- if (!sh7722_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE])
- return SUSP_SH_STANDBY | SUSP_SH_SF;
-
- if (!sh7722_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE])
- return SUSP_SH_SLEEP | SUSP_SH_SF;
-
- return SUSP_SH_SLEEP;
-}
-
-int __init arch_hwblk_init(void)
-{
- return hwblk_register(&sh7722_hwblk_info);
-}
diff --git a/arch/sh/kernel/cpu/shmobile/Makefile b/arch/sh/kernel/cpu/shmobile/Makefile
index 2f32a03..e83c9d5 100644
--- a/arch/sh/kernel/cpu/shmobile/Makefile
+++ b/arch/sh/kernel/cpu/shmobile/Makefile
@@ -5,6 +5,6 @@
# Power Management & Sleep mode
obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
-ifneq ($(CONFIG_CPU_SUBTYPE_SH7724),y)
+ifneq ($(CONFIG_CPU_SUBTYPE_SH7724)$(CONFIG_CPU_SUBTYPE_SH7722),y)
obj-$(CONFIG_PM_RUNTIME) += pm_runtime.o
endif
diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile
index 30c2594..ffca2b4 100644
--- a/drivers/sh/Makefile
+++ b/drivers/sh/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_GENERIC_GPIO) += pfc.o
#
obj-$(CONFIG_SUPERH)$(CONFIG_ARCH_SHMOBILE) += pm_runtime.o
obj-$(CONFIG_CPU_SUBTYPE_SH7724) += pm_runtime.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7722) += pm_runtime.o
--
1.7.2.5
^ permalink raw reply related
* [PATCH 1/3] sh: sh7724: use runtime PM implementation, common with
From: Guennadi Liakhovetski @ 2011-11-16 12:35 UTC (permalink / raw)
To: linux-sh
Switch sh7724 to a runtime PM implementation, common with ARM-based
sh-mobile platforms.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
arch/sh/include/asm/hwblk.h | 5 +-
arch/sh/kernel/cpu/Makefile | 5 +-
arch/sh/kernel/cpu/sh4a/Makefile | 2 +-
arch/sh/kernel/cpu/sh4a/clock-sh7724.c | 160 ++++++++++++++++---------------
arch/sh/kernel/cpu/sh4a/hwblk-sh7724.c | 121 ------------------------
arch/sh/kernel/cpu/shmobile/Makefile | 2 +
drivers/sh/Makefile | 1 +
7 files changed, 95 insertions(+), 201 deletions(-)
delete mode 100644 arch/sh/kernel/cpu/sh4a/hwblk-sh7724.c
diff --git a/arch/sh/include/asm/hwblk.h b/arch/sh/include/asm/hwblk.h
index 855e945..567c9aa 100644
--- a/arch/sh/include/asm/hwblk.h
+++ b/arch/sh/include/asm/hwblk.h
@@ -44,6 +44,7 @@ struct hwblk_info {
int nr_hwblks;
};
+#if !defined(CONFIG_CPU_SUBTYPE_SH7724)
/* Should be defined by processor-specific code */
int arch_hwblk_init(void);
int arch_hwblk_sleep_mode(void);
@@ -66,5 +67,7 @@ void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int cnt);
}
int sh_hwblk_clk_register(struct clk *clks, int nr);
-
+#else
+#define hwblk_init() 0
+#endif
#endif /* __ASM_SH_HWBLK_H */
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index ae95935..b937f1a 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -18,4 +18,7 @@ obj-$(CONFIG_ARCH_SHMOBILE) += shmobile/
obj-$(CONFIG_SH_ADC) += adc.o
obj-$(CONFIG_SH_CLK_CPG_LEGACY) += clock-cpg.o
-obj-y += irq/ init.o clock.o fpu.o hwblk.o proc.o
+obj-y += irq/ init.o clock.o fpu.o proc.o
+ifneq ($(CONFIG_CPU_SUBTYPE_SH7724),y)
+obj-y += hwblk.o
+endif
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index c57fb28..cb93287 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -29,7 +29,7 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7786) := clock-sh7786.o
clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o hwblk-sh7722.o
clock-$(CONFIG_CPU_SUBTYPE_SH7723) := clock-sh7723.o hwblk-sh7723.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7724) := clock-sh7724.o hwblk-sh7724.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7724) := clock-sh7724.o
clock-$(CONFIG_CPU_SUBTYPE_SH7366) := clock-sh7366.o
clock-$(CONFIG_CPU_SUBTYPE_SHX3) := clock-shx3.o
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
index 8668f55..2ec89e8 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
@@ -23,8 +23,8 @@
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
+#include <linux/sh_clk.h>
#include <asm/clock.h>
-#include <asm/hwblk.h>
#include <cpu/sh7724.h>
/* SH7724 registers */
@@ -35,6 +35,9 @@
#define FCLKBCR 0xa415000c
#define IRDACLKCR 0xa4150018
#define PLLCR 0xa4150024
+#define MSTPCR0 0xa4150030
+#define MSTPCR1 0xa4150034
+#define MSTPCR2 0xa4150038
#define SPUCLKCR 0xa415003c
#define FLLFRQ 0xa4150050
#define LSTATS 0xa4150060
@@ -195,61 +198,64 @@ static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
fclkbcr_parent, ARRAY_SIZE(fclkbcr_parent), 6, 2),
};
+#define MSTP(_parent, _reg, _bit, _flags) \
+ SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
+
static struct clk mstp_clks[HWBLK_NR] = {
- SH_HWBLK_CLK(HWBLK_TLB, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_IC, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_OC, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_RSMEM, &div4_clks[DIV4_B], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_ILMEM, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_L2C, &div4_clks[DIV4_SH], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_FPU, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_INTC, &div4_clks[DIV4_P], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_DMAC0, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_SHYWAY, &div4_clks[DIV4_SH], CLK_ENABLE_ON_INIT),
- SH_HWBLK_CLK(HWBLK_HUDI, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_UBC, &div4_clks[DIV4_I], 0),
- SH_HWBLK_CLK(HWBLK_TMU0, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_CMT, &r_clk, 0),
- SH_HWBLK_CLK(HWBLK_RWDT, &r_clk, 0),
- SH_HWBLK_CLK(HWBLK_DMAC1, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_TMU1, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_SCIF0, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_SCIF1, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_SCIF2, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_SCIF3, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_SCIF4, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_SCIF5, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_MSIOF0, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_MSIOF1, &div4_clks[DIV4_B], 0),
-
- SH_HWBLK_CLK(HWBLK_KEYSC, &r_clk, 0),
- SH_HWBLK_CLK(HWBLK_RTC, &r_clk, 0),
- SH_HWBLK_CLK(HWBLK_IIC0, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_IIC1, &div4_clks[DIV4_P], 0),
-
- SH_HWBLK_CLK(HWBLK_MMC, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_ETHER, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_ATAPI, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_TPU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_IRDA, &div4_clks[DIV4_P], 0),
- SH_HWBLK_CLK(HWBLK_TSIF, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_USB1, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_USB0, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_2DG, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_SDHI0, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_SDHI1, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_VEU1, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_CEU1, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_BEU1, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_2DDMAC, &div4_clks[DIV4_SH], 0),
- SH_HWBLK_CLK(HWBLK_SPU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_JPU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_VOU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_BEU0, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_CEU0, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_VEU0, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_VPU, &div4_clks[DIV4_B], 0),
- SH_HWBLK_CLK(HWBLK_LCDC, &div4_clks[DIV4_B], 0),
+ [HWBLK_TLB] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT),
+ [HWBLK_IC] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 30, CLK_ENABLE_ON_INIT),
+ [HWBLK_OC] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 29, CLK_ENABLE_ON_INIT),
+ [HWBLK_RSMEM] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
+ [HWBLK_ILMEM] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 27, CLK_ENABLE_ON_INIT),
+ [HWBLK_L2C] = MSTP(&div4_clks[DIV4_SH], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
+ [HWBLK_FPU] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 24, CLK_ENABLE_ON_INIT),
+ [HWBLK_INTC] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 22, CLK_ENABLE_ON_INIT),
+ [HWBLK_DMAC0] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 21, 0),
+ [HWBLK_SHYWAY] = MSTP(&div4_clks[DIV4_SH], MSTPCR0, 20, CLK_ENABLE_ON_INIT),
+ [HWBLK_HUDI] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 19, 0),
+ [HWBLK_UBC] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 17, 0),
+ [HWBLK_TMU0] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
+ [HWBLK_CMT] = MSTP(&r_clk, MSTPCR0, 14, 0),
+ [HWBLK_RWDT] = MSTP(&r_clk, MSTPCR0, 13, 0),
+ [HWBLK_DMAC1] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 12, 0),
+ [HWBLK_TMU1] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
+ [HWBLK_SCIF0] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 9, 0),
+ [HWBLK_SCIF1] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 8, 0),
+ [HWBLK_SCIF2] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
+ [HWBLK_SCIF3] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 6, 0),
+ [HWBLK_SCIF4] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 5, 0),
+ [HWBLK_SCIF5] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 4, 0),
+ [HWBLK_MSIOF0] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 2, 0),
+ [HWBLK_MSIOF1] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 1, 0),
+
+ [HWBLK_KEYSC] = MSTP(&r_clk, MSTPCR1, 12, 0),
+ [HWBLK_RTC] = MSTP(&r_clk, MSTPCR1, 11, 0),
+ [HWBLK_IIC0] = MSTP(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
+ [HWBLK_IIC1] = MSTP(&div4_clks[DIV4_P], MSTPCR1, 8, 0),
+
+ [HWBLK_MMC] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 29, 0),
+ [HWBLK_ETHER] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 28, 0),
+ [HWBLK_ATAPI] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 26, 0),
+ [HWBLK_TPU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 25, 0),
+ [HWBLK_IRDA] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 24, 0),
+ [HWBLK_TSIF] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 22, 0),
+ [HWBLK_USB1] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 21, 0),
+ [HWBLK_USB0] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 20, 0),
+ [HWBLK_2DG] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 19, 0),
+ [HWBLK_SDHI0] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 18, 0),
+ [HWBLK_SDHI1] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 17, 0),
+ [HWBLK_VEU1] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 15, 0),
+ [HWBLK_CEU1] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 13, 0),
+ [HWBLK_BEU1] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 12, 0),
+ [HWBLK_2DDMAC] = MSTP(&div4_clks[DIV4_SH], MSTPCR2, 10, 0),
+ [HWBLK_SPU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 9, 0),
+ [HWBLK_JPU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 6, 0),
+ [HWBLK_VOU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 5, 0),
+ [HWBLK_BEU0] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 4, 0),
+ [HWBLK_CEU0] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 3, 0),
+ [HWBLK_VEU0] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 2, 0),
+ [HWBLK_VPU] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 1, 0),
+ [HWBLK_LCDC] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 0, 0),
};
static struct clk_lookup lookups[] = {
@@ -283,7 +289,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("l2c0", &mstp_clks[HWBLK_L2C]),
CLKDEV_CON_ID("fpu0", &mstp_clks[HWBLK_FPU]),
CLKDEV_CON_ID("intc0", &mstp_clks[HWBLK_INTC]),
- CLKDEV_CON_ID("dmac0", &mstp_clks[HWBLK_DMAC0]),
+ CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[HWBLK_DMAC0]),
CLKDEV_CON_ID("sh0", &mstp_clks[HWBLK_SHYWAY]),
CLKDEV_CON_ID("hudi0", &mstp_clks[HWBLK_HUDI]),
CLKDEV_CON_ID("ubc0", &mstp_clks[HWBLK_UBC]),
@@ -294,26 +300,26 @@ static struct clk_lookup lookups[] = {
CLKDEV_ICK_ID("tmu_fck", "sh_tmu.3", &mstp_clks[HWBLK_TMU1]),
CLKDEV_CON_ID("cmt_fck", &mstp_clks[HWBLK_CMT]),
- CLKDEV_CON_ID("rwdt0", &mstp_clks[HWBLK_RWDT]),
- CLKDEV_CON_ID("dmac1", &mstp_clks[HWBLK_DMAC1]),
+ CLKDEV_DEV_ID("sh-wdt.0", &mstp_clks[HWBLK_RWDT]),
+ CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[HWBLK_DMAC1]),
CLKDEV_ICK_ID("tmu_fck", "sh_tmu.4", &mstp_clks[HWBLK_TMU1]),
CLKDEV_ICK_ID("tmu_fck", "sh_tmu.5", &mstp_clks[HWBLK_TMU1]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[HWBLK_SCIF4]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[HWBLK_SCIF5]),
-
- CLKDEV_CON_ID("msiof0", &mstp_clks[HWBLK_MSIOF0]),
- CLKDEV_CON_ID("msiof1", &mstp_clks[HWBLK_MSIOF1]),
- CLKDEV_CON_ID("keysc0", &mstp_clks[HWBLK_KEYSC]),
+ CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
+ CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
+ CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
+ CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
+ CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[HWBLK_SCIF4]),
+ CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[HWBLK_SCIF5]),
+
+ CLKDEV_DEV_ID("spi_sh_msiof.0", &mstp_clks[HWBLK_MSIOF0]),
+ CLKDEV_DEV_ID("spi_sh_msiof.1", &mstp_clks[HWBLK_MSIOF1]),
+ CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[HWBLK_KEYSC]),
CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),
CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC0]),
CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[HWBLK_IIC1]),
- CLKDEV_CON_ID("mmc0", &mstp_clks[HWBLK_MMC]),
- CLKDEV_CON_ID("eth0", &mstp_clks[HWBLK_ETHER]),
+ CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[HWBLK_MMC]),
+ CLKDEV_DEV_ID("sh-eth.0", &mstp_clks[HWBLK_ETHER]),
CLKDEV_CON_ID("atapi0", &mstp_clks[HWBLK_ATAPI]),
CLKDEV_CON_ID("tpu0", &mstp_clks[HWBLK_TPU]),
CLKDEV_CON_ID("irda0", &mstp_clks[HWBLK_IRDA]),
@@ -321,20 +327,20 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("usb1", &mstp_clks[HWBLK_USB1]),
CLKDEV_CON_ID("usb0", &mstp_clks[HWBLK_USB0]),
CLKDEV_CON_ID("2dg0", &mstp_clks[HWBLK_2DG]),
- CLKDEV_CON_ID("sdhi0", &mstp_clks[HWBLK_SDHI0]),
- CLKDEV_CON_ID("sdhi1", &mstp_clks[HWBLK_SDHI1]),
+ CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[HWBLK_SDHI0]),
+ CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[HWBLK_SDHI1]),
CLKDEV_CON_ID("veu1", &mstp_clks[HWBLK_VEU1]),
- CLKDEV_CON_ID("ceu1", &mstp_clks[HWBLK_CEU1]),
+ CLKDEV_DEV_ID("sh_mobile_ceu.1", &mstp_clks[HWBLK_CEU1]),
CLKDEV_CON_ID("beu1", &mstp_clks[HWBLK_BEU1]),
CLKDEV_CON_ID("2ddmac0", &mstp_clks[HWBLK_2DDMAC]),
CLKDEV_CON_ID("spu0", &mstp_clks[HWBLK_SPU]),
CLKDEV_CON_ID("jpu0", &mstp_clks[HWBLK_JPU]),
- CLKDEV_CON_ID("vou0", &mstp_clks[HWBLK_VOU]),
+ CLKDEV_DEV_ID("sh-vou.0", &mstp_clks[HWBLK_VOU]),
CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU0]),
- CLKDEV_CON_ID("ceu0", &mstp_clks[HWBLK_CEU0]),
+ CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU0]),
CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU0]),
CLKDEV_CON_ID("vpu0", &mstp_clks[HWBLK_VPU]),
- CLKDEV_CON_ID("lcdc0", &mstp_clks[HWBLK_LCDC]),
+ CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]),
};
int __init arch_clk_init(void)
@@ -362,7 +368,7 @@ int __init arch_clk_init(void)
ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_REPARENT_NR);
if (!ret)
- ret = sh_hwblk_clk_register(mstp_clks, HWBLK_NR);
+ ret = sh_clk_mstp32_register(mstp_clks, HWBLK_NR);
return ret;
}
diff --git a/arch/sh/kernel/cpu/sh4a/hwblk-sh7724.c b/arch/sh/kernel/cpu/sh4a/hwblk-sh7724.c
deleted file mode 100644
index 1613ad6..0000000
--- a/arch/sh/kernel/cpu/sh4a/hwblk-sh7724.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * arch/sh/kernel/cpu/sh4a/hwblk-sh7724.c
- *
- * SH7724 hardware block support
- *
- * Copyright (C) 2009 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <asm/suspend.h>
-#include <asm/hwblk.h>
-#include <cpu/sh7724.h>
-
-/* SH7724 registers */
-#define MSTPCR0 0xa4150030
-#define MSTPCR1 0xa4150034
-#define MSTPCR2 0xa4150038
-
-/* SH7724 Power Domains */
-enum { CORE_AREA, SUB_AREA, CORE_AREA_BM };
-static struct hwblk_area sh7724_hwblk_area[] = {
- [CORE_AREA] = HWBLK_AREA(0, 0),
- [CORE_AREA_BM] = HWBLK_AREA(HWBLK_AREA_FLAG_PARENT, CORE_AREA),
- [SUB_AREA] = HWBLK_AREA(0, 0),
-};
-
-/* Table mapping HWBLK to Module Stop Bit and Power Domain */
-static struct hwblk sh7724_hwblk[HWBLK_NR] = {
- [HWBLK_TLB] = HWBLK(MSTPCR0, 31, CORE_AREA),
- [HWBLK_IC] = HWBLK(MSTPCR0, 30, CORE_AREA),
- [HWBLK_OC] = HWBLK(MSTPCR0, 29, CORE_AREA),
- [HWBLK_RSMEM] = HWBLK(MSTPCR0, 28, CORE_AREA),
- [HWBLK_ILMEM] = HWBLK(MSTPCR0, 27, CORE_AREA),
- [HWBLK_L2C] = HWBLK(MSTPCR0, 26, CORE_AREA),
- [HWBLK_FPU] = HWBLK(MSTPCR0, 24, CORE_AREA),
- [HWBLK_INTC] = HWBLK(MSTPCR0, 22, CORE_AREA),
- [HWBLK_DMAC0] = HWBLK(MSTPCR0, 21, CORE_AREA_BM),
- [HWBLK_SHYWAY] = HWBLK(MSTPCR0, 20, CORE_AREA),
- [HWBLK_HUDI] = HWBLK(MSTPCR0, 19, CORE_AREA),
- [HWBLK_DBG] = HWBLK(MSTPCR0, 18, CORE_AREA),
- [HWBLK_UBC] = HWBLK(MSTPCR0, 17, CORE_AREA),
- [HWBLK_TMU0] = HWBLK(MSTPCR0, 15, CORE_AREA),
- [HWBLK_CMT] = HWBLK(MSTPCR0, 14, SUB_AREA),
- [HWBLK_RWDT] = HWBLK(MSTPCR0, 13, SUB_AREA),
- [HWBLK_DMAC1] = HWBLK(MSTPCR0, 12, CORE_AREA_BM),
- [HWBLK_TMU1] = HWBLK(MSTPCR0, 10, CORE_AREA),
- [HWBLK_SCIF0] = HWBLK(MSTPCR0, 9, CORE_AREA),
- [HWBLK_SCIF1] = HWBLK(MSTPCR0, 8, CORE_AREA),
- [HWBLK_SCIF2] = HWBLK(MSTPCR0, 7, CORE_AREA),
- [HWBLK_SCIF3] = HWBLK(MSTPCR0, 6, CORE_AREA),
- [HWBLK_SCIF4] = HWBLK(MSTPCR0, 5, CORE_AREA),
- [HWBLK_SCIF5] = HWBLK(MSTPCR0, 4, CORE_AREA),
- [HWBLK_MSIOF0] = HWBLK(MSTPCR0, 2, CORE_AREA),
- [HWBLK_MSIOF1] = HWBLK(MSTPCR0, 1, CORE_AREA),
-
- [HWBLK_KEYSC] = HWBLK(MSTPCR1, 12, SUB_AREA),
- [HWBLK_RTC] = HWBLK(MSTPCR1, 11, SUB_AREA),
- [HWBLK_IIC0] = HWBLK(MSTPCR1, 9, CORE_AREA),
- [HWBLK_IIC1] = HWBLK(MSTPCR1, 8, CORE_AREA),
-
- [HWBLK_MMC] = HWBLK(MSTPCR2, 29, CORE_AREA),
- [HWBLK_ETHER] = HWBLK(MSTPCR2, 28, CORE_AREA_BM),
- [HWBLK_ATAPI] = HWBLK(MSTPCR2, 26, CORE_AREA_BM),
- [HWBLK_TPU] = HWBLK(MSTPCR2, 25, CORE_AREA),
- [HWBLK_IRDA] = HWBLK(MSTPCR2, 24, CORE_AREA),
- [HWBLK_TSIF] = HWBLK(MSTPCR2, 22, CORE_AREA),
- [HWBLK_USB1] = HWBLK(MSTPCR2, 21, CORE_AREA),
- [HWBLK_USB0] = HWBLK(MSTPCR2, 20, CORE_AREA),
- [HWBLK_2DG] = HWBLK(MSTPCR2, 19, CORE_AREA_BM),
- [HWBLK_SDHI0] = HWBLK(MSTPCR2, 18, CORE_AREA),
- [HWBLK_SDHI1] = HWBLK(MSTPCR2, 17, CORE_AREA),
- [HWBLK_VEU1] = HWBLK(MSTPCR2, 15, CORE_AREA_BM),
- [HWBLK_CEU1] = HWBLK(MSTPCR2, 13, CORE_AREA_BM),
- [HWBLK_BEU1] = HWBLK(MSTPCR2, 12, CORE_AREA_BM),
- [HWBLK_2DDMAC] = HWBLK(MSTPCR2, 10, CORE_AREA_BM),
- [HWBLK_SPU] = HWBLK(MSTPCR2, 9, CORE_AREA_BM),
- [HWBLK_JPU] = HWBLK(MSTPCR2, 6, CORE_AREA_BM),
- [HWBLK_VOU] = HWBLK(MSTPCR2, 5, CORE_AREA_BM),
- [HWBLK_BEU0] = HWBLK(MSTPCR2, 4, CORE_AREA_BM),
- [HWBLK_CEU0] = HWBLK(MSTPCR2, 3, CORE_AREA_BM),
- [HWBLK_VEU0] = HWBLK(MSTPCR2, 2, CORE_AREA_BM),
- [HWBLK_VPU] = HWBLK(MSTPCR2, 1, CORE_AREA_BM),
- [HWBLK_LCDC] = HWBLK(MSTPCR2, 0, CORE_AREA_BM),
-};
-
-static struct hwblk_info sh7724_hwblk_info = {
- .areas = sh7724_hwblk_area,
- .nr_areas = ARRAY_SIZE(sh7724_hwblk_area),
- .hwblks = sh7724_hwblk,
- .nr_hwblks = ARRAY_SIZE(sh7724_hwblk),
-};
-
-int arch_hwblk_sleep_mode(void)
-{
- if (!sh7724_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE])
- return SUSP_SH_STANDBY | SUSP_SH_SF;
-
- if (!sh7724_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE])
- return SUSP_SH_SLEEP | SUSP_SH_SF;
-
- return SUSP_SH_SLEEP;
-}
-
-int __init arch_hwblk_init(void)
-{
- return hwblk_register(&sh7724_hwblk_info);
-}
diff --git a/arch/sh/kernel/cpu/shmobile/Makefile b/arch/sh/kernel/cpu/shmobile/Makefile
index a39f88e..2f32a03 100644
--- a/arch/sh/kernel/cpu/shmobile/Makefile
+++ b/arch/sh/kernel/cpu/shmobile/Makefile
@@ -5,4 +5,6 @@
# Power Management & Sleep mode
obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+ifneq ($(CONFIG_CPU_SUBTYPE_SH7724),y)
obj-$(CONFIG_PM_RUNTIME) += pm_runtime.o
+endif
diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile
index 67e272ab..30c2594 100644
--- a/drivers/sh/Makefile
+++ b/drivers/sh/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_GENERIC_GPIO) += pfc.o
# special casing can go away.
#
obj-$(CONFIG_SUPERH)$(CONFIG_ARCH_SHMOBILE) += pm_runtime.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7724) += pm_runtime.o
--
1.7.2.5
^ permalink raw reply related
* [PATCH 0/3] Switch sh7722, sh7723, and sh7724 to a generic sh-mobile
From: Guennadi Liakhovetski @ 2011-11-16 12:35 UTC (permalink / raw)
To: linux-sh
The sh/pm-runtime branch of https://github.com/pmundt/linux-sh begins the
migration of SuperH platforms from their hwblk runtime PM implementation
to the common with ARM-based sh-mobile platforms code. These patches
actually migrate sh7722, sh7723, and sh7724 architectures over.
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply
* Re: [PATCH 4/5] treewide: Convert uses of ATTRIB_NORETURN to __noreturn
From: Geert Uytterhoeven @ 2011-11-14 20:50 UTC (permalink / raw)
To: Joe Perches
Cc: Andrew Morton, linux-kernel, Tony Luck, Fenghua Yu, Ralf Baechle,
David Howells, Koichi Yasutake, Benjamin Herrenschmidt,
Paul Mackerras, Martin Schwidefsky, Heiko Carstens, linux390,
Paul Mundt, Chris Metcalf, linux-ia64, linux-m68k, linux-mips,
linux-am33-list, linuxppc-dev, linux-s390, linux-sh
In-Reply-To: <abb1d8b542872ef3bfd695e85d3b8a0fd70645b9.1320917558.git.joe@perches.com>
On Thu, Nov 10, 2011 at 10:41, Joe Perches <joe@perches.com> wrote:
> Use the more commonly used __noreturn instead of ATTRIB_NORETURN.
>
> Signed-off-by: Joe Perches <joe@perches.com>
For the m68k parts:
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [GIT PULL] rmobile fixes for 3.2-rc2
From: Paul Mundt @ 2011-11-14 8:15 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-sh, linux-kernel
Nothing terribly exciting here, either. In addition to build fixes for
the recent cpuidle changes, the bulk of it is simply shuffling some code
around for an upcoming board/CPU combination, and tidying up the in-tree
variants in the process.
Please pull from:
git://github.com/pmundt/linux-sh.git rmobile-fixes-for-linus
Which contains:
Kuninori Morimoto (7):
ARM: mach-shmobile: sh73a0: add MMC data pin pull-up
ARM: mach-shmobile: kota2: add comment out separator
ARM: mach-shmobile: clock-sh7372: remove un-necessary index
ARM: mach-shmobile: ap4evb: remove white space from end of line
ARM: mach-shmobile: move helper macro PORT_DATA_xx to sh_pfc.h
ARM: mach-shmobile: move helper macro PORT_xx to sh_pfc.h
ARM: mach-shmobile: move helper macro PORTCR to sh_pfc.h
Magnus Damm (1):
ARM: mach-shmobile: cpuidle single/global and last_state fixes
arch/arm/mach-shmobile/board-ag5evm.c | 16 +-
arch/arm/mach-shmobile/board-ap4evb.c | 2 +-
arch/arm/mach-shmobile/board-kota2.c | 7 +
arch/arm/mach-shmobile/clock-sh7372.c | 8 +-
arch/arm/mach-shmobile/cpuidle.c | 52 +++---
arch/arm/mach-shmobile/include/mach/common.h | 4 +-
arch/arm/mach-shmobile/include/mach/sh73a0.h | 8 +
arch/arm/mach-shmobile/pfc-sh7367.c | 122 +++----------
arch/arm/mach-shmobile/pfc-sh7372.c | 262 ++++++++++++--------------
arch/arm/mach-shmobile/pfc-sh7377.c | 159 ++++------------
arch/arm/mach-shmobile/pfc-sh73a0.c | 193 ++++++++-----------
arch/arm/mach-shmobile/pm-sh7372.c | 14 +-
include/linux/sh_pfc.h | 76 ++++++++
13 files changed, 400 insertions(+), 523 deletions(-)
^ permalink raw reply
* [GIT PULL] sh fixes for 3.2-rc2
From: Paul Mundt @ 2011-11-14 8:15 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-sh, linux-kernel
There is mostly odd fixes and the addition of a couple helpers that
some stuff aimed at the next merge window wants. There's the shuffling
over of the runtime PM platform stub that was in use by the ARM
SH/R-Mobile code and using it generically for the rest of the SH
platforms, too (this fixes up some regressions with the runtime PM code
on SH platforms that tie their MSTP bits in to the clock framework but
don't otherwise have their own private runtime PM implementations).
Please pull from:
git://github.com/pmundt/linux-sh.git sh-fixes-for-linus
Which contains:
Kuninori Morimoto (2):
sh: clkfwk: add clk_rate_mult_range_round()
mailmap: Fix up some renesas attributions
Nobuhiro Iwamatsu (1):
sh: Fix cached/uncaced address calculation in 29bit mode
Paul Mundt (4):
sh: Wire up process_vm syscalls.
drivers: sh: Generalize runtime PM platform stub.
drivers: sh: Kill off dead pathname for runtime PM stub.
sh: clkfwk: Kill off remaining debugfs cruft.
Phil Edworthy (1):
serial: sh-sci: Fix up SH-2A SCIF support.
.mailmap | 2 +
arch/arm/mach-shmobile/Makefile | 2 +-
arch/sh/include/asm/page.h | 5 +
arch/sh/include/asm/unistd_32.h | 4 +-
arch/sh/include/asm/unistd_64.h | 4 +-
arch/sh/kernel/cpu/sh2a/setup-sh7203.c | 16 ++-
arch/sh/kernel/syscalls_32.S | 2 +
arch/sh/kernel/syscalls_64.S | 2 +
drivers/sh/Makefile | 8 ++
drivers/sh/clk/core.c | 107 ++++----------------
.../arm/mach-shmobile => drivers/sh}/pm_runtime.c | 4 +-
drivers/tty/serial/sh-sci.c | 19 ++++
include/linux/serial_sci.h | 1 +
include/linux/sh_clk.h | 4 +-
14 files changed, 82 insertions(+), 98 deletions(-)
rename {arch/arm/mach-shmobile => drivers/sh}/pm_runtime.c (94%)
^ permalink raw reply
* [update][PATCH 7/7] PM / Domains: Automatically update overoptimistic latency information
From: Rafael J. Wysocki @ 2011-11-14 0:28 UTC (permalink / raw)
To: Linux PM list
Cc: LKML, Linux-sh list, Magnus Damm, Guennadi Liakhovetski,
Kevin Hilman, jean.pihet
In-Reply-To: <201111140122.27328.rjw@sisk.pl>
From: Rafael J. Wysocki <rjw@sisk.pl>
Measure the time of execution of the .stop(), .start(), .save_state()
and .restore_state() PM domain device callbacks and if the result
is greater than the corresponding latency value stored in the
device's struct generic_pm_domain_data object, replace the inaccurate
value with the measured time.
Do analogously for the PM domains' .power_off() and .power_off()
callbacks.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/base/power/domain.c | 39 +++++++++++++++++++++++++++++++++++----
1 file changed, 35 insertions(+), 4 deletions(-)
Index: linux/drivers/base/power/domain.c
=================================--- linux.orig/drivers/base/power/domain.c
+++ linux/drivers/base/power/domain.c
@@ -33,6 +33,17 @@
__ret; \
})
+#define GENPD_DEV_TIMED_CALLBACK(genpd, type, callback, dev, latency) \
+({ \
+ ktime_t __start = ktime_get(); \
+ type __retval = GENPD_DEV_CALLBACK(genpd, type, callback, dev); \
+ s64 __elapsed = ktime_to_ns(ktime_sub(ktime_get(), __start)); \
+ struct generic_pm_domain_data *__gpd_data = dev_gpd_data(dev); \
+ if (__elapsed > __gpd_data->td.latency) \
+ __gpd_data->td.latency = __elapsed; \
+ __retval; \
+})
+
static LIST_HEAD(gpd_list);
static DEFINE_MUTEX(gpd_list_lock);
@@ -48,22 +59,26 @@ struct generic_pm_domain *dev_to_genpd(s
static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev)
{
- return GENPD_DEV_CALLBACK(genpd, int, stop, dev);
+ return GENPD_DEV_TIMED_CALLBACK(genpd, int, stop, dev,
+ stop_latency_ns);
}
static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev)
{
- return GENPD_DEV_CALLBACK(genpd, int, start, dev);
+ return GENPD_DEV_TIMED_CALLBACK(genpd, int, start, dev,
+ start_latency_ns);
}
static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev)
{
- return GENPD_DEV_CALLBACK(genpd, int, save_state, dev);
+ return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev,
+ save_state_latency_ns);
}
static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev)
{
- return GENPD_DEV_CALLBACK(genpd, int, restore_state, dev);
+ return GENPD_DEV_TIMED_CALLBACK(genpd, int, restore_state, dev,
+ restore_state_latency_ns);
}
static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
@@ -182,9 +197,16 @@ int __pm_genpd_poweron(struct generic_pm
}
if (genpd->power_on) {
+ ktime_t time_start = ktime_get();
+ s64 elapsed_ns;
+
ret = genpd->power_on(genpd);
if (ret)
goto err;
+
+ elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
+ if (elapsed_ns > genpd->power_on_latency_ns)
+ genpd->power_on_latency_ns = elapsed_ns;
}
genpd_set_active(genpd);
@@ -377,11 +399,16 @@ static int pm_genpd_poweroff(struct gene
}
if (genpd->power_off) {
+ ktime_t time_start;
+ s64 elapsed_ns;
+
if (atomic_read(&genpd->sd_count) > 0) {
ret = -EBUSY;
goto out;
}
+ time_start = ktime_get();
+
/*
* If sd_count > 0 at this point, one of the subdomains hasn't
* managed to call pm_genpd_poweron() for the master yet after
@@ -395,6 +422,10 @@ static int pm_genpd_poweroff(struct gene
genpd_set_active(genpd);
goto out;
}
+
+ elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
+ if (elapsed_ns > genpd->power_off_latency_ns)
+ genpd->power_off_latency_ns = elapsed_ns;
}
genpd->status = GPD_STATE_POWER_OFF;
^ permalink raw reply
* [update][PATCH 6/7] PM / Domains: Add default power off governor function (v4)
From: Rafael J. Wysocki @ 2011-11-14 0:27 UTC (permalink / raw)
To: Linux PM list
Cc: LKML, Linux-sh list, Magnus Damm, Guennadi Liakhovetski,
Kevin Hilman, jean.pihet
In-Reply-To: <201111140122.27328.rjw@sisk.pl>
From: Rafael J. Wysocki <rjw@sisk.pl>
Add a function deciding whether or not a given PM domain should
be powered off on the basis of the PM QoS constraints of devices
belonging to it and their PM QoS timing data.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/base/power/domain.c | 12 +++
drivers/base/power/domain_governor.c | 110 +++++++++++++++++++++++++++++++++++
include/linux/pm_domain.h | 7 ++
3 files changed, 129 insertions(+)
Index: linux/include/linux/pm_domain.h
=================================--- linux.orig/include/linux/pm_domain.h
+++ linux/include/linux/pm_domain.h
@@ -57,8 +57,13 @@ struct generic_pm_domain {
bool suspend_power_off; /* Power status before system suspend */
bool dev_irq_safe; /* Device callbacks are IRQ-safe */
int (*power_off)(struct generic_pm_domain *domain);
+ s64 power_off_latency_ns;
int (*power_on)(struct generic_pm_domain *domain);
+ s64 power_on_latency_ns;
struct gpd_dev_ops dev_ops;
+ s64 break_even_ns; /* Power break even for the entire domain. */
+ s64 max_off_time_ns; /* Maximum allowed "suspended" time. */
+ ktime_t power_off_time;
};
static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
@@ -76,6 +81,8 @@ struct gpd_link {
struct gpd_timing_data {
s64 stop_latency_ns;
s64 start_latency_ns;
+ s64 save_state_latency_ns;
+ s64 restore_state_latency_ns;
s64 break_even_ns;
};
Index: linux/drivers/base/power/domain_governor.c
=================================--- linux.orig/drivers/base/power/domain_governor.c
+++ linux/drivers/base/power/domain_governor.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/pm_domain.h>
#include <linux/pm_qos.h>
+#include <linux/hrtimer.h>
/**
* default_stop_ok - Default PM domain governor routine for stopping devices.
@@ -28,6 +29,115 @@ bool default_stop_ok(struct device *dev)
&& td->break_even_ns < dev->power.max_time_suspended_ns;
}
+/**
+ * default_power_down_ok - Default generic PM domain power off governor routine.
+ * @pd: PM domain to check.
+ *
+ * This routine must be executed under the PM domain's lock.
+ */
+static bool default_power_down_ok(struct dev_pm_domain *pd)
+{
+ struct generic_pm_domain *genpd = pd_to_genpd(pd);
+ struct gpd_link *link;
+ struct pm_domain_data *pdd;
+ s64 min_dev_off_time_ns;
+ s64 off_on_time_ns;
+ ktime_t time_now = ktime_get();
+
+ off_on_time_ns = genpd->power_off_latency_ns +
+ genpd->power_on_latency_ns;
+ /*
+ * It doesn't make sense to remove power from the domain if saving
+ * the state of all devices in it and the power off/power on operations
+ * take too much time.
+ *
+ * All devices in this domain have been stopped already at this point.
+ */
+ list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+ if (pdd->dev->driver)
+ off_on_time_ns ++ to_gpd_data(pdd)->td.save_state_latency_ns;
+ }
+
+ /*
+ * Check if subdomains can be off for enough time.
+ *
+ * All subdomains have been powered off already at this point.
+ */
+ list_for_each_entry(link, &genpd->master_links, master_node) {
+ struct generic_pm_domain *sd = link->slave;
+ s64 sd_max_off_ns = sd->max_off_time_ns;
+
+ if (sd_max_off_ns < 0)
+ continue;
+
+ sd_max_off_ns -= ktime_to_ns(ktime_sub(time_now,
+ sd->power_off_time));
+ /*
+ * Check if the subdomain is allowed to be off long enough for
+ * the current domain to turn off and on (that's how much time
+ * it will have to wait worst case).
+ */
+ if (sd_max_off_ns <= off_on_time_ns)
+ return false;
+ }
+
+ /*
+ * Check if the devices in the domain can be off enough time.
+ */
+ min_dev_off_time_ns = -1;
+ list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+ struct gpd_timing_data *td;
+ struct device *dev = pdd->dev;
+ s64 dev_off_time_ns;
+
+ if (!dev->driver || dev->power.max_time_suspended_ns < 0)
+ continue;
+
+ td = &to_gpd_data(pdd)->td;
+ dev_off_time_ns = dev->power.max_time_suspended_ns -
+ (td->start_latency_ns + td->restore_state_latency_ns +
+ ktime_to_ns(ktime_sub(time_now,
+ dev->power.suspend_time)));
+ if (dev_off_time_ns <= off_on_time_ns)
+ return false;
+
+ if (min_dev_off_time_ns > dev_off_time_ns
+ || min_dev_off_time_ns < 0)
+ min_dev_off_time_ns = dev_off_time_ns;
+ }
+
+ if (min_dev_off_time_ns < 0) {
+ /*
+ * There are no latency constraints, so the domain can spend
+ * arbitrary time in the "off" state.
+ */
+ genpd->max_off_time_ns = -1;
+ return true;
+ }
+
+ /*
+ * The difference between the computed minimum delta and the time needed
+ * to turn the domain on is the maximum theoretical time this domain can
+ * spend in the "off" state.
+ */
+ min_dev_off_time_ns -= genpd->power_on_latency_ns;
+
+ /*
+ * If the difference between the computed minimum delta and the time
+ * needed to turn the domain off and back on on is smaller than the
+ * domain's power break even time, removing power from the domain is not
+ * worth it.
+ */
+ if (genpd->break_even_ns >
+ min_dev_off_time_ns - genpd->power_off_latency_ns)
+ return false;
+
+ genpd->max_off_time_ns = min_dev_off_time_ns;
+ return true;
+}
+
struct dev_power_governor simple_qos_governor = {
.stop_ok = default_stop_ok,
+ .power_down_ok = default_power_down_ok,
};
Index: linux/drivers/base/power/domain.c
=================================--- linux.orig/drivers/base/power/domain.c
+++ linux/drivers/base/power/domain.c
@@ -398,6 +398,17 @@ static int pm_genpd_poweroff(struct gene
}
genpd->status = GPD_STATE_POWER_OFF;
+ genpd->power_off_time = ktime_get();
+
+ /* Update PM QoS information for devices in the domain. */
+ list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
+ struct gpd_timing_data *td = &to_gpd_data(pdd)->td;
+
+ pm_runtime_update_max_time_suspended(pdd->dev,
+ td->start_latency_ns +
+ td->restore_state_latency_ns +
+ genpd->power_on_latency_ns);
+ }
list_for_each_entry(link, &genpd->slave_links, slave_node) {
genpd_sd_counter_dec(link->master);
@@ -1417,6 +1428,7 @@ void pm_genpd_init(struct generic_pm_dom
genpd->resume_count = 0;
genpd->device_count = 0;
genpd->suspended_count = 0;
+ genpd->max_off_time_ns = -1;
genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
^ permalink raw reply
* [update][PATCH 5/7] PM / Domains: Add device stop governor function (v4)
From: Rafael J. Wysocki @ 2011-11-14 0:27 UTC (permalink / raw)
To: Linux PM list
Cc: LKML, Linux-sh list, Magnus Damm, Guennadi Liakhovetski,
Kevin Hilman, jean.pihet
In-Reply-To: <201111140122.27328.rjw@sisk.pl>
From: Rafael J. Wysocki <rjw@sisk.pl>
Add a function deciding whether or not devices should be stopped in
pm_genpd_runtime_suspend() depending on their PM QoS constraints
and stop/start timing values. Make it possible to add information
used by this function to device objects.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
arch/arm/mach-shmobile/pm-sh7372.c | 4 +-
drivers/base/power/Makefile | 2 -
drivers/base/power/domain.c | 33 ++++++++++++++----
drivers/base/power/domain_governor.c | 33 ++++++++++++++++++
include/linux/pm_domain.h | 63 ++++++++++++++++++++++++++++++-----
5 files changed, 118 insertions(+), 17 deletions(-)
Index: linux/include/linux/pm_domain.h
=================================--- linux.orig/include/linux/pm_domain.h
+++ linux/include/linux/pm_domain.h
@@ -21,6 +21,7 @@ enum gpd_status {
struct dev_power_governor {
bool (*power_down_ok)(struct dev_pm_domain *domain);
+ bool (*stop_ok)(struct device *dev);
};
struct gpd_dev_ops {
@@ -72,9 +73,16 @@ struct gpd_link {
struct list_head slave_node;
};
+struct gpd_timing_data {
+ s64 stop_latency_ns;
+ s64 start_latency_ns;
+ s64 break_even_ns;
+};
+
struct generic_pm_domain_data {
struct pm_domain_data base;
struct gpd_dev_ops ops;
+ struct gpd_timing_data td;
bool need_restore;
};
@@ -89,20 +97,48 @@ static inline struct generic_pm_domain_d
}
#ifdef CONFIG_PM_GENERIC_DOMAINS
-extern int pm_genpd_add_device(struct generic_pm_domain *genpd,
- struct device *dev);
+extern struct dev_power_governor simple_qos_governor;
+
+extern struct generic_pm_domain *dev_to_genpd(struct device *dev);
+extern int __pm_genpd_add_device(struct generic_pm_domain *genpd,
+ struct device *dev,
+ struct gpd_timing_data *td);
+
+static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
+ struct device *dev)
+{
+ return __pm_genpd_add_device(genpd, dev, NULL);
+}
+
extern int pm_genpd_remove_device(struct generic_pm_domain *genpd,
struct device *dev);
extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
struct generic_pm_domain *new_subdomain);
extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
struct generic_pm_domain *target);
-extern int pm_genpd_add_callbacks(struct device *dev, struct gpd_dev_ops *ops);
-extern int pm_genpd_remove_callbacks(struct device *dev);
+extern int pm_genpd_add_callbacks(struct device *dev,
+ struct gpd_dev_ops *ops,
+ struct gpd_timing_data *td);
+extern int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td);
extern void pm_genpd_init(struct generic_pm_domain *genpd,
struct dev_power_governor *gov, bool is_off);
+
extern int pm_genpd_poweron(struct generic_pm_domain *genpd);
+
+extern bool default_stop_ok(struct device *dev);
+
#else
+
+static inline struct generic_pm_domain *dev_to_genpd(struct device *dev)
+{
+ return ERR_PTR(-ENOSYS);
+}
+static inline int __pm_genpd_add_device(struct generic_pm_domain *genpd,
+ struct device *dev,
+ struct gpd_timing_data *td)
+{
+ return -ENOSYS;
+}
static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
struct device *dev)
{
@@ -124,22 +160,33 @@ static inline int pm_genpd_remove_subdom
return -ENOSYS;
}
static inline int pm_genpd_add_callbacks(struct device *dev,
- struct gpd_dev_ops *ops)
+ struct gpd_dev_ops *ops,
+ struct gpd_timing_data *td)
{
return -ENOSYS;
}
-static inline int pm_genpd_remove_callbacks(struct device *dev)
+static inline int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td)
{
return -ENOSYS;
}
-static inline void pm_genpd_init(struct generic_pm_domain *genpd,
- struct dev_power_governor *gov, bool is_off) {}
+static inline void pm_genpd_init(struct generic_pm_domain *genpd, bool is_off)
+{
+}
static inline int pm_genpd_poweron(struct generic_pm_domain *genpd)
{
return -ENOSYS;
}
+static inline bool default_stop_ok(struct device *dev)
+{
+ return false;
+}
#endif
+static inline int pm_genpd_remove_callbacks(struct device *dev)
+{
+ return __pm_genpd_remove_callbacks(dev, true);
+}
+
#ifdef CONFIG_PM_GENERIC_DOMAINS_RUNTIME
extern void genpd_queue_power_off_work(struct generic_pm_domain *genpd);
extern void pm_genpd_poweroff_unused(void);
Index: linux/drivers/base/power/domain.c
=================================--- linux.orig/drivers/base/power/domain.c
+++ linux/drivers/base/power/domain.c
@@ -38,7 +38,7 @@ static DEFINE_MUTEX(gpd_list_lock);
#ifdef CONFIG_PM
-static struct generic_pm_domain *dev_to_genpd(struct device *dev)
+struct generic_pm_domain *dev_to_genpd(struct device *dev)
{
if (IS_ERR_OR_NULL(dev->pm_domain))
return ERR_PTR(-EINVAL);
@@ -436,6 +436,7 @@ static void genpd_power_off_work_fn(stru
static int pm_genpd_runtime_suspend(struct device *dev)
{
struct generic_pm_domain *genpd;
+ bool (*stop_ok)(struct device *__dev);
int ret;
dev_dbg(dev, "%s()\n", __func__);
@@ -446,10 +447,17 @@ static int pm_genpd_runtime_suspend(stru
might_sleep_if(!genpd->dev_irq_safe);
+ stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL;
+ if (stop_ok && !stop_ok(dev))
+ return -EBUSY;
+
ret = genpd_stop_dev(genpd, dev);
if (ret)
return ret;
+ pm_runtime_update_max_time_suspended(dev,
+ dev_gpd_data(dev)->td.start_latency_ns);
+
/*
* If power.irq_safe is set, this routine will be run with interrupts
* off, so it can't use mutexes.
@@ -1022,11 +1030,13 @@ static void pm_genpd_complete(struct dev
#endif /* CONFIG_PM_SLEEP */
/**
- * pm_genpd_add_device - Add a device to an I/O PM domain.
+ * __pm_genpd_add_device - Add a device to an I/O PM domain.
* @genpd: PM domain to add the device to.
* @dev: Device to be added.
+ * @td: Set of PM QoS timing parameters to attach to the device.
*/
-int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
+int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
+ struct gpd_timing_data *td)
{
struct generic_pm_domain_data *gpd_data;
struct pm_domain_data *pdd;
@@ -1069,6 +1079,8 @@ int pm_genpd_add_device(struct generic_p
gpd_data->base.dev = dev;
gpd_data->need_restore = false;
list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
+ if (td)
+ gpd_data->td = *td;
out:
genpd_release_lock(genpd);
@@ -1229,8 +1241,10 @@ int pm_genpd_remove_subdomain(struct gen
* pm_genpd_add_callbacks - Add PM domain callbacks to a given device.
* @dev: Device to add the callbacks to.
* @ops: Set of callbacks to add.
+ * @td: Timing data to add to the device along with the callbacks (optional).
*/
-int pm_genpd_add_callbacks(struct device *dev, struct gpd_dev_ops *ops)
+int pm_genpd_add_callbacks(struct device *dev, struct gpd_dev_ops *ops,
+ struct gpd_timing_data *td)
{
struct pm_domain_data *pdd;
int ret = 0;
@@ -1246,6 +1260,8 @@ int pm_genpd_add_callbacks(struct device
struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
gpd_data->ops = *ops;
+ if (td)
+ gpd_data->td = *td;
} else {
ret = -EINVAL;
}
@@ -1258,10 +1274,11 @@ int pm_genpd_add_callbacks(struct device
EXPORT_SYMBOL_GPL(pm_genpd_add_callbacks);
/**
- * pm_genpd_remove_callbacks - Remove PM domain callbacks from a given device.
+ * __pm_genpd_remove_callbacks - Remove PM domain callbacks from a given device.
* @dev: Device to remove the callbacks from.
+ * @clear_td: If set, clear the device's timing data too.
*/
-int pm_genpd_remove_callbacks(struct device *dev)
+int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td)
{
struct pm_domain_data *pdd;
int ret = 0;
@@ -1277,6 +1294,8 @@ int pm_genpd_remove_callbacks(struct dev
struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
gpd_data->ops = (struct gpd_dev_ops){ 0 };
+ if (clear_td)
+ gpd_data->td = (struct gpd_timing_data){ 0 };
} else {
ret = -EINVAL;
}
@@ -1286,7 +1305,7 @@ int pm_genpd_remove_callbacks(struct dev
return ret;
}
-EXPORT_SYMBOL_GPL(pm_genpd_remove_callbacks);
+EXPORT_SYMBOL_GPL(__pm_genpd_remove_callbacks);
/* Default device callbacks for generic PM domains. */
Index: linux/drivers/base/power/Makefile
=================================--- linux.orig/drivers/base/power/Makefile
+++ linux/drivers/base/power/Makefile
@@ -3,7 +3,7 @@ obj-$(CONFIG_PM_SLEEP) += main.o wakeup.
obj-$(CONFIG_PM_RUNTIME) += runtime.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
obj-$(CONFIG_PM_OPP) += opp.o
-obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o
+obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o
obj-$(CONFIG_HAVE_CLK) += clock_ops.o
ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
Index: linux/drivers/base/power/domain_governor.c
=================================--- /dev/null
+++ linux/drivers/base/power/domain_governor.c
@@ -0,0 +1,33 @@
+/*
+ * drivers/base/power/domain_governor.c - Governors for device PM domains.
+ *
+ * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_qos.h>
+
+/**
+ * default_stop_ok - Default PM domain governor routine for stopping devices.
+ * @dev: Device to check.
+ */
+bool default_stop_ok(struct device *dev)
+{
+ struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+
+ dev_dbg(dev, "%s()\n", __func__);
+
+ if (dev->power.max_time_suspended_ns < 0 || td->break_even_ns = 0)
+ return true;
+
+ return td->stop_latency_ns + td->start_latency_ns < td->break_even_ns
+ && td->break_even_ns < dev->power.max_time_suspended_ns;
+}
+
+struct dev_power_governor simple_qos_governor = {
+ .stop_ok = default_stop_ok,
+};
Index: linux/arch/arm/mach-shmobile/pm-sh7372.c
=================================--- linux.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux/arch/arm/mach-shmobile/pm-sh7372.c
@@ -169,6 +169,7 @@ static bool sh7372_power_down_forbidden(
struct dev_power_governor sh7372_always_on_gov = {
.power_down_ok = sh7372_power_down_forbidden,
+ .stop_ok = default_stop_ok,
};
static int sh7372_stop_dev(struct device *dev)
@@ -203,8 +204,9 @@ static int sh7372_start_dev(struct devic
void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd)
{
struct generic_pm_domain *genpd = &sh7372_pd->genpd;
+ struct dev_power_governor *gov = sh7372_pd->gov;
- pm_genpd_init(genpd, sh7372_pd->gov, false);
+ pm_genpd_init(genpd, gov ? : &simple_qos_governor, false);
genpd->dev_ops.stop = sh7372_stop_dev;
genpd->dev_ops.start = sh7372_start_dev;
genpd->dev_ops.active_wakeup = pd_active_wakeup;
^ permalink raw reply
* [update][PATCH 4/7] PM / Runtime: Use device PM QoS constraints
From: Rafael J. Wysocki @ 2011-11-14 0:26 UTC (permalink / raw)
To: Linux PM list
Cc: LKML, Linux-sh list, Magnus Damm, Guennadi Liakhovetski,
Kevin Hilman, jean.pihet
In-Reply-To: <201111140122.27328.rjw@sisk.pl>
From: Rafael J. Wysocki <rjw@sisk.pl>
Make the runtime PM core use device PM QoS constraints to check if
it is allowed to suspend a given device, so that an error code is
returned if the device's own PM QoS constraint is negative or one of
its children has already been suspended for too long. If this is
not the case, the maximum estimated time the device is allowed to be
suspended, computed as the minimum of the device's PM QoS constraint
and the PM QoS constraints of its children (reduced by the difference
between the current time and their suspend times) is stored in a new
device's PM field power.max_time_suspended_ns that can be used by
the device's subsystem or PM domain to decide whether or not to put
the device into lower-power (and presumably higher-latency) states
later (if the constraint is 0, which means "no constraint", the
power.max_time_suspended_ns is set to -1).
Additionally, the time of execution of the subsystem-level
.runtime_suspend() callback for the device is recorded in the new
power.suspend_time field for later use by the device's subsystem or
PM domain along with power.max_time_suspended_ns (it also is used
by the core code when the device's parent is suspended).
Introduce a new helper function,
pm_runtime_update_max_time_suspended(), allowing subsystems and PM
domains (or device drivers) to update the power.max_time_suspended_ns
field, for example after changing the power state of a suspended
device.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/base/power/qos.c | 24 ++++++++----
drivers/base/power/runtime.c | 85 +++++++++++++++++++++++++++++++++++++++++++
include/linux/pm.h | 2 +
include/linux/pm_runtime.h | 5 ++
4 files changed, 108 insertions(+), 8 deletions(-)
Index: linux/include/linux/pm.h
=================================--- linux.orig/include/linux/pm.h
+++ linux/include/linux/pm.h
@@ -482,6 +482,8 @@ struct dev_pm_info {
unsigned long active_jiffies;
unsigned long suspended_jiffies;
unsigned long accounting_timestamp;
+ ktime_t suspend_time;
+ s64 max_time_suspended_ns;
#endif
struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */
struct pm_qos_constraints *constraints;
Index: linux/drivers/base/power/runtime.c
=================================--- linux.orig/drivers/base/power/runtime.c
+++ linux/drivers/base/power/runtime.c
@@ -279,6 +279,38 @@ static int rpm_callback(int (*cb)(struct
return retval != -EACCES ? retval : -EIO;
}
+struct rpm_qos_data {
+ ktime_t time_now;
+ s64 constraint_ns;
+};
+
+/**
+ * rpm_update_qos_constraint - Update a given PM QoS constraint data.
+ * @dev: Device whose timing data to use.
+ * @data: PM QoS constraint data to update.
+ *
+ * Use the suspend timing data of @dev to update PM QoS constraint data pointed
+ * to by @data.
+ */
+static int rpm_update_qos_constraint(struct device *dev, void *data)
+{
+ struct rpm_qos_data *qos = data;
+ s64 delta_ns;
+
+ if (dev->power.max_time_suspended_ns < 0)
+ return 0;
+
+ delta_ns = dev->power.max_time_suspended_ns -
+ ktime_to_ns(ktime_sub(qos->time_now, dev->power.suspend_time));
+ if (delta_ns <= 0)
+ return -EBUSY;
+
+ if (qos->constraint_ns > delta_ns || qos->constraint_ns = 0)
+ qos->constraint_ns = delta_ns;
+
+ return 0;
+}
+
/**
* rpm_suspend - Carry out runtime suspend of given device.
* @dev: Device to suspend.
@@ -305,6 +337,7 @@ static int rpm_suspend(struct device *de
{
int (*callback)(struct device *);
struct device *parent = NULL;
+ struct rpm_qos_data qos;
int retval;
trace_rpm_suspend(dev, rpmflags);
@@ -400,6 +433,25 @@ static int rpm_suspend(struct device *de
goto out;
}
+ qos.constraint_ns = __dev_pm_qos_read_value(dev);
+ if (qos.constraint_ns < 0) {
+ /* Negative constraint means "never suspend". */
+ retval = -EPERM;
+ goto out;
+ }
+ qos.constraint_ns *= NSEC_PER_USEC;
+ qos.time_now = ktime_get();
+
+ if (!dev->power.ignore_children) {
+ retval = device_for_each_child(dev, &qos,
+ rpm_update_qos_constraint);
+ if (retval)
+ goto out;
+ }
+
+ dev->power.suspend_time = qos.time_now;
+ dev->power.max_time_suspended_ns = qos.constraint_ns ? : -1;
+
__update_runtime_status(dev, RPM_SUSPENDING);
if (dev->pm_domain)
@@ -416,6 +468,8 @@ static int rpm_suspend(struct device *de
retval = rpm_callback(callback, dev);
if (retval) {
__update_runtime_status(dev, RPM_ACTIVE);
+ dev->power.suspend_time = ktime_set(0, 0);
+ dev->power.max_time_suspended_ns = -1;
dev->power.deferred_resume = false;
if (retval = -EAGAIN || retval = -EBUSY) {
dev->power.runtime_error = 0;
@@ -620,6 +674,9 @@ static int rpm_resume(struct device *dev
if (dev->power.no_callbacks)
goto no_callback; /* Assume success. */
+ dev->power.suspend_time = ktime_set(0, 0);
+ dev->power.max_time_suspended_ns = -1;
+
__update_runtime_status(dev, RPM_RESUMING);
if (dev->pm_domain)
@@ -1279,6 +1336,9 @@ void pm_runtime_init(struct device *dev)
setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,
(unsigned long)dev);
+ dev->power.suspend_time = ktime_set(0, 0);
+ dev->power.max_time_suspended_ns = -1;
+
init_waitqueue_head(&dev->power.wait_queue);
}
@@ -1296,3 +1356,28 @@ void pm_runtime_remove(struct device *de
if (dev->power.irq_safe && dev->parent)
pm_runtime_put_sync(dev->parent);
}
+
+/**
+ * pm_runtime_update_max_time_suspended - Update device's suspend time data.
+ * @dev: Device to handle.
+ * @delta_ns: Value to subtract from the device's max_time_suspended_ns field.
+ *
+ * Update the device's power.max_time_suspended_ns field by subtracting
+ * @delta_ns from it. The resulting value of power.max_time_suspended_ns is
+ * never negative.
+ */
+void pm_runtime_update_max_time_suspended(struct device *dev, s64 delta_ns)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->power.lock, flags);
+
+ if (delta_ns > 0 && dev->power.max_time_suspended_ns > 0) {
+ if (dev->power.max_time_suspended_ns > delta_ns)
+ dev->power.max_time_suspended_ns -= delta_ns;
+ else
+ dev->power.max_time_suspended_ns = 0;
+ }
+
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+}
Index: linux/include/linux/pm_runtime.h
=================================--- linux.orig/include/linux/pm_runtime.h
+++ linux/include/linux/pm_runtime.h
@@ -45,6 +45,8 @@ extern void pm_runtime_irq_safe(struct d
extern void __pm_runtime_use_autosuspend(struct device *dev, bool use);
extern void pm_runtime_set_autosuspend_delay(struct device *dev, int delay);
extern unsigned long pm_runtime_autosuspend_expiration(struct device *dev);
+extern void pm_runtime_update_max_time_suspended(struct device *dev,
+ s64 delta_ns);
static inline bool pm_children_suspended(struct device *dev)
{
@@ -154,6 +156,9 @@ static inline void pm_runtime_set_autosu
static inline unsigned long pm_runtime_autosuspend_expiration(
struct device *dev) { return 0; }
+static inline void pm_runtime_update_max_time_suspended(struct device *dev,
+ s64 delta_ns) {}
+
#endif /* !CONFIG_PM_RUNTIME */
static inline int pm_runtime_idle(struct device *dev)
Index: linux/drivers/base/power/qos.c
=================================--- linux.orig/drivers/base/power/qos.c
+++ linux/drivers/base/power/qos.c
@@ -47,21 +47,29 @@ static DEFINE_MUTEX(dev_pm_qos_mtx);
static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
/**
- * dev_pm_qos_read_value - Get PM QoS constraint for a given device.
+ * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
+ * @dev: Device to get the PM QoS constraint value for.
+ *
+ * This routine must be called with dev->power.lock held.
+ */
+s32 __dev_pm_qos_read_value(struct device *dev)
+{
+ struct pm_qos_constraints *c = dev->power.constraints;
+
+ return c ? pm_qos_read_value(c) : 0;
+}
+
+/**
+ * dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
* @dev: Device to get the PM QoS constraint value for.
*/
s32 dev_pm_qos_read_value(struct device *dev)
{
- struct pm_qos_constraints *c;
unsigned long flags;
- s32 ret = 0;
+ s32 ret;
spin_lock_irqsave(&dev->power.lock, flags);
-
- c = dev->power.constraints;
- if (c)
- ret = pm_qos_read_value(c);
-
+ ret = __dev_pm_qos_read_value(dev);
spin_unlock_irqrestore(&dev->power.lock, flags);
return ret;
^ permalink raw reply
* [update][PATCH 3/7] PM / Domains: Rework system suspend callback routines
From: Rafael J. Wysocki @ 2011-11-14 0:25 UTC (permalink / raw)
To: Linux PM list
Cc: LKML, Linux-sh list, Magnus Damm, Guennadi Liakhovetski,
Kevin Hilman, jean.pihet
In-Reply-To: <201111140122.27328.rjw@sisk.pl>
From: Rafael J. Wysocki <rjw@sisk.pl>
The current generic PM domains code attempts to use the generic
system suspend operations along with the domains' device stop/start
routines, which requires device drivers to assume that their
system suspend/resume (and hibernation/restore) callbacks will always
be used with generic PM domains. However, in theory, the same
hardware may be used in devices that don't belong to any PM domain,
in which case it would be necessary to add "fake" PM domains to
satisfy the above assumption. Also, the domain the hardware belongs
to may not be handled with the help of the generic code.
To allow device drivers that may be used along with the generic PM
domains code of more flexibility, add new device callbacks, .freeze(),
.freeze_late(), .thaw_early() and .thaw(), that can be supplied by
the drivers in addition to their "standard" system suspend and
hibernation callbacks. These new callbacks, if defined, will be used
by the generic PM domains code for the handling of system suspend and
hibernation instead of the "standard" ones. This will allow drivers
to be designed to work with generic PM domains as well as without
them.
For backwards compatibility, introduce default .freeze(), .thaw(),
.freeze_late() and .thaw_early() callback routines for PM domains that
will execute pm_generic_suspend(), pm_generic_resume(),
pm_generic_suspend_noirq() and pm_generic_resume_noirq(),
respectively, for the given device if its driver doesn't provide its
own implementations of .freeze(), .thaw(), .freeze_late() and
.thaw_early() (this works slightly differently from the current code,
but its existing users don't care anyway).
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/base/power/domain.c | 189 +++++++++++++++++++-------------------------
include/linux/pm_domain.h | 4
2 files changed, 87 insertions(+), 106 deletions(-)
Index: linux/include/linux/pm_domain.h
=================================--- linux.orig/include/linux/pm_domain.h
+++ linux/include/linux/pm_domain.h
@@ -28,6 +28,10 @@ struct gpd_dev_ops {
int (*stop)(struct device *dev);
int (*save_state)(struct device *dev);
int (*restore_state)(struct device *dev);
+ int (*freeze)(struct device *dev);
+ int (*freeze_late)(struct device *dev);
+ int (*thaw_early)(struct device *dev);
+ int (*thaw)(struct device *dev);
bool (*active_wakeup)(struct device *dev);
};
Index: linux/drivers/base/power/domain.c
=================================--- linux.orig/drivers/base/power/domain.c
+++ linux/drivers/base/power/domain.c
@@ -561,6 +561,26 @@ static bool genpd_dev_active_wakeup(stru
return GENPD_DEV_CALLBACK(genpd, bool, active_wakeup, dev);
}
+static int genpd_freeze_dev(struct generic_pm_domain *genpd, struct device *dev)
+{
+ return GENPD_DEV_CALLBACK(genpd, int, freeze, dev);
+}
+
+static int genpd_freeze_late(struct generic_pm_domain *genpd, struct device *dev)
+{
+ return GENPD_DEV_CALLBACK(genpd, int, freeze_late, dev);
+}
+
+static int genpd_thaw_early(struct generic_pm_domain *genpd, struct device *dev)
+{
+ return GENPD_DEV_CALLBACK(genpd, int, thaw_early, dev);
+}
+
+static int genpd_thaw_dev(struct generic_pm_domain *genpd, struct device *dev)
+{
+ return GENPD_DEV_CALLBACK(genpd, int, thaw, dev);
+}
+
/**
* pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
* @genpd: PM domain to power off, if possible.
@@ -695,27 +715,6 @@ static int pm_genpd_prepare(struct devic
}
/**
- * pm_genpd_suspend - Suspend a device belonging to an I/O PM domain.
- * @dev: Device to suspend.
- *
- * Suspend a device under the assumption that its pm_domain field points to the
- * domain member of an object of type struct generic_pm_domain representing
- * a PM domain consisting of I/O devices.
- */
-static int pm_genpd_suspend(struct device *dev)
-{
- struct generic_pm_domain *genpd;
-
- dev_dbg(dev, "%s()\n", __func__);
-
- genpd = dev_to_genpd(dev);
- if (IS_ERR(genpd))
- return -EINVAL;
-
- return genpd->suspend_power_off ? 0 : pm_generic_suspend(dev);
-}
-
-/**
* pm_genpd_suspend_noirq - Late suspend of a device from an I/O PM domain.
* @dev: Device to suspend.
*
@@ -737,7 +736,7 @@ static int pm_genpd_suspend_noirq(struct
if (genpd->suspend_power_off)
return 0;
- ret = pm_generic_suspend_noirq(dev);
+ ret = genpd_freeze_late(genpd, dev);
if (ret)
return ret;
@@ -788,28 +787,7 @@ static int pm_genpd_resume_noirq(struct
genpd->suspended_count--;
genpd_start_dev(genpd, dev);
- return pm_generic_resume_noirq(dev);
-}
-
-/**
- * pm_genpd_resume - Resume a device belonging to an I/O power domain.
- * @dev: Device to resume.
- *
- * Resume a device under the assumption that its pm_domain field points to the
- * domain member of an object of type struct generic_pm_domain representing
- * a power domain consisting of I/O devices.
- */
-static int pm_genpd_resume(struct device *dev)
-{
- struct generic_pm_domain *genpd;
-
- dev_dbg(dev, "%s()\n", __func__);
-
- genpd = dev_to_genpd(dev);
- if (IS_ERR(genpd))
- return -EINVAL;
-
- return genpd->suspend_power_off ? 0 : pm_generic_resume(dev);
+ return genpd_thaw_early(genpd, dev);
}
/**
@@ -830,14 +808,14 @@ static int pm_genpd_freeze(struct device
if (IS_ERR(genpd))
return -EINVAL;
- return genpd->suspend_power_off ? 0 : pm_generic_freeze(dev);
+ return genpd->suspend_power_off ? 0 : genpd_freeze_dev(genpd, dev);
}
/**
* pm_genpd_freeze_noirq - Late freeze of a device from an I/O power domain.
* @dev: Device to freeze.
*
- * Carry out a late freeze of a device under the assumption that its
+ * Carry out a late "freeze" of a device under the assumption that its
* pm_domain field points to the domain member of an object of type
* struct generic_pm_domain representing a power domain consisting of I/O
* devices.
@@ -856,7 +834,7 @@ static int pm_genpd_freeze_noirq(struct
if (genpd->suspend_power_off)
return 0;
- ret = pm_generic_freeze_noirq(dev);
+ ret = genpd_freeze_late(genpd, dev);
if (ret)
return ret;
@@ -869,7 +847,7 @@ static int pm_genpd_freeze_noirq(struct
* pm_genpd_thaw_noirq - Early thaw of a device from an I/O power domain.
* @dev: Device to thaw.
*
- * Carry out an early thaw of a device under the assumption that its
+ * Carry out an early "thaw" of a device under the assumption that its
* pm_domain field points to the domain member of an object of type
* struct generic_pm_domain representing a power domain consisting of I/O
* devices.
@@ -889,7 +867,7 @@ static int pm_genpd_thaw_noirq(struct de
genpd_start_dev(genpd, dev);
- return pm_generic_thaw_noirq(dev);
+ return genpd_thaw_early(genpd, dev);
}
/**
@@ -910,28 +888,7 @@ static int pm_genpd_thaw(struct device *
if (IS_ERR(genpd))
return -EINVAL;
- return genpd->suspend_power_off ? 0 : pm_generic_thaw(dev);
-}
-
-/**
- * pm_genpd_dev_poweroff - Power off a device belonging to an I/O PM domain.
- * @dev: Device to suspend.
- *
- * Power off a device under the assumption that its pm_domain field points to
- * the domain member of an object of type struct generic_pm_domain representing
- * a PM domain consisting of I/O devices.
- */
-static int pm_genpd_dev_poweroff(struct device *dev)
-{
- struct generic_pm_domain *genpd;
-
- dev_dbg(dev, "%s()\n", __func__);
-
- genpd = dev_to_genpd(dev);
- if (IS_ERR(genpd))
- return -EINVAL;
-
- return genpd->suspend_power_off ? 0 : pm_generic_poweroff(dev);
+ return genpd->suspend_power_off ? 0 : genpd_thaw_dev(genpd, dev);
}
/**
@@ -945,7 +902,6 @@ static int pm_genpd_dev_poweroff(struct
static int pm_genpd_dev_poweroff_noirq(struct device *dev)
{
struct generic_pm_domain *genpd;
- int ret;
dev_dbg(dev, "%s()\n", __func__);
@@ -956,10 +912,6 @@ static int pm_genpd_dev_poweroff_noirq(s
if (genpd->suspend_power_off)
return 0;
- ret = pm_generic_poweroff_noirq(dev);
- if (ret)
- return ret;
-
if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
return 0;
@@ -1015,28 +967,7 @@ static int pm_genpd_restore_noirq(struct
genpd->suspended_count--;
genpd_start_dev(genpd, dev);
- return pm_generic_restore_noirq(dev);
-}
-
-/**
- * pm_genpd_restore - Restore a device belonging to an I/O power domain.
- * @dev: Device to resume.
- *
- * Restore a device under the assumption that its pm_domain field points to the
- * domain member of an object of type struct generic_pm_domain representing
- * a power domain consisting of I/O devices.
- */
-static int pm_genpd_restore(struct device *dev)
-{
- struct generic_pm_domain *genpd;
-
- dev_dbg(dev, "%s()\n", __func__);
-
- genpd = dev_to_genpd(dev);
- if (IS_ERR(genpd))
- return -EINVAL;
-
- return genpd->suspend_power_off ? 0 : pm_generic_restore(dev);
+ return genpd_thaw_early(genpd, dev);
}
/**
@@ -1078,18 +1009,14 @@ static void pm_genpd_complete(struct dev
#else
#define pm_genpd_prepare NULL
-#define pm_genpd_suspend NULL
#define pm_genpd_suspend_noirq NULL
#define pm_genpd_resume_noirq NULL
-#define pm_genpd_resume NULL
#define pm_genpd_freeze NULL
#define pm_genpd_freeze_noirq NULL
#define pm_genpd_thaw_noirq NULL
#define pm_genpd_thaw NULL
#define pm_genpd_dev_poweroff_noirq NULL
-#define pm_genpd_dev_poweroff NULL
#define pm_genpd_restore_noirq NULL
-#define pm_genpd_restore NULL
#define pm_genpd_complete NULL
#endif /* CONFIG_PM_SLEEP */
@@ -1361,6 +1288,8 @@ int pm_genpd_remove_callbacks(struct dev
}
EXPORT_SYMBOL_GPL(pm_genpd_remove_callbacks);
+/* Default device callbacks for generic PM domains. */
+
/**
* pm_genpd_default_save_state - Default "save device state" for PM domians.
* @dev: Device to handle.
@@ -1400,6 +1329,50 @@ static int pm_genpd_default_restore_stat
}
/**
+ * pm_genpd_default_freeze - Default "device freeze" for PM domians.
+ * @dev: Device to handle.
+ */
+static int pm_genpd_default_freeze(struct device *dev)
+{
+ int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze;
+
+ return cb ? cb(dev) : pm_generic_suspend(dev);
+}
+
+/**
+ * pm_genpd_default_freeze_late - Default "late device freeze" for PM domians.
+ * @dev: Device to handle.
+ */
+static int pm_genpd_default_freeze_late(struct device *dev)
+{
+ int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late;
+
+ return cb ? cb(dev) : pm_generic_suspend_noirq(dev);
+}
+
+/**
+ * pm_genpd_default_thaw_early - Default "early device thaw" for PM domians.
+ * @dev: Device to handle.
+ */
+static int pm_genpd_default_thaw_early(struct device *dev)
+{
+ int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early;
+
+ return cb ? cb(dev) : pm_generic_resume_noirq(dev);
+}
+
+/**
+ * pm_genpd_default_thaw - Default "device thaw" for PM domians.
+ * @dev: Device to handle.
+ */
+static int pm_genpd_default_thaw(struct device *dev)
+{
+ int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw;
+
+ return cb ? cb(dev) : pm_generic_resume(dev);
+}
+
+/**
* pm_genpd_init - Initialize a generic I/O PM domain object.
* @genpd: PM domain object to initialize.
* @gov: PM domain governor to associate with the domain (may be NULL).
@@ -1429,21 +1402,25 @@ void pm_genpd_init(struct generic_pm_dom
genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
genpd->domain.ops.prepare = pm_genpd_prepare;
- genpd->domain.ops.suspend = pm_genpd_suspend;
+ genpd->domain.ops.suspend = pm_genpd_freeze;
genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq;
genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq;
- genpd->domain.ops.resume = pm_genpd_resume;
+ genpd->domain.ops.resume = pm_genpd_thaw;
genpd->domain.ops.freeze = pm_genpd_freeze;
genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq;
genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq;
genpd->domain.ops.thaw = pm_genpd_thaw;
- genpd->domain.ops.poweroff = pm_genpd_dev_poweroff;
+ genpd->domain.ops.poweroff = pm_genpd_freeze;
genpd->domain.ops.poweroff_noirq = pm_genpd_dev_poweroff_noirq;
genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq;
- genpd->domain.ops.restore = pm_genpd_restore;
+ genpd->domain.ops.restore = pm_genpd_thaw;
genpd->domain.ops.complete = pm_genpd_complete;
genpd->dev_ops.save_state = pm_genpd_default_save_state;
genpd->dev_ops.restore_state = pm_genpd_default_restore_state;
+ genpd->dev_ops.freeze = pm_genpd_default_freeze;
+ genpd->dev_ops.freeze_late = pm_genpd_default_freeze_late;
+ genpd->dev_ops.thaw_early = pm_genpd_default_thaw_early;
+ genpd->dev_ops.thaw = pm_genpd_default_thaw;
mutex_lock(&gpd_list_lock);
list_add(&genpd->gpd_list_node, &gpd_list);
mutex_unlock(&gpd_list_lock);
^ permalink raw reply
* [update][PATCH 2/7] PM / Domains: Introduce "save/restore state" device callbacks
From: Rafael J. Wysocki @ 2011-11-14 0:24 UTC (permalink / raw)
To: Linux PM list
Cc: LKML, Linux-sh list, Magnus Damm, Guennadi Liakhovetski,
Kevin Hilman, jean.pihet
In-Reply-To: <201111140122.27328.rjw@sisk.pl>
From: Rafael J. Wysocki <rjw@sisk.pl>
The current PM domains code uses device drivers' .runtime_suspend()
and .runtime_resume() callbacks as the "save device state" and
"restore device state" operations, which may not be appropriate in
general, because it forces drivers to assume that they always will
be used with generic PM domains. However, in theory, the same
hardware may be used in devices that don't belong to any PM
domain, in which case it would be necessary to add "fake" PM
domains to satisfy the above assumption. It also may be located in
a PM domain that's not handled with the help of the generic code.
To allow device drivers that may be used along with the generic PM
domains code of more flexibility, introduce new device callbacks,
.save_state() and .restore_state(), that can be supplied by the
drivers in addition to their "standard" runtime PM callbacks. This
will allow the drivers to be designed to work with generic PM domains
as well as without them.
For backwards compatibility, introduce default .save_state() and
.restore_state() callback routines for PM domains that will execute
a device driver's .runtime_suspend() and .runtime_resume() callbacks,
respectively, for the given device if the driver doesn't provide its
own implementations of .save_state() and .restore_state().
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/base/power/domain.c | 68 ++++++++++++++++++++++++++++++++++++--------
include/linux/pm_domain.h | 2 +
2 files changed, 58 insertions(+), 12 deletions(-)
Index: linux/include/linux/pm_domain.h
=================================--- linux.orig/include/linux/pm_domain.h
+++ linux/include/linux/pm_domain.h
@@ -26,6 +26,8 @@ struct dev_power_governor {
struct gpd_dev_ops {
int (*start)(struct device *dev);
int (*stop)(struct device *dev);
+ int (*save_state)(struct device *dev);
+ int (*restore_state)(struct device *dev);
bool (*active_wakeup)(struct device *dev);
};
Index: linux/drivers/base/power/domain.c
=================================--- linux.orig/drivers/base/power/domain.c
+++ linux/drivers/base/power/domain.c
@@ -56,6 +56,16 @@ static int genpd_start_dev(struct generi
return GENPD_DEV_CALLBACK(genpd, int, start, dev);
}
+static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev)
+{
+ return GENPD_DEV_CALLBACK(genpd, int, save_state, dev);
+}
+
+static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev)
+{
+ return GENPD_DEV_CALLBACK(genpd, int, restore_state, dev);
+}
+
static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
{
bool ret = false;
@@ -217,7 +227,6 @@ static int __pm_genpd_save_device(struct
{
struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
struct device *dev = pdd->dev;
- struct device_driver *drv = dev->driver;
int ret = 0;
if (gpd_data->need_restore)
@@ -225,11 +234,9 @@ static int __pm_genpd_save_device(struct
mutex_unlock(&genpd->lock);
- if (drv && drv->pm && drv->pm->runtime_suspend) {
- genpd_start_dev(genpd, dev);
- ret = drv->pm->runtime_suspend(dev);
- genpd_stop_dev(genpd, dev);
- }
+ genpd_start_dev(genpd, dev);
+ ret = genpd_save_dev(genpd, dev);
+ genpd_stop_dev(genpd, dev);
mutex_lock(&genpd->lock);
@@ -250,18 +257,15 @@ static void __pm_genpd_restore_device(st
{
struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
struct device *dev = pdd->dev;
- struct device_driver *drv = dev->driver;
if (!gpd_data->need_restore)
return;
mutex_unlock(&genpd->lock);
- if (drv && drv->pm && drv->pm->runtime_resume) {
- genpd_start_dev(genpd, dev);
- drv->pm->runtime_resume(dev);
- genpd_stop_dev(genpd, dev);
- }
+ genpd_start_dev(genpd, dev);
+ genpd_restore_dev(genpd, dev);
+ genpd_stop_dev(genpd, dev);
mutex_lock(&genpd->lock);
@@ -1358,6 +1362,44 @@ int pm_genpd_remove_callbacks(struct dev
EXPORT_SYMBOL_GPL(pm_genpd_remove_callbacks);
/**
+ * pm_genpd_default_save_state - Default "save device state" for PM domians.
+ * @dev: Device to handle.
+ */
+static int pm_genpd_default_save_state(struct device *dev)
+{
+ int (*cb)(struct device *__dev);
+ struct device_driver *drv = dev->driver;
+
+ cb = dev_gpd_data(dev)->ops.save_state;
+ if (cb)
+ return cb(dev);
+
+ if (drv && drv->pm && drv->pm->runtime_suspend)
+ return drv->pm->runtime_suspend(dev);
+
+ return 0;
+}
+
+/**
+ * pm_genpd_default_restore_state - Default PM domians "restore device state".
+ * @dev: Device to handle.
+ */
+static int pm_genpd_default_restore_state(struct device *dev)
+{
+ int (*cb)(struct device *__dev);
+ struct device_driver *drv = dev->driver;
+
+ cb = dev_gpd_data(dev)->ops.restore_state;
+ if (cb)
+ return cb(dev);
+
+ if (drv && drv->pm && drv->pm->runtime_resume)
+ return drv->pm->runtime_resume(dev);
+
+ return 0;
+}
+
+/**
* pm_genpd_init - Initialize a generic I/O PM domain object.
* @genpd: PM domain object to initialize.
* @gov: PM domain governor to associate with the domain (may be NULL).
@@ -1400,6 +1442,8 @@ void pm_genpd_init(struct generic_pm_dom
genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq;
genpd->domain.ops.restore = pm_genpd_restore;
genpd->domain.ops.complete = pm_genpd_complete;
+ genpd->dev_ops.save_state = pm_genpd_default_save_state;
+ genpd->dev_ops.restore_state = pm_genpd_default_restore_state;
mutex_lock(&gpd_list_lock);
list_add(&genpd->gpd_list_node, &gpd_list);
mutex_unlock(&gpd_list_lock);
^ permalink raw reply
* [update][PATCH 1/7] PM / Domains: Make it possible to use per-device domain callbacks
From: Rafael J. Wysocki @ 2011-11-14 0:23 UTC (permalink / raw)
To: Linux PM list
Cc: LKML, Linux-sh list, Magnus Damm, Guennadi Liakhovetski,
Kevin Hilman, jean.pihet
In-Reply-To: <201111140122.27328.rjw@sisk.pl>
From: Rafael J. Wysocki <rjw@sisk.pl>
The current generic PM domains code requires that the same .stop(),
.start() and .active_wakeup() device callback routines be used for
all devices in the given domain, which is inflexible and may not
cover some specific use cases. For this reason, make it possible to
use device specific .start()/.stop() and .active_wakeup() callback
routines by adding corresponding callback pointers to struct
generic_pm_domain_data. Add a new helper routine,
pm_genpd_register_callbacks(), that can be used to populate
the new per-device callback pointers.
Modify the shmobile's power domains code to allow drivers to add
their own code to be run during the device stop and start operations
with the help of the new callback pointers.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
arch/arm/mach-shmobile/pm-sh7372.c | 40 ++++++++-
drivers/base/power/domain.c | 152 +++++++++++++++++++++++++++----------
include/linux/pm_domain.h | 27 +++++-
3 files changed, 175 insertions(+), 44 deletions(-)
Index: linux/include/linux/pm_domain.h
=================================--- linux.orig/include/linux/pm_domain.h
+++ linux/include/linux/pm_domain.h
@@ -23,6 +23,12 @@ struct dev_power_governor {
bool (*power_down_ok)(struct dev_pm_domain *domain);
};
+struct gpd_dev_ops {
+ int (*start)(struct device *dev);
+ int (*stop)(struct device *dev);
+ bool (*active_wakeup)(struct device *dev);
+};
+
struct generic_pm_domain {
struct dev_pm_domain domain; /* PM domain operations */
struct list_head gpd_list_node; /* Node in the global PM domains list */
@@ -45,9 +51,7 @@ struct generic_pm_domain {
bool dev_irq_safe; /* Device callbacks are IRQ-safe */
int (*power_off)(struct generic_pm_domain *domain);
int (*power_on)(struct generic_pm_domain *domain);
- int (*start_device)(struct device *dev);
- int (*stop_device)(struct device *dev);
- bool (*active_wakeup)(struct device *dev);
+ struct gpd_dev_ops dev_ops;
};
static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
@@ -64,6 +68,7 @@ struct gpd_link {
struct generic_pm_domain_data {
struct pm_domain_data base;
+ struct gpd_dev_ops ops;
bool need_restore;
};
@@ -72,6 +77,11 @@ static inline struct generic_pm_domain_d
return container_of(pdd, struct generic_pm_domain_data, base);
}
+static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev)
+{
+ return to_gpd_data(dev->power.subsys_data->domain_data);
+}
+
#ifdef CONFIG_PM_GENERIC_DOMAINS
extern int pm_genpd_add_device(struct generic_pm_domain *genpd,
struct device *dev);
@@ -81,6 +91,8 @@ extern int pm_genpd_add_subdomain(struct
struct generic_pm_domain *new_subdomain);
extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
struct generic_pm_domain *target);
+extern int pm_genpd_add_callbacks(struct device *dev, struct gpd_dev_ops *ops);
+extern int pm_genpd_remove_callbacks(struct device *dev);
extern void pm_genpd_init(struct generic_pm_domain *genpd,
struct dev_power_governor *gov, bool is_off);
extern int pm_genpd_poweron(struct generic_pm_domain *genpd);
@@ -105,6 +117,15 @@ static inline int pm_genpd_remove_subdom
{
return -ENOSYS;
}
+static inline int pm_genpd_add_callbacks(struct device *dev,
+ struct gpd_dev_ops *ops)
+{
+ return -ENOSYS;
+}
+static inline int pm_genpd_remove_callbacks(struct device *dev)
+{
+ return -ENOSYS;
+}
static inline void pm_genpd_init(struct generic_pm_domain *genpd,
struct dev_power_governor *gov, bool is_off) {}
static inline int pm_genpd_poweron(struct generic_pm_domain *genpd)
Index: linux/drivers/base/power/domain.c
=================================--- linux.orig/drivers/base/power/domain.c
+++ linux/drivers/base/power/domain.c
@@ -15,6 +15,23 @@
#include <linux/err.h>
#include <linux/sched.h>
#include <linux/suspend.h>
+#include <linux/export.h>
+
+#define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \
+({ \
+ type (*__routine)(struct device *__d); \
+ type __ret = (type)0; \
+ \
+ __routine = genpd->dev_ops.callback; \
+ if (__routine) { \
+ __ret = __routine(dev); \
+ } else { \
+ __routine = dev_gpd_data(dev)->ops.callback; \
+ if (__routine) \
+ __ret = __routine(dev); \
+ } \
+ __ret; \
+})
static LIST_HEAD(gpd_list);
static DEFINE_MUTEX(gpd_list_lock);
@@ -29,6 +46,16 @@ static struct generic_pm_domain *dev_to_
return pd_to_genpd(dev->pm_domain);
}
+static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev)
+{
+ return GENPD_DEV_CALLBACK(genpd, int, stop, dev);
+}
+
+static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev)
+{
+ return GENPD_DEV_CALLBACK(genpd, int, start, dev);
+}
+
static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
{
bool ret = false;
@@ -199,13 +226,9 @@ static int __pm_genpd_save_device(struct
mutex_unlock(&genpd->lock);
if (drv && drv->pm && drv->pm->runtime_suspend) {
- if (genpd->start_device)
- genpd->start_device(dev);
-
+ genpd_start_dev(genpd, dev);
ret = drv->pm->runtime_suspend(dev);
-
- if (genpd->stop_device)
- genpd->stop_device(dev);
+ genpd_stop_dev(genpd, dev);
}
mutex_lock(&genpd->lock);
@@ -235,13 +258,9 @@ static void __pm_genpd_restore_device(st
mutex_unlock(&genpd->lock);
if (drv && drv->pm && drv->pm->runtime_resume) {
- if (genpd->start_device)
- genpd->start_device(dev);
-
+ genpd_start_dev(genpd, dev);
drv->pm->runtime_resume(dev);
-
- if (genpd->stop_device)
- genpd->stop_device(dev);
+ genpd_stop_dev(genpd, dev);
}
mutex_lock(&genpd->lock);
@@ -413,6 +432,7 @@ static void genpd_power_off_work_fn(stru
static int pm_genpd_runtime_suspend(struct device *dev)
{
struct generic_pm_domain *genpd;
+ int ret;
dev_dbg(dev, "%s()\n", __func__);
@@ -422,11 +442,9 @@ static int pm_genpd_runtime_suspend(stru
might_sleep_if(!genpd->dev_irq_safe);
- if (genpd->stop_device) {
- int ret = genpd->stop_device(dev);
- if (ret)
- return ret;
- }
+ ret = genpd_stop_dev(genpd, dev);
+ if (ret)
+ return ret;
/*
* If power.irq_safe is set, this routine will be run with interrupts
@@ -502,8 +520,7 @@ static int pm_genpd_runtime_resume(struc
mutex_unlock(&genpd->lock);
out:
- if (genpd->start_device)
- genpd->start_device(dev);
+ genpd_start_dev(genpd, dev);
return 0;
}
@@ -534,6 +551,12 @@ static inline void genpd_power_off_work_
#ifdef CONFIG_PM_SLEEP
+static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
+ struct device *dev)
+{
+ return GENPD_DEV_CALLBACK(genpd, bool, active_wakeup, dev);
+}
+
/**
* pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
* @genpd: PM domain to power off, if possible.
@@ -590,7 +613,7 @@ static bool resume_needed(struct device
if (!device_can_wakeup(dev))
return false;
- active_wakeup = genpd->active_wakeup && genpd->active_wakeup(dev);
+ active_wakeup = genpd_dev_active_wakeup(genpd, dev);
return device_may_wakeup(dev) ? active_wakeup : !active_wakeup;
}
@@ -646,7 +669,7 @@ static int pm_genpd_prepare(struct devic
/*
* The PM domain must be in the GPD_STATE_ACTIVE state at this point,
* so pm_genpd_poweron() will return immediately, but if the device
- * is suspended (e.g. it's been stopped by .stop_device()), we need
+ * is suspended (e.g. it's been stopped by genpd_stop_dev()), we need
* to make it operational.
*/
pm_runtime_resume(dev);
@@ -714,12 +737,10 @@ static int pm_genpd_suspend_noirq(struct
if (ret)
return ret;
- if (dev->power.wakeup_path
- && genpd->active_wakeup && genpd->active_wakeup(dev))
+ if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
return 0;
- if (genpd->stop_device)
- genpd->stop_device(dev);
+ genpd_stop_dev(genpd, dev);
/*
* Since all of the "noirq" callbacks are executed sequentially, it is
@@ -761,8 +782,7 @@ static int pm_genpd_resume_noirq(struct
*/
pm_genpd_poweron(genpd);
genpd->suspended_count--;
- if (genpd->start_device)
- genpd->start_device(dev);
+ genpd_start_dev(genpd, dev);
return pm_generic_resume_noirq(dev);
}
@@ -836,8 +856,7 @@ static int pm_genpd_freeze_noirq(struct
if (ret)
return ret;
- if (genpd->stop_device)
- genpd->stop_device(dev);
+ genpd_stop_dev(genpd, dev);
return 0;
}
@@ -864,8 +883,7 @@ static int pm_genpd_thaw_noirq(struct de
if (genpd->suspend_power_off)
return 0;
- if (genpd->start_device)
- genpd->start_device(dev);
+ genpd_start_dev(genpd, dev);
return pm_generic_thaw_noirq(dev);
}
@@ -938,12 +956,10 @@ static int pm_genpd_dev_poweroff_noirq(s
if (ret)
return ret;
- if (dev->power.wakeup_path
- && genpd->active_wakeup && genpd->active_wakeup(dev))
+ if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
return 0;
- if (genpd->stop_device)
- genpd->stop_device(dev);
+ genpd_stop_dev(genpd, dev);
/*
* Since all of the "noirq" callbacks are executed sequentially, it is
@@ -993,8 +1009,7 @@ static int pm_genpd_restore_noirq(struct
pm_genpd_poweron(genpd);
genpd->suspended_count--;
- if (genpd->start_device)
- genpd->start_device(dev);
+ genpd_start_dev(genpd, dev);
return pm_generic_restore_noirq(dev);
}
@@ -1280,6 +1295,69 @@ int pm_genpd_remove_subdomain(struct gen
}
/**
+ * pm_genpd_add_callbacks - Add PM domain callbacks to a given device.
+ * @dev: Device to add the callbacks to.
+ * @ops: Set of callbacks to add.
+ */
+int pm_genpd_add_callbacks(struct device *dev, struct gpd_dev_ops *ops)
+{
+ struct pm_domain_data *pdd;
+ int ret = 0;
+
+ if (!(dev && dev->power.subsys_data && ops))
+ return -EINVAL;
+
+ pm_runtime_disable(dev);
+ device_pm_lock();
+
+ pdd = dev->power.subsys_data->domain_data;
+ if (pdd) {
+ struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
+
+ gpd_data->ops = *ops;
+ } else {
+ ret = -EINVAL;
+ }
+
+ device_pm_unlock();
+ pm_runtime_enable(dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pm_genpd_add_callbacks);
+
+/**
+ * pm_genpd_remove_callbacks - Remove PM domain callbacks from a given device.
+ * @dev: Device to remove the callbacks from.
+ */
+int pm_genpd_remove_callbacks(struct device *dev)
+{
+ struct pm_domain_data *pdd;
+ int ret = 0;
+
+ if (!(dev && dev->power.subsys_data))
+ return -EINVAL;
+
+ pm_runtime_disable(dev);
+ device_pm_lock();
+
+ pdd = dev->power.subsys_data->domain_data;
+ if (pdd) {
+ struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
+
+ gpd_data->ops = (struct gpd_dev_ops){ 0 };
+ } else {
+ ret = -EINVAL;
+ }
+
+ device_pm_unlock();
+ pm_runtime_enable(dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pm_genpd_remove_callbacks);
+
+/**
* pm_genpd_init - Initialize a generic I/O PM domain object.
* @genpd: PM domain object to initialize.
* @gov: PM domain governor to associate with the domain (may be NULL).
Index: linux/arch/arm/mach-shmobile/pm-sh7372.c
=================================--- linux.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux/arch/arm/mach-shmobile/pm-sh7372.c
@@ -156,7 +156,10 @@ static void sh7372_a4r_suspend(void)
static bool pd_active_wakeup(struct device *dev)
{
- return true;
+ bool (*active_wakeup)(struct device *dev);
+
+ active_wakeup = dev_gpd_data(dev)->ops.active_wakeup;
+ return active_wakeup ? active_wakeup(dev) : true;
}
static bool sh7372_power_down_forbidden(struct dev_pm_domain *domain)
@@ -168,15 +171,44 @@ struct dev_power_governor sh7372_always_
.power_down_ok = sh7372_power_down_forbidden,
};
+static int sh7372_stop_dev(struct device *dev)
+{
+ int (*stop)(struct device *dev);
+
+ stop = dev_gpd_data(dev)->ops.stop;
+ if (stop) {
+ int ret = stop(dev);
+ if (ret)
+ return ret;
+ }
+ return pm_clk_suspend(dev);
+}
+
+static int sh7372_start_dev(struct device *dev)
+{
+ int (*start)(struct device *dev);
+ int ret;
+
+ ret = pm_clk_resume(dev);
+ if (ret)
+ return ret;
+
+ start = dev_gpd_data(dev)->ops.start;
+ if (start)
+ ret = start(dev);
+
+ return ret;
+}
+
void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd)
{
struct generic_pm_domain *genpd = &sh7372_pd->genpd;
pm_genpd_init(genpd, sh7372_pd->gov, false);
- genpd->stop_device = pm_clk_suspend;
- genpd->start_device = pm_clk_resume;
+ genpd->dev_ops.stop = sh7372_stop_dev;
+ genpd->dev_ops.start = sh7372_start_dev;
+ genpd->dev_ops.active_wakeup = pd_active_wakeup;
genpd->dev_irq_safe = true;
- genpd->active_wakeup = pd_active_wakeup;
genpd->power_off = pd_power_down;
genpd->power_on = pd_power_up;
__pd_power_up(sh7372_pd, false);
^ permalink raw reply
* [update][PATCH 0/7] PM / Domains: Per-device callbacks and PM QoS
From: Rafael J. Wysocki @ 2011-11-14 0:22 UTC (permalink / raw)
To: Linux PM list
Cc: LKML, Linux-sh list, Magnus Damm, Guennadi Liakhovetski,
Kevin Hilman, jean.pihet
In-Reply-To: <201111070101.33960.rjw@sisk.pl>
Hi,
This is the second iteration of the patchset introducing per-device callbacks
and PM QoS support to PM domains.
All patches have been updated, the second one have been folded into the
first one and there's one more patch in the series. Please look into the
changelogs for more details.
[1/7] - Make it possible to define per-device start/stop and .active_wakeup()
routines.
[2/7] - Introduce "save/restore state" device callbacks.
[3/7] - Introduce per-device PM domain callbacks for system suspend.
[4/7] - Make runtime PM core take device PM QoS constraints into account.
[5/7] - Add device "stop governor".
[6/7] - Add domain "power off governor".
[7/7] - Automatically update overoptimistic latency information.
The patchset have been tested for backwards compatibility, but it still needs
some testing for the new features it adds.
Thanks,
Rafael
^ permalink raw reply
* Re: [PATCH] ARM: mach-shmobile: sh7372 A4R suspend/resume order fix
From: Rafael J. Wysocki @ 2011-11-11 11:58 UTC (permalink / raw)
To: linux-sh
In-Reply-To: <20110927085408.27727.59395.sendpatchset@w520>
On Friday, November 11, 2011, Magnus Damm wrote:
> > From: Rafael J. Wysocki <rjw@sisk.pl>
> > Subject: PM / shmobile: Avoid restoring the INTCS state during initialization
> >
> > The SH7372 PM domain initialization routine calls pd_power_up()
> > that executes the domain's .resume() callback, if present, and for
> > the A4R domain this callback attepmts to restore the INTCS state from
> > uninitialized data. To avoid that, introduce __pd_power_up() that
> > will only execute the domain's .resume() callback if its second
> > argument is 'true' and make the SH7372 PM domain initialization
> > use it with 'false' as its second argument. Redefine pd_power_up()
> > as a wrapper around __pd_power_up().
> >
> > Reported-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
>
> Looks fine to me, from my point of view your implementation is better
> than the other alternatives.
>
> It is correct that Guennadi reported this issue, and the Signed-off
> clearly shows that this specific implementation is coming from you. I
> suppose there are more important things in life than git attribution,
> but I do feel that I did spend a significant amount of time tracking
> down this issue, writing the initial patch and then also communicating
> with you guys. I may be wrong, but I suspect that if didn't do this
> then this issue wouldn't have been fixed.
>
> Unfortunately there does not seem to be any tag for that kind of work,
> but if it existed then I would prefer to add this in between you and
> Guennadi:
>
> Tracked-down-by: Magnus Damm <damm@opensource.se>
OK
I'll add your ack too, if you don't mind. :-)
Thanks,
Rafael
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox