i.MX35 从 IRAM 挂起 CPU 和 DDR2 [英] i.MX35 suspend CPU and DDR2 from IRAM

查看:31
本文介绍了i.MX35 从 IRAM 挂起 CPU 和 DDR2的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须让我的设备从 Linux 2.6.38 进入非常深的低功耗模式,因此,有必要暂停所有组件,包括 CPU 和 DDR2.

I have to put my device into a very deep low power mode from Linux 2.6.38 and therefore, it's necessary to suspend all components, including CPU und DDR2.

到目前为止我发现我必须将核心汇编器函数复制到处理器的内部存储器中并从那里执行它.基本上,它看起来像这样:

What I found out so far is that I have to copy the core assembler function into the processor's internal memory and execute it from there. Basically, it looks like this:

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));

到目前为止,一切都按预期进行,我可以使用 JTAG 调试器从内部存储器(在虚拟地址空间中)验证代码执行情况.

So far everything works as expected, I can verify code execution from internal memory (in virtual address space) with the JTAG debugger.

如果我理解正确,我必须在 IRAM 函数中执行以下操作:

If I understand it all correctly, I have to do the following in the IRAM function:

  • 禁用中断和缓存
  • 将 SDRAM 控制器设置为预充电断电模式
  • 执行预充电所有命令并以 A10 高电平(例如 0x400)访问内存以有效关闭所有 bank
  • 通过执行 WFI 指令使 CPU 进入待机状态
  • 之后重新启用所有内容(在下面的源代码中被遗漏了)

对应的代码如下:

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)

问题出在通过虚拟写入访问 RAM 的地方.它只会导致数据中止异常,然后 CPU 丢失.如果我不考虑这部分,DDR2 似乎不会进入低功耗模式,因为电流消耗不会下降.

The problem is at the point where the RAM is accessed with a dummy write. It simply results in a data abort exception and then the CPU gets lost. If I leave this part out, the DDR2 doesn't seem to be put into low power mode, because the current consumption doesn't go down.

现在我完全陷入困境并且没有想法.有人可以给我一个提示,我做错了什么或者我在这里遗漏了什么?或者是否有任何文档或源代码可用于演示 Linux 上 i.MX35 的整个过程?

Now I'm totally stuck and out of ideas here. Could someone please give me a hint what I'm doing wrong or what I'm missing here? Or is there any documentation or source code available demonstrating the whole procedure for the i.MX35 on Linux?

推荐答案

除了禁用 icachedcache,还需要清空所有缓冲区.我只在 IMX25 上实现了这个;它是一个 ARM926 (armv5).我现在正在为 armv7 开发,看起来 dcache 刷新可能合适.即,确保 CPU 将所有内容转储到 SDRAM.

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.

现在,您似乎也错过了关闭 MMU 的关键步骤.当您运行 str r2, [r1] @ dummy write access 时,您将遇到 TLB 未命中并尝试访问可能位于 SDRAM 中的页表.我看到一个问题;-).幸运的是,您拥有与 PC 相关的汇编程序,并且可以随时随地运行.

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.

这是在物理调用例程之前禁用 MMU 的示例函数.它适用于 ARMV5,您需要将 p15 值更新为 CPU 的等效功能.

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"
        );
}

r1r2 将使其进入通过物理内存调用的例程.您可以重新编码它以硬编码三个参数,然后将函数指针放入r4.但是,您的

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

必须更改为物理地址,以便cpu_v6_sdram_off运行时,将访问非虚拟地址.

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

这篇关于i.MX35 从 IRAM 挂起 CPU 和 DDR2的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