建议先看《[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)》,根据例子了解一下上电之后的BL0BL1BL2阶段,以及各个阶段的运行位置、功能。
一、说明
1、疑问
前面文章中《[uboot] (第三章)uboot流程——uboot-spl代码流程》中,最后uboot-spl的操作是调用board_init_f了,在board_init_f中实现了加载BL2镜像(uboot.bin)到ddr上,然后跳转到相应位置。
那么前面有个坑,就是tiny210的board_init_f中,是
如何实现加载BL2镜像(uboot.bin)到ddr上,然后跳转到BL2的相应地址上?
这个也就是本文里面的主要介绍的:
s5pv210是如何实现把镜像从存储设备上加载到ddr上的?
2、原理
通过《[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)》,
s5pv210的BL0会根据启动模式从相应存储设备上获取BL1的镜像到DDR上。
例如,当启动模式是SD boot的时候,BL0会从SD卡上获取BL1镜像,加载到对应位置上。当启动模式是nand flash boot的时候,BL0会从nand flash上获取BL1镜像,加载到对应位置上。
如下表格(从《[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)》截取的一部分)
模式 |
硬件支持 |
BL1镜像存放起始位置 |
BL1镜像是否需要header |
加载位置 |
跳转位置 |
Nand Boot
Nand flash
page0
是
0xD002_0000
0xD002_0010
SD / MMC Boot
SD / MMC
block1
是
0xD002_0000
0xD002_0010
同时,BL0是固化在s5pv210的IROM中的,是芯片在出厂的时候已经实现好了的。相应的,其从存储设备(SD/nand/eMMC)上获取镜像的代码就也就必须是已经实现好的。
既然,从存储设备(SD/nand/eMMC)上获取镜像的代码已经实现好了,也就是存储设备代码拷贝函数,并且在BL1阶段和BL2阶段可能也要需要使用到相同的功能,于是s5pv210将这部分代码的也是固化在IROM中,并且将这些函数接口的函数指针存放到某一个固定的地方。
当BL1或者BL2需要使用到从存储设备(SD/nand/eMMC)上获取镜像的函数接口时,就可以从对应的地方获取函数指针。
而剩下的,也就是最重要的是,这些函数指针被存放在上什么地方?这也是我们后续重点关注的地方。
为什么是函数指针而不是函数地址呢,是因为可以直接使用函数指针来调用函数。
二、s5pv210代码拷贝函数介绍
现在,我们要关心的是s5pv210的存储设备代码拷贝函数的函数原型以及函数指针的存放位置。
主要参考文档:《S5PV210-iROM-ApplicationNote-Preliminary-20091126》
先一段文档里面的说明:
s5pv210的IROM中集成了一些启动存储设备的块拷贝函数。因此,开发者不需要实现对应的存储设备的拷贝函数了。这些拷贝函数可以实现从存储设备到memory的拷贝。当IROM启动完成之后,开发者也可以直接使用这些拷贝函数了。
这和我们第一节中,说明的是一致的。
1、存储设备代码拷贝函数(Device Copy Function)地址存储位置
这里要特别注意,这里既不是指函数指针,也不是指函数地址,而是指函数指针被存放到的位置。
可以通过函数指针被存放到的位置找到函数指针,调用函数指针就可以调用到相应的函数了。
函数指针的地址 |
函数名 |
功能 |
0xD0037F90
NF8_ReadPage_Adv
is advanced NF8_ReadPage function.
0xD0037F94
NF16_ReadPage_Adv
is advanced NF16_ReadPage function.
0xD0037F98
CopySDMMCtoMem
can copy any data from SD/MMC device to SDRAM.
0xD0037F9C
CopyMMC4_3toMem
can copy any data from eMMC device to SDRAM.
0xD0037FA0
CopyOND_ReadMultiPages
can copy any data from OneNand device to SDRAM.
0xD0037FA4
CopyOND_ReadMultiPages_Adv
can copy any data from OneNand device to SDRAM.
0xD0037FA8
Copy_eSSDtoMem
can copy any data from eSSD device to SDRAM.
0xD0037FAC
Copy_eSSDtoMem_Adv
can copy any data from eSSD device to SDRAM.
0xD0037FB0
NF8_ReadPage_Adv128p
is advanced NF8_ReadPage function.
更详细的功能介绍建议参考文档《S5PV210-iROM-ApplicationNote-Preliminary-20091126》。
这些地址是递归的,位于0xD003_7F90-0xD003_7FB0
通过文档《[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)》,我们知道了0xD002_0000-0xD003_7FFF是属于IRAM的区域,所以说’函数指针存放地址’是放在IRAM上的,按照我猜,应该是在启动过程中,BL0把这些IROM上这些固化的函数的地址写到IRAM对应的位置上,例如0xD0037F90,对应位置就可以当作一个函数指针来使用。
2、函数原型说明
文档中的函数原型和使用过程中的函数原型有所差异。个人感觉可能是文档有问题,但是这里还是以文档为准。使用介绍中,再以实际的使用为准。
因为tiny210只支持SD boot和nand flash的方式,下面我就以SD和nand flash作为存储设备的拷贝函数做介绍。
(1)
CopySDMMCtoMem
从SD/MMC拷贝(加载)块到内存中的函数。
函数结构如下(也就是一个简单的使用范例)
?
1
2
3
4
5
6
7
8
9
10
11
/**
*
This Function copy MMC(MoviNAND/iNand) Card Data to memory.
*
Always use EPLL source clock.
*
This function works at 20Mhz.
*
@param u32 StartBlkAddress : Source card(MoviNAND/iNand MMC)) Address.(It must block address.)
*
@param u16 blockSize : Number of blocks to copy.
*
@param u32* memoryPtr : Buffer to copy from.
*
@param bool with_init : determined card initialization.
*
@return bool(u8) - Success or failure.
*/
#define
CopySDMMCtoMem(z,a,b,c,e) (((bool(*)(
int
,
unsigned
int
,
unsigned
short
,
unsigned
int
*,
bool))(*((unsigned
int
*)
0xD0037F98
)))(z,a,b,c,e))
可以简单推测出函数原型为bool CopySDMMCtoMem(int, unsigned int, unsigned short, unsigned int*, bool)。
argv0=起始块号 argv1=块数量 argv2=要拷贝到内存的什么位置上,也就是目标地址指针。 argv3=是否需要检测初始化 argv4=返回参数,用于决定是成功还是失败。
注意:以上是文档的说明,
但是在实际使用中,实际的函数原型如下:
boot copy_sd_to_ddr(u32 channel, u32 start_block, u16 block_size, u32 *trg, u32 init);
可见,文档是有问题的。后续会说明。
(2)
NF8_ReadPage_Adv
从nand flash拷贝(加载)页到内存中的函数。
8bit ECC校验的函数结构如下(也就是一个简单的使用范例)
?
1
2
3
4
5
6
7
8
/**
*
This Function copies a block of page to destination memory.( 8-Bit ECC only )
*
@param uint32 block : Source block address number to copy.
*
@param uint32 page : Source page address number to copy.
*
@param uint8 *buffer : Target Buffer pointer.
*
@return int32 - Success or failure.
*/
#define
NF8_ReadPage_Adv (a,b,c) (((
int
(*)(uint32,
uint32, uint8*))(*((uint32 *)
0xD0037F90
)))(a,b,c))
其参数意义参考注释,这里不加以说明了。
三、s5pv210代码拷贝函数使用示例
s5pv210代码拷贝函数是以函数指针的方式进行使用的,因为,在这里先介绍一个简单的函数指针的使用示例。
1、函数指针简单示例说明
假设有一个函数原型是int function(int a, int b),其函数指针被存放在了0x10的位置上。
那么我们调用该函数的方法如下:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#define
CopySDMMCtoMem
0xD0037F98
typedef
u32(*copy_sd_mmc_to_mem)
(u32
channel, u32 start_block, u16 block_size, u32 *trg, u32 init);
void
copy_bl2_to_ddr(
void
)
{
u32
sdmmc_base_addr;
copy_sd_mmc_to_mem
copy_bl2 = (copy_sd_mmc_to_mem)(*(u32*)CopySDMMCtoMem);
sdmmc_base_addr
= *(u32 *)SDMMC_BASE;
if
(sdmmc_base_addr
== SDMMC_CH0_BASE_ADDR)
copy_bl2(
0
,
MOVI_BL2_SDCARD_POS, MOVI_BL2_BLKCNT, (u32 *)CONFIG_SYS_TEXT_BASE,
0
);
if
(sdmmc_base_addr
== SDMMC_CH2_BASE_ADDR)
copy_bl2(
2
,
MOVI_BL2_SDCARD_POS, MOVI_BL2_BLKCNT, (u32 *)CONFIG_SYS_TEXT_BASE,
0
);