本视频是在u-boot-1.1.6的基础上进行修改。
我们仿照cmd_menu命令(对应cmd_menu.c(common)文件),添加一个cmd_suspend.c文件实现suspend命令。
U-boot中的每个命令都是通过这个宏来实现的(参数1表示在执行该命令时只要suspend一个参数就够了):
U_BOOT_CMD(
suspend, 1, 0, do_suspend,
"suspend - suspend the board\n",
" - suspend the board"
);
查看2440的芯片手册:
可知,进入2440的休眠模式需要以下步骤:
进入休眠模式的方法:
/* 1. 配置GPIO: 比如想维持LED亮或灭, 用于唤醒CPU的引脚要设为中断功能 */
Jz2440有四个按键,但是只有EINT0、EINT2、EINT11可以用作唤醒源(不明白为什么?),因此将S2(对应外部中断EINT0)、S3、S4这三个按键对应的引脚使能中断。
/* 2. 设置INTMSK屏蔽所有中断: 在sleep模式下,这些引脚只是用于唤醒系统(即使已经在第一步设置成了中断功能,但是也是起不到和正常一样的中断功能的),当CPU正常运行时可以重新设置INTMSK让这些引脚用于中断功能 */
rINTMSK = ~0;
/* 3. 配置唤醒源 */
(可以在这里设置这三个外部中断的中断触发方式,在2440芯片手册里搜索rising即可找到所用寄存器)
/* 4. 设置MISCCR[13:12]=11b, 使得USB模块进入休眠 */
/* 5. 在GSTATUS[4:3]保存某值, 它们可以在系统被唤醒时使用 */
rGSTATUS3 = ; //存放唤醒时首先执行的函数的地址.
rGSTATUS4 = ; //想存点什么就存点什么
/* 6. 设置 MISCCR[1:0] 使能数据总线的上拉电阻 */
/* 7. 清除 LCDCON1.ENVID 以停止LCD */
//8~12使用汇编来实现,参考内核源码/arch/arm/mach_s3c2410/sleep.S。但是为什么要使用汇编来实现? 新建suspend.S,保存到u-boot-1.1.6\cpu\arm920t\目录下,为什么要保存到这个目录下?
以下几步涉及到一个问题,那就是第11步到第12步的过度问题,如图所示,这两步之间还是有一部分代码要执行的,并且如果用到MMU,则还需要用到SDRAM中的页表。但是在将SDRAM设置为自刷新模式后,CPU将不能访问SDRAM中存放的指令(代码)及页表,那么这些要执行的代码及页表要去哪里取呢?
关于第二个问题,即页表的问题,内核的sleep.s中的前几行代码故意去读一下虚拟地址,映射关系就会存放在TLB中供临时使用,关闭SDRAM后,再去访问这些地址时,就可以从TLB中得到映射关系,而不需要去SDRAM上读取页表了。
同样的道理,关于第一个问题,即代码的问题,解决的方式是差不多的,就是在SDRAM关闭前,先读取一下,保存到Icache中,SDRAM关闭后,使用时直接从Icache中读取。如下图所示。
/* 8. 读这2个寄存器: rREFRESH and rCLKCON, 以便填充TLB
* 如果不使用MMU的话,这个目的可以忽略
*/
/* 9. 设置 REFRESH[22]=1b,让SDRAM进入self-refresh mode (这个模式下CPU将不能访问SDRAM中的指令)*/
/* 10. 等待SDRAM成功进入self-refresh mode */
/* 11.设置 MISCCR[19:17]=111b以保护SDRAM信号(SCLK0,SCLK1 and SCKE) */
/* 12. 设置CLKCON的SLEEP位让系统进入sleep mode */
附录:
在文件s3c_24x0.h中定义了各种宏(本节所用到的有关宏都是使用的该文件里定义的宏,没有再重新定义),比如: