现在我的Redboot已经实现了从NAND启动,并加载了cs8900网卡的驱动,但是仍然无法对NAND Flash进行操作,如fconfig命令、fis命令还是无法完成的。于是,需要给Redboot加载NAND Flash的驱动。
eCos的源代码中并没有提供对NAND器件的支持,只是提供了一个flash抽象设备的接口,如fis和fconfig命令都是针对于flash抽象设备接口实现的。flash抽象设备接口驱动是置于io设备驱动下的。而具体的flash器件的驱动则放在devs目录下,在flash器件驱动中大多是实用于NOR Flash器件,只有Toshiba的TC58xxx是NAND Flash器件。而Flash驱动中与平台相关的部分则放在devs\flash\下的各平台目录下。
在网上转了一圈,想找找现成的NAND Flash驱动,发现了有一些对NAND驱动结构的意见。其主要有两种意见,一种是按照linux的结构来实现;一种则直接采用flash抽象设备接口的结构,而只是实现NAND器件的驱动。按照linux结构实现较为复杂,但是能够做到与linux兼容,对于用Redboot引导linux的系统来说比较合适。按后一种方式则实现较为简单,对eCos的目录结构的调整也不大,如Toshiba的TC58xxx那样,则对于fis、fconfig命令而言是透明的,无需修改。由于是初学,也没有必要做得太复杂,至于与linux的兼容性也就先丢到一边吧,呵呵。况且,在网上还找到Alexey Shusharin写的NAND Flash的patch(
url:http://www.nabble.com/NAND-Flash-device-driver-td14252516.html),据他称已经在SAMSUNG的K9F5608U0D上测试通过。而我的开发板上的NAND Flash是SAMSUNG的K9F1208U0B,应该正好可以拿来用,呵呵。
Alexey的驱动主要由两个部分组成,一个是NAND器件的驱动,位于\devs\flash\nand\目录下,包括nand_flash.c,nand_flash_parts.inl,nand_flash.h文件,在nand_flash.cdl中实现了NAND Flash驱动的配置脚本文件,定义了CYGPKG_DEVS_FLASH_NAND包,以及相关的一些配置选项。另外一部分是与平台相关的,放在了\devs\flash\arm\leo2410\目录下了,包括flash_nand_leo2410.cdl和devs_flash_arm_leo2410.inl两个文件。
在nand_flash.c文件中实现了flash.c函数中所有相关的接口函数,如flash_query()、flash_hwr_init()、...等函数,这样fis、fconfig命令就可以通过这些函数访问到NAND Flash,当然这样的实现只能适合于只有NAND Flash的情况。nand_flash_parts.inl中定义了NAND器件的型号和参数;flash_nand_leo2410.cdl中对平台相关的包含文件devs_flash_arm_leo2410.inl做了连接,并定义了相关的宏以便能够使用NAND Flash驱动。而devs_flash_arm_leo2410.inl中则是平台对NAND控制器的实现。
在Alexey的这个patch中,实现了NAND Flash的驱动部分,平台相关部分给出了函数的空实现,以便于按照平台要求添加相应的代码。根据s3c2410的NAND控制器的访问方法,对这段代码进行了添加,如下所示:
#include <cyg/hal/s3c2410x.h> #define __REGb(x) (*(volatile unsigned char *)(x)) #define __REGi(x) (*(volatile unsigned int *)(x)) //----------------------------------------------------------------- // Platform specific access to control-lines //----------------------------------------------------------------- #define CYGHWR_FLASH_NAND_PLF_RESET nand_plf_reset #define CYGHWR_FLASH_NAND_PLF_INIT nand_plf_init #define CYGHWR_FLASH_NAND_PLF_CE nand_plf_ce #define CYGHWR_FLASH_NAND_PLF_WP nand_plf_wp #define CYGHWR_FLASH_NAND_PLF_CMD nand_plf_cmd #define CYGHWR_FLASH_NAND_PLF_ADDR nand_plf_addr #define CYGHWR_FLASH_NAND_PLF_WAIT nand_plf_wait //---------------------------------------------------------------- // Global variables //----------------------------------------------------------------- // The device-specific data static cyg_nand_dev nand_device = { .flash_base = (void*) (0x80000000), .addr_r = (void*) NFDATA, .addr_w = (void*) NFDATA, .delay_cmd = 1, .delay_rst = 500, }; //----------------------------------------------------------------- // Reset platform nand //----------------------------------------------------------------- static inline void nand_plf_reset(void) { int i; __REGi(NFCONF) &= ~(1<<11); __REGi(NFCMD) = 0xFF; /* reset command */ for(i = 0; i < 10; i++); /* tWB = 100ns. */ while (!(__REGi(NFSTAT) & (1<<0))); /* wait 200~500us; */ __REGi(NFCONF) |= (1<<11); } //----------------------------------------------------------------- // Init platform nand //----------------------------------------------------------------- static inline void nand_plf_init(void) { // Init NAND Flash platform stuff #if 1 #define TACLS 0 #define TWRPH0 1 #define TWRPH1 0 #else #define TACLS 0 #define TWRPH0 4 #define TWRPH1 2 #endif __REGi(NFCONF) = ((1<<15)|(0<<14)|(0<<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 */ nand_plf_reset(); } //----------------------------------------------------------------- // Enable/disable nand chip //----------------------------------------------------------------- static inline void nand_plf_ce(int state) { if(state) { // Enable CE line __REGi(NFCONF) &= ~(1<<11); } else { // Disable CE line __REGi(NFCONF) |= (1<<11); } } //----------------------------------------------------------------- // Enable/disable write protect //----------------------------------------------------------------- static inline void nand_plf_wp(int nowrite) { if(nowrite) { // Enable WP } else { // Disable WP } } //----------------------------------------------------------------- // Write nand command //----------------------------------------------------------------- static inline void nand_plf_cmd(int cmd) { // Enable CLE line // Write command // Disable CLE line __REGi(NFCMD) = cmd; } //----------------------------------------------------------------- // Write nand address //-----------------------------------------------------------------
static inline void nand_plf_addr(int addr) { // Enable ALE line // Write address // Disable ALE line __REGi(NFADDR) = addr; } //----------------------------------------------------------------- // Wait device ready pin //----------------------------------------------------------------- static inline void nand_plf_wait(void) { // Wait while device is not ready while (!(__REGi(NFSTAT) & (1<<0))); } |
其中nand_plf_wp没有实现,是因为我的开发板上写保护线是直接接的高电平,故无需控制。而nand_plf_cmd和nand_plf_addr的实现没有考虑CLE和ALE的控制是由于s3c2410的控制器是由硬件直接控制的,无需由软件控制。
这样,在eCos.db的leo2410 target中加入下面几行:
CYGPKG_IO_FLASH CYGPKG_DEVS_FLASH_NAND CYGPKG_DEVS_FLASH_ARM_LEO2410_NAND |
就可以用configureTool进行配置、编译了。下载之后启动,Redboot发现了NAND Flash器件,但是fconfig初始化错误,NAND驱动中的bbm也无法初始化。使用fconfig命令、fis命令发现完全没有作用。于是将nand_flash.c文件中的NAND_DEBUG_LEVEL设置为3,以打印出调试信息。重新编译,下载,发现打印出的调试信息都是success,这就奇怪了,为什么无法执行操作却返回成功呢?
左思右想没有结果,怎么办呢,只有借鉴成功经验了。一开始想在vivi中找,却发现vivi对NAND器件的驱动不是很清晰,看起来比较费劲。又分析了一下,发现erase、write甚至read命令都无法正常工作,因此猜想应该是底层命令的原因,第一个怀疑的就是command命令了。这时候,突然想到用来刷NAND Flash的SJF2410也有源代码,于是打开将command的实现进行了一下比较,才发现Alexey代码中少了一段page地址的设置,s3c2410的控制方法不一致,如下列代码中红色部分所示。
// Write page address if needed if(page_addr >= 0) { CYGHWR_FLASH_NAND_PLF_ADDR(page_addr & 0xFF); CYGHWR_FLASH_NAND_PLF_ADDR((page_addr >> 8) & 0xFF); CYGHWR_FLASH_NAND_PLF_ADDR((page_addr >> 16) & 0xFF); } |
page地址没有写对,那么当然无法正常工作,但是并没有影响到NAND控制器的状态改变,所以总是返回成功了。重新编译、下载,启动,终于没有报初始化不成功的错误了,试验了一下fconfig命令,也可以正确的设置了,这样修改ip地址等变得很方便了。
+NAND FLASH Device probed: Samsung K9F1208U0B, size 64MB ... Read from 0x03ffc000-0x04000000 at 0x83f7c000: . ... Read from 0x03ffb000-0x03ffc000 at 0x83f7f000: . CS8900A[0x19000300] - type: 0x630e, rev: 0x0a00 CS8900 - status: 0x0ad6 (EEPROM present) Got hardcoded ESA ESA 00:21:85:92:d5:0e Ethernet eth0: MAC address 00:21:85:92:d5:0e IP: 192.168.0.4/255.255.255.0, Gateway: 192.168.0.1 Default server: 192.168.1.21 RedBoot(tm) bootstrap and debug environment [NAND] Non-certified release, version UNKNOWN - built 11:48:11, Jan 14 2009 Platform: LEO2410 system (ARM9) Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. Copyright (C) 2003, 2004, 2005, 2006 eCosCentric Limited RAM: 0x00000000-0x04000000, [0x0002d568-0x03ff5000] available FLASH: 0x80000000 - 0x83f80000, 4064 blocks of 0x00004000 bytes each. RedBoot> |
其中NAND器件的信号是自己在nand_flash_parts.inl的结构中添加的,并在nand_flash.c的flash_hwr_init()函数添加了以下代码而实现的打印NAND Flash器件的信息:
flash_info.pf("NAND FLASH Device probed: %s, size %dMB\n", name, flash_info.block_size * dev->blocks_count / 0x100000); |
fis命令也能工作了,用fis list命令看了一下,发现有三个image,如下:
RedBoot> fis list ... Read from 0x03ffc000-0x03fff000 at 0x83f7c000: . Name FLASH addr Mem addr Length Entry point RedBoot 0x80000000 0x80000000 0x00020000 0x00000000 FIS directory 0x83F7C000 0x83F7C000 0x00003000 0x00000000 RedBoot config 0x83F7F000 0x83F7F000 0x00001000 0x00000000 |
这样,我的Redboot就可以使用NAND驱动了,通过配置可以直接用load命令将映像文件下载到NAND Flash中去,采用tftp速度飞快,再也不需要在SJF2410下载时经历那样漫长的等待了,呵呵!
原文见:http://blog.chinaunix.net/uid-20802172-id-458568.html