Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
f5f0e17a
Commit
f5f0e17a
authored
Mar 26, 2009
by
Russell King
Committed by
Russell King
Mar 26, 2009
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'next-s3c-pm' of
git://aeryn.fluff.org.uk/bjdooks/linux
into devel
parents
2f3ec501
fff94cd9
Changes
28
Hide whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
1038 additions
and
764 deletions
+1038
-764
Documentation/arm/Samsung-S3C24XX/Suspend.txt
Documentation/arm/Samsung-S3C24XX/Suspend.txt
+4
-4
arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
+23
-0
arch/arm/mach-s3c2410/include/mach/gpio.h
arch/arm/mach-s3c2410/include/mach/gpio.h
+3
-0
arch/arm/mach-s3c2410/include/mach/irqs.h
arch/arm/mach-s3c2410/include/mach/irqs.h
+1
-1
arch/arm/mach-s3c2410/include/mach/regs-gpio.h
arch/arm/mach-s3c2410/include/mach/regs-gpio.h
+1
-10
arch/arm/mach-s3c2410/mach-h1940.c
arch/arm/mach-s3c2410/mach-h1940.c
+1
-1
arch/arm/mach-s3c2410/mach-qt2410.c
arch/arm/mach-s3c2410/mach-qt2410.c
+1
-1
arch/arm/mach-s3c2410/pm.c
arch/arm/mach-s3c2410/pm.c
+3
-10
arch/arm/mach-s3c2412/mach-jive.c
arch/arm/mach-s3c2412/mach-jive.c
+2
-2
arch/arm/mach-s3c2412/pm.c
arch/arm/mach-s3c2412/pm.c
+2
-2
arch/arm/mach-s3c2440/mach-rx3715.c
arch/arm/mach-s3c2440/mach-rx3715.c
+1
-1
arch/arm/mach-s3c24a0/include/mach/irqs.h
arch/arm/mach-s3c24a0/include/mach/irqs.h
+2
-0
arch/arm/plat-s3c/Makefile
arch/arm/plat-s3c/Makefile
+5
-0
arch/arm/plat-s3c/include/plat/pm.h
arch/arm/plat-s3c/include/plat/pm.h
+174
-0
arch/arm/plat-s3c/pm-check.c
arch/arm/plat-s3c/pm-check.c
+242
-0
arch/arm/plat-s3c/pm.c
arch/arm/plat-s3c/pm.c
+363
-0
arch/arm/plat-s3c24xx/Makefile
arch/arm/plat-s3c24xx/Makefile
+1
-0
arch/arm/plat-s3c24xx/common-smdk.c
arch/arm/plat-s3c24xx/common-smdk.c
+1
-1
arch/arm/plat-s3c24xx/include/plat/irq.h
arch/arm/plat-s3c24xx/include/plat/irq.h
+6
-0
arch/arm/plat-s3c24xx/include/plat/map.h
arch/arm/plat-s3c24xx/include/plat/map.h
+2
-0
arch/arm/plat-s3c24xx/include/plat/pm-core.h
arch/arm/plat-s3c24xx/include/plat/pm-core.h
+59
-0
arch/arm/plat-s3c24xx/include/plat/pm.h
arch/arm/plat-s3c24xx/include/plat/pm.h
+0
-73
arch/arm/plat-s3c24xx/irq-pm.c
arch/arm/plat-s3c24xx/irq-pm.c
+95
-0
arch/arm/plat-s3c24xx/irq.c
arch/arm/plat-s3c24xx/irq.c
+1
-151
arch/arm/plat-s3c24xx/pm-simtec.c
arch/arm/plat-s3c24xx/pm-simtec.c
+1
-1
arch/arm/plat-s3c24xx/pm.c
arch/arm/plat-s3c24xx/pm.c
+24
-479
arch/arm/plat-s3c24xx/s3c244x.c
arch/arm/plat-s3c24xx/s3c244x.c
+2
-2
arch/arm/plat-s3c24xx/sleep.S
arch/arm/plat-s3c24xx/sleep.S
+18
-25
No files found.
Documentation/arm/Samsung-S3C24XX/Suspend.txt
View file @
f5f0e17a
...
...
@@ -40,13 +40,13 @@ Resuming
Machine Support
---------------
The machine specific functions must call the s3c
2410
_pm_init() function
The machine specific functions must call the s3c_pm_init() function
to say that its bootloader is capable of resuming. This can be as
simple as adding the following to the machine's definition:
INITMACHINE(s3c
2410
_pm_init)
INITMACHINE(s3c_pm_init)
A board can do its own setup before calling s3c
2410
_pm_init, if it
A board can do its own setup before calling s3c_pm_init, if it
needs to setup anything else for power management support.
There is currently no support for over-riding the default method of
...
...
@@ -74,7 +74,7 @@ statuc void __init machine_init(void)
enable_irq_wake(IRQ_EINT0);
s3c
2410
_pm_init();
s3c_pm_init();
}
...
...
arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
0 → 100644
View file @
f5f0e17a
/* arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
*
* Copyright (c) 2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 - GPIO bank numbering
*
* 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.
*/
#define S3C2410_GPIONO(bank,offset) ((bank) + (offset))
#define S3C2410_GPIO_BANKA (32*0)
#define S3C2410_GPIO_BANKB (32*1)
#define S3C2410_GPIO_BANKC (32*2)
#define S3C2410_GPIO_BANKD (32*3)
#define S3C2410_GPIO_BANKE (32*4)
#define S3C2410_GPIO_BANKF (32*5)
#define S3C2410_GPIO_BANKG (32*6)
#define S3C2410_GPIO_BANKH (32*7)
arch/arm/mach-s3c2410/include/mach/gpio.h
View file @
f5f0e17a
...
...
@@ -23,3 +23,6 @@
#define ARCH_NR_GPIOS (256 + CONFIG_S3C24XX_GPIO_EXTRA)
#include <asm-generic/gpio.h>
#include <mach/gpio-nrs.h>
#define S3C_GPIO_END (S3C2410_GPIO_BANKH + 32)
arch/arm/mach-s3c2410/include/mach/irqs.h
View file @
f5f0e17a
...
...
@@ -80,7 +80,7 @@
#define IRQ_EINT22 S3C2410_IRQ(50)
#define IRQ_EINT23 S3C2410_IRQ(51)
#define IRQ_EINT_BIT(x) ((x) - IRQ_EINT4 + 4)
#define IRQ_EINT(x) (((x) >= 4) ? (IRQ_EINT4 + (x) - 4) : (IRQ_EINT0 + (x)))
#define IRQ_LCD_FIFO S3C2410_IRQ(52)
...
...
arch/arm/mach-s3c2410/include/mach/regs-gpio.h
View file @
f5f0e17a
...
...
@@ -14,16 +14,7 @@
#ifndef __ASM_ARCH_REGS_GPIO_H
#define __ASM_ARCH_REGS_GPIO_H
#define S3C2410_GPIONO(bank,offset) ((bank) + (offset))
#define S3C2410_GPIO_BANKA (32*0)
#define S3C2410_GPIO_BANKB (32*1)
#define S3C2410_GPIO_BANKC (32*2)
#define S3C2410_GPIO_BANKD (32*3)
#define S3C2410_GPIO_BANKE (32*4)
#define S3C2410_GPIO_BANKF (32*5)
#define S3C2410_GPIO_BANKG (32*6)
#define S3C2410_GPIO_BANKH (32*7)
#include <mach/gpio-nrs.h>
#ifdef CONFIG_CPU_S3C2400
#define S3C24XX_GPIO_BASE(x) S3C2400_GPIO_BASE(x)
...
...
arch/arm/mach-s3c2410/mach-h1940.c
View file @
f5f0e17a
...
...
@@ -203,7 +203,7 @@ static void __init h1940_map_io(void)
#ifdef CONFIG_PM_H1940
memcpy
(
phys_to_virt
(
H1940_SUSPEND_RESUMEAT
),
h1940_pm_return
,
1024
);
#endif
s3c
2410
_pm_init
();
s3c_pm_init
();
}
static
void
__init
h1940_init_irq
(
void
)
...
...
arch/arm/mach-s3c2410/mach-qt2410.c
View file @
f5f0e17a
...
...
@@ -355,7 +355,7 @@ static void __init qt2410_machine_init(void)
s3c2410_gpio_cfgpin
(
S3C2410_GPB5
,
S3C2410_GPIO_OUTPUT
);
platform_add_devices
(
qt2410_devices
,
ARRAY_SIZE
(
qt2410_devices
));
s3c
2410
_pm_init
();
s3c_pm_init
();
}
MACHINE_START
(
QT2410
,
"QT2410"
)
...
...
arch/arm/mach-s3c2410/pm.c
View file @
f5f0e17a
...
...
@@ -37,21 +37,14 @@
#include <plat/cpu.h>
#include <plat/pm.h>
#ifdef CONFIG_S3C2410_PM_DEBUG
extern
void
pm_dbg
(
const
char
*
fmt
,
...);
#define DBG(fmt...) pm_dbg(fmt)
#else
#define DBG(fmt...) printk(KERN_DEBUG fmt)
#endif
static
void
s3c2410_pm_prepare
(
void
)
{
/* ensure at least GSTATUS3 has the resume address */
__raw_writel
(
virt_to_phys
(
s3c
2410
_cpu_resume
),
S3C2410_GSTATUS3
);
__raw_writel
(
virt_to_phys
(
s3c_cpu_resume
),
S3C2410_GSTATUS3
);
DBG
(
"GSTATUS3 0x%08x
\n
"
,
__raw_readl
(
S3C2410_GSTATUS3
));
DBG
(
"GSTATUS4 0x%08x
\n
"
,
__raw_readl
(
S3C2410_GSTATUS4
));
S3C_PM
DBG
(
"GSTATUS3 0x%08x
\n
"
,
__raw_readl
(
S3C2410_GSTATUS3
));
S3C_PM
DBG
(
"GSTATUS4 0x%08x
\n
"
,
__raw_readl
(
S3C2410_GSTATUS4
));
if
(
machine_is_h1940
())
{
void
*
base
=
phys_to_virt
(
H1940_SUSPEND_CHECK
);
...
...
arch/arm/mach-s3c2412/mach-jive.c
View file @
f5f0e17a
...
...
@@ -494,7 +494,7 @@ static int jive_pm_suspend(struct sys_device *sd, pm_message_t state)
* correct address to resume from. */
__raw_writel
(
0x2BED
,
S3C2412_INFORM0
);
__raw_writel
(
virt_to_phys
(
s3c
2410
_cpu_resume
),
S3C2412_INFORM1
);
__raw_writel
(
virt_to_phys
(
s3c_cpu_resume
),
S3C2412_INFORM1
);
return
0
;
}
...
...
@@ -630,7 +630,7 @@ static void __init jive_machine_init(void)
/* initialise the power management now we've setup everything. */
s3c
2410
_pm_init
();
s3c_pm_init
();
s3c_device_nand
.
dev
.
platform_data
=
&
jive_nand_info
;
...
...
arch/arm/mach-s3c2412/pm.c
View file @
f5f0e17a
...
...
@@ -85,7 +85,7 @@ static struct sleep_save s3c2412_sleep[] = {
static
int
s3c2412_pm_suspend
(
struct
sys_device
*
dev
,
pm_message_t
state
)
{
s3c
2410
_pm_do_save
(
s3c2412_sleep
,
ARRAY_SIZE
(
s3c2412_sleep
));
s3c_pm_do_save
(
s3c2412_sleep
,
ARRAY_SIZE
(
s3c2412_sleep
));
return
0
;
}
...
...
@@ -98,7 +98,7 @@ static int s3c2412_pm_resume(struct sys_device *dev)
tmp
|=
S3C2412_PWRCFG_STANDBYWFI_IDLE
;
__raw_writel
(
tmp
,
S3C2412_PWRCFG
);
s3c
2410
_pm_do_restore
(
s3c2412_sleep
,
ARRAY_SIZE
(
s3c2412_sleep
));
s3c_pm_do_restore
(
s3c2412_sleep
,
ARRAY_SIZE
(
s3c2412_sleep
));
return
0
;
}
...
...
arch/arm/mach-s3c2440/mach-rx3715.c
View file @
f5f0e17a
...
...
@@ -203,7 +203,7 @@ static void __init rx3715_init_machine(void)
#ifdef CONFIG_PM_H1940
memcpy
(
phys_to_virt
(
H1940_SUSPEND_RESUMEAT
),
h1940_pm_return
,
1024
);
#endif
s3c
2410
_pm_init
();
s3c_pm_init
();
s3c24xx_fb_set_platdata
(
&
rx3715_fb_info
);
platform_add_devices
(
rx3715_devices
,
ARRAY_SIZE
(
rx3715_devices
));
...
...
arch/arm/mach-s3c24a0/include/mach/irqs.h
View file @
f5f0e17a
...
...
@@ -70,6 +70,8 @@
#define IRQ_EINT17 S3C2410_IRQ(49)
#define IRQ_EINT18 S3C2410_IRQ(50)
#define IRQ_EINT_BIT(x) ((x) - IRQ_EINT00)
/* SUB IRQS */
#define IRQ_S3CUART_RX0 S3C2410_IRQ(51)
/* 67 */
#define IRQ_S3CUART_TX0 S3C2410_IRQ(52)
...
...
arch/arm/plat-s3c/Makefile
View file @
f5f0e17a
...
...
@@ -18,6 +18,11 @@ obj-y += pwm-clock.o
obj-y
+=
gpio.o
obj-y
+=
gpio-config.o
# PM support
obj-$(CONFIG_PM)
+=
pm.o
obj-$(CONFIG_S3C2410_PM_CHECK)
+=
pm-check.o
# devices
obj-$(CONFIG_S3C_DEV_HSMMC)
+=
dev-hsmmc.o
...
...
arch/arm/plat-s3c/include/plat/pm.h
0 → 100644
View file @
f5f0e17a
/* linux/include/asm-arm/plat-s3c24xx/pm.h
*
* Copyright (c) 2004 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Written by Ben Dooks, <ben@simtec.co.uk>
*
* 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.
*/
/* s3c_pm_init
*
* called from board at initialisation time to setup the power
* management
*/
#ifdef CONFIG_PM
extern
__init
int
s3c_pm_init
(
void
);
#else
static
inline
int
s3c_pm_init
(
void
)
{
return
0
;
}
#endif
/* configuration for the IRQ mask over sleep */
extern
unsigned
long
s3c_irqwake_intmask
;
extern
unsigned
long
s3c_irqwake_eintmask
;
/* IRQ masks for IRQs allowed to go to sleep (see irq.c) */
extern
unsigned
long
s3c_irqwake_intallow
;
extern
unsigned
long
s3c_irqwake_eintallow
;
/* per-cpu sleep functions */
extern
void
(
*
pm_cpu_prep
)(
void
);
extern
void
(
*
pm_cpu_sleep
)(
void
);
/* Flags for PM Control */
extern
unsigned
long
s3c_pm_flags
;
/* from sleep.S */
extern
int
s3c_cpu_save
(
unsigned
long
*
saveblk
);
extern
void
s3c_cpu_resume
(
void
);
extern
void
s3c2410_cpu_suspend
(
void
);
extern
unsigned
long
s3c_sleep_save_phys
;
/* sleep save info */
/**
* struct sleep_save - save information for shared peripherals.
* @reg: Pointer to the register to save.
* @val: Holder for the value saved from reg.
*
* This describes a list of registers which is used by the pm core and
* other subsystem to save and restore register values over suspend.
*/
struct
sleep_save
{
void
__iomem
*
reg
;
unsigned
long
val
;
};
#define SAVE_ITEM(x) \
{ .reg = (x) }
/**
* struct pm_uart_save - save block for core UART
* @ulcon: Save value for S3C2410_ULCON
* @ucon: Save value for S3C2410_UCON
* @ufcon: Save value for S3C2410_UFCON
* @umcon: Save value for S3C2410_UMCON
* @ubrdiv: Save value for S3C2410_UBRDIV
*
* Save block for UART registers to be held over sleep and restored if they
* are needed (say by debug).
*/
struct
pm_uart_save
{
u32
ulcon
;
u32
ucon
;
u32
ufcon
;
u32
umcon
;
u32
ubrdiv
;
};
/* helper functions to save/restore lists of registers. */
extern
void
s3c_pm_do_save
(
struct
sleep_save
*
ptr
,
int
count
);
extern
void
s3c_pm_do_restore
(
struct
sleep_save
*
ptr
,
int
count
);
extern
void
s3c_pm_do_restore_core
(
struct
sleep_save
*
ptr
,
int
count
);
#ifdef CONFIG_PM
extern
int
s3c_irqext_wake
(
unsigned
int
irqno
,
unsigned
int
state
);
extern
int
s3c24xx_irq_suspend
(
struct
sys_device
*
dev
,
pm_message_t
state
);
extern
int
s3c24xx_irq_resume
(
struct
sys_device
*
dev
);
#else
#define s3c_irqext_wake NULL
#define s3c24xx_irq_suspend NULL
#define s3c24xx_irq_resume NULL
#endif
/* PM debug functions */
#ifdef CONFIG_S3C2410_PM_DEBUG
/**
* s3c_pm_dbg() - low level debug function for use in suspend/resume.
* @msg: The message to print.
*
* This function is used mainly to debug the resume process before the system
* can rely on printk/console output. It uses the low-level debugging output
* routine printascii() to do its work.
*/
extern
void
s3c_pm_dbg
(
const
char
*
msg
,
...);
#define S3C_PMDBG(fmt...) s3c_pm_dbg(fmt)
#else
#define S3C_PMDBG(fmt...) printk(KERN_DEBUG fmt)
#endif
/* suspend memory checking */
#ifdef CONFIG_S3C2410_PM_CHECK
extern
void
s3c_pm_check_prepare
(
void
);
extern
void
s3c_pm_check_restore
(
void
);
extern
void
s3c_pm_check_cleanup
(
void
);
extern
void
s3c_pm_check_store
(
void
);
#else
#define s3c_pm_check_prepare() do { } while(0)
#define s3c_pm_check_restore() do { } while(0)
#define s3c_pm_check_cleanup() do { } while(0)
#define s3c_pm_check_store() do { } while(0)
#endif
/**
* s3c_pm_configure_extint() - ensure pins are correctly set for IRQ
*
* Setup all the necessary GPIO pins for waking the system on external
* interrupt.
*/
extern
void
s3c_pm_configure_extint
(
void
);
/**
* s3c_pm_restore_gpios() - restore the state of the gpios after sleep.
*
* Restore the state of the GPIO pins after sleep, which may involve ensuring
* that we do not glitch the state of the pins from that the bootloader's
* resume code has done.
*/
extern
void
s3c_pm_restore_gpios
(
void
);
/**
* s3c_pm_save_gpios() - save the state of the GPIOs for restoring after sleep.
*
* Save the GPIO states for resotration on resume. See s3c_pm_restore_gpios().
*/
extern
void
s3c_pm_save_gpios
(
void
);
/**
* s3c_pm_cb_flushcache - callback for assembly code
*
* Callback to issue flush_cache_all() as this call is
* not a directly callable object.
*/
extern
void
s3c_pm_cb_flushcache
(
void
);
extern
void
s3c_pm_save_core
(
void
);
extern
void
s3c_pm_restore_core
(
void
);
arch/arm/plat-s3c/pm-check.c
0 → 100644
View file @
f5f0e17a
/* linux/arch/arm/plat-s3c/pm-check.c
* originally in linux/arch/arm/plat-s3c24xx/pm.c
*
* Copyright (c) 2004,2006,2008 Simtec Electronics
* http://armlinux.simtec.co.uk
* Ben Dooks <ben@simtec.co.uk>
*
* S3C Power Mangament - suspend/resume memory corruptiuon check.
*
* 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/suspend.h>
#include <linux/init.h>
#include <linux/crc32.h>
#include <linux/ioport.h>
#include <plat/pm.h>
#if CONFIG_S3C2410_PM_CHECK_CHUNKSIZE < 1
#error CONFIG_S3C2410_PM_CHECK_CHUNKSIZE must be a positive non-zero value
#endif
/* suspend checking code...
*
* this next area does a set of crc checks over all the installed
* memory, so the system can verify if the resume was ok.
*
* CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC,
* increasing it will mean that the area corrupted will be less easy to spot,
* and reducing the size will cause the CRC save area to grow
*/
#define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024)
static
u32
crc_size
;
/* size needed for the crc block */
static
u32
*
crcs
;
/* allocated over suspend/resume */
typedef
u32
*
(
run_fn_t
)(
struct
resource
*
ptr
,
u32
*
arg
);
/* s3c_pm_run_res
*
* go through the given resource list, and look for system ram
*/
static
void
s3c_pm_run_res
(
struct
resource
*
ptr
,
run_fn_t
fn
,
u32
*
arg
)
{
while
(
ptr
!=
NULL
)
{
if
(
ptr
->
child
!=
NULL
)
s3c_pm_run_res
(
ptr
->
child
,
fn
,
arg
);
if
((
ptr
->
flags
&
IORESOURCE_MEM
)
&&
strcmp
(
ptr
->
name
,
"System RAM"
)
==
0
)
{
S3C_PMDBG
(
"Found system RAM at %08lx..%08lx
\n
"
,
(
unsigned
long
)
ptr
->
start
,
(
unsigned
long
)
ptr
->
end
);
arg
=
(
fn
)(
ptr
,
arg
);
}
ptr
=
ptr
->
sibling
;
}
}
static
void
s3c_pm_run_sysram
(
run_fn_t
fn
,
u32
*
arg
)
{
s3c_pm_run_res
(
&
iomem_resource
,
fn
,
arg
);
}
static
u32
*
s3c_pm_countram
(
struct
resource
*
res
,
u32
*
val
)
{
u32
size
=
(
u32
)(
res
->
end
-
res
->
start
)
+
1
;
size
+=
CHECK_CHUNKSIZE
-
1
;
size
/=
CHECK_CHUNKSIZE
;
S3C_PMDBG
(
"Area %08lx..%08lx, %d blocks
\n
"
,
(
unsigned
long
)
res
->
start
,
(
unsigned
long
)
res
->
end
,
size
);
*
val
+=
size
*
sizeof
(
u32
);
return
val
;
}
/* s3c_pm_prepare_check
*
* prepare the necessary information for creating the CRCs. This
* must be done before the final save, as it will require memory
* allocating, and thus touching bits of the kernel we do not
* know about.
*/
void
s3c_pm_check_prepare
(
void
)
{
crc_size
=
0
;
s3c_pm_run_sysram
(
s3c_pm_countram
,
&
crc_size
);
S3C_PMDBG
(
"s3c_pm_prepare_check: %u checks needed
\n
"
,
crc_size
);
crcs
=
kmalloc
(
crc_size
+
4
,
GFP_KERNEL
);
if
(
crcs
==
NULL
)
printk
(
KERN_ERR
"Cannot allocated CRC save area
\n
"
);
}
static
u32
*
s3c_pm_makecheck
(
struct
resource
*
res
,
u32
*
val
)
{
unsigned
long
addr
,
left
;
for
(
addr
=
res
->
start
;
addr
<
res
->
end
;
addr
+=
CHECK_CHUNKSIZE
)
{
left
=
res
->
end
-
addr
;
if
(
left
>
CHECK_CHUNKSIZE
)
left
=
CHECK_CHUNKSIZE
;
*
val
=
crc32_le
(
~
0
,
phys_to_virt
(
addr
),
left
);
val
++
;
}
return
val
;
}
/* s3c_pm_check_store
*
* compute the CRC values for the memory blocks before the final
* sleep.
*/
void
s3c_pm_check_store
(
void
)
{
if
(
crcs
!=
NULL
)
s3c_pm_run_sysram
(
s3c_pm_makecheck
,
crcs
);
}
/* in_region
*
* return TRUE if the area defined by ptr..ptr+size contains the
* what..what+whatsz
*/
static
inline
int
in_region
(
void
*
ptr
,
int
size
,
void
*
what
,
size_t
whatsz
)
{
if
((
what
+
whatsz
)
<
ptr
)
return
0
;
if
(
what
>
(
ptr
+
size
))
return
0
;
return
1
;
}
/**
* s3c_pm_runcheck() - helper to check a resource on restore.
* @res: The resource to check
* @vak: Pointer to list of CRC32 values to check.
*
* Called from the s3c_pm_check_restore() via s3c_pm_run_sysram(), this
* function runs the given memory resource checking it against the stored
* CRC to ensure that memory is restored. The function tries to skip as
* many of the areas used during the suspend process.
*/
static
u32
*
s3c_pm_runcheck
(
struct
resource
*
res
,
u32
*
val
)
{
void
*
save_at
=
phys_to_virt
(
s3c_sleep_save_phys
);
unsigned
long
addr
;
unsigned
long
left
;
void
*
stkpage
;
void
*
ptr
;
u32
calc
;
stkpage
=
(
void
*
)((
u32
)
&
calc
&
~
PAGE_MASK
);
for
(
addr
=
res
->
start
;
addr
<
res
->
end
;
addr
+=
CHECK_CHUNKSIZE
)
{
left
=
res
->
end
-
addr
;
if
(
left
>
CHECK_CHUNKSIZE
)
left
=
CHECK_CHUNKSIZE
;
ptr
=
phys_to_virt
(
addr
);
if
(
in_region
(
ptr
,
left
,
stkpage
,
4096
))
{
S3C_PMDBG
(
"skipping %08lx, has stack in
\n
"
,
addr
);
goto
skip_check
;
}
if
(
in_region
(
ptr
,
left
,
crcs
,
crc_size
))
{
S3C_PMDBG
(
"skipping %08lx, has crc block in
\n
"
,
addr
);
goto
skip_check
;
}
if
(
in_region
(
ptr
,
left
,
save_at
,
32
*
4
))
{
S3C_PMDBG
(
"skipping %08lx, has save block in
\n
"
,
addr
);
goto
skip_check
;
}
/* calculate and check the checksum */
calc
=
crc32_le
(
~
0
,
ptr
,
left
);
if
(
calc
!=
*
val
)
{
printk
(
KERN_ERR
"Restore CRC error at "
"%08lx (%08x vs %08x)
\n
"
,
addr
,
calc
,
*
val
);
S3C_PMDBG
(
"Restore CRC error at %08lx (%08x vs %08x)
\n
"
,
addr
,
calc
,
*
val
);
}
skip_check:
val
++
;
}
return
val
;
}
/**
* s3c_pm_check_restore() - memory check called on resume
*
* check the CRCs after the restore event and free the memory used
* to hold them
*/
void
s3c_pm_check_restore
(
void
)
{
if
(
crcs
!=
NULL
)
s3c_pm_run_sysram
(
s3c_pm_runcheck
,
crcs
);
}
/**
* s3c_pm_check_cleanup() - free memory resources
*
* Free the resources that where allocated by the suspend
* memory check code. We do this separately from the
* s3c_pm_check_restore() function as we cannot call any
* functions that might sleep during that resume.
*/
void
s3c_pm_check_cleanup
(
void
)
{
kfree
(
crcs
);
crcs
=
NULL
;
}
arch/arm/plat-s3c/pm.c
0 → 100644
View file @
f5f0e17a
/* linux/arch/arm/plat-s3c/pm.c
*
* Copyright 2008 Openmoko, Inc.
* Copyright 2004,2006,2008 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
* S3C common power management (suspend to ram) 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/errno.h>
#include <linux/delay.h>
#include <linux/serial_core.h>
#include <linux/io.h>
#include <asm/cacheflush.h>
#include <mach/hardware.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>
#include <plat/pm.h>
#include <plat/pm-core.h>
/* for external use */
unsigned
long
s3c_pm_flags
;
/* Debug code:
*
* This code supports debug output to the low level UARTs for use on
* resume before the console layer is available.
*/
#ifdef CONFIG_S3C2410_PM_DEBUG
extern
void
printascii
(
const
char
*
);
void
s3c_pm_dbg
(
const
char
*
fmt
,
...)
{
va_list
va
;
char
buff
[
256
];
va_start
(
va
,
fmt
);
vsprintf
(
buff
,
fmt
,
va
);
va_end
(
va
);
printascii
(
buff
);
}
static
inline
void
s3c_pm_debug_init
(
void
)
{
/* restart uart clocks so we can use them to output */
s3c_pm_debug_init_uart
();
}
#else
#define s3c_pm_debug_init() do { } while(0)
#endif
/* CONFIG_S3C2410_PM_DEBUG */
/* Save the UART configurations if we are configured for debug. */
#ifdef CONFIG_S3C2410_PM_DEBUG
struct
pm_uart_save
uart_save
[
CONFIG_SERIAL_SAMSUNG_UARTS
];
static
void
s3c_pm_save_uart
(
unsigned
int
uart
,
struct
pm_uart_save
*
save
)
{
void
__iomem
*
regs
=
S3C_VA_UARTx
(
uart
);
save
->
ulcon
=
__raw_readl
(
regs
+
S3C2410_ULCON
);
save
->
ucon
=
__raw_readl
(
regs
+
S3C2410_UCON
);
save
->
ufcon
=
__raw_readl
(
regs
+
S3C2410_UFCON
);
save
->
umcon
=
__raw_readl
(
regs
+
S3C2410_UMCON
);
save
->
ubrdiv
=
__raw_readl
(
regs
+
S3C2410_UBRDIV
);
}
static
void
s3c_pm_save_uarts
(
void
)
{
struct
pm_uart_save
*
save
=
uart_save
;
unsigned
int
uart
;
for
(
uart
=
0
;
uart
<
CONFIG_SERIAL_SAMSUNG_UARTS
;
uart
++
,
save
++
)
s3c_pm_save_uart
(
uart
,
save
);
}
static
void
s3c_pm_restore_uart
(
unsigned
int
uart
,
struct
pm_uart_save
*
save
)
{
void
__iomem
*
regs
=
S3C_VA_UARTx
(
uart
);
__raw_writel
(
save
->
ulcon
,
regs
+
S3C2410_ULCON
);
__raw_writel
(
save
->
ucon
,
regs
+
S3C2410_UCON
);
__raw_writel
(
save
->
ufcon
,
regs
+
S3C2410_UFCON
);
__raw_writel
(
save
->
umcon
,
regs
+
S3C2410_UMCON
);
__raw_writel
(
save
->
ubrdiv
,
regs
+
S3C2410_UBRDIV
);
}
static
void
s3c_pm_restore_uarts
(
void
)
{
struct
pm_uart_save
*
save
=
uart_save
;
unsigned
int
uart
;
for
(
uart
=
0
;
uart
<
CONFIG_SERIAL_SAMSUNG_UARTS
;
uart
++
,
save
++
)
s3c_pm_restore_uart
(
uart
,
save
);
}
#else
static
void
s3c_pm_save_uarts
(
void
)
{
}
static
void
s3c_pm_restore_uarts
(
void
)
{
}
#endif
/* The IRQ ext-int code goes here, it is too small to currently bother
* with its own file. */
unsigned
long
s3c_irqwake_intmask
=
0xffffffffL
;
unsigned
long
s3c_irqwake_eintmask
=
0xffffffffL
;
int
s3c_irqext_wake
(
unsigned
int
irqno
,
unsigned
int
state
)
{
unsigned
long
bit
=
1L
<<
IRQ_EINT_BIT
(
irqno
);
if
(
!
(
s3c_irqwake_eintallow
&
bit
))
return
-
ENOENT
;
printk
(
KERN_INFO
"wake %s for irq %d
\n
"
,
state
?
"enabled"
:
"disabled"
,
irqno
);
if
(
!
state
)
s3c_irqwake_eintmask
|=
bit
;
else
s3c_irqwake_eintmask
&=
~
bit
;
return
0
;
}
/* helper functions to save and restore register state */
/**
* s3c_pm_do_save() - save a set of registers for restoration on resume.
* @ptr: Pointer to an array of registers.
* @count: Size of the ptr array.
*
* Run through the list of registers given, saving their contents in the
* array for later restoration when we wakeup.
*/
void
s3c_pm_do_save
(
struct
sleep_save
*
ptr
,
int
count
)
{
for
(;
count
>
0
;
count
--
,
ptr
++
)
{
ptr
->
val
=
__raw_readl
(
ptr
->
reg
);
S3C_PMDBG
(
"saved %p value %08lx
\n
"
,
ptr
->
reg
,
ptr
->
val
);
}
}
/**
* s3c_pm_do_restore() - restore register values from the save list.
* @ptr: Pointer to an array of registers.
* @count: Size of the ptr array.
*
* Restore the register values saved from s3c_pm_do_save().
*
* Note, we do not use S3C_PMDBG() in here, as the system may not have
* restore the UARTs state yet
*/
void
s3c_pm_do_restore
(
struct
sleep_save
*
ptr
,
int
count
)
{
for
(;
count
>
0
;
count
--
,
ptr
++
)
{
printk
(
KERN_DEBUG
"restore %p (restore %08lx, was %08x)
\n
"
,
ptr
->
reg
,
ptr
->
val
,
__raw_readl
(
ptr
->
reg
));
__raw_writel
(
ptr
->
val
,
ptr
->
reg
);
}
}
/**
* s3c_pm_do_restore_core() - early restore register values from save list.
*
* This is similar to s3c_pm_do_restore() except we try and minimise the
* side effects of the function in case registers that hardware might need
* to work has been restored.
*
* WARNING: Do not put any debug in here that may effect memory or use
* peripherals, as things may be changing!
*/
void
s3c_pm_do_restore_core
(
struct
sleep_save
*
ptr
,
int
count
)
{
for
(;
count
>
0
;
count
--
,
ptr
++
)
__raw_writel
(
ptr
->
val
,
ptr
->
reg
);
}
/* s3c2410_pm_show_resume_irqs
*
* print any IRQs asserted at resume time (ie, we woke from)
*/
static
void
s3c_pm_show_resume_irqs
(
int
start
,
unsigned
long
which
,
unsigned
long
mask
)
{
int
i
;
which
&=
~
mask
;
for
(
i
=
0
;
i
<=
31
;
i
++
)
{
if
(
which
&
(
1L
<<
i
))
{
S3C_PMDBG
(
"IRQ %d asserted at resume
\n
"
,
start
+
i
);
}
}
}
void
(
*
pm_cpu_prep
)(
void
);
void
(
*
pm_cpu_sleep
)(
void
);
#define any_allowed(mask, allow) (((mask) & (allow)) != (allow))
/* s3c_pm_enter
*
* central control for sleep/resume process
*/
static
int
s3c_pm_enter
(
suspend_state_t
state
)
{
static
unsigned
long
regs_save
[
16
];
/* ensure the debug is initialised (if enabled) */
s3c_pm_debug_init
();
S3C_PMDBG
(
"%s(%d)
\n
"
,
__func__
,
state
);
if
(
pm_cpu_prep
==
NULL
||
pm_cpu_sleep
==
NULL
)
{
printk
(
KERN_ERR
"%s: error: no cpu sleep function
\n
"
,
__func__
);
return
-
EINVAL
;
}
/* check if we have anything to wake-up with... bad things seem
* to happen if you suspend with no wakeup (system will often
* require a full power-cycle)
*/
if
(
!
any_allowed
(
s3c_irqwake_intmask
,
s3c_irqwake_intallow
)
&&
!
any_allowed
(
s3c_irqwake_eintmask
,
s3c_irqwake_eintallow
))
{
printk
(
KERN_ERR
"%s: No wake-up sources!
\n
"
,
__func__
);
printk
(
KERN_ERR
"%s: Aborting sleep
\n
"
,
__func__
);
return
-
EINVAL
;
}
/* store the physical address of the register recovery block */
s3c_sleep_save_phys
=
virt_to_phys
(
regs_save
);
S3C_PMDBG
(
"s3c_sleep_save_phys=0x%08lx
\n
"
,
s3c_sleep_save_phys
);
/* save all necessary core registers not covered by the drivers */
s3c_pm_save_gpios
();
s3c_pm_save_uarts
();
s3c_pm_save_core
();
/* set the irq configuration for wake */
s3c_pm_configure_extint
();
S3C_PMDBG
(
"sleep: irq wakeup masks: %08lx,%08lx
\n
"
,
s3c_irqwake_intmask
,
s3c_irqwake_eintmask
);
s3c_pm_arch_prepare_irqs
();
/* call cpu specific preparation */
pm_cpu_prep
();
/* flush cache back to ram */
flush_cache_all
();
s3c_pm_check_store
();
/* send the cpu to sleep... */
s3c_pm_arch_stop_clocks
();
/* s3c_cpu_save will also act as our return point from when
* we resume as it saves its own register state and restores it
* during the resume. */
s3c_cpu_save
(
regs_save
);
/* restore the cpu state using the kernel's cpu init code. */
cpu_init
();
/* restore the system state */
s3c_pm_restore_core
();
s3c_pm_restore_uarts
();
s3c_pm_restore_gpios
();
s3c_pm_debug_init
();
/* check what irq (if any) restored the system */
s3c_pm_arch_show_resume_irqs
();
S3C_PMDBG
(
"%s: post sleep, preparing to return
\n
"
,
__func__
);
s3c_pm_check_restore
();
/* ok, let's return from sleep */
S3C_PMDBG
(
"S3C PM Resume (post-restore)
\n
"
);
return
0
;
}
/* callback from assembly code */
void
s3c_pm_cb_flushcache
(
void
)
{
flush_cache_all
();
}
static
int
s3c_pm_prepare
(
void
)
{
/* prepare check area if configured */
s3c_pm_check_prepare
();
return
0
;
}
static
void
s3c_pm_finish
(
void
)
{
s3c_pm_check_cleanup
();
}
static
struct
platform_suspend_ops
s3c_pm_ops
=
{
.
enter
=
s3c_pm_enter
,
.
prepare
=
s3c_pm_prepare
,
.
finish
=
s3c_pm_finish
,
.
valid
=
suspend_valid_only_mem
,
};
/* s3c_pm_init
*
* Attach the power management functions. This should be called
* from the board specific initialisation if the board supports
* it.
*/
int
__init
s3c_pm_init
(
void
)
{
printk
(
"S3C Power Management, Copyright 2004 Simtec Electronics
\n
"
);
suspend_set_ops
(
&
s3c_pm_ops
);
return
0
;
}
arch/arm/plat-s3c24xx/Makefile
View file @
f5f0e17a
...
...
@@ -27,6 +27,7 @@ obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o
obj-$(CONFIG_CPU_S3C244X)
+=
s3c244x-clock.o
obj-$(CONFIG_PM_SIMTEC)
+=
pm-simtec.o
obj-$(CONFIG_PM)
+=
pm.o
obj-$(CONFIG_PM)
+=
irq-pm.o
obj-$(CONFIG_PM)
+=
sleep.o
obj-$(CONFIG_HAVE_PWM)
+=
pwm.o
obj-$(CONFIG_S3C2410_CLOCK)
+=
s3c2410-clock.o
...
...
arch/arm/plat-s3c24xx/common-smdk.c
View file @
f5f0e17a
...
...
@@ -201,5 +201,5 @@ void __init smdk_machine_init(void)
platform_add_devices
(
smdk_devs
,
ARRAY_SIZE
(
smdk_devs
));
s3c
2410
_pm_init
();
s3c_pm_init
();
}
arch/arm/plat-s3c24xx/include/plat/irq.h
View file @
f5f0e17a
...
...
@@ -10,6 +10,12 @@
* published by the Free Software Foundation.
*/
#include <linux/io.h>
#include <mach/hardware.h>
#include <mach/regs-irq.h>
#include <mach/regs-gpio.h>
#define irqdbf(x...)
#define irqdbf2(x...)
...
...
arch/arm/plat-s3c24xx/include/plat/map.h
View file @
f5f0e17a
...
...
@@ -31,6 +31,8 @@
#define S3C24XX_SZ_UART SZ_1M
#define S3C_UART_OFFSET (0x4000)
#define S3C_VA_UARTx(uart) (S3C_VA_UART + ((uart * S3C_UART_OFFSET)))
/* Timers */
#define S3C24XX_VA_TIMER S3C_VA_TIMER
#define S3C2410_PA_TIMER (0x51000000)
...
...
arch/arm/plat-s3c24xx/include/plat/pm-core.h
0 → 100644
View file @
f5f0e17a
/* linux/arch/arm/plat-s3c24xx/include/plat/pll.h
*
* Copyright 2008 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
* S3C24xx - 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.
*/
static
inline
void
s3c_pm_debug_init_uart
(
void
)
{
unsigned
long
tmp
=
__raw_readl
(
S3C2410_CLKCON
);
/* re-start uart clocks */
tmp
|=
S3C2410_CLKCON_UART0
;
tmp
|=
S3C2410_CLKCON_UART1
;
tmp
|=
S3C2410_CLKCON_UART2
;
__raw_writel
(
tmp
,
S3C2410_CLKCON
);
udelay
(
10
);
}
static
inline
void
s3c_pm_arch_prepare_irqs
(
void
)
{
__raw_writel
(
s3c_irqwake_intmask
,
S3C2410_INTMSK
);
__raw_writel
(
s3c_irqwake_eintmask
,
S3C2410_EINTMASK
);
/* ack any outstanding external interrupts before we go to sleep */
__raw_writel
(
__raw_readl
(
S3C2410_EINTPEND
),
S3C2410_EINTPEND
);
__raw_writel
(
__raw_readl
(
S3C2410_INTPND
),
S3C2410_INTPND
);
__raw_writel
(
__raw_readl
(
S3C2410_SRCPND
),
S3C2410_SRCPND
);
}
static
inline
void
s3c_pm_arch_stop_clocks
(
void
)
{
__raw_writel
(
0x00
,
S3C2410_CLKCON
);
/* turn off clocks over sleep */
}
static
void
s3c_pm_show_resume_irqs
(
int
start
,
unsigned
long
which
,
unsigned
long
mask
);
static
inline
void
s3c_pm_arch_show_resume_irqs
(
void
)
{
S3C_PMDBG
(
"post sleep: IRQs 0x%08x, 0x%08x
\n
"
,
__raw_readl
(
S3C2410_SRCPND
),
__raw_readl
(
S3C2410_EINTPEND
));
s3c_pm_show_resume_irqs
(
IRQ_EINT0
,
__raw_readl
(
S3C2410_SRCPND
),
s3c_irqwake_intmask
);
s3c_pm_show_resume_irqs
(
IRQ_EINT4
-
4
,
__raw_readl
(
S3C2410_EINTPEND
),
s3c_irqwake_eintmask
);
}
arch/arm/plat-s3c24xx/include/plat/pm.h
deleted
100644 → 0
View file @
2f3ec501
/* linux/include/asm-arm/plat-s3c24xx/pm.h
*
* Copyright (c) 2004 Simtec Electronics
* Written by Ben Dooks, <ben@simtec.co.uk>
*
* 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.
*/
/* s3c2410_pm_init
*
* called from board at initialisation time to setup the power
* management
*/
#ifdef CONFIG_PM
extern
__init
int
s3c2410_pm_init
(
void
);
#else
static
inline
int
s3c2410_pm_init
(
void
)
{
return
0
;
}
#endif
/* configuration for the IRQ mask over sleep */
extern
unsigned
long
s3c_irqwake_intmask
;
extern
unsigned
long
s3c_irqwake_eintmask
;
/* IRQ masks for IRQs allowed to go to sleep (see irq.c) */
extern
unsigned
long
s3c_irqwake_intallow
;
extern
unsigned
long
s3c_irqwake_eintallow
;
/* per-cpu sleep functions */
extern
void
(
*
pm_cpu_prep
)(
void
);
extern
void
(
*
pm_cpu_sleep
)(
void
);
/* Flags for PM Control */
extern
unsigned
long
s3c_pm_flags
;
/* from sleep.S */
extern
int
s3c2410_cpu_save
(
unsigned
long
*
saveblk
);
extern
void
s3c2410_cpu_suspend
(
void
);
extern
void
s3c2410_cpu_resume
(
void
);
extern
unsigned
long
s3c2410_sleep_save_phys
;
/* sleep save info */
struct
sleep_save
{
void
__iomem
*
reg
;
unsigned
long
val
;
};
#define SAVE_ITEM(x) \
{ .reg = (x) }
extern
void
s3c2410_pm_do_save
(
struct
sleep_save
*
ptr
,
int
count
);
extern
void
s3c2410_pm_do_restore
(
struct
sleep_save
*
ptr
,
int
count
);
#ifdef CONFIG_PM
extern
int
s3c24xx_irq_suspend
(
struct
sys_device
*
dev
,
pm_message_t
state
);
extern
int
s3c24xx_irq_resume
(
struct
sys_device
*
dev
);
#else
#define s3c24xx_irq_suspend NULL
#define s3c24xx_irq_resume NULL
#endif
arch/arm/plat-s3c24xx/irq-pm.c
0 → 100644
View file @
f5f0e17a
/* linux/arch/arm/plat-s3c24xx/irq-om.c
*
* Copyright (c) 2003,2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
* S3C24XX - IRQ PM 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/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/sysdev.h>
#include <plat/cpu.h>
#include <plat/pm.h>
#include <plat/irq.h>
/* state for IRQs over sleep */
/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources
*
* set bit to 1 in allow bitfield to enable the wakeup settings on it
*/
unsigned
long
s3c_irqwake_intallow
=
1L
<<
(
IRQ_RTC
-
IRQ_EINT0
)
|
0xfL
;
unsigned
long
s3c_irqwake_eintallow
=
0x0000fff0L
;
int
s3c_irq_wake
(
unsigned
int
irqno
,
unsigned
int
state
)
{
unsigned
long
irqbit
=
1
<<
(
irqno
-
IRQ_EINT0
);
if
(
!
(
s3c_irqwake_intallow
&
irqbit
))
return
-
ENOENT
;
printk
(
KERN_INFO
"wake %s for irq %d
\n
"
,
state
?
"enabled"
:
"disabled"
,
irqno
);
if
(
!
state
)
s3c_irqwake_intmask
|=
irqbit
;
else
s3c_irqwake_intmask
&=
~
irqbit
;
return
0
;
}
static
struct
sleep_save
irq_save
[]
=
{
SAVE_ITEM
(
S3C2410_INTMSK
),
SAVE_ITEM
(
S3C2410_INTSUBMSK
),
};
/* the extint values move between the s3c2410/s3c2440 and the s3c2412
* so we use an array to hold them, and to calculate the address of
* the register at run-time
*/
static
unsigned
long
save_extint
[
3
];
static
unsigned
long
save_eintflt
[
4
];
static
unsigned
long
save_eintmask
;
int
s3c24xx_irq_suspend
(
struct
sys_device
*
dev
,
pm_message_t
state
)
{
unsigned
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
save_extint
);
i
++
)
save_extint
[
i
]
=
__raw_readl
(
S3C24XX_EXTINT0
+
(
i
*
4
));
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
save_eintflt
);
i
++
)
save_eintflt
[
i
]
=
__raw_readl
(
S3C24XX_EINFLT0
+
(
i
*
4
));
s3c_pm_do_save
(
irq_save
,
ARRAY_SIZE
(
irq_save
));
save_eintmask
=
__raw_readl
(
S3C24XX_EINTMASK
);
return
0
;
}
int
s3c24xx_irq_resume
(
struct
sys_device
*
dev
)
{
unsigned
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
save_extint
);
i
++
)
__raw_writel
(
save_extint
[
i
],
S3C24XX_EXTINT0
+
(
i
*
4
));
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
save_eintflt
);
i
++
)
__raw_writel
(
save_eintflt
[
i
],
S3C24XX_EINFLT0
+
(
i
*
4
));
s3c_pm_do_restore
(
irq_save
,
ARRAY_SIZE
(
irq_save
));
__raw_writel
(
save_eintmask
,
S3C24XX_EINTMASK
);
return
0
;
}
arch/arm/plat-s3c24xx/irq.c
View file @
f5f0e17a
/* linux/arch/arm/plat-s3c24xx/irq.c
*
* Copyright (c) 2003,2004 Simtec Electronics
* Copyright (c) 2003,2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* This program is free software; you can redistribute it and/or modify
...
...
@@ -16,38 +16,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Changelog:
*
* 22-Jul-2004 Ben Dooks <ben@simtec.co.uk>
* Fixed compile warnings
*
* 22-Jul-2004 Roc Wu <cooloney@yahoo.com.cn>
* Fixed s3c_extirq_type
*
* 21-Jul-2004 Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org>
* Addition of ADC/TC demux
*
* 04-Oct-2004 Klaus Fetscher <k.fetscher@fetron.de>
* Fix for set_irq_type() on low EINT numbers
*
* 05-Oct-2004 Ben Dooks <ben@simtec.co.uk>
* Tidy up KF's patch and sort out new release
*
* 05-Oct-2004 Ben Dooks <ben@simtec.co.uk>
* Add support for power management controls
*
* 04-Nov-2004 Ben Dooks
* Fix standard IRQ wake for EINT0..4 and RTC
*
* 22-Feb-2005 Ben Dooks
* Fixed edge-triggering on ADC IRQ
*
* 28-Jun-2005 Ben Dooks
* Mark IRQ_LCD valid
*
* 25-Jul-2005 Ben Dooks
* Split the S3C2440 IRQ code to separate file
*/
#include <linux/init.h>
...
...
@@ -55,81 +23,16 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/sysdev.h>
#include <linux/io.h>
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <plat/regs-irqtype.h>
#include <mach/regs-irq.h>
#include <mach/regs-gpio.h>
#include <plat/cpu.h>
#include <plat/pm.h>
#include <plat/irq.h>
/* wakeup irq control */
#ifdef CONFIG_PM
/* state for IRQs over sleep */
/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources
*
* set bit to 1 in allow bitfield to enable the wakeup settings on it
*/
unsigned
long
s3c_irqwake_intallow
=
1L
<<
(
IRQ_RTC
-
IRQ_EINT0
)
|
0xfL
;
unsigned
long
s3c_irqwake_intmask
=
0xffffffffL
;
unsigned
long
s3c_irqwake_eintallow
=
0x0000fff0L
;
unsigned
long
s3c_irqwake_eintmask
=
0xffffffffL
;
int
s3c_irq_wake
(
unsigned
int
irqno
,
unsigned
int
state
)
{
unsigned
long
irqbit
=
1
<<
(
irqno
-
IRQ_EINT0
);
if
(
!
(
s3c_irqwake_intallow
&
irqbit
))
return
-
ENOENT
;
printk
(
KERN_INFO
"wake %s for irq %d
\n
"
,
state
?
"enabled"
:
"disabled"
,
irqno
);
if
(
!
state
)
s3c_irqwake_intmask
|=
irqbit
;
else
s3c_irqwake_intmask
&=
~
irqbit
;
return
0
;
}
static
int
s3c_irqext_wake
(
unsigned
int
irqno
,
unsigned
int
state
)
{
unsigned
long
bit
=
1L
<<
(
irqno
-
EXTINT_OFF
);
if
(
!
(
s3c_irqwake_eintallow
&
bit
))
return
-
ENOENT
;
printk
(
KERN_INFO
"wake %s for irq %d
\n
"
,
state
?
"enabled"
:
"disabled"
,
irqno
);
if
(
!
state
)
s3c_irqwake_eintmask
|=
bit
;
else
s3c_irqwake_eintmask
&=
~
bit
;
return
0
;
}
#else
#define s3c_irqext_wake NULL
#define s3c_irq_wake NULL
#endif
static
void
s3c_irq_mask
(
unsigned
int
irqno
)
{
...
...
@@ -590,59 +493,6 @@ s3c_irq_demux_extint4t7(unsigned int irq,
}
}
#ifdef CONFIG_PM
static
struct
sleep_save
irq_save
[]
=
{
SAVE_ITEM
(
S3C2410_INTMSK
),
SAVE_ITEM
(
S3C2410_INTSUBMSK
),
};
/* the extint values move between the s3c2410/s3c2440 and the s3c2412
* so we use an array to hold them, and to calculate the address of
* the register at run-time
*/
static
unsigned
long
save_extint
[
3
];
static
unsigned
long
save_eintflt
[
4
];
static
unsigned
long
save_eintmask
;
int
s3c24xx_irq_suspend
(
struct
sys_device
*
dev
,
pm_message_t
state
)
{
unsigned
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
save_extint
);
i
++
)
save_extint
[
i
]
=
__raw_readl
(
S3C24XX_EXTINT0
+
(
i
*
4
));
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
save_eintflt
);
i
++
)
save_eintflt
[
i
]
=
__raw_readl
(
S3C24XX_EINFLT0
+
(
i
*
4
));
s3c2410_pm_do_save
(
irq_save
,
ARRAY_SIZE
(
irq_save
));
save_eintmask
=
__raw_readl
(
S3C24XX_EINTMASK
);
return
0
;
}
int
s3c24xx_irq_resume
(
struct
sys_device
*
dev
)
{
unsigned
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
save_extint
);
i
++
)
__raw_writel
(
save_extint
[
i
],
S3C24XX_EXTINT0
+
(
i
*
4
));
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
save_eintflt
);
i
++
)
__raw_writel
(
save_eintflt
[
i
],
S3C24XX_EINFLT0
+
(
i
*
4
));
s3c2410_pm_do_restore
(
irq_save
,
ARRAY_SIZE
(
irq_save
));
__raw_writel
(
save_eintmask
,
S3C24XX_EINTMASK
);
return
0
;
}
#else
#define s3c24xx_irq_suspend NULL
#define s3c24xx_irq_resume NULL
#endif
/* s3c24xx_init_irq
*
* Initialise S3C2410 IRQ system
...
...
arch/arm/plat-s3c24xx/pm-simtec.c
View file @
f5f0e17a
...
...
@@ -61,7 +61,7 @@ static __init int pm_simtec_init(void)
__raw_writel
(
gstatus4
,
S3C2410_GSTATUS4
);
return
s3c
2410
_pm_init
();
return
s3c_pm_init
();
}
arch_initcall
(
pm_simtec_init
);
arch/arm/plat-s3c24xx/pm.c
View file @
f5f0e17a
...
...
@@ -31,14 +31,9 @@
#include <linux/errno.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/crc32.h>
#include <linux/ioport.h>
#include <linux/serial_core.h>
#include <linux/io.h>
#include <asm/cacheflush.h>
#include <mach/hardware.h>
#include <plat/regs-serial.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
...
...
@@ -49,10 +44,6 @@
#include <plat/pm.h>
/* for external use */
unsigned
long
s3c_pm_flags
;
#define PFX "s3c24xx-pm: "
static
struct
sleep_save
core_save
[]
=
{
...
...
@@ -120,328 +111,14 @@ static struct sleep_save misc_save[] = {
SAVE_ITEM
(
S3C2410_DCLKCON
),
};
#ifdef CONFIG_S3C2410_PM_DEBUG
#define SAVE_UART(va) \
SAVE_ITEM((va) + S3C2410_ULCON), \
SAVE_ITEM((va) + S3C2410_UCON), \
SAVE_ITEM((va) + S3C2410_UFCON), \
SAVE_ITEM((va) + S3C2410_UMCON), \
SAVE_ITEM((va) + S3C2410_UBRDIV)
static
struct
sleep_save
uart_save
[]
=
{
SAVE_UART
(
S3C24XX_VA_UART0
),
SAVE_UART
(
S3C24XX_VA_UART1
),
#ifndef CONFIG_CPU_S3C2400
SAVE_UART
(
S3C24XX_VA_UART2
),
#endif
};
/* debug
*
* we send the debug to printascii() to allow it to be seen if the
* system never wakes up from the sleep
*/
extern
void
printascii
(
const
char
*
);
void
pm_dbg
(
const
char
*
fmt
,
...)
{
va_list
va
;
char
buff
[
256
];
va_start
(
va
,
fmt
);
vsprintf
(
buff
,
fmt
,
va
);
va_end
(
va
);
printascii
(
buff
);
}
static
void
s3c2410_pm_debug_init
(
void
)
{
unsigned
long
tmp
=
__raw_readl
(
S3C2410_CLKCON
);
/* re-start uart clocks */
tmp
|=
S3C2410_CLKCON_UART0
;
tmp
|=
S3C2410_CLKCON_UART1
;
tmp
|=
S3C2410_CLKCON_UART2
;
__raw_writel
(
tmp
,
S3C2410_CLKCON
);
udelay
(
10
);
}
#define DBG(fmt...) pm_dbg(fmt)
#else
#define DBG(fmt...) printk(KERN_DEBUG fmt)
#define s3c2410_pm_debug_init() do { } while(0)
static
struct
sleep_save
uart_save
[]
=
{};
#endif
#if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0
/* suspend checking code...
*
* this next area does a set of crc checks over all the installed
* memory, so the system can verify if the resume was ok.
*
* CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC,
* increasing it will mean that the area corrupted will be less easy to spot,
* and reducing the size will cause the CRC save area to grow
*/
#define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024)
static
u32
crc_size
;
/* size needed for the crc block */
static
u32
*
crcs
;
/* allocated over suspend/resume */
typedef
u32
*
(
run_fn_t
)(
struct
resource
*
ptr
,
u32
*
arg
);
/* s3c2410_pm_run_res
*
* go thorugh the given resource list, and look for system ram
*/
static
void
s3c2410_pm_run_res
(
struct
resource
*
ptr
,
run_fn_t
fn
,
u32
*
arg
)
{
while
(
ptr
!=
NULL
)
{
if
(
ptr
->
child
!=
NULL
)
s3c2410_pm_run_res
(
ptr
->
child
,
fn
,
arg
);
if
((
ptr
->
flags
&
IORESOURCE_MEM
)
&&
strcmp
(
ptr
->
name
,
"System RAM"
)
==
0
)
{
DBG
(
"Found system RAM at %08lx..%08lx
\n
"
,
ptr
->
start
,
ptr
->
end
);
arg
=
(
fn
)(
ptr
,
arg
);
}
ptr
=
ptr
->
sibling
;
}
}
static
void
s3c2410_pm_run_sysram
(
run_fn_t
fn
,
u32
*
arg
)
{
s3c2410_pm_run_res
(
&
iomem_resource
,
fn
,
arg
);
}
static
u32
*
s3c2410_pm_countram
(
struct
resource
*
res
,
u32
*
val
)
{
u32
size
=
(
u32
)(
res
->
end
-
res
->
start
)
+
1
;
size
+=
CHECK_CHUNKSIZE
-
1
;
size
/=
CHECK_CHUNKSIZE
;
DBG
(
"Area %08lx..%08lx, %d blocks
\n
"
,
res
->
start
,
res
->
end
,
size
);
*
val
+=
size
*
sizeof
(
u32
);
return
val
;
}
/* s3c2410_pm_prepare_check
*
* prepare the necessary information for creating the CRCs. This
* must be done before the final save, as it will require memory
* allocating, and thus touching bits of the kernel we do not
* know about.
*/
static
void
s3c2410_pm_check_prepare
(
void
)
{
crc_size
=
0
;
s3c2410_pm_run_sysram
(
s3c2410_pm_countram
,
&
crc_size
);
DBG
(
"s3c2410_pm_prepare_check: %u checks needed
\n
"
,
crc_size
);
crcs
=
kmalloc
(
crc_size
+
4
,
GFP_KERNEL
);
if
(
crcs
==
NULL
)
printk
(
KERN_ERR
"Cannot allocated CRC save area
\n
"
);
}
static
u32
*
s3c2410_pm_makecheck
(
struct
resource
*
res
,
u32
*
val
)
{
unsigned
long
addr
,
left
;
for
(
addr
=
res
->
start
;
addr
<
res
->
end
;
addr
+=
CHECK_CHUNKSIZE
)
{
left
=
res
->
end
-
addr
;
if
(
left
>
CHECK_CHUNKSIZE
)
left
=
CHECK_CHUNKSIZE
;
*
val
=
crc32_le
(
~
0
,
phys_to_virt
(
addr
),
left
);
val
++
;
}
return
val
;
}
/* s3c2410_pm_check_store
*
* compute the CRC values for the memory blocks before the final
* sleep.
*/
static
void
s3c2410_pm_check_store
(
void
)
{
if
(
crcs
!=
NULL
)
s3c2410_pm_run_sysram
(
s3c2410_pm_makecheck
,
crcs
);
}
/* in_region
*
* return TRUE if the area defined by ptr..ptr+size contatins the
* what..what+whatsz
*/
static
inline
int
in_region
(
void
*
ptr
,
int
size
,
void
*
what
,
size_t
whatsz
)
{
if
((
what
+
whatsz
)
<
ptr
)
return
0
;
if
(
what
>
(
ptr
+
size
))
return
0
;
return
1
;
}
static
u32
*
s3c2410_pm_runcheck
(
struct
resource
*
res
,
u32
*
val
)
{
void
*
save_at
=
phys_to_virt
(
s3c2410_sleep_save_phys
);
unsigned
long
addr
;
unsigned
long
left
;
void
*
ptr
;
u32
calc
;
for
(
addr
=
res
->
start
;
addr
<
res
->
end
;
addr
+=
CHECK_CHUNKSIZE
)
{
left
=
res
->
end
-
addr
;
if
(
left
>
CHECK_CHUNKSIZE
)
left
=
CHECK_CHUNKSIZE
;
ptr
=
phys_to_virt
(
addr
);
if
(
in_region
(
ptr
,
left
,
crcs
,
crc_size
))
{
DBG
(
"skipping %08lx, has crc block in
\n
"
,
addr
);
goto
skip_check
;
}
if
(
in_region
(
ptr
,
left
,
save_at
,
32
*
4
))
{
DBG
(
"skipping %08lx, has save block in
\n
"
,
addr
);
goto
skip_check
;
}
/* calculate and check the checksum */
calc
=
crc32_le
(
~
0
,
ptr
,
left
);
if
(
calc
!=
*
val
)
{
printk
(
KERN_ERR
PFX
"Restore CRC error at "
"%08lx (%08x vs %08x)
\n
"
,
addr
,
calc
,
*
val
);
DBG
(
"Restore CRC error at %08lx (%08x vs %08x)
\n
"
,
addr
,
calc
,
*
val
);
}
skip_check:
val
++
;
}
return
val
;
}
/* s3c2410_pm_check_restore
*
* check the CRCs after the restore event and free the memory used
* to hold them
*/
static
void
s3c2410_pm_check_restore
(
void
)
{
if
(
crcs
!=
NULL
)
{
s3c2410_pm_run_sysram
(
s3c2410_pm_runcheck
,
crcs
);
kfree
(
crcs
);
crcs
=
NULL
;
}
}
#else
#define s3c2410_pm_check_prepare() do { } while(0)
#define s3c2410_pm_check_restore() do { } while(0)
#define s3c2410_pm_check_store() do { } while(0)
#endif
/* helper functions to save and restore register state */
void
s3c2410_pm_do_save
(
struct
sleep_save
*
ptr
,
int
count
)
{
for
(;
count
>
0
;
count
--
,
ptr
++
)
{
ptr
->
val
=
__raw_readl
(
ptr
->
reg
);
DBG
(
"saved %p value %08lx
\n
"
,
ptr
->
reg
,
ptr
->
val
);
}
}
/* s3c2410_pm_do_restore
*
* restore the system from the given list of saved registers
*
* Note, we do not use DBG() in here, as the system may not have
* restore the UARTs state yet
*/
void
s3c2410_pm_do_restore
(
struct
sleep_save
*
ptr
,
int
count
)
{
for
(;
count
>
0
;
count
--
,
ptr
++
)
{
printk
(
KERN_DEBUG
"restore %p (restore %08lx, was %08x)
\n
"
,
ptr
->
reg
,
ptr
->
val
,
__raw_readl
(
ptr
->
reg
));
__raw_writel
(
ptr
->
val
,
ptr
->
reg
);
}
}
/* s3c2410_pm_do_restore_core
*
* similar to s3c2410_pm_do_restore_core
*
* WARNING: Do not put any debug in here that may effect memory or use
* peripherals, as things may be changing!
*/
static
void
s3c2410_pm_do_restore_core
(
struct
sleep_save
*
ptr
,
int
count
)
{
for
(;
count
>
0
;
count
--
,
ptr
++
)
{
__raw_writel
(
ptr
->
val
,
ptr
->
reg
);
}
}
/* s3c2410_pm_show_resume_irqs
*
* print any IRQs asserted at resume time (ie, we woke from)
*/
static
void
s3c2410_pm_show_resume_irqs
(
int
start
,
unsigned
long
which
,
unsigned
long
mask
)
{
int
i
;
which
&=
~
mask
;
for
(
i
=
0
;
i
<=
31
;
i
++
)
{
if
((
which
)
&
(
1L
<<
i
))
{
DBG
(
"IRQ %d asserted at resume
\n
"
,
start
+
i
);
}
}
}
/* s3c2410_pm_check_resume_pin
/* s3c_pm_check_resume_pin
*
* check to see if the pin is configured correctly for sleep mode, and
* make any necessary adjustments if it is not
*/
static
void
s3c
2410
_pm_check_resume_pin
(
unsigned
int
pin
,
unsigned
int
irqoffs
)
static
void
s3c_pm_check_resume_pin
(
unsigned
int
pin
,
unsigned
int
irqoffs
)
{
unsigned
long
irqstate
;
unsigned
long
pinstate
;
...
...
@@ -456,21 +133,21 @@ static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs)
if
(
!
irqstate
)
{
if
(
pinstate
==
S3C2410_GPIO_IRQ
)
DBG
(
"Leaving IRQ %d (pin %d) enabled
\n
"
,
irq
,
pin
);
S3C_PM
DBG
(
"Leaving IRQ %d (pin %d) enabled
\n
"
,
irq
,
pin
);
}
else
{
if
(
pinstate
==
S3C2410_GPIO_IRQ
)
{
DBG
(
"Disabling IRQ %d (pin %d)
\n
"
,
irq
,
pin
);
S3C_PM
DBG
(
"Disabling IRQ %d (pin %d)
\n
"
,
irq
,
pin
);
s3c2410_gpio_cfgpin
(
pin
,
S3C2410_GPIO_INPUT
);
}
}
}
/* s3c
2410
_pm_configure_extint
/* s3c_pm_configure_extint
*
* configure all external interrupt pins
*/
static
void
s3c2410
_pm_configure_extint
(
void
)
void
s3c
_pm_configure_extint
(
void
)
{
int
pin
;
...
...
@@ -480,11 +157,11 @@ static void s3c2410_pm_configure_extint(void)
*/
for
(
pin
=
S3C2410_GPF0
;
pin
<=
S3C2410_GPF7
;
pin
++
)
{
s3c
2410
_pm_check_resume_pin
(
pin
,
pin
-
S3C2410_GPF0
);
s3c_pm_check_resume_pin
(
pin
,
pin
-
S3C2410_GPF0
);
}
for
(
pin
=
S3C2410_GPG0
;
pin
<=
S3C2410_GPG7
;
pin
++
)
{
s3c
2410
_pm_check_resume_pin
(
pin
,
(
pin
-
S3C2410_GPG0
)
+
8
);
s3c_pm_check_resume_pin
(
pin
,
(
pin
-
S3C2410_GPG0
)
+
8
);
}
}
...
...
@@ -494,12 +171,12 @@ static void s3c2410_pm_configure_extint(void)
#define OFFS_DAT (S3C2410_GPADAT - S3C2410_GPACON)
#define OFFS_UP (S3C2410_GPBUP - S3C2410_GPBCON)
/* s3c
2410
_pm_save_gpios()
/* s3c_pm_save_gpios()
*
* Save the state of the GPIOs
*/
static
void
s3c2410
_pm_save_gpios
(
void
)
void
s3c
_pm_save_gpios
(
void
)
{
struct
gpio_sleep
*
gps
=
gpio_save
;
unsigned
int
gpio
;
...
...
@@ -538,7 +215,10 @@ static inline int is_out(unsigned long con)
return
con
==
1
;
}
/* s3c2410_pm_restore_gpio()
/**
* s3c2410_pm_restore_gpio() - restore the given GPIO bank
* @index: The number of the GPIO bank being resumed.
* @gps: The sleep confgiuration for the bank.
*
* Restore one of the GPIO banks that was saved during suspend. This is
* not as simple as once thought, due to the possibility of glitches
...
...
@@ -646,8 +326,8 @@ static void s3c2410_pm_restore_gpio(int index, struct gpio_sleep *gps)
__raw_writel
(
gps
->
gpup
,
base
+
OFFS_UP
);
}
DBG
(
"GPIO[%d] CON %08lx => %08lx, DAT %08lx => %08lx
\n
"
,
index
,
old_gpcon
,
gps_gpcon
,
old_gpdat
,
gps_gpdat
);
S3C_PM
DBG
(
"GPIO[%d] CON %08lx => %08lx, DAT %08lx => %08lx
\n
"
,
index
,
old_gpcon
,
gps_gpcon
,
old_gpdat
,
gps_gpdat
);
}
...
...
@@ -656,7 +336,7 @@ static void s3c2410_pm_restore_gpio(int index, struct gpio_sleep *gps)
* Restore the state of the GPIOs
*/
static
void
s3c2410
_pm_restore_gpios
(
void
)
void
s3c
_pm_restore_gpios
(
void
)
{
struct
gpio_sleep
*
gps
=
gpio_save
;
int
gpio
;
...
...
@@ -666,150 +346,15 @@ static void s3c2410_pm_restore_gpios(void)
}
}
void
(
*
pm_cpu_prep
)(
void
);
void
(
*
pm_cpu_sleep
)(
void
);
#define any_allowed(mask, allow) (((mask) & (allow)) != (allow))
/* s3c2410_pm_enter
*
* central control for sleep/resume process
*/
static
int
s3c2410_pm_enter
(
suspend_state_t
state
)
void
s3c_pm_restore_core
(
void
)
{
unsigned
long
regs_save
[
16
];
/* ensure the debug is initialised (if enabled) */
s3c2410_pm_debug_init
();
DBG
(
"s3c2410_pm_enter(%d)
\n
"
,
state
);
if
(
pm_cpu_prep
==
NULL
||
pm_cpu_sleep
==
NULL
)
{
printk
(
KERN_ERR
PFX
"error: no cpu sleep functions set
\n
"
);
return
-
EINVAL
;
}
/* check if we have anything to wake-up with... bad things seem
* to happen if you suspend with no wakeup (system will often
* require a full power-cycle)
*/
if
(
!
any_allowed
(
s3c_irqwake_intmask
,
s3c_irqwake_intallow
)
&&
!
any_allowed
(
s3c_irqwake_eintmask
,
s3c_irqwake_eintallow
))
{
printk
(
KERN_ERR
PFX
"No sources enabled for wake-up!
\n
"
);
printk
(
KERN_ERR
PFX
"Aborting sleep
\n
"
);
return
-
EINVAL
;
}
/* prepare check area if configured */
s3c2410_pm_check_prepare
();
/* store the physical address of the register recovery block */
s3c2410_sleep_save_phys
=
virt_to_phys
(
regs_save
);
DBG
(
"s3c2410_sleep_save_phys=0x%08lx
\n
"
,
s3c2410_sleep_save_phys
);
/* save all necessary core registers not covered by the drivers */
s3c2410_pm_save_gpios
();
s3c2410_pm_do_save
(
misc_save
,
ARRAY_SIZE
(
misc_save
));
s3c2410_pm_do_save
(
core_save
,
ARRAY_SIZE
(
core_save
));
s3c2410_pm_do_save
(
uart_save
,
ARRAY_SIZE
(
uart_save
));
/* set the irq configuration for wake */
s3c2410_pm_configure_extint
();
DBG
(
"sleep: irq wakeup masks: %08lx,%08lx
\n
"
,
s3c_irqwake_intmask
,
s3c_irqwake_eintmask
);
__raw_writel
(
s3c_irqwake_intmask
,
S3C2410_INTMSK
);
__raw_writel
(
s3c_irqwake_eintmask
,
S3C2410_EINTMASK
);
/* ack any outstanding external interrupts before we go to sleep */
__raw_writel
(
__raw_readl
(
S3C2410_EINTPEND
),
S3C2410_EINTPEND
);
__raw_writel
(
__raw_readl
(
S3C2410_INTPND
),
S3C2410_INTPND
);
__raw_writel
(
__raw_readl
(
S3C2410_SRCPND
),
S3C2410_SRCPND
);
/* call cpu specific preparation */
pm_cpu_prep
();
/* flush cache back to ram */
flush_cache_all
();
s3c2410_pm_check_store
();
/* send the cpu to sleep... */
__raw_writel
(
0x00
,
S3C2410_CLKCON
);
/* turn off clocks over sleep */
/* s3c2410_cpu_save will also act as our return point from when
* we resume as it saves its own register state, so use the return
* code to differentiate return from save and return from sleep */
if
(
s3c2410_cpu_save
(
regs_save
)
==
0
)
{
flush_cache_all
();
pm_cpu_sleep
();
}
/* restore the cpu state */
cpu_init
();
/* restore the system state */
s3c2410_pm_do_restore_core
(
core_save
,
ARRAY_SIZE
(
core_save
));
s3c2410_pm_do_restore
(
misc_save
,
ARRAY_SIZE
(
misc_save
));
s3c2410_pm_do_restore
(
uart_save
,
ARRAY_SIZE
(
uart_save
));
s3c2410_pm_restore_gpios
();
s3c2410_pm_debug_init
();
/* check what irq (if any) restored the system */
DBG
(
"post sleep: IRQs 0x%08x, 0x%08x
\n
"
,
__raw_readl
(
S3C2410_SRCPND
),
__raw_readl
(
S3C2410_EINTPEND
));
s3c2410_pm_show_resume_irqs
(
IRQ_EINT0
,
__raw_readl
(
S3C2410_SRCPND
),
s3c_irqwake_intmask
);
s3c2410_pm_show_resume_irqs
(
IRQ_EINT4
-
4
,
__raw_readl
(
S3C2410_EINTPEND
),
s3c_irqwake_eintmask
);
DBG
(
"post sleep, preparing to return
\n
"
);
s3c2410_pm_check_restore
();
/* ok, let's return from sleep */
DBG
(
"S3C2410 PM Resume (post-restore)
\n
"
);
return
0
;
s3c_pm_do_restore_core
(
core_save
,
ARRAY_SIZE
(
core_save
));
s3c_pm_do_restore
(
misc_save
,
ARRAY_SIZE
(
misc_save
));
}
static
struct
platform_suspend_ops
s3c2410_pm_ops
=
{
.
enter
=
s3c2410_pm_enter
,
.
valid
=
suspend_valid_only_mem
,
};
/* s3c2410_pm_init
*
* Attach the power management functions. This should be called
* from the board specific initialisation if the board supports
* it.
*/
int
__init
s3c2410_pm_init
(
void
)
void
s3c_pm_save_core
(
void
)
{
printk
(
"S3C2410 Power Management, (c) 2004 Simtec Electronics
\n
"
);
suspend_set_ops
(
&
s3c2410_pm_ops
);
return
0
;
s3c_pm_do_save
(
misc_save
,
ARRAY_SIZE
(
misc_save
));
s3c_pm_do_save
(
core_save
,
ARRAY_SIZE
(
core_save
));
}
arch/arm/plat-s3c24xx/s3c244x.c
View file @
f5f0e17a
...
...
@@ -145,13 +145,13 @@ static struct sleep_save s3c244x_sleep[] = {
static
int
s3c244x_suspend
(
struct
sys_device
*
dev
,
pm_message_t
state
)
{
s3c
2410
_pm_do_save
(
s3c244x_sleep
,
ARRAY_SIZE
(
s3c244x_sleep
));
s3c_pm_do_save
(
s3c244x_sleep
,
ARRAY_SIZE
(
s3c244x_sleep
));
return
0
;
}
static
int
s3c244x_resume
(
struct
sys_device
*
dev
)
{
s3c
2410
_pm_do_restore
(
s3c244x_sleep
,
ARRAY_SIZE
(
s3c244x_sleep
));
s3c_pm_do_restore
(
s3c244x_sleep
,
ARRAY_SIZE
(
s3c244x_sleep
));
return
0
;
}
...
...
arch/arm/plat-s3c24xx/sleep.S
View file @
f5f0e17a
...
...
@@ -41,25 +41,13 @@
.
text
/
*
s3c2410_cpu_save
*
*
save
enough
of
the
CPU
state
to
allow
us
to
re
-
start
*
pm
.
c
code
.
as
we
store
items
like
the
sp
/
lr
,
we
will
*
end
up
returning
from
this
function
when
the
cpu
resumes
*
so
the
return
value
is
set
to
mark
this
.
*
*
This
arangement
means
we
avoid
having
to
flush
the
cache
*
from
this
code
.
/
*
s3c_cpu_save
*
*
entry
:
*
r0
=
pointer
to
save
block
*
*
exit
:
*
r0
=
0
=>
we
stored
everything
*
1
=>
resumed
from
sleep
*
r0
=
save
address
(
virtual
addr
of
s3c_sleep_save_phys
)
*/
ENTRY
(
s3c
2410
_cpu_save
)
ENTRY
(
s3c_cpu_save
)
stmfd
sp
!,
{
r4
-
r12
,
lr
}
@@
store
co
-
processor
registers
...
...
@@ -71,20 +59,25 @@ ENTRY(s3c2410_cpu_save)
stmia
r0
,
{
r4
-
r13
}
mov
r0
,
#
0
ldmfd
sp
,
{
r4
-
r12
,
pc
}
@@
write
our
state
back
to
RAM
bl
s3c_pm_cb_flushcache
@@
jump
to
final
code
to
send
system
to
sleep
ldr
r0
,
=
pm_cpu_sleep
@@
ldr
pc
,
[
r0
]
ldr
r0
,
[
r0
]
mov
pc
,
r0
@@
return
to
the
caller
,
after
having
the
MMU
@@
turned
on
,
this
restores
the
last
bits
from
the
@@
stack
resume_with_mmu
:
mov
r0
,
#
1
ldmfd
sp
!,
{
r4
-
r12
,
pc
}
.
ltorg
@@
the
next
bits
sit
in
the
.
data
segment
,
even
though
they
@@
happen
to
be
code
...
the
s3c
2410
_sleep_save_phys
needs
to
be
@@
happen
to
be
code
...
the
s3c_sleep_save_phys
needs
to
be
@@
accessed
by
the
resume
code
before
it
can
restore
the
MMU
.
@@
This
means
that
the
variable
has
to
be
close
enough
for
the
@@
code
to
read
it
...
since
the
.
text
segment
needs
to
be
RO
,
...
...
@@ -92,19 +85,19 @@ resume_with_mmu:
.
data
.
global
s3c
2410
_sleep_save_phys
s3c
2410
_sleep_save_phys
:
.
global
s3c_sleep_save_phys
s3c_sleep_save_phys
:
.
word
0
/
*
sleep
magic
,
to
allow
the
bootloader
to
check
for
an
valid
*
image
to
resume
to
.
Must
be
the
first
word
before
the
*
s3c
2410
_cpu_resume
entry
.
*
s3c_cpu_resume
entry
.
*/
.
word
0x2bedf00d
/
*
s3c
2410
_cpu_resume
/
*
s3c_cpu_resume
*
*
resume
code
entry
for
bootloader
to
call
*
...
...
@@ -113,7 +106,7 @@ s3c2410_sleep_save_phys:
*
must
not
write
to
the
code
segment
(
code
is
read
-
only
)
*/
ENTRY
(
s3c
2410
_cpu_resume
)
ENTRY
(
s3c_cpu_resume
)
mov
r0
,
#
PSR_I_BIT
| PSR_F_BIT |
SVC_MODE
msr
cpsr_c
,
r0
...
...
@@ -145,7 +138,7 @@ ENTRY(s3c2410_cpu_resume)
mcr
p15
,
0
,
r1
,
c8
,
c7
,
0
@@
invalidate
I
&
D
TLBs
mcr
p15
,
0
,
r1
,
c7
,
c7
,
0
@@
invalidate
I
&
D
caches
ldr
r0
,
s3c
2410_sleep_save_phys
@
address
of
restore
block
ldr
r0
,
s3c
_sleep_save_phys
@
address
of
restore
block
ldmia
r0
,
{
r4
-
r13
}
mcr
p15
,
0
,
r4
,
c13
,
c0
,
0
@
PID
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment