根据u-boot-1.1.6目录下的README文件2375行的提示,可以知道要使uboot支持一款新的开发板,要经过以下步骤:
l 在顶层Makefile文件中新增一个配置选项。
l 在board目录下添加一个新的目录来支持你的开发板,在该目录下,至少需要有以下文件:Makefile,<board>.c flash.c u-boot.lds。
l 在include/configs目录下添加一个头文件 <board>.h。
l 如果你的cpu不被uboot所支持,还要添加一个新的目录和所需要的文件来支持你的cpu。
l 运行make<board>_config
l 运行make
下面根据以上的提示一步一步的说明如何使uboot支持FS2410开发板
1. 修改顶层Makefile文件,在1881行添家如下内容:
fs2410_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t fs2410NULL s3c24x0
2. 进入board目录,执行如下命令。
cp –avsmdk2410 fs2410
cd fs2410
mv smdk2410.c fs2410.c
根据开发板的配置修改board/fs2410/lowlevel_init.S文件。
将54行的
#define B1_BWSCON (DW32)
改为
#define B1_BWSCON (DW16)
将126行的
#define REFCNT 1112
改为
#define REFCNT 0x4f4
在board/fs2410目录下新建boot_init.c文件,内容如下:
#include <common.h>
#include <s3c2410.h>
#define BUSY 1
void nand_init_ll(void);
void nand_read_ll(unsigned char *buf, unsigned longstart_addr, int size);
static void s3c2410_nand_reset(void);
static void s3c2410_wait_idle(void);
static void s3c2410_nand_select_chip(void);
static void s3c2410_nand_deselect_chip(void);
static void s3c2410_write_cmd(intcmd);
static void s3c2410_write_addr(unsignedint addr);
static unsigned char s3c2410_read_data(void);
static void s3c2410_nand_reset(void)
{
s3c2410_nand_select_chip();
s3c2410_write_cmd(0xff);
s3c2410_wait_idle();
s3c2410_nand_deselect_chip();
}
static void s3c2410_wait_idle(void)
{
int i;
S3C2410_NAND* s3c2410nand = (S3C2410_NAND *)0x4e000000;
volatile unsigned char *p = (volatileunsigned char *)&s3c2410nand->NFSTAT;
while(!(*p & BUSY))
for(i=0; i<10; i++);
}
static void s3c2410_nand_select_chip(void)
{
int i;
S3C2410_NAND* s3c2410nand = (S3C2410_NAND *)0x4e000000;
s3c2410nand->NFCONF&= ~(1<<11);
for(i=0; i<10; i++);
}
static void s3c2410_nand_deselect_chip(void)
{
S3C2410_NAND* s3c2410nand = (S3C2410_NAND *)0x4e000000;
s3c2410nand->NFCONF|= (1<<11);
}
static void s3c2410_write_cmd(intcmd)
{
S3C2410_NAND* s3c2410nand = (S3C2410_NAND *)0x4e000000;
volatile unsigned char *p = (volatileunsigned char *)&s3c2410nand->NFCMD;
*p = cmd;
}
static void s3c2410_write_addr(unsignedint addr)
{
int i;
S3C2410_NAND* s3c2410nand = (S3C2410_NAND *)0x4e000000;
volatile unsigned char *p = (volatileunsigned char *)&s3c2410nand->NFADDR;
*p = addr & 0xff;
for(i=0; i<10; i++);
*p = (addr >> 9) & 0xff;
for(i=0; i<10; i++);
*p = (addr >> 17) & 0xff;
for(i=0; i<10; i++);
*p = (addr >> 25) & 0xff;
for(i=0; i<10; i++);
}
static unsigned char s3c2410_read_data(void)
{
S3C2410_NAND* s3c2410nand = (S3C2410_NAND *)0x4e000000;
volatile unsigned char *p = (volatileunsigned char *)&s3c2410nand->NFDATA;
return *p;
}
void nand_init_ll(void)
{
S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;
#define TACLS 0
#define TWRPH0 3
#define TWRPH1 0
s3c2410nand->NFCONF=(1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
s3c2410_nand_reset();
}
#define NAND_SECTOR_SIZE 512
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)
void nand_read_ll(unsigned char *buf, unsigned longstart_addr, int size)
{
int i, j;
if ((start_addr & NAND_BLOCK_MASK) ||(size & NAND_BLOCK_MASK)) {
return ;
}
s3c2410_nand_select_chip();
for(i=start_addr; i < (start_addr +size);) {
s3c2410_write_cmd(0);
/* Write Address */
s3c2410_write_addr(i);
s3c2410_wait_idle();
for(j=0; j < NAND_SECTOR_SIZE; j++,i++) {
*buf = s3c2410_read_data();
buf++;
}
}
s3c2410_nand_deselect_chip();
return ;
}
int CopyCode2Ram(unsigned long start_addr, unsigned char*buf, int size)
{
nand_init_ll();
nand_read_ll(buf,start_addr,(size+NAND_BLOCK_MASK)&~(NAND_BLOCK_MASK));
return 0;
}
修改/board/fs2410/Makefile文件
将28行的
COBJS := smdk2410.o flash.o
改为
COBJS := fs2410.o flash.o boot_init.o
修改/board/fs2410/u-boot.lds文件
在第36行添加
board/fs2410/boot_init.o(.text)
3. 进入include/configs目录,将smdk2410.h复制为 fs2410.h。
cp smdk2410.h fs2410.h
4. 修改cpu/arm920t/start.S文件
在relocate:标号前添加如下内容
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE /* upper128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3words for abort-stack */
将relocate子程序中的
beq stack_setup
改为
beq clear_bss
在add r2, r0, r2(copy_loop:标号的上一行)指令的前面添加如下内容
#if 1
bl CopyCode2Ram /* r0: source,r1: dest, r2: size */
#else
在ble copy_loop 指令后添加 #endif
最后删除clear_bss:标号前的设置堆栈的那些代码,否则编译的时候将出现重复定义的错误。
至此,u-boot已经可以从nand上启动了。
5. 执行
make distclean
make fs2410_config
make
将生成的u-boot.bin 烧到nand中,运行将会出现如下提示信息:
U-Boot 1.1.6(Jun 5 2010 - 19:19:07)
DRAM: 64 MB
Flash: 512 kB
*** Warning - bad CRC, usingdefault environment
In: serial
Out: serial
Err: serial
SMDK2410 #
6. 增加u-boot对Nand flash的支持
取消include/configs/fs2410.h 文件中
#define CONFIG_COMMANDS \
(CONFIG_CMD_DFL | \
CFG_CMD_CACHE | \
CFG_CMD_NAND | \
/*CFG_CMD_EEPROM |*/ \
/*CFG_CMD_I2C |*/ \
/*CFG_CMD_USB |*/ \
CFG_CMD_REGINFO | \
CFG_CMD_DATE | \
CFG_CMD_ELF)
中的CFG_CMD_NAND的注释,使之有效
然后执行
Make fs2410_config
Make
出现如下提示
error: `NAND_MAX_CHIPS'undeclared here (not in a function)
nand.c:35: error:`CFG_MAX_NAND_DEVICE' undeclared here (not in a function)
nand.c:38: error:`CFG_NAND_BASE' undeclared here (not in a function)
nand.c:35: error: storage sizeof `nand_info' isn't known
nand.c:37: error: storage sizeof `nand_chip' isn't known
nand.c:38: error: storage sizeof `base_address' isn't known
nand.c:37: warning:'nand_chip' defined but not used
nand.c:38: warning:'base_address' defined but not used
在include/configs/fs2410.h 文件中增加如下语句即可解决上述错误:
#define CFG_NAND_BASE 0
#defineCFG_MAX_NAND_DEVICE 1
#define NAND_MAX_CHIPS 1
然后重新编译,出现如下信息:
/drivers/nand/nand.c:50: undefinedreference to `board_nand_init'
说明 board_nand_init 函数未定义,需要做如下修改
在cpu/arm920t/s3c24x0 目录下新建一个nand_flash.c 文件,内容如下:
/*
* Changed from drivers/mtd/nand/s3c2410.c of kernel 2.6.13
*/
#include <common.h>
#if (CONFIG_COMMANDS &CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
#include <s3c2410.h>
#include <nand.h>
DECLARE_GLOBAL_DATA_PTR;
#define S3C2410_NFSTAT_READY (1<<0)
#define S3C2410_NFCONF_nFCE (1<<11)
/* select chip, for s3c2410 */
static void s3c2410_nand_select_chip(struct mtd_info*mtd, int chip)
{
S3C2410_NAND* const s3c2410nand =S3C2410_GetBase_NAND();
if (chip == -1) {
s3c2410nand->NFCONF|= S3C2410_NFCONF_nFCE;
} else {
s3c2410nand->NFCONF&= ~S3C2410_NFCONF_nFCE;
}
}
/* command and controlfunctions, for s3c2410
*
* Note, these all use tglx's method of changingthe IO_ADDR_W field
* to make the code simpler, and use the nandlayer's code to issue the
* command and address sequences via the properIO ports.
*
*/
static void s3c2410_nand_hwcontrol(struct mtd_info*mtd, int cmd)
{
S3C2410_NAND* const s3c2410nand = S3C2410_GetBase_NAND();
struct nand_chip *chip = mtd->priv;
switch (cmd) {
case NAND_CTL_SETNCE:
case NAND_CTL_CLRNCE:
printf("%s: called forNCE\n", __FUNCTION__);
break;
case NAND_CTL_SETCLE:
chip->IO_ADDR_W = (void *)&s3c2410nand->NFCMD;
break;
case NAND_CTL_SETALE:
chip->IO_ADDR_W = (void *)&s3c2410nand->NFADDR;
break;
/* NAND_CTL_CLRCLE: */
/* NAND_CTL_CLRALE: */
default:
chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;
break;
}
}
/* s3c2410_nand_devready()
* returns 0 if the nand is busy, 1 if it isready
*/
static int s3c2410_nand_devready(struct mtd_info*mtd)
{
S3C2410_NAND* const s3c2410nand = S3C2410_GetBase_NAND();
return (s3c2410nand->NFSTAT & S3C2410_NFSTAT_READY);
}
/*
* Nand flash hardware initialization:
* Set the timing, enable NAND flash controller
*/
static void s3c24x0_nand_inithw(void)
{
S3C2410_NAND* const s3c2410nand =S3C2410_GetBase_NAND();
#define TACLS 0
#define TWRPH0 4
#define TWRPH1 2
if (gd->bd->bi_arch_number ==MACH_TYPE_SMDK2410)
{
/* Enable NAND flashcontroller, Initialize ECC, enable chip select, Set flash memory timing */
s3c2410nand->NFCONF=(1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH
<<0);
}
}
/*
* Called by drivers/nand/nand.c, initializethe interface of nand flash
*/
void board_nand_init(structnand_chip *chip)
{
S3C2410_NAND* const s3c2410nand = S3C2410_GetBase_NAND();
s3c24x0_nand_inithw();
if (gd->bd->bi_arch_number ==MACH_TYPE_SMDK2410) {
chip->IO_ADDR_R = (void *)&s3c2410nand->NFDATA;
chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;
chip->hwcontrol = s3c2410_nand_hwcontrol;
chip->dev_ready = s3c2410_nand_devready;
chip->select_chip = s3c2410_nand_select_chip;
chip->options = 0;
}
chip->eccmode = NAND_ECC_SOFT;
}
#endif
修改该目录下的Makefile文件
将
COBJS = i2c.ointerrupts.o serial.o speed.o \
usb_ohci.o
改为
COBJS = i2c.ointerrupts.o serial.o speed.o \
usb_ohci.o nand_flash.o
重新执行
Make fs2410_config
Make
将生成的u-boot.bin 烧写进nand,运行结果如下:
U-Boot 1.1.6(Jun 5 2010 - 20:42:43)
DRAM: 64 MB
Flash: 512KB
NAND: 64 MiB
*** Warning - bad CRC or NAND,using default environment
In: serial
Out: serial
Err: serial
SMDK2410 #
7. 增加 yaffs文件系统烧写支持。
修改common/cmd_nand.c文件。
在458行的U_BOOT_CMD 中加入 nand write.yaffs 的说明,修改后的U_BOOT_CMD 如下所示
U_BOOT_CMD(nand, 5,1, do_nand,
"nand - NAND sub-system\n",
"info - show available NANDdevices\n"
"nand device[dev] - show or set currentdevice\n"
"nandread[.jffs2] - addr off|partitionsize\n"
"nand write[.jffs2] - addr off|partiton size - read/write`size' bytes starting\n"
" at offset `off' to/from memory address`addr'\n"
"nandread.yaffs addr off size - read the `size' byte yaffs image starting\n"
" at offset `off' to memory address`addr'\n"
"nandwrite.yaffs addr off size - write the `size' byte yaffs image starting\n"
" at offset `off' from memory address`addr'\n"
"nand erase[clean] [off size] - erase `size' bytes from\n"
" offset `off' (entire device if notspecified)\n"
"nand bad -show bad blocks\n"
"nanddump[.oob] off - dump page\n"
"nand scrub- really clean NAND erasing bad blocks (UNSAFE)\n"
"nandmarkbad off - mark bad block at offset (UNSAFE)\n"
"nand biterroff - make a bit error at offset (UNSAFE)\n"
"nand lock[tight] [status] - bring nand to lock state or display locked pages\n"
"nand unlock[offset] [size] - unlock section\n");
然后,修改 do_nand函数,在其中加入 nand write.yaffs 的支持:具体修改如下
在354行的
} else {
前添加如下语句:
}else if ( s != NULL && !strcmp(s,".yaffs")){
if (read) {
/* read */
nand_read_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer = (u_char*) addr;
opts.length = size;
opts.offset = off;
opts.readoob = 1;
opts.quiet = quiet;
ret = nand_read_opts(nand, &opts);
}else {
/* write */
nand_write_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer = (u_char*) addr;
opts.length = size;
opts.offset = off;
/* opts.forceyaffs = 1; */
opts.noecc = 1;
opts.writeoob = 1;
opts.blockalign = 1;
opts.quiet = quiet;
opts.skipfirstblk = 1;
ret = nand_write_opts(nand, &opts);
}
修改include/nand.h文件中的 nand_write_options 结构,
在79行的
int blockalign
后面添加如下语句
int skipfirstblk;
修改 drivers/nand/nand_util.c 文件中的 nand_write_opts 函数
在300行的
int result;
后面添加
int skipfirstblk =opts->skipfirstblk;
修改 drivers/nand/nand_base.c文件中的 nand_write_page函数
将910行的
printk(KERN_WARNING "Writing data without ECC to NAND-FLASH is notrecommended\n");
注释掉。
至此,u-boot移植完成。
最后,修改include/configs/fs2410.h 文件的参数以方便今后的开发,下面仅列出部分内容
#define CONFIG_BOOTDELAY 3
#define CONFIG_BOOTARGS "noinitrd root=/dev/mtdblock2init=/linuxrc rootfstype=yaffs console=ttySAC0"
#define CONFIG_ETHADDR 08:00:3e:26:0a:5b
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 192.168.0.4
#define CONFIG_SERVERIP 192.168.0.10
/*#define CONFIG_BOOTFILE "elinos-lart" */
#defineCONFIG_BOOTCOMMAND "nboot0x30000000 0 0x100000; bootm 0x30000000"
/* for tag(s) to transfermessage to kernel, add by yetao */
#defineCONFIG_SETUP_MEMORY_TAGS 1
#defineCONFIG_CMDLINE_TAG 1
#define CFG_PROMPT "FS2410 # " /* Monitor Command Prompt */
//#define CFG_ENV_IS_IN_FLASH 1
#defineCFG_ENV_IS_IN_NAND 1
#define CFG_ENV_OFFSET 0x40000
#define CFG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */
#define CFG_NAND_BASE 0
#defineCFG_MAX_NAND_DEVICE 1
#define NAND_MAX_CHIPS 1
8. 增加自定义分区支持
在include/configs/fs2410.h 文件中增加如下宏,就可以使uboot支持分区
#define CONFIG_JFFS2_CMDLINE 1
#define CONFIG_JFFS2_NAND 1
#define MTDIDS_DEFAULT"nand0=nandflash0"
#define MTDPARTS_DEFAULT"mtdparts=nandflash0:1m@0(bios),"\
"2m(kernel)," \
"-(fs)"
#define CONFIG_COMMANDS \
(CONFIG_CMD_DFL | \
CFG_CMD_CACHE | \
CFG_CMD_NAND | \
CFG_CMD_JFFS2 | \
/*CFG_CMD_EEPROM |*/ \
/*CFG_CMD_I2C |*/ \
/*CFG_CMD_USB |*/ \
CFG_CMD_REGINFO | \
CFG_CMD_DATE | \
CFG_CMD_ELF)
上面的MTDPARTS_DEFAULT宏将nand分为3个区
Bios 分区 1MB
kernel 分区 2MB
fs 分区 63MB
9. 制作用户自定义的启动菜单
首先在 common 目录下新建一个 cmd_menu.c 文件。内容如下:
#include <common.h>
#include <command.h>
#include <nand.h>
extern char console_buffer[];
extern int readline (constchar *const prompt);
void param_menu_usage(void)
{
printf("\r\n<**********************************>\r\n");
printf("\r\n<* FS2410 Parameter Options *>\r\n");
printf("\r\n<* http://yet.cublog.cn *>\r\n");
printf("\r\n<**********************************>\r\n");
printf("[v] View theparameters\r\n");
printf("[s] Set parameter \r\n");
printf("[d] Delete parameter\r\n");
printf("[w] Write the parameters toNand Flash \r\n");
printf("[q] Quit \r\n");
printf("Enter your selection: ");
}
void param_menu_shell(void)
{
char c;
char cmd_buf[256];
while (1)
{
param_menu_usage();
c = getc();
printf("%c\n", c);
switch (c)
{
case 'V':
case 'v':
{
strcpy(cmd_buf, "printenv");
printf("Name(enter to viewall paramters): ");
readline(NULL);
strcat(cmd_buf,console_buffer);
run_command(cmd_buf, 0);
break;
}
case 'S':
case 's':
{
sprintf(cmd_buf, "setenv");
printf("Name: ");
readline(NULL);
strcat(cmd_buf, console_buffer);
printf("Value: ");
readline(NULL);
strcat(cmd_buf, " ");
strcat(cmd_buf,console_buffer);
run_command(cmd_buf, 0);
break;
}
case 'D':
case 'd':
{
sprintf(cmd_buf, "setenv");
printf("Name: ");
readline(NULL);
strcat(cmd_buf,console_buffer);
run_command(cmd_buf, 0);
break;
}
case 'W':
case 'w':
{
sprintf(cmd_buf,"saveenv");
run_command(cmd_buf, 0);
break;
}
case 'Q':
case 'q':
{
return;
break;
}
}
}
}
void main_menu_usage(void)
{
printf("\r\n<*****************************>\r\n");
printf("\r\n<* FS2410 Boot Option *>\r\n");
printf("\r\n<* http://yet.cublog.cn *>\r\n");
printf("\r\n<*****************************>\r\n");
printf("[u] Download u-boot to NandFlash\r\n");
printf("[k] Download Linux kernel toNand Flash\r\n");
printf("[j] Download JFFS2 image toNand Flash\r\n");
printf("[y] Download YAFFS image toNand Flash\r\n");
printf("[p] Download test.bin to SDRAMand Run it\r\n");
printf("[b] Boot thesystem\r\n");
printf("[s] Set the bootparameters\r\n");
printf("[r] Reboot u-boot\r\n");
printf("[q] Quit from menu\r\n");
printf("Enter your selection: ");
}
void menu_shell(void)
{
char c;
char cmd_buf[200];
while (1)
{
main_menu_usage();
c = getc();
printf("%c\n", c);
switch (c)
{
case 'U':
case 'u':
{
strcpy(cmd_buf, "tftp0x30000000 u-boot.bin; nand erase bios; nand write.jffs2 0x30000000 bios$(filesize)");
run_command(cmd_buf, 0);
break;
}
case 'K':
case 'k':
{
strcpy(cmd_buf, "tftp0x30000000 uImage; nand erase kernel; nand write.jffs2 0x30000000 kernel $(filesize)");
run_command(cmd_buf, 0);
break;
}
case 'J':
case 'j':
{
strcpy(cmd_buf, "tftp0x30000000 fs.jffs2; nand erase fs; nand write.jffs2 0x30000000 fs$(filesize)");
run_command(cmd_buf, 0);
break;
}
case 'Y':
case 'y':
{
strcpy(cmd_buf, "tftp0x30000000 fs.yaffs; nand erase fs; nand write.yaffs 0x30000000 fs$(filesize)");
run_command(cmd_buf, 0);
break;
}
case 'P':
case 'p':
{
strcpy(cmd_buf, "tftp0x30000000 test.bin");
run_command(cmd_buf, 0);
strcpy(cmd_buf, "go0x30000000");
run_command(cmd_buf, 0);
break;
}
case 'B':
case 'b':
{
printf("Booting Linux ...\n");
strcpy(cmd_buf, "nandread.jffs2 0x30000000 kernel; bootm 0x30000000");
run_command(cmd_buf, 0);
break;
}
case 'S':
case 's':
{
param_menu_shell();
break;
}
case 'R':
case 'r':
{
strcpy(cmd_buf,"reset");
run_command(cmd_buf, 0);
break;
}
case 'Q':
case 'q':
{
return;
break;
}
}
}
}
int do_menu (cmd_tbl_t *cmdtp,int flag, int argc, char *argv[])
{
menu_shell();
return 0;
}
U_BOOT_CMD(
menu, 3, 0, do_menu,
"menu - display a menu, to select the items to dosomething\n",
" - display a menu, to select the items to dosomething"
);
然后修改common/main.c 文件中的 main_loop 函数
在366行的
#ifdef CONFIG_PREBOOT
前添加如下内容:
#ifdef CONFIG_JFFS2_CMDLINE
extern int mtdparts_init(void);
if (!getenv("mtdparts"))
{
run_command("mtdpartsdefault", 0);
}
else
{
mtdparts_init();
}
#endif
在
#ifdef CFG_HUSH_PARSER
parse_file_outer();
/* This point is never reached */
for (;;);
前添加
run_command("menu",0);
修改common/Makefile 文件
将54行的
virtex2.o xilinx.o crc16.oxyzModem.o cmd_mac.o
改为
virtex2.o xilinx.o crc16.oxyzModem.o cmd_mac.o cmd_menu.o
最后执行
make fs2410_config
make
将生成的u-boot.bin 文件烧进nand flash 中,启动后3秒内按任意键就可进入用户菜单了。(完)