您的位置:首页 > 其它

uboot移植记录之前言

2014-11-30 09:14 363 查看
首先是uboot移植记录系列。这系列文章适合于uboot移植的初学者,这里基于常见的开发平台S3C2410。若需要移植uboot到一个全新开发板,则需要参考更多的资料并对uboot有更深入的了解。本人对此也有所钻研,也有个较牛的同事专门做这这个的,呵呵~:) 若感兴趣的朋友大家可以一起探讨。因此关于新平台uboot的移植这里就不多讲了。

uboot移植记录系列专题

环境:Crosstool 3.3.2 + uboot 1.14 + ARMSYS2410开发板

作者:Dongas

移植uboot,通常的方法是参考uboot中已支持的板子进行修改。

在源码下执行#find . -exec grep -l 2410 {} \; 可以查看到uboot中已支持的2410相关的板子。里面有smdk2410,一般情况下我们移植uboot到s3c2410时都是基于这个配置进行修改。具体修改的多少要视板子而定。如果你的板子和smdk2410配置相同的话,甚至不需要修改直接编译针对smdk210平台的就能使用。但这种情况并不多,大部分情况下还是需要进行些简单的修改。 uboot的整个移植过程我们可以分为三个阶段:

一,移植可以从Nor flash启动的uboot

这个阶段是移植一个最简单的uboot,可以烧在Nor flash内运行.

http://blog.chinaunix.net/u2/60011/showart.php?id=1005057

二,移植支持Nand flash驱动的uboot

加入Nand flash驱动的支持,可以在uboot命令行下操作Nand flash.但还未能从Nand flash启动,只能在Nor flash内运行.

http://blog.chinaunix.net/u2/60011/showart.php?id=1005795

三,移植可以从Nand flash启动的uboot

可以烧录在Nand flash,并设置从Nand flash启动运行uboot.

http://blog.chinaunix.net/u2/60011/showart.php?id=1006458

分三个阶段进行移植,可以对整个uboot的移植过程及原理更加清晰明了,同时降低了发现问题时解决问题的困难度和解决范围.

uboot移植记录之一

uboot整个移植过程我们可以分为三个阶段:

一,移植可以从Nor flash启动的uboot

这个阶段是移植一个最简单的uboot,可以烧在Nor flash内运行.

二,移植支持Nand flash驱动的uboot

加入Nand flash驱动的支持,可以在uboot命令行下操作Nand flash.但还未能从Nand flash启动,只能在Nor flash内运行.

三,移植可以从Nor flash启动的uboot

可以烧录在Nand flash,并设置从Nand flash启动运行uboot.

分三个阶段进行移植,可以对整个uboot的移植过程及原理更加清晰明了,同时降低了发现问题时解决问题的困难度和解决范围.

首先介绍移植可以从Nor flash启动的uboot. 这个阶段相对简单一点,是移植一个最简单的uboot,可以烧在Nor flash内运行.不需要修改太多的东西。步骤如下:

测试一下默认的smdk2410_config配置能否在你的板子上正常运行

1.编译uboot1.1.4

#make smdk2410_config

#make ARCH=arm

注:编译针对arm的平台时,uboot默认使用arm-linux-gcc编译,若交叉编译器名字不一样,需要自行在Makefile里修改。

会出现两个错误.

错误信息一:

cc1: Invalid option `abi=apcs-gnu'

  make[1]: *** [hello_world.o] Error 1

  make[1]: Leaving directory `/root/u-boot-1.1.4/examples'

  make: *** [examples] Error 2  

解决办法:

出错的文件是/cpu/arm920t/下的config.mk:



  PLATform_CPPFLAGS +=$(call cc-option,-mapcs-32,-mabi=apcs-gnu)

改成:

  PLATform_CPPFLAGS +=$(call cc-option,-mapcs-32,$(call cc-option,-mabi=apcs-gnu,))

错误信息二:

make[1]: *** No rule to make target `hello_world.srec', needed by `all'. Stop.

