s3c6410_nand.c源码:
// 参考: drivers\mtd\nand\h1910.c
#include "linux/slab.h"
#include "linux/init.h"
#include "linux/module.h"
#include "linux/mtd/mtd.h"
#include "linux/mtd/nand.h"
#include "linux/mtd/partitions.h"
#include "asm/io.h"
#include "mach/hardware.h" // for CLPS7111_VIRT_BASE
#include "asm/sizes.h"
#include "linux/clk.h"
//drivers/mtd/nand/s3c_nand.c
// samsung K9GAG08U0D MLC nand flash oob size =218 Byte
static struct nand_ecclayout s3c_nand_oob_mlc_218_8bit = {
.eccbytes = 104,
.eccpos = {
114,115,116,117,118,119,120,121,122,123,
124,125,126,127,128,129,130,131,132,133,
134,135,136,137,138,139,140,141,142,143,
144,145,146,147,148,149,150,151,152,153,
154,155,156,157,158,159,160,161,162,163,
164,165,166,167,168,169,170,171,172,173,
174,175,176,177,178,179,180,181,182,183,
184,185,186,187,188,189,190,191,192,193,
194,195,196,197,198,199,200,201,202,203,
204,205,206,207,208,209,210,211,212,213,
214,215,216,217 },
.oobfree = {
{.offset = 2,
.length = 110}}
};
static struct mtd_info *s3c6410_mtd;
struct s3c6410_nand_regs {
unsigned long NFCONF;
unsigned long NFCONT;
unsigned long NFCMD;
unsigned long NFADDR;
unsigned long NFDATA;
unsigned long NFMECCDATA0;
unsigned long NFMECCDATA1;
unsigned long NFSECCDATA;
unsigned long NFSBLK;
unsigned long NFEBLK;
unsigned long NFSTAT;
unsigned long NFMECCERR0;
unsigned long NFMECCERR1;
unsigned long NFMECC0;
unsigned long NFMECC1;
unsigned long NFSECC;
unsigned long NFMLCBITPT;
};
static struct s3c6410_nand_regs *s3c6410_nand_regs;
static struct mtd_partition s3c_partitions[] = {
{
.name = "Bootloader",
.offset = 0,
.size = (256*SZ_1K),
.mask_flags = MTD_CAP_NANDFLASH,
},
{
.name = "Kernel",
.offset = (256*SZ_1K),
.size = (4*SZ_1M) - (256*SZ_1K),
.mask_flags = MTD_CAP_NANDFLASH,
},
{
.name = "Rootfs",
.offset = (4*SZ_1M),
.size = (80*SZ_1M),//(48*SZ_1M),
},
{
.name = "File System",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
}
};
static void s3c6410_nand_select(struct mtd_info *mtd, int chip)
{
if (0 == chip)
{
s3c6410_nand_regs->NFCONT &= ~(1<<1); //0: NAND Flash Controller Disable (Don’t work)
//printk("s3c6410_nand_select : %x\n", s3c6410_nand_regs->NFCONT);
}
else
{
//printk("s3c6410_nand_deselect\n");
s3c6410_nand_regs->NFCONT |= (1<<1); //1: NAND Flash Controller Enable
}
}
static void s3c6410_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
if (ctrl & NAND_CLE)
{
//printk("send cmd: %x\n", dat);
s3c6410_nand_regs->NFCMD = dat;
}
else if (ctrl & NAND_ALE)
{
//printk("send addr: %x\n", dat);
s3c6410_nand_regs->NFADDR = dat;
}
}
static void s3c6410_nand_hw_init(void)
{
// MEM_SYS_CFG &= ~(1<<1);
// setup time parameter
#define TACLS 7
#define TWRPH0 7
#define TWRPH1 7
s3c6410_nand_regs->NFCONF &= ~((1<<30) | (7<<12) | (7<<8) | (7<<4));
s3c6410_nand_regs->NFCONF |= ((TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4));
// enable nand flash controller
s3c6410_nand_regs->NFCONT |= 1;
s3c6410_nand_regs->NFCONT &= ~(1<<16); // disable soft lock
}
static int s3c6410_nand_ready(struct mtd_info *mtd)
{
return (s3c6410_nand_regs->NFSTAT & 0x1);
}
static int s3c6410_nand_init(void)
{
struct nand_chip *chip;
struct clk *clk;
volatile unsigned long *MEM_SYS_CFG;
MEM_SYS_CFG = ioremap(0x7E00F120, 4);
*MEM_SYS_CFG &= ~(1<<1);
iounmap(MEM_SYS_CFG);
clk = clk_get(NULL, "nand");
clk_enable(clk);
s3c6410_nand_regs = ioremap(0x70200000, 1024);
s3c6410_nand_hw_init();
s3c6410_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
chip = (struct nand_chip *)&s3c6410_mtd[1];
s3c6410_mtd->priv = chip;
s3c6410_mtd->owner = THIS_MODULE;
// setup nand_chip:
chip->options = 0;
chip->select_chip = s3c6410_nand_select;
chip->cmd_ctrl = s3c6410_nand_cmd_ctrl;
chip->IO_ADDR_R = &s3c6410_nand_regs->NFDATA;
chip->IO_ADDR_W = &s3c6410_nand_regs->NFDATA;
chip->dev_ready = s3c6410_nand_ready;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.layout = &s3c_nand_oob_mlc_218_8bit;
if (nand_scan(s3c6410_mtd, 1))
{
printk("can't find nand flash for s3c6410\n");
kfree(s3c6410_mtd);
iounmap(s3c6410_nand_regs);
return -EAGAIN;
}
//add_mtd_partitions(s3c6410_mtd, s3c_partitions, 4); // add_disk
mtd_device_register(s3c6410_mtd, s3c_partitions, 4); //注册mtd设备
return 0;
}
static void s3c610_nand_exit(void)
{
//del_mtd_partitions(s3c6410_mtd);
mtd_device_unregister(s3c6410_mtd);
kfree(s3c6410_mtd);
iounmap(s3c6410_nand_regs);
}
module_init(s3c6410_nand_init);
module_exit(s3c610_nand_exit);
MODULE_LICENSE("GPL");
=====================================================================
Makefile文件:
KERN_DIR = /work/tools/linux/linux-3.0.1
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += s3c6410_nand.o
=====================================================================
NAND FLASH控制流程:
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的芯片手册,一般的过程是:
发出命令
发出地址
发出数据/读数据
=====================================================================
S3C6410 NAND FLASH命令操作:
1. 读ID
S3C6410 u-boot
选中 NFCONT的bit1设为0 md.l 0x70200004 1; mw.l 0x70200004 1
//md.l内存数据显示,单位 : .b读一字节 .w读2字节 .l读4字节 0x70200004 地址 1 读一次
// mw.l 内存写入0x70200004地址,1写入数值1 即 01 含义: 0: Force Xm0CSn2 to low(Enable chip select),1: NAND Flash Controller Enable
//.b: byte 字节 .w word 字 .l long 长的
发出命令0x90 NFCMMD=0x90 mw.b 0x70200008 0x90 写入一个字节
发出地址0x00 NFADDR=0x00 mw.b 0x7020000C 0x00
读数据得到0xEC val=NFDATA md.b 0x70200010 1
读数据得到device code val=NFDATA md.b 0x70200010 1
0xda
退出读ID的状态 NFCMMD=0xff mw.b 0x70200008 0xff
SMDK6410 # mw.l 0x70200004 1 发出片选
SMDK6410 # mw.b 0x70200008 0x90 发出90h命令
SMDK6410 # mw.b 0x7020000C 0x00 发出0地址
SMDK6410 # md.b 0x70200010 1 读数据
70200010: ec . 读到ec
SMDK6410 # md.b 0x70200010 1 读到设备id
70200010: d7 .
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 0x70200004 1; mw.l 0x70200004 1
发出命令0x00 NFCMMD=0x00 mw.b 0x70200008 0x00
发出地址0x00 NFADDR=0x00 mw.b 0x7020000C 0x00
发出地址0x00 NFADDR=0x00 mw.b 0x7020000C 0x00
发出地址0x00 NFADDR=0x00 mw.b 0x7020000C 0x00
发出地址0x00 NFADDR=0x00 mw.b 0x7020000C 0x00
发出地址0x00 NFADDR=0x00 mw.b 0x7020000C 0x00
发出命令0x30 NFCMMD=0x30 mw.b 0x70200008 0x30
读数据得到0x17 val=NFDATA md.b 0x70200010 1
读数据得到0x00 val=NFDATA md.b 0x70200010 1
读数据得到0x00 val=NFDATA md.b 0x70200010 1
读数据得到0xea val=NFDATA md.b 0x70200010 1
退出读状态 NFCMMD=0xff mw.b 0x70200008 0xff
SMDK6410 # nand dump 0
Page 00000000 dump:
13 00 00 ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5 每行显示16字节数据
14 f0 9f e5 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5
SMDK6410 # md.l 0x70200004 1
70200004: 000000c7 ....
SMDK6410 # mw.l 0x70200004 0xc5
SMDK6410 # md.l 0x70200004 1
70200004: 000000c5 ....
SMDK6410 # mw.b 0x70200008 0x00
SMDK6410 # mw.b 0x7020000C 0x00
SMDK6410 # mw.b 0x7020000C 0x00
SMDK6410 # mw.b 0x7020000C 0x00
SMDK6410 # mw.b 0x7020000C 0x00
SMDK6410 # mw.b 0x7020000C 0x00
SMDK6410 # mw.b 0x70200008 0x30
SMDK6410 # md.b 0x70200010 1
70200010: 13 .
SMDK6410 # md.b 0x70200010 1
70200010: 00 .
SMDK6410 # md.b 0x70200010 1
70200010: 00 .
SMDK6410 # md.b 0x70200010 1
70200010: ea .
SMDK6410 # mw.b 0x70200008 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 nand扫描 // drivers/mtd/nand/nand_base.c 根据nand_chip的底层操作函数识别NAND FLASH,构造mtd_info
nand_scan_ident
nand_set_defaults默认的设置 nand_base.c
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);
//读id {"NAND 4GiB 3,3V 8-bit", 0xD7, 0, 4096, 0, LP_OPTIONS},
*maf_id = chip->read_byte(mtd);读字节
dev_id = chip->read_byte(mtd);
nand_scan_tail
mtd->erase = nand_erase; mtd_info结构体
mtd->read = nand_read;
mtd->write = nand_write;
s3c2410_nand_add_partition
add_mtd_partitions添加分区
add_mtd_device添加mtd设备
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 创建两个设备节点,一个是mtd1,另一个是mtd1ro ro只读
class_device_create
再看块设备的blktrans_notify_add
list_for_each(this, &blktrans_majors) {
// 问. blktrans_majors在哪设置
// 答. drivers\mtd\mdblock.c或mtdblock_ro.c register_mtd_blktrans注册mtd块传输
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添加磁盘
=====================================================================
s3c6410:
s3c_nand.c何时被使用:
内核arch/arm/plat-samsung/dev-nand.c有一个平台设备:
struct platform_device s3c_device_nand = {
.name = "s3c6410-nand",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_nand_resource),
.resource = s3c_nand_resource,
};
EXPORT_SYMBOL(s3c_device_nand);
它会注册一个名字是"s3c6410-nand"的platform_device,
当s3c_nand.c注册平台驱动时发现有同名的平台设备,
就会调用平台驱动的probe函数,如果没有这个平台设备,
执行到s3c_nand.c时它不会做任何事情。
在ok6410官方内核linux-3.0.1源码arch/arm/plat-samsung/ 目录下有很多platform_device结构体
=====================================================================
测试:
1. make menuconfig去掉内核自带的NAND FLASH驱动
linux-3.0.1
默认:
-> Device Drivers
-> Memory Technology Device (MTD) support
-> NAND Device Support
[ ] NAND Flash support for Samsung S3C SoCs
[*] NAND support for Samsung S3C
[*] S3C NAND driver debug
[*] S3C NAND Hardware ECC
改为:
-> Device Drivers
-> Memory Technology Device (MTD) support
-> NAND Device Support
[ ] NAND Flash support for Samsung S3C SoCs
[ ] NAND support for Samsung S3C
//添加mtd分区,linux-3.0.1编译会有警告:
//WARNING: "add_mtd_partitions" [/home/cheng/cross/nand_flash_mtd/s3c6410nand.ko] undefined!
//WARNING: "del_mtd_partitions" [/home/cheng/cross/nand_flash_mtd/s3c6410nand.ko] undefined!
//加载时会有错误:
//s3c6410_nand: Unknown symbol del_mtd_partitions (err 0)
//s3c6410_nand: Unknown symbol add_mtd_partitions (err 0)
add_mtd_partitons()警告解决方法:
使用mtd_device_register(s3c6410_mtd,ok6410_nand_part,3);//注册mtd设备
或者:
在add_mtd_partitions()函数后面添加:
EXPORT_SYMBOL(add_mtd_partitions);
EXPORT_SYMBOL(del_mtd_partitions);
2. make uImage/make zImage
cp arch/arm/boot/zImage ../../zImage_no_nand
把开发板设置为SD卡启动,使用SD卡启动后按空格进入SD卡的u-boot;
用SD卡里面的u-boot烧写内核到0x000000200000-0x000000700000 : "Kernel"分区:
tftp 50008000 zImage_no_nand
nand erase 200000 500000
nand write 50008000 200000 500000
烧写完成后设置开发版为nand flash启动,使用新内核启动, 并且使用NFS作为根文件系统,因为之前根文件系统在nand flash上面,现在内核去除了nand flash的驱动,内核就无法访问根文件系统了。
print命令查看u-boot参数:
bootcmd=nand read 0xc0008000 0x200000 0x500000;bootm 0xc0008000
baudrate=115200
ethaddr=00:40:5c:26:0a:5b
netmask=255.255.255.0
bootdelay=10
serverip=192.168.48.103
ipaddr=192.168.48.100
gatewayip=192.168.48.1
bootargs=noinitrd root=/dev/nfs nfsroot=192.168.48.104:/home/book/workspace/ok6410_project/fs_ok6410_yaffs2 ip=192.168.48.100:192.168.48.104:192.168.48.255:255.255.255.0::eth0:off init=/linuxrc console=ttySAC0,115200
ls /dev/mtd* 看不到mtd分区
3. insmod s3c_nand.ko
ls /dev/mtd* -l
crw-rw---- 1 0 0 90, 0 Jan 1 01:23 /dev/mtd0 字符设备
crw-rw---- 1 0 0 90, 1 Jan 1 01:23 /dev/mtd0ro 只读
crw-rw---- 1 0 0 90, 2 Jan 1 01:23 /dev/mtd1
crw-rw---- 1 0 0 90, 3 Jan 1 01:23 /dev/mtd1ro
crw-rw---- 1 0 0 90, 4 Jan 1 01:23 /dev/mtd2
crw-rw---- 1 0 0 90, 5 Jan 1 01:23 /dev/mtd2ro
brw-rw---- 1 0 0 31, 0 Jan 1 01:23 /dev/mtdblock0 块设备
brw-rw---- 1 0 0 31, 1 Jan 1 01:23 /dev/mtdblock1
brw-rw---- 1 0 0 31, 2 Jan 1 01:23 /dev/mtdblock2
root=/dev/mtdblock2 rootfstype=jffs2 rw init=/linuxrc console=ttySAC0,115200
flash_eraseall -j /dev/mtd2 //nand格式化为jffs2
mount -t jffs2 /dev/mtdblock2 /mnt
4. 格式化 (参考下面编译工具)
flash_eraseall /dev/mtd3 // 格式化mtd3分区 默认格式成yaffs
5. 挂接
mount -t yaffs /dev/mtdblock3 /mnt //挂载设备节点
如果出现以下提示则说明nand flash可能有有坏块:
uncorrectable error :
end_request: I/O error, dev mtdblock2, sector 0
Buffer I/O error on device mtdblock2, logical block 0
uncorrectable error :
end_request: I/O error, dev mtdblock2, sector 0
Buffer I/O error on device mtdblock2, logical block 0
代码页可能出错:
static void s3c6410_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
if(ctrl & NAND_CLE)
{
//如果是CLE ,发命令:NFCMMD = dat
nand_regs->nfcmmd = dat;
}
else if (ctrl & NAND_ALE)
//如果不加ctrl & NAND_ALE此项直接就 else 会有错误:uncorrectable :I/O error, dev mtdblock2, sector 0 等
{
//否则如果是发地址 :NFADDR = dat
nand_regs->nfaddr = dat;
}
}
6. 在/mnt目录下建文件
编译工具:
①. tar xjf mtd-utils-05.07.23.tar.bz2
②. cd mtd-utils-05.07.23/util
修改Makefile:
#CROSS=arm-linux-
CC := $(CROSS)gcc
改为:
CROSS=arm-linux-
CC := $(CROSS)gcc
③. make
④. cp flash_erase flash_eraseall /work/nfs_root/first_fs/bin/
注意:s3c6410启动时自动拷贝nand flash前4页的内容到片内内存执行,而且拷贝时只拷每页中的前2KByte,好像是为了兼容2k页的,所有copy2ddr函数中不要把所有数据全部照搬过去,只搬每页的前2k到ddr连接起来 。
=====================================================================
错误解决:
在程序的开始并没有定义s3c_nand_oob_mlc_218_8bit结构体,按照S3C2440的nand flash驱动,OOB设置由内核自动完成,但是在测试驱动的时候发现内核运行崩溃,报“Segmentation fault”:
NAND device: Manufacturer ID: 0xec, Chip ID: 0xd7 (Samsung NAND 4GiB 3,3V 8-bit)
No oob scheme defined for oobsize 218
kernel BUG at drivers/mtd/nand/nand_base.c:3278!
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = cbc24000
[00000000] *pgd=5c7a0831, *pte=00000000, *ppte=00000000
Internal error: Oops: 817 [#1]
Modules linked in: s3c6410_nand(+)
CPU: 0 Tainted: G W (3.0.1 #442)
PC is at __bug+0x20/0x2c
LR is at console_unlock+0x15c/0x1b8
pc : [] lr : [] psr: 60000013
sp : cbc5fec0 ip : cbc5fde8 fp : cbc5fecc
r10: 00000000 r9 : bf0000d0 r8 : cbc5e000
r7 : 00000000 r6 : cc6e3400 r5 : cc6e3590 r4 : cc6e3400
r3 : 00000000 r2 : c27c5ac5 r1 : 00000000 r0 : 00000037
Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 00c5387d Table: 5bc24008 DAC: 00000015
Process insmod (pid: 114, stack limit = 0xcbc5e268)
Stack: (0xcbc5fec0 to 0xcbc60000)
fec0: cbc5feec cbc5fed0 c026c9c4 c00383d0 cc6e3400 00000001 bf000320 00000000
fee0: cbc5ff04 cbc5fef0 c026f8c0 c026c498 bf000d10 00000000 cbc5ff24 cbc5ff08
ff00: bf0001c4 c026f888 c073d9a0 00000000 bf000ba8 00000000 cbc5ff7c cbc5ff28
ff20: c00343c8 bf0000dc cbc5ff64 cbc5ff38 c0073e24 00000000 00000000 00000000
ff40: 00000000 000127c8 000d5bf9 bf000ba8 00000000 000127c8 000d5bf9 bf000ba8
ff60: 00000000 c0034ce8 cbc5e000 00000000 cbc5ffa4 cbc5ff80 c0085960 c0034398
ff80: c00e8738 c00e8610 401ad4a8 000dfcf8 00000000 00000080 00000000 cbc5ffa8
ffa0: c0034b40 c00858e0 401ad4a8 000dfcf8 00ae0038 000127c8 000d5bf9 ffff5f01
ffc0: 401ad4a8 000dfcf8 00000000 00000080 00000069 00000001 bef6de74 bef6de78
ffe0: bef6de78 bef6db24 00021cfc 4026ed74 60000010 00ae0038 00000000 00000000
[] (__bug+0x20/0x2c) from [] (nand_scan_tail+0x538/0x644)
[] (nand_scan_tail+0x538/0x644) from [] (nand_scan+0x44/0x7c)
[] (nand_scan+0x44/0x7c) from [] (s3c6410_nand_init+0xf4/0x170 [s3c6410_nand])
[] (s3c6410_nand_init+0xf4/0x170 [s3c6410_nand]) from [] (do_one_initcall+0x3c/0x188)
[] (do_one_initcall+0x3c/0x188) from [] (sys_init_module+0x8c/0x1a4)
[] (sys_init_module+0x8c/0x1a4) from [] (ret_fast_syscall+0x0/0x30)
Code: e1a01000 e59f000c eb11b57b e3a03000 (e5833000)
---[ end trace da227214a82491b9 ]---
Segmentation fault
根据此错误信息“kernel BUG at drivers/mtd/nand/nand_base.c:3278!”找到对应报错点:
if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) {
即没有定义chip->ecc.layout
在网上找了一天!!!
参考“ok6410 nandflash 驱动注意地方”
ECC相关的结构体:
struct nand_ecclayout {
uint32_t eccbytes;
uint32_t eccpos[64];
uint32_t oobavail;
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
};
这是用来定义ECC在oob中布局的一个结构体。
static struct nand_ecclayout s3c_nand_oob_mlc_128_8bit = {
.eccbytes = 104,
.eccpos = {
24,25,26,27,28,29,30,31,32,33,
34,35,36,37,38,39,40,41,42,43,
44,45,46,47,48,49,50,51,52,53,
54,55,56,57,58,59,60,61,62,63,
64,65,66,67,68,69,70,71,72,73,
74,75,76,77,78,79,80,81,82,83,
84,85,86,87,88,89,90,91,92,93,
94,95,96,97,98,99,100,101,102,103,
104,105,106,107,108,109,110,111,112,113,
114,115,116,117,118,119,120,121,122,123,
124,125,126,127},
.oobfree = {
{.offset = 2,
.length = 20}}
};
前面已经提及过,oob中主要存储两种信息:坏块信息和ECC数据。对与small page的NAND芯片来说,其中坏块信息占据1个字节(一般固定在第六个字节),ECC数据占据三个字节。所以sturct nand_ecclayout这个结构体,也就是用来告诉那些与ECC操作无关的函数,Nand芯片的oob部分中,哪些字节是用来存储ECC的(即不可用作它用的),哪些字节是空闲的,即可用的。
其实之所以有这个结构体,主要是因为硬件ECC的缘故。以写数据为例,在使用硬件ECC的情况下,那三个字节的ECC数据是由硬件计算得到,并且写到NAND芯片的oob中去的,同时也是由硬件决定写到oob的哪三个字节中去。这些都是由硬件做的,而NAND驱动并不知道,所以就需要用这个结构体来告诉驱动了。
所以,在写NAND驱动时,就有可能需要对这个结构体进行赋值。这里说“有可能”,是因为MTD对这个结构体有一个默认的赋值,假如这个赋值所定义的ECC位置与你的硬件一致的话,那就不必在你的驱动中手动赋值了。其实对大多数硬件(这里所说的硬件,不是指NAND芯片,而是NAND控制器)来说,是不必手动赋值的,但也有许多例外。
值得一提的是,这个结构体不仅仅用来定义ECC布局,也可以用来将你的驱动在oob中需要额外用到的字节位置保护起来。
现在对struct nand_ecclayout 这个结构体进行一下说明:
uint32_t eccbytes:ECC的字节数,对于512B-per-page的NAND来说,eccbytes = 3,如果你需要额外用到oob中的数据,那么也可以大于3.
uint32_t eccpos[64]:ECC数据在oob中的位置,这里之所以是个64字节的数组,是因为对于2048-per-page的NAND来说,它的oob有64个字节。而对于512B-per-page的NAND来说,可以而且只可以定义它的前16个字节。
uint32_t oobavail:oob中可用的字节数,这个值不用赋值,MTD会根据其它三个变量自动计算得到。
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]:显示定义空闲的oob字节。
=====================================================================
所以定义一个nand_ecclayout结构体,于是在内核源码中搜索“nand_ecclayout”
找到drivers/mtd/nand/s3c_nand.c:
#if 0
// samsung K9GAG08U0D MLC nand flash oob size =218 Byte
static struct nand_ecclayout s3c_nand_oob_mlc_218_8bit = {
.eccbytes = 104,
.eccpos = {
114,115,116,117,118,119,120,121,122,123,
124,125,126,127,128,129,130,131,132,133,
134,135,136,137,138,139,140,141,142,143,
144,145,146,147,148,149,150,151,152,153,
154,155,156,157,158,159,160,161,162,163,
164,165,166,167,168,169,170,171,172,173,
174,175,176,177,178,179,180,181,182,183,
184,185,186,187,188,189,190,191,192,193,
194,195,196,197,198,199,200,201,202,203,
204,205,206,207,208,209,210,211,212,213,
214,215,216,217 },
.oobfree = {
{.offset = 2,
.length = 110}}
};
#endif
这个nand flash型号正是我板子用的型号,在内核中中断代码竟然被屏蔽了,而且在源码中报错点处:
if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH))
如果chip->ecc.layout没有定义内核会设置一个默认值,但是源码中:
if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) {
switch (mtd->oobsize) {
case 8:
chip->ecc.layout = &nand_oob_8;
break;
case 16:
chip->ecc.layout = &nand_oob_16;
break;
case 64:
chip->ecc.layout = &nand_oob_64;
break;
case 128:
chip->ecc.layout = &nand_oob_128;
break;
default:
printk(KERN_WARNING "No oob scheme defined for "
"oobsize %d\n", mtd->oobsize);
BUG();
}
}
设置默认值的时候oob最大只支持128B,但是我用的nand flash是(4K + 218)Byte:
Page Read Operation
- Page Size : (4K + 218)Byte
- Random Read : 60μs(Max.)
- Serial Access : 30ns(Min.)
即OOB为218B,所以内核根本没有设置chip->ecc.layout,故报错!
所以在源码中增加s3c_nand_oob_mlc_218_8bit的定义,设置:
chip->ecc.layout = &s3c_nand_oob_mlc_218_8bit;
问题自然解决!
上一篇:OK6410之LCD驱动
下一篇:OK6410启动自动挂载nfs文件系统
推荐阅读
史海拾趣
在电子行业的初期,FCT electronic公司由一群富有远见和激情的工程师创立。他们看到了挠性电路板在未来电子产品中的巨大潜力,并致力于研发出更高效、更可靠的挠性电路板解决方案。经过数年的不懈努力,FCT electronic公司终于研发出了具有革命性意义的挠性电路板技术,这一技术为公司在行业中树立了良好的口碑,也为公司的后续发展奠定了坚实的基础。
Aplus Flash Technology Inc公司深知企业文化对于企业发展的重要性。因此,公司注重企业文化建设,积极营造积极向上、团结协作的工作氛围。公司定期举办各种团队建设活动,增强员工之间的凝聚力和归属感。同时,公司还建立了完善的激励机制和培训体系,鼓励员工不断学习和创新。这些举措使公司拥有一支高素质、高效率的团队,为公司的持续发展提供了有力保障。
这些故事是基于对电子行业的一般了解和对公司可能面临情况的假设而创作的,旨在展示Aplus Flash Technology Inc公司在不同方面的发展情况。请注意,这些故事并非基于真实事件,因此可能与公司的实际情况存在出入。如需了解Aplus Flash Technology Inc公司的真实发展情况,建议查阅相关报道或公司官方资料。
随着国内市场的饱和,BOCA公司开始将目光投向海外市场。公司首先在欧洲和北美设立了分公司,通过本地化运营和营销策略,成功打开了这些市场。随后,BOCA又陆续在亚洲、非洲等地区设立了分支机构,形成了全球化的销售网络。国际化战略的实施不仅为BOCA带来了更广阔的市场空间,也提升了公司的品牌影响力和国际竞争力。
在国内市场取得一定成绩后,FerriShield开始将目光投向国际市场。公司积极参加国际电子展,展示其先进的技术和产品。同时,FerriShield还与国际知名电子品牌建立了合作关系,为其提供定制化的电磁屏蔽解决方案。通过这些努力,FerriShield的产品逐渐打入国际市场,并赢得了良好的口碑。
随着公司规模的扩大和产品线的丰富,Ark-Les Connectors公司开始积极寻求市场拓展。公司制定了针对不同区域和行业的市场拓展策略,通过参加国际电子展会、建立销售网络、开展合作伙伴计划等方式,不断扩大品牌影响力。同时,公司还根据市场需求调整产品策略,推出定制化解决方案,满足不同客户的个性化需求。这些举措使得Ark-Les的市场占有率稳步提升,公司业绩也实现了稳步增长。
随着公司规模的扩大和产品线的丰富,Ark-Les Connectors公司开始积极寻求市场拓展。公司制定了针对不同区域和行业的市场拓展策略,通过参加国际电子展会、建立销售网络、开展合作伙伴计划等方式,不断扩大品牌影响力。同时,公司还根据市场需求调整产品策略,推出定制化解决方案,满足不同客户的个性化需求。这些举措使得Ark-Les的市场占有率稳步提升,公司业绩也实现了稳步增长。
跟大家分享下学习单片机的一要点和方法!!QQ:313807838 一、理论与实践相结合,在理解理论的基础上大量的实践这才是学习的最好办法,其他的说什么也没用。 首先对一个初学单片机的人来说,按照平时的一些教材书上的方法,开始学就给你一大堆 ...… 查看全部问答∨ |
|
哪个高手,手里有platform builder.reg文件? 这个文件是我用PB软件编译后在release文件夹下见到的,现在想要这个文件,请问哪个哥哥姐姐有这个文件,发给我好吗?QQ 397293284 急用啊····谢谢啦… 查看全部问答∨ |
|
目前产品中已经有好几个芯片有类似情况,就是上电后,eth不能连接,换个cpu后就好了,不知道是什么情况。电路如下图所示:请有经验的大虾帮忙分析分析!CPU型号是LM3S9B92-C5 [ 本帖最后由 zxq6 于 2012-4-18 12:28 编辑 ]… 查看全部问答∨ |
|
《玩转TI MSP430 Launchpad》与大家见面了! TI-EEWORLD联手打造的《玩转TI MSP430 Launchpad》与广大工程师朋友们见面了!按照传统的观念,单片机入门教材或工具书之类都应是由资深专业人士编写,而与此不同的是,本书中大量精彩内容来自于网友们的经验和知识,这些都是来自于 ...… 查看全部问答∨ |