[RFC PATCH 2/2] ARM: CSR: add PM sleep entry for SiRFprimaII

Barry Song 21cnbao at gmail.com
Mon Aug 15 03:54:58 EDT 2011


Hi Russell,
Thanks!

2011/8/14 Russell King - ARM Linux <linux at arm.linux.org.uk>:
> On Thu, Aug 04, 2011 at 07:54:48PM -0700, Barry Song wrote:
>> +ENTRY(sirfsoc_sleep)
>> +sirfsoc_sleep:
>
> POINT A
>
>> +     stmdb  sp!, {r0-r12, lr}                @ Push SVC state onto our stack
>> +
>> +     mrc     p15, 0, r2, c1, c0, 1           @ cp15 c1 auxiliary Control register
>> +     mrc     p15, 0, r3, c1, c0, 2           @ cp15 c1 coprocessor access control register
>> +     mrc     p15, 0, r4, c2, c0, 0           @ cp15 c2_r0 translation table base resigter 0
>> +     mrc     p15, 0, r5, c2, c0, 1           @ cp15 c2_r1 translation table base resigter 1
>> +
>> +     mrc     p15, 0, r6, c2, c0, 2           @ cp15 c2_r2 translation table base control resigter
>> +
>> +     mrc     p15, 0, r7, c3, c0, 0           @ load r2 with domain access control.
>> +     mrc     p15, 0, r8, c1, c0, 0           @ MMU Control
>> +     mrc     p15, 0, r9, c10,c2, 0           @ cp15 PRRR register
>> +     mrc     p15, 0, r10, c10,c2, 1          @ cp15 NMRR register
>> +     mov     r11, sp
>> +     ldr     r0, =save_context
>> +     add     r0, r0, #124
>> +     stmdb   r0!, {r2-r11}                   @ Save CP15 and the SP to stack
>> +
>> +     mov     r1, #FIQ_MODE|PSR_I_BIT|PSR_F_BIT       @ Enter FIQ mode, no interrupts
>> +     msr     cpsr, r1
>> +     mrs     r2, spsr
>> +     stmdb   r0!, {r2, r8-r12, sp, lr}       @ store the FIQ Mode Registers
>> +
>> +     mov     r1, #ABT_MODE|PSR_I_BIT|PSR_F_BIT       @ Enter ABT mode, no interrupts
>> +     msr     cpsr, r1
>> +     mrs     r2, spsr
>> +     stmdb   r0!, {r2, sp, lr}               @ store the ABT Mode Registers
>> +
>> +     mov     r1, #IRQ_MODE|PSR_I_BIT|PSR_F_BIT       @ Enter IRQ mode, no interrupts
>> +     msr     cpsr, r1
>> +     mrs     r2, spsr
>> +     stmdb   r0!, {r2, sp, lr}               @ store the IRQ Mode Registers
>> +
>> +     mov     r1, #UND_MODE|PSR_I_BIT|PSR_F_BIT       @ Enter UND mode, no interrupts
>> +     msr     cpsr, r1
>> +     mrs     r2, spsr
>> +     stmdb   r0!, {r2, sp, lr}               @ store the UND Mode Registers
>> +
>> +     mov     r1, #SYSTEM_MODE|PSR_I_BIT|PSR_F_BIT    @ Enter SYS mode, no interrupts
>> +     msr     cpsr, r1
>> +     mrs     r2, spsr
>> +     stmdb   r0!, {r2, sp, lr}               @ store the SYS Mode Registers
>> +
>> +     mov     r1, #SVC_MODE|PSR_I_BIT|PSR_F_BIT @ Enter SVC mode, no interrupts
>> +     msr     cpsr, r1
>> +
>> +     ldr     r1, =save_context                  @ Get address of label save_sp in r1
>> +     sub     r0, r0, r1
>> +     str     r0, [r1]                      @ Store context offset to label memory
>
> POINT B
>
>> +
>> +     bl      sirfsoc_pre_suspend_power_off
>> +     cmp     r0,#0
>> +     bne     sirfsoc_sleep_exit
>> +
>
> POINT C
>
>> +     @ r5:   mem controller
>> +     ldr     r0, =sirfsoc_memc_base
>> +     ldr     r5, [r0]
>> +     @ r7:   rtc iobrg controller
>> +     ldr     r0, =sirfsoc_rtciobrg_base
>> +     ldr     r7, [r0]
>> +
>> +     @ Clean and invalidate all caches
>> +     bl v7_flush_kern_cache_all
>
> POINT D
>
>> +
>> +#ifdef CONFIG_CACHE_L2X0
>> +     ldr     r1, =sirfsoc_l2x_base
>> +     ldr     r0, [r1]
>> +     ldr     r1, =L2X0_CLEAN_INV_WAY
>> +     mov     r2, #0xff
>> +     str     r2, [r0,r1]
>> +     mov     r2, #0
>> +1:
>> +     ldr     r3, [r0,r1]
>> +     cmp     r2,r3
>> +     bne     1b
>> +     ldr     r1, =L2X0_CACHE_SYNC
>> +     mov     r2, #0
>> +     str     r2, [r0,r1]
>> +
>> +     ldr     r1, =L2X0_CTRL
>> +     mov     r2, #0
>> +     str     r2, [r0,r1]
>> +#endif
>> +
>> +     @ Read the power control register and set the
>> +     @ sleep force bit.
>> +     ldr     r0, =SIRFSOC_PWRC_PDN_CTRL
>> +     bl      __sirfsoc_rtc_iobrg_readl
>> +     orr     r0,r0,#SIRFSOC_PWR_SLEEPFORCE
>> +     ldr     r1, =SIRFSOC_PWRC_PDN_CTRL
>> +     bl      sirfsoc_rtc_iobrg_pre_writel
>> +     mov     r1, #0x1
>> +
>> +     @ The following code is arranged in such a way
>> +     @ that the code to be run after memory is put
>> +     @ into self refresh fits in a cache line (32 bytes).
>> +     @ This is done to make sure the code runs from
>> +     @ cache after memory is put into self refresh.
>> +
>> +     @ read the MEM ctl register and set the self
>> +     @ refresh bit
>> +
>> +     ldr     r2, [r5, #DENALI_CTL_22_OFF]
>> +     orr     r2, r2, #0x1
>> +
>> +     @ Following code has to run from cache since
>> +     @ the RAM is going to self refresh mode
>> +     .align 5
>> +     str     r2, [r5, #DENALI_CTL_22_OFF]
>> +
>> +1:
>> +     ldr     r4, [r5, #DENALI_CTL_112_OFF]
>> +     tst     r4, #0x1
>> +     bne     1b
>> +
>> +     @ write SLEEPFORCE through rtc iobridge
>> +
>> +     str     r1, [r7]
>> +     @ wait rtc io bridge sync
>> +1:
>> +     ldr     r3, [r7]
>> +     tst     r3, #0x01
>> +     bne     1b
>> +     b .
>> +
>> +     @ bootloader will jump here on wakeup
>> +
>> +     .align 5
>> +.globl sirfsoc_wakeup
>> +sirfsoc_wakeup:
>> +
>
> POINT E
>
>> +     mov r4, #0
>> +        mcr p15,0,r4,c8,c7,0            @invalid all unified tlb
>> +        mcr p15,0,r4,c8,c6,0            @invalid all data tlb
>> +        mcr p15,0,r4,c8,c5,0            @invalid all instruction tlb
>> +        mcr p15,0,r4,c7,c5,4            @flush prefetch buffer
>> +        mcr p15,0,r4,c7,c10,4           @Drain write buffer
>> +     mcr p15,0,r4,c7,c5,0            @invalid instruction cache
>> +
>> +     mov     r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
>> +     msr     cpsr, r0                        @ set SVC, irqs off
>> +
>> +     @ Get save_context phys address
>> +     ldr     r1, =save_context
>> +     ldr     r3, =(.+12)
>> +     sub     r3, r3, pc
>> +     sub     r1, r1, r3
>> +     ldr     r0, [r1]
>> +
>> +     add     r0, r0, r1
>> +
>> +     mov     r1, #SYSTEM_MODE|PSR_I_BIT|PSR_F_BIT    @ Enter SYS mode, no interrupts
>> +     msr     cpsr, r1
>> +     ldmfd   r0!, {r2, sp, lr}               @ store the SYS Mode Registers
>> +     msr     spsr, r2
>> +
>> +     mov     r1, #UND_MODE|PSR_I_BIT|PSR_F_BIT       @ Enter UND mode, no interrupts
>> +     msr     cpsr, r1
>> +     ldmfd   r0!, {r2, sp, lr}               @ store the UND Mode Registers
>> +     msr     spsr, r2
>> +
>> +     mov     r1, #IRQ_MODE|PSR_I_BIT|PSR_F_BIT       @ Enter IRQ mode, no interrupts
>> +     msr     cpsr, r1
>> +     ldmfd   r0!, {r2, sp, lr}               @ store the IRQ Mode Registers
>> +     msr     spsr, r2
>> +
>> +     mov     r1, #ABT_MODE|PSR_I_BIT|PSR_F_BIT       @ Enter ABT mode, no interrupts
>> +     msr     cpsr, r1
>> +     ldmfd   r0!, {r2, sp, lr}               @ store the ABT Mode Registers
>> +     msr     spsr, r2
>> +
>> +     mov     r1, #FIQ_MODE|PSR_I_BIT|PSR_F_BIT       @ Enter FIQ mode, no interrupts
>> +     msr     cpsr, r1
>> +     ldmfd   r0!, {r2, r8-r12,sp, lr}        @ store the FIQ Mode Registers
>> +     msr     spsr, r2
>> +
>> +     mov     r1, #SVC_MODE|PSR_I_BIT|PSR_F_BIT       @ Enter SVC mode, no interrupts
>> +     msr     cpsr, r1
>> +
>> +     ldr     r1, =sirfsoc_sleep_exit         @ its absolute virtual address
>> +     ldmfd   r0, {r2 - r10, sp}              @ CP regs + virt stack ptr
>> +
>> +     mcr     p15, 0, r7, c3, c0, 0           @ load r2 with domain access control.
>> +     mcr     p15, 0, r6, c2, c0, 2           @ cp15 c2_r2 translation table base control resigter
>> +     mcr     p15, 0, r4, c2, c0, 0           @ cp15 c2_r0 translation table base resigter 0
>> +     mcr     p15, 0, r5, c2, c0, 1           @ cp15 c2_r1 translation table base resigter 1
>> +
>> +     mcr     p15, 0, r3, c1, c0, 2           @ cp15 c1 coprocessor access control register
>> +     mcr     p15, 0, r2, c1, c0, 1           @ cp15 c1 auxiliary Control register
>> +     mcr     p15, 0, r10, c10,c2, 1          @ cp15 NMRR register
>> +     mcr     p15, 0, r9, C10,c2, 0           @ cp15 PRRR register
>> +     b       resume_turn_on_mmu              @ cache align execution
>> +
>> +     .align 5
>> +resume_turn_on_mmu:
>> +     mcr     p15, 0, r8, c1, c0, 0           @ MMU Control
>> +     nop
>> +     mov     pc, r1                          @ jump to virtual addr
>> +     nop
>> +     nop
>> +     nop
>> +
>> +sirfsoc_sleep_exit:
>> +     ldmfd   sp!, {r0 - r12, pc}             @ return to caller
>> +     /* back to caller of sleep */
>> +     nop
>> +     nop
>> +     nop
>> +@    .data
>> +     .align 5
>> +save_context:
>> +     .space 128,0
>> +
>
> POINT F
>
> NAK, at least until you look at the generic CPU suspend support in
> mainline kernels.  At least until you look at what actually needs to
> be saved.  At least until you do some investigation into what is
> actually required rather than simply believing silly statements in
> chip manuals which says you have to save the entire planet.

Sorry, my fault. i simply picked these lines which have been verified
to be working in local old 2.6.38.8 kernel and really didn't think and
refine more carefully.
in deep sleep mode, SiRFprimaII will powerdown CPU core. due to this,
i just ignored to delete the codes saving registers of all kinds of
CPU modes. but it is not the real situation in kernel. For example,
IRQ mode used the stack of corrupted thread, and kernel was not in
interrupt while going to pm_ops->enter(), then it is unnecessary to
enter IRQ and save sp of IRQ:
        mov     r1, #IRQ_MODE|PSR_I_BIT|PSR_F_BIT       @ Enter IRQ
mode, no interrupts
        msr     cpsr, r1
        mrs     r2, spsr
        stmdb   r0!, {r2, sp, lr}               @ store the IRQ Mode Registers

For CP15 saving, we should be able to get into cpu_suspend -> cpu_v7_do_suspend.

>
> I assert you can get rid of all code between points A to B, C to D,
> E to F using the generic CPU suspend support, which is most of your
> code.

Ok. agree. then the work flow for SiRFprimaII suspend can be:
pm.enter()->
    sirfsoc_cpu_sleep(v:p offset)
    1. save registers on stack
    2. load sirfsoc_cpu_resume to r3
    3. bl cpu_suspend
    4. make sdram self-refresh
    5. write force DEEPSLEEP by rtciobrg


One issue is L2 cache. we actually shutdown the L2 and re-initilized
L2 again after resuming. that required l2x0_init() to be not in __init
section. i remember Colin Cross has sent a patch about that before.
"[PATCH] ARM: mm: cache-l2x0: Add support for re-enabling l2x0"


Thanks
Barry



More information about the linux-arm-kernel mailing list