看了韦东山老师的u-boot-2012.04.01移植,然后把大概移植内容整理了一下,如下。
开发环境:
u-boot-2012.04.01
arm-linux-gcc-4.3.2.tar
1.环境配置:
老版本的gcc编译器编译时有问题,所以使用4.3.2
解压到根目录:
book@book-desktop:/work/tools$sudo tar xjf arm-linux-gcc-4.3.2.tar.bz2 -C /
查看环境变量:
book@book-desktop:/work/tools$echo $PATH
book@book-desktop:/work/tools$/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
设置环境变量:以下两种方法均可
1)book@book-desktop:/work/tools$export PATH=/usr/local/arm/4.3.2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
2)book@book-desktop:/work/tools$ sudo vi /etc/environment
需要用到的gcc编译器、u-boot-2012.04.01在以下地址:
http://download.youkuaiyun.com/detail/qq361294382/9501324
2.u-boot启动流程分析
2.1 自己写的精简版u-boot:
a.初始化硬件: 关看门狗、设置时钟、设置SDRAM、初始化NAND FLASH
b.如果bootloader比较大,要把它重定位到SDRAM
c.把内核从NAND FLASH读到SDRAM
d.设置“要传给内核的参数”
e.跳转执行内核
2.2新版u-boot
1 set the cpu to SVC32 mode
2 turn off the watchdog
3 mask all IRQS by setting all bits in the INTMR
4 设置时钟比例
5 设置内存控制器
6 设置栈,调用C函数board_init_f
7 调用函数数组init_sequence里的各个函数 board.c->board_init_f
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
7.1 board_early_init_f: 设置系统时钟、设置GPIO
可以修改配置文件,定义CONFIG_S3C2440
8 重定位代码:
arm-linux-ld --help | grep pie
-pie, --pic-executable Create a position independent executable
8.1 从NOR FLASH把代码复制到链接地址SDRAM中
8.2 程序的链接地址是0.访问全局变量、静态变量、调用函数时是使"基于0地址编译得到的地址"
现在把程序复制到了SDRAM
需要修改代码,把"基于0地址编译得到的地址“改为新地址
1) 复制到哪里?任选
2) 复制过去后,为何能执行:修改代码,改变里面的变量、函数
8.3 程序里有些地址在链接是不能确定,要到运行前才能确定:fixabs
9 clear_bss
10调用C函数board_init_r: 第二阶段的代码
看似差别挺大,其实原理相同,只是根据适应性不同,实现起来步骤有点差别。
3.修改u-boot-2012.04.01代码
3.1 新建一个单板
cd board/samsung/
cp smdk2410 smdk2440 -rf
cd ../../include/configs/
cp smdk2410.h smdk2440.h
修改:boards.config
仿照:smdk2410 arm arm920t-samsungs3c24x0
添加:smdk2440 arm arm920t-samsungs3c24x0
make smdk2440_config
make
3.2 烧写看结果
阅读代码发现不足:UBOOT里先以60MHZ的时钟计算参数来设置内存控制器,但是MPLL还未设置
处理措施: 把MPLL的设置放到start.S里,取消board_init_f->init_sequence->board_early_init_f里对MPLL的设置
乱码,查看串口波特率的设置,发现在get_HCLK里没有定义CONFIG_S3C2440
处理措施:
include/configs/smdk2440.h :去掉CONFIG_S3C2410 根据Makefile找到根据哪个宏编译模块,把对应的宏去掉即可 去掉#define CONFIG_S3C2410
添加#define CONFIG_S3C2440
有错误,去掉下面#define CONFIG_CMD_NAND
3.3参考"毕业班第一课"的start.S、init.c来修改代码
把init.c放入board/samsung/smdk2440目录,修改Makefile 添加init.c -> COBJS:= smdk2410.o init.o
修改init.c 函数+static
smdk2440.h: #define CONFIG_SYS_TEXT_BASE 0x33f80000//改 34000000 - 33f80000 = 512k 用于SDRAM中存放代码
start.S中修改时钟配置信息:
ldr r0, =0x4c000014
/* mov r1, #0x03; FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1*/
mov r1, #0x05; /* FCLK:HCLK:PCLK=1:4:8*/
str 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/* 写入控制寄存器 */
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
/* MPLLCON = S3C2440_MPLL_200MHZ */
ldr r0, =0x4c000004
ldr r1, =S3C2440_MPLL_400MHZ
str r1, [r0]
/* 启动ICACHE */
mrc p15, 0, r0, c1, c0, 0 @ read control reg
orr r0, r0, #(1<<12)
mcr p15, 0, r0, c1, c0, 0 @ write it back
lowlevel_init.S SDRAM配置信息改为以下
SMRDATA:
.long 0x22011110 //BWSCON
.long 0x00000700 //BANKCON0
.long 0x00000700 //BANKCON1
.long 0x00000700 //BANKCON2
.long 0x00000700 //BANKCON3
.long 0x00000700 //BANKCON4
.long 0x00000700 //BANKCON5
.long 0x00018005 //BANKCON6
.long 0x00018005 //BANKCON7
.long 0x008C04F4 // REFRESH
.long 0x000000B1 //BANKSIZE
.long 0x00000030 //MRSRB6
.long 0x00000030 //MRSRB7
然后就串口就可以正常打印信息了
3.4 修改board_init_f,把relocate_code去掉
去掉: arch/arm/config.mk:75:LDFLAGS_u-boot += -pie
./arch/arm/cpu/u-boot.lds
board/samsung/smdk2440/libsmdk2440.o (.text)
vi cpu/samsung/Makefile
自己定义sdram代码复制函数,跳转函数
start.S修改代码如下:
bl nand_init_ll();
/*设置cop_to_sdram参数*/
mov r0, #0 /*源*/
//ldr r1, =_start
ldr r1, _TEXT_BASE/*目的0x33f80000*/
//ldr r2, =__bss_start
//sub r2,r2,r1
ldr r2, _bss_start_ofs /*大小*/
bl copy_code_to_sdram/* 将启动代码copy到sdram */
bl clear_bss /* 清除bss段 */
ldr pc, = call_board_init_f
/* Set stackpointer in internal RAM to call board_init_f */
call_board_init_f:
ldr r0,=0x00000000
bl board_init_f
烧写到nor flash后效果:
U-Boot 2012.04.01 (Apr 22 2016 - 22:09:48)
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
此处有一个问题,导致代码无法继续执行
include/common.h中
unsigned int board_init_f (ulong) __attribute__ ((noreturn));
把__attribute__ ((noreturn)去掉,否则board_init_r无法取得需要的参数,导致程序不能正常运行。
3.5 修改UBOOT,支持NOR FLASH
drivers\mtd\jedec_flash.c加上新的型号
#define CONFIG_SYS_MAX_FLASH_SECT (128)
修复了重定位时留下来的BUG: SP要重新设置
board.c:
flash_size = flash_init();
flash_detect_legacy
jedec_flash_match(info, info->start[0])
jedec_table :添加nor flash信息:
#define CONFIG_SYS_MAX_FLASH_SECT (128)
修复了重定位时留下来的BUG: SP要重新设置
board.c:
flash_size = flash_init();
flash_detect_legacy
jedec_flash_match(info, info- >start[0])
jedec_table :添加nor flash信息:
/* mini 2440 使用的是AM29LV160DB*/
{
.mfr_id = (u16)AMD_MANUFACT, /*厂家ID 01 */
.dev_id = 0x2249, //AM29LV160DB/*设备ID*/
.name = "AMD AM29LV160DB", /*芯片名称 自定义*/
.uaddr = {
[1] = MTD_UADDR_0x0555_0x02AA /* x16 解锁地址 */
},
.DevSize = SIZE_2MiB,
.CmdSet = CFI_CMDSET_AMD_LEGACY,
.NumEraseRegions= 4,
.regions = {
ERASEINFO(0x04000, 1), /*8K*/
ERASEINFO(0x02000, 2), /*4K*/
ERASEINFO(0x08000, 1), /*16K*/
ERASEINFO(0x10000, 31),/*32K*/
}
},
3.6 修改u-boot支持NAND Flash
把drivers\mtd\nand\s3c2410_nand.c 复制为s3c2440_nand.c
nand 初始化过程如下:
nand_init
nand_init_chip
board_nand_init
初始化时序,ECC,禁止片选
设置nand_chip结构体,提供底层的操作函数
nand_scan
nand_scan_ident
nand_set_defaults
chip->select_chip = nand_select_chip;
chip->cmd_func(mtd,NAND_CMD_RESET, -1, -1);
nand_command();
chip->cmd_ctrl
s3c2440_hwcontrol
chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
chip->IO_ADDR_R
nand->IO_ADDR_R = (void *)&nand_reg->nfdata;
nand_get_flash_type
chip->select_chip
chip->cmdfunc(mtd,NAND_CMD_RESET, -1, -1);
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
s3c2440_hwcontrol(,,,)//选中、取消选中、发命令、地址
既可以用来发送命令又可以发送地址
chip->cmdfunc(mtd,NAND_CMD_READIO, 0x00, -1);
*maf_id = chip->read_byte(mtd);
*dev_id = chip->read_byte(mtd);
按照结构修改board_nand_init、s3c2440_nand_select、s3c2440_hwcontrol
注意:s3c2440 时钟配置寄存器、nand使能控制器跟s3c2410有差别,需要修改
至此就完成了u-boot的nor与nand支持
接下来是添加DM9000网卡、文件系统的支持
3.7添加DM9000支持
DM9000初始化过程如下
eth_initialize
board_eth_init
dm9000_initialize
smdk中添加DM9000宏
#define CONFIG_DRIVER_DM9000
#define CONFIG_DM9000_BASE 0x20000000
#define DM9000_IO CONFIG_DM9000_BASE
#define DM9000_DATA (CONFIG_DM9000_BASE + 4)
然后ping一下主机,ping不通,提示无ipaddr,*** ERROR: `ethaddr' not set
解决方法如下,一个临时,一个永久的,都可以:
1).
set ipaddr 10.170.41.110
set ethaddr 00:0c:29:4d:e4:f4
set serverip 10.170.62.44
set gatewayip 10.170.41.33
2)初始化时设置
/*下面的根据自己ip地址填写,仅供参考*/
#define CONFIG_NETMASK255.255.255.0
#define CONFIG_IPADDR 192.168.1.110
#define CONFIG_SERVERIP 192.168.1.44
#define CONFIG_ETHADDR 25:00:45:23:23:34
然后就可以使用tftp工具下载了
例如:利用原有u-boot更新u-boot
tftp 30000000 u-boot_new.bin
protect off all
erase 0 3ffff
cp.b 30000000 0 40000
3.8 设置启动环境参数:
因为前面一直未划分flash分区,所以环境参数设置完不能直接保存。
划分分区之前,由于前面编译的u-boot.bin太大,400K左右,等下划分的u-boot分区大小256K,因此需要将不用的模块去掉:
smdk2440.h:
#define CONFIG_USB_OHCI
#define CONFIG_USB_KEYBOARD
#define CONFIG_USB_STORAGE
#define CONFIG_DOS_PARTITION
#define CONFIG_BOOTP_BOOTFILESIZE
#define CONFIG_BOOTP_BOOTPATH
#define CONFIG_BOOTP_GATEWAY
#define CONFIG_BOOTP_HOSTNAM
//#define CONFIG_CMD_DATE
//#define CONFIG_CMD_DHCP
//#define CONFIG_CMD_USB
#define CONFIG_ENV_ADDR(CONFIG_SYS_FLASH_BASE + 0x070000)
#define CONFIG_ENV_IS_IN_FLASH
#define CONFIG_ENV_SIZE 0x10000
/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE
#define CONFIG_CMD_FAT
#define CONFIG_CMD_EXT2
#define CONFIG_CMD_UBI
#define CONFIG_CMD_UBIFS
#define CONFIG_CMD_MTDPARTS
#define CONFIG_MTD_DEVICE
#define CONFIG_MTD_PARTITIONS
#define CONFIG_YAFFS2
#define CONFIG_RBTREE
以上内容皆可去掉,剩下的可以根据自己需要适当裁剪。
下面划分分区:
smdk2440.h:
//环境变量参数存放地址
#define CONFIG_ENV_IS_IN_NAND
#define CONFIG_ENV_OFFSET 0x00040000
#define CONFIG_ENV_SIZE 0x20000
#define CONFIG_ENV_RANGECONFIG_ENV_SIZE
#define CONFIG_CMD_MTDPARTS
#define CONFIG_MTD_DEVICE
#define MTDIDS_DEFAULT "nand0=mini2440-0"/*哪一个设备*/
//u-boot、params、kernel、rootfs分区情况
#define MTDPARTS_DEFAULT "mtdparts=mini2440-0:256k(u-boot),"\
"128k(params),"\
"2m(kernel)," \
"-(rootfs)" \
//启动命令
#define CONFIG_BOOTARGS "console=ttySAC0 root=/dev/mtdblock3"
#define CONFIG_BOOTCOMMAND "nand read 30000000 kernel;bootm 30000000"
smdk2440.h:
内核打印出来的分区信息
0x00000000 - 0x00040000 : "bootloader"
0x00040000 - 0x00060000 : "params"
0x00060000 - 0x00260000 : "kernel"
0x00260000 - 0x10000000 : "root"
分区之后u-boot对分区操作就方便多了,前后对比如下:
未分区之前的指令:
nand erase 60000 200000 //擦除6000以后的2M空间
nand write 30000000 60000 200000 //将30000000开始的2M内容写到60000
需要执行mtdparts default 或者nand init后面添加 run_command
分区后指令:
tftp 30000000 uImage
nand erase.part kernel
nand write 30000000 kernel
可以直接设置保存环境参数
set bootcmd 'nand read 30000000 kernel;bootm 30000000'
save
3.9支持文件系统
3.9.1 jffs2
烧写jffs2文件系统
tftp 30000000 fs_mini_mdev.jffs2
nand erase.part rootfs
nand write.jffs2 30000000 0x00260000 3b8e30 (实际文件大小,否则烧写整个root分区)
//设置启动参数,文件系统格式jffs2
set bootargs console=ttySAC0 root=/dev/mtdblock3 rootfstype=jffs2
3.9.2 yaffs2文件系统
smdk2440.h:
tftp 30000000 first_fs.yaffs2
nand erase.part rootfs
nand write.yaffs 30000000 0x260000 85ce00
问题:无write.yaffs
解决:
smdk2440.h:
添加#define CONFIG_CMD_NAND_YAFFS
将yaffs相关函数编译进u-boot
然后烧写yaffs2文件:
现象:不能正常启动,不能识别文件系统
原因:
1)nand_util.c中
if (flags & WITH_YAFFS_OOB) {
if (!rval)
break;}
判断有误,需要去掉!
2) ops.mode = MTD_OOB_AUTO;
改为:ops.mode = MTD_OOB_RAW;//
3) if (!need_skip && !(flags & WITH_DROP_FFS))
缺少判断条件:
改为:
if (!need_skip && !(flags & WITH_DROP_FFS) && !(flags &WITH_YAFFS_OOB))
我测试时第3条必须加,否则判断条件有误,直接将oob烧写到正常数据内存中。
然后编译烧写就可以进入系统了。
至此,u-boot移植基本完成。
4.制作补丁
diff -urN linux-3.4.2 linux-3.4.2_100ask > linux-3.4.2_100ask.patch
patch -p1 < ../linux-3.4.2_100ask.patch