Linux移植随笔:让内核支持nor flash

 

内核: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

你可能感兴趣的:(Linux移植随笔:让内核支持nor flash)