本文的主要任务是实现JZ2440开发板板载的MX29LV800BBTC这款NOR FLASH驱动。
一、MX29LV800BBTC的简单介绍
这是一块容量为2MB,位宽为16位的NOR FLASH存储芯片,它可以像内存一样直接进行访问,但是不能像内存一样直接写入,它支持XIP。它的原理图如下所示:
它的引脚定义如下:
LDATA0~LDATA15:数据引脚
LADDR1~LADDR20:地址引脚
LnOE:读使能引脚
LnWE:写使能引脚
nGCS0:片选引脚
二、驱动程序编写
驱动基于Linux-3.4.10内核编写。
1、一般实现步骤
a、分配一个map_info结构体变量
b、设置这个结构体变量
c、使用:do_map_probe()
d、添加分区
2、驱动程序编写
2.1 前期准备工作,为了方便整个驱动程序的编写,定义了全局结构体,并定义了一个该结构体的全局变量,具体实现如下:
/* 构造一个方便编写驱动程序的结构体 */
struct yl_nor_mtd{
struct map_info *map_info; // 定义map_info结构体的指针变量
struct mtd_info *mtd_info; // 定义mtd_info结构体的指针变量
};
/* 定义一个yl_nor_mtd结构体的全局变量 */
static struct yl_nor_mtd nor_mtd; 2.2 分配一个map_info结构体的指针变量
/* 1、分配一个map_info结构体变量 */
nor_mtd.map_info = kzalloc(sizeof(struct map_info), GFP_KERNEL);2.3 设置这个结构体变量
/* 2、设置 */
nor_mtd.map_info->name = "yl_nor_flash"; // 名字
nor_mtd.map_info->phys = 0; // 物理基地址
nor_mtd.map_info->size = 0x200000; // 尺寸,>=真实大小
nor_mtd.map_info->bankwidth = 2; // 位宽
/* 设置虚拟地址的基地址 */
nor_mtd.map_info->virt = ioremap(nor_mtd.map_info->phys, nor_mtd.map_info->size);
if (nor_mtd.map_info->virt == NULL)
{
printk("Failed to ioremap flash region\n");
ret = -EIO;
goto out2;
}
/* 其他的nor flash的通用的初始化 */
simple_map_init(nor_mtd.map_info); 2.4 使用这个结构体变量,获得一个mtd_info结构体变量的实例
/* 3、使用 */
nor_mtd.mtd_info = do_map_probe("cfi_probe", nor_mtd.map_info);
if(nor_mtd.mtd_info == NULL)
{
printk("do_map_probe for cfi_probe failure!\n");
ret = -ENXIO;
goto out3;
} 2.5 添加分区
/* 4、添加分区 */
ret = mtd_device_parse_register(nor_mtd.mtd_info, NULL, NULL,
yl_s3c_nor_partitions, ARRAY_SIZE(yl_s3c_nor_partitions)); 添加分区需要有一个分区表作为分区依据,分区表的实现如下所示:
/* 定义nor flash的分区表 */
static struct mtd_partition yl_s3c_nor_partitions[] =
{
[0] = {
.name = "bootloader_nor",
.size = SZ_256K,
.offset = 0,
},
[1] = {
.name = "params_nor",
.offset = MTDPART_OFS_APPEND,
.size = SZ_128K,
},
[2] = {
.name = "rootfs_nor",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
}
};
#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/concat.h>
#include <linux/io.h>
/* 构造一个方便编写驱动程序的结构体 */
struct yl_nor_mtd{
struct map_info *map_info; // 定义map_info结构体的指针变量
struct mtd_info *mtd_info; // 定义mtd_info结构体的指针变量
};
/* 定义一个yl_nor_mtd结构体的全局变量 */
static struct yl_nor_mtd nor_mtd;
/* 定义nor flash的分区表 */
static struct mtd_partition yl_s3c_nor_partitions[] =
{
[0] = {
.name = "bootloader_nor",
.size = SZ_256K,
.offset = 0,
},
[1] = {
.name = "params_nor",
.offset = MTDPART_OFS_APPEND,
.size = SZ_128K,
},
[2] = {
.name = "rootfs_nor",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
}
};
/* 模块的入口函数 */
static int __init yl_s3c_nor_init(void)
{
int ret = 0;
/* 1、分配一个map_info结构体变量 */
nor_mtd.map_info = kzalloc(sizeof(struct map_info), GFP_KERNEL);
if (!nor_mtd.map_info) {
printk("kzalloc for map_info error!\n");
ret = -ENOMEM;
goto out1;
}
/* 2、设置 */
nor_mtd.map_info->name = "yl_nor_flash"; // 名字
nor_mtd.map_info->phys = 0; // 物理基地址
nor_mtd.map_info->size = 0x200000; // 尺寸,>=真实大小
nor_mtd.map_info->bankwidth = 2; // 位宽
/* 设置虚拟地址的基地址 */
nor_mtd.map_info->virt = ioremap(nor_mtd.map_info->phys, nor_mtd.map_info->size);
if (nor_mtd.map_info->virt == NULL)
{
printk("Failed to ioremap flash region\n");
ret = -EIO;
goto out2;
}
/* 其他的nor flash的通用的初始化 */
simple_map_init(nor_mtd.map_info);
/* 3、使用 */
nor_mtd.mtd_info = do_map_probe("cfi_probe", nor_mtd.map_info);
if(nor_mtd.mtd_info == NULL)
{
printk("do_map_probe for cfi_probe failure!\n");
ret = -ENXIO;
goto out3;
}
/* 4、添加分区 */
ret = mtd_device_parse_register(nor_mtd.mtd_info, NULL, NULL,
yl_s3c_nor_partitions, ARRAY_SIZE(yl_s3c_nor_partitions));
if(ret) // 失败
{
printk("mtd_device_parse_register error!\n");
ret = -ENODEV;
goto out3;
}
else // 成功
{
return 0;
}
out3:
iounmap(nor_mtd.map_info->virt);
out2:
kfree(nor_mtd.map_info);
out1:
return ret;
}
/* 模块的出口函数 */
static void __exit yl_s3c_nor_exit(void)
{
/* 进行出口的一些操作,释放资源,解除绑定,取消注册 */
mtd_device_unregister(nor_mtd.mtd_info);
iounmap(nor_mtd.map_info->virt);
kfree(nor_mtd.map_info);
}
module_init(yl_s3c_nor_init);
module_exit(yl_s3c_nor_exit);
MODULE_LICENSE("GPL");
3、编译驱动程序并把模块加载进内核,结果如下所示:
本文详细介绍了如何在Linux-3.4.10内核下为JZ2440开发板上的MX29LV800BBTC NOR FLASH编写驱动程序。首先,对MX29LV800BBTC的基本特性和引脚定义进行了说明。接着,概述了驱动程序的一般实现步骤,包括分配map_info结构体、设置结构体参数、调用do_map_probe()函数以及添加分区。最后,展示了驱动程序的前期准备工作,定义了全局结构体和变量。

1510

被折叠的 条评论
为什么被折叠?



