OMAP3: rework of the ASM sleep code execution paths
- Reworked and simplified the execution paths for better readability and to avoid duplication of code, - Added comments on the entry and exit points and the interaction with the ROM code for OFF mode restore, - Reworked the existing comments for better readability. Tested on N900 and Beagleboard with full RET and OFF modes, using cpuidle and suspend. Signed-off-by: Jean Pihet <j-pihet@ti.com> Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Tested-by: Nishanth Menon <nm@ti.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
This commit is contained in:
Родитель
1e81bc015a
Коммит
f7dfe3d8a9
|
@ -239,7 +239,14 @@ void omap3_save_scratchpad_contents(void)
|
|||
struct omap3_scratchpad_prcm_block prcm_block_contents;
|
||||
struct omap3_scratchpad_sdrc_block sdrc_block_contents;
|
||||
|
||||
/* Populate the Scratchpad contents */
|
||||
/*
|
||||
* Populate the Scratchpad contents
|
||||
*
|
||||
* The "get_*restore_pointer" functions are used to provide a
|
||||
* physical restore address where the ROM code jumps while waking
|
||||
* up from MPU OFF/OSWR state.
|
||||
* The restore pointer is stored into the scratchpad.
|
||||
*/
|
||||
scratchpad_contents.boot_config_ptr = 0x0;
|
||||
if (cpu_is_omap3630())
|
||||
scratchpad_contents.public_restore_ptr =
|
||||
|
|
|
@ -69,6 +69,13 @@
|
|||
|
||||
/*
|
||||
* API functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* The "get_*restore_pointer" functions are used to provide a
|
||||
* physical restore address where the ROM code jumps while waking
|
||||
* up from MPU OFF/OSWR state.
|
||||
* The restore pointer is stored into the scratchpad.
|
||||
*/
|
||||
|
||||
.text
|
||||
|
@ -102,7 +109,7 @@ ENTRY(get_es3_restore_pointer_sz)
|
|||
/*
|
||||
* L2 cache needs to be toggled for stable OFF mode functionality on 3630.
|
||||
* This function sets up a flag that will allow for this toggling to take
|
||||
* place on 3630. Hopefully some version in the future maynot need this
|
||||
* place on 3630. Hopefully some version in the future may not need this.
|
||||
*/
|
||||
ENTRY(enable_omap3630_toggle_l2_on_restore)
|
||||
stmfd sp!, {lr} @ save registers on stack
|
||||
|
@ -143,35 +150,163 @@ api_params:
|
|||
ENTRY(save_secure_ram_context_sz)
|
||||
.word . - save_secure_ram_context
|
||||
|
||||
/*
|
||||
* ======================
|
||||
* == Idle entry point ==
|
||||
* ======================
|
||||
*/
|
||||
|
||||
/*
|
||||
* Forces OMAP into idle state
|
||||
*
|
||||
* omap34xx_suspend() - This bit of code just executes the WFI
|
||||
* for normal idles.
|
||||
* omap34xx_cpu_suspend() - This bit of code saves the CPU context if needed
|
||||
* and executes the WFI instruction. Calling WFI effectively changes the
|
||||
* power domains states to the desired target power states.
|
||||
*
|
||||
* Note: This code get's copied to internal SRAM at boot. When the OMAP
|
||||
* wakes up it continues execution at the point it went to sleep.
|
||||
*
|
||||
* Notes:
|
||||
* - this code gets copied to internal SRAM at boot. The execution pointer
|
||||
* in SRAM is _omap_sram_idle.
|
||||
* - when the OMAP wakes up it continues at different execution points
|
||||
* depending on the low power mode (non-OFF vs OFF modes),
|
||||
* cf. 'Resume path for xxx mode' comments.
|
||||
*/
|
||||
ENTRY(omap34xx_cpu_suspend)
|
||||
stmfd sp!, {r0-r12, lr} @ save registers on stack
|
||||
|
||||
/* r0 contains restore pointer in sdram */
|
||||
/* r1 contains information about saving context */
|
||||
ldr r4, sdrc_power @ read the SDRC_POWER register
|
||||
ldr r5, [r4] @ read the contents of SDRC_POWER
|
||||
orr r5, r5, #0x40 @ enable self refresh on idle req
|
||||
str r5, [r4] @ write back to SDRC_POWER register
|
||||
/*
|
||||
* r0 contains restore pointer in sdram
|
||||
* r1 contains information about saving context:
|
||||
* 0 - No context lost
|
||||
* 1 - Only L1 and logic lost
|
||||
* 2 - Only L2 lost
|
||||
* 3 - Both L1 and L2 lost
|
||||
*/
|
||||
|
||||
/* Directly jump to WFI is the context save is not required */
|
||||
cmp r1, #0x0
|
||||
/* If context save is required, do that and execute wfi */
|
||||
bne save_context_wfi
|
||||
beq omap3_do_wfi
|
||||
|
||||
/* Otherwise fall through to the save context code */
|
||||
save_context_wfi:
|
||||
mov r8, r0 @ Store SDRAM address in r8
|
||||
mrc p15, 0, r5, c1, c0, 1 @ Read Auxiliary Control Register
|
||||
mov r4, #0x1 @ Number of parameters for restore call
|
||||
stmia r8!, {r4-r5} @ Push parameters for restore call
|
||||
mrc p15, 1, r5, c9, c0, 2 @ Read L2 AUX ctrl register
|
||||
stmia r8!, {r4-r5} @ Push parameters for restore call
|
||||
|
||||
/* Check what that target sleep state is from r1 */
|
||||
cmp r1, #0x2 @ Only L2 lost, no need to save context
|
||||
beq clean_caches
|
||||
|
||||
l1_logic_lost:
|
||||
/* Store sp and spsr to SDRAM */
|
||||
mov r4, sp
|
||||
mrs r5, spsr
|
||||
mov r6, lr
|
||||
stmia r8!, {r4-r6}
|
||||
/* Save all ARM registers */
|
||||
/* Coprocessor access control register */
|
||||
mrc p15, 0, r6, c1, c0, 2
|
||||
stmia r8!, {r6}
|
||||
/* TTBR0, TTBR1 and Translation table base control */
|
||||
mrc p15, 0, r4, c2, c0, 0
|
||||
mrc p15, 0, r5, c2, c0, 1
|
||||
mrc p15, 0, r6, c2, c0, 2
|
||||
stmia r8!, {r4-r6}
|
||||
/*
|
||||
* Domain access control register, data fault status register,
|
||||
* and instruction fault status register
|
||||
*/
|
||||
mrc p15, 0, r4, c3, c0, 0
|
||||
mrc p15, 0, r5, c5, c0, 0
|
||||
mrc p15, 0, r6, c5, c0, 1
|
||||
stmia r8!, {r4-r6}
|
||||
/*
|
||||
* Data aux fault status register, instruction aux fault status,
|
||||
* data fault address register and instruction fault address register
|
||||
*/
|
||||
mrc p15, 0, r4, c5, c1, 0
|
||||
mrc p15, 0, r5, c5, c1, 1
|
||||
mrc p15, 0, r6, c6, c0, 0
|
||||
mrc p15, 0, r7, c6, c0, 2
|
||||
stmia r8!, {r4-r7}
|
||||
/*
|
||||
* user r/w thread and process ID, user r/o thread and process ID,
|
||||
* priv only thread and process ID, cache size selection
|
||||
*/
|
||||
mrc p15, 0, r4, c13, c0, 2
|
||||
mrc p15, 0, r5, c13, c0, 3
|
||||
mrc p15, 0, r6, c13, c0, 4
|
||||
mrc p15, 2, r7, c0, c0, 0
|
||||
stmia r8!, {r4-r7}
|
||||
/* Data TLB lockdown, instruction TLB lockdown registers */
|
||||
mrc p15, 0, r5, c10, c0, 0
|
||||
mrc p15, 0, r6, c10, c0, 1
|
||||
stmia r8!, {r5-r6}
|
||||
/* Secure or non secure vector base address, FCSE PID, Context PID*/
|
||||
mrc p15, 0, r4, c12, c0, 0
|
||||
mrc p15, 0, r5, c13, c0, 0
|
||||
mrc p15, 0, r6, c13, c0, 1
|
||||
stmia r8!, {r4-r6}
|
||||
/* Primary remap, normal remap registers */
|
||||
mrc p15, 0, r4, c10, c2, 0
|
||||
mrc p15, 0, r5, c10, c2, 1
|
||||
stmia r8!,{r4-r5}
|
||||
|
||||
/* Store current cpsr*/
|
||||
mrs r2, cpsr
|
||||
stmia r8!, {r2}
|
||||
|
||||
mrc p15, 0, r4, c1, c0, 0
|
||||
/* save control register */
|
||||
stmia r8!, {r4}
|
||||
|
||||
clean_caches:
|
||||
/*
|
||||
* Clean Data or unified cache to POU
|
||||
* How to invalidate only L1 cache???? - #FIX_ME#
|
||||
* mcr p15, 0, r11, c7, c11, 1
|
||||
*/
|
||||
cmp r1, #0x1 @ Check whether L2 inval is required
|
||||
beq omap3_do_wfi
|
||||
|
||||
clean_l2:
|
||||
/*
|
||||
* jump out to kernel flush routine
|
||||
* - reuse that code is better
|
||||
* - it executes in a cached space so is faster than refetch per-block
|
||||
* - should be faster and will change with kernel
|
||||
* - 'might' have to copy address, load and jump to it
|
||||
*/
|
||||
ldr r1, kernel_flush
|
||||
mov lr, pc
|
||||
bx r1
|
||||
|
||||
omap3_do_wfi:
|
||||
ldr r4, sdrc_power @ read the SDRC_POWER register
|
||||
ldr r5, [r4] @ read the contents of SDRC_POWER
|
||||
orr r5, r5, #0x40 @ enable self refresh on idle req
|
||||
str r5, [r4] @ write back to SDRC_POWER register
|
||||
|
||||
/* Data memory barrier and Data sync barrier */
|
||||
mov r1, #0
|
||||
mcr p15, 0, r1, c7, c10, 4
|
||||
mcr p15, 0, r1, c7, c10, 5
|
||||
|
||||
/*
|
||||
* ===================================
|
||||
* == WFI instruction => Enter idle ==
|
||||
* ===================================
|
||||
*/
|
||||
wfi @ wait for interrupt
|
||||
|
||||
/*
|
||||
* ===================================
|
||||
* == Resume path for non-OFF modes ==
|
||||
* ===================================
|
||||
*/
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
@ -184,7 +319,29 @@ ENTRY(omap34xx_cpu_suspend)
|
|||
nop
|
||||
bl wait_sdrc_ok
|
||||
|
||||
ldmfd sp!, {r0-r12, pc} @ restore regs and return
|
||||
/*
|
||||
* ===================================
|
||||
* == Exit point from non-OFF modes ==
|
||||
* ===================================
|
||||
*/
|
||||
ldmfd sp!, {r0-r12, pc} @ restore regs and return
|
||||
|
||||
|
||||
/*
|
||||
* ==============================
|
||||
* == Resume path for OFF mode ==
|
||||
* ==============================
|
||||
*/
|
||||
|
||||
/*
|
||||
* The restore_* functions are called by the ROM code
|
||||
* when back from WFI in OFF mode.
|
||||
* Cf. the get_*restore_pointer functions.
|
||||
*
|
||||
* restore_es3: applies to 34xx >= ES3.0
|
||||
* restore_3630: applies to 36xx
|
||||
* restore: common code for 3xxx
|
||||
*/
|
||||
restore_es3:
|
||||
ldr r5, pm_prepwstst_core_p
|
||||
ldr r4, [r5]
|
||||
|
@ -214,12 +371,17 @@ restore_3630:
|
|||
ldr r1, control_mem_rta
|
||||
mov r2, #OMAP36XX_RTA_DISABLE
|
||||
str r2, [r1]
|
||||
/* Fall thru for the remaining logic */
|
||||
|
||||
/* Fall through to common code for the remaining logic */
|
||||
|
||||
restore:
|
||||
/* Check what was the reason for mpu reset and store the reason in r9*/
|
||||
/* 1 - Only L1 and logic lost */
|
||||
/* 2 - Only L2 lost - In this case, we wont be here */
|
||||
/* 3 - Both L1 and L2 lost */
|
||||
/*
|
||||
* Check what was the reason for mpu reset and store the reason in r9:
|
||||
* 0 - No context lost
|
||||
* 1 - Only L1 and logic lost
|
||||
* 2 - Only L2 lost - In this case, we wont be here
|
||||
* 3 - Both L1 and L2 lost
|
||||
*/
|
||||
ldr r1, pm_pwstctrl_mpu
|
||||
ldr r2, [r1]
|
||||
and r2, r2, #0x3
|
||||
|
@ -422,119 +584,12 @@ usettbr0:
|
|||
and r4, r2
|
||||
mcr p15, 0, r4, c1, c0, 0
|
||||
|
||||
/*
|
||||
* ==============================
|
||||
* == Exit point from OFF mode ==
|
||||
* ==============================
|
||||
*/
|
||||
ldmfd sp!, {r0-r12, pc} @ restore regs and return
|
||||
save_context_wfi:
|
||||
mov r8, r0 /* Store SDRAM address in r8 */
|
||||
mrc p15, 0, r5, c1, c0, 1 @ Read Auxiliary Control Register
|
||||
mov r4, #0x1 @ Number of parameters for restore call
|
||||
stmia r8!, {r4-r5} @ Push parameters for restore call
|
||||
mrc p15, 1, r5, c9, c0, 2 @ Read L2 AUX ctrl register
|
||||
stmia r8!, {r4-r5} @ Push parameters for restore call
|
||||
/* Check what that target sleep state is:stored in r1*/
|
||||
/* 1 - Only L1 and logic lost */
|
||||
/* 2 - Only L2 lost */
|
||||
/* 3 - Both L1 and L2 lost */
|
||||
cmp r1, #0x2 /* Only L2 lost */
|
||||
beq clean_l2
|
||||
cmp r1, #0x1 /* L2 retained */
|
||||
/* r9 stores whether to clean L2 or not*/
|
||||
moveq r9, #0x0 /* Dont Clean L2 */
|
||||
movne r9, #0x1 /* Clean L2 */
|
||||
l1_logic_lost:
|
||||
/* Store sp and spsr to SDRAM */
|
||||
mov r4, sp
|
||||
mrs r5, spsr
|
||||
mov r6, lr
|
||||
stmia r8!, {r4-r6}
|
||||
/* Save all ARM registers */
|
||||
/* Coprocessor access control register */
|
||||
mrc p15, 0, r6, c1, c0, 2
|
||||
stmia r8!, {r6}
|
||||
/* TTBR0, TTBR1 and Translation table base control */
|
||||
mrc p15, 0, r4, c2, c0, 0
|
||||
mrc p15, 0, r5, c2, c0, 1
|
||||
mrc p15, 0, r6, c2, c0, 2
|
||||
stmia r8!, {r4-r6}
|
||||
/* Domain access control register, data fault status register,
|
||||
and instruction fault status register */
|
||||
mrc p15, 0, r4, c3, c0, 0
|
||||
mrc p15, 0, r5, c5, c0, 0
|
||||
mrc p15, 0, r6, c5, c0, 1
|
||||
stmia r8!, {r4-r6}
|
||||
/* Data aux fault status register, instruction aux fault status,
|
||||
datat fault address register and instruction fault address register*/
|
||||
mrc p15, 0, r4, c5, c1, 0
|
||||
mrc p15, 0, r5, c5, c1, 1
|
||||
mrc p15, 0, r6, c6, c0, 0
|
||||
mrc p15, 0, r7, c6, c0, 2
|
||||
stmia r8!, {r4-r7}
|
||||
/* user r/w thread and process ID, user r/o thread and process ID,
|
||||
priv only thread and process ID, cache size selection */
|
||||
mrc p15, 0, r4, c13, c0, 2
|
||||
mrc p15, 0, r5, c13, c0, 3
|
||||
mrc p15, 0, r6, c13, c0, 4
|
||||
mrc p15, 2, r7, c0, c0, 0
|
||||
stmia r8!, {r4-r7}
|
||||
/* Data TLB lockdown, instruction TLB lockdown registers */
|
||||
mrc p15, 0, r5, c10, c0, 0
|
||||
mrc p15, 0, r6, c10, c0, 1
|
||||
stmia r8!, {r5-r6}
|
||||
/* Secure or non secure vector base address, FCSE PID, Context PID*/
|
||||
mrc p15, 0, r4, c12, c0, 0
|
||||
mrc p15, 0, r5, c13, c0, 0
|
||||
mrc p15, 0, r6, c13, c0, 1
|
||||
stmia r8!, {r4-r6}
|
||||
/* Primary remap, normal remap registers */
|
||||
mrc p15, 0, r4, c10, c2, 0
|
||||
mrc p15, 0, r5, c10, c2, 1
|
||||
stmia r8!,{r4-r5}
|
||||
|
||||
/* Store current cpsr*/
|
||||
mrs r2, cpsr
|
||||
stmia r8!, {r2}
|
||||
|
||||
mrc p15, 0, r4, c1, c0, 0
|
||||
/* save control register */
|
||||
stmia r8!, {r4}
|
||||
clean_caches:
|
||||
/* Clean Data or unified cache to POU*/
|
||||
/* How to invalidate only L1 cache???? - #FIX_ME# */
|
||||
/* mcr p15, 0, r11, c7, c11, 1 */
|
||||
cmp r9, #1 /* Check whether L2 inval is required or not*/
|
||||
bne skip_l2_inval
|
||||
clean_l2:
|
||||
/*
|
||||
* Jump out to kernel flush routine
|
||||
* - reuse that code is better
|
||||
* - it executes in a cached space so is faster than refetch per-block
|
||||
* - should be faster and will change with kernel
|
||||
* - 'might' have to copy address, load and jump to it
|
||||
* - lr is used since we are running in SRAM currently.
|
||||
*/
|
||||
ldr r1, kernel_flush
|
||||
mov lr, pc
|
||||
bx r1
|
||||
|
||||
skip_l2_inval:
|
||||
/* Data memory barrier and Data sync barrier */
|
||||
mov r1, #0
|
||||
mcr p15, 0, r1, c7, c10, 4
|
||||
mcr p15, 0, r1, c7, c10, 5
|
||||
|
||||
wfi @ wait for interrupt
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
bl wait_sdrc_ok
|
||||
/* restore regs and return */
|
||||
ldmfd sp!, {r0-r12, pc}
|
||||
|
||||
|
||||
/*
|
||||
|
@ -687,5 +742,6 @@ kick_counter:
|
|||
.word 0
|
||||
wait_dll_lock_counter:
|
||||
.word 0
|
||||
|
||||
ENTRY(omap34xx_cpu_suspend_sz)
|
||||
.word . - omap34xx_cpu_suspend
|
||||
|
|
Загрузка…
Ссылка в новой задаче