make[1]: Leaving directory `/work/src/u-boot-1.1.4/examples'

解决方法:

打开 examples/Makefile

把example文件夹下的Makefile中的

第126行

%.srec: % 改成 %.srec: %.o

第129行的

%.bin: % 改成 %.bin: %.o

2.若编译成功,则会在uboot源码下产生u-boot.bin文件。将这个文件烧录到nor flash。

注意: 默认u-boot的smdk2410_config是不支持nandflash的,只能在nor flash内运行,所以只能烧录到nor flash内运行。如果烧录到nandflash下是不能运行的。

3.参考开发板资料,设置好跳线,从nor flash启动。

启动信息如下:

U-Boot 1.1.4 (Dec 30 2007 - 23:25:02)

U-Boot code: 33F80000 -> 33F9696C BSS: -> 33F9AC58

RAM Configuration:

Bank #0: 30000000 64 MB

*** Warning - bad CRC, using default environment

Flash: 512 kB

In: serial

Out: serial

Err: serial

发现有3个问题:

1) 启动时开发板蜂鸣器一直在响。

怀疑是我的开发板蜂鸣器对应的GPIO口和smdk2410的GPIO口地址不对应,从而导致启动时误赋了值,一直在响。

2) Warning - bad CRC, using default environment

这个问题是因为第一次使用uboot时没有设置过变量,设置保存一下就不会在出现了。

3) Flash: 512 kB

我的板子Nor flash是1MB的,而这里显示512KB

4.下面进行uboot源码修改

这里主要根据开发板硬件的实际情况,基于smdk2410的源码进行修改(主要是配置文件include/configs/smdk2410.h),并解决如上碰到的问题1和3。

若对硬件板子的情况不是太了解,可以参考2410的datasheet以及开发板供应商提供的硬件资料。

从我开发板uboot第一次启动的情况来看,问题不是太大。

首先修改include/configs/smdk2410.h。里面包含了很多对目标板设置的宏。

smdk2410.h的内容和要修改的地方如下:

#define CONFIG_BOOTDELAY 3

/*#define CONFIG_BOOTARGS "root=ramfs devfs=mount console=ttySA0,9600" */

#define CONFIG_ETHADDR 08:00:3e:26:0a:5b

#define CONFIG_NETMASK 255.255.255.0

#define CONFIG_IPADDR 192.168.1.103

#define CONFIG_SERVERIP 192.168.1.102

#define CONFIG_BOOTFILE "uImage"

#define CONFIG_BOOTCOMMAND "tftp 30000000 uImage\; bootm 30000000"

//这是bootdelay后运行的命令

//这些宏对应与uboot的变量,即在uboot命令行下执行printenv打印出的变量。可以在这里设置(定义为默认值),也可以在uboot启动后通过setenv命令设置。

#define CFG_PROMPT "ARMSYS2410 # " /* Monitor Command Prompt */

#define CFG_LOAD_ADDR 0x33000000 /* default load address */

#define CONFIG_NR_DRAM_BANKS 1 /* we have 1 bank of DRAM */

#define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */

#define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */

解决问题3:



#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */

#if 0

#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */

#endif

改为:

#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */

#if 0

#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */

#endif

注意如下两个地方:

#ifdef CONFIG_AMD_LV800

#define PHYS_FLASH_SIZE 0x00100000 /* 1MB */

这里解决了u-boot启动时的问题3即Nor Flash大小为512 kB ,是因为没有选择正确的Nor flash型号。

#define CFG_MAX_FLASH_SECT (19) /* max number of sectors on one chip */

#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x0F0000) /* addr of environment */

宏CFG_ENV_ADDR定义了存放uboot变量的地址,换算一下为1MB-64KB=960KB地方,而实际uboot编译出来的大小仅为120KB左右,由此可以得出,即使从新烧录了新编译的uboot到Nor flash内,也不会影响先前设定使用的uboot变量。

#endif

注:可以在u-boot的README里查到这些部分宏的作用

5.解决蜂鸣器一直响问题

查看ARMSYS2410-B底板电路图,在Reset Singal模块里可以看到蜂鸣器(BUZZER)控制口连接到TOUT1引脚,并且低电平响。如下:



由s3c2410 Datasheet知道TOUT1复用了GPB1口。因此,只要在uboot启动时给GPBDAT寄存器适当赋值,关闭BUZZER就可以了。

修改smdk2410.c

#vi board/smdk2410/smdk2410.c

找到board_init()函数

在gpio->GPBUP = 0x000007FF;下面

添加如下内容:

/*******stop beep******/

gpio->GPBDAT &= ~0x00000002; //Open BUZZER

delay (5000000); //BUZZER Delay Time

gpio->GPBDAT |= 0x00000002;

6.重新编译

#make clean

#make ARCH=arm

7.烧录u-boot.bin到nor flash

启动信息:

U-Boot 1.1.4 (Jan 3 2008 - 23:11:07)

U-Boot code: 33F80000 -> 33F96DC4 BSS: -> 33F9B0E8

RAM Configuration:

Bank #0: 30000000 64 MB

Flash: 1 MB

In: serial

Out: serial

Err: serial

Hit any key to stop autoboot: 0

ARMSYS2410 #

uboot移植记录之二

移植可以从Nor flash启动的uboot请参考uboot移植系列的《uboot移植记录之一》

http://blog.chinaunix.net/u2/60011/showart.php?id=1005057

下面介绍移植支持Nand flash驱动的uboot.

加入Nand flash驱动的支持,可以在uboot命令行下操作Nand flash.但还未能从Nand flash启动,只能在Nor flash内运行.支持从Nandflash启动会在下节介绍。

下面描述详细步骤:

1. 打开Nandflash驱动支持

要使uboot支持nand驱动,需要在smdk2410.h中将CFG_CMD_NAND部分注释取消,打开nandflash功能。

修改如下:

/* include/configs/smdk2410.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)

2. 添加nand_init()函数

Uboot对SMDK2410板的NAND Flash初始化部分没有写

即在lib_arm/board.c中的start_armboot函数中有这么一句:

#if (CONFIG_COMMANDS & CFG_CMD_NAND)

puts ("NAND:");

nand_init(); /* go init the NAND */

#endif

因为前面打开了CFG_CMD_NAND这个宏,uboot编译时会去查询nand_init()这个函数。而在board/smdk2410目录下任何源文件中都没有定义nand_init这个函数。所以需要我们补充这个函数以及这个函数涉及的底层操作。这里我们可以参考VCMA9板的nand_init函数,VCMA9板是一款用S3C2410的板子,因此这部分操作和SMDK2410 Demo Board很相似。大部分代码可以照搬。

分析VCM9板的nand_init()函数,发现需要拷贝如下内容:

首先将board/mpl/vcma9/vcma9.h中下面代码拷贝到common/cmd_nand.c中do_nand函数前面。

/* dongas - support nand driver */

#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

/* dongas - support nand driver - end */

再接着将board/mpl/vcma9/vcma9.c中下面代码拷贝到common/cmd_nand.c中来。

/* dongas - support nand driver */

/*

* 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

/* dongas - support nand driver - end */

另外还要在cmd_nand.c前面加上#i nclude <s3c2410.h>,否则编译时会出现ERROR: "S3C2410_NAND" Undeclared错误!

最后将include/configs/VCMA.9中下面代码拷贝到include/configs/smdk2410.h中来。

/* dongas - support nand driver */

/*-----------------------------------------------------------------------

* NAND flash settings

*/

#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()

/* the following s 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)

#define CONFIG_MTD_NAND_VERIFY_WRITE 1

#define CONFIG_MTD_NAND_ECC_JFFS2 1

#endif /* CONFIG_COMMANDS & CFG_CMD_NAND */

/* dongas - support nand driver - end */

3. 重新编译uboot

#make ARCH=arm

4. 测试加入Nand驱动支持的uboot

下面我们测试一下新编译的带Nand驱动支持的uboot是否有用。由于之前我们已经编译了NOR版本的uboot并烧录在nor flash中,这时我们无需重新烧录新编译的uboot到Nor Flash了。可以直接使用Nor里的uboot提供的串口传输功能,将新编译好的uboot(带nand驱动支持)通过串口传输到sdram中测试,相比重新烧录,这种方法高效率快捷得多。

传输的方法有两种:

1) 使用loadb指令加载uboot.bin

loadb指令使用kermit协议从串口下载二进制文件到开发板的内存中,默认下载到0x33000000。当然你可以改在别的地址。

例如:loadb 30000000就是下载到0x30000000。

首先在uboot命令行模式下执行loadb指令

# loadb

## Ready for binary (kermit) download to 0x33000000 at 115200 bps...

然后选择超级终端菜单上:传送〉发送文件,文件名选择编译好的U-Boot.bin,协议选择Kermit发送,可以看到发送进度。

注:这里使用secure CRT好象不行,没发现其支持kermit协议,只能使用windows自带的超级终端或minicom

发送结束出现提示:

## Total Size = 0x00019a14 = 104980 Bytes

## Start Addr = 0x33000000

传输完后可以测试一下新编译的uboot是否有用:

ARMSYS2410 # go 30000000

注:go指令可以直接执行指定内存地址上的程序,例如刚下载到0x30000000的支持NAND驱动的uboot。

2)其实这里也可以使用tftp协议将uboot下载到指定地址如0x30000000处,再用go指令执行。效果一样,相比上一种这种方法更快捷,前提是网络

功能可用。当然,因为我的板子使用的是CS8900网卡,默认smdk2410就是支持的,所以直接可以使用。(tftp的用法请参考相关资料)

#tftpboot 30000000 u-boot.bin

#go 30000000

执行go指令启动sdram中的uboot后,若出现了“NAND: 64MB”这一行,那么恭喜你,基本上可以确定你的Nand驱动移植已经成功了。

我的启动信息如下:

ARMSYS2410 # go 30000000

## Starting application at 0x30000000 ...

U-Boot 1.1.4 (Jan 9 2008 - 00:08:10)

U-Boot code: 33F80000 -> 33F9A04C BSS: -> 33F9E3E8

RAM Configuration:

Bank #0: 30000000 64 MB

Flash: 1 MB

NAND: 64 MB <------------- 多了这一行! Happying!

In: serial

Out: serial

Err: serial

Hit any key to stop autoboot: 0

ARMSYS2410 nand#

确认一下,输入help,发现比先前NOR版本的U-Boot多了一组nand命令!

#help

mw - memory write (fill)

nand - NAND sub-system <--------- 新增加的Nand命令

nboot - boot from NAND device

……

help nand可以看到更详细的命令说明:

ARMSYS2410 nand# help nand

nand info - show available NAND devices

nand device [dev] - show or set current device

nand read[.jffs2[s]] addr off size

nand write[.jffs2] addr off size - read/write `size' bytes starting at offset `off' to/from memory address `addr'

nand erase [clean] [off size] - erase `size' bytes from offset `off

