i.MX35 suspender CPU y DDR2 de IRAM
Tengo que poner mi dispositivo en un modo de baja potencia muy profundo desde Linux 2.6.38 y, por lo tanto, es necesario suspender todos los componentes, incluidos CPU y DDR2.
Lo que descubrí hasta ahora es que tengo que copiar la función del ensamblador central en la memoria interna del procesador y ejecutarla desde allí. Básicamente, se ve así:
cpaddr = iram_alloc(SZ_1K, &iram_addr);
if(!cpaddr) return -ENOMEM;
suspend_iram_base = __arm_ioremap(iram_addr, SZ_1K, MT_HIGH_VECTORS);
memcpy(suspend_iram_base, cpu_v6_sdram_off, SZ_1K);
flush_icache_range(suspend_iram_base, suspend_iram_base + SZ_1K);
flush_cache_all();
__asm__ __volatile__(
"ldr r0, %0\n"
"ldr r1, %1\n"
"ldr r2, %2\n"
"blx r2\n"
"nop\n"
: : "m" (esdctl_addr),
"m" (csd0_addr),
"m" (suspend_iram_base));
Hasta ahora todo funciona como se esperaba, puedo verificar la ejecución del código desde la memoria interna (en el espacio de direcciones virtuales) con el depurador JTAG.
Si lo entiendo todo correctamente, tengo que hacer lo siguiente en la función IRAM:
deshabilitar interrupciones y cachésconfigurar el controlador SDRAM en modo de apagado de precargaejecute una precarga de todos los comandos y acceda a la memoria con A10 alto (por ejemplo, 0x400) para cerrar todos los bancosponer la CPU en espera ejecutando una instrucción WFIvuelva a habilitar todo después (excluido en el código fuente a continuación)El código correspondiente se ve así:
ENTRY(cpu_v6_sdram_off)
@ r0: esdctl base address
@ r1: csd0 address with a10 high
cpsid if
@ disable I and D cache
mrc p15, 0, r2, c1, c0, 0
bic r2, r2, #0x00001000 @ disable I cache
bic r2, r2, #0x00000004 @ disable D cache
mcr p15, 0, r2, c1, c0, 0
@ invalidate I cache
mov r2, #0
mcr p15, 0, r2, c7, c5, 0
@ clear and invalidate D cache
mov r2, #0
mcr p15, 0, r2, c7, c14, 0
@ precharge power down mode
ldr r2, [r0]
bic r2, r2, #0xc00
orr r2, r2, #0x400
str r2, [r0]
@ precharge all command
mov r2, #0x92
lsl r2, #24
orr r2, r2, #0x228000
orr r2, r2, #0x0400
str r2, [r0]
mov r2, #0x12
lsl r2, #24
orr r2, r2, #0x340000
orr r2, r2, #0x5600
orr r2, r2, #0x78
str r2, [r1] @ dummy write access
@ execute wait for interrupt
mov r1, #0
mcr p15, 0, r1, c7, c10, 4
mcr p15, 0, r1, c7, c0, 4
cpsie if
bx lr
ENDPROC(cpu_v6_sdram_off)
El problema está en el punto donde se accede a la RAM con una escritura ficticia. Simplemente da como resultado una excepción de cancelación de datos y luego la CPU se pierde. Si dejo esta parte, el DDR2 no parece estar en modo de bajo consumo, porque el consumo de corriente no baja.
Ahora estoy totalmente atascado y sin ideas aquí. ¿Podría alguien darme una pista de lo que estoy haciendo mal o de lo que me estoy perdiendo aquí? ¿O hay alguna documentación o código fuente disponible que demuestre todo el procedimiento para el i.MX35 en Linux?