美学原理25.Linux-Nor Flash让(详解)

1.nor硬件介绍:

 美学原理 1

起规律图中我们会见到NOR
FLASH有地址线,有数据线,它与我们的SDRAM接口相似,能一直读取数据,但是非克像SDRAM直接写副数据,需要有指令才行

1.1中我们2440之地址线共有27干净(LADDR0~26),为什么是27根?

因2440齐产生7只bank内存块,每个bank=128MB=(2^27)B,所以共有27绝望数据线

1.2为什么Nor
Flash的地址线A0是搭在2440底LADDR1上?

因Nor
Flash的数码共有16各,也就是是每个地点保存了2B数,而我辈的2440每个地方是保存的1B数据,

比如:

当2440访问问0X00地址时,就会见读取到Nor上0地址的2B数据,然后2440底内存控制器会根据0x00来找到低8个字节,并返给CPU,

当2440拜问0x01地址时,由于2440之LADDR0线未接,所以还是看Nor的0地址上之2B数据,然后内存控制器会基于0x01来找到高8个字节,并赶回给CPU

1.3
nand和nor区别:

nor flash于价钱达成比nand贵,且容量非常小
,擦除和描写多少都磨蹭,好处在接口简单,稳定,无位反转,坏块,常用于保存要数据,而nand
flash常用于保存好容量数据

于2440着凡经过硬件开关来设置OM0为Nand启动或Nor启动,如下图所示:

 美学原理 2

OM0有血有肉参数如下所示,其中2440底OM1挑起脚默认接地

 美学原理 3

对nand启动:OM0过渡地,nand
flash的上马4KB会自动地让加载到2440放权的SRAM缓存器中,就可以直接读写

于nor启动:OM0连接大,2440拜的内存就是nor
flash,可以一直读,但是未可知直接写

 

2.nor
flash命令如下所示(参考MX29LV160DBTI.pdf)

 美学原理 4

其中word是针对16位nand,byte针对8位nand.

由我们2440底flash型号是MX29LV160DB,所以设备ID为0x2249

 

2.1
比如,当我们要program(往0x20地方写入0xff数据)时

消以下3步:

1.殡葬解锁地址:

往nor地址0x555写入0xAA

往nor地址0x2AA写入0x55 

2.发送命令:     

往nor地址0x555写入0xA0               
//进入program模式

3.写数据:

往nor地址0x20(PA)写入0xff(PD)         
//往0x20写入0xff

(接下去就会见一直是program模式,执行reset模式就是得以退出)

2.2欠NOR有零星种标准,
jedec, cfi(common flash interface) 

jedec

就是和nandflash的一样,通过读ID来匹配linux内核中drivers/mtd/chips/jedec_probe.c里的jedec_table[]频繁组,来规定norflash的依次参数(名称、容量、位宽等),如下图所示:

 美学原理 5

  • [0] =
    MTD_UADDR_0x5555_0x2AAA

意味着解锁地址也0x5555,0x2AAAM,其中数组[0],表示属于8个flash,定义如下:

美学原理 6

  •  CmdSet

以啊种命令,一般CmdSet=0xFFF0

  • .NumEraseRegions= 1

仅来1个不等之扇区区域

  • ERASEINFO(0x10000, 64)

共有64单扇区,每个扇区都是64KB(0x10000)

cfi

即便将这些参数保存于cfi模式下指定地点被,
往nor的0x55地址写入0x98,即可进入cfi模式,

cfi模式有令如下图所示:

 美学原理 7

当我们在cfi模式下,比如:读取nor地址0x27处的数目,便会读到nor的容量

一般来说图所示,之所以地址*2,是因为nor地址线A0接在咱们2440的A1达成(退出cfi模式,使用复位命令即可)

美学原理 8

朗诵到0X15,0x15=21,如下图,刚好对应我们原理图的21干净nor地址线,所以容量也2^21=2MB

 美学原理 9

2.3为什么上图的A20挑起脚没对接?

于2440来讲话,因为此时之A0~A19底容量刚好也2MB,与cfi模式下读取的数一致,所以无接A20

 

3.接下来便来分析哪些勾勒norflash驱动

3.1
先来回顾下前的nandflsh驱动:

nandflsh驱动会放在内核的mtd设备遭遇,而mtd设备接头怎么通过命令/地址/数据来操作nandflash,所以我们事先的nandflash驱动只兑现了硬件相关的操作(构造mtd_info,nand_chip结构体、启动nand控制器等)

