O i.MX35 suspende a CPU e o DDR2 da IRAM
Eu tenho que colocar meu dispositivo em um modo de baixa energia muito profundo a partir do Linux 2.6.38 e, portanto, é necessário suspender todos os componentes, incluindo CPU e DDR2.
O que descobri até agora é que tenho que copiar a função do assembler principal na memória interna do processador e executá-la a partir daí. Basicamente, fica assim:
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));
Até agora tudo funciona como esperado, posso verificar a execução do código da memória interna (no espaço de endereço virtual) com o depurador JTAG.
Se eu entendi tudo corretamente, tenho que fazer o seguinte na função IRAM:
desativar interrupções e cachesDefina o controlador SDRAM no modo de pré-carga para desligarexecute uma pré-carga de todos os comandos e acesse a memória com A10 alto (por exemplo, 0x400) para fechar efetivamente todos os bancoscolocar a CPU em espera executando uma instrução WFIreative tudo depois (deixado de fora no código fonte abaixo)O código correspondente é assim:
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)
O problema está no ponto em que a RAM é acessada com uma gravação fictícia. Isso simplesmente resulta em uma exceção de abortamento de dados e a CPU se perde. Se eu deixar essa parte de fora, o DDR2 não parece ser colocado no modo de baixa energia, porque o consumo atual não diminui.
Agora estou totalmente preso e sem idéias aqui. Alguém poderia me dar uma dica do que estou fazendo de errado ou do que estou perdendo aqui? Ou existe alguma documentação ou código-fonte disponível demonstrando todo o procedimento para o i.MX35 no Linux?