利用这些命令可以对Nandflash进行读写操作!

输入nand info可以查看NandFlash型片的信息:

ARMSYS2410 # nand info

Device 0: Samsung unknown 64Mb at 0x4e000000 (64 MB, 16 kB sector)

说明我们的Nand驱动移植成功了。

注:这里Nand型号显示为unknown没关系,默认的也可以使用。因为uboot的nand列表里没有K9S1208 64MB,可以自己添加,加入NAND闪存芯片型号

在/include/linux/mtd/ nand_ids.h中对如下结构体赋值进行修改:

static struct nand_flash_dev nand_flash_ids[] = {

......

{"Samsung K9F1208U0B", NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000, 0},

}

当然不添加也没关系,使用默认参数操作NAND也可以。

测试成功后我们将新编好的带Nand驱动支持的uboot烧录到Nor中。

这里也不需要使用工具烧录,用uboot提供的cp命令就可以将自身拷贝到Nor flash了。强大吧,呵呵~

比sjflash烧快多了,uboot既然提供了这么多好的功能,如果不用就太可惜啦!:)

1) 先看看NOR Flash的情况:

ARMSYS2410 nand# flinfo

Bank # 1: AMD: 1x Amd29LV800BB (8Mbit)

Size: 1 MB in 19 Sectors

