fl2440u-boot移植

本文详细介绍了U-Boot在FL2440开发板上的移植过程,包括配置交叉编译工具链、修改启动代码、添加NAND Flash启动支持、集成DM9000网卡驱动等内容,并分享了移植过程中遇到的问题及解决方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在移植u-boot之前,可以参考我之前的博客移植操作一遍,理解一下ARM-LINUX的启动流程:bootloader->linux内核->文件系统->应用程序。最重要的一点,移植u-boot一定要耐心、细心,因为u-boot涉及到开发板cpu的时钟配置、内存初始化等等软硬件环境的配置。

一、

1.我们的FL2440开发板移植u-bootsmdk2410为母板进行移植,所以用smdk2410创建配置文件;

2.修改顶层makefile,定义交叉编译工具链,然后定义开发板配置选项,我们用的u-boot-2010.09是在boards.cfg中配置的:

 

3、就是u-boot启动代码的修改了,主要是修改start.Slowlevel_init.S

4.板子外设驱动添加,这里我们主要添加的是DM9000网卡的支持;

5.nand flash启动代码修改,支持nandflash启动;

二、

指定你的linux操作系统下的交叉编译器的路径,用于编译整个u-boot



三、

u-boot顶层makefile文件中添加交叉编译器的路径

vim Makefile  


vim boards.cfg 


smdk2410 arm arm920t - samsung s3c24x0


fl2440 arm arm920t fl2440 lingyun s3c24x0

make fl2440_config 

make

生成.bin文件  u-boot.bin

四、

start.S 修改

vim arch/arm/cpu/arm920t/start.S 

下面这两行代码是 AT91RM9200DK这个开发板才有的代码,所以我们应该把他注释掉。汇编中@
表示单行注释,在 GNU 的汇编中,也支持 C 代码中的各种注释。
@bl coloured_LED_init
@bl red_LED_on


# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
#elif defined CONFIG_S3C2440(添加该代码对于S3C2440 CPU向其中写入0x7fff 就是将 INTSUBMSK
寄存器全部有效位(低 15 位)置 1,从而屏蔽对应的中断。
ldr r1, =0x7fff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif

添加S3C2440汇编初始化 LED CPU时钟的代码
# if defined(CONFIG_S3C2440)
#define GPBCON 0x56000010
#define GPBDAT 0x56000014
#define GPBUP 0x56000018

/*Set GPIO5, GPIO6, GPIO8, GPIO10 as GPIO OUTPUT mode*/(对灯进行初始化)
ldr r0, =GPBCON
ldr r1, [r0]
bic r1, r1, #0x3c00 /*Set GPBCON for GPIO5,GPIO6 as 0x00 */
orr r1, r1, #0x1400 /*Set GPBCON for GPIO5,GPIO6 as GPIOOUT, 0x01*/
bic r1, r1, #0x00330000 /*Set GPBCON for GPIO8,GPIO10 as 0x00*/
orr r1, r1, #0x00110000 /*Set GPBCON for GPIO8,GPIO10 as GPIOOUT, 0x01*/
str r1, [r0]
/*Set internal pullup resister*/
ldr r0, =GPBUP
ldr r1, [r0]
orr r1, r1, #0x0560 /*Set bit 5,6,8,10, disable pullup resister*/
str r1, [r0]
ldr r2, =GPBDAT
ldr r3, [r2]
orr r3, r3, #0x0560 /*Set bit 5,6,8,10 as high level, Turn Off LED*/(把所有等设置为灭)可以利用等的亮灭来提示u-boot进行到哪一个步骤,相当于自己加一个debug
str r3, [r2]


# define MPLLCON 0x4C000004
# define MDIV_405 0x7f << 12
# define PSDIV_405 0x21
/* FCLK:HCLK:PCLK = 1:4:8 */
ldr r0, =CLKDIVN
/*CLKDIVN寄存器地址存入 R0 */
mov r1, #0x05 /*把立即数5存入寄存器 R1*/
str r1, [r0] /*把寄存器R1的值(5)存入到R0所指向的地址中(CLKDIVN寄存器的
地址
)*/

