Re: [RFC/PATCH] OMAP3: run the ASM sleep code from DDR

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Jan 13, 2011 at 5:19 PM,  <jean.pihet@xxxxxxxxxxxxxx> wrote:
> From: Jean Pihet <j-pihet@xxxxxx>
>
> 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 <j-pihet@xxxxxx>

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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux