LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] PowerPC 440EPx Sequoia USB OHCI DTS entry
From: Valentine Barshak @ 2007-10-23 17:18 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: linuxppc-dev, linux-usb-devel
In-Reply-To: <e1b19c12c7006e763a56627fa9a05ec9@kernel.crashing.org>

Segher Boessenkool wrote:
>> +            compatible = "ohci-be";
> 
> Can we fix this please, in the same way as with EHCI?  I.e., the
> "compatible" should say it is USB, e.g. "usb-ohci"; and the
> "big-endian" quirkiness should be expressed by a property, not by
> the "compatible" name (since that would lead to exponential
> explosion of all possible combinations of quirks, if nothing else).
> 
> 
> Segher
> 
I was thinking about it too.
We need to fix the OHCI OF driver and all its users' dts files (if any).
Actually I also don't see much reason for the 
USB_OHCI_HCD_PPC_OF_BE/USB_OHCI_HCD_PPC_OF_LE stuff.
Is this really needed?
Thanks,
Valentine.

^ permalink raw reply

* Re: FDT bindings for I2C devices
From: Scott Wood @ 2007-10-23 18:30 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-embedded
In-Reply-To: <fa686aa40710190738q1211a266lced10ac8767e5071@mail.gmail.com>

Grant Likely wrote:
> Scott Wood made an attempt at defining a device binding for I2C
> devices, but it has not been merged into booting-without-of.txt yet.
> I've copied what he wrote below.  I would add to his definition the
> following:
> - If compatible is missing, driver should *not* fall back to the device name.
> - 'compatible' list should include the exact device in the form "<mfg>,<part>"

Those are good recommendations for any node, but I don't see why i2c in 
particular should mandate it.

-Scott

^ permalink raw reply

* Ocotea board?
From: Jeff Mock @ 2007-10-23 18:13 UTC (permalink / raw)
  To: linuxppc-dev, linuxppc-embedded

Is the Ocotea board (the original 440GX eval board) still interesting? 
I'm wrapping up a project using the 440GX, I started out hacking on the 
Ocotea board to get started, but we moved off Ocotea long ago onto our 
own hardware.

I'm cleaning up the lab now that the project is nearly finished and I 
would like to give the board to someone that will put it to good use. 
I've sponged off this mailing list quite a lot, it's about time I give a 
little something back.

The board has been hacked a little bit but still works fine.  I just 
powered it up and it happily booted Linux via TFTP.  The boot ROM now 
has u-boot, the original PIBs (or whatever) is long gone. All I ask is 
that you're self-sufficient and don't bug me too much about it...

Can someone recommend a good home?  Otherwise it will wind up in 
storeroom purgatory.

jeff

^ permalink raw reply

* Re: [PATCH] Use the new sg_page() helper
From: Jens Axboe @ 2007-10-23 18:40 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: chris, grundler, linux-kernel, Emil Medve, kyle, linuxppc-dev,
	paulus, anil.s.keshavamurthy, shaohua.li, linux-arm-kernel,
	parisc-linux, ashok.raj
In-Reply-To: <alpine.LFD.0.999.0710230956330.30120@woody.linux-foundation.org>

On Tue, Oct 23 2007, Linus Torvalds wrote:
> 
> 
> On Tue, 23 Oct 2007, Emil Medve wrote:
> >
> > Fix build error messages such as this:
> 
> Some - but apparently not all - of these are already fixed in my tree, 
> through pulls from Jens. I just pushed out the result, can you resend the 
> parts that didn't already get fixed?
> 
> As is, the patch won't apply for me, since it touches many different parts 
> and some of them are fixed.

Looks like just the mmc and xtensa bits, I've merged those up.

-- 
Jens Axboe

^ permalink raw reply

* C67x00 driver and usb keyboard
From: Robertson, Joseph M. @ 2007-10-23 18:43 UTC (permalink / raw)
  To: linuxppc-embedded

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

Hi,

I have everything in the kernel about usb that will compile turned on.  HID, input, mousedev, keybdev, usbcore, c67x00, usbhid.   And yet a keyboard or mouse does not work.  USB memory keys work fine.

c67x00 detects keyboard and mouse, I get messages telling me the correct devices.  But no key strokes or mouse input.  Even cat /dev/input/mice gets nothing.

Kinda getting real tired of everyone saying it should 'just work'.  
Theres a way and a reason how the keyboard works, and something isn't right, it does not work.

Anyone ever have a similar problem?

Thanks,

Joe Robertson
Joseph.Robertson@sanmina-sci.com


CONFIDENTIALITY
This e-mail message and any attachments thereto, is intended only for use by the addressee(s) named herein and may contain legally privileged and/or confidential information. If you are not the intended recipient of this e-mail message, you are hereby notified that any dissemination, distribution or copying of this e-mail message, and any attachments thereto, is strictly prohibited.  If you have received this e-mail message in error, please immediately notify the sender and permanently delete the original and any copies of this email and any prints thereof.
ABSENT AN EXPRESS STATEMENT TO THE CONTRARY HEREINABOVE, THIS E-MAIL IS NOT INTENDED AS A SUBSTITUTE FOR A WRITING.  Notwithstanding the Uniform Electronic Transactions Act or the applicability of any other law of similar substance and effect, absent an express statement to the contrary hereinabove, this e-mail message its contents, and any attachments hereto are not intended to represent an offer or acceptance to enter into a contract and are not otherwise intended to bind the sender, Sanmina-SCI Corporation (or any of its subsidiaries), or any other person or entity.

