I.Mx35 Suspend CPU and Ddr2 from Iram

i.MX35 suspend CPU and DDR2 from IRAM

As well as disabling the icache and dcache, it is needed to drain any buffers. I have only implemented this on an IMX25; It is an ARM926 (armv5). I am now developing for an armv7 and it seems like a dcache flush maybe appropriate. Ie, ensure that the CPU dumps everything to SDRAM.

Now, it also seems you missed a key step of turning off the MMU. When you run str r2, [r1] @ dummy write access, you will get a TLB miss and try to access the page tables, which are probably in SDRAM. I see a problem ;-). Luckily you have assembler which is PC relative and will run anywhere, anytime.

Here is a sample function to disable the MMU before calling the routine physically. It is for the ARMV5, you need to update the p15 values to the functional equivalents for your CPU.

static void phys_execute(void /*@unused@*/ (*function_pointer)(void))
{
__asm volatile (
" push {r4-r12,lr} \n" /* save everything */
"1: mrc p15, 0, r15, c7, c14, 3 \n" /* armv5 specific.. */
" bne 1b \n" /* dcache clean */
" mov r8, #0 \n"
" mcr p15, 0, r8, c7, c5, 0 \n" /* invalidate icache */
" mcr p15, 0, r8, c7, c10, 4 \n" /* drain wb armv5 */
" mrc p15, 0, r10, c1, c0, 0 \n" /* caches/mmu off */
" bic r8, r10, #0x5 \n"
" bic r8, r8, #0x1000 \n"
" mcr p15, 0, r8, c1, c0, 0 \n"
" blx r0 \n" /* Call r0 */
" mcr p15, 0, r10, c1, c0, 0 \n" /* caches on..*
"1: mrc p15, 0, r15, c7, c14, 3 \n" /* armv5 again */
" mov r8, #0 \n"
" bne 1b \n"
" mcr p15, 0, r8, c7, c5, 0 \n"
" mcr p15, 0, r8, c7, c10, 4 \n"
" pop {r4-r12,pc} \n"
);
}

r1 and r2 will make it to the routine called via physical ram. You can re-jig this to hard code three parameters and then the function pointer to put it in r4. However, your

 @ r0: esdctl base address
@ r1: csd0 address with a10 high

must change to be physical addresses so that when cpu_v6_sdram_off runs, it will be accessing the non-virtual addresses.

How linux suspend/wakeup works for mach-omap2?

System suspend is happening in the middle of omap_sram_idle(). The second part of omap_sram_idle() is actually restoring code. More precisely, actual sleeping is done by wfi ARM instruction in omap34xx_cpu_suspend() assembler function. Read further for details.

Suspend path

  • take a look at omap_sram_idle() function implementation
  • you can see (judging from comments) that the last line before system falls to sleep is _omap_sram_idle() call (here)
  • _omap_sram_idle() points to omap34xx_cpu_suspend() assembler function, which copied previously to SRAM (so it will not be lost during RAM power-off); take a look at next lines of code:

    1. _omap_sram_idle() assignment (notice that first parameter that is passed to it is omap34xx_cpu_suspend function address)
    2. omap_sram_push() implementation; pay attention to memcpy() call: omap_sram_ceil is start address of SRAM memory, start is address of omap34xx_cpu_suspend() function
    3. omap34xx_cpu_suspend() implementation; it's the actual function being executed at this line (instead of _omap_sram_idle()). Take a look at comment above this function:

      /*
      * Forces OMAP into idle state
      *
      * omap34xx_suspend() - This bit of code just executes the WFI
      * for normal idles.
      *
      * 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.
      */
  • actual sleeping is happening in wfi (Wait For Interrupt) ARM instruction (in omap34xx_cpu_suspend() function); the processor will sleep and it will wake up only when some IRQ will happen

  • there are 2 places in omap34xx_cpu_suspend() when wfi can be executed:
    • if context save is not required: here
    • if context save is required: here

Restore path

Once some wake-up signal happened, CPU will continue to execute instructions just after wfi instruction (that have put it to the sleep in the first place). So your system wakes up in omap34xx_cpu_suspend() assembler function (starting from wait_sdrk_ok: label), then returns back to omap_sram_idle() (to this line), and then returns back to omap3_pm_suspend(), to restore: label.

Why does adding 1.0/3.0 numeric literal three times evaluates to exactly 1 in Golang?

According to The Go Programming Language Specification, “Constant expressions are always evaluated exactly…” This means the compiler (or other implementation) is required to do full real-number arithmetic to the extent required to evaluate a constant expression. Thus 1.0/3.0 + 1.0/3.0 + 1.0/3.0 is evaluated as ⅓ + ⅓ + ⅓, which is of course 1.



Related Topics



Leave a reply



Submit