同地,norflash驱动也是坐落内核的mtd设备中,mtd设备也懂得针对nor如何来读写擦除,只是不明了norflash的位宽(数据线个数),基地址等,所以我们的norflash驱动同样如果促成硬件相关的操作,供给mtd设备调用

 

3.2参考内核自带的nor驱动:drivers/mtd/maps/physmap.c

跻身她的init函数:

 美学原理 10

意识报了少于单platform平台设备驱动,进入physmap_flash结构体中:

 美学原理 11

发觉3独无定义的变量:

CONFIG_MTD_PHYSMAP_BANKWIDTH:
nandflash的许节位宽

CONFIG_MTD_PHYSMAP_START:nandflash的物理基地址

CONFIG_MTD_PHYSMAP_LEN:
nandflash的容量长度

顿时3个变量是经linux的menuconfig菜单配置出的,若自己填写入值,就非需因此menuconfig菜单配置了

 

3.3连片下我们虽来部署基本,然后挂载这个根本自带的norflash驱动实验一番

3.4 首先make
menuconfig,配置方面3个变量,然后设为模块

-> Device
Drivers                

 -> Memory Technology Device (MTD)
support  

 -> Mapping drivers for chip
access                   //进入映射驱动


 

<M>
CFI Flash device in physical memory map       
  //将支持cfi的norflash设置为模块

  •    (0x0)
    Physical start address of flash mapping  // 设置物理基地址
  •   
    (0x1000000) Physical length of flash mapping  //
    设置容量长度,必须超过等于我nor的2MB
  •    (2)  
    Bank width in octets (NEW)                   //
    设置字节位宽,因为nor为16个,所以当2

 


3.5 make modules 编译模块

如下图所示,可以看physmap.c编译成.ko模块了

 美学原理 12

3.6
然后在nfs目录下,启动开发板

一般来说图所示,insmod后打印了千篇一律差信息:

 美学原理 13

如下图所示,可以看到创建了2只mtd0字符设备,一个mtd0块设备:

 美学原理 14

 

4.接下来我们尽管分析physmap.c,如何勾勒起norflash驱动的

其中physmap.c的probe函数如下

struct physmap_flash_info {
       struct mtd_info             *mtd;             //实现对flash的读写擦除等操作
       struct map_info            map;              //存放硬件相关的结构体
       struct resource             *res;
#ifdef CONFIG_MTD_PARTITIONS
       int                 nr_parts;
       struct mtd_partition      *parts;
#endif
};

static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };    //芯片名称

... ...
static int physmap_flash_probe(struct platform_device *dev)
{
       const char **probe_type;
       ... ...
       /*1. 分配结构体*/
       info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);

       /*2.设置map_info 结构体*/
    info->map.name = dev->dev.bus_id;                 //norflash的名字
       info->map.phys = dev->resource->start;          //物理基地址
       info->map.size = dev->resource->end - dev->resource->start + 1;       //容量长度
       info->map.bankwidth = physmap_data->width;                     //字节位宽
       info->map.virt = ioremap(info->map.phys, info->map.size);    //虚拟地址

       simple_map_init(&info->map);                   //简单初始化map_info的其它成员

       probe_type = rom_probe_types;
       /*3. 设置mtd_info 结构体 */
       /*通过probe_type指向的名称来识别芯片,当do_map_probe()函数返回NULL表示没找到*/
       /*当找到对应的芯片mtd_info结构体,便返回给当前的info->mtd */
       for (; info->mtd == NULL && *probe_type != NULL; probe_type++)       
       info->mtd = do_map_probe(*probe_type, &info->map); //通过do_map_probe ()来识别芯片


       if (info->mtd == NULL) {             //最终还是没找到芯片,便注销之前注册的东西并退出
              dev_err(&dev->dev, "map_probe failed\n");
              err = -ENXIO;
              goto err_out;
       }

       info->mtd->owner = THIS_MODULE;        



       /*4.添加mtd设备*/

       add_mtd_device(info->mtd);              

       return 0;



err_out:

       physmap_flash_remove(dev);                      //该函数用来注销之前注册的东西

       return err;

}

 

经上面的代码和注释分析及,和咱们达成同节省的nandflash驱动相似,这里是设置map_info
结构体和mtd_info结构体来就的,当我们如果针对norflash分区即将使add_mtd_partitions()才行

