[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