1 Nor Flash
原理图
与Nand Flash不同,Nor Flash有地址线、数据线,能直接读取数据,但是不能直接写入数据,需要有命令才行。当进行写时,一般要解锁->命令->数据,当写完毕,要reset,退出当前模式。
Nor Flash规范:
1)jedec:用来帮助程序读取Flash的制造商ID和设备ID,通过读ID来匹配linux内核中drivers/mtd/chips/jedec_probe.c里的jedec_table[]数组,来确定norflash的各个参数(名称、容量、位宽等)。
2)cfi(common flash interface):用来帮助程序从Flash芯片中获取操作方式信息。
2 源码
内核中的nor flash,drivers/mtd/maps/physmap.c。physmap_init中注册了平台设备和驱动。physmap_flash中的资源CONFIG__xxx可在make menuconfig中进行配置。
CONFIG_MTD_PHYSMAP_BANKWIDTH:位宽
CONFIG_MTD_PHYSMAP_START:物理基地址
CONFIG_MTD_PHYSMAP_LEN:容量长度
static struct physmap_flash_data physmap_flash_data = {
.width = CONFIG_MTD_PHYSMAP_BANKWIDTH,
};
static struct resource physmap_flash_resource = {
.start = CONFIG_MTD_PHYSMAP_START,
.end = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN - 1,
.flags = IORESOURCE_MEM,
};
static struct platform_device physmap_flash = {
.name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &physmap_flash_data,
},
.num_resources = 1,
.resource = &physmap_flash_resource,
};
static int __init physmap_init(void)
{
int err;
err = platform_driver_register(&physmap_flash_driver);
#ifdef CONFIG_MTD_PHYSMAP_COMPAT
if (err == 0)
platform_device_register(&physmap_flash);
#endif
return err;
}
physmap_flash_probe
static int physmap_flash_probe(struct platform_device *dev)
{
...
//分配结构体
info = devm_kzalloc(&dev->dev, sizeof(struct physmap_flash_info),
GFP_KERNEL);
...
for (i = 0; i < dev->num_resources; i++) {
...
//填充map_info
info->map[i].name = dev_name(&dev->dev);
info->map[i].phys = dev->resource[i].start;
info->map[i].size = dev->resource[i].end - dev->resource[i].start + 1;
info->map[i].bankwidth = physmap_data->width;
info->map[i].set_vpp = physmap_data->set_vpp;
info->map[i].pfow_base = physmap_data->pfow_base;
info->map[i].virt = devm_ioremap(&dev->dev, info->map[i].phys,
info->map[i].size);
...
simple_map_init(&info->map[i]);
probe_type = rom_probe_types;
for (; info->mtd[i] == NULL && *probe_type != NULL; probe_type++)
info->mtd[i] = do_map_probe(*probe_type, &info->map[i]); //通过do_map_probe ()来识别芯片
...
info->mtd[i]->owner = THIS_MODULE;
info->mtd[i]->dev.parent = &dev->dev;
}
...
add_mtd_device(info->cmtd); //添加设备
return 0;
err_out:
physmap_flash_remove(dev);
return err;
}
do_map_probe根据传入的name,调用cfi_probe_chip或者jedec_probe_chip。
3 程序
#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 <linux/mtd/physmap.h>
#include <linux/mtd/concat.h>
#include <linux/io.h>
static struct map_info *s3c_nor_map;
static struct mtd_info *s3c_nor_mtd;
static struct mtd_partition s3c_nor_parts[] = {
[0] = {
.name = "bootloader_nor",
.size = 0x00040000,
.offset = 0,
},
[1] = {
.name = "root_nor",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
}
};
static int s3c_nor_init(void)
{
/* 1. 分配map_info结构体 */
s3c_nor_map = kzalloc(sizeof(struct map_info), GFP_KERNEL);
/* 2. 设置: 物理基地址(phys), 大小(size), 位宽(bankwidth), 虚拟基地址(virt) */
s3c_nor_map->name = "s3c_nor";
s3c_nor_map->phys = 0;
s3c_nor_map->size = 0x1000000; /* >= NOR的真正大小 */
s3c_nor_map->bankwidth = 2;
s3c_nor_map->virt = ioremap(s3c_nor_map->phys, s3c_nor_map->size);
simple_map_init(s3c_nor_map);
/* 3. 使用: 调用NOR FLASH协议层提供的函数来识别 */
s3c_nor_mtd = do_map_probe("cfi_probe", s3c_nor_map);
if (!s3c_nor_mtd)
{
printk("use jedec_probe\n");
s3c_nor_mtd = do_map_probe("jedec_probe", s3c_nor_map);
}
if (!s3c_nor_mtd)
{
iounmap(s3c_nor_map->virt);
kfree(s3c_nor_map);
return -EIO;
}
/* 4. add_mtd_partitions */
add_mtd_partitions(s3c_nor_mtd, s3c_nor_parts, 2);
return 0;
}
static void s3c_nor_exit(void)
{
del_mtd_partitions(s3c_nor_mtd);
iounmap(s3c_nor_map->virt);
kfree(s3c_nor_map);
}
module_init(s3c_nor_init);
module_exit(s3c_nor_exit);
MODULE_LICENSE("GPL");
4 测试
(1)测试1:通过配置内核支持NOR FLASH
1)内核配置
在上次nand flash配置的基础上,
Device Drivers --->
Memory Technology Device (MTD) support --->
RAM/ROM/Flash chip drivers --->
-> Device Drivers
-> Memory Technology Device (MTD) support
-> Mapping drivers for chip access
<M> CFI Flash device in physical memory map
(0x0) Physical start address of flash mapping // 物理基地址
(0x1000000) Physical length of flash mapping // 长度
(2) Bank width in octets (NEW) // 位宽
2)make modules
cp drivers/mtd/maps/physmap.ko /work/nfs_root/first_fs
3)启动开发板
ls /dev/mtd*
insmod physmap.ko
ls /dev/mtd*
cat /proc/mtd
(2)测试2: 使用自己写的驱动程序
ls /dev/mtd*
insmod s3c_nor.ko
ls /dev/mtd*
#格式化: 使用mtd-util工具的flash_eraseal命令来擦除root分区(mtd1)
flash_eraseall -j /dev/mtd1
mount -t jffs2 /dev/mtdblock1 /mnt
#在/mnt目录下操作文件