[PATCH V5 1/3] ARM: imx: add suspend in ocram support for i.mx6q
Anson.Huang at freescale.com
Anson.Huang at freescale.com
Wed Jan 15 00:23:59 EST 2014
Hi, Shawn
these comments should be applicable, will optimize this asm code in V6, thanks.
Sent from Anson's iPhone
> 在 2014年1月15日,11:42,"Shawn Guo" <shawn.guo at linaro.org> 写道:
>
>> On Tue, Jan 14, 2014 at 02:35:13PM +0800, Anson Huang wrote:
>> When system enter suspend, we can set the DDR IO to
>> high-Z state to save DDR IOs' power consumption, this
>> operation can save many power(from ~26mA at 1.5V to ~15mA at 1.5V,
>> measured on i.MX6Q SabreSD board, R25) of DDR IOs. To
>> achieve that, we need to copy the suspend code to ocram
>> and run the low level hardware related code(set DDR IOs
>> to high-Z state) in ocram.
>>
>> If there is no ocram space available, then system will
>> still do suspend in external DDR, hence no DDR IOs will
>> be set to high-Z.
>>
>> The OCRAM usage layout is as below,
>>
>> ocram suspend region(4K currently):
>> ======================== high address ======================
>> .
>> .
>> .
>> ^
>> ^
>> ^
>> imx6_suspend code
>> reserved space(to make imx6_suspend aligned with 8)
>
> We can remove this line now, right? Same for the comment in code.
>
>> PM_INFO structure(imx6_cpu_pm_info)
>> ======================== low address =======================
>>
>> Signed-off-by: Anson Huang <b20788 at freescale.com>
>
> <snip>
>
>> +ENTRY(imx6_suspend)
>> + ldr r1, [r0, #PM_INFO_PBASE_OFFSET]
>> + ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
>> + ldr r3, [r0, #PM_INFO_CPU_TYPE_OFFSET]
>> + ldr r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
>> +
>> + /*
>> + * counting the resume address in iram
>> + * to set it in SRC register.
>> + */
>> + ldr r6, =imx6_suspend
>> + ldr r7, =resume
>> + sub r7, r7, r6
>> + add r8, r1, r4
>> + add r9, r8, r7
>> +
>> + /*
>> + * make sure TLB contain the addr we want,
>> + * as we will access them after MMDC IO floated.
>> + */
>> +
>> + ldr r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
>> + ldr r6, [r11, #0x0]
>> + ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
>> + ldr r6, [r11, #0x0]
>> +
>> + /* use r11 to store the IO address */
>> + ldr r11, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET]
>> + /* store physical resume addr and pm_info address. */
>> + str r9, [r11, #MX6Q_SRC_GPR1]
>> + str r1, [r11, #MX6Q_SRC_GPR2]
>> +
>> + /* need to sync L2 cache before DSM. */
>> + sync_l2_cache
>> +
>> + ldr r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
>> + /*
>> + * put DDR explicitly into self-refresh and
>> + * disable automatic power savings.
>> + */
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + orr r7, r7, #0x1
>> + str r7, [r11, #MX6Q_MMDC_MAPSR]
>> +
>> + /* make the DDR explicitly enter self-refresh. */
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + orr r7, r7, #(1 << 21)
>> + str r7, [r11, #MX6Q_MMDC_MAPSR]
>> +
>> +poll_dvfs_set_1:
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + ands r7, r7, #(1 << 25)
>> + beq poll_dvfs_set_1
>> +
>> + ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
>> + ldr r6, =0x0
>> + ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
>> + ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET
>
> If we add the following instruction here
>
> add r8, r0, r8
>
>> +set_mmdc_io_lpm:
>> + ldr r9, [r0, r8]
>
> , it can be replaced by the following one
>
> ldr r9, [r8], #0x8
>
>> + str r6, [r11, r9]
>> + add r8, r8, #0x8
>
> , and then we can save this one in the loop, right?
>
>> + sub r7, r7, #0x1
>> + cmp r7, #0x0
>
> The sequence of 'sub ...; cmp ..., #0' and 'and ...; cmp ..., #0' can
> generally be replaced by 'subs ...' and 'ands' respectively to save one
> instruction, right?
>
> The above two comments apply to a few other places in the code.
>
>> + bne set_mmdc_io_lpm
>> +
>> + /*
>> + * mask all GPC interrupts before
>> + * enabling the RBC counters to
>> + * avoid the counter starting too
>> + * early if an interupt is already
>> + * pending.
>> + */
>> + ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
>> + ldr r6, [r11, #MX6Q_GPC_IMR1]
>> + ldr r7, [r11, #MX6Q_GPC_IMR2]
>> + ldr r8, [r11, #MX6Q_GPC_IMR3]
>> + ldr r9, [r11, #MX6Q_GPC_IMR4]
>> +
>> + ldr r10, =0xffffffff
>> + str r10, [r11, #MX6Q_GPC_IMR1]
>> + str r10, [r11, #MX6Q_GPC_IMR2]
>> + str r10, [r11, #MX6Q_GPC_IMR3]
>> + str r10, [r11, #MX6Q_GPC_IMR4]
>> +
>> + /*
>> + * enable the RBC bypass counter here
>> + * to hold off the interrupts. RBC counter
>> + * = 32 (1ms), Minimum RBC delay should be
>> + * 400us for the analog LDOs to power down.
>> + */
>> + ldr r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
>> + ldr r10, [r11, #MX6Q_CCM_CCR]
>> + bic r10, r10, #(0x3f << 21)
>> + orr r10, r10, #(0x20 << 21)
>> + str r10, [r11, #MX6Q_CCM_CCR]
>> +
>> + /* enable the counter. */
>> + ldr r10, [r11, #MX6Q_CCM_CCR]
>> + orr r10, r10, #(0x1 << 27)
>> + str r10, [r11, #MX6Q_CCM_CCR]
>> +
>> + /* unmask all the GPC interrupts. */
>> + ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
>> + str r6, [r11, #MX6Q_GPC_IMR1]
>> + str r7, [r11, #MX6Q_GPC_IMR2]
>> + str r8, [r11, #MX6Q_GPC_IMR3]
>> + str r9, [r11, #MX6Q_GPC_IMR4]
>> +
>> + /*
>> + * now delay for a short while (3usec)
>> + * ARM is at 1GHz at this point
>> + * so a short loop should be enough.
>> + * this delay is required to ensure that
>> + * the RBC counter can start counting in
>> + * case an interrupt is already pending
>> + * or in case an interrupt arrives just
>> + * as ARM is about to assert DSM_request.
>> + */
>> + ldr r6, =2000
>> +rbc_loop:
>> + sub r6, r6, #0x1
>> + cmp r6, #0x0
>> + bne rbc_loop
>> +
>> + /* Zzz, enter stop mode */
>> + wfi
>> + nop
>> + nop
>> + nop
>> + nop
>> +
>> + /*
>> + * run to here means there is pending
>> + * wakeup source, system should auto
>> + * resume, we need to restore MMDC IO first
>> + */
>
> The MMDC restoring code looks identical between the case of wakeup
> source pending and the normal resume case, except that the former runs
> at virtual address and the later runs at the physical. Can we make
> a macro for it to save some code duplication?
>
> Shawn
>
>> + ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
>> + ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
>> + ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET
>> +restore_mmdc_io:
>> + ldr r8, [r0, r7]
>> + add r7, r7, #0x4
>> + ldr r9, [r0, r7]
>> + add r7, r7, #0x4
>> + str r9, [r11, r8]
>> + sub r6, r6, #0x1
>> + cmp r6, #0x0
>> + bne restore_mmdc_io
>> +
>> + ldr r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
>> + /* let DDR out of self-refresh. */
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + bic r7, r7, #(1 << 21)
>> + str r7, [r11, #MX6Q_MMDC_MAPSR]
>> +
>> +poll_dvfs_clear_2:
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + ands r7, r7, #(1 << 25)
>> + bne poll_dvfs_clear_2
>> + /* enable DDR auto power saving */
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + bic r7, r7, #0x1
>> + str r7, [r11, #MX6Q_MMDC_MAPSR]
>> + /* return to suspend finish */
>> + mov pc, lr
>> +
>> +resume:
>> + /* invalidate L1 I-cache first */
>> + mov r6, #0x0
>> + mcr p15, 0, r6, c7, c5, 0
>> + mcr p15, 0, r6, c7, c5, 0
>> + mcr p15, 0, r6, c7, c5, 6
>> + /* enable the Icache and branch prediction */
>> + mov r6, #0x1800
>> + mcr p15, 0, r6, c1, c0, 0
>> + isb
>> +
>> + /* get physical resume address from pm_info. */
>> + ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
>> + /* clear core0's entry and parameter */
>> + ldr r11, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET]
>> + mov r7, #0
>> + str r7, [r11, #MX6Q_SRC_GPR1]
>> + str r7, [r11, #MX6Q_SRC_GPR2]
>> +
>> + ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET]
>> + ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
>> + ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET
>> +dsm_restore_mmdc_io:
>> + ldr r8, [r0, r7]
>> + add r7, r7, #0x4
>> + ldr r9, [r0, r7]
>> + add r7, r7, #0x4
>> + str r9, [r11, r8]
>> + sub r6, r6, #0x1
>> + cmp r6, #0x0
>> + bne dsm_restore_mmdc_io
>> +
>> + ldr r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET]
>> + /* let DDR out of self-refresh */
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + bic r7, r7, #(1 << 21)
>> + str r7, [r11, #MX6Q_MMDC_MAPSR]
>> +
>> +poll_dvfs_clear_1:
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + ands r7, r7, #(1 << 25)
>> + bne poll_dvfs_clear_1
>> + /* enable DDR auto power saving */
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + bic r7, r7, #0x1
>> + str r7, [r11, #MX6Q_MMDC_MAPSR]
>> + mov pc, lr
>> +ENDPROC(imx6_suspend)
>> --
>> 1.7.9.5
>
More information about the linux-arm-kernel
mailing list