Bootloader启动过程可分为单阶段和多阶段。通常多阶段 Bootloader它可以提供更复杂的功能和更好的可移植性。从固态存储设备上启动 Bootloader大部分是两个阶段的启动过程。在第一阶段,它依赖于汇编来完成CPU系统结构的初始化,并调用第二阶段的代码;第二阶段通常使用C语言来实现更复杂的功能,代码具有更好的可读性和可移植性。
嵌入式高级教程分类整理,看起来很方便。因为内容多,这里截取一些图片。
需要的朋友可以通过私信内核获得。
一般来说,这两个阶段的功能可以分类如下:
Bootloader功能的第一阶段硬件设备的初始化首先,需要设置时钟MPLL(详见下面FCLK HCLK PCLK 部分)。接着设置CLKDIVN地址为0x4C000014,写入0x05表示设置分频系数为FCLK:HCLK:PCLK=1:4:8。然后关闭看门狗,关闭中断,启动ICACHE,关闭DCACHE和TLB,关闭MMU(ICACHE对于指令缓存,可以直接操作的硬件和实际物理地址不关闭。但是DCACHE此时必须关闭MMU虚拟地址映射失败,sdram无法访问,DCACHE无数据)。start.s具体代码如下:
/* 设置时钟 */ldr r0, =0x4c000014//mov r1, #0x03;mov r1, #0x05; // FCLK:HCLK:PCLK=1:4:8str r1,[r0]/* 如果HDIVN非0,CPU总线模式应从fast bus mode”变为“asynchronous bus mode” */mrc p15, 0, r1, c1, c0, 0/* 读取控制寄存器 */ orr r1, r1, #0xc0000000 /* 设置为“asynchronous bus mode” */mcr p15, 0, r1, c1, c0, 0/* 写入控制寄存器 *//* MPLLCON = S3C2440_MPLL_200MHZ */ldr r0, =0x4c000004ldr r1, =S3C2440_MPLL_400MHZstr r1,[r0]/* 启动ICACHE */mrc p15, 0, r0, c1, c0, 0@ read control regorr r0, r0, #(1<<12)mcr p15, 0, r0, c1, c0, 0@ write it back
这里具体说说如何设置FCLK HCLK PCLK。 FCLK又称为内核时钟,是提供给ARM920T 的时钟。 FCLK又称为内核时钟,是提供给ARM920T 的时钟。HCLK又称为
总线时钟,为存储器控制器提供中断控制器,LCD 控制器,DMA 和 USB 主机模块的 AHB总线(advanced high-performance bus)的时钟。 ?PCLK又称为
I/O接口时钟,为外设提供WDT,IIS,I2C,PWM 定时器,MMC/SD 接口,ADC,UART,GPIO,RTC 和SPI的 APB (advanced peripherals bus)总线时钟。
S3C2440 FLCK值为400MHz,HCLK值为100MHz、PCLK值为50MHz。那么如何计算这些值呢?S3C2440上的时钟源是12MHz,如果想让CPU在更高的频率下工作需要通过PLL(锁相环)提高主频。S3C2440上的PLL有两种,一种是MPLL,它是用来生产的FCLK、HCLK、PCLK高频工作时钟;还有一个UPLL,用来为USB提供工作频率。S3C2440时钟系统如下:从时序图可以看出,如果上电后什么都没设置,FCLK等于晶振的频率。当设置PLL后,CPU设置的高频时钟不是马上用的,而是有一段锁定时间,CPU停止运行,等待12MHz在高频时钟稳定后,整个系统重新运行。
开启MPLL的过程: 1、设置LOCKTIME设置变频锁定时间2FCLK晶振输入频率(Fin)的倍数 、设置FCLK,HCLK,PCLK手册上可以看到三者之间的比例,LOCKTIME默认时间为0xFFFFFFFF,控制方法如图所示:刚刚设置PLL当,系统认为这是PLL还没稳定,此时不需要一切PLL用外部晶振制作时钟的时钟PLL锁住,过了LOCKTIME后认为PLL使用前已稳定PLL为系统提供时钟)FCLK与Fin的倍数通过MPLLCON寄存器设置,三者关系如下: MPLL(FCLK) = (2 * m * Fin)/(p*2^s) 其中:m = MDIV 8, p = PDIV 2, s = SDIV ???PLL配置寄存器如图所示:当设置完MPLL之后,它将自动进入LockTime变频锁定期间,LOCKTIME之后,MPLL稳定时钟频率的输出。 电脑 FCLK、HCLK、PCLK如图所示:如果HDIV设置为非0,CPU改变总线模式,默认情况下FCLK = HCLK,CPU工作在fast bus mode在快速总线模式下,HDIV设置为非0后, FCLK与HCLK不再相等,要将CPU改为asynchronous bus mod可通过以下嵌入汇编代码实现异步总线模式:__asm__( "mrc p15, 0, r1, c1, c0, 0\
" /* 读取控制寄存器 */ "orr r1, r1, #0xc0000000\
" /* 设置为“asynchronous bus mode” */ "mcr p15, 0, r1, c1, c0, 0\
" /* 写入控制寄存器 */ );
为加载 Bootloader代码准备的第二阶段RAM空间(初始内存空间)lowlevel_init中设置相应BANK地址,主要用于设置SDRAM。内存在0中映射x30000000-0x40000000的位置,即
bank6与bank7。内存在0中映射x30000000-0x40000000的位置,即bank6与bank7
。所以在设置内存时序时,主要关心的是bank6与bank7。当然,bank0也需要注意,因为它是启动程序存储的位置。但是bank0是由OM[1:0],即板上的两个小开关来控制,所以这里的程序不需要管理。
接下来,设置栈地址指向NAND,准备初始化NANDFLASH。
初始化NANDFLASH,包括设置时序NFCONF,(参考芯片手册和2440手册nandflsh)。TACLS建立所表示的时间,TWRPH0表示nWE编写控制信号的持续时间,TWRPH1表示数据生效所需的时间,以及何时可以读取数据。TACLS建立所表示的时间,TWRPH0表示nWE编写控制信号的持续时间,TWRPH1表示数据生效所需的时间,以及何时可以读取数据。 最后是使能NFCONT NAND Flash控制器,初始化ECC, 电脑 禁止片选。到这里,NANDFLASH初始化已经完成。以下是重定位。void nand_init_ll(void){#define TACLS 0#define TWRPH0 1#define TWRPH1 0/* 设置时序 */NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);/* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */NFCONT = (1<<4)|(1<<1)|(1<<0);}
Bootloader代码的第二阶段SDRAM空间(重定位)首先判断是NOR启动还是NAND如果是,启动NAND启动时直接复制数据。在复制代码之前,将三个参数、源、目的和长度传递给复制函数。在复制代码之前,将三个参数、源、目的和长度传递给复制函数。NAND如果芯片手册NAND读取数据的时序,选择NAND,发出阅读命令,发出地址,发出阅读命令,判断状态,阅读数据,取消中等选择。
bl copy_code_to_sdrambl clear_bss //清除bss段(参考自制uboot章节)
最后要清除bss。bss段不占空间,是未初始化的全局变量或已初始化为零的变量,本来是零,直接清零就好。bss段落不占用空间,是未初始化的全球变量或已初始化为零的变量,最初是零,直接清除。未初始化的变量可能有未知的值。
设置好栈设置栈跳转SDRAM执行。ldr pc,=call_board_init_f //绝对跳转,跳转SDRAM上执行
跳转到第二阶段代码的C入口点跳转到SDRAM执行剩余程序。call_board_init_f:.globl base_spbase_sp:.long 0ldrr0,=0x00000000blboard_init_f/*unsigned int id 的值存在r0中,正好给board_init_r使用*/ldr r1, =_TEXT_BASE/*重新设置栈到以前的位置 指向原来addr_sp = 128;*/ldr sp,base_sp /*调用第二阶段代码*/bl
bo
电脑