移植u-boot2009.08到OK2440V3开发板(1)---方向与方法
开发板到了之后,用的是板子自带的bootloader、linux内核和文件系统,在上面跑了几个小程序知道流程和方法后,就想着用自已移植的这些东西了,因为既然要搞底层的东西,我想这些东西还是要学会的。
刚开始踌躇满志,以为不会有什么困难,网上不都多得是文章吗。可实际上,下了N多资料,看了N多文章之后,下到flash中一运行,串口控制台中什么都没有,当时真有点蒙了。其实不成功,倒还没什么,关键是你想继续努力的时候,却没有方向和方法,那真的才是又浪费时间,又郁闷。
不过还得感谢网络,文章看多了,就知道哪些可以直接close,那些可以复制下来慢慢看(我通常都是一气狂搜,一气“另存为”,最后再集中在一起看)。三五天后,终于找到了方向和方法,而且在sdram中运行,成功地在串口输出里看到了u-boot启动信息。
第一次学做u-boot移植,综合别人的方法,总结归纳如下:
1. 先不去考虑nor/nand flash启动,先让u-boot在SDARM中成功运行。
2. 把那个既经典又简单又very useful的调试方法用上,那就是在程序中需要的地方加上led灯指示。
(有时串口没信息,一头雾水,连自己的程序是否在运行都不知道,这里在程序开头加led的代码,最合适不过了)
3. u-boot能在SDRAM中运行后,先考虑nor flash中运行(如果有nor flash的话),因为支持nor flash比支持nand flash改动少,较容易一些。SMDK2410里也是支持nor flash的,那里用的是AMD公司的。
4. 能在flash 中启动后,增加nand支持,看是否能检测到nand,并在u-boot中用些nand的命令验证驱动是否有问题。
5. 增加代码,让u-boot从nand启动。
6. u-boot可是从nand启动后,增加代码,让代码能自动识别跳线的设置,从相应的flash启动。
以上6步完成之后,关于启动方面的就完成了,如果有需要,再增加这个u-boot的其它功能,比如:网络支持、USB支持等,这些部分如果自已的开发板和SMDK2410不同的话,也是要做移植的。
这个过程我正在进行中,已进行到第三步,前两部的具体实现过程在后面的文章中写出来,只为了自已以后用到的时候,有资料可查,不然忘了又得花时间,相当于做笔记吧。
移植u-boot2009.08到OK2440V3开发板(2)---在SDRAM中运行
(2009-12-8 17:07) 其实这篇日记早就该出炉了,只因为在进行下一步(nor flash驱动)的移植中,遇到了麻烦,很大的麻烦,所以也没时间来写这一篇日记。nor flash驱动还没有搞定,自己花了太多的时间,又没人指导,身心疲惫,想先放一放,或者先跳过。于是现在来整理一下移植过程的第一步---u-boot在SDRAM中运行。
前一篇移植日记之所以把移植过程分那么多步,是因为这样可以减少问题出现的范围,也可以让自己更清楚所有的移植是怎样一步步做起来的。这一步是移植中最简单的,也是最基本的,先这样做可以为以后的移植搭好一个平台和框架。
1.拷贝/board/samsung/目录下smdk2410文件夹到/board/samsung/下,取名为ok2440v3;并修改ok2440v3目录下的smdk2410.c文件的文件名为ok2440v3.c。(建立自己的开发板目录)
2.拷贝/include/configs目录下smdk2410.h,并重命名为ok2440v3.h(建立自己的开发板的配属文件);
因为我们是在SDRAM中运行,所以在此文件中定义两个宏,不拷贝代码到ram中和不进行底层初始化:
#define CONFIG_SKIP_LOWLEVEL_INIT 1
#define CONFIG_SKIP_RELOCATE_UBOOT 1
3.修改顶层Makefile文件,在smdk2410_config后面添加ok2440v3_config,如下所示:(设置自己的开发板的编译配置)
# added by liweikui for supporting OK2440V3
ok2440v3_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t ok2440v3 samsung s3c24x0
4.修改顶层Makefile文件,在CROSS_COMPILE ?=后面添加自己的交叉编译工具。(设置交叉编译工具)
CROSS_COMPILE ?= /usr/local/arm_across/4.3.2/bin/arm-linux-
5.修改/board/samsung/ok2440v3目录下的Makefile文件中的COBJS,如下所示:
COBJS := ok2440v3.o flash.o
上面这几步是很通用的了,到这里,就可以用下面两条命令编译,测试一下是否可以生成最后的u-boot.bin文件:
make ok2440v3_config
make
成功生成u-boot.bin文件后,对于CPU为s3c2410,控制台串口用的是串口0的开发板来说,应当就可以使用了。但对于s3c2440来说,运行这个bin文件是没有串口输出的!
************************************
原来,2440与2410的一个重要的区别就是,在相同的外部时钟(12M)的情况下,默认得到的内部时钟FCLK/HCLK/PCLK是不一样的,而这些时钟会影响到口串口的波特率。具体修改如下:
1.修改/cpu/arm920t/start.S中的相关部分:
(1)先在相应位置增加如下宏定义:
# define LOCKTIME 0x4C000000
# define MPLLCON 0x4C000004
# define UPLLCON 0x4C000008
# define CAMDIVN 0x4C000018
(2) 修改禁止中断部分,2440比2410的中断多了几位,相应部分,修改如下:
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x7fff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
(3)中断修改完后,新增下述两个寄存器的配置:
//locktime用来在正常运行时更改时钟的时候保护时钟
ldr r0,=LOCKTIME
mov r1,#0xffffff
str r1,[r0]
//清除摄像头分频寄存器值,这个值会影响HCLK
ldr r0,=CAMDIVN
mov r1,#0
str r1,[r0]
(4)关于时钟的初始化部分,把相应部分替换为:
//初始化时钟,晶振为12MHz,主频为405MHz
/* FCLK:HCLK:PCLK = 1:4:8 */
ldr r0, =CLKDIVN
mov r1, #5
str r1, [r0]
//在2440的手册中写着若HDIVN不为0,则需要下面几句
mrc p15, 0, r1, c1, c0, 0 //read ctrl register
orr r1, r1, #0xc0000000 //Asynchronous
mcr p15, 0, r1, c1, c0, 0 //write ctrl register
//USB时钟48MHz (56<<12)+(2<<4)+(2)
ldr r0, =UPLLCON
ldr r1, =0x00038022
str r1, [r0]
//arm920t为5级流水线,延迟几个周期,使指令生效
nop
nop
nop
nop
nop
nop
nop
nop
//写MPLL使pll生效,405MHz,(127<<12)+(2<<4)+(1)
ldr r0, =MPLLCON
ldr r1, =0x0007f021
str r1, [r0]
(注:上述的遇到CONFIG_S3C2410保持原样,如果要u-boot能分辩2410与2440的话,定义CONFIG_S3C2440后,改的地方很多,为了抓住移植的关键部分,我暂没有那样做)
2.修改/board/samsung/ok2440v3目录下ok2440v3.C文件中关于时钟的部分,如下所示:
#elif FCLK_SPEED==1 /* Fout = 405MHz FCLK:HCLK:PCLK = 1:4:8 */
#define M_MDIV 0x7f
#define M_PDIV 0x2
#define M_SDIV 0x1
3.因为2440与2410对FCLK的计算公式不一样,所以还要修改/cpu/arm920t/s3c24x0/speed.c文件中FCLK的计算:
把下面的部分:
m = ((r & 0xFF000) >> 12) + 8;
p = ((r & 0x003F0) >> 4) + 2;
s = r & 0x3;
return((CONFIG_SYS_CLK_FREQ * m) / (p << s));
替换为:
m = ((r & 0xFF000) >> 12) + 8;
p = ((r & 0x003F0) >> 4) + 2;
s = r & 0x3;
if(pllreg == MPLL)
return((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s));
else
return((CONFIG_SYS_CLK_FREQ * m) / (p << s));
4.修改/cpu/arm920t/s3c24x0/speed.c中的 get_HCLK函数如下:
/* return HCLK frequency */
ulong get_HCLK(void)
{
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
//return((clk_power->CLKDIVN & 0x2) ? get_FCLK()/2 : get_FCLK());
return (get_FCLK()/4); //for s3c2440 1:4:8 !!!
}
(注:这里的修改采取了一个简单的,但适应性不好的改法,只用于FCLK:HCLK:PCLK = 1:4:8的情况,如果要完整修改的话,按2440的数据手册,这里不能这么简单处理。如何做,网上很多,可以找到)
到这里,关于串口的修改就结束了。说来不怕笑话,因为这个问题,我也被搞了两天,一直没串口输出,问题不难,却真的是一个时钟频率引发的血案啊,呵呵。。
好了,做完上面所有修改后,执行make ok2440v3_config与make,生成u-boot.bin,下载到SDRAM中,就可以从串口看到信息了。
*************************************
如果在实验中遇到了问题,可以用led灯来跟踪的方法,这里,我附上针对OK2440V3开发板的点亮led灯的汇编代码和C代码:
/* leds for testing and tracing ,GPF3-6 : LED0-3 */
#define GPFCON 0x56000050
#define GPFDAT 0x56000054
#define GPFUP 0x56000058
ldr r0,=GPFUP // 0:enable pull up ; 1:disable pull up
ldr r1,=0xfffff87 //使能上拉F3-6
str r1,[r0]
ldr r0,=GPFCON
ldr r1,=0xd57f //将F3-6设为输出口
str r1,[r0]
ldr r0,=GPFDAT
ldr r1,=0xf7 //点亮LED0 (不同的地方我们可以点亮不同的灯)
str r1,[r0]
/* end of leds testing */
/* leds test for ok2440v3 */
S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
gpio->GPFCON = 0xd57f; //将F3-6设为输出口
gpio->GPFUP = 0xfffff87; //使能上拉F3-6
gpio->GPFDAT = 0xe7; //再点亮LED1
(注:若要使用上述C语言的led测试程序,需包含头文件 s3c2410.h)
*******************************
这里再总结一下,在这一移植过程中,我们要关注的有哪些文件:
1.两个Makefile文件,顶层Makefile和自已的开发板下的Makefile;
2.自已的开发板下ok2440v3.c文件;
3.启动后执行的第一个文件,/cpu/arm920t/start.S;
4.C语言入口文件/lib_arm/board.c,start.S执行完后跳到此文件执行;
5.和时钟计算相关的文件/cpu/arm920t/s3c24x0/speed.c
6.板级初始化/board/samsung/ok2440v3/ok2440v3.C文件
7.板级配置文件/include/configs/ok2440v3.h
移植u-boot2009.08到OK2440V3开发板(3)---nor flash启动
(2009-12-10 19:43) 前面一篇移植关键在于串口输出的部分,当时花了我2,3天时间,我叫它“一个时钟引发的惨案”,现在想起来,那还是小的,这篇日记要记录的,整整花了我一个星期的时间!真的可以叫做“一个驱动引发的血案”了,呵呵。
本来如果只是支持从nor flash启动倒是不难,u-boot的启动过程中只用到了一个flash的初始化函数。如下所示:
#ifndef CONFIG_SYS_NO_FLASH
/* configure available FLASH banks */
display_flash_config (flash_init ());
#endif /* CONFIG_SYS_NO_FLASH */
关键是,我没有在linux下烧写我这款norflash的工具!我必须要切换到windows下才行,这太麻烦了,我就想在u-boot里把我这款norflash的驱动搞定,包括保护、去保护、擦除、读写等,好让u-boot启动后能使用flash的命令,然后烧写norflash。这一想不要紧,在u-boot里找到的驱动程序有问题。为了解决这个问题,自己又不想放弃,“血案”就这样发生了,呵呵。
不过一个星期后的痛苦挣扎后,问题总算解决了。(虽然问题不大,但对我这样的新手来说,又没人指导,有时一个小问题真的会让人郁闷透顶!)
*************************************
下面先看如何在u-boot中支持nor flash的烧写,我的开发板上的norflash芯片是Intel的JS28F320(4MB)(1device=32blocks,1block=128MB)。为了缩小问题发生的范围,我们还是先让u-boot在SDRAM中运行(仍然要定义那两个宏定义:不复制代码到SDARM和不进行底层初始化)。当然,在SDRAM中运行前,需要用别的初始化程序先初始化内存才行。
下面的操作都是前一篇移植完成后的基础上进行的。
1. 把开发板的配置文件ok2440v3.h(/include/configs/ok2440v3.h)中关于flash的配置部分都删掉,换成下面的配置:
/*-----------------------------------------------------------------------
* Physical Memory Map
*/
#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 */
#define PHYS_FLASH_1 0x00000000 /* Flash Bank #1 */
#define CONFIG_SYS_FLASH_BASE PHYS_FLASH_1
#define CONFIG_SYS_MONITOR_BASE TEXT_BASE
#define FLASH_BASE0_PRELIM PHYS_FLASH_1
/*------------------------------------------------------------
* FLASH and environment organization
*/
#define CONFIG_SYS_FLASH_PROTECTION 1
#define CONFIG_SYS_MAX_FLASH_BANKS 1 /*max number of memory banks*/
#define CONFIG_SYS_FLASH_SIZE 0x00400000 /*4 MB*/
#define CONFIG_SYS_MAX_FLASH_SECT 32 /*max number of sectors on one chip*/
/*timeout values are in ticks*/
#define CONFIG_SYS_FLASH_ERASE_TOUT (2*CONFIG_SYS_HZ) /*Timeout for Flash Erase*/
#define CONFIG_SYS_FLASH_WRITE_TOUT (2*CONFIG_SYS_HZ) /*Timeout for Flash Write*/
#define CONFIG_ENV_IS_IN_FLASH 1
#define CONFIG_ENV_SIZE 0x20000 /*128KB*/
#define CONFIG_ENV_OFFSET 0x40000
2.把开发板目录下flash.c文件替换成下面的/board/cmi/下面的flash.c文件,然后删除这个write_short函数的申明和定义、删除write_buff函数。替换成下面的两个函数:(为了不占篇幅,我把这两个函数单独写在名为<<Intel JS28F320nor flash 的write_buff函数>>这篇日记中。
3. 修改flash.c文件中的一个宏定义:
把:
#define FLASH_BLOCK_SIZE 0x00010000
改为:
#define FLASH_BLOCK_SIZE 0x00020000
上述3步完成后,生新编译,下载u-boot.bin文件到SDRAM中运行,便可看到u-boot检测到了我们的flash。用flinfo命令可以看到具体的块信息,还可以用flash的各种命令对flash进行操作,从而实现这块norflash驱动的完全支持。烧写当然也是没问题的了,把需要烧写的文件下载到SDRAM中后,用cp.b命令就可以了。
下面大该分析一下这个驱动文件的函数调用,此flash.c文件中有如下几个函数:
static ulong flash_get_size (vu_short *addr, flash_info_t *info);
static void flash_get_offsets (ulong base, flash_info_t *info);
static int write_word (flash_info_t *info, ulong dest, ushort data)
unsigned long flash_init (void)
void flash_print_info (flash_info_t *info)
int flash_erase (flash_info_t *info, int s_first, int s_last)
int flash_real_protect(flash_info_t *info, long sector, int prot)
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
1.u-boot启动只会用到flash.c文件中的flash_init函数,正如上面所述;
2.以static修饰的3个函数只在flash.c文件中被调用;
3.最后面的4个函数会被/common/cmd_flash.c文件中的函数调用,以实现u-boot下的各种命令操作。
*************************************
上面的操作做完之后,如果没有问题,我们就可以考虑让u-boot从nor flash启动了。为了实现这个目的,有下面几步操作:
1.注释或删除掉下面的两个宏定义:
//#define CONFIG_SKIP_LOWLEVEL_INIT 1
//#define CONFIG_SKIP_RELOCATE_UBOOT 1
2.修改开发板目录下的lowlevel_init.S文件中SDARM刷新参数为:
#define REFCNT 1258 /* period=7.8125us, HCLK=405/4 Mhz, (2048+1-7.8125*405/4) */
重新编译,设置好开发板上的跳线,下载到nor flash中,重启开发板,串口控制台看到u-boot启动成功!
****************************************
后记:
也许,很多人觉得这篇文章的移植怎么会花了一个星期这么长时间,现在想来,我自己也不太相信,不过确是事实。那是哪里出错了呢,现特记录下来,以提醒自己:
1. CONFIG_SYS_FLASH_ERASE_TOUT和CONFIG_SYS_FLASH_WRITE_TOUT定义出错。首先我用的就是拷贝过来的参数,不行,我又把它增大了一倍,有改善,便还是不行。原因:不要把timeout直接定义为以ms为单位的值,要定义为以“ticks“为单位的值,即次数。因为在驱动中进行比较时,get_timer得到的值就是PWM4定时器中的值经过一些计数后得到的。
2. FLASH_BLOCK_SIZE定义错,应当以字节为单位,是20000,而不是以半字为单位为10000。我之前一直以为,我的flash是16位位宽的,那就当以半字为单位,其实不是这样的。
3.刷新参数没改正确,我之前都是用别人的值,因为别人的也是2440,后来不这样想了,自已计算!从而解决问题!因为这个还和时钟有关!
移植u-boot2009.08到OK2440V3开发板(4)---nand flash识别与操作
(2009-12-13 20:06) 出了问题是痛苦的,但是解决了问题又是让人兴奋的。摸爬滚打三四天后,我的u-boo终于可以正确识别nand flash了!也许就是这一次次,哪怕是一瞬间的兴奋,才让自己坚持了下来。郁闷几天又如何,呵呵。
正如此系列日记的第一篇所述,为了降低解决问题的难度,缩小问题问题出现的范围,我们先在这篇日记中完成nand驱动支持这个功能,能在u-boot中对nand进行各种命令操作,从nand启动u-boot的功能在下篇日记中完成。
**********************************************************************************************
为了支持nand,我们必须知道nand是如何与u-boot作用的,我们先来看这个版本中nand驱动框架。
网上看了很多的相关资料,都说nand驱动有两种不同的实现流程和框架,取决于是否定义CONFIG_NAND_LEGACY,其实这个现象在u-boot2009.08这个版本中已经不存在了。nand驱动现在用的就是和linux内核一样的MTD(内存技术设备)架构,这个在u-boot根目录下有清楚的说明:
The current NAND implementation is based on what is in recent
Linux kernels. The old legacy implementation has been removed.
If you have board code which used CONFIG_NAND_LEGACY, you'll need
to convert to the current NAND interface for it to continue to work.
说来好笑,我为了弄清这个问题,尽然在网上到处确认,现在的nand驱动架构是什么样子,原来真的是舍近求远了,浪费了些时间。这也是引发我写<<自学嵌入式中的点点滴滴>>这篇日记的原因之一。
*****************************************************************************************
我们先从u-boot启动过程中,以s3c2410为例,怎样调用到nand驱动这个角度来分析。还有另外一个角度,那就是在u-boot中执行某一nand命令时,从上到下到底发生了什么。
u-boot启动到第二个阶段后,在/cpu/arm920t/board.c这个文件中start_armboot函数里,有下面的代码:
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init(); /* go init the NAND */
#endif
所以,我们只要定交了CONFIG_CMD_NAND这个宏,就会开始nand初始化。通过用KScope(Linux下的一个不错的IDE,可用来做代码分析)来一步步地查看函数执行过程,得出下面的nand执行流程:
1./cpu/arm920t/board.c文件中的start_armboot函数调用/drivers/mtd/nand/nand.c文件中的nand_init函数;
2.nand_init调用同文件下的nand_init_chip函数;
3.nand_init_chip函数调用/drivers/mtd/nand/s3c2410_nand.c文件下的board_nand_init函数,然后再调用/drivers/mtd/nand/nand_base.c函数中的nand_scan函数;
4.s3c2410_nand.c就是我们做移植需要实现的文件,是与具体的硬件密切相关的。
5.nand_scan函数会调用同文件下的nand_scan_ident等函数。
从这里我们得知,我们要把nand移植到2440上,就要修改s3c2410_nand.c这个文件!因为对nand flash的操作,实际上就是对nand控制器的操作,而2440的nand控制器和2410相比,有很大的不同!我们的修改工作量主要也是在这里。s3c2410与s3c2440具体有什么区别,请看我的另一篇日记<<s3c2410与s3c2440的全方位对比>>
*********************************************************************************
下一步就是根据s3c2440的手册中nand控制器部分修改s3c2410_nand.c文件,我们在同目录下(/drivers/mtd/nand/)复制此文件,并重命名为s3c2440_nand.c,下面我们来对s3c2410_nand.c文件进行修改:
(这里我使用的是网上别人的函数,文末有说明)
1.修改s3c2410_nand.c文件中NAND Flash控制器的相关定义:
(针对S3C2440 NAND Flash控制器的不同来重新定义一些寄存器,把原文件中对s3c2410 nand寄存器的定义删除,重新定义如下)
#define NF_BASE 0x4e000000
#define NFCONF __REGi(NF_BASE + 0x0)
#define NFCONT __REGi(NF_BASE + 0x4)
#define NFCMD __REGb(NF_BASE + 0x8)
#define NFADDR __REGb(NF_BASE + 0xc)
#define NFDATA __REGb(NF_BASE + 0x10)
#define NFMECCD0 __REGi(NF_BASE + 0x14)
#define NFMECCD1 __REGi(NF_BASE + 0x18)
#define NFSECCD __REGi(NF_BASE + 0x1C)
#define NFSTAT __REGb(NF_BASE + 0x20)
#define NFSTAT0 __REGi(NF_BASE + 0x24)
#define NFSTAT1 __REGi(NF_BASE + 0x28)
#define NFMECC0 __REGi(NF_BASE + 0x2C)
#define NFMECC1 __REGi(NF_BASE + 0x30)
#define NFSECC __REGi(NF_BASE + 0x34)
#define NFSBLK __REGi(NF_BASE + 0x38)
#define NFEBLK __REGi(NF_BASE + 0x3c)
#define S3C2440_NFCONT_nCE (1<<1)
#define S3C2440_ADDR_NALE 0x0c
#define S3C2440_ADDR_NCLE 0x08
2.增加一个全局变量:ulong IO_ADDR_W = NF_BASE;
3.修改s3c2410_nand.c文件的s3c2410_hwcontrol函数和board_nand_init函数:
(为了不在这里占篇幅,具体修改的内容请看我的另一篇日记<<s3c2440的hwcontrol和board_nand_init函数>>)
4.除了以上对3c2410_nand.c的文件进行修改之外,我们还要在开发板的配置文件中(ok2440v3.h)定义支持nand的相关的宏:
/* Command line configuration. */
......
#define CONFIG_CMD_NAND
#define CONFIG_CMDLINE_EDITING
#ifdef CONFIG_CMDLINE_EDITING
#undef CONFIG_AUTO_COMPLETE
#else
#define CONFIG_AUTO_COMPLETE
#endif
/* NAND flash settings */
#if defined(CONFIG_CMD_NAND)
#define CONFIG_NAND_BASE 0x4E000000
#define CONFIG_MAX_NAND_DEVICE 1
#define CONFIG_MTD_NAND_VERIFY_WRITE 1
#define NAND_SAMSUNG_LP_OPTIONS 1 /*注意,这个定义很重要,因为我们用的是大块nand!!我就是因为没定义这里卡了较长时间 */
#undef CONFIG_ENV_IS_IN_FLASH
#define CONFIG_ENV_IS_IN_NAND 1 /* 环境变量的保存位置 */
#define CONFIG_ENV_SIZE 0x20000
#define CONFIG_ENV_OFFSET 0x40000
#endif
5.我们要把新建立的这个文件编译进去,所以要修改相同目录(/drivers/mtd/nand/)下的Makefile文件:
在相应位置加入:
COBJS-y += s3c2440_nand.o
COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o
6.我们为了在SDRAM中调试,定义上下面的两个宏定义,下载到SDRAM中运行:
#define CONFIG_SKIP_LOWLEVEL_INIT 1
#define CONFIG_SKIP_RELOCATE_UBOOT 1
7.编译,下载到SDRAM中运行,成功检测到nand:
U-Boot 2009.08 (12栽? 13 2009 - 18:03:40)
DRAM: 64 MB
Flash: 4 MB
NAND: 128 MiB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
OK2440V3 #
OK2440V3 # nand info
Device 0: NAND 128MiB 3,3V 8-bit, sector size 128 KiB
OK2440V3 #
进行nand命令的基本操作,nand info、nand dump、nand read、nand write,都能够成功!
**********************************************************************************
下面列一下,此篇移植中,我们需关注的文件:
/cpu/arm920t/board.c
/drivers/mtd/nand/nand.c
/drivers/mtd/nand/s3c2410_nand.c
/drivers/mtd/nand/nand_base.c
/driver/mtd/nand/Makefile
/include/configs/ok2440v3.h
移植u-boot2009.08到OK2440V3开发板(5)---nand flash启动
(2009-12-16 21:35) 在完成前面的nand flash识别与操作后(在nor flash中运行,检测到nand外设并可对其用u-boot命令进行操作),让u-boot从nand中启动,就相对比较简单了。当然,这个简单的前提是是,有开发板自带的bootloader中的nand启动代码可参考。
移植的重要关键部分是是代码的拷贝,从nand拷贝到sdram。从编程的角度看,nor flash是存储设备,而nand是I/O外设,对它们的底层操作有本质的不同。u-boot中对ARM的支持部分,没有支持nand启动的代码,只有nor flash的,拷贝u-boot的那部分代码只适用于nor flash,不适用于nand。
1. 删除或注释掉原来的 relocate 部分,用飞凌公司提供的bootloader中的nand启动相关部分来替代。由于这个bootloader用的是汇编语言环境是armasm的,不是GUN ARM的,所以要进行一些语法上的转换。转换之后的结果如下:
/**********************************************************/
//如果是从nand启动,到这里执行
//将程序从nandflash拷贝到sdram
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
#define NFCONF 0x4E000000
relocate_nand: /* 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
mov r5, #NFCONF
//set timing value
ldr r0, =(7<<12)|(7<<8)|(7<<4)
str r0, [r5]
//enable control
ldr r0, =(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)
str r0, [r5, #4]
bl ReadNandID
mov r6, #0
ldr r0, =0xecF1
cmp r5, r0
beq 1f
ldr r0, =0xec76
cmp r5, r0
beq 1f
mov r6, #1
1:
bl ReadNandStatus
mov r8, #0
ldr r9, =_start
mov r10, #128 //u-boot 256k,128页 --这里原来是32!!
2:
ands r0, r8, #0x3f //如果是第一页,则检测坏块
bne 3f
mov r0, r8
bl CheckBadBlk
cmp r0, #0
addne r8, r8, #64 //每块的页数
addne r10,r10,#64 //+081010 feiling
bne 4f
3:
mov r0, r8
mov r1, r9
bl ReadNandPage
add r9, r9, #2048 //每页的字节数
add r8, r8, #1 //页数+1
4:
cmp r8, r10 //要拷贝的页数 081010 pht:#32->r10
bcc 2b
mov r5, #NFCONF //DsNandFlash
ldr r0, [r5, #4]
bic r0, r0, #1
str r0, [r5, #4]
#endif
(注意上面的mov r10, #128 那一句,把拷贝的页数改大一些,原来是32。我之前,怎么都没调通,就是因为这里,因为u-boot编译出来比飞凌的bootloader大多了)
2. 上述代码中用到的几个子函数ReadNandID、ReadNandStatu、 WaitNandBusy、CheckBadBlk、ReadNandPage也一同拷贝过来,并进行简单的一些语法修改。
3. s3c2440的两种启动方式,nor 和 nand 启动在原理上不些不同,若从nor 启动,就是直接从nor flash的0地址开始执行(flash 映射到bank0),可以执行flash的内部的任意地址的内容。而从nand启动,是在运行之前,由CPU自动地拷贝nand的前4K的内容到内部的4K RAM中,再从内部的这个RAM中的0地址开始执行。所以我们必须保证在跳到SDARM运行之前的所有代码,都在前4K范围之内。
而通过查看编译后u-boot根目录下的u-boot.map文件可知,lowlevel_init.o并不在
前4K的范围:
.text 0x33f948e0 0x9c board/samsung/ok2440v3/libok2440v3.a(lowlevel_init.o)
0x33f948e4 lowlevel_init // (u-boot的起始地址为0x33f80000)
所以我们要修改/cpu/arm920t/u-boot.lds文件,使lowlevel_init.o在前4K范围:
.text :
{
cpu/arm920t/start.o (.text)
board/samsung/ok2440v3/lowlevel_init.o (.text)
*(.text)
}
修改后,重新编译,再次查看,已在前4K,如下:
board/samsung/ok2440v3/lowlevel_init.o(.text)
.text 0x33f80700 0x64 board/samsung/ok2440v3/lowlevel_init.o
0x33f80704 lowlevel_init
把编译之后的u-boot.bin文件下载到nand 中,重新启动,串口控制台得出正确的启动信息,完成。
OK2440V3 # reset
resetting ...
U-Boot 2009.08 (12栽? 16 2009 - 20:30:08)
DRAM: 64 MB
## Unknown FLASH on Bank 0: ID 0xffff, Size = 0x00000000 = 0 MB
Flash: 0 kB
NAND: 128 MiB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
OK2440V3 #
后记:这篇移植就两个重点,一是修改复制u-boot时要复制nand的页数,一是lowlevel_init.o的连接位置保证在前4K。