分类: LINUX
2009-06-15 14:42:23
能够支持多种体系结构的处理器,支持的开发板也越来越多。以S3C2410处理器的开发板为例,我们可以基于SMDK2410移植。
开始移植之前,需要先分析一下U-Boot已经支持的开发板,比较出硬件配置最接近的开发板。选择的原则是,首先处理器相同,其次处理器体系结构相同,然后是以太网接口等外围接口。推荐使用官方FTP下载UBOOT源码。http://www.icdev.com.cn/batch.viewlink.php?itemid=1694
移植U-Boot的基本步骤如下:
(1) 在board目录下创建自己的工作目录,将smdk2410目录下的内容全部拷贝到qt2410e目录下。
(2) cd u-boot-1.2.0/board
(3) mkdir qt2410e
(4) cd qt2410e
(5) cp ../smdk2410/* .
(6) mv smdk2410.c qt2410e.c
(7) vi Makefile并把COBJS更改为:COBJS := qt2410e.o flash.o nand_read.o
(8) cd ../..
(9) cp include/configs/smdk2410.h include/configs/qt2410e.h
(10) vi Makefile顶层Makefile中1924行填加如下两行:
qt2410e_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t qt2410e null s3c24x0
start.S文件中需要使用的nand_read_ll读写函数,用来将uboot拷贝到内存里去。在/board/qt2410e目录下需要添加nand_read.c文件,主要实现了nand_read_ll读写函数。
(1) cd board/qt2410e
(2) vi nand_read.c创建此文件
(3) 阅读并分析nand_read_ll函数,将其添加到nand_read.c中,代码如下:
(1) #include
(2)
(3) #define __REGb(x) (*(volatile unsigned char *)(x))
(4) #define __REGi(x) (*(volatile unsigned int *)(x))
(5) #define NF_BASE 0x4e000000
(6) #define NFCONF __REGi(NF_BASE + 0x0)
(7) #define NFCMD __REGb(NF_BASE + 0x4)
(8) #define NFADDR __REGb(NF_BASE + 0x8)
(9) #define NFDATA __REGb(NF_BASE + 0xc)
(10) #define NFSTAT __REGb(NF_BASE + 0x10)
(11)
(12) #define BUSY 1
(13) inline void wait_idle(void) {
(14) int i;
(15)
(16) while(!(NFSTAT & BUSY))
(17) for(i=0; i<10; i++);
(18) }
(19)
(20) #define NAND_SECTOR_SIZE 512
(21) #define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)
(22)
(23)
(24) int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
(25) {
(26) int i, j;
(27)
(28) if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
(29) return -1;
(30) }
(31)
(32)
(33) NFCONF &= ~0x800;
(34) for(i=0; i<10; i++);
(35)
(36) for(i=start_addr; i < (start_addr + size);) {
(37)
(38) NFCMD = 0;
(39)
(40)
(41) NFADDR = i & 0xff;
(42) NFADDR = (i >> 9) & 0xff;
(43) NFADDR = (i >> 17) & 0xff;
(44) NFADDR = (i >> 25) & 0xff;
(45)
(46) wait_idle();
(47)
(48) for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
(49) *buf = (NFDATA & 0xff);
(50) buf++;
(51) }
(52) }
(53) NFCONF |= 0x800;
(54) return 0;
(55) }
(1) vi ../../cpu/arm920t/start.S
(2) 在vi编辑器的命令模式下输入如下命令找到选择FLASH启动部分代码,命令如下:
(3) /RELOCATE
(4) 这时将看到如下代码为NOR的重定向代码:
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
(5) 可以将上述代码注释掉或删除,或者直接不予以理会,我们这里将光标移至#ifndef CONFIG_SKIP_RELOCATE_UBOOT行并执行18dd命令直接将其删除。
(6) 删除部分将替换为NAND FLASH的初始化代码,并由此代码最终调用nand_read.c的函数。代码如下:
#ifdef CONFIG_S3C2410_NAND_BOOT
@ 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
nand1:
add r3, r3, #0x1
cmp r3, #0xa
blt nand1
nand2:
ldr r2, [r1, #oNFSTAT] @ wait ready
tst r2, #0x1
beq nand2
ldr r2, [r1, #oNFCONF]
orr r2, r2, #0x800 @ disable chip
str r2, [r1, #oNFCONF]
@ get read 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 U-Boot to RAM
ldr r0, =TEXT_BASE
mov r1, #0x0
mov r2, #0x20000
bl nand_read_ll 这个函数在nand_read.c中实现
tst r0, #0x0
beq ok_nand_read
bad_nand_read:
loop2: b loop2 @ infinite loop
ok_nand_read:
@ verify
mov r0, #0
ldr r1, =TEXT_BASE
mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes,这句话的意思在start.S中已注释。
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4
beq stack_setup
bne go_next
notmatch:
loop3: b loop3 @ infinite loop
#endif @ CONFIG_S3C2410_NAND_BOOT
注:实现比较简单,同学要仔细推敲NAND工作原理,如看不懂,老师会在同学完成实验后给予讲解。其中@为注释部分,可不必写入。
(7) 用命令行模式找到_start_armboot: .word start_armboot后加入:
.align 2(前面用TAB键空出)
DW_STACK_START: .word STACK_BASE+STACK_SIZE-4
在include/configs/qt2410e.h头文件中添加nandflash的初始化信息:
(1) 找到#define CFG_ENV_IS_IN_FLASH 1并将其用//注释掉。
//#define CFG_ENV_IS_IN_FLASH 1
(2) 后面添加如下宏定义:
#define CFG_ENV_IS_IN_NAND 1
#define CFG_ENV_OFFSET 0x020000
#define CFG_NAND_BASE 0x4E000000
#define CMD_SAVEENV
#define CFG_NAND_LEGACY
#define CFG_MONITOR_BASE PHYS_SDRAM_1
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
#define CFG_NAND_BASE 0x4E000000
/* NandFlash控制器在SFR区起始寄存器地址 */
#define CFG_MAX_NAND_DEVICE 1
/* 支持的最在Nand Flash数据 */
#define SECTORSIZE 512
/* 1页的大小 */
#define NAND_SECTOR_SIZE SECTORSIZE
#define NAND_BLOCK_MASK 511
/* 页掩码 */
#define ADDR_COLUMN 1
/* 一个字节的Column地址 */
#define ADDR_PAGE 3
/* 3字节的页块地址!!!!!*/
#define ADDR_COLUMN_PAGE 4
/* 总共4字节的页块地址!!!!! */
#define NAND_ChipID_UNKNOWN 0x00
/* 未知芯片的ID号 */
#define NAND_MAX_FLOORS 1
#define NAND_MAX_CHIPS 1
/* Nand Flash命令层底层接口函数 */
#define WRITE_NAND_COMMAND(d, adr) {rNFCMD = d;}
#define WRITE_NAND_ADDRESS(d, adr) {rNFADDR = d;}
#define WRITE_NAND(d, adr) {rNFDATA = d;}
#define READ_NAND(adr) (rNFDATA)
#define NAND_WAIT_READY(nand) {while(!(rNFSTAT&(1<<0)));}
#define NAND_DISABLE_CE(nand) {rNFCONF |= (1<<11);}
#define NAND_ENABLE_CE(nand) {rNFCONF &= ~(1<<11);}
/* the following functions are NOP's because S3C24X0 handles this in hardware 一定要加上 */
#define NAND_CTL_CLRALE(nandptr)
#define NAND_CTL_SETALE(nandptr)
#define NAND_CTL_CLRCLE(nandptr)
#define NAND_CTL_SETCLE(nandptr)
/* 允许Nand Flash写校验 */
#define CONFIG_MTD_NAND_VERIFY_WRITE 1
/*
* Nandflash Boot
*/
#define CONFIG_S3C2410_NAND_BOOT 1
#define STACK_BASE 0x33f00000
#define STACK_SIZE 0x8000
#define UBOOT_RAM_BASE 0x33f80000
/* NAND Flash 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
#define rNFCONF (*(volatile unsigned int *)0x4e000000)
#define rNFCMD (*(volatile unsigned char *)0x4e000004)
#define rNFADDR (*(volatile unsigned char *)0x4e000008)
#define rNFDATA (*(volatile unsigned char *)0x4e00000c)
#define rNFSTAT (*(volatile unsigned int *)0x4e000010)
#define rNFECC (*(volatile unsigned int *)0x4e000014)
#define rNFECC0 (*(volatile unsigned char *)0x4e000014)
#define rNFECC1 (*(volatile unsigned char *)0x4e000015)
#define rNFECC2 (*(volatile unsigned char *)0x4e000016)
#endif /* CONFIG_COMMANDS & CFG_CMD_NAND*/
(3) 85行后添加CFG_CMD_ENV | \和CFG_CMD_NAND | \
u-boot运行至第二阶段进入start_armboot()函数。其中nand_init()函数是对nand flash的最初初始化函数。Nand_init()函数在两个文件中实现。其调用与CFG_NAND_LEGACY宏有关,如果没有定义这个宏,系统调用 drivers/nnd/nand.c中的nand_init();否则调用board/smdk2410/smdk2410.c中的nand_init()函数。这里我选择第二种方式。
在/board/qt2410e/qt2410e.c文件的末尾添加对Nand Flash 的初始化函数:
#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
/*
* NAND flash initialization.
*/
#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++); /* tWB = 100ns. */
NF_WaitRB(); /* wait 200~500us; */
NF_SetCE(NFCE_HIGH);
}
static inline void NF_Init(void)
{
#if 0 /* a little bit too optimistic */
#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));
/*nand->NFCONF = (1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0); */
/* 1 1 1 1, 1 xxx, r xxx, r xxx */
/* En 512B 4step ECCR nFCE=H tACLS tWRPH0 tWRPH1 */
NF_Reset();
}
void
nand_init(void)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
NF_Init();
#ifdef DEBUG
printf("NAND flash probing at 0x%.8lX\n", (ulong)nand);
#endif
printf ("%4lu MB\n", nand_probe((ulong)nand) >> 20);
}
#endif
(1) 59行int nand_legacy_rw (struct nand_chip* nand, int cmd,
size_t start, size_t len,
size_t * retlen, u_char * buf);
后添加:
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs, size_t len, int clean);
并将下面的extern nand_info_t nand_info[];改为
extern nand_info_t nand_info[CFG_MAX_NAND_DEVICE];
(2) 搜索saveenv找到(190行左右第二个saveenv函数):
#else /* ! CFG_ENV_OFFSET_REDUND */
int saveenv(void)
将saveenv函数中puts ("Erasing Nand...");后的if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))注释并添加
//if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))
if (nand_legacy_erase(nand_dev_desc + 0, CFG_ENV_OFFSET, CFG_ENV_SIZE, 0))
将saveenv函数中total = CFG_ENV_SIZE; 后的//ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);注释并添加:
ret = nand_legacy_rw(nand_dev_desc + 0,0x00 | 0x02, CFG_ENV_OFFSET, CFG_ENV_SIZE,&total, (u_char*)env_ptr);
(3) 搜索env_relocate_spec找到第二个env_relocate_spec函数(270行左右):
找到函数中total = CFG_ENV_SIZE;
将后面的ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);注释并添加:
ret = nand_legacy_rw(nand_dev_desc + 0, 0x01 | 0x02, CFG_ENV_OFFSET, CFG_ENV_SIZE, &total, (u_char*)env_ptr);
(1) make distclean
(2) make qt2410e_config
(3) make all ARCH=arm
将生成u-boot.bin镜像,可将其下载到板子运行。