Sector Start Addresses:

00000000 (RO) 00004000 (RO) 00006000 (RO) 00008000 (RO) 00010000 (RO)

00020000 00030000 00040000 00050000 00060000

00070000 00080000 00090000 000A0000 000B0000

000C0000 000D0000 000E0000 000F0000 (RO)

一共有19个sector,其中前5个总计128kb的sector有U-Boot程序,是写保护的(RO)。要烧写首先要去掉写保护:

注:flinfo命令的作用是显示当前flash(nor)的信息

2) 去掉前5个sector的写保护,大小为128KB,足够容纳我们的uboot了。

ARMSYS2410 # protect off 0 1ffff

Un-Protected 5 sectors

3) 再查看一下:
ARMSYS2410 nand# flinfo

Bank # 1: AMD: 1x Amd29LV800BB (8Mbit)

Size: 1 MB in 19 Sectors

Sector Start Addresses:

00000000 00004000 00006000 00008000 00010000

00020000 00030000 00040000 00050000 00060000

00070000 00080000 00090000 000A0000 000B0000

000C0000 000D0000 000E0000 000F0000 (RO)

可以发现写保护已经去掉了(RO标志不见了)。

4) 擦除前5个sector:

ARMSYS2410 # erase 0 1ffff

Erasing sector 0 ... ok.

