一:nor flash原理及硬件
1.NOR 的接口与内存的接口是一样的,而 NAND(数据线只有 7 条,发地址又发命令和数据等)。
NOR 可以像内存一样的来读,但不能像内存一样的去写。
NOR 的烧写要发出某些特定的命令,在某地址上写某个值就称为命令
2.NOR 存放关键性的代码,如 bootload\内核或文件系统。而 NADN 有位反转的缺点,如存一些海量数据如视频监控文件等
3.用 NOR 启动时,CPU 看到的“0”地址是“NOR”FLASH。
若为 NAND 启动,则 CPU 看到的“0”地址是 2440 片的 4K 内存。
用 NAND 启动时 CPU 完全看不到 NOR,只有用 NOR 启动时,CPU 看到的“0”地址才是 NOR。
代码可以直接在 NOR 上运行,在 NAND 上不行。CPU 可以直接从 NOR 上取到指令来运行。而用 NAND 启动,2440 是有将 NAND 的前 4K 数据自动拷贝到 2440 的 4K 片内内存里,这时 CPU再从片内 4K 内存中取指令运行
4.NOR有两种规范, jedec, cfi(common flash interface)
jedec
就是和nandflash的一样,通过读ID来匹配linux内核中drivers/mtd/chips/jedec_probe.c里的jedec_table[]数组,来确定norflash的各个参数(名称、容量、位宽等),如下图所示:
cfi
就是将这些参数保存在cfi模式下指定地址中, 往nor的0x55地址写入0x98,即可进入cfi模式,
当我们在cfi模式下,比如:读取nor地址0x27处的数据,便能读到nor的容量
二:驱动编写
所以注册一个块设备驱动,需要以下步骤:
- 分配mtd_info结构体和map_info结构体
- 设置map_info 结构体
物理基地址(phys), 大小(size), 位宽(bankwidth), 虚拟基地址(virt) 。
内核看到不同开发板 NOR 的最小差别 - 设置mtd_info 结构体
- 使用add_mtd_partitions()或者add_mtd_device()来创建MTD字符/块 设备
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
static struct mtd_info *mynor_mtd_info;
static struct map_info *mynor_map_info;
static struct mtd_partition mynor_partitions[] = {
[0] = {
.name = "bootloader",
.size = 0x00040000,
.offset = 0,
},
[1] = {
.name = "root",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
}
};
static const char *mynor_probe_types[] = { "cfi_probe", "jedec_probe",NULL};
static int mynor_init(void)
{
int val;
/*1. 分配map_info 结构体和mtd_info结构体*/
mynor_mtd_info=kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
mynor_map_info=kzalloc(sizeof(struct map_info), GFP_KERNEL);
/*2. 设置map_info 结构体*/
mynor_map_info->name="my_nor";
mynor_map_info->phys=0x0; //物理地址
mynor_map_info->size=0x1000000; //=16M,长度必须大于等于norflash的2M容量
mynor_map_info->bankwidth=2; //16位宽
mynor_map_info->virt = ioremap(0x0, mynor_map_info->size); //虚拟地址
simple_map_init(mynor_map_info);
/*3. 设置mtd_info 结构体*/
mynor_mtd_info = do_map_probe("cfi_probe", mynor_map_info);
if (!mynor_mtd_info)
{
mynor_mtd_info = do_map_probe("jedec_probe", mynor_map_info);
}
if (!mynor_mtd_info)
{
printk("not available norflash !!!\r\n");
goto err_out;
}
mynor_mtd_info->owner=THIS_MODULE;
/*4. 使用add_mtd_partitions()或者add_mtd_device()来创建MTD字符/块 设备*/
add_mtd_partitions(mynor_mtd_info,mynor_partitions,2);
return 0;
err_out:
iounmap(mynor_map_info->virt); //取消虚拟地址映射
kfree(mynor_map_info);
kfree(mynor_mtd_info);
return 0;
}
static void mynor_exit(void)
{
del_mtd_partitions(mynor_mtd_info); //卸载分区
iounmap(mynor_map_info->virt); //取消虚拟地址映射
kfree(mynor_map_info);
kfree(mynor_mtd_info);
}
module_init(mynor_init);
module_exit(mynor_exit);
MODULE_LICENSE("GPL");
三,nor 驱动实验
(一定要在nor启动下挂载才行,因为2440使用nand启动时,是访问不了nor的前4k地址)
1.重新编译内核(去掉默认nor flash驱动)
2.insmod 挂载驱动
3. 接下来便来对root分区(mtd1)来试验(使用flash之前最好擦除一次)
./flash_eraseall -j /dev/mtd1 //使用mtd-util工具的flash_eraseal命令来擦除root分区(mtd1)
mount -t jffs2 /dev/mtdblock1 /mnt/ //使用mount挂载文件系统, -t:文件系统类型(type)
接下来就可以在/mnt目录下来任意读写文件了,最终会保存在flash的mtdblock1块设备中
**2.**利用内核自带的 NORFLASH 底层驱动程序
Physmap.c”做测试:
内核里有这一个底层的 NORFLASH 驱动程序,这时可以直接拿来做实验:
测试 1:通过配置内核支持 NOR FLASH
1. make menuconfig
-> Device Drivers
-> Memory Technology Device (MTD) support //内存技术设备支持
-> Mapping drivers for chip access
<M> CFI Flash device in physical memory map //M作为模块
(0x0) Physical start address of flash mapping // 物理基地址 写为0
(0x1000000) Physical length of flash mapping // 长度 这里写大些为16M,此长度要大于等于
NORFLASH的真实长度即可。因为它要ioremap。设置长度的意思是让它ioremap映射得到虚拟地址。
(2) Bank width in octets (NEW) // 位宽 16,单位是 octets(8
的意思).故设为 2
- make modules(不需 make uImage)得到“physmap.ko”。
- cp drivers/mtd/maps/physmap.ko /work/nfs_root/first_fs
- 启动开发板
ls /dev/mtd*
insmod physmap.ko