天天看点

Nand Flash的驱动程序一、关于NAND FLASH的基本问题:二、驱动程序框架三、测试

一、关于NAND FLASH的基本问题:

问1. 原理图上NAND FLASH和S3C2440之间只有数据线,怎么传输地址?

答1.在DATA0~DATA7上既传输数据,又传输地址

当ALE为高电平时传输的是地址,

问2. 从NAND FLASH芯片手册可知,要操作NAND FLASH需要先发出命令怎么传入命令?

答2.在DATA0~DATA7上既传输数据,又传输地址,也传输命令

当ALE为高电平时传输的是地址,

当CLE为高电平时传输的是命令

当ALE和CLE都为低电平时传输的是数据

问3. 假设烧写NAND FLASH,把命令、地址、数据发给它之后,

NAND FLASH肯定不可能瞬间完成烧写的,怎么判断烧写完成?

答3. 通过状态引脚RnB来判断:它为高电平表示就绪,它为低电平表示正忙

问4. NAND Flash引脚描述?

答4. CLE:指令锁存使能 ALE:地址锁存使能 CE:芯片使能

RE: 读使能 WE:写使能 WP:写保护

R/B:就绪/忙

问5. 怎么操作NAND FLASH呢?

答5. 根据NAND FLASH的芯片手册,一般的过程是:

a. 发出命令

b. 发出地址

c. 发出数据/读数据

由于S3C2440内部存在NAND Flash的控制器,可以方便开发,省掉很多繁琐的操作比如说发命令,它需要经历“选中芯片”、“CLE设为高电平”、“在DATA0~DATA7上输出命令值”发出一个写脉冲”一系列操作才可以实现发命令,但是斗鱼S3c2440的内部NAND Flash的控制器的存在,只需要令寄存器“ NFCMMD=命令值”就可以实现。

Nand Flash的驱动程序一、关于NAND FLASH的基本问题:二、驱动程序框架三、测试

6.用UBOOT来体验NAND FLASH的操作:

Nand Flash的驱动程序一、关于NAND FLASH的基本问题:二、驱动程序框架三、测试
Nand Flash的驱动程序一、关于NAND FLASH的基本问题:二、驱动程序框架三、测试

二、驱动程序框架

static int s3c_nand_init(void)

{

1.分配一个nand_chip结构体

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2. 设置nand_chip

s3c_nand->select_chip = s3c2440_select_chip;

s3c_nand->cmd_ctrl = s3c2440_cmd_ctrl;

s3c_nand->IO_ADDR_R = &s3c_nand_regs->nfdata;

s3c_nand->IO_ADDR_W = &s3c_nand_regs->nfdata;

s3c_nand->dev_ready = s3c2440_dev_ready;

s3c_nand->ecc.mode = NAND_ECC_SOFT; //ECC

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

3. 硬件相关的设置: 根据NAND FLASH的手册设置时间参数

3.1 设置 TACLS、TWRPH0、TWRPH1三个参数

3.2 取消片选 、使能NAND FLASH控制器

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

4. 使用: nand_scan

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

5. add_mtd_partitions

}

static void s3c_nand_exit(void)

{

}

以上需要用到的函数定义

static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr)

{

if (chipnr == -1)

{

}

else

{

}

}

static void s3c2440_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)

{

if (ctrl & NAND_CLE)

{

}

else

{

}

}

static int s3c2440_dev_ready(struct mtd_info *mtd)

{

}

以下是完整代码:

/* 参考 
 * drivers\mtd\nand\s3c2410.c
 * drivers\mtd\nand\at91_nand.c
 */

#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/clk.h>

#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>

#include <asm/io.h>

#include <asm/arch/regs-nand.h>
#include <asm/arch/nand.h>

struct s3c_nand_regs {
    unsigned long nfconf  ;
    unsigned long nfcont  ;
    unsigned long nfcmd   ;
    unsigned long nfaddr  ;
    unsigned long nfdata  ;
    unsigned long nfeccd0 ;
    unsigned long nfeccd1 ;
    unsigned long nfeccd  ;
    unsigned long nfstat  ;
    unsigned long nfestat0;
    unsigned long nfestat1;
    unsigned long nfmecc0 ;
    unsigned long nfmecc1 ;
    unsigned long nfsecc  ;
    unsigned long nfsblk  ;
    unsigned long nfeblk  ;
};


static struct nand_chip *s3c_nand;
static struct mtd_info *s3c_mtd;
static struct s3c_nand_regs *s3c_nand_regs;

static struct mtd_partition s3c_nand_parts[] = {
    [] = {
        .name   = "bootloader",
        .size   = ,
        .offset = ,
    },
    [] = {
        .name   = "params",
        .offset = MTDPART_OFS_APPEND,
        .size   = ,
    },
    [] = {
        .name   = "kernel",
        .offset = MTDPART_OFS_APPEND,
        .size   = ,
    },
    [] = {
        .name   = "root",
        .offset = MTDPART_OFS_APPEND,
        .size   = MTDPART_SIZ_FULL,
    }
};