Erasing sector 1 ... ok.

Erasing sector 2 ... ok.

Erasing sector 3 ... ok.

Erasing sector 4 ... ok.

Erased 5 sectors

注:这里要确保当前执行的是sdram中的uboot,而非Nor Flash中的uboot ,即依照前面的步骤下载uboot到sdram中,并运行了go指令。

否则会因擦除掉nor中的uboot而crash掉。

5) 拷贝先前加载到内存中的带Nand驱动的uboot到nor flash,即先前使用kermit协议或tftp加载到0x30000000处的uboot。

ARMSYS2410 # cp.b 30000000 0 0x1ffff

Copy to Flash... done

注:cp.b的作用是拷贝内存中的数据,支持cp到nor.

ARMSYS2410 #help cp

cp [.b, .w, .l] source target count.

0x30000000为uboot加载的地址,0x0是NOR Flash的起始地址,烧写的长度为0x1ffff。

6) 重启开发板,启动信息如下:

ARMSYS2410 nand# go 0 //nor起始地址为0x0

U-Boot 1.1.4 (Jan 9 2008 - 00:08:10)

U-Boot code: 33F80000 -> 33F9A04C BSS: -> 33F9E3E8

RAM Configuration:

Bank #0: 30000000 64 MB

Flash: 1 MB

NAND: 64 MB

In: serial

Out: serial

Err: serial

Hit any key to stop autoboot: 0

可以发现新烧写到Nor Flash的uboot可以使用了。

移植记录之三

移植可以从Nor flash启动的uboot请参考uboot移植系列的《uboot移植记录之一》

http://blog.chinaunix.net/u2/60011/showart.php?id=1005057

移植支持Nand flash驱动的uboot请参考uboot移植系列的《uboot移植记录之二》

http://blog.chinaunix.net/u2/60011/showart.php?id=1006458

到目前为此,这个版本的uboot已经加进了Nand驱动,可以使用Nand命令对nandflash进行读写。但是还不能从Nand启动,只可以从Norflash启动或用tftp下载到sdram中然后go到该地址使用。原因是目前移植的uboot还没有实现s3c2410支持的从Nand Flash启动机制需要的自拷贝功能。下面介绍移植可以从Nand flash启动的uboot。

关于这里的Nand Boot概念,如果分析过vivi源码,明白vivi是如何从Nand跳转到sdram中继续执行以及copy_myself原理的话,再理解这里就比较简单了。其实我们这里使uboot支持从nand启动的原理正是移植vivi里的copy_myself机制。关于s3c2410从Nand Flash启动的原理可以查阅其他相关资料,不懂的话也没关系,不影响移植过程。

当然,我们的最终目的是编译一个可以直接烧录到nand中启动的uboot。既然已经到这一步了,要实现nand启动已经很容易了。只需要添加几行代码,大部分从vivi拷贝,只需修改少许地方。

过程如下:

1.在board/smdk2410加入NAND Flash读函数,建立nand_read.c文件,加入如下内容(copy from vivi):

(在vivi源码下的arch\s3c2410\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 */

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; /* chip disable */

return 0;

}

2.修改cpu/arm920t/start.S文件(copy from vivi)

(在vivi源码下的arch\s3c2410\Head.s。

只不过要注意的是完全拷贝过来后需修改两个地方,下面我已经修改好,并且标了出来)

在ldr pc, _start_armboot之前加入:

#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, #0x1

beq 2b

