Skip to content

Commit

Permalink
ARM: at91/pm_slowclock: add runtime detection of memory contoller
Browse files Browse the repository at this point in the history
This will allow to have all SoC in one kernel image.

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
  • Loading branch information
Jean-Christophe PLAGNIOL-VILLARD authored and Nicolas Ferre committed Feb 23, 2012
1 parent f363c40 commit fb7e197
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 22 deletions.
9 changes: 5 additions & 4 deletions arch/arm/mach-at91/include/mach/at91_ramc.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ extern void __iomem *at91_ramc_base[];
.extern at91_ramc_base
#endif

#ifdef CONFIG_ARCH_AT91RM9200
#include <mach/at91rm9200_mc.h>
#else
#define AT91_MEMCTRL_MC 0
#define AT91_MEMCTRL_SDRAMC 1
#define AT91_MEMCTRL_DDRSDR 2

#include <mach/at91rm9200_sdramc.h>
#include <mach/at91sam9_ddrsdr.h>
#include <mach/at91sam9_sdramc.h>
#endif

#endif /* __AT91_RAMC_H__ */
15 changes: 12 additions & 3 deletions arch/arm/mach-at91/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,12 @@ int at91_suspend_entering_slow_clock(void)
EXPORT_SYMBOL(at91_suspend_entering_slow_clock);


static void (*slow_clock)(void __iomem *pmc, void __iomem *ramc0, void __iomem *ramc1);
static void (*slow_clock)(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, void __iomem *ramc1);
extern void at91_slow_clock(void __iomem *pmc, void __iomem *ramc0,
void __iomem *ramc1, int memctrl);
extern u32 at91_slow_clock_sz;
#endif

Expand Down Expand Up @@ -241,11 +243,18 @@ static int at91_pm_enter(suspend_state_t state)
* turning off the main oscillator; reverse on wakeup.
*/
if (slow_clock) {
int memctrl = AT91_MEMCTRL_SDRAMC;

if (cpu_is_at91rm9200())
memctrl = AT91_MEMCTRL_MC;
else if (cpu_is_at91sam9g45())
memctrl = AT91_MEMCTRL_DDRSDR;
#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]);
slow_clock(at91_pmc_base, at91_ramc_base[0],
at91_ramc_base[1], memctrl);
break;
} else {
pr_info("AT91: PM - no slow clock mode enabled ...\n");
Expand Down
66 changes: 51 additions & 15 deletions arch/arm/mach-at91/pm_slowclock.S
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@
pmc .req r0
sdramc .req r1
ramc1 .req r2
tmp1 .req r3
tmp2 .req r4
memctrl .req r3
tmp1 .req r4
tmp2 .req r5

/*
* Wait until master clock is ready (after switching master clock source)
Expand Down Expand Up @@ -103,29 +104,44 @@ tmp2 .req r4

.text

/* void at91_slow_clock(void __iomem *pmc, void __iomem *sdramc, void __iomem *ramc1) */
/* 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!, {r3 - r12, lr}
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 = temporary register
* R3 = Memory controller
* R4 = temporary register
* R5 = temporary register
*/

/* Drain write buffer */
mov tmp1, #0
mcr p15, 0, tmp1, c7, c10, 4

#ifdef CONFIG_ARCH_AT91RM9200
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]
#elif defined(CONFIG_ARCH_AT91SAM9G45)
b sdr_sr_done

/*
* DDRSDR Memory controller
*/
ddr_sr_enable:
cmp memctrl, #AT91_MEMCTRL_DDRSDR
bne sdr_sr_enable

/* prepare for DDRAM self-refresh mode */
ldr tmp1, [sdramc, #AT91_DDRSDRC_LPR]
Expand All @@ -143,16 +159,22 @@ ENTRY(at91_slow_clock)
/* Enable DDRAM self-refresh mode */
str tmp1, [sdramc, #AT91_DDRSDRC_LPR]
strne tmp2, [ramc1, #AT91_DDRSDRC_LPR]
#else

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]
#endif

sdr_sr_done:
/* Save Master clock setting */
ldr tmp1, [pmc, #(AT91_PMC_MCKR - AT91_PMC)]
str tmp1, .saved_mckr
Expand Down Expand Up @@ -255,9 +277,18 @@ ENTRY(at91_slow_clock)

wait_mckrdy

#ifdef CONFIG_ARCH_AT91RM9200
/* Do nothing - self-refresh is automatically disabled. */
#elif defined(CONFIG_ARCH_AT91SAM9G45)
/*
* 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 LPR on AT91 with DDRAM */
ldr tmp1, .saved_sam9_lpr
str tmp1, [sdramc, #AT91_DDRSDRC_LPR]
Expand All @@ -267,14 +298,19 @@ ENTRY(at91_slow_clock)
ldrne tmp2, .saved_sam9_lpr1
strne tmp2, [ramc1, #AT91_DDRSDRC_LPR]

#else
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]
#endif

ram_restored:
/* Restore registers, and return */
ldmfd sp!, {r3 - r12, pc}
ldmfd sp!, {r4 - r12, pc}


.saved_mckr:
Expand Down

0 comments on commit fb7e197

Please sign in to comment.