历史上的今天

今天是:2024年10月11日(星期五)

正在发生

2018年10月11日 | OK6410之nand flash块设备驱动

发布者:RadiantExplorer 来源: eefocus关键字:OK6410  nand  flash  块设备驱动 手机看文章 扫描二维码
随时随地手机看文章

s3c6410_nand.c源码:

// 参考: drivers\mtd\nand\h1910.c 

#include "linux/slab.h"

#include "linux/init.h"

#include "linux/module.h"

#include "linux/mtd/mtd.h"

#include "linux/mtd/nand.h"

#include "linux/mtd/partitions.h"

#include "asm/io.h"

#include "mach/hardware.h"    // for CLPS7111_VIRT_BASE 

#include "asm/sizes.h"

#include "linux/clk.h"

//drivers/mtd/nand/s3c_nand.c

// samsung  K9GAG08U0D  MLC nand flash  oob size =218 Byte

static struct nand_ecclayout s3c_nand_oob_mlc_218_8bit = {

    .eccbytes = 104,

    .eccpos = {

           114,115,116,117,118,119,120,121,122,123,

           124,125,126,127,128,129,130,131,132,133,

           134,135,136,137,138,139,140,141,142,143,

           144,145,146,147,148,149,150,151,152,153,

           154,155,156,157,158,159,160,161,162,163,

           164,165,166,167,168,169,170,171,172,173,

           174,175,176,177,178,179,180,181,182,183,

           184,185,186,187,188,189,190,191,192,193,

           194,195,196,197,198,199,200,201,202,203,

           204,205,206,207,208,209,210,211,212,213,

           214,215,216,217 },

    .oobfree = {

        {.offset = 2,

         .length = 110}}

};

static struct mtd_info *s3c6410_mtd;

struct s3c6410_nand_regs {

    unsigned long  NFCONF;

    unsigned long  NFCONT;

    unsigned long  NFCMD;

    unsigned long  NFADDR;

    unsigned long  NFDATA;

    unsigned long  NFMECCDATA0;

    unsigned long  NFMECCDATA1;

    unsigned long  NFSECCDATA;

    unsigned long  NFSBLK;

    unsigned long  NFEBLK;

    unsigned long  NFSTAT;

    unsigned long  NFMECCERR0;

    unsigned long  NFMECCERR1;

    unsigned long  NFMECC0;

    unsigned long  NFMECC1;

    unsigned long  NFSECC;

    unsigned long  NFMLCBITPT;

};

static struct s3c6410_nand_regs *s3c6410_nand_regs;

static struct mtd_partition s3c_partitions[] = {

    {

            .name        = "Bootloader",

            .offset      = 0,

            .size        = (256*SZ_1K),

            .mask_flags  = MTD_CAP_NANDFLASH,

    },

    {

            .name        = "Kernel",

            .offset      = (256*SZ_1K),

            .size        = (4*SZ_1M) - (256*SZ_1K),

            .mask_flags  = MTD_CAP_NANDFLASH,

    },

    {

            .name        = "Rootfs",

            .offset      = (4*SZ_1M),

            .size        = (80*SZ_1M),//(48*SZ_1M),

    },

    {

            .name        = "File System",

            .offset      = MTDPART_OFS_APPEND,

            .size        = MTDPART_SIZ_FULL,

    }

};

static void s3c6410_nand_select(struct mtd_info *mtd, int chip)

{

    if (0 == chip)

    {

        s3c6410_nand_regs->NFCONT &= ~(1<<1);  //0: NAND Flash Controller Disable (Don’t work)

        //printk("s3c6410_nand_select : %x\n", s3c6410_nand_regs->NFCONT);

    }

    else

    {

        //printk("s3c6410_nand_deselect\n");

        s3c6410_nand_regs->NFCONT |= (1<<1);   //1: NAND Flash Controller Enable

    }

}

static void s3c6410_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)

{

    if (ctrl & NAND_CLE)

    {

        //printk("send cmd: %x\n", dat);

        s3c6410_nand_regs->NFCMD = dat;

    }

    else if (ctrl & NAND_ALE)

    {

        //printk("send addr: %x\n", dat);

        s3c6410_nand_regs->NFADDR = dat;

    }

}

static void s3c6410_nand_hw_init(void)

{

//    MEM_SYS_CFG &= ~(1<<1);

// setup time parameter 

#define TACLS        7

#define TWRPH0    7

#define TWRPH1    7

    s3c6410_nand_regs->NFCONF &= ~((1<<30) | (7<<12) | (7<<8) | (7<<4));

    s3c6410_nand_regs->NFCONF |= ((TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4));

    // enable nand flash controller 

    s3c6410_nand_regs->NFCONT |= 1;

    s3c6410_nand_regs->NFCONT &= ~(1<<16); // disable soft lock 

}

