1

我试图弄清楚如何实现挂起/唤醒mach-omap2,特别是在针对 TI OMAP3530/DM3730 的 Linux 2.6.37 中。

下面是一些相关代码:

http://lxr.free-electrons.com/source/arch/arm/mach-omap2/pm34xx.c?v=2.6.37

static int omap3_pm_suspend(void)
{
    struct power_state *pwrst;
    int state, ret = 0;

    if (wakeup_timer_seconds || wakeup_timer_milliseconds)
        omap2_pm_wakeup_on_timer(wakeup_timer_seconds,
                     wakeup_timer_milliseconds);

    /* Read current next_pwrsts */
    list_for_each_entry(pwrst, &pwrst_list, node)
        pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
    /* Set ones wanted by suspend */
    list_for_each_entry(pwrst, &pwrst_list, node) {
        if (omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
            goto restore;
        if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
            goto restore;
    }

    omap_uart_prepare_suspend();
    omap3_intc_suspend();

    omap_sram_idle();

restore:
    /* Restore next_pwrsts */
    list_for_each_entry(pwrst, &pwrst_list, node) {
        state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
        if (state > pwrst->next_state) {
            printk(KERN_INFO "Powerdomain (%s) didn't enter "
                   "target state %d\n",
                   pwrst->pwrdm->name, pwrst->next_state);
            ret = -1;
        }
        omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
    }
    if (ret)
        printk(KERN_ERR "Could not enter target state in pm_suspend\n");
    else
        printk(KERN_INFO "Successfully put all powerdomains "
               "to target state\n");

    return ret;
}

我真的很难理解它是如何工作的。

看起来,当挂起过程运行到 afteromap_sram_idle();时,系统已经处于挂起模式,并且在这个函数的上下文中,一切都在那里冻结。当它醒来时,它只是继续restore:并恢复一切。这个对吗?

4

1 回答 1

3

系统挂起发生. omap_sram_idle()第二部分omap_sram_idle()实际上是恢复代码。更准确地说,实际的休眠是由汇编函数wfi中的 ARM 指令完成的。omap34xx_cpu_suspend()进一步阅读了解详情。

暂停路径

  • 看看omap_sram_idle()函数实现
  • 你可以看到(从评论来看)系统进入睡眠状态之前的最后一行是_omap_sram_idle()call (这里
  • _omap_sram_idle()指向omap34xx_cpu_suspend()汇编程序函数,该函数之前复制到SRAM(因此在 RAM 断电期间不会丢失);看看下一行代码:

    1. _omap_sram_idle() 赋值(注意传递给它的第一个参数是omap34xx_cpu_suspend函数地址)
    2. omap_sram_push()实现;注意memcpy() 调用omap_sram_ceil是 SRAM 内存的起始地址,startomap34xx_cpu_suspend() function
    3. omap34xx_cpu_suspend()实现;它是在这一行执行的实际函数(而不是_omap_sram_idle())。看看这个函数上面的注释:

      /*
       * Forces OMAP into idle state
       *
       * omap34xx_suspend() - This bit of code just executes the WFI
       * for normal idles.
       *
       * Note: This code get's copied to internal SRAM at boot. When the OMAP
       *       wakes up it continues execution at the point it went to sleep.
       */
      
  • 实际睡眠发生在wfi(等待中断)ARM 指令(omap34xx_cpu_suspend()函数中)中;处理器将休眠,并且仅在发生某些 IRQ 时才会唤醒

  • omap34xx_cpu_suspend()when有两个地方wfi可以执行:
    • 如果不需要上下文保存:这里
    • 如果需要上下文保存:这里

恢复路径

一旦某个唤醒信号发生,CPU 将在指令之后继续执行指令wfi(首先使其进入睡眠状态)。所以你的系统在汇编函数中唤醒omap34xx_cpu_suspend()(从wait_sdrk_ok:标签开始),然后返回omap_sram_idle()(到这一行),然后返回到omap3_pm_suspend(), 到restore:标签。

于 2015-05-20T21:28:52.007 回答