u-boot移植--4、对于NAND FLASH的支持

来源:互联网 发布:curl windows 64 下载 编辑:程序博客网 时间:2024/05/16 08:54

常常说自己是老年人记忆,因为看过的东西很快就忘。秉承着看自己写的东西肯定要比看别人写东西要好理解的原则。写下这个系列的u-boot移植,同时也加深自己的理解。其实到现在网上大神很多,给出了很多的解决方案。我也以他们为参考。与之不同我会加上一些我自己对某些地方的理解来进行处理。希望对大家有帮助。
开发板:天嵌TQ2440
u-boot:u-boot-1.1.6
手里的开发板是天嵌的TQ2440,看的书是韦东山老师的《嵌入式Linux开发完全手册》,有些许不同的地方,增加了移植困得,当应该也更加深自己的理解。


NAND FLASH型号:K9F2G08U0A


对于NAND FLASH,我们需要了解如下的信息。K9F2G08UXA 是一个具有128K页,2048块,每一块64页,每一页具有(2K+64)byte,2K是主区,64是信息区域,每一块是(128K+4K)byte的空间。所有的操作都是通过一个8位的IO实现。对每一页的访问通过列地址进行访问,2K空间一共需要11个位宽,因此列访问需要两次,第一次前8位,
第二次前4位,后4位为0。行地址和列地址是分开访问的。页访问通过行地址实现,一共128K,则需要17位位宽,这样8位IO口需要三次才能访问完全,前两次的8位,后一次的1位,其他位都必须为0。因此K9F2G08UXA 的地址是5次地址方式。这才导致了5个周期输入。实质上存储空间不止256M。具体的操作的方式是通过一些命令实现的,因此需要熟悉命令,才能实现控制。我们以一张图来看看NAND FLASH的构架。


首先我们在include/configs/TQ2440.h文件中的CONFIG_COMMANDS中增加CFG_CMD_NAND的命令,如下所示。

#define CONFIG_COMMANDS \                        (CONFIG_CMD_DFL  | \                        CFG_CMD_CACHE    | \                        CFG_CMD_NAND     | \                        CFG_CMD_REGINFO  | \                        CFG_CMD_DATE     | \                        CFG_CMD_PING     | \                        CFG_CMD_ELF)

定义的CFG_CMD_NAND实际上就相当于u-boot对nand支持的总开关,定义之后u-boot对于NAND的应用就被打开了。我们先编译一下,看看现在是什么状态。make all,发现了如下的报错信息。

/work/system/u-boot-1.1.6/include/linux/mtd/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 knownnand.c:37: error: storage size of `nand_chip' isn't knownnand.c:38: error: storage size of `base_address' isn't knownnand.c:37: warning: 'nand_chip' defined but not usednand.c:38: warning: 'base_address' defined but not used

可以看到实际上虽然我们打开了对于NAND FLASH的支持,但是我们并没有添加NAND的信息,这样NAND肯定是有意见的。我们没有定义这三个宏定义,也缺少一些基本信息。那么我们首先在include/configs/TQ2440.h中添加三个宏定义信息。如下所示

/*----------------------------------------------------------------------- * NAND FLASH environment organization */#define CFG_NAND_BASE        0x4E000000          /* define the base address  */#define CFG_MAX_NAND_DEVICE  1                   /* the count of device */#define NAND_MAX_CHIPS       1                   /* every device is consist of 1 chip */
可以看到我们定义的CFG_NAND_BASE是使用S3C2410_NAND_BASE来定义的,这是因为S3C2440的NAND控制器首地址是与S3C2410相同的,另外定义CFG_NAND_BASE实际上就是指的S3C2440的NAND控制器的所有寄存器的首地址。所以这里定义的CFG_NAND_BASE即为S3C2410_NAND_BASE所代表的0x4E000000.

对于u-boot来说,他的启动分两个阶段,第一阶段的文件为cpu/arm920t/start.s和board/TQ2440/low_level_init.s文件,前者是和平台相关的,后者是和开发板相关的。第二阶段是从lib_arm/board.c中的start_armboot函数开始的,如下图所示