[-- Attachment #2: Type: text/html, Size: 2291 bytes --]

^ permalink raw reply

* Re: [PATCH] [POWERPC] Fix fallout from sg_page changes
From: Jens Axboe @ 2007-10-23 18:44 UTC (permalink / raw)
  To: Dale Farnsworth; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20071023145300.GA18989@xyzzy.farnsworth.org>

On Tue, Oct 23 2007, Dale Farnsworth wrote:
> 
> Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
> ---
>  include/asm-powerpc/dma-mapping.h |   10 +++++-----
>  1 files changed, 5 insertions(+), 5 deletions(-)

Should already be merged in Linus' current tree.

-- 
Jens Axboe

^ permalink raw reply

* Re: DMA problem - mpc8xx
From: Scott Wood @ 2007-10-23 18:49 UTC (permalink / raw)
  To: raul.moreno; +Cc: linuxppc-embedded
In-Reply-To: <OF0ED90B65.60296006-ONC125737D.0028DB92-C125737D.002A55F3@abengoa.com>

raul.moreno@telvent.abengoa.com wrote:
> Hi everybody,
> 
> I am having problems with the serial cpm driver in a mpc866. But I've found
> out that my problem comes from the DMA and not really from the driver.  The
> Rx and Tx buffers use the DMA and then the sytem hangs. However, if I set
> these buffers to internal ram memory (DPRAM), it works. The DMA address is
> configured with a kernel parameter in advance setup:
> CONFIG_CONSISTENT_START (and the size in CONFIG_CONSISTENT_SIZE), but I
> don't know what they are exactly and I could not find a right documentation
> about it.
> I saw a pair of mailing list where some guys set the
> CONFIG_CONSISTENT_START to 0xff100000, but my driver continues failing (and
> an error about dma-mapping appears in the boot).

What kernel version?  arch/ppc or arch/powerpc?  What is the error about 
dma-mapping that you get?  What does your memory map look like (in 
particular, is there anything that might be getting mapped in conflict 
with the consistent area at 0xff100000)?

-Scott

^ permalink raw reply

* Re: FDT bindings for I2C devices
From: Grant Likely @ 2007-10-23 18:50 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-embedded
In-Reply-To: <471E3DD8.4060508@freescale.com>

On 10/23/07, Scott Wood <scottwood@freescale.com> wrote:
> Grant Likely wrote:
> > Scott Wood made an attempt at defining a device binding for I2C
> > devices, but it has not been merged into booting-without-of.txt yet.
> > I've copied what he wrote below.  I would add to his definition the
> > following:
> > - If compatible is missing, driver should *not* fall back to the device name.
> > - 'compatible' list should include the exact device in the form "<mfg>,<part>"
>
> Those are good recommendations for any node, but I don't see why i2c in
> particular should mandate it.

I only mention it because the example given doesn't show that.

g.


-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195

^ permalink raw reply

* Re: Kernel function having physical address. how?
From: Scott Wood @ 2007-10-23 18:51 UTC (permalink / raw)
  To: Barisa Kisku; +Cc: linuxppc-embedded
In-Reply-To: <80bb1bc60710230322t17fa517bt324031195abced24@mail.gmail.com>

Barisa Kisku wrote:
> I have  ported linux-2.6.20 in cutom board based on MPC860.Kernel
> with the KERNELBASE as default 0xc00000000. uImage is downloaded at
> some address and booted with "bootm" command.Kernel is uncompressed
> and  loaded at 0x00000000.All  the kernel function is now having
> physical address (e.g.  0x000020c8 instead of 0xc00020c8, which is
> given by compiler).I think this required, to run kernel before MMU is
>  on, but how  this change in assembled code happens.

There is no change in the code itself -- the kernel is merely careful to 
avoid (or fix up) data references before the MMU is turned on (which 
happens quite early).

> Does u-boot do
> this when uncompressing and loading the kernel.

No.

-Scott

^ permalink raw reply

* Re: [PATCH v6 resend 9/9] add MPC837x MDS board default device tree
From: Scott Wood @ 2007-10-23 19:02 UTC (permalink / raw)
  To: Li Yang-r58472; +Cc: linuxppc-dev, paulus
In-Reply-To: <989B956029373F45A0B8AF0297081890019B5BD6@zch01exm26.fsl.freescale.net>

On Thu, Oct 18, 2007 at 11:10:43PM +0800, Li Yang-r58472 wrote:
> Do we still need address-cell and size-cell even when it has no child
> node?

Maybe not *need*, but we do want it...  it makes it less likely to be
screwed up if someone adds a child node in the future.

-Scott

^ permalink raw reply

* Re: Device trees and audio codecs
From: Scott Wood @ 2007-10-23 19:12 UTC (permalink / raw)
  To: Timur Tabi; +Cc: PowerPC dev list
In-Reply-To: <471CA082.1050304@freescale.com>

On Mon, Oct 22, 2007 at 08:07:14AM -0500, Timur Tabi wrote:
> Either you do it at driver __init time, or via a probe.  The probe 
> actually occurs at __init time, anyway, so they're kinda the same thing. 
>   The only thing the probe gets you is that you're called multiple times 
> for each instance of a node in the tree.

It also means that you're *not* called if there's no node in the tree at all
-- which I believe was Jon's point about being platform specific.

-Scott

^ permalink raw reply

* Re: [PATCH] [POWERPC] Fix fallout from sg_page changes
From: Dale Farnsworth @ 2007-10-23 19:15 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-kernel, linuxppc-dev
In-Reply-To: <20071023184448.GE14671@kernel.dk>

On Tue, Oct 23, 2007 at 08:44:48PM +0200, Jens Axboe wrote:
> On Tue, Oct 23 2007, Dale Farnsworth wrote:
> > 
> > Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
> > ---
> >  include/asm-powerpc/dma-mapping.h |   10 +++++-----
> >  1 files changed, 5 insertions(+), 5 deletions(-)
> 
> Should already be merged in Linus' current tree.

Yes, it is.  Thank you.

-Dale

^ permalink raw reply

* [PATCH] [POWERPC] Fix mv643xx_pci sysfs .read and .write functions
From: Dale Farnsworth @ 2007-10-23 19:20 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

Commit 91a69029 introduced an additional parameter to the .read and .write
methods for sysfs binary attributes.  Two mv64x60_pci functions
were missed in that patch, resulting in these errors:
	/cache/git/linux-2.6/arch/powerpc/sysdev/mv64x60_pci.c:77: warning: initialization from incompatible pointer type
	/cache/git/linux-2.6/arch/powerpc/sysdev/mv64x60_pci.c:78: warning: initialization from incompatible pointer type

Add the missing "struct bin_attribute *" parameter.

Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
---
 arch/powerpc/sysdev/mv64x60_pci.c |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/sysdev/mv64x60_pci.c b/arch/powerpc/sysdev/mv64x60_pci.c
index 9b3baa7..6933f9c 100644
--- a/arch/powerpc/sysdev/mv64x60_pci.c
+++ b/arch/powerpc/sysdev/mv64x60_pci.c
@@ -24,8 +24,9 @@
 #define MV64X60_VAL_LEN_MAX		11
 #define MV64X60_PCICFG_CPCI_HOTSWAP	0x68
 
-static ssize_t mv64x60_hs_reg_read(struct kobject *kobj, char *buf, loff_t off,
-				   size_t count)
+static ssize_t mv64x60_hs_reg_read(struct kobject *kobj,
+				   struct bin_attribute *attr, char *buf,
+				   loff_t off, size_t count)
 {
 	struct pci_dev *phb;
 	u32 v;
@@ -44,8 +45,9 @@ static ssize_t mv64x60_hs_reg_read(struct kobject *kobj, char *buf, loff_t off,
 	return sprintf(buf, "0x%08x\n", v);
 }
 
-static ssize_t mv64x60_hs_reg_write(struct kobject *kobj, char *buf, loff_t off,
-				    size_t count)
+static ssize_t mv64x60_hs_reg_write(struct kobject *kobj,
+				    struct bin_attribute *attr, char *buf,
+				    loff_t off, size_t count)
 {
 	struct pci_dev *phb;
 	u32 v;
-- 
1.5.3.4

^ permalink raw reply related

* Re: [PATCH] windfarm: fix windfarm thread freezer interaction
From: Rafael J. Wysocki @ 2007-10-23 20:17 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Paul Mackerras, linuxppc-dev list
In-Reply-To: <1193142822.7733.3.camel@johannes.berg>

On Tuesday, 23 October 2007 14:33, Johannes Berg wrote:
> When I fixed the windfarm freezer interaction first in commit
> 1ed2ddf380e19dafeec2150ca709ef7f4a67cd21, an earlier patch than the one
> I came up with after comments was committed. This has come back to haunt
> us now because commit d5d8c5976d6adeddb8208c240460411e2198b393 changed
> the freezer to no long send signals. Fix it by removing the windfarm
> thread's signal logic and restoring the original try_to_freeze().
> 
> We could simply revert 1ed2ddf380e19dafeec2150ca709ef7f4a67cd21 now
> but I feel that the assertion that no signal is delivered to the
> windfarm thread needs not be there.
> 
> Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

Acked-by: Rafael J. Wysocki <rjw@sisk.pl>

> ---
>  drivers/macintosh/windfarm_core.c |   10 +++-------
>  1 file changed, 3 insertions(+), 7 deletions(-)
> 
> --- linux-2.6-git.orig/drivers/macintosh/windfarm_core.c	2007-10-23 14:23:02.406437623 +0200
> +++ linux-2.6-git/drivers/macintosh/windfarm_core.c	2007-10-23 14:25:28.745447695 +0200
> @@ -94,7 +94,9 @@ static int wf_thread_func(void *data)
>  	DBG("wf: thread started\n");
>  
>  	set_freezable();
> -	while(!kthread_should_stop()) {
> +	while (!kthread_should_stop()) {
> +		try_to_freeze();
> +
>  		if (time_after_eq(jiffies, next)) {
>  			wf_notify(WF_EVENT_TICK, NULL);
>  			if (wf_overtemp) {
> @@ -116,12 +118,6 @@ static int wf_thread_func(void *data)
>  		delay = next - jiffies;
>  		if (delay <= HZ)
>  			schedule_timeout_interruptible(delay);
> -
> -		/* there should be no non-suspend signal, but oh well */
> -		if (signal_pending(current) && !try_to_freeze()) {
> -			printk(KERN_WARNING "windfarm: thread got sigl !\n");
> -			break;
> -		}
>  	}
>  
>  	DBG("wf: thread stopped\n");
> 
> 
> 
> 

^ permalink raw reply

* Re: Ocotea board?
From: Benjamin Herrenschmidt @ 2007-10-23 20:36 UTC (permalink / raw)
  To: Jeff Mock; +Cc: linuxppc-dev, linuxppc-embedded
In-Reply-To: <471E39E0.5070106@mock.com>


On Tue, 2007-10-23 at 11:13 -0700, Jeff Mock wrote:
> Is the Ocotea board (the original 440GX eval board) still interesting? 
> I'm wrapping up a project using the 440GX, I started out hacking on the 
> Ocotea board to get started, but we moved off Ocotea long ago onto our 
> own hardware.
> 
> I'm cleaning up the lab now that the project is nearly finished and I 
> would like to give the board to someone that will put it to good use. 
> I've sponged off this mailing list quite a lot, it's about time I give a 
> little something back.

Well, the ocotea has an interesting "feature" related to the way the
ethernet PHY an EMAC interact which I haven't dealt with in the new EMAC
driver at this stage.

I -think- the Taishan I have may have the same issue though, in which
case I won't need it, but if not, I could have good use (or Josh in
Rochester) for one of these.

> The board has been hacked a little bit but still works fine.  I just 
> powered it up and it happily booted Linux via TFTP.  The boot ROM now 
> has u-boot, the original PIBs (or whatever) is long gone. All I ask is 
> that you're self-sufficient and don't bug me too much about it...
> 
> Can someone recommend a good home?  Otherwise it will wind up in 
> storeroom purgatory.
> 
> jeff
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev

^ permalink raw reply

* Re: Ocotea board?
From: Josh Boyer @ 2007-10-23 21:18 UTC (permalink / raw)
  To: benh; +Cc: linuxppc-dev, Jeff Mock, linuxppc-embedded
In-Reply-To: <1193171771.2085.1.camel@pasglop>

On Wed, 24 Oct 2007 06:36:11 +1000
Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:

> 
> On Tue, 2007-10-23 at 11:13 -0700, Jeff Mock wrote:
> > Is the Ocotea board (the original 440GX eval board) still interesting? 
> > I'm wrapping up a project using the 440GX, I started out hacking on the 
> > Ocotea board to get started, but we moved off Ocotea long ago onto our 
> > own hardware.
> > 
> > I'm cleaning up the lab now that the project is nearly finished and I 
> > would like to give the board to someone that will put it to good use. 
> > I've sponged off this mailing list quite a lot, it's about time I give a 
> > little something back.
> 
> Well, the ocotea has an interesting "feature" related to the way the
> ethernet PHY an EMAC interact which I haven't dealt with in the new EMAC
> driver at this stage.
> 
> I -think- the Taishan I have may have the same issue though, in which
> case I won't need it, but if not, I could have good use (or Josh in
> Rochester) for one of these.

Hardware is always welcome.  I actually care about 4xx so if Ben
doesn't want it then I'm sure I could find a good home...

josh

^ permalink raw reply

* [PATCH 1/7] Implement arch disable/enable irq hooks.
From: Scott Wood @ 2007-10-23 21:24 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev

These hooks ensure that a decrementer interrupt is not pending when
suspending; otherwise, problems may occur.  For example, with deep sleep
on the 831x, a pending decrementer will cause a system freeze because the
SoC thinks the decrementer interrupt would have woken the system, but the
core must have interrupts disabled due to the setup required for deep
sleep.

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
Please queue these patches for 2.6.25 if they do not offend.

 arch/powerpc/kernel/time.c    |   41 +++++++++++++++++++++++++++++++++++++++++
 include/asm-powerpc/machdep.h |   13 +++++++++++++
 2 files changed, 54 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 9eb3284..5e2a39b 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -647,6 +647,47 @@ void wakeup_decrementer(void)
 	set_dec(ticks);
 }
 
+#ifdef CONFIG_SUSPEND
+void generic_suspend_disable_irqs(void)
+{
+	preempt_disable();
+
+	/* Disable the decrementer, so that it doesn't interfere
+	 * with suspending.
+	 */
+
+	set_dec(0x7fffffff);
+	hard_irq_disable();
+	set_dec(0x7fffffff);
+}
+
+void generic_suspend_enable_irqs(void)
+{
+	wakeup_decrementer();
+
+	local_irq_enable();
+	preempt_enable();
+}
+
+/* Overrides the weak version in kernel/power/main.c */
+void arch_suspend_disable_irqs(void)
+{
+	if (ppc_md.suspend_disable_irqs)
+		ppc_md.suspend_disable_irqs();
+	else
+		generic_suspend_disable_irqs();
+}
+
+/* Overrides the weak version in kernel/power/main.c */
+void arch_suspend_enable_irqs(void)
+{
+	if (ppc_md.suspend_enable_irqs)
+		ppc_md.suspend_enable_irqs();
+	else
+		generic_suspend_enable_irqs();
+}
+#endif
+
 #ifdef CONFIG_SMP
 void __init smp_space_timers(unsigned int max_cpus)
 {
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index 6968f43..15ba15a 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -253,6 +253,16 @@ struct machdep_calls {
 	 */
 	void (*machine_kexec)(struct kimage *image);
 #endif /* CONFIG_KEXEC */
+
+#ifdef CONFIG_SUSPEND
+	/* These are called to disable and enable, respectively, IRQs when
+	 * entering a suspend state.  If NULL, then the generic versions
+	 * will be called.  The generic versions disable/enable the
+	 * decrementer along with interrupts.
+	 */
+	void (*suspend_disable_irqs)(void);
+	void (*suspend_enable_irqs)(void);
+#endif
 };
 
 extern void power4_idle(void);
@@ -326,5 +336,8 @@ static inline void log_error(char *buf, unsigned int err_type, int fatal)
 		ppc_md.log_error(buf, err_type, fatal);
 }
 
+void generic_suspend_disable_irqs(void);
+void generic_suspend_enable_irqs(void);
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_MACHDEP_H */
-- 
1.5.3.4

^ permalink raw reply related

* [PATCH 2/7] pm: Add TLF_SLEEPING hack to delay interrupt delivery when waking from sleep.
From: Scott Wood @ 2007-10-23 21:24 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20071023212404.GA30942@loki.buserror.net>

The e300 core (and probably most other 6xx chips) can only come out of
sleep mode with an interrupt.  However, interrupts are logically disabled
by the power management layer.

This hack extends the existing doze/nap hack to also suppress the running
of the interrupt handler when in sleep mode.

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
 arch/powerpc/kernel/entry_32.S    |    6 ++--
 arch/powerpc/kernel/idle_6xx.S    |   41 ++++++++++++++++++++++++++++++++++++-
 include/asm-powerpc/thread_info.h |    2 +
 3 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 21d889e..85710b7 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -138,8 +138,8 @@ transfer_to_handler:
 #ifdef CONFIG_6xx
 	tophys(r9,r9)			/* check local flags */
 	lwz	r12,TI_LOCAL_FLAGS(r9)
-	mtcrf	0x01,r12
-	bt-	31-TLF_NAPPING,4f
+	andi.	r8, r12, _TLF_NAPPING | _TLF_SLEEPING
+	bne-	4f
 #endif /* CONFIG_6xx */
 	.globl transfer_to_handler_cont
 transfer_to_handler_cont:
@@ -154,7 +154,7 @@ transfer_to_handler_cont:
 	RFI				/* jump to handler, enable MMU */
 
 #ifdef CONFIG_6xx
-4:	rlwinm	r12,r12,0,~_TLF_NAPPING
+4:	rlwinm	r12,r12,0,~(_TLF_NAPPING | _TLF_SLEEPING)
 	stw	r12,TI_LOCAL_FLAGS(r9)
 	b	power_save_6xx_restore
 #endif
diff --git a/arch/powerpc/kernel/idle_6xx.S b/arch/powerpc/kernel/idle_6xx.S
index 01bcd52..341f474 100644
--- a/arch/powerpc/kernel/idle_6xx.S
+++ b/arch/powerpc/kernel/idle_6xx.S
@@ -147,16 +147,30 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 	isync
 	b	1b
 
+#ifdef CONFIG_SUSPEND
+ret_from_sleep:
+	.long	ret_from_except
+	.long	ret_from_except
+#endif
+
 /*
  * Return from NAP/DOZE mode, restore some CPU specific registers,
  * we are called with DR/IR still off and r2 containing physical
  * address of current.  R11 points to the exception frame (physical
- * address).  We have to preserve r10.
+ * address).  r8 contains _TLF_NAPPING or _TLF_SLEEPING.  We have to
+ * preserve r10.
  */
 _GLOBAL(power_save_6xx_restore)
 	lwz	r9,_LINK(r11)		/* interrupted in ppc6xx_idle: */
+#ifdef CONFIG_SUSPEND
+	andi.	r12, r8, _TLF_SLEEPING
+#endif
 	stw	r9,_NIP(r11)		/* make it do a blr */
 
+#ifdef CONFIG_SUSPEND
+	bne-	sleep_6xx_restore
+#endif
+
 #ifdef CONFIG_SMP
 	mfspr	r12,SPRN_SPRG3
 	lwz	r11,TI_CPU(r12)		/* get cpu number * 4 */
@@ -185,6 +199,31 @@ BEGIN_FTR_SECTION
 END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX)
 	b	transfer_to_handler_cont
 
+#ifdef CONFIG_SUSPEND
+sleep_6xx_restore:
+	/*
+	 * SLEEP mode is invoked through the PM subsystem, which means
+	 * that interrupts should be disabled.  However, the hardware
+	 * requires them to be enabled to wake up.  To prevent the
+	 * interrupt from being visible to Linux, return immediately
+	 * rather than run the interrupt handler.
+	 */
+	lis	r9, ret_from_sleep@h
+	ori	r9, r9, ret_from_sleep@l
+	tophys(r9, r9)
+	mtlr	r9
+
+	/*
+	 * Disable interrupts, so that the interrupt doesn't happen
+	 * again until the PM code sets MSR[EE].
+	 */
+	lwz	r9, _MSR(r11)
+	rlwinm	r9, r9, 0, ~MSR_EE
+	stw	r9, _MSR(r11)
+
+	b	transfer_to_handler_cont
+#endif
+
 	.data
 
 _GLOBAL(nap_save_msscr0)
diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h
index 40d5f98..f7cb48b 100644
--- a/include/asm-powerpc/thread_info.h
+++ b/include/asm-powerpc/thread_info.h
@@ -151,8 +151,10 @@ static inline struct thread_info *current_thread_info(void)
 /* Bits in local_flags */
 /* Don't move TLF_NAPPING without adjusting the code in entry_32.S */
 #define TLF_NAPPING		0	/* idle thread enabled NAP mode */
+#define TLF_SLEEPING		1	/* suspend code enabled SLEEP mode */
 
 #define _TLF_NAPPING		(1 << TLF_NAPPING)
+#define _TLF_SLEEPING		(1 << TLF_SLEEPING)
 
 #endif /* __KERNEL__ */
 
-- 
1.5.3.4

^ permalink raw reply related

* [PATCH 3/7] Add 6xx-style HID0_SLEEP support.
From: Scott Wood @ 2007-10-23 21:24 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20071023212404.GA30942@loki.buserror.net>

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
 arch/powerpc/sysdev/6xx-suspend.S |   52 +++++++++++++++++++++++++++++++++++++
 arch/powerpc/sysdev/Makefile      |    4 +++
 include/asm-powerpc/mpc6xx.h      |    6 ++++
 3 files changed, 62 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/sysdev/6xx-suspend.S
 create mode 100644 include/asm-powerpc/mpc6xx.h

diff --git a/arch/powerpc/sysdev/6xx-suspend.S b/arch/powerpc/sysdev/6xx-suspend.S
new file mode 100644
index 0000000..21cda08
--- /dev/null
+++ b/arch/powerpc/sysdev/6xx-suspend.S
@@ -0,0 +1,52 @@
+/*
+ * Enter and leave sleep state on chips with 6xx-style HID0
+ * power management bits, which don't leave sleep state via reset.
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2006-2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <asm/ppc_asm.h>
+#include <asm/reg.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+
+_GLOBAL(mpc6xx_enter_standby)
+	mflr	r4
+
+	mfspr	r5, SPRN_HID0
+	rlwinm	r5, r5, 0, ~(HID0_DOZE | HID0_NAP)
+	oris	r5, r5, HID0_SLEEP@h
+	mtspr	SPRN_HID0, r5
+	isync
+
+	lis	r5, ret_from_standby@h
+	ori	r5, r5, ret_from_standby@l
+	mtlr	r5
+
+	rlwinm	r5, r1, 0, 0, 31-THREAD_SHIFT
+	lwz	r6, TI_LOCAL_FLAGS(r5)
+	ori	r6, r6, _TLF_SLEEPING
+	stw	r6, TI_LOCAL_FLAGS(r5)
+
+	mfmsr	r5
+	ori	r5, r5, MSR_EE
+	oris	r5, r5, MSR_POW@h
+	sync
+	mtmsr	r5
+	isync
+
+1:	b	1b
+
+ret_from_standby:
+	mfspr	r5, SPRN_HID0
+	rlwinm	r5, r5, 0, ~HID0_SLEEP
+	mtspr	SPRN_HID0, r5
+
+	mtlr	r4
+	blr
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 99a77d7..df2b885 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -37,3 +37,7 @@ obj-$(CONFIG_PPC_DCR)		+= dcr.o
 obj-$(CONFIG_8xx)		+= mpc8xx_pic.o commproc.o
 obj-$(CONFIG_UCODE_PATCH)	+= micropatch.o
 endif
+
+ifeq ($(CONFIG_SUSPEND),y)
+obj-$(CONFIG_6xx)		+= 6xx-suspend.o
+endif
diff --git a/include/asm-powerpc/mpc6xx.h b/include/asm-powerpc/mpc6xx.h
new file mode 100644
index 0000000..effc229
--- /dev/null
+++ b/include/asm-powerpc/mpc6xx.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_POWERPC_MPC6xx_H
+#define __ASM_POWERPC_MPC6xx_H
+
+void mpc6xx_enter_standby(void);
+
+#endif
-- 
1.5.3.4

^ permalink raw reply related

* [PATCH 4/7] fsl_soc: Factor fsl_get_sys_freq() out of the wdt init.
From: Scott Wood @ 2007-10-23 21:24 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20071023212404.GA30942@loki.buserror.net>

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
 arch/powerpc/sysdev/fsl_soc.c |   44 ++++++++++++++++++++++------------------
 arch/powerpc/sysdev/fsl_soc.h |    1 +
 2 files changed, 25 insertions(+), 20 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 3ace747..e1ba33c 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -66,6 +66,27 @@ phys_addr_t get_immrbase(void)
 
 EXPORT_SYMBOL(get_immrbase);
 
+u32 fsl_get_sys_freq(void)
+{
+	struct device_node *soc = of_find_node_by_type(NULL, "soc");
+	const u32 *freq;
+	u32 ret = 0;
+
+	if (!soc)
+		goto err;
+
+	freq = of_get_property(soc, "bus-frequency", NULL);
+	if (!freq)
+		goto err;
+
+	ret = *freq;
+
+err:
+	of_node_put(soc);
+	return ret;
+}
+EXPORT_SYMBOL(fsl_get_sys_freq);
+
 #if defined(CONFIG_CPM2) || defined(CONFIG_8xx)
 
 static u32 brgfreq = -1;
@@ -450,9 +471,9 @@ arch_initcall(fsl_i2c_of_init);
 static int __init mpc83xx_wdt_init(void)
 {
 	struct resource r;
-	struct device_node *soc, *np;
+	struct device_node *np;
 	struct platform_device *dev;
-	const unsigned int *freq;
+	u32 freq = fsl_get_sys_freq();
 	int ret;
 
 	np = of_find_compatible_node(NULL, "watchdog", "mpc83xx_wdt");
@@ -462,19 +483,6 @@ static int __init mpc83xx_wdt_init(void)
 		goto nodev;
 	}
 
-	soc = of_find_node_by_type(NULL, "soc");
-
-	if (!soc) {
-		ret = -ENODEV;
-		goto nosoc;
-	}
-
-	freq = of_get_property(soc, "bus-frequency", NULL);
-	if (!freq) {
-		ret = -ENODEV;
-		goto err;
-	}
-
 	memset(&r, 0, sizeof(r));
 
 	ret = of_address_to_resource(np, 0, &r);
@@ -487,20 +495,16 @@ static int __init mpc83xx_wdt_init(void)
 		goto err;
 	}
 
-	ret = platform_device_add_data(dev, freq, sizeof(int));
+	ret = platform_device_add_data(dev, &freq, sizeof(int));
 	if (ret)
 		goto unreg;
 
-	of_node_put(soc);
 	of_node_put(np);
-
 	return 0;
 
 unreg:
 	platform_device_unregister(dev);
 err:
-	of_node_put(soc);
-nosoc:
 	of_node_put(np);
 nodev:
 	return ret;
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 63e7db3..74c4a96 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -7,6 +7,7 @@
 extern phys_addr_t get_immrbase(void);
 extern u32 get_brgfreq(void);
 extern u32 get_baudrate(void);
+extern u32 fsl_get_sys_freq(void);
 
 struct spi_board_info;
 
-- 
1.5.3.4

^ permalink raw reply related

* [PATCH 6/7] mpc83xx: timer driver for PM wakeup
From: Scott Wood @ 2007-10-23 21:25 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20071023212404.GA30942@loki.buserror.net>

This is a driver for the mpc83xx's GTM4 timer.  It's functionality
is limited to providing a wakeup source for suspend-to-RAM.

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
 arch/powerpc/platforms/83xx/Kconfig  |    9 +
 arch/powerpc/platforms/83xx/Makefile |    1 +
 arch/powerpc/platforms/83xx/timer.c  |  299 ++++++++++++++++++++++++++++++++++
 3 files changed, 309 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/platforms/83xx/timer.c

diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
index 901dbaf..800f547 100644
--- a/arch/powerpc/platforms/83xx/Kconfig
+++ b/arch/powerpc/platforms/83xx/Kconfig
@@ -80,3 +80,12 @@ config PPC_83xx_SUSPEND
 	bool
 	default y
 	depends on PPC_83xx && SUSPEND
+
+config MPC83xx_GTM
+	tristate "83xx General-Purpose Timers for PM wakeup"
+	help
+	  This enables a driver for the GTM4 timer, to be used
+	  as a wakeup source for suspend-to-RAM.  To arm the
+	  timer, write the number of seconds until expiration
+	  to the "timeout" file in the device's sysfs directory.
+	  To disarm, write 0 to the "timeout" file.
diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile
index 944369e..bcc1003 100644
--- a/arch/powerpc/platforms/83xx/Makefile
+++ b/arch/powerpc/platforms/83xx/Makefile
@@ -4,6 +4,7 @@
 obj-y				:= misc.o usb.o
 obj-$(CONFIG_PCI)		+= pci.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o suspend-asm.o
+obj-$(CONFIG_MPC83xx_GTM)	+= timer.o
 obj-$(CONFIG_MPC8313_RDB)	+= mpc8313_rdb.o
 obj-$(CONFIG_MPC832x_RDB)	+= mpc832x_rdb.o
 obj-$(CONFIG_MPC834x_MDS)	+= mpc834x_mds.o
diff --git a/arch/powerpc/platforms/83xx/timer.c b/arch/powerpc/platforms/83xx/timer.c
new file mode 100644
index 0000000..ed7b469
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/timer.c
@@ -0,0 +1,299 @@
+/*
+ * MPC83xx Global Timer4 support
+ *
+ * This driver is currently specific to timer 4 in 16-bit mode,
+ * as that is all that can be used as a wakeup source for deep sleep
+ * on the MPC8313.
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/of_platform.h>
+
+#include <sysdev/fsl_soc.h>
+
+#define MDR_ICLK_DIV16	0x0004
+
+struct gtm_regs {
+	u8    cfr1; /* Timer1/2 Configuration  */
+	#define CFR1_PCAS 0x80 /* Pair Cascade mode  */
+	#define CFR1_BCM  0x40  /* Backward compatible mode  */
+	#define CFR1_STP2 0x20 /* Stop timer  */
+	#define CFR1_RST2 0x10 /* Reset timer  */
+	#define CFR1_GM2  0x08 /* Gate mode for pin 2  */
+	#define CFR1_GM1  0x04 /* Gate mode for pin 1  */
+	#define CFR1_STP1 0x02 /* Stop timer  */
+	#define CFR1_RST1 0x01 /* Reset timer  */
+	#define CFR1_RES ~(CFR1_PCAS | CFR1_STP2 | CFR1_RST2 | CFR1_GM2 |\
+		CFR1_GM1 | CFR1_STP1 | CFR1_RST1)
+
+	u8    res0[3];
+	u8    cfr2; /* Timer3/4 Configuration  */
+	#define CFR2_PCAS 0x80 /* Pair Cascade mode  */
+	#define CFR2_SCAS 0x40 /* Super Cascade mode  */
+	#define CFR2_STP4 0x20 /* Stop timer  */
+	#define CFR2_RST4 0x10 /* Reset timer  */
+	#define CFR2_GM4  0x08 /* Gate mode for pin 4  */
+	#define CFR2_GM3  0x04 /* Gate mode for pin 3  */
+	#define CFR2_STP3 0x02 /* Stop timer  */
+	#define CFR2_RST3 0x01 /* Reset timer  */
+
+	u8    res1[11];
+	u16   mdr1; /* Timer1 Mode Register  */
+	#define MDR_SPS  0xff00 /* Secondary Prescaler value (256) */
+	#define MDR_CE   0x00c0 /* Capture edge and enable interrupt  */
+	#define MDR_OM   0x0020 /* Output mode  */
+	#define MDR_ORI  0x0010 /* Output reference interrupt enable  */
+	#define MDR_FRR  0x0008 /* Free run/restart  */
+	#define MDR_ICLK 0x0006 /* Input clock source for the timer */
+	#define MDR_GE   0x0001 /* Gate enable  */
+
+	u16   mdr2; /* Timer2 Mode Register  */
+	u16   rfr1; /* Timer1 Reference Register  */
+	u16   rfr2; /* Timer2 Reference Register  */
+	u16   cpr1; /* Timer1 Capture Register  */
+	u16   cpr2; /* Timer2 Capture Register  */
+	u16   cnr1; /* Timer1 Counter Register  */
+	u16   cnr2; /* Timer2 Counter Register  */
+	u16   mdr3; /* Timer3 Mode Register  */
+	u16   mdr4; /* Timer4 Mode Register  */
+	u16   rfr3; /* Timer3 Reference Register  */
+	u16   rfr4; /* Timer4 Reference Register  */
+	u16   cpr3; /* Timer3 Capture Register  */
+	u16   cpr4; /* Timer4 Capture Register  */
+	u16   cnr3; /* Timer3 Counter Register  */
+	u16   cnr4; /* Timer4 Counter Register  */
+	u16   evr1; /* Timer1 Event Register  */
+	u16   evr2; /* Timer2 Event Register  */
+	u16   evr3; /* Timer3 Event Register  */
+	u16   evr4; /* Timer4 Event Register  */
+	#define GTEVR_REF 0x0002 /* Output reference event  */
+	#define GTEVR_CAP 0x0001 /* Counter Capture event   */
+	#define GTEVR_RES ~(EVR_CAP|EVR_REF)
+
+	u16   psr1; /* Timer1 Prescaler Register  */
+	u16   psr2; /* Timer2 Prescaler Register  */
+	u16   psr3; /* Timer3 Prescaler Register  */
+	u16   psr4; /* Timer4 Prescaler Register  */
+	#define GTPSR_PPS  0x00FF /* Primary Prescaler Bits (256). */
+	#define GTPSR_RES  ~(GTPSR_PPS)
+};
+
+struct gtm_priv {
+	struct gtm_regs __iomem *regs;
+	int irq;
+	int ticks_per_sec;
+	spinlock_t lock;
+};
+
+static irqreturn_t fsl_gtm_isr(int irq, void *dev_id)
+{
+	struct gtm_priv *priv = dev_id;
+	unsigned long flags;
+	u16 event;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	event = in_be16(&priv->regs->evr4);
+	out_be16(&priv->regs->evr4, event);
+
+	if (event & GTEVR_REF)
+		out_8(&priv->regs->cfr2, CFR2_STP4);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return event ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static ssize_t gtm_timeout_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+	struct gtm_priv *priv = dev_get_drvdata(dev);
+	unsigned long interval = simple_strtoul(buf, NULL, 0);
+
+	if (interval > 0xffff) {
+		dev_dbg(dev, "gtm: interval %lu (in ns) too long\n", interval);
+		return -EINVAL;
+	}
+
+	interval *= priv->ticks_per_sec;
+
+	if (interval > 0xffff) {
+		dev_dbg(dev, "gtm: interval %lu (in ticks) too long\n",
+		        interval);
+		return -EINVAL;
+	}
+
+	spin_lock_irq(&priv->lock);
+
+	/* reset timer 4 */
+	out_8(&priv->regs->cfr2, CFR2_STP3 | CFR2_STP4);
+
+	if (interval != 0) {
+		out_8(&priv->regs->cfr2, CFR2_GM4 | CFR2_RST4 | CFR2_STP4);
+		/* clear events */
+		out_be16(&priv->regs->evr4, GTEVR_REF | GTEVR_CAP);
+		/* maximum primary prescale (256) */
+		out_be16(&priv->regs->psr4, GTPSR_PPS);
+		/* clear current counter */
+		out_be16(&priv->regs->cnr4, 0x0);
+		/* set count limit */
+		out_be16(&priv->regs->rfr4, interval);
+		out_be16(&priv->regs->mdr4, MDR_SPS | MDR_ORI | MDR_FRR |
+		                            MDR_ICLK_DIV16);
+		/* start timer */
+		out_8(&priv->regs->cfr2, CFR2_GM4 | CFR2_STP3 | CFR2_RST4);
+	}
+
+	spin_unlock_irq(&priv->lock);
+	return count;
+}
+
+static ssize_t gtm_timeout_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+	struct gtm_priv *priv = dev_get_drvdata(dev);
+	int timeout = 0;
+
+	spin_lock_irq(&priv->lock);
+
+	if (!(in_8(&priv->regs->cfr2) & CFR2_STP4)) {
+		timeout = in_be16(&priv->regs->rfr4) -
+		          in_be16(&priv->regs->cnr4);
+		timeout += priv->ticks_per_sec - 1;
+		timeout /= priv->ticks_per_sec;
+	}
+
+	spin_unlock_irq(&priv->lock);
+	return sprintf(buf, "%u\n", timeout);
+}
+
+static DEVICE_ATTR(timeout, 0660, gtm_timeout_show, gtm_timeout_store);
+
+static int __devinit gtm_probe(struct of_device *dev,
+                               const struct of_device_id *match)
+{
+	struct device_node *np = dev->node;
+	struct resource res;
+	int ret = 0;
+	u32 busfreq = fsl_get_sys_freq();
+	struct gtm_priv *priv;
+
+	if (busfreq == 0) {
+		printk(KERN_ERR "gtm: No bus frequency in device tree.\n");
+		return -ENODEV;
+	}
+
+	priv = kmalloc(sizeof(struct gtm_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	spin_lock_init(&priv->lock);
+	dev_set_drvdata(&dev->dev, priv);
+
+	ret = of_address_to_resource(np, 0, &res);
+	if (ret)
+		goto out;
+
+	priv->irq = irq_of_parse_and_map(np, 0);
+	if (priv->irq == NO_IRQ) {
+		printk(KERN_ERR "mpc83xx-gtm exists in device tree "
+		                "without an IRQ.\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	ret = request_irq(priv->irq, fsl_gtm_isr, 0, "gtm timer", priv);
+	if (ret)
+		goto out;
+
+	priv->regs = ioremap(res.start, sizeof(struct gtm_regs));
+	if (!priv->regs) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* Disable the unused clocks to save power. */
+	out_8(&priv->regs->cfr1, CFR1_STP1 | CFR1_STP2);
+	out_8(&priv->regs->cfr2, CFR2_STP3 | CFR2_STP4);
+
+	/*
+	 * Maximum prescaling is used (input clock/16, 256 primary prescaler,
+	 * 256 secondary prescaler) to maximize the timer's range.  With a
+	 * bus clock of 133MHz, this yields a maximum interval of 516
+	 * seconds while retaining subsecond precision.  Since only
+	 * timer 4 is supported for wakeup on the 8313, and timer 4
+	 * is the LSB when chained, we can't use chaining to increase
+	 * the range.
+	 */
+	priv->ticks_per_sec = busfreq / (16*256*256);
+
+	ret = device_create_file(&dev->dev, &dev_attr_timeout);
+	if (ret)
+		goto out;
+
+	return 0;
+
+out:
+	kfree(priv);
+	return ret;
+}
+
+static int __devexit gtm_remove(struct of_device *dev)
+{
+	struct gtm_priv *priv = dev_get_drvdata(&dev->dev);
+
+	device_remove_file(&dev->dev, &dev_attr_timeout);
+	free_irq(priv->irq, priv);
+	iounmap(priv->regs);
+
+	dev_set_drvdata(&dev->dev, NULL);
+	kfree(priv);
+	return 0;
+}
+
+static struct of_device_id gtm_match[] = {
+	{
+		.compatible = "fsl,mpc83xx-gtm",
+	},
+	{},
+};
+
+static struct of_platform_driver gtm_driver = {
+	.name = "mpc83xx-gtm-timer",
+	.match_table = gtm_match,
+	.probe = gtm_probe,
+	.remove = __devexit_p(gtm_remove)
+};
+
+static int __init gtm_init(void)
+{
+	return of_register_platform_driver(&gtm_driver);
+}
+
+static void __exit gtm_exit(void)
+{
+	of_unregister_platform_driver(&gtm_driver);
+}
+
+module_init(gtm_init);
+module_exit(gtm_exit);
-- 
1.5.3.4

^ permalink raw reply related

* [PATCH 7/7] gianfar: Add flags for magic packet and MDIO.
From: Scott Wood @ 2007-10-23 21:25 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20071023212404.GA30942@loki.buserror.net>

The magic packet flag indicates that the hardware has this
capability.  The MDIO flag indicates that this device's
registers contain active MDIO registers, and thus this
device should not be put to sleep.

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
 arch/powerpc/sysdev/fsl_soc.c |    7 +++++++
 include/linux/fsl_devices.h   |    2 ++
 2 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index d5fd916..032b8e8 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -324,6 +324,9 @@ static int __init gfar_of_init(void)
 		else
 			gfar_data.interface = PHY_INTERFACE_MODE_MII;
 
+		if (of_get_property(np, "fsl,magic-packet", NULL))
+			gfar_data.device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET;
+
 		ph = of_get_property(np, "phy-handle", NULL);
 		phy = of_find_node_by_phandle(*ph);
 
@@ -345,6 +348,10 @@ static int __init gfar_of_init(void)
 		gfar_data.phy_id = *id;
 		gfar_data.bus_id = res.start;
 
+		if (res.start >= gfar_dev->resource[0].start &&
+		    res.start < gfar_dev->resource[0].end)
+			gfar_data.device_flags |= FSL_GIANFAR_DEV_HAS_MDIO;
+
 		of_node_put(phy);
 		of_node_put(mdio);
 
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 5cec939..81fcc67 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -87,6 +87,8 @@ struct gianfar_mdio_data {
 #define FSL_GIANFAR_DEV_HAS_VLAN		0x00000020
 #define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH	0x00000040
 #define FSL_GIANFAR_DEV_HAS_PADDING		0x00000080
+#define FSL_GIANFAR_DEV_HAS_MAGIC_PACKET	0x00000100
+#define FSL_GIANFAR_DEV_HAS_MDIO		0x00000200
 
 /* Flags in gianfar_platform_data */
 #define FSL_GIANFAR_BRD_HAS_PHY_INTR	0x00000001 /* set or use a timer */
-- 
1.5.3.4

^ permalink raw reply related

* [PATCH 5/7] mpc83xx: Power Management support
From: Scott Wood @ 2007-10-23 21:25 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20071023212404.GA30942@loki.buserror.net>

Basic PM support for 83xx.  Standby is implemented as sleep.
Suspend-to-RAM is implemented as "deep sleep" (with the processor
turned off) on 831x.

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
 arch/powerpc/platforms/83xx/Kconfig       |    5 +
 arch/powerpc/platforms/83xx/Makefile      |    1 +
 arch/powerpc/platforms/83xx/suspend-asm.S |  531 +++++++++++++++++++++++++++++
 arch/powerpc/platforms/83xx/suspend.c     |  423 +++++++++++++++++++++++
 arch/powerpc/sysdev/fsl_soc.c             |   33 ++
 arch/powerpc/sysdev/fsl_soc.h             |   10 +
 arch/powerpc/sysdev/ipic.c                |   71 ++++
 include/asm-powerpc/reg.h                 |    4 +
 include/linux/fsl_devices.h               |   24 ++
 9 files changed, 1102 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/platforms/83xx/suspend-asm.S
 create mode 100644 arch/powerpc/platforms/83xx/suspend.c

diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
index ec305f1..901dbaf 100644
--- a/arch/powerpc/platforms/83xx/Kconfig
+++ b/arch/powerpc/platforms/83xx/Kconfig
@@ -75,3 +75,8 @@ config PPC_MPC836x
 	select PPC_UDBG_16550
 	select PPC_INDIRECT_PCI
 	default y if MPC836x_MDS
+
+config PPC_83xx_SUSPEND
+	bool
+	default y
+	depends on PPC_83xx && SUSPEND
diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile
index 5a98f88..944369e 100644
--- a/arch/powerpc/platforms/83xx/Makefile
+++ b/arch/powerpc/platforms/83xx/Makefile
@@ -3,6 +3,7 @@
 #
 obj-y				:= misc.o usb.o
 obj-$(CONFIG_PCI)		+= pci.o
+obj-$(CONFIG_SUSPEND)		+= suspend.o suspend-asm.o
 obj-$(CONFIG_MPC8313_RDB)	+= mpc8313_rdb.o
 obj-$(CONFIG_MPC832x_RDB)	+= mpc832x_rdb.o
 obj-$(CONFIG_MPC834x_MDS)	+= mpc834x_mds.o
diff --git a/arch/powerpc/platforms/83xx/suspend-asm.S b/arch/powerpc/platforms/83xx/suspend-asm.S
new file mode 100644
index 0000000..bfff3bd
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/suspend-asm.S
@@ -0,0 +1,531 @@
+/*
+ * Enter and leave sleep state on MPC83xx
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2006 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/reg.h>
+#include <asm/asm-offsets.h>
+
+#define SS_MEMSAVE	0x00
+#define SS_HID		0x08 /* 3 HIDs */
+#define SS_IABR		0x14 /* 2 IABRs */
+#define SS_IBCR		0x1c
+#define SS_DABR		0x20 /* 2 DABRs */
+#define SS_DBCR		0x28
+#define SS_SP		0x2c
+#define SS_SR		0x30 /* 16 segment registers */
+#define SS_CURRENT	0x70
+#define SS_MSR		0x74
+#define SS_SDR1		0x78
+#define SS_LR		0x7c
+#define SS_SPRG		0x80 /* 4 SPRGs */
+#define SS_DBAT		0x90 /* 8 DBATs */
+#define SS_IBAT		0xd0 /* 8 IBATs */
+#define SS_TB		0x110
+#define SS_CR		0x118
+#define SS_GPREG	0x11c /* r12-r31 */
+#define STATE_SAVE_SIZE 0x16c
+
+	.section .data
+	.align	5
+
+mpc83xx_sleep_save_area:
+	.space	STATE_SAVE_SIZE
+immrbase:
+	.long	0
+
+	.section .text
+	.align	5
+
+	/* r3 = physical address of IMMR */
+_GLOBAL(mpc83xx_enter_deep_sleep)
+	/* Re-use the state saving/restoring code in
+	 * arch/powerpc/kernel/swsusp_32.S, but have
+	 * it call us instead of swsusp_save.
+	 */
+
+	lis	r4, immrbase@ha
+	stw	r3, immrbase@l(r4)
+
+	/* The first 2 words of memory are used to communicate with the
+	 * bootloader, to tell it how to resume.
+	 *
+	 * The first word is the magic number 0xf5153ae5, and the second
+	 * is the pointer to mpc83xx_deep_resume.
+	 *
+	 * The original content of these two words is saved in the state
+	 * save area.
+	 */
+
+	lis	r3, mpc83xx_sleep_save_area@h
+	ori	r3, r3, mpc83xx_sleep_save_area@l
+
+	lis	r4, KERNELBASE@h
+	lwz	r5, 0(r4)
+	lwz	r6, 4(r4)
+
+	stw	r5, SS_MEMSAVE+0(r3)
+	stw	r6, SS_MEMSAVE+4(r3)
+
+	mfspr	r5, SPRN_HID0
+	mfspr	r6, SPRN_HID1
+	mfspr	r7, SPRN_HID2
+
+	stw	r5, SS_HID+0(r3)
+	stw	r6, SS_HID+4(r3)
+	stw	r7, SS_HID+8(r3)
+
+	mfspr	r4, SPRN_IABR
+	mfspr	r5, SPRN_IABR2
+	mfspr	r6, SPRN_IBCR
+	mfspr	r7, SPRN_DABR
+	mfspr	r8, SPRN_DABR2
+	mfspr	r9, SPRN_DBCR
+
+	stw	r4, SS_IABR+0(r3)
+	stw	r5, SS_IABR+4(r3)
+	stw	r6, SS_IBCR(r3)
+	stw	r7, SS_DABR+0(r3)
+	stw	r8, SS_DABR+4(r3)
+	stw	r9, SS_DBCR(r3)
+
+	mfspr	r4, SPRN_SPRG0
+	mfspr	r5, SPRN_SPRG1
+	mfspr	r6, SPRN_SPRG2
+	mfspr	r7, SPRN_SPRG3
+	mfsdr1	r8
+
+	stw	r4, SS_SPRG+0(r3)
+	stw	r5, SS_SPRG+4(r3)
+	stw	r6, SS_SPRG+8(r3)
+	stw	r7, SS_SPRG+12(r3)
+	stw	r8, SS_SDR1(r3)
+
+	mfspr	r4, SPRN_DBAT0U
+	mfspr	r5, SPRN_DBAT0L
+	mfspr	r6, SPRN_DBAT1U
+	mfspr	r7, SPRN_DBAT1L
+
+	stw	r4, SS_DBAT+0x00(r3)
+	stw	r5, SS_DBAT+0x04(r3)
+	stw	r6, SS_DBAT+0x08(r3)
+	stw	r7, SS_DBAT+0x0c(r3)
+
+	mfspr	r4, SPRN_DBAT2U
+	mfspr	r5, SPRN_DBAT2L
+	mfspr	r6, SPRN_DBAT3U
+	mfspr	r7, SPRN_DBAT3L
+
+	stw	r4, SS_DBAT+0x10(r3)
+	stw	r5, SS_DBAT+0x14(r3)
+	stw	r6, SS_DBAT+0x18(r3)
+	stw	r7, SS_DBAT+0x1c(r3)
+
+	mfspr	r4, SPRN_DBAT4U
+	mfspr	r5, SPRN_DBAT4L
+	mfspr	r6, SPRN_DBAT5U
+	mfspr	r7, SPRN_DBAT5L
+
+	stw	r4, SS_DBAT+0x20(r3)
+	stw	r5, SS_DBAT+0x24(r3)
+	stw	r6, SS_DBAT+0x28(r3)
+	stw	r7, SS_DBAT+0x2c(r3)
+
+	mfspr	r4, SPRN_DBAT6U
+	mfspr	r5, SPRN_DBAT6L
+	mfspr	r6, SPRN_DBAT7U
+	mfspr	r7, SPRN_DBAT7L
+
+	stw	r4, SS_DBAT+0x30(r3)
+	stw	r5, SS_DBAT+0x34(r3)
+	stw	r6, SS_DBAT+0x38(r3)
+	stw	r7, SS_DBAT+0x3c(r3)
+
+	mfspr	r4, SPRN_IBAT0U
+	mfspr	r5, SPRN_IBAT0L
+	mfspr	r6, SPRN_IBAT1U
+	mfspr	r7, SPRN_IBAT1L
+
+	stw	r4, SS_IBAT+0x00(r3)
+	stw	r5, SS_IBAT+0x04(r3)
+	stw	r6, SS_IBAT+0x08(r3)
+	stw	r7, SS_IBAT+0x0c(r3)
+
+	mfspr	r4, SPRN_IBAT2U
+	mfspr	r5, SPRN_IBAT2L
+	mfspr	r6, SPRN_IBAT3U
+	mfspr	r7, SPRN_IBAT3L
+
+	stw	r4, SS_IBAT+0x10(r3)
+	stw	r5, SS_IBAT+0x14(r3)
+	stw	r6, SS_IBAT+0x18(r3)
+	stw	r7, SS_IBAT+0x1c(r3)
+
+	mfspr	r4, SPRN_IBAT4U
+	mfspr	r5, SPRN_IBAT4L
+	mfspr	r6, SPRN_IBAT5U
+	mfspr	r7, SPRN_IBAT5L
+
+	stw	r4, SS_IBAT+0x20(r3)
+	stw	r5, SS_IBAT+0x24(r3)
+	stw	r6, SS_IBAT+0x28(r3)
+	stw	r7, SS_IBAT+0x2c(r3)
+
+	mfspr	r4, SPRN_IBAT6U
+	mfspr	r5, SPRN_IBAT6L
+	mfspr	r6, SPRN_IBAT7U
+	mfspr	r7, SPRN_IBAT7L
+
+	stw	r4, SS_IBAT+0x30(r3)
+	stw	r5, SS_IBAT+0x34(r3)
+	stw	r6, SS_IBAT+0x38(r3)
+	stw	r7, SS_IBAT+0x3c(r3)
+
+	mfmsr	r4
+	mflr	r5
+	mfcr	r6
+
+	stw	r4, SS_MSR(r3)
+	stw	r5, SS_LR(r3)
+	stw	r6, SS_CR(r3)
+	stw	r1, SS_SP(r3)
+	stw	r2, SS_CURRENT(r3)
+
+1:	mftbu	r4
+	mftb	r5
+	mftbu	r6
+	cmpw	r4, r6
+	bne	1b
+
+	stw	r4, SS_TB+0(r3)
+	stw	r5, SS_TB+4(r3)
+
+	stmw	r12, SS_GPREG(r3)
+
+	li	r4, 0
+	addi	r6, r3, SS_SR-4
+1:	mfsrin	r5, r4
+	stwu	r5, 4(r6)
+	addis	r4, r4, 0x1000
+	cmpwi	r4, 0
+	bne	1b
+
+	/* Disable machine checks and critical exceptions */
+	mfmsr	r4
+	rlwinm	r4, r4, 0, ~MSR_CE
+	rlwinm	r4, r4, 0, ~MSR_ME
+	mtmsr	r4
+	isync
+
+#define TMP_VIRT_IMMR		0xf0000000
+#define DEFAULT_IMMR_VALUE	0xff400000
+#define IMMRBAR_BASE		0x0000
+
+	lis	r4, immrbase@ha
+	lwz	r4, immrbase@l(r4)
+
+	/* Use DBAT0 to address the current IMMR space */
+
+	ori	r4, r4, 0x002a
+	mtspr	SPRN_DBAT0L, r4
+	lis	r8, TMP_VIRT_IMMR@h
+	ori	r4, r8, 0x001e	/* 1 MByte accessable from Kernel Space only */
+	mtspr	SPRN_DBAT0U, r4
+	isync
+
+	/* Use DBAT1 to address the original IMMR space */
+
+	lis	r4, DEFAULT_IMMR_VALUE@h
+	ori	r4, r4, 0x002a
+	mtspr	SPRN_DBAT1L, r4
+	lis	r9, (TMP_VIRT_IMMR + 0x01000000)@h
+	ori	r4, r9, 0x001e	/* 1 MByte accessable from Kernel Space only */
+	mtspr	SPRN_DBAT1U, r4
+	isync
+
+	/* Use DBAT2 to address the beginning of RAM.  This isn't done
+	 * using the normal virtual mapping, because with page debugging
+	 * enabled it will be read-only. */
+
+	li	r4, 0x0002
+	mtspr	SPRN_DBAT2L, r4
+	lis	r4, KERNELBASE@h
+	ori	r4, r4, 0x001e	/* 1 MByte accessable from Kernel Space only */
+	mtspr	SPRN_DBAT2U, r4
+	isync
+
+	/* Flush the cache with our BAT, as there will be TLB misses
+	 * otherwise if page debugging is enabled, and these misses
+	 * will disturb the PLRU algorithm.
+	 */
+
+	bl	__flush_disable_L1
+
+	lis	r6, 0xf515
+	ori	r6, r6, 0x3ae5
+
+	lis	r7, mpc83xx_deep_resume@h
+	ori	r7, r7, mpc83xx_deep_resume@l
+	tophys(r7, r7)
+
+	lis	r5, KERNELBASE@h
+	stw	r6, 0(r5)
+	stw	r7, 4(r5)
+
+	/* Reset BARs */
+
+	li	r4, 0
+	stw	r4, 0x0024(r8)
+	stw	r4, 0x002c(r8)
+	stw	r4, 0x0034(r8)
+	stw	r4, 0x003c(r8)
+	stw	r4, 0x0064(r8)
+	stw	r4, 0x006c(r8)
+
+	/* Rev 1 of the 8313 has problems with wakeup events that are
+	 * pending during the transition to deep sleep state (such as if
+	 * the PCI host sets the state to D3 and then D0 in rapid
+	 * succession).  This check shrinks the race window somewhat.
+	 *
+	 * See erratum PCI23, though the problem is not limited
+	 * to PCI.
+	 */
+
+	lwz	r3, 0x0b04(r8)
+	andi.	r3, r3, 1
+	bne-	mpc83xx_deep_resume
+
+	/* Move IMMR back to the default location, following the
+	 * procedure specified in the MPC8313 manual.
+	 */
+	lwz	r4, IMMRBAR_BASE(r8)
+	isync
+	lis	r4, DEFAULT_IMMR_VALUE@h
+	stw	r4, IMMRBAR_BASE(r8)
+	lis	r4, KERNELBASE@h
+	lwz	r4, 0(r4)
+	isync
+	lwz	r4, IMMRBAR_BASE(r9)
+	mr	r8, r9
+	isync
+
+	/* Check the Reset Configuration Word to see whether flash needs
+	 * to be mapped at a low address or a high address.
+	 */
+
+	lwz	r4, 0x0904(r8)
+	andis.	r4, r4, 0x0400
+	li	r4, 0
+	beq	boot_low
+	lis	r4, 0xff80
+boot_low:
+	stw	r4, 0x0020(r8)
+	lis	r7, 0x8000
+	ori	r7, r7, 0x0016
+
+	mfspr	r5, SPRN_HID0
+	rlwinm	r5, r5, 0, ~(HID0_DOZE | HID0_NAP)
+	oris	r5, r5, HID0_SLEEP@h
+	mtspr	SPRN_HID0, r5
+	isync
+
+	mfmsr	r5
+	oris	r5, r5, MSR_POW@h
+
+	/* Enable the flash mapping at the appropriate address.  This
+	 * mapping will override the RAM mapping, so there's no need to
+	 * disable the latter.  This must be done inside the same cache
+	 * line as setting MSR_POW, so that no instruction fetches from
+	 * RAM happen after the flash mapping is turned on.
+	 */
+
+	.align	5
+	stw	r7, 0x0024(r8)
+	sync
+	isync
+	mtmsr	r5
+	isync
+1:	b	1b
+
+mpc83xx_deep_resume:
+	lis	r4, 1f@h
+	ori	r4, r4, 1f@l
+	tophys(r4, r4)
+	mtsrr0	r4
+
+	mfmsr	r4
+	rlwinm	r4, r4, 0, ~(MSR_IR | MSR_DR)
+	mtsrr1	r4
+
+	rfi
+
+1:	tlbia
+	bl	__inval_enable_L1
+
+	lis	r3, mpc83xx_sleep_save_area@h
+	ori	r3, r3, mpc83xx_sleep_save_area@l
+	tophys(r3, r3)
+
+	lwz	r5, SS_MEMSAVE+0(r3)
+	lwz	r6, SS_MEMSAVE+4(r3)
+
+	stw	r5, 0(0)
+	stw	r6, 4(0)
+
+	lwz	r5, SS_HID+0(r3)
+	lwz	r6, SS_HID+4(r3)
+	lwz	r7, SS_HID+8(r3)
+
+	mtspr	SPRN_HID0, r5
+	mtspr	SPRN_HID1, r6
+	mtspr	SPRN_HID2, r7
+
+	lwz	r4, SS_IABR+0(r3)
+	lwz	r5, SS_IABR+4(r3)
+	lwz	r6, SS_IBCR(r3)
+	lwz	r7, SS_DABR+0(r3)
+	lwz	r8, SS_DABR+4(r3)
+	lwz	r9, SS_DBCR(r3)
+
+	mtspr	SPRN_IABR, r4
+	mtspr	SPRN_IABR2, r5
+	mtspr	SPRN_IBCR, r6
+	mtspr	SPRN_DABR, r7
+	mtspr	SPRN_DABR2, r8
+	mtspr	SPRN_DBCR, r9
+
+	li	r4, 0
+	addi	r6, r3, SS_SR-4
+1:	lwzu	r5, 4(r6)
+	mtsrin	r5, r4
+	addis	r4, r4, 0x1000
+	cmpwi	r4, 0
+	bne	1b
+
+	lwz	r4, SS_DBAT+0x00(r3)
+	lwz	r5, SS_DBAT+0x04(r3)
+	lwz	r6, SS_DBAT+0x08(r3)
+	lwz	r7, SS_DBAT+0x0c(r3)
+
+	mtspr	SPRN_DBAT0U, r4
+	mtspr	SPRN_DBAT0L, r5
+	mtspr	SPRN_DBAT1U, r6
+	mtspr	SPRN_DBAT1L, r7
+
+	lwz	r4, SS_DBAT+0x10(r3)
+	lwz	r5, SS_DBAT+0x14(r3)
+	lwz	r6, SS_DBAT+0x18(r3)
+	lwz	r7, SS_DBAT+0x1c(r3)
+
+	mtspr	SPRN_DBAT2U, r4
+	mtspr	SPRN_DBAT2L, r5
+	mtspr	SPRN_DBAT3U, r6
+	mtspr	SPRN_DBAT3L, r7
+
+	lwz	r4, SS_DBAT+0x20(r3)
+	lwz	r5, SS_DBAT+0x24(r3)
+	lwz	r6, SS_DBAT+0x28(r3)
+	lwz	r7, SS_DBAT+0x2c(r3)
+
+	mtspr	SPRN_DBAT4U, r4
+	mtspr	SPRN_DBAT4L, r5
+	mtspr	SPRN_DBAT5U, r6
+	mtspr	SPRN_DBAT5L, r7
+
+	lwz	r4, SS_DBAT+0x30(r3)
+	lwz	r5, SS_DBAT+0x34(r3)
+	lwz	r6, SS_DBAT+0x38(r3)
+	lwz	r7, SS_DBAT+0x3c(r3)
+
+	mtspr	SPRN_DBAT6U, r4
+	mtspr	SPRN_DBAT6L, r5
+	mtspr	SPRN_DBAT7U, r6
+	mtspr	SPRN_DBAT7L, r7
+
+	lwz	r4, SS_IBAT+0x00(r3)
+	lwz	r5, SS_IBAT+0x04(r3)
+	lwz	r6, SS_IBAT+0x08(r3)
+	lwz	r7, SS_IBAT+0x0c(r3)
+
+	mtspr	SPRN_IBAT0U, r4
+	mtspr	SPRN_IBAT0L, r5
+	mtspr	SPRN_IBAT1U, r6
+	mtspr	SPRN_IBAT1L, r7
+
+	lwz	r4, SS_IBAT+0x10(r3)
+	lwz	r5, SS_IBAT+0x14(r3)
+	lwz	r6, SS_IBAT+0x18(r3)
+	lwz	r7, SS_IBAT+0x1c(r3)
+
+	mtspr	SPRN_IBAT2U, r4
+	mtspr	SPRN_IBAT2L, r5
+	mtspr	SPRN_IBAT3U, r6
+	mtspr	SPRN_IBAT3L, r7
+
+	lwz	r4, SS_IBAT+0x20(r3)
+	lwz	r5, SS_IBAT+0x24(r3)
+	lwz	r6, SS_IBAT+0x28(r3)
+	lwz	r7, SS_IBAT+0x2c(r3)
+
+	mtspr	SPRN_IBAT4U, r4
+	mtspr	SPRN_IBAT4L, r5
+	mtspr	SPRN_IBAT5U, r6
+	mtspr	SPRN_IBAT5L, r7
+
+	lwz	r4, SS_IBAT+0x30(r3)
+	lwz	r5, SS_IBAT+0x34(r3)
+	lwz	r6, SS_IBAT+0x38(r3)
+	lwz	r7, SS_IBAT+0x3c(r3)
+
+	mtspr	SPRN_IBAT6U, r4
+	mtspr	SPRN_IBAT6L, r5
+	mtspr	SPRN_IBAT7U, r6
+	mtspr	SPRN_IBAT7L, r7
+
+	lwz	r4, SS_SPRG+0(r3)
+	lwz	r5, SS_SPRG+4(r3)
+	lwz	r6, SS_SPRG+8(r3)
+	lwz	r7, SS_SPRG+12(r3)
+	lwz	r8, SS_SDR1(r3)
+
+	mtspr	SPRN_SPRG0, r4
+	mtspr	SPRN_SPRG1, r5
+	mtspr	SPRN_SPRG2, r6
+	mtspr	SPRN_SPRG3, r7
+	mtsdr1	r8
+
+	lwz	r4, SS_MSR(r3)
+	lwz	r5, SS_LR(r3)
+	lwz	r6, SS_CR(r3)
+	lwz	r1, SS_SP(r3)
+	lwz	r2, SS_CURRENT(r3)
+
+	mtsrr1	r4
+	mtsrr0	r5
+	mtcr	r6
+
+	li	r4, 0
+	mtspr	SPRN_TBWL, r4
+
+	lwz	r4, SS_TB+0(r3)
+	lwz	r5, SS_TB+4(r3)
+
+	mtspr	SPRN_TBWU, r4
+	mtspr	SPRN_TBWL, r5
+
+	lmw	r12, SS_GPREG(r3)
+
+	/* Kick decrementer */
+	li	r0, 1
+	mtdec	r0
+
+	rfi
diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c
new file mode 100644
index 0000000..e085006
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/suspend.c
@@ -0,0 +1,423 @@
+/*
+ * MPC83xx suspend support
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2006-2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/suspend.h>
+#include <linux/fsl_devices.h>
+#include <linux/of_platform.h>
+
+#include <asm/reg.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/mpc6xx.h>
+
+#include <sysdev/fsl_soc.h>
+
+#define PMCCR1_NEXT_STATE       0x0C /* Next state for power management */
+#define PMCCR1_NEXT_STATE_SHIFT 2
+#define PMCCR1_CURR_STATE       0x03 /* Current state for power management*/
+#define IMMR_RCW_OFFSET         0x900
+#define RCW_PCI_HOST            0x80000000
+
+void mpc83xx_enter_deep_sleep(phys_addr_t immrbase);
+
+struct mpc83xx_pmc {
+	u32 config;
+#define PMCCR_DLPEN 2 /* DDR SDRAM low power enable */
+#define PMCCR_SLPEN 1 /* System low power enable */
+
+	u32 event;
+	u32 mask;
+/* All but PMCI are deep-sleep only */
+#define PMCER_GPIO   0x100
+#define PMCER_PCI    0x080
+#define PMCER_USB    0x040
+#define PMCER_ETSEC1 0x020
+#define PMCER_ETSEC2 0x010
+#define PMCER_TIMER  0x008
+#define PMCER_INT1   0x004
+#define PMCER_INT2   0x002
+#define PMCER_PMCI   0x001
+#define PMCER_ALL    0x1FF
+
+	/* deep-sleep only */
+	u32 config1;
+#define PMCCR1_USE_STATE  0x80000000
+#define PMCCR1_PME_EN     0x00000080
+#define PMCCR1_ASSERT_PME 0x00000040
+#define PMCCR1_POWER_OFF  0x00000020
+
+	/* deep-sleep only */
+	u32 config2;
+};
+
+struct mpc83xx_rcw {
+	u32 rcwlr;
+	u32 rcwhr;
+};
+
+struct mpc83xx_clock {
+	u32 spmr;
+	u32 occr;
+	u32 sccr;
+};
+
+struct pmc_type {
+	int has_deep_sleep;
+};
+
+static struct of_device *pmc_dev;
+static int has_deep_sleep, deep_sleeping;
+static int pmc_irq;
+static struct mpc83xx_pmc __iomem *pmc_regs;
+static struct mpc83xx_clock __iomem *clock_regs;
+static int is_pci_agent, wake_from_pci;
+static phys_addr_t immrbase;
+static int pci_pm_state;
+static DECLARE_WAIT_QUEUE_HEAD(agent_wq);
+
+static u32 saved_sccr;
+static DEFINE_SPINLOCK(device_sleep_lock);
+
+void fsl_sleep_device(struct fsl_sleep_platform_data *data)
+{
+	if (clock_regs && data->sccr_mask) {
+		unsigned long flags;
+		u32 sccr;
+
+		spin_lock_irqsave(&device_sleep_lock, flags);
+		sccr = in_be32(&clock_regs->sccr);
+
+		saved_sccr &= ~data->sccr_mask;
+		saved_sccr |= sccr & data->sccr_mask;
+
+		out_be32(&clock_regs->sccr, sccr & ~data->sccr_mask);
+		spin_unlock_irqrestore(&device_sleep_lock, flags);
+	}
+}
+EXPORT_SYMBOL(fsl_sleep_device);
+
+void fsl_wake_device(struct fsl_sleep_platform_data *data)
+{
+	if (clock_regs && data->sccr_mask) {
+		unsigned long flags;
+		u32 sccr;
+
+		spin_lock_irqsave(&device_sleep_lock, flags);
+
+		sccr = in_be32(&clock_regs->sccr);
+		sccr |= saved_sccr & data->sccr_mask;
+		out_be32(&clock_regs->sccr, sccr);
+
+		spin_unlock_irqrestore(&device_sleep_lock, flags);
+	}
+}
+EXPORT_SYMBOL(fsl_wake_device);
+
+int fsl_deep_sleep(void)
+{
+	return deep_sleeping;
+}
+
+static int mpc83xx_change_state(void)
+{
+	u32 curr_state;
+	u32 reg_cfg1 = in_be32(&pmc_regs->config1);
+
+	if (is_pci_agent) {
+		pci_pm_state = (reg_cfg1 & PMCCR1_NEXT_STATE) >>
+		               PMCCR1_NEXT_STATE_SHIFT;
+		curr_state = reg_cfg1 & PMCCR1_CURR_STATE;
+
+		if (curr_state != pci_pm_state) {
+			reg_cfg1 &= ~PMCCR1_CURR_STATE;
+			reg_cfg1 |= pci_pm_state;
+			out_be32(&pmc_regs->config1, reg_cfg1);
+
+			wake_up(&agent_wq);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static irqreturn_t pmc_irq_handler(int irq, void *dev_id)
+{
+	u32 event = in_be32(&pmc_regs->event);
+	int ret = IRQ_NONE;
+
+	if (mpc83xx_change_state())
+		ret = IRQ_HANDLED;
+
+	if (event) {
+		out_be32(&pmc_regs->event, event);
+		ret = IRQ_HANDLED;
+	}
+
+	return ret;
+}
+
+static int mpc83xx_suspend_enter(suspend_state_t state)
+{
+	int ret = -EAGAIN;
+
+	/* Don't go to sleep if there's a race where pci_pm_state changes
+	 * between the agent thread checking it and the PM code disabling
+	 * interrupts.
+	 */
+	if (wake_from_pci) {
+		if (pci_pm_state != (deep_sleeping ? 3 : 2))
+			goto out;
+
+		out_be32(&pmc_regs->config1,
+		         in_be32(&pmc_regs->config1) | PMCCR1_PME_EN);
+	}
+
+	/* Put the system into low-power mode and the RAM
+	 * into self-refresh mode once the core goes to
+	 * sleep.
+	 */
+
+	out_be32(&pmc_regs->config, PMCCR_SLPEN | PMCCR_DLPEN);
+
+	/* If it has deep sleep (i.e. it's an 831x or compatible),
+	 * disable power to the core upon entering sleep mode.  This will
+	 * require going through the boot firmware upon a wakeup event.
+	 */
+
+	if (deep_sleeping) {
+		out_be32(&pmc_regs->mask, PMCER_ALL);
+
+		out_be32(&pmc_regs->config1,
+		         in_be32(&pmc_regs->config1) | PMCCR1_POWER_OFF);
+
+		enable_kernel_fp();
+
+		mpc83xx_enter_deep_sleep(immrbase);
+
+		out_be32(&pmc_regs->config1,
+		         in_be32(&pmc_regs->config1) & ~PMCCR1_POWER_OFF);
+
+		out_be32(&pmc_regs->mask, PMCER_PMCI);
+	} else {
+		out_be32(&pmc_regs->mask, PMCER_PMCI);
+
+		mpc6xx_enter_standby();
+	}
+
+	ret = 0;
+
+out:
+	out_be32(&pmc_regs->config1,
+	         in_be32(&pmc_regs->config1) & ~PMCCR1_PME_EN);
+
+	return ret;
+}
+
+static void mpc83xx_suspend_finish(void)
+{
+	deep_sleeping = 0;
+}
+
+static int mpc83xx_suspend_valid(suspend_state_t state)
+{
+	return state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM;
+}
+
+static int mpc83xx_suspend_set_target(suspend_state_t state)
+{
+	switch (state) {
+		case PM_SUSPEND_STANDBY:
+			deep_sleeping = 0;
+			return 0;
+
+		case PM_SUSPEND_MEM:
+			if (has_deep_sleep)
+				deep_sleeping = 1;
+
+			return 0;
+
+		default:
+			return -EINVAL;
+	}
+}
+
+static int agent_thread_fn(void *data)
+{
+	while (1) {
+		wait_event_interruptible(agent_wq, pci_pm_state >= 2);
+		try_to_freeze();
+
+		if (signal_pending(current) || pci_pm_state < 2)
+			continue;
+
+		/* With a preemptible kernel (or SMP), this could race with a
+		 * userspace-driven suspend request.  It's probably best to
+		 * avoid mixing the two with such a configuration (or else fix
+		 * it by adding a mutex to state_store that we can synchronize
+		 * with).
+		 */
+
+		wake_from_pci = 1;
+
+		pm_suspend(pci_pm_state == 3 ? PM_SUSPEND_MEM :
+		                               PM_SUSPEND_STANDBY);
+
+		wake_from_pci = 0;
+	}
+
+	return 0;
+}
+
+void mpc83xx_set_agent(void)
+{
+	out_be32(&pmc_regs->config1, PMCCR1_USE_STATE);
+	out_be32(&pmc_regs->mask, PMCER_PMCI);
+
+	kthread_run(agent_thread_fn, NULL, "PCI power mgt");
+}
+
+static int mpc83xx_is_pci_agent(void)
+{
+	struct mpc83xx_rcw __iomem *rcw_regs;
+	int ret;
+
+	rcw_regs = ioremap(get_immrbase() + IMMR_RCW_OFFSET,
+	                   sizeof(struct mpc83xx_rcw));
+
+	if (!rcw_regs)
+		return -ENOMEM;
+
+	ret = !(in_be32(&rcw_regs->rcwhr) & RCW_PCI_HOST);
+
+	iounmap(rcw_regs);
+	return ret;
+}
+
+static struct platform_suspend_ops mpc83xx_suspend_ops = {
+	.valid = mpc83xx_suspend_valid,
+	.set_target = mpc83xx_suspend_set_target,
+	.enter = mpc83xx_suspend_enter,
+	.finish = mpc83xx_suspend_finish,
+};
+
+static int pmc_probe(struct of_device *ofdev,
+                     const struct of_device_id *match)
+{
+	struct device_node *np = ofdev->node;
+	struct resource res;
+	struct pmc_type *type = match->data;
+	int ret = 0;
+
+	has_deep_sleep = type->has_deep_sleep;
+	immrbase = get_immrbase();
+	pmc_dev = ofdev;
+
+	is_pci_agent = mpc83xx_is_pci_agent();
+	if (is_pci_agent < 0)
+		return is_pci_agent;
+
+	ret = of_address_to_resource(np, 0, &res);
+	if (ret)
+		return -ENODEV;
+
+	pmc_irq = irq_of_parse_and_map(np, 0);
+	if (pmc_irq != NO_IRQ) {
+		ret = request_irq(pmc_irq, pmc_irq_handler, IRQF_SHARED,
+		                  "pmc", ofdev);
+
+		if (ret)
+			return -EBUSY;
+	}
+
+	pmc_regs = ioremap(res.start, sizeof(struct mpc83xx_pmc));
+
+	if (!pmc_regs) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = of_address_to_resource(np, 1, &res);
+	if (ret) {
+		ret = -ENODEV;
+		goto out_pmc;
+	}
+
+	clock_regs = ioremap(res.start, sizeof(struct mpc83xx_pmc));
+
+	if (!clock_regs) {
+		ret = -ENOMEM;
+		goto out_pmc;
+	}
+
+	if (is_pci_agent)
+		mpc83xx_set_agent();
+
+	suspend_set_ops(&mpc83xx_suspend_ops);
+	return 0;
+
+out_pmc:
+	iounmap(pmc_regs);
+out:
+	if (pmc_irq != NO_IRQ)
+		free_irq(pmc_irq, ofdev);
+
+	return ret;
+}
+
+static int pmc_remove(struct of_device *ofdev)
+{
+	return -EPERM;
+};
+
+static struct pmc_type pmc_types[] = {
+	{
+		.has_deep_sleep = 1,
+	},
+	{
+		.has_deep_sleep = 0,
+	}
+};
+
+static struct of_device_id pmc_match[] = {
+	{
+		.compatible = "fsl,mpc831x-pmc",
+		.data = &pmc_types[0],
+	},
+	{
+		.compatible = "fsl,mpc83xx-pmc",
+		.data = &pmc_types[1],
+	},
+	{}
+};
+
+static struct of_platform_driver pmc_driver = {
+	.name = "mpc83xx-pmc",
+	.match_table = pmc_match,
+	.probe = pmc_probe,
+	.remove = pmc_remove
+};
+
+static int pmc_init(void)
+{
+	return of_register_platform_driver(&pmc_driver);
+}
+
+module_init(pmc_init);
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index e1ba33c..d5fd916 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -151,6 +151,33 @@ u32 get_baudrate(void)
 EXPORT_SYMBOL(get_baudrate);
 #endif /* CONFIG_CPM2 */
 
+int fsl_sleep_init(struct fsl_sleep_platform_data *sleep,
+                   struct device_node *node)
+{
+	int proplen, ret = -ENODEV;
+	const u32 *sleepdata = of_get_property(node, "sleep", &proplen);
+	struct device_node *sleep_controller;
+
+	if (!sleepdata || proplen != 8)
+		return -ENODEV;
+
+	sleep_controller = of_find_node_by_phandle(sleepdata[0]);
+	if (!sleep_controller)
+		return -ENODEV;
+
+	/* There can only be one fsl,mpc83xx-pmc device in the system;
+	 * it is assumed that it is the one that the pmc driver matches.
+	 */
+	if (of_device_is_compatible(sleep_controller, "fsl,mpc83xx-pmc")) {
+		sleep->sccr_mask = sleepdata[1];
+		ret = 0;
+	}
+
+	of_node_put(sleep_controller);
+	return ret;
+}
+EXPORT_SYMBOL(fsl_sleep_init);
+
 static int __init gfar_mdio_of_init(void)
 {
 	struct device_node *np;
@@ -321,6 +348,8 @@ static int __init gfar_of_init(void)
 		of_node_put(phy);
 		of_node_put(mdio);
 
+		fsl_sleep_init(&gfar_data.sleep, np);
+
 		ret =
 		    platform_device_add_data(gfar_dev, &gfar_data,
 					     sizeof(struct
@@ -576,6 +605,8 @@ static int __init fsl_usb_of_init(void)
 		prop = of_get_property(np, "phy_type", NULL);
 		usb_data.phy_mode = determine_usb_phy(prop);
 
+		fsl_sleep_init(&usb_data.sleep, np);
+
 		ret =
 		    platform_device_add_data(usb_dev_mph, &usb_data,
 					     sizeof(struct
@@ -640,6 +671,8 @@ static int __init fsl_usb_of_init(void)
 		prop = of_get_property(np, "phy_type", NULL);
 		usb_data.phy_mode = determine_usb_phy(prop);
 
+		fsl_sleep_init(&usb_data.sleep, np);
+
 		if (usb_dev_dr_host) {
 			usb_dev_dr_host->dev.coherent_dma_mask = 0xffffffffUL;
 			usb_dev_dr_host->dev.dma_mask = &usb_dev_dr_host->
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 74c4a96..fb52d39 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -10,12 +10,22 @@ extern u32 get_baudrate(void);
 extern u32 fsl_get_sys_freq(void);
 
 struct spi_board_info;
+struct fsl_sleep_platform_data;
+struct device_node;
 
 extern int fsl_spi_init(struct spi_board_info *board_infos,
 			unsigned int num_board_infos,
 			void (*activate_cs)(u8 cs, u8 polarity),
 			void (*deactivate_cs)(u8 cs, u8 polarity));
 
+int fsl_sleep_init(struct fsl_sleep_platform_data *sleep,
+                   struct device_node *node);
+
+/* Calls to fsl_sleep_dev and fsl_wake_dev cannot be nested. */
+void fsl_sleep_dev(struct fsl_sleep_platform_data *sleep);
+void fsl_wake_dev(struct fsl_sleep_platform_data *sleep);
+
 extern void fsl_rstcr_restart(char *cmd);
+
 #endif
 #endif
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
index 05a56e5..e2388cf 100644
--- a/arch/powerpc/sysdev/ipic.c
+++ b/arch/powerpc/sysdev/ipic.c
@@ -22,6 +22,7 @@
 #include <linux/device.h>
 #include <linux/bootmem.h>
 #include <linux/spinlock.h>
+#include <linux/fsl_devices.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/prom.h>
@@ -724,8 +725,78 @@ unsigned int ipic_get_irq(void)
 	return irq_linear_revmap(primary_ipic->irqhost, irq);
 }
 
+#ifdef CONFIG_PM
+static struct {
+	u32 sicfr;
+	u32 siprr[2];
+	u32 simsr[2];
+	u32 sicnr;
+	u32 smprr[2];
+	u32 semsr;
+	u32 secnr;
+	u32 sermr;
+	u32 sercr;
+} ipic_saved_state;
+
+static int ipic_suspend(struct sys_device *sdev, pm_message_t state)
+{
+	struct ipic *ipic = primary_ipic;
+
+	ipic_saved_state.sicfr = ipic_read(ipic->regs, IPIC_SICFR);
+	ipic_saved_state.siprr[0] = ipic_read(ipic->regs, IPIC_SIPRR_A);
+	ipic_saved_state.siprr[1] = ipic_read(ipic->regs, IPIC_SIPRR_D);
+	ipic_saved_state.simsr[0] = ipic_read(ipic->regs, IPIC_SIMSR_H);
+	ipic_saved_state.simsr[1] = ipic_read(ipic->regs, IPIC_SIMSR_L);
+	ipic_saved_state.sicnr = ipic_read(ipic->regs, IPIC_SICNR);
+	ipic_saved_state.smprr[0] = ipic_read(ipic->regs, IPIC_SMPRR_A);
+	ipic_saved_state.smprr[1] = ipic_read(ipic->regs, IPIC_SMPRR_B);
+	ipic_saved_state.semsr = ipic_read(ipic->regs, IPIC_SEMSR);
+	ipic_saved_state.secnr = ipic_read(ipic->regs, IPIC_SECNR);
+	ipic_saved_state.sermr = ipic_read(ipic->regs, IPIC_SERMR);
+	ipic_saved_state.sercr = ipic_read(ipic->regs, IPIC_SERCR);
+
+	if (fsl_deep_sleep()) {
+		/* In deep sleep, make sure there can be no
+		 * pending interrupts, as this can cause
+		 * problems on 831x.
+		 */
+		ipic_write(ipic->regs, IPIC_SIMSR_H, 0);
+		ipic_write(ipic->regs, IPIC_SIMSR_L, 0);
+		ipic_write(ipic->regs, IPIC_SEMSR, 0);
+		ipic_write(ipic->regs, IPIC_SERMR, 0);
+	}
+
+	return 0;
+}
+
+static int ipic_resume(struct sys_device *sdev)
+{
+	struct ipic *ipic = primary_ipic;
+
+	ipic_write(ipic->regs, IPIC_SICFR, ipic_saved_state.sicfr);
+	ipic_write(ipic->regs, IPIC_SIPRR_A, ipic_saved_state.siprr[0]);
+	ipic_write(ipic->regs, IPIC_SIPRR_D, ipic_saved_state.siprr[1]);
+	ipic_write(ipic->regs, IPIC_SIMSR_H, ipic_saved_state.simsr[0]);
+	ipic_write(ipic->regs, IPIC_SIMSR_L, ipic_saved_state.simsr[1]);
+	ipic_write(ipic->regs, IPIC_SICNR, ipic_saved_state.sicnr);
+	ipic_write(ipic->regs, IPIC_SMPRR_A, ipic_saved_state.smprr[0]);
+	ipic_write(ipic->regs, IPIC_SMPRR_B, ipic_saved_state.smprr[1]);
+	ipic_write(ipic->regs, IPIC_SEMSR, ipic_saved_state.semsr);
+	ipic_write(ipic->regs, IPIC_SECNR, ipic_saved_state.secnr);
+	ipic_write(ipic->regs, IPIC_SERMR, ipic_saved_state.sermr);
+	ipic_write(ipic->regs, IPIC_SERCR, ipic_saved_state.sercr);
+
+	return 0;
+}
+#else
+#define ipic_suspend NULL
+#define ipic_resume NULL
+#endif
+
 static struct sysdev_class ipic_sysclass = {
 	set_kset_name("ipic"),
+	.suspend = ipic_suspend,
+	.resume = ipic_resume,
 };
 
 static struct sys_device device_ipic = {
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index e775ff1..97f4b8c 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -149,7 +149,9 @@
 #define   CTRL_RUNLATCH	0x1
 #define SPRN_DABR	0x3F5	/* Data Address Breakpoint Register */
 #define   DABR_TRANSLATION	(1UL << 2)
+#define SPRN_DABR2	0x13D	/* 83xx */
 #define SPRN_DAR	0x013	/* Data Address Register */
+#define SPRN_DBCR	0x136	/* 83xx Data Breakpoint Control Reg */
 #define SPRN_DSISR	0x012	/* Data Storage Interrupt Status Register */
 #define   DSISR_NOHPTE		0x40000000	/* no translation found */
 #define   DSISR_PROTFAULT	0x08000000	/* protection fault */
@@ -255,6 +257,8 @@
 #define HID1_PS		(1<<16)		/* 750FX PLL selection */
 #define SPRN_HID2	0x3F8		/* Hardware Implementation Register 2 */
 #define SPRN_IABR	0x3F2	/* Instruction Address Breakpoint Register */
+#define SPRN_IABR2	0x3FA		/* 83xx */
+#define SPRN_IBCR	0x135		/* 83xx Insn Breakpoint Control Reg */
 #define SPRN_HID4	0x3F4		/* 970 HID4 */
 #define SPRN_HID5	0x3F6		/* 970 HID5 */
 #define SPRN_HID6	0x3F9	/* BE HID 6 */
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 1831b19..5cec939 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -45,10 +45,27 @@
  *
  */
 
+struct fsl_sleep_platform_data {
+	/*
+	 * The bits set in this mask will be cleared in the SCCR
+	 * when put to sleep, and restored on wakeup.
+	 */
+	u32 sccr_mask;
+};
+
+/*
+ * Calls to fsl_sleep_device do not nest -- if you call
+ * sleep twice without an intervening wake, you will not
+ * be able to wake the device again.
+ */
+void fsl_sleep_device(struct fsl_sleep_platform_data *data);
+void fsl_wake_device(struct fsl_sleep_platform_data *data);
+
 struct gianfar_platform_data {
 	/* device specific information */
 	u32	device_flags;
 	/* board specific information */
+	struct fsl_sleep_platform_data sleep;
 	u32	board_flags;
 	u32	bus_id;
 	u32	phy_id;
@@ -104,6 +121,7 @@ struct fsl_usb2_platform_data {
 	enum fsl_usb2_operating_modes	operating_mode;
 	enum fsl_usb2_phy_modes		phy_mode;
 	unsigned int			port_enables;
+	struct fsl_sleep_platform_data sleep;
 };
 
 /* Flags in fsl_usb2_mph_platform_data */
@@ -126,5 +144,11 @@ struct mpc8xx_pcmcia_ops {
 	int(*voltage_set)(int slot, int vcc, int vpp);
 };
 
+/* Returns non-zero if the current suspend operation would
+ * lead to a deep sleep (i.e. power removed from the core,
+ * instead of just the clock).
+ */
+int fsl_deep_sleep(void);
+
 #endif /* _FSL_DEVICE_H_ */
 #endif /* __KERNEL__ */
-- 
1.5.3.4

^ permalink raw reply related

* Re: [PATCH 1/7] Implement arch disable/enable irq hooks.
From: Josh Boyer @ 2007-10-23 21:33 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, paulus
In-Reply-To: <20071023212404.GA30942@loki.buserror.net>

On Tue, 23 Oct 2007 16:24:04 -0500
Scott Wood <scottwood@freescale.com> wrote:

> These hooks ensure that a decrementer interrupt is not pending when
> suspending; otherwise, problems may occur.  For example, with deep sleep
> on the 831x, a pending decrementer will cause a system freeze because the
> SoC thinks the decrementer interrupt would have woken the system, but the
> core must have interrupts disabled due to the setup required for deep
> sleep.
> 
> Signed-off-by: Scott Wood <scottwood@freescale.com>
> ---
> Please queue these patches for 2.6.25 if they do not offend.
> 
>  arch/powerpc/kernel/time.c    |   41 +++++++++++++++++++++++++++++++++++++++++
>  include/asm-powerpc/machdep.h |   13 +++++++++++++
>  2 files changed, 54 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
> index 9eb3284..5e2a39b 100644
> --- a/arch/powerpc/kernel/time.c
> +++ b/arch/powerpc/kernel/time.c
> @@ -647,6 +647,47 @@ void wakeup_decrementer(void)
>  	set_dec(ticks);
>  }
> 
> +#ifdef CONFIG_SUSPEND
> +void generic_suspend_disable_irqs(void)
> +{
> +	preempt_disable();
> +
> +	/* Disable the decrementer, so that it doesn't interfere
> +	 * with suspending.
> +	 */
> +
> +	set_dec(0x7fffffff);
> +	hard_irq_disable();
> +	set_dec(0x7fffffff);
> +}
> +
> +void generic_suspend_enable_irqs(void)
> +{
> +	wakeup_decrementer();
> +
> +	local_irq_enable();
> +	preempt_enable();
> +}

Should these be static functions?  Seems so...

> +
> +/* Overrides the weak version in kernel/power/main.c */
> +void arch_suspend_disable_irqs(void)
> +{
> +	if (ppc_md.suspend_disable_irqs)
> +		ppc_md.suspend_disable_irqs();
> +	else
> +		generic_suspend_disable_irqs();
> +}
> +
> +/* Overrides the weak version in kernel/power/main.c */
> +void arch_suspend_enable_irqs(void)
> +{
> +	if (ppc_md.suspend_enable_irqs)
> +		ppc_md.suspend_enable_irqs();
> +	else
> +		generic_suspend_enable_irqs();
> +}
> +#endif
> +
>  #ifdef CONFIG_SMP
>  void __init smp_space_timers(unsigned int max_cpus)
>  {
> diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
> index 6968f43..15ba15a 100644
> --- a/include/asm-powerpc/machdep.h
> +++ b/include/asm-powerpc/machdep.h
> @@ -253,6 +253,16 @@ struct machdep_calls {
>  	 */
>  	void (*machine_kexec)(struct kimage *image);
>  #endif /* CONFIG_KEXEC */
> +
> +#ifdef CONFIG_SUSPEND
> +	/* These are called to disable and enable, respectively, IRQs when
> +	 * entering a suspend state.  If NULL, then the generic versions
> +	 * will be called.  The generic versions disable/enable the
> +	 * decrementer along with interrupts.
> +	 */
> +	void (*suspend_disable_irqs)(void);
> +	void (*suspend_enable_irqs)(void);
> +#endif
>  };
> 
>  extern void power4_idle(void);
> @@ -326,5 +336,8 @@ static inline void log_error(char *buf, unsigned int err_type, int fatal)
>  		ppc_md.log_error(buf, err_type, fatal);
>  }
> 
> +void generic_suspend_disable_irqs(void);
> +void generic_suspend_enable_irqs(void);

And do they really need to be declared here?

josh

^ permalink raw reply

* Re: [PATCH 1/7] Implement arch disable/enable irq hooks.
From: Scott Wood @ 2007-10-23 21:34 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev, paulus
In-Reply-To: <20071023163301.4857393e@weaponx.rchland.ibm.com>

Josh Boyer wrote:
>> +#ifdef CONFIG_SUSPEND
>> +void generic_suspend_disable_irqs(void)
>> +{
>> +	preempt_disable();
>> +
>> +	/* Disable the decrementer, so that it doesn't interfere
>> +	 * with suspending.
>> +	 */
>> +
>> +	set_dec(0x7fffffff);
>> +	hard_irq_disable();
>> +	set_dec(0x7fffffff);
>> +}
>> +
>> +void generic_suspend_enable_irqs(void)
>> +{
>> +	wakeup_decrementer();
>> +
>> +	local_irq_enable();
>> +	preempt_enable();
>> +}
> 
> Should these be static functions?  Seems so...

I was asked to make them available to be called by non-generic 
implementations.

-Scott

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox