diff mbox

[08/12] pm: at91: rename file name: pm_slowclock.S -->pm_suspend.S

Message ID 1421741825-18226-9-git-send-email-wenyou.yang@atmel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Wenyou Yang Jan. 20, 2015, 8:17 a.m. UTC
Because the sram function is used for the suspend to standby mode as well,
more than suspend to memory, so renaming is more elegant.

Signed-off-by: Wenyou Yang <wenyou.yang@atmel.com>
Acked-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
 arch/arm/mach-at91/Makefile       |    2 +-
 arch/arm/mach-at91/pm_slowclock.S |  280 -------------------------------------
 arch/arm/mach-at91/pm_suspend.S   |  280 +++++++++++++++++++++++++++++++++++++
 3 files changed, 281 insertions(+), 281 deletions(-)
 delete mode 100644 arch/arm/mach-at91/pm_slowclock.S
 create mode 100644 arch/arm/mach-at91/pm_suspend.S

Comments

Sylvain Rochet Jan. 23, 2015, 7:17 p.m. UTC | #1
Hello Wenyou,

On Tue, Jan 20, 2015 at 04:17:01PM +0800, Wenyou Yang wrote:
> 
> diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S
> new file mode 100644
> index 0000000..420e730
> --- /dev/null


> +	/* Turn off the main oscillator */
> +	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
> +	bic	tmp1, tmp1, #AT91_PMC_MOSCEN

at91sam9x5 and probably others need a key here:
	orr     tmp1, tmp1, #AT91_PMC_KEY

