On Thu, Jan 13, 2011 at 5:19 PM, <[email protected]> wrote:
> From: Jean Pihet <[email protected]>
>
> Most of the ASM sleep code (in arch/arm/mach-omap2/sleep34xx.S)
> is copied to internal SRAM and run from there.
> However only a small part of the code really needs to run from internal SRAM.
>
> This fix lets most of the ASM idle code run from the DDR
> in order to minimize the SRAM usage. No performance
> loss or gain can be measured with a 32KHz clock period.
>
> The only pieces of code that are mandatory in SRAM
> are:
> - the i443 erratum WA,
> - the i581 erratum WA,
> - the security extension code.
>
> SRAM usage:
> - original code:
> . 560 bytes for omap3_sram_configure_core_dpll (used by DVFS),
> . 1368 bytes for omap_sram_idle (used by suspend/resume in RETention),
> . 124 bytes for es3_sdrc_fix (used by suspend/resume in OFF mode on ES3.x),
> . 108 bytes for save_secure_ram_context (used on HS parts).
>
> With this fix the usage for suspend/resume in RETention goes down 312 bytes,
> so the
> gain in SRAM usage for suspend/resume is > 1KB.
>
> Tested on OMAP3EVM, Beagleboard (ES2.x) and N900 (ES3.1)
> in idle with full RET and OFF modes.
>
> Signed-off-by: Jean Pihet <[email protected]>
Is there any feedback on this code?
This change would need some more testing on all OMAP3 platforms,
especially on the 36xx platforms that I do not have at hand.
Comments are welcome!
Regards,
Jean
> ---
> arch/arm/mach-omap2/pm.h | 19 ++-
> arch/arm/mach-omap2/pm34xx.c | 19 ++-
> arch/arm/mach-omap2/sleep34xx.S | 299
> +++++++++++++++++++++++----------------
> 3 files changed, 200 insertions(+), 137 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
> index 1c1b0ab..ae9dec0 100644
> --- a/arch/arm/mach-omap2/pm.h
> +++ b/arch/arm/mach-omap2/pm.h
> @@ -87,18 +87,29 @@ extern int pm_dbg_regset_init(int reg_set);
> #define pm_dbg_regset_init(reg_set) do {} while (0);
> #endif /* CONFIG_PM_DEBUG */
>
> +/* 24xx */
> extern void omap24xx_idle_loop_suspend(void);
> +extern unsigned int omap24xx_idle_loop_suspend_sz;
>
> extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl,
> void __iomem *sdrc_power);
> +extern unsigned int omap24xx_cpu_suspend_sz;
> +
> +/* 3xxx */
> extern void omap34xx_cpu_suspend(u32 *addr, int save_state);
> +
> +/* omap3_do_wfi function pointer and size, for copy to SRAM */
> +extern void omap3_do_wfi(void);
> +extern unsigned int omap3_do_wfi_sz;
> +/* ... and its pointer from SRAM after copy */
> +extern void (*omap3_do_wfi_sram)(void);
> +
> +/* save_secure_ram_context function pointer and size, for copy to SRAM */
> extern void save_secure_ram_context(u32 *addr);
> -extern void omap3_save_scratchpad_contents(void);
>
> -extern unsigned int omap24xx_idle_loop_suspend_sz;
> extern unsigned int save_secure_ram_context_sz;
> -extern unsigned int omap24xx_cpu_suspend_sz;
> -extern unsigned int omap34xx_cpu_suspend_sz;
> +
> +extern void omap3_save_scratchpad_contents(void);
>
> #define PM_RTA_ERRATUM_i608 (1 << 0)
> #define PM_SDRC_WAKEUP_ERRATUM_i583 (1 << 1)
> diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
> index 5b323f2..56ca3cb 100644
> --- a/arch/arm/mach-omap2/pm34xx.c
> +++ b/arch/arm/mach-omap2/pm34xx.c
> @@ -82,9 +82,8 @@ struct power_state {
>
> static LIST_HEAD(pwrst_list);
>
> -static void (*_omap_sram_idle)(u32 *addr, int save_state);
> -
> static int (*_omap_save_secure_sram)(u32 *addr);
> +void (*omap3_do_wfi_sram)(void);
>
> static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
> static struct powerdomain *core_pwrdm, *per_pwrdm;
> @@ -355,9 +354,6 @@ void omap_sram_idle(void)
> int core_prev_state, per_prev_state;
> u32 sdrc_pwr = 0;
>
> - if (!_omap_sram_idle)
> - return;
> -
> pwrdm_clear_all_prev_pwrst(mpu_pwrdm);
> pwrdm_clear_all_prev_pwrst(neon_pwrdm);
> pwrdm_clear_all_prev_pwrst(core_pwrdm);
> @@ -439,7 +435,7 @@ void omap_sram_idle(void)
> * get saved. The restore path then reads from this
> * location and restores them back.
> */
> - _omap_sram_idle(omap3_arm_context, save_state);
> + omap34xx_cpu_suspend(omap3_arm_context, save_state);
> cpu_init();
>
> /* Restore normal SDRC POWER settings */
> @@ -996,10 +992,17 @@ static int __init clkdms_setup(struct clockdomain
> *clkdm, void *unused)
> return 0;
> }
>
> +/*
> + * Push functions to SRAM
> + *
> + * The minimum set of functions is pushed to SRAM for execution:
> + * - omap3_do_wfi for erratum i581 WA,
> + * - save_secure_ram_context for security extensions.
> + */
> void omap_push_sram_idle(void)
> {
> - _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
> - omap34xx_cpu_suspend_sz);
> + omap3_do_wfi_sram = omap_sram_push(omap3_do_wfi, omap3_do_wfi_sz);
> +
> if (omap_type() != OMAP2_DEVICE_TYPE_GP)
> _omap_save_secure_sram =
> omap_sram_push(save_secure_ram_context,
> save_secure_ram_context_sz);
> diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
> index 98d8232..ced85b5 100644
> --- a/arch/arm/mach-omap2/sleep34xx.S
> +++ b/arch/arm/mach-omap2/sleep34xx.S
> @@ -163,8 +163,10 @@ ENTRY(save_secure_ram_context_sz)
> *
> *
> * Notes:
> - * - this code gets copied to internal SRAM at boot and after wake-up
> - * from OFF mode. The execution pointer in SRAM is _omap_sram_idle.
> + * - only the minimum set of functions gets copied to internal SRAM at boot
> + * and after wake-up from OFF mode, cf. omap_push_sram_idle. The function
> + * pointers in SDRAM or SRAM are called depending on the desired low power
> + * target state.
> * - 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.
> @@ -181,9 +183,15 @@ ENTRY(omap34xx_cpu_suspend)
> * 3 - Both L1 and L2 lost
> */
>
> - /* Directly jump to WFI is the context save is not required */
> - cmp r1, #0x0
> - beq omap3_do_wfi
> + /*
> + * For OFF mode: save context and jump to WFI in SDRAM (omap3_do_wfi)
> + * For non-OFF modes: jump to the WFI code in SRAM (omap3_do_wfi_sram)
> + */
> + ldr r4, omap3_do_wfi_sram_addr
> + ldr r5, [r4]
> + cmp r1, #0x0 @ If no context save required,
> + bxeq r5 @ jump to the WFI code in SRAM
> +
>
> /* Otherwise fall through to the save context code */
> save_context_wfi:
> @@ -282,7 +290,31 @@ clean_l2:
> mov lr, pc
> bx r1
>
> -omap3_do_wfi:
> + b omap3_do_wfi
> +
> +/*
> + * Local variables
> + */
> +omap3_do_wfi_sram_addr:
> + .word omap3_do_wfi_sram
> +kernel_flush:
> + .word v7_flush_dcache_all
> +
> +/* ===================================
> + * == WFI instruction => Enter idle ==
> + * ===================================
> + */
> +
> +/*
> + * Do WFI instruction
> + * Includes the resume path for non-OFF modes
> + *
> + * This code gets copied to internal SRAM and is accessible
> + * from both SDRAM and SRAM:
> + * - executed from SRAM for non-off modes (omap3_do_wfi_sram),
> + * - executed from SDRAM for OFF mode (omap3_do_wfi).
> + */
> +ENTRY(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
> @@ -315,15 +347,111 @@ omap3_do_wfi:
> nop
> nop
> nop
> - bl wait_sdrc_ok
> +
> +/*
> + * wait_sdrc_ok implements the erratum ID i581 WA:
> + * SDRC state restore before accessing the SDRAM
> + *
> + * Only used at return from non-OFF mode. For OFF
> + * mode the ROM code configures the SDRC and
> + * the DPLL before calling the restore code directly
> + * from SDRAM.
> + */
> +
> +/* Make sure SDRC accesses are ok */
> +wait_sdrc_ok:
> +
> +/* DPLL3 must be locked before accessing the SDRC. Maybe the HW ensures this
> */
> + ldr r4, cm_idlest_ckgen
> +wait_dpll3_lock:
> + ldr r5, [r4]
> + tst r5, #1
> + beq wait_dpll3_lock
> +
> + ldr r4, cm_idlest1_core
> +wait_sdrc_ready:
> + ldr r5, [r4]
> + tst r5, #0x2
> + bne wait_sdrc_ready
> + /* allow DLL powerdown upon hw idle req */
> + ldr r4, sdrc_power
> + ldr r5, [r4]
> + bic r5, r5, #0x40
> + str r5, [r4]
> +
> +is_dll_in_lock_mode:
> + /* Is dll in lock mode? */
> + ldr r4, sdrc_dlla_ctrl
> + ldr r5, [r4]
> + tst r5, #0x4
> + bne exit_nonoff_modes @ Return if locked
> +
> + /* wait till dll locks */
> +wait_dll_lock_timed:
> + ldr r4, wait_dll_lock_counter
> + add r4, r4, #1
> + str r4, wait_dll_lock_counter
> + ldr r4, sdrc_dlla_status
> + /* Wait 20uS for lock */
> + mov r6, #8
> +wait_dll_lock:
> + subs r6, r6, #0x1
> + beq kick_dll
> + ldr r5, [r4]
> + and r5, r5, #0x4
> + cmp r5, #0x4
> + bne wait_dll_lock
> + b exit_nonoff_modes @ Return when locked
> +
> + /* disable/reenable DLL if not locked */
> +kick_dll:
> + ldr r4, sdrc_dlla_ctrl
> + ldr r5, [r4]
> + mov r6, r5
> + bic r6, #(1<<3) @ disable dll
> + str r6, [r4]
> + dsb
> + orr r6, r6, #(1<<3) @ enable dll
> + str r6, [r4]
> + dsb
> + ldr r4, kick_counter
> + add r4, r4, #1
> + str r4, kick_counter
> + b wait_dll_lock_timed
>
> /*
> * ===================================
> * == Exit point from non-OFF modes ==
> * ===================================
> */
> +exit_nonoff_modes:
> ldmfd sp!, {r0-r12, pc} @ restore regs and return
>
> +/*
> + * Local variables
> + */
> +sdrc_power:
> + .word SDRC_POWER_V
> +cm_idlest1_core:
> + .word CM_IDLEST1_CORE_V
> +cm_idlest_ckgen:
> + .word CM_IDLEST_CKGEN_V
> +sdrc_dlla_status:
> + .word SDRC_DLLA_STATUS_V
> +sdrc_dlla_ctrl:
> + .word SDRC_DLLA_CTRL_V
> + /*
> + * When exporting to userspace while the counters are in SRAM,
> + * these 2 words need to be at the end to facilitate retrival!
> + */
> +kick_counter:
> + .word 0
> +wait_dll_lock_counter:
> + .word 0
> +
> +ENTRY(omap3_do_wfi_sz)
> + .word . - omap3_do_wfi
> +
>
> /*
> * ==============================
> @@ -339,6 +467,10 @@ omap3_do_wfi:
> * restore_es3: applies to 34xx >= ES3.0
> * restore_3630: applies to 36xx
> * restore: common code for 3xxx
> + *
> + * Note: when back from CORE and MPU OFF mode we are running
> + * from SDRAM, without MMU, without the caches and prediction.
> + * Also the SRAM content has been cleared.
> */
> restore_es3:
> ldr r5, pm_prepwstst_core_p
> @@ -357,7 +489,8 @@ copy_to_sram:
> bne copy_to_sram
> ldr r1, sram_base
> blx r1
> - b restore
> +
> + b restore @ Fall through to common code
>
> restore_3630:
> ldr r1, pm_prepwstst_core_p
> @@ -600,12 +733,41 @@ usettbr0:
> */
> ldmfd sp!, {r0-r12, pc} @ restore regs and return
>
> +/*
> + * Local variables
> + */
> +pm_prepwstst_core_p:
> + .word PM_PREPWSTST_CORE_P
> +pm_pwstctrl_mpu:
> + .word PM_PWSTCTRL_MPU_P
> +scratchpad_base:
> + .word SCRATCHPAD_BASE_P
> +sram_base:
> + .word SRAM_BASE_P + 0x8000
> +ttbrbit_mask:
> + .word 0xFFFFC000
> +table_index_mask:
> + .word 0xFFF00000
> +table_entry:
> + .word 0x00000C02
> +cache_pred_disable_mask:
> + .word 0xFFFFE7FB
> +control_stat:
> + .word CONTROL_STAT
> +control_mem_rta:
> + .word CONTROL_MEM_RTA_CTRL
> +l2dis_3630:
> + .word 0
> +
>
> /*
> * Internal functions
> */
>
> -/* This function implements the erratum ID i443 WA, applies to 34xx >= ES3.0
> */
> +/* This function implements the erratum ID i443 WA, applies to 34xx >= ES3.0
> + *
> + * Copied and run from SRAM in order to reconfigure the SDRC parameters.
> + */
> .text
> ENTRY(es3_sdrc_fix)
> ldr r4, sdrc_syscfg @ get config addr
> @@ -634,6 +796,9 @@ ENTRY(es3_sdrc_fix)
> str r5, [r4] @ kick off refreshes
> bx lr
>
> +/*
> + * Local variables
> + */
> sdrc_syscfg:
> .word SDRC_SYSCONFIG_P
> sdrc_mr_0:
> @@ -650,119 +815,3 @@ sdrc_manual_1:
> .word SDRC_MANUAL_1_P
> ENTRY(es3_sdrc_fix_sz)
> .word . - es3_sdrc_fix
> -
> -/*
> - * This function implements the erratum ID i581 WA:
> - * SDRC state restore before accessing the SDRAM
> - *
> - * Only used at return from non-OFF mode. For OFF
> - * mode the ROM code configures the SDRC and
> - * the DPLL before calling the restore code directly
> - * from DDR.
> - */
> -
> -/* Make sure SDRC accesses are ok */
> -wait_sdrc_ok:
> -
> -/* DPLL3 must be locked before accessing the SDRC. Maybe the HW ensures this
> */
> - ldr r4, cm_idlest_ckgen
> -wait_dpll3_lock:
> - ldr r5, [r4]
> - tst r5, #1
> - beq wait_dpll3_lock
> -
> - ldr r4, cm_idlest1_core
> -wait_sdrc_ready:
> - ldr r5, [r4]
> - tst r5, #0x2
> - bne wait_sdrc_ready
> - /* allow DLL powerdown upon hw idle req */
> - ldr r4, sdrc_power
> - ldr r5, [r4]
> - bic r5, r5, #0x40
> - str r5, [r4]
> -
> -is_dll_in_lock_mode:
> - /* Is dll in lock mode? */
> - ldr r4, sdrc_dlla_ctrl
> - ldr r5, [r4]
> - tst r5, #0x4
> - bxne lr @ Return if locked
> - /* wait till dll locks */
> -wait_dll_lock_timed:
> - ldr r4, wait_dll_lock_counter
> - add r4, r4, #1
> - str r4, wait_dll_lock_counter
> - ldr r4, sdrc_dlla_status
> - /* Wait 20uS for lock */
> - mov r6, #8
> -wait_dll_lock:
> - subs r6, r6, #0x1
> - beq kick_dll
> - ldr r5, [r4]
> - and r5, r5, #0x4
> - cmp r5, #0x4
> - bne wait_dll_lock
> - bx lr @ Return when locked
> -
> - /* disable/reenable DLL if not locked */
> -kick_dll:
> - ldr r4, sdrc_dlla_ctrl
> - ldr r5, [r4]
> - mov r6, r5
> - bic r6, #(1<<3) @ disable dll
> - str r6, [r4]
> - dsb
> - orr r6, r6, #(1<<3) @ enable dll
> - str r6, [r4]
> - dsb
> - ldr r4, kick_counter
> - add r4, r4, #1
> - str r4, kick_counter
> - b wait_dll_lock_timed
> -
> -cm_idlest1_core:
> - .word CM_IDLEST1_CORE_V
> -cm_idlest_ckgen:
> - .word CM_IDLEST_CKGEN_V
> -sdrc_dlla_status:
> - .word SDRC_DLLA_STATUS_V
> -sdrc_dlla_ctrl:
> - .word SDRC_DLLA_CTRL_V
> -pm_prepwstst_core_p:
> - .word PM_PREPWSTST_CORE_P
> -pm_pwstctrl_mpu:
> - .word PM_PWSTCTRL_MPU_P
> -scratchpad_base:
> - .word SCRATCHPAD_BASE_P
> -sram_base:
> - .word SRAM_BASE_P + 0x8000
> -sdrc_power:
> - .word SDRC_POWER_V
> -ttbrbit_mask:
> - .word 0xFFFFC000
> -table_index_mask:
> - .word 0xFFF00000
> -table_entry:
> - .word 0x00000C02
> -cache_pred_disable_mask:
> - .word 0xFFFFE7FB
> -control_stat:
> - .word CONTROL_STAT
> -control_mem_rta:
> - .word CONTROL_MEM_RTA_CTRL
> -kernel_flush:
> - .word v7_flush_dcache_all
> -l2dis_3630:
> - .word 0
> - /*
> - * When exporting to userspace while the counters are in SRAM,
> - * these 2 words need to be at the end to facilitate retrival!
> - */
> -kick_counter:
> - .word 0
> -wait_dll_lock_counter:
> - .word 0
> -
> -ENTRY(omap34xx_cpu_suspend_sz)
> - .word . - omap34xx_cpu_suspend
> --
> 1.7.2.3
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html