Commit 8e6de970 authored by Nicolas Ferre's avatar Nicolas Ferre
Browse files

Merge tag 'at91-cleanup' into at91-4.1-multiplatform

First batch of cleanup for 4.1:
- little phy fixup that is not needed anymore
- hudge cleanup of the PM code:
  - removal of "use slow clock" option => always use this for suspend to RAM
  - quicker suspend as the asm function is copied only once to SRAM
  - use of the same asm function for "standby" and "mem" types of suspend
    actions
  - adaptation to the ARMv7 processors
parents 5e358e39 385acc0d
Loading
Loading
Loading
Loading
+3 −15
Original line number Diff line number Diff line
@@ -24,7 +24,7 @@ config SOC_SAMA5
	select GENERIC_CLOCKEVENTS
	select MEMORY
	select ATMEL_SDRAMC
	select PHYLIB if NETDEVICES
	select SRAM if PM

menu "Atmel AT91 System-on-Chip"

@@ -81,6 +81,7 @@ config SOC_AT91RM9200
	select CPU_ARM920T
	select GENERIC_CLOCKEVENTS
	select HAVE_AT91_USB_CLK
	select SRAM if PM

config SOC_AT91SAM9
	bool "AT91SAM9"
@@ -94,6 +95,7 @@ config SOC_AT91SAM9
	select HAVE_AT91_UTMI
	select HAVE_FB_ATMEL
	select MEMORY
	select SRAM if PM
	help
	  Select this if you are using one of those Atmel SoC:
	    AT91SAM9260
@@ -116,20 +118,6 @@ endif # SOC_SAM_V4_V5

comment "AT91 Feature Selections"

config AT91_SLOW_CLOCK
	bool "Suspend-to-RAM disables main oscillator"
	select SRAM
	depends on SUSPEND
	help
	  Select this if you want Suspend-to-RAM to save the most power
	  possible (without powering off the CPU) by disabling the PLLs
	  and main oscillator so that only the 32 KiHz clock is available.

	  When only that slow-clock is available, some peripherals lose
	  functionality.  Many can't issue wakeup events unless faster
	  clocks are available.  Some lose their operating state and
	  need to be completely re-initialized.

config AT91_TIMER_HZ
       int "Kernel HZ (jiffies per second)"
       range 32 1024
+1 −1
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@ obj-$(CONFIG_SOC_SAMA5) += sama5.o

# Power Management
obj-$(CONFIG_PM)		+= pm.o
obj-$(CONFIG_AT91_SLOW_CLOCK)	+= pm_slowclock.o
obj-$(CONFIG_PM)		+= pm_suspend.o

ifeq ($(CONFIG_PM_DEBUG),y)
CFLAGS_pm.o += -DDEBUG
+67 −72
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@
#include <linux/atomic.h>
#include <asm/mach/time.h>
#include <asm/mach/irq.h>
#include <asm/fncpy.h>
#include <asm/cacheflush.h>

#include <mach/cpu.h>
#include <mach/hardware.h>
@@ -41,7 +43,6 @@ static struct {
	int memctrl;
} at91_pm_data;

static void (*at91_pm_standby)(void);
void __iomem *at91_ramc_base[2];

static int at91_pm_valid_state(suspend_state_t state)
@@ -119,15 +120,28 @@ int at91_suspend_entering_slow_clock(void)
}
EXPORT_SYMBOL(at91_suspend_entering_slow_clock);


