您的位置 首页 IC

NAND FLASH驱动程序

参考*driversmtdnands3c2410c*driversmtdnandat91_nandcincludelinuxmodulehincludelinuxtypeshinclude

// 参阅

* 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[] = {
[0] = {
.name = “bootloader”,
.size = 0x00040000,
.offset = 0,
},
[1] = {
.name = “params”,
.offset = MTDPART_OFS_APPEND, //紧跟着上一个分区
.size = 0x00020000,
},
[2] = {
.name = “kernel”,
.offset = MTDPART_OFS_APPEND,
.size = 0x00200000,
},
[3] = {
.name = “root”,
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL, //剩余的一切空间都是”root”分区
}
};
static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr)
{
if (chipnr == -1)
{
//撤销选中: NFCONT[1]设为1
s3c_nand_regs->nfcont |= (1<<1);
}
else
{
// 选中: NFCONT[1]设为0
s3c_nand_regs->nfcont &= ~(1<<1);
}
}
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 & (1<<0));
}
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(0x4E000000, 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);
// 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<<12) | (TWRPH0<<8) | (TWRPH1<<4);
// NFCONT:
* BIT1-设为1, 撤销片选
* BIT0-设为1, 使能NAND FLASH控制器
//
s3c_nand_regs->nfcont = (1<<1) | (1<<0);
// 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, 1); // 辨认NAND FLASH, 结构mtd_info ,最大芯片个数1
// 5. add_mtd_partitions
add_mtd_partitions(s3c_mtd, s3c_nand_parts, 4); //分区数4
//add_mtd_device(s3c_mtd); //整个nand flash 作为一个分区运用
return 0;
}
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”);
=================================================================
NAND FLASH是一个存储芯片
那么: 这样的操作很合理”读地址A的数据,把数据B写到地址A”
问1. 原理图上NAND FLASH和S3C2440之间只要数据线,
怎样传输地址?
答1.在DATA0~DATA7上既传输数据,又传输地址
当ALE为高电平时传输的是地址,
问2. 从NAND FLASH芯片手册可知,要操作NAND FLASH需求先宣布指令
怎样传入指令?
答2.在DATA0~DATA7上既传输数据,又传输地址,也传输指令
当ALE为高电平时传输的是地址,
当CLE为高电平时传输的是指令
当ALE和CLE都为低电平时传输的是数据
问3. 数据线既接到NAND FLASH,也接到NOR FLASH,还接到SDRAM、DM9000等等
那么怎样防止搅扰?
答3. 这些设备,要拜访之有必要”选中”,
没有选中的芯片不会作业,相当于没接相同
问4. 假定烧写NAND FLASH,把指令、地址、数据发给它之后,
NAND FLASH必定不可能瞬间完结烧写的,
怎样判别烧写完结?
答4. 经过状况引脚RnB来判别:它为高电平表明安排妥当,它为低电平表明正忙
问5. 怎样操作NAND FLASH呢?
答5. 依据NAND FLASH的芯片手册,一般的进程是:
宣布指令
宣布地址
宣布数据/读数据
NAND FLASH S3C2440
发指令 选中芯片
CLE设为高电平 NFCMMD=指令值
在DATA0~DATA7上输出指令值
宣布一个写脉冲
发地址 选中芯片 NFADDR=地址值
ALE设为高电平
在DATA0~DATA7上输出地址值
宣布一个写脉冲
发数据 选中芯片 NFDATA=数据值
ALE,CLE设为低电平
在DATA0~DATA7上输出数据值
宣布一个写脉冲
读数据 选中芯片 val=NFDATA
宣布读脉冲
读DATA0~DATA7的数据
用UBOOT来体会NAND FLASH的操作:
1. 读ID
S3C2440 u-boot
选中 NFCONT的bit1设为0 md.l 0x4E000004 1; mw.l 0x4E000004 1
宣布指令0x90 NFCMMD=0x90 mw.b 0x4E000008 0x90
宣布地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
读数据得到0xEC val=NFDATA md.b 0x4E000010 1
读数据得到device code val=NFDATA md.b 0x4E000010 1
0xda
退出读ID的状况 NFCMMD=0xff mw.b 0x4E000008 0xff
2. 读内容: 读0地址的数据
运用UBOOT指令:
nand dump 0
Page 00000000 dump:
17 00 00 ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5
S3C2440 u-boot
选中 NFCONT的bit1设为0 md.l 0x4E000004 1; mw.l 0x4E000004 1
宣布指令0x00 NFCMMD=0x00 mw.b 0x4E000008 0x00
宣布地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
宣布地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
宣布地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
宣布地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
宣布地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
宣布指令0x30 NFCMMD=0x30 mw.b 0x4E000008 0x30
读数据得到0x17 val=NFDATA md.b 0x4E000010 1
读数据得到0x00 val=NFDATA md.b 0x4E000010 1
读数据得到0x00 val=NFDATA md.b 0x4E000010 1
读数据得到0xea val=NFDATA md.b 0x4E000010 1
退出读状况 NFCMMD=0xff mw.b 0x4E000008 0xff
NAND FLASH驱动程序层次
看内核发动信息
S3C24XX NAND Driver, (c) 2004 Simtec Electronics
s3c2440-nand s3c2440-nand: Tacls=3, 30ns Twrph0=7 70ns, Twrph1=3 30ns
NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)
Scanning device for bad blocks
Bad eraseblock 256 at 0x02000000
Bad eraseblock 257 at 0x02020000
Bad eraseblock 319 at 0x027e0000
Bad eraseblock 606 at 0x04bc0000
Bad eraseblock 608 at 0x04c00000
Creating 4 MTD partitions on “NAND 256MiB 3,3V 8-bit”:
0x00000000-0x00040000 : “bootloader”
0x00040000-0x00060000 : “params”
0x00060000-0x00260000 : “kernel”
0x00260000-0x10000000 : “root”
搜”S3C24XX NAND Driver”
S3c2410.c (drivers\mtd\nand)
s3c2410_nand_inithw
s3c2410_nand_init_chip
nand_scan // drivers/mtd/nand/nand_base.c 依据nand_chip的底层操作函数辨认NAND FLASH,结构mtd_info
nand_scan_ident
nand_set_defaults
if (!chip->select_chip)
chip->select_chip = nand_select_chip; // 默认值不适用
if (chip->cmdfunc == NULL)
chip->cmdfunc = nand_command;
chip->cmd_ctrl(mtd, command, ctrl);
if (!chip->read_byte)
chip->read_byte = nand_read_byte;
readb(chip->IO_ADDR_R);
if (chip->waitfunc == NULL)
chip->waitfunc = nand_wait;
chip->dev_ready
nand_get_flash_type
chip->select_chip(mtd, 0);
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
*maf_id = chip->read_byte(mtd);
dev_id = chip->read_byte(mtd);
nand_scan_tail
mtd->erase = nand_erase;
mtd->read = nand_read;
mtd->write = nand_write;
s3c2410_nand_add_partition
add_mtd_partitions
add_mtd_device
list_for_each(this, &mtd_notifiers) { // 问. mtd_notifiers在哪设置
// 答. drivers/mtd/mtdchar.c,mtd_blkdev.c调用register_mtd_user
struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
not->add(mtd);
// mtd_notify_add 和 blktrans_notify_add
先看字符设备的mtd_notify_add
class_device_create
class_device_create
再看块设备的blktrans_notify_add
list_for_each(this, &blktrans_majors) { // 问. blktrans_majors在哪设置
// 答. drivers\mtd\mdblock.c或mtdblock_ro.c register_mtd_blktrans
struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
tr->add_mtd(tr, mtd);
mtdblock_add_mtd (drivers\mtd\mdblock.c)
add_mtd_blktrans_dev
alloc_disk
gd->queue = tr->blkcore_priv->rq; // tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);
add_disk
测验4th:
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作为根文件体系,由于之前根文件体系在nand flash上面,现在内核去除了nand flash的驱动,内核就无法拜访根文件体系了。
3. 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/
flash_erase:只擦除一个扇区
flash_eraseall:整个分区都擦除去

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/bandaoti/263396.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部