mrc p15, 0, r1, c1, c0, 0
orr r1, r1, #0xc0000000
/* 修改CPU总线模式为"asynchronous bus mode" */
mcr p15, 0, r1, c1, c0, 0
Ldr r0,=MPLLCON
/*MPLLCON寄存器地址存入 R1 */
mov r1, #MDIV_405 /*把常量MDIV_405存入寄存器 R2 */
add r1, r1, #PSDIV_405 /*r2=MDIV_405+PSDIV_405*/
str r1, [r0] /*R2的值写入 MPLLCON寄存器中*/
#else /*S3C2410, S3C2440 */
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif /* end of if defined(CONFIG_S3C2440)

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
0x33f80000写入 r1 寄存器*/
cmp r0, r1 /* don't reloc during debug
比较 r0 r1寄存器的值*/
beq stack_setup


judgment_norflash_nandflash_boot:
ldr r1, =( (4<<28)|(3<<4)|(3<<2) ) /* 0x4000003C
地址(S3C24x0内部SRAM)写入r1寄存器*/
mov r0, #0 /*
将立即数 0x0写入r0 寄存器*/
str r0, [r1] /*
r0的值写入r1 存放的内存地址中去,即把0x4000 003C地址修改为0 */
mov r1, #0x3c /* 把地址 0x0000003C 写入到 r1寄存器*/
ldr r0, [r1] /*
r1所存放的内存单元(0x0000003C)的值装入r0*/
cmp r0, #0 /* r0
的值(0x0000003C的值)0比较 */
bne norflash_boot
nandflash_boot:
#define LENGTH_UBOOT 0x60000
定义从Nandflash拷贝u-boot的长度
#define NAND_CTL_BASE 0x4E000000 Nandflash控制器一系列寄存器的基地址
/* Offset */
#define oNFCONF 0x00
NFCONF 寄存器相对于NAND_CTRL_BASE的偏移值,下类似
#define oNFCONT 0x04
#define oNFCMD 0x08
#define oNFSTAT 0x20