static int s3c6410_nand_ready(struct mtd_info *mtd)

{

    return (s3c6410_nand_regs->NFSTAT & 0x1);

}

static int s3c6410_nand_init(void)

{

    struct nand_chip *chip;

    struct clk *clk;

    volatile unsigned long *MEM_SYS_CFG;

    MEM_SYS_CFG = ioremap(0x7E00F120, 4);

    *MEM_SYS_CFG &= ~(1<<1);

    iounmap(MEM_SYS_CFG);

    clk = clk_get(NULL, "nand");

    clk_enable(clk);

    s3c6410_nand_regs = ioremap(0x70200000, 1024);

    s3c6410_nand_hw_init();

    

    s3c6410_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);

    chip = (struct nand_chip *)&s3c6410_mtd[1];

    s3c6410_mtd->priv = chip;

    s3c6410_mtd->owner = THIS_MODULE;

    // setup nand_chip: 

    chip->options         = 0;

    chip->select_chip   = s3c6410_nand_select;

    chip->cmd_ctrl       = s3c6410_nand_cmd_ctrl;

    chip->IO_ADDR_R  = &s3c6410_nand_regs->NFDATA;

    chip->IO_ADDR_W = &s3c6410_nand_regs->NFDATA;

    chip->dev_ready     = s3c6410_nand_ready;

    chip->ecc.mode     = NAND_ECC_SOFT;

    chip->ecc.layout    = &s3c_nand_oob_mlc_218_8bit;

    

    if (nand_scan(s3c6410_mtd, 1))

    {

        printk("can't find nand flash for s3c6410\n");

        kfree(s3c6410_mtd);

        iounmap(s3c6410_nand_regs);

        return -EAGAIN;

    }

    //add_mtd_partitions(s3c6410_mtd, s3c_partitions, 4);  // add_disk 

    mtd_device_register(s3c6410_mtd, s3c_partitions, 4);    //注册mtd设备

    

    return 0;

}

static void s3c610_nand_exit(void)

{

    //del_mtd_partitions(s3c6410_mtd);

    mtd_device_unregister(s3c6410_mtd);

    kfree(s3c6410_mtd);

    iounmap(s3c6410_nand_regs);

}

module_init(s3c6410_nand_init);

module_exit(s3c610_nand_exit);

MODULE_LICENSE("GPL");

=====================================================================

Makefile文件:

KERN_DIR = /work/tools/linux/linux-3.0.1

all:

    make -C $(KERN_DIR) M=`pwd` modules 

clean:

    make -C $(KERN_DIR) M=`pwd` modules clean

    rm -rf modules.order

obj-m += s3c6410_nand.o

=====================================================================

NAND FLASH控制流程:

NAND FLASH是一个存储芯片

那么: 这样的操作很合理"读地址A的数据,把数据B写到地址A"

问1. 原理图上NAND FLASH和S3C2440之间只有数据线,

     怎么传输地址?

答1.在DATA0~DATA7上既传输数据,又传输地址

     当ALE为高电平时传输的是地址,

问2. 从NAND FLASH芯片手册可知,要操作NAND FLASH需要先发出命令

     怎么传入命令?

答2.在DATA0~DATA7上既传输数据,又传输地址,也传输命令

     当ALE为高电平时传输的是地址,

     当CLE为高电平时传输的是命令

     当ALE和CLE都为低电平时传输的是数据

问3. 数据线既接到NAND FLASH,也接到NOR FLASH,还接到SDRAM、DM9000等等

     那么怎么避免干扰?

答3. 这些设备,要访问之必须"选中",

     没有选中的芯片不会工作,相当于没接一样

问4. 假设烧写NAND FLASH,把命令、地址、数据发给它之后,

     NAND FLASH肯定不可能瞬间完成烧写的,

     怎么判断烧写完成?

答4. 通过状态引脚RnB来判断:它为高电平表示就绪,它为低电平表示正忙

问5. 怎么操作NAND FLASH呢?

答5. 根据NAND FLASH的芯片手册,一般的过程是:

     发出命令

     发出地址

     发出数据/读数据

=====================================================================

S3C6410 NAND FLASH命令操作:

1. 读ID

                               S3C6410                 u-boot 

选中                           NFCONT的bit1设为0   md.l 0x70200004 1; mw.l 0x70200004 1  

//md.l内存数据显示,单位 : .b读一字节  .w读2字节 .l读4字节 0x70200004 地址 1 读一次 

// mw.l 内存写入0x70200004地址,1写入数值1 即 01 含义:   0: Force Xm0CSn2 to low(Enable chip select),1: NAND Flash Controller Enable

//.b:  byte 字节   .w word 字   .l long 长的

