[RFC PATCH 2/2] ARM: CSR: add PM sleep entry for SiRFprimaII
Russell King - ARM Linux
linux at arm.linux.org.uk
Sun Aug 14 03:59:27 EDT 2011
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.
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.
More information about the linux-arm-kernel
mailing list