mov r1, #NAND_CTL_BASE
ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )
str r2, [r1, #oNFCONF]
ldr r2, [r1, #oNFCONF]

ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control
str r2, [r1, #oNFCONT]
ldr r2, [r1, #oNFCONT]

ldr r2, =(0x6) @ RnB Clear
str r2, [r1, #oNFSTAT]
ldr r2, [r1, #oNFSTAT]

mov r2, #0xff @ RESET command
strb r2, [r1, #oNFCMD]
重启 Nandflash 后,用循环用来等待一段时间
mov r3, #0 @ wait
nand_delay:
add r3, r3, #0x1
cmp r3, #0xa
blt nand_delay
通过读 Nandflash 控制器的 NFSTAT 寄存器中bit2来判断 Nandflash是否Ready
nand_wait:
ldr r2, [r1, #oNFSTAT] @ wait ready
tst r2, #0x4
beq nand_wait
通过设置 NFCONT 寄存器的 bit1 Disable Chip Select
ldr r2, [r1, #oNFCONT]
orr r2, r2, #0x2 @ Flash Memory Chip Disable
str r2, [r1, #oNFCONT]

ldr sp, DW_STACK_START @ setup stack pointer
mov fp, #0 @ no previous frame, so fp=0

ldr r0, =TEXT_BASE nand_read_ll()第一个参数buf指向 0x33f80000,这就是u-boot拷贝的目标地址
mov r1, #0x0 nand_read_ll()第二个参数start_addr指向 0,即从nandflash0 地址开始拷贝
mov r2, #LENGTH_UBOOT nand_read_ll()第三个参数size为要拷贝的 u-boot 的大小
bl nand_read_ll 调用nand_read_ll()函数
tst r0, #0x0 判断 nand_read_ll()函数的返回值是否为
0
beq ok_nand_read
bad_nand_read:
dead_loop:
b dead_loop @ infinite loop

ok_nand_read:
@ verify
mov r0, #0
CPU 片内4K SRAM的起始地址为 0,启动时硬件自动拷贝u-boot4K到这里
ldr r1, =TEXT_BASE SDRAM内存中地址0x33F80000,刚才的nand_read_ll()搬移u-boot 到这里
mov r2, #0x400 0x400 = 1K-bytes,下面一下子比较4个字节,所以总共比较 4K-bytes
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
4 个字节处开始比较,如果不相同则跳到notmatch处,程序死循环。
bne notmatch
subs r2, r2, #4
如果相等,就看是否已比较完
beq stack_setup 如果比较完,说明搬运OK。这时开始跳到堆栈处初始化堆栈开始执行C代码
bne go_next 如果没有比较完,就继续下一次比较
notmatch: 如果某个字节不匹配则在程序在这里死掉
infinite_loop:
b infinite_loop @ infinite loop
norflash_boot:

这段代码用来计算要搬运的 u-boot 代码的起始地址和结束地址 

。。。。。。略
start_armboot: .word start_armboot
#ifdef CONFIG_S3C24X0
#define STACK_BASE 0x33f00000
在调用 nand_read_ll()函数之前设置的临时堆栈地址和大小
#define STACK_SIZE 0x10000
.align 2
DW_STACK_START: .word STACK_BASE+STACK_SIZE-4
#endif


五、

lowlevel_init.S 修改 

/* REFRESH parameter */
#define REFEN 0x1 /* Refresh enable
使能刷新 */
#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh
设置为自动刷新*/
#if defined(CONFIG_S3C2440)
/* REFRESH parameter */
#define REFEN 0x1 /* Refresh enable
使能刷新 */
#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh
设置为自动刷新*/
#if defined(CONFIG_S3C2440)
#define REFCNT 1268
#else


#define Trp 0x0 /* 2clk */
#define Trc 0x3 /* 7clk */
#define Tchr 0x2 /* 3clk */
#define REFCNT 1113 /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */

#endif 
TEXT_BASE:
.word TEXT_BASE
这里相当于定义一个全局的 lowlevel_init函数,在start.S 中会调用它
.globl lowlevel_init
lowlevel_init:
/* memory control configuration */
/* make r0 relative the current location so that it */
/* reads SMRDATA out of FLASH rather than memory ! */
SMDATA 地址(13个寄存器的值存放在内存中的起始地址0x33F8xxxx)加载到r0
ldr r0, =SMRDATA
lowlevel_init 的地址加载到 r1 寄存器中
ldr r1, =lowlevel_init
r0 减去 r1的结果存入r0,也即SMDATA相对于 lowlevel_inti的偏移地址
sub r0, r0, r1
获取 lowlevel_init 在内存中的实际地址
adr r3, lowlevel_init /* r3 <- current position of code */
运行时 lowlevel_init在内存中的地址加上SMDATA 相对于它的偏移,就获取到了SMDATA 在内存中的实际地址
add r0, r0, r3

六、
添加从 nandflash拷贝U-boot SDRAM中去的SDRAM C代码源文件 nand_read.c ,篇幅所限这里的代码略了。。。

修改 board/lingyun/fl2440/Makefile,添加nand_read.c文件的编译支持
vim board/lingyun/fl2440/Makefile
COBJS := fl2440.o nand_read.oflash.o
.....
修改 u-boot链接文件arch/arm/cpu/arm920t/u-boot.lds
vim arch/arm/cpu/arm920t/u-boot.lds
text :
{
arch/arm/cpu/arm920t/start.o (.text)
board/lingyun/fl2440/lowlevel_init.o (.text)
board/lingyun/fl2440/nand_read.o (.text)
*(.text)
}


七、添加 CONFIG_S3C2440条件编译

vim include/configs/fl2440.h
#define CONFIG_ARM920T 1 /* This is an ARM920T Core */
#define CONFIG_S3C24X0 1 /* in a SAMSUNG S3C24x0-type SoC */
CONFIG_S3C2410 改成 CONFIG_S3C2440,因为我们用的是S3C2440这颗 CPU
#define CONFIG_S3C2440 1 /* specifically a SAMSUNG S3C2440 SoC */
CONFIG_SMDK2410改成CONFIG_FL2440
#define CONFIG_FL2440 1 /* FL2440 board */

vim include/serial.h 
.................
#if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
extern struct serial_device s3c24xx_serial0_device;
extern struct serial_device s3c24xx_serial1_device;
extern struct serial_device s3c24xx_serial2_device;
#endif


vim common/serial.c
...............
#if defined(CONFIG_S3C2410)|| defined(CONFIG_S3C2440)
serial_register(&s3c24xx_serial0_device);
serial_register(&s3c24xx_serial1_device);
serial_register(&s3c24xx_serial2_device);
#endif
 
...............
#elif defined(CONFIG_S3C2410)|| defined(CONFIG_S3C2440)
#if defined(CONFIG_SERIAL1) 
...................
vim arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h
#ifdef CONFIG_S3C2400
#include <asm/arch/s3c2400.h>
#elif
defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
..............
vim arch/arm/include/asm/arch-s3c24x0/s3c24x0.h
struct s3c24x0_interrupt {
u32 SRCPND;
u32 INTMOD;
u32 INTMSK;
u32 PRIORITY;
u32 INTPND;
u32 INTOFFSET;
S3C2440 CPU 的中断寄存器地址和S3C2410完全一样
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
........
struct s3c24x0_dma {
u32 DISRC;
s3c2440 CPU DMA 寄存器地址和 S3C2410的也完全一样
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
u32 DISRCC;
#endif
u32 DIDST;
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
........
#ifdef CONFIG_S3C2400
u32 res[1];
#endif
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
u32 res[7];
#endif
};
 
.........
struct s3c24x0_clock_power {
u32 LOCKTIME;
u32 MPLLCON;
u32 UPLLCON;
u32 CLKCON;
u32 CLKSLOW;
u32 CLKDIVN;
S3C2440 S3C2410 CPU 多了摄像头接口,在时钟管理相关的寄存器中也多了这个摄像头的部分
#if defined (CONFIG_S3C2440)
u32 CAMDIVN;
#endif

};

#if defined(CONFIG_S3C2410)
struct s3c2410_nand {
u32 NFCONF;
u32 NFCMD;
u32 NFADDR;
u32 NFDATA;
u32 NFSTAT;
u32 NFECC;
};
#elif defined (CONFIG_S3C2440)
struct s3c2410_nand {
u32 NFCONF;
u32 NFCONT;
u32 NFCMD;
u32 NFADDR;
u32 NFDATA;
u32 NFMECCD0;
u32 NFMECCD1;
u32 NFSECCD;
u32 NFSTAT;
u32 NFESTAT0;
u32 NFESTAT1;
u32 NFMECC0;
u32 NFMECC1;
u32 NFSECC;
u32 NFSBLK;
u32 NFEBLK;
};
#endif

...  ...
struct s3c24x0_gpio {
#ifdef CONFIG_S3C2400
......
u32 MISCCR;
u32 EXTINT;
S3C2440 GPIO 口寄存器前面部分的地址和 S3C2410 的完全一样,但前者比后者要多出一些寄存器
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)

#if defined (CONFIG_S3C2440)
u32 res9[3];
u32 MSLCON;
u32 GPJCON;
u32 GPJDAT;
u32 GPJUP;
#endif

#endif
};


vim arch/arm/cpu/arm920t/s3c24x0/timer.c
.........
vim arch/arm/cpu/arm920t/s3c24x0/speed.c
...........
m = ((r & 0xFF000) >> 12) + 8;
p = ((r & 0x003F0) >> 4) + 2;
s = r & 0x3;
这里 S3C2440 PLL 时钟和S3C2410的不一样
#if defined(CONFIG_S3C2440)
if (pllreg == MPLL)
return ((CONFIG_SYS_CLK_FREQ * m * 2) /(p << s));
else if (pllreg == UPLL)
#
endif


ulong get_HCLK(void)
{
struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
S3C2440 根据 CLKDIV 寄存器的值来返回 HCLK的频率
#if defined(CONFIG_S3C2440)
if (readl(&clk_power->CLKDIVN) & 0x6)
{
if ((readl(&clk_power->CLKDIVN) & 0x6)==2)
return(get_FCLK()/2);
if ((readl(&clk_power->CLKDIVN) & 0x6)==6)
return((readl(&clk_power->CAMDIVN) & 0x100) ? get_FCLK()/6 :
get_FCLK()/3);
if ((readl(&clk_power->CLKDIVN) & 0x6)==4)
return((readl(&clk_power->CAMDIVN) & 0x200) ? get_FCLK()/8 :
get_FCLK()/4);
return(get_FCLK());
}
else
return(get_FCLK());
#else
return (readl(&clk_power->CLKDIVN) & 2) ? get_FCLK() / 2 : get_FCLK();
#endif
}


八、
添加网络支持
vim include/configs/fl2440.h
#if 0 禁用 CS89000网卡
#define CONFIG_NET_MULTI
#define CONFIG_CS8900 /* we have a CS8900 on-board */
#define CONFIG_CS8900_BASE 0x19000300
#define CONFIG_CS8900_BUS16 /* the Linux driver does accesses as shorts */
#else 添加 DM9000网卡
#define CONFIG_NET_MULTI 1
#define CONFIG_NET_RETRY_COUNT 20
#define CONFIG_DRIVER_DM9000 1
#define CONFIG_DM9000_BASE 0x20000300 /* nGCS4 */
#define DM9000_IO CONFIG_DM9000_BASE
#define DM9000_DATA (CONFIG_DM9000_BASE+4)

#define CONFIG_DM9000_USE_16BIT 1
#define CONFIG_DM9000_NO_SROM 1
#undef CONFIG_DM9000_DEBUG
#endif
... ...
#define CONFIG_CMD_CACHE
#define CONFIG_CMD_DATE
#define CONFIG_CMD_ELF
#define CONFIG_CMD_PING 添加ping命令支持
我们可以在这里修改
CONFIG_BOOTDELAY 来改变启动时按任意键进入debug模式的延时时间
#define CONFIG_BOOTDELAY 2
/*#define CONFIG_BOOTARGS "root=ramfs devfs=mount console=ttySA0,9600" */
#define CONFIG_ETHADDR 08:00:3e:26:0a:5b 配置网卡的MAC地址
#define CONFIG_NETMASK 255.255.255.0 配置网络子网掩码
#define CONFIG_IPADDR 192.168.1.168 配置网卡IP地址
#define CONFIG_SERVERIP 192.168.1.2 配置TFTP服务器 IP地址
/*#define CONFIG_BOOTFILE "elinos-lart" */
/*#define CONFIG_BOOTCOMMAND "tftp; bootm" */
...  ...
我们可以在这里通过修改 CONFIG_SYS_PROMPT来修改u-boot 的命令提示符
#define CONFIG_SYS_PROMPT "[fl2440@lingyun]# " /* Monitor Command Prompt */ 

vim board/lingyun/fl2440/fl2440.c 从(初始化DM9000网卡)
#ifdef CONFIG_CMD_NET
int board_eth_init(bd_t *bis)
{
int rc = 0;
#ifdef CONFIG_CS8900
rc = cs8900_initialize(0, CONFIG_CS8900_BASE);
#endif
#ifdef CONFIG_DRIVER_DM9000
rc = dm9000_initialize(bis);
#endif
return rc;
}
#endif


九、添加nand flash支持
略.......

到了这里整个u-boot移植就告一段落


问题及解决方法:
1,不能自启动judgment 代码没写在patch文档150行左右
2,删除了宏定义,对照文档修改
3,环境变量设置有问题,要根据自己的系统来修改

关键是细心、细心、细心,重要的事情说三遍,欢迎大家和我讨论,我对u-boot移植也有点一知半解,参考郭工的文档,做了一个多星期。总算是完成了。















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值