发出命令0x90                   NFCMMD=0x90         mw.b 0x70200008 0x90     写入一个字节

发出地址0x00                   NFADDR=0x00           mw.b 0x7020000C 0x00

读数据得到0xEC               val=NFDATA               md.b 0x70200010 1

读数据得到device code   val=NFDATA               md.b 0x70200010 1

          0xda

退出读ID的状态                 NFCMMD=0xff         mw.b 0x70200008 0xff

SMDK6410 # mw.l 0x70200004  1        发出片选

SMDK6410 # mw.b 0x70200008 0x90  发出90h命令                                             

SMDK6410 # mw.b 0x7020000C 0x00  发出0地址                                            

SMDK6410 # md.b 0x70200010 1        读数据                                             

70200010: ec    .                                     读到ec                                           

SMDK6410 # md.b 0x70200010 1        读到设备id                                           

70200010: d7    .  

2. 读内容: 读0地址的数据

使用UBOOT命令:

nand dump 0

Page 00000000 dump:

   17 00 00 ea 14 f0 9f e5  14 f0 9f e5 14 f0 9f e5

S3C2440                 u-boot 

选中                     NFCONT的bit1设为0   md.l 0x70200004 1; mw.l 0x70200004  1

发出命令0x00        NFCMMD=0x00         mw.b 0x70200008 0x00 

发出地址0x00        NFADDR=0x00         mw.b 0x7020000C 0x00

发出地址0x00        NFADDR=0x00         mw.b 0x7020000C 0x00

发出地址0x00        NFADDR=0x00         mw.b 0x7020000C 0x00

发出地址0x00        NFADDR=0x00         mw.b 0x7020000C 0x00

发出地址0x00        NFADDR=0x00         mw.b 0x7020000C 0x00

发出命令0x30        NFCMMD=0x30       mw.b 0x70200008 0x30 

读数据得到0x17      val=NFDATA          md.b 0x70200010 1

读数据得到0x00      val=NFDATA          md.b 0x70200010 1

读数据得到0x00      val=NFDATA          md.b 0x70200010 1

读数据得到0xea      val=NFDATA          md.b 0x70200010 1

退出读状态          NFCMMD=0xff          mw.b 0x70200008 0xff

SMDK6410 # nand dump 0                                                          

Page 00000000 dump:                                                             

   13 00 00 ea 14 f0 9f e5  14 f0 9f e5 14 f0 9f e5   每行显示16字节数据                     

   14 f0 9f e5 14 f0 9f e5  14 f0 9f e5 14 f0 9f e5

        

SMDK6410 # md.l 0x70200004 1                                                    

70200004: 000000c7    ....                                                      

SMDK6410 # mw.l 0x70200004   0xc5                                               

SMDK6410 # md.l 0x70200004 1                                                    

70200004: 000000c5    ....                                                      

SMDK6410 # mw.b 0x70200008 0x00                                                 

SMDK6410 # mw.b 0x7020000C 0x00                                                 

SMDK6410 # mw.b 0x7020000C 0x00                                                 

SMDK6410 # mw.b 0x7020000C 0x00                                                 

SMDK6410 # mw.b 0x7020000C 0x00                                                 

SMDK6410 # mw.b 0x7020000C 0x00                                                 

SMDK6410 # mw.b 0x70200008 0x30                                                 

SMDK6410 # md.b 0x70200010 1                                                    

70200010: 13    .                                                               

SMDK6410 # md.b 0x70200010 1                                                    

70200010: 00    .    

SMDK6410 #  md.b 0x70200010 1                                                   

70200010: 00    .                                                               

SMDK6410 # md.b 0x70200010 1                                                    

70200010: ea    .      

SMDK6410 # mw.b 0x70200008 0xff   

=====================================================================

NAND FLASH驱动程序层次  文件系统把对文件的操作转换为对块设备的读写

看内核启动信息

S3C24XX NAND Driver, (c) 2004 Simtec Electronics

s3c2440-nand s3c2440-nand: Tacls=3, 30ns Twrph0=7 70ns, Twrph1=3 30ns

NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)

Scanning device for bad blocks

Bad eraseblock 256 at 0x02000000

Bad eraseblock 257 at 0x02020000

Bad eraseblock 319 at 0x027e0000

Bad eraseblock 606 at 0x04bc0000

Bad eraseblock 608 at 0x04c00000

Creating 4 MTD partitions on "NAND 256MiB 3,3V 8-bit":

0x00000000-0x00040000 : "bootloader"

0x00040000-0x00060000 : "params"

0x00060000-0x00260000 : "kernel"

0x00260000-0x10000000 : "root"

搜"S3C24XX NAND Driver"

S3c2410.c (drivers\mtd\nand)

s3c2410_nand_inithw初始化硬件

