Chinaunix首页 | 论坛 | 博客
  • 博客访问: 531097
  • 博文数量: 81
  • 博客积分: 1438
  • 博客等级: 上尉
  • 技术积分: 866
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-12 11:32
文章分类

全部博文(81)

文章存档

2014年(1)

2013年(1)

2012年(33)

2011年(46)

分类: 嵌入式

2012-03-19 11:37:59

1、源码包
Kernel   :linux-2.6.18.2
Uboot    :u-boot-1.1.4
Gcc      :arm-linux-gcc-3.4.1.tar.bz2
 
 
开发流程及详细步骤
1、休眠部分
1.       电源管理守护进程
省略
 
2.内核接口文件(arch/arm/kernel/apm.c)
电源守护进程通过apm.c的ioctl函数来使内核开始进入sleep模式。
case APM_IOC_SUSPEND:
        as->suspend_result = -EINTR;
        if (as->suspend_state == SUSPEND_READ) {
               as->suspend_state = SUSPEND_ACKED;
               suspends_pending--;
        } else {
               queue_event(APM_USER_SUSPEND, as);
        }
        if (suspends_pending == 0)
               apm_suspend(); //由此进入sleep
       调用的顺序如下:
3.进sleep前的准备工作
A.关闭系统进程(kernel/power/ console.c)
int pm_prepare_console(void) //该函数使所有系统进程休眠或关闭。
B.关闭外设驱动电源(drivers/base/power/suspend.c)
int device_power_down(pm_message_t state) //该函数使所有设备驱动sleep
4.进入sleep前的设置(arch/arm/mach-s3c2410/pm.c)
static int s3c2410_pm_enter(suspend_state_t state) //该函数引导进sleep前的设置
static int s3c2410_pm_enter(suspend_state_t state)
{
unsigned long regs_save[16];
unsigned long tmp;
s3c2410_pm_debug_init(); //sleep中uart不能再用,此函数实现uart重新初始化用来调试
DBG("s3c2410_pm_enter(%d)\n", state); //打印信息
if (state != PM_SUSPEND_MEM) {
        printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
        return -EINVAL;
} //判断是否是休眠只用ram实现,应为该项目不支持硬盘休眠功能。
if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) &&
    !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) {
        printk(KERN_ERR PFX "No sources enabled for wake-up!\n");
        printk(KERN_ERR PFX "Aborting sleep\n");
        return -EINVAL;
} //判断中断唤醒是否允许,不允许则不能进入休眠。
s3c2410_pm_check_prepare(); //如果需要在sleep前检查ram则此函数会运行,否则此函数为空,即如果CONFIG_S3C2410_PM_CHECK被定义。
s3c2410_sleep_save_phys = virt_to_phys(regs_save);
//将用来保存系统寄存器的数组地址转为物理地址,以供后面调用。
DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys); //打印信息
__raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3);
                             //将系统唤醒时需要调用的函数地址写入GSTATUS3寄存器。
DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3)); //打印信息
DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4)); //打印信息
s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));  //保存io口配置状态
s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));      //保存中断配置状态
s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));  //保存核心配置状态
s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));    //保存串口配置状态
s3c2410_pm_configure_extint(); //配置外部中断唤醒,使系统休眠中可以按键唤醒
DBG("sleep: irq wakeup masks: %08lx,%08lx\n",
    s3c_irqwake_intmask, s3c_irqwake_eintmask); //打印信息
__raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK);        //屏蔽系统定义中断
__raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK); //打开外部唤醒中断
__raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
//通过写已经被申请的位,将中断请求寄存器清空
arm920_flush_kern_cache_all(); //清缓冲区
s3c2410_pm_check_store();//如果需要在sleep前检查ram则此函数会运行,否则此函数为空,即如果CONFIG_S3C2410_PM_CHECK被定义。
__raw_writel(0x00, S3C2410_CLKCON);  //关闭所有外设时钟
s3c2410_cpu_suspend(regs_save); //调用汇编函数s3c2410_cpu_suspend 进入sleep。
/************************************************************************/
上为进入休眠部分,下为唤醒部分。
/************************************************************************/
cpu_init(); //CPU初始化
tmp = __raw_readl(S3C2410_GSTATUS2);
tmp &= S3C2410_GSTATUS2_OFFRESET;
__raw_writel(tmp, S3C2410_GSTATUS2); //清除唤醒复位标记
s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); //恢复核心配置
s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));       //恢复io口配置
s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));            //恢复中断配置
s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save));         //恢复串口配置
s3c2410_pm_debug_init(); //串口调试函数初始化
DBG("post sleep: IRQs 0x%08x, 0x%08x\n",
    __raw_readl(S3C2410_SRCPND),
    __raw_readl(S3C2410_EINTPEND)); //打印信息