static void (*slow_clock)(void __iomem *pmc, void __iomem *ramc0,
static void (*at91_suspend_sram_fn)(void __iomem *pmc, void __iomem *ramc0,
			  void __iomem *ramc1, int memctrl);

#ifdef CONFIG_AT91_SLOW_CLOCK
extern void at91_slow_clock(void __iomem *pmc, void __iomem *ramc0,
extern void at91_pm_suspend_in_sram(void __iomem *pmc, void __iomem *ramc0,
			    void __iomem *ramc1, int memctrl);
extern u32 at91_slow_clock_sz;
#endif
extern u32 at91_pm_suspend_in_sram_sz;

static void at91_pm_suspend(suspend_state_t state)
{
	unsigned int pm_data = at91_pm_data.memctrl;

	pm_data |= (state == PM_SUSPEND_MEM) ?
				AT91_PM_MODE(AT91_PM_SLOW_CLOCK) : 0;

	flush_cache_all();
	outer_disable();

	at91_suspend_sram_fn(at91_pmc_base, at91_ramc_base[0],
				at91_ramc_base[1], pm_data);

	outer_resume();
}

static int at91_pm_enter(suspend_state_t state)
{
@@ -136,8 +150,8 @@ static int at91_pm_enter(suspend_state_t state)
	switch (state) {
	/*
	 * Suspend-to-RAM is like STANDBY plus slow clock mode, so
		 * drivers must suspend more deeply:  only the master clock
		 * controller may be using the main oscillator.
	 * drivers must suspend more deeply, the master clock switches
	 * to the clk32k and turns off the main oscillator
	 */
	case PM_SUSPEND_MEM:
		/*
@@ -146,23 +160,9 @@ static int at91_pm_enter(suspend_state_t state)
		if (!at91_pm_verify_clocks())
			goto error;

			/*
			 * Enter slow clock mode by switching over to clk32k and
			 * turning off the main oscillator; reverse on wakeup.
			 */
			if (slow_clock) {
#ifdef CONFIG_AT91_SLOW_CLOCK
				/* copy slow_clock handler to SRAM, and call it */
				memcpy(slow_clock, at91_slow_clock, at91_slow_clock_sz);
#endif
				slow_clock(at91_pmc_base, at91_ramc_base[0],
					   at91_ramc_base[1],
					   at91_pm_data.memctrl);
		at91_pm_suspend(state);

		break;
			} else {
				pr_info("AT91: PM - no slow clock mode enabled ...\n");
				/* FALLTHROUGH leaving master clock alone */
			}

	/*
	 * STANDBY mode has *all* drivers suspended; ignores irqs not
@@ -171,15 +171,7 @@ static int at91_pm_enter(suspend_state_t state)
	 * nothing fancy done with main or cpu clocks.
	 */
	case PM_SUSPEND_STANDBY:
			/*
			 * NOTE: the Wait-for-Interrupt instruction needs to be
			 * in icache so no SDRAM accesses are needed until the
			 * wakeup IRQ occurs and self-refresh is terminated.
			 * For ARM 926 based chips, this requirement is weaker
			 * as at91sam9 can access a RAM in self-refresh mode.
			 */
			if (at91_pm_standby)
				at91_pm_standby();
		at91_pm_suspend(state);
		break;

	case PM_SUSPEND_ON:
@@ -218,12 +210,10 @@ static struct platform_device at91_cpuidle_device = {
	.name = "cpuidle-at91",
};

void at91_pm_set_standby(void (*at91_standby)(void))
static void at91_pm_set_standby(void (*at91_standby)(void))
{
	if (at91_standby) {
	if (at91_standby)
		at91_cpuidle_device.dev.platform_data = at91_standby;
		at91_pm_standby = at91_standby;
	}
}

static const struct of_device_id ramc_ids[] __initconst = {
@@ -263,7 +253,6 @@ static __init void at91_dt_ramc(void)
	at91_pm_set_standby(standby);
}

#ifdef CONFIG_AT91_SLOW_CLOCK
static void __init at91_pm_sram_init(void)
{
	struct gen_pool *sram_pool;
@@ -291,30 +280,36 @@ static void __init at91_pm_sram_init(void)
		return;
	}

	sram_base = gen_pool_alloc(sram_pool, at91_slow_clock_sz);
	sram_base = gen_pool_alloc(sram_pool, at91_pm_suspend_in_sram_sz);
	if (!sram_base) {
		pr_warn("%s: unable to alloc ocram!\n", __func__);
		pr_warn("%s: unable to alloc sram!\n", __func__);
		return;
	}

	sram_pbase = gen_pool_virt_to_phys(sram_pool, sram_base);
	slow_clock = __arm_ioremap_exec(sram_pbase, at91_slow_clock_sz, false);
	at91_suspend_sram_fn = __arm_ioremap_exec(sram_pbase,
					at91_pm_suspend_in_sram_sz, false);
	if (!at91_suspend_sram_fn) {
		pr_warn("SRAM: Could not map\n");
		return;
	}
#endif

	/* Copy the pm suspend handler to SRAM */
	at91_suspend_sram_fn = fncpy(at91_suspend_sram_fn,
			&at91_pm_suspend_in_sram, at91_pm_suspend_in_sram_sz);
}

static void __init at91_pm_init(void)
{
#ifdef CONFIG_AT91_SLOW_CLOCK
	at91_pm_sram_init();
#endif

	pr_info("AT91: Power Management%s\n", (slow_clock ? " (with slow clock mode)" : ""));

	if (at91_cpuidle_device.dev.platform_data)
		platform_device_register(&at91_cpuidle_device);

	if (at91_suspend_sram_fn)
		suspend_set_ops(&at91_pm_ops);
	else
		pr_info("AT91: PM not supported, due to no SRAM allocated\n");
}

void __init at91rm9200_pm_init(void)
+9 −5
Original line number Diff line number Diff line
@@ -15,11 +15,13 @@

#include <mach/at91_ramc.h>

#ifdef CONFIG_PM
extern void at91_pm_set_standby(void (*at91_standby)(void));
#else
static inline void at91_pm_set_standby(void (*at91_standby)(void)) { }
#endif
#define	AT91_PM_MEMTYPE_MASK	0x0f

#define	AT91_PM_MODE_OFFSET	4
#define	AT91_PM_MODE_MASK	0x01
#define	AT91_PM_MODE(x)		(((x) & AT91_PM_MODE_MASK) << AT91_PM_MODE_OFFSET)

#define	AT91_PM_SLOW_CLOCK	0x01

/*
 * The AT91RM9200 goes into self-refresh mode with this command, and will
@@ -31,6 +33,7 @@ static inline void at91_pm_set_standby(void (*at91_standby)(void)) { }
 * still in self-refresh is "not recommended", but seems to work.
 */

#ifndef __ASSEMBLY__
static inline void at91rm9200_standby(void)
{
	u32 lpr = at91_ramc_read(0, AT91RM9200_SDRAMC_LPR);
@@ -112,3 +115,4 @@ static inline void at91sam9_sdram_standby(void)
}

#endif
#endif
+338 −0
Original line number Diff line number Diff line
@@ -11,24 +11,16 @@
 * published by the Free Software Foundation.
 *
 */

#include <linux/linkage.h>
#include <linux/clk/at91_pmc.h>
#include <mach/hardware.h>
#include <mach/at91_ramc.h>
#include "pm.h"

/*
 * When SLOWDOWN_MASTER_CLOCK is defined we will also slow down the Master
 * clock during suspend by adjusting its prescalar and divisor.
 * NOTE: This hasn't been shown to be stable on SAM9s; and on the RM9200 there
 *       are errata regarding adjusting the prescalar and divisor.
 */
#undef SLOWDOWN_MASTER_CLOCK
#define	SRAMC_SELF_FRESH_ACTIVE		0x01
#define	SRAMC_SELF_FRESH_EXIT		0x00

pmc	.req	r0
sdramc	.req	r1
ramc1	.req	r2
memctrl	.req	r3
tmp1	.req	r4
tmp2	.req	r5

@@ -60,111 +52,65 @@ tmp2 .req r5
	.endm

/*
 * Wait until PLLB has locked.
 * Put the processor to enter the idle state
 */
	.macro wait_pllblock
1:	ldr	tmp1, [pmc, #AT91_PMC_SR]
	tst	tmp1, #AT91_PMC_LOCKB
	beq	1b
	.macro at91_cpu_idle

#if defined(CONFIG_CPU_V7)
	mov	tmp1, #AT91_PMC_PCK
	str	tmp1, [pmc, #AT91_PMC_SCDR]

	dsb

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

	.endm

	.text

	.arm

/* void at91_slow_clock(void __iomem *pmc, void __iomem *sdramc,
/*
 * void at91_pm_suspend_in_sram(void __iomem *pmc, void __iomem *sdramc,
 *			void __iomem *ramc1, int memctrl)
 * @input param:
 * 	@r0: base address of AT91_PMC
 *  	@r1: base address of SDRAM Controller (SDRAM, DDRSDR, or AT91_SYS)
 *	@r2: base address of second SDRAM Controller or 0 if not present
 *	@r3: pm information
 */
ENTRY(at91_slow_clock)
ENTRY(at91_pm_suspend_in_sram)
	/* 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

	cmp	memctrl, #AT91_MEMCTRL_MC
	bne	ddr_sr_enable
	str	r0, .pmc_base
	str	r1, .sramc_base
	str	r2, .sramc1_base

	/*
	 * at91rm9200 Memory controller
	 */
	/* Put SDRAM in self-refresh mode */
	mov	tmp1, #1
	str	tmp1, [sdramc, #AT91RM9200_SDRAMC_SRR]
	b	sdr_sr_done
	and	r0, r3, #AT91_PM_MEMTYPE_MASK
	str	r0, .memtype

	/*
	 * DDRSDR Memory controller
	 */
ddr_sr_enable:
	cmp	memctrl, #AT91_MEMCTRL_DDRSDR
	bne	sdr_sr_enable
	lsr	r0, r3, #AT91_PM_MODE_OFFSET
	and	r0, r0, #AT91_PM_MODE_MASK
	str	r0, .pm_mode

	/* 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
	/* Active the self-refresh mode */
	mov	r0, #SRAMC_SELF_FRESH_ACTIVE
	bl	at91_sramc_self_refresh

	/*
	 * SDRAMC Memory controller
	 */
sdr_sr_enable:
	/* Enable SDRAM self-refresh mode */
	ldr	tmp1, [sdramc, #AT91_SDRAMC_LPR]
	str	tmp1, .saved_sam9_lpr
	ldr	r0, .pm_mode
	tst	r0, #AT91_PM_SLOW_CLOCK
	beq	skip_disable_main_clock

	bic	tmp1, #AT91_SDRAMC_LPCB
	orr	tmp1, #AT91_SDRAMC_LPCB_SELF_REFRESH
	str	tmp1, [sdramc, #AT91_SDRAMC_LPR]
	ldr	pmc, .pmc_base

sdr_sr_done:
	/* Save Master clock setting */
	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
	str	tmp1, .saved_mckr
@@ -177,18 +123,6 @@ sdr_sr_done:

	wait_mckrdy

#ifdef SLOWDOWN_MASTER_CLOCK
	/*
	 * Set the Master Clock PRES and MDIV fields.
	 *
	 * See AT91RM9200 errata #27 and #28 for details.
	 */
	mov	tmp1, #0
	str	tmp1, [pmc, #AT91_PMC_MCKR]

	wait_mckrdy
#endif

	/* Save PLLA setting and disable it */
	ldr	tmp1, [pmc, #AT91_CKGR_PLLAR]
	str	tmp1, .saved_pllar
@@ -197,21 +131,23 @@ sdr_sr_done:
	orr	tmp1, tmp1, #(1 << 29)		/* bit 29 always set */
	str	tmp1, [pmc, #AT91_CKGR_PLLAR]

	/* Save PLLB setting and disable it */
	ldr	tmp1, [pmc, #AT91_CKGR_PLLBR]
	str	tmp1, .saved_pllbr

	mov	tmp1, #AT91_PMC_PLLCOUNT
	str	tmp1, [pmc, #AT91_CKGR_PLLBR]

	/* Turn off the main oscillator */
	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
	bic	tmp1, tmp1, #AT91_PMC_MOSCEN
	orr	tmp1, tmp1, #AT91_PMC_KEY
	str	tmp1, [pmc, #AT91_CKGR_MOR]

skip_disable_main_clock:
	ldr	pmc, .pmc_base

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

	ldr	r0, .pm_mode
	tst	r0, #AT91_PM_SLOW_CLOCK
	beq	skip_enable_main_clock

	ldr	pmc, .pmc_base

	/* Turn on the main oscillator */
	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
@@ -221,18 +157,6 @@ sdr_sr_done:

	wait_moscrdy

	/* Restore PLLB setting */
	ldr	tmp1, .saved_pllbr
	str	tmp1, [pmc, #AT91_CKGR_PLLBR]

	tst	tmp1, #(AT91_PMC_MUL &  0xff0000)
	bne	1f
	tst	tmp1, #(AT91_PMC_MUL & ~0xff0000)
	beq	2f
1:
	wait_pllblock
2:

	/* Restore PLLA setting */
	ldr	tmp1, .saved_pllar
	str	tmp1, [pmc, #AT91_CKGR_PLLAR]
@@ -245,91 +169,170 @@ sdr_sr_done:
	wait_pllalock
4:

#ifdef SLOWDOWN_MASTER_CLOCK
	/*
	 * First set PRES if it was not 0,
	 * than set CSS and MDIV fields.
	 *
	 * See AT91RM9200 errata #27 and #28 for details.
	 * Restore master clock setting
	 */
	ldr	tmp1, .saved_mckr
	tst	tmp1, #AT91_PMC_PRES
	beq	2f
	and	tmp1, tmp1, #AT91_PMC_PRES
	str	tmp1, [pmc, #AT91_PMC_MCKR]

	wait_mckrdy
#endif

skip_enable_main_clock:
	/* Exit the self-refresh mode */
	mov	r0, #SRAMC_SELF_FRESH_EXIT
	bl	at91_sramc_self_refresh

	/* Restore registers, and return */
	ldmfd	sp!, {r4 - r12, pc}
ENDPROC(at91_pm_suspend_in_sram)

/*
	 * Restore master clock setting
 * void at91_sramc_self_refresh(unsigned int is_active)
 *
 * @input param:
 *	@r0: 1 - active self-refresh mode
 *	     0 - exit self-refresh mode
 * register usage:
 * 	@r1: memory type
 *	@r2: base address of the sram controller
 */
2:	ldr	tmp1, .saved_mckr
	str	tmp1, [pmc, #AT91_PMC_MCKR]

	wait_mckrdy
ENTRY(at91_sramc_self_refresh)
	ldr	r1, .memtype
	ldr	r2, .sramc_base

	cmp	r1, #AT91_MEMCTRL_MC
	bne	ddrc_sf

	/*
	 * at91rm9200 Memory controller
	 * Do nothing - self-refresh is automatically disabled.
	 */
	cmp	memctrl, #AT91_MEMCTRL_MC
	beq	ram_restored

	 /*
	 * DDRSDR Memory controller
	  * For exiting the self-refresh mode, do nothing,
	  * automatically exit the self-refresh mode.
	  */
	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]
	tst	r0, #SRAMC_SELF_FRESH_ACTIVE
	beq	exit_sramc_sf

	/* 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]
	/* Active SDRAM self-refresh mode */
	mov	r3, #1
	str	r3, [r2, #AT91RM9200_SDRAMC_SRR]
	b	exit_sramc_sf

	b	ram_restored
ddrc_sf:
	cmp	r1, #AT91_MEMCTRL_DDRSDR
	bne	sdramc_sf

	/*
	 * SDRAMC Memory controller
	 * DDR Memory controller
	 */
sdr_en_restore:
	/* Restore LPR on AT91 with SDRAM */
	ldr	tmp1, .saved_sam9_lpr
	str	tmp1, [sdramc, #AT91_SDRAMC_LPR]
	tst	r0, #SRAMC_SELF_FRESH_ACTIVE
	beq	ddrc_exit_sf

ram_restored:
	/* Restore registers, and return */
	ldmfd	sp!, {r4 - r12, pc}
	/* LPDDR1 --> force DDR2 mode during self-refresh */
	ldr	r3, [r2, #AT91_DDRSDRC_MDR]
	str	r3, .saved_sam9_mdr
	bic	r3, r3, #~AT91_DDRSDRC_MD
	cmp	r3, #AT91_DDRSDRC_MD_LOW_POWER_DDR
	ldreq	r3, [r2, #AT91_DDRSDRC_MDR]
	biceq	r3, r3, #AT91_DDRSDRC_MD
	orreq	r3, r3, #AT91_DDRSDRC_MD_DDR2
	streq	r3, [r2, #AT91_DDRSDRC_MDR]

	/* Active DDRC self-refresh mode */
	ldr	r3, [r2, #AT91_DDRSDRC_LPR]
	str	r3, .saved_sam9_lpr
	bic	r3, r3, #AT91_DDRSDRC_LPCB
	orr	r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
	str	r3, [r2, #AT91_DDRSDRC_LPR]

	/* If using the 2nd ddr controller */
	ldr	r2, .sramc1_base
	cmp	r2, #0
	beq	no_2nd_ddrc

	ldr	r3, [r2, #AT91_DDRSDRC_MDR]
	str	r3, .saved_sam9_mdr1
	bic	r3, r3, #~AT91_DDRSDRC_MD
	cmp	r3, #AT91_DDRSDRC_MD_LOW_POWER_DDR
	ldreq	r3, [r2, #AT91_DDRSDRC_MDR]
	biceq	r3, r3, #AT91_DDRSDRC_MD
	orreq	r3, r3, #AT91_DDRSDRC_MD_DDR2
	streq	r3, [r2, #AT91_DDRSDRC_MDR]

	/* Active DDRC self-refresh mode */
	ldr	r3, [r2, #AT91_DDRSDRC_LPR]
	str	r3, .saved_sam9_lpr1
	bic	r3, r3, #AT91_DDRSDRC_LPCB
	orr	r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
	str	r3, [r2, #AT91_DDRSDRC_LPR]

no_2nd_ddrc:
	b	exit_sramc_sf

ddrc_exit_sf:
	/* Restore MDR in case of LPDDR1 */
	ldr	r3, .saved_sam9_mdr
	str	r3, [r2, #AT91_DDRSDRC_MDR]
	/* Restore LPR on AT91 with DDRAM */
	ldr	r3, .saved_sam9_lpr
	str	r3, [r2, #AT91_DDRSDRC_LPR]

	/* If using the 2nd ddr controller */
	ldr	r2, .sramc1_base
	cmp	r2, #0
	ldrne	r3, .saved_sam9_mdr1
	strne	r3, [r2, #AT91_DDRSDRC_MDR]
	ldrne	r3, .saved_sam9_lpr1
	strne	r3, [r2, #AT91_DDRSDRC_LPR]

	b	exit_sramc_sf

	/*
	 * SDRAMC Memory controller
	 */
sdramc_sf:
	tst	r0, #SRAMC_SELF_FRESH_ACTIVE
	beq	sdramc_exit_sf

	/* Active SDRAMC self-refresh mode */
	ldr	r3, [r2, #AT91_SDRAMC_LPR]
	str	r3, .saved_sam9_lpr
	bic	r3, r3, #AT91_SDRAMC_LPCB
	orr	r3, r3, #AT91_SDRAMC_LPCB_SELF_REFRESH
	str	r3, [r2, #AT91_SDRAMC_LPR]

sdramc_exit_sf:
	ldr	r3, .saved_sam9_lpr
	str	r3, [r2, #AT91_SDRAMC_LPR]

exit_sramc_sf:
	mov	pc, lr
ENDPROC(at91_sramc_self_refresh)

.pmc_base:
	.word 0
.sramc_base:
	.word 0
.sramc1_base:
	.word 0
.memtype:
	.word 0
.pm_mode:
	.word 0
.saved_mckr:
	.word 0

.saved_pllar:
	.word 0

.saved_pllbr:
	.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
ENTRY(at91_pm_suspend_in_sram_sz)
	.word .-at91_pm_suspend_in_sram
Loading