其中当*probe_type==“cfi_probe”时:

即便会见由此do_map_probe(“cfi_probe”,
&info->map)来辨别芯片.

末段会进入drivers/mtd/chips/cfi_probe.c中的cfi_probe_chip()函数来上cfi模式,读取芯片信息

当*probe_type==”jedec_probe”时:

末了见面跻身drivers/mtd/chips/jedec_probe.c中的jedec_probe_chip
()函数来运读ID命令,通过ID来配合配jedec_table[]数组.

从而注册一个块设备驱动,需要以下步骤:

  • 1.
    分配mtd_info结构体和map_info结构体
    1. 设置map_info
      结构体
    1. 设置mtd_info
      结构体
  • 4.
    使用add_mtd_partitions()或者add_mtd_device()来创建MTD字符/块
    设备

 

5.接下来我们来参考physmap.c来协调写norflah驱动

代码如下:

#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 <asm/io.h>


static struct mtd_info        *mynor_mtd_info;
static struct map_info         *mynor_map_info;


static struct mtd_partition mynor_partitions[] = {
       [0] = {
        .name   = "bootloader",
        .size   = 0x00040000,
        .offset     = 0,
       },
       [1] = {
        .name   = "root",
        .offset = MTDPART_OFS_APPEND,
        .size   = MTDPART_SIZ_FULL,
       }
};

static const char *mynor_probe_types[] = { "cfi_probe", "jedec_probe",NULL};


static int mynor_init(void)
{
    int val;

/*1. 分配map_info 结构体和mtd_info结构体*/
    mynor_mtd_info=kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
    mynor_map_info=kzalloc(sizeof(struct map_info), GFP_KERNEL);

/*2. 设置map_info 结构体*/
    mynor_map_info->name="my_nor";
    mynor_map_info->phys=0x0;                          //物理地址
    mynor_map_info->size=0x1000000;                 //=16M,长度必须大于等于norflash的2M容量
    mynor_map_info->bankwidth=2;                     //16位宽
    mynor_map_info->virt = ioremap(0x0, mynor_map_info->size);   //虚拟地址
    simple_map_init(mynor_map_info);

/*3. 设置mtd_info 结构体*/
   mynor_mtd_info = do_map_probe("cfi_probe", mynor_map_info);
   if (!mynor_mtd_info)
   {
     mynor_mtd_info = do_map_probe("jedec_probe", mynor_map_info);
    }

    if (!mynor_mtd_info)
    {
    printk(“not available norflash !!!\r\n”);
    goto err_out;
    }
    mynor_mtd_info->owner=THIS_MODULE;

 

/*4. 使用add_mtd_partitions()或者add_mtd_device()来创建MTD字符/块 设备*/
       add_mtd_partitions(mynor_mtd_info,mynor_partitions,2);
       return 0;


err_out:
       iounmap(mynor_map_info->virt);                      //取消虚拟地址映射
       kfree(mynor_map_info);
       kfree(mynor_mtd_info);      
       return 0;
}


static  void mynor_exit(void)
{
    del_mtd_partitions(mynor_mtd_info);                  //卸载分区
    iounmap(mynor_map_info->virt);                      //取消虚拟地址映射
    kfree(mynor_map_info);
    kfree(mynor_mtd_info);       
}

module_init(mynor_init);
module_exit(mynor_exit);
MODULE_LICENSE("GPL");

 

6.挂载驱动试验

(一定要以nor启动下挂载才行,因为2440施用nand启动时,是看不了nor的前4k地址)

insmod挂载驱动后,如下图所示:

 美学原理 15

足见见创建了一定量只分区“bootloader”,“root”,如下图所出示,可以视创建了2针对mtd字符/块设备

 美学原理 16

6.1
接下就来针对root分区(mtd1)来考试(使用flash之前最好好擦除同坏)

手续如下:

./flash_eraseall -j /dev/mtd1                      //使用mtd-util工具的flash_eraseal命令来擦除root分区(mtd1)

mount -t jffs2 /dev/mtdblock1 /mnt/                //使用mount挂载文件系统, -t:文件系统类型(type)

 

连下就可以/mnt目录下来任意读写文件了,最终会保留于flash的mtdblock1块配备遭遇

(PS:可以参见内核自带的mtdram.c,里面是用外存来模拟flash,
里面通过memcopy()等来兑现对内存读写擦除)