s3c2410_nand_init_chip初始化芯片

nand_scan  nand扫描  // drivers/mtd/nand/nand_base.c 根据nand_chip的底层操作函数识别NAND FLASH,构造mtd_info

  nand_scan_ident

    nand_set_defaults默认的设置   nand_base.c

      if (!chip->select_chip)

        chip->select_chip = nand_select_chip; // 默认值不适用

    

      if (chip->cmdfunc == NULL)

        chip->cmdfunc = nand_command;

           chip->cmd_ctrl(mtd, command, ctrl);

      if (!chip->read_byte)

        chip->read_byte = nand_read_byte;

           readb(chip->IO_ADDR_R);

      if (chip->waitfunc == NULL)

        chip->waitfunc = nand_wait;

           chip->dev_ready

      nand_get_flash_type

           chip->select_chip(mtd, 0);

           chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);

           //读id   {"NAND 4GiB 3,3V 8-bit",    0xD7, 0, 4096, 0, LP_OPTIONS},

           

           *maf_id = chip->read_byte(mtd);读字节

           dev_id = chip->read_byte(mtd);

        nand_scan_tail

           mtd->erase = nand_erase; mtd_info结构体

           mtd->read = nand_read;

           mtd->write = nand_write;

      s3c2410_nand_add_partition

          add_mtd_partitions添加分区

              add_mtd_device添加mtd设备

                  list_for_each(this, &mtd_notifiers) { 

                  // 问. mtd_notifiers在哪设置

                  // 答. drivers/mtd/mtdchar.c,mtd_blkdev.c调用register_mtd_user

                  

                  struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);

                  not->add(mtd);// mtd_notify_add  和 blktrans_notify_add

                  先看字符设备的mtd_notify_add

                  class_device_create  创建两个设备节点,一个是mtd1,另一个是mtd1ro ro只读

                  class_device_create

                  再看块设备的blktrans_notify_add

                    list_for_each(this, &blktrans_majors) { 

                    // 问. blktrans_majors在哪设置

                    // 答. drivers\mtd\mdblock.c或mtdblock_ro.c   register_mtd_blktrans注册mtd块传输

                       struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);              

                          tr->add_mtd(tr, mtd);

                             mtdblock_add_mtd (drivers\mtd\mdblock.c)

                               add_mtd_blktrans_dev

                                 alloc_disk分配磁盘

                                 gd->queue = tr->blkcore_priv->rq; 

// tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);队列

                                 add_disk添加磁盘

=====================================================================

s3c6410:

s3c_nand.c何时被使用:

内核arch/arm/plat-samsung/dev-nand.c有一个平台设备:

struct platform_device s3c_device_nand = {

    .name          = "s3c6410-nand",

    .id                = -1,

    .num_resources      = ARRAY_SIZE(s3c_nand_resource),

    .resource      = s3c_nand_resource,

};

EXPORT_SYMBOL(s3c_device_nand);

它会注册一个名字是"s3c6410-nand"的platform_device,

当s3c_nand.c注册平台驱动时发现有同名的平台设备,

就会调用平台驱动的probe函数,如果没有这个平台设备,

执行到s3c_nand.c时它不会做任何事情。

在ok6410官方内核linux-3.0.1源码arch/arm/plat-samsung/  目录下有很多platform_device结构体

=====================================================================

测试:

1. make menuconfig去掉内核自带的NAND FLASH驱动

linux-3.0.1

默认:

-> Device Drivers

  -> Memory Technology Device (MTD) support

    -> NAND Device Support

         [ ]   NAND Flash support for Samsung S3C SoCs

         [*]   NAND support for Samsung S3C

         [*]     S3C NAND driver debug

         [*]     S3C NAND Hardware ECC

改为:

-> Device Drivers

  -> Memory Technology Device (MTD) support

    -> NAND Device Support

    [ ]   NAND Flash support for Samsung S3C SoCs

    [ ]   NAND support for Samsung S3C 

//添加mtd分区,linux-3.0.1编译会有警告:

//WARNING: "add_mtd_partitions" [/home/cheng/cross/nand_flash_mtd/s3c6410nand.ko] undefined!

//WARNING: "del_mtd_partitions" [/home/cheng/cross/nand_flash_mtd/s3c6410nand.ko] undefined!

//加载时会有错误:

//s3c6410_nand: Unknown symbol del_mtd_partitions (err 0)                         

//s3c6410_nand: Unknown symbol add_mtd_partitions (err 0)  

add_mtd_partitons()警告解决方法:

    使用mtd_device_register(s3c6410_mtd,ok6410_nand_part,3);//注册mtd设备

或者:

    在add_mtd_partitions()函数后面添加:

    EXPORT_SYMBOL(add_mtd_partitions);

    EXPORT_SYMBOL(del_mtd_partitions);

