文章目录
前言
通过前面两篇博客,我们已经将U-Boot移植进行了一半。使我们的U-Boot同时支持S3C2410和S3C2440两款芯片。支持我们的xmodem串口协议,支持网卡芯片CS8900。
今天的这篇博客我们将U-BOOT移植剩下的内容分析完
第四步:支持NAND Flash
第五步:支持烧写yaffs文件系统映象
第六步:修改默认参数以便使用
支持NAND Flash
U-Boot 1.1.6中对NAND Flash的支持有新旧两套代码,新代码在drivers/nand目录下,旧代码在drivers/nand_legacy目录下。
文档doc/README.nand对两套代码都有说明:使用旧代码需要定义更多的宏,而新代码移植自Linux内核2.6.12,它更加智能,可以自动识别更多型号的NAND Flash。目前之所以还保留旧代码,是因为两个目标板NETTA,NETTA_ISDN使用JFFS文件系统,他们依赖于旧代码。当相关功能移植到新代码后,旧的代码将从U-Boot中去除。
要让U-Boot支持NAND Flash,首先在配置文件include/configs/100ask24x0.h,的宏CONFIG_COMMANDS中增加CFG_CMD_NAND,如下所示:
然后选择使用那套代码:在配置文件中定义宏CFG_NAND_LEGACY则使用旧代码,否则使用新代码。
使用旧代码时,需要实现drivers/nand_legacy/nand_legacy.c中使用到的各种宏,比如:
#define WRITE_NAND_COMMAND(d,adr) //写NAND Flash命令,代码依赖于具体的开发板
参考书籍采用新代码,下面分析移植过程。
代码的移植没有现成的文档,可以配置文件include/configs/100ask24x0.h的宏CONFIG_COMMANDS中增加CFG_CMD_NAND后就编译代码,然后一个一个地解决出现地错误
nand.h:412: 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 size of 'nand_info' isn't known
nand.c:37:error: storage size of 'nand_chip' isn't known
nand.c:38:error: storage size of 'base_address' isn't known
nand.c:37:warning : 'nand_chip' defined but not used
nand.c:38:warning: 'base_address' defined but nnot used
在配置文件include/configs/100ask24x0.h增加如下3个宏就可以解决上述错误。在Flash的驱动程序中,设备是逻辑上的概念,表示一组相同结构,访问函数相同的Flash芯片。在参考书籍所用的开发板中,只有一个NAND Falsh芯片,所以设备数是1,芯片数也是1。
修改文件后再次编译,现在只有一个错误了,“board_nand_init函数未定义”,如下
nand.c:50: undefined reference to 'board_nand_init'
调用board_nand_init函数的过程为:NAND Flash的初始化入口函数是nand_init,它在lib_arm/board.c的start_armboot函数中被调用;nand_init函数在drivers/nand/nand.c中实现,它调用相同文件中的nand_init_chip函数:nand_init_chip函数首先调用board_nand_init函数来初始化NAND Flash设备,最后才是统一的识别过程。
从board_nand_init函数的名称就可以知道它是平台/开发板相关的函数,需要自己编写。
在cpu/arm920t/s3c24x0目录下新建一个文件nand_flash.c,在里面针对S3C2410,S3C2440实现了统一的board_nand_init函数。
在编写board_nand_init函数之前,需要针对S3C2410,S3C2440NAND Flash控制器的不同来定义一些数据结构和函数;
1、在include/s3c24x0.h文件中增加S3C2440_NAND数据结构
2、在include/s3c2410.h 文件仿造S3C2410_GetBase_NAND函数定义S3C2440_GetBase_NAND函数
既然新的NAND Flash代码是从Linux内核2.6.12中移植来的,那么cpu/arm920t/s3c24x0/nand_flash.c文件也可以仿照内核中对S3C2410,S3C2440的NAND Flash进行初始化的drivers/mtd/nand/s3c2410.c文件来编写。为了方便阅读,先把cpu/arm920t/s3c24x0/nand_flash.c文件的代码全部列出来,如下所示(因为太长,我就使用书籍上的直接分析)
文件中分别针对S3C2410和S3C2440实现了NAND Flash最底层访问函数,并进行了一些硬件的设置(比如时序,使能NAND Flash控制器等)。新代码对NAND Flash的封装做的很好,只要向上提供底层初始化函数board_nand_init来设置好平台/开发板相关的初始化、提供底层接口即可。
最后,只要将新建的nand_flash.c文件编入U-Boot就可以擦除,读写NAND Flash了。如下修改cpu/arm920t/s3c24x0/Makefle文件即可
修改前:
修改后:
支持烧写yaffs文件系统映象
在实际生产中,可以通过烧片器等手段将内核,文件系统映象烧入固态存储设备中,Bootloader不需要具备烧写功能。但是为了方便开发,通常在Bootloader中增加烧写内核、文件系统映象文件的功能。
增加了NAND Flash功能的U-Boot 1.16已经可以通过 “nand write…”,“nand write.jffs2…”等命令来烧写内核,烧写cramfs,jffs2文件系统映象文件。但是在NAND Flash上,yaffs文件系统的性能更佳,下面增加 "nand write。yaffs…"命令以烧写yaffs文件系统映象文件。
"nand write.yaffs…"字样的命令中,“nand”是具体的命令,“write.yaffs…”是参数。nand命令在common/cmd_nand.c中实现如下:
先在其中增加“nand write.yaffs…”的使用说明,如下所示:
然后,在nand命令的处理函数do_nand中增加对“write.yaffs…”的支持。do_nand函数仍在common/cmd_nand.c中实现,代码修改如下:
第354行~379行就是针对命令“nand read.yaffs…”、“nand write.yaffs…”增加的代码。有兴趣的朋友可以自己分析 “if(read)”分支的代码,下面只讲解“else”分支,即"nand write.yaffs…"命令的实现。
NAND Flash每一页大小为(512+16)字节(还有其他格式的NAND Flash,比如每页大小为(256+8),(2048+64)等),其中的512字节就是一般存储数据的区域,16字节称为OBB(OUT OF BAND)区。通常在OBB区存放环块标记,前面512字节的ECC校验码等。
cramfs,jffs2文件系统映象文件中并没有OBB区的内容,如果将他们烧入NOR Flash中,则是简单的“平铺关系”;如果将他们烧入NAND Flash中,则NAND Flash的驱动程序首先根据OBB的标记略过环块,然后将一页数据(512字节)写入后,还会计算这512字节的ECC检验码,最后将它写入OBB区,如此循环。cramfs,jffs文件系统映象文件的大小通常是512的整数倍。
而yaffs文件系统映象文件的格式跟他们不同,文件本身就包含了OBB区的数据(里面有环块标记,ECC校验码,其他yaffs相关信息)。所以烧写时,不需要在计算ECC值,首先检查是否环块(是则跳过),然后写入512字节的数据,最后写入16字节的OBB数据,如此循环。yaffs文件系统映象文件的大小是(512+16)地整数倍。
(注意:烧写yaffs文件系统映象时,分区上第一个可用地(不是环块)块也要跳过)
下面分析369~371行设置地源地址,目的地址,长度。烧写yaffs文件系统映象前,一般通过网络将它下载到内存某个地址处(比如0x30000000),然后通过类似“nand write.yaffs 0x300000000 0x00A00000 $(filesize)”的命令烧写到NAND Flash的便宜地址0x00A00000处。这对于这个命令第369行中opts.buffer等于0x30000000,第270行opts.length= $ (filesize)的值,就是前面下载的文件的大小,第371行中的opts.offset等于0x00A00000。
这里列出不使用的第372行,是因为opts.forceyaffs这个名字很有欺骗性,它其实是指计算ECC校验码的一种方法。烧写yaffs文件系统映象时,不需要计算ECC校验码。
第373,374行指定烧写数据时不计算ECC校验码,而是烧入文件中的OBB数据。
第375行指定“逻辑块”的大小,“逻辑块”可以由多个“物理块”组成,在yaffs文件系统映象中,它们是1:1的关系。
第377行的opts.shipfirstblk是新加项,nand_write_options_t结构中没有shipfirstblk成员。它表示烧写时跳过第一个可用的逻辑块,这是由yaffs文件系统的特性决定的。
既然skipfirstblk是在nand_write_options_t结构中新加的项,那么就要重新定义nand_write_options_t结构,并在下面调用的nand_write_opts函数中对他进行处理。
首先在include/nand.h中进行如下的修改,增加skipfirstblk成员
然后,修改nand_write_opts函数,增加skipfirstblk成员支持。它在drivers/nand/nand_util.c文件中,下面的第301,地430~435行是新加的
进行了上面的移植后,U-Boot已经可以烧写yaffs文件系统映象了。由于前面设置“opts.noecc =1”不使用ECC校验码,在烧写过程中会出现很多的提示信息,如下
writing data without ECC to NAND-FlASH is not recommended
可以修改drivers/nand/nand_base.c文件的nand_write_page函数,将它去掉。
修改前:
修改后:
修改默认配置参数以方便使用
前面移植网卡芯片CS8900时,已经设置过默认IP地址等。为了使用U-Boot时减少一些设置,现在修改配置文件include/configs/100ask24x0.h,增加默认配置参数,其中一些在移植过程中已经增加的选项这里也再次说明。
Linux启动参数
增加如下3个宏:
自动启动命令
增加如下两个宏:
自启动时(开机3秒内无输入),首先执行“nboot 0x32000000 0 0”命令将第0个NAND Flash偏移地址0上的映象文件复制到内存0x32000000中;然后执行“bootm 0x32000000”命令启动内存中的映象。
默认网络设置
根据具体网络环境增加,修改下面4个宏:
总结
U-Boot的移植完结了,下一篇博客分析U-Boot的常用命令。
希望这些博客也能帮助到您。