mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 02:50:43 +00:00
[ARM] S3C64XX: Initial support for PM (suspend to RAM)
Add the initial support for the S3C64XX based systems to use suspend-to-RAM to sleep. Includes basic debugging for use with the SMDK6410 usign the LEDs on the baseboard. Signed-off-by: Ben Dooks <ben-linux@fluff.org>
This commit is contained in:
parent
4b637dc231
commit
bd117bd161
11 changed files with 479 additions and 2 deletions
16
arch/arm/mach-s3c6400/include/mach/regs-clock.h
Normal file
16
arch/arm/mach-s3c6400/include/mach/regs-clock.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* linux/arch/arm/mach-s3c6400/include/mach/regs-clock.h
|
||||
*
|
||||
* Copyright 2008 Openmoko, Inc.
|
||||
* Copyright 2008 Simtec Electronics
|
||||
* http://armlinux.simtec.co.uk/
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
*
|
||||
* S3C64XX - clock register compatibility with s3c24xx
|
||||
*
|
||||
* 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 <plat/regs-clock.h>
|
||||
|
|
@ -71,6 +71,15 @@ config S3C2410_PM_DEBUG
|
|||
Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
|
||||
for more information.
|
||||
|
||||
config S3C_PM_DEBUG_LED_SMDK
|
||||
bool "SMDK LED suspend/resume debugging"
|
||||
depends on PM && (MACH_SMDK6410)
|
||||
help
|
||||
Say Y here to enable the use of the SMDK LEDs on the baseboard
|
||||
for debugging of the state of the suspend and resume process.
|
||||
|
||||
Note, this currently only works for S3C64XX based SMDK boards.
|
||||
|
||||
config S3C2410_PM_CHECK
|
||||
bool "S3C2410 PM Suspend Memory CRC"
|
||||
depends on PM && CRC32
|
||||
|
|
|
@ -127,6 +127,18 @@ extern void s3c_pm_dbg(const char *msg, ...);
|
|||
#define S3C_PMDBG(fmt...) printk(KERN_DEBUG fmt)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
|
||||
/**
|
||||
* s3c_pm_debug_smdkled() - Debug PM suspend/resume via SMDK Board LEDs
|
||||
* @set: set bits for the state of the LEDs
|
||||
* @clear: clear bits for the state of the LEDs.
|
||||
*/
|
||||
extern void s3c_pm_debug_smdkled(u32 set, u32 clear);
|
||||
|
||||
#else
|
||||
static inline void s3c_pm_debug_smdkled(u32 set, u32 clear) { }
|
||||
#endif /* CONFIG_S3C_PM_DEBUG_LED_SMDK */
|
||||
|
||||
/* suspend memory checking */
|
||||
|
||||
#ifdef CONFIG_S3C2410_PM_CHECK
|
||||
|
|
|
@ -21,11 +21,10 @@
|
|||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/map.h>
|
||||
|
||||
#include <plat/regs-serial.h>
|
||||
#include <mach/regs-clock.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
#include <mach/regs-mem.h>
|
||||
#include <mach/regs-irq.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
|
@ -326,6 +325,9 @@ static int s3c_pm_enter(suspend_state_t state)
|
|||
|
||||
S3C_PMDBG("%s: post sleep, preparing to return\n", __func__);
|
||||
|
||||
/* LEDs should now be 1110 */
|
||||
s3c_pm_debug_smdkled(1 << 1, 0);
|
||||
|
||||
s3c_pm_check_restore();
|
||||
|
||||
/* ok, let's return from sleep */
|
||||
|
|
|
@ -24,6 +24,11 @@ obj-y += gpiolib.o
|
|||
obj-$(CONFIG_CPU_S3C6400_INIT) += s3c6400-init.o
|
||||
obj-$(CONFIG_CPU_S3C6400_CLOCK) += s3c6400-clock.o
|
||||
|
||||
# PM support
|
||||
|
||||
obj-$(CONFIG_PM) += pm.o
|
||||
obj-$(CONFIG_PM) += sleep.o
|
||||
|
||||
# Device setup
|
||||
|
||||
obj-$(CONFIG_S3C64XX_SETUP_I2C0) += setup-i2c0.o
|
||||
|
|
|
@ -157,6 +157,7 @@
|
|||
|
||||
#define S3C_EINT(x) ((x) + S3C_IRQ_EINT_BASE)
|
||||
#define IRQ_EINT(x) S3C_EINT(x)
|
||||
#define IRQ_EINT_BIT(x) ((x) - S3C_EINT(0))
|
||||
|
||||
/* Next the external interrupt groups. These are similar to the IRQ_EINT(x)
|
||||
* that they are sourced from the GPIO pins but with a different scheme for
|
||||
|
|
98
arch/arm/plat-s3c64xx/include/plat/pm-core.h
Normal file
98
arch/arm/plat-s3c64xx/include/plat/pm-core.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/* linux/arch/arm/plat-s3c64xx/include/plat/pm-core.h
|
||||
*
|
||||
* Copyright 2008 Openmoko, Inc.
|
||||
* Copyright 2008 Simtec Electronics
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
* http://armlinux.simtec.co.uk/
|
||||
*
|
||||
* S3C64XX - PM core support for arch/arm/plat-s3c/pm.c
|
||||
*
|
||||
* 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 <plat/regs-gpio.h>
|
||||
|
||||
static inline void s3c_pm_debug_init_uart(void)
|
||||
{
|
||||
u32 tmp = __raw_readl(S3C_PCLK_GATE);
|
||||
|
||||
/* As a note, since the S3C64XX UARTs generally have multiple
|
||||
* clock sources, we simply enable PCLK at the moment and hope
|
||||
* that the resume settings for the UART are suitable for the
|
||||
* use with PCLK.
|
||||
*/
|
||||
|
||||
tmp |= S3C_CLKCON_PCLK_UART0;
|
||||
tmp |= S3C_CLKCON_PCLK_UART1;
|
||||
tmp |= S3C_CLKCON_PCLK_UART2;
|
||||
tmp |= S3C_CLKCON_PCLK_UART3;
|
||||
|
||||
__raw_writel(tmp, S3C_PCLK_GATE);
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
static inline void s3c_pm_arch_prepare_irqs(void)
|
||||
{
|
||||
/* VIC should have already been taken care of */
|
||||
|
||||
/* clear any pending EINT0 interrupts */
|
||||
__raw_writel(__raw_readl(S3C64XX_EINT0PEND), S3C64XX_EINT0PEND);
|
||||
}
|
||||
|
||||
static inline void s3c_pm_arch_stop_clocks(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void s3c_pm_arch_show_resume_irqs(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* make these defines, we currently do not have any need to change
|
||||
* the IRQ wake controls depending on the CPU we are running on */
|
||||
|
||||
#define s3c_irqwake_eintallow ((1 << 28) - 1)
|
||||
#define s3c_irqwake_intallow (0)
|
||||
|
||||
static inline void s3c_pm_arch_update_uart(void __iomem *regs,
|
||||
struct pm_uart_save *save)
|
||||
{
|
||||
u32 ucon = __raw_readl(regs + S3C2410_UCON);
|
||||
u32 ucon_clk = ucon & S3C6400_UCON_CLKMASK;
|
||||
u32 save_clk = save->ucon & S3C6400_UCON_CLKMASK;
|
||||
u32 new_ucon;
|
||||
u32 delta;
|
||||
|
||||
/* S3C64XX UART blocks only support level interrupts, so ensure that
|
||||
* when we restore unused UART blocks we force the level interrupt
|
||||
* settigs. */
|
||||
save->ucon |= S3C2410_UCON_TXILEVEL | S3C2410_UCON_RXILEVEL;
|
||||
|
||||
/* We have a constraint on changing the clock type of the UART
|
||||
* between UCLKx and PCLK, so ensure that when we restore UCON
|
||||
* that the CLK field is correctly modified if the bootloader
|
||||
* has changed anything.
|
||||
*/
|
||||
if (ucon_clk != save_clk) {
|
||||
new_ucon = save->ucon;
|
||||
delta = ucon_clk ^ save_clk;
|
||||
|
||||
/* change from UCLKx => wrong PCLK,
|
||||
* either UCLK can be tested for by a bit-test
|
||||
* with UCLK0 */
|
||||
if (ucon_clk & S3C6400_UCON_UCLK0 &&
|
||||
!(save_clk & S3C6400_UCON_UCLK0) &&
|
||||
delta & S3C6400_UCON_PCLK2) {
|
||||
new_ucon &= ~S3C6400_UCON_UCLK0;
|
||||
} else if (delta == S3C6400_UCON_PCLK2) {
|
||||
/* as an precaution, don't change from
|
||||
* PCLK2 => PCLK or vice-versa */
|
||||
new_ucon ^= S3C6400_UCON_PCLK2;
|
||||
}
|
||||
|
||||
S3C_PMDBG("ucon change %04x => %04x (save=%04x)\n",
|
||||
ucon, new_ucon, save->ucon);
|
||||
save->ucon = new_ucon;
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@
|
|||
#define S3C_HCLK_GATE S3C_CLKREG(0x30)
|
||||
#define S3C_PCLK_GATE S3C_CLKREG(0x34)
|
||||
#define S3C_SCLK_GATE S3C_CLKREG(0x38)
|
||||
#define S3C_MEM0_GATE S3C_CLKREG(0x3C)
|
||||
|
||||
/* CLKDIV0 */
|
||||
#define S3C6400_CLKDIV0_MFC_MASK (0xf << 28)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sysdev.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -26,6 +27,7 @@
|
|||
|
||||
#include <mach/map.h>
|
||||
#include <plat/cpu.h>
|
||||
#include <plat/pm.h>
|
||||
|
||||
#define eint_offset(irq) ((irq) - IRQ_EINT(0))
|
||||
#define eint_irq_to_bit(irq) (1 << eint_offset(irq))
|
||||
|
@ -134,6 +136,7 @@ static struct irq_chip s3c_irq_eint = {
|
|||
.mask_ack = s3c_irq_eint_maskack,
|
||||
.ack = s3c_irq_eint_ack,
|
||||
.set_type = s3c_irq_eint_set_type,
|
||||
.set_wake = s3c_irqext_wake,
|
||||
};
|
||||
|
||||
/* s3c_irq_demux_eint
|
||||
|
|
186
arch/arm/plat-s3c64xx/pm.c
Normal file
186
arch/arm/plat-s3c64xx/pm.c
Normal file
|
@ -0,0 +1,186 @@
|
|||
/* linux/arch/arm/plat-s3c64xx/pm.c
|
||||
*
|
||||
* Copyright 2008 Openmoko, Inc.
|
||||
* Copyright 2008 Simtec Electronics
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
* http://armlinux.simtec.co.uk/
|
||||
*
|
||||
* S3C64XX CPU PM support.
|
||||
*
|
||||
* 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/suspend.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/map.h>
|
||||
|
||||
#include <plat/pm.h>
|
||||
#include <plat/regs-sys.h>
|
||||
#include <plat/regs-gpio.h>
|
||||
#include <plat/regs-clock.h>
|
||||
#include <plat/regs-syscon-power.h>
|
||||
#include <plat/regs-gpio-memport.h>
|
||||
|
||||
#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
|
||||
#include <plat/gpio-bank-n.h>
|
||||
|
||||
void s3c_pm_debug_smdkled(u32 set, u32 clear)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
local_irq_save(flags);
|
||||
reg = __raw_readl(S3C64XX_GPNCON);
|
||||
reg &= ~(S3C64XX_GPN_CONMASK(12) | S3C64XX_GPN_CONMASK(13) |
|
||||
S3C64XX_GPN_CONMASK(14) | S3C64XX_GPN_CONMASK(15));
|
||||
reg |= S3C64XX_GPN_OUTPUT(12) | S3C64XX_GPN_OUTPUT(13) |
|
||||
S3C64XX_GPN_OUTPUT(14) | S3C64XX_GPN_OUTPUT(15);
|
||||
__raw_writel(reg, S3C64XX_GPNCON);
|
||||
|
||||
reg = __raw_readl(S3C64XX_GPNDAT);
|
||||
reg &= ~(clear << 12);
|
||||
reg |= set << 12;
|
||||
__raw_writel(reg, S3C64XX_GPNDAT);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct sleep_save core_save[] = {
|
||||
SAVE_ITEM(S3C_APLL_LOCK),
|
||||
SAVE_ITEM(S3C_MPLL_LOCK),
|
||||
SAVE_ITEM(S3C_EPLL_LOCK),
|
||||
SAVE_ITEM(S3C_CLK_SRC),
|
||||
SAVE_ITEM(S3C_CLK_DIV0),
|
||||
SAVE_ITEM(S3C_CLK_DIV1),
|
||||
SAVE_ITEM(S3C_CLK_DIV2),
|
||||
SAVE_ITEM(S3C_CLK_OUT),
|
||||
SAVE_ITEM(S3C_HCLK_GATE),
|
||||
SAVE_ITEM(S3C_PCLK_GATE),
|
||||
SAVE_ITEM(S3C_SCLK_GATE),
|
||||
SAVE_ITEM(S3C_MEM0_GATE),
|
||||
|
||||
SAVE_ITEM(S3C_EPLL_CON1),
|
||||
SAVE_ITEM(S3C_EPLL_CON0),
|
||||
|
||||
SAVE_ITEM(S3C64XX_MEM0DRVCON),
|
||||
SAVE_ITEM(S3C64XX_MEM1DRVCON),
|
||||
|
||||
#ifndef CONFIG_CPU_FREQ
|
||||
SAVE_ITEM(S3C_APLL_CON),
|
||||
SAVE_ITEM(S3C_MPLL_CON),
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct sleep_save misc_save[] = {
|
||||
SAVE_ITEM(S3C64XX_AHB_CON0),
|
||||
SAVE_ITEM(S3C64XX_AHB_CON1),
|
||||
SAVE_ITEM(S3C64XX_AHB_CON2),
|
||||
|
||||
SAVE_ITEM(S3C64XX_SPCON),
|
||||
|
||||
SAVE_ITEM(S3C64XX_MEM0CONSTOP),
|
||||
SAVE_ITEM(S3C64XX_MEM1CONSTOP),
|
||||
SAVE_ITEM(S3C64XX_MEM0CONSLP0),
|
||||
SAVE_ITEM(S3C64XX_MEM0CONSLP1),
|
||||
SAVE_ITEM(S3C64XX_MEM1CONSLP),
|
||||
};
|
||||
|
||||
void s3c_pm_configure_extint(void)
|
||||
{
|
||||
__raw_writel(s3c_irqwake_eintmask, S3C64XX_EINT_MASK);
|
||||
}
|
||||
|
||||
void s3c_pm_save_gpios(void)
|
||||
{
|
||||
/* currently, unless the bootloader does something really stupid
|
||||
* the gpio blocks should be maintained over their sleep.
|
||||
*/
|
||||
}
|
||||
|
||||
void s3c_pm_restore_gpios(void)
|
||||
{
|
||||
}
|
||||
|
||||
void s3c_pm_restore_core(void)
|
||||
{
|
||||
__raw_writel(0, S3C64XX_EINT_MASK);
|
||||
|
||||
s3c_pm_debug_smdkled(1 << 2, 0);
|
||||
|
||||
s3c_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
|
||||
s3c_pm_do_restore(misc_save, ARRAY_SIZE(misc_save));
|
||||
}
|
||||
|
||||
void s3c_pm_save_core(void)
|
||||
{
|
||||
s3c_pm_do_save(misc_save, ARRAY_SIZE(misc_save));
|
||||
s3c_pm_do_save(core_save, ARRAY_SIZE(core_save));
|
||||
}
|
||||
|
||||
/* since both s3c6400 and s3c6410 share the same sleep pm calls, we
|
||||
* put the per-cpu code in here until any new cpu comes along and changes
|
||||
* this.
|
||||
*/
|
||||
|
||||
#include <plat/regs-gpio.h>
|
||||
|
||||
static void s3c64xx_cpu_suspend(void)
|
||||
{
|
||||
unsigned long tmp;
|
||||
|
||||
/* set our standby method to sleep */
|
||||
|
||||
tmp = __raw_readl(S3C64XX_PWR_CFG);
|
||||
tmp &= ~S3C64XX_PWRCFG_CFG_WFI_MASK;
|
||||
tmp |= S3C64XX_PWRCFG_CFG_WFI_SLEEP;
|
||||
__raw_writel(tmp, S3C64XX_PWR_CFG);
|
||||
|
||||
/* clear any old wakeup */
|
||||
|
||||
__raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT),
|
||||
S3C64XX_WAKEUP_STAT);
|
||||
|
||||
/* set the LED state to 0110 over sleep */
|
||||
s3c_pm_debug_smdkled(3 << 1, 0xf);
|
||||
|
||||
/* issue the standby signal into the pm unit. Note, we
|
||||
* issue a write-buffer drain just in case */
|
||||
|
||||
tmp = 0;
|
||||
|
||||
asm("b 1f\n\t"
|
||||
".align 5\n\t"
|
||||
"1:\n\t"
|
||||
"mcr p15, 0, %0, c7, c10, 5\n\t"
|
||||
"mcr p15, 0, %0, c7, c10, 4\n\t"
|
||||
"mcr p15, 0, %0, c7, c0, 4" :: "r" (tmp));
|
||||
|
||||
/* we should never get past here */
|
||||
|
||||
panic("sleep resumed to originator?");
|
||||
}
|
||||
|
||||
static void s3c64xx_pm_prepare(void)
|
||||
{
|
||||
/* store address of resume. */
|
||||
__raw_writel(virt_to_phys(s3c_cpu_resume), S3C64XX_INFORM0);
|
||||
|
||||
/* ensure previous wakeup state is cleared before sleeping */
|
||||
__raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT), S3C64XX_WAKEUP_STAT);
|
||||
}
|
||||
|
||||
static int s3c64xx_pm_init(void)
|
||||
{
|
||||
pm_cpu_prep = s3c64xx_pm_prepare;
|
||||
pm_cpu_sleep = s3c64xx_cpu_suspend;
|
||||
pm_uart_udivslot = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(s3c64xx_pm_init);
|
144
arch/arm/plat-s3c64xx/sleep.S
Normal file
144
arch/arm/plat-s3c64xx/sleep.S
Normal file
|
@ -0,0 +1,144 @@
|
|||
/* linux/0arch/arm/plat-s3c64xx/sleep.S
|
||||
*
|
||||
* Copyright 2008 Openmoko, Inc.
|
||||
* Copyright 2008 Simtec Electronics
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
* http://armlinux.simtec.co.uk/
|
||||
*
|
||||
* S3C64XX CPU sleep code
|
||||
*
|
||||
* 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 <asm/assembler.h>
|
||||
#include <mach/map.h>
|
||||
|
||||
#undef S3C64XX_VA_GPIO
|
||||
#define S3C64XX_VA_GPIO (0x0)
|
||||
|
||||
#include <plat/regs-gpio.h>
|
||||
#include <plat/gpio-bank-n.h>
|
||||
|
||||
#define LL_UART (S3C_PA_UART + (0x400 * CONFIG_S3C_LOWLEVEL_UART_PORT))
|
||||
|
||||
.text
|
||||
|
||||
/* s3c_cpu_save
|
||||
*
|
||||
* Save enough processor state to allow the restart of the pm.c
|
||||
* code after resume.
|
||||
*
|
||||
* entry:
|
||||
* r0 = pointer to the save block
|
||||
*/
|
||||
|
||||
ENTRY(s3c_cpu_save)
|
||||
stmfd sp!, { r4 - r12, lr }
|
||||
|
||||
mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID
|
||||
mrc p15, 0, r5, c3, c0, 0 @ Domain ID
|
||||
mrc p15, 0, r6, c2, c0, 0 @ Translation Table BASE0
|
||||
mrc p15, 0, r7, c2, c0, 1 @ Translation Table BASE1
|
||||
mrc p15, 0, r8, c2, c0, 2 @ Translation Table Control
|
||||
mrc p15, 0, r9, c1, c0, 0 @ Control register
|
||||
mrc p15, 0, r10, c1, c0, 1 @ Auxiliary control register
|
||||
mrc p15, 0, r11, c1, c0, 2 @ Co-processor access controls
|
||||
|
||||
stmia r0, { r4 - r13 } @ Save CP registers and SP
|
||||
|
||||
@@ save our state to ram
|
||||
bl s3c_pm_cb_flushcache
|
||||
|
||||
@@ call final suspend code
|
||||
ldr r0, =pm_cpu_sleep
|
||||
ldr pc, [r0]
|
||||
|
||||
@@ return to the caller, after the MMU is turned on.
|
||||
@@ restore the last bits of the stack and return.
|
||||
resume_with_mmu:
|
||||
ldmfd sp!, { r4 - r12, pc } @ return, from sp from s3c_cpu_save
|
||||
|
||||
.data
|
||||
|
||||
/* the next bit is code, but it requires easy access to the
|
||||
* s3c_sleep_save_phys data before the MMU is switched on, so
|
||||
* we store the code that needs this variable in the .data where
|
||||
* the value can be written to (the .text segment is RO).
|
||||
*/
|
||||
|
||||
.global s3c_sleep_save_phys
|
||||
s3c_sleep_save_phys:
|
||||
.word 0
|
||||
|
||||
/* Sleep magic, the word before the resume entry point so that the
|
||||
* bootloader can check for a resumeable image. */
|
||||
|
||||
.word 0x2bedf00d
|
||||
|
||||
/* s3c_cpu_reusme
|
||||
*
|
||||
* This is the entry point, stored by whatever method the bootloader
|
||||
* requires to get the kernel runnign again. This code expects to be
|
||||
* entered with no caches live and the MMU disabled. It will then
|
||||
* restore the MMU and other basic CP registers saved and restart
|
||||
* the kernel C code to finish the resume code.
|
||||
*/
|
||||
|
||||
ENTRY(s3c_cpu_resume)
|
||||
msr cpsr_c, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
|
||||
ldr r2, =LL_UART /* for debug */
|
||||
|
||||
#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
|
||||
/* Initialise the GPIO state if we are debugging via the SMDK LEDs,
|
||||
* as the uboot version supplied resets these to inputs during the
|
||||
* resume checks.
|
||||
*/
|
||||
|
||||
ldr r3, =S3C64XX_PA_GPIO
|
||||
ldr r0, [ r3, #S3C64XX_GPNCON ]
|
||||
bic r0, r0, #(S3C64XX_GPN_CONMASK(12) | S3C64XX_GPN_CONMASK(13) | \
|
||||
S3C64XX_GPN_CONMASK(14) | S3C64XX_GPN_CONMASK(15))
|
||||
orr r0, r0, #(S3C64XX_GPN_OUTPUT(12) | S3C64XX_GPN_OUTPUT(13) | \
|
||||
S3C64XX_GPN_OUTPUT(14) | S3C64XX_GPN_OUTPUT(15))
|
||||
str r0, [ r3, #S3C64XX_GPNCON ]
|
||||
|
||||
ldr r0, [ r3, #S3C64XX_GPNDAT ]
|
||||
bic r0, r0, #0xf << 12 @ GPN12..15
|
||||
orr r0, r0, #1 << 15 @ GPN15
|
||||
str r0, [ r3, #S3C64XX_GPNDAT ]
|
||||
#endif
|
||||
|
||||
/* __v6_setup from arch/arm/mm/proc-v6.S, ensure that the caches
|
||||
* are thoroughly cleaned just in case the bootloader didn't do it
|
||||
* for us. */
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c14, 0 @ clean+invalidate D cache
|
||||
mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
|
||||
mcr p15, 0, r0, c7, c15, 0 @ clean+invalidate cache
|
||||
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
|
||||
@@mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs
|
||||
@@mcr p15, 0, r0, c7, c7, 0 @ Invalidate I + D caches
|
||||
|
||||
ldr r0, s3c_sleep_save_phys
|
||||
ldmia r0, { r4 - r13 }
|
||||
|
||||
mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID
|
||||
mcr p15, 0, r5, c3, c0, 0 @ Domain ID
|
||||
mcr p15, 0, r6, c2, c0, 0 @ Translation Table BASE0
|
||||
mcr p15, 0, r7, c2, c0, 1 @ Translation Table BASE1
|
||||
mcr p15, 0, r8, c2, c0, 2 @ Translation Table Control
|
||||
mcr p15, 0, r10, c1, c0, 1 @ Auxiliary control register
|
||||
|
||||
mov r0, #0 @ restore copro access controls
|
||||
mcr p15, 0, r11, c1, c0, 2 @ Co-processor access controls
|
||||
mcr p15, 0, r0, c7, c5, 4
|
||||
|
||||
ldr r2, =resume_with_mmu
|
||||
mcr p15, 0, r9, c1, c0, 0 /* turn mmu back on */
|
||||
nop
|
||||
mov pc, r2 /* jump back */
|
||||
|
||||
.end
|
Loading…
Reference in a new issue