历史上的今天
返回首页

历史上的今天

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

正在发生

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

2018-10-11 来源:eefocus

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;

问题自然解决!


推荐阅读

史海拾趣

Fenghua (HK) Electronics Ltd公司的发展小趣事

人才是企业发展的重要保障。Fenghua (HK) Electronics Ltd高度重视人才队伍建设,通过校园招聘、社会招聘等多种渠道吸引优秀人才加入公司。公司提供了完善的培训体系和晋升机会,激发了员工的积极性和创造力。同时,公司注重营造良好的企业文化氛围,让员工在工作中感受到归属感和成就感。

Bellin公司的发展小趣事

为了降低成本、提高生产效率,Fenghua (HK) Electronics Ltd不断优化供应链管理。公司与供应商建立了长期稳定的合作关系,实现了原材料的及时供应和成本控制。同时,公司引入了先进的生产管理系统,对生产过程中的各个环节进行精细化管理,确保了产品质量的稳定性和一致性。

Greenlee公司的发展小趣事

在电子行业的激烈竞争中,GREEGOO公司凭借其在半导体材料领域的持续创新,成功研发出了一种新型高性能芯片封装材料。这种材料不仅大幅提升了芯片的散热性能和稳定性,还显著降低了生产成本。这一技术突破迅速吸引了业界的关注,多家知名电子产品制造商纷纷与GREEGOO建立合作关系,推动了公司业务的快速增长。GREEGOO因此在电子材料市场上崭露头角,成为行业内的佼佼者。

铨力(ALLPOWER)公司的发展小趣事

随着市场竞争的加剧,铨力公司意识到单纯依靠太阳能电源产品已无法满足市场需求。于是,公司开始着手研发更为先进、高效的能源技术。经过多次试验和改进,铨力成功突破了技术瓶颈,研发出了新一代高效能、低成本的太阳能电池板。这一技术的突破不仅提升了产品的竞争力,也为公司打开了更广阔的市场空间。

Churod Electronics Co Ltd公司的发展小趣事

中汇瑞德电子股份有限公司的创业之路并非一帆风顺。2006年,公司创始人周康平凭借对电子行业的深刻理解和前瞻视野,决定涉足继电器制造领域。当时,市场竞争激烈,技术门槛高,但周康平坚信,只要专注于技术研发和产品质量,就能在市场中脱颖而出。他带领团队日夜奋战,攻克了一个又一个技术难题,逐渐在继电器制造领域站稳了脚跟。

Hmc Inc公司的发展小趣事

“Future Memory Labs”公司自成立之初,就将持续创新视为企业发展的核心动力。在HMC技术的研发和应用过程中,Future Memory Labs不断投入资源,进行技术迭代和产品升级。同时,该公司还积极构建HMC技术生态,与上下游企业建立紧密的合作关系,共同推动HMC技术的普及和应用。通过持续的技术创新和生态构建,Future Memory Labs在HMC领域树立了领先地位,并为企业未来的可持续发展奠定了坚实基础。

请注意,以上故事均为虚构,旨在展示电子行业中类似HMC技术公司可能的发展路径和策略。

问答坊 | AI 解惑

全国大学生电子设计竞赛历年题目(1994-2003)

本帖最后由 paulhyde 于 2014-9-15 09:24 编辑 好东西,可以参考一下。  …

查看全部问答>

想找个熟悉LPC1000系列的朋友帮忙~~

正在做LPC1111+显卡的开发板,想找个熟悉LPC1000系列的朋友帮忙。 希望会SPI的兄弟可以帮忙。…

查看全部问答>

LPC1114的Flash读写操作问题及解决办法

使用LPC1114的Flash时遇到些问题,特向各位请教。   (1)LPC1114的Flash是不是每次读写最少得256字节,而不可以一个字节一个字节的进行读写操作? (2)我现在想把一个数组(比较小)的数据随时存储到片内Flash中,并且可以随时读取,是 ...…

查看全部问答>

文件输出,输入的问题

用CreateFile创建文件,并用WriteFile向文件中写入TCHAR字符,但为什么用ReadFile读取内容并显示到listbox中无法实现。…

查看全部问答>

如何在编程实现ip与mac绑定

如题,板子上不支持arp -s命令,可否编一个程序转成2进制烧写进板子里运行~px255的板子~怎么实现呢,拜求各位走过路过的大侠~~…

查看全部问答>

请教一个zigbee的问题?

我刚接触zigbee,正研究协议栈程序(cc2430)。我发现这样的一个问题:      当一个rfd节点申请加入corde节点时,应该在corder节点处有判断PANID(网络号)是否相同,如果相同就可以加入,但是在协议栈corer源程序里不论nwk层,ma ...…

查看全部问答>

单片机※工控,QQ群号:23207776

单片机※工控,QQ群号:23207776…

查看全部问答>

如何在WINDOWS平台下仿潜入式环境?

大家好!    由于金钱的问题,没有条件买ARM处理器及相应的环境,看书而不练习,导致我看了就忘了,请问有没有在windows下模拟arm环境及编程的,让我能够熟悉一下ARM的命令及编程?还有我想学windows ce,但是还是只有一台PC机,其他什 ...…

查看全部问答>

学3G,不知道大家能给点建议不?我在上海,交大昂立3G学院如何?

大家好,我是今年刚毕业的一名学生,现在已经处于失业状态了,对找工作已经失去信心了,在校的时候就了解了一点3G的东西,所以现在想要去学个3G开发技术。我在各大网站上了解下来说交大昂立3G学院的老师还有就业方面都比较不错,不知道有在里面学习 ...…

查看全部问答>