uboot移植过程
1.修改Makefile
首先给要建立的S3C2410开发板取名为TE2410, 移植uboot时以smdk2410为模板,
修改Makefile
#tar xvjf u-boot-1.1.3.tar.bz2
#cd u-boot-1.1.3
#vi Makefile
scb9328_config : unconfig
@./mkconfig $(@:_config=) arm arm920t scb9328 NULL imx
smdk2400_config : unconfig
@./mkconfig $(@:_config=) arm arm920t smdk2400 NULL s3c24x0
smdk2410_config : unconfig
@./mkconfig $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
SX1_config : unconfig
@./mkconfig $(@:_config=) arm arm925t sx1
te2410_config : unconfig
@./mkconfig $(@:_config=) arm arm920t te2410 NULL s3c24x0
蓝色字体是添加的内容。其中,te2410_config : unconfig意思是为TE2410建立一个编译项,@./mkconfig $(@:_config=) arm arm920t te2410 NULL s3c24x0中的
arm表示CPU的架构是基于ARM体系结构的;arm920t表示CPU类型是arm920t;te2410是开发板的型号;NULL表示开发商或经销商的名称为空;s3c24x0表示是基于s3c24x0的片上系统。
2.在uboot的board目录下建立te2410开发板子目录
#cp –fr board/smdk2410 /board/te2410
#cd board/te2410
#mv smdk2410.c te2410.c
还要修改board/te2410/Makefile文件,
OBJS := smdk2410.o flash.o --------à OBJS := te2410.o flash.o
3.在include/configs目录下建立te2410.h头文件
#cd include/configs
#cp –fr smdk2410.h te2410.h
4.指定交叉编译器的路径
选择支持softfloatpoint的交叉编译器,在etc/bashrc文件中添加一行
export PATH=/home/newdisk/toolchain/gcc-3.4.5-glibc-2.3.6/arm-softfloat-linux-gnu/bin:$PATH
其中,/home/newdisk/toolchain/gcc-3.4.5-glibc-2.3.6/arm-softfloat-linux-gnu/bin是交叉编译器路径
修改Makefile中的交叉编译器
ifeq ($(ARCH),arm)
CROSS_COMPILE = arm-softfloat-linux-gnu-
Endif
5.测试编译
#cd u-boot-1.1.3
#make te2410_config
#make
如果编译正确,将会在u-boot-1.1.3目录下生成u-boot、u-boot.bin、u-boot.srec 三个文件,其中u-boot是ELF格式二进制的image文件,u-boot.bin是原始的二进制image文件,u-boot.srec是Motorola S-Record格式的image文件。接下来的工作就是根据开发板的硬件配置来修改。
6.修改start.S文件
首先在 ldr pc, _start_armboot一行之前添加如下代码,将程序从Flash复制到DRAM中运行
#ifdef CONFIG_S3C2410_NAND_BOOT
bl copy_myself
@jump to ram
ldr r1, =on_the_ram
add pc, r1, #0
nop
nop
1:b 1b @infinite loop
on_the_ram:
#endif
然后在_start_armboot: .word start_armboot一行之后添加下面内容
#ifdef CONFIG_S3C2410_NAND_BOOT
copy_myself:
mov r10, lr
@reset NAND
mov r1, #NAND_CTL_BASE
ldr r2, =0xF830 @initial value
str r2, [r1, #oNFCONF]
ldr r2, [r1, #oNFCONF]
bic r2, r2, #0x800 @enable chip
str r2, [r1, #oNFCONF]
mov r2, #0xFF @reset command
strb r2, [r1, #oNFCMD]
mov r3, #0 @wait
1:add r3, r3, #0x1
cmp r3, #0xa
blt 1b
2:ldr r2, [r1,#oNFSTAT] @wait ready
tst r2, #0x01
beq 2b
ldr r2, [r1, #oNFCONF]
orr r2, r2, #0x800 @disable chip
str r2, [r1, #oNFCONF]
@get ready to call C functions(for nand_read())
ldr sp, DW_STACK_START @setup stack pointer
mov fp, #0 @no previous frame,so fp=0
@copy uboot to ram
ldr r0, =UBOOT_RAM_BASE
mov r1, #0
mov r2, #0x30000
bl nand_read_ll
tst r0, #0x0
beq ok_nand_read
#ifdef CONFIG_DEBUG_LL
bad_nand_read:
ldr r0, STR_FAIL
ldr r1, SerBase
bl PrintWord
1:b 1b @infinite loop
#endif
ok_nand_read:
#ifdef CONFIG_DEBUG_LL
ldr r0, STR_OK
ldr r1, SerBase
bl PrintWord
#endif
@verify
mov r0, #0
ldr r1, =UBOOT_RAM_BASE
mov r2, #0x400
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4
beq done_nand_read
bne go_next
notmatch:
#ifdef CONFIG_DEBUG_LL
ldr r0, STR_FAIL
ldr r1, SerBase
bl PrintWord
#endif
1: b 1b
done_nand_read:
#ifdef CONFIG_DEBUG_LL
ldr r0, STR_OK
ldr r1, SerBase
bl PrintWord
#endif
mov pc, r10
@ clear memory
@ r0:start address
@ r1:length
mem_clear:
mov r2, #0
mov r3, r2
mov r4, r2
mov r5, r2
mov r6, r2
mov r7, r2
mov r8, r2
mov r9, r2
clear_loop:
stmia r0!,{r2-r9}
subs r1, r1, #(8*4)
bne clear_loop
mov pc, lr
#endif /*CONFIG_S3C2410_NAND_BOOT*/
在start.S文件最后添加下面几行的内容,用于定义栈地址变量
#ifdef CONFIG_S3C2410_NAND_BOOT
.align 2
DW_STACK_START:
.word STACK_BASE+STACK_SIZE-4
#endif
7.添加nand_read.c和nandflash.h源文件
在start.S中调用了nand_read_ll函数,该函数用于NAND Flash读操作,在board/te2410目录下新建nand_read.c源文件,文件内容如下:
#include<config.h>
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))
#define NF_BASE 0x4e000000
#define NFCONF __REGi(NF_BASE+0x0)
#define NFCMD __REGb(NF_BASE+0x4)
#define NFADDR __REGb(NF_BASE+0x8)
#define NFDATA __REGb(NF_BASE+0xc)
#define NFSTAT __REGb(NF_BASE+0x10)
#define BUSY 1
inline void wait_idle(void)
{
int i;
while(!(NFSTAT & BUSY))
for(i=0;i<10;i++);
}
#define NAND_SECTOR_SIZE 512
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE-1)
/*low level nand read function*/
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int i,j;
if ((start_addr & NAND_BLOCK_MASK)||(size & NAND_BLOCK_MASK))
{
return -1; /*invalid alignment*/
}
/*chip enable*/
NFCONF &= ~0x800;
for(i=0; i<10; i++);
for(i=start_addr; i<(start_addr+size);)
{
/*Read0*/
NFCMD = 0;
/*Write Address*/
NFADDR = i& 0xFF;
NFADDR = (i>>9) & 0xFF;
NFADDR = (i>>17) & 0xFF;
NFADDR = (i>>25) & 0xFF;
wait_idle();
for(j=0; j<NAND_SECTOR_SIZE; j++, i++)
{
*buf = (NFDATA & 0xFF);
buf++;
}
}
/*chip disable*/
NFCONF |= 0x800;
return 0;
}
修改board/te2410目录下的Makefile文件
OBJS := te2410.o flash.o 改为 OBJS := te2410.o flash.o nand_read.o
在board/te2410目录下添加nandflash.h文件,该文件主要定义了NAND Flash的一些芯片配置函数,代码如下:
#include<s3c2410.h>
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
typedef enum
{
NFCE_LOW,
NFCE_HIGH
}NFCE_STATE;
static inline void NF_Conf(u16 conf )
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
nand->NFCONF = conf;
}
static inline void NF_Cmd(u8 cmd)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
nand->NFCMD = cmd;
}
static inline void NF_CmdW(u8 cmd)
{
NF_Cmd(cmd);
udelay(1);
}
static inline void NF_Addr(u8 addr)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
nand->NFADDR = addr;
}
static inline void NF_SetCE(NFCE_STATE s)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
switch(s)
{
case NFCE_LOW:
nand->NFCONF &= ~(1<<11);
break;
case NFCE_HIGH:
nand->NFCONF |= (1<<11);
break;
}
}
static inline void NF_WaitRB(void)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
while( !(nand->NFSTAT & (1<<0)) );
}
static inline void NF_Write(u8 data)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
nand->NFDATA = data;
}
static inline u8 NF_Read(void)
{
S3C2410_NAND *const nand = S3C2410_GetBase_NAND();
return (nand->NFDATA);
}
static inline void NF_Init_ECC(void)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
nand->NFCONF |= (1<<12);
}
static inline u32 NF_Read_ECC(void)
{
S3C2410_NAND *const nand = S3C2410_GetBase_NAND();
return (nand->NFECC);
}
#endif
8.修改te2410文件
修改这个文件的目的有两个,一是初始化CPU相关的寄存器来支持USB主从设备,二是初始化NAND Flash设备。添加代码如下:
#include "nandflash.h"
int board_init(void)
{
...
/*support usb function*/
gpio->MISCCR |= (1<<3);
gpio->MISCCR &= ~((1<<12)|(1<<13));
...
}
/*添加以下代码实现NAND Flash的初始化*/
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
extern ulong nand_probe(ulong physadr);
static inline void NF_Reset(void)
{
int i;
NF_SetCE(NFCE_LOW);
NF_Cmd(0xFF); /*reset command*/
for(i = 0; i < 10; i++);
NF_WaitRB();
NF_SetCE(NFCE_HIGH);
}
static inline void NF_Init(void)
{
#if 0
#define TACLS 0
#define TWRPH0 3
#define TWRPH1 0
#else
#define TACLS 0
#define TWRPH0 4
#define TWRPH1 2
#endif
NF_Conf((1<<15)|(0<<14)|(0<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0));
NF_Conf((1<<15)|(0<<14)|(0<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0));
}
void nand_init(void)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
NF_Init();
#if DEBUG
printf("NAND flash probing at 0x%.8lX/n",(ulong)nand);
#endif
printf("%ld MB/n",nand_probe((ulong)nand)>>20);
}
#endif
9.修改头文件te2410.h
修改include/configs/te2410.h文件,其中定义了栈的基地址和栈的大小、RAM的基地址以及NAND Flash设置参数等内容。
...
#define CONFIG_CMDLINE_TAG 1
#define CONFIG_SETUP_MEMORY_TAGS 1
#define CONFIG_INITRD_TAG 1
...
#define CONFIG_COMMANDS /
(CONFIG_CMD_DFL | /
CFG_CMD_CACHE | /
CFG_CMD_ENV | /
CFG_CMD_PING | /
CFG_CMD_NAND | /
/*CFG_CMD_EEPROM |*/ /
/*CFG_CMD_I2C |*/ /
/*CFG_CMD_USB |*/ /
CFG_CMD_REGINFO | /
CFG_CMD_DATE | /
CFG_CMD_ELF)
...
/*Nandflash Boot*/
#define CONFIG_S3C2410_NAND_BOOT 1
#define STACK_BASE 0x33FF8000
#define STACK_SIZE 0x8000
#define UBOOT_RAM_BASE 0x33F80000
/*Nandflash Controller*/
#define NAND_CTL_BASE 0x4e000000
#define bINT_CTL(Nb) __REG(INT_CTL_BASE+(Nb))
/*Offset*/
#define oNFCONF 0x00
#define oNFCMD 0x04
#define oNFADDR 0x08
#define oNFDATA 0x0c
#define oNFSTAT 0x10
#define oNFECC 0x14
/*定义Nandflash设置参数*/
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
#define CFG_MAX_NAND_DEVICE 1 /*Max number of NAND devices*/
#define SECTORSIZE 512
#define ADDR_COLUMN 1
#define ADDR_PAGE 2
#define ADDR_COLUMN_PAGE 3
#define NAND_ChipID_UNKNOWN 0x00
#define NAND_MAX_FLOORS 1
#define NAND_MAX_CHIPS 1
#define NAND_WAIT_READY(nand) NF_WaitRB()
#define NAND_DISABLE_CE(nand) NF_SetCE(NFCE_HIGH)
#define NAND_ENABLE_CE(nand) NF_SetCE(NFCE_LOW)
#define WRITE_NAND_COMMAND(d,adr) NF_Cmd(d)
#define WRITE_NAND_COMMANDW(d,adr) NF_CmdW(d)
#define WRITE_NAND_ADDRESS(d,adr) NF_Addr(d)
#define WRITE_NAND(d,adr) NF_Write(d)
#define READ_NAND(adr) NF_Read()
#define NAND_CTL_CLRALE(nandptr)
#define NAND_CTL_SETALE(nandptr)
#define NAND_CTL_CLRCLE(nandptr)
#define NAND_CTL_SETCLE(nandptr)
#define CONFIG_MTD_NAND_VERIFY_WRITE 1
#define CONFIG_MTD_NAND_ECC_JFFS2 1
#define CONFIG_DEBUG_LL 1
#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND)*/
修改以下各宏的值,内存相关地址、启动提示字母和网络的设置
#define CFG_MEMTEST_END 0x33F00000 /* 63 MB in DRAM */
#define CFG_LOAD_ADDR 0x30008000 /*default load address*/
#define PHYS_SDRAM_1_SIZE 0x04000000 /*64 MB*/
#define CFG_PROMPT ”TE2410”
#define CONFIG_IPADDR 192.168.1.10
#define CONFIG_SERVERIP 192.168.1.104
#define CFG_ENV_IS_IN_NAND 1
#define CFG_ENV_OFFSET 0x30000
#define UBOOT_RAM_BASE 0x33F80000
10.修改cmd_nand.c文件
添加包含nandflash.h的头文件 #include <nandflash.h>
将nandflash.h复制到u-boot-1.1.3/include目录下
11.重新编译
以上参考<<ARM嵌入式Linux系统开发从入门到精通>>
编译中遇到一些问题,需要注意的是要选择支持软件浮点的交叉编译器,因为uboot使用软件浮点,我使用的arm-linux-gcc3.4.1不支持软件浮点,后来自己构建一个支持软件浮点的交叉编译器。
修改u-boot-1.1.3/cpu/arm920t/config.mk
PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 /
-malignment-traps -msoft-float
改为
PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 /
-mshort-load-bytes -msoft-float
板子已经有下载好的vivi,将uboot直接下载到RAM中运行,所以修改start.S和上面的修改说明不同,只需将start.S中的bl lowlevel_init注释掉,其他不需要改动。
关于uboot的bootm和go命令,bootm和uImage对应,而go和zImage对应。uImage由zImage添加64字节头信息得来,由这个头信息构成的结构体如下(IH_NMLEN=32):
typedef struct image_header {
uint32_t ih_magic; /* Image Header Magic Number */
uint32_t ih_hcrc; /* Image Header CRC Checksum */
uint32_t ih_time; /* Image Creation Timestamp */
uint32_t ih_size; /* Image Data Size */
uint32_t ih_load; /* Data Load Address */
uint32_t ih_ep; /* Entry Point Address */
uint32_t ih_dcrc; /* Image Data CRC Checksum */
uint8_t ih_os; /* Operating System */
uint8_t ih_arch; /* CPU architecture */
uint8_t ih_type; /* Image Type */
uint8_t ih_comp; /* Compression Type */
uint8_t ih_name[IH_NMLEN]; /* Image Name */
} image_header_t;
uboot源代码的tools/目录下有mkimage工具,这个工具可以用来制作uImage
mkimage在制作映象文件的时候,是在原来的可执行映象文件的前面加上一个0x40字节的头,记录参数所指定的信息,这样uboot才能识别这个映象是针对哪个CPU体系结构的,哪个OS的,哪种类型,加载内存中的哪个位置, 入口点在内存的那个位置以及映象名是什么
mkimage -A arm -O Linux -T kernel -C none -a 0x30008000 -e 0x30008040 -n Linux-2.6.14 -d zImage uImage
-A ==> set architecture to 'arch'-O ==> set operating system to 'os'
-T ==> set image type to 'type'
-C ==> set compression type 'comp'
-a ==> set load address to 'addr' (hex)
-e ==> set entry point to 'ep' (hex)
-n ==> set image name to 'name'
-d ==> use image data from 'datafile'
-x ==> set XIP (execute in place)