ldr r2, [r1, #oNFCONF]

orr r2, r2, #0x800 @ disable chip

str r2, [r1, #oNFCONF]

@ get read to call C s (for nand_read())

ldr sp, DW_STACK_START @ setup stack pointer

mov fp, #0 @ no previous , so fp=0

@ copy vivi to RAM

ldr r0, =UBOOT_RAM_BASE //replace VIVI_RAM_BASE with UBOOT_RAM_BASE

mov r1, #0x0

mov r2, #0x20000

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 //replace 0x33f00000 with UBOOT_RAM_BASE

mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes

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

sub r0, r0, #4

ldr r1, SerBase

bl PrintHexWord

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 {r2-r9}

subs r1, r1, #(8 * 4)

bne clear_loop

mov pc, lr

#endif @ CONFIG_S3C2410_NAND_BOOT

在文件的最后加入:

.align 2

DW_STACK_START:

.word STACK_BASE+STACK_SIZE-4

注:UBOOT_RAM_BASE即uboot从nand启动时将自身拷贝到sdram中的地址,换句话说就是uboot在sdram中运行的地址。这个地址会在smdk2410中定义。

3.修改include/configs/smdk2410.h文件

添加如下内容:

/*

* Nandflash Boot

*/

#define CONFIG_S3C2410_NAND_BOOT 1

#define STACK_BASE 0x33f00000

#define STACK_SIZE 0x8000

#define UBOOT_RAM_BASE 0x33f80000 //define the position of uboot in the sdram

/* NAND Flash Controller */ //copy from vivi

#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

4.修改board/smdk2410/Makefile为

OBJS := smdk2410.o flash.o nand_read.o

注:此处的目的是把新添加的nand_read.c编译进uboot,若不添加编译时会提示找不到nand_read_ll函数错误。

5.最后将新编译好的带Nand boot功能的uboot.bin烧录到Nand flash中

这里同样不需要烧录工具(sjflash),使用上篇文章已实现的nand驱动提供的命令对nand flash烧写即可。

步骤如下:

1)将新编译好的uboot.bin下载到sdram中地址0x30000000处

ARMSYS2410 nand# tftp 30000000 u-boot.bin

TFTP from server 192.168.1.102; our IP address is 192.168.1.103

Filename 'u-boot.bin'.

Load address: 0x30000000

Loading: #####################

done

Bytes transferred = 107108 (1a264 hex)

2)help一下查看nand命令帮助

ARMSYS2410 nand# help nand

nand info - show available NAND devices

nand device [dev] - show or set current device

nand read[.jffs2[s]] addr off size

nand write[.jffs2] addr off size - read/write `size' bytes starting at offset `off' to/from memory address `addr'

nand erase [clean] [off size] - erase `size' bytes from offset `off

发现nand read/write命令使用很简单,addr为内存地址,off为偏移地址,size为数据大小。要注意的是写nand前必须先擦除。

3)檫除Nand flash前128KB:

ARMSYS2410 nand# nand erase 0 20000

NAND erase: device 0 offset 0, size 131072 ... OK

4)将sdram中的uboot烧录到Nand Flash 0块位置:

ARMSYS2410 nand# nand write 30000000 0 20000

NAND write: device 0 offset 0, size 131072 ... 131072 bytes written: OK

6.重起开发板,设置好跳线从nand flash启动。

之前一直用的从nor flash启动,这把终于可以从nand flash启动啦,激动ing!

启动信息如下:

U-Boot 1.1.4 (Jan 15 2008 - 23:54:03)

U-Boot code: 33F80000 -> 33F9C7E0 BSS: -> 33FA08F0

RAM Configuration:

Bank #0: 30000000 64 MB

Flash: 1 MB

NAND: 64 MB

*** Warning - bad CRC, using default environment

In: serial

Out: serial

Err: serial

Hit any key to stop autoboot: 0

测试了一下,可以正常使用!

到此,uboot移植记录系列完成了!

注:这边有个小插曲。uboot从nand启动时老是卡在"*** Warning - bad CRC, using default environment"这里,并且显示"NAND: 0 MB"。解决这个问题花了好长时间,最后发现竟然是编译器问题,这里我的板子需要把编译器改为crosstool 2.95.3编译,而不是3.3.2。编译后再烧到板子上跑"NAND: 0 MB"的问题就消失了。

还有另外一个问题是不能保存环境变量,错误log如下:

ARMSYS2410 nand# saveenv

Saving Environment to Flash...

Un-Protected 1 sectors

Erasing Flash...Erasing sector 18 ... Erased 1 sectors <-只打印到这边,实际没能保存

上网搜了一下发现解决办法如下:

#vi smdk2410.h

注销掉CFG_ENV_IS_IN_FLASH,改为:

//#define CFG_ENV_IS_IN_FLASH 1 /* Environment is in Nor Flash */

#define CFG_ENV_IS_IN_NAND 1 /* Environment is in Nand Flash */

#define CFG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */

#define CFG_ENV_OFFSET 0X20000

意思是saveenv时将命令保存到nandflash,而不是默认的Nor flash

保存环境变量成功LOG如下:

ARMSYS2410 nand# saveenv

Saving Environment to NAND...

Erasing Nand...Writing to Nand... done
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: