打印
[嵌入式linux]

请教2440或者6410的休眠唤醒问题

[复制链接]
4772|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
jkeqiang|  楼主 | 2010-11-6 16:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
以6410为例

休眠过程如下

static int s3c6410_pm_enter(suspend_state_t state)
{
unsigned long regs_save[16];
unsigned int tmp;
/* ensure the debug is initialised (if enabled) */
DBG("s3c6410_pm_enter(%d)\n", state);
if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) {
  printk(KERN_ERR PFX "error: no cpu sleep functions set\n");
  return -EINVAL;
}
/* prepare check area if configured */
s3c6410_pm_check_prepare();
/* store the physical address of the register recovery block */
s3c6410_sleep_save_phys = virt_to_phys(regs_save);
printk("s3c6410_sleep_save_phys=0x%08lx\n", s3c6410_sleep_save_phys);
/* save all necessary core registers not covered by the drivers */
s3c6410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
s3c6410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
s3c6410_pm_do_save(core_save, ARRAY_SIZE(core_save));
s3c6410_pm_do_save(sromc_save, ARRAY_SIZE(sromc_save));
/* ensure INF_REG0  has the resume address */
__raw_writel(virt_to_phys(s3c6410_cpu_resume), S3C_INFORM0);
/* set the irq configuration for wake */
s3c6410_pm_configure_extint();
/* call cpu specific preperation */
pm_cpu_prep();
/* flush cache back to ram */
flush_cache_all();
s3c6410_pm_check_store();
/* send the cpu to sleep... */
__raw_writel(0xffffffff, S3C64XX_VIC0INTENCLEAR);
__raw_writel(0xffffffff, S3C64XX_VIC1INTENCLEAR);
__raw_writel(0xffffffff, S3C64XX_VIC0SOFTINTCLEAR);
__raw_writel(0xffffffff, S3C64XX_VIC1SOFTINTCLEAR);
__raw_writel(1, S3C_OSC_STABLE);
__raw_writel(1, S3C_PWR_STABLE);
/* Set WFI instruction to SLEEP mode */
tmp = __raw_readl(S3C_PWR_CFG);
tmp &= ~(0x60<<0);
tmp |= (0x3<<5);
__raw_writel(tmp, S3C_PWR_CFG);
tmp = __raw_readl(S3C_SLEEP_CFG);
tmp &= ~(0x61<<0);
__raw_writel(tmp, S3C_SLEEP_CFG);
/* Clear WAKEUP_STAT register for next wakeup -jc.lee */
/* If this register do not be cleared, Wakeup will be failed */
tmp = __raw_readl(S3C_WAKEUP_STAT);
__raw_writel(tmp, S3C_WAKEUP_STAT);
/* ALL sub block "ON" before enterring sleep mode - EVT0 bug*/
__raw_writel(0xffffff00, S3C_NORMAL_CFG);
/* Open all clock gate to enter sleep mode - EVT0 bug*/
__raw_writel(0xffffffff, S3C_HCLK_GATE);
__raw_writel(0xffffffff, S3C_PCLK_GATE);
__raw_writel(0xffffffff, S3C_SCLK_GATE);
/* s3c6410_cpu_save will also act as our return point from when
  * we resume as it saves its own register state, so use the return
  * code to differentiate return from save and return from sleep */
if (s3c6410_cpu_save(regs_save) == 0) {
  flush_cache_all();
  pm_cpu_sleep();
}
/* restore the cpu state */
cpu_init();
/* restore the system state */
s3c6410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
s3c6410_pm_do_restore(sromc_save, ARRAY_SIZE(sromc_save));
s3c6410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));
s3c6410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
tmp = __raw_readl(S3C64XX_EINT0PEND);
__raw_writel(tmp, S3C64XX_EINT0PEND);
DBG("post sleep, preparing to return\n");
s3c6410_pm_check_restore();
/* ok, let's return from sleep */
DBG("S3C6410 PM Resume (post-restore)\n");
return 0;
}



唤醒过程如下
ENTRY(s3c6410_cpu_resume)
msr cpsr_c, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
ldr r2, =LL_UART  /* for debug */
#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
/* Initialise the GPIO state if we are debugging via the SMDK LEDs,
  * as the uboot version supplied resets these to inputs during the
  * resume checks.
*/
ldr r3, =S3C64XX_PA_GPIO
ldr r0, [ r3, #S3C64XX_GPNCON ]
bic r0, r0, #(S3C64XX_GPN_CONMASK(12) | S3C64XX_GPN_CONMASK(13) | \
     S3C64XX_GPN_CONMASK(14) | S3C64XX_GPN_CONMASK(15))
orr r0, r0, #(S3C64XX_GPN_OUTPUT(12) | S3C64XX_GPN_OUTPUT(13) | \
     S3C64XX_GPN_OUTPUT(14) | S3C64XX_GPN_OUTPUT(15))
str r0, [ r3, #S3C64XX_GPNCON ]
ldr r0, [ r3, #S3C64XX_GPNDAT ]
bic r0, r0, #0xf << 12   @ GPN12..15
orr r0, r0, #1 << 15   @ GPN15
str r0, [ r3, #S3C64XX_GPNDAT ]
#endif
/* __v6_setup from arch/arm/mm/proc-v6.S, ensure that the caches
  * are thoroughly cleaned just in case the bootloader didn't do it
  * for us. */
mov r0, #0
mcr p15, 0, r0, c7, c14, 0  @ clean+invalidate D cache
mcr p15, 0, r0, c7, c5, 0  @ invalidate I cache
mcr p15, 0, r0, c7, c15, 0  @ clean+invalidate cache
mcr p15, 0, r0, c7, c10, 4  @ drain write buffer
@@mcr p15, 0, r0, c8, c7, 0  @ invalidate I + D TLBs
@@mcr p15, 0, r0, c7, c7, 0  @ Invalidate I + D caches
ldr r0, s3c6410_sleep_save_phys
ldmia r0, { r4 - r13 }
mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID
mcr p15, 0, r5, c3, c0, 0 @ Domain ID
mcr p15, 0, r6, c2, c0, 0 @ Translation Table BASE0
mcr p15, 0, r7, c2, c0, 1 @ Translation Table BASE1
mcr p15, 0, r8, c2, c0, 2 @ Translation Table Control
mcr p15, 0, r10, c1, c0, 1 @ Auxiliary control register
mov r0, #0   @ restore copro access controls
mcr p15, 0, r11, c1, c0, 2 @ Co-processor access controls
mcr  p15, 0, r0, c7, c5, 4
ldr r2, =resume_with_mmu
mcr p15, 0, r9, c1, c0, 0  /* turn mmu back on */
nop
mov pc, r2    /* jump back */
.end



调试的过程中发现了一个问题
mcr p15, 0, r9, c1, c0, 0  /* turn mmu back on */
之后程序就飞了。
原因我明白,6410的sdram物理地址是50000000,开启mmu之后地址变为了c0000000。所以程序飞了。

目前想到了这个问题的两种解决办法。
1。内核运行后,一直保持50000000->50000000 和 c0000000->50000000的映射。
2。在sleep之前。remap一下,把虚拟地址的50000000和物理地址的50000000对应起来,唤醒之后,再去掉这个映射关系。

显然第二种关系比较好。(自己感觉理论可行,还没有来得及测试)


对于这个问题,想听听对电源管理熟悉的朋友的建议。
期待您的答复

相关帖子

沙发
liufang520| | 2011-6-2 14:52 | 只看该作者
我也遇到类似的问题,请问你有解决这个问题吗?楼上的。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

237

主题

313

帖子

2

粉丝