在start_armboot函数中flash_init完成之后,如果定了的nand则会初始化nand,函数为nand_init(),nand_init()是drivers/nand/nand.c文件中函数,在nand_init()中又调用了同文件中的nand_init_chip();,然后nand_init_chip()又调用同文件中的board_nand_init()函数,可以看到这个函数也在nand.c文件中,只不过只有个名字,没有被实现。我们需要自己来实现这个函数。

在编写nand_init_chip()之前我们应该知道s3c2410和s3c2440还是有差异存在。这其中就包括了nand控制寄存器的差异。在s3c2410中,nand控制寄存器地址范围为0x4E000000到0x4E000014(6个32位寄存器)。而在s3c2440在nand控制寄存器地址范围为0x4E000000到0x4E00003C(12个32位寄存器)。s3c2410的寄存器的定义是在include/S3c24x0.h中定义的(S3c2410.h包含这个头文件),代码中寄存器的定义是按照2410的寄存器定义的,因为s3c2440的nand控制器的寄存器更多一些,我们新建一个S3C2440_NAND结构体来定义我们要用的关于S3C2440的寄存器。具体添加什么寄存器,及对应顺序可以去s3c2440的数据手册里去查。添加完成后的两个片子的nand控制器寄存器结构体如下所示。

/* NAND FLASH (see S3C2410 manual chapter 6) */typedef struct {S3C24X0_REG32NFCONF;S3C24X0_REG32NFCMD;S3C24X0_REG32NFADDR;S3C24X0_REG32NFDATA;S3C24X0_REG32NFSTAT;S3C24X0_REG32NFECC;} /*__attribute__((__packed__))*/ S3C2410_NAND;/* NAND FLASH (see S3C2440) */typedef struct {S3C24X0_REG32NFCONF;S3C24X0_REG32NFCONT;S3C24X0_REG32NFCMD;S3C24X0_REG32NFADDR;S3C24X0_REG32NFDATA;        S3C24X0_REG32NFMECCD0;        S3C24X0_REG32NFMECCD1;        S3C24X0_REG32NFSECCD; S3C24X0_REG32NFSTAT;        S3C24X0_REG32NFESTAT0;        S3C24X0_REG32NFESTAT1;        S3C24X0_REG32NFMECC0;        S3C24X0_REG32NFMECC1;        S3C24X0_REG32NFSECC; S3C24X0_REG32NFSBLK;        S3C24X0_REG32NFEBLK;} /*__attribute__((__packed__))*/ S3C2440_NAND;

好接下来我们只要实现board_nand_init()函数就好了。为了能够更好地层次化处理我们代码我们在单独编写一个s3c2440_nand.c文件来单独实现一个s3c2440_nand_init()函数以及其他几个用到的函数。这样我们就可以直接在drivers/nand/nand.c中用board_nand_init()直接调用函数s3c2440_nand_init函数就可以了。

首先为了更好地编写s3c2440_nand.c文件,我们在include/s3c2410.h中添加对于获取nand地址的函数,即仿照S3C2410_GetBase_NAND函数定义实现一个函数名为S3C2410_GetBase_NAND的函数来获取地址,如下所示

static inline S3C2410_NAND * const S3C2410_GetBase_NAND(void){return (S3C2410_NAND * const)S3C2410_NAND_BASE;}static inline S3C2440_NAND * const S3C2440_GetBase_NAND(void){return (S3C2440_NAND * const)S3C2440_NAND_BASE;}

这里的S3C2440_NAND_BASE我们需要在前面的宏定义添加一下,这个地址是芯片寄存器已经定义好的。宏定义如下所示

#define S3C2440_NAND_BASE               0x4E000000

(这里需要说明一下,这里定义的S3C2440_NAND_BASE地址和我们之前定义的CFG_NAND_BASE一样都指向了S3C2440片子的NAND控制器寄存器的首地址。)

然后编写的s3c2440_nand.c文件代码为(s3c2440_nand.c的文件路径是/cpu/arm920t/s3c24x0/s3c2440_nand.c)

