/* 参考
* 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,
}
};
static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr)
{
if (chipnr == -1)
{
s3c_nand_regs->nfcont |= (1<<1);
}
else
{
s3c_nand_regs->nfcont &= ~(1<<1);
}
}
static void s3c2440_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
if (ctrl & NAND_CLE)
{
s3c_nand_regs->nfcmd = dat;
}
else
{
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;
s3c_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
s3c_nand_regs = ioremap(0x4E000000, sizeof(struct s3c_nand_regs));
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;
clk = clk_get(NULL, "nand");
clk_enable(clk); /* CLKCON'bit[4] */
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
s3c_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
s3c_nand_regs->nfcont = (1<<1) | (1<<0);
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 */
/* add_mtd_partitions */
add_mtd_partitions(s3c_mtd, s3c_nand_parts, 4);
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");
分析:
add_mtd_partitions这个函数用于添加分区,它需要3个参数:第一个参数是mtd_info 结构体,我们已经有了。第二个参数上hi分区表,我们在上面蓝色部分定义了。第三个是分区表里面分区的个数,我们在分区表里面有4个分区,所有它是4。接下来我们看分区表:
第一个分区是:bootloader分区,它从0偏移地址开始,大小是:0x00040000
第二个分区是:params分区,MTDPART_OFS_APPEND表示紧随上一个分区,大小是:0x00020000
第三个分区是:kernel分区,紧随上一个分区,大小是:0x00200000
第四个分区是:root分区,紧随上一个分区,MTDPART_SIZ_FULL表示下面所有的空间都给了这个分区
接下来我们从测试中更进一步来理解:
1. make menuconfig去掉内核自带的NAND FLASH驱动
-> Device Drivers
-> Memory Technology Device (MTD) support
-> NAND Device Support
< > NAND Flash support for S3C2410/S3C2440 SoC
2. 由于上面已经去掉了对nandflash的支持,而我们原来的文件系统在nandflash上面,所有我们必须挂在网络文件系统,步骤如下:
(1)设置启动参数:
我们下看一个原来的启动参数,再来写我们自己需要的启动参数
原来的启动参数是:
bootargs=noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0
bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0
我们设置的启动参数是:
set bootargs console=ttySAC0 root=/dev/nfs nfsroot=192.168.183.128:/home/share/jz2440/fs_mini_mdev ip=192.168.183.127:192.168.183.128:192.168.183.225:255.255.255.0::eth0:off
关于参数的设置我们要清楚:
192.168.183.127:开发板ip
192.168.183.128:主机ip
192.168.183.225:开发板网关
255.255.255.0:子网掩码
(2)装载新内核,并启动
这里我遇到了问题,提示:主机没有应答,后来发现在/etc/init.d/rcS里面设置了ip地址,这个ip地址跟我们在(2)中设置的不一样,而它的优先级
要高于我们之前设置的,所以出错。
3. 加载:insmod nandflash.ko
输出如下信心:
NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)
Scanning device for bad blocks
Bad eraseblock 408 at 0x03300000
Bad eraseblock 441 at 0x03720000
Bad eraseblock 804 at 0x06480000
Bad eraseblock 1155 at 0x09060000
Bad eraseblock 1236 at 0x09a80000
Creating 4 MTD partitions on "NAND 256MiB 3,3V 8-bit":
0x00000000-0x00040000 : "bootloader"
0x00040000-0x00060000 : "params"
0x00060000-0x00260000 : "kernel"
0x00260000-0x10000000 : "root"
我们看到首先是扫描的输出信息,接下来是创建MTD分区,跟我们上节分析的相一致。
4. ls /dev/mtd* -l
输出如下信息:
# ls /dev/mtd* -l
crw-rw---- 1 0 0 90, 0 Jan 1 00:02 /dev/mtd0
crw-rw---- 1 0 0 90, 1 Jan 1 00:02 /dev/mtd0ro
crw-rw---- 1 0 0 90, 2 Jan 1 00:02 /dev/mtd1
crw-rw---- 1 0 0 90, 3 Jan 1 00:02 /dev/mtd1ro
crw-rw---- 1 0 0 90, 4 Jan 1 00:02 /dev/mtd2
crw-rw---- 1 0 0 90, 5 Jan 1 00:02 /dev/mtd2ro
crw-rw---- 1 0 0 90, 6 Jan 1 00:02 /dev/mtd3
crw-rw---- 1 0 0 90, 7 Jan 1 00:02 /dev/mtd3ro
brw-rw---- 1 0 0 31, 0 Jan 1 00:02 /dev/mtdblock0
brw-rw---- 1 0 0 31, 1 Jan 1 00:02 /dev/mtdblock1
brw-rw---- 1 0 0 31, 2 Jan 1 00:02 /dev/mtdblock2
brw-rw---- 1 0 0 31, 3 Jan 1 00:02 /dev/mtdblock3
我们看到有4个字符设备和4个块设备,这也与我们分析的相一致。
5. mount /dev/mtdblock3 /mnt
UDF-fs: No partition found (1)
yaffs: dev is 32505859 name is "mtdblock3"
yaffs: passed flags ""
yaffs: Attempting MTD mount on 31.3, "mtdblock3"
yaffs: auto selecting yaffs2
block 390 is bad
block 423 is bad
block 786 is bad
block 1137 is bad
block 1218 is bad
yaffs: dev is 32505859 name is "mtdblock3"
yaffs: passed flags ""
yaffs: Attempting MTD mount on 31.3, "mtdblock3"
block 390 is bad
block 423 is bad
block 786 is bad
block 1137 is bad
block 1218 is bad
我们将mtdblock3挂到/mnt目录下面,我们进入/mnt
cd /mnt
ls
输出如下信息:
bin include lost+found proc sys
dev lib mnt root tmp
etc linuxrc opt sbin usr
文件系统的信息都在里面!这是怎么回事儿呢?别忘了,我们的
mtdblock3
分区可是
root分区,里面放的就是根文件系统。
我们卸载:
cd ..
umount /mnt
ls /mnt
发现上面那些信息不见了。
6. 格式化
(1)准备工具:
编译工具:
tar xjf mtd-utils-05.07.23.tar.bz2
cd mtd-utils-05.07.23/util
修改Makefile:
#CROSS=arm-linux-
改为
CROSS=arm-linux-
make
cp flash_eraseall /home/share/jz2440/fs_mini_mdev/bin/ //将擦除工具拷贝到开发板的bin目录下面,当然也可以拷贝其它的工具
(2)擦除mtd3分区:flash_eraseall /dev/mtd3,擦除后这个分区里面的内容就是yaffs文件系统了。
(3)挂接:mount -t yaffs /dev/mtdblock3 /mnt
(4)接下来就可以再/mnt目录下创建文件了,创建的文件实际上是在第三分区上面。