2. make uImage/make zImage 

   cp arch/arm/boot/zImage ../../zImage_no_nand

   把开发板设置为SD卡启动,使用SD卡启动后按空格进入SD卡的u-boot;

   用SD卡里面的u-boot烧写内核到0x000000200000-0x000000700000 : "Kernel"分区:

      tftp 50008000 zImage_no_nand

      nand erase 200000 500000

      nand write 50008000 200000 500000

   烧写完成后设置开发版为nand flash启动,使用新内核启动, 并且使用NFS作为根文件系统,因为之前根文件系统在nand flash上面,现在内核去除了nand flash的驱动,内核就无法访问根文件系统了。

      print命令查看u-boot参数:

      bootcmd=nand read 0xc0008000 0x200000 0x500000;bootm 0xc0008000

      baudrate=115200

      ethaddr=00:40:5c:26:0a:5b

      netmask=255.255.255.0

      bootdelay=10

      serverip=192.168.48.103

      ipaddr=192.168.48.100

      gatewayip=192.168.48.1

      bootargs=noinitrd root=/dev/nfs nfsroot=192.168.48.104:/home/book/workspace/ok6410_project/fs_ok6410_yaffs2 ip=192.168.48.100:192.168.48.104:192.168.48.255:255.255.255.0::eth0:off init=/linuxrc console=ttySAC0,115200

   ls /dev/mtd*  看不到mtd分区

3. insmod s3c_nand.ko

ls /dev/mtd* -l

crw-rw----    1 0        0          90,   0 Jan  1 01:23 /dev/mtd0   字符设备          

crw-rw----    1 0        0          90,   1 Jan  1 01:23 /dev/mtd0ro  只读          

crw-rw----    1 0        0          90,   2 Jan  1 01:23 /dev/mtd1              

crw-rw----    1 0        0          90,   3 Jan  1 01:23 /dev/mtd1ro            

crw-rw----    1 0        0          90,   4 Jan  1 01:23 /dev/mtd2              

crw-rw----    1 0        0          90,   5 Jan  1 01:23 /dev/mtd2ro            

brw-rw----    1 0        0          31,   0 Jan  1 01:23 /dev/mtdblock0   块设备   

brw-rw----    1 0        0          31,   1 Jan  1 01:23 /dev/mtdblock1         

brw-rw----    1 0        0          31,   2 Jan  1 01:23 /dev/mtdblock2  

root=/dev/mtdblock2 rootfstype=jffs2 rw init=/linuxrc console=ttySAC0,115200

flash_eraseall -j /dev/mtd2                         //nand格式化为jffs2

mount -t jffs2 /dev/mtdblock2 /mnt

4. 格式化 (参考下面编译工具)

   flash_eraseall  /dev/mtd3                         // 格式化mtd3分区 默认格式成yaffs

   

5. 挂接

   mount -t yaffs /dev/mtdblock3 /mnt     //挂载设备节点

如果出现以下提示则说明nand flash可能有有坏块:

uncorrectable error :                                                           

end_request: I/O error, dev mtdblock2, sector 0                                 

Buffer I/O error on device mtdblock2, logical block 0                           

uncorrectable error :                                                           

end_request: I/O error, dev mtdblock2, sector 0                                 

Buffer I/O error on device mtdblock2, logical block 0     

代码页可能出错:

static void s3c6410_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)

{

    if(ctrl & NAND_CLE)

    {

        //如果是CLE ,发命令:NFCMMD = dat

        nand_regs->nfcmmd = dat;

    }

    else if (ctrl & NAND_ALE) 

    //如果不加ctrl & NAND_ALE此项直接就  else  会有错误:uncorrectable :I/O error, dev mtdblock2, sector 0 等

    {   

        //否则如果是发地址 :NFADDR = dat

        nand_regs->nfaddr = dat;

    }

}

6. 在/mnt目录下建文件  

编译工具:

①. tar xjf mtd-utils-05.07.23.tar.bz2 

②. cd mtd-utils-05.07.23/util

修改Makefile:

#CROSS=arm-linux-

CC := $(CROSS)gcc

改为:

CROSS=arm-linux-

CC := $(CROSS)gcc

③. make

④. cp flash_erase flash_eraseall /work/nfs_root/first_fs/bin/

                     

注意:s3c6410启动时自动拷贝nand flash前4页的内容到片内内存执行,而且拷贝时只拷每页中的前2KByte,好像是为了兼容2k页的,所有copy2ddr函数中不要把所有数据全部照搬过去,只搬每页的前2k到ddr连接起来 。

=====================================================================