s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND),
                          s3c_irqwake_intmask); //查看中断唤醒源信息
s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
                          s3c_irqwake_eintmask); //查看中断唤醒源信息
DBG("post sleep, preparing to return\n");
s3c2410_pm_check_restore();//如果需要在sleep前检查ram则此函数会运行,否则此函数为空,即如果CONFIG_S3C2410_PM_CHECK被定义。
DBG("S3C2410 PM Resume (post-restore)\n");
return 0;
}
5.进休眠前的最后汇编段程序(arch/arm/mach-s3c2410/sleep.s)
ENTRY(s3c2410_cpu_suspend)
stmfd      sp!, { r4 - r12, lr }
@@ store co-processor registers
mrc p15, 0, r4, c15, c1, 0     @ CP access register
mrc p15, 0, r5, c13, c0, 0     @ PID
mrc p15, 0, r6, c3, c0, 0       @ Domain ID
mrc p15, 0, r7, c2, c0, 0       @ translation table base address
mrc p15, 0, r8, c1, c0, 0       @ control register
stmia       r0, { r4 - r13 }
@@ flush the caches to ensure everything is back out to
@@ SDRAM before the core powers down
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
bl    arm920_flush_kern_cache_all
#endif
@@ prepare cpu to sleep
ldr   r4, =S3C2410_REFRESH
ldr   r5, =S3C24XX_MISCCR
ldr   r6, =S3C2410_CLKCON
ldr   r7, [ r4 ]         @ get REFRESH (and ensure in TLB)
ldr   r8, [ r5 ]         @ get MISCCR (and ensure in TLB)
ldr   r9, [ r6 ]         @ get CLKCON (and ensure in TLB)
orr   r7, r7, #S3C2410_REFRESH_SELF    @ SDRAM sleep command
orr   r8, r8, #(S3C2410_MISCCR_USBSUSPND0 | S3C2410_MISCCR_USBSUSPND1) @suspend usb
orr   r8, r8, #(S3C2400_MISCCR_SPUCR_LDIS | S3C2400_MISCCR_SPUCR_HDIS) @suspend d(0-31)
orr   r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
orr   r9, r9, #S3C2410_CLKCON_POWER    @ power down command
teq   pc, #0                   @ first as a trial-run to load cache
bl    s3c2410_do_sleep
teq   r0, r0                    @ now do it for real
b     s3c2410_do_sleep   @
@@ align next bit of code to cache line
.align      8
s3c2410_do_sleep:
streq       r7, [ r4 ]                @ SDRAM sleep command
    mov r0, #0x1000
1: subs r0, r0, #1          @wait until the SelfRefresh is released
    bne 1b
