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:- _omap_sram_idle() assignment (notice that first parameter that is passed to it is
omap34xx_cpu_suspend
function address) - omap_sram_push() implementation; pay attention to memcpy() call:
omap_sram_ceil
is start address of SRAM memory,start
is address ofomap34xx_cpu_suspend() function
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.
*/
- _omap_sram_idle() assignment (notice that first parameter that is passed to it is
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()
whenwfi
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
Temporarily Prevent Linux from Shutting Down
Windows Equivalent of ./ (Current Directory)
Arm Assembly "Retne" Instruction
Linux Assembler Error "Impossible Constraint in 'Asm'"
Accessing Files Outside the Document Root with Apache
"Cannot Write to Log File Pg_Upgrade_Internal.Log" When Upgrading from Postgresql 9.1 to 9.3
Add Suffix to Each Line with Shell Script
How to Replace a Multi Line String in a Bunch Files
Linux: Instantiate from User-Space:Eeprom New_Device
Parsing Data from Ifconfig with Awk or Sed
Does Using Xvfb to Run Opengl Effects Version
Analyzing CPU Registers During Kernel Crash Dump
Bash (Or Other Shell): Wrap All Commands with Function/Script
Is It Good Practice to Use Mkdir as File-Based Locking on Linux
How to Capitalize First Letter of Each Line in Bash
Clear Screen in a Linux Terminal Using Assembly
What Does the Line '!/Bin/Sh -E' Do
How to Convert a Linux Executable File (Binary) to Windows Exe File