移植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下烧写我这款nor flash的工具!我必须要切换到windows下才行,这太麻烦了,我就想在u-boot里把我这款nor flash的驱动搞定,包括保护、去保护、擦除、读写等,好让u-boot启动后能使用flash的命令,然后烧写nor flash。这一想不要紧,在u-boot里找到的驱动程序有问题。为了解决这个问题,自己又不想放弃,“血案”就这样发生了,呵呵。 不过一个星期后的痛苦挣扎后,问题总算解决了。(虽然问题不大,但对我这样的新手来说,又没人指导,有时一个小问题真的会让人郁闷透顶!) ************************************* 下面先看如何在u-boot中支持nor flash的烧写,我的开发板上的nor flash芯片是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 JS28F320 nor 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进行操作,从而实现这块nor flash驱动的完全支持。烧写当然也是没问题的了,把需要烧写的文件下载到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定义出错。首先我用的就是拷贝过来的参数,不行,我又把它增大了一倍,有改善,便还是不行。原 因:不要把time out直接定义为以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。 |
|