linux-kernel-test/arch/blackfin/include/asm/context.S
Sonic Zhang c7e48e1e3e bfin: pm: add deepsleep for bf60x
Add add deepsleep for bf60x.
1. Call DMC init functions to enter and exit DDR self refresh mode.
2. Wait till CGU PLL is locked after wake up and exit DDR self refresh mode.
3. Make asessembly function enter_deepsleep comply with C funtion ABI in
order to call other C functions.
4. Switch kernel stack by register EX_SCRATCH_REG.

Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
Signed-off-by: Bob Liu <lliubbo@gmail.com>
2012-07-24 13:39:49 +08:00

408 lines
5.9 KiB
ArmAsm

/*
* Copyright 2007-2009 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
/*
* NOTE! The single-stepping code assumes that all interrupt handlers
* start by saving SYSCFG on the stack with their first instruction.
*/
/*
* Code to save processor context.
* We even save the register which are preserved by a function call
* - r4, r5, r6, r7, p3, p4, p5
*/
.macro save_context_with_interrupts
[--sp] = SYSCFG;
[--sp] = P0; /*orig_p0*/
[--sp] = R0; /*orig_r0*/
[--sp] = ( R7:0, P5:0 );
[--sp] = fp;
[--sp] = usp;
[--sp] = i0;
[--sp] = i1;
[--sp] = i2;
[--sp] = i3;
[--sp] = m0;
[--sp] = m1;
[--sp] = m2;
[--sp] = m3;
[--sp] = l0;
[--sp] = l1;
[--sp] = l2;
[--sp] = l3;
[--sp] = b0;
[--sp] = b1;
[--sp] = b2;
[--sp] = b3;
[--sp] = a0.x;
[--sp] = a0.w;
[--sp] = a1.x;
[--sp] = a1.w;
[--sp] = LC0;
[--sp] = LC1;
[--sp] = LT0;
[--sp] = LT1;
[--sp] = LB0;
[--sp] = LB1;
[--sp] = ASTAT;
[--sp] = r0; /* Skip reserved */
[--sp] = RETS;
r0 = RETI;
[--sp] = r0;
[--sp] = RETX;
[--sp] = RETN;
[--sp] = RETE;
[--sp] = SEQSTAT;
[--sp] = r0; /* Skip IPEND as well. */
/* Switch to other method of keeping interrupts disabled. */
#ifdef CONFIG_DEBUG_HWERR
r0 = 0x3f;
sti r0;
#else
cli r0;
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
sp += -12;
call _trace_hardirqs_off;
sp += 12;
#endif
[--sp] = RETI; /*orig_pc*/
/* Clear all L registers. */
r0 = 0 (x);
l0 = r0;
l1 = r0;
l2 = r0;
l3 = r0;
.endm
.macro save_context_syscall
[--sp] = SYSCFG;
[--sp] = P0; /*orig_p0*/
[--sp] = R0; /*orig_r0*/
[--sp] = ( R7:0, P5:0 );
[--sp] = fp;
[--sp] = usp;
[--sp] = i0;
[--sp] = i1;
[--sp] = i2;
[--sp] = i3;
[--sp] = m0;
[--sp] = m1;
[--sp] = m2;
[--sp] = m3;
[--sp] = l0;
[--sp] = l1;
[--sp] = l2;
[--sp] = l3;
[--sp] = b0;
[--sp] = b1;
[--sp] = b2;
[--sp] = b3;
[--sp] = a0.x;
[--sp] = a0.w;
[--sp] = a1.x;
[--sp] = a1.w;
[--sp] = LC0;
[--sp] = LC1;
[--sp] = LT0;
[--sp] = LT1;
[--sp] = LB0;
[--sp] = LB1;
[--sp] = ASTAT;
[--sp] = r0; /* Skip reserved */
[--sp] = RETS;
r0 = RETI;
[--sp] = r0;
[--sp] = RETX;
[--sp] = RETN;
[--sp] = RETE;
[--sp] = SEQSTAT;
[--sp] = r0; /* Skip IPEND as well. */
[--sp] = RETI; /*orig_pc*/
/* Clear all L registers. */
r0 = 0 (x);
l0 = r0;
l1 = r0;
l2 = r0;
l3 = r0;
.endm
.macro save_context_no_interrupts
[--sp] = SYSCFG;
[--sp] = P0; /* orig_p0 */
[--sp] = R0; /* orig_r0 */
[--sp] = ( R7:0, P5:0 );
[--sp] = fp;
[--sp] = usp;
[--sp] = i0;
[--sp] = i1;
[--sp] = i2;
[--sp] = i3;
[--sp] = m0;
[--sp] = m1;
[--sp] = m2;
[--sp] = m3;
[--sp] = l0;
[--sp] = l1;
[--sp] = l2;
[--sp] = l3;
[--sp] = b0;
[--sp] = b1;
[--sp] = b2;
[--sp] = b3;
[--sp] = a0.x;
[--sp] = a0.w;
[--sp] = a1.x;
[--sp] = a1.w;
[--sp] = LC0;
[--sp] = LC1;
[--sp] = LT0;
[--sp] = LT1;
[--sp] = LB0;
[--sp] = LB1;
[--sp] = ASTAT;
#ifdef CONFIG_KGDB
fp = 0(Z);
r1 = sp;
r1 += 60;
r1 += 60;
r1 += 60;
[--sp] = r1;
#else
[--sp] = r0; /* Skip reserved */
#endif
[--sp] = RETS;
r0 = RETI;
[--sp] = r0;
[--sp] = RETX;
[--sp] = RETN;
[--sp] = RETE;
[--sp] = SEQSTAT;
#ifdef CONFIG_DEBUG_KERNEL
p1.l = lo(IPEND);
p1.h = hi(IPEND);
r1 = [p1];
[--sp] = r1;
#else
[--sp] = r0; /* Skip IPEND as well. */
#endif
[--sp] = r0; /*orig_pc*/
/* Clear all L registers. */
r0 = 0 (x);
l0 = r0;
l1 = r0;
l2 = r0;
l3 = r0;
.endm
.macro restore_context_no_interrupts
sp += 4; /* Skip orig_pc */
sp += 4; /* Skip IPEND */
SEQSTAT = [sp++];
RETE = [sp++];
RETN = [sp++];
RETX = [sp++];
r0 = [sp++];
RETI = r0; /* Restore RETI indirectly when in exception */
RETS = [sp++];
sp += 4; /* Skip Reserved */
ASTAT = [sp++];
LB1 = [sp++];
LB0 = [sp++];
LT1 = [sp++];
LT0 = [sp++];
LC1 = [sp++];
LC0 = [sp++];
a1.w = [sp++];
a1.x = [sp++];
a0.w = [sp++];
a0.x = [sp++];
b3 = [sp++];
b2 = [sp++];
b1 = [sp++];
b0 = [sp++];
l3 = [sp++];
l2 = [sp++];
l1 = [sp++];
l0 = [sp++];
m3 = [sp++];
m2 = [sp++];
m1 = [sp++];
m0 = [sp++];
i3 = [sp++];
i2 = [sp++];
i1 = [sp++];
i0 = [sp++];
sp += 4;
fp = [sp++];
( R7 : 0, P5 : 0) = [ SP ++ ];
sp += 8; /* Skip orig_r0/orig_p0 */
SYSCFG = [sp++];
.endm
.macro restore_context_with_interrupts
sp += 4; /* Skip orig_pc */
sp += 4; /* Skip IPEND */
SEQSTAT = [sp++];
RETE = [sp++];
RETN = [sp++];
RETX = [sp++];
RETI = [sp++];
#ifdef CONFIG_TRACE_IRQFLAGS
sp += -12;
call _trace_hardirqs_on;
sp += 12;
#endif
RETS = [sp++];
#ifdef CONFIG_SMP
GET_PDA(p0, r0);
r0 = [p0 + PDA_IRQFLAGS];
#else
p0.h = _bfin_irq_flags;
p0.l = _bfin_irq_flags;
r0 = [p0];
#endif
sti r0;
sp += 4; /* Skip Reserved */
ASTAT = [sp++];
LB1 = [sp++];
LB0 = [sp++];
LT1 = [sp++];
LT0 = [sp++];
LC1 = [sp++];
LC0 = [sp++];
a1.w = [sp++];
a1.x = [sp++];
a0.w = [sp++];
a0.x = [sp++];
b3 = [sp++];
b2 = [sp++];
b1 = [sp++];
b0 = [sp++];
l3 = [sp++];
l2 = [sp++];
l1 = [sp++];
l0 = [sp++];
m3 = [sp++];
m2 = [sp++];
m1 = [sp++];
m0 = [sp++];
i3 = [sp++];
i2 = [sp++];
i1 = [sp++];
i0 = [sp++];
sp += 4;
fp = [sp++];
( R7 : 0, P5 : 0) = [ SP ++ ];
sp += 8; /* Skip orig_r0/orig_p0 */
csync;
SYSCFG = [sp++];
csync;
.endm
.macro save_context_cplb
[--sp] = (R7:0, P5:0);
[--sp] = fp;
[--sp] = a0.x;
[--sp] = a0.w;
[--sp] = a1.x;
[--sp] = a1.w;
[--sp] = LC0;
[--sp] = LC1;
[--sp] = LT0;
[--sp] = LT1;
[--sp] = LB0;
[--sp] = LB1;
[--sp] = RETS;
.endm
.macro restore_context_cplb
RETS = [sp++];
LB1 = [sp++];
LB0 = [sp++];
LT1 = [sp++];
LT0 = [sp++];
LC1 = [sp++];
LC0 = [sp++];
a1.w = [sp++];
a1.x = [sp++];
a0.w = [sp++];
a0.x = [sp++];
fp = [sp++];
(R7:0, P5:0) = [SP++];
.endm
.macro pseudo_long_call func:req, scratch:req
#ifdef CONFIG_ROMKERNEL
\scratch\().l = \func;
\scratch\().h = \func;
call (\scratch);
#else
call \func;
#endif
.endm
#if defined(CONFIG_BFIN_SCRATCH_REG_RETN)
# define EX_SCRATCH_REG RETN
#elif defined(CONFIG_BFIN_SCRATCH_REG_RETE)
# define EX_SCRATCH_REG RETE
#else
# define EX_SCRATCH_REG CYCLES
#endif