sleep34xx.S, sram34xx.S:
* Added ENDPROC() directives for all exported function symbols. Without these, exported function symbols are not correctly identified as Thumb by the linker, causing incorrect linkage. This is needed to avoid some calls to the functions ending up with the CPU in the wrong instruction set.
* Added .align directives where needed to ensure that .word won't be misaligned. (Note that ENTRY() implies .align; no extra .align has been added for these cases.)
* Exported new "base address" symbols for functions which get copied to sram by code outside sleep34xx.S (applies to save_secure_ram_context and omap32xx_cpu_suspend), and fix up the relevant address arithmetic so that these will be copied and called correctly by the Thumb code in the rest of the kernel.
* Explicitly build a few parts of sleep34xx.S as ARM.
* lock_scratchpad_sem is kept as ARM because of the need to synchronise with hardware (?) using the SWP instruction.
* save_secure_ram_context and omap34xx_cpu_suspend are built as ARM in case the Secure World firmware expects to decode the comment field from the SMC (aka smi) instructions.
This can be undone later if the firmware is confirmed as able to decode the Thumb SMC encoding (or ignores the comment field).
* es3_sdrc_fix should presumably only be called from the low-level wakeup code. To minimise the diff, switched this to ARM and demoted it to be a local symbol, since I believe it shouldn't be called from outside anyway.
To prevent future maintainence problems, it would probably be a good idea to demote _all_ functions which aren't called externally to local. (i.e., everything except for get_es3_restore_pointer, get_restore_pointer, omap34xx_cpu_suspend and save_secure_ram_context).
For now, I've left these as-is to minimise disruption.
* Use a separate base register instead of PC-relative stores in sram34xx.S. This isn't permitted in Thumb-2, but at least some versions of gas will silently output non-working code, leading to unpredictable run-time behaviour.
pm34xx.c, pm.h, sram.c, sram.h:
* Resolve some memory addressing issues where a function symbol's value is assumed to be equal to the start address of the function body for the purpose of copying some low-level code from sleep34xx.S to SRAM.
This assumption breaks for Thumb, since Thumb functions symbols have bit 0 set to indicate the Thumb-ness. This would result in a non-working, off-by-one copy of the function body.
Tested on Beagle xM A2: * CONFIG_THUMB2_KERNEL && !CONFIG_SMP_ON_UP * CONFIG_THUMB2_KERNEL && CONFIG_SMP_ON_UP * !CONFIG_THUMB2_KERNEL && !CONFIG_SMP_ON_UP * !CONFIG_THUMB2_KERNEL && CONFIG_SMP_ON_UP
Signed-off-by: Dave Martin dave.martin@linaro.org --- KernelVersion: 2.6.37-rc4
arch/arm/mach-omap2/pm.h | 2 + arch/arm/mach-omap2/pm34xx.c | 13 ++++++++-- arch/arm/mach-omap2/sleep34xx.S | 37 +++++++++++++++++++++++++++++-- arch/arm/mach-omap2/sram34xx.S | 34 +++++++++++++++++++++------- arch/arm/plat-omap/include/plat/sram.h | 1 + arch/arm/plat-omap/sram.c | 10 +++++++- 6 files changed, 80 insertions(+), 17 deletions(-)
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 0d75bfd..c333bfd 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -80,7 +80,9 @@ extern void save_secure_ram_context(u32 *addr); extern void omap3_save_scratchpad_contents(void);
extern unsigned int omap24xx_idle_loop_suspend_sz; +extern char *const omap34xx_cpu_suspend_base; extern unsigned int omap34xx_suspend_sz; +extern char *const save_secure_ram_context_base; extern unsigned int save_secure_ram_context_sz; extern unsigned int omap24xx_cpu_suspend_sz; extern unsigned int omap34xx_cpu_suspend_sz; diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 0ec8a04..93f0ee8 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -982,11 +982,18 @@ static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
void omap_push_sram_idle(void) { - _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend, + _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend_base, omap34xx_cpu_suspend_sz); - if (omap_type() != OMAP2_DEVICE_TYPE_GP) - _omap_save_secure_sram = omap_sram_push(save_secure_ram_context, + _omap_sram_idle += (char *)omap34xx_cpu_suspend - + omap34xx_cpu_suspend_base; + + if (omap_type() != OMAP2_DEVICE_TYPE_GP) { + _omap_save_secure_sram = omap_sram_push( + save_secure_ram_context_base, save_secure_ram_context_sz); + _omap_save_secure_sram += (char *)save_secure_ram_context - + save_secure_ram_context_base; + } }
static int __init omap3_pm_init(void) diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index 2fb205a..06ae955 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -61,6 +61,7 @@
.text /* Function to acquire the semaphore in scratchpad */ + .arm @ Do this in ARM for now, due to use of SWP. ENTRY(lock_scratchpad_sem) stmfd sp!, {lr} @ save registers on stack wait_sem: @@ -74,6 +75,9 @@ wait_loop: cmp r2, r0 @ did we succeed ? beq wait_sem @ no - try again ldmfd sp!, {pc} @ restore regs and return +ENDPROC(lock_scratchpad_sem) + THUMB( .thumb ) + .align sdrc_scratchpad_sem: .word SDRC_SCRATCHPAD_SEM_V ENTRY(lock_scratchpad_sem_sz) @@ -87,6 +91,7 @@ ENTRY(unlock_scratchpad_sem) mov r2,#0 str r2,[r3] ldmfd sp!, {pc} @ restore regs and return +ENDPROC(unlock_scratchpad_sem) ENTRY(unlock_scratchpad_sem_sz) .word . - unlock_scratchpad_sem
@@ -96,6 +101,7 @@ ENTRY(get_restore_pointer) stmfd sp!, {lr} @ save registers on stack adr r0, restore ldmfd sp!, {pc} @ restore regs and return +ENDPROC(get_restore_pointer) ENTRY(get_restore_pointer_sz) .word . - get_restore_pointer
@@ -105,10 +111,16 @@ ENTRY(get_es3_restore_pointer) stmfd sp!, {lr} @ save registers on stack adr r0, restore_es3 ldmfd sp!, {pc} @ restore regs and return +ENDPROC(get_es3_restore_pointer) ENTRY(get_es3_restore_pointer_sz) .word . - get_es3_restore_pointer
-ENTRY(es3_sdrc_fix) +@ For simplicity, make this ARM so it gets called OK from es3_restore. +@ Demote to a local symbol, since this gives this function an ARM ABI interface +@ which won't be callable directly from a Thumb-2 kernel. This code +@ shouldn't be called from outside anyway... + .arm +es3_sdrc_fix: ldr r4, sdrc_syscfg @ get config addr ldr r5, [r4] @ get value tst r5, #0x100 @ is part access blocked @@ -134,6 +146,9 @@ ENTRY(es3_sdrc_fix) mov r5, #0x2 @ autorefresh command str r5, [r4] @ kick off refreshes bx lr +ENDPROC(es3_sdrc_fix) + THUMB( .thumb ) + .align sdrc_syscfg: .word SDRC_SYSCONFIG_P sdrc_mr_0: @@ -150,8 +165,12 @@ sdrc_manual_1: .word SDRC_MANUAL_1_P ENTRY(es3_sdrc_fix_sz) .word . - es3_sdrc_fix + THUMB( .thumb )
/* Function to call rom code to save secure ram context */ + .arm @ Do this in ARM for now, due to use of SMC, + @ in case the Secure World firmware may depends + @ on decoding the SMC instruction. ENTRY(save_secure_ram_context) stmfd sp!, {r1-r12, lr} @ save registers on stack save_secure_ram_debug: @@ -175,6 +194,9 @@ save_secure_ram_debug: nop nop ldmfd sp!, {r1-r12, pc} +ENDPROC(save_secure_ram_context) + THUMB( .thumb ) + .align sram_phy_addr_mask: .word SRAM_BASE_P high_mask: @@ -183,6 +205,8 @@ api_params: .word 0x4, 0x0, 0x0, 0x1, 0x1 ENTRY(save_secure_ram_context_sz) .word . - save_secure_ram_context +ENTRY(save_secure_ram_context_base) + .word save_secure_ram_context_base
/* * Forces OMAP into idle state @@ -193,6 +217,7 @@ ENTRY(save_secure_ram_context_sz) * 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. */ + .arm @ Do this in ARM for now, due to use of SMC. ENTRY(omap34xx_cpu_suspend) stmfd sp!, {r0-r12, lr} @ save registers on stack loop: @@ -563,10 +588,12 @@ loop2: mov r9, r4 /* create working copy of max way size*/ loop3: + mov r1, r9, lsl r5 + mov r2, r7, lsl r2 /* factor way and cache number into r11 */ - orr r11, r10, r9, lsl r5 + orr r11, r10, r1 /* factor index number into r11 */ - orr r11, r11, r7, lsl r2 + orr r11, r11, r2 /*clean & invalidate by set/way */ mcr p15, 0, r11, c7, c10, 2 /* decrement the way*/ @@ -631,7 +658,9 @@ wait_dll_lock: cmp r5, #0x4 bne wait_dll_lock bx lr +ENDPROC(omap34xx_cpu_suspend)
+ .align cm_idlest1_core: .word CM_IDLEST1_CORE_V sdrc_dlla_status: @@ -670,3 +699,5 @@ control_stat: .word CONTROL_STAT ENTRY(omap34xx_cpu_suspend_sz) .word . - omap34xx_cpu_suspend +ENTRY(omap34xx_cpu_suspend_base) + .word omap34xx_cpu_suspend diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S index 3637274..65fd54f 100644 --- a/arch/arm/mach-omap2/sram34xx.S +++ b/arch/arm/mach-omap2/sram34xx.S @@ -105,29 +105,42 @@ * can satisfy the above requirement can enable the CONFIG_OMAP3_SDRC_AC_TIMING * option. */ +__omap3_sram_configure_core_dpll_base: @ Separate local symbol with the Thumb + @ bit _not_ set (for base address when + @ copying to sram). ENTRY(omap3_sram_configure_core_dpll) stmfd sp!, {r1-r12, lr} @ store regs to stack
@ pull the extra args off the stack @ and store them in SRAM + +@ PC-relative stores lead to undefined behaviour in Thumb-2: use a r7 as a +@ base instead. +@ Be careful not to clobber r7 when maintaing this file. + THUMB( adr r7, omap3_sram_configure_core_dpll ) + .macro strtext Rt:req, label:req + ARM( str \Rt, \label ) + THUMB( str \Rt, [r7, \label - omap3_sram_configure_core_dpll] ) + .endm + ldr r4, [sp, #52] - str r4, omap_sdrc_rfr_ctrl_0_val + strtext r4, omap_sdrc_rfr_ctrl_0_val ldr r4, [sp, #56] - str r4, omap_sdrc_actim_ctrl_a_0_val + strtext r4, omap_sdrc_actim_ctrl_a_0_val ldr r4, [sp, #60] - str r4, omap_sdrc_actim_ctrl_b_0_val + strtext r4, omap_sdrc_actim_ctrl_b_0_val ldr r4, [sp, #64] - str r4, omap_sdrc_mr_0_val + strtext r4, omap_sdrc_mr_0_val ldr r4, [sp, #68] - str r4, omap_sdrc_rfr_ctrl_1_val + strtext r4, omap_sdrc_rfr_ctrl_1_val cmp r4, #0 @ if SDRC_RFR_CTRL_1 is 0, beq skip_cs1_params @ do not use cs1 params ldr r4, [sp, #72] - str r4, omap_sdrc_actim_ctrl_a_1_val + strtext r4, omap_sdrc_actim_ctrl_a_1_val ldr r4, [sp, #76] - str r4, omap_sdrc_actim_ctrl_b_1_val + strtext r4, omap_sdrc_actim_ctrl_b_1_val ldr r4, [sp, #80] - str r4, omap_sdrc_mr_1_val + strtext r4, omap_sdrc_mr_1_val skip_cs1_params: mrc p15, 0, r8, c1, c0, 0 @ read ctrl register bic r10, r8, #0x800 @ clear Z-bit, disable branch prediction @@ -264,7 +277,9 @@ configure_sdrc: skip_cs1_prog: ldr r12, [r11] @ posted-write barrier for SDRC bx lr +ENDPROC(omap3_sram_configure_core_dpll)
+ .align omap3_sdrc_power: .word OMAP34XX_SDRC_REGADDR(SDRC_POWER) omap3_cm_clksel1_pll: @@ -316,4 +331,5 @@ core_m2_mask_val:
ENTRY(omap3_sram_configure_core_dpll_sz) .word . - omap3_sram_configure_core_dpll - +ENTRY(omap3_sram_configure_core_dpll_base) + .word __omap3_sram_configure_core_dpll_base diff --git a/arch/arm/plat-omap/include/plat/sram.h b/arch/arm/plat-omap/include/plat/sram.h index 5905100..2f27167 100644 --- a/arch/arm/plat-omap/include/plat/sram.h +++ b/arch/arm/plat-omap/include/plat/sram.h @@ -67,6 +67,7 @@ extern u32 omap3_sram_configure_core_dpll( u32 sdrc_rfr_ctrl_1, u32 sdrc_actim_ctrl_a_1, u32 sdrc_actim_ctrl_b_1, u32 sdrc_mr_1); extern unsigned long omap3_sram_configure_core_dpll_sz; +extern char *omap3_sram_configure_core_dpll_base;
#ifdef CONFIG_PM extern void omap_push_sram_idle(void); diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index e2c8eeb..61282f4 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -386,8 +386,11 @@ void omap3_sram_restore_context(void) omap_sram_ceil = omap_sram_base + omap_sram_size;
_omap3_sram_configure_core_dpll = - omap_sram_push(omap3_sram_configure_core_dpll, + omap_sram_push(omap3_sram_configure_core_dpll_base, omap3_sram_configure_core_dpll_sz); + _omap3_sram_configure_core_dpll += + (char *)omap3_sram_configure_core_dpll - + omap3_sram_configure_core_dpll_base; omap_push_sram_idle(); } #endif /* CONFIG_PM */ @@ -395,8 +398,11 @@ void omap3_sram_restore_context(void) static int __init omap34xx_sram_init(void) { _omap3_sram_configure_core_dpll = - omap_sram_push(omap3_sram_configure_core_dpll, + omap_sram_push(omap3_sram_configure_core_dpll_base, omap3_sram_configure_core_dpll_sz); + _omap3_sram_configure_core_dpll += + (char *)omap3_sram_configure_core_dpll - + omap3_sram_configure_core_dpll_base; omap_push_sram_idle(); return 0; }