2005-04-16 15:20:36 -07:00
/*
* SA1100 Power Management Routines
*
* Copyright ( c ) 2001 Cliff Brake < cbrake @ accelent . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License .
*
* History :
*
* 2001 - 02 - 06 : Cliff Brake Initial code
*
* 2001 - 02 - 25 : Sukjae Cho < sjcho @ east . isi . edu > &
* Chester Kuo < chester @ linux . org . tw >
* Save more value for the resume function ! Support
* Bitsy / Assabet / Freebird board
*
2009-09-14 03:25:28 -04:00
* 2001 - 08 - 29 : Nicolas Pitre < nico @ fluxnic . net >
2005-04-16 15:20:36 -07:00
* Cleaned up , pushed platform dependent stuff
* in the platform specific files .
*
* 2002 - 05 - 27 : Nicolas Pitre Killed sleep . h and the kmalloced save array .
* Storage is local on the stack now .
*/
# include <linux/init.h>
2012-06-06 11:42:36 +01:00
# include <linux/io.h>
2005-04-16 15:20:36 -07:00
# include <linux/suspend.h>
# include <linux/errno.h>
# include <linux/time.h>
2008-08-05 16:14:15 +01:00
# include <mach/hardware.h>
ARM: mm: Make virt_to_pfn() a static inline
Making virt_to_pfn() a static inline taking a strongly typed
(const void *) makes the contract of a passing a pointer of that
type to the function explicit and exposes any misuse of the
macro virt_to_pfn() acting polymorphic and accepting many types
such as (void *), (unitptr_t) or (unsigned long) as arguments
without warnings.
Doing this is a bit intrusive: virt_to_pfn() requires
PHYS_PFN_OFFSET and PAGE_SHIFT to be defined, and this is defined in
<asm/page.h>, so this must be included *before* <asm/memory.h>.
The use of macros were obscuring the unclear inclusion order here,
as the macros would eventually be resolved, but a static inline
like this cannot be compiled with unresolved macros.
The naive solution to include <asm/page.h> at the top of
<asm/memory.h> does not work, because <asm/memory.h> sometimes
includes <asm/page.h> at the end of itself, which would create a
confusing inclusion loop. So instead, take the approach to always
unconditionally include <asm/page.h> at the end of <asm/memory.h>
arch/arm uses <asm/memory.h> explicitly in a lot of places,
however it turns out that if we just unconditionally include
<asm/memory.h> into <asm/page.h> and switch all inclusions of
<asm/memory.h> to <asm/page.h> instead, we enforce the right
order and <asm/memory.h> will always have access to the
definitions.
Put an inclusion guard in place making it impossible to include
<asm/memory.h> explicitly.
Link: https://lore.kernel.org/linux-mm/20220701160004.2ffff4e5ab59a55499f4c736@linux-foundation.org/
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2022-06-02 10:18:32 +02:00
# include <asm/page.h>
2011-06-22 17:41:48 +01:00
# include <asm/suspend.h>
2005-04-16 15:20:36 -07:00
# include <asm/mach/time.h>
2023-05-16 17:31:07 +02:00
# include "generic.h"
2011-07-02 09:54:01 +01:00
extern int sa1100_finish_suspend ( unsigned long ) ;
2005-04-16 15:20:36 -07:00
# define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
# define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
/*
* List of global SA11x0 peripheral registers to preserve .
* More ones like CP and general purpose register values are preserved
* on the stack and then the stack pointer is stored last in sleep . S .
*/
2008-05-02 21:17:06 +01:00
enum { SLEEP_SAVE_GPDR , SLEEP_SAVE_GAFR ,
2005-04-16 15:20:36 -07:00
SLEEP_SAVE_PPDR , SLEEP_SAVE_PPSR , SLEEP_SAVE_PPAR , SLEEP_SAVE_PSDR ,
SLEEP_SAVE_Ser1SDCR0 ,
2008-05-02 21:17:06 +01:00
SLEEP_SAVE_COUNT
2005-04-16 15:20:36 -07:00
} ;
static int sa11x0_pm_enter ( suspend_state_t state )
{
2008-05-02 21:17:06 +01:00
unsigned long gpio , sleep_save [ SLEEP_SAVE_COUNT ] ;
2005-04-16 15:20:36 -07:00
gpio = GPLR ;
/* save vital registers */
SAVE ( GPDR ) ;
SAVE ( GAFR ) ;
SAVE ( PPDR ) ;
SAVE ( PPSR ) ;
SAVE ( PPAR ) ;
SAVE ( PSDR ) ;
SAVE ( Ser1SDCR0 ) ;
/* Clear previous reset status */
RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR ;
/* set resume return address */
2017-01-15 03:59:29 +01:00
PSPR = __pa_symbol ( cpu_resume ) ;
2005-04-16 15:20:36 -07:00
/* go zzz */
2011-06-22 17:41:48 +01:00
cpu_suspend ( 0 , sa1100_finish_suspend ) ;
2005-04-16 15:20:36 -07:00
/*
* Ensure not to come back here if it wasn ' t intended
*/
2015-01-15 03:06:22 +01:00
RCSR = RCSR_SMR ;
2005-04-16 15:20:36 -07:00
PSPR = 0 ;
/*
* Ensure interrupt sources are disabled ; we will re - init
* the interrupt subsystem via the device manager .
*/
ICLR = 0 ;
ICCR = 1 ;
ICMR = 0 ;
/* restore registers */
RESTORE ( GPDR ) ;
RESTORE ( GAFR ) ;
RESTORE ( PPDR ) ;
RESTORE ( PPSR ) ;
RESTORE ( PPAR ) ;
RESTORE ( PSDR ) ;
RESTORE ( Ser1SDCR0 ) ;
GPSR = gpio ;
GPCR = ~ gpio ;
/*
* Clear the peripheral sleep - hold bit .
*/
PSSR = PSSR_PH ;
return 0 ;
}
2010-11-16 14:14:02 +01:00
static const struct platform_suspend_ops sa11x0_pm_ops = {
2005-04-16 15:20:36 -07:00
. enter = sa11x0_pm_enter ,
2007-10-18 03:04:40 -07:00
. valid = suspend_valid_only_mem ,
2005-04-16 15:20:36 -07:00
} ;
2012-04-26 21:22:45 +08:00
int __init sa11x0_pm_init ( void )
2005-04-16 15:20:36 -07:00
{
2007-10-18 03:04:40 -07:00
suspend_set_ops ( & sa11x0_pm_ops ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}