Linux驱动开发笔记:NOR FLASH编写实例

Linux驱动开发笔记:NOR FLASH编写实例,第1张

1、 背景介绍

板子上的zynq通过emc外接一块nor flash,地址分配如下:

Linux驱动开发笔记:NOR FLASH编写实例,第2张

Nor flash的起始地址为0x80000000。当zynq上运行Linux后可以通过对该地址起始的区域进行擦除、读写 *** 作从而对NOR FLASH进行 *** 作。具体参看前一篇博客点击打开链接

不过,这种实现方式虽然简单,但对用户来说使用不方便,没有用户会自己计算需要擦除多少扇区或读写多少扇区的。基于这点考虑,在nor flash上面挂载文件系统就显得格外重要。

2、 MTD介绍

linux中挂载文件系统需要借助MTD系统,结构图如下:

Linux驱动开发笔记:NOR FLASH编写实例,第3张

具体每层的含义以及每层之间是如何交互的可以参看宋宝华的《Linux驱动开发详解》这本书。

对于NOR FLASH来说,MTD往下的层次结构如下:

Linux驱动开发笔记:NOR FLASH编写实例,第4张

上图中提到了需要使用CFI JFDEC等驱动,这些驱动已经实现了大多数常见的NOR FLASH *** 作,驱动开发人员完全不需要实现最底层的FLASH *** 作序列。

为了使用这些驱动,加载NOR FLASH时需要进行下面 *** 作:

Linux驱动开发笔记:NOR FLASH编写实例,第5张

根据板子上的NOR FLASH编写对应的代码,代码中需要做的事情不多。

(1) 定义 map_info 的实例,初始化其中的成员,根据目标板的情况为 name、size、bankwidth 和 phys 赋值。

(2) 如果 Flash 要分区,则定义 mtd_parTITIon 数组,将实际电路板中 Flash 分区信息记录于其中。

(3) 以 map_info 和探测的接口类型(如"cfi_probe"、"jedec_probe"等)为参数调用do_map_ probe(),探测Flash 得到mtd_info。do_map_probe()会根据传入的参数 name 通过 get_mtd_chip_driver()得到具体的MTD驱动,调用与接口对应的 probe()函数探测设备,利用 map_info 中的配置,do_map_probe()可以自动识别支持 CFI 或 JEDEC(电子元件工业联合会)接口的 Flash 芯片,MTD以后会自动采用适当的命令参数对 Flash进行读写或擦除。

(4) 在模块初始化时以 mtd_info 为参数调用 add_mtd_device()或以mtd_info、mtd_parTITIon数组及分区数为参数调用 add_mtd_partitions()注册设备或分区。当然,在这之前可以调用 parse_mtd_partitions()查看Flash 上是否已有分区信息,并将查看出的分区信息通过 add_mtd_partitions()注册。

最后将代码编译到内核中即可。

3、 代码实现
下面是根据板子的具体配置编写的NOR FLASH驱动代码,其实也就是执行上面的几个 *** 作,配置一下相关的信息。
#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include
#include

#include

#include

#include "mtdcore.h"

#define WINDOW_ADDR 0x80000000
#define WINDOW_SIZE 0x8000000
#define BUSWIDTH 2

#define PROBETYPES { "cfi_probe", NULL }

#define MSG_PREFIX "S3C2410-NOR:"
#define MTDID "s3c2410-nor"
#define CONFIG_MTD_PARTITIONS

static struct mtd_info *mymtd;

struct map_info s3c2410nor_map = // map_info
{
.name = "NOR Flash on S3C2410",
.size = WINDOW_SIZE,
.bankwidth = BUSWIDTH,
.phys = WINDOW_ADDR,
};

#ifdef CONFIG_MTD_PARTITIONS

static struct mtd_partition static_partitions[] =
{
{
.name = "test1", .size = 0x200000, .offset = 0x020000
} ,
{
.name = "test2", .size = 0x400000, .offset = 0x200000
} ,
};
#endif

static int mtd_parts_nb = 0;
static struct mtd_partition *mtd_parts = 0;

int __init init_s3c2410nor(void)
{
static const char *rom_probe_types[] = PROBETYPES;
const char **type;
const char *part_type = 0;

printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", WINDOW_SIZE,WINDOW_ADDR);
s3c2410nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
if (!s3c2410nor_map.virt)
{
printk(MSG_PREFIX "failed to ioremap\n");
return - EIO;
}
simple_map_init(&s3c2410nor_map);
mymtd = 0;
type = rom_probe_types;
for (; !mymtd && *type; type++)
{
mymtd = do_map_probe(*type, &s3c2410nor_map);
}
if (mymtd)
{
mymtd->owner = THIS_MODULE;
#ifdef CONFIG_MTD_PARTITIONS

if (mtd_parts_nb == 0) //using default partitions
{
mtd_parts = static_partitions;
mtd_parts_nb = ARRAY_SIZE(static_partitions);
part_type = "static";
}

#endif

add_mtd_device(mymtd);
printk("mtd parts is %d\n",mtd_parts_nb);

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/dianzi/2716938.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-08-17
下一篇 2022-08-17

发表评论

登录后才能评论

评论列表(0条)

保存