一、start.S 解析5
注释的中文含义:
当我们已经在 RAM 中运行时,我们不需要重新定位 U-Boot。实际上,在 U-Boot 在 RAM 中运行之前,必须配置内存控制器。
1、判断当前代码执行位置
(1) lowlevel_init.S 的 110-115 行。
(2) 这几行代码的作用,就是判定当前代码执行的位置在芯片内部 SRAM 中还是在 DDR 内存中。
为什么要做这个判定?
原因1:BL1(uboot 的前一部分)在 SRAM 中有一份,在 DDR 中也会有一份(从 SRAM 中copy 过去的)。因此如果是冷启动,那么当前代码应该是在 SRAM 中运行的 BL1;如果是低功耗状态的复位,这时候应该就是在 DDR 中运行的。
原因2:我们判定 “当前运行代码的地址” 是有用的,可以指导后面代码的运行。譬如在 lowlevel_init.S 中判定当前代码的运行地址,就是为了确定:要不要执行 “时钟初始化和初始化 DDR” 的代码。如果当前代码是在 SRAM 中,说明是冷启动,那么时钟和 DDR 都需要初始化;如果当前代码是在 DDR 内存中,那么说明是热启动,则时钟和 DDR 都不用再次初始化。
(3) bic r1, pc, r0
这句代码的意义是:将 pc 的值中的某些 bit 位清0,剩下一些特殊的 bit 位赋值给 r1( r0 中为 1 的那些位清零)相等于:r1 = pc & ~(ff000fff)
ldr r2, _TEXT_BASE
加载链接地址到 r2,然后将 r2 的相应位清 0 ,剩下特定的位。
(4) 最后比较 r1 和 r2.
总结:这一段代码是通过读取当前运行地址和链接地址,然后处理两个地址后对比是否相等,来判定当前运行是在 SRAM中(如果不相等)还是 DDR 中(如果相等)。从而决定是否跳过下面的时钟和 DDR 初始化。
2、system_clock_init
(1) 搜索 system_clock_init,确定这个函数就在当前文件的 205 行,一直到 第385 行。这个初始化时钟的过程和裸机中初始化的过程一样的,只是更加完整而且是用汇编代码写的。
(2) 在 x210_sd.h 中 300 行到 428 行,都是和时钟相关的配置值。这些宏定义就决定了 210 的时钟配置是多少。也就是说代码在 lowlevel_init.S 中都写好了,但是代码的设置值都被宏定义在 x210_sd.h 中了。因此,如果移植时需要更改 CPU 的时钟设置,根本不需要动代码,只需要在 x210_sd.h 中更改配置值即可。
时钟频率的参数宏,来自于《S5PV210_UM_REV1.1.pdf》文档。
二、start.S 解析6
1、mem_ctrl_asm_init
(1) 该函数用来初始化 DDR。
(2) 函数位置在 uboot/cpu/s5pc11x/s5pc110/cpu_init.S
文件中。
(3) 该函数和裸机中初始化 DDR 代码是一样的。实际上裸机中初始化 DDR 的代码就是从这里抄的。配置值也可以从这里抄,但是当时我自己根据理解+抄袭整出来的一份。
(4) 配置值中其他配置值参考裸机中的解释即可明白,有一个和裸机中讲的不一样。
DMC0_MEMCONFIG_0
,在裸机中配置值为 0x20E01323
;在 uboot 中配置为 0x30F01313
. 这个配置不同就导致结果不同。
在 裸机中,DMC0 的 256MB 内存地址范围是 0x20000000-0x2FFFFFFF;
在uboot中,DMC0 的 256MB 内存地址范围为 0x30000000-0x3FFFFFFF。
(DMC1 的配置都是一样的,0x4000,0000 ~ 0x4FFF,FFFF,一共 256M。)
(5) 之前在裸机中时,配置为 2 开头的地址,当时并没有说可以配置为 3 开头的地址。从分析九鼎移植的 uboot 可以看出:DMC0 上允许的地址范围是 0x2000,0000 ~ 0x3FFF,FFFF(一共是512MB),而我们实际只接了 256MB 物理内存,SoC 允许我们给这 256MB 挑选地址范围。
(6) 总结一下:在 uboot 中,可用的物理地址范围为:0x30000000 ~ 0x4FFFFFFF。一共512MB,其中 0x3000,0000 ~ 0x3FFF,FFFF 为 DMC0,0x4000,0000 ~ 0x4FFF,FFFF为 DMC1。
(7) 我们需要的内存配置值在 x210_sd.h 的 438 行到 468 行之间。分析的时候要注意条件编译的条件,配置头文件中考虑了不同时钟配置下的内存配置值,这个的主要目的是让不同时钟需求的客户都能找到合适自己的内存配置值。
(8) 在 uboot 中 DMC0 和 DMC1 都工作了。所以在裸机中,只要把 uboot 中的配置值和配置代码全部移植过去,应该是能够让 DMC0 和 DMC1 都工作的。
2、uart_asm_init
(1) 这个函数用来初始化串口。
(2) 初始化完了后通过串口发送了一个’O’ 字符。
3、tzpc_init
(1) trust zone初始化,没搞过,不管。
4、pop {pc} 以返回
(1) 返回前通过串口打印 ‘K’ 字符。
分析:lowlevel_init.S 执行完如果没错误,那么就会串口打印出 “OK” 字样。这应该是我们 uboot 中看到的最早的输出信息。
源自朱有鹏老师.