i.MX35 从 IRAM 暂停 CPU 和 DDR2 [英] i.MX35 suspend CPU and DDR2 from IRAM

查看:27
本文介绍了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
"
  "ldr r1, %1
"
  "ldr r2, %2
"
  "blx r2
"
  "nop
"
  : : "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)访问内存以有效关闭所有银行
  • 通过执行 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}                 
" /* save everything */
        "1: mrc     p15, 0, r15, c7, c14, 3     
" /* armv5 specific.. */
        "   bne     1b                          
" /* dcache clean */
        "   mov     r8, #0                      
"
        "   mcr     p15, 0, r8, c7, c5, 0       
" /* invalidate icache */
        "   mcr     p15, 0, r8, c7, c10, 4      
" /* drain wb armv5 */
        "   mrc     p15, 0, r10, c1, c0, 0      
" /* caches/mmu off */
        "   bic     r8, r10, #0x5               
"
        "   bic     r8, r8, #0x1000             
"
        "   mcr     p15, 0, r8, c1, c0, 0       
"
        "   blx     r0                          
" /* Call r0 */
        "   mcr     p15, 0, r10, c1, c0, 0      
"  /* caches on..*
        "1: mrc     p15, 0, r15, c7, c14, 3     
"  /* armv5 again */
        "   mov     r8, #0                      
"
        "   bne     1b                          
"
        "   mcr     p15, 0, r8, c7, c5, 0       
"
        "   mcr     p15, 0, r8, c7, c10, 4      
"
        "   pop     {r4-r12,pc}                 
"
        );
}

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天全站免登陆