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?

questionAnswers(2)

yourAnswerToTheQuestion