*同上篇,还是针对遇到的问题简要先记录下,以后有空再补全。
一、工程建立
工程目标板 友善 sbc2410x
由于工程中已有sbc2410x的内容。所以先要删除一部分。
删除include/configs/sbc2410x.h
删除board/sbc2410x整个目录
修改顶层boards.cfg
CPU项由arm920t改为s3c2410x。u-boot的初忠是希望尽可能的通用。但带来的坏处是无用代码很多,需要定义很多条件,实际结果是可读性很差,特别是CPU相关的汇编代码部分。所以这里使用arm920t的部分文件+arm920t中s3c24x0的SoC中的文件,在arch/arm/cpu/重新建立一个s3c2410x的CPU,以专一针对s3c2410x组织CPU相关的代码,以方便阅读和分析。
建立 arch/arm/cpu/s3c2410x
拷贝 arch/arm/cpu/arm920t/
start.S
cpu.c
config.mk
Makefile
u-boot.lds
拷贝 arch/arm/cpu/arm920t/s3c24x0/
interrupts.c
speed.c
timer.c
usb.c
usb_ohci.c
usb_ohci.h
修改 arch/arm/cpu/s3c2410x/Makefile
在COBJS-y += cpu.o下面增加
COBJS-y += cpu.o
COBJS-y += speed.o
COBJS-y += timer.o
COBJS-y += usb.o
COBJS-y += usb_ohci.o
在board目录中建立sbc2410x目录
并将board/samsung/smdk2410/的所有文件拷贝到该目录
重命名smdk2410.c 为 sbc2410x.c 并修改Makefile中的smdk2410.o 为 sbc2410x.o
拷贝一份 arch/arm/cpu/arm920t/u-boot.lds到该目录,以修改链接脚本使支持nand启动使用
修改board/sbc2410x/中的config.mk 在末尾增加一句
LDSCRIPT=$(SRCTREE)/board/sbc2410x/u-boot.lds
这样,根目录的链接脚本文件会从board/sbc2410x/u-boot.lds复制。
在include/configs/将smdk2410.h拷贝一份为sbc2410x.h
至此,在主目录中执行
make sbc2410x_config
make
应该可以生成一个u-boot.bin
该u-boot.bin和smdk2410的完全一样。
二、基于smdk2410对sbc2410x的汇编级修改
目标:简化代码,并且从NAND引导,将u-boot复制到RAM中运行。
原理:当从NAND启动时,S3C2410X会将NAND FLASH中的前4K内容复制到片内的4K SRAM中。该4K SRAM在NAND启动时会被映射到0x0。CPU自动复制后会将PC转至0x0处开始执行。则对于CPU的设置,DRAM的设置,NAND控制器的初始化,代码搬运就必须都在这前4K代码中完成。ARM指令为32位字指令,即,4字节一个指令。编译后必须将arch/arm/cpu/s3c2410x/start.s和board/sbc2410x/lowlevel_init.s的编译后指令控制在1024条以内(4K/4) 。
首先修改board/sbc2410x/u-boot.lds,以使链接两个汇编文件在前面部分。压缩代码,以使之在4K之内。
u-boot.lds修改为:
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
arch/arm/cpu/s3c2410x/start.o (.text)
board/sbc2410x/lowlevel_init.o (.text) //这行是加入的
*(.text)
}
......
*这里有一说明,由汇编代码生成的目标文件,不会含有bss rodata等段,完全是text段。
精简和修改arch/arm/cpu/s3c2410x/start.S
主要是去掉和本处理器无关的代码,去掉中断响应代码(u-boot在s3c2410中不用中断),去掉从nor flash搬运代码的部分。
增加一个子程序调用,从lowlevel_init.s中调用relocate,以使从nand flash中将指令码搬运到内存执行。
修改 board/sbc2410x/lowlevel_init.s
修改对MPLL的初始化代码,以使主频运行在200M上。修改SDRAM的参数以使可以支持本板的SDRAM运行。这里面有一个设计比较巧妙的地方:该代码的链接地址为0x33f80000,所以SMRDATA的地址在链接后就为0x33f80000+偏移量。而初始化时,代码是在0x0为基地址的4K SRAM中执行的。这样,在代码搬运前SMRDATA实际并不在0x33f80000+偏移量的位置上。所以,这里引入TEXT_BASE,并用编译得到的SMRDATA地址去减基地址TEXT_BASE,得到的恰恰是开始运行的0x33f80000的偏移量,也正是从0x0处计算的实际地址。
这段代码搬运的代码写的还比较粗,只适用于K9F1208U0M以及指令兼容的片子。代码中没有进行坏块处理和识别,最大只读取256页,即128K字节的内容。
对于其中的一些内容进行一点说明
1)在进入relocate:之后,执行mov ip,lr是为了保护返回地址。因为在后面还有大量的子程序调用。
2)在整体搬运过程中,r8属于一个局部的全局变量,用于记录当前在搬运的页地址 0~256
r9也是一个局部的全局变量,用于记录内存中的偏移位置 0x33f80000~0x33f80000+128K
3)对于NAND FLASH控制器,每当将需要执行的指令以及地址输入到相应寄存器后,都要轮询NFSTAT寄存器,直到寄存器状态为READY后才能进行数据读取/写入或其他指令操作。一开始,由于没有注意到这一点,从NAND中读出的不是00就是FF,要不就是乱数据。
4)NAND FLASH在使用00/01指令进行读取数据的时候,其实可以连续的读取后面的数据,后面的数据不光是本页的,还有下一页的数据。包据A段,B段,以及用于校验的C段。由于计算不便,所以本程序每次都重新输入读指令和页地址。
5)readpage子程序中的 r0->r6 ... r6->r0 属于设计失误,临时保存一下r0的状态。
至此,编译生成的u-boot.bin可以烧入2410的nand flash,启动u-boot了。
三、u-boot提供了另一种nand启动的方法。
即在nand_spl中的方式。
大体思路是这样的:写一段较小的可以放入stepping stone中的程序,这段程序用于初始化CPU,初始化RAM,并将NAND FLASH指定位置的指定大小的内容搬到内存中的指定位置,然后跳转到这个内存的指定位置执行后面的代码。
编译后,指定这个小程序的代码尺寸。编译U-boot,生成u-boot.bin 再通过
cat loader.bin u-boot.bin > u-boot-nand.bin
将文件合并成一个文件。烧入NAND中。
这样,当从0x0执行时,首先载入loader那段小程序,将后面的u-boot.bin搬入RAM,然后跳到RAM执行。
这样做的好处是将u-boot系统又进行了一次拆分,以使可读性和可修改性得到更大的提高。
这种方法实现起来并不复杂,只是看懂了模式,等后面有时间的时候实践一下。