内核:linux-2.6.37.3
nor flash芯片:SST39VF6401B
网上有文章说了如何让linux内核支持nor flash。不过那些转载的文章中没有头文件(因为使用了<尖括号>,在一些网页中是不会显示的,详细请参考HTML相关资料)。后来研究了类似的驱动文件,发现它们都是大同小异,只是在一些参数上有改变而已。本文中源代码基于那些转载文章的代码。
MTD设备驱动程序在./driver/mtd下面,分为nor flash和nand flash两种。在chips中定义了几种访问nor的接口,包括cfi、jedec、map_ram和map_rom,而实际芯片所要添加的“驱动程序”放到maps目录下(比如本文使用的s3c2440-flash.c文件,详见文章后面)。从map这个单词来看,它描述的是一些映射信息,当然也包括了芯片信息,如总大小、块总数、访问接口等等。
这个过程其实是在内核代码树中添加自己的驱动的过程,当然是一些“标准”步骤了:在对应的代码树目录下,添加驱动源代码文件、在Makefile添加内容、在Kconfig添加内容,当然,还需要在make menuconfig里配置。
1、./driver/mtd/maps/Makefile
在这个Makefile最后添加:
obj-$(CONFIG_MTD_S3C2440) += s3c2440-flash.o
这个CONFIG_MTD_S3C2440由内核配置所得。
2、./driver/mtd/maps/Kconfig
在这个Kconfig文件最后添加(但在endmenu之前):
config MTD_S3C2440
tristate "CFI Flash device mapped on S3C2440"
depends on ARM && MTD_CFI
help
This enables access to the CFI Flash on the SMDK2440 board.
If you have such a board, say 'Y' here.
这里的MTD_S3C2440就是前面Makefile中的那个,注意,CONFIG_前缀是内核自己添加的。可以在编译内核后生成的autoconf.h文件中查看该宏定义。
3、内核配置
在Device Drivers ---> <*> Memory Technology Device (MTD) support ---> 下面:
Mapping drivers for chip access --->
<*> CFI Flash device mapped on S3C2440
RAM /ROM/Flash chip drivers --->
<*> Detect flash chips by Common Flash Interface (CFI) probe
[*] Flash chip driver advanced configuration options
[*] Specific CFI Flash geometry selection
[*] Support 16-bit buswidth
[*] Support 1-chip flash interleave
4、./driver/mtd/maps/s3c2440-flash.c
代码见文章后面。
这个文件主要是修改前面的几个宏定义。我特地添加一些调试语句。开始时我使用2.6.30.2内核,驱动中使用cfi_probe接口,但是没有显示分区信息,后来我添加多几个接口才发现它是使用map_rom。这个过程花费了一些时间。
在2.6.30.2内核中,启动信息如下:
S3C2440-NOR:0x00800000 at 0x01000000
S3C2440-NOR:func:init_s3c2440nor [120] mymtd:0 type:cfi_probe
S3C2440-NOR:func:init_s3c2440nor [120] mymtd:0 type:jedec_probe
S3C2440-NOR:func:init_s3c2440nor [120] mymtd:c39cb600 type:map_rom
S3C2440-NOR:using static partition definition
Creating 4 MTD partitions on "NOR Flash(SST39VF6401B) on S3C2440":
0x000000000000-0x000000030000 : "U-Boot"
0x000000030000-0x000000240000 : "Kernel"
0x000000240000-0x0000007f0000 : "RootFS(jffs2)"
0x0000007f0000-0x000000800000 : "Parameter"
可以看到,的确是使用map_rom接口。但是,当我使用2.6.37.2时,发现它使用的是cfi_probe接口,启动信息如下:
S3C2440-NOR:0x00800000 at 0x01000000
NOR Flash(SST39VF6401B) on S3C2440: Found 1 x16 devices at 0x0 in 16-bit bank.
Manufacturer ID 0x0000bf Chip ID 0x00236d
number of CFI chips: 1
## LL debug S3C2440-NOR:func:init_s3c2440nor[121] mymtd:c3a19200 type:cfi_probe
mtd: Giving out device 0 to NOR Flash(SST39VF6401B) on S3C2440
S3C2440-NOR:using static partition definition
Creating 4 MTD partitions on "NOR Flash(SST39VF6401B) on S3C2440":
0x000000000000-0x000000030000 : "U-Boot"
mtd: Giving out device 1 to U-Boot
0x000000030000-0x000000240000 : "Kernel"
mtd: Giving out device 2 to Kernel
0x000000240000-0x0000007f0000 : "Rootfs(jffs2)"
mtd: Giving out device 3 to Rootfs(jffs2)
0x0000007f0000-0x000000800000 : "Parameter"
mtd: Giving out device 4 to Parameter
与前面不同的是,它打印了芯片的信息,如厂商ID、芯片ID等等。
这是我想不通的地方,也是我采用新内核的原因。
不过,在这片nor flash上使用jffs2文件系统却不成功,出现了大量的警告信息,提示说制作根文件系统时的erase block有问题。
s3c2440-flash.c源代码:
/*
* $Id: s3c2410.c,v 1.00 2006/12/05 10:18:14 gleixner Exp $
*
* Handle mapping of the NOR flash on Cogent S3C2410 boards
*
* Copyright 2002 SYSGO Real-Time Solutions GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* Late Lee
* This file is modified and the file name has changed to 's3c2440-flash.c'.
* The SMDK2440 board has only one flash bank which is a 64Mbit(4Mx16) SST SST39VF6401B;
* 128 x 64 KiB blocks.
*
* This code is GPLed.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
#ifdef CONFIG_MTD_PARTITIONS
#include <linux/mtd/partitions.h>
#endif
#define WINDOW_ADDR 0x01000000 /* physical properties of flash */
#define WINDOW_SIZE 0x800000 /* 8MB */
#define BUSWIDTH 2 /* 2*8 = 16 */
#define FLASH_BLOCKSIZE_MAIN 0x10000 /* 64KB(0x10000) 128 blocks */
#define FLASH_NUMBLOCKS_MAIN 128
/* can be "cfi_probe", "jedec_probe", "map_rom", NULL }; */
#define PROBETYPES { "cfi_probe", "jedec_probe", "map_rom", NULL }
#define MSG_PREFIX "S3C2440-NOR:" /* prefix for our printk()'s */
#define MTDID "s3c2440-nor" /* for mtdparts= partitioning */
#define DEBUG_FLASH
#ifdef DEBUG_FLASH
#define flash_debug(fmt, args...) printk(KERN_NOTICE "## LL debug " MSG_PREFIX fmt, ##args)
#else
#define flash_debug(fmt, args...)
#endif
static struct mtd_info *mymtd;
struct map_info s3c2440nor_map = {
.name = "NOR Flash(SST39VF6401B) on S3C2440",
.size = WINDOW_SIZE,
.bankwidth = BUSWIDTH,
.phys = WINDOW_ADDR,
};
#ifdef CONFIG_MTD_PARTITIONS
/*
* MTD partitioning stuff
*/
static struct mtd_partition static_partitions[] = {
/*0: U-Boot: 0-0x30000 0x30000=192KB*/
{
.name = "U-Boot",
.size = 0x030000,
.offset = 0x0,
},
/*1: Kernel: 0x30000-0x240000 0x210000=2112KB=2.0625MB*/
{
.name = "Kernel",
.size = 0x210000,
.offset = 0x30000,
},
/*2: Rootfs(jffs2): 0x240000-0x7f0000 0x5b0000=5824KB=5.6875MB*/
{
.name = "Rootfs(jffs2)",
.size = 0x5b0000,
.offset = 0x240000,
},
/*3: U-Boot Parameters: 0x7f0000-0x800000 0x10000=64KB*/
{.name = "Parameter",
.size = 0x010000,
.offset = 0x7f0000,
},
};
//static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
static const char *probes[] = { NULL };
#endif
static int mtd_parts_nb = 0;
static struct mtd_partition *mtd_parts = 0;
int __init init_s3c2440nor( 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);
s3c2440nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
if (!s3c2440nor_map.virt) {
printk(MSG_PREFIX "failed to ioremap/n");
return -EIO;
}
simple_map_init(&s3c2440nor_map);
mymtd = 0;
type = rom_probe_types;
for(; !mymtd && *type; type++) {
mymtd = do_map_probe(*type, &s3c2440nor_map);
flash_debug( "func:%s[%d] mymtd:%x type:%s/n", __func__, __LINE__, mymtd, *type);
}
if (mymtd) {
mymtd->owner = THIS_MODULE;
#ifdef CONFIG_MTD_PARTITIONS
mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, MTDID);
if (mtd_parts_nb > 0)
part_type = "detected";
if (mtd_parts_nb == 0){
mtd_parts = static_partitions;
mtd_parts_nb = ARRAY_SIZE(static_partitions);
part_type = "static";
}
#endif
add_mtd_device(mymtd);
if (mtd_parts_nb == 0)
printk(KERN_NOTICE MSG_PREFIX "no partition info available/n");
else{
printk(KERN_NOTICE MSG_PREFIX
"using %s partition definition/n", part_type);
add_mtd_partitions(mymtd, mtd_parts, mtd_parts_nb);
}
return 0;
}
iounmap(( void *)s3c2440nor_map.virt);
return -ENXIO;
}
static void __exit cleanup_s3c2440nor( void)
{
if (mymtd) {
del_mtd_device(mymtd);
map_destroy(mymtd);
}
if (s3c2440nor_map.virt) {
iounmap(( void *)s3c2440nor_map.virt);
s3c2440nor_map.virt = 0;
}
}
module_init(init_s3c2440nor);
module_exit(cleanup_s3c2440nor);
MODULE_LICENSE( "GPL");
MODULE_AUTHOR( "GengYaoJun ");
MODULE_DESCRIPTION( "Generic configurable MTD map driver");
致歉:
文中关于头文件在网页不显示的问题观点错误,现已修正,但是本文被许多网站转载而不注明出处,错误依旧却又无能为力,在此表示歉意。大家看到不是原文的,可不要找山人啊!
木草山人于3.16