> +	str	tmp1, [pmc, #AT91_CKGR_MOR]



> +	/* Wait for interrupt */
> +	mcr	p15, 0, tmp1, c7, c0, 4

The linux-3.10-at91 branch uses a different approach which seem 
necessary for newer board, you probably forget to merge the following:

/*
 * Put the processor to enter into Standby mode, wait for interrupt to wakeup
 */
	.macro _do_wfi

#if defined(CONFIG_CPU_V7)
	dsb

	/* Disable the processor clock */
	mov	tmp1, #AT91_PMC_PCK
	str	tmp1, [pmc, #AT91_PMC_SCDR]

	wfi		@ Wait For Interrupt
#else
	mcr	p15, 0, tmp1, c7, c0, 4
#endif

	.endm

	.text

ENTRY(at91_slow_clock)
(...)
	/* Wait for interrupt */
	_do_wfi
(...)




> +	/* Turn on the main oscillator */
> +	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
> +	orr	tmp1, tmp1, #AT91_PMC_MOSCEN

at91sam9x5 and probably others need a key here:
        orr     tmp1, tmp1, #AT91_PMC_KEY

> +	str	tmp1, [pmc, #AT91_CKGR_MOR]



What about the following parts which are also in linux-3.10-at91 branch 
but not in this rework, are they necessary ?

sdr_sr_done:
	/* Disable MPDDRC Clock*/
	cmp	ddrcid, #0
	beq	2f
	bic	tmp2, ddrcid, #0xe0 /* fetch lowest 5 bits */
	mov	tmp1, #0x01
	mov	tmp1, tmp1, lsl tmp2

	tst	ddrcid, #0x20	/* > 32 ? */
	beq	1f
	str	tmp1, [pmc, #AT91_PMC_PCDR1]
	b	2f
1:
	str	tmp1, [pmc, #AT91_PMC_PCDR]
2:

	/* Disable DDR Clock */
	mov 	tmp1, #AT91_PMC_SYS_DDR
	str	tmp1, [pmc, #AT91_PMC_SCDR]




	/* Enable MPDDRC Clock*/
	cmp	ddrcid, #0
	beq	4f
	bic	tmp2, ddrcid, #0xe0 /* fetch lowest 5 bits */
	mov	tmp1, #0x01
	mov	tmp1, tmp1, lsl tmp2

	tst	ddrcid, #0x20	/* > 32 ? */
	beq	3f
	str	tmp1, [pmc, #AT91_PMC_PCER1]
	b	4f
3:
	str	tmp1, [pmc, #AT91_PMC_PCER]
4:

	/* Enable DDR clock */
	mov 	tmp1, #AT91_PMC_SYS_DDR
	str	tmp1, [pmc, #AT91_PMC_SCER]



Sylvain
Alexandre Belloni Jan. 23, 2015, 11:17 p.m. UTC | #2
Hi,

On 23/01/2015 at 20:17:19 +0100, Sylvain Rochet wrote :
> Hello Wenyou,
> 
> On Tue, Jan 20, 2015 at 04:17:01PM +0800, Wenyou Yang wrote:
> > 
> > diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S
> > new file mode 100644
> > index 0000000..420e730
> > --- /dev/null
> 
> 
> > +	/* Turn off the main oscillator */
> > +	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
> > +	bic	tmp1, tmp1, #AT91_PMC_MOSCEN
> 
> at91sam9x5 and probably others need a key here:
> 	orr     tmp1, tmp1, #AT91_PMC_KEY
> 
> > +	str	tmp1, [pmc, #AT91_CKGR_MOR]
> 
> 
> 
> > +	/* Wait for interrupt */
> > +	mcr	p15, 0, tmp1, c7, c0, 4
> 
> The linux-3.10-at91 branch uses a different approach which seem 
> necessary for newer board, you probably forget to merge the following:
> 
> /*
>  * Put the processor to enter into Standby mode, wait for interrupt to wakeup
>  */
> 	.macro _do_wfi
> 
> #if defined(CONFIG_CPU_V7)
> 	dsb
> 
> 	/* Disable the processor clock */
> 	mov	tmp1, #AT91_PMC_PCK
> 	str	tmp1, [pmc, #AT91_PMC_SCDR]
> 
> 	wfi		@ Wait For Interrupt
> #else
> 	mcr	p15, 0, tmp1, c7, c0, 4
> #endif
> 
> 	.endm
> 
> 	.text
> 
> ENTRY(at91_slow_clock)
> (...)
> 	/* Wait for interrupt */
> 	_do_wfi
> (...)
> 
> 
> 
> 
> > +	/* Turn on the main oscillator */
> > +	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
> > +	orr	tmp1, tmp1, #AT91_PMC_MOSCEN
> 
> at91sam9x5 and probably others need a key here:
>         orr     tmp1, tmp1, #AT91_PMC_KEY
> 
> > +	str	tmp1, [pmc, #AT91_CKGR_MOR]
> 
> 
> 
> What about the following parts which are also in linux-3.10-at91 branch 
> but not in this rework, are they necessary ?
> 
> sdr_sr_done:
> 	/* Disable MPDDRC Clock*/
> 	cmp	ddrcid, #0
> 	beq	2f
> 	bic	tmp2, ddrcid, #0xe0 /* fetch lowest 5 bits */
> 	mov	tmp1, #0x01
> 	mov	tmp1, tmp1, lsl tmp2
> 
> 	tst	ddrcid, #0x20	/* > 32 ? */
> 	beq	1f
> 	str	tmp1, [pmc, #AT91_PMC_PCDR1]
> 	b	2f
> 1:
> 	str	tmp1, [pmc, #AT91_PMC_PCDR]
> 2:
> 
> 	/* Disable DDR Clock */
> 	mov 	tmp1, #AT91_PMC_SYS_DDR
> 	str	tmp1, [pmc, #AT91_PMC_SCDR]
> 
> 
> 
> 
> 	/* Enable MPDDRC Clock*/
> 	cmp	ddrcid, #0
> 	beq	4f
> 	bic	tmp2, ddrcid, #0xe0 /* fetch lowest 5 bits */
> 	mov	tmp1, #0x01
> 	mov	tmp1, tmp1, lsl tmp2
> 
> 	tst	ddrcid, #0x20	/* > 32 ? */
> 	beq	3f
> 	str	tmp1, [pmc, #AT91_PMC_PCER1]
> 	b	4f
> 3:
> 	str	tmp1, [pmc, #AT91_PMC_PCER]
> 4:
> 
> 	/* Enable DDR clock */
> 	mov 	tmp1, #AT91_PMC_SYS_DDR
> 	str	tmp1, [pmc, #AT91_PMC_SCER]
> 
> 

This is a rework, what is part of linux-3.10-at91 and not yet present in
mainline should be part of a following series. I would prefer not mixing
reworks and "new" functionalities (they have been present in the atmel
tree for a while but never mainlined). I would say that PM on 9x5, n12
and sama5 in mainline is clearly not well tested and is lagging behind
the atmel tree.
Sylvain Rochet Jan. 25, 2015, 1:30 p.m. UTC | #3
Hello Alexandre,


On Sat, Jan 24, 2015 at 12:17:38AM +0100, Alexandre Belloni wrote:
> 
> This is a rework, what is part of linux-3.10-at91 and not yet present in
> mainline should be part of a following series. I would prefer not mixing
> reworks and "new" functionalities (they have been present in the atmel
> tree for a while but never mainlined).

I agree, I just didn't know a new series will follow, maybe I missed 
this point.

Maybe I am a bit too picky (or boring: if I am, please told me), but 
this series by itself adds regression to all users of >= 9x5 boards 
(sama5, …) because it merges MEM target and MEM+SLOW_CLOCK target, which 
used to be too different target states, not selectable at runtime indeed 
but this is still in practice two different target states. Note that I 
am not saying that MEM target and MEM+SLOW_CLOCK target should not be 
merged, they should, absolutely ;-). For >= 9x5 boards (sama5, …), MEM 
target works and MEM+SLOW_CLOCK target does not work, MEM and 
MEM+SLOW_CLOCK merge breaks MEM target for those boards.

There is however a good news !, at91_pm_verify_clocks() used to be 
called for MEM target without considering if it was MEM (~STANDBY) or 
MEM+SLOW_CLOCK. It means that all MEM target users can with very good 
chance go to a deeper sleep state without issue because 
at91_pm_verify_clocks() successfully checked on those boards and is why 
we can merge MEM and MEM+SLOW_CLOCK without adding a regression.

Care should be taken to pull-request at the same time both the rework 
and the above cited following series about slow clock support for all 
known boards so we don't break MEM target for a release cycle.


> I would say that PM on 9x5, n12 and sama5 in mainline is clearly not 
> well tested and is lagging behind the atmel tree.

Well, at the current mainline state, everything works fine for me except 
slow clock mode, I thoroughly checked everything else.


Sylvain
Wenyou Yang Jan. 26, 2015, 1:25 a.m. UTC | #4
Hi Sylvain,

Thank you for your review.

> -----Original Message-----
> From: Sylvain Rochet [mailto:sylvain.rochet@finsecur.com]
> Sent: Saturday, January 24, 2015 3:17 AM
> To: Yang, Wenyou
> Cc: Ferre, Nicolas; linux@arm.linux.org.uk; linux-kernel@vger.kernel.org;
> alexandre.belloni@free-electrons.com; peda@axentia.se; linux-arm-
> kernel@lists.infradead.org
> Subject: Re: [PATCH 08/12] pm: at91: rename file name: pm_slowclock.S --
> >pm_suspend.S
> 
> Hello Wenyou,
> 
> On Tue, Jan 20, 2015 at 04:17:01PM +0800, Wenyou Yang wrote:
> >
> > diff --git a/arch/arm/mach-at91/pm_suspend.S
> > b/arch/arm/mach-at91/pm_suspend.S new file mode 100644 index
> > 0000000..420e730
> > --- /dev/null
> 
> 
> > +	/* Turn off the main oscillator */
> > +	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
> > +	bic	tmp1, tmp1, #AT91_PMC_MOSCEN
> 
> at91sam9x5 and probably others need a key here:
> 	orr     tmp1, tmp1, #AT91_PMC_KEY
> 
Yes, I am preparing the patches to support other SoCs.

> > +	str	tmp1, [pmc, #AT91_CKGR_MOR]
> 
> 
> 
> > +	/* Wait for interrupt */
> > +	mcr	p15, 0, tmp1, c7, c0, 4
> 
> The linux-3.10-at91 branch uses a different approach which seem necessary for
> newer board, you probably forget to merge the following:
> 
> /*
>  * Put the processor to enter into Standby mode, wait for interrupt to wakeup  */
> 	.macro _do_wfi
> 
> #if defined(CONFIG_CPU_V7)
> 	dsb
> 
> 	/* Disable the processor clock */
> 	mov	tmp1, #AT91_PMC_PCK
> 	str	tmp1, [pmc, #AT91_PMC_SCDR]
> 
> 	wfi		@ Wait For Interrupt
> #else
> 	mcr	p15, 0, tmp1, c7, c0, 4
> #endif
> 
> 	.endm
> 
> 	.text
> 
I will send the new patch serials to support it in this week. Thanks.

> ENTRY(at91_slow_clock)
> (...)
> 	/* Wait for interrupt */
> 	_do_wfi
> (...)
> 
> 
> 
> 
> > +	/* Turn on the main oscillator */
> > +	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
> > +	orr	tmp1, tmp1, #AT91_PMC_MOSCEN
> 
> at91sam9x5 and probably others need a key here:
>         orr     tmp1, tmp1, #AT91_PMC_KEY
> 
> > +	str	tmp1, [pmc, #AT91_CKGR_MOR]
> 
> 
> 
> What about the following parts which are also in linux-3.10-at91 branch but not in
> this rework, are they necessary ?
Yes, they are necessary, I will send the next patch serial in this week.

> 
> sdr_sr_done:
> 	/* Disable MPDDRC Clock*/
> 	cmp	ddrcid, #0
> 	beq	2f
> 	bic	tmp2, ddrcid, #0xe0 /* fetch lowest 5 bits */
> 	mov	tmp1, #0x01
> 	mov	tmp1, tmp1, lsl tmp2
> 
> 	tst	ddrcid, #0x20	/* > 32 ? */
> 	beq	1f
> 	str	tmp1, [pmc, #AT91_PMC_PCDR1]
> 	b	2f
> 1:
> 	str	tmp1, [pmc, #AT91_PMC_PCDR]
> 2:
> 
> 	/* Disable DDR Clock */
> 	mov 	tmp1, #AT91_PMC_SYS_DDR
> 	str	tmp1, [pmc, #AT91_PMC_SCDR]
> 
> 
> 
> 
> 	/* Enable MPDDRC Clock*/
> 	cmp	ddrcid, #0
> 	beq	4f
> 	bic	tmp2, ddrcid, #0xe0 /* fetch lowest 5 bits */
> 	mov	tmp1, #0x01
> 	mov	tmp1, tmp1, lsl tmp2
> 
> 	tst	ddrcid, #0x20	/* > 32 ? */
> 	beq	3f
> 	str	tmp1, [pmc, #AT91_PMC_PCER1]
> 	b	4f
> 3:
> 	str	tmp1, [pmc, #AT91_PMC_PCER]
> 4:
> 
> 	/* Enable DDR clock */
> 	mov 	tmp1, #AT91_PMC_SYS_DDR
> 	str	tmp1, [pmc, #AT91_PMC_SCER]
> 
> 
> 
> Sylvain

Best Regards,
Wenyou Yang
diff mbox

Patch

diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 9c755d9..80473d8 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -18,7 +18,7 @@  obj-$(CONFIG_SOC_SAMA5)		+= board-dt-sama5.o
 
 # Power Management
 obj-$(CONFIG_PM)		+= pm.o
-obj-$(CONFIG_PM)		+= pm_slowclock.o
+obj-$(CONFIG_PM)		+= pm_suspend.o
 
 ifeq ($(CONFIG_PM_DEBUG),y)
 CFLAGS_pm.o += -DDEBUG
diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S
deleted file mode 100644
index 92d7e63..0000000
--- a/arch/arm/mach-at91/pm_slowclock.S
+++ /dev/null
@@ -1,280 +0,0 @@ 
-/*
- * arch/arm/mach-at91/pm_slow_clock.S
- *
- *  Copyright (C) 2006 Savin Zlobec
- *
- * AT91SAM9 support:
- *  Copyright (C) 2007 Anti Sullin <anti.sullin@artecdesign.ee
- *
- * 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/linkage.h>
-#include <linux/clk/at91_pmc.h>
-#include <mach/at91_ramc.h>
-
-#include "pm.h"
-
-pmc	.req	r0
-sdramc	.req	r1
-ramc1	.req	r2
-memctrl	.req	r3
-tmp1	.req	r4
-tmp2	.req	r5
-mode	.req	r6
-
-/*
- * Wait until master clock is ready (after switching master clock source)
- */
-	.macro wait_mckrdy
-1:	ldr	tmp1, [pmc, #AT91_PMC_SR]
-	tst	tmp1, #AT91_PMC_MCKRDY
-	beq	1b
-	.endm
-
-/*
- * Wait until master oscillator has stabilized.
- */
-	.macro wait_moscrdy
-1:	ldr	tmp1, [pmc, #AT91_PMC_SR]
-	tst	tmp1, #AT91_PMC_MOSCS
-	beq	1b
-	.endm
-
-/*
- * Wait until PLLA has locked.
- */
-	.macro wait_pllalock
-1:	ldr	tmp1, [pmc, #AT91_PMC_SR]
-	tst	tmp1, #AT91_PMC_LOCKA
-	beq	1b
-	.endm
-
-	.text
-
-/* void at91_slow_clock(void __iomem *pmc, void __iomem *sdramc,
- *			void __iomem *ramc1, int memctrl)
- */
-ENTRY(at91_slow_clock)
-	/* Save registers on stack */
-	stmfd	sp!, {r4 - r12, lr}
-
-	/*
-	 * Register usage:
-	 *  R0 = Base address of AT91_PMC
-	 *  R1 = Base address of RAM Controller (SDRAM, DDRSDR, or AT91_SYS)
-	 *  R2 = Base address of second RAM Controller or 0 if not present
-	 *  R3 = Memory controller
-	 *  R4 = temporary register
-	 *  R5 = temporary register
-	 */
-
-	/* Drain write buffer */
-	mov	tmp1, #0
-	mcr	p15, 0, tmp1, c7, c10, 4
-
-	mov	tmp1, memctrl
-	mov	tmp2, tmp1, lsr#AT91_PM_MODE_OFFSET
-	and	mode, tmp2, #AT91_PM_MODE_MASK
-
-	mov	tmp1, memctrl
-	and	memctrl, tmp1, #AT91_PM_MEMCTRL_MASK
-
-	cmp	memctrl, #AT91_MEMCTRL_MC
-	bne	ddr_sr_enable
-
-	/*
-	 * at91rm9200 Memory controller
-	 */
-	/* Put SDRAM in self-refresh mode */
-	mov	tmp1, #1
-	str	tmp1, [sdramc, #AT91RM9200_SDRAMC_SRR]
-	b	sdr_sr_done
-
-	/*
-	 * DDRSDR Memory controller
-	 */
-ddr_sr_enable:
-	cmp	memctrl, #AT91_MEMCTRL_DDRSDR
-	bne	sdr_sr_enable
-
-	/* LPDDR1 --> force DDR2 mode during self-refresh */
-	ldr	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
-	str	tmp1, .saved_sam9_mdr
-	bic	tmp1, tmp1, #~AT91_DDRSDRC_MD
-	cmp	tmp1, #AT91_DDRSDRC_MD_LOW_POWER_DDR
-	ldreq	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
-	biceq	tmp1, tmp1, #AT91_DDRSDRC_MD
-	orreq	tmp1, tmp1, #AT91_DDRSDRC_MD_DDR2
-	streq	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
-
-	/* prepare for DDRAM self-refresh mode */
-	ldr	tmp1, [sdramc, #AT91_DDRSDRC_LPR]
-	str	tmp1, .saved_sam9_lpr
-	bic	tmp1, #AT91_DDRSDRC_LPCB
-	orr	tmp1, #AT91_DDRSDRC_LPCB_SELF_REFRESH
-
-	/* figure out if we use the second ram controller */
-	cmp	ramc1, #0
-	beq	ddr_no_2nd_ctrl
-
-	ldr	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
-	str	tmp2, .saved_sam9_mdr1
-	bic	tmp2, tmp2, #~AT91_DDRSDRC_MD
-	cmp	tmp2, #AT91_DDRSDRC_MD_LOW_POWER_DDR
-	ldreq	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
-	biceq	tmp2, tmp2, #AT91_DDRSDRC_MD
-	orreq	tmp2, tmp2, #AT91_DDRSDRC_MD_DDR2
-	streq	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
-
-	ldr	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
-	str	tmp2, .saved_sam9_lpr1
-	bic	tmp2, #AT91_DDRSDRC_LPCB
-	orr	tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
-
-	/* Enable DDRAM self-refresh mode */
-	str	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
-ddr_no_2nd_ctrl:
-	str	tmp1, [sdramc, #AT91_DDRSDRC_LPR]
-
-	b	sdr_sr_done
-
-	/*
-	 * SDRAMC Memory controller
-	 */
-sdr_sr_enable:
-	/* Enable SDRAM self-refresh mode */
-	ldr	tmp1, [sdramc, #AT91_SDRAMC_LPR]
-	str	tmp1, .saved_sam9_lpr
-
-	bic	tmp1, #AT91_SDRAMC_LPCB
-	orr	tmp1, #AT91_SDRAMC_LPCB_SELF_REFRESH
-	str	tmp1, [sdramc, #AT91_SDRAMC_LPR]
-
-sdr_sr_done:
-	tst	mode, #AT91_PM_SLOW_CLOCK
-	beq	skip_disable_clock
-
-	/* Save Master clock setting */
-	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
-	str	tmp1, .saved_mckr
-
-	/*
-	 * Set the Master clock source to slow clock
-	 */
-	bic	tmp1, tmp1, #AT91_PMC_CSS
-	str	tmp1, [pmc, #AT91_PMC_MCKR]
-
-	wait_mckrdy
-
-	/* Save PLLA setting and disable it */
-	ldr	tmp1, [pmc, #AT91_CKGR_PLLAR]
-	str	tmp1, .saved_pllar
-
-	mov	tmp1, #AT91_PMC_PLLCOUNT
-	orr	tmp1, tmp1, #(1 << 29)		/* bit 29 always set */
-	str	tmp1, [pmc, #AT91_CKGR_PLLAR]
-
-	/* Turn off the main oscillator */
-	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
-	bic	tmp1, tmp1, #AT91_PMC_MOSCEN
-	str	tmp1, [pmc, #AT91_CKGR_MOR]
-
-skip_disable_clock:
-	/* Wait for interrupt */
-	mcr	p15, 0, tmp1, c7, c0, 4
-
-	tst	mode, #AT91_PM_SLOW_CLOCK
-	beq	skip_enable_clock
-
-	/* Turn on the main oscillator */
-	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
-	orr	tmp1, tmp1, #AT91_PMC_MOSCEN
-	str	tmp1, [pmc, #AT91_CKGR_MOR]
-
-	wait_moscrdy
-
-	/* Restore PLLA setting */
-	ldr	tmp1, .saved_pllar
-	str	tmp1, [pmc, #AT91_CKGR_PLLAR]
-
-	tst	tmp1, #(AT91_PMC_MUL &  0xff0000)
-	bne	3f
-	tst	tmp1, #(AT91_PMC_MUL & ~0xff0000)
-	beq	4f
-3:
-	wait_pllalock
-4:
-
-	/*
-	 * Restore master clock setting
-	 */
-2:	ldr	tmp1, .saved_mckr
-	str	tmp1, [pmc, #AT91_PMC_MCKR]
-
-	wait_mckrdy
-
-skip_enable_clock:
-	/*
-	 * at91rm9200 Memory controller
-	 * Do nothing - self-refresh is automatically disabled.
-	 */
-	cmp	memctrl, #AT91_MEMCTRL_MC
-	beq	ram_restored
-
-	/*
-	 * DDRSDR Memory controller
-	 */
-	cmp	memctrl, #AT91_MEMCTRL_DDRSDR
-	bne	sdr_en_restore
-	/* Restore MDR in case of LPDDR1 */
-	ldr	tmp1, .saved_sam9_mdr
-	str	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
-	/* Restore LPR on AT91 with DDRAM */
-	ldr	tmp1, .saved_sam9_lpr
-	str	tmp1, [sdramc, #AT91_DDRSDRC_LPR]
-
-	/* if we use the second ram controller */
-	cmp	ramc1, #0
-	ldrne	tmp2, .saved_sam9_mdr1
-	strne	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
-	ldrne	tmp2, .saved_sam9_lpr1
-	strne	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
-
-	b	ram_restored
-
-	/*
-	 * SDRAMC Memory controller
-	 */
-sdr_en_restore:
-	/* Restore LPR on AT91 with SDRAM */
-	ldr	tmp1, .saved_sam9_lpr
-	str	tmp1, [sdramc, #AT91_SDRAMC_LPR]
-
-ram_restored:
-	/* Restore registers, and return */
-	ldmfd	sp!, {r4 - r12, pc}
-
-
-.saved_mckr:
-	.word 0
-
-.saved_pllar:
-	.word 0
-
-.saved_sam9_lpr:
-	.word 0
-
-.saved_sam9_lpr1:
-	.word 0
-
-.saved_sam9_mdr:
-	.word 0
-
-.saved_sam9_mdr1:
-	.word 0
-
-ENTRY(at91_slow_clock_sz)
-	.word .-at91_slow_clock
diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S
new file mode 100644
index 0000000..420e730
--- /dev/null
+++ b/arch/arm/mach-at91/pm_suspend.S
@@ -0,0 +1,280 @@ 
+/*
+ * arch/arm/mach-at91/pm_suspend.S
+ *
+ *  Copyright (C) 2006 Savin Zlobec
+ *
+ * AT91SAM9 support:
+ *  Copyright (C) 2007 Anti Sullin <anti.sullin@artecdesign.ee
+ *
+ * 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/linkage.h>
+#include <linux/clk/at91_pmc.h>
+#include <mach/at91_ramc.h>
+
+#include "pm.h"
+
+pmc	.req	r0
+sdramc	.req	r1
+ramc1	.req	r2
+memctrl	.req	r3
+tmp1	.req	r4
+tmp2	.req	r5
+mode	.req	r6
+
+/*
+ * Wait until master clock is ready (after switching master clock source)
+ */
+	.macro wait_mckrdy
+1:	ldr	tmp1, [pmc, #AT91_PMC_SR]
+	tst	tmp1, #AT91_PMC_MCKRDY
+	beq	1b
+	.endm
+
+/*
+ * Wait until master oscillator has stabilized.
+ */
+	.macro wait_moscrdy
+1:	ldr	tmp1, [pmc, #AT91_PMC_SR]
+	tst	tmp1, #AT91_PMC_MOSCS
+	beq	1b
+	.endm
+
+/*
+ * Wait until PLLA has locked.
+ */
+	.macro wait_pllalock
+1:	ldr	tmp1, [pmc, #AT91_PMC_SR]
+	tst	tmp1, #AT91_PMC_LOCKA
+	beq	1b
+	.endm
+
+	.text
+
+/* void at91_slow_clock(void __iomem *pmc, void __iomem *sdramc,
+ *			void __iomem *ramc1, int memctrl)
+ */
+ENTRY(at91_slow_clock)
+	/* Save registers on stack */
+	stmfd	sp!, {r4 - r12, lr}
+
+	/*
+	 * Register usage:
+	 *  R0 = Base address of AT91_PMC
+	 *  R1 = Base address of RAM Controller (SDRAM, DDRSDR, or AT91_SYS)
+	 *  R2 = Base address of second RAM Controller or 0 if not present
+	 *  R3 = Memory controller
+	 *  R4 = temporary register
+	 *  R5 = temporary register
+	 */
+
+	/* Drain write buffer */
+	mov	tmp1, #0
+	mcr	p15, 0, tmp1, c7, c10, 4
+
+	mov	tmp1, memctrl
+	mov	tmp2, tmp1, lsr#AT91_PM_MODE_OFFSET
+	and	mode, tmp2, #AT91_PM_MODE_MASK
+
+	mov	tmp1, memctrl
+	and	memctrl, tmp1, #AT91_PM_MEMCTRL_MASK
+
+	cmp	memctrl, #AT91_MEMCTRL_MC
+	bne	ddr_sr_enable
+
+	/*
+	 * at91rm9200 Memory controller
+	 */
+	/* Put SDRAM in self-refresh mode */
+	mov	tmp1, #1
+	str	tmp1, [sdramc, #AT91RM9200_SDRAMC_SRR]
+	b	sdr_sr_done
+
+	/*
+	 * DDRSDR Memory controller
+	 */
+ddr_sr_enable:
+	cmp	memctrl, #AT91_MEMCTRL_DDRSDR
+	bne	sdr_sr_enable
+
+	/* LPDDR1 --> force DDR2 mode during self-refresh */
+	ldr	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+	str	tmp1, .saved_sam9_mdr
+	bic	tmp1, tmp1, #~AT91_DDRSDRC_MD
+	cmp	tmp1, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+	ldreq	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+	biceq	tmp1, tmp1, #AT91_DDRSDRC_MD
+	orreq	tmp1, tmp1, #AT91_DDRSDRC_MD_DDR2
+	streq	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+
+	/* prepare for DDRAM self-refresh mode */
+	ldr	tmp1, [sdramc, #AT91_DDRSDRC_LPR]
+	str	tmp1, .saved_sam9_lpr
+	bic	tmp1, #AT91_DDRSDRC_LPCB
+	orr	tmp1, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+
+	/* figure out if we use the second ram controller */
+	cmp	ramc1, #0
+	beq	ddr_no_2nd_ctrl
+
+	ldr	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+	str	tmp2, .saved_sam9_mdr1
+	bic	tmp2, tmp2, #~AT91_DDRSDRC_MD
+	cmp	tmp2, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+	ldreq	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+	biceq	tmp2, tmp2, #AT91_DDRSDRC_MD
+	orreq	tmp2, tmp2, #AT91_DDRSDRC_MD_DDR2
+	streq	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+
+	ldr	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+	str	tmp2, .saved_sam9_lpr1
+	bic	tmp2, #AT91_DDRSDRC_LPCB
+	orr	tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+
+	/* Enable DDRAM self-refresh mode */
+	str	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+ddr_no_2nd_ctrl:
+	str	tmp1, [sdramc, #AT91_DDRSDRC_LPR]
+
+	b	sdr_sr_done
+
+	/*
+	 * SDRAMC Memory controller
+	 */
+sdr_sr_enable:
+	/* Enable SDRAM self-refresh mode */
+	ldr	tmp1, [sdramc, #AT91_SDRAMC_LPR]
+	str	tmp1, .saved_sam9_lpr
+
+	bic	tmp1, #AT91_SDRAMC_LPCB
+	orr	tmp1, #AT91_SDRAMC_LPCB_SELF_REFRESH
+	str	tmp1, [sdramc, #AT91_SDRAMC_LPR]
+
+sdr_sr_done:
+	tst	mode, #AT91_PM_SLOW_CLOCK
+	beq	skip_disable_clock
+
+	/* Save Master clock setting */
+	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
+	str	tmp1, .saved_mckr
+
+	/*
+	 * Set the Master clock source to slow clock
+	 */
+	bic	tmp1, tmp1, #AT91_PMC_CSS
+	str	tmp1, [pmc, #AT91_PMC_MCKR]
+
+	wait_mckrdy
+
+	/* Save PLLA setting and disable it */
+	ldr	tmp1, [pmc, #AT91_CKGR_PLLAR]
+	str	tmp1, .saved_pllar
+
+	mov	tmp1, #AT91_PMC_PLLCOUNT
+	orr	tmp1, tmp1, #(1 << 29)		/* bit 29 always set */
+	str	tmp1, [pmc, #AT91_CKGR_PLLAR]
+
+	/* Turn off the main oscillator */
+	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
+	bic	tmp1, tmp1, #AT91_PMC_MOSCEN
+	str	tmp1, [pmc, #AT91_CKGR_MOR]
+
+skip_disable_clock:
+	/* Wait for interrupt */
+	mcr	p15, 0, tmp1, c7, c0, 4
+
+	tst	mode, #AT91_PM_SLOW_CLOCK
+	beq	skip_enable_clock
+
+	/* Turn on the main oscillator */
+	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
+	orr	tmp1, tmp1, #AT91_PMC_MOSCEN
+	str	tmp1, [pmc, #AT91_CKGR_MOR]
+
+	wait_moscrdy
+
+	/* Restore PLLA setting */
+	ldr	tmp1, .saved_pllar
+	str	tmp1, [pmc, #AT91_CKGR_PLLAR]
+
+	tst	tmp1, #(AT91_PMC_MUL &  0xff0000)
+	bne	3f
+	tst	tmp1, #(AT91_PMC_MUL & ~0xff0000)
+	beq	4f
+3:
+	wait_pllalock
+4:
+
+	/*
+	 * Restore master clock setting
+	 */
+2:	ldr	tmp1, .saved_mckr
+	str	tmp1, [pmc, #AT91_PMC_MCKR]
+
+	wait_mckrdy
+
+skip_enable_clock:
+	/*
+	 * at91rm9200 Memory controller
+	 * Do nothing - self-refresh is automatically disabled.
+	 */
+	cmp	memctrl, #AT91_MEMCTRL_MC
+	beq	ram_restored
+
+	/*
+	 * DDRSDR Memory controller
+	 */
+	cmp	memctrl, #AT91_MEMCTRL_DDRSDR
+	bne	sdr_en_restore
+	/* Restore MDR in case of LPDDR1 */
+	ldr	tmp1, .saved_sam9_mdr
+	str	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+	/* Restore LPR on AT91 with DDRAM */
+	ldr	tmp1, .saved_sam9_lpr
+	str	tmp1, [sdramc, #AT91_DDRSDRC_LPR]
+
+	/* if we use the second ram controller */
+	cmp	ramc1, #0
+	ldrne	tmp2, .saved_sam9_mdr1
+	strne	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+	ldrne	tmp2, .saved_sam9_lpr1
+	strne	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+
+	b	ram_restored
+
+	/*
+	 * SDRAMC Memory controller
+	 */
+sdr_en_restore:
+	/* Restore LPR on AT91 with SDRAM */
+	ldr	tmp1, .saved_sam9_lpr
+	str	tmp1, [sdramc, #AT91_SDRAMC_LPR]
+
+ram_restored:
+	/* Restore registers, and return */
+	ldmfd	sp!, {r4 - r12, pc}
+
+
+.saved_mckr:
+	.word 0
+
+.saved_pllar:
+	.word 0
+
+.saved_sam9_lpr:
+	.word 0
+
+.saved_sam9_lpr1:
+	.word 0
+
+.saved_sam9_mdr:
+	.word 0
+
+.saved_sam9_mdr1:
+	.word 0
+
+ENTRY(at91_slow_clock_sz)
+	.word .-at91_slow_clock