/* * Nand flash interface of s3c2410/s3c2440, by www.100ask.net * Changed from drivers/mtd/nand/s3c2410.c of kernel 2.6.13 */#include <common.h>#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)#include <s3c2410.h>#include <nand.h>DECLARE_GLOBAL_DATA_PTR;#define S3C2440_NFSTAT_READY    (1<<0)#define S3C2440_NFCONT_nFCE     (1<<1)/* select chip, for s3c2440 */static void s3c2440_nand_select_chip(struct mtd_info *mtd, int chip){    S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();    if (chip == -1) {        s3c2440nand->NFCONT |= S3C2440_NFCONT_nFCE;    } else {        s3c2440nand->NFCONT &= ~S3C2440_NFCONT_nFCE;    }}/* command and control functions */static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd){    S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();    struct nand_chip *chip = mtd->priv;    switch (cmd) {    case NAND_CTL_SETNCE:    case NAND_CTL_CLRNCE:        printf("%s: called for NCE\n", __FUNCTION__);        break;    case NAND_CTL_SETCLE:        chip->IO_ADDR_W = (void *)&s3c2440nand->NFCMD;        break;    case NAND_CTL_SETALE:        chip->IO_ADDR_W = (void *)&s3c2440nand->NFADDR;        break;        /* NAND_CTL_CLRCLE: */        /* NAND_CTL_CLRALE: */    default:        chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA;        break;    }}/* s3c2440_nand_devready() * * returns 0 if the nand is busy, 1 if it is ready */static int s3c2440_nand_devready(struct mtd_info *mtd){    S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();    return (s3c2440nand->NFSTAT & S3C2440_NFSTAT_READY);}/* * Nand flash hardware initialization: * Set the timing, enable NAND flash controller */static void s3c2440_nand_inithw(void){    S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();#define TACLS   0#define TWRPH0  4#define TWRPH1  2    /* Set flash memory timing */    s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);    /* Initialize ECC, enable chip select, NAND flash controller enable */    s3c2440nand->NFCONT = (1<<4)|(0<<1)|(1<<0);}/* * Called by drivers/nand/nand.c, initialize the interface of nand flash */void s3c2440_nand_init(struct nand_chip *chip){    S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();    s3c2440_nand_inithw();    chip->IO_ADDR_R    = (void *)&s3c2440nand->NFDATA;    chip->IO_ADDR_W    = (void *)&s3c2440nand->NFDATA;    chip->hwcontrol    = s3c2440_nand_hwcontrol;    chip->dev_ready    = s3c2440_nand_devready;    chip->select_chip  = s3c2440_nand_select_chip;    chip->options      = 0;    chip->eccmode       = NAND_ECC_SOFT;}#endif
(这段代码是直接由韦东山老师的代码改的)

(详细的研究下这段代码的作用,多研究http://blog.csdn.net/ying_seven/article/details/6888923)


接着修改drivers/nand/nand.c文件在其中建立函数board_nand_init(),其代码为

void board_nand_init(struct nand_chip *nand){        s3c2440_nand_init(nand);}

最后修改将s3c2440_nand.c文件加入到编译链中,就可以了。修改cpu/arm920t/s3c24x0/Makefile文件

修改前:

COBJS= i2c.o interrupts.o serial.o speed.o \  usb_ohci.o

修改后:

COBJS= i2c.o interrupts.o serial.o speed.o \  usb_ohci.o s3c2440_nand.o

这样就大功告成了,我们编译一下make all,然后编译通过,就可以了



最后说一下关于nand中的调用关系实际上是比较复杂,也比较完善的。我这里并没有提及这些东西,因为我也不是搞的很清楚,本博文的移植实际上也只是皮毛的移植。如果想深入了解,这里有一篇好博文大家可以去看。我自己也深受其益。http://blog.csdn.net/ying_seven/article/details/6888923


参考文献:1、《嵌入式linux开发完全手册》、韦东山

2、http://blog.csdn.NET/zhaocj (这位博主下面的u-boot系列)

3、http://blog.csdn.net/ying_seven/article/details/6888923


阅读全文
0 0
原创粉丝点击