错误解决:

       在程序的开始并没有定义s3c_nand_oob_mlc_218_8bit结构体,按照S3C2440的nand flash驱动,OOB设置由内核自动完成,但是在测试驱动的时候发现内核运行崩溃,报“Segmentation fault”:

NAND device: Manufacturer ID: 0xec, Chip ID: 0xd7 (Samsung NAND 4GiB 3,3V 8-bit)

No oob scheme defined for oobsize 218

kernel BUG at drivers/mtd/nand/nand_base.c:3278!

Unable to handle kernel NULL pointer dereference at virtual address 00000000

pgd = cbc24000

[00000000] *pgd=5c7a0831, *pte=00000000, *ppte=00000000

Internal error: Oops: 817 [#1]

Modules linked in: s3c6410_nand(+)

CPU: 0    Tainted: G        W    (3.0.1 #442)

PC is at __bug+0x20/0x2c

LR is at console_unlock+0x15c/0x1b8

pc : []    lr : []    psr: 60000013

sp : cbc5fec0  ip : cbc5fde8  fp : cbc5fecc

r10: 00000000  r9 : bf0000d0  r8 : cbc5e000

r7 : 00000000  r6 : cc6e3400  r5 : cc6e3590  r4 : cc6e3400

r3 : 00000000  r2 : c27c5ac5  r1 : 00000000  r0 : 00000037

Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user

Control: 00c5387d  Table: 5bc24008  DAC: 00000015

Process insmod (pid: 114, stack limit = 0xcbc5e268)

Stack: (0xcbc5fec0 to 0xcbc60000)

fec0: cbc5feec cbc5fed0 c026c9c4 c00383d0 cc6e3400 00000001 bf000320 00000000

fee0: cbc5ff04 cbc5fef0 c026f8c0 c026c498 bf000d10 00000000 cbc5ff24 cbc5ff08

ff00: bf0001c4 c026f888 c073d9a0 00000000 bf000ba8 00000000 cbc5ff7c cbc5ff28

ff20: c00343c8 bf0000dc cbc5ff64 cbc5ff38 c0073e24 00000000 00000000 00000000

ff40: 00000000 000127c8 000d5bf9 bf000ba8 00000000 000127c8 000d5bf9 bf000ba8

ff60: 00000000 c0034ce8 cbc5e000 00000000 cbc5ffa4 cbc5ff80 c0085960 c0034398

ff80: c00e8738 c00e8610 401ad4a8 000dfcf8 00000000 00000080 00000000 cbc5ffa8

ffa0: c0034b40 c00858e0 401ad4a8 000dfcf8 00ae0038 000127c8 000d5bf9 ffff5f01

ffc0: 401ad4a8 000dfcf8 00000000 00000080 00000069 00000001 bef6de74 bef6de78

ffe0: bef6de78 bef6db24 00021cfc 4026ed74 60000010 00ae0038 00000000 00000000

[] (__bug+0x20/0x2c) from [] (nand_scan_tail+0x538/0x644)

[] (nand_scan_tail+0x538/0x644) from [] (nand_scan+0x44/0x7c)

[] (nand_scan+0x44/0x7c) from [] (s3c6410_nand_init+0xf4/0x170 [s3c6410_nand])

[] (s3c6410_nand_init+0xf4/0x170 [s3c6410_nand]) from [] (do_one_initcall+0x3c/0x188)

[] (do_one_initcall+0x3c/0x188) from [] (sys_init_module+0x8c/0x1a4)

[] (sys_init_module+0x8c/0x1a4) from [] (ret_fast_syscall+0x0/0x30)

Code: e1a01000 e59f000c eb11b57b e3a03000 (e5833000) 

---[ end trace da227214a82491b9 ]---

Segmentation fault

根据此错误信息“kernel BUG at drivers/mtd/nand/nand_base.c:3278!”找到对应报错点:

if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) {

即没有定义chip->ecc.layout

在网上找了一天!!!

参考“ok6410 nandflash 驱动注意地方”

ECC相关的结构体:

struct nand_ecclayout {

           uint32_t eccbytes; 

           uint32_t eccpos[64];

           uint32_t oobavail;

           struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];

};

这是用来定义ECC在oob中布局的一个结构体。

static struct nand_ecclayout s3c_nand_oob_mlc_128_8bit = {

        .eccbytes = 104,

        .eccpos = {

                   24,25,26,27,28,29,30,31,32,33,

                   34,35,36,37,38,39,40,41,42,43,

                   44,45,46,47,48,49,50,51,52,53,

                   54,55,56,57,58,59,60,61,62,63,

                   64,65,66,67,68,69,70,71,72,73,

                   74,75,76,77,78,79,80,81,82,83,

                   84,85,86,87,88,89,90,91,92,93,

                   94,95,96,97,98,99,100,101,102,103,

                   104,105,106,107,108,109,110,111,112,113,

                   114,115,116,117,118,119,120,121,122,123,

                   124,125,126,127},

        .oobfree = {

                {.offset = 2,

                 .length = 20}}

};

       前面已经提及过,oob中主要存储两种信息:坏块信息和ECC数据。对与small page的NAND芯片来说,其中坏块信息占据1个字节(一般固定在第六个字节),ECC数据占据三个字节。所以sturct nand_ecclayout这个结构体,也就是用来告诉那些与ECC操作无关的函数,Nand芯片的oob部分中,哪些字节是用来存储ECC的(即不可用作它用的),哪些字节是空闲的,即可用的。

       其实之所以有这个结构体,主要是因为硬件ECC的缘故。以写数据为例,在使用硬件ECC的情况下,那三个字节的ECC数据是由硬件计算得到,并且写到NAND芯片的oob中去的,同时也是由硬件决定写到oob的哪三个字节中去。这些都是由硬件做的,而NAND驱动并不知道,所以就需要用这个结构体来告诉驱动了。

       所以,在写NAND驱动时,就有可能需要对这个结构体进行赋值。这里说“有可能”,是因为MTD对这个结构体有一个默认的赋值,假如这个赋值所定义的ECC位置与你的硬件一致的话,那就不必在你的驱动中手动赋值了。其实对大多数硬件(这里所说的硬件,不是指NAND芯片,而是NAND控制器)来说,是不必手动赋值的,但也有许多例外。

       值得一提的是,这个结构体不仅仅用来定义ECC布局,也可以用来将你的驱动在oob中需要额外用到的字节位置保护起来。

       现在对struct nand_ecclayout 这个结构体进行一下说明:

uint32_t eccbytes:ECC的字节数,对于512B-per-page的NAND来说,eccbytes = 3,如果你需要额外用到oob中的数据,那么也可以大于3.

uint32_t eccpos[64]:ECC数据在oob中的位置,这里之所以是个64字节的数组,是因为对于2048-per-page的NAND来说,它的oob有64个字节。而对于512B-per-page的NAND来说,可以而且只可以定义它的前16个字节。

uint32_t oobavail:oob中可用的字节数,这个值不用赋值,MTD会根据其它三个变量自动计算得到。

struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]:显示定义空闲的oob字节。