streq       r8, [ r5 ]                @ SDRAM power-down config
streq       r9, [ r6 ]                @ CPU sleep
1:     beq 1b
mov pc, r14
2、唤醒部分
1、Uboot部分(u-boot-1.1.4/cpu/arm920t/start.s)
reset:
#if 0
mrs r0, cpsr      /* Set the cpu to SVC32 mode */
bic   r0, r0, #0x1f
orr   r0, r0, #0xd3
msr cpsr, r0
#endif
/* disable watchdog timer */
mov r0, #WTCON_BASE
ldr r1, =0x0
str r1, [r0, #oWTCON]
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r0, #INT_BASE
ldr   r1, =0xffffffff
str    r1, [r0, #oINTMSK]
ldr   r1, =0x7ff
str    r1, [r0, #oINTSUBMSK]
mov r0, #CLK_BASE
ldr r1, =0xffffffff
str r1, [r0, #oLOCKTIME]
/* FCLK:HCLK:PCLK */
ldr r1, =0x0
str r1, [r0, #oCAMDIVN]
ldr r1, =_clkdivn
str r1, [r0, #oCLKDIVN]
mrc p15, 0, r1, c1, c0, 0           /* read ctrl register */
orr r1, r1, #0xc0000000           /* Asynchronous */
mcr p15, 0, r1, c1, c0, 0           /* write ctrl register */
/* UPLL setup */
ldr r1, =_upllcon
str r1, [r0, #oUPLLCON]
nop
nop
nop         /* wait until upll has the effect */
nop
nop
/* PLL setup */
ldr r1, =_mpllcon
str r1, [r0, #oMPLLCON]
/* configure memory */
bl    memset
/* Power Manage  Check if this is a wake-up from sleep */
ldr r1, PMST_ADDR
ldr r0, [r1]
@bic r0,r0,#0xfffffffd
tst r0, #(0x02)
bne WakeupStart
WakeupStart:
    /* Clear sleep reset bit */   
    ldr r0, PMST_ADDR
    mov r1, #0x0       @PMST_SMR
    str r1, [r0]
  
    ldr r0, PMCTL1_ADDR  /* Release the SDRAM signal protections */
    ldr r1, =0x00010330
   str r1, [r0]
   
    ldr r0, =0x48000024
    ldr r1, [r0]
    bic r1, r1, #0x400000
    str r1, [r0]
     
   mov r1, #0x1000
1: subs r1, r1, #1 /* wait until the SelfRefresh is released. */
    bne 1b
   
    /* Go... */  
    ldr r0, =0x560000B8 /* read a return address  go to s3c2410_cpu_resume*/
    ldr r1, [r0]
      
    mov pc, r1
    nop
    nop
1: b   1b      /* infinite loop */
 
 
2、Kernel部分
1.唤醒程序汇编部分(arch/arm/mach-s3c2410/sleep.s)
resume_with_mmu:
ldmfd       sp!, { r4 - r12, pc }
.ltorg
.data
.global     s3c2410_sleep_save_phys
s3c2410_sleep_save_phys:
.word       0
ENTRY(s3c2410_cpu_resume)
mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
msr cpsr_c, r0
mov r2, #S3C24XX_PA_UART & 0xff000000
orr   r2, r2, #S3C24XX_PA_UART & 0xff000
#if 0
/* SMDK2440 LED set */
mov r14, #S3C24XX_PA_GPIO
ldr   r12, [ r14, #0x54 ]
bic   r12, r12, #3<<4
orr   r12, r12, #1<<7
str    r12, [ r14, #0x54 ]
#endif
#ifdef CONFIG_DEBUG_RESUME
mov r3, #'L'
strb r3, [ r2, #S3C2410_UTXH ]
1001:
ldrb r14, [ r3, #S3C2410_UTRSTAT ]
tst    r14, #S3C2410_UTRSTAT_TXE
beq 1001b
#endif /* CONFIG_DEBUG_RESUME */
mov r1, #0
mcr p15, 0, r1, c8, c7, 0              @@ invalidate I & D TLBs
mcr p15, 0, r1, c7, c7, 0              @@ invalidate I & D caches
ldr   r0, s3c2410_sleep_save_phys @ address of restore block
ldmia      r0, { r4 - r13 }
mcr p15, 0, r4, c15, c1, 0            @ CP access register
mcr p15, 0, r5, c13, c0, 0            @ PID
mcr p15, 0, r6, c3, c0, 0              @ Domain ID
mcr p15, 0, r7, c2, c0, 0              @ translation table base
#ifdef CONFIG_DEBUG_RESUME
mov r3, #'R'
strb r3, [ r2, #S3C2410_UTXH ]
#endif
ldr   r2, =resume_with_mmu
mcr p15, 0, r8, c1, c0, 0              @ turn on MMU, etc
nop                              @ second-to-last before mmu
mov pc, r2                           @ go back to virtual address
.ltorg
2.唤醒恢复设置阶段(arch/arm/mach-s3c2410/pm.c)
static int s3c2410_pm_enter(suspend_state_t state) //该函数后半部分引导配置系统
cpu_init(); //CPU初始化
tmp = __raw_readl(S3C2410_GSTATUS2);
tmp &= S3C2410_GSTATUS2_OFFRESET;
__raw_writel(tmp, S3C2410_GSTATUS2); //清除唤醒复位标记
s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); //恢复核心配置
s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));       //恢复io口配置
s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));            //恢复中断配置
s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save));         //恢复串口配置
s3c2410_pm_debug_init(); //串口调试函数初始化
DBG("post sleep: IRQs 0x%08x, 0x%08x\n",
    __raw_readl(S3C2410_SRCPND),
    __raw_readl(S3C2410_EINTPEND)); //打印信息
s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND),
                          s3c_irqwake_intmask); //查看中断唤醒源信息
s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
                          s3c_irqwake_eintmask); //查看中断唤醒源信息
DBG("post sleep, preparing to return\n");
s3c2410_pm_check_restore();//如果需要在sleep前检查ram则此函数会运行,否则此函数为空,即如果CONFIG_S3C2410_PM_CHECK被定义。
DBG("S3C2410 PM Resume (post-restore)\n");
return 0;
3.恢复系统
A.开启外设驱动电源(drivers/base/power/resume.c)
int device_power_up(pm_message_t state) //该函数使所有设备驱动sleep
B.启动系统进程(kernel/power/ console.c)
void pm_restore_console(void) //该函数使所有系统进程休眠或关闭。
4.内核接口文件(arch/arm/kernel/apm.c)
由原接口退出sleep模式。
(
阅读(2695) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~