现在很多博客文章都有写到关于从uboot到linux,或者是android的话就是再到android层面上的启动过程。但很少文章会讲述到关于board lever 层面上的启动过程。我这里说的board level 是关于板子上电启动,硬件相关的开机流程。
好,咋们开门见山,不兜圈子。直接说如正题。
本文分为几部分:上电-->电源管理-->cpu启动-->uboot-->跳转启动device。下面正式介绍。
第一部分:上电
首先是上电,我们知道一般CPU的供电电压是3.3V,而输入电压在不通应用场合有不用的输入值:5V,12V,19V,24V等等。所以板子上电,首先有一个减压的过程,这个过程是经过降压电路或者是转压芯片,把高电压转换为CPU使用的低电压。这里所谓的“低电压”的范围比较广泛,除了包括cpu的使用电压外,还包括一些板子上外设的电压。这些电源都是根据具体情况而定,这里不做详细介绍。
第二部分:电源管理
对于电源管理这一块,可能不是每个平台都会有这个功能,但以经验来看,有电源管理的电路,稳定性肯定会更好,因为上电时序可以得到保证,而且对电路电压的开启跟关闭也能更有保障。
对于电源管理部分的上电时序大概如下(不同电路可能有所差异):
接受经过转压芯片转压后,电源IC启动起来,首先电源管理IC会给CPU上电,让CPU跑起来,在这过程中,cpu会初始化各种外设,反过来·通知电源管理IC去开启各种外设的电压。一般电源管理IC跟CPU之间的通讯是由i2c来完成。电源管理上电部分的过程基本如此,当然,电源管理部分包含的内容很多,还有:休眠唤醒,开关机等。有兴趣的话可以自行深入研究这一块的内容。这篇文字仅仅介绍到开机的流程部分。
第三部分:CPU启动:
首先提一个问题:CPU上电后,做的第一件事情是什么?
CPU上电第一件事并不是立即去flash 或者emmc的某一个地址去寻找程序,然后搬运到内存中运行。CPU上电的第一件事是跑自身里面的一段小程序,至于这一段小程序做了些什么内容,我们不得而知,这可能只有CPU厂家才能知道。不过接触过freescale 或者TI的CPU的人都知道,CPU连接着一个拨码开关,通过不同的拨号方式,CPU会从特定的位置:flash,emmc或者sata启动。
好,说到这里,就有所感觉了吧,最起码,我们知道对于freescale 或者TI的CPU而言,上电做的事情其中有一件就是:检测拨码开关电平,然后从相应的位置寻找代码。
说到这里,顺便提一下,每个厂家的CPU到device(flash,sd card,sata)寻找代码的地址可能有所区别,如以下一行烧录程序的脚本:
dd if=u-boot_crc.bin.crc of=${node} bs=512 seek=2
从这行脚本可以看出,这个CPU寻找程序的地方是位于(flash,sdcard,sata)的1K的地方处。仔细想想,这是有原因的,原因就是:对于任何一块存储器而言,开头的512K的地方是存放其私有数据和分区信息的地方,也就是我们常说的mbr。
第四部分Uboot:
当CPU从存储(flash,Sdcard,sata)找到程序后,首先是程序里面前4K的内容,也就是uboot里面的start.s ,负责初始化硬件,把整个uboot的代码load到ddr里面跑起来。这里面我们不分析这些代码的具体作用,我们分析的是uboot完成各系列的初始化工作之后,怎么跳转的。那么我们首先来看看以下一段代码:
/* load SD card */ if(!mmc_boot(0, 0x26800000, 0x03, 0x4B0))//read 600KB { printf("booting from SD\n"); *(int *)0x22200000 = 0x01; goto SECOND_LEVEL_BOOT; } /* load SATA */ if (!sata_boot(0, 0x26800000, 0x03, 0x4B0)) { printf("booting from SATA\n"); *(int *)0x22200000 = 0x02; goto SECOND_LEVEL_BOOT; } /* load iNAND */ if(!mmc_boot(1, 0x26800000, 0x03, 0x4B0))//read 600KB { printf("booting from iNAND\n"); *(int *)0x22200000 = 0x03; goto SECOND_LEVEL_BOOT; } /* load SPI */
相信以上一段代码很容易看得懂,先检查SD卡启动时候成功,如果是,则把0x01 装载到0x22200000这个地址里面,然后跳转到第二阶段的启动当中。如果SD卡不存在,则检测SATA。如果SATA不存在,最后检测iNAND。详细的情况,有兴趣的话可以去查看uboot里面相应的代码。
好,最后想说的是,如果知道这个启动流程,那么我们就可以做一些定制的启动服务,如指定在某一个存储器件的某一个地址需找code等等。