=====================================================================

所以定义一个nand_ecclayout结构体,于是在内核源码中搜索“nand_ecclayout”

找到drivers/mtd/nand/s3c_nand.c:

#if 0

// samsung  K9GAG08U0D  MLC nand flash  oob size =218 Byte

static struct nand_ecclayout s3c_nand_oob_mlc_218_8bit = {

    .eccbytes = 104,

    .eccpos = {

           114,115,116,117,118,119,120,121,122,123,

           124,125,126,127,128,129,130,131,132,133,

           134,135,136,137,138,139,140,141,142,143,

           144,145,146,147,148,149,150,151,152,153,

           154,155,156,157,158,159,160,161,162,163,

           164,165,166,167,168,169,170,171,172,173,

           174,175,176,177,178,179,180,181,182,183,

           184,185,186,187,188,189,190,191,192,193,

           194,195,196,197,198,199,200,201,202,203,

           204,205,206,207,208,209,210,211,212,213,

           214,215,216,217 },

    .oobfree = {

        {.offset = 2,

         .length = 110}}

};

#endif

这个nand flash型号正是我板子用的型号,在内核中中断代码竟然被屏蔽了,而且在源码中报错点处:

if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH))

如果chip->ecc.layout没有定义内核会设置一个默认值,但是源码中:

    if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) {

        switch (mtd->oobsize) {

        case 8:

            chip->ecc.layout = &nand_oob_8;

            break;

        case 16:

            chip->ecc.layout = &nand_oob_16;

            break;

        case 64:

            chip->ecc.layout = &nand_oob_64;

            break;

        case 128:

            chip->ecc.layout = &nand_oob_128;

            break;

        default:

            printk(KERN_WARNING "No oob scheme defined for "

                   "oobsize %d\n", mtd->oobsize);

            BUG();

        }

    }

设置默认值的时候oob最大只支持128B,但是我用的nand flash是(4K + 218)Byte:

Page Read Operation

- Page Size : (4K + 218)Byte

- Random Read : 60μs(Max.)

- Serial Access : 30ns(Min.)

即OOB为218B,所以内核根本没有设置chip->ecc.layout,故报错!

所以在源码中增加s3c_nand_oob_mlc_218_8bit的定义,设置:

chip->ecc.layout   = &s3c_nand_oob_mlc_218_8bit;

问题自然解决!


关键字:OK6410  nand  flash  块设备驱动 引用地址:OK6410之nand flash块设备驱动

