[PATCH] ARM: omap: Enable low-level omap3 PM code to work with CONFIG_THUMB2_KERNEL
Dave Martin
dave.martin at linaro.org
Tue Nov 30 08:31:17 EST 2010
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 at 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;
}
--
1.7.1
More information about the linux-arm-kernel
mailing list