static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr)
{
    if (chipnr == -)
    {
        /* 取消选中: NFCONT[1]设为1 */
        s3c_nand_regs->nfcont |= (<<);        
    }
    else
    {
        /* 选中: NFCONT[1]设为0 */
        s3c_nand_regs->nfcont &= ~(<<);
    }
}

static void s3c2440_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
    if (ctrl & NAND_CLE)
    {
        /* 发命令: NFCMMD=dat */
        s3c_nand_regs->nfcmd = dat;
    }
    else
    {
        /* 发地址: NFADDR=dat */
        s3c_nand_regs->nfaddr = dat;
    }
}

static int s3c2440_dev_ready(struct mtd_info *mtd)
{
    return (s3c_nand_regs->nfstat & (<<));
}


static int s3c_nand_init(void)
{
    struct clk *clk;

    /* 1. 分配一个nand_chip结构体 */
    s3c_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);

    s3c_nand_regs = ioremap(, sizeof(struct s3c_nand_regs));

    /* 2. 设置nand_chip */
    /* 设置nand_chip是给nand_scan函数使用的, 如果不知道怎么设置, 先看nand_scan怎么使用 
     * 它应该提供:选中,发命令,发地址,发数据,读数据,判断状态的功能
     */
    s3c_nand->select_chip = s3c2440_select_chip;
    s3c_nand->cmd_ctrl    = s3c2440_cmd_ctrl;
    s3c_nand->IO_ADDR_R   = &s3c_nand_regs->nfdata;
    s3c_nand->IO_ADDR_W   = &s3c_nand_regs->nfdata;
    s3c_nand->dev_ready   = s3c2440_dev_ready;
    s3c_nand->ecc.mode    = NAND_ECC_SOFT;

    /* 3. 硬件相关的设置: 根据NAND FLASH的手册设置时间参数 */
    /* 使能NAND FLASH控制器的时钟 */
    clk = clk_get(NULL, "nand");
    clk_enable(clk);              /* CLKCON'bit[4] */

    /* HCLK=100MHz
     * TACLS:  发出CLE/ALE之后多长时间才发出nWE信号, 从NAND手册可知CLE/ALE与nWE可以同时发出,所以TACLS=0
     * TWRPH0: nWE的脉冲宽度, HCLK x ( TWRPH0 + 1 ), 从NAND手册可知它要>=12ns, 所以TWRPH0>=1
     * TWRPH1: nWE变为高电平后多长时间CLE/ALE才能变为低电平, 从NAND手册可知它要>=5ns, 所以TWRPH1>=0
     */
#define TACLS    0
#define TWRPH0   1
#define TWRPH1   0
    s3c_nand_regs->nfconf = (TACLS<<) | (TWRPH0<<) | (TWRPH1<<);

    /* NFCONT: 
     * BIT1-设为1, 取消片选 
     * BIT0-设为1, 使能NAND FLASH控制器
     */
    s3c_nand_regs->nfcont = (<<) | (<<);

    /* 4. 使用: nand_scan */
    s3c_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
    s3c_mtd->owner = THIS_MODULE;
    s3c_mtd->priv  = s3c_nand;

    nand_scan(s3c_mtd, );  /* 识别NAND FLASH, 构造mtd_info */

    /* 5. add_mtd_partitions */
    add_mtd_partitions(s3c_mtd, s3c_nand_parts, );

    //add_mtd_device(s3c_mtd);
    return ;
}

static void s3c_nand_exit(void)
{
    del_mtd_partitions(s3c_mtd);
    kfree(s3c_mtd);
    iounmap(s3c_nand_regs);
    kfree(s3c_nand);
}

module_init(s3c_nand_init);
module_exit(s3c_nand_exit);

MODULE_LICENSE("GPL");

           

三、测试

  1. make menuconfig去掉内核自带的NAND FLASH驱动

    -> Device Drivers

    -> Memory Technology Device (MTD) support

    -> NAND Device Support

    < > NAND Flash support for S3C2410/S3C2440 SoC

  2. make uImage

    使用新内核启动, 并且使用NFS作为根文件系统

    cp arch/arm/boot/uImage /work/nfs_root/uImage_nonand 复制到文件系统

    重启开发板,倒数到0之前按下Q:

    set bootargs console=ttySAC0 root=/dev/nfs nfsroot=192.168.1.7:/work/nfs_root/first_fs ip=192.168.1.2:192.168.1.7:192.168.1.1:255.255.255.0::eth0:off 设置启动参数

    save

    nfs 30000000 192.168.1.7:/work/nfs_root/uImage_nonand

    bootm 30000000

  3. 装载

    ls /dev/mtd* 显示 ls: /dev/mtd*: No such file or directory

    insmod s3c_nand.ko

  4. 格式化 (参考下面编译工具)

    flash_eraseall /dev/mtd3 // yaffs

  5. 挂接

    mount -t yaffs /dev/mtdblock3 /mnt

  6. 在/mnt目录下建文件

编译工具:

1. tar xjf mtd-utils-05.07.23.tar.bz2

2. cd mtd-utils-05.07.23/util

修改Makefile:

#CROSS=arm-linux-

改为

CROSS=arm-linux-

3. make

4. cp flash_erase flash_eraseall /work/nfs_root/first_fs/bin/

继续阅读