上一篇:OK6410之LCD驱动
下一篇:OK6410启动自动挂载nfs文件系统

推荐阅读

在2018华为全联接大会(HUAWEI CONNECT)上,全球领先的技术与服务供应商博世与全球领先的信息与通信技术基础设施和智能终端提供商华为正式宣布合作,博世物联网套件软件服务(Bosch IoT Suite)将搭载于华为云实现在华落地应用,加速物联网在中国的发展。 中国物联网平台的市场预计在未来几年将增长近70%。“中国对物联网解决方案的需求与日俱增,是亚洲发...
过了十一,临近年尾,“双十一”大战又近。 但是今年的“双十一”却来得很特别——因为这是阿里巴巴董事局主席马云于今年教师节卸任后的第一个“双十一”。这位“马爸爸”,用了十几年的时间,在创造一个奇迹般企业的同时,彻底改变了中国人乃至全世界相当一部分人的消费习惯。 马云是电子商务的践行者。谈及电子商务,让我想起1996年,IBM率先提出了E-Com...
外媒 WMPU 报道,微软 Surface Duo 最初是采用金属框架设计的,但在去年的某些时候,微软决定采用塑料边框,这似乎是近期不少问题的根源。  此前IT之家报道,微软 Surface Duo 出现了 USB-C 端口塑料边框破裂的问题,现在多个用户抱怨设备的塑料边框出现发黄问题。  这似乎是一个公认的问题,多名用户报告称,微软允许他们退回边框发黄的手...
事情的起因是这样的,每次苹果发布新款iPhone,托尼总能注意到网上都会出现一帮网友在喊着“ 老款iPhone降价,终于可以去买老款了 ” 的口号。  出现这种现象的原因往往不是因为新出来的iPhone不香,而是要怪iPhone实在是太耐用了。  要知道苹果 A系芯片本来就比同时期的安卓强,再加上iOS系统的优化真的是很到位,使得我们即便是买旧款iPhon...

史海拾趣

问答坊 | AI 解惑

PLD设计技巧——消除组合逻辑产生的毛刺

PLD设计技巧——消除组合逻辑产生的毛刺…

查看全部问答∨

分享学习单片机技术的一些技巧跟方法!!

跟大家分享下学习单片机的一要点和方法!!QQ:313807838 一、理论与实践相结合,在理解理论的基础上大量的实践这才是学习的最好办法,其他的说什么也没用。 首先对一个初学单片机的人来说,按照平时的一些教材书上的方法,开始学就给你一大堆 ...…

查看全部问答∨

模拟技术是一门手艺

模拟技术是一门手艺,硬件工程师的功力全在画印制板上,就像厨师的功力全在火候上一样。电原理图就像菜谱,网上随处可找到。我们看了菜谱,但炒出的菜和厨师不一样,但菜的名字是一样的。我们可以在网上、杂志中找到各种原理图,按照原理图画出印制 ...…

查看全部问答∨

哪个高手,手里有platform builder.reg文件?

这个文件是我用PB软件编译后在release文件夹下见到的,现在想要这个文件,请问哪个哥哥姐姐有这个文件,发给我好吗?QQ 397293284 急用啊····谢谢啦…

查看全部问答∨

关于驱动加载的问题

我做一个ndis驱动,如何往hp的PDA里面加载. 谢谢各位了…

查看全部问答∨

承接casio dt930 程序开发,有意者QQ:88483816

本人承接casio dt930 程序开发,有意者QQ:88483816…

查看全部问答∨

C语言基本排序算法

C语言一些基本的排序算法,需要的可以直接用到自己的项目上哦!~很多朋友是以谭浩强老师编的《c语言教程》作为学习C语言的入门教程的。书中涉及排序问题一般都以“冒泡法”和“选择法”实现。为了扩大视野,增加学习编程的兴趣,我参阅了有关书籍, ...…

查看全部问答∨

LM3S的eth接口是不是很容易坏?

目前产品中已经有好几个芯片有类似情况,就是上电后,eth不能连接,换个cpu后就好了,不知道是什么情况。电路如下图所示:请有经验的大虾帮忙分析分析!CPU型号是LM3S9B92-C5 [ 本帖最后由 zxq6 于 2012-4-18 12:28 编辑 ]…

查看全部问答∨

一定要好好学下430

RT~,很希望这个铁电开发板呢…

查看全部问答∨

《玩转TI MSP430 Launchpad》与大家见面了!

    TI-EEWORLD联手打造的《玩转TI MSP430 Launchpad》与广大工程师朋友们见面了!按照传统的观念,单片机入门教材或工具书之类都应是由资深专业人士编写,而与此不同的是,本书中大量精彩内容来自于网友们的经验